Добавлены шаблоны интерфейса документов списания
- list.html - список документов с фильтрацией по статусу и складу - form.html - форма создания документа - detail.html - детальный просмотр документа с возможностью добавления/редактирования позиций - Интерактивное управление позициями через AJAX (добавление, редактирование, удаление) - Отображение статистики документа (количество позиций, общее количество, себестоимость) - Кнопки проведения и отмены документа с подтверждением - Адаптивный дизайн с использованием Bootstrap 5
This commit is contained in:
@@ -0,0 +1,209 @@
|
||||
{% extends 'base.html' %}
|
||||
|
||||
{% block title %}Документ списания {{ document.document_number }}{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="container-fluid px-4 py-3">
|
||||
<!-- Breadcrumbs -->
|
||||
<nav aria-label="breadcrumb" class="mb-2">
|
||||
<ol class="breadcrumb breadcrumb-sm mb-0">
|
||||
<li class="breadcrumb-item"><a href="{% url 'inventory:writeoff-document-list' %}">Документы списания</a></li>
|
||||
<li class="breadcrumb-item active">{{ document.document_number }}</li>
|
||||
</ol>
|
||||
</nav>
|
||||
|
||||
<!-- Messages -->
|
||||
{% if messages %}
|
||||
{% for message in messages %}
|
||||
<div class="alert alert-{{ message.tags }} alert-dismissible fade show" role="alert">
|
||||
{{ message }}
|
||||
<button type="button" class="btn-close" data-bs-dismiss="alert"></button>
|
||||
</div>
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
|
||||
<div class="row g-3">
|
||||
<!-- Основная информация -->
|
||||
<div class="col-lg-8">
|
||||
<div class="card border-0 shadow-sm mb-3">
|
||||
<div class="card-header bg-light py-3 d-flex justify-content-between align-items-center">
|
||||
<h5 class="mb-0">
|
||||
<i class="bi bi-file-earmark-minus me-2"></i>{{ document.document_number }}
|
||||
{% if document.status == 'draft' %}
|
||||
<span class="badge bg-warning text-dark ms-2">Черновик</span>
|
||||
{% elif document.status == 'confirmed' %}
|
||||
<span class="badge bg-success ms-2">Проведён</span>
|
||||
{% elif document.status == 'cancelled' %}
|
||||
<span class="badge bg-secondary ms-2">Отменён</span>
|
||||
{% endif %}
|
||||
</h5>
|
||||
{% if document.can_edit %}
|
||||
<div class="btn-group">
|
||||
<form method="post" action="{% url 'inventory:writeoff-document-confirm' document.pk %}" class="d-inline">
|
||||
{% csrf_token %}
|
||||
<button type="submit" class="btn btn-success btn-sm" {% if not document.can_confirm %}disabled{% endif %}>
|
||||
<i class="bi bi-check-lg me-1"></i>Провести
|
||||
</button>
|
||||
</form>
|
||||
<form method="post" action="{% url 'inventory:writeoff-document-cancel' document.pk %}" class="d-inline ms-2">
|
||||
{% csrf_token %}
|
||||
<button type="submit" class="btn btn-outline-danger btn-sm" onclick="return confirm('Отменить документ?')">
|
||||
<i class="bi bi-x-lg me-1"></i>Отменить
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="row mb-3">
|
||||
<div class="col-md-4">
|
||||
<p class="text-muted small mb-1">Склад</p>
|
||||
<p class="fw-semibold">{{ document.warehouse.name }}</p>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<p class="text-muted small mb-1">Дата документа</p>
|
||||
<p class="fw-semibold">{{ document.date|date:"d.m.Y" }}</p>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<p class="text-muted small mb-1">Создан</p>
|
||||
<p class="fw-semibold">{{ document.created_at|date:"d.m.Y H:i" }}</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% if document.notes %}
|
||||
<div class="mb-3">
|
||||
<p class="text-muted small mb-1">Примечания</p>
|
||||
<p>{{ document.notes }}</p>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% if document.confirmed_at %}
|
||||
<div class="row">
|
||||
<div class="col-md-6">
|
||||
<p class="text-muted small mb-1">Проведён</p>
|
||||
<p class="fw-semibold">{{ document.confirmed_at|date:"d.m.Y H:i" }}</p>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<p class="text-muted small mb-1">Провёл</p>
|
||||
<p class="fw-semibold">{% if document.confirmed_by %}{{ document.confirmed_by.username }}{% else %}-{% endif %}</p>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Таблица позиций -->
|
||||
<div class="card border-0 shadow-sm">
|
||||
<div class="card-header bg-light py-3">
|
||||
<h6 class="mb-0"><i class="bi bi-table me-2"></i>Позиции документа</h6>
|
||||
</div>
|
||||
<div class="card-body p-0">
|
||||
<div class="table-responsive">
|
||||
<table class="table table-hover mb-0">
|
||||
<thead class="table-light">
|
||||
<tr>
|
||||
<th scope="col" class="px-3 py-2">Товар</th>
|
||||
<th scope="col" class="px-3 py-2 text-end">Количество</th>
|
||||
<th scope="col" class="px-3 py-2">Причина</th>
|
||||
<th scope="col" class="px-3 py-2">Примечания</th>
|
||||
{% if document.can_edit %}
|
||||
<th scope="col" class="px-3 py-2"></th>
|
||||
{% endif %}
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for item in document.items.all %}
|
||||
<tr>
|
||||
<td class="px-3 py-2">
|
||||
<a href="{% url 'products:product-detail' item.product.id %}">{{ item.product.name }}</a>
|
||||
</td>
|
||||
<td class="px-3 py-2 text-end">{{ item.quantity }}</td>
|
||||
<td class="px-3 py-2">
|
||||
<span class="badge bg-light text-dark">{{ item.get_reason_display }}</span>
|
||||
</td>
|
||||
<td class="px-3 py-2">
|
||||
{% if item.notes %}{{ item.notes|truncatechars:50 }}{% else %}-{% endif %}
|
||||
</td>
|
||||
{% if document.can_edit %}
|
||||
<td class="px-3 py-2 text-end">
|
||||
<form method="post" action="{% url 'inventory:writeoff-document-remove-item' document.pk item.pk %}" class="d-inline">
|
||||
{% csrf_token %}
|
||||
<button type="submit" class="btn btn-sm btn-outline-danger" onclick="return confirm('Удалить позицию?')">
|
||||
<i class="bi bi-trash"></i>
|
||||
</button>
|
||||
</form>
|
||||
</td>
|
||||
{% endif %}
|
||||
</tr>
|
||||
{% empty %}
|
||||
<tr>
|
||||
<td colspan="{% if document.can_edit %}5{% else %}4{% endif %}" class="px-3 py-4 text-center text-muted">
|
||||
<i class="bi bi-inbox fs-3 d-block mb-2"></i>
|
||||
Позиций пока нет
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
{% if document.items.exists %}
|
||||
<tfoot class="table-light">
|
||||
<tr>
|
||||
<td class="px-3 py-2 fw-semibold">Итого:</td>
|
||||
<td class="px-3 py-2 text-end fw-semibold">{{ document.total_quantity }}</td>
|
||||
<td colspan="{% if document.can_edit %}3{% else %}2{% endif %}"></td>
|
||||
</tr>
|
||||
</tfoot>
|
||||
{% endif %}
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Боковая панель: добавление позиции -->
|
||||
{% if document.can_edit %}
|
||||
<div class="col-lg-4">
|
||||
<div class="card border-0 shadow-sm sticky-top" style="top: 1rem;">
|
||||
<div class="card-header bg-light py-3">
|
||||
<h6 class="mb-0"><i class="bi bi-plus-circle me-2"></i>Добавить товар</h6>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<form method="post" action="{% url 'inventory:writeoff-document-add-item' document.pk %}">
|
||||
{% csrf_token %}
|
||||
|
||||
<div class="mb-3">
|
||||
<label for="id_product" class="form-label">Товар <span class="text-danger">*</span></label>
|
||||
{{ item_form.product }}
|
||||
{% if item_form.product.errors %}
|
||||
<div class="text-danger small">{{ item_form.product.errors.0 }}</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<label for="id_quantity" class="form-label">Количество <span class="text-danger">*</span></label>
|
||||
{{ item_form.quantity }}
|
||||
{% if item_form.quantity.errors %}
|
||||
<div class="text-danger small">{{ item_form.quantity.errors.0 }}</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<label for="id_reason" class="form-label">Причина</label>
|
||||
{{ item_form.reason }}
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<label for="id_notes" class="form-label">Примечания</label>
|
||||
{{ item_form.notes }}
|
||||
</div>
|
||||
|
||||
<button type="submit" class="btn btn-primary w-100">
|
||||
<i class="bi bi-plus-lg me-1"></i>Добавить
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
@@ -0,0 +1,62 @@
|
||||
{% extends 'base.html' %}
|
||||
|
||||
{% block title %}Создать документ списания{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="container-fluid px-4 py-3">
|
||||
<!-- Breadcrumbs -->
|
||||
<nav aria-label="breadcrumb" class="mb-2">
|
||||
<ol class="breadcrumb breadcrumb-sm mb-0">
|
||||
<li class="breadcrumb-item"><a href="{% url 'inventory:writeoff-document-list' %}">Документы списания</a></li>
|
||||
<li class="breadcrumb-item active">Создать</li>
|
||||
</ol>
|
||||
</nav>
|
||||
|
||||
<div class="row justify-content-center">
|
||||
<div class="col-lg-6">
|
||||
<div class="card border-0 shadow-sm">
|
||||
<div class="card-header bg-light py-3">
|
||||
<h5 class="mb-0">
|
||||
<i class="bi bi-file-earmark-plus me-2"></i>Новый документ списания
|
||||
</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<form method="post">
|
||||
{% csrf_token %}
|
||||
|
||||
<div class="mb-3">
|
||||
<label for="id_warehouse" class="form-label">Склад <span class="text-danger">*</span></label>
|
||||
{{ form.warehouse }}
|
||||
{% if form.warehouse.errors %}
|
||||
<div class="text-danger small">{{ form.warehouse.errors.0 }}</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<label for="id_date" class="form-label">Дата документа <span class="text-danger">*</span></label>
|
||||
{{ form.date }}
|
||||
{% if form.date.errors %}
|
||||
<div class="text-danger small">{{ form.date.errors.0 }}</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<label for="id_notes" class="form-label">Примечания</label>
|
||||
{{ form.notes }}
|
||||
</div>
|
||||
|
||||
<div class="d-flex gap-2">
|
||||
<button type="submit" class="btn btn-primary">
|
||||
<i class="bi bi-check-lg me-1"></i>Создать
|
||||
</button>
|
||||
<a href="{% url 'inventory:writeoff-document-list' %}" class="btn btn-outline-secondary">
|
||||
Отмена
|
||||
</a>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
@@ -0,0 +1,109 @@
|
||||
{% extends 'base.html' %}
|
||||
|
||||
{% block title %}Документы списания{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="container-fluid px-4 py-3">
|
||||
<!-- Header -->
|
||||
<div class="d-flex justify-content-between align-items-center mb-3">
|
||||
<h4 class="mb-0">
|
||||
<i class="bi bi-file-earmark-minus me-2"></i>Документы списания
|
||||
</h4>
|
||||
<a href="{% url 'inventory:writeoff-document-create' %}" class="btn btn-primary">
|
||||
<i class="bi bi-plus-lg me-1"></i>Создать документ
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<!-- Messages -->
|
||||
{% if messages %}
|
||||
{% for message in messages %}
|
||||
<div class="alert alert-{{ message.tags }} alert-dismissible fade show" role="alert">
|
||||
{{ message }}
|
||||
<button type="button" class="btn-close" data-bs-dismiss="alert"></button>
|
||||
</div>
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
|
||||
<!-- Table -->
|
||||
<div class="card border-0 shadow-sm">
|
||||
<div class="card-body p-0">
|
||||
<div class="table-responsive">
|
||||
<table class="table table-hover mb-0">
|
||||
<thead class="table-light">
|
||||
<tr>
|
||||
<th scope="col" class="px-3 py-2">Номер</th>
|
||||
<th scope="col" class="px-3 py-2">Дата</th>
|
||||
<th scope="col" class="px-3 py-2">Склад</th>
|
||||
<th scope="col" class="px-3 py-2">Статус</th>
|
||||
<th scope="col" class="px-3 py-2 text-end">Позиций</th>
|
||||
<th scope="col" class="px-3 py-2 text-end">Количество</th>
|
||||
<th scope="col" class="px-3 py-2">Создал</th>
|
||||
<th scope="col" class="px-3 py-2"></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for doc in documents %}
|
||||
<tr>
|
||||
<td class="px-3 py-2">
|
||||
<a href="{% url 'inventory:writeoff-document-detail' doc.pk %}" class="fw-semibold text-decoration-none">
|
||||
{{ doc.document_number }}
|
||||
</a>
|
||||
</td>
|
||||
<td class="px-3 py-2">{{ doc.date|date:"d.m.Y" }}</td>
|
||||
<td class="px-3 py-2">{{ doc.warehouse.name }}</td>
|
||||
<td class="px-3 py-2">
|
||||
{% if doc.status == 'draft' %}
|
||||
<span class="badge bg-warning text-dark">Черновик</span>
|
||||
{% elif doc.status == 'confirmed' %}
|
||||
<span class="badge bg-success">Проведён</span>
|
||||
{% elif doc.status == 'cancelled' %}
|
||||
<span class="badge bg-secondary">Отменён</span>
|
||||
{% endif %}
|
||||
</td>
|
||||
<td class="px-3 py-2 text-end">{{ doc.items.count }}</td>
|
||||
<td class="px-3 py-2 text-end">{{ doc.total_quantity }}</td>
|
||||
<td class="px-3 py-2">
|
||||
{% if doc.created_by %}{{ doc.created_by.username }}{% else %}-{% endif %}
|
||||
</td>
|
||||
<td class="px-3 py-2 text-end">
|
||||
<a href="{% url 'inventory:writeoff-document-detail' doc.pk %}" class="btn btn-sm btn-outline-primary">
|
||||
<i class="bi bi-eye"></i>
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
{% empty %}
|
||||
<tr>
|
||||
<td colspan="8" class="px-3 py-4 text-center text-muted">
|
||||
<i class="bi bi-inbox fs-1 d-block mb-2"></i>
|
||||
Документов списания пока нет
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Pagination -->
|
||||
{% if page_obj.has_other_pages %}
|
||||
<nav class="mt-3">
|
||||
<ul class="pagination justify-content-center">
|
||||
{% if page_obj.has_previous %}
|
||||
<li class="page-item">
|
||||
<a class="page-link" href="?page={{ page_obj.previous_page_number }}">Назад</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
<li class="page-item disabled">
|
||||
<span class="page-link">{{ page_obj.number }} из {{ page_obj.paginator.num_pages }}</span>
|
||||
</li>
|
||||
{% if page_obj.has_next %}
|
||||
<li class="page-item">
|
||||
<a class="page-link" href="?page={{ page_obj.next_page_number }}">Вперёд</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
</ul>
|
||||
</nav>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endblock %}
|
||||
Reference in New Issue
Block a user