Skip to content

Commit

Permalink
feat(core): Include address-based tax zone strategy (#3198)
Browse files Browse the repository at this point in the history
  • Loading branch information
martijnvdbrug authored Nov 7, 2024
1 parent 0cd0ef2 commit 5547128
Show file tree
Hide file tree
Showing 4 changed files with 112 additions and 1 deletion.
18 changes: 17 additions & 1 deletion license/signatures/version1/cla.json
Original file line number Diff line number Diff line change
Expand Up @@ -279,6 +279,22 @@
"created_at": "2024-10-31T08:42:52Z",
"repoId": 136938012,
"pullRequestNo": 3174
},
{
"name": "kkerti",
"id": 47832952,
"comment_id": 2458191015,
"created_at": "2024-11-05T21:33:05Z",
"repoId": 136938012,
"pullRequestNo": 3187
},
{
"name": "shingoaoyama1",
"id": 17615101,
"comment_id": 2459213307,
"created_at": "2024-11-06T10:15:37Z",
"repoId": 136938012,
"pullRequestNo": 3192
}
]
}
}
1 change: 1 addition & 0 deletions packages/core/src/config/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ export * from './system/health-check-strategy';
export * from './system/error-handler-strategy';
export * from './tax/default-tax-line-calculation-strategy';
export * from './tax/default-tax-zone-strategy';
export * from './tax/address-based-tax-zone-strategy';
export * from './tax/tax-line-calculation-strategy';
export * from './tax/tax-zone-strategy';
export * from './vendure-config';
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import { RequestContext, Zone, Channel, Order } from '@vendure/core';
import { describe, it, expect } from 'vitest';

import { Logger } from '../logger/vendure-logger';

import { AddressBasedTaxZoneStrategy } from './address-based-tax-zone-strategy';

describe('AddressBasedTaxZoneStrategy', () => {
const strategy = new AddressBasedTaxZoneStrategy();

const ctx = {} as RequestContext;
const defaultZone = { name: 'Default Zone' } as Zone;
const channel = { defaultTaxZone: defaultZone } as Channel;

const zones: Zone[] = [
defaultZone,
{ name: 'US Zone', members: [{ code: 'US' }] } as Zone,
{ name: 'DE Zone', members: [{ code: 'DE' }] } as Zone,
];

it('Determines zone based on billing address country', () => {
const order = {
billingAddress: { countryCode: 'US' },
shippingAddress: { countryCode: 'DE' },
} as Order;
const result = strategy.determineTaxZone(ctx, zones, channel, order);
expect(result.name).toBe('US Zone');
});

it('Determines zone based on shipping address if no billing address set', () => {
const order = { shippingAddress: { countryCode: 'DE' } } as Order;
const result = strategy.determineTaxZone(ctx, zones, channel, order);
expect(result.name).toBe('DE Zone');
});

it('Returns the default zone if no matching zone is found', () => {
const order = { billingAddress: { countryCode: 'FR' } } as Order;
const result = strategy.determineTaxZone(ctx, zones, channel, order);
expect(result.name).toBe('Default Zone');
});

it('Returns the default zone if no order is provided', () => {
const result = strategy.determineTaxZone(ctx, zones, channel);
expect(result.name).toBe('Default Zone');
});

it('Returns the default zone if no address is set on order', () => {
const order = {} as Order;
const result = strategy.determineTaxZone(ctx, zones, channel, order);
expect(result.name).toBe('Default Zone');
});
});
42 changes: 42 additions & 0 deletions packages/core/src/config/tax/address-based-tax-zone-strategy.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import { RequestContext } from '../../api/common/request-context';
import { Channel, Order, Zone } from '../../entity';
import { Logger } from '../logger/vendure-logger';

import { TaxZoneStrategy } from './tax-zone-strategy';

const loggerCtx = 'AddressBasedTaxZoneStrategy';

/**
* @description
* Address based {@link TaxZoneStrategy} which tries to find the applicable {@link Zone} based on the
* country of the billing address, or else the country of the shipping address of the Order.
*
* Returns the default {@link Channel}'s default tax zone if no applicable zone is found.
*
* @since 3.1.0
*
* :::info
*
* This is configured via `taxOptions.taxZoneStrategy = new AddressBasedTaxZoneStrategy()` in
* your VendureConfig.
*
* :::
*
* @docsCategory tax
*/
export class AddressBasedTaxZoneStrategy implements TaxZoneStrategy {
determineTaxZone(ctx: RequestContext, zones: Zone[], channel: Channel, order?: Order): Zone {
const countryCode = order?.billingAddress?.countryCode ?? order?.shippingAddress?.countryCode;
if (order && countryCode) {
const zone = zones.find(z => z.members?.find(member => member.code === countryCode));
if (zone) {
return zone;
}
Logger.debug(
`No tax zone found for country ${countryCode}. Returning default ${channel.defaultTaxZone.name} for order ${order.code}`,
loggerCtx,
);
}
return channel.defaultTaxZone;
}
}

0 comments on commit 5547128

Please sign in to comment.