refactor: avataxId instead of externalId
This commit is contained in:
parent
ac9acdf0c6
commit
e4ac0e7827
10 changed files with 33 additions and 55 deletions
|
@ -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
|
||||||
|
|
|
@ -47,10 +47,7 @@ fragment OrderFulfilledSubscription on Order {
|
||||||
amount
|
amount
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
privateMetadata {
|
avataxId: metafield(key: "avataxId")
|
||||||
key
|
|
||||||
value
|
|
||||||
}
|
|
||||||
lines {
|
lines {
|
||||||
...OrderLine
|
...OrderLine
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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),
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue