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>
128 lines
5.3 KiB
Markdown
128 lines
5.3 KiB
Markdown
# 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
|
|
|
|
```bash
|
|
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:
|
|
|
|
```bash
|
|
scripts/hesk-import/hesk-import.sh --domain=firma.pl
|
|
```
|
|
|
|
Try a small batch for real before committing to the whole thing:
|
|
|
|
```bash
|
|
scripts/hesk-import/hesk-import.sh --domain=firma.pl --limit=10 --commit
|
|
```
|
|
|
|
Then the full import:
|
|
|
|
```bash
|
|
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:
|
|
|
|
```bash
|
|
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):
|
|
|
|
```bash
|
|
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:
|
|
|
|
```bash
|
|
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`](../../src/app/Console/Commands/ImportHeskTickets.php).
|