@bisondesk/core-sdk 1.0.626 → 1.0.628
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.
- package/lib/apis/opportunities.d.ts +2 -0
- package/lib/apis/opportunities.d.ts.map +1 -1
- package/lib/apis/opportunities.js +12 -0
- package/lib/apis/opportunities.js.map +1 -1
- package/lib/apis/opportunities.test.d.ts +2 -0
- package/lib/apis/opportunities.test.d.ts.map +1 -0
- package/lib/apis/opportunities.test.js +53 -0
- package/lib/apis/opportunities.test.js.map +1 -0
- package/lib/types/internet-opportunities.d.ts +1 -1
- package/lib/types/internet-opportunities.d.ts.map +1 -1
- package/lib/types/internet-opportunities.js.map +1 -1
- package/lib/types/opportunities.d.ts +4 -1
- package/lib/types/opportunities.d.ts.map +1 -1
- package/lib/types/opportunities.js +2 -0
- package/lib/types/opportunities.js.map +1 -1
- package/lib/types/tenants.d.ts +1 -0
- package/lib/types/tenants.d.ts.map +1 -1
- package/lib/types/tenants.js.map +1 -1
- package/lib/utils/opportunities.d.ts +1 -0
- package/lib/utils/opportunities.d.ts.map +1 -1
- package/lib/utils/opportunities.js +1 -0
- package/lib/utils/opportunities.js.map +1 -1
- package/lib/utils/tenants.d.ts +1 -0
- package/lib/utils/tenants.d.ts.map +1 -1
- package/lib/utils/tenants.js +1 -0
- package/lib/utils/tenants.js.map +1 -1
- package/lib/utils/vehicles.d.ts +2 -0
- package/lib/utils/vehicles.d.ts.map +1 -1
- package/lib/utils/vehicles.js +2 -0
- package/lib/utils/vehicles.js.map +1 -1
- package/package.json +2 -2
- package/src/apis/opportunities.test.ts +68 -0
- package/src/apis/opportunities.ts +14 -0
- package/src/types/internet-opportunities.ts +1 -1
- package/src/types/opportunities.ts +8 -0
- package/src/types/tenants.ts +4 -0
- package/src/utils/opportunities.ts +3 -0
- package/src/utils/tenants.ts +4 -0
- package/src/utils/vehicles.ts +20 -0
- package/tsconfig.tsbuildinfo +1 -1
- package/src/types/activities.js +0 -13
- package/src/types/activities.js.map +0 -1
- package/src/types/comparables.js +0 -2
- package/src/types/comparables.js.map +0 -1
- package/src/types/crm.js +0 -58
- package/src/types/crm.js.map +0 -1
- package/src/types/dashboard.js +0 -2
- package/src/types/dashboard.js.map +0 -1
- package/src/types/definitions.js +0 -2
- package/src/types/definitions.js.map +0 -1
- package/src/types/fields.js +0 -2
- package/src/types/fields.js.map +0 -1
- package/src/types/insights.js +0 -2
- package/src/types/insights.js.map +0 -1
- package/src/types/interests.js +0 -6
- package/src/types/interests.js.map +0 -1
- package/src/types/internal-events.js +0 -18
- package/src/types/internal-events.js.map +0 -1
- package/src/types/internet-opportunities.js +0 -2
- package/src/types/internet-opportunities.js.map +0 -1
- package/src/types/internet-vehicles.js +0 -2
- package/src/types/internet-vehicles.js.map +0 -1
- package/src/types/leasing-administration.js +0 -2
- package/src/types/leasing-administration.js.map +0 -1
- package/src/types/leasing-debtors.js +0 -2
- package/src/types/leasing-debtors.js.map +0 -1
- package/src/types/leasing-search.js +0 -2
- package/src/types/leasing-search.js.map +0 -1
- package/src/types/leasing-settings.js +0 -7
- package/src/types/leasing-settings.js.map +0 -1
- package/src/types/leasing.js +0 -38
- package/src/types/leasing.js.map +0 -1
- package/src/types/marketing.js +0 -35
- package/src/types/marketing.js.map +0 -1
- package/src/types/offers.js +0 -56
- package/src/types/opportunities.js +0 -107
- package/src/types/opportunities.js.map +0 -1
- package/src/types/payments.js +0 -7
- package/src/types/picklists.js +0 -2
- package/src/types/picklists.js.map +0 -1
- package/src/types/quotes.js +0 -42
- package/src/types/recently-viewed.js +0 -2
- package/src/types/recently-viewed.js.map +0 -1
- package/src/types/reservations.js +0 -5
- package/src/types/reservations.js.map +0 -1
- package/src/types/roi-ratings.js +0 -5
- package/src/types/roi-ratings.js.map +0 -1
- package/src/types/saved-filters.js +0 -9
- package/src/types/saved-filters.js.map +0 -1
- package/src/types/search.js +0 -2
- package/src/types/search.js.map +0 -1
- package/src/types/settings.js +0 -2
- package/src/types/settings.js.map +0 -1
- package/src/types/templates.js +0 -2
- package/src/types/templates.js.map +0 -1
- package/src/types/tenants.js +0 -21
- package/src/types/tenants.js.map +0 -1
- package/src/types/user-performance.js +0 -7
- package/src/types/user-performance.js.map +0 -1
- package/src/types/utils.js +0 -2
- package/src/types/validation.js +0 -2
- package/src/types/validation.js.map +0 -1
- package/src/types/vehicle-sales.js +0 -6
- package/src/types/vehicle-sales.js.map +0 -1
- package/src/types/vehicles.js +0 -98
- package/src/types/vehicles.js.map +0 -1
- package/src/utils/leasing.js +0 -6
- package/src/utils/leasing.js.map +0 -1
- package/src/utils/opportunities.js +0 -48
- package/src/utils/opportunities.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"opportunities.js","sourceRoot":"/","sources":["utils/opportunities.ts"],"names":[],"mappings":"AAAA,OAAO,EAAe,iBAAiB,EAAE,sBAAsB,EAAE,MAAM,2BAA2B,CAAC;AAOnG,MAAM,wBAAwB,GAAG,CAAC,KAAmB,EAAE,EAAE;IACvD,MAAM,EAAE,aAAa,EAAE,eAAe,EAAE,GAAG,KAAK,CAAC;IAEjD,MAAM,gBAAgB,GAAG,sBAAsB,CAAC,OAAO,CAAC,aAAa,CAAC,CAAC;IACvE,MAAM,kBAAkB,GAAG,sBAAsB,CAAC,OAAO,CAAC,eAAe,CAAC,CAAC;IAE3E,OAAO;QACL,gBAAgB;QAChB,kBAAkB;KACnB,CAAC;AACJ,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAC/B,aAAgC,EACD,EAAE;IACjC,MAAM,YAAY,GAAG,sBAAsB,CAAC,OAAO,CAAC,aAAa,CAAC,CAAC;IACnE,IAAI,YAAY,KAAK,CAAC,EAAE,CAAC;QACvB,OAAO;IACT,CAAC;IACD,OAAO,sBAAsB,CAAC,YAAY,GAAG,CAAC,CAAC,CAAC;AAClD,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,aAAa,GAAG,CAAC,MAAyB,EAAiC,EAAE;IACxF,MAAM,WAAW,GAAG,sBAAsB,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;IAC3D,IAAI,WAAW,IAAI,sBAAsB,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACrD,OAAO;IACT,CAAC;IACD,OAAO,sBAAsB,CAAC,WAAW,GAAG,CAAC,CAAC,CAAC;AACjD,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,uCAAuC,GAAG,CAAC,KAAmB,EAAW,EAAE;IACtF,MAAM,EAAE,gBAAgB,EAAE,kBAAkB,EAAE,GAAG,wBAAwB,CAAC,KAAK,CAAC,CAAC;IAEjF,OAAO,gBAAgB,IAAI,kBAAkB,CAAC;AAChD,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,iCAAiC,GAAG,CAAC,KAAmB,EAAW,EAAE;IAChF,MAAM,EAAE,gBAAgB,EAAE,kBAAkB,EAAE,GAAG,wBAAwB,CAAC,KAAK,CAAC,CAAC;IAEjF,OAAO,gBAAgB,GAAG,kBAAkB,CAAC;AAC/C,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,wCAAwC,GAAG,CAAC,KAAmB,EAAW,EAAE;IACvF,MAAM,EAAE,gBAAgB,EAAE,kBAAkB,EAAE,GAAG,wBAAwB,CAAC,KAAK,CAAC,CAAC;IAEjF,OAAO,gBAAgB,IAAI,kBAAkB,CAAC;AAChD,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,kCAAkC,GAAG,CAAC,KAAmB,EAAW,EAAE;IACjF,MAAM,EAAE,gBAAgB,EAAE,kBAAkB,EAAE,GAAG,wBAAwB,CAAC,KAAK,CAAC,CAAC;IAEjF,OAAO,gBAAgB,GAAG,kBAAkB,CAAC;AAC/C,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAAC,KAAkB,EAAW,EAAE,CAAC,KAAK,CAAC,MAAM,IAAI,IAAI,CAAC;AAEvF,MAAM,CAAC,MAAM,4BAA4B,GAAG,GAAwB,EAAE,CAAC;IACrE,iBAAiB,CAAC,MAAM;IACxB,iBAAiB,CAAC,WAAW;IAC7B,iBAAiB,CAAC,QAAQ;CAC3B,CAAC;AAEF,MAAM,CAAC,MAAM,qBAAqB,GAAG,CAAC,KAAkB,EAAW,EAAE,CACnE,4BAA4B,EAAE,CAAC,QAAQ,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;AASxD,MAAM,CAAC,MAAM,6BAA6B,GAAG,CAAC,KAAkB,EAAW,EAAE,CAC3E,qBAAqB,CAAC,KAAK,CAAC,IAAI,CAAC,iBAAiB,CAAC,KAAK,CAAC,CAAC;AAO5D,MAAM,CAAC,MAAM,+BAA+B,GAAG,CAC7C,KAA8B,EACV,EAAE,CACtB,KAAK,IAAI,IAAI,IAAI,6BAA6B,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC","sourcesContent":["import { Opportunity, OpportunityStatus, OpportunityStatusOrder } from '../types/opportunities.js';\n\ntype CompareInput = {\n currentStatus: OpportunityStatus;\n referenceStatus: OpportunityStatus;\n};\n\nconst compareOpportunityStatus = (input: CompareInput) => {\n const { currentStatus, referenceStatus } = input;\n\n const currentStatusIdx = OpportunityStatusOrder.indexOf(currentStatus);\n const referenceStatusIdx = OpportunityStatusOrder.indexOf(referenceStatus);\n\n return {\n currentStatusIdx,\n referenceStatusIdx,\n };\n};\n\nexport const getPreviousStatus = (\n currentStatus: OpportunityStatus,\n): OpportunityStatus | undefined => {\n const currentIndex = OpportunityStatusOrder.indexOf(currentStatus);\n if (currentIndex === 0) {\n return;\n }\n return OpportunityStatusOrder[currentIndex - 1];\n};\n\nexport const getNextStatus = (status: OpportunityStatus): OpportunityStatus | undefined => {\n const statusIndex = OpportunityStatusOrder.indexOf(status);\n if (statusIndex >= OpportunityStatusOrder.length - 1) {\n return;\n }\n return OpportunityStatusOrder[statusIndex + 1];\n};\n\nexport const isSameOrAfterReferenceOpportunityStatus = (input: CompareInput): boolean => {\n const { currentStatusIdx, referenceStatusIdx } = compareOpportunityStatus(input);\n\n return currentStatusIdx >= referenceStatusIdx;\n};\n\nexport const isAfterReferenceOpportunityStatus = (input: CompareInput): boolean => {\n const { currentStatusIdx, referenceStatusIdx } = compareOpportunityStatus(input);\n\n return currentStatusIdx > referenceStatusIdx;\n};\n\nexport const isSameOrBeforeReferenceOpportunityStatus = (input: CompareInput): boolean => {\n const { currentStatusIdx, referenceStatusIdx } = compareOpportunityStatus(input);\n\n return currentStatusIdx <= referenceStatusIdx;\n};\n\nexport const isBeforeReferenceOpportunityStatus = (input: CompareInput): boolean => {\n const { currentStatusIdx, referenceStatusIdx } = compareOpportunityStatus(input);\n\n return currentStatusIdx < referenceStatusIdx;\n};\n\nexport const isOpportunityLost = (input: Opportunity): boolean => input.lostAt != null;\n\nexport const getOpportunityReservedStatus = (): OpportunityStatus[] => [\n OpportunityStatus.REVIEW,\n OpportunityStatus.PREPARATION,\n OpportunityStatus.DELIVERY,\n];\n\nexport const isOpportunityReserved = (input: Opportunity): boolean =>\n getOpportunityReservedStatus().includes(input.status);\n\n/**\n * Whether the opportunity currently reserves the vehicle attached to it: reserved-stage\n * (REVIEW onwards) and not lost — independent of whether a reservation row exists. Query-side\n * twin: `getOpportunityReservingVehicle` in core's opportunities/read.ts. Availability\n * propagation, warnings and guards must share this one definition rather than re-composing\n * the two primitives.\n */\nexport const isOpportunityReservingVehicle = (input: Opportunity): boolean =>\n isOpportunityReserved(input) && !isOpportunityLost(input);\n\n/**\n * The vehicle the opportunity currently reserves, if any — undefined outside the reserved\n * range, when lost, without a vehicle, or for a missing opportunity. Compare this value\n * before/after an update to detect a vehicle being taken or freed.\n */\nexport const getOpportunityReservedVehicleId = (\n input: Opportunity | undefined,\n): string | undefined =>\n input != null && isOpportunityReservingVehicle(input) ? input.vehicleId : undefined;\n"]}
|
|
1
|
+
{"version":3,"file":"opportunities.js","sourceRoot":"/","sources":["utils/opportunities.ts"],"names":[],"mappings":"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","sourcesContent":["import { Opportunity, OpportunityStatus, OpportunityStatusOrder } from '../types/opportunities.js';\n\ntype CompareInput = {\n currentStatus: OpportunityStatus;\n referenceStatus: OpportunityStatus;\n};\n\nconst compareOpportunityStatus = (input: CompareInput) => {\n const { currentStatus, referenceStatus } = input;\n\n const currentStatusIdx = OpportunityStatusOrder.indexOf(currentStatus);\n const referenceStatusIdx = OpportunityStatusOrder.indexOf(referenceStatus);\n\n return {\n currentStatusIdx,\n referenceStatusIdx,\n };\n};\n\nexport const getPreviousStatus = (\n currentStatus: OpportunityStatus,\n): OpportunityStatus | undefined => {\n const currentIndex = OpportunityStatusOrder.indexOf(currentStatus);\n if (currentIndex === 0) {\n return;\n }\n return OpportunityStatusOrder[currentIndex - 1];\n};\n\nexport const getNextStatus = (status: OpportunityStatus): OpportunityStatus | undefined => {\n const statusIndex = OpportunityStatusOrder.indexOf(status);\n if (statusIndex >= OpportunityStatusOrder.length - 1) {\n return;\n }\n return OpportunityStatusOrder[statusIndex + 1];\n};\n\nexport const isSameOrAfterReferenceOpportunityStatus = (input: CompareInput): boolean => {\n const { currentStatusIdx, referenceStatusIdx } = compareOpportunityStatus(input);\n\n return currentStatusIdx >= referenceStatusIdx;\n};\n\nexport const isAfterReferenceOpportunityStatus = (input: CompareInput): boolean => {\n const { currentStatusIdx, referenceStatusIdx } = compareOpportunityStatus(input);\n\n return currentStatusIdx > referenceStatusIdx;\n};\n\nexport const isSameOrBeforeReferenceOpportunityStatus = (input: CompareInput): boolean => {\n const { currentStatusIdx, referenceStatusIdx } = compareOpportunityStatus(input);\n\n return currentStatusIdx <= referenceStatusIdx;\n};\n\nexport const isBeforeReferenceOpportunityStatus = (input: CompareInput): boolean => {\n const { currentStatusIdx, referenceStatusIdx } = compareOpportunityStatus(input);\n\n return currentStatusIdx < referenceStatusIdx;\n};\n\nexport const isOpportunityLost = (input: Opportunity): boolean => input.lostAt != null;\n\nexport const isOpportunityClosed = (input: Opportunity): boolean =>\n input.lostAt != null || input.wonAt != null;\n\nexport const getOpportunityReservedStatus = (): OpportunityStatus[] => [\n OpportunityStatus.REVIEW,\n OpportunityStatus.PREPARATION,\n OpportunityStatus.DELIVERY,\n];\n\nexport const isOpportunityReserved = (input: Opportunity): boolean =>\n getOpportunityReservedStatus().includes(input.status);\n\n/**\n * Whether the opportunity currently reserves the vehicle attached to it: reserved-stage\n * (REVIEW onwards) and not lost — independent of whether a reservation row exists. Query-side\n * twin: `getOpportunityReservingVehicle` in core's opportunities/read.ts. Availability\n * propagation, warnings and guards must share this one definition rather than re-composing\n * the two primitives.\n */\nexport const isOpportunityReservingVehicle = (input: Opportunity): boolean =>\n isOpportunityReserved(input) && !isOpportunityLost(input);\n\n/**\n * The vehicle the opportunity currently reserves, if any — undefined outside the reserved\n * range, when lost, without a vehicle, or for a missing opportunity. Compare this value\n * before/after an update to detect a vehicle being taken or freed.\n */\nexport const getOpportunityReservedVehicleId = (\n input: Opportunity | undefined,\n): string | undefined =>\n input != null && isOpportunityReservingVehicle(input) ? input.vehicleId : undefined;\n"]}
|
package/lib/utils/tenants.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { Branch, Tenant } from '../types/tenants.js';
|
|
2
2
|
export declare const getBranch: (tenant: Tenant, branchId: string) => Branch;
|
|
3
3
|
export declare const getDefaultBranch: (tenant: Tenant) => Branch;
|
|
4
|
+
export declare const isDropshippingBranch: (branch: Branch) => boolean;
|
|
4
5
|
export declare const getBranchStandardVatRate: (tenant: Tenant, branchId: string) => string;
|
|
5
6
|
//# sourceMappingURL=tenants.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tenants.d.ts","sourceRoot":"/","sources":["utils/tenants.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAC;AAErD,eAAO,MAAM,SAAS,GAAI,QAAQ,MAAM,EAAE,UAAU,MAAM,KAAG,MAO5D,CAAC;AAEF,eAAO,MAAM,gBAAgB,GAAI,QAAQ,MAAM,KAAG,MAAiC,CAAC;
|
|
1
|
+
{"version":3,"file":"tenants.d.ts","sourceRoot":"/","sources":["utils/tenants.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAC;AAErD,eAAO,MAAM,SAAS,GAAI,QAAQ,MAAM,EAAE,UAAU,MAAM,KAAG,MAO5D,CAAC;AAEF,eAAO,MAAM,gBAAgB,GAAI,QAAQ,MAAM,KAAG,MAAiC,CAAC;AAIpF,eAAO,MAAM,oBAAoB,GAAI,QAAQ,MAAM,KAAG,OAAuC,CAAC;AAE9F,eAAO,MAAM,wBAAwB,GAAI,QAAQ,MAAM,EAAE,UAAU,MAAM,KAAG,MAG3E,CAAC"}
|
package/lib/utils/tenants.js
CHANGED
|
@@ -8,6 +8,7 @@ export const getBranch = (tenant, branchId) => {
|
|
|
8
8
|
return branch;
|
|
9
9
|
};
|
|
10
10
|
export const getDefaultBranch = (tenant) => first(tenant.branches);
|
|
11
|
+
export const isDropshippingBranch = (branch) => branch.dropshipping === true;
|
|
11
12
|
export const getBranchStandardVatRate = (tenant, branchId) => {
|
|
12
13
|
const branch = getBranch(tenant, branchId);
|
|
13
14
|
return branch.vatRates.standard;
|
package/lib/utils/tenants.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tenants.js","sourceRoot":"/","sources":["utils/tenants.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,+BAA+B,CAAC;AACvD,OAAO,EAAE,KAAK,EAAE,MAAM,WAAW,CAAC;AAGlC,MAAM,CAAC,MAAM,SAAS,GAAG,CAAC,MAAc,EAAE,QAAgB,EAAU,EAAE;IACpE,MAAM,MAAM,GAAG,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,MAAc,EAAE,EAAE,CAAC,MAAM,CAAC,EAAE,KAAK,QAAQ,CAAC,CAAC;IAChF,IAAI,MAAM,IAAI,IAAI,EAAE,CAAC;QACnB,MAAM,IAAI,MAAM,CAAC,0BAA0B,EAAE,EAAE,QAAQ,EAAE,MAAM,CAAC,EAAE,EAAE,QAAQ,EAAE,CAAC,CAAC;IAClF,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAAC,MAAc,EAAU,EAAE,CAAC,KAAK,CAAC,MAAM,CAAC,QAAQ,CAAE,CAAC;
|
|
1
|
+
{"version":3,"file":"tenants.js","sourceRoot":"/","sources":["utils/tenants.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,+BAA+B,CAAC;AACvD,OAAO,EAAE,KAAK,EAAE,MAAM,WAAW,CAAC;AAGlC,MAAM,CAAC,MAAM,SAAS,GAAG,CAAC,MAAc,EAAE,QAAgB,EAAU,EAAE;IACpE,MAAM,MAAM,GAAG,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,MAAc,EAAE,EAAE,CAAC,MAAM,CAAC,EAAE,KAAK,QAAQ,CAAC,CAAC;IAChF,IAAI,MAAM,IAAI,IAAI,EAAE,CAAC;QACnB,MAAM,IAAI,MAAM,CAAC,0BAA0B,EAAE,EAAE,QAAQ,EAAE,MAAM,CAAC,EAAE,EAAE,QAAQ,EAAE,CAAC,CAAC;IAClF,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAAC,MAAc,EAAU,EAAE,CAAC,KAAK,CAAC,MAAM,CAAC,QAAQ,CAAE,CAAC;AAIpF,MAAM,CAAC,MAAM,oBAAoB,GAAG,CAAC,MAAc,EAAW,EAAE,CAAC,MAAM,CAAC,YAAY,KAAK,IAAI,CAAC;AAE9F,MAAM,CAAC,MAAM,wBAAwB,GAAG,CAAC,MAAc,EAAE,QAAgB,EAAU,EAAE;IACnF,MAAM,MAAM,GAAW,SAAS,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;IACnD,OAAO,MAAM,CAAC,QAAQ,CAAC,QAAQ,CAAC;AAClC,CAAC,CAAC","sourcesContent":["import { XError } from '@bisondesk/commons-sdk/errors';\nimport { first } from 'lodash-es';\nimport { Branch, Tenant } from '../types/tenants.js';\n\nexport const getBranch = (tenant: Tenant, branchId: string): Branch => {\n const branch = tenant.branches.find((branch: Branch) => branch.id === branchId);\n if (branch == null) {\n throw new XError('tenants.branch-not-found', { tenantId: tenant.id, branchId });\n }\n\n return branch;\n};\n\nexport const getDefaultBranch = (tenant: Tenant): Branch => first(tenant.branches)!;\n\n/** The source invoices the end customer directly; this branch collects payment and earns\n * commission (see {@link Branch.dropshipping}). */\nexport const isDropshippingBranch = (branch: Branch): boolean => branch.dropshipping === true;\n\nexport const getBranchStandardVatRate = (tenant: Tenant, branchId: string): string => {\n const branch: Branch = getBranch(tenant, branchId);\n return branch.vatRates.standard;\n};\n"]}
|
package/lib/utils/vehicles.d.ts
CHANGED
|
@@ -2,6 +2,7 @@ import { Vehicle, VehicleExternalInfo, VehiclePurchase } from '../types/vehicles
|
|
|
2
2
|
export declare const isDealInMarketing: (purchase: VehiclePurchase | undefined) => boolean;
|
|
3
3
|
export declare const isSourceMastered: (vehicle: Pick<Vehicle, "original">, purchase: VehiclePurchase | undefined) => boolean;
|
|
4
4
|
export declare const isUnavailableFromSource: (vehicle: Pick<Vehicle, "original">, purchase: VehiclePurchase | undefined) => boolean;
|
|
5
|
+
export declare const isNewTrailer: (vehicle: Pick<Vehicle, "external">) => boolean;
|
|
5
6
|
export declare const extractCustomFeatures: (vehicle: VehicleExternalInfo) => string[];
|
|
6
7
|
export declare const getInternalTitle: ({ make, category, modelName, bodywork, modelTypeName, }: {
|
|
7
8
|
category: string;
|
|
@@ -12,6 +13,7 @@ export declare const getInternalTitle: ({ make, category, modelName, bodywork, m
|
|
|
12
13
|
}) => string;
|
|
13
14
|
export declare const convertNumberToLetters: (num: number) => string;
|
|
14
15
|
export declare const convertLettersToNumber: (letters: string) => number;
|
|
16
|
+
export declare const buildStockNumberPattern: (prefixPattern: string) => string;
|
|
15
17
|
export declare const getNextRelatedStockNumber: (stockNumber: string) => string;
|
|
16
18
|
export declare const getVehicleDescription: (external: VehicleExternalInfo, { showStockNumber, showAxleConfiguration, lang, }: {
|
|
17
19
|
showStockNumber?: boolean;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"vehicles.d.ts","sourceRoot":"/","sources":["utils/vehicles.ts"],"names":[],"mappings":"AAGA,OAAO,EACL,OAAO,EACP,mBAAmB,EACnB,eAAe,EAEhB,MAAM,sBAAsB,CAAC;AAO9B,eAAO,MAAM,iBAAiB,GAAI,UAAU,eAAe,GAAG,SAAS,KAAG,OACQ,CAAC;AASnF,eAAO,MAAM,gBAAgB,GAC3B,SAAS,IAAI,CAAC,OAAO,EAAE,UAAU,CAAC,EAClC,UAAU,eAAe,GAAG,SAAS,KACpC,OAAkE,CAAC;AAQtE,eAAO,MAAM,uBAAuB,GAClC,SAAS,IAAI,CAAC,OAAO,EAAE,UAAU,CAAC,EAClC,UAAU,eAAe,GAAG,SAAS,KACpC,OAC+F,CAAC;
|
|
1
|
+
{"version":3,"file":"vehicles.d.ts","sourceRoot":"/","sources":["utils/vehicles.ts"],"names":[],"mappings":"AAGA,OAAO,EACL,OAAO,EACP,mBAAmB,EACnB,eAAe,EAEhB,MAAM,sBAAsB,CAAC;AAO9B,eAAO,MAAM,iBAAiB,GAAI,UAAU,eAAe,GAAG,SAAS,KAAG,OACQ,CAAC;AASnF,eAAO,MAAM,gBAAgB,GAC3B,SAAS,IAAI,CAAC,OAAO,EAAE,UAAU,CAAC,EAClC,UAAU,eAAe,GAAG,SAAS,KACpC,OAAkE,CAAC;AAQtE,eAAO,MAAM,uBAAuB,GAClC,SAAS,IAAI,CAAC,OAAO,EAAE,UAAU,CAAC,EAClC,UAAU,eAAe,GAAG,SAAS,KACpC,OAC+F,CAAC;AAOnG,eAAO,MAAM,YAAY,GAAI,SAAS,IAAI,CAAC,OAAO,EAAE,UAAU,CAAC,KAAG,OAG1B,CAAC;AAEzC,eAAO,MAAM,qBAAqB,GAAI,SAAS,mBAAmB,KAAG,MAAM,EAiD1E,CAAC;AAEF,eAAO,MAAM,gBAAgB,GAAI,yDAM9B;IACD,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB,KAAG,MAcH,CAAC;AAKF,eAAO,MAAM,sBAAsB,GAAI,KAAK,MAAM,KAAG,MAiBpD,CAAC;AAGF,eAAO,MAAM,sBAAsB,GAAI,SAAS,MAAM,KAAG,MAWxD,CAAC;AASF,eAAO,MAAM,uBAAuB,GAAI,eAAe,MAAM,KAAG,MACxB,CAAC;AAEzC,eAAO,MAAM,yBAAyB,GAAI,aAAa,MAAM,KAAG,MAa/D,CAAC;AAEF,eAAO,MAAM,qBAAqB,GAChC,UAAU,mBAAmB,EAC7B,mDAIG;IACD,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,qBAAqB,CAAC,EAAE,OAAO,CAAC;IAChC,IAAI,CAAC,EAAE,MAAM,CAAC;CACf,WAyBF,CAAC"}
|
package/lib/utils/vehicles.js
CHANGED
|
@@ -5,6 +5,7 @@ import { VehiclePurchaseDealStatus, } from '../types/vehicles.js';
|
|
|
5
5
|
export const isDealInMarketing = (purchase) => purchase == null || purchase.deal.status === VehiclePurchaseDealStatus.Marketing;
|
|
6
6
|
export const isSourceMastered = (vehicle, purchase) => vehicle.original != null && isDealInMarketing(purchase);
|
|
7
7
|
export const isUnavailableFromSource = (vehicle, purchase) => isSourceMastered(vehicle, purchase) && (vehicle.original?.salesConditions?.unavailable ?? false);
|
|
8
|
+
export const isNewTrailer = (vehicle) => [Categories.Trailer, Categories.SemiTrailer].includes(vehicle.external.general.category) && !vehicle.external.condition?.used;
|
|
8
9
|
export const extractCustomFeatures = (vehicle) => {
|
|
9
10
|
const features = [
|
|
10
11
|
{
|
|
@@ -87,6 +88,7 @@ export const convertLettersToNumber = (letters) => {
|
|
|
87
88
|
}
|
|
88
89
|
return result;
|
|
89
90
|
};
|
|
91
|
+
export const buildStockNumberPattern = (prefixPattern) => `(?:${prefixPattern})\\d{5}[A-Z]{0,2}`;
|
|
90
92
|
export const getNextRelatedStockNumber = (stockNumber) => {
|
|
91
93
|
const counterPattern = /^([A-Z]+\d{5})([A-Z]{0,2})$/;
|
|
92
94
|
const match = stockNumber.match(counterPattern);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"vehicles.js","sourceRoot":"/","sources":["utils/vehicles.ts"],"names":[],"mappings":"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","sourcesContent":["import { XError } from '@bisondesk/commons-sdk/errors';\nimport { joinWithSeparator } from '@bisondesk/commons-sdk/formatting';\nimport { Categories } from '../constants.js';\nimport {\n Vehicle,\n VehicleExternalInfo,\n VehiclePurchase,\n VehiclePurchaseDealStatus,\n} from '../types/vehicles.js';\n\n/**\n * The deal has not been committed: there is no purchase yet, or its deal is still in\n * `Marketing`. Copies are created in this state; it ends when the owner agrees to buy\n * (e.g. an ICO invoice moves the deal to PurchaseAgreed).\n */\nexport const isDealInMarketing = (purchase: VehiclePurchase | undefined): boolean =>\n purchase == null || purchase.deal.status === VehiclePurchaseDealStatus.Marketing;\n\n/**\n * A cross-tenant copy whose source still masters it: it has an `original` link and its deal is\n * still in Marketing ({@link isDealInMarketing}). While this holds, the next sync overwrites\n * `external` (specs, pictures, videos) and `salesConditions` from the source; once the deal\n * progresses, the vehicle is the owner's own stock and the sync hands off. Native vehicles are\n * never source-mastered.\n */\nexport const isSourceMastered = (\n vehicle: Pick<Vehicle, 'original'>,\n purchase: VehiclePurchase | undefined,\n): boolean => vehicle.original != null && isDealInMarketing(purchase);\n\n/**\n * A cross-tenant copy whose source is not sellable, as stamped on the last sync hop. Only\n * meaningful while the source still masters the copy ({@link isSourceMastered}): past Marketing\n * the vehicle is the owner's own stock, and a still-present flag is merely stale — the sync\n * clears it on the next source event — so it must be ignored.\n */\nexport const isUnavailableFromSource = (\n vehicle: Pick<Vehicle, 'original'>,\n purchase: VehiclePurchase | undefined,\n): boolean =>\n isSourceMastered(vehicle, purchase) && (vehicle.original?.salesConditions?.unavailable ?? false);\n\nexport const extractCustomFeatures = (vehicle: VehicleExternalInfo): string[] => {\n const features: {\n getValue: (vehicle: VehicleExternalInfo) => any;\n picklistValueId: string;\n }[] = [\n {\n getValue: (vehicle) => vehicle.superstructure?.crane?.present,\n picklistValueId: 'crane',\n },\n {\n getValue: (vehicle) => vehicle.superstructure?.tailgate?.present,\n picklistValueId: 'tailgate',\n },\n { getValue: (vehicle) => vehicle.accessories.adr, picklistValueId: 'adr' },\n {\n getValue: (vehicle) => vehicle.accessories.retarderIntarder,\n picklistValueId: 'retarderIntarder',\n },\n {\n getValue: (vehicle) => vehicle.accessories.hydraulicTipperKit,\n picklistValueId: 'hydraulicTipperKit',\n },\n {\n getValue: (vehicle) => vehicle.accessories.lowDeck,\n picklistValueId: 'lowDeck',\n },\n {\n getValue: (vehicle) => vehicle.accessories.coil,\n picklistValueId: 'coil',\n },\n {\n getValue: (vehicle) => vehicle.accessories.doubleStock,\n picklistValueId: 'doubleStock',\n },\n {\n getValue: (vehicle) => vehicle.accessories.mega,\n picklistValueId: 'mega',\n },\n {\n getValue: (vehicle) =>\n vehicle.salesConditions?.manufacturerWarranty?.available ||\n vehicle.salesConditions?.manufacturerWarranty?.included,\n picklistValueId: 'warranty',\n },\n ];\n\n return features\n .filter((feature) => !!feature.getValue(vehicle))\n .map((feature) => feature.picklistValueId);\n};\n\nexport const getInternalTitle = ({\n make,\n category,\n modelName,\n bodywork,\n modelTypeName,\n}: {\n category: string;\n make?: string;\n modelName?: string;\n modelTypeName?: string;\n bodywork?: string;\n}): string => {\n if (category === Categories.Trailer || category === Categories.SemiTrailer) {\n return [make, modelName, modelTypeName, bodywork]\n .filter((v): v is string => !!v)\n .map((v) => v.trim())\n .join(' ')\n .trim();\n }\n\n return [make, modelName, modelTypeName]\n .filter((v): v is string => !!v)\n .map((v) => v.trim())\n .join(' ')\n .trim();\n};\n\nconst ALPHABET = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';\n\n// example: 1 -> A, 2 -> B, 26 -> Z, 27 -> AA, 28 -> AB, 52 -> AZ, 53 -> BA, 54 -> BB, 702 -> ZZ\nexport const convertNumberToLetters = (num: number): string => {\n const lettersLength = ALPHABET.length;\n\n if (num < 1) {\n return '';\n }\n\n let remainder = num % lettersLength;\n let quotient = Math.floor(num / lettersLength);\n\n // If remainder is 0, it means we should map it to 'Z' and reduce the quotient by 1\n if (remainder === 0) {\n remainder = lettersLength;\n quotient -= 1;\n }\n\n return convertNumberToLetters(quotient) + ALPHABET.charAt(remainder - 1);\n};\n\n// example: A -> 1, B -> 2, Z -> 26, AA -> 27, AB -> 28, AZ -> 52, BA -> 53, BB -> 54, ZZ -> 702\nexport const convertLettersToNumber = (letters: string): number => {\n const base = ALPHABET.length;\n\n let result = 0;\n\n for (let i = 0; i < letters.length; i++) {\n const charValue = ALPHABET.indexOf(letters[i]) + 1;\n result = result * base + charValue;\n }\n\n return result;\n};\n\nexport const getNextRelatedStockNumber = (stockNumber: string): string => {\n const counterPattern = /^([A-Z]+\\d{5})([A-Z]{0,2})$/;\n const match = stockNumber.match(counterPattern);\n if (match == null) {\n throw new XError('core-sdk.vehicles.bad-stock-number', { stockNumber });\n }\n\n const baseStockNumber = match[1];\n const counterLetters = match[2];\n const counterNumber = convertLettersToNumber(counterLetters);\n const nextCounterNumber = counterNumber + 1;\n const nextCounterLetters = convertNumberToLetters(nextCounterNumber);\n return `${baseStockNumber}${nextCounterLetters}`;\n};\n\nexport const getVehicleDescription = (\n external: VehicleExternalInfo,\n {\n showStockNumber = false,\n showAxleConfiguration = false,\n lang,\n }: {\n showStockNumber?: boolean;\n showAxleConfiguration?: boolean;\n lang?: string;\n },\n) => {\n const dimensions = [\n external.superstructure?.dimensions?.extended,\n external.superstructure?.dimensions?.heightened,\n ]\n .filter((value) => !!value)\n .join('');\n const kmFormatter = Intl.NumberFormat(lang, {\n style: 'unit',\n unit: 'kilometer',\n });\n\n const text = joinWithSeparator([\n showStockNumber ? external.identification.stockNumber : undefined,\n external.history?.advertisingYear,\n external.condition?.odometer?.km != null\n ? kmFormatter.format(external.condition.odometer.km)\n : undefined,\n external.powertrain?.emissions?.subclass ?? external.powertrain?.emissions?.class,\n dimensions,\n showAxleConfiguration ? external.powertrain?.axles?.configuration : undefined,\n ]);\n\n return text;\n};\n"]}
|
|
1
|
+
{"version":3,"file":"vehicles.js","sourceRoot":"/","sources":["utils/vehicles.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,+BAA+B,CAAC;AACvD,OAAO,EAAE,iBAAiB,EAAE,MAAM,mCAAmC,CAAC;AACtE,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7C,OAAO,EAIL,yBAAyB,GAC1B,MAAM,sBAAsB,CAAC;AAO9B,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAAC,QAAqC,EAAW,EAAE,CAClF,QAAQ,IAAI,IAAI,IAAI,QAAQ,CAAC,IAAI,CAAC,MAAM,KAAK,yBAAyB,CAAC,SAAS,CAAC;AASnF,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAC9B,OAAkC,EAClC,QAAqC,EAC5B,EAAE,CAAC,OAAO,CAAC,QAAQ,IAAI,IAAI,IAAI,iBAAiB,CAAC,QAAQ,CAAC,CAAC;AAQtE,MAAM,CAAC,MAAM,uBAAuB,GAAG,CACrC,OAAkC,EAClC,QAAqC,EAC5B,EAAE,CACX,gBAAgB,CAAC,OAAO,EAAE,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,QAAQ,EAAE,eAAe,EAAE,WAAW,IAAI,KAAK,CAAC,CAAC;AAOnG,MAAM,CAAC,MAAM,YAAY,GAAG,CAAC,OAAkC,EAAW,EAAE,CAC1E,CAAC,UAAU,CAAC,OAAO,EAAE,UAAU,CAAC,WAAW,CAAC,CAAC,QAAQ,CACnD,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAC,QAAsB,CAChD,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,SAAS,EAAE,IAAI,CAAC;AAEzC,MAAM,CAAC,MAAM,qBAAqB,GAAG,CAAC,OAA4B,EAAY,EAAE;IAC9E,MAAM,QAAQ,GAGR;QACJ;YACE,QAAQ,EAAE,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,cAAc,EAAE,KAAK,EAAE,OAAO;YAC7D,eAAe,EAAE,OAAO;SACzB;QACD;YACE,QAAQ,EAAE,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,cAAc,EAAE,QAAQ,EAAE,OAAO;YAChE,eAAe,EAAE,UAAU;SAC5B;QACD,EAAE,QAAQ,EAAE,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,WAAW,CAAC,GAAG,EAAE,eAAe,EAAE,KAAK,EAAE;QAC1E;YACE,QAAQ,EAAE,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,WAAW,CAAC,gBAAgB;YAC3D,eAAe,EAAE,kBAAkB;SACpC;QACD;YACE,QAAQ,EAAE,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,WAAW,CAAC,kBAAkB;YAC7D,eAAe,EAAE,oBAAoB;SACtC;QACD;YACE,QAAQ,EAAE,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,WAAW,CAAC,OAAO;YAClD,eAAe,EAAE,SAAS;SAC3B;QACD;YACE,QAAQ,EAAE,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,WAAW,CAAC,IAAI;YAC/C,eAAe,EAAE,MAAM;SACxB;QACD;YACE,QAAQ,EAAE,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,WAAW,CAAC,WAAW;YACtD,eAAe,EAAE,aAAa;SAC/B;QACD;YACE,QAAQ,EAAE,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,WAAW,CAAC,IAAI;YAC/C,eAAe,EAAE,MAAM;SACxB;QACD;YACE,QAAQ,EAAE,CAAC,OAAO,EAAE,EAAE,CACpB,OAAO,CAAC,eAAe,EAAE,oBAAoB,EAAE,SAAS;gBACxD,OAAO,CAAC,eAAe,EAAE,oBAAoB,EAAE,QAAQ;YACzD,eAAe,EAAE,UAAU;SAC5B;KACF,CAAC;IAEF,OAAO,QAAQ;SACZ,MAAM,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;SAChD,GAAG,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,eAAe,CAAC,CAAC;AAC/C,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAAC,EAC/B,IAAI,EACJ,QAAQ,EACR,SAAS,EACT,QAAQ,EACR,aAAa,GAOd,EAAU,EAAE;IACX,IAAI,QAAQ,KAAK,UAAU,CAAC,OAAO,IAAI,QAAQ,KAAK,UAAU,CAAC,WAAW,EAAE,CAAC;QAC3E,OAAO,CAAC,IAAI,EAAE,SAAS,EAAE,aAAa,EAAE,QAAQ,CAAC;aAC9C,MAAM,CAAC,CAAC,CAAC,EAAe,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;aAC/B,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;aACpB,IAAI,CAAC,GAAG,CAAC;aACT,IAAI,EAAE,CAAC;IACZ,CAAC;IAED,OAAO,CAAC,IAAI,EAAE,SAAS,EAAE,aAAa,CAAC;SACpC,MAAM,CAAC,CAAC,CAAC,EAAe,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;SAC/B,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;SACpB,IAAI,CAAC,GAAG,CAAC;SACT,IAAI,EAAE,CAAC;AACZ,CAAC,CAAC;AAEF,MAAM,QAAQ,GAAG,4BAA4B,CAAC;AAG9C,MAAM,CAAC,MAAM,sBAAsB,GAAG,CAAC,GAAW,EAAU,EAAE;IAC5D,MAAM,aAAa,GAAG,QAAQ,CAAC,MAAM,CAAC;IAEtC,IAAI,GAAG,GAAG,CAAC,EAAE,CAAC;QACZ,OAAO,EAAE,CAAC;IACZ,CAAC;IAED,IAAI,SAAS,GAAG,GAAG,GAAG,aAAa,CAAC;IACpC,IAAI,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,GAAG,aAAa,CAAC,CAAC;IAG/C,IAAI,SAAS,KAAK,CAAC,EAAE,CAAC;QACpB,SAAS,GAAG,aAAa,CAAC;QAC1B,QAAQ,IAAI,CAAC,CAAC;IAChB,CAAC;IAED,OAAO,sBAAsB,CAAC,QAAQ,CAAC,GAAG,QAAQ,CAAC,MAAM,CAAC,SAAS,GAAG,CAAC,CAAC,CAAC;AAC3E,CAAC,CAAC;AAGF,MAAM,CAAC,MAAM,sBAAsB,GAAG,CAAC,OAAe,EAAU,EAAE;IAChE,MAAM,IAAI,GAAG,QAAQ,CAAC,MAAM,CAAC;IAE7B,IAAI,MAAM,GAAG,CAAC,CAAC;IAEf,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACxC,MAAM,SAAS,GAAG,QAAQ,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;QACnD,MAAM,GAAG,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC;IACrC,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC,CAAC;AASF,MAAM,CAAC,MAAM,uBAAuB,GAAG,CAAC,aAAqB,EAAU,EAAE,CACvE,MAAM,aAAa,mBAAmB,CAAC;AAEzC,MAAM,CAAC,MAAM,yBAAyB,GAAG,CAAC,WAAmB,EAAU,EAAE;IACvE,MAAM,cAAc,GAAG,6BAA6B,CAAC;IACrD,MAAM,KAAK,GAAG,WAAW,CAAC,KAAK,CAAC,cAAc,CAAC,CAAC;IAChD,IAAI,KAAK,IAAI,IAAI,EAAE,CAAC;QAClB,MAAM,IAAI,MAAM,CAAC,oCAAoC,EAAE,EAAE,WAAW,EAAE,CAAC,CAAC;IAC1E,CAAC;IAED,MAAM,eAAe,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;IACjC,MAAM,cAAc,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;IAChC,MAAM,aAAa,GAAG,sBAAsB,CAAC,cAAc,CAAC,CAAC;IAC7D,MAAM,iBAAiB,GAAG,aAAa,GAAG,CAAC,CAAC;IAC5C,MAAM,kBAAkB,GAAG,sBAAsB,CAAC,iBAAiB,CAAC,CAAC;IACrE,OAAO,GAAG,eAAe,GAAG,kBAAkB,EAAE,CAAC;AACnD,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,qBAAqB,GAAG,CACnC,QAA6B,EAC7B,EACE,eAAe,GAAG,KAAK,EACvB,qBAAqB,GAAG,KAAK,EAC7B,IAAI,GAKL,EACD,EAAE;IACF,MAAM,UAAU,GAAG;QACjB,QAAQ,CAAC,cAAc,EAAE,UAAU,EAAE,QAAQ;QAC7C,QAAQ,CAAC,cAAc,EAAE,UAAU,EAAE,UAAU;KAChD;SACE,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC;SAC1B,IAAI,CAAC,EAAE,CAAC,CAAC;IACZ,MAAM,WAAW,GAAG,IAAI,CAAC,YAAY,CAAC,IAAI,EAAE;QAC1C,KAAK,EAAE,MAAM;QACb,IAAI,EAAE,WAAW;KAClB,CAAC,CAAC;IAEH,MAAM,IAAI,GAAG,iBAAiB,CAAC;QAC7B,eAAe,CAAC,CAAC,CAAC,QAAQ,CAAC,cAAc,CAAC,WAAW,CAAC,CAAC,CAAC,SAAS;QACjE,QAAQ,CAAC,OAAO,EAAE,eAAe;QACjC,QAAQ,CAAC,SAAS,EAAE,QAAQ,EAAE,EAAE,IAAI,IAAI;YACtC,CAAC,CAAC,WAAW,CAAC,MAAM,CAAC,QAAQ,CAAC,SAAS,CAAC,QAAQ,CAAC,EAAE,CAAC;YACpD,CAAC,CAAC,SAAS;QACb,QAAQ,CAAC,UAAU,EAAE,SAAS,EAAE,QAAQ,IAAI,QAAQ,CAAC,UAAU,EAAE,SAAS,EAAE,KAAK;QACjF,UAAU;QACV,qBAAqB,CAAC,CAAC,CAAC,QAAQ,CAAC,UAAU,EAAE,KAAK,EAAE,aAAa,CAAC,CAAC,CAAC,SAAS;KAC9E,CAAC,CAAC;IAEH,OAAO,IAAI,CAAC;AACd,CAAC,CAAC","sourcesContent":["import { XError } from '@bisondesk/commons-sdk/errors';\nimport { joinWithSeparator } from '@bisondesk/commons-sdk/formatting';\nimport { Categories } from '../constants.js';\nimport {\n Vehicle,\n VehicleExternalInfo,\n VehiclePurchase,\n VehiclePurchaseDealStatus,\n} from '../types/vehicles.js';\n\n/**\n * The deal has not been committed: there is no purchase yet, or its deal is still in\n * `Marketing`. Copies are created in this state; it ends when the owner agrees to buy\n * (e.g. an ICO invoice moves the deal to PurchaseAgreed).\n */\nexport const isDealInMarketing = (purchase: VehiclePurchase | undefined): boolean =>\n purchase == null || purchase.deal.status === VehiclePurchaseDealStatus.Marketing;\n\n/**\n * A cross-tenant copy whose source still masters it: it has an `original` link and its deal is\n * still in Marketing ({@link isDealInMarketing}). While this holds, the next sync overwrites\n * `external` (specs, pictures, videos) and `salesConditions` from the source; once the deal\n * progresses, the vehicle is the owner's own stock and the sync hands off. Native vehicles are\n * never source-mastered.\n */\nexport const isSourceMastered = (\n vehicle: Pick<Vehicle, 'original'>,\n purchase: VehiclePurchase | undefined,\n): boolean => vehicle.original != null && isDealInMarketing(purchase);\n\n/**\n * A cross-tenant copy whose source is not sellable, as stamped on the last sync hop. Only\n * meaningful while the source still masters the copy ({@link isSourceMastered}): past Marketing\n * the vehicle is the owner's own stock, and a still-present flag is merely stale — the sync\n * clears it on the next source event — so it must be ignored.\n */\nexport const isUnavailableFromSource = (\n vehicle: Pick<Vehicle, 'original'>,\n purchase: VehiclePurchase | undefined,\n): boolean =>\n isSourceMastered(vehicle, purchase) && (vehicle.original?.salesConditions?.unavailable ?? false);\n\n/**\n * A trailer or semi-trailer that has never been used — what the sales ladder calls a new\n * trailer, and the reason it has opportunity types of its own (`NEW_TRAILER`,\n * `NEW_TRAILER_NEW_PRODUCTION`) instead of going through plain sales.\n */\nexport const isNewTrailer = (vehicle: Pick<Vehicle, 'external'>): boolean =>\n [Categories.Trailer, Categories.SemiTrailer].includes(\n vehicle.external.general.category as Categories,\n ) && !vehicle.external.condition?.used;\n\nexport const extractCustomFeatures = (vehicle: VehicleExternalInfo): string[] => {\n const features: {\n getValue: (vehicle: VehicleExternalInfo) => any;\n picklistValueId: string;\n }[] = [\n {\n getValue: (vehicle) => vehicle.superstructure?.crane?.present,\n picklistValueId: 'crane',\n },\n {\n getValue: (vehicle) => vehicle.superstructure?.tailgate?.present,\n picklistValueId: 'tailgate',\n },\n { getValue: (vehicle) => vehicle.accessories.adr, picklistValueId: 'adr' },\n {\n getValue: (vehicle) => vehicle.accessories.retarderIntarder,\n picklistValueId: 'retarderIntarder',\n },\n {\n getValue: (vehicle) => vehicle.accessories.hydraulicTipperKit,\n picklistValueId: 'hydraulicTipperKit',\n },\n {\n getValue: (vehicle) => vehicle.accessories.lowDeck,\n picklistValueId: 'lowDeck',\n },\n {\n getValue: (vehicle) => vehicle.accessories.coil,\n picklistValueId: 'coil',\n },\n {\n getValue: (vehicle) => vehicle.accessories.doubleStock,\n picklistValueId: 'doubleStock',\n },\n {\n getValue: (vehicle) => vehicle.accessories.mega,\n picklistValueId: 'mega',\n },\n {\n getValue: (vehicle) =>\n vehicle.salesConditions?.manufacturerWarranty?.available ||\n vehicle.salesConditions?.manufacturerWarranty?.included,\n picklistValueId: 'warranty',\n },\n ];\n\n return features\n .filter((feature) => !!feature.getValue(vehicle))\n .map((feature) => feature.picklistValueId);\n};\n\nexport const getInternalTitle = ({\n make,\n category,\n modelName,\n bodywork,\n modelTypeName,\n}: {\n category: string;\n make?: string;\n modelName?: string;\n modelTypeName?: string;\n bodywork?: string;\n}): string => {\n if (category === Categories.Trailer || category === Categories.SemiTrailer) {\n return [make, modelName, modelTypeName, bodywork]\n .filter((v): v is string => !!v)\n .map((v) => v.trim())\n .join(' ')\n .trim();\n }\n\n return [make, modelName, modelTypeName]\n .filter((v): v is string => !!v)\n .map((v) => v.trim())\n .join(' ')\n .trim();\n};\n\nconst ALPHABET = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';\n\n// example: 1 -> A, 2 -> B, 26 -> Z, 27 -> AA, 28 -> AB, 52 -> AZ, 53 -> BA, 54 -> BB, 702 -> ZZ\nexport const convertNumberToLetters = (num: number): string => {\n const lettersLength = ALPHABET.length;\n\n if (num < 1) {\n return '';\n }\n\n let remainder = num % lettersLength;\n let quotient = Math.floor(num / lettersLength);\n\n // If remainder is 0, it means we should map it to 'Z' and reduce the quotient by 1\n if (remainder === 0) {\n remainder = lettersLength;\n quotient -= 1;\n }\n\n return convertNumberToLetters(quotient) + ALPHABET.charAt(remainder - 1);\n};\n\n// example: A -> 1, B -> 2, Z -> 26, AA -> 27, AB -> 28, AZ -> 52, BA -> 53, BB -> 54, ZZ -> 702\nexport const convertLettersToNumber = (letters: string): number => {\n const base = ALPHABET.length;\n\n let result = 0;\n\n for (let i = 0; i < letters.length; i++) {\n const charValue = ALPHABET.indexOf(letters[i]) + 1;\n result = result * base + charValue;\n }\n\n return result;\n};\n\n/**\n * Canonical stock-number shape: a branch prefix of 1 to 3 letters followed by exactly 5 digits\n * and up to 2 trailing counter letters (e.g. B49397AB, TC12345 — see\n * {@link getNextRelatedStockNumber}). Callers supply the prefix pattern (concrete branch\n * prefixes, or a policy like `[A-Z]{2}`) and wrap their own boundary/anchor policy around the\n * returned pattern.\n */\nexport const buildStockNumberPattern = (prefixPattern: string): string =>\n `(?:${prefixPattern})\\\\d{5}[A-Z]{0,2}`;\n\nexport const getNextRelatedStockNumber = (stockNumber: string): string => {\n const counterPattern = /^([A-Z]+\\d{5})([A-Z]{0,2})$/;\n const match = stockNumber.match(counterPattern);\n if (match == null) {\n throw new XError('core-sdk.vehicles.bad-stock-number', { stockNumber });\n }\n\n const baseStockNumber = match[1];\n const counterLetters = match[2];\n const counterNumber = convertLettersToNumber(counterLetters);\n const nextCounterNumber = counterNumber + 1;\n const nextCounterLetters = convertNumberToLetters(nextCounterNumber);\n return `${baseStockNumber}${nextCounterLetters}`;\n};\n\nexport const getVehicleDescription = (\n external: VehicleExternalInfo,\n {\n showStockNumber = false,\n showAxleConfiguration = false,\n lang,\n }: {\n showStockNumber?: boolean;\n showAxleConfiguration?: boolean;\n lang?: string;\n },\n) => {\n const dimensions = [\n external.superstructure?.dimensions?.extended,\n external.superstructure?.dimensions?.heightened,\n ]\n .filter((value) => !!value)\n .join('');\n const kmFormatter = Intl.NumberFormat(lang, {\n style: 'unit',\n unit: 'kilometer',\n });\n\n const text = joinWithSeparator([\n showStockNumber ? external.identification.stockNumber : undefined,\n external.history?.advertisingYear,\n external.condition?.odometer?.km != null\n ? kmFormatter.format(external.condition.odometer.km)\n : undefined,\n external.powertrain?.emissions?.subclass ?? external.powertrain?.emissions?.class,\n dimensions,\n showAxleConfiguration ? external.powertrain?.axles?.configuration : undefined,\n ]);\n\n return text;\n};\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bisondesk/core-sdk",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.628",
|
|
4
4
|
"description": "",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"author": "TheTruckCompany",
|
|
@@ -36,7 +36,7 @@
|
|
|
36
36
|
},
|
|
37
37
|
"scripts": {
|
|
38
38
|
"clean": "rm -rf build dist lib *.tsbuildinfo",
|
|
39
|
-
"unittest": "
|
|
39
|
+
"unittest": "npx vitest run src/",
|
|
40
40
|
"integrationtest": "echo \"No test specified\"",
|
|
41
41
|
"build": "npx tsc --build tsconfig.json",
|
|
42
42
|
"watch": "npx tsc --build --watch"
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { TENANT_ID_ADMIN_HEADER } from '@bisondesk/commons-sdk/constants';
|
|
2
|
+
import { XError } from '@bisondesk/commons-sdk/errors';
|
|
3
|
+
import { InternetOpportunityEvent } from '../types/internet-opportunities.js';
|
|
4
|
+
import { createInternetOpportunity } from './opportunities.js';
|
|
5
|
+
|
|
6
|
+
const ADMIN_KEY = 'test-admin-key';
|
|
7
|
+
const ORIGIN = 'https://core.example.com';
|
|
8
|
+
|
|
9
|
+
const event: InternetOpportunityEvent = {
|
|
10
|
+
tenantId: 'ttc',
|
|
11
|
+
branchId: 'ttc-nl',
|
|
12
|
+
name: 'John Doe',
|
|
13
|
+
phoneNumber: '+31612345678',
|
|
14
|
+
source: 'website',
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
const mockFetch = vi.fn();
|
|
18
|
+
|
|
19
|
+
const okResponse = (): Response =>
|
|
20
|
+
({
|
|
21
|
+
ok: true,
|
|
22
|
+
status: 202,
|
|
23
|
+
json: async () => ({ queued: true }),
|
|
24
|
+
}) as unknown as Response;
|
|
25
|
+
|
|
26
|
+
const errorResponse = (status: number, statusText: string): Response =>
|
|
27
|
+
({
|
|
28
|
+
ok: false,
|
|
29
|
+
status,
|
|
30
|
+
statusText,
|
|
31
|
+
text: async () => statusText,
|
|
32
|
+
}) as unknown as Response;
|
|
33
|
+
|
|
34
|
+
beforeEach(() => {
|
|
35
|
+
vi.resetAllMocks();
|
|
36
|
+
vi.stubGlobal('fetch', mockFetch);
|
|
37
|
+
process.env.ADMIN_KEY = ADMIN_KEY;
|
|
38
|
+
process.env.CORE_API_ORIGIN = ORIGIN;
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
afterEach(() => {
|
|
42
|
+
vi.unstubAllGlobals();
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
describe('createInternetOpportunity', () => {
|
|
46
|
+
test('POSTs to /api/opportunities/internet with admin auth + tenant headers and JSON body', async () => {
|
|
47
|
+
mockFetch.mockResolvedValueOnce(okResponse());
|
|
48
|
+
|
|
49
|
+
await createInternetOpportunity(event);
|
|
50
|
+
|
|
51
|
+
expect(mockFetch).toHaveBeenCalledTimes(1);
|
|
52
|
+
const [url, init] = mockFetch.mock.calls[0];
|
|
53
|
+
expect(url.toString()).toBe(`${ORIGIN}/api/opportunities/internet`);
|
|
54
|
+
expect(init.method).toBe('POST');
|
|
55
|
+
expect(init.body).toBe(JSON.stringify(event));
|
|
56
|
+
|
|
57
|
+
const headers = Object.fromEntries(init.headers as [string, string][]);
|
|
58
|
+
expect(headers.Authorization).toBe(`AdminKey ${ADMIN_KEY}`);
|
|
59
|
+
expect(headers['Content-Type']).toBe('application/json');
|
|
60
|
+
expect(headers[TENANT_ID_ADMIN_HEADER]).toBe(event.tenantId);
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
test('throws XError when the response is a non-2xx', async () => {
|
|
64
|
+
mockFetch.mockResolvedValueOnce(errorResponse(500, 'Internal Server Error'));
|
|
65
|
+
|
|
66
|
+
await expect(createInternetOpportunity(event)).rejects.toBeInstanceOf(XError);
|
|
67
|
+
});
|
|
68
|
+
});
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { TENANT_ID_ADMIN_HEADER } from '@bisondesk/commons-sdk/constants';
|
|
2
2
|
import { cleanHeaders, fetchJson, getAdminAuth } from '@bisondesk/commons-sdk/fetch';
|
|
3
|
+
import { InternetOpportunityEvent } from '../types/internet-opportunities.js';
|
|
3
4
|
import {
|
|
4
5
|
Bid,
|
|
5
6
|
ListOpportunitiesFilters,
|
|
@@ -101,6 +102,19 @@ export const createOpportunity = async (
|
|
|
101
102
|
return response;
|
|
102
103
|
};
|
|
103
104
|
|
|
105
|
+
export const createInternetOpportunity = async (event: InternetOpportunityEvent): Promise<void> => {
|
|
106
|
+
const auth = await getAdminAuth();
|
|
107
|
+
await fetchJson(`${process.env.CORE_API_ORIGIN}/api/opportunities/internet`, {
|
|
108
|
+
method: 'POST',
|
|
109
|
+
headers: cleanHeaders({
|
|
110
|
+
Authorization: auth,
|
|
111
|
+
[TENANT_ID_ADMIN_HEADER]: event.tenantId,
|
|
112
|
+
'Content-Type': 'application/json',
|
|
113
|
+
}),
|
|
114
|
+
body: JSON.stringify(event),
|
|
115
|
+
});
|
|
116
|
+
};
|
|
117
|
+
|
|
104
118
|
//
|
|
105
119
|
// Bids
|
|
106
120
|
//
|
|
@@ -93,6 +93,8 @@ export enum OpportunityWarningsCode {
|
|
|
93
93
|
QUOTE_MISSING_FINANCING_DETAILS = 'quote_missing_financing_details',
|
|
94
94
|
VEHICLE_BRANCH_MISMATCH = 'vehicle_branch_mismatch',
|
|
95
95
|
VEHICLE_UNAVAILABLE_AT_SOURCE = 'vehicle_unavailable_at_source',
|
|
96
|
+
INTERCOMPANY_LINKED = 'intercompany_linked',
|
|
97
|
+
INTERCOMPANY_SOURCE_OPPORTUNITY = 'intercompany_source_opportunity',
|
|
96
98
|
}
|
|
97
99
|
|
|
98
100
|
export const OpportunityWonColumnId = 'closed_won';
|
|
@@ -266,6 +268,12 @@ export type OpportunityStatusRequirement = { code: OpportunityRequirementsCode;
|
|
|
266
268
|
type OportunityWarningActionLink = {
|
|
267
269
|
businessEntityId: BusinessEntityIds;
|
|
268
270
|
recordId: string;
|
|
271
|
+
/**
|
|
272
|
+
* Absolute URL, set only when the record lives at another tenant — in-app routing cannot
|
|
273
|
+
* reach it, so the client opens it in a new tab. Same shape the intercompany payments walk
|
|
274
|
+
* already hands the client (ADR-0024's `opportunityUrl`).
|
|
275
|
+
*/
|
|
276
|
+
url?: string;
|
|
269
277
|
};
|
|
270
278
|
|
|
271
279
|
type OportunityWarningActionData = { [key: string]: string | number };
|
package/src/types/tenants.ts
CHANGED
|
@@ -116,6 +116,10 @@ export type Branch = {
|
|
|
116
116
|
externalQuote?: boolean;
|
|
117
117
|
hyperdmsId?: string;
|
|
118
118
|
internalDealsEnabled?: boolean;
|
|
119
|
+
/** The source invoices the end customer directly; this branch collects payment and earns
|
|
120
|
+
* commission. Intercompany source opportunities for this branch's deals take the buyer
|
|
121
|
+
* deal's own client instead of the branch counterparty org. */
|
|
122
|
+
dropshipping?: boolean;
|
|
119
123
|
};
|
|
120
124
|
|
|
121
125
|
export type HdmsVehiclesSync = {
|
|
@@ -61,6 +61,9 @@ export const isBeforeReferenceOpportunityStatus = (input: CompareInput): boolean
|
|
|
61
61
|
|
|
62
62
|
export const isOpportunityLost = (input: Opportunity): boolean => input.lostAt != null;
|
|
63
63
|
|
|
64
|
+
export const isOpportunityClosed = (input: Opportunity): boolean =>
|
|
65
|
+
input.lostAt != null || input.wonAt != null;
|
|
66
|
+
|
|
64
67
|
export const getOpportunityReservedStatus = (): OpportunityStatus[] => [
|
|
65
68
|
OpportunityStatus.REVIEW,
|
|
66
69
|
OpportunityStatus.PREPARATION,
|
package/src/utils/tenants.ts
CHANGED
|
@@ -13,6 +13,10 @@ export const getBranch = (tenant: Tenant, branchId: string): Branch => {
|
|
|
13
13
|
|
|
14
14
|
export const getDefaultBranch = (tenant: Tenant): Branch => first(tenant.branches)!;
|
|
15
15
|
|
|
16
|
+
/** The source invoices the end customer directly; this branch collects payment and earns
|
|
17
|
+
* commission (see {@link Branch.dropshipping}). */
|
|
18
|
+
export const isDropshippingBranch = (branch: Branch): boolean => branch.dropshipping === true;
|
|
19
|
+
|
|
16
20
|
export const getBranchStandardVatRate = (tenant: Tenant, branchId: string): string => {
|
|
17
21
|
const branch: Branch = getBranch(tenant, branchId);
|
|
18
22
|
return branch.vatRates.standard;
|
package/src/utils/vehicles.ts
CHANGED
|
@@ -40,6 +40,16 @@ export const isUnavailableFromSource = (
|
|
|
40
40
|
): boolean =>
|
|
41
41
|
isSourceMastered(vehicle, purchase) && (vehicle.original?.salesConditions?.unavailable ?? false);
|
|
42
42
|
|
|
43
|
+
/**
|
|
44
|
+
* A trailer or semi-trailer that has never been used — what the sales ladder calls a new
|
|
45
|
+
* trailer, and the reason it has opportunity types of its own (`NEW_TRAILER`,
|
|
46
|
+
* `NEW_TRAILER_NEW_PRODUCTION`) instead of going through plain sales.
|
|
47
|
+
*/
|
|
48
|
+
export const isNewTrailer = (vehicle: Pick<Vehicle, 'external'>): boolean =>
|
|
49
|
+
[Categories.Trailer, Categories.SemiTrailer].includes(
|
|
50
|
+
vehicle.external.general.category as Categories,
|
|
51
|
+
) && !vehicle.external.condition?.used;
|
|
52
|
+
|
|
43
53
|
export const extractCustomFeatures = (vehicle: VehicleExternalInfo): string[] => {
|
|
44
54
|
const features: {
|
|
45
55
|
getValue: (vehicle: VehicleExternalInfo) => any;
|
|
@@ -155,6 +165,16 @@ export const convertLettersToNumber = (letters: string): number => {
|
|
|
155
165
|
return result;
|
|
156
166
|
};
|
|
157
167
|
|
|
168
|
+
/**
|
|
169
|
+
* Canonical stock-number shape: a branch prefix of 1 to 3 letters followed by exactly 5 digits
|
|
170
|
+
* and up to 2 trailing counter letters (e.g. B49397AB, TC12345 — see
|
|
171
|
+
* {@link getNextRelatedStockNumber}). Callers supply the prefix pattern (concrete branch
|
|
172
|
+
* prefixes, or a policy like `[A-Z]{2}`) and wrap their own boundary/anchor policy around the
|
|
173
|
+
* returned pattern.
|
|
174
|
+
*/
|
|
175
|
+
export const buildStockNumberPattern = (prefixPattern: string): string =>
|
|
176
|
+
`(?:${prefixPattern})\\d{5}[A-Z]{0,2}`;
|
|
177
|
+
|
|
158
178
|
export const getNextRelatedStockNumber = (stockNumber: string): string => {
|
|
159
179
|
const counterPattern = /^([A-Z]+\d{5})([A-Z]{0,2})$/;
|
|
160
180
|
const match = stockNumber.match(counterPattern);
|