@carlonicora/nestjs-neo4jsonapi 7.0.0 → 8.0.0

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 (193) hide show
  1. package/dist/bootstrap/app.module.factory.d.ts.map +1 -1
  2. package/dist/bootstrap/app.module.factory.js +1 -0
  3. package/dist/bootstrap/app.module.factory.js.map +1 -1
  4. package/dist/bootstrap/bootstrap.options.d.ts +20 -0
  5. package/dist/bootstrap/bootstrap.options.d.ts.map +1 -1
  6. package/dist/common/decorators/audit.decorator.d.ts +3 -0
  7. package/dist/common/decorators/audit.decorator.d.ts.map +1 -1
  8. package/dist/common/decorators/audit.decorator.js +15 -2
  9. package/dist/common/decorators/audit.decorator.js.map +1 -1
  10. package/dist/common/decorators/cache-invalidate.decorator.d.ts.map +1 -1
  11. package/dist/common/decorators/cache-invalidate.decorator.js +3 -11
  12. package/dist/common/decorators/cache-invalidate.decorator.js.map +1 -1
  13. package/dist/common/decorators/handler-wrapper.d.ts +13 -0
  14. package/dist/common/decorators/handler-wrapper.d.ts.map +1 -0
  15. package/dist/common/decorators/handler-wrapper.js +25 -0
  16. package/dist/common/decorators/handler-wrapper.js.map +1 -0
  17. package/dist/common/decorators/validate-id.decorator.d.ts.map +1 -1
  18. package/dist/common/decorators/validate-id.decorator.js +3 -11
  19. package/dist/common/decorators/validate-id.decorator.js.map +1 -1
  20. package/dist/core/email/templates/en/cardExpiring.hbs +28 -0
  21. package/dist/core/email/templates/en/paymentFailure.hbs +4 -0
  22. package/dist/foundations/ai-connection/controllers/ai-connection.controller.d.ts +2 -1
  23. package/dist/foundations/ai-connection/controllers/ai-connection.controller.d.ts.map +1 -1
  24. package/dist/foundations/ai-connection/controllers/ai-connection.controller.js +5 -4
  25. package/dist/foundations/ai-connection/controllers/ai-connection.controller.js.map +1 -1
  26. package/dist/foundations/analytics/controllers/analytics.admin.controller.d.ts +2 -1
  27. package/dist/foundations/analytics/controllers/analytics.admin.controller.d.ts.map +1 -1
  28. package/dist/foundations/analytics/controllers/analytics.admin.controller.js +5 -4
  29. package/dist/foundations/analytics/controllers/analytics.admin.controller.js.map +1 -1
  30. package/dist/foundations/billing/billing.module.d.ts +26 -0
  31. package/dist/foundations/billing/billing.module.d.ts.map +1 -0
  32. package/dist/foundations/billing/billing.module.js +74 -0
  33. package/dist/foundations/billing/billing.module.js.map +1 -0
  34. package/dist/foundations/billing/cron/billing-lifecycle.cron.d.ts +16 -0
  35. package/dist/foundations/billing/cron/billing-lifecycle.cron.d.ts.map +1 -0
  36. package/dist/foundations/billing/cron/billing-lifecycle.cron.js +52 -0
  37. package/dist/foundations/billing/cron/billing-lifecycle.cron.js.map +1 -0
  38. package/dist/foundations/billing/index.d.ts +7 -0
  39. package/dist/foundations/billing/index.d.ts.map +1 -0
  40. package/dist/foundations/billing/index.js +28 -0
  41. package/dist/foundations/billing/index.js.map +1 -0
  42. package/dist/foundations/billing/interfaces/billing.config.interface.d.ts +71 -0
  43. package/dist/foundations/billing/interfaces/billing.config.interface.d.ts.map +1 -0
  44. package/dist/foundations/billing/interfaces/billing.config.interface.js +41 -0
  45. package/dist/foundations/billing/interfaces/billing.config.interface.js.map +1 -0
  46. package/dist/foundations/billing/processors/billing-email.jobs.d.ts +127 -0
  47. package/dist/foundations/billing/processors/billing-email.jobs.d.ts.map +1 -0
  48. package/dist/foundations/billing/processors/billing-email.jobs.js +196 -0
  49. package/dist/foundations/billing/processors/billing-email.jobs.js.map +1 -0
  50. package/dist/foundations/billing/processors/billing-email.processor.d.ts +33 -0
  51. package/dist/foundations/billing/processors/billing-email.processor.d.ts.map +1 -0
  52. package/dist/foundations/billing/processors/billing-email.processor.js +95 -0
  53. package/dist/foundations/billing/processors/billing-email.processor.js.map +1 -0
  54. package/dist/foundations/billing/services/card-expiry-warning.service.d.ts +58 -0
  55. package/dist/foundations/billing/services/card-expiry-warning.service.d.ts.map +1 -0
  56. package/dist/foundations/billing/services/card-expiry-warning.service.js +90 -0
  57. package/dist/foundations/billing/services/card-expiry-warning.service.js.map +1 -0
  58. package/dist/foundations/company/repositories/company.repository.d.ts +2 -0
  59. package/dist/foundations/company/repositories/company.repository.d.ts.map +1 -1
  60. package/dist/foundations/company/repositories/company.repository.js +2 -2
  61. package/dist/foundations/company/repositories/company.repository.js.map +1 -1
  62. package/dist/foundations/foundations.modules.d.ts +3 -0
  63. package/dist/foundations/foundations.modules.d.ts.map +1 -1
  64. package/dist/foundations/foundations.modules.js +3 -1
  65. package/dist/foundations/foundations.modules.js.map +1 -1
  66. package/dist/foundations/handbook/controllers/handbook.controller.d.ts +1 -1
  67. package/dist/foundations/handbook/controllers/handbook.controller.d.ts.map +1 -1
  68. package/dist/foundations/handbook/controllers/handbook.controller.js +5 -4
  69. package/dist/foundations/handbook/controllers/handbook.controller.js.map +1 -1
  70. package/dist/foundations/index.d.ts +1 -0
  71. package/dist/foundations/index.d.ts.map +1 -1
  72. package/dist/foundations/index.js +1 -0
  73. package/dist/foundations/index.js.map +1 -1
  74. package/dist/foundations/notification/controllers/notification.controller.d.ts.map +1 -1
  75. package/dist/foundations/notification/controllers/notification.controller.js +0 -1
  76. package/dist/foundations/notification/controllers/notification.controller.js.map +1 -1
  77. package/dist/foundations/role/controllers/role.controller.d.ts +1 -1
  78. package/dist/foundations/role/controllers/role.controller.d.ts.map +1 -1
  79. package/dist/foundations/role/controllers/role.controller.js +4 -3
  80. package/dist/foundations/role/controllers/role.controller.js.map +1 -1
  81. package/dist/foundations/stripe-coupon/controllers/stripe-coupon-code-checkout.controller.d.ts +2 -1
  82. package/dist/foundations/stripe-coupon/controllers/stripe-coupon-code-checkout.controller.d.ts.map +1 -1
  83. package/dist/foundations/stripe-coupon/controllers/stripe-coupon-code-checkout.controller.js +5 -6
  84. package/dist/foundations/stripe-coupon/controllers/stripe-coupon-code-checkout.controller.js.map +1 -1
  85. package/dist/foundations/stripe-coupon/controllers/stripe-coupon-code.controller.d.ts +1 -1
  86. package/dist/foundations/stripe-coupon/controllers/stripe-coupon-code.controller.d.ts.map +1 -1
  87. package/dist/foundations/stripe-coupon/controllers/stripe-coupon-code.controller.js +5 -4
  88. package/dist/foundations/stripe-coupon/controllers/stripe-coupon-code.controller.js.map +1 -1
  89. package/dist/foundations/stripe-coupon/controllers/stripe-coupon.controller.d.ts +1 -1
  90. package/dist/foundations/stripe-coupon/controllers/stripe-coupon.controller.d.ts.map +1 -1
  91. package/dist/foundations/stripe-coupon/controllers/stripe-coupon.controller.js +5 -4
  92. package/dist/foundations/stripe-coupon/controllers/stripe-coupon.controller.js.map +1 -1
  93. package/dist/foundations/stripe-coupon/controllers/stripe-coupon.public.controller.d.ts +1 -0
  94. package/dist/foundations/stripe-coupon/controllers/stripe-coupon.public.controller.d.ts.map +1 -1
  95. package/dist/foundations/stripe-coupon/controllers/stripe-coupon.public.controller.js +4 -0
  96. package/dist/foundations/stripe-coupon/controllers/stripe-coupon.public.controller.js.map +1 -1
  97. package/dist/foundations/stripe-coupon/dtos/stripe-coupon-code.automatic.query.dto.d.ts +8 -0
  98. package/dist/foundations/stripe-coupon/dtos/stripe-coupon-code.automatic.query.dto.d.ts.map +1 -0
  99. package/dist/foundations/stripe-coupon/dtos/stripe-coupon-code.automatic.query.dto.js +25 -0
  100. package/dist/foundations/stripe-coupon/dtos/stripe-coupon-code.automatic.query.dto.js.map +1 -0
  101. package/dist/foundations/stripe-coupon/entities/stripe-coupon-code.js +1 -1
  102. package/dist/foundations/stripe-coupon/entities/stripe-coupon-code.js.map +1 -1
  103. package/dist/foundations/stripe-coupon/entities/stripe-coupon-offer.d.ts +5 -0
  104. package/dist/foundations/stripe-coupon/entities/stripe-coupon-offer.d.ts.map +1 -1
  105. package/dist/foundations/stripe-coupon/entities/stripe-coupon-offer.js.map +1 -1
  106. package/dist/foundations/stripe-coupon/entities/stripe-coupon.d.ts +25 -2
  107. package/dist/foundations/stripe-coupon/entities/stripe-coupon.d.ts.map +1 -1
  108. package/dist/foundations/stripe-coupon/entities/stripe-coupon.js +1 -1
  109. package/dist/foundations/stripe-coupon/entities/stripe-coupon.js.map +1 -1
  110. package/dist/foundations/stripe-coupon/index.d.ts +1 -0
  111. package/dist/foundations/stripe-coupon/index.d.ts.map +1 -1
  112. package/dist/foundations/stripe-coupon/index.js +1 -0
  113. package/dist/foundations/stripe-coupon/index.js.map +1 -1
  114. package/dist/foundations/stripe-coupon/services/stripe-coupon-api.service.d.ts +5 -8
  115. package/dist/foundations/stripe-coupon/services/stripe-coupon-api.service.d.ts.map +1 -1
  116. package/dist/foundations/stripe-coupon/services/stripe-coupon-api.service.js +9 -9
  117. package/dist/foundations/stripe-coupon/services/stripe-coupon-api.service.js.map +1 -1
  118. package/dist/foundations/stripe-coupon/services/stripe-coupon-offer.service.js.map +1 -1
  119. package/dist/foundations/stripe-coupon/services/stripe-coupon.service.d.ts +36 -3
  120. package/dist/foundations/stripe-coupon/services/stripe-coupon.service.d.ts.map +1 -1
  121. package/dist/foundations/stripe-coupon/services/stripe-coupon.service.js +69 -33
  122. package/dist/foundations/stripe-coupon/services/stripe-coupon.service.js.map +1 -1
  123. package/dist/foundations/stripe-customer/services/stripe-customer-api.service.d.ts +17 -0
  124. package/dist/foundations/stripe-customer/services/stripe-customer-api.service.d.ts.map +1 -1
  125. package/dist/foundations/stripe-customer/services/stripe-customer-api.service.js +40 -0
  126. package/dist/foundations/stripe-customer/services/stripe-customer-api.service.js.map +1 -1
  127. package/dist/foundations/stripe-invoice/entities/stripe-invoice.entity.d.ts +1 -1
  128. package/dist/foundations/stripe-invoice/entities/stripe-invoice.entity.d.ts.map +1 -1
  129. package/dist/foundations/stripe-invoice/serialisers/stripe-invoice.serialiser.js +2 -2
  130. package/dist/foundations/stripe-invoice/serialisers/stripe-invoice.serialiser.js.map +1 -1
  131. package/dist/foundations/stripe-invoice/services/stripe-invoice-api.service.d.ts +13 -0
  132. package/dist/foundations/stripe-invoice/services/stripe-invoice-api.service.d.ts.map +1 -1
  133. package/dist/foundations/stripe-invoice/services/stripe-invoice-api.service.js +21 -0
  134. package/dist/foundations/stripe-invoice/services/stripe-invoice-api.service.js.map +1 -1
  135. package/dist/foundations/stripe-subscription/controllers/stripe-subscription.controller.d.ts +1 -3
  136. package/dist/foundations/stripe-subscription/controllers/stripe-subscription.controller.d.ts.map +1 -1
  137. package/dist/foundations/stripe-subscription/controllers/stripe-subscription.controller.js +5 -38
  138. package/dist/foundations/stripe-subscription/controllers/stripe-subscription.controller.js.map +1 -1
  139. package/dist/foundations/stripe-subscription/entities/stripe-subscription.d.ts +60 -0
  140. package/dist/foundations/stripe-subscription/entities/stripe-subscription.d.ts.map +1 -0
  141. package/dist/foundations/stripe-subscription/entities/stripe-subscription.discount.d.ts +1 -1
  142. package/dist/foundations/stripe-subscription/entities/stripe-subscription.discount.d.ts.map +1 -1
  143. package/dist/foundations/stripe-subscription/entities/stripe-subscription.js +61 -0
  144. package/dist/foundations/stripe-subscription/entities/stripe-subscription.js.map +1 -0
  145. package/dist/foundations/stripe-subscription/index.d.ts +1 -4
  146. package/dist/foundations/stripe-subscription/index.d.ts.map +1 -1
  147. package/dist/foundations/stripe-subscription/index.js +4 -8
  148. package/dist/foundations/stripe-subscription/index.js.map +1 -1
  149. package/dist/foundations/stripe-subscription/repositories/stripe-subscription.repository.d.ts +93 -165
  150. package/dist/foundations/stripe-subscription/repositories/stripe-subscription.repository.d.ts.map +1 -1
  151. package/dist/foundations/stripe-subscription/repositories/stripe-subscription.repository.js +206 -274
  152. package/dist/foundations/stripe-subscription/repositories/stripe-subscription.repository.js.map +1 -1
  153. package/dist/foundations/stripe-subscription/services/stripe-subscription-admin.service.d.ts +34 -36
  154. package/dist/foundations/stripe-subscription/services/stripe-subscription-admin.service.d.ts.map +1 -1
  155. package/dist/foundations/stripe-subscription/services/stripe-subscription-admin.service.js +20 -72
  156. package/dist/foundations/stripe-subscription/services/stripe-subscription-admin.service.js.map +1 -1
  157. package/dist/foundations/stripe-subscription/services/stripe-subscription-api.service.d.ts +1 -29
  158. package/dist/foundations/stripe-subscription/services/stripe-subscription-api.service.d.ts.map +1 -1
  159. package/dist/foundations/stripe-subscription/services/stripe-subscription-api.service.js +1 -53
  160. package/dist/foundations/stripe-subscription/services/stripe-subscription-api.service.js.map +1 -1
  161. package/dist/foundations/stripe-subscription/stripe-subscription.module.d.ts +3 -3
  162. package/dist/foundations/stripe-subscription/stripe-subscription.module.d.ts.map +1 -1
  163. package/dist/foundations/stripe-subscription/stripe-subscription.module.js +8 -7
  164. package/dist/foundations/stripe-subscription/stripe-subscription.module.js.map +1 -1
  165. package/dist/foundations/stripe-usage/entities/stripe-usage-record.entity.d.ts +1 -1
  166. package/dist/foundations/stripe-usage/entities/stripe-usage-record.entity.d.ts.map +1 -1
  167. package/dist/foundations/stripe-usage/serialisers/stripe-usage-record.serialiser.js +2 -2
  168. package/dist/foundations/stripe-usage/serialisers/stripe-usage-record.serialiser.js.map +1 -1
  169. package/dist/foundations/stripe-webhook/processors/stripe-webhook.processor.d.ts +6 -1
  170. package/dist/foundations/stripe-webhook/processors/stripe-webhook.processor.d.ts.map +1 -1
  171. package/dist/foundations/stripe-webhook/processors/stripe-webhook.processor.js +73 -15
  172. package/dist/foundations/stripe-webhook/processors/stripe-webhook.processor.js.map +1 -1
  173. package/dist/foundations/stripe-webhook/services/stripe-webhook-notification.service.d.ts +24 -2
  174. package/dist/foundations/stripe-webhook/services/stripe-webhook-notification.service.d.ts.map +1 -1
  175. package/dist/foundations/stripe-webhook/services/stripe-webhook-notification.service.js +88 -20
  176. package/dist/foundations/stripe-webhook/services/stripe-webhook-notification.service.js.map +1 -1
  177. package/package.json +1 -1
  178. package/dist/foundations/stripe-subscription/entities/stripe-subscription.entity.d.ts +0 -27
  179. package/dist/foundations/stripe-subscription/entities/stripe-subscription.entity.d.ts.map +0 -1
  180. package/dist/foundations/stripe-subscription/entities/stripe-subscription.entity.js +0 -3
  181. package/dist/foundations/stripe-subscription/entities/stripe-subscription.entity.js.map +0 -1
  182. package/dist/foundations/stripe-subscription/entities/stripe-subscription.map.d.ts +0 -8
  183. package/dist/foundations/stripe-subscription/entities/stripe-subscription.map.d.ts.map +0 -1
  184. package/dist/foundations/stripe-subscription/entities/stripe-subscription.map.js +0 -30
  185. package/dist/foundations/stripe-subscription/entities/stripe-subscription.map.js.map +0 -1
  186. package/dist/foundations/stripe-subscription/entities/stripe-subscription.model.d.ts +0 -4
  187. package/dist/foundations/stripe-subscription/entities/stripe-subscription.model.d.ts.map +0 -1
  188. package/dist/foundations/stripe-subscription/entities/stripe-subscription.model.js +0 -17
  189. package/dist/foundations/stripe-subscription/entities/stripe-subscription.model.js.map +0 -1
  190. package/dist/foundations/stripe-subscription/serialisers/stripe-subscription.serialiser.d.ts +0 -9
  191. package/dist/foundations/stripe-subscription/serialisers/stripe-subscription.serialiser.d.ts.map +0 -1
  192. package/dist/foundations/stripe-subscription/serialisers/stripe-subscription.serialiser.js +0 -59
  193. package/dist/foundations/stripe-subscription/serialisers/stripe-subscription.serialiser.js.map +0 -1
@@ -12,169 +12,131 @@ Object.defineProperty(exports, "__esModule", { value: true });
12
12
  exports.StripeSubscriptionRepository = void 0;
13
13
  const common_1 = require("@nestjs/common");
14
14
  const crypto_1 = require("crypto");
15
- const neo4j_1 = require("../../../core/neo4j");
16
- const company_1 = require("../../company");
15
+ const nestjs_cls_1 = require("nestjs-cls");
16
+ const abstract_repository_1 = require("../../../core/neo4j/abstracts/abstract.repository");
17
+ const neo4j_service_1 = require("../../../core/neo4j/services/neo4j.service");
18
+ const security_service_1 = require("../../../core/security/services/security.service");
19
+ const company_meta_1 = require("../../company/entities/company.meta");
17
20
  const stripe_customer_meta_1 = require("../../stripe-customer/entities/stripe-customer.meta");
18
21
  const stripe_price_meta_1 = require("../../stripe-price/entities/stripe-price.meta");
19
22
  const stripe_product_meta_1 = require("../../stripe-product/entities/stripe-product.meta");
23
+ const user_meta_1 = require("../../user/entities/user.meta");
24
+ const stripe_subscription_1 = require("../entities/stripe-subscription");
20
25
  const stripe_subscription_discount_1 = require("../entities/stripe-subscription.discount");
21
26
  const stripe_subscription_meta_1 = require("../entities/stripe-subscription.meta");
22
- const stripe_subscription_model_1 = require("../entities/stripe-subscription.model");
27
+ const S = stripe_subscription_meta_1.stripeSubscriptionMeta.nodeName;
28
+ /** Datetime fields `update()` can set or clear: undefined leaves, null clears. */
29
+ const CLEARABLE_DATETIME_FIELDS = ["canceledAt", "cardExpiryCheckedFor"];
23
30
  /**
24
31
  * StripeSubscriptionRepository
25
32
  *
26
- * Neo4j repository for managing Subscription nodes and their relationships to BillingCustomer and Price nodes.
27
- * Handles subscription lifecycle data storage and queries with status filtering.
33
+ * Neo4j repository for StripeSubscription nodes:
34
+ * `(stripeSubscription)-[:BELONGS_TO]->(stripeCustomer)`, `-[:USES_PRICE]->(stripePrice)`,
35
+ * `-[:BELONGS_TO]->(company)` and `-[:CREATED_BY]->(user)`.
28
36
  *
29
- * Key Features:
30
- * - Automatic constraint creation for ID and Stripe subscription ID uniqueness
31
- * - Query subscriptions by customer, status, or Stripe ID
32
- * - Create and update operations with relationship management
33
- * - Support for plan changes by updating price relationships
34
- * - Sync operations for webhook data
35
- * - Track trial periods, billing cycles, and cancellation status
36
- * - Bulk cancel operations for customer deletion
37
- *
38
- * @example
39
- * ```typescript
40
- * const subscription = await subscriptionRepository.create({
41
- * stripeCustomerId: 'cust_123',
42
- * priceId: 'price_456',
43
- * stripeSubscriptionId: 'sub_stripe789',
44
- * status: 'active',
45
- * currentPeriodStart: new Date(),
46
- * currentPeriodEnd: new Date(Date.now() + 30 * 24 * 60 * 60 * 1000),
47
- * cancelAtPeriodEnd: false,
48
- * quantity: 1
49
- * });
50
- * ```
37
+ * Every read and every request-time write starts from `buildDefaultMatch()`, so a request is
38
+ * scoped to the caller's company. Jobs with no company in CLS (webhooks, crons, backfills)
39
+ * reach every company through the `$companyId IS NULL` branch.
51
40
  */
52
- let StripeSubscriptionRepository = class StripeSubscriptionRepository {
53
- constructor(neo4j) {
54
- this.neo4j = neo4j;
41
+ let StripeSubscriptionRepository = class StripeSubscriptionRepository extends abstract_repository_1.AbstractRepository {
42
+ constructor(neo4j, securityService, clsService) {
43
+ super(neo4j, securityService, clsService);
44
+ this.descriptor = stripe_subscription_1.StripeSubscriptionDescriptor;
55
45
  }
56
- /**
57
- * Initialize repository constraints
58
- *
59
- * Creates unique constraints and indexes on module initialization.
60
- */
46
+ /** The inherited id constraint and indexes, plus the unique Stripe subscription id. */
61
47
  async onModuleInit() {
48
+ await super.onModuleInit();
62
49
  await this.neo4j.writeOne({
63
- query: `CREATE CONSTRAINT ${stripe_subscription_meta_1.stripeSubscriptionMeta.nodeName}_id IF NOT EXISTS FOR (${stripe_subscription_meta_1.stripeSubscriptionMeta.nodeName}:${stripe_subscription_meta_1.stripeSubscriptionMeta.labelName}) REQUIRE ${stripe_subscription_meta_1.stripeSubscriptionMeta.nodeName}.id IS UNIQUE`,
64
- });
65
- await this.neo4j.writeOne({
66
- query: `CREATE CONSTRAINT ${stripe_subscription_meta_1.stripeSubscriptionMeta.nodeName}_stripeSubscriptionId IF NOT EXISTS FOR (${stripe_subscription_meta_1.stripeSubscriptionMeta.nodeName}:${stripe_subscription_meta_1.stripeSubscriptionMeta.labelName}) REQUIRE ${stripe_subscription_meta_1.stripeSubscriptionMeta.nodeName}.stripeSubscriptionId IS UNIQUE`,
50
+ query: `CREATE CONSTRAINT ${S}_stripeSubscriptionId IF NOT EXISTS FOR (${S}:${stripe_subscription_meta_1.stripeSubscriptionMeta.labelName}) REQUIRE ${S}.stripeSubscriptionId IS UNIQUE`,
67
51
  });
68
52
  }
69
53
  /**
70
- * Find subscriptions by stripe customer ID
71
- *
72
- * @param params - Query parameters
73
- * @param params.stripeCustomerId - Stripe customer identifier (internal ID)
74
- * @param params.status - Optional filter by subscription status
75
- * @returns Array of subscriptions ordered by creation date descending
54
+ * The subscription with its company, customer, price, the price's product and its creator.
76
55
  */
77
- async findByStripeCustomerId(params) {
78
- const query = this.neo4j.initQuery({ serialiser: stripe_subscription_model_1.StripeSubscriptionModel });
79
- const whereParams = [];
80
- if (params.status) {
81
- query.queryParams.status = params.status;
82
- whereParams.push(`${stripe_subscription_meta_1.stripeSubscriptionMeta.nodeName}.status = $status`);
83
- }
84
- const where = whereParams.length > 0 ? `AND ${whereParams.join(" AND ")}` : "";
85
- query.queryParams.stripeCustomerId = params.stripeCustomerId;
86
- query.query = `
87
- MATCH (${stripe_subscription_meta_1.stripeSubscriptionMeta.nodeName}:${stripe_subscription_meta_1.stripeSubscriptionMeta.labelName})-[:BELONGS_TO]->(${stripe_customer_meta_1.stripeCustomerMeta.nodeName}:${stripe_customer_meta_1.stripeCustomerMeta.labelName} {id: $stripeCustomerId})
88
- MATCH (${stripe_subscription_meta_1.stripeSubscriptionMeta.nodeName})-[:USES_PRICE]->(${stripe_subscription_meta_1.stripeSubscriptionMeta.nodeName}_${stripe_price_meta_1.stripePriceMeta.nodeName}:${stripe_price_meta_1.stripePriceMeta.labelName})-[:BELONGS_TO]->(${stripe_subscription_meta_1.stripeSubscriptionMeta.nodeName}_${stripe_price_meta_1.stripePriceMeta.nodeName}_${stripe_product_meta_1.stripeProductMeta.nodeName}:${stripe_product_meta_1.stripeProductMeta.labelName})
89
- WHERE 1=1 ${where}
90
- RETURN ${stripe_subscription_meta_1.stripeSubscriptionMeta.nodeName}, ${stripe_subscription_meta_1.stripeSubscriptionMeta.nodeName}_${stripe_price_meta_1.stripePriceMeta.nodeName}, ${stripe_subscription_meta_1.stripeSubscriptionMeta.nodeName}_${stripe_price_meta_1.stripePriceMeta.nodeName}_${stripe_product_meta_1.stripeProductMeta.nodeName}
91
- ORDER BY ${stripe_subscription_meta_1.stripeSubscriptionMeta.nodeName}.createdAt DESC
56
+ buildReturnStatement() {
57
+ return `
58
+ MATCH (${S})-[:BELONGS_TO]->(${S}_${company_meta_1.companyMeta.nodeName}:${company_meta_1.companyMeta.labelName})
59
+ MATCH (${S})-[:BELONGS_TO]->(${S}_stripeCustomer:${stripe_customer_meta_1.stripeCustomerMeta.labelName})
60
+ MATCH (${S})-[:USES_PRICE]->(${S}_stripePrice:${stripe_price_meta_1.stripePriceMeta.labelName})-[:BELONGS_TO]->(${S}_stripePrice_${stripe_product_meta_1.stripeProductMeta.nodeName}:${stripe_product_meta_1.stripeProductMeta.labelName})
61
+ OPTIONAL MATCH (${S})-[:CREATED_BY]->(${S}_createdBy:${user_meta_1.userMeta.labelName})
62
+ RETURN ${S},
63
+ ${S}_${company_meta_1.companyMeta.nodeName},
64
+ ${S}_stripeCustomer,
65
+ ${S}_stripePrice,
66
+ ${S}_stripePrice_${stripe_product_meta_1.stripeProductMeta.nodeName},
67
+ ${S}_createdBy
92
68
  `;
93
- return this.neo4j.readMany(query);
94
69
  }
95
70
  /**
96
- * Find subscription by internal ID
71
+ * The cron finders read across every company. Inside a request `buildDefaultMatch()` would
72
+ * scope them to the caller's company, so they refuse to run there.
73
+ */
74
+ assertNoRequestCompany(method) {
75
+ if (this.clsService.get("companyId")) {
76
+ throw new Error(`StripeSubscriptionRepository.${method} is for the worker cron only, not for a request.`);
77
+ }
78
+ }
79
+ /**
80
+ * Subscriptions of a customer, newest first.
97
81
  *
98
- * @param params - Query parameters
99
- * @param params.id - Internal subscription ID
100
- * @returns Subscription if found, null otherwise
82
+ * @param params.stripeCustomerId - internal StripeCustomer id
83
+ * @param params.status - optional status filter
101
84
  */
102
- async findById(params) {
103
- const query = this.neo4j.initQuery({ serialiser: stripe_subscription_model_1.StripeSubscriptionModel });
85
+ async findByStripeCustomerId(params) {
86
+ const query = this.neo4j.initQuery({ serialiser: stripe_subscription_1.StripeSubscriptionDescriptor.model, fetchAll: true });
104
87
  query.queryParams = {
105
- id: params.id,
88
+ ...query.queryParams,
89
+ stripeCustomerId: params.stripeCustomerId,
90
+ ...(params.status ? { status: params.status } : {}),
106
91
  };
107
- query.query = `
108
- MATCH (${stripe_subscription_meta_1.stripeSubscriptionMeta.nodeName}:${stripe_subscription_meta_1.stripeSubscriptionMeta.labelName} {id: $id})-[:BELONGS_TO]->(${stripe_subscription_meta_1.stripeSubscriptionMeta.nodeName}_${stripe_customer_meta_1.stripeCustomerMeta.nodeName}:${stripe_customer_meta_1.stripeCustomerMeta.labelName})
109
- MATCH (${stripe_subscription_meta_1.stripeSubscriptionMeta.nodeName})-[:USES_PRICE]->(${stripe_subscription_meta_1.stripeSubscriptionMeta.nodeName}_${stripe_price_meta_1.stripePriceMeta.nodeName}:${stripe_price_meta_1.stripePriceMeta.labelName})-[:BELONGS_TO]->(${stripe_subscription_meta_1.stripeSubscriptionMeta.nodeName}_${stripe_price_meta_1.stripePriceMeta.nodeName}_${stripe_product_meta_1.stripeProductMeta.nodeName}:${stripe_product_meta_1.stripeProductMeta.labelName})
110
- RETURN ${stripe_subscription_meta_1.stripeSubscriptionMeta.nodeName}, ${stripe_subscription_meta_1.stripeSubscriptionMeta.nodeName}_${stripe_customer_meta_1.stripeCustomerMeta.nodeName}, ${stripe_subscription_meta_1.stripeSubscriptionMeta.nodeName}_${stripe_price_meta_1.stripePriceMeta.nodeName}, ${stripe_subscription_meta_1.stripeSubscriptionMeta.nodeName}_${stripe_price_meta_1.stripePriceMeta.nodeName}_${stripe_product_meta_1.stripeProductMeta.nodeName}
92
+ query.query += `
93
+ ${this.buildDefaultMatch()}
94
+ MATCH (${S})-[:BELONGS_TO]->(:${stripe_customer_meta_1.stripeCustomerMeta.labelName} {id: $stripeCustomerId})
95
+ ${params.status ? `WHERE ${S}.status = $status` : ``}
96
+ WITH ${S}
97
+ ${this.buildReturnStatement()}
98
+ ORDER BY ${S}.createdAt DESC
111
99
  `;
112
- return this.neo4j.readOne(query);
100
+ return this.neo4j.readMany(query);
113
101
  }
114
102
  /**
115
- * Find every subscription, of every company.
116
- *
117
- * Not company-scoped and not paginated: it serves system jobs that run outside a
118
- * request (the discount backfill), never an endpoint. It matches the same
119
- * customer and price path as {@link update}, so every row it returns can be updated.
120
- *
121
- * @returns All subscriptions ordered by creation date ascending
103
+ * Every subscription, oldest first. Not paginated: it serves system jobs that run outside a
104
+ * request (the discount backfill), never an endpoint.
122
105
  */
123
106
  async findAll() {
124
- const query = this.neo4j.initQuery({ serialiser: stripe_subscription_model_1.StripeSubscriptionModel, fetchAll: true });
107
+ const query = this.neo4j.initQuery({ serialiser: stripe_subscription_1.StripeSubscriptionDescriptor.model, fetchAll: true });
125
108
  query.query += `
126
- MATCH (${stripe_subscription_meta_1.stripeSubscriptionMeta.nodeName}:${stripe_subscription_meta_1.stripeSubscriptionMeta.labelName})-[:BELONGS_TO]->(${stripe_subscription_meta_1.stripeSubscriptionMeta.nodeName}_${stripe_customer_meta_1.stripeCustomerMeta.nodeName}:${stripe_customer_meta_1.stripeCustomerMeta.labelName})
127
- MATCH (${stripe_subscription_meta_1.stripeSubscriptionMeta.nodeName})-[:USES_PRICE]->(${stripe_subscription_meta_1.stripeSubscriptionMeta.nodeName}_${stripe_price_meta_1.stripePriceMeta.nodeName}:${stripe_price_meta_1.stripePriceMeta.labelName})-[:BELONGS_TO]->(${stripe_subscription_meta_1.stripeSubscriptionMeta.nodeName}_${stripe_price_meta_1.stripePriceMeta.nodeName}_${stripe_product_meta_1.stripeProductMeta.nodeName}:${stripe_product_meta_1.stripeProductMeta.labelName})
128
- RETURN ${stripe_subscription_meta_1.stripeSubscriptionMeta.nodeName}, ${stripe_subscription_meta_1.stripeSubscriptionMeta.nodeName}_${stripe_customer_meta_1.stripeCustomerMeta.nodeName}, ${stripe_subscription_meta_1.stripeSubscriptionMeta.nodeName}_${stripe_price_meta_1.stripePriceMeta.nodeName}, ${stripe_subscription_meta_1.stripeSubscriptionMeta.nodeName}_${stripe_price_meta_1.stripePriceMeta.nodeName}_${stripe_product_meta_1.stripeProductMeta.nodeName}
129
- ORDER BY ${stripe_subscription_meta_1.stripeSubscriptionMeta.nodeName}.createdAt ASC
109
+ ${this.buildDefaultMatch()}
110
+ ${this.buildReturnStatement()}
111
+ ORDER BY ${S}.createdAt ASC
130
112
  `;
131
113
  return this.neo4j.readMany(query);
132
114
  }
133
- /**
134
- * Find subscription by Stripe subscription ID
135
- *
136
- * @param params - Query parameters
137
- * @param params.stripeSubscriptionId - Stripe subscription ID
138
- * @returns Subscription if found, null otherwise
139
- */
115
+ /** The subscription with this Stripe subscription id, or null. */
140
116
  async findByStripeSubscriptionId(params) {
141
- const query = this.neo4j.initQuery({ serialiser: stripe_subscription_model_1.StripeSubscriptionModel });
142
- query.queryParams = {
143
- stripeSubscriptionId: params.stripeSubscriptionId,
144
- };
145
- query.query = `
146
- MATCH (${stripe_subscription_meta_1.stripeSubscriptionMeta.nodeName}:${stripe_subscription_meta_1.stripeSubscriptionMeta.labelName} {stripeSubscriptionId: $stripeSubscriptionId})-[:BELONGS_TO]->(${stripe_subscription_meta_1.stripeSubscriptionMeta.nodeName}_${stripe_customer_meta_1.stripeCustomerMeta.nodeName}:${stripe_customer_meta_1.stripeCustomerMeta.labelName})
147
- MATCH (${stripe_subscription_meta_1.stripeSubscriptionMeta.nodeName})-[:USES_PRICE]->(${stripe_subscription_meta_1.stripeSubscriptionMeta.nodeName}_${stripe_price_meta_1.stripePriceMeta.nodeName}:${stripe_price_meta_1.stripePriceMeta.labelName})-[:BELONGS_TO]->(${stripe_subscription_meta_1.stripeSubscriptionMeta.nodeName}_${stripe_price_meta_1.stripePriceMeta.nodeName}_${stripe_product_meta_1.stripeProductMeta.nodeName}:${stripe_product_meta_1.stripeProductMeta.labelName})
148
- RETURN ${stripe_subscription_meta_1.stripeSubscriptionMeta.nodeName}, ${stripe_subscription_meta_1.stripeSubscriptionMeta.nodeName}_${stripe_customer_meta_1.stripeCustomerMeta.nodeName}, ${stripe_subscription_meta_1.stripeSubscriptionMeta.nodeName}_${stripe_price_meta_1.stripePriceMeta.nodeName}, ${stripe_subscription_meta_1.stripeSubscriptionMeta.nodeName}_${stripe_price_meta_1.stripePriceMeta.nodeName}_${stripe_product_meta_1.stripeProductMeta.nodeName}
117
+ const query = this.neo4j.initQuery({ serialiser: stripe_subscription_1.StripeSubscriptionDescriptor.model });
118
+ query.queryParams = { ...query.queryParams, searchValue: params.stripeSubscriptionId };
119
+ query.query += `
120
+ ${this.buildDefaultMatch({ searchField: "stripeSubscriptionId" })}
121
+ ${this.buildReturnStatement()}
149
122
  `;
150
123
  return this.neo4j.readOne(query);
151
124
  }
152
125
  /**
153
- * Create a new subscription
154
- *
155
- * Creates a Subscription node with BELONGS_TO relationship to StripeCustomer
156
- * and USES_PRICE relationship to StripePrice.
157
- *
158
- * @param params - Creation parameters
159
- * @param params.stripeCustomerId - Stripe customer ID to link to
160
- * @param params.priceId - Price ID to link to
161
- * @param params.stripeSubscriptionId - Stripe subscription ID
162
- * @param params.stripeSubscriptionItemId - Optional Stripe subscription item ID
163
- * @param params.status - Subscription status
164
- * @param params.currentPeriodStart - Current billing period start date
165
- * @param params.currentPeriodEnd - Current billing period end date
166
- * @param params.cancelAtPeriodEnd - Whether subscription cancels at period end
167
- * @param params.trialStart - Optional trial start date
168
- * @param params.trialEnd - Optional trial end date
169
- * @param params.quantity - Subscription quantity
170
- * @returns Created Subscription
126
+ * Creates a subscription linked to its customer, its price, the caller's company and the
127
+ * caller. The customer and price ids are checked against the caller's company first.
171
128
  */
172
- async create(params) {
173
- const query = this.neo4j.initQuery({ serialiser: stripe_subscription_model_1.StripeSubscriptionModel });
174
- const id = (0, crypto_1.randomUUID)();
129
+ async createSubscription(params) {
130
+ await this.neo4j.validateRelatedNodes({
131
+ nodes: [
132
+ { id: params.stripeCustomerId, label: stripe_customer_meta_1.stripeCustomerMeta.labelName },
133
+ { id: params.priceId, label: stripe_price_meta_1.stripePriceMeta.labelName },
134
+ ],
135
+ });
136
+ const query = this.neo4j.initQuery({ serialiser: stripe_subscription_1.StripeSubscriptionDescriptor.model });
175
137
  query.queryParams = {
176
138
  ...query.queryParams,
177
- id: id,
139
+ id: (0, crypto_1.randomUUID)(),
178
140
  stripeCustomerId: params.stripeCustomerId,
179
141
  priceId: params.priceId,
180
142
  stripeSubscriptionId: params.stripeSubscriptionId,
@@ -188,11 +150,12 @@ let StripeSubscriptionRepository = class StripeSubscriptionRepository {
188
150
  quantity: params.quantity,
189
151
  ...(0, stripe_subscription_discount_1.discountQueryParams)(params.discount ?? null),
190
152
  };
191
- // Guarded: initQuery() binds this variable only when the id is in CLS; an unbound CREATE target creates an orphan node.
153
+ // Guarded: initQuery() binds `company` / `currentUser` only when CLS holds them; an
154
+ // unbound CREATE target would create an orphan node.
192
155
  query.query += `
193
- MATCH (${stripe_customer_meta_1.stripeCustomerMeta.nodeName}:${stripe_customer_meta_1.stripeCustomerMeta.labelName} {id: $stripeCustomerId})
194
- MATCH (${stripe_subscription_meta_1.stripeSubscriptionMeta.nodeName}_${stripe_price_meta_1.stripePriceMeta.nodeName}:${stripe_price_meta_1.stripePriceMeta.labelName} {id: $priceId})-[:BELONGS_TO]->(${stripe_subscription_meta_1.stripeSubscriptionMeta.nodeName}_${stripe_price_meta_1.stripePriceMeta.nodeName}_${stripe_product_meta_1.stripeProductMeta.nodeName}:${stripe_product_meta_1.stripeProductMeta.labelName})
195
- CREATE (${stripe_subscription_meta_1.stripeSubscriptionMeta.nodeName}:${stripe_subscription_meta_1.stripeSubscriptionMeta.labelName} {
156
+ MATCH (newStripeCustomer:${stripe_customer_meta_1.stripeCustomerMeta.labelName} {id: $stripeCustomerId})
157
+ MATCH (newStripePrice:${stripe_price_meta_1.stripePriceMeta.labelName} {id: $priceId})
158
+ CREATE (${S}:${stripe_subscription_meta_1.stripeSubscriptionMeta.labelName} {
196
159
  id: $id,
197
160
  stripeSubscriptionId: $stripeSubscriptionId,
198
161
  stripeSubscriptionItemId: $stripeSubscriptionItemId,
@@ -212,213 +175,182 @@ let StripeSubscriptionRepository = class StripeSubscriptionRepository {
212
175
  createdAt: datetime(),
213
176
  updatedAt: datetime()
214
177
  })
215
- CREATE (${stripe_subscription_meta_1.stripeSubscriptionMeta.nodeName})-[:BELONGS_TO]->(${stripe_customer_meta_1.stripeCustomerMeta.nodeName})
216
- CREATE (${stripe_subscription_meta_1.stripeSubscriptionMeta.nodeName})-[:USES_PRICE]->(${stripe_subscription_meta_1.stripeSubscriptionMeta.nodeName}_${stripe_price_meta_1.stripePriceMeta.nodeName})
217
- ${query.queryParams.companyId ? `CREATE (${stripe_subscription_meta_1.stripeSubscriptionMeta.nodeName})-[:BELONGS_TO]->(${company_1.companyMeta.nodeName})` : ``}
218
- ${query.queryParams.currentUserId ? `CREATE (${stripe_subscription_meta_1.stripeSubscriptionMeta.nodeName})-[:CREATED_BY]->(currentUser)` : ``}
219
- RETURN ${stripe_subscription_meta_1.stripeSubscriptionMeta.nodeName}, ${stripe_subscription_meta_1.stripeSubscriptionMeta.nodeName}_${stripe_price_meta_1.stripePriceMeta.nodeName}, ${stripe_subscription_meta_1.stripeSubscriptionMeta.nodeName}_${stripe_price_meta_1.stripePriceMeta.nodeName}_${stripe_product_meta_1.stripeProductMeta.nodeName}
178
+ CREATE (${S})-[:BELONGS_TO]->(newStripeCustomer)
179
+ CREATE (${S})-[:USES_PRICE]->(newStripePrice)
180
+ ${query.queryParams.companyId ? `CREATE (${S})-[:BELONGS_TO]->(${company_meta_1.companyMeta.nodeName})` : ``}
181
+ ${query.queryParams.currentUserId ? `CREATE (${S})-[:CREATED_BY]->(currentUser)` : ``}
182
+ WITH ${S}
183
+ ${this.buildReturnStatement()}
220
184
  `;
221
185
  return this.neo4j.writeOne(query);
222
186
  }
223
187
  /**
224
- * Update subscription by internal ID
225
- *
226
- * @param params - Update parameters
227
- * @param params.id - Internal subscription ID
228
- * @param params.status - Optional new status
229
- * @param params.currentPeriodStart - Optional new period start
230
- * @param params.currentPeriodEnd - Optional new period end
231
- * @param params.cancelAtPeriodEnd - Optional cancel at period end flag
232
- * @param params.canceledAt - Optional cancellation date (null to clear)
233
- * @param params.trialStart - Optional trial start date
234
- * @param params.trialEnd - Optional trial end date
235
- * @param params.pausedAt - Optional pause date (null to clear)
236
- * @param params.quantity - Optional new quantity
237
- * @returns Updated Subscription
188
+ * Updates a subscription by internal id. For every optional field, undefined leaves the
189
+ * stored value and (where the type allows it) null clears it.
238
190
  */
239
191
  async update(params) {
240
- const query = this.neo4j.initQuery({ serialiser: stripe_subscription_model_1.StripeSubscriptionModel });
241
- const setParams = [];
242
- setParams.push(`${stripe_subscription_meta_1.stripeSubscriptionMeta.nodeName}.updatedAt = datetime()`);
192
+ const query = this.neo4j.initQuery({ serialiser: stripe_subscription_1.StripeSubscriptionDescriptor.model });
193
+ const setParams = [`${S}.updatedAt = datetime()`];
194
+ const values = {};
243
195
  if (params.status !== undefined) {
244
- setParams.push(`${stripe_subscription_meta_1.stripeSubscriptionMeta.nodeName}.status = $status`);
196
+ setParams.push(`${S}.status = $status`);
197
+ values.status = params.status;
245
198
  }
246
199
  if (params.currentPeriodStart !== undefined) {
247
- setParams.push(`${stripe_subscription_meta_1.stripeSubscriptionMeta.nodeName}.currentPeriodStart = datetime($currentPeriodStart)`);
200
+ setParams.push(`${S}.currentPeriodStart = datetime($currentPeriodStart)`);
201
+ values.currentPeriodStart = params.currentPeriodStart.toISOString();
248
202
  }
249
203
  if (params.currentPeriodEnd !== undefined) {
250
- setParams.push(`${stripe_subscription_meta_1.stripeSubscriptionMeta.nodeName}.currentPeriodEnd = datetime($currentPeriodEnd)`);
204
+ setParams.push(`${S}.currentPeriodEnd = datetime($currentPeriodEnd)`);
205
+ values.currentPeriodEnd = params.currentPeriodEnd.toISOString();
251
206
  }
252
207
  if (params.cancelAtPeriodEnd !== undefined) {
253
- setParams.push(`${stripe_subscription_meta_1.stripeSubscriptionMeta.nodeName}.cancelAtPeriodEnd = $cancelAtPeriodEnd`);
254
- }
255
- if (params.canceledAt !== undefined) {
256
- setParams.push(params.canceledAt === null
257
- ? `${stripe_subscription_meta_1.stripeSubscriptionMeta.nodeName}.canceledAt = null`
258
- : `${stripe_subscription_meta_1.stripeSubscriptionMeta.nodeName}.canceledAt = datetime($canceledAt)`);
208
+ setParams.push(`${S}.cancelAtPeriodEnd = $cancelAtPeriodEnd`);
209
+ values.cancelAtPeriodEnd = params.cancelAtPeriodEnd;
259
210
  }
260
211
  if (params.trialStart !== undefined) {
261
- setParams.push(`${stripe_subscription_meta_1.stripeSubscriptionMeta.nodeName}.trialStart = datetime($trialStart)`);
212
+ setParams.push(`${S}.trialStart = datetime($trialStart)`);
213
+ values.trialStart = params.trialStart.toISOString();
262
214
  }
263
215
  if (params.trialEnd !== undefined) {
264
- setParams.push(`${stripe_subscription_meta_1.stripeSubscriptionMeta.nodeName}.trialEnd = datetime($trialEnd)`);
216
+ setParams.push(`${S}.trialEnd = datetime($trialEnd)`);
217
+ values.trialEnd = params.trialEnd.toISOString();
265
218
  }
266
- if (params.pausedAt !== undefined) {
267
- setParams.push(params.pausedAt === null
268
- ? `${stripe_subscription_meta_1.stripeSubscriptionMeta.nodeName}.pausedAt = null`
269
- : `${stripe_subscription_meta_1.stripeSubscriptionMeta.nodeName}.pausedAt = datetime($pausedAt)`);
219
+ for (const field of CLEARABLE_DATETIME_FIELDS) {
220
+ const value = params[field];
221
+ if (value === undefined)
222
+ continue;
223
+ if (value === null) {
224
+ setParams.push(`${S}.${field} = null`);
225
+ }
226
+ else {
227
+ setParams.push(`${S}.${field} = datetime($${field})`);
228
+ values[field] = value.toISOString();
229
+ }
270
230
  }
271
231
  if (params.quantity !== undefined) {
272
- setParams.push(`${stripe_subscription_meta_1.stripeSubscriptionMeta.nodeName}.quantity = $quantity`);
232
+ setParams.push(`${S}.quantity = $quantity`);
233
+ values.quantity = params.quantity;
273
234
  }
274
235
  // undefined leaves the stored discount as it is; null clears it.
275
236
  if (params.discount !== undefined) {
276
- setParams.push(`${stripe_subscription_meta_1.stripeSubscriptionMeta.nodeName}.discountPercentOff = $discountPercentOff`, `${stripe_subscription_meta_1.stripeSubscriptionMeta.nodeName}.discountAmountOff = $discountAmountOff`, `${stripe_subscription_meta_1.stripeSubscriptionMeta.nodeName}.discountCurrency = $discountCurrency`, `${stripe_subscription_meta_1.stripeSubscriptionMeta.nodeName}.discountDuration = $discountDuration`, `${stripe_subscription_meta_1.stripeSubscriptionMeta.nodeName}.discountDurationInMonths = $discountDurationInMonths`, `${stripe_subscription_meta_1.stripeSubscriptionMeta.nodeName}.discountEnd = CASE WHEN $discountEnd IS NOT NULL THEN datetime($discountEnd) ELSE null END`);
237
+ setParams.push(`${S}.discountPercentOff = $discountPercentOff`, `${S}.discountAmountOff = $discountAmountOff`, `${S}.discountCurrency = $discountCurrency`, `${S}.discountDuration = $discountDuration`, `${S}.discountDurationInMonths = $discountDurationInMonths`, `${S}.discountEnd = CASE WHEN $discountEnd IS NOT NULL THEN datetime($discountEnd) ELSE null END`);
238
+ Object.assign(values, (0, stripe_subscription_discount_1.discountQueryParams)(params.discount));
277
239
  }
278
- query.queryParams = {
279
- id: params.id,
280
- status: params.status,
281
- currentPeriodStart: params.currentPeriodStart?.toISOString(),
282
- currentPeriodEnd: params.currentPeriodEnd?.toISOString(),
283
- cancelAtPeriodEnd: params.cancelAtPeriodEnd,
284
- canceledAt: params.canceledAt?.toISOString(),
285
- trialStart: params.trialStart?.toISOString(),
286
- trialEnd: params.trialEnd?.toISOString(),
287
- pausedAt: params.pausedAt?.toISOString(),
288
- quantity: params.quantity,
289
- ...(params.discount !== undefined ? (0, stripe_subscription_discount_1.discountQueryParams)(params.discount) : {}),
290
- };
291
- query.query = `
292
- MATCH (${stripe_subscription_meta_1.stripeSubscriptionMeta.nodeName}:${stripe_subscription_meta_1.stripeSubscriptionMeta.labelName} {id: $id})-[:BELONGS_TO]->(${stripe_customer_meta_1.stripeCustomerMeta.nodeName}:${stripe_customer_meta_1.stripeCustomerMeta.labelName})
293
- MATCH (${stripe_subscription_meta_1.stripeSubscriptionMeta.nodeName})-[:USES_PRICE]->(${stripe_subscription_meta_1.stripeSubscriptionMeta.nodeName}_${stripe_price_meta_1.stripePriceMeta.nodeName}:${stripe_price_meta_1.stripePriceMeta.labelName})-[:BELONGS_TO]->(${stripe_subscription_meta_1.stripeSubscriptionMeta.nodeName}_${stripe_price_meta_1.stripePriceMeta.nodeName}_${stripe_product_meta_1.stripeProductMeta.nodeName}:${stripe_product_meta_1.stripeProductMeta.labelName})
240
+ query.queryParams = { ...query.queryParams, ...values, searchValue: params.id };
241
+ query.query += `
242
+ ${this.buildDefaultMatch({ searchField: "id" })}
294
243
  SET ${setParams.join(", ")}
295
- RETURN ${stripe_subscription_meta_1.stripeSubscriptionMeta.nodeName}, ${stripe_subscription_meta_1.stripeSubscriptionMeta.nodeName}_${stripe_price_meta_1.stripePriceMeta.nodeName}, ${stripe_subscription_meta_1.stripeSubscriptionMeta.nodeName}_${stripe_price_meta_1.stripePriceMeta.nodeName}_${stripe_product_meta_1.stripeProductMeta.nodeName}
244
+ WITH ${S}
245
+ ${this.buildReturnStatement()}
296
246
  `;
297
247
  return this.neo4j.writeOne(query);
298
248
  }
299
249
  /**
300
- * Update subscription by Stripe subscription ID
250
+ * Updates a subscription by Stripe subscription id (webhook sync).
301
251
  *
302
- * Used primarily by webhook handlers to sync subscription data from Stripe.
303
- *
304
- * @param params - Update parameters
305
- * @param params.stripeSubscriptionId - Stripe subscription ID
306
- * @param params.status - Optional new status
307
- * @param params.currentPeriodStart - Optional new period start
308
- * @param params.currentPeriodEnd - Optional new period end
309
- * @param params.cancelAtPeriodEnd - Optional cancel at period end flag
310
- * @param params.canceledAt - Optional cancellation date (null to clear)
311
- * @param params.trialStart - Optional trial start date
312
- * @param params.trialEnd - Optional trial end date
313
- * @param params.pausedAt - Optional pause date (null to clear)
314
- * @param params.quantity - Optional new quantity
315
- * @returns Updated Subscription if found, null otherwise
252
+ * @returns the updated subscription, or null when none has this id
316
253
  */
317
254
  async updateByStripeSubscriptionId(params) {
318
255
  const existing = await this.findByStripeSubscriptionId({ stripeSubscriptionId: params.stripeSubscriptionId });
319
256
  if (!existing)
320
257
  return null;
321
- return this.update({
322
- id: existing.id,
323
- ...params,
324
- });
258
+ return this.update({ id: existing.id, ...params });
325
259
  }
326
260
  /**
327
- * Update subscription price (change plan)
328
- *
329
- * Removes old USES_PRICE relationship and creates new one to different price.
330
- *
331
- * @param params - Update parameters
332
- * @param params.id - Internal subscription ID
333
- * @param params.newPriceId - New price ID to switch to
334
- * @returns Updated Subscription with new price relationship
261
+ * Moves the subscription to another price (plan change). The price id is checked against
262
+ * the caller's company first.
335
263
  */
336
264
  async updatePrice(params) {
337
- const query = this.neo4j.initQuery({ serialiser: stripe_subscription_model_1.StripeSubscriptionModel });
338
- query.queryParams = {
339
- id: params.id,
340
- newPriceId: params.newPriceId,
341
- };
342
- query.query = `
343
- MATCH (${stripe_subscription_meta_1.stripeSubscriptionMeta.nodeName}:${stripe_subscription_meta_1.stripeSubscriptionMeta.labelName} {id: $id})-[:BELONGS_TO]->(${stripe_customer_meta_1.stripeCustomerMeta.nodeName}:${stripe_customer_meta_1.stripeCustomerMeta.labelName})
344
- MATCH (${stripe_subscription_meta_1.stripeSubscriptionMeta.nodeName})-[oldRel:USES_PRICE]->(:${stripe_price_meta_1.stripePriceMeta.labelName})
265
+ await this.neo4j.validateRelatedNodes({
266
+ nodes: [{ id: params.newPriceId, label: stripe_price_meta_1.stripePriceMeta.labelName }],
267
+ });
268
+ const query = this.neo4j.initQuery({ serialiser: stripe_subscription_1.StripeSubscriptionDescriptor.model });
269
+ query.queryParams = { ...query.queryParams, searchValue: params.id, newPriceId: params.newPriceId };
270
+ query.query += `
271
+ ${this.buildDefaultMatch({ searchField: "id" })}
272
+ MATCH (${S})-[oldRel:USES_PRICE]->(:${stripe_price_meta_1.stripePriceMeta.labelName})
345
273
  DELETE oldRel
346
- WITH ${stripe_subscription_meta_1.stripeSubscriptionMeta.nodeName}, ${stripe_customer_meta_1.stripeCustomerMeta.nodeName}
347
- MATCH (${stripe_subscription_meta_1.stripeSubscriptionMeta.nodeName}_${stripe_price_meta_1.stripePriceMeta.nodeName}:${stripe_price_meta_1.stripePriceMeta.labelName} {id: $newPriceId})-[:BELONGS_TO]->(${stripe_subscription_meta_1.stripeSubscriptionMeta.nodeName}_${stripe_price_meta_1.stripePriceMeta.nodeName}_${stripe_product_meta_1.stripeProductMeta.nodeName}:${stripe_product_meta_1.stripeProductMeta.labelName})
348
- CREATE (${stripe_subscription_meta_1.stripeSubscriptionMeta.nodeName})-[:USES_PRICE]->(${stripe_subscription_meta_1.stripeSubscriptionMeta.nodeName}_${stripe_price_meta_1.stripePriceMeta.nodeName})
349
- SET ${stripe_subscription_meta_1.stripeSubscriptionMeta.nodeName}.updatedAt = datetime()
350
- RETURN ${stripe_subscription_meta_1.stripeSubscriptionMeta.nodeName}, ${stripe_subscription_meta_1.stripeSubscriptionMeta.nodeName}_${stripe_price_meta_1.stripePriceMeta.nodeName}, ${stripe_subscription_meta_1.stripeSubscriptionMeta.nodeName}_${stripe_price_meta_1.stripePriceMeta.nodeName}_${stripe_product_meta_1.stripeProductMeta.nodeName}
274
+ WITH ${S}
275
+ MATCH (newStripePrice:${stripe_price_meta_1.stripePriceMeta.labelName} {id: $newPriceId})
276
+ CREATE (${S})-[:USES_PRICE]->(newStripePrice)
277
+ SET ${S}.updatedAt = datetime()
278
+ WITH ${S}
279
+ ${this.buildReturnStatement()}
351
280
  `;
352
281
  return this.neo4j.writeOne(query);
353
282
  }
354
283
  /**
355
- * Delete subscription
356
- *
357
- * Performs a DETACH DELETE to remove the subscription and all relationships.
358
- *
359
- * @param params - Deletion parameters
360
- * @param params.id - Internal subscription ID
361
- * @returns Promise that resolves when deletion is complete
362
- */
363
- async delete(params) {
364
- const query = this.neo4j.initQuery();
365
- query.queryParams = {
366
- id: params.id,
367
- };
368
- query.query = `
369
- MATCH (${stripe_subscription_meta_1.stripeSubscriptionMeta.nodeName}:${stripe_subscription_meta_1.stripeSubscriptionMeta.labelName} {id: $id})
370
- DETACH DELETE ${stripe_subscription_meta_1.stripeSubscriptionMeta.nodeName}
371
- `;
372
- await this.neo4j.writeOne(query);
373
- }
374
- /**
375
- * Cancel all active subscriptions for a Stripe customer
376
- *
377
- * Bulk operation to cancel all active, trialing, or past_due subscriptions
378
- * when a customer is deleted. Sets status to canceled and updates timestamps.
284
+ * Cancels every active, trialing or past_due subscription of a customer (customer deleted).
379
285
  *
380
- * @param params - Cancellation parameters
381
- * @param params.stripeCustomerId - Stripe customer ID
382
- * @returns Number of subscriptions canceled
286
+ * @param params.stripeCustomerId - Stripe customer id (cus_xxx)
287
+ * @returns number of subscriptions cancelled
383
288
  */
384
289
  async cancelAllByStripeCustomerId(params) {
385
- const query = this.neo4j.initQuery();
290
+ const query = this.neo4j.initQuery({ serialiser: stripe_subscription_1.StripeSubscriptionDescriptor.model });
386
291
  query.queryParams = {
292
+ ...query.queryParams,
387
293
  stripeCustomerId: params.stripeCustomerId,
388
294
  canceledStatus: "canceled",
389
295
  canceledAt: new Date().toISOString(),
390
296
  };
391
- query.query = `
392
- MATCH (${stripe_subscription_meta_1.stripeSubscriptionMeta.nodeName}:${stripe_subscription_meta_1.stripeSubscriptionMeta.labelName})-[:BELONGS_TO]->(${stripe_customer_meta_1.stripeCustomerMeta.nodeName}:${stripe_customer_meta_1.stripeCustomerMeta.labelName} {stripeCustomerId: $stripeCustomerId})
393
- WHERE ${stripe_subscription_meta_1.stripeSubscriptionMeta.nodeName}.status IN ['active', 'trialing', 'past_due']
394
- SET ${stripe_subscription_meta_1.stripeSubscriptionMeta.nodeName}.status = $canceledStatus,
395
- ${stripe_subscription_meta_1.stripeSubscriptionMeta.nodeName}.canceledAt = datetime($canceledAt),
396
- ${stripe_subscription_meta_1.stripeSubscriptionMeta.nodeName}.cancelAtPeriodEnd = false,
397
- ${stripe_subscription_meta_1.stripeSubscriptionMeta.nodeName}.updatedAt = datetime()
398
- RETURN count(${stripe_subscription_meta_1.stripeSubscriptionMeta.nodeName}) as count
297
+ query.query += `
298
+ ${this.buildDefaultMatch()}
299
+ MATCH (${S})-[:BELONGS_TO]->(:${stripe_customer_meta_1.stripeCustomerMeta.labelName} {stripeCustomerId: $stripeCustomerId})
300
+ WHERE ${S}.status IN ['active', 'trialing', 'past_due']
301
+ SET ${S}.status = $canceledStatus,
302
+ ${S}.canceledAt = datetime($canceledAt),
303
+ ${S}.cancelAtPeriodEnd = false,
304
+ ${S}.updatedAt = datetime()
305
+ WITH ${S}
306
+ ${this.buildReturnStatement()}
399
307
  `;
400
- const result = await this.neo4j.writeOne(query);
401
- return result?.count ?? 0;
308
+ const cancelled = await this.neo4j.writeAndReturnMany(query);
309
+ return (cancelled ?? []).length;
402
310
  }
403
311
  /**
404
- * Find all active subscriptions for a Stripe customer
405
- * Used for smart feature removal to check overlapping features
312
+ * Active or trialing subscriptions of a customer, newest first (smart feature removal).
406
313
  *
407
- * @param params - Query parameters
408
- * @param params.stripeCustomerId - Stripe customer ID (cus_xxx format)
409
- * @returns Array of active subscriptions with price and product info
314
+ * @param params.stripeCustomerId - Stripe customer id (cus_xxx)
410
315
  */
411
316
  async findActiveByStripeCustomerId(params) {
412
- const query = this.neo4j.initQuery({ serialiser: stripe_subscription_model_1.StripeSubscriptionModel });
317
+ const query = this.neo4j.initQuery({ serialiser: stripe_subscription_1.StripeSubscriptionDescriptor.model, fetchAll: true });
318
+ query.queryParams = { ...query.queryParams, stripeCustomerId: params.stripeCustomerId };
319
+ query.query += `
320
+ ${this.buildDefaultMatch()}
321
+ MATCH (${S})-[:BELONGS_TO]->(:${stripe_customer_meta_1.stripeCustomerMeta.labelName} {stripeCustomerId: $stripeCustomerId})
322
+ WHERE ${S}.status IN ['active', 'trialing']
323
+ WITH ${S}
324
+ ${this.buildReturnStatement()}
325
+ ORDER BY ${S}.createdAt DESC
326
+ `;
327
+ return this.neo4j.readMany(query);
328
+ }
329
+ /**
330
+ * Worker cron only. Active recurring subscriptions renewing between `now` (excluded) and
331
+ * `before` (included), not cancelling, whose card has not been checked yet for this renewal.
332
+ */
333
+ async findRenewalsForCardCheck(params) {
334
+ this.assertNoRequestCompany("findRenewalsForCardCheck");
335
+ const query = this.neo4j.initQuery({ serialiser: stripe_subscription_1.StripeSubscriptionDescriptor.model, fetchAll: true });
413
336
  query.queryParams = {
414
- stripeCustomerId: params.stripeCustomerId,
337
+ ...query.queryParams,
338
+ now: params.now.toISOString(),
339
+ before: params.before.toISOString(),
415
340
  };
416
- query.query = `
417
- MATCH (${stripe_subscription_meta_1.stripeSubscriptionMeta.nodeName}:${stripe_subscription_meta_1.stripeSubscriptionMeta.labelName})-[:BELONGS_TO]->(${stripe_customer_meta_1.stripeCustomerMeta.nodeName}:${stripe_customer_meta_1.stripeCustomerMeta.labelName} {stripeCustomerId: $stripeCustomerId})
418
- WHERE ${stripe_subscription_meta_1.stripeSubscriptionMeta.nodeName}.status IN ['active', 'trialing']
419
- MATCH (${stripe_subscription_meta_1.stripeSubscriptionMeta.nodeName})-[:USES_PRICE]->(${stripe_subscription_meta_1.stripeSubscriptionMeta.nodeName}_${stripe_price_meta_1.stripePriceMeta.nodeName}:${stripe_price_meta_1.stripePriceMeta.labelName})-[:BELONGS_TO]->(${stripe_subscription_meta_1.stripeSubscriptionMeta.nodeName}_${stripe_price_meta_1.stripePriceMeta.nodeName}_${stripe_product_meta_1.stripeProductMeta.nodeName}:${stripe_product_meta_1.stripeProductMeta.labelName})
420
- RETURN ${stripe_subscription_meta_1.stripeSubscriptionMeta.nodeName}, ${stripe_subscription_meta_1.stripeSubscriptionMeta.nodeName}_${stripe_price_meta_1.stripePriceMeta.nodeName}, ${stripe_subscription_meta_1.stripeSubscriptionMeta.nodeName}_${stripe_price_meta_1.stripePriceMeta.nodeName}_${stripe_product_meta_1.stripeProductMeta.nodeName}
421
- ORDER BY ${stripe_subscription_meta_1.stripeSubscriptionMeta.nodeName}.createdAt DESC
341
+ query.query += `
342
+ ${this.buildDefaultMatch()}
343
+ WHERE ${S}.status = "active"
344
+ AND ${S}.cancelAtPeriodEnd = false
345
+ AND ${S}.currentPeriodEnd > datetime($now)
346
+ AND ${S}.currentPeriodEnd <= datetime($before)
347
+ AND (${S}.cardExpiryCheckedFor IS NULL OR ${S}.cardExpiryCheckedFor <> ${S}.currentPeriodEnd)
348
+ AND EXISTS {
349
+ MATCH (${S})-[:USES_PRICE]->(recurringPrice:${stripe_price_meta_1.stripePriceMeta.labelName})
350
+ WHERE recurringPrice.priceType = "recurring"
351
+ }
352
+ ${this.buildReturnStatement()}
353
+ ORDER BY ${S}.currentPeriodEnd ASC
422
354
  `;
423
355
  return this.neo4j.readMany(query);
424
356
  }
@@ -426,6 +358,6 @@ let StripeSubscriptionRepository = class StripeSubscriptionRepository {
426
358
  exports.StripeSubscriptionRepository = StripeSubscriptionRepository;
427
359
  exports.StripeSubscriptionRepository = StripeSubscriptionRepository = __decorate([
428
360
  (0, common_1.Injectable)(),
429
- __metadata("design:paramtypes", [neo4j_1.Neo4jService])
361
+ __metadata("design:paramtypes", [neo4j_service_1.Neo4jService, security_service_1.SecurityService, nestjs_cls_1.ClsService])
430
362
  ], StripeSubscriptionRepository);
431
363
  //# sourceMappingURL=stripe-subscription.repository.js.map