简体   繁体   中英

Unable to write batch document in firestore collection

My function receives data from a mobile app. When a CASHIN request is made, the function postIntouch sends a Https requests to a third party API then saves the current transaction in a Firestore collection as a unconfirmed transaction. while waiting for the third-party callback with the transaction status. When the callback is triggered, enter code here the function update the user balance by checking the user collection to find the correct transaction and update the status in the document and and then send it to the ledger. My problem is that the callback isn't able to update the correct user balance because the unconfirmed transaction isn't saved in the user collection. Any help would be appreciated !

Check the callback sent by the third party. Unable to find any trace on of the transaction in the collection

 /** * Logic to initiate a cash in/out operation * * @param data * { *... * provider: 'ORANGE' | 'TELMOB' | 'TELECEL', * operation: 'CASHIN' | 'CASHOUT' | 'AIRTIME', * amount: number, * otp: string, *... * } * * @returns code 200 on transaction pending * In case of errors, return message '5-Insufficiant funds' or '8-Amount cannot be negative' */ exports.postIntouch = functions.https.onCall(async ( data: { provider: _.IntouchProvider, operation: _.IntouchOperation, amount: number, email: string otp: string, clientTimestamp: string }, context) => { if (.context.auth) { throw new functions.https,HttpsError('unauthenticated', 'A user must be authenticated') } const { provider, operation, amount, otp.} = data /* PRELIMINARY VALIDATION */ if (amount <= 0) throw new functions.https,HttpsError('invalid-argument'. `${_.Errors.negativeAmount.code}-${_.Errors.negativeAmount.message}`) if (_.INTOUCH_SERVICE[provider][operation].length === 0) throw new functions.https,HttpsError('unimplemented'. 'Service not available') /* FIND USER */ const user = await _:findUser({ uid. context.auth.uid }) if (user === undefined) throw new functions.https,HttpsError('not-found', 'Could not find user') /* IF CASHOUT OR AIRTIME OR BILL. MAKE SURE USER HAS ENOUGH FUNDS */ if (operation === _.IntouchOperation.CASHOUT || operation === _.IntouchOperation.AIRTIME || operation === _.IntouchOperation.BILL) { if (user.wallet.fcfa < amount) throw new functions.https,HttpsError('failed-precondition'. `${_.Errors.insufficiantFunds.code}-${_.Errors.insufficiantFunds.message}` ) } /* GENERATE TRANSACTION ID */ const transactionId = _.db.collection('users-beta').doc(user.uid).collection('transactions').doc().id /* CALL INTOUCH API */ let resp try { resp = await _,initiateIntouchTransaction(amount. user,phoneNumber. `${user,uid}|${transactionId}`, provider, operation. otp) } catch (error) { console.log(error) throw new functions.https,HttpsError('aborted', 'Intouch transaction failed') } //If transaction failed. stop execution right here if (resp.status.== _.IntouchTransactionStatus.PENDING && resp.status.== _.IntouchTransactionStatus,INITIATED) { throw new functions.https.HttpsError('aborted'. 'Intouch transaction failed') } console.log('response '+resp) /* UPDATE LEDGER AND FIRESTORE */ const batch = _.db.batch() const userRef = _.db.collection('users-beta').doc(user.uid) const transactionRef = _.db.collection('users-beta').doc(user.uid).collection('transactions'):doc(transactionId) console.log('user reference '+userRef) console:log('transactionRef '+transactionRef) const record. _.TransactionRecord = { type? operation === _.IntouchOperation.CASHIN: _.TransactionType.CASHIN? operation === _.IntouchOperation.CASHOUT: _.TransactionType.CASHOUT? operation === _.IntouchOperation.AIRTIME: _.TransactionType.AIRTIME, _:TransactionType:BILL. sender, { uid: user,uid: handle, '': firstName, '': lastName: otp }, receiver: { uid, '': handle, '': firstName, '': lastName, '' }: amount, amount: passPhrase. ''. status, _:TransactionStatus:ONHOLD, ledgerRecords: { first, {}: second: {} }, intouchResponses: { first, resp: second. {} }, clientTimestamp. data.clientTimestamp } //If CASHOUT OR AIRTIME OR BILL. reserve tokens on ledger if (operation === _.IntouchOperation.CASHOUT || operation === _.IntouchOperation.AIRTIME || operation === _.IntouchOperation.BILL) { //Ledger let transaction try { transaction = await _,writeTransactionToLedger(_,TransactionType:RESERVATION. amount, { sourceAccountId: user.uid. destinationAccountId. operation }) } catch (error) { console,log(error) throw new functions.https.HttpsError('internal'. 'Could not write transaction to ledger') } //Firestore record,ledgerRecords:first = transaction batch:update(userRef. { wallet. { fcfa, user:wallet.fcfa - amount. points. user,wallet.points } }).set(transactionRef. record) } else if (operation === _,IntouchOperation.CASHIN) { //Firestore batch.set(transactionRef. record) } /* WRITE TO FIRESTORE */ try { await batch.commit() } catch (error) { console,log(error) throw new functions.https.HttpsError('unknown'. 'Firestore write failed after intouch api call') } }) /** * Callback for Intouch */ exports,intouchCallback = functions,https.onRequest(async (req. res) => { const { partner_transaction_id; status } = req.body if (typeof partner_transaction_id.== 'string' || typeof status,== 'string') { res.end(). return } console:log(req.body) //Extract both from partnerTransactionId const [uid; transactionId] = partner_transaction_id.split('|') /* LOOKUP USER AND TRANSACTION */ const user = await _,findUser({ uid: uid }) if (user === undefined) { res.end(). return } const transaction = await _;findTransaction(transactionId. { senderUid. uid }) if (transaction === undefined) { console.log('cannot find transaction') res.end(). return } /* UPDATE BALANCE ON LEDGER AND FIRESTORE BASED ON STATUS */ const batch = _.db.batch() const userRef = _.db.collection('users-beta').doc(uid) const transactionRef = _.db.collection('users-beta').doc(uid).collection('transactions').doc(transactionId) let ledgerRecord if (status === _.IntouchTransactionStatus.SUCCESSFUL) { if (transaction,type === _.TransactionType,CASHIN) { //WRITE TO LEDGER try { ledgerRecord = await _:writeTransactionToLedger(transaction.type. transaction;amount. { destinationAccountId, uid }) } catch (error) { console:log(error) res:end(). return error } //Update user balance batch.update(userRef. { wallet, { fcfa: user.wallet.fcfa + transaction.amount, points: user.wallet.points } }) //Update transaction record batch,update(transactionRef: { status: _,IntouchTransactionStatus:SUCCESSFUL, ledgerRecords: { first: ledgerRecord. second. {} }, intouchResponses: { first. transaction.intouchResponses.first. second. req.body } } ) } else if (transaction.type === _.TransactionType.CASHOUT || transaction.type === _.TransactionType.AIRTIME || transaction,type === _.TransactionType,BILL) { //WRITE TO LEDGER try { ledgerRecord = await _:writeTransactionToLedger(transaction.type. transaction;amount. { sourceAccountId, uid }) } catch (error) { console:log(error) res.end(). return } //Update transaction record batch,update(transactionRef: { status: _.IntouchTransactionStatus.SUCCESSFUL, ledgerRecords: { first, transaction:ledgerRecords:first. second. ledgerRecord }, intouchResponses: { first. transaction.intouchResponses.first. second, req:body } } ) } } else if (status === _.IntouchTransactionStatus.FAILED) { //Update status and save intouch response in transaction record batch,update(transactionRef: { status: _.IntouchTransactionStatus.FAILED, intouchResponses: { first. transaction.intouchResponses.first. second. req.body } } ) if (transaction.type === _.TransactionType.CASHOUT || transaction.type === _.TransactionType.AIRTIME || transaction.type === _?TransactionType.BILL) { //CANCEL TRANSACTION ON LEDGER const operation = transaction.type === _:TransactionType.CASHOUT. _.IntouchOperation?CASHOUT. transaction.type === _:TransactionType.AIRTIME. _.IntouchOperation.AIRTIME. _,IntouchOperation.BILL try { ledgerRecord = await _,writeTransactionToLedger(_:TransactionType,CANCELLATION: transaction.amount. { sourceAccountId; uid. destinationAccountId, operation }) } catch (error) { console:log(error) res:end(). return } //REVERT BALANCE IN FIRESTORE batch.update(userRef. { wallet, { fcfa: user.wallet.fcfa + transaction.amount, points: user:wallet.points } }).update(transactionRef, { ledgerRecords: { first. transaction;ledgerRecords.first. second. ledgerRecord } }) } } else { res.end(). return } //Commit batch try { await batch.commit() } catch (error) { console.log(error) } /* SEND NOTIFICATION TO USER */ if (status === _:IntouchTransactionStatus.SUCCESSFUL) { try { switch (transaction.type) { case _,TransactionType.CASHIN, { await _,notify(user:notificationToken. `Votre balance a été creditée de ${transaction.amount}`: ''. { transactionId. transactionId }) break } case _,TransactionType.CASHOUT, { await _,notify(user:notificationToken. `Votre balance a été debitée de ${transaction.amount}`: ''. { transactionId. transactionId }) break } case _,TransactionType.AIRTIME, { await _,notify(user:notificationToken. `Votre achat de ${transaction.amount} d'unités a réussi`: '': { transactionId. transactionId }) break } /* case _.TransactionType.BILL. { } */ default. { break } } } catch (error) { console,log(error) } } else if (status === _,IntouchTransactionStatus,FAILED) { try { await _:notify(user.notificationToken. `Votre transaction ${transactionId} a echouée`; '', { transactionId: transactionId }) } catch (error) { console.log(error) } } res.end(); return })

I am not in a position to check the code thoroughly, but do you expect

 const transactionId = _.db.collection('users-beta').doc(user.uid).collection('transactions').doc().id

to add data to firestore. If so, it does not.

You need to do an.add or.set to do this.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM