Kgshop commited on
Commit
37617e3
·
verified ·
1 Parent(s): fba6dda

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +83 -40
app.py CHANGED
@@ -100,6 +100,7 @@ translations = {
100
  'error_page_title': 'Ошибка',
101
  'order_not_found_by_id': 'Заказ с таким ID не найден.',
102
  'whatsapp_greeting': 'Здравствуйте! Хочу подтвердить свой заказ на emir:',
 
103
  'whatsapp_order_number': 'Номер заказа:',
104
  'whatsapp_order_link': 'Ссылка на заказ:',
105
  'whatsapp_contact_request': 'Пожалуйста, свяжитесь со мной для уточнения деталей оплаты и доставки.',
@@ -205,11 +206,11 @@ translations = {
205
  'flash_category_delete_success': "Категория '{category_name}' удалена.",
206
  'flash_category_delete_failed': "Не удалось удалить категорию '{category_name}'.",
207
  'flash_subcategory_added_success': "Подкатегория '{subcategory_name}' успешно добавлена.",
208
- 'flash_subcategory_name_empty': 'Название подкатегории не может быть пустым.',
209
  'flash_parent_category_not_selected': 'Необходимо выбрать родительскую категорию.',
210
  'flash_subcategory_already_exists': "Подкатегория '{subcategory_name}' уже существует в этой категории.",
211
  'flash_subcategory_delete_success': "Подкатегория '{subcategory_name}' удалена.",
212
- 'flash_subcategory_delete_failed': "Не удалось удалить подкатегорию.",
213
  'flash_supplier_added_success': "Поставщик '{supplier_name}' успешно добавлен.",
214
  'flash_supplier_name_empty': 'Имя поставщика не может быть пустым.',
215
  'flash_supplier_already_exists': "Поставщик '{supplier_name}' уже существует.",
@@ -238,7 +239,7 @@ translations = {
238
  'flash_failed_delete_hf_files_warning': "Не удалось удалить файлы для товара '{product_name}' с сервера. Товар удален локально.",
239
  'flash_hf_token_write_not_set_files_not_deleted_warning': "Товар '{product_name}' удален локально, но файлы не удалены с сервера (токен не задан).",
240
  'flash_product_deleted_success': "Товар '{product_name}' удален.",
241
- 'flash_delete_error_not_found': "Ошибка удаления: товар с ID '{product_id}' не найден.",
242
  'flash_unknown_action': 'Неизвестное действие: {action}',
243
  'flash_internal_error': "Произошла внутренняя ошибка при выполнении действия '{action}'. Подробности в логе сервера.",
244
  'flash_data_uploaded_hf_success': 'Данные успешно загружены на Hugging Face.',
@@ -255,7 +256,7 @@ translations = {
255
  'flash_settings_updated': 'Настройки успешно обновлены.',
256
  'prices_disabled_notice_catalog': 'Цены временно не отображаются. Добавьте товары в корзину для запроса стоимости.',
257
  'prices_disabled_notice_cart': 'Цены не отображаются. Стоимость будет рассчитана после оформления заказа.',
258
- 'request_price_calculation_button': 'Запросить расчет стоимости',
259
  'price_on_request': 'Цена по запросу',
260
  'video_modal_title': 'Видео о товаре',
261
  'save_all_changes_button': 'Сохранить все изменения ({count})',
@@ -941,14 +942,18 @@ CATALOG_TEMPLATE = '''
941
  <div class="product-price-container">
942
  {% set discount = product.get('discount_percent', 0) %}
943
  {% set original_price_kgs = product.price_kgs %}
944
- {% if app_config.prices_enabled and original_price_kgs > 0 %}
945
  {% if discount > 0 %}
946
  {% set discounted_price_kgs = original_price_kgs * (100 - discount) / 100 %}
947
  <span class="original-price">{{ "%.2f"|format(original_price_kgs) }} {{ currency_code }}</span><br>
948
  <span class="product-price discounted">{{ "%.2f"|format(discounted_price_kgs) }} {{ currency_code }}</span>
949
  <span class="discount-badge">{{ get_translation('discount_badge_text', discount=discount) }}</span>
950
  {% else %}
951
- <span class="product-price">{{ "%.2f"|format(original_price_kgs) }} {{ currency_code }}</span>
 
 
 
 
952
  {% endif %}
953
  {% else %}
954
  <div class="product-price on-request">{{ get_translation('price_on_request') }}</div>
@@ -962,9 +967,16 @@ CATALOG_TEMPLATE = '''
962
  <i class="fas fa-play-circle"></i> {{ get_translation('view_video_button') }}
963
  </button>
964
  {% endif %}
965
- <button class="product-button add-to-cart" onclick="openQuantityModal({{ loop.index0 }})">
966
- <i class="fas fa-cart-plus"></i> {{ get_translation('add_to_cart') }}
967
- </button>
 
 
 
 
 
 
 
968
  </div>
969
  </div>
970
  </div>
@@ -1061,6 +1073,21 @@ CATALOG_TEMPLATE = '''
1061
  return text;
1062
  }
1063
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1064
  function openModal(index) {
1065
  loadProductDetails(index);
1066
  const modal = document.getElementById('productModal');
@@ -1202,6 +1229,12 @@ CATALOG_TEMPLATE = '''
1202
  if (product.discount_percent && product.discount_percent > 0) {
1203
  priceToAdd = product.price_kgs * (100 - product.discount_percent) / 100;
1204
  }
 
 
 
 
 
 
1205
 
1206
  if (existingItemIndex > -1) {
1207
  cart[existingItemIndex].quantity += quantity;
@@ -1540,7 +1573,7 @@ PRODUCT_DETAIL_TEMPLATE = '''
1540
 
1541
  {% set discount = product_info.get('discount_percent', 0) %}
1542
  {% set original_price_kgs = product_info.price_kgs %}
1543
- {% if app_config.prices_enabled and original_price_kgs > 0 %}
1544
  <div style="margin: 20px 0; padding: 15px; background: var(--bg-steel-mid); border-radius: 8px;">
1545
  <strong style="font-size: 1.1rem; color: var(--text-light);">{{ get_translation('price') }}</strong>
1546
  {% if discount > 0 %}
@@ -1548,7 +1581,11 @@ PRODUCT_DETAIL_TEMPLATE = '''
1548
  <span style="font-size: 1.8rem; font-weight: 700; color: var(--accent-red); margin-left: 10px;">{{ "%.2f"|format(discounted_price_kgs) }} {{ currency_code }}</span>
1549
  <span style="text-decoration: line-through; color: var(--text-steel); font-size: 1.2rem; margin-left: 15px;">{{ "%.2f"|format(original_price_kgs) }} {{ currency_code }}</span>
1550
  {% else %}
1551
- <span style="font-size: 1.8rem; font-weight: 700; color: var(--text-light); margin-left: 10px;">{{ "%.2f"|format(original_price_kgs) }} {{ currency_code }}</span>
 
 
 
 
1552
  {% endif %}
1553
  </div>
1554
  {% else %}
@@ -1624,13 +1661,13 @@ ORDER_TEMPLATE = '''
1624
  <img src="{{ item.photo_url }}" alt="{{ item.name }}" {% if not item.photo %}style="opacity: 0.5;"{% endif %}>
1625
  <div class="item-details">
1626
  <strong>{{ item.name }} {% if item.color != 'N/A' %}({{ item.color }}){% endif %}</strong>
1627
- {% if order.prices_were_enabled_at_order %}
1628
  <span>{{ "%.2f"|format(item.price_kgs_at_order) }} {{ currency_code }} × {{ item.quantity }}</span>
1629
  {% else %}
1630
  <span>{{ get_translation('quantity') }} {{ item.quantity }}</span>
1631
  {% endif %}
1632
  </div>
1633
- {% if order.prices_were_enabled_at_order %}
1634
  <div class="item-total">
1635
  {{ "%.2f"|format(item.price_kgs_at_order * item.quantity) }} {{ currency_code }}
1636
  </div>
@@ -1643,7 +1680,7 @@ ORDER_TEMPLATE = '''
1643
  {% endfor %}
1644
  </div>
1645
 
1646
- {% if order.prices_were_enabled_at_order %}
1647
  <div class="order-summary">
1648
  <p>{{ get_translation('total_products_sum') }} <strong>{{ "%.2f"|format(order.total_price_kgs) }} {{ currency_code }}</strong></p>
1649
  </div>
@@ -1676,7 +1713,7 @@ ORDER_TEMPLATE = '''
1676
  message += `*{{ get_translation('whatsapp_order_number') | replace("'", "\\'") }}* ${orderId}` + "%0A";
1677
  message += `*{{ get_translation('whatsapp_order_link') | replace("'", "\\'") }}* ${encodedOrderUrl}` + "%0A%0A";
1678
 
1679
- {% if not order.prices_were_enabled_at_order %}
1680
  message += `{{ get_translation('whatsapp_request_price_calculation') | replace("'", "\\'") }}` + "%0A%0A";
1681
  {% endif %}
1682
 
@@ -1805,6 +1842,7 @@ ADMIN_TEMPLATE = '''
1805
  <h2><i class="fas fa-cog"></i> {{ get_translation('admin_settings_title') }}</h2>
1806
  <form method="POST" action="{{ url_for('admin_actions') }}">
1807
  <input type="hidden" name="action" value="update_settings">
 
1808
  <div style="margin-top: 15px;">
1809
  <input type="checkbox" id="prices_enabled" name="prices_enabled" {% if app_config.prices_enabled %}checked{% endif %}>
1810
  <label for="prices_enabled" class="inline-label">{{ get_translation('admin_prices_enabled_checkbox_label') }}</label>
@@ -2039,7 +2077,7 @@ ADMIN_TEMPLATE = '''
2039
  <p><strong>{{ get_translation('supplier') }}:</strong> {{ product_info.supplier_name }}</p>
2040
  <p><strong>{{ get_translation('category') }}:</strong> {{ product_info.category_name }}</p>
2041
  <p><strong>{{ get_translation('subcategory') }}:</strong> {{ product_info.subcategory_name }}</p>
2042
- <p><strong>{{ get_translation('price') }}:</strong> {{ "%.2f"|format(product_info.price_kgs) }} {{ currency_code }}</p>
2043
  {% if product_info.get('discount_percent', 0) > 0 %}
2044
  <p><strong class="discount-info">{{ get_translation('discount_label_item') }} {{ product_info.discount_percent }}%</strong></p>
2045
  {% endif %}
@@ -2538,10 +2576,11 @@ def create_order():
2538
  price_kgs_in_cart = float(item['price_kgs'])
2539
  original_price_kgs = float(item.get('original_price_kgs', price_kgs_in_cart))
2540
  quantity = int(item['quantity'])
2541
- if price_kgs_in_cart < 0 or quantity <= 0:
2542
- raise ValueError("Invalid price or quantity")
2543
-
2544
- if prices_currently_enabled:
 
2545
  total_price_kgs += price_kgs_in_cart * quantity
2546
 
2547
  processed_cart.append({
@@ -2673,24 +2712,24 @@ def admin_api():
2673
  try:
2674
  if action == 'add_product':
2675
  name = request.form.get('name', '').strip()
 
2676
  if not name:
2677
- return jsonify({'error': get_translation('flash_product_name_price_required')}), 400
2678
 
2679
- price_kgs_str = request.form.get('price_kgs', '').replace(',', '.')
2680
- if not price_kgs_str:
2681
- price_kgs = 0.0
2682
- else:
2683
- try:
2684
- price_kgs = round(float(price_kgs_str), 2)
2685
- if price_kgs < 0: price_kgs = 0.0
2686
- except ValueError:
2687
- return jsonify({'error': get_translation('flash_invalid_price_format')}), 400
2688
 
2689
  discount_percent_str = request.form.get('discount_percent', '0')
2690
  try:
2691
  discount_percent = int(discount_percent_str)
2692
  if not (0 <= discount_percent <= 100): discount_percent = 0
2693
- except (ValueError, TypeError):
2694
  discount_percent = 0
2695
 
2696
  description = request.form.get('description', '').strip()
@@ -2701,6 +2740,9 @@ def admin_api():
2701
  on_order = 'on_order' in request.form
2702
  is_top = 'is_top' in request.form
2703
 
 
 
 
2704
  photos_list = []
2705
  video_filename = None
2706
 
@@ -2769,24 +2811,25 @@ def admin_api():
2769
 
2770
  product_to_edit['name'] = request.form.get('name', product_to_edit['name']).strip()
2771
 
2772
- price_kgs_str = request.form.get('price_kgs', '').replace(',', '.')
2773
- if not price_kgs_str:
2774
- product_to_edit['price_kgs'] = 0.0
2775
- else:
 
 
2776
  try:
2777
  price_kgs = round(float(price_kgs_str), 2)
2778
- if price_kgs < 0: price_kgs = 0.0
2779
  product_to_edit['price_kgs'] = price_kgs
2780
- except ValueError:
2781
- pass
2782
 
2783
  discount_percent_str = request.form.get('discount_percent', str(product_to_edit.get('discount_percent',0)))
2784
  try:
2785
  discount_percent = int(discount_percent_str)
2786
  if not (0 <= discount_percent <= 100): discount_percent = product_to_edit.get('discount_percent', 0)
2787
  product_to_edit['discount_percent'] = discount_percent
2788
- except (ValueError, TypeError):
2789
- pass
2790
 
2791
  product_to_edit['description'] = request.form.get('description', product_to_edit.get('description', '')).strip()
2792
  product_to_edit['subcategory_id'] = request.form.get('subcategory_id') or None
 
100
  'error_page_title': 'Ошибка',
101
  'order_not_found_by_id': 'Заказ с таким ID не найден.',
102
  'whatsapp_greeting': 'Здравствуйте! Хочу подтвердить свой заказ на emir:',
103
+ 'whatsapp_product_inquiry': 'Здравствуйте! Хочу уточнить цену на товар: {product_name}',
104
  'whatsapp_order_number': 'Номер заказа:',
105
  'whatsapp_order_link': 'Ссылка на заказ:',
106
  'whatsapp_contact_request': 'Пожалуйста, свяжитесь со мной для уточнения деталей оплаты и доставки.',
 
206
  'flash_category_delete_success': "Категория '{category_name}' удалена.",
207
  'flash_category_delete_failed': "Не удалось удалить категорию '{category_name}'.",
208
  'flash_subcategory_added_success': "Подкатегория '{subcategory_name}' успешно добавлена.",
209
+ 'flash_subcategory_name_empty': 'Название подкатегодии не может быть пустым.',
210
  'flash_parent_category_not_selected': 'Необходимо выбрать родительскую категорию.',
211
  'flash_subcategory_already_exists': "Подкатегория '{subcategory_name}' уже существует в этой категории.",
212
  'flash_subcategory_delete_success': "Подкатегория '{subcategory_name}' удалена.",
213
+ 'flash_subcategory_delete_failed': "Не удалось удалить подкатегодию.",
214
  'flash_supplier_added_success': "Поставщик '{supplier_name}' успешно добавлен.",
215
  'flash_supplier_name_empty': 'Имя поставщика не может быть пустым.',
216
  'flash_supplier_already_exists': "Поставщик '{supplier_name}' уже существует.",
 
239
  'flash_failed_delete_hf_files_warning': "Не удалось удалить файлы для товара '{product_name}' с сервера. Товар удален локально.",
240
  'flash_hf_token_write_not_set_files_not_deleted_warning': "Товар '{product_name}' удален локально, но файлы не удалены с сервера (токен не задан).",
241
  'flash_product_deleted_success': "Товар '{product_name}' удален.",
242
+ 'flash_delete_error_not_found': "Ошибка удаления: товар с таким ID не найден.",
243
  'flash_unknown_action': 'Неизвестное действие: {action}',
244
  'flash_internal_error': "Произошла внутренняя ошибка при выполнении действия '{action}'. Подробности в логе сервера.",
245
  'flash_data_uploaded_hf_success': 'Данные успешно загружены на Hugging Face.',
 
256
  'flash_settings_updated': 'Настройки успешно обновлены.',
257
  'prices_disabled_notice_catalog': 'Цены временно не отображаются. Добавьте товары в корзину для запроса стоимости.',
258
  'prices_disabled_notice_cart': 'Цены не отображаются. Стоимость будет рассчитана после оформления заказа.',
259
+ 'request_price_calculation_button': 'Уточнить цену в WhatsApp',
260
  'price_on_request': 'Цена по запросу',
261
  'video_modal_title': 'Видео о товаре',
262
  'save_all_changes_button': 'Сохранить все изменения ({count})',
 
942
  <div class="product-price-container">
943
  {% set discount = product.get('discount_percent', 0) %}
944
  {% set original_price_kgs = product.price_kgs %}
945
+ {% if app_config.prices_enabled %}
946
  {% if discount > 0 %}
947
  {% set discounted_price_kgs = original_price_kgs * (100 - discount) / 100 %}
948
  <span class="original-price">{{ "%.2f"|format(original_price_kgs) }} {{ currency_code }}</span><br>
949
  <span class="product-price discounted">{{ "%.2f"|format(discounted_price_kgs) }} {{ currency_code }}</span>
950
  <span class="discount-badge">{{ get_translation('discount_badge_text', discount=discount) }}</span>
951
  {% else %}
952
+ {% if original_price_kgs > 0 %}
953
+ <span class="product-price">{{ "%.2f"|format(original_price_kgs) }} {{ currency_code }}</span>
954
+ {% else %}
955
+ <div class="product-price on-request">{{ get_translation('price_on_request') }}</div>
956
+ {% endif %}
957
  {% endif %}
958
  {% else %}
959
  <div class="product-price on-request">{{ get_translation('price_on_request') }}</div>
 
967
  <i class="fas fa-play-circle"></i> {{ get_translation('view_video_button') }}
968
  </button>
969
  {% endif %}
970
+
971
+ {% if app_config.prices_enabled %}
972
+ <button class="product-button add-to-cart" onclick="openQuantityModal({{ loop.index0 }})">
973
+ <i class="fas fa-cart-plus"></i> {{ get_translation('add_to_cart') }}
974
+ </button>
975
+ {% else %}
976
+ <button class="product-button add-to-cart" style="background-color: #25D366;" onclick="inquireProductWhatsApp({{ loop.index0 }})">
977
+ <i class="fab fa-whatsapp"></i> {{ get_translation('request_price_calculation_button') }}
978
+ </button>
979
+ {% endif %}
980
  </div>
981
  </div>
982
  </div>
 
1073
  return text;
1074
  }
1075
 
1076
+ function inquireProductWhatsApp(index) {
1077
+ const product = products[index];
1078
+ if (!product) return;
1079
+
1080
+ const phoneNumber = "996553303156";
1081
+
1082
+ const inquiryMessageTemplate = `{{ get_translation('whatsapp_product_inquiry', product_name='PLACEHOLDER_NAME') }}`;
1083
+ const inquiryMessage = encodeURIComponent(
1084
+ inquiryMessageTemplate.replace('PLACEHOLDER_NAME', product.name)
1085
+ );
1086
+
1087
+ const whatsappUrl = `https://wa.me/${phoneNumber}?text=${inquiryMessage}`;
1088
+ window.open(whatsappUrl, '_blank');
1089
+ }
1090
+
1091
  function openModal(index) {
1092
  loadProductDetails(index);
1093
  const modal = document.getElementById('productModal');
 
1229
  if (product.discount_percent && product.discount_percent > 0) {
1230
  priceToAdd = product.price_kgs * (100 - product.discount_percent) / 100;
1231
  }
1232
+
1233
+ // If price is 0 (optional price field not set by admin) but prices are enabled in config, we still use 0.
1234
+ if (!pricesEnabled && priceToAdd === 0) {
1235
+ // If prices are disabled, we treat the price as irrelevant for calculation here, but we save 0 to the cart item if not set.
1236
+ }
1237
+
1238
 
1239
  if (existingItemIndex > -1) {
1240
  cart[existingItemIndex].quantity += quantity;
 
1573
 
1574
  {% set discount = product_info.get('discount_percent', 0) %}
1575
  {% set original_price_kgs = product_info.price_kgs %}
1576
+ {% if app_config.prices_enabled %}
1577
  <div style="margin: 20px 0; padding: 15px; background: var(--bg-steel-mid); border-radius: 8px;">
1578
  <strong style="font-size: 1.1rem; color: var(--text-light);">{{ get_translation('price') }}</strong>
1579
  {% if discount > 0 %}
 
1581
  <span style="font-size: 1.8rem; font-weight: 700; color: var(--accent-red); margin-left: 10px;">{{ "%.2f"|format(discounted_price_kgs) }} {{ currency_code }}</span>
1582
  <span style="text-decoration: line-through; color: var(--text-steel); font-size: 1.2rem; margin-left: 15px;">{{ "%.2f"|format(original_price_kgs) }} {{ currency_code }}</span>
1583
  {% else %}
1584
+ {% if original_price_kgs > 0 %}
1585
+ <span style="font-size: 1.8rem; font-weight: 700; color: var(--text-light); margin-left: 10px;">{{ "%.2f"|format(original_price_kgs) }} {{ currency_code }}</span>
1586
+ {% else %}
1587
+ <span style="font-size: 1.2rem; font-weight: bold; color: var(--text-steel); margin-left: 10px;">{{ get_translation('price_on_request') }}</span>
1588
+ {% endif %}
1589
  {% endif %}
1590
  </div>
1591
  {% else %}
 
1661
  <img src="{{ item.photo_url }}" alt="{{ item.name }}" {% if not item.photo %}style="opacity: 0.5;"{% endif %}>
1662
  <div class="item-details">
1663
  <strong>{{ item.name }} {% if item.color != 'N/A' %}({{ item.color }}){% endif %}</strong>
1664
+ {% if order.prices_were_enabled_at_order and item.price_kgs_at_order > 0 %}
1665
  <span>{{ "%.2f"|format(item.price_kgs_at_order) }} {{ currency_code }} × {{ item.quantity }}</span>
1666
  {% else %}
1667
  <span>{{ get_translation('quantity') }} {{ item.quantity }}</span>
1668
  {% endif %}
1669
  </div>
1670
+ {% if order.prices_were_enabled_at_order and item.price_kgs_at_order > 0 %}
1671
  <div class="item-total">
1672
  {{ "%.2f"|format(item.price_kgs_at_order * item.quantity) }} {{ currency_code }}
1673
  </div>
 
1680
  {% endfor %}
1681
  </div>
1682
 
1683
+ {% if order.prices_were_enabled_at_order and order.total_price_kgs > 0 %}
1684
  <div class="order-summary">
1685
  <p>{{ get_translation('total_products_sum') }} <strong>{{ "%.2f"|format(order.total_price_kgs) }} {{ currency_code }}</strong></p>
1686
  </div>
 
1713
  message += `*{{ get_translation('whatsapp_order_number') | replace("'", "\\'") }}* ${orderId}` + "%0A";
1714
  message += `*{{ get_translation('whatsapp_order_link') | replace("'", "\\'") }}* ${encodedOrderUrl}` + "%0A%0A";
1715
 
1716
+ {% if not order.prices_were_enabled_at_order or order.total_price_kgs == 0 %}
1717
  message += `{{ get_translation('whatsapp_request_price_calculation') | replace("'", "\\'") }}` + "%0A%0A";
1718
  {% endif %}
1719
 
 
1842
  <h2><i class="fas fa-cog"></i> {{ get_translation('admin_settings_title') }}</h2>
1843
  <form method="POST" action="{{ url_for('admin_actions') }}">
1844
  <input type="hidden" name="action" value="update_settings">
1845
+ <label>{{ get_translation('admin_prices_visibility_label') }}</label>
1846
  <div style="margin-top: 15px;">
1847
  <input type="checkbox" id="prices_enabled" name="prices_enabled" {% if app_config.prices_enabled %}checked{% endif %}>
1848
  <label for="prices_enabled" class="inline-label">{{ get_translation('admin_prices_enabled_checkbox_label') }}</label>
 
2077
  <p><strong>{{ get_translation('supplier') }}:</strong> {{ product_info.supplier_name }}</p>
2078
  <p><strong>{{ get_translation('category') }}:</strong> {{ product_info.category_name }}</p>
2079
  <p><strong>{{ get_translation('subcategory') }}:</strong> {{ product_info.subcategory_name }}</p>
2080
+ <p><strong>{{ get_translation('price') }}:</strong> {% if product_info.price_kgs > 0 %} {{ "%.2f"|format(product_info.price_kgs) }} {{ currency_code }} {% else %} {{ get_translation('price_on_request') }} {% endif %}</p>
2081
  {% if product_info.get('discount_percent', 0) > 0 %}
2082
  <p><strong class="discount-info">{{ get_translation('discount_label_item') }} {{ product_info.discount_percent }}%</strong></p>
2083
  {% endif %}
 
2576
  price_kgs_in_cart = float(item['price_kgs'])
2577
  original_price_kgs = float(item.get('original_price_kgs', price_kgs_in_cart))
2578
  quantity = int(item['quantity'])
2579
+ if quantity <= 0:
2580
+ raise ValueError("Invalid quantity")
2581
+
2582
+ # If prices are enabled OR the price is positive, calculate total
2583
+ if prices_currently_enabled and price_kgs_in_cart > 0:
2584
  total_price_kgs += price_kgs_in_cart * quantity
2585
 
2586
  processed_cart.append({
 
2712
  try:
2713
  if action == 'add_product':
2714
  name = request.form.get('name', '').strip()
2715
+
2716
  if not name:
2717
+ return jsonify({'error': get_translation('flash_product_name_price_required')}), 400
2718
 
2719
+ price_kgs_str = request.form.get('price_kgs', '0').replace(',', '.')
2720
+ if not price_kgs_str.strip(): price_kgs_str = '0'
2721
+
2722
+ try:
2723
+ price_kgs = round(float(price_kgs_str), 2)
2724
+ if price_kgs < 0: price_kgs = 0
2725
+ except ValueError:
2726
+ return jsonify({'error': get_translation('flash_invalid_price_format')}), 400
 
2727
 
2728
  discount_percent_str = request.form.get('discount_percent', '0')
2729
  try:
2730
  discount_percent = int(discount_percent_str)
2731
  if not (0 <= discount_percent <= 100): discount_percent = 0
2732
+ except ValueError:
2733
  discount_percent = 0
2734
 
2735
  description = request.form.get('description', '').strip()
 
2740
  on_order = 'on_order' in request.form
2741
  is_top = 'is_top' in request.form
2742
 
2743
+ if in_stock and on_order: # Ensure mutual exclusion
2744
+ on_order = False
2745
+
2746
  photos_list = []
2747
  video_filename = None
2748
 
 
2811
 
2812
  product_to_edit['name'] = request.form.get('name', product_to_edit['name']).strip()
2813
 
2814
+ price_kgs_str = request.form.get('price_kgs')
2815
+
2816
+ if price_kgs_str is not None:
2817
+ price_kgs_str = price_kgs_str.replace(',', '.')
2818
+ if not price_kgs_str.strip(): price_kgs_str = '0'
2819
+
2820
  try:
2821
  price_kgs = round(float(price_kgs_str), 2)
2822
+ if price_kgs < 0: price_kgs = 0
2823
  product_to_edit['price_kgs'] = price_kgs
2824
+ except ValueError:
2825
+ logging.warning(get_translation('flash_invalid_price_format_edit_warning', product_name=product_to_edit['name']))
2826
 
2827
  discount_percent_str = request.form.get('discount_percent', str(product_to_edit.get('discount_percent',0)))
2828
  try:
2829
  discount_percent = int(discount_percent_str)
2830
  if not (0 <= discount_percent <= 100): discount_percent = product_to_edit.get('discount_percent', 0)
2831
  product_to_edit['discount_percent'] = discount_percent
2832
+ except ValueError: pass
 
2833
 
2834
  product_to_edit['description'] = request.form.get('description', product_to_edit.get('description', '')).strip()
2835
  product_to_edit['subcategory_id'] = request.form.get('subcategory_id') or None