@winible/winible-typed 1.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 (243) hide show
  1. package/README.md +32 -0
  2. package/dist/index.js +20 -0
  3. package/dist/index.js.map +1 -0
  4. package/dist/migrations/20220601151258-custom_name_describing_your_migration.js +19 -0
  5. package/dist/migrations/20220601151258-custom_name_describing_your_migration.js.map +1 -0
  6. package/dist/migrations/20220605225655-create-dashboard-user-permissions.js +27 -0
  7. package/dist/migrations/20220605225655-create-dashboard-user-permissions.js.map +1 -0
  8. package/dist/migrations/20220606001300-update-dashboard-user-permissions.js +14 -0
  9. package/dist/migrations/20220606001300-update-dashboard-user-permissions.js.map +1 -0
  10. package/dist/migrations/20220607091109-add-read-date-for-message.js +19 -0
  11. package/dist/migrations/20220607091109-add-read-date-for-message.js.map +1 -0
  12. package/dist/migrations/20220616225456-add-delete-columns.js +21 -0
  13. package/dist/migrations/20220616225456-add-delete-columns.js.map +1 -0
  14. package/dist/migrations/20220709202211-disable-feed.js +24 -0
  15. package/dist/migrations/20220709202211-disable-feed.js.map +1 -0
  16. package/dist/migrations/20220723215213-limit-promotion-claims.js +18 -0
  17. package/dist/migrations/20220723215213-limit-promotion-claims.js.map +1 -0
  18. package/dist/migrations/20220723220233-num_claims.js +12 -0
  19. package/dist/migrations/20220723220233-num_claims.js.map +1 -0
  20. package/dist/migrations/20220723221907-default_false_promos.js +17 -0
  21. package/dist/migrations/20220723221907-default_false_promos.js.map +1 -0
  22. package/dist/migrations/20220724172559-default_zero_claims.js +13 -0
  23. package/dist/migrations/20220724172559-default_zero_claims.js.map +1 -0
  24. package/dist/migrations/20220724201419-pinned_post.js +13 -0
  25. package/dist/migrations/20220724201419-pinned_post.js.map +1 -0
  26. package/dist/migrations/20220729164625-unsend_mass.js +12 -0
  27. package/dist/migrations/20220729164625-unsend_mass.js.map +1 -0
  28. package/dist/migrations/20220823033002-interval-unit.js +14 -0
  29. package/dist/migrations/20220823033002-interval-unit.js.map +1 -0
  30. package/dist/migrations/20220830193530-processorId.js +15 -0
  31. package/dist/migrations/20220830193530-processorId.js.map +1 -0
  32. package/dist/migrations/20220907121932-add-processor-to-sub.js +15 -0
  33. package/dist/migrations/20220907121932-add-processor-to-sub.js.map +1 -0
  34. package/dist/migrations/20220907212232-add-trans-id.js +12 -0
  35. package/dist/migrations/20220907212232-add-trans-id.js.map +1 -0
  36. package/dist/migrations/20220907220423-big-int-trans.js +12 -0
  37. package/dist/migrations/20220907220423-big-int-trans.js.map +1 -0
  38. package/dist/migrations/20220909161902-add-stale.js +13 -0
  39. package/dist/migrations/20220909161902-add-stale.js.map +1 -0
  40. package/dist/migrations/20220922000225-verified-spender.js +13 -0
  41. package/dist/migrations/20220922000225-verified-spender.js.map +1 -0
  42. package/dist/migrations/20220922212108-verified-spender-2.js +16 -0
  43. package/dist/migrations/20220922212108-verified-spender-2.js.map +1 -0
  44. package/dist/migrations/20221013223648-product-subscription-list.js +12 -0
  45. package/dist/migrations/20221013223648-product-subscription-list.js.map +1 -0
  46. package/dist/migrations/20221014001037-product-subscription-list.js +75 -0
  47. package/dist/migrations/20221014001037-product-subscription-list.js.map +1 -0
  48. package/dist/migrations/20221026055245-update-type.js +15 -0
  49. package/dist/migrations/20221026055245-update-type.js.map +1 -0
  50. package/dist/scripts/authorizeTransfer.js +188 -0
  51. package/dist/scripts/authorizeTransfer.js.map +1 -0
  52. package/dist/scripts/createDashboardLink.js +30 -0
  53. package/dist/scripts/createDashboardLink.js.map +1 -0
  54. package/dist/scripts/deleteMalformedImages.js +84 -0
  55. package/dist/scripts/deleteMalformedImages.js.map +1 -0
  56. package/dist/scripts/importMixpanelEvents.js +44 -0
  57. package/dist/scripts/importMixpanelEvents.js.map +1 -0
  58. package/dist/scripts/payoutSubscriptions.js +185 -0
  59. package/dist/scripts/payoutSubscriptions.js.map +1 -0
  60. package/dist/scripts/removeUnreferenceSubs.js +39 -0
  61. package/dist/scripts/removeUnreferenceSubs.js.map +1 -0
  62. package/dist/scripts/test.js +33 -0
  63. package/dist/scripts/test.js.map +1 -0
  64. package/dist/server/index.js +30 -0
  65. package/dist/server/index.js.map +1 -0
  66. package/dist/server/middlewares/slack-auth.js +40 -0
  67. package/dist/server/middlewares/slack-auth.js.map +1 -0
  68. package/dist/server/v1/bypassCreator.js +81 -0
  69. package/dist/server/v1/bypassCreator.js.map +1 -0
  70. package/dist/server/v1/cancelSubscription.js +35 -0
  71. package/dist/server/v1/cancelSubscription.js.map +1 -0
  72. package/dist/server/v1/changeName.js +41 -0
  73. package/dist/server/v1/changeName.js.map +1 -0
  74. package/dist/server/v1/checkAuthSub.js +58 -0
  75. package/dist/server/v1/checkAuthSub.js.map +1 -0
  76. package/dist/server/v1/dashboardLink.js +30 -0
  77. package/dist/server/v1/dashboardLink.js.map +1 -0
  78. package/dist/server/v1/getSuspendedSubs.js +76 -0
  79. package/dist/server/v1/getSuspendedSubs.js.map +1 -0
  80. package/dist/server/v1/index.js +28 -0
  81. package/dist/server/v1/index.js.map +1 -0
  82. package/dist/server/v1/manualCreateSub.js +159 -0
  83. package/dist/server/v1/manualCreateSub.js.map +1 -0
  84. package/dist/server/v1/refund.js +78 -0
  85. package/dist/server/v1/refund.js.map +1 -0
  86. package/dist/server/v1/retrySubscription.js +81 -0
  87. package/dist/server/v1/retrySubscription.js.map +1 -0
  88. package/dist/server/v1/searchUser.js +169 -0
  89. package/dist/server/v1/searchUser.js.map +1 -0
  90. package/dist/server/v1/slack.js +14 -0
  91. package/dist/server/v1/slack.js.map +1 -0
  92. package/dist/src/index.js +24 -0
  93. package/dist/src/index.js.map +1 -0
  94. package/dist/src/pk-client.js +1103 -0
  95. package/dist/src/pk-client.js.map +1 -0
  96. package/dist/src/pk-sub.js +310 -0
  97. package/dist/src/pk-sub.js.map +1 -0
  98. package/dist/src/slack-client.js +48 -0
  99. package/dist/src/slack-client.js.map +1 -0
  100. package/dist/src/types.js +3 -0
  101. package/dist/src/types.js.map +1 -0
  102. package/dist/support/index.js +19 -0
  103. package/dist/support/index.js.map +1 -0
  104. package/dist/support/metrics.js +21 -0
  105. package/dist/support/metrics.js.map +1 -0
  106. package/dist/support/mixpanel.js +7 -0
  107. package/dist/support/mixpanel.js.map +1 -0
  108. package/dist/support/slack-client.js +51 -0
  109. package/dist/support/slack-client.js.map +1 -0
  110. package/dist/support/uploadcare.js +140 -0
  111. package/dist/support/uploadcare.js.map +1 -0
  112. package/dist/support/utils.js +69 -0
  113. package/dist/support/utils.js.map +1 -0
  114. package/dist/typed-model/asset-category.js +38 -0
  115. package/dist/typed-model/asset-category.js.map +1 -0
  116. package/dist/typed-model/asset-constent-person.js +56 -0
  117. package/dist/typed-model/asset-constent-person.js.map +1 -0
  118. package/dist/typed-model/blocked-ip.js +34 -0
  119. package/dist/typed-model/blocked-ip.js.map +1 -0
  120. package/dist/typed-model/category-tag.js +46 -0
  121. package/dist/typed-model/category-tag.js.map +1 -0
  122. package/dist/typed-model/consent-person.js +55 -0
  123. package/dist/typed-model/consent-person.js.map +1 -0
  124. package/dist/typed-model/content-category-tag.js +58 -0
  125. package/dist/typed-model/content-category-tag.js.map +1 -0
  126. package/dist/typed-model/content-like.js +58 -0
  127. package/dist/typed-model/content-like.js.map +1 -0
  128. package/dist/typed-model/credit-payment.js +389 -0
  129. package/dist/typed-model/credit-payment.js.map +1 -0
  130. package/dist/typed-model/credit-payout.js +42 -0
  131. package/dist/typed-model/credit-payout.js.map +1 -0
  132. package/dist/typed-model/credit-purchase.js +46 -0
  133. package/dist/typed-model/credit-purchase.js.map +1 -0
  134. package/dist/typed-model/customer-profile.js +51 -0
  135. package/dist/typed-model/customer-profile.js.map +1 -0
  136. package/dist/typed-model/dashboard-user-permissions.js +34 -0
  137. package/dist/typed-model/dashboard-user-permissions.js.map +1 -0
  138. package/dist/typed-model/dashboard-user.js +109 -0
  139. package/dist/typed-model/dashboard-user.js.map +1 -0
  140. package/dist/typed-model/fan-list.js +46 -0
  141. package/dist/typed-model/fan-list.js.map +1 -0
  142. package/dist/typed-model/fraud.js +41 -0
  143. package/dist/typed-model/fraud.js.map +1 -0
  144. package/dist/typed-model/index.js +101 -0
  145. package/dist/typed-model/index.js.map +1 -0
  146. package/dist/typed-model/list-member.js +47 -0
  147. package/dist/typed-model/list-member.js.map +1 -0
  148. package/dist/typed-model/mass-message.js +43 -0
  149. package/dist/typed-model/mass-message.js.map +1 -0
  150. package/dist/typed-model/media-asset.js +73 -0
  151. package/dist/typed-model/media-asset.js.map +1 -0
  152. package/dist/typed-model/media-category.js +49 -0
  153. package/dist/typed-model/media-category.js.map +1 -0
  154. package/dist/typed-model/media.js +59 -0
  155. package/dist/typed-model/media.js.map +1 -0
  156. package/dist/typed-model/message-media.js +53 -0
  157. package/dist/typed-model/message-media.js.map +1 -0
  158. package/dist/typed-model/message.js +191 -0
  159. package/dist/typed-model/message.js.map +1 -0
  160. package/dist/typed-model/notification.js +84 -0
  161. package/dist/typed-model/notification.js.map +1 -0
  162. package/dist/typed-model/pb-sequelize.js +25 -0
  163. package/dist/typed-model/pb-sequelize.js.map +1 -0
  164. package/dist/typed-model/phone-chat-participation.js +127 -0
  165. package/dist/typed-model/phone-chat-participation.js.map +1 -0
  166. package/dist/typed-model/phone-chat.js +118 -0
  167. package/dist/typed-model/phone-chat.js.map +1 -0
  168. package/dist/typed-model/phone-owner.js +266 -0
  169. package/dist/typed-model/phone-owner.js.map +1 -0
  170. package/dist/typed-model/phone-user.js +109 -0
  171. package/dist/typed-model/phone-user.js.map +1 -0
  172. package/dist/typed-model/premium-content.js +123 -0
  173. package/dist/typed-model/premium-content.js.map +1 -0
  174. package/dist/typed-model/purchased-content.js +69 -0
  175. package/dist/typed-model/purchased-content.js.map +1 -0
  176. package/dist/typed-model/short-url.js +88 -0
  177. package/dist/typed-model/short-url.js.map +1 -0
  178. package/dist/typed-model/subscription-bundle.js +53 -0
  179. package/dist/typed-model/subscription-bundle.js.map +1 -0
  180. package/dist/typed-model/subscription-category-tags.js +58 -0
  181. package/dist/typed-model/subscription-category-tags.js.map +1 -0
  182. package/dist/typed-model/subscription-plan.js +126 -0
  183. package/dist/typed-model/subscription-plan.js.map +1 -0
  184. package/dist/typed-model/subscription-promotion.js +93 -0
  185. package/dist/typed-model/subscription-promotion.js.map +1 -0
  186. package/dist/typed-model/subscription.js +123 -0
  187. package/dist/typed-model/subscription.js.map +1 -0
  188. package/dist/typed-model/twilio-phone.js +92 -0
  189. package/dist/typed-model/twilio-phone.js.map +1 -0
  190. package/dist/typed-model/user-follow.js +103 -0
  191. package/dist/typed-model/user-follow.js.map +1 -0
  192. package/dist/typed-model/verification-code.js +52 -0
  193. package/dist/typed-model/verification-code.js.map +1 -0
  194. package/index.ts +3 -0
  195. package/package.json +72 -0
  196. package/src/index.ts +2 -0
  197. package/src/pk-client.ts +1650 -0
  198. package/src/pk-sub.ts +455 -0
  199. package/src/types.ts +40 -0
  200. package/support/index.ts +2 -0
  201. package/support/slack-client.ts +43 -0
  202. package/support/uploadcare.ts +191 -0
  203. package/support/utils.ts +72 -0
  204. package/typed-model/asset-category.ts +57 -0
  205. package/typed-model/asset-constent-person.ts +82 -0
  206. package/typed-model/blocked-ip.ts +52 -0
  207. package/typed-model/category-tag.ts +66 -0
  208. package/typed-model/consent-person.ts +78 -0
  209. package/typed-model/content-category-tag.ts +79 -0
  210. package/typed-model/content-like.ts +79 -0
  211. package/typed-model/credit-payment.ts +678 -0
  212. package/typed-model/credit-payout.ts +62 -0
  213. package/typed-model/credit-purchase.ts +67 -0
  214. package/typed-model/customer-profile.ts +70 -0
  215. package/typed-model/dashboard-user-permissions.ts +51 -0
  216. package/typed-model/dashboard-user.ts +146 -0
  217. package/typed-model/fan-list.ts +68 -0
  218. package/typed-model/fraud.ts +62 -0
  219. package/typed-model/index.ts +58 -0
  220. package/typed-model/list-member.ts +67 -0
  221. package/typed-model/mass-message.ts +64 -0
  222. package/typed-model/media-asset.ts +99 -0
  223. package/typed-model/media-category.ts +70 -0
  224. package/typed-model/media.ts +85 -0
  225. package/typed-model/message-media.ts +74 -0
  226. package/typed-model/message.ts +258 -0
  227. package/typed-model/notification.ts +130 -0
  228. package/typed-model/pb-sequelize.ts +25 -0
  229. package/typed-model/phone-chat-participation.ts +166 -0
  230. package/typed-model/phone-chat.ts +185 -0
  231. package/typed-model/phone-owner.ts +341 -0
  232. package/typed-model/phone-user.ts +146 -0
  233. package/typed-model/premium-content.ts +164 -0
  234. package/typed-model/purchased-content.ts +100 -0
  235. package/typed-model/short-url.ts +120 -0
  236. package/typed-model/subscription-bundle.ts +75 -0
  237. package/typed-model/subscription-category-tags.ts +79 -0
  238. package/typed-model/subscription-plan.ts +171 -0
  239. package/typed-model/subscription-promotion.ts +125 -0
  240. package/typed-model/subscription.ts +170 -0
  241. package/typed-model/twilio-phone.ts +149 -0
  242. package/typed-model/user-follow.ts +141 -0
  243. package/typed-model/verification-code.ts +74 -0
@@ -0,0 +1,678 @@
1
+ import { Transaction } from "sequelize";
2
+ import {
3
+ Model,
4
+ InferAttributes,
5
+ InferCreationAttributes,
6
+ CreationOptional,
7
+ DataTypes,
8
+ fn,
9
+ NOW,
10
+ } from "sequelize";
11
+
12
+ import sequelize from "./pb-sequelize";
13
+ import PhoneOwner from "./phone-owner";
14
+ import PhoneUser from "./phone-user";
15
+ import PremiumContent from "./premium-content";
16
+ import Message from "./message";
17
+ import Subscription from "./subscription";
18
+ import PurchasedContent from "./purchased-content";
19
+ import Notification from "./notification";
20
+
21
+ type InteractionType =
22
+ | "subscription"
23
+ | "tip"
24
+ | "text"
25
+ | "unlock_message"
26
+ | "content"
27
+ | "unlock"
28
+ | "audio"
29
+ | "referral"
30
+ | "video";
31
+
32
+ const INTERACTION_TYPES: { [key: string]: InteractionType } = {
33
+ CONTENT: "content",
34
+ AUDIO: "audio",
35
+ TEXT: "text",
36
+ VIDEO: "video",
37
+ TIP: "tip",
38
+ UNLOCK: "unlock",
39
+ UNLOCK_MESSAGE: "unlock_message",
40
+ REFERRAL: "referral",
41
+ SUBSCRIPTION: "subscription",
42
+ };
43
+
44
+ // order of InferAttributes & InferCreationAttributes is important.
45
+ class CreditPayments extends Model<
46
+ InferAttributes<CreditPayments>,
47
+ InferCreationAttributes<CreditPayments>
48
+ > {
49
+ // 'CreationOptional' is a special type that marks the field as optional
50
+ // when creating an instance of the model (such as using Model.create()).
51
+ declare id: CreationOptional<string>;
52
+ declare userId?: string;
53
+ declare ownerId: string;
54
+ declare creditAmountInCents: number;
55
+ declare interactionType: InteractionType;
56
+ declare payoutDate?: Date;
57
+ declare metadata?: string;
58
+ declare earningAmountInCents: number;
59
+ declare payoutId?: string;
60
+ declare referredCreditPaymentId?: string;
61
+ declare transId?: number;
62
+ declare createdAt: CreationOptional<Date>;
63
+ declare updatedAt: CreationOptional<Date>;
64
+ static getById: (id: string) => Promise<CreditPayments | null>;
65
+ static logContentPurchase: (
66
+ user: PhoneUser,
67
+ contentId: string,
68
+ owner: PhoneOwner,
69
+ alreadyPaid?: boolean,
70
+ transaction?: Transaction,
71
+ transId?: number
72
+ ) => Promise<CreditPayments>;
73
+ static logMessage: (
74
+ user: PhoneUser,
75
+ owner: PhoneOwner,
76
+ chatRateInCents: number
77
+ ) => Promise<CreditPayments>;
78
+ static logTip: (
79
+ user: PhoneUser,
80
+ owner: PhoneOwner,
81
+ tipAmountInCents: number
82
+ ) => Promise<CreditPayments>;
83
+ static logAudioCall: (
84
+ user: PhoneUser,
85
+ owner: PhoneOwner,
86
+ callAmountInCents: number
87
+ ) => Promise<CreditPayments>;
88
+ static logVideoCall: (
89
+ user: PhoneUser,
90
+ owner: PhoneOwner,
91
+ callAmountInCents: number
92
+ ) => Promise<CreditPayments>;
93
+ static logUnlockMessage: (
94
+ user: PhoneUser,
95
+ owner: PhoneOwner,
96
+ message: Message,
97
+ alreadyPaid?: boolean,
98
+ transaction?: Transaction,
99
+ transId?: number
100
+ ) => Promise<CreditPayments>;
101
+ static logSubscriptionPayment: (
102
+ userId: string,
103
+ owner: PhoneOwner,
104
+ subscriptionAmountInCents: number,
105
+ subscription: Subscription,
106
+ transaction: Transaction | undefined,
107
+ transId: number
108
+ ) => Promise<CreditPayments>;
109
+ static logUnlockedContent: (
110
+ user: PhoneUser,
111
+ owner: PhoneOwner,
112
+ lockedContent: PremiumContent
113
+ ) => Promise<CreditPayments>;
114
+ }
115
+
116
+ CreditPayments.init(
117
+ {
118
+ id: {
119
+ type: DataTypes.BIGINT,
120
+ primaryKey: true,
121
+ allowNull: false,
122
+ defaultValue: sequelize.fn("next_id"),
123
+ },
124
+ userId: {
125
+ type: DataTypes.BIGINT,
126
+ field: "user_id",
127
+ },
128
+ ownerId: {
129
+ type: DataTypes.BIGINT,
130
+ allowNull: false,
131
+ field: "owner_id",
132
+ },
133
+ creditAmountInCents: {
134
+ type: DataTypes.INTEGER,
135
+ field: "credit_amount_in_cents",
136
+ },
137
+ interactionType: {
138
+ type: DataTypes.STRING,
139
+ field: "interaction_type",
140
+ },
141
+ payoutDate: {
142
+ type: DataTypes.DATE,
143
+ field: "payout_date",
144
+ },
145
+ metadata: {
146
+ type: DataTypes.STRING,
147
+ field: "metadata",
148
+ },
149
+ earningAmountInCents: {
150
+ type: DataTypes.INTEGER,
151
+ field: "earning_amount_in_cents",
152
+ },
153
+ payoutId: {
154
+ type: DataTypes.BIGINT,
155
+ field: "payout_id",
156
+ },
157
+ referredCreditPaymentId: {
158
+ type: DataTypes.BIGINT,
159
+ field: "referred_credit_payment_id",
160
+ },
161
+ transId: {
162
+ type: DataTypes.BIGINT,
163
+ field: "trans_id",
164
+ },
165
+ createdAt: DataTypes.DATE,
166
+ updatedAt: DataTypes.DATE,
167
+ },
168
+ {
169
+ // Other model options go here
170
+ tableName: "credit_payments",
171
+ sequelize,
172
+ }
173
+ );
174
+
175
+ const REFERRAL_PERCENTAGE = 0.03;
176
+
177
+ /*
178
+ ====================================================================
179
+ Class functions
180
+ ====================================================================
181
+ */
182
+
183
+ CreditPayments.getById = async (id: string) => {
184
+ return await CreditPayments.findOne({
185
+ where: {
186
+ id,
187
+ },
188
+ });
189
+ };
190
+
191
+ CreditPayments.logContentPurchase = async (
192
+ user: PhoneUser,
193
+ contentId: string,
194
+ owner: PhoneOwner,
195
+ alreadyPaid?: boolean,
196
+ transaction?: Transaction,
197
+ transId?: number
198
+ ) => {
199
+ const content = await PremiumContent.getById(contentId);
200
+
201
+ if (!content) {
202
+ throw new Error("No such content for id: " + contentId);
203
+ }
204
+
205
+ if (user.creditsInCents! < content.amountInCents! && !alreadyPaid) {
206
+ throw new Error("Not enough credits");
207
+ }
208
+
209
+ if (content.amountInCents! < 0) {
210
+ throw new Error("Cannot be less than 0");
211
+ }
212
+
213
+ let purchasedContent = await PurchasedContent.create(
214
+ {
215
+ userId: user.id!,
216
+ contentId: content.id!,
217
+ },
218
+ { transaction }
219
+ );
220
+
221
+ if (!alreadyPaid) {
222
+ user.creditsInCents = user.creditsInCents! - content.amountInCents!;
223
+ await user.save({ transaction });
224
+ }
225
+
226
+ let creditPayment = await CreditPayments.create(
227
+ {
228
+ userId: user.id,
229
+ ownerId: content.ownerId,
230
+ creditAmountInCents: content.amountInCents!,
231
+ earningAmountInCents: earningsAmount(
232
+ content.amountInCents!,
233
+ owner && owner.serviceFeePercentage
234
+ ),
235
+ interactionType: INTERACTION_TYPES.CONTENT,
236
+ metadata: JSON.stringify({ contentId }),
237
+ transId,
238
+ },
239
+ { transaction }
240
+ );
241
+
242
+ try {
243
+ await Notification.create(
244
+ {
245
+ ownerId: content.ownerId,
246
+ userId: user.id,
247
+ creditPaymentId: creditPayment.id,
248
+ type: "content",
249
+ purchasedContentId: purchasedContent.id,
250
+ },
251
+ { transaction }
252
+ );
253
+ } catch (err) {
254
+ console.log(err);
255
+ }
256
+
257
+ if (owner && owner.referringOwnerId) {
258
+ await createReferralPayment(
259
+ owner,
260
+ creditPayment,
261
+ content.amountInCents!,
262
+ transaction
263
+ );
264
+ }
265
+
266
+ if (user.referringOwnerId) {
267
+ await createUserReferralPayment(
268
+ user,
269
+ creditPayment,
270
+ content.amountInCents!,
271
+ transaction
272
+ );
273
+ }
274
+
275
+ return creditPayment;
276
+ };
277
+
278
+ CreditPayments.logTip = async (
279
+ user: PhoneUser,
280
+ owner: PhoneOwner,
281
+ tipAmountInCents: number
282
+ ) => {
283
+ if (tipAmountInCents > user.creditsInCents!) {
284
+ let url = await getPaymentUrl(user, owner);
285
+ throw new Error(
286
+ `Sorry, it looks like you've run out of credits. To send a tip, add more credits here: ${url}`
287
+ );
288
+ }
289
+
290
+ if (tipAmountInCents < 0) {
291
+ throw new Error("Cannot be less than 0");
292
+ }
293
+
294
+ user.creditsInCents = user.creditsInCents! - tipAmountInCents;
295
+ await user.save();
296
+
297
+ let creditPayment = await CreditPayments.create({
298
+ userId: user.id,
299
+ ownerId: owner.id,
300
+ creditAmountInCents: tipAmountInCents,
301
+ earningAmountInCents: earningsAmount(
302
+ tipAmountInCents,
303
+ owner.serviceFeePercentage
304
+ ),
305
+ interactionType: INTERACTION_TYPES.TIP,
306
+ });
307
+
308
+ if (owner.referringOwnerId) {
309
+ await createReferralPayment(owner, creditPayment, tipAmountInCents);
310
+ }
311
+
312
+ if (user.referringOwnerId) {
313
+ await createUserReferralPayment(user, creditPayment, tipAmountInCents);
314
+ }
315
+
316
+ try {
317
+ await Notification.create({
318
+ ownerId: owner.id,
319
+ userId: user.id,
320
+ creditPaymentId: creditPayment.id,
321
+ type: "tip",
322
+ });
323
+ } catch (err) {
324
+ console.log(err);
325
+ }
326
+
327
+ return creditPayment;
328
+ };
329
+
330
+ CreditPayments.logMessage = async (
331
+ user: PhoneUser,
332
+ owner: PhoneOwner,
333
+ chatRateInCents: number
334
+ ) => {
335
+ if (chatRateInCents > user.creditsInCents!) {
336
+ let url = await getPaymentUrl(user, owner);
337
+ throw new Error(
338
+ `Sorry, it looks like you've run out of credits. To keep texting, add more credits here: ${url}`
339
+ );
340
+ }
341
+
342
+ if (chatRateInCents < 0) {
343
+ throw new Error("Cannot be less than 0");
344
+ }
345
+
346
+ user.creditsInCents = user.creditsInCents! - chatRateInCents;
347
+ await user.save();
348
+
349
+ let creditPayment = await CreditPayments.create({
350
+ userId: user.id,
351
+ ownerId: owner.id,
352
+ creditAmountInCents: chatRateInCents,
353
+ earningAmountInCents: earningsAmount(chatRateInCents),
354
+ interactionType: INTERACTION_TYPES.TEXT,
355
+ });
356
+
357
+ if (owner.referringOwnerId) {
358
+ await createReferralPayment(owner, creditPayment, chatRateInCents);
359
+ }
360
+
361
+ if (user.referringOwnerId) {
362
+ await createUserReferralPayment(user, creditPayment, chatRateInCents);
363
+ }
364
+
365
+ return creditPayment;
366
+ };
367
+
368
+ CreditPayments.logAudioCall = async (
369
+ user: PhoneUser,
370
+ owner: PhoneOwner,
371
+ callAmountInCents: number
372
+ ) => {
373
+ if (callAmountInCents < 0) {
374
+ throw new Error("Cannot be less than 0");
375
+ }
376
+
377
+ user.creditsInCents = user.creditsInCents! - callAmountInCents;
378
+ await user.save();
379
+
380
+ let creditPayment = await CreditPayments.create({
381
+ userId: user.id,
382
+ ownerId: owner.id,
383
+ creditAmountInCents: callAmountInCents,
384
+ earningAmountInCents: earningsAmount(
385
+ callAmountInCents,
386
+ owner.serviceFeePercentage
387
+ ),
388
+ interactionType: INTERACTION_TYPES.AUDIO,
389
+ });
390
+
391
+ if (owner.referringOwnerId) {
392
+ await createReferralPayment(owner, creditPayment, callAmountInCents);
393
+ }
394
+
395
+ if (user.referringOwnerId) {
396
+ await createUserReferralPayment(user, creditPayment, callAmountInCents);
397
+ }
398
+
399
+ return creditPayment;
400
+ };
401
+
402
+ CreditPayments.logVideoCall = async (
403
+ user: PhoneUser,
404
+ owner: PhoneOwner,
405
+ callAmountInCents: number
406
+ ) => {
407
+ if (callAmountInCents < 0) {
408
+ throw new Error("Cannot be less than 0");
409
+ }
410
+
411
+ user.creditsInCents = user.creditsInCents! - callAmountInCents;
412
+ await user.save();
413
+
414
+ let creditPayment = await CreditPayments.create({
415
+ userId: user.id,
416
+ ownerId: owner.id,
417
+ creditAmountInCents: callAmountInCents,
418
+ earningAmountInCents: earningsAmount(
419
+ callAmountInCents,
420
+ owner.serviceFeePercentage
421
+ ),
422
+ interactionType: INTERACTION_TYPES.VIDEO,
423
+ });
424
+
425
+ if (owner.referringOwnerId) {
426
+ await createReferralPayment(owner, creditPayment, callAmountInCents);
427
+ }
428
+
429
+ if (user.referringOwnerId) {
430
+ await createUserReferralPayment(user, creditPayment, callAmountInCents);
431
+ }
432
+
433
+ return creditPayment;
434
+ };
435
+
436
+ CreditPayments.logUnlockMessage = async (
437
+ user: PhoneUser,
438
+ owner: PhoneOwner,
439
+ message: Message,
440
+ alreadyPaid?: boolean,
441
+ transaction?: Transaction,
442
+ transId?: number
443
+ ) => {
444
+ if (message.amountInCents! > user.creditsInCents! && !alreadyPaid) {
445
+ throw new Error(`Sorry, it looks like you've run out of credits`);
446
+ }
447
+
448
+ if (!message.amountInCents) {
449
+ throw new Error("Must contain message amount");
450
+ }
451
+
452
+ if (message.amountInCents! < 0) {
453
+ throw new Error("Cannot be less than 0");
454
+ }
455
+
456
+ if (!alreadyPaid) {
457
+ user.creditsInCents = user.creditsInCents! - message.amountInCents!;
458
+ await user.save({ transaction });
459
+ }
460
+
461
+ let creditPayment = await CreditPayments.create(
462
+ {
463
+ userId: user.id,
464
+ ownerId: owner.id,
465
+ creditAmountInCents: message.amountInCents!,
466
+ earningAmountInCents: earningsAmount(
467
+ message.amountInCents!,
468
+ owner.serviceFeePercentage
469
+ ),
470
+ transId,
471
+ interactionType: INTERACTION_TYPES.UNLOCK_MESSAGE,
472
+ },
473
+ { transaction }
474
+ );
475
+
476
+ try {
477
+ await Notification.create(
478
+ {
479
+ ownerId: owner.id,
480
+ userId: user.id,
481
+ creditPaymentId: creditPayment.id,
482
+ type: "unlock_message",
483
+ messageId: message.id,
484
+ },
485
+ { transaction }
486
+ );
487
+ } catch (err) {
488
+ console.log(err);
489
+ }
490
+
491
+ if (owner.referringOwnerId) {
492
+ await createReferralPayment(
493
+ owner,
494
+ creditPayment,
495
+ message.amountInCents!,
496
+ transaction
497
+ );
498
+ }
499
+
500
+ return creditPayment;
501
+ };
502
+
503
+ CreditPayments.logUnlockedContent = async (
504
+ user: PhoneUser,
505
+ owner: PhoneOwner,
506
+ lockedContent: PremiumContent
507
+ ) => {
508
+ if (lockedContent.amountInCents! < 0) {
509
+ throw new Error("Cannot be less than 0");
510
+ }
511
+
512
+ if (lockedContent.amountInCents! > user.creditsInCents!) {
513
+ let url = await getPaymentUrl(user, owner);
514
+ throw new Error(
515
+ `Sorry, it looks like you've run out of credits. To unlock this content, add more credits here: ${url}`
516
+ );
517
+ }
518
+
519
+ user.creditsInCents = user.creditsInCents! - lockedContent.amountInCents!;
520
+ await user.save();
521
+
522
+ let creditPayment = await CreditPayments.create({
523
+ userId: user.id,
524
+ ownerId: owner.id,
525
+ creditAmountInCents: lockedContent.amountInCents!,
526
+ earningAmountInCents: earningsAmount(
527
+ lockedContent.amountInCents!,
528
+ owner.serviceFeePercentage
529
+ ),
530
+ interactionType: INTERACTION_TYPES.UNLOCK,
531
+ });
532
+
533
+ if (owner.referringOwnerId) {
534
+ await createReferralPayment(
535
+ owner,
536
+ creditPayment,
537
+ lockedContent.amountInCents!
538
+ );
539
+ }
540
+
541
+ if (user.referringOwnerId) {
542
+ await createUserReferralPayment(
543
+ user,
544
+ creditPayment,
545
+ lockedContent.amountInCents!
546
+ );
547
+ }
548
+
549
+ return creditPayment;
550
+ };
551
+
552
+ CreditPayments.logSubscriptionPayment = async (
553
+ userId: string,
554
+ owner: PhoneOwner,
555
+ subscriptionAmountInCents: number,
556
+ subscription: Subscription,
557
+ transaction: Transaction | undefined,
558
+ transId: number
559
+ ) => {
560
+ let creditPayment = await CreditPayments.create(
561
+ {
562
+ userId: userId,
563
+ ownerId: owner.id,
564
+ creditAmountInCents: subscriptionAmountInCents,
565
+ earningAmountInCents: earningsAmount(
566
+ subscriptionAmountInCents,
567
+ owner.serviceFeePercentage
568
+ ),
569
+ interactionType: INTERACTION_TYPES.SUBSCRIPTION,
570
+ metadata: JSON.stringify({ subscription_id: subscription.id }),
571
+ transId,
572
+ },
573
+ { transaction }
574
+ );
575
+
576
+ try {
577
+ if (owner.referringOwnerId) {
578
+ await createReferralPayment(
579
+ owner,
580
+ creditPayment,
581
+ subscriptionAmountInCents,
582
+ transaction
583
+ );
584
+ }
585
+ const user = await PhoneUser.getById(userId);
586
+ if (user && user.referringOwnerId) {
587
+ await createUserReferralPayment(
588
+ user,
589
+ creditPayment,
590
+ subscriptionAmountInCents,
591
+ transaction
592
+ );
593
+ }
594
+ } catch (err) {
595
+ console.log(err);
596
+ console.log("Issue creating referral payment");
597
+ }
598
+
599
+ return creditPayment;
600
+ };
601
+
602
+ const earningsAmount = (amount: number, serviceFeePercentage?: number) => {
603
+ return Math.floor(amount * (1 - (serviceFeePercentage || 0.2)));
604
+ };
605
+
606
+ const createReferralPayment = async (
607
+ owner: PhoneOwner,
608
+ creditPayment: CreditPayments,
609
+ creditAmount: number,
610
+ transaction?: Transaction
611
+ ) => {
612
+ return await CreditPayments.create(
613
+ {
614
+ ownerId: owner.referringOwnerId!,
615
+ creditAmountInCents: creditAmount,
616
+ earningAmountInCents: Math.floor(
617
+ creditAmount * (owner.referralPercentage || REFERRAL_PERCENTAGE)
618
+ ),
619
+ interactionType: INTERACTION_TYPES.REFERRAL,
620
+ referredCreditPaymentId: creditPayment.id,
621
+ },
622
+ { transaction }
623
+ );
624
+ };
625
+
626
+ const createUserReferralPayment = async (
627
+ user: PhoneUser,
628
+ creditPayment: CreditPayments,
629
+ creditAmount: number,
630
+ transaction?: Transaction
631
+ ) => {
632
+ return await CreditPayments.create(
633
+ {
634
+ ownerId: user.referringOwnerId!,
635
+ creditAmountInCents: creditAmount,
636
+ earningAmountInCents: Math.floor(creditAmount * 0.04),
637
+ interactionType: INTERACTION_TYPES.REFERRAL,
638
+ referredCreditPaymentId: creditPayment.id!,
639
+ },
640
+ { transaction }
641
+ );
642
+ };
643
+
644
+ const getPaymentUrl = async (user: PhoneUser, owner: PhoneOwner) => {
645
+ let name = owner.name && owner.name.toLowerCase().replace(/\s+/g, "-");
646
+ return `https://${process.env.SITE_DOMAIN}/${name}`;
647
+ };
648
+
649
+ PhoneOwner.hasMany(CreditPayments, {
650
+ foreignKey: "owner_id",
651
+ onDelete: "NO ACTION",
652
+ constraints: false,
653
+ });
654
+ PhoneUser.hasMany(CreditPayments, {
655
+ foreignKey: "user_id",
656
+ onDelete: "NO ACTION",
657
+ constraints: false,
658
+ });
659
+ CreditPayments.hasOne(PhoneOwner, {
660
+ foreignKey: "id",
661
+ sourceKey: "owner_id",
662
+ onDelete: "NO ACTION",
663
+ constraints: false,
664
+ });
665
+ CreditPayments.hasOne(PhoneUser, {
666
+ foreignKey: "id",
667
+ sourceKey: "user_id",
668
+ onDelete: "NO ACTION",
669
+ constraints: false,
670
+ });
671
+ Notification.hasOne(CreditPayments, {
672
+ foreignKey: "id",
673
+ sourceKey: "creditPaymentId",
674
+ constraints: false,
675
+ onDelete: "NO ACTION",
676
+ });
677
+
678
+ export default CreditPayments;