# Rozliczenia — Billing cross-project

> Wystawiaj rozliczenia, zamrażaj tickety i pilnuj budżetu projektów

Moduł Rozliczeń pozwala łączyć tickety z wielu projektów w jedno rozliczenie, prowadzić je przez workflow statusów (draft → wysłane → opłacone) i zarządzać załącznikami (faktury, raporty, protokoły odbioru). Po wysłaniu rozliczenia tickety są zamrażane — edycja zablokowana, ale status nadal można zmieniać na tablicy Kanban.

## Funkcje

- **Cross-project M2M**: Jedno rozliczenie może obejmować wiele projektów. Tickety podpinasz z każdego z powiązanych projektów — idealne dla freelancerów i agencji.
- **Workflow statusów (dwukierunkowy)**: Draft → Wysłane → Opłacone z automatycznymi timestampami (sent_at, paid_at). Cofanie statusów dozwolone — admin może odmrozić tickety gdy trzeba.
- **Zamrażanie ticketów**: Po wysłaniu rozliczenia powiązane tickety są zamrażane — pełna edycja (tytuł, opis, priorytet) zablokowana. Sam status nadal można zmieniać drag-dropem na Kanbanie.
- **Załączniki z kategoriami**: Upload faktur, raportów, protokołów odbioru do MinIO z kategoriami (invoice, report, acceptance_protocol, other) i stanem (draft/signed). Limit 200MB, 10 plików na rozliczenie.
- **RBAC z granularnością**: Uprawnienia rozliczenia:read/write/delete per projekt. User bez uprawnień nie widzi sekcji na ticketach (ukryta w HTML i MCP) — nie tylko disabled.
- **Globalny widok cross-project**: Strona /dashboard/rozliczenia pokazuje rozliczenia z wszystkich projektów, do których masz dostęp. Filtry po projektach, statusie i dacie.

## Jak to działa

1. **Utwórz rozliczenie**: Nowe rozliczenie (ROZ-N) z okresem, nazwą i wybranymi projektami. Wymaga rozliczenia:write w każdym z projektów.
2. **Podepnij tickety**: Search z autocomplete (HTMX) — szukaj po numerze (MNX-12) lub tytule. Tylko tickety z projektów settlement.
3. **Dodaj załączniki**: Upload faktury, raportu lub protokołu odbioru. Kategorie i stan (draft/signed) do wyboru. Podgląd/pobranie/usuwanie.
4. **Wyślij i zamroź**: Zmień status na 'Wysłane' — tickety stają się zamrożone (edycja 403), ale status na Kanbanie dalej działa.
5. **Oznacz jako opłacone**: Po otrzymaniu zapłaty — klik 'Oznacz jako opłacone'. paid_at ustawiany, sent_at zachowany. Tickety nadal zamrożone.
6. **Cofnij jeśli trzeba**: Admin może cofnąć status (paid → sent → draft). Tickety automatycznie odmrażają się przy draft.

## AI i MCP

Wszystkie operacje na rozliczeniach dostępne przez MCP — agent AI może tworzyć rozliczenia, podpinać tickety, uploadować załączniki (base64) i zmieniać statusy. RBAC egzekwowany przez każdy tool.

- `list_settlements`: Lista rozliczeń projektu z filtrami (status, okres, strony).
- `get_settlement`: Szczegóły rozliczenia: projekty, tickety, załączniki, status, timestampy.
- `create_settlement`: Utwórz rozliczenie cross-project (walidacja write we wszystkich projektach).
- `update_settlement`: Edycja rozliczenia w statusie draft (nazwa, okres, projekty, notatki).
- `delete_settlement`: Soft delete rozliczenia w statusie draft.
- `change_settlement_status`: Workflow draft ↔ sent ↔ paid z walidacją przejść i timestampami.
- `link_ticket_to_settlement`: Podepnij ticket (tylko draft + walidacja cross-project).
- `unlink_ticket_from_settlement`: Odepnij ticket od rozliczenia.
- `list_settlement_tickets`: Lista powiązanych ticketów (klucze + tytuły + statusy).
- `add_settlement_attachment`: Upload pliku jako base64 → MinIO. Kategorie: invoice/report/acceptance_protocol/other.
- `get_settlement_attachment`: Pobierz załącznik jako base64 z mime_type i filename.
- `list_settlement_attachments`: Lista metadanych załączników (bez bytes).
- `delete_settlement_attachment`: Usuń załącznik (tylko draft).

## Szczegóły techniczne

- **Model danych**: Settlement + M2M SettlementProject + M2M SettlementTicket + 1:N SettlementAttachment. Soft delete (is_active=False).
- **Workflow**: ALLOWED_SETTLEMENT_TRANSITIONS: dict[str, frozenset[str]] — state machine z walidacją przejść i timestampami (sent_at, paid_at).
- **Storage**: MinIO dla załączników, PostgreSQL dla metadanych. Upload i download w ThreadPoolExecutor (async-friendly).
- **Freeze logic**: is_ticket_frozen(ticket) — dynamiczna funkcja sprawdza czy ticket jest podpięty do settlement w status sent/paid. Automatyczne odmrożenie gdy settlement wraca do draft.
- **RBAC**: Nowy klucz 'rozliczenia' w PERMISSION_MODULES (read/write/delete). Walidacja per projekt — cross-project settlements wymagają write we wszystkich projektach.
- **Regresja z MON-62**: Zamrażanie chroni integralność wysłanych rozliczeń. Same status update jest dozwolone dla frozen ticketów (drag-drop na Kanbanie) — pełna edycja zablokowana.
