{% extends "base.html" %} {% block title %}Skladki Czlonkowskie - Norda Biznes Partner{% endblock %} {% block extra_css %} {% endblock %} {% block content %}

Skladki Czlonkowskie

{{ total_companies }}
Firm czlonkowskich
{{ paid_count }}
Oplaconych
{{ pending_count }}
Oczekujacych
{{ total_paid|int }} zł
Zebrano
{{ (total_due - total_paid)|int }} zł
Do zebrania
Opłacone 1 Niepełna wpłata 1 Oczekujące 1 Zaległe - Brak danych
{% if month %} {% endif %}

Lista firm {% if month %}({{ dict(months).get(month, month) }} {{ year }}){% else %}({{ year }}){% endif %}

{% if month %} {% endif %}
{% if month %}{% endif %} {% if month %} {% else %} {% endif %} {% for cf in companies_fees %} {% if month %} {% else %} {% for m in range(1, 13) %} {% endfor %} {% endif %} {% endfor %}
FirmaStatus Kwota Zaplacono Data platnosci AkcjeStyLutMarKwiMajCze LipSieWrzPazLisGru
{% if cf.fee %} {% endif %} {{ cf.company.name }} {% if cf.status == 'paid' %}Oplacone {% elif cf.status == 'pending' %}Oczekuje {% elif cf.status == 'overdue' %}Zalegle {% elif cf.status == 'partial' %}Czesciowe {% else %}Brak {% endif %} {% if cf.fee %}{{ cf.fee.amount }} zl{% else %}-{% endif %} {% if cf.fee and cf.fee.amount_paid %}{{ cf.fee.amount_paid }} zl{% else %}-{% endif %} {% if cf.fee and cf.fee.payment_date %}{{ cf.fee.payment_date }}{% else %}-{% endif %} {% if cf.fee and cf.status != 'paid' %} {% elif not cf.fee %} Brak rekordu {% endif %} {{ cf.company.name }} {% if cf.monthly_rate and cf.monthly_rate > 200 %} {{ cf.monthly_rate }} zł {% endif %} {% set fee = cf.months.get(m) %} {% if fee %} {{ m }}{% if fee.status == 'partial' %}{{ fee.amount_paid|int }}{% endif %} {% else %} - {% endif %}
{% endblock %} {% block extra_js %} // Modal system let confirmResolve = null; function showConfirm(message, options = {}) { return new Promise(resolve => { confirmResolve = resolve; document.getElementById('confirmModalIcon').textContent = options.icon || '❓'; document.getElementById('confirmModalTitle').textContent = options.title || 'Potwierdzenie'; document.getElementById('confirmModalMessage').innerHTML = message; document.getElementById('confirmModalOk').textContent = options.okText || 'OK'; document.getElementById('confirmModalOk').className = 'btn ' + (options.okClass || 'btn-primary'); document.getElementById('confirmModal').classList.add('active'); }); } function closeConfirm(result) { document.getElementById('confirmModal').classList.remove('active'); if (confirmResolve) { confirmResolve(result); confirmResolve = null; } } document.getElementById('confirmModalOk').addEventListener('click', () => closeConfirm(true)); document.getElementById('confirmModalCancel').addEventListener('click', () => closeConfirm(false)); document.getElementById('confirmModal').addEventListener('click', e => { if (e.target.id === 'confirmModal') closeConfirm(false); }); function showToast(message, type = 'info', duration = 4000) { const container = document.getElementById('toastContainer'); const icons = { success: '✓', error: '✕', warning: '⚠', info: 'ℹ' }; const toast = document.createElement('div'); toast.className = `toast ${type}`; toast.innerHTML = `${icons[type]||'ℹ'}${message}`; container.appendChild(toast); setTimeout(() => { toast.style.animation = 'toastOut 0.3s ease forwards'; setTimeout(() => toast.remove(), 300); }, duration); } async function generateFees() { const confirmed = await showConfirm('Czy na pewno chcesz wygenerować rekordy składek dla wszystkich firm na wybrany miesiąc?', { icon: '📋', title: 'Generowanie składek', okText: 'Generuj', okClass: 'btn-success' }); if (!confirmed) return; const formData = new FormData(); formData.append('year', {{ year }}); formData.append('month', {{ month or 'null' }}); try { const response = await fetch('{{ url_for("admin.admin_fees_generate") }}', { method: 'POST', body: formData, headers: { 'X-CSRFToken': '{{ csrf_token() }}' } }); const data = await response.json(); if (data.success) { showToast(data.message, 'success'); setTimeout(() => location.reload(), 1500); } else { showToast('Błąd: ' + data.error, 'error'); } } catch (err) { showToast('Błąd: ' + err, 'error'); } } function openPaymentModal(feeId, companyName, amount) { document.getElementById('modalFeeId').value = feeId; document.getElementById('modalCompanyName').value = companyName; document.getElementById('modalAmount').value = amount; document.getElementById('modalDate').value = new Date().toISOString().split('T')[0]; document.getElementById('paymentModal').classList.add('active'); } function closePaymentModal() { document.getElementById('paymentModal').classList.remove('active'); } document.getElementById('paymentForm').addEventListener('submit', async function(e) { e.preventDefault(); const feeId = document.getElementById('modalFeeId').value; const formData = new FormData(this); try { const response = await fetch('/admin/fees/' + feeId + '/mark-paid', { method: 'POST', body: formData, headers: { 'X-CSRFToken': '{{ csrf_token() }}' } }); const data = await response.json(); if (data.success) { closePaymentModal(); showToast(data.message, 'success'); setTimeout(() => location.reload(), 1500); } else { showToast('Błąd: ' + data.error, 'error'); } } catch (err) { showToast('Błąd: ' + err, 'error'); } }); function toggleSelectAll() { const selectAll = document.getElementById('selectAll'); const checkboxes = document.querySelectorAll('.fee-checkbox:not(:disabled)'); checkboxes.forEach(cb => cb.checked = selectAll.checked); } async function bulkMarkPaid() { const checkboxes = document.querySelectorAll('.fee-checkbox:checked'); if (checkboxes.length === 0) { showToast('Zaznacz przynajmniej jedną składkę', 'warning'); return; } const confirmed = await showConfirm(`Czy na pewno chcesz oznaczyć ${checkboxes.length} składek jako opłacone?`, { icon: '💰', title: 'Oznaczanie płatności', okText: 'Oznacz', okClass: 'btn-success' }); if (!confirmed) return; const formData = new FormData(); checkboxes.forEach(cb => formData.append('fee_ids[]', cb.value)); try { const response = await fetch('{{ url_for("admin.admin_fees_bulk_mark_paid") }}', { method: 'POST', body: formData, headers: { 'X-CSRFToken': '{{ csrf_token() }}' } }); const data = await response.json(); if (data.success) { showToast(data.message, 'success'); setTimeout(() => location.reload(), 1500); } else { showToast('Błąd: ' + data.error, 'error'); } } catch (err) { showToast('Błąd: ' + err, 'error'); } } // Close modal on outside click document.getElementById('paymentModal').addEventListener('click', function(e) { if (e.target === this) { closePaymentModal(); } }); {% endblock %}