Billing in MindFlow is a unified financial layer covering OPD consultations, pharmacy purchases, IPD charges, and store orders. All financial transactions flow into the same invoices → invoice_items → transactions model, with a tamper-evident billing_audit_log for every change.
invoices → invoice_items → transactions. An invoice can contain OPD consultation fees, pharmacy items, IPD ward charges, lab charges, and store items in any combination. Each line item has a tax rate slot (configurable for GST — CGST + SGST or IGST).
billing_audit_log records every change to an invoice (created, item added, amount changed, payment received, refunded) with the acting user ID and a before/after snapshot. The log table has no UPDATE or DELETE permissions for application users — append-only at the DB grant level.
financial_periods allows admins to close a month, preventing backdated edits to invoices in a closed period. Useful for monthly P&L reconciliation.
cash_shifts + cash_deposits: front-desk staff open and close shifts with a physical cash count. All cash transactions in the shift period are totalled automatically and compared to the declared cash to produce a variance report.
The billing-export plugin (plugins/billing-export/) exports invoices as a Tally-compatible XML voucher file or CSV for the chosen date range. The plugin hooks into the billing data via plugins/billing-export/api/handler.php — no changes to core billing tables.
Handles card, UPI, net banking, and EMI payments for Indian patients. api/payu_webhook.php receives asynchronous payment notifications from PayU. pages/payment_process.php + pages/payment_return.php manage the redirect flow. Credentials stored in app_settings, never in code.
actions/paypal_return.php handles the PayPal redirect callback for international card / PayPal wallet payments. Used for overseas patients or for clinics that invoice international clients.
Both gateway webhooks verify the payment provider's HMAC signature before processing. Failed signature checks are logged and the payment is not applied.
store_categories → store_products → store_cart_items → store_orders → store_order_items. Products can be physical (require shipping) or digital. store_order_item_batches links each dispensed product to a specific pharmacy stock batch for traceability.
A credit balance is stored per patient (queryable via storeWalletBalance()). Patients can pay using their wallet balance at checkout. Failed payment attempts that were pre-deducted from the wallet are automatically reconciled via storeReconcileWalletAfterFailedAttempt().
store_coupons defines discount codes (percentage or fixed, minimum order, per-patient usage limit, expiry). storeValidateCoupon() checks all constraints before applying. store_coupon_redemptions records every use.
store_prescriptions: orders that require a valid prescription (scheduled medicines, certain supplements) are linked to a prescription ID from the clinic record. The pharmacist reviews the prescription before the order is dispensed.
store_returns: a patient can request a return on an order item. The return request goes to staff for approval; on approval, a refund is issued to the wallet or via the original payment method.
includes/shiprocket.php + api/shiprocket_webhook.php: physical orders are shipped via Shiprocket. A shipment is created via the Shiprocket API on order confirmation, and tracking updates are received via webhook and stored on the order.
store products get JSON-LD (Product schema) markup via storeProductJsonLd(). A store sitemap listing all active products is generated by storeGenerateSitemapXml() and included in the main sitemap.
The demo has real sample data — appointments, patients, prescriptions — so you can explore freely.