@floristcloud/api-lib 1.2.167 → 1.2.168

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,14 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.DISCOUNT_RULES_PRICING_TYPE_LIST = void 0;
4
+ const discount_rules_type_enum_1 = require("../enum/discount-rules-type.enum");
5
+ /**
6
+ * Правила ценообразования: задают цену клиента целиком, а не уменьшают её.
7
+ *
8
+ * Цена от себестоимости или от прайса плюс наценка. Если у клиента есть такое правило, скидки к нему не
9
+ * применяются, и больше одного действующего правила ценообразования на клиента быть не может.
10
+ */
11
+ exports.DISCOUNT_RULES_PRICING_TYPE_LIST = [
12
+ discount_rules_type_enum_1.DiscountRulesTypeEnum.COST_PLUS_MARKUP,
13
+ discount_rules_type_enum_1.DiscountRulesTypeEnum.PRICE_PLUS_MARKUP,
14
+ ];
@@ -1363,6 +1363,17 @@ exports.ERRORS = {
1363
1363
  message: 'Too many products for a single consignment discount operation',
1364
1364
  httpCode: 400,
1365
1365
  },
1366
+ DISCOUNT_RULES_PRICING_RULE_CONFLICT: {
1367
+ code: 'DR007',
1368
+ message: 'A client can have only one active pricing rule',
1369
+ httpCode: 409,
1370
+ },
1371
+ // Не дождались транзакционной блокировки правил ценообразования компании (lock_timeout).
1372
+ DISCOUNT_RULES_PRICING_RULE_LOCK_BUSY: {
1373
+ code: 'DR008',
1374
+ message: 'Pricing rules of this company are being changed right now, try again',
1375
+ httpCode: 409,
1376
+ },
1366
1377
  DISCOUNT_RULES_NOT_FOUND: { code: 'DR010', message: 'Discount-rules not found', httpCode: 404 },
1367
1378
  // ACTION LOG
1368
1379
  ACTION_LOG_NOT_CREATED: { code: 'ALG001', message: 'Failed to create action-log', httpCode: 500 },
@@ -31,3 +31,4 @@ __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
33
  __exportStar(require("./order-external-number.constant"), exports);
34
+ __exportStar(require("./discount-rules-pricing-type-list.constant"), exports);
@@ -8,10 +8,8 @@ var DiscountRulesModeTypeEnum;
8
8
  /**
9
9
  * Готовая цена, а не величина скидки.
10
10
  *
11
- * Значение вычисляемое: его выставляет правило `COST_PLUS_MARKUP`, посчитав цену от
12
- * себестоимости товара. Задать его снаружи нельзя — схема ввода правила
13
- * (`discountRulesModeSchema`) знает только FIXED и PERCENT, а схема выдачи
14
- * (`discountPriceOutcomeSchema`) — все три.
11
+ * Больше не отдаётся: правило `COST_PLUS_MARKUP` стало правилом ценообразования и задаёт цену
12
+ * клиента, а не вариант скидки. Значение оставлено, чтобы не ломать клиентов, которые его разбирают.
15
13
  */
16
14
  DiscountRulesModeTypeEnum["TARGET_PRICE"] = "TARGET_PRICE";
17
15
  })(DiscountRulesModeTypeEnum || (exports.DiscountRulesModeTypeEnum = DiscountRulesModeTypeEnum = {}));
@@ -9,4 +9,5 @@ var DiscountRulesTypeEnum;
9
9
  DiscountRulesTypeEnum["ITEM_DISCOUNT"] = "ITEM_DISCOUNT";
10
10
  DiscountRulesTypeEnum["DISCOUNT_PROHIBITED"] = "DISCOUNT_PROHIBITED";
11
11
  DiscountRulesTypeEnum["COST_PLUS_MARKUP"] = "COST_PLUS_MARKUP";
12
+ DiscountRulesTypeEnum["PRICE_PLUS_MARKUP"] = "PRICE_PLUS_MARKUP";
12
13
  })(DiscountRulesTypeEnum || (exports.DiscountRulesTypeEnum = DiscountRulesTypeEnum = {}));
@@ -22,10 +22,9 @@ exports.discountRulesModeSchema = zod_1.z.discriminatedUnion('typeDiscount', [di
22
22
  /**
23
23
  * Итог применения правила к товару — то, что уезжает клиенту в `discountDataList`.
24
24
  *
25
- * От схемы ввода отличается ровно одной веткой: TARGET_PRICE несёт уже посчитанную цену, а не
26
- * величину скидки. Так работает правило от себестоимости: считать цену на клиенте нечем — там нет
27
- * ни себестоимости, ни права её видеть. Ветка живёт только в выдаче: задать TARGET_PRICE при
28
- * создании правила нельзя, `discountRulesModeSchema` его не принимает.
25
+ * Ветка TARGET_PRICE больше не отдаётся: правило от себестоимости стало правилом ценообразования и
26
+ * задаёт цену клиента (`price`, `clientPrice`), а не вариант скидки. Ветка оставлена, чтобы не ломать
27
+ * клиентов, которые её разбирают.
29
28
  */
30
29
  exports.discountPriceOutcomeSchema = zod_1.z.discriminatedUnion('typeDiscount', [
31
30
  discountPercentModeSchema,
@@ -61,18 +60,29 @@ const DiscountRulesQuantityBasedDataSchema = zod_1.z
61
60
  const DiscountRulesItemDiscountDataSchema = exports.discountRulesModeSchema;
62
61
  const DiscountRulesDiscountProhibitedDataSchema = zod_1.z.object({}).default({});
63
62
  /**
64
- * Наценка к себестоимости: цена клиента = себестоимость + наценка.
63
+ * Наценка правила ценообразования: процент или сумма на единицу.
65
64
  *
66
- * Три отличия от режима скидки, и все намеренные:
67
- * — только вверх, знака у величины нет: продажу ниже себестоимости правилом не задают;
68
- * — ноль допустим (`markupValue: 0` — продаём по себестоимости), поэтому FIXED берёт
69
- * `NonNegativeMoneySchema`, а не `PositiveMoneySchema`;
65
+ * Отличия от режима скидки намеренные:
66
+ * — только вверх, знака у величины нет;
67
+ * — ноль допустим (цена ровно равна источнику), поэтому FIXED берёт `NonNegativeMoneySchema`;
70
68
  * — у процента нет верхней границы: наценка в 150 % законна, в отличие от скидки в 150 %.
71
69
  */
70
+ const pricingMarkupPercentSchema = zod_1.z.object({ typeMarkup: zod_1.z.literal(enum_1.DiscountRulesModeTypeEnum.PERCENT), markupValue: zod_1.z.number().min(0) });
71
+ const pricingMarkupFixedSchema = zod_1.z.object({ typeMarkup: zod_1.z.literal(enum_1.DiscountRulesModeTypeEnum.FIXED), markupValue: non_negative_money_schema_1.NonNegativeMoneySchema });
72
+ /**
73
+ * Потолок «не выше прайса» есть только у цены от себестоимости: цена от прайса с наценкой выше
74
+ * прайса по определению. Поле необязательное, и отсутствие значит разное: при создании — потолка
75
+ * нет, при правке — оставить как было. Так старая панель, которая флага не знает, не снимает потолок
76
+ * у правил, которым его проставила миграция.
77
+ */
78
+ const costPlusCapShape = { isCappedByPrice: zod_1.z.boolean().optional() };
79
+ /** Цена клиента = себестоимость + наценка. */
72
80
  const DiscountRulesCostPlusMarkupDataSchema = zod_1.z.discriminatedUnion('typeMarkup', [
73
- zod_1.z.object({ typeMarkup: zod_1.z.literal(enum_1.DiscountRulesModeTypeEnum.PERCENT), markupValue: zod_1.z.number().min(0) }),
74
- zod_1.z.object({ typeMarkup: zod_1.z.literal(enum_1.DiscountRulesModeTypeEnum.FIXED), markupValue: non_negative_money_schema_1.NonNegativeMoneySchema }),
81
+ pricingMarkupPercentSchema.extend(costPlusCapShape),
82
+ pricingMarkupFixedSchema.extend(costPlusCapShape),
75
83
  ]);
84
+ /** Цена клиента = цена позиции (фасовки, если она выбрана) + наценка. */
85
+ const DiscountRulesPricePlusMarkupDataSchema = zod_1.z.discriminatedUnion('typeMarkup', [pricingMarkupPercentSchema, pricingMarkupFixedSchema]);
76
86
  exports.DiscountRulesTypeSchema = zod_1.z.discriminatedUnion('type', [
77
87
  zod_1.z.object({
78
88
  type: zod_1.z.literal(enum_1.DiscountRulesTypeEnum.PERSONAL_DISCOUNT),
@@ -98,6 +108,10 @@ exports.DiscountRulesTypeSchema = zod_1.z.discriminatedUnion('type', [
98
108
  type: zod_1.z.literal(enum_1.DiscountRulesTypeEnum.COST_PLUS_MARKUP),
99
109
  data: DiscountRulesCostPlusMarkupDataSchema,
100
110
  }),
111
+ zod_1.z.object({
112
+ type: zod_1.z.literal(enum_1.DiscountRulesTypeEnum.PRICE_PLUS_MARKUP),
113
+ data: DiscountRulesPricePlusMarkupDataSchema,
114
+ }),
101
115
  ]);
102
116
  exports.DiscountRulesBaseSchema = zod_1.z.object({
103
117
  uuid: zod_1.z.string(),
@@ -5,9 +5,18 @@ const zod_1 = require("zod");
5
5
  const money_schema_1 = require("../money.schema");
6
6
  const product_discount_price_item_schema_1 = require("./product-discount-price-item.schema");
7
7
  const product_discount_price_multiplicity_option_schema_1 = require("./product-discount-price-multiplicity-option.schema");
8
+ /**
9
+ * Две базы рядом, и это намеренно. `price` / `optionPrice` — прайс, одинаковый для всех.
10
+ * `clientPrice` / `clientOptionPrice` — цена этого клиента до скидок: у клиента с правилом
11
+ * ценообразования (от себестоимости или от прайса с наценкой) это цена по правилу, у остальных — тот
12
+ * же прайс. Скидки считаются от прайса и только у клиентов без правила ценообразования: у клиента с
13
+ * таким правилом скидок нет, списки вариантов пусты. Цену позиции без скидки берите из `clientPrice`,
14
+ * а не из `price`: иначе цена по правилу потеряется.
15
+ */
8
16
  exports.ProductDiscountPriceDataSchema = zod_1.z.object({
9
17
  productUUID: zod_1.z.string(),
10
18
  price: money_schema_1.MoneySchema,
19
+ clientPrice: money_schema_1.MoneySchema,
11
20
  priceWithBestDiscount: money_schema_1.MoneySchema.nullable(),
12
21
  multiplicityOptions: product_discount_price_multiplicity_option_schema_1.ProductDiscountPriceMultiplicityOptionSchema.array(),
13
22
  /**
@@ -7,6 +7,8 @@ const product_discount_price_item_schema_1 = require("./product-discount-price-i
7
7
  exports.ProductDiscountPriceMultiplicityOptionSchema = zod_1.z.object({
8
8
  uuid: zod_1.z.string(),
9
9
  optionPrice: money_schema_1.MoneySchema.nullable(),
10
+ /** `null` ровно тогда, когда `null` у `optionPrice`: своей цены у фасовки нет, база — `clientPrice`. */
11
+ clientOptionPrice: money_schema_1.MoneySchema.nullable(),
10
12
  optionPriceWithDiscount: money_schema_1.MoneySchema.nullable(),
11
13
  isDiscountApplicable: zod_1.z.boolean(),
12
14
  /**
@@ -34,6 +34,12 @@ exports.PriceCorrectionAnalyzeItemSchema = zod_1.z.object({
34
34
  // Разницы могут быть отрицательными — цена корректируется в обе стороны, поэтому без ограничения знака.
35
35
  priceDifferenceWithoutDiscount: money_schema_1.MoneySchema,
36
36
  priceDifferenceWithDiscount: money_schema_1.MoneySchema,
37
+ /**
38
+ * У клиента действует правило ценообразования (от себестоимости или от прайса с наценкой).
39
+ * Его цена — `newPriceWithDiscount`; «без скидок» для него означает прайс, то есть снятие наценки.
40
+ * Сотруднику стоит показать это до применения.
41
+ */
42
+ hasPricingRule: zod_1.z.boolean(),
37
43
  isSkipped: zod_1.z.boolean(),
38
44
  skipReason: error_message_schema_1.ErrorMessageSchema.optional(),
39
45
  });
@@ -0,0 +1,12 @@
1
+ import { DiscountRulesTypeEnum } from '../enum/discount-rules-type.enum';
2
+
3
+ /**
4
+ * Правила ценообразования: задают цену клиента целиком, а не уменьшают её.
5
+ *
6
+ * Цена от себестоимости или от прайса плюс наценка. Если у клиента есть такое правило, скидки к нему не
7
+ * применяются, и больше одного действующего правила ценообразования на клиента быть не может.
8
+ */
9
+ export const DISCOUNT_RULES_PRICING_TYPE_LIST: DiscountRulesTypeEnum[] = [
10
+ DiscountRulesTypeEnum.COST_PLUS_MARKUP,
11
+ DiscountRulesTypeEnum.PRICE_PLUS_MARKUP,
12
+ ];
package/constant/error.ts CHANGED
@@ -1406,6 +1406,17 @@ export const ERRORS = {
1406
1406
  message: 'Too many products for a single consignment discount operation',
1407
1407
  httpCode: 400,
1408
1408
  },
1409
+ DISCOUNT_RULES_PRICING_RULE_CONFLICT: {
1410
+ code: 'DR007',
1411
+ message: 'A client can have only one active pricing rule',
1412
+ httpCode: 409,
1413
+ },
1414
+ // Не дождались транзакционной блокировки правил ценообразования компании (lock_timeout).
1415
+ DISCOUNT_RULES_PRICING_RULE_LOCK_BUSY: {
1416
+ code: 'DR008',
1417
+ message: 'Pricing rules of this company are being changed right now, try again',
1418
+ httpCode: 409,
1419
+ },
1409
1420
  DISCOUNT_RULES_NOT_FOUND: { code: 'DR010', message: 'Discount-rules not found', httpCode: 404 },
1410
1421
 
1411
1422
  // ACTION LOG
package/constant/index.ts CHANGED
@@ -15,3 +15,4 @@ export * from './product-image-merge.constant';
15
15
  export * from './client-group-actions.constant';
16
16
  export * from './standing-order-positions.constant';
17
17
  export * from './order-external-number.constant';
18
+ export * from './discount-rules-pricing-type-list.constant';
@@ -4,10 +4,8 @@ export enum DiscountRulesModeTypeEnum {
4
4
  /**
5
5
  * Готовая цена, а не величина скидки.
6
6
  *
7
- * Значение вычисляемое: его выставляет правило `COST_PLUS_MARKUP`, посчитав цену от
8
- * себестоимости товара. Задать его снаружи нельзя — схема ввода правила
9
- * (`discountRulesModeSchema`) знает только FIXED и PERCENT, а схема выдачи
10
- * (`discountPriceOutcomeSchema`) — все три.
7
+ * Больше не отдаётся: правило `COST_PLUS_MARKUP` стало правилом ценообразования и задаёт цену
8
+ * клиента, а не вариант скидки. Значение оставлено, чтобы не ломать клиентов, которые его разбирают.
11
9
  */
12
10
  TARGET_PRICE = 'TARGET_PRICE',
13
11
  }
@@ -5,4 +5,5 @@ export enum DiscountRulesTypeEnum {
5
5
  ITEM_DISCOUNT = 'ITEM_DISCOUNT',
6
6
  DISCOUNT_PROHIBITED = 'DISCOUNT_PROHIBITED',
7
7
  COST_PLUS_MARKUP = 'COST_PLUS_MARKUP',
8
+ PRICE_PLUS_MARKUP = 'PRICE_PLUS_MARKUP',
8
9
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@floristcloud/api-lib",
3
- "version": "1.2.167",
3
+ "version": "1.2.168",
4
4
  "description": "",
5
5
  "main": "./build/index.js",
6
6
  "scripts": {
@@ -23,10 +23,9 @@ export const discountRulesModeSchema = z.discriminatedUnion('typeDiscount', [dis
23
23
  /**
24
24
  * Итог применения правила к товару — то, что уезжает клиенту в `discountDataList`.
25
25
  *
26
- * От схемы ввода отличается ровно одной веткой: TARGET_PRICE несёт уже посчитанную цену, а не
27
- * величину скидки. Так работает правило от себестоимости: считать цену на клиенте нечем — там нет
28
- * ни себестоимости, ни права её видеть. Ветка живёт только в выдаче: задать TARGET_PRICE при
29
- * создании правила нельзя, `discountRulesModeSchema` его не принимает.
26
+ * Ветка TARGET_PRICE больше не отдаётся: правило от себестоимости стало правилом ценообразования и
27
+ * задаёт цену клиента (`price`, `clientPrice`), а не вариант скидки. Ветка оставлена, чтобы не ломать
28
+ * клиентов, которые её разбирают.
30
29
  */
31
30
  export const discountPriceOutcomeSchema = z.discriminatedUnion('typeDiscount', [
32
31
  discountPercentModeSchema,
@@ -68,19 +67,33 @@ const DiscountRulesItemDiscountDataSchema = discountRulesModeSchema;
68
67
  const DiscountRulesDiscountProhibitedDataSchema = z.object({}).default({});
69
68
 
70
69
  /**
71
- * Наценка к себестоимости: цена клиента = себестоимость + наценка.
70
+ * Наценка правила ценообразования: процент или сумма на единицу.
72
71
  *
73
- * Три отличия от режима скидки, и все намеренные:
74
- * — только вверх, знака у величины нет: продажу ниже себестоимости правилом не задают;
75
- * — ноль допустим (`markupValue: 0` — продаём по себестоимости), поэтому FIXED берёт
76
- * `NonNegativeMoneySchema`, а не `PositiveMoneySchema`;
72
+ * Отличия от режима скидки намеренные:
73
+ * — только вверх, знака у величины нет;
74
+ * — ноль допустим (цена ровно равна источнику), поэтому FIXED берёт `NonNegativeMoneySchema`;
77
75
  * — у процента нет верхней границы: наценка в 150 % законна, в отличие от скидки в 150 %.
78
76
  */
77
+ const pricingMarkupPercentSchema = z.object({ typeMarkup: z.literal(DiscountRulesModeTypeEnum.PERCENT), markupValue: z.number().min(0) });
78
+ const pricingMarkupFixedSchema = z.object({ typeMarkup: z.literal(DiscountRulesModeTypeEnum.FIXED), markupValue: NonNegativeMoneySchema });
79
+
80
+ /**
81
+ * Потолок «не выше прайса» есть только у цены от себестоимости: цена от прайса с наценкой выше
82
+ * прайса по определению. Поле необязательное, и отсутствие значит разное: при создании — потолка
83
+ * нет, при правке — оставить как было. Так старая панель, которая флага не знает, не снимает потолок
84
+ * у правил, которым его проставила миграция.
85
+ */
86
+ const costPlusCapShape = { isCappedByPrice: z.boolean().optional() };
87
+
88
+ /** Цена клиента = себестоимость + наценка. */
79
89
  const DiscountRulesCostPlusMarkupDataSchema = z.discriminatedUnion('typeMarkup', [
80
- z.object({ typeMarkup: z.literal(DiscountRulesModeTypeEnum.PERCENT), markupValue: z.number().min(0) }),
81
- z.object({ typeMarkup: z.literal(DiscountRulesModeTypeEnum.FIXED), markupValue: NonNegativeMoneySchema }),
90
+ pricingMarkupPercentSchema.extend(costPlusCapShape),
91
+ pricingMarkupFixedSchema.extend(costPlusCapShape),
82
92
  ]);
83
93
 
94
+ /** Цена клиента = цена позиции (фасовки, если она выбрана) + наценка. */
95
+ const DiscountRulesPricePlusMarkupDataSchema = z.discriminatedUnion('typeMarkup', [pricingMarkupPercentSchema, pricingMarkupFixedSchema]);
96
+
84
97
  export const DiscountRulesTypeSchema = z.discriminatedUnion('type', [
85
98
  z.object({
86
99
  type: z.literal(DiscountRulesTypeEnum.PERSONAL_DISCOUNT),
@@ -106,6 +119,10 @@ export const DiscountRulesTypeSchema = z.discriminatedUnion('type', [
106
119
  type: z.literal(DiscountRulesTypeEnum.COST_PLUS_MARKUP),
107
120
  data: DiscountRulesCostPlusMarkupDataSchema,
108
121
  }),
122
+ z.object({
123
+ type: z.literal(DiscountRulesTypeEnum.PRICE_PLUS_MARKUP),
124
+ data: DiscountRulesPricePlusMarkupDataSchema,
125
+ }),
109
126
  ]);
110
127
 
111
128
  export const DiscountRulesBaseSchema = z.object({
@@ -3,9 +3,18 @@ import { MoneySchema } from '../money.schema';
3
3
  import { ProductDiscountPriceItemSchema } from './product-discount-price-item.schema';
4
4
  import { ProductDiscountPriceMultiplicityOptionSchema } from './product-discount-price-multiplicity-option.schema';
5
5
 
6
+ /**
7
+ * Две базы рядом, и это намеренно. `price` / `optionPrice` — прайс, одинаковый для всех.
8
+ * `clientPrice` / `clientOptionPrice` — цена этого клиента до скидок: у клиента с правилом
9
+ * ценообразования (от себестоимости или от прайса с наценкой) это цена по правилу, у остальных — тот
10
+ * же прайс. Скидки считаются от прайса и только у клиентов без правила ценообразования: у клиента с
11
+ * таким правилом скидок нет, списки вариантов пусты. Цену позиции без скидки берите из `clientPrice`,
12
+ * а не из `price`: иначе цена по правилу потеряется.
13
+ */
6
14
  export const ProductDiscountPriceDataSchema = z.object({
7
15
  productUUID: z.string(),
8
16
  price: MoneySchema,
17
+ clientPrice: MoneySchema,
9
18
  priceWithBestDiscount: MoneySchema.nullable(),
10
19
  multiplicityOptions: ProductDiscountPriceMultiplicityOptionSchema.array(),
11
20
  /**
@@ -5,6 +5,8 @@ import { ProductDiscountPriceItemSchema } from './product-discount-price-item.sc
5
5
  export const ProductDiscountPriceMultiplicityOptionSchema = z.object({
6
6
  uuid: z.string(),
7
7
  optionPrice: MoneySchema.nullable(),
8
+ /** `null` ровно тогда, когда `null` у `optionPrice`: своей цены у фасовки нет, база — `clientPrice`. */
9
+ clientOptionPrice: MoneySchema.nullable(),
8
10
  optionPriceWithDiscount: MoneySchema.nullable(),
9
11
  isDiscountApplicable: z.boolean(),
10
12
  /**
@@ -37,6 +37,13 @@ export const PriceCorrectionAnalyzeItemSchema = z.object({
37
37
  priceDifferenceWithoutDiscount: MoneySchema,
38
38
  priceDifferenceWithDiscount: MoneySchema,
39
39
 
40
+ /**
41
+ * У клиента действует правило ценообразования (от себестоимости или от прайса с наценкой).
42
+ * Его цена — `newPriceWithDiscount`; «без скидок» для него означает прайс, то есть снятие наценки.
43
+ * Сотруднику стоит показать это до применения.
44
+ */
45
+ hasPricingRule: z.boolean(),
46
+
40
47
  isSkipped: z.boolean(),
41
48
  skipReason: ErrorMessageSchema.optional(),
42
49
  });