WooCommerce REST API v2: как обработать платеж?

Используя WooCommerce REST API v2, я успешное создание заказа в ожидающем неоплаченном состоянии.

Я вижу, что я могу установить для поля order.payment_details.paid значение true, которое создаст заказ в состоянии завершения и отправит электронное письмо с завершенным заказом, но на самом деле это не обработает платеж.

Как правильно использовать REST API v2 для создания заказа и обработки платежа WooCommerce с помощью платежного шлюза?

Или мне нужно добавить хук плагина в API на стороне сервера? (Я так думаю)

Вот что я пробовал

curl -X POST https://example.com/wc-api/v2/orders \
    -u consumer_key:consumer_secret \
    -H "Content-Type: application/json" \
    -d '{
          "order": {
            "customer_id": 2,
            "payment_details": {
              "method_id": "da_big_bank",
              "method_title": "StackOverflow Money Laundering, Inc.",
              "paid":true
            },
            "line_items": [
              {
                "product_id": 341,
                "quantity": 1
              }
            ]
          }
        }'

который, как я уже сказал, генерирует заказ в завершенном состоянии, но на самом деле не обрабатывает деньги с помощью моего шлюза (который не является «StackOverflow Money Laundering, Inc.» и является законным шлюзом, который работает при использовании нашего сайта WooCommerce)


person Kirby    schedule 18.06.2015    source источник
comment
Я не верю, что вы можете обработать платеж через API. По крайней мере, глядя на документацию по API, я не вижу раздела для обработки платежа.   -  person helgatheviking    schedule 19.06.2015


Ответы (3)


Как согласился helgatheviking, в настоящее время нет способа обработать оплату заказа с помощью WooCommerce REST API.

В итоге я написал хук в фильтре woocommerce_api_create_order, который сразу же обрабатывает заказ на оплату при его создании. Если обработка не удалась, то ошибки добавляются в поле order->post->post_excerpt, из-за чего оно отображается как order->note в ответе JSON.

Чтобы это работало, мне также пришлось расширить платежный шлюз, чтобы его метод process_payment() принимал $user_id в качестве входных данных. Это связано с тем, что он изначально закодирован для работы с пользователем, вошедшим в систему в данный момент, который в моем случае и, вероятно, в большинстве случаев является системным пользователем, под которым входит клиент REST, а не фактический пользователь, делающий покупку.

Другим преимуществом расширения шлюза стало то, что теперь ошибки можно возвращать, а не записывать в wc_add_notice(). Поскольку это служба REST, ничто никогда не видит вывод wc_add_notice()

add_filter('woocommerce_api_create_order', 'acme_on_api_create_order', 10, 3);

/**
 * When order is created in REST client, actually make them pay for it
 * @param int $id order id
 * @param array $data order data posted by client
 * @param WC_API_Orders $api not used
 * @return array the data passed back unaltered
 */
function acme_on_api_create_order($id, $data, $api) {
    if($data['payment_details']['method_id'] == 'acme_rest_gateway') {
        $order = wc_get_order($id);
        $order->calculate_totals();
        $acme_gateway = new WC_Acme_Gateway_For_Rest();
        $payment = $acme_gateway->process_payment($id, $data['customer_id']);
        if($payment["result"] == "success") {
            $order->update_status('completed');
        }
        else {
            $order->update_status("cancelled");
            wp_update_post(array(
                'ID' => $id,
                'post_excerpt' => json_encode($payment)
            ));
        }
    }
    return $data;
}

// Register the payment gateway
add_filter('woocommerce_payment_gateways', 'acme_add_payment_gateway_class');

function acme_add_payment_gateway_class($methods) {
    $methods[] = 'WC_Acme_Gateway_For_Rest';
    return $methods;
}

// Load the new payment gateway needed by REST client
add_action('after_setup_theme', 'acme_init_rest_gateway_class');

function acme_init_rest_gateway_class() {

    /**
     * Extend the payment gateway to work in the REST API context
     */
    class WC_Acme_Gateway_For_Rest extends WC_Acme_Gateway {

        /**
         * Constructor for the gateway.
         */
        public function __construct() {
            parent::__construct();
            $this->id = 'acme_rest_gateway';
        }

        /**
         * Process Payment. This is the same as the parent::process_payment($order_id) except that we're also passing
         * the user id rather than reading get_current_user_id().
         * And we're returning errors rather than writing them as notices
         * @param int $order_id the order id
         * @param int $user_id user id
         * @return array|null an array if success. otherwise returns nothing
         */
        function process_payment($order_id, $user_id) {
                $order = wc_get_order( $order_id );
            /* 
             * todo: code sending da moneez to da bank
             */
                return array(
                    'result'   => 'success',
                    'redirect' => $this->get_return_url( $order )
                );
        }
    }
}
person Kirby    schedule 19.06.2015

Спасибо за направление, которое вы мне дали.

Я внес некоторые изменения и упростил шаги.

Следующее:

add_filter('woocommerce_api_order_response', 'intercept_api_response', 1, 4);
/**
* Here, intercept api's response to include the url of payment
**/
function intercept_api_response($order_data, $order)
{
    $order_data['payment_url'] = $order->payment_url;

    return $order_data;
}

add_filter('woocommerce_api_create_order', 'intercept_on_api_create_order', 10, 3);


function intercept_on_api_create_order($id, $data, $api)
{
    if (in_array($data['payment_details']['method_id'], ['pagseguro', 'paypal'])) {
        $order = wc_get_order($id);
        $order->calculate_totals();

        if ($data['payment_details']['method_id'] == 'paypal') {
            $paypal = new WC_Gateway_Paypal();
            $payment = $paypal->process_payment($id);
        }
        update_post_meta($id, '_payment_url', $payment['redirect']);
    }
    return $payment;
}

Я надеюсь, что это может помочь кому-то еще. Это была тяжелая работа с множеством проб и ошибок.

person Eder Ribeiro    schedule 03.11.2015
comment
Как произвести оплату с помощью этого плагина WooCommerce PayPal Powered by Braintree Payment Gateway через REST API WooCommerce - person Mr. Ajay; 25.12.2017
comment
В этой версии отсутствует критический шаг по расширению шлюза и передаче идентификатора пользователя в процесс вызова метода оплаты, верно? как в: function process_payment ($ order_id, $ user_id), принятый ответ сработал для меня. - person Claytronicon; 02.02.2018

Если вы НЕ имеете дело с размещенными платежными шлюзами (теми, которые требуют от пользователей перенаправления на их собственный домен для обработки платежей, таких как PayPal), вы можете просто сделать это, как это делает WC, через запрос ajax:

// this is a function as a callback for a restful api - process_payment

// collect payment related info: billing, shipping info, including shipping_method & payment_method

// put all that info inside $_POST global var

// so that the nonce won't fail
$_REQUEST['_wpnonce'] =
        wp_create_nonce( 'woocommerce-process_checkout' );

// make it look like an ajax request
wc_maybe_define_constant('DOING_AJAX', 1);

add_filter('woocommerce_payment_successful_result', function($response) {
     // wp_send_json appropriate response
}

WC()->checkout()->process_checkout();

WC()->checkout()->process_checkout() создаст для вас заказ, который WC()->cart не пуст.

Вы также можете попробовать это для размещенных платежных шлюзов, но это вернет redirect, который вы можете открыть в веб-просмотре мобильного приложения и получить платеж.

https://gist.github.com/swport/afd9292412752df9e2e086ac38030e8f

person Sumit Wadhwa    schedule 23.06.2020