from odoo import models, fields, api from odoo.exceptions import UserError class CreateAdvancePaymentWizard(models.TransientModel): _name = 'create.advance.payment.wizard' _description = 'Create Advance Payment Wizard' purchase_order_id = fields.Many2one( 'purchase.order', string='Purchase Order', required=True, readonly=True ) partner_id = fields.Many2one( 'res.partner', string='Vendor', related='purchase_order_id.partner_id', readonly=True ) journal_id = fields.Many2one( 'account.journal', string='Journal', required=True, domain=[('type', 'in', ['bank', 'cash'])] ) amount = fields.Monetary( string='Amount', required=True, currency_field='currency_id' ) currency_id = fields.Many2one( 'res.currency', string='Currency', related='purchase_order_id.currency_id', readonly=True ) date = fields.Date( string='Date', required=True, default=fields.Date.context_today ) memo = fields.Char( string='Memo' ) expense_account_id = fields.Many2one( 'account.account', string='Expense Account', compute='_compute_expense_account', store=True, readonly=True ) @api.model def default_get(self, fields_list): res = super().default_get(fields_list) if self._context.get('default_purchase_order_id'): po = self.env['purchase.order'].browse(self._context['default_purchase_order_id']) res['amount'] = po.amount_residual res['memo'] = f'Advance payment for {po.name}' return res @api.depends('purchase_order_id') def _compute_expense_account(self): """Get expense account from default advance payment product""" for wizard in self: 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)) # Get expense account from product account = product.property_account_expense_id or product.categ_id.property_account_expense_categ_id wizard.expense_account_id = account.id else: wizard.expense_account_id = False def action_create_payment(self): """Create advance payment with proper journal entries""" self.ensure_one() if self.amount <= 0: raise UserError("Amount must be greater than zero.") # Get expense account from default deposit product if not self.expense_account_id: raise UserError( "Please configure a default advance payment product in Purchase settings " "with a valid 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 not outstanding_account: raise UserError( f"Please configure an outstanding payment account for journal '{self.journal_id.name}'.\n" f"You can set it in:\n" f"1. Journal level: Accounting > Configuration > Journals > {self.journal_id.name} > " f"Outgoing Payments tab > Payment Method > Outstanding Payments Account\n" f"OR\n" f"2. Company level: Accounting > Configuration > Settings > Default Accounts > " f"Outstanding Payments Account" ) # Create payment payment_vals = { 'payment_type': 'outbound', 'partner_type': 'supplier', 'partner_id': self.partner_id.id, 'amount': self.amount, 'currency_id': self.currency_id.id, 'date': self.date, 'journal_id': self.journal_id.id, 'ref': self.memo or f'Advance payment for {self.purchase_order_id.name}', 'purchase_order_id': self.purchase_order_id.id, 'is_advance_payment': True, } payment = self.env['account.payment'].create(payment_vals) # Create deposit line in purchase order immediately self._create_deposit_line() # Return action to open the created payment return { 'type': 'ir.actions.act_window', 'name': 'Advance Payment', 'res_model': 'account.payment', 'res_id': payment.id, 'view_mode': 'form', 'target': 'current', } def _create_deposit_line(self): """Create deposit line in purchase order""" # Get or create deposit product deposit_product_id = self.env['ir.config_parameter'].sudo().get_param( 'purchase_advance_payment.deposit_product_id') if not deposit_product_id: raise UserError( "Please configure a default advance payment product in Purchase settings." ) deposit_product = self.env['product.product'].browse(int(deposit_product_id)) # Check if deposit line already exists existing_deposit_line = self.purchase_order_id.order_line.filtered(lambda l: l.is_deposit) # Calculate new total advance payment new_advance_total = self.purchase_order_id.advance_payment_total + self.amount if existing_deposit_line: # Update existing deposit line existing_deposit_line.write({ 'product_qty': 1, 'price_unit': -new_advance_total, 'taxes_id': [(6, 0, [])], }) else: # Create new deposit line deposit_vals = { 'order_id': self.purchase_order_id.id, 'product_id': deposit_product.id, 'name': f'Advance payment for {self.purchase_order_id.name}', 'product_qty': 1, 'product_uom': deposit_product.uom_id.id, 'price_unit': -self.amount, 'is_deposit': True, 'date_planned': fields.Datetime.now(), 'taxes_id': [(6, 0, [])], } self.env['purchase.order.line'].create(deposit_vals)