Kgshop commited on
Commit
2cb2227
·
verified ·
1 Parent(s): 8240a5c

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +92 -54
app.py CHANGED
@@ -4,7 +4,6 @@ import os
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
@@ -13,60 +12,47 @@ from werkzeug.utils import secure_filename
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"
20
  HF_TOKEN_WRITE = os.getenv("HF_TOKEN")
21
  HF_TOKEN_READ = os.getenv("HF_TOKEN_READ")
22
 
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:
@@ -157,7 +143,6 @@ def catalog():
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 = '''
@@ -166,7 +151,7 @@ def catalog():
166
  <head>
167
  <meta charset="UTF-8">
168
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
169
- <title>Детская обувь оптом, Дордой, ряд 9, контейнер 06</title>
170
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.1/css/all.min.css">
171
  <link href="https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;600&display=swap" rel="stylesheet">
172
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/Swiper/10.2.0/swiper-bundle.min.css">
@@ -505,7 +490,7 @@ def catalog():
505
  <i class="fas fa-moon"></i>
506
  </button>
507
  </div>
508
- <div class="store-address">{{ store_address }}</div>
509
  <div class="filters-container">
510
  <button class="category-filter active" data-category="all">Все категории</button>
511
  {% for category in categories %}
@@ -530,7 +515,7 @@ def catalog():
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 %}
@@ -586,6 +571,7 @@ def catalog():
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,7 +693,8 @@ def catalog():
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,7 +702,7 @@ def catalog():
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>
@@ -736,9 +723,10 @@ def catalog():
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`;
@@ -785,8 +773,8 @@ def catalog():
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>')
@@ -794,7 +782,6 @@ 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]
@@ -827,7 +814,7 @@ def product_detail(index):
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 %}
@@ -837,7 +824,7 @@ def product_detail(index):
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():
@@ -852,6 +839,8 @@ def register():
852
  if request.method == 'POST':
853
  login = request.form.get('login')
854
  password = request.form.get('password')
 
 
855
  country = request.form.get('country')
856
  city = request.form.get('city')
857
  purchase_type = request.form.get('purchase_type')
@@ -868,6 +857,8 @@ def register():
868
 
869
  users[login] = {
870
  'password': password,
 
 
871
  'country': country,
872
  'city': city,
873
  'purchase_type': purchase_type
@@ -938,6 +929,10 @@ def register():
938
  <input type="text" name="login" required>
939
  <label>Пароль:</label>
940
  <input type="password" name="password" required>
 
 
 
 
941
  <label>Страна:</label>
942
  <input type="text" name="country" required>
943
  <label>Город:</label>
@@ -1079,6 +1074,8 @@ def admin():
1079
  data = load_data()
1080
  products = data['products']
1081
  categories = data['categories']
 
 
1082
 
1083
  if request.method == 'POST':
1084
  action = request.form.get('action')
@@ -1191,6 +1188,18 @@ def admin():
1191
  del products[index]
1192
  save_data(data)
1193
  return redirect(url_for('admin'))
 
 
 
 
 
 
 
 
 
 
 
 
1194
 
1195
  admin_html = '''
1196
  <!DOCTYPE html>
@@ -1268,11 +1277,11 @@ def admin():
1268
  background-color: #dc2626;
1269
  box-shadow: 0 4px 15px rgba(220, 38, 38, 0.4);
1270
  }
1271
- .product-list, .category-list {
1272
  display: grid;
1273
  gap: 20px;
1274
  }
1275
- .product-item, .category-item {
1276
  background: #fff;
1277
  padding: 20px;
1278
  border-radius: 15px;
@@ -1302,6 +1311,15 @@ def admin():
1302
  <div class="header">
1303
  <h1>Админ-панель</h1>
1304
  </div>
 
 
 
 
 
 
 
 
 
1305
  <h1>Добавление товара</h1>
1306
  <form method="POST" enctype="multipart/form-data">
1307
  <input type="hidden" name="action" value="add">
@@ -1366,7 +1384,7 @@ def admin():
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 %}
@@ -1418,6 +1436,24 @@ def admin():
1418
  </div>
1419
  {% endfor %}
1420
  </div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1421
  </div>
1422
  <script>
1423
  function addColorInput(containerId = 'color-inputs') {
@@ -1431,7 +1467,9 @@ def admin():
1431
  </body>
1432
  </html>
1433
  '''
1434
- return render_template_string(admin_html, products=products, categories=categories, repo_id=REPO_ID)
 
 
1435
 
1436
  @app.route('/backup', methods=['POST'])
1437
  def backup():
 
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
 
12
  app = Flask(__name__)
13
  app.secret_key = 'your_unique_secret_key_12345' # Уникальный секретный ключ
14
  DATA_FILE = 'data_detobuv.json'
15
+ USERS_FILE = 'users.json'
16
+ CONFIG_FILE = 'config.json' # Файл для хранения курса KGS к USD
17
 
18
  # Настройки Hugging Face
19
  REPO_ID = "Kgshop/clients"
20
  HF_TOKEN_WRITE = os.getenv("HF_TOKEN")
21
  HF_TOKEN_READ = os.getenv("HF_TOKEN_READ")
22
 
23
+ # Адреса магазина
24
+ WHOLESALE_ADDRESS = "Дордой, рынок Кербен, 9 ряд, 06 бутик" # Опт
25
+ RETAIL_ADDRESS = "Дордой Мир Обуви, номер 150" # Розница
 
 
 
26
 
27
  # Поддерживаемые валюты
28
  CURRENCIES = {
29
  'USD': 'Доллар США ($)',
30
+ 'KGS': 'Кыргызский сом (с)'
 
 
31
  }
32
 
33
  # Настройка логирования
34
  logging.basicConfig(level=logging.DEBUG)
35
 
36
+ def load_config():
37
+ """Загрузка конфигурации (курс KGS к USD)."""
38
  try:
39
+ with open(CONFIG_FILE, 'r', encoding='utf-8') as file:
40
+ config = json.load(file)
41
+ return config.get('kgs_to_usd', 89.0) # Значение по умолчанию
42
+ except (FileNotFoundError, json.JSONDecodeError):
43
+ return 89.0 # Резервное значение
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
44
 
45
+ def save_config(kgs_to_usd):
46
+ """Сохранение конфигурации."""
47
+ with open(CONFIG_FILE, 'w', encoding='utf-8') as file:
48
+ json.dump({'kgs_to_usd': kgs_to_usd}, file, ensure_ascii=False, indent=4)
49
+
50
+ def convert_price(price_usd, currency):
51
  """Конвертация цены из USD в указанную валюту."""
52
+ kgs_to_usd = load_config()
53
+ if currency == 'KGS':
54
+ return round(price_usd * kgs_to_usd, 2)
55
+ return round(price_usd, 2)
56
 
57
  def load_data():
58
  try:
 
143
  products = data['products']
144
  categories = data['categories']
145
  is_authenticated = 'user' in session
 
146
  selected_currency = session.get('currency', 'USD') if is_authenticated else 'USD'
147
 
148
  catalog_html = '''
 
151
  <head>
152
  <meta charset="UTF-8">
153
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
154
+ <title>Детская обувь оптом и в розницу</title>
155
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.1/css/all.min.css">
156
  <link href="https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;600&display=swap" rel="stylesheet">
157
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/Swiper/10.2.0/swiper-bundle.min.css">
 
490
  <i class="fas fa-moon"></i>
491
  </button>
492
  </div>
493
+ <div class="store-address">Опт: {{ wholesale_address }} | ��озница: {{ retail_address }}</div>
494
  <div class="filters-container">
495
  <button class="category-filter active" data-category="all">Все категории</button>
496
  {% for category in categories %}
 
515
  {% endif %}
516
  <h2>{{ product['name'] }}</h2>
517
  {% if is_authenticated %}
518
+ <div class="product-price">{{ convert_price(product['price'], selected_currency) }} {{ selected_currency }}</div>
519
  {% else %}
520
  <div class="product-price">Цена доступна после входа</div>
521
  {% endif %}
 
571
  const products = {{ products|tojson }};
572
  let selectedProductIndex = null;
573
  const selectedCurrency = '{{ selected_currency }}';
574
+ const kgsToUsd = {{ load_config()|tojson }};
575
 
576
  function toggleTheme() {
577
  document.body.classList.toggle('dark-mode');
 
693
  let total = 0;
694
 
695
  cartContent.innerHTML = cart.length === 0 ? '<p>Корзина пуста</p>' : cart.map(item => {
696
+ const itemPrice = selectedCurrency === 'KGS' ? (item.price * kgsToUsd) : item.price;
697
+ const itemTotal = itemPrice * item.quantity;
698
  total += itemTotal;
699
  return `
700
  <div class="cart-item">
 
702
  ${item.photo ? `<img src="https://huggingface.co/datasets/{{ repo_id }}/resolve/main/photos/${item.photo}" alt="${item.name}">` : ''}
703
  <div>
704
  <strong>${item.name}</strong>
705
+ <p>${itemPrice.toFixed(2)} ${selectedCurrency} × ${item.quantity} (Цвет: ${item.color})</p>
706
  </div>
707
  </div>
708
  <span>${itemTotal.toFixed(2)} ${selectedCurrency}</span>
 
723
  let total = 0;
724
  let orderText = "Заказ:%0A";
725
  cart.forEach((item, index) => {
726
+ const itemPrice = selectedCurrency === 'KGS' ? (item.price * kgsToUsd) : item.price;
727
+ const itemTotal = itemPrice * item.quantity;
728
  total += itemTotal;
729
+ orderText += `${index + 1}. ${item.name} - ${itemPrice.toFixed(2)} ${selectedCurrency} × ${item.quantity} (Цвет: ${item.color})%0A`;
730
  });
731
  orderText += `Итого: ${total.toFixed(2)} ${selectedCurrency}%0A`;
732
  orderText += `Страна: {{ session.get('country', 'Не указана') }}%0A`;
 
773
  '''
774
  return render_template_string(catalog_html, products=products, categories=categories,
775
  repo_id=REPO_ID, is_authenticated=is_authenticated,
776
+ wholesale_address=WHOLESALE_ADDRESS, retail_address=RETAIL_ADDRESS,
777
+ session=session, convert_price=convert_price,
778
  selected_currency=selected_currency, currencies=CURRENCIES)
779
 
780
  @app.route('/product/<int:index>')
 
782
  data = load_data()
783
  products = data['products']
784
  is_authenticated = 'user' in session
 
785
  selected_currency = session.get('currency', 'USD') if is_authenticated else 'USD'
786
  try:
787
  product = products[index]
 
814
  </div>
815
  <p><strong>Категория:</strong> {{ product.get('category', 'Без категории') }}</p>
816
  {% if is_authenticated %}
817
+ <p><strong>Цена:</strong> {{ convert_price(product['price'], selected_currency) }} {{ selected_currency }}</p>
818
  {% else %}
819
  <p><strong>Цена:</strong> Доступна после входа</p>
820
  {% endif %}
 
824
  '''
825
  return render_template_string(detail_html, product=product, repo_id=REPO_ID,
826
  is_authenticated=is_authenticated, convert_price=convert_price,
827
+ selected_currency=selected_currency)
828
 
829
  @app.route('/set_currency', methods=['POST'])
830
  def set_currency():
 
839
  if request.method == 'POST':
840
  login = request.form.get('login')
841
  password = request.form.get('password')
842
+ first_name = request.form.get('first_name')
843
+ last_name = request.form.get('last_name')
844
  country = request.form.get('country')
845
  city = request.form.get('city')
846
  purchase_type = request.form.get('purchase_type')
 
857
 
858
  users[login] = {
859
  'password': password,
860
+ 'first_name': first_name,
861
+ 'last_name': last_name,
862
  'country': country,
863
  'city': city,
864
  'purchase_type': purchase_type
 
929
  <input type="text" name="login" required>
930
  <label>Пароль:</label>
931
  <input type="password" name="password" required>
932
+ <label>Имя:</label>
933
+ <input type="text" name="first_name" required>
934
+ <label>Фамилия:</label>
935
+ <input type="text" name="last_name" required>
936
  <label>Страна:</label>
937
  <input type="text" name="country" required>
938
  <label>Город:</label>
 
1074
  data = load_data()
1075
  products = data['products']
1076
  categories = data['categories']
1077
+ users = load_users()
1078
+ kgs_to_usd = load_config()
1079
 
1080
  if request.method == 'POST':
1081
  action = request.form.get('action')
 
1188
  del products[index]
1189
  save_data(data)
1190
  return redirect(url_for('admin'))
1191
+
1192
+ elif action == 'set_exchange_rate':
1193
+ kgs_to_usd = float(request.form.get('kgs_to_usd').replace(',', '.'))
1194
+ save_config(kgs_to_usd)
1195
+ return redirect(url_for('admin'))
1196
+
1197
+ elif action == 'delete_user':
1198
+ login = request.form.get('login')
1199
+ if login in users:
1200
+ del users[login]
1201
+ save_users(users)
1202
+ return redirect(url_for('admin'))
1203
 
1204
  admin_html = '''
1205
  <!DOCTYPE html>
 
1277
  background-color: #dc2626;
1278
  box-shadow: 0 4px 15px rgba(220, 38, 38, 0.4);
1279
  }
1280
+ .product-list, .category-list, .user-list {
1281
  display: grid;
1282
  gap: 20px;
1283
  }
1284
+ .product-item, .category-item, .user-item {
1285
  background: #fff;
1286
  padding: 20px;
1287
  border-radius: 15px;
 
1311
  <div class="header">
1312
  <h1>Админ-панель</h1>
1313
  </div>
1314
+
1315
+ <h1>Установка курса KGS к USD</h1>
1316
+ <form method="POST">
1317
+ <input type="hidden" name="action" value="set_exchange_rate">
1318
+ <label>Курс KGS к USD (1 USD = ? KGS):</label>
1319
+ <input type="number" name="kgs_to_usd" step="0.01" value="{{ kgs_to_usd }}" required>
1320
+ <button type="submit">Сохранить</button>
1321
+ </form>
1322
+
1323
  <h1>Добавление товара</h1>
1324
  <form method="POST" enctype="multipart/form-data">
1325
  <input type="hidden" name="action" value="add">
 
1384
  <div class="product-item">
1385
  <h3>{{ product['name'] }}</h3>
1386
  <p><strong>Категория:</strong> {{ product.get('category', 'Без категории') }}</p>
1387
+ <p><strong>Цена:</strong> {{ product['price'] }} USD ({{ convert_price(product['price'], 'KGS') }} KGS)</p>
1388
  <p><strong>Описание:</strong> {{ product['description'] }}</p>
1389
  <p><strong>Цвета:</strong> {{ product.get('colors', ['Нет цветов'])|join(', ') }}</p>
1390
  {% if product.get('photos') and product['photos']|length > 0 %}
 
1436
  </div>
1437
  {% endfor %}
1438
  </div>
1439
+
1440
+ <h2>Список пользователей</h2>
1441
+ <div class="user-list">
1442
+ {% for login, user in users.items() %}
1443
+ <div class="user-item">
1444
+ <p><strong>Логин:</strong> {{ login }}</p>
1445
+ <p><strong>Имя:</strong> {{ user['first_name'] }}</p>
1446
+ <p><strong>Фlastname:</strong> {{ user['last_name'] }}</p>
1447
+ <p><strong>Страна:</strong> {{ user['country'] }}</p>
1448
+ <p><strong>Город:</strong> {{ user['city'] }}</p>
1449
+ <form method="POST">
1450
+ <input type="hidden" name="action" value="delete_user">
1451
+ <input type="hidden" name="login" value="{{ login }}">
1452
+ <button type="submit" class="delete-button">Удалить</button>
1453
+ </form>
1454
+ </div>
1455
+ {% endfor %}
1456
+ </div>
1457
  </div>
1458
  <script>
1459
  function addColorInput(containerId = 'color-inputs') {
 
1467
  </body>
1468
  </html>
1469
  '''
1470
+ return render_template_string(admin_html, products=products, categories=categories,
1471
+ repo_id=REPO_ID, users=users, kgs_to_usd=kgs_to_usd,
1472
+ convert_price=convert_price)
1473
 
1474
  @app.route('/backup', methods=['POST'])
1475
  def backup():