如何使用Firebase Cloud Firestore创建M-Pesa回调URL?

如何使用Firebase Cloud Firestore创建M-Pesa回调URL?,firebase,google-cloud-firestore,callbackurl,mpesa,Firebase,Google Cloud Firestore,Callbackurl,Mpesa,我正在尝试用Safaricom的“Lipa Na m-Pesa”(一个肯尼亚的东西)制作一个应用程序,可以将付款发送到账单号码。该调用是对URL的POST请求: https://sandbox.safaricom.co.ke/mpesa/stkpush/v1/processrequest 带标题: { 'Host': 'sandbox.safaricom.co.ke', 'Authorization': 'Bearer ${await mpesaAccessTo

我正在尝试用Safaricom的“Lipa Na m-Pesa”(一个肯尼亚的东西)制作一个应用程序,可以将付款发送到账单号码。该调用是对URL的
POST
请求:

https://sandbox.safaricom.co.ke/mpesa/stkpush/v1/processrequest
带标题:

{
        'Host': 'sandbox.safaricom.co.ke',
        'Authorization': 'Bearer ${await mpesaAccessToken}',
        'Content-Type': 'application/json',
      }
和机构:

{
        "BusinessShortCode": "$businessShortCode",
        "Password": "${generateLnmPassword(timeStamp)}",
        "Timestamp": "$timeStamp",
        "TransactionType": "CustomerPayBillOnline",
        "Amount": "10",
        "PartyA": "$userPhoneNumber",
        "PartyB": "$businessShortCode",
        "PhoneNumber": "$userPhoneNumber",
        "CallBackURL": "?????????????????????????????",
        "AccountReference": "account",
        "TransactionDesc": "test",
      }
我收到了一个访问令牌,生成了一个密码并成功地拨打了电话,除了CallBackURL的事情。。。M-Pesa文档对其回调的描述如下:

回调URL 这是您希望传递事务结果的端点。注册URL API回调也适用相同的规则

来自事务性请求的所有API回调都是POST请求,不要期望回调的GET请求。此外,数据未格式化为application/x-www-form-urlencoded格式,它是application/json,因此不要期望数据出现在您语言的常用POST字段/变量中,直接从传入的输入流读取结果

(此处有更多信息,但您可能需要登录:请参阅“Lipa na M-Pesa”)

我的应用程序托管在Firebase Cloud Firestore上。我有没有办法与他们一起创建一个回调URL,将他们的回调作为Firestore集合中的文档接收

或者这是不可能的,因为他们需要授权令牌和其他东西来完成这项工作。。。我不能影响M-Pesa将发送的标题和正文

(顺便说一句,我用flatter/Dart编码,所以请不要用Javascript或任何东西回答!我会不知所措的…:p flatter/Dart或纯文本就可以了。谢谢!)

我有没有办法用它们创建一个回调URL 将其回调作为Firestore集合中的文档接收

在Firebase生态系统中,最常见的方法是编写一个将由Safaricom服务调用的

在云功能中,您将能够根据POST请求的内容更新Firestore文档

比如:

exports.safaricom = functions.https.onRequest((req, res) => {
    // Get the header and body through the req variable
    // See https://firebase.google.com/docs/functions/http-events#read_values_from_the_request

    return admin.firestore().collection('...').doc('...').update({ foo: bar })
        .then(() => {
            res.status(200).send("OK");
        })
        .catch(error => {
            // ...
            // See https://www.youtube.com/watch?v=7IkUgCLr5oA&t=1s&list=PLl-K7zZEsYLkPZHe41m4jfAxUi0JjLgSM&index=3
        })

});

我确实注意到,您要求我们不要“用Javascript或任何东西回答”,而是使用Flutter/Dart,但我认为您无法在Flutter中实现这一点:您需要在您完全控制并公开API端点的环境中实现此webhook,如您自己的服务器或云函数


云函数乍一看可能很复杂,但实现HTTPS云函数并没有那么复杂。我建议您阅读并观看Firebase中关于“JavaScript承诺”的三个视频,如果您遇到任何问题,请就此提出新问题。

云函数不是基于Dart的

见下面的解决方案

const functions = require("firebase-functions");
const admin = require("firebase-admin");
const parse = require("./parse");

admin.initializeApp();

exports.lmno_callback_url = functions.https.onRequest(async (req, res) => {
    const callbackData = req.body.Body.stkCallback;
    const parsedData = parse(callbackData);

    let lmnoResponse = admin.firestore().collection('lmno_responses').doc('/' + parsedData.checkoutRequestID + '/');
    let transaction = admin.firestore().collection('transactions').doc('/' + parsedData.checkoutRequestID + '/');
    let wallets = admin.firestore().collection('wallets');

    if ((await lmnoResponse.get()).exists) {
        await lmnoResponse.update(parsedData);
    } else {
        await lmnoResponse.set(parsedData);
    }
    if ((await transaction.get()).exists) {
        await transaction.update({
            'amount': parsedData.amount,
            'confirmed': true
        });
    } else {
        await transaction.set({
            'moneyType': 'money',
            'type': 'deposit',
            'amount': parsedData.amount,
            'confirmed': true
        });
    }
    let walletId = await transaction.get().then(value => value.data().toUserId);

    let wallet = wallets.doc('/' + walletId + '/');

    if ((await wallet.get()).exists) {
        let balance = await wallet.get().then(value => value.data().moneyBalance);
        await wallet.update({
            'moneyBalance': parsedData.amount + balance
        })
    } else {
        await wallet.set({
            'moneyBalance': parsedData.amount
        })
    }

    res.send("Completed");
});
解析函数

const moment = require("moment");

function parse(responseData) {
    const parsedData = {};
    parsedData.merchantRequestID = responseData.MerchantRequestID;
    parsedData.checkoutRequestID = responseData.CheckoutRequestID;
    parsedData.resultDesc = responseData.ResultDesc;
    parsedData.resultCode = responseData.ResultCode;

    if (parsedData.resultCode === 0) {
        responseData.CallbackMetadata.Item.forEach(element => {
            switch (element.Name) {
                case "Amount":
                    parsedData.amount = element.Value;
                    break;
                case "MpesaReceiptNumber":
                    parsedData.mpesaReceiptNumber = element.Value;
                    break;
                case "TransactionDate":
                    parsedData.transactionDate = moment(
                        element.Value,
                        "YYYYMMDDhhmmss"
                    ).unix();
                    break;
                case "PhoneNumber":
                    parsedData.phoneNumber = element.Value;
                    break;
            }
        });
    }

    return parsedData;
}

module.exports = parse;

哇!你让它听起来完全可行!:)是的,我确实在某个地方读到云函数只接受JavaScript。。。这就是为什么我当时没有进一步调查的原因。好吧,如果需要的话,现在可能是时候了(我想投票支持你的答案,但我没有足够的声誉。无论如何,非常感谢!)@KarolinaHagegård很高兴我能帮助你!你可以接受答案。啊!现在发现了那个小记号。。。小东西!哇,我们为你感到高兴你在用颤振吗?