feat: disable document recording (#803)

* feat:  add disable document recording

* build: 👷 add changeset

* refactor: ♻️ address feedback

* feat: 💄 increase margin on HelperText

* refactor: ♻️ add default value for isDocumentRecordingEnabled
This commit is contained in:
Adrian Pilarczyk 2023-07-25 15:01:08 +02:00 committed by GitHub
parent 1b47ad22da
commit ce608872bd
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
13 changed files with 125 additions and 24 deletions

View file

@ -0,0 +1,5 @@
---
"saleor-app-taxes": minor
---
Added "document recording" toggle. It is turned on by default. When turned off, the document type of all Avatax transactions change to "SalesOrder", making them not record. Read more about document recording [here](https://developer.avalara.com/ecommerce-integration-guide/sales-tax-badge/designing/disable-document-recording/).

View file

@ -14,6 +14,7 @@ const mockedProviders: ProviderConnections = [
companyCode: "DEFAULT",
isAutocommit: false,
isSandbox: true,
isDocumentRecordingEnabled: true,
name: "avatax-1",
shippingTaxCode: "FR000000",
credentials: {

View file

@ -6,6 +6,7 @@ const defaultAvataxConfig: AvataxConfig = {
isSandbox: true,
name: "Avatax-1",
shippingTaxCode: "FR000000",
isDocumentRecordingEnabled: true,
address: {
country: "US",
zip: "95008",

View file

@ -27,6 +27,7 @@ export const avataxConfigSchema = z
companyCode: z.string().optional(),
isAutocommit: z.boolean(),
shippingTaxCode: z.string().optional(),
isDocumentRecordingEnabled: z.boolean().default(true),
address: addressSchema,
})
.merge(baseAvataxConfigSchema);
@ -38,6 +39,7 @@ export const defaultAvataxConfig: AvataxConfig = {
companyCode: "",
isSandbox: false,
isAutocommit: false,
isDocumentRecordingEnabled: true,
shippingTaxCode: "",
credentials: {
username: "",

View file

@ -1,11 +1,25 @@
import { describe, expect, it } from "vitest";
import { AvataxCalculateTaxesMockGenerator } from "./avatax-calculate-taxes-mock-generator";
import { AvataxCalculateTaxesPayloadTransformer } from "./avatax-calculate-taxes-payload-transformer";
import { DocumentType } from "avatax/lib/enums/DocumentType";
const mockGenerator = new AvataxCalculateTaxesMockGenerator();
const avataxConfigMock = mockGenerator.generateAvataxConfig();
describe("AvataxCalculateTaxesPayloadTransformer", () => {
it("returns document type of SalesInvoice", () => {
const taxBaseMock = mockGenerator.generateTaxBase();
const matchesMock = mockGenerator.generateTaxCodeMatches();
const payload = new AvataxCalculateTaxesPayloadTransformer().transform(
taxBaseMock,
avataxConfigMock,
matchesMock
);
expect(payload.model.type).toBe(DocumentType.SalesOrder);
});
it("when discounts, calculates the sum of discounts", () => {
const mockGenerator = new AvataxCalculateTaxesMockGenerator();
const avataxConfigMock = mockGenerator.generateAvataxConfig();
const taxBaseMock = mockGenerator.generateTaxBase({ discounts: [{ amount: { amount: 10 } }] });
const matchesMock = mockGenerator.generateTaxCodeMatches();
@ -18,8 +32,6 @@ describe("AvataxCalculateTaxesPayloadTransformer", () => {
expect(payload.model.discount).toEqual(10);
});
it("when no discounts, the sum of discount is 0", () => {
const mockGenerator = new AvataxCalculateTaxesMockGenerator();
const avataxConfigMock = mockGenerator.generateAvataxConfig();
const taxBaseMock = mockGenerator.generateTaxBase();
const matchesMock = mockGenerator.generateTaxCodeMatches();

View file

@ -8,6 +8,16 @@ import { AvataxTaxCodeMatches } from "../tax-code/avatax-tax-code-match-reposito
import { AvataxCalculateTaxesPayloadLinesTransformer } from "./avatax-calculate-taxes-payload-lines-transformer";
export class AvataxCalculateTaxesPayloadTransformer {
private matchDocumentType(config: AvataxConfig): DocumentType {
/*
* * For calculating taxes, we always use DocumentType.SalesOrder because it doesn't cause transaction recording.
* * The full flow is described here: https://developer.avalara.com/ecommerce-integration-guide/sales-tax-badge/design-document-workflow/should-i-commit/
* * config.isDocumentRecordingEnabledEnabled is used to determine if the transaction should be recorded (hence if the document type should be SalesOrder).
* * Given that we never want to record the transaction in calculate taxes, we always return DocumentType.SalesOrder.
*/
return DocumentType.SalesOrder;
}
transform(
taxBase: TaxBaseFragment,
avataxConfig: AvataxConfig,
@ -17,7 +27,7 @@ export class AvataxCalculateTaxesPayloadTransformer {
return {
model: {
type: DocumentType.SalesOrder,
type: this.matchDocumentType(avataxConfig),
customerCode: taxBase.sourceObject.user?.id ?? "",
companyCode: avataxConfig.companyCode,
// * commit: If true, the transaction will be committed immediately after it is created. See: https://developer.avalara.com/communications/dev-guide_rest_v2/commit-uncommit

View file

@ -1,6 +1,7 @@
import { describe, expect, it } from "vitest";
import { AvataxOrderCreatedMockGenerator } from "./avatax-order-created-mock-generator";
import { AvataxOrderCreatedPayloadTransformer } from "./avatax-order-created-payload-transformer";
import { DocumentType } from "avatax/lib/enums/DocumentType";
const mockGenerator = new AvataxOrderCreatedMockGenerator();
@ -16,12 +17,29 @@ const discountedOrderMock = mockGenerator.generateOrder({
],
});
const transformer = new AvataxOrderCreatedPayloadTransformer();
export const avataxConfigMock = mockGenerator.generateAvataxConfig();
describe("AvataxOrderCreatedPayloadTransformer", () => {
it("returns lines with discounted: true when there are discounts", () => {
const transformer = new AvataxOrderCreatedPayloadTransformer();
it("returns document type of SalesInvoice when isDocumentRecordingEnabled is true", () => {
const payload = transformer.transform(orderMock, avataxConfigMock, []);
expect(payload.model.type).toBe(DocumentType.SalesInvoice);
}),
it("returns document type of SalesOrder when isDocumentRecordingEnabled is false", () => {
const payload = transformer.transform(
orderMock,
{
...avataxConfigMock,
isDocumentRecordingEnabled: false,
},
[]
);
expect(payload.model.type).toBe(DocumentType.SalesOrder);
});
it("returns lines with discounted: true when there are discounts", () => {
const payload = transformer.transform(discountedOrderMock, avataxConfigMock, []);
const linesWithoutShipping = payload.model.lines.slice(0, -1);
@ -30,7 +48,6 @@ describe("AvataxOrderCreatedPayloadTransformer", () => {
expect(check).toBe(true);
});
it("returns lines with discounted: false when there are no discounts", () => {
const transformer = new AvataxOrderCreatedPayloadTransformer();
const payload = transformer.transform(orderMock, avataxConfigMock, []);
const linesWithoutShipping = payload.model.lines.slice(0, -1);

View file

@ -10,6 +10,14 @@ import { AvataxOrderCreatedPayloadLinesTransformer } from "./avatax-order-create
export const SHIPPING_ITEM_CODE = "Shipping";
export class AvataxOrderCreatedPayloadTransformer {
private matchDocumentType(config: AvataxConfig): DocumentType {
if (!config.isDocumentRecordingEnabled) {
// isDocumentRecordingEnabled = false changes all the DocTypes within your AvaTax requests to SalesOrder. This will stop any transaction from being recorded within AvaTax.
return DocumentType.SalesOrder;
}
return DocumentType.SalesInvoice;
}
transform(
order: OrderCreatedSubscriptionFragment,
avataxConfig: AvataxConfig,
@ -19,7 +27,7 @@ export class AvataxOrderCreatedPayloadTransformer {
return {
model: {
type: DocumentType.SalesInvoice,
type: this.matchDocumentType(avataxConfig),
customerCode:
order.user?.id ??
"" /* In Saleor Avatax plugin, the customer code is 0. In Taxes App, we set it to the user id. */,

View file

@ -12,6 +12,7 @@ import {
const MOCK_AVATAX_CONFIG: AvataxConfig = {
companyCode: "DEFAULT",
isDocumentRecordingEnabled: true,
isAutocommit: false,
isSandbox: true,
name: "Avatax-1",
@ -129,8 +130,6 @@ describe("getTransactionCodeFromMetadata", () => {
});
});
const transformer = new AvataxOrderFulfilledPayloadTransformer(MOCK_AVATAX_CONFIG);
const MOCKED_ORDER_FULFILLED_PAYLOAD: {
order: OrderFulfilledSubscriptionFragment;
} = {
@ -138,7 +137,26 @@ const MOCKED_ORDER_FULFILLED_PAYLOAD: {
};
describe("AvataxOrderFulfilledPayloadTransformer", () => {
it("returns document type of SalesOrder when isDocumentRecordingEnabled is false", () => {
const transformer = new AvataxOrderFulfilledPayloadTransformer({
...MOCK_AVATAX_CONFIG,
isDocumentRecordingEnabled: false,
});
const payload = transformer.transform(MOCKED_ORDER_FULFILLED_PAYLOAD);
expect(payload.documentType).toBe(DocumentType.SalesOrder);
}),
it("returns document type of SalesInvoice when isDocumentRecordingEnabled is true", () => {
const transformer = new AvataxOrderFulfilledPayloadTransformer(MOCK_AVATAX_CONFIG);
const payload = transformer.transform(MOCKED_ORDER_FULFILLED_PAYLOAD);
expect(payload.documentType).toBe(DocumentType.SalesInvoice);
}),
it("returns transformed payload", () => {
const transformer = new AvataxOrderFulfilledPayloadTransformer(MOCK_AVATAX_CONFIG);
const mappedPayload = transformer.transform(MOCKED_ORDER_FULFILLED_PAYLOAD);
expect(mappedPayload).toEqual({

View file

@ -24,13 +24,20 @@ export function getTransactionCodeFromMetadata(
export class AvataxOrderFulfilledPayloadTransformer {
constructor(private readonly config: AvataxConfig) {}
private matchDocumentType(config: AvataxConfig): DocumentType {
if (!config.isDocumentRecordingEnabled) {
return DocumentType.SalesOrder;
}
return DocumentType.SalesInvoice;
}
transform({ order }: AvataxOrderFulfilledPayload): AvataxOrderFulfilledTarget {
const transactionCode = getTransactionCodeFromMetadata(order.privateMetadata);
return {
transactionCode,
companyCode: this.config.companyCode ?? "",
documentType: DocumentType.SalesInvoice,
documentType: this.matchDocumentType(this.config),
model: {
commit: true,
},

View file

@ -121,7 +121,24 @@ export const AvataxConfigurationCredentialsFragment = (
}
name="isSandbox"
/>
<AppToggle
control={control}
label="Document recording"
helperText={
<HelperText>
When turned off, the document type will always be set to <i>SalesOrder</i>. This
means the transactions will not be recorded in Avatax. Read more{" "}
<TextLink
href="https://developer.avalara.com/ecommerce-integration-guide/sales-tax-badge/designing/disable-document-recording/"
newTab
>
here
</TextLink>
.
</HelperText>
}
name="isDocumentRecordingEnabled"
/>
<AppToggle
control={control}
label="Autocommit"

View file

@ -12,6 +12,8 @@ export const HelperText = ({
<Text
color={disabled ? "textNeutralDisabled" : "textNeutralSubdued"}
fontWeight={"captionLarge"}
marginTop={2}
as="p"
>
{children}
</Text>

View file

@ -21,6 +21,7 @@ const mockedProviders: ProviderConnections = [
provider: "avatax",
id: "1",
config: {
isDocumentRecordingEnabled: true,
companyCode: "DEFAULT",
isAutocommit: false,
isSandbox: true,