Files
IT_asset_management/app/templates/paperwork/detail.html

239 lines
9.8 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
{% extends 'base.html' %}
{% block title %}{{ doc.title }} IT Asset Management{% endblock %}
{% block breadcrumb %}
<li class="breadcrumb-item"><a href="{{ url_for('dashboard.index') }}">Home</a></li>
<li class="breadcrumb-item"><a href="{{ url_for('paperwork.index') }}">Paperwork</a></li>
<li class="breadcrumb-item active">{{ doc.title }}</li>
{% endblock %}
{% block content %}
<div class="page-header d-flex align-items-center justify-content-between mb-4">
<h1><i class="bi bi-file-earmark-text me-2"></i>{{ doc.title }}</h1>
<div class="d-flex gap-2 flex-wrap">
{% if doc.pdf_filename %}
<a href="{{ url_for('paperwork.download', doc_id=doc.id) }}" class="btn btn-sm btn-primary">
<i class="bi bi-filetype-pdf me-1"></i>Download PDF
</a>
{% endif %}
{% if doc.docx_filename %}
<a href="{{ url_for('paperwork.download_docx', doc_id=doc.id) }}" class="btn btn-sm btn-outline-primary">
<i class="bi bi-file-earmark-word me-1"></i>Download .docx
</a>
{% endif %}
<form method="POST" action="{{ url_for('paperwork.regenerate', doc_id=doc.id) }}" class="d-inline">
<button type="submit" class="btn btn-sm btn-outline-secondary">
<i class="bi bi-arrow-clockwise me-1"></i>Regenerate
</button>
</form>
</div>
</div>
<div class="row g-3">
<!-- Left column: meta -->
<div class="col-md-4">
<div class="card border-0 shadow-sm mb-3">
<div class="card-header bg-white fw-semibold py-3">
<i class="bi bi-info-circle me-2 text-primary"></i>Document Info
</div>
<div class="card-body">
<dl class="row mb-0">
<dt class="col-5 text-muted small">Type</dt>
<dd class="col-7"><span class="badge bg-info text-dark">{{ doc.doc_type_label }}</span></dd>
<dt class="col-5 text-muted small">User</dt>
<dd class="col-7">
<a href="{{ url_for('users.detail', user_id=doc.user.id) }}">{{ doc.user.display_name }}</a>
<br><code class="small">WID: {{ doc.user.windows_id }}</code>
</dd>
{% if doc.asset %}
<dt class="col-5 text-muted small">Asset</dt>
<dd class="col-7">
<a href="{{ url_for('assets.detail', asset_id=doc.asset.id) }}">
{{ doc.asset.brand or '' }} {{ doc.asset.model or '' }}
</a>
<br><code class="small">{{ doc.asset.serial_number }}</code>
</dd>
{% endif %}
{% if doc.template %}
<dt class="col-5 text-muted small">Template</dt>
<dd class="col-7">
<a href="{{ url_for('doc_templates.detail', template_id=doc.template.id) }}">{{ doc.template.name }}</a>
</dd>
{% endif %}
<dt class="col-5 text-muted small">Created</dt>
<dd class="col-7">{{ doc.created_at.strftime('%d/%m/%Y %H:%M') if doc.created_at else '—' }}</dd>
<dt class="col-5 text-muted small">Created by</dt>
<dd class="col-7">{{ doc.created_by.username if doc.created_by else '—' }}</dd>
<dt class="col-5 text-muted small">PDF</dt>
<dd class="col-7">
{% if doc.pdf_filename %}<span class="badge bg-success">Generated</span>
{% else %}<span class="badge bg-secondary">Not generated</span>{% endif %}
</dd>
<dt class="col-5 text-muted small">Word doc</dt>
<dd class="col-7">
{% if doc.docx_filename %}<span class="badge bg-primary">Available</span>
{% else %}<span class="badge bg-secondary">None</span>{% endif %}
</dd>
<dt class="col-5 text-muted small">Signed</dt>
<dd class="col-7">
{% if doc.is_signed %}
<span class="badge bg-success">
<i class="bi bi-pen me-1"></i>{{ doc.signed_by_name }}
</span>
<br><span class="small text-muted">{{ doc.signed_at.strftime('%d/%m/%Y %H:%M') }}</span>
{% else %}
<span class="badge bg-warning text-dark">Unsigned</span>
{% endif %}
</dd>
</dl>
</div>
</div>
<!-- Signature card -->
{% if doc.is_signed %}
<div class="card border-0 shadow-sm mb-3">
<div class="card-header bg-white fw-semibold py-3 d-flex justify-content-between">
<span><i class="bi bi-pen me-2 text-success"></i>Signature</span>
<form method="POST" action="{{ url_for('paperwork.unsign', doc_id=doc.id) }}" class="d-inline">
<button class="btn btn-sm btn-outline-danger" onclick="return confirm('Remove signature?')">Remove</button>
</form>
</div>
<div class="card-body text-center">
{% if doc.signature_data %}
<img src="{{ doc.signature_data }}" alt="Signature" class="img-fluid border rounded"
style="max-height:80px; background:#fff;">
{% endif %}
<p class="mb-0 mt-2 small text-muted">
Signed by <strong>{{ doc.signed_by_name }}</strong><br>
{{ doc.signed_at.strftime('%d/%m/%Y at %H:%M') }}
</p>
</div>
</div>
{% else %}
<!-- Sign document card -->
<div class="card border-0 shadow-sm mb-3">
<div class="card-header bg-white fw-semibold py-3">
<i class="bi bi-pen me-2 text-warning"></i>Sign Document
</div>
<div class="card-body">
<form method="POST" action="{{ url_for('paperwork.sign', doc_id=doc.id) }}">
<div class="mb-2">
<label class="form-label small">Signer's full name <span class="text-danger">*</span></label>
<input type="text" name="signed_by_name" class="form-control form-control-sm"
placeholder="{{ doc.user.display_name }}" required>
</div>
<div class="mb-2">
<label class="form-label small">Draw signature (optional)</label>
<canvas id="sigCanvas" width="260" height="80"
class="border rounded d-block"
style="background:#fff; cursor:crosshair; touch-action:none;"></canvas>
<input type="hidden" name="signature_data" id="sigData">
<div class="d-flex gap-2 mt-1">
<button type="button" class="btn btn-xs btn-outline-secondary btn-sm" id="clearSig">Clear</button>
</div>
</div>
<button type="submit" class="btn btn-sm btn-success w-100" id="signBtn">
<i class="bi bi-pen me-1"></i>Sign Document
</button>
</form>
</div>
</div>
{% endif %}
</div>
<!-- Right column: notes + merge vars -->
<div class="col-md-8">
{% if doc.notes %}
<div class="card border-0 shadow-sm mb-3">
<div class="card-header bg-white fw-semibold py-3">
<i class="bi bi-chat-left-text me-2 text-primary"></i>Notes
</div>
<div class="card-body">
<p class="mb-0">{{ doc.notes }}</p>
</div>
</div>
{% endif %}
{% if merge_vars %}
<div class="card border-0 shadow-sm">
<div class="card-header bg-white fw-semibold py-3 d-flex justify-content-between align-items-center">
<span><i class="bi bi-braces me-2 text-primary"></i>Merge Variables Used</span>
<button class="btn btn-sm btn-outline-secondary" type="button"
data-bs-toggle="collapse" data-bs-target="#mergeVarsBody">
Toggle
</button>
</div>
<div id="mergeVarsBody" class="collapse show">
<div class="card-body p-0">
<table class="table table-sm table-striped mb-0 small">
<thead class="table-light"><tr><th>Variable</th><th>Value</th></tr></thead>
<tbody>
{% set PII = ['user_name','user_email','user_phone'] %}
{% for k, v in merge_vars.items()|sort %}
<tr {% if k in PII %}class="table-danger"{% endif %}>
<td><code>{{ '{{' }} {{ k }} {{ '}}' }}</code>
{% if k in PII %}<span class="badge bg-danger ms-1 small">PII</span>{% endif %}
</td>
<td>{{ v or '—' }}</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
</div>
{% endif %}
</div>
</div>
{% endblock %}
{% block extra_js %}
{% if not doc.is_signed %}
<script>
(function () {
const canvas = document.getElementById('sigCanvas');
const ctx = canvas.getContext('2d');
let drawing = false;
function getPos(e) {
const r = canvas.getBoundingClientRect();
const src = e.touches ? e.touches[0] : e;
return { x: src.clientX - r.left, y: src.clientY - r.top };
}
canvas.addEventListener('mousedown', e => { drawing = true; const p = getPos(e); ctx.beginPath(); ctx.moveTo(p.x, p.y); });
canvas.addEventListener('mousemove', e => { if (!drawing) return; const p = getPos(e); ctx.lineTo(p.x, p.y); ctx.stroke(); });
canvas.addEventListener('mouseup', () => { drawing = false; });
canvas.addEventListener('touchstart', e => { e.preventDefault(); drawing = true; const p = getPos(e); ctx.beginPath(); ctx.moveTo(p.x, p.y); });
canvas.addEventListener('touchmove', e => { e.preventDefault(); if (!drawing) return; const p = getPos(e); ctx.lineTo(p.x, p.y); ctx.stroke(); });
canvas.addEventListener('touchend', () => { drawing = false; });
ctx.strokeStyle = '#1a1a1a';
ctx.lineWidth = 2;
ctx.lineJoin = 'round';
ctx.lineCap = 'round';
document.getElementById('clearSig').addEventListener('click', () => {
ctx.clearRect(0, 0, canvas.width, canvas.height);
});
document.querySelector('form[action*="/sign"]').addEventListener('submit', () => {
// Only attach non-empty canvas
const blank = document.createElement('canvas');
blank.width = canvas.width; blank.height = canvas.height;
if (canvas.toDataURL() !== blank.toDataURL()) {
document.getElementById('sigData').value = canvas.toDataURL('image/png');
}
});
})();
</script>
{% endif %}
{% endblock %}