django-ledger 0.8.2__py3-none-any.whl → 0.8.2.2__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 +63 -110
- 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/chart_of_accounts.py +113 -180
- django_ledger/models/coa_default.py +1 -0
- django_ledger/models/customer.py +17 -26
- django_ledger/models/data_import.py +457 -153
- django_ledger/models/receipt.py +90 -121
- 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 +66 -36
- django_ledger/templates/django_ledger/data_import/tags/data_import_job_txs_table.html +10 -10
- django_ledger/urls/data_import.py +3 -0
- django_ledger/views/data_import.py +37 -21
- {django_ledger-0.8.2.dist-info → django_ledger-0.8.2.2.dist-info}/METADATA +1 -1
- {django_ledger-0.8.2.dist-info → django_ledger-0.8.2.2.dist-info}/RECORD +20 -19
- {django_ledger-0.8.2.dist-info → django_ledger-0.8.2.2.dist-info}/WHEEL +0 -0
- {django_ledger-0.8.2.dist-info → django_ledger-0.8.2.2.dist-info}/licenses/AUTHORS.md +0 -0
- {django_ledger-0.8.2.dist-info → django_ledger-0.8.2.2.dist-info}/licenses/LICENSE +0 -0
- {django_ledger-0.8.2.dist-info → django_ledger-0.8.2.2.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.2'
|
|
10
10
|
__license__ = 'GPLv3 License'
|
|
11
11
|
|
|
12
12
|
__author__ = 'Miguel Sanda'
|
|
@@ -11,7 +11,7 @@ from django.forms import (
|
|
|
11
11
|
)
|
|
12
12
|
from django.utils.translation import gettext_lazy as _
|
|
13
13
|
|
|
14
|
-
from django_ledger.io import GROUP_EXPENSES, GROUP_INCOME
|
|
14
|
+
from django_ledger.io import GROUP_EXPENSES, GROUP_INCOME, GROUP_TRANSFERS, GROUP_DEBT_PAYMENT
|
|
15
15
|
from django_ledger.models import (
|
|
16
16
|
StagedTransactionModel,
|
|
17
17
|
ImportJobModel,
|
|
@@ -24,9 +24,7 @@ class ImportJobModelCreateForm(ModelForm):
|
|
|
24
24
|
def __init__(self, entity_model: EntityModel, *args, **kwargs):
|
|
25
25
|
super().__init__(*args, **kwargs)
|
|
26
26
|
self.ENTITY_MODEL: EntityModel = entity_model
|
|
27
|
-
self.fields[
|
|
28
|
-
'bank_account_model'
|
|
29
|
-
].queryset = self.ENTITY_MODEL.bankaccountmodel_set.all().active()
|
|
27
|
+
self.fields['bank_account_model'].queryset = self.ENTITY_MODEL.bankaccountmodel_set.all().active()
|
|
30
28
|
|
|
31
29
|
ofx_file = forms.FileField(
|
|
32
30
|
label='Select File...',
|
|
@@ -54,9 +52,7 @@ class ImportJobModelCreateForm(ModelForm):
|
|
|
54
52
|
),
|
|
55
53
|
}
|
|
56
54
|
help_texts = {
|
|
57
|
-
'bank_account_model': _(
|
|
58
|
-
'Select the bank account to import transactions from.'
|
|
59
|
-
),
|
|
55
|
+
'bank_account_model': _('Select the bank account to import transactions from.'),
|
|
60
56
|
}
|
|
61
57
|
|
|
62
58
|
|
|
@@ -64,9 +60,7 @@ class ImportJobModelUpdateForm(ModelForm):
|
|
|
64
60
|
class Meta:
|
|
65
61
|
model = ImportJobModel
|
|
66
62
|
fields = ['description']
|
|
67
|
-
widgets = {
|
|
68
|
-
'description': TextInput(attrs={'class': DJANGO_LEDGER_FORM_INPUT_CLASSES})
|
|
69
|
-
}
|
|
63
|
+
widgets = {'description': TextInput(attrs={'class': DJANGO_LEDGER_FORM_INPUT_CLASSES})}
|
|
70
64
|
|
|
71
65
|
|
|
72
66
|
class StagedTransactionModelForm(ModelForm):
|
|
@@ -75,59 +69,49 @@ class StagedTransactionModelForm(ModelForm):
|
|
|
75
69
|
|
|
76
70
|
def __init__(self, base_formset_instance, *args, **kwargs):
|
|
77
71
|
super().__init__(*args, **kwargs)
|
|
78
|
-
self.BASE_FORMSET_INSTANCE: 'BaseStagedTransactionModelFormSet' =
|
|
79
|
-
base_formset_instance
|
|
80
|
-
)
|
|
72
|
+
self.BASE_FORMSET_INSTANCE: 'BaseStagedTransactionModelFormSet' = base_formset_instance
|
|
81
73
|
self.VENDOR_CHOICES = self.BASE_FORMSET_INSTANCE.VENDOR_CHOICES
|
|
82
74
|
self.VENDOR_MAP = self.BASE_FORMSET_INSTANCE.VENDOR_MAP
|
|
83
75
|
|
|
84
76
|
self.CUSTOMER_CHOICES = self.BASE_FORMSET_INSTANCE.CUSTOMER_CHOICES
|
|
85
77
|
self.CUSTOMER_MAP = self.BASE_FORMSET_INSTANCE.CUSTOMER_MAP
|
|
86
78
|
|
|
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
|
|
79
|
+
self.EXPENSE_ACCOUNT_CHOICES = self.BASE_FORMSET_INSTANCE.ACCOUNT_MODEL_EXPENSES_CHOICES
|
|
80
|
+
self.SALES_ACCOUNT_CHOICES = self.BASE_FORMSET_INSTANCE.ACCOUNT_MODEL_SALES_CHOICES
|
|
81
|
+
self.TRANSFER_ACCOUNT_CHOICES = self.BASE_FORMSET_INSTANCE.ACCOUNT_MODEL_TRANSFERS_CHOICES
|
|
82
|
+
self.CC_PAYMENT_ACCOUNT_CHOICES = self.BASE_FORMSET_INSTANCE.ACCOUNT_MODEL_TRANSFERS_CC_PAYMENT
|
|
95
83
|
|
|
96
84
|
staged_tx_model: StagedTransactionModel = getattr(self, 'instance', None)
|
|
97
85
|
|
|
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
|
|
86
|
+
self.fields['vendor_model'].choices = self.VENDOR_CHOICES
|
|
87
|
+
self.fields['customer_model'].choices = self.CUSTOMER_CHOICES
|
|
88
|
+
self.fields['account_model'].choices = self.BASE_FORMSET_INSTANCE.ACCOUNT_MODEL_CHOICES
|
|
116
89
|
|
|
117
90
|
# avoids multiple DB queries rendering the formset...
|
|
118
|
-
self.fields[
|
|
119
|
-
'unit_model'
|
|
120
|
-
].choices = self.BASE_FORMSET_INSTANCE.UNIT_MODEL_CHOICES
|
|
91
|
+
self.fields['unit_model'].choices = self.BASE_FORMSET_INSTANCE.UNIT_MODEL_CHOICES
|
|
121
92
|
|
|
122
93
|
if staged_tx_model:
|
|
123
|
-
if
|
|
94
|
+
if staged_tx_model.is_sales():
|
|
95
|
+
self.fields['account_model'].choices = self.SALES_ACCOUNT_CHOICES
|
|
96
|
+
|
|
97
|
+
if staged_tx_model.is_expense():
|
|
98
|
+
self.fields['account_model'].choices = self.EXPENSE_ACCOUNT_CHOICES
|
|
99
|
+
|
|
100
|
+
if staged_tx_model.is_transfer():
|
|
101
|
+
self.fields['account_model'].choices = self.TRANSFER_ACCOUNT_CHOICES
|
|
102
|
+
|
|
103
|
+
if staged_tx_model.is_debt_payment():
|
|
104
|
+
self.fields['account_model'].choices = self.CC_PAYMENT_ACCOUNT_CHOICES
|
|
105
|
+
|
|
106
|
+
if not staged_tx_model.can_have_amount_split():
|
|
124
107
|
self.fields['amount_split'].widget = HiddenInput()
|
|
125
108
|
self.fields['amount_split'].disabled = True
|
|
126
|
-
|
|
109
|
+
|
|
110
|
+
if not staged_tx_model.can_have_bundle_split():
|
|
127
111
|
self.fields['bundle_split'].widget = HiddenInput()
|
|
128
112
|
self.fields['bundle_split'].disabled = True
|
|
129
113
|
|
|
130
|
-
if staged_tx_model.
|
|
114
|
+
if not staged_tx_model.can_have_receipt():
|
|
131
115
|
self.fields['receipt_type'].widget = HiddenInput()
|
|
132
116
|
self.fields['receipt_type'].disabled = True
|
|
133
117
|
|
|
@@ -139,22 +123,15 @@ class StagedTransactionModelForm(ModelForm):
|
|
|
139
123
|
self.fields['unit_model'].widget = HiddenInput()
|
|
140
124
|
self.fields['unit_model'].disabled = True
|
|
141
125
|
|
|
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
|
|
126
|
+
if not staged_tx_model.can_have_vendor():
|
|
127
|
+
self.fields['vendor_model'].widget = HiddenInput()
|
|
128
|
+
self.fields['vendor_model'].disabled = True
|
|
156
129
|
|
|
157
|
-
if not staged_tx_model.
|
|
130
|
+
if not staged_tx_model.can_have_customer():
|
|
131
|
+
self.fields['customer_model'].widget = HiddenInput()
|
|
132
|
+
self.fields['customer_model'].disabled = True
|
|
133
|
+
|
|
134
|
+
if not staged_tx_model.can_import():
|
|
158
135
|
self.fields['tx_import'].widget = HiddenInput()
|
|
159
136
|
self.fields['tx_import'].disabled = True
|
|
160
137
|
|
|
@@ -162,6 +139,10 @@ class StagedTransactionModelForm(ModelForm):
|
|
|
162
139
|
self.fields['tx_split'].widget = HiddenInput()
|
|
163
140
|
self.fields['tx_split'].disabled = True
|
|
164
141
|
|
|
142
|
+
if not staged_tx_model.can_unbundle():
|
|
143
|
+
# self.fields['bundle_split'].widget = HiddenInput()
|
|
144
|
+
self.fields['bundle_split'].disabled = True
|
|
145
|
+
|
|
165
146
|
def clean_account_model(self):
|
|
166
147
|
staged_txs_model: StagedTransactionModel = self.instance
|
|
167
148
|
if staged_txs_model.has_children():
|
|
@@ -186,20 +167,6 @@ class StagedTransactionModelForm(ModelForm):
|
|
|
186
167
|
if self.cleaned_data['tx_import'] and self.cleaned_data['tx_split']:
|
|
187
168
|
raise ValidationError(message=_('Cannot import and split at the same time'))
|
|
188
169
|
|
|
189
|
-
staged_txs_model: StagedTransactionModel = self.instance
|
|
190
|
-
if all(
|
|
191
|
-
[
|
|
192
|
-
staged_txs_model.has_children(),
|
|
193
|
-
staged_txs_model.has_receipt(),
|
|
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
|
-
)
|
|
202
|
-
|
|
203
170
|
class Meta:
|
|
204
171
|
model = StagedTransactionModel
|
|
205
172
|
fields = [
|
|
@@ -223,18 +190,10 @@ class StagedTransactionModelForm(ModelForm):
|
|
|
223
190
|
'class': DJANGO_LEDGER_FORM_INPUT_CLASSES + ' is-small',
|
|
224
191
|
}
|
|
225
192
|
),
|
|
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
|
-
),
|
|
193
|
+
'amount_split': NumberInput(attrs={'class': DJANGO_LEDGER_FORM_INPUT_CLASSES + ' is-small'}),
|
|
194
|
+
'vendor_model': Select(attrs={'class': DJANGO_LEDGER_FORM_INPUT_CLASSES + ' is-small'}),
|
|
195
|
+
'customer_model': Select(attrs={'class': DJANGO_LEDGER_FORM_INPUT_CLASSES + ' is-small'}),
|
|
196
|
+
'receipt_type': Select(attrs={'class': DJANGO_LEDGER_FORM_INPUT_CLASSES + ' is-small'}),
|
|
238
197
|
}
|
|
239
198
|
|
|
240
199
|
|
|
@@ -250,29 +209,23 @@ class BaseStagedTransactionModelFormSet(BaseModelFormSet):
|
|
|
250
209
|
|
|
251
210
|
# validates that the job import model belongs to the entity model...
|
|
252
211
|
if import_job_model.entity_uuid != entity_model.uuid:
|
|
253
|
-
raise ValidationError(
|
|
254
|
-
message=_('Import job does not belong to this entity')
|
|
255
|
-
)
|
|
212
|
+
raise ValidationError(message=_('Import job does not belong to this entity'))
|
|
256
213
|
|
|
257
214
|
self.ENTITY_MODEL = entity_model
|
|
258
215
|
self.IMPORT_JOB_MODEL: ImportJobModel = import_job_model
|
|
259
216
|
|
|
260
217
|
self.queryset = (
|
|
261
|
-
|
|
218
|
+
StagedTransactionModel.objects.for_entity(entity_model=entity_model)
|
|
219
|
+
.for_import_job(import_job_model=import_job_model)
|
|
220
|
+
.is_pending()
|
|
262
221
|
)
|
|
263
222
|
|
|
264
|
-
self.MAPPED_ACCOUNT_MODEL =
|
|
265
|
-
self.IMPORT_JOB_MODEL.bank_account_model.account_model
|
|
266
|
-
)
|
|
223
|
+
self.MAPPED_ACCOUNT_MODEL = self.IMPORT_JOB_MODEL.bank_account_model.account_model
|
|
267
224
|
|
|
268
225
|
self.account_model_qs = (
|
|
269
|
-
entity_model.get_coa_accounts()
|
|
270
|
-
.available()
|
|
271
|
-
.exclude(uuid__exact=self.MAPPED_ACCOUNT_MODEL.uuid)
|
|
226
|
+
entity_model.get_coa_accounts().available().exclude(uuid__exact=self.MAPPED_ACCOUNT_MODEL.uuid)
|
|
272
227
|
)
|
|
273
|
-
self.ACCOUNT_MODEL_CHOICES = [(None, '----')] + [
|
|
274
|
-
(a.uuid, a) for a in self.account_model_qs
|
|
275
|
-
]
|
|
228
|
+
self.ACCOUNT_MODEL_CHOICES = [(None, '----')] + [(a.uuid, a) for a in self.account_model_qs]
|
|
276
229
|
self.ACCOUNT_MODEL_EXPENSES_CHOICES = [(None, '----')] + [
|
|
277
230
|
(a.uuid, a) for a in self.account_model_qs if a.role in GROUP_EXPENSES
|
|
278
231
|
]
|
|
@@ -280,22 +233,22 @@ class BaseStagedTransactionModelFormSet(BaseModelFormSet):
|
|
|
280
233
|
(a.uuid, a) for a in self.account_model_qs if a.role in GROUP_INCOME
|
|
281
234
|
]
|
|
282
235
|
|
|
283
|
-
self.
|
|
284
|
-
|
|
285
|
-
|
|
236
|
+
self.ACCOUNT_MODEL_TRANSFERS_CHOICES = [(None, '----')] + [
|
|
237
|
+
(a.uuid, a) for a in self.account_model_qs if a.role in GROUP_TRANSFERS
|
|
238
|
+
]
|
|
239
|
+
|
|
240
|
+
self.ACCOUNT_MODEL_TRANSFERS_CC_PAYMENT = [(None, '----')] + [
|
|
241
|
+
(a.uuid, a) for a in self.account_model_qs if a.role in GROUP_DEBT_PAYMENT
|
|
286
242
|
]
|
|
287
243
|
|
|
244
|
+
self.unit_model_qs = entity_model.entityunitmodel_set.all()
|
|
245
|
+
self.UNIT_MODEL_CHOICES = [(None, '----')] + [(u.uuid, u) for i, u in enumerate(self.unit_model_qs)]
|
|
246
|
+
|
|
288
247
|
self.VENDOR_MODEL_QS = entity_model.vendormodel_set.visible()
|
|
289
|
-
len(self.VENDOR_MODEL_QS)
|
|
290
248
|
self.CUSTOMER_MODEL_QS = entity_model.customermodel_set.visible()
|
|
291
|
-
len(self.CUSTOMER_MODEL_QS)
|
|
292
249
|
|
|
293
|
-
self.VENDOR_CHOICES = [(None, '-----')] + [
|
|
294
|
-
|
|
295
|
-
]
|
|
296
|
-
self.CUSTOMER_CHOICES = [(None, '-----')] + [
|
|
297
|
-
(str(c.uuid), c) for c in self.CUSTOMER_MODEL_QS
|
|
298
|
-
]
|
|
250
|
+
self.VENDOR_CHOICES = [(None, '-----')] + [(str(v.uuid), v) for v in self.VENDOR_MODEL_QS]
|
|
251
|
+
self.CUSTOMER_CHOICES = [(None, '-----')] + [(str(c.uuid), c) for c in self.CUSTOMER_MODEL_QS]
|
|
299
252
|
|
|
300
253
|
self.VENDOR_MAP = dict(self.VENDOR_CHOICES)
|
|
301
254
|
self.CUSTOMER_MAP = dict(self.CUSTOMER_CHOICES)
|