Module Documentation
Cash Sale Module
This module handles direct over-the-counter sales, including invoicing, immediate payment collection, and returns management. It ensures streamlined point-of-sale operations.
Data Structure (ERD)
erDiagram
%% --- MASTER DATA ---
cash_sale_customers {
bigint id PK
foreignId branch_id FK
foreignId customer_group_id FK
string customer_code
string customer_name
string customer_cnic
string customer_mobile
string customer_email
string customer_ntn
string status
foreignId created_by FK
timestamp created_at
timestamp updated_at
}
item_cash_sale_prices {
bigint id PK
foreignId item_variant_id FK
foreignId branch_id FK
string price_list_code
decimal salesman_price
decimal retail_price
decimal fixed_price
enum default_price_type
boolean change_price
datetime effective_date
}
%% --- INVOICING ---
cash_sale_invoices {
bigint id PK
foreignId branch_id FK
foreignId cash_sale_customer_id FK
foreignId sales_person_id FK
string invoice_number
date invoice_date
decimal subtotal
decimal discount_amount
decimal tax_amount
decimal grand_total
string reference_type
bigint reference_id
enum payment_status
enum invoice_status
enum status "PENDING, APPROVED..."
timestamp posted_at
foreignId created_by FK
timestamp created_at
}
cash_sale_invoice_items {
bigint id PK
foreignId invoice_id FK
foreignId item_variant_id FK
decimal quantity
decimal unit_price
decimal unit_cost
decimal discount
json tax
decimal total_tax_amount
decimal total_amount
}
cash_sale_payments {
bigint id PK
foreignId invoice_id FK
string payment_method
decimal amount_paid
date payment_date
string reference_no
enum status
timestamp created_at
}
%% --- RETURNS ---
cash_sale_return_invoices {
bigint id PK
string return_number
foreignId cash_sale_invoice_id FK
foreignId delivery_return_voucher_id FK
foreignId customer_id FK
foreignId branch_id FK
date return_date
string return_reason
decimal sub_total
decimal total_discount
decimal tax_amount
decimal total_amount
enum status
timestamp posted_at
text remarks
foreignId created_by FK
timestamp created_at
}
cash_sale_return_invoice_items {
bigint id PK
foreignId cash_sale_return_invoice_id FK
foreignId item_variant_id FK
decimal quantity
decimal unit_price
decimal discount
json tax
decimal total_tax_amount
decimal line_total
}
%% --- RELATIONSHIPS ---
cash_sale_customers ||--o{ cash_sale_invoices : "has"
cash_sale_customers ||--o{ cash_sale_return_invoices : "returns"
cash_sale_invoices ||--o{ cash_sale_invoice_items : "contains"
cash_sale_invoices ||--o{ cash_sale_payments : "receives"
cash_sale_invoices ||--o{ cash_sale_return_invoices : "reference for"
cash_sale_return_invoices ||--o{ cash_sale_return_invoice_items : "contains"
%% Implicit / Pricing
item_cash_sale_prices ||--o{ cash_sale_invoice_items : "determines price"
Order to Cash Flow
sequenceDiagram
autonumber
actor Sales as Sales Person
participant UI as Livewire
(CashSaleCreate)
participant Svc as CashSaleService
participant Repo as CashSaleRepo
participant Stock as InventoryService
participant Appr as ApprovalEngine
participant Fin as FinanceService
Sales->>UI: Create Invoice (Items + Cust)
UI->>Svc: createInvoice(data)
activate Svc
Svc->>Stock: checkAvailability(items)
Stock-->>Svc: OK
Svc->>Repo: create(data) -> DRAFT Invoice
Svc->>Appr: checkSetupExists('CREATE', Invoice::class)
alt Needs Approval
Svc->>Repo: updateStatus(PENDING)
else Auto-Approved
Svc->>Repo: updateStatus(APPROVED)
Svc->>Svc: fireCreatedEvent()
Svc->>Stock: reserveStock(items)
end
Svc-->>UI: Invoice #INV-1001 Created
deactivate Svc
Sales->>UI: Record Payment
UI->>Svc: addPayment(inv_id, amount, method)
activate Svc
Svc->>Repo: createPayment(data)
Svc->>Repo: updatePaymentStatus(PARTIAL/PAID)
opt Fully Paid & Approved
Svc->>Stock: deductStock(items)
Svc->>Fin: postToGL(revenue)
Svc->>Repo: updateStatus(POSTED)
end
Svc-->>UI: Payment Recorded
deactivate Svc
Invoice Lifecycle State
stateDiagram-v2
state "Administrative Status" as AdminStatus {
[*] --> Pending : Created
Pending --> Approved : Manager Signs Off
Pending --> Rejected : Fix Required
Approved --> Posted : GL/Stock Impacted
Approved --> Cancelled : Voided
}
state "Payment Status" as PayStatus {
[*] --> Unpaid
Unpaid --> Partial : Deposit Received
Partial --> Paid : Full Settlement
Unpaid --> Paid : Full Settlement
}
state "Operational Status" as OpStatus {
[*] --> Open
Open --> Closed : Delivered & Paid
Open --> Returned : Sales Return
}
Note right of AdminStatus : Controls Visibility & Reporting
Note right of PayStatus : Controls Financial Aging
Business Process Flowchart
flowchart TD
%% Sales Process
Start([Start]) --> SelectCust[Select/Create Customer]
SelectCust --> ScanItems[Scan Items]
%% Pricing Logic (Loop for each item)
ScanItems --> GetPrice[Get Base Price]
GetPrice --> CheckOverride{Price Override?}
CheckOverride -- No --> AddItem[Add to Invoice]
CheckOverride -- Yes --> NeedPerm{Has Permission?}
NeedPerm -- Yes --> AllowEdit[Edit Price]
NeedPerm -- No --> ReqAppr[Request Price Approval]
%% Fixing the Dead End
ReqAppr -- Approved --> AllowEdit
AllowEdit --> AddItem
%% Scan Loop
AddItem --> MoreItems{More Items?}
MoreItems -- Yes --> ScanItems
%% Finalization
MoreItems -- No --> Finalize[Finalize Invoice]
Finalize --> Payment{Payment?}
Payment -- Now --> Collect[Collect Cash/Card]
Payment -- Later --> CreditSale[Mark Unpaid Credit]
Collect --> Post[Post Invoice]
CreditSale --> Post
%% Post-Sale Logistics
Post --> StockOut[Update Inventory]
Post --> CheckDeliv{Delivery Required?}
CheckDeliv -- Yes --> GenDel[Generate Delivery Voucher]
CheckDeliv -- No --> SaleEnd([Sale Complete])
GenDel --> SaleEnd
%% Return Process (Separate Trigger)
subgraph Return_Process [Subsequent Return Flow]
RetStart([Return Request]) --> ProcessReturn[Process Return]
ProcessReturn --> CreateRetInv[Create Return Invoice]
CreateRetInv --> Refund[Process Refund/Credit]
Refund --> Restock[Restock Items]
Restock --> End([End])
end
%% Optional link just to show relationship,
%% though in reality this is an async event
SaleEnd -.-> RetStart