Files
breadcrumb-the-shire/modules/helpdesk/pages/helpdesk/debitor(default).phtml
fs a5213977ca fix(helpdesk): drop stale require of removed app-flash partial
Commit 4890a28 folded templates/partials/app-flash.phtml into
app-toast-stack.phtml, which the base layout now mounts itself. 14
helpdesk views still required the deleted partial and crashed every
helpdesk page with a 500 (Failed opening required app-flash.phtml).
Remove the redundant requires; the unified toast stack continues to
render flash messages via the layout.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-29 07:59:51 +02:00

524 lines
26 KiB
PHTML

<?php
/**
* @var string $customerNo
* @var array $customer
* @var bool $hasError
* @var string $errorMessage
* @var string $customerName
* @var string $backUrl
*/
$customerNo = $customerNo ?? '';
$customer = is_array($customer ?? null) ? $customer : [];
$hasError = $hasError ?? false;
$errorMessage = $errorMessage ?? '';
$customerName = $customerName ?? '';
$backUrl = $backUrl ?? lurl('helpdesk');
$searchToolbarFilterSchema = is_array($searchToolbarFilterSchema ?? null) ? $searchToolbarFilterSchema : [];
$drawerToolbarFilterSchema = is_array($drawerToolbarFilterSchema ?? null) ? $drawerToolbarFilterSchema : [];
$toolbarFilterState = is_array($toolbarFilterState ?? null) ? $toolbarFilterState : [];
$toolbarOptionSets = is_array($toolbarOptionSets ?? null) ? $toolbarOptionSets : [];
$filterChipMeta = is_array($filterChipMeta ?? null) ? $filterChipMeta : [];
$clientFilterSchema = is_array($clientFilterSchema ?? null) ? $clientFilterSchema : [];
$searchConfig = is_array($searchConfig ?? null) ? $searchConfig : null;
?>
<div class="app-details-container"
data-app-component="helpdesk-detail"
data-customer-no="<?php e($customerNo); ?>"
data-customer-name="<?php e($customerName); ?>"
data-support-dashboard-url="<?php e(lurl('helpdesk/debitor-support-dashboard-data')); ?>"
data-contacts-url="<?php e(lurl('helpdesk/debitor-contacts-data')); ?>"
data-tickets-url="<?php e(lurl('helpdesk/debitor-tickets-data')); ?>"
data-ticket-base-url="<?php e(lurl('helpdesk/ticket/')); ?>"
data-communication-url="<?php e(lurl('helpdesk/debitor-communication-data')); ?>"
data-file-download-url="<?php e(lurl('helpdesk/ticket-file-data')); ?>"
data-sales-dashboard-url="<?php e(lurl('helpdesk/debitor-sales-dashboard-data')); ?>"
data-meetings-url="<?php e(lurl('helpdesk/debitor-meetings-data')); ?>"
data-controlling-dashboard-url="<?php e(lurl('helpdesk/debitor-controlling-dashboard-data')); ?>"
>
<section>
<?php
$titlebarActions = [];
if (!$hasError && $customer !== []) {
$titlebarActions[] = [
'label' => t('Refresh data'),
'type' => 'button',
'name' => 'support-refresh',
'class' => 'secondary outline',
];
}
$titlebar = [
'title' => $customerName,
'backHref' => $backUrl,
'backTitle' => t('Back'),
'actions' => $titlebarActions,
];
require templatePath('partials/app-details-titlebar.phtml');
?>
<?php if ($hasError): ?>
<div class="notice" data-variant="error" role="alert">
<p><?php e(t('Could not connect to Business Central.')); ?></p>
<?php if ($errorMessage !== ''): ?>
<small><?php e($errorMessage); ?></small>
<?php endif; ?>
</div>
<?php elseif ($customer !== []): ?>
<!-- Tabs: Support / Sales / Controlling -->
<div class="app-tabs" data-tabs data-app-component="tabs" data-tabs-param="tab" data-tabs-storage-key="helpdesk-debitor-detail">
<div class="app-tabs-nav">
<button type="button" data-tab="support" data-tab-default>
<?php e(t('Support')); ?>
</button>
<button type="button" data-tab="sales">
<?php e(t('Sales')); ?>
</button>
<button type="button" data-tab="controlling">
<?php e(t('Controlling')); ?>
</button>
</div>
<!-- Support panel -->
<div data-tab-panel="support">
<div id="support-loading">
<div class="helpdesk-support-metrics">
<?php for ($i = 0; $i < 4; $i++): ?>
<div class="helpdesk-skeleton-kpi">
<div class="helpdesk-skeleton helpdesk-skeleton-kpi-label"></div>
<div class="helpdesk-skeleton helpdesk-skeleton-kpi-value"></div>
<div class="helpdesk-skeleton helpdesk-skeleton-kpi-trend"></div>
</div>
<?php endfor; ?>
</div>
<div class="helpdesk-skeleton-divider"></div>
<?php for ($i = 0; $i < 4; $i++): ?>
<div class="helpdesk-skeleton-row">
<div class="helpdesk-skeleton helpdesk-skeleton-cell helpdesk-skeleton-cell-narrow"></div>
<div class="helpdesk-skeleton helpdesk-skeleton-cell"></div>
<div class="helpdesk-skeleton helpdesk-skeleton-cell helpdesk-skeleton-cell-narrow"></div>
<div class="helpdesk-skeleton helpdesk-skeleton-cell helpdesk-skeleton-cell-narrow"></div>
</div>
<?php endfor; ?>
</div>
<div id="support-content" hidden>
<section>
<h3 class="helpdesk-support-section-title"><?php e(t('Tickets')); ?></h3>
<div class="helpdesk-support-metrics">
<article class="helpdesk-support-metric helpdesk-kpi-clickable" data-kpi-filter="open">
<p class="helpdesk-support-metric-label"><?php e(t('Open tickets')); ?></p>
<p class="helpdesk-support-metric-value" id="support-kpi-open-tickets"></p>
<p class="helpdesk-support-metric-trend" id="support-kpi-open-trend"></p>
</article>
<article class="helpdesk-support-metric helpdesk-kpi-clickable" data-kpi-filter="">
<p class="helpdesk-support-metric-label"><?php e(t('New (30d)')); ?></p>
<p class="helpdesk-support-metric-value" id="support-kpi-created-30d"></p>
<p class="helpdesk-support-metric-trend" id="support-kpi-created-trend"></p>
</article>
<article class="helpdesk-support-metric helpdesk-kpi-clickable" data-kpi-filter="closed">
<p class="helpdesk-support-metric-label"><?php e(t('Resolved (30d)')); ?></p>
<p class="helpdesk-support-metric-value" id="support-kpi-closed-30d"></p>
<p class="helpdesk-support-metric-trend" id="support-kpi-closed-trend"></p>
</article>
<article class="helpdesk-support-metric helpdesk-kpi-clickable" data-kpi-sort="Last_Activity_Date:asc">
<p class="helpdesk-support-metric-label"><?php e(t('Avg. age open')); ?></p>
<p class="helpdesk-support-metric-value" id="support-kpi-avg-age"></p>
<p class="helpdesk-support-metric-trend" id="support-kpi-age-hint"></p>
</article>
</div>
</section>
<section id="support-recommendations-wrapper" hidden>
<h3 class="helpdesk-support-section-title"><?php e(t('Attention needed')); ?></h3>
<div id="support-system-recommendations"></div>
</section>
<section class="helpdesk-support-ticket-list">
<h3 class="helpdesk-support-section-title"><?php e(t('Ticket list')); ?></h3>
<?php
$filterUiNamespace = 'helpdesk-tickets';
require templatePath('partials/app-list-filters.phtml');
?>
<div id="helpdesk-tickets-grid"></div>
</section>
</div>
</div>
<!-- Sales panel -->
<div data-tab-panel="sales" hidden>
<div id="sales-loading">
<div class="helpdesk-support-metrics">
<?php for ($i = 0; $i < 4; $i++): ?>
<div class="helpdesk-skeleton-kpi">
<div class="helpdesk-skeleton helpdesk-skeleton-kpi-label"></div>
<div class="helpdesk-skeleton helpdesk-skeleton-kpi-value"></div>
<div class="helpdesk-skeleton helpdesk-skeleton-kpi-trend"></div>
</div>
<?php endfor; ?>
</div>
<div class="helpdesk-skeleton-divider"></div>
<div class="helpdesk-skeleton helpdesk-skeleton-line" style="width:30%;margin-bottom:0.75rem"></div>
<?php for ($i = 0; $i < 3; $i++): ?>
<div class="helpdesk-skeleton-row">
<div class="helpdesk-skeleton helpdesk-skeleton-cell helpdesk-skeleton-cell-narrow"></div>
<div class="helpdesk-skeleton helpdesk-skeleton-cell"></div>
</div>
<?php endfor; ?>
</div>
<div id="sales-content" hidden>
<section>
<h3 class="helpdesk-support-section-title"><?php e(t('Contracts & products')); ?></h3>
<div class="helpdesk-support-metrics">
<article class="helpdesk-support-metric">
<p class="helpdesk-support-metric-label"><?php e(t('Monthly volume')); ?></p>
<p class="helpdesk-support-metric-value" id="sales-kpi-monthly-volume">0</p>
<p class="helpdesk-support-metric-trend" id="sales-kpi-monthly-volume-trend"></p>
</article>
<article class="helpdesk-support-metric">
<p class="helpdesk-support-metric-label"><?php e(t('Active contracts')); ?></p>
<p class="helpdesk-support-metric-value" id="sales-kpi-active-contracts">0</p>
<p class="helpdesk-support-metric-trend" id="sales-kpi-active-contracts-trend"></p>
</article>
<article class="helpdesk-support-metric">
<p class="helpdesk-support-metric-label"><?php e(t('Avg. contract value')); ?></p>
<p class="helpdesk-support-metric-value" id="sales-kpi-avg-value">0</p>
<p class="helpdesk-support-metric-trend" id="sales-kpi-avg-value-trend"></p>
</article>
<article class="helpdesk-support-metric">
<p class="helpdesk-support-metric-label"><?php e(t('Next invoicing')); ?></p>
<p class="helpdesk-support-metric-value" id="sales-kpi-next-invoicing">&mdash;</p>
<p class="helpdesk-support-metric-trend" id="sales-kpi-next-invoicing-trend"></p>
</article>
</div>
</section>
<section id="sales-trend-section">
<h3 class="helpdesk-support-section-title"><?php e(t('Contract trend')); ?></h3>
<div id="sales-trend-chart"></div>
</section>
<div class="helpdesk-sales-split">
<section id="sales-contacts-section" class="helpdesk-sales-split-main">
<h3 class="helpdesk-support-section-title"><?php e(t('Contacts')); ?></h3>
<?php
$filterUiNamespace = 'helpdesk-contacts';
$searchToolbarFilterSchema = $contactsSearchToolbarFilterSchema;
$drawerToolbarFilterSchema = $contactsDrawerToolbarFilterSchema;
$toolbarFilterState = $contactsToolbarFilterState;
$toolbarOptionSets = $contactsToolbarOptionSets;
require templatePath('partials/app-list-filters.phtml');
?>
<div id="helpdesk-contacts-grid"></div>
</section>
<section id="sales-meetings-section" class="helpdesk-sales-split-aside">
<h3 class="helpdesk-support-section-title"><?php e(t('Meetings')); ?></h3>
<div id="meetings-loading">
<?php for ($i = 0; $i < 3; $i++): ?>
<div class="helpdesk-skeleton-row">
<div class="helpdesk-skeleton helpdesk-skeleton-cell helpdesk-skeleton-cell-narrow"></div>
<div class="helpdesk-skeleton helpdesk-skeleton-cell"></div>
</div>
<?php endfor; ?>
</div>
<div id="meetings-content" hidden>
<div id="meetings-timeline"></div>
</div>
<div id="meetings-empty" hidden></div>
<div id="meetings-error" hidden></div>
</section>
</div>
</div>
</div>
<!-- Controlling panel -->
<div data-tab-panel="controlling" hidden>
<div id="controlling-spinner">
<div class="helpdesk-support-metrics">
<?php for ($i = 0; $i < 4; $i++): ?>
<div class="helpdesk-skeleton-kpi">
<div class="helpdesk-skeleton helpdesk-skeleton-kpi-label"></div>
<div class="helpdesk-skeleton helpdesk-skeleton-kpi-value"></div>
<div class="helpdesk-skeleton helpdesk-skeleton-kpi-trend"></div>
</div>
<?php endfor; ?>
</div>
<div class="helpdesk-skeleton-divider"></div>
<div class="helpdesk-skeleton" style="height:10rem;margin-bottom:1rem"></div>
<div class="helpdesk-skeleton-divider"></div>
<?php for ($i = 0; $i < 3; $i++): ?>
<div class="helpdesk-skeleton-row">
<div class="helpdesk-skeleton helpdesk-skeleton-cell helpdesk-skeleton-cell-narrow"></div>
<div class="helpdesk-skeleton helpdesk-skeleton-cell"></div>
<div class="helpdesk-skeleton helpdesk-skeleton-cell helpdesk-skeleton-cell-narrow"></div>
</div>
<?php endfor; ?>
</div>
<div id="controlling-content" hidden>
<div class="helpdesk-segment-control" id="controlling-period-selector">
<input type="radio" name="controlling-period" id="controlling-period-30" value="30">
<label for="controlling-period-30"><?php e(t('30 days')); ?></label>
<input type="radio" name="controlling-period" id="controlling-period-90" value="90" checked>
<label for="controlling-period-90"><?php e(t('90 days')); ?></label>
<input type="radio" name="controlling-period" id="controlling-period-180" value="180">
<label for="controlling-period-180"><?php e(t('6 months')); ?></label>
<input type="radio" name="controlling-period" id="controlling-period-365" value="365">
<label for="controlling-period-365"><?php e(t('1 year')); ?></label>
</div>
<div class="helpdesk-support-metrics" id="controlling-kpis">
<div class="helpdesk-support-metric">
<div class="helpdesk-support-metric-label"><?php e(t('Ticket volume')); ?></div>
<div class="helpdesk-support-metric-value" id="controlling-kpi-volume"></div>
<p class="helpdesk-support-metric-trend" id="controlling-kpi-volume-trend"></p>
</div>
<div class="helpdesk-support-metric">
<div class="helpdesk-support-metric-label"><?php e(t('Close rate')); ?> <span class="helpdesk-kpi-info" data-tooltip="<?php e(t('kpi_tooltip_close_rate')); ?>" data-tooltip-pos="top" tabindex="0">i</span></div>
<div class="helpdesk-support-metric-value" id="controlling-kpi-closerate"></div>
<p class="helpdesk-support-metric-trend" id="controlling-kpi-closerate-trend"></p>
</div>
<div class="helpdesk-support-metric">
<div class="helpdesk-support-metric-label"><?php e(t('Avg. resolution')); ?> <span class="helpdesk-kpi-info" data-tooltip="<?php e(t('kpi_tooltip_resolution')); ?>" data-tooltip-pos="top" tabindex="0">i</span></div>
<div class="helpdesk-support-metric-value" id="controlling-kpi-resolution"></div>
<p class="helpdesk-support-metric-trend" id="controlling-kpi-resolution-trend"></p>
</div>
<div class="helpdesk-support-metric">
<div class="helpdesk-support-metric-label"><?php e(t('Open backlog')); ?> <span class="helpdesk-kpi-info" data-tooltip="<?php e(t('kpi_tooltip_backlog')); ?>" data-tooltip-pos="top" tabindex="0">i</span></div>
<div class="helpdesk-support-metric-value" id="controlling-kpi-backlog"></div>
<p class="helpdesk-support-metric-trend" id="controlling-kpi-backlog-trend"></p>
</div>
</div>
<div class="app-stats-table">
<div class="app-stats-table-header"><?php e(t('Ticket trend')); ?></div>
<div class="helpdesk-controlling-chart" id="controlling-trend-chart"></div>
</div>
<div class="app-stats-table">
<div class="app-stats-table-header"><?php e(t('Risk assessment')); ?></div>
<div id="controlling-risk-indicators"></div>
</div>
</div>
<div id="controlling-error" hidden></div>
<div id="controlling-empty" hidden></div>
</div>
</div>
<?php endif; ?>
</section>
<?php if (!$hasError && $customer !== []): ?>
<aside id="app-details-aside-section">
<div class="app-details-aside-section helpdesk-comm-aside">
<hgroup>
<h2><?php e(t('Ticket communication')); ?></h2>
<p><?php e(t('Last 5 tickets')); ?></p>
</hgroup>
<hr>
<div id="debitor-communication-loading">
<div class="helpdesk-skeleton helpdesk-skeleton-aside-bubble helpdesk-skeleton-aside-bubble-short"></div>
<div class="helpdesk-skeleton helpdesk-skeleton-aside-bubble helpdesk-skeleton-aside-bubble-alt"></div>
<div class="helpdesk-skeleton helpdesk-skeleton-aside-bubble"></div>
<div class="helpdesk-skeleton helpdesk-skeleton-aside-bubble helpdesk-skeleton-aside-bubble-alt" style="width:50%"></div>
</div>
<div id="debitor-communication-content" hidden>
<div id="debitor-communication-feed"></div>
</div>
</div>
</aside>
<?php endif; ?>
</div>
<!-- Grid.js tickets config -->
<script type="application/json" id="page-config-helpdesk-tickets"><?php gridJsonForJs([
'dataUrl' => lurl('helpdesk/debitor-tickets-data'),
'categoryOptionsUrl' => lurl('helpdesk/debitor-ticket-categories-data'),
'customerNo' => $customerNo,
'customerName' => $customerName,
'ticketBaseUrl' => lurl('helpdesk/ticket/'),
'gridLang' => gridLang(),
'labels' => [
'ticketNo' => t('Ticket No.'),
'description' => t('Description'),
'status' => t('Status'),
'category' => t('Category'),
'contact' => t('Contact'),
'support' => t('Support'),
'created' => t('Created'),
'lastActivity' => t('Last activity'),
],
'gridSearch' => $searchConfig,
'filterSchema' => $clientFilterSchema,
'filterChipMeta' => $filterChipMeta,
]); ?></script>
<!-- Grid.js contacts config -->
<script type="application/json" id="page-config-helpdesk-contacts"><?php gridJsonForJs([
'dataUrl' => lurl('helpdesk/debitor-contacts-data'),
'customerNo' => $customerNo,
'customerName' => $customerName,
'gridLang' => gridLang(),
'labels' => [
'name' => t('Name'),
'type' => t('Type'),
'jobTitle' => t('Job title'),
'email' => t('E-Mail'),
'phone' => t('Phone'),
'mobile' => t('Mobile'),
],
'gridSearch' => $contactsSearchConfig,
'filterSchema' => $contactsClientFilterSchema,
'filterChipMeta' => $contactsFilterChipMeta,
]); ?></script>
<!-- i18n strings for JS rendering -->
<script type="application/json" id="helpdesk-i18n"><?php gridJsonForJs([
'Ticket No.' => t('Ticket No.'),
'Description' => t('Description'),
'Status' => t('Status'),
'Sales' => t('Sales'),
'Controlling' => t('Controlling'),
'Category' => t('Category'),
'Contact' => t('Contact'),
'Support' => t('Support'),
'Created' => t('Created'),
'Last activity' => t('Last activity'),
'No.' => t('No.'),
'Name' => t('Name'),
'Type' => t('Type'),
'Job title' => t('Job title'),
'E-Mail' => t('E-Mail'),
'Phone' => t('Phone'),
'Mobile' => t('Mobile'),
'No open tickets' => t('No open tickets'),
'No tickets found' => t('No tickets found'),
'No tickets are linked to this debtor in Business Central.' => t('No tickets are linked to this debtor in Business Central.'),
'No contacts found' => t('No contacts found'),
'No contacts are linked to this debtor in Business Central.' => t('No contacts are linked to this debtor in Business Central.'),
'Total tickets' => t('Total tickets'),
'Critical (>48h)' => t('Critical (>48h)'),
'Oldest open' => t('Oldest open'),
'Ticket list' => t('Ticket list'),
'Attention needed' => t('Attention needed'),
'No system recommendations right now.' => t('No system recommendations right now.'),
'helpdesk.recommendation.escalation_overdue' => t('Escalation SLA exceeded by {overdue_hours}h ({escalation_code}).'),
'helpdesk.recommendation.high_risk_aging' => t('High-risk ticket ({escalation_code}) is open for {age_hours}h.'),
'helpdesk.recommendation.unassigned_open' => t('Ticket is unassigned for {age_hours}h.'),
'helpdesk.recommendation.stale_open' => t('No activity for {age_hours}h.'),
'helpdesk.recommendation.customer_backlog' => t('Customer backlog: {open_tickets} open tickets.'),
'Contracts & products' => t('Contracts & products'),
'No contracts found for this customer.' => t('No contracts found for this customer.'),
'Contract No.' => t('Contract No.'),
'Product type' => t('Product type'),
'Amount' => t('Amount'),
'Active contracts' => t('Active contracts'),
'Total contracts' => t('Total contracts'),
'Could not load contracts.' => t('Could not load contracts.'),
'Escalation code' => t('Escalation code'),
'Ticket volume' => t('Ticket volume'),
'Close rate' => t('Close rate'),
'Avg. resolution' => t('Avg. resolution'),
'Open backlog' => t('Open backlog'),
'Backlog shrinking' => t('Backlog shrinking'),
'Backlog growing' => t('Backlog growing'),
'unassigned' => t('unassigned'),
'Ticket trend' => t('Ticket trend'),
'Risk assessment' => t('Risk assessment'),
'vs. prev. period' => t('vs. prev. period'),
'Low' => t('Low'),
'Medium' => t('Medium'),
'High' => t('High'),
'All checks passed' => t('All checks passed'),
'of' => t('of'),
'checks flagged' => t('checks flagged'),
'Limit' => t('Limit'),
'No controlling data available.' => t('No controlling data available.'),
'Resolution time' => t('Resolution time'),
'Oldest open ticket' => t('Oldest open ticket'),
'Unassigned' => t('Unassigned'),
'risk_desc_ticket_volume' => t('risk_desc_ticket_volume'),
'risk_desc_resolution_time' => t('risk_desc_resolution_time'),
'risk_desc_open_aging' => t('risk_desc_open_aging'),
'risk_desc_unassigned' => t('risk_desc_unassigned'),
'Could not load controlling dashboard.' => t('Could not load controlling dashboard.'),
'Without assignee' => t('Without assignee'),
'Created' => t('Created'),
'Closed' => t('Closed'),
'30 days' => t('30 days'),
'90 days' => t('90 days'),
'6 months' => t('6 months'),
'1 year' => t('1 year'),
'Oldest open' => t('Oldest open'),
'Open ticket without activity for' => t('Open ticket without activity for'),
'hours' => t('hours'),
'Open ticket without assigned support user' => t('Open ticket without assigned support user'),
'Follow up oldest open ticket' => t('Follow up oldest open ticket'),
'Could not load contacts.' => t('Could not load contacts.'),
'Could not load tickets.' => t('Could not load tickets.'),
'Ticket communication' => t('Ticket communication'),
'Last 5 tickets' => t('Last 5 tickets'),
'No communication found.' => t('No communication found.'),
'Could not load communication history.' => t('Could not load communication history.'),
'Some ticket communications could not be loaded completely.' => t('Some ticket communications could not be loaded completely.'),
'Unknown user' => t('Unknown user'),
'Unknown time' => t('Unknown time'),
'Ticket' => t('Ticket'),
'Activity' => t('Activity'),
'Message' => t('Message'),
'Status change' => t('Status change'),
'Forwarded' => t('Forwarded'),
'attached a file' => t('attached a file'),
'logged an activity' => t('logged an activity'),
'on' => t('on'),
'SOAP' => t('SOAP'),
'Activity fallback' => t('Activity fallback'),
'Loading...' => t('Loading...'),
'Refresh data' => t('Refresh data'),
'Active contracts' => t('Active contracts'),
'Monthly volume' => t('Monthly volume'),
'Support hours' => t('Support hours'),
'Next invoicing' => t('Next invoicing'),
'Contract trend' => t('Contract trend'),
'New contracts' => t('New contracts'),
'Ended contracts' => t('Ended contracts'),
'active' => t('active'),
'ended' => t('ended'),
'No contract details available.' => t('No contract details available.'),
'Could not load sales dashboard.' => t('Could not load sales dashboard.'),
'Meetings' => t('Meetings'),
'Released' => t('Released'),
'Pending' => t('Pending'),
'Upcoming meetings' => t('Upcoming meetings'),
'Past meetings' => t('Past meetings'),
'No meetings found for this customer.' => t('No meetings found for this customer.'),
'Could not load meetings.' => t('Could not load meetings.'),
'Quantity' => t('Quantity'),
'Unit price' => t('Unit price'),
'Line amount' => t('Line amount'),
'Line state' => t('Line state'),
'Starting date' => t('Starting date'),
'Invoicing period' => t('Invoicing period'),
'Salesperson' => t('Salesperson'),
'Contacts' => t('Contacts'),
'positions' => t('positions'),
'Last invoicing' => t('Last invoicing'),
'Close' => t('Close'),
'New (30d)' => t('New (30d)'),
'Resolved (30d)' => t('Resolved (30d)'),
'Avg. age open' => t('Avg. age open'),
'vs. prev. 30d' => t('vs. prev. 30d'),
'net (30d)' => t('net (30d)'),
'critical' => t('critical'),
'Analysis' => t('Analysis'),
'Open tickets' => t('Open tickets'),
'Avg. contract value' => t('Avg. contract value'),
'of {total} total' => t('of {total} total'),
'in {days} days' => t('in {days} days'),
'largest' => t('largest'),
]); ?></script>
<script src="<?php e(assetVersion('vendor/gridjs/gridjs.umd.js')); ?>"></script>