Payment concept
Payment service will manage orders and transactions which allows client application to integrate payment gateway to allow users to purchase digital items from application.
Database schema

Orders
Order will manages a single purchasing from user, it includes many order items that define item name, quantities and price for each items.

Order properties
| Field | Type | Values | Description |
|---|---|---|---|
status | Enum | OrderStatus | status of order. |
sub_total | Decimal | total order price. | |
currency_code | String(10) | USD, VND | 3 characters for currency code, default VND. |
note | Text | note for admin | |
custom-data | Record | any user provide custom json data. | |
request-id | String(96) | (Optional) request id from caller service, for tracking perpose. | |
app-id | String(96) | (Optional) app id generate the request. |
export enum OrderStatus {
PLACED = "PLACED", // The order has been placed.
PAYMENT_PENDING = "PAYMENT_PENDING", // The payment for the order is pending.
PAYMENT_FAILED = "PAYMENT_FAILED", // The payment for the order has failed, can be repay ?
PAYMENT_CANCELED = "PAYMENT_CANCELED", // The payment for the order has been canceled.
PAYMENT_SUCCEEDED = "PAYMENT_SUCCEEDED", // The payment for the order has succeeded.
CONFIRMED = "CONFIRMED", // The order has been confirmed or shipped
ACKNOWLEDGED = "ACKNOWLEDGED", // The order has been acknowledged or delivered
COMPLETED = "COMPLETED", // The order has been completed, final state
ABANDONED = "ABANDONED", // The order has abandoned, final state
CANCELED = "CANCELED", // The order has been canceled, final state
}
OrderItem Properties
| Field | Type | Values | Description |
|---|---|---|---|
name | String(255) | displayable name. | |
slug | String(255) | url friendly name, ex: item-upgrade-1 | |
quantity | Int | quantity of item | |
price_per_item | Decimal | price per item in quantity. | |
options | Record | any custom options for the item. |
Paygate Providers
Paygate Providers will present for payment gateways with API configuration, such as Google Play, Apple Store, Momo, Paypal, Stripe. Each gateway can have multiple provider records with difference API configuration or accounts.
| Field | Type | Values | Description |
|---|---|---|---|
provider-type | String(100) | apple-store, google-play | paygate provider type |
name | String(100) | unique identifier name | |
methods | Array | PgProviderMethod | supported methods |
options | Record | option to connect into 3rd-party paygates |
export enum PgProviderMethod {
VERIFY_RECEIPT = "verify-receipt",
}
Paygate Transactions
Paygate Transactions will manages a single payment transaction from a single paygate provider. There will be many ways to interact and update paypage transaction depend on which methods that payment gateway provides.

| Field | Type | Values | Description |
|---|---|---|---|
status | Enum | PgTransactStatus | Status of transaction |
userId | Id | User id. | |
amount | Decimal | Amount in transaction | |
capturedAmount | String(10) | Amount that captured in transaction | |
currencyCode | String(10) | USD, VND | 3 characters for currency code, default VND. |
providerName | String(128) | Provider name that issue the transaction. | |
providerMethods | Array | PgProviderMethod | Support methods of provider. |
orderId | Record | Order id. | |
pendingAction | Enum | PgPendingAction | Pending action need to be process. |
customData | Record | Any user provide custom json data. | |
failedReason | String(64) | The short string reason that transaction failed. | |
auditMessages | String Array | Any audit messages. |
/**
* These enum values represent the possible states a transaction can be in during its lifecycle within a payment gateway or payment processing system.
*/
export enum PgTransactStatus {
PENDING = "PENDING", // The transaction is pending and has not started processing yet, maybe waiting for user to input details
PROCESSING = "PROCESSING", // The transaction is currently being processed.
FAILED = "FAILED", // The transaction has failed.
CANCELED = "CANCELED", // The transaction has been canceled.
AUTHORIZED = "AUTHORIZED", // The transaction has been authorized.
CAPTURED = "CAPTURED", // The transaction has been successfully captured or completed.
}
export enum PgPendingAction {
RECEIPT_VERIFIED = "receipt-verified",
MARK_AS_CANCELED = "mark-as-canceled",
MARK_AS_FAILED = "mark-as-failed",
}
Resolve a transaction status
In-app-purchase
- Client mobile app will submit receipt data
- The transaction will success if the receipt data valid
- The transaction will failed if the receipt data invalid
Banking
- Client show bank transfering account and waiting for user to top-up
- Service will poll for top-up transaction and update transaction status
- or admin resolve transaction status manually after checking bank account
....
Enity locking
A simple mechanism allows to lock an entity (Order, Transact) to prevent multiple access in multi threading environment
Characteristics
- Only one locked entity allow at a time (locked key is entity id, ex Order id...)
- Successful lock with return lock id, the thread must store this lock id in order to unlock it, any subsequence lock arquired calls will throw (HTTP 409)
- Only call with right lock id and entity id can unlock
- To prevent an entity is locked forever, an lock expires time is required, lock will be unlocked automatically when expired