webhook.service.js 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193
  1. // api/webhooks/webhook.service.js
  2. import moment from "moment";
  3. import i18n from "../../common/i18n.js";
  4. import BaseService from "../../services/base.service.js";
  5. import stripeConf from "../../stripe.conf.js";
  6. import AccountService from "../accounts/account.service.js";
  7. import EmailService from "../emails/email.service.js";
  8. import UserService from "../users/user.service.js";
  9. import Webhook from "./webhook.model.js";
  10. class WebhookService extends BaseService {
  11. getModel() {
  12. return Webhook;
  13. }
  14. async handleWebhook(data) {
  15. this.create({ payload: data });
  16. switch (data.type) {
  17. case "customer.subscription.updated":
  18. this.subscriptionUpdated(data);
  19. break;
  20. case "customer.subscription.created":
  21. this.subscriptionUpdated(data);
  22. break;
  23. case "invoice.paid":
  24. this.paymentSuccessful(data);
  25. break;
  26. case "invoice.payment_failed":
  27. this.paymentFailed(data);
  28. break;
  29. default:
  30. console.log(`Webhook: ${data.type}: No handler`);
  31. }
  32. }
  33. async paymentSuccessful(data) {
  34. const stripeCustomerId = data.data.object.customer;
  35. const account = await AccountService.oneBy({
  36. stripeCustomerId: stripeCustomerId,
  37. });
  38. if (!account) {
  39. return;
  40. }
  41. const user = await UserService.oneBy({
  42. accountId: account.id,
  43. accountOwner: true,
  44. });
  45. if (data.data.object.billing_reason === "subscription_create") {
  46. EmailService.generalNotification(
  47. user.email,
  48. i18n.t("webhookService.newSubscription.subject"),
  49. i18n.t("webhookService.newSubscription.message"),
  50. user.language
  51. );
  52. EmailService.generalNotification(
  53. process.env.NOTIFIED_ADMIN_EMAIL,
  54. i18n.t("webhookService.newSubscription.subject"),
  55. i18n.t("webhookService.newSubscription.messageAdmin", {
  56. email: user.email,
  57. subdomain: account.subdomain,
  58. })
  59. );
  60. }
  61. if (data.data.object.billing_reason === "subscription_update") {
  62. EmailService.generalNotification(
  63. user.email,
  64. i18n.t("webhookService.subscriptionUpdated.subject"),
  65. i18n.t("webhookService.subscriptionUpdated.message"),
  66. user.language
  67. );
  68. EmailService.generalNotification(
  69. process.env.NOTIFIED_ADMIN_EMAIL,
  70. i18n.t("webhookService.subscriptionUpdated.subject"),
  71. i18n.t("webhookService.subscriptionUpdated.messageAdmin", {
  72. email: user.email,
  73. subdomain: account.subdomain,
  74. })
  75. );
  76. }
  77. if (data.data.object.billing_reason === "subscription_cycle") {
  78. EmailService.generalNotification(
  79. user.email,
  80. i18n.t("webhookService.paymentSuccessful.subject"),
  81. i18n.t("webhookService.paymentSuccessful.message"),
  82. user.language
  83. );
  84. EmailService.generalNotification(
  85. process.env.NOTIFIED_ADMIN_EMAIL,
  86. i18n.t("webhookService.paymentSuccessful.subject"),
  87. i18n.t("webhookService.paymentSuccessful.messageAdmin", {
  88. email: user.email,
  89. subdomain: account.subdomain,
  90. })
  91. );
  92. }
  93. AccountService.update(account.id, {
  94. paymentFailed: false,
  95. active: true,
  96. paymentFailedFirstAt: null,
  97. paymentFailedSubscriptionEndsAt: null,
  98. trialPeriodEndsAt: null,
  99. });
  100. }
  101. async subscriptionUpdated(data) {
  102. const stripeCustomerId = data.data.object.customer;
  103. if (data.data.object.status !== "active") {
  104. return;
  105. }
  106. const account = await AccountService.oneBy({
  107. stripeCustomerId: stripeCustomerId,
  108. });
  109. if (!account) {
  110. return;
  111. }
  112. const user = await UserService.oneBy({
  113. accountId: account.id,
  114. accountOwner: true,
  115. });
  116. const expiresAt = data.data.object.cancel_at;
  117. account.subscriptionExpiresAt = expiresAt ? moment.unix(expiresAt) : null;
  118. account.stripePlanId = data.data.object.plan.id;
  119. account.planType = stripeConf.plans.find(
  120. (p) => p.id === data.data.object.plan.id
  121. ).planType;
  122. account.save();
  123. }
  124. async paymentFailed(data) {
  125. const stripeCustomerId = data.data.object.customer;
  126. if (
  127. data.data.object.billing_reason === "subscription_create" ||
  128. data.data.object.billing_reason === "subscription_update"
  129. ) {
  130. return;
  131. }
  132. // if (data.data.object.attempt_count >= 1) {
  133. let account = await AccountService.oneBy({
  134. stripeCustomerId: stripeCustomerId,
  135. });
  136. if (!account) {
  137. return;
  138. }
  139. const user = await UserService.oneBy({
  140. accountId: account.id,
  141. accountOwner: true,
  142. });
  143. if (!account.paymentFailedFirstAt) {
  144. const paymentFailedSubscriptionEndsAt = moment(Date.now()).add(
  145. process.env.PAYMENT_FAILED_RETRY_DAYS,
  146. "days"
  147. );
  148. account = await AccountService.update(account.id, {
  149. paymentFailed: true,
  150. paymentFailedFirstAt: Date.now(),
  151. paymentFailedSubscriptionEndsAt: paymentFailedSubscriptionEndsAt,
  152. });
  153. } else {
  154. account = await AccountService.update(account.id, {
  155. paymentFailed: true,
  156. });
  157. }
  158. const stripeHostedInvoiceUrl = data.data.object.hosted_invoice_url;
  159. EmailService.generalNotification(
  160. user.email,
  161. i18n.t("webhookService.paymentFailed.subject"),
  162. i18n.t("webhookService.paymentFailed.message", {
  163. date: moment(account.paymentFailedSubscriptionEndsAt).format(
  164. "DD/MM/YYYY"
  165. ),
  166. stripeHostedInvoiceUrl: stripeHostedInvoiceUrl,
  167. }),
  168. user.language
  169. );
  170. EmailService.generalNotification(
  171. process.env.NOTIFIED_ADMIN_EMAIL,
  172. i18n.t("webhookService.paymentFailed.subject"),
  173. i18n.t("webhookService.paymentFailed.messageAdmin", {
  174. email: user.email,
  175. subdomain: account.subdomain,
  176. date: moment(account.paymentFailedSubscriptionEndsAt).format(
  177. "DD/MM/YYYY"
  178. ),
  179. })
  180. );
  181. // }
  182. }
  183. }
  184. export default new WebhookService();