taler-typescript-core

Wallet core logic and WebUIs for various components
Log | Files | Refs | Submodules | README | LICENSE

commit 9b6c06f2a010725d04b2114c11cc384442cf0782
parent 326d942d9634ee5f2a7b7874be06bc6c8ece167a
Author: Sebastian <sebasjm@gmail.com>
Date:   Thu,  9 Oct 2025 16:10:47 -0300

add paydeadline

Diffstat:
Mpackages/merchant-backoffice-ui/src/paths/instance/orders/create/OrderCreatedSuccessfully.tsx | 19+++++++++----------
Mpackages/merchant-backoffice-ui/src/paths/instance/orders/create/index.tsx | 10+++++++++-
Mpackages/merchant-backoffice-ui/src/paths/instance/orders/details/Detail.stories.tsx | 3+++
Mpackages/merchant-backoffice-ui/src/paths/instance/orders/details/index.tsx | 12++++--------
Mpackages/merchant-backoffice-ui/src/paths/instance/orders/list/index.tsx | 15++++++---------
Mpackages/taler-util/src/http-client/merchant.ts | 41+++++++++++++++++------------------------
Mpackages/taler-util/src/types-taler-merchant.ts | 14++++++++++++--
7 files changed, 60 insertions(+), 54 deletions(-)

diff --git a/packages/merchant-backoffice-ui/src/paths/instance/orders/create/OrderCreatedSuccessfully.tsx b/packages/merchant-backoffice-ui/src/paths/instance/orders/create/OrderCreatedSuccessfully.tsx @@ -17,6 +17,7 @@ import { HttpStatusCode, OrderVersion, TalerError, + TalerErrorCode, assertUnreachable, } from "@gnu-taler/taler-util"; import { Loading, useTranslationContext } from "@gnu-taler/web-util/browser"; @@ -47,7 +48,8 @@ export function OrderCreatedSuccessfully({ return <ErrorLoadingMerchant error={result} />; } - if (entity.request.order.version !== undefined && + if ( + entity.request.order.version !== undefined && entity.request.order.version !== OrderVersion.V0 ) { return <div>Unsupported order version {entity.request.order.version}</div>; @@ -55,16 +57,11 @@ export function OrderCreatedSuccessfully({ if (result.type === "fail") { switch (result.case) { - case HttpStatusCode.NotFound: { + case TalerErrorCode.MERCHANT_GENERIC_INSTANCE_UNKNOWN: { return <NotFoundPageOrAdminCreate />; } - case HttpStatusCode.BadGateway: { - return <div>Failed to obtain a response from the exchange</div>; - } - case HttpStatusCode.GatewayTimeout: { - return ( - <div>The merchant's interaction with the exchange took too long</div> - ); + case TalerErrorCode.MERCHANT_GENERIC_ORDER_UNKNOWN: { + return <i18n.Translate>Order unkown</i18n.Translate>; } case HttpStatusCode.Unauthorized: { return <LoginPage />; @@ -114,7 +111,9 @@ export function OrderCreatedSuccessfully({ <div class="field-body is-flex-grow-3"> <div class="field"> <p class="control"> - <i18n.Translate>This feature is not yet supported</i18n.Translate> + <i18n.Translate> + This feature is not yet supported + </i18n.Translate> </p> </div> </div> diff --git a/packages/merchant-backoffice-ui/src/paths/instance/orders/create/index.tsx b/packages/merchant-backoffice-ui/src/paths/instance/orders/create/index.tsx @@ -22,6 +22,7 @@ import { HttpStatusCode, TalerError, + TalerErrorCode, TalerMerchantApi, assertUnreachable, } from "@gnu-taler/taler-util"; @@ -113,7 +114,6 @@ export default function OrderCreate({ onConfirm, onBack }: Props): VNode { return; } case HttpStatusCode.Unauthorized: - case HttpStatusCode.NotFound: case HttpStatusCode.Conflict: { setNotif({ message: i18n.str`Could not create order`, @@ -130,6 +130,14 @@ export default function OrderCreate({ onConfirm, onBack }: Props): VNode { }); return; } + case HttpStatusCode.NotFound: { + setNotif({ + message: i18n.str`Could not create order`, + type: "ERROR", + description: i18n.str`Instance not found`, + }); + return; + } default: { assertUnreachable(resp); } diff --git a/packages/merchant-backoffice-ui/src/paths/instance/orders/details/Detail.stories.tsx b/packages/merchant-backoffice-ui/src/paths/instance/orders/details/Detail.stories.tsx @@ -124,6 +124,9 @@ export const Unpaid = createExample(TestedComponent, { id: "2021.165-03GDFC26Y1NNG", selected: { order_status: "unpaid", + pay_deadline: { + t_s: "never", + }, order_status_url: "http://merchant.backend/status", creation_time: { t_s: new Date().getTime() / 1000, diff --git a/packages/merchant-backoffice-ui/src/paths/instance/orders/details/index.tsx b/packages/merchant-backoffice-ui/src/paths/instance/orders/details/index.tsx @@ -16,6 +16,7 @@ import { HttpStatusCode, TalerError, + TalerErrorCode, assertUnreachable, } from "@gnu-taler/taler-util"; import { useTranslationContext } from "@gnu-taler/web-util/browser"; @@ -49,16 +50,11 @@ export default function Update({ oid, onBack }: Props): VNode { } if (result.type === "fail") { switch (result.case) { - case HttpStatusCode.NotFound: { + case TalerErrorCode.MERCHANT_GENERIC_INSTANCE_UNKNOWN: { return <NotFoundPageOrAdminCreate />; } - case HttpStatusCode.BadGateway: { - return <div>Failed to obtain a response from the exchange</div>; - } - case HttpStatusCode.GatewayTimeout: { - return ( - <div>The merchant's interaction with the exchange took too long</div> - ); + case TalerErrorCode.MERCHANT_GENERIC_ORDER_UNKNOWN: { + return <i18n.Translate>Order unkown</i18n.Translate> } case HttpStatusCode.Unauthorized: { return <LoginPage />; diff --git a/packages/merchant-backoffice-ui/src/paths/instance/orders/list/index.tsx b/packages/merchant-backoffice-ui/src/paths/instance/orders/list/index.tsx @@ -23,6 +23,7 @@ import { AbsoluteTime, HttpStatusCode, TalerError, + TalerErrorCode, TalerMerchantApi, assertUnreachable, stringifyPayUri, @@ -208,6 +209,7 @@ interface RefundProps { } function RefundModalForTable({ id, onConfirm, onCancel }: RefundProps): VNode { + const {i18n} = useTranslationContext(); const result = useOrderDetails(id); if (!result) return <Loading />; @@ -216,16 +218,11 @@ function RefundModalForTable({ id, onConfirm, onCancel }: RefundProps): VNode { } if (result.type === "fail") { switch (result.case) { - case HttpStatusCode.NotFound: { - return <NotFoundPageOrAdminCreate />; - } - case HttpStatusCode.BadGateway: { - return <div>Failed to obtain a response from the exchange</div>; + case TalerErrorCode.MERCHANT_GENERIC_INSTANCE_UNKNOWN: { + return <i18n.Translate>Instance unkown</i18n.Translate> } - case HttpStatusCode.GatewayTimeout: { - return ( - <div>The merchant's interaction with the exchange took too long</div> - ); + case TalerErrorCode.MERCHANT_GENERIC_ORDER_UNKNOWN: { + return <i18n.Translate>Order unkown</i18n.Translate> } case HttpStatusCode.Unauthorized: { return <LoginPage />; diff --git a/packages/taler-util/src/http-client/merchant.ts b/packages/taler-util/src/http-client/merchant.ts @@ -72,7 +72,6 @@ import { codecForWalletTemplateDetails, codecForWebhookDetails, codecForWebhookSummaryResponse, - codecOptionalDefault, opEmptySuccess, opFixedSuccess, opKnownAlternativeHttpFailure, @@ -84,7 +83,7 @@ import { HttpRequestLibrary, HttpResponse, createPlatformHttpLib, - readTalerErrorResponse + readTalerErrorResponse, } from "@gnu-taler/taler-util/http"; import { opSuccessFromHttp } from "../operation.js"; import { @@ -173,7 +172,10 @@ export class TalerMerchantInstanceHttpClient { } static isCompatible(version: string): boolean { - const compare = LibtoolVersion.compare(TalerMerchantInstanceHttpClient.PROTOCOL_VERSION, version); + const compare = LibtoolVersion.compare( + TalerMerchantInstanceHttpClient.PROTOCOL_VERSION, + version, + ); return compare?.compatible ?? false; } @@ -1505,17 +1507,7 @@ export class TalerMerchantInstanceHttpClient { token: AccessToken | undefined, orderId: string, params: TalerMerchantApi.GetOrderRequestParams = {}, - ): Promise< - | OperationOk<TalerMerchantApi.MerchantOrderStatusResponse> - | OperationFail<HttpStatusCode.NotFound> - | OperationFail<HttpStatusCode.Unauthorized> - | OperationFail<HttpStatusCode.BadGateway> - // FIXME: This can't be right! - | OperationAlternative< - HttpStatusCode.GatewayTimeout, - TalerMerchantApi.OutOfStockResponse - > - > { + ) { const url = new URL(`private/orders/${orderId}`, this.baseUrl); if (params.allowRefundedForRepurchase !== undefined) { @@ -1546,18 +1538,19 @@ export class TalerMerchantInstanceHttpClient { resp, codecForMerchantOrderPrivateStatusResponse(), ); - case HttpStatusCode.NotFound: - return opKnownHttpFailure(resp.status, resp); + case HttpStatusCode.NotFound: { + const details = await readTalerErrorResponse(resp); + switch (details.code) { + case TalerErrorCode.MERCHANT_GENERIC_ORDER_UNKNOWN: + return opKnownTalerFailure(details.code, details); + case TalerErrorCode.MERCHANT_GENERIC_INSTANCE_UNKNOWN: + return opKnownTalerFailure(details.code, details); + default: + return opUnknownHttpFailure(resp, details); + } + } case HttpStatusCode.Unauthorized: // FIXME: missing in docs return opKnownHttpFailure(resp.status, resp); - case HttpStatusCode.BadGateway: - return opKnownHttpFailure(resp.status, resp); - case HttpStatusCode.GatewayTimeout: - return opKnownAlternativeHttpFailure( - resp, - resp.status, - codecForOutOfStockResponse(), - ); default: return opUnknownHttpFailure(resp); } diff --git a/packages/taler-util/src/types-taler-merchant.ts b/packages/taler-util/src/types-taler-merchant.ts @@ -2485,6 +2485,10 @@ export interface PostOrderResponse { // Order ID of the response that was just created. order_id: string; + // Deadline when the offer expires; the customer must pay before. + // @since protocol **v21**. + pay_deadline?: Timestamp; + // Token that authorizes the wallet to claim the order. // Provided only if "create_token" was set to 'true' // in the request. @@ -2614,9 +2618,13 @@ export interface CheckPaymentUnpaidResponse { // URI that the wallet must process to complete the payment. taler_pay_uri: string; - // when was the order created + // Time when the order was created. creation_time: Timestamp; + // Deadline when the offer expires; the customer must pay before. + // @since protocol **v21**. + pay_deadline: Timestamp; + // Order summary text. summary: string; @@ -3962,6 +3970,7 @@ export const codecForTax = (): Codec<Tax> => export const codecForPostOrderResponse = (): Codec<PostOrderResponse> => buildCodecForObject<PostOrderResponse>() .property("order_id", codecForString()) + .property("pay_deadline", codecOptional(codecForTimestamp)) .property("token", codecOptional(codecForString())) .build("TalerMerchantApi.PostOrderResponse"); @@ -4143,6 +4152,7 @@ export const codecForCheckPaymentUnpaidResponse = .property("order_status", codecForConstString("unpaid")) .property("taler_pay_uri", codecForTalerUriString()) .property("creation_time", codecForTimestamp) + .property("pay_deadline", codecForTimestamp) .property("summary", codecForString()) .property("total_amount", codecForAmountString()) .property("already_paid_order_id", codecOptional(codecForString())) @@ -4427,7 +4437,7 @@ export const codecForChallengeResponse = (): Codec<ChallengeResponse> => export interface ChallengeRequestResponse { // FIXME: this response fields are mandatory but - // put it optional from the client side to + // put it optional from the client side to // handle server that doesn't support this response. // Remove it when all server has been upgraded