django-ledger 0.8.2.1__py3-none-any.whl → 0.8.2.3__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of django-ledger might be problematic. Click here for more details.
- django_ledger/__init__.py +1 -1
- django_ledger/forms/data_import.py +104 -111
- django_ledger/io/roles.py +238 -303
- django_ledger/migrations/0027_alter_accountmodel_role_alter_receiptmodel_amount_and_more.py +159 -0
- django_ledger/models/__init__.py +1 -0
- django_ledger/models/chart_of_accounts.py +32 -90
- django_ledger/models/coa_default.py +1 -0
- django_ledger/models/customer.py +17 -26
- django_ledger/models/data_import.py +562 -182
- django_ledger/models/receipt.py +92 -123
- django_ledger/templates/django_ledger/data_import/data_import_job_txs.html +6 -0
- django_ledger/templates/django_ledger/data_import/tags/data_import_job_txs_imported.html +68 -36
- django_ledger/templates/django_ledger/data_import/tags/data_import_job_txs_table.html +8 -10
- django_ledger/templates/django_ledger/receipt/receipt_detail.html +4 -2
- django_ledger/urls/data_import.py +3 -0
- django_ledger/views/data_import.py +47 -27
- {django_ledger-0.8.2.1.dist-info → django_ledger-0.8.2.3.dist-info}/METADATA +1 -1
- {django_ledger-0.8.2.1.dist-info → django_ledger-0.8.2.3.dist-info}/RECORD +22 -21
- {django_ledger-0.8.2.1.dist-info → django_ledger-0.8.2.3.dist-info}/WHEEL +0 -0
- {django_ledger-0.8.2.1.dist-info → django_ledger-0.8.2.3.dist-info}/licenses/AUTHORS.md +0 -0
- {django_ledger-0.8.2.1.dist-info → django_ledger-0.8.2.3.dist-info}/licenses/LICENSE +0 -0
- {django_ledger-0.8.2.1.dist-info → django_ledger-0.8.2.3.dist-info}/top_level.txt +0 -0
django_ledger/__init__.py
CHANGED
|
@@ -6,7 +6,7 @@ Copyright© EDMA Group Inc licensed under the GPLv3 Agreement.
|
|
|
6
6
|
default_app_config = 'django_ledger.apps.DjangoLedgerConfig'
|
|
7
7
|
|
|
8
8
|
"""Django Ledger"""
|
|
9
|
-
__version__ = '0.8.2.
|
|
9
|
+
__version__ = '0.8.2.3'
|
|
10
10
|
__license__ = 'GPLv3 License'
|
|
11
11
|
|
|
12
12
|
__author__ = 'Miguel Sanda'
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
from itertools import groupby
|
|
2
|
+
|
|
1
3
|
from django import forms
|
|
2
4
|
from django.forms import (
|
|
3
5
|
ModelForm,
|
|
@@ -11,7 +13,7 @@ from django.forms import (
|
|
|
11
13
|
)
|
|
12
14
|
from django.utils.translation import gettext_lazy as _
|
|
13
15
|
|
|
14
|
-
from django_ledger.io import GROUP_EXPENSES, GROUP_INCOME
|
|
16
|
+
from django_ledger.io import GROUP_EXPENSES, GROUP_INCOME, GROUP_TRANSFERS, GROUP_DEBT_PAYMENT
|
|
15
17
|
from django_ledger.models import (
|
|
16
18
|
StagedTransactionModel,
|
|
17
19
|
ImportJobModel,
|
|
@@ -24,9 +26,7 @@ class ImportJobModelCreateForm(ModelForm):
|
|
|
24
26
|
def __init__(self, entity_model: EntityModel, *args, **kwargs):
|
|
25
27
|
super().__init__(*args, **kwargs)
|
|
26
28
|
self.ENTITY_MODEL: EntityModel = entity_model
|
|
27
|
-
self.fields[
|
|
28
|
-
'bank_account_model'
|
|
29
|
-
].queryset = self.ENTITY_MODEL.bankaccountmodel_set.all().active()
|
|
29
|
+
self.fields['bank_account_model'].queryset = self.ENTITY_MODEL.bankaccountmodel_set.all().active()
|
|
30
30
|
|
|
31
31
|
ofx_file = forms.FileField(
|
|
32
32
|
label='Select File...',
|
|
@@ -54,9 +54,7 @@ class ImportJobModelCreateForm(ModelForm):
|
|
|
54
54
|
),
|
|
55
55
|
}
|
|
56
56
|
help_texts = {
|
|
57
|
-
'bank_account_model': _(
|
|
58
|
-
'Select the bank account to import transactions from.'
|
|
59
|
-
),
|
|
57
|
+
'bank_account_model': _('Select the bank account to import transactions from.'),
|
|
60
58
|
}
|
|
61
59
|
|
|
62
60
|
|
|
@@ -64,9 +62,7 @@ class ImportJobModelUpdateForm(ModelForm):
|
|
|
64
62
|
class Meta:
|
|
65
63
|
model = ImportJobModel
|
|
66
64
|
fields = ['description']
|
|
67
|
-
widgets = {
|
|
68
|
-
'description': TextInput(attrs={'class': DJANGO_LEDGER_FORM_INPUT_CLASSES})
|
|
69
|
-
}
|
|
65
|
+
widgets = {'description': TextInput(attrs={'class': DJANGO_LEDGER_FORM_INPUT_CLASSES})}
|
|
70
66
|
|
|
71
67
|
|
|
72
68
|
class StagedTransactionModelForm(ModelForm):
|
|
@@ -75,59 +71,49 @@ class StagedTransactionModelForm(ModelForm):
|
|
|
75
71
|
|
|
76
72
|
def __init__(self, base_formset_instance, *args, **kwargs):
|
|
77
73
|
super().__init__(*args, **kwargs)
|
|
78
|
-
self.BASE_FORMSET_INSTANCE: 'BaseStagedTransactionModelFormSet' =
|
|
79
|
-
base_formset_instance
|
|
80
|
-
)
|
|
74
|
+
self.BASE_FORMSET_INSTANCE: 'BaseStagedTransactionModelFormSet' = base_formset_instance
|
|
81
75
|
self.VENDOR_CHOICES = self.BASE_FORMSET_INSTANCE.VENDOR_CHOICES
|
|
82
76
|
self.VENDOR_MAP = self.BASE_FORMSET_INSTANCE.VENDOR_MAP
|
|
83
77
|
|
|
84
78
|
self.CUSTOMER_CHOICES = self.BASE_FORMSET_INSTANCE.CUSTOMER_CHOICES
|
|
85
79
|
self.CUSTOMER_MAP = self.BASE_FORMSET_INSTANCE.CUSTOMER_MAP
|
|
86
80
|
|
|
87
|
-
self.EXPENSE_ACCOUNT_CHOICES =
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
self.
|
|
91
|
-
self.BASE_FORMSET_INSTANCE.ACCOUNT_MODEL_SALES_CHOICES
|
|
92
|
-
)
|
|
93
|
-
self.SHOW_VENDOR_FIELD: bool = False
|
|
94
|
-
self.SHOW_CUSTOMER_FIELD: bool = False
|
|
81
|
+
self.EXPENSE_ACCOUNT_CHOICES = self.BASE_FORMSET_INSTANCE.ACCOUNT_MODEL_EXPENSES_CHOICES
|
|
82
|
+
self.SALES_ACCOUNT_CHOICES = self.BASE_FORMSET_INSTANCE.ACCOUNT_MODEL_SALES_CHOICES
|
|
83
|
+
self.TRANSFER_ACCOUNT_CHOICES = self.BASE_FORMSET_INSTANCE.ACCOUNT_MODEL_TRANSFERS_CHOICES
|
|
84
|
+
self.CC_PAYMENT_ACCOUNT_CHOICES = self.BASE_FORMSET_INSTANCE.ACCOUNT_MODEL_TRANSFERS_CC_PAYMENT
|
|
95
85
|
|
|
96
86
|
staged_tx_model: StagedTransactionModel = getattr(self, 'instance', None)
|
|
97
87
|
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
self.fields['vendor_model'].choices = self.VENDOR_CHOICES
|
|
102
|
-
self.fields['account_model'].choices = self.EXPENSE_ACCOUNT_CHOICES
|
|
103
|
-
self.SHOW_VENDOR_FIELD = True
|
|
104
|
-
elif staged_tx_model.is_sales():
|
|
105
|
-
self.fields['vendor_model'].widget = forms.HiddenInput()
|
|
106
|
-
self.fields['customer_model'].choices = self.CUSTOMER_CHOICES
|
|
107
|
-
self.fields['account_model'].choices = self.SALES_ACCOUNT_CHOICES
|
|
108
|
-
self.SHOW_CUSTOMER_FIELD = True
|
|
109
|
-
else:
|
|
110
|
-
self.fields['customer_model'].widget = forms.HiddenInput()
|
|
111
|
-
self.fields['vendor_model'].widget = forms.HiddenInput()
|
|
112
|
-
# avoids multiple DB queries rendering the formset...
|
|
113
|
-
self.fields[
|
|
114
|
-
'account_model'
|
|
115
|
-
].choices = self.BASE_FORMSET_INSTANCE.ACCOUNT_MODEL_CHOICES
|
|
88
|
+
self.fields['vendor_model'].choices = self.VENDOR_CHOICES
|
|
89
|
+
self.fields['customer_model'].choices = self.CUSTOMER_CHOICES
|
|
90
|
+
self.fields['account_model'].choices = self.BASE_FORMSET_INSTANCE.ACCOUNT_MODEL_CHOICES
|
|
116
91
|
|
|
117
92
|
# avoids multiple DB queries rendering the formset...
|
|
118
|
-
self.fields[
|
|
119
|
-
'unit_model'
|
|
120
|
-
].choices = self.BASE_FORMSET_INSTANCE.UNIT_MODEL_CHOICES
|
|
93
|
+
self.fields['unit_model'].choices = self.BASE_FORMSET_INSTANCE.UNIT_MODEL_CHOICES
|
|
121
94
|
|
|
122
95
|
if staged_tx_model:
|
|
123
|
-
if
|
|
96
|
+
if staged_tx_model.is_sales():
|
|
97
|
+
self.fields['account_model'].choices = self.SALES_ACCOUNT_CHOICES
|
|
98
|
+
|
|
99
|
+
if staged_tx_model.is_expense():
|
|
100
|
+
self.fields['account_model'].choices = self.EXPENSE_ACCOUNT_CHOICES
|
|
101
|
+
|
|
102
|
+
if staged_tx_model.is_transfer():
|
|
103
|
+
self.fields['account_model'].choices = self.TRANSFER_ACCOUNT_CHOICES
|
|
104
|
+
|
|
105
|
+
if staged_tx_model.is_debt_payment():
|
|
106
|
+
self.fields['account_model'].choices = self.CC_PAYMENT_ACCOUNT_CHOICES
|
|
107
|
+
|
|
108
|
+
if not staged_tx_model.can_have_amount_split():
|
|
124
109
|
self.fields['amount_split'].widget = HiddenInput()
|
|
125
110
|
self.fields['amount_split'].disabled = True
|
|
126
|
-
|
|
111
|
+
|
|
112
|
+
if not staged_tx_model.can_have_bundle_split():
|
|
127
113
|
self.fields['bundle_split'].widget = HiddenInput()
|
|
128
114
|
self.fields['bundle_split'].disabled = True
|
|
129
115
|
|
|
130
|
-
if staged_tx_model.
|
|
116
|
+
if not staged_tx_model.can_have_receipt():
|
|
131
117
|
self.fields['receipt_type'].widget = HiddenInput()
|
|
132
118
|
self.fields['receipt_type'].disabled = True
|
|
133
119
|
|
|
@@ -139,22 +125,15 @@ class StagedTransactionModelForm(ModelForm):
|
|
|
139
125
|
self.fields['unit_model'].widget = HiddenInput()
|
|
140
126
|
self.fields['unit_model'].disabled = True
|
|
141
127
|
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
'receipt_type',
|
|
146
|
-
'vendor_model',
|
|
147
|
-
'customer_model',
|
|
148
|
-
'bundle_split',
|
|
149
|
-
]:
|
|
150
|
-
self.fields[f].widget = HiddenInput()
|
|
151
|
-
self.fields[f].disabled = True
|
|
152
|
-
|
|
153
|
-
if staged_tx_model.is_single():
|
|
154
|
-
self.fields['bundle_split'].widget = HiddenInput()
|
|
155
|
-
self.fields['bundle_split'].disabled = True
|
|
128
|
+
if not staged_tx_model.can_have_vendor():
|
|
129
|
+
self.fields['vendor_model'].widget = HiddenInput()
|
|
130
|
+
self.fields['vendor_model'].disabled = True
|
|
156
131
|
|
|
157
|
-
if not staged_tx_model.
|
|
132
|
+
if not staged_tx_model.can_have_customer():
|
|
133
|
+
self.fields['customer_model'].widget = HiddenInput()
|
|
134
|
+
self.fields['customer_model'].disabled = True
|
|
135
|
+
|
|
136
|
+
if not staged_tx_model.can_import():
|
|
158
137
|
self.fields['tx_import'].widget = HiddenInput()
|
|
159
138
|
self.fields['tx_import'].disabled = True
|
|
160
139
|
|
|
@@ -162,6 +141,10 @@ class StagedTransactionModelForm(ModelForm):
|
|
|
162
141
|
self.fields['tx_split'].widget = HiddenInput()
|
|
163
142
|
self.fields['tx_split'].disabled = True
|
|
164
143
|
|
|
144
|
+
if not staged_tx_model.can_unbundle():
|
|
145
|
+
self.fields['bundle_split'].widget = HiddenInput()
|
|
146
|
+
self.fields['bundle_split'].disabled = True
|
|
147
|
+
|
|
165
148
|
def clean_account_model(self):
|
|
166
149
|
staged_txs_model: StagedTransactionModel = self.instance
|
|
167
150
|
if staged_txs_model.has_children():
|
|
@@ -179,26 +162,41 @@ class StagedTransactionModelForm(ModelForm):
|
|
|
179
162
|
def clean_tx_import(self):
|
|
180
163
|
staged_txs_model: StagedTransactionModel = self.instance
|
|
181
164
|
if staged_txs_model.is_children():
|
|
182
|
-
|
|
165
|
+
parent_form = self.BASE_FORMSET_INSTANCE.FORMS_BY_ID[staged_txs_model.parent_id]
|
|
166
|
+
if all(
|
|
167
|
+
[
|
|
168
|
+
any(
|
|
169
|
+
[
|
|
170
|
+
staged_txs_model.is_child_not_bundled_has_receipt(),
|
|
171
|
+
staged_txs_model.is_child_not_bundled_no_receipt(),
|
|
172
|
+
]
|
|
173
|
+
),
|
|
174
|
+
parent_form.cleaned_data['tx_import'] is True,
|
|
175
|
+
]
|
|
176
|
+
):
|
|
177
|
+
return True
|
|
183
178
|
return self.cleaned_data['tx_import']
|
|
184
179
|
|
|
180
|
+
def clean_bundle_split(self):
|
|
181
|
+
staged_txs_model: StagedTransactionModel = self.instance
|
|
182
|
+
if staged_txs_model.is_single():
|
|
183
|
+
return True
|
|
184
|
+
if staged_txs_model.is_children():
|
|
185
|
+
parent_form = self.BASE_FORMSET_INSTANCE.FORMS_BY_ID[staged_txs_model.parent.uuid]
|
|
186
|
+
return parent_form.cleaned_data['bundle_split']
|
|
187
|
+
return self.cleaned_data['bundle_split']
|
|
188
|
+
|
|
185
189
|
def clean(self):
|
|
186
190
|
if self.cleaned_data['tx_import'] and self.cleaned_data['tx_split']:
|
|
187
191
|
raise ValidationError(message=_('Cannot import and split at the same time'))
|
|
188
192
|
|
|
193
|
+
def has_changed(self):
|
|
194
|
+
has_changed = super().has_changed()
|
|
189
195
|
staged_txs_model: StagedTransactionModel = self.instance
|
|
190
|
-
if
|
|
191
|
-
[
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
not staged_txs_model.bundle_split,
|
|
195
|
-
]
|
|
196
|
-
):
|
|
197
|
-
raise ValidationError(
|
|
198
|
-
message=_(
|
|
199
|
-
'Receipt transactions cannot be split into multiple receipts.'
|
|
200
|
-
)
|
|
201
|
-
)
|
|
196
|
+
if not has_changed and staged_txs_model.is_children():
|
|
197
|
+
parent_form = self.BASE_FORMSET_INSTANCE.FORMS_BY_ID[staged_txs_model.parent.uuid]
|
|
198
|
+
return parent_form.has_changed()
|
|
199
|
+
return has_changed
|
|
202
200
|
|
|
203
201
|
class Meta:
|
|
204
202
|
model = StagedTransactionModel
|
|
@@ -223,18 +221,10 @@ class StagedTransactionModelForm(ModelForm):
|
|
|
223
221
|
'class': DJANGO_LEDGER_FORM_INPUT_CLASSES + ' is-small',
|
|
224
222
|
}
|
|
225
223
|
),
|
|
226
|
-
'amount_split': NumberInput(
|
|
227
|
-
|
|
228
|
-
),
|
|
229
|
-
'
|
|
230
|
-
attrs={'class': DJANGO_LEDGER_FORM_INPUT_CLASSES + ' is-small'}
|
|
231
|
-
),
|
|
232
|
-
'customer_model': Select(
|
|
233
|
-
attrs={'class': DJANGO_LEDGER_FORM_INPUT_CLASSES + ' is-small'}
|
|
234
|
-
),
|
|
235
|
-
'receipt_type': Select(
|
|
236
|
-
attrs={'class': DJANGO_LEDGER_FORM_INPUT_CLASSES + ' is-small'}
|
|
237
|
-
),
|
|
224
|
+
'amount_split': NumberInput(attrs={'class': DJANGO_LEDGER_FORM_INPUT_CLASSES + ' is-small'}),
|
|
225
|
+
'vendor_model': Select(attrs={'class': DJANGO_LEDGER_FORM_INPUT_CLASSES + ' is-small'}),
|
|
226
|
+
'customer_model': Select(attrs={'class': DJANGO_LEDGER_FORM_INPUT_CLASSES + ' is-small'}),
|
|
227
|
+
'receipt_type': Select(attrs={'class': DJANGO_LEDGER_FORM_INPUT_CLASSES + ' is-small'}),
|
|
238
228
|
}
|
|
239
229
|
|
|
240
230
|
|
|
@@ -250,29 +240,23 @@ class BaseStagedTransactionModelFormSet(BaseModelFormSet):
|
|
|
250
240
|
|
|
251
241
|
# validates that the job import model belongs to the entity model...
|
|
252
242
|
if import_job_model.entity_uuid != entity_model.uuid:
|
|
253
|
-
raise ValidationError(
|
|
254
|
-
message=_('Import job does not belong to this entity')
|
|
255
|
-
)
|
|
243
|
+
raise ValidationError(message=_('Import job does not belong to this entity'))
|
|
256
244
|
|
|
257
245
|
self.ENTITY_MODEL = entity_model
|
|
258
246
|
self.IMPORT_JOB_MODEL: ImportJobModel = import_job_model
|
|
259
247
|
|
|
260
248
|
self.queryset = (
|
|
261
|
-
|
|
249
|
+
StagedTransactionModel.objects.for_entity(entity_model=entity_model)
|
|
250
|
+
.for_import_job(import_job_model=import_job_model)
|
|
251
|
+
.is_pending()
|
|
262
252
|
)
|
|
263
253
|
|
|
264
|
-
self.MAPPED_ACCOUNT_MODEL =
|
|
265
|
-
self.IMPORT_JOB_MODEL.bank_account_model.account_model
|
|
266
|
-
)
|
|
254
|
+
self.MAPPED_ACCOUNT_MODEL = self.IMPORT_JOB_MODEL.bank_account_model.account_model
|
|
267
255
|
|
|
268
256
|
self.account_model_qs = (
|
|
269
|
-
entity_model.get_coa_accounts()
|
|
270
|
-
.available()
|
|
271
|
-
.exclude(uuid__exact=self.MAPPED_ACCOUNT_MODEL.uuid)
|
|
257
|
+
entity_model.get_coa_accounts().available().exclude(uuid__exact=self.MAPPED_ACCOUNT_MODEL.uuid)
|
|
272
258
|
)
|
|
273
|
-
self.ACCOUNT_MODEL_CHOICES = [(None, '----')] + [
|
|
274
|
-
(a.uuid, a) for a in self.account_model_qs
|
|
275
|
-
]
|
|
259
|
+
self.ACCOUNT_MODEL_CHOICES = [(None, '----')] + [(a.uuid, a) for a in self.account_model_qs]
|
|
276
260
|
self.ACCOUNT_MODEL_EXPENSES_CHOICES = [(None, '----')] + [
|
|
277
261
|
(a.uuid, a) for a in self.account_model_qs if a.role in GROUP_EXPENSES
|
|
278
262
|
]
|
|
@@ -280,26 +264,35 @@ class BaseStagedTransactionModelFormSet(BaseModelFormSet):
|
|
|
280
264
|
(a.uuid, a) for a in self.account_model_qs if a.role in GROUP_INCOME
|
|
281
265
|
]
|
|
282
266
|
|
|
283
|
-
self.
|
|
284
|
-
|
|
285
|
-
(u.uuid, u) for i, u in enumerate(self.unit_model_qs)
|
|
267
|
+
self.ACCOUNT_MODEL_TRANSFERS_CHOICES = [(None, '----')] + [
|
|
268
|
+
(a.uuid, a) for a in self.account_model_qs if a.role in GROUP_TRANSFERS
|
|
286
269
|
]
|
|
287
270
|
|
|
288
|
-
self.
|
|
289
|
-
|
|
290
|
-
self.CUSTOMER_MODEL_QS = entity_model.customermodel_set.visible()
|
|
291
|
-
len(self.CUSTOMER_MODEL_QS)
|
|
292
|
-
|
|
293
|
-
self.VENDOR_CHOICES = [(None, '-----')] + [
|
|
294
|
-
(str(v.uuid), v) for v in self.VENDOR_MODEL_QS
|
|
295
|
-
]
|
|
296
|
-
self.CUSTOMER_CHOICES = [(None, '-----')] + [
|
|
297
|
-
(str(c.uuid), c) for c in self.CUSTOMER_MODEL_QS
|
|
271
|
+
self.ACCOUNT_MODEL_TRANSFERS_CC_PAYMENT = [(None, '----')] + [
|
|
272
|
+
(a.uuid, a) for a in self.account_model_qs if a.role in GROUP_DEBT_PAYMENT
|
|
298
273
|
]
|
|
299
274
|
|
|
275
|
+
self.unit_model_qs = entity_model.entityunitmodel_set.all()
|
|
276
|
+
self.UNIT_MODEL_CHOICES = [(None, '----')] + [(u.uuid, u) for i, u in enumerate(self.unit_model_qs)]
|
|
277
|
+
|
|
278
|
+
self.VENDOR_MODEL_QS = entity_model.vendormodel_set.visible().order_by('vendor_name')
|
|
279
|
+
self.CUSTOMER_MODEL_QS = entity_model.customermodel_set.visible().order_by('customer_name')
|
|
280
|
+
|
|
281
|
+
self.VENDOR_CHOICES = [(None, '-----')] + [(str(v.uuid), v) for v in self.VENDOR_MODEL_QS]
|
|
282
|
+
self.CUSTOMER_CHOICES = [(None, '-----')] + [(str(c.uuid), c) for c in self.CUSTOMER_MODEL_QS]
|
|
283
|
+
|
|
300
284
|
self.VENDOR_MAP = dict(self.VENDOR_CHOICES)
|
|
301
285
|
self.CUSTOMER_MAP = dict(self.CUSTOMER_CHOICES)
|
|
302
286
|
|
|
287
|
+
self.FORMS_BY_ID = {
|
|
288
|
+
f.instance.uuid: f for f in self.forms if getattr(f, 'instance', None) and getattr(f.instance, 'uuid', None)
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
form_children = [(f.instance.parent_id, f.instance.uuid) for f in self.forms if f.instance.parent_id]
|
|
292
|
+
form_children.sort(key=lambda f: f[0])
|
|
293
|
+
|
|
294
|
+
self.FORM_CHILDREN = {g: list(j[1] for j in p) for g, p in groupby(form_children, key=lambda i: i[0])}
|
|
295
|
+
|
|
303
296
|
def get_form_kwargs(self, index):
|
|
304
297
|
return {
|
|
305
298
|
'base_formset_instance': self,
|