Versiunea funcțională EUMI

This commit is contained in:
2026-08-31 16:10:46 +03:00
parent 75bcef3095
commit ce5028a27f
58 changed files with 4271 additions and 98 deletions
@@ -0,0 +1,71 @@
{% extends 'base.html' %}
{% block content %}
<div class="d-flex justify-content-between align-items-center mb-4">
<div>
<h2 class="fw-bold text-info">Certificate Digitale (Semnături)</h2>
<p class="text-muted">Gestiunea token-urilor și a semnăturilor în cloud.</p>
</div>
{% if user.is_staff %}
<button class="btn btn-info fw-bold shadow-sm"
hx-get="{% url 'equipment:certificate_create' %}"
hx-target="#modal-content-area"
data-bs-toggle="modal"
data-bs-target="#form-modal">
➕ Adaugă Certificat
</button>
{% endif %}
</div>
<div class="card shadow-sm border-info">
<table class="table table-striped table-hover mb-0">
<thead class="table-dark">
<tr>
<th>Titular</th>
<th>Tip</th>
<th>Dată Emitere</th>
<th>Dată Expirare</th>
<th>Status</th>
<th class="text-center">Acțiuni</th>
</tr>
</thead>
<tbody id="certificate-table-body">
{% for cert in certificates %}
<tr>
<td class="align-middle fw-bold">👤 {{ cert.assigned_to.name }}</td>
<td class="align-middle">
{% if cert.certificate_type == 'usb' %}🔑 USB Token{% else %}☁️ Cloud{% endif %}
</td>
<td class="align-middle">{{ cert.issue_date|date:"d.m.Y" }}</td>
<td class="align-middle fw-bold">{{ cert.expiration_date|date:"d.m.Y" }}</td>
<td class="align-middle">
<span class="badge bg-{{ cert.status_color }}">{{ cert.status_text }}</span>
</td>
<td class="align-middle text-center">
{% if user.is_staff %}
<button class="btn btn-sm btn-outline-secondary"
hx-get="{% url 'equipment:certificate_edit' cert.id %}"
hx-target="#modal-content-area"
data-bs-toggle="modal"
data-bs-target="#form-modal">
✏️ Editează
{% endif %}
</button>
</td>
</tr>
{% empty %}
<tr>
<td colspan="6" class="text-center text-muted py-4">Nu există certificate digitale înregistrate.</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
<!-- Modal Container -->
<div class="modal fade" id="form-modal" tabindex="-1" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content" id="modal-content-area"></div>
</div>
</div>
{% endblock %}
@@ -0,0 +1,104 @@
{% extends 'base.html' %}
{% block content %}
<!-- Am adăugat clasa 'text-center' aici pentru a centra titlul -->
<div class="mb-4 text-center">
<h2 class="fw-bold">Panou de Control</h2>
<p class="text-muted">Privire de ansamblu asupra infrastructurii I.T.</p>
</div>
<div class="row g-4">
<!-- Coloana 1: Sumar Inventar -->
<div class="col-md-4">
<div class="card shadow-sm border-primary">
<div class="card-header bg-primary text-white fw-bold">
ℹ️ Sumar & Echipamente Libere
</div>
<!-- Am adăugat înălțime fixă (max-height) și overflow-y pentru scroll -->
<div class="card-body" style="max-height: 450px; overflow-y: auto;">
<p class="mb-2">Total Calculatoare: <strong>{{ total_computers }}</strong></p>
<hr>
<h6 class="fw-bold text-danger mt-3">Calculatoare Neasignate:</h6>
<ul class="list-unstyled mb-3">
{% for pc in unassigned_computers %}
<li>💻 {{ pc.equipment_code }} - <small>{{ pc.cpu }} / {{ pc.ram }}</small></li>
{% empty %}
<li><small class="text-muted">Toate calculatoarele sunt asignate.</small></li>
{% endfor %}
</ul>
<h6 class="fw-bold text-danger mt-3">Monitoare Neasignate:</h6>
<ul class="list-unstyled">
{% for mon in unassigned_monitors %}
<li>🖥️ {{ mon.equipment_code }} - <small>{{ mon.screen_diagonal }}</small></li>
{% empty %}
<li><small class="text-muted">Toate monitoarele sunt asignate.</small></li>
{% endfor %}
</ul>
</div>
</div>
</div>
<!-- Coloana 2: Acțiuni Executate (Istoric) -->
<div class="col-md-4">
<div class="card shadow-sm border-success">
<div class="card-header bg-success text-white fw-bold">
🔄 Ultimele Acțiuni
</div>
<!-- Scroll adăugat aici -->
<div class="card-body p-0" style="max-height: 450px; overflow-y: auto;">
<ul class="list-group list-group-flush">
{% for record in activity_log %}
<li class="list-group-item">
<small class="text-muted d-block">{{ record.history_date|date:"d.m.Y H:i" }}</small>
<strong>{{ record.history_user.username|default:"Sistem" }}</strong> a
{% if record.history_type == '+' %}
<span class="text-success">adăugat</span>
{% elif record.history_type == '~' %}
<span class="text-warning text-dark">modificat</span>
{% elif record.history_type == '-' %}
<span class="text-danger">șters</span>
{% endif %}
<br>
<span class="text-dark">{{ record.equipment_code }}</span>
</li>
{% empty %}
<li class="list-group-item text-muted text-center py-4">Nu există acțiuni recente.</li>
{% endfor %}
</ul>
</div>
</div>
</div>
<!-- Coloana 3: Mentenanțe Efectuate -->
<div class="col-md-4">
<div class="card shadow-sm border-warning">
<div class="card-header bg-warning text-dark fw-bold">
🛠️ Ultimele Mentenanțe
</div>
<!-- Scroll adăugat aici -->
<div class="card-body p-0" style="max-height: 450px; overflow-y: auto;">
<ul class="list-group list-group-flush">
{% for maint in recent_maintenance %}
<li class="list-group-item">
<small class="text-muted d-block">{{ maint.date|date:"d.m.Y" }} | Efectuat de: {{ maint.performed_by }}</small>
<strong>{{ maint.operation_type }}</strong>
<br>
<span class="text-dark small">
Pentru:
{% if maint.computer %}💻 {{ maint.computer.equipment_code }}{% endif %}
{% if maint.monitor %}🖥️ {{ maint.monitor.equipment_code }}{% endif %}
{% if maint.peripheral %}🖨️ {{ maint.peripheral.equipment_code }}{% endif %}
</span>
</li>
{% empty %}
<li class="list-group-item text-muted text-center py-4">Nu există mentenanțe înregistrate.</li>
{% endfor %}
</ul>
</div>
</div>
</div>
</div>
{% endblock %}
@@ -0,0 +1,79 @@
{% extends 'base.html' %}
{% block content %}
<div class="d-flex justify-content-between align-items-center mb-4">
<div>
<h2 class="fw-bold text-danger">Procese Verbale de Casare</h2>
<p class="text-muted">Evidența echipamentelor scoase din uz.</p>
</div>
{% if user.is_staff %}
<button class="btn btn-danger fw-bold shadow-sm"
hx-get="{% url 'equipment:decommission_create' %}"
hx-target="#modal-content-area"
data-bs-toggle="modal"
data-bs-target="#form-modal">
➕ Adaugă PV Casare
</button>
{% endif %}
</div>
<div class="card shadow-sm border-danger">
<table class="table table-striped table-hover mb-0">
<thead class="table-dark">
<tr>
<th>Număr PV</th>
<th>Data</th>
<th>Motiv</th>
<th>Echipamente Casate</th>
<th class="text-center">Acțiuni</th>
</tr>
</thead>
<tbody id="decommission-table-body">
{% for record in records %}
<tr>
<td class="align-middle fw-bold"># {{ record.document_number }}</td>
<td class="align-middle">{{ record.date|date:"d.m.Y" }}</td>
<td class="align-middle text-truncate" style="max-width: 250px;" title="{{ record.reason }}">{{ record.reason }}</td>
<td class="align-middle">
<small>
💻 Computere: <strong>{{ record.computers.count }}</strong><br>
🖥️ Monitoare: <strong>{{ record.monitors.count }}</strong><br>
🖨️ Periferice: <strong>{{ record.peripherals.count }}</strong>
</small>
</td>
<td class="align-middle text-center">
<a href="{% url 'equipment:decommission_pdf' record.id %}"
class="btn btn-sm btn-outline-primary me-1"
target="_blank"
title="Descarcă PV Casare">
📄 PDF
</a>
{% if user.is_staff %}
<button class="btn btn-sm btn-outline-secondary"
hx-get="{% url 'equipment:decommission_edit' record.id %}"
hx-target="#modal-content-area"
data-bs-toggle="modal"
data-bs-target="#form-modal">
✏️ Editează
</button>
{% endif %}
</td>
</tr>
{% empty %}
<tr>
<td colspan="5" class="text-center text-muted py-4">Nu există procese verbale de casare înregistrate.</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
<!-- Modal Container -->
<div class="modal fade" id="form-modal" tabindex="-1" aria-hidden="true">
<div class="modal-dialog modal-xl">
<div class="modal-content" id="modal-content-area">
<!-- Formularul se va încărca aici prin HTMX -->
</div>
</div>
</div>
{% endblock %}
@@ -0,0 +1,58 @@
{% extends 'base.html' %}
{% block content %}
<div class="d-flex justify-content-between align-items-center mb-4">
<h2 class="fw-bold">Inventar Echipamente Active</h2>
<div class="d-flex gap-3 w-50 justify-content-end">
<!-- HTMX Live Search Input -->
<input class="form-control w-50" type="search"
name="search" placeholder="Caută cod, nume sau angajat..."
hx-get="{% url 'equipment:equipment_list' %}"
hx-trigger="input changed delay:400ms, search"
hx-target="#equipment-tables-container">
<!-- Dropdown to add different types of equipment -->
<div class="dropdown">
{% if user.is_staff %}
<button class="btn btn-success fw-bold dropdown-toggle" type="button" data-bs-toggle="dropdown">
+ Adaugă Echipament
</button>
{% endif %}
<ul class="dropdown-menu">
<li><a class="dropdown-item" href="#" hx-get="{% url 'equipment:computer_create' %}" hx-target="#modal-content-area" data-bs-toggle="modal" data-bs-target="#form-modal">💻 Computer / Laptop</a></li>
<li><a class="dropdown-item" href="#" hx-get="{% url 'equipment:monitor_create' %}" hx-target="#modal-content-area" data-bs-toggle="modal" data-bs-target="#form-modal">🖥️ Monitor</a></li>
<li><a class="dropdown-item" href="#" hx-get="{% url 'equipment:peripheral_create' %}" hx-target="#modal-content-area" data-bs-toggle="modal" data-bs-target="#form-modal">🖨️ Periferic</a></li>
</ul>
</div>
<a href="{% url 'equipment:export_inventory' %}" class="btn btn-success fw-bold shadow-sm me-2">
📊 Exportă Inventar (Excel)
</a>
</div>
</div>
<!-- Added hx-trigger="equipmentListChanged from:body" to refresh the tables upon save -->
<div id="equipment-tables-container" hx-get="{% url 'equipment:equipment_list' %}" hx-trigger="equipmentListChanged from:body">
{% include 'equipment/partials/equipment_tables.html' %}
</div>
<!-- Empty Bootstrap Modal Container -->
<div class="modal fade" id="form-modal" tabindex="-1" aria-hidden="true">
<div class="modal-dialog modal-lg">
<div class="modal-content" id="modal-content-area">
<!-- Form will be injected here by HTMX -->
</div>
</div>
</div>
<!-- Script to automatically close the modal when HTMX triggers 'closeModal' -->
<script>
document.body.addEventListener('closeModal', function() {
var modalEl = document.getElementById('form-modal');
var modal = bootstrap.Modal.getInstance(modalEl);
if (modal) {
modal.hide();
}
});
</script>
{% endblock %}
@@ -0,0 +1,87 @@
{% extends 'base.html' %}
{% block content %}
<div class="d-flex justify-content-between align-items-center mb-4">
<h2 class="fw-bold">Procese Verbale (Predare-Primire)</h2>
{% if user.is_staff %}
<button class="btn btn-success fw-bold"
hx-get="{% url 'equipment:handover_create' %}"
hx-target="#modal-content-area"
data-bs-toggle="modal"
data-bs-target="#form-modal">
+ Adaugă Proces Verbal
</button>
{% endif %}
</div>
<div class="card shadow-sm">
<div class="card-body p-0">
<table class="table table-hover mb-0">
<thead class="table-dark">
<tr>
<th>Nr. / Dată</th>
<th>Predat de</th>
<th>Primit de</th>
<th>Echipamente transferate</th>
<th>Document Scanat</th>
<th class="text-center">Acțiuni</th>
</tr>
</thead>
<tbody>
{% for protocol in protocols %}
<tr>
<td class="align-middle fw-bold">Nr. {{ protocol.document_number }}<br><small class="text-muted">{{ protocol.date|date:"d.m.Y" }}</small></td>
<td class="align-middle text-danger">{{ protocol.previous_holder.name|default:"-" }}</td>
<td class="align-middle text-success">{{ protocol.new_holder.name|default:"-" }}</td>
<td class="align-middle">
<small>
{% for pc in protocol.computers.all %}💻 {{ pc.equipment_code }}<br>{% endfor %}
{% for mon in protocol.monitors.all %}🖥️ {{ mon.equipment_code }}<br>{% endfor %}
{% for peri in protocol.peripherals.all %}🖨️ {{ peri.equipment_code }}<br>{% endfor %}
</small>
</td>
<td class="align-middle text-center">
{% if protocol.scanned_document %}
<a href="{{ protocol.scanned_document.url }}" target="_blank" class="btn btn-sm btn-outline-danger">📥 Vezi PDF</a>
{% else %}
<span class="text-muted small">Fără document</span>
{% endif %}
</td>
<td class="align-middle text-center">
<!-- Butonul nou pentru Generare PDF -->
<a href="{% url 'equipment:handover_pdf' protocol.id %}"
class="btn btn-sm btn-outline-primary me-1"
target="_blank"
title="Descarcă Procesul Verbal în format PDF">
📄 PDF
</a>
<!-- Butonul existent de Editare -->
<button class="btn btn-sm btn-outline-secondary"
hx-get="{% url 'equipment:handover_edit' protocol.id %}"
hx-target="#modal-content-area"
data-bs-toggle="modal"
data-bs-target="#form-modal">
✏️ Editează
</button>
</td>
</tr>
{% empty %}
<tr>
<td colspan="6" class="text-center py-4 text-muted">Nu există procese verbale înregistrate.</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
<!-- Container Modal -->
<div class="modal fade" id="form-modal" tabindex="-1" aria-hidden="true">
<div class="modal-dialog modal-lg">
<div class="modal-content" id="modal-content-area">
<!-- Formularul se va încărca aici prin HTMX -->
</div>
</div>
</div>
{% endblock %}
@@ -0,0 +1,64 @@
{% extends 'base.html' %}
{% block content %}
<div class="d-flex justify-content-between align-items-center mb-4">
<h2 class="fw-bold">Fișă Tehnică Monitor: {{ monitor.equipment_code }}</h2>
<a href="{% url 'equipment:equipment_list' %}" class="btn btn-outline-secondary">⬅️ Înapoi la Inventar</a>
</div>
<div class="row g-4">
<div class="col-md-5">
<div class="card shadow-sm h-100">
<div class="card-header bg-dark text-white fw-bold">Specificații Curente</div>
<ul class="list-group list-group-flush">
<li class="list-group-item"><strong>Model:</strong> {{ monitor.name }}</li>
<li class="list-group-item"><strong>Serial (S/N):</strong> {{ monitor.serial_number }}</li>
<li class="list-group-item"><strong>Diagonală:</strong> {{ monitor.screen_diagonal }}</li>
<li class="list-group-item"><strong>Utilizator Curent:</strong> {{ monitor.assigned_to.name|default:"Neasignat" }}</li>
<li class="list-group-item"><strong>Observații:</strong> {{ monitor.observations|default:"-" }}</li>
</ul>
</div>
</div>
<div class="col-md-7">
<div class="card shadow-sm">
<div class="card-header bg-warning text-dark fw-bold d-flex justify-content-between align-items-center">
<span>Jurnal Mentenanță</span>
<button class="btn btn-sm btn-dark" hx-get="{% url 'equipment:monitor_maintenance_create' monitor.id %}" hx-target="#modal-content-area" data-bs-toggle="modal" data-bs-target="#form-modal">+ Adaugă Intervenție</button>
</div>
<div class="card-body p-0">
<table class="table table-sm table-striped mb-0">
<thead class="table-light"><tr><th>Dată</th><th>Tip Operațiune</th><th>Efectuat de</th></tr></thead>
<tbody>
{% for log in maintenance_logs %}
<tr><td>{{ log.date|date:"d.m.Y" }}</td><td>{{ log.operation_type }}<br><small class="text-muted">{{ log.description }}</small></td><td>{{ log.performed_by }}</td></tr>
{% empty %}
<tr><td colspan="3" class="text-center py-3">Nu există intervenții de mentenanță.</td></tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
</div>
<h5 class="fw-bold mt-4 mb-3 border-bottom pb-2">Istoric Posesie (Custodie)</h5>
<ul class="list-group mb-4 shadow-sm">
{% for record in ownership_history %}
<li class="list-group-item d-flex justify-content-between align-items-center">
<div>
<strong>👤 {{ record.owner }}</strong>
</div>
<div class="text-muted small">
{{ record.start_date|date:"d.m.Y" }}
<span class="mx-1">→</span>
{% if record.end_date %}
{{ record.end_date|date:"d.m.Y" }}
{% else %}
<span class="badge bg-success">Prezent</span>
{% endif %}
</div>
</li>
{% empty %}
<li class="list-group-item text-muted text-center">Fără istoric de posesie.</li>
{% endfor %}
</ul>
</div>
<div class="modal fade" id="form-modal" tabindex="-1" aria-hidden="true"><div class="modal-dialog"><div class="modal-content" id="modal-content-area"></div></div></div>
{% endblock %}
@@ -0,0 +1,79 @@
<div class="modal-header bg-info text-dark">
<h5 class="modal-title fw-bold">
{% if certificate %}Editează Certificat{% else %}Adaugă Certificat Nou{% endif %}
</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<form {% if certificate %} hx-post="{% url 'equipment:certificate_edit' certificate.id %}" {% else %} hx-post="{% url 'equipment:certificate_create' %}" {% endif %}
hx-target="#modal-content-area">
{% csrf_token %}
<div class="modal-body bg-light">
{% if form.errors %}
<div class="alert alert-danger p-2 mb-3">
<ul class="mb-0">
{% for field, errors in form.errors.items %}
{% for error in errors %}<li><strong>{{ field|title }}:</strong> {{ error }}</li>{% endfor %}
{% endfor %}
</ul>
</div>
{% endif %}
<div class="row g-3">
<div class="col-md-6">
<label class="form-label fw-bold">Titular Certificat</label>
{{ form.assigned_to }}
</div>
<div class="col-md-6">
<label class="form-label fw-bold">Tip Certificat</label>
{{ form.certificate_type }}
</div>
<div class="col-md-6">
<label class="form-label fw-bold">Data Emiterii</label>
{{ form.issue_date }}
</div>
<div class="col-md-6">
<label class="form-label fw-bold text-danger">Data Expirării</label>
{{ form.expiration_date }}
</div>
<div class="col-md-12">
<label class="form-label fw-bold">Observații</label>
{{ form.observations }}
</div>
{% if certificate %}
<div class="col-md-12 mt-2">
<div class="form-check form-switch fs-5">
{{ form.is_canceled }}
<label class="form-check-label text-danger fw-bold ms-2" for="{{ form.is_canceled.id_for_label }}">
Marchează certificatul ca ANULAT / REVOCAT
</label>
</div>
</div>
{% endif %}
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Anulează</button>
<button type="submit" class="btn btn-info fw-bold">Salvează Certificat</button>
</div>
</form>
<!-- Încărcăm biblioteca Flatpickr și pachetul de limba română -->
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/flatpickr/dist/flatpickr.min.css">
<script src="https://cdn.jsdelivr.net/npm/flatpickr"></script>
<script src="https://npmcdn.com/flatpickr/dist/l10n/ro.js"></script>
<!-- <script>
// Așteptăm 100ms pentru ca HTMX să descarce complet librăria înainte de inițializare
setTimeout(function() {
flatpickr("#cert-issue-picker, #cert-expiry-picker", {
dateFormat: "d.m.Y",
locale: "ro",
allowInput: true
});
}, 100);
</script> -->
@@ -0,0 +1,86 @@
<div class="modal-header bg-dark text-white">
<h5 class="modal-title">{% if computer %}Editează Computer{% else %}Adaugă Computer Nou{% endif %}</h5>
<button type="button" class="btn-close btn-close-white" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<form hx-post="{% if computer %}{% url 'equipment:computer_edit' computer.pk %}{% else %}{% url 'equipment:computer_create' %}{% endif %}"
hx-target="#modal-content-area">
{% csrf_token %}
<div class="modal-body">
<!-- Bloc pentru afișarea erorilor -->
{% if form.errors %}
<div class="alert alert-danger p-2 mb-3">
<ul class="mb-0">
{% for field, errors in form.errors.items %}
{% for error in errors %}
<li><strong>{{ field|title }}:</strong> {{ error }}</li>
{% endfor %}
{% endfor %}
</ul>
</div>
{% endif %}
<h6 class="text-primary border-bottom pb-1 mb-3">Informații Generale</h6>
<div class="row g-3 mb-4">
<div class="col-md-4">
<label class="form-label fw-bold">Cod Echipament</label>
{{ form.equipment_code }}
</div>
<div class="col-md-4">
<label class="form-label fw-bold">Status</label>
{{ form.status }}
</div>
<div class="col-md-4">
<label class="form-label fw-bold">Data Intrării</label>
{{ form.entry_date }}
</div>
<div class="col-md-12">
<label class="form-label fw-bold">Atribuit Către (Custodie)</label>
{{ form.assigned_to }}
</div>
</div>
<h6 class="text-primary border-bottom pb-1 mb-3">Specificații Hardware & Software</h6>
<div class="row g-3">
<div class="col-md-6">
<label class="form-label fw-bold">Producător (OEM)</label>
{{ form.oem_name }}
</div>
<div class="col-md-6">
<label class="form-label fw-bold">Placă de bază</label>
{{ form.motherboard }}
</div>
<div class="col-md-6">
<label class="form-label fw-bold">Procesor (CPU)</label>
{{ form.cpu }}
</div>
<div class="col-md-6">
<label class="form-label fw-bold">Memorie RAM</label>
{{ form.ram }}
</div>
<div class="col-md-6">
<label class="form-label fw-bold">Stocare (HDD/SSD)</label>
{{ form.storage }}
</div>
<div class="col-md-6">
<label class="form-label fw-bold">Adresă MAC</label>
{{ form.mac_address }}
</div>
<div class="col-md-6">
<label class="form-label fw-bold">Licență OS</label>
{{ form.os_license }}
</div>
<div class="col-md-6">
<label class="form-label fw-bold">Licențe adiționale</label>
{{ form.additional_licenses }}
</div>
<div class="col-md-12">
<label class="form-label fw-bold">Observații</label>
{{ form.observations }}
</div>
</div>
</div>
<div class="modal-footer bg-light">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Anulează</button>
<button type="submit" class="btn btn-primary">Salvează Echipament</button>
</div>
</form>
@@ -0,0 +1,76 @@
<div class="modal-header bg-danger text-white">
<h5 class="modal-title fw-bold">
{% if record %}Editează PV Casare Nr. {{ record.document_number }}{% else %}Adaugă PV Casare Nou{% endif %}
</h5>
<button type="button" class="btn-close btn-close-white" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<form {% if record %} hx-post="{% url 'equipment:decommission_edit' record.id %}" {% else %} hx-post="{% url 'equipment:decommission_create' %}" {% endif %}
hx-target="#modal-content-area">
{% csrf_token %}
<div class="modal-body bg-light">
<div class="alert alert-warning mb-4">
<i class="bi bi-exclamation-triangle-fill"></i> Atenție: Echipamentele selectate aici vor fi trecute automat cu statusul <strong>"Casat"</strong> și vor fi scoase din gestiunea angajaților!
</div>
<div class="row g-3">
<div class="col-md-6">
<label class="form-label fw-bold">Număr Proces Verbal</label>
{{ form.document_number }}
</div>
<div class="col-md-6">
<label class="form-label fw-bold">Data Casării</label>
{{ form.date }}
</div>
<div class="col-md-12">
<label class="form-label fw-bold">Motivul Casării</label>
{{ form.reason }}
<div class="form-text">Ex: Uzaură fizică și morală, defect iremediabil etc.</div>
</div>
<hr class="my-4">
<h6 class="fw-bold text-danger mb-3">Selecție Echipamente pentru Casare:</h6>
<div class="col-md-12 mb-3">
<label class="form-label fw-bold">Computere</label>
{{ form.computers }}
<div class="form-text">Doar echipamentele ACTIVE apar în listă. Folosiți CTRL pt. selecție multiplă.</div>
</div>
<div class="col-md-12 mb-3">
<label class="form-label fw-bold">Monitoare</label>
{{ form.monitors }}
</div>
<div class="col-md-12 mb-3">
<label class="form-label fw-bold">Periferice</label>
{{ form.peripherals }}
</div>
<hr class="my-4">
<div class="col-md-12">
<label class="form-label fw-bold">Membrii Comisiei de Casare</label>
{{ form.committee_members }}
<div class="form-text">Nume și funcție (pentru generarea PDF-ului ulterior).</div>
</div>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Anulează</button>
<button type="submit" class="btn btn-danger fw-bold">Casare Echipamente</button>
</div>
</form>
<!-- Flatpickr pentru calendar -->
<!-- <script>
if (typeof flatpickr !== 'undefined') {
flatpickr("#decommission-date-picker", {
dateFormat: "d.m.Y",
locale: "ro",
allowInput: true
});
}
</script> -->
@@ -0,0 +1,13 @@
<div class="col-md-12 mb-3">
<label class="form-label fw-bold">Computere</label>
{{ form.computers }}
<div class="form-text">Folosiți CTRL pt. selecție multiplă.</div>
</div>
<div class="col-md-12 mb-3">
<label class="form-label fw-bold">Monitoare</label>
{{ form.monitors }}
</div>
<div class="col-md-12 mb-3">
<label class="form-label fw-bold">Periferice</label>
{{ form.peripherals }}
</div>
@@ -0,0 +1,150 @@
<ul class="nav nav-tabs mb-3" id="equipmentTabs" role="tablist">
<li class="nav-item" role="presentation">
<button class="nav-link active fw-bold" id="computers-tab" data-bs-toggle="tab" data-bs-target="#computers" type="button" role="tab">
Computere / Laptopuri <span class="badge bg-secondary ms-1">{{ computers.count }}</span>
</button>
</li>
<li class="nav-item" role="presentation">
<button class="nav-link fw-bold" id="monitors-tab" data-bs-toggle="tab" data-bs-target="#monitors" type="button" role="tab">
Monitoare <span class="badge bg-secondary ms-1">{{ monitors.count }}</span>
</button>
</li>
<li class="nav-item" role="presentation">
<button class="nav-link fw-bold" id="peripherals-tab" data-bs-toggle="tab" data-bs-target="#peripherals" type="button" role="tab">
Periferice <span class="badge bg-secondary ms-1">{{ peripherals.count }}</span>
</button>
</li>
</ul>
<div class="tab-content card shadow-sm p-0 border-top-0" id="equipmentTabsContent">
<!-- COMPUTERS TAB -->
<div class="tab-pane fade show active" id="computers" role="tabpanel">
<table class="table table-striped table-hover mb-0">
<thead class="table-dark">
<tr>
<th>Cod</th>
<th>Detalii Sistem</th>
<th>Asignat Către</th>
<th>Data Intrării</th>
<th class="text-center">Acțiuni</th>
</tr>
</thead>
<tbody>
{% for pc in computers %}
<tr>
<td class="align-middle fw-medium">{{ pc.equipment_code }}</td>
<td>
<!--<strong>{{ pc.oem_name|default:"Sistem Asamblat" }}</strong><br>-->
<small class="text-muted">
<span class="d-block">{{ pc.cpu }} | {{ pc.ram }}</span>
<span class="d-block">{{ pc.motherboard }} | {{ pc.mac_address }}</span>
</small>
</td>
<td class="align-middle">{{ pc.assigned_to.name|default:"<span class='text-danger'>Neasignat</span>" }}</td>
<td class="align-middle">{{ pc.entry_date|date:"d.m.Y" }}</td>
<td class="align-middle text-center">
<!-- Technical Sheet Button -->
<a href="{% url 'equipment:computer_sheet' pc.id %}" class="btn btn-sm btn-outline-info me-1">
📄 Fișă Tehnică
</a>
<!-- Edit Button -->
{% if user.is_staff %}
<button class="btn btn-sm btn-outline-secondary"
hx-get="{% url 'equipment:computer_edit' pc.id %}"
hx-target="#modal-content-area"
data-bs-toggle="modal" data-bs-target="#form-modal">
✏️ Editează
</button>
{% endif %}
</td>
</tr>
{% empty %}
<tr><td colspan="4" class="text-center py-4">Nu există computere active.</td></tr>
{% endfor %}
</tbody>
</table>
</div>
<!-- MONITORS TAB -->
<div class="tab-pane fade" id="monitors" role="tabpanel">
<table class="table table-striped table-hover mb-0">
<thead class="table-dark">
<tr>
<th>Cod</th>
<th>Model & S/N</th>
<th>Asignat Către</th>
<th>Data Intrării</th>
<th class="text-center">Acțiuni</th>
</tr>
</thead>
<tbody>
{% for monitor in monitors %}
<tr>
<td class="align-middle fw-medium">{{ monitor.equipment_code }}</td>
<td>
<strong>{{ monitor.name }} ({{ monitor.screen_diagonal }})</strong><br>
<small class="text-muted">S/N: {{ monitor.serial_number }}</small>
</td>
<td class="align-middle">{{ monitor.assigned_to.name|default:"<span class='text-danger'>Neasignat</span>" }}</td>
<td class="align-middle">{{ monitor.entry_date|date:"d.m.Y" }}</td>
<td class="align-middle text-center">
<a href="{% url 'equipment:monitor_sheet' monitor.id %}" class="btn btn-sm btn-outline-info me-1">📄 Fișă</a>
{% if user.is_staff %}
<button class="btn btn-sm btn-outline-secondary"
hx-get="{% url 'equipment:monitor_edit' monitor.id %}"
hx-target="#modal-content-area"
data-bs-toggle="modal" data-bs-target="#form-modal">
✏️ Editează
</button>
{% endif %}
</td>
</tr>
{% empty %}
<tr><td colspan="5" class="text-center py-4">Nu există monitoare active.</td></tr>
{% endfor %}
</tbody>
</table>
</div>
<!-- PERIPHERALS TAB -->
<div class="tab-pane fade" id="peripherals" role="tabpanel">
<table class="table table-striped table-hover mb-0">
<thead class="table-dark">
<tr>
<th>Cod</th>
<th>Tip & Model</th>
<th>Asignat Către</th>
<th>Data Intrării</th>
<th class="text-center">Acțiuni</th>
</tr>
</thead>
<tbody>
{% for peripheral in peripherals %}
<tr>
<td class="align-middle fw-medium">{{ peripheral.equipment_code }}</td>
<td>
<strong>{{ peripheral.get_peripheral_type_display }}: {{ peripheral.name }}</strong><br>
<small class="text-muted">S/N: {{ peripheral.serial_number }}</small>
</td>
<td class="align-middle">{{ peripheral.assigned_to.name|default:"<span class='text-danger'>Neasignat</span>" }}</td>
<td class="align-middle">{{ peripheral.entry_date|date:"d.m.Y" }}</td>
<td class="align-middle text-center">
<a href="{% url 'equipment:peripheral_sheet' peripheral.id %}" class="btn btn-sm btn-outline-info me-1">📄 Fișă</a>
{% if user.is_staff %}
<button class="btn btn-sm btn-outline-secondary"
hx-get="{% url 'equipment:peripheral_edit' peripheral.id %}"
hx-target="#modal-content-area"
data-bs-toggle="modal" data-bs-target="#form-modal">
✏️ Editează
</button>
{% endif %}
</td>
</tr>
{% empty %}
<tr><td colspan="5" class="text-center py-4">Nu există periferice active.</td></tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
@@ -0,0 +1,78 @@
<div class="modal-header bg-dark text-white">
<h5 class="modal-title fw-bold">
{% if protocol %}Editează Proces Verbal Nr. {{ protocol.document_number }}{% else %}Adaugă Proces Verbal Nou{% endif %}
</h5>
<button type="button" class="btn-close btn-close-white" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<!-- ATENȚIE: hx-encoding este OBLIGATORIU pentru încărcarea de fișiere (PDF) prin HTMX -->
<form {% if protocol %} hx-post="{% url 'equipment:handover_edit' protocol.id %}" {% else %} hx-post="{% url 'equipment:handover_create' %}" {% endif %}
hx-target="#modal-content-area"
hx-encoding="multipart/form-data"
enctype="multipart/form-data">
{% csrf_token %}
<div class="modal-body bg-light">
<!-- Bloc afișare erori (ex: PDF prea mare) -->
{% if form.errors %}
<div class="alert alert-danger p-2 mb-3">
<ul class="mb-0">
{% for field, errors in form.errors.items %}
{% for error in errors %}<li><strong>{{ field|title }}:</strong> {{ error }}</li>{% endfor %}
{% endfor %}
</ul>
</div>
{% endif %}
<div class="row g-3">
<div class="col-md-12">
<label class="form-label fw-bold text-danger">Document Scanat (Semnat)</label>
{{ form.scanned_document }}
<div class="form-text">Încărcați varianta semnată (max. 3 MB).</div>
</div>
<div class="col-md-4">
<label class="form-label fw-bold">Dată</label>
{{ form.date }}
</div>
<div class="col-md-4">
<label class="form-label fw-bold">Predat de</label>
{{ form.previous_holder }}
</div>
<div class="col-md-4">
<label class="form-label fw-bold">Primit de</label>
{{ form.new_holder }}
</div>
<hr class="my-4">
<!-- Aici se vor încărca dinamic listele verticale prin HTMX -->
<div id="equipment-lists" class="row">
{% include 'equipment/partials/equipment_dropdowns.html' %}
</div>
<div class="col-md-12 mt-2">
<label class="form-label fw-bold">Observații</label>
{{ form.notes }}
</div>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Anulează</button>
<button type="submit" class="btn btn-success fw-bold">Salvează Documentul</button>
</div>
</form>
<!-- Încărcăm biblioteca Flatpickr pentru calendarul în limba română -->
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/flatpickr/dist/flatpickr.min.css">
<script src="https://cdn.jsdelivr.net/npm/flatpickr"></script>
<script src="https://npmcdn.com/flatpickr/dist/l10n/ro.js"></script>
<script>
flatpickr("#date-picker", {
dateFormat: "d.m.Y",
locale: "ro",
allowInput: true
});
</script>
@@ -0,0 +1,31 @@
<div class="modal-header bg-warning text-dark">
<h5 class="modal-title fw-bold">Adaugă Mentenanță: {{ equipment_title }}</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<form hx-post="{{ post_url }}" hx-target="#modal-content-area">
{% csrf_token %}
<div class="modal-body">
<div class="row g-3">
<div class="col-md-6">
<label class="form-label fw-bold">Data intervenției</label>
{{ form.date }}
</div>
<div class="col-md-6">
<label class="form-label fw-bold">Efectuat de</label>
{{ form.performed_by }}
</div>
<div class="col-md-12">
<label class="form-label fw-bold">Tip operațiune</label>
{{ form.operation_type }}
</div>
<div class="col-md-12">
<label class="form-label fw-bold">Descriere detaliată</label>
{{ form.description }}
</div>
</div>
</div>
<div class="modal-footer bg-light">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Anulează</button>
<button type="submit" class="btn btn-warning fw-bold text-dark">Salvează Intervenția</button>
</div>
</form>
@@ -0,0 +1,36 @@
<div class="modal-header bg-dark text-white">
<h5 class="modal-title">{% if monitor %}Editează Monitor{% else %}Adaugă Monitor Nou{% endif %}</h5>
<button type="button" class="btn-close btn-close-white" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<form hx-post="{% if monitor %}{% url 'equipment:monitor_edit' monitor.pk %}{% else %}{% url 'equipment:monitor_create' %}{% endif %}" hx-target="#modal-content-area">
{% csrf_token %}
<div class="modal-body">
<!-- Bloc pentru afișarea erorilor -->
{% if form.errors %}
<div class="alert alert-danger p-2 mb-3">
<ul class="mb-0">
{% for field, errors in form.errors.items %}
{% for error in errors %}
<li><strong>{{ field|title }}:</strong> {{ error }}</li>
{% endfor %}
{% endfor %}
</ul>
</div>
{% endif %}
<div class="row g-3">
<div class="col-md-6"><label class="form-label fw-bold">Cod Echipament</label>{{ form.equipment_code }}</div>
<div class="col-md-6"><label class="form-label fw-bold">Status</label>{{ form.status }}</div>
<div class="col-md-6"><label class="form-label fw-bold">Data Intrării</label>{{ form.entry_date }}</div>
<div class="col-md-6"><label class="form-label fw-bold">Atribuit Către</label>{{ form.assigned_to }}</div>
<div class="col-md-6"><label class="form-label fw-bold">Denumire / Model</label>{{ form.name }}</div>
<div class="col-md-6"><label class="form-label fw-bold">Număr Serial (S/N)</label>{{ form.serial_number }}</div>
<div class="col-md-6"><label class="form-label fw-bold">Diagonală</label>{{ form.screen_diagonal }}</div>
<div class="col-md-12"><label class="form-label fw-bold">Observații</label>{{ form.observations }}</div>
</div>
</div>
<div class="modal-footer bg-light">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Anulează</button>
<button type="submit" class="btn btn-primary">Salvează</button>
</div>
</form>
@@ -0,0 +1,39 @@
<div class="modal-header bg-dark text-white">
<h5 class="modal-title">{% if peripheral %}Editează Periferic{% else %}Adaugă Periferic Nou{% endif %}</h5>
<button type="button" class="btn-close btn-close-white" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<form hx-post="{% if peripheral %}{% url 'equipment:peripheral_edit' peripheral.pk %}{% else %}{% url 'equipment:peripheral_create' %}{% endif %}" hx-target="#modal-content-area">
{% csrf_token %}
<div class="modal-body">
<!-- Bloc pentru afișarea erorilor -->
{% if form.errors %}
<div class="alert alert-danger p-2 mb-3">
<ul class="mb-0">
{% for field, errors in form.errors.items %}
{% for error in errors %}
<li><strong>{{ field|title }}:</strong> {{ error }}</li>
{% endfor %}
{% endfor %}
</ul>
</div>
{% endif %}
<div class="row g-3">
<div class="col-md-6"><label class="form-label fw-bold">Cod Echipament</label>{{ form.equipment_code }}</div>
<div class="col-md-6"><label class="form-label fw-bold">Status</label>{{ form.status }}</div>
<div class="col-md-6"><label class="form-label fw-bold">Data Intrării</label>{{ form.entry_date }}</div>
<div class="col-md-6"><label class="form-label fw-bold">Atribuit Către</label>{{ form.assigned_to }}</div>
<div class="col-md-4"><label class="form-label fw-bold">Tip Periferic</label>{{ form.peripheral_type }}</div>
<div class="col-md-8"><label class="form-label fw-bold">Denumire / Model</label>{{ form.name }}</div>
<div class="col-md-12"><label class="form-label fw-bold">Număr Serial (S/N)</label>{{ form.serial_number }}</div>
<div class="col-md-12">
<label class="form-label fw-bold">Observații</label>
{{ form.observations }}
</div>
</div>
</div>
<div class="modal-footer bg-light">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Anulează</button>
<button type="submit" class="btn btn-primary">Salvează</button>
</div>
</form>
@@ -0,0 +1,130 @@
<!DOCTYPE html>
<html lang="ro">
<head>
<meta charset="UTF-8">
<style>
@font-face {
font-family: 'LiberationSerif';
src: url('{{ font_regular }}');
}
@font-face {
font-family: 'LiberationSerif';
src: url('{{ font_bold }}');
font-weight: bold;
}
@page {
size: A4 portrait;
margin: 1.5cm;
margin-bottom: 2.5cm; /* Lăsăm loc pentru footer */
/* Așa forțăm xhtml2pdf să lipească footer-ul de marginea de jos pe fiecare pagină */
@frame footer_frame {
-pdf-frame-content: footer_content;
left: 1.5cm;
right: 1.5cm;
bottom: 1cm;
height: 1.5cm;
}
}
body {
font-family: 'LiberationSerif', serif;
font-size: 14px;
color: #333;
line-height: 1.3;
}
.title { text-align: center; font-size: 16px; font-weight: bold; margin-top: 15px; margin-bottom: 20px; }
ul { margin-top: 5px; margin-bottom: 10px; }
li { margin-bottom: 4px; text-align: justify; }
p { margin-bottom: 8px; }
</style>
</head>
<body>
<!-- 1. FOOTER-UL (Capturat de rama "footer_frame" setată în CSS) -->
<div id="footer_content">
<table style="width: 100%; border-top: 1px dashed #ccc; padding-top: 5px; font-size: 10px; color: #555;">
<tr>
<td style="text-align: left; width: 70%; border: none;">
Generat de E.U.M.I. v.4.0.0 &bull; Aplicație dezvoltată de Tololoi Cătălin (catalin@x3c.ro)
</td>
<td style="text-align: right; width: 30%; border: none;">
pag. <pdf:pagenumber> din <pdf:pagecount>
</td>
</tr>
</table>
</div>
<!-- 2. ANTETUL -->
<table style="width: 100%; border: none;">
<tr>
<td style="width: 15%; text-align: left; vertical-align: middle; border: none;">
{% if logo_path %}
<img src="{{ logo_path }}" width="50">
{% endif %}
</td>
<td style="width: 85%; text-align: right; vertical-align: middle; border: none;">
<strong>U.A.T. Municipiul Roman</strong><br>
Compartiment administrare infrastructură I.T. și baze de date
</td>
</tr>
</table>
<!-- Linia de departajare -->
<hr style="border: 0; border-top: 1px solid #000; margin-top: 5px; margin-bottom: 15px;">
<!-- 3. TITLUL -->
<div class="title">
PROCES VERBAL DE CASARE (SCOATERE DIN FUNCȚIUNE)<br>
Nr. {{ record.document_number }} din {{ record.date|date:"d.m.Y" }}
</div>
<!-- 4. CONȚINUTUL -->
<p>Prezentul proces verbal s-a încheiat astăzi, <strong>{{ record.date|date:"d F Y"|lower }}</strong>, pentru scoaterea din funcțiune și casarea următoarelor echipamente de calcul și periferice:</p>
<ul>
{% for pc in record.computers.all %}
<li>
unitate centrală, nr. inventar {{ pc.equipment_code }}, caracteristici:
{{ pc.cpu|default:"-" }} | {{ pc.ram|default:"-" }} | {{ pc.motherboard|default:"-" }}.
</li>
{% endfor %}
{% for mon in record.monitors.all %}
<li>
monitor, nr. inventar {{ mon.equipment_code }}, model: {{ mon.name|default:"-" }}.
</li>
{% endfor %}
{% for per in record.peripherals.all %}
<li>
periferic ({{ per.get_peripheral_type_display }}), nr. inventar {{ per.equipment_code }}, model: {{ per.name|default:"-" }}.
</li>
{% endfor %}
</ul>
<p><strong>Motivul casării:</strong> {{ record.reason }}</p>
<!-- 5. SEMNĂTURILE -->
<table style="width: 100%; border: none; margin-top: 40px; text-align: center;">
<tr>
<td style="width: 50%; border: none; vertical-align: top;">
<strong>Membrii Comisiei de Casare:</strong><br><br>
{{ record.committee_members|linebreaksbr }}<br><br><br>
Semnături:<br>
...............................................<br><br>
...............................................
</td>
<td style="width: 50%; border: none; vertical-align: top;">
<strong>Întocmit de,</strong><br><br>
{{ generated_by }}<br><br><br>
Semnătură:<br>
...............................................
</td>
</tr>
</table>
</body>
</html>
@@ -0,0 +1,149 @@
<!DOCTYPE html>
<html lang="ro">
<head>
<meta charset="UTF-8">
<style>
@font-face {
font-family: 'LiberationSerif';
src: url('{{ font_regular }}');
}
@font-face {
font-family: 'LiberationSerif';
src: url('{{ font_bold }}');
font-weight: bold;
}
@page {
size: A4 portrait;
margin: 1.5cm;
margin-bottom: 2.5cm; /* Lăsăm loc pentru footer */
/* Așa forțăm xhtml2pdf să lipească footer-ul de marginea de jos pe fiecare pagină */
@frame footer_frame {
-pdf-frame-content: footer_content;
left: 1.5cm;
right: 1.5cm;
bottom: 1cm;
height: 1.5cm;
}
}
body {
font-family: 'LiberationSerif', serif;
font-size: 14px;
color: #333;
line-height: 1.3;
}
.title { text-align: center; font-size: 16px; font-weight: bold; margin-top: 15px; margin-bottom: 20px; }
ul { margin-top: 5px; margin-bottom: 10px; }
li { margin-bottom: 4px; text-align: justify; }
p { margin-bottom: 8px; }
</style>
</head>
<body>
<!-- 1. FOOTER-UL (Capturat de rama "footer_frame" setată în CSS) -->
<div id="footer_content">
<table style="width: 100%; border-top: 1px dashed #ccc; padding-top: 5px; font-size: 10px; color: #555;">
<tr>
<td style="text-align: left; width: 70%; border: none;">
Generat de E.U.M.I. v.4.0.0 &bull; Aplicație dezvoltată de Tololoi Cătălin (catalin@x3c.ro)
</td>
<td style="text-align: right; width: 30%; border: none;">
pag. <pdf:pagenumber> din <pdf:pagecount>
</td>
</tr>
</table>
</div>
<!-- 2. ANTETUL -->
<table style="width: 100%; border: none;">
<tr>
<td style="width: 15%; text-align: left; vertical-align: middle; border: none;">
{% if logo_path %}
<img src="{{ logo_path }}" width="50">
{% endif %}
</td>
<td style="width: 85%; text-align: right; vertical-align: middle; border: none;">
<strong>U.A.T. Municipiul Roman</strong><br>
Compartiment administrare infrastructură I.T. și baze de date
</td>
</tr>
</table>
<!-- Linia de departajare -->
<hr style="border: 0; border-top: 1px solid #000; margin-top: 5px; margin-bottom: 15px;">
<!-- 3. TITLUL -->
<div class="title">
PROCES VERBAL DE PREDARE &ndash; PRIMIRE<br>
Nr. {{ protocol.document_number }}
</div>
<!-- 4. CONȚINUTUL -->
<p>Încheiat astăzi: <strong>{{ protocol.date|date:"d F Y"|lower }}</strong>, între:</p>
<!-- ATENȚIE: Înlocuiește "job_title" și "department" cu variabilele corecte din modelul tău Employee -->
<p>
<strong>{{ protocol.previous_holder.name|default:"Magazie (Neasignat)" }}</strong>, având funcția de
{{ protocol.previous_holder.job_title|default:"-" }} de la {{ protocol.previous_holder.department|default:"-" }},
în calitate de <strong>PREDĂTOR</strong>
</p>
<p style="text-align: center;">și</p>
<p>
<strong>{{ protocol.new_holder.name|default:"Magazie (Neasignat)" }}</strong>, având funcția de
{{ protocol.new_holder.job_title|default:"-" }} de la {{ protocol.new_holder.department|default:"-" }},
în calitate de <strong>PRIMITOR</strong>
</p>
<p>Primitorul a preluat de la predător următoarele:</p>
<ul>
{% for pc in protocol.computers.all %}
<li>
unitate centrală, nr. inventar {{ pc.equipment_code }}, caracteristici:
{{ pc.cpu|default:"-" }} | {{ pc.motherboard|default:"-" }} |
{{ pc.ram|default:"-" }} | {{ pc.storage|default:"-" }} |
{{ pc.mac_address|default:"-" }};
</li>
{% endfor %}
{% for mon in protocol.monitors.all %}
<li>
monitor, nr. inventar {{ mon.equipment_code }}, {{ mon.name|default:"-" }},
s/n {{ mon.serial_number|default:"-" }};
</li>
{% endfor %}
{% for per in protocol.peripherals.all %}
<li>
periferic ({{ per.get_peripheral_type_display }}), nr. inventar {{ per.equipment_code }},
{{ per.name|default:"-" }}, s/n {{ per.serial_number|default:"-" }};
</li>
{% endfor %}
</ul>
<p><strong>Observații:</strong> {{ protocol.notes|default:"Fără observații." }}</p>
<!-- 5. SEMNĂTURILE -->
<table style="width: 100%; border: none; margin-top: 30px; text-align: center;">
<tr>
<td style="width: 33%; border: none; vertical-align: top;">
<strong>Am predat,</strong><br><br><br><br>
...................................
</td>
<td style="width: 34%; border: none; vertical-align: top;">
<strong>Avizat I.T.,</strong><br>
{{ generated_by }}<br><br><br>
...................................
</td>
<td style="width: 33%; border: none; vertical-align: top;">
<strong>Am primit,</strong><br><br><br><br>
...................................
</td>
</tr>
</table>
</body>
</html>
@@ -0,0 +1,64 @@
{% extends 'base.html' %}
{% block content %}
<div class="d-flex justify-content-between align-items-center mb-4">
<h2 class="fw-bold">Fișă Tehnică Periferic: {{ peripheral.equipment_code }}</h2>
<a href="{% url 'equipment:equipment_list' %}" class="btn btn-outline-secondary">⬅️ Înapoi la Inventar</a>
</div>
<div class="row g-4">
<div class="col-md-5">
<div class="card shadow-sm h-100">
<div class="card-header bg-dark text-white fw-bold">Specificații Curente</div>
<ul class="list-group list-group-flush">
<li class="list-group-item"><strong>Tip:</strong> {{ peripheral.get_peripheral_type_display }}</li>
<li class="list-group-item"><strong>Model:</strong> {{ peripheral.name }}</li>
<li class="list-group-item"><strong>Serial (S/N):</strong> {{ peripheral.serial_number }}</li>
<li class="list-group-item"><strong>Utilizator Curent:</strong> {{ peripheral.assigned_to.name|default:"Neasignat" }}</li>
<li class="list-group-item"><strong>Observații:</strong> {{ peripheral.observations|default:"-" }}</li>
</ul>
</div>
</div>
<div class="col-md-7">
<div class="card shadow-sm">
<div class="card-header bg-warning text-dark fw-bold d-flex justify-content-between align-items-center">
<span>Jurnal Mentenanță</span>
<button class="btn btn-sm btn-dark" hx-get="{% url 'equipment:peripheral_maintenance_create' peripheral.id %}" hx-target="#modal-content-area" data-bs-toggle="modal" data-bs-target="#form-modal">+ Adaugă Intervenție</button>
</div>
<div class="card-body p-0">
<table class="table table-sm table-striped mb-0">
<thead class="table-light"><tr><th>Dată</th><th>Tip Operațiune</th><th>Efectuat de</th></tr></thead>
<tbody>
{% for log in maintenance_logs %}
<tr><td>{{ log.date|date:"d.m.Y" }}</td><td>{{ log.operation_type }}<br><small class="text-muted">{{ log.description }}</small></td><td>{{ log.performed_by }}</td></tr>
{% empty %}
<tr><td colspan="3" class="text-center py-3">Nu există intervenții de mentenanță.</td></tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
</div>
<h5 class="fw-bold mt-4 mb-3 border-bottom pb-2">Istoric Posesie (Custodie)</h5>
<ul class="list-group mb-4 shadow-sm">
{% for record in ownership_history %}
<li class="list-group-item d-flex justify-content-between align-items-center">
<div>
<strong>👤 {{ record.owner }}</strong>
</div>
<div class="text-muted small">
{{ record.start_date|date:"d.m.Y" }}
<span class="mx-1">→</span>
{% if record.end_date %}
{{ record.end_date|date:"d.m.Y" }}
{% else %}
<span class="badge bg-success">Prezent</span>
{% endif %}
</div>
</li>
{% empty %}
<li class="list-group-item text-muted text-center">Fără istoric de posesie.</li>
{% endfor %}
</ul>
</div>
<div class="modal fade" id="form-modal" tabindex="-1" aria-hidden="true"><div class="modal-dialog"><div class="modal-content" id="modal-content-area"></div></div></div>
{% endblock %}
@@ -0,0 +1,76 @@
<!DOCTYPE html>
<html lang="ro">
<head>
<meta charset="UTF-8">
<title>PV Predare-Primire {{ protocol.document_number }}</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet">
<style>
@media print { .no-print { display: none !important; } }
body { font-size: 14px; line-height: 1.6; }
.signature-box { margin-top: 60px; }
</style>
</head>
<body class="p-5">
<div class="text-end mb-4 no-print">
<button class="btn btn-primary" onclick="window.print()">Printează PV</button>
</div>
<h3 class="text-center fw-bold mb-2">PROCES VERBAL DE PREDARE – PRIMIRE</h3>
<h4 class="text-center fw-bold mb-4">Nr. {{ protocol.document_number }}</h4>
<p>
Încheiat astăzi: <strong>{{ protocol.date|date:"d F Y" }}</strong>, între:<br><br>
<strong>{{ protocol.previous_holder.name|default:"____________________" }}</strong>, având funcția
{{ protocol.previous_holder.role|default:"____________________" }} -
{% if protocol.previous_holder.compartiment %}{{ protocol.previous_holder.compartiment.name }}
{% elif protocol.previous_holder.serviciu %}{{ protocol.previous_holder.serviciu.name }}
{% elif protocol.previous_holder.directie %}{{ protocol.previous_holder.directie.name }}{% endif %},
în calitate de <strong>PREDĂTOR</strong> și<br><br>
<strong>{{ protocol.new_holder.name|default:"____________________" }}</strong>, având funcția
{{ protocol.new_holder.role|default:"____________________" }} -
{% if protocol.new_holder.compartiment %}{{ protocol.new_holder.compartiment.name }}
{% elif protocol.new_holder.serviciu %}{{ protocol.new_holder.serviciu.name }}
{% elif protocol.new_holder.directie %}{{ protocol.new_holder.directie.name }}{% endif %},
în calitate de <strong>PRIMITOR</strong>.
</p>
<p class="mt-3">Primitorul a preluat de la predător echipamentul de mai jos:</p>
<div class="mb-4 ps-3">
{% for pc in protocol.computers.all %}
<strong>Unitate centrală:</strong> nr. inventar {{ pc.equipment_code }} | Procesor: {{ pc.cpu }} | Placă de bază: {{ pc.motherboard }} | RAM: {{ pc.ram }} | Stocare: {{ pc.storage }} {% if pc.optical_drive %}| Optic: {{ pc.optical_drive }}{% endif %} | MAC {{ pc.mac_address }} | Licența S.O.: {{ pc.os_license }} {% if pc.additional_licenses %}| Licențe: {{ pc.additional_licenses }}{% endif %};<br>
{% endfor %}
{% for monitor in protocol.monitors.all %}
<strong>Monitor:</strong> nr. inventar {{ monitor.equipment_code }} | Denumire: {{ monitor.name }} | s/n: {{ monitor.serial_number }};<br>
{% endfor %}
{% for peripheral in protocol.peripherals.all %}
<strong>{{ peripheral.get_peripheral_type_display }}:</strong> nr. inventar {{ peripheral.equipment_code }} | Denumire: {{ peripheral.name }} | s/n: {{ peripheral.serial_number }};<br>
{% endfor %}
</div>
<div class="row signature-box">
<div class="col-4">
<strong>Întocmit,</strong><br>
Numele în clar: {{ protocol.it_validator }}<br>
Data: {{ protocol.date|date:"d.m.Y" }}<br>
Semnătura: ....................................
</div>
<div class="col-4">
<strong>Am predat,</strong><br>
Numele în clar: {{ protocol.previous_holder.name|default:"...................................." }}<br>
Data: {{ protocol.date|date:"d.m.Y" }}<br>
Semnătura: ....................................
</div>
<div class="col-4">
<strong>Am primit,</strong><br>
Numele în clar: {{ protocol.new_holder.name|default:"...................................." }}<br>
Data: {{ protocol.date|date:"d.m.Y" }}<br>
Semnătura: ....................................
</div>
</div>
</body>
</html>
@@ -0,0 +1,105 @@
{% load static %}
<!DOCTYPE html>
<html lang="ro">
<head>
<meta charset="UTF-8">
<title>Fișă Inventar - {{ employee.name }}</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet">
<style>
@media print {
.no-print { display: none !important; }
}
.signature-box { margin-top: 50px; }
</style>
</head>
<body class="p-4">
<div class="d-flex justify-content-between align-items-center mb-4">
<!-- Antet Oficial pentru interfața web -->
<div class="d-flex align-items-center mb-4 pb-3 border-bottom">
<img src="{% static 'img/stema.png' %}" alt="Stema Roman" style="width: 55px; height: auto;" class="me-3">
<div class="lh-sm">
<div class="fw-bold fs-5">U.A.T. Municipiul Roman</div>
<div class="text-secondary" style="font-size: 0.9em;">Compartiment administrare infrastructură I.T. și baze de date</div>
</div>
</div>
<button class="btn btn-primary no-print" onclick="window.print()">Printează Fișa</button>
</div>
<h3 class="text-center mb-4">Fișă de Inventar Echipamente IT</h3>
<h5 class="text-center text-muted mb-4">la data de: {% now "d.m.Y" %}</h5>
<div class="mb-4">
<strong>Nume Angajat:</strong> {{ employee.name }}<br>
<strong>Funcție:</strong> {{ employee.role }}<br>
<strong>Birou:</strong> {{ employee.office_number }}<br>
<strong>Structură:</strong>
{% if employee.directie %}{{ employee.directie.name }}{% endif %}
{% if employee.serviciu %} / {{ employee.serviciu.name }}{% endif %}
{% if employee.compartiment %} / {{ employee.compartiment.name }}{% endif %}
</div>
<h4>Echipamente în custodie</h4>
<table class="table table-bordered table-sm mt-3">
<thead class="table-light">
<tr>
<th>Cod Echipament</th>
<th>Tip</th>
<th>Detalii / Producător</th>
</tr>
</thead>
<tbody>
{% for pc in inventory.computers %}
<tr>
<td class="align-middle">{{ pc.equipment_code }}</td>
<td class="align-middle">Computer/Laptop</td>
<td>
<strong>{{ pc.oem_name|default:"Sistem Asamblat" }}</strong><br>
<span style="font-size: 0.9em;">
<strong>Procesor:</strong> {{ pc.cpu }} | <strong>Placă de bază:</strong> {{ pc.motherboard }} | <strong>RAM:</strong> {{ pc.ram }} | <strong>Stocare:</strong> {{ pc.storage }} {% if pc.optical_drive %}| <strong>Optic:</strong> {{ pc.optical_drive }}{% endif %}<br>
<strong>MAC:</strong> {{ pc.mac_address }} | <strong>Licența S.O.:</strong> {{ pc.os_license }} {% if pc.additional_licenses %}| <strong>Licențe:</strong> {{ pc.additional_licenses }}{% endif %}
</span>
</td>
</tr>
{% endfor %}
{% for monitor in inventory.monitors %}
<tr>
<td class="align-middle">{{ monitor.equipment_code }}</td>
<td class="align-middle">Monitor</td>
<td>
<strong>{{ monitor.name }}</strong><br>
<span style="font-size: 0.9em;">
<strong>Diagonală:</strong> {{ monitor.screen_diagonal }} | <strong>S/N:</strong> {{ monitor.serial_number }}
{% if monitor.observations %}<br><strong>Observații:</strong> {{ monitor.observations }}{% endif %}
</span>
</td>
</tr>
{% endfor %}
{% for peripheral in inventory.peripherals %}
<tr>
<td class="align-middle">{{ peripheral.equipment_code }}</td>
<td class="align-middle">{{ peripheral.get_peripheral_type_display }}</td>
<td>
<strong>{{ peripheral.name }}</strong><br>
<span style="font-size: 0.9em;">
<strong>S/N:</strong> {{ peripheral.serial_number }}
</span>
</td>
</tr>
{% endfor %}
</tbody>
</table>
<div class="row signature-box">
<div class="col-6 text-center">
<strong>Compartimentul IT</strong><br><br>
....................................
</div>
<div class="col-6 text-center">
<strong>Semnătură Titular (Angajat)</strong><br><br>
....................................
</div>
</div>
</body>
</html>
@@ -0,0 +1,127 @@
{% extends 'base.html' %}
{% block content %}
<div class="d-flex justify-content-between align-items-center mb-4">
<h2 class="fw-bold">Fișă Tehnică: {{ computer.equipment_code }}</h2>
<a href="{% url 'equipment:equipment_list' %}" class="btn btn-outline-secondary">⬅️ Înapoi la Inventar</a>
</div>
<div class="row g-4">
<!-- Left Column: Current Specs -->
<div class="col-md-5">
<div class="card shadow-sm h-100">
<div class="card-header bg-dark text-white fw-bold">Specificații Curente</div>
<ul class="list-group list-group-flush">
<li class="list-group-item"><strong>OEM:</strong> {{ computer.oem_name|default:"Sistem Asamblat" }}</li>
<li class="list-group-item"><strong>Placă de bază:</strong> {{ computer.motherboard }}</li>
<li class="list-group-item"><strong>CPU:</strong> {{ computer.cpu }}</li>
<li class="list-group-item"><strong>RAM:</strong> {{ computer.ram }}</li>
<li class="list-group-item"><strong>Stocare:</strong> {{ computer.storage }}</li>
<li class="list-group-item"><strong>OS:</strong> {{ computer.os_license }}</li>
<li class="list-group-item"><strong>MAC:</strong> {{ computer.mac_address }}</li>
<li class="list-group-item"><strong>Utilizator Curent:</strong> {{ computer.assigned_to.name|default:"Neasignat" }}</li>
</ul>
</div>
</div>
<!-- Right Column: History & Maintenance -->
<div class="col-md-7">
<!-- Hardware History -->
<div class="card shadow-sm mb-4">
<div class="card-header bg-primary text-white fw-bold">Istoric Modificări Hardware</div>
<div class="card-body p-0">
<table class="table table-sm table-striped mb-0">
<thead class="table-light">
<tr>
<th>Dată</th>
<th>Componentă</th>
<th>Valoare Veche</th>
<th>Valoare Nouă</th>
</tr>
</thead>
<tbody>
{% for change in hardware_changes %}
<tr>
<td>{{ change.date|date:"d.m.Y H:i" }}</td>
<td><strong>{{ change.field }}</strong></td>
<td class="text-danger text-decoration-line-through">{{ change.old|default:"-" }}</td>
<td class="text-success">{{ change.new|default:"-" }}</td>
</tr>
{% empty %}
<tr><td colspan="4" class="text-center py-3">Nu există modificări hardware înregistrate.</td></tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
<!-- Maintenance Logs -->
<div class="card shadow-sm">
<div class="card-header bg-warning text-dark fw-bold d-flex justify-content-between align-items-center">
<span>Jurnal Mentenanță</span>
<!-- Buton care deschide modalul HTMX -->
{% if user.is_staff %}
<button class="btn btn-sm btn-dark"
hx-get="{% url 'equipment:computer_maintenance_create' computer.id %}"
hx-target="#modal-content-area"
data-bs-toggle="modal"
data-bs-target="#form-modal">
+ Adaugă Mentenanță
</button>
{% endif %}
</div>
<div class="card-body p-0">
<table class="table table-sm table-striped mb-0">
<thead class="table-light">
<tr>
<th>Dată</th>
<th>Tip Operațiune</th>
<th>Efectuat de</th>
</tr>
</thead>
<tbody>
{% for log in maintenance_logs %}
<tr>
<td>{{ log.date|date:"d.m.Y" }}</td>
<td>{{ log.operation_type }}<br><small class="text-muted">{{ log.description }}</small></td>
<td>{{ log.performed_by }}</td>
</tr>
{% empty %}
<tr><td colspan="3" class="text-center py-3">Nu există intervenții de mentenanță.</td></tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
</div>
<h5 class="fw-bold mt-4 mb-3 border-bottom pb-2">Istoric Posesie (Custodie)</h5>
<ul class="list-group mb-4 shadow-sm">
{% for record in ownership_history %}
<li class="list-group-item d-flex justify-content-between align-items-center">
<div>
<strong>👤 {{ record.owner }}</strong>
</div>
<div class="text-muted small">
{{ record.start_date|date:"d.m.Y" }}
<span class="mx-1">→</span>
{% if record.end_date %}
{{ record.end_date|date:"d.m.Y" }}
{% else %}
<span class="badge bg-success">Prezent</span>
{% endif %}
</div>
</li>
{% empty %}
<li class="list-group-item text-muted text-center">Fără istoric de posesie.</li>
{% endfor %}
</ul>
</div>
<div class="modal fade" id="form-modal" tabindex="-1" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content" id="modal-content-area">
<!-- Conținutul se va încărca dinamic -->
</div>
</div>
</div>
{% endblock %}