commit 9b6c06f2a010725d04b2114c11cc384442cf0782
parent 326d942d9634ee5f2a7b7874be06bc6c8ece167a
Author: Sebastian <sebasjm@gmail.com>
Date: Thu, 9 Oct 2025 16:10:47 -0300
add paydeadline
Diffstat:
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