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")
|
||||
avataxTaxCalculationDate: metafield(key: "avataxTaxCalculationDate")
|
||||
}
|
||||
fragment OrderConfirmedEventSubscription on Event {
|
||||
__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 { AvataxOrderConfirmedPayloadLinesTransformer } from "./avatax-order-confirmed-payload-lines-transformer";
|
||||
import { AvataxEntityTypeMatcher } from "../avatax-entity-type-matcher";
|
||||
import { AvataxOrderConfirmedCalculationDateResolver } from "./avatax-order-confirmed-calculation-date-resolver";
|
||||
|
||||
export const SHIPPING_ITEM_CODE = "Shipping";
|
||||
|
||||
|
@ -19,15 +20,20 @@ export class AvataxOrderConfirmedPayloadTransformer {
|
|||
|
||||
return DocumentType.SalesInvoice;
|
||||
}
|
||||
|
||||
async transform(
|
||||
order: OrderConfirmedSubscriptionFragment,
|
||||
avataxConfig: AvataxConfig,
|
||||
matches: AvataxTaxCodeMatches
|
||||
): Promise<CreateTransactionArgs> {
|
||||
const linesTransformer = new AvataxOrderConfirmedPayloadLinesTransformer();
|
||||
const avataxClient = new AvataxClient(avataxConfig);
|
||||
|
||||
const linesTransformer = new AvataxOrderConfirmedPayloadLinesTransformer();
|
||||
const dateResolver = new AvataxOrderConfirmedCalculationDateResolver();
|
||||
const entityTypeMatcher = new AvataxEntityTypeMatcher({ client: avataxClient });
|
||||
|
||||
const entityUseCode = await entityTypeMatcher.match(order.avataxEntityCode);
|
||||
const date = dateResolver.resolve(order);
|
||||
|
||||
return {
|
||||
model: {
|
||||
|
@ -47,7 +53,7 @@ export class AvataxOrderConfirmedPayloadTransformer {
|
|||
currencyCode: order.total.currency,
|
||||
email: order.user?.email ?? "",
|
||||
lines: linesTransformer.transform(order, avataxConfig, matches),
|
||||
date: new Date(order.created),
|
||||
date,
|
||||
discount: discountUtils.sumDiscounts(
|
||||
order.discounts.map((discount) => discount.amount.amount)
|
||||
),
|
||||
|
|
Loading…
Reference in a new issue