Update app.py
Browse files
app.py
CHANGED
|
@@ -780,10 +780,13 @@ ORDER_TEMPLATE = '''
|
|
| 780 |
</tr>
|
| 781 |
</thead>
|
| 782 |
<tbody>
|
|
|
|
| 783 |
{% for item in order.cart %}
|
| 784 |
{% set ppb = item.pieces_per_box|default(1)|int %}
|
| 785 |
{% set boxes = item.quantity // ppb %}
|
| 786 |
{% set remainder = item.quantity % ppb %}
|
|
|
|
|
|
|
| 787 |
<tr>
|
| 788 |
<td>{{ loop.index }}</td>
|
| 789 |
<td style="text-align: left; font-weight: 500;">{{ item.name }}</td>
|
|
@@ -817,12 +820,24 @@ ORDER_TEMPLATE = '''
|
|
| 817 |
</div>
|
| 818 |
</td>
|
| 819 |
<td>{{ item.price }}</td>
|
| 820 |
-
<td>{{
|
| 821 |
</tr>
|
| 822 |
{% endfor %}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 823 |
<tr class="total-row">
|
| 824 |
-
<td colspan="5" style="text-align: right; padding-right: 20px;">
|
| 825 |
-
<td>{{ order.total_price }} {{ currency_code }}</td>
|
| 826 |
</tr>
|
| 827 |
</tbody>
|
| 828 |
</table>
|
|
@@ -963,6 +978,11 @@ ADMIN_TEMPLATE = '''
|
|
| 963 |
|
| 964 |
.file-input-wrapper { position: relative; width: 100%; }
|
| 965 |
input[type="file"] { width: 100%; padding: 10px; border: 1px dashed #ccc; border-radius: 10px; background: #fafafa; font-size: 0.9rem; }
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 966 |
|
| 967 |
@media (max-width: 600px) {
|
| 968 |
.header-panel { flex-direction: column; align-items: stretch; text-align: center; }
|
|
@@ -989,6 +1009,52 @@ ADMIN_TEMPLATE = '''
|
|
| 989 |
</form>
|
| 990 |
</div>
|
| 991 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 992 |
<div class="card">
|
| 993 |
<h2>Управление категориями</h2>
|
| 994 |
<form method="POST" class="add-cat-form">
|
|
@@ -1210,6 +1276,7 @@ def create_order():
|
|
| 1210 |
"id": order_id,
|
| 1211 |
"created_at": datetime.now().strftime('%Y-%m-%d %H:%M:%S'),
|
| 1212 |
"cart": processed_cart,
|
|
|
|
| 1213 |
"total_price": total_price,
|
| 1214 |
"customer_name": customer_name,
|
| 1215 |
"customer_phone": customer_phone,
|
|
@@ -1264,7 +1331,9 @@ def edit_order(order_id):
|
|
| 1264 |
order['cart'].remove(item)
|
| 1265 |
break
|
| 1266 |
|
| 1267 |
-
|
|
|
|
|
|
|
| 1268 |
save_data(data)
|
| 1269 |
|
| 1270 |
return jsonify({"success": True, "total_price": order['total_price']})
|
|
@@ -1274,11 +1343,23 @@ def admin():
|
|
| 1274 |
data = load_data()
|
| 1275 |
products = data.get('products', [])
|
| 1276 |
categories = data.get('categories', [])
|
|
|
|
| 1277 |
|
| 1278 |
if request.method == 'POST':
|
| 1279 |
action = request.form.get('action')
|
| 1280 |
|
| 1281 |
-
if action == '
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1282 |
cat_name = request.form.get('category_name', '').strip()
|
| 1283 |
if cat_name and cat_name not in categories:
|
| 1284 |
categories.append(cat_name)
|
|
@@ -1401,6 +1482,7 @@ def admin():
|
|
| 1401 |
ADMIN_TEMPLATE,
|
| 1402 |
products=products,
|
| 1403 |
categories=categories,
|
|
|
|
| 1404 |
repo_id=REPO_ID,
|
| 1405 |
currency_code=CURRENCY_CODE
|
| 1406 |
)
|
|
@@ -1423,4 +1505,4 @@ if __name__ == '__main__':
|
|
| 1423 |
threading.Thread(target=periodic_backup, daemon=True).start()
|
| 1424 |
|
| 1425 |
port = int(os.environ.get('PORT', 7860))
|
| 1426 |
-
app.run(host='0.0.0.0', port=port)
|
|
|
|
| 780 |
</tr>
|
| 781 |
</thead>
|
| 782 |
<tbody>
|
| 783 |
+
{% set raw_total = 0 %}
|
| 784 |
{% for item in order.cart %}
|
| 785 |
{% set ppb = item.pieces_per_box|default(1)|int %}
|
| 786 |
{% set boxes = item.quantity // ppb %}
|
| 787 |
{% set remainder = item.quantity % ppb %}
|
| 788 |
+
{% set item_sum = item.price * item.quantity %}
|
| 789 |
+
{% set raw_total = raw_total + item_sum %}
|
| 790 |
<tr>
|
| 791 |
<td>{{ loop.index }}</td>
|
| 792 |
<td style="text-align: left; font-weight: 500;">{{ item.name }}</td>
|
|
|
|
| 820 |
</div>
|
| 821 |
</td>
|
| 822 |
<td>{{ item.price }}</td>
|
| 823 |
+
<td>{{ item_sum }}</td>
|
| 824 |
</tr>
|
| 825 |
{% endfor %}
|
| 826 |
+
|
| 827 |
+
{% set discount = order.discount|default(0)|float %}
|
| 828 |
+
{% if discount > 0 %}
|
| 829 |
+
<tr class="total-row" style="background:transparent;">
|
| 830 |
+
<td colspan="5" style="text-align: right; padding-right: 20px; font-weight:600; color:#636e72;">Сумма:</td>
|
| 831 |
+
<td style="font-weight:600; color:#636e72;">{{ raw_total }} {{ currency_code }}</td>
|
| 832 |
+
</tr>
|
| 833 |
+
<tr class="total-row" style="background:transparent;">
|
| 834 |
+
<td colspan="5" style="text-align: right; padding-right: 20px; font-weight:600; color:#ff7675;">Скидка:</td>
|
| 835 |
+
<td style="font-weight:600; color:#ff7675;">-{{ discount }} {{ currency_code }}</td>
|
| 836 |
+
</tr>
|
| 837 |
+
{% endif %}
|
| 838 |
<tr class="total-row">
|
| 839 |
+
<td colspan="5" style="text-align: right; padding-right: 20px;">К оплате:</td>
|
| 840 |
+
<td style="color:var(--wa);">{{ order.total_price }} {{ currency_code }}</td>
|
| 841 |
</tr>
|
| 842 |
</tbody>
|
| 843 |
</table>
|
|
|
|
| 978 |
|
| 979 |
.file-input-wrapper { position: relative; width: 100%; }
|
| 980 |
input[type="file"] { width: 100%; padding: 10px; border: 1px dashed #ccc; border-radius: 10px; background: #fafafa; font-size: 0.9rem; }
|
| 981 |
+
|
| 982 |
+
.orders-table { width: 100%; border-collapse: collapse; min-width: 800px; text-align: left; }
|
| 983 |
+
.orders-table th { padding: 12px; background: #fafafa; border-bottom: 2px solid var(--border); color: #636e72; font-size: 0.85rem; text-transform: uppercase; }
|
| 984 |
+
.orders-table td { padding: 12px; border-bottom: 1px solid var(--border); vertical-align: middle; }
|
| 985 |
+
.orders-table tr:hover { background: #fafafa; }
|
| 986 |
|
| 987 |
@media (max-width: 600px) {
|
| 988 |
.header-panel { flex-direction: column; align-items: stretch; text-align: center; }
|
|
|
|
| 1009 |
</form>
|
| 1010 |
</div>
|
| 1011 |
|
| 1012 |
+
<div class="card">
|
| 1013 |
+
<h2><i class="fas fa-file-invoice-dollar"></i> История накладных</h2>
|
| 1014 |
+
<div style="overflow-x: auto;">
|
| 1015 |
+
<table class="orders-table">
|
| 1016 |
+
<tr>
|
| 1017 |
+
<th>ID / Дата</th>
|
| 1018 |
+
<th>Клиент</th>
|
| 1019 |
+
<th>Сумма</th>
|
| 1020 |
+
<th>Скидка</th>
|
| 1021 |
+
<th>К оплате</th>
|
| 1022 |
+
<th>Действия</th>
|
| 1023 |
+
</tr>
|
| 1024 |
+
{% for order in orders.values()|sort(attribute='created_at', reverse=True) %}
|
| 1025 |
+
{% set raw_total = 0 %}
|
| 1026 |
+
{% for item in order.cart %}
|
| 1027 |
+
{% set raw_total = raw_total + (item.price|float * item.quantity|int) %}
|
| 1028 |
+
{% endfor %}
|
| 1029 |
+
<tr>
|
| 1030 |
+
<td>
|
| 1031 |
+
<a href="/order/{{ order.id }}" target="_blank" style="color:var(--info); font-weight:bold; text-decoration:none;">{{ order.id }}</a><br>
|
| 1032 |
+
<span style="font-size:0.8rem; color:#636e72;">{{ order.created_at }}</span>
|
| 1033 |
+
</td>
|
| 1034 |
+
<td style="font-size:0.9rem;">
|
| 1035 |
+
{{ order.customer_name }}<br>
|
| 1036 |
+
<i class="fas fa-phone" style="font-size:0.7rem; color:#999;"></i> {{ order.customer_phone }}<br>
|
| 1037 |
+
<i class="fas fa-map-marker-alt" style="font-size:0.7rem; color:#999;"></i> {{ order.customer_city }}
|
| 1038 |
+
</td>
|
| 1039 |
+
<td style="font-weight:600;">{{ raw_total }} {{ currency_code }}</td>
|
| 1040 |
+
<td>
|
| 1041 |
+
<form method="POST" style="display:flex; gap:5px; margin:0; align-items:center;">
|
| 1042 |
+
<input type="hidden" name="action" value="apply_discount">
|
| 1043 |
+
<input type="hidden" name="order_id" value="{{ order.id }}">
|
| 1044 |
+
<input type="number" name="discount_amount" value="{{ order.discount|default(0) }}" min="0" step="0.01" style="width:80px; padding:6px; font-size:0.9rem;">
|
| 1045 |
+
<button type="submit" class="btn btn-warning" style="padding:6px 10px;" title="Применить скидку"><i class="fas fa-check"></i></button>
|
| 1046 |
+
</form>
|
| 1047 |
+
</td>
|
| 1048 |
+
<td style="font-weight:800; color:var(--success);">{{ order.total_price }} {{ currency_code }}</td>
|
| 1049 |
+
<td>
|
| 1050 |
+
<a href="/order/{{ order.id }}" class="btn btn-primary" style="padding:6px 10px;" target="_blank"><i class="fas fa-eye"></i></a>
|
| 1051 |
+
</td>
|
| 1052 |
+
</tr>
|
| 1053 |
+
{% endfor %}
|
| 1054 |
+
</table>
|
| 1055 |
+
</div>
|
| 1056 |
+
</div>
|
| 1057 |
+
|
| 1058 |
<div class="card">
|
| 1059 |
<h2>Управление категориями</h2>
|
| 1060 |
<form method="POST" class="add-cat-form">
|
|
|
|
| 1276 |
"id": order_id,
|
| 1277 |
"created_at": datetime.now().strftime('%Y-%m-%d %H:%M:%S'),
|
| 1278 |
"cart": processed_cart,
|
| 1279 |
+
"discount": 0,
|
| 1280 |
"total_price": total_price,
|
| 1281 |
"customer_name": customer_name,
|
| 1282 |
"customer_phone": customer_phone,
|
|
|
|
| 1331 |
order['cart'].remove(item)
|
| 1332 |
break
|
| 1333 |
|
| 1334 |
+
cart_total = sum(float(i['price']) * int(i['quantity']) for i in order['cart'])
|
| 1335 |
+
discount = order.get('discount', 0)
|
| 1336 |
+
order['total_price'] = max(0, cart_total - discount)
|
| 1337 |
save_data(data)
|
| 1338 |
|
| 1339 |
return jsonify({"success": True, "total_price": order['total_price']})
|
|
|
|
| 1343 |
data = load_data()
|
| 1344 |
products = data.get('products', [])
|
| 1345 |
categories = data.get('categories', [])
|
| 1346 |
+
orders = data.get('orders', {})
|
| 1347 |
|
| 1348 |
if request.method == 'POST':
|
| 1349 |
action = request.form.get('action')
|
| 1350 |
|
| 1351 |
+
if action == 'apply_discount':
|
| 1352 |
+
order_id = request.form.get('order_id')
|
| 1353 |
+
discount_val = float(request.form.get('discount_amount', 0))
|
| 1354 |
+
if order_id in orders:
|
| 1355 |
+
order = orders[order_id]
|
| 1356 |
+
order['discount'] = discount_val
|
| 1357 |
+
cart_total = sum(float(i['price']) * int(i['quantity']) for i in order['cart'])
|
| 1358 |
+
order['total_price'] = max(0, cart_total - discount_val)
|
| 1359 |
+
data['orders'] = orders
|
| 1360 |
+
save_data(data)
|
| 1361 |
+
|
| 1362 |
+
elif action == 'add_category':
|
| 1363 |
cat_name = request.form.get('category_name', '').strip()
|
| 1364 |
if cat_name and cat_name not in categories:
|
| 1365 |
categories.append(cat_name)
|
|
|
|
| 1482 |
ADMIN_TEMPLATE,
|
| 1483 |
products=products,
|
| 1484 |
categories=categories,
|
| 1485 |
+
orders=orders,
|
| 1486 |
repo_id=REPO_ID,
|
| 1487 |
currency_code=CURRENCY_CODE
|
| 1488 |
)
|
|
|
|
| 1505 |
threading.Thread(target=periodic_backup, daemon=True).start()
|
| 1506 |
|
| 1507 |
port = int(os.environ.get('PORT', 7860))
|
| 1508 |
+
app.run(host='0.0.0.0', port=port)
|