@endora-commerce/mod-quote-requests 0.100.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/LICENSE +21 -0
- package/README.md +59 -0
- package/dist/admin/index.d.ts +26 -0
- package/dist/admin/index.d.ts.map +1 -0
- package/dist/admin/index.js +56 -0
- package/dist/admin/index.js.map +1 -0
- package/dist/admin/pages/RfqCreatePage.d.ts +9 -0
- package/dist/admin/pages/RfqCreatePage.d.ts.map +1 -0
- package/dist/admin/pages/RfqCreatePage.js +163 -0
- package/dist/admin/pages/RfqCreatePage.js.map +1 -0
- package/dist/admin/pages/RfqDetail.d.ts +9 -0
- package/dist/admin/pages/RfqDetail.d.ts.map +1 -0
- package/dist/admin/pages/RfqDetail.js +399 -0
- package/dist/admin/pages/RfqDetail.js.map +1 -0
- package/dist/admin/pages/RfqList.d.ts +9 -0
- package/dist/admin/pages/RfqList.d.ts.map +1 -0
- package/dist/admin/pages/RfqList.js +214 -0
- package/dist/admin/pages/RfqList.js.map +1 -0
- package/dist/admin/validity.d.ts +52 -0
- package/dist/admin/validity.d.ts.map +1 -0
- package/dist/admin/validity.js +61 -0
- package/dist/admin/validity.js.map +1 -0
- package/dist/backend/entities/quote-request-event.entity.d.ts +24 -0
- package/dist/backend/entities/quote-request-event.entity.d.ts.map +1 -0
- package/dist/backend/entities/quote-request-event.entity.js +67 -0
- package/dist/backend/entities/quote-request-event.entity.js.map +1 -0
- package/dist/backend/entities/quote-request-item.entity.d.ts +34 -0
- package/dist/backend/entities/quote-request-item.entity.d.ts.map +1 -0
- package/dist/backend/entities/quote-request-item.entity.js +119 -0
- package/dist/backend/entities/quote-request-item.entity.js.map +1 -0
- package/dist/backend/entities/quote-request-notification-event.entity.d.ts +23 -0
- package/dist/backend/entities/quote-request-notification-event.entity.d.ts.map +1 -0
- package/dist/backend/entities/quote-request-notification-event.entity.js +72 -0
- package/dist/backend/entities/quote-request-notification-event.entity.js.map +1 -0
- package/dist/backend/entities/quote-request-revision.entity.d.ts +35 -0
- package/dist/backend/entities/quote-request-revision.entity.d.ts.map +1 -0
- package/dist/backend/entities/quote-request-revision.entity.js +67 -0
- package/dist/backend/entities/quote-request-revision.entity.js.map +1 -0
- package/dist/backend/entities/quote-request.entity.d.ts +90 -0
- package/dist/backend/entities/quote-request.entity.d.ts.map +1 -0
- package/dist/backend/entities/quote-request.entity.js +191 -0
- package/dist/backend/entities/quote-request.entity.js.map +1 -0
- package/dist/backend/index.d.ts +120 -0
- package/dist/backend/index.d.ts.map +1 -0
- package/dist/backend/index.js +361 -0
- package/dist/backend/index.js.map +1 -0
- package/dist/backend/plugin.d.ts +95 -0
- package/dist/backend/plugin.d.ts.map +1 -0
- package/dist/backend/plugin.js +152 -0
- package/dist/backend/plugin.js.map +1 -0
- package/dist/backend/routes.admin.d.ts +13 -0
- package/dist/backend/routes.admin.d.ts.map +1 -0
- package/dist/backend/routes.admin.js +82 -0
- package/dist/backend/routes.admin.js.map +1 -0
- package/dist/backend/routes.customer.d.ts +18 -0
- package/dist/backend/routes.customer.d.ts.map +1 -0
- package/dist/backend/routes.customer.js +98 -0
- package/dist/backend/routes.customer.js.map +1 -0
- package/dist/backend/routes.sales-reps.d.ts +12 -0
- package/dist/backend/routes.sales-reps.d.ts.map +1 -0
- package/dist/backend/routes.sales-reps.js +57 -0
- package/dist/backend/routes.sales-reps.js.map +1 -0
- package/dist/backend/services/order-completion-reactor.d.ts +32 -0
- package/dist/backend/services/order-completion-reactor.d.ts.map +1 -0
- package/dist/backend/services/order-completion-reactor.js +57 -0
- package/dist/backend/services/order-completion-reactor.js.map +1 -0
- package/dist/backend/services/quote-request-business-id-generator.d.ts +46 -0
- package/dist/backend/services/quote-request-business-id-generator.d.ts.map +1 -0
- package/dist/backend/services/quote-request-business-id-generator.js +69 -0
- package/dist/backend/services/quote-request-business-id-generator.js.map +1 -0
- package/dist/backend/services/quote-request-read-port.d.ts +36 -0
- package/dist/backend/services/quote-request-read-port.d.ts.map +1 -0
- package/dist/backend/services/quote-request-read-port.js +96 -0
- package/dist/backend/services/quote-request-read-port.js.map +1 -0
- package/dist/backend/services/raised-on-channel.d.ts +23 -0
- package/dist/backend/services/raised-on-channel.d.ts.map +1 -0
- package/dist/backend/services/raised-on-channel.js +26 -0
- package/dist/backend/services/raised-on-channel.js.map +1 -0
- package/dist/backend/services/rfq-admin-service.d.ts +75 -0
- package/dist/backend/services/rfq-admin-service.d.ts.map +1 -0
- package/dist/backend/services/rfq-admin-service.js +487 -0
- package/dist/backend/services/rfq-admin-service.js.map +1 -0
- package/dist/backend/services/rfq-event-service.d.ts +32 -0
- package/dist/backend/services/rfq-event-service.d.ts.map +1 -0
- package/dist/backend/services/rfq-event-service.js +28 -0
- package/dist/backend/services/rfq-event-service.js.map +1 -0
- package/dist/backend/services/rfq-expiry-worker.d.ts +50 -0
- package/dist/backend/services/rfq-expiry-worker.d.ts.map +1 -0
- package/dist/backend/services/rfq-expiry-worker.js +70 -0
- package/dist/backend/services/rfq-expiry-worker.js.map +1 -0
- package/dist/backend/services/rfq-notification-service.d.ts +36 -0
- package/dist/backend/services/rfq-notification-service.d.ts.map +1 -0
- package/dist/backend/services/rfq-notification-service.js +52 -0
- package/dist/backend/services/rfq-notification-service.js.map +1 -0
- package/dist/backend/services/rfq-revision-service.d.ts +70 -0
- package/dist/backend/services/rfq-revision-service.d.ts.map +1 -0
- package/dist/backend/services/rfq-revision-service.js +120 -0
- package/dist/backend/services/rfq-revision-service.js.map +1 -0
- package/dist/backend/services/rfq-service.d.ts +140 -0
- package/dist/backend/services/rfq-service.d.ts.map +1 -0
- package/dist/backend/services/rfq-service.js +786 -0
- package/dist/backend/services/rfq-service.js.map +1 -0
- package/dist/backend/services/sales-channel-attributions.d.ts +38 -0
- package/dist/backend/services/sales-channel-attributions.d.ts.map +1 -0
- package/dist/backend/services/sales-channel-attributions.js +48 -0
- package/dist/backend/services/sales-channel-attributions.js.map +1 -0
- package/dist/manifest.d.ts +203 -0
- package/dist/manifest.d.ts.map +1 -0
- package/dist/manifest.js +277 -0
- package/dist/manifest.js.map +1 -0
- package/dist/migrations/20260424T190112_quote_requests_init.d.ts +19 -0
- package/dist/migrations/20260424T190112_quote_requests_init.d.ts.map +1 -0
- package/dist/migrations/20260424T190112_quote_requests_init.js +65 -0
- package/dist/migrations/20260424T190112_quote_requests_init.js.map +1 -0
- package/dist/migrations/20260503T141344_quote_requests_workflow.d.ts +37 -0
- package/dist/migrations/20260503T141344_quote_requests_workflow.d.ts.map +1 -0
- package/dist/migrations/20260503T141344_quote_requests_workflow.js +251 -0
- package/dist/migrations/20260503T141344_quote_requests_workflow.js.map +1 -0
- package/dist/migrations/20260611T140415_quote_requests_qr_item_packaging.d.ts +10 -0
- package/dist/migrations/20260611T140415_quote_requests_qr_item_packaging.d.ts.map +1 -0
- package/dist/migrations/20260611T140415_quote_requests_qr_item_packaging.js +16 -0
- package/dist/migrations/20260611T140415_quote_requests_qr_item_packaging.js.map +1 -0
- package/dist/migrations/20260611T140417_quote_requests_business_id.d.ts +24 -0
- package/dist/migrations/20260611T140417_quote_requests_business_id.d.ts.map +1 -0
- package/dist/migrations/20260611T140417_quote_requests_business_id.js +34 -0
- package/dist/migrations/20260611T140417_quote_requests_business_id.js.map +1 -0
- package/dist/migrations/20260617T095510_quote_requests_backfill_admin_created_awaiting.d.ts +21 -0
- package/dist/migrations/20260617T095510_quote_requests_backfill_admin_created_awaiting.d.ts.map +1 -0
- package/dist/migrations/20260617T095510_quote_requests_backfill_admin_created_awaiting.js +29 -0
- package/dist/migrations/20260617T095510_quote_requests_backfill_admin_created_awaiting.js.map +1 -0
- package/dist/migrations/20260718T200342_quote_requests_quote_request_custom_field_values.d.ts +12 -0
- package/dist/migrations/20260718T200342_quote_requests_quote_request_custom_field_values.d.ts.map +1 -0
- package/dist/migrations/20260718T200342_quote_requests_quote_request_custom_field_values.js +16 -0
- package/dist/migrations/20260718T200342_quote_requests_quote_request_custom_field_values.js.map +1 -0
- package/dist/migrations/20260912T125614_quote_requests_quote_request_channel_attribution.d.ts +34 -0
- package/dist/migrations/20260912T125614_quote_requests_quote_request_channel_attribution.d.ts.map +1 -0
- package/dist/migrations/20260912T125614_quote_requests_quote_request_channel_attribution.js +57 -0
- package/dist/migrations/20260912T125614_quote_requests_quote_request_channel_attribution.js.map +1 -0
- package/dist/migrations/index.d.ts +53 -0
- package/dist/migrations/index.d.ts.map +1 -0
- package/dist/migrations/index.js +61 -0
- package/dist/migrations/index.js.map +1 -0
- package/dist/migrations/status-mapping.d.ts +18 -0
- package/dist/migrations/status-mapping.d.ts.map +1 -0
- package/dist/migrations/status-mapping.js +28 -0
- package/dist/migrations/status-mapping.js.map +1 -0
- package/docs/quote_requests.md +168 -0
- package/i18n/en.json +14 -0
- package/i18n/pl.json +14 -0
- package/package.json +99 -0
- package/tailwind.css +14 -0
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import { OPEN_QUOTE_REQUEST_STATUSES } from '@endora-commerce/contracts';
|
|
2
|
+
import { QuoteRequest } from '../entities/quote-request.entity.js';
|
|
3
|
+
import { QuoteRequestItem } from '../entities/quote-request-item.entity.js';
|
|
4
|
+
/**
|
|
5
|
+
* The row-level read model `quote_requests` publishes (feature 075, Phase P).
|
|
6
|
+
*
|
|
7
|
+
* Two consumers, two questions. `carts` resolves the quote a cart was
|
|
8
|
+
* converted from; `organizations` counts the open quotes per organisation on
|
|
9
|
+
* the sales-rep screen, where the three open statuses had been written out as
|
|
10
|
+
* a literal array in a module that does not own the lifecycle.
|
|
11
|
+
*
|
|
12
|
+
* The full customer-facing projection stays `RfqService` — this is the row,
|
|
13
|
+
* for the callers that only need to count or cross-reference one.
|
|
14
|
+
*/
|
|
15
|
+
export class QuoteRequestReadService {
|
|
16
|
+
emFactory;
|
|
17
|
+
constructor(emFactory) {
|
|
18
|
+
this.emFactory = emFactory;
|
|
19
|
+
}
|
|
20
|
+
async findById(id) {
|
|
21
|
+
const quote = await this.emFactory().findOne(QuoteRequest, { id });
|
|
22
|
+
return quote ? toQuoteRequestRecord(quote) : null;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* The business id is unique by construction (`QR-<uuid>` unless a caller
|
|
26
|
+
* passes one) and the column carries a unique index, so `findOne` is the
|
|
27
|
+
* whole of the lookup.
|
|
28
|
+
*/
|
|
29
|
+
async findByBusinessId(businessId) {
|
|
30
|
+
const quote = await this.emFactory().findOne(QuoteRequest, { businessId });
|
|
31
|
+
return quote ? toQuoteRequestRecord(quote) : null;
|
|
32
|
+
}
|
|
33
|
+
async listOpenForOrganizations(organizationIds) {
|
|
34
|
+
// A rep assigned nothing sees nothing. Answering the unfiltered set here
|
|
35
|
+
// would be the opposite of what the caller means, and the caller is a
|
|
36
|
+
// visibility screen.
|
|
37
|
+
if (organizationIds.length === 0)
|
|
38
|
+
return [];
|
|
39
|
+
const quotes = await this.emFactory().find(QuoteRequest, {
|
|
40
|
+
organizationId: { $in: [...organizationIds] },
|
|
41
|
+
status: { $in: [...OPEN_QUOTE_REQUEST_STATUSES] },
|
|
42
|
+
});
|
|
43
|
+
return quotes.map(toQuoteRequestRecord);
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Added in feature 075's `carts` cut. The quote-to-cart conversion read
|
|
47
|
+
* `QuoteRequestItem` itself; the money columns are deliberately not on the
|
|
48
|
+
* record, because that conversion re-resolves every price against the
|
|
49
|
+
* buyer's current list (FR-017) and a caller that cannot see the quoted
|
|
50
|
+
* price cannot carry it over by accident.
|
|
51
|
+
*/
|
|
52
|
+
async listItems(quoteRequestId) {
|
|
53
|
+
const items = await this.emFactory().find(QuoteRequestItem, { quoteRequestId }, { orderBy: { createdAt: 'asc' } });
|
|
54
|
+
return items.map((item) => ({
|
|
55
|
+
id: item.id,
|
|
56
|
+
quoteRequestId: item.quoteRequestId,
|
|
57
|
+
productId: item.productId,
|
|
58
|
+
productName: item.productName,
|
|
59
|
+
variantId: item.variantId ?? null,
|
|
60
|
+
quantity: item.quantity,
|
|
61
|
+
packagingUnitName: item.packagingUnitName ?? null,
|
|
62
|
+
packagingUnitBaseQuantity: item.packagingUnitBaseQuantity ?? null,
|
|
63
|
+
lineCurrency: item.lineCurrency,
|
|
64
|
+
agreedUnitPrice: item.agreedUnitPrice ?? null,
|
|
65
|
+
desiredUnitPrice: item.desiredUnitPrice ?? null,
|
|
66
|
+
}));
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
export function toQuoteRequestRecord(quote) {
|
|
70
|
+
return {
|
|
71
|
+
id: quote.id,
|
|
72
|
+
businessId: quote.businessId,
|
|
73
|
+
organizationId: quote.organizationId,
|
|
74
|
+
customerAccountId: quote.customerAccountId,
|
|
75
|
+
createdByAdminUserId: quote.createdByAdminUserId ?? null,
|
|
76
|
+
assignedAdminUserId: quote.assignedAdminUserId ?? null,
|
|
77
|
+
status: quote.status,
|
|
78
|
+
headerNote: quote.headerNote ?? null,
|
|
79
|
+
cancellationReason: quote.cancellationReason ?? null,
|
|
80
|
+
awaitingCustomerRevisionAcceptance: quote.awaitingCustomerRevisionAcceptance,
|
|
81
|
+
lastCustomerSeenRevisionNumber: quote.lastCustomerSeenRevisionNumber,
|
|
82
|
+
currentRevisionNumber: quote.currentRevisionNumber,
|
|
83
|
+
submittedAt: quote.submittedAt ?? null,
|
|
84
|
+
approvedAt: quote.approvedAt ?? null,
|
|
85
|
+
canceledAt: quote.canceledAt ?? null,
|
|
86
|
+
completedAt: quote.completedAt ?? null,
|
|
87
|
+
expiredAt: quote.expiredAt ?? null,
|
|
88
|
+
expiresAt: quote.expiresAt ?? null,
|
|
89
|
+
convertedOrderId: quote.convertedOrderId ?? null,
|
|
90
|
+
customFieldValues: quote.customFieldValues ?? {},
|
|
91
|
+
version: quote.version,
|
|
92
|
+
createdAt: quote.createdAt,
|
|
93
|
+
updatedAt: quote.updatedAt,
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
//# sourceMappingURL=quote-request-read-port.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"quote-request-read-port.js","sourceRoot":"","sources":["../../../src/backend/services/quote-request-read-port.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,2BAA2B,EAAE,MAAM,4BAA4B,CAAC;AACzE,OAAO,EAAE,YAAY,EAAE,MAAM,qCAAqC,CAAC;AACnE,OAAO,EAAE,gBAAgB,EAAE,MAAM,0CAA0C,CAAC;AAE5E;;;;;;;;;;GAUG;AACH,MAAM,OAAO,uBAAuB;IACL;IAA7B,YAA6B,SAA8B;QAA9B,cAAS,GAAT,SAAS,CAAqB;IAAG,CAAC;IAE/D,KAAK,CAAC,QAAQ,CAAC,EAAU;QACvB,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,SAAS,EAAE,CAAC,OAAO,CAAC,YAAY,EAAE,EAAE,EAAE,EAAE,CAAC,CAAC;QACnE,OAAO,KAAK,CAAC,CAAC,CAAC,oBAAoB,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;IACpD,CAAC;IAED;;;;OAIG;IACH,KAAK,CAAC,gBAAgB,CAAC,UAAkB;QACvC,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,SAAS,EAAE,CAAC,OAAO,CAAC,YAAY,EAAE,EAAE,UAAU,EAAE,CAAC,CAAC;QAC3E,OAAO,KAAK,CAAC,CAAC,CAAC,oBAAoB,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;IACpD,CAAC;IAED,KAAK,CAAC,wBAAwB,CAC5B,eAAkC;QAElC,yEAAyE;QACzE,sEAAsE;QACtE,qBAAqB;QACrB,IAAI,eAAe,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO,EAAE,CAAC;QAC5C,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,SAAS,EAAE,CAAC,IAAI,CAAC,YAAY,EAAE;YACvD,cAAc,EAAE,EAAE,GAAG,EAAE,CAAC,GAAG,eAAe,CAAC,EAAE;YAC7C,MAAM,EAAE,EAAE,GAAG,EAAE,CAAC,GAAG,2BAA2B,CAAC,EAAE;SAClD,CAAC,CAAC;QACH,OAAO,MAAM,CAAC,GAAG,CAAC,oBAAoB,CAAC,CAAC;IAC1C,CAAC;IAED;;;;;;OAMG;IACH,KAAK,CAAC,SAAS,CAAC,cAAsB;QACpC,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,SAAS,EAAE,CAAC,IAAI,CACvC,gBAAgB,EAChB,EAAE,cAAc,EAAE,EAClB,EAAE,OAAO,EAAE,EAAE,SAAS,EAAE,KAAK,EAAE,EAAE,CAClC,CAAC;QACF,OAAO,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;YAC1B,EAAE,EAAE,IAAI,CAAC,EAAE;YACX,cAAc,EAAE,IAAI,CAAC,cAAc;YACnC,SAAS,EAAE,IAAI,CAAC,SAAS;YACzB,WAAW,EAAE,IAAI,CAAC,WAAW;YAC7B,SAAS,EAAE,IAAI,CAAC,SAAS,IAAI,IAAI;YACjC,QAAQ,EAAE,IAAI,CAAC,QAAQ;YACvB,iBAAiB,EAAE,IAAI,CAAC,iBAAiB,IAAI,IAAI;YACjD,yBAAyB,EAAE,IAAI,CAAC,yBAAyB,IAAI,IAAI;YACjE,YAAY,EAAE,IAAI,CAAC,YAAY;YAC/B,eAAe,EAAE,IAAI,CAAC,eAAe,IAAI,IAAI;YAC7C,gBAAgB,EAAE,IAAI,CAAC,gBAAgB,IAAI,IAAI;SAChD,CAAC,CAAC,CAAC;IACN,CAAC;CACF;AAED,MAAM,UAAU,oBAAoB,CAAC,KAAmB;IACtD,OAAO;QACL,EAAE,EAAE,KAAK,CAAC,EAAE;QACZ,UAAU,EAAE,KAAK,CAAC,UAAU;QAC5B,cAAc,EAAE,KAAK,CAAC,cAAc;QACpC,iBAAiB,EAAE,KAAK,CAAC,iBAAiB;QAC1C,oBAAoB,EAAE,KAAK,CAAC,oBAAoB,IAAI,IAAI;QACxD,mBAAmB,EAAE,KAAK,CAAC,mBAAmB,IAAI,IAAI;QACtD,MAAM,EAAE,KAAK,CAAC,MAAM;QACpB,UAAU,EAAE,KAAK,CAAC,UAAU,IAAI,IAAI;QACpC,kBAAkB,EAAE,KAAK,CAAC,kBAAkB,IAAI,IAAI;QACpD,kCAAkC,EAAE,KAAK,CAAC,kCAAkC;QAC5E,8BAA8B,EAAE,KAAK,CAAC,8BAA8B;QACpE,qBAAqB,EAAE,KAAK,CAAC,qBAAqB;QAClD,WAAW,EAAE,KAAK,CAAC,WAAW,IAAI,IAAI;QACtC,UAAU,EAAE,KAAK,CAAC,UAAU,IAAI,IAAI;QACpC,UAAU,EAAE,KAAK,CAAC,UAAU,IAAI,IAAI;QACpC,WAAW,EAAE,KAAK,CAAC,WAAW,IAAI,IAAI;QACtC,SAAS,EAAE,KAAK,CAAC,SAAS,IAAI,IAAI;QAClC,SAAS,EAAE,KAAK,CAAC,SAAS,IAAI,IAAI;QAClC,gBAAgB,EAAE,KAAK,CAAC,gBAAgB,IAAI,IAAI;QAChD,iBAAiB,EAAE,KAAK,CAAC,iBAAiB,IAAI,EAAE;QAChD,OAAO,EAAE,KAAK,CAAC,OAAO;QACtB,SAAS,EAAE,KAAK,CAAC,SAAS;QAC1B,SAAS,EAAE,KAAK,CAAC,SAAS;KAC3B,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The sales channel a quote request is being raised on (issue #266).
|
|
3
|
+
*
|
|
4
|
+
* **Read, never resolved.** The kernel's resolver middleware runs once as an
|
|
5
|
+
* `onRequest` hook on every `/api/v1/*` path and puts the answer on the request
|
|
6
|
+
* scope; this reads that slot. There is no header re-parse, no `sales_channels`
|
|
7
|
+
* query and no second call to the resolver here — MR !775 removed four such
|
|
8
|
+
* re-resolutions and this is not the fifth (feature 053 / FR-011, Principle
|
|
9
|
+
* XII).
|
|
10
|
+
*
|
|
11
|
+
* **`null` is a real answer and the only shape "no channel" is allowed to
|
|
12
|
+
* take.** On a storefront request it cannot happen: step 4 of the resolver
|
|
13
|
+
* falls back to the system-default channel, which always exists. It happens
|
|
14
|
+
* where there is no request scope at all — a CLI entry point, a BullMQ worker,
|
|
15
|
+
* a test or fixture calling the service directly — and there `null` is the
|
|
16
|
+
* truth. It is not filled in with the system default, because that would make
|
|
17
|
+
* a request nobody raised on a channel indistinguishable from one that was,
|
|
18
|
+
* and the FR-006 delete guard would then refuse a channel on evidence the
|
|
19
|
+
* platform made up. An empty string, the nil uuid and `randomUUID()` are the
|
|
20
|
+
* other three spellings of this, and all three are defects (D-47…D-51).
|
|
21
|
+
*/
|
|
22
|
+
export declare function raisedOnChannelId(): string | null;
|
|
23
|
+
//# sourceMappingURL=raised-on-channel.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"raised-on-channel.d.ts","sourceRoot":"","sources":["../../../src/backend/services/raised-on-channel.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,iBAAiB,IAAI,MAAM,GAAG,IAAI,CAEjD"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { currentSalesChannel } from '@endora-commerce/platform/kernel';
|
|
2
|
+
/**
|
|
3
|
+
* The sales channel a quote request is being raised on (issue #266).
|
|
4
|
+
*
|
|
5
|
+
* **Read, never resolved.** The kernel's resolver middleware runs once as an
|
|
6
|
+
* `onRequest` hook on every `/api/v1/*` path and puts the answer on the request
|
|
7
|
+
* scope; this reads that slot. There is no header re-parse, no `sales_channels`
|
|
8
|
+
* query and no second call to the resolver here — MR !775 removed four such
|
|
9
|
+
* re-resolutions and this is not the fifth (feature 053 / FR-011, Principle
|
|
10
|
+
* XII).
|
|
11
|
+
*
|
|
12
|
+
* **`null` is a real answer and the only shape "no channel" is allowed to
|
|
13
|
+
* take.** On a storefront request it cannot happen: step 4 of the resolver
|
|
14
|
+
* falls back to the system-default channel, which always exists. It happens
|
|
15
|
+
* where there is no request scope at all — a CLI entry point, a BullMQ worker,
|
|
16
|
+
* a test or fixture calling the service directly — and there `null` is the
|
|
17
|
+
* truth. It is not filled in with the system default, because that would make
|
|
18
|
+
* a request nobody raised on a channel indistinguishable from one that was,
|
|
19
|
+
* and the FR-006 delete guard would then refuse a channel on evidence the
|
|
20
|
+
* platform made up. An empty string, the nil uuid and `randomUUID()` are the
|
|
21
|
+
* other three spellings of this, and all three are defects (D-47…D-51).
|
|
22
|
+
*/
|
|
23
|
+
export function raisedOnChannelId() {
|
|
24
|
+
return currentSalesChannel()?.id ?? null;
|
|
25
|
+
}
|
|
26
|
+
//# sourceMappingURL=raised-on-channel.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"raised-on-channel.js","sourceRoot":"","sources":["../../../src/backend/services/raised-on-channel.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,MAAM,kCAAkC,CAAC;AAEvE;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,MAAM,UAAU,iBAAiB;IAC/B,OAAO,mBAAmB,EAAE,EAAE,EAAE,IAAI,IAAI,CAAC;AAC3C,CAAC"}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import type { EntityManager } from '@mikro-orm/postgresql';
|
|
2
|
+
import { type AdminCreateQuoteRequest, type AdminPatchQuoteRequest, type QuoteRequest as RfqDto, type QuoteRequestSummary, type AdminUserReadPort, type CatalogProductReadPort, type CustomerAccountReadPort, type CustomFieldValuePort, type OrganizationDetailsPort, type SalesRepAssignmentPort } from '@endora-commerce/contracts';
|
|
3
|
+
import type { AuditPort } from '@endora-commerce/platform/kernel';
|
|
4
|
+
import { type QuoteRequestStatus } from '../entities/quote-request.entity.js';
|
|
5
|
+
import type { RfqService } from './rfq-service.js';
|
|
6
|
+
import { type RfqEventBus } from './rfq-service.js';
|
|
7
|
+
import type { RfqEventService } from './rfq-event-service.js';
|
|
8
|
+
import type { RfqRevisionService } from './rfq-revision-service.js';
|
|
9
|
+
import type { RfqNotificationService } from './rfq-notification-service.js';
|
|
10
|
+
/**
|
|
11
|
+
* Admin-facing Quote Requests service — feature 008 workflow.
|
|
12
|
+
*
|
|
13
|
+
* Endpoints implemented:
|
|
14
|
+
* - listAll(scope) (US2)
|
|
15
|
+
* - getById (US2)
|
|
16
|
+
* - approve (US2)
|
|
17
|
+
* - cancel (US2)
|
|
18
|
+
* - assign (US2)
|
|
19
|
+
* - modify (US3)
|
|
20
|
+
* - createOnBehalf (US4)
|
|
21
|
+
*
|
|
22
|
+
* Visibility scoping is centralised in `SalesRepAssignmentService.canSeeOrganization`
|
|
23
|
+
* (research §R2). Platform admins skip the predicate.
|
|
24
|
+
*/
|
|
25
|
+
export interface AdminContext {
|
|
26
|
+
adminUserId: string;
|
|
27
|
+
isPlatformAdmin: boolean;
|
|
28
|
+
/** Display label embedded in event records ('Sales representative', 'Platform administrator', …) */
|
|
29
|
+
roleLabel: string;
|
|
30
|
+
}
|
|
31
|
+
export type AdminAssignmentScope = 'mine' | 'unassigned' | 'all';
|
|
32
|
+
export interface AdminListFilter {
|
|
33
|
+
scope?: AdminAssignmentScope;
|
|
34
|
+
status?: QuoteRequestStatus | QuoteRequestStatus[];
|
|
35
|
+
organizationId?: string;
|
|
36
|
+
}
|
|
37
|
+
export interface RfqAdminServiceDeps {
|
|
38
|
+
emFactory: () => EntityManager;
|
|
39
|
+
events: RfqEventBus;
|
|
40
|
+
rfqService: RfqService;
|
|
41
|
+
eventService: RfqEventService;
|
|
42
|
+
revisionService: RfqRevisionService;
|
|
43
|
+
notificationService: RfqNotificationService;
|
|
44
|
+
salesRepAssignment: SalesRepAssignmentPort;
|
|
45
|
+
/** Feature 054 — audits RFQ admin writes co-transactionally when provided. */
|
|
46
|
+
auditLog?: AuditPort;
|
|
47
|
+
/** Feature 055 — validates + merges custom-field values on RFQ edit. */
|
|
48
|
+
customFieldValues?: CustomFieldValuePort;
|
|
49
|
+
/**
|
|
50
|
+
* Feature 075, Phase C — the three rows the admin list and detail read and
|
|
51
|
+
* none of which this module owns. They were `em.find` calls against
|
|
52
|
+
* `catalog`'s, `customer_accounts`' and `organizations`' tables; over their
|
|
53
|
+
* published ports the same reads fail closed with their owners.
|
|
54
|
+
*/
|
|
55
|
+
catalogProducts: CatalogProductReadPort;
|
|
56
|
+
customerAccounts: CustomerAccountReadPort;
|
|
57
|
+
organizations: OrganizationDetailsPort;
|
|
58
|
+
adminUsers: AdminUserReadPort;
|
|
59
|
+
}
|
|
60
|
+
export declare class RfqAdminService {
|
|
61
|
+
#private;
|
|
62
|
+
private readonly deps;
|
|
63
|
+
constructor(deps: RfqAdminServiceDeps);
|
|
64
|
+
listAll(ctx: AdminContext, filter?: AdminListFilter): Promise<QuoteRequestSummary[]>;
|
|
65
|
+
getById(ctx: AdminContext, rfqId: string): Promise<RfqDto>;
|
|
66
|
+
approve(ctx: AdminContext, rfqId: string, expectedVersion: number | null, note: string | undefined): Promise<RfqDto>;
|
|
67
|
+
cancel(ctx: AdminContext, rfqId: string, expectedVersion: number | null, reason: string | undefined): Promise<RfqDto>;
|
|
68
|
+
assign(ctx: AdminContext, rfqId: string, targetAdminUserId: string): Promise<RfqDto>;
|
|
69
|
+
modify(ctx: AdminContext, rfqId: string, expectedVersion: number | null, body: AdminPatchQuoteRequest): Promise<RfqDto>;
|
|
70
|
+
createOnBehalf(ctx: AdminContext, body: AdminCreateQuoteRequest): Promise<RfqDto>;
|
|
71
|
+
private findVisibleForAdmin;
|
|
72
|
+
private assertVersion;
|
|
73
|
+
private isUnassigned;
|
|
74
|
+
}
|
|
75
|
+
//# sourceMappingURL=rfq-admin-service.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rfq-admin-service.d.ts","sourceRoot":"","sources":["../../../src/backend/services/rfq-admin-service.ts"],"names":[],"mappings":"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"}
|