feat: Avatax metadata tax calculation date (#843)
* feat: ✨ add metadata tax calculation date * build: 👷 add changeset
This commit is contained in:
parent
2b073e7113
commit
6106e1d5fa
5 changed files with 78 additions and 2 deletions
5
.changeset/ninety-lobsters-design.md
Normal file
5
.changeset/ninety-lobsters-design.md
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
---
|
||||||
|
"saleor-app-taxes": minor
|
||||||
|
---
|
||||||
|
|
||||||
|
Added support for reading the tax calculation date from metadata field `avataxTaxCalculationDate`. The value has to be valid UTC datetime string (e.g. "2021-08-31T13:00:00.000Z").
|
|
@ -65,6 +65,7 @@ fragment OrderConfirmedSubscription on Order {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
avataxEntityCode: metafield(key: "avataxEntityCode")
|
avataxEntityCode: metafield(key: "avataxEntityCode")
|
||||||
|
avataxTaxCalculationDate: metafield(key: "avataxTaxCalculationDate")
|
||||||
}
|
}
|
||||||
fragment OrderConfirmedEventSubscription on Event {
|
fragment OrderConfirmedEventSubscription on Event {
|
||||||
__typename
|
__typename
|
||||||
|
|
|
@ -0,0 +1,31 @@
|
||||||
|
import { describe, expect, it } from "vitest";
|
||||||
|
import { OrderConfirmedSubscriptionFragment } from "../../../../generated/graphql";
|
||||||
|
import { AvataxOrderConfirmedCalculationDateResolver } from "./avatax-order-confirmed-calculation-date-resolver";
|
||||||
|
|
||||||
|
const resolver = new AvataxOrderConfirmedCalculationDateResolver();
|
||||||
|
|
||||||
|
describe("AvataxOrderConfirmedCalculationDateResolver", () => {
|
||||||
|
it("should return the metadata tax calculation date if it is set", () => {
|
||||||
|
const order = {
|
||||||
|
avataxTaxCalculationDate: "2021-01-01T00:00:00.000Z",
|
||||||
|
created: "2021-01-02T00:00:00.000Z",
|
||||||
|
} as any as OrderConfirmedSubscriptionFragment;
|
||||||
|
|
||||||
|
expect(resolver.resolve(order)).toEqual(new Date("2021-01-01T00:00:00.000Z"));
|
||||||
|
});
|
||||||
|
it("should fallback to order created when metadata tax calculation date is not a string datetime", () => {
|
||||||
|
const order = {
|
||||||
|
avataxTaxCalculationDate: "not-a-datetime",
|
||||||
|
created: "2021-01-02T00:00:00.000Z",
|
||||||
|
} as any as OrderConfirmedSubscriptionFragment;
|
||||||
|
|
||||||
|
expect(resolver.resolve(order)).toEqual(new Date("2021-01-02T00:00:00.000Z"));
|
||||||
|
});
|
||||||
|
it("should return the order creation date if the metadata tax calculation date is not set", () => {
|
||||||
|
const order = {
|
||||||
|
created: "2021-01-02T00:00:00.000Z",
|
||||||
|
} as any as OrderConfirmedSubscriptionFragment;
|
||||||
|
|
||||||
|
expect(resolver.resolve(order)).toEqual(new Date("2021-01-02T00:00:00.000Z"));
|
||||||
|
});
|
||||||
|
});
|
|
@ -0,0 +1,33 @@
|
||||||
|
import { z } from "zod";
|
||||||
|
import { OrderConfirmedSubscriptionFragment } from "../../../../generated/graphql";
|
||||||
|
import { createLogger } from "../../../lib/logger";
|
||||||
|
|
||||||
|
export class AvataxOrderConfirmedCalculationDateResolver {
|
||||||
|
private logger = createLogger({
|
||||||
|
name: "AvataxOrderConfirmedCalculationDateResolver",
|
||||||
|
});
|
||||||
|
|
||||||
|
resolve(order: OrderConfirmedSubscriptionFragment): Date {
|
||||||
|
if (!order.avataxTaxCalculationDate) {
|
||||||
|
this.logger.info("No tax calculation date provided. Falling back to order created date.");
|
||||||
|
return new Date(order.created);
|
||||||
|
}
|
||||||
|
|
||||||
|
// UTC datetime string, e.g. "2021-08-31T13:00:00.000Z"
|
||||||
|
const taxCalculationParse = z.string().datetime().safeParse(order.avataxTaxCalculationDate);
|
||||||
|
|
||||||
|
if (taxCalculationParse.success) {
|
||||||
|
// The user is able to pass other tax calculation date than the order creation date.
|
||||||
|
this.logger.info(
|
||||||
|
"Valid UTC tax calculation date found in metadata. Using it for tax calculation."
|
||||||
|
);
|
||||||
|
return new Date(taxCalculationParse.data);
|
||||||
|
} else {
|
||||||
|
this.logger.warn(
|
||||||
|
`The tax calculation date ${order.avataxTaxCalculationDate} is not a valid UTC datetime. Falling back to order created date.`
|
||||||
|
);
|
||||||
|
|
||||||
|
return new Date(order.created);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -7,6 +7,7 @@ import { AvataxConfig } from "../avatax-connection-schema";
|
||||||
import { AvataxTaxCodeMatches } from "../tax-code/avatax-tax-code-match-repository";
|
import { AvataxTaxCodeMatches } from "../tax-code/avatax-tax-code-match-repository";
|
||||||
import { AvataxOrderConfirmedPayloadLinesTransformer } from "./avatax-order-confirmed-payload-lines-transformer";
|
import { AvataxOrderConfirmedPayloadLinesTransformer } from "./avatax-order-confirmed-payload-lines-transformer";
|
||||||
import { AvataxEntityTypeMatcher } from "../avatax-entity-type-matcher";
|
import { AvataxEntityTypeMatcher } from "../avatax-entity-type-matcher";
|
||||||
|
import { AvataxOrderConfirmedCalculationDateResolver } from "./avatax-order-confirmed-calculation-date-resolver";
|
||||||
|
|
||||||
export const SHIPPING_ITEM_CODE = "Shipping";
|
export const SHIPPING_ITEM_CODE = "Shipping";
|
||||||
|
|
||||||
|
@ -19,15 +20,20 @@ export class AvataxOrderConfirmedPayloadTransformer {
|
||||||
|
|
||||||
return DocumentType.SalesInvoice;
|
return DocumentType.SalesInvoice;
|
||||||
}
|
}
|
||||||
|
|
||||||
async transform(
|
async transform(
|
||||||
order: OrderConfirmedSubscriptionFragment,
|
order: OrderConfirmedSubscriptionFragment,
|
||||||
avataxConfig: AvataxConfig,
|
avataxConfig: AvataxConfig,
|
||||||
matches: AvataxTaxCodeMatches
|
matches: AvataxTaxCodeMatches
|
||||||
): Promise<CreateTransactionArgs> {
|
): Promise<CreateTransactionArgs> {
|
||||||
const linesTransformer = new AvataxOrderConfirmedPayloadLinesTransformer();
|
|
||||||
const avataxClient = new AvataxClient(avataxConfig);
|
const avataxClient = new AvataxClient(avataxConfig);
|
||||||
|
|
||||||
|
const linesTransformer = new AvataxOrderConfirmedPayloadLinesTransformer();
|
||||||
|
const dateResolver = new AvataxOrderConfirmedCalculationDateResolver();
|
||||||
const entityTypeMatcher = new AvataxEntityTypeMatcher({ client: avataxClient });
|
const entityTypeMatcher = new AvataxEntityTypeMatcher({ client: avataxClient });
|
||||||
|
|
||||||
const entityUseCode = await entityTypeMatcher.match(order.avataxEntityCode);
|
const entityUseCode = await entityTypeMatcher.match(order.avataxEntityCode);
|
||||||
|
const date = dateResolver.resolve(order);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
model: {
|
model: {
|
||||||
|
@ -47,7 +53,7 @@ export class AvataxOrderConfirmedPayloadTransformer {
|
||||||
currencyCode: order.total.currency,
|
currencyCode: order.total.currency,
|
||||||
email: order.user?.email ?? "",
|
email: order.user?.email ?? "",
|
||||||
lines: linesTransformer.transform(order, avataxConfig, matches),
|
lines: linesTransformer.transform(order, avataxConfig, matches),
|
||||||
date: new Date(order.created),
|
date,
|
||||||
discount: discountUtils.sumDiscounts(
|
discount: discountUtils.sumDiscounts(
|
||||||
order.discounts.map((discount) => discount.amount.amount)
|
order.discounts.map((discount) => discount.amount.amount)
|
||||||
),
|
),
|
||||||
|
|
Loading…
Reference in a new issue