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.

@@ -39,13 +39,13 @@ roles to create comprehensive financial statements.
39
39
  This structure ensures a clear and organized approach to financial management within Django Ledger, facilitating
40
40
  accurate record-keeping and reporting.
41
41
  """
42
+
42
43
  import warnings
43
44
  from random import choices
44
45
  from string import ascii_lowercase, digits
45
46
  from typing import Optional, Union, Dict
46
47
  from uuid import uuid4, UUID
47
48
 
48
- from django.apps import apps
49
49
  from django.contrib.auth import get_user_model
50
50
  from django.core.exceptions import ValidationError
51
51
  from django.db import models
@@ -56,9 +56,16 @@ from django.urls import reverse
56
56
  from django.utils.translation import gettext_lazy as _
57
57
 
58
58
  from django_ledger.io import (
59
- ROOT_COA, ROOT_GROUP_LEVEL_2, ROOT_GROUP_META, ROOT_ASSETS,
60
- ROOT_LIABILITIES, ROOT_CAPITAL,
61
- ROOT_INCOME, ROOT_COGS, ROOT_EXPENSES, ROOT_GROUP
59
+ ROOT_COA,
60
+ ROOT_GROUP_LEVEL_2,
61
+ ROOT_GROUP_META,
62
+ ROOT_ASSETS,
63
+ ROOT_LIABILITIES,
64
+ ROOT_CAPITAL,
65
+ ROOT_INCOME,
66
+ ROOT_COGS,
67
+ ROOT_EXPENSES,
68
+ ROOT_GROUP,
62
69
  )
63
70
  from django_ledger.models import lazy_loader
64
71
  from django_ledger.models.accounts import AccountModel, AccountModelQuerySet
@@ -70,15 +77,12 @@ UserModel = get_user_model()
70
77
 
71
78
  SLUG_SUFFIX = ascii_lowercase + digits
72
79
 
73
- app_config = apps.get_app_config('django_ledger')
74
-
75
80
 
76
81
  class ChartOfAccountsModelValidationError(ValidationError):
77
82
  pass
78
83
 
79
84
 
80
85
  class ChartOfAccountModelQuerySet(QuerySet):
81
-
82
86
  def active(self) -> 'ChartOfAccountModelQuerySet':
83
87
  """
84
88
  QuerySet method to retrieve active items.
@@ -112,12 +116,7 @@ class ChartOfAccountModelQuerySet(QuerySet):
112
116
  if user_model.is_superuser:
113
117
  return self
114
118
 
115
- return self.filter(
116
- (
117
- Q(entity__admin=user_model) |
118
- Q(entity__managers__in=[user_model])
119
- )
120
- )
119
+ return self.filter((Q(entity__admin=user_model) | Q(entity__managers__in=[user_model])))
121
120
 
122
121
 
123
122
  class ChartOfAccountModelManager(Manager):
@@ -128,49 +127,52 @@ class ChartOfAccountModelManager(Manager):
128
127
 
129
128
  def get_queryset(self) -> ChartOfAccountModelQuerySet:
130
129
  qs = ChartOfAccountModelQuerySet(self.model, using=self._db)
131
- return qs.annotate(
132
- _entity_slug=F('entity__slug'),
133
- accountmodel_total__count=Count(
134
- 'accountmodel',
135
- # excludes coa root accounts...
136
- filter=Q(accountmodel__depth__gt=2)
137
- ),
138
- accountmodel_locked__count=Count(
139
- 'accountmodel',
140
- # excludes coa root accounts...
141
- filter=Q(accountmodel__depth__gt=2) & Q(accountmodel__locked=True)
142
- ),
143
- accountmodel_active__count=Count(
144
- 'accountmodel',
145
- # excludes coa root accounts...
146
- filter=Q(accountmodel__depth__gt=2) & Q(accountmodel__active=True)
147
- ),
148
- # Root-group presence and uniqueness checks:
149
- accountmodel_rootgroup__count=Count(
150
- 'accountmodel',
151
- filter=Q(accountmodel__role__in=ROOT_GROUP)
152
- ),
153
- accountmodel_rootgroup_roles__distinct_count=Count(
154
- 'accountmodel__role',
155
- filter=Q(accountmodel__role__in=ROOT_GROUP_META),
156
- distinct=True
157
- ),
158
- ).annotate(
159
- configured=models.Case(
160
- models.When(
161
- Q(accountmodel_rootgroup__count__gte=1) &
162
- Q(accountmodel_rootgroup__count=F('accountmodel_rootgroup_roles__distinct_count')),
163
- then=Value(True, output_field=BooleanField()),
130
+ return (
131
+ qs.annotate(
132
+ _entity_slug=F('entity__slug'),
133
+ accountmodel_total__count=Count(
134
+ 'accountmodel',
135
+ # excludes coa root accounts...
136
+ filter=Q(accountmodel__depth__gt=2),
137
+ ),
138
+ accountmodel_locked__count=Count(
139
+ 'accountmodel',
140
+ # excludes coa root accounts...
141
+ filter=Q(accountmodel__depth__gt=2) & Q(accountmodel__locked=True),
142
+ ),
143
+ accountmodel_active__count=Count(
144
+ 'accountmodel',
145
+ # excludes coa root accounts...
146
+ filter=Q(accountmodel__depth__gt=2) & Q(accountmodel__active=True),
147
+ ),
148
+ # Root-group presence and uniqueness checks:
149
+ accountmodel_rootgroup__count=Count('accountmodel', filter=Q(accountmodel__role__in=ROOT_GROUP)),
150
+ accountmodel_rootgroup_roles__distinct_count=Count(
151
+ 'accountmodel__role',
152
+ filter=Q(accountmodel__role__in=ROOT_GROUP_META),
153
+ distinct=True,
164
154
  ),
165
- default=Value(False, output_field=BooleanField()),
166
- output_field=BooleanField()
167
155
  )
168
- ).select_related('entity')
156
+ .annotate(
157
+ configured=models.Case(
158
+ models.When(
159
+ Q(accountmodel_rootgroup__count__gte=1)
160
+ & Q(accountmodel_rootgroup__count=F('accountmodel_rootgroup_roles__distinct_count')),
161
+ then=Value(True, output_field=BooleanField()),
162
+ ),
163
+ default=Value(False, output_field=BooleanField()),
164
+ output_field=BooleanField(),
165
+ )
166
+ )
167
+ .select_related('entity')
168
+ )
169
169
 
170
170
  @deprecated_entity_slug_behavior
171
- def for_entity(self,
172
- entity_model: Union['EntityModel | str | UUID'] = None,
173
- **kwargs) -> ChartOfAccountModelQuerySet:
171
+ def for_entity(
172
+ self,
173
+ entity_model: 'Union[EntityModel | str | UUID]' = None, # noqa: F821
174
+ **kwargs, # noqa: F821
175
+ ) -> ChartOfAccountModelQuerySet:
174
176
  """
175
177
  Fetches a QuerySet of ChartOfAccountsModel associated with a specific EntityModel & UserModel.
176
178
  May pass an instance of EntityModel or a String representing the EntityModel slug.
@@ -195,7 +197,7 @@ class ChartOfAccountModelManager(Manager):
195
197
  'user_model parameter is deprecated and will be removed in a future release. '
196
198
  'Use for_user(user_model).for_entity(entity_model) instead to keep current behavior.',
197
199
  DeprecationWarning,
198
- stacklevel=2
200
+ stacklevel=2,
199
201
  )
200
202
  if DJANGO_LEDGER_USE_DEPRECATED_BEHAVIOR:
201
203
  qs = qs.for_user(kwargs['user_model'])
@@ -232,9 +234,7 @@ class ChartOfAccountModelAbstract(SlugNameMixIn, CreateUpdateMixIn):
232
234
  """
233
235
 
234
236
  uuid = models.UUIDField(default=uuid4, editable=False, primary_key=True)
235
- entity = models.ForeignKey('django_ledger.EntityModel',
236
- verbose_name=_('Entity'),
237
- on_delete=models.CASCADE)
237
+ entity = models.ForeignKey('django_ledger.EntityModel', verbose_name=_('Entity'), on_delete=models.CASCADE)
238
238
  active = models.BooleanField(default=True, verbose_name=_('Is Active'))
239
239
  description = models.TextField(verbose_name=_('CoA Description'), null=True, blank=True)
240
240
  objects = ChartOfAccountModelManager.from_queryset(queryset_class=ChartOfAccountModelQuerySet)()
@@ -244,9 +244,7 @@ class ChartOfAccountModelAbstract(SlugNameMixIn, CreateUpdateMixIn):
244
244
  ordering = ['-created']
245
245
  verbose_name = _('Chart of Account')
246
246
  verbose_name_plural = _('Chart of Accounts')
247
- indexes = [
248
- models.Index(fields=['entity'])
249
- ]
247
+ indexes = [models.Index(fields=['entity'])]
250
248
 
251
249
  def __str__(self):
252
250
  if self.name is not None:
@@ -265,7 +263,7 @@ class ChartOfAccountModelAbstract(SlugNameMixIn, CreateUpdateMixIn):
265
263
  return getattr(self, 'configured')
266
264
  except AttributeError:
267
265
  pass
268
- account_qs = self.accountmodel_set.filter(role__in=[ROOT_GROUP])
266
+ account_qs = self.accountmodel_set.filter(role__in=ROOT_GROUP)
269
267
  self.configured = len(account_qs) == len(ROOT_GROUP)
270
268
  return self.configured
271
269
 
@@ -305,7 +303,7 @@ class ChartOfAccountModelAbstract(SlugNameMixIn, CreateUpdateMixIn):
305
303
  role_default=True,
306
304
  active=False,
307
305
  locked=True,
308
- balance_type=role_meta['balance_type']
306
+ balance_type=role_meta['balance_type'],
309
307
  )
310
308
  AccountModel.add_root(instance=root_account)
311
309
 
@@ -326,8 +324,9 @@ class ChartOfAccountModelAbstract(SlugNameMixIn, CreateUpdateMixIn):
326
324
  role_default=True,
327
325
  active=False,
328
326
  locked=True,
329
- balance_type=role_meta['balance_type']
330
- ))
327
+ balance_type=role_meta['balance_type'],
328
+ )
329
+ )
331
330
  self.configured = True
332
331
 
333
332
  def get_coa_root_accounts_qs(self) -> AccountModelQuerySet:
@@ -350,10 +349,12 @@ class ChartOfAccountModelAbstract(SlugNameMixIn, CreateUpdateMixIn):
350
349
  qs = self.get_coa_root_accounts_qs()
351
350
  return qs.get(role__exact=ROOT_COA)
352
351
 
353
- def get_account_root_node(self,
354
- account_model: AccountModel,
355
- root_account_qs: Optional[AccountModelQuerySet] = None,
356
- as_queryset: bool = False) -> AccountModel:
352
+ def get_account_root_node(
353
+ self,
354
+ account_model: AccountModel,
355
+ root_account_qs: Optional[AccountModelQuerySet] = None,
356
+ as_queryset: bool = False,
357
+ ) -> AccountModel:
357
358
  """
358
359
  Fetches the root node of the ChartOfAccountModel instance. The root node is the highest level of the CoA
359
360
  hierarchy. It can be used to traverse the hierarchy of the CoA structure downstream.
@@ -389,7 +390,6 @@ class ChartOfAccountModelAbstract(SlugNameMixIn, CreateUpdateMixIn):
389
390
  self.configure(raise_exception=True)
390
391
 
391
392
  if not account_model.is_root_account():
392
-
393
393
  if not root_account_qs:
394
394
  root_account_qs = self.get_coa_root_accounts_qs()
395
395
 
@@ -406,16 +406,16 @@ class ChartOfAccountModelAbstract(SlugNameMixIn, CreateUpdateMixIn):
406
406
  elif account_model.is_expense():
407
407
  qs = root_account_qs.filter(code__exact=ROOT_GROUP_META[ROOT_EXPENSES]['code'])
408
408
  else:
409
- raise ChartOfAccountsModelValidationError(message=f'Unable to locate Balance Sheet'
410
- ' root node for account code: '
411
- f'{account_model.code} {account_model.name}')
409
+ raise ChartOfAccountsModelValidationError(
410
+ message=f'Unable to locate Balance Sheet'
411
+ ' root node for account code: '
412
+ f'{account_model.code} {account_model.name}'
413
+ )
412
414
  if as_queryset:
413
415
  return qs
414
416
  return qs.get()
415
417
 
416
- raise ChartOfAccountsModelValidationError(
417
- message='Adding Root account to Chart of Accounts is not allowed.'
418
- )
418
+ raise ChartOfAccountsModelValidationError(message='Adding Root account to Chart of Accounts is not allowed.')
419
419
 
420
420
  def get_non_root_coa_accounts_qs(self) -> AccountModelQuerySet:
421
421
  """
@@ -486,19 +486,12 @@ class ChartOfAccountModelAbstract(SlugNameMixIn, CreateUpdateMixIn):
486
486
  """
487
487
  if self.slug:
488
488
  if raise_exception:
489
- raise ChartOfAccountsModelValidationError(
490
- message=_(f'CoA {self.uuid} already has a slug')
491
- )
489
+ raise ChartOfAccountsModelValidationError(message=_(f'CoA {self.uuid} already has a slug'))
492
490
  return
493
491
  self.slug = f'coa-{self.entity.slug[-5:]}-' + ''.join(choices(SLUG_SUFFIX, k=15))
494
492
 
495
493
  if commit:
496
- self.save(
497
- update_fields=[
498
- 'slug',
499
- 'updated'
500
- ]
501
- )
494
+ self.save(update_fields=['slug', 'updated'])
502
495
 
503
496
  def is_default(self) -> bool:
504
497
  """
@@ -540,18 +533,16 @@ class ChartOfAccountModelAbstract(SlugNameMixIn, CreateUpdateMixIn):
540
533
 
541
534
  """
542
535
  if not isinstance(account_model_qs, AccountModelQuerySet):
543
- raise ChartOfAccountsModelValidationError(
544
- message='Must pass an instance of AccountModelQuerySet'
545
- )
536
+ raise ChartOfAccountsModelValidationError(message='Must pass an instance of AccountModelQuerySet')
546
537
  for acc_model in account_model_qs:
547
538
  if not acc_model.coa_model_id == self.uuid:
548
- raise ChartOfAccountsModelValidationError(
549
- message=f'Invalid root queryset for CoA {self.name}'
550
- )
539
+ raise ChartOfAccountsModelValidationError(message=f'Invalid root queryset for CoA {self.name}')
551
540
 
552
- def insert_account(self,
553
- account_model: AccountModel,
554
- root_account_qs: Optional[AccountModelQuerySet] = None):
541
+ def insert_account(
542
+ self,
543
+ account_model: AccountModel,
544
+ root_account_qs: Optional[AccountModelQuerySet] = None,
545
+ ):
555
546
  """
556
547
  This method inserts the given account model into the chart of accounts (COA) instance.
557
548
  It first verifies if the account model's COA model ID matches the COA's UUID. If not, it
@@ -599,21 +590,22 @@ class ChartOfAccountModelAbstract(SlugNameMixIn, CreateUpdateMixIn):
599
590
  self.validate_account_model_qs(root_account_qs)
600
591
 
601
592
  account_root_node: AccountModel = self.get_account_root_node(
602
- account_model=account_model,
603
- root_account_qs=root_account_qs
593
+ account_model=account_model, root_account_qs=root_account_qs
604
594
  )
605
595
 
606
596
  account_root_node.add_child(instance=account_model)
607
597
  coa_accounts_qs = self.get_non_root_coa_accounts_qs()
608
598
  return coa_accounts_qs.get(uuid__exact=account_model.uuid)
609
599
 
610
- def create_account(self,
611
- code: str,
612
- role: str,
613
- name: str,
614
- balance_type: str,
615
- active: bool,
616
- root_account_qs: Optional[AccountModelQuerySet] = None):
600
+ def create_account(
601
+ self,
602
+ code: str,
603
+ role: str,
604
+ name: str,
605
+ balance_type: str,
606
+ active: bool,
607
+ root_account_qs: Optional[AccountModelQuerySet] = None,
608
+ ):
617
609
  """
618
610
  Proper method for inserting a new Account Model into a CoA.
619
611
  Use this in liu of the direct instantiation of the AccountModel of using the django related manager.
@@ -644,14 +636,11 @@ class ChartOfAccountModelAbstract(SlugNameMixIn, CreateUpdateMixIn):
644
636
  role=role,
645
637
  active=active,
646
638
  balance_type=balance_type,
647
- coa_model=self
639
+ coa_model=self,
648
640
  )
649
641
  account_model.clean()
650
642
 
651
- account_model = self.insert_account(
652
- account_model=account_model,
653
- root_account_qs=root_account_qs
654
- )
643
+ account_model = self.insert_account(account_model=account_model, root_account_qs=root_account_qs)
655
644
  return account_model
656
645
 
657
646
  # ACTIONS -----
@@ -692,18 +681,10 @@ class ChartOfAccountModelAbstract(SlugNameMixIn, CreateUpdateMixIn):
692
681
  self.entity.default_coa_id = self.uuid
693
682
  self.clean()
694
683
  if commit:
695
- self.entity.save(
696
- update_fields=[
697
- 'default_coa_id',
698
- 'updated'
699
- ]
700
- )
684
+ self.entity.save(update_fields=['default_coa_id', 'updated'])
701
685
 
702
686
  def can_mark_as_default(self):
703
- return all([
704
- self.is_active(),
705
- not self.is_default()
706
- ])
687
+ return all([self.is_active(), not self.is_default()])
707
688
 
708
689
  def can_activate(self) -> bool:
709
690
  """
@@ -723,10 +704,7 @@ class ChartOfAccountModelAbstract(SlugNameMixIn, CreateUpdateMixIn):
723
704
  -------
724
705
  True if the object can be deactivated, False otherwise.
725
706
  """
726
- return all([
727
- self.is_active(),
728
- not self.is_default()
729
- ])
707
+ return all([self.is_active(), not self.is_default()])
730
708
 
731
709
  def mark_as_active(self, commit: bool = False, raise_exception: bool = False, **kwargs):
732
710
  """
@@ -741,19 +719,13 @@ class ChartOfAccountModelAbstract(SlugNameMixIn, CreateUpdateMixIn):
741
719
  """
742
720
  if self.is_active():
743
721
  if raise_exception:
744
- raise ChartOfAccountsModelValidationError(
745
- message=_('The Chart of Accounts is currently active.')
746
- )
722
+ raise ChartOfAccountsModelValidationError(message=_('The Chart of Accounts is currently active.'))
747
723
  return
748
724
 
749
725
  self.active = True
750
726
  self.clean()
751
727
  if commit:
752
- self.save(
753
- update_fields=[
754
- 'active',
755
- 'updated'
756
- ])
728
+ self.save(update_fields=['active', 'updated'])
757
729
 
758
730
  def mark_as_inactive(self, commit: bool = False, raise_exception: bool = False, **kwargs):
759
731
  """
@@ -768,19 +740,13 @@ class ChartOfAccountModelAbstract(SlugNameMixIn, CreateUpdateMixIn):
768
740
  """
769
741
  if not self.is_active():
770
742
  if raise_exception:
771
- raise ChartOfAccountsModelValidationError(
772
- message=_('The Chart of Accounts is currently not active.')
773
- )
743
+ raise ChartOfAccountsModelValidationError(message=_('The Chart of Accounts is currently not active.'))
774
744
  return
775
745
 
776
746
  self.active = False
777
747
  self.clean()
778
748
  if commit:
779
- self.save(
780
- update_fields=[
781
- 'active',
782
- 'updated'
783
- ])
749
+ self.save(update_fields=['active', 'updated'])
784
750
 
785
751
  # URLS....
786
752
  def mark_as_default_url(self) -> str:
@@ -794,10 +760,7 @@ class ChartOfAccountModelAbstract(SlugNameMixIn, CreateUpdateMixIn):
794
760
  """
795
761
  return reverse(
796
762
  viewname='django_ledger:coa-action-mark-as-default',
797
- kwargs={
798
- 'entity_slug': self.entity_slug,
799
- 'coa_slug': self.slug
800
- }
763
+ kwargs={'entity_slug': self.entity_slug, 'coa_slug': self.slug},
801
764
  )
802
765
 
803
766
  def mark_as_active_url(self) -> str:
@@ -811,10 +774,7 @@ class ChartOfAccountModelAbstract(SlugNameMixIn, CreateUpdateMixIn):
811
774
  """
812
775
  return reverse(
813
776
  viewname='django_ledger:coa-action-mark-as-active',
814
- kwargs={
815
- 'entity_slug': self.entity_slug,
816
- 'coa_slug': self.slug
817
- }
777
+ kwargs={'entity_slug': self.entity_slug, 'coa_slug': self.slug},
818
778
  )
819
779
 
820
780
  def mark_as_inactive_url(self) -> str:
@@ -828,74 +788,49 @@ class ChartOfAccountModelAbstract(SlugNameMixIn, CreateUpdateMixIn):
828
788
  """
829
789
  return reverse(
830
790
  viewname='django_ledger:coa-action-mark-as-inactive',
831
- kwargs={
832
- 'entity_slug': self.entity_slug,
833
- 'coa_slug': self.slug
834
- }
791
+ kwargs={'entity_slug': self.entity_slug, 'coa_slug': self.slug},
835
792
  )
836
793
 
837
794
  def get_coa_list_url(self):
838
- return reverse(
839
- viewname='django_ledger:coa-list',
840
- kwargs={
841
- 'entity_slug': self.entity_slug
842
- }
843
- )
795
+ return reverse(viewname='django_ledger:coa-list', kwargs={'entity_slug': self.entity_slug})
844
796
 
845
797
  def get_coa_list_inactive_url(self):
846
798
  return reverse(
847
799
  viewname='django_ledger:coa-list-inactive',
848
- kwargs={
849
- 'entity_slug': self.entity_slug
850
- }
800
+ kwargs={'entity_slug': self.entity_slug},
851
801
  )
852
802
 
853
803
  def get_coa_create_url(self):
854
804
  return reverse(
855
805
  viewname='django_ledger:coa-create',
856
- kwargs={
857
- 'entity_slug': self.entity_slug
858
- }
806
+ kwargs={'entity_slug': self.entity_slug},
859
807
  )
860
808
 
861
809
  def get_absolute_url(self) -> str:
862
810
  return reverse(
863
811
  viewname='django_ledger:coa-detail',
864
- kwargs={
865
- 'entity_slug': self.entity_slug,
866
- 'coa_slug': self.slug
867
- }
812
+ kwargs={'entity_slug': self.entity_slug, 'coa_slug': self.slug},
868
813
  )
869
814
 
870
815
  def get_update_url(self) -> str:
871
816
  return reverse(
872
817
  viewname='django_ledger:coa-update',
873
- kwargs={
874
- 'entity_slug': self.entity_slug,
875
- 'coa_slug': self.slug
876
- }
818
+ kwargs={'entity_slug': self.entity_slug, 'coa_slug': self.slug},
877
819
  )
878
820
 
879
821
  def get_account_list_url(self):
880
-
881
822
  if not self.slug:
882
823
  self.generate_slug(commit=True)
883
824
 
884
825
  return reverse(
885
826
  viewname='django_ledger:account-list',
886
- kwargs={
887
- 'entity_slug': self.entity_slug,
888
- 'coa_slug': self.slug
889
- }
827
+ kwargs={'entity_slug': self.entity_slug, 'coa_slug': self.slug},
890
828
  )
891
829
 
892
830
  def get_create_coa_account_url(self):
893
831
  return reverse(
894
832
  viewname='django_ledger:account-create',
895
- kwargs={
896
- 'coa_slug': self.slug,
897
- 'entity_slug': self.entity_slug
898
- }
833
+ kwargs={'coa_slug': self.slug, 'entity_slug': self.entity_slug},
899
834
  )
900
835
 
901
836
  def clean(self):
@@ -915,9 +850,7 @@ class ChartOfAccountModel(ChartOfAccountModelAbstract):
915
850
  def chartofaccountsmodel_presave(instance: ChartOfAccountModelAbstract, **kwargs):
916
851
  instance.generate_slug()
917
852
  if instance.is_default() and not instance.active:
918
- raise ChartOfAccountsModelValidationError(
919
- _('Default Chart of Accounts cannot be deactivated.')
920
- )
853
+ raise ChartOfAccountsModelValidationError(_('Default Chart of Accounts cannot be deactivated.'))
921
854
 
922
855
 
923
856
  @receiver(post_save, sender=ChartOfAccountModel)
@@ -109,6 +109,7 @@ Default Chart of Accounts Table
109
109
  4050 in_other credit Other Income root_income
110
110
  4020 in_passive credit Investing Income root_income
111
111
  2010 lia_cl_acc_payable credit Accounts Payable root_liabilities
112
+ 2015 lia_cl_credit_line credit Accounts Payable root_liabilities
112
113
  2060 lia_cl_def_rev credit Deferred Revenues root_liabilities
113
114
  2030 lia_cl_int_payable credit Interest Payable root_liabilities
114
115
  2050 lia_cl_ltd_mat credit Current Maturities LT Debt root_liabilities
@@ -54,7 +54,7 @@ class CustomerModelQueryset(QuerySet):
54
54
  reports.
55
55
  """
56
56
 
57
- def for_user(self, user_model):
57
+ def for_user(self, user_model) -> 'CustomerModelQueryset':
58
58
  """
59
59
  Fetches a QuerySet of BillModels that the UserModel as access to.
60
60
  May include BillModels from multiple Entities.
@@ -70,12 +70,9 @@ class CustomerModelQueryset(QuerySet):
70
70
  """
71
71
  if user_model.is_superuser:
72
72
  return self
73
- return self.filter(
74
- Q(entity_model__admin=user_model)
75
- | Q(entity_model__managers__in=[user_model])
76
- )
73
+ return self.filter(Q(entity_model__admin=user_model) | Q(entity_model__managers__in=[user_model]))
77
74
 
78
- def active(self) -> QuerySet:
75
+ def active(self) -> 'CustomerModelQueryset':
79
76
  """
80
77
  Active customers can be assigned to new Invoices and show on dropdown menus and views.
81
78
 
@@ -86,7 +83,7 @@ class CustomerModelQueryset(QuerySet):
86
83
  """
87
84
  return self.filter(active=True)
88
85
 
89
- def inactive(self) -> QuerySet:
86
+ def inactive(self) -> 'CustomerModelQueryset':
90
87
  """
91
88
  Active customers can be assigned to new Invoices and show on dropdown menus and views.
92
89
  Marking CustomerModels as inactive can help reduce Database load to populate select inputs and also inactivate
@@ -100,7 +97,7 @@ class CustomerModelQueryset(QuerySet):
100
97
  """
101
98
  return self.filter(active=False)
102
99
 
103
- def hidden(self) -> QuerySet:
100
+ def hidden(self) -> 'CustomerModelQueryset':
104
101
  """
105
102
  Hidden customers do not show on dropdown menus, but may be used via APIs or any other method that does not
106
103
  involve the UI.
@@ -112,7 +109,7 @@ class CustomerModelQueryset(QuerySet):
112
109
  """
113
110
  return self.filter(hidden=True)
114
111
 
115
- def visible(self) -> QuerySet:
112
+ def visible(self) -> 'CustomerModelQueryset':
116
113
  """
117
114
  Visible customers show on dropdown menus and views. Visible customers are active and not hidden.
118
115
 
@@ -130,10 +127,11 @@ class CustomerModelManager(Manager):
130
127
  CustomerModel.
131
128
  """
132
129
 
130
+ def get_queryset(self) -> CustomerModelQueryset:
131
+ return CustomerModelQueryset(self.model, using=self._db)
132
+
133
133
  @deprecated_entity_slug_behavior
134
- def for_entity(
135
- self, entity_model: 'EntityModel | str | UUID' = None, **kwargs
136
- ) -> CustomerModelQueryset:
134
+ def for_entity(self, entity_model: 'EntityModel | str | UUID', **kwargs) -> CustomerModelQueryset: # noqa: F821
137
135
  """
138
136
  Fetches a QuerySet of CustomerModel associated with a specific EntityModel & UserModel.
139
137
  May pass an instance of EntityModel or a String representing the EntityModel slug.
@@ -161,16 +159,15 @@ class CustomerModelManager(Manager):
161
159
  qs = qs.for_user(kwargs['user_model'])
162
160
 
163
161
  if isinstance(entity_model, EntityModel):
164
- qs = qs.filter(entity_model=entity_model)
162
+ return qs.filter(entity_model=entity_model)
165
163
  elif isinstance(entity_model, str):
166
- qs = qs.filter(entity_model__slug__exact=entity_model)
164
+ return qs.filter(entity_model__slug__exact=entity_model)
167
165
  elif isinstance(entity_model, UUID):
168
- qs = qs.filter(entity_model_id=entity_model)
166
+ return qs.filter(entity_model_id=entity_model)
169
167
  else:
170
168
  raise CustomerModelValidationError(
171
169
  message='Must pass EntityModel, slug or EntityModel UUID',
172
170
  )
173
- return qs
174
171
 
175
172
 
176
173
  class CustomerModelAbstract(ContactInfoMixIn, TaxCollectionMixIn, CreateUpdateMixIn):
@@ -232,9 +229,7 @@ class CustomerModelAbstract(ContactInfoMixIn, TaxCollectionMixIn, CreateUpdateMi
232
229
  description = models.TextField()
233
230
  active = models.BooleanField(default=True)
234
231
  hidden = models.BooleanField(default=False)
235
- picture = models.ImageField(
236
- upload_to=customer_picture_upload_to, null=True, blank=True
237
- )
232
+ picture = models.ImageField(upload_to=customer_picture_upload_to, null=True, blank=True)
238
233
 
239
234
  additional_info = models.JSONField(null=True, blank=True, default=dict)
240
235
 
@@ -292,9 +287,7 @@ class CustomerModelAbstract(ContactInfoMixIn, TaxCollectionMixIn, CreateUpdateMi
292
287
  'key__exact': EntityStateModel.KEY_CUSTOMER,
293
288
  }
294
289
 
295
- state_model_qs = EntityStateModel.objects.filter(
296
- **LOOKUP
297
- ).select_for_update()
290
+ state_model_qs = EntityStateModel.objects.filter(**LOOKUP).select_for_update()
298
291
  state_model = state_model_qs.get()
299
292
  state_model.sequence = F('sequence') + 1
300
293
  state_model.save()
@@ -344,11 +337,9 @@ class CustomerModelAbstract(ContactInfoMixIn, TaxCollectionMixIn, CreateUpdateMi
344
337
 
345
338
  return self.customer_number
346
339
 
347
- def validate_for_entity(self, entity_model: 'EntityModel'):
340
+ def validate_for_entity(self, entity_model: 'EntityModel'): # noqa: F821
348
341
  if entity_model.uuid != self.entity_model_id:
349
- raise CustomerModelValidationError(
350
- 'EntityModel does not belong to this Vendor'
351
- )
342
+ raise CustomerModelValidationError('EntityModel does not belong to this Vendor')
352
343
 
353
344
  def clean(self):
354
345
  """