fix the _ error

This commit is contained in:
admin.suherdy 2025-11-19 16:13:23 +07:00
parent 8f13d5bc82
commit fbb48b893c
13 changed files with 351 additions and 351 deletions

View File

@ -1,22 +1,22 @@
{ {
'name': 'Vendor Payment with Misc Journals', 'name': 'Vendor Payment with Misc Journals',
'version': '17.0.1.0.0', 'version': '17.0.1.0.0',
'category': 'Accounting', 'category': 'Accounting',
'summary': 'Allow using misc journals for vendor bill payments', 'summary': 'Allow using misc journals for vendor bill payments',
'description': """ 'description': """
This module extends the vendor payment functionality to allow using misc journals This module extends the vendor payment functionality to allow using misc journals
for registering payments of vendor bills. When a misc journal is selected, for registering payments of vendor bills. When a misc journal is selected,
the payment entry will use the default account of the selected journal. the payment entry will use the default account of the selected journal.
""", """,
'author': 'Suherdy Yacob', 'author': 'Suherdy Yacob',
'depends': [ 'depends': [
'account', 'account',
'purchase', 'purchase',
], ],
'data': [ 'data': [
'views/account_payment_views.xml', 'views/account_payment_views.xml',
], ],
'installable': True, 'installable': True,
'auto_install': False, 'auto_install': False,
'license': 'LGPL-3', 'license': 'LGPL-3',
} }

Binary file not shown.

Binary file not shown.

View File

@ -1,2 +1,2 @@
from . import account_payment from . import account_payment
from . import account_payment_register from . import account_payment_register

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -1,212 +1,212 @@
from odoo import models, fields, api from odoo import models, fields, api, _
from odoo.exceptions import UserError from odoo.exceptions import UserError
class AccountPayment(models.Model): class AccountPayment(models.Model):
_inherit = 'account.payment' _inherit = 'account.payment'
@api.depends('payment_type', 'partner_type') @api.depends('payment_type', 'partner_type')
def _compute_available_journal_ids(self): def _compute_available_journal_ids(self):
""" """
Override to include misc journals for vendor payments Override to include misc journals for vendor payments
""" """
# Call the parent method to get the original computation with bank/cash journals # Call the parent method to get the original computation with bank/cash journals
super()._compute_available_journal_ids() super()._compute_available_journal_ids()
# Then extend with general journals for supplier payments # Then extend with general journals for supplier payments
for pay in self: for pay in self:
if pay.partner_type == 'supplier': if pay.partner_type == 'supplier':
# Include all general journals (not just those with payment methods) # Include all general journals (not just those with payment methods)
# We'll handle payment method availability separately # We'll handle payment method availability separately
all_general_journals = self.env['account.journal'].search([ all_general_journals = self.env['account.journal'].search([
'|', '|',
('company_id', 'parent_of', self.env.company.id), ('company_id', 'parent_of', self.env.company.id),
('company_id', 'child_of', self.env.company.id), ('company_id', 'child_of', self.env.company.id),
('type', '=', 'general'), ('type', '=', 'general'),
]) ])
pay.available_journal_ids |= all_general_journals pay.available_journal_ids |= all_general_journals
@api.depends('payment_type', 'journal_id', 'currency_id') @api.depends('payment_type', 'journal_id', 'currency_id')
def _compute_payment_method_line_fields(self): def _compute_payment_method_line_fields(self):
""" """
Override to include payment methods for general journals Override to include payment methods for general journals
""" """
for pay in self: for pay in self:
available_payment_method_lines = pay.journal_id._get_available_payment_method_lines(pay.payment_type) available_payment_method_lines = pay.journal_id._get_available_payment_method_lines(pay.payment_type)
# For general journals, if no payment methods are available, provide defaults # For general journals, if no payment methods are available, provide defaults
if pay.journal_id.type == 'general' and not available_payment_method_lines: if pay.journal_id.type == 'general' and not available_payment_method_lines:
# Get the manual payment methods (these work with general journals) # Get the manual payment methods (these work with general journals)
if pay.payment_type == 'outbound': if pay.payment_type == 'outbound':
manual_out = self.env.ref('account.account_payment_method_manual_out', raise_if_not_found=False) manual_out = self.env.ref('account.account_payment_method_manual_out', raise_if_not_found=False)
if manual_out: if manual_out:
# Create a payment method line for this journal if it doesn't exist # Create a payment method line for this journal if it doesn't exist
method_line = self.env['account.payment.method.line'].search([ method_line = self.env['account.payment.method.line'].search([
('journal_id', '=', pay.journal_id.id), ('journal_id', '=', pay.journal_id.id),
('payment_method_id', '=', manual_out.id) ('payment_method_id', '=', manual_out.id)
], limit=1) ], limit=1)
if not method_line: if not method_line:
method_line = self.env['account.payment.method.line'].create({ method_line = self.env['account.payment.method.line'].create({
'name': 'Manual (Outbound)', 'name': 'Manual (Outbound)',
'payment_method_id': manual_out.id, 'payment_method_id': manual_out.id,
'journal_id': pay.journal_id.id, 'journal_id': pay.journal_id.id,
}) })
available_payment_method_lines = method_line available_payment_method_lines = method_line
elif pay.payment_type == 'inbound': elif pay.payment_type == 'inbound':
manual_in = self.env.ref('account.account_payment_method_manual_in', raise_if_not_found=False) manual_in = self.env.ref('account.account_payment_method_manual_in', raise_if_not_found=False)
if manual_in: if manual_in:
# Create a payment method line for this journal if it doesn't exist # Create a payment method line for this journal if it doesn't exist
method_line = self.env['account.payment.method.line'].search([ method_line = self.env['account.payment.method.line'].search([
('journal_id', '=', pay.journal_id.id), ('journal_id', '=', pay.journal_id.id),
('payment_method_id', '=', manual_in.id) ('payment_method_id', '=', manual_in.id)
], limit=1) ], limit=1)
if not method_line: if not method_line:
method_line = self.env['account.payment.method.line'].create({ method_line = self.env['account.payment.method.line'].create({
'name': 'Manual (Inbound)', 'name': 'Manual (Inbound)',
'payment_method_id': manual_in.id, 'payment_method_id': manual_in.id,
'journal_id': pay.journal_id.id, 'journal_id': pay.journal_id.id,
}) })
available_payment_method_lines = method_line available_payment_method_lines = method_line
pay.available_payment_method_line_ids = available_payment_method_lines pay.available_payment_method_line_ids = available_payment_method_lines
to_exclude = pay._get_payment_method_codes_to_exclude() to_exclude = pay._get_payment_method_codes_to_exclude()
if to_exclude: if to_exclude:
pay.available_payment_method_line_ids = pay.available_payment_method_line_ids.filtered(lambda x: x.code not in to_exclude) pay.available_payment_method_line_ids = pay.available_payment_method_line_ids.filtered(lambda x: x.code not in to_exclude)
@api.depends('available_payment_method_line_ids') @api.depends('available_payment_method_line_ids')
def _compute_payment_method_line_id(self): def _compute_payment_method_line_id(self):
""" """
Override to ensure payment method is selected for general journals Override to ensure payment method is selected for general journals
""" """
for pay in self: for pay in self:
available_payment_method_lines = pay.available_payment_method_line_ids available_payment_method_lines = pay.available_payment_method_line_ids
# Select the first available one by default. # Select the first available one by default.
if pay.payment_method_line_id in available_payment_method_lines: if pay.payment_method_line_id in available_payment_method_lines:
pay.payment_method_line_id = pay.payment_method_line_id pay.payment_method_line_id = pay.payment_method_line_id
elif available_payment_method_lines: elif available_payment_method_lines:
pay.payment_method_line_id = available_payment_method_lines[0]._origin pay.payment_method_line_id = available_payment_method_lines[0]._origin
else: else:
# For general journals, we might need to handle this differently # For general journals, we might need to handle this differently
# But we'll let the constraint handle validation # But we'll let the constraint handle validation
pay.payment_method_line_id = False pay.payment_method_line_id = False
def _synchronize_from_moves(self, changed_fields): def _synchronize_from_moves(self, changed_fields):
""" """
Override to allow general journals for payments Override to allow general journals for payments
""" """
# Remove the check that restricts journals to only bank/cash types # Remove the check that restricts journals to only bank/cash types
if self._context.get('skip_account_move_synchronization'): if self._context.get('skip_account_move_synchronization'):
return return
for pay in self.with_context(skip_account_move_synchronization=True): for pay in self.with_context(skip_account_move_synchronization=True):
# After the migration to 14.0, the journal entry could be shared between the account.payment and the # After the migration to 14.0, the journal entry could be shared between the account.payment and the
# account.bank.statement.line. In that case, the synchronization will only be made with the statement line. # account.bank.statement.line. In that case, the synchronization will only be made with the statement line.
if pay.move_id.statement_line_id: if pay.move_id.statement_line_id:
continue continue
move = pay.move_id move = pay.move_id
move_vals_to_write = {} move_vals_to_write = {}
payment_vals_to_write = {} payment_vals_to_write = {}
if 'journal_id' in changed_fields: if 'journal_id' in changed_fields:
# Remove the original restriction - allow general journals too # Remove the original restriction - allow general journals too
if pay.journal_id.type not in ('bank', 'cash', 'general'): if pay.journal_id.type not in ('bank', 'cash', 'general'):
raise UserError(_("A payment must belongs to a bank, cash, or general journal.")) raise UserError(_("A payment must belongs to a bank, cash, or general journal."))
# Continue with the rest of the original method # Continue with the rest of the original method
if 'line_ids' in changed_fields: if 'line_ids' in changed_fields:
all_lines = move.line_ids all_lines = move.line_ids
liquidity_lines, counterpart_lines, writeoff_lines = pay._seek_for_lines() liquidity_lines, counterpart_lines, writeoff_lines = pay._seek_for_lines()
if len(liquidity_lines) != 1: if len(liquidity_lines) != 1:
raise UserError(_( raise UserError(_(
"Journal Entry %s is not valid. In order to proceed, the journal items must " "Journal Entry %s is not valid. In order to proceed, the journal items must "
"include one and only one outstanding payments/receipts account.", "include one and only one outstanding payments/receipts account.",
move.display_name, move.display_name,
)) ))
if len(counterpart_lines) != 1: if len(counterpart_lines) != 1:
raise UserError(_( raise UserError(_(
"Journal Entry %s is not valid. In order to proceed, the journal items must " "Journal Entry %s is not valid. In order to proceed, the journal items must "
"include one and only one receivable/payable account (with an exception of " "include one and only one receivable/payable account (with an exception of "
"internal transfers).", "internal transfers).",
move.display_name, move.display_name,
)) ))
if any(line.currency_id != all_lines[0].currency_id for line in all_lines): if any(line.currency_id != all_lines[0].currency_id for line in all_lines):
raise UserError(_( raise UserError(_(
"Journal Entry %s is not valid. In order to proceed, the journal items must " "Journal Entry %s is not valid. In order to proceed, the journal items must "
"share the same currency.", "share the same currency.",
move.display_name, move.display_name,
)) ))
if any(line.partner_id != all_lines[0].partner_id for line in all_lines): if any(line.partner_id != all_lines[0].partner_id for line in all_lines):
raise UserError(_( raise UserError(_(
"Journal Entry %s is not valid. In order to proceed, the journal items must " "Journal Entry %s is not valid. In order to proceed, the journal items must "
"share the same partner.", "share the same partner.",
move.display_name, move.display_name,
)) ))
if counterpart_lines.account_id.account_type == 'asset_receivable': if counterpart_lines.account_id.account_type == 'asset_receivable':
partner_type = 'customer' partner_type = 'customer'
else: else:
partner_type = 'supplier' partner_type = 'supplier'
liquidity_amount = liquidity_lines.amount_currency liquidity_amount = liquidity_lines.amount_currency
move_vals_to_write.update({ move_vals_to_write.update({
'currency_id': liquidity_lines.currency_id.id, 'currency_id': liquidity_lines.currency_id.id,
'partner_id': liquidity_lines.partner_id.id, 'partner_id': liquidity_lines.partner_id.id,
}) })
payment_vals_to_write.update({ payment_vals_to_write.update({
'amount': abs(liquidity_amount), 'amount': abs(liquidity_amount),
'partner_type': partner_type, 'partner_type': partner_type,
'currency_id': liquidity_lines.currency_id.id, 'currency_id': liquidity_lines.currency_id.id,
'destination_account_id': counterpart_lines.account_id.id, 'destination_account_id': counterpart_lines.account_id.id,
'partner_id': liquidity_lines.partner_id.id, 'partner_id': liquidity_lines.partner_id.id,
}) })
if liquidity_amount > 0.0: if liquidity_amount > 0.0:
payment_vals_to_write.update({'payment_type': 'inbound'}) payment_vals_to_write.update({'payment_type': 'inbound'})
elif liquidity_amount < 0.0: elif liquidity_amount < 0.0:
payment_vals_to_write.update({'payment_type': 'outbound'}) payment_vals_to_write.update({'payment_type': 'outbound'})
move.write(move._cleanup_write_orm_values(move, move_vals_to_write)) move.write(move._cleanup_write_orm_values(move, move_vals_to_write))
pay.write(move._cleanup_write_orm_values(pay, payment_vals_to_write)) pay.write(move._cleanup_write_orm_values(pay, payment_vals_to_write))
@api.depends('journal_id', 'payment_type', 'payment_method_line_id') @api.depends('journal_id', 'payment_type', 'payment_method_line_id')
def _compute_outstanding_account_id(self): def _compute_outstanding_account_id(self):
""" """
Override to use the default account of misc journal when selected Override to use the default account of misc journal when selected
""" """
for pay in self: for pay in self:
# If using a general/misc journal, use its default account # If using a general/misc journal, use its default account
if pay.journal_id.type == 'general': if pay.journal_id.type == 'general':
if pay.journal_id.default_account_id: if pay.journal_id.default_account_id:
pay.outstanding_account_id = pay.journal_id.default_account_id pay.outstanding_account_id = pay.journal_id.default_account_id
else: else:
# Fallback to the original logic if no default account is set # Fallback to the original logic if no default account is set
if pay.payment_type == 'inbound': if pay.payment_type == 'inbound':
pay.outstanding_account_id = (pay.payment_method_line_id.payment_account_id pay.outstanding_account_id = (pay.payment_method_line_id.payment_account_id
or pay.journal_id.company_id.account_journal_payment_debit_account_id) or pay.journal_id.company_id.account_journal_payment_debit_account_id)
elif pay.payment_type == 'outbound': elif pay.payment_type == 'outbound':
pay.outstanding_account_id = (pay.payment_method_line_id.payment_account_id pay.outstanding_account_id = (pay.payment_method_line_id.payment_account_id
or pay.journal_id.company_id.account_journal_payment_credit_account_id) or pay.journal_id.company_id.account_journal_payment_credit_account_id)
else: else:
pay.outstanding_account_id = False pay.outstanding_account_id = False
else: else:
# For bank/cash journals, use the original logic # For bank/cash journals, use the original logic
if pay.payment_type == 'inbound': if pay.payment_type == 'inbound':
pay.outstanding_account_id = (pay.payment_method_line_id.payment_account_id pay.outstanding_account_id = (pay.payment_method_line_id.payment_account_id
or pay.journal_id.company_id.account_journal_payment_debit_account_id) or pay.journal_id.company_id.account_journal_payment_debit_account_id)
elif pay.payment_type == 'outbound': elif pay.payment_type == 'outbound':
pay.outstanding_account_id = (pay.payment_method_line_id.payment_account_id pay.outstanding_account_id = (pay.payment_method_line_id.payment_account_id
or pay.journal_id.company_id.account_journal_payment_credit_account_id) or pay.journal_id.company_id.account_journal_payment_credit_account_id)
else: else:
pay.outstanding_account_id = False pay.outstanding_account_id = False

View File

@ -1,94 +1,94 @@
from odoo import models, api from odoo import models, api
class AccountPaymentRegister(models.TransientModel): class AccountPaymentRegister(models.TransientModel):
_inherit = 'account.payment.register' _inherit = 'account.payment.register'
@api.depends('payment_type', 'partner_type') @api.depends('payment_type', 'partner_type')
def _compute_available_journal_ids(self): def _compute_available_journal_ids(self):
""" """
Override to include misc journals for vendor payments in the register payment wizard Override to include misc journals for vendor payments in the register payment wizard
""" """
# Call the parent method to get the original computation with bank/cash journals # Call the parent method to get the original computation with bank/cash journals
super()._compute_available_journal_ids() super()._compute_available_journal_ids()
# Then extend with general journals for supplier payments # Then extend with general journals for supplier payments
for pay in self: for pay in self:
if pay.partner_type == 'supplier': if pay.partner_type == 'supplier':
# Include all general journals for supplier payments # Include all general journals for supplier payments
all_general_journals = self.env['account.journal'].search([ all_general_journals = self.env['account.journal'].search([
'|', '|',
('company_id', 'parent_of', self.env.company.id), ('company_id', 'parent_of', self.env.company.id),
('company_id', 'child_of', self.env.company.id), ('company_id', 'child_of', self.env.company.id),
('type', '=', 'general'), ('type', '=', 'general'),
]) ])
pay.available_journal_ids |= all_general_journals pay.available_journal_ids |= all_general_journals
@api.depends('payment_type', 'journal_id', 'currency_id') @api.depends('payment_type', 'journal_id', 'currency_id')
def _compute_payment_method_line_fields(self): def _compute_payment_method_line_fields(self):
""" """
Override to include payment methods for general journals in register payment wizard Override to include payment methods for general journals in register payment wizard
""" """
for pay in self: for pay in self:
available_payment_method_lines = pay.journal_id._get_available_payment_method_lines(pay.payment_type) available_payment_method_lines = pay.journal_id._get_available_payment_method_lines(pay.payment_type)
# For general journals, if no payment methods are available, provide defaults # For general journals, if no payment methods are available, provide defaults
if pay.journal_id.type == 'general' and not available_payment_method_lines: if pay.journal_id.type == 'general' and not available_payment_method_lines:
# Get the manual payment methods (these work with general journals) # Get the manual payment methods (these work with general journals)
if pay.payment_type == 'outbound': if pay.payment_type == 'outbound':
manual_out = self.env.ref('account.account_payment_method_manual_out', raise_if_not_found=False) manual_out = self.env.ref('account.account_payment_method_manual_out', raise_if_not_found=False)
if manual_out: if manual_out:
# Create a payment method line for this journal if it doesn't exist # Create a payment method line for this journal if it doesn't exist
method_line = self.env['account.payment.method.line'].search([ method_line = self.env['account.payment.method.line'].search([
('journal_id', '=', pay.journal_id.id), ('journal_id', '=', pay.journal_id.id),
('payment_method_id', '=', manual_out.id) ('payment_method_id', '=', manual_out.id)
], limit=1) ], limit=1)
if not method_line: if not method_line:
method_line = self.env['account.payment.method.line'].create({ method_line = self.env['account.payment.method.line'].create({
'name': 'Manual (Outbound)', 'name': 'Manual (Outbound)',
'payment_method_id': manual_out.id, 'payment_method_id': manual_out.id,
'journal_id': pay.journal_id.id, 'journal_id': pay.journal_id.id,
}) })
available_payment_method_lines = method_line available_payment_method_lines = method_line
elif pay.payment_type == 'inbound': elif pay.payment_type == 'inbound':
manual_in = self.env.ref('account.account_payment_method_manual_in', raise_if_not_found=False) manual_in = self.env.ref('account.account_payment_method_manual_in', raise_if_not_found=False)
if manual_in: if manual_in:
# Create a payment method line for this journal if it doesn't exist # Create a payment method line for this journal if it doesn't exist
method_line = self.env['account.payment.method.line'].search([ method_line = self.env['account.payment.method.line'].search([
('journal_id', '=', pay.journal_id.id), ('journal_id', '=', pay.journal_id.id),
('payment_method_id', '=', manual_in.id) ('payment_method_id', '=', manual_in.id)
], limit=1) ], limit=1)
if not method_line: if not method_line:
method_line = self.env['account.payment.method.line'].create({ method_line = self.env['account.payment.method.line'].create({
'name': 'Manual (Inbound)', 'name': 'Manual (Inbound)',
'payment_method_id': manual_in.id, 'payment_method_id': manual_in.id,
'journal_id': pay.journal_id.id, 'journal_id': pay.journal_id.id,
}) })
available_payment_method_lines = method_line available_payment_method_lines = method_line
pay.available_payment_method_line_ids = available_payment_method_lines pay.available_payment_method_line_ids = available_payment_method_lines
# Note: account.payment.register doesn't have _get_payment_method_codes_to_exclude method # Note: account.payment.register doesn't have _get_payment_method_codes_to_exclude method
# So we skip the exclusion logic for this model # So we skip the exclusion logic for this model
@api.depends('available_payment_method_line_ids') @api.depends('available_payment_method_line_ids')
def _compute_payment_method_line_id(self): def _compute_payment_method_line_id(self):
""" """
Override to ensure payment method is selected for general journals in register payment wizard Override to ensure payment method is selected for general journals in register payment wizard
""" """
for pay in self: for pay in self:
available_payment_method_lines = pay.available_payment_method_line_ids available_payment_method_lines = pay.available_payment_method_line_ids
# Select the first available one by default. # Select the first available one by default.
if pay.payment_method_line_id in available_payment_method_lines: if pay.payment_method_line_id in available_payment_method_lines:
pay.payment_method_line_id = pay.payment_method_line_id pay.payment_method_line_id = pay.payment_method_line_id
elif available_payment_method_lines: elif available_payment_method_lines:
pay.payment_method_line_id = available_payment_method_lines[0]._origin pay.payment_method_line_id = available_payment_method_lines[0]._origin
else: else:
# For general journals, we might need to handle this differently # For general journals, we might need to handle this differently
# But we'll let the constraint handle validation # But we'll let the constraint handle validation
pay.payment_method_line_id = False pay.payment_method_line_id = False

View File

@ -1,26 +1,26 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<odoo> <odoo>
<!-- Inherit the payment form view to potentially add any custom fields or logic if needed --> <!-- Inherit the payment form view to potentially add any custom fields or logic if needed -->
<record id="view_account_payment_form_inherit" model="ir.ui.view"> <record id="view_account_payment_form_inherit" model="ir.ui.view">
<field name="name">account.payment.form.inherit.vendor.payment.misc</field> <field name="name">account.payment.form.inherit.vendor.payment.misc</field>
<field name="model">account.payment</field> <field name="model">account.payment</field>
<field name="inherit_id" ref="account.view_account_payment_form"/> <field name="inherit_id" ref="account.view_account_payment_form"/>
<field name="arch" type="xml"> <field name="arch" type="xml">
<field name="journal_id" position="attributes"> <field name="journal_id" position="attributes">
<!-- No additional attributes needed as the logic is handled in the model --> <!-- No additional attributes needed as the logic is handled in the model -->
</field> </field>
</field> </field>
</record> </record>
<!-- Inherit the register payment wizard view if needed --> <!-- Inherit the register payment wizard view if needed -->
<record id="view_account_payment_register_form_inherit" model="ir.ui.view"> <record id="view_account_payment_register_form_inherit" model="ir.ui.view">
<field name="name">account.register.payment.form.inherit.vendor.payment.misc</field> <field name="name">account.register.payment.form.inherit.vendor.payment.misc</field>
<field name="model">account.payment.register</field> <field name="model">account.payment.register</field>
<field name="inherit_id" ref="account.view_account_payment_register_form"/> <field name="inherit_id" ref="account.view_account_payment_register_form"/>
<field name="arch" type="xml"> <field name="arch" type="xml">
<field name="journal_id" position="attributes"> <field name="journal_id" position="attributes">
<!-- No additional attributes needed as the logic is handled in the model --> <!-- No additional attributes needed as the logic is handled in the model -->
</field> </field>
</field> </field>
</record> </record>
</odoo> </odoo>