Update app.py
Browse files
app.py
CHANGED
|
@@ -4,15 +4,16 @@ import os
|
|
| 4 |
import logging
|
| 5 |
import threading
|
| 6 |
import time
|
|
|
|
| 7 |
from datetime import datetime
|
| 8 |
from huggingface_hub import HfApi, hf_hub_download
|
| 9 |
from huggingface_hub.utils import RepositoryNotFoundError
|
| 10 |
from werkzeug.utils import secure_filename
|
| 11 |
|
| 12 |
app = Flask(__name__)
|
| 13 |
-
app.secret_key = 'your_unique_secret_key_12345' #
|
| 14 |
DATA_FILE = 'data_detobuv.json'
|
| 15 |
-
USERS_FILE = '
|
| 16 |
|
| 17 |
# Настройки Hugging Face
|
| 18 |
REPO_ID = "Kgshop/clients"
|
|
@@ -22,9 +23,51 @@ HF_TOKEN_READ = os.getenv("HF_TOKEN_READ")
|
|
| 22 |
# Адрес магазина
|
| 23 |
STORE_ADDRESS = "Бишкек, Рынок Дордой, 9 ряд, 06 контейнер"
|
| 24 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 25 |
# Настройка логирования
|
| 26 |
logging.basicConfig(level=logging.DEBUG)
|
| 27 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 28 |
def load_data():
|
| 29 |
try:
|
| 30 |
download_db_from_hf()
|
|
@@ -114,7 +157,9 @@ def catalog():
|
|
| 114 |
products = data['products']
|
| 115 |
categories = data['categories']
|
| 116 |
is_authenticated = 'user' in session
|
| 117 |
-
|
|
|
|
|
|
|
| 118 |
catalog_html = '''
|
| 119 |
<!DOCTYPE html>
|
| 120 |
<html lang="ru">
|
|
@@ -428,6 +473,12 @@ def catalog():
|
|
| 428 |
font-style: italic;
|
| 429 |
color: #666;
|
| 430 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 431 |
</style>
|
| 432 |
</head>
|
| 433 |
<body>
|
|
@@ -437,6 +488,13 @@ def catalog():
|
|
| 437 |
<div class="auth-links">
|
| 438 |
{% if is_authenticated %}
|
| 439 |
<span>Добро пожаловать, {{ session['user'] }}!</span>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 440 |
<a href="{{ url_for('logout') }}">Выйти</a>
|
| 441 |
{% else %}
|
| 442 |
<a href="{{ url_for('login') }}">Войти</a>
|
|
@@ -472,7 +530,7 @@ def catalog():
|
|
| 472 |
{% endif %}
|
| 473 |
<h2>{{ product['name'] }}</h2>
|
| 474 |
{% if is_authenticated %}
|
| 475 |
-
<div class="product-price">{{ product['price'] }}
|
| 476 |
{% else %}
|
| 477 |
<div class="product-price">Цена доступна после входа</div>
|
| 478 |
{% endif %}
|
|
@@ -512,7 +570,7 @@ def catalog():
|
|
| 512 |
<h2>Корзина</h2>
|
| 513 |
<div id="cartContent"></div>
|
| 514 |
<div style="margin-top: 20px; text-align: right;">
|
| 515 |
-
<strong>Итого: <span id="cartTotal">0</span>
|
| 516 |
<button class="product-button clear-cart" onclick="clearCart()">Очистить</button>
|
| 517 |
<button class="product-button order-button" onclick="orderViaWhatsApp()">Заказать</button>
|
| 518 |
</div>
|
|
@@ -527,6 +585,7 @@ def catalog():
|
|
| 527 |
<script>
|
| 528 |
const products = {{ products|tojson }};
|
| 529 |
let selectedProductIndex = null;
|
|
|
|
| 530 |
|
| 531 |
function toggleTheme() {
|
| 532 |
document.body.classList.toggle('dark-mode');
|
|
@@ -648,7 +707,7 @@ def catalog():
|
|
| 648 |
let total = 0;
|
| 649 |
|
| 650 |
cartContent.innerHTML = cart.length === 0 ? '<p>Корзина пуста</p>' : cart.map(item => {
|
| 651 |
-
const itemTotal = item.price * item.quantity;
|
| 652 |
total += itemTotal;
|
| 653 |
return `
|
| 654 |
<div class="cart-item">
|
|
@@ -656,15 +715,15 @@ def catalog():
|
|
| 656 |
${item.photo ? `<img src="https://huggingface.co/datasets/{{ repo_id }}/resolve/main/photos/${item.photo}" alt="${item.name}">` : ''}
|
| 657 |
<div>
|
| 658 |
<strong>${item.name}</strong>
|
| 659 |
-
<p>${item.price}
|
| 660 |
</div>
|
| 661 |
</div>
|
| 662 |
-
<span>${itemTotal}
|
| 663 |
</div>
|
| 664 |
`;
|
| 665 |
}).join('');
|
| 666 |
|
| 667 |
-
document.getElementById('cartTotal').textContent = total;
|
| 668 |
document.getElementById('cartModal').style.display = 'block';
|
| 669 |
}
|
| 670 |
|
|
@@ -677,11 +736,11 @@ def catalog():
|
|
| 677 |
let total = 0;
|
| 678 |
let orderText = "Заказ:%0A";
|
| 679 |
cart.forEach((item, index) => {
|
| 680 |
-
const itemTotal = item.price * item.quantity;
|
| 681 |
total += itemTotal;
|
| 682 |
-
orderText += `${index + 1}. ${item.name} - ${item.price}
|
| 683 |
});
|
| 684 |
-
orderText += `Итого: ${total}
|
| 685 |
orderText += `Страна: {{ session.get('country', 'Не указана') }}%0A`;
|
| 686 |
orderText += `Город: {{ session.get('city', 'Не указан') }}`;
|
| 687 |
window.open(`https://api.whatsapp.com/send?phone=996555360556&text=${orderText}`, '_blank');
|
|
@@ -726,13 +785,17 @@ def catalog():
|
|
| 726 |
'''
|
| 727 |
return render_template_string(catalog_html, products=products, categories=categories,
|
| 728 |
repo_id=REPO_ID, is_authenticated=is_authenticated,
|
| 729 |
-
store_address=STORE_ADDRESS, session=session
|
|
|
|
|
|
|
| 730 |
|
| 731 |
@app.route('/product/<int:index>')
|
| 732 |
def product_detail(index):
|
| 733 |
data = load_data()
|
| 734 |
products = data['products']
|
| 735 |
is_authenticated = 'user' in session
|
|
|
|
|
|
|
| 736 |
try:
|
| 737 |
product = products[index]
|
| 738 |
except IndexError:
|
|
@@ -764,7 +827,7 @@ def product_detail(index):
|
|
| 764 |
</div>
|
| 765 |
<p><strong>Категория:</strong> {{ product.get('category', 'Без категории') }}</p>
|
| 766 |
{% if is_authenticated %}
|
| 767 |
-
<p><strong>Цена:</strong> {{ product['price'] }}
|
| 768 |
{% else %}
|
| 769 |
<p><strong>Цена:</strong> Доступна после входа</p>
|
| 770 |
{% endif %}
|
|
@@ -772,7 +835,17 @@ def product_detail(index):
|
|
| 772 |
<p><strong>Доступные цвета:</strong> {{ product.get('colors', ['Нет цветов'])|join(', ') }}</p>
|
| 773 |
</div>
|
| 774 |
'''
|
| 775 |
-
return render_template_string(detail_html, product=product, repo_id=REPO_ID,
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 776 |
|
| 777 |
@app.route('/register', methods=['GET', 'POST'])
|
| 778 |
def register():
|
|
@@ -794,7 +867,7 @@ def register():
|
|
| 794 |
return "Пользователь с таким логином уже существует", 400
|
| 795 |
|
| 796 |
users[login] = {
|
| 797 |
-
'password': password,
|
| 798 |
'country': country,
|
| 799 |
'city': city,
|
| 800 |
'purchase_type': purchase_type
|
|
@@ -803,6 +876,7 @@ def register():
|
|
| 803 |
session['user'] = login
|
| 804 |
session['country'] = country
|
| 805 |
session['city'] = city
|
|
|
|
| 806 |
return redirect(url_for('catalog'))
|
| 807 |
|
| 808 |
return render_template_string('''
|
|
@@ -900,6 +974,7 @@ def login():
|
|
| 900 |
session['user'] = login
|
| 901 |
session['country'] = users[login]['country']
|
| 902 |
session['city'] = users[login]['city']
|
|
|
|
| 903 |
return redirect(url_for('catalog'))
|
| 904 |
return "Неверный логин или пароль", 401
|
| 905 |
|
|
@@ -987,6 +1062,7 @@ def auto_login():
|
|
| 987 |
session['user'] = login
|
| 988 |
session['country'] = users[login]['country']
|
| 989 |
session['city'] = users[login]['city']
|
|
|
|
| 990 |
return "OK", 200
|
| 991 |
return "Ошибка авторизации", 401
|
| 992 |
|
|
@@ -995,6 +1071,7 @@ def logout():
|
|
| 995 |
session.pop('user', None)
|
| 996 |
session.pop('country', None)
|
| 997 |
session.pop('city', None)
|
|
|
|
| 998 |
return redirect(url_for('catalog'))
|
| 999 |
|
| 1000 |
@app.route('/admin', methods=['GET', 'POST'])
|
|
@@ -1056,10 +1133,10 @@ def admin():
|
|
| 1056 |
if not name or not price or not description:
|
| 1057 |
return "Ошибка: Заполните все обязательные поля", 400
|
| 1058 |
|
| 1059 |
-
price = float(price.replace(',', '.'))
|
| 1060 |
new_product = {
|
| 1061 |
'name': name,
|
| 1062 |
-
'price': price,
|
| 1063 |
'description': description,
|
| 1064 |
'category': category if category in categories else 'Без категории',
|
| 1065 |
'photos': photos_list,
|
|
@@ -1102,7 +1179,7 @@ def admin():
|
|
| 1102 |
products[index]['photos'] = new_photos_list
|
| 1103 |
|
| 1104 |
products[index]['name'] = name
|
| 1105 |
-
products[index]['price'] = float(price.replace(',', '.'))
|
| 1106 |
products[index]['description'] = description
|
| 1107 |
products[index]['category'] = category if category in categories else 'Без категории'
|
| 1108 |
products[index]['colors'] = colors if colors else []
|
|
@@ -1230,7 +1307,7 @@ def admin():
|
|
| 1230 |
<input type="hidden" name="action" value="add">
|
| 1231 |
<label>Название товара:</label>
|
| 1232 |
<input type="text" name="name" required>
|
| 1233 |
-
<label
|
| 1234 |
<input type="number" name="price" step="0.01" required>
|
| 1235 |
<label>Описание:</label>
|
| 1236 |
<textarea name="description" rows="4" required></textarea>
|
|
@@ -1289,7 +1366,7 @@ def admin():
|
|
| 1289 |
<div class="product-item">
|
| 1290 |
<h3>{{ product['name'] }}</h3>
|
| 1291 |
<p><strong>Категория:</strong> {{ product.get('category', 'Без категории') }}</p>
|
| 1292 |
-
<p><strong>Цена:</strong> {{ product['price'] }}
|
| 1293 |
<p><strong>Описание:</strong> {{ product['description'] }}</p>
|
| 1294 |
<p><strong>Цвета:</strong> {{ product.get('colors', ['Нет цветов'])|join(', ') }}</p>
|
| 1295 |
{% if product.get('photos') and product['photos']|length > 0 %}
|
|
@@ -1308,7 +1385,7 @@ def admin():
|
|
| 1308 |
<input type="hidden" name="index" value="{{ loop.index0 }}">
|
| 1309 |
<label>Название:</label>
|
| 1310 |
<input type="text" name="name" value="{{ product['name'] }}" required>
|
| 1311 |
-
<label
|
| 1312 |
<input type="number" name="price" step="0.01" value="{{ product['price'] }}" required>
|
| 1313 |
<label>Описание:</label>
|
| 1314 |
<textarea name="description" rows="4" required>{{ product['description'] }}</textarea>
|
|
|
|
| 4 |
import logging
|
| 5 |
import threading
|
| 6 |
import time
|
| 7 |
+
import requests
|
| 8 |
from datetime import datetime
|
| 9 |
from huggingface_hub import HfApi, hf_hub_download
|
| 10 |
from huggingface_hub.utils import RepositoryNotFoundError
|
| 11 |
from werkzeug.utils import secure_filename
|
| 12 |
|
| 13 |
app = Flask(__name__)
|
| 14 |
+
app.secret_key = 'your_unique_secret_key_12345' # Уникальный секретный ключ
|
| 15 |
DATA_FILE = 'data_detobuv.json'
|
| 16 |
+
USERS_FILE = 'users_detobuv.json'
|
| 17 |
|
| 18 |
# Настройки Hugging Face
|
| 19 |
REPO_ID = "Kgshop/clients"
|
|
|
|
| 23 |
# Адрес магазина
|
| 24 |
STORE_ADDRESS = "Бишкек, Рынок Дордой, 9 ряд, 06 контейнер"
|
| 25 |
|
| 26 |
+
# API для получения актуальных курсов валют
|
| 27 |
+
EXCHANGE_RATE_API_KEY = "a1bbe02a37d9584ab12ffc1f" # Замените на ваш ключ от ExchangeRate-API
|
| 28 |
+
EXCHANGE_RATE_API_URL = f"https://v6.exchangerate-api.com/v6/{EXCHANGE_RATE_API_KEY}/latest/USD"
|
| 29 |
+
|
| 30 |
+
# Поддерживаемые валюты
|
| 31 |
+
CURRENCIES = {
|
| 32 |
+
'USD': 'Доллар США ($)',
|
| 33 |
+
'KGS': 'Кыргызский сом (с)',
|
| 34 |
+
'RUB': 'Российский рубль (₽)',
|
| 35 |
+
'KZT': 'Казахский тенге (₸)'
|
| 36 |
+
}
|
| 37 |
+
|
| 38 |
# Настройка логирования
|
| 39 |
logging.basicConfig(level=logging.DEBUG)
|
| 40 |
|
| 41 |
+
def get_exchange_rates():
|
| 42 |
+
"""Получение актуальных курсов валют из API."""
|
| 43 |
+
try:
|
| 44 |
+
response = requests.get(EXCHANGE_RATE_API_URL)
|
| 45 |
+
data = response.json()
|
| 46 |
+
if data['result'] == 'success':
|
| 47 |
+
rates = {
|
| 48 |
+
'USD': 1.0,
|
| 49 |
+
'KGS': data['conversion_rates']['KGS'],
|
| 50 |
+
'RUB': data['conversion_rates']['RUB'],
|
| 51 |
+
'KZT': data['conversion_rates']['KZT']
|
| 52 |
+
}
|
| 53 |
+
logging.info("Курсы валют успешно обновлены из API")
|
| 54 |
+
return rates
|
| 55 |
+
else:
|
| 56 |
+
raise Exception("Ошибка API: " + data['error-type'])
|
| 57 |
+
except Exception as e:
|
| 58 |
+
logging.error(f"Не удалось получить курсы валют: {e}")
|
| 59 |
+
# Резервные фиксированные курсы в случае сбоя API
|
| 60 |
+
return {
|
| 61 |
+
'USD': 1.0,
|
| 62 |
+
'KGS': 89.0,
|
| 63 |
+
'RUB': 97.0,
|
| 64 |
+
'KZT': 480.0
|
| 65 |
+
}
|
| 66 |
+
|
| 67 |
+
def convert_price(price_usd, currency, rates):
|
| 68 |
+
"""Конвертация цены из USD в указанную валюту."""
|
| 69 |
+
return round(price_usd * rates[currency], 2)
|
| 70 |
+
|
| 71 |
def load_data():
|
| 72 |
try:
|
| 73 |
download_db_from_hf()
|
|
|
|
| 157 |
products = data['products']
|
| 158 |
categories = data['categories']
|
| 159 |
is_authenticated = 'user' in session
|
| 160 |
+
rates = get_exchange_rates()
|
| 161 |
+
selected_currency = session.get('currency', 'USD') if is_authenticated else 'USD'
|
| 162 |
+
|
| 163 |
catalog_html = '''
|
| 164 |
<!DOCTYPE html>
|
| 165 |
<html lang="ru">
|
|
|
|
| 473 |
font-style: italic;
|
| 474 |
color: #666;
|
| 475 |
}
|
| 476 |
+
.currency-select {
|
| 477 |
+
padding: 8px;
|
| 478 |
+
border-radius: 8px;
|
| 479 |
+
border: 1px solid #e2e8f0;
|
| 480 |
+
font-size: 1rem;
|
| 481 |
+
}
|
| 482 |
</style>
|
| 483 |
</head>
|
| 484 |
<body>
|
|
|
|
| 488 |
<div class="auth-links">
|
| 489 |
{% if is_authenticated %}
|
| 490 |
<span>Добро пожаловать, {{ session['user'] }}!</span>
|
| 491 |
+
<form method="POST" action="{{ url_for('set_currency') }}" style="display: inline;">
|
| 492 |
+
<select name="currency" class="currency-select" onchange="this.form.submit()">
|
| 493 |
+
{% for code, name in currencies.items() %}
|
| 494 |
+
<option value="{{ code }}" {% if code == selected_currency %}selected{% endif %}>{{ name }}</option>
|
| 495 |
+
{% endfor %}
|
| 496 |
+
</select>
|
| 497 |
+
</form>
|
| 498 |
<a href="{{ url_for('logout') }}">Выйти</a>
|
| 499 |
{% else %}
|
| 500 |
<a href="{{ url_for('login') }}">Войти</a>
|
|
|
|
| 530 |
{% endif %}
|
| 531 |
<h2>{{ product['name'] }}</h2>
|
| 532 |
{% if is_authenticated %}
|
| 533 |
+
<div class="product-price">{{ convert_price(product['price'], selected_currency, rates) }} {{ selected_currency }}</div>
|
| 534 |
{% else %}
|
| 535 |
<div class="product-price">Цена доступна после входа</div>
|
| 536 |
{% endif %}
|
|
|
|
| 570 |
<h2>Корзина</h2>
|
| 571 |
<div id="cartContent"></div>
|
| 572 |
<div style="margin-top: 20px; text-align: right;">
|
| 573 |
+
<strong>Итого: <span id="cartTotal">0</span> {{ selected_currency }}</strong>
|
| 574 |
<button class="product-button clear-cart" onclick="clearCart()">Очистить</button>
|
| 575 |
<button class="product-button order-button" onclick="orderViaWhatsApp()">Заказать</button>
|
| 576 |
</div>
|
|
|
|
| 585 |
<script>
|
| 586 |
const products = {{ products|tojson }};
|
| 587 |
let selectedProductIndex = null;
|
| 588 |
+
const selectedCurrency = '{{ selected_currency }}';
|
| 589 |
|
| 590 |
function toggleTheme() {
|
| 591 |
document.body.classList.toggle('dark-mode');
|
|
|
|
| 707 |
let total = 0;
|
| 708 |
|
| 709 |
cartContent.innerHTML = cart.length === 0 ? '<p>Корзина пуста</p>' : cart.map(item => {
|
| 710 |
+
const itemTotal = item.price * item.quantity * {{ rates[selected_currency]|tojson }};
|
| 711 |
total += itemTotal;
|
| 712 |
return `
|
| 713 |
<div class="cart-item">
|
|
|
|
| 715 |
${item.photo ? `<img src="https://huggingface.co/datasets/{{ repo_id }}/resolve/main/photos/${item.photo}" alt="${item.name}">` : ''}
|
| 716 |
<div>
|
| 717 |
<strong>${item.name}</strong>
|
| 718 |
+
<p>${(item.price * {{ rates[selected_currency]|tojson }}).toFixed(2)} ${selectedCurrency} × ${item.quantity} (Цвет: ${item.color})</p>
|
| 719 |
</div>
|
| 720 |
</div>
|
| 721 |
+
<span>${itemTotal.toFixed(2)} ${selectedCurrency}</span>
|
| 722 |
</div>
|
| 723 |
`;
|
| 724 |
}).join('');
|
| 725 |
|
| 726 |
+
document.getElementById('cartTotal').textContent = total.toFixed(2);
|
| 727 |
document.getElementById('cartModal').style.display = 'block';
|
| 728 |
}
|
| 729 |
|
|
|
|
| 736 |
let total = 0;
|
| 737 |
let orderText = "Заказ:%0A";
|
| 738 |
cart.forEach((item, index) => {
|
| 739 |
+
const itemTotal = item.price * item.quantity * {{ rates[selected_currency]|tojson }};
|
| 740 |
total += itemTotal;
|
| 741 |
+
orderText += `${index + 1}. ${item.name} - ${(item.price * {{ rates[selected_currency]|tojson }}).toFixed(2)} ${selectedCurrency} × ${item.quantity} (Цвет: ${item.color})%0A`;
|
| 742 |
});
|
| 743 |
+
orderText += `Итого: ${total.toFixed(2)} ${selectedCurrency}%0A`;
|
| 744 |
orderText += `Страна: {{ session.get('country', 'Не указана') }}%0A`;
|
| 745 |
orderText += `Город: {{ session.get('city', 'Не указан') }}`;
|
| 746 |
window.open(`https://api.whatsapp.com/send?phone=996555360556&text=${orderText}`, '_blank');
|
|
|
|
| 785 |
'''
|
| 786 |
return render_template_string(catalog_html, products=products, categories=categories,
|
| 787 |
repo_id=REPO_ID, is_authenticated=is_authenticated,
|
| 788 |
+
store_address=STORE_ADDRESS, session=session,
|
| 789 |
+
convert_price=convert_price, rates=rates,
|
| 790 |
+
selected_currency=selected_currency, currencies=CURRENCIES)
|
| 791 |
|
| 792 |
@app.route('/product/<int:index>')
|
| 793 |
def product_detail(index):
|
| 794 |
data = load_data()
|
| 795 |
products = data['products']
|
| 796 |
is_authenticated = 'user' in session
|
| 797 |
+
rates = get_exchange_rates()
|
| 798 |
+
selected_currency = session.get('currency', 'USD') if is_authenticated else 'USD'
|
| 799 |
try:
|
| 800 |
product = products[index]
|
| 801 |
except IndexError:
|
|
|
|
| 827 |
</div>
|
| 828 |
<p><strong>Категория:</strong> {{ product.get('category', 'Без категории') }}</p>
|
| 829 |
{% if is_authenticated %}
|
| 830 |
+
<p><strong>Цена:</strong> {{ convert_price(product['price'], selected_currency, rates) }} {{ selected_currency }}</p>
|
| 831 |
{% else %}
|
| 832 |
<p><strong>Цена:</strong> Доступна после входа</p>
|
| 833 |
{% endif %}
|
|
|
|
| 835 |
<p><strong>Доступные цвета:</strong> {{ product.get('colors', ['Нет цветов'])|join(', ') }}</p>
|
| 836 |
</div>
|
| 837 |
'''
|
| 838 |
+
return render_template_string(detail_html, product=product, repo_id=REPO_ID,
|
| 839 |
+
is_authenticated=is_authenticated, convert_price=convert_price,
|
| 840 |
+
rates=rates, selected_currency=selected_currency)
|
| 841 |
+
|
| 842 |
+
@app.route('/set_currency', methods=['POST'])
|
| 843 |
+
def set_currency():
|
| 844 |
+
if 'user' in session:
|
| 845 |
+
currency = request.form.get('currency')
|
| 846 |
+
if currency in CURRENCIES:
|
| 847 |
+
session['currency'] = currency
|
| 848 |
+
return redirect(url_for('catalog'))
|
| 849 |
|
| 850 |
@app.route('/register', methods=['GET', 'POST'])
|
| 851 |
def register():
|
|
|
|
| 867 |
return "Пользователь с таким логином уже существует", 400
|
| 868 |
|
| 869 |
users[login] = {
|
| 870 |
+
'password': password,
|
| 871 |
'country': country,
|
| 872 |
'city': city,
|
| 873 |
'purchase_type': purchase_type
|
|
|
|
| 876 |
session['user'] = login
|
| 877 |
session['country'] = country
|
| 878 |
session['city'] = city
|
| 879 |
+
session['currency'] = 'USD' # Устанавливаем валюту по умолчанию
|
| 880 |
return redirect(url_for('catalog'))
|
| 881 |
|
| 882 |
return render_template_string('''
|
|
|
|
| 974 |
session['user'] = login
|
| 975 |
session['country'] = users[login]['country']
|
| 976 |
session['city'] = users[login]['city']
|
| 977 |
+
session['currency'] = 'USD' # Устанавливаем валюту по умолчанию
|
| 978 |
return redirect(url_for('catalog'))
|
| 979 |
return "Неверный логин или пароль", 401
|
| 980 |
|
|
|
|
| 1062 |
session['user'] = login
|
| 1063 |
session['country'] = users[login]['country']
|
| 1064 |
session['city'] = users[login]['city']
|
| 1065 |
+
session['currency'] = 'USD' # Устанавливаем валюту по умолчанию
|
| 1066 |
return "OK", 200
|
| 1067 |
return "Ошибка авторизации", 401
|
| 1068 |
|
|
|
|
| 1071 |
session.pop('user', None)
|
| 1072 |
session.pop('country', None)
|
| 1073 |
session.pop('city', None)
|
| 1074 |
+
session.pop('currency', None)
|
| 1075 |
return redirect(url_for('catalog'))
|
| 1076 |
|
| 1077 |
@app.route('/admin', methods=['GET', 'POST'])
|
|
|
|
| 1133 |
if not name or not price or not description:
|
| 1134 |
return "Ошибка: Заполните все обязательные поля", 400
|
| 1135 |
|
| 1136 |
+
price = float(price.replace(',', '.')) # Цена в USD
|
| 1137 |
new_product = {
|
| 1138 |
'name': name,
|
| 1139 |
+
'price': price, # Цена в долларах
|
| 1140 |
'description': description,
|
| 1141 |
'category': category if category in categories else 'Без категории',
|
| 1142 |
'photos': photos_list,
|
|
|
|
| 1179 |
products[index]['photos'] = new_photos_list
|
| 1180 |
|
| 1181 |
products[index]['name'] = name
|
| 1182 |
+
products[index]['price'] = float(price.replace(',', '.')) # Цена в USD
|
| 1183 |
products[index]['description'] = description
|
| 1184 |
products[index]['category'] = category if category in categories else 'Без категории'
|
| 1185 |
products[index]['colors'] = colors if colors else []
|
|
|
|
| 1307 |
<input type="hidden" name="action" value="add">
|
| 1308 |
<label>Название товара:</label>
|
| 1309 |
<input type="text" name="name" required>
|
| 1310 |
+
<label>Цена (USD):</label>
|
| 1311 |
<input type="number" name="price" step="0.01" required>
|
| 1312 |
<label>Описание:</label>
|
| 1313 |
<textarea name="description" rows="4" required></textarea>
|
|
|
|
| 1366 |
<div class="product-item">
|
| 1367 |
<h3>{{ product['name'] }}</h3>
|
| 1368 |
<p><strong>Категория:</strong> {{ product.get('category', 'Без категории') }}</p>
|
| 1369 |
+
<p><strong>Цена:</strong> {{ product['price'] }} USD</p>
|
| 1370 |
<p><strong>Описание:</strong> {{ product['description'] }}</p>
|
| 1371 |
<p><strong>Цвета:</strong> {{ product.get('colors', ['Нет цветов'])|join(', ') }}</p>
|
| 1372 |
{% if product.get('photos') and product['photos']|length > 0 %}
|
|
|
|
| 1385 |
<input type="hidden" name="index" value="{{ loop.index0 }}">
|
| 1386 |
<label>Название:</label>
|
| 1387 |
<input type="text" name="name" value="{{ product['name'] }}" required>
|
| 1388 |
+
<label>Цена (USD):</label>
|
| 1389 |
<input type="number" name="price" step="0.01" value="{{ product['price'] }}" required>
|
| 1390 |
<label>Описание:</label>
|
| 1391 |
<textarea name="description" rows="4" required>{{ product['description'] }}</textarea>
|