[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[taler-wallet-core] 01/02: implement merchant v16
From: |
gnunet |
Subject: |
[taler-wallet-core] 01/02: implement merchant v16 |
Date: |
Thu, 01 Aug 2024 17:17:22 +0200 |
This is an automated email from the git hooks/post-receive script.
sebasjm pushed a commit to branch master
in repository wallet-core.
commit 24c6d46d34de6b42fe6434d0a5ab4f405c86f27d
Author: Sebastian <sebasjm@gmail.com>
AuthorDate: Thu Aug 1 12:16:34 2024 -0300
implement merchant v16
---
packages/taler-util/src/http-client/merchant.ts | 177 +++++++++++++++++++++++-
packages/taler-util/src/types-taler-merchant.ts | 117 ++++++++++++++--
2 files changed, 283 insertions(+), 11 deletions(-)
diff --git a/packages/taler-util/src/http-client/merchant.ts
b/packages/taler-util/src/http-client/merchant.ts
index 1b2d39dcc..3260c1546 100644
--- a/packages/taler-util/src/http-client/merchant.ts
+++ b/packages/taler-util/src/http-client/merchant.ts
@@ -32,6 +32,8 @@ import {
codecForAccountKycRedirects,
codecForAccountsSummaryResponse,
codecForBankAccountDetail,
+ codecForCategoryListResponse,
+ codecForCategoryProductList,
codecForClaimResponse,
codecForInstancesResponse,
codecForInventorySummaryResponse,
@@ -99,6 +101,9 @@ export enum TalerMerchantInstanceCacheEviction {
CREATE_PRODUCT,
UPDATE_PRODUCT,
DELETE_PRODUCT,
+ CREATE_CATEGORY,
+ UPDATE_CATEGORY,
+ DELETE_CATEGORY,
CREATE_TRANSFER,
DELETE_TRANSFER,
CREATE_DEVICE,
@@ -132,7 +137,7 @@ export enum TalerMerchantManagementCacheEviction {
* Uses libtool's current:revision:age versioning.
*/
export class TalerMerchantInstanceHttpClient {
- public readonly PROTOCOL_VERSION = "15:0:0";
+ public readonly PROTOCOL_VERSION = "16:0:0";
readonly httpLib: HttpRequestLibrary;
readonly cacheEvictor: CacheEvictor<TalerMerchantInstanceCacheEviction>;
@@ -792,6 +797,172 @@ export class TalerMerchantInstanceHttpClient {
// Inventory Management
//
+ /**
+ *
https://docs.taler.net/core/api-merchant.html#get-[-instances-$INSTANCE]-private-categories
+ */
+ async listCategories(token: AccessToken, params?: PaginationParams) {
+ const url = new URL(`private/categories`, this.baseUrl);
+
+ // addMerchantPaginationParams(url, params);
+
+ const headers: Record<string, string> = {};
+ if (token) {
+ headers.Authorization = makeBearerTokenAuthHeader(token);
+ }
+ const resp = await this.httpLib.fetch(url.href, {
+ method: "GET",
+ headers,
+ });
+
+ switch (resp.status) {
+ case HttpStatusCode.Ok:
+ return opSuccessFromHttp(resp, codecForCategoryListResponse());
+ case HttpStatusCode.NotFound:
+ return opKnownHttpFailure(resp.status, resp);
+ case HttpStatusCode.Unauthorized: // FIXME: missing in docs
+ return opKnownHttpFailure(resp.status, resp);
+ default:
+ return opUnknownFailure(resp, await readTalerErrorResponse(resp));
+ }
+ }
+
+ /**
+ *
https://docs.taler.net/core/api-merchant.html#get-[-instances-$INSTANCE]-private-categories-$CATEGORY_ID
+ */
+ async getCategoryDetails(token: AccessToken | undefined, cId: string) {
+ const url = new URL(`private/categories/${cId}`, this.baseUrl);
+
+ const headers: Record<string, string> = {};
+ if (token) {
+ headers.Authorization = makeBearerTokenAuthHeader(token);
+ }
+ const resp = await this.httpLib.fetch(url.href, {
+ method: "GET",
+ headers,
+ });
+
+ switch (resp.status) {
+ case HttpStatusCode.Ok:
+ return opSuccessFromHttp(resp, codecForCategoryProductList());
+ case HttpStatusCode.Unauthorized: // FIXME: missing in docs
+ return opKnownHttpFailure(resp.status, resp);
+ case HttpStatusCode.NotFound:
+ return opKnownHttpFailure(resp.status, resp);
+ default:
+ return opUnknownFailure(resp, await readTalerErrorResponse(resp));
+ }
+ }
+
+ /**
+ *
https://docs.taler.net/core/api-merchant.html#post-[-instances-$INSTANCE]-private-categories
+ */
+ async addCategory(
+ token: AccessToken | undefined,
+ body: TalerMerchantApi.CategoryCreateRequest,
+ ) {
+ const url = new URL(`private/categories`, this.baseUrl);
+
+ const headers: Record<string, string> = {};
+ if (token) {
+ headers.Authorization = makeBearerTokenAuthHeader(token);
+ }
+ const resp = await this.httpLib.fetch(url.href, {
+ method: "POST",
+ body,
+ headers,
+ });
+
+ switch (resp.status) {
+ case HttpStatusCode.Ok: {
+ this.cacheEvictor.notifySuccess(
+ TalerMerchantInstanceCacheEviction.CREATE_CATEGORY,
+ );
+ return opEmptySuccess(resp);
+ }
+ case HttpStatusCode.Unauthorized: // FIXME: missing in docs
+ return opKnownHttpFailure(resp.status, resp);
+ case HttpStatusCode.NotFound: // FIXME: missing in docs
+ return opKnownHttpFailure(resp.status, resp);
+ // case HttpStatusCode.Conflict:
+ // return opKnownHttpFailure(resp.status, resp);
+ default:
+ return opUnknownFailure(resp, await readTalerErrorResponse(resp));
+ }
+ }
+
+ /**
+ *
https://docs.taler.net/core/api-merchant.html#post-[-instances-$INSTANCE]-private-categories
+ */
+ async updateCategory(
+ token: AccessToken | undefined,
+ cid: string,
+ body: TalerMerchantApi.CategoryCreateRequest,
+ ) {
+ const url = new URL(`private/categories/${cid}`, this.baseUrl);
+
+ const headers: Record<string, string> = {};
+ if (token) {
+ headers.Authorization = makeBearerTokenAuthHeader(token);
+ }
+ const resp = await this.httpLib.fetch(url.href, {
+ method: "PATCH",
+ body,
+ headers,
+ });
+
+ switch (resp.status) {
+ case HttpStatusCode.NoContent: {
+ this.cacheEvictor.notifySuccess(
+ TalerMerchantInstanceCacheEviction.UPDATE_CATEGORY,
+ );
+ return opEmptySuccess(resp);
+ }
+ case HttpStatusCode.Unauthorized: // FIXME: missing in docs
+ return opKnownHttpFailure(resp.status, resp);
+ case HttpStatusCode.NotFound: // FIXME: missing in docs
+ return opKnownHttpFailure(resp.status, resp);
+ // case HttpStatusCode.Conflict:
+ // return opKnownHttpFailure(resp.status, resp);
+ default:
+ return opUnknownFailure(resp, await readTalerErrorResponse(resp));
+ }
+ }
+
+
+ /**
+ *
https://docs.taler.net/core/api-merchant.html#delete-[-instances-$INSTANCE]-private-categories-$CATEGORY_ID
+ */
+ async deleteCategory(token: AccessToken | undefined, cId: string) {
+ const url = new URL(`private/categories/${cId}`, this.baseUrl);
+
+ const headers: Record<string, string> = {};
+ if (token) {
+ headers.Authorization = makeBearerTokenAuthHeader(token);
+ }
+ const resp = await this.httpLib.fetch(url.href, {
+ method: "DELETE",
+ headers,
+ });
+
+ switch (resp.status) {
+ case HttpStatusCode.NoContent: {
+ this.cacheEvictor.notifySuccess(
+ TalerMerchantInstanceCacheEviction.DELETE_CATEGORY,
+ );
+ return opEmptySuccess(resp);
+ }
+ case HttpStatusCode.Unauthorized: // FIXME: missing in docs
+ return opKnownHttpFailure(resp.status, resp);
+ case HttpStatusCode.NotFound:
+ return opKnownHttpFailure(resp.status, resp);
+ // case HttpStatusCode.Conflict:
+ // return opKnownHttpFailure(resp.status, resp);
+ default:
+ return opUnknownFailure(resp, await readTalerErrorResponse(resp));
+ }
+ }
+
+
/**
*
https://docs.taler.net/core/api-merchant.html#post-[-instances-$INSTANCE]-private-products
*/
@@ -952,7 +1123,7 @@ export class TalerMerchantInstanceHttpClient {
}
/**
- * https://docs.taler.net/core/api-merchant.html#reserving-inventory
+ *
https://docs.taler.net/core/api-merchant.html#post-[-instances-$INSTANCE]-private-products-$PRODUCT_ID-lock
*/
async lockProduct(
token: AccessToken | undefined,
@@ -990,7 +1161,7 @@ export class TalerMerchantInstanceHttpClient {
}
/**
- *
https://docs.taler.net/core/api-merchant.html#removing-products-from-inventory
+ *
https://docs.taler.net/core/api-merchant.html#delete-[-instances-$INSTANCE]-private-products-$PRODUCT_ID
*/
async deleteProduct(token: AccessToken | undefined, productId: string) {
const url = new URL(`private/products/${productId}`, this.baseUrl);
diff --git a/packages/taler-util/src/types-taler-merchant.ts
b/packages/taler-util/src/types-taler-merchant.ts
index 33c383a95..38d17b8c0 100644
--- a/packages/taler-util/src/types-taler-merchant.ts
+++ b/packages/taler-util/src/types-taler-merchant.ts
@@ -1455,6 +1455,64 @@ export interface BankAccountDetail {
active?: boolean;
}
+export interface CategoryListResponse {
+ // Array with all of the categories we know.
+ categories: CategoryListEntry[];
+}
+
+export interface CategoryListEntry {
+ // Unique number for the category.
+ category_id: Integer;
+
+ // Name of the category.
+ name: string;
+
+ // Translations of the name into various
+ // languages.
+ name_i18n?: { [lang_tag: string]: string };
+
+ // Number of products in this category.
+ // A product can be in more than one category.
+ product_count: Integer;
+}
+
+export interface CategoryProductList {
+ // Name of the category.
+ name: string;
+
+ // Translations of the name into various
+ // languages.
+ name_i18n?: { [lang_tag: string]: string };
+
+ // The products in this category.
+ products: ProductSummary[];
+}
+
+export interface ProductSummary {
+ // Product ID to use.
+ product_id: string;
+
+ // Human-readable product description.
+ description: string;
+
+ // Map from IETF BCP 47 language tags to localized descriptions.
+ description_i18n?: { [lang_tag: string]: string };
+}
+
+export interface CategoryCreateRequest {
+ // Name of the category.
+ name: string;
+
+ // Translations of the name into various
+ // languages.
+ name_i18n?: { [lang_tag: string]: string };
+}
+
+export interface CategoryCreatedResponse {
+ // Number of the newly created category.
+ category_id: Integer;
+}
+
export interface ProductAddDetail {
// Product ID to use.
product_id: string;
@@ -1465,6 +1523,11 @@ export interface ProductAddDetail {
// Map from IETF BCP 47 language tags to localized descriptions.
description_i18n?: { [lang_tag: string]: string };
+ // Categories into which the product belongs.
+ // Used in the POS-endpoint.
+ // Since API version **v16**.
+ categories?: Integer[];
+
// Unit in which the product is measured (liters, kilograms, packages, etc.).
unit: string;
@@ -1504,6 +1567,11 @@ export interface ProductPatchDetail {
// Map from IETF BCP 47 language tags to localized descriptions.
description_i18n?: { [lang_tag: string]: string };
+ // Categories into which the product belongs.
+ // Used in the POS-endpoint.
+ // Since API version **v16**.
+ categories?: Integer[];
+
// Unit in which the product is measured (liters, kilograms, packages, etc.).
unit: string;
@@ -1623,6 +1691,10 @@ export interface ProductDetail {
// Unit in which the product is measured (liters, kilograms, packages, etc.).
unit: string;
+ // Categories into which the product belongs.
+ // Since API version **v16**.
+ categories: Integer[];
+
// The price for one unit of the product. Zero is used
// to imply that this product is not sold separately, or
// that the price is not fixed, and must be supplied by the
@@ -2734,14 +2806,15 @@ const codecForExchangeConfigInfo = ():
Codec<ExchangeConfigInfo> =>
.property("master_pub", codecForString())
.build("TalerMerchantApi.ExchangeConfigInfo");
-export const codecForTalerMerchantConfigResponse = ():
Codec<TalerMerchantConfigResponse> =>
- buildCodecForObject<TalerMerchantConfigResponse>()
- .property("name", codecForConstString("taler-merchant"))
- .property("currency", codecForString())
- .property("version", codecForString())
- .property("currencies", codecForMap(codecForCurrencySpecificiation()))
- .property("exchanges", codecForList(codecForExchangeConfigInfo()))
- .build("TalerMerchantApi.VersionResponse");
+export const codecForTalerMerchantConfigResponse =
+ (): Codec<TalerMerchantConfigResponse> =>
+ buildCodecForObject<TalerMerchantConfigResponse>()
+ .property("name", codecForConstString("taler-merchant"))
+ .property("currency", codecForString())
+ .property("version", codecForString())
+ .property("currencies", codecForMap(codecForCurrencySpecificiation()))
+ .property("exchanges", codecForList(codecForExchangeConfigInfo()))
+ .build("TalerMerchantApi.VersionResponse");
export const codecForClaimResponse = (): Codec<ClaimResponse> =>
buildCodecForObject<ClaimResponse>()
@@ -2941,6 +3014,33 @@ export const codecForBankAccountDetail = ():
Codec<BankAccountDetail> =>
.property("active", codecOptional(codecForBoolean()))
.build("TalerMerchantApi.BankAccountEntry");
+export const codecForCategoryListResponse = (): Codec<CategoryListResponse> =>
+ buildCodecForObject<CategoryListResponse>()
+ .property("categories", codecForList(codecForCategoryListEntry()))
+ .build("TalerMerchantApi.CategoryListResponse");
+
+export const codecForCategoryListEntry = (): Codec<CategoryListEntry> =>
+ buildCodecForObject<CategoryListEntry>()
+ .property("category_id", codecForNumber())
+ .property("name", codecForString())
+ .property("name_i18n", codecForInternationalizedString())
+ .property("product_count", codecForNumber())
+ .build("TalerMerchantApi.CategoryListEntry");
+
+export const codecForCategoryProductList = (): Codec<CategoryProductList> =>
+ buildCodecForObject<CategoryProductList>()
+ .property("name", codecForString())
+ .property("name_i18n", codecForInternationalizedString())
+ .property("products", codecForList(codecForProductSummary()))
+ .build("TalerMerchantApi.CategoryProductList");
+
+export const codecForProductSummary = (): Codec<ProductSummary> =>
+ buildCodecForObject<ProductSummary>()
+ .property("product_id", codecForString())
+ .property("description", codecForString())
+ .property("description_i18n", codecForInternationalizedString())
+ .build("TalerMerchantApi.ProductSummary");
+
export const codecForInventorySummaryResponse =
(): Codec<InventorySummaryResponse> =>
buildCodecForObject<InventorySummaryResponse>()
@@ -2990,6 +3090,7 @@ export const codecForProductDetail = ():
Codec<ProductDetail> =>
.property("unit", codecForString())
.property("price", codecForAmountString())
.property("image", codecForString())
+ .property("categories", codecForList(codecForNumber()))
.property("taxes", codecOptional(codecForList(codecForTax())))
.property("address", codecOptional(codecForLocation()))
.property("next_restock", codecOptional(codecForTimestamp))
--
To stop receiving notification emails like this one, please contact
gnunet@gnunet.org.