diff --git a/addons/account/wizard/accrued_orders.py b/addons/account/wizard/accrued_orders.py index d61c6048114..d9c26105c1b 100644 --- a/addons/account/wizard/accrued_orders.py +++ b/addons/account/wizard/accrued_orders.py @@ -105,7 +105,7 @@ class AccruedExpenseRevenue(models.TransientModel): }) def _compute_move_vals(self): - def _get_aml_vals(order, balance, amount_currency, account_id, label=""): + def _get_aml_vals(order, balance, amount_currency, account_id, label="", analytic_distribution=None): if not is_purchase: balance *= -1 amount_currency *= -1 @@ -115,6 +115,10 @@ class AccruedExpenseRevenue(models.TransientModel): 'credit': balance * -1 if balance < 0 else 0.0, 'account_id': account_id, } + if analytic_distribution: + values.update({ + 'analytic_distribution': analytic_distribution, + }) if len(order) == 1 and self.company_id.currency_id != order.currency_id: values.update({ 'amount_currency': amount_currency, @@ -146,7 +150,11 @@ class AccruedExpenseRevenue(models.TransientModel): account = order_line.product_id.property_account_expense_id or order_line.product_id.categ_id.property_account_expense_categ_id else: account = order_line.product_id.property_account_income_id or order_line.product_id.categ_id.property_account_income_categ_id - values = _get_aml_vals(order, self.amount, 0, account.id, label=_('Manual entry')) + distribution = order_line.analytic_distribution if order_line.analytic_distribution else {} + if not is_purchase and order.analytic_account_id: + analytic_account_id = str(order.analytic_account_id.id) + distribution[analytic_account_id] = distribution.get(analytic_account_id, 0) + 100.0 + values = _get_aml_vals(order, self.amount, 0, account.id, label=_('Manual entry'), analytic_distribution=distribution) move_lines.append(Command.create(values)) else: other_currency = self.company_id.currency_id != order.currency_id @@ -183,7 +191,11 @@ class AccruedExpenseRevenue(models.TransientModel): amount_currency = order_line.untaxed_amount_to_invoice fnames = ['qty_to_invoice', 'untaxed_amount_to_invoice', 'qty_invoiced', 'qty_delivered', 'invoice_lines'] label = _('%s - %s; %s Invoiced, %s Delivered at %s each', order.name, _ellipsis(order_line.name, 20), order_line.qty_invoiced, order_line.qty_delivered, formatLang(self.env, order_line.price_unit, currency_obj=order.currency_id)) - values = _get_aml_vals(order, amount, amount_currency, account.id, label=label) + distribution = order_line.analytic_distribution if order_line.analytic_distribution else {} + if not is_purchase and order.analytic_account_id: + analytic_account_id = str(order.analytic_account_id.id) + distribution[analytic_account_id] = distribution.get(analytic_account_id, 0) + 100.0 + values = _get_aml_vals(order, amount, amount_currency, account.id, label=label, analytic_distribution=distribution) move_lines.append(Command.create(values)) total_balance += amount # must invalidate cache or o can mess when _create_invoices().action_post() of original order after this @@ -191,7 +203,18 @@ class AccruedExpenseRevenue(models.TransientModel): if not self.company_id.currency_id.is_zero(total_balance): # globalized counterpart for the whole orders selection - values = _get_aml_vals(orders, -total_balance, 0.0, self.account_id.id, label=_('Accrued total')) + analytic_distribution = {} + total = sum(order.amount_total for order in orders) + for line in orders.order_line: + ratio = line.price_total / total + if not is_purchase and line.order_id.analytic_account_id: + account_id = str(line.order_id.analytic_account_id.id) + analytic_distribution.update({account_id: analytic_distribution.get(account_id, 0) +100.0*ratio}) + if not line.analytic_distribution: + continue + for account_id, distribution in line.analytic_distribution.items(): + analytic_distribution.update({account_id : analytic_distribution.get(account_id, 0) + distribution*ratio}) + values = _get_aml_vals(orders, -total_balance, 0.0, self.account_id.id, label=_('Accrued total'), analytic_distribution=analytic_distribution) move_lines.append(Command.create(values)) move_type = _('Expense') if is_purchase else _('Revenue') diff --git a/addons/purchase/tests/test_accrued_purchase_orders.py b/addons/purchase/tests/test_accrued_purchase_orders.py index 3fb790bdcab..d1bda4fb22a 100644 --- a/addons/purchase/tests/test_accrued_purchase_orders.py +++ b/addons/purchase/tests/test_accrued_purchase_orders.py @@ -15,6 +15,18 @@ class TestAccruedPurchaseOrders(AccountTestInvoicingCommon): # set 'type' to 'service' to allow manualy set 'qty_delivered' even with purchase_stock installed cls.product_a.update({'type': 'service', 'purchase_method': 'receive'}) cls.product_b.update({'type': 'service', 'purchase_method': 'receive'}) + #analytic distribution + cls.default_plan = cls.env['account.analytic.plan'].create({'name': 'Default', 'company_id': False}) + cls.analytic_account_a = cls.env['account.analytic.account'].create({ + 'name': 'analytic_account_a', + 'plan_id': cls.default_plan.id, + 'company_id': False, + }) + cls.analytic_account_b = cls.env['account.analytic.account'].create({ + 'name': 'analytic_account_b', + 'plan_id': cls.default_plan.id, + 'company_id': False, + }) cls.product_b.property_account_expense_id = cls.alt_exp_account cls.purchase_order = cls.env['purchase.order'].with_context(tracking_disable=True).create({ 'partner_id': cls.partner_a.id, @@ -26,6 +38,10 @@ class TestAccruedPurchaseOrders(AccountTestInvoicingCommon): 'product_uom': cls.product_a.uom_id.id, 'price_unit': cls.product_a.list_price, 'taxes_id': False, + 'analytic_distribution': { + cls.analytic_account_a.id : 80.0, + cls.analytic_account_b.id : 20.0, + }, }), Command.create({ 'name': cls.product_b.name, @@ -34,6 +50,9 @@ class TestAccruedPurchaseOrders(AccountTestInvoicingCommon): 'product_uom': cls.product_b.uom_id.id, 'price_unit': cls.product_b.list_price, 'taxes_id': False, + 'analytic_distribution': { + cls.analytic_account_b.id : 100.0, + }, }), ], }) @@ -88,3 +107,17 @@ class TestAccruedPurchaseOrders(AccountTestInvoicingCommon): {'account_id': self.alt_exp_account.id, 'debit': 1000 / 2, 'credit': 0, 'amount_currency': 1000}, {'account_id': self.account_revenue.id, 'debit': 0, 'credit': 6000 / 2, 'amount_currency': 0.0}, ]) + + def test_analytic_account_accrued_order(self): + self.purchase_order.order_line.qty_received = 10 + + self.assertRecordValues(self.env['account.move'].search(self.wizard.create_entries()['domain']).line_ids, [ + # reverse move lines + {'account_id': self.account_expense.id, 'debit': 0.0, 'credit': 10000.0, 'analytic_distribution': {str(self.analytic_account_a.id): 80.0, str(self.analytic_account_b.id): 20.0}}, + {'account_id': self.alt_exp_account.id, 'debit': 0.0, 'credit': 2000.0, 'analytic_distribution': {str(self.analytic_account_b.id): 100.0}}, + {'account_id': self.account_revenue.id, 'debit': 12000.0, 'credit': 0.0, 'analytic_distribution': {str(self.analytic_account_a.id): 66.67, str(self.analytic_account_b.id): 33.33}}, + # move lines + {'account_id': self.account_expense.id, 'debit': 10000.0, 'credit': 0.0, 'analytic_distribution': {str(self.analytic_account_a.id): 80.0, str(self.analytic_account_b.id): 20.0}}, + {'account_id': self.alt_exp_account.id, 'debit': 2000.0, 'credit': 0.0, 'analytic_distribution': {str(self.analytic_account_b.id): 100.0}}, + {'account_id': self.account_revenue.id, 'debit': 0.0, 'credit': 12000.0, 'analytic_distribution': {str(self.analytic_account_a.id): 66.67, str(self.analytic_account_b.id): 33.33}}, + ]) diff --git a/addons/sale/tests/test_accrued_sale_orders.py b/addons/sale/tests/test_accrued_sale_orders.py index d68b6d3703d..09ee6c063d1 100644 --- a/addons/sale/tests/test_accrued_sale_orders.py +++ b/addons/sale/tests/test_accrued_sale_orders.py @@ -25,6 +25,22 @@ class TestAccruedSaleOrders(AccountTestInvoicingCommon): 'invoice_policy': 'delivery', 'property_account_income_id': cls.alt_inc_account.id, }) + cls.default_plan = cls.env['account.analytic.plan'].create({'name': 'Default', 'company_id': False}) + cls.analytic_account_a = cls.env['account.analytic.account'].create({ + 'name': 'analytic_account_a', + 'plan_id': cls.default_plan.id, + 'company_id': False, + }) + cls.analytic_account_b = cls.env['account.analytic.account'].create({ + 'name': 'analytic_account_b', + 'plan_id': cls.default_plan.id, + 'company_id': False, + }) + cls.analytic_account_c = cls.env['account.analytic.account'].create({ + 'name': 'analytic_account_c', + 'plan_id': cls.default_plan.id, + 'company_id': False, + }) cls.sale_order = cls.env['sale.order'].with_context(tracking_disable=True).create({ 'partner_id': cls.partner_a.id, 'order_line': [ @@ -35,6 +51,10 @@ class TestAccruedSaleOrders(AccountTestInvoicingCommon): 'product_uom': cls.product_a.uom_id.id, 'price_unit': cls.product_a.list_price, 'tax_id': False, + 'analytic_distribution': { + cls.analytic_account_a.id : 80.0, + cls.analytic_account_b.id : 20.0, + }, }), Command.create({ 'name': cls.product_b.name, @@ -43,9 +63,13 @@ class TestAccruedSaleOrders(AccountTestInvoicingCommon): 'product_uom': cls.product_b.uom_id.id, 'price_unit': cls.product_b.list_price, 'tax_id': False, + 'analytic_distribution': { + cls.analytic_account_b.id : 100.0, + }, }) ] }) + cls.sale_order.analytic_account_id = cls.analytic_account_c cls.sale_order.action_confirm() cls.account_expense = cls.company_data['default_account_expense'] cls.account_revenue = cls.company_data['default_account_revenue'] @@ -96,3 +120,18 @@ class TestAccruedSaleOrders(AccountTestInvoicingCommon): {'account_id': self.alt_inc_account.id, 'debit': 0, 'credit': 1000 / 2, 'amount_currency': -1000}, {'account_id': self.account_expense.id, 'debit': 6000 / 2, 'credit': 0, 'amount_currency': 0.0}, ]) + + def test_analytic_account_accrued_order(self): + self.sale_order.order_line.qty_delivered = 10 + + self.assertRecordValues(self.env['account.move'].search(self.wizard.create_entries()['domain']).line_ids, [ + # reverse move lines + {'account_id': self.account_revenue.id, 'debit': 10000.0, 'credit': 0.0, 'analytic_distribution': {str(self.analytic_account_a.id): 80.0, str(self.analytic_account_b.id): 20.0, str(self.analytic_account_c.id): 100.0}}, + {'account_id': self.alt_inc_account.id, 'debit': 2000.0, 'credit': 0.0, 'analytic_distribution': {str(self.analytic_account_b.id): 100.0, str(self.analytic_account_c.id): 100.0}}, + {'account_id': self.account_expense.id, 'debit': 0.0, 'credit': 12000.0, 'analytic_distribution': {str(self.analytic_account_a.id): 66.67, str(self.analytic_account_b.id): 33.33, str(self.analytic_account_c.id): 100.0}}, + # move lines + {'account_id': self.account_revenue.id, 'debit': 0.0, 'credit': 10000.0, 'analytic_distribution': {str(self.analytic_account_a.id): 80.0, str(self.analytic_account_b.id): 20.0, str(self.analytic_account_c.id): 100.0}}, + {'account_id': self.alt_inc_account.id, 'debit': 0.0, 'credit': 2000.0, 'analytic_distribution': {str(self.analytic_account_b.id): 100.0, str(self.analytic_account_c.id): 100.0}}, + {'account_id': self.account_expense.id, 'debit': 12000.0, 'credit': 0.0, 'analytic_distribution': {str(self.analytic_account_a.id): 66.67, str(self.analytic_account_b.id): 33.33, str(self.analytic_account_c.id): 100.0}}, + + ])