sqlalchemy-connection 2.0.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (33) hide show
  1. sqlalchemy_connection-2.0.1.dist-info/METADATA +26 -0
  2. sqlalchemy_connection-2.0.1.dist-info/RECORD +33 -0
  3. sqlalchemy_connection-2.0.1.dist-info/WHEEL +5 -0
  4. sqlalchemy_connection-2.0.1.dist-info/entry_points.txt +2 -0
  5. sqlalchemy_connection-2.0.1.dist-info/top_level.txt +1 -0
  6. sqlalchemy_connector/__init__.py +3 -0
  7. sqlalchemy_connector/_builder.py +425 -0
  8. sqlalchemy_connector/cli.py +200 -0
  9. sqlalchemy_connector/real_generator.py +2908 -0
  10. sqlalchemy_connector/templates/admin_cart_html_template.html +372 -0
  11. sqlalchemy_connector/templates/admin_html_template.html +364 -0
  12. sqlalchemy_connector/templates/admin_users_html_template.html +82 -0
  13. sqlalchemy_connector/templates/app_template.py +434 -0
  14. sqlalchemy_connector/templates/base_html_template.html +100 -0
  15. sqlalchemy_connector/templates/cart_html_template.html +103 -0
  16. sqlalchemy_connector/templates/catalog_html_template.html +98 -0
  17. sqlalchemy_connector/templates/checkout_html_template.html +70 -0
  18. sqlalchemy_connector/templates/dashboard_html_template.html +121 -0
  19. sqlalchemy_connector/templates/index_html_template.html +91 -0
  20. sqlalchemy_connector/templates/login_html_template.html +59 -0
  21. sqlalchemy_connector/templates/models_template.py +65 -0
  22. sqlalchemy_connector/templates/new_request_html_template.html +49 -0
  23. sqlalchemy_connector/templates/orders_html_template.html +65 -0
  24. sqlalchemy_connector/templates/product_form_html_template.html +142 -0
  25. sqlalchemy_connector/templates/product_html_template.html +131 -0
  26. sqlalchemy_connector/templates/profile_html_template.html +104 -0
  27. sqlalchemy_connector/templates/register_html_template.html +183 -0
  28. sqlalchemy_connector/templates/reviews_html_template.html +104 -0
  29. sqlalchemy_connector/templates/service_detail_html_template.html +67 -0
  30. sqlalchemy_connector/templates/service_form_html_template.html +86 -0
  31. sqlalchemy_connector/templates/services_html_template.html +47 -0
  32. sqlalchemy_connector/templates/slider_js_template.js +99 -0
  33. sqlalchemy_connector/templates/style_css_template.css +502 -0
@@ -0,0 +1,372 @@
1
+ {% extends "base.html" %}
2
+
3
+ {% block title %}Админ-панель{% endblock %}
4
+
5
+ {% block extra_head %}
6
+ <!-- Chart.js для статистики -->
7
+ <script src="https://cdn.jsdelivr.net/npm/chart.js@4.4.0/dist/chart.umd.min.js"></script>
8
+ <style>
9
+ /* ═══ ПОЛНЫЙ ФИКС дёрганья модального окна ═══ */
10
+ html {
11
+ overflow-y: scroll !important;
12
+ scrollbar-gutter: stable;
13
+ }
14
+ body.modal-open {
15
+ padding-right: 0 !important;
16
+ overflow: hidden !important;
17
+ }
18
+ body.modal-open .navbar,
19
+ body.modal-open .fixed-top {
20
+ padding-right: 0 !important;
21
+ }
22
+ .modal {
23
+ padding-right: 0 !important;
24
+ }
25
+ .modal-backdrop {
26
+ width: 100vw !important;
27
+ }
28
+ /* Убираем ВСЕ анимации/переходы внутри модального окна */
29
+ .modal,
30
+ .modal * {
31
+ transition: none !important;
32
+ animation: none !important;
33
+ will-change: auto !important;
34
+ }
35
+ .modal *:hover,
36
+ .modal *:focus,
37
+ .modal *:active {
38
+ transform: none !important;
39
+ box-shadow: inherit !important;
40
+ transition: none !important;
41
+ }
42
+ .modal.fade,
43
+ .modal.fade .modal-dialog {
44
+ transform: none !important;
45
+ transition: none !important;
46
+ }
47
+ .modal-dialog {
48
+ margin: 80px auto !important;
49
+ transform: none !important;
50
+ transition: none !important;
51
+ will-change: auto !important;
52
+ }
53
+ .modal-content {
54
+ transform: none !important;
55
+ transition: none !important;
56
+ animation: none !important;
57
+ will-change: auto !important;
58
+ }
59
+ /* Отключаем hover-эффекты на элементах ПОД модальным окном */
60
+ body.modal-open .card,
61
+ body.modal-open .card:hover,
62
+ body.modal-open .btn:hover,
63
+ body.modal-open .product-card:hover,
64
+ body.modal-open .table-hover tbody tr:hover {
65
+ transform: none !important;
66
+ box-shadow: inherit !important;
67
+ transition: none !important;
68
+ }
69
+ /* Dropdown z-index fix */
70
+ .dropdown-menu {
71
+ position: absolute !important;
72
+ z-index: 1050 !important;
73
+ }
74
+ .table-responsive {
75
+ overflow: visible !important;
76
+ }
77
+ </style>
78
+ {% endblock %}
79
+
80
+ {% block content %}
81
+ <!-- Заголовок -->
82
+ <div class="d-flex justify-content-between align-items-center mb-4 flex-wrap gap-2">
83
+ <h3 class="mb-0">👑 Админ-панель</h3>
84
+ <div class="d-flex gap-2">
85
+ <a href="{{ url_for('admin_users') }}" class="btn btn-outline-primary btn-sm">
86
+ 👥 Пользователи
87
+ </a>
88
+ <a href="{{ url_for('admin_products') }}" class="btn btn-outline-info btn-sm">
89
+ 📦 Товары
90
+ </a>
91
+ <a href="{{ url_for('admin_orders') }}" class="btn btn-outline-warning btn-sm">
92
+ 🛒 Заказы
93
+ </a>
94
+ </div>
95
+ </div>
96
+
97
+ <!-- Статистика продаж -->
98
+ <div class="row g-3 mb-4">
99
+ <div class="col-6 col-md-3">
100
+ <div class="card text-center border-0 shadow-sm h-100">
101
+ <div class="card-body py-3">
102
+ <div class="fs-2 fw-bold text-primary">{{ total_orders }}</div>
103
+ <small class="text-muted">Всего заказов</small>
104
+ </div>
105
+ </div>
106
+ </div>
107
+ <div class="col-6 col-md-3">
108
+ <div class="card text-center border-0 shadow-sm h-100">
109
+ <div class="card-body py-3">
110
+ <div class="fs-2 fw-bold text-success">{{ total_revenue|round(2) }} ₽</div>
111
+ <small class="text-muted">Общая выручка</small>
112
+ </div>
113
+ </div>
114
+ </div>
115
+ <div class="col-6 col-md-3">
116
+ <div class="card text-center border-0 shadow-sm h-100">
117
+ <div class="card-body py-3">
118
+ <div class="fs-2 fw-bold text-info">{{ total_products }}</div>
119
+ <small class="text-muted">Товаров в каталоге</small>
120
+ </div>
121
+ </div>
122
+ </div>
123
+ <div class="col-6 col-md-3">
124
+ <div class="card text-center border-0 shadow-sm h-100">
125
+ <div class="card-body py-3">
126
+ <div class="fs-2 fw-bold text-warning">{{ total_users }}</div>
127
+ <small class="text-muted">Пользователей</small>
128
+ </div>
129
+ </div>
130
+ </div>
131
+ </div>
132
+
133
+ <!-- Статистика по статусам заказов + График -->
134
+ <div class="row g-3 mb-4">
135
+ <div class="col-md-5">
136
+ <div class="card border-0 shadow-sm h-100">
137
+ <div class="card-body">
138
+ <h6 class="card-title">Заказы по статусам</h6>
139
+ <canvas id="ordersChart" height="200"></canvas>
140
+ </div>
141
+ </div>
142
+ </div>
143
+ <div class="col-md-7">
144
+ <div class="card border-0 shadow-sm h-100">
145
+ <div class="card-body">
146
+ <h6 class="card-title">Выручка за последние 7 дней</h6>
147
+ <canvas id="revenueChart" height="200"></canvas>
148
+ </div>
149
+ </div>
150
+ </div>
151
+ </div>
152
+
153
+ <!-- Последние заказы -->
154
+ <div class="card border-0 shadow-sm mb-4">
155
+ <div class="card-header bg-dark text-white d-flex justify-content-between align-items-center">
156
+ <h5 class="mb-0">Последние заказы</h5>
157
+ <a href="{{ url_for('admin_orders') }}" class="btn btn-outline-light btn-sm">Все заказы →</a>
158
+ </div>
159
+ <div class="card-body p-0">
160
+ <div class="table-responsive">
161
+ <table class="table table-hover align-middle mb-0">
162
+ <thead class="table-light">
163
+ <tr>
164
+ <th>#</th>
165
+ <th>Покупатель</th>
166
+ <th>Дата</th>
167
+ <th>Сумма</th>
168
+ <th>Статус</th>
169
+ <th>Действия</th>
170
+ </tr>
171
+ </thead>
172
+ <tbody>
173
+ {% for order in recent_orders %}
174
+ <tr>
175
+ <td class="text-muted">{{ order.id }}</td>
176
+ <td>
177
+ <strong>{{ (order.order_user.email or order.order_user.login or 'N/A') if order.order_user else 'N/A' }}</strong>
178
+ {% if order.order_user and order.order_user.full_name is defined and order.order_user.full_name %}
179
+ <br><small class="text-muted">{{ order.order_user.full_name }}</small>
180
+ {% endif %}
181
+ </td>
182
+ <td>
183
+ {{ order.created_at.strftime('%d.%m.%Y') }}<br>
184
+ <small class="text-muted">{{ order.created_at.strftime('%H:%M') }}</small>
185
+ </td>
186
+ <td><strong>{{ order.total_price|round(2) }} ₽</strong></td>
187
+ <td>
188
+ {% set status_colors = {'Новый': 'warning', 'Оплачен': 'info', 'Отправлен': 'primary', 'Доставлен': 'success', 'Отменён': 'danger'} %}
189
+ <span class="badge bg-{{ status_colors.get(order.status, 'secondary') }}
190
+ {% if order.status == 'Новый' %}text-dark{% endif %}">
191
+ {{ order.status }}
192
+ </span>
193
+ </td>
194
+ <td>
195
+ <button type="button" class="btn btn-sm btn-outline-secondary"
196
+ data-bs-toggle="modal" data-bs-target="#adminOrderModal{{ order.id }}">
197
+ 👁 Подробнее
198
+ </button>
199
+ </td>
200
+ </tr>
201
+ {% else %}
202
+ <tr>
203
+ <td colspan="6" class="text-center text-muted py-4">Заказов пока нет</td>
204
+ </tr>
205
+ {% endfor %}
206
+ </tbody>
207
+ </table>
208
+ </div>
209
+
210
+ <!-- Модальные окна деталей заказов (админ) -->
211
+ {% for order in recent_orders %}
212
+ <div class="modal fade" id="adminOrderModal{{ order.id }}" tabindex="-1" aria-hidden="true">
213
+ <div class="modal-dialog">
214
+ <div class="modal-content">
215
+ <div class="modal-header">
216
+ <h5 class="modal-title">Заказ #{{ order.id }}</h5>
217
+ <button type="button" class="btn-close" data-bs-dismiss="modal"></button>
218
+ </div>
219
+ <div class="modal-body">
220
+ <dl class="row mb-0">
221
+ <dt class="col-sm-5">Покупатель:</dt>
222
+ <dd class="col-sm-7">{{ (order.order_user.email or order.order_user.login or 'N/A') if order.order_user else 'N/A' }}
223
+ {% if order.order_user and order.order_user.full_name is defined and order.order_user.full_name %}
224
+ ({{ order.order_user.full_name }})
225
+ {% endif %}
226
+ </dd>
227
+ <dt class="col-sm-5">Дата:</dt>
228
+ <dd class="col-sm-7">{{ order.created_at.strftime('%d.%m.%Y %H:%M') }}</dd>
229
+ <dt class="col-sm-5">Статус:</dt>
230
+ <dd class="col-sm-7">
231
+ {% set status_colors = {'Новый': 'warning', 'Оплачен': 'info', 'Отправлен': 'primary', 'Доставлен': 'success', 'Отменён': 'danger'} %}
232
+ <span class="badge bg-{{ status_colors.get(order.status, 'secondary') }}
233
+ {% if order.status == 'Новый' %}text-dark{% endif %}">
234
+ {{ order.status }}
235
+ </span>
236
+ </dd>
237
+ <dt class="col-sm-5">Сумма:</dt>
238
+ <dd class="col-sm-7">{{ "%.2f"|format(order.total_price) }} ₽</dd>
239
+ {{ADMIN_ORDER_DETAIL_FIELDS}}
240
+ </dl>
241
+ <hr>
242
+ <h6>Товары:</h6>
243
+ <ul class="list-unstyled">
244
+ {% for item in order.items %}
245
+ <li>{{ item.product_name }} × {{ item.quantity }} — {{ "%.2f"|format(item.price * item.quantity) }} ₽</li>
246
+ {% endfor %}
247
+ </ul>
248
+ <hr>
249
+ <!-- Смена статуса -->
250
+ <h6>Изменить статус:</h6>
251
+ <form method="POST" action="{{ url_for('admin_order_status', order_id=order.id) }}" class="d-flex gap-2 align-items-center mb-3">
252
+ <select name="new_status" class="form-select form-select-sm" style="max-width: 200px;">
253
+ {% for s in order_statuses %}
254
+ <option value="{{ s }}" {% if order.status == s %}selected{% endif %}>{{ s }}</option>
255
+ {% endfor %}
256
+ </select>
257
+ <button type="submit" class="btn btn-sm btn-primary">Сохранить</button>
258
+ </form>
259
+ </div>
260
+ <div class="modal-footer d-flex justify-content-between">
261
+ <form method="POST" action="{{ url_for('admin_delete_order', order_id=order.id) }}"
262
+ onsubmit="return confirm('Удалить заказ #{{ order.id }}? Это действие необратимо.');">
263
+ <button type="submit" class="btn btn-sm btn-danger">🗑 Удалить заказ</button>
264
+ </form>
265
+ <button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Закрыть</button>
266
+ </div>
267
+ </div>
268
+ </div>
269
+ </div>
270
+ {% endfor %}
271
+ </div>
272
+ </div>
273
+
274
+ <!-- Популярные товары -->
275
+ <div class="card border-0 shadow-sm">
276
+ <div class="card-header bg-dark text-white">
277
+ <h5 class="mb-0">Популярные товары</h5>
278
+ </div>
279
+ <div class="card-body p-0">
280
+ <div class="table-responsive">
281
+ <table class="table table-hover align-middle mb-0">
282
+ <thead class="table-light">
283
+ <tr>
284
+ <th>Товар</th>
285
+ <th>Цена</th>
286
+ <th>Продано</th>
287
+ <th>На складе</th>
288
+ </tr>
289
+ </thead>
290
+ <tbody>
291
+ {% for item in popular_products %}
292
+ <tr>
293
+ <td><strong>{{ item.name }}</strong></td>
294
+ <td>{{ item.price|round(2) }} ₽</td>
295
+ <td>{{ item.sold_count }}</td>
296
+ <td>
297
+ {% if item.stock <= 5 %}
298
+ <span class="text-danger fw-bold">{{ item.stock }}</span>
299
+ {% else %}
300
+ {{ item.stock }}
301
+ {% endif %}
302
+ </td>
303
+ </tr>
304
+ {% else %}
305
+ <tr>
306
+ <td colspan="4" class="text-center text-muted py-4">Товаров пока нет</td>
307
+ </tr>
308
+ {% endfor %}
309
+ </tbody>
310
+ </table>
311
+ </div>
312
+ </div>
313
+ </div>
314
+ {% endblock %}
315
+
316
+ {% block extra_scripts %}
317
+ <script>
318
+ // ─── График заказов по статусам ──────────────────────────────
319
+ const ordersCtx = document.getElementById('ordersChart');
320
+ if (ordersCtx) {
321
+ const orderStats = {{ order_stats | tojson }};
322
+ new Chart(ordersCtx, {
323
+ type: 'doughnut',
324
+ data: {
325
+ labels: Object.keys(orderStats),
326
+ datasets: [{
327
+ data: Object.values(orderStats),
328
+ backgroundColor: [
329
+ '#ffc107', '#0dcaf0', '#0d6efd', '#198754', '#dc3545',
330
+ '#6c757d', '#fd7e14', '#20c997'
331
+ ],
332
+ borderWidth: 2
333
+ }]
334
+ },
335
+ options: {
336
+ responsive: true,
337
+ plugins: {
338
+ legend: { position: 'bottom' }
339
+ }
340
+ }
341
+ });
342
+ }
343
+
344
+ // ─── График выручки за 7 дней ────────────────────────────────
345
+ const revenueCtx = document.getElementById('revenueChart');
346
+ if (revenueCtx) {
347
+ const revenueData = {{ revenue_by_day | tojson }};
348
+ new Chart(revenueCtx, {
349
+ type: 'bar',
350
+ data: {
351
+ labels: Object.keys(revenueData),
352
+ datasets: [{
353
+ label: 'Выручка (₽)',
354
+ data: Object.values(revenueData),
355
+ backgroundColor: 'rgba(25, 135, 84, 0.6)',
356
+ borderColor: '#198754',
357
+ borderWidth: 1
358
+ }]
359
+ },
360
+ options: {
361
+ responsive: true,
362
+ plugins: {
363
+ legend: { display: false }
364
+ },
365
+ scales: {
366
+ y: { beginAtZero: true }
367
+ }
368
+ }
369
+ });
370
+ }
371
+ </script>
372
+ {% endblock %}