commit e256276effc7df369add3ca463c4d36921a5820e
parent 1c51dc52b0b4e9cecd208f2f596fa2eb6dc8e702
Author: Sebastian <sebasjm@gmail.com>
Date: Tue, 11 Nov 2025 16:54:39 -0300
merchant protocol v23
Diffstat:
9 files changed, 301 insertions(+), 145 deletions(-)
diff --git a/packages/aml-backoffice-ui/src/pages/AccountList.tsx b/packages/aml-backoffice-ui/src/pages/AccountList.tsx
@@ -20,9 +20,8 @@ import {
HttpStatusCode,
Paytos,
TalerError,
- TalerProtocolTimestamp,
assertUnreachable,
- opFixedSuccess,
+ opFixedSuccess
} from "@gnu-taler/taler-util";
import {
Attention,
@@ -39,12 +38,12 @@ import {
import { Fragment, VNode, h } from "preact";
import { useAmlAccounts } from "../hooks/decisions.js";
+import { format } from "date-fns";
import { useEffect, useState } from "preact/hooks";
-import { useOfficer } from "../hooks/officer.js";
-import { Profile } from "./Profile.js";
import csvIcon from "../assets/csv-icon.png";
import xlsIcon from "../assets/excel-icon.png";
-import { format } from "date-fns";
+import { useOfficer } from "../hooks/officer.js";
+import { Profile } from "./Profile.js";
export function AccountList({
routeToAccountById: caseByIdRoute,
diff --git a/packages/merchant-backoffice-ui/src/hooks/instance.ts b/packages/merchant-backoffice-ui/src/hooks/instance.ts
@@ -164,7 +164,7 @@ export function useInstanceKYCDetailsLongPolling() {
}
}
latestRequestTime = new Date().getTime();
- return lib.instance.getCurrentInstanceKycStatus(state.token, {
+ return lib.instance.getCurrentInstanceKycStatus(token, {
timeout: DEFAULT_WAIT,
reason: latestReason,
});
diff --git a/packages/merchant-backoffice-ui/src/hooks/order.test.ts b/packages/merchant-backoffice-ui/src/hooks/order.test.ts
@@ -19,7 +19,11 @@
* @author Sebastian Javier Marchano (sebasjm)
*/
-import { AbsoluteTime, AmountString, TalerMerchantApi } from "@gnu-taler/taler-util";
+import {
+ AbsoluteTime,
+ AmountString,
+ TalerMerchantApi,
+} from "@gnu-taler/taler-util";
import * as tests from "@gnu-taler/web-util/testing";
import { expect } from "chai";
import { useInstanceOrders, useOrderDetails } from "./order.js";
@@ -41,7 +45,10 @@ describe("order api interaction with listing", () => {
env.addRequestExpectation(API_LIST_ORDERS, {
qparam: { delta: -20, paid: "yes" },
response: {
- orders: [{ order_id: "1" }, { order_id: "2" } as TalerMerchantApi.OrderHistoryEntry],
+ orders: [
+ { order_id: "1" },
+ { order_id: "2" } as TalerMerchantApi.OrderHistoryEntry,
+ ],
},
});
@@ -52,7 +59,7 @@ describe("order api interaction with listing", () => {
const hookBehavior = await tests.hookBehaveLikeThis(
() => {
const query = useInstanceOrders({ paid: true }, newDate);
- const { lib: api } = useMerchantApiContext()
+ const { lib: api } = useMerchantApiContext();
return { query, api };
},
{},
@@ -74,21 +81,25 @@ describe("order api interaction with listing", () => {
env.addRequestExpectation(API_CREATE_ORDER, {
request: {
order: { amount: "ARS:12" as AmountString, summary: "pay me" },
- lock_uuids: []
+ lock_uuids: [],
},
- response: { order_id: "3" },
+ response: { order_id: "3", pay_deadline: { t_s: "never" } },
});
env.addRequestExpectation(API_LIST_ORDERS, {
qparam: { delta: -20, paid: "yes" },
response: {
- orders: [{ order_id: "1" }, { order_id: "2" } as any, { order_id: "3" } as any],
+ orders: [
+ { order_id: "1" },
+ { order_id: "2" } as any,
+ { order_id: "3" } as any,
+ ],
},
});
api.instance.createOrder(undefined, {
order: { amount: "ARS:12" as AmountString, summary: "pay me" },
- })
+ });
},
({ query, api }) => {
expect(env.assertJustExpectedRequestWereMade()).deep.eq({
@@ -115,11 +126,13 @@ describe("order api interaction with listing", () => {
env.addRequestExpectation(API_LIST_ORDERS, {
qparam: { delta: -20, paid: "yes" },
response: {
- orders: [{
- order_id: "1",
- amount: "EUR:12",
- refundable: true,
- } as TalerMerchantApi.OrderHistoryEntry]
+ orders: [
+ {
+ order_id: "1",
+ amount: "EUR:12",
+ refundable: true,
+ } as TalerMerchantApi.OrderHistoryEntry,
+ ],
},
});
@@ -130,7 +143,7 @@ describe("order api interaction with listing", () => {
const hookBehavior = await tests.hookBehaveLikeThis(
() => {
const query = useInstanceOrders({ paid: true }, newDate);
- const { lib: api } = useMerchantApiContext()
+ const { lib: api } = useMerchantApiContext();
return { query, api };
},
{},
@@ -167,14 +180,14 @@ describe("order api interaction with listing", () => {
response: {
orders: [
{ order_id: "1", amount: "EUR:12", refundable: false } as any,
- ]
+ ],
},
});
api.instance.addRefund(undefined, "1", {
reason: "double pay",
refund: "EUR:1" as AmountString,
- })
+ });
},
({ query, api }) => {
expect(env.assertJustExpectedRequestWereMade()).deep.eq({
@@ -208,7 +221,10 @@ describe("order api interaction with listing", () => {
env.addRequestExpectation(API_LIST_ORDERS, {
qparam: { delta: -20, paid: "yes" },
response: {
- orders: [{ order_id: "1" }, { order_id: "2" } as TalerMerchantApi.OrderHistoryEntry],
+ orders: [
+ { order_id: "1" },
+ { order_id: "2" } as TalerMerchantApi.OrderHistoryEntry,
+ ],
},
});
@@ -219,7 +235,7 @@ describe("order api interaction with listing", () => {
const hookBehavior = await tests.hookBehaveLikeThis(
() => {
const query = useInstanceOrders({ paid: true }, newDate);
- const { lib: api } = useMerchantApiContext()
+ const { lib: api } = useMerchantApiContext();
return { query, api };
},
{},
@@ -247,7 +263,7 @@ describe("order api interaction with listing", () => {
},
});
- api.instance.deleteOrder(undefined, "1")
+ api.instance.deleteOrder(undefined, "1");
},
({ query, api }) => {
expect(env.assertJustExpectedRequestWereMade()).deep.eq({
@@ -283,7 +299,7 @@ describe("order api interaction with details", () => {
const hookBehavior = await tests.hookBehaveLikeThis(
() => {
const query = useOrderDetails("1");
- const { lib: api } = useMerchantApiContext()
+ const { lib: api } = useMerchantApiContext();
return { query, api };
},
{},
@@ -319,7 +335,7 @@ describe("order api interaction with details", () => {
api.instance.addRefund(undefined, "1", {
reason: "double pay",
refund: "EUR:1" as AmountString,
- })
+ });
},
({ query, api }) => {
expect(env.assertJustExpectedRequestWereMade()).deep.eq({
@@ -355,7 +371,7 @@ describe("order api interaction with details", () => {
const hookBehavior = await tests.hookBehaveLikeThis(
() => {
const query = useOrderDetails("1");
- const { lib: api } = useMerchantApiContext()
+ const { lib: api } = useMerchantApiContext();
return { query, api };
},
{},
@@ -388,7 +404,7 @@ describe("order api interaction with details", () => {
api.instance.forgetOrder(undefined, "1", {
fields: ["$.summary"],
- })
+ });
},
({ query, api }) => {
expect(env.assertJustExpectedRequestWereMade()).deep.eq({
@@ -433,8 +449,11 @@ describe("order listing pagination", () => {
const hookBehavior = await tests.hookBehaveLikeThis(
() => {
const date = new Date(12000);
- const query = useInstanceOrders({ wired: true, date: AbsoluteTime.fromMilliseconds(date.getTime()) }, newDate);
- const { lib: api } = useMerchantApiContext()
+ const query = useInstanceOrders(
+ { wired: true, date: AbsoluteTime.fromMilliseconds(date.getTime()) },
+ newDate,
+ );
+ const { lib: api } = useMerchantApiContext();
return { query, api };
},
{},
@@ -454,7 +473,6 @@ describe("order listing pagination", () => {
// });
// expect(query.isReachingEnd).true;
// expect(query.isReachingStart).true;
-
},
],
env.buildTestingContext(),
@@ -495,8 +513,11 @@ describe("order listing pagination", () => {
const hookBehavior = await tests.hookBehaveLikeThis(
() => {
const date = new Date(12000);
- const query = useInstanceOrders({ wired: true, date: AbsoluteTime.fromMilliseconds(date.getTime()) }, newDate);
- const { lib: api } = useMerchantApiContext()
+ const query = useInstanceOrders(
+ { wired: true, date: AbsoluteTime.fromMilliseconds(date.getTime()) },
+ newDate,
+ );
+ const { lib: api } = useMerchantApiContext();
return { query, api };
},
{},
diff --git a/packages/merchant-backoffice-ui/src/paths/admin/create/Create.stories.tsx b/packages/merchant-backoffice-ui/src/paths/admin/create/Create.stories.tsx
@@ -22,6 +22,7 @@
import { MerchantApiProviderTesting } from "@gnu-taler/web-util/browser";
import { FunctionalComponent, h } from "preact";
import { CreatePage as TestedComponent } from "./CreatePage.js";
+import { RoundingInterval } from "@gnu-taler/taler-util";
export default {
title: "Pages/Instance/Create",
@@ -53,6 +54,8 @@ function createExample<Props>(
num_fractional_trailing_zero_digits: 1,
}
},
+ default_wire_transfer_rounding_interval: RoundingInterval.NONE,
+ default_pay_delay: {d_us:"forever"},
have_donau: false,
mandatory_tan_channels: [],
payment_target_regex: "*",
diff --git a/packages/merchant-backoffice-ui/src/paths/admin/create/stories.tsx b/packages/merchant-backoffice-ui/src/paths/admin/create/stories.tsx
@@ -22,6 +22,7 @@
import { FunctionalComponent, h } from "preact";
import { CreatePage as TestedComponent } from "./CreatePage.js";
import { MerchantApiProviderTesting } from "@gnu-taler/web-util/browser";
+import { RoundingInterval } from "@gnu-taler/taler-util";
export default {
title: "Pages/Instance/Create",
@@ -45,20 +46,22 @@ function createExample<Props>(
currency: "ARS",
version: "1",
currencies: {
- "ASD": {
+ ASD: {
name: "testkudos",
alt_unit_names: {},
num_fractional_input_digits: 1,
num_fractional_normal_digits: 1,
num_fractional_trailing_zero_digits: 1,
- }
+ },
},
+ default_wire_transfer_rounding_interval: RoundingInterval.NONE,
+ default_pay_delay: { d_us: "forever" },
have_donau: false,
mandatory_tan_channels: [],
payment_target_regex: "*",
payment_target_types: "*",
exchanges: [],
- name: "taler-merchant"
+ name: "taler-merchant",
},
hints: [],
lib: {} as any,
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
@@ -92,6 +92,7 @@ export const PaidNotRefundable = createExample(TestedComponent, {
refund_pending: false,
wire_details: [],
wired: false,
+ last_payment: { t_s: "never" },
wire_reports: [],
},
});
@@ -115,6 +116,7 @@ export const PaidRefundable = createExample(TestedComponent, {
refund_details: [],
wire_reports: [],
refund_pending: false,
+ last_payment: { t_s: "never" },
wire_details: [],
wired: false,
},
diff --git a/packages/merchant-backoffice-ui/src/paths/instance/update/Update.stories.tsx b/packages/merchant-backoffice-ui/src/paths/instance/update/Update.stories.tsx
@@ -21,7 +21,7 @@
import { FunctionalComponent, h } from "preact";
import { UpdatePage as TestedComponent } from "./UpdatePage.js";
-import { MerchantAuthMethod } from "@gnu-taler/taler-util";
+import { MerchantAuthMethod, RoundingInterval } from "@gnu-taler/taler-util";
export default {
title: "Pages/Instance/Update",
@@ -54,6 +54,8 @@ export const Example = createExample(TestedComponent, {
default_wire_transfer_delay: {
d_us: 1000 * 1000, //one second
},
+ default_wire_transfer_rounding_interval: RoundingInterval.NONE,
+ default_refund_delay: { d_us: "forever" },
merchant_pub: "ASDWQEKASJDKSADJ",
},
});
diff --git a/packages/taler-util/src/http-client/merchant.ts b/packages/taler-util/src/http-client/merchant.ts
@@ -15,6 +15,7 @@
*/
import {
+ AbsoluteTime,
AccessToken,
CancellationToken,
ChallengeRequestResponse,
@@ -155,7 +156,7 @@ export enum TalerMerchantManagementCacheEviction {
* Uses libtool's current:revision:age versioning.
*/
export class TalerMerchantInstanceHttpClient {
- public static readonly PROTOCOL_VERSION = "22:0:4";
+ public static readonly PROTOCOL_VERSION = "23:0:0";
readonly httpLib: HttpRequestLibrary;
readonly cacheEvictor: CacheEvictor<TalerMerchantInstanceCacheEviction>;
@@ -1242,11 +1243,24 @@ export class TalerMerchantInstanceHttpClient {
*/
async listProducts(
token: AccessToken | undefined,
- params?: PaginationParams,
+ params: PaginationParams & {
+ category?: string;
+ name?: string;
+ description?: string;
+ } = {},
) {
const url = new URL(`private/products`, this.baseUrl);
addPaginationParams(url, params);
+ if (params.category) {
+ url.searchParams.set("category_filter", params.category);
+ }
+ if (params.name) {
+ url.searchParams.set("name_filter", params.name);
+ }
+ if (params.description) {
+ url.searchParams.set("description_filter", params.description);
+ }
const headers: Record<string, string> = {};
if (token) {
@@ -1457,8 +1471,9 @@ export class TalerMerchantInstanceHttpClient {
) {
const url = new URL(`private/orders`, this.baseUrl);
- if (params.date) {
- url.searchParams.set("date_s", String(params.date));
+ if (params.date && !AbsoluteTime.isNever(params.date)) {
+ const time = AbsoluteTime.toProtocolTimestamp(params.date)
+ url.searchParams.set("date_s", String(time.t_s));
}
if (params.fulfillmentUrl) {
url.searchParams.set("fulfillment_url", params.fulfillmentUrl);
@@ -1478,6 +1493,9 @@ export class TalerMerchantInstanceHttpClient {
if (params.wired !== undefined) {
url.searchParams.set("wired", params.wired ? "YES" : "NO");
}
+ if (params.summary) {
+ url.searchParams.set("summary_filter", params.summary);
+ }
addPaginationParams(url, params);
const headers: Record<string, string> = {};
diff --git a/packages/taler-util/src/types-taler-merchant.ts b/packages/taler-util/src/types-taler-merchant.ts
@@ -30,7 +30,9 @@ import {
import {
AccessToken,
AccountLimit,
+ BlindedDonationReceiptKeyPair,
DenomKeyType,
+ DonationRequestData,
ExchangeWireAccount,
ObjectCodec,
PaytoString,
@@ -85,6 +87,7 @@ import {
codecForInternationalizedString,
codecForURLString,
} from "./types-taler-common.js";
+import { PayWalletData } from "./types-taler-wallet.js";
/**
* Proposal returned from the contract URL.
@@ -144,11 +147,26 @@ export interface TokenUseSig {
}
export interface MerchantPayResponse {
- sig: string;
+ // Signature on TALER_PaymentResponsePS with the public
+ // key of the merchant instance.
+ sig: EddsaSignatureString;
+
+ // Text to be shown to the point-of-sale staff as a proof of
+ // payment.
pos_confirmation?: string;
+
+ // Signed tokens. Returned in the same order as the
+ // token envelopes were provided in the request. Specifically,
+ // the order will follow the order of the outputs from the
+ // contract terms, and then within each output follow the
+ // order in which the wallet_data contained the respective
+ // blinded envelopes. The donation tokens will be present
+ // at the offset matching the place where a donation receipt
+ // was indicated in the outputs array, and of course be skipped
+ // if the PayWalletData did not have a donau field.
+ // @since protocol **v21**
token_sigs?: SignedTokenEnvelope[];
}
-
interface MerchantOrderStatusPaid {
// Was the payment refunded (even partially, via refund or abort)?
refunded: boolean;
@@ -1242,7 +1260,11 @@ export interface MerchantVersionResponse {
// Optional, no restrictions are imposed if the field is
// absent.
// @since **v22**
- payment_target_regex: string;
+ // CAUTION: Likely to be removed/deprecated,
+ // as we'll want an array of restrictions with the
+ // same format as the exchange uses, as this allows
+ // proper i18n and spec/code reuse.
+ payment_target_regex?: string;
// Default wire transfer delay for new instances.
// This is the default to use for new instances, see the instance value for
@@ -1262,6 +1284,24 @@ export interface MerchantVersionResponse {
// the instance-specific default.
// @since **v22**
default_refund_delay?: RelativeTime;
+
+ // Default interval to which wire deadlines computed by
+ // adding the wire_transfer_delay on top of the refund
+ // deadline should be rounded up to.
+ // @since **v23**
+ default_wire_transfer_rounding_interval: RoundingInterval;
+}
+
+export enum RoundingInterval {
+ NONE = "none",
+ SECOND = "second",
+ MINUTE = "minute",
+ HOUR = "hour",
+ DAY = "day",
+ WEEK = "week",
+ MONTH = "month",
+ QUARTER = "quarter",
+ YEAR = "year",
}
export interface ExchangeConfigInfo {
@@ -1351,8 +1391,17 @@ export interface PaymentStatusRequestParams {
}
export enum KycStatusLongPollingReason {
+ /**
+ * Waiting for an account to receive the wire transfer
+ */
AUTH_TRANSFER = 1,
+ /**
+ * Waiting for an account on aml investigation to be completed
+ */
AML_INVESTIGATION = 2,
+ /**
+ * Waiting for an account to be ready to be used
+ */
TO_BE_OK = 3,
}
export interface GetKycStatusRequestParams {
@@ -1418,40 +1467,61 @@ export interface ListWireTransferRequestParams {
order?: "asc" | "dec";
}
export interface ListOrdersRequestParams {
- // If set to yes, only return paid orders, if no only
- // unpaid orders. Do not give (or use “all”) to see all
- // orders regardless of payment status.
+ /**
+ * If set to yes, only return paid orders, if no only
+ * unpaid orders. Do not give (or use “all”) to see all
+ * orders regardless of payment status.
+ */
paid?: boolean;
- // If set to yes, only return refunded orders, if no only
- // unrefunded orders. Do not give (or use “all”) to see
- // all orders regardless of refund status.
+ /**
+ * If set to yes, only return refunded orders, if no only
+ * unrefunded orders. Do not give (or use “all”) to see
+ * all orders regardless of refund status.
+ */
refunded?: boolean;
- // If set to yes, only return wired orders, if no only
- // orders with missing wire transfers. Do not give (or
- // use “all”) to see all orders regardless of wire transfer
- // status.
+ /**
+ * If set to yes, only return wired orders, if no only
+ * orders with missing wire transfers. Do not give (or
+ * use “all”) to see all orders regardless of wire transfer
+ * status.
+ */
wired?: boolean;
- // At most return the given number of results. Negative
- // for descending by row ID, positive for ascending by
- // row ID. Default is 20. Since protocol v12.
+ /**
+ * At most return the given number of results. Negative
+ * for descending by row ID, positive for ascending by
+ * row ID. Default is 20. Since protocol v12.
+ */
limit?: number;
- // Non-negative date in seconds after the UNIX Epoc, see delta
- // for its interpretation. If not specified, we default to the
- // oldest or most recent entry, depending on delta.
+ /**
+ * Non-negative date in seconds after the UNIX Epoc, see delta
+ * for its interpretation. If not specified, we default to the
+ * oldest or most recent entry, depending on delta.
+ */
date?: AbsoluteTime;
- // Starting product_serial_id for an iteration.
- // Since protocol v12.
+ /**
+ * Starting product_serial_id for an iteration.
+ * Since protocol v12.
+ */
offset?: string;
- // Timeout in milliseconds to wait for additional orders if the
- // answer would otherwise be negative (long polling). Only useful
- // if delta is positive. Note that the merchant MAY still return
- // a response that contains fewer than delta orders.
+ /**
+ * Timeout in milliseconds to wait for additional orders if the
+ * answer would otherwise be negative (long polling). Only useful
+ * if delta is positive. Note that the merchant MAY still return
+ * a response that contains fewer than delta orders.
+ */
timeout?: number;
- // Since protocol v6. Filters by session ID.
+ /**
+ * Filters by session ID.
+ */
sessionId?: string;
- // Since protocol v6. Filters by fulfillment URL.
+ /**
+ * Filters by fulfillment URL.
+ */
fulfillmentUrl?: string;
-
+ /**
+ * Only returns orders where the summary contains the given text as a substring. Matching is case-insensitive
+ */
+ summary?: string;
order?: "asc" | "dec";
}
@@ -1459,8 +1529,12 @@ export interface PayRequest {
// The coins used to make the payment.
coins: CoinPaySig[];
+ // Input tokens required by choice indicated by choice_index.
+ // @since protocol **v21**
+ tokens?: TokenUseSig[];
+
// Custom inputs from the wallet for the contract.
- wallet_data?: Object;
+ wallet_data?: PayWalletData;
// The session for which the payment is made (or replayed).
// Only set for session-based payments.
@@ -1659,15 +1733,32 @@ export interface InstanceConfigurationMessage {
// Can always be overridden by the frontend on a per-order basis.
use_stefan: boolean;
+ // If the frontend does NOT specify a payment deadline, how long should
+ // offers we make be valid by default?
+ // Optional @since **v22** (before the setting was mandatory).
+ // If not provided, the global merchant default will be used.
+ default_pay_delay?: RelativeTime;
+
+ // If the frontend does NOT specify a refund deadline, how long should
+ // refunds be allowed by default? Added on top of the
+ // payment deadline.
+ // @since **v22**
+ default_refund_delay?: RelativeTime;
+
// If the frontend does NOT specify an execution date, how long should
// we tell the exchange to wait to aggregate transactions before
- // executing the wire transfer? This delay is added to the current
- // time when we generate the advisory execution time for the exchange.
- default_wire_transfer_delay: RelativeTime;
+ // executing the wire transfer? This delay is added on top of
+ // the refund deadline and afterwards subject to rounding
+ // via the default_wire_transfer_rounding_interval.
+ // Optional @since **v22** (before the setting was mandatory).
+ // If not provided, the global merchant default will be used.
+ default_wire_transfer_delay?: RelativeTime;
- // If the frontend does NOT specify a payment deadline, how long should
- // offers we make be valid by default?
- default_pay_delay: RelativeTime;
+ // How far should the wire deadline (if computed with the help of
+ // the default_wire_transfer_delay) be rounded up to compute
+ // the ultimate wire deadline?
+ // @since **v22**, defaults to no rounding if not given.
+ default_wire_transfer_rounding_interval?: RoundingInterval;
}
export interface InstanceAuthConfigurationMessage {
@@ -1782,15 +1873,31 @@ export interface InstanceReconfigurationMessage {
// Can always be overridden by the frontend on a per-order basis.
use_stefan: boolean;
+ // If the frontend does NOT specify a payment deadline, how long should
+ // offers we make be valid by default?
+ // Optional @since **v22** (before the setting was mandatory).
+ // If not provided, the previous setting will now simply be preserved.
+ default_pay_delay?: RelativeTime;
+
+ // If the frontend does NOT specify a refund deadline, how long should
+ // refunds be allowed by default? Added on top of the payment deadline.
+ // @since **v22**
+ default_refund_delay?: RelativeTime;
+
// If the frontend does NOT specify an execution date, how long should
// we tell the exchange to wait to aggregate transactions before
- // executing the wire transfer? This delay is added to the current
- // time when we generate the advisory execution time for the exchange.
- default_wire_transfer_delay: RelativeTime;
+ // executing the wire transfer? This delay is added on top of
+ // the refund deadline and afterwards subject to rounding
+ // via the default_wire_transfer_rounding_interval.
+ // Optional @since **v22** (before the setting was mandatory).
+ // If not provided, the previous setting will now simply be preserved.
+ default_wire_transfer_delay?: RelativeTime;
- // If the frontend does NOT specify a payment deadline, how long should
- // offers we make be valid by default?
- default_pay_delay: RelativeTime;
+ // How far should the wire deadline (if computed with the help of
+ // the default_wire_transfer_delay) be rounded up to compute
+ // the ultimate wire deadline?
+ // @since **v22**, defaults to no rounding if not given.
+ default_wire_transfer_rounding_interval?: RoundingInterval;
}
export interface InstancesResponse {
@@ -1863,15 +1970,28 @@ export interface QueryInstancesResponse {
// Can always be overridden by the frontend on a per-order basis.
use_stefan: boolean;
+ // If the frontend does NOT specify a payment deadline, how long should
+ // offers we make be valid by default? Added to the order creation
+ // time.
+ default_pay_delay: RelativeTime;
+
+ // If the frontend does NOT specify a refund deadline, how long should
+ // refunds be allowed by default? Added to the payment deadline.
+ // @since **v22**
+ default_refund_delay: RelativeTime;
+
// If the frontend does NOT specify an execution date, how long should
// we tell the exchange to wait to aggregate transactions before
- // executing the wire transfer? This delay is added to the current
- // time when we generate the advisory execution time for the exchange.
+ // executing the wire transfer? This delay is added to the
+ // refund deadline and subject to rounding to the
+ // default_wire_transfer_rounding_interval.
default_wire_transfer_delay: RelativeTime;
- // If the frontend does NOT specify a payment deadline, how long should
- // offers we make be valid by default?
- default_pay_delay: RelativeTime;
+ // Default interval to which wire deadlines computed by
+ // adding the wire_transfer_delay on top of the refund
+ // deadline should be rounded up to.
+ // @since **v23**
+ default_wire_transfer_rounding_interval: RoundingInterval;
// Authentication configuration.
// Does not contain the token when token auth is configured.
@@ -2527,7 +2647,7 @@ export interface PostOrderResponse {
// Deadline when the offer expires; the customer must pay before.
// @since protocol **v21**.
- pay_deadline?: Timestamp;
+ pay_deadline: Timestamp;
// Token that authorizes the wallet to claim the order.
// Provided only if "create_token" was set to 'true'
@@ -2622,6 +2742,15 @@ export interface CheckPaymentPaidResponse {
// FIXME: support for contract v1
contract_terms: MerchantContractTerms;
+ // Index of the selected choice within the choices array of
+ // contract terms.
+ // @since protocol **v21**
+ choice_index?: Integer;
+
+ // If the order is paid, set to the last time when a payment
+ // was made to pay for this order. @since **v14**.
+ last_payment: Timestamp;
+
// The wire transfer status from the exchange for this order if
// available, otherwise empty array.
wire_details: TransactionWireTransfer[];
@@ -3182,6 +3311,14 @@ export interface TokenFamilySummary {
// Human-readable name for the token family.
name: string;
+ // Human-readable description for the token family.
+ // @since protocol **v23**.
+ description: string;
+
+ // Optional map from IETF BCP 47 language tags to localized descriptions.
+ // @since protocol **v23**.
+ description_i18n?: { [lang_tag: string]: string };
+
// Start time of the token family's validity period.
valid_after: Timestamp;
@@ -3427,11 +3564,11 @@ export interface OrderV0 extends OrderCommon {
export interface OrderV1 extends OrderCommon {
// Version 1 order support discounts and subscriptions.
// https://docs.taler.net/design-documents/046-mumimo-contracts.html
- // @since protocol **vSUBSCRIBE**
+ // @since protocol **v21**
version: OrderVersion.V1;
// List of contract choices that the customer can select from.
- // @since protocol **vSUBSCRIBE**
+ // @since protocol **v21**
choices?: OrderChoice[];
}
@@ -3629,60 +3766,6 @@ const codecForExchangeConfigInfo = (): Codec<ExchangeConfigInfo> =>
.property("master_pub", codecForEddsaPublicKey())
.build("TalerMerchantApi.ExchangeConfigInfo");
-// // Set when the merchant supports
-// // self-provisioning instances.
-// // Since protocol **v21**
-// have_self_provisioning: boolean;
-
-// // True if this merchant backend supports the Donau
-// // extension and can thus issue donation receipts.
-// // Should primarily be used to control the SPA's CRUD
-// // functionality for Donau.
-// // @since **v21**
-// have_donau: boolean;
-
-// // Tan channels that are required
-// // to be confirmed for an instance to
-// // be useable.
-// // @since **v21**
-// mandatory_tan_channels?: TanChannel[];
-
-// // Space-separated list of enabled payment target types.
-// // Useful if the SPA should not show allow adding other
-// // types of bank accounts. "*" is used to represent no
-// // restriction.
-// // @since **v22**
-// payment_target_types: string;
-
-// // Regular expression representing further restrictions
-// // on allowed payment targets. Any "payto://"-URI supplied
-// // for a bank account must match the given regular expression.
-// // For example, "payto://iban/CH.*" would restrict the system
-// // to only Swiss bank accounts.
-// // Optional, no restrictions are imposed if the field is
-// // absent.
-// // @since **v22**
-// payment_target_regex? string;
-
-// // Default wire transfer delay for new instances.
-// // This is the default to use for new instances, see the instance value for
-// // the instance-specific default.
-// // @since **v22**
-// default_wire_transfer_delay: RelativeTime;
-
-// // Default payment delay for new instances.
-// // This is the default to use for new instances, see the instance value for
-// // the instance-specific default.
-// // @since **v22**
-// default_pay_delay: RelativeTime;
-
-// // If the frontend does NOT specify a refund deadline, how long should
-// // refunds be allowed by default?
-// // This is the default to use for new instances, see the instance value for
-// // the instance-specific default.
-// // @since **v22**
-// default_refund_delay: RelativeTime;
-
export const codecForTalerMerchantConfigResponse =
(): Codec<MerchantVersionResponse> =>
buildCodecForObject<MerchantVersionResponse>()
@@ -3720,8 +3803,24 @@ export const codecForTalerMerchantConfigResponse =
"payment_target_types",
codecOptionalDefault(codecForString(), "*"),
)
+ .property(
+ "default_wire_transfer_rounding_interval",
+ codecForRoundingInterval,
+ )
.build("TalerMerchantApi.VersionResponse");
+export const codecForRoundingInterval = codecForEither(
+ codecForConstString(RoundingInterval.NONE),
+ codecForConstString(RoundingInterval.SECOND),
+ codecForConstString(RoundingInterval.MINUTE),
+ codecForConstString(RoundingInterval.HOUR),
+ codecForConstString(RoundingInterval.DAY),
+ codecForConstString(RoundingInterval.WEEK),
+ codecForConstString(RoundingInterval.MONTH),
+ codecForConstString(RoundingInterval.QUARTER),
+ codecForConstString(RoundingInterval.YEAR),
+);
+
export const codecForClaimResponse = (): Codec<ClaimResponse> =>
buildCodecForObject<ClaimResponse>()
// Must be 'any', otherwise, contract terms won't match.
@@ -3873,6 +3972,11 @@ export const codecForQueryInstancesResponse =
.property("use_stefan", codecForBoolean())
.property("default_wire_transfer_delay", codecForDuration)
.property("default_pay_delay", codecForDuration)
+ .property("default_refund_delay", codecForDuration)
+ .property(
+ "default_wire_transfer_rounding_interval",
+ codecForRoundingInterval,
+ )
.property(
"auth",
buildCodecForObject<{
@@ -4078,7 +4182,7 @@ export const codecForTax = (): Codec<Tax> =>
export const codecForPostOrderResponse = (): Codec<PostOrderResponse> =>
buildCodecForObject<PostOrderResponse>()
.property("order_id", codecForString())
- .property("pay_deadline", codecOptional(codecForTimestamp))
+ .property("pay_deadline", codecForTimestamp)
.property("token", codecOptional(codecForString()))
.build("TalerMerchantApi.PostOrderResponse");
@@ -4248,6 +4352,8 @@ export const codecForCheckPaymentPaidResponse =
.property("exchange_http_status", codecForNumber())
.property("refund_amount", codecForAmountString())
.property("contract_terms", codecForMerchantContractTerms())
+ .property("choice_index", codecOptional(codecForNumber()))
+ .property("last_payment", codecForTimestamp)
.property("wire_reports", codecForList(codecForTransactionWireReport()))
.property("wire_details", codecForList(codecForTransactionWireTransfer()))
.property("refund_details", codecForList(codecForRefundDetails()))
@@ -4459,6 +4565,8 @@ export const codecForTokenFamilySummary = (): Codec<TokenFamilySummary> =>
buildCodecForObject<TokenFamilySummary>()
.property("slug", codecForString())
.property("name", codecForString())
+ .property("description", codecForString())
+ .property("description_i18n", codecForInternationalizedString())
.property("valid_after", codecForTimestamp)
.property("valid_before", codecForTimestamp)
.property("kind", codecForTokenFamilyKind)