taler-typescript-core

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

commit e2cee7a88fb22824eddab146aa462d9dd2dacea6
parent 9d6d313afb68bb4e22926a34867148f01001d923
Author: Sebastian <sebasjm@taler-systems.com>
Date:   Fri,  5 Dec 2025 10:38:25 -0300

fix #10725

Diffstat:
Mpackages/merchant-backoffice-ui/src/paths/instance/orders/details/DetailPage.tsx | 137+++++++++++++++++++++++++++++++++++++++++++++++--------------------------------
1 file changed, 82 insertions(+), 55 deletions(-)

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 @@ -32,7 +32,7 @@ import { import { useTranslationContext } from "@gnu-taler/web-util/browser"; import { format, formatDistance } from "date-fns"; import { Fragment, VNode, h } from "preact"; -import { useState } from "preact/hooks"; +import { useEffect, useState } from "preact/hooks"; import { FormProvider } from "../../../../components/form/FormProvider.js"; import { Input } from "../../../../components/form/Input.js"; import { InputCurrency } from "../../../../components/form/InputCurrency.js"; @@ -51,7 +51,6 @@ import { mergeRefunds } from "../../../../utils/amount.js"; import { RefundModal } from "../list/Table.js"; import { Event, Timeline } from "./Timeline.js"; - const TALER_SCREEN_ID = 44; type Entity = TalerMerchantApi.MerchantOrderStatusResponse; @@ -74,15 +73,15 @@ type Claimed = TalerMerchantApi.CheckPaymentClaimedResponse; function ContractTerms({ value }: { value: CT }) { if (value.version === undefined) { - return <ContractTerms_V0 value={value} /> + return <ContractTerms_V0 value={value} />; } switch (value.version) { case MerchantContractVersion.V0: - return <ContractTerms_V0 value={value} /> + return <ContractTerms_V0 value={value} />; case MerchantContractVersion.V1: - return <ContractTerms_V1 value={value} /> + return <ContractTerms_V1 value={value} />; default: - assertUnreachable(value.version) + assertUnreachable(value.version); } } @@ -265,7 +264,6 @@ function ClaimedPage({ id: string; order: TalerMerchantApi.CheckPaymentClaimedResponse; }) { - const now = new Date(); const refundable = order.contract_terms.refund_deadline.t_s !== "never" && @@ -360,11 +358,11 @@ function ClaimedPage({ {order.contract_terms.timestamp.t_s === "never" ? i18n.str`Never` : format( - new Date( - order.contract_terms.timestamp.t_s * 1000, - ), - datetimeFormatForSettings(settings), - )} + new Date( + order.contract_terms.timestamp.t_s * 1000, + ), + datetimeFormatForSettings(settings), + )} </p> </div> </div> @@ -439,14 +437,34 @@ function PaidPage({ onRefund: (id: string) => void; }) { const { config } = useSessionContext(); + const [value, valueHandler] = useState<Partial<Paid>>(order); + const { state } = useSessionContext(); + const { i18n } = useTranslationContext(); const now = new Date(); - const refundable = + const merchantCanRefund = order.contract_terms.refund_deadline.t_s !== "never" && now.getTime() < order.contract_terms.refund_deadline.t_s * 1000; + const hasBeenWired = + order.contract_terms.wire_transfer_deadline.t_s !== "never" && + order.contract_terms.wire_transfer_deadline.t_s * 1000 < now.getTime(); + const [_, reload] = useState(false); + useEffect(() => { + if (hasBeenWired) return; + const deadline = order.contract_terms.wire_transfer_deadline; + if (deadline.t_s === "never") return; + const diff = deadline.t_s * 1000 - new Date().getTime(); + setTimeout(() => { + reload(true); + }, diff + 100); + }, []); + const events: Event[] = []; - if (order.contract_terms.refund_deadline.t_s !== "never" && refundable) { + if ( + order.contract_terms.refund_deadline.t_s !== "never" && + merchantCanRefund + ) { events.push({ when: new Date(order.contract_terms.refund_deadline.t_s * 1000), description: "refund deadline", @@ -481,26 +499,24 @@ function PaidPage({ } }); - const [value, valueHandler] = useState<Partial<Paid>>(order); - const { state } = useSessionContext(); - const { i18n } = useTranslationContext(); - - - const orderAmounts = getOrderAmountAndWirefee(order) + const orderAmounts = getOrderAmountAndWirefee(order); if (orderAmounts === "v1-without-index") { - return <i18n.Translate>The contract terms has a v1 order without choices_index.</i18n.Translate> + return ( + <i18n.Translate> + The contract terms has a v1 order without choices_index. + </i18n.Translate> + ); } if (orderAmounts === "v1-wrong-index") { - return <i18n.Translate>The contract terms has a v1 order with a bad choices_index.</i18n.Translate> - - } - const { amount, wireFee } = orderAmounts - if (order.contract_terms.version === MerchantContractVersion.V1) { - - order.choice_index + return ( + <i18n.Translate> + The contract terms has a v1 order with a bad choices_index. + </i18n.Translate> + ); } + const { amount, wireFee } = orderAmounts; const ra = !order.refunded ? undefined : Amounts.parse(order.refund_amount); - // const am = Amounts.parseOrThrow(order.contract_terms.amount); + if (ra && Amounts.cmp(ra, amount) === 1) { if (order.wire_details && order.wire_details.length) { if (order.wire_details.length > 1) { @@ -557,11 +573,13 @@ function PaidPage({ return e.when.getTime() > now.getTime(); }); - - const refundurl = stringifyRefundUri({ - merchantBaseUrl: state.backendUrl.href as HostPortPath, - orderId: order.contract_terms.order_id, - }); + const refundURI = + !order.refunded || hasBeenWired + ? undefined + : stringifyRefundUri({ + merchantBaseUrl: state.backendUrl.href as HostPortPath, + orderId: order.contract_terms.order_id, + }); const refund_taken = order.refund_details.reduce((prev, cur) => { if (cur.pending) return prev; @@ -610,14 +628,15 @@ function PaidPage({ <span class="has-tooltip-left" data-tooltip={ - refundable + merchantCanRefund ? i18n.str`Refund order` : i18n.str`Not refundable` } > - <button type="button" + <button + type="button" class="button is-danger" - disabled={!refundable} + disabled={!merchantCanRefund} onClick={() => onRefund(id)} > <i18n.Translate>Refund</i18n.Translate> @@ -705,13 +724,13 @@ function PaidPage({ {order.order_status_url} </a> </TextField> - {order.refunded && ( + {refundURI && ( <TextField<Paid> name="order_status_url" label={i18n.str`Refund URI`} > - <a target="_blank" rel="noreferrer" href={refundurl}> - {refundurl} + <a target="_blank" rel="noreferrer" href={refundURI}> + {refundURI} </a> </TextField> )} @@ -797,9 +816,9 @@ function UnpaidPage({ {order.creation_time.t_s === "never" ? i18n.str`Never` : format( - new Date(order.creation_time.t_s * 1000), - datetimeFormatForSettings(settings), - )} + new Date(order.creation_time.t_s * 1000), + datetimeFormatForSettings(settings), + )} </p> </div> </div> @@ -903,19 +922,27 @@ export function DetailPage({ id, selected, onRefunded, onBack }: Props): VNode { </Fragment> ); } -export function getOrderAmountAndWirefee(order: TalerMerchantApi.CheckPaymentPaidResponse | TalerMerchantApi.CheckPaymentPaidResponse) { - if (order.contract_terms.version === undefined || order.contract_terms.version === MerchantContractVersion.V0) { - const amount = Amounts.parseOrThrow(order.contract_terms.amount) - const wireFee = Amounts.parseOrThrow(order.contract_terms.wire_method) - return { amount, wireFee } +export function getOrderAmountAndWirefee( + order: + | TalerMerchantApi.CheckPaymentPaidResponse + | TalerMerchantApi.CheckPaymentPaidResponse, +) { + if ( + order.contract_terms.version === undefined || + order.contract_terms.version === MerchantContractVersion.V0 + ) { + const amount = Amounts.parseOrThrow(order.contract_terms.amount); + const wireFee = Amounts.parseOrThrow(order.contract_terms.max_fee); + return { amount, wireFee }; } if (order.contract_terms.version === MerchantContractVersion.V1) { - if (order.choice_index === undefined) return "v1-without-index" as const - if (order.choice_index > order.contract_terms.choices.length) return "v1-wrong-index" as const - const choice = order.contract_terms.choices[order.choice_index] - const amount = Amounts.parseOrThrow(choice.amount) - const wireFee = Amounts.parseOrThrow(choice.max_fee) - return { amount, wireFee } + if (order.choice_index === undefined) return "v1-without-index" as const; + if (order.choice_index > order.contract_terms.choices.length) + return "v1-wrong-index" as const; + const choice = order.contract_terms.choices[order.choice_index]; + const amount = Amounts.parseOrThrow(choice.amount); + const wireFee = Amounts.parseOrThrow(choice.max_fee); + return { amount, wireFee }; } - assertUnreachable(order.contract_terms.version) + assertUnreachable(order.contract_terms.version); }