WooCommerce REST API v2:如何处理付款?
WooCommerce REST API v2: How to process payment?
使用 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": "Whosebug Money Laundering, Inc.",
"paid":true
},
"line_items": [
{
"product_id": 341,
"quantity": 1
}
]
}
}'
正如我所说,它生成一个已完成状态的订单,但实际上并没有通过我的网关处理任何资金(这不是 "Whosebug Money Laundering, Inc." 并且是在使用我们的 WooCommerce 时确实有效的合法网关网站)
正如 helgatheviking 所同意的那样,目前没有一种方法可以使用 WooCommerce REST API 处理订单付款。
我最终在 woocommerce_api_create_order
过滤器中编写了一个钩子,它在创建订单时立即处理付款订单。如果处理失败,则会将错误添加到 order->post->post_excerpt
字段,使其在 JSON 响应中显示为 order->note
。
为此,我还必须扩展支付网关,以便其 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 )
);
}
}
}
谢谢你给我的指导。
我做了一些更改并简化了步骤。
如下:
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;
}
我希望这可以帮助其他人。这是一项艰苦的工作,需要大量的反复试验。
如果您不处理托管支付网关(需要用户重定向到他们自己的域以处理付款的支付网关,例如 paypal),那么您可以通过 ajax 按照 WC 的方式进行操作要求:
// 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
不为空。
您也可以针对托管支付网关尝试此操作,但它会 return 一个 redirect
您可以在移动应用程序的网络视图中打开并收取付款。
https://gist.github.com/swport/afd9292412752df9e2e086ac38030e8f
使用 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": "Whosebug Money Laundering, Inc.",
"paid":true
},
"line_items": [
{
"product_id": 341,
"quantity": 1
}
]
}
}'
正如我所说,它生成一个已完成状态的订单,但实际上并没有通过我的网关处理任何资金(这不是 "Whosebug Money Laundering, Inc." 并且是在使用我们的 WooCommerce 时确实有效的合法网关网站)
正如 helgatheviking 所同意的那样,目前没有一种方法可以使用 WooCommerce REST API 处理订单付款。
我最终在 woocommerce_api_create_order
过滤器中编写了一个钩子,它在创建订单时立即处理付款订单。如果处理失败,则会将错误添加到 order->post->post_excerpt
字段,使其在 JSON 响应中显示为 order->note
。
为此,我还必须扩展支付网关,以便其 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 )
);
}
}
}
谢谢你给我的指导。
我做了一些更改并简化了步骤。
如下:
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;
}
我希望这可以帮助其他人。这是一项艰苦的工作,需要大量的反复试验。
如果您不处理托管支付网关(需要用户重定向到他们自己的域以处理付款的支付网关,例如 paypal),那么您可以通过 ajax 按照 WC 的方式进行操作要求:
// 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
不为空。
您也可以针对托管支付网关尝试此操作,但它会 return 一个 redirect
您可以在移动应用程序的网络视图中打开并收取付款。
https://gist.github.com/swport/afd9292412752df9e2e086ac38030e8f