[10.0] extract hr_expense_private_car (#36)
* remove private car stuff from hr_expense_usability * hr_private_car_expenses
This commit is contained in:
committed by
Alexis de Lattre
parent
19d2614feb
commit
a9d8137d1f
13
hr_expense_private_car/README.rst
Normal file
13
hr_expense_private_car/README.rst
Normal file
@@ -0,0 +1,13 @@
|
||||
====================
|
||||
HR Expense Usability
|
||||
====================
|
||||
|
||||
* support for Private car expenses (frais kilométriques selon barème fiscal),
|
||||
|
||||
Credits
|
||||
=======
|
||||
|
||||
Contributors
|
||||
------------
|
||||
|
||||
* Alexis de Lattre <alexis.delattre@akretion.com>
|
||||
4
hr_expense_private_car/__init__.py
Normal file
4
hr_expense_private_car/__init__.py
Normal file
@@ -0,0 +1,4 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from . import hr_expense
|
||||
from .post_install import create_private_car_km_prices
|
||||
29
hr_expense_private_car/__manifest__.py
Normal file
29
hr_expense_private_car/__manifest__.py
Normal file
@@ -0,0 +1,29 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# © 2015-2017 Akretion (http://www.akretion.com)
|
||||
# @author Alexis de Lattre <alexis.delattre@akretion.com>
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||
|
||||
{
|
||||
'name': 'HR Expense Private Car',
|
||||
'version': '10.0.1.0.0',
|
||||
'category': 'Human Resources',
|
||||
'license': 'AGPL-3',
|
||||
'summary': 'Better usability for the management of expenses',
|
||||
'description': '',
|
||||
'author': 'Akretion',
|
||||
'website': 'http://www.akretion.com',
|
||||
'depends': [
|
||||
'hr_expense_usability',
|
||||
],
|
||||
'data': [
|
||||
'hr_expense_data.xml',
|
||||
'hr_employee_view.xml',
|
||||
'hr_expense_view.xml',
|
||||
'private_car_km_price_view.xml',
|
||||
'security/expense_security.xml',
|
||||
'security/ir.model.access.csv',
|
||||
],
|
||||
'post_init_hook': 'create_private_car_km_prices',
|
||||
'demo': ['private_car_demo.xml'],
|
||||
'installable': True,
|
||||
}
|
||||
190
hr_expense_private_car/hr_expense.py
Normal file
190
hr_expense_private_car/hr_expense.py
Normal file
@@ -0,0 +1,190 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# © 2014-2017 Akretion (http://www.akretion.com)
|
||||
# @author Alexis de Lattre <alexis.delattre@akretion.com>
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||
|
||||
from odoo import models, fields, api, _
|
||||
from odoo.exceptions import UserError, ValidationError
|
||||
from odoo.tools import float_compare, float_is_zero
|
||||
import odoo.addons.decimal_precision as dp
|
||||
|
||||
|
||||
# I had to choose between several ideas when I developped this module :
|
||||
# 1) constraint on product_id in expense line
|
||||
# Idea : we put a constraint on the field product_id of the expense line
|
||||
# and, if it's a private_car_expense_ok=True product but it's not the private
|
||||
# car expense product of the employee, we block
|
||||
# Drawback : not convenient for the employee because he has to select the
|
||||
# right private car expense product by himself
|
||||
|
||||
# 2) single product, dedicated object for prices
|
||||
# Idea : we create only one "private car expense" product, and we
|
||||
# create a new object to store the price depending on the CV, etc...
|
||||
# Drawback : need to create a new object
|
||||
# => that's what is implemented in this module
|
||||
|
||||
# 3) single generic "My private car" product selectable by the user ;
|
||||
# several specific private car products NOT selectable by the user
|
||||
# Idea : When the user selects the generic "My private car" product,
|
||||
# it is automatically replaced by the specific one via the on_change
|
||||
# Drawback : decimal precision 'Product Price' on standard_price of product
|
||||
# (but we need 3)
|
||||
|
||||
class PrivateCarKmPrice(models.Model):
|
||||
_name = 'private.car.km.price'
|
||||
_description = 'Private Car Kilometer Price'
|
||||
_order = 'name'
|
||||
|
||||
name = fields.Char(required=True)
|
||||
unit_amount = fields.Float(
|
||||
string='Price per KM', digits=dp.get_precision('Expense Unit Price'),
|
||||
help='Price per kilometer in company currency.')
|
||||
company_id = fields.Many2one(
|
||||
'res.company', string='Company',
|
||||
default=lambda self: self.env['res.company']._company_default_get(
|
||||
'private.car.km.price'))
|
||||
active = fields.Boolean(default=True)
|
||||
|
||||
|
||||
class HrEmployee(models.Model):
|
||||
_inherit = 'hr.employee'
|
||||
|
||||
def compute_private_car_total_km_this_year(self):
|
||||
res = {}
|
||||
private_car_product_id = self.env.ref(
|
||||
'hr_expense_usability.generic_private_car_expense').id
|
||||
today = fields.Date.context_today(self)
|
||||
today_dt = fields.Date.from_string(today)
|
||||
self._cr.execute(
|
||||
"""
|
||||
SELECT el.employee_id, sum(el.quantity)
|
||||
FROM hr_expense el
|
||||
WHERE el.state NOT IN ('draft', 'cancel')
|
||||
AND el.employee_id IN %s
|
||||
AND el.product_id=%s
|
||||
AND EXTRACT(year FROM el.date) = %s
|
||||
GROUP BY el.employee_id
|
||||
""",
|
||||
(tuple(self.ids), private_car_product_id, today_dt.year))
|
||||
for line in self._cr.dictfetchall():
|
||||
res[line['employee_id']] = line['sum']
|
||||
for empl in self:
|
||||
empl.private_car_total_km_this_year = res.get(empl.id) or 0.0
|
||||
|
||||
private_car_plate = fields.Char(
|
||||
'Private Car Plate', size=32, copy=False, track_visibility='onchange',
|
||||
help="This field will be copied on the expenses of this employee.")
|
||||
private_car_km_price_id = fields.Many2one(
|
||||
'private.car.km.price', string='Private Car Price', copy=False,
|
||||
ondelete='restrict', track_visibility='onchange',
|
||||
help="This field will be copied on the expenses of this employee.")
|
||||
private_car_total_km_this_year = fields.Float(
|
||||
compute='compute_private_car_total_km_this_year',
|
||||
string="Total KM with Private Car This Year", readonly=True,
|
||||
help="Number of kilometers (KM) with private car for this "
|
||||
"employee in expenses in Approved, Waiting Payment or Paid "
|
||||
"state in the current civil year. This is usefull to check or "
|
||||
"estimate if the Private Car Product selected for this "
|
||||
"employee is compatible with the number of kilometers "
|
||||
"reimbursed to this employee during the civil year.")
|
||||
|
||||
|
||||
class HrExpense(models.Model):
|
||||
_inherit = 'hr.expense'
|
||||
|
||||
private_car_plate = fields.Char(
|
||||
string='Private Car Plate', size=32, track_visibility='onchange',
|
||||
readonly=True, states={'draft': [('readonly', False)]})
|
||||
private_car_km_price_id = fields.Many2one(
|
||||
'private.car.km.price', string='Private Car Price', copy=False,
|
||||
ondelete='restrict', track_visibility='onchange',
|
||||
help="This field will be copied on the expenses of this employee.")
|
||||
# only for field visibility
|
||||
private_car_expense = fields.Boolean()
|
||||
|
||||
@api.onchange('product_id')
|
||||
def _onchange_product_id(self):
|
||||
private_car_product = self.env.ref(
|
||||
'hr_expense_usability.generic_private_car_expense')
|
||||
if (
|
||||
self.product_id and
|
||||
self.product_id == private_car_product and
|
||||
self.employee_id):
|
||||
if not self.employee_id.private_car_km_price_id:
|
||||
raise UserError(_(
|
||||
"Missing Private Car Km Price on the configuration of "
|
||||
"the employee '%s'.") % self.employee_id.display_name)
|
||||
if not self.employee_id.private_car_plate:
|
||||
raise UserError(_(
|
||||
"Missing Private Car Plate on the configuration of "
|
||||
"the employee '%s'.") % self.employee_id.display_name)
|
||||
self.private_car_expense = True
|
||||
self.currency_id = self.company_id.currency_id
|
||||
self.private_car_plate = self.employee_id.private_car_plate
|
||||
self.private_car_km_price_id =\
|
||||
self.employee_id.private_car_km_price_id
|
||||
else:
|
||||
self.private_car_expense = False
|
||||
self.private_car_plate = False
|
||||
self.private_car_km_price_id = False
|
||||
return super(HrExpense, self)._onchange_product_id()
|
||||
|
||||
@api.onchange('private_car_km_price_id')
|
||||
def _onchange_private_car_km_price_id(self):
|
||||
if self.private_car_km_price_id and self.employee_id:
|
||||
self.unit_amount =\
|
||||
self.employee_id.private_car_km_price_id.unit_amount
|
||||
|
||||
@api.onchange('unit_amount')
|
||||
def _onchange_unit_amount(self):
|
||||
res = {}
|
||||
if self.private_car_expense:
|
||||
original_unit_amount = self.private_car_km_price_id.unit_amount
|
||||
prec = self.env['decimal.precision'].precision_get(
|
||||
'Expense Unit Price')
|
||||
if float_compare(
|
||||
original_unit_amount, self.unit_amount,
|
||||
precision_digits=prec):
|
||||
if self.env.user.has_group('account.group_account_manager'):
|
||||
res['warning'] = {
|
||||
'title': _('Warning - Private Car Expense'),
|
||||
'message': _(
|
||||
"You should not change the unit price "
|
||||
"for private car expenses. You should change "
|
||||
"the Private Car Product or update the Cost "
|
||||
"Price of the selected Private Car Product "
|
||||
"and re-create the Expense.\n\nBut, as "
|
||||
"you are in the group 'Account Manager', we "
|
||||
"suppose that you know what you are doing, "
|
||||
"so the original unit amount (%s) is not "
|
||||
"restored.") % original_unit_amount,
|
||||
}
|
||||
else:
|
||||
res['warning'] = {
|
||||
'title': _('Warning - Private Car Expense'),
|
||||
'message': _(
|
||||
"You should not change the unit price "
|
||||
"for private car expenses. The original unit "
|
||||
"amount has been restored.\n\nOnly users in "
|
||||
"the 'Account Manager' group are allowed to "
|
||||
"change the unit amount for private car "
|
||||
"expenses manually.")}
|
||||
res['value'] = {'unit_amount': original_unit_amount}
|
||||
return res
|
||||
|
||||
@api.constrains(
|
||||
'product_id', 'private_car_plate', 'private_car_km_price_id')
|
||||
def _check_expense(self):
|
||||
generic_private_car_product = self.env.ref(
|
||||
'hr_expense_usability.generic_private_car_expense')
|
||||
for exp in self:
|
||||
if exp.product_id == generic_private_car_product:
|
||||
if not exp.private_car_plate:
|
||||
raise ValidationError(_(
|
||||
"Missing 'Private Car Plate' on the "
|
||||
"expense '%s' of employee '%s'.")
|
||||
% (exp.name, exp.employee_id.display_name))
|
||||
if not exp.private_car_km_price_id:
|
||||
raise ValidationError(_(
|
||||
"Missing 'Private Car Km Price' on the "
|
||||
"expense '%s'.") % exp.name)
|
||||
24
hr_expense_private_car/hr_expense_view.xml
Normal file
24
hr_expense_private_car/hr_expense_view.xml
Normal file
@@ -0,0 +1,24 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
© 2014-2017 Akretion (http://www.akretion.com)
|
||||
@author: Alexis de Lattre <alexis.delattre@akretion.com>
|
||||
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||
-->
|
||||
|
||||
<odoo>
|
||||
|
||||
|
||||
<record id="hr_expense_form_view" model="ir.ui.view">
|
||||
<field name="name">usability.hr.expense.form</field>
|
||||
<field name="model">hr.expense</field>
|
||||
<field name="inherit_id" ref="hr_expense.hr_expense_form_view"/>
|
||||
<field name="arch" type="xml">
|
||||
<field name="reference" position="after">
|
||||
<field name="private_car_expense" invisible="1"/>
|
||||
<field name="private_car_plate" attrs="{'invisible': [('private_car_expense', '!=', True)]}"/>
|
||||
<field name="private_car_km_price_id" attrs="{'invisible': [('private_car_expense', '!=', True)]}" groups="hr_expense.group_hr_expense_manager,account.group_account_manager"/>
|
||||
</field>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
</odoo>
|
||||
10
hr_expense_private_car/security/expense_security.xml
Normal file
10
hr_expense_private_car/security/expense_security.xml
Normal file
@@ -0,0 +1,10 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo noupdate="1">
|
||||
|
||||
<record id="private_car_km_price_multicompany" model="ir.rule">
|
||||
<field name="name">Private Car Kilometer Prices Multi-company</field>
|
||||
<field name="model_id" ref="model_private_car_km_price"/>
|
||||
<field name="domain_force">['|', ('company_id', '=', False), ('company_id', 'child_of', [user.company_id.id])]</field>
|
||||
</record>
|
||||
|
||||
</odoo>
|
||||
BIN
hr_expense_private_car/static/description/icon.png
Normal file
BIN
hr_expense_private_car/static/description/icon.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 6.5 KiB |
@@ -4,7 +4,6 @@ HR Expense Usability
|
||||
|
||||
This module adds a many usability enhancements and new features to the official Expense modules:
|
||||
|
||||
* support for Private car expenses (frais kilométriques selon barème fiscal),
|
||||
* remove support for *Payment by Company*
|
||||
* multi-currency fixes (cf https://github.com/odoo/odoo/issues/17341)
|
||||
* full re-implementation of the generation of the account.move (by default, it generates 1 move per expense line ; with this module, it generates 1 move per expense report and move lines can be grouped)
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from . import hr_expense
|
||||
from .post_install import create_private_car_km_prices
|
||||
|
||||
@@ -17,15 +17,9 @@
|
||||
'hr_expense_usability_dp',
|
||||
],
|
||||
'data': [
|
||||
'hr_expense_data.xml',
|
||||
'hr_employee_view.xml',
|
||||
'hr_expense_view.xml',
|
||||
'product_view.xml',
|
||||
'private_car_km_price_view.xml',
|
||||
'security/expense_security.xml',
|
||||
'security/ir.model.access.csv',
|
||||
],
|
||||
'post_init_hook': 'create_private_car_km_prices',
|
||||
'demo': ['private_car_demo.xml'],
|
||||
'installable': True,
|
||||
}
|
||||
|
||||
@@ -9,27 +9,6 @@ from odoo.tools import float_compare, float_is_zero
|
||||
import odoo.addons.decimal_precision as dp
|
||||
|
||||
|
||||
# I had to choose between several ideas when I developped this module :
|
||||
# 1) constraint on product_id in expense line
|
||||
# Idea : we put a constraint on the field product_id of the expense line
|
||||
# and, if it's a private_car_expense_ok=True product but it's not the private
|
||||
# car expense product of the employee, we block
|
||||
# Drawback : not convenient for the employee because he has to select the
|
||||
# right private car expense product by himself
|
||||
|
||||
# 2) single product, dedicated object for prices
|
||||
# Idea : we create only one "private car expense" product, and we
|
||||
# create a new object to store the price depending on the CV, etc...
|
||||
# Drawback : need to create a new object
|
||||
# => that's what is implemented in this module
|
||||
|
||||
# 3) single generic "My private car" product selectable by the user ;
|
||||
# several specific private car products NOT selectable by the user
|
||||
# Idea : When the user selects the generic "My private car" product,
|
||||
# it is automatically replaced by the specific one via the on_change
|
||||
# Drawback : decimal precision 'Product Price' on standard_price of product
|
||||
# (but we need 3)
|
||||
|
||||
class ProductTemplate(models.Model):
|
||||
_inherit = 'product.template'
|
||||
|
||||
@@ -84,64 +63,9 @@ class ProductProduct(models.Model):
|
||||
self.taxes_id = False
|
||||
|
||||
|
||||
class PrivateCarKmPrice(models.Model):
|
||||
_name = 'private.car.km.price'
|
||||
_description = 'Private Car Kilometer Price'
|
||||
_order = 'name'
|
||||
|
||||
name = fields.Char(required=True)
|
||||
unit_amount = fields.Float(
|
||||
string='Price per KM', digits=dp.get_precision('Expense Unit Price'),
|
||||
help='Price per kilometer in company currency.')
|
||||
company_id = fields.Many2one(
|
||||
'res.company', string='Company',
|
||||
default=lambda self: self.env['res.company']._company_default_get(
|
||||
'private.car.km.price'))
|
||||
active = fields.Boolean(default=True)
|
||||
|
||||
|
||||
class HrEmployee(models.Model):
|
||||
_inherit = 'hr.employee'
|
||||
|
||||
def compute_private_car_total_km_this_year(self):
|
||||
res = {}
|
||||
private_car_product_id = self.env.ref(
|
||||
'hr_expense_usability.generic_private_car_expense').id
|
||||
today = fields.Date.context_today(self)
|
||||
today_dt = fields.Date.from_string(today)
|
||||
self._cr.execute(
|
||||
"""
|
||||
SELECT el.employee_id, sum(el.quantity)
|
||||
FROM hr_expense el
|
||||
WHERE el.state NOT IN ('draft', 'cancel')
|
||||
AND el.employee_id IN %s
|
||||
AND el.product_id=%s
|
||||
AND EXTRACT(year FROM el.date) = %s
|
||||
GROUP BY el.employee_id
|
||||
""",
|
||||
(tuple(self.ids), private_car_product_id, today_dt.year))
|
||||
for line in self._cr.dictfetchall():
|
||||
res[line['employee_id']] = line['sum']
|
||||
for empl in self:
|
||||
empl.private_car_total_km_this_year = res.get(empl.id) or 0.0
|
||||
|
||||
private_car_plate = fields.Char(
|
||||
'Private Car Plate', size=32, copy=False, track_visibility='onchange',
|
||||
help="This field will be copied on the expenses of this employee.")
|
||||
private_car_km_price_id = fields.Many2one(
|
||||
'private.car.km.price', string='Private Car Price', copy=False,
|
||||
ondelete='restrict', track_visibility='onchange',
|
||||
help="This field will be copied on the expenses of this employee.")
|
||||
private_car_total_km_this_year = fields.Float(
|
||||
compute='compute_private_car_total_km_this_year',
|
||||
string="Total KM with Private Car This Year", readonly=True,
|
||||
help="Number of kilometers (KM) with private car for this "
|
||||
"employee in expenses in Approved, Waiting Payment or Paid "
|
||||
"state in the current civil year. This is usefull to check or "
|
||||
"estimate if the Private Car Product selected for this "
|
||||
"employee is compatible with the number of kilometers "
|
||||
"reimbursed to this employee during the civil year.")
|
||||
|
||||
def _get_accounting_partner_from_employee(self):
|
||||
# By default, odoo uses self.employee_id.address_home_id
|
||||
# which users usually don't configure
|
||||
@@ -172,15 +96,6 @@ class HrExpense(models.Model):
|
||||
# I want a specific precision for unit_amount of expense
|
||||
# main reason is KM cost which is 3 by default
|
||||
unit_amount = fields.Float(digits=dp.get_precision('Expense Unit Price'))
|
||||
private_car_plate = fields.Char(
|
||||
string='Private Car Plate', size=32, track_visibility='onchange',
|
||||
readonly=True, states={'draft': [('readonly', False)]})
|
||||
private_car_km_price_id = fields.Many2one(
|
||||
'private.car.km.price', string='Private Car Price', copy=False,
|
||||
ondelete='restrict', track_visibility='onchange',
|
||||
help="This field will be copied on the expenses of this employee.")
|
||||
# only for field visibility
|
||||
private_car_expense = fields.Boolean()
|
||||
tax_amount = fields.Monetary(
|
||||
string='Tax Amount', currency_field='currency_id',
|
||||
readonly=True, states={'draft': [('readonly', False)]})
|
||||
@@ -241,106 +156,11 @@ class HrExpense(models.Model):
|
||||
self.untaxed_amount_usability = total
|
||||
self.tax_amount = False
|
||||
|
||||
@api.onchange('product_id')
|
||||
def _onchange_product_id(self):
|
||||
private_car_product = self.env.ref(
|
||||
'hr_expense_usability.generic_private_car_expense')
|
||||
if (
|
||||
self.product_id and
|
||||
self.product_id == private_car_product and
|
||||
self.employee_id):
|
||||
if not self.employee_id.private_car_km_price_id:
|
||||
raise UserError(_(
|
||||
"Missing Private Car Km Price on the configuration of "
|
||||
"the employee '%s'.") % self.employee_id.display_name)
|
||||
if not self.employee_id.private_car_plate:
|
||||
raise UserError(_(
|
||||
"Missing Private Car Plate on the configuration of "
|
||||
"the employee '%s'.") % self.employee_id.display_name)
|
||||
self.private_car_expense = True
|
||||
self.currency_id = self.company_id.currency_id
|
||||
self.private_car_plate = self.employee_id.private_car_plate
|
||||
self.private_car_km_price_id =\
|
||||
self.employee_id.private_car_km_price_id
|
||||
else:
|
||||
self.private_car_expense = False
|
||||
self.private_car_plate = False
|
||||
self.private_car_km_price_id = False
|
||||
return super(HrExpense, self)._onchange_product_id()
|
||||
|
||||
@api.onchange('private_car_km_price_id')
|
||||
def _onchange_private_car_km_price_id(self):
|
||||
if self.private_car_km_price_id and self.employee_id:
|
||||
self.unit_amount =\
|
||||
self.employee_id.private_car_km_price_id.unit_amount
|
||||
|
||||
@api.onchange('unit_amount')
|
||||
def _onchange_unit_amount(self):
|
||||
res = {}
|
||||
if self.private_car_expense:
|
||||
original_unit_amount = self.private_car_km_price_id.unit_amount
|
||||
prec = self.env['decimal.precision'].precision_get(
|
||||
'Expense Unit Price')
|
||||
if float_compare(
|
||||
original_unit_amount, self.unit_amount,
|
||||
precision_digits=prec):
|
||||
if self.env.user.has_group('account.group_account_manager'):
|
||||
res['warning'] = {
|
||||
'title': _('Warning - Private Car Expense'),
|
||||
'message': _(
|
||||
"You should not change the unit price "
|
||||
"for private car expenses. You should change "
|
||||
"the Private Car Product or update the Cost "
|
||||
"Price of the selected Private Car Product "
|
||||
"and re-create the Expense.\n\nBut, as "
|
||||
"you are in the group 'Account Manager', we "
|
||||
"suppose that you know what you are doing, "
|
||||
"so the original unit amount (%s) is not "
|
||||
"restored.") % original_unit_amount,
|
||||
}
|
||||
else:
|
||||
res['warning'] = {
|
||||
'title': _('Warning - Private Car Expense'),
|
||||
'message': _(
|
||||
"You should not change the unit price "
|
||||
"for private car expenses. The original unit "
|
||||
"amount has been restored.\n\nOnly users in "
|
||||
"the 'Account Manager' group are allowed to "
|
||||
"change the unit amount for private car "
|
||||
"expenses manually.")}
|
||||
res['value'] = {'unit_amount': original_unit_amount}
|
||||
return res
|
||||
|
||||
@api.constrains(
|
||||
'product_id', 'private_car_plate', 'payment_mode', 'tax_ids',
|
||||
'product_id', 'payment_mode', 'tax_ids',
|
||||
'untaxed_amount_usability', 'tax_amount', 'quantity', 'unit_amount')
|
||||
def _check_expense(self):
|
||||
generic_private_car_product = self.env.ref(
|
||||
'hr_expense_usability.generic_private_car_expense')
|
||||
for exp in self:
|
||||
if exp.product_id == generic_private_car_product:
|
||||
if not exp.private_car_plate:
|
||||
raise ValidationError(_(
|
||||
"Missing 'Private Car Plate' on the "
|
||||
"expense '%s' of employee '%s'.")
|
||||
% (exp.name, exp.employee_id.display_name))
|
||||
if not exp.private_car_km_price_id:
|
||||
raise ValidationError(_(
|
||||
"Missing 'Private Car Km Price' on the "
|
||||
"expense '%s'.") % exp.name)
|
||||
if exp.currency_id != exp.company_id.currency_id:
|
||||
raise ValidationError(_(
|
||||
"The expense '%s' is a private car expense, "
|
||||
"so the currency of this expense (%s) should "
|
||||
"be the currency of the company (%s).") % (
|
||||
exp.name,
|
||||
exp.currency_id.name,
|
||||
exp.company_id.currency_id.name))
|
||||
if exp.tax_ids:
|
||||
raise ValidationError(_(
|
||||
"The expense '%s' is a private car expense "
|
||||
"so it shouldn't have taxes.")
|
||||
% exp.name)
|
||||
if exp.tax_ids:
|
||||
if len(exp.tax_ids) > 1:
|
||||
raise ValidationError(_(
|
||||
|
||||
@@ -13,11 +13,6 @@
|
||||
<field name="model">hr.expense</field>
|
||||
<field name="inherit_id" ref="hr_expense.hr_expense_form_view"/>
|
||||
<field name="arch" type="xml">
|
||||
<field name="reference" position="after">
|
||||
<field name="private_car_expense" invisible="1"/>
|
||||
<field name="private_car_plate" attrs="{'invisible': [('private_car_expense', '!=', True)]}"/>
|
||||
<field name="private_car_km_price_id" attrs="{'invisible': [('private_car_expense', '!=', True)]}" groups="hr_expense.group_hr_expense_manager,account.group_account_manager"/>
|
||||
</field>
|
||||
<label for="payment_mode" position="attributes">
|
||||
<attribute name="invisible">1</attribute>
|
||||
</label>
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
<odoo>
|
||||
|
||||
<record id="product_template_search_view" model="ir.ui.view">
|
||||
<field name="name">private.car.expense.product.template.search</field>
|
||||
<field name="name">hr.expense.usablility.product.template.search</field>
|
||||
<field name="model">product.template</field>
|
||||
<field name="inherit_id" ref="product.product_template_search_view"/>
|
||||
<field name="arch" type="xml">
|
||||
|
||||
@@ -15,10 +15,4 @@
|
||||
<field name="groups" eval="[(4, ref('account.group_account_user')), (4, ref('hr_expense.group_hr_expense_manager')), (4, ref('hr_expense.group_hr_expense_user'))]"/>
|
||||
</record>
|
||||
|
||||
<record id="private_car_km_price_multicompany" model="ir.rule">
|
||||
<field name="name">Private Car Kilometer Prices Multi-company</field>
|
||||
<field name="model_id" ref="model_private_car_km_price"/>
|
||||
<field name="domain_force">['|', ('company_id', '=', False), ('company_id', 'child_of', [user.company_id.id])]</field>
|
||||
</record>
|
||||
|
||||
</odoo>
|
||||
|
||||
1
setup/hr_expense_private_car/odoo/__init__.py
Normal file
1
setup/hr_expense_private_car/odoo/__init__.py
Normal file
@@ -0,0 +1 @@
|
||||
__import__('pkg_resources').declare_namespace(__name__)
|
||||
1
setup/hr_expense_private_car/odoo/addons/__init__.py
Normal file
1
setup/hr_expense_private_car/odoo/addons/__init__.py
Normal file
@@ -0,0 +1 @@
|
||||
__import__('pkg_resources').declare_namespace(__name__)
|
||||
1
setup/hr_expense_private_car/odoo/addons/hr_expense_private_car
Symbolic link
1
setup/hr_expense_private_car/odoo/addons/hr_expense_private_car
Symbolic link
@@ -0,0 +1 @@
|
||||
../../../../hr_expense_private_car
|
||||
6
setup/hr_expense_private_car/setup.py
Normal file
6
setup/hr_expense_private_car/setup.py
Normal file
@@ -0,0 +1,6 @@
|
||||
import setuptools
|
||||
|
||||
setuptools.setup(
|
||||
setup_requires=['setuptools-odoo'],
|
||||
odoo_addon=True,
|
||||
)
|
||||
Reference in New Issue
Block a user