Skip to main content

Checkout System Integration

This document guides frontend developers on interacting with the backend checkout system via its GraphQL API.

Overview

The checkout system manages the billing process for a patient's visit. A central Checkout record aggregates all billable services, merchandise, drugs, and diagnostics (BillableItem records) added during the patient's journey. It also tracks applied discounts (CheckoutDiscount) and payments (Payment). The system calculates totals like subtotal, total discounts, total due, total paid, and balance due.

Core GraphQL Types

Checkout: The main record for a patient's bill.

  • id: Unique identifier (UUID).
  • status: Current state (OPEN, PARTIALLY_PAID, PAID, CLOSED, CANCELLED).
  • patientId: ID of the associated patient.
  • billableItems: List of BillableItem objects associated with this checkout.
  • payments: List of Payment objects made against this checkout.
  • discountApplications: List of CheckoutDiscount objects applied directly to the checkout total.
  • subtotal: Calculated sum of totalPrice for all non-cancelled BillableItems before checkout-level discounts. (Type: Money)
  • totalCheckoutDiscount: Calculated sum of discountAmount from checkout-level CheckoutDiscounts. (Type: Money)
  • totalDue: Calculated final amount owed (subtotal - totalCheckoutDiscount). (Type: Money)
  • totalPaid: Calculated sum of amount from all completed Payments. (Type: Money)
  • balanceDue: Calculated totalDue - totalPaid. (Type: Money)

BillableItem: A single line item on the checkout.

  • id: Unique identifier (UUID).
  • checkoutId: ID of the parent Checkout.
  • description: Name/description of the item.
  • quantity: Quantity of the item.
  • unitPrice: Price per unit before item-level discounts. (Type: Money)
  • discountApplications: List of CheckoutDiscount objects applied directly to this item.
  • totalDiscount: Calculated sum of discountAmount from item-level CheckoutDiscounts. (Type: Money)
  • totalPrice: Calculated final price for this line item ((quantity * unitPrice) - totalDiscount). (Type: Money)
  • status: Status of the item (PENDING, PAID, CANCELLED).

Payment: A record of a payment transaction.

  • id: Unique identifier (UUID).
  • checkoutId: ID of the associated Checkout.
  • amount: The amount of this payment applied towards the balanceDue. (Type: Money)
  • paymentMethod: How the payment was made (CASH, CARD, MOBILE_MONEY, etc.).
  • status: Status of the payment (PENDING, COMPLETED, FAILED, REFUNDED).
  • amountPaid: (For cash) The physical amount received from the customer. (Type: Money, nullable)
  • changeAmount: (For cash) Calculated change returned (amountPaid - amount). (Type: Money, nullable)
  • transactionReference: Optional reference ID from payment gateway.
  • processedAt: Timestamp when payment was processed.

CheckoutDiscount: Represents a single discount application.

  • id: Unique identifier (UUID).
  • checkoutId: ID of the Checkout this discount applies to (nullable).
  • billableItemId: ID of the BillableItem this discount applies to (nullable).
  • discountType: Type of discount (PERCENTAGE, FIXED).
  • discountValue: The percentage (e.g., 10.0) or fixed amount (e.g., 500 for $5.00) value. (Type: Decimal or Float)
  • discountAmount: The calculated monetary value of this discount. (Type: Money)
  • reason: Optional text description.

Money: Represents monetary values. Typically exposed as an object/map:

  • amount: The value as a string (e.g., "123.45").
  • currency: Currency code (e.g., "USD").

Workflow & Key Operations

  • Fetching Checkout Data:

Use the getCheckout query, providing the checkoutId and healthFacilityId as input variables. This query should return the Checkout object populated with its associated billableItems, payments, discountApplications, and all calculated totals needed to display the current bill.

# Example: Fetching checkout details
query GetCheckout($id: ID!) {
getCheckout(id: $id) {
id
status
subtotal { amount currency }
totalCheckoutDiscount { amount currency }
totalDue { amount currency }
totalPaid { amount currency }
balanceDue { amount currency }
billableItems {
id
description
quantity
unitPrice { amount currency }
totalDiscount { amount currency }
totalPrice { amount currency }
status
discounts { # Item-level discounts
id
discountType
discountValue
discountAmount { amount currency }
reason
}
}
payments {
id
amount { amount currency }
paymentMethod
status
amountPaid { amount currency }
changeAmount { amount currency }
processedAt
}
discounts { # Checkout-level discounts
id
discountType
discountValue
discountAmount { amount currency }
reason
}
}
}
  • Adding Billable Items:

Triggered by Nurses, Doctors, Pharmacists, Lab Techs, or Cashiers. Use the addBillableItem mutation (or similar name defined in your schema). Provide checkoutId, description, quantity, unitPrice. Optionally include item-level discount info if applying at creation. The backend handles creating the BillableItem and associating it with the Checkout. It implicitly creates the Checkout if this is the first item for the patient's visit context. Recommendation: After adding an item, refetch the Checkout data to update the displayed bill totals.

# Example: Adding a billable item
mutation AddBillableItem($checkoutId: ID!, $description: String!, $quantity: Int!, $unitPrice: MoneyInput!) {
addBillableItem(checkoutId: $checkoutId, description: $description, quantity: $quantity, unitPrice: $unitPrice) {
id
status
billableItems {
id
description
quantity
unitPrice { amount currency }
totalDiscount { amount currency }
totalPrice { amount currency }
}
}
}
# Variables
{
"checkoutId": "12345",
"description": "Bandage",
"quantity": 1,
"unitPrice": { "amount": "5.00", "currency": "USD" }
}
  • Applying Discounts:

Use applyDiscountToBillableItem or applyDiscountToCheckout mutations. Provide the target ID (billableItemId or checkoutId), discountType, discountValue, and optionally a reason. The backend creates a CheckoutDiscount record and recalculates relevant totals. Recommendation: Refetch Checkout data after applying a discount.

# Example: Applying a discount to a billable item
mutation ApplyDiscountToBillableItem($billableItemId: ID!, $discountType: DiscountType!, $discountValue: Float!, $reason: String) {
applyDiscountToBillableItem(billableItemId: $billableItemId, discountType: $discountType, discountValue: $discountValue, reason: $reason) {
id
totalDiscount { amount currency }
totalPrice { amount currency }
}
}
# Variables
{
"billableItemId": "67890",
"discountType": "PERCENTAGE",
"discountValue": 10.0,
"reason": "Loyalty Discount"
}

# Example: Applying a discount to the entire checkout
mutation ApplyDiscountToCheckout($checkoutId: ID!, $discountType: DiscountType!, $discountValue: Float!, $reason: String) {
applyDiscountToCheckout(checkoutId: $checkoutId, discountType: $discountType, discountValue: $discountValue, reason: $reason) {
id
totalCheckoutDiscount { amount currency }
totalDue { amount currency }
}
}
# Variables
{
"checkoutId": "12345",
"discountType": "FIXED",
"discountValue": 50.0,
"reason": "End of Month Discount"
}
  • Removing Discounts:

Use removeDiscountFromBillableItem or removeDiscountFromCheckout mutations. Provide the target ID (billableItemId or checkoutId) and the discount ID to be removed. The backend updates the CheckoutDiscount record and recalculates relevant totals. Recommendation: Refetch Checkout data after removing a discount.

# Example: Removing a discount from a billable item
mutation RemoveDiscountFromBillableItem($billableItemId: ID!, $discountId: ID!) {
removeDiscountFromBillableItem(billableItemId: $billableItemId, discountId: $discountId) {
id
totalDiscount { amount currency }
totalPrice { amount currency }
}
}
# Variables
{
"billableItemId": "67890",
"discountId": "abc123"
}
# Example: Removing a discount from the entire checkout
mutation RemoveDiscountFromCheckout($checkoutId: ID!, $discountId: ID!) {
removeDiscountFromCheckout(checkoutId: $checkoutId, discountId: $discountId) {
id
totalCheckoutDiscount { amount currency }
totalDue { amount currency }
}
}
# Variables
{
"checkoutId": "12345",
"discountId": "xyz789"
}
  • Recording Payments:

Use the recordPayment mutation. Provide checkoutId, amount, paymentMethod, and optionally amountPaid (for cash payments). The backend creates a Payment record and updates the Checkout status. Recommendation: Refetch Checkout data after recording a payment to update totals and status.

# Example: Recording a payment
mutation RecordPayment($checkoutId: ID!, $amount: MoneyInput!, $paymentMethod: PaymentMethod!, $amountPaid: MoneyInput) {
recordPayment(checkoutId: $checkoutId, amount: $amount, paymentMethod: $paymentMethod, amountPaid: $amountPaid) {
id
status
payments {
id
amount { amount currency }
paymentMethod
status
processedAt
}
totalPaid { amount currency }
balanceDue { amount currency }
}
}
# Variables
{
"checkoutId": "12345
"amount": { "amount": "150.00", "currency": "USD" },
"paymentMethod": "CASH",
"amountPaid": { "amount": "200.00", "currency": "USD" }

}
  • Handling Checkout Status:

  • Monitor the Checkout.status field.

  • OPEN / PARTIALLY_PAID: Payment is expected. Enable payment actions.

  • PAID: Payment complete. Disable payment actions, potentially show receipt options.

  • CLOSED: Finalized. Usually read-only.

  • CANCELLED: Visit/Checkout aborted. Read-only.

Sequence Diagram