我一直在努力解决通过 woocommerce 订单休息 API 端点在源站点和目标站点之间同步订单的重复问题:
/wp-json/wc/v3/orders
我提出了以下代码,它成功地从源检索订单数据并在目标上创建,但它反复从源获取相同的订单,并使用自动分配给它的新 ID 一次又一次地创建它。
因此,我希望订单仅同步一次,然后在源站点上的状态发生变化时进行更新
if (!empty($orders) && is_array($orders)) {
foreach ($orders as $order) {
if (isset($order['status']) && isset($order['customer_id'])) {
$first_name = $order['billing']['first_name'];
$last_name = $order['billing']['last_name'];
$phone = $order['billing']['phone'];
//line items
if (isset($order['line_items']) && is_array($order['line_items'])) {
foreach ($order['line_items'] as $item) {
$line_item_data = array(
'name' => $item['name'],
'quantity' => $item['quantity'],
'price' => $item['price'],
'subtotal' => $item['subtotal'],
'total' => $item['total'],
'product_id' => $item['product_id'],
);
$line_items_data[] = $line_item_data;
}
}
$order_data = array(
'status' => $order['status'],
'customer_id' => $order['customer_id'],
'billing' => array(
'first_name' => $first_name,
'last_name' => $last_name,
'phone' => $phone,
),
'line_items' => $line_items_data,
);
首先,我尝试匹配两个网站的订单 ID,这当然不是推荐做法,但值得一试,通过
$url .= '/' . $order_data['number'];
现在两个站点的订单都有相同的标识符,避免了重复订单,但却导致了
line_items
字段的积累(包括数量、价格等)
因此,在第二步中,我删除了上面的行,并尝试通过在
id
数组中包含 line_items
属性来区分订单:
$line_item_data = array(
'id' => $item['id'], //adding id object
'name' => $item['name'],
'quantity' => $item['quantity'],
'price' => $item['price'],
'subtotal' => $item['subtotal'],
'total' => $item['total'],
'product_id' => $item['product_id'],
);
但是我最后发现这是不允许的,所以这个方法也无法解决问题。
{
"code": "woocommerce_rest_invalid_item_id",
"message": "Order item ID provided is not associated with order.",
"data": {
"status": 400
}
}
问题似乎是由于缺乏映射机制、源 ID 及其对应的目标 ID 的跟踪而导致的,如果没有映射机制,源上的相同订单将被一遍又一遍地获取,而不是更新其状态。 我想知道是否还有其他方法可以解决这个令人沮丧的问题。 任何帮助将不胜感激。
完整代码:
// Cron Schedule to Run the Code
add_filter('cron_schedules', 'add_every_minute_interval');
function add_every_minute_interval($schedules) {
$schedules['every_minute'] = array(
'interval' => 60,
'display' => __('Every Minute')
);
return $schedules;
}
add_action('wp_loaded', 'schedule_order_sync');
function schedule_order_sync() {
if (!wp_next_scheduled('sync_orders_event')) {
wp_schedule_event(time(), 'every_minute', 'sync_orders_event');
}
}
add_action('sync_orders_event', 'sync_orders_from_source_to_destination');
// Function to create order on destination site
function create_order_on_destination_site($order_data, $api_url, $consumer_key, $consumer_secret) {
$url = $api_url . '/wp-json/wc/v3/orders';
$response = wp_remote_post($url, array(
'headers' => array(
'Authorization' => 'Basic ' . base64_encode($consumer_key . ':' . $consumer_secret),
'Content-Type' => 'application/json',
),
'body' => json_encode($order_data),
));
if (is_wp_error($response)) {
return false;
}
$body = wp_remote_retrieve_body($response);
$created_order = json_decode($body, true);
return $created_order;
}
// Function to get orders from source site
function get_orders_from_source_site($api_url, $consumer_key, $consumer_secret) {
$url = $api_url . '/wp-json/wc/v3/orders';
$response = wp_remote_get($url, array(
'headers' => array(
'Authorization' => 'Basic ' . base64_encode($consumer_key . ':' . $consumer_secret),
),
));
if (is_wp_error($response)) {
return array();
}
$body = wp_remote_retrieve_body($response);
$orders = json_decode($body, true);
return $orders;
}
// Main function to sync orders from source to destination
function sync_orders_from_source_to_destination() {
// Source site API credentials
$sourceSiteApiUrl = 'https://source.com';
$sourceConsumerKey = 'xxxxxxxxxxxxxxxxxxxx';
$sourceConsumerSecret = 'xxxxxxxxxxxxxxxxxxxx';
// Destination site API credentials
$destinationSiteApiUrl = 'https://destination.com';
$destinationConsumerKey = 'xxxxxxxxxxxxxxxxxxxx';
$destinationConsumerSecret = 'xxxxxxxxxxxxxxxxxxxx';
// Get orders from source site
$orders = get_orders_from_source_site($sourceSiteApiUrl, $sourceConsumerKey, $sourceConsumerSecret);
if (!empty($orders) && is_array($orders)) {
foreach ($orders as $order) {
if (isset($order['status']) && isset($order['customer_id'])) {
$first_name = $order['billing']['first_name'];
$last_name = $order['billing']['last_name'];
$phone = $order['billing']['phone'];
if (isset($order['line_items']) && is_array($order['line_items'])) {
foreach ($order['line_items'] as $item) {
$line_item_data = array(
'name' => $item['name'],
'quantity' => $item['quantity'],
'price' => $item['price'],
'subtotal' => $item['subtotal'],
'total' => $item['total'],
'product_id' => $item['product_id'],
);
$line_items_data[] = $line_item_data;
}
}
// order data
$order_data = array(
'status' => $order['status'],
'customer_id' => $order['customer_id'],
'billing' => array(
'first_name' => $first_name,
'last_name' => $last_name,
'phone' => $phone,
),
'line_items' => $line_items_data,
//etc
);
// Create order on destination site
$created_order = create_order_on_destination_site($order_data, $destinationSiteApiUrl, $destinationConsumerKey, $destinationConsumerSecret);
if ($created_order) {
echo 'Order ' . $created_order['id'] . ' created on destination site';
} else {
echo 'Failed to create order on destination site';
}
} else {
echo 'Order data is missing required fields';
}
}
} else {
echo 'No orders fetched from the source site';
}
}
正确的做法是明确要插入的各个数据表之间的关系:哪个是主表,哪个是子表,是一对一还是一对多或多对许多。 要同步数据,您可以使用
redis
队列或 kafka
。
生成格式化数据并推送到队列,然后让消费者消费并与数据表同步。
例如,确保数据表具有订单号字段的唯一索引。
防止插入重复数据。
您可以维护一个redis
集合来存储已消耗的订单。