from odoo import models, _ from odoo.tools import float_is_zero class PosSession(models.Model): _inherit = 'pos.session' def _create_account_move(self, balancing_account=False, amount_to_balance=0, bank_payment_method_diffs=None): """ Extend _create_account_move to generate additional journal entry lines for 100% discount orders (where total amount is 0). """ # Call super to generate the standard move data = super(PosSession, self)._create_account_move(balancing_account, amount_to_balance, bank_payment_method_diffs) if not self.config_id.discount_100_income_account_id or not self.config_id.discount_100_expense_account_id: return data # Identify orders with 0 absolute paid amount but non-zero gross amount # We look for orders where amount_total is near zero. # Note: 100% discount orders have amount_total = 0. MoveLine = data.get('MoveLine') if not MoveLine: # Depending on Odoo 19's internal structure changes, fallback / ensure MoveLine exists. Odoo 17 returns a dict with 'MoveLine'. MoveLine = self.env['account.move.line'] income_account = self.config_id.discount_100_income_account_id expense_account = self.config_id.discount_100_expense_account_id # Helper to convert amount to company currency if needed, similar to Odoo's internals def _get_amounts(amount, date): return self._update_amounts({'amount': 0, 'amount_converted': 0}, {'amount': amount}, date) zero_value_moves = [] for order in self._get_closed_orders(): if float_is_zero(order.amount_total, precision_rounding=self.currency_id.rounding): # Calculate the exact discount amount applied by loyalty rewards discount_amount = sum( abs(line.price_subtotal) for line in order.lines if line.price_subtotal < 0 and (getattr(line, 'is_reward_line', False) or getattr(line, 'reward_id', False)) ) if float_is_zero(discount_amount, precision_rounding=self.currency_id.rounding): continue amounts = _get_amounts(discount_amount, order.date_order) # Create Credit Line (Income) # We use _credit_amounts helper logic style manually credit_vals = { 'name': _('100%% Discount Income: %s') % order.name, 'account_id': income_account.id, 'move_id': self.move_id.id, 'partner_id': order.partner_id.id or False, } credit_vals.update(self._credit_amounts(credit_vals, amounts['amount'], amounts['amount_converted'])) zero_value_moves.append(credit_vals) # Create Debit Line (Expense/Discount) debit_vals = { 'name': _('100%% Discount Expense: %s') % order.name, 'account_id': expense_account.id, 'move_id': self.move_id.id, 'partner_id': order.partner_id.id or False, } debit_vals.update(self._debit_amounts(debit_vals, amounts['amount'], amounts['amount_converted'])) zero_value_moves.append(debit_vals) if zero_value_moves and self.move_id: MoveLine.with_context(check_move_validity=False).create(zero_value_moves) return data