From b8950ab49a1176bc33a7180d327cbf32f4dbccdd Mon Sep 17 00:00:00 2001 From: Nicolas Martinelli Date: Mon, 25 Mar 2019 13:54:19 +0000 Subject: [PATCH 01/48] [FIX] purchase: currency of supplierinfo Set the currency of the supplier info according to the currency set on the partner. opw-1951314 closes odoo/odoo#32098 Signed-off-by: Nicolas Martinelli (nim) --- addons/purchase/models/product.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/addons/purchase/models/product.py b/addons/purchase/models/product.py index 49897429a4e..2de7e229044 100644 --- a/addons/purchase/models/product.py +++ b/addons/purchase/models/product.py @@ -91,3 +91,11 @@ class ProductCategory(models.Model): 'account.account', string="Price Difference Account", company_dependent=True, help="This account will be used to value price difference between purchase price and accounting cost.") + + +class SupplierInfo(models.Model): + _inherit = "product.supplierinfo" + + @api.onchange('name') + def _onchange_partner_id(self): + self.currency_id = self.name.property_purchase_currency_id or self.env.user.company_id.currency_id From 80b900ee578450ba9d32d23ef991cedaae242d28 Mon Sep 17 00:00:00 2001 From: "Lucas Perais (lpe)" Date: Mon, 25 Mar 2019 15:50:00 +0000 Subject: [PATCH 02/48] [FIX] account: reconciliation matching rule div by zero Do a MISC operation representing a payment revert it Do a statement line for that amount Click on "reconcile" on the bank journal Before this commit there was a Division By Zero traceback This was because the bank account line had a zero amount_residual due to its reversion while the statement line was negative. After this commit, for liquidity lines, we take the total amount instead of the residual Because a reverted payment line can always be associated with a statement OPW 1947362 courtesy of @smetl (las@odoo.com) for the fix closes odoo/odoo#32105 Signed-off-by: Lucas Perais (lpe) --- .../account/models/account_reconcile_model.py | 12 +++- .../test_reconciliation_matching_rules.py | 61 +++++++++++++++++-- 2 files changed, 65 insertions(+), 8 deletions(-) diff --git a/addons/account/models/account_reconcile_model.py b/addons/account/models/account_reconcile_model.py index f4c29afeb40..df4295912d2 100644 --- a/addons/account/models/account_reconcile_model.py +++ b/addons/account/models/account_reconcile_model.py @@ -393,6 +393,9 @@ class AccountReconcileModel(models.Model): aml.date_maturity AS aml_date_maturity, aml.amount_residual AS aml_amount_residual, aml.amount_residual_currency AS aml_amount_residual_currency, + aml.balance AS aml_balance, + aml.amount_currency AS aml_amount_currency, + account.internal_type AS account_internal_type, -- Determine a matching or not with the statement line communication using the move.name or move.ref. regexp_split_to_array(TRIM(REGEXP_REPLACE(move.name, '[^0-9|^\s]', '', 'g')),'\s+') @@ -540,9 +543,12 @@ class AccountReconcileModel(models.Model): return True # Match total residual amount. - total_residual = sum( - aml['aml_currency_id'] and aml['aml_amount_residual_currency'] or aml['aml_amount_residual'] for aml in - candidates) + total_residual = 0.0 + for aml in candidates: + if aml['account_internal_type'] == 'liquidity': + total_residual += aml['aml_currency_id'] and aml['aml_amount_currency'] or aml['aml_balance'] + else: + total_residual += aml['aml_currency_id'] and aml['aml_amount_residual_currency'] or aml['aml_amount_residual'] line_residual = statement_line.currency_id and statement_line.amount_currency or statement_line.amount line_currency = statement_line.currency_id or statement_line.journal_id.currency_id or statement_line.company_id.currency_id diff --git a/addons/account/tests/test_reconciliation_matching_rules.py b/addons/account/tests/test_reconciliation_matching_rules.py index f50173296b5..cb10bee162e 100644 --- a/addons/account/tests/test_reconciliation_matching_rules.py +++ b/addons/account/tests/test_reconciliation_matching_rules.py @@ -24,8 +24,10 @@ class TestReconciliationMatchingRules(AccountingTestCase): lines = invoice.move_id.line_ids return lines.filtered(lambda l: l.account_id == invoice.account_id) - def _check_statement_matching(self, rules, expected_values): - statement_lines = (self.bank_st + self.cash_st).mapped('line_ids') + def _check_statement_matching(self, rules, expected_values, statements=None): + if statements is None: + statements = self.bank_st + self.cash_st + statement_lines = statements.mapped('line_ids') matching_values = rules._apply_rules(statement_lines) for st_line_id, values in matching_values.items(): values.pop('reconciled_lines', None) @@ -34,6 +36,10 @@ class TestReconciliationMatchingRules(AccountingTestCase): def setUp(self): super(AccountingTestCase, self).setUp() + self.account_pay = self.env['account.account'].search([('internal_type', '=', 'payable')], limit=1) + self.account_liq = self.env['account.account'].search([('internal_type', '=', 'liquidity')], limit=1) + self.account_rcv = self.env['account.account'].search([('internal_type', '=', 'receivable')], limit=1) + self.partner_1 = self.env['res.partner'].create({'name': 'partner_1'}) self.partner_2 = self.env['res.partner'].create({'name': 'partner_2'}) @@ -45,7 +51,8 @@ class TestReconciliationMatchingRules(AccountingTestCase): current_assets_account = self.env['account.account'].search( [('user_type_id', '=', self.env.ref('account.data_account_type_current_assets').id)], limit=1) - self.rule_1 = self.env.ref('account.reconciliation_model_default_rule') + self.rule_0 = self.env.ref('account.reconciliation_model_default_rule') + self.rule_1 = self.rule_0.copy() self.rule_1.account_id = current_assets_account self.rule_1.match_partner = True self.rule_1.match_partner_ids |= self.partner_1 + self.partner_2 @@ -59,10 +66,10 @@ class TestReconciliationMatchingRules(AccountingTestCase): invoice_number = self.invoice_line_1.move_id.name - bank_journal = self.env['account.journal'].search([('type', '=', 'bank')], limit=1) + self.bank_journal = self.env['account.journal'].search([('type', '=', 'bank')], limit=1) self.bank_st = self.env['account.bank.statement'].create({ - 'name': 'test bank journal', 'journal_id': bank_journal.id, + 'name': 'test bank journal', 'journal_id': self.bank_journal.id, }) self.bank_line_1 = self.env['account.bank.statement.line'].create({ 'statement_id': self.bank_st.id, @@ -296,3 +303,47 @@ class TestReconciliationMatchingRules(AccountingTestCase): {'partner_id': self.partner_2.id, 'debit': 0.0, 'credit': 1000.0}, {'partner_id': self.partner_2.id, 'debit': 1000.0, 'credit': 0.0}, ]) + + def test_reverted_move_matching(self): + AccountMove = self.env['account.move'] + move = AccountMove.create({ + 'name': 'To Revert', + 'journal_id': self.bank_journal.id, + }) + + partner = self.env['res.partner'].create({'name': 'Eugene'}) + AccountMoveLine = self.env['account.move.line'].with_context(check_move_validity=False) + payment_payable_line = AccountMoveLine.create({ + 'account_id': self.account_pay.id, + 'move_id': move.id, + 'partner_id': partner.id, + 'name': 'One of these days', + 'debit': 10, + }) + payment_bnk_line = AccountMoveLine.create({ + 'account_id': self.account_liq.id, + 'move_id': move.id, + 'partner_id': partner.id, + 'name': 'I\'m gonna cut you into little pieces', + 'credit': 10, + }) + + move.post() + move_reversed = AccountMove.browse(move.reverse_moves()) + self.assertTrue(move_reversed.exists()) + + bank_st = self.env['account.bank.statement'].create({ + 'name': 'test bank journal', 'journal_id': self.bank_journal.id, + }) + bank_line_1 = self.env['account.bank.statement.line'].create({ + 'statement_id': bank_st.id, + 'name': '8', + 'partner_id': partner.id, + 'amount': -10, + 'sequence': 1, + }) + + expected_values = { + bank_line_1.id: {'aml_ids': [payment_bnk_line.id], 'model': self.rule_0} + } + self._check_statement_matching(self.rule_0, expected_values, statements=bank_st) From f5e99060b66dd62d8154c07f1110bf1c913a1424 Mon Sep 17 00:00:00 2001 From: Nicolas Martinelli Date: Tue, 26 Mar 2019 09:32:43 +0000 Subject: [PATCH 03/48] [FIX] stock: discard scrap - Process a WO (e.g. 'Manual Assembly' from the demo data) - Create a scrap for component 'Drawer Black' - A new wizard appears: 'The product XXX is not available in sufficient quantity' - Click on 'Discard' A scrap is created in draft, but it cannot be canceled. The scrap shouldn't have been created in a first place, but this cannot be changed in stable. Therefore, we delete it. opw-1946254 closes odoo/odoo#32122 Signed-off-by: Nicolas Martinelli (nim) --- addons/stock/wizard/stock_warn_insufficient_qty.py | 4 ++++ addons/stock/wizard/stock_warn_insufficient_qty_views.xml | 3 +++ 2 files changed, 7 insertions(+) diff --git a/addons/stock/wizard/stock_warn_insufficient_qty.py b/addons/stock/wizard/stock_warn_insufficient_qty.py index 50247d130bf..3e480c73e83 100644 --- a/addons/stock/wizard/stock_warn_insufficient_qty.py +++ b/addons/stock/wizard/stock_warn_insufficient_qty.py @@ -34,3 +34,7 @@ class StockWarnInsufficientQtyScrap(models.TransientModel): def action_done(self): return self.scrap_id.do_scrap() + + def action_cancel(self): + # FIXME in master: we should not have created the scrap in a first place + return self.scrap_id.sudo().unlink() diff --git a/addons/stock/wizard/stock_warn_insufficient_qty_views.xml b/addons/stock/wizard/stock_warn_insufficient_qty_views.xml index f6fb8eee99e..01de1f8e482 100644 --- a/addons/stock/wizard/stock_warn_insufficient_qty_views.xml +++ b/addons/stock/wizard/stock_warn_insufficient_qty_views.xml @@ -44,6 +44,9 @@ + +