taler-typescript-core

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

commit a6bfddd10e1b1a8505a9e2b8ee46e1b7e194ded3
parent b1c90808839c69194d98e7ca4ea9edd14800ac4d
Author: Sebastian <sebasjm@taler-systems.com>
Date:   Thu, 15 Jan 2026 11:26:23 -0300

grouping payment cut-off times

Diffstat:
Mpackages/merchant-backoffice-ui/src/components/form/InputDate.tsx | 5+++--
Mpackages/merchant-backoffice-ui/src/components/instance/DefaultInstanceFormFields.tsx | 122+++++++++++++++++++++++++++++++++++++++++--------------------------------------
Mpackages/merchant-backoffice-ui/src/hooks/instance.ts | 3++-
Mpackages/merchant-backoffice-ui/src/hooks/order.ts | 3++-
Mpackages/merchant-backoffice-ui/src/paths/admin/create/CreatePage.tsx | 4++--
Mpackages/merchant-backoffice-ui/src/paths/instance/orders/details/DetailPage.tsx | 24++++++++++++------------
Mpackages/taler-util/src/http-client/merchant.ts | 2+-
7 files changed, 86 insertions(+), 77 deletions(-)

diff --git a/packages/merchant-backoffice-ui/src/components/form/InputDate.tsx b/packages/merchant-backoffice-ui/src/components/form/InputDate.tsx @@ -26,6 +26,7 @@ import { DatePicker } from "../picker/DatePicker.js"; import { InputProps, useField } from "./useField.js"; import { dateFormatForSettings, + datetimeFormatForSettings, usePreference, } from "../../hooks/preference.js"; @@ -60,14 +61,14 @@ export function InputDate<T>({ if (!value) { strValue = withTimestampSupport ? "unknown" : ""; } else if (value instanceof Date) { - strValue = format(value, dateFormatForSettings(settings)); + strValue = format(value, datetimeFormatForSettings(settings)); } else if (value.t_s) { strValue = value.t_s === "never" ? withTimestampSupport ? i18n.str`Never` : "" - : format(new Date(value.t_s * 1000), dateFormatForSettings(settings)); + : format(new Date(value.t_s * 1000), datetimeFormatForSettings(settings)); } return ( diff --git a/packages/merchant-backoffice-ui/src/components/instance/DefaultInstanceFormFields.tsx b/packages/merchant-backoffice-ui/src/components/instance/DefaultInstanceFormFields.tsx @@ -104,69 +104,75 @@ export function DefaultInstanceFormFields({ <InputLocation name="jurisdiction" /> </InputGroup> + <InputGroup label={i18n.str`Default cut-off times`} tooltip={i18n.str`These will be the values are going to be used if are not overriden in the order creation.`} name="" > + + <InputDuration<Entity> + name="default_pay_delay" + label={i18n.str`Payment delay`} + tooltip={i18n.str`Time customers have to pay an order before the offer expires by default.`} + useProtocolDuration + /> + + <InputDuration<Entity> + name="default_refund_delay" + label={i18n.str`Refund delay`} + tooltip={i18n.str`Time merchants have to refund an order.`} + useProtocolDuration + /> + + <InputDuration<Entity> + name="default_wire_transfer_delay" + label={i18n.str`Wire transfer delay`} + tooltip={i18n.str`Maximum time an exchange is allowed to delay wiring funds to the merchant, enabling it to aggregate smaller payments into larger wire transfers and reducing wire fees.`} + useProtocolDuration + /> + + <InputSelector<Entity> + name="default_wire_transfer_rounding_interval" + label={i18n.str`Wire transfer rounding`} + tooltip={i18n.str`Interval to which wire deadlines should be rounded up to.`} + help={i18n.str`As an example if you set the interval to day the wire transfer deadline will be rounded to midnight.`} + values={[ + RoundingInterval.DAY, + RoundingInterval.WEEK, + RoundingInterval.SECOND, + RoundingInterval.HOUR, + RoundingInterval.MINUTE, + RoundingInterval.MONTH, + RoundingInterval.QUARTER, + RoundingInterval.YEAR, + RoundingInterval.NONE, + ]} + toStr={(v: RoundingInterval) => { + switch (v) { + case RoundingInterval.NONE: + return i18n.str`No rounding`; + case RoundingInterval.SECOND: + return i18n.str`To second`; + case RoundingInterval.MINUTE: + return i18n.str`To minute`; + case RoundingInterval.HOUR: + return i18n.str`To hour`; + case RoundingInterval.DAY: + return i18n.str`To day`; + case RoundingInterval.WEEK: + return i18n.str`To week`; + case RoundingInterval.MONTH: + return i18n.str`To month`; + case RoundingInterval.QUARTER: + return i18n.str`To quarter`; + case RoundingInterval.YEAR: + return i18n.str`To year`; + } + }} + /> + </InputGroup> + <InputToggle<Entity> name="use_stefan" label={i18n.str`Pay transaction fee`} tooltip={i18n.str`Cover the transaction cost or pass it on to the user.`} /> - - <InputDuration<Entity> - name="default_pay_delay" - label={i18n.str`Default payment delay`} - tooltip={i18n.str`Time customers have to pay an order before the offer expires by default.`} - /> - - <InputDuration<Entity> - name="default_refund_delay" - label={i18n.str`Default refund delay`} - tooltip={i18n.str`Time merchants have to refund an order.`} - /> - - <InputDuration<Entity> - name="default_wire_transfer_delay" - label={i18n.str`Default wire transfer delay`} - tooltip={i18n.str`Maximum time an exchange is allowed to delay wiring funds to the merchant, enabling it to aggregate smaller payments into larger wire transfers and reducing wire fees.`} - /> - - <InputSelector<Entity> - name="default_wire_transfer_rounding_interval" - label={i18n.str`Default wire transfer rounding interval`} - tooltip={i18n.str`Interval to which wire deadlines should be rounded up to.`} - help={i18n.str`As an example if you set the interval to day the wire transfer deadline will be rounded to midnight.`} - values={[ - RoundingInterval.DAY, - RoundingInterval.WEEK, - RoundingInterval.SECOND, - RoundingInterval.HOUR, - RoundingInterval.MINUTE, - RoundingInterval.MONTH, - RoundingInterval.QUARTER, - RoundingInterval.YEAR, - RoundingInterval.NONE, - ]} - toStr={(v: RoundingInterval) => { - switch (v) { - case RoundingInterval.NONE: - return i18n.str`No rounding`; - case RoundingInterval.SECOND: - return i18n.str`To second`; - case RoundingInterval.MINUTE: - return i18n.str`To minute`; - case RoundingInterval.HOUR: - return i18n.str`To hour`; - case RoundingInterval.DAY: - return i18n.str`To day`; - case RoundingInterval.WEEK: - return i18n.str`To week`; - case RoundingInterval.MONTH: - return i18n.str`To month`; - case RoundingInterval.QUARTER: - return i18n.str`To quarter`; - case RoundingInterval.YEAR: - return i18n.str`To year`; - } - }} - /> </FragmentPersonaFlag> </Fragment> ); diff --git a/packages/merchant-backoffice-ui/src/hooks/instance.ts b/packages/merchant-backoffice-ui/src/hooks/instance.ts @@ -22,6 +22,7 @@ import { KycStatusLongPollingReason, MerchantAccountKycRedirect, MerchantAccountKycStatus, + opEmptySuccess, TalerHttpError, TalerMerchantManagementResultByMethod, } from "@gnu-taler/taler-util"; @@ -150,7 +151,7 @@ export function useInstanceKYCDetailsLongPolling() { const token = state.token; const fetcher = useMemo(() => { - if (!token) throw Error("should login first"); // unreachable + if (!token) return async () => undefined return async () => { const DEFAULT_WAIT = 5000; const now = new Date().getTime(); diff --git a/packages/merchant-backoffice-ui/src/hooks/order.ts b/packages/merchant-backoffice-ui/src/hooks/order.ts @@ -21,6 +21,7 @@ import { AccessToken, HttpStatusCode, MerchantOrderStatusResponse, + opEmptySuccess, OperationFail, OperationOk, TalerErrorCode, @@ -67,7 +68,7 @@ export function useWaitForOrderPayment( const token = state.status === "loggedIn" ? state.token : undefined; const evictWhenPaid = useMemo(() => { - if (!token) throw Error("should login first"); // unreachable + if (!token) return async () => undefined return async () => { const DEFAULT_WAIT = 5000; const now = new Date().getTime(); diff --git a/packages/merchant-backoffice-ui/src/paths/admin/create/CreatePage.tsx b/packages/merchant-backoffice-ui/src/paths/admin/create/CreatePage.tsx @@ -164,7 +164,7 @@ export function CreatePage({ onConfirm, onBack, forceId }: Props): VNode { }; const create = safeFunctionHandler( async ( - token: AccessToken, + token: AccessToken | undefined, data: TalerMerchantApi.InstanceConfigurationMessage, challengeIds: string[], ) => { @@ -189,7 +189,7 @@ export function CreatePage({ onConfirm, onBack, forceId }: Props): VNode { } return opEmptySuccess(); }, - !session.token || hasErrors ? undefined : [session.token, data, []], + hasErrors ? undefined : [session.token, data, []], ); create.onSuccess = (success, oldtoken, data) => { if (success) { diff --git a/packages/merchant-backoffice-ui/src/paths/instance/orders/details/DetailPage.tsx b/packages/merchant-backoffice-ui/src/paths/instance/orders/details/DetailPage.tsx @@ -127,18 +127,18 @@ function ContractTerms_V0({ value }: { value: CT0 }) { /> <InputDate<CT0> readonly - name="refund_deadline" - label={i18n.str`Refund deadline`} - tooltip={i18n.str`After this deadline has passed, no refunds will be accepted.`} - /> - <InputDate<CT0> - readonly name="pay_deadline" label={i18n.str`Payment deadline`} tooltip={i18n.str`After this deadline, the merchant won't accept payments for the contract`} /> <InputDate<CT0> readonly + name="refund_deadline" + label={i18n.str`Refund deadline`} + tooltip={i18n.str`After this deadline has passed, no refunds will be accepted.`} + /> + <InputDate<CT0> + readonly name="wire_transfer_deadline" label={i18n.str`Wire transfer deadline`} tooltip={i18n.str`Transfer deadline for the exchange`} @@ -213,18 +213,18 @@ function ContractTerms_V1({ value }: { value: CT1 }) { /> <InputDate<CT1> readonly - name="refund_deadline" - label={i18n.str`Refund deadline`} - tooltip={i18n.str`After this deadline has passed, no refunds will be accepted.`} - /> - <InputDate<CT1> - readonly name="pay_deadline" label={i18n.str`Payment deadline`} tooltip={i18n.str`After this deadline, the merchant won't accept payments for the contract`} /> <InputDate<CT1> readonly + name="refund_deadline" + label={i18n.str`Refund deadline`} + tooltip={i18n.str`After this deadline has passed, no refunds will be accepted.`} + /> + <InputDate<CT1> + readonly name="wire_transfer_deadline" label={i18n.str`Wire transfer deadline`} tooltip={i18n.str`Transfer deadline for the exchange`} diff --git a/packages/taler-util/src/http-client/merchant.ts b/packages/taler-util/src/http-client/merchant.ts @@ -3344,7 +3344,7 @@ export class TalerMerchantManagementHttpClient extends TalerMerchantInstanceHttp * https://docs.taler.net/core/api-merchant.html#post--management-instances */ async createInstance( - token: AccessToken, + token: AccessToken | undefined, body: TalerMerchantApi.InstanceConfigurationMessage, params: { challengeIds?: string[];