Accounts Payable (AP) Module Documentation
Overview
The Accounts Payable (AP) module manages vendor bills and payment processing. It ensures all company expenditures are properly recorded, vendor obligations are tracked, and payments are processed efficiently. Like the AR module, it integrates tightly with the Accounting module for proper GL posting.
Key Features
- Vendor Bill Management: Record and track vendor invoices
- Payment Processing: Process vendor payments with split tender support
- Payment Application: Allocate payments to specific bills
- AP Aging Reports: Track outstanding payables by age
- Automatic GL Posting: Seamless accounting integration
- Bill Status Tracking: DRAFT, OPEN, PARTIAL, PAID, VOID
- Multi-vendor Payments: Pay multiple bills in one payment
Architecture
Domain Layer (app/Domain/Ap)
Models (5 Models)
Bill (Bill.php)
- Vendor bill/invoice header
- Table:
ap_bills - Key Fields:
bill_no: Unique bill number (per property)vendor_id: Bill-from vendorbill_date: Bill datedue_date: Payment due datestatus: DRAFT | OPEN | PARTIAL | PAID | VOIDsubtotal: Line items total (before tax)tax_amount: Total taxtotal_amount: Final amount payablenotes: Bill notes
- Relationships:
vendor(): Vendor (via Party)lines(): BillLine recordsallocations(): PaymentAllocation records (payments applied)
- Computed Attributes:
amount_paid: Sum of allocationsbalance_due: total_amount - amount_paid
- Traits:
BelongsToProperty
BillLine (BillLine.php)
- Bill line items
- Table:
ap_bill_lines - Key Fields:
ap_bill_id: Parent billline_no: Line numberdescription: Line descriptionqty: Quantityunit_cost: Unit costline_total: Extended amount (qty × unit_cost)expense_account_id: GL expense account
- Relationships:
bill(): Parent billexpenseAccount(): GL account
Payment (Payment.php)
- Vendor payment header
- Table:
ap_payments - Key Fields:
payment_no: Unique payment numbervendor_id: Payee vendorpayment_date: Payment datetotal_amount_paid: Total payment amountreference_no: External reference (check #, wire transfer #)notes: Payment notes
- Relationships:
vendor(): Vendorpayments(): PaymentPayment records (split tender)allocations(): PaymentAllocation records (application to bills)
- Traits:
BelongsToProperty
PaymentPayment (PaymentPayment.php)
- Payment method breakdown
- Table:
ap_payment_payments - Key Fields:
ap_payment_id: Parent paymentpayment_method: CASH | BANK | MOBILE_MONEY | CARD | OTHERamount: Amount for this methodcash_account_id: GL cash/bank accountreference_no: Method-specific reference (check #, etc.)
- Relationships:
payment(): Parent paymentcashAccount(): GL account
PaymentAllocation (PaymentAllocation.php)
- Payment application to bills
- Table:
ap_payment_allocations - Key Fields:
ap_payment_id: Payment being appliedap_bill_id: Bill being paidamount_applied: Amount allocated
- Relationships:
payment(): Paymentbill(): Bill
- Constraints: Unique (payment_id, bill_id)
Services (3 Services)
BillService (BillService.php)
Purpose: Create and post vendor bills
Dependencies:
- AccountingPoster
Key Methods:
createBill(Vendor $vendor, array $lines, ...): Bill
Creates a new vendor bill
$bill = $billService->createBill(
vendor: $vendor,
lines: [
[
'description' => 'Office Supplies',
'qty' => 10,
'unit_cost' => 25.00,
'expense_account_id' => $officeSuppliesAccount->id,
],
[
'description' => 'Monthly Internet Service',
'qty' => 1,
'unit_cost' => 150.00,
'expense_account_id' => $utilitiesAccount->id,
]
],
billDate: '2026-01-26',
dueDate: '2026-02-25', // 30 days
billNo: 'VENDOR-12345', // Vendor's bill number
notes: 'Net 30 payment terms'
);Process:
- Creates bill in DRAFT status
- Creates bill lines
- Calculates totals
- Returns bill
Note: Unlike AR invoices, AP bills typically don't have complex tax calculations (tax is often included in vendor bill total)
postBill(Bill $bill): void
Posts draft bill to GL and marks OPEN
$billService->postBill($bill);Process:
- Validates bill is DRAFT
- Prepares journal entry lines:
Debit: Expense Accounts (by line item) Credit: Accounts Payable (Liability) - Posts via AccountingPoster (Purchase Journal - PJ)
- Updates bill status to OPEN
- Increments vendor outstanding_balance
Accounting Entry Example:
Journal: PJ (Purchase Journal)
Reference: Bill #VENDOR-12345
Line 1:
Account: 5010 (Office Supplies Expense)
Debit: $250.00
Memo: "Office Supplies"
Line 2:
Account: 5020 (Utilities Expense)
Debit: $150.00
Memo: "Monthly Internet Service"
Line 3:
Account: 201 (Accounts Payable)
Credit: $400.00
Memo: "Bill from ABC Supplies Inc"
Total Debits: $400.00 = Total Credits: $400.00 ✓PaymentService (PaymentService.php)
Purpose: Process vendor payments and apply to bills
Dependencies:
- AccountingPoster
Key Methods:
createPayment(Vendor $vendor, array $payments, array $allocations, ...): Payment
Records a vendor payment
$payment = $paymentService->createPayment(
vendor: $vendor,
payments: [
[
'method' => 'BANK',
'amount' => 400.00,
'account_id' => $bankAccount->id,
'reference' => 'CHK-001234',
]
],
allocations: [
[
'bill_id' => $bill->id,
'amount' => 400.00,
]
],
paymentDate: '2026-01-26',
reference: 'Check #1234',
notes: 'Payment for office supplies'
);Process:
- Creates payment header
- Creates payment method records
- Creates allocations to bills
- Updates bill status (PARTIAL or PAID)
- Decrements vendor outstanding_balance
- Returns payment
Bill Status Update Logic:
- If
amount_paid >= total_amount: Status = PAID - If
amount_paid > 0 && amount_paid < total_amount: Status = PARTIAL - If
amount_paid = 0: Status = OPEN
postPayment(Payment $payment): void
Posts payment to GL
Accounting Entry:
Journal: CP (Cash Payments)
Reference: Payment #PAY-001
Line 1:
Account: 201 (Accounts Payable)
Debit: $400.00
Memo: "Payment to ABC Supplies Inc"
Line 2:
Account: 102 (Bank Checking)
Credit: $400.00
Memo: "Payment PAY-001 - BANK - CHK-001234"
Total Debits: $400.00 = Total Credits: $400.00 ✓APAgingService (APAgingService.php)
Purpose: Generate accounts payable aging reports
Key Methods:
getAgingReport(?int $propertyId = null): Collection
Returns aging report by vendor
Aging Buckets:
- Current (0-30 days)
- 31-60 days
- 61-90 days
- Over 90 days
Output Format:
[
'vendor_name' => 'ABC Supplies Inc',
'total_outstanding' => 5000.00,
'current' => 2000.00,
'31_60' => 1500.00,
'61_90' => 1000.00,
'over_90' => 500.00,
]Database Schema
Entity Relationship Diagram
erDiagram
BILL ||--o{ BILL_LINE : contains
BILL }o--|| VENDOR : "from"
BILL ||--o{ PAYMENT_ALLOCATION : "paid by"
BILL_LINE }o--|| ACCOUNTING_ACCOUNT : "posts to expense"
PAYMENT }o--|| VENDOR : "to"
PAYMENT ||--o{ PAYMENT_PAYMENT : "split tender"
PAYMENT ||--o{ PAYMENT_ALLOCATION : "applied to"
PAYMENT_PAYMENT }o--|| ACCOUNTING_ACCOUNT : "from cash"
PAYMENT_ALLOCATION }o--|| BILL : "pays"
BILL {
bigint id PK
bigint property_id FK
bigint vendor_id FK
string bill_no UK
date bill_date
date due_date
enum status
decimal subtotal
decimal tax_amount
decimal total_amount
}
BILL_LINE {
bigint id PK
bigint ap_bill_id FK
int line_no
string description
decimal qty
decimal unit_cost
decimal line_total
bigint expense_account_id FK
}
PAYMENT {
bigint id PK
bigint property_id FK
bigint vendor_id FK
string payment_no UK
date payment_date
decimal total_amount_paid
}
PAYMENT_PAYMENT {
bigint id PK
bigint ap_payment_id FK
enum payment_method
decimal amount
bigint cash_account_id FK
}
PAYMENT_ALLOCATION {
bigint id PK
bigint ap_payment_id FK
bigint ap_bill_id FK
decimal amount_applied
}Integration with Other Modules
Accounting Module Integration
Every AP transaction posts to the general ledger:
Bill Posting:
Debit: Expense Accounts (Expense increases)
Credit: Accounts Payable (Liability increases)Payment Posting:
Debit: Accounts Payable (Liability decreases)
Credit: Cash/Bank (Asset decreases)Expense Module Integration
Expense Approval to AP Bill: When an expense is approved:
- Expense module creates reimbursement obligation
- BillService creates AP bill for the employee/vendor
- Bill posted to GL
- Payment processed later
Inventory Module Integration
Purchase Orders: When inventory is received:
- Inventory module updates stock
- Creates AP bill automatically from PO
- Bill posted to GL
- Vendor payable tracked
Common Workflows
1. Record Vendor Bill
User: AP Clerk / Accountant
- Navigate to AP > Bills > Create
- Select vendor
- Enter vendor's bill number
- Enter bill date and due date
- Add line items:
- Description
- Quantity
- Unit cost
- Expense account
- Review calculated total
- Save as DRAFT (for approval)
- Manager reviews and approves
- Click Post Bill
- System:
- Posts to GL
- Updates vendor balance
- Marks bill OPEN
- Adds to aged payables
2. Process Vendor Payment
User: AP Clerk / Accountant
- Navigate to AP > Payments > Create
- Select vendor
- Enter payment method(s):
- Method (BANK, CHECK, etc.)
- Amount
- Bank account
- Check number or reference
- Allocate to bill(s):
- Select bills to pay
- Enter amount for each
- Review total = allocations
- Save payment
- Print check (if applicable)
- System:
- Records payment
- Posts to GL
- Updates bill status
- Reduces vendor balance
3. Review Payables Due
User: AP Manager / Accountant
- Navigate to AP > Reports > Due Bills
- Select date range (e.g., due in next 7 days)
- Review bills by:
- Vendor
- Due date
- Amount
- Prioritize payments:
- Critical vendors
- Discounts available
- Cash flow constraints
- Create payment batch
- Process payments
4. Generate Aging Report
User: AP Manager / Accountant
- Navigate to AP > Reports > Aging
- Select as-of date
- Optional filters:
- Vendor
- Overdue only
- Generate report
- Review buckets for each vendor
- Follow up on:
- Disputed bills
- Payment scheduling
- Vendor negotiations
Configuration
Account Mapping
Required GL accounts for AP:
- 201 - Accounts Payable (Liability)
- 101 - Cash (Asset)
- 102 - Bank Checking (Asset)
- Expense Accounts - Various (5000 series)
Payment Methods
Supported methods:
- CASH: Petty cash payments
- BANK: Bank transfers, ACH
- CARD: Credit card payments
- MOBILE_MONEY: Mobile payments
- OTHER: Other payment types
Numbering Sequences
Currently uses:
'BILL-' . strtoupper(uniqid()) // Bills (internal)
'PAY-' . strtoupper(uniqid()) // PaymentsNOTE
Bill number can be vendor's invoice number
Known Issues (from Audit)
MAJOR
MAJ-AP-001: Hardcoded Account Lookup
- Location:
PaymentService::postPayment() - Status: [FIXED]
- Description: Now uses
AccountingMapServiceto resolve accounts dynamically. - Priority: P1
MAJ-AP-002: Unsafe property_id Handling
- Location:
BillService::createBill() - Status: [FIXED]
- Description:
createBillnow requires explicitproperty_idparameter. - Priority: P1
MAJ-AP-003: Missing Tax Calculation
- Description: Tax amount field exists but not calculated automatically
- Impact: Must manually calculate and enter tax
- Fix: Integrate TaxEngine for input tax tracking (VAT)
- Priority: P2
MINOR
MIN-AP-001: Payment Not Auto-Posted
- Description: Payments created but not automatically posted to GL
- Impact: Requires manual posting step
- Fix: Auto-post payments
- Priority: P2
MIN-AP-002: Missing Void Functionality
- Description: No service method to void bills or payments
- Impact: Cannot reverse incorrect transactions
- Fix: Add
voidBill()andvoidPayment()methods - Priority: P2
MIN-AP-003: No Partial Payment Support in UI
- Description: System supports partial payments but UI assumes full payment
- Impact: User experience confusion
- Fix: Enhance UI to show outstanding balance
- Priority: P3
Best Practices
For Developers
- Always use BillService: Never create Bill models directly
- Post bills promptly: Drafts are for approval workflow only
- Validate allocations: Ensure payments don't exceed bill balance
- Use transactions: AP operations are multi-step
- Track references: Always include vendor bill number
For Users
- Review before posting: Bills cannot be edited after posting
- Match vendor invoices: Reconcile bill amounts with vendor invoice
- Apply payments correctly: Allocate to specific bills
- Track payment dates: Schedule payments for due dates
- Take discounts: Pay early if discount terms available
- Reconcile statements: Match AP to vendor statements monthly
Improvements Planned
ENH-AP-001: Payment Terms Management
- Store vendor payment terms (Net 30, 2/10 Net 30, etc.)
- Automatic due date calculation
- Early payment discount tracking
ENH-AP-002: 3-Way Matching
- Match PO → Receipt → Bill
- Prevent payment without matching
- Quantity and price variance detection
ENH-AP-003: Recurring Bills
- Support for subscription-based vendor bills
- Automatic bill generation
ENH-AP-004: Payment Automation
- Batch payment processing
- ACH file generation
- Wire transfer integration
ENH-AP-005: Vendor Portal
- Vendors can submit invoices online
- Real-time payment status
- Statement download
AR vs AP Comparison
| Feature | AR (Customer) | AP (Vendor) |
|---|---|---|
| Document | Invoice | Bill |
| Payment | Receipt | Payment |
| Party | Customer | Vendor |
| GL Impact | Debit AR | Credit AP |
| Nature | Asset (owes us) | Liability (we owe) |
| Journal | SJ, CR | PJ, CP |
| Aging | How much customers owe | How much we owe vendors |
Similarities:
- Both use split tender (multiple payment methods)
- Both use allocation (payment application)
- Both have aging reports
- Both integrate with GL via AccountingPoster
- Both track status (DRAFT → OPEN → PARTIAL → PAID)
Module Version: 1.0 Last Reviewed: January 26, 2026 Status: Production