Files
Kacper 4b70b910a9 v1.5.0
Co nowego:
- Podgląd logów w panelu admina (Admin > Logi) — pliki storage/logs/*.log
  bez potrzeby dostępu do kontenera, z filtrami poziomu/tekstu/liczby wpisów
  i auto-odświeżaniem.
- Filtr „Bez kategorii” w kolejce operatora — izoluje zgłoszenia bez
  przypisanej kategorii/podkategorii.
- Narzędzie importu z Heska: już nie tworzy automatycznie kont klientów dla
  nieznanych e-maili (pomija takie zgłoszenia zamiast zakładać konto),
  łączy odpowiedzi/właścicieli zgłoszeń z realnymi kontami operatorów po
  e-mailu, nowe flagi --assign-operators i --fix-closed-dates do
  donaprawiania wcześniejszych importów, dedykowany log
  storage/logs/hesk-import.log.
- Poprawka: pulpit statystyk operatora (rozkład wg kategorii/podkategorii i
  filtr kategorii) pomijał zgłoszenia przypisane do samej kategorii bez
  podkategorii (np. z poczty IMAP) — teraz liczone poprawnie.
- Poprawka: błąd JS i zawieszone w tle liczniki przy nawigacji z widoku z
  aktywnym licznikiem (najbardziej odczuwalne w liczniku czasu pracy
  operatora).
- Porządki w bazie: usunięte niewykorzystywane kolumny
  (users.remember_token, users.email_verified_at,
  email_templates.trigger_label); wartości pól dodatkowych, stan
  triage/podsumowania AI i powiązany sprzęt Snipe-IT przeniesione z tabeli
  tickets do osobnych tabel (ticket_field_values, ticket_ai_summaries,
  ticket_snipeit_assets) — bez zmiany zachowania, ale pola dodatkowe są
  teraz efektywnie przeszukiwalne; dodane brakujące indeksy na 4 tabelach
  pivot; tickets.source/ticket_messages.source walidowane względem znanego
  zestawu wartości.

Zaktualizowana dokumentacja: README, CLAUDE.md, ARCHITECTURE.md,
CHANGELOG.md, wiki/admin, wiki/operator.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-05 14:28:03 +02:00

5.3 KiB

Hesk 3.x import

One-time historical migration of tickets (with full reply/note history) from a Hesk 3.x helpdesk database into this app, restricted to a single e-mail domain. Read-only against the Hesk database — never writes there.

This is not an ongoing sync. Run it once to backfill history from an old Hesk install; it doesn't pick up edits made in Hesk afterward.

What it does

  • Matches Hesk tickets by requester e-mail domain (--domain=firma.pl).
  • Imports each ticket's subject/body, status, priority, and full reply + internal-note history, converting Hesk's <br />-laden "plain" text into real line breaks.
  • Maps Hesk categories to this app's categories by exact (case/whitespace- insensitive) name match. A Hesk category with no match is skipped by default — pass --include-unmapped-categories to import those tickets anyway, uncategorized.
  • Auto-assigns a team when every subcategory under the matched category routes to the same single team (same rule TicketService::autoAssignTeam() uses for normal ticket creation); ambiguous categories are left unrouted.
  • Finds the local client account per requester e-mail (matched by e-mail, adding the client role if it doesn't have it yet). Never creates a User — the servicedesk user base is treated as authoritative/complete, so a Hesk requester e-mail with no matching account means that ticket is skipped (reported at the end, with the list of skipped e-mails).
  • Hesk staff replies/notes are linked to a real operator account when the Hesk staff member's e-mail matches an existing servicedesk operator/admin account; otherwise they fall back to showing the correct staff name and "operator" badge via author_name only, without a clickable user behind it (this script never creates operator accounts either).
  • Every imported ticket also stores its source Hesk ticket id (tickets.hesk_ticket_id, unique). This is a second, DB-level guard against duplicate imports on top of the state file below — if the state file is ever lost or out of sync, a re-run still can't create a duplicate ticket for the same Hesk id.
  • A ticket's Hesk owner is matched the same way as reply/note authors and set as assignee_id, so imported tickets show up correctly assigned in the operator queue instead of everything landing in "Nieprzypisane".

Setup

cp scripts/hesk-import/.env.example scripts/hesk-import/.env

Fill in scripts/hesk-import/.env with the Hesk database's host/port/database/username/password. That file is gitignored — it holds real credentials for a database this app otherwise has no access to.

Usage

Always dry-run first — it reports what would happen without writing anything:

scripts/hesk-import/hesk-import.sh --domain=firma.pl

Try a small batch for real before committing to the whole thing:

scripts/hesk-import/hesk-import.sh --domain=firma.pl --limit=10 --commit

Then the full import:

scripts/hesk-import/hesk-import.sh --domain=firma.pl --commit

Safe to re-run (including after an interrupted/crashed run): already-imported Hesk ticket ids are tracked in storage/app/hesk-import-state.json inside the app container and skipped on subsequent runs.

Backfilling team assignment

If tickets were already imported before team-by-category mapping existed (or teams/subcategories changed since), backfill team_id on existing imported tickets without importing anything new:

scripts/hesk-import/hesk-import.sh --assign-teams --commit

Fixing closed-ticket dates

New imports already use Hesk's dedicated closedat column (not lastchange, which moves forward on any later edit — e.g. a note added after closing) for a closed ticket's date, and record a matching "Status zmieniony na: Zamknięte" history entry. To apply the same correction to tickets imported before this existed (including the original import, from before hesk_ticket_id was even tracked — matched back to Hesk via the unique (email, created_at) pair instead):

scripts/hesk-import/hesk-import.sh --fix-closed-dates --commit

Doesn't import anything new; safe to re-run (already-correct tickets are left alone).

Backfilling ticket ownership

New imports already set assignee_id from Hesk's ticket owner. To apply the same to tickets imported before this existed:

scripts/hesk-import/hesk-import.sh --assign-operators --commit

Only touches tickets with no assignee_id yet (never overwrites a manual reassignment made since import) and never invents an assignment — a Hesk owner of 0 or one with no matching servicedesk account is left unassigned, unless it's one of the two ids in ImportHeskTickets::DELETED_STAFF_REASSIGNMENT (Hesk staff accounts deleted since, with historical tickets explicitly reassigned to a current operator per the app owner).

How it's wired up

hesk-import.sh is a thin wrapper: it loads .env in this folder, then runs php artisan hesk:import inside the app container via docker compose exec, passing the Hesk DB credentials as one-off environment variables (they never touch the app's own .env or get persisted anywhere but the state file). The actual import logic lives in ../../src/app/Console/Commands/ImportHeskTickets.php.