Account Claim Documentation¶
Overview¶
The Account Claim model (account.claim) manages expense reimbursement claims from users. It aggregates expense receipts, handles approval workflows, creates journal entries, and tracks payment status until the claim is fully paid.
Model Information¶
Model Name: account.claim
Display Name: Claim
Name Field: number
Key Fields: None (no unique constraint defined)
Features¶
- ❌ Audit logging enabled (
_audit_log) - ❌ Multi-company support (
company_id) - ❌ Full-text content search (
_content_search) - ✅ UUID for unique identification
- ✅ Approval workflow
- ✅ Journal entry creation
- ✅ Payment tracking
- ✅ Computed state based on payment status
State Workflow¶
| State | Code | Description |
|---|---|---|
| Waiting Approval | waiting_approval |
Claim submitted, pending authorization |
| Waiting Payment | waiting_payment |
Approved, awaiting reimbursement |
| Paid | paid |
Fully reimbursed |
| Voided | voided |
Cancelled/voided |
Note: State transitions between waiting_payment and paid are automatic based on amount_due.
Key Fields Reference¶
Header Fields¶
| Field | Type | Required | Description |
|---|---|---|---|
number |
Char | ❌ | Claim number |
user_id |
Many2One | ❌ | Claim owner (readonly) |
date |
Date | ❌ | Date submitted (readonly) |
due_date |
Date | ❌ | Payment due date |
account_id |
Many2One | ❌ | Unpaid claims account |
uuid |
Char | ❌ | Unique identifier |
Computed Amount Fields¶
| Field | Type | Description |
|---|---|---|
amount_total |
Decimal | Sum of all expense totals (stored) |
amount_approved |
Decimal | Sum of approved expenses (stored) |
amount_paid |
Decimal | Sum of payments made (stored) |
amount_due |
Decimal | Approved minus paid (stored) |
num_receipts |
Integer | Count of expenses |
can_authorize |
Boolean | All expenses approved/declined |
Relationship Fields¶
| Field | Type | Description |
|---|---|---|
expenses |
One2Many | Expense receipts |
payments |
One2Many | Payment lines |
move_id |
Many2One | Journal entry |
Default Values¶
_defaults = {
"state": "waiting_approval",
"date": lambda *a: time.strftime("%Y-%m-%d"),
"uuid": lambda *a: str(uuid.uuid4()),
}
API Methods¶
1. Authorize Claim¶
Method: do_authorize(ids, context)
Authorizes the claim and creates journal entry.
Prerequisites:
- due_date must be set
- All expenses must be approved or declined
Behavior:
1. Validates due date is set
2. Calls post() to create journal entry
3. Changes state to waiting_payment
Example:
# Set due date and authorize
get_model("account.claim").write([claim_id], {"due_date": "2024-12-31"})
get_model("account.claim").do_authorize([claim_id])
2. Post Journal Entry¶
Method: post(ids, context)
Creates and posts the journal entry for the claim.
Journal Entry Structure: - Credit: Unpaid claims account (total approved amount) - Debit: Expense accounts (by line) - Debit: Tax accounts (if applicable)
Prerequisites:
- unpaid_claim_id must be configured in Settings
- general_journal_id must be configured in Settings
Example:
3. Void Claim¶
Method: void(ids, context)
Voids/cancels the claim.
Prerequisites: - Claim must not have any payments
Behavior:
1. Validates no payments exist
2. Deletes journal entry if exists
3. Changes state to voided
Example:
4. Get Amount¶
Method: get_amount(ids, context)
Calculates totals from expenses and payments.
Returns:
{
"amount_total": sum(expense.amount_total for all expenses),
"amount_approved": sum(expense.amount_total for approved expenses),
"amount_paid": sum(payment.amount for all payments),
"amount_due": amount_approved - amount_paid,
}
5. Get State¶
Method: get_state(ids, context)
Computes state based on payment status.
Logic:
if state == "waiting_payment" and amount_due == 0:
return "paid"
elif state == "paid" and amount_due > 0:
return "waiting_payment"
else:
return state
6. Get Can Authorize¶
Method: get_can_authorize(ids, context)
Checks if all expenses have been reviewed.
Returns: True if all expenses are approved or declined
Related Models¶
| Model | Relationship | Description |
|---|---|---|
account.expense |
One2Many (expenses) | Expense receipts |
account.payment.line |
One2Many (payments) | Payment allocations |
account.move |
Many2One (move_id) | Journal entry |
base.user |
Many2One (user_id) | Claim owner |
account.account |
Many2One (account_id) | Unpaid claims account |
Common Use Cases¶
Use Case 1: Create and Submit Claim¶
# Create claim
claim_id = get_model("account.claim").create({
"user_id": user_id,
})
# Add expenses to claim
expense_ids = get_model("account.expense").search([
["user_id", "=", user_id],
["claim_id", "=", None],
["state", "=", "approved"]
])
get_model("account.expense").write(expense_ids, {"claim_id": claim_id})
Use Case 2: Authorize Claim¶
# Set due date
get_model("account.claim").write([claim_id], {
"due_date": "2024-12-31"
})
# Check if can authorize
claim = get_model("account.claim").browse([claim_id])[0]
if claim.can_authorize:
get_model("account.claim").do_authorize([claim_id])
Use Case 3: Process Payment¶
# Use claim.payment wizard
wizard_id = get_model("claim.payment").create({
"claim_id": claim_id,
"amount": claim.amount_due,
"date": "2024-12-15",
"account_id": bank_account_id,
})
get_model("claim.payment").add_payment([wizard_id])
Use Case 4: Track Claim Status¶
claim = get_model("account.claim").browse([claim_id])[0]
print(f"Claim: {claim.number}")
print(f"State: {claim.state}")
print(f"Total: {claim.amount_total}")
print(f"Approved: {claim.amount_approved}")
print(f"Paid: {claim.amount_paid}")
print(f"Due: {claim.amount_due}")
print(f"Receipts: {claim.num_receipts}")
Journal Entry Structure¶
When authorized, creates:
Date: [claim date]
Narration: "Claim: [number]"
Credit:
- Unpaid Claims Account: [amount_approved]
Debit:
- Expense Account 1: [base_amount_1]
- Expense Account 2: [base_amount_2]
- Tax Account: [tax_amount] (if applicable)
Best Practices¶
1. Set Due Date Before Authorization¶
# Good: Due date set
get_model("account.claim").write([claim_id], {"due_date": "2024-12-31"})
get_model("account.claim").do_authorize([claim_id])
# Bad: Missing due date (will fail)
get_model("account.claim").do_authorize([claim_id])
2. Review All Expenses First¶
# Good: Ensure all expenses are reviewed
claim = get_model("account.claim").browse([claim_id])[0]
if not claim.can_authorize:
# Find pending expenses
for exp in claim.expenses:
if exp.state not in ("approved", "declined"):
print(f"Pending: {exp.ref}")
3. Configure Settings¶
Ensure these are configured:
- settings.unpaid_claim_id - Account for unpaid claims
- settings.general_journal_id - General journal
Troubleshooting¶
"Missing payment due date"¶
Cause: Trying to authorize without due_date Solution: Set due_date before calling do_authorize
"Missing unpaid expense claims account"¶
Cause: unpaid_claim_id not configured in Settings Solution: Configure the unpaid claims account in Settings
"General journal not found"¶
Cause: general_journal_id not configured in Settings Solution: Configure the general journal in Settings
"This claim is already paid"¶
Cause: Trying to void a claim with payments Solution: Reverse payments first, then void
Testing Examples¶
Unit Test: Claim Authorization¶
def test_claim_authorization():
# Create claim with approved expense
claim_id = get_model("account.claim").create({})
expense_id = get_model("account.expense").create({
"claim_id": claim_id,
"ref": "TEST-001",
"contact_id": vendor_id,
"date": "2024-12-15",
"tax_type": "no_tax",
"state": "approved",
"lines": [("create", {
"description": "Test",
"qty": 1,
"unit_price": 100.00,
"account_id": expense_account_id,
})]
})
claim = get_model("account.claim").browse([claim_id])[0]
assert claim.amount_approved == 100.00
assert claim.can_authorize == True
# Authorize
claim.write({"due_date": "2024-12-31"})
get_model("account.claim").do_authorize([claim_id])
claim = get_model("account.claim").browse([claim_id])[0]
assert claim.state == "waiting_payment"
assert claim.move_id is not None
Security Considerations¶
Permission Model¶
- Users can view their own claims
- Managers can authorize claims
- Finance can view and process all claims
Data Access¶
- Claims linked to users via user_id
- Journal entries require proper accounting permissions
Configuration Requirements¶
| Setting | Location | Description |
|---|---|---|
unpaid_claim_id |
Settings | Account for unpaid claims liability |
general_journal_id |
Settings | Journal for claim entries |
Version History¶
Last Updated: December 2024 Model Version: account_claim.py Framework: Netforce
Additional Resources¶
- Account Expense Documentation:
account.expense - Claim Payment Wizard:
claim.payment - Payment Documentation:
account.payment - Journal Entry Documentation:
account.move
This documentation is generated for developer onboarding and reference purposes.