diff options
Diffstat (limited to 'packages/taler-util/src/http-client/merchant.ts')
-rw-r--r-- | packages/taler-util/src/http-client/merchant.ts | 2343 |
1 files changed, 2343 insertions, 0 deletions
diff --git a/packages/taler-util/src/http-client/merchant.ts b/packages/taler-util/src/http-client/merchant.ts new file mode 100644 index 000000000..d682dcfa0 --- /dev/null +++ b/packages/taler-util/src/http-client/merchant.ts @@ -0,0 +1,2343 @@ +/* + This file is part of GNU Taler + (C) 2022-2024 Taler Systems S.A. + + GNU Taler is free software; you can redistribute it and/or modify it under the + terms of the GNU General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along with + GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/> + */ + +import { + AccessToken, + FailCasesByMethod, + HttpStatusCode, + LibtoolVersion, + PaginationParams, + ResultByMethod, + TalerMerchantApi, + codecForAbortResponse, + codecForAccountAddResponse, + codecForAccountKycRedirects, + codecForAccountsSummaryResponse, + codecForBankAccountEntry, + codecForClaimResponse, + codecForInstancesResponse, + codecForInventorySummaryResponse, + codecForMerchantConfig, + codecForMerchantOrderPrivateStatusResponse, + codecForMerchantRefundResponse, + codecForOrderHistory, + codecForOtpDeviceDetails, + codecForOtpDeviceSummaryResponse, + codecForOutOfStockResponse, + codecForPaidRefundStatusResponse, + codecForPaymentResponse, + codecForPostOrderResponse, + codecForProductDetail, + codecForQueryInstancesResponse, + codecForStatusGoto, + codecForStatusPaid, + codecForStatusStatusUnpaid, + codecForTansferList, + codecForTemplateDetails, + codecForTemplateSummaryResponse, + codecForTokenFamiliesList, + codecForTokenFamilyDetails, + codecForWalletRefundResponse, + codecForWalletTemplateDetails, + codecForWebhookDetails, + codecForWebhookSummaryResponse, + opEmptySuccess, + opKnownAlternativeFailure, + opKnownHttpFailure, +} from "@gnu-taler/taler-util"; +import { + HttpRequestLibrary, + HttpResponse, + createPlatformHttpLib, + readTalerErrorResponse, +} from "@gnu-taler/taler-util/http"; +import { opSuccessFromHttp, opUnknownFailure } from "../operation.js"; +import { + CacheEvictor, + addMerchantPaginationParams, + makeBearerTokenAuthHeader, + nullEvictor, +} from "./utils.js"; + +export type TalerMerchantInstanceResultByMethod< + prop extends keyof TalerMerchantInstanceHttpClient, +> = ResultByMethod<TalerMerchantInstanceHttpClient, prop>; +export type TalerMerchantInstanceErrorsByMethod< + prop extends keyof TalerMerchantInstanceHttpClient, +> = FailCasesByMethod<TalerMerchantInstanceHttpClient, prop>; + +export enum TalerMerchantInstanceCacheEviction { + CREATE_ORDER, + UPDATE_ORDER, + DELETE_ORDER, + UPDATE_CURRENT_INSTANCE, + DELETE_CURRENT_INSTANCE, + CREATE_BANK_ACCOUNT, + UPDATE_BANK_ACCOUNT, + DELETE_BANK_ACCOUNT, + CREATE_PRODUCT, + UPDATE_PRODUCT, + DELETE_PRODUCT, + CREATE_TRANSFER, + DELETE_TRANSFER, + CREATE_DEVICE, + UPDATE_DEVICE, + DELETE_DEVICE, + CREATE_TEMPLATE, + UPDATE_TEMPLATE, + DELETE_TEMPLATE, + CREATE_WEBHOOK, + UPDATE_WEBHOOK, + DELETE_WEBHOOK, + CREATE_TOKENFAMILY, + UPDATE_TOKENFAMILY, + DELETE_TOKENFAMILY, + LAST, +} +export enum TalerMerchantManagementCacheEviction { + CREATE_INSTANCE = TalerMerchantInstanceCacheEviction.LAST + 1, + UPDATE_INSTANCE, + DELETE_INSTANCE, +} +/** + * Protocol version spoken with the core bank. + * + * Endpoint must be ordered in the same way that in the docs + * Response code (http and taler) must have the same order that in the docs + * That way is easier to see changes + * + * Uses libtool's current:revision:age versioning. + */ +export class TalerMerchantInstanceHttpClient { + public readonly PROTOCOL_VERSION = "10:0:6"; + + readonly httpLib: HttpRequestLibrary; + readonly cacheEvictor: CacheEvictor<TalerMerchantInstanceCacheEviction>; + + constructor( + readonly baseUrl: string, + httpClient?: HttpRequestLibrary, + cacheEvictor?: CacheEvictor<TalerMerchantInstanceCacheEviction>, + ) { + this.httpLib = httpClient ?? createPlatformHttpLib(); + this.cacheEvictor = cacheEvictor ?? nullEvictor; + } + + isCompatible(version: string): boolean { + const compare = LibtoolVersion.compare(this.PROTOCOL_VERSION, version); + return compare?.compatible ?? false; + } + + /** + * https://docs.taler.net/core/api-merchant.html#get--config + * + */ + async getConfig() { + const url = new URL(`config`, this.baseUrl); + + const resp = await this.httpLib.fetch(url.href, { + method: "GET", + }); + switch (resp.status) { + case HttpStatusCode.Ok: + return opSuccessFromHttp(resp, codecForMerchantConfig()); + case HttpStatusCode.NotFound: + return opKnownHttpFailure(resp.status, resp); + default: + return opUnknownFailure(resp, await readTalerErrorResponse(resp)); + } + } + + // + // Wallet API + // + + /** + * https://docs.taler.net/core/api-merchant.html#post-[-instances-$INSTANCE]-orders-$ORDER_ID-claim + */ + async claimOrder(orderId: string, body: TalerMerchantApi.ClaimRequest) { + const url = new URL(`orders/${orderId}/claim`, this.baseUrl); + + const resp = await this.httpLib.fetch(url.href, { + method: "POST", + body, + }); + + switch (resp.status) { + case HttpStatusCode.Ok: { + this.cacheEvictor.notifySuccess( + TalerMerchantInstanceCacheEviction.UPDATE_ORDER, + ); + return opSuccessFromHttp(resp, codecForClaimResponse()); + } + case HttpStatusCode.Conflict: + 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]-orders-$ORDER_ID-pay + */ + async makePayment(orderId: string, body: TalerMerchantApi.PayRequest) { + const url = new URL(`orders/${orderId}/pay`, this.baseUrl); + + const resp = await this.httpLib.fetch(url.href, { + method: "POST", + body, + }); + + switch (resp.status) { + case HttpStatusCode.Ok: { + this.cacheEvictor.notifySuccess( + TalerMerchantInstanceCacheEviction.UPDATE_ORDER, + ); + return opSuccessFromHttp(resp, codecForPaymentResponse()); + } + case HttpStatusCode.BadRequest: + return opKnownHttpFailure(resp.status, resp); + case HttpStatusCode.PaymentRequired: + return opKnownHttpFailure(resp.status, resp); + case HttpStatusCode.Forbidden: + return opKnownHttpFailure(resp.status, resp); + case HttpStatusCode.NotFound: + return opKnownHttpFailure(resp.status, resp); + case HttpStatusCode.RequestTimeout: + return opKnownHttpFailure(resp.status, resp); + case HttpStatusCode.Conflict: + return opKnownHttpFailure(resp.status, resp); + case HttpStatusCode.Gone: + return opKnownHttpFailure(resp.status, resp); + case HttpStatusCode.PreconditionFailed: + return opKnownHttpFailure(resp.status, resp); + case HttpStatusCode.BadGateway: + return opKnownHttpFailure(resp.status, resp); + case HttpStatusCode.GatewayTimeout: + return opKnownHttpFailure(resp.status, resp); + default: + return opUnknownFailure(resp, await readTalerErrorResponse(resp)); + } + } + + /** + * https://docs.taler.net/core/api-merchant.html#get-[-instances-$INSTANCE]-orders-$ORDER_ID + */ + + async getPaymentStatus( + orderId: string, + params: TalerMerchantApi.PaymentStatusRequestParams = {}, + ) { + const url = new URL(`orders/${orderId}`, this.baseUrl); + + if (params.allowRefundedForRepurchase !== undefined) { + url.searchParams.set( + "allow_refunded_for_repurchase", + params.allowRefundedForRepurchase ? "YES" : "NO", + ); + } + if (params.awaitRefundObtained !== undefined) { + url.searchParams.set( + "await_refund_obtained", + params.allowRefundedForRepurchase ? "YES" : "NO", + ); + } + if (params.claimToken !== undefined) { + url.searchParams.set("token", params.claimToken); + } + if (params.contractTermHash !== undefined) { + url.searchParams.set("h_contract", params.contractTermHash); + } + if (params.refund !== undefined) { + url.searchParams.set("refund", params.refund); + } + if (params.sessionId !== undefined) { + url.searchParams.set("session_id", params.sessionId); + } + if (params.timeout !== undefined) { + url.searchParams.set("timeout_ms", String(params.timeout)); + } + + const resp = await this.httpLib.fetch(url.href, { + method: "GET", + // body, + }); + + switch (resp.status) { + case HttpStatusCode.Ok: + return opSuccessFromHttp(resp, codecForStatusPaid()); + case HttpStatusCode.Accepted: + return opSuccessFromHttp(resp, codecForStatusGoto()); + // case HttpStatusCode.Found: not possible since content is not HTML + case HttpStatusCode.PaymentRequired: + return opSuccessFromHttp(resp, codecForStatusStatusUnpaid()); + case HttpStatusCode.Forbidden: + return opKnownHttpFailure(resp.status, resp); + case HttpStatusCode.NotFound: + return opKnownHttpFailure(resp.status, resp); + case HttpStatusCode.NotAcceptable: + return opKnownHttpFailure(resp.status, resp); + default: + return opUnknownFailure(resp, await readTalerErrorResponse(resp)); + } + } + + /** + * https://docs.taler.net/core/api-merchant.html#demonstrating-payment + */ + async demostratePayment(orderId: string, body: TalerMerchantApi.PaidRequest) { + const url = new URL(`orders/${orderId}/paid`, this.baseUrl); + + const resp = await this.httpLib.fetch(url.href, { + method: "POST", + body, + }); + + switch (resp.status) { + case HttpStatusCode.Ok: { + this.cacheEvictor.notifySuccess( + TalerMerchantInstanceCacheEviction.UPDATE_ORDER, + ); + return opSuccessFromHttp(resp, codecForPaidRefundStatusResponse()); + } + case HttpStatusCode.BadRequest: + return opKnownHttpFailure(resp.status, resp); + case HttpStatusCode.Forbidden: + 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#aborting-incomplete-payments + */ + async abortIncompletePayment( + orderId: string, + body: TalerMerchantApi.AbortRequest, + ) { + const url = new URL(`orders/${orderId}/abort`, this.baseUrl); + + const resp = await this.httpLib.fetch(url.href, { + method: "POST", + body, + }); + + switch (resp.status) { + case HttpStatusCode.Ok: { + this.cacheEvictor.notifySuccess( + TalerMerchantInstanceCacheEviction.UPDATE_ORDER, + ); + return opSuccessFromHttp(resp, codecForAbortResponse()); + } + case HttpStatusCode.BadRequest: + return opKnownHttpFailure(resp.status, resp); + case HttpStatusCode.Forbidden: + 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#obtaining-refunds + */ + async obtainRefund( + orderId: string, + body: TalerMerchantApi.WalletRefundRequest, + ) { + const url = new URL(`orders/${orderId}/refund`, this.baseUrl); + + const resp = await this.httpLib.fetch(url.href, { + method: "POST", + body, + }); + + switch (resp.status) { + case HttpStatusCode.Ok: { + this.cacheEvictor.notifySuccess( + TalerMerchantInstanceCacheEviction.UPDATE_ORDER, + ); + return opSuccessFromHttp(resp, codecForWalletRefundResponse()); + } + case HttpStatusCode.BadRequest: + return opKnownHttpFailure(resp.status, resp); + case HttpStatusCode.Forbidden: + return opKnownHttpFailure(resp.status, resp); + case HttpStatusCode.NotFound: + return opKnownHttpFailure(resp.status, resp); + default: + return opUnknownFailure(resp, await readTalerErrorResponse(resp)); + } + } + + // + // Management + // + + /** + * https://docs.taler.net/core/api-merchant.html#post-[-instances-$INSTANCE]-private-auth + */ + async updateCurrentInstanceAuthentication( + token: AccessToken | undefined, + body: TalerMerchantApi.InstanceAuthConfigurationMessage, + ) { + const url = new URL(`private/auth`, 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: // FIXME: missing in docs + return opEmptySuccess(resp); + case HttpStatusCode.NoContent: + return opEmptySuccess(resp); + 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#patch-[-instances-$INSTANCE]-private + */ + async updateCurrentInstance( + token: AccessToken | undefined, + body: TalerMerchantApi.InstanceReconfigurationMessage, + ) { + const url = new URL(`private`, 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_CURRENT_INSTANCE, + ); + return opEmptySuccess(resp); + } + 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#get-[-instances-$INSTANCE]-private + * + */ + async getCurrentInstanceDetails(token: AccessToken) { + const url = new URL(`private`, 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, codecForQueryInstancesResponse()); + case HttpStatusCode.Unauthorized: // FIXME: missing in docs + return opKnownHttpFailure(resp.status, resp); + case HttpStatusCode.NotFound: // FIXME: missing in docs + return opKnownHttpFailure(resp.status, resp); + default: + return opUnknownFailure(resp, await readTalerErrorResponse(resp)); + } + } + + /** + * https://docs.taler.net/core/api-merchant.html#delete-[-instances-$INSTANCE]-private + */ + async deleteCurrentInstance( + token: AccessToken | undefined, + params: { purge?: boolean } = {}, + ) { + const url = new URL(`private`, this.baseUrl); + + if (params.purge !== undefined) { + url.searchParams.set("purge", params.purge ? "YES" : "NO"); + } + + 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_CURRENT_INSTANCE, + ); + return opEmptySuccess(resp); + } + case HttpStatusCode.Unauthorized: + 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#get--instances-$INSTANCE-private-kyc + */ + async getCurrentIntanceKycStatus( + token: AccessToken | undefined, + params: TalerMerchantApi.GetKycStatusRequestParams = {}, + ) { + const url = new URL(`private/kyc`, this.baseUrl); + + if (params.wireHash) { + url.searchParams.set("h_wire", params.wireHash); + } + if (params.exchangeURL) { + url.searchParams.set("exchange_url", params.exchangeURL); + } + if (params.timeout) { + url.searchParams.set("timeout_ms", String(params.timeout)); + } + + 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.Accepted: + return opSuccessFromHttp(resp, codecForAccountKycRedirects()); + case HttpStatusCode.NoContent: + 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.BadGateway: + return opKnownAlternativeFailure( + resp, + resp.status, + codecForAccountKycRedirects(), + ); + case HttpStatusCode.ServiceUnavailable: + return opKnownHttpFailure(resp.status, resp); + case HttpStatusCode.GatewayTimeout: + return opKnownHttpFailure(resp.status, resp); + default: + return opUnknownFailure(resp, await readTalerErrorResponse(resp)); + } + } + + // + // Bank Accounts + // + + /** + * https://docs.taler.net/core/api-merchant.html#post-[-instances-$INSTANCE]-private-accounts + */ + async addBankAccount( + token: AccessToken | undefined, + body: TalerMerchantApi.AccountAddDetails, + ) { + const url = new URL(`private/accounts`, 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_BANK_ACCOUNT, + ); + return opSuccessFromHttp(resp, codecForAccountAddResponse()); + } + 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#patch-[-instances-$INSTANCE]-private-accounts-$H_WIRE + */ + async updateBankAccount( + token: AccessToken | undefined, + wireAccount: string, + body: TalerMerchantApi.AccountPatchDetails, + ) { + const url = new URL(`private/accounts/${wireAccount}`, 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_BANK_ACCOUNT, + ); + return opEmptySuccess(resp); + } + 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#get-[-instances-$INSTANCE]-private-accounts + */ + async listBankAccounts(token: AccessToken, params?: PaginationParams) { + const url = new URL(`private/accounts`, 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, codecForAccountsSummaryResponse()); + 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#get-[-instances-$INSTANCE]-private-accounts-$H_WIRE + */ + async getBankAccountDetails( + token: AccessToken | undefined, + wireAccount: string, + ) { + const url = new URL(`private/accounts/${wireAccount}`, 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, codecForBankAccountEntry()); + 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#delete-[-instances-$INSTANCE]-private-accounts-$H_WIRE + */ + async deleteBankAccount(token: AccessToken | undefined, wireAccount: string) { + const url = new URL(`private/accounts/${wireAccount}`, 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_BANK_ACCOUNT, + ); + return opEmptySuccess(resp); + } + 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)); + } + } + + // + // Inventory Management + // + + /** + * https://docs.taler.net/core/api-merchant.html#post-[-instances-$INSTANCE]-private-products + */ + async addProduct( + token: AccessToken | undefined, + body: TalerMerchantApi.ProductAddDetail, + ) { + const url = new URL(`private/products`, 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.NoContent: { + this.cacheEvictor.notifySuccess( + TalerMerchantInstanceCacheEviction.CREATE_PRODUCT, + ); + 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#patch-[-instances-$INSTANCE]-private-products-$PRODUCT_ID + */ + async updateProduct( + token: AccessToken | undefined, + productId: string, + body: TalerMerchantApi.ProductPatchDetail, + ) { + const url = new URL(`private/products/${productId}`, 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_PRODUCT, + ); + 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#get-[-instances-$INSTANCE]-private-products + */ + async listProducts( + token: AccessToken | undefined, + params?: PaginationParams, + ) { + const url = new URL(`private/products`, 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, codecForInventorySummaryResponse()); + case HttpStatusCode.Unauthorized: // FIXME: not 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#get-[-instances-$INSTANCE]-private-products-$PRODUCT_ID + */ + async getProductDetails(token: AccessToken | undefined, productId: string) { + const url = new URL(`private/products/${productId}`, 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, codecForProductDetail()); + 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#reserving-inventory + */ + async lockProduct( + token: AccessToken | undefined, + productId: string, + body: TalerMerchantApi.LockRequest, + ) { + const url = new URL(`private/products/${productId}/lock`, 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.NoContent: { + this.cacheEvictor.notifySuccess( + TalerMerchantInstanceCacheEviction.UPDATE_PRODUCT, + ); + 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.Gone: + return opKnownHttpFailure(resp.status, resp); + default: + return opUnknownFailure(resp, await readTalerErrorResponse(resp)); + } + } + + /** + * https://docs.taler.net/core/api-merchant.html#removing-products-from-inventory + */ + async deleteProduct(token: AccessToken | undefined, productId: string) { + const url = new URL(`private/products/${productId}`, 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_PRODUCT, + ); + 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)); + } + } + + // + // Payment processing + // + + /** + * https://docs.taler.net/core/api-merchant.html#post-[-instances-$INSTANCE]-private-orders + */ + async createOrder( + token: AccessToken | undefined, + body: TalerMerchantApi.PostOrderRequest, + ) { + const url = new URL(`private/orders`, 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, + }); + return this.procesOrderCreationResponse(resp); + } + + private async procesOrderCreationResponse(resp: HttpResponse) { + switch (resp.status) { + case HttpStatusCode.Ok: { + this.cacheEvictor.notifySuccess( + TalerMerchantInstanceCacheEviction.CREATE_ORDER, + ); + return opSuccessFromHttp(resp, codecForPostOrderResponse()); + } + case HttpStatusCode.NotFound: + return opKnownHttpFailure(resp.status, resp); + case HttpStatusCode.Unauthorized: // FIXME: missing in docs + return opKnownHttpFailure(resp.status, resp); + case HttpStatusCode.Conflict: + return opKnownHttpFailure(resp.status, resp); + case HttpStatusCode.Gone: + return opKnownAlternativeFailure( + resp, + resp.status, + codecForOutOfStockResponse(), + ); + default: + return opUnknownFailure(resp, await readTalerErrorResponse(resp)); + } + } + + /** + * https://docs.taler.net/core/api-merchant.html#inspecting-orders + */ + async listOrders( + token: AccessToken | undefined, + params: TalerMerchantApi.ListOrdersRequestParams = {}, + ) { + const url = new URL(`private/orders`, this.baseUrl); + + if (params.date) { + url.searchParams.set("date_s", String(params.date)); + } + if (params.fulfillmentUrl) { + url.searchParams.set("fulfillment_url", params.fulfillmentUrl); + } + if (params.paid !== undefined) { + url.searchParams.set("paid", params.paid ? "YES" : "NO"); + } + if (params.refunded !== undefined) { + url.searchParams.set("refunded", params.refunded ? "YES" : "NO"); + } + if (params.sessionId) { + url.searchParams.set("session_id", params.sessionId); + } + if (params.timeout) { + url.searchParams.set("timeout", String(params.timeout)); + } + if (params.wired !== undefined) { + url.searchParams.set("wired", params.wired ? "YES" : "NO"); + } + 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, codecForOrderHistory()); + case HttpStatusCode.NotFound: // FIXME: missing in docs + 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-orders-$ORDER_ID + */ + async getOrderDetails( + token: AccessToken | undefined, + orderId: string, + params: TalerMerchantApi.GetOrderRequestParams = {}, + ) { + const url = new URL(`private/orders/${orderId}`, this.baseUrl); + + if (params.allowRefundedForRepurchase !== undefined) { + url.searchParams.set( + "allow_refunded_for_repurchase", + params.allowRefundedForRepurchase ? "YES" : "NO", + ); + } + if (params.sessionId) { + url.searchParams.set("session_id", params.sessionId); + } + if (params.timeout) { + url.searchParams.set("timeout_ms", String(params.timeout)); + } + + 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, + codecForMerchantOrderPrivateStatusResponse(), + ); + case HttpStatusCode.NotFound: + return opKnownHttpFailure(resp.status, resp); + case HttpStatusCode.Unauthorized: // FIXME: missing in docs + return opKnownHttpFailure(resp.status, resp); + case HttpStatusCode.BadGateway: + return opKnownHttpFailure(resp.status, resp); + case HttpStatusCode.GatewayTimeout: + return opKnownAlternativeFailure( + resp, + resp.status, + codecForOutOfStockResponse(), + ); + default: + return opUnknownFailure(resp, await readTalerErrorResponse(resp)); + } + } + + /** + * https://docs.taler.net/core/api-merchant.html#private-order-data-cleanup + */ + async forgetOrder( + token: AccessToken | undefined, + orderId: string, + body: TalerMerchantApi.ForgetRequest, + ) { + const url = new URL(`private/orders/${orderId}/forget`, 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.Ok: { + this.cacheEvictor.notifySuccess( + TalerMerchantInstanceCacheEviction.UPDATE_ORDER, + ); + return opEmptySuccess(resp); + } + case HttpStatusCode.NoContent: + return opEmptySuccess(resp); + case HttpStatusCode.Unauthorized: // FIXME: missing in docs + return opKnownHttpFailure(resp.status, resp); + case HttpStatusCode.BadRequest: + 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#delete-[-instances-$INSTANCE]-private-orders-$ORDER_ID + */ + async deleteOrder(token: AccessToken | undefined, orderId: string) { + const url = new URL(`private/orders/${orderId}`, 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_ORDER, + ); + 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)); + } + } + + // + // Refunds + // + + /** + * https://docs.taler.net/core/api-merchant.html#post-[-instances-$INSTANCE]-private-orders-$ORDER_ID-refund + */ + async addRefund( + token: AccessToken | undefined, + orderId: string, + body: TalerMerchantApi.RefundRequest, + ) { + const url = new URL(`private/orders/${orderId}/refund`, 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.UPDATE_ORDER, + ); + return opSuccessFromHttp(resp, codecForMerchantRefundResponse()); + } + case HttpStatusCode.Forbidden: + return opKnownHttpFailure(resp.status, resp); + case HttpStatusCode.Unauthorized: // FIXME: missing in docs + return opKnownHttpFailure(resp.status, resp); + case HttpStatusCode.NotFound: + return opKnownHttpFailure(resp.status, resp); + case HttpStatusCode.Gone: + return opKnownHttpFailure(resp.status, resp); + case HttpStatusCode.Conflict: + return opKnownHttpFailure(resp.status, resp); + default: + return opUnknownFailure(resp, await readTalerErrorResponse(resp)); + } + } + + // + // Wire Transfer + // + + /** + * https://docs.taler.net/core/api-merchant.html#post-[-instances-$INSTANCE]-private-transfers + */ + async informWireTransfer( + token: AccessToken | undefined, + body: TalerMerchantApi.TransferInformation, + ) { + const url = new URL(`private/transfers`, 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.NoContent: { + this.cacheEvictor.notifySuccess( + TalerMerchantInstanceCacheEviction.CREATE_TRANSFER, + ); + 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#get-[-instances-$INSTANCE]-private-transfers + */ + async listWireTransfers( + token: AccessToken | undefined, + params: TalerMerchantApi.ListWireTransferRequestParams = {}, + ) { + const url = new URL(`private/transfers`, this.baseUrl); + + if (params.after) { + url.searchParams.set("after", String(params.after)); + } + if (params.before) { + url.searchParams.set("before", String(params.before)); + } + if (params.paytoURI) { + url.searchParams.set("payto_uri", params.paytoURI); + } + if (params.verified !== undefined) { + url.searchParams.set("verified", params.verified ? "YES" : "NO"); + } + 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, codecForTansferList()); + case HttpStatusCode.Unauthorized: // FIXME: missing in docs + return opKnownHttpFailure(resp.status, resp); + case HttpStatusCode.NotFound: // FIXME: missing in docs + return opKnownHttpFailure(resp.status, resp); + default: + return opUnknownFailure(resp, await readTalerErrorResponse(resp)); + } + } + + /** + * https://docs.taler.net/core/api-merchant.html#delete-[-instances-$INSTANCE]-private-transfers-$TID + */ + async deleteWireTransfer(token: AccessToken | undefined, transferId: string) { + const url = new URL(`private/transfers/${transferId}`, 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_TRANSFER, + ); + 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)); + } + } + + // + // OTP Devices + // + + /** + * https://docs.taler.net/core/api-merchant.html#post-[-instances-$INSTANCE]-private-otp-devices + */ + async addOtpDevice( + token: AccessToken | undefined, + body: TalerMerchantApi.OtpDeviceAddDetails, + ) { + const url = new URL(`private/otp-devices`, 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.NoContent: { + this.cacheEvictor.notifySuccess( + TalerMerchantInstanceCacheEviction.CREATE_DEVICE, + ); + return opEmptySuccess(resp); + } + 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#patch-[-instances-$INSTANCE]-private-otp-devices-$DEVICE_ID + */ + async updateOtpDevice( + token: AccessToken | undefined, + deviceId: string, + body: TalerMerchantApi.OtpDevicePatchDetails, + ) { + const url = new URL(`private/otp-devices/${deviceId}`, 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_DEVICE, + ); + 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#get-[-instances-$INSTANCE]-private-otp-devices + */ + async listOtpDevices( + token: AccessToken | undefined, + params?: PaginationParams, + ) { + const url = new URL(`private/otp-devices`, 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, codecForOtpDeviceSummaryResponse()); + 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#get-[-instances-$INSTANCE]-private-otp-devices-$DEVICE_ID + */ + async getOtpDeviceDetails( + token: AccessToken | undefined, + deviceId: string, + params: TalerMerchantApi.GetOtpDeviceRequestParams = {}, + ) { + const url = new URL(`private/otp-devices/${deviceId}`, this.baseUrl); + + if (params.faketime) { + url.searchParams.set("faketime", String(params.faketime)); + } + if (params.price) { + url.searchParams.set("price", params.price); + } + 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, codecForOtpDeviceDetails()); + 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#delete-[-instances-$INSTANCE]-private-otp-devices-$DEVICE_ID + */ + async deleteOtpDevice(token: AccessToken | undefined, deviceId: string) { + const url = new URL(`private/otp-devices/${deviceId}`, 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_DEVICE, + ); + return opEmptySuccess(resp); + } + 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)); + } + } + + // + // Templates + // + + /** + * https://docs.taler.net/core/api-merchant.html#post-[-instances-$INSTANCE]-private-templates + */ + async addTemplate( + token: AccessToken | undefined, + body: TalerMerchantApi.TemplateAddDetails, + ) { + const url = new URL(`private/templates`, 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.NoContent: { + this.cacheEvictor.notifySuccess( + TalerMerchantInstanceCacheEviction.CREATE_TEMPLATE, + ); + return opEmptySuccess(resp); + } + 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#patch-[-instances-$INSTANCE]-private-templates-$TEMPLATE_ID + */ + async updateTemplate( + token: AccessToken | undefined, + templateId: string, + body: TalerMerchantApi.TemplatePatchDetails, + ) { + const url = new URL(`private/templates/${templateId}`, 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_TEMPLATE, + ); + 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#inspecting-template + */ + async listTemplates( + token: AccessToken | undefined, + params?: PaginationParams, + ) { + const url = new URL(`private/templates`, 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, codecForTemplateSummaryResponse()); + 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#get-[-instances-$INSTANCE]-private-templates-$TEMPLATE_ID + */ + async getTemplateDetails(token: AccessToken | undefined, templateId: string) { + const url = new URL(`private/templates/${templateId}`, 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, codecForTemplateDetails()); + 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#delete-[-instances-$INSTANCE]-private-templates-$TEMPLATE_ID + */ + async deleteTemplate(token: AccessToken | undefined, templateId: string) { + const url = new URL(`private/templates/${templateId}`, 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_TEMPLATE, + ); + return opEmptySuccess(resp); + } + 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#get-[-instances-$INSTANCE]-templates-$TEMPLATE_ID + */ + async useTemplateGetInfo(templateId: string) { + const url = new URL(`templates/${templateId}`, this.baseUrl); + + const resp = await this.httpLib.fetch(url.href, { + method: "GET", + }); + switch (resp.status) { + case HttpStatusCode.Ok: + return opSuccessFromHttp(resp, codecForWalletTemplateDetails()); + 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-$INSTANCES]-templates-$TEMPLATE_ID + */ + async useTemplateCreateOrder( + templateId: string, + body: TalerMerchantApi.UsingTemplateDetails, + ) { + const url = new URL(`templates/${templateId}`, this.baseUrl); + + const resp = await this.httpLib.fetch(url.href, { + method: "POST", + body, + }); + + return this.procesOrderCreationResponse(resp); + } + + // + // Webhooks + // + + /** + * https://docs.taler.net/core/api-merchant.html#post-[-instances-$INSTANCES]-private-webhooks + */ + async addWebhook( + token: AccessToken | undefined, + body: TalerMerchantApi.WebhookAddDetails, + ) { + const url = new URL(`private/webhooks`, 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.NoContent: { + this.cacheEvictor.notifySuccess( + TalerMerchantInstanceCacheEviction.CREATE_WEBHOOK, + ); + return opEmptySuccess(resp); + } + 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#patch-[-instances-$INSTANCES]-private-webhooks-$WEBHOOK_ID + */ + async updateWebhook( + token: AccessToken | undefined, + webhookId: string, + body: TalerMerchantApi.WebhookPatchDetails, + ) { + const url = new URL(`private/webhooks/${webhookId}`, 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_WEBHOOK, + ); + 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#get-[-instances-$INSTANCES]-private-webhooks + */ + async listWebhooks( + token: AccessToken | undefined, + params?: PaginationParams, + ) { + const url = new URL(`private/webhooks`, 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, codecForWebhookSummaryResponse()); + 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#get-[-instances-$INSTANCES]-private-webhooks-$WEBHOOK_ID + */ + async getWebhookDetails(token: AccessToken | undefined, webhookId: string) { + const url = new URL(`private/webhooks/${webhookId}`, 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.NoContent: + return opSuccessFromHttp(resp, codecForWebhookDetails()); + 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#delete-[-instances-$INSTANCES]-private-webhooks-$WEBHOOK_ID + */ + async deleteWebhook(token: AccessToken | undefined, webhookId: string) { + const url = new URL(`private/webhooks/${webhookId}`, 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_WEBHOOK, + ); + return opEmptySuccess(resp); + } + 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)); + } + } + + // + // token families + // + + /** + * https://docs.taler.net/core/api-merchant.html#post-[-instances-$INSTANCES]-private-tokenfamilies + */ + async createTokenFamily( + token: AccessToken | undefined, + body: TalerMerchantApi.TokenFamilyCreateRequest, + ) { + const url = new URL(`private/tokenfamilies`, 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.NoContent: { + this.cacheEvictor.notifySuccess( + TalerMerchantInstanceCacheEviction.CREATE_TOKENFAMILY, + ); + return opEmptySuccess(resp); + } + 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#patch-[-instances-$INSTANCES]-private-tokenfamilies-$TOKEN_FAMILY_SLUG + */ + async updateTokenFamily( + token: AccessToken | undefined, + tokenSlug: string, + body: TalerMerchantApi.TokenFamilyUpdateRequest, + ) { + const url = new URL(`private/tokenfamilies/${tokenSlug}`, 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.UPDATE_TOKENFAMILY, + ); + return opSuccessFromHttp(resp, codecForTokenFamilyDetails()); + } + 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#get-[-instances-$INSTANCES]-private-tokenfamilies + */ + async listTokenFamilies( + token: AccessToken | undefined, + params?: PaginationParams, + ) { + const url = new URL(`private/tokenfamilies`, 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, codecForTokenFamiliesList()); + 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#get-[-instances-$INSTANCES]-private-tokenfamilies-$TOKEN_FAMILY_SLUG + */ + async getTokenFamilyDetails( + token: AccessToken | undefined, + tokenSlug: string, + ) { + const url = new URL(`private/tokenfamilies/${tokenSlug}`, 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, codecForTokenFamilyDetails()); + 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#delete-[-instances-$INSTANCES]-private-tokenfamilies-$TOKEN_FAMILY_SLUG + */ + async deleteTokenFamily(token: AccessToken | undefined, tokenSlug: string) { + const url = new URL(`private/tokenfamilies/${tokenSlug}`, 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_TOKENFAMILY, + ); + return opEmptySuccess(resp); + } + 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)); + } + } + + /** + * Get the auth api against the current instance + * + * https://docs.taler.net/core/api-merchant.html#post-[-instances-$INSTANCE]-private-token + * https://docs.taler.net/core/api-merchant.html#delete-[-instances-$INSTANCE]-private-token + */ + getAuthenticationAPI(): URL { + return new URL(`private/`, this.baseUrl); + } +} + +export type TalerMerchantManagementResultByMethod< + prop extends keyof TalerMerchantManagementHttpClient, +> = ResultByMethod<TalerMerchantManagementHttpClient, prop>; +export type TalerMerchantManagementErrorsByMethod< + prop extends keyof TalerMerchantManagementHttpClient, +> = FailCasesByMethod<TalerMerchantManagementHttpClient, prop>; + +export class TalerMerchantManagementHttpClient extends TalerMerchantInstanceHttpClient { + readonly cacheManagementEvictor: CacheEvictor< + TalerMerchantInstanceCacheEviction | TalerMerchantManagementCacheEviction + >; + constructor( + readonly baseUrl: string, + httpClient?: HttpRequestLibrary, + // cacheManagementEvictor?: CacheEvictor<TalerMerchantManagementCacheEviction>, + cacheEvictor?: CacheEvictor< + TalerMerchantInstanceCacheEviction | TalerMerchantManagementCacheEviction + >, + ) { + super(baseUrl, httpClient, cacheEvictor); + this.cacheManagementEvictor = cacheEvictor ?? nullEvictor; + } + + getSubInstanceAPI(instanceId: string) { + return new URL(`instances/${instanceId}/`, this.baseUrl); + } + + // + // Instance Management + // + + /** + * https://docs.taler.net/core/api-merchant.html#post--management-instances + */ + async createInstance( + token: AccessToken | undefined, + body: TalerMerchantApi.InstanceConfigurationMessage, + ) { + const url = new URL(`management/instances`, 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.NoContent: { + this.cacheManagementEvictor.notifySuccess( + TalerMerchantManagementCacheEviction.CREATE_INSTANCE, + ); + return opEmptySuccess(resp); + } + case HttpStatusCode.Unauthorized: // 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--management-instances-$INSTANCE-auth + */ + async updateInstanceAuthentication( + token: AccessToken | undefined, + instanceId: string, + body: TalerMerchantApi.InstanceAuthConfigurationMessage, + ) { + const url = new URL( + `management/instances/${instanceId}/auth`, + 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.NoContent: + return opEmptySuccess(resp); + 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#patch--management-instances-$INSTANCE + */ + async updateInstance( + token: AccessToken | undefined, + instanceId: string, + body: TalerMerchantApi.InstanceReconfigurationMessage, + ) { + const url = new URL(`management/instances/${instanceId}`, 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.cacheManagementEvictor.notifySuccess( + TalerMerchantManagementCacheEviction.UPDATE_INSTANCE, + ); + return opEmptySuccess(resp); + } + 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#get--management-instances + */ + async listInstances( + token: AccessToken | undefined, + params?: PaginationParams, + ) { + const url = new URL(`management/instances`, 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, codecForInstancesResponse()); + 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--management-instances-$INSTANCE + * + */ + async getInstanceDetails(token: AccessToken | undefined, instanceId: string) { + const url = new URL(`management/instances/${instanceId}`, 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, codecForQueryInstancesResponse()); + case HttpStatusCode.Unauthorized: // FIXME: missing in docs + return opKnownHttpFailure(resp.status, resp); + case HttpStatusCode.NotFound: // FIXME: missing in docs + return opKnownHttpFailure(resp.status, resp); + default: + return opUnknownFailure(resp, await readTalerErrorResponse(resp)); + } + } + + /** + * https://docs.taler.net/core/api-merchant.html#delete--management-instances-$INSTANCE + */ + async deleteInstance( + token: AccessToken | undefined, + instanceId: string, + params: { purge?: boolean } = {}, + ) { + const url = new URL(`management/instances/${instanceId}`, this.baseUrl); + + if (params.purge !== undefined) { + url.searchParams.set("purge", params.purge ? "YES" : "NO"); + } + + 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.cacheManagementEvictor.notifySuccess( + TalerMerchantManagementCacheEviction.DELETE_INSTANCE, + ); + 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#get--management-instances-$INSTANCE-kyc + */ + async getIntanceKycStatus( + token: AccessToken | undefined, + instanceId: string, + params: TalerMerchantApi.GetKycStatusRequestParams, + ) { + const url = new URL(`management/instances/${instanceId}/kyc`, this.baseUrl); + + if (params.wireHash) { + url.searchParams.set("h_wire", params.wireHash); + } + if (params.exchangeURL) { + url.searchParams.set("exchange_url", params.exchangeURL); + } + if (params.timeout) { + url.searchParams.set("timeout_ms", String(params.timeout)); + } + + 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.Accepted: + return opSuccessFromHttp(resp, codecForAccountKycRedirects()); + case HttpStatusCode.NoContent: + return opEmptySuccess(resp); + case HttpStatusCode.NotFound: + return opEmptySuccess(resp); + case HttpStatusCode.Unauthorized: // FIXME: missing in docs + return opKnownHttpFailure(resp.status, resp); + case HttpStatusCode.BadGateway: + return opKnownHttpFailure(resp.status, resp); + case HttpStatusCode.ServiceUnavailable: + return opKnownHttpFailure(resp.status, resp); + case HttpStatusCode.Conflict: + return opKnownHttpFailure(resp.status, resp); + default: + return opUnknownFailure(resp, await readTalerErrorResponse(resp)); + } + } +} |