[FIX] purchase_stock: discount on invoice
- Create a product P Costing Method: FIFO Inventory Valuation: Perpetual (automated) Price Difference Account set - Create a PO with P, set a price of 100 (no tax). - Receive the product 2 journal items are generated: | Account | Debit| Credit| |-------------------------|--------|--------| | Stock Valuation | 100.0| 0.0| | Stock Interim (Received)| 0.0| 100.0| - Create the corresponding invoice - Change the: Discount: 10 - Validate the invoice (for a total of 90.0) 2 journal items are generated: | Account | Debit| Credit| |-------------------------|--------|--------| | Account Payable | 0.0| 90.0| | Stock Interim (Received)| 90.0| 0.0| This is not correct, it should be: | Account | Debit| Credit| |-------------------------|--------|--------| | Account Payable | 0.0| 90.0| | Difference Account | 0.0| 10.0| | Stock Interim (Received)| 100.0| 0.0| This comes from the fact that the valuation price is compared to the price unit without the discount. opw-1974002 closes odoo/odoo#33296 Signed-off-by: Nicolas Martinelli (nim) <nim@odoo.com>
This commit is contained in:
@@ -96,26 +96,25 @@ class AccountInvoice(models.Model):
|
||||
interim_account_price = valuation_price_unit * line['quantity']
|
||||
invoice_cur_prec = inv.currency_id.decimal_places
|
||||
|
||||
if float_compare(valuation_price_unit, i_line.price_unit, precision_digits=invoice_cur_prec) != 0 and float_compare(line['price_unit'], i_line.price_unit, precision_digits=invoice_cur_prec) == 0:
|
||||
|
||||
# price with discount and without tax included
|
||||
price_unit = i_line.price_unit * (1 - (i_line.discount or 0.0) / 100.0)
|
||||
tax_ids = []
|
||||
if line['tax_ids']:
|
||||
#line['tax_ids'] is like [(4, tax_id, None), (4, tax_id2, None)...]
|
||||
taxes = self.env['account.tax'].browse([x[1] for x in line['tax_ids']])
|
||||
price_unit = taxes.compute_all(price_unit, currency=inv.currency_id, quantity=1.0)['total_excluded']
|
||||
for tax in taxes:
|
||||
tax_ids.append((4, tax.id, None))
|
||||
for child in tax.children_tax_ids:
|
||||
if child.type_tax_use != 'none':
|
||||
tax_ids.append((4, child.id, None))
|
||||
# price with discount and without tax included
|
||||
price_unit = i_line.price_unit * (1 - (i_line.discount or 0.0) / 100.0)
|
||||
tax_ids = []
|
||||
if line['tax_ids']:
|
||||
#line['tax_ids'] is like [(4, tax_id, None), (4, tax_id2, None)...]
|
||||
taxes = self.env['account.tax'].browse([x[1] for x in line['tax_ids']])
|
||||
price_unit = taxes.compute_all(price_unit, currency=inv.currency_id, quantity=1.0)['total_excluded']
|
||||
for tax in taxes:
|
||||
tax_ids.append((4, tax.id, None))
|
||||
for child in tax.children_tax_ids:
|
||||
if child.type_tax_use != 'none':
|
||||
tax_ids.append((4, child.id, None))
|
||||
|
||||
if float_compare(valuation_price_unit, price_unit, precision_digits=invoice_cur_prec) != 0 and float_compare(line['price_unit'], i_line.price_unit, precision_digits=invoice_cur_prec) == 0:
|
||||
price_before = line.get('price', 0.0)
|
||||
price_unit_val_dif = price_unit - valuation_price_unit
|
||||
|
||||
price_val_dif = price_before - interim_account_price
|
||||
if inv.currency_id.compare_amounts(i_line.price_unit, valuation_price_unit) != 0 and acc:
|
||||
if inv.currency_id.compare_amounts(price_unit, valuation_price_unit) != 0 and acc:
|
||||
# If the unit prices have not changed and we have a
|
||||
# valuation difference, it means this difference is due to exchange rates,
|
||||
# so we don't create anything, the exchange rate entries will
|
||||
|
||||
@@ -1168,3 +1168,101 @@ class TestStockValuationWithCOA(AccountingTestCase):
|
||||
self.assertEquals(len(input_aml), 2, "Only two lines should have been generated in stock input account: one when receiving the product, one when making the invoice.")
|
||||
self.assertAlmostEquals(sum(input_aml.mapped('debit')), 110, "Total debit value on stock input account should be equal to the original PO price of the product.")
|
||||
self.assertAlmostEquals(sum(input_aml.mapped('credit')), 110, "Total credit value on stock input account should be equal to the original PO price of the product.")
|
||||
|
||||
def test_anglosaxon_valuation_discount(self):
|
||||
"""
|
||||
PO: price unit: 100
|
||||
Inv: price unit: 100
|
||||
discount: 10
|
||||
"""
|
||||
self.env.user.company_id.anglo_saxon_accounting = True
|
||||
self.product1.product_tmpl_id.cost_method = 'fifo'
|
||||
self.product1.product_tmpl_id.valuation = 'real_time'
|
||||
self.product1.product_tmpl_id.invoice_policy = 'delivery'
|
||||
self.product1.property_account_creditor_price_difference = self.price_diff_account
|
||||
|
||||
# Create PO
|
||||
po_form = Form(self.env['purchase.order'])
|
||||
po_form.partner_id = self.partner_id
|
||||
with po_form.order_line.new() as po_line:
|
||||
po_line.product_id = self.product1
|
||||
po_line.product_qty = 1
|
||||
po_line.price_unit = 100.0
|
||||
order = po_form.save()
|
||||
order.button_confirm()
|
||||
|
||||
# Receive the goods
|
||||
receipt = order.picking_ids[0]
|
||||
receipt.move_lines.quantity_done = 1
|
||||
receipt.button_validate()
|
||||
|
||||
# Create an invoice with a different price and a discount
|
||||
invoice = self.env['account.invoice'].create({
|
||||
'partner_id': order.partner_id.id,
|
||||
'purchase_id': order.id,
|
||||
'account_id': order.partner_id.property_account_payable_id.id,
|
||||
'type': 'in_invoice',
|
||||
})
|
||||
invoice.purchase_order_change()
|
||||
invoice.invoice_line_ids[0].discount = 10.0
|
||||
invoice.action_invoice_open()
|
||||
|
||||
# Check what was posted in the price difference account
|
||||
price_diff_aml = self.env['account.move.line'].search([('account_id','=', self.price_diff_account.id)])
|
||||
self.assertEquals(len(price_diff_aml), 1, "Only one line should have been generated in the price difference account.")
|
||||
self.assertAlmostEquals(price_diff_aml.credit, 10, "Price difference should be equal to 20 (110-90)")
|
||||
|
||||
# Check what was posted in stock input account
|
||||
input_aml = self.env['account.move.line'].search([('account_id','=', self.stock_input_account.id)])
|
||||
self.assertEquals(len(input_aml), 2, "Only two lines should have been generated in stock input account: one when receiving the product, one when making the invoice.")
|
||||
self.assertAlmostEquals(sum(input_aml.mapped('debit')), 100, "Total debit value on stock input account should be equal to the original PO price of the product.")
|
||||
self.assertAlmostEquals(sum(input_aml.mapped('credit')), 100, "Total credit value on stock input account should be equal to the original PO price of the product.")
|
||||
|
||||
def test_anglosaxon_valuation_price_unit_diff_discount(self):
|
||||
"""
|
||||
PO: price unit: 90
|
||||
Inv: price unit: 100
|
||||
discount: 10
|
||||
"""
|
||||
self.env.user.company_id.anglo_saxon_accounting = True
|
||||
self.product1.product_tmpl_id.cost_method = 'fifo'
|
||||
self.product1.product_tmpl_id.valuation = 'real_time'
|
||||
self.product1.product_tmpl_id.invoice_policy = 'delivery'
|
||||
self.product1.property_account_creditor_price_difference = self.price_diff_account
|
||||
|
||||
# Create PO
|
||||
po_form = Form(self.env['purchase.order'])
|
||||
po_form.partner_id = self.partner_id
|
||||
with po_form.order_line.new() as po_line:
|
||||
po_line.product_id = self.product1
|
||||
po_line.product_qty = 1
|
||||
po_line.price_unit = 90.0
|
||||
order = po_form.save()
|
||||
order.button_confirm()
|
||||
|
||||
# Receive the goods
|
||||
receipt = order.picking_ids[0]
|
||||
receipt.move_lines.quantity_done = 1
|
||||
receipt.button_validate()
|
||||
|
||||
# Create an invoice with a different price and a discount
|
||||
invoice = self.env['account.invoice'].create({
|
||||
'partner_id': order.partner_id.id,
|
||||
'purchase_id': order.id,
|
||||
'account_id': order.partner_id.property_account_payable_id.id,
|
||||
'type': 'in_invoice',
|
||||
})
|
||||
invoice.purchase_order_change()
|
||||
invoice.invoice_line_ids[0].price_unit = 100.0
|
||||
invoice.invoice_line_ids[0].discount = 10.0
|
||||
invoice.action_invoice_open()
|
||||
|
||||
# Check if something was posted in the price difference account
|
||||
price_diff_aml = self.env['account.move.line'].search([('account_id','=', self.price_diff_account.id)])
|
||||
self.assertEquals(len(price_diff_aml), 0, "No line should have been generated in the price difference account.")
|
||||
|
||||
# Check what was posted in stock input account
|
||||
input_aml = self.env['account.move.line'].search([('account_id','=', self.stock_input_account.id)])
|
||||
self.assertEquals(len(input_aml), 2, "Only two lines should have been generated in stock input account: one when receiving the product, one when making the invoice.")
|
||||
self.assertAlmostEquals(sum(input_aml.mapped('debit')), 90, "Total debit value on stock input account should be equal to the original PO price of the product.")
|
||||
self.assertAlmostEquals(sum(input_aml.mapped('credit')), 90, "Total credit value on stock input account should be equal to the original PO price of the product.")
|
||||
|
||||
Reference in New Issue
Block a user