Skip to content

Commit

Permalink
feat(core): Implement TaxLineCalculationStrategy
Browse files Browse the repository at this point in the history
Relates to #307
  • Loading branch information
michaelbromley committed Dec 9, 2020
1 parent d2a971c commit 95663b4
Show file tree
Hide file tree
Showing 22 changed files with 698 additions and 127 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -1553,7 +1553,7 @@ export type ProductVariant = Node & {
assets: Array<Asset>;
price: Scalars['Int'];
currencyCode: CurrencyCode;
/** @deprecated price is now always exluding tax */
/** @deprecated price now always excludes tax */
priceIncludesTax: Scalars['Boolean'];
priceWithTax: Scalars['Int'];
taxRateApplied: TaxRate;
Expand Down Expand Up @@ -3291,6 +3291,8 @@ export enum LanguageCode {
* by taxRate.
*/
export type OrderTaxSummary = {
/** A description of this tax */
description: Scalars['String'];
/** The taxRate as a percentage */
taxRate: Scalars['Float'];
/** The total net price or OrderItems to which this taxRate applies */
Expand Down
4 changes: 3 additions & 1 deletion packages/common/src/generated-shop-types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1765,6 +1765,8 @@ export type OrderHistoryArgs = {
*/
export type OrderTaxSummary = {
__typename?: 'OrderTaxSummary';
/** A description of this tax */
description: Scalars['String'];
/** The taxRate as a percentage */
taxRate: Scalars['Float'];
/** The total net price or OrderItems to which this taxRate applies */
Expand Down Expand Up @@ -2123,7 +2125,7 @@ export type ProductVariant = Node & {
assets: Array<Asset>;
price: Scalars['Int'];
currencyCode: CurrencyCode;
/** @deprecated price is now always exluding tax */
/** @deprecated price now always excludes tax */
priceIncludesTax: Scalars['Boolean'];
priceWithTax: Scalars['Int'];
taxRateApplied: TaxRate;
Expand Down
4 changes: 3 additions & 1 deletion packages/common/src/generated-types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1705,7 +1705,7 @@ export type ProductVariant = Node & {
assets: Array<Asset>;
price: Scalars['Int'];
currencyCode: CurrencyCode;
/** @deprecated price is now always exluding tax */
/** @deprecated price now always excludes tax */
priceIncludesTax: Scalars['Boolean'];
priceWithTax: Scalars['Int'];
taxRateApplied: TaxRate;
Expand Down Expand Up @@ -3493,6 +3493,8 @@ export enum LanguageCode {
*/
export type OrderTaxSummary = {
__typename?: 'OrderTaxSummary';
/** A description of this tax */
description: Scalars['String'];
/** The taxRate as a percentage */
taxRate: Scalars['Float'];
/** The total net price or OrderItems to which this taxRate applies */
Expand Down
4 changes: 3 additions & 1 deletion packages/core/e2e/graphql/generated-e2e-admin-types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1553,7 +1553,7 @@ export type ProductVariant = Node & {
assets: Array<Asset>;
price: Scalars['Int'];
currencyCode: CurrencyCode;
/** @deprecated price is now always exluding tax */
/** @deprecated price now always excludes tax */
priceIncludesTax: Scalars['Boolean'];
priceWithTax: Scalars['Int'];
taxRateApplied: TaxRate;
Expand Down Expand Up @@ -3291,6 +3291,8 @@ export enum LanguageCode {
* by taxRate.
*/
export type OrderTaxSummary = {
/** A description of this tax */
description: Scalars['String'];
/** The taxRate as a percentage */
taxRate: Scalars['Float'];
/** The total net price or OrderItems to which this taxRate applies */
Expand Down
6 changes: 4 additions & 2 deletions packages/core/e2e/graphql/generated-e2e-shop-types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1713,6 +1713,8 @@ export type OrderHistoryArgs = {
* by taxRate.
*/
export type OrderTaxSummary = {
/** A description of this tax */
description: Scalars['String'];
/** The taxRate as a percentage */
taxRate: Scalars['Float'];
/** The total net price or OrderItems to which this taxRate applies */
Expand Down Expand Up @@ -2047,7 +2049,7 @@ export type ProductVariant = Node & {
assets: Array<Asset>;
price: Scalars['Int'];
currencyCode: CurrencyCode;
/** @deprecated price is now always exluding tax */
/** @deprecated price now always excludes tax */
priceIncludesTax: Scalars['Boolean'];
priceWithTax: Scalars['Int'];
taxRateApplied: TaxRate;
Expand Down Expand Up @@ -2829,7 +2831,7 @@ export type GetActiveOrderWithPriceDataQuery = {
taxLines: Array<Pick<TaxLine, 'taxRate' | 'description'>>;
}
>;
taxSummary: Array<Pick<OrderTaxSummary, 'taxRate' | 'taxBase' | 'taxTotal'>>;
taxSummary: Array<Pick<OrderTaxSummary, 'description' | 'taxRate' | 'taxBase' | 'taxTotal'>>;
}
>;
};
Expand Down
1 change: 1 addition & 0 deletions packages/core/e2e/graphql/shop-definitions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -338,6 +338,7 @@ export const GET_ACTIVE_ORDER_WITH_PRICE_DATA = gql`
}
}
taxSummary {
description
taxRate
taxBase
taxTotal
Expand Down
3 changes: 3 additions & 0 deletions packages/core/e2e/order-taxes.e2e-spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -159,16 +159,19 @@ describe('Order taxes', () => {

expect(activeOrder?.taxSummary).toEqual([
{
description: 'Standard Tax Europe',
taxRate: 20,
taxBase: 200,
taxTotal: 40,
},
{
description: 'Reduced Tax Europe',
taxRate: 10,
taxBase: 200,
taxTotal: 20,
},
{
description: 'Zero Tax Europe',
taxRate: 0,
taxBase: 200,
taxTotal: 0,
Expand Down
2 changes: 2 additions & 0 deletions packages/core/src/api/schema/common/order.type.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,8 @@ A summary of the taxes being applied to this order, grouped
by taxRate.
"""
type OrderTaxSummary {
"A description of this tax"
description: String!
"The taxRate as a percentage"
taxRate: Float!
"The total net price or OrderItems to which this taxRate applies"
Expand Down
2 changes: 1 addition & 1 deletion packages/core/src/config/config.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ export class ConfigService implements VendureConfig {
return this.activeConfig.paymentOptions;
}

get taxOptions(): TaxOptions {
get taxOptions(): Required<TaxOptions> {
return this.activeConfig.taxOptions;
}

Expand Down
2 changes: 2 additions & 0 deletions packages/core/src/config/default-config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import { defaultPromotionActions, defaultPromotionConditions } from './promotion
import { InMemorySessionCacheStrategy } from './session-cache/in-memory-session-cache-strategy';
import { defaultShippingCalculator } from './shipping-method/default-shipping-calculator';
import { defaultShippingEligibilityChecker } from './shipping-method/default-shipping-eligibility-checker';
import { DefaultTaxLineCalculationStrategy } from './tax/default-tax-line-calculation-strategy';
import { DefaultTaxZoneStrategy } from './tax/default-tax-zone-strategy';
import { RuntimeVendureConfig } from './vendure-config';

Expand Down Expand Up @@ -118,6 +119,7 @@ export const defaultConfig: RuntimeVendureConfig = {
},
taxOptions: {
taxZoneStrategy: new DefaultTaxZoneStrategy(),
taxLineCalculationStrategy: new DefaultTaxLineCalculationStrategy(),
},
importExportOptions: {
importAssetsDir: __dirname,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { TaxLine } from '@vendure/common/lib/generated-types';

import { CalculateTaxLinesArgs, TaxLineCalculationStrategy } from './tax-line-calculation-strategy';

/**
* @description
* The default {@link TaxLineCalculationStrategy} which applies a single TaxLine to the OrderItem
* based on the applicable {@link TaxRate}.
*
* @docsCategory tax
*/
export class DefaultTaxLineCalculationStrategy implements TaxLineCalculationStrategy {
calculate(args: CalculateTaxLinesArgs): TaxLine[] {
const { orderItem, applicableTaxRate } = args;
return [applicableTaxRate.apply(orderItem.proratedUnitPrice)];
}
}
47 changes: 47 additions & 0 deletions packages/core/src/config/tax/tax-line-calculation-strategy.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import { TaxLine } from '@vendure/common/lib/generated-types';

import { RequestContext } from '../../api/common/request-context';
import { InjectableStrategy } from '../../common/types/injectable-strategy';
import { OrderItem } from '../../entity/order-item/order-item.entity';
import { OrderLine } from '../../entity/order-line/order-line.entity';
import { Order } from '../../entity/order/order.entity';
import { TaxRate } from '../../entity/tax-rate/tax-rate.entity';

/**
* @description
* This strategy defines how the TaxLines on OrderItems are calculated. By default,
* the {@link DefaultTaxLineCalculationStrategy} is used, which directly applies
* a single TaxLine based on the applicable {@link TaxRate}.
*
* However, custom strategies may use any suitable method for calculating TaxLines.
* For example, a third-party tax API or a lookup of a custom tax table may be used.
*
* @docsCategory tax
* @docsPage TaxLineCalculationStrategy
* @docsWeight 0
*/
export interface TaxLineCalculationStrategy extends InjectableStrategy {
/**
* @description
* This method is called when calculating the Order prices. Since it will be called
* whenever an Order is modified in some way (adding/removing items, applying promotions,
* setting ShippingMethod etc), care should be taken so that calling the function does
* not adversely impact overall performance. For example, by using caching and only
* calling external APIs when absolutely necessary.
*/
calculate(args: CalculateTaxLinesArgs): TaxLine[] | Promise<TaxLine[]>;
}

/**
* @description
*
* @docsCategory tax
* @docsPage TaxLineCalculationStrategy
*/
export interface CalculateTaxLinesArgs {
ctx: RequestContext;
order: Order;
orderLine: OrderLine;
orderItem: OrderItem;
applicableTaxRate: TaxRate;
}
11 changes: 10 additions & 1 deletion packages/core/src/config/vendure-config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ import { PromotionCondition } from './promotion/promotion-condition';
import { SessionCacheStrategy } from './session-cache/session-cache-strategy';
import { ShippingCalculator } from './shipping-method/shipping-calculator';
import { ShippingEligibilityChecker } from './shipping-method/shipping-eligibility-checker';
import { TaxLineCalculationStrategy } from './tax/tax-line-calculation-strategy';
import { TaxZoneStrategy } from './tax/tax-zone-strategy';

/**
Expand Down Expand Up @@ -599,7 +600,14 @@ export interface TaxOptions {
*
* @default DefaultTaxZoneStrategy
*/
taxZoneStrategy: TaxZoneStrategy;
taxZoneStrategy?: TaxZoneStrategy;
/**
* @description
* Defines the strategy used to calculate the TaxLines added to OrderItems.
*
* @default DefaultTaxLineCalculationStrategy
*/
taxLineCalculationStrategy?: TaxLineCalculationStrategy;
}

/**
Expand Down Expand Up @@ -840,6 +848,7 @@ export interface RuntimeVendureConfig extends Required<VendureConfig> {
promotionOptions: Required<PromotionOptions>;
shippingOptions: Required<ShippingOptions>;
workerOptions: Required<WorkerOptions>;
taxOptions: Required<TaxOptions>;
}

type DeepPartialSimple<T> = {
Expand Down
Loading

0 comments on commit 95663b4

Please sign in to comment.