@floristcloud/api-lib 1.2.155 → 1.2.157
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/build/commands/order/create-order.command.js +4 -0
- package/build/commands/order/get-order-list.query.js +2 -2
- package/build/commands/order/group/pin-group-order-planned-shipment-date.command.js +21 -0
- package/build/commands/order/index.js +1 -0
- package/build/commands/order/update-order.command.js +4 -0
- package/build/commands/order/webshop/update-cart.command.js +5 -0
- package/build/constant/error-i18n-key.js +1 -0
- package/build/constant/error.js +16 -0
- package/build/constant/index.js +1 -0
- package/build/constant/order-external-number.constant.js +6 -0
- package/build/enum/order-updated-field.enum.js +2 -0
- package/build/schemas/calendar-day.schema.js +27 -0
- package/build/schemas/index.js +2 -0
- package/build/schemas/order/order-external-number.schema.js +9 -0
- package/build/schemas/order/order.schema.js +8 -1
- package/build/schemas/order-delivery/order-delivery.schema.js +5 -0
- package/commands/order/create-order.command.ts +5 -1
- package/commands/order/get-order-list.query.ts +2 -2
- package/commands/order/group/pin-group-order-planned-shipment-date.command.ts +23 -0
- package/commands/order/index.ts +1 -0
- package/commands/order/update-order.command.ts +5 -1
- package/commands/order/webshop/update-cart.command.ts +6 -1
- package/constant/error-i18n-key.ts +1 -0
- package/constant/error.ts +16 -0
- package/constant/index.ts +1 -0
- package/constant/order-external-number.constant.ts +3 -0
- package/enum/order-updated-field.enum.ts +2 -0
- package/package.json +1 -1
- package/schemas/calendar-day.schema.ts +26 -0
- package/schemas/index.ts +2 -0
- package/schemas/order/order-external-number.schema.ts +7 -0
- package/schemas/order/order.schema.ts +8 -1
- package/schemas/order-delivery/order-delivery.schema.ts +5 -0
|
@@ -14,6 +14,10 @@ const CreateOrderRequestSchema = zod_1.z.object({
|
|
|
14
14
|
comment: zod_1.z.string().nullable(),
|
|
15
15
|
clientComment: zod_1.z.string().nullable(),
|
|
16
16
|
tag: zod_1.z.string().nullable(),
|
|
17
|
+
externalNumber: schemas_1.OrderExternalNumberRequestSchema,
|
|
18
|
+
// Дата отгрузки/выдачи — одна для самовывоза и доставки. Приоритет над устаревшим
|
|
19
|
+
// `delivery.deliveryDate`.
|
|
20
|
+
plannedShipmentDate: schemas_1.CalendarDaySchema.nullable().optional(),
|
|
17
21
|
delivery: schemas_1.OrderDeliverySchema.omit({ uuid: true }).nullable(),
|
|
18
22
|
});
|
|
19
23
|
const CreateOrderResponseSchema = zod_1.z.object({
|
|
@@ -24,8 +24,8 @@ const GetOrderListRequestSchema = zod_1.z
|
|
|
24
24
|
* ссылок и MCP-клиентов: трактуется как период из одного дня (from = to = deliveryDate).
|
|
25
25
|
*/
|
|
26
26
|
deliveryDate: zod_1.z.coerce.date().optional(),
|
|
27
|
-
//
|
|
28
|
-
//
|
|
27
|
+
// Период даты отгрузки/выдачи заказа (`plannedShipmentDate`) — и доставка, и самовывоз; имена
|
|
28
|
+
// остались от фильтра по дате доставки. Календарные дни `YYYY-MM-DD`, обе границы включительно.
|
|
29
29
|
deliveryDateFrom: zod_1.z.coerce.date().optional(),
|
|
30
30
|
deliveryDateTo: zod_1.z.coerce.date().optional(),
|
|
31
31
|
byProductSearchQuery: zod_1.z.string().optional(),
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.PinGroupOrderPlannedShipmentDateContractCommand = void 0;
|
|
4
|
+
const zod_1 = require("zod");
|
|
5
|
+
// Подтянуть дату отгрузки/выдачи выбранных заказов к приходу товара в пути — например, после того как
|
|
6
|
+
// сдвинули дату прихода задержавшейся партии. Заказы целиком в наличии не меняются.
|
|
7
|
+
const PinGroupOrderPlannedShipmentDateRequestSchema = zod_1.z.object({
|
|
8
|
+
orderUUIDList: zod_1.z.array(zod_1.z.uuid()).min(1),
|
|
9
|
+
});
|
|
10
|
+
const PinGroupOrderPlannedShipmentDateResponseSchema = zod_1.z.object({
|
|
11
|
+
message: zod_1.z.string().optional(),
|
|
12
|
+
data: zod_1.z.object({
|
|
13
|
+
// Сколько заказов получили новую дату.
|
|
14
|
+
updatedCount: zod_1.z.number(),
|
|
15
|
+
}),
|
|
16
|
+
});
|
|
17
|
+
var PinGroupOrderPlannedShipmentDateContractCommand;
|
|
18
|
+
(function (PinGroupOrderPlannedShipmentDateContractCommand) {
|
|
19
|
+
PinGroupOrderPlannedShipmentDateContractCommand.RequestSchema = PinGroupOrderPlannedShipmentDateRequestSchema;
|
|
20
|
+
PinGroupOrderPlannedShipmentDateContractCommand.ResponseSchema = PinGroupOrderPlannedShipmentDateResponseSchema;
|
|
21
|
+
})(PinGroupOrderPlannedShipmentDateContractCommand || (exports.PinGroupOrderPlannedShipmentDateContractCommand = PinGroupOrderPlannedShipmentDateContractCommand = {}));
|
|
@@ -34,6 +34,7 @@ __exportStar(require("./group/split-group-order.command"), exports);
|
|
|
34
34
|
__exportStar(require("./group/merge-orders.command"), exports);
|
|
35
35
|
__exportStar(require("./group/get-group-order-invoice-info.query"), exports);
|
|
36
36
|
__exportStar(require("./group/send-group-order-invoice.command"), exports);
|
|
37
|
+
__exportStar(require("./group/pin-group-order-planned-shipment-date.command"), exports);
|
|
37
38
|
//webshop
|
|
38
39
|
__exportStar(require("./webshop/get-order-for-client.query"), exports);
|
|
39
40
|
__exportStar(require("./webshop/create-cart.command"), exports);
|
|
@@ -13,12 +13,16 @@ const UpdateOrderRequestSchema = zod_1.z.object({
|
|
|
13
13
|
comment: zod_1.z.string().nullable(),
|
|
14
14
|
clientComment: zod_1.z.string().nullable(),
|
|
15
15
|
tag: zod_1.z.string().nullable(),
|
|
16
|
+
externalNumber: schemas_1.OrderExternalNumberRequestSchema,
|
|
16
17
|
status: zod_1.z.nativeEnum(enum_1.OrderStatusEnum),
|
|
17
18
|
isPaid: zod_1.z.coerce.boolean(),
|
|
18
19
|
deliveryVat: zod_1.z.coerce.number().nullable(),
|
|
19
20
|
deliveryVatAmount: money_schema_1.MoneySchema,
|
|
20
21
|
completedAt: zod_1.z.coerce.date().nullable().optional(),
|
|
21
22
|
paymentDueAt: zod_1.z.coerce.date().nullable().optional(),
|
|
23
|
+
// Дата отгрузки/выдачи — одна для самовывоза и доставки. Не раньше прихода товара в пути
|
|
24
|
+
// (O061, в errorData — самый ранний день). Не передано — не меняется, null — снять.
|
|
25
|
+
plannedShipmentDate: schemas_1.CalendarDaySchema.nullable().optional(),
|
|
22
26
|
});
|
|
23
27
|
const UpdateOrderResponseSchema = zod_1.z.object({
|
|
24
28
|
message: zod_1.z.string().optional(),
|
|
@@ -6,8 +6,13 @@ const schemas_1 = require("../../../schemas");
|
|
|
6
6
|
const UpdateCartRequestSchema = zod_1.z.object({
|
|
7
7
|
clientComment: zod_1.z.string().nullable().optional().default(null),
|
|
8
8
|
branchUUID: zod_1.z.uuid().optional().nullable().default(null),
|
|
9
|
+
// Дата выдачи/доставки заказа — одна для самовывоза и доставки. Относится к товару в наличии:
|
|
10
|
+
// заказы с товаром в пути после оформления получают дату прихода. Имеет приоритет над
|
|
11
|
+
// устаревшим `delivery.deliveryDate`.
|
|
12
|
+
plannedShipmentDate: schemas_1.CalendarDaySchema.nullable().optional(),
|
|
9
13
|
delivery: zod_1.z
|
|
10
14
|
.object({
|
|
15
|
+
/** @deprecated Используйте `plannedShipmentDate` — единую дату для самовывоза и доставки. */
|
|
11
16
|
deliveryDate: zod_1.z.coerce.date().optional().nullable().default(null),
|
|
12
17
|
address: zod_1.z.string().nullable().optional().default(null),
|
|
13
18
|
time: zod_1.z.string().nullable().optional().default(null),
|
|
@@ -12,6 +12,7 @@ exports.ErrorI18nKey = {
|
|
|
12
12
|
mergeOrderHasDistribution: 'mergeOrder.hasDistribution',
|
|
13
13
|
mergeOrderHasPaymentInvoice: 'mergeOrder.hasPaymentInvoice',
|
|
14
14
|
mergeOrderHasTransferDocument: 'mergeOrder.hasTransferDocument',
|
|
15
|
+
mergeOrderSourceHasExternalNumber: 'mergeOrder.sourceHasExternalNumber',
|
|
15
16
|
mergeOrderPaymentsTransfer: 'mergeOrder.paymentsTransfer',
|
|
16
17
|
mergeOrderDeliveryMerge: 'mergeOrder.deliveryMerge',
|
|
17
18
|
mergeOrderDeliveryTransfer: 'mergeOrder.deliveryTransfer',
|
package/build/constant/error.js
CHANGED
|
@@ -414,6 +414,12 @@ exports.ERRORS = {
|
|
|
414
414
|
message: 'The order is included in a transfer document and cannot be changed or deleted',
|
|
415
415
|
httpCode: 409,
|
|
416
416
|
},
|
|
417
|
+
// В data — номер заказа, за которым номер уже закреплён: UI пишет «привязан к заказу №…».
|
|
418
|
+
ORDER_EXTERNAL_NUMBER_TAKEN: {
|
|
419
|
+
code: 'O063',
|
|
420
|
+
message: 'The external number is already assigned to another order',
|
|
421
|
+
httpCode: 409,
|
|
422
|
+
},
|
|
417
423
|
ORDER_SPLIT_NOT_COMPLETELY_ERROR: { code: 'O019', message: 'Error splitting orders, not all orders were split', httpCode: 500 },
|
|
418
424
|
ORDER_TOTAL_COST_NEGATIVE: { code: 'O020', message: 'Order total cost is negative', httpCode: 400 },
|
|
419
425
|
ORDER_SUBTOTAL_NEGATIVE: { code: 'O021', message: 'Order subtotal is negative', httpCode: 400 },
|
|
@@ -429,6 +435,16 @@ exports.ERRORS = {
|
|
|
429
435
|
ORDER_MERGE_HAS_DISTRIBUTION: { code: 'O032', message: 'Order has products with distribution', httpCode: 400 },
|
|
430
436
|
ORDER_MERGE_HAS_PAYMENT_INVOICE: { code: 'O040', message: 'Order is included in a payment invoice', httpCode: 400 },
|
|
431
437
|
ORDER_MERGE_HAS_TRANSFER_DOCUMENT: { code: 'O060', message: 'Order is included in a transfer document', httpCode: 400 },
|
|
438
|
+
// Дата отгрузки/выдачи раньше прихода товара на склад. В errorData — самый ранний допустимый день
|
|
439
|
+
// (`YYYY-MM-DD`), чтобы UI мог его подсказать, а не отправлял угадывать.
|
|
440
|
+
ORDER_PLANNED_SHIPMENT_DATE_BEFORE_ARRIVAL: {
|
|
441
|
+
code: 'O061',
|
|
442
|
+
message: 'Planned shipment date cannot be earlier than the arrival of the goods',
|
|
443
|
+
httpCode: 400,
|
|
444
|
+
},
|
|
445
|
+
ORDER_PLANNED_SHIPMENT_DATE_NOT_UPDATED: { code: 'O062', message: 'Failed to update order planned shipment date', httpCode: 500 },
|
|
446
|
+
// Источник объединения удаляется, и его связь с документом ERP пропала бы молча.
|
|
447
|
+
ORDER_MERGE_SOURCE_HAS_EXTERNAL_NUMBER: { code: 'O064', message: 'Source order has an external number', httpCode: 400 },
|
|
432
448
|
ORDER_MERGE_BALANCE_STATUS_NOT_ALLOWED: {
|
|
433
449
|
code: 'O033',
|
|
434
450
|
message: 'Order status is balance affecting, merge not allowed',
|
package/build/constant/index.js
CHANGED
|
@@ -30,3 +30,4 @@ __exportStar(require("./attribute-normalization.constant"), exports);
|
|
|
30
30
|
__exportStar(require("./product-image-merge.constant"), exports);
|
|
31
31
|
__exportStar(require("./client-group-actions.constant"), exports);
|
|
32
32
|
__exportStar(require("./standing-order-positions.constant"), exports);
|
|
33
|
+
__exportStar(require("./order-external-number.constant"), exports);
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ORDER_EXTERNAL_NUMBER_MAX_LENGTH = void 0;
|
|
4
|
+
// Номера документов ERP/CRM короткие («ЗК-00123», GUID в 36 символов), 100 — с запасом. Колонка
|
|
5
|
+
// TEXT длину не держит, поэтому граница — только схема запроса.
|
|
6
|
+
exports.ORDER_EXTERNAL_NUMBER_MAX_LENGTH = 100;
|
|
@@ -20,4 +20,6 @@ var OrderUpdatedFieldEnum;
|
|
|
20
20
|
OrderUpdatedFieldEnum["IS_PAID"] = "IS_PAID";
|
|
21
21
|
OrderUpdatedFieldEnum["COMPLETED_AT"] = "COMPLETED_AT";
|
|
22
22
|
OrderUpdatedFieldEnum["PAYMENT_DUE_AT"] = "PAYMENT_DUE_AT";
|
|
23
|
+
OrderUpdatedFieldEnum["PLANNED_SHIPMENT_DATE"] = "PLANNED_SHIPMENT_DATE";
|
|
24
|
+
OrderUpdatedFieldEnum["EXTERNAL_NUMBER"] = "EXTERNAL_NUMBER";
|
|
23
25
|
})(OrderUpdatedFieldEnum || (exports.OrderUpdatedFieldEnum = OrderUpdatedFieldEnum = {}));
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.CalendarDaySchema = void 0;
|
|
4
|
+
const zod_1 = require("zod");
|
|
5
|
+
/**
|
|
6
|
+
* Единственное описание календарного дня в контрактах — даты без времени и таймзоны.
|
|
7
|
+
*
|
|
8
|
+
* День пересекает границу строкой `YYYY-MM-DD` в обе стороны. Не `Date` и не ISO-момент: момент
|
|
9
|
+
* требует таймзоны, чтобы из него вернуть день, а у клиента (браузер, устройство) она своя и
|
|
10
|
+
* с таймзоной компании не обязана совпадать — `2026-09-24T21:00:00Z` это 25-е в Москве и 24-е в
|
|
11
|
+
* Лондоне. Строка дня однозначна везде.
|
|
12
|
+
*
|
|
13
|
+
* Сервер хранит такие поля колонкой `DATE`; в JS они живут как полночь UTC, читать и писать их —
|
|
14
|
+
* только через `calendar-day.helper.ts` на бэке.
|
|
15
|
+
*
|
|
16
|
+
* Модификаторы `.optional()` и `.nullable()` работают напрямую.
|
|
17
|
+
*/
|
|
18
|
+
exports.CalendarDaySchema = zod_1.z
|
|
19
|
+
.string()
|
|
20
|
+
.regex(/^\d{4}-\d{2}-\d{2}$/)
|
|
21
|
+
.refine(isExistingCalendarDay, { message: 'Invalid calendar day' });
|
|
22
|
+
// Регэксп пропускает `2026-02-30`: такой день парсер либо отвергает, либо переносит на март —
|
|
23
|
+
// в обоих случаях строка обратно не совпадёт.
|
|
24
|
+
function isExistingCalendarDay(value) {
|
|
25
|
+
const date = new Date(`${value}T00:00:00.000Z`);
|
|
26
|
+
return !Number.isNaN(date.getTime()) && date.toISOString().startsWith(value);
|
|
27
|
+
}
|
package/build/schemas/index.js
CHANGED
|
@@ -33,6 +33,7 @@ __exportStar(require("./write-off/write-off-list.schema"), exports);
|
|
|
33
33
|
__exportStar(require("./write-off/write-off-archive-file.schema"), exports);
|
|
34
34
|
__exportStar(require("./write-off/write-off-export.schema"), exports);
|
|
35
35
|
__exportStar(require("./order/order.schema"), exports);
|
|
36
|
+
__exportStar(require("./order/order-external-number.schema"), exports);
|
|
36
37
|
__exportStar(require("./order-delivery/order-delivery.schema"), exports);
|
|
37
38
|
__exportStar(require("./order-product/order-product.schema"), exports);
|
|
38
39
|
__exportStar(require("./order-product/order-product-list.schema"), exports);
|
|
@@ -106,6 +107,7 @@ __exportStar(require("./account-deletion-request/account-deletion-request.schema
|
|
|
106
107
|
__exportStar(require("./consignment-transfer"), exports);
|
|
107
108
|
__exportStar(require("./api-error.schema"), exports);
|
|
108
109
|
__exportStar(require("./access-policy"), exports);
|
|
110
|
+
__exportStar(require("./calendar-day.schema"), exports);
|
|
109
111
|
__exportStar(require("./money.schema"), exports);
|
|
110
112
|
__exportStar(require("./non-negative-money.schema"), exports);
|
|
111
113
|
__exportStar(require("./positive-money.schema"), exports);
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.OrderExternalNumberRequestSchema = void 0;
|
|
4
|
+
const zod_1 = require("zod");
|
|
5
|
+
const order_external_number_constant_1 = require("../../constant/order-external-number.constant");
|
|
6
|
+
// Номер заказа в ERP/CRM компании на входе create/update. Поле не пришло — номер не меняется;
|
|
7
|
+
// null или строка из пробелов — номер снимается (пустую строку сервер сохраняет как null, иначе
|
|
8
|
+
// вторая пустая строка упрётся в уникальность номера в пределах компании).
|
|
9
|
+
exports.OrderExternalNumberRequestSchema = zod_1.z.string().trim().max(order_external_number_constant_1.ORDER_EXTERNAL_NUMBER_MAX_LENGTH).nullable().optional();
|
|
@@ -8,6 +8,7 @@ const branch_schema_1 = require("../branch/branch.schema");
|
|
|
8
8
|
const order_delivery_schema_1 = require("../order-delivery/order-delivery.schema");
|
|
9
9
|
const delivery_route_schema_1 = require("../delivery-route/delivery-route.schema");
|
|
10
10
|
const money_schema_1 = require("../money.schema");
|
|
11
|
+
const calendar_day_schema_1 = require("../calendar-day.schema");
|
|
11
12
|
exports.OrderSchema = zod_1.z.object({
|
|
12
13
|
uuid: zod_1.z.uuid(),
|
|
13
14
|
orderNumber: zod_1.z.number(),
|
|
@@ -40,19 +41,25 @@ exports.OrderSchema = zod_1.z.object({
|
|
|
40
41
|
// ссылка, документ читается через GET /transfer-document/:uuid. Непустое значение означает, что
|
|
41
42
|
// заказ заморожен — состав, статус, доставка, дата отгрузки и скидка ему уже недоступны.
|
|
42
43
|
transferDocumentUUID: zod_1.z.uuid().nullable(),
|
|
44
|
+
// Номер заказа в ERP/CRM компании, которым сотрудники сверяют заказ со своей учётной системой.
|
|
45
|
+
externalNumber: zod_1.z.string().nullable(),
|
|
43
46
|
completedAt: zod_1.z.date().nullable(),
|
|
44
47
|
paymentDueAt: zod_1.z.date().nullable(),
|
|
48
|
+
// План отгрузки/выдачи — одна дата для самовывоза и доставки, календарный день `YYYY-MM-DD`.
|
|
49
|
+
// Не путать с `completedAt` (факт отгрузки) и датой прихода партии.
|
|
50
|
+
plannedShipmentDate: calendar_day_schema_1.CalendarDaySchema.nullable(),
|
|
45
51
|
createdAt: zod_1.z.date(),
|
|
46
52
|
updatedAt: zod_1.z.date(),
|
|
47
53
|
deletedAt: zod_1.z.date().nullable(),
|
|
48
54
|
});
|
|
49
55
|
// Витрина клиента не показывает внутреннюю кухню документов, поэтому ссылки на счёт и на УПД
|
|
50
|
-
// сюда не попадают.
|
|
56
|
+
// сюда не попадают. Номер в ERP компании — тоже её внутренний учёт.
|
|
51
57
|
exports.OrderForClientSchema = exports.OrderSchema.omit({
|
|
52
58
|
comment: true,
|
|
53
59
|
tag: true,
|
|
54
60
|
paymentInvoiceUUID: true,
|
|
55
61
|
transferDocumentUUID: true,
|
|
62
|
+
externalNumber: true,
|
|
56
63
|
});
|
|
57
64
|
exports.OrderExtendedSchema = exports.OrderSchema.extend({
|
|
58
65
|
client: client_1.ClientSchema,
|
|
@@ -6,6 +6,11 @@ const enum_1 = require("../../enum");
|
|
|
6
6
|
exports.OrderDeliverySchema = zod_1.z.object({
|
|
7
7
|
uuid: zod_1.z.uuid(),
|
|
8
8
|
city: zod_1.z.string().nullable(),
|
|
9
|
+
/**
|
|
10
|
+
* @deprecated Дата доставки живёт в заказе: `Order.plannedShipmentDate` (`YYYY-MM-DD`) — одна для
|
|
11
|
+
* самовывоза и доставки. Поле принимается и отдаётся ради совместимости: запись перекладывается
|
|
12
|
+
* в заказ, чтение возвращает дату заказа.
|
|
13
|
+
*/
|
|
9
14
|
deliveryDate: zod_1.z.coerce.date().nullable(),
|
|
10
15
|
address: zod_1.z.string().nullable(),
|
|
11
16
|
time: zod_1.z.string().nullable(),
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
2
|
import { OrderTypeEnum } from '../../enum';
|
|
3
|
-
import { OrderDeliverySchema, OrderSchema } from '../../schemas';
|
|
3
|
+
import { CalendarDaySchema, OrderDeliverySchema, OrderExternalNumberRequestSchema, OrderSchema } from '../../schemas';
|
|
4
4
|
import { MoneySchema } from '../../schemas/money.schema';
|
|
5
5
|
|
|
6
6
|
const CreateOrderRequestSchema = z.object({
|
|
@@ -12,6 +12,10 @@ const CreateOrderRequestSchema = z.object({
|
|
|
12
12
|
comment: z.string().nullable(),
|
|
13
13
|
clientComment: z.string().nullable(),
|
|
14
14
|
tag: z.string().nullable(),
|
|
15
|
+
externalNumber: OrderExternalNumberRequestSchema,
|
|
16
|
+
// Дата отгрузки/выдачи — одна для самовывоза и доставки. Приоритет над устаревшим
|
|
17
|
+
// `delivery.deliveryDate`.
|
|
18
|
+
plannedShipmentDate: CalendarDaySchema.nullable().optional(),
|
|
15
19
|
delivery: OrderDeliverySchema.omit({ uuid: true }).nullable(),
|
|
16
20
|
});
|
|
17
21
|
|
|
@@ -22,8 +22,8 @@ const GetOrderListRequestSchema = z
|
|
|
22
22
|
* ссылок и MCP-клиентов: трактуется как период из одного дня (from = to = deliveryDate).
|
|
23
23
|
*/
|
|
24
24
|
deliveryDate: z.coerce.date().optional(),
|
|
25
|
-
//
|
|
26
|
-
//
|
|
25
|
+
// Период даты отгрузки/выдачи заказа (`plannedShipmentDate`) — и доставка, и самовывоз; имена
|
|
26
|
+
// остались от фильтра по дате доставки. Календарные дни `YYYY-MM-DD`, обе границы включительно.
|
|
27
27
|
deliveryDateFrom: z.coerce.date().optional(),
|
|
28
28
|
deliveryDateTo: z.coerce.date().optional(),
|
|
29
29
|
byProductSearchQuery: z.string().optional(),
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
|
|
3
|
+
// Подтянуть дату отгрузки/выдачи выбранных заказов к приходу товара в пути — например, после того как
|
|
4
|
+
// сдвинули дату прихода задержавшейся партии. Заказы целиком в наличии не меняются.
|
|
5
|
+
const PinGroupOrderPlannedShipmentDateRequestSchema = z.object({
|
|
6
|
+
orderUUIDList: z.array(z.uuid()).min(1),
|
|
7
|
+
});
|
|
8
|
+
|
|
9
|
+
const PinGroupOrderPlannedShipmentDateResponseSchema = z.object({
|
|
10
|
+
message: z.string().optional(),
|
|
11
|
+
data: z.object({
|
|
12
|
+
// Сколько заказов получили новую дату.
|
|
13
|
+
updatedCount: z.number(),
|
|
14
|
+
}),
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
export namespace PinGroupOrderPlannedShipmentDateContractCommand {
|
|
18
|
+
export const RequestSchema = PinGroupOrderPlannedShipmentDateRequestSchema;
|
|
19
|
+
export type Request = z.infer<typeof RequestSchema>;
|
|
20
|
+
|
|
21
|
+
export const ResponseSchema = PinGroupOrderPlannedShipmentDateResponseSchema;
|
|
22
|
+
export type Response = z.infer<typeof ResponseSchema>;
|
|
23
|
+
}
|
package/commands/order/index.ts
CHANGED
|
@@ -18,6 +18,7 @@ export * from './group/split-group-order.command';
|
|
|
18
18
|
export * from './group/merge-orders.command';
|
|
19
19
|
export * from './group/get-group-order-invoice-info.query';
|
|
20
20
|
export * from './group/send-group-order-invoice.command';
|
|
21
|
+
export * from './group/pin-group-order-planned-shipment-date.command';
|
|
21
22
|
//webshop
|
|
22
23
|
export * from './webshop/get-order-for-client.query';
|
|
23
24
|
export * from './webshop/create-cart.command';
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
2
|
import { OrderStatusEnum, OrderTypeEnum } from '../../enum';
|
|
3
|
-
import { OrderSchema } from '../../schemas';
|
|
3
|
+
import { CalendarDaySchema, OrderExternalNumberRequestSchema, OrderSchema } from '../../schemas';
|
|
4
4
|
import { MoneySchema } from '../../schemas/money.schema';
|
|
5
5
|
|
|
6
6
|
const UpdateOrderRequestSchema = z.object({
|
|
@@ -11,12 +11,16 @@ const UpdateOrderRequestSchema = z.object({
|
|
|
11
11
|
comment: z.string().nullable(),
|
|
12
12
|
clientComment: z.string().nullable(),
|
|
13
13
|
tag: z.string().nullable(),
|
|
14
|
+
externalNumber: OrderExternalNumberRequestSchema,
|
|
14
15
|
status: z.nativeEnum(OrderStatusEnum),
|
|
15
16
|
isPaid: z.coerce.boolean(),
|
|
16
17
|
deliveryVat: z.coerce.number().nullable(),
|
|
17
18
|
deliveryVatAmount: MoneySchema,
|
|
18
19
|
completedAt: z.coerce.date().nullable().optional(),
|
|
19
20
|
paymentDueAt: z.coerce.date().nullable().optional(),
|
|
21
|
+
// Дата отгрузки/выдачи — одна для самовывоза и доставки. Не раньше прихода товара в пути
|
|
22
|
+
// (O061, в errorData — самый ранний день). Не передано — не меняется, null — снять.
|
|
23
|
+
plannedShipmentDate: CalendarDaySchema.nullable().optional(),
|
|
20
24
|
});
|
|
21
25
|
|
|
22
26
|
const UpdateOrderResponseSchema = z.object({
|
|
@@ -1,11 +1,16 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
|
-
import { OrderForClientSchema } from '../../../schemas';
|
|
2
|
+
import { CalendarDaySchema, OrderForClientSchema } from '../../../schemas';
|
|
3
3
|
|
|
4
4
|
const UpdateCartRequestSchema = z.object({
|
|
5
5
|
clientComment: z.string().nullable().optional().default(null),
|
|
6
6
|
branchUUID: z.uuid().optional().nullable().default(null),
|
|
7
|
+
// Дата выдачи/доставки заказа — одна для самовывоза и доставки. Относится к товару в наличии:
|
|
8
|
+
// заказы с товаром в пути после оформления получают дату прихода. Имеет приоритет над
|
|
9
|
+
// устаревшим `delivery.deliveryDate`.
|
|
10
|
+
plannedShipmentDate: CalendarDaySchema.nullable().optional(),
|
|
7
11
|
delivery: z
|
|
8
12
|
.object({
|
|
13
|
+
/** @deprecated Используйте `plannedShipmentDate` — единую дату для самовывоза и доставки. */
|
|
9
14
|
deliveryDate: z.coerce.date().optional().nullable().default(null),
|
|
10
15
|
address: z.string().nullable().optional().default(null),
|
|
11
16
|
time: z.string().nullable().optional().default(null),
|
|
@@ -9,6 +9,7 @@ export const ErrorI18nKey = {
|
|
|
9
9
|
mergeOrderHasDistribution: 'mergeOrder.hasDistribution',
|
|
10
10
|
mergeOrderHasPaymentInvoice: 'mergeOrder.hasPaymentInvoice',
|
|
11
11
|
mergeOrderHasTransferDocument: 'mergeOrder.hasTransferDocument',
|
|
12
|
+
mergeOrderSourceHasExternalNumber: 'mergeOrder.sourceHasExternalNumber',
|
|
12
13
|
mergeOrderPaymentsTransfer: 'mergeOrder.paymentsTransfer',
|
|
13
14
|
mergeOrderDeliveryMerge: 'mergeOrder.deliveryMerge',
|
|
14
15
|
mergeOrderDeliveryTransfer: 'mergeOrder.deliveryTransfer',
|
package/constant/error.ts
CHANGED
|
@@ -428,6 +428,12 @@ export const ERRORS = {
|
|
|
428
428
|
message: 'The order is included in a transfer document and cannot be changed or deleted',
|
|
429
429
|
httpCode: 409,
|
|
430
430
|
},
|
|
431
|
+
// В data — номер заказа, за которым номер уже закреплён: UI пишет «привязан к заказу №…».
|
|
432
|
+
ORDER_EXTERNAL_NUMBER_TAKEN: {
|
|
433
|
+
code: 'O063',
|
|
434
|
+
message: 'The external number is already assigned to another order',
|
|
435
|
+
httpCode: 409,
|
|
436
|
+
},
|
|
431
437
|
ORDER_SPLIT_NOT_COMPLETELY_ERROR: { code: 'O019', message: 'Error splitting orders, not all orders were split', httpCode: 500 },
|
|
432
438
|
ORDER_TOTAL_COST_NEGATIVE: { code: 'O020', message: 'Order total cost is negative', httpCode: 400 },
|
|
433
439
|
ORDER_SUBTOTAL_NEGATIVE: { code: 'O021', message: 'Order subtotal is negative', httpCode: 400 },
|
|
@@ -443,6 +449,16 @@ export const ERRORS = {
|
|
|
443
449
|
ORDER_MERGE_HAS_DISTRIBUTION: { code: 'O032', message: 'Order has products with distribution', httpCode: 400 },
|
|
444
450
|
ORDER_MERGE_HAS_PAYMENT_INVOICE: { code: 'O040', message: 'Order is included in a payment invoice', httpCode: 400 },
|
|
445
451
|
ORDER_MERGE_HAS_TRANSFER_DOCUMENT: { code: 'O060', message: 'Order is included in a transfer document', httpCode: 400 },
|
|
452
|
+
// Дата отгрузки/выдачи раньше прихода товара на склад. В errorData — самый ранний допустимый день
|
|
453
|
+
// (`YYYY-MM-DD`), чтобы UI мог его подсказать, а не отправлял угадывать.
|
|
454
|
+
ORDER_PLANNED_SHIPMENT_DATE_BEFORE_ARRIVAL: {
|
|
455
|
+
code: 'O061',
|
|
456
|
+
message: 'Planned shipment date cannot be earlier than the arrival of the goods',
|
|
457
|
+
httpCode: 400,
|
|
458
|
+
},
|
|
459
|
+
ORDER_PLANNED_SHIPMENT_DATE_NOT_UPDATED: { code: 'O062', message: 'Failed to update order planned shipment date', httpCode: 500 },
|
|
460
|
+
// Источник объединения удаляется, и его связь с документом ERP пропала бы молча.
|
|
461
|
+
ORDER_MERGE_SOURCE_HAS_EXTERNAL_NUMBER: { code: 'O064', message: 'Source order has an external number', httpCode: 400 },
|
|
446
462
|
ORDER_MERGE_BALANCE_STATUS_NOT_ALLOWED: {
|
|
447
463
|
code: 'O033',
|
|
448
464
|
message: 'Order status is balance affecting, merge not allowed',
|
package/constant/index.ts
CHANGED
package/package.json
CHANGED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Единственное описание календарного дня в контрактах — даты без времени и таймзоны.
|
|
5
|
+
*
|
|
6
|
+
* День пересекает границу строкой `YYYY-MM-DD` в обе стороны. Не `Date` и не ISO-момент: момент
|
|
7
|
+
* требует таймзоны, чтобы из него вернуть день, а у клиента (браузер, устройство) она своя и
|
|
8
|
+
* с таймзоной компании не обязана совпадать — `2026-09-24T21:00:00Z` это 25-е в Москве и 24-е в
|
|
9
|
+
* Лондоне. Строка дня однозначна везде.
|
|
10
|
+
*
|
|
11
|
+
* Сервер хранит такие поля колонкой `DATE`; в JS они живут как полночь UTC, читать и писать их —
|
|
12
|
+
* только через `calendar-day.helper.ts` на бэке.
|
|
13
|
+
*
|
|
14
|
+
* Модификаторы `.optional()` и `.nullable()` работают напрямую.
|
|
15
|
+
*/
|
|
16
|
+
export const CalendarDaySchema = z
|
|
17
|
+
.string()
|
|
18
|
+
.regex(/^\d{4}-\d{2}-\d{2}$/)
|
|
19
|
+
.refine(isExistingCalendarDay, { message: 'Invalid calendar day' });
|
|
20
|
+
|
|
21
|
+
// Регэксп пропускает `2026-02-30`: такой день парсер либо отвергает, либо переносит на март —
|
|
22
|
+
// в обоих случаях строка обратно не совпадёт.
|
|
23
|
+
function isExistingCalendarDay(value: string): boolean {
|
|
24
|
+
const date = new Date(`${value}T00:00:00.000Z`);
|
|
25
|
+
return !Number.isNaN(date.getTime()) && date.toISOString().startsWith(value);
|
|
26
|
+
}
|
package/schemas/index.ts
CHANGED
|
@@ -17,6 +17,7 @@ export * from './write-off/write-off-list.schema';
|
|
|
17
17
|
export * from './write-off/write-off-archive-file.schema';
|
|
18
18
|
export * from './write-off/write-off-export.schema';
|
|
19
19
|
export * from './order/order.schema';
|
|
20
|
+
export * from './order/order-external-number.schema';
|
|
20
21
|
export * from './order-delivery/order-delivery.schema';
|
|
21
22
|
export * from './order-product/order-product.schema';
|
|
22
23
|
export * from './order-product/order-product-list.schema';
|
|
@@ -90,6 +91,7 @@ export * from './account-deletion-request/account-deletion-request.schema';
|
|
|
90
91
|
export * from './consignment-transfer';
|
|
91
92
|
export * from './api-error.schema';
|
|
92
93
|
export * from './access-policy';
|
|
94
|
+
export * from './calendar-day.schema';
|
|
93
95
|
export * from './money.schema';
|
|
94
96
|
export * from './non-negative-money.schema';
|
|
95
97
|
export * from './positive-money.schema';
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { ORDER_EXTERNAL_NUMBER_MAX_LENGTH } from '../../constant/order-external-number.constant';
|
|
3
|
+
|
|
4
|
+
// Номер заказа в ERP/CRM компании на входе create/update. Поле не пришло — номер не меняется;
|
|
5
|
+
// null или строка из пробелов — номер снимается (пустую строку сервер сохраняет как null, иначе
|
|
6
|
+
// вторая пустая строка упрётся в уникальность номера в пределах компании).
|
|
7
|
+
export const OrderExternalNumberRequestSchema = z.string().trim().max(ORDER_EXTERNAL_NUMBER_MAX_LENGTH).nullable().optional();
|
|
@@ -5,6 +5,7 @@ import { BranchSchema } from '../branch/branch.schema';
|
|
|
5
5
|
import { OrderDeliverySchema } from '../order-delivery/order-delivery.schema';
|
|
6
6
|
import { DeliveryRouteSchema } from '../delivery-route/delivery-route.schema';
|
|
7
7
|
import { MoneySchema } from '../money.schema';
|
|
8
|
+
import { CalendarDaySchema } from '../calendar-day.schema';
|
|
8
9
|
|
|
9
10
|
export const OrderSchema = z.object({
|
|
10
11
|
uuid: z.uuid(),
|
|
@@ -42,9 +43,14 @@ export const OrderSchema = z.object({
|
|
|
42
43
|
// ссылка, документ читается через GET /transfer-document/:uuid. Непустое значение означает, что
|
|
43
44
|
// заказ заморожен — состав, статус, доставка, дата отгрузки и скидка ему уже недоступны.
|
|
44
45
|
transferDocumentUUID: z.uuid().nullable(),
|
|
46
|
+
// Номер заказа в ERP/CRM компании, которым сотрудники сверяют заказ со своей учётной системой.
|
|
47
|
+
externalNumber: z.string().nullable(),
|
|
45
48
|
|
|
46
49
|
completedAt: z.date().nullable(),
|
|
47
50
|
paymentDueAt: z.date().nullable(),
|
|
51
|
+
// План отгрузки/выдачи — одна дата для самовывоза и доставки, календарный день `YYYY-MM-DD`.
|
|
52
|
+
// Не путать с `completedAt` (факт отгрузки) и датой прихода партии.
|
|
53
|
+
plannedShipmentDate: CalendarDaySchema.nullable(),
|
|
48
54
|
|
|
49
55
|
createdAt: z.date(),
|
|
50
56
|
updatedAt: z.date(),
|
|
@@ -52,12 +58,13 @@ export const OrderSchema = z.object({
|
|
|
52
58
|
});
|
|
53
59
|
|
|
54
60
|
// Витрина клиента не показывает внутреннюю кухню документов, поэтому ссылки на счёт и на УПД
|
|
55
|
-
// сюда не попадают.
|
|
61
|
+
// сюда не попадают. Номер в ERP компании — тоже её внутренний учёт.
|
|
56
62
|
export const OrderForClientSchema = OrderSchema.omit({
|
|
57
63
|
comment: true,
|
|
58
64
|
tag: true,
|
|
59
65
|
paymentInvoiceUUID: true,
|
|
60
66
|
transferDocumentUUID: true,
|
|
67
|
+
externalNumber: true,
|
|
61
68
|
});
|
|
62
69
|
|
|
63
70
|
export const OrderExtendedSchema = OrderSchema.extend({
|
|
@@ -4,6 +4,11 @@ import { OrderDeliveryStatusEnum } from '../../enum';
|
|
|
4
4
|
export const OrderDeliverySchema = z.object({
|
|
5
5
|
uuid: z.uuid(),
|
|
6
6
|
city: z.string().nullable(),
|
|
7
|
+
/**
|
|
8
|
+
* @deprecated Дата доставки живёт в заказе: `Order.plannedShipmentDate` (`YYYY-MM-DD`) — одна для
|
|
9
|
+
* самовывоза и доставки. Поле принимается и отдаётся ради совместимости: запись перекладывается
|
|
10
|
+
* в заказ, чтение возвращает дату заказа.
|
|
11
|
+
*/
|
|
7
12
|
deliveryDate: z.coerce.date().nullable(),
|
|
8
13
|
address: z.string().nullable(),
|
|
9
14
|
time: z.string().nullable(),
|