Товарищи, представляю готовый модуль JavaScript для осуществления платежей с помощью Google Pay. Модуль предполагает использование в современной среде разработки npm с экспортами-импортами, однако, те, кто хочет чистого ES5, думаю, без труда смогут его переделать.

Ссылка на модуль. В коде есть нужная документация и комментарии. Здесь дам некоторые пояснения.



Надо сказать, что гугловская документация именно по платёжной кнопке оказалось не самая простая, список ошибок, возвращаемых Google Pay API, тоже не самый полный. Поэтому, в отличие от работы с ApplePay, с Google Pay пришлось чуть-чуть почертыхаться, прежде чем модуль действительно заработал.

Работа состоит из двух этапов: сначала мы должны принять решение, показывать или нет кнопку (не все браузеры поддерживают Google Pay), а потом выполнить сам платёжный процессинг.

1. Показ кнопки

export function showGooglePayButton(options, callbacks) {
    // проверка параметров
    const check = checkParams("showGooglePayButton", options, callbacks);
    if (!check) {
        return false;
    } else {
        options = check.options;
    }

    const paymentsClient = new google.payments.api.PaymentsClient({environment: options.environment});
    // в приложении запоминаем экземпляр платёжного клиента, который создало API
    callbacks.setPaymentClient(paymentsClient);
    const request = {
        apiVersion: 2,
        apiVersionMinor: 0,
        allowedPaymentMethods: [options.googleBaseCardPaymentMethod]
    };
    paymentsClient.isReadyToPay(request)
        .then(function(response) {
            if (response.result) {
                callbacks.success();
                return true;
            } else {
                console.log("Запрос на показ кнопки Google Pay закончился неудачно");
                callbacks.fail();
            }
        })
        .catch(function(err) {
            console.log("showGooglePayButton ERROR");
            callbacks.fail();
        });
}

Тут ничего сложного. В options мы передаём два параметра — googleBaseCardPaymentMethod и environment.

googleBaseCardPaymentMethod — это объект, в котором перечислены платёжные типы и параметры (подробнее здесь по поиску allowed). Если он не задан, мы в коде вызываем стандартный сеттер, возвращающий нам типовой объект:

const setGoogleBaseCardPaymentMethod = () => {
    return {
        type: "CARD",
        parameters: {
            allowedAuthMethods: ["PAN_ONLY", "CRYPTOGRAM_3DS"],
            allowedCardNetworks: ["AMEX", "DISCOVER", "JCB", "MASTERCARD", "VISA"]
        }
    }
};

environment — это окружение, PRODUCTION или TEST

На вызове коллбэка success мы собственно отрисовываем (либо показываем уже отрисованную) кнопку. Это на ваш выбор. Помните только, что Google требует соответствия его гайдам.

2. Процессинг

Для показа кнопки Google Pay API вашего браузера создало объект paymentsClient, который теперь вместе с другими параметрами нужно передать в функцию процессинга. Посмотрим на другие параметры:

googleBaseCardPaymentMethod — см. выше
googlePayPublicKey, merc_id, merc_name — для успешной работы с Google Pay у вас должен быть зарегистрированный merchant. Его параметры мы получаем то бэка.

Кроме того, мы передаём коллбэки success и fail, а также данные для осуществления платежа (см. ниже).

Итак, для осуществления платежа мы должны взять ранее созданный объект paymentsClient и вызвать у него метод loadPaymentData с объектом paymentDataRequest: const paymentDataRequest = getGooglePaymentDataRequest():

const getGooglePaymentDataRequest = () => {
        const cardPaymentMethod = Object.assign(
            {},
            baseMethod,
            {
                tokenizationSpecification: token
            }
        );

        const paymentDataRequest = {
            apiVersion: 2,
            apiVersionMinor: 0,
            allowedPaymentMethods : [cardPaymentMethod],
            /* for demo (enviroment TEST):
                merchantInfo : {
                    merchantId: '12345678901234567890',
                    merchantName: 'JOHN SMITH'
                },
            */
            /* for prod (enviroment PRODUCTION):
                merchantInfo : {
                    merchantId: options.merc_id,
                    merchantName: options.merc_name
                },
            */
            merchantInfo : {
                merchantId: options.merc_id,
                merchantName: options.merc_name
            },
            transactionInfo : {
                currencyCode: options.currency,
                totalPriceStatus: 'FINAL',
                totalPrice: "" + options.sum
            }
        };

        return paymentDataRequest;
    };

Для тестовой среды Google предлагает свой объект merchantInfo. Его нужно использовать именно с тем merchantId, который записан в примере, merchantName не существенно.

Кроме того, нам нужен объект token:

const token = {
        /* for demo (enviroment TEST):
            parameters: {
                "protocolVersion": "ECv1",
                "publicKey": yourTestPublicKey
            }
        */
        /* for prod (enviroment PRODUCTION):
            parameters: {
                "protocolVersion": "ECv1",
                "publicKey": params.googlePayPublicKey
            }
        */
        type: 'DIRECT',
        parameters: {
            "protocolVersion": "ECv1",
            "publicKey": options.googlePayPublicKey
        }
    };

> Подробнее о параметрах читать тут

Далее, когда объект сформирован, с помощью метода loadPaymentData посылается запрос на сервер Google, открывается фрейм с сохранёнными картами, после завершения операции фрейм закрывается:


 paymentsClient.loadPaymentData(paymentDataRequest)
        .then(function(paymentData) {
            const googleToken = JSON.parse(paymentData.paymentMethodData.tokenizationData.token);
// your own client-back ajax request here

}

После успешного выполнения метода (то есть вызова сохранённых карт и прохождения верификации) мы можем делать AJAX-запрос на собственный бэк с целью провести платёж с помощью Google Pay. В этом запросе нам нужно будет обязательно передать пришедший от Гугла googleToken, а также публичный ключ.

Всё, наш платёж Google Pay после обработки на бэке состоялся!

Комментарии (14)


  1. jlex_
    14.12.2018 13:58

    Ссылка ЯндексДиск? А почему не GitHub?


    1. botyaslonim Автор
      14.12.2018 14:08

      Да, конечно, вы правы. Сделал GitHub


  1. vanyas
    14.12.2018 14:44

    А почему комментарии в коде и сообщения в лог на русском то?


    1. botyaslonim Автор
      14.12.2018 14:46

      Возможно, потому что я русский


      1. MeGaPk
        14.12.2018 15:14
        -1

        просто в ИТ сообществе принят за основу английских язык. Поэтому такой вопрос у человека возник :).


        1. botyaslonim Автор
          14.12.2018 15:17

          It seems strange you're talking russian to me, right?


          1. MeGaPk
            14.12.2018 15:18

            Ясно, уточнений от меня больше нету.


    1. Perlovich
      14.12.2018 15:22
      +1

      Если команда исключительно русскоязычная, то зачем мучить разработчиков? Пусть пишут комментарии, логи и тикеты на русском языке. Это быстрее, понятней и не надо постоянно расшифровывать корявый, наполненный ошибками, английский.

      Сотрудников опять же проще набирать. Если проект ведется полностью на английском языке (включая документацию и создание тикетов), то приходится отсекать некоторых кандидатов, которые по остальным критериями подходят.


      1. vanyas
        14.12.2018 15:36

        Ну одно дело проект внутри компании, а другое — публичный opensource проект на гитхабе, который может быть потенциально интересен разработчикам не из России. Такое имхо стоит все же оформлять на английском


      1. Fedcomp
        14.12.2018 20:05
        +1

        и получаем монстров вроде

        it 'создает заказ' do
          pokupka = blahblah
          expect(pokupka).to be_kupleno
        end
        


  1. Sly_tom_cat
    14.12.2018 19:52

    "protocolVersion": "ECv1",

    Это уже оутдейтед. Гугл активно пушит ECv2.

    Ну и честно говоря не понял критики кодов примеров расположенных на сайте гугла для разработчиков. Там вполне рабочий код. Напильника не требует.

    А «PAN_ONLY» в allowedAuthMethods вернет вам сохраненную в гуглоакаунте карту (PAN и EXP) — и хрен вы их где-нибудь отпроцессите без CVC…


    1. botyaslonim Автор
      14.12.2018 20:08

      Верно, мы должны будем ввести CVV.
      Но я прошу отнестись к этому коду как к рыбе для своей задачи, а не как к универсальному инструменту на все случаи


      1. Sly_tom_cat
        15.12.2018 17:45

        Если вы сами раскрываете криптоконтейнер, да еще CVC запрашивать собрались — то вы уже попали под PI DSS и PCI DSS.

        Тут ведь вся петрушка — в ECv2 нужно только имя гейта передать в запрос и отдать пакет вашему гейту (платежному шлюзу). В таком раскладе ваше приложение ни с какими картами и токенами не работает, и не под какую сертификацию не попадает.


        1. botyaslonim Автор
          16.12.2018 11:11

          Спасибо за дополнения.
          Да, я этот код разрабатывал для компании, которая сертифицирована по PCIDSS