Bỏ qua để đến nội dung

POS card terminal — CodePay (ECR Hub)

Nội dung này hiện chưa có sẵn bằng ngôn ngữ của bạn.

CodePay integration in LionPOS uses the same POS bridge WebSocket and activation flow as other terminal tooling: clients pair via pos-bridge/activate, then exchange JSON messages whose shape follows CodePay’s ECR Hub contract (ecrhub.* topics). The monorepo implements this in @indochina/ecr-hub — package path packages/ecr-hub — via CodepayAdapter, encoder/parser helpers under manufacturers/codepay/, and shared constants (also re-exported from @indochina/shared for backwards compatibility).

Official reference (Kotlin samples, topic names, demo app_id): codepay-us/codepay-regsiter-same-terminal-integration-demo.

For platform-wide behaviour (payment intent, polling, terminal-webhook, bridge pairing), see POS card terminals & ECR Hub (PAX focus).


ConcernDetail
ChannelWebSocket — same wsUrl from POST /api/v1/pos-bridge/activate (or vendor dashboard activate) as the generic POS bridge; path /api/v1/pos-bridge/ws with terminalId + token query params.
HeartbeatClients may send bridge_heartbeat so the server keeps store_devices.is_connected accurate; the CodePay lab does this while testing.
Outcome to SaaSProduction bridges still turn terminal success/failure into POST /api/v1/pos/payments/terminal-webhook with x-pos-terminal-key — see POS and payment webhooks.

Server ECR relay (ecr_relay_request / ecr_relay_response): when the SaaS backend dispatches through EcrHubService with createBridgeRelayTransport, the POS bridge carries opaque hub payloads to vendor-desktop, which opens the CodePay service WebSocket (relayTransportKind: "ws"). Those socket JSON bodies are still ecrhub.* envelopes as below; they are not re-wrapped except for the outer bridge message type and correlationId. Manufacturer is ECR_MFR.CODEPAY in application code. See the bridge-relay matrix and sequence in POS card terminals & ECR Hub (PAX focus) (section Bridge relay).


Each outbound request is a JSON object with (at minimum):

FieldRole
versionProtocol version — constants CODEPAY_ECR_HUB_VERSION_1_1 ("1.1") or CODEPAY_ECR_HUB_VERSION_2_0 ("2.0").
app_idMerchant / integration id from CodePay (device settings in vendor dashboard). The demo repo uses a sample id also exposed as CODEPAY_ECR_HUB_DEMO_APP_ID in code — replace in production.
topicECR Hub topic (see table below).
request_idCorrelates request/response; the hub uses the command’s correlationId.
biz_dataTopic-specific payload (e.g. trans_type, amounts, merchant_order_no).

Encoder implementation: packages/ecr-hub/src/manufacturers/codepay/codepay-encoder.ts.


Constant (code)topic valueTypical use
CODEPAY_ECR_HUB_TOPIC_PAYecrhub.pay.orderSale, refund, void (via trans_type in biz_data).
CODEPAY_ECR_HUB_TOPIC_TIP_ADJUSTMENTecrhub.pay.tip.adjustmentPost-auth tip adjustment.
CODEPAY_ECR_HUB_TOPIC_BATCH_CLOSEecrhub.pay.batch.closeBatch close / settlement housekeeping.
CODEPAY_ECR_HUB_TOPIC_QUERYecrhub.pay.queryQuery / report-style lookup (REPORT in the adapter maps here).
CODEPAY_ECR_HUB_TOPIC_REPRINTecrhub.pay.reprintReprint last receipt (PRINTER in the adapter).

String codes align with the official demo’s invoke constants:

ConstantValueMeaning
CODEPAY_TRANS_TYPE_PURCHASE1Purchase / sale.
CODEPAY_TRANS_TYPE_VOID2Void.
CODEPAY_TRANS_TYPE_REFUND3Refund / return.
CODEPAY_TRANS_TYPE_PRE_AUTH4Pre-authorization (constants exist; CodepayAdapter does not expose PRE_AUTH today — lab samples may build raw envelopes).
CODEPAY_TRANS_TYPE_PRE_AUTH_COMPLETE6Complete pre-auth.
CODEPAY_TRANS_TYPE_QUERY21Query.
CODEPAY_TRANS_TYPE_REPRINT22Reprint.
CODEPAY_TRANS_TYPE_BATCH_CLOSE23Batch close.
CODEPAY_TRANS_TYPE_TIP_ADJUSTMENT24Tip adjustment.

Default in encoders: CODEPAY_PAY_SCENARIO_SWIPE_CARD (SWIPE_CARD). Other supported scenario constants include SCANQR_PAY, BSCANQR_PAY, CASH_PAY — pass via encoder payScenario options when wiring a custom transport.


packages/ecr-hub/src/manufacturers/codepay/codepay-parser.ts normalizes terminal JSON into EcrNormalizedPayment fields used across the hub (auth code, trace/reference, card hints, tip cents, etc.). CodePay returns two common envelope shapes:

  1. Legacy ECR Hub — top-level { version, app_id, topic, request_id, biz_data } with no top-level response_code / response_msg. Approval follows biz_data.trans_status === "1" only (see constants below).
  2. App-mode (e.g. callAppMode) — top-level response_code, response_msg (or response_message), plus biz_data. Live terminals often return response_code: "0" and response_msg: "SUCCESS" together with biz_data.trans_status: "2" for a completed sale. The parser treats approval as zero host response code, no explicit decline phrase in the host message, and either a success-like response_msg (SUCCESS / APPROVED / OK) or terminal-complete trans_status of "1" or "2". trans_status 3 / 4 still mean cancelled / pending and are never approved.
ValueConstantLegacy biz_data-only envelopeApp-mode + host fields
1CODEPAY_TRANS_STATUS_SUCCESSApprovedCompleted / success
2CODEPAY_TRANS_STATUS_FAILDeclined / failed (legacy)Often completed sale when paired with response_code: "0" and response_msg: "SUCCESS"
3CODEPAY_TRANS_STATUS_CANCELCancelledCancelled
4CODEPAY_TRANS_STATUS_PENDINGPendingPending

CodepayAdapter — supported canonical actions

Section titled “CodepayAdapter — supported canonical actions”

CodepayAdapter requires options.appId. Default timeouts: 90s for payment flows, 30s for housekeeping (BATCH_CLOSE, REPORT, PRINTER).

EcrHubCommand.actionMaps to
SALEecrhub.pay.order + purchase trans_type; optional metadata onScreenTip, onScreenSignature, description.
RETURNecrhub.pay.order + refund; requires reference as original merchant_order_no; optional tipAmountCents.
VOID_SALE / VOID_RETURNecrhub.pay.order + void; requires reference as orig_merchant_order_no.
TIP_ADJUSTMENTecrhub.pay.tip.adjustment.
BATCH_CLOSEecrhub.pay.batch.close.
REPORTecrhub.pay.query (uses merchant_order_no from reference / correlationId).
PRINTERecrhub.pay.reprint.

Not implemented on the adapter today: SIGN, ABORT, and PRE_AUTH / pre-auth complete — use PAX or raw envelope construction only if the device contract requires it.

Import: @indochina/ecr-hub/codepay or @indochina/ecr-hub.


AreaLocation
Device recordVendor → Settings → Devices — set manufacturer to CodePay and configure app id (and LAN fields if applicable).
WebSocket lab/dashboard/settings/codepay-ws — connect with wsUrl, send envelopes, inspect responses (developer tooling).
Sample payloadsapps/vendor-web/src/lib/codepay-ws-lab-samples.ts — includes pre-auth style samples for manual testing (may not match CodepayAdapter surface).

flowchart LR
  subgraph browser["Vendor web"]
    Lab["CodePay WS lab\n/settings/codepay-ws"]
    Future["Future POS / bridge"]
  end
  subgraph bridge["POS bridge WebSocket"]
    WS["/api/v1/pos-bridge/ws"]
  end
  subgraph device["CodePay terminal / app"]
    ECR["ECR Hub runtime"]
  end
  Lab -->|"JSON ecrhub.*"| WS
  Future -->|"JSON ecrhub.*"| WS
  WS <--> ECR

Implementation checklist (CodePay-specific)

Section titled “Implementation checklist (CodePay-specific)”
  • Obtain production app_id from CodePay; do not ship the demo id outside dev/test.
  • Wire CodepayAdapter + an EcrTransport that sends encode() payloads on the bridge socket and returns raw JSON strings to decode().
  • Map EcrHubResult.normalized + command context into TerminalPaymentWebhookDto and POST to terminal-webhook with x-pos-terminal-key.
  • Align pay_scenario with store payment methods (card vs QR).
  • If PRE_AUTH is required, extend CodepayAdapter or document a dedicated path — constants already exist in codepay-constants.ts.
  • Add/extend *.spec.ts for any new adapter branches per project rules.


VersionDateNotes
1.02026-04-26Initial CodePay ECR Hub reference: envelope, topics, adapter, parser, vendor-web lab