usuniecie zbednego kodu
This commit is contained in:
87
app.py
87
app.py
@@ -2456,9 +2456,8 @@ def admin_receipts(id):
|
||||
if id == "all":
|
||||
all_filenames = {r.filename for r in Receipt.query.all()}
|
||||
|
||||
pagination = (
|
||||
Receipt.query.order_by(Receipt.uploaded_at.desc())
|
||||
.paginate(page=page, per_page=per_page, error_out=False)
|
||||
pagination = Receipt.query.order_by(Receipt.uploaded_at.desc()).paginate(
|
||||
page=page, per_page=per_page, error_out=False
|
||||
)
|
||||
|
||||
receipts_paginated = pagination.items
|
||||
@@ -2839,11 +2838,13 @@ def list_products():
|
||||
per_page = request.args.get("per_page", 125, type=int)
|
||||
per_page = max(1, min(per_page, 300))
|
||||
|
||||
# Pobierz wszystkie itemy – tylko name, id i relacje potrzebne do odtworzenia unikalnych
|
||||
all_items = Item.query.options(
|
||||
joinedload(Item.shopping_list),
|
||||
joinedload(Item.added_by_user)
|
||||
).order_by(Item.id.desc()).all()
|
||||
all_items = (
|
||||
Item.query.options(
|
||||
joinedload(Item.added_by_user),
|
||||
)
|
||||
.order_by(Item.id.desc())
|
||||
.all()
|
||||
)
|
||||
|
||||
seen_names = set()
|
||||
unique_items = []
|
||||
@@ -2853,38 +2854,64 @@ def list_products():
|
||||
unique_items.append(item)
|
||||
seen_names.add(key)
|
||||
|
||||
# Paginacja ręczna na unikalnych
|
||||
total_items = len(unique_items)
|
||||
total_pages = (total_items + per_page - 1) // per_page
|
||||
start = (page - 1) * per_page
|
||||
end = start + per_page
|
||||
items = unique_items[start:end]
|
||||
|
||||
# Słownik użytkowników (ograniczony do używanych)
|
||||
user_ids = {item.added_by for item in items if item.added_by}
|
||||
users = User.query.filter(User.id.in_(user_ids)).all()
|
||||
users = User.query.filter(User.id.in_(user_ids)).all() if user_ids else []
|
||||
users_dict = {u.id: u.username for u in users}
|
||||
|
||||
# Wszystkie sugestie – do dopasowań
|
||||
suggestions = SuggestedProduct.query.all()
|
||||
all_suggestions_dict = {
|
||||
(s.name or "").strip().lower(): s for s in suggestions if s.name and s.name.strip()
|
||||
(s.name or "").strip().lower(): s
|
||||
for s in suggestions
|
||||
if s.name and s.name.strip()
|
||||
}
|
||||
used_suggestion_names = {(i.name or "").strip().lower() for i in unique_items}
|
||||
|
||||
used_suggestion_names = {(item.name or "").strip().lower() for item in unique_items}
|
||||
|
||||
# Powiązane i osierocone
|
||||
suggestions_dict = {
|
||||
name: all_suggestions_dict[name]
|
||||
for name in used_suggestion_names
|
||||
if name in all_suggestions_dict
|
||||
}
|
||||
|
||||
orphan_suggestions = [
|
||||
s for name, s in all_suggestions_dict.items()
|
||||
s
|
||||
for name, s in all_suggestions_dict.items()
|
||||
if name not in used_suggestion_names
|
||||
]
|
||||
|
||||
orphan_names_lower = {(s.name or "").strip().lower() for s in orphan_suggestions}
|
||||
if orphan_names_lower:
|
||||
items_for_orphans = (
|
||||
Item.query.filter(func.lower(Item.name).in_(orphan_names_lower))
|
||||
.filter(Item.added_by.isnot(None))
|
||||
.options(joinedload(Item.added_by_user))
|
||||
.order_by(Item.id.desc())
|
||||
.all()
|
||||
)
|
||||
name_to_user = {}
|
||||
for it in items_for_orphans:
|
||||
key = (it.name or "").strip().lower()
|
||||
if key not in name_to_user and it.added_by:
|
||||
name_to_user[key] = it.added_by
|
||||
suggestion_added_by_map = {
|
||||
s.id: name_to_user.get((s.name or "").strip().lower())
|
||||
for s in orphan_suggestions
|
||||
}
|
||||
missing_user_ids = {
|
||||
uid
|
||||
for uid in suggestion_added_by_map.values()
|
||||
if uid and uid not in users_dict
|
||||
}
|
||||
if missing_user_ids:
|
||||
extra_users = User.query.filter(User.id.in_(missing_user_ids)).all()
|
||||
users_dict.update({u.id: u.username for u in extra_users})
|
||||
else:
|
||||
suggestion_added_by_map = {}
|
||||
|
||||
query_string = urlencode({k: v for k, v in request.args.items() if k != "page"})
|
||||
|
||||
return render_template(
|
||||
@@ -2893,10 +2920,12 @@ def list_products():
|
||||
users_dict=users_dict,
|
||||
suggestions_dict=suggestions_dict,
|
||||
orphan_suggestions=orphan_suggestions,
|
||||
suggestion_added_by_map=suggestion_added_by_map,
|
||||
page=page,
|
||||
per_page=per_page,
|
||||
total_pages=total_pages,
|
||||
query_string=query_string,
|
||||
total_items=total_items,
|
||||
)
|
||||
|
||||
|
||||
@@ -3000,7 +3029,6 @@ def recalculate_filesizes_all():
|
||||
return redirect(url_for("admin_receipts", id="all"))
|
||||
|
||||
|
||||
|
||||
@app.route("/admin/mass_edit_categories", methods=["GET", "POST"])
|
||||
@login_required
|
||||
@admin_required
|
||||
@@ -3034,7 +3062,9 @@ def admin_mass_edit_categories():
|
||||
l.categories.extend(cats)
|
||||
db.session.commit()
|
||||
flash("Zaktualizowano kategorie dla wybranych list", "success")
|
||||
return redirect(url_for("admin_mass_edit_categories", page=page, per_page=per_page))
|
||||
return redirect(
|
||||
url_for("admin_mass_edit_categories", page=page, per_page=per_page)
|
||||
)
|
||||
|
||||
query_string = urlencode({k: v for k, v in request.args.items() if k != "page"})
|
||||
|
||||
@@ -3071,14 +3101,15 @@ def admin_list_items_json(list_id):
|
||||
purchased_count = sum(1 for item in l.items if item.purchased)
|
||||
total_expense = sum(exp.amount for exp in l.expenses)
|
||||
|
||||
return jsonify({
|
||||
"title": l.title,
|
||||
"items": items,
|
||||
"total_count": len(l.items),
|
||||
"purchased_count": purchased_count,
|
||||
"total_expense": round(total_expense, 2)
|
||||
})
|
||||
|
||||
return jsonify(
|
||||
{
|
||||
"title": l.title,
|
||||
"items": items,
|
||||
"total_count": len(l.items),
|
||||
"purchased_count": purchased_count,
|
||||
"total_expense": round(total_expense, 2),
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
@app.route("/healthcheck")
|
||||
|
@@ -9,11 +9,9 @@
|
||||
|
||||
<div class="card bg-dark text-white mb-5">
|
||||
<div class="card-body">
|
||||
|
||||
|
||||
<div class="card-header d-flex justify-content-between align-items-center">
|
||||
<h4 class="m-0">📦 Produkty (z synchronizacją sugestii)</h4>
|
||||
<span class="badge bg-info">{{ items|length }} produktów</span>
|
||||
<h4 class="m-0">📦 Produkty (z synchronizacją sugestii o unikalnych nazwach)</h4>
|
||||
<span class="badge bg-info">{{ total_items }} produktów</span>
|
||||
</div>
|
||||
<div class="card-body p-0">
|
||||
<table class="table table-dark table-striped align-middle sortable">
|
||||
@@ -22,8 +20,7 @@
|
||||
<th>ID</th>
|
||||
<th>Nazwa</th>
|
||||
<th>Dodany przez</th>
|
||||
<th>Sugestia</th>
|
||||
<th>Lista</th>
|
||||
<th>Akcja</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@@ -49,26 +46,11 @@
|
||||
Synchronizuj</button>
|
||||
{% endif %}
|
||||
</td>
|
||||
<td>
|
||||
<div class="btn-group btn-group-sm" role="group">
|
||||
<button type="button" class="btn btn-outline-light disabled" data-bs-toggle="tooltip"
|
||||
data-bs-title="{{ item.shopping_list.title }}">
|
||||
ID: {{ item.list_id }}
|
||||
</button>
|
||||
<a href="{{ url_for('view_list', list_id=item.list_id) }}" class="btn btn-outline-light">
|
||||
📄 Otwórz
|
||||
</a>
|
||||
<button type="button" class="btn btn-outline-light preview-btn" data-list-id="{{ item.list_id }}">
|
||||
🔍 Podgląd
|
||||
</button>
|
||||
</div>
|
||||
</td>
|
||||
|
||||
</tr>
|
||||
{% endfor %}
|
||||
{% if items|length == 0 %}
|
||||
<tr>
|
||||
<td colspan="5" class="text-center text-muted">Brak produktów do wyświetlenia.</td>
|
||||
<td colspan="5" class="text-center">Pusta lista produktów.</td>
|
||||
</tr>
|
||||
{% endif %}
|
||||
</tbody>
|
||||
@@ -90,6 +72,7 @@
|
||||
<tr>
|
||||
<th>ID</th>
|
||||
<th>Nazwa</th>
|
||||
<th>Dodany przez</th>
|
||||
<th>Akcje</th>
|
||||
</tr>
|
||||
</thead>
|
||||
@@ -99,6 +82,14 @@
|
||||
<tr>
|
||||
<td>{{ suggestion.id }}</td>
|
||||
<td class="fw-bold"><span class="badge bg-primary">{{ suggestion.name }}</span></td>
|
||||
<td>
|
||||
{% set uid = suggestion_added_by_map.get(suggestion.id) %}
|
||||
{% if uid and users_dict.get(uid) %}
|
||||
👤 {{ users_dict[uid] }} ({{ uid }})
|
||||
{% else %}
|
||||
-
|
||||
{% endif %}
|
||||
</td>
|
||||
<td>
|
||||
<button class="btn btn-sm btn-outline-danger delete-suggestion-btn"
|
||||
data-suggestion-id="{{ suggestion.id }}">🗑️ Usuń</button>
|
||||
@@ -108,7 +99,7 @@
|
||||
{% endfor %}
|
||||
{% if suggestions_dict|length == 0 %}
|
||||
<tr>
|
||||
<td colspan="3" class="text-center text-muted">Brak sugestii do wyświetlenia.</td>
|
||||
<td colspan="3" class="text-center">Brak sugestii do wyświetlenia.</td>
|
||||
</tr>
|
||||
{% endif %}
|
||||
</tbody>
|
||||
@@ -145,24 +136,8 @@
|
||||
</nav>
|
||||
</div>
|
||||
|
||||
<!-- Modal podglądu produktów -->
|
||||
<div class="modal fade" id="productPreviewModal" tabindex="-1" aria-labelledby="previewModalLabel" aria-hidden="true">
|
||||
<div class="modal-dialog modal-lg modal-dialog-scrollable">
|
||||
<div class="modal-content bg-dark text-white">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title" id="previewModalLabel">Podgląd produktów</h5>
|
||||
<button type="button" class="btn-close btn-close-white" data-bs-dismiss="modal" aria-label="Zamknij"></button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<ul id="product-list" class="list-group list-group-flush"></ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% block scripts %}
|
||||
<script src="{{ url_for('static_bp.serve_js', filename='product_suggestion.js') }}"></script>
|
||||
<script src="{{ url_for('static_bp.serve_js', filename='preview_list_modal.js') }}"></script>
|
||||
{% endblock %}
|
||||
|
||||
{% endblock %}
|
Reference in New Issue
Block a user