diff --git a/addons/purchase/report/purchase_report.py b/addons/purchase/report/purchase_report.py index 525fae40113..7aac1f26d82 100644 --- a/addons/purchase/report/purchase_report.py +++ b/addons/purchase/report/purchase_report.py @@ -5,7 +5,7 @@ # Please note that these reports are not multi-currency !!! # -from odoo import fields, models +from odoo import fields, models, api class PurchaseReport(models.Model): @@ -147,3 +147,29 @@ class PurchaseReport(models.Model): currency_table.rate """ return group_by_str + + @api.model + def read_group(self, domain, fields, groupby, offset=0, limit=None, orderby=False, lazy=True): + """ + This is a hack to allow us to correctly calculate the average price of product. + """ + if 'price_average:avg' in fields: + fields.extend(['aggregated_qty_ordered:array_agg(qty_ordered)']) + fields.extend(['aggregated_price_average:array_agg(price_average)']) + + res = [] + if fields: + res = super(PurchaseReport, self).read_group(domain, fields, groupby, offset=offset, limit=limit, orderby=orderby, lazy=lazy) + + if 'price_average:avg' in fields: + qties = 'aggregated_qty_ordered' + special_field = 'aggregated_price_average' + for data in res: + if data[special_field] and data[qties]: + total_unit_cost = sum(float(value) * float(qty) for value, qty in zip(data[special_field], data[qties]) if qty and value) + total_qty_ordered = sum(float(qty) for qty in data[qties] if qty) + data['price_average'] = (total_unit_cost / total_qty_ordered) if total_qty_ordered else 0 + del data[special_field] + del data[qties] + + return res diff --git a/addons/purchase/tests/test_purchase_order_report.py b/addons/purchase/tests/test_purchase_order_report.py index 2f060a7b571..0696dc5d10d 100644 --- a/addons/purchase/tests/test_purchase_order_report.py +++ b/addons/purchase/tests/test_purchase_order_report.py @@ -184,3 +184,37 @@ class TestPurchaseOrderReport(AccountTestInvoicingCommon): po_2.flush_model() report = self.env['purchase.report'].search([('product_id', "=", self.product_a.id)]) self.assertEqual(report.currency_id, self.env.company.currency_id) + + def test_avg_price_calculation(self): + """ + Check that the average price is calculated based on the quantity ordered in each line + PO: + - 10 unit of product A -> price $50 + - 1 unit of product A -> price $10 + Total qty_ordered: 11 + avergae price: 46.36 = ((10 * 50) + (10 * 1)) / 11 + """ + po = self.env['purchase.order'].create({ + 'partner_id': self.partner_a.id, + 'order_line': [ + (0, 0, { + 'product_id': self.product_a.id, + 'product_qty': 10.0, + 'price_unit': 50.0, + }), + (0, 0, { + 'product_id': self.product_a.id, + 'product_qty': 1.0, + 'price_unit': 10.0, + }), + ], + }) + po.button_confirm() + po.flush_model() + report = self.env['purchase.report'].read_group( + [('product_id', '=', self.product_a.id)], + ['qty_ordered', 'price_average:avg'], + ['product_id'], + ) + self.assertEqual(report[0]['qty_ordered'], 11) + self.assertEqual(round(report[0]['price_average'], 2), 46.36)