django-ledger 0.7.5.2__py3-none-any.whl → 0.7.6__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 (38) hide show
  1. django_ledger/__init__.py +1 -1
  2. django_ledger/forms/closing_entry.py +2 -1
  3. django_ledger/forms/journal_entry.py +1 -0
  4. django_ledger/io/io_context.py +10 -0
  5. django_ledger/io/io_core.py +22 -0
  6. django_ledger/models/accounts.py +40 -1
  7. django_ledger/models/bank_account.py +0 -1
  8. django_ledger/models/bill.py +0 -1
  9. django_ledger/models/chart_of_accounts.py +0 -1
  10. django_ledger/models/closing_entry.py +27 -13
  11. django_ledger/models/customer.py +0 -1
  12. django_ledger/models/data_import.py +0 -2
  13. django_ledger/models/entity.py +15 -3
  14. django_ledger/models/estimate.py +0 -1
  15. django_ledger/models/invoice.py +0 -1
  16. django_ledger/models/items.py +0 -3
  17. django_ledger/models/journal_entry.py +5 -3
  18. django_ledger/models/ledger.py +0 -1
  19. django_ledger/models/purchase_order.py +0 -1
  20. django_ledger/models/transactions.py +27 -4
  21. django_ledger/models/unit.py +0 -1
  22. django_ledger/models/vendor.py +0 -1
  23. django_ledger/settings.py +22 -21
  24. django_ledger/templates/django_ledger/layouts/base.html +6 -1
  25. django_ledger/urls/ledger.py +1 -1
  26. django_ledger/views/closing_entry.py +47 -40
  27. django_ledger/views/mixins.py +6 -0
  28. django_ledger/views/unit.py +11 -14
  29. django_ledger/views/vendor.py +10 -8
  30. {django_ledger-0.7.5.2.dist-info → django_ledger-0.7.6.dist-info}/METADATA +3 -1
  31. {django_ledger-0.7.5.2.dist-info → django_ledger-0.7.6.dist-info}/RECORD +35 -38
  32. {django_ledger-0.7.5.2.dist-info → django_ledger-0.7.6.dist-info}/WHEEL +1 -1
  33. {django_ledger-0.7.5.2.dist-info → django_ledger-0.7.6.dist-info}/top_level.txt +0 -1
  34. django_ledger/static/.DS_Store +0 -0
  35. django_ledger/static/django_ledger/.DS_Store +0 -0
  36. django_ledger/static/django_ledger/logo_2/.DS_Store +0 -0
  37. {django_ledger-0.7.5.2.dist-info → django_ledger-0.7.6.dist-info}/AUTHORS.md +0 -0
  38. {django_ledger-0.7.5.2.dist-info → django_ledger-0.7.6.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.5.2'
9
+ __version__ = '0.7.6'
10
10
  __license__ = 'GPLv3 License'
11
11
 
12
12
  __author__ = 'Miguel Sanda'
@@ -26,7 +26,8 @@ class ClosingEntryCreateForm(ModelForm):
26
26
  'closing_date': DateInput(attrs={
27
27
  'class': DJANGO_LEDGER_FORM_INPUT_CLASSES + ' is-large',
28
28
  'placeholder': _('Closing Date (YYYY-MM-DD)...'),
29
- 'id': 'djl-datepicker'
29
+ 'id': 'djl-datepicker',
30
+ 'type': 'date'
30
31
  })
31
32
  }
32
33
  labels = {
@@ -53,6 +53,7 @@ class JournalEntryModelCreateForm(ModelForm):
53
53
  'class': DJANGO_LEDGER_FORM_INPUT_CLASSES
54
54
  }),
55
55
  'timestamp': DateTimeInput(attrs={
56
+ 'type': 'datetime-local',
56
57
  'class': DJANGO_LEDGER_FORM_INPUT_CLASSES
57
58
  }),
58
59
  'description': Textarea(attrs={
@@ -89,6 +89,16 @@ class IODigestContextManager:
89
89
  def is_by_activity(self) -> bool:
90
90
  return self.IO_DATA['by_activity']
91
91
 
92
+ # Account Information
93
+ def get_account_data(self, key_func=None) -> Dict:
94
+ if key_func:
95
+ return {
96
+ key_func(acc): acc for acc in self.IO_DATA['accounts']
97
+ }
98
+ return {
99
+ acc['account_uuid']: acc for acc in self.IO_DATA['accounts']
100
+ }
101
+
92
102
  # Balance Sheet Data...
93
103
  def has_balance_sheet(self) -> bool:
94
104
  return 'balance_sheet' in self.IO_DATA
@@ -847,6 +847,28 @@ class IODatabaseMixIn:
847
847
  if role:
848
848
  txs_queryset = txs_queryset.for_roles(role_list=role)
849
849
 
850
+ # Cleared transaction filter via KWARGS....
851
+ cleared_filter = kwargs.get('cleared')
852
+ if cleared_filter is not None:
853
+ if cleared_filter in [True, False]:
854
+ txs_queryset = txs_queryset.is_cleared() if cleared_filter else txs_queryset.not_cleared()
855
+ else:
856
+ raise IOValidationError(
857
+ message=f'Invalid value for cleared filter: {cleared_filter}. '
858
+ f'Valid values are True, False'
859
+ )
860
+
861
+ # Reconciled transaction filter via KWARGS....
862
+ reconciled_filter = kwargs.get('reconciled')
863
+ if reconciled_filter is not None:
864
+ if reconciled_filter in [True, False]:
865
+ txs_queryset = txs_queryset.is_reconciled() if reconciled_filter else txs_queryset.not_reconciled()
866
+ else:
867
+ raise IOValidationError(
868
+ message=f'Invalid value for reconciled filter: {reconciled_filter}. '
869
+ f'Valid values are True, False'
870
+ )
871
+
850
872
  if io_result.is_bounded:
851
873
  txs_queryset = txs_queryset.annotate(
852
874
  amount_io=Case(
@@ -472,8 +472,35 @@ class AccountModelAbstract(MP_Node, CreateUpdateMixIn):
472
472
  x5=self.code
473
473
  )
474
474
 
475
+ def alt_str(self):
476
+ """
477
+ Returns a formatted string representation of the object.
478
+
479
+ The formatted string includes the code, name, role, and balance type
480
+ of the object. The role is converted to uppercase for consistency,
481
+ and the balance type is displayed as is. This method provides a
482
+ concise textual representation for quick identification or display.
483
+
484
+ Returns:
485
+ str: A formatted string in the format 'code: name (ROLE/BALANCE_TYPE)'.
486
+ """
487
+ return f'{self.code}: {self.name} ({self.role.upper()}/{self.balance_type})'
488
+
475
489
  @property
476
490
  def coa_slug(self):
491
+ """
492
+ Property that retrieves the `coa_slug` attribute from the object. If the attribute
493
+ is not found, it fetches the `slug` attribute from the `coa_model`.
494
+
495
+ Attributes:
496
+ _coa_slug (str): Cached value of the `coa_slug` if it exists.
497
+ coa_model (Any): Object containing the `slug` attribute that serves
498
+ as a fallback when `_coa_slug` is not present.
499
+
500
+ Returns:
501
+ str: The value of `_coa_slug` if defined, or the `slug` attribute from
502
+ `coa_model` if `_coa_slug` is not available.
503
+ """
477
504
  try:
478
505
  return getattr(self, '_coa_slug')
479
506
  except AttributeError:
@@ -481,6 +508,19 @@ class AccountModelAbstract(MP_Node, CreateUpdateMixIn):
481
508
 
482
509
  @property
483
510
  def entity_slug(self):
511
+ """
512
+ Retrieve the slug value associated with the entity.
513
+
514
+ This property method returns the value of the private attribute
515
+ '_entity_slug' for the current instance. The purpose of the
516
+ slug is typically to provide a URL-friendly string representing
517
+ the entity.
518
+
519
+ Returns
520
+ -------
521
+ Any
522
+ The value of the '_entity_slug' attribute.
523
+ """
484
524
  return getattr(self, '_entity_slug')
485
525
 
486
526
  @classmethod
@@ -1059,7 +1099,6 @@ class AccountModel(AccountModelAbstract):
1059
1099
  """
1060
1100
 
1061
1101
  class Meta(AccountModelAbstract.Meta):
1062
- swappable = 'DJANGO_LEDGER_ACCOUNT_MODEL'
1063
1102
  abstract = False
1064
1103
 
1065
1104
 
@@ -213,5 +213,4 @@ class BankAccountModel(BankAccountModelAbstract):
213
213
  """
214
214
 
215
215
  class Meta(BankAccountModelAbstract.Meta):
216
- swappable = 'DJANGO_LEDGER_BANK_ACCOUNT_MODEL'
217
216
  abstract = False
@@ -1920,7 +1920,6 @@ class BillModel(BillModelAbstract):
1920
1920
  """
1921
1921
 
1922
1922
  class Meta(BillModelAbstract.Meta):
1923
- swappable = 'DJANGO_LEDGER_BILL_MODEL'
1924
1923
  abstract = False
1925
1924
 
1926
1925
 
@@ -840,7 +840,6 @@ class ChartOfAccountModel(ChartOfAccountModelAbstract):
840
840
  Base ChartOfAccounts Model
841
841
  """
842
842
  class Meta(ChartOfAccountModelAbstract.Meta):
843
- swappable = 'DJANGO_LEDGER_CHART_OF_ACCOUNTS_MODEL'
844
843
  abstract = False
845
844
 
846
845
 
@@ -9,11 +9,10 @@ from itertools import groupby, chain
9
9
  from typing import Optional
10
10
  from uuid import uuid4, UUID
11
11
 
12
- from django.conf import settings
13
12
  from django.core.exceptions import ValidationError
14
13
  from django.core.validators import MinValueValidator
15
14
  from django.db import models
16
- from django.db.models import Q
15
+ from django.db.models import Q, Count
17
16
  from django.db.models.signals import pre_save
18
17
  from django.urls import reverse
19
18
  from django.utils.timezone import make_aware
@@ -24,7 +23,6 @@ from django_ledger.models.ledger import LedgerModel
24
23
  from django_ledger.models.mixins import CreateUpdateMixIn, MarkdownNotesMixIn
25
24
  from django_ledger.models.transactions import TransactionModel
26
25
  from django_ledger.models.utils import lazy_loader
27
- from django_ledger.settings import DJANGO_LEDGER_LEDGER_MODEL
28
26
 
29
27
 
30
28
  class ClosingEntryValidationError(ValidationError):
@@ -42,6 +40,12 @@ class ClosingEntryModelQuerySet(models.QuerySet):
42
40
 
43
41
  class ClosingEntryModelManager(models.Manager):
44
42
 
43
+ def get_queryset(self):
44
+ qs = ClosingEntryModelQuerySet(self.model, using=self._db)
45
+ return qs.annotate(
46
+ ce_txs_count=Count('closingentrytransactionmodel')
47
+ )
48
+
45
49
  def for_user(self, user_model):
46
50
  qs = self.get_queryset()
47
51
  if user_model.is_superuser:
@@ -102,6 +106,7 @@ class ClosingEntryModelAbstract(CreateUpdateMixIn, MarkdownNotesMixIn):
102
106
  return make_aware(datetime.combine(self.closing_date, time.max))
103
107
 
104
108
  def migrate(self):
109
+
105
110
  ce_txs = self.closingentrytransactionmodel_set.all().select_related(
106
111
  'account_model',
107
112
  'unit_model'
@@ -118,8 +123,9 @@ class ClosingEntryModelAbstract(CreateUpdateMixIn, MarkdownNotesMixIn):
118
123
  ce_txs_gb = groupby(ce_txs, key=lambda k: k.tx_type)
119
124
 
120
125
  # adding DEBITS and CREDITS...
121
- # ce_txs_gb = {k: list(l) for k, l in ce_txs_gb}
122
- ce_txs_sum = {k: sum(v.balance for v in l) for k, l in ce_txs_gb}
126
+ ce_txs_sum = {
127
+ k: sum(v.balance for v in l) for k, l in ce_txs_gb
128
+ }
123
129
 
124
130
  if len(ce_txs_sum) and ce_txs_sum[TransactionModel.DEBIT] != ce_txs_sum[TransactionModel.CREDIT]:
125
131
  raise ClosingEntryValidationError(
@@ -131,7 +137,9 @@ class ClosingEntryModelAbstract(CreateUpdateMixIn, MarkdownNotesMixIn):
131
137
 
132
138
  ce_txs.sort(key=key_func)
133
139
  ce_txs_gb = groupby(ce_txs, key=key_func)
134
- ce_txs_gb = {unit_model_id: list(je_txs) for unit_model_id, je_txs in ce_txs_gb}
140
+ ce_txs_gb = {
141
+ unit_model_id: list(je_txs) for unit_model_id, je_txs in ce_txs_gb
142
+ }
135
143
 
136
144
  ce_txs_journal_entries = {
137
145
  (unit_model_id, activity): JournalEntryModel(
@@ -164,6 +172,8 @@ class ClosingEntryModelAbstract(CreateUpdateMixIn, MarkdownNotesMixIn):
164
172
  for k, je_model in ce_txs_journal_entries.items():
165
173
  je_model.save(verify=True)
166
174
 
175
+ self.ledger_model.lock(commit=True, raise_exception=True)
176
+
167
177
  return ce_txs_journal_entries, ce_je_txs
168
178
 
169
179
  def create_entry_ledger(self, commit: bool = False):
@@ -172,7 +182,7 @@ class ClosingEntryModelAbstract(CreateUpdateMixIn, MarkdownNotesMixIn):
172
182
  name=f'Closing Entry {self.closing_date} Ledger',
173
183
  entity_id=self.entity_model_id,
174
184
  hidden=True,
175
- locked=True,
185
+ locked=False,
176
186
  posted=True
177
187
  )
178
188
  ledger_model.clean()
@@ -189,7 +199,7 @@ class ClosingEntryModelAbstract(CreateUpdateMixIn, MarkdownNotesMixIn):
189
199
  def can_post(self) -> bool:
190
200
  return not self.is_posted()
191
201
 
192
- def mark_as_posted(self, commit: bool = False, update_entity_meta: bool = False, **kwargs):
202
+ def mark_as_posted(self, commit: bool = False, update_entity_meta: bool = True, **kwargs):
193
203
  if not self.can_post():
194
204
  raise ClosingEntryValidationError(
195
205
  message=_(f'Closing Entry {self.closing_date} is already posted.')
@@ -226,11 +236,14 @@ class ClosingEntryModelAbstract(CreateUpdateMixIn, MarkdownNotesMixIn):
226
236
  def can_unpost(self) -> bool:
227
237
  return self.is_posted()
228
238
 
229
- def mark_as_unposted(self, commit: bool = False, update_entity_meta: bool = False, **kwargs):
239
+ def mark_as_unposted(self, commit: bool = False, update_entity_meta: bool = True, **kwargs):
230
240
  if not self.can_unpost():
231
241
  raise ClosingEntryValidationError(
232
242
  message=_(f'Closing Entry {self.closing_date} is not posted.')
233
243
  )
244
+
245
+ self.ledger_model.unlock(commit=False, raise_exception=True)
246
+ self.ledger_model.save(update_fields=['posted', 'locked', 'updated'])
234
247
  self.posted = False
235
248
 
236
249
  TransactionModel.objects.for_entity(
@@ -305,6 +318,8 @@ class ClosingEntryModelAbstract(CreateUpdateMixIn, MarkdownNotesMixIn):
305
318
  message=_('Cannot delete a posted Closing Entry')
306
319
  )
307
320
 
321
+ self.ledger_model.unpost(commit=True, raise_exception=True)
322
+
308
323
  TransactionModel.objects.for_entity(
309
324
  entity_slug=self.entity_model_id
310
325
  ).for_ledger(ledger_model=self.ledger_model).delete()
@@ -343,12 +358,9 @@ class ClosingEntryModelAbstract(CreateUpdateMixIn, MarkdownNotesMixIn):
343
358
 
344
359
  class ClosingEntryModel(ClosingEntryModelAbstract):
345
360
  class Meta(ClosingEntryModelAbstract.Meta):
346
- swappable = 'DJANGO_LEDGER_CLOSING_ENTRY_MODEL'
347
361
  abstract = False
348
362
 
349
363
 
350
- # todo: Remove this model!
351
-
352
364
  class ClosingEntryTransactionModelQuerySet(models.QuerySet):
353
365
  pass
354
366
 
@@ -433,7 +445,6 @@ class ClosingEntryTransactionModelAbstract(CreateUpdateMixIn):
433
445
  name='unique_ce_opt_3'
434
446
  )
435
447
  ]
436
-
437
448
  indexes = [
438
449
  models.Index(fields=['closing_entry_model']),
439
450
  models.Index(fields=['account_model'])
@@ -470,6 +481,9 @@ class ClosingEntryTransactionModel(ClosingEntryTransactionModelAbstract):
470
481
  Base ClosingEntryModel Class
471
482
  """
472
483
 
484
+ class Meta(ClosingEntryTransactionModelAbstract.Meta):
485
+ abstract = False
486
+
473
487
 
474
488
  def closingentrymodel_presave(instance: ClosingEntryModel, **kwargs):
475
489
  instance.create_entry_ledger(commit=False)
@@ -321,5 +321,4 @@ class CustomerModel(CustomerModelAbstract):
321
321
  """
322
322
 
323
323
  class Meta(CustomerModelAbstract.Meta):
324
- swappable = 'DJANGO_LEDGER_CUSTOMER_MODEL'
325
324
  abstract = False
@@ -1176,7 +1176,6 @@ class ImportJobModel(ImportJobModelAbstract):
1176
1176
  """
1177
1177
 
1178
1178
  class Meta(ImportJobModelAbstract.Meta):
1179
- swappable = 'DJANGO_LEDGER_IMPORT_JOB_MODEL'
1180
1179
  abstract = False
1181
1180
 
1182
1181
 
@@ -1197,5 +1196,4 @@ class StagedTransactionModel(StagedTransactionModelAbstract):
1197
1196
  """
1198
1197
 
1199
1198
  class Meta(StagedTransactionModelAbstract.Meta):
1200
- swappable = 'DJANGO_LEDGER_STAGED_TRANSACTION_MODEL'
1201
1199
  abstract = False
@@ -1517,6 +1517,20 @@ class EntityModelAbstract(MP_Node,
1517
1517
  # account_model.clean()
1518
1518
  return coa_model, coa_model.create_account(**account_model_kwargs)
1519
1519
 
1520
+ def get_account_balance(self,
1521
+ account_codes: List[str],
1522
+ to_date: Union[datetime, date, str],
1523
+ **kwargs):
1524
+
1525
+ io_context = self.digest(
1526
+ entity_model=self.slug,
1527
+ accounts=account_codes,
1528
+ to_date=to_date,
1529
+ **kwargs
1530
+ )
1531
+
1532
+ return io_context
1533
+
1520
1534
  # ### LEDGER MANAGEMENT ####
1521
1535
  def get_ledgers(self, posted: Optional[bool] = None):
1522
1536
  if posted is not None:
@@ -3135,12 +3149,11 @@ class EntityModel(EntityModelAbstract):
3135
3149
  """
3136
3150
  Entity Model Base Class From Abstract
3137
3151
  """
3152
+
3138
3153
  class Meta(EntityModelAbstract.Meta):
3139
- swappable = 'DJANGO_LEDGER_ENTITY_MODEL'
3140
3154
  abstract = False
3141
3155
 
3142
3156
 
3143
-
3144
3157
  # ## ENTITY STATE....
3145
3158
  class EntityStateModelAbstract(Model):
3146
3159
  KEY_JOURNAL_ENTRY = 'je'
@@ -3204,7 +3217,6 @@ class EntityStateModel(EntityStateModelAbstract):
3204
3217
  """
3205
3218
 
3206
3219
  class Meta(EntityStateModelAbstract.Meta):
3207
- swappable = 'DJANGO_LEDGER_ENTITY_STATE_MODEL'
3208
3220
  abstract = False
3209
3221
 
3210
3222
 
@@ -1614,5 +1614,4 @@ class EstimateModel(EstimateModelAbstract):
1614
1614
  """
1615
1615
 
1616
1616
  class Meta(EstimateModelAbstract.Meta):
1617
- swappable = 'DJANGO_LEDGER_ESTIMATE_MODEL'
1618
1617
  abstract = False
@@ -1828,7 +1828,6 @@ class InvoiceModel(InvoiceModelAbstract):
1828
1828
  """
1829
1829
 
1830
1830
  class Meta(InvoiceModelAbstract.Meta):
1831
- swappable = 'DJANGO_LEDGER_INVOICE_MODEL'
1832
1831
  abstract = False
1833
1832
 
1834
1833
 
@@ -1411,7 +1411,6 @@ class UnitOfMeasureModel(UnitOfMeasureModelAbstract):
1411
1411
 
1412
1412
  class Meta(UnitOfMeasureModelAbstract.Meta):
1413
1413
  abstract = False
1414
- swappable = 'DJANGO_LEDGER_UNIT_OF_MEASURE_MODEL'
1415
1414
 
1416
1415
 
1417
1416
  class ItemTransactionModel(ItemTransactionModelAbstract):
@@ -1421,7 +1420,6 @@ class ItemTransactionModel(ItemTransactionModelAbstract):
1421
1420
 
1422
1421
  class Meta(ItemTransactionModelAbstract.Meta):
1423
1422
  abstract = False
1424
- swappable = 'DJANGO_LEDGER_ITEM_TRANSACTION_MODEL'
1425
1423
 
1426
1424
 
1427
1425
  class ItemModel(ItemModelAbstract):
@@ -1431,4 +1429,3 @@ class ItemModel(ItemModelAbstract):
1431
1429
 
1432
1430
  class Meta(ItemModelAbstract.Meta):
1433
1431
  abstract = False
1434
- swappable = 'DJANGO_LEDGER_ITEM_MODEL'
@@ -1243,7 +1243,10 @@ class JournalEntryModelAbstract(CreateUpdateMixIn):
1243
1243
  self.activity = None
1244
1244
  else:
1245
1245
  role_list = self.get_txs_roles(txs_qs, exclude_cash_role=True)
1246
- self.activity = self.get_activity_from_roles(role_set=role_list)
1246
+ self.activity = self.get_activity_from_roles(
1247
+ role_set=role_list,
1248
+ raise_exception=raise_exception
1249
+ )
1247
1250
  return self.activity
1248
1251
 
1249
1252
  # todo: add entity_model as parameter on all functions...
@@ -1534,7 +1537,7 @@ class JournalEntryModelAbstract(CreateUpdateMixIn):
1534
1537
 
1535
1538
  if verify:
1536
1539
  txs_qs, is_verified = self.clean(verify=True)
1537
- if self.is_verified() and post_on_verify:
1540
+ if is_verified and post_on_verify:
1538
1541
  # Mark as posted if verification succeeds and posting is requested
1539
1542
  self.mark_as_posted(commit=False, verify=False, force_lock=True, raise_exception=True)
1540
1543
 
@@ -1762,7 +1765,6 @@ class JournalEntryModel(JournalEntryModelAbstract):
1762
1765
  """
1763
1766
 
1764
1767
  class Meta(JournalEntryModelAbstract.Meta):
1765
- swappable = 'DJANGO_LEDGER_JOURNAL_ENTRY_MODEL'
1766
1768
  abstract = False
1767
1769
 
1768
1770
 
@@ -767,7 +767,6 @@ class LedgerModel(LedgerModelAbstract):
767
767
  """
768
768
 
769
769
  class Meta(LedgerModelAbstract.Meta):
770
- swappable = 'DJANGO_LEDGER_LEDGER_MODEL'
771
770
  abstract = False
772
771
 
773
772
 
@@ -1234,7 +1234,6 @@ class PurchaseOrderModel(PurchaseOrderModelAbstract):
1234
1234
  """
1235
1235
 
1236
1236
  class Meta(PurchaseOrderModelAbstract.Meta):
1237
- swappable = 'DJANGO_LEDGER_PURCHASE_ORDER_MODEL'
1238
1237
  abstract = False
1239
1238
 
1240
1239
 
@@ -67,7 +67,7 @@ class TransactionModelQuerySet(QuerySet):
67
67
  Q(journal_entry__ledger__posted=True)
68
68
  )
69
69
 
70
- def for_accounts(self, account_list: List[str or AccountModel]):
70
+ def for_accounts(self, account_list: List[Union[AccountModel, str, UUID]]):
71
71
  """
72
72
  Filters transactions based on the accounts they are associated with.
73
73
 
@@ -82,9 +82,20 @@ class TransactionModelQuerySet(QuerySet):
82
82
  TransactionModelQuerySet
83
83
  A QuerySet filtered for transactions associated with the specified accounts.
84
84
  """
85
- if isinstance(account_list, list) > 0 and isinstance(account_list[0], str):
85
+
86
+ if not isinstance(account_list, list) or not len(account_list) > 0:
87
+ raise TransactionModelValidationError(
88
+ message=_('Account list must be a list of AccountModel, UUID or str objects (codes).')
89
+ )
90
+ if isinstance(account_list[0], str):
86
91
  return self.filter(account__code__in=account_list)
87
- return self.filter(account__in=account_list)
92
+ elif isinstance(account_list[0], UUID):
93
+ return self.filter(account__uuid__in=account_list)
94
+ elif isinstance(account_list[0], AccountModel):
95
+ return self.filter(account__in=account_list)
96
+ raise TransactionModelValidationError(
97
+ message=_('Account list must be a list of AccountModel, UUID or str objects (codes).')
98
+ )
88
99
 
89
100
  def for_roles(self, role_list: Union[str, List[str], Set[str]]):
90
101
  """
@@ -294,6 +305,18 @@ class TransactionModelQuerySet(QuerySet):
294
305
  timestamp=F('journal_entry__timestamp'),
295
306
  )
296
307
 
308
+ def is_cleared(self):
309
+ return self.filter(cleared=True)
310
+
311
+ def not_cleared(self):
312
+ return self.filter(cleared=False)
313
+
314
+ def is_reconciled(self):
315
+ return self.filter(reconciled=True)
316
+
317
+ def not_reconciled(self):
318
+ return self.filter(reconciled=False)
319
+
297
320
 
298
321
  class TransactionModelManager(Manager):
299
322
  """
@@ -317,6 +340,7 @@ class TransactionModelManager(Manager):
317
340
  """
318
341
  qs = TransactionModelQuerySet(self.model, using=self._db)
319
342
  return qs.annotate(
343
+ timestamp=F('journal_entry__timestamp'),
320
344
  _coa_id=F('account__coa_model_id') # Annotates the `coa_model_id` from the related `account`.
321
345
  ).select_related(
322
346
  'journal_entry', # Pre-loads the related Journal Entry.
@@ -510,7 +534,6 @@ class TransactionModel(TransactionModelAbstract):
510
534
 
511
535
  class Meta(TransactionModelAbstract.Meta):
512
536
  abstract = False
513
- swappable = 'DJANGO_LEDGER_TRANSACTION_MODEL'
514
537
 
515
538
 
516
539
  def transactionmodel_presave(instance: TransactionModel, **kwargs):
@@ -245,5 +245,4 @@ class EntityUnitModel(EntityUnitModelAbstract):
245
245
  """
246
246
 
247
247
  class Meta(EntityUnitModelAbstract.Meta):
248
- swappable = 'DJANGO_LEDGER_ENTITY_UNIT_MODEL'
249
248
  abstract = False
@@ -325,5 +325,4 @@ class VendorModel(VendorModelAbstract):
325
325
  """
326
326
 
327
327
  class Meta(VendorModelAbstract.Meta):
328
- swappable = 'DJANGO_LEDGER_VENDOR_MODEL'
329
328
  abstract = False
django_ledger/settings.py CHANGED
@@ -30,27 +30,28 @@ logger.info(f'Django Ledger GraphQL Enabled: {DJANGO_LEDGER_GRAPHQL_SUPPORT_ENAB
30
30
 
31
31
 
32
32
  ## MODEL ABSTRACTS ##
33
- DJANGO_LEDGER_ACCOUNT_MODEL = getattr(settings, 'DJANGO_LEDGER_ACCOUNT_MODEL', 'django_ledger.AccountModel')
34
- DJANGO_LEDGER_CHART_OF_ACCOUNTS_MODEL = getattr(settings, 'DJANGO_LEDGER_ACCOUNT_MODEL', 'django_ledger.ChartOfAccountModel')
35
- DJANGO_LEDGER_TRANSACTION_MODEL = getattr(settings, 'DJANGO_LEDGER_TRANSACTION_MODEL', 'django_ledger.TransactionModel')
36
- DJANGO_LEDGER_JOURNAL_ENTRY_MODEL = getattr(settings, 'DJANGO_LEDGER_JOURNAL_ENTRY_MODEL', 'django_ledger.JournalEntryModel')
37
- DJANGO_LEDGER_LEDGER_MODEL = getattr(settings, 'DJANGO_LEDGER_LEDGER_MODEL', 'django_ledger.LedgerModel')
38
- DJANGO_LEDGER_ENTITY_MODEL = getattr(settings, 'DJANGO_LEDGER_ENTITY_MODEL', 'django_ledger.EntityModel')
39
- DJANGO_LEDGER_ENTITY_STATE_MODEL = getattr(settings, 'DJANGO_LEDGER_ENTITY_STATE_MODEL', 'django_ledger.EntityStateModel')
40
- DJANGO_LEDGER_ENTITY_UNIT_MODEL = getattr(settings, 'DJANGO_LEDGER_ENTITY_UNIT_MODEL', 'django_ledger.EntityUnitModel')
41
- DJANGO_LEDGER_ESTIMATE_MODEL = getattr(settings, 'DJANGO_LEDGER_ESTIMATE_MODEL', 'django_ledger.EstimateModel')
42
- DJANGO_LEDGER_BILL_MODEL = getattr(settings, 'DJANGO_LEDGER_BILL_MODEL', 'django_ledger.BillModel')
43
- DJANGO_LEDGER_INVOICE_MODEL = getattr(settings, 'DJANGO_LEDGER_INVOICE_MODEL', 'django_ledger.InvoiceModel')
44
- DJANGO_LEDGER_PURCHASE_ORDER_MODEL = getattr(settings, 'DJANGO_LEDGER_PURCHASE_ORDER_MODEL', 'django_ledger.PurchaseOrderModel')
45
- DJANGO_LEDGER_CUSTOMER_MODEL = getattr(settings, 'DJANGO_LEDGER_CUSTOMER_MODEL', 'django_ledger.CustomerModel')
46
- DJANGO_LEDGER_VENDOR_MODEL = getattr(settings, 'DJANGO_LEDGER_VENDOR_MODEL', 'django_ledger.VendorModel')
47
- DJANGO_LEDGER_BANK_ACCOUNT_MODEL = getattr(settings, 'DJANGO_LEDGER_BANK_ACCOUNT_MODEL', 'django_ledger.BankAccountModel')
48
- DJANGO_LEDGER_CLOSING_ENTRY_MODEL = getattr(settings, 'DJANGO_LEDGER_CLOSING_ENTRY_MODEL', 'django_ledger.ClosingEntryModel')
49
- DJANGO_LEDGER_UNIT_OF_MEASURE_MODEL = getattr(settings, 'DJANGO_LEDGER_UNIT_OF_MEASURE_MODEL', 'django_ledger.UnitOfMeasureModel')
50
- DJANGO_LEDGER_ITEM_TRANSACTION_MODEL = getattr(settings, 'DJANGO_LEDGER_ITEM_TRANSACTION_MODEL', 'django_ledger.ItemTransactionModel')
51
- DJANGO_LEDGER_ITEM_MODEL = getattr(settings, 'DJANGO_LEDGER_ITEM_MODEL', 'django_ledger.ItemModel')
52
- DJANGO_LEDGER_STAGED_TRANSACTION_MODEL = getattr(settings, 'DJANGO_LEDGER_STAGED_TRANSACTION_MODEL', 'django_ledger.StagedTransactionModel')
53
- DJANGO_LEDGER_IMPORT_JOB_MODEL = getattr(settings, 'DJANGO_LEDGER_IMPORT_JOB_MODEL', 'django_ledger.ImportJobModel')
33
+ # DJANGO_LEDGER_ACCOUNT_MODEL = getattr(settings, 'DJANGO_LEDGER_ACCOUNT_MODEL', 'django_ledger.AccountModel')
34
+ # DJANGO_LEDGER_CHART_OF_ACCOUNTS_MODEL = getattr(settings, 'DJANGO_LEDGER_ACCOUNT_MODEL', 'django_ledger.ChartOfAccountModel')
35
+ # DJANGO_LEDGER_TRANSACTION_MODEL = getattr(settings, 'DJANGO_LEDGER_TRANSACTION_MODEL', 'django_ledger.TransactionModel')
36
+ # DJANGO_LEDGER_JOURNAL_ENTRY_MODEL = getattr(settings, 'DJANGO_LEDGER_JOURNAL_ENTRY_MODEL', 'django_ledger.JournalEntryModel')
37
+ # DJANGO_LEDGER_LEDGER_MODEL = getattr(settings, 'DJANGO_LEDGER_LEDGER_MODEL', 'django_ledger.LedgerModel')
38
+ # DJANGO_LEDGER_ENTITY_MODEL = getattr(settings, 'DJANGO_LEDGER_ENTITY_MODEL', 'django_ledger.EntityModel')
39
+ # DJANGO_LEDGER_ENTITY_STATE_MODEL = getattr(settings, 'DJANGO_LEDGER_ENTITY_STATE_MODEL', 'django_ledger.EntityStateModel')
40
+ # DJANGO_LEDGER_ENTITY_UNIT_MODEL = getattr(settings, 'DJANGO_LEDGER_ENTITY_UNIT_MODEL', 'django_ledger.EntityUnitModel')
41
+ # DJANGO_LEDGER_ESTIMATE_MODEL = getattr(settings, 'DJANGO_LEDGER_ESTIMATE_MODEL', 'django_ledger.EstimateModel')
42
+ # DJANGO_LEDGER_BILL_MODEL = getattr(settings, 'DJANGO_LEDGER_BILL_MODEL', 'django_ledger.BillModel')
43
+ # DJANGO_LEDGER_INVOICE_MODEL = getattr(settings, 'DJANGO_LEDGER_INVOICE_MODEL', 'django_ledger.InvoiceModel')
44
+ # DJANGO_LEDGER_PURCHASE_ORDER_MODEL = getattr(settings, 'DJANGO_LEDGER_PURCHASE_ORDER_MODEL', 'django_ledger.PurchaseOrderModel')
45
+ # DJANGO_LEDGER_CUSTOMER_MODEL = getattr(settings, 'DJANGO_LEDGER_CUSTOMER_MODEL', 'django_ledger.CustomerModel')
46
+ # DJANGO_LEDGER_VENDOR_MODEL = getattr(settings, 'DJANGO_LEDGER_VENDOR_MODEL', 'django_ledger.VendorModel')
47
+ # DJANGO_LEDGER_BANK_ACCOUNT_MODEL = getattr(settings, 'DJANGO_LEDGER_BANK_ACCOUNT_MODEL', 'django_ledger.BankAccountModel')
48
+ # DJANGO_LEDGER_CLOSING_ENTRY_MODEL = getattr(settings, 'DJANGO_LEDGER_CLOSING_ENTRY_MODEL', 'django_ledger.ClosingEntryModel')
49
+ # DJANGO_LEDGER_CLOSING_ENTRY_TRANSACTION_MODEL = getattr(settings, 'DJANGO_LEDGER_CLOSING_ENTRY_TRANSACTION_MODEL', 'django_ledger.ClosingEntryTransactionModel')
50
+ # DJANGO_LEDGER_UNIT_OF_MEASURE_MODEL = getattr(settings, 'DJANGO_LEDGER_UNIT_OF_MEASURE_MODEL', 'django_ledger.UnitOfMeasureModel')
51
+ # DJANGO_LEDGER_ITEM_TRANSACTION_MODEL = getattr(settings, 'DJANGO_LEDGER_ITEM_TRANSACTION_MODEL', 'django_ledger.ItemTransactionModel')
52
+ # DJANGO_LEDGER_ITEM_MODEL = getattr(settings, 'DJANGO_LEDGER_ITEM_MODEL', 'django_ledger.ItemModel')
53
+ # DJANGO_LEDGER_STAGED_TRANSACTION_MODEL = getattr(settings, 'DJANGO_LEDGER_STAGED_TRANSACTION_MODEL', 'django_ledger.StagedTransactionModel')
54
+ # DJANGO_LEDGER_IMPORT_JOB_MODEL = getattr(settings, 'DJANGO_LEDGER_IMPORT_JOB_MODEL', 'django_ledger.ImportJobModel')
54
55
 
55
56
  DJANGO_LEDGER_USE_CLOSING_ENTRIES = getattr(settings, 'DJANGO_LEDGER_USE_CLOSING_ENTRIES', True)
56
57
  DJANGO_LEDGER_DEFAULT_CLOSING_ENTRY_CACHE_TIMEOUT = getattr(settings,
@@ -10,6 +10,10 @@
10
10
  <title>{% block page_title %}{% session_entity_name %} | {{ page_title }}{% endblock %}</title>
11
11
  <script src="{% static 'django_ledger/bundle/styles.bundle.js' %}"></script>
12
12
  <link rel="shortcut icon" type="image/jpg" href="{% static 'django_ledger/logo/favicon.png' %}">
13
+
14
+ {% block header_extra_js %}{% endblock %}
15
+ {% block header_extra_css %}{% endblock %}
16
+
13
17
  </head>
14
18
 
15
19
  <body>
@@ -50,8 +54,9 @@
50
54
  datePickers.forEach(dp => djLedger.getCalendar(dp.attributes.id.value, dateNavigationUrl))
51
55
  {% endif %}
52
56
  </script>
53
-
54
57
  {% endblock %}
55
58
 
59
+ {% block bottom_extra_js %}{% endblock %}
60
+
56
61
  </body>
57
62
  </html>
@@ -14,7 +14,7 @@ urlpatterns = [
14
14
  path('<slug:entity_slug>/list/year/<int:year>/',
15
15
  views.LedgerModelYearListView.as_view(),
16
16
  name='ledger-list-year'),
17
- path('<slug:entity_slug>/list/month/<int:year>/<int:month>',
17
+ path('<slug:entity_slug>/list/month/<int:year>/<int:month>/',
18
18
  views.LedgerModelMonthListView.as_view(),
19
19
  name='ledger-list-month'),
20
20
  path('<slug:entity_slug>/create/',
@@ -8,13 +8,15 @@ Contributions to this module:
8
8
 
9
9
  from django.contrib import messages
10
10
  from django.core.exceptions import ValidationError, ImproperlyConfigured
11
- from django.db.models import Count
12
11
  from django.http import HttpResponseRedirect
13
- from django.shortcuts import get_object_or_404
14
12
  from django.urls import reverse
15
13
  from django.utils.translation import gettext_lazy as _
16
- from django.views.generic import ArchiveIndexView, YearArchiveView, MonthArchiveView, DetailView, \
17
- RedirectView, CreateView, DeleteView, UpdateView
14
+ from django.views.generic import (
15
+ ArchiveIndexView, YearArchiveView,
16
+ MonthArchiveView, DetailView,
17
+ RedirectView, CreateView,
18
+ DeleteView, UpdateView
19
+ )
18
20
  from django.views.generic.detail import SingleObjectMixin
19
21
 
20
22
  from django_ledger.forms.closing_entry import ClosingEntryCreateForm, ClosingEntryUpdateForm
@@ -24,25 +26,21 @@ from django_ledger.models.entity import EntityModel
24
26
  from django_ledger.views import DjangoLedgerSecurityMixIn
25
27
 
26
28
 
27
- class ClosingEntryModelViewQuerySetMixIn:
29
+ class ClosingEntryModelBaseView(DjangoLedgerSecurityMixIn):
28
30
  queryset = None
29
- queryset_annotate_txs_count = False
30
31
 
31
32
  def get_queryset(self):
32
33
  if self.queryset is None:
33
- qs = ClosingEntryModel.objects.for_entity(
34
- entity_slug=self.kwargs['entity_slug'],
35
- user_model=self.request.user
36
- ).select_related('entity_model', 'ledger_model')
37
- if self.queryset_annotate_txs_count:
38
- qs = qs.annotate(ce_txs_count=Count('closingentrytransactionmodel'))
39
- self.queryset = qs
40
- return super().get_queryset()
41
-
42
-
43
- class ClosingEntryModelListView(DjangoLedgerSecurityMixIn,
44
- ClosingEntryModelViewQuerySetMixIn,
45
- ArchiveIndexView):
34
+ entity_model: EntityModel = self.get_authorized_entity_instance()
35
+ closing_entry_model_qs = entity_model.closingentrymodel_set.all().select_related(
36
+ 'entity_model',
37
+ 'ledger_model'
38
+ ).order_by('-closing_date')
39
+ self.queryset = closing_entry_model_qs
40
+ return self.queryset
41
+
42
+
43
+ class ClosingEntryModelListView(ClosingEntryModelBaseView, ArchiveIndexView):
46
44
  template_name = 'django_ledger/closing_entry/closing_entry_list.html'
47
45
  date_field = 'closing_date'
48
46
  allow_future = False
@@ -56,23 +54,21 @@ class ClosingEntryModelListView(DjangoLedgerSecurityMixIn,
56
54
  'header_title': PAGE_TITLE,
57
55
  'header_subtitle_icon': 'file-icons:finaldraft'
58
56
  }
59
- queryset_annotate_txs_count = True
60
57
 
61
58
 
62
- class ClosingEntryModelYearListView(YearArchiveView, ClosingEntryModelListView):
59
+ class ClosingEntryModelYearListView(ClosingEntryModelListView, YearArchiveView):
63
60
  paginate_by = 10
64
61
  make_object_list = True
65
62
 
66
63
 
67
- class ClosingEntryModelMonthListView(MonthArchiveView, ClosingEntryModelListView):
64
+ class ClosingEntryModelMonthListView(ClosingEntryModelListView, MonthArchiveView):
68
65
  paginate_by = 10
69
66
  month_format = '%m'
70
67
  date_list_period = 'year'
71
68
 
72
69
 
73
- class ClosingEntryModelCreateView(DjangoLedgerSecurityMixIn, ClosingEntryModelViewQuerySetMixIn, CreateView):
70
+ class ClosingEntryModelCreateView(ClosingEntryModelBaseView, CreateView):
74
71
  template_name = 'django_ledger/closing_entry/closing_entry_create.html'
75
- form_class = ClosingEntryCreateForm
76
72
  PAGE_TITLE = _('Create Closing Entry')
77
73
  extra_context = {
78
74
  'page_title': PAGE_TITLE,
@@ -85,23 +81,25 @@ class ClosingEntryModelCreateView(DjangoLedgerSecurityMixIn, ClosingEntryModelVi
85
81
  'closing_date': get_localdate()
86
82
  }
87
83
 
88
- def get_object(self, queryset=None):
89
- if not getattr(self, 'object'):
90
- entity_model_qs = EntityModel.objects.for_user(user_model=self.request.user)
91
- entity_model = get_object_or_404(entity_model_qs, slug__exact=self.kwargs['entity_slug'])
92
- self.object = entity_model
93
- return self.object
84
+ def get_form(self, form_class=None, **kwargs):
85
+ return ClosingEntryCreateForm(
86
+ **self.get_form_kwargs()
87
+ )
94
88
 
95
89
  def get_context_data(self, **kwargs):
96
90
  ctx = super().get_context_data(**kwargs)
97
- entity_model = self.get_object()
91
+ entity_model: EntityModel = self.get_authorized_entity_instance()
98
92
  ctx['header_subtitle'] = entity_model.name
99
93
  return ctx
100
94
 
101
95
  def form_valid(self, form):
102
96
  closing_date = form.cleaned_data['closing_date']
103
- entity_model: EntityModel = self.get_object()
104
- ce_model, _ = entity_model.close_entity_books(closing_date=closing_date, force_update=True)
97
+ entity_model: EntityModel = self.get_authorized_entity_instance()
98
+ ce_model, _ = entity_model.close_entity_books(
99
+ closing_date=closing_date,
100
+ force_update=True,
101
+ post_closing_entry=False
102
+ )
105
103
  self.ce_model = ce_model
106
104
  return HttpResponseRedirect(self.get_success_url())
107
105
 
@@ -115,7 +113,7 @@ class ClosingEntryModelCreateView(DjangoLedgerSecurityMixIn, ClosingEntryModelVi
115
113
  )
116
114
 
117
115
 
118
- class ClosingEntryModelDetailView(DjangoLedgerSecurityMixIn, ClosingEntryModelViewQuerySetMixIn, DetailView):
116
+ class ClosingEntryModelDetailView(ClosingEntryModelBaseView, DetailView):
119
117
  template_name = 'django_ledger/closing_entry/closing_entry_detail.html'
120
118
  pk_url_kwarg = 'closing_entry_pk'
121
119
  context_object_name = 'closing_entry_model'
@@ -123,7 +121,6 @@ class ClosingEntryModelDetailView(DjangoLedgerSecurityMixIn, ClosingEntryModelVi
123
121
  'header_title': 'Closing Entry Detail',
124
122
  'header_subtitle_icon': 'file-icons:finaldraft'
125
123
  }
126
- queryset_annotate_txs_count = True
127
124
 
128
125
  def get_context_data(self, **kwargs):
129
126
  ctx = super().get_context_data(**kwargs)
@@ -135,12 +132,11 @@ class ClosingEntryModelDetailView(DjangoLedgerSecurityMixIn, ClosingEntryModelVi
135
132
  return ctx
136
133
 
137
134
 
138
- class ClosingEntryModelUpdateView(DjangoLedgerSecurityMixIn, ClosingEntryModelViewQuerySetMixIn, UpdateView):
135
+ class ClosingEntryModelUpdateView(ClosingEntryModelBaseView, UpdateView):
139
136
  template_name = 'django_ledger/closing_entry/closing_entry_update.html'
140
137
  pk_url_kwarg = 'closing_entry_pk'
141
138
  form_class = ClosingEntryUpdateForm
142
139
  context_object_name = 'closing_entry_model'
143
- queryset_annotate_txs_count = True
144
140
  extra_context = {
145
141
  'header_title': 'Closing Entry Detail',
146
142
  'header_subtitle_icon': 'file-icons:finaldraft'
@@ -165,10 +161,22 @@ class ClosingEntryModelUpdateView(DjangoLedgerSecurityMixIn, ClosingEntryModelVi
165
161
  )
166
162
 
167
163
 
168
- class ClosingEntryDeleteView(DjangoLedgerSecurityMixIn, ClosingEntryModelViewQuerySetMixIn, DeleteView):
164
+ class ClosingEntryDeleteView(ClosingEntryModelBaseView, DeleteView):
169
165
  template_name = 'django_ledger/closing_entry/closing_entry_delete.html'
170
166
  pk_url_kwarg = 'closing_entry_pk'
171
167
  context_object_name = 'closing_entry'
168
+ extra_context = {
169
+ 'header_title': _('Delete Closing Entry'),
170
+ 'header_subtitle_icon': 'file-icons:finaldraft'
171
+ }
172
+
173
+ def get_context_data(self, **kwargs):
174
+ context = super().get_context_data(**kwargs)
175
+ closing_entry_model: ClosingEntryModel = self.object
176
+ entity_model: EntityModel = self.get_authorized_entity_instance()
177
+ context['page_title'] = 'Delete Closing Entry {}'.format(closing_entry_model.closing_date)
178
+ context['header_subtitle'] = entity_model.name
179
+ return context
172
180
 
173
181
  def get_success_url(self):
174
182
  return reverse(viewname='django_ledger:closing-entry-list',
@@ -177,9 +185,8 @@ class ClosingEntryDeleteView(DjangoLedgerSecurityMixIn, ClosingEntryModelViewQue
177
185
  })
178
186
 
179
187
 
180
- class ClosingEntryModelActionView(DjangoLedgerSecurityMixIn,
188
+ class ClosingEntryModelActionView(ClosingEntryModelBaseView,
181
189
  RedirectView,
182
- ClosingEntryModelViewQuerySetMixIn,
183
190
  SingleObjectMixin):
184
191
  http_method_names = ['get']
185
192
  pk_url_kwarg = 'closing_entry_pk'
@@ -361,6 +361,12 @@ class DjangoLedgerSecurityMixIn(LoginRequiredMixin, PermissionRequiredMixin):
361
361
  return
362
362
  return self.AUTHORIZED_ENTITY_MODEL
363
363
 
364
+ def get_authorized_entity_instance_name(self) -> Optional[str]:
365
+ entity_model: EntityModel = self.get_authorized_entity_instance()
366
+ if not entity_model:
367
+ return None
368
+ return entity_model.name
369
+
364
370
 
365
371
  class EntityUnitMixIn:
366
372
  UNIT_SLUG_KWARG = 'unit_slug'
@@ -22,7 +22,7 @@ from django_ledger.views.mixins import (DjangoLedgerSecurityMixIn, QuarterlyRepo
22
22
  PDFReportMixIn)
23
23
 
24
24
 
25
- class EntityUnitModelModelViewQuerySetMixIn:
25
+ class EntityUnitModelModelBaseView(DjangoLedgerSecurityMixIn):
26
26
  queryset = None
27
27
 
28
28
  def get_queryset(self):
@@ -34,7 +34,7 @@ class EntityUnitModelModelViewQuerySetMixIn:
34
34
  return super().get_queryset()
35
35
 
36
36
 
37
- class EntityUnitModelListView(DjangoLedgerSecurityMixIn, EntityUnitModelModelViewQuerySetMixIn, ListView):
37
+ class EntityUnitModelListView(EntityUnitModelModelBaseView, ListView):
38
38
  template_name = 'django_ledger/unit/unit_list.html'
39
39
  PAGE_TITLE = _('Entity Unit List')
40
40
  extra_context = {
@@ -45,7 +45,7 @@ class EntityUnitModelListView(DjangoLedgerSecurityMixIn, EntityUnitModelModelVie
45
45
  context_object_name = 'unit_list'
46
46
 
47
47
 
48
- class EntityUnitModelDetailView(DjangoLedgerSecurityMixIn, EntityUnitModelModelViewQuerySetMixIn, DetailView):
48
+ class EntityUnitModelDetailView(EntityUnitModelModelBaseView, DetailView):
49
49
  template_name = 'django_ledger/unit/unit_detail.html'
50
50
  PAGE_TITLE = _('Entity Unit Detail')
51
51
  slug_url_kwarg = 'unit_slug'
@@ -57,7 +57,7 @@ class EntityUnitModelDetailView(DjangoLedgerSecurityMixIn, EntityUnitModelModelV
57
57
  context_object_name = 'unit'
58
58
 
59
59
 
60
- class EntityUnitModelCreateView(DjangoLedgerSecurityMixIn, EntityUnitModelModelViewQuerySetMixIn, CreateView):
60
+ class EntityUnitModelCreateView(EntityUnitModelModelBaseView, CreateView):
61
61
  template_name = 'django_ledger/unit/unit_create.html'
62
62
  PAGE_TITLE = _('Entity Unit Create')
63
63
  extra_context = {
@@ -88,7 +88,7 @@ class EntityUnitModelCreateView(DjangoLedgerSecurityMixIn, EntityUnitModelModelV
88
88
  return HttpResponseRedirect(self.get_success_url())
89
89
 
90
90
 
91
- class EntityUnitUpdateView(DjangoLedgerSecurityMixIn, EntityUnitModelModelViewQuerySetMixIn, UpdateView):
91
+ class EntityUnitUpdateView(EntityUnitModelModelBaseView, UpdateView):
92
92
  template_name = 'django_ledger/unit/unit_update.html'
93
93
  PAGE_TITLE = _('Entity Unit Update')
94
94
  slug_url_kwarg = 'unit_slug'
@@ -123,7 +123,7 @@ class EntityUnitUpdateView(DjangoLedgerSecurityMixIn, EntityUnitModelModelViewQu
123
123
 
124
124
 
125
125
  # BALANCE SHEET.....
126
- class BaseEntityUnitModelBalanceSheetView(DjangoLedgerSecurityMixIn, RedirectView):
126
+ class BaseEntityUnitModelBalanceSheetView(EntityUnitModelModelBaseView, RedirectView):
127
127
 
128
128
  def get_redirect_url(self, *args, **kwargs):
129
129
  year = get_localdate().year
@@ -135,8 +135,7 @@ class BaseEntityUnitModelBalanceSheetView(DjangoLedgerSecurityMixIn, RedirectVie
135
135
  })
136
136
 
137
137
 
138
- class FiscalYearEntityUnitModelBalanceSheetView(DjangoLedgerSecurityMixIn,
139
- EntityUnitModelModelViewQuerySetMixIn,
138
+ class FiscalYearEntityUnitModelBalanceSheetView(EntityUnitModelModelBaseView,
140
139
  BaseDateNavigationUrlMixIn,
141
140
  EntityUnitMixIn,
142
141
  YearlyReportMixIn,
@@ -176,7 +175,7 @@ class DateEntityUnitModelBalanceSheetView(MonthlyEntityUnitModelBalanceSheetView
176
175
 
177
176
 
178
177
  # INCOME STATEMENT....
179
- class BaseEntityUnitModelIncomeStatementView(DjangoLedgerSecurityMixIn, RedirectView):
178
+ class BaseEntityUnitModelIncomeStatementView(EntityUnitModelModelBaseView, RedirectView):
180
179
 
181
180
  def get_redirect_url(self, *args, **kwargs):
182
181
  year = get_localdate().year
@@ -188,8 +187,7 @@ class BaseEntityUnitModelIncomeStatementView(DjangoLedgerSecurityMixIn, Redirect
188
187
  })
189
188
 
190
189
 
191
- class FiscalYearEntityUnitModelIncomeStatementView(DjangoLedgerSecurityMixIn,
192
- EntityUnitModelModelViewQuerySetMixIn,
190
+ class FiscalYearEntityUnitModelIncomeStatementView(EntityUnitModelModelBaseView,
193
191
  BaseDateNavigationUrlMixIn,
194
192
  EntityUnitMixIn,
195
193
  YearlyReportMixIn,
@@ -225,7 +223,7 @@ class DateIncomeStatementView(FiscalYearIncomeStatementView, DateReportMixIn):
225
223
 
226
224
 
227
225
  # CASHFLOW STATEMENT
228
- class BaseEntityUnitModelCashFlowStatementView(DjangoLedgerSecurityMixIn, RedirectView):
226
+ class BaseEntityUnitModelCashFlowStatementView(EntityUnitModelModelBaseView, RedirectView):
229
227
 
230
228
  def get_redirect_url(self, *args, **kwargs):
231
229
  year = get_localdate().year
@@ -237,8 +235,7 @@ class BaseEntityUnitModelCashFlowStatementView(DjangoLedgerSecurityMixIn, Redire
237
235
  })
238
236
 
239
237
 
240
- class FiscalYearEntityUnitModelCashFlowStatementView(DjangoLedgerSecurityMixIn,
241
- EntityUnitModelModelViewQuerySetMixIn,
238
+ class FiscalYearEntityUnitModelCashFlowStatementView(EntityUnitModelModelBaseView,
242
239
  BaseDateNavigationUrlMixIn,
243
240
  EntityUnitMixIn,
244
241
  YearlyReportMixIn,
@@ -16,7 +16,7 @@ from django_ledger.models.vendor import VendorModel
16
16
  from django_ledger.views.mixins import DjangoLedgerSecurityMixIn
17
17
 
18
18
 
19
- class VendorModelModelViewQuerySetMixIn:
19
+ class VendorModelModelBaseView(DjangoLedgerSecurityMixIn):
20
20
  queryset = None
21
21
 
22
22
  def get_queryset(self):
@@ -28,7 +28,7 @@ class VendorModelModelViewQuerySetMixIn:
28
28
  return super().get_queryset()
29
29
 
30
30
 
31
- class VendorModelListView(DjangoLedgerSecurityMixIn, VendorModelModelViewQuerySetMixIn, ListView):
31
+ class VendorModelListView(VendorModelModelBaseView, ListView):
32
32
  template_name = 'django_ledger/vendor/vendor_list.html'
33
33
  context_object_name = 'vendors'
34
34
  PAGE_TITLE = _('Vendor List')
@@ -38,8 +38,14 @@ class VendorModelListView(DjangoLedgerSecurityMixIn, VendorModelModelViewQuerySe
38
38
  'header_subtitle_icon': 'bi:person-lines-fill'
39
39
  }
40
40
 
41
+ def get_context_data(self, **kwargs):
42
+ context = super().get_context_data(**kwargs)
43
+ entity_model: EntityModel = self.get_authorized_entity_instance()
44
+ context['header_subtitle'] = entity_model.name
45
+ return context
46
+
41
47
 
42
- class VendorModelCreateView(DjangoLedgerSecurityMixIn, VendorModelModelViewQuerySetMixIn, CreateView):
48
+ class VendorModelCreateView(VendorModelModelBaseView, CreateView):
43
49
  template_name = 'django_ledger/vendor/vendor_create.html'
44
50
  PAGE_TITLE = _('Create New Vendor')
45
51
  form_class = VendorModelForm
@@ -66,7 +72,7 @@ class VendorModelCreateView(DjangoLedgerSecurityMixIn, VendorModelModelViewQuery
66
72
  return super().form_valid(form)
67
73
 
68
74
 
69
- class VendorModelUpdateView(DjangoLedgerSecurityMixIn, VendorModelModelViewQuerySetMixIn, UpdateView):
75
+ class VendorModelUpdateView(VendorModelModelBaseView, UpdateView):
70
76
  template_name = 'django_ledger/vendor/vendor_update.html'
71
77
  PAGE_TITLE = _('Vendor Update')
72
78
  context_object_name = 'vendor'
@@ -89,7 +95,3 @@ class VendorModelUpdateView(DjangoLedgerSecurityMixIn, VendorModelModelViewQuery
89
95
  kwargs={
90
96
  'entity_slug': self.kwargs['entity_slug']
91
97
  })
92
-
93
- def form_valid(self, form):
94
- form.save()
95
- return super().form_valid(form)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: django-ledger
3
- Version: 0.7.5.2
3
+ Version: 0.7.6
4
4
  Summary: Double entry accounting system built on the Django Web Framework.
5
5
  Author-email: Miguel Sanda <msanda@arrobalytics.com>
6
6
  Maintainer-email: Miguel Sanda <msanda@arrobalytics.com>
@@ -48,6 +48,8 @@ Requires-Dist: furo; extra == "dev"
48
48
  Django Ledger is a powerful financial management system built on the Django Web Framework. It offers a simplified API
49
49
  for handling complex accounting tasks in financially driven applications.
50
50
 
51
+ Created and developed by [Miguel Sanda](https://www.miguelsanda.com).
52
+
51
53
  [FREE Get Started Guide](https://www.djangoledger.com/get-started) | [Join our Discord](https://discord.gg/c7PZcbYgrc) | [Documentation](https://django-ledger.readthedocs.io/en/latest/) | [QuickStart Notebook](https://github.com/arrobalytics/django-ledger/blob/develop/notebooks/QuickStart%20Notebook.ipynb)
52
54
 
53
55
  ## Key Features
@@ -1,7 +1,7 @@
1
- django_ledger/__init__.py,sha256=fj4DntGD1AocFAxeIBUZQeKEd2qzpUr65BwMehYhIUU,382
1
+ django_ledger/__init__.py,sha256=aTfSdt9Ut8YUTePLahpvV0ij_nGgDNYOiYRiVXkSpNU,380
2
2
  django_ledger/apps.py,sha256=H-zEWUjKGakgSDSZmLIoXChZ2h6e0dth0ZO5SpoT-8U,163
3
3
  django_ledger/exceptions.py,sha256=rML8sQQ0Hq-DYMLZ76dfw2RYSAsXWUoyHuyC_yP9o1o,491
4
- django_ledger/settings.py,sha256=S5AwPEk8JvKMtU230VfP3q8tv6hxzgPd1FDGRD5zYpY,8747
4
+ django_ledger/settings.py,sha256=QOMK8mhT8MLrMxVDEzNRJ9W01Pm-Po26y7KaBPLVeNk,8952
5
5
  django_ledger/utils.py,sha256=eGEdrDRrnILIsk69FVN9pjX1VoDVc1nx_MfVAwiY5dg,3519
6
6
  django_ledger/admin/__init__.py,sha256=-1h4Qg9dfRq9g-EoDZAq96L8lcOoGlwJXNBsbqVIY7U,472
7
7
  django_ledger/admin/chart_of_accounts.py,sha256=tRQXsa5oi9behZc_A_aMsbDoT_wzxR2EvEF-aUuV0H8,3539
@@ -49,7 +49,7 @@ django_ledger/forms/auth.py,sha256=HaJDEIRFoAHEAv-s_ZfTe0rZbhzIQ7GkKnaBX1qiAW4,7
49
49
  django_ledger/forms/bank_account.py,sha256=Ir6eQk4PSL7dii4mYGM895u6twrgvPm8vn3FCozSg8Q,4828
50
50
  django_ledger/forms/bill.py,sha256=vJbLZhHpolhzM0WKZdSAcuBnQAXDGGeKmY3RrswB-ZM,10813
51
51
  django_ledger/forms/chart_of_accounts.py,sha256=wymLQ8iLNPU_LgS79BOdMUapuLqoTvgqVdAyL1Pw0Ro,2414
52
- django_ledger/forms/closing_entry.py,sha256=AwEEhphjQ-D4pQ6lRk2zGSmMSMkoamIVICnUY8rgqKU,1494
52
+ django_ledger/forms/closing_entry.py,sha256=ARKHmwf8n2vLMpLTTven9xuwVBQ7aMBcIUMnnWkbUdw,1526
53
53
  django_ledger/forms/customer.py,sha256=GrpREV8c3UsNhg5KzwNsofnuW5uv25Ue-Aa-pJeyXUc,2501
54
54
  django_ledger/forms/data_import.py,sha256=AMb8C867KZ6qxTHtGkpexj7VY1yehPJX0DE0-4pFIcA,6930
55
55
  django_ledger/forms/entity.py,sha256=b0QirmsFSnaM8YWDO4V6GQXfFgR_MLmdq27I2q2sGQ0,6880
@@ -57,7 +57,7 @@ django_ledger/forms/estimate.py,sha256=0A30F4mosT4uvIde61lAWbPV4JePUQIX87VAcTtby
57
57
  django_ledger/forms/feedback.py,sha256=WUT-kI4uT6q5aqEYaDYwyIFfhXpmtwMv6qf9BFSYsDo,1850
58
58
  django_ledger/forms/invoice.py,sha256=Y7m5DxlNYsjBoZKWb99SFquwIW_tbVuLkJBgqSZmt1g,9675
59
59
  django_ledger/forms/item.py,sha256=i2pMhneb27a2HyQ9I48dYeHdSd1cgsZsjWYWDjGJ5UQ,12457
60
- django_ledger/forms/journal_entry.py,sha256=JQj7QTj6_fhpeGI2eXeitsSZWvm49h8uvlx52Ir4AjM,3227
60
+ django_ledger/forms/journal_entry.py,sha256=DmL_5_akNm7Da4mAFeodg4wEx8hS9MSb9XoEGdkFyNE,3269
61
61
  django_ledger/forms/ledger.py,sha256=jz2Ipdj-6hDBGeU4X0rodFT0yPQcFwTQ0EeUqDpKC6g,1739
62
62
  django_ledger/forms/purchase_order.py,sha256=XIi7v6ZaBd9nYgcWLmgNKm9751XBXpbwmUtlpPJklHI,7479
63
63
  django_ledger/forms/transactions.py,sha256=ockQjKihNY07m9NWL9nJtHBQMzROaQQO18QZSuiFn8s,3210
@@ -65,8 +65,8 @@ django_ledger/forms/unit.py,sha256=rXUefjpuAmUU0vPOqu1ObO4k-bN-_Q6kOqHJ4kp_Vlg,1
65
65
  django_ledger/forms/utils.py,sha256=sgkwBZs15_rZ5NT7h-8Z7wi3-ItM1E1sqoVDo3NQ5Jc,513
66
66
  django_ledger/forms/vendor.py,sha256=Nuh8MmSpz4ycMZwiVe--U9Ec6ezIsfACHDkhA2SyiZ4,2215
67
67
  django_ledger/io/__init__.py,sha256=8m5AoBRiG2ymrX0Y4LVjq0275i7I5Sk7YRa1BTzVofI,369
68
- django_ledger/io/io_context.py,sha256=xgykRoB6hVSN2q20f62j_4zbOeAHU5ZgbZaSwRaSkOU,4444
69
- django_ledger/io/io_core.py,sha256=hsvRnkfP2gC19easYu8U_lbphcko75uATYcYgDdqgS4,86073
68
+ django_ledger/io/io_context.py,sha256=2AiQyJSTkYUCu09Ig0ZPgYj8PtlvUKNS30KvRp9e7zA,4753
69
+ django_ledger/io/io_core.py,sha256=qG6ZDbdJw5OzADNR37zeLbhG7wAKWLpRBDfSkm0hv6k,87133
70
70
  django_ledger/io/io_generator.py,sha256=IN_ZuMlPHXgoEffxA7PMN2fyTvWPJktzVR6yIaocsRs,34725
71
71
  django_ledger/io/io_library.py,sha256=CGZABR4P80VfIube4QEryNOi01llrPq0Gh-8vVbtZDY,22496
72
72
  django_ledger/io/io_middleware.py,sha256=vbWIBYA4V9nwoiEtB0W9pq19QIwPmaAyVJlo_1Gg2BY,20284
@@ -99,27 +99,27 @@ django_ledger/migrations/0020_remove_bankaccountmodel_django_ledg_cash_ac_59a8af
99
99
  django_ledger/migrations/0021_alter_bankaccountmodel_account_model_and_more.py,sha256=b3eJA_QzNzvx7BPSaj2RCPIbsrCkZrpkvk_qN7v-4OA,1101
100
100
  django_ledger/migrations/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
101
101
  django_ledger/models/__init__.py,sha256=OesBx4My9GnqU1xB5WXuuGLOnmzgxEJxI-WWxRxi658,807
102
- django_ledger/models/accounts.py,sha256=PR0s0oJntnhFaJsiUuKY50NJWyXaAXu1WgTCso1oovI,34969
103
- django_ledger/models/bank_account.py,sha256=62WSTc2Oiftbny-pSKNOsF767WOjYbW00YmTLDK7MZQ,7832
104
- django_ledger/models/bill.py,sha256=iMdON5tLOcolkm2c9XTJzXGWqqxyLZOYB2MkPd__9EY,65047
105
- django_ledger/models/chart_of_accounts.py,sha256=t7E4rHToyeM2IV5JSQJBYE0FkDFG_zzuzhyUrxorT8Q,30368
106
- django_ledger/models/closing_entry.py,sha256=b0EwuYFdGH1GbwWdT_rtQqHSQO8Je62BUJHQLNmeJ8w,17914
102
+ django_ledger/models/accounts.py,sha256=O4BYLGiTduA1fnKFVCo6_URVeQiXmTu2fAngchxBd6Y,36560
103
+ django_ledger/models/bank_account.py,sha256=S0bhQ4MIakdraFTvxy_7Y8mmd9GN2Trg43UsfInhcQs,7777
104
+ django_ledger/models/bill.py,sha256=LCuYvyOtkZ6H-tcV4AYN1GFe_C6s__QxEbR0IcfTak8,65000
105
+ django_ledger/models/chart_of_accounts.py,sha256=cMHAc0TQdYD1iMan9qbrq2FX3NlmPYI_g1qwXPa4sSU,30308
106
+ django_ledger/models/closing_entry.py,sha256=ILFNwxvCNvlEKuK2AL8z49izEBtfco-IT_oXcCMcbP8,18294
107
107
  django_ledger/models/coa_default.py,sha256=CK4vOZ73QePciZUL93wigDXpxKamdXAKBaQR7r-G7tk,27482
108
- django_ledger/models/customer.py,sha256=YX7IQYa_6hx5GobDLxq30aPsscXdEA0kMthM_YPC9Jw,11387
109
- django_ledger/models/data_import.py,sha256=lD2qRgvj8T0a-ONUHHqx8wuObKvtB7jc07csQPIwZAc,47688
110
- django_ledger/models/entity.py,sha256=y4pbPM6c0-AzdNJ_jxP-GrvufeWcPPDDNvYW9qGV1bM,124425
111
- django_ledger/models/estimate.py,sha256=EPkGMJwn3bkyYYeVHOfyLeWqtlJIyjF8fUc36dLz_18,58107
112
- django_ledger/models/invoice.py,sha256=me_3JunnYYQYNhaPeytK9Ts4fgwBPj6vU-w7V3xV0RM,63272
113
- django_ledger/models/items.py,sha256=-l_ibAiJTu4dO7TZUdGD4sq524Ew8oIwhq_hiHVUDeY,55251
114
- django_ledger/models/journal_entry.py,sha256=XLht0Q6irj-aObcJRawSgBmUg77MdgR4PZlogOCvI5c,66941
115
- django_ledger/models/ledger.py,sha256=3C_q3xj06XtZyHDEo4BwMFHyTeMfPeRFXqodyxkG9KA,26315
108
+ django_ledger/models/customer.py,sha256=2v6E1Ri9v3yBPMS8wpnqbEdDeLD897DEfR6vSDf2lVY,11336
109
+ django_ledger/models/data_import.py,sha256=uD2rdmguH6L8gTSltImFRZZ3vrBrmCEG-EWWdSJB0k8,47574
110
+ django_ledger/models/entity.py,sha256=mC7SprHV9zJkMYbvU_rC9NcER_6xFQF-g-j8svz1Lwg,124708
111
+ django_ledger/models/estimate.py,sha256=t3ZSBHZUUOdWP6eMCyQwNgvNSY4myKbkdfaFd9zlpH0,58056
112
+ django_ledger/models/invoice.py,sha256=l1yI-kpePNNSp0MfwGeccdPLAmTmvVV4CquNIxMrmc4,63222
113
+ django_ledger/models/items.py,sha256=cGv681aocJJxXSbsz9NlLhPp7kJ-gQrtxl7EcsiwULg,55087
114
+ django_ledger/models/journal_entry.py,sha256=Hqfz7oNUBXt1Vprd5W1adrFmZzCebemc2cvQZTlKVrk,66993
115
+ django_ledger/models/ledger.py,sha256=ltWmPIzauwxODO-FSupphIOkJYPDGT47-xKOst5DEvQ,26266
116
116
  django_ledger/models/mixins.py,sha256=NKBbtARYi9Z3sWuZajYNQB7Tsx4VEAN5cL-VaVZgoAU,52575
117
- django_ledger/models/purchase_order.py,sha256=YFbtRGO0FW4nOnKy2OAQoI6pdA-kt3IhqjpyxKxNvwg,44197
117
+ django_ledger/models/purchase_order.py,sha256=A0fKA1lU12CYePb43T--wSNqf_d6Vwap1deyNXUoFEg,44140
118
118
  django_ledger/models/signals.py,sha256=3cm_8--Jz-Jb0fPgrVmm5xx_jKFARV6_A29VDjqHeIw,1563
119
- django_ledger/models/transactions.py,sha256=P8i6ngy5Ywb6E73lPxOSpkaC4hCzLo-gEvQzL64g0Es,23214
120
- django_ledger/models/unit.py,sha256=QbQYXqq5KxddzkOausWVyxgtBeXkU3ebYIDnI-YH4FY,8429
119
+ django_ledger/models/transactions.py,sha256=b_ChD6FG-ru7FgT7c9D_1ku1YyhCz840wSrnyVQN6AU,24045
120
+ django_ledger/models/unit.py,sha256=cHybPxSI3PUr6aSRQZSFUEyj8e-rAdhyafekNOkYoew,8375
121
121
  django_ledger/models/utils.py,sha256=Weta2Cwsn4wRqvxMecIuD7aHYiiXBwUeMqpUDK4CokE,8360
122
- django_ledger/models/vendor.py,sha256=TyQdiH9GHQlGQleyKh1IOZyvroC31BOG92qiJbMotlw,11371
122
+ django_ledger/models/vendor.py,sha256=ha_sTc9BHY7RKk70n50eZ-EvqbKHbDObyf0_khhLWN8,11322
123
123
  django_ledger/models/schemas/__init__.py,sha256=8Tvw33tVJtCvxoXje2lrs9C1bsP_iuGcVi1JqzdPUao,157
124
124
  django_ledger/models/schemas/digest.py,sha256=ME_dJ4g2p3dQ97Skh_RTZMwuNLmwTi19BdLM1G6tyAo,1077
125
125
  django_ledger/models/schemas/net_payable.py,sha256=2FcfLaaJySjZ3Yk_IMu8SxYWNO_sngEtbuFCXInrQUU,958
@@ -130,8 +130,6 @@ django_ledger/report/balance_sheet.py,sha256=iw8VOcJfJJHcKwFmdR9p2uYj5iKyX6avUjV
130
130
  django_ledger/report/cash_flow_statement.py,sha256=61HlJHu-WguG-aR4dTZ8fs8kNDcPCLdEy1hfK1WLJp8,8718
131
131
  django_ledger/report/core.py,sha256=MSWOHvYrAfAJJtm1_vXv7vZxgAja6ycKxknoaIvJT_g,7436
132
132
  django_ledger/report/income_statement.py,sha256=m4pG0Yjpl7SELx3-yYKT4dCluKt6nT2bkD9gay9tNKI,11156
133
- django_ledger/static/.DS_Store,sha256=ohv3-BA3m5CUHedTAFiR2MLIeBhMNEz_a0LMOFhljzc,6148
134
- django_ledger/static/django_ledger/.DS_Store,sha256=EDcdC71oJjK355v2FDhienPd1ek36-Zl8YjoiTltcpk,8196
135
133
  django_ledger/static/django_ledger/bundle/djetler.bundle.js,sha256=kTHqgMK1QbX-Yc192tyLANsuRjSH_94aDNz5EahGU0s,585360
136
134
  django_ledger/static/django_ledger/bundle/styles.bundle.js,sha256=qlpwKrCVyhi5mcS5dZ36AZLORSis9sgXzRZJRFTWzMg,769929
137
135
  django_ledger/static/django_ledger/img/daniel-weiss-aj2Os9mYgJU-unsplash.jpg,sha256=zYNOMM56QE4AdRkvdGRNifDqj4OJcUA49oebJqsRjuQ,276317
@@ -154,7 +152,6 @@ django_ledger/static/django_ledger/logo/django-ledger-text@2x.png,sha256=QJVyPER
154
152
  django_ledger/static/django_ledger/logo/django-ledger-text@3x.png,sha256=ddWSMY9dXrAMPTS3LZ6K4sDVvJpYFW4KrVUTqJKU-wg,67707
155
153
  django_ledger/static/django_ledger/logo/django-ledger-text@4x.png,sha256=d5hPUkvmJS_5LXPGgJ5VhcI_2CeteVsiNABv1Q2R6aw,99253
156
154
  django_ledger/static/django_ledger/logo/favicon.png,sha256=7QIRzizQUig3PHi9zyV1tK8kXid410_mmin-WZ3zY4M,6434
157
- django_ledger/static/django_ledger/logo_2/.DS_Store,sha256=c7XYmqnuWTT7tJYaMqpBJGL2BAD8sqK0RwupHKEu__g,6148
158
155
  django_ledger/static/django_ledger/logo_2/django_ledger_logo_dark.png,sha256=NtTFrUKckyevB2rIcDqAdqKdaO8QOADf9YoU9BBm-Ao,12705
159
156
  django_ledger/static/django_ledger/logo_2/django_ledger_logo_dark@0.5x.png,sha256=HOt8mW4FHF4eEH3LD9YvPs7gpFZn4XC5SKYLB0XSCGs,5873
160
157
  django_ledger/static/django_ledger/logo_2/django_ledger_logo_dark@2x.png,sha256=exEY0ViG9EeXxy2V7PGvPOnlaEzMGsMRu4sZnPXhsgE,27393
@@ -303,7 +300,7 @@ django_ledger/templates/django_ledger/journal_entry/je_update.html,sha256=XXxhA3
303
300
  django_ledger/templates/django_ledger/journal_entry/includes/card_journal_entry.html,sha256=PU-tOMBuQcwxP73uXyNePaCF8aY0KutWuuAdYUWJofw,2547
304
301
  django_ledger/templates/django_ledger/journal_entry/tags/je_table.html,sha256=IQyHXHA3goBjdGM0Hzih46Z82JVhMGPpCRgMVCNGmaA,5747
305
302
  django_ledger/templates/django_ledger/journal_entry/tags/je_txs_table.html,sha256=6gqASIlyKmeTgV-0Lp_DVB7SGLcL1y_U8cpR4sJFLyU,3366
306
- django_ledger/templates/django_ledger/layouts/base.html,sha256=SaqRxA4MvJZTOkM94gJvJVAY5KF0zwGFcQChLHmaZFM,1773
303
+ django_ledger/templates/django_ledger/layouts/base.html,sha256=_M49Ivw6TKU4dFjESTBd7vcc1kqXLWbDgcBnHUy_5Z4,1910
307
304
  django_ledger/templates/django_ledger/layouts/content_layout_1.html,sha256=U-32AnGwhIOGHtSTlSst580OwrUBIoDIt93_xZRtOTw,936
308
305
  django_ledger/templates/django_ledger/layouts/content_layout_2.html,sha256=gqXgaGj3ByTI7EziEw0Wo-XBPZEB82selzrXDuCNz_Y,355
309
306
  django_ledger/templates/django_ledger/ledger/ledger_create.html,sha256=eyfmLniuAVMUo12HWdMrq0YP3DfP1aCz6M2QZm8fuYc,896
@@ -381,7 +378,7 @@ django_ledger/urls/inventory.py,sha256=n7d4lX_8thDikWbQIGE4gyZIrjpSY1kVO0qYpjLBr
381
378
  django_ledger/urls/invoice.py,sha256=Yf11g0Up_8uaosfyi1w0oc1YWEJSPk8Jo3HDldcE2KU,2999
382
379
  django_ledger/urls/item.py,sha256=PZxdnaUMCegk17b7eSwKpd9k74apHFbzz12KRdp1ryo,2609
383
380
  django_ledger/urls/journal_entry.py,sha256=sKuYtKDSaAVcW--iIe8GQecuVZ7wF6W3vOtgATUIr0c,2094
384
- django_ledger/urls/ledger.py,sha256=9OD7jvR3D3F6KY9RU-Hj6asvH4OiapQzvwaG3IS7haY,2801
381
+ django_ledger/urls/ledger.py,sha256=4Np3M0OuVdyoNRKVMqYIEA6MmwdlJSQp0vrnqYCWSZM,2802
385
382
  django_ledger/urls/purchase_order.py,sha256=iUNdzy8dcxkkmDAOt2fO4Up3e0pHDqZNSf9JOKbO4Wo,2388
386
383
  django_ledger/urls/transactions.py,sha256=e_x_z5qbkR6i7o8OWWdXshDiY_WVmu9WVhR9A96fnhI,80
387
384
  django_ledger/urls/unit.py,sha256=QEVKrgcw2dqMaaXsUHfqYecTa5-iaPlS9smrYJ1QsgM,1506
@@ -392,7 +389,7 @@ django_ledger/views/auth.py,sha256=I8Mv_aAfW-8Z5VYPOX7P3IUO4Fp5jJPkSuu1ZSVpWtI,7
392
389
  django_ledger/views/bank_account.py,sha256=MbiVurJTNK-UsDPn17-ai4G8sE3qIMrdmXaWPX-J8n8,5025
393
390
  django_ledger/views/bill.py,sha256=5tNb3pyh8GQM4hjV0FXqCXrEQF2LwpEWLkOkpknEdjA,22239
394
391
  django_ledger/views/chart_of_accounts.py,sha256=wMdnXRNWzdPgxl1YeHbdAQXbCBU2VkmxVxxtUuk9NAQ,5485
395
- django_ledger/views/closing_entry.py,sha256=_6y-0QjNPYBD-E3KlFXi8SavDtBXA9K2qgBa_EL6VbA,8316
392
+ django_ledger/views/closing_entry.py,sha256=SbJMyBVG8KTfZ6oo4Gdzx03utKY5CoC7qioU_dm9n5I,8157
396
393
  django_ledger/views/customer.py,sha256=FYnwhRx6JXE4bsjXQqFp8b9H8a4m7zv6ohoSj1OkZD8,3678
397
394
  django_ledger/views/data_import.py,sha256=bRCCxfFJCzmthMkDcELDI_JfkgGjchTATrNnojv9p6c,8179
398
395
  django_ledger/views/djl_api.py,sha256=6ADX9fBK8DroTeg8UIeCf2x4wt6-AF5xLlDQnqXBfsM,4411
@@ -406,14 +403,14 @@ django_ledger/views/invoice.py,sha256=BCCvQCtB1p7WBRQZeJakUhDJy4Fr5jvEYIDgLnZDh3
406
403
  django_ledger/views/item.py,sha256=WvwvNWe4Wu9tZWbm75iciNvaSxh9b8h_P_FHt4jsKXs,20604
407
404
  django_ledger/views/journal_entry.py,sha256=7qWagPqk8Nc8E9ylThYfCnvB4o8dsW1GQApMLG3Jb_8,11277
408
405
  django_ledger/views/ledger.py,sha256=_-y8_Na5JyLYzkYIGrOJzAMWC3Hk8hzsikqXsxf8MkM,12178
409
- django_ledger/views/mixins.py,sha256=xUGguHo9xVLe9XaBZ3dy6PFFDScM_N3OqgYVsa6xx9s,23015
406
+ django_ledger/views/mixins.py,sha256=YuH1ATKepDonZNOEn1kMa-Y4lRnZwO-7jr8k83vsmLA,23244
410
407
  django_ledger/views/purchase_order.py,sha256=CyftKrQWV1SBz7W0CvZOfZ81OPEiBHPD7b9zt1k6CFY,21088
411
408
  django_ledger/views/transactions.py,sha256=3ijtJzdLPFkqG7OYpe-7N4QVjCyR2yl5ht_9RyfquBA,212
412
- django_ledger/views/unit.py,sha256=MF9tEeWCOt5XrtK-UFmHFisyBM-h3WzgL6v8IX2Ynbk,10446
413
- django_ledger/views/vendor.py,sha256=qlkd3gsjZ6RYuPrRYDVZp-Im65calM9ed3KxsaT4cxw,3467
414
- django_ledger-0.7.5.2.dist-info/AUTHORS.md,sha256=ShPwf-qniJkbjRzX5_lqhmgoLMEYMSHSwKPXHZtWmyk,824
415
- django_ledger-0.7.5.2.dist-info/LICENSE,sha256=ixuiBLtpoK3iv89l7ylKkg9rs2GzF9ukPH7ynZYzK5s,35148
416
- django_ledger-0.7.5.2.dist-info/METADATA,sha256=oh6gUyIED8VoN1EDraq5t_Wjq5gUvFdBfVl1RhhrpsM,8757
417
- django_ledger-0.7.5.2.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
418
- django_ledger-0.7.5.2.dist-info/top_level.txt,sha256=g6f6tIwlFvhkDfmttGdJyDja8Scm3-jUhZ0dL-J9h_g,52
419
- django_ledger-0.7.5.2.dist-info/RECORD,,
409
+ django_ledger/views/unit.py,sha256=CarmOKzXANssVD3qMS1oXvJw614Y3rS0QHhSGJC0jBE,10069
410
+ django_ledger/views/vendor.py,sha256=7gtVK_bgnXxbVwNAHYtI_eNEJPefCz807LgE1vqOov8,3532
411
+ django_ledger-0.7.6.dist-info/AUTHORS.md,sha256=ShPwf-qniJkbjRzX5_lqhmgoLMEYMSHSwKPXHZtWmyk,824
412
+ django_ledger-0.7.6.dist-info/LICENSE,sha256=ixuiBLtpoK3iv89l7ylKkg9rs2GzF9ukPH7ynZYzK5s,35148
413
+ django_ledger-0.7.6.dist-info/METADATA,sha256=b_8iKhZzuT-Kct82K-4_YG3Af0Xv_JMTEGhuGpV8zQY,8826
414
+ django_ledger-0.7.6.dist-info/WHEEL,sha256=nn6H5-ilmfVryoAQl3ZQ2l8SH5imPWFpm1A5FgEuFV4,91
415
+ django_ledger-0.7.6.dist-info/top_level.txt,sha256=fmHWehb2HfoDncQ3eQtYzeYc-gJMywf6q_ZpKBjwzoQ,38
416
+ django_ledger-0.7.6.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (75.8.0)
2
+ Generator: setuptools (75.8.1)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5
 
@@ -1,5 +1,4 @@
1
1
  assets
2
- dev_notebooks
3
2
  django_ledger
4
3
  docs
5
4
  screenshots
Binary file