6.9 KiB
Payment Scenarios with Deductions
This document explains how the module handles different payment scenarios.
Scenario 1: Payment WITHOUT Expense Account
When you create a vendor payment without setting an expense account, the system uses the standard vendor payable account.
Example:
- Vendor: PT Telkom Indonesia
- Amount: Rp 2,000,000
- Deductions:
- PPh 21: Rp 100,000
- PPh 29: Rp 50,000
- Final Payment: Rp 1,850,000
Journal Entry:
Account | Debit | Credit
-------------------------------------|-----------------|------------------
Accounts Payable - PT Telkom | Rp 2,000,000.00 |
PPh 21 (Tax Payable) | | Rp 100,000.00
PPh 29 (Tax Payable) | | Rp 50,000.00
Bank Account | | Rp 1,850,000.00
-------------------------------------|-----------------|------------------
TOTAL | Rp 2,000,000.00 | Rp 2,000,000.00
Explanation:
- The Accounts Payable line uses the vendor's payable account (from partner configuration)
- The payable account has the partner_id set (PT Telkom Indonesia)
- This is the standard Odoo behavior, just with deductions added
Scenario 2: Payment WITH Expense Account
When you create a vendor payment with an expense account set, the system uses that expense account instead of the payable account.
Example:
- Vendor: PT Telkom Indonesia
- Amount: Rp 2,000,000
- Expense Account: 611505 Telepon & Internet
- Deductions:
- PPh 21: Rp 100,000
- PPh 29: Rp 50,000
- Final Payment: Rp 1,850,000
Journal Entry:
Account | Debit | Credit
-------------------------------------|-----------------|------------------
611505 Telepon & Internet (Expense) | Rp 2,000,000.00 |
PPh 21 (Tax Payable) | | Rp 100,000.00
PPh 29 (Tax Payable) | | Rp 50,000.00
Bank Account | | Rp 1,850,000.00
-------------------------------------|-----------------|------------------
TOTAL | Rp 2,000,000.00 | Rp 2,000,000.00
Explanation:
- The Expense Account replaces the payable account
- This allows direct expense recording without going through payables
- The expense account still has the partner_id set for tracking
- This is useful for immediate expense recognition
Key Differences
| Aspect | Without Expense Account | With Expense Account |
|---|---|---|
| Counterpart Account | Accounts Payable | Expense Account |
| Account Type | liability_payable | expense |
| Partner Required | Yes | Yes |
| Use Case | Standard vendor payment | Direct expense recording |
| Payable Created | Yes | No |
When to Use Each Scenario
Use WITHOUT Expense Account when:
- You want to track vendor payables
- You need to reconcile with vendor bills
- You're following standard AP workflow
- You need aging reports for vendors
Use WITH Expense Account when:
- You want immediate expense recognition
- You don't need to track payables
- You're making direct payments (no bill)
- You want simplified accounting
Technical Notes
Module Integration
This module (vendor_payment_diff_amount) works seamlessly with vendor_batch_payment_merge:
- vendor_batch_payment_merge provides the
expense_account_idfield - vendor_payment_diff_amount adds deduction functionality
- Both modules modify
_prepare_move_line_default_vals()method - The methods are called in sequence (inheritance chain)
Method Call Order
1. Standard Odoo: Creates basic 2-line entry (bank + payable)
2. vendor_batch_payment_merge: Replaces payable with expense (if set)
3. vendor_payment_diff_amount: Adds deduction lines and adjusts bank
Result
Final journal entry has:
- 1 debit line (payable or expense at original amount)
- N credit lines (one per deduction)
- 1 credit line (bank at final_payment_amount)
Total: 2 + N lines (where N = number of deductions)
Validation Rules
The module ensures:
- ✅ Counterpart line always has
partner_idset - ✅ Counterpart line stays at original amount
- ✅ Bank line reduced to final_payment_amount
- ✅ Deduction lines are credits
- ✅ Deduction lines only have
partner_idif account type requires it (payable/receivable) - ✅ Entry is balanced (total debit = total credit)
- ✅ All required fields are present
Troubleshooting
Error: "Missing required account on accountable line"
Cause: An accountable line (payable/receivable account) is missing the required partner_id field.
Solution: The module now automatically handles this:
- Counterpart line (payable/expense) always has
partner_idset - Deduction lines only have
partner_idif the account type requires it - Tax accounts (liability/expense) don't need
partner_id
If you still see this error:
- Check that the partner has a payable account configured
- Check that the expense account (if used) is valid
- Verify the payment has a partner selected
- Ensure deduction accounts are NOT payable/receivable accounts (use tax/expense accounts instead)
Error: "Entry is not balanced"
Cause: The debit and credit totals don't match.
Solution: This should not happen with the current implementation. If it does:
- Check that all deduction amounts are positive
- Verify currency conversion is working
- Check for rounding issues
Examples
Example 1: Simple Payment with One Deduction
# Create payment
payment = env['account.payment'].create({
'payment_type': 'outbound',
'partner_type': 'supplier',
'partner_id': partner.id,
'amount': 1000.0,
'journal_id': bank_journal.id,
})
# Add deduction
env['payment.deduction.line'].create({
'payment_id': payment.id,
'amount_substract': 100.0,
'substract_account_id': tax_account.id,
'name': 'Withholding Tax',
})
# Post payment
payment.action_post()
# Result:
# - Payable: Debit 1000
# - Tax: Credit 100
# - Bank: Credit 900
Example 2: Payment with Expense Account and Multiple Deductions
# Create payment with expense account
payment = env['account.payment'].create({
'payment_type': 'outbound',
'partner_type': 'supplier',
'partner_id': partner.id,
'amount': 2000.0,
'expense_account_id': expense_account.id,
'journal_id': bank_journal.id,
})
# Add multiple deductions
env['payment.deduction.line'].create({
'payment_id': payment.id,
'amount_substract': 100.0,
'substract_account_id': pph21_account.id,
'name': 'PPh 21',
})
env['payment.deduction.line'].create({
'payment_id': payment.id,
'amount_substract': 50.0,
'substract_account_id': pph29_account.id,
'name': 'PPh 29',
})
# Post payment
payment.action_post()
# Result:
# - Expense: Debit 2000
# - PPh 21: Credit 100
# - PPh 29: Credit 50
# - Bank: Credit 1850