Add support for private car expenses
This commit is contained in:
@@ -1,9 +1,13 @@
|
|||||||
|
====================
|
||||||
HR Expense Usability
|
HR Expense Usability
|
||||||
====================
|
====================
|
||||||
|
|
||||||
This module adds a few usability enhancements to the official Expense modules:
|
This module adds a many usability enhancements and new features to the official Expense modules:
|
||||||
|
|
||||||
* Re-organise access rights: Officer can see the expense notes of his subordinates ; Manager can see all expense notes
|
* support for Private car expenses (frais kilométriques selon barème fiscal),
|
||||||
|
* remove support for *Payment by Company*
|
||||||
|
* TODO: multi-currency fixes
|
||||||
|
* TODO: full re-implementation of the account.move
|
||||||
|
|
||||||
Credits
|
Credits
|
||||||
=======
|
=======
|
||||||
|
|||||||
@@ -1 +1,3 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
from . import hr_expense
|
||||||
|
|||||||
@@ -1,38 +1,28 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
##############################################################################
|
# © 2015-2017 Akretion (http://www.akretion.com)
|
||||||
#
|
# @author Alexis de Lattre <alexis.delattre@akretion.com>
|
||||||
# HR Expense Usability module for Odoo
|
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||||
# Copyright (C) 2015 Akretion (http://www.akretion.com)
|
|
||||||
# @author Alexis de Lattre <alexis.delattre@akretion.com>
|
|
||||||
#
|
|
||||||
# This program is free software: you can redistribute it and/or modify
|
|
||||||
# it under the terms of the GNU Affero General Public License as
|
|
||||||
# published by the Free Software Foundation, either version 3 of the
|
|
||||||
# License, or (at your option) any later version.
|
|
||||||
#
|
|
||||||
# This program is distributed in the hope that it will be useful,
|
|
||||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
# GNU Affero General Public License for more details.
|
|
||||||
#
|
|
||||||
# You should have received a copy of the GNU Affero General Public License
|
|
||||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
#
|
|
||||||
##############################################################################
|
|
||||||
|
|
||||||
|
|
||||||
{
|
{
|
||||||
'name': 'HR Expense Usability',
|
'name': 'HR Expense Usability',
|
||||||
'version': '0.1',
|
'version': '10.0.1.0.0',
|
||||||
'category': 'Human Resources',
|
'category': 'Human Resources',
|
||||||
'license': 'AGPL-3',
|
'license': 'AGPL-3',
|
||||||
'summary': 'Better usability for the management of expenses',
|
'summary': 'Better usability for the management of expenses',
|
||||||
'description': '',
|
'description': '',
|
||||||
'author': 'Akretion',
|
'author': 'Akretion',
|
||||||
'website': 'http://www.akretion.com',
|
'website': 'http://www.akretion.com',
|
||||||
'depends': ['hr_expense'],
|
'depends': [
|
||||||
|
'hr_expense',
|
||||||
|
'hr_expense_sequence',
|
||||||
|
],
|
||||||
'data': [
|
'data': [
|
||||||
|
'private_car_data.xml',
|
||||||
|
'hr_employee_view.xml',
|
||||||
|
'hr_expense_view.xml',
|
||||||
|
'product_view.xml',
|
||||||
'security/expense_security.xml',
|
'security/expense_security.xml',
|
||||||
],
|
],
|
||||||
'installable': False,
|
'demo': ['private_car_demo.xml'],
|
||||||
|
'installable': True,
|
||||||
}
|
}
|
||||||
|
|||||||
26
hr_expense_usability/hr_employee_view.xml
Normal file
26
hr_expense_usability/hr_employee_view.xml
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
<?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="view_employee_form" model="ir.ui.view">
|
||||||
|
<field name="name">private.car.employee.form</field>
|
||||||
|
<field name="model">hr.employee</field>
|
||||||
|
<field name="inherit_id" ref="hr.view_employee_form"/>
|
||||||
|
<field name="arch" type="xml">
|
||||||
|
<page name="hr_settings" position="inside">
|
||||||
|
<group name="private_car_expenses" string="Private Car Expenses">
|
||||||
|
<field name="private_car_plate"/>
|
||||||
|
<field name="private_car_product_id"
|
||||||
|
context="{'default_private_car_expense_ok': True}"/>
|
||||||
|
<field name="private_car_total_km_this_year"/>
|
||||||
|
</group>
|
||||||
|
</page>
|
||||||
|
</field>
|
||||||
|
</record>
|
||||||
|
|
||||||
|
</odoo>
|
||||||
203
hr_expense_usability/hr_expense.py
Normal file
203
hr_expense_usability/hr_expense.py
Normal file
@@ -0,0 +1,203 @@
|
|||||||
|
# -*- 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
|
||||||
|
|
||||||
|
|
||||||
|
# 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
|
||||||
|
|
||||||
|
# 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 : none ? :)
|
||||||
|
# => that's what is implemented in this module
|
||||||
|
|
||||||
|
|
||||||
|
class ProductTemplate(models.Model):
|
||||||
|
_inherit = 'product.template'
|
||||||
|
|
||||||
|
private_car_expense_ok = fields.Boolean(
|
||||||
|
string='Private Car Expense', track_visibility='onchange')
|
||||||
|
|
||||||
|
@api.onchange('private_car_expense_ok')
|
||||||
|
def onchange_private_car_expense_ok(self):
|
||||||
|
if self.private_car_expense_ok:
|
||||||
|
km_uom = self.env.ref('product.product_uom_km')
|
||||||
|
self.type = 'service'
|
||||||
|
self.list_price = 0.0
|
||||||
|
self.can_be_expensed = False
|
||||||
|
self.sale_ok = False
|
||||||
|
self.purchase_ok = False
|
||||||
|
self.uom_id = km_uom.id
|
||||||
|
self.po_uom_id = km_uom.id
|
||||||
|
self.taxes_id = False
|
||||||
|
self.supplier_taxes_id = False
|
||||||
|
|
||||||
|
@api.constrains(
|
||||||
|
'private_car_expense_ok', 'can_be_expensed', 'uom_id',
|
||||||
|
'standard_price')
|
||||||
|
def _check_private_car_expense(self):
|
||||||
|
for product in self:
|
||||||
|
if product.private_car_expense_ok:
|
||||||
|
if product.can_be_expensed:
|
||||||
|
raise ValidationError(_(
|
||||||
|
"The product '%s' cannot have both the properties "
|
||||||
|
"'Can be Expensed' and 'Private Car Expense'.")
|
||||||
|
% product.display_name)
|
||||||
|
km_uom = self.env.ref('product.product_uom_km')
|
||||||
|
if product.uom_id != km_uom:
|
||||||
|
raise ValidationError(_(
|
||||||
|
"The product '%s' is a Private Car Expense, so "
|
||||||
|
"it's unit of measure must be kilometers (KM).")
|
||||||
|
% product.display_name)
|
||||||
|
|
||||||
|
|
||||||
|
class HrEmployee(models.Model):
|
||||||
|
_inherit = 'hr.employee'
|
||||||
|
|
||||||
|
def compute_private_car_total_km_this_year(self):
|
||||||
|
print "compute_private_car_total_km_this_year self=", self
|
||||||
|
res = {}
|
||||||
|
private_car_products = self.env['product.product'].search(
|
||||||
|
[('private_car_expense_ok', '=', True)])
|
||||||
|
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 IN %s
|
||||||
|
AND EXTRACT(year FROM el.date) = %s
|
||||||
|
GROUP BY el.employee_id
|
||||||
|
""",
|
||||||
|
(tuple(self.ids), tuple(private_car_products.ids), 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_product_id = fields.Many2one(
|
||||||
|
'product.product', string='Private Car Product', copy=False,
|
||||||
|
domain=[('private_car_expense_ok', '=', True)],
|
||||||
|
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, readonly=True,
|
||||||
|
track_visibility='onchange',
|
||||||
|
states={'draft': [('readonly', False)]})
|
||||||
|
private_car_expense = fields.Boolean(
|
||||||
|
related='product_id.private_car_expense_ok', readonly=True, store=True)
|
||||||
|
|
||||||
|
# as private_car_plate id readonly, we have to inherit create() to set it
|
||||||
|
|
||||||
|
@api.onchange('product_id')
|
||||||
|
def _onchange_product_id(self):
|
||||||
|
if (
|
||||||
|
self.product_id and self.product_id == self.env.ref(
|
||||||
|
'hr_expense_usability.generic_private_car_expense')):
|
||||||
|
if not self.employee_id.private_car_product_id:
|
||||||
|
raise UserError(_(
|
||||||
|
"Missing Private Car Product 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.product_id = self.employee_id.private_car_product_id
|
||||||
|
self.private_car_plate = self.employee_id.private_car_plate
|
||||||
|
return super(HrExpense, self)._onchange_product_id()
|
||||||
|
|
||||||
|
@api.onchange('unit_amount')
|
||||||
|
def _onchange_unit_amount(self):
|
||||||
|
res = {}
|
||||||
|
if self.product_id.private_car_expense_ok:
|
||||||
|
original_unit_amount = self.product_id.price_compute(
|
||||||
|
'standard_price')[self.product_id.id]
|
||||||
|
prec = self.env['decimal.precision'].precision_get('Product 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')
|
||||||
|
def _check_private_car(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:
|
||||||
|
raise ValidationError(_(
|
||||||
|
"You are trying to save the expense '%s' "
|
||||||
|
"with the generic product '%s': it is not possible, "
|
||||||
|
"this product should have been automatically replaced "
|
||||||
|
"by the specific private car product configured for "
|
||||||
|
"the employee '%s'.") % (
|
||||||
|
exp.name,
|
||||||
|
generic_private_car_product.name,
|
||||||
|
exp.employee_id.display_name))
|
||||||
|
if (
|
||||||
|
exp.product_id.private_car_expense_ok and
|
||||||
|
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))
|
||||||
41
hr_expense_usability/hr_expense_view.xml
Normal file
41
hr_expense_usability/hr_expense_view.xml
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
<?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>
|
||||||
|
<label for="payment_mode" position="attributes">
|
||||||
|
<attribute name="invisible">1</attribute>
|
||||||
|
</label>
|
||||||
|
<field name="payment_mode" position="attributes">
|
||||||
|
<attribute name="invisible">1</attribute>
|
||||||
|
</field>
|
||||||
|
</field>
|
||||||
|
</record>
|
||||||
|
|
||||||
|
<record id="view_hr_expense_sheet_form" model="ir.ui.view">
|
||||||
|
<field name="name">usability.hr.expense.sheet.form</field>
|
||||||
|
<field name="model">hr.expense.sheet</field>
|
||||||
|
<field name="inherit_id" ref="hr_expense.view_hr_expense_sheet_form"/>
|
||||||
|
<field name="arch" type="xml">
|
||||||
|
<field name="payment_mode" position="attributes">
|
||||||
|
<attribute name="invisible">1</attribute>
|
||||||
|
</field>
|
||||||
|
</field>
|
||||||
|
</record>
|
||||||
|
|
||||||
|
|
||||||
|
</odoo>
|
||||||
281
hr_expense_usability/private_car_data.xml
Normal file
281
hr_expense_usability/private_car_data.xml
Normal file
@@ -0,0 +1,281 @@
|
|||||||
|
<?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 noupdate="1">
|
||||||
|
|
||||||
|
<record id="generic_private_car_expense" model="product.product">
|
||||||
|
<field name="name">My Private Car Expense (in km)</field>
|
||||||
|
<field name="default_code">PrivateCarExp</field>
|
||||||
|
<field name="categ_id" ref="hr_expense.cat_expense"/>
|
||||||
|
<field name="sale_ok" eval="False"/>
|
||||||
|
<field name="purchase_ok" eval="False"/>
|
||||||
|
<field name="can_be_expensed" eval="True"/>
|
||||||
|
<field name="type">service</field>
|
||||||
|
<field name="list_price">0</field>
|
||||||
|
<field name="uom_id" ref="product.product_uom_km"/>
|
||||||
|
<field name="uom_po_id" ref="product.product_uom_km"/>
|
||||||
|
<field name="taxes_id" eval="False"/>
|
||||||
|
<field name="supplier_taxes_id" eval="False"/>
|
||||||
|
</record>
|
||||||
|
|
||||||
|
<record id="1-3cv_0-5000km_private_car_expense" model="product.product">
|
||||||
|
<field name="name">1-3CV 0-5000km Private Car Expenses</field>
|
||||||
|
<field name="default_code">1-3CV/0-5000km</field>
|
||||||
|
<field name="categ_id" ref="hr_expense.cat_expense"/>
|
||||||
|
<field name="sale_ok" eval="False"/>
|
||||||
|
<field name="purchase_ok" eval="False"/>
|
||||||
|
<field name="can_be_expensed" eval="False"/>
|
||||||
|
<field name="private_car_expense_ok" eval="True"/>
|
||||||
|
<field name="type">service</field>
|
||||||
|
<field name="list_price">0</field>
|
||||||
|
<field name="standard_price">0.41</field>
|
||||||
|
<field name="uom_id" ref="product.product_uom_km"/>
|
||||||
|
<field name="uom_po_id" ref="product.product_uom_km"/>
|
||||||
|
<field name="taxes_id" eval="False"/>
|
||||||
|
<field name="supplier_taxes_id" eval="False"/>
|
||||||
|
</record>
|
||||||
|
|
||||||
|
<record id="4cv_0-5000km_private_car_expense" model="product.product">
|
||||||
|
<field name="name">4CV 0-5000km Private Car Expenses</field>
|
||||||
|
<field name="default_code">4CV/0-5000km</field>
|
||||||
|
<field name="categ_id" ref="hr_expense.cat_expense"/>
|
||||||
|
<field name="sale_ok" eval="False"/>
|
||||||
|
<field name="purchase_ok" eval="False"/>
|
||||||
|
<field name="can_be_expensed" eval="False"/>
|
||||||
|
<field name="private_car_expense_ok" eval="True"/>
|
||||||
|
<field name="type">service</field>
|
||||||
|
<field name="list_price">0</field>
|
||||||
|
<field name="standard_price">0.493</field>
|
||||||
|
<field name="uom_id" ref="product.product_uom_km"/>
|
||||||
|
<field name="uom_po_id" ref="product.product_uom_km"/>
|
||||||
|
<field name="taxes_id" eval="False"/>
|
||||||
|
<field name="supplier_taxes_id" eval="False"/>
|
||||||
|
</record>
|
||||||
|
|
||||||
|
<record id="5cv_0-5000km_private_car_expense" model="product.product">
|
||||||
|
<field name="name">5CV 0-5000km Private Car Expenses</field>
|
||||||
|
<field name="default_code">5CV/0-5000km</field>
|
||||||
|
<field name="categ_id" ref="hr_expense.cat_expense"/>
|
||||||
|
<field name="sale_ok" eval="False"/>
|
||||||
|
<field name="purchase_ok" eval="False"/>
|
||||||
|
<field name="can_be_expensed" eval="False"/>
|
||||||
|
<field name="private_car_expense_ok" eval="True"/>
|
||||||
|
<field name="type">service</field>
|
||||||
|
<field name="list_price">0</field>
|
||||||
|
<field name="standard_price">0.543</field>
|
||||||
|
<field name="uom_id" ref="product.product_uom_km"/>
|
||||||
|
<field name="uom_po_id" ref="product.product_uom_km"/>
|
||||||
|
<field name="taxes_id" eval="False"/>
|
||||||
|
<field name="supplier_taxes_id" eval="False"/>
|
||||||
|
</record>
|
||||||
|
|
||||||
|
<record id="6cv_0-5000km_private_car_expense" model="product.product">
|
||||||
|
<field name="name">6CV 0-5000km Private Car Expenses</field>
|
||||||
|
<field name="default_code">6CV/0-5000km</field>
|
||||||
|
<field name="categ_id" ref="hr_expense.cat_expense"/>
|
||||||
|
<field name="sale_ok" eval="False"/>
|
||||||
|
<field name="purchase_ok" eval="False"/>
|
||||||
|
<field name="can_be_expensed" eval="False"/>
|
||||||
|
<field name="private_car_expense_ok" eval="True"/>
|
||||||
|
<field name="type">service</field>
|
||||||
|
<field name="list_price">0</field>
|
||||||
|
<field name="standard_price">0.568</field>
|
||||||
|
<field name="uom_id" ref="product.product_uom_km"/>
|
||||||
|
<field name="uom_po_id" ref="product.product_uom_km"/>
|
||||||
|
<field name="taxes_id" eval="False"/>
|
||||||
|
<field name="supplier_taxes_id" eval="False"/>
|
||||||
|
</record>
|
||||||
|
|
||||||
|
<record id="7cv+_0-5000km_private_car_expense" model="product.product">
|
||||||
|
<field name="name">7CV+ 0-5000km Private Car Expenses</field>
|
||||||
|
<field name="default_code">7CV+/0-5000km</field>
|
||||||
|
<field name="categ_id" ref="hr_expense.cat_expense"/>
|
||||||
|
<field name="sale_ok" eval="False"/>
|
||||||
|
<field name="purchase_ok" eval="False"/>
|
||||||
|
<field name="can_be_expensed" eval="False"/>
|
||||||
|
<field name="private_car_expense_ok" eval="True"/>
|
||||||
|
<field name="type">service</field>
|
||||||
|
<field name="list_price">0</field>
|
||||||
|
<field name="standard_price">0.595</field>
|
||||||
|
<field name="uom_id" ref="product.product_uom_km"/>
|
||||||
|
<field name="uom_po_id" ref="product.product_uom_km"/>
|
||||||
|
<field name="taxes_id" eval="False"/>
|
||||||
|
<field name="supplier_taxes_id" eval="False"/>
|
||||||
|
</record>
|
||||||
|
|
||||||
|
<record id="1-3cv_5-20000km_private_car_expense" model="product.product">
|
||||||
|
<field name="name">1-3CV 5-20000km Private Car Expenses</field>
|
||||||
|
<field name="default_code">1-3CV/5-20000km</field>
|
||||||
|
<field name="categ_id" ref="hr_expense.cat_expense"/>
|
||||||
|
<field name="sale_ok" eval="False"/>
|
||||||
|
<field name="purchase_ok" eval="False"/>
|
||||||
|
<field name="can_be_expensed" eval="False"/>
|
||||||
|
<field name="private_car_expense_ok" eval="True"/>
|
||||||
|
<field name="type">service</field>
|
||||||
|
<field name="list_price">0</field>
|
||||||
|
<field name="standard_price">0.245</field>
|
||||||
|
<field name="uom_id" ref="product.product_uom_km"/>
|
||||||
|
<field name="uom_po_id" ref="product.product_uom_km"/>
|
||||||
|
<field name="taxes_id" eval="False"/>
|
||||||
|
<field name="supplier_taxes_id" eval="False"/>
|
||||||
|
</record>
|
||||||
|
|
||||||
|
<record id="4cv_5-20000km_private_car_expense" model="product.product">
|
||||||
|
<field name="name">4CV 5-20000km Private Car Expenses</field>
|
||||||
|
<field name="default_code">4CV/5-20000km</field>
|
||||||
|
<field name="categ_id" ref="hr_expense.cat_expense"/>
|
||||||
|
<field name="sale_ok" eval="False"/>
|
||||||
|
<field name="purchase_ok" eval="False"/>
|
||||||
|
<field name="can_be_expensed" eval="False"/>
|
||||||
|
<field name="private_car_expense_ok" eval="True"/>
|
||||||
|
<field name="type">service</field>
|
||||||
|
<field name="list_price">0</field>
|
||||||
|
<field name="standard_price">0.277</field>
|
||||||
|
<field name="uom_id" ref="product.product_uom_km"/>
|
||||||
|
<field name="uom_po_id" ref="product.product_uom_km"/>
|
||||||
|
<field name="taxes_id" eval="False"/>
|
||||||
|
<field name="supplier_taxes_id" eval="False"/>
|
||||||
|
</record>
|
||||||
|
|
||||||
|
<record id="5cv_5-20000km_private_car_expense" model="product.product">
|
||||||
|
<field name="name">5CV 5-20000km Private Car Expenses</field>
|
||||||
|
<field name="default_code">5CV/5-20000km</field>
|
||||||
|
<field name="categ_id" ref="hr_expense.cat_expense"/>
|
||||||
|
<field name="sale_ok" eval="False"/>
|
||||||
|
<field name="purchase_ok" eval="False"/>
|
||||||
|
<field name="can_be_expensed" eval="False"/>
|
||||||
|
<field name="private_car_expense_ok" eval="True"/>
|
||||||
|
<field name="type">service</field>
|
||||||
|
<field name="list_price">0</field>
|
||||||
|
<field name="standard_price">0.305</field>
|
||||||
|
<field name="uom_id" ref="product.product_uom_km"/>
|
||||||
|
<field name="uom_po_id" ref="product.product_uom_km"/>
|
||||||
|
<field name="taxes_id" eval="False"/>
|
||||||
|
<field name="supplier_taxes_id" eval="False"/>
|
||||||
|
</record>
|
||||||
|
|
||||||
|
<record id="6cv_5-20000km_private_car_expense" model="product.product">
|
||||||
|
<field name="name">6CV 5-20000km Private Car Expenses</field>
|
||||||
|
<field name="default_code">6CV/5-20000km</field>
|
||||||
|
<field name="categ_id" ref="hr_expense.cat_expense"/>
|
||||||
|
<field name="sale_ok" eval="False"/>
|
||||||
|
<field name="purchase_ok" eval="False"/>
|
||||||
|
<field name="can_be_expensed" eval="False"/>
|
||||||
|
<field name="private_car_expense_ok" eval="True"/>
|
||||||
|
<field name="type">service</field>
|
||||||
|
<field name="list_price">0</field>
|
||||||
|
<field name="standard_price">0.32</field>
|
||||||
|
<field name="uom_id" ref="product.product_uom_km"/>
|
||||||
|
<field name="uom_po_id" ref="product.product_uom_km"/>
|
||||||
|
<field name="taxes_id" eval="False"/>
|
||||||
|
<field name="supplier_taxes_id" eval="False"/>
|
||||||
|
</record>
|
||||||
|
|
||||||
|
<record id="7cv+_5-20000km_private_car_expense" model="product.product">
|
||||||
|
<field name="name">7CV+ 5-20000km Private Car Expenses</field>
|
||||||
|
<field name="default_code">7CV+/5-20000km</field>
|
||||||
|
<field name="categ_id" ref="hr_expense.cat_expense"/>
|
||||||
|
<field name="sale_ok" eval="False"/>
|
||||||
|
<field name="purchase_ok" eval="False"/>
|
||||||
|
<field name="can_be_expensed" eval="False"/>
|
||||||
|
<field name="private_car_expense_ok" eval="True"/>
|
||||||
|
<field name="type">service</field>
|
||||||
|
<field name="list_price">0</field>
|
||||||
|
<field name="standard_price">0.337</field>
|
||||||
|
<field name="uom_id" ref="product.product_uom_km"/>
|
||||||
|
<field name="uom_po_id" ref="product.product_uom_km"/>
|
||||||
|
<field name="taxes_id" eval="False"/>
|
||||||
|
<field name="supplier_taxes_id" eval="False"/>
|
||||||
|
</record>
|
||||||
|
|
||||||
|
<record id="1-3cv_20000km+_private_car_expense" model="product.product">
|
||||||
|
<field name="name">1-3CV 20000km+ Private Car Expenses</field>
|
||||||
|
<field name="default_code">1-3CV/20000km+</field>
|
||||||
|
<field name="categ_id" ref="hr_expense.cat_expense"/>
|
||||||
|
<field name="sale_ok" eval="False"/>
|
||||||
|
<field name="purchase_ok" eval="False"/>
|
||||||
|
<field name="can_be_expensed" eval="False"/>
|
||||||
|
<field name="private_car_expense_ok" eval="True"/>
|
||||||
|
<field name="type">service</field>
|
||||||
|
<field name="list_price">0</field>
|
||||||
|
<field name="standard_price">0.286</field>
|
||||||
|
<field name="uom_id" ref="product.product_uom_km"/>
|
||||||
|
<field name="uom_po_id" ref="product.product_uom_km"/>
|
||||||
|
<field name="taxes_id" eval="False"/>
|
||||||
|
<field name="supplier_taxes_id" eval="False"/>
|
||||||
|
</record>
|
||||||
|
|
||||||
|
<record id="4cv_20000km+_private_car_expense" model="product.product">
|
||||||
|
<field name="name">4CV 20000km+ Private Car Expenses</field>
|
||||||
|
<field name="default_code">4CV/20000km+</field>
|
||||||
|
<field name="categ_id" ref="hr_expense.cat_expense"/>
|
||||||
|
<field name="sale_ok" eval="False"/>
|
||||||
|
<field name="purchase_ok" eval="False"/>
|
||||||
|
<field name="can_be_expensed" eval="False"/>
|
||||||
|
<field name="private_car_expense_ok" eval="True"/>
|
||||||
|
<field name="type">service</field>
|
||||||
|
<field name="list_price">0</field>
|
||||||
|
<field name="standard_price">0.332</field>
|
||||||
|
<field name="uom_id" ref="product.product_uom_km"/>
|
||||||
|
<field name="uom_po_id" ref="product.product_uom_km"/>
|
||||||
|
<field name="taxes_id" eval="False"/>
|
||||||
|
<field name="supplier_taxes_id" eval="False"/>
|
||||||
|
</record>
|
||||||
|
|
||||||
|
<record id="5cv_20000km+_private_car_expense" model="product.product">
|
||||||
|
<field name="name">5CV 20000km+ Private Car Expenses</field>
|
||||||
|
<field name="default_code">5CV/20000km+</field>
|
||||||
|
<field name="categ_id" ref="hr_expense.cat_expense"/>
|
||||||
|
<field name="sale_ok" eval="False"/>
|
||||||
|
<field name="purchase_ok" eval="False"/>
|
||||||
|
<field name="can_be_expensed" eval="False"/>
|
||||||
|
<field name="private_car_expense_ok" eval="True"/>
|
||||||
|
<field name="type">service</field>
|
||||||
|
<field name="list_price">0</field>
|
||||||
|
<field name="standard_price">0.364</field>
|
||||||
|
<field name="uom_id" ref="product.product_uom_km"/>
|
||||||
|
<field name="uom_po_id" ref="product.product_uom_km"/>
|
||||||
|
<field name="taxes_id" eval="False"/>
|
||||||
|
<field name="supplier_taxes_id" eval="False"/>
|
||||||
|
</record>
|
||||||
|
|
||||||
|
<record id="6cv_20000km+_private_car_expense" model="product.product">
|
||||||
|
<field name="name">6CV 20000km+ Private Car Expenses</field>
|
||||||
|
<field name="default_code">6CV/20000km+</field>
|
||||||
|
<field name="categ_id" ref="hr_expense.cat_expense"/>
|
||||||
|
<field name="sale_ok" eval="False"/>
|
||||||
|
<field name="purchase_ok" eval="False"/>
|
||||||
|
<field name="can_be_expensed" eval="False"/>
|
||||||
|
<field name="private_car_expense_ok" eval="True"/>
|
||||||
|
<field name="type">service</field>
|
||||||
|
<field name="list_price">0</field>
|
||||||
|
<field name="standard_price">0.382</field>
|
||||||
|
<field name="uom_id" ref="product.product_uom_km"/>
|
||||||
|
<field name="uom_po_id" ref="product.product_uom_km"/>
|
||||||
|
<field name="taxes_id" eval="False"/>
|
||||||
|
<field name="supplier_taxes_id" eval="False"/>
|
||||||
|
</record>
|
||||||
|
|
||||||
|
<record id="7cv+_20000km+_private_car_expense" model="product.product">
|
||||||
|
<field name="name">7CV+ 20000km+ Private Car Expenses</field>
|
||||||
|
<field name="default_code">7CV+/20000km+</field>
|
||||||
|
<field name="categ_id" ref="hr_expense.cat_expense"/>
|
||||||
|
<field name="sale_ok" eval="False"/>
|
||||||
|
<field name="purchase_ok" eval="False"/>
|
||||||
|
<field name="can_be_expensed" eval="False"/>
|
||||||
|
<field name="private_car_expense_ok" eval="True"/>
|
||||||
|
<field name="type">service</field>
|
||||||
|
<field name="list_price">0</field>
|
||||||
|
<field name="standard_price">0.401</field>
|
||||||
|
<field name="uom_id" ref="product.product_uom_km"/>
|
||||||
|
<field name="uom_po_id" ref="product.product_uom_km"/>
|
||||||
|
<field name="taxes_id" eval="False"/>
|
||||||
|
<field name="supplier_taxes_id" eval="False"/>
|
||||||
|
</record>
|
||||||
|
|
||||||
|
|
||||||
|
</odoo>
|
||||||
30
hr_expense_usability/private_car_demo.xml
Normal file
30
hr_expense_usability/private_car_demo.xml
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
<?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 noupdate="1">
|
||||||
|
|
||||||
|
<record id="hr.employee_root" model="hr.employee">
|
||||||
|
<field name="private_car_plate">OD 4212 OO</field>
|
||||||
|
<field name="private_car_product_id" ref="5cv_0-5000km_private_car_expense"/>
|
||||||
|
</record>
|
||||||
|
|
||||||
|
<record id="hr.employee_mit" model="hr.employee">
|
||||||
|
<field name="private_car_plate">OE 1234 EO</field>
|
||||||
|
<field name="private_car_product_id" ref="6cv_0-5000km_private_car_expense"/>
|
||||||
|
</record>
|
||||||
|
|
||||||
|
<record id="hr.employee_al" model="hr.employee">
|
||||||
|
<field name="private_car_plate">BE 6543 AL</field>
|
||||||
|
<field name="private_car_product_id" ref="4cv_0-5000km_private_car_expense"/>
|
||||||
|
</record>
|
||||||
|
|
||||||
|
<record id="hr.employee_qdp" model="hr.employee">
|
||||||
|
<field name="private_car_plate">BE 1235 QD</field>
|
||||||
|
<field name="private_car_product_id" ref="4cv_0-5000km_private_car_expense"/>
|
||||||
|
</record>
|
||||||
|
|
||||||
|
</odoo>
|
||||||
47
hr_expense_usability/product_view.xml
Normal file
47
hr_expense_usability/product_view.xml
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
<?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="view_product_hr_expense_form" model="ir.ui.view">
|
||||||
|
<field name="name">private.car.expense.product.template.form</field>
|
||||||
|
<field name="model">product.template</field>
|
||||||
|
<field name="inherit_id" ref="hr_expense.view_product_hr_expense_form"/>
|
||||||
|
<field name="arch" type="xml">
|
||||||
|
<div name="options" position="inside">
|
||||||
|
<div name="private_car_expense">
|
||||||
|
<field name="private_car_expense_ok"/>
|
||||||
|
<label for="private_car_expense_ok"/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</field>
|
||||||
|
</record>
|
||||||
|
|
||||||
|
<record id="product_template_search_view" model="ir.ui.view">
|
||||||
|
<field name="name">private.car.expense.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">
|
||||||
|
<filter name="filter_to_purchase" position="after">
|
||||||
|
<filter name="can_be_expensed" domain="[('can_be_expensed', '=', True)]"
|
||||||
|
string="Can be Expensed"/>
|
||||||
|
<filter string="Private Car Expense" name="private_car_expense_ok"
|
||||||
|
domain="[('private_car_expense_ok', '=', 1)]"/>
|
||||||
|
</filter>
|
||||||
|
</field>
|
||||||
|
</record>
|
||||||
|
|
||||||
|
<record id="private_car_product_action" model="ir.actions.act_window">
|
||||||
|
<field name="name">Private Car Expenses</field>
|
||||||
|
<field name="res_model">product.product</field>
|
||||||
|
<field name="view_mode">tree,form,kanban</field>
|
||||||
|
<field name="context">{'default_private_car_expense_ok': 1, 'search_default_private_car_expense_ok': 1}</field>
|
||||||
|
</record>
|
||||||
|
|
||||||
|
<menuitem id="private_car_product_menu" parent="hr_expense.menu_hr_expense_configuration"
|
||||||
|
action="private_car_product_action" groups="hr_expense.group_hr_expense_manager"/>
|
||||||
|
|
||||||
|
</odoo>
|
||||||
@@ -1,24 +1,19 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<openerp>
|
<odoo noupdate="1">
|
||||||
<data noupdate="0">
|
|
||||||
|
|
||||||
<!--
|
<record id="expense_sheet_employee" model="ir.rule">
|
||||||
Employee : only see his expenses
|
<field name="name">Employee Expense Sheets</field>
|
||||||
HR Officer = the manager of some employees : see his expenses and the ones of his subordinates
|
<field name="model_id" ref="hr_expense.model_hr_expense_sheet"/>
|
||||||
HR Manager = person that administrates the expense process : can see everything
|
<field name="domain_force">[('employee_id.user_id', '=', user.id)]</field>
|
||||||
-->
|
<field name="groups" eval="[(4, ref('base.group_user'))]"/>
|
||||||
|
|
||||||
<!-- inherit native ir.rule ; remove HR Officer from 1=1 rule -->
|
|
||||||
<record id="hr_expense.property_rule_expense_manager" model="ir.rule">
|
|
||||||
<field name="groups" eval="[(6, 0, [ref('base.group_hr_manager')])]"/>
|
|
||||||
</record>
|
</record>
|
||||||
|
|
||||||
<record id="hr_expense_officer_see_subordinates" model="ir.rule">
|
<record id="expense_sheet_manager" model="ir.rule">
|
||||||
<field name="name">HR Officer can see expenses of his subordinates</field>
|
<field name="name">Manager Expense Sheets</field>
|
||||||
<field name="model_id" ref="hr_expense.model_hr_expense_expense"/>
|
<field name="model_id" ref="hr_expense.model_hr_expense_sheet"/>
|
||||||
<field name="domain_force">['|', ('employee_id.user_id','=',user.id), ('employee_id','child_of',user.employee_ids.ids)]</field>
|
<field name="domain_force">[(1, '=', 1)]</field>
|
||||||
<field name="groups" eval="[(4, ref('base.group_hr_user'))]"/>
|
<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>
|
||||||
|
|
||||||
</data>
|
|
||||||
</openerp>
|
</odoo>
|
||||||
|
|||||||
Reference in New Issue
Block a user