from odoo import models, fields, api class AccountPayment(models.Model): _inherit = 'account.payment' purchase_order_id = fields.Many2one( 'purchase.order', string='Purchase Order', domain="[('partner_id', '=', partner_id), ('state', 'in', ('purchase', 'done'))]" ) is_advance_payment = fields.Boolean( string='Is Advance Payment', default=False, help='Identifies if this payment is an advance payment for a purchase order' ) @api.model_create_multi def create(self, vals_list): """Override create to ensure payment_method_line_id is correctly set for advance payments""" for vals in vals_list: # If this is an advance payment and payment_method_line_id is set, # ensure it matches the journal's payment methods if vals.get('is_advance_payment') and vals.get('journal_id') and vals.get('payment_method_line_id'): journal = self.env['account.journal'].browse(vals['journal_id']) payment_method_line = self.env['account.payment.method.line'].browse(vals['payment_method_line_id']) # Verify the payment method line belongs to this journal if payment_method_line not in journal.outbound_payment_method_line_ids: # If not, find the correct one correct_method = journal.outbound_payment_method_line_ids.filtered( lambda l: l.payment_method_id == payment_method_line.payment_method_id )[:1] if correct_method: vals['payment_method_line_id'] = correct_method.id return super().create(vals_list) @api.onchange('purchase_order_id') def _onchange_purchase_order_id(self): if self.purchase_order_id: self.amount = self.purchase_order_id.amount_residual def _prepare_move_line_default_vals(self, write_off_line_vals=None, force_balance=None): """Override to use correct accounts for advance payments""" line_vals_list = super()._prepare_move_line_default_vals(write_off_line_vals=write_off_line_vals, force_balance=force_balance) if self.is_advance_payment and self.purchase_order_id: # Get expense account from default deposit product deposit_product_id = self.env['ir.config_parameter'].sudo().get_param( 'purchase_advance_payment.deposit_product_id') if deposit_product_id: product = self.env['product.product'].browse(int(deposit_product_id)) expense_account = product.property_account_expense_id or product.categ_id.property_account_expense_categ_id if expense_account: # Get outstanding payment account from journal # For outbound payments, first check journal-specific account, then company default outstanding_account = None # Try to get from journal's outbound payment method if self.journal_id.outbound_payment_method_line_ids: outstanding_account = self.journal_id.outbound_payment_method_line_ids[0].payment_account_id # Fall back to company default if not set on journal if not outstanding_account: outstanding_account = self.journal_id.company_id.account_journal_payment_credit_account_id if outstanding_account: # Modify the line vals to use correct accounts for line_vals in line_vals_list: # The debit line (expense) - partner line if line_vals.get('debit', 0) > 0 and line_vals.get('partner_id'): line_vals['account_id'] = expense_account.id # The credit line (outstanding payment) elif line_vals.get('credit', 0) > 0: line_vals['account_id'] = outstanding_account.id return line_vals_list def action_post(self): res = super().action_post() # When an advance payment is posted, update deposit line in purchase order for payment in self: if payment.is_advance_payment and payment.purchase_order_id: # Update the deposit line with the actual posted amount payment.purchase_order_id._update_deposit_line() return res