Невозможно перевести сумму на счет Connect Stripe - PullRequest
4 голосов
/ 30 мая 2020

BackGround:

Я пытаюсь создать торговую площадку, где клиент может приобретать услуги продавца. Проект представляет собой приложение для путешествий MERN Stack. точно. Я бы хотел, чтобы клиент платил Платформе ( Мой веб-сайт, связанный с Stripe ), когда он желает приобрести услугу, например, номер в отеле. Клиент остается в отеле в течение отведенного времени, и когда он оформляет заказ, платформа сохраняет часть суммы клиента в качестве сбора за подачу заявления, а остальную часть передает поставщику услуг, в данном случае отелю.

Текущий Усилия:

Я использовал STRIPE CONNECT для достижения необходимой функциональности.

(Note: вам, ребята, не нужно видеть весь код ниже, только заголовок и описание даст вам представление о том, что я сделал и о чем пытаюсь спросить, но, пожалуйста, прочтите раздел проблема )

я создаю Connect account для продавца, когда он регистрируется на моем веб-сайте

Создать учетную запись Connect

const express = require("express");
const router = express.Router();
  router.post("/createAccount", async (req, res) => {
  const { name, email } = req.body; //Data Passed from the FrontEnd
  stripe.accounts.create(
    {
      type: "custom",
      country: "US",
      email: email,
      requested_capabilities: ["card_payments", "transfers"],
    },
    function (err, account) {
      res.json({ account: account });
    }
  );
});

Когда Продавец предоставляет остальные необходимые данные (включая банковский счет) после входа в Seller Portal я создаю bank_account, обновляю уже созданный Connect Account и связываю bank_account с Connect Account (надеюсь, это как-то имеет смысл)

Создать банковский счет

  router.post("/createBankAccount", async (req, res) => {
  const { account_holder_name, routing_number, account_number } = req.body;
  stripe.tokens.create(
    {
      bank_account: {
        country: "US",
        currency: "USD",
        account_holder_name,
        account_holder_type: "individual",
        routing_number,
        account_number,
      },
    },
    function (err, token) {
      res.send(token);
    }
  );
});

Обновить Учетная запись:

  router.post("/updateAccount", async (req, res) => {
      const {
        AccountID,
        Day,
        Month,
        Year,
        first_name,
        last_name,
        email,
        BankAccountID,
      } = req.body;

      const FrontFilePath = fs.readFileSync("PathToFileHere");
      const FrontPhotoIDUpload = await stripe.files.create({
        file: {
          data: FrontFilePath,
          name: "FrontPhotoID.jpg",
          type: "application.octet-stream",
        },
        purpose: "identity_document",
      });

      const BackFilePath = fs.readFileSync("PathToFileHere");
      const BackPhotoIDUpload = await stripe.files.create({
        file: {
          data: BackFilePath,
          name: "BackPhotoID.jpg",
          type: "application.octet-stream",
        },
        purpose: "identity_document",
      });

      stripe.accounts.update(
        AccountID,
        {
          business_type: "individual",
          individual: {
            dob: { day: Day, month: Month, year: Year },
            first_name: first_name,
            last_name: last_name,
            id_number: "006-20-8311",
            phone: "605-628-6049",
            address: {
              city: "Half Way",
              line1: "2467  Twin House Lane",
              postal_code: "65663",
              state: "MO",
            },
            email,
            ssn_last_4: "8311",
            verification: {
              document: {
                front: FrontPhotoIDUpload.id,
                back: BackPhotoIDUpload.id,
              },
            },
          },
          business_profile: {
            mcc: "4722",
            url: "http://www.baoisne.com",
          },
          tos_acceptance: {
            date: Math.floor(Date.now() / 1000),
            ip: req.connection.remoteAddress, 
          },
        },
        function (err, account) {
          console.log(err);
          console.log(account);
        }
      );
     //Connect External Account
      stripe.accounts.createExternalAccount(
        AccountID,
        {
          external_account: BankAccountID,
        },
        function (err, bankAccount) {
          console.log(err);
          res.send(bankAccount);
        }
      );
    });

Затем, когда клиент предоставляет данные своей учетной записи, я беру с клиента деньги, оставляю часть денег в качестве платы за подачу заявления, а остальные переводю на счет Service Providers Connect.

Плата за клиента

  router.post("/charge", async (req, res) => {
  const { TokenID, CustomerID, Amount, AccountID } = req.body;
  let PaymentAmount = Amount * 100;
  let application_fee_amount = 400;
  try {
    const payment = await stripe.paymentIntents.create({
      amount: PaymentAmount,
      currency: "USD",
      description: "We did it boss",
      payment_method_data: {
        type: "card",
        card: {
          token: TokenID,
        },
      },
      receipt_email: "abdullahabid427@gmail.com",
      customer: CustomerID,
      application_fee_amount,
      transfer_data: {
      destination: AccountID,
      },
      confirm: true,
    });
    return res.status(200).json({
      confirm: "Payment Succeeded",
    });
  } catch (error) {
    console.log(error);
    return res.status(400).json({
      message: error.message,
    });
  }
});

Выполняя описанную выше процедуру, создается учетная запись подключения, и сумма перемещается в подключенную учетную запись.

Проблема

Вышеупомянутая процедура, хотя и работает правильно, она перемещает сумму в учетную запись подключенного поставщика услуг сразу после того, как с клиента будет снята оплата; я бы хотел, чтобы клиент заплатил платформе и после Поставщик услуг предоставил свои услуги, Платформа платит Поставщику услуг, я подумал об удалении

  application_fee_amount,
  transfer_data: {
  destination: AccountID,
  }

вышеуказанных параметров в конечной точке Charge или Stripe.paymentIntents.create и после того, как Поставщик услуг завершит свои услуги я перевожу сумму с помощью Stripe Transfer API

router.post("/transfer", async (req, res) => {
  try {
    console.log("TRANSFER=");
    const { AccountID, amount } = req.body;
    const transfer = await stripe.transfers.create({
      amount,
      currency: "USD",
      destination: AccountID,
    });
    res.send(transfer);
  } catch (error) {
    res.send(error);
  }
});

проблема в том, что конечная точка перевода t возвращает " В вашей целевой учетной записи должна быть включена хотя бы одна из следующих возможностей: переводы, legacy_payments ", я проверил подключенную учетную запись на панели инструментов Stripe и в разделе возможностей Card_Payment и Transfers оба установлены на Активный, плюс Платежи и Выплаты включены, а статус подключенной учетной записи - "Завершено"

Так что, если бы кто-нибудь мог указать в правильном направлении, я был бы очень признателен, Ура :)

Ответы [ 2 ]

3 голосов
/ 01 июня 2020

Хорошо - соглашаемся, что Stripe работает по назначению. Вы получаете сообщение об ошибке, которое возникает из-за удаления идентификатора целевой учетной записи из функции создания платежного намерения. Вот в чем проблема, под вашим заголовком Charge Customer .

Давайте посмотрим на это: (сокращенная версия)

const payment = await stripe.paymentIntents.create({
  amount: PaymentAmount,
  currency: "USD",
  ...
  customer: CustomerID,
  application_fee_amount,
  transfer_data: {
    destination: AccountID,
  },
  confirm: true,
});

Последнее свойство confirm: true - эквивалентно созданию и подтверждению платежного намерения в одном звонке. Значение по умолчанию - false - при этом статус вновь созданного платежного намерения будет requires_confirmation. И когда вы будете готовы, вы подтверждаете намерение платежа в следующих строках:

const confirmedPayment = await stripe.paymentIntents.confirm(
    'payment_intent_id',
    {payment_method: 'card'},
    function(err, paymentIntent) {

    }
});

Несколько общих комментариев о том, что что-то идет не так

Когда плательщик платит деньги для некоторых товаров в Интернете разработчик приложения отвечает за реализацию логи c, в соответствии с которой деньги и товары отправляются и принимаются: это может быть предоплата, постоплата или частично и то, и другое. Нет logi c надежный. В общем, если мы беспокоимся о том, что клиенты воспользуются нашей политикой оплаты, мы можем потребовать, чтобы все платежи были предоплачены всеми плательщиками, и включить политику справедливого возмещения. В этом случае Stripe поддерживает возврат средств по платежным намерениям, но, что более важно, отслеживает статус платежа.

Когда платежное намерение создано, но не подтверждено, статус будет requires_confirmation. Здесь не так уж много go. Но после подтверждения платежного намерения статус будет processing - это может занять несколько дней. Вы можете принять решение об отмене платежа в любое время. Но если все go в порядке, статус изменится на succeeded, что означает, что средства находятся на целевом счете. Но если платеж не состоится по какой-либо причине, статус вернется на requires_payment_method. Даже в этом случае нет необходимости создавать новый объект платежа или перевода. Вы можете узнать о платежном намерении в любое время, позвонив по номеру stripe.retrievePaymentIntent(clientSecret) и проверить статус. Но, на мой взгляд, гораздо проще отслеживать изменения статуса с помощью веб-перехватчика, который настроен на получение событий изменения статуса. Даже если при изменении статуса сразу же не происходит никаких действий, мы можем сохранить статус в базе данных, где он доступен.

По опыту я видел, насколько часто платежи терпят неудачу. Это не означает, что с обеих сторон происходит какое-то мошенничество, но это означает, что приложение должно быть готово обработать оба случая. События, которые нужно добавить в конфигурацию веб-перехватчика: payment_intent.succeeded и payment_intent.payment_failed. Способ обработки этих событий определяется c для каждого приложения.

0 голосов
/ 01 июня 2020

Создать веб-перехватчик (конфигурация полосы), который включает:

  • События, отправляемые на веб-перехватчик: в данном случае customer.created, customer.source.created, customer.source.updated
  • URL = маршрут, который обрабатывает события, когда они прибывают

Таким образом, вам нужно сначала сохранить ожидающий платеж в своей БД. Затем в веб-перехватчике найдите его в БД и завершите перенос.

...