diff --git a/docs/content/modules/taxes/backend/create-tax-provider.md b/docs/content/modules/taxes/backend/create-tax-provider.md new file mode 100644 index 0000000000..f58f5c8f3f --- /dev/null +++ b/docs/content/modules/taxes/backend/create-tax-provider.md @@ -0,0 +1,212 @@ +--- +description: 'Learn how to create a tax provider. You can create a tax provider in a Medusa backend or a plugin.' +addHowToData: true +--- + +# How to Create a Tax Provider + +In this document, you’ll learn how to create a tax provider. + +## Overview + +A tax provider is used to retrieve the tax lines in a cart. The Medusa backend provides a default `system` provider. You can create your own tax provider, either in a plugin or directly in your Medusa backend, then use it in any region. + +--- + +## Step 1: Create Tax Provider Class + +A tax provider class should be defined in a TypeScript or JavaScript file under `src/services` and the class should extend `AbstractTaxService` imported from `@medusajs/medusa`. + +For example, you can create the file `src/services/my-tax.ts` with the following content: + +```ts title=src/services/my-tax.ts +import { + AbstractTaxService, + ItemTaxCalculationLine, + ShippingTaxCalculationLine, + TaxCalculationContext, +} from "@medusajs/medusa" +import { + ProviderTaxLine, +} from "@medusajs/medusa/dist/types/tax-service" + +class MyTaxService extends AbstractTaxService { + async getTaxLines( + itemLines: ItemTaxCalculationLine[], + shippingLines: ShippingTaxCalculationLine[], + context: TaxCalculationContext): + Promise { + throw new Error("Method not implemented.") + } +} + +export default MyTaxService +``` + +Since the class extends `AbstractTaxService`, it must implement its abstract method `getTaxLines`, which is explained later in this guide. + +### Using a Constructor + +You can use a constructor to access services and resources registered in the dependency container using dependency injection. For example: + +```ts title=src/services/my-tax.ts +// ... +import { LineItemService } from "@medusajs/medusa" + +type InjectedDependencies = { + lineItemService: LineItemService +} + +class MyTaxService extends AbstractTaxService { + protected readonly lineItemService_: LineItemService + + constructor({ lineItemService }: InjectedDependencies) { + super() + this.lineItemService_ = lineItemService + } + + // ... +} + +export default MyTaxService +``` + +--- + +## Step 2: Define Identifier + +Every tax provider must have a unique identifier. The identifier is defined as a static property in the class, and its value is used when registering the tax provider in the database and in the dependency container. + +Add the static property `identifier` in your tax provider class: + +```ts title=src/services/my-tax.ts +class MyTaxService extends AbstractTaxService { + static identifer = "my-tax" + // ... +} +``` + +Make sure to change `my-tax` to the name of your tax provider. + +--- + +## Step 3: Implement getTaxLines Method + +The `getTaxLines` method is the only required method in a tax provider. It’s used when retrieving the tax lines for line items and shipping methods, typically during checkout or when calculating totals, for example, for orders, swaps, or returns. + +The method accepts three parameters. The first parameter is an array of tax calculation objects for line items. Each object having the following properties: + +- `item`: a line item object. +- `rates`: an array of objects, each object having the following properties: + - `rate`: an optional number indicating the tax rate. + - `name`: a string indicating the name of the tax rate. + - `code`: an optional string indicating the tax code. + +The second parameter is an array of tax calculation objects for shipping methods. Each object having the following properties: + +- `shipping_method`: a shipping method object. +- `rates`: an array of objects, each object having the following properties: + - `rate`: an optional number indicating the tax rate. + - `name`: a string indicating the name of the tax rate. + - `code`: an optional string indicating the tax code. + +The third parameter is a context object that can be helpful for the tax calculation. The object can have the following properties: + +- `shipping_address`: an optional address object used for shipping. +- `customer`: an optional customer object. +- `region`: an optional region object. +- `is_return`: a boolean value that determines whether the taxes are being calculated for a return flow. +- `shipping_methods`: an array of shipping methods being used in the current context. +- `allocation_map`: an object that indicates the gift cards and discounts applied on line items. Each object key or property is an ID of a line item, and the value is an object having the following properties: + - `gift_card`: an optional object indicating the gift card applied on the line item. + - `discount`: an optional object indicating the discount applied on the line item. + +This method is expected to return an array of line item tax line or shipping method tax line objects. + +The line item tax line object has the following properties: + +- `rate`: a number indicating the tax rate. +- `name`: a string indicating the name of the tax rate. +- `code`: an optional string indicating the tax code. +- `item_id`: the ID of the line item. +- `metadata`: an optional object that can hold any necessary additional data to be added to the line item tax lines. + +The shipping method tax line object has the following properties: + +- `rate`: a number indicating the tax rate. +- `name`: a string indicating the name of the tax rate. +- `code`: an optional string indicating the tax code. +- `shipping_method_id`: the ID of the shipping method. +- `metadata`: an optional object that can hold any necessary additional data to be added to the shipping method tax lines. + +The returned array would be a combination of both the line item tax lines and shipping method tax lines. + +:::note + +The Medusa backend determines whether an object in the returned array is a shipping method tax line item, depending on the availability of the `shipping_method_id` attribute. For line items, it depends on the availability of the `item_id` attribute. + +::: + +For example, the `system` tax provider returns the tax calculation line items in the first parameter and the tax calculation shipping methods in the second parameter as is: + +```ts title=src/services/my-tax.ts +// ... + +class SystemTaxService extends AbstractTaxService { + // ... + + async getTaxLines( + itemLines: ItemTaxCalculationLine[], + shippingLines: ShippingTaxCalculationLine[], + context: TaxCalculationContext + ): Promise { + let taxLines: ProviderTaxLine[] = itemLines.flatMap((l) => { + return l.rates.map((r) => ({ + rate: r.rate || 0, + name: r.name, + code: r.code, + item_id: l.item.id, + })) + }) + + taxLines = taxLines.concat( + shippingLines.flatMap((l) => { + return l.rates.map((r) => ({ + rate: r.rate || 0, + name: r.name, + code: r.code, + shipping_method_id: l.shipping_method.id, + })) + }) + ) + + return taxLines + } +} +``` + +--- + +## Step 3: Run the Build Command + +In the directory of the Medusa backend, run the `build` command to transpile the files in the `src` directory into the `dist` directory: + +```bash npm2yarn +npm run build +``` + +--- + +## Test it Out + +Run your backend to test it out: + +```bash npm2yarn +npm run start +``` + +Before you can test out your tax provider, you must enable it in a region. You can do that either using the [Medusa Admin dashboard](../../../user-guide/taxes/manage.md#change-tax-provider) or using the [Update Region admin endpoint](https://docs.medusajs.com/api/admin#tag/Regions/operation/PostRegionsRegion). + +Then, you can test out the tax provider by simulating a checkout process in that region. You should see the line item tax lines in the cart’s `items`, as each item object has a `tax_lines` array which are the tax lines that you return in the `getTaxLines` method for line items. + +Similarly, you should see the shipping method tax lines in the cart’s `shipping_methods`, as each shipping method object has a `tax_lines` array which are the tax lines that you return in the `getTaxLines` method for shipping methods. diff --git a/docs/content/modules/taxes/overview.mdx b/docs/content/modules/taxes/overview.mdx index d011e5ed71..53fa22e48a 100644 --- a/docs/content/modules/taxes/overview.mdx +++ b/docs/content/modules/taxes/overview.mdx @@ -28,12 +28,11 @@ Customers can view calculated taxes during their checkout process.