from odoo import _, api, exceptions, models class AccountMove(models.Model): _inherit = "account.move" @api.depends("company_id", "invoice_filter_type_domain") def _compute_suitable_journal_ids(self): res = super()._compute_suitable_journal_ids() for move in self: if move.move_type in {"in_receipt", "out_receipt"}: move.suitable_journal_ids = move.suitable_journal_ids.filtered( "receipts" ) continue move.suitable_journal_ids = move.suitable_journal_ids.filtered( lambda x: not x.receipts ) return res def _search_default_receipt_journal(self, journal_types): company_id = self.env.context.get("default_company_id", self.env.company.id) currency_id = self.env.context.get("default_currency_id") domain = [ ("company_id", "=", company_id), ("type", "in", journal_types), ("receipts", "=", True), ] journal = None if currency_id: journal = self.env["account.journal"].search( domain + [("currency_id", "=", currency_id)], limit=1 ) if not journal: journal = self.env["account.journal"].search(domain, limit=1) return journal def _search_default_journal(self): journal = super()._search_default_journal() # We can assume that if move_type is not in receipts, a journal without # receipts it's coming because of the Journal constraint if self.move_type not in {"in_receipt", "out_receipt"} or journal.receipts: return journal journal_types = self._get_valid_journal_types() return self._search_default_receipt_journal(journal_types) or journal def _get_journal_types(self, move_type): if move_type in self.get_sale_types(include_receipts=True): journal_types = ["sale"] elif move_type in self.get_purchase_types(include_receipts=True): journal_types = ["purchase"] else: journal_types = self.env.context.get( "default_move_journal_types", ["general"] ) return journal_types @api.model def _update_receipts_journal(self, vals_list): """ Update `vals_list` in place to set journal_id to the receipt journal when move_type is receipt. Model defaults are also considered it move_type or journal_id are not in a `vals_list`. """ defaults = self.default_get(["journal_id", "move_type"]) default_journal = defaults.get("journal_id") default_move_type = defaults.get("move_type") for vals in vals_list: move_type = vals.get("move_type", default_move_type) if move_type in ("in_receipt", "out_receipt"): selected_journal_id = vals.get("journal_id", default_journal) selected_journal = self.env["account.journal"].browse( selected_journal_id ) if not selected_journal.receipts: journal_types = self._get_journal_types(move_type) receipt_journal = self._search_default_receipt_journal( journal_types ) if receipt_journal: vals["journal_id"] = receipt_journal.id @api.model_create_multi def create(self, vals_list): self._update_receipts_journal(vals_list) return super().create(vals_list) @api.constrains("move_type", "journal_id") def _check_receipts_journal(self): """ Ensure that Receipt Journal is only used in Receipts if exists Receipt Journals for its type """ aj_model = self.env["account.journal"] receipt_domain = [("receipts", "=", True)] has_in_rjournals = aj_model.search([("type", "=", "purchase")] + receipt_domain) has_out_rjournals = aj_model.search([("type", "=", "sale")] + receipt_domain) for move in self: is_rj = move.journal_id.receipts if move.move_type not in {"in_receipt", "out_receipt"} and is_rj: raise exceptions.ValidationError( _("Receipt Journal is restricted to Receipts") ) elif move.move_type == "in_receipt" and not is_rj and has_in_rjournals: raise exceptions.ValidationError( _( "Purchase Receipt must use a Receipt Journal because " "there is already a Receipt Journal for Purchases" ) ) elif move.move_type == "out_receipt" and not is_rj and has_out_rjournals: raise exceptions.ValidationError( _( "Sale Receipt must use a Receipt Journal because " "there is already a Receipt Journal for Sales" ) )