Commit Graph

33 Commits

Author SHA1 Message Date
fs
ea786f5341 feat(helpdesk): add multi-tenant BC connection settings with risk radar refinements
Introduce per-tenant override for helpdesk BC connection config.
New table helpdesk_tenant_settings stores tenant-specific credentials
with encrypted secrets (AES-256-GCM). EffectiveHelpdeskSettingsService
resolves global vs tenant config per request. Settings UI extended with
tenant override tab, toggle, and dual editing mode.

All runtime consumers (OData, SOAP, OAuth) read through the new
resolver. Token cache flushed on any config change. Default behavior
unchanged — tenants use global config until override explicitly enabled.

Also includes risk radar UI refinements: Stripe-style card redesign
with accent borders and score pills, removal of redundant KPI tiles
and search, and filtering of zero-score entries.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-06 10:29:59 +02:00
fs
97dbc7f57b fix(helpdesk): reset card margin-bottom and tighten risk level thresholds
- margin-bottom: 0 on cards to override article shell default
- Level thresholds stricter: high >= 55 (was 70), medium >= 25 (was 40)
  so fewer customers appear as 'low risk' and issues surface earlier

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-06 00:55:41 +02:00
fs
28cb60efb3 refactor(helpdesk): remove resolution time dimension from risk score
Resolution time measures the past, not current risk. The remaining
4 dimensions (open pressure 35%, trend 30%, SLA overdue 25%,
inactivity 10%) are all current and actionable. Removes resolution
aggregation, median calculation, and weight redistribution logic.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-06 00:47:58 +02:00
fs
5a4974909b feat(helpdesk): add Risk Radar dashboard with customer risk scoring
New portfolio view scoring customers 0-100 across five dimensions:
- Open pressure (30%): open + critical ticket count
- Trend (25%): net ticket flow (created - closed) in period
- SLA overdue (20%): tickets exceeding escalation targets
- Resolution time (15%): median hours to close (null = neutral)
- Inactivity (10%): age of oldest open ticket

Card grid with score badges (color-coded high/medium/low), metric
pills, driver bars. Click opens detail dialog with all dimensions
and open ticket list. Clientside search filter.

PBI_LV_Tickets with client-driven paging ($skip/$top, hardcap 5000).
Escalation definitions cached separately (30min TTL). Truncated
banner when data is capped.

New: RiskRadarService, getTicketsForRiskRadar(), 13 PHPUnit tests,
permission helpdesk.risk-radar.view, 2 routes, i18n de+en.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-06 00:24:48 +02:00
fs
2b2f41ebab fix(helpdesk): extract SOAP fault detail from GetTicketFile error responses
Show the actual BC error message instead of just 'HTTP 500' to help
diagnose authentication and parameter issues.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-05 22:55:12 +02:00
fs
c2eba3e671 fix(helpdesk): add empty ticketNo field to GetTicketFile SOAP envelope
BC expects all four parameters in the envelope even if ticketNo is
empty. The entry number alone should be sufficient to identify the file.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-05 22:54:22 +02:00
fs
792f706d9e feat(helpdesk): add ticket file download and inline image preview
New SOAP method getTicketFile() on BcSoapGateway calls BC's
GetTicketFile to retrieve file attachments as Base64, decodes in
memory and returns binary data without writing to disk.

New proxy endpoint helpdesk/ticket-file-data streams files directly
to the browser with correct MIME type. Images served inline, other
files as download attachment.

TicketCommunicationService now attaches file_entry_no and file_name
to file-type events. Frontend renders download links with bi-download
icon and inline image previews for jpg/png/gif attachments.

Works in both ticket detail and debitor detail communication feeds.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-05 22:49:01 +02:00
fs
659a6d71c5 fix(helpdesk): only resolve most recent support code on reassigned tickets
When a ticket was reassigned (multiple support codes), all codes were
mapped to the current Support_User_Name — replacing the previous
agent's name with the new one on older entries.

Now: if multiple support codes exist, only the code from the most
recent entry is mapped to the current name. Older codes remain as
abbreviations, preserving the actual history of who worked on what.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-05 22:26:25 +02:00
fs
fbe8140937 fix(helpdesk): drop redundant SOAP message entries when OData has them
When the SOAP message map is applied to OData entries, the message text
is already embedded in the OData entries. The separate SOAP message
entries then cause duplicates with different actor/timestamp metadata.

Now: when soapMessageMap was used, filter out SOAP entries with
type_variant 'message' since they are already represented in OData.
Non-message SOAP entries (status, activity) are kept.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-05 22:21:28 +02:00
fs
66be390fa9 fix(helpdesk): remove actor from dedup signature to prevent duplicate entries
SOAP entries often have an empty actor while OData entries have a code
like 'NKS'. After name resolution, one becomes 'Nikita Soldatov' and
the other stays empty — producing different signatures and causing
duplicates. The actor is not a reliable dedup field since the same
event can have different actor representations across sources.

Dedup now uses: ticket_no + timestamp_iso + type + message_hash.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-05 22:13:04 +02:00
fs
f2aa45dd2c feat(helpdesk): add trend delta indicator per agent in team dashboard
Shows a small arrow next to the ticket count in each agent card header:
↑3 (orange) = received 3 more than resolved → backlog growing
↓2 (green) = resolved 2 more than received → backlog shrinking
Hidden when delta is 0 (stable).

Delta is computed from received_in_period (tickets created in the
selected period assigned to this agent) minus resolved_in_period.
No snapshot storage needed — derived from existing ticket data.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-05 21:09:52 +02:00
fs
5c0364f687 feat(helpdesk): clickable top customers/categories filter resolution times
Clicking a customer or category in the Historical tab recalculates
Ø/Min/Max resolution times for only that filter. Click again to reset.
All computation is client-side from resolved_details already in the
response — no extra API calls. Active filter highlighted with primary
color, resolution values turn primary when filtered.

Backend now includes resolved_ticket_details per agent (customer_name,
category, resolution_hours) for client-side filtering.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-05 20:31:08 +02:00
fs
fc98f2684a fix(helpdesk): consolidation fixes from drift/performance/security review
- Fix docblock: getTicketsForTeam() uses PBI_FP_Tickets, not LV
- Process_Stage check now uses isset() guard — FP entity does not
  expose this field, prevents false positives from default 0
- Remove exception message from JSON error response (security)
- Remove dead JS functions: formatAge(), formatDate()
- Remove debug console.error and verbose error display from JS

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-05 20:25:51 +02:00
fs
4ce7a32bfc feat(helpdesk): redesign Historical tab with per-agent performance widgets
Each agent gets a card with three insight columns:
- Resolution time: Ø / Min / Max (formatted as hours or days)
- Top 3 customers by resolved ticket count (ranked list)
- Top 3 categories by resolved ticket count (ranked list)

Backend collects resolved ticket details per agent: customer names,
categories, and resolution hours. Aggregates top-3 and min/max/avg.
Replaces the old compact single-row layout with rich widget cards
matching the Current tab pattern.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-05 20:11:44 +02:00
fs
c80e317875 fix(helpdesk): fix contact name resolution when customerNo is empty
getContactsForCustomerWithMeta() returned early when customerNo OR
customerName was empty. The communication service calls it with empty
customerNo and only customerName — which always hit the early return,
preventing any contact lookup. Fix: only return early when BOTH are
empty, so the primary Company_Name query path works correctly.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-05 20:02:05 +02:00
fs
422746d141 fix(helpdesk): resolve all support actor codes instead of requiring exactly one per ticket
The previous logic only resolved support user codes to full names when
exactly one unique support code existed per ticket. Tickets with multiple
support codes (e.g. after reassignment) left all codes unresolved,
showing abbreviations like 'NKS' or 'FA' instead of full names.

Now: every support-role actor code in a ticket is mapped to that ticket's
Support_User_Name. For the debitor feed, codes are mapped on first
encounter to avoid conflicts from reassigned tickets.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-05 20:00:50 +02:00
fs
3123b8aa77 fix(helpdesk): edge-to-edge table in cards, larger avatar, sort by urgency
- Remove card padding, table goes full-width inside card border
- Section title gets own padding + subtle background as card header
- Avatar inline size increased from 1.6rem to 2rem
- Sort agents by critical tickets first (most urgent on top),
  then by open tickets. Unassigned queue stays last.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-05 19:49:40 +02:00
fs
9e94456759 feat(helpdesk): switch team query to PBI_FP_Tickets for richer data
FP entity provides Company_Contact_Name (full customer name),
Category_1_Description (readable category), and Last_Activity_By_Code.
Customer column shows name instead of number. Category shows readable
description instead of code. Debitor link only rendered when
customer_no is available (FP may not expose it).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-05 19:47:10 +02:00
fs
d214f08c3f feat(helpdesk): add Description and Cust_Name from LV entity to team table
PBI_LV_Tickets exposes Description and Cust_Name (not Company_Contact_Name
which is FP-only). Add both to select. Table now shows 5 columns:
Ticket (link) | Customer name (link) | Description (ellipsis) |
Category | Last activity.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-05 19:44:53 +02:00
fs
cc1ae1aaca fix(helpdesk): replace description column with category in team ticket table
Description is not available on PBI_LV_Tickets. Show Category_1_Code
as its own 'Category' column instead of misusing it as description.
Remove unused ticket-desc CSS class.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-05 19:39:45 +02:00
fs
bfa3f5a154 fix(helpdesk): remove unavailable fields from LV ticket query
PBI_LV_Tickets does not expose Description or Company_Contact_Name —
BC returns HTTP 400 on unknown select fields. Revert to original LV
field set. Description falls back to Category_1_Code. Customer column
shows Customer_No when Company_Contact_Name is unavailable. Show API
error message in UI for debugging.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-05 19:38:26 +02:00
fs
72d39822bc fix(helpdesk): revert to PBI_LV_Tickets for team query, add error logging
PBI_FP_Tickets (FactPage) fails without a customer filter. Switch back
to PBI_LV_Tickets which works reliably unfiltered. Description and
Company_Contact_Name added to select — BC will return them if available,
otherwise they fall back to empty strings via existing null-coalescing.
Add console.error in JS catch to surface rendering errors.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-05 19:36:58 +02:00
fs
98ba2c024d fix(helpdesk): remove title line in team widgets, fix table columns and debitor links
- Hide section-title ::after line inside team widgets
- Fixed table-layout with consistent column widths (12/25/43/20%)
- Debitor link uses customer_no (route param), displays customer_name
- Add Customer_No to OData select for debitor link resolution
- Add customer_no to open_ticket_details backend structure

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-05 19:31:58 +02:00
fs
98f703b231 feat(helpdesk): enrich team ticket table with links, customer name, description, last activity
- Switch gateway from PBI_LV_Tickets to PBI_FP_Tickets to get
  Description and Company_Contact_Name fields
- Ticket number links to ticket detail page
- Customer column shows Company_Contact_Name with link to debitor detail
- Description column with text-overflow ellipsis
- Last activity column shows formatted date (was: age in hours)
- Backend provides last_activity ISO string and customer_name per ticket
- Table headers use i18n labels via data attributes

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-05 19:29:02 +02:00
fs
397f9fe659 feat(helpdesk): redesign team dashboard with agent cards and ticket details
Replace KPI tiles + table with visual agent cards showing workload at a
glance. Each card has the agent name, ticket count badge (warning-colored
when critical), a proportional load bar, and the actual open tickets
listed underneath (number, description, age). Critical tickets are
highlighted with warning color. Queue (unassigned) shown as dashed card
at top. Performance tab uses compact cards with success-colored bars.
Backend now returns open_ticket_details per member (sorted: critical
first, then by age descending).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-05 19:09:15 +02:00
fs
cae66e5361 feat(helpdesk): add team workload dashboard with per-agent metrics
New standalone page (helpdesk/team) showing support agent workload
aggregated from BC tickets. KPI bar (open, unassigned, avg age, resolved),
per-agent table sorted by open tickets, period selector (30/90/180/365d).
Global OData query via getTicketsForTeam() without customer filter.
New permission helpdesk.team-workload.view with admin role assignment.
Includes 6 PHPUnit tests for buildTeamWorkloadDashboard().

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-05 18:46:54 +02:00
fs
7220aa7459 feat(helpdesk): add ticket grid filters and resolve support user names in chat
Add 3 new ticket list filters: Support User (dynamic select), Contact (dynamic
select), and Period (30/90/180/365 days). Extend categories endpoint to also
return support_users and contacts arrays from the same cached ticket data.
Add server-side filtering for all three in the data endpoint.

Resolve support user abbreviation codes to full names in the communication chat
widget. For single-ticket view, infer code-to-name from Support_User_Name when
only one support code appears. For debitor view, build map from already-fetched
entries across tickets with no additional API calls.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-05 16:37:07 +02:00
fs
2f0f407268 feat(helpdesk): redesign dashboards with KPI groups, skeleton loading, and unified spacing
Restructure Support dashboard into 2 KPI groups (Tickets + Contracts) with
section dividers, merge escalations and recommendations into "Attention needed".
Redesign Sales dashboard with clickable contract timeline and dialog.
Add CSS shimmer skeleton loading for all dashboard tabs and aside.
Unify vertical rhythm via * + * sibling combinator on tab content containers.
Remove ~265 lines of dead CSS (contract cards, escalation styles) and unused JS
functions. Refactor hydrateTicketCategoryFilter into generic hydrateSelectFilter.
Fix role="button" CSS bleed from shell and remove extra future year from timeline.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-05 16:32:34 +02:00
fs
aee9cb10f3 feat(helpdesk): add dashboards, communication feed, settings UI and fix routing
Add support/sales/controlling dashboards with KPIs, trend charts and
risk indicators. Add debitor communication timeline, contact filters,
system recommendations engine, and configurable controlling risk rules.

Rename search→index to fix query-string preservation on back navigation.
Remove fake escalation rate metric, add KPI info tooltips, and switch
trend chart colors to red (created) / green (closed) for clarity.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-04 18:34:03 +02:00
fs
e897cc2c56 feat(helpdesk): add ticket/debtor communication feed and chat timeline UI 2026-04-03 16:45:41 +02:00
fs
8de67fa882 feat(helpdesk): enable oauth2 token flow and tenant-scoped cache 2026-04-02 21:46:01 +02:00
fs
a37486c0e3 feat(helpdesk): align module with core UI standards and fix KPI accuracy
- Add server-side ticket summary endpoint for exact KPI counts instead
  of client-side calculation from first 200 tickets
- Extract summarizeTickets() as shared static method to avoid duplication
- Replace custom .helpdesk-spinner CSS with core [aria-busy] pattern
- Migrate settings connection-test feedback to showAsyncFlash()
- Replace helpdesk-clickable-rows.js with delegated event handling
- Remove unused helpdesk-search.js (dead code, never loaded)
- Harmonize German wording: Debitoren → Kunden (8 i18n keys)
- Add 6 PHPUnit tests for loadTicketSummary()

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-02 21:05:54 +02:00
fs
a0d7670dd7 feat(helpdesk): align module with core list/drawer standards
- add helpdesk module pages, services, settings and tests

- standardize debtor list on drawer/grid contracts and robust filter drawer behavior

- add helpdesk aside panel navigation and settings visibility provider

- switch primary list slug to helpdesk/debitor and remove helpdesk/search compatibility

- include required core contract updates for list contracts and detail/drawer integration
2026-04-02 17:48:27 +02:00