From 146517062ade5709ec4b9cc3898458f3c28c86ec Mon Sep 17 00:00:00 2001 From: Adrian Pilarczyk Date: Thu, 27 Jul 2023 17:16:13 +0200 Subject: [PATCH] feat: :construction: add basic boilerplate --- .../subscriptions/OrderCancelled.graphql | 32 +++++++++++ .../modules/avatax/avatax-webhook.service.ts | 7 +++ .../taxes/get-active-connection-service.ts | 5 ++ .../src/modules/taxes/tax-provider-webhook.ts | 3 +- .../modules/taxjar/taxjar-webhook.service.ts | 12 ++++- .../src/pages/api/webhooks/order-cancelled.ts | 54 +++++++++++++++++++ 6 files changed, 111 insertions(+), 2 deletions(-) create mode 100644 apps/taxes/graphql/subscriptions/OrderCancelled.graphql create mode 100644 apps/taxes/src/pages/api/webhooks/order-cancelled.ts diff --git a/apps/taxes/graphql/subscriptions/OrderCancelled.graphql b/apps/taxes/graphql/subscriptions/OrderCancelled.graphql new file mode 100644 index 0000000..07b2bc8 --- /dev/null +++ b/apps/taxes/graphql/subscriptions/OrderCancelled.graphql @@ -0,0 +1,32 @@ +fragment OrderCancelledSubscription on Order { + id + privateMetadata { + key + value + } + channel { + id + slug + } +} + +fragment OrderCancelledEventSubscription on Event { + __typename + ... on OrderCancelled { + order { + ...OrderCancelledSubscription + } + recipient { + privateMetadata { + key + value + } + } + } +} + +subscription OrderCancelledSubscription { + event { + ...OrderCancelledEventSubscription + } +} diff --git a/apps/taxes/src/modules/avatax/avatax-webhook.service.ts b/apps/taxes/src/modules/avatax/avatax-webhook.service.ts index 6def76b..68ae0fa 100644 --- a/apps/taxes/src/modules/avatax/avatax-webhook.service.ts +++ b/apps/taxes/src/modules/avatax/avatax-webhook.service.ts @@ -1,5 +1,6 @@ import { AuthData } from "@saleor/app-sdk/APL"; import { + OrderCancelledEventSubscriptionFragment, OrderCreatedSubscriptionFragment, OrderFulfilledSubscriptionFragment, TaxBaseFragment, @@ -50,4 +51,10 @@ export class AvataxWebhookService implements ProviderWebhookService { return response; } + + async cancelOrder(payload: OrderCancelledEventSubscriptionFragment) { + // todo: implement + this.logger.debug("cancelOrder", payload); + return { ok: true }; + } } diff --git a/apps/taxes/src/modules/taxes/get-active-connection-service.ts b/apps/taxes/src/modules/taxes/get-active-connection-service.ts index 480b165..0a8e6e8 100644 --- a/apps/taxes/src/modules/taxes/get-active-connection-service.ts +++ b/apps/taxes/src/modules/taxes/get-active-connection-service.ts @@ -1,6 +1,7 @@ import { AuthData } from "@saleor/app-sdk/APL"; import { MetadataItem, + OrderCancelledEventSubscriptionFragment, OrderCreatedSubscriptionFragment, OrderFulfilledSubscriptionFragment, TaxBaseFragment, @@ -55,6 +56,10 @@ class ActiveTaxProviderService implements ProviderWebhookService { async fulfillOrder(payload: OrderFulfilledSubscriptionFragment) { return this.client.fulfillOrder(payload); } + + async cancelOrder(payload: OrderCancelledEventSubscriptionFragment) { + return this.client.cancelOrder(payload); + } } export function getActiveConnectionService( diff --git a/apps/taxes/src/modules/taxes/tax-provider-webhook.ts b/apps/taxes/src/modules/taxes/tax-provider-webhook.ts index a516f60..e942722 100644 --- a/apps/taxes/src/modules/taxes/tax-provider-webhook.ts +++ b/apps/taxes/src/modules/taxes/tax-provider-webhook.ts @@ -1,10 +1,10 @@ import { SyncWebhookResponsesMap } from "@saleor/app-sdk/handlers/next"; import { + OrderCancelledEventSubscriptionFragment, OrderCreatedSubscriptionFragment, OrderFulfilledSubscriptionFragment, TaxBaseFragment, } from "../../../generated/graphql"; -import { ChannelConfig } from "../channel-configuration/channel-config"; export type CalculateTaxesResponse = SyncWebhookResponsesMap["ORDER_CALCULATE_TAXES"]; @@ -14,4 +14,5 @@ export interface ProviderWebhookService { calculateTaxes: (payload: TaxBaseFragment) => Promise; createOrder: (payload: OrderCreatedSubscriptionFragment) => Promise; fulfillOrder: (payload: OrderFulfilledSubscriptionFragment) => Promise<{ ok: boolean }>; + cancelOrder: (payload: OrderCancelledEventSubscriptionFragment) => Promise; } diff --git a/apps/taxes/src/modules/taxjar/taxjar-webhook.service.ts b/apps/taxes/src/modules/taxjar/taxjar-webhook.service.ts index 120c0a4..dfb1ac3 100644 --- a/apps/taxes/src/modules/taxjar/taxjar-webhook.service.ts +++ b/apps/taxes/src/modules/taxjar/taxjar-webhook.service.ts @@ -1,4 +1,8 @@ -import { OrderCreatedSubscriptionFragment, TaxBaseFragment } from "../../../generated/graphql"; +import { + OrderCancelledEventSubscriptionFragment, + OrderCreatedSubscriptionFragment, + TaxBaseFragment, +} from "../../../generated/graphql"; import { Logger, createLogger } from "../../lib/logger"; import { TaxJarCalculateTaxesAdapter } from "./calculate-taxes/taxjar-calculate-taxes-adapter"; import { TaxJarClient } from "./taxjar-client"; @@ -42,4 +46,10 @@ export class TaxJarWebhookService implements ProviderWebhookService { async fulfillOrder() { return { ok: true }; } + + async cancelOrder(payload: OrderCancelledEventSubscriptionFragment) { + // todo: implement + this.logger.debug("cancelOrder", payload); + return { ok: true }; + } } diff --git a/apps/taxes/src/pages/api/webhooks/order-cancelled.ts b/apps/taxes/src/pages/api/webhooks/order-cancelled.ts new file mode 100644 index 0000000..c9f0186 --- /dev/null +++ b/apps/taxes/src/pages/api/webhooks/order-cancelled.ts @@ -0,0 +1,54 @@ +import { SaleorAsyncWebhook } from "@saleor/app-sdk/handlers/next"; +import { + OrderCancelledEventSubscriptionFragment, + UntypedOrderCancelledSubscriptionDocument, +} from "../../../../generated/graphql"; +import { saleorApp } from "../../../../saleor-app"; +import { createLogger } from "../../../lib/logger"; +import { getActiveConnectionService } from "../../../modules/taxes/get-active-connection-service"; +import { WebhookResponse } from "../../../modules/app/webhook-response"; +export const config = { + api: { + bodyParser: false, + }, +}; + +type OrderCancelledPayload = Extract< + OrderCancelledEventSubscriptionFragment, + { __typename: "OrderCancelled" } +>; + +export const orderCancelledAsyncWebhook = new SaleorAsyncWebhook({ + name: "OrderCancelled", + apl: saleorApp.apl, + event: "ORDER_CANCELLED", + query: UntypedOrderCancelledSubscriptionDocument, + webhookPath: "/api/webhooks/order-cancelled", +}); + +export default orderCancelledAsyncWebhook.createHandler(async (req, res, ctx) => { + const logger = createLogger({ event: ctx.event }); + const { payload } = ctx; + const webhookResponse = new WebhookResponse(res); + + logger.info("Handler called with payload"); + + try { + const appMetadata = payload.recipient?.privateMetadata ?? []; + const channelSlug = payload.order?.channel.slug; + const taxProvider = getActiveConnectionService(channelSlug, appMetadata, ctx.authData); + + logger.info("Fetched taxProvider"); + + if (!payload.order) { + return webhookResponse.error(new Error("Insufficient order data")); + } + await taxProvider.cancelOrder(payload); + + logger.info("Order cancelled"); + + return webhookResponse.success(); + } catch (error) { + return webhookResponse.error(new Error("Error while fulfilling tax provider order")); + } +});