@bisondesk/core-sdk 1.0.678 → 1.0.680

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.
@@ -0,0 +1,40 @@
1
+ import { BusinessEntityIds } from '../constants.js';
2
+ import { TransportStatus, TransportType } from '../types/transports.js';
3
+ import { VehiclePurchaseLogisticsStatus } from '../types/vehicles.js';
4
+ import { getTransportDocumentOwner, isTransportCompleted } from './transports.js';
5
+ describe('getTransportDocumentOwner', () => {
6
+ test.each([
7
+ {
8
+ description: 'a sale transport files on its deal',
9
+ transport: { type: TransportType.Sale, vehicleId: 'V1', opportunityId: 'OPP1' },
10
+ expected: { businessEntityId: BusinessEntityIds.Opportunities, recordId: 'OPP1' },
11
+ },
12
+ {
13
+ description: 'a purchase transport files on its vehicle',
14
+ transport: { type: TransportType.Purchase, vehicleId: 'V1' },
15
+ expected: { businessEntityId: BusinessEntityIds.Vehicles, recordId: 'V1' },
16
+ },
17
+ {
18
+ description: 'a sale transport without a deal has no owner',
19
+ transport: { type: TransportType.Sale, vehicleId: 'V1' },
20
+ expected: undefined,
21
+ },
22
+ ])('$description', ({ transport, expected }) => {
23
+ expect(getTransportDocumentOwner(transport)).toEqual(expected);
24
+ });
25
+ });
26
+ describe('isTransportCompleted', () => {
27
+ test.each([
28
+ { status: TransportStatus.Done, expected: true },
29
+ { status: TransportStatus.OngoingInternal, expected: false },
30
+ ])('a sale transport at $status is completed: $expected', ({ status, expected }) => {
31
+ expect(isTransportCompleted({ type: TransportType.Sale, status }, {})).toBe(expected);
32
+ });
33
+ test.each([
34
+ { logistics: VehiclePurchaseLogisticsStatus.Arrived, expected: true },
35
+ { logistics: VehiclePurchaseLogisticsStatus.AtOrigin, expected: false },
36
+ ])('a purchase transport whose vehicle is $logistics is completed: $expected', ({ logistics, expected, }) => {
37
+ expect(isTransportCompleted({ type: TransportType.Purchase, status: TransportStatus.OngoingInternal }, { purchase: { logistics: { status: logistics } } })).toBe(expected);
38
+ });
39
+ });
40
+ //# sourceMappingURL=transports.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"transports.test.js","sourceRoot":"/","sources":["utils/transports.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AACpD,OAAO,EAAE,eAAe,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AACxE,OAAO,EAAE,8BAA8B,EAAE,MAAM,sBAAsB,CAAC;AACtE,OAAO,EAAE,yBAAyB,EAAE,oBAAoB,EAAE,MAAM,iBAAiB,CAAC;AAElF,QAAQ,CAAC,2BAA2B,EAAE,GAAG,EAAE;IACzC,IAAI,CAAC,IAAI,CAAC;QACR;YACE,WAAW,EAAE,oCAAoC;YACjD,SAAS,EAAE,EAAE,IAAI,EAAE,aAAa,CAAC,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,aAAa,EAAE,MAAM,EAAE;YAC/E,QAAQ,EAAE,EAAE,gBAAgB,EAAE,iBAAiB,CAAC,aAAa,EAAE,QAAQ,EAAE,MAAM,EAAE;SAClF;QACD;YACE,WAAW,EAAE,2CAA2C;YACxD,SAAS,EAAE,EAAE,IAAI,EAAE,aAAa,CAAC,QAAQ,EAAE,SAAS,EAAE,IAAI,EAAE;YAC5D,QAAQ,EAAE,EAAE,gBAAgB,EAAE,iBAAiB,CAAC,QAAQ,EAAE,QAAQ,EAAE,IAAI,EAAE;SAC3E;QACD;YACE,WAAW,EAAE,8CAA8C;YAC3D,SAAS,EAAE,EAAE,IAAI,EAAE,aAAa,CAAC,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE;YACxD,QAAQ,EAAE,SAAS;SACpB;KACF,CAAC,CAAC,cAAc,EAAE,CAAC,EAAE,SAAS,EAAE,QAAQ,EAAE,EAAE,EAAE;QAC7C,MAAM,CAAC,yBAAyB,CAAC,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;IACjE,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,QAAQ,CAAC,sBAAsB,EAAE,GAAG,EAAE;IACpC,IAAI,CAAC,IAAI,CAAC;QACR,EAAE,MAAM,EAAE,eAAe,CAAC,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE;QAChD,EAAE,MAAM,EAAE,eAAe,CAAC,eAAe,EAAE,QAAQ,EAAE,KAAK,EAAE;KAC7D,CAAC,CAAC,qDAAqD,EAAE,CAAC,EAAE,MAAM,EAAE,QAAQ,EAAE,EAAE,EAAE;QACjF,MAAM,CAAC,oBAAoB,CAAC,EAAE,IAAI,EAAE,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;IACxF,CAAC,CAAC,CAAC;IAEH,IAAI,CAAC,IAAI,CAAC;QACR,EAAE,SAAS,EAAE,8BAA8B,CAAC,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE;QACrE,EAAE,SAAS,EAAE,8BAA8B,CAAC,QAAQ,EAAE,QAAQ,EAAE,KAAK,EAAE;KACxE,CAAC,CAAC,0EAA0E,EAAE,CAAC,EAC9E,SAAS,EACT,QAAQ,GACT,EAAE,EAAE;QACH,MAAM,CACJ,oBAAoB,CAClB,EAAE,IAAI,EAAE,aAAa,CAAC,QAAQ,EAAE,MAAM,EAAE,eAAe,CAAC,eAAe,EAAE,EACzE,EAAE,QAAQ,EAAE,EAAE,SAAS,EAAE,EAAE,MAAM,EAAE,SAAS,EAAE,EAAE,EAAE,CACnD,CACF,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;IACnB,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC","sourcesContent":["import { BusinessEntityIds } from '../constants.js';\nimport { TransportStatus, TransportType } from '../types/transports.js';\nimport { VehiclePurchaseLogisticsStatus } from '../types/vehicles.js';\nimport { getTransportDocumentOwner, isTransportCompleted } from './transports.js';\n\ndescribe('getTransportDocumentOwner', () => {\n test.each([\n {\n description: 'a sale transport files on its deal',\n transport: { type: TransportType.Sale, vehicleId: 'V1', opportunityId: 'OPP1' },\n expected: { businessEntityId: BusinessEntityIds.Opportunities, recordId: 'OPP1' },\n },\n {\n description: 'a purchase transport files on its vehicle',\n transport: { type: TransportType.Purchase, vehicleId: 'V1' },\n expected: { businessEntityId: BusinessEntityIds.Vehicles, recordId: 'V1' },\n },\n {\n description: 'a sale transport without a deal has no owner',\n transport: { type: TransportType.Sale, vehicleId: 'V1' },\n expected: undefined,\n },\n ])('$description', ({ transport, expected }) => {\n expect(getTransportDocumentOwner(transport)).toEqual(expected);\n });\n});\n\ndescribe('isTransportCompleted', () => {\n test.each([\n { status: TransportStatus.Done, expected: true },\n { status: TransportStatus.OngoingInternal, expected: false },\n ])('a sale transport at $status is completed: $expected', ({ status, expected }) => {\n expect(isTransportCompleted({ type: TransportType.Sale, status }, {})).toBe(expected);\n });\n\n test.each([\n { logistics: VehiclePurchaseLogisticsStatus.Arrived, expected: true },\n { logistics: VehiclePurchaseLogisticsStatus.AtOrigin, expected: false },\n ])('a purchase transport whose vehicle is $logistics is completed: $expected', ({\n logistics,\n expected,\n }) => {\n expect(\n isTransportCompleted(\n { type: TransportType.Purchase, status: TransportStatus.OngoingInternal },\n { purchase: { logistics: { status: logistics } } },\n ),\n ).toBe(expected);\n });\n});\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bisondesk/core-sdk",
3
- "version": "1.0.678",
3
+ "version": "1.0.680",
4
4
  "description": "",
5
5
  "type": "module",
6
6
  "author": "TheTruckCompany",
@@ -521,6 +521,7 @@ export type HpLeasingDealRunDataCi = HpLeasingDealRunDataBase & {
521
521
  dueeDuLeasingEnMois: number;
522
522
  travauxHorsNormesNecessaire: boolean;
523
523
  descriptionDesTravauxHorsNormes: string;
524
+ prixTravaexSupplementaire: string;
524
525
  };
525
526
 
526
527
  export type HpLeasingDealRequest = {
@@ -340,7 +340,7 @@ export const KANBAN_TRANSPORT_ITEM_FIELDS = [
340
340
  'org.name',
341
341
  'org.countryCode',
342
342
  'org.externalId',
343
- 'opportunity.deliveredAt',
343
+ 'opportunity.branch',
344
344
  'purchase.logistics.status',
345
345
  'purchase.logistics.availableWeek',
346
346
  'purchase.logistics.pickupAddress',
@@ -89,11 +89,23 @@ export type VehiclePurchasePaymentBff = {
89
89
  exportChecks?: PaymentExportChecks;
90
90
  };
91
91
 
92
+ /**
93
+ * The group an unpaid purchase is listed under, in the order the Unpaid list shows them: sold to a
94
+ * client (whether or not it has arrived), arrived on our park and not sold, or still expected —
95
+ * neither sold nor arrived.
96
+ */
97
+ export enum UnpaidPurchaseGroup {
98
+ Sold = 'sold',
99
+ Arrived = 'arrived',
100
+ Expected = 'expected',
101
+ }
102
+
92
103
  /**
93
104
  * A row on the Unpaid tab: an agreed purchase that still has an amount to authorise for payment.
94
105
  * Derived from the purchase deal and the payments already authorised, not a payment record.
95
106
  */
96
107
  export type UnpaidPurchase = {
108
+ group: UnpaidPurchaseGroup;
97
109
  vehicle: SearchVehicle;
98
110
  /** The agreed purchase price including VAT (`deal.purchase` grossed up by `deal.purchaseVatRate`),
99
111
  * so it matches the VAT-inclusive cost the vehicle purchase tab authorises against. */
@@ -110,6 +122,14 @@ export type UnpaidPurchase = {
110
122
  supplierName?: string;
111
123
  };
112
124
 
125
+ /** What a page of one Unpaid group carries besides its rows. */
126
+ export type UnpaidPurchasesMeta = {
127
+ /** Whether the requester may authorise a payment, as on the vehicle purchase tab. */
128
+ canAllowPayment: boolean;
129
+ /** How many purchases each group holds, for the group headers. */
130
+ counts: Record<UnpaidPurchaseGroup, number>;
131
+ };
132
+
113
133
  /** Body of the export request: the Processing payments to put in one file, the paying account, and the execution date. */
114
134
  export type ExportPaymentsRequest = {
115
135
  paymentIds: string[];
@@ -0,0 +1,50 @@
1
+ import { BusinessEntityIds } from '../constants.js';
2
+ import { TransportStatus, TransportType } from '../types/transports.js';
3
+ import { VehiclePurchaseLogisticsStatus } from '../types/vehicles.js';
4
+ import { getTransportDocumentOwner, isTransportCompleted } from './transports.js';
5
+
6
+ describe('getTransportDocumentOwner', () => {
7
+ test.each([
8
+ {
9
+ description: 'a sale transport files on its deal',
10
+ transport: { type: TransportType.Sale, vehicleId: 'V1', opportunityId: 'OPP1' },
11
+ expected: { businessEntityId: BusinessEntityIds.Opportunities, recordId: 'OPP1' },
12
+ },
13
+ {
14
+ description: 'a purchase transport files on its vehicle',
15
+ transport: { type: TransportType.Purchase, vehicleId: 'V1' },
16
+ expected: { businessEntityId: BusinessEntityIds.Vehicles, recordId: 'V1' },
17
+ },
18
+ {
19
+ description: 'a sale transport without a deal has no owner',
20
+ transport: { type: TransportType.Sale, vehicleId: 'V1' },
21
+ expected: undefined,
22
+ },
23
+ ])('$description', ({ transport, expected }) => {
24
+ expect(getTransportDocumentOwner(transport)).toEqual(expected);
25
+ });
26
+ });
27
+
28
+ describe('isTransportCompleted', () => {
29
+ test.each([
30
+ { status: TransportStatus.Done, expected: true },
31
+ { status: TransportStatus.OngoingInternal, expected: false },
32
+ ])('a sale transport at $status is completed: $expected', ({ status, expected }) => {
33
+ expect(isTransportCompleted({ type: TransportType.Sale, status }, {})).toBe(expected);
34
+ });
35
+
36
+ test.each([
37
+ { logistics: VehiclePurchaseLogisticsStatus.Arrived, expected: true },
38
+ { logistics: VehiclePurchaseLogisticsStatus.AtOrigin, expected: false },
39
+ ])('a purchase transport whose vehicle is $logistics is completed: $expected', ({
40
+ logistics,
41
+ expected,
42
+ }) => {
43
+ expect(
44
+ isTransportCompleted(
45
+ { type: TransportType.Purchase, status: TransportStatus.OngoingInternal },
46
+ { purchase: { logistics: { status: logistics } } },
47
+ ),
48
+ ).toBe(expected);
49
+ });
50
+ });
@@ -1,7 +1,7 @@
1
+ import { BusinessEntityIds } from '../constants.js';
1
2
  import { PurchaseDeliveryTypes } from '../types/deliveries.js';
2
- import { Opportunity } from '../types/opportunities.js';
3
3
  import { PickFieldIds } from '../types/search.js';
4
- import { SearchTransport, Transport, TransportType } from '../types/transports.js';
4
+ import { SearchTransport, Transport, TransportStatus, TransportType } from '../types/transports.js';
5
5
  import { VehiclePurchase } from '../types/vehicles.js';
6
6
  import { hasPurchaseArrived } from './vehicles.js';
7
7
 
@@ -14,39 +14,56 @@ export const isPurchaseDropOffTransport = (
14
14
  isPurchaseTransport(transport) && transport.delivery.type === PurchaseDeliveryTypes.DROP_OFF;
15
15
 
16
16
  /**
17
- * A transport is finished when the journey it describes has demonstrably happened: the customer has
18
- * the vehicle for a sale delivery, the vehicle is on our park for a purchase. From then on
19
- * the record is history and the server refuses edits to it.
17
+ * A transport is finished when the journey it describes is over. From then on the record is
18
+ * history and the server refuses edits to it.
20
19
  *
21
- * Not the same thing as the transport's own `doneAt`. Delivery can be declared on the opportunity
22
- * (a CMR, a delivery confirmation) and arrival on the purchase, without the transport ever being
23
- * moved — and reversing either of those is what unlocks the transport again, which a status stamped
24
- * on the transport itself could not express.
20
+ * A sale delivery is over when the transport itself is at Done: the transport drives the deal's
21
+ * delivery, not the other way around, so a deal delivered some other way (a CMR or the Deliver
22
+ * action, before that rule) does not lock a transport that never got there. Moving it out of Done
23
+ * unlocks it again.
24
+ *
25
+ * A purchase is over when the vehicle is on our park. The park declares the arrival on the purchase,
26
+ * without the transport ever being moved, and putting the purchase back to At origin is what
27
+ * unlocks the transport again.
25
28
  *
26
29
  * Shared so the board, the drawer and the server all answer the question the same way.
27
30
  */
28
31
  export const isTransportCompleted = (
29
- transport: Pick<Transport, 'type'>,
30
- context: {
31
- opportunity?: Pick<Opportunity, 'deliveredAt'>;
32
- purchase?: { logistics: Pick<VehiclePurchase['logistics'], 'status'> };
33
- },
32
+ transport: Pick<Transport, 'type' | 'status'>,
33
+ context: { purchase?: { logistics: Pick<VehiclePurchase['logistics'], 'status'> } } = {},
34
34
  ): boolean => {
35
35
  if (transport.type === TransportType.Sale) {
36
- return context.opportunity?.deliveredAt != null;
36
+ return transport.status === TransportStatus.Done;
37
37
  }
38
38
 
39
39
  return context.purchase != null && hasPurchaseArrived(context.purchase);
40
40
  };
41
41
 
42
- /** The same question asked of a search document, which already carries both sides. */
42
+ /** The same question asked of a search document, which already carries the purchase. */
43
43
  export const isSearchTransportCompleted = (
44
44
  record: PickFieldIds<
45
45
  SearchTransport,
46
- 'transport.type' | 'opportunity.deliveredAt' | 'purchase.logistics.status'
46
+ 'transport.type' | 'transport.status' | 'purchase.logistics.status'
47
47
  >,
48
- ): boolean =>
49
- isTransportCompleted(record.transport, {
50
- opportunity: record.opportunity,
51
- purchase: record.purchase,
52
- });
48
+ ): boolean => isTransportCompleted(record.transport, { purchase: record.purchase });
49
+
50
+ export type TransportDocumentOwner = {
51
+ businessEntityId: BusinessEntityIds.Opportunities | BusinessEntityIds.Vehicles;
52
+ recordId: string;
53
+ };
54
+
55
+ /**
56
+ * Where a transport's documents are filed. A transport owns none: a sale's belong to the deal and a
57
+ * purchase's to the vehicle, whose purchase tab lists them. Undefined for a sale without a deal.
58
+ */
59
+ export const getTransportDocumentOwner = (
60
+ transport: Pick<Transport, 'type' | 'vehicleId' | 'opportunityId'>,
61
+ ): TransportDocumentOwner | undefined => {
62
+ if (isPurchaseTransport(transport)) {
63
+ return { businessEntityId: BusinessEntityIds.Vehicles, recordId: transport.vehicleId };
64
+ }
65
+
66
+ return transport.opportunityId == null
67
+ ? undefined
68
+ : { businessEntityId: BusinessEntityIds.Opportunities, recordId: transport.opportunityId };
69
+ };