Готовый клиентский модуль Google Pay

    Товарищи, представляю готовый модуль 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

      0
      Ссылка ЯндексДиск? А почему не GitHub?
        0
        Да, конечно, вы правы. Сделал GitHub
        –1
        А почему комментарии в коде и сообщения в лог на русском то?
          +2
          Возможно, потому что я русский
            0
            просто в ИТ сообществе принят за основу английских язык. Поэтому такой вопрос у человека возник :).
              0
              It seems strange you're talking russian to me, right?
                +1
                Ясно, уточнений от меня больше нету.
            +2
            Если команда исключительно русскоязычная, то зачем мучить разработчиков? Пусть пишут комментарии, логи и тикеты на русском языке. Это быстрее, понятней и не надо постоянно расшифровывать корявый, наполненный ошибками, английский.

            Сотрудников опять же проще набирать. Если проект ведется полностью на английском языке (включая документацию и создание тикетов), то приходится отсекать некоторых кандидатов, которые по остальным критериями подходят.
              +4
              Ну одно дело проект внутри компании, а другое — публичный opensource проект на гитхабе, который может быть потенциально интересен разработчикам не из России. Такое имхо стоит все же оформлять на английском
                +3
                и получаем монстров вроде
                it 'создает заказ' do
                  pokupka = blahblah
                  expect(pokupka).to be_kupleno
                end
                
              +1
              "protocolVersion": "ECv1",

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

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

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

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

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

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

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

              Самое читаемое