django-ledger 0.5.6.5__py3-none-any.whl → 0.6.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of django-ledger might be problematic. Click here for more details.
- django_ledger/__init__.py +1 -1
- django_ledger/io/io_core.py +20 -16
- django_ledger/io/io_digest.py +1 -1
- django_ledger/io/io_middleware.py +2 -4
- django_ledger/models/accounts.py +11 -1
- django_ledger/models/closing_entry.py +4 -4
- django_ledger/models/coa.py +251 -74
- django_ledger/models/entity.py +21 -2
- django_ledger/models/mixins.py +1 -1
- django_ledger/models/transactions.py +209 -111
- django_ledger/models/utils.py +117 -116
- django_ledger/views/account.py +1 -1
- {django_ledger-0.5.6.5.dist-info → django_ledger-0.6.0.dist-info}/METADATA +81 -131
- {django_ledger-0.5.6.5.dist-info → django_ledger-0.6.0.dist-info}/RECORD +18 -19
- django_ledger/static/django_ledger/bundle/djetler.bundle.js.LICENSE.txt +0 -28
- {django_ledger-0.5.6.5.dist-info → django_ledger-0.6.0.dist-info}/AUTHORS.md +0 -0
- {django_ledger-0.5.6.5.dist-info → django_ledger-0.6.0.dist-info}/LICENSE +0 -0
- {django_ledger-0.5.6.5.dist-info → django_ledger-0.6.0.dist-info}/WHEEL +0 -0
- {django_ledger-0.5.6.5.dist-info → django_ledger-0.6.0.dist-info}/top_level.txt +0 -0
django_ledger/models/coa.py
CHANGED
|
@@ -9,24 +9,23 @@ Contributions to this module:
|
|
|
9
9
|
Chart Of Accounts
|
|
10
10
|
_________________
|
|
11
11
|
|
|
12
|
-
A Chart of Accounts (CoA) is a collection of
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
Accounts can be used when creating Journal Entries**. No commingling between CoAs is allowed in order to preserve the
|
|
23
|
-
integrity of the Journal Entry.
|
|
12
|
+
A Chart of Accounts (CoA) is a crucial collection of logically grouped accounts within a ChartOfAccountModel,
|
|
13
|
+
forming the backbone of financial statements. The CoA includes various account roles such as cash, accounts receivable,
|
|
14
|
+
expenses, liabilities, and income. For example, the Balance Sheet may have a Fixed Assets heading consisting of
|
|
15
|
+
Tangible and Intangible Assets with multiple accounts like Building, Plant & Equipments, and Machinery under
|
|
16
|
+
tangible assets. Aggregation of individual account balances based on the Chart of Accounts and AccountModel roles is
|
|
17
|
+
essential for preparing Financial Statements.
|
|
18
|
+
|
|
19
|
+
All EntityModel must have a default CoA to create any type of transaction. When no explicit CoA is specified, the
|
|
20
|
+
default behavior is to use the EntityModel default CoA. Only ONE Chart of Accounts can be used when creating
|
|
21
|
+
Journal Entries. No commingling between CoAs is allowed to preserve the integrity of the Journal Entry.
|
|
24
22
|
"""
|
|
25
23
|
from random import choices
|
|
26
24
|
from string import ascii_lowercase, digits
|
|
27
|
-
from typing import Optional, Union
|
|
25
|
+
from typing import Optional, Union, Dict
|
|
28
26
|
from uuid import uuid4
|
|
29
27
|
|
|
28
|
+
from django.apps import apps
|
|
30
29
|
from django.contrib.auth import get_user_model
|
|
31
30
|
from django.core.exceptions import ValidationError
|
|
32
31
|
from django.db import models
|
|
@@ -45,6 +44,8 @@ UserModel = get_user_model()
|
|
|
45
44
|
|
|
46
45
|
SLUG_SUFFIX = ascii_lowercase + digits
|
|
47
46
|
|
|
47
|
+
app_config = apps.get_app_config('django_ledger')
|
|
48
|
+
|
|
48
49
|
|
|
49
50
|
class ChartOfAccountsModelValidationError(ValidationError):
|
|
50
51
|
pass
|
|
@@ -53,6 +54,9 @@ class ChartOfAccountsModelValidationError(ValidationError):
|
|
|
53
54
|
class ChartOfAccountModelQuerySet(models.QuerySet):
|
|
54
55
|
|
|
55
56
|
def active(self):
|
|
57
|
+
"""
|
|
58
|
+
QuerySet method to retrieve active items.
|
|
59
|
+
"""
|
|
56
60
|
return self.filter(active=True)
|
|
57
61
|
|
|
58
62
|
|
|
@@ -74,13 +78,8 @@ class ChartOfAccountModelManager(models.Manager):
|
|
|
74
78
|
user_model
|
|
75
79
|
Logged in and authenticated django UserModel instance.
|
|
76
80
|
|
|
77
|
-
Examples
|
|
78
|
-
________
|
|
79
|
-
>>> request_user = self.request.user
|
|
80
|
-
>>> coa_model_qs = ChartOfAccountModel.objects.for_user(user_model=request_user)
|
|
81
|
-
|
|
82
81
|
Returns
|
|
83
|
-
|
|
82
|
+
-------
|
|
84
83
|
ChartOfAccountQuerySet
|
|
85
84
|
Returns a ChartOfAccountQuerySet with applied filters.
|
|
86
85
|
"""
|
|
@@ -106,15 +105,8 @@ class ChartOfAccountModelManager(models.Manager):
|
|
|
106
105
|
user_model
|
|
107
106
|
Logged in and authenticated django UserModel instance.
|
|
108
107
|
|
|
109
|
-
Examples
|
|
110
|
-
________
|
|
111
|
-
|
|
112
|
-
>>> request_user = self.request.user
|
|
113
|
-
>>> slug = self.kwargs['entity_slug'] # may come from request kwargs
|
|
114
|
-
>>> coa_model_qs = ChartOfAccountModelManager.objects.for_entity(user_model=request_user, entity_slug=slug)
|
|
115
|
-
|
|
116
108
|
Returns
|
|
117
|
-
|
|
109
|
+
-------
|
|
118
110
|
ChartOfAccountQuerySet
|
|
119
111
|
Returns a ChartOfAccountQuerySet with applied filters.
|
|
120
112
|
"""
|
|
@@ -126,26 +118,20 @@ class ChartOfAccountModelManager(models.Manager):
|
|
|
126
118
|
|
|
127
119
|
class ChartOfAccountModelAbstract(SlugNameMixIn, CreateUpdateMixIn):
|
|
128
120
|
"""
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
2. :func:`CreateUpdateMixIn <django_ledger.models.mixins.SlugMixIn>`
|
|
132
|
-
2. :func:`CreateUpdateMixIn <django_ledger.models.mixins.CreateUpdateMixIn>`
|
|
133
|
-
|
|
121
|
+
Abstract base class for the Chart of Account model.
|
|
122
|
+
|
|
134
123
|
Attributes
|
|
135
124
|
----------
|
|
136
|
-
uuid :
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
description: str
|
|
148
|
-
A user generated description for this Chart of Accounts.
|
|
125
|
+
uuid : UUIDField
|
|
126
|
+
UUID field for the chart of account model (primary key).
|
|
127
|
+
entity : ForeignKey
|
|
128
|
+
ForeignKey to the EntityModel.
|
|
129
|
+
active : BooleanField
|
|
130
|
+
BooleanField indicating whether the chart of account is active or not.
|
|
131
|
+
description : TextField
|
|
132
|
+
TextField storing the description of the chart of account.
|
|
133
|
+
objects : ChartOfAccountModelManager
|
|
134
|
+
Manager for the ChartOfAccountModel.
|
|
149
135
|
"""
|
|
150
136
|
|
|
151
137
|
uuid = models.UUIDField(default=uuid4, editable=False, primary_key=True)
|
|
@@ -172,16 +158,58 @@ class ChartOfAccountModelAbstract(SlugNameMixIn, CreateUpdateMixIn):
|
|
|
172
158
|
return self.slug
|
|
173
159
|
|
|
174
160
|
def get_coa_root_accounts_qs(self) -> AccountModelQuerySet:
|
|
161
|
+
"""
|
|
162
|
+
Retrieves the root accounts in the chart of accounts.
|
|
163
|
+
|
|
164
|
+
Returns:
|
|
165
|
+
AccountModelQuerySet: A queryset containing the root accounts in the chart of accounts.
|
|
166
|
+
"""
|
|
175
167
|
return self.accountmodel_set.all().is_coa_root()
|
|
176
168
|
|
|
177
|
-
def
|
|
169
|
+
def get_coa_root_node(self) -> AccountModel:
|
|
170
|
+
"""
|
|
171
|
+
Retrieves the root node of the chart of accounts.
|
|
172
|
+
|
|
173
|
+
Returns:
|
|
174
|
+
AccountModel: The root node of the chart of accounts.
|
|
175
|
+
|
|
176
|
+
"""
|
|
178
177
|
qs = self.get_coa_root_accounts_qs()
|
|
179
178
|
return qs.get(role__exact=ROOT_COA)
|
|
180
179
|
|
|
181
|
-
def
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
180
|
+
def get_account_root_node(self,
|
|
181
|
+
account_model: AccountModel,
|
|
182
|
+
root_account_qs: Optional[AccountModelQuerySet] = None,
|
|
183
|
+
as_queryset: bool = False) -> AccountModel:
|
|
184
|
+
"""
|
|
185
|
+
Fetches the root node of the ChartOfAccountModel instance. The root node is the highest level of the CoA
|
|
186
|
+
hierarchy. It can be used to traverse the hierarchy of the CoA structure downstream.
|
|
187
|
+
|
|
188
|
+
|
|
189
|
+
Parameters
|
|
190
|
+
----------
|
|
191
|
+
account_model : AccountModel
|
|
192
|
+
The account model for which to find the root node.
|
|
193
|
+
root_account_qs : Optional[AccountModelQuerySet], optional
|
|
194
|
+
The queryset of root accounts. If not provided, it will be retrieved using `get_coa_root_accounts_qs` method.
|
|
195
|
+
as_queryset : bool, optional
|
|
196
|
+
If True, return the root account queryset instead of a single root account. Default is False.
|
|
197
|
+
|
|
198
|
+
Returns
|
|
199
|
+
-------
|
|
200
|
+
Union[AccountModelQuerySet, AccountModel]
|
|
201
|
+
If `as_queryset` is True, returns the root account queryset. Otherwise, returns a single root account.
|
|
202
|
+
|
|
203
|
+
Raises
|
|
204
|
+
------
|
|
205
|
+
ChartOfAccountsModelValidationError
|
|
206
|
+
If the account model is not part of the chart of accounts.
|
|
207
|
+
"""
|
|
208
|
+
|
|
209
|
+
if account_model.coa_model_id != self.uuid:
|
|
210
|
+
raise ChartOfAccountsModelValidationError(
|
|
211
|
+
message=_(f'The account model {account_model} is not part of the chart of accounts {self.name}.'),
|
|
212
|
+
)
|
|
185
213
|
|
|
186
214
|
if not account_model.is_root_account():
|
|
187
215
|
|
|
@@ -209,13 +237,72 @@ class ChartOfAccountModelAbstract(SlugNameMixIn, CreateUpdateMixIn):
|
|
|
209
237
|
return qs.get()
|
|
210
238
|
|
|
211
239
|
def get_non_root_coa_accounts_qs(self) -> AccountModelQuerySet:
|
|
240
|
+
"""
|
|
241
|
+
Returns a query set of non-root accounts in the chart of accounts.
|
|
242
|
+
|
|
243
|
+
Returns
|
|
244
|
+
-------
|
|
245
|
+
AccountModelQuerySet
|
|
246
|
+
A query set of non-root accounts in the chart of accounts.
|
|
247
|
+
"""
|
|
212
248
|
return self.accountmodel_set.all().not_coa_root()
|
|
213
249
|
|
|
214
|
-
def
|
|
215
|
-
|
|
250
|
+
def get_coa_accounts(self, active_only: bool = True) -> AccountModelQuerySet:
|
|
251
|
+
"""
|
|
252
|
+
Returns the AccountModelQuerySet associated with the ChartOfAccounts model instance.
|
|
253
|
+
|
|
254
|
+
Parameters
|
|
255
|
+
----------
|
|
256
|
+
active_only : bool, optional
|
|
257
|
+
Flag to indicate whether to retrieve only active accounts or all accounts.
|
|
258
|
+
Default is True.
|
|
259
|
+
|
|
260
|
+
Returns
|
|
261
|
+
-------
|
|
262
|
+
AccountModelQuerySet
|
|
263
|
+
A queryset containing accounts from the chart of accounts.
|
|
264
|
+
|
|
265
|
+
"""
|
|
266
|
+
qs = self.get_non_root_coa_accounts_qs()
|
|
267
|
+
if active_only:
|
|
268
|
+
return qs.active()
|
|
269
|
+
return qs
|
|
270
|
+
|
|
271
|
+
def get_coa_account_tree(self) -> Dict:
|
|
272
|
+
"""
|
|
273
|
+
Performs a bulk dump of the ChartOfAccounts model instance accounts to a dictionary.
|
|
274
|
+
The method invokes the`dump_bulk` method on the ChartOfAccount model instance root node.
|
|
275
|
+
See Django Tree Beard documentation for more information.
|
|
276
|
+
|
|
277
|
+
Returns
|
|
278
|
+
-------
|
|
279
|
+
Dict
|
|
280
|
+
A dictionary containing all accounts from the chart of accounts in a nested structure.
|
|
281
|
+
"""
|
|
282
|
+
root_account = self.get_coa_root_node()
|
|
216
283
|
return AccountModel.dump_bulk(parent=root_account)
|
|
217
284
|
|
|
218
285
|
def generate_slug(self, raise_exception: bool = False) -> str:
|
|
286
|
+
"""
|
|
287
|
+
Generates and assigns a slug based on the ChartOfAccounts model instance EntityModel information.
|
|
288
|
+
|
|
289
|
+
|
|
290
|
+
Parameters
|
|
291
|
+
----------
|
|
292
|
+
raise_exception : bool, optional
|
|
293
|
+
If set to True, it will raise a ChartOfAccountsModelValidationError if the `self.slug` is already set.
|
|
294
|
+
|
|
295
|
+
Returns
|
|
296
|
+
-------
|
|
297
|
+
str
|
|
298
|
+
The generated slug for the Chart of Accounts.
|
|
299
|
+
|
|
300
|
+
Raises
|
|
301
|
+
------
|
|
302
|
+
ChartOfAccountsModelValidationError
|
|
303
|
+
If `raise_exception` is set to True and `self.slug` is already set.
|
|
304
|
+
|
|
305
|
+
"""
|
|
219
306
|
if self.slug:
|
|
220
307
|
if raise_exception:
|
|
221
308
|
raise ChartOfAccountsModelValidationError(
|
|
@@ -225,7 +312,17 @@ class ChartOfAccountModelAbstract(SlugNameMixIn, CreateUpdateMixIn):
|
|
|
225
312
|
self.slug = f'coa-{self.entity.slug[-5:]}-' + ''.join(choices(SLUG_SUFFIX, k=15))
|
|
226
313
|
|
|
227
314
|
def configure(self, raise_exception: bool = True):
|
|
315
|
+
"""
|
|
316
|
+
A method that properly configures the ChartOfAccounts model and creates the appropriate hierarchy boilerplate
|
|
317
|
+
to support the insertion of new accounts into the chart of account model tree.
|
|
318
|
+
This method must be called every time the ChartOfAccounts model is created.
|
|
228
319
|
|
|
320
|
+
Parameters
|
|
321
|
+
----------
|
|
322
|
+
raise_exception : bool, optional
|
|
323
|
+
Whether to raise an exception if root nodes already exist in the Chart of Accounts (default is True).
|
|
324
|
+
This indicates that the ChartOfAccountModel instance is already configured.
|
|
325
|
+
"""
|
|
229
326
|
self.generate_slug()
|
|
230
327
|
|
|
231
328
|
root_accounts_qs = self.get_coa_root_accounts_qs()
|
|
@@ -274,6 +371,14 @@ class ChartOfAccountModelAbstract(SlugNameMixIn, CreateUpdateMixIn):
|
|
|
274
371
|
))
|
|
275
372
|
|
|
276
373
|
def is_default(self) -> bool:
|
|
374
|
+
"""
|
|
375
|
+
Check if the ChartOfAccountModel instance is set as the default for the EntityModel.
|
|
376
|
+
|
|
377
|
+
Returns
|
|
378
|
+
-------
|
|
379
|
+
bool
|
|
380
|
+
True if the ChartOfAccountModel instance is set as the default for the EntityModel. Else, False.
|
|
381
|
+
"""
|
|
277
382
|
if not self.entity_id:
|
|
278
383
|
return False
|
|
279
384
|
if not self.entity.default_coa_id:
|
|
@@ -281,9 +386,29 @@ class ChartOfAccountModelAbstract(SlugNameMixIn, CreateUpdateMixIn):
|
|
|
281
386
|
return self.entity.default_coa_id == self.uuid
|
|
282
387
|
|
|
283
388
|
def is_active(self) -> bool:
|
|
389
|
+
"""
|
|
390
|
+
Check if the ChartOfAccountModel instance is active.
|
|
391
|
+
|
|
392
|
+
Returns:
|
|
393
|
+
bool: True if the ChartOfAccountModel instance is active, False otherwise.
|
|
394
|
+
"""
|
|
284
395
|
return self.active is True
|
|
285
396
|
|
|
286
397
|
def validate_account_model_qs(self, account_model_qs: AccountModelQuerySet):
|
|
398
|
+
"""
|
|
399
|
+
Validates the given AccountModelQuerySet for the ChartOfAccountsModel.
|
|
400
|
+
|
|
401
|
+
Parameters
|
|
402
|
+
----------
|
|
403
|
+
account_model_qs : AccountModelQuerySet
|
|
404
|
+
The AccountModelQuerySet to validate.
|
|
405
|
+
|
|
406
|
+
Raises
|
|
407
|
+
------
|
|
408
|
+
ChartOfAccountsModelValidationError
|
|
409
|
+
If the account_model_qs is not an instance of AccountModelQuerySet or if it contains an account model with a different coa_model_id than the current CoA model.
|
|
410
|
+
|
|
411
|
+
"""
|
|
287
412
|
if not isinstance(account_model_qs, AccountModelQuerySet):
|
|
288
413
|
raise ChartOfAccountsModelValidationError(
|
|
289
414
|
message='Must pass an instance of AccountModelQuerySet'
|
|
@@ -294,24 +419,40 @@ class ChartOfAccountModelAbstract(SlugNameMixIn, CreateUpdateMixIn):
|
|
|
294
419
|
message=f'Invalid root queryset for CoA {self.name}'
|
|
295
420
|
)
|
|
296
421
|
|
|
297
|
-
def
|
|
298
|
-
|
|
299
|
-
|
|
422
|
+
def insert_account(self,
|
|
423
|
+
account_model: AccountModel,
|
|
424
|
+
root_account_qs: Optional[AccountModelQuerySet] = None):
|
|
300
425
|
"""
|
|
301
|
-
|
|
426
|
+
This method inserts the given account model into the chart of accounts (COA) instance.
|
|
427
|
+
It first verifies if the account model's COA model ID matches the COA's UUID. If not, it
|
|
428
|
+
raises a `ChartOfAccountsModelValidationError`. If the `root_account_qs` is not provided, it retrieves the
|
|
429
|
+
root account query set using the `get_coa_root_accounts_qs` method. Providing a pre-fetched `root_account_qs`
|
|
430
|
+
avoids unnecessary retrieval of the root account query set every an account model is inserted into the CoA.
|
|
431
|
+
|
|
432
|
+
Next, it validates the provided `root_account_qs` if it is not None. Then, it obtains the root node for the
|
|
433
|
+
account model using the `get_account_root_node` method and assigns it to `account_root_node`.
|
|
434
|
+
|
|
435
|
+
Finally, it adds the account model as a child to the `account_root_node` and retrieves the updated COA accounts
|
|
436
|
+
query set using the `get_non_root_coa_accounts_qs` method. It returns the inserted account model found in the
|
|
437
|
+
COA accounts query set.
|
|
302
438
|
|
|
303
439
|
Parameters
|
|
304
440
|
----------
|
|
305
|
-
account_model: AccountModel
|
|
306
|
-
The
|
|
307
|
-
root_account_qs:
|
|
308
|
-
The
|
|
309
|
-
|
|
441
|
+
account_model : AccountModel
|
|
442
|
+
The account model to be inserted into the chart of accounts.
|
|
443
|
+
root_account_qs : Optional[AccountModelQuerySet], default=None
|
|
444
|
+
The root account query set. If not provided, it will be obtained using the `get_coa_root_accounts_qs`
|
|
445
|
+
method.
|
|
310
446
|
|
|
311
447
|
Returns
|
|
312
448
|
-------
|
|
313
449
|
AccountModel
|
|
314
|
-
The
|
|
450
|
+
The inserted account model.
|
|
451
|
+
|
|
452
|
+
Raises
|
|
453
|
+
------
|
|
454
|
+
ChartOfAccountsModelValidationError
|
|
455
|
+
If the provided account model has an invalid COA model ID for the current COA.
|
|
315
456
|
"""
|
|
316
457
|
|
|
317
458
|
if account_model.coa_model_id:
|
|
@@ -325,13 +466,12 @@ class ChartOfAccountModelAbstract(SlugNameMixIn, CreateUpdateMixIn):
|
|
|
325
466
|
else:
|
|
326
467
|
self.validate_account_model_qs(root_account_qs)
|
|
327
468
|
|
|
328
|
-
|
|
469
|
+
account_root_node: AccountModel = self.get_account_root_node(
|
|
329
470
|
account_model=account_model,
|
|
330
471
|
root_account_qs=root_account_qs
|
|
331
472
|
)
|
|
332
473
|
|
|
333
|
-
|
|
334
|
-
l2_root_node.add_child(instance=account_model)
|
|
474
|
+
account_root_node.add_child(instance=account_model)
|
|
335
475
|
coa_accounts_qs = self.get_non_root_coa_accounts_qs()
|
|
336
476
|
return coa_accounts_qs.get(uuid__exact=account_model.uuid)
|
|
337
477
|
|
|
@@ -342,17 +482,41 @@ class ChartOfAccountModelAbstract(SlugNameMixIn, CreateUpdateMixIn):
|
|
|
342
482
|
balance_type: str,
|
|
343
483
|
active: bool,
|
|
344
484
|
root_account_qs: Optional[AccountModelQuerySet] = None):
|
|
485
|
+
"""
|
|
486
|
+
Proper method for inserting a new Account Model into a CoA.
|
|
487
|
+
Use this in liu of the direct instantiation of the AccountModel of using the django related manager.
|
|
488
|
+
|
|
489
|
+
Parameters
|
|
490
|
+
----------
|
|
491
|
+
code : str
|
|
492
|
+
The code of the account to be created.
|
|
493
|
+
role : str
|
|
494
|
+
The role of the account. This can be a user-defined value.
|
|
495
|
+
name : str
|
|
496
|
+
The name of the account.
|
|
497
|
+
balance_type : str
|
|
498
|
+
The balance type of the account. This can be a user-defined value.
|
|
499
|
+
active : bool
|
|
500
|
+
Specifies whether the account is active or not.
|
|
501
|
+
root_account_qs : Optional[AccountModelQuerySet], optional
|
|
502
|
+
The query set of root accounts to which the created account should be linked. Defaults to None.
|
|
345
503
|
|
|
504
|
+
Returns
|
|
505
|
+
-------
|
|
506
|
+
AccountModel
|
|
507
|
+
The created account model instance.
|
|
508
|
+
"""
|
|
346
509
|
account_model = AccountModel(
|
|
347
510
|
code=code,
|
|
348
511
|
name=name,
|
|
349
512
|
role=role,
|
|
350
513
|
active=active,
|
|
351
|
-
balance_type=balance_type
|
|
514
|
+
balance_type=balance_type,
|
|
515
|
+
coa_model=self
|
|
352
516
|
)
|
|
353
517
|
account_model.clean()
|
|
354
518
|
|
|
355
|
-
account_model = self.
|
|
519
|
+
account_model = self.insert_account(
|
|
356
520
|
account_model=account_model,
|
|
357
521
|
root_account_qs=root_account_qs
|
|
358
522
|
)
|
|
@@ -361,14 +525,14 @@ class ChartOfAccountModelAbstract(SlugNameMixIn, CreateUpdateMixIn):
|
|
|
361
525
|
# ACTIONS -----
|
|
362
526
|
# todo: use these methods once multi CoA features are enabled...
|
|
363
527
|
def lock_all_accounts(self) -> AccountModelQuerySet:
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
return
|
|
528
|
+
account_qs = self.get_coa_accounts()
|
|
529
|
+
account_qs.update(locked=True)
|
|
530
|
+
return account_qs
|
|
367
531
|
|
|
368
532
|
def unlock_all_accounts(self) -> AccountModelQuerySet:
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
return
|
|
533
|
+
account_qs = self.get_non_root_coa_accounts_qs()
|
|
534
|
+
account_qs.update(locked=False)
|
|
535
|
+
return account_qs
|
|
372
536
|
|
|
373
537
|
def mark_as_default(self, commit: bool = False, raise_exception: bool = False, **kwargs):
|
|
374
538
|
"""
|
|
@@ -415,9 +579,23 @@ class ChartOfAccountModelAbstract(SlugNameMixIn, CreateUpdateMixIn):
|
|
|
415
579
|
)
|
|
416
580
|
|
|
417
581
|
def can_activate(self) -> bool:
|
|
582
|
+
"""
|
|
583
|
+
Check if the ChartOffAccountModel instance can be activated.
|
|
584
|
+
|
|
585
|
+
Returns
|
|
586
|
+
-------
|
|
587
|
+
True if the object can be activated, False otherwise.
|
|
588
|
+
"""
|
|
418
589
|
return self.active is False
|
|
419
590
|
|
|
420
591
|
def can_deactivate(self) -> bool:
|
|
592
|
+
"""
|
|
593
|
+
Check if the ChartOffAccountModel instance can be deactivated.
|
|
594
|
+
|
|
595
|
+
Returns
|
|
596
|
+
-------
|
|
597
|
+
True if the object can be deactivated, False otherwise.
|
|
598
|
+
"""
|
|
421
599
|
return all([
|
|
422
600
|
self.is_active(),
|
|
423
601
|
not self.is_default()
|
|
@@ -548,7 +726,6 @@ class ChartOfAccountModelAbstract(SlugNameMixIn, CreateUpdateMixIn):
|
|
|
548
726
|
|
|
549
727
|
def clean(self):
|
|
550
728
|
self.generate_slug()
|
|
551
|
-
|
|
552
729
|
if self.is_default() and not self.active:
|
|
553
730
|
raise ChartOfAccountsModelValidationError(
|
|
554
731
|
_('Default Chart of Accounts cannot be deactivated.')
|
django_ledger/models/entity.py
CHANGED
|
@@ -1100,7 +1100,7 @@ class EntityModelAbstract(MP_Node,
|
|
|
1100
1100
|
role=a['role'],
|
|
1101
1101
|
balance_type=a['balance_type'],
|
|
1102
1102
|
active=activate_accounts,
|
|
1103
|
-
|
|
1103
|
+
coa_model=coa_model,
|
|
1104
1104
|
) for a in v] for k, v in CHART_OF_ACCOUNTS_ROOT_MAP.items()
|
|
1105
1105
|
}
|
|
1106
1106
|
|
|
@@ -1115,7 +1115,7 @@ class EntityModelAbstract(MP_Node,
|
|
|
1115
1115
|
pass
|
|
1116
1116
|
|
|
1117
1117
|
account_model.clean()
|
|
1118
|
-
coa_model.
|
|
1118
|
+
coa_model.insert_account(account_model, root_account_qs=root_account_qs)
|
|
1119
1119
|
|
|
1120
1120
|
else:
|
|
1121
1121
|
if not ignore_if_default_coa:
|
|
@@ -1124,6 +1124,25 @@ class EntityModelAbstract(MP_Node,
|
|
|
1124
1124
|
'Use force=True to bypass this check'
|
|
1125
1125
|
)
|
|
1126
1126
|
|
|
1127
|
+
def get_coa_model_qs(self, active: bool = True):
|
|
1128
|
+
"""
|
|
1129
|
+
Fetches the current Entity Model instance Chart of Accounts Model Queryset.
|
|
1130
|
+
|
|
1131
|
+
Parameters
|
|
1132
|
+
----------
|
|
1133
|
+
active: bool
|
|
1134
|
+
Returns only active Chart of Account Models. Defaults to True.
|
|
1135
|
+
|
|
1136
|
+
Returns
|
|
1137
|
+
-------
|
|
1138
|
+
ChartOfAccountModelQuerySet
|
|
1139
|
+
"""
|
|
1140
|
+
|
|
1141
|
+
coa_model_qs = self.chartofaccountmodel_set.all()
|
|
1142
|
+
if active:
|
|
1143
|
+
return coa_model_qs.active()
|
|
1144
|
+
return coa_model_qs
|
|
1145
|
+
|
|
1127
1146
|
# Model Validators....
|
|
1128
1147
|
def validate_chart_of_accounts_for_entity(self,
|
|
1129
1148
|
coa_model: ChartOfAccountModel,
|
django_ledger/models/mixins.py
CHANGED
|
@@ -743,7 +743,7 @@ class AccrualMixIn(models.Model):
|
|
|
743
743
|
|
|
744
744
|
if commit:
|
|
745
745
|
JournalEntryModel = lazy_loader.get_journal_entry_model()
|
|
746
|
-
TransactionModel = lazy_loader.
|
|
746
|
+
TransactionModel = lazy_loader.get_txs_model()
|
|
747
747
|
|
|
748
748
|
unit_uuids = list(set(k[1] for k in idx_keys))
|
|
749
749
|
|