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:
parent
822ed95c53
commit
a6c1d582ed
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -1,4 +1,5 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from . import account_batch_payment
|
||||
from . import account_payment
|
||||
from . import account_payment_register
|
||||
from . import account_payment_register
|
||||
from . import account_payment_debug
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -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')
|
||||
|
||||
22
models/account_payment_debug.py
Normal file
22
models/account_payment_debug.py
Normal 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)
|
||||
|
||||
@ -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>
|
||||
Loading…
Reference in New Issue
Block a user