Some checks are pending
NordaBiz Tests / Unit & Integration Tests (push) Waiting to run
NordaBiz Tests / E2E Tests (Playwright) (push) Blocked by required conditions
NordaBiz Tests / Smoke Tests (Production) (push) Blocked by required conditions
NordaBiz Tests / Send Failure Notification (push) Blocked by required conditions
- AdmissionWorkflowLog model + migration - services/admission_workflow.py — auto-extract admitted companies from board meeting proceedings, match to existing companies, create placeholders, notify Office Managers (in-app + email) - Hook in meeting_publish_protocol() — triggers workflow in background - Dashboard /rada/posiedzenia/ID/przyjecia for Office Manager - /nowi-czlonkowie redesigned: grouped by board meetings, fixed Polish characters, removed days-based filter Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
216 lines
7.4 KiB
HTML
216 lines
7.4 KiB
HTML
{% extends "base.html" %}
|
|
|
|
{% block title %}Przyjęcia nowych członków — Posiedzenie {{ meeting.meeting_identifier }} — Norda Biznes Partner{% endblock %}
|
|
|
|
{% block extra_css %}
|
|
<style>
|
|
.admissions-header {
|
|
margin-bottom: var(--spacing-xl);
|
|
}
|
|
.admissions-header h1 {
|
|
font-size: var(--font-size-2xl);
|
|
color: var(--text-primary);
|
|
}
|
|
.admissions-header p {
|
|
color: var(--text-secondary);
|
|
margin-top: var(--spacing-xs);
|
|
}
|
|
.admissions-stats {
|
|
display: flex;
|
|
gap: var(--spacing-lg);
|
|
margin-bottom: var(--spacing-xl);
|
|
}
|
|
.stat-card {
|
|
background: var(--surface);
|
|
border-radius: var(--radius);
|
|
padding: var(--spacing-md) var(--spacing-lg);
|
|
border: 1px solid var(--border);
|
|
text-align: center;
|
|
min-width: 120px;
|
|
}
|
|
.stat-card .stat-value {
|
|
font-size: var(--font-size-2xl);
|
|
font-weight: 700;
|
|
color: var(--primary);
|
|
}
|
|
.stat-card .stat-label {
|
|
font-size: var(--font-size-sm);
|
|
color: var(--text-secondary);
|
|
margin-top: 2px;
|
|
}
|
|
.stat-card.pending .stat-value { color: #D97706; }
|
|
.stat-card.active .stat-value { color: var(--success); }
|
|
|
|
.companies-table {
|
|
width: 100%;
|
|
border-collapse: collapse;
|
|
background: var(--surface);
|
|
border-radius: var(--radius);
|
|
overflow: hidden;
|
|
border: 1px solid var(--border);
|
|
}
|
|
.companies-table th {
|
|
text-align: left;
|
|
padding: var(--spacing-sm) var(--spacing-md);
|
|
background: var(--background);
|
|
font-size: var(--font-size-sm);
|
|
font-weight: 600;
|
|
color: var(--text-secondary);
|
|
text-transform: uppercase;
|
|
letter-spacing: 0.5px;
|
|
}
|
|
.companies-table td {
|
|
padding: var(--spacing-sm) var(--spacing-md);
|
|
border-top: 1px solid var(--border);
|
|
font-size: var(--font-size-sm);
|
|
}
|
|
.status-badge {
|
|
display: inline-block;
|
|
padding: 2px 8px;
|
|
border-radius: var(--radius-sm);
|
|
font-size: var(--font-size-xs);
|
|
font-weight: 600;
|
|
}
|
|
.status-badge.active {
|
|
background: #D1FAE5;
|
|
color: #065F46;
|
|
}
|
|
.status-badge.pending {
|
|
background: #FEF3C7;
|
|
color: #92400E;
|
|
}
|
|
.action-btn {
|
|
display: inline-block;
|
|
padding: 4px 12px;
|
|
border-radius: var(--radius-sm);
|
|
font-size: var(--font-size-xs);
|
|
font-weight: 500;
|
|
text-decoration: none;
|
|
border: 1px solid var(--border);
|
|
color: var(--text-primary);
|
|
transition: var(--transition);
|
|
}
|
|
.action-btn:hover {
|
|
background: var(--primary);
|
|
color: white;
|
|
border-color: var(--primary);
|
|
}
|
|
.workflow-log {
|
|
margin-top: var(--spacing-xl);
|
|
background: var(--surface);
|
|
border: 1px solid var(--border);
|
|
border-radius: var(--radius);
|
|
padding: var(--spacing-md);
|
|
}
|
|
.workflow-log h3 {
|
|
font-size: var(--font-size-base);
|
|
margin-bottom: var(--spacing-sm);
|
|
color: var(--text-secondary);
|
|
}
|
|
.workflow-log .log-item {
|
|
font-size: var(--font-size-sm);
|
|
color: var(--text-secondary);
|
|
padding: 2px 0;
|
|
}
|
|
</style>
|
|
{% endblock %}
|
|
|
|
{% block content %}
|
|
<div class="admissions-header">
|
|
<a href="{{ url_for('board.meeting_view', meeting_id=meeting.id) }}" style="color: var(--text-secondary); text-decoration: none; font-size: var(--font-size-sm);">← Powrót do posiedzenia</a>
|
|
<h1>Przyjęcia nowych członków</h1>
|
|
<p>Posiedzenie Rady {{ meeting.meeting_identifier }} — {{ meeting.meeting_date.strftime('%d.%m.%Y') }}</p>
|
|
</div>
|
|
|
|
{% set active_count = admitted|selectattr('status', 'equalto', 'active')|list|length %}
|
|
{% set pending_count = admitted|length - active_count %}
|
|
|
|
<div class="admissions-stats">
|
|
<div class="stat-card">
|
|
<div class="stat-value">{{ admitted|length }}</div>
|
|
<div class="stat-label">Przyjętych firm</div>
|
|
</div>
|
|
<div class="stat-card active">
|
|
<div class="stat-value">{{ active_count }}</div>
|
|
<div class="stat-label">Profil uzupełniony</div>
|
|
</div>
|
|
<div class="stat-card pending">
|
|
<div class="stat-value">{{ pending_count }}</div>
|
|
<div class="stat-label">Wymaga uzupełnienia</div>
|
|
</div>
|
|
</div>
|
|
|
|
{% if admitted %}
|
|
<table class="companies-table">
|
|
<thead>
|
|
<tr>
|
|
<th>Firma</th>
|
|
<th>Status profilu</th>
|
|
<th>NIP</th>
|
|
<th>Kategoria</th>
|
|
<th>Akcje</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
{% for company in admitted %}
|
|
<tr>
|
|
<td>
|
|
<strong>{{ company.name }}</strong>
|
|
{% if company.address_city %}
|
|
<br><span style="color: var(--text-muted); font-size: var(--font-size-xs);">{{ company.address_city }}</span>
|
|
{% endif %}
|
|
</td>
|
|
<td>
|
|
{% if company.status == 'active' %}
|
|
<span class="status-badge active">Aktywny</span>
|
|
{% else %}
|
|
<span class="status-badge pending">Do uzupełnienia</span>
|
|
{% endif %}
|
|
</td>
|
|
<td>{{ company.nip or '—' }}</td>
|
|
<td>{{ company.category.name if company.category else '—' }}</td>
|
|
<td>
|
|
{% if company.status == 'active' %}
|
|
<a href="{{ url_for('public.company_detail_by_slug', slug=company.slug) }}" class="action-btn" target="_blank">Profil</a>
|
|
{% else %}
|
|
<a href="{{ url_for('admin.admin_company_detail', company_id=company.id) }}" class="action-btn" style="border-color: #D97706; color: #92400E;">Uzupełnij</a>
|
|
{% endif %}
|
|
<a href="{{ url_for('admin.admin_company_detail', company_id=company.id) }}" class="action-btn">Edytuj</a>
|
|
</td>
|
|
</tr>
|
|
{% endfor %}
|
|
</tbody>
|
|
</table>
|
|
{% else %}
|
|
<div style="text-align: center; padding: var(--spacing-2xl); color: var(--text-secondary); background: var(--surface); border-radius: var(--radius);">
|
|
<p>Brak firm przypisanych do tego posiedzenia.</p>
|
|
<p style="font-size: var(--font-size-sm); margin-top: var(--spacing-sm);">Firmy zostaną automatycznie przypisane po opublikowaniu protokołu.</p>
|
|
</div>
|
|
{% endif %}
|
|
|
|
{% if workflow_log %}
|
|
<div class="workflow-log">
|
|
<h3>Log workflow przyjęć</h3>
|
|
<div class="log-item">Wykonano: {{ workflow_log.executed_at|local_time }}</div>
|
|
<div class="log-item">Status: {{ workflow_log.status }}</div>
|
|
{% if workflow_log.extracted_companies %}
|
|
<div class="log-item">Wyodrębniono z protokołu: {{ workflow_log.extracted_companies|length }} firm</div>
|
|
{% endif %}
|
|
{% if workflow_log.matched_companies %}
|
|
<div class="log-item">Dopasowano do istniejących: {{ workflow_log.matched_companies|length }}</div>
|
|
{% endif %}
|
|
{% if workflow_log.created_companies %}
|
|
<div class="log-item">Utworzono nowe profile: {{ workflow_log.created_companies|length }}</div>
|
|
{% endif %}
|
|
{% if workflow_log.skipped %}
|
|
<div class="log-item">Pominięto (już przypisane): {{ workflow_log.skipped|length }}</div>
|
|
{% endif %}
|
|
<div class="log-item">Powiadomienia: {{ workflow_log.notifications_sent }} in-app, {{ workflow_log.emails_sent }} email</div>
|
|
{% if workflow_log.error_message %}
|
|
<div class="log-item" style="color: var(--error);">Błąd: {{ workflow_log.error_message }}</div>
|
|
{% endif %}
|
|
</div>
|
|
{% endif %}
|
|
|
|
{% endblock %}
|