Kgshop commited on
Commit
9bfdf79
·
verified ·
1 Parent(s): cc0bbcd

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +115 -4
app.py CHANGED
@@ -1,6 +1,4 @@
1
 
2
-
3
-
4
  from flask import Flask, render_template_string, request, redirect, url_for, send_file, flash, jsonify
5
  import json
6
  import os
@@ -24,7 +22,7 @@ DATA_FILE = 'data.json'
24
 
25
  SYNC_FILES = [DATA_FILE]
26
 
27
- REPO_ID = "Kgshop/Mobilmir" # Assuming the Hugging Face repo ID remains the same for dataset storage
28
  HF_TOKEN_WRITE = os.getenv("HF_TOKEN")
29
  HF_TOKEN_READ = os.getenv("HF_TOKEN_READ")
30
 
@@ -36,6 +34,13 @@ CURRENCY_NAME = 'Казахстанский тенге'
36
  DOWNLOAD_RETRIES = 3
37
  DOWNLOAD_DELAY = 5
38
 
 
 
 
 
 
 
 
39
  logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
40
 
41
 
@@ -1020,6 +1025,23 @@ ADMIN_TEMPLATE = '''
1020
  .status-indicator.in-stock { background-color: #c6f6d5; color: #2f855a; }
1021
  .status-indicator.out-of-stock { background-color: #fed7d7; color: #c53030; }
1022
  .status-indicator.top-product { background-color: #feebc8; color: #9c4221; margin-left: 5px;}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1023
  </style>
1024
  </head>
1025
  <body>
@@ -1054,6 +1076,68 @@ ADMIN_TEMPLATE = '''
1054
  <p style="font-size: 0.85rem; color: #a0aec0;">Резервное копирование происходит автоматически каждые 30 минут, а также после каждого сохранения данных. Используйте эти кнопки для немедленной синхронизации.</p>
1055
  </div>
1056
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1057
  <div class="flex-container">
1058
  <div class="flex-item">
1059
  <div class="section">
@@ -1431,6 +1515,7 @@ def admin():
1431
  data = load_data()
1432
  products = data.get('products', [])
1433
  categories = data.get('categories', [])
 
1434
 
1435
  needs_save = False
1436
  for product in products:
@@ -1451,7 +1536,30 @@ def admin():
1451
  logging.info(f"Admin action received: {action}")
1452
 
1453
  try:
1454
- if action == 'add_category':
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1455
  category_name = request.form.get('category_name', '').strip()
1456
  if category_name and category_name not in categories:
1457
  categories.append(category_name)
@@ -1744,11 +1852,14 @@ def admin():
1744
  current_data = load_data()
1745
  display_products = sorted(current_data.get('products', []), key=lambda p: p.get('name', '').lower())
1746
  display_categories = sorted(current_data.get('categories', []))
 
1747
 
1748
  return render_template_string(
1749
  ADMIN_TEMPLATE,
1750
  products=display_products,
1751
  categories=display_categories,
 
 
1752
  repo_id=REPO_ID,
1753
  currency_code=CURRENCY_CODE
1754
  )
 
1
 
 
 
2
  from flask import Flask, render_template_string, request, redirect, url_for, send_file, flash, jsonify
3
  import json
4
  import os
 
22
 
23
  SYNC_FILES = [DATA_FILE]
24
 
25
+ REPO_ID = "Kgshop/Mobilmir"
26
  HF_TOKEN_WRITE = os.getenv("HF_TOKEN")
27
  HF_TOKEN_READ = os.getenv("HF_TOKEN_READ")
28
 
 
34
  DOWNLOAD_RETRIES = 3
35
  DOWNLOAD_DELAY = 5
36
 
37
+ STATUS_MAP_RU = {
38
+ "new": "Новый",
39
+ "accepted": "Принят",
40
+ "prepared": "Собран",
41
+ "shipped": "Отправлен"
42
+ }
43
+
44
  logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
45
 
46
 
 
1025
  .status-indicator.in-stock { background-color: #c6f6d5; color: #2f855a; }
1026
  .status-indicator.out-of-stock { background-color: #fed7d7; color: #c53030; }
1027
  .status-indicator.top-product { background-color: #feebc8; color: #9c4221; margin-left: 5px;}
1028
+
1029
+ /* Order Specific Status Styles */
1030
+ .status-indicator.new { background-color: #fefcbf; color: #744210; }
1031
+ .status-indicator.accepted { background-color: #b3e5fc; color: #0277bd; }
1032
+ .status-indicator.prepared { background-color: #c6f6d5; color: #2f855a; }
1033
+ .status-indicator.shipped { background-color: #a7f3d0; color: #065f46; }
1034
+
1035
+ .order-details-content { padding: 10px 0 0 0; }
1036
+ .order-item-detail { display: flex; gap: 15px; padding: 8px 0; border-top: 1px dashed #E0E7FF; font-size: 0.9rem; align-items: center; }
1037
+ .order-item-detail:first-child { border-top: none; }
1038
+ .order-item-detail img { width: 40px; height: 40px; object-fit: contain; border-radius: 4px; }
1039
+ .order-item-name { flex-grow: 1; }
1040
+ .order-item-qty-price { width: 150px; text-align: right; flex-shrink: 0; }
1041
+ .order-total-summary { font-size: 1.1rem; font-weight: 600; margin-top: 15px; padding-top: 10px; border-top: 1px solid #4F46E5; text-align: right; }
1042
+ .order-status-form { display: flex; gap: 10px; align-items: center; margin-top: 15px; padding-top: 15px; border-top: 1px dashed #E0E7FF; flex-wrap: wrap; }
1043
+ .order-status-form select { max-width: 200px; margin-top: 0; flex-grow: 1;}
1044
+ .order-status-form .button { margin-top: 0; flex-grow: 0; }
1045
  </style>
1046
  </head>
1047
  <body>
 
1076
  <p style="font-size: 0.85rem; color: #a0aec0;">Резервное копирование происходит автоматически каждые 30 минут, а также после каждого сохранения данных. Используйте эти кнопки для немедленной синхронизации.</p>
1077
  </div>
1078
 
1079
+ <div class="section">
1080
+ <h2><i class="fas fa-history"></i> История заказов (Предполагается Алматинское время)</h2>
1081
+
1082
+ {% if orders %}
1083
+ {% set sorted_orders = orders | sort(attribute='created_at', reverse=true) %}
1084
+ {% for order in sorted_orders %}
1085
+ {% set current_status = order.get('status', 'new') %}
1086
+ {% set total_items = order.cart | sum(attribute='quantity') %}
1087
+ <details style="margin-bottom: 10px;">
1088
+ <summary style="display: flex; justify-content: space-between; align-items: center; padding: 15px 20px;">
1089
+ <span>
1090
+ Заказ №{{ order.id }}
1091
+ <span class="status-indicator {{ current_status }}">{{ status_map_ru.get(current_status, current_status) }}</span>
1092
+ </span>
1093
+ <span style="font-size: 0.9rem; color: #4d333f; flex-shrink: 0;">
1094
+ Дата: {{ order.created_at }} | Итого: {{ "%.2f"|format(order.total_price) }} {{ currency_code }} ({{ total_items }} шт.)
1095
+ </span>
1096
+ </summary>
1097
+ <div class="form-content">
1098
+ <h3>Состав заказа:</h3>
1099
+ <div class="order-details-content">
1100
+ {% for item in order.cart %}
1101
+ {% set item_price = item.price * item.quantity %}
1102
+ <div class="order-item-detail">
1103
+ <img src="{{ item.photo_url }}" alt="{{ item.name }}">
1104
+ <div class="order-item-name">
1105
+ <strong>{{ item.name }}</strong>
1106
+ {% if item.color != 'N/A' %}<p style="margin: 0; color: #a0aec0;">Цвет: {{ item.color }}</p>{% endif %}
1107
+ </div>
1108
+ <div class="order-item-qty-price">
1109
+ {{ item.quantity }} × {{ "%.2f"|format(item.price) }} {{ currency_code }} = <strong>{{ "%.2f"|format(item_price) }} {{ currency_code }}</strong>
1110
+ </div>
1111
+ </div>
1112
+ {% endfor %}
1113
+ </div>
1114
+ <div class="order-total-summary">
1115
+ Общая сумма: {{ "%.2f"|format(order.total_price) }} {{ currency_code }}
1116
+ </div>
1117
+
1118
+ <div class="order-status-form">
1119
+ <form method="POST" style="display: flex; gap: 10px; width: 100%; align-items: center; flex-wrap: wrap;">
1120
+ <input type="hidden" name="action" value="update_order_status">
1121
+ <input type="hidden" name="order_id" value="{{ order.id }}">
1122
+ <label for="status_{{ order.id }}" style="margin: 0; display: inline; font-size: 0.9rem;">Изменить статус:</label>
1123
+ <select name="new_status" id="status_{{ order.id }}" style="max-width: 200px; margin: 0;">
1124
+ {% for status_key, status_value in status_map_ru.items() %}
1125
+ <option value="{{ status_key }}" {% if current_status == status_key %}selected{% endif %}>{{ status_value }}</option>
1126
+ {% endfor %}
1127
+ </select>
1128
+ <button type="submit" class="button"><i class="fas fa-check"></i> Сохранить</button>
1129
+ <a href="{{ url_for('view_order', order_id=order.id) }}" target="_blank" class="button" style="background-color: #6366F1;"><i class="fas fa-eye"></i> Просмотр</a>
1130
+ </form>
1131
+ </div>
1132
+ </div>
1133
+ </details>
1134
+ {% endfor %}
1135
+ {% else %}
1136
+ <p>Активных заказов нет.</p>
1137
+ {% endif %}
1138
+ </div>
1139
+
1140
+
1141
  <div class="flex-container">
1142
  <div class="flex-item">
1143
  <div class="section">
 
1515
  data = load_data()
1516
  products = data.get('products', [])
1517
  categories = data.get('categories', [])
1518
+ orders = data.get('orders', {})
1519
 
1520
  needs_save = False
1521
  for product in products:
 
1536
  logging.info(f"Admin action received: {action}")
1537
 
1538
  try:
1539
+ if action == 'update_order_status':
1540
+ order_id = request.form.get('order_id')
1541
+ new_status = request.form.get('new_status')
1542
+
1543
+ if order_id in data['orders']:
1544
+ order = data['orders'][order_id]
1545
+ valid_statuses = list(STATUS_MAP_RU.keys())
1546
+
1547
+ if new_status in valid_statuses:
1548
+ old_status_key = order.get('status', 'new')
1549
+
1550
+ order['status'] = new_status
1551
+ data['orders'][order_id] = order
1552
+ save_data(data)
1553
+ logging.info(f"Order {order_id} status updated from {old_status_key} to {new_status}")
1554
+ flash(f"Статус заказа №{order_id} успешно изменен на '{STATUS_MAP_RU.get(new_status)}'.", 'success')
1555
+ else:
1556
+ flash(f"Неверный статус: {new_status}", 'error')
1557
+ else:
1558
+ flash(f"Заказ №{order_id} не найден.", 'error')
1559
+
1560
+ return redirect(url_for('admin'))
1561
+
1562
+ elif action == 'add_category':
1563
  category_name = request.form.get('category_name', '').strip()
1564
  if category_name and category_name not in categories:
1565
  categories.append(category_name)
 
1852
  current_data = load_data()
1853
  display_products = sorted(current_data.get('products', []), key=lambda p: p.get('name', '').lower())
1854
  display_categories = sorted(current_data.get('categories', []))
1855
+ display_orders = list(current_data.get('orders', {}).values())
1856
 
1857
  return render_template_string(
1858
  ADMIN_TEMPLATE,
1859
  products=display_products,
1860
  categories=display_categories,
1861
+ orders=display_orders,
1862
+ status_map_ru=STATUS_MAP_RU,
1863
  repo_id=REPO_ID,
1864
  currency_code=CURRENCY_CODE
1865
  )