Compare commits

...

2 Commits
main ... 19.0

Author SHA1 Message Date
f7ffb8b16d initial odoo 19 changes 2025-11-12 16:00:05 +07:00
3328179534 change to odoo 19 2025-11-12 15:59:12 +07:00
28 changed files with 469 additions and 456 deletions

View File

@ -1,26 +1,26 @@
# Purchase Advance Payment
This module allows linking payments to purchase orders as advance payments.
## Features
- Link payments to purchase orders as advance payments
- Automatically subtract advance payments from the total when the PO is fully billed
- Create deposit products on the PO so the final invoice includes the deposit product
- Track advance payments linked to purchase orders
## Usage
1. Create a purchase order
2. Create a payment and link it to the purchase order as an advance payment
3. When the payment is posted, it will automatically be applied as a deposit to the purchase order
4. The deposit will appear as a negative line item on the purchase order
5. When creating the vendor bill, the deposit will be included
## Configuration
No additional configuration is required.
## Known Issues
# Purchase Advance Payment
This module allows linking payments to purchase orders as advance payments.
## Features
- Link payments to purchase orders as advance payments
- Automatically subtract advance payments from the total when the PO is fully billed
- Create deposit products on the PO so the final invoice includes the deposit product
- Track advance payments linked to purchase orders
## Usage
1. Create a purchase order
2. Create a payment and link it to the purchase order as an advance payment
3. When the payment is posted, it will automatically be applied as a deposit to the purchase order
4. The deposit will appear as a negative line item on the purchase order
5. When creating the vendor bill, the deposit will be included
## Configuration
No additional configuration is required.
## Known Issues
- None

View File

@ -1,2 +1,2 @@
from . import models
from . import models
from . import wizard

View File

@ -1,25 +1,25 @@
{
'name': 'Purchase Advance Payment',
'version': '17.0.1.0.0',
'category': 'Purchase',
'summary': 'Link payments to purchase orders as advance payments',
'description': """
This module allows linking payments to purchase orders as advance payments.
When a PO is fully billed, the total is subtracted by the advance payment made.
After payment is linked to the PO, a deposit product is created so the final
invoice/vendor bills will include the deposit product.
""",
'author': 'Suherdy Yacob',
'depends': ['purchase', 'account'],
'data': [
'security/ir.model.access.csv',
'data/product_data.xml',
'wizard/link_advance_payment_wizard_views.xml',
'views/purchase_advance_payment_views.xml',
'views/purchase_order_views.xml',
'views/res_config_settings_views.xml',
],
'installable': True,
'auto_install': False,
'license': 'LGPL-3',
}
{
'name': 'Purchase Advance Payment',
'version': '19.0.1.0.0',
'category': 'Purchase',
'summary': 'Link payments to purchase orders as advance payments',
'description': """
This module allows linking payments to purchase orders as advance payments.
When a PO is fully billed, the total is subtracted by the advance payment made.
After payment is linked to the PO, a deposit product is created so the final
invoice/vendor bills will include the deposit product.
""",
'author': 'Suherdy Yacob',
'depends': ['purchase', 'account'],
'data': [
'security/ir.model.access.csv',
'data/product_data.xml',
'wizard/link_advance_payment_wizard_views.xml',
'views/purchase_advance_payment_views.xml',
'views/purchase_order_views.xml',
'views/res_config_settings_views.xml',
],
'installable': True,
'auto_install': False,
'license': 'LGPL-3',
}

Binary file not shown.

Binary file not shown.

View File

@ -1,10 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<data noupdate="1">
<!-- Product Category for Deposit Products -->
<record id="product_category_deposit" model="product.category">
<field name="name">Deposit</field>
<field name="parent_id" ref="product.product_category_all"/>
</record>
</data>
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<data noupdate="1">
<!-- Product Category for Deposit Products -->
<record id="product_category_deposit" model="product.category">
<field name="name">Deposit</field>
<field name="parent_id" ref="product.product_category_all"/>
</record>
</data>
</odoo>

View File

@ -1,3 +1,3 @@
from . import purchase_order
from . import account_payment
from . import purchase_order
from . import account_payment
from . import res_config_settings

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -1,31 +1,31 @@
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.onchange('purchase_order_id')
def _onchange_purchase_order_id(self):
if self.purchase_order_id:
self.amount = self.purchase_order_id.amount_residual
def action_post(self):
res = super().action_post()
# When an advance payment is posted, link it to the purchase order
for payment in self:
if payment.is_advance_payment and payment.purchase_order_id:
# Apply the deposit to the purchase order
payment.purchase_order_id.action_apply_deposit()
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.onchange('purchase_order_id')
def _onchange_purchase_order_id(self):
if self.purchase_order_id:
self.amount = self.purchase_order_id.amount_residual
def action_post(self):
res = super().action_post()
# When an advance payment is posted, link it to the purchase order
for payment in self:
if payment.is_advance_payment and payment.purchase_order_id:
# Apply the deposit to the purchase order
payment.purchase_order_id.action_apply_deposit()
return res

View File

@ -1,187 +1,187 @@
from odoo import models, fields, api
from odoo.exceptions import UserError
from odoo.tools import float_compare
class PurchaseOrder(models.Model):
_inherit = 'purchase.order'
advance_payment_ids = fields.One2many(
'account.payment',
'purchase_order_id',
string='Advance Payments',
domain=[('state', '=', 'posted')]
)
advance_payment_total = fields.Monetary(
string='Advance Payment Total',
compute='_compute_advance_payment_total',
store=True
)
amount_residual = fields.Monetary(
string='Amount Residual',
compute='_compute_amount_residual',
store=True
)
deposit_product_id = fields.Many2one(
'product.product',
string='Deposit Product',
help='Product used for advance payment deposit'
)
@api.depends('advance_payment_ids', 'advance_payment_ids.state', 'advance_payment_ids.amount')
def _compute_advance_payment_total(self):
for order in self:
order.advance_payment_total = sum(
payment.amount for payment in order.advance_payment_ids.filtered(lambda p: p.state == 'posted')
)
@api.depends('amount_total', 'advance_payment_total')
def _compute_amount_residual(self):
for order in self:
order.amount_residual = order.amount_total - order.advance_payment_total
def action_view_advance_payments(self):
self.ensure_one()
action = self.env.ref('account.action_account_payments').sudo().read()[0]
action['domain'] = [('id', 'in', self.advance_payment_ids.ids)]
action['context'] = {
'default_purchase_order_id': self.id,
'default_partner_id': self.partner_id.id,
'default_payment_type': 'outbound',
'default_partner_type': 'supplier',
}
return action
def action_create_deposit_product(self):
"""Create a deposit product for this purchase order"""
self.ensure_one()
# Check if there's a default deposit product in settings
default_deposit_product = self.env['ir.config_parameter'].sudo().get_param(
'purchase_advance_payment.deposit_product_id')
if default_deposit_product:
self.deposit_product_id = int(default_deposit_product)
return self.deposit_product_id
# If no default product, create one
if not self.deposit_product_id:
product_vals = {
'name': f'Deposit for PO {self.name}',
'type': 'service',
'purchase_ok': True,
'sale_ok': False,
'invoice_policy': 'order', # Ordered quantities for deposit
'supplier_taxes_id': [(6, 0, [])], # No supplier taxes
}
deposit_product = self.env['product.product'].create(product_vals)
self.deposit_product_id = deposit_product.id
return self.deposit_product_id
def button_draft(self):
res = super().button_draft()
# Remove deposit lines when resetting to draft
for order in self:
deposit_lines = order.order_line.filtered(lambda l: l.is_deposit)
deposit_lines.unlink()
return res
def action_apply_deposit(self):
"""Apply advance payment as deposit line in the purchase order"""
self.ensure_one()
if self.advance_payment_total <= 0:
raise UserError("No advance payment found for this purchase order.")
# Create or update deposit product
if not self.deposit_product_id:
self.action_create_deposit_product()
# Check if deposit line already exists
existing_deposit_line = self.order_line.filtered(lambda l: l.is_deposit)
if existing_deposit_line:
# Update existing deposit line
existing_deposit_line.write({
'product_qty': 1,
'price_unit': -self.advance_payment_total, # Negative value for deposit
'taxes_id': [(6, 0, [])], # No taxes
})
else:
# Create new deposit line
deposit_vals = {
'order_id': self.id,
'product_id': self.deposit_product_id.id,
'name': f'Deposit payment for PO {self.name}',
'product_qty': 1,
'product_uom': self.deposit_product_id.uom_id.id,
'price_unit': -self.advance_payment_total, # Negative value for deposit
'is_deposit': True,
'date_planned': fields.Datetime.now(),
'taxes_id': [(6, 0, [])], # No taxes
}
self.env['purchase.order.line'].create(deposit_vals)
return True
def action_create_invoice(self):
"""Override to ensure deposit line is included in vendor bill"""
# Apply deposit before creating invoice
for order in self:
if order.advance_payment_total > 0:
order.action_apply_deposit()
# Call super to create the invoice
invoices = super().action_create_invoice()
# Ensure deposit lines have quantity 1 in the created invoices
if 'res_id' in invoices and invoices['res_id']:
# Single invoice
invoice = self.env['account.move'].browse(invoices['res_id'])
self._fix_deposit_line_quantities(invoice)
elif 'domain' in invoices and invoices['domain']:
# Multiple invoices
invoice_ids = self.env['account.move'].search(invoices['domain'])
for invoice in invoice_ids:
self._fix_deposit_line_quantities(invoice)
return invoices
def _fix_deposit_line_quantities(self, invoice):
"""Fix deposit line quantities in the invoice"""
for line in invoice.invoice_line_ids:
if line.purchase_line_id and line.purchase_line_id.is_deposit:
line.write({
'quantity': 1.0,
'tax_ids': [(6, 0, [])] # No taxes
})
class PurchaseOrderLine(models.Model):
_inherit = 'purchase.order.line'
is_deposit = fields.Boolean(
string='Is Deposit',
default=False,
help='Identifies if this line is a deposit payment'
)
def _prepare_account_move_line(self, move=False):
"""Override to ensure deposit lines have correct quantity in vendor bill"""
self.ensure_one()
res = super()._prepare_account_move_line(move)
# If this is a deposit line, ensure quantity is 1 and no taxes
if self.is_deposit:
res['quantity'] = 1
res['tax_ids'] = [(6, 0, [])] # No taxes
return res
def _get_invoice_qty(self):
"""Override to ensure deposit lines have correct quantity for invoicing"""
self.ensure_one()
if self.is_deposit:
# For deposit lines, always invoice quantity 1 regardless of received qty
return 1.0
from odoo import models, fields, api
from odoo.exceptions import UserError
from odoo.tools import float_compare
class PurchaseOrder(models.Model):
_inherit = 'purchase.order'
advance_payment_ids = fields.One2many(
'account.payment',
'purchase_order_id',
string='Advance Payments',
domain=[('state', '=', 'posted')]
)
advance_payment_total = fields.Monetary(
string='Advance Payment Total',
compute='_compute_advance_payment_total',
store=True
)
amount_residual = fields.Monetary(
string='Amount Residual',
compute='_compute_amount_residual',
store=True
)
deposit_product_id = fields.Many2one(
'product.product',
string='Deposit Product',
help='Product used for advance payment deposit'
)
@api.depends('advance_payment_ids', 'advance_payment_ids.state', 'advance_payment_ids.amount')
def _compute_advance_payment_total(self):
for order in self:
order.advance_payment_total = sum(
payment.amount for payment in order.advance_payment_ids.filtered(lambda p: p.state == 'posted')
)
@api.depends('amount_total', 'advance_payment_total')
def _compute_amount_residual(self):
for order in self:
order.amount_residual = order.amount_total - order.advance_payment_total
def action_view_advance_payments(self):
self.ensure_one()
action = self.env.ref('account.action_account_payments').sudo().read()[0]
action['domain'] = [('id', 'in', self.advance_payment_ids.ids)]
action['context'] = {
'default_purchase_order_id': self.id,
'default_partner_id': self.partner_id.id,
'default_payment_type': 'outbound',
'default_partner_type': 'supplier',
}
return action
def action_create_deposit_product(self):
"""Create a deposit product for this purchase order"""
self.ensure_one()
# Check if there's a default deposit product in settings
default_deposit_product = self.env['ir.config_parameter'].sudo().get_param(
'purchase_advance_payment.deposit_product_id')
if default_deposit_product:
self.deposit_product_id = int(default_deposit_product)
return self.deposit_product_id
# If no default product, create one
if not self.deposit_product_id:
product_vals = {
'name': f'Deposit for PO {self.name}',
'type': 'service',
'purchase_ok': True,
'sale_ok': False,
'invoice_policy': 'order', # Ordered quantities for deposit
'supplier_taxes_id': [(6, 0, [])], # No supplier taxes
}
deposit_product = self.env['product.product'].create(product_vals)
self.deposit_product_id = deposit_product.id
return self.deposit_product_id
def button_draft(self):
res = super().button_draft()
# Remove deposit lines when resetting to draft
for order in self:
deposit_lines = order.order_line.filtered(lambda l: l.is_deposit)
deposit_lines.unlink()
return res
def action_apply_deposit(self):
"""Apply advance payment as deposit line in the purchase order"""
self.ensure_one()
if self.advance_payment_total <= 0:
raise UserError("No advance payment found for this purchase order.")
# Create or update deposit product
if not self.deposit_product_id:
self.action_create_deposit_product()
# Check if deposit line already exists
existing_deposit_line = self.order_line.filtered(lambda l: l.is_deposit)
if existing_deposit_line:
# Update existing deposit line
existing_deposit_line.write({
'product_qty': 1,
'price_unit': -self.advance_payment_total, # Negative value for deposit
'taxes_id': [(6, 0, [])], # No taxes
})
else:
# Create new deposit line
deposit_vals = {
'order_id': self.id,
'product_id': self.deposit_product_id.id,
'name': f'Deposit payment for PO {self.name}',
'product_qty': 1,
'product_uom': self.deposit_product_id.uom_id.id,
'price_unit': -self.advance_payment_total, # Negative value for deposit
'is_deposit': True,
'date_planned': fields.Datetime.now(),
'taxes_id': [(6, 0, [])], # No taxes
}
self.env['purchase.order.line'].create(deposit_vals)
return True
def action_create_invoice(self):
"""Override to ensure deposit line is included in vendor bill"""
# Apply deposit before creating invoice
for order in self:
if order.advance_payment_total > 0:
order.action_apply_deposit()
# Call super to create the invoice
invoices = super().action_create_invoice()
# Ensure deposit lines have quantity 1 in the created invoices
if 'res_id' in invoices and invoices['res_id']:
# Single invoice
invoice = self.env['account.move'].browse(invoices['res_id'])
self._fix_deposit_line_quantities(invoice)
elif 'domain' in invoices and invoices['domain']:
# Multiple invoices
invoice_ids = self.env['account.move'].search(invoices['domain'])
for invoice in invoice_ids:
self._fix_deposit_line_quantities(invoice)
return invoices
def _fix_deposit_line_quantities(self, invoice):
"""Fix deposit line quantities in the invoice"""
for line in invoice.invoice_line_ids:
if line.purchase_line_id and line.purchase_line_id.is_deposit:
line.write({
'quantity': 1.0,
'tax_ids': [(6, 0, [])] # No taxes
})
class PurchaseOrderLine(models.Model):
_inherit = 'purchase.order.line'
is_deposit = fields.Boolean(
string='Is Deposit',
default=False,
help='Identifies if this line is a deposit payment'
)
def _prepare_account_move_line(self, move=False):
"""Override to ensure deposit lines have correct quantity in vendor bill"""
self.ensure_one()
res = super()._prepare_account_move_line(move)
# If this is a deposit line, ensure quantity is 1 and no taxes
if self.is_deposit:
res['quantity'] = 1
res['tax_ids'] = [(6, 0, [])] # No taxes
return res
def _get_invoice_qty(self):
"""Override to ensure deposit lines have correct quantity for invoicing"""
self.ensure_one()
if self.is_deposit:
# For deposit lines, always invoice quantity 1 regardless of received qty
return 1.0
return super()._get_invoice_qty()

View File

@ -1,13 +1,13 @@
from odoo import models, fields, api
class ResConfigSettings(models.TransientModel):
_inherit = 'res.config.settings'
deposit_product_id = fields.Many2one(
'product.product',
string='Default Deposit Product',
domain=[('type', '=', 'service')],
config_parameter='purchase_advance_payment.deposit_product_id',
help='Default product used for advance payment deposits'
from odoo import models, fields, api
class ResConfigSettings(models.TransientModel):
_inherit = 'res.config.settings'
deposit_product_id = fields.Many2one(
'product.product',
string='Default Deposit Product',
domain=[('type', '=', 'service')],
config_parameter='purchase_advance_payment.deposit_product_id',
help='Default product used for advance payment deposits'
)

View File

@ -1,2 +1,2 @@
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
access_link_advance_payment_wizard,access.link.advance.payment.wizard,model_link_advance_payment_wizard,base.group_user,1,1,1,1
1 id name model_id:id group_id:id perm_read perm_write perm_create perm_unlink
2 access_link_advance_payment_wizard access.link.advance.payment.wizard model_link_advance_payment_wizard base.group_user 1 1 1 1

View File

@ -1,40 +1,40 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<data>
<!-- Account Payment Form View -->
<record id="view_account_payment_form_inherit_advance_payment" model="ir.ui.view">
<field name="name">account.payment.form.inherit.advance.payment</field>
<field name="model">account.payment</field>
<field name="inherit_id" ref="account.view_account_payment_form"/>
<field name="arch" type="xml">
<xpath expr="//sheet/group[2]" position="after">
<group>
<field name="is_advance_payment" invisible="1"/>
<field name="purchase_order_id"
invisible="not is_advance_payment"
required="is_advance_payment"/>
</group>
</xpath>
<xpath expr="//header" position="inside">
<button name="%(purchase_advance_payment.action_link_advance_payment_wizard_payment)d"
string="Link to PO"
type="action"
class="btn-primary"
invisible="state != 'draft' or is_advance_payment"/>
</xpath>
</field>
</record>
<!-- Account Payment Tree View -->
<record id="view_account_payment_tree_inherit_advance_payment" model="ir.ui.view">
<field name="name">account.payment.tree.inherit.advance.payment</field>
<field name="model">account.payment</field>
<field name="inherit_id" ref="account.view_account_payment_tree"/>
<field name="arch" type="xml">
<xpath expr="//tree/field[@name='partner_id']" position="after">
<field name="purchase_order_id"/>
</xpath>
</field>
</record>
</data>
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<data>
<!-- Account Payment Form View -->
<record id="view_account_payment_form_inherit_advance_payment" model="ir.ui.view">
<field name="name">account.payment.form.inherit.advance.payment</field>
<field name="model">account.payment</field>
<field name="inherit_id" ref="account.view_account_payment_form"/>
<field name="arch" type="xml">
<xpath expr="//sheet/group[2]" position="after">
<group>
<field name="is_advance_payment" invisible="1"/>
<field name="purchase_order_id"
invisible="not is_advance_payment"
required="is_advance_payment"/>
</group>
</xpath>
<xpath expr="//header" position="inside">
<button name="%(purchase_advance_payment.action_link_advance_payment_wizard_payment)d"
string="Link to PO"
type="action"
class="btn-primary"
invisible="state != 'draft' or is_advance_payment"/>
</xpath>
</field>
</record>
<!-- Account Payment List View -->
<record id="view_account_payment_tree_inherit_advance_payment" model="ir.ui.view">
<field name="name">account.payment.tree.inherit.advance.payment</field>
<field name="model">account.payment</field>
<field name="inherit_id" ref="account.view_account_payment_tree"/>
<field name="arch" type="xml">
<xpath expr="//list/field[@name='partner_id']" position="after">
<field name="purchase_order_id"/>
</xpath>
</field>
</record>
</data>
</odoo>

View File

@ -1,56 +1,56 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<data>
<!-- Purchase Order Form View -->
<record id="view_purchase_order_form_inherit_advance_payment" model="ir.ui.view">
<field name="name">purchase.order.form.inherit.advance.payment</field>
<field name="model">purchase.order</field>
<field name="inherit_id" ref="purchase.purchase_order_form"/>
<field name="arch" type="xml">
<xpath expr="//sheet/group/group[2]" position="after">
<group>
<field name="deposit_product_id" invisible="1"/>
</group>
</xpath>
<xpath expr="//sheet/notebook" position="inside">
<page string="Advance Payments" name="advance_payments">
<group>
<field name="advance_payment_total" widget="monetary"/>
<field name="amount_residual" widget="monetary"/>
</group>
<group>
<button name="action_apply_deposit"
string="Apply Deposit"
type="object"
class="btn-primary"
invisible="advance_payment_total &lt;= 0"/>
<button name="%(purchase_advance_payment.action_link_advance_payment_wizard)d"
string="Link Advance Payment"
type="action"
class="btn-secondary"
context="{'default_purchase_order_id': active_id}"/>
</group>
<field name="advance_payment_ids">
<tree>
<field name="name"/>
<field name="date"/>
<field name="amount" widget="monetary"/>
<field name="state"/>
<field name="journal_id"/>
</tree>
</field>
</page>
</xpath>
<xpath expr="//field[@name='order_line']/tree/field[@name='price_unit']" position="after">
<field name="is_deposit" invisible="1"/>
</xpath>
<xpath expr="//field[@name='order_line']/form//field[@name='price_unit']" position="after">
<field name="is_deposit" invisible="1"/>
</xpath>
</field>
</record>
</data>
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<data>
<!-- Purchase Order Form View -->
<record id="view_purchase_order_form_inherit_advance_payment" model="ir.ui.view">
<field name="name">purchase.order.form.inherit.advance.payment</field>
<field name="model">purchase.order</field>
<field name="inherit_id" ref="purchase.purchase_order_form"/>
<field name="arch" type="xml">
<xpath expr="//sheet/group/group[2]" position="after">
<group>
<field name="deposit_product_id" invisible="1"/>
</group>
</xpath>
<xpath expr="//sheet/notebook" position="inside">
<page string="Advance Payments" name="advance_payments">
<group>
<field name="advance_payment_total" widget="monetary"/>
<field name="amount_residual" widget="monetary"/>
</group>
<group>
<button name="action_apply_deposit"
string="Apply Deposit"
type="object"
class="btn-primary"
invisible="advance_payment_total &lt;= 0"/>
<button name="%(purchase_advance_payment.action_link_advance_payment_wizard)d"
string="Link Advance Payment"
type="action"
class="btn-secondary"
context="{'default_purchase_order_id': id}"/>
</group>
<field name="advance_payment_ids">
<list>
<field name="name"/>
<field name="date"/>
<field name="amount" widget="monetary"/>
<field name="state"/>
<field name="journal_id"/>
</list>
</field>
</page>
</xpath>
<xpath expr="//field[@name='order_line']/list/field[@name='price_unit']" position="after">
<field name="is_deposit" invisible="1"/>
</xpath>
<xpath expr="//field[@name='order_line']/form//field[@name='price_unit']" position="after">
<field name="is_deposit" invisible="1"/>
</xpath>
</field>
</record>
</data>
</odoo>

View File

@ -1,28 +1,34 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<data>
<record id="res_config_settings_view_form_purchase_advance_payment" model="ir.ui.view">
<field name="name">res.config.settings.view.form.inherit.purchase.advance.payment</field>
<field name="model">res.config.settings</field>
<field name="inherit_id" ref="base.res_config_settings_view_form"/>
<field name="arch" type="xml">
<xpath expr="//form" position="inside">
<div class="app_settings_block" data-string="Purchase" string="Purchase" data-key="purchase">
<h2>Advance Payment</h2>
<div class="row mt16 o_settings_container">
<div class="col-12 col-lg-6 o_setting_box">
<div class="o_setting_left_pane">
<field name="deposit_product_id"/>
<label for="deposit_product_id"/>
<div class="text-muted">
Default product used for advance payment deposits
</div>
</div>
</div>
</div>
</div>
</xpath>
</field>
</record>
</data>
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<data>
<record id="res_config_settings_view_form_purchase_advance_payment" model="ir.ui.view">
<field name="name">res.config.settings.view.form.inherit.purchase.advance.payment</field>
<field name="model">res.config.settings</field>
<field name="inherit_id" ref="base.res_config_settings_view_form"/>
<field name="arch" type="xml">
<xpath expr="//form" position="inside">
<div class="app_settings_block" data-string="Purchase" string="Purchase" data-key="purchase">
<h2>Advance Payment</h2>
<div class="row mt16 o_settings_container">
<div class="col-12 col-lg-6 o_setting_box">
<div class="o_setting_left_pane" />
<div class="o_setting_right_pane">
<label
for="deposit_product_id"
string="Advance Payments"
/>
<div class="text-muted">
Default product used for advance payment deposits
</div>
<div class="text-muted">
<field name="deposit_product_id" />
</div>
</div>
</div>
</div>
</div>
</xpath>
</field>
</record>
</data>
</odoo>

Binary file not shown.

Binary file not shown.

View File

@ -30,15 +30,22 @@ class LinkAdvancePaymentWizard(models.TransientModel):
def default_get(self, fields):
res = super().default_get(fields)
# Handle context from purchase order
if self._context.get('active_model') == 'purchase.order' and self._context.get('active_id'):
po = self.env['purchase.order'].browse(self._context['active_id'])
if self.env.context.get('active_model') == 'purchase.order' and self.env.context.get('active_id'):
po = self.env['purchase.order'].browse(self.env.context['active_id'])
res['purchase_order_id'] = po.id
res['currency_id'] = po.currency_id.id
if 'amount' in fields:
res['amount'] = po.amount_residual
# Handle context from purchase order when called from the button (using default_purchase_order_id)
elif self.env.context.get('default_purchase_order_id'):
po = self.env['purchase.order'].browse(self.env.context['default_purchase_order_id'])
res['purchase_order_id'] = po.id
res['currency_id'] = po.currency_id.id
if 'amount' in fields and 'amount' not in res:
res['amount'] = po.amount_residual
# Handle context from payment
elif self._context.get('active_model') == 'account.payment' and self._context.get('active_id'):
payment = self.env['account.payment'].browse(self._context['active_id'])
elif self.env.context.get('active_model') == 'account.payment' and self.env.context.get('active_id'):
payment = self.env['account.payment'].browse(self.env.context['active_id'])
res['payment_id'] = payment.id
res['currency_id'] = payment.currency_id.id
if 'amount' in fields:

View File

@ -1,41 +1,41 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<data>
<!-- Link Advance Payment Wizard Form View -->
<record id="view_link_advance_payment_wizard_form" model="ir.ui.view">
<field name="name">link.advance.payment.wizard.form</field>
<field name="model">link.advance.payment.wizard</field>
<field name="arch" type="xml">
<form string="Link Advance Payment">
<group>
<field name="purchase_order_id"/>
<field name="payment_id" domain="[('state', '=', 'draft'), ('payment_type', '=', 'outbound')]"/>
<field name="amount"/>
<field name="currency_id" invisible="1"/>
</group>
<footer>
<button string="Link Payment" name="action_link_payment" type="object" class="btn-primary"/>
<button string="Cancel" class="btn-secondary" special="cancel"/>
</footer>
</form>
</field>
</record>
<!-- Link Advance Payment Wizard Action -->
<record id="action_link_advance_payment_wizard" model="ir.actions.act_window">
<field name="name">Link Advance Payment</field>
<field name="res_model">link.advance.payment.wizard</field>
<field name="view_mode">form</field>
<field name="target">new</field>
</record>
<!-- Link Advance Payment Wizard Action from Payment -->
<record id="action_link_advance_payment_wizard_payment" model="ir.actions.act_window">
<field name="name">Link to Purchase Order</field>
<field name="res_model">link.advance.payment.wizard</field>
<field name="view_mode">form</field>
<field name="target">new</field>
<field name="context">{'active_model': 'account.payment', 'active_id': active_id}</field>
</record>
</data>
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<data>
<!-- Link Advance Payment Wizard Form View -->
<record id="view_link_advance_payment_wizard_form" model="ir.ui.view">
<field name="name">link.advance.payment.wizard.form</field>
<field name="model">link.advance.payment.wizard</field>
<field name="arch" type="xml">
<form string="Link Advance Payment">
<group>
<field name="purchase_order_id"/>
<field name="payment_id" domain="[('state', '=', 'draft'), ('payment_type', '=', 'outbound')]"/>
<field name="amount"/>
<field name="currency_id" invisible="1"/>
</group>
<footer>
<button string="Link Payment" name="action_link_payment" type="object" class="btn-primary"/>
<button string="Cancel" class="btn-secondary" special="cancel"/>
</footer>
</form>
</field>
</record>
<!-- Link Advance Payment Wizard Action -->
<record id="action_link_advance_payment_wizard" model="ir.actions.act_window">
<field name="name">Link Advance Payment</field>
<field name="res_model">link.advance.payment.wizard</field>
<field name="view_mode">form</field>
<field name="target">new</field>
</record>
<!-- Link Advance Payment Wizard Action from Payment -->
<record id="action_link_advance_payment_wizard_payment" model="ir.actions.act_window">
<field name="name">Link to Purchase Order</field>
<field name="res_model">link.advance.payment.wizard</field>
<field name="view_mode">form</field>
<field name="target">new</field>
<field name="context">{'active_model': 'account.payment', 'active_id': active_id}</field>
</record>
</data>
</odoo>