project2463/templates/add_order.html

737 lines
26 KiB
HTML
Raw Permalink 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 %}Добавление заказа{% endblock %}
{% block content %}
<div class="container">
<div class="row justify-content-center">
<div class="col-md-8">
<!-- Хлебные крошки -->
<nav aria-label="breadcrumb" class="mb-3">
<ol class="breadcrumb">
<li class="breadcrumb-item"><a href="{{ url_for('index') }}">Поставщики</a></li>
<li class="breadcrumb-item"><a href="{{ url_for('order_history', client_id=client.id) }}">{{ client.name }}</a></li>
<li class="breadcrumb-item active">Добавление заказа</li>
</ol>
</nav>
<div class="form-card">
<div class="form-card-header">
<h2 class="form-card-title">
<i class="fas fa-cart-plus"></i> Добавление заказа
</h2>
</div>
<div class="form-card-body">
<!-- Информация о поставщике -->
<div class="supplier-info mb-4">
<div class="supplier-info-header">
<i class="fas fa-truck"></i> Информация о поставщике
</div>
<div class="supplier-info-body">
<div class="row">
<div class="col-md-6">
<div class="info-item">
<span class="info-label">Поставщик:</span>
<span class="info-value">{{ client.name }}</span>
</div>
<div class="info-item">
<span class="info-label">Тип:</span>
<span class="info-value">{{ client.contractor_type_name }}</span>
</div>
</div>
<div class="col-md-6">
<div class="info-item">
<span class="info-label">Email:</span>
<span class="info-value">{{ client.email }}</span>
</div>
<div class="info-item">
<span class="info-label">Телефон:</span>
<span class="info-value">{{ client.phone or 'Не указан' }}</span>
</div>
</div>
</div>
</div>
</div>
<form method="POST" id="orderForm">
<div class="row">
<div class="col-md-6">
<div class="form-group">
<label for="product_id" class="form-label">
<i class="fas fa-cube"></i>
Материал
</label>
<div class="select-wrapper">
<select class="form-select modern-select" id="product_id" name="product_id" required>
<option value="" selected disabled>Выберите материал</option>
{% for product in products %}
<option value="{{ product.id }}"
data-price="{{ product.min_price }}"
data-name="{{ product.product_name }}"
data-stock="{{ product.quantity_in_stock or 0 }}">
{{ product.product_name }} ({{ product.article }}) - {{ product.min_price }} руб. (в наличии: {{ product.quantity_in_stock or 0 }})
</option>
{% endfor %}
</select>
<i class="fas fa-chevron-down select-arrow"></i>
</div>
</div>
<div class="form-group">
<label for="quantity" class="form-label">
<i class="fas fa-cubes"></i>
Количество
</label>
<input type="number" class="form-control modern-input" id="quantity" name="quantity"
min="1" max="0" required value="1">
<div class="form-text" id="maxQuantityHint">
<i class="fas fa-info-circle"></i>
Максимально доступно: <span id="maxAvailable">0</span> ед.
</div>
</div>
</div>
<div class="col-md-6">
<div class="form-group">
<label for="order_date" class="form-label">
<i class="fas fa-calendar-alt"></i>
Дата заказа
</label>
<input type="date" class="form-control modern-input" id="order_date" name="order_date"
required value="{{ today }}">
</div>
<!-- Скрытое поле для статуса (всегда "Новый") -->
<input type="hidden" name="status" value="Новый">
</div>
</div>
<!-- Информация о выбранном товаре -->
<div class="material-info-block mt-3">
<div class="material-info-row">
<div class="material-info-item">
<i class="fas fa-cog"></i>
<span class="material-info-label">Материал:</span>
<span class="material-info-value" id="selectedMaterial">Не выбран</span>
</div>
<div class="material-info-item text-end">
<i class="fas fa-warehouse"></i>
<span class="material-info-label">На складе:</span>
<span class="material-info-value" id="maxOrder">0</span> ед.
</div>
</div>
</div>
<!-- Автоматический расчет суммы со скидкой -->
<div class="calculation-block mt-4">
<div class="calculation-header">
<i class="fas fa-calculator"></i> Расчет стоимости
</div>
<div class="calculation-body">
<div class="calculation-row">
<span class="calculation-label">Количество:</span>
<span class="calculation-value"><span id="displayQuantity">1</span> ед.</span>
</div>
<div class="calculation-row">
<span class="calculation-label">Цена за единицу:</span>
<span class="calculation-value"><span id="displayPrice">0</span> руб.</span>
</div>
<div class="calculation-row">
<span class="calculation-label">Базовая сумма:</span>
<span class="calculation-value"><span id="baseAmount">0</span> руб.</span>
</div>
<div class="calculation-row">
<span class="calculation-label">Транспортные расходы (10%):</span>
<span class="calculation-value"><span id="transportAmount">0</span> руб.</span>
</div>
<div class="calculation-row total-row">
<span class="calculation-label">
<i class="fas fa-percent"></i>
Итоговая сумма <span id="discountPercentLabel"></span>:
</span>
<span class="calculation-value total-value">
<span id="totalAmount">0.00</span> руб.
</span>
</div>
</div>
</div>
<!-- Кнопки -->
<div class="form-actions">
<a href="javascript:history.back()" class="btn btn-outline">
<i class="fas fa-times"></i> Отмена
</a>
<button type="submit" class="btn btn-primary" id="submitBtn">
<i class="fas fa-save"></i> Создать заказ
</button>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
<style>
/* ===== ОСНОВНЫЕ ПЕРЕМЕННЫЕ ===== */
:root {
--antique-white: #FAEBD7;
--light-brown: #DEB887;
--brown: #A0522D;
--dark-brown: #8B4513;
}
/* ===== ХЛЕБНЫЕ КРОШКИ ===== */
.breadcrumb {
background: none;
padding: 0;
}
.breadcrumb-item a {
color: var(--brown);
text-decoration: none;
font-family: 'Verdana', sans-serif;
}
.breadcrumb-item a:hover {
text-decoration: underline;
}
.breadcrumb-item.active {
color: #6c757d;
font-family: 'Verdana', sans-serif;
}
.breadcrumb-item + .breadcrumb-item::before {
color: var(--light-brown);
}
/* ===== КАРТОЧКА ФОРМЫ ===== */
.form-card {
background: white;
border: 1px solid var(--light-brown);
border-radius: 16px;
box-shadow: 0 4px 20px rgba(160, 82, 45, 0.1);
overflow: hidden;
}
.form-card-header {
background: linear-gradient(135deg, var(--brown) 0%, var(--dark-brown) 100%);
padding: 20px 25px;
color: white;
}
.form-card-title {
font-size: 1.4rem;
font-weight: 600;
font-family: 'Verdana', sans-serif;
margin: 0;
}
.form-card-title i {
margin-right: 10px;
color: white;
}
.form-card-body {
padding: 25px;
}
/* ===== ИНФОРМАЦИЯ О ПОСТАВЩИКЕ ===== */
.supplier-info {
border: 1px solid var(--light-brown);
border-radius: 12px;
margin-bottom: 25px;
overflow: hidden;
}
.supplier-info-header {
background: var(--antique-white);
padding: 12px 20px;
font-weight: 600;
color: var(--brown);
font-family: 'Verdana', sans-serif;
border-bottom: 1px solid var(--light-brown);
}
.supplier-info-header i {
margin-right: 8px;
}
.supplier-info-body {
padding: 15px 20px;
background: white;
}
.info-item {
margin-bottom: 8px;
font-family: 'Verdana', sans-serif;
}
.info-label {
color: #6c757d;
font-weight: 500;
margin-right: 8px;
}
.info-value {
color: #2c3e50;
font-weight: 500;
}
/* ===== ЭЛЕМЕНТЫ ФОРМЫ ===== */
.form-group {
margin-bottom: 20px;
}
.form-label {
display: flex;
align-items: center;
gap: 6px;
color: var(--brown);
font-weight: 600;
font-size: 0.95rem;
margin-bottom: 6px;
font-family: 'Verdana', sans-serif;
}
.form-label i {
color: var(--brown);
font-size: 1rem;
}
.modern-input {
width: 100%;
height: 42px;
padding: 0 12px;
border: 2px solid var(--light-brown);
border-radius: 10px;
font-size: 0.95rem;
font-family: 'Verdana', sans-serif;
transition: all 0.2s ease;
background: white;
}
.modern-input:focus {
outline: none;
border-color: var(--brown);
box-shadow: 0 0 0 3px rgba(160, 82, 45, 0.1);
}
.modern-input:hover {
border-color: var(--brown);
}
.select-wrapper {
position: relative;
}
.modern-select {
width: 100%;
height: auto;
min-height: 42px;
padding: 8px 35px 8px 12px;
border: 2px solid var(--light-brown);
border-radius: 10px;
font-size: 0.95rem;
font-family: 'Verdana', sans-serif;
background: white;
cursor: pointer;
appearance: none;
transition: all 0.2s ease;
line-height: 1.4;
white-space: normal;
word-wrap: break-word;
}
.modern-select:focus {
outline: none;
border-color: var(--brown);
box-shadow: 0 0 0 3px rgba(160, 82, 45, 0.1);
}
.modern-select:hover {
border-color: var(--brown);
}
.select-arrow {
position: absolute;
right: 15px;
top: 50%;
transform: translateY(-50%);
color: var(--brown);
pointer-events: none;
}
.form-text {
font-size: 0.8rem;
color: #6c757d;
margin-top: 4px;
font-family: 'Verdana', sans-serif;
}
.form-text i {
color: var(--brown);
margin-right: 4px;
}
/* ===== ИНФОРМАЦИЯ О МАТЕРИАЛЕ ===== */
.material-info-block {
border: 1px solid var(--light-brown);
border-radius: 10px;
background: var(--antique-white);
padding: 12px 15px;
}
.material-info-row {
display: flex;
justify-content: space-between;
align-items: center;
flex-wrap: wrap;
gap: 10px;
}
.material-info-item {
display: flex;
align-items: center;
gap: 8px;
font-family: 'Verdana', sans-serif;
}
.material-info-item i {
color: var(--brown);
}
.material-info-label {
color: #6c757d;
font-weight: 500;
}
.material-info-value {
color: var(--brown);
font-weight: 600;
}
.material-info-item.text-end {
flex: 1;
justify-content: flex-end;
}
/* ===== БЛОК РАСЧЕТА ===== */
.calculation-block {
border: 1px solid var(--light-brown);
border-radius: 12px;
overflow: hidden;
}
.calculation-header {
background: var(--antique-white);
padding: 12px 20px;
font-weight: 600;
color: var(--brown);
font-family: 'Verdana', sans-serif;
border-bottom: 1px solid var(--light-brown);
}
.calculation-header i {
margin-right: 8px;
}
.calculation-body {
padding: 15px 20px;
background: white;
}
.calculation-row {
display: flex;
justify-content: space-between;
align-items: center;
padding: 8px 0;
border-bottom: 1px dashed var(--light-brown);
font-family: 'Verdana', sans-serif;
}
.calculation-row:last-of-type {
border-bottom: none;
}
.calculation-row.total-row {
margin-top: 5px;
padding-top: 12px;
border-top: 2px solid var(--light-brown);
border-bottom: none;
}
.calculation-label {
color: #6c757d;
font-weight: 500;
}
.calculation-value {
color: #2c3e50;
font-weight: 600;
}
.total-value {
color: var(--brown) !important;
font-size: 1.2rem;
font-weight: 700;
}
#discountPercentLabel {
color: var(--brown);
font-size: 0.9rem;
font-weight: normal;
}
/* ===== КНОПКИ ===== */
.form-actions {
display: flex;
justify-content: space-between;
margin-top: 25px;
padding-top: 20px;
border-top: 2px solid var(--light-brown);
}
.btn {
padding: 10px 25px;
border-radius: 10px;
font-size: 0.95rem;
font-weight: 500;
font-family: 'Verdana', sans-serif;
transition: all 0.2s ease;
border: none;
cursor: pointer;
display: inline-flex;
align-items: center;
gap: 8px;
text-decoration: none;
}
.btn-primary {
background: var(--brown);
color: white;
}
.btn-primary:hover {
background: var(--dark-brown);
transform: translateY(-2px);
box-shadow: 0 4px 12px rgba(160, 82, 45, 0.3);
}
.btn-primary:disabled {
background: #6c757d;
transform: none;
box-shadow: none;
cursor: not-allowed;
}
.btn-outline {
background: white;
border: 2px solid var(--light-brown);
color: var(--brown);
}
.btn-outline:hover {
background: var(--antique-white);
border-color: var(--brown);
transform: translateY(-2px);
}
/* ===== АДАПТИВНОСТЬ ===== */
@media (max-width: 768px) {
.form-card-body {
padding: 20px;
}
.form-actions {
flex-direction: column-reverse;
gap: 10px;
}
.form-actions .btn {
width: 100%;
justify-content: center;
}
.material-info-row {
flex-direction: column;
align-items: flex-start;
}
.material-info-item.text-end {
justify-content: flex-start;
width: 100%;
}
.info-item {
margin-bottom: 12px;
}
.calculation-row {
flex-direction: column;
align-items: flex-start;
gap: 5px;
}
.calculation-label, .calculation-value {
width: 100%;
}
}
</style>
<script>
document.addEventListener('DOMContentLoaded', function() {
console.log('Script loaded!');
const productSelect = document.getElementById('product_id');
const quantityInput = document.getElementById('quantity');
const displayQuantitySpan = document.getElementById('displayQuantity');
const displayPriceSpan = document.getElementById('displayPrice');
const baseAmountSpan = document.getElementById('baseAmount');
const transportAmountSpan = document.getElementById('transportAmount');
const totalAmountSpan = document.getElementById('totalAmount');
const discountPercentLabel = document.getElementById('discountPercentLabel');
const selectedMaterialSpan = document.getElementById('selectedMaterial');
const maxAvailableSpan = document.getElementById('maxAvailable');
const maxOrderSpan = document.getElementById('maxOrder');
const maxQuantityHint = document.getElementById('maxQuantityHint');
// Устанавливаем сегодняшнюю дату по умолчанию
const today = new Date().toISOString().split('T')[0];
document.getElementById('order_date').value = today;
// Обновление информации о товаре и материале
productSelect.addEventListener('change', function() {
console.log('Product changed');
const selectedOption = this.options[this.selectedIndex];
const price = selectedOption.getAttribute('data-price');
const stock = parseInt(selectedOption.getAttribute('data-stock')) || 0;
const productName = selectedOption.getAttribute('data-name');
console.log('Price:', price);
console.log('Stock:', stock);
if (price) {
displayPriceSpan.textContent = parseFloat(price).toFixed(2);
selectedMaterialSpan.textContent = productName;
maxAvailableSpan.textContent = stock;
maxOrderSpan.textContent = stock;
// Устанавливаем максимальное значение для поля ввода
if (stock > 0) {
quantityInput.max = stock;
quantityInput.value = 1;
maxQuantityHint.style.display = 'block';
} else {
quantityInput.max = 0;
quantityInput.value = 0;
maxQuantityHint.style.display = 'block';
}
calculateTotal();
} else {
selectedMaterialSpan.textContent = 'Не выбран';
maxAvailableSpan.textContent = '0';
maxOrderSpan.textContent = '0';
quantityInput.removeAttribute('max');
maxQuantityHint.style.display = 'none';
}
});
// Расчет общей суммы со скидкой
function calculateTotal() {
const quantity = parseInt(quantityInput.value) || 0;
const price = parseFloat(displayPriceSpan.textContent) || 0;
const baseAmount = quantity * price;
const transportAmount = baseAmount * 0.1; // 10% транспортные расходы
const amountWithTransport = baseAmount + transportAmount;
// Расчет скидки в зависимости от суммы
let discountPercent = 0;
let discountLabel = '';
if (amountWithTransport >= 500000) {
discountPercent = 20;
discountLabel = 'со скидкой 20%';
} else if (amountWithTransport >= 300000) {
discountPercent = 15;
discountLabel = 'со скидкой 15%';
} else if (amountWithTransport >= 150000) {
discountPercent = 10;
discountLabel = 'со скидкой 10%';
}
const discountAmount = amountWithTransport * discountPercent / 100;
const total = amountWithTransport - discountAmount;
displayQuantitySpan.textContent = quantity;
displayPriceSpan.textContent = price.toFixed(2);
baseAmountSpan.textContent = baseAmount.toFixed(2);
transportAmountSpan.textContent = transportAmount.toFixed(2);
totalAmountSpan.textContent = total.toFixed(2);
// Обновляем текст с информацией о скидке
if (discountPercent > 0) {
discountPercentLabel.textContent = discountLabel;
} else {
discountPercentLabel.textContent = '';
}
}
// Слушатели изменений
quantityInput.addEventListener('input', function() {
const max = parseInt(this.max);
const value = parseInt(this.value);
if (max && value > max) {
this.value = max;
alert(`Максимально доступное количество: ${max} ед.`);
}
if (value < 1) {
this.value = 1;
}
calculateTotal();
});
productSelect.addEventListener('change', calculateTotal);
// Проверка перед отправкой формы
document.getElementById('orderForm').addEventListener('submit', function(e) {
const productId = document.getElementById('product_id').value;
const quantity = parseInt(quantityInput.value) || 0;
const maxStock = parseInt(maxOrderSpan.textContent) || 0;
if (!productId) {
e.preventDefault();
alert('Пожалуйста, выберите материал');
return false;
}
if (quantity <= 0) {
e.preventDefault();
alert('Количество должно быть больше 0');
return false;
}
if (quantity > maxStock) {
e.preventDefault();
alert(`Невозможно создать заказ!\nНедостаточно материалов на складе.\nДоступно: ${maxStock} ед., запрошено: ${quantity} ед.`);
return false;
}
if (maxStock === 0) {
e.preventDefault();
alert(`Невозможно создать заказ!\nМатериал отсутствует на складе.`);
return false;
}
});
// Инициализация расчета
calculateTotal();
});
</script>
{% endblock %}