@lyxa.ai/marketing 1.0.42 → 1.0.44

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.
Files changed (194) hide show
  1. package/dist/lib/event/event-initializations.d.ts.map +1 -1
  2. package/dist/lib/event/event-initializations.js +2 -0
  3. package/dist/lib/event/event-initializations.js.map +1 -1
  4. package/dist/lib/event/event-listeners/event-listeners.d.ts +2 -0
  5. package/dist/lib/event/event-listeners/event-listeners.d.ts.map +1 -1
  6. package/dist/lib/event/event-listeners/event-listeners.js +59 -0
  7. package/dist/lib/event/event-listeners/event-listeners.js.map +1 -1
  8. package/dist/lib/event/events/marketing-product-seed.event.d.ts +17 -0
  9. package/dist/lib/event/events/marketing-product-seed.event.d.ts.map +1 -0
  10. package/dist/lib/event/events/marketing-product-seed.event.js +12 -0
  11. package/dist/lib/event/events/marketing-product-seed.event.js.map +1 -0
  12. package/dist/lib/index.d.ts +224 -82
  13. package/dist/lib/index.d.ts.map +1 -1
  14. package/dist/lib/modules/coupon/routers/coupon.router.d.ts +118 -0
  15. package/dist/lib/modules/coupon/routers/coupon.router.d.ts.map +1 -1
  16. package/dist/lib/modules/coupon/routers/coupon.router.js +33 -1
  17. package/dist/lib/modules/coupon/routers/coupon.router.js.map +1 -1
  18. package/dist/lib/modules/coupon/services/patterns/repository/CouponMetricsRepository.d.ts +32 -0
  19. package/dist/lib/modules/coupon/services/patterns/repository/CouponMetricsRepository.d.ts.map +1 -0
  20. package/dist/lib/modules/coupon/services/patterns/repository/CouponMetricsRepository.js +504 -0
  21. package/dist/lib/modules/coupon/services/patterns/repository/CouponMetricsRepository.js.map +1 -0
  22. package/dist/lib/modules/coupon/validations/coupon.validation.d.ts +420 -1
  23. package/dist/lib/modules/coupon/validations/coupon.validation.d.ts.map +1 -1
  24. package/dist/lib/modules/coupon/validations/coupon.validation.js +40 -1
  25. package/dist/lib/modules/coupon/validations/coupon.validation.js.map +1 -1
  26. package/dist/lib/modules/coupon/validations/create-coupon.validation.d.ts +1118 -0
  27. package/dist/lib/modules/coupon/validations/create-coupon.validation.d.ts.map +1 -0
  28. package/dist/lib/modules/coupon/validations/create-coupon.validation.js +13 -0
  29. package/dist/lib/modules/coupon/validations/create-coupon.validation.js.map +1 -0
  30. package/dist/lib/modules/coupon/validations/index.d.ts +1 -0
  31. package/dist/lib/modules/coupon/validations/index.d.ts.map +1 -1
  32. package/dist/lib/modules/coupon/validations/index.js +1 -0
  33. package/dist/lib/modules/coupon/validations/index.js.map +1 -1
  34. package/dist/lib/modules/limited-time-offer/campaign/campaign.router.d.ts +29 -72
  35. package/dist/lib/modules/limited-time-offer/campaign/campaign.router.d.ts.map +1 -1
  36. package/dist/lib/modules/limited-time-offer/campaign/campaign.router.js +3 -16
  37. package/dist/lib/modules/limited-time-offer/campaign/campaign.router.js.map +1 -1
  38. package/dist/lib/modules/limited-time-offer/campaign/limited-time-offer-campaign.builder.d.ts +36 -0
  39. package/dist/lib/modules/limited-time-offer/campaign/limited-time-offer-campaign.builder.d.ts.map +1 -0
  40. package/dist/lib/modules/limited-time-offer/campaign/limited-time-offer-campaign.builder.js +48 -0
  41. package/dist/lib/modules/limited-time-offer/campaign/limited-time-offer-campaign.builder.js.map +1 -0
  42. package/dist/lib/modules/limited-time-offer/campaign/limited-time-offer-campaign.repository.d.ts +22 -0
  43. package/dist/lib/modules/limited-time-offer/campaign/limited-time-offer-campaign.repository.d.ts.map +1 -0
  44. package/dist/lib/modules/limited-time-offer/campaign/limited-time-offer-campaign.repository.js +131 -0
  45. package/dist/lib/modules/limited-time-offer/campaign/limited-time-offer-campaign.repository.js.map +1 -0
  46. package/dist/lib/modules/limited-time-offer/campaign/limited-time-offer-campaign.validation.d.ts +78 -78
  47. package/dist/lib/modules/limited-time-offer/campaign/services/limited-time-offer-campaign-lifecycle.service.d.ts +1 -2
  48. package/dist/lib/modules/limited-time-offer/campaign/services/limited-time-offer-campaign-lifecycle.service.d.ts.map +1 -1
  49. package/dist/lib/modules/limited-time-offer/campaign/services/limited-time-offer-campaign-lifecycle.service.js +6 -11
  50. package/dist/lib/modules/limited-time-offer/campaign/services/limited-time-offer-campaign-lifecycle.service.js.map +1 -1
  51. package/dist/lib/modules/limited-time-offer/campaign/services/limited-time-offer-campaign.service.d.ts +16 -51
  52. package/dist/lib/modules/limited-time-offer/campaign/services/limited-time-offer-campaign.service.d.ts.map +1 -1
  53. package/dist/lib/modules/limited-time-offer/campaign/services/limited-time-offer-campaign.service.js +33 -156
  54. package/dist/lib/modules/limited-time-offer/campaign/services/limited-time-offer-campaign.service.js.map +1 -1
  55. package/dist/lib/modules/limited-time-offer/config/limited-time-offer-config.builder.d.ts +8 -0
  56. package/dist/lib/modules/limited-time-offer/config/limited-time-offer-config.builder.d.ts.map +1 -0
  57. package/dist/lib/modules/limited-time-offer/config/limited-time-offer-config.builder.js +13 -0
  58. package/dist/lib/modules/limited-time-offer/config/limited-time-offer-config.builder.js.map +1 -0
  59. package/dist/lib/modules/limited-time-offer/config/limited-time-offer-config.repository.d.ts +14 -0
  60. package/dist/lib/modules/limited-time-offer/config/limited-time-offer-config.repository.d.ts.map +1 -0
  61. package/dist/lib/modules/limited-time-offer/config/limited-time-offer-config.repository.js +77 -0
  62. package/dist/lib/modules/limited-time-offer/config/limited-time-offer-config.repository.js.map +1 -0
  63. package/dist/lib/modules/limited-time-offer/config/limited-time-offer-config.service.d.ts +1 -2
  64. package/dist/lib/modules/limited-time-offer/config/limited-time-offer-config.service.d.ts.map +1 -1
  65. package/dist/lib/modules/limited-time-offer/config/limited-time-offer-config.service.js +19 -26
  66. package/dist/lib/modules/limited-time-offer/config/limited-time-offer-config.service.js.map +1 -1
  67. package/dist/lib/modules/limited-time-offer/config/limited-time-offer.router.d.ts.map +1 -1
  68. package/dist/lib/modules/limited-time-offer/config/limited-time-offer.router.js.map +1 -1
  69. package/dist/lib/modules/limited-time-offer/limited-time-offer.router.d.ts +92 -77
  70. package/dist/lib/modules/limited-time-offer/limited-time-offer.router.d.ts.map +1 -1
  71. package/dist/lib/modules/limited-time-offer/participant/limited-time-offer-participant.builder.d.ts +53 -0
  72. package/dist/lib/modules/limited-time-offer/participant/limited-time-offer-participant.builder.d.ts.map +1 -0
  73. package/dist/lib/modules/limited-time-offer/participant/limited-time-offer-participant.builder.js +55 -0
  74. package/dist/lib/modules/limited-time-offer/participant/limited-time-offer-participant.builder.js.map +1 -0
  75. package/dist/lib/modules/limited-time-offer/participant/limited-time-offer-participant.repository.d.ts +21 -0
  76. package/dist/lib/modules/limited-time-offer/participant/limited-time-offer-participant.repository.d.ts.map +1 -0
  77. package/dist/lib/modules/limited-time-offer/participant/limited-time-offer-participant.repository.js +142 -0
  78. package/dist/lib/modules/limited-time-offer/participant/limited-time-offer-participant.repository.js.map +1 -0
  79. package/dist/lib/modules/limited-time-offer/participant/limited-time-offer-participant.router.d.ts +63 -5
  80. package/dist/lib/modules/limited-time-offer/participant/limited-time-offer-participant.router.d.ts.map +1 -1
  81. package/dist/lib/modules/limited-time-offer/participant/limited-time-offer-participant.router.js +8 -2
  82. package/dist/lib/modules/limited-time-offer/participant/limited-time-offer-participant.router.js.map +1 -1
  83. package/dist/lib/modules/limited-time-offer/participant/limited-time-offer-participant.service.d.ts +1 -0
  84. package/dist/lib/modules/limited-time-offer/participant/limited-time-offer-participant.service.d.ts.map +1 -0
  85. package/dist/lib/modules/limited-time-offer/participant/limited-time-offer-participant.service.js +2 -0
  86. package/dist/lib/modules/limited-time-offer/participant/limited-time-offer-participant.service.js.map +1 -0
  87. package/dist/lib/modules/limited-time-offer/participant/limited-time-offer-participant.validation.d.ts +161 -27
  88. package/dist/lib/modules/limited-time-offer/participant/limited-time-offer-participant.validation.d.ts.map +1 -1
  89. package/dist/lib/modules/limited-time-offer/participant/limited-time-offer-participant.validation.js +11 -9
  90. package/dist/lib/modules/limited-time-offer/participant/limited-time-offer-participant.validation.js.map +1 -1
  91. package/dist/lib/modules/limited-time-offer/participant/services/limited-time-offer-participant-marketing.service.d.ts +6 -1
  92. package/dist/lib/modules/limited-time-offer/participant/services/limited-time-offer-participant-marketing.service.d.ts.map +1 -1
  93. package/dist/lib/modules/limited-time-offer/participant/services/limited-time-offer-participant-marketing.service.js +17 -38
  94. package/dist/lib/modules/limited-time-offer/participant/services/limited-time-offer-participant-marketing.service.js.map +1 -1
  95. package/dist/lib/modules/limited-time-offer/participant/services/limited-time-offer-participant.service.d.ts +20 -8
  96. package/dist/lib/modules/limited-time-offer/participant/services/limited-time-offer-participant.service.d.ts.map +1 -1
  97. package/dist/lib/modules/limited-time-offer/participant/services/limited-time-offer-participant.service.js +38 -27
  98. package/dist/lib/modules/limited-time-offer/participant/services/limited-time-offer-participant.service.js.map +1 -1
  99. package/dist/lib/modules/marketing/routers/marketing.router.d.ts +12 -3
  100. package/dist/lib/modules/marketing/routers/marketing.router.d.ts.map +1 -1
  101. package/dist/lib/modules/marketing/routers/marketing.router.js +7 -0
  102. package/dist/lib/modules/marketing/routers/marketing.router.js.map +1 -1
  103. package/dist/lib/modules/marketing/services/buy1-get1-marketing.service.d.ts.map +1 -1
  104. package/dist/lib/modules/marketing/services/buy1-get1-marketing.service.js +11 -9
  105. package/dist/lib/modules/marketing/services/buy1-get1-marketing.service.js.map +1 -1
  106. package/dist/lib/modules/marketing/services/discount-marketing.service.d.ts.map +1 -1
  107. package/dist/lib/modules/marketing/services/discount-marketing.service.js +15 -13
  108. package/dist/lib/modules/marketing/services/discount-marketing.service.js.map +1 -1
  109. package/dist/lib/modules/marketing/services/marketing.service.d.ts +1 -0
  110. package/dist/lib/modules/marketing/services/marketing.service.d.ts.map +1 -1
  111. package/dist/lib/modules/marketing/services/marketing.service.js +57 -7
  112. package/dist/lib/modules/marketing/services/marketing.service.js.map +1 -1
  113. package/dist/lib/modules/marketing/services/product-marketing.service.d.ts +11 -0
  114. package/dist/lib/modules/marketing/services/product-marketing.service.d.ts.map +1 -1
  115. package/dist/lib/modules/marketing/services/product-marketing.service.js +23 -0
  116. package/dist/lib/modules/marketing/services/product-marketing.service.js.map +1 -1
  117. package/dist/lib/modules/marketing/services/synchronize-product-marketing.service.d.ts.map +1 -1
  118. package/dist/lib/modules/marketing/services/synchronize-product-marketing.service.js +6 -31
  119. package/dist/lib/modules/marketing/services/synchronize-product-marketing.service.js.map +1 -1
  120. package/dist/lib/modules/marketing/validations/marketing.validation.d.ts +2 -2
  121. package/dist/lib/modules/marketing/validations/product-marketing.validation.d.ts +2 -2
  122. package/dist/lib/modules/punch-marketing-history/routers/punch-marketing-history.router.d.ts +2 -2
  123. package/dist/lib/modules/punch-marketing-history/services/punch-marketing-history.service.d.ts +1 -0
  124. package/dist/lib/modules/punch-marketing-history/services/punch-marketing-history.service.d.ts.map +1 -1
  125. package/dist/lib/modules/punch-marketing-history/services/punch-marketing-history.service.js +14 -0
  126. package/dist/lib/modules/punch-marketing-history/services/punch-marketing-history.service.js.map +1 -1
  127. package/dist/lib/modules/punch-marketing-history/validations/punch-marketing-history.validation.d.ts +4 -4
  128. package/dist/types/event/event-initializations.d.ts.map +1 -1
  129. package/dist/types/event/event-listeners/event-listeners.d.ts +2 -0
  130. package/dist/types/event/event-listeners/event-listeners.d.ts.map +1 -1
  131. package/dist/types/event/events/marketing-product-seed.event.d.ts +17 -0
  132. package/dist/types/event/events/marketing-product-seed.event.d.ts.map +1 -0
  133. package/dist/types/index.d.ts +224 -82
  134. package/dist/types/index.d.ts.map +1 -1
  135. package/dist/types/modules/coupon/routers/coupon.router.d.ts +118 -0
  136. package/dist/types/modules/coupon/routers/coupon.router.d.ts.map +1 -1
  137. package/dist/types/modules/coupon/services/patterns/repository/CouponMetricsRepository.d.ts +32 -0
  138. package/dist/types/modules/coupon/services/patterns/repository/CouponMetricsRepository.d.ts.map +1 -0
  139. package/dist/types/modules/coupon/validations/coupon.validation.d.ts +420 -1
  140. package/dist/types/modules/coupon/validations/coupon.validation.d.ts.map +1 -1
  141. package/dist/types/modules/coupon/validations/create-coupon.validation.d.ts +1118 -0
  142. package/dist/types/modules/coupon/validations/create-coupon.validation.d.ts.map +1 -0
  143. package/dist/types/modules/coupon/validations/index.d.ts +1 -0
  144. package/dist/types/modules/coupon/validations/index.d.ts.map +1 -1
  145. package/dist/types/modules/limited-time-offer/campaign/campaign.router.d.ts +29 -72
  146. package/dist/types/modules/limited-time-offer/campaign/campaign.router.d.ts.map +1 -1
  147. package/dist/types/modules/limited-time-offer/campaign/limited-time-offer-campaign.builder.d.ts +36 -0
  148. package/dist/types/modules/limited-time-offer/campaign/limited-time-offer-campaign.builder.d.ts.map +1 -0
  149. package/dist/types/modules/limited-time-offer/campaign/limited-time-offer-campaign.repository.d.ts +22 -0
  150. package/dist/types/modules/limited-time-offer/campaign/limited-time-offer-campaign.repository.d.ts.map +1 -0
  151. package/dist/types/modules/limited-time-offer/campaign/limited-time-offer-campaign.validation.d.ts +78 -78
  152. package/dist/types/modules/limited-time-offer/campaign/services/limited-time-offer-campaign-lifecycle.service.d.ts +1 -2
  153. package/dist/types/modules/limited-time-offer/campaign/services/limited-time-offer-campaign-lifecycle.service.d.ts.map +1 -1
  154. package/dist/types/modules/limited-time-offer/campaign/services/limited-time-offer-campaign.service.d.ts +16 -51
  155. package/dist/types/modules/limited-time-offer/campaign/services/limited-time-offer-campaign.service.d.ts.map +1 -1
  156. package/dist/types/modules/limited-time-offer/config/limited-time-offer-config.builder.d.ts +8 -0
  157. package/dist/types/modules/limited-time-offer/config/limited-time-offer-config.builder.d.ts.map +1 -0
  158. package/dist/types/modules/limited-time-offer/config/limited-time-offer-config.repository.d.ts +14 -0
  159. package/dist/types/modules/limited-time-offer/config/limited-time-offer-config.repository.d.ts.map +1 -0
  160. package/dist/types/modules/limited-time-offer/config/limited-time-offer-config.service.d.ts +1 -2
  161. package/dist/types/modules/limited-time-offer/config/limited-time-offer-config.service.d.ts.map +1 -1
  162. package/dist/types/modules/limited-time-offer/config/limited-time-offer.router.d.ts.map +1 -1
  163. package/dist/types/modules/limited-time-offer/limited-time-offer.router.d.ts +92 -77
  164. package/dist/types/modules/limited-time-offer/limited-time-offer.router.d.ts.map +1 -1
  165. package/dist/types/modules/limited-time-offer/participant/limited-time-offer-participant.builder.d.ts +53 -0
  166. package/dist/types/modules/limited-time-offer/participant/limited-time-offer-participant.builder.d.ts.map +1 -0
  167. package/dist/types/modules/limited-time-offer/participant/limited-time-offer-participant.repository.d.ts +21 -0
  168. package/dist/types/modules/limited-time-offer/participant/limited-time-offer-participant.repository.d.ts.map +1 -0
  169. package/dist/types/modules/limited-time-offer/participant/limited-time-offer-participant.router.d.ts +63 -5
  170. package/dist/types/modules/limited-time-offer/participant/limited-time-offer-participant.router.d.ts.map +1 -1
  171. package/dist/types/modules/limited-time-offer/participant/limited-time-offer-participant.validation.d.ts +161 -27
  172. package/dist/types/modules/limited-time-offer/participant/limited-time-offer-participant.validation.d.ts.map +1 -1
  173. package/dist/types/modules/limited-time-offer/participant/services/limited-time-offer-participant-marketing.service.d.ts +6 -1
  174. package/dist/types/modules/limited-time-offer/participant/services/limited-time-offer-participant-marketing.service.d.ts.map +1 -1
  175. package/dist/types/modules/limited-time-offer/participant/services/limited-time-offer-participant.service.d.ts +20 -8
  176. package/dist/types/modules/limited-time-offer/participant/services/limited-time-offer-participant.service.d.ts.map +1 -1
  177. package/dist/types/modules/marketing/routers/marketing.router.d.ts +12 -3
  178. package/dist/types/modules/marketing/routers/marketing.router.d.ts.map +1 -1
  179. package/dist/types/modules/marketing/services/buy1-get1-marketing.service.d.ts.map +1 -1
  180. package/dist/types/modules/marketing/services/discount-marketing.service.d.ts.map +1 -1
  181. package/dist/types/modules/marketing/services/marketing.service.d.ts +1 -0
  182. package/dist/types/modules/marketing/services/marketing.service.d.ts.map +1 -1
  183. package/dist/types/modules/marketing/services/product-marketing.service.d.ts +11 -0
  184. package/dist/types/modules/marketing/services/product-marketing.service.d.ts.map +1 -1
  185. package/dist/types/modules/marketing/services/synchronize-product-marketing.service.d.ts.map +1 -1
  186. package/dist/types/modules/marketing/validations/marketing.validation.d.ts +2 -2
  187. package/dist/types/modules/marketing/validations/product-marketing.validation.d.ts +2 -2
  188. package/dist/types/modules/punch-marketing-history/routers/punch-marketing-history.router.d.ts +2 -2
  189. package/dist/types/modules/punch-marketing-history/services/punch-marketing-history.service.d.ts +1 -0
  190. package/dist/types/modules/punch-marketing-history/services/punch-marketing-history.service.d.ts.map +1 -1
  191. package/dist/types/modules/punch-marketing-history/validations/punch-marketing-history.validation.d.ts +4 -4
  192. package/package.json +3 -3
  193. package/dist/types/events/event-initializations.d.ts +0 -2
  194. package/dist/types/events/event-initializations.d.ts.map +0 -1
@@ -1,40 +1,26 @@
1
- import { mongoose } from '@typegoose/typegoose';
1
+ import { DocumentType, mongoose } from '@typegoose/typegoose';
2
2
  import { LimitedTimeOfferCampaign as Model } from '@lyxa.ai/core/dist/libraries/mongo/models';
3
- import { CreateLtoCampaignDTO, GetLtoCampaignHistoryDTO, GetLtoCampaignParticipantsDTO, UpdateLtoCampaignDTO } from '../limited-time-offer-campaign.validation';
3
+ import { LimitedTimeOfferCampaignStatus } from '@lyxa.ai/core/dist/utilities/enum';
4
+ import { CreateLtoCampaignDTO, GetLtoCampaignHistoryDTO, UpdateLtoCampaignDTO } from '../limited-time-offer-campaign.validation';
4
5
  export declare class LtoCampaignService {
5
- private model;
6
+ private repository;
6
7
  private scheduler;
7
8
  private lifecycle;
8
9
  private participantMarketing;
10
+ private configService;
9
11
  constructor();
10
- create(dto: CreateLtoCampaignDTO): Promise<Model & {
11
- _id: mongoose.Types.ObjectId;
12
- } & {
13
- __v: number;
14
- }>;
15
- getCurrent(): Promise<(Model & {
16
- _id: mongoose.Types.ObjectId;
17
- } & {
18
- __v: number;
19
- }) | null>;
20
- getActiveCampaign(): Promise<(Model & {
21
- _id: mongoose.Types.ObjectId;
22
- } & {
23
- __v: number;
24
- }) | null>;
25
- getById(campaignId: mongoose.Types.ObjectId): Promise<Model & {
26
- _id: mongoose.Types.ObjectId;
27
- } & {
28
- __v: number;
29
- }>;
12
+ create(dto: CreateLtoCampaignDTO): Promise<DocumentType<Model>>;
13
+ getCurrent(): Promise<DocumentType<Model> | null>;
14
+ getActive(): Promise<DocumentType<Model> | null>;
15
+ getById(campaignId: mongoose.Types.ObjectId): Promise<DocumentType<Model>>;
30
16
  getHistory(dto: GetLtoCampaignHistoryDTO): Promise<{
31
17
  documents: {
32
- id: any;
33
- campaignNumber: any;
34
- startDateTime: any;
35
- endDateTime: any;
36
- shopsJoined: any;
37
- status: any;
18
+ status: LimitedTimeOfferCampaignStatus;
19
+ id: string;
20
+ campaignNumber: number;
21
+ shopsJoined: number;
22
+ startDateTime?: Date | null | undefined;
23
+ endDateTime?: Date | null | undefined;
38
24
  }[];
39
25
  metadata: {
40
26
  page: number;
@@ -43,36 +29,15 @@ export declare class LtoCampaignService {
43
29
  totalPages: number;
44
30
  };
45
31
  }>;
46
- update(dto: UpdateLtoCampaignDTO): Promise<Model & {
47
- _id: mongoose.Types.ObjectId;
48
- } & {
49
- __v: number;
50
- }>;
32
+ update(dto: UpdateLtoCampaignDTO): Promise<DocumentType<Model>>;
51
33
  cancel(campaignId: mongoose.Types.ObjectId): Promise<void>;
52
- getParticipants(dto: GetLtoCampaignParticipantsDTO): Promise<{
53
- documents: {
54
- shopName: any;
55
- shopPhoto: any;
56
- joinedAt: any;
57
- discountPercentage: any;
58
- maxDiscountCap: any;
59
- }[];
60
- metadata: {
61
- page: number;
62
- size: number;
63
- totalElements: number;
64
- totalPages: number;
65
- };
66
- }>;
67
34
  private assertUpdateAllowed;
68
- private buildCampaignUpdates;
69
35
  private shouldExpireImmediately;
70
36
  private applyImmediateExpiry;
71
37
  private rescheduleIfDatesChanged;
72
38
  private assertNoCampaignRunning;
73
39
  private assertEditable;
74
40
  private loadConfigSnapshot;
75
- private nextCampaignNumber;
76
41
  }
77
42
  export declare const ltoCampaignService: LtoCampaignService;
78
43
  //# sourceMappingURL=limited-time-offer-campaign.service.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"limited-time-offer-campaign.service.d.ts","sourceRoot":"/","sources":["modules/limited-time-offer/campaign/services/limited-time-offer-campaign.service.ts"],"names":[],"mappings":"AACA,OAAO,EAAC,QAAQ,EAAC,MAAM,sBAAsB,CAAC;AAC9C,OAAO,EAEH,wBAAwB,IAAI,KAAK,EAKpC,MAAM,2CAA2C,CAAC;AAInD,OAAO,EACH,oBAAoB,EACpB,wBAAwB,EACxB,6BAA6B,EAC7B,oBAAoB,EACvB,MAAM,2CAA2C,CAAC;AAQnD,qBACa,kBAAkB;IAC3B,OAAO,CAAC,KAAK,CAAgE;IAC7E,OAAO,CAAC,SAAS,CAA8B;IAC/C,OAAO,CAAC,SAAS,CAA8B;IAC/C,OAAO,CAAC,oBAAoB,CAAiC;;IAShD,MAAM,CAAC,GAAG,EAAE,oBAAoB;;;;;IA8BhC,UAAU;;;;;IAOV,iBAAiB;;;;;IAOjB,OAAO,CAAC,UAAU,EAAE,QAAQ,CAAC,KAAK,CAAC,QAAQ;;;;;IAM3C,UAAU,CAAC,GAAG,EAAE,wBAAwB;;;;;;;;;;;;;;;;IAyExC,MAAM,CAAC,GAAG,EAAE,oBAAoB;;;;;IAoBhC,MAAM,CAAC,UAAU,EAAE,QAAQ,CAAC,KAAK,CAAC,QAAQ;IAc1C,eAAe,CAAC,GAAG,EAAE,6BAA6B;;;;;;;;;;;;;;;IA0C/D,OAAO,CAAC,mBAAmB;IAY3B,OAAO,CAAC,oBAAoB;IAW5B,OAAO,CAAC,uBAAuB;YAIjB,oBAAoB;YAOpB,wBAAwB;YAmBxB,uBAAuB;IAKrC,OAAO,CAAC,cAAc;YAMR,kBAAkB;YAQlB,kBAAkB;CAQnC;AAED,eAAO,MAAM,kBAAkB,oBAAoC,CAAC"}
1
+ {"version":3,"file":"limited-time-offer-campaign.service.d.ts","sourceRoot":"/","sources":["modules/limited-time-offer/campaign/services/limited-time-offer-campaign.service.ts"],"names":[],"mappings":"AACA,OAAO,EAAC,YAAY,EAAE,QAAQ,EAAC,MAAM,sBAAsB,CAAC;AAC5D,OAAO,EAAC,wBAAwB,IAAI,KAAK,EAAC,MAAM,2CAA2C,CAAC;AAC5F,OAAO,EAAC,8BAA8B,EAAgB,MAAM,mCAAmC,CAAC;AAEhG,OAAO,EACH,oBAAoB,EACpB,wBAAwB,EACxB,oBAAoB,EACvB,MAAM,2CAA2C,CAAC;AAUnD,qBACa,kBAAkB;IAC3B,OAAO,CAAC,UAAU,CAAwB;IAC1C,OAAO,CAAC,SAAS,CAA8B;IAC/C,OAAO,CAAC,SAAS,CAA8B;IAC/C,OAAO,CAAC,oBAAoB,CAAiC;IAC7D,OAAO,CAAC,aAAa,CAAgC;;IAUxC,MAAM,CAAC,GAAG,EAAE,oBAAoB;IAqBhC,UAAU;IAIV,SAAS;IAIT,OAAO,CAAC,UAAU,EAAE,QAAQ,CAAC,KAAK,CAAC,QAAQ;IAM3C,UAAU,CAAC,GAAG,EAAE,wBAAwB;;;;;;;;;;;;;;;;IAQxC,MAAM,CAAC,GAAG,EAAE,oBAAoB;IAoBhC,MAAM,CAAC,UAAU,EAAE,QAAQ,CAAC,KAAK,CAAC,QAAQ;IAcvD,OAAO,CAAC,mBAAmB;IAY3B,OAAO,CAAC,uBAAuB;YAIjB,oBAAoB;YASpB,wBAAwB;YAmBxB,uBAAuB;IAMrC,OAAO,CAAC,cAAc;YAMR,kBAAkB;CAUnC;AAED,eAAO,MAAM,kBAAkB,oBAAoC,CAAC"}
@@ -44,24 +44,27 @@ var __metadata = (this && this.__metadata) || function (k, v) {
44
44
  Object.defineProperty(exports, "__esModule", { value: true });
45
45
  exports.ltoCampaignService = exports.LtoCampaignService = void 0;
46
46
  const typedi_1 = __importStar(require("typedi"));
47
- const models_1 = require("@lyxa.ai/core/dist/libraries/mongo/models");
48
47
  const enum_1 = require("@lyxa.ai/core/dist/utilities/enum");
49
48
  const error_common_1 = require("@lyxa.ai/core/dist/utilities/error-common");
50
49
  const limited_time_offer_campaign_lifecycle_service_1 = require("./limited-time-offer-campaign-lifecycle.service");
51
50
  const limited_time_offer_campaign_scheduler_service_1 = require("./limited-time-offer-campaign-scheduler.service");
52
51
  const limited_time_offer_participant_marketing_service_1 = require("../../../limited-time-offer/participant/services/limited-time-offer-participant-marketing.service");
52
+ const limited_time_offer_campaign_repository_1 = require("../../../limited-time-offer/campaign/limited-time-offer-campaign.repository");
53
+ const limited_time_offer_campaign_builder_1 = require("../../../limited-time-offer/campaign/limited-time-offer-campaign.builder");
54
+ const limited_time_offer_config_service_1 = require("../../../limited-time-offer/config/limited-time-offer-config.service");
53
55
  const ACTIVE_STATUSES = [enum_1.LimitedTimeOfferCampaignStatus.SCHEDULED, enum_1.LimitedTimeOfferCampaignStatus.ACTIVE];
54
- const ARCHIVED_STATUSES = [enum_1.LimitedTimeOfferCampaignStatus.EXPIRED, enum_1.LimitedTimeOfferCampaignStatus.CANCELLED];
55
56
  let LtoCampaignService = class LtoCampaignService {
56
- model;
57
+ repository;
57
58
  scheduler;
58
59
  lifecycle;
59
60
  participantMarketing;
61
+ configService;
60
62
  constructor() {
61
- this.model = models_1.LimitedTimeOfferCampaignModel;
63
+ this.repository = typedi_1.default.get(limited_time_offer_campaign_repository_1.LtoCampaignRepository);
62
64
  this.scheduler = typedi_1.default.get(limited_time_offer_campaign_scheduler_service_1.LtoCampaignSchedulerService);
63
65
  this.lifecycle = typedi_1.default.get(limited_time_offer_campaign_lifecycle_service_1.LtoCampaignLifecycleService);
64
66
  this.participantMarketing = typedi_1.default.get(limited_time_offer_participant_marketing_service_1.LtoParticipantMarketingService);
67
+ this.configService = typedi_1.default.get(limited_time_offer_config_service_1.LimitedTimeOfferConfigService);
65
68
  }
66
69
  async create(dto) {
67
70
  await this.assertNoCampaignRunning();
@@ -70,129 +73,49 @@ let LtoCampaignService = class LtoCampaignService {
70
73
  const status = dto.startDate <= now
71
74
  ? enum_1.LimitedTimeOfferCampaignStatus.ACTIVE
72
75
  : enum_1.LimitedTimeOfferCampaignStatus.SCHEDULED;
73
- const campaign = await this.model.create({
74
- campaignNumber: await this.nextCampaignNumber(),
75
- title: dto.title,
76
- subTitle: dto.subTitle,
77
- startDate: dto.startDate,
78
- endDate: dto.endDate,
79
- status,
80
- discountOptions: config.discountOptions,
81
- maxDiscountCaps: config.maxDiscountCaps,
82
- });
83
- const campaignId = campaign._id;
76
+ const campaign = await this.repository.create(limited_time_offer_campaign_builder_1.LtoCampaignQueryBuilder.buildCreateInput(dto, status, await this.repository.nextCampaignNumber(), config));
84
77
  if (status === enum_1.LimitedTimeOfferCampaignStatus.SCHEDULED) {
85
- await this.scheduler.scheduleActivation(campaignId, dto.startDate);
78
+ await this.scheduler.scheduleActivation(campaign._id, dto.startDate);
86
79
  }
87
- await this.scheduler.scheduleExpiry(campaignId, dto.endDate);
88
- return campaign.toObject();
80
+ await this.scheduler.scheduleExpiry(campaign._id, dto.endDate);
81
+ return campaign;
89
82
  }
90
83
  async getCurrent() {
91
- const campaign = await this.model
92
- .findOne({ status: { $in: ACTIVE_STATUSES } })
93
- .sort({ createdAt: -1 });
94
- return campaign ? campaign.toObject() : null;
84
+ return this.repository.findCurrent();
95
85
  }
96
- async getActiveCampaign() {
97
- const campaign = await this.model
98
- .findOne({ status: enum_1.LimitedTimeOfferCampaignStatus.ACTIVE })
99
- .sort({ createdAt: -1 });
100
- return campaign ? campaign.toObject() : null;
86
+ async getActive() {
87
+ return this.repository.findActive();
101
88
  }
102
89
  async getById(campaignId) {
103
- const campaign = await this.model.findById(campaignId);
90
+ const campaign = await this.repository.findById(campaignId);
104
91
  if (!campaign)
105
92
  throw (0, error_common_1.notFoundError)('Campaign not found');
106
- return campaign.toObject();
93
+ return campaign;
107
94
  }
108
95
  async getHistory(dto) {
109
- const query = dto.status
110
- ? { status: dto.status }
111
- : { status: { $in: ARCHIVED_STATUSES } };
112
- const sortFieldMap = {
113
- id: '_id',
114
- campaignNumber: 'campaignNumber',
115
- startDateTime: 'startDate',
116
- endDateTime: 'endDate',
117
- shopsJoined: 'shopsJoined',
118
- status: 'status',
119
- };
120
- const sortField = dto.sortBy ? sortFieldMap[dto.sortBy] : 'createdAt';
121
- const sortDirection = dto.sortOrder === 'asc' ? 1 : -1;
122
- const participantCollection = models_1.LimitedTimeOfferParticipantModel.collection.name;
123
- const [total, documents] = await Promise.all([
124
- this.model.countDocuments(query),
125
- this.model.aggregate([
126
- { $match: query },
127
- {
128
- $lookup: {
129
- from: participantCollection,
130
- let: { campaignId: '$_id' },
131
- pipeline: [
132
- {
133
- $match: {
134
- $expr: {
135
- $and: [
136
- { $eq: ['$campaign', '$$campaignId'] },
137
- { $eq: ['$isWithdrawn', false] },
138
- ],
139
- },
140
- },
141
- },
142
- { $count: 'count' },
143
- ],
144
- as: 'joinedStats',
145
- },
146
- },
147
- {
148
- $addFields: {
149
- shopsJoined: { $ifNull: [{ $arrayElemAt: ['$joinedStats.count', 0] }, 0] },
150
- },
151
- },
152
- { $sort: { [sortField]: sortDirection, _id: sortDirection } },
153
- {
154
- $project: {
155
- _id: 1,
156
- campaignNumber: 1,
157
- startDate: 1,
158
- endDate: 1,
159
- status: 1,
160
- shopsJoined: 1,
161
- },
162
- },
163
- { $skip: (dto.page - 1) * dto.size },
164
- { $limit: dto.size },
165
- ]),
166
- ]);
96
+ const { documents, total } = await this.repository.findHistory(dto);
167
97
  return {
168
- documents: documents.map(d => ({
169
- id: d._id.toString(),
170
- campaignNumber: d.campaignNumber,
171
- startDateTime: d.startDate,
172
- endDateTime: d.endDate,
173
- shopsJoined: d.shopsJoined,
174
- status: d.status,
175
- })),
98
+ documents,
176
99
  metadata: { page: dto.page, size: dto.size, totalElements: total, totalPages: Math.ceil(total / dto.size) },
177
100
  };
178
101
  }
179
102
  async update(dto) {
180
- const campaign = await this.model.findById(dto._id);
103
+ const campaign = await this.repository.findById(dto._id);
181
104
  if (!campaign)
182
105
  throw (0, error_common_1.notFoundError)('Campaign not found');
183
106
  this.assertUpdateAllowed(campaign, dto);
184
- const updates = this.buildCampaignUpdates(campaign, dto);
107
+ const updates = limited_time_offer_campaign_builder_1.LtoCampaignQueryBuilder.buildUpdateInput(campaign, dto);
185
108
  if (this.shouldExpireImmediately(campaign.status, dto.endDate)) {
186
109
  return this.applyImmediateExpiry(dto._id, updates);
187
110
  }
188
- const result = await this.model.findByIdAndUpdate(dto._id, { $set: updates }, { new: true });
111
+ const result = await this.repository.updateById(dto._id, updates);
189
112
  if (!result)
190
113
  throw (0, error_common_1.notFoundError)('Campaign not found after update');
191
114
  await this.rescheduleIfDatesChanged(dto._id, result.status, campaign, dto);
192
- return result.toObject();
115
+ return result;
193
116
  }
194
117
  async cancel(campaignId) {
195
- const campaign = await this.model.findById(campaignId);
118
+ const campaign = await this.repository.findById(campaignId);
196
119
  if (!campaign)
197
120
  throw (0, error_common_1.notFoundError)('Campaign not found');
198
121
  this.assertEditable(campaign.status);
@@ -202,42 +125,6 @@ let LtoCampaignService = class LtoCampaignService {
202
125
  }
203
126
  await this.lifecycle.cancelCampaign(campaignId);
204
127
  }
205
- async getParticipants(dto) {
206
- const query = { campaign: dto.campaignId, isWithdrawn: false };
207
- const search = dto.search?.trim();
208
- if (search) {
209
- const matchingShops = await models_1.ShopModel.find({ name: { $regex: search, $options: 'i' } }).select('_id');
210
- const matchingShopIds = matchingShops.map(shop => shop._id);
211
- if (matchingShopIds.length === 0) {
212
- return {
213
- documents: [],
214
- metadata: { page: dto.page, size: dto.size, totalElements: 0, totalPages: 0 },
215
- };
216
- }
217
- query.shop = { $in: matchingShopIds };
218
- }
219
- const [total, participants] = await Promise.all([
220
- models_1.LimitedTimeOfferParticipantModel.countDocuments(query),
221
- models_1.LimitedTimeOfferParticipantModel.find(query)
222
- .populate('shop', 'name logo')
223
- .sort({ joinedAt: -1 })
224
- .skip((dto.page - 1) * dto.size)
225
- .limit(dto.size),
226
- ]);
227
- return {
228
- documents: participants.map(p => {
229
- const raw = p.toObject();
230
- return {
231
- shopName: raw.shop?.name ?? null,
232
- shopPhoto: raw.shop?.logo ?? null,
233
- joinedAt: raw.joinedAt,
234
- discountPercentage: raw.discountPercentage,
235
- maxDiscountCap: raw.maxDiscountCap,
236
- };
237
- }),
238
- metadata: { page: dto.page, size: dto.size, totalElements: total, totalPages: Math.ceil(total / dto.size) },
239
- };
240
- }
241
128
  assertUpdateAllowed(campaign, dto) {
242
129
  this.assertEditable(campaign.status);
243
130
  if (campaign.status === enum_1.LimitedTimeOfferCampaignStatus.ACTIVE && !dto.confirmActive) {
@@ -247,24 +134,17 @@ let LtoCampaignService = class LtoCampaignService {
247
134
  throw (0, error_common_1.badRequestError)('Start date cannot be in the past.');
248
135
  }
249
136
  }
250
- buildCampaignUpdates(campaign, dto) {
251
- return {
252
- title: dto.title ?? campaign.title,
253
- subTitle: dto.subTitle ?? campaign.subTitle,
254
- startDate: dto.startDate,
255
- endDate: dto.endDate,
256
- ...(dto.discountOptions && { discountOptions: dto.discountOptions }),
257
- ...(dto.maxDiscountCaps && { maxDiscountCaps: dto.maxDiscountCaps }),
258
- };
259
- }
260
137
  shouldExpireImmediately(status, endDate) {
261
138
  return status === enum_1.LimitedTimeOfferCampaignStatus.ACTIVE && endDate <= new Date();
262
139
  }
263
140
  async applyImmediateExpiry(campaignId, updates) {
264
141
  await this.scheduler.cancelJobs(campaignId);
265
- await this.model.findByIdAndUpdate(campaignId, { $set: updates });
142
+ await this.repository.updateById(campaignId, updates);
266
143
  await this.lifecycle.expireCampaign(campaignId);
267
- return (await this.model.findById(campaignId)).toObject();
144
+ const result = await this.repository.findById(campaignId);
145
+ if (!result)
146
+ throw (0, error_common_1.notFoundError)('Campaign not found after expiry');
147
+ return result;
268
148
  }
269
149
  async rescheduleIfDatesChanged(campaignId, currentStatus, original, dto) {
270
150
  const datesChanged = dto.startDate.getTime() !== original.startDate.getTime() ||
@@ -278,9 +158,9 @@ let LtoCampaignService = class LtoCampaignService {
278
158
  await this.scheduler.scheduleExpiry(campaignId, dto.endDate);
279
159
  }
280
160
  async assertNoCampaignRunning() {
281
- const exists = await this.model.exists({ status: { $in: ACTIVE_STATUSES } });
282
- if (exists)
161
+ if (await this.repository.hasActiveCampaign()) {
283
162
  throw (0, error_common_1.conflictError)('A campaign is already scheduled or active. Delete it before creating a new one.');
163
+ }
284
164
  }
285
165
  assertEditable(status) {
286
166
  if (!ACTIVE_STATUSES.includes(status)) {
@@ -288,16 +168,13 @@ let LtoCampaignService = class LtoCampaignService {
288
168
  }
289
169
  }
290
170
  async loadConfigSnapshot() {
291
- const config = await models_1.LimitedTimeOfferConfigModel.findOne({ campaignType: enum_1.MarketingType.DISCOUNT });
292
- if (!config || config.discountOptions.length === 0 || config.maxDiscountCaps.length === 0) {
171
+ const config = await this.configService.getByType(enum_1.MarketingType.DISCOUNT)
172
+ .catch(() => { throw (0, error_common_1.badRequestError)('Global config is incomplete. Set discount options and max caps first.'); });
173
+ if (config.discountOptions.length === 0 || config.maxDiscountCaps.length === 0) {
293
174
  throw (0, error_common_1.badRequestError)('Global config is incomplete. Set discount options and max caps first.');
294
175
  }
295
176
  return config;
296
177
  }
297
- async nextCampaignNumber() {
298
- const counter = await models_1.CounterModel.findOneAndUpdate({ counterType: enum_1.CounterType.LTO_CAMPAIGN }, { $inc: { value: 1 } }, { upsert: true, new: true, setDefaultsOnInsert: true });
299
- return counter.value;
300
- }
301
178
  };
302
179
  exports.LtoCampaignService = LtoCampaignService;
303
180
  exports.LtoCampaignService = LtoCampaignService = __decorate([
@@ -1 +1 @@
1
- {"version":3,"file":"limited-time-offer-campaign.service.js","sourceRoot":"/","sources":["modules/limited-time-offer/campaign/services/limited-time-offer-campaign.service.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,iDAA0C;AAE1C,sEAOmD;AAEnD,4DAA6G;AAC7G,4EAAwG;AAOxG,mHAA4F;AAC5F,mHAA4F;AAC5F,wKAAiJ;AAEjJ,MAAM,eAAe,GAAG,CAAC,qCAA8B,CAAC,SAAS,EAAE,qCAA8B,CAAC,MAAM,CAAC,CAAC;AAC1G,MAAM,iBAAiB,GAAG,CAAC,qCAA8B,CAAC,OAAO,EAAE,qCAA8B,CAAC,SAAS,CAAC,CAAC;AAGtG,IAAM,kBAAkB,GAAxB,MAAM,kBAAkB;IACnB,KAAK,CAAgE;IACrE,SAAS,CAA8B;IACvC,SAAS,CAA8B;IACvC,oBAAoB,CAAiC;IAE7D;QACI,IAAI,CAAC,KAAK,GAAG,sCAA8F,CAAC;QAC5G,IAAI,CAAC,SAAS,GAAG,gBAAS,CAAC,GAAG,CAAC,2EAA2B,CAAC,CAAC;QAC5D,IAAI,CAAC,SAAS,GAAG,gBAAS,CAAC,GAAG,CAAC,2EAA2B,CAAC,CAAC;QAC5D,IAAI,CAAC,oBAAoB,GAAG,gBAAS,CAAC,GAAG,CAAC,iFAA8B,CAAC,CAAC;IAC9E,CAAC;IAEM,KAAK,CAAC,MAAM,CAAC,GAAyB;QACzC,MAAM,IAAI,CAAC,uBAAuB,EAAE,CAAC;QAErC,MAAM,GAAG,GAAG,IAAI,IAAI,EAAE,CAAC;QAEvB,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,kBAAkB,EAAE,CAAC;QAC/C,MAAM,MAAM,GAAG,GAAG,CAAC,SAAS,IAAI,GAAG;YAC/B,CAAC,CAAC,qCAA8B,CAAC,MAAM;YACvC,CAAC,CAAC,qCAA8B,CAAC,SAAS,CAAC;QAE/C,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC;YACrC,cAAc,EAAE,MAAM,IAAI,CAAC,kBAAkB,EAAE;YAC/C,KAAK,EAAE,GAAG,CAAC,KAAK;YAChB,QAAQ,EAAE,GAAG,CAAC,QAAQ;YACtB,SAAS,EAAE,GAAG,CAAC,SAAS;YACxB,OAAO,EAAE,GAAG,CAAC,OAAO;YACpB,MAAM;YACN,eAAe,EAAE,MAAM,CAAC,eAAe;YACvC,eAAe,EAAE,MAAM,CAAC,eAAe;SAC1C,CAAC,CAAC;QAEH,MAAM,UAAU,GAAG,QAAQ,CAAC,GAAG,CAAC;QAChC,IAAI,MAAM,KAAK,qCAA8B,CAAC,SAAS,EAAE,CAAC;YACtD,MAAM,IAAI,CAAC,SAAS,CAAC,kBAAkB,CAAC,UAAU,EAAE,GAAG,CAAC,SAAS,CAAC,CAAC;QACvE,CAAC;QACD,MAAM,IAAI,CAAC,SAAS,CAAC,cAAc,CAAC,UAAU,EAAE,GAAG,CAAC,OAAO,CAAC,CAAC;QAE7D,OAAO,QAAQ,CAAC,QAAQ,EAAE,CAAC;IAC/B,CAAC;IAEM,KAAK,CAAC,UAAU;QACnB,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,KAAK;aAC5B,OAAO,CAAC,EAAC,MAAM,EAAE,EAAC,GAAG,EAAE,eAAe,EAAC,EAAC,CAAC;aACzC,IAAI,CAAC,EAAC,SAAS,EAAE,CAAC,CAAC,EAAC,CAAC,CAAC;QAC3B,OAAO,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;IACjD,CAAC;IAEM,KAAK,CAAC,iBAAiB;QAC1B,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,KAAK;aAC5B,OAAO,CAAC,EAAC,MAAM,EAAE,qCAA8B,CAAC,MAAM,EAAC,CAAC;aACxD,IAAI,CAAC,EAAC,SAAS,EAAE,CAAC,CAAC,EAAC,CAAC,CAAC;QAC3B,OAAO,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;IACjD,CAAC;IAEM,KAAK,CAAC,OAAO,CAAC,UAAmC;QACpD,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAC;QACvD,IAAI,CAAC,QAAQ;YAAE,MAAM,IAAA,4BAAa,EAAC,oBAAoB,CAAC,CAAC;QACzD,OAAO,QAAQ,CAAC,QAAQ,EAAE,CAAC;IAC/B,CAAC;IAEM,KAAK,CAAC,UAAU,CAAC,GAA6B;QACjD,MAAM,KAAK,GAAwB,GAAG,CAAC,MAAM;YACzC,CAAC,CAAC,EAAC,MAAM,EAAE,GAAG,CAAC,MAAM,EAAC;YACtB,CAAC,CAAC,EAAC,MAAM,EAAE,EAAC,GAAG,EAAE,iBAAiB,EAAC,EAAC,CAAC;QACzC,MAAM,YAAY,GAA2B;YACzC,EAAE,EAAE,KAAK;YACT,cAAc,EAAE,gBAAgB;YAChC,aAAa,EAAE,WAAW;YAC1B,WAAW,EAAE,SAAS;YACtB,WAAW,EAAE,aAAa;YAC1B,MAAM,EAAE,QAAQ;SACnB,CAAC;QACF,MAAM,SAAS,GAAG,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,YAAY,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC;QACtE,MAAM,aAAa,GAAG,GAAG,CAAC,SAAS,KAAK,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QACvD,MAAM,qBAAqB,GAAG,yCAAgC,CAAC,UAAU,CAAC,IAAI,CAAC;QAC/E,MAAM,CAAC,KAAK,EAAE,SAAS,CAAC,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC;YACzC,IAAI,CAAC,KAAK,CAAC,cAAc,CAAC,KAAK,CAAC;YAChC,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC;gBACjB,EAAC,MAAM,EAAE,KAAK,EAAC;gBACf;oBACI,OAAO,EAAE;wBACL,IAAI,EAAE,qBAAqB;wBAC3B,GAAG,EAAE,EAAC,UAAU,EAAE,MAAM,EAAC;wBACzB,QAAQ,EAAE;4BACN;gCACI,MAAM,EAAE;oCACJ,KAAK,EAAE;wCACH,IAAI,EAAE;4CACF,EAAC,GAAG,EAAE,CAAC,WAAW,EAAE,cAAc,CAAC,EAAC;4CACpC,EAAC,GAAG,EAAE,CAAC,cAAc,EAAE,KAAK,CAAC,EAAC;yCACjC;qCACJ;iCACJ;6BACJ;4BACD,EAAC,MAAM,EAAE,OAAO,EAAC;yBACpB;wBACD,EAAE,EAAE,aAAa;qBACpB;iBACJ;gBACD;oBACI,UAAU,EAAE;wBACR,WAAW,EAAE,EAAC,OAAO,EAAE,CAAC,EAAC,YAAY,EAAE,CAAC,oBAAoB,EAAE,CAAC,CAAC,EAAC,EAAE,CAAC,CAAC,EAAC;qBACzE;iBACJ;gBACD,EAAC,KAAK,EAAE,EAAC,CAAC,SAAS,CAAC,EAAE,aAAa,EAAE,GAAG,EAAE,aAAa,EAAC,EAAC;gBACzD;oBACI,QAAQ,EAAE;wBACN,GAAG,EAAE,CAAC;wBACN,cAAc,EAAE,CAAC;wBACjB,SAAS,EAAE,CAAC;wBACZ,OAAO,EAAE,CAAC;wBACV,MAAM,EAAE,CAAC;wBACT,WAAW,EAAE,CAAC;qBACjB;iBACJ;gBACD,EAAC,KAAK,EAAE,CAAC,GAAG,CAAC,IAAI,GAAG,CAAC,CAAC,GAAG,GAAG,CAAC,IAAI,EAAC;gBAClC,EAAC,MAAM,EAAE,GAAG,CAAC,IAAI,EAAC;aACrB,CAAC;SACL,CAAC,CAAC;QAEH,OAAO;YACH,SAAS,EAAE,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;gBAC3B,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,QAAQ,EAAE;gBACpB,cAAc,EAAE,CAAC,CAAC,cAAc;gBAChC,aAAa,EAAE,CAAC,CAAC,SAAS;gBAC1B,WAAW,EAAE,CAAC,CAAC,OAAO;gBACtB,WAAW,EAAE,CAAC,CAAC,WAAW;gBAC1B,MAAM,EAAE,CAAC,CAAC,MAAM;aACnB,CAAC,CAAC;YACH,QAAQ,EAAE,EAAC,IAAI,EAAE,GAAG,CAAC,IAAI,EAAE,IAAI,EAAE,GAAG,CAAC,IAAI,EAAE,aAAa,EAAE,KAAK,EAAE,UAAU,EAAE,IAAI,CAAC,IAAI,CAAC,KAAK,GAAG,GAAG,CAAC,IAAI,CAAC,EAAC;SAC5G,CAAC;IACN,CAAC;IAEM,KAAK,CAAC,MAAM,CAAC,GAAyB;QACzC,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QACpD,IAAI,CAAC,QAAQ;YAAE,MAAM,IAAA,4BAAa,EAAC,oBAAoB,CAAC,CAAC;QAEzD,IAAI,CAAC,mBAAmB,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAC;QAExC,MAAM,OAAO,GAAG,IAAI,CAAC,oBAAoB,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAC;QAEzD,IAAI,IAAI,CAAC,uBAAuB,CAAC,QAAQ,CAAC,MAAM,EAAE,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC;YAC7D,OAAO,IAAI,CAAC,oBAAoB,CAAC,GAAG,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC;QACvD,CAAC;QAED,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC,iBAAiB,CAAC,GAAG,CAAC,GAAG,EAAE,EAAC,IAAI,EAAE,OAAO,EAAC,EAAE,EAAC,GAAG,EAAE,IAAI,EAAC,CAAC,CAAC;QACzF,IAAI,CAAC,MAAM;YAAE,MAAM,IAAA,4BAAa,EAAC,iCAAiC,CAAC,CAAC;QAEpE,MAAM,IAAI,CAAC,wBAAwB,CAAC,GAAG,CAAC,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,QAAQ,EAAE,GAAG,CAAC,CAAC;QAE3E,OAAO,MAAM,CAAC,QAAQ,EAAE,CAAC;IAC7B,CAAC;IAEM,KAAK,CAAC,MAAM,CAAC,UAAmC;QACnD,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAC;QACvD,IAAI,CAAC,QAAQ;YAAE,MAAM,IAAA,4BAAa,EAAC,oBAAoB,CAAC,CAAC;QAEzD,IAAI,CAAC,cAAc,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;QACrC,MAAM,IAAI,CAAC,SAAS,CAAC,UAAU,CAAC,UAAU,CAAC,CAAC;QAE5C,IAAI,QAAQ,CAAC,MAAM,KAAK,qCAA8B,CAAC,MAAM,EAAE,CAAC;YAC5D,MAAM,IAAI,CAAC,oBAAoB,CAAC,2BAA2B,CAAC,UAAU,CAAC,CAAC;QAC5E,CAAC;QAED,MAAM,IAAI,CAAC,SAAS,CAAC,cAAc,CAAC,UAAU,CAAC,CAAC;IACpD,CAAC;IAEM,KAAK,CAAC,eAAe,CAAC,GAAkC;QAC3D,MAAM,KAAK,GAAwB,EAAC,QAAQ,EAAE,GAAG,CAAC,UAAU,EAAE,WAAW,EAAE,KAAK,EAAC,CAAC;QAClF,MAAM,MAAM,GAAG,GAAG,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC;QAElC,IAAI,MAAM,EAAE,CAAC;YACT,MAAM,aAAa,GAAG,MAAM,kBAAS,CAAC,IAAI,CAAC,EAAC,IAAI,EAAE,EAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,GAAG,EAAC,EAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;YAClG,MAAM,eAAe,GAAG,aAAa,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;YAE5D,IAAI,eAAe,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;gBAC/B,OAAO;oBACH,SAAS,EAAE,EAAE;oBACb,QAAQ,EAAE,EAAC,IAAI,EAAE,GAAG,CAAC,IAAI,EAAE,IAAI,EAAE,GAAG,CAAC,IAAI,EAAE,aAAa,EAAE,CAAC,EAAE,UAAU,EAAE,CAAC,EAAC;iBAC9E,CAAC;YACN,CAAC;YAED,KAAK,CAAC,IAAI,GAAG,EAAC,GAAG,EAAE,eAAe,EAAC,CAAC;QACxC,CAAC;QAED,MAAM,CAAC,KAAK,EAAE,YAAY,CAAC,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC;YAC5C,yCAAgC,CAAC,cAAc,CAAC,KAAK,CAAC;YACtD,yCAAgC,CAAC,IAAI,CAAC,KAAK,CAAC;iBACvC,QAAQ,CAAC,MAAM,EAAE,WAAW,CAAC;iBAC7B,IAAI,CAAC,EAAC,QAAQ,EAAE,CAAC,CAAC,EAAC,CAAC;iBACpB,IAAI,CAAC,CAAC,GAAG,CAAC,IAAI,GAAG,CAAC,CAAC,GAAG,GAAG,CAAC,IAAI,CAAC;iBAC/B,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC;SACvB,CAAC,CAAC;QAEH,OAAO;YACH,SAAS,EAAE,YAAY,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE;gBAC5B,MAAM,GAAG,GAAG,CAAC,CAAC,QAAQ,EAAS,CAAC;gBAChC,OAAO;oBACH,QAAQ,EAAE,GAAG,CAAC,IAAI,EAAE,IAAI,IAAI,IAAI;oBAChC,SAAS,EAAE,GAAG,CAAC,IAAI,EAAE,IAAI,IAAI,IAAI;oBACjC,QAAQ,EAAE,GAAG,CAAC,QAAQ;oBACtB,kBAAkB,EAAE,GAAG,CAAC,kBAAkB;oBAC1C,cAAc,EAAE,GAAG,CAAC,cAAc;iBACrC,CAAC;YACN,CAAC,CAAC;YACF,QAAQ,EAAE,EAAC,IAAI,EAAE,GAAG,CAAC,IAAI,EAAE,IAAI,EAAE,GAAG,CAAC,IAAI,EAAE,aAAa,EAAE,KAAK,EAAE,UAAU,EAAE,IAAI,CAAC,IAAI,CAAC,KAAK,GAAG,GAAG,CAAC,IAAI,CAAC,EAAC;SAC5G,CAAC;IACN,CAAC;IAEO,mBAAmB,CAAC,QAAe,EAAE,GAAyB;QAClE,IAAI,CAAC,cAAc,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;QAErC,IAAI,QAAQ,CAAC,MAAM,KAAK,qCAA8B,CAAC,MAAM,IAAI,CAAC,GAAG,CAAC,aAAa,EAAE,CAAC;YAClF,MAAM,IAAA,8BAAe,EAAC,4DAA4D,CAAC,CAAC;QACxF,CAAC;QAED,IAAI,GAAG,CAAC,SAAS,GAAG,IAAI,IAAI,EAAE,IAAI,QAAQ,CAAC,MAAM,KAAK,qCAA8B,CAAC,SAAS,EAAE,CAAC;YAC7F,MAAM,IAAA,8BAAe,EAAC,mCAAmC,CAAC,CAAC;QAC/D,CAAC;IACL,CAAC;IAEO,oBAAoB,CAAC,QAAe,EAAE,GAAyB;QACnE,OAAO;YACH,KAAK,EAAE,GAAG,CAAC,KAAK,IAAI,QAAQ,CAAC,KAAK;YAClC,QAAQ,EAAE,GAAG,CAAC,QAAQ,IAAI,QAAQ,CAAC,QAAQ;YAC3C,SAAS,EAAE,GAAG,CAAC,SAAS;YACxB,OAAO,EAAE,GAAG,CAAC,OAAO;YACpB,GAAG,CAAC,GAAG,CAAC,eAAe,IAAI,EAAC,eAAe,EAAE,GAAG,CAAC,eAAe,EAAC,CAAC;YAClE,GAAG,CAAC,GAAG,CAAC,eAAe,IAAI,EAAC,eAAe,EAAE,GAAG,CAAC,eAAe,EAAC,CAAC;SACrE,CAAC;IACN,CAAC;IAEO,uBAAuB,CAAC,MAAsC,EAAE,OAAa;QACjF,OAAO,MAAM,KAAK,qCAA8B,CAAC,MAAM,IAAI,OAAO,IAAI,IAAI,IAAI,EAAE,CAAC;IACrF,CAAC;IAEO,KAAK,CAAC,oBAAoB,CAAC,UAAmC,EAAE,OAA4B;QAChG,MAAM,IAAI,CAAC,SAAS,CAAC,UAAU,CAAC,UAAU,CAAC,CAAC;QAC5C,MAAM,IAAI,CAAC,KAAK,CAAC,iBAAiB,CAAC,UAAU,EAAE,EAAC,IAAI,EAAE,OAAO,EAAC,CAAC,CAAC;QAChE,MAAM,IAAI,CAAC,SAAS,CAAC,cAAc,CAAC,UAAU,CAAC,CAAC;QAChD,OAAO,CAAC,MAAM,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAE,CAAC,QAAQ,EAAE,CAAC;IAC/D,CAAC;IAEO,KAAK,CAAC,wBAAwB,CAClC,UAAmC,EACnC,aAA6C,EAC7C,QAAe,EACf,GAAyB;QAEzB,MAAM,YAAY,GACd,GAAG,CAAC,SAAS,CAAC,OAAO,EAAE,KAAK,QAAQ,CAAC,SAAS,CAAC,OAAO,EAAE;YACxD,GAAG,CAAC,OAAO,CAAC,OAAO,EAAE,KAAK,QAAQ,CAAC,OAAO,CAAC,OAAO,EAAE,CAAC;QAEzD,IAAI,CAAC,YAAY;YAAE,OAAO;QAE1B,MAAM,IAAI,CAAC,SAAS,CAAC,UAAU,CAAC,UAAU,CAAC,CAAC;QAC5C,IAAI,aAAa,KAAK,qCAA8B,CAAC,SAAS,EAAE,CAAC;YAC7D,MAAM,IAAI,CAAC,SAAS,CAAC,kBAAkB,CAAC,UAAU,EAAE,GAAG,CAAC,SAAS,CAAC,CAAC;QACvE,CAAC;QACD,MAAM,IAAI,CAAC,SAAS,CAAC,cAAc,CAAC,UAAU,EAAE,GAAG,CAAC,OAAO,CAAC,CAAC;IACjE,CAAC;IAEO,KAAK,CAAC,uBAAuB;QACjC,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,EAAC,MAAM,EAAE,EAAC,GAAG,EAAE,eAAe,EAAC,EAAC,CAAC,CAAC;QACzE,IAAI,MAAM;YAAE,MAAM,IAAA,4BAAa,EAAC,iFAAiF,CAAC,CAAC;IACvH,CAAC;IAEO,cAAc,CAAC,MAAsC;QACzD,IAAI,CAAC,eAAe,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC;YACpC,MAAM,IAAA,8BAAe,EAAC,qDAAqD,CAAC,CAAC;QACjF,CAAC;IACL,CAAC;IAEO,KAAK,CAAC,kBAAkB;QAC5B,MAAM,MAAM,GAAG,MAAM,oCAA2B,CAAC,OAAO,CAAC,EAAC,YAAY,EAAE,oBAAa,CAAC,QAAQ,EAAC,CAAC,CAAC;QACjG,IAAI,CAAC,MAAM,IAAI,MAAM,CAAC,eAAe,CAAC,MAAM,KAAK,CAAC,IAAI,MAAM,CAAC,eAAe,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACxF,MAAM,IAAA,8BAAe,EAAC,uEAAuE,CAAC,CAAC;QACnG,CAAC;QACD,OAAO,MAAM,CAAC;IAClB,CAAC;IAEO,KAAK,CAAC,kBAAkB;QAC5B,MAAM,OAAO,GAAG,MAAM,qBAAY,CAAC,gBAAgB,CAC/C,EAAC,WAAW,EAAE,kBAAW,CAAC,YAAY,EAAC,EACvC,EAAC,IAAI,EAAE,EAAC,KAAK,EAAE,CAAC,EAAC,EAAC,EAClB,EAAC,MAAM,EAAE,IAAI,EAAE,GAAG,EAAE,IAAI,EAAE,mBAAmB,EAAE,IAAI,EAAC,CACvD,CAAC;QACF,OAAO,OAAO,CAAC,KAAK,CAAC;IACzB,CAAC;CACJ,CAAA;AApSY,gDAAkB;6BAAlB,kBAAkB;IAD9B,IAAA,gBAAO,GAAE;;GACG,kBAAkB,CAoS9B;AAEY,QAAA,kBAAkB,GAAG,gBAAS,CAAC,GAAG,CAAC,kBAAkB,CAAC,CAAC","sourcesContent":["import Container, {Service} from 'typedi';\nimport {mongoose} from '@typegoose/typegoose';\nimport {\n CounterModel,\n LimitedTimeOfferCampaign as Model,\n LimitedTimeOfferCampaignModel,\n LimitedTimeOfferConfigModel,\n LimitedTimeOfferParticipantModel,\n ShopModel,\n} from '@lyxa.ai/core/dist/libraries/mongo/models';\nimport {SoftDeleteModel} from '@lyxa.ai/core/dist/libraries/mongo/plugins/soft-delete-plugin';\nimport {CounterType, LimitedTimeOfferCampaignStatus, MarketingType} from '@lyxa.ai/core/dist/utilities/enum';\nimport {badRequestError, conflictError, notFoundError} from '@lyxa.ai/core/dist/utilities/error-common';\nimport {\n CreateLtoCampaignDTO,\n GetLtoCampaignHistoryDTO,\n GetLtoCampaignParticipantsDTO,\n UpdateLtoCampaignDTO,\n} from '../limited-time-offer-campaign.validation';\nimport {LtoCampaignLifecycleService} from './limited-time-offer-campaign-lifecycle.service';\nimport {LtoCampaignSchedulerService} from './limited-time-offer-campaign-scheduler.service';\nimport {LtoParticipantMarketingService} from '@modules/limited-time-offer/participant/services/limited-time-offer-participant-marketing.service';\n\nconst ACTIVE_STATUSES = [LimitedTimeOfferCampaignStatus.SCHEDULED, LimitedTimeOfferCampaignStatus.ACTIVE];\nconst ARCHIVED_STATUSES = [LimitedTimeOfferCampaignStatus.EXPIRED, LimitedTimeOfferCampaignStatus.CANCELLED];\n\n@Service()\nexport class LtoCampaignService {\n private model: typeof LimitedTimeOfferCampaignModel & SoftDeleteModel<Model>;\n private scheduler: LtoCampaignSchedulerService;\n private lifecycle: LtoCampaignLifecycleService;\n private participantMarketing: LtoParticipantMarketingService;\n\n constructor() {\n this.model = LimitedTimeOfferCampaignModel as typeof LimitedTimeOfferCampaignModel & SoftDeleteModel<Model>;\n this.scheduler = Container.get(LtoCampaignSchedulerService);\n this.lifecycle = Container.get(LtoCampaignLifecycleService);\n this.participantMarketing = Container.get(LtoParticipantMarketingService);\n }\n\n public async create(dto: CreateLtoCampaignDTO) {\n await this.assertNoCampaignRunning();\n\n const now = new Date();\n\n const config = await this.loadConfigSnapshot();\n const status = dto.startDate <= now\n ? LimitedTimeOfferCampaignStatus.ACTIVE\n : LimitedTimeOfferCampaignStatus.SCHEDULED;\n\n const campaign = await this.model.create({\n campaignNumber: await this.nextCampaignNumber(),\n title: dto.title,\n subTitle: dto.subTitle,\n startDate: dto.startDate,\n endDate: dto.endDate,\n status,\n discountOptions: config.discountOptions,\n maxDiscountCaps: config.maxDiscountCaps,\n });\n\n const campaignId = campaign._id;\n if (status === LimitedTimeOfferCampaignStatus.SCHEDULED) {\n await this.scheduler.scheduleActivation(campaignId, dto.startDate);\n }\n await this.scheduler.scheduleExpiry(campaignId, dto.endDate);\n\n return campaign.toObject();\n }\n\n public async getCurrent() {\n const campaign = await this.model\n .findOne({status: {$in: ACTIVE_STATUSES}})\n .sort({createdAt: -1});\n return campaign ? campaign.toObject() : null;\n }\n\n public async getActiveCampaign() {\n const campaign = await this.model\n .findOne({status: LimitedTimeOfferCampaignStatus.ACTIVE})\n .sort({createdAt: -1});\n return campaign ? campaign.toObject() : null;\n }\n\n public async getById(campaignId: mongoose.Types.ObjectId) {\n const campaign = await this.model.findById(campaignId);\n if (!campaign) throw notFoundError('Campaign not found');\n return campaign.toObject();\n }\n\n public async getHistory(dto: GetLtoCampaignHistoryDTO) {\n const query: Record<string, any> = dto.status\n ? {status: dto.status}\n : {status: {$in: ARCHIVED_STATUSES}};\n const sortFieldMap: Record<string, string> = {\n id: '_id',\n campaignNumber: 'campaignNumber',\n startDateTime: 'startDate',\n endDateTime: 'endDate',\n shopsJoined: 'shopsJoined',\n status: 'status',\n };\n const sortField = dto.sortBy ? sortFieldMap[dto.sortBy] : 'createdAt';\n const sortDirection = dto.sortOrder === 'asc' ? 1 : -1;\n const participantCollection = LimitedTimeOfferParticipantModel.collection.name;\n const [total, documents] = await Promise.all([\n this.model.countDocuments(query),\n this.model.aggregate([\n {$match: query},\n {\n $lookup: {\n from: participantCollection,\n let: {campaignId: '$_id'},\n pipeline: [\n {\n $match: {\n $expr: {\n $and: [\n {$eq: ['$campaign', '$$campaignId']},\n {$eq: ['$isWithdrawn', false]},\n ],\n },\n },\n },\n {$count: 'count'},\n ],\n as: 'joinedStats',\n },\n },\n {\n $addFields: {\n shopsJoined: {$ifNull: [{$arrayElemAt: ['$joinedStats.count', 0]}, 0]},\n },\n },\n {$sort: {[sortField]: sortDirection, _id: sortDirection}},\n {\n $project: {\n _id: 1,\n campaignNumber: 1,\n startDate: 1,\n endDate: 1,\n status: 1,\n shopsJoined: 1,\n },\n },\n {$skip: (dto.page - 1) * dto.size},\n {$limit: dto.size},\n ]),\n ]);\n\n return {\n documents: documents.map(d => ({\n id: d._id.toString(),\n campaignNumber: d.campaignNumber,\n startDateTime: d.startDate,\n endDateTime: d.endDate,\n shopsJoined: d.shopsJoined,\n status: d.status,\n })),\n metadata: {page: dto.page, size: dto.size, totalElements: total, totalPages: Math.ceil(total / dto.size)},\n };\n }\n\n public async update(dto: UpdateLtoCampaignDTO) {\n const campaign = await this.model.findById(dto._id);\n if (!campaign) throw notFoundError('Campaign not found');\n\n this.assertUpdateAllowed(campaign, dto);\n\n const updates = this.buildCampaignUpdates(campaign, dto);\n\n if (this.shouldExpireImmediately(campaign.status, dto.endDate)) {\n return this.applyImmediateExpiry(dto._id, updates);\n }\n\n const result = await this.model.findByIdAndUpdate(dto._id, {$set: updates}, {new: true});\n if (!result) throw notFoundError('Campaign not found after update');\n\n await this.rescheduleIfDatesChanged(dto._id, result.status, campaign, dto);\n\n return result.toObject();\n }\n\n public async cancel(campaignId: mongoose.Types.ObjectId) {\n const campaign = await this.model.findById(campaignId);\n if (!campaign) throw notFoundError('Campaign not found');\n\n this.assertEditable(campaign.status);\n await this.scheduler.cancelJobs(campaignId);\n\n if (campaign.status === LimitedTimeOfferCampaignStatus.ACTIVE) {\n await this.participantMarketing.removeAllCampaignMarketings(campaignId);\n }\n\n await this.lifecycle.cancelCampaign(campaignId);\n }\n\n public async getParticipants(dto: GetLtoCampaignParticipantsDTO) {\n const query: Record<string, any> = {campaign: dto.campaignId, isWithdrawn: false};\n const search = dto.search?.trim();\n\n if (search) {\n const matchingShops = await ShopModel.find({name: {$regex: search, $options: 'i'}}).select('_id');\n const matchingShopIds = matchingShops.map(shop => shop._id);\n\n if (matchingShopIds.length === 0) {\n return {\n documents: [],\n metadata: {page: dto.page, size: dto.size, totalElements: 0, totalPages: 0},\n };\n }\n\n query.shop = {$in: matchingShopIds};\n }\n\n const [total, participants] = await Promise.all([\n LimitedTimeOfferParticipantModel.countDocuments(query),\n LimitedTimeOfferParticipantModel.find(query)\n .populate('shop', 'name logo')\n .sort({joinedAt: -1})\n .skip((dto.page - 1) * dto.size)\n .limit(dto.size),\n ]);\n\n return {\n documents: participants.map(p => {\n const raw = p.toObject() as any;\n return {\n shopName: raw.shop?.name ?? null,\n shopPhoto: raw.shop?.logo ?? null,\n joinedAt: raw.joinedAt,\n discountPercentage: raw.discountPercentage,\n maxDiscountCap: raw.maxDiscountCap,\n };\n }),\n metadata: {page: dto.page, size: dto.size, totalElements: total, totalPages: Math.ceil(total / dto.size)},\n };\n }\n\n private assertUpdateAllowed(campaign: Model, dto: UpdateLtoCampaignDTO): void {\n this.assertEditable(campaign.status);\n\n if (campaign.status === LimitedTimeOfferCampaignStatus.ACTIVE && !dto.confirmActive) {\n throw badRequestError('Set confirmActive=true to confirm editing a live campaign.');\n }\n\n if (dto.startDate < new Date() && campaign.status === LimitedTimeOfferCampaignStatus.SCHEDULED) {\n throw badRequestError('Start date cannot be in the past.');\n }\n }\n\n private buildCampaignUpdates(campaign: Model, dto: UpdateLtoCampaignDTO): Record<string, any> {\n return {\n title: dto.title ?? campaign.title,\n subTitle: dto.subTitle ?? campaign.subTitle,\n startDate: dto.startDate,\n endDate: dto.endDate,\n ...(dto.discountOptions && {discountOptions: dto.discountOptions}),\n ...(dto.maxDiscountCaps && {maxDiscountCaps: dto.maxDiscountCaps}),\n };\n }\n\n private shouldExpireImmediately(status: LimitedTimeOfferCampaignStatus, endDate: Date): boolean {\n return status === LimitedTimeOfferCampaignStatus.ACTIVE && endDate <= new Date();\n }\n\n private async applyImmediateExpiry(campaignId: mongoose.Types.ObjectId, updates: Record<string, any>) {\n await this.scheduler.cancelJobs(campaignId);\n await this.model.findByIdAndUpdate(campaignId, {$set: updates});\n await this.lifecycle.expireCampaign(campaignId);\n return (await this.model.findById(campaignId))!.toObject();\n }\n\n private async rescheduleIfDatesChanged(\n campaignId: mongoose.Types.ObjectId,\n currentStatus: LimitedTimeOfferCampaignStatus,\n original: Model,\n dto: UpdateLtoCampaignDTO,\n ): Promise<void> {\n const datesChanged =\n dto.startDate.getTime() !== original.startDate.getTime() ||\n dto.endDate.getTime() !== original.endDate.getTime();\n\n if (!datesChanged) return;\n\n await this.scheduler.cancelJobs(campaignId);\n if (currentStatus === LimitedTimeOfferCampaignStatus.SCHEDULED) {\n await this.scheduler.scheduleActivation(campaignId, dto.startDate);\n }\n await this.scheduler.scheduleExpiry(campaignId, dto.endDate);\n }\n\n private async assertNoCampaignRunning(): Promise<void> {\n const exists = await this.model.exists({status: {$in: ACTIVE_STATUSES}});\n if (exists) throw conflictError('A campaign is already scheduled or active. Delete it before creating a new one.');\n }\n\n private assertEditable(status: LimitedTimeOfferCampaignStatus): void {\n if (!ACTIVE_STATUSES.includes(status)) {\n throw badRequestError('Only SCHEDULED or ACTIVE campaigns can be modified.');\n }\n }\n\n private async loadConfigSnapshot() {\n const config = await LimitedTimeOfferConfigModel.findOne({campaignType: MarketingType.DISCOUNT});\n if (!config || config.discountOptions.length === 0 || config.maxDiscountCaps.length === 0) {\n throw badRequestError('Global config is incomplete. Set discount options and max caps first.');\n }\n return config;\n }\n\n private async nextCampaignNumber(): Promise<number> {\n const counter = await CounterModel.findOneAndUpdate(\n {counterType: CounterType.LTO_CAMPAIGN},\n {$inc: {value: 1}},\n {upsert: true, new: true, setDefaultsOnInsert: true}\n );\n return counter.value;\n }\n}\n\nexport const ltoCampaignService = Container.get(LtoCampaignService);\n"]}
1
+ {"version":3,"file":"limited-time-offer-campaign.service.js","sourceRoot":"/","sources":["modules/limited-time-offer/campaign/services/limited-time-offer-campaign.service.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,iDAA0C;AAG1C,4DAAgG;AAChG,4EAAwG;AAMxG,mHAA4F;AAC5F,mHAA4F;AAC5F,wKAAiJ;AACjJ,wIAAkH;AAClH,kIAAiH;AACjH,4HAAmH;AAEnH,MAAM,eAAe,GAAG,CAAC,qCAA8B,CAAC,SAAS,EAAE,qCAA8B,CAAC,MAAM,CAAC,CAAC;AAGnG,IAAM,kBAAkB,GAAxB,MAAM,kBAAkB;IACnB,UAAU,CAAwB;IAClC,SAAS,CAA8B;IACvC,SAAS,CAA8B;IACvC,oBAAoB,CAAiC;IACrD,aAAa,CAAgC;IAErD;QACI,IAAI,CAAC,UAAU,GAAG,gBAAS,CAAC,GAAG,CAAC,8DAAqB,CAAC,CAAC;QACvD,IAAI,CAAC,SAAS,GAAG,gBAAS,CAAC,GAAG,CAAC,2EAA2B,CAAC,CAAC;QAC5D,IAAI,CAAC,SAAS,GAAG,gBAAS,CAAC,GAAG,CAAC,2EAA2B,CAAC,CAAC;QAC5D,IAAI,CAAC,oBAAoB,GAAG,gBAAS,CAAC,GAAG,CAAC,iFAA8B,CAAC,CAAC;QAC1E,IAAI,CAAC,aAAa,GAAG,gBAAS,CAAC,GAAG,CAAC,iEAA6B,CAAC,CAAC;IACtE,CAAC;IAEM,KAAK,CAAC,MAAM,CAAC,GAAyB;QACzC,MAAM,IAAI,CAAC,uBAAuB,EAAE,CAAC;QAErC,MAAM,GAAG,GAAG,IAAI,IAAI,EAAE,CAAC;QACvB,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,kBAAkB,EAAE,CAAC;QAC/C,MAAM,MAAM,GAAG,GAAG,CAAC,SAAS,IAAI,GAAG;YAC/B,CAAC,CAAC,qCAA8B,CAAC,MAAM;YACvC,CAAC,CAAC,qCAA8B,CAAC,SAAS,CAAC;QAE/C,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,UAAU,CAAC,MAAM,CACzC,6DAAuB,CAAC,gBAAgB,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,IAAI,CAAC,UAAU,CAAC,kBAAkB,EAAE,EAAE,MAAM,CAAC,CAC5G,CAAC;QAEF,IAAI,MAAM,KAAK,qCAA8B,CAAC,SAAS,EAAE,CAAC;YACtD,MAAM,IAAI,CAAC,SAAS,CAAC,kBAAkB,CAAC,QAAQ,CAAC,GAAG,EAAE,GAAG,CAAC,SAAS,CAAC,CAAC;QACzE,CAAC;QACD,MAAM,IAAI,CAAC,SAAS,CAAC,cAAc,CAAC,QAAQ,CAAC,GAAG,EAAE,GAAG,CAAC,OAAO,CAAC,CAAC;QAE/D,OAAO,QAAQ,CAAC;IACpB,CAAC;IAEM,KAAK,CAAC,UAAU;QACnB,OAAO,IAAI,CAAC,UAAU,CAAC,WAAW,EAAE,CAAC;IACzC,CAAC;IAEM,KAAK,CAAC,SAAS;QAClB,OAAO,IAAI,CAAC,UAAU,CAAC,UAAU,EAAE,CAAC;IACxC,CAAC;IAEM,KAAK,CAAC,OAAO,CAAC,UAAmC;QACpD,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAC;QAC5D,IAAI,CAAC,QAAQ;YAAE,MAAM,IAAA,4BAAa,EAAC,oBAAoB,CAAC,CAAC;QACzD,OAAO,QAAQ,CAAC;IACpB,CAAC;IAEM,KAAK,CAAC,UAAU,CAAC,GAA6B;QACjD,MAAM,EAAC,SAAS,EAAE,KAAK,EAAC,GAAG,MAAM,IAAI,CAAC,UAAU,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC;QAClE,OAAO;YACH,SAAS;YACT,QAAQ,EAAE,EAAC,IAAI,EAAE,GAAG,CAAC,IAAI,EAAE,IAAI,EAAE,GAAG,CAAC,IAAI,EAAE,aAAa,EAAE,KAAK,EAAE,UAAU,EAAE,IAAI,CAAC,IAAI,CAAC,KAAK,GAAG,GAAG,CAAC,IAAI,CAAC,EAAC;SAC5G,CAAC;IACN,CAAC;IAEM,KAAK,CAAC,MAAM,CAAC,GAAyB;QACzC,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QACzD,IAAI,CAAC,QAAQ;YAAE,MAAM,IAAA,4BAAa,EAAC,oBAAoB,CAAC,CAAC;QAEzD,IAAI,CAAC,mBAAmB,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAC;QAExC,MAAM,OAAO,GAAG,6DAAuB,CAAC,gBAAgB,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAC;QAExE,IAAI,IAAI,CAAC,uBAAuB,CAAC,QAAQ,CAAC,MAAM,EAAE,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC;YAC7D,OAAO,IAAI,CAAC,oBAAoB,CAAC,GAAG,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC;QACvD,CAAC;QAED,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,UAAU,CAAC,UAAU,CAAC,GAAG,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC;QAClE,IAAI,CAAC,MAAM;YAAE,MAAM,IAAA,4BAAa,EAAC,iCAAiC,CAAC,CAAC;QAEpE,MAAM,IAAI,CAAC,wBAAwB,CAAC,GAAG,CAAC,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,QAAQ,EAAE,GAAG,CAAC,CAAC;QAE3E,OAAO,MAAM,CAAC;IAClB,CAAC;IAEM,KAAK,CAAC,MAAM,CAAC,UAAmC;QACnD,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAC;QAC5D,IAAI,CAAC,QAAQ;YAAE,MAAM,IAAA,4BAAa,EAAC,oBAAoB,CAAC,CAAC;QAEzD,IAAI,CAAC,cAAc,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;QACrC,MAAM,IAAI,CAAC,SAAS,CAAC,UAAU,CAAC,UAAU,CAAC,CAAC;QAE5C,IAAI,QAAQ,CAAC,MAAM,KAAK,qCAA8B,CAAC,MAAM,EAAE,CAAC;YAC5D,MAAM,IAAI,CAAC,oBAAoB,CAAC,2BAA2B,CAAC,UAAU,CAAC,CAAC;QAC5E,CAAC;QAED,MAAM,IAAI,CAAC,SAAS,CAAC,cAAc,CAAC,UAAU,CAAC,CAAC;IACpD,CAAC;IAEO,mBAAmB,CAAC,QAA6B,EAAE,GAAyB;QAChF,IAAI,CAAC,cAAc,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;QAErC,IAAI,QAAQ,CAAC,MAAM,KAAK,qCAA8B,CAAC,MAAM,IAAI,CAAC,GAAG,CAAC,aAAa,EAAE,CAAC;YAClF,MAAM,IAAA,8BAAe,EAAC,4DAA4D,CAAC,CAAC;QACxF,CAAC;QAED,IAAI,GAAG,CAAC,SAAS,GAAG,IAAI,IAAI,EAAE,IAAI,QAAQ,CAAC,MAAM,KAAK,qCAA8B,CAAC,SAAS,EAAE,CAAC;YAC7F,MAAM,IAAA,8BAAe,EAAC,mCAAmC,CAAC,CAAC;QAC/D,CAAC;IACL,CAAC;IAEO,uBAAuB,CAAC,MAAsC,EAAE,OAAa;QACjF,OAAO,MAAM,KAAK,qCAA8B,CAAC,MAAM,IAAI,OAAO,IAAI,IAAI,IAAI,EAAE,CAAC;IACrF,CAAC;IAEO,KAAK,CAAC,oBAAoB,CAAC,UAAmC,EAAE,OAAe;QACnF,MAAM,IAAI,CAAC,SAAS,CAAC,UAAU,CAAC,UAAU,CAAC,CAAC;QAC5C,MAAM,IAAI,CAAC,UAAU,CAAC,UAAU,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC;QACtD,MAAM,IAAI,CAAC,SAAS,CAAC,cAAc,CAAC,UAAU,CAAC,CAAC;QAChD,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAC;QAC1D,IAAI,CAAC,MAAM;YAAE,MAAM,IAAA,4BAAa,EAAC,iCAAiC,CAAC,CAAC;QACpE,OAAO,MAAM,CAAC;IAClB,CAAC;IAEO,KAAK,CAAC,wBAAwB,CAClC,UAAmC,EACnC,aAA6C,EAC7C,QAA6B,EAC7B,GAAyB;QAEzB,MAAM,YAAY,GACd,GAAG,CAAC,SAAS,CAAC,OAAO,EAAE,KAAK,QAAQ,CAAC,SAAU,CAAC,OAAO,EAAE;YACzD,GAAG,CAAC,OAAO,CAAC,OAAO,EAAE,KAAK,QAAQ,CAAC,OAAQ,CAAC,OAAO,EAAE,CAAC;QAE1D,IAAI,CAAC,YAAY;YAAE,OAAO;QAE1B,MAAM,IAAI,CAAC,SAAS,CAAC,UAAU,CAAC,UAAU,CAAC,CAAC;QAC5C,IAAI,aAAa,KAAK,qCAA8B,CAAC,SAAS,EAAE,CAAC;YAC7D,MAAM,IAAI,CAAC,SAAS,CAAC,kBAAkB,CAAC,UAAU,EAAE,GAAG,CAAC,SAAS,CAAC,CAAC;QACvE,CAAC;QACD,MAAM,IAAI,CAAC,SAAS,CAAC,cAAc,CAAC,UAAU,EAAE,GAAG,CAAC,OAAO,CAAC,CAAC;IACjE,CAAC;IAEO,KAAK,CAAC,uBAAuB;QACjC,IAAI,MAAM,IAAI,CAAC,UAAU,CAAC,iBAAiB,EAAE,EAAE,CAAC;YAC5C,MAAM,IAAA,4BAAa,EAAC,iFAAiF,CAAC,CAAC;QAC3G,CAAC;IACL,CAAC;IAEO,cAAc,CAAC,MAAsC;QACzD,IAAI,CAAC,eAAe,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC;YACpC,MAAM,IAAA,8BAAe,EAAC,qDAAqD,CAAC,CAAC;QACjF,CAAC;IACL,CAAC;IAEO,KAAK,CAAC,kBAAkB;QAC5B,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,aAAa,CAAC,SAAS,CAAC,oBAAa,CAAC,QAAQ,CAAC;aACpE,KAAK,CAAC,GAAG,EAAE,GAAG,MAAM,IAAA,8BAAe,EAAC,uEAAuE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QAEtH,IAAI,MAAM,CAAC,eAAe,CAAC,MAAM,KAAK,CAAC,IAAI,MAAM,CAAC,eAAe,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC7E,MAAM,IAAA,8BAAe,EAAC,uEAAuE,CAAC,CAAC;QACnG,CAAC;QAED,OAAO,MAAM,CAAC;IAClB,CAAC;CACJ,CAAA;AA9JY,gDAAkB;6BAAlB,kBAAkB;IAD9B,IAAA,gBAAO,GAAE;;GACG,kBAAkB,CA8J9B;AAEY,QAAA,kBAAkB,GAAG,gBAAS,CAAC,GAAG,CAAC,kBAAkB,CAAC,CAAC","sourcesContent":["import Container, {Service} from 'typedi';\nimport {DocumentType, mongoose} from '@typegoose/typegoose';\nimport {LimitedTimeOfferCampaign as Model} from '@lyxa.ai/core/dist/libraries/mongo/models';\nimport {LimitedTimeOfferCampaignStatus, MarketingType} from '@lyxa.ai/core/dist/utilities/enum';\nimport {badRequestError, conflictError, notFoundError} from '@lyxa.ai/core/dist/utilities/error-common';\nimport {\n CreateLtoCampaignDTO,\n GetLtoCampaignHistoryDTO,\n UpdateLtoCampaignDTO,\n} from '../limited-time-offer-campaign.validation';\nimport {LtoCampaignLifecycleService} from './limited-time-offer-campaign-lifecycle.service';\nimport {LtoCampaignSchedulerService} from './limited-time-offer-campaign-scheduler.service';\nimport {LtoParticipantMarketingService} from '@modules/limited-time-offer/participant/services/limited-time-offer-participant-marketing.service';\nimport {LtoCampaignRepository} from '@modules/limited-time-offer/campaign/limited-time-offer-campaign.repository';\nimport {LtoCampaignQueryBuilder} from '@modules/limited-time-offer/campaign/limited-time-offer-campaign.builder';\nimport {LimitedTimeOfferConfigService} from '@modules/limited-time-offer/config/limited-time-offer-config.service';\n\nconst ACTIVE_STATUSES = [LimitedTimeOfferCampaignStatus.SCHEDULED, LimitedTimeOfferCampaignStatus.ACTIVE];\n\n@Service()\nexport class LtoCampaignService {\n private repository: LtoCampaignRepository;\n private scheduler: LtoCampaignSchedulerService;\n private lifecycle: LtoCampaignLifecycleService;\n private participantMarketing: LtoParticipantMarketingService;\n private configService: LimitedTimeOfferConfigService;\n\n constructor() {\n this.repository = Container.get(LtoCampaignRepository);\n this.scheduler = Container.get(LtoCampaignSchedulerService);\n this.lifecycle = Container.get(LtoCampaignLifecycleService);\n this.participantMarketing = Container.get(LtoParticipantMarketingService);\n this.configService = Container.get(LimitedTimeOfferConfigService);\n }\n\n public async create(dto: CreateLtoCampaignDTO) {\n await this.assertNoCampaignRunning();\n\n const now = new Date();\n const config = await this.loadConfigSnapshot();\n const status = dto.startDate <= now\n ? LimitedTimeOfferCampaignStatus.ACTIVE\n : LimitedTimeOfferCampaignStatus.SCHEDULED;\n\n const campaign = await this.repository.create(\n LtoCampaignQueryBuilder.buildCreateInput(dto, status, await this.repository.nextCampaignNumber(), config),\n );\n\n if (status === LimitedTimeOfferCampaignStatus.SCHEDULED) {\n await this.scheduler.scheduleActivation(campaign._id, dto.startDate);\n }\n await this.scheduler.scheduleExpiry(campaign._id, dto.endDate);\n\n return campaign;\n }\n\n public async getCurrent() {\n return this.repository.findCurrent();\n }\n\n public async getActive() {\n return this.repository.findActive();\n }\n\n public async getById(campaignId: mongoose.Types.ObjectId) {\n const campaign = await this.repository.findById(campaignId);\n if (!campaign) throw notFoundError('Campaign not found');\n return campaign;\n }\n\n public async getHistory(dto: GetLtoCampaignHistoryDTO) {\n const {documents, total} = await this.repository.findHistory(dto);\n return {\n documents,\n metadata: {page: dto.page, size: dto.size, totalElements: total, totalPages: Math.ceil(total / dto.size)},\n };\n }\n\n public async update(dto: UpdateLtoCampaignDTO) {\n const campaign = await this.repository.findById(dto._id);\n if (!campaign) throw notFoundError('Campaign not found');\n\n this.assertUpdateAllowed(campaign, dto);\n\n const updates = LtoCampaignQueryBuilder.buildUpdateInput(campaign, dto);\n\n if (this.shouldExpireImmediately(campaign.status, dto.endDate)) {\n return this.applyImmediateExpiry(dto._id, updates);\n }\n\n const result = await this.repository.updateById(dto._id, updates);\n if (!result) throw notFoundError('Campaign not found after update');\n\n await this.rescheduleIfDatesChanged(dto._id, result.status, campaign, dto);\n\n return result;\n }\n\n public async cancel(campaignId: mongoose.Types.ObjectId) {\n const campaign = await this.repository.findById(campaignId);\n if (!campaign) throw notFoundError('Campaign not found');\n\n this.assertEditable(campaign.status);\n await this.scheduler.cancelJobs(campaignId);\n\n if (campaign.status === LimitedTimeOfferCampaignStatus.ACTIVE) {\n await this.participantMarketing.removeAllCampaignMarketings(campaignId);\n }\n\n await this.lifecycle.cancelCampaign(campaignId);\n }\n\n private assertUpdateAllowed(campaign: DocumentType<Model>, dto: UpdateLtoCampaignDTO): void {\n this.assertEditable(campaign.status);\n\n if (campaign.status === LimitedTimeOfferCampaignStatus.ACTIVE && !dto.confirmActive) {\n throw badRequestError('Set confirmActive=true to confirm editing a live campaign.');\n }\n\n if (dto.startDate < new Date() && campaign.status === LimitedTimeOfferCampaignStatus.SCHEDULED) {\n throw badRequestError('Start date cannot be in the past.');\n }\n }\n\n private shouldExpireImmediately(status: LimitedTimeOfferCampaignStatus, endDate: Date): boolean {\n return status === LimitedTimeOfferCampaignStatus.ACTIVE && endDate <= new Date();\n }\n\n private async applyImmediateExpiry(campaignId: mongoose.Types.ObjectId, updates: object) {\n await this.scheduler.cancelJobs(campaignId);\n await this.repository.updateById(campaignId, updates);\n await this.lifecycle.expireCampaign(campaignId);\n const result = await this.repository.findById(campaignId);\n if (!result) throw notFoundError('Campaign not found after expiry');\n return result;\n }\n\n private async rescheduleIfDatesChanged(\n campaignId: mongoose.Types.ObjectId,\n currentStatus: LimitedTimeOfferCampaignStatus,\n original: DocumentType<Model>,\n dto: UpdateLtoCampaignDTO,\n ): Promise<void> {\n const datesChanged =\n dto.startDate.getTime() !== original.startDate!.getTime() ||\n dto.endDate.getTime() !== original.endDate!.getTime();\n\n if (!datesChanged) return;\n\n await this.scheduler.cancelJobs(campaignId);\n if (currentStatus === LimitedTimeOfferCampaignStatus.SCHEDULED) {\n await this.scheduler.scheduleActivation(campaignId, dto.startDate);\n }\n await this.scheduler.scheduleExpiry(campaignId, dto.endDate);\n }\n\n private async assertNoCampaignRunning(): Promise<void> {\n if (await this.repository.hasActiveCampaign()) {\n throw conflictError('A campaign is already scheduled or active. Delete it before creating a new one.');\n }\n }\n\n private assertEditable(status: LimitedTimeOfferCampaignStatus): void {\n if (!ACTIVE_STATUSES.includes(status)) {\n throw badRequestError('Only SCHEDULED or ACTIVE campaigns can be modified.');\n }\n }\n\n private async loadConfigSnapshot() {\n const config = await this.configService.getByType(MarketingType.DISCOUNT)\n .catch(() => { throw badRequestError('Global config is incomplete. Set discount options and max caps first.'); });\n\n if (config.discountOptions.length === 0 || config.maxDiscountCaps.length === 0) {\n throw badRequestError('Global config is incomplete. Set discount options and max caps first.');\n }\n\n return config;\n }\n}\n\nexport const ltoCampaignService = Container.get(LtoCampaignService);\n"]}
@@ -0,0 +1,8 @@
1
+ import { UpdateLimitedTimeOfferConfigDTO } from './limited-time-offer-config.validation';
2
+ export declare class LtoConfigQueryBuilder {
3
+ static buildUpdateInput(dto: UpdateLimitedTimeOfferConfigDTO): {
4
+ discountOptions: number[];
5
+ maxDiscountCaps: number[];
6
+ };
7
+ }
8
+ //# sourceMappingURL=limited-time-offer-config.builder.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"limited-time-offer-config.builder.d.ts","sourceRoot":"/","sources":["modules/limited-time-offer/config/limited-time-offer-config.builder.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,+BAA+B,EAAC,MAAM,wCAAwC,CAAC;AAEvF,qBAAa,qBAAqB;IAC9B,MAAM,CAAC,gBAAgB,CAAC,GAAG,EAAE,+BAA+B;;;;CAM/D"}
@@ -0,0 +1,13 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.LtoConfigQueryBuilder = void 0;
4
+ class LtoConfigQueryBuilder {
5
+ static buildUpdateInput(dto) {
6
+ return {
7
+ discountOptions: dto.discountOptions,
8
+ maxDiscountCaps: dto.maxDiscountCaps,
9
+ };
10
+ }
11
+ }
12
+ exports.LtoConfigQueryBuilder = LtoConfigQueryBuilder;
13
+ //# sourceMappingURL=limited-time-offer-config.builder.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"limited-time-offer-config.builder.js","sourceRoot":"/","sources":["modules/limited-time-offer/config/limited-time-offer-config.builder.ts"],"names":[],"mappings":";;;AAEA,MAAa,qBAAqB;IAC9B,MAAM,CAAC,gBAAgB,CAAC,GAAoC;QACxD,OAAO;YACH,eAAe,EAAE,GAAG,CAAC,eAAe;YACpC,eAAe,EAAE,GAAG,CAAC,eAAe;SACvC,CAAC;IACN,CAAC;CACJ;AAPD,sDAOC","sourcesContent":["import {UpdateLimitedTimeOfferConfigDTO} from './limited-time-offer-config.validation';\n\nexport class LtoConfigQueryBuilder {\n static buildUpdateInput(dto: UpdateLimitedTimeOfferConfigDTO) {\n return {\n discountOptions: dto.discountOptions,\n maxDiscountCaps: dto.maxDiscountCaps,\n };\n }\n}\n"]}
@@ -0,0 +1,14 @@
1
+ import { LimitedTimeOfferConfig as Model } from '@lyxa.ai/core/dist/libraries/mongo/models';
2
+ import { MarketingType } from '@lyxa.ai/core/dist/utilities/enum';
3
+ import { mongoose } from '@typegoose/typegoose';
4
+ export declare class LtoConfigRepository {
5
+ private model;
6
+ constructor();
7
+ existsByCampaignType(campaignType: MarketingType): Promise<boolean>;
8
+ create(input: object): Promise<Model>;
9
+ findByCampaignType(campaignType: MarketingType): Promise<Model | null>;
10
+ findById(id: mongoose.Types.ObjectId): Promise<Model | null>;
11
+ updateById(id: mongoose.Types.ObjectId, updates: object): Promise<Model | null>;
12
+ }
13
+ export declare const ltoConfigRepository: LtoConfigRepository;
14
+ //# sourceMappingURL=limited-time-offer-config.repository.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"limited-time-offer-config.repository.d.ts","sourceRoot":"/","sources":["modules/limited-time-offer/config/limited-time-offer-config.repository.ts"],"names":[],"mappings":"AACA,OAAO,EACH,sBAAsB,IAAI,KAAK,EAElC,MAAM,2CAA2C,CAAC;AAEnD,OAAO,EAAC,aAAa,EAAC,MAAM,mCAAmC,CAAC;AAChE,OAAO,EAAC,QAAQ,EAAC,MAAM,sBAAsB,CAAC;AAE9C,qBACa,mBAAmB;IAC5B,OAAO,CAAC,KAAK,CAA8D;;IAMrE,oBAAoB,CAAC,YAAY,EAAE,aAAa,GAAG,OAAO,CAAC,OAAO,CAAC;IAInE,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,KAAK,CAAC;IAKrC,kBAAkB,CAAC,YAAY,EAAE,aAAa,GAAG,OAAO,CAAC,KAAK,GAAG,IAAI,CAAC;IAItE,QAAQ,CAAC,EAAE,EAAE,QAAQ,CAAC,KAAK,CAAC,QAAQ,GAAG,OAAO,CAAC,KAAK,GAAG,IAAI,CAAC;IAI5D,UAAU,CAAC,EAAE,EAAE,QAAQ,CAAC,KAAK,CAAC,QAAQ,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,KAAK,GAAG,IAAI,CAAC;CAIxF;AAED,eAAO,MAAM,mBAAmB,qBAAqC,CAAC"}
@@ -0,0 +1,77 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
19
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
20
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
21
+ 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;
22
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
23
+ };
24
+ var __importStar = (this && this.__importStar) || (function () {
25
+ var ownKeys = function(o) {
26
+ ownKeys = Object.getOwnPropertyNames || function (o) {
27
+ var ar = [];
28
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
29
+ return ar;
30
+ };
31
+ return ownKeys(o);
32
+ };
33
+ return function (mod) {
34
+ if (mod && mod.__esModule) return mod;
35
+ var result = {};
36
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
37
+ __setModuleDefault(result, mod);
38
+ return result;
39
+ };
40
+ })();
41
+ var __metadata = (this && this.__metadata) || function (k, v) {
42
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
43
+ };
44
+ Object.defineProperty(exports, "__esModule", { value: true });
45
+ exports.ltoConfigRepository = exports.LtoConfigRepository = void 0;
46
+ const typedi_1 = __importStar(require("typedi"));
47
+ const models_1 = require("@lyxa.ai/core/dist/libraries/mongo/models");
48
+ let LtoConfigRepository = class LtoConfigRepository {
49
+ model;
50
+ constructor() {
51
+ this.model = models_1.LimitedTimeOfferConfigModel;
52
+ }
53
+ async existsByCampaignType(campaignType) {
54
+ return !!(await this.model.exists({ campaignType }));
55
+ }
56
+ async create(input) {
57
+ const doc = await this.model.create(input);
58
+ return doc.toObject();
59
+ }
60
+ async findByCampaignType(campaignType) {
61
+ return this.model.findOne({ campaignType }).lean();
62
+ }
63
+ async findById(id) {
64
+ return this.model.findById(id).lean();
65
+ }
66
+ async updateById(id, updates) {
67
+ const doc = await this.model.findByIdAndUpdate(id, { $set: updates }, { new: true }).lean();
68
+ return doc;
69
+ }
70
+ };
71
+ exports.LtoConfigRepository = LtoConfigRepository;
72
+ exports.LtoConfigRepository = LtoConfigRepository = __decorate([
73
+ (0, typedi_1.Service)(),
74
+ __metadata("design:paramtypes", [])
75
+ ], LtoConfigRepository);
76
+ exports.ltoConfigRepository = typedi_1.default.get(LtoConfigRepository);
77
+ //# sourceMappingURL=limited-time-offer-config.repository.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"limited-time-offer-config.repository.js","sourceRoot":"/","sources":["modules/limited-time-offer/config/limited-time-offer-config.repository.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,iDAA0C;AAC1C,sEAGmD;AAM5C,IAAM,mBAAmB,GAAzB,MAAM,mBAAmB;IACpB,KAAK,CAA8D;IAE3E;QACI,IAAI,CAAC,KAAK,GAAG,oCAA0F,CAAC;IAC5G,CAAC;IAED,KAAK,CAAC,oBAAoB,CAAC,YAA2B;QAClD,OAAO,CAAC,CAAC,CAAC,MAAM,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,EAAC,YAAY,EAAC,CAAC,CAAC,CAAC;IACvD,CAAC;IAED,KAAK,CAAC,MAAM,CAAC,KAAa;QACtB,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;QAC3C,OAAO,GAAG,CAAC,QAAQ,EAAE,CAAC;IAC1B,CAAC;IAED,KAAK,CAAC,kBAAkB,CAAC,YAA2B;QAChD,OAAO,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,EAAC,YAAY,EAAC,CAAC,CAAC,IAAI,EAA2B,CAAC;IAC9E,CAAC;IAED,KAAK,CAAC,QAAQ,CAAC,EAA2B;QACtC,OAAO,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,IAAI,EAA2B,CAAC;IACnE,CAAC;IAED,KAAK,CAAC,UAAU,CAAC,EAA2B,EAAE,OAAe;QACzD,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC,iBAAiB,CAAC,EAAE,EAAE,EAAC,IAAI,EAAE,OAAO,EAAC,EAAE,EAAC,GAAG,EAAE,IAAI,EAAC,CAAC,CAAC,IAAI,EAAE,CAAC;QACxF,OAAO,GAAmB,CAAC;IAC/B,CAAC;CACJ,CAAA;AA5BY,kDAAmB;8BAAnB,mBAAmB;IAD/B,IAAA,gBAAO,GAAE;;GACG,mBAAmB,CA4B/B;AAEY,QAAA,mBAAmB,GAAG,gBAAS,CAAC,GAAG,CAAC,mBAAmB,CAAC,CAAC","sourcesContent":["import Container, {Service} from 'typedi';\nimport {\n LimitedTimeOfferConfig as Model,\n LimitedTimeOfferConfigModel,\n} from '@lyxa.ai/core/dist/libraries/mongo/models';\nimport {SoftDeleteModel} from '@lyxa.ai/core/dist/libraries/mongo/plugins/soft-delete-plugin';\nimport {MarketingType} from '@lyxa.ai/core/dist/utilities/enum';\nimport {mongoose} from '@typegoose/typegoose';\n\n@Service()\nexport class LtoConfigRepository {\n private model: typeof LimitedTimeOfferConfigModel & SoftDeleteModel<Model>;\n\n constructor() {\n this.model = LimitedTimeOfferConfigModel as typeof LimitedTimeOfferConfigModel & SoftDeleteModel<Model>;\n }\n\n async existsByCampaignType(campaignType: MarketingType): Promise<boolean> {\n return !!(await this.model.exists({campaignType}));\n }\n\n async create(input: object): Promise<Model> {\n const doc = await this.model.create(input);\n return doc.toObject();\n }\n\n async findByCampaignType(campaignType: MarketingType): Promise<Model | null> {\n return this.model.findOne({campaignType}).lean() as Promise<Model | null>;\n }\n\n async findById(id: mongoose.Types.ObjectId): Promise<Model | null> {\n return this.model.findById(id).lean() as Promise<Model | null>;\n }\n\n async updateById(id: mongoose.Types.ObjectId, updates: object): Promise<Model | null> {\n const doc = await this.model.findByIdAndUpdate(id, {$set: updates}, {new: true}).lean();\n return doc as Model | null;\n }\n}\n\nexport const ltoConfigRepository = Container.get(LtoConfigRepository);\n"]}
@@ -1,9 +1,8 @@
1
1
  import { MarketingType } from '@lyxa.ai/core/dist/utilities/enum';
2
2
  import { CreateLimitedTimeOfferConfigDTO, LimitedTimeOfferConfigDTO, UpdateLimitedTimeOfferConfigDTO } from './limited-time-offer-config.validation';
3
3
  export declare class LimitedTimeOfferConfigService {
4
- private model;
4
+ private repository;
5
5
  constructor();
6
- private validateConfigUnique;
7
6
  create(input: CreateLimitedTimeOfferConfigDTO): Promise<LimitedTimeOfferConfigDTO>;
8
7
  getByType(campaignType: MarketingType): Promise<LimitedTimeOfferConfigDTO>;
9
8
  update(input: UpdateLimitedTimeOfferConfigDTO): Promise<LimitedTimeOfferConfigDTO>;
@@ -1 +1 @@
1
- {"version":3,"file":"limited-time-offer-config.service.d.ts","sourceRoot":"/","sources":["modules/limited-time-offer/config/limited-time-offer-config.service.ts"],"names":[],"mappings":"AAIA,OAAO,EAAC,aAAa,EAAC,MAAM,mCAAmC,CAAC;AAChE,OAAO,EACH,+BAA+B,EAC/B,yBAAyB,EACzB,+BAA+B,EAClC,MAAM,wCAAwC,CAAC;AAGhD,qBACa,6BAA6B;IACtC,OAAO,CAAC,KAAK,CAA8D;;YAM7D,oBAAoB;IAOrB,MAAM,CAAC,KAAK,EAAE,+BAA+B,GAAG,OAAO,CAAC,yBAAyB,CAAC;IAMlF,SAAS,CAAC,YAAY,EAAE,aAAa,GAAG,OAAO,CAAC,yBAAyB,CAAC;IAU1E,MAAM,CAAC,KAAK,EAAE,+BAA+B,GAAG,OAAO,CAAC,yBAAyB,CAAC;CA0BlG;AAED,eAAO,MAAM,6BAA6B,+BAA+C,CAAC"}
1
+ {"version":3,"file":"limited-time-offer-config.service.d.ts","sourceRoot":"/","sources":["modules/limited-time-offer/config/limited-time-offer-config.service.ts"],"names":[],"mappings":"AAEA,OAAO,EAAC,aAAa,EAAC,MAAM,mCAAmC,CAAC;AAChE,OAAO,EACH,+BAA+B,EAC/B,yBAAyB,EACzB,+BAA+B,EAClC,MAAM,wCAAwC,CAAC;AAKhD,qBACa,6BAA6B;IACtC,OAAO,CAAC,UAAU,CAAsB;;IAM3B,MAAM,CAAC,KAAK,EAAE,+BAA+B,GAAG,OAAO,CAAC,yBAAyB,CAAC;IAOlF,SAAS,CAAC,YAAY,EAAE,aAAa,GAAG,OAAO,CAAC,yBAAyB,CAAC;IAM1E,MAAM,CAAC,KAAK,EAAE,+BAA+B,GAAG,OAAO,CAAC,yBAAyB,CAAC;CAelG;AAED,eAAO,MAAM,6BAA6B,+BAA+C,CAAC"}