refactor: avataxId instead of externalId

This commit is contained in:
Adrian Pilarczyk 2023-08-01 08:34:55 +02:00
parent ac9acdf0c6
commit e4ac0e7827
10 changed files with 33 additions and 55 deletions

View file

@ -1,6 +1,6 @@
fragment OrderCancelledSubscription on Order { fragment OrderCancelledSubscription on Order {
id id
externalId: metafield(key: "externalId") avataxId: metafield(key: "avataxId")
channel { channel {
id id
slug slug

View file

@ -47,10 +47,7 @@ fragment OrderFulfilledSubscription on Order {
amount amount
} }
} }
privateMetadata { avataxId: metafield(key: "avataxId")
key
value
}
lines { lines {
...OrderLine ...OrderLine
} }

View file

@ -1,10 +1,11 @@
import { Client } from "urql";
import { import {
UpdateMetadataDocument, UpdateMetadataDocument,
UpdateMetadataMutation, UpdateMetadataMutation,
UpdateMetadataMutationVariables, UpdateMetadataMutationVariables,
} from "../../../generated/graphql"; } from "../../../generated/graphql";
import { Client } from "urql";
import { PROVIDER_ORDER_ID_KEY } from "../avatax/order-fulfilled/avatax-order-fulfilled-payload-transformer"; const PROVIDER_ORDER_ID_KEY = "avataxId";
export class OrderMetadataManager { export class OrderMetadataManager {
private privateOrderIdKey = PROVIDER_ORDER_ID_KEY; private privateOrderIdKey = PROVIDER_ORDER_ID_KEY;

View file

@ -55,7 +55,6 @@ export class AvataxWebhookService implements ProviderWebhookService {
} }
async cancelOrder(payload: OrderCancelledPayload) { async cancelOrder(payload: OrderCancelledPayload) {
this.logger.debug("cancelOrder", payload);
const adapter = new AvataxOrderCancelledAdapter(this.config); const adapter = new AvataxOrderCancelledAdapter(this.config);
await adapter.send(payload); await adapter.send(payload);

View file

@ -15,7 +15,10 @@ export class AvataxOrderCancelledAdapter implements WebhookAdapter<OrderCancelle
} }
async send(payload: OrderCancelledPayload) { async send(payload: OrderCancelledPayload) {
this.logger.debug("Transforming the Saleor payload for cancelling transaction with Avatax..."); this.logger.debug(
{ payload },
"Transforming the Saleor payload for cancelling transaction with Avatax..."
);
const payloadTransformer = new AvataxOrderCancelledPayloadTransformer(this.config); const payloadTransformer = new AvataxOrderCancelledPayloadTransformer(this.config);
const target = payloadTransformer.transform({ ...payload }); const target = payloadTransformer.transform({ ...payload });
@ -26,6 +29,6 @@ export class AvataxOrderCancelledAdapter implements WebhookAdapter<OrderCancelle
await client.voidTransaction(target); await client.voidTransaction(target);
this.logger.debug("Avatax commitTransaction succesfully responded"); this.logger.debug(`Succesfully voided the transaction of id: ${target.transactionCode}`);
} }
} }

View file

@ -13,14 +13,14 @@ describe("AvataxOrderCancelledPayloadTransformer", () => {
expect(() => transformer.transform(payload)).toThrow("Order is required"); expect(() => transformer.transform(payload)).toThrow("Order is required");
}); });
it("throws an error when no externalId is present", () => { it("throws an error when no avataxId is present", () => {
const payload = { order: {} } as any as OrderCancelledPayload; const payload = { order: {} } as any as OrderCancelledPayload;
const transformer = new AvataxOrderCancelledPayloadTransformer(avataxMockConfig); const transformer = new AvataxOrderCancelledPayloadTransformer(avataxMockConfig);
expect(() => transformer.transform(payload)).toThrow(); expect(() => transformer.transform(payload)).toThrow();
}); });
it("returns a valid AvataxOrderCancelledTarget", () => { it("returns a valid AvataxOrderCancelledTarget", () => {
const payload = { order: { externalId: "123" } } as any as OrderCancelledPayload; const payload = { order: { avataxId: "123" } } as any as OrderCancelledPayload;
const transformer = new AvataxOrderCancelledPayloadTransformer(avataxMockConfig); const transformer = new AvataxOrderCancelledPayloadTransformer(avataxMockConfig);
const target = transformer.transform(payload); const target = transformer.transform(payload);

View file

@ -1,5 +1,5 @@
import { z } from "zod";
import { OrderCancelledPayload } from "../../../pages/api/webhooks/order-cancelled"; import { OrderCancelledPayload } from "../../../pages/api/webhooks/order-cancelled";
import { taxProviderUtils } from "../../taxes/tax-provider-utils";
import { AvataxConfig } from "../avatax-connection-schema"; import { AvataxConfig } from "../avatax-connection-schema";
import { AvataxOrderCancelledTarget } from "./avatax-order-cancelled-adapter"; import { AvataxOrderCancelledTarget } from "./avatax-order-cancelled-adapter";
@ -11,7 +11,7 @@ export class AvataxOrderCancelledPayloadTransformer {
throw new Error("Order is required"); throw new Error("Order is required");
} }
const transactionCode = taxProviderUtils.resolveOptionalOrThrow(order.externalId); const transactionCode = z.string().min(1).parse(order.avataxId);
return { return {
transactionCode, transactionCode,

View file

@ -2,11 +2,7 @@ import { DocumentType } from "avatax/lib/enums/DocumentType";
import { describe, expect, it } from "vitest"; import { describe, expect, it } from "vitest";
import { OrderFulfilledSubscriptionFragment } from "../../../../generated/graphql"; import { OrderFulfilledSubscriptionFragment } from "../../../../generated/graphql";
import { AvataxConfig } from "../avatax-connection-schema"; import { AvataxConfig } from "../avatax-connection-schema";
import { import { AvataxOrderFulfilledPayloadTransformer } from "./avatax-order-fulfilled-payload-transformer";
AvataxOrderFulfilledPayloadTransformer,
PROVIDER_ORDER_ID_KEY,
getTransactionCodeFromMetadata,
} from "./avatax-order-fulfilled-payload-transformer";
// todo: add AvataxOrderFulfilledMockGenerator // todo: add AvataxOrderFulfilledMockGenerator
@ -30,19 +26,12 @@ const MOCK_AVATAX_CONFIG: AvataxConfig = {
}, },
}; };
const MOCKED_METADATA: OrderFulfilledSubscriptionFragment["privateMetadata"] = [
{
key: PROVIDER_ORDER_ID_KEY,
value: "transaction-code",
},
];
type OrderFulfilled = OrderFulfilledSubscriptionFragment; type OrderFulfilled = OrderFulfilledSubscriptionFragment;
const ORDER_FULFILLED_MOCK: OrderFulfilled = { const ORDER_FULFILLED_MOCK: OrderFulfilled = {
id: "T3JkZXI6OTU4MDA5YjQtNDUxZC00NmQ1LThhMWUtMTRkMWRmYjFhNzI5", id: "T3JkZXI6OTU4MDA5YjQtNDUxZC00NmQ1LThhMWUtMTRkMWRmYjFhNzI5",
created: "2023-04-11T11:03:09.304109+00:00", created: "2023-04-11T11:03:09.304109+00:00",
privateMetadata: MOCKED_METADATA, avataxId: "transaction-code",
channel: { channel: {
id: "Q2hhbm5lbDoy", id: "Q2hhbm5lbDoy",
slug: "channel-pln", slug: "channel-pln",
@ -120,16 +109,6 @@ const ORDER_FULFILLED_MOCK: OrderFulfilled = {
], ],
}; };
describe("getTransactionCodeFromMetadata", () => {
it("returns transaction code", () => {
expect(getTransactionCodeFromMetadata(MOCKED_METADATA)).toBe("transaction-code");
});
it("throws error when transaction code not found", () => {
expect(() => getTransactionCodeFromMetadata([])).toThrowError();
});
});
const MOCKED_ORDER_FULFILLED_PAYLOAD: { const MOCKED_ORDER_FULFILLED_PAYLOAD: {
order: OrderFulfilledSubscriptionFragment; order: OrderFulfilledSubscriptionFragment;
} = { } = {
@ -137,6 +116,19 @@ const MOCKED_ORDER_FULFILLED_PAYLOAD: {
}; };
describe("AvataxOrderFulfilledPayloadTransformer", () => { describe("AvataxOrderFulfilledPayloadTransformer", () => {
it("throws error when no avataxId", () => {
const transformer = new AvataxOrderFulfilledPayloadTransformer(MOCK_AVATAX_CONFIG);
expect(() =>
transformer.transform({
...MOCKED_ORDER_FULFILLED_PAYLOAD,
order: {
...MOCKED_ORDER_FULFILLED_PAYLOAD.order,
avataxId: null,
},
})
).toThrow();
});
it("returns document type of SalesOrder when isDocumentRecordingEnabled is false", () => { it("returns document type of SalesOrder when isDocumentRecordingEnabled is false", () => {
const transformer = new AvataxOrderFulfilledPayloadTransformer({ const transformer = new AvataxOrderFulfilledPayloadTransformer({
...MOCK_AVATAX_CONFIG, ...MOCK_AVATAX_CONFIG,

View file

@ -1,27 +1,11 @@
import { DocumentType } from "avatax/lib/enums/DocumentType"; import { DocumentType } from "avatax/lib/enums/DocumentType";
import { OrderFulfilledSubscriptionFragment } from "../../../../generated/graphql"; import { z } from "zod";
import { AvataxConfig } from "../avatax-connection-schema"; import { AvataxConfig } from "../avatax-connection-schema";
import { import {
AvataxOrderFulfilledPayload, AvataxOrderFulfilledPayload,
AvataxOrderFulfilledTarget, AvataxOrderFulfilledTarget,
} from "./avatax-order-fulfilled-adapter"; } from "./avatax-order-fulfilled-adapter";
// * This is the key that we use to store the provider order id in the Saleor order metadata.
export const PROVIDER_ORDER_ID_KEY = "externalId";
export function getTransactionCodeFromMetadata(
metadata: OrderFulfilledSubscriptionFragment["privateMetadata"]
) {
const transactionCode = metadata.find((item) => item.key === PROVIDER_ORDER_ID_KEY);
if (!transactionCode) {
throw new Error("Transaction code not found");
}
return transactionCode.value;
}
export class AvataxOrderFulfilledPayloadTransformer { export class AvataxOrderFulfilledPayloadTransformer {
constructor(private readonly config: AvataxConfig) {} constructor(private readonly config: AvataxConfig) {}
private matchDocumentType(config: AvataxConfig): DocumentType { private matchDocumentType(config: AvataxConfig): DocumentType {
@ -32,7 +16,7 @@ export class AvataxOrderFulfilledPayloadTransformer {
return DocumentType.SalesInvoice; return DocumentType.SalesInvoice;
} }
transform({ order }: AvataxOrderFulfilledPayload): AvataxOrderFulfilledTarget { transform({ order }: AvataxOrderFulfilledPayload): AvataxOrderFulfilledTarget {
const transactionCode = getTransactionCodeFromMetadata(order.privateMetadata); const transactionCode = z.string().min(1).parse(order.avataxId);
return { return {
transactionCode, transactionCode,

View file

@ -7,6 +7,7 @@ import { orderCalculateTaxesSyncWebhook } from "./webhooks/order-calculate-taxes
import { orderCreatedAsyncWebhook } from "./webhooks/order-created"; import { orderCreatedAsyncWebhook } from "./webhooks/order-created";
import { orderFulfilledAsyncWebhook } from "./webhooks/order-fulfilled"; import { orderFulfilledAsyncWebhook } from "./webhooks/order-fulfilled";
import { REQUIRED_SALEOR_VERSION } from "../../../saleor-app"; import { REQUIRED_SALEOR_VERSION } from "../../../saleor-app";
import { orderCancelledAsyncWebhook } from "./webhooks/order-cancelled";
export default createManifestHandler({ export default createManifestHandler({
async manifestFactory({ appBaseUrl }) { async manifestFactory({ appBaseUrl }) {
@ -37,6 +38,7 @@ export default createManifestHandler({
checkoutCalculateTaxesSyncWebhook.getWebhookManifest(apiBaseURL), checkoutCalculateTaxesSyncWebhook.getWebhookManifest(apiBaseURL),
orderCreatedAsyncWebhook.getWebhookManifest(apiBaseURL), orderCreatedAsyncWebhook.getWebhookManifest(apiBaseURL),
orderFulfilledAsyncWebhook.getWebhookManifest(apiBaseURL), orderFulfilledAsyncWebhook.getWebhookManifest(apiBaseURL),
orderCancelledAsyncWebhook.getWebhookManifest(apiBaseURL),
], ],
}; };