taler-typescript-core

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

commit f082dfd7ab4a90bf410bf973228892693f729a15
parent 8c142162591487ca02173c3b9c1ac62205b26e7e
Author: Sebastian <sebasjm@gmail.com>
Date:   Sun,  6 Jul 2025 00:30:49 -0300

fix #9511

Diffstat:
Mpackages/merchant-backoffice-ui/src/components/product/NonInventoryProductForm.tsx | 1+
Mpackages/merchant-backoffice-ui/src/components/product/ProductForm.tsx | 6++++++
Mpackages/merchant-backoffice-ui/src/components/product/ProductList.tsx | 4++--
Mpackages/merchant-backoffice-ui/src/paths/instance/orders/create/CreatePage.tsx | 1+
Mpackages/merchant-backoffice-ui/src/paths/instance/products/list/Table.tsx | 13+++++++++++++
Mpackages/taler-util/src/types-taler-merchant.ts | 94++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---
6 files changed, 114 insertions(+), 5 deletions(-)

diff --git a/packages/merchant-backoffice-ui/src/components/product/NonInventoryProductForm.tsx b/packages/merchant-backoffice-ui/src/components/product/NonInventoryProductForm.tsx @@ -51,6 +51,7 @@ export function NonInventoryProductFrom({ if (result) { setShowCreateProduct(false); return onAddProduct({ + product_name: result.product_name || "", quantity: result.quantity || 0, taxes: result.taxes || [], description: result.description || "", diff --git a/packages/merchant-backoffice-ui/src/components/product/ProductForm.tsx b/packages/merchant-backoffice-ui/src/components/product/ProductForm.tsx @@ -115,6 +115,7 @@ export function ProductForm({ onSubscribe, initial, alreadyExist }: Props) { const errors = undefinedIfEmpty({ product_id: !value.product_id ? i18n.str`Required` : undefined, + product_name: !value.product_name ? i18n.str`Required` : undefined, description: !value.description ? i18n.str`Required` : undefined, unit: !value.unit ? i18n.str`Required` : undefined, price: !value.price @@ -202,6 +203,11 @@ export function ProductForm({ onSubscribe, initial, alreadyExist }: Props) { tooltip={i18n.str`Illustration of the product for customers.`} /> <Input<Entity> + name="product_name" + label={i18n.str`Name`} + tooltip={i18n.str`Product name.`} + /> + <Input<Entity> name="description" inputType="multiline" label={i18n.str`Description`} diff --git a/packages/merchant-backoffice-ui/src/components/product/ProductList.tsx b/packages/merchant-backoffice-ui/src/components/product/ProductList.tsx @@ -37,7 +37,7 @@ export function ProductList({ list, actions = [] }: Props): VNode { <i18n.Translate>Image</i18n.Translate> </th> <th> - <i18n.Translate>Description</i18n.Translate> + <i18n.Translate>Name</i18n.Translate> </th> <th> <i18n.Translate>Quantity</i18n.Translate> @@ -71,7 +71,7 @@ export function ProductList({ list, actions = [] }: Props): VNode { src={entry.image ? entry.image : emptyImage} /> </td> - <td>{entry.description}</td> + <td>{entry.product_name}</td> <td> {entry.quantity === 0 ? "--" diff --git a/packages/merchant-backoffice-ui/src/paths/instance/orders/create/CreatePage.tsx b/packages/merchant-backoffice-ui/src/paths/instance/orders/create/CreatePage.tsx @@ -808,6 +808,7 @@ export function CreatePage({ function asProduct(p: ProductAndQuantity): TalerMerchantApi.Product { return { product_id: p.product.id, + product_name: p.product.product_name, image: p.product.image, price: p.product.price, unit: p.product.unit, diff --git a/packages/merchant-backoffice-ui/src/paths/instance/products/list/Table.tsx b/packages/merchant-backoffice-ui/src/paths/instance/products/list/Table.tsx @@ -152,6 +152,9 @@ function Table({ <i18n.Translate>Image</i18n.Translate> </th> <th> + <i18n.Translate>Name</i18n.Translate> + </th> + <th> <i18n.Translate>Description</i18n.Translate> </th> <th> @@ -223,6 +226,16 @@ function Table({ </td> <td class="has-tooltip-right" + data-tooltip={i.product_name} + onClick={() => + rowSelection !== i.id && rowSelectionHandler(i.id) + } + style={{ cursor: "pointer" }} + > + {i.product_name} + </td> + <td + class="has-tooltip-right" data-tooltip={i.description} onClick={() => rowSelection !== i.id && rowSelectionHandler(i.id) diff --git a/packages/taler-util/src/types-taler-merchant.ts b/packages/taler-util/src/types-taler-merchant.ts @@ -360,7 +360,11 @@ export interface AbortingCoin { coin_pub: EddsaPublicKeyString; // The amount to be refunded (matches the original contribution) - contribution: AmountString; + // @deprecated since **v18**. + /** + * @deprecated + */ + contribution?: AmountString; // URL of the exchange this coin was withdrawn from. exchange_url: string; @@ -1604,16 +1608,71 @@ export interface InstanceAuthConfigurationMessage { // "external": The mechant backend does not do // any authentication checks. Instead an API // gateway must do the authentication. - // "token": The merchant checks an auth token. + // "token": (deprecated) The merchant checks an auth token. // See "token" for details. + // Since **v19**: APIs use login tokens retrieved from the /private/token + // endpoint. + // See "password" for details. method: MerchantAuthMethod; - // For method "token", this field is mandatory. + // Deprecated: For method "token", this field is mandatory. // The token MUST begin with the string "secret-token:". // After the auth token has been set (with method "token"), // the value must be provided in a "Authorization: Bearer $token" // header. token?: AccessToken; + + // Since **v19**: For method "token", this field is mandatory. + // Authentication against the /private/token endpoint + // is done using basic authentication with the configured password + // in the "password" field. Tokens are passed to other endpoints for + // authorization using RFC 8959 bearer tokens. + password?: string; +} + +export type LoginTokenScope = + | "readonly" + | "write" + | "all" + | "order-simple" + | "order-pos" + | "order-mgmt" + | "order-full"; + +export interface LoginTokenRequest { + // Scope of the token (which kinds of operations it will allow) + scope: LoginTokenScope; + + // Server may impose its own upper bound + // on the token validity duration + duration?: RelativeTime; + + // Can this token be refreshed? + // Defaults to false. Deprecated since **v19**. + // Use ":refreshable" scope prefix instead. + refreshable?: boolean; +} + +export interface LoginTokenSuccessResponse { + // @deprecated since v19. See access_token + // token: string; + + // The login token that can be used to access resources + // that are in scope for some time. Must be prefixed + // with "Bearer " when used in the "Authorization" HTTP header. + // Will already begin with the RFC 8959 prefix. + // **Since v19** + access_token: AccessToken; + + // Scope of the token (which kinds of operations it will allow) + scope: LoginTokenScope; + + // Server may impose its own upper bound + // on the token validity duration + expiration: Timestamp; + + // Can this token be refreshed? + refreshable: boolean; } export interface InstanceReconfigurationMessage { @@ -2065,6 +2124,12 @@ export interface ProductAddDetail { // Product ID to use. product_id: string; + // Human-readable product name. + // Since API version **v20**. Optional only for + // backwards-compatibility, should be considered mandatory + // moving forward! + product_name: string; + // Human-readable product description. description: string; @@ -2109,6 +2174,12 @@ export interface ProductAddDetail { } export interface ProductPatchDetail { + // Human-readable product name. + // Since API version **v20**. Optional only for + // backwards-compatibility, should be considered mandatory + // moving forward! + product_name: string; + // Human-readable product description. description: string; @@ -2182,6 +2253,10 @@ export interface MerchantPosProductDetail { // A merchant-internal unique identifier for the product product_id?: string; + // Human-readable product name. + // Since API version **v20**. + product_name: string; + // A list of category IDs this product belongs to. // Typically, a product only belongs to one category, but more than one is supported. categories: number[]; @@ -2230,6 +2305,10 @@ export interface MerchantCategory { } export interface ProductDetail { + // Human-readable product name. + // Since API version **v20**. + product_name: string; + // Human-readable product description. description: string; @@ -3260,6 +3339,12 @@ export interface Product { // Merchant-internal identifier for the product. product_id?: string; + // Name of the product. + // Since API version **v20**. Optional only for + // backwards-compatibility, should be considered mandatory + // moving forward! + product_name: string; + // Human-readable product description. description: string; @@ -3731,6 +3816,7 @@ export const codecForMerchantPosProductDetail = buildCodecForObject<MerchantPosProductDetail>() .property("product_serial", codecForNumber()) .property("product_id", codecOptional(codecForString())) + .property("product_name", codecForString()) .property("categories", codecForList(codecForNumber())) .property("description", codecForString()) .property("description_i18n", codecForInternationalizedString()) @@ -3761,6 +3847,7 @@ export const codecForProductDetail = (): Codec<ProductDetail> => .property("description", codecForString()) .property("description_i18n", codecForInternationalizedString()) .property("unit", codecForString()) + .property("product_name", codecForString()) .property("price", codecForAmountString()) .property("image", codecForString()) .property("categories", codecForList(codecForNumber())) @@ -3919,6 +4006,7 @@ export const codecForOrderOutputTaxReceipt = (): Codec<OrderOutputTaxReceipt> => export const codecForProduct = (): Codec<Product> => buildCodecForObject<Product>() .property("product_id", codecOptional(codecForString())) + .property("product_name", codecForString()) .property("description", codecForString()) .property( "description_i18n",