diff --git a/account_rec_set_partner/models/account.py b/account_rec_set_partner/models/account.py index e5fb0d53..62ad59cd 100644 --- a/account_rec_set_partner/models/account.py +++ b/account_rec_set_partner/models/account.py @@ -13,79 +13,57 @@ class AccountReconcileModel(models.Model): write off if the rule has a "set_partner_id" and the statement line does not have a partner set. """ - def _apply_rules(self, st_lines, excluded_ids=None, partner_map=None): + def _apply_rules(self, st_line, partner): ''' Apply criteria to get candidates for all reconciliation models. This function is called in enterprise by the reconciliation widget to match - the statement lines with the available candidates (using the reconciliation models). + the statement line with the available candidates (using the reconciliation models). - :param st_lines: Account.bank.statement.lines recordset. - :param excluded_ids: Account.move.lines to exclude. - :param partner_map: Dict mapping each line with new partner eventually. - :return: A dict mapping each statement line id with: - * aml_ids: A list of account.move.line ids. - * model: An account.reconcile.model record (optional). - * status: 'reconciled' if the lines has been already reconciled, 'write_off' if the write-off must be - applied on the statement line. + :param st_line: The statement line to match. + :param partner: The partner to consider. + :return: A dict mapping each statement line id with: + * aml_ids: A list of account.move.line ids. + * model: An account.reconcile.model record (optional). + * status: 'reconciled' if the lines has been already reconciled, 'write_off' if the write-off + must be applied on the statement line. + * auto_reconcile: A flag indicating if the match is enough significant to auto reconcile the candidates. ''' - # This functions uses SQL to compute its results. We need to flush before doing anything more. - for model_name in ('account.bank.statement', 'account.bank.statement.line', 'account.move', 'account.move.line', 'res.company', 'account.journal', 'account.account'): - self.env[model_name].flush(self.env[model_name]._fields) - - results = {line.id: {'aml_ids': []} for line in st_lines} - available_models = self.filtered(lambda m: m.rule_type != 'writeoff_button').sorted() - aml_ids_to_exclude = set() # Keep track of already processed amls. - reconciled_amls_ids = set() # Keep track of already reconciled amls. - # First associate with each rec models all the statement lines for which it is applicable - lines_with_partner_per_model = defaultdict(lambda: []) - for st_line in st_lines: - - # Statement lines created in old versions could have a residual amount of zero. In that case, don't try to - # match anything. - if not st_line.amount_residual: - continue - - mapped_partner = (partner_map and partner_map.get(st_line.id) and self.env['res.partner'].browse(partner_map[st_line.id])) or st_line.partner_id - - for rec_model in available_models: - partner = mapped_partner or rec_model._get_partner_from_mapping(st_line) - - if rec_model._is_applicable_for(st_line, partner): - # Customization - if not partner and rec_model.set_partner_id and not rec_model.match_partner: - partner = rec_model.set_partner_id - st_line.partner_id = partner - # End Customization - - lines_with_partner_per_model[rec_model].append((st_line, partner)) - - # Execute only one SQL query for each model (for performance) - matched_lines = self.env['account.bank.statement.line'] for rec_model in available_models: - # We filter the lines for this model, in case a previous one has already found something for them - filtered_st_lines_with_partner = [x for x in lines_with_partner_per_model[rec_model] if x[0] not in matched_lines] - - if not filtered_st_lines_with_partner: - # No unreconciled statement line for this model + if not rec_model._is_applicable_for(st_line, partner): continue - all_model_candidates = rec_model._get_candidates(filtered_st_lines_with_partner, excluded_ids) + if rec_model.rule_type == 'invoice_matching': + rules_map = rec_model._get_invoice_matching_rules_map() + for rule_index in sorted(rules_map.keys()): + for rule_method in rules_map[rule_index]: + candidate_vals = rule_method(st_line, partner) + if not candidate_vals: + continue - for st_line, partner in filtered_st_lines_with_partner: - candidates = all_model_candidates[st_line.id] - if candidates: - model_rslt, new_reconciled_aml_ids, new_treated_aml_ids = rec_model._get_rule_result(st_line, candidates, aml_ids_to_exclude, reconciled_amls_ids, partner) + if candidate_vals.get('amls'): + res = rec_model._get_invoice_matching_amls_result(st_line, partner, candidate_vals) + if res: + return { + **res, + 'model': rec_model, + } + else: + return { + **candidate_vals, + 'model': rec_model, + } - if model_rslt: - # We inject the selected partner (possibly coming from the rec model) - model_rslt['partner']= partner - - results[st_line.id] = model_rslt - reconciled_amls_ids |= new_reconciled_aml_ids - aml_ids_to_exclude |= new_treated_aml_ids - matched_lines += st_line - - return results + elif rec_model.rule_type == 'writeoff_suggestion': + # customize + if rec_model.set_partner_id and not st_line.partner_id: + st_line.partner_id = rec_model.set_partner_id + return { + 'model': rec_model, + 'status': 'write_off', + 'auto_reconcile': rec_model.auto_reconcile, + } + # end customize + return {} diff --git a/connector_opencart/models/sale_order/common.py b/connector_opencart/models/sale_order/common.py index eb0481f7..45fd17f5 100644 --- a/connector_opencart/models/sale_order/common.py +++ b/connector_opencart/models/sale_order/common.py @@ -30,6 +30,13 @@ class OpencartSaleOrder(models.Model): digits=dp.get_precision('Account') ) + @api.model + def create(self, values): + res = super().create(values) + # this is unfortunate, but the initial fiscal position gets set incorrectly + res.odoo_id._compute_fiscal_position_id() + return res + @api.model def import_batch(self, backend, filters=None): """ Prepare the import of Sales Orders from Opencart """