Как отправить почтовый запрос в функцию Firebase? - PullRequest
0 голосов
/ 17 декабря 2018

Я создал функцию Firebase для выплаты драйвера через PayPal.

index.js из firebase-function

'use strict';
const functions = require('firebase-functions');
const paypal = require('paypal-rest-sdk');
const admin = require('firebase-admin');
admin.initializeApp(functions.config().firebase);

paypal.configure({
    mode: 'sandbox',
    client_id: functions.config().paypal.client_id,
    client_secret: functions.config().paypal.client_secret
})

exports.newRequest = functions.database.ref('/history/{pushId}').onCreate((snapshot, context) => {
    var requestSnapshot = snapshot.val();
    var price  = snapshot.child('price').val();
    var pushId = context.params.pushId;

    return snapshot.ref.parent.child(pushId).child('price').set(price);
 });


function getPayoutsPending(uid) {
    return admin.database().ref('Users/Drivers/' + uid + '/history').once('value').then((snap) => {
        if(snap === null){
            throw new Error("profile doesn't exist");
        }
        var array = [];
        if(snap.hasChildren()){
            snap.forEach(element => {
                if (element.val() === true) {
                    array.push(element.key);
                }
            });
        }
        return array;
    }).catch((error) => {
        return console.error(error);
    });
}

function getPayoutsAmount(array) {
    return admin.database().ref('history').once('value').then((snap) => {
        var value = 0.0;
        if(snap.hasChildren()){
            snap.forEach(element => {
                if(array.indexOf(element.key) > -1) {
                        if(element.child('price').val() !== null){
                            value += element.child('price').val();
                        }
                }
            });
            return value;
        }
        return value;
    }).catch((error) => {
        return console.error(error);
    });
}

function updatePaymentsPending(uid, paymentId) {
    return admin.database().ref('Users/Drivers/' + uid + '/history').once('value').then((snap) => {
        if(snap === null){
            throw new Error("profile doesn't exist");
        }

        if(snap.hasChildren()){
            snap.forEach(element => {
                if(element.val() === true) {
                    admin.database().ref('Users/Drivers/' + uid + '/history/' + element.key).set( {
                        timestamp: admin.database.ServerValue.TIMESTAMP,
                        paymentId: paymentId
                    });
                    admin.database().ref('history/' + element.key + '/driverPaidOut').set(true);
                }
            });
        }
        return null;
    }).catch((error) => {
        return console.error(error);
    });
}

exports.payout = functions.https.onRequest((request, response) => {
    return getPayoutsPending(request.body.uid)
        .then(array => getPayoutsAmount(array))
        .then(value => {
            var valueTrunc = parseFloat(Math.round((value * 0.75) * 100) / 100).toFixed(2);
            const sender_batch_id = Math.random().toString(36).substring(9);
            const sync_mode = 'false';
            const payReq = JSON.stringify({
                sender_batch_header: {
                    sender_batch_id: sender_batch_id,
                    email_subject: "You have a payment"
                },
                items: [
                    {
                        recipient_type: "EMAIL",
                        amount: {
                            value: valueTrunc,
                            currency: "CAD"
                        },
                        receiver: request.body.email,
                        note: "Thank you.",
                        sender_item_id: "Payment"
                    }
                ]
            });

            return paypal.payout.create(payReq, sync_mode, (error, payout) => {
                if (error) {
                    console.warn(error.response);
                    response.status('500').end();
                    throw error;
                }
                console.info("payout created");
                console.info(payout);
                return updatePaymentsPending(request.body.uid, sender_batch_id)
            });
        }).then(() => {
            response.status('200').end();
            return null;
        }).catch(error => {
            console.error(error);
        });
});

Код, который я использовал в Androidработает нормально, но с кодом, который у меня есть в iOS, он не работает правильно.

Код в IOS, согласно файлу index.js, после помещения электронного письма водителя в текстовое поле и при нажатии кнопки PAYOUT, онвыполняет следующие действия:

  • добавляет идентификатор платежа и метку времени для пользователей / водителей и пользователей / райдеров
  • добавляет 'driverPaidOut = true' в историю db
  • он создает, в функциях Firebase регистрирует «созданную выплату»

Но что он не делает, так это делает это в PayPal и создает уведомление на электронную почту водителя.

Как видите, есть две переменные, которые требуются файлу index.js: «uid» и «email» драйвера

Android-код, который работает:

final OkHttpClient client = new OkHttpClient();

    // in json - we need variables for the hardcoded uid and Email
    JSONObject postData = new JSONObject();

    try {
        postData.put("uid", FirebaseAuth.getInstance().getCurrentUser().getUid());
        postData.put("email", mPayoutEmail.getText().toString());

    } catch (JSONException e) {
        e.printStackTrace();
    }

    // Request body ...
    RequestBody body = RequestBody.create(MEDIA_TYPE, postData.toString());

    // Build Request ...
    final Request request = new Request.Builder()
            .url("https://us-central1-ryyde-sj.cloudfunctions.net/payout")
            .post(body)
            .addHeader("Content-Type", "application/json")
            .addHeader("cache-control", "no-cache")
            .addHeader("Authorization", "Your Token")
            .build();

    client.newCall(request).enqueue(new Callback() {
        @Override
        public void onFailure(Call call, IOException e) {
            // something went wrong right off the bat
            progress.dismiss();
        }

        @Override
        public void onResponse(Call call, Response response) throws IOException {
            // response successful ....
            // refers to response.status('200') or ('500')
            int responseCode = response.code();
            if (response.isSuccessful()) {
                switch(responseCode) {
                    case 200:
                        Snackbar.make(findViewById(R.id.layout),
                                "Payout Successful!", Snackbar.LENGTH_LONG)
                                .show();
                        break;

                    case 500:
                        Snackbar.make(findViewById(R.id.layout),
                                "Error: no payout available", Snackbar
                                        .LENGTH_LONG).show();
                        break;

                    default:
                        Snackbar.make(findViewById(R.id.layout),
                                "Error: couldn't complete the transaction",
                                Snackbar.LENGTH_LONG).show();
                        break;
                }

            } else {
                Snackbar.make(findViewById(R.id.layout),
                        "Error: couldn't complete the transaction",
                        Snackbar.LENGTH_LONG).show();
            }

            progress.dismiss();
        }
    });

Код iOS, не работает:

let email = txtPayoutEmail.text!
    let userId = self.uid!

    let parameters = "uid=\(userId)&email=\(email)"
    let url = "https://us-central1-ryyde-sj.cloudfunctions.net/payout"
    var request = URLRequest(url: URL(string: url)!)

    request.setValue("application/json", forHTTPHeaderField: "Content-Type")
    request.setValue("Your Token", forHTTPHeaderField: "Authorization")
    request.setValue("no-cache", forHTTPHeaderField: "cache-control")

    request.httpMethod = "POST"
    print("URL : \(request)")

    request.httpBody = parameters.data(using: .utf8)

    let task = URLSession.shared.dataTask(with: request) { data, response, error in
        guard let data = data, error == nil else { return }

        if let httpStatus = response as? HTTPURLResponse, httpStatus.statusCode != 200 { // check for http errors
            print("statusCode should be 200, but is \(httpStatus.statusCode)")
        }

        do {
            let response = try JSONSerialization.jsonObject(with: data, options: []) as? [String:AnyObject]
            print(response!)

        } catch let error as NSError {
            print(error)
        }
    }

    task.resume()

Я пробовал different (практически каждый в сети) приводит примеры из Интернета, будь то Alamofire или нет, и, кажется, ничего не работает.

Редактировать - ответ от Sahil Manchanda

Получение httpResponse:

Optional(<NSHTTPURLResponse: 0x600000132620> { URL: https://us-central1-ryyde-sj.cloudfunctions.net/payout } { Status Code: 200, Headers {
"Content-Length" =     (
    0
);
"Content-Type" =     (
    "text/html"
);
Date =     (
    "Mon, 17 Dec 2018 07:44:57 GMT"
);
Server =     (
    "Google Frontend"
);
"alt-svc" =     (
    "quic=\":443\"; ma=2592000; v=\"44,43,39,35\""
);
"function-execution-id" =     (
    wspeunpt1umy
);
"x-cloud-trace-context" =     (
    "a2444e17fb874853489b56684de9fe10;o=1"
);
"x-powered-by" =     (
    Express
);
} })

Редактировать # 2 - все еще не работает

Sahil Manchanda был очень полезным, но не экспертом по бэкэнду Firebase.

После внесения нескольких исправлений в код, отладка индекса.JS, по какой-то причине он не работает на стороне сервера.

Мой новый код:

let email = txtPayoutEmail.text!

    let headers = [
        "Content-Type": "application/json",
        "cache-control": "no-cache",
        "Authorization" : "Bearer \(token)"
    ]

    let body = ["uid": uid, "email": email]

    let postData = try! JSONSerialization.data(withJSONObject: body, options: [])


    let request = NSMutableURLRequest(url: NSURL(string: "https://us-central1-ryyde-sj.cloudfunctions.net/payout")! as URL,  cachePolicy: .useProtocolCachePolicy, timeoutInterval: 10.0)

    request.httpMethod = "POST"
    request.allHTTPHeaderFields = headers
    request.httpBody = postData as Data

    let session = URLSession.shared
    let dataTask = session.dataTask(with: request as URLRequest, completionHandler: { (data, response, error) -> Void in
        if (error != nil) {
            print(error!)
        } else {
            let httpResponse = response as? HTTPURLResponse
            print(httpResponse!)
        }
    })

    dataTask.resume()

При запуске приложения это то, что видно в функциях Firebase, кажется, хорошо,но не попадает в PayPal, как в приложении для Android?

result

1 Ответ

0 голосов
/ 17 декабря 2018

Главное, что вам не хватает - это строка JSON в вашем коде iOS.в Android вы используете JSONObject, а затем конвертируете его в строку.тогда как в вашей iOS это преобразование отсутствует.Попробуйте код ниже.посмотрим, работает ли он или нет.Я внес некоторые коррективы, которые должны удовлетворить ваши потребности.

import Foundation

let headers = [
  "Content-Type": "application/json",
  "Cache-Control": "no-cache",
  "Authorization" : "your token"
]
let parameters = [
  "email": "abc@abc.com",
  "uid": "12"
] as [String : Any]

let postData = JSONSerialization.data(withJSONObject: parameters, options: [])

let request = NSMutableURLRequest(url: NSURL(string: "https://us-central1-ryyde-sj.cloudfunctions.net/payout")! as URL,
                                        cachePolicy: .useProtocolCachePolicy,
                                    timeoutInterval: 10.0)
request.httpMethod = "POST"
request.allHTTPHeaderFields = headers
request.httpBody = postData as Data

let session = URLSession.shared
let dataTask = session.dataTask(with: request as URLRequest, completionHandler: { (data, response, error) -> Void in
  if (error != nil) {
    print(error)
  } else {
    let httpResponse = response as? HTTPURLResponse
    print(httpResponse)
  }
})

dataTask.resume()
...