@bisondesk/core-sdk 1.0.596 → 1.0.597

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (53) hide show
  1. package/lib/apis/country-delivery.d.ts +3 -0
  2. package/lib/apis/country-delivery.d.ts.map +1 -0
  3. package/lib/apis/{country-pricing.js → country-delivery.js} +3 -3
  4. package/lib/apis/country-delivery.js.map +1 -0
  5. package/lib/types/country-delivery.d.ts +18 -0
  6. package/lib/types/country-delivery.d.ts.map +1 -0
  7. package/lib/types/country-delivery.js +2 -0
  8. package/lib/types/country-delivery.js.map +1 -0
  9. package/lib/types/exchange-rates.d.ts +6 -0
  10. package/lib/types/exchange-rates.d.ts.map +1 -0
  11. package/lib/types/exchange-rates.js +2 -0
  12. package/lib/types/exchange-rates.js.map +1 -0
  13. package/lib/types/quote-settings.d.ts +4 -0
  14. package/lib/types/quote-settings.d.ts.map +1 -1
  15. package/lib/types/quote-settings.js.map +1 -1
  16. package/lib/types/vehicles.d.ts +10 -7
  17. package/lib/types/vehicles.d.ts.map +1 -1
  18. package/lib/types/vehicles.js.map +1 -1
  19. package/lib/utils/exchange-rates.d.ts +3 -0
  20. package/lib/utils/exchange-rates.d.ts.map +1 -0
  21. package/lib/utils/exchange-rates.js +15 -0
  22. package/lib/utils/exchange-rates.js.map +1 -0
  23. package/lib/utils/exchange-rates.test.d.ts +2 -0
  24. package/lib/utils/exchange-rates.test.d.ts.map +1 -0
  25. package/lib/utils/exchange-rates.test.js +23 -0
  26. package/lib/utils/exchange-rates.test.js.map +1 -0
  27. package/package.json +1 -1
  28. package/src/apis/{country-pricing.ts → country-delivery.ts} +5 -3
  29. package/src/types/country-delivery.ts +42 -0
  30. package/src/types/exchange-rates.ts +10 -0
  31. package/src/types/quote-settings.ts +4 -0
  32. package/src/types/vehicles.ts +38 -4
  33. package/src/utils/exchange-rates.test.ts +29 -0
  34. package/src/utils/exchange-rates.ts +32 -0
  35. package/tsconfig.tsbuildinfo +1 -1
  36. package/lib/apis/country-pricing.d.ts +0 -3
  37. package/lib/apis/country-pricing.d.ts.map +0 -1
  38. package/lib/apis/country-pricing.js.map +0 -1
  39. package/lib/types/country-pricing.d.ts +0 -16
  40. package/lib/types/country-pricing.d.ts.map +0 -1
  41. package/lib/types/country-pricing.js +0 -2
  42. package/lib/types/country-pricing.js.map +0 -1
  43. package/lib/utils/country-pricing.d.ts +0 -5
  44. package/lib/utils/country-pricing.d.ts.map +0 -1
  45. package/lib/utils/country-pricing.js +0 -17
  46. package/lib/utils/country-pricing.js.map +0 -1
  47. package/lib/utils/country-pricing.test.d.ts +0 -2
  48. package/lib/utils/country-pricing.test.d.ts.map +0 -1
  49. package/lib/utils/country-pricing.test.js +0 -65
  50. package/lib/utils/country-pricing.test.js.map +0 -1
  51. package/src/types/country-pricing.ts +0 -25
  52. package/src/utils/country-pricing.test.ts +0 -82
  53. package/src/utils/country-pricing.ts +0 -44
@@ -1,3 +0,0 @@
1
- import { CountryPricingRule } from '../types/country-pricing.js';
2
- export declare const listCountryPricingRules: (tenantId: string) => Promise<CountryPricingRule[]>;
3
- //# sourceMappingURL=country-pricing.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"country-pricing.d.ts","sourceRoot":"/","sources":["apis/country-pricing.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,kBAAkB,EAAE,MAAM,6BAA6B,CAAC;AAEjE,eAAO,MAAM,uBAAuB,GAAU,UAAU,MAAM,KAAG,OAAO,CAAC,kBAAkB,EAAE,CAgB5F,CAAC"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"country-pricing.js","sourceRoot":"/","sources":["apis/country-pricing.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,sBAAsB,EAAE,MAAM,kCAAkC,CAAC;AAC1E,OAAO,EAAE,MAAM,EAAE,MAAM,+BAA+B,CAAC;AACvD,OAAO,EAAE,YAAY,EAAE,MAAM,8BAA8B,CAAC;AAC5D,OAAO,KAAmB,MAAM,YAAY,CAAC;AAG7C,MAAM,CAAC,MAAM,uBAAuB,GAAG,KAAK,EAAE,QAAgB,EAAiC,EAAE;IAC/F,MAAM,IAAI,GAAG,MAAM,YAAY,EAAE,CAAC;IAClC,MAAM,GAAG,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC,eAAe,+BAA+B,CAAC;IAC1E,MAAM,QAAQ,GAAa,MAAM,KAAK,CAAC,GAAG,EAAE;QAC1C,OAAO,EAAE;YACP,aAAa,EAAE,IAAI;YACnB,CAAC,sBAAsB,CAAC,EAAE,QAAQ;SACnC;KACF,CAAC,CAAC;IAEH,IAAI,QAAQ,CAAC,EAAE,EAAE,CAAC;QAChB,OAAO,QAAQ,CAAC,IAAI,EAAS,CAAC;IAChC,CAAC;IAED,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC;IACnC,MAAM,IAAI,MAAM,CAAC,QAAQ,CAAC,UAAU,EAAE,EAAE,GAAG,EAAE,IAAI,EAAE,CAAC,CAAC;AACvD,CAAC,CAAC","sourcesContent":["import { TENANT_ID_ADMIN_HEADER } from '@bisondesk/commons-sdk/constants';\nimport { XError } from '@bisondesk/commons-sdk/errors';\nimport { getAdminAuth } from '@bisondesk/commons-sdk/fetch';\nimport fetch, { Response } from 'node-fetch';\nimport { CountryPricingRule } from '../types/country-pricing.js';\n\nexport const listCountryPricingRules = async (tenantId: string): Promise<CountryPricingRule[]> => {\n const auth = await getAdminAuth();\n const url = `${process.env.CORE_API_ORIGIN}/api/settings/country-pricing`;\n const response: Response = await fetch(url, {\n headers: {\n Authorization: auth,\n [TENANT_ID_ADMIN_HEADER]: tenantId,\n },\n });\n\n if (response.ok) {\n return response.json() as any;\n }\n\n const body = await response.text();\n throw new XError(response.statusText, { url, body });\n};\n"]}
@@ -1,16 +0,0 @@
1
- import { Categories } from '../constants.js';
2
- type DeliveryFields = {
3
- deliveryCostByCategory: Partial<Record<Categories, number>>;
4
- deliveryLocation: string;
5
- } | {
6
- deliveryCostByCategory?: never;
7
- deliveryLocation?: never;
8
- };
9
- export type CountryPricingRule = {
10
- countryCode: string;
11
- currency: string;
12
- rate: number;
13
- leasing?: boolean;
14
- } & DeliveryFields;
15
- export {};
16
- //# sourceMappingURL=country-pricing.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"country-pricing.d.ts","sourceRoot":"/","sources":["types/country-pricing.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAE7C,KAAK,cAAc,GACf;IAEE,sBAAsB,EAAE,OAAO,CAAC,MAAM,CAAC,UAAU,EAAE,MAAM,CAAC,CAAC,CAAC;IAE5D,gBAAgB,EAAE,MAAM,CAAC;CAC1B,GACD;IAAE,sBAAsB,CAAC,EAAE,KAAK,CAAC;IAAC,gBAAgB,CAAC,EAAE,KAAK,CAAA;CAAE,CAAC;AAEjE,MAAM,MAAM,kBAAkB,GAAG;IAC/B,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;IASjB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB,GAAG,cAAc,CAAC"}
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=country-pricing.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"country-pricing.js","sourceRoot":"/","sources":["types/country-pricing.ts"],"names":[],"mappings":"","sourcesContent":["import { Categories } from '../constants.js';\n\ntype DeliveryFields =\n | {\n /** Flat cost in `currency` per vehicle category, added after conversion. */\n deliveryCostByCategory: Partial<Record<Categories, number>>;\n /** Human-readable, e.g., \"Iquique (Chile)\". */\n deliveryLocation: string;\n }\n | { deliveryCostByCategory?: never; deliveryLocation?: never };\n\nexport type CountryPricingRule = {\n countryCode: string; // lower-cased ISO 3166-1 alpha-2 (e.g., \"cl\")\n currency: string; // ISO 4217 (e.g., \"USD\")\n /**\n * Fixed multiplier applied to a price expressed in the owning branch's\n * currency (`branch.currency`) to produce a price in `rule.currency`.\n * For a tenant whose primary branch is EUR, a Bolivia rule with\n * `currency: \"USD\"` carries `rate ≈ 1.08`. For a tenant whose primary\n * branch is USD, a Belgium rule with `currency: \"EUR\"` carries\n * `rate ≈ 0.92`.\n */\n rate: number;\n leasing?: boolean; // Override for leasing visibility\n} & DeliveryFields;\n"]}
@@ -1,5 +0,0 @@
1
- import { CountryPricingRule } from '../types/country-pricing.js';
2
- export declare const shouldApplyDeliveryCost: (rule: Pick<CountryPricingRule, "countryCode">, originCountry: string | undefined) => boolean;
3
- export declare const getApplicableDeliveryCost: (rule: CountryPricingRule, category: string | undefined, originCountry: string | undefined) => number | undefined;
4
- export declare const convertFromBranchCurrency: (branchAmount: number, rule: Pick<CountryPricingRule, "rate">) => number;
5
- //# sourceMappingURL=country-pricing.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"country-pricing.d.ts","sourceRoot":"/","sources":["utils/country-pricing.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,kBAAkB,EAAE,MAAM,6BAA6B,CAAC;AAOjE,eAAO,MAAM,uBAAuB,GAClC,MAAM,IAAI,CAAC,kBAAkB,EAAE,aAAa,CAAC,EAC7C,eAAe,MAAM,GAAG,SAAS,KAChC,OAKF,CAAC;AASF,eAAO,MAAM,yBAAyB,GACpC,MAAM,kBAAkB,EACxB,UAAU,MAAM,GAAG,SAAS,EAC5B,eAAe,MAAM,GAAG,SAAS,KAChC,MAAM,GAAG,SAQX,CAAC;AAGF,eAAO,MAAM,yBAAyB,GACpC,cAAc,MAAM,EACpB,MAAM,IAAI,CAAC,kBAAkB,EAAE,MAAM,CAAC,KACrC,MAA6C,CAAC"}
@@ -1,17 +0,0 @@
1
- export const shouldApplyDeliveryCost = (rule, originCountry) => {
2
- if (originCountry == null) {
3
- return true;
4
- }
5
- return originCountry.toLowerCase() !== rule.countryCode.toLowerCase();
6
- };
7
- export const getApplicableDeliveryCost = (rule, category, originCountry) => {
8
- if (!shouldApplyDeliveryCost(rule, originCountry)) {
9
- return undefined;
10
- }
11
- if (category == null) {
12
- return undefined;
13
- }
14
- return rule.deliveryCostByCategory?.[category];
15
- };
16
- export const convertFromBranchCurrency = (branchAmount, rule) => Math.ceil(branchAmount * rule.rate);
17
- //# sourceMappingURL=country-pricing.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"country-pricing.js","sourceRoot":"/","sources":["utils/country-pricing.ts"],"names":[],"mappings":"AAQA,MAAM,CAAC,MAAM,uBAAuB,GAAG,CACrC,IAA6C,EAC7C,aAAiC,EACxB,EAAE;IACX,IAAI,aAAa,IAAI,IAAI,EAAE,CAAC;QAC1B,OAAO,IAAI,CAAC;IACd,CAAC;IACD,OAAO,aAAa,CAAC,WAAW,EAAE,KAAK,IAAI,CAAC,WAAW,CAAC,WAAW,EAAE,CAAC;AACxE,CAAC,CAAC;AASF,MAAM,CAAC,MAAM,yBAAyB,GAAG,CACvC,IAAwB,EACxB,QAA4B,EAC5B,aAAiC,EACb,EAAE;IACtB,IAAI,CAAC,uBAAuB,CAAC,IAAI,EAAE,aAAa,CAAC,EAAE,CAAC;QAClD,OAAO,SAAS,CAAC;IACnB,CAAC;IACD,IAAI,QAAQ,IAAI,IAAI,EAAE,CAAC;QACrB,OAAO,SAAS,CAAC;IACnB,CAAC;IACD,OAAO,IAAI,CAAC,sBAAsB,EAAE,CAAC,QAAsB,CAAC,CAAC;AAC/D,CAAC,CAAC;AAGF,MAAM,CAAC,MAAM,yBAAyB,GAAG,CACvC,YAAoB,EACpB,IAAsC,EAC9B,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,YAAY,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC","sourcesContent":["import { Categories } from '../constants.js';\nimport { CountryPricingRule } from '../types/country-pricing.js';\n\n/**\n * Should the delivery cost defined by `rule` be applied for a vehicle whose\n * origin branch is in `originCountry`? Returns `false` when the vehicle is\n * already located in the rule's country (case-insensitive ISO-2 compare).\n */\nexport const shouldApplyDeliveryCost = (\n rule: Pick<CountryPricingRule, 'countryCode'>,\n originCountry: string | undefined,\n): boolean => {\n if (originCountry == null) {\n return true;\n }\n return originCountry.toLowerCase() !== rule.countryCode.toLowerCase();\n};\n\n/**\n * Look up the per-category delivery cost on the rule. Returns `undefined` when delivery is\n * not applicable (same-country suppression, missing category, or category not in the rule's\n * map). Returns the configured number — including `0` — when the rule explicitly covers the\n * category. A `0` is a legitimate value: the operator has opted in for this category but is\n * charging no fee on top (e.g. for vehicles already at the rule's `deliveryLocation`).\n */\nexport const getApplicableDeliveryCost = (\n rule: CountryPricingRule,\n category: string | undefined,\n originCountry: string | undefined,\n): number | undefined => {\n if (!shouldApplyDeliveryCost(rule, originCountry)) {\n return undefined;\n }\n if (category == null) {\n return undefined;\n }\n return rule.deliveryCostByCategory?.[category as Categories];\n};\n\n/** Convert an amount in the owning branch's currency to `rule.currency`. */\nexport const convertFromBranchCurrency = (\n branchAmount: number,\n rule: Pick<CountryPricingRule, 'rate'>,\n): number => Math.ceil(branchAmount * rule.rate);\n"]}
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=country-pricing.test.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"country-pricing.test.d.ts","sourceRoot":"/","sources":["utils/country-pricing.test.ts"],"names":[],"mappings":""}
@@ -1,65 +0,0 @@
1
- import { Categories } from '../constants.js';
2
- import { convertFromBranchCurrency, getApplicableDeliveryCost, shouldApplyDeliveryCost, } from './country-pricing.js';
3
- const baseRule = {
4
- countryCode: 'bo',
5
- currency: 'USD',
6
- rate: 1.08,
7
- deliveryCostByCategory: { [Categories.Truck]: 500 },
8
- deliveryLocation: 'La Paz (Bolivia)',
9
- };
10
- describe('convertFromBranchCurrency', () => {
11
- test('multiplies by rate', () => {
12
- expect(convertFromBranchCurrency(1000, { rate: 1.08 })).toBe(1080);
13
- });
14
- test('uses Math.ceil to avoid underselling on partial cents', () => {
15
- expect(convertFromBranchCurrency(999.5, { rate: 1.0 })).toBe(1000);
16
- });
17
- });
18
- describe('shouldApplyDeliveryCost', () => {
19
- test('returns false when origin equals rule country', () => {
20
- expect(shouldApplyDeliveryCost({ countryCode: 'bo' }, 'bo')).toBe(false);
21
- });
22
- test('is case-insensitive', () => {
23
- expect(shouldApplyDeliveryCost({ countryCode: 'bo' }, 'BO')).toBe(false);
24
- expect(shouldApplyDeliveryCost({ countryCode: 'BO' }, 'bo')).toBe(false);
25
- });
26
- test('returns true when origin differs from rule country', () => {
27
- expect(shouldApplyDeliveryCost({ countryCode: 'bo' }, 'be')).toBe(true);
28
- });
29
- test('returns true when origin is undefined (safe default)', () => {
30
- expect(shouldApplyDeliveryCost({ countryCode: 'bo' }, undefined)).toBe(true);
31
- });
32
- });
33
- describe('getApplicableDeliveryCost', () => {
34
- test('returns undefined when same country, even with a configured cost', () => {
35
- expect(getApplicableDeliveryCost(baseRule, Categories.Truck, 'bo')).toBeUndefined();
36
- });
37
- test('returns undefined when category is undefined', () => {
38
- expect(getApplicableDeliveryCost(baseRule, undefined, 'be')).toBeUndefined();
39
- });
40
- test('returns the matching cost for a different country and known category', () => {
41
- expect(getApplicableDeliveryCost(baseRule, Categories.Truck, 'be')).toBe(500);
42
- });
43
- test('returns 0 when the category is explicitly mapped to 0 (opt-in with no fee)', () => {
44
- const zeroFeeRule = {
45
- countryCode: 'bo',
46
- currency: 'USD',
47
- rate: 1.08,
48
- deliveryCostByCategory: { [Categories.Truck]: 0 },
49
- deliveryLocation: 'Bolivia',
50
- };
51
- expect(getApplicableDeliveryCost(zeroFeeRule, Categories.Truck, 'be')).toBe(0);
52
- });
53
- test('returns undefined when category has no configured cost', () => {
54
- expect(getApplicableDeliveryCost(baseRule, Categories.Van, 'be')).toBeUndefined();
55
- });
56
- test('returns undefined when rule has no deliveryCostByCategory at all', () => {
57
- const pureRateRule = {
58
- countryCode: 'bo',
59
- currency: 'USD',
60
- rate: 1.08,
61
- };
62
- expect(getApplicableDeliveryCost(pureRateRule, Categories.Truck, 'be')).toBeUndefined();
63
- });
64
- });
65
- //# sourceMappingURL=country-pricing.test.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"country-pricing.test.js","sourceRoot":"/","sources":["utils/country-pricing.test.ts"],"names":[],"mappings":"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","sourcesContent":["import { Categories } from '../constants.js';\nimport { CountryPricingRule } from '../types/country-pricing.js';\nimport {\n convertFromBranchCurrency,\n getApplicableDeliveryCost,\n shouldApplyDeliveryCost,\n} from './country-pricing.js';\n\nconst baseRule: CountryPricingRule = {\n countryCode: 'bo',\n currency: 'USD',\n rate: 1.08,\n deliveryCostByCategory: { [Categories.Truck]: 500 },\n deliveryLocation: 'La Paz (Bolivia)',\n};\n\ndescribe('convertFromBranchCurrency', () => {\n test('multiplies by rate', () => {\n expect(convertFromBranchCurrency(1000, { rate: 1.08 })).toBe(1080);\n });\n\n test('uses Math.ceil to avoid underselling on partial cents', () => {\n expect(convertFromBranchCurrency(999.5, { rate: 1.0 })).toBe(1000);\n });\n});\n\ndescribe('shouldApplyDeliveryCost', () => {\n test('returns false when origin equals rule country', () => {\n expect(shouldApplyDeliveryCost({ countryCode: 'bo' }, 'bo')).toBe(false);\n });\n\n test('is case-insensitive', () => {\n expect(shouldApplyDeliveryCost({ countryCode: 'bo' }, 'BO')).toBe(false);\n expect(shouldApplyDeliveryCost({ countryCode: 'BO' }, 'bo')).toBe(false);\n });\n\n test('returns true when origin differs from rule country', () => {\n expect(shouldApplyDeliveryCost({ countryCode: 'bo' }, 'be')).toBe(true);\n });\n\n test('returns true when origin is undefined (safe default)', () => {\n expect(shouldApplyDeliveryCost({ countryCode: 'bo' }, undefined)).toBe(true);\n });\n});\n\ndescribe('getApplicableDeliveryCost', () => {\n test('returns undefined when same country, even with a configured cost', () => {\n expect(getApplicableDeliveryCost(baseRule, Categories.Truck, 'bo')).toBeUndefined();\n });\n\n test('returns undefined when category is undefined', () => {\n expect(getApplicableDeliveryCost(baseRule, undefined, 'be')).toBeUndefined();\n });\n\n test('returns the matching cost for a different country and known category', () => {\n expect(getApplicableDeliveryCost(baseRule, Categories.Truck, 'be')).toBe(500);\n });\n\n test('returns 0 when the category is explicitly mapped to 0 (opt-in with no fee)', () => {\n const zeroFeeRule: CountryPricingRule = {\n countryCode: 'bo',\n currency: 'USD',\n rate: 1.08,\n deliveryCostByCategory: { [Categories.Truck]: 0 },\n deliveryLocation: 'Bolivia',\n };\n expect(getApplicableDeliveryCost(zeroFeeRule, Categories.Truck, 'be')).toBe(0);\n });\n\n test('returns undefined when category has no configured cost', () => {\n expect(getApplicableDeliveryCost(baseRule, Categories.Van, 'be')).toBeUndefined();\n });\n\n test('returns undefined when rule has no deliveryCostByCategory at all', () => {\n const pureRateRule: CountryPricingRule = {\n countryCode: 'bo',\n currency: 'USD',\n rate: 1.08,\n };\n expect(getApplicableDeliveryCost(pureRateRule, Categories.Truck, 'be')).toBeUndefined();\n });\n});\n"]}
@@ -1,25 +0,0 @@
1
- import { Categories } from '../constants.js';
2
-
3
- type DeliveryFields =
4
- | {
5
- /** Flat cost in `currency` per vehicle category, added after conversion. */
6
- deliveryCostByCategory: Partial<Record<Categories, number>>;
7
- /** Human-readable, e.g., "Iquique (Chile)". */
8
- deliveryLocation: string;
9
- }
10
- | { deliveryCostByCategory?: never; deliveryLocation?: never };
11
-
12
- export type CountryPricingRule = {
13
- countryCode: string; // lower-cased ISO 3166-1 alpha-2 (e.g., "cl")
14
- currency: string; // ISO 4217 (e.g., "USD")
15
- /**
16
- * Fixed multiplier applied to a price expressed in the owning branch's
17
- * currency (`branch.currency`) to produce a price in `rule.currency`.
18
- * For a tenant whose primary branch is EUR, a Bolivia rule with
19
- * `currency: "USD"` carries `rate ≈ 1.08`. For a tenant whose primary
20
- * branch is USD, a Belgium rule with `currency: "EUR"` carries
21
- * `rate ≈ 0.92`.
22
- */
23
- rate: number;
24
- leasing?: boolean; // Override for leasing visibility
25
- } & DeliveryFields;
@@ -1,82 +0,0 @@
1
- import { Categories } from '../constants.js';
2
- import { CountryPricingRule } from '../types/country-pricing.js';
3
- import {
4
- convertFromBranchCurrency,
5
- getApplicableDeliveryCost,
6
- shouldApplyDeliveryCost,
7
- } from './country-pricing.js';
8
-
9
- const baseRule: CountryPricingRule = {
10
- countryCode: 'bo',
11
- currency: 'USD',
12
- rate: 1.08,
13
- deliveryCostByCategory: { [Categories.Truck]: 500 },
14
- deliveryLocation: 'La Paz (Bolivia)',
15
- };
16
-
17
- describe('convertFromBranchCurrency', () => {
18
- test('multiplies by rate', () => {
19
- expect(convertFromBranchCurrency(1000, { rate: 1.08 })).toBe(1080);
20
- });
21
-
22
- test('uses Math.ceil to avoid underselling on partial cents', () => {
23
- expect(convertFromBranchCurrency(999.5, { rate: 1.0 })).toBe(1000);
24
- });
25
- });
26
-
27
- describe('shouldApplyDeliveryCost', () => {
28
- test('returns false when origin equals rule country', () => {
29
- expect(shouldApplyDeliveryCost({ countryCode: 'bo' }, 'bo')).toBe(false);
30
- });
31
-
32
- test('is case-insensitive', () => {
33
- expect(shouldApplyDeliveryCost({ countryCode: 'bo' }, 'BO')).toBe(false);
34
- expect(shouldApplyDeliveryCost({ countryCode: 'BO' }, 'bo')).toBe(false);
35
- });
36
-
37
- test('returns true when origin differs from rule country', () => {
38
- expect(shouldApplyDeliveryCost({ countryCode: 'bo' }, 'be')).toBe(true);
39
- });
40
-
41
- test('returns true when origin is undefined (safe default)', () => {
42
- expect(shouldApplyDeliveryCost({ countryCode: 'bo' }, undefined)).toBe(true);
43
- });
44
- });
45
-
46
- describe('getApplicableDeliveryCost', () => {
47
- test('returns undefined when same country, even with a configured cost', () => {
48
- expect(getApplicableDeliveryCost(baseRule, Categories.Truck, 'bo')).toBeUndefined();
49
- });
50
-
51
- test('returns undefined when category is undefined', () => {
52
- expect(getApplicableDeliveryCost(baseRule, undefined, 'be')).toBeUndefined();
53
- });
54
-
55
- test('returns the matching cost for a different country and known category', () => {
56
- expect(getApplicableDeliveryCost(baseRule, Categories.Truck, 'be')).toBe(500);
57
- });
58
-
59
- test('returns 0 when the category is explicitly mapped to 0 (opt-in with no fee)', () => {
60
- const zeroFeeRule: CountryPricingRule = {
61
- countryCode: 'bo',
62
- currency: 'USD',
63
- rate: 1.08,
64
- deliveryCostByCategory: { [Categories.Truck]: 0 },
65
- deliveryLocation: 'Bolivia',
66
- };
67
- expect(getApplicableDeliveryCost(zeroFeeRule, Categories.Truck, 'be')).toBe(0);
68
- });
69
-
70
- test('returns undefined when category has no configured cost', () => {
71
- expect(getApplicableDeliveryCost(baseRule, Categories.Van, 'be')).toBeUndefined();
72
- });
73
-
74
- test('returns undefined when rule has no deliveryCostByCategory at all', () => {
75
- const pureRateRule: CountryPricingRule = {
76
- countryCode: 'bo',
77
- currency: 'USD',
78
- rate: 1.08,
79
- };
80
- expect(getApplicableDeliveryCost(pureRateRule, Categories.Truck, 'be')).toBeUndefined();
81
- });
82
- });
@@ -1,44 +0,0 @@
1
- import { Categories } from '../constants.js';
2
- import { CountryPricingRule } from '../types/country-pricing.js';
3
-
4
- /**
5
- * Should the delivery cost defined by `rule` be applied for a vehicle whose
6
- * origin branch is in `originCountry`? Returns `false` when the vehicle is
7
- * already located in the rule's country (case-insensitive ISO-2 compare).
8
- */
9
- export const shouldApplyDeliveryCost = (
10
- rule: Pick<CountryPricingRule, 'countryCode'>,
11
- originCountry: string | undefined,
12
- ): boolean => {
13
- if (originCountry == null) {
14
- return true;
15
- }
16
- return originCountry.toLowerCase() !== rule.countryCode.toLowerCase();
17
- };
18
-
19
- /**
20
- * Look up the per-category delivery cost on the rule. Returns `undefined` when delivery is
21
- * not applicable (same-country suppression, missing category, or category not in the rule's
22
- * map). Returns the configured number — including `0` — when the rule explicitly covers the
23
- * category. A `0` is a legitimate value: the operator has opted in for this category but is
24
- * charging no fee on top (e.g. for vehicles already at the rule's `deliveryLocation`).
25
- */
26
- export const getApplicableDeliveryCost = (
27
- rule: CountryPricingRule,
28
- category: string | undefined,
29
- originCountry: string | undefined,
30
- ): number | undefined => {
31
- if (!shouldApplyDeliveryCost(rule, originCountry)) {
32
- return undefined;
33
- }
34
- if (category == null) {
35
- return undefined;
36
- }
37
- return rule.deliveryCostByCategory?.[category as Categories];
38
- };
39
-
40
- /** Convert an amount in the owning branch's currency to `rule.currency`. */
41
- export const convertFromBranchCurrency = (
42
- branchAmount: number,
43
- rule: Pick<CountryPricingRule, 'rate'>,
44
- ): number => Math.ceil(branchAmount * rule.rate);