All checks were successful
Deploy MES Core / deploy (push) Successful in 13s
218 lines
12 KiB
HTML
218 lines
12 KiB
HTML
{% 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 %} |