Skip to content

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 vendor
    • bill_date: Bill date
    • due_date: Payment due date
    • status: DRAFT | OPEN | PARTIAL | PAID | VOID
    • subtotal: Line items total (before tax)
    • tax_amount: Total tax
    • total_amount: Final amount payable
    • notes: Bill notes
  • Relationships:
    • vendor(): Vendor (via Party)
    • lines(): BillLine records
    • allocations(): PaymentAllocation records (payments applied)
  • Computed Attributes:
    • amount_paid: Sum of allocations
    • balance_due: total_amount - amount_paid
  • Traits: BelongsToProperty
BillLine (BillLine.php)
  • Bill line items
  • Table: ap_bill_lines
  • Key Fields:
    • ap_bill_id: Parent bill
    • line_no: Line number
    • description: Line description
    • qty: Quantity
    • unit_cost: Unit cost
    • line_total: Extended amount (qty × unit_cost)
    • expense_account_id: GL expense account
  • Relationships:
    • bill(): Parent bill
    • expenseAccount(): GL account
Payment (Payment.php)
  • Vendor payment header
  • Table: ap_payments
  • Key Fields:
    • payment_no: Unique payment number
    • vendor_id: Payee vendor
    • payment_date: Payment date
    • total_amount_paid: Total payment amount
    • reference_no: External reference (check #, wire transfer #)
    • notes: Payment notes
  • Relationships:
    • vendor(): Vendor
    • payments(): 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 payment
    • payment_method: CASH | BANK | MOBILE_MONEY | CARD | OTHER
    • amount: Amount for this method
    • cash_account_id: GL cash/bank account
    • reference_no: Method-specific reference (check #, etc.)
  • Relationships:
    • payment(): Parent payment
    • cashAccount(): GL account
PaymentAllocation (PaymentAllocation.php)
  • Payment application to bills
  • Table: ap_payment_allocations
  • Key Fields:
    • ap_payment_id: Payment being applied
    • ap_bill_id: Bill being paid
    • amount_applied: Amount allocated
  • Relationships:
    • payment(): Payment
    • bill(): 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

php
$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:

  1. Creates bill in DRAFT status
  2. Creates bill lines
  3. Calculates totals
  4. 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

php
$billService->postBill($bill);

Process:

  1. Validates bill is DRAFT
  2. Prepares journal entry lines:
    Debit: Expense Accounts (by line item)
    Credit: Accounts Payable (Liability)
  3. Posts via AccountingPoster (Purchase Journal - PJ)
  4. Updates bill status to OPEN
  5. 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

php
$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:

  1. Creates payment header
  2. Creates payment method records
  3. Creates allocations to bills
  4. Updates bill status (PARTIAL or PAID)
  5. Decrements vendor outstanding_balance
  6. 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:

php
[
    '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

mermaid
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:

  1. Expense module creates reimbursement obligation
  2. BillService creates AP bill for the employee/vendor
  3. Bill posted to GL
  4. Payment processed later

Inventory Module Integration

Purchase Orders: When inventory is received:

  1. Inventory module updates stock
  2. Creates AP bill automatically from PO
  3. Bill posted to GL
  4. Vendor payable tracked

Common Workflows

1. Record Vendor Bill

User: AP Clerk / Accountant

  1. Navigate to AP > Bills > Create
  2. Select vendor
  3. Enter vendor's bill number
  4. Enter bill date and due date
  5. Add line items:
    • Description
    • Quantity
    • Unit cost
    • Expense account
  6. Review calculated total
  7. Save as DRAFT (for approval)
  8. Manager reviews and approves
  9. Click Post Bill
  10. System:
    • Posts to GL
    • Updates vendor balance
    • Marks bill OPEN
    • Adds to aged payables

2. Process Vendor Payment

User: AP Clerk / Accountant

  1. Navigate to AP > Payments > Create
  2. Select vendor
  3. Enter payment method(s):
    • Method (BANK, CHECK, etc.)
    • Amount
    • Bank account
    • Check number or reference
  4. Allocate to bill(s):
    • Select bills to pay
    • Enter amount for each
  5. Review total = allocations
  6. Save payment
  7. Print check (if applicable)
  8. System:
    • Records payment
    • Posts to GL
    • Updates bill status
    • Reduces vendor balance

3. Review Payables Due

User: AP Manager / Accountant

  1. Navigate to AP > Reports > Due Bills
  2. Select date range (e.g., due in next 7 days)
  3. Review bills by:
    • Vendor
    • Due date
    • Amount
  4. Prioritize payments:
    • Critical vendors
    • Discounts available
    • Cash flow constraints
  5. Create payment batch
  6. Process payments

4. Generate Aging Report

User: AP Manager / Accountant

  1. Navigate to AP > Reports > Aging
  2. Select as-of date
  3. Optional filters:
    • Vendor
    • Overdue only
  4. Generate report
  5. Review buckets for each vendor
  6. 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:

php
'BILL-' . strtoupper(uniqid())  // Bills (internal)
'PAY-' . strtoupper(uniqid())   // Payments

NOTE

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 AccountingMapService to resolve accounts dynamically.
  • Priority: P1

MAJ-AP-002: Unsafe property_id Handling

  • Location: BillService::createBill()
  • Status: [FIXED]
  • Description: createBill now requires explicit property_id parameter.
  • 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() and voidPayment() 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

  1. Always use BillService: Never create Bill models directly
  2. Post bills promptly: Drafts are for approval workflow only
  3. Validate allocations: Ensure payments don't exceed bill balance
  4. Use transactions: AP operations are multi-step
  5. Track references: Always include vendor bill number

For Users

  1. Review before posting: Bills cannot be edited after posting
  2. Match vendor invoices: Reconcile bill amounts with vendor invoice
  3. Apply payments correctly: Allocate to specific bills
  4. Track payment dates: Schedule payments for due dates
  5. Take discounts: Pay early if discount terms available
  6. 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

FeatureAR (Customer)AP (Vendor)
DocumentInvoiceBill
PaymentReceiptPayment
PartyCustomerVendor
GL ImpactDebit ARCredit AP
NatureAsset (owes us)Liability (we owe)
JournalSJ, CRPJ, CP
AgingHow much customers oweHow 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