diff --git a/.gitignore b/.gitignore old mode 100644 new mode 100755 diff --git a/AMOUNT_FIX_GUIDE.md b/AMOUNT_FIX_GUIDE.md old mode 100644 new mode 100755 diff --git a/CHANGELOG.md b/CHANGELOG.md old mode 100644 new mode 100755 diff --git a/README.md b/README.md old mode 100644 new mode 100755 diff --git a/__init__.py b/__init__.py old mode 100644 new mode 100755 diff --git a/__manifest__.py b/__manifest__.py old mode 100644 new mode 100755 diff --git a/__pycache__/__init__.cpython-310.pyc b/__pycache__/__init__.cpython-310.pyc old mode 100644 new mode 100755 diff --git a/fix_amount_issue.py b/fix_amount_issue.py old mode 100644 new mode 100755 index ea6a382..1d9a962 --- a/fix_amount_issue.py +++ b/fix_amount_issue.py @@ -24,23 +24,25 @@ def fix_payment_amounts(): fixed_count = 0 for payment in payments: if payment.move_id: - # Find the counterpart line (payable/expense line with debit) - counterpart_lines = payment.move_id.line_ids.filtered( - lambda l: l.debit > 0 and l.account_id.account_type in ('liability_payable', 'expense') - ) + # Robust logic to find gross amount from moves + liquidity_lines, counterpart_lines, writeoff_lines = payment._seek_for_lines() + non_liquidity_lines = counterpart_lines + writeoff_lines - if counterpart_lines: - correct_amount = counterpart_lines[0].debit + if payment.payment_type == 'outbound': + gross_lines = non_liquidity_lines.filtered(lambda l: l.debit > 0) + else: + gross_lines = non_liquidity_lines.filtered(lambda l: l.credit > 0) + + if gross_lines: + correct_amount = sum(abs(l.amount_currency) for l in gross_lines) current_amount = payment.amount # Check if amount needs fixing (allow for small rounding differences) - if abs(current_amount - correct_amount) > 0.01: + if abs(current_amount - correct_amount) > 0.001: print(f"Payment {payment.name} (ID: {payment.id}):") print(f" Current amount: {current_amount}") print(f" Correct amount: {correct_amount}") print(f" Deductions: {payment.amount_substract}") - print(f" Current final: {payment.final_payment_amount}") - print(f" Expected final: {correct_amount - payment.amount_substract}") # Fix the amount using SQL to avoid triggering computed fields env.cr.execute( diff --git a/models/__init__.py b/models/__init__.py old mode 100644 new mode 100755 diff --git a/models/__pycache__/__init__.cpython-310.pyc b/models/__pycache__/__init__.cpython-310.pyc old mode 100644 new mode 100755 diff --git a/models/__pycache__/account_batch_payment.cpython-310.pyc b/models/__pycache__/account_batch_payment.cpython-310.pyc old mode 100644 new mode 100755 diff --git a/models/__pycache__/account_payment.cpython-310.pyc b/models/__pycache__/account_payment.cpython-310.pyc old mode 100644 new mode 100755 diff --git a/models/account_batch_payment.py b/models/account_batch_payment.py old mode 100644 new mode 100755 diff --git a/models/account_payment.py b/models/account_payment.py old mode 100644 new mode 100755 index 77f1c58..11b01eb --- a/models/account_payment.py +++ b/models/account_payment.py @@ -100,13 +100,18 @@ class AccountPayment(models.Model): if payment.amount_substract and payment.amount_substract > 0: # Get the correct amount from the journal entry if payment.move_id: - # Find the counterpart line (payable/expense line) - counterpart_lines = payment.move_id.line_ids.filtered( - lambda l: l.account_id.account_type in ('liability_payable', 'expense') and l.debit > 0 - ) - if counterpart_lines: - correct_amount = counterpart_lines[0].debit - if abs(payment.amount - correct_amount) > 0.01: # Allow for rounding differences + liquidity_lines, counterpart_lines, writeoff_lines = payment._seek_for_lines() + non_liquidity_lines = counterpart_lines + writeoff_lines + + # Find gross amount lines (Debits for outbound, Credits for inbound) + if payment.payment_type == 'outbound': + gross_lines = non_liquidity_lines.filtered(lambda l: l.debit > 0) + else: + gross_lines = non_liquidity_lines.filtered(lambda l: l.credit > 0) + + if gross_lines: + correct_amount = sum(abs(l.amount_currency) for l in gross_lines) + if abs(payment.amount - correct_amount) > 0.001: import logging _logger = logging.getLogger(__name__) _logger.info(f"Fixing amount for payment {payment.id}: {payment.amount} -> {correct_amount}") @@ -133,14 +138,19 @@ class AccountPayment(models.Model): fixed_count = 0 for payment in payments: if payment.move_id: - # Find the counterpart line (payable/expense line with debit) - counterpart_lines = payment.move_id.line_ids.filtered( - lambda l: l.debit > 0 and l.account_id.account_type in ('liability_payable', 'expense') - ) + # Robust logic to find gross amount from moves + liquidity_lines, counterpart_lines, writeoff_lines = payment._seek_for_lines() + non_liquidity_lines = counterpart_lines + writeoff_lines - if counterpart_lines: - correct_amount = counterpart_lines[0].debit - if abs(payment.amount - correct_amount) > 0.01: + # Find gross amount lines (Debits for outbound, Credits for inbound) + if payment.payment_type == 'outbound': + gross_lines = non_liquidity_lines.filtered(lambda l: l.debit > 0) + else: + gross_lines = non_liquidity_lines.filtered(lambda l: l.credit > 0) + + if gross_lines: + correct_amount = sum(abs(l.amount_currency) for l in gross_lines) + if abs(payment.amount - correct_amount) > 0.001: # Fix using SQL to avoid sync issues payment.env.cr.execute( "UPDATE account_payment SET amount = %s WHERE id = %s", @@ -165,38 +175,51 @@ class AccountPayment(models.Model): Override to handle synchronization when we have deductions. When we have a substract amount, the bank credit line is reduced to final_payment_amount, - but we want to keep the payment amount at the original value (not sync it down). + but we want to keep the payment amount at the original gross value. """ # For payments with deductions, we need to handle synchronization carefully for payment in self: if payment.amount_substract and payment.amount_substract > 0: - # Store the original amount before any synchronization + # Store potential original values original_amount = payment.amount - original_substract = payment.amount_substract - # Try to call parent sync but handle any errors + # Call parent sync try: super(AccountPayment, payment)._synchronize_from_moves(changed_fields) except Exception as e: - # If there's an error (like missing payable account when using expense_account_id), - # that's expected, so we just continue import logging _logger = logging.getLogger(__name__) - _logger.info(f"Sync error for payment {payment.id} (expected with deductions): {e}") + _logger.debug(f"Sync info for payment {payment.id} (handling deductions): {e}") - # After sync, ensure the amount is still correct - # The sync might have changed it based on journal entry lines - if payment.amount != original_amount: - import logging - _logger = logging.getLogger(__name__) - _logger.info(f"Restoring amount for payment {payment.id}: {payment.amount} -> {original_amount}") + # Restore gross amount from the move's counterpart lines + if payment.move_id: + liquidity_lines, counterpart_lines, writeoff_lines = payment._seek_for_lines() - # Use SQL to restore the original amount without triggering more syncs - payment.env.cr.execute( - "UPDATE account_payment SET amount = %s WHERE id = %s", - (original_amount, payment.id) - ) - payment.invalidate_recordset(['amount']) + # The gross amount is the sum of counterpart/writeoff lines that balance the liquidity line + # For outbound (Send Money): Gross = Sum of Debits (excluding liquidity) + # For inbound (Receive Money): Gross = Sum of Credits (excluding liquidity) + + non_liquidity_lines = counterpart_lines + writeoff_lines + if payment.payment_type == 'outbound': + gross_lines = non_liquidity_lines.filtered(lambda l: l.debit > 0) + else: + gross_lines = non_liquidity_lines.filtered(lambda l: l.credit > 0) + + if gross_lines: + # Use amount_currency because it represents the amount in payment currency + correct_gross_amount = sum(abs(l.amount_currency) for l in gross_lines) + + if abs(payment.amount - correct_gross_amount) > 0.001: + import logging + _logger = logging.getLogger(__name__) + _logger.info(f"Restoring gross amount for payment {payment.id}: {payment.amount} -> {correct_gross_amount}") + + # Use SQL to restore to avoid triggering more syncs + payment.env.cr.execute( + "UPDATE account_payment SET amount = %s WHERE id = %s", + (correct_gross_amount, payment.id) + ) + payment.invalidate_recordset(['amount']) # Ensure final_payment_amount is recalculated correctly payment._compute_final_payment_amount() diff --git a/models/payment_deduction_line.py b/models/payment_deduction_line.py old mode 100644 new mode 100755 diff --git a/security/ir.model.access.csv b/security/ir.model.access.csv old mode 100644 new mode 100755 diff --git a/tests/__init__.py b/tests/__init__.py old mode 100644 new mode 100755 diff --git a/tests/__pycache__/__init__.cpython-310.pyc b/tests/__pycache__/__init__.cpython-310.pyc old mode 100644 new mode 100755 diff --git a/tests/__pycache__/test_account_payment.cpython-310.pyc b/tests/__pycache__/test_account_payment.cpython-310.pyc old mode 100644 new mode 100755 diff --git a/tests/__pycache__/test_batch_payment_integration.cpython-310.pyc b/tests/__pycache__/test_batch_payment_integration.cpython-310.pyc old mode 100644 new mode 100755 diff --git a/tests/test_account_payment.py b/tests/test_account_payment.py old mode 100644 new mode 100755 diff --git a/tests/test_batch_payment_integration.py b/tests/test_batch_payment_integration.py old mode 100644 new mode 100755 diff --git a/views/account_batch_payment_views.xml b/views/account_batch_payment_views.xml old mode 100644 new mode 100755 diff --git a/views/account_payment_views.xml b/views/account_payment_views.xml old mode 100644 new mode 100755 diff --git a/wizard/__init__.py b/wizard/__init__.py old mode 100644 new mode 100755 diff --git a/wizard/payment_amount_fix_wizard.py b/wizard/payment_amount_fix_wizard.py old mode 100644 new mode 100755 diff --git a/wizard/payment_amount_fix_wizard_views.xml b/wizard/payment_amount_fix_wizard_views.xml old mode 100644 new mode 100755