Skip to content
Permalink
Browse files

Phew, that's a big one

  • Loading branch information...
kebeclibre committed Apr 2, 2019
1 parent 05da627 commit adf218066ab07d3207c93b80055cb162a0e17de3
@@ -177,6 +177,7 @@ def _anglo_saxon_purchase_move_lines(self, i_line, res):
for val_stock_move in valuation_stock_move:
valuation_price_unit_total += abs(val_stock_move.price_unit) * val_stock_move.product_qty
valuation_total_qty += val_stock_move.product_qty

# in Stock Move price unit is in company_currency
valuation_price_unit = valuation_price_unit_total / valuation_total_qty
valuation_price_unit = i_line.product_id.uom_id._compute_price(valuation_price_unit, i_line.uom_id)
@@ -188,7 +189,7 @@ def _anglo_saxon_purchase_move_lines(self, i_line, res):
if order_id.currency_id != order_id.company_id.currency_id:
valuation_price_unit = (
order_id.currency_id
.with_context(date=i_line.purchase_line_id.date_planned)
.with_context(date=i_line.purchase_line_id.order_id.date_approve)
.compute(valuation_price_unit, order_id.company_id.currency_id, round=False)
)

@@ -705,7 +705,7 @@ def _get_stock_move_price_unit(self):
if line.product_uom.id != line.product_id.uom_id.id:
price_unit *= line.product_uom.factor / line.product_id.uom_id.factor
if order.currency_id != order.company_id.currency_id:
price_unit = order.currency_id.compute(price_unit, order.company_id.currency_id, round=False)
price_unit = order.currency_id.with_context(date=order.date_approve).compute(price_unit, order.company_id.currency_id, round=False)
return price_unit

@api.multi
@@ -725,7 +725,7 @@ def _prepare_stock_moves(self, picking):
'name': self.name or '',
'product_id': self.product_id.id,
'product_uom': self.product_uom.id,
'date': self.order_id.date_order,
'date': self.order_id.date_approve,
'date_expected': self.date_planned,
'location_id': self.order_id.partner_id.property_stock_supplier.id,
'location_dest_id': self.order_id._get_destination_location(),
@@ -46,7 +46,7 @@ def _get_price_unit(self):
if line.product_uom.id != line.product_id.uom_id.id:
price_unit *= line.product_uom.factor / line.product_id.uom_id.factor
if order.currency_id != order.company_id.currency_id:
price_unit = order.currency_id.compute(price_unit, order.company_id.currency_id, round=False)
price_unit = order.currency_id.with_context(date=self.date or order.date_approve).compute(price_unit, order.company_id.currency_id, round=False)
return price_unit
return super(StockMove, self)._get_price_unit()

@@ -3,6 +3,7 @@

import time
from datetime import datetime
from unittest.mock import patch

from odoo.tests.common import TransactionCase
from odoo.addons.account.tests.account_test_classes import AccountingTestCase
@@ -140,6 +141,7 @@ def test_change_currency_rate_average_1(self):
the currency rate, validate the receipt and then check that the value of the received goods
is set according to the last currency rate.
"""
self.env['res.currency.rate'].search([]).unlink()
usd_currency = self.env.ref('base.USD')
self.env.user.company_id.currency_id = usd_currency.id

@@ -495,7 +497,7 @@ def test_average_realtime_anglo_saxon_valuation_multicurrency_same_date(self):
self.assertEqual(stock_line.amount_currency, 100.0)
self.assertAlmostEqual(stock_line.balance, 66.67)

def test_average_realtime_anglo_saxon_valuation_multicurrency_different_dates(self):
def test_realtime_anglo_saxon_valuation_multicurrency_different_dates(self):
"""
The PO and invoice are in the same foreign currency.
The PO is invoiced at a later date than its creation.
@@ -526,15 +528,6 @@ def test_average_realtime_anglo_saxon_valuation_multicurrency_different_dates(se
'property_account_creditor_price_difference': self.price_diff_account.id
}).product_variant_id

# SetUp product FIFO
# same as average, but with stock moves :D
product_fifo = self.product1.product_tmpl_id.copy({
'cost_method': 'fifo',
'name': 'Standard Val',
'standard_price': 60,
'property_account_creditor_price_difference': self.price_diff_account.id
}).product_variant_id

# SetUp currency and rates
self.cr.execute("UPDATE res_company SET currency_id = %s WHERE id = %s", (self.usd_currency.id, company.id))
self.env['res.currency.rate'].search([]).unlink()
@@ -559,6 +552,16 @@ def test_average_realtime_anglo_saxon_valuation_multicurrency_different_dates(se
'company_id': company.id,
})

# To allow testing validation of PO
def _today(*args, **kwargs):
return date_po
patchers = [
patch('odoo.fields.Date.context_today', _today),
]

for p in patchers:
p.start()

# Proceed
po = self.env['purchase.order'].create({
'currency_id': self.eur_currency.id,
@@ -579,7 +582,7 @@ def test_average_realtime_anglo_saxon_valuation_multicurrency_different_dates(se
'product_uom': product_standard.uom_po_id.id,
'price_unit': 40.0,
'date_planned': date_po,
})
}),
],
})
po.button_confirm()
@@ -613,33 +616,36 @@ def test_average_realtime_anglo_saxon_valuation_multicurrency_different_dates(se
'purchase_line_id': line_product_standard.id,
'quantity': 1.0,
'account_id': self.stock_input_account.id,
})]
})
]
})

inv.action_invoice_open()

move_lines = inv.move_id.line_ids
import pudb;pu.db
for p in patchers:
p.stop()

move_lines = inv.move_id.line_ids
self.assertEqual(len(move_lines), 5)

for p in products:
m_lines = move_line_ids.filtered
self.assertEqual(len(move_lines), 3)
# PAYABLE CHECK
payable_line = move_lines.filtered(lambda l: l.account_id.internal_type == 'payable')
self.assertEqual(payable_line.amount_currency, -170.0)
self.assertAlmostEqual(payable_line.balance, -85.00)

# PRODUCTS CHECKS

# EXCHANGE DIFFERENCE (average)
# We ordered for a value of 100 EUR
# But by the time we are invoiced for it
# the foreign currency appreciated from 1.5 to 2.0
# We still have to pay 100 EUR, which now values at 50 USD
payable_line = move_lines.filtered(lambda l: l.account_id.internal_type == 'payable')
self.assertEqual(payable_line.amount_currency, -100.0)
self.assertAlmostEqual(payable_line.balance, -50.00)
product_lines = move_lines.filtered(lambda l: l.product_id == self.product1)

# Stock-wise, we have been invoiced 100 EUR
# which in the past valued at 100 * 1/1.5 = 66.66 USD
# However, those 66.66 USD now have a value of 133.33 EUR
stock_line = move_lines.filtered(lambda l: l.account_id == self.stock_input_account)
stock_line = product_lines.filtered(lambda l: l.account_id == self.stock_input_account)
self.assertEqual(stock_line.amount_currency, 133.33)
self.assertAlmostEqual(stock_line.balance, 66.67)

@@ -648,6 +654,165 @@ def test_average_realtime_anglo_saxon_valuation_multicurrency_different_dates(se
# The stock "gained" 33.33 EUR in value
# in this case all due to the currency appreciation
# which have a today value of 16.67 USD
price_diff_line = move_lines.filtered(lambda l: l.account_id == self.price_diff_account)
price_diff_line = product_lines.filtered(lambda l: l.account_id == self.price_diff_account)
self.assertEqual(price_diff_line.amount_currency, -33.33)
self.assertAlmostEqual(price_diff_line.balance, -16.67)

# PRICE DIFFERENCE (STANDARD)
# We ordered a product that should have cost 60 USD (120 EUR)
# However, we effectively got invoiced 70 EUR (35 USD)
product_lines = move_lines.filtered(lambda l: l.product_id == product_standard)

stock_line = product_lines.filtered(lambda l: l.account_id == self.stock_input_account)
self.assertEqual(stock_line.amount_currency, 120.00)
self.assertAlmostEqual(stock_line.balance, 60.00)

price_diff_line = product_lines.filtered(lambda l: l.account_id == self.price_diff_account)
self.assertEqual(price_diff_line.amount_currency, -50.00)
self.assertAlmostEqual(price_diff_line.balance, -25.00)

def test_fifo_realtime_anglo_saxon_valuation_multicurrency_different_dates(self):
"""
The PO and invoice are in the same foreign currency.
The PO is invoiced at a later date than its creation.
This should create a price difference entry.
"""
company = self.env.user.company_id
company.anglo_saxon_accounting = True

date_po = '2019-01-01'
date_delivery = '2019-01-08'
date_invoice = '2019-01-16'

product_fifo = self.product1.product_tmpl_id.copy({
'valuation': 'real_time',
'invoice_policy': 'order',
'purchase_method': 'purchase',
'cost_method': 'fifo',
'name': 'FIFO',
'standard_price': 60,
'property_account_creditor_price_difference': self.price_diff_account.id
}).product_variant_id

# SetUp currency and rates
self.cr.execute("UPDATE res_company SET currency_id = %s WHERE id = %s", (self.usd_currency.id, company.id))
self.env['res.currency.rate'].search([]).unlink()
self.env['res.currency.rate'].create({
'name': date_po,
'rate': 1.0,
'currency_id': self.usd_currency.id,
'company_id': company.id,
})

self.env['res.currency.rate'].create({
'name': date_po,
'rate': 1.5,
'currency_id': self.eur_currency.id,
'company_id': company.id,
})

self.env['res.currency.rate'].create({
'name': date_delivery,
'rate': 0.7,
'currency_id': self.eur_currency.id,
'company_id': company.id,
})

self.env['res.currency.rate'].create({
'name': date_invoice,
'rate': 2,
'currency_id': self.eur_currency.id,
'company_id': company.id,
})

# To allow testing validation of PO
def _today(*args, **kwargs):
return date_po
# To allow testing validation of Delivery
def _now(*args, **kwargs):
return date_delivery + ' 01:00:00'

patchers = [
patch('odoo.fields.Date.context_today', _today),
patch('odoo.fields.Datetime.now', _now),
]

for p in patchers:
p.start()

# Proceed
po = self.env['purchase.order'].create({
'currency_id': self.eur_currency.id,
'partner_id': self.partner_id.id,
'order_line': [
(0, 0, {
'name': product_fifo.name,
'product_id': product_fifo.id,
'product_qty': 1.0,
'product_uom': product_fifo.uom_po_id.id,
'price_unit': 30.0,
'date_planned': date_po,
})
],
})
po.button_confirm()

line_product_fifo = po.order_line.filtered(lambda l: l.product_id == product_fifo)

picking = po.picking_ids
(picking.move_lines
.filtered(lambda l: l.purchase_line_id == line_product_fifo)
.write({'quantity_done': 1.0}))

picking.button_validate()

inv = self.env['account.invoice'].create({
'type': 'in_invoice',
'date_invoice': date_invoice,
'currency_id': self.eur_currency.id,
'purchase_id': po.id,
'partner_id': self.partner_id.id,
'invoice_line_ids': [
(0, 0, {
'name': product_fifo.name,
'price_subtotal': 30.0,
'price_unit': 30.0,
'product_id': product_fifo.id,
'purchase_id': po.id,
'purchase_line_id': line_product_fifo.id,
'quantity': 1.0,
'account_id': self.stock_input_account.id,
})
]
})

inv.action_invoice_open()

for p in patchers:
p.stop()

move_lines = inv.move_id.line_ids
self.assertEqual(len(move_lines), 3)

# PAYABLE CHECK
payable_line = move_lines.filtered(lambda l: l.account_id.internal_type == 'payable')
self.assertEqual(payable_line.amount_currency, -30.0)
self.assertAlmostEqual(payable_line.balance, -15.00)

# PRODUCTS CHECKS

# DELIVERY DIFFERENCE (FIFO)
# We ordered a product at 30 EUR valued at 20 USD
# We received it when the exchange rate has appreciated
# So, the actualized 20 USD are now 20*1.5/0.7 = 42.857 USD
# At invoice time, it amounts to 85.71 EUR
product_lines = move_lines.filtered(lambda l: l.product_id == product_fifo)

# The value of the stock is then 42.86 USD
stock_line = product_lines.filtered(lambda l: l.account_id == self.stock_input_account)
self.assertEqual(stock_line.amount_currency, 85.71)
self.assertAlmostEqual(stock_line.balance, 42.86)

price_diff_line = product_lines.filtered(lambda l: l.account_id == self.price_diff_account)
self.assertEqual(price_diff_line.amount_currency, -55.71)
self.assertAlmostEqual(price_diff_line.balance, -27.86)

0 comments on commit adf2180

Please sign in to comment.
You can’t perform that action at this time.