feat: Enable cross-company batch payments by overriding payment constraints, adjusting payment creation logic, and updating views to support multi-company contexts, while also adding a payment search debug logger.

This commit is contained in:
Suherdy Yacob 2026-03-09 14:49:36 +07:00
parent 822ed95c53
commit a6c1d582ed
10 changed files with 88 additions and 3 deletions

Binary file not shown.

View File

@ -2,3 +2,4 @@
from . import account_batch_payment
from . import account_payment
from . import account_payment_register
from . import account_payment_debug

View File

@ -9,6 +9,23 @@ _logger = logging.getLogger(__name__)
class AccountBatchPayment(models.Model):
_inherit = "account.batch.payment"
# Override payment_ids to remove strict company check, allowing cross-company payments to be added
payment_ids = fields.One2many(
'account.payment',
'batch_payment_id',
string="Payments",
required=True,
check_company=False
)
company_id = fields.Many2one(
'res.company',
string='Company',
related='journal_id.company_id',
store=True,
readonly=True
)
# Add a field to store direct payment lines
direct_payment_line_ids = fields.One2many(
'account.batch.payment.line',
@ -83,12 +100,21 @@ class AccountBatchPayment(models.Model):
'currency_id': line.currency_id.id,
'date': line.date,
'journal_id': self.journal_id.id,
'company_id': line.company_id.id,
'payment_method_line_id': payment_method_line.id,
'ref': line.memo,
'expense_account_id': line.expense_account_id.id,
}
payment = self.env['account.payment'].create(payment_vals)
# Create the payment with the branch's company context, bypassing security limits momentarily
payment = self.env['account.payment'].sudo().with_context(
allowed_company_ids=[line.company_id.id, self.company_id.id, self.env.company.id],
default_company_id=line.company_id.id,
).create(payment_vals)
# Since some compute methods might try to overwrite company_id based on journal, force it again
payment.write({'company_id': line.company_id.id})
payment.action_post()
# Link the payment to the line
@ -109,6 +135,25 @@ class AccountBatchPayment(models.Model):
# If validation fails, log the error but don't prevent payment creation
_logger.warning(f"Failed to automatically validate batch payment {self.id}: {str(e)}")
@api.constrains('batch_type', 'journal_id', 'payment_ids')
def _check_payments_constrains(self):
"""Override standard constraint to allow cross-company / cross-journal payments."""
for record in self:
all_types = set(record.payment_ids.mapped('payment_type'))
if all_types and record.batch_type not in all_types:
raise ValidationError(_("The batch must have the same type as the payments it contains."))
all_payment_methods = record.payment_ids.payment_method_id
if len(all_payment_methods) > 1:
raise ValidationError(_("All payments in the batch must share the same payment method."))
if all_payment_methods and record.payment_method_id not in all_payment_methods:
raise ValidationError(_("The batch must have the same payment method as the payments it contains."))
payment_null = record.payment_ids.filtered(lambda p: p.amount == 0)
if payment_null:
raise ValidationError(_('You cannot add payments with zero amount in a Batch Payment.'))
non_posted = record.payment_ids.filtered(lambda p: p.state != 'posted')
if non_posted:
raise ValidationError(_('You cannot add payments that are not posted.'))
class AccountBatchPaymentLine(models.Model):
_name = "account.batch.payment.line"
@ -120,9 +165,15 @@ class AccountBatchPaymentLine(models.Model):
required=True,
ondelete='cascade'
)
company_id = fields.Many2one(
'res.company',
string='Company',
default=lambda self: self.env.company
)
partner_id = fields.Many2one(
'res.partner',
string='Partner'
string='Partner',
check_company=True
# Removed required=True to avoid constraint issues
)
amount = fields.Monetary(
@ -138,6 +189,7 @@ class AccountBatchPaymentLine(models.Model):
expense_account_id = fields.Many2one(
'account.account',
string='Expense Account',
check_company=True,
domain="[('account_type', 'not in', ('asset_receivable', 'liability_payable'))]"
)
memo = fields.Char(string='Memo')

View File

@ -0,0 +1,22 @@
import logging
from odoo import models, api
_logger = logging.getLogger(__name__)
class AccountPayment(models.Model):
_inherit = "account.payment"
@api.model
def search(self, args, offset=0, limit=None, order=None, count=False):
try:
with open('/tmp/odoo_payment_search.log', 'a') as f:
f.write(f"\\n{'='*40}\\n")
f.write(f"ACCOUNT PAYMENT SEARCH CALLED\\n")
f.write(f"Args: {args}\\n")
f.write(f"Context: {self.env.context}\\n")
f.write(f"{'='*40}\\n")
except Exception as e:
_logger.error(f"Failed to log to /tmp: {e}")
return super(AccountPayment, self).search(args, offset, limit, order, count)

View File

@ -9,6 +9,7 @@
<page string="Direct Payment Lines" name="direct_payment_lines">
<field name="direct_payment_line_ids">
<tree editable="bottom">
<field name="company_id" options="{'no_create': True}"/>
<field name="partner_id" domain="parent.batch_type == 'outbound' and [('supplier_rank', '>', 0)] or [('customer_rank', '>', 0)]" options="{'no_create': True}"/>
<field name="amount" sum="Total"/>
<field name="expense_account_id"/>
@ -23,6 +24,15 @@
<button name="generate_payments_from_lines" string="Generate Payments" type="object"
class="oe_highlight" invisible="state != 'draft'"/>
</xpath>
<!-- Override payment_ids to remove journal_id constraint to allow cross-company branch payments -->
<xpath expr="//field[@name='payment_ids']" position="before">
<field name="company_id" invisible="1"/>
</xpath>
<xpath expr="//field[@name='payment_ids']" position="attributes">
<attribute name="domain">[('batch_payment_id', '=', False), ('state', '=', 'posted'), ('is_move_sent', '=', False), ('payment_method_id', '=', payment_method_id), ('payment_type','=',batch_type), ('amount', '!=', 0)]</attribute>
<!-- Context to allow viewing payments across all companies the user has access to -->
<attribute name="context">{'default_payment_type': batch_type, 'default_journal_id': journal_id}</attribute>
</xpath>
</field>
</record>
</odoo>