Payment Category Documentation¶
Overview¶
The Payment Category model (payment.category) provides a simple way to categorize and organize payment records. Categories help with reporting, filtering, and analysis by grouping similar types of payments together.
Model Information¶
Model Name: payment.category
Display Name: Payment Category
Key Fields: None (no unique constraint defined)
Features¶
- ❌ Audit logging enabled (
_audit_log) - ❌ Multi-company support (
company_id) - ❌ Full-text content search (
_content_search) - ✅ Active/Inactive flag for soft delete
- ✅ Simple lookup model for categorization
Key Fields Reference¶
All Fields¶
| Field | Type | Required | Description |
|---|---|---|---|
name |
Char | ✅ | Category name (searchable) |
description |
Text | ❌ | Detailed description of the category |
active |
Boolean | ❌ | Whether category is active (for filtering) |
API Methods¶
1. Create Category¶
Method: create(vals, context)
Creates a new payment category.
Parameters:
vals = {
"name": "Supplier Payments", # Required: Category name
"description": "Payments to suppliers and vendors", # Optional
"active": True, # Optional: Defaults to active
}
Returns: int - New record ID
Example:
categ_id = get_model("payment.category").create({
"name": "Payroll",
"description": "Employee salary and wage payments",
"active": True,
})
2. Search Categories¶
Method: search(condition, context)
Search for payment categories.
Example:
# Find all active categories
active_categs = get_model("payment.category").search([["active", "=", True]])
# Find category by name
categ_ids = get_model("payment.category").search([["name", "=", "Payroll"]])
# Find categories with partial name match
categ_ids = get_model("payment.category").search([["name", "ilike", "%supplier%"]])
3. Browse Categories¶
Method: browse(ids, context)
Retrieve category records for reading.
Example:
categs = get_model("payment.category").browse(categ_ids)
for categ in categs:
print(f"Category: {categ.name}")
print(f"Description: {categ.description}")
print(f"Active: {categ.active}")
4. Update Category¶
Method: write(ids, vals, context)
Update existing category records.
Example:
# Update description
get_model("payment.category").write([categ_id], {
"description": "Updated description"
})
# Deactivate category (soft delete)
get_model("payment.category").write([categ_id], {
"active": False
})
5. Delete Category¶
Method: delete(ids, context)
Delete payment categories.
Example:
# Prefer soft delete (set active=False) over hard delete
get_model("payment.category").write([categ_id], {"active": False})
# Or hard delete if necessary
get_model("payment.category").delete([categ_id])
Related Models¶
| Model | Relationship | Description |
|---|---|---|
account.payment |
Many2One (payment_category_id) | Payments linked to this category |
Note: The relationship field payments is currently commented out in the model.
Common Use Cases¶
Use Case 1: Set Up Standard Payment Categories¶
# Create standard payment categories
categories = [
{"name": "Supplier Payments", "description": "Payments to vendors and suppliers", "active": True},
{"name": "Payroll", "description": "Employee salaries and wages", "active": True},
{"name": "Tax Payments", "description": "Tax remittances to authorities", "active": True},
{"name": "Utilities", "description": "Electricity, water, internet bills", "active": True},
{"name": "Rent & Lease", "description": "Property rental and lease payments", "active": True},
{"name": "Customer Refunds", "description": "Refunds issued to customers", "active": True},
{"name": "Intercompany", "description": "Transfers between group companies", "active": True},
{"name": "Miscellaneous", "description": "Other uncategorized payments", "active": True},
]
for cat in categories:
existing = get_model("payment.category").search([["name", "=", cat["name"]]])
if not existing:
get_model("payment.category").create(cat)
Use Case 2: Get Active Categories for Dropdown¶
# Get all active categories for a selection field
categs = get_model("payment.category").search_browse([["active", "=", True]])
options = []
for categ in categs:
options.append({
"id": categ.id,
"name": categ.name,
})
Use Case 3: Categorize Payment Reports¶
# Get payments grouped by category
from collections import defaultdict
# Assuming payments have payment_category_id field
payments = get_model("account.payment").search_browse([
["date", ">=", "2024-01-01"],
["date", "<=", "2024-12-31"],
["state", "=", "posted"]
])
by_category = defaultdict(lambda: {"count": 0, "total": 0})
for pmt in payments:
cat_name = pmt.payment_category_id.name if pmt.payment_category_id else "Uncategorized"
by_category[cat_name]["count"] += 1
by_category[cat_name]["total"] += pmt.amount
print("Payments by Category (2024):")
for cat, data in sorted(by_category.items()):
print(f" {cat}: {data['count']} payments, {data['total']:,.2f} total")
Use Case 4: Archive Unused Categories¶
# Find and deactivate categories with no payments
categs = get_model("payment.category").search_browse([["active", "=", True]])
for categ in categs:
# Check if any payments use this category
payments = get_model("account.payment").search([
["payment_category_id", "=", categ.id]
])
if not payments:
categ.write({"active": False})
print(f"Deactivated unused category: {categ.name}")
Best Practices¶
1. Use Descriptive Names¶
# Good: Clear and specific
get_model("payment.category").create({
"name": "International Wire Transfers",
"description": "Overseas payments via SWIFT/wire transfer"
})
# Bad: Vague name
get_model("payment.category").create({
"name": "Other"
})
2. Use Soft Delete¶
# Good: Preserve history by deactivating
get_model("payment.category").write([categ_id], {"active": False})
# Avoid: Hard delete loses referential integrity
get_model("payment.category").delete([categ_id])
3. Maintain Consistent Naming¶
- Use Title Case for category names
- Keep names concise (2-4 words)
- Add detailed descriptions for clarity
Troubleshooting¶
"Category name is required"¶
Cause: Creating category without a name
Solution: Always provide the name field
"Category not showing in dropdown"¶
Cause: Category is inactive
Solution: Set active = True or include inactive in search
"Cannot delete category with linked payments"¶
Cause: Attempting to delete category referenced by payments Solution: Use soft delete (active=False) or reassign payments first
Testing Examples¶
Unit Test: Create and Query Category¶
def test_payment_category():
# Create category
categ_id = get_model("payment.category").create({
"name": "Test Category",
"description": "For testing",
"active": True,
})
# Verify creation
categ = get_model("payment.category").browse([categ_id])[0]
assert categ.name == "Test Category"
assert categ.active == True
# Test soft delete
categ.write({"active": False})
categ = get_model("payment.category").browse([categ_id])[0]
assert categ.active == False
# Cleanup
get_model("payment.category").delete([categ_id])
Security Considerations¶
Permission Model¶
- Read access typically granted to all accounting users
- Write/Delete access restricted to accounting managers
Data Access¶
- Categories are shared across the system
- Changes affect all users who reference the category
Version History¶
Last Updated: December 2024 Model Version: payment_category.py Framework: Netforce
Additional Resources¶
- Payment Documentation:
account.payment - Payment Method Documentation:
payment.method
This documentation is generated for developer onboarding and reference purposes.