147 lines
6.9 KiB
HTML
147 lines
6.9 KiB
HTML
{% extends "layout.html" %}
|
||
{% block content %}
|
||
<div class="page-wide">
|
||
<div class="panel" style="width:100%;">
|
||
<div class="panel-title">PTO Balance Tracker</div>
|
||
|
||
<form id="ptoForm" method="get" action="/pto-tracker" class="panel toolbar" style="gap:12px;flex-wrap:wrap;align-items:center;">
|
||
<label class="label">Employee</label>
|
||
<select class="select" id="employeeSelect" name="employee_id">
|
||
{% for e in employees %}
|
||
<option value="{{ e.id }}" {% if selected_employee and e.id == selected_employee.id %}selected{% endif %}>
|
||
{{ e.name }}{% if include_inactive and (inactive_ids and e.id in inactive_ids) %} (inactive){% endif %}
|
||
</option>
|
||
{% endfor %}
|
||
</select>
|
||
|
||
<label class="label">Year</label>
|
||
<select class="select" id="yearSelect" name="year">
|
||
{% for y in years %}
|
||
<option value="{{ y }}" {% if selected_year == y %}selected{% endif %}>{{ y }}</option>
|
||
{% endfor %}
|
||
</select>
|
||
|
||
<label class="checkbox" style="display:flex; gap:6px; align-items:center;">
|
||
<input id="includeInactive" type="checkbox" name="include_inactive" value="1" {% if include_inactive %}checked{% endif %}>
|
||
Show inactive
|
||
</label>
|
||
|
||
<button type="submit" class="btn primary">Load</button>
|
||
|
||
{% if selected_employee %}
|
||
<a class="btn" target="_blank"
|
||
href="/pto-tracker/print?employee_id={{ selected_employee.id }}&year={{ selected_year }}">
|
||
Print
|
||
</a>
|
||
<a class="btn" target="_blank"
|
||
href="/pto-tracker/print-all?year={{ selected_year }}{% if include_inactive %}&include_inactive=1{% endif %}">
|
||
Print All
|
||
</a>
|
||
{% endif %}
|
||
</form>
|
||
|
||
{% if selected_employee %}
|
||
<div class="panel" style="margin-top:12px;">
|
||
<div class="panel-title">Balances</div>
|
||
<div style="display:flex;gap:16px;align-items:flex-end;flex-wrap:wrap;">
|
||
<form method="post" action="/pto-tracker/set-starting" class="inline" onsubmit="return confirm('Update starting balance?')">
|
||
<input type="hidden" name="employee_id" value="{{ selected_employee.id }}">
|
||
<input type="hidden" name="year" value="{{ selected_year }}">
|
||
<label class="label" for="starting_balance">Starting balance ({{ selected_year }})</label>
|
||
<input class="input" id="starting_balance" name="starting_balance" type="number" step="0.01" value="{{ starting_balance|fmt2 }}">
|
||
<button class="btn" type="submit">Save</button>
|
||
</form>
|
||
|
||
<div class="inline" style="gap:8px;">
|
||
<div class="label">Remaining</div>
|
||
<div class="total" style="min-width:140px; display:flex; align-items:center; justify-content:center;">
|
||
<div class="t-val">{{ remaining_balance|fmt2 }}</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="panel" style="margin-top:12px;">
|
||
<div class="panel-title">Add Adjustment</div>
|
||
<form method="post" action="/pto-tracker/add-adjustment" class="inline" style="gap:8px;flex-wrap:wrap;">
|
||
<input type="hidden" name="employee_id" value="{{ selected_employee.id }}">
|
||
<input type="hidden" name="year" value="{{ selected_year }}">
|
||
<label class="label" for="hours">Hours (+/−)</label>
|
||
<input class="input" id="hours" name="hours" type="number" step="0.01" placeholder="e.g. 8.00 or -4.00" required>
|
||
<label class="label" for="note">Note</label>
|
||
<input class="input" id="note" name="note" type="text" placeholder="e.g. Grant, carryover correction">
|
||
<button class="btn" type="submit">Add</button>
|
||
</form>
|
||
<div class="muted" style="margin-top:6px;">Adjustments apply to the selected year.</div>
|
||
</div>
|
||
|
||
<div class="panel" style="margin-top:12px;">
|
||
<div class="panel-title">PTO Ledger ({{ selected_year }}, submitted timesheets only)</div>
|
||
<div class="table-wrap">
|
||
<table class="table compact" style="width:100%;">
|
||
<thead>
|
||
<tr>
|
||
<th style="text-align:center;">Date</th>
|
||
<th>Description</th>
|
||
<th class="num">Hours (±)</th>
|
||
<th class="num">Running Balance</th>
|
||
<th>Actions</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
{% for row in ledger %}
|
||
<tr>
|
||
<td class="mono" style="text-align:center;">{% if row.date %}{{ row.date.strftime("%b %d, %Y") }}{% endif %}</td>
|
||
<td>{{ row.desc }}</td>
|
||
<td class="num mono">{% if row.delta != '' %}{{ row.delta|fmt2 }}{% endif %}</td>
|
||
<td class="num mono">{{ row.balance|fmt2 }}</td>
|
||
<td>
|
||
{% if row.kind == 'adjustment' and row.adj_id %}
|
||
<form method="post" action="/pto-tracker/delete-adjustment" onsubmit="return confirm('Delete this adjustment?')" style="display:inline;">
|
||
<input type="hidden" name="employee_id" value="{{ selected_employee.id }}">
|
||
<input type="hidden" name="year" value="{{ selected_year }}">
|
||
<input type="hidden" name="adjustment_id" value="{{ row.adj_id }}">
|
||
<button class="btn danger" type="submit">Delete</button>
|
||
</form>
|
||
{% elif row.kind == 'usage' and row.u_date is defined %}
|
||
<form method="post" action="/pto-tracker/exclude-usage" onsubmit="return confirm('Exclude this usage row from the ledger?')" style="display:inline;">
|
||
<input type="hidden" name="employee_id" value="{{ selected_employee.id }}">
|
||
<input type="hidden" name="year" value="{{ selected_year }}">
|
||
<input type="hidden" name="work_date" value="{{ row.u_date }}">
|
||
<input type="hidden" name="pto_type" value="{{ row.u_type }}">
|
||
<button class="btn" type="submit">Exclude</button>
|
||
</form>
|
||
{% else %}
|
||
<!-- starting balance row -->
|
||
{% endif %}
|
||
</td>
|
||
</tr>
|
||
{% endfor %}
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
<div class="muted" style="margin-top:8px;">
|
||
Usage rows reflect PTO on submitted timesheets within the selected year. “Exclude” hides a specific date/type without altering timesheets. Adjustments and starting balances are year-specific.
|
||
</div>
|
||
</div>
|
||
{% endif %}
|
||
</div>
|
||
</div>
|
||
|
||
<script>
|
||
// Auto-submit on employee change and Show inactive toggle
|
||
(function () {
|
||
var form = document.getElementById('ptoForm');
|
||
if (!form) return;
|
||
var emp = document.getElementById('employeeSelect');
|
||
var chk = document.getElementById('includeInactive');
|
||
|
||
if (emp) {
|
||
emp.addEventListener('change', function () { form.submit(); });
|
||
}
|
||
if (chk) {
|
||
chk.addEventListener('change', function () { form.submit(); });
|
||
}
|
||
})();
|
||
</script>
|
||
{% endblock %} |