Virtuemart дробное количество товаров
- Подробности
- Категория: Virtuemart-2
- Обновлено 22.01.2018
Сформулируем задачу:
Нам нужно, чтобы скрипт интуитивно добавлял в корзину и дробное, и целое число товаров в зависимости от того, как установлена цена: за штуку (Integer) или за метр квадратный (Float).
Для Opencart(OcStore) решение смотрите здесь.
В стандартной поставке компонент Virtuemart настроен на работу только с целым количеством товаров – "штуками". Очень часто магазины продают товары дробным количеством: метры квадратные, килограммы, литры. При этом цена указывается за единицу измерения, например за 1 квадратный метр или за 1 килограмм. Например магазину нужно продать остаток линолеума, площадь которого составляет 3,27 кв.м. Стандартный виртумарт не понимает количество товара 3,27. Бывают и более сложные ситуации с количеством товаров, например продажа керамической плитки. Базовая плитка продаётся квадратными метрами (и цена указывается за 1кв.м.), а декоративные элементы (вставки, бордюры, плинтусы) продаются поштучно и цена указывается за 1 штуку. Но вся прелесть ситуации в том, что в отличие от линолеума, вы не можете дробить каждую плитку! Другими словами, вы всегда продаёте плитку только штуками: и базовую, и декоры. Такая ситуация проиллюстрирована на Картинке-1, здесь пользователю разрешено заказывать только целое число плиток, так как нельзя продавать половинку или четвертинку плитки. Продать-то можно, но... продавать нельзя. При этом расчет количества заказываемого товара ведется в метрах квадратных для базовой плитки, и в штуках для декоративных элементов. На Картинке-2 показана корзина с добавленными товарами
Вот наш план действий (упрощенный)
- Давайте скажем Виртумарту, что у нас бывает несколько единиц измерений товаров и они всегда дробные, даже те, которые целые. Ну и пусть, главное чтобы работало. Для этого:
– Можно добавить новое поле в таблицу #__virtuemart_products для хранения единиц измерения. Но мы для быстроты и удобства использовали для этой цели уже существующее поле product_mpn, которое обычно никак не используется и, главное, оно отображается в админке в карточке товара на первой вкладе "Информация". В это поле и будем писать штуки, метры, литры, килограммы и так далее. Это показано на картинках 3 и 4. Умный читатель скажет: – Ха, так в этой таблице уже есть поле product_unit для хранения единиц товаров и оно легко заполняется из админки в той же карточке товара на вкладке "Габариты/Вес". Мы не против, – используйте на здоровье это поле. Мы исходили из практических соображений.– Теперь меняем тип данных с целых чисел на дробные ( float 10,4 ) в поле product_quantity в таблице #__virtuemart_order_items. Для хранения дробных чисел не рекомендуем использовать тип данных DECIMAL, так как не только по нашему мнению это не "бухгалтерский" формат.
- Решаем задачу "Плюсик" & "Минусик". Это две смешные кнопочки рядом с полем ввода количества товаров. При нажатии на "плюсик" количество увеличивается на единицу. При нажатии на "минусик" – уменьшается. Смешно, правда? Нам быстрее ввести число 100, чем сто раз нажимать на кнопочку. Поэтому мы пошли радикальным путем: убрали из кода страницы обе кнопки. НО! Сам Javascript, который обрабатывает события для этих кнопок мы модифицировали и использовали его для трех целей: 1. Проверка введенного числа только на ЦЕЛОЕ (никаких дробных "плиток" покупатель вводить не должен), ибо только целые плиточки продаёт наш магазин. 2. Копирование введённого целого значения в "целевое поле", если цена указана за "штуку"; или ввод в "целевое поле" рассчитанной "на лету" суммарной площади, если цена указана за квадратный метр; 3. Округление дробного значения до четвёртого знака после запятой.
Да, для этого нам пришлось добавить на страницу дополнительное "целевое поле" input, закрытое от редактирования параметром readonly. Именно из этого поля POST отправляет данные на сервер.
Если ваш магазин продает только дробные товары, то задача упрощается. Если вам нужны на странице "Плюсик" & "Минусик", то придется изменить значение переменной $step с 1 на дробное, например, на 0.01Задача пункта-2 решается в файлах: site.com/components/com_virtuemart/views/productdetails/tmpl/default.php и default_addtocart.php
Для удобства работы мы объединили коды этих двух файлов в один. То есть ушли от конструкции echo $this->loadTemplate('addtocart');
- Добавление в корзину и апдейт дробного числа товаров.
Править нужно четыре функции в файле:
site.com/components/com_virtuemart/helpers/cart.php
1) public function add($virtuemart_product_ids=null,&$errorMsg='')
в строке: $quantityPost = (int) $post['quantity'][$p_key];
меняем на: $quantityPost = (float) $post['quantity'][$p_key];
после строки: $product -> product_sku = $tmpProduct -> product_sku;
Добавляем строку: $product -> product_mpn = $tmpProduct -> product_mpn;
в строке: $product->quantity = (int)$quantityPost;
меняем на: $product->quantity = (float)$quantityPost;
2) public function updateProductCart($cart_virtuemart_product_id=0,$quantity = null)
в строке: if ($quantity === null) $quantity = vRequest::getInt('quantity');
меняем на: if ($quantity === null) $quantity = vRequest::getFloat('quantity');
3) private function checkForQuantities($product, &$quantity=0,&$errorMsg ='')
в строке: if ($quantity < 1) {
меняем на: if ($quantity < 0.01) { // Здесь вы можете указать свой минимальный порог
4) function prepareAjaxData($checkAutomaticSelected=false)
находим: $this->data->products[$i]['product_sku'] = $product->product_sku;
ниже добавляем: $this->data->products[$i]['product_mpn'] = $product->product_mpn; - Вывод дробного числа товаров на странице "Корзина".
Редактируем файл: site.com/components/com_virtuemart/views/cart/tmpl/default_pricelist.php
После редактирования функции function prepareAjaxData() в объект $cart попадает переменная product_mpn.
И в файле default_pricelist.php она становится доступна:
foreach ($this->cart->products as $pkey => $prow) {
.......
echo $prow->product_mpn;
.......
} - Выводим единицы измерения товаров в админке на странице Заказа.
Для этого нужно:
добавить в таблицу базы данных #__virtuemart_order_items поле, например, order_item_mpn varchar(255)
и отредактировать три файла:
1) site.com/administrator/components/com_virtuemart/tables/order_items.php
после строки:
var $order_item_sku = NULL;
добавить:
var $order_item_mpn = NULL;
2) site.com/administrator/components/com_virtuemart/models/orders.php
в функцию (примерно 1145 строка) private function _createOrderLines($_id, $_cart)
после строки:
$_orderItems->order_item_sku = $_prod->product_sku;
добавить:
$_orderItems->order_item_mpn = $_prod->product_mpn;
в функцию (примерно 173 строка) public function getOrder($virtuemart_order_id) в запросе
(примерно 201 строка) $q = 'SELECT virtuemart_order_item_id, product_quantity,....
добавить
$q = 'SELECT virtuemart_order_item_id, product_quantity,order_item_mpn,....
3) site.com/administrator/components/com_virtuemart/views/orders/tmpl/order.php
добавить заголовок колонки в таблицу (примерно 430 строка)
<th class="title" width="47" align="left">Ед.изм.</th>
и в цикл вывода списка товаров добавить колонку (примерно 500 строка):
<td><?php echo $item->order_item_mpn; ?></td>
После добавления колонки не лишним будет подправить объединение ячеек в нижних строках таблицы.
У нас ниже расположена только одна строка таблицы с итоговыми значениями.
Поэтому в коде правим <td colspan="4"> на <td colspan="5">, это примерно 566 строка. - Осталось добавить product_mpn в тело письма покупателю и в счёт. Как вы уже догадались, нужно править файл шаблона.
А именно
site.com/components/com_virtuemart/views/invoice/tmpl/invoice_items.php
В нужное место таблицы вставляем заголовок столбца (примерно 40 сторока):
<td style="border-collapse: collapse; border: 1px dotted black;" align="left" width="5%"><strong>Ед.изм.</strong></td>
и сам столбец (в цикле foreach):
<td style="border-collapse: collapse; border: 1px dotted black;" align="left" >
<?php echo $item->order_item_mpn; //Единицы измерения товара ?>
</td>