@@ -12,6 +12,16 @@ import {
1212 UserTransactionStatus ,
1313} from '../../entity/user/UserTransaction' ;
1414import createOrGetConnection from '../../db' ;
15+ import { purchaseCores , UserTransactionError } from '../njord' ;
16+ import { TransferError } from '../../errors' ;
17+ import {
18+ concatTextToNewline ,
19+ isProd ,
20+ isTest ,
21+ updateFlagsStatement ,
22+ } from '../utils' ;
23+ import type { Block , KnownBlock } from '@slack/web-api' ;
24+ import { webhooks } from '../slack' ;
1525
1626export const isCorePurchaseApple = ( {
1727 transactionInfo,
@@ -25,6 +35,109 @@ export const isCorePurchaseApple = ({
2535 ) ;
2636} ;
2737
38+ export const notifyNewStoreKitPurchase = async ( {
39+ data,
40+ transaction,
41+ user,
42+ currencyInUSD,
43+ } : {
44+ data : JWSTransactionDecodedPayload ;
45+ transaction : UserTransaction ;
46+ user : User ;
47+ currencyInUSD : number ;
48+ } ) => {
49+ if ( isTest ) {
50+ return ;
51+ }
52+
53+ const blocks : ( KnownBlock | Block ) [ ] = [
54+ {
55+ type : 'header' ,
56+ text : {
57+ type : 'plain_text' ,
58+ text : 'Cores purchased :cores: :apple-ico:' ,
59+ emoji : true ,
60+ } ,
61+ } ,
62+ {
63+ type : 'section' ,
64+ fields : [
65+ {
66+ type : 'mrkdwn' ,
67+ text : concatTextToNewline ( '*Transaction ID:*' , data . appTransactionId ) ,
68+ } ,
69+ {
70+ type : 'mrkdwn' ,
71+ text : concatTextToNewline (
72+ '*App Account Token:*' ,
73+ data . appAccountToken ,
74+ ) ,
75+ } ,
76+ ] ,
77+ } ,
78+ {
79+ type : 'section' ,
80+ fields : [
81+ {
82+ type : 'mrkdwn' ,
83+ text : concatTextToNewline ( '*Product:*' , data . productId ) ,
84+ } ,
85+ {
86+ type : 'mrkdwn' ,
87+ text : concatTextToNewline ( '*Cores:*' , transaction . value . toString ( ) ) ,
88+ } ,
89+ {
90+ type : 'mrkdwn' ,
91+ text : concatTextToNewline (
92+ '*Purchased by:*' ,
93+ `<https://app.daily.dev/${ user . id } |${ user . id } >` ,
94+ ) ,
95+ } ,
96+ ] ,
97+ } ,
98+ {
99+ type : 'section' ,
100+ fields : [
101+ {
102+ type : 'mrkdwn' ,
103+ text : concatTextToNewline (
104+ '*Cost:*' ,
105+ new Intl . NumberFormat ( 'en-US' , {
106+ style : 'currency' ,
107+ currency : 'USD' ,
108+ } ) . format ( currencyInUSD || 0 ) ,
109+ ) ,
110+ } ,
111+ {
112+ type : 'mrkdwn' ,
113+ text : concatTextToNewline ( '*Currency:*' , 'USD' ) ,
114+ } ,
115+ ] ,
116+ } ,
117+ {
118+ type : 'section' ,
119+ fields : [
120+ {
121+ type : 'mrkdwn' ,
122+ text : concatTextToNewline (
123+ '*Cost (local):*' ,
124+ new Intl . NumberFormat ( 'en-US' , {
125+ style : 'currency' ,
126+ currency : data . currency ,
127+ } ) . format ( ( data . price || 0 ) / 1000 ) ,
128+ ) ,
129+ } ,
130+ {
131+ type : 'mrkdwn' ,
132+ text : concatTextToNewline ( '*Currency (local):*' , data . currency ) ,
133+ } ,
134+ ] ,
135+ } ,
136+ ] ;
137+
138+ await webhooks . transactions . send ( { blocks } ) ;
139+ } ;
140+
28141export const handleCoresPurchase = async ( {
29142 transactionInfo,
30143 user,
@@ -62,9 +175,62 @@ export const handleCoresPurchase = async ({
62175 } ,
63176 } ) ;
64177
65- const userTransaction = await con
66- . getRepository ( UserTransaction )
67- . save ( payload ) ;
178+ const transaction = await con . transaction ( async ( entityManager ) => {
179+ const userTransaction = await entityManager
180+ . getRepository ( UserTransaction )
181+ . save ( payload ) ;
182+
183+ // TODO feat/cores-iap enable for production https://dailydotdev.slack.com/archives/C07VA1FJTDK/p1745580651217029
184+ if ( ! isProd ) {
185+ try {
186+ await purchaseCores ( {
187+ transaction : userTransaction ,
188+ } ) ;
189+ } catch ( error ) {
190+ if ( error instanceof TransferError ) {
191+ const userTransactionError = new UserTransactionError ( {
192+ status : error . transfer . status ,
193+ transaction : userTransaction ,
194+ } ) ;
195+
196+ // update transaction status to error
197+ await entityManager . getRepository ( UserTransaction ) . update (
198+ {
199+ id : userTransaction . id ,
200+ } ,
201+ {
202+ status : error . transfer . status as number ,
203+ flags : updateFlagsStatement < UserTransaction > ( {
204+ error : userTransactionError . message ,
205+ } ) ,
206+ } ,
207+ ) ;
208+
209+ return entityManager . getRepository ( UserTransaction ) . create ( {
210+ ...userTransaction ,
211+ status : error . transfer . status as number ,
212+ flags : {
213+ ...userTransaction . flags ,
214+ error : userTransactionError . message ,
215+ } ,
216+ } ) ;
217+ }
218+
219+ throw error ;
220+ }
221+ }
222+
223+ return userTransaction ;
224+ } ) ;
225+
226+ if ( transaction . status === UserTransactionStatus . Success ) {
227+ await notifyNewStoreKitPurchase ( {
228+ data : transactionInfo ,
229+ transaction,
230+ user,
231+ currencyInUSD : transaction . valueIncFees ,
232+ } ) ;
233+ }
68234
69- return userTransaction ;
235+ return transaction ;
70236} ;
0 commit comments