django-ledger 0.7.4__py3-none-any.whl → 0.7.5__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.

Files changed (31) hide show
  1. django_ledger/__init__.py +1 -1
  2. django_ledger/contrib/django_ledger_graphene/bank_account/schema.py +1 -1
  3. django_ledger/forms/bank_account.py +16 -12
  4. django_ledger/forms/data_import.py +70 -33
  5. django_ledger/io/io_core.py +945 -127
  6. django_ledger/io/io_generator.py +7 -3
  7. django_ledger/io/ofx.py +37 -16
  8. django_ledger/migrations/0020_remove_bankaccountmodel_django_ledg_cash_ac_59a8af_idx_and_more.py +44 -0
  9. django_ledger/migrations/0021_alter_bankaccountmodel_account_model_and_more.py +33 -0
  10. django_ledger/models/bank_account.py +14 -11
  11. django_ledger/models/customer.py +3 -13
  12. django_ledger/models/data_import.py +690 -35
  13. django_ledger/models/entity.py +39 -24
  14. django_ledger/models/journal_entry.py +18 -8
  15. django_ledger/models/mixins.py +17 -3
  16. django_ledger/models/vendor.py +2 -2
  17. django_ledger/settings.py +18 -22
  18. django_ledger/templates/django_ledger/bank_account/tags/bank_accounts_table.html +2 -2
  19. django_ledger/templates/django_ledger/data_import/data_import_job_txs.html +1 -1
  20. django_ledger/templates/django_ledger/data_import/import_job_create.html +11 -2
  21. django_ledger/templates/django_ledger/data_import/tags/data_import_job_txs_imported.html +1 -1
  22. django_ledger/templates/django_ledger/data_import/tags/data_import_job_txs_table.html +5 -2
  23. django_ledger/templatetags/django_ledger.py +12 -12
  24. django_ledger/views/bank_account.py +1 -1
  25. django_ledger/views/data_import.py +60 -134
  26. {django_ledger-0.7.4.dist-info → django_ledger-0.7.5.dist-info}/METADATA +17 -17
  27. {django_ledger-0.7.4.dist-info → django_ledger-0.7.5.dist-info}/RECORD +31 -29
  28. {django_ledger-0.7.4.dist-info → django_ledger-0.7.5.dist-info}/WHEEL +1 -1
  29. {django_ledger-0.7.4.dist-info → django_ledger-0.7.5.dist-info}/top_level.txt +1 -0
  30. {django_ledger-0.7.4.dist-info → django_ledger-0.7.5.dist-info}/AUTHORS.md +0 -0
  31. {django_ledger-0.7.4.dist-info → django_ledger-0.7.5.dist-info}/LICENSE +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.7.4'
9
+ __version__ = '0.7.5'
10
10
  __license__ = 'GPLv3 License'
11
11
 
12
12
  __author__ = 'Miguel Sanda'
@@ -28,7 +28,7 @@ class Bank_account_Query(graphene.ObjectType):
28
28
  return BankAccountModel.objects.for_entity(
29
29
  entity_slug=slug_name,
30
30
  user_model=info.context.user
31
- ).select_related('cash_account')
31
+ ).select_related('account_model')
32
32
  else:
33
33
  return BankAccountModel.objects.none()
34
34
 
@@ -1,7 +1,7 @@
1
1
  from django.forms import ModelForm, TextInput, Select, ValidationError
2
2
  from django.utils.translation import gettext_lazy as _
3
3
 
4
- from django_ledger.io.roles import ASSET_CA_CASH
4
+ from django_ledger.io.roles import ASSET_CA_CASH, LIABILITY_CL_ACC_PAYABLE, LIABILITY_LTL_MORTGAGE_PAYABLE
5
5
  from django_ledger.models import BankAccountModel
6
6
  from django_ledger.models.accounts import AccountModel
7
7
  from django_ledger.settings import DJANGO_LEDGER_FORM_INPUT_CLASSES
@@ -19,20 +19,24 @@ class BankAccountCreateForm(ModelForm):
19
19
  user_model=self.USER_MODEL,
20
20
  entity_model=self.ENTITY_SLUG
21
21
  ).available().filter(
22
- role__exact=ASSET_CA_CASH)
23
- self.fields['cash_account'].queryset = account_qs
22
+ role__in=[
23
+ ASSET_CA_CASH,
24
+ LIABILITY_CL_ACC_PAYABLE,
25
+ LIABILITY_LTL_MORTGAGE_PAYABLE
26
+ ])
27
+ self.fields['account_model'].queryset = account_qs
24
28
 
25
29
  def clean(self):
26
- cash_account = self.cleaned_data['cash_account']
30
+ account_model = self.cleaned_data['account_model']
27
31
  routing_number = self.cleaned_data['routing_number']
28
32
  account_number = self.cleaned_data['account_number']
29
33
 
30
- if not cash_account:
34
+ if not account_model:
31
35
  raise ValidationError('Must select a bank account.')
32
36
 
33
37
  # catching unique database constraint...
34
38
  if BankAccountModel.objects.filter(
35
- cash_account=cash_account,
39
+ account_model=account_model,
36
40
  routing_number__exact=routing_number,
37
41
  account_number__exact=account_number
38
42
  ).exists():
@@ -47,7 +51,7 @@ class BankAccountCreateForm(ModelForm):
47
51
  'routing_number',
48
52
  'aba_number',
49
53
  'swift_number',
50
- 'cash_account',
54
+ 'account_model',
51
55
  'active'
52
56
  ]
53
57
  widgets = {
@@ -74,7 +78,7 @@ class BankAccountCreateForm(ModelForm):
74
78
  'account_type': Select(attrs={
75
79
  'class': DJANGO_LEDGER_FORM_INPUT_CLASSES
76
80
  }),
77
- 'cash_account': Select(attrs={
81
+ 'account_model': Select(attrs={
78
82
  'class': DJANGO_LEDGER_FORM_INPUT_CLASSES
79
83
  })
80
84
  }
@@ -82,7 +86,7 @@ class BankAccountCreateForm(ModelForm):
82
86
  'name': _('Account Name'),
83
87
  'account_number': _('Account Number'),
84
88
  'account_type': _('Account Type'),
85
- 'cash_account': _('Cash Account'),
89
+ 'account_model': _('CoA Account'),
86
90
  'aba_number': _('ABA Number'),
87
91
  'routing_number': _('Routing Number'),
88
92
  'active': _('Make Active'),
@@ -95,7 +99,7 @@ class BankAccountUpdateForm(BankAccountCreateForm):
95
99
  fields = [
96
100
  'name',
97
101
  'account_type',
98
- 'cash_account',
102
+ 'account_model',
99
103
  'active'
100
104
  ]
101
105
  widgets = {
@@ -106,13 +110,13 @@ class BankAccountUpdateForm(BankAccountCreateForm):
106
110
  'account_type': Select(attrs={
107
111
  'class': DJANGO_LEDGER_FORM_INPUT_CLASSES
108
112
  }),
109
- 'cash_account': Select(attrs={
113
+ 'account_model': Select(attrs={
110
114
  'class': DJANGO_LEDGER_FORM_INPUT_CLASSES
111
115
  })
112
116
  }
113
117
 
114
118
  def clean(self):
115
- cash_account = self.cleaned_data['cash_account']
119
+ cash_account = self.cleaned_data['account_model']
116
120
 
117
121
  if not cash_account:
118
122
  raise ValidationError('Must select a bank account.')
@@ -1,16 +1,29 @@
1
1
  from django import forms
2
- from django.forms import (ModelForm, BaseModelFormSet, modelformset_factory, Select, NumberInput, HiddenInput,
3
- TextInput,
4
- ValidationError)
2
+ from django.forms import (
3
+ ModelForm, BaseModelFormSet, modelformset_factory,
4
+ Select, NumberInput, HiddenInput,
5
+ TextInput, ValidationError
6
+ )
5
7
  from django.utils.translation import gettext_lazy as _
6
8
 
7
- from django_ledger.models import StagedTransactionModel, AccountModel, EntityUnitModel, ImportJobModel
9
+ from django_ledger.models import (
10
+ StagedTransactionModel,
11
+ ImportJobModel,
12
+ EntityModel
13
+ )
8
14
  from django_ledger.settings import DJANGO_LEDGER_FORM_INPUT_CLASSES
9
15
 
10
16
 
11
17
  class ImportJobModelCreateForm(ModelForm):
18
+
19
+ def __init__(self, entity_model: EntityModel, *args, **kwargs):
20
+ super().__init__(*args, **kwargs)
21
+ self.ENTITY_MODEL: EntityModel = entity_model
22
+ self.fields['bank_account_model'].queryset = self.ENTITY_MODEL.bankaccountmodel_set.all().active()
23
+
12
24
  ofx_file = forms.FileField(
13
25
  label='Select File...',
26
+ required=True,
14
27
  widget=forms.FileInput(
15
28
  attrs={
16
29
  'class': 'file-input',
@@ -21,13 +34,21 @@ class ImportJobModelCreateForm(ModelForm):
21
34
  class Meta:
22
35
  model = ImportJobModel
23
36
  fields = [
24
- 'description'
37
+ 'bank_account_model',
38
+ 'description',
25
39
  ]
26
40
  widgets = {
27
41
  'description': TextInput(attrs={
28
42
  'class': DJANGO_LEDGER_FORM_INPUT_CLASSES + ' is-large',
29
43
  'placeholder': _('What\'s this import about?...')
30
- })
44
+ }),
45
+ 'bank_account_model': Select(
46
+ attrs={
47
+ 'class': DJANGO_LEDGER_FORM_INPUT_CLASSES,
48
+ }),
49
+ }
50
+ help_texts = {
51
+ 'bank_account_model': _('Select the bank account to import transactions from.'),
31
52
  }
32
53
 
33
54
 
@@ -48,11 +69,20 @@ class StagedTransactionModelForm(ModelForm):
48
69
  tx_import = forms.BooleanField(initial=False, required=False)
49
70
  tx_split = forms.BooleanField(initial=False, required=False)
50
71
 
51
- def __init__(self, *args, **kwargs):
72
+ def __init__(self, base_formset_instance, *args, **kwargs):
52
73
  super().__init__(*args, **kwargs)
74
+ self.BASE_FORMSET_INSTANCE = base_formset_instance
75
+
76
+ # for IDE typing hints...
53
77
  instance: StagedTransactionModel = getattr(self, 'instance', None)
54
- if instance:
55
78
 
79
+ # avoids multiple DB queries rendering the formset...
80
+ self.fields['unit_model'].choices = self.BASE_FORMSET_INSTANCE.UNIT_MODEL_CHOICES
81
+
82
+ # avoids multiple DB queries rendering the formset...
83
+ self.fields['account_model'].choices = self.BASE_FORMSET_INSTANCE.ACCOUNT_MODEL_CHOICES
84
+
85
+ if instance:
56
86
  if not instance.is_children():
57
87
  self.fields['amount_split'].widget = HiddenInput()
58
88
  self.fields['amount_split'].disabled = True
@@ -100,7 +130,7 @@ class StagedTransactionModelForm(ModelForm):
100
130
  raise ValidationError(message=_('Cannot import and split at the same time'))
101
131
 
102
132
  class Meta:
103
- model = StagedTransactionModel.objects.get_queryset().model
133
+ model = StagedTransactionModel
104
134
  fields = [
105
135
  'tx_import',
106
136
  'bundle_split',
@@ -123,32 +153,39 @@ class StagedTransactionModelForm(ModelForm):
123
153
 
124
154
  class BaseStagedTransactionModelFormSet(BaseModelFormSet):
125
155
 
126
- def __init__(self, *args, entity_slug, user_model, exclude_account=None, **kwargs):
156
+ def __init__(self, *args,
157
+ entity_model: EntityModel,
158
+ import_job_model: ImportJobModel,
159
+ **kwargs):
127
160
  super().__init__(*args, **kwargs)
128
- self.ENTITY_SLUG = entity_slug
129
- self.USER_MODEL = user_model
130
- self.IMPORT_DISABLED = not exclude_account
131
- self.CASH_ACCOUNT = exclude_account
132
-
133
- account_model_qs = AccountModel.objects.for_entity(
134
- user_model=self.USER_MODEL,
135
- entity_model=self.ENTITY_SLUG
136
- ).available().order_by('role', 'name')
137
-
138
- unit_model_qs = EntityUnitModel.objects.for_entity(
139
- user_model=self.USER_MODEL,
140
- entity_slug=self.ENTITY_SLUG
141
- )
142
161
 
143
- if exclude_account:
144
- account_model_qs = account_model_qs.exclude(uuid__exact=exclude_account.uuid)
162
+ # validates that the job import model belongs to the entity model...
163
+ if import_job_model.entity_uuid != entity_model.uuid:
164
+ raise ValidationError(message=_('Import job does not belong to this entity'))
145
165
 
146
- for form in self.forms:
147
- form.fields['account_model'].queryset = account_model_qs
148
- form.fields['account_model'].widget.attrs['disabled'] = self.IMPORT_DISABLED
149
- form.fields['unit_model'].queryset = unit_model_qs
166
+ self.ENTITY_MODEL = entity_model
167
+ self.IMPORT_JOB_MODEL: ImportJobModel = import_job_model
168
+ self.MAPPED_ACCOUNT_MODEL = self.IMPORT_JOB_MODEL.bank_account_model.account_model
150
169
 
151
- # def get_queryset(self):
170
+ self.account_model_qs = entity_model.get_coa_accounts().available().exclude(
171
+ uuid__exact=self.MAPPED_ACCOUNT_MODEL.uuid
172
+ )
173
+ self.ACCOUNT_MODEL_CHOICES = [
174
+ (a.uuid, a) if i > 0 else (None, '----') for i, a in
175
+ enumerate(self.account_model_qs)
176
+ ]
177
+
178
+ self.unit_model_qs = entity_model.entityunitmodel_set.all()
179
+ self.UNIT_MODEL_CHOICES = [
180
+ (u.uuid, u) if i > 0 else (None, '----') for i, u in
181
+ enumerate(self.unit_model_qs)
182
+ ]
183
+ self.queryset = self.IMPORT_JOB_MODEL.stagedtransactionmodel_set.all().is_pending()
184
+
185
+ def get_form_kwargs(self, index):
186
+ return {
187
+ 'base_formset_instance': self,
188
+ }
152
189
 
153
190
 
154
191
  StagedTransactionModelFormSet = modelformset_factory(
@@ -156,6 +193,6 @@ StagedTransactionModelFormSet = modelformset_factory(
156
193
  form=StagedTransactionModelForm,
157
194
  formset=BaseStagedTransactionModelFormSet,
158
195
  can_delete=True,
159
- can_delete_extra=0,
160
196
  can_order=False,
161
- extra=0)
197
+ extra=0
198
+ )