@escapenavigator/types 1.10.106 → 1.10.108
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/dist/order/order.ro.d.ts +22 -1
- package/dist/order/order.ro.js +26 -3
- package/dist/shared/export-limits.d.ts +21 -0
- package/dist/shared/export-limits.js +23 -0
- package/dist/statistics/certificates.d.ts +68 -5
- package/dist/statistics/promocodes.d.ts +9 -13
- package/dist/statistics/promocodes.js +26 -0
- package/dist/tsconfig.build.tsbuildinfo +1 -1
- package/dist/user/task/user-task.dto.d.ts +1 -1
- package/package.json +2 -2
- package/dist/user/task/user-need.dto.d.ts +0 -6
- package/dist/user/task/user-need.dto.js +0 -38
package/dist/order/order.ro.d.ts
CHANGED
|
@@ -107,7 +107,28 @@ declare class ReturnedPromocode {
|
|
|
107
107
|
discount: number;
|
|
108
108
|
}
|
|
109
109
|
export declare class OrderRO extends RO {
|
|
110
|
-
|
|
110
|
+
/**
|
|
111
|
+
* UTM-метки — flat-поля прямо на ордере. Источник истины:
|
|
112
|
+
* денормализованные колонки `OrderEntity.utm*`. Legacy-relation
|
|
113
|
+
* `OrderEntity.utm` (eager:false) и сам `OrderUtmEntity` остались
|
|
114
|
+
* только под refill, в RO/UI больше не пробрасываются.
|
|
115
|
+
*/
|
|
116
|
+
utmSource?: string | null;
|
|
117
|
+
utmMedium?: string | null;
|
|
118
|
+
utmCampaign?: string | null;
|
|
119
|
+
utmContent?: string | null;
|
|
120
|
+
utmTerm?: string | null;
|
|
121
|
+
/**
|
|
122
|
+
* Внутренний (escapenavigator) FK на `profile-marketing-email-campaign.id`.
|
|
123
|
+
* В отличие от `utmCampaign`, не редактируется юзером — используется
|
|
124
|
+
* для точной атрибуции кампаний без `LIKE`-матчинга по slug-у.
|
|
125
|
+
*/
|
|
126
|
+
enCampaignId?: number | null;
|
|
127
|
+
/**
|
|
128
|
+
* Last-click ID конкретной ссылки внутри письма (`cta_primary`,
|
|
129
|
+
* `section_${i}` и т.п.). При повторном клике перезаписывается.
|
|
130
|
+
*/
|
|
131
|
+
enLinkId?: string | null;
|
|
111
132
|
customFields: CustomFiled[];
|
|
112
133
|
otherId: string;
|
|
113
134
|
updatedAt: Date;
|
package/dist/order/order.ro.js
CHANGED
|
@@ -315,9 +315,32 @@ class OrderRO extends ro_class_1.RO {
|
|
|
315
315
|
exports.OrderRO = OrderRO;
|
|
316
316
|
__decorate([
|
|
317
317
|
(0, class_transformer_1.Expose)(),
|
|
318
|
-
(
|
|
319
|
-
|
|
320
|
-
|
|
318
|
+
__metadata("design:type", String)
|
|
319
|
+
], OrderRO.prototype, "utmSource", void 0);
|
|
320
|
+
__decorate([
|
|
321
|
+
(0, class_transformer_1.Expose)(),
|
|
322
|
+
__metadata("design:type", String)
|
|
323
|
+
], OrderRO.prototype, "utmMedium", void 0);
|
|
324
|
+
__decorate([
|
|
325
|
+
(0, class_transformer_1.Expose)(),
|
|
326
|
+
__metadata("design:type", String)
|
|
327
|
+
], OrderRO.prototype, "utmCampaign", void 0);
|
|
328
|
+
__decorate([
|
|
329
|
+
(0, class_transformer_1.Expose)(),
|
|
330
|
+
__metadata("design:type", String)
|
|
331
|
+
], OrderRO.prototype, "utmContent", void 0);
|
|
332
|
+
__decorate([
|
|
333
|
+
(0, class_transformer_1.Expose)(),
|
|
334
|
+
__metadata("design:type", String)
|
|
335
|
+
], OrderRO.prototype, "utmTerm", void 0);
|
|
336
|
+
__decorate([
|
|
337
|
+
(0, class_transformer_1.Expose)(),
|
|
338
|
+
__metadata("design:type", Number)
|
|
339
|
+
], OrderRO.prototype, "enCampaignId", void 0);
|
|
340
|
+
__decorate([
|
|
341
|
+
(0, class_transformer_1.Expose)(),
|
|
342
|
+
__metadata("design:type", String)
|
|
343
|
+
], OrderRO.prototype, "enLinkId", void 0);
|
|
321
344
|
__decorate([
|
|
322
345
|
(0, class_transformer_1.Expose)(),
|
|
323
346
|
(0, class_transformer_1.Type)(() => CustomFiled),
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Единые лимиты на размер XLSX-выгрузок. Импортится и бэком
|
|
3
|
+
* (`*.Service.EXPORT_LIMIT` + count-precheck в контроллере), и
|
|
4
|
+
* фронтом (`ExportAndCount` дизейблит кнопку, если `count > limit`).
|
|
5
|
+
*
|
|
6
|
+
* Зачем общая константа: иначе магическое `5000` живёт в двух местах,
|
|
7
|
+
* и при апдейте бэка фронт продолжит разрешать клик на 5001-й строке,
|
|
8
|
+
* валя пользователя в 400 `EXPORT_TOO_LARGE`.
|
|
9
|
+
*
|
|
10
|
+
* Реализованные на бэке потолки:
|
|
11
|
+
* - `OrderService.EXPORT_LIMIT` — `GET /orders/export`
|
|
12
|
+
* - `ClientService.EXPORT_LIMIT` — `GET /clients/export`
|
|
13
|
+
*
|
|
14
|
+
* Не покрыты лимитом (TODO): `transactions/export`, `users/sessions/export`.
|
|
15
|
+
* Когда добавится — взять отсюда же.
|
|
16
|
+
*/
|
|
17
|
+
export declare const EXPORT_LIMITS: {
|
|
18
|
+
readonly ORDERS: 5000;
|
|
19
|
+
readonly CLIENTS: 5000;
|
|
20
|
+
};
|
|
21
|
+
export type ExportLimitKey = keyof typeof EXPORT_LIMITS;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.EXPORT_LIMITS = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* Единые лимиты на размер XLSX-выгрузок. Импортится и бэком
|
|
6
|
+
* (`*.Service.EXPORT_LIMIT` + count-precheck в контроллере), и
|
|
7
|
+
* фронтом (`ExportAndCount` дизейблит кнопку, если `count > limit`).
|
|
8
|
+
*
|
|
9
|
+
* Зачем общая константа: иначе магическое `5000` живёт в двух местах,
|
|
10
|
+
* и при апдейте бэка фронт продолжит разрешать клик на 5001-й строке,
|
|
11
|
+
* валя пользователя в 400 `EXPORT_TOO_LARGE`.
|
|
12
|
+
*
|
|
13
|
+
* Реализованные на бэке потолки:
|
|
14
|
+
* - `OrderService.EXPORT_LIMIT` — `GET /orders/export`
|
|
15
|
+
* - `ClientService.EXPORT_LIMIT` — `GET /clients/export`
|
|
16
|
+
*
|
|
17
|
+
* Не покрыты лимитом (TODO): `transactions/export`, `users/sessions/export`.
|
|
18
|
+
* Когда добавится — взять отсюда же.
|
|
19
|
+
*/
|
|
20
|
+
exports.EXPORT_LIMITS = {
|
|
21
|
+
ORDERS: 5000,
|
|
22
|
+
CLIENTS: 5000,
|
|
23
|
+
};
|
|
@@ -2,8 +2,12 @@
|
|
|
2
2
|
* Сводный отчёт по продажам сертификатов за выбранный период.
|
|
3
3
|
*
|
|
4
4
|
* Все денежные суммы — в минимальных единицах валюты (копейки/центы).
|
|
5
|
-
*
|
|
6
|
-
*
|
|
5
|
+
*
|
|
6
|
+
* Когорта периода = `code != NOT_GENERATED_CODE` + `annul = false` +
|
|
7
|
+
* `paidAt ∈ [start, end)`. ВСЕ агрегаты overview (включая остаток
|
|
8
|
+
* номиналов, количество полностью использованных и аннулированных)
|
|
9
|
+
* считаются по одной и той же когорте — это снимает прежний разнобой,
|
|
10
|
+
* когда `outstandingBalance` суммировался по всей истории профиля.
|
|
7
11
|
*
|
|
8
12
|
* Семантика финансовых полей:
|
|
9
13
|
* - gross — стоимость по прайсу (SUM(total)). Не выручка.
|
|
@@ -11,13 +15,19 @@
|
|
|
11
15
|
* - discount — сумма ручных скидок (SUM(discountTotal)).
|
|
12
16
|
* - promocode — сумма промокодов (SUM(promocodeTotal)).
|
|
13
17
|
* - refunded — реально возвращённые клиенту деньги (SUM(refundedAmount)).
|
|
18
|
+
* - nominalSold — суммарный номинал когорты (SUM(nominal)).
|
|
19
|
+
* - nominalRedeemed — сколько из этого номинала уже потрачено в заказах
|
|
20
|
+
* (SUM(usedAmount)).
|
|
21
|
+
* - outstandingBalance — остаток номиналов когорты у ещё не закрытых
|
|
22
|
+
* сертификатов (SUM(balance) WHERE used = false).
|
|
23
|
+
* - redemptionRate — целое число процентов, nominalRedeemed / nominalSold.
|
|
14
24
|
*/
|
|
15
25
|
export type CertificatesOverview = {
|
|
16
26
|
/** Сколько сертификатов выписано (paid) за период. */
|
|
17
27
|
soldCount: number;
|
|
18
|
-
/** Сколько аннулировано
|
|
28
|
+
/** Сколько из когорты уже аннулировано (annul = true к моменту запроса). */
|
|
19
29
|
annulledCount: number;
|
|
20
|
-
/** Сколько
|
|
30
|
+
/** Сколько из когорты уже полностью погашено (fullyUsedAt IS NOT NULL). */
|
|
21
31
|
fullyUsedCount: number;
|
|
22
32
|
/** Сколько ушло в подарок (isGift = true) среди soldCount. */
|
|
23
33
|
giftCount: number;
|
|
@@ -28,8 +38,14 @@ export type CertificatesOverview = {
|
|
|
28
38
|
refunded: number;
|
|
29
39
|
/** Средний чек по cash: cash / soldCount, 0 если нет продаж. */
|
|
30
40
|
avgCheck: number;
|
|
31
|
-
/**
|
|
41
|
+
/** Суммарный номинал по когорте: SUM(nominal). */
|
|
42
|
+
nominalSold: number;
|
|
43
|
+
/** Сколько номинала уже потрачено в заказах: SUM(usedAmount). */
|
|
44
|
+
nominalRedeemed: number;
|
|
45
|
+
/** Остаток номиналов когорты у не закрытых сертификатов: SUM(balance) WHERE used = false. */
|
|
32
46
|
outstandingBalance: number;
|
|
47
|
+
/** Доля погашения номинала, целое число процентов (0..100). */
|
|
48
|
+
redemptionRate: number;
|
|
33
49
|
};
|
|
34
50
|
export type CertificatesDynamicRow = {
|
|
35
51
|
period: string;
|
|
@@ -66,6 +82,52 @@ export type CertificatesByUtmRow = {
|
|
|
66
82
|
soldCount: number;
|
|
67
83
|
cash: number;
|
|
68
84
|
};
|
|
85
|
+
/**
|
|
86
|
+
* Бакеты «через сколько дней после покупки сертификат…»
|
|
87
|
+
* - d0 — в день покупки
|
|
88
|
+
* - d1_7 — 1..7 дней
|
|
89
|
+
* - d8_30 — 8..30 дней
|
|
90
|
+
* - d31_90 — 31..90 дней
|
|
91
|
+
* - d91_180 — 91..180 дней
|
|
92
|
+
* - d181_365 — 181..365 дней
|
|
93
|
+
* - d_over_365 — больше года
|
|
94
|
+
* - not_yet — ещё не активирован / не погашен полностью
|
|
95
|
+
*/
|
|
96
|
+
export type CertificatesVelocityBucket = 'd0' | 'd1_7' | 'd8_30' | 'd31_90' | 'd91_180' | 'd181_365' | 'd_over_365' | 'not_yet';
|
|
97
|
+
export type CertificatesVelocityBucketRow = {
|
|
98
|
+
bucket: CertificatesVelocityBucket;
|
|
99
|
+
/** Сколько сертификатов когорты попало в бакет. */
|
|
100
|
+
count: number;
|
|
101
|
+
};
|
|
102
|
+
/**
|
|
103
|
+
* Скорость использования сертификатов когорты периода.
|
|
104
|
+
*
|
|
105
|
+
* Когорта = `code != NOT_GENERATED_CODE` + `annul = false` +
|
|
106
|
+
* `paidAt ∈ [start, end)`. Источники дат — `firstUsedAt`, `fullyUsedAt`,
|
|
107
|
+
* `expireDate`. Никаких джоинов — считаем по плоской `certificatesales`.
|
|
108
|
+
*/
|
|
109
|
+
export type CertificatesRedemptionVelocity = {
|
|
110
|
+
/** Распределение времени до первого применения. */
|
|
111
|
+
firstUseBuckets: CertificatesVelocityBucketRow[];
|
|
112
|
+
/** Распределение времени до полного погашения. */
|
|
113
|
+
fullRedeemBuckets: CertificatesVelocityBucketRow[];
|
|
114
|
+
/** Медианное число дней от покупки до первого применения. */
|
|
115
|
+
medianDaysToFirstUse: number | null;
|
|
116
|
+
/** Медианное число дней от покупки до полного погашения. */
|
|
117
|
+
medianDaysToFullRedeem: number | null;
|
|
118
|
+
/** Активировано в течение 7 дней после покупки. */
|
|
119
|
+
activatedWithin7d: number;
|
|
120
|
+
/** Активировано в течение 30 дней после покупки. */
|
|
121
|
+
activatedWithin30d: number;
|
|
122
|
+
/** Полностью погашено в течение 30 дней после покупки. */
|
|
123
|
+
fullyRedeemedWithin30d: number;
|
|
124
|
+
/** Полностью погашено в течение 90 дней после покупки. */
|
|
125
|
+
fullyRedeemedWithin90d: number;
|
|
126
|
+
/** «Спящие» — куплены больше 90 дней назад и ни разу не применены. */
|
|
127
|
+
dormantOver90d: number;
|
|
128
|
+
/** Сгорели (expireDate < сегодня) и не были полностью использованы. */
|
|
129
|
+
expiredUnused: number;
|
|
130
|
+
};
|
|
69
131
|
export type CertificatesReportRO = {
|
|
70
132
|
overview: CertificatesOverview;
|
|
71
133
|
dynamic: CertificatesDynamicRow[];
|
|
@@ -73,4 +135,5 @@ export type CertificatesReportRO = {
|
|
|
73
135
|
bySource: CertificatesBySourceRow[];
|
|
74
136
|
byDelivery: CertificatesByDeliveryRow[];
|
|
75
137
|
byUtm: CertificatesByUtmRow[];
|
|
138
|
+
redemption: CertificatesRedemptionVelocity;
|
|
76
139
|
};
|
|
@@ -1,4 +1,13 @@
|
|
|
1
1
|
import { PromocodeKindEnum } from '../promocode/emun/promocode-kind.enum';
|
|
2
|
+
import { DashboardQueryDto } from './pnl';
|
|
3
|
+
/**
|
|
4
|
+
* Запрос отчёта по промокодам. Расширяет общий `DashboardQueryDto`
|
|
5
|
+
* опциональным фильтром по типу промокода (`kind`). При отсутствии
|
|
6
|
+
* `kind` бекенд считает по всем типам как раньше.
|
|
7
|
+
*/
|
|
8
|
+
export declare class PromocodesQueryDto extends DashboardQueryDto {
|
|
9
|
+
kind?: PromocodeKindEnum;
|
|
10
|
+
}
|
|
2
11
|
/**
|
|
3
12
|
* Богатый отчёт по промокодам за выбранный период.
|
|
4
13
|
*
|
|
@@ -37,22 +46,9 @@ export type PromocodesTopRow = {
|
|
|
37
46
|
applications: number;
|
|
38
47
|
discountAmount: number;
|
|
39
48
|
};
|
|
40
|
-
export type PromocodesTimelineRow = {
|
|
41
|
-
period: string;
|
|
42
|
-
created: number;
|
|
43
|
-
applied: number;
|
|
44
|
-
discountAmount: number;
|
|
45
|
-
};
|
|
46
|
-
export type PromocodesByUtmRow = {
|
|
47
|
-
utmCampaign: string;
|
|
48
|
-
applications: number;
|
|
49
|
-
discountAmount: number;
|
|
50
|
-
};
|
|
51
49
|
export type PromocodesReportRO = {
|
|
52
50
|
kpi: PromocodesKpi;
|
|
53
51
|
byKind: PromocodesByKindRow[];
|
|
54
52
|
byChannel: PromocodesByChannelRow[];
|
|
55
53
|
topPromocodes: PromocodesTopRow[];
|
|
56
|
-
timeline: PromocodesTimelineRow[];
|
|
57
|
-
topUtmCampaigns: PromocodesByUtmRow[];
|
|
58
54
|
};
|
|
@@ -1,2 +1,28 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
3
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
4
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
5
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
6
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
7
|
+
};
|
|
8
|
+
var __metadata = (this && this.__metadata) || function (k, v) {
|
|
9
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
10
|
+
};
|
|
2
11
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.PromocodesQueryDto = void 0;
|
|
13
|
+
const class_validator_1 = require("class-validator");
|
|
14
|
+
const promocode_kind_enum_1 = require("../promocode/emun/promocode-kind.enum");
|
|
15
|
+
const pnl_1 = require("./pnl");
|
|
16
|
+
/**
|
|
17
|
+
* Запрос отчёта по промокодам. Расширяет общий `DashboardQueryDto`
|
|
18
|
+
* опциональным фильтром по типу промокода (`kind`). При отсутствии
|
|
19
|
+
* `kind` бекенд считает по всем типам как раньше.
|
|
20
|
+
*/
|
|
21
|
+
class PromocodesQueryDto extends pnl_1.DashboardQueryDto {
|
|
22
|
+
}
|
|
23
|
+
exports.PromocodesQueryDto = PromocodesQueryDto;
|
|
24
|
+
__decorate([
|
|
25
|
+
(0, class_validator_1.IsOptional)(),
|
|
26
|
+
(0, class_validator_1.IsEnum)(promocode_kind_enum_1.PromocodeKindEnum),
|
|
27
|
+
__metadata("design:type", String)
|
|
28
|
+
], PromocodesQueryDto.prototype, "kind", void 0);
|