Back to Hub

Cash Sale Module

Point of Sale & Transactions

v2.0
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