fix: Payment formset not saving - fixed template replacement and has_changed()
Проблема: Платежи не сохранялись при создании/редактировании заказа. Причины: 1. JavaScript функция addNewPayment() использовала неправильный метод замены __prefix__. При clone().innerHTML.replace() атрибуты name оставались с буквальным "__prefix__" вместо номера формы. 2. PaymentForm не переопределял has_changed(), из-за чего Django formset считал заполненные формы "пустыми" и не сохранял их. Исправления: - order_form.html: Переписана addNewPayment() - теперь клонирует template.content, конвертирует в HTML строку, делает replace, и только потом парсит обратно в DOM элемент - forms.py: Добавлен метод PaymentForm.has_changed() который правильно определяет что форма заполнена если указан payment_method ИЛИ amount - views.py: Добавлена отладочная информация для диагностики проблем с formset (TODO: удалить после тестирования) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -510,6 +510,22 @@ class PaymentForm(forms.ModelForm):
|
|||||||
# Делаем notes опциональным
|
# Делаем notes опциональным
|
||||||
self.fields['notes'].required = False
|
self.fields['notes'].required = False
|
||||||
|
|
||||||
|
def has_changed(self):
|
||||||
|
"""
|
||||||
|
Переопределяем has_changed() чтобы formset не считал форму пустой.
|
||||||
|
Форма считается заполненной если указан payment_method ИЛИ amount.
|
||||||
|
"""
|
||||||
|
# Если есть ID - значит форма существует в БД, проверяем изменения стандартно
|
||||||
|
if self.instance and self.instance.pk:
|
||||||
|
return super().has_changed()
|
||||||
|
|
||||||
|
# Для новых форм: считаем заполненной если есть payment_method или amount
|
||||||
|
payment_method = self.cleaned_data.get('payment_method') if hasattr(self, 'cleaned_data') else self.data.get(self.add_prefix('payment_method'))
|
||||||
|
amount = self.cleaned_data.get('amount') if hasattr(self, 'cleaned_data') else self.data.get(self.add_prefix('amount'))
|
||||||
|
|
||||||
|
# Форма изменена если заполнено хотя бы одно из ключевых полей
|
||||||
|
return bool(payment_method or amount)
|
||||||
|
|
||||||
def clean(self):
|
def clean(self):
|
||||||
"""Валидация платежа, особенно для оплаты из кошелька"""
|
"""Валидация платежа, особенно для оплаты из кошелька"""
|
||||||
cleaned = super().clean()
|
cleaned = super().clean()
|
||||||
|
|||||||
@@ -1745,11 +1745,17 @@ document.addEventListener('DOMContentLoaded', function() {
|
|||||||
|
|
||||||
// Функция для добавления нового платежа
|
// Функция для добавления нового платежа
|
||||||
function addNewPayment() {
|
function addNewPayment() {
|
||||||
const newPaymentHtml = paymentFormTemplate.content.cloneNode(true);
|
// ВАЖНО: Получаем HTML из template.content и заменяем __prefix__
|
||||||
const newPaymentDiv = newPaymentHtml.querySelector('.payment-form');
|
const tempContainer = document.createElement('div');
|
||||||
|
tempContainer.appendChild(paymentFormTemplate.content.cloneNode(true));
|
||||||
|
const templateHtml = tempContainer.innerHTML;
|
||||||
|
const replacedHtml = templateHtml.replace(/__prefix__/g, paymentFormCount);
|
||||||
|
|
||||||
|
// Создаем элемент из обработанного HTML
|
||||||
|
const tempDiv = document.createElement('div');
|
||||||
|
tempDiv.innerHTML = replacedHtml;
|
||||||
|
const newPaymentDiv = tempDiv.firstElementChild;
|
||||||
|
|
||||||
// Заменяем __prefix__ на актуальный индекс
|
|
||||||
newPaymentDiv.innerHTML = newPaymentDiv.innerHTML.replace(/__prefix__/g, paymentFormCount);
|
|
||||||
newPaymentDiv.setAttribute('data-form-index', paymentFormCount);
|
newPaymentDiv.setAttribute('data-form-index', paymentFormCount);
|
||||||
|
|
||||||
// Добавляем в контейнер
|
// Добавляем в контейнер
|
||||||
|
|||||||
Reference in New Issue
Block a user