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:
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[];