@escapenavigator/utils 2.2.8 → 2.2.10

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,10 @@
1
+ import { QuestroomConfirmTypeEnum } from '@escapenavigator/types/dist/questroom/enum/questroom-confirm-type.enum';
2
+ import type { TFunction } from 'i18next';
3
+ /** The CRM preview and widget must use the same scenario, keys and interpolation. */
4
+ export declare function getBookingCompletionDefaults(t: TFunction, { confirmType, email }: {
5
+ confirmType?: QuestroomConfirmTypeEnum;
6
+ email?: string;
7
+ }): {
8
+ title: string;
9
+ subtitle: string;
10
+ };
@@ -0,0 +1,25 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getBookingCompletionDefaults = getBookingCompletionDefaults;
4
+ const questroom_confirm_type_enum_1 = require("@escapenavigator/types/dist/questroom/enum/questroom-confirm-type.enum");
5
+ /** The CRM preview and widget must use the same scenario, keys and interpolation. */
6
+ function getBookingCompletionDefaults(t, { confirmType, email = '' }) {
7
+ if (confirmType === questroom_confirm_type_enum_1.QuestroomConfirmTypeEnum.REQUEST) {
8
+ return {
9
+ title: t('Запрос отправлен', { ns: 'widgets', defaultValue: 'Request sent' }),
10
+ subtitle: t('Дождитесь подтерждения', {
11
+ ns: 'widgets',
12
+ defaultValue: 'You will receive a booking confirmation at {{email}}',
13
+ email,
14
+ }),
15
+ };
16
+ }
17
+ return {
18
+ title: t('Бронирование завершено', { ns: 'widgets', defaultValue: 'Booking completed!' }),
19
+ subtitle: t('Мы отправили всю важную информацию Вам на почту X', {
20
+ ns: 'widgets',
21
+ defaultValue: 'An email with details has been sent to {{value}}',
22
+ value: email,
23
+ }),
24
+ };
25
+ }
@@ -1,3 +1,4 @@
1
+ import { OrderTeamDto } from '@escapenavigator/types/dist/order/order-team.dto';
1
2
  import { OrderComposition, TariffCategory } from '@escapenavigator/types/dist/tariff/tariff-category';
2
3
  import { ReducedPricingConfig } from './reduced-price';
3
4
  /**
@@ -10,6 +11,7 @@ import { ReducedPricingConfig } from './reduced-price';
10
11
  * внутри всё равно считает один движок — `composition-price`.
11
12
  */
12
13
  export type GamePriceSource = ReducedPricingConfig & {
14
+ teams?: OrderTeamDto[] | null;
13
15
  price: Record<string, number>;
14
16
  players: number;
15
17
  children: number;
@@ -23,7 +25,7 @@ export type GamePriceSource = ReducedPricingConfig & {
23
25
  reducedPriceDescription?: string | null;
24
26
  childPriceDescription?: string | null;
25
27
  };
26
- export declare const getPlayersPrice: (order: GamePriceSource) => number;
28
+ export declare const getPlayersPrice: (order: GamePriceSource) => any;
27
29
  /**
28
30
  * Сколько всего можно скинуть с игры, не пробив минимальную стоимость.
29
31
  * Ноль означает «скидок на этом составе не остаётся»: так минимум защищает
@@ -28,6 +28,16 @@ const toCompositionSource = (order) => {
28
28
  const getPlayersPrice = (order) => {
29
29
  if (!order?.price)
30
30
  return 0;
31
+ if (order.teams?.length)
32
+ return order.teams.reduce((sum, team) => sum +
33
+ (0, exports.getPlayersPrice)({
34
+ ...order,
35
+ ...team,
36
+ composition: team.composition,
37
+ children: team.children || 0,
38
+ reducedPlayers: team.reducedPlayers || 0,
39
+ teams: undefined,
40
+ }), 0);
31
41
  return (0, composition_price_1.getCompositionPrice)(toCompositionSource(order));
32
42
  };
33
43
  exports.getPlayersPrice = getPlayersPrice;
@@ -36,5 +46,5 @@ exports.getPlayersPrice = getPlayersPrice;
36
46
  * Ноль означает «скидок на этом составе не остаётся»: так минимум защищает
37
47
  * выручку от процентов, а не только от льготного состава.
38
48
  */
39
- const getMaxGameDiscount = (order) => Math.max(0, (0, exports.getPlayersPrice)(order) - (0, reduced_price_1.getMinGameAmount)(order));
49
+ const getMaxGameDiscount = (order) => Math.max(0, (0, exports.getPlayersPrice)(order) - (0, reduced_price_1.getMinGameAmount)(order) * (order.teams?.length || 1));
40
50
  exports.getMaxGameDiscount = getMaxGameDiscount;
@@ -1,8 +1,9 @@
1
+ import { OrderTeamDto } from '@escapenavigator/types/dist/order/order-team.dto';
1
2
  import { PromocodeDiscountTargetEnum } from '@escapenavigator/types/dist/promocode/emun/promocode-discount-target.enum';
2
3
  import { PromocodeTypeEnum } from '@escapenavigator/types/dist/promocode/emun/promocode-type.enum';
3
4
  import { OrderComposition, TariffCategory } from '@escapenavigator/types/dist/tariff/tariff-category';
4
5
  import { ReducedPricingConfig } from './reduced-price';
5
- export declare const getPromocodeDiscount: ({ slotId, slotDiscountAmount, promocodeType, promocodeDiscount, discountTargets, upsellingsTotal, productsTotal, price, players, children, reducedPlayers, composition, categories, reducedRateMode, reducedRate, minGameAmount, }: ReducedPricingConfig & {
6
+ export declare const getPromocodeDiscount: ({ slotId, slotDiscountAmount, promocodeType, promocodeDiscount, discountTargets, upsellingsTotal, productsTotal, price, players, children, reducedPlayers, composition, teams, categories, reducedRateMode, reducedRate, minGameAmount, }: ReducedPricingConfig & {
6
7
  slotId: number;
7
8
  children?: number;
8
9
  total: number;
@@ -15,6 +16,7 @@ export declare const getPromocodeDiscount: ({ slotId, slotDiscountAmount, promoc
15
16
  reducedPlayers?: number | null;
16
17
  /** Состав по категориям. Приоритетнее полей выше. */
17
18
  composition?: OrderComposition | null;
19
+ teams?: OrderTeamDto[] | null;
18
20
  /** Категории тарифа (или их снимок на брони). */
19
21
  categories?: TariffCategory[] | null;
20
22
  /**
@@ -4,13 +4,14 @@ exports.getPromocodeDiscount = void 0;
4
4
  const promocode_discount_target_enum_1 = require("@escapenavigator/types/dist/promocode/emun/promocode-discount-target.enum");
5
5
  const promocode_type_enum_1 = require("@escapenavigator/types/dist/promocode/emun/promocode-type.enum");
6
6
  const get_players_price_1 = require("./get-players-price");
7
- const getPromocodeDiscount = ({ slotId, slotDiscountAmount = 0, promocodeType, promocodeDiscount, discountTargets, upsellingsTotal = 0, productsTotal = 0, price, players, children = 0, reducedPlayers = 0, composition, categories, reducedRateMode = null, reducedRate = 0, minGameAmount = 0, }) => {
7
+ const getPromocodeDiscount = ({ slotId, slotDiscountAmount = 0, promocodeType, promocodeDiscount, discountTargets, upsellingsTotal = 0, productsTotal = 0, price, players, children = 0, reducedPlayers = 0, composition, teams, categories, reducedRateMode = null, reducedRate = 0, minGameAmount = 0, }) => {
8
8
  const game = {
9
9
  price,
10
10
  players,
11
11
  children,
12
12
  reducedPlayers,
13
13
  composition,
14
+ teams,
14
15
  categories,
15
16
  reducedRateMode,
16
17
  reducedRate,
@@ -147,3 +147,27 @@ describe('getPromocodeDiscount / discount targets', () => {
147
147
  })).toBe(2000);
148
148
  });
149
149
  });
150
+ describe('one booking with separately priced teams', () => {
151
+ const booking = {
152
+ ...base,
153
+ price: { 2: 4000, 3: 5500, 4: 7000 },
154
+ players: 6,
155
+ total: 12000,
156
+ teams: [{ players: 2 }, { players: 2 }, { players: 2 }],
157
+ };
158
+ it('takes a percentage from the sum of teams', () => {
159
+ expect((0, get_promocode_discount_1.getPromocodeDiscount)({
160
+ ...booking,
161
+ promocodeType: promocode_type_enum_1.PromocodeTypeEnum.PERCENT_BASE_SUM,
162
+ promocodeDiscount: 1000,
163
+ })).toBe(1200);
164
+ });
165
+ it('applies a fixed discount once and preserves every team minimum', () => {
166
+ expect((0, get_promocode_discount_1.getPromocodeDiscount)({
167
+ ...booking,
168
+ minGameAmount: 3500,
169
+ promocodeType: promocode_type_enum_1.PromocodeTypeEnum.FIXED,
170
+ promocodeDiscount: 2000,
171
+ })).toBe(1500);
172
+ });
173
+ });
@@ -0,0 +1,22 @@
1
+ import type { OrderTeamDto } from '@escapenavigator/types/dist/order/order-team.dto';
2
+ import type { OrderComposition } from '@escapenavigator/types/dist/tariff/tariff-category';
3
+ export declare const aggregateTeams: (teams: OrderTeamDto[]) => {
4
+ players: number;
5
+ children: number;
6
+ reducedPlayers: number;
7
+ composition: OrderComposition;
8
+ teams: OrderTeamDto[];
9
+ };
10
+ /** Keep historical large bookings intact; only seed a single team when it fits. */
11
+ export declare const bookingTeamsFor: (order: {
12
+ teams?: OrderTeamDto[] | null;
13
+ players?: number;
14
+ children?: number;
15
+ reducedPlayers?: number;
16
+ composition?: OrderComposition;
17
+ }, questroom?: {
18
+ ticketSystem?: boolean;
19
+ resourceUnitSize?: number;
20
+ resourceUnitsTotal?: number;
21
+ playersMax?: number;
22
+ }) => OrderTeamDto[] | undefined;
@@ -0,0 +1,39 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.bookingTeamsFor = exports.aggregateTeams = void 0;
4
+ const aggregateTeams = (teams) => {
5
+ const composition = {};
6
+ for (const team of teams)
7
+ for (const [key, count] of Object.entries(team.composition || {})) {
8
+ composition[key] = (composition[key] || 0) + count;
9
+ }
10
+ return {
11
+ players: teams.reduce((n, team) => n + team.players, 0),
12
+ children: teams.reduce((n, team) => n + (team.children || 0), 0),
13
+ reducedPlayers: teams.reduce((n, team) => n + (team.reducedPlayers || 0), 0),
14
+ composition,
15
+ teams,
16
+ };
17
+ };
18
+ exports.aggregateTeams = aggregateTeams;
19
+ /** Keep historical large bookings intact; only seed a single team when it fits. */
20
+ const bookingTeamsFor = (order, questroom) => {
21
+ if (order.teams?.length)
22
+ return order.teams;
23
+ if (!questroom?.ticketSystem ||
24
+ !(questroom.resourceUnitSize > 0) ||
25
+ !(questroom.resourceUnitsTotal > 1) ||
26
+ !(questroom.playersMax > questroom.resourceUnitSize) ||
27
+ !(order.players > 0) ||
28
+ order.players + (order.children || 0) > questroom.resourceUnitSize)
29
+ return undefined;
30
+ return [
31
+ {
32
+ players: order.players,
33
+ children: order.children || 0,
34
+ reducedPlayers: order.reducedPlayers || 0,
35
+ composition: order.composition,
36
+ },
37
+ ];
38
+ };
39
+ exports.bookingTeamsFor = bookingTeamsFor;
@@ -9,6 +9,9 @@ type Props = {
9
9
  export declare const serializeSlotOrderData: (order: OrderRO & {
10
10
  workers: any[];
11
11
  hasStaffComments?: boolean;
12
+ group?: {
13
+ code: string;
14
+ };
12
15
  }) => SlotRO["orders"][number];
13
16
  export declare const serializeSlot: ({ slot, orders }: Props) => SlotRO;
14
17
  export {};
@@ -32,6 +32,8 @@ const serializeSlotOrderData = (order) => order && {
32
32
  hold: order.hold,
33
33
  expiration: order.expiration,
34
34
  groupId: order.groupId,
35
+ offerStatus: order.offerStatus,
36
+ offerCode: order.offerStatus ? order.group?.code : undefined,
35
37
  language: order.language,
36
38
  discountTotal: order.discountTotal,
37
39
  promocodeTotal: order.promocodeTotal,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@escapenavigator/utils",
3
- "version": "2.2.8",
3
+ "version": "2.2.10",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },
@@ -14,7 +14,7 @@
14
14
  "test": "jest"
15
15
  },
16
16
  "dependencies": {
17
- "@escapenavigator/types": "^2.2.8",
17
+ "@escapenavigator/types": "^2.2.10",
18
18
  "axios": "^0.21.4",
19
19
  "class-transformer": "^0.5.1",
20
20
  "class-validator": "^0.13.2",
@@ -29,5 +29,5 @@
29
29
  "ts-jest": "^29.1.1",
30
30
  "typescript": "^5.6"
31
31
  },
32
- "gitHead": "30230db507f7483ba425b0811f31d980d3b0a684"
32
+ "gitHead": "cc2b4544fd91b36fe91063f106e71e48dc0a197e"
33
33
  }