Конкретно пересмотрел логику работы. Легаси вынесена в архив
All checks were successful
Deploy MES Core / deploy (push) Successful in 13s

This commit is contained in:
2026-04-13 07:36:57 +03:00
parent 86215c9fa8
commit 28537447f8
80 changed files with 10246 additions and 684 deletions

View File

@@ -0,0 +1,218 @@
{% extends 'base.html' %}
{% block content %}
<div class="card shadow border-secondary">
<div class="card-header border-secondary py-3 d-flex justify-content-between align-items-center">
<div class="w-100">
<div class="d-flex flex-wrap align-items-center gap-3 justify-content-between">
<h3 class="text-accent mb-0"><i class="bi bi-truck me-2"></i>Снабжение</h3>
<form method="get" class="d-flex flex-wrap align-items-center gap-2">
<input type="hidden" name="filtered" value="1">
<div class="d-flex w-100 mb-2 gap-2">
<input type="text" class="form-control form-control-sm border-secondary" name="q" placeholder="Сделка / компонент" value="{{ q }}" style="max-width: 300px;">
<button type="submit" class="btn btn-outline-accent btn-sm">
<i class="bi bi-search me-1"></i>Применить
</button>
<a class="btn btn-outline-secondary btn-sm" href="{% url 'procurement' %}">Сброс</a>
<div class="ms-auto">
<button type="submit" name="print" value="1" class="btn btn-outline-secondary btn-sm" formtarget="_blank">
<i class="bi bi-printer me-1"></i>Печать
</button>
</div>
</div>
<div class="d-flex align-items-center gap-1">
<input type="checkbox" class="btn-check" name="grouped" id="grouped" value="1" {% if grouped %}checked{% endif %} onchange="this.form.submit()">
<label class="btn btn-outline-accent btn-sm" for="grouped"><i class="bi bi-layers me-1"></i>Группировать</label>
</div>
<div class="d-flex flex-wrap align-items-center gap-1">
<span class="small text-muted me-1">Тип:</span>
{% for code, label in type_choices %}
<input type="checkbox" class="btn-check" name="types" id="type_{{ code }}" value="{{ code }}" {% if code in selected_types %}checked{% endif %} onchange="this.form.submit()">
<label class="btn btn-sm {% if code == 'raw' %}btn-outline-info{% elif code == 'purchased' %}btn-outline-primary{% elif code == 'casting' %}btn-outline-secondary{% elif code == 'outsourced' %}btn-outline-warning{% else %}btn-outline-secondary{% endif %}" for="type_{{ code }}">{{ label }}</label>
{% endfor %}
</div>
<div class="d-flex flex-wrap align-items-center gap-1">
<span class="small text-muted me-1">Статус:</span>
{% for code, label in status_choices %}
<input type="checkbox" class="btn-check" name="statuses" id="st_{{ code }}" value="{{ code }}" {% if code in selected_statuses %}checked{% endif %} onchange="this.form.submit()">
<label class="btn btn-sm {% if code == 'to_order' %}btn-outline-danger{% elif code == 'ordered' %}btn-outline-warning{% else %}btn-outline-success{% endif %}" for="st_{{ code }}">{{ label }}</label>
{% endfor %}
</div>
</form>
</div>
</div>
</div>
<div class="card-body p-0">
<div class="table-responsive">
<table class="table table-hover mb-0 align-middle" data-sortable="1">
<thead>
<tr class="table-custom-header">
<th>Компонент</th>
<th style="width: 140px;">Тип</th>
<th style="width: 140px;">К заказу</th>
<th style="width: 220px;">Сделки</th>
<th style="width: 140px;">Статус</th>
<th style="width: 70px;" data-sort="false"></th>
</tr>
</thead>
<tbody>
{% for r in requirements %}
<tr>
<td>
<div class="fw-semibold">{{ r.component_label }}</div>
</td>
<td class="small">
{% if r.type == 'raw' %}Сырьё{% elif r.type == 'purchased' %}Покупное{% elif r.type == 'casting' %}Литьё{% elif r.type == 'outsourced' %}Аутсорс{% else %}—{% endif %}
</td>
<td class="fw-semibold">
{{ r.required_qty }}{% if r.kind == 'raw' %} {{ r.unit }}{% endif %}
</td>
<td>
{% if r.deals and r.deals|length > 0 %}
{% for dn in r.deals|slice:":3" %}
<span class="badge bg-secondary">{{ dn }}</span>
{% endfor %}
{% if r.deals|length > 3 %}
<span class="badge bg-secondary" title="{{ r.deals|join:", " }}"></span>
{% endif %}
{% else %}
<span class="text-muted"></span>
{% endif %}
</td>
<td>
{% if r.status == 'to_order' %}
<span class="badge bg-danger">К заказу</span>
{% elif r.status == 'ordered' %}
<span class="badge bg-warning text-dark">Заказано</span>
{% else %}
<span class="badge bg-success">Закрыто</span>
{% endif %}
</td>
<td class="text-end">
{% if can_edit and not grouped and r.kind == 'component' %}
{% if r.status == 'to_order' %}
<form method="post" class="d-inline">
{% csrf_token %}
<input type="hidden" name="action" value="mark_ordered">
<input type="hidden" name="pr_id" value="{{ r.obj_id }}">
<input type="hidden" name="next" value="{{ request.get_full_path }}">
<button type="submit" class="btn btn-outline-accent btn-sm" title="Отметить как заказано">+</button>
</form>
{% elif r.status == 'ordered' %}
<button
type="button"
class="btn btn-outline-accent btn-sm"
title="Оформить приход"
data-bs-toggle="modal"
data-bs-target="#receiveModal"
data-pr-id="{{ r.obj_id }}"
data-label="{{ r.component_label }}"
data-deal-id="{{ r.deal_id }}"
data-deal-number="{{ r.deals.0 }}"
data-max="{{ r.required_qty }}"
>+</button>
{% else %}
<span class="text-muted"></span>
{% endif %}
{% else %}
<span class="text-muted"></span>
{% endif %}
</td>
</tr>
{% empty %}
<tr><td colspan="6" class="text-center p-5 text-muted">Потребностей не найдено</td></tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
</div>
<div class="modal fade" id="receiveModal" tabindex="-1" aria-hidden="true">
<div class="modal-dialog">
<form method="post" class="modal-content border-secondary">
{% csrf_token %}
<input type="hidden" name="action" value="receive_component">
<input type="hidden" name="next" value="{{ request.get_full_path }}">
<input type="hidden" name="pr_id" id="receivePrId">
<div class="modal-header border-secondary">
<h5 class="modal-title">Приход компонента</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Закрыть"></button>
</div>
<div class="modal-body">
<div class="mb-2 small text-muted" id="receiveLabel"></div>
<div class="mb-3">
<label class="form-label">Склад</label>
<select class="form-select border-secondary" name="location_id" required>
{% for loc in locations %}
<option value="{{ loc.id }}">{{ loc.name }}</option>
{% endfor %}
</select>
</div>
<div class="mb-3">
<label class="form-label">Сделка (опционально)</label>
<select class="form-select border-secondary" name="deal_id" id="receiveDealId">
<option value="">Свободно</option>
{% for d in deals %}
<option value="{{ d.id }}">{{ d.number }}</option>
{% endfor %}
</select>
</div>
<div class="mb-3">
<label class="form-label">Количество (шт)</label>
<input class="form-control border-secondary" name="quantity" id="receiveQty" placeholder="Напр. 100" required>
<div class="form-text">Количество уменьшит потребность выбранной строки. При достижении 0 статус станет «Закрыто».</div>
</div>
</div>
<div class="modal-footer border-secondary">
<button type="button" class="btn btn-outline-secondary" data-bs-dismiss="modal">Отмена</button>
<button type="submit" class="btn btn-outline-accent">Оформить</button>
</div>
</form>
</div>
</div>
<script>
(function () {
const modal = document.getElementById('receiveModal');
if (!modal) return;
const prId = document.getElementById('receivePrId');
const label = document.getElementById('receiveLabel');
const dealId = document.getElementById('receiveDealId');
const qty = document.getElementById('receiveQty');
modal.addEventListener('show.bs.modal', function (event) {
const btn = event.relatedTarget;
if (!btn) return;
const id = btn.getAttribute('data-pr-id') || '';
const text = btn.getAttribute('data-label') || '';
const max = btn.getAttribute('data-max') || '';
const dId = btn.getAttribute('data-deal-id') || '';
const dNum = btn.getAttribute('data-deal-number') || '';
if (prId) prId.value = id;
if (label) label.textContent = (text ? ('Компонент: ' + text) : '') + (dNum ? (' · Сделка: ' + dNum) : '');
if (dealId) dealId.value = dId;
if (qty) {
qty.value = max || '';
qty.focus();
qty.select();
}
});
})();
</script>
{% endblock %}