[IMP] sale,hr_expense: simplify invoice policy, 2 options instead of 3

The invoice_policy 'time & material' has been replaced by an
    expense_policy!='no', with invoice_policy='delivery'.
This commit is contained in:
Fabien Pinckaers
2016-05-22 15:57:33 +02:00
parent 26603b0877
commit 48ea59d46e
14 changed files with 42 additions and 98 deletions
+2 -1
View File
@@ -7,4 +7,5 @@ from openerp import fields, models
class ProductTemplate(models.Model):
_inherit = "product.template"
can_be_expensed = fields.Boolean(help="Specify whether the product can be selected in an HR expense.")
can_be_expensed = fields.Boolean(help="Specify whether the product can be selected in an HR expense.", string="Can be Expensed")
+1 -2
View File
@@ -71,8 +71,7 @@ class sale_configuration(osv.TransientModel):
'Advanced pricing based on formula: You can have all the rights on pricelist'),
'default_invoice_policy': fields.selection([
('order', 'Invoice ordered quantities'),
('delivery', 'Invoice delivered quantities'),
('cost', 'Invoice based on costs (time and material, expenses)')
('delivery', 'Invoice delivered quantities')
], 'Default Invoicing', default_model='product.template'),
'deposit_product_id_setting': fields.many2one('product.product', 'Deposit Product',\
domain="[('type', '=', 'service')]",\
+8 -17
View File
@@ -449,11 +449,6 @@ class SaleOrder(models.Model):
if self.env.context.get('send_email'):
self.force_quotation_send()
order.order_line._action_procurement_create()
if not order.project_id:
for line in order.order_line:
if line.product_id.invoice_policy == 'cost':
order._create_analytic_account()
break
if self.env['ir.values'].get_default('sale.config.settings', 'auto_done_setting'):
self.action_done()
return True
@@ -572,7 +567,7 @@ class SaleOrderLine(models.Model):
@api.depends('product_id.invoice_policy', 'order_id.state')
def _compute_qty_delivered_updateable(self):
for line in self:
line.qty_delivered_updateable = line.product_id.invoice_policy in ('order', 'delivery') and line.order_id.state == 'sale' and line.product_id.track_service == 'manual'
line.qty_delivered_updateable = line.order_id.state == 'sale' and line.product_id.track_service == 'manual'
@api.depends('qty_invoiced', 'qty_delivered', 'product_uom_qty', 'order_id.state')
def _get_to_invoice_qty(self):
@@ -671,10 +666,6 @@ class SaleOrderLine(models.Model):
new_procs.run()
return new_procs
@api.model
def _get_analytic_invoice_policy(self):
return ['cost']
@api.model
def _get_analytic_track_service(self):
return []
@@ -691,8 +682,7 @@ class SaleOrderLine(models.Model):
line = super(SaleOrderLine, self).create(values)
if line.state == 'sale':
if (not line.order_id.project_id and
(line.product_id.track_service in self._get_analytic_track_service() or
line.product_id.invoice_policy in self._get_analytic_invoice_policy())):
(line.product_id.track_service in self._get_analytic_track_service())):
line.order_id._create_analytic_account()
line._action_procurement_create()
@@ -1004,7 +994,10 @@ class ProductTemplate(models.Model):
default='manual')
sale_line_warn = fields.Selection(WARNING_MESSAGE, 'Sales Order Line', help=WARNING_HELP, required=True, default="no-message")
sale_line_warn_msg = fields.Text('Message for Sales Order Line')
expense_policy = fields.Selection(
[('no', 'No'), ('cost', 'At cost'), ('sales_price', 'At sale price')],
string='Re-Invoice Expenses',
default='no')
@api.multi
@api.depends('product_variant_ids.sales_count')
def _sales_count(self):
@@ -1033,8 +1026,6 @@ class ProductTemplate(models.Model):
invoice_policy = fields.Selection(
[('order', 'Ordered quantities'),
('delivery', 'Delivered quantities'),
('cost', 'Reinvoice Costs')],
string='Invoicing Policy', help='Ordered Quantity: Invoice based on the quantity the customer ordered.\n'
'Delivered Quantity: Invoiced based on the quantity the vendor delivered.\n'
'Reinvoice Costs: Invoice with some additional charges (product transfer, labour charges,...)',
], string='Invoicing Policy', help='Ordered Quantity: Invoice based on the quantity the customer ordered.\n'
'Delivered Quantity: Invoiced based on the quantity the vendor delivered (time or deliveries).',
default='order')
+22 -29
View File
@@ -40,6 +40,13 @@ class AccountAnalyticLine(models.Model):
so_line = fields.Many2one('sale.order.line', string='Sale Order Line')
def _get_invoice_price(self, order):
if self.product_id.expense_policy == 'sales_price':
return self.product_id.with_context(
partner=order.partner_id.id,
date_order=order.date_order,
pricelist=order.pricelist_id.id,
uom=self.product_uom_id.id
).price
if self.unit_amount == 0.0:
return 0.0
price_unit = abs(self.amount / self.unit_amount)
@@ -47,20 +54,12 @@ class AccountAnalyticLine(models.Model):
price_unit = self.currency_id.compute(price_unit, order.currency_id)
return price_unit
def _get_sale_order_line_vals(self):
order = self.env['sale.order'].search([('project_id', '=', self.account_id.id)], limit=1)
if not order:
return False
if order.state != 'sale':
raise UserError(_('The Sale Order %s linked to the Analytic Account must be validated before registering expenses.') % order.name)
def _get_sale_order_line_vals(self, order, price):
last_so_line = self.env['sale.order.line'].search([('order_id', '=', order.id)], order='sequence desc', limit=1)
last_sequence = last_so_line.sequence + 1 if last_so_line else 100
fpos = order.fiscal_position_id or order.partner_id.property_account_position_id
taxes = fpos.map_tax(self.product_id.taxes_id)
price = self._get_invoice_price(order)
return {
'order_id': order.id,
'name': self.name,
@@ -77,30 +76,24 @@ class AccountAnalyticLine(models.Model):
def _get_sale_order_line(self, vals=None):
result = dict(vals or {})
so_line = result.get('so_line', False) or self.so_line
if not so_line and self.account_id and self.product_id and self.product_id.invoice_policy in ('cost', 'order'):
if not so_line and self.account_id and self.product_id and (self.product_id.expense_policy!='no'):
order = self.env['sale.order'].search([('project_id', '=', self.account_id.id), ('state','=','sale')], limit=1)
if not order:
return result
price = self._get_invoice_price(order)
so_lines = self.env['sale.order.line'].search([
('order_id.project_id', '=', self.account_id.id),
('state', '=', 'sale'),
('order_id', '=', order.id),
('price_unit', '=', price),
('product_id', '=', self.product_id.id)])
# Use the existing SO line only if the unit prices are the same, otherwise we create
# a new line
for line in so_lines:
if line.product_id.invoice_policy != 'cost' or (line.product_id.invoice_policy == 'cost' and line.price_unit == self._get_invoice_price(line.order_id)):
result.update({'so_line': line.id})
so_line = line
break
if so_lines:
result.update({'so_line': so_lines[0].id})
else:
# This will trigger the creation of a new SO line
so_line = False
if not so_line and self.account_id and self.product_id and self.product_id.invoice_policy == 'cost':
order_line_vals = self._get_sale_order_line_vals()
if order_line_vals:
so_line = self.env['sale.order.line'].create(order_line_vals)
so_line._compute_tax_id()
result.update({'so_line': so_line.id})
order_line_vals = self._get_sale_order_line_vals(order, price)
if order_line_vals:
so_line = self.env['sale.order.line'].create(order_line_vals)
so_line._compute_tax_id()
result.update({'so_line': so_line.id})
return result
@api.multi
+1 -1
View File
@@ -146,7 +146,7 @@
</record>
<record id="product.service_cost_01" model="product.product">
<field name="invoice_policy">cost</field>
<field name="expense_policy">cost</field>
</record>
<record id="product.service_order_01" model="product.product">
+1 -1
View File
@@ -40,7 +40,7 @@ class TestSaleOrder(TestSale):
# deliver lines except 'time and material' then invoice again
for line in so.order_line:
line.qty_delivered = 2 if line.product_id.invoice_policy in ['order', 'delivery'] else 0
line.qty_delivered = 2 if line.product_id.expense_policy=='no' else 0
self.assertTrue(so.invoice_status == 'to invoice', 'Sale: SO status after delivery should be "to invoice"')
inv_id = so.action_invoice_create()
inv = inv_obj.browse(inv_id)
-1
View File
@@ -1,3 +1,2 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
import models
-4
View File
@@ -1,4 +0,0 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
import analytic
import product
-19
View File
@@ -1,19 +0,0 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from openerp import models
class AccountAnalyticLine(models.Model):
_inherit = "account.analytic.line"
def _get_invoice_price(self, order):
if self.product_id.invoice_policy == 'cost' and self.product_id.expense_policy == 'sales_price':
return self.product_id.with_context(
partner=order.partner_id.id,
date_order=order.date_order,
pricelist=order.pricelist_id.id,
uom=self.product_uom_id.id
).price
else:
return super(AccountAnalyticLine, self)._get_invoice_price(order)
-15
View File
@@ -1,15 +0,0 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from openerp import fields, models
class ProductProduct(models.Model):
_inherit = "product.template"
expense_policy = fields.Selection(
[('cost', 'At Cost'), ('sales_price', 'At Sales Price')],
string='Expense Invoice Policy',
help="If you invoice at cost, the expense will be invoiced on the sale order at the cost of the analytic line;"
"if you invoice at sales price, the price of the product will be used instead.",
default='cost')
+4 -4
View File
@@ -1,19 +1,19 @@
<?xml version="1.0" encoding="utf-8"?>
<openerp>
<data noupdate="1">
<record id="hr_expense.car_travel" model="product.product">
<field name="invoice_policy">cost</field>
<field name="invoice_policy">delivery</field>
<field name="expense_policy">sales_price</field>
</record>
<record id="hr_expense.air_ticket" model="product.product">
<field name="invoice_policy">cost</field>
<field name="invoice_policy">delivery</field>
<field name="expense_policy">cost</field>
</record>
<record id="hr_expense.hotel_rent" model="product.product">
<field name="invoice_policy">cost</field>
<field name="invoice_policy">delivery</field>
<field name="expense_policy">cost</field>
</record>
+1 -2
View File
@@ -7,9 +7,8 @@
<field name="arch" type="xml">
<field name="invoice_policy" position="after">
<field name="expense_policy" widget="radio"
attrs="{'invisible': [('invoice_policy','!=','cost')]}"/>
attrs="{'invisible': [('can_be_expensed','=',False)]}"/>
</field>
</field>
</record>
</odoo>
+1 -1
View File
@@ -285,7 +285,7 @@ class StockMove(models.Model):
# Update delivered quantities on sale order lines
todo = self.env['sale.order.line']
for move in self:
if (move.procurement_id.sale_line_id) and (move.product_id.invoice_policy in ('order', 'delivery')):
if (move.procurement_id.sale_line_id) and (move.product_id.expense_policy=='no'):
todo |= move.procurement_id.sale_line_id
for line in todo:
line.qty_delivered = line._get_delivered_qty()
@@ -33,7 +33,7 @@ class ProductTemplate(models.Model):
@api.onchange('type', 'invoice_policy')
def onchange_type_timesheet(self):
if self.type == 'service' and self.invoice_policy != 'cost':
if self.type == 'service':
self.track_service = 'timesheet'
else:
self.track_service = 'manual'