an updated and hopefully faster version of the ST Toolbox
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

86 lines
3.8 KiB

{{define "generic_content"}}
<div class="page-header">
<h2>Generic Tools</h2>
<p>Miscellaneous tools and utilities for ServiceTrade operations.</p>
</div>
<div class="page-content">
<div class="content">
<h3 class="submenu-header">Generic Tools & Utilities</h3>
<section class="card">
<h4>Invoice Clock Events Report (Proof of Concept)</h4>
<p>
Upload a CSV export that contains either job ids or invoice numbers. The tool automatically detects
which identifier is usable, gathers the related clock activity, and returns an Excel workbook formatted
like the shared audit template (Customer PO, id, Link, Clock In, Clock Out) with the header row frozen
and columns expanded.
</p>
<form id="invoice-clock-form" class="form" action="/reports/invoice-clock" method="POST"
enctype="multipart/form-data" hx-target="#invoice-clock-status" hx-indicator=".htmx-indicator">
{{if .CSRFField}}
{{.CSRFField}}
{{end}}
<input type="hidden" name="csrfToken" id="generic-csrf-token" value="{{.CSRFCookie}}">
<div class="form-group">
<label for="invoiceCsv">Select CSV file</label>
<input class="card-input" type="file" id="invoiceCsv" name="invoiceCsv" accept=".csv" required>
</div>
<p class="help-text">
If a <code>job id</code> column is present we use it directly; otherwise we fall back to columns such as
<code>invoice_number</code> or <code>customer po</code> to discover the job before pulling clock events.
</p>
<button class="btn-primary" type="submit">Generate XLSX Report</button>
</form>
<div class="status-message subtle-tip">
Generating very large reports can take a few minutes after you submit. Please keep the tab open while the download prepares.
</div>
<div id="invoice-clock-indicator" class="htmx-indicator status-indicator" style="display:none;">
<div class="spinner"></div>
<div>
<strong>Building report…</strong>
<p>Hang tight while we fetch clock events and assemble the workbook.</p>
</div>
</div>
<div id="invoice-clock-status" class="status-message"></div>
</section>
</div>
</div>
<script>
(function () {
function readCookie(name) {
var re = new RegExp('(?:^|; )' + name.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&') + '=([^;]+)');
var m = document.cookie.match(re);
return m ? decodeURIComponent(m[1]) : null;
}
function applyToken(root) {
var form = root.querySelector ? root.querySelector('#invoice-clock-form') : document.getElementById('invoice-clock-form');
if (!form) { return; }
var field = form.querySelector('#generic-csrf-token');
if (!field) { return; }
var token = readCookie('XSRF-TOKEN') || readCookie('XSRF-TOKEN-VALUE');
if (token) {
field.value = token;
}
}
function ensureTokenBeforeSubmit(evt) {
if (!evt.target || evt.target.id !== 'invoice-clock-form') {
return;
}
applyToken(evt.target);
}
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', function () { applyToken(document); });
} else {
applyToken(document);
}
document.addEventListener('submit', ensureTokenBeforeSubmit, true);
})();
</script>
{{end}}