Вопрос или проблема
Я использую этот код, который разделяет элементы заказов WooCommerce на отдельные заказы. Я нашел это на WP Answers, который я модифицировал для плагина билетирования событий.
Все работает отлично, на каждом билете есть QR-код, который проверяет и предотвращает дублирование билетов, с пользовательским статусом заказа, поэтому мне нужно, чтобы каждый билет был отдельным заказом. Я не могу понять, как остановить уменьшение запасов на оригинальном заказе, а также на запасах, которые уменьшаются для новых заказов. Например, если я покупаю 3 билета, то уменьшается 6 с общего запаса.
Это код, я буду признателен любому, кто сможет помочь.
add_action("woocommerce_thankyou", "action_woocommerce_checkout_order_processed", 10, 1);
function action_woocommerce_checkout_order_processed($order_id) {
// Получите объект заказа
$order = wc_get_order($order_id);
$taxonomy = "product_tag";
$items_to_remove = array();
// Перебираем каждый элемент в заказе
foreach ($order->get_items() as $item_key => $item) {
$product = $item->get_product();
$product_id = $item->get_product_id();
$quantity = $item->get_quantity();
// Проверяем, есть ли у продукта тег 'ticket'
if (has_term('ticket', $taxonomy, $product_id)) {
$items_to_remove[] = $item->get_id(); // Отметить этот элемент для удаления
// Отметить запас как уже уменьшенный для этого элемента
wc_update_order_item_meta($item->get_id(), '_stock_reduced', 'yes');
// Создать новые заказы для каждого количества билетов
for ($i = 1; $i <= $quantity; $i++) {
$new_order = wc_create_order();
// Добавить продукт в новый заказ с количеством 1
$new_order->add_product($product, 1);
// Скопировать информацию о выставлении и доставке
$new_order->set_address($order->get_address('billing'), 'billing');
$new_order->set_address($order->get_address('shipping'), 'shipping');
$new_order->set_currency($order->get_currency());
$new_order->set_payment_method($order->get_payment_method());
$new_order->set_payment_method_title($order->get_payment_method_title());
$new_order->set_date_paid(current_time('mysql')); // Отметить как оплаченный
// Уменьшить запас вручную на 1
if ($product->managing_stock()) {
wc_update_product_stock($product, $product->get_stock_quantity() - 1);
}
// Скопировать пользовательские поля для каждого билета (имя и электронная почта)
$ticket_name_meta_key = "ticket_name_{$item_key}_{$i}";
$ticket_email_meta_key = "ticket_email_{$item_key}_{$i}";
$ticket_name = get_post_meta($order_id, $ticket_name_meta_key, true);
$ticket_email = get_post_meta($order_id, $ticket_email_meta_key, true);
if (!empty($ticket_name)) {
update_post_meta($new_order->get_id(), 'ticket_name', $ticket_name);
}
if (!empty($ticket_email)) {
update_post_meta($new_order->get_id(), 'ticket_email', $ticket_email);
}
// Рассчитать итоги и сохранить новый заказ
$new_order->calculate_totals();
$new_order->save();
// Добавить заметку о заказе для отслеживания
$new_order->add_order_note(
'Автоматический заказ "билета". Создан из оригинального заказа ID: ' . $order_id
);
}
}
}
// Удалить элементы билетов из оригинального заказа, чтобы предотвратить дублирование записей
foreach ($items_to_remove as $item_id) {
$order->remove_item($item_id);
}
// Пересчитать и сохранить оригинальный заказ
$order->calculate_totals();
$order->save();
}
Ответ или решение
Как предотвратить двойное снижение запасов при использовании кода для разделения заказов в WooCommerce?
В процессе написания кода для вашего плагина Event Ticket вы столкнулись с проблемой уменьшения запасов на складском учете. Давайте проанализируем ваш код и предложим решение, которое предотвратит двойное снижение запасов, когда пользователи покупают билеты.
Проблема
При покупке 3 билетов замечаете, что запасы уменьшаются на 6 единиц. Это происходит из-за того, что вместо того, чтобы уменьшать запасы только на индивидуальные заказы билетов, код также продолжает уменьшать запасы оригинального заказа. Рассмотрим, как исправить эту ситуацию.
Решение
-
Отменить снижение запасов для оригинального заказа:
В вашем коде, когда каждый новый заказ создается из оригинального заказа, происходит снижение запасов. Это ведет к ненужному уменьшению. Нам нужно убедиться, что запас уменьшается только один раз для каждого нового заказа, который вы создаете. -
Добавление проверки на уменьшение запасов:
Вам необходимо добавить логику, которая будет управлять состоянием запаса и предотвращать его дальнейшее уменьшение с оригинального заказа.
Обновленный Код
Вот пример кода с внесенными изменениями:
add_action("woocommerce_thankyou", "action_woocommerce_checkout_order_processed", 10, 1);
function action_woocommerce_checkout_order_processed($order_id) {
$order = wc_get_order($order_id);
$taxonomy = "product_tag";
$items_to_remove = array();
foreach ($order->get_items() as $item_key => $item) {
$product = $item->get_product();
$product_id = $item->get_product_id();
$quantity = $item->get_quantity();
if (has_term('ticket', $taxonomy, $product_id)) {
$items_to_remove[] = $item->get_id(); // Mark this item for removal
// Создаем новый заказ для каждого билета
for ($i = 1; $i <= $quantity; $i++) {
$new_order = wc_create_order();
$new_order->add_product($product, 1);
// Копируем данные о покупке
$new_order->set_address($order->get_address('billing'), 'billing');
$new_order->set_address($order->get_address('shipping'), 'shipping');
$new_order->set_currency($order->get_currency());
$new_order->set_payment_method($order->get_payment_method());
$new_order->set_payment_method_title($order->get_payment_method_title());
$new_order->set_date_paid(current_time('mysql'));
// Проверяем, управляет ли продукт запасом
if ($product->managing_stock()) {
// Уменьшаем запасы лишь для нового заказа
$new_order_stock_quantity = $product->get_stock_quantity() - 1;
wc_update_product_stock($product, $new_order_stock_quantity);
}
// Копируем покупательские данные
$ticket_name_meta_key = "ticket_name_{$item_key}_{$i}";
$ticket_email_meta_key = "ticket_email_{$item_key}_{$i}";
$ticket_name = get_post_meta($order_id, $ticket_name_meta_key, true);
$ticket_email = get_post_meta($order_id, $ticket_email_meta_key, true);
if (!empty($ticket_name)) {
update_post_meta($new_order->get_id(), 'ticket_name', $ticket_name);
}
if (!empty($ticket_email)) {
update_post_meta($new_order->get_id(), 'ticket_email', $ticket_email);
}
$new_order->calculate_totals();
$new_order->save();
$new_order->add_order_note(
'Автоматический "билетный" заказ. Создан из оригинального заказа ID: ' . $order_id
);
}
}
}
// Удаление элементов билетов из оригинального заказа
foreach ($items_to_remove as $item_id) {
$order->remove_item($item_id);
}
// Пересчитываем и сохраняем оригинальный заказ
$order->calculate_totals();
$order->save();
}
Объяснение изменений
-
Убрали логику снижения запасов из оригинального заказа. Теперь снижение запасов происходит только для новых заказов.
-
Добавлена проверка управления запасами. Убедитесь, что у каждого продукта включен режим управления запасами, прежде чем уменьшать количество.
Заключение
С этой модификацией ваш код будет корректно обрабатывать заказы на билеты, предотвращая двойное снижение запасов. Вы также можете дополнительно протестировать новый функционал, чтобы убедиться в его корректности. Внедряя такие изменения, вы оптимизируете систему управления запасами в вашей WooCommerce среде, что способствует более эффективному обслуживанию клиентов и более точному учету.