Invoice Overpay Documentation¶
Overview¶
The Invoice Overpay model (invoice.overpay) is a transient wizard model that handles overpayment scenarios when a payment exceeds the invoice amount due. It allows users to confirm and process overpayments with an optional description.
Model Information¶
Model Name: invoice.overpay
Display Name: Invoice Overpay
Key Fields: None (transient model)
Features¶
- ✅ Transient model (temporary data)
- ❌ Audit logging enabled (
_audit_log) - ❌ Multi-company support (
company_id) - ✅ Automatic overpayment calculation
- ✅ Overpayment description support
Key Fields Reference¶
All Fields¶
| Field | Type | Required | Description |
|---|---|---|---|
payment_id |
Many2One | ✅ | Payment record with overpayment |
amount_overpay |
Decimal | ❌ | Calculated overpayment amount (readonly) |
description |
Char | ❌ | Description for overpayment record |
Default Values¶
_defaults = {
"payment_id": _get_payment, # From context payment_id
"amount_overpay": _get_amount, # Calculated overpayment amount
}
API Methods¶
1. Get Payment (Default)¶
Method: _get_payment(context)
Gets the payment ID from context.
Context Parameters:
- payment_id - ID of the payment with overpayment
2. Get Amount (Default)¶
Method: _get_amount(context)
Calculates the total overpayment amount from payment lines.
Logic:
# For each invoice line in payment
amt_over = sum(
max(0, line.amount_invoice - line.invoice_id.amount_due)
for line in payment.invoice_lines
)
Raises:
- Exception("Wrong payment type") - If payment type is not invoice
3. Process Overpay¶
Method: do_overpay(ids, context)
Confirms and processes the overpayment.
Behavior: 1. Posts the payment with overpayment description in context 2. Returns navigation to payment form view
Context Passed to Post:
Example:
# Create overpay wizard
wizard_id = get_model("invoice.overpay").create({
"payment_id": payment_id,
"description": "Customer advance payment for future orders",
}, context={"payment_id": payment_id})
# Process overpayment
result = get_model("invoice.overpay").do_overpay([wizard_id])
Related Models¶
| Model | Relationship | Description |
|---|---|---|
account.payment |
Many2One (payment_id) | Payment with overpayment |
account.payment.line |
Reference | Payment lines for calculation |
account.invoice |
Reference | Invoices being overpaid |
Common Use Cases¶
Use Case 1: Process Customer Advance Payment¶
# Customer pays more than invoice amount
# Payment is created but not posted due to overpayment
# Create overpay wizard to confirm
wizard_id = get_model("invoice.overpay").create({
"description": "Customer advance - credit on account",
}, context={"payment_id": payment_id})
# Check overpayment amount
wizard = get_model("invoice.overpay").browse([wizard_id])[0]
print(f"Overpayment amount: {wizard.amount_overpay}")
# Confirm and process
get_model("invoice.overpay").do_overpay([wizard_id])
Use Case 2: Bulk Payment with Overpay¶
# Payment covers multiple invoices with excess
# Example: Pay 5000 for invoices totaling 4500
# After payment creation triggers overpay wizard
wizard_id = get_model("invoice.overpay").create({
"description": "Excess payment - apply to next invoice",
}, context={"payment_id": payment_id})
wizard = get_model("invoice.overpay").browse([wizard_id])[0]
print(f"Total overpayment: {wizard.amount_overpay}") # Shows 500
get_model("invoice.overpay").do_overpay([wizard_id])
Overpayment Flow¶
1. User creates payment with amount > invoice due
│
2. System detects overpayment
│
3. Overpay wizard is displayed
│
├─ Shows overpayment amount
└─ Allows description entry
│
4. User confirms overpayment
│
5. Payment is posted
│
6. Overpayment recorded (creates credit on account)
Best Practices¶
1. Always Provide Description¶
# Good: Clear description for audit trail
wizard = get_model("invoice.overpay").create({
"description": "Customer prepayment for PO-2024-001",
}, context={"payment_id": payment_id})
# Bad: No description
wizard = get_model("invoice.overpay").create({
}, context={"payment_id": payment_id})
2. Review Overpayment Amount¶
# Good: Verify overpayment before confirming
wizard = get_model("invoice.overpay").browse([wizard_id])[0]
if wizard.amount_overpay > expected_advance:
print(f"Warning: Overpayment {wizard.amount_overpay} higher than expected")
# Investigate before proceeding
Troubleshooting¶
"Wrong payment type"¶
Cause: Payment is not of type invoice
Solution: Only use this wizard for invoice payments
"Overpayment amount is 0"¶
Cause: Payment lines don't exceed invoice amounts Solution: Verify payment amounts vs invoice due amounts
"Payment not posting"¶
Cause: Overpayment not confirmed through wizard Solution: Complete the overpay wizard to post payment
Testing Examples¶
Unit Test: Overpayment Calculation¶
def test_overpay_calculation():
# Create invoice for 1000
invoice_id = get_model("account.invoice").create({
"type": "out",
"contact_id": customer_id,
"lines": [("create", {
"description": "Test",
"qty": 1,
"unit_price": 1000.00,
})]
})
get_model("account.invoice").post([invoice_id])
# Create payment for 1500 (500 overpay)
payment_id = get_model("account.payment").create({
"type": "in",
"pay_type": "invoice",
"contact_id": customer_id,
"account_id": bank_account_id,
"lines": [("create", {
"invoice_id": invoice_id,
"amount": 1500.00,
})]
}, context={"type": "in"})
# Create overpay wizard
wizard_id = get_model("invoice.overpay").create({
"description": "Test overpay",
}, context={"payment_id": payment_id})
wizard = get_model("invoice.overpay").browse([wizard_id])[0]
assert wizard.amount_overpay == 500.00
Security Considerations¶
Permission Model¶
- Users need payment posting permissions
- Overpayment requires explicit confirmation
Data Access¶
- Transient model - not persisted
- Creates permanent records in payment system
Version History¶
Last Updated: December 2024 Model Version: invoice_overpay.py Framework: Netforce
Additional Resources¶
- Invoice Documentation:
account.invoice - Payment Documentation:
account.payment - Invoice Payment Wizard:
invoice.payment
This documentation is generated for developer onboarding and reference purposes.