Payment Term Documentation¶
Overview¶
The Payment Term module (payment.term) defines payment conditions for invoices and purchase orders, specifying when payment is due. Payment terms are simple reference data used throughout the sales and purchasing processes to standardize credit terms with customers and suppliers.
Model Information¶
Model Name: payment.term
Display Name: Payment Term
Name Field: name
Key Fields: None (allows duplicate names)
Default Sort Order: sequence, name
Features¶
- ✅ Simple reference data model
- ✅ Sequence-based ordering
- ✅ Days-based payment calculation
- ✅ Used in invoices and purchase orders
- ✅ Standard credit terms management
Understanding Payment Terms¶
What is a Payment Term?¶
A Payment Term defines when a customer must pay an invoice or when you must pay a supplier. Common examples: - Immediate - Payment on delivery (COD) - Net 30 - Payment due in 30 days - Net 60 - Payment due in 60 days - Net 15 - Payment due in 15 days - Due on Receipt - Payment due immediately
How Payment Terms Work¶
Payment terms are typically: 1. Set as default on customer/supplier records 2. Applied automatically when creating invoices/bills 3. Used to calculate due dates 4. Referenced in aging reports
Key Fields Reference¶
Core Fields¶
| Field | Type | Required | Description |
|---|---|---|---|
name |
Char | ✅ | Payment term name (e.g., "Net 30") |
description |
Text | ❌ | Detailed description of terms |
sequence |
Integer | ❌ | Display order (lower numbers first) |
days |
Integer | ❌ | Number of days until payment due |
Field Details¶
name: - Descriptive term name - Shown in dropdowns and reports - No uniqueness constraint (though unique names recommended) - Examples: "Net 30", "Net 60", "COD", "Due on Receipt"
description: - Optional detailed explanation - Can include special conditions - Not typically shown in UI dropdowns
sequence: - Controls display order in lists - Lower numbers appear first - Useful for prioritizing common terms
days: - Number of days from invoice date to due date - Used for automatic due date calculation - Can be 0 for immediate payment - Negative values possible for advance payment
API Methods¶
1. Create Payment Term¶
Method: create(vals, context)
Creates a new payment term.
Parameters:
vals = {
"name": "Net 30", # Required
"description": "Payment due within 30 days",
"sequence": 10, # Optional
"days": 30 # Optional
}
Returns: int - New payment term ID
Example:
# Create standard terms
net30_id = get_model("payment.term").create({
"name": "Net 30",
"description": "Payment due within 30 days from invoice date",
"sequence": 20,
"days": 30
})
net60_id = get_model("payment.term").create({
"name": "Net 60",
"description": "Payment due within 60 days from invoice date",
"sequence": 30,
"days": 60
})
cod_id = get_model("payment.term").create({
"name": "Cash on Delivery",
"description": "Payment due immediately upon delivery",
"sequence": 10,
"days": 0
})
Search Functions¶
Find Term by Name¶
# Find Net 30 term
terms = get_model("payment.term").search_browse([
["name", "=", "Net 30"]
])
if terms:
term = terms[0]
print(f"{term.name}: {term.days} days")
Get All Terms (Ordered)¶
# Get all payment terms in display order
terms = get_model("payment.term").search_browse([])
print("Available Payment Terms:")
for term in terms:
days_text = f"{term.days} days" if term.days else "Immediate"
print(f" {term.name}: {days_text}")
Search by Days¶
# Find all 30-day terms
terms_30 = get_model("payment.term").search_browse([
["days", "=", 30]
])
# Find terms over 30 days
long_terms = get_model("payment.term").search_browse([
["days", ">", 30]
])
Best Practices¶
1. Use Standard Names¶
# Good: Clear, standard names
"Net 30"
"Net 60"
"Cash on Delivery"
"Due on Receipt"
"Net 15"
# Less clear: Ambiguous names
"30 Days"
"Standard"
"Quick"
2. Set Logical Sequences¶
# Good: Ordered by payment urgency
{
"name": "Cash on Delivery",
"sequence": 10,
"days": 0
}
{
"name": "Net 15",
"sequence": 20,
"days": 15
}
{
"name": "Net 30",
"sequence": 30,
"days": 30
}
{
"name": "Net 60",
"sequence": 40,
"days": 60
}
3. Provide Clear Descriptions¶
# Good: Detailed description
{
"name": "Net 30",
"description": "Payment due within 30 days from invoice date. "
"Late payment subject to 1.5% monthly interest."
}
# Minimal: Just basics
{
"name": "Net 30",
"description": "30 day payment term"
}
Database Constraints¶
No explicit constraints defined in the model.
Recommendations: - Consider adding unique constraint on name - Validate days >= 0 in application logic if needed
Related Models¶
| Model | Relationship | Description |
|---|---|---|
contact |
Referenced | Customers/suppliers have default payment terms |
account.invoice |
Referenced | Invoices use payment terms |
sale.order |
Referenced | Sales orders may use payment terms |
purchase.order |
Referenced | Purchase orders may use payment terms |
Common Use Cases¶
Use Case 1: Setup Standard Payment Terms¶
# Create standard set of payment terms
standard_terms = [
{
"name": "Cash on Delivery",
"description": "Payment due immediately upon delivery",
"sequence": 10,
"days": 0
},
{
"name": "Net 15",
"description": "Payment due within 15 days from invoice date",
"sequence": 20,
"days": 15
},
{
"name": "Net 30",
"description": "Payment due within 30 days from invoice date",
"sequence": 30,
"days": 30
},
{
"name": "Net 45",
"description": "Payment due within 45 days from invoice date",
"sequence": 40,
"days": 45
},
{
"name": "Net 60",
"description": "Payment due within 60 days from invoice date",
"sequence": 50,
"days": 60
},
{
"name": "Net 90",
"description": "Payment due within 90 days from invoice date",
"sequence": 60,
"days": 90
}
]
for term_data in standard_terms:
# Check if exists
existing = get_model("payment.term").search([
["name", "=", term_data["name"]]
])
if not existing:
term_id = get_model("payment.term").create(term_data)
print(f"✓ Created: {term_data['name']}")
else:
print(f"⊙ Exists: {term_data['name']}")
Use Case 2: Calculate Due Date¶
# Calculate invoice due date from payment term
from datetime import datetime, timedelta
invoice_date = datetime.strptime("2025-01-15", "%Y-%m-%d")
payment_term_id = net30_id
# Get payment term
term = get_model("payment.term").browse([payment_term_id])[0]
# Calculate due date
if term.days:
due_date = invoice_date + timedelta(days=term.days)
else:
due_date = invoice_date # Immediate payment
print(f"Invoice Date: {invoice_date.strftime('%Y-%m-%d')}")
print(f"Payment Term: {term.name}")
print(f"Due Date: {due_date.strftime('%Y-%m-%d')}")
# Output:
# Invoice Date: 2025-01-15
# Payment Term: Net 30
# Due Date: 2025-02-14
Use Case 3: Set Default Payment Term on Customer¶
# Set default payment term for customer
customer_id = 123
net30_id = get_model("payment.term").search([
["name", "=", "Net 30"]
])[0]
get_model("contact").write([customer_id], {
"payment_term_id": net30_id
})
print(f"✓ Default payment term set to Net 30")
# Now all invoices for this customer will default to Net 30
Use Case 4: Payment Terms Report¶
# Generate report of all payment terms
terms = get_model("payment.term").search_browse([], order="sequence,name")
print("PAYMENT TERMS CONFIGURATION")
print("=" * 60)
print(f"{'Name':30} {'Days':>10} {'Sequence':>10}")
print("-" * 60)
for term in terms:
days_display = str(term.days) if term.days else "Immediate"
seq_display = str(term.sequence) if term.sequence else "-"
print(f"{term.name:30} {days_display:>10} {seq_display:>10}")
print("=" * 60)
print(f"Total Terms: {len(terms)}")
Use Case 5: Aging Report by Payment Terms¶
# Analyze overdue invoices by payment term
from datetime import date
today = date.today()
terms = get_model("payment.term").search_browse([])
print("OVERDUE ANALYSIS BY PAYMENT TERM")
print("=" * 80)
for term in terms:
# Find invoices with this term
invoices = get_model("account.invoice").search_browse([
["payment_term_id", "=", term.id],
["state", "=", "waiting_payment"],
["due_date", "<", str(today)]
])
if invoices:
total_overdue = sum(inv.amount_due for inv in invoices)
print(f"\n{term.name}:")
print(f" Overdue Invoices: {len(invoices)}")
print(f" Total Overdue: ${total_overdue:,.2f}")
for inv in invoices:
days_overdue = (today - datetime.strptime(inv.due_date, "%Y-%m-%d").date()).days
print(f" {inv.number}: ${inv.amount_due:,.2f} ({days_overdue} days overdue)")
Performance Tips¶
1. Index on Name Field¶
CREATE INDEX idx_payment_term_name ON payment_term(name);
CREATE INDEX idx_payment_term_sequence ON payment_term(sequence);
2. Cache Common Terms¶
# Cache frequently used terms
term_cache = {}
def get_payment_term(name):
if name not in term_cache:
terms = get_model("payment.term").search_browse([
["name", "=", name]
])
term_cache[name] = terms[0] if terms else None
return term_cache[name]
# Use cached lookup
net30 = get_payment_term("Net 30")
Troubleshooting¶
"Payment term not found"¶
Cause: Term hasn't been created yet Solution: Create the payment term:
"Wrong due date calculated"¶
Cause: Days value incorrect or not set Solution: Verify days field:
term = get_model("payment.term").browse([term_id])[0]
print(f"Days: {term.days}")
# Update if needed
get_model("payment.term").write([term_id], {"days": 30})
"Terms not showing in correct order"¶
Cause: Sequence values not set Solution: Set sequence values:
# Update sequences
terms = [
("Cash on Delivery", 10),
("Net 15", 20),
("Net 30", 30),
("Net 60", 40)
]
for name, seq in terms:
term_ids = get_model("payment.term").search([["name", "=", name]])
if term_ids:
get_model("payment.term").write(term_ids, {"sequence": seq})
Testing Examples¶
Unit Test: Payment Term Creation¶
def test_payment_term():
# Create test term
term_id = get_model("payment.term").create({
"name": "Test Net 30",
"description": "Test payment term",
"sequence": 100,
"days": 30
})
# Verify
term = get_model("payment.term").browse([term_id])[0]
assert term.name == "Test Net 30"
assert term.days == 30
assert term.sequence == 100
# Test due date calculation
from datetime import datetime, timedelta
invoice_date = datetime(2025, 1, 15)
due_date = invoice_date + timedelta(days=term.days)
assert due_date == datetime(2025, 2, 14)
print("✓ Payment term test passed")
# Cleanup
get_model("payment.term").delete([term_id])
Security Considerations¶
Permission Model¶
- Term creation typically restricted to accounting/admin users
- Terms are global reference data (not company-specific)
- Changes affect all invoices using the term
Data Integrity¶
- Validate days value is reasonable (0-365 typical range)
- Avoid deleting terms still referenced by invoices
- Consider making terms inactive instead of deleting
Integration Points¶
Internal Modules¶
- contact: Default payment terms for customers/suppliers
- account.invoice: Invoice payment terms and due dates
- sale.order: Sales order payment conditions
- purchase.order: Purchase order payment conditions
External Systems¶
- ERP systems (payment term mapping)
- Aging reports (term-based analysis)
- Collection systems (term tracking)
Version History¶
Last Updated: 2025-12-16 Model Version: payment_term.py Framework: Netforce
Additional Resources¶
- Invoice Documentation:
account.invoice - Contact Documentation:
contact - Sales Order Documentation:
sale.order - Purchase Order Documentation:
purchase.order
This documentation is generated for developer onboarding and reference purposes.