фикс
This commit is contained in:
@@ -126,8 +126,7 @@ export class PaymentWidget {
|
|||||||
method_id: null,
|
method_id: null,
|
||||||
method_code: null,
|
method_code: null,
|
||||||
method_name: null,
|
method_name: null,
|
||||||
amount: remaining,
|
amount: remaining
|
||||||
fixed: false
|
|
||||||
};
|
};
|
||||||
|
|
||||||
this.payments.push(row);
|
this.payments.push(row);
|
||||||
@@ -139,16 +138,43 @@ export class PaymentWidget {
|
|||||||
if (!container) return;
|
if (!container) return;
|
||||||
|
|
||||||
container.innerHTML = this.payments.map((payment, index) => {
|
container.innerHTML = this.payments.map((payment, index) => {
|
||||||
if (payment.fixed) {
|
// Редактируемая строка (без системы fixed/unfixed)
|
||||||
// Зафиксированная строка
|
const methodsOptions = this.paymentMethods.map(m =>
|
||||||
return `
|
`<option value="${m.id}"
|
||||||
<div class="payment-row mb-2 p-2 border rounded bg-light" data-index="${index}">
|
data-code="${m.code}"
|
||||||
<div class="d-flex justify-content-between align-items-center">
|
data-name="${m.name}"
|
||||||
<span>
|
${payment.method_id == m.id ? 'selected' : ''}>
|
||||||
<i class="bi bi-check-circle-fill text-success"></i>
|
${m.name}
|
||||||
<strong>${payment.method_name}:</strong>
|
${m.code === 'account_balance' && this.customer ?
|
||||||
<span class="text-success">${payment.amount.toFixed(2)} руб.</span>
|
` (${this.customer.wallet_balance.toFixed(2)} руб.)` : ''}
|
||||||
</span>
|
</option>`
|
||||||
|
).join('');
|
||||||
|
|
||||||
|
return `
|
||||||
|
<div class="payment-row mb-2 p-2 border rounded" data-index="${index}">
|
||||||
|
<div class="row g-2 align-items-center">
|
||||||
|
<div class="col-5">
|
||||||
|
<select class="form-select form-select-sm payment-method-select"
|
||||||
|
data-index="${index}">
|
||||||
|
<option value="">Выберите способ</option>
|
||||||
|
${methodsOptions}
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div class="col-5">
|
||||||
|
<div class="input-group input-group-sm">
|
||||||
|
<input type="number"
|
||||||
|
class="form-control payment-amount-input"
|
||||||
|
data-index="${index}"
|
||||||
|
value="${payment.amount.toFixed(2)}"
|
||||||
|
step="0.01"
|
||||||
|
min="0.01">
|
||||||
|
<span class="input-group-text">руб.</span>
|
||||||
|
</div>
|
||||||
|
<small class="text-danger payment-error"
|
||||||
|
data-index="${index}"
|
||||||
|
style="display: none;"></small>
|
||||||
|
</div>
|
||||||
|
<div class="col-2 text-end">
|
||||||
<button type="button"
|
<button type="button"
|
||||||
class="btn btn-sm btn-outline-danger remove-payment-row"
|
class="btn btn-sm btn-outline-danger remove-payment-row"
|
||||||
data-index="${index}">
|
data-index="${index}">
|
||||||
@@ -156,60 +182,8 @@ export class PaymentWidget {
|
|||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
`;
|
</div>
|
||||||
} else {
|
`;
|
||||||
// Редактируемая строка
|
|
||||||
const methodsOptions = this.paymentMethods.map(m =>
|
|
||||||
`<option value="${m.id}"
|
|
||||||
data-code="${m.code}"
|
|
||||||
data-name="${m.name}"
|
|
||||||
${payment.method_id == m.id ? 'selected' : ''}>
|
|
||||||
${m.name}
|
|
||||||
${m.code === 'account_balance' && this.customer ?
|
|
||||||
` (${this.customer.wallet_balance.toFixed(2)} руб.)` : ''}
|
|
||||||
</option>`
|
|
||||||
).join('');
|
|
||||||
|
|
||||||
return `
|
|
||||||
<div class="payment-row mb-2 p-2 border rounded" data-index="${index}">
|
|
||||||
<div class="row g-2 align-items-center">
|
|
||||||
<div class="col-5">
|
|
||||||
<select class="form-select form-select-sm payment-method-select"
|
|
||||||
data-index="${index}">
|
|
||||||
<option value="">Выберите способ</option>
|
|
||||||
${methodsOptions}
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
<div class="col-4">
|
|
||||||
<div class="input-group input-group-sm">
|
|
||||||
<input type="number"
|
|
||||||
class="form-control payment-amount-input"
|
|
||||||
data-index="${index}"
|
|
||||||
value="${payment.amount.toFixed(2)}"
|
|
||||||
step="0.01"
|
|
||||||
min="0.01">
|
|
||||||
<span class="input-group-text">руб.</span>
|
|
||||||
</div>
|
|
||||||
<small class="text-danger payment-error"
|
|
||||||
data-index="${index}"
|
|
||||||
style="display: none;"></small>
|
|
||||||
</div>
|
|
||||||
<div class="col-3 text-end">
|
|
||||||
<button type="button"
|
|
||||||
class="btn btn-sm btn-success confirm-payment-row me-1"
|
|
||||||
data-index="${index}">
|
|
||||||
<i class="bi bi-check-lg"></i>
|
|
||||||
</button>
|
|
||||||
<button type="button"
|
|
||||||
class="btn btn-sm btn-outline-danger remove-payment-row"
|
|
||||||
data-index="${index}">
|
|
||||||
<i class="bi bi-trash"></i>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
`;
|
|
||||||
}
|
|
||||||
}).join('');
|
}).join('');
|
||||||
|
|
||||||
// Обновляем подсказку об остатке
|
// Обновляем подсказку об остатке
|
||||||
@@ -254,14 +228,8 @@ export class PaymentWidget {
|
|||||||
input.addEventListener('input', (e) => {
|
input.addEventListener('input', (e) => {
|
||||||
const index = parseInt(e.target.dataset.index);
|
const index = parseInt(e.target.dataset.index);
|
||||||
this.payments[index].amount = parseFloat(e.target.value) || 0;
|
this.payments[index].amount = parseFloat(e.target.value) || 0;
|
||||||
});
|
// Real-time обновление остатка!
|
||||||
});
|
this.updateRemainingHint();
|
||||||
|
|
||||||
// Обработчик подтверждения (галочка)
|
|
||||||
document.querySelectorAll('.confirm-payment-row').forEach(btn => {
|
|
||||||
btn.addEventListener('click', (e) => {
|
|
||||||
const index = parseInt(e.target.closest('button').dataset.index);
|
|
||||||
this.confirmPaymentRow(index);
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -276,7 +244,10 @@ export class PaymentWidget {
|
|||||||
// Обработчик кнопки "Добавить еще"
|
// Обработчик кнопки "Добавить еще"
|
||||||
const addRowBtn = document.getElementById(`${this.containerId}-add-row-btn`);
|
const addRowBtn = document.getElementById(`${this.containerId}-add-row-btn`);
|
||||||
if (addRowBtn) {
|
if (addRowBtn) {
|
||||||
addRowBtn.addEventListener('click', () => this.addPaymentRow());
|
// Используем replaceWith для пересоздания элемента и удаления всех обработчиков
|
||||||
|
const newBtn = addRowBtn.cloneNode(true);
|
||||||
|
addRowBtn.replaceWith(newBtn);
|
||||||
|
newBtn.addEventListener('click', () => this.addPaymentRow());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -331,50 +302,6 @@ export class PaymentWidget {
|
|||||||
// СТАРЫЕ МЕТОДЫ addPayment(), removePayment() и updatePaymentsList() УДАЛЕНЫ
|
// СТАРЫЕ МЕТОДЫ addPayment(), removePayment() и updatePaymentsList() УДАЛЕНЫ
|
||||||
// Теперь используются новые методы для построчного UI
|
// Теперь используются новые методы для построчного UI
|
||||||
|
|
||||||
confirmPaymentRow(index) {
|
|
||||||
const payment = this.payments[index];
|
|
||||||
const errorEl = document.querySelector(`.payment-error[data-index="${index}"]`);
|
|
||||||
|
|
||||||
// Валидация
|
|
||||||
if (!payment.method_id) {
|
|
||||||
errorEl.textContent = 'Выберите способ оплаты';
|
|
||||||
errorEl.style.display = 'block';
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!payment.amount || payment.amount <= 0) {
|
|
||||||
errorEl.textContent = 'Введите сумму больше 0';
|
|
||||||
errorEl.style.display = 'block';
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Проверка превышения остатка
|
|
||||||
const totalOtherPayments = this.payments
|
|
||||||
.filter((p, i) => i !== index && p.fixed)
|
|
||||||
.reduce((sum, p) => sum + p.amount, 0);
|
|
||||||
|
|
||||||
if (totalOtherPayments + payment.amount > this.order.amount_due) {
|
|
||||||
const maxAmount = this.order.amount_due - totalOtherPayments;
|
|
||||||
errorEl.textContent = `Максимум: ${maxAmount.toFixed(2)} руб.`;
|
|
||||||
errorEl.style.display = 'block';
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Проверка кошелька
|
|
||||||
if (payment.method_code === 'account_balance' && this.customer) {
|
|
||||||
if (payment.amount > this.customer.wallet_balance) {
|
|
||||||
errorEl.textContent = `Недостаточно средств (${this.customer.wallet_balance.toFixed(2)} руб.)`;
|
|
||||||
errorEl.style.display = 'block';
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Все ОК - фиксируем
|
|
||||||
errorEl.style.display = 'none';
|
|
||||||
payment.fixed = true;
|
|
||||||
this.renderPaymentRows();
|
|
||||||
}
|
|
||||||
|
|
||||||
removePaymentRow(index) {
|
removePaymentRow(index) {
|
||||||
this.payments.splice(index, 1);
|
this.payments.splice(index, 1);
|
||||||
|
|
||||||
@@ -394,21 +321,27 @@ export class PaymentWidget {
|
|||||||
const totalPaid = this.getTotalPayments();
|
const totalPaid = this.getTotalPayments();
|
||||||
const remaining = this.order.amount_due - totalPaid;
|
const remaining = this.order.amount_due - totalPaid;
|
||||||
|
|
||||||
if (remaining <= 0) {
|
if (totalPaid > this.order.amount_due) {
|
||||||
|
// Превышение суммы
|
||||||
|
const excess = totalPaid - this.order.amount_due;
|
||||||
|
hintEl.innerHTML = '<strong class="text-danger">⚠ Превышение: +' +
|
||||||
|
excess.toFixed(2) + ' руб.</strong>';
|
||||||
|
if (addRowBtn) addRowBtn.style.display = 'none';
|
||||||
|
} else if (remaining <= 0) {
|
||||||
|
// Точная оплата
|
||||||
hintEl.innerHTML = '<strong class="text-success">✅ Оплачено полностью: ' +
|
hintEl.innerHTML = '<strong class="text-success">✅ Оплачено полностью: ' +
|
||||||
this.order.amount_due.toFixed(2) + ' руб.</strong>';
|
this.order.amount_due.toFixed(2) + ' руб.</strong>';
|
||||||
// СКРЫТЬ кнопку добавления
|
|
||||||
if (addRowBtn) addRowBtn.style.display = 'none';
|
if (addRowBtn) addRowBtn.style.display = 'none';
|
||||||
} else {
|
} else {
|
||||||
|
// Осталось оплатить
|
||||||
hintEl.textContent = 'Осталось оплатить: ' + remaining.toFixed(2) + ' руб.';
|
hintEl.textContent = 'Осталось оплатить: ' + remaining.toFixed(2) + ' руб.';
|
||||||
// ПОКАЗАТЬ кнопку добавления
|
|
||||||
if (addRowBtn) addRowBtn.style.display = 'block';
|
if (addRowBtn) addRowBtn.style.display = 'block';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
getTotalPayments() {
|
getTotalPayments() {
|
||||||
return this.payments
|
return this.payments
|
||||||
.filter(p => p.fixed) // Считаем только зафиксированные!
|
.filter(p => p.method_id) // Считать только если выбран способ оплаты
|
||||||
.reduce((sum, p) => sum + p.amount, 0);
|
.reduce((sum, p) => sum + p.amount, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -439,21 +372,31 @@ export class PaymentWidget {
|
|||||||
|
|
||||||
} else {
|
} else {
|
||||||
// Смешанная оплата
|
// Смешанная оплата
|
||||||
const fixedPayments = this.payments.filter(p => p.fixed);
|
const validPayments = this.payments.filter(p => p.method_id && p.amount > 0);
|
||||||
|
|
||||||
if (fixedPayments.length === 0) {
|
if (validPayments.length === 0) {
|
||||||
throw new Error('Добавьте хотя бы один платеж');
|
throw new Error('Добавьте хотя бы один платеж');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Проверить незавершенные платежи
|
||||||
|
const incompletePayments = this.payments.filter(p =>
|
||||||
|
(p.method_id && !p.amount) || (!p.method_id && p.amount)
|
||||||
|
);
|
||||||
|
|
||||||
|
if (incompletePayments.length > 0) {
|
||||||
|
throw new Error('Заполните все поля или удалите незавершенные строки');
|
||||||
|
}
|
||||||
|
|
||||||
const total = this.getTotalPayments();
|
const total = this.getTotalPayments();
|
||||||
|
|
||||||
if (total > this.order.amount_due) {
|
if (total > this.order.amount_due) {
|
||||||
throw new Error(`Сумма платежей превышает остаток к оплате (${this.order.amount_due.toFixed(2)} руб.)`);
|
const excess = total - this.order.amount_due;
|
||||||
|
throw new Error(`Сумма платежей превышает остаток к оплате на ${excess.toFixed(2)} руб.`);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Проверка кошелька
|
// Проверка кошелька
|
||||||
if (this.customer) {
|
if (this.customer) {
|
||||||
const walletPayments = fixedPayments.filter(p => p.method_code === 'account_balance');
|
const walletPayments = validPayments.filter(p => p.method_code === 'account_balance');
|
||||||
const walletTotal = walletPayments.reduce((sum, p) => sum + p.amount, 0);
|
const walletTotal = walletPayments.reduce((sum, p) => sum + p.amount, 0);
|
||||||
|
|
||||||
if (walletTotal > this.customer.wallet_balance) {
|
if (walletTotal > this.customer.wallet_balance) {
|
||||||
@@ -481,9 +424,9 @@ export class PaymentWidget {
|
|||||||
notes: ''
|
notes: ''
|
||||||
}];
|
}];
|
||||||
} else {
|
} else {
|
||||||
// Смешанная оплата - берем только зафиксированные
|
// Смешанная оплата - берем только заполненные
|
||||||
paymentsData = this.payments
|
paymentsData = this.payments
|
||||||
.filter(p => p.fixed)
|
.filter(p => p.method_id && p.amount > 0)
|
||||||
.map(p => ({
|
.map(p => ({
|
||||||
payment_method: p.method_code,
|
payment_method: p.method_code,
|
||||||
amount: p.amount,
|
amount: p.amount,
|
||||||
|
|||||||
Reference in New Issue
Block a user