@unchainedshop/core-quotations 4.3.4 → 4.5.0

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/README.md CHANGED
@@ -1,5 +1,102 @@
1
- # Quotations (Unchained Engine)
1
+ [![npm version](https://img.shields.io/npm/v/@unchainedshop/core-quotations.svg)](https://npmjs.com/package/@unchainedshop/core-quotations)
2
+ [![License: EUPL-1.2](https://img.shields.io/badge/License-EUPL--1.2-blue.svg)](https://opensource.org/licenses/EUPL-1.2)
2
3
 
3
- This package contains business logic and database abstraction for quotations in Unchained.
4
+ # @unchainedshop/core-quotations
4
5
 
5
- Find documentation of available [settings](https://docs.unchained.shop/config/quotations/) here
6
+ Quotation management module for the Unchained Engine. Handles quote requests, proposals, and quotation workflows for custom pricing.
7
+
8
+ ## Installation
9
+
10
+ ```bash
11
+ npm install @unchainedshop/core-quotations
12
+ ```
13
+
14
+ ## Usage
15
+
16
+ ```typescript
17
+ import { configureQuotationsModule, QuotationStatus } from '@unchainedshop/core-quotations';
18
+
19
+ const quotationsModule = await configureQuotationsModule({ db });
20
+
21
+ // Create a quotation request
22
+ const quotationId = await quotationsModule.create({
23
+ userId: 'user-123',
24
+ productId: 'custom-product-456',
25
+ configuration: [{ key: 'quantity', value: '1000' }],
26
+ });
27
+
28
+ // Propose a quote
29
+ await quotationsModule.propose(quotationId, {
30
+ price: { amount: 5000, currency: 'CHF' },
31
+ expiresAt: new Date('2024-12-31'),
32
+ });
33
+
34
+ // Find quotations
35
+ const quotations = await quotationsModule.findQuotations({
36
+ status: QuotationStatus.PROPOSED,
37
+ });
38
+ ```
39
+
40
+ ## API Overview
41
+
42
+ ### Module Configuration
43
+
44
+ | Export | Description |
45
+ |--------|-------------|
46
+ | `configureQuotationsModule` | Configure and return the quotations module |
47
+
48
+ ### Queries
49
+
50
+ | Method | Description |
51
+ |--------|-------------|
52
+ | `findQuotation` | Find quotation by ID |
53
+ | `findQuotations` | Find quotations with filtering and pagination |
54
+ | `count` | Count quotations matching query |
55
+ | `quotationExists` | Check if quotation exists |
56
+
57
+ ### Mutations
58
+
59
+ | Method | Description |
60
+ |--------|-------------|
61
+ | `create` | Create a quotation request |
62
+ | `update` | Update quotation data |
63
+ | `delete` | Delete a quotation |
64
+ | `propose` | Propose a quote |
65
+ | `verify` | Verify a quotation |
66
+ | `reject` | Reject a quotation |
67
+ | `fulfill` | Mark quotation as fulfilled |
68
+
69
+ ### Constants
70
+
71
+ | Export | Description |
72
+ |--------|-------------|
73
+ | `QuotationStatus` | Status values (REQUESTED, PROCESSING, PROPOSED, FULLFILLED, REJECTED) |
74
+
75
+ ### Settings
76
+
77
+ | Export | Description |
78
+ |--------|-------------|
79
+ | `quotationsSettings` | Access quotation module settings |
80
+
81
+ ### Types
82
+
83
+ | Export | Description |
84
+ |--------|-------------|
85
+ | `Quotation` | Quotation document type |
86
+ | `QuotationConfiguration` | Configuration item type |
87
+ | `QuotationsModule` | Module interface type |
88
+
89
+ ## Events
90
+
91
+ | Event | Description |
92
+ |-------|-------------|
93
+ | `QUOTATION_CREATE` | Quotation requested |
94
+ | `QUOTATION_UPDATE` | Quotation updated |
95
+ | `QUOTATION_REMOVE` | Quotation deleted |
96
+ | `QUOTATION_PROPOSE` | Quote proposed |
97
+ | `QUOTATION_REJECT` | Quotation rejected |
98
+ | `QUOTATION_FULLFILL` | Quotation fulfilled |
99
+
100
+ ## License
101
+
102
+ EUPL-1.2
@@ -1,11 +1,12 @@
1
- import { mongodb, TimestampFields, LogFields } from '@unchainedshop/mongodb';
2
- export declare enum QuotationStatus {
3
- REQUESTED = "REQUESTED",
4
- PROCESSING = "PROCESSING",
5
- PROPOSED = "PROPOSED",
6
- FULLFILLED = "FULLFILLED",
7
- REJECTED = "REJECTED"
8
- }
1
+ import { mongodb, type TimestampFields, type LogFields } from '@unchainedshop/mongodb';
2
+ export declare const QuotationStatus: {
3
+ readonly REQUESTED: "REQUESTED";
4
+ readonly PROCESSING: "PROCESSING";
5
+ readonly PROPOSED: "PROPOSED";
6
+ readonly FULLFILLED: "FULLFILLED";
7
+ readonly REJECTED: "REJECTED";
8
+ };
9
+ export type QuotationStatus = (typeof QuotationStatus)[keyof typeof QuotationStatus];
9
10
  export interface QuotationProposal {
10
11
  price?: number;
11
12
  expires?: Date;
@@ -38,4 +39,3 @@ export type Quotation = {
38
39
  userId: string;
39
40
  } & LogFields & TimestampFields;
40
41
  export declare const QuotationsCollection: (db: mongodb.Db) => Promise<mongodb.Collection<Quotation>>;
41
- //# sourceMappingURL=QuotationsCollection.d.ts.map
@@ -1,12 +1,11 @@
1
- import { buildDbIndexes, isDocumentDBCompatModeEnabled, } from '@unchainedshop/mongodb';
2
- export var QuotationStatus;
3
- (function (QuotationStatus) {
4
- QuotationStatus["REQUESTED"] = "REQUESTED";
5
- QuotationStatus["PROCESSING"] = "PROCESSING";
6
- QuotationStatus["PROPOSED"] = "PROPOSED";
7
- QuotationStatus["FULLFILLED"] = "FULLFILLED";
8
- QuotationStatus["REJECTED"] = "REJECTED";
9
- })(QuotationStatus || (QuotationStatus = {}));
1
+ import { mongodb, buildDbIndexes, isDocumentDBCompatModeEnabled, } from '@unchainedshop/mongodb';
2
+ export const QuotationStatus = {
3
+ REQUESTED: 'REQUESTED',
4
+ PROCESSING: 'PROCESSING',
5
+ PROPOSED: 'PROPOSED',
6
+ FULLFILLED: 'FULLFILLED',
7
+ REJECTED: 'REJECTED',
8
+ };
10
9
  export const QuotationsCollection = async (db) => {
11
10
  const Quotations = db.collection('quotations');
12
11
  if (!isDocumentDBCompatModeEnabled()) {
@@ -34,7 +33,6 @@ export const QuotationsCollection = async (db) => {
34
33
  },
35
34
  ]);
36
35
  }
37
- // Quotation Indexes
38
36
  await buildDbIndexes(Quotations, [
39
37
  { index: { userId: 1 } },
40
38
  { index: { productId: 1 } },
@@ -42,4 +40,3 @@ export const QuotationsCollection = async (db) => {
42
40
  ]);
43
41
  return Quotations;
44
42
  };
45
- //# sourceMappingURL=QuotationsCollection.js.map
@@ -1,3 +1,2 @@
1
- import { MigrationRepository } from '@unchainedshop/mongodb';
1
+ import type { MigrationRepository } from '@unchainedshop/mongodb';
2
2
  export default function renameCurrencyCode(repository: MigrationRepository): void;
3
- //# sourceMappingURL=20250502111800-currency-code.d.ts.map
@@ -1,4 +1,4 @@
1
- import { QuotationsCollection } from '../quotations-index.js';
1
+ import { QuotationsCollection } from "../quotations-index.js";
2
2
  export default function renameCurrencyCode(repository) {
3
3
  repository?.register({
4
4
  id: 20250502113100,
@@ -11,4 +11,3 @@ export default function renameCurrencyCode(repository) {
11
11
  },
12
12
  });
13
13
  }
14
- //# sourceMappingURL=20250502111800-currency-code.js.map
@@ -1,10 +1,11 @@
1
- import { SortOption } from '@unchainedshop/utils';
2
- import { Quotation, QuotationStatus } from '../db/QuotationsCollection.js';
3
- import { mongodb, ModuleInput } from '@unchainedshop/mongodb';
4
- import { QuotationsSettingsOptions } from '../quotations-settings.js';
5
- export interface QuotationQuery extends mongodb.Filter<Quotation> {
1
+ import { type SortOption } from '@unchainedshop/utils';
2
+ import { type Quotation, QuotationStatus } from '../db/QuotationsCollection.ts';
3
+ import { mongodb, type ModuleInput } from '@unchainedshop/mongodb';
4
+ import { type QuotationsSettingsOptions } from '../quotations-settings.ts';
5
+ export interface QuotationQuery {
6
6
  userId?: string;
7
7
  queryString?: string;
8
+ quotationIds?: string[];
8
9
  }
9
10
  export interface QuotationData {
10
11
  configuration?: {
@@ -15,7 +16,7 @@ export interface QuotationData {
15
16
  productId: string;
16
17
  userId: string;
17
18
  }
18
- export declare const buildFindSelector: ({ userId, queryString, ...rest }?: QuotationQuery) => mongodb.Filter<Quotation>;
19
+ export declare const buildFindSelector: ({ userId, queryString, quotationIds }?: QuotationQuery) => mongodb.Filter<Quotation>;
19
20
  export declare const configureQuotationsModule: ({ db, migrationRepository, options: quotationsOptions, }: ModuleInput<QuotationsSettingsOptions>) => Promise<{
20
21
  count: (query: QuotationQuery) => Promise<number>;
21
22
  openQuotationWithProduct: ({ productId }: {
@@ -46,4 +47,3 @@ export declare const configureQuotationsModule: ({ db, migrationRepository, opti
46
47
  }) => Promise<mongodb.WithId<Quotation> | null>;
47
48
  }>;
48
49
  export type QuotationsModule = Awaited<ReturnType<typeof configureQuotationsModule>>;
49
- //# sourceMappingURL=configureQuotationsModule.d.ts.map
@@ -1,16 +1,19 @@
1
1
  import { SortDirection } from '@unchainedshop/utils';
2
- import { QuotationStatus } from '../db/QuotationsCollection.js';
2
+ import { QuotationStatus } from "../db/QuotationsCollection.js";
3
3
  import { emit, registerEvents } from '@unchainedshop/events';
4
- import { generateDbFilterById, buildSortOptions, generateDbObjectId, assertDocumentDBCompatMode, } from '@unchainedshop/mongodb';
5
- import { QuotationsCollection } from '../db/QuotationsCollection.js';
6
- import { quotationsSettings } from '../quotations-settings.js';
7
- import renameCurrencyCode from '../migrations/20250502111800-currency-code.js';
4
+ import { generateDbFilterById, buildSortOptions, mongodb, generateDbObjectId, assertDocumentDBCompatMode, } from '@unchainedshop/mongodb';
5
+ import { QuotationsCollection } from "../db/QuotationsCollection.js";
6
+ import { quotationsSettings } from "../quotations-settings.js";
7
+ import renameCurrencyCode from "../migrations/20250502111800-currency-code.js";
8
8
  const QUOTATION_EVENTS = ['QUOTATION_REQUEST_CREATE', 'QUOTATION_REMOVE', 'QUOTATION_UPDATE'];
9
- export const buildFindSelector = ({ userId, queryString, ...rest } = {}) => {
10
- const selector = { ...rest };
9
+ export const buildFindSelector = ({ userId, queryString, quotationIds } = {}) => {
10
+ const selector = {};
11
11
  if (userId) {
12
12
  selector.userId = userId;
13
13
  }
14
+ if (quotationIds) {
15
+ selector._id = { $in: quotationIds };
16
+ }
14
17
  if (queryString) {
15
18
  assertDocumentDBCompatMode();
16
19
  selector.$text = { $search: queryString };
@@ -18,7 +21,6 @@ export const buildFindSelector = ({ userId, queryString, ...rest } = {}) => {
18
21
  return selector;
19
22
  };
20
23
  export const configureQuotationsModule = async ({ db, migrationRepository, options: quotationsOptions = {}, }) => {
21
- // Migration v3 -> v4
22
24
  renameCurrencyCode(migrationRepository);
23
25
  registerEvents(QUOTATION_EVENTS);
24
26
  quotationsSettings.configureSettings(quotationsOptions);
@@ -43,13 +45,12 @@ export const configureQuotationsModule = async ({ db, migrationRepository, optio
43
45
  updated: new Date(),
44
46
  };
45
47
  switch (status) {
46
- // explicitly use fallthrough here!
47
48
  case QuotationStatus.FULLFILLED:
48
49
  if (!quotation.fullfilled) {
49
50
  $set.fullfilled = date;
50
51
  }
51
52
  $set.expires = date;
52
- case QuotationStatus.PROCESSING: // eslint-disable-line no-fallthrough
53
+ case QuotationStatus.PROCESSING:
53
54
  if (!quotation.quotationNumber) {
54
55
  $set.quotationNumber = await findNewQuotationNumber(quotation);
55
56
  }
@@ -90,7 +91,6 @@ export const configureQuotationsModule = async ({ db, migrationRepository, optio
90
91
  return quotation;
91
92
  };
92
93
  return {
93
- // Queries
94
94
  count: async (query) => {
95
95
  const quotationCount = await Quotations.countDocuments(buildFindSelector(query));
96
96
  return quotationCount;
@@ -114,7 +114,6 @@ export const configureQuotationsModule = async ({ db, migrationRepository, optio
114
114
  });
115
115
  return quotations.toArray();
116
116
  },
117
- // Transformations
118
117
  normalizedStatus: (quotation) => {
119
118
  return quotation.status === null
120
119
  ? QuotationStatus.REQUESTED
@@ -131,7 +130,6 @@ export const configureQuotationsModule = async ({ db, migrationRepository, optio
131
130
  isProposalValid(quotation) {
132
131
  return quotation.status === QuotationStatus.PROPOSED && !this.isExpired(quotation);
133
132
  },
134
- // Mutations
135
133
  create: async ({ countryCode, currencyCode, ...quotationData }) => {
136
134
  const { insertedId: quotationId } = await Quotations.insertOne({
137
135
  _id: generateDbObjectId(),
@@ -159,4 +157,3 @@ export const configureQuotationsModule = async ({ db, migrationRepository, optio
159
157
  updateStatus,
160
158
  };
161
159
  };
162
- //# sourceMappingURL=configureQuotationsModule.js.map
@@ -1,4 +1,3 @@
1
- export * from './db/QuotationsCollection.js';
2
- export * from './module/configureQuotationsModule.js';
3
- export * from './quotations-settings.js';
4
- //# sourceMappingURL=quotations-index.d.ts.map
1
+ export * from './db/QuotationsCollection.ts';
2
+ export * from './module/configureQuotationsModule.ts';
3
+ export * from './quotations-settings.ts';
@@ -1,4 +1,3 @@
1
- export * from './db/QuotationsCollection.js';
2
- export * from './module/configureQuotationsModule.js';
3
- export * from './quotations-settings.js';
4
- //# sourceMappingURL=quotations-index.js.map
1
+ export * from "./db/QuotationsCollection.js";
2
+ export * from "./module/configureQuotationsModule.js";
3
+ export * from "./quotations-settings.js";
@@ -1,8 +1,7 @@
1
- import { Quotation } from './db/QuotationsCollection.js';
1
+ import type { Quotation } from './db/QuotationsCollection.ts';
2
2
  export interface QuotationsSettings {
3
3
  quotationNumberHashFn: (quotation: Quotation, index: number) => string;
4
4
  configureSettings: (options: QuotationsSettingsOptions) => void;
5
5
  }
6
6
  export type QuotationsSettingsOptions = Omit<Partial<QuotationsSettings>, 'configureSettings'>;
7
7
  export declare const quotationsSettings: QuotationsSettings;
8
- //# sourceMappingURL=quotations-settings.d.ts.map
@@ -5,4 +5,3 @@ export const quotationsSettings = {
5
5
  this.quotationNumberHashFn = quotationNumberHashFn || generateRandomHash;
6
6
  },
7
7
  };
8
- //# sourceMappingURL=quotations-settings.js.map
package/package.json CHANGED
@@ -1,16 +1,17 @@
1
1
  {
2
2
  "name": "@unchainedshop/core-quotations",
3
- "version": "4.3.4",
3
+ "version": "4.5.0",
4
4
  "main": "lib/quotations-index.js",
5
5
  "types": "lib/quotations-index.d.ts",
6
6
  "type": "module",
7
+ "sideEffects": false,
7
8
  "scripts": {
8
9
  "clean": "tsc -b --clean",
9
10
  "build": "tsc -b",
10
11
  "prepublishOnly": "npm run clean && npm run build",
11
12
  "watch": "tsc -w",
12
- "test": "tsx --test",
13
- "test:watch": "tsx --test --watch"
13
+ "test": "node --test",
14
+ "test:watch": "node --test --watch"
14
15
  },
15
16
  "repository": {
16
17
  "type": "git",
@@ -22,8 +23,10 @@
22
23
  "core"
23
24
  ],
24
25
  "authors": [
25
- "Joël Meiller",
26
- "Pascal Kaufmann"
26
+ "Pascal Kaufmann",
27
+ "Mikael Araya",
28
+ "Vedran Rudelj",
29
+ "Joël Meiller"
27
30
  ],
28
31
  "license": "EUPL-1.2",
29
32
  "bugs": {
@@ -31,13 +34,12 @@
31
34
  },
32
35
  "homepage": "https://github.com/unchainedshop/unchained#readme",
33
36
  "dependencies": {
34
- "@unchainedshop/events": "^4.3.0",
35
- "@unchainedshop/logger": "^4.3.0",
36
- "@unchainedshop/utils": "^4.3.0"
37
+ "@unchainedshop/events": "^4.5.0",
38
+ "@unchainedshop/logger": "^4.5.0",
39
+ "@unchainedshop/utils": "^4.5.0"
37
40
  },
38
41
  "devDependencies": {
39
- "@types/node": "^24.0.13",
40
- "tsx": "^4.20.3",
42
+ "@types/node": "^25.0.0",
41
43
  "typescript": "^5.8.3"
42
44
  }
43
45
  }
@@ -1 +0,0 @@
1
- {"version":3,"file":"QuotationsCollection.d.ts","sourceRoot":"","sources":["../../src/db/QuotationsCollection.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,OAAO,EAEP,eAAe,EACf,SAAS,EAEV,MAAM,wBAAwB,CAAC;AAEhC,oBAAY,eAAe;IACzB,SAAS,cAAc;IACvB,UAAU,eAAe;IACzB,QAAQ,aAAa;IACrB,UAAU,eAAe;IACzB,QAAQ,aAAa;CACtB;AAED,MAAM,WAAW,iBAAiB;IAChC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,IAAI,CAAC;IACf,IAAI,CAAC,EAAE,GAAG,CAAC;CACZ;AAED,MAAM,WAAW,0BAA0B;IACzC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,aAAa,EAAE;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;CACjD;AAED,MAAM,MAAM,SAAS,GAAG;IACtB,GAAG,EAAE,MAAM,CAAC;IACZ,aAAa,CAAC,EAAE;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;IACjD,OAAO,CAAC,EAAE,GAAG,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,OAAO,CAAC,EAAE,IAAI,CAAC;IACf,UAAU,CAAC,EAAE,IAAI,CAAC;IAClB,IAAI,CAAC,EAAE,GAAG,CAAC;IACX,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;IAClB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,EAAE,IAAI,CAAC;IAChB,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,MAAM,EAAE,MAAM,CAAC;CAChB,GAAG,SAAS,GACX,eAAe,CAAC;AAElB,eAAO,MAAM,oBAAoB,GAAU,IAAI,OAAO,CAAC,EAAE,2CAqCxD,CAAC"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"QuotationsCollection.js","sourceRoot":"","sources":["../../src/db/QuotationsCollection.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,cAAc,EAGd,6BAA6B,GAC9B,MAAM,wBAAwB,CAAC;AAEhC,MAAM,CAAN,IAAY,eAMX;AAND,WAAY,eAAe;IACzB,0CAAuB,CAAA;IACvB,4CAAyB,CAAA;IACzB,wCAAqB,CAAA;IACrB,4CAAyB,CAAA;IACzB,wCAAqB,CAAA;AACvB,CAAC,EANW,eAAe,KAAf,eAAe,QAM1B;AA+BD,MAAM,CAAC,MAAM,oBAAoB,GAAG,KAAK,EAAE,EAAc,EAAE,EAAE;IAC3D,MAAM,UAAU,GAAG,EAAE,CAAC,UAAU,CAAY,YAAY,CAAC,CAAC;IAE1D,IAAI,CAAC,6BAA6B,EAAE,EAAE,CAAC;QACrC,MAAM,cAAc,CAAY,UAAU,EAAE;YAC1C;gBACE,KAAK,EAAE;oBACL,GAAG,EAAE,MAAM;oBACX,MAAM,EAAE,MAAM;oBACd,eAAe,EAAE,MAAM;oBACvB,MAAM,EAAE,MAAM;oBACd,mBAAmB,EAAE,MAAM;oBAC3B,sBAAsB,EAAE,MAAM;iBACxB;gBACR,OAAO,EAAE;oBACP,OAAO,EAAE;wBACP,GAAG,EAAE,CAAC;wBACN,MAAM,EAAE,CAAC;wBACT,eAAe,EAAE,CAAC;wBAClB,mBAAmB,EAAE,CAAC;wBACtB,sBAAsB,EAAE,CAAC;wBACzB,MAAM,EAAE,CAAC;qBACV;oBACD,IAAI,EAAE,2BAA2B;iBAClC;aACF;SACF,CAAC,CAAC;IACL,CAAC;IAED,oBAAoB;IACpB,MAAM,cAAc,CAAY,UAAU,EAAE;QAC1C,EAAE,KAAK,EAAE,EAAE,MAAM,EAAE,CAAC,EAAE,EAAE;QACxB,EAAE,KAAK,EAAE,EAAE,SAAS,EAAE,CAAC,EAAE,EAAE;QAC3B,EAAE,KAAK,EAAE,EAAE,MAAM,EAAE,CAAC,EAAE,EAAE;KACzB,CAAC,CAAC;IAEH,OAAO,UAAU,CAAC;AACpB,CAAC,CAAC"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"20250502111800-currency-code.d.ts","sourceRoot":"","sources":["../../src/migrations/20250502111800-currency-code.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,MAAM,wBAAwB,CAAC;AAG7D,MAAM,CAAC,OAAO,UAAU,kBAAkB,CAAC,UAAU,EAAE,mBAAmB,QAczE"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"20250502111800-currency-code.js","sourceRoot":"","sources":["../../src/migrations/20250502111800-currency-code.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAC;AAE9D,MAAM,CAAC,OAAO,UAAU,kBAAkB,CAAC,UAA+B;IACxE,UAAU,EAAE,QAAQ,CAAC;QACnB,EAAE,EAAE,cAAc;QAClB,IAAI,EAAE,qDAAqD;QAC3D,EAAE,EAAE,KAAK,IAAI,EAAE;YACb,MAAM,UAAU,GAAG,MAAM,oBAAoB,CAAC,UAAU,CAAC,EAAE,CAAC,CAAC;YAC7D,MAAM,UAAU,CAAC,UAAU,CACzB,EAAE,EACF;gBACE,OAAO,EAAE,EAAE,QAAQ,EAAE,cAAc,EAAE;aACtC,CACF,CAAC;QACJ,CAAC;KACF,CAAC,CAAC;AACL,CAAC"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"configureQuotationsModule.d.ts","sourceRoot":"","sources":["../../src/module/configureQuotationsModule.ts"],"names":[],"mappings":"AAAA,OAAO,EAAiB,UAAU,EAAE,MAAM,sBAAsB,CAAC;AACjE,OAAO,EAAE,SAAS,EAAE,eAAe,EAAE,MAAM,+BAA+B,CAAC;AAE3E,OAAO,EAGL,OAAO,EAEP,WAAW,EAEZ,MAAM,wBAAwB,CAAC;AAEhC,OAAO,EAAsB,yBAAyB,EAAE,MAAM,2BAA2B,CAAC;AAI1F,MAAM,WAAW,cAAe,SAAQ,OAAO,CAAC,MAAM,CAAC,SAAS,CAAC;IAC/D,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AACD,MAAM,WAAW,aAAa;IAC5B,aAAa,CAAC,EAAE;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;IACjD,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;CAChB;AAID,eAAO,MAAM,iBAAiB,GAAI,mCAAkC,cAAmB,8BAYtF,CAAC;AAEF,eAAO,MAAM,yBAAyB,GAAU,0DAI7C,WAAW,CAAC,yBAAyB,CAAC;mBAyFhB,cAAc,KAAG,OAAO,CAAC,MAAM,CAAC;8CAIL;QAAE,SAAS,EAAE,MAAM,CAAA;KAAE;qCAM9B;QAAE,WAAW,EAAE,MAAM,CAAA;KAAE,YAAY,OAAO,CAAC,WAAW;wDAWxF,cAAc,GAAG;QAClB,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB,IAAI,CAAC,EAAE,UAAU,EAAE,CAAC;KACrB,YACS,OAAO,CAAC,WAAW,KAC5B,OAAO,CAAC,SAAS,EAAE,CAAC;kCAaO,SAAS,KAAG,eAAe;yBAMpC,SAAS,qBAAqB;QAAE,aAAa,EAAE,IAAI,CAAA;KAAE;+BAQ/C,SAAS,GAAG,OAAO;8DAS3C,aAAa,GAAG;QAAE,YAAY,EAAE,MAAM,CAAA;KAAE;4CAgBG,MAAM;iCA7FqB,MAAM,UAAU,GAAG;kCAAnB,MAAM,UAAU,GAAG;gCAxD/E,MAAM,oBACI;QAAE,MAAM,EAAE,eAAe,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE;EAgKpE,CAAC;AAEF,MAAM,MAAM,gBAAgB,GAAG,OAAO,CAAC,UAAU,CAAC,OAAO,yBAAyB,CAAC,CAAC,CAAC"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"configureQuotationsModule.js","sourceRoot":"","sources":["../../src/module/configureQuotationsModule.ts"],"names":[],"mappings":"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"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"quotations-index.d.ts","sourceRoot":"","sources":["../src/quotations-index.ts"],"names":[],"mappings":"AAAA,cAAc,8BAA8B,CAAC;AAE7C,cAAc,uCAAuC,CAAC;AACtD,cAAc,0BAA0B,CAAC"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"quotations-index.js","sourceRoot":"","sources":["../src/quotations-index.ts"],"names":[],"mappings":"AAAA,cAAc,8BAA8B,CAAC;AAE7C,cAAc,uCAAuC,CAAC;AACtD,cAAc,0BAA0B,CAAC"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"quotations-settings.d.ts","sourceRoot":"","sources":["../src/quotations-settings.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAE,MAAM,8BAA8B,CAAC;AAEzD,MAAM,WAAW,kBAAkB;IACjC,qBAAqB,EAAE,CAAC,SAAS,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,KAAK,MAAM,CAAC;IACvE,iBAAiB,EAAE,CAAC,OAAO,EAAE,yBAAyB,KAAK,IAAI,CAAC;CACjE;AAED,MAAM,MAAM,yBAAyB,GAAG,IAAI,CAAC,OAAO,CAAC,kBAAkB,CAAC,EAAE,mBAAmB,CAAC,CAAC;AAE/F,eAAO,MAAM,kBAAkB,EAAE,kBAKhC,CAAC"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"quotations-settings.js","sourceRoot":"","sources":["../src/quotations-settings.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAU1D,MAAM,CAAC,MAAM,kBAAkB,GAAuB;IACpD,qBAAqB,EAAE,kBAAkB;IACzC,iBAAiB,CAAC,EAAE,qBAAqB,EAAE,GAAG,EAAE;QAC9C,IAAI,CAAC,qBAAqB,GAAG,qBAAqB,IAAI,kBAAkB,CAAC;IAC3E,CAAC;CACF,CAAC"}
@@ -1,83 +0,0 @@
1
- import {
2
- mongodb,
3
- buildDbIndexes,
4
- TimestampFields,
5
- LogFields,
6
- isDocumentDBCompatModeEnabled,
7
- } from '@unchainedshop/mongodb';
8
-
9
- export enum QuotationStatus {
10
- REQUESTED = 'REQUESTED',
11
- PROCESSING = 'PROCESSING',
12
- PROPOSED = 'PROPOSED',
13
- FULLFILLED = 'FULLFILLED',
14
- REJECTED = 'REJECTED',
15
- }
16
-
17
- export interface QuotationProposal {
18
- price?: number;
19
- expires?: Date;
20
- meta?: any;
21
- }
22
-
23
- export interface QuotationItemConfiguration {
24
- quantity?: number;
25
- configuration: { key: string; value: string }[];
26
- }
27
-
28
- export type Quotation = {
29
- _id: string;
30
- configuration?: { key: string; value: string }[];
31
- context?: any;
32
- countryCode?: string;
33
- currencyCode?: string;
34
- expires?: Date;
35
- fullfilled?: Date;
36
- meta?: any;
37
- price?: number;
38
- productId: string;
39
- quotationNumber?: string;
40
- rejected?: Date;
41
- status: string | null;
42
- userId: string;
43
- } & LogFields &
44
- TimestampFields;
45
-
46
- export const QuotationsCollection = async (db: mongodb.Db) => {
47
- const Quotations = db.collection<Quotation>('quotations');
48
-
49
- if (!isDocumentDBCompatModeEnabled()) {
50
- await buildDbIndexes<Quotation>(Quotations, [
51
- {
52
- index: {
53
- _id: 'text',
54
- userId: 'text',
55
- quotationNumber: 'text',
56
- status: 'text',
57
- 'contact.telNumber': 'text',
58
- 'contact.emailAddress': 'text',
59
- } as any,
60
- options: {
61
- weights: {
62
- _id: 8,
63
- userId: 3,
64
- quotationNumber: 6,
65
- 'contact.telNumber': 5,
66
- 'contact.emailAddress': 4,
67
- status: 1,
68
- },
69
- name: 'quotation_fulltext_search',
70
- },
71
- },
72
- ]);
73
- }
74
-
75
- // Quotation Indexes
76
- await buildDbIndexes<Quotation>(Quotations, [
77
- { index: { userId: 1 } },
78
- { index: { productId: 1 } },
79
- { index: { status: 1 } },
80
- ]);
81
-
82
- return Quotations;
83
- };
@@ -1,18 +0,0 @@
1
- import { MigrationRepository } from '@unchainedshop/mongodb';
2
- import { QuotationsCollection } from '../quotations-index.js';
3
-
4
- export default function renameCurrencyCode(repository: MigrationRepository) {
5
- repository?.register({
6
- id: 20250502113100,
7
- name: 'Rename quotation.currency to quotation.currencyCode',
8
- up: async () => {
9
- const Quotations = await QuotationsCollection(repository.db);
10
- await Quotations.updateMany(
11
- {},
12
- {
13
- $rename: { currency: 'currencyCode' },
14
- },
15
- );
16
- },
17
- });
18
- }
@@ -1,230 +0,0 @@
1
- import { SortDirection, SortOption } from '@unchainedshop/utils';
2
- import { Quotation, QuotationStatus } from '../db/QuotationsCollection.js';
3
- import { emit, registerEvents } from '@unchainedshop/events';
4
- import {
5
- generateDbFilterById,
6
- buildSortOptions,
7
- mongodb,
8
- generateDbObjectId,
9
- ModuleInput,
10
- assertDocumentDBCompatMode,
11
- } from '@unchainedshop/mongodb';
12
- import { QuotationsCollection } from '../db/QuotationsCollection.js';
13
- import { quotationsSettings, QuotationsSettingsOptions } from '../quotations-settings.js';
14
-
15
- import renameCurrencyCode from '../migrations/20250502111800-currency-code.js';
16
-
17
- export interface QuotationQuery extends mongodb.Filter<Quotation> {
18
- userId?: string;
19
- queryString?: string;
20
- }
21
- export interface QuotationData {
22
- configuration?: { key: string; value: string }[];
23
- countryCode?: string;
24
- productId: string;
25
- userId: string;
26
- }
27
-
28
- const QUOTATION_EVENTS: string[] = ['QUOTATION_REQUEST_CREATE', 'QUOTATION_REMOVE', 'QUOTATION_UPDATE'];
29
-
30
- export const buildFindSelector = ({ userId, queryString, ...rest }: QuotationQuery = {}) => {
31
- const selector: mongodb.Filter<Quotation> = { ...rest };
32
-
33
- if (userId) {
34
- selector.userId = userId;
35
- }
36
- if (queryString) {
37
- assertDocumentDBCompatMode();
38
- (selector as any).$text = { $search: queryString };
39
- }
40
-
41
- return selector;
42
- };
43
-
44
- export const configureQuotationsModule = async ({
45
- db,
46
- migrationRepository,
47
- options: quotationsOptions = {},
48
- }: ModuleInput<QuotationsSettingsOptions>) => {
49
- // Migration v3 -> v4
50
- renameCurrencyCode(migrationRepository);
51
-
52
- registerEvents(QUOTATION_EVENTS);
53
-
54
- quotationsSettings.configureSettings(quotationsOptions);
55
-
56
- const Quotations = await QuotationsCollection(db);
57
-
58
- const findNewQuotationNumber = async (quotation: Quotation, index = 0) => {
59
- const newHashID = quotationsSettings.quotationNumberHashFn(quotation, index);
60
- if ((await Quotations.countDocuments({ quotationNumber: newHashID }, { limit: 1 })) === 0) {
61
- return newHashID;
62
- }
63
- return findNewQuotationNumber(quotation, index + 1);
64
- };
65
-
66
- const updateStatus = async (
67
- quotationId: string,
68
- { status, info = '' }: { status: QuotationStatus; info?: string },
69
- ) => {
70
- const selector = generateDbFilterById(quotationId);
71
- const quotation = await Quotations.findOne(selector, {});
72
-
73
- if (!quotation) return null;
74
-
75
- if (quotation.status === status) return quotation;
76
-
77
- const date = new Date();
78
- const $set: Partial<Quotation> = {
79
- status,
80
- updated: new Date(),
81
- };
82
-
83
- switch (status) {
84
- // explicitly use fallthrough here!
85
- case QuotationStatus.FULLFILLED:
86
- if (!quotation.fullfilled) {
87
- $set.fullfilled = date;
88
- }
89
- $set.expires = date;
90
- case QuotationStatus.PROCESSING: // eslint-disable-line no-fallthrough
91
- if (!quotation.quotationNumber) {
92
- $set.quotationNumber = await findNewQuotationNumber(quotation);
93
- }
94
- break;
95
- case QuotationStatus.REJECTED:
96
- $set.expires = date;
97
- $set.rejected = date;
98
- break;
99
- default:
100
- break;
101
- }
102
-
103
- const modifier: mongodb.UpdateFilter<Quotation> = {
104
- $set,
105
- $push: {
106
- log: {
107
- date,
108
- status,
109
- info,
110
- },
111
- },
112
- };
113
-
114
- const updatedQuotation = await Quotations.findOneAndUpdate(selector, modifier, {
115
- returnDocument: 'after',
116
- });
117
-
118
- await emit('QUOTATION_UPDATE', { quotation, field: 'status' });
119
-
120
- return updatedQuotation;
121
- };
122
-
123
- const updateQuotationFields = (fieldKeys: string[]) => async (quotationId: string, values: any) => {
124
- const quotation = await Quotations.findOneAndUpdate(generateDbFilterById(quotationId), {
125
- $set: {
126
- updated: new Date(),
127
- ...fieldKeys.reduce((set, key) => ({ ...set, [key]: values[key] }), {}),
128
- },
129
- });
130
- if (!quotation) return null;
131
- await emit('QUOTATION_UPDATE', { quotation, fields: fieldKeys });
132
- return quotation;
133
- };
134
-
135
- return {
136
- // Queries
137
- count: async (query: QuotationQuery): Promise<number> => {
138
- const quotationCount = await Quotations.countDocuments(buildFindSelector(query));
139
- return quotationCount;
140
- },
141
- openQuotationWithProduct: async ({ productId }: { productId: string }) => {
142
- const selector: mongodb.Filter<Quotation> = { productId };
143
- selector.status = { $in: [QuotationStatus.REQUESTED, QuotationStatus.PROPOSED] };
144
- return Quotations.findOne(selector);
145
- },
146
-
147
- findQuotation: async ({ quotationId }: { quotationId: string }, options?: mongodb.FindOptions) => {
148
- const selector = generateDbFilterById(quotationId);
149
- return Quotations.findOne(selector, options);
150
- },
151
-
152
- findQuotations: async (
153
- {
154
- limit,
155
- offset,
156
- sort,
157
- ...query
158
- }: QuotationQuery & {
159
- limit?: number;
160
- offset?: number;
161
- sort?: SortOption[];
162
- },
163
- options?: mongodb.FindOptions,
164
- ): Promise<Quotation[]> => {
165
- const defaultSortOption: SortOption[] = [{ key: 'created', value: SortDirection.ASC }];
166
- const quotations = Quotations.find(buildFindSelector(query), {
167
- limit,
168
- skip: offset,
169
- sort: buildSortOptions(sort || defaultSortOption),
170
- ...options,
171
- });
172
-
173
- return quotations.toArray();
174
- },
175
-
176
- // Transformations
177
- normalizedStatus: (quotation: Quotation): QuotationStatus => {
178
- return quotation.status === null
179
- ? QuotationStatus.REQUESTED
180
- : (quotation.status as QuotationStatus);
181
- },
182
-
183
- isExpired(quotation: Quotation, { referenceDate }: { referenceDate: Date }) {
184
- const relevantDate = referenceDate ? new Date(referenceDate) : new Date();
185
- if (!quotation.expires) return false;
186
- const expiryDate = new Date(quotation.expires);
187
- const isQuotationExpired = relevantDate.getTime() > expiryDate.getTime();
188
- return isQuotationExpired;
189
- },
190
-
191
- isProposalValid(quotation: Quotation): boolean {
192
- return quotation.status === QuotationStatus.PROPOSED && !this.isExpired(quotation);
193
- },
194
-
195
- // Mutations
196
- create: async ({
197
- countryCode,
198
- currencyCode,
199
- ...quotationData
200
- }: QuotationData & { currencyCode: string }) => {
201
- const { insertedId: quotationId } = await Quotations.insertOne({
202
- _id: generateDbObjectId(),
203
- created: new Date(),
204
- ...quotationData,
205
- configuration: quotationData.configuration || [],
206
- countryCode,
207
- currencyCode,
208
- log: [],
209
- status: QuotationStatus.REQUESTED,
210
- });
211
-
212
- const quotation = (await Quotations.findOne(generateDbFilterById(quotationId), {})) as Quotation;
213
- await emit('QUOTATION_REQUEST_CREATE', { quotation });
214
- return quotation;
215
- },
216
- deleteRequestedUserQuotations: async (userId: string) => {
217
- const { deletedCount } = await Quotations.deleteMany({
218
- userId,
219
- status: { $in: [QuotationStatus.REQUESTED, null] },
220
- });
221
- return deletedCount;
222
- },
223
- updateContext: updateQuotationFields(['context']),
224
- updateProposal: updateQuotationFields(['price', 'expires', 'meta']),
225
-
226
- updateStatus,
227
- };
228
- };
229
-
230
- export type QuotationsModule = Awaited<ReturnType<typeof configureQuotationsModule>>;
@@ -1,27 +0,0 @@
1
- import { describe, it } from 'node:test';
2
- import assert from 'node:assert';
3
- import { buildFindSelector } from './configureQuotationsModule.js';
4
-
5
- describe('Quotation', () => {
6
- describe('buildFindSelector', () => {
7
- it('Return correct filter object when passed no argument', () => {
8
- assert.deepStrictEqual(buildFindSelector({}), {});
9
- });
10
-
11
- it('Return correct filter object when passed queryString and userId', () => {
12
- assert.deepStrictEqual(buildFindSelector({ queryString: 'hello world', userId: 'admin-id' }), {
13
- userId: 'admin-id',
14
- $text: { $search: 'hello world' },
15
- });
16
- });
17
-
18
- it('Return correct filter object when passed userId', () => {
19
- assert.deepStrictEqual(buildFindSelector({ userId: 'admin-id' }), { userId: 'admin-id' });
20
- });
21
- it('Return correct filter object when passed queryString', () => {
22
- assert.deepStrictEqual(buildFindSelector({ queryString: 'hello world' }), {
23
- $text: { $search: 'hello world' },
24
- });
25
- });
26
- });
27
- });
@@ -1,4 +0,0 @@
1
- export * from './db/QuotationsCollection.js';
2
-
3
- export * from './module/configureQuotationsModule.js';
4
- export * from './quotations-settings.js';
@@ -1,16 +0,0 @@
1
- import { generateRandomHash } from '@unchainedshop/utils';
2
- import { Quotation } from './db/QuotationsCollection.js';
3
-
4
- export interface QuotationsSettings {
5
- quotationNumberHashFn: (quotation: Quotation, index: number) => string;
6
- configureSettings: (options: QuotationsSettingsOptions) => void;
7
- }
8
-
9
- export type QuotationsSettingsOptions = Omit<Partial<QuotationsSettings>, 'configureSettings'>;
10
-
11
- export const quotationsSettings: QuotationsSettings = {
12
- quotationNumberHashFn: generateRandomHash,
13
- configureSettings({ quotationNumberHashFn } = {}) {
14
- this.quotationNumberHashFn = quotationNumberHashFn || generateRandomHash;
15
- },
16
- };
package/tsconfig.json DELETED
@@ -1,10 +0,0 @@
1
- {
2
- "extends": "../shared/base.tsconfig.json",
3
- "compilerOptions": {
4
- "declarationDir": "./lib",
5
- "rootDir": "./src",
6
- "outDir": "./lib",
7
-
8
- },
9
- "exclude": ["**/*.test.ts", "**/*.test.js", "tests", "lib"]
10
- }