@mamindom/contracts 1.0.213 → 1.0.216

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.
@@ -6,4 +6,9 @@ export interface OtpRequestedEvent {
6
6
  userId?: string;
7
7
  identifier?: string;
8
8
  type?: string;
9
+ /**
10
+ * Мова покупця (`UK` | `RU`) — нею йдуть листи й SMS. Порожньо — `UK`.
11
+ * Необов'язкове: старі продюсери поле не шлють.
12
+ */
13
+ locale?: 'UK' | 'RU';
9
14
  }
@@ -15,4 +15,9 @@ export interface OrderCancelledEvent {
15
15
  email: string;
16
16
  phone: string;
17
17
  };
18
+ /**
19
+ * Мова покупця (`UK` | `RU`) — нею йдуть листи й SMS. Порожньо — `UK`.
20
+ * Необов'язкове: старі продюсери поле не шлють.
21
+ */
22
+ locale?: 'UK' | 'RU';
18
23
  }
@@ -15,6 +15,11 @@ export interface OrderCreatedEvent {
15
15
  sku: string;
16
16
  quantity: number;
17
17
  price: string;
18
+ /** Знімок назви, фото й підсумку рядка — для таблиці товарів у листі. */
19
+ name?: string;
20
+ imageUrl?: string;
21
+ size?: string;
22
+ lineTotal?: string;
18
23
  }>;
19
24
  delivery: {
20
25
  method: string;
@@ -34,4 +39,9 @@ export interface OrderCreatedEvent {
34
39
  email: string;
35
40
  };
36
41
  createdAt: number;
42
+ /**
43
+ * Мова покупця (`UK` | `RU`) — нею йдуть листи й SMS. Порожньо — `UK`.
44
+ * Необов'язкове: старі продюсери поле не шлють.
45
+ */
46
+ locale?: 'UK' | 'RU';
37
47
  }
@@ -22,4 +22,9 @@ export interface OrderSurchargeRequestedEvent {
22
22
  email: string;
23
23
  phone: string;
24
24
  };
25
+ /**
26
+ * Мова покупця (`UK` | `RU`) — нею йдуть листи й SMS. Порожньо — `UK`.
27
+ * Необов'язкове: старі продюсери поле не шлють.
28
+ */
29
+ locale?: 'UK' | 'RU';
25
30
  }
@@ -17,4 +17,9 @@ export interface OrderStatusChangedEvent {
17
17
  };
18
18
  trackingNumber?: string;
19
19
  trackingUrl?: string;
20
+ /**
21
+ * Мова покупця (`UK` | `RU`) — нею йдуть листи й SMS. Порожньо — `UK`.
22
+ * Необов'язкове: старі продюсери поле не шлють.
23
+ */
24
+ locale?: 'UK' | 'RU';
20
25
  }
@@ -9,6 +9,8 @@ export interface LogoutResponse {
9
9
  export interface SendOtpRequest {
10
10
  identifier: string;
11
11
  type: string;
12
+ /** Мова сайту (uk | ru) — нею прийде лист/SMS із кодом. */
13
+ locale?: string | undefined;
12
14
  }
13
15
  export interface SendOtpResponse {
14
16
  ok: boolean;
@@ -34,6 +36,7 @@ export interface RegisterRequest {
34
36
  export interface RequestPasswordResetRequest {
35
37
  identifier: string;
36
38
  type: string;
39
+ locale?: string | undefined;
37
40
  }
38
41
  export interface RequestPasswordResetResponse {
39
42
  ok: boolean;
@@ -1,7 +1,9 @@
1
1
  import { Observable } from "rxjs";
2
2
  export declare const protobufPackage = "promo.v1";
3
3
  export interface BonusSettingsResponse {
4
- earnRate: number;
4
+ earnStepUah: number;
5
+ earnPerStepUah: number;
6
+ earnMinPriceUah: number;
5
7
  redeemRate: number;
6
8
  minOrderForEarn: number;
7
9
  maxRedeemShare: number;
@@ -10,7 +12,9 @@ export interface BonusSettingsResponse {
10
12
  export interface GetBonusSettingsRequest {
11
13
  }
12
14
  export interface UpdateBonusSettingsRequest {
13
- earnRate?: number | undefined;
15
+ earnStepUah?: number | undefined;
16
+ earnPerStepUah?: number | undefined;
17
+ earnMinPriceUah?: number | undefined;
14
18
  redeemRate?: number | undefined;
15
19
  minOrderForEarn?: number | undefined;
16
20
  maxRedeemShare?: number | undefined;
@@ -49,6 +49,10 @@ export declare enum NotificationStatus {
49
49
  FAILED = 3,
50
50
  SIMULATED = 4,
51
51
  SUPPRESSED = 5,
52
+ /** DUPLICATE - Не надіслано: таке саме повідомлення вже пішло раніше (повтор події). */
53
+ DUPLICATE = 6,
54
+ /** DISABLED - Не надіслано: адмін вимкнув шаблон цього листа. */
55
+ DISABLED = 7,
52
56
  UNRECOGNIZED = -1
53
57
  }
54
58
  export declare enum TelegramTopic {
@@ -276,6 +280,13 @@ export interface BrandingProfile {
276
280
  resolvedBrandUrl: string;
277
281
  resolvedSupportEmail: string;
278
282
  headerHtml: string;
283
+ /**
284
+ * Оформлення листа за замовчуванням (JSON EmailTheme) і глобальні шапка й
285
+ * підвал блоками (JSON EmailBlock[]). Порожній рядок — «як у коді».
286
+ */
287
+ themeJson: string;
288
+ headerBlocksJson: string;
289
+ footerBlocksJson: string;
279
290
  }
280
291
  export interface UpdateBrandingRequest {
281
292
  logoUrl?: string | undefined;
@@ -285,6 +296,9 @@ export interface UpdateBrandingRequest {
285
296
  footerHtml?: string | undefined;
286
297
  actorId: string;
287
298
  headerHtml?: string | undefined;
299
+ themeJson?: string | undefined;
300
+ headerBlocksJson?: string | undefined;
301
+ footerBlocksJson?: string | undefined;
288
302
  }
289
303
  export interface NotificationTemplate {
290
304
  id: string;
@@ -377,15 +391,69 @@ export interface RenderPreviewRequest {
377
391
  variablesJson: string;
378
392
  subject?: string | undefined;
379
393
  brandingJson?: string | undefined;
394
+ /**
395
+ * Блоковий лист (JSON EmailDocument). Якщо заданий — рендеримо його, а
396
+ * body_html лише запасний шлях, як і при відправці.
397
+ */
398
+ contentJson?: string | undefined;
399
+ /** Категорія впливає на лист: у масових є посилання «Відписатися». */
400
+ category?: NotificationCategory | undefined;
401
+ locale?: NotificationLocale | undefined;
402
+ /** Ключ листа — щоб попередити про змінні, яких цей лист не отримає. */
403
+ templateKey?: string | undefined;
380
404
  }
381
405
  export interface RenderPreviewResponse {
382
406
  html: string;
383
407
  subject: string;
408
+ /** Плейн-текстова версія — саме та, що піде в листі. */
409
+ text: string;
410
+ /** Попередження (невідома змінна, порожній alt, зламана розмітка тощо). */
411
+ warnings: string[];
384
412
  }
385
413
  export interface SendTestRequest {
386
414
  templateId: string;
387
415
  recipient: string;
388
416
  variablesJson: string;
417
+ /**
418
+ * Незбережений стан редактора. Задані поля замінюють збережені — тестовий
419
+ * лист показує те, що адмін бачить зараз, а не останнє збереження.
420
+ */
421
+ subject?: string | undefined;
422
+ contentJson?: string | undefined;
423
+ bodyHtml?: string | undefined;
424
+ bodyText?: string | undefined;
425
+ }
426
+ export interface GetTemplateVariablesRequest {
427
+ key: string;
428
+ }
429
+ export interface TemplateVariable {
430
+ path: string;
431
+ label: string;
432
+ example: string;
433
+ isList: boolean;
434
+ }
435
+ export interface TemplateVariablesResponse {
436
+ /** event — лист шле система за подією; campaign — лист розсилки. */
437
+ source: string;
438
+ trigger: string;
439
+ variables: TemplateVariable[];
440
+ /** Приклад значень (JSON) — для попереднього перегляду. */
441
+ sampleJson: string;
442
+ }
443
+ export interface DuplicateTemplateRequest {
444
+ id: string;
445
+ newKey: string;
446
+ locale?: NotificationLocale | undefined;
447
+ title?: string | undefined;
448
+ actorId?: string | undefined;
449
+ }
450
+ export interface DeleteTemplateRequest {
451
+ id: string;
452
+ actorId?: string | undefined;
453
+ }
454
+ export interface DeleteTemplateResponse {
455
+ ok: boolean;
456
+ errorMessage: string;
389
457
  }
390
458
  export interface SendTestResponse {
391
459
  ok: boolean;
@@ -476,6 +544,12 @@ export interface NotificationTemplateServiceClient {
476
544
  restoreVersion(request: RestoreVersionRequest): Observable<TemplateResponse>;
477
545
  renderPreview(request: RenderPreviewRequest): Observable<RenderPreviewResponse>;
478
546
  sendTest(request: SendTestRequest): Observable<SendTestResponse>;
547
+ /** Які змінні реально передає система в шаблон із цим ключем + приклад значень. */
548
+ getTemplateVariables(request: GetTemplateVariablesRequest): Observable<TemplateVariablesResponse>;
549
+ /** Копія шаблону під новим ключем і/або мовою (з тілом, блоками й темою). */
550
+ duplicateTemplate(request: DuplicateTemplateRequest): Observable<TemplateResponse>;
551
+ /** Видалення — лише для листів, створених адміном; системні ключі не видаляються. */
552
+ deleteTemplate(request: DeleteTemplateRequest): Observable<DeleteTemplateResponse>;
479
553
  sendToCustomer(request: SendToCustomerRequest): Observable<SendToCustomerResponse>;
480
554
  }
481
555
  export interface NotificationTemplateServiceController {
@@ -488,6 +562,12 @@ export interface NotificationTemplateServiceController {
488
562
  restoreVersion(request: RestoreVersionRequest): Promise<TemplateResponse> | Observable<TemplateResponse> | TemplateResponse;
489
563
  renderPreview(request: RenderPreviewRequest): Promise<RenderPreviewResponse> | Observable<RenderPreviewResponse> | RenderPreviewResponse;
490
564
  sendTest(request: SendTestRequest): Promise<SendTestResponse> | Observable<SendTestResponse> | SendTestResponse;
565
+ /** Які змінні реально передає система в шаблон із цим ключем + приклад значень. */
566
+ getTemplateVariables(request: GetTemplateVariablesRequest): Promise<TemplateVariablesResponse> | Observable<TemplateVariablesResponse> | TemplateVariablesResponse;
567
+ /** Копія шаблону під новим ключем і/або мовою (з тілом, блоками й темою). */
568
+ duplicateTemplate(request: DuplicateTemplateRequest): Promise<TemplateResponse> | Observable<TemplateResponse> | TemplateResponse;
569
+ /** Видалення — лише для листів, створених адміном; системні ключі не видаляються. */
570
+ deleteTemplate(request: DeleteTemplateRequest): Promise<DeleteTemplateResponse> | Observable<DeleteTemplateResponse> | DeleteTemplateResponse;
491
571
  sendToCustomer(request: SendToCustomerRequest): Promise<SendToCustomerResponse> | Observable<SendToCustomerResponse> | SendToCustomerResponse;
492
572
  }
493
573
  export declare function NotificationTemplateServiceControllerMethods(): (constructor: Function) => void;
@@ -71,6 +71,10 @@ var NotificationStatus;
71
71
  NotificationStatus[NotificationStatus["FAILED"] = 3] = "FAILED";
72
72
  NotificationStatus[NotificationStatus["SIMULATED"] = 4] = "SIMULATED";
73
73
  NotificationStatus[NotificationStatus["SUPPRESSED"] = 5] = "SUPPRESSED";
74
+ /** DUPLICATE - Не надіслано: таке саме повідомлення вже пішло раніше (повтор події). */
75
+ NotificationStatus[NotificationStatus["DUPLICATE"] = 6] = "DUPLICATE";
76
+ /** DISABLED - Не надіслано: адмін вимкнув шаблон цього листа. */
77
+ NotificationStatus[NotificationStatus["DISABLED"] = 7] = "DISABLED";
74
78
  NotificationStatus[NotificationStatus["UNRECOGNIZED"] = -1] = "UNRECOGNIZED";
75
79
  })(NotificationStatus || (exports.NotificationStatus = NotificationStatus = {}));
76
80
  var TelegramTopic;
@@ -100,6 +104,9 @@ function NotificationTemplateServiceControllerMethods() {
100
104
  "restoreVersion",
101
105
  "renderPreview",
102
106
  "sendTest",
107
+ "getTemplateVariables",
108
+ "duplicateTemplate",
109
+ "deleteTemplate",
103
110
  "sendToCustomer",
104
111
  ];
105
112
  for (const method of grpcMethods) {
@@ -198,6 +198,8 @@ export interface Order {
198
198
  saleRecordedAt: number;
199
199
  oneCOrderNumber: string;
200
200
  oneCOrderDate: string;
201
+ /** Подію purchase уже відправлено в GA4 (дедуплікація, ТЗ GA4 розділ 8). */
202
+ analyticsSent: boolean;
201
203
  }
202
204
  export interface CreateOrderRequest {
203
205
  idempotencyKey: string;
@@ -205,6 +207,8 @@ export interface CreateOrderRequest {
205
207
  guestId: string;
206
208
  source: string;
207
209
  cartId: string;
210
+ /** Мова сайту на момент оформлення (uk | ru) — нею йдуть листи й SMS про замовлення. */
211
+ locale?: string | undefined;
208
212
  }
209
213
  export interface CreateManualOrderRequest {
210
214
  idempotencyKey: string;
@@ -217,6 +221,8 @@ export interface CreateManualOrderRequest {
217
221
  payment: OrderPayment | undefined;
218
222
  promoCode: string;
219
223
  comment: string;
224
+ /** Мова листів покупцю (uk | ru); порожньо — українська. */
225
+ locale?: string | undefined;
220
226
  }
221
227
  export interface OrderItemInput {
222
228
  productId: string;
@@ -282,6 +288,15 @@ export interface SetCrmOrderIdRequest {
282
288
  id: string;
283
289
  crmOrderId: string;
284
290
  }
291
+ export interface MarkAnalyticsSentRequest {
292
+ id: string;
293
+ }
294
+ export interface MarkAnalyticsSentResponse {
295
+ ok: boolean;
296
+ /** Саме цей виклик поставив прапорець. false — його вже було поставлено раніше. */
297
+ claimed: boolean;
298
+ errorMessage: string;
299
+ }
285
300
  export interface MoneyAdjustment {
286
301
  id: string;
287
302
  orderId: string;
@@ -501,6 +516,11 @@ export interface OrderServiceClient {
501
516
  setTrackingNumber(request: SetTrackingNumberRequest): Observable<OrderResponse>;
502
517
  applyRecalculation(request: ApplyRecalculationRequest): Observable<OrderResponse>;
503
518
  setCrmOrderId(request: SetCrmOrderIdRequest): Observable<OrderResponse>;
519
+ /**
520
+ * GA4 (ТЗ KIPLAR, розділ 8): покупку в аналітику відправлено. Ідемпотентно:
521
+ * `claimed` = true лише для того виклику, що перевів прапорець false → true.
522
+ */
523
+ markAnalyticsSent(request: MarkAnalyticsSentRequest): Observable<MarkAnalyticsSentResponse>;
504
524
  setOneCOrderRef(request: SetOneCOrderRefRequest): Observable<OrderResponse>;
505
525
  applyOneCStatus(request: ApplyOneCStatusRequest): Observable<OrderResponse>;
506
526
  /** Врегулювання грошей після перерахунку (доплата / повернення). */
@@ -548,6 +568,11 @@ export interface OrderServiceController {
548
568
  setTrackingNumber(request: SetTrackingNumberRequest): Promise<OrderResponse> | Observable<OrderResponse> | OrderResponse;
549
569
  applyRecalculation(request: ApplyRecalculationRequest): Promise<OrderResponse> | Observable<OrderResponse> | OrderResponse;
550
570
  setCrmOrderId(request: SetCrmOrderIdRequest): Promise<OrderResponse> | Observable<OrderResponse> | OrderResponse;
571
+ /**
572
+ * GA4 (ТЗ KIPLAR, розділ 8): покупку в аналітику відправлено. Ідемпотентно:
573
+ * `claimed` = true лише для того виклику, що перевів прапорець false → true.
574
+ */
575
+ markAnalyticsSent(request: MarkAnalyticsSentRequest): Promise<MarkAnalyticsSentResponse> | Observable<MarkAnalyticsSentResponse> | MarkAnalyticsSentResponse;
551
576
  setOneCOrderRef(request: SetOneCOrderRefRequest): Promise<OrderResponse> | Observable<OrderResponse> | OrderResponse;
552
577
  applyOneCStatus(request: ApplyOneCStatusRequest): Promise<OrderResponse> | Observable<OrderResponse> | OrderResponse;
553
578
  /** Врегулювання грошей після перерахунку (доплата / повернення). */
package/dist/gen/order.js CHANGED
@@ -33,6 +33,7 @@ function OrderServiceControllerMethods() {
33
33
  "setTrackingNumber",
34
34
  "applyRecalculation",
35
35
  "setCrmOrderId",
36
+ "markAnalyticsSent",
36
37
  "setOneCOrderRef",
37
38
  "applyOneCStatus",
38
39
  "listMoneyAdjustments",
@@ -25,6 +25,8 @@ message LogoutResponse {
25
25
  message SendOtpRequest {
26
26
  string identifier = 1;
27
27
  string type = 2;
28
+ // Мова сайту (uk | ru) — нею прийде лист/SMS із кодом.
29
+ optional string locale = 3;
28
30
  }
29
31
 
30
32
  message SendOtpResponse {
@@ -55,6 +57,7 @@ message RegisterRequest {
55
57
  message RequestPasswordResetRequest {
56
58
  string identifier = 1;
57
59
  string type = 2;
60
+ optional string locale = 3;
58
61
  }
59
62
 
60
63
  message RequestPasswordResetResponse {
@@ -8,7 +8,19 @@ service BonusSettingsService {
8
8
  }
9
9
 
10
10
  message BonusSettingsResponse {
11
- double earn_rate = 1;
11
+ // Формула нарахування (п.17 переліку): кожні `earn_step_uah` гривень ціни
12
+ // товару дають `earn_per_step_uah` гривень бонусів, і лише для товарів не
13
+ // дешевших за `earn_min_price_uah`. Ціна береться ПІСЛЯ знижки.
14
+ //
15
+ // Поле 1 (`earn_rate`, відсоткова ставка) прибране: формула не відсоткова,
16
+ // а поле показувало 2% і тим вводило в оману. Номер зарезервовано, щоб його
17
+ // ніколи не перевикористали під інше значення.
18
+ reserved 1;
19
+ reserved "earn_rate";
20
+
21
+ double earn_step_uah = 6;
22
+ double earn_per_step_uah = 7;
23
+ double earn_min_price_uah = 8;
12
24
 
13
25
  double redeem_rate = 2;
14
26
 
@@ -22,7 +34,12 @@ message BonusSettingsResponse {
22
34
  message GetBonusSettingsRequest {}
23
35
 
24
36
  message UpdateBonusSettingsRequest {
25
- optional double earn_rate = 1;
37
+ reserved 1;
38
+ reserved "earn_rate";
39
+
40
+ optional double earn_step_uah = 6;
41
+ optional double earn_per_step_uah = 7;
42
+ optional double earn_min_price_uah = 8;
26
43
  optional double redeem_rate = 2;
27
44
  optional double min_order_for_earn = 3;
28
45
  optional double max_redeem_share = 4;
@@ -13,6 +13,13 @@ service NotificationTemplateService {
13
13
  rpc RenderPreview(RenderPreviewRequest) returns (RenderPreviewResponse);
14
14
  rpc SendTest(SendTestRequest) returns (SendTestResponse);
15
15
 
16
+ // Які змінні реально передає система в шаблон із цим ключем + приклад значень.
17
+ rpc GetTemplateVariables(GetTemplateVariablesRequest) returns (TemplateVariablesResponse);
18
+ // Копія шаблону під новим ключем і/або мовою (з тілом, блоками й темою).
19
+ rpc DuplicateTemplate(DuplicateTemplateRequest) returns (TemplateResponse);
20
+ // Видалення — лише для листів, створених адміном; системні ключі не видаляються.
21
+ rpc DeleteTemplate(DeleteTemplateRequest) returns (DeleteTemplateResponse);
22
+
16
23
  rpc SendToCustomer(SendToCustomerRequest) returns (SendToCustomerResponse);
17
24
  }
18
25
 
@@ -341,6 +348,12 @@ message BrandingProfile {
341
348
  string resolved_support_email = 11;
342
349
 
343
350
  string header_html = 12;
351
+
352
+ // Оформлення листа за замовчуванням (JSON EmailTheme) і глобальні шапка й
353
+ // підвал блоками (JSON EmailBlock[]). Порожній рядок — «як у коді».
354
+ string theme_json = 13;
355
+ string header_blocks_json = 14;
356
+ string footer_blocks_json = 15;
344
357
  }
345
358
 
346
359
  message UpdateBrandingRequest {
@@ -351,6 +364,9 @@ message UpdateBrandingRequest {
351
364
  optional string footer_html = 5;
352
365
  string actor_id = 6;
353
366
  optional string header_html = 7;
367
+ optional string theme_json = 8;
368
+ optional string header_blocks_json = 9;
369
+ optional string footer_blocks_json = 10;
354
370
  }
355
371
 
356
372
  enum NotificationChannel {
@@ -382,6 +398,10 @@ enum NotificationStatus {
382
398
  FAILED = 3;
383
399
  SIMULATED = 4;
384
400
  SUPPRESSED = 5;
401
+ // Не надіслано: таке саме повідомлення вже пішло раніше (повтор події).
402
+ DUPLICATE = 6;
403
+ // Не надіслано: адмін вимкнув шаблон цього листа.
404
+ DISABLED = 7;
385
405
  }
386
406
 
387
407
  enum TelegramTopic {
@@ -509,11 +529,24 @@ message RenderPreviewRequest {
509
529
  optional string subject = 3;
510
530
 
511
531
  optional string branding_json = 4;
532
+
533
+ // Блоковий лист (JSON EmailDocument). Якщо заданий — рендеримо його, а
534
+ // body_html лише запасний шлях, як і при відправці.
535
+ optional string content_json = 5;
536
+ // Категорія впливає на лист: у масових є посилання «Відписатися».
537
+ optional NotificationCategory category = 6;
538
+ optional NotificationLocale locale = 7;
539
+ // Ключ листа — щоб попередити про змінні, яких цей лист не отримає.
540
+ optional string template_key = 8;
512
541
  }
513
542
 
514
543
  message RenderPreviewResponse {
515
544
  string html = 1;
516
545
  string subject = 2;
546
+ // Плейн-текстова версія — саме та, що піде в листі.
547
+ string text = 3;
548
+ // Попередження (невідома змінна, порожній alt, зламана розмітка тощо).
549
+ repeated string warnings = 4;
517
550
  }
518
551
 
519
552
  message SendTestRequest {
@@ -522,6 +555,51 @@ message SendTestRequest {
522
555
  string recipient = 2;
523
556
 
524
557
  string variables_json = 3;
558
+
559
+ // Незбережений стан редактора. Задані поля замінюють збережені — тестовий
560
+ // лист показує те, що адмін бачить зараз, а не останнє збереження.
561
+ optional string subject = 4;
562
+ optional string content_json = 5;
563
+ optional string body_html = 6;
564
+ optional string body_text = 7;
565
+ }
566
+
567
+ message GetTemplateVariablesRequest {
568
+ string key = 1;
569
+ }
570
+
571
+ message TemplateVariable {
572
+ string path = 1;
573
+ string label = 2;
574
+ string example = 3;
575
+ bool is_list = 4;
576
+ }
577
+
578
+ message TemplateVariablesResponse {
579
+ // event — лист шле система за подією; campaign — лист розсилки.
580
+ string source = 1;
581
+ string trigger = 2;
582
+ repeated TemplateVariable variables = 3;
583
+ // Приклад значень (JSON) — для попереднього перегляду.
584
+ string sample_json = 4;
585
+ }
586
+
587
+ message DuplicateTemplateRequest {
588
+ string id = 1;
589
+ string new_key = 2;
590
+ optional NotificationLocale locale = 3;
591
+ optional string title = 4;
592
+ optional string actor_id = 5;
593
+ }
594
+
595
+ message DeleteTemplateRequest {
596
+ string id = 1;
597
+ optional string actor_id = 2;
598
+ }
599
+
600
+ message DeleteTemplateResponse {
601
+ bool ok = 1;
602
+ string error_message = 2;
525
603
  }
526
604
 
527
605
  message SendTestResponse {
@@ -30,6 +30,10 @@ service OrderService {
30
30
 
31
31
  rpc SetCrmOrderId(SetCrmOrderIdRequest) returns (OrderResponse);
32
32
 
33
+ // GA4 (ТЗ KIPLAR, розділ 8): покупку в аналітику відправлено. Ідемпотентно:
34
+ // `claimed` = true лише для того виклику, що перевів прапорець false → true.
35
+ rpc MarkAnalyticsSent(MarkAnalyticsSentRequest) returns (MarkAnalyticsSentResponse);
36
+
33
37
 
34
38
  rpc SetOneCOrderRef(SetOneCOrderRefRequest) returns (OrderResponse);
35
39
 
@@ -308,6 +312,9 @@ message Order {
308
312
  string one_c_order_number = 28;
309
313
 
310
314
  string one_c_order_date = 29;
315
+
316
+ // Подію purchase уже відправлено в GA4 (дедуплікація, ТЗ GA4 розділ 8).
317
+ bool analytics_sent = 30;
311
318
  }
312
319
 
313
320
  message CreateOrderRequest {
@@ -316,6 +323,8 @@ message CreateOrderRequest {
316
323
  string guest_id = 3;
317
324
  string source = 4;
318
325
  string cart_id = 5;
326
+ // Мова сайту на момент оформлення (uk | ru) — нею йдуть листи й SMS про замовлення.
327
+ optional string locale = 6;
319
328
  }
320
329
 
321
330
  message CreateManualOrderRequest {
@@ -331,6 +340,8 @@ message CreateManualOrderRequest {
331
340
 
332
341
  string promo_code = 9;
333
342
  string comment = 10;
343
+ // Мова листів покупцю (uk | ru); порожньо — українська.
344
+ optional string locale = 11;
334
345
  }
335
346
 
336
347
  message OrderItemInput {
@@ -414,6 +425,17 @@ message SetCrmOrderIdRequest {
414
425
  string crm_order_id = 2;
415
426
  }
416
427
 
428
+ message MarkAnalyticsSentRequest {
429
+ string id = 1;
430
+ }
431
+
432
+ message MarkAnalyticsSentResponse {
433
+ bool ok = 1;
434
+ // Саме цей виклик поставив прапорець. false — його вже було поставлено раніше.
435
+ bool claimed = 2;
436
+ string error_message = 3;
437
+ }
438
+
417
439
 
418
440
 
419
441
  message MoneyAdjustment {
@@ -9,4 +9,10 @@ export interface OtpRequestedEvent {
9
9
 
10
10
  identifier?: string
11
11
  type?: string
12
+
13
+ /**
14
+ * Мова покупця (`UK` | `RU`) — нею йдуть листи й SMS. Порожньо — `UK`.
15
+ * Необов'язкове: старі продюсери поле не шлють.
16
+ */
17
+ locale?: 'UK' | 'RU'
12
18
  }
@@ -17,4 +17,10 @@ export interface OrderCancelledEvent {
17
17
  email: string
18
18
  phone: string
19
19
  }
20
+
21
+ /**
22
+ * Мова покупця (`UK` | `RU`) — нею йдуть листи й SMS. Порожньо — `UK`.
23
+ * Необов'язкове: старі продюсери поле не шлють.
24
+ */
25
+ locale?: 'UK' | 'RU'
20
26
  }
@@ -15,6 +15,11 @@ export interface OrderCreatedEvent {
15
15
  sku: string
16
16
  quantity: number
17
17
  price: string
18
+ /** Знімок назви, фото й підсумку рядка — для таблиці товарів у листі. */
19
+ name?: string
20
+ imageUrl?: string
21
+ size?: string
22
+ lineTotal?: string
18
23
  }>
19
24
  delivery: {
20
25
  method: string
@@ -34,4 +39,10 @@ export interface OrderCreatedEvent {
34
39
  email: string
35
40
  }
36
41
  createdAt: number
42
+
43
+ /**
44
+ * Мова покупця (`UK` | `RU`) — нею йдуть листи й SMS. Порожньо — `UK`.
45
+ * Необов'язкове: старі продюсери поле не шлють.
46
+ */
47
+ locale?: 'UK' | 'RU'
37
48
  }
@@ -27,4 +27,10 @@ export interface OrderSurchargeRequestedEvent {
27
27
  email: string
28
28
  phone: string
29
29
  }
30
+
31
+ /**
32
+ * Мова покупця (`UK` | `RU`) — нею йдуть листи й SMS. Порожньо — `UK`.
33
+ * Необов'язкове: старі продюсери поле не шлють.
34
+ */
35
+ locale?: 'UK' | 'RU'
30
36
  }
@@ -20,4 +20,10 @@ export interface OrderStatusChangedEvent {
20
20
 
21
21
  trackingNumber?: string
22
22
  trackingUrl?: string
23
+
24
+ /**
25
+ * Мова покупця (`UK` | `RU`) — нею йдуть листи й SMS. Порожньо — `UK`.
26
+ * Необов'язкове: старі продюсери поле не шлють.
27
+ */
28
+ locale?: 'UK' | 'RU'
23
29
  }
package/gen/auth.ts CHANGED
@@ -21,6 +21,8 @@ export interface LogoutResponse {
21
21
  export interface SendOtpRequest {
22
22
  identifier: string;
23
23
  type: string;
24
+ /** Мова сайту (uk | ru) — нею прийде лист/SMS із кодом. */
25
+ locale?: string | undefined;
24
26
  }
25
27
 
26
28
  export interface SendOtpResponse {
@@ -51,6 +53,7 @@ export interface RegisterRequest {
51
53
  export interface RequestPasswordResetRequest {
52
54
  identifier: string;
53
55
  type: string;
56
+ locale?: string | undefined;
54
57
  }
55
58
 
56
59
  export interface RequestPasswordResetResponse {
@@ -11,7 +11,9 @@ import { Observable } from "rxjs";
11
11
  export const protobufPackage = "promo.v1";
12
12
 
13
13
  export interface BonusSettingsResponse {
14
- earnRate: number;
14
+ earnStepUah: number;
15
+ earnPerStepUah: number;
16
+ earnMinPriceUah: number;
15
17
  redeemRate: number;
16
18
  minOrderForEarn: number;
17
19
  maxRedeemShare: number;
@@ -22,7 +24,9 @@ export interface GetBonusSettingsRequest {
22
24
  }
23
25
 
24
26
  export interface UpdateBonusSettingsRequest {
25
- earnRate?: number | undefined;
27
+ earnStepUah?: number | undefined;
28
+ earnPerStepUah?: number | undefined;
29
+ earnMinPriceUah?: number | undefined;
26
30
  redeemRate?: number | undefined;
27
31
  minOrderForEarn?: number | undefined;
28
32
  maxRedeemShare?: number | undefined;
@@ -64,6 +64,10 @@ export enum NotificationStatus {
64
64
  FAILED = 3,
65
65
  SIMULATED = 4,
66
66
  SUPPRESSED = 5,
67
+ /** DUPLICATE - Не надіслано: таке саме повідомлення вже пішло раніше (повтор події). */
68
+ DUPLICATE = 6,
69
+ /** DISABLED - Не надіслано: адмін вимкнув шаблон цього листа. */
70
+ DISABLED = 7,
67
71
  UNRECOGNIZED = -1,
68
72
  }
69
73
 
@@ -325,6 +329,13 @@ export interface BrandingProfile {
325
329
  resolvedBrandUrl: string;
326
330
  resolvedSupportEmail: string;
327
331
  headerHtml: string;
332
+ /**
333
+ * Оформлення листа за замовчуванням (JSON EmailTheme) і глобальні шапка й
334
+ * підвал блоками (JSON EmailBlock[]). Порожній рядок — «як у коді».
335
+ */
336
+ themeJson: string;
337
+ headerBlocksJson: string;
338
+ footerBlocksJson: string;
328
339
  }
329
340
 
330
341
  export interface UpdateBrandingRequest {
@@ -335,6 +346,9 @@ export interface UpdateBrandingRequest {
335
346
  footerHtml?: string | undefined;
336
347
  actorId: string;
337
348
  headerHtml?: string | undefined;
349
+ themeJson?: string | undefined;
350
+ headerBlocksJson?: string | undefined;
351
+ footerBlocksJson?: string | undefined;
338
352
  }
339
353
 
340
354
  export interface NotificationTemplate {
@@ -439,18 +453,84 @@ export interface RenderPreviewRequest {
439
453
  bodyHtml: string;
440
454
  variablesJson: string;
441
455
  subject?: string | undefined;
442
- brandingJson?: string | undefined;
456
+ brandingJson?:
457
+ | string
458
+ | undefined;
459
+ /**
460
+ * Блоковий лист (JSON EmailDocument). Якщо заданий — рендеримо його, а
461
+ * body_html лише запасний шлях, як і при відправці.
462
+ */
463
+ contentJson?:
464
+ | string
465
+ | undefined;
466
+ /** Категорія впливає на лист: у масових є посилання «Відписатися». */
467
+ category?: NotificationCategory | undefined;
468
+ locale?:
469
+ | NotificationLocale
470
+ | undefined;
471
+ /** Ключ листа — щоб попередити про змінні, яких цей лист не отримає. */
472
+ templateKey?: string | undefined;
443
473
  }
444
474
 
445
475
  export interface RenderPreviewResponse {
446
476
  html: string;
447
477
  subject: string;
478
+ /** Плейн-текстова версія — саме та, що піде в листі. */
479
+ text: string;
480
+ /** Попередження (невідома змінна, порожній alt, зламана розмітка тощо). */
481
+ warnings: string[];
448
482
  }
449
483
 
450
484
  export interface SendTestRequest {
451
485
  templateId: string;
452
486
  recipient: string;
453
487
  variablesJson: string;
488
+ /**
489
+ * Незбережений стан редактора. Задані поля замінюють збережені — тестовий
490
+ * лист показує те, що адмін бачить зараз, а не останнє збереження.
491
+ */
492
+ subject?: string | undefined;
493
+ contentJson?: string | undefined;
494
+ bodyHtml?: string | undefined;
495
+ bodyText?: string | undefined;
496
+ }
497
+
498
+ export interface GetTemplateVariablesRequest {
499
+ key: string;
500
+ }
501
+
502
+ export interface TemplateVariable {
503
+ path: string;
504
+ label: string;
505
+ example: string;
506
+ isList: boolean;
507
+ }
508
+
509
+ export interface TemplateVariablesResponse {
510
+ /** event — лист шле система за подією; campaign — лист розсилки. */
511
+ source: string;
512
+ trigger: string;
513
+ variables: TemplateVariable[];
514
+ /** Приклад значень (JSON) — для попереднього перегляду. */
515
+ sampleJson: string;
516
+ }
517
+
518
+ export interface DuplicateTemplateRequest {
519
+ id: string;
520
+ newKey: string;
521
+ locale?: NotificationLocale | undefined;
522
+ title?: string | undefined;
523
+ actorId?: string | undefined;
524
+ }
525
+
526
+ export interface DeleteTemplateRequest {
527
+ id: string;
528
+ actorId?: string | undefined;
529
+ }
530
+
531
+ export interface DeleteTemplateResponse {
532
+ ok: boolean;
533
+ errorMessage: string;
454
534
  }
455
535
 
456
536
  export interface SendTestResponse {
@@ -565,6 +645,18 @@ export interface NotificationTemplateServiceClient {
565
645
 
566
646
  sendTest(request: SendTestRequest): Observable<SendTestResponse>;
567
647
 
648
+ /** Які змінні реально передає система в шаблон із цим ключем + приклад значень. */
649
+
650
+ getTemplateVariables(request: GetTemplateVariablesRequest): Observable<TemplateVariablesResponse>;
651
+
652
+ /** Копія шаблону під новим ключем і/або мовою (з тілом, блоками й темою). */
653
+
654
+ duplicateTemplate(request: DuplicateTemplateRequest): Observable<TemplateResponse>;
655
+
656
+ /** Видалення — лише для листів, створених адміном; системні ключі не видаляються. */
657
+
658
+ deleteTemplate(request: DeleteTemplateRequest): Observable<DeleteTemplateResponse>;
659
+
568
660
  sendToCustomer(request: SendToCustomerRequest): Observable<SendToCustomerResponse>;
569
661
  }
570
662
 
@@ -601,6 +693,24 @@ export interface NotificationTemplateServiceController {
601
693
 
602
694
  sendTest(request: SendTestRequest): Promise<SendTestResponse> | Observable<SendTestResponse> | SendTestResponse;
603
695
 
696
+ /** Які змінні реально передає система в шаблон із цим ключем + приклад значень. */
697
+
698
+ getTemplateVariables(
699
+ request: GetTemplateVariablesRequest,
700
+ ): Promise<TemplateVariablesResponse> | Observable<TemplateVariablesResponse> | TemplateVariablesResponse;
701
+
702
+ /** Копія шаблону під новим ключем і/або мовою (з тілом, блоками й темою). */
703
+
704
+ duplicateTemplate(
705
+ request: DuplicateTemplateRequest,
706
+ ): Promise<TemplateResponse> | Observable<TemplateResponse> | TemplateResponse;
707
+
708
+ /** Видалення — лише для листів, створених адміном; системні ключі не видаляються. */
709
+
710
+ deleteTemplate(
711
+ request: DeleteTemplateRequest,
712
+ ): Promise<DeleteTemplateResponse> | Observable<DeleteTemplateResponse> | DeleteTemplateResponse;
713
+
604
714
  sendToCustomer(
605
715
  request: SendToCustomerRequest,
606
716
  ): Promise<SendToCustomerResponse> | Observable<SendToCustomerResponse> | SendToCustomerResponse;
@@ -618,6 +728,9 @@ export function NotificationTemplateServiceControllerMethods() {
618
728
  "restoreVersion",
619
729
  "renderPreview",
620
730
  "sendTest",
731
+ "getTemplateVariables",
732
+ "duplicateTemplate",
733
+ "deleteTemplate",
621
734
  "sendToCustomer",
622
735
  ];
623
736
  for (const method of grpcMethods) {
package/gen/order.ts CHANGED
@@ -231,6 +231,8 @@ export interface Order {
231
231
  saleRecordedAt: number;
232
232
  oneCOrderNumber: string;
233
233
  oneCOrderDate: string;
234
+ /** Подію purchase уже відправлено в GA4 (дедуплікація, ТЗ GA4 розділ 8). */
235
+ analyticsSent: boolean;
234
236
  }
235
237
 
236
238
  export interface CreateOrderRequest {
@@ -239,6 +241,8 @@ export interface CreateOrderRequest {
239
241
  guestId: string;
240
242
  source: string;
241
243
  cartId: string;
244
+ /** Мова сайту на момент оформлення (uk | ru) — нею йдуть листи й SMS про замовлення. */
245
+ locale?: string | undefined;
242
246
  }
243
247
 
244
248
  export interface CreateManualOrderRequest {
@@ -252,6 +256,8 @@ export interface CreateManualOrderRequest {
252
256
  payment: OrderPayment | undefined;
253
257
  promoCode: string;
254
258
  comment: string;
259
+ /** Мова листів покупцю (uk | ru); порожньо — українська. */
260
+ locale?: string | undefined;
255
261
  }
256
262
 
257
263
  export interface OrderItemInput {
@@ -327,6 +333,17 @@ export interface SetCrmOrderIdRequest {
327
333
  crmOrderId: string;
328
334
  }
329
335
 
336
+ export interface MarkAnalyticsSentRequest {
337
+ id: string;
338
+ }
339
+
340
+ export interface MarkAnalyticsSentResponse {
341
+ ok: boolean;
342
+ /** Саме цей виклик поставив прапорець. false — його вже було поставлено раніше. */
343
+ claimed: boolean;
344
+ errorMessage: string;
345
+ }
346
+
330
347
  export interface MoneyAdjustment {
331
348
  id: string;
332
349
  orderId: string;
@@ -600,6 +617,13 @@ export interface OrderServiceClient {
600
617
 
601
618
  setCrmOrderId(request: SetCrmOrderIdRequest): Observable<OrderResponse>;
602
619
 
620
+ /**
621
+ * GA4 (ТЗ KIPLAR, розділ 8): покупку в аналітику відправлено. Ідемпотентно:
622
+ * `claimed` = true лише для того виклику, що перевів прапорець false → true.
623
+ */
624
+
625
+ markAnalyticsSent(request: MarkAnalyticsSentRequest): Observable<MarkAnalyticsSentResponse>;
626
+
603
627
  setOneCOrderRef(request: SetOneCOrderRefRequest): Observable<OrderResponse>;
604
628
 
605
629
  applyOneCStatus(request: ApplyOneCStatusRequest): Observable<OrderResponse>;
@@ -699,6 +723,15 @@ export interface OrderServiceController {
699
723
 
700
724
  setCrmOrderId(request: SetCrmOrderIdRequest): Promise<OrderResponse> | Observable<OrderResponse> | OrderResponse;
701
725
 
726
+ /**
727
+ * GA4 (ТЗ KIPLAR, розділ 8): покупку в аналітику відправлено. Ідемпотентно:
728
+ * `claimed` = true лише для того виклику, що перевів прапорець false → true.
729
+ */
730
+
731
+ markAnalyticsSent(
732
+ request: MarkAnalyticsSentRequest,
733
+ ): Promise<MarkAnalyticsSentResponse> | Observable<MarkAnalyticsSentResponse> | MarkAnalyticsSentResponse;
734
+
702
735
  setOneCOrderRef(request: SetOneCOrderRefRequest): Promise<OrderResponse> | Observable<OrderResponse> | OrderResponse;
703
736
 
704
737
  applyOneCStatus(request: ApplyOneCStatusRequest): Promise<OrderResponse> | Observable<OrderResponse> | OrderResponse;
@@ -789,6 +822,7 @@ export function OrderServiceControllerMethods() {
789
822
  "setTrackingNumber",
790
823
  "applyRecalculation",
791
824
  "setCrmOrderId",
825
+ "markAnalyticsSent",
792
826
  "setOneCOrderRef",
793
827
  "applyOneCStatus",
794
828
  "listMoneyAdjustments",
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@mamindom/contracts",
3
3
  "description": "proto",
4
- "version": "1.0.213",
4
+ "version": "1.0.216",
5
5
  "main": "./dist/src/index.js",
6
6
  "types": "./dist/src/index.d.ts",
7
7
  "exports": {
package/proto/auth.proto CHANGED
@@ -25,6 +25,8 @@ message LogoutResponse {
25
25
  message SendOtpRequest {
26
26
  string identifier = 1;
27
27
  string type = 2;
28
+ // Мова сайту (uk | ru) — нею прийде лист/SMS із кодом.
29
+ optional string locale = 3;
28
30
  }
29
31
 
30
32
  message SendOtpResponse {
@@ -55,6 +57,7 @@ message RegisterRequest {
55
57
  message RequestPasswordResetRequest {
56
58
  string identifier = 1;
57
59
  string type = 2;
60
+ optional string locale = 3;
58
61
  }
59
62
 
60
63
  message RequestPasswordResetResponse {
@@ -8,7 +8,19 @@ service BonusSettingsService {
8
8
  }
9
9
 
10
10
  message BonusSettingsResponse {
11
- double earn_rate = 1;
11
+ // Формула нарахування (п.17 переліку): кожні `earn_step_uah` гривень ціни
12
+ // товару дають `earn_per_step_uah` гривень бонусів, і лише для товарів не
13
+ // дешевших за `earn_min_price_uah`. Ціна береться ПІСЛЯ знижки.
14
+ //
15
+ // Поле 1 (`earn_rate`, відсоткова ставка) прибране: формула не відсоткова,
16
+ // а поле показувало 2% і тим вводило в оману. Номер зарезервовано, щоб його
17
+ // ніколи не перевикористали під інше значення.
18
+ reserved 1;
19
+ reserved "earn_rate";
20
+
21
+ double earn_step_uah = 6;
22
+ double earn_per_step_uah = 7;
23
+ double earn_min_price_uah = 8;
12
24
 
13
25
  double redeem_rate = 2;
14
26
 
@@ -22,7 +34,12 @@ message BonusSettingsResponse {
22
34
  message GetBonusSettingsRequest {}
23
35
 
24
36
  message UpdateBonusSettingsRequest {
25
- optional double earn_rate = 1;
37
+ reserved 1;
38
+ reserved "earn_rate";
39
+
40
+ optional double earn_step_uah = 6;
41
+ optional double earn_per_step_uah = 7;
42
+ optional double earn_min_price_uah = 8;
26
43
  optional double redeem_rate = 2;
27
44
  optional double min_order_for_earn = 3;
28
45
  optional double max_redeem_share = 4;
@@ -13,6 +13,13 @@ service NotificationTemplateService {
13
13
  rpc RenderPreview(RenderPreviewRequest) returns (RenderPreviewResponse);
14
14
  rpc SendTest(SendTestRequest) returns (SendTestResponse);
15
15
 
16
+ // Які змінні реально передає система в шаблон із цим ключем + приклад значень.
17
+ rpc GetTemplateVariables(GetTemplateVariablesRequest) returns (TemplateVariablesResponse);
18
+ // Копія шаблону під новим ключем і/або мовою (з тілом, блоками й темою).
19
+ rpc DuplicateTemplate(DuplicateTemplateRequest) returns (TemplateResponse);
20
+ // Видалення — лише для листів, створених адміном; системні ключі не видаляються.
21
+ rpc DeleteTemplate(DeleteTemplateRequest) returns (DeleteTemplateResponse);
22
+
16
23
  rpc SendToCustomer(SendToCustomerRequest) returns (SendToCustomerResponse);
17
24
  }
18
25
 
@@ -341,6 +348,12 @@ message BrandingProfile {
341
348
  string resolved_support_email = 11;
342
349
 
343
350
  string header_html = 12;
351
+
352
+ // Оформлення листа за замовчуванням (JSON EmailTheme) і глобальні шапка й
353
+ // підвал блоками (JSON EmailBlock[]). Порожній рядок — «як у коді».
354
+ string theme_json = 13;
355
+ string header_blocks_json = 14;
356
+ string footer_blocks_json = 15;
344
357
  }
345
358
 
346
359
  message UpdateBrandingRequest {
@@ -351,6 +364,9 @@ message UpdateBrandingRequest {
351
364
  optional string footer_html = 5;
352
365
  string actor_id = 6;
353
366
  optional string header_html = 7;
367
+ optional string theme_json = 8;
368
+ optional string header_blocks_json = 9;
369
+ optional string footer_blocks_json = 10;
354
370
  }
355
371
 
356
372
  enum NotificationChannel {
@@ -382,6 +398,10 @@ enum NotificationStatus {
382
398
  FAILED = 3;
383
399
  SIMULATED = 4;
384
400
  SUPPRESSED = 5;
401
+ // Не надіслано: таке саме повідомлення вже пішло раніше (повтор події).
402
+ DUPLICATE = 6;
403
+ // Не надіслано: адмін вимкнув шаблон цього листа.
404
+ DISABLED = 7;
385
405
  }
386
406
 
387
407
  enum TelegramTopic {
@@ -509,11 +529,24 @@ message RenderPreviewRequest {
509
529
  optional string subject = 3;
510
530
 
511
531
  optional string branding_json = 4;
532
+
533
+ // Блоковий лист (JSON EmailDocument). Якщо заданий — рендеримо його, а
534
+ // body_html лише запасний шлях, як і при відправці.
535
+ optional string content_json = 5;
536
+ // Категорія впливає на лист: у масових є посилання «Відписатися».
537
+ optional NotificationCategory category = 6;
538
+ optional NotificationLocale locale = 7;
539
+ // Ключ листа — щоб попередити про змінні, яких цей лист не отримає.
540
+ optional string template_key = 8;
512
541
  }
513
542
 
514
543
  message RenderPreviewResponse {
515
544
  string html = 1;
516
545
  string subject = 2;
546
+ // Плейн-текстова версія — саме та, що піде в листі.
547
+ string text = 3;
548
+ // Попередження (невідома змінна, порожній alt, зламана розмітка тощо).
549
+ repeated string warnings = 4;
517
550
  }
518
551
 
519
552
  message SendTestRequest {
@@ -522,6 +555,51 @@ message SendTestRequest {
522
555
  string recipient = 2;
523
556
 
524
557
  string variables_json = 3;
558
+
559
+ // Незбережений стан редактора. Задані поля замінюють збережені — тестовий
560
+ // лист показує те, що адмін бачить зараз, а не останнє збереження.
561
+ optional string subject = 4;
562
+ optional string content_json = 5;
563
+ optional string body_html = 6;
564
+ optional string body_text = 7;
565
+ }
566
+
567
+ message GetTemplateVariablesRequest {
568
+ string key = 1;
569
+ }
570
+
571
+ message TemplateVariable {
572
+ string path = 1;
573
+ string label = 2;
574
+ string example = 3;
575
+ bool is_list = 4;
576
+ }
577
+
578
+ message TemplateVariablesResponse {
579
+ // event — лист шле система за подією; campaign — лист розсилки.
580
+ string source = 1;
581
+ string trigger = 2;
582
+ repeated TemplateVariable variables = 3;
583
+ // Приклад значень (JSON) — для попереднього перегляду.
584
+ string sample_json = 4;
585
+ }
586
+
587
+ message DuplicateTemplateRequest {
588
+ string id = 1;
589
+ string new_key = 2;
590
+ optional NotificationLocale locale = 3;
591
+ optional string title = 4;
592
+ optional string actor_id = 5;
593
+ }
594
+
595
+ message DeleteTemplateRequest {
596
+ string id = 1;
597
+ optional string actor_id = 2;
598
+ }
599
+
600
+ message DeleteTemplateResponse {
601
+ bool ok = 1;
602
+ string error_message = 2;
525
603
  }
526
604
 
527
605
  message SendTestResponse {
package/proto/order.proto CHANGED
@@ -30,6 +30,10 @@ service OrderService {
30
30
 
31
31
  rpc SetCrmOrderId(SetCrmOrderIdRequest) returns (OrderResponse);
32
32
 
33
+ // GA4 (ТЗ KIPLAR, розділ 8): покупку в аналітику відправлено. Ідемпотентно:
34
+ // `claimed` = true лише для того виклику, що перевів прапорець false → true.
35
+ rpc MarkAnalyticsSent(MarkAnalyticsSentRequest) returns (MarkAnalyticsSentResponse);
36
+
33
37
 
34
38
  rpc SetOneCOrderRef(SetOneCOrderRefRequest) returns (OrderResponse);
35
39
 
@@ -308,6 +312,9 @@ message Order {
308
312
  string one_c_order_number = 28;
309
313
 
310
314
  string one_c_order_date = 29;
315
+
316
+ // Подію purchase уже відправлено в GA4 (дедуплікація, ТЗ GA4 розділ 8).
317
+ bool analytics_sent = 30;
311
318
  }
312
319
 
313
320
  message CreateOrderRequest {
@@ -316,6 +323,8 @@ message CreateOrderRequest {
316
323
  string guest_id = 3;
317
324
  string source = 4;
318
325
  string cart_id = 5;
326
+ // Мова сайту на момент оформлення (uk | ru) — нею йдуть листи й SMS про замовлення.
327
+ optional string locale = 6;
319
328
  }
320
329
 
321
330
  message CreateManualOrderRequest {
@@ -331,6 +340,8 @@ message CreateManualOrderRequest {
331
340
 
332
341
  string promo_code = 9;
333
342
  string comment = 10;
343
+ // Мова листів покупцю (uk | ru); порожньо — українська.
344
+ optional string locale = 11;
334
345
  }
335
346
 
336
347
  message OrderItemInput {
@@ -414,6 +425,17 @@ message SetCrmOrderIdRequest {
414
425
  string crm_order_id = 2;
415
426
  }
416
427
 
428
+ message MarkAnalyticsSentRequest {
429
+ string id = 1;
430
+ }
431
+
432
+ message MarkAnalyticsSentResponse {
433
+ bool ok = 1;
434
+ // Саме цей виклик поставив прапорець. false — його вже було поставлено раніше.
435
+ bool claimed = 2;
436
+ string error_message = 3;
437
+ }
438
+
417
439
 
418
440
 
419
441
  message MoneyAdjustment {