django-ledger 0.5.6.3__py3-none-any.whl → 0.5.6.4__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/admin/coa.py +3 -3
- django_ledger/forms/account.py +1 -1
- django_ledger/forms/coa.py +1 -6
- django_ledger/io/roles.py +25 -9
- django_ledger/migrations/0015_remove_chartofaccountmodel_locked_and_more.py +22 -0
- django_ledger/models/accounts.py +9 -9
- django_ledger/models/coa.py +244 -35
- django_ledger/models/entity.py +43 -28
- django_ledger/templates/django_ledger/account/account_create.html +17 -11
- django_ledger/templates/django_ledger/account/account_list.html +12 -9
- django_ledger/templates/django_ledger/account/tags/accounts_table.html +97 -93
- django_ledger/templates/django_ledger/chart_of_accounts/coa_list.html +17 -0
- django_ledger/templates/django_ledger/{code_of_accounts → chart_of_accounts}/coa_update.html +1 -4
- django_ledger/templates/django_ledger/chart_of_accounts/includes/coa_card.html +74 -0
- django_ledger/templates/django_ledger/invoice/invoice_list.html +91 -94
- django_ledger/templatetags/django_ledger.py +1 -1
- django_ledger/tests/base.py +23 -1
- django_ledger/tests/test_accounts.py +16 -0
- django_ledger/tests/test_chart_of_accounts.py +46 -0
- django_ledger/urls/account.py +18 -3
- django_ledger/urls/chart_of_accounts.py +21 -1
- django_ledger/views/account.py +26 -3
- django_ledger/views/coa.py +79 -4
- django_ledger/views/mixins.py +3 -0
- {django_ledger-0.5.6.3.dist-info → django_ledger-0.5.6.4.dist-info}/METADATA +1 -1
- {django_ledger-0.5.6.3.dist-info → django_ledger-0.5.6.4.dist-info}/RECORD +31 -26
- {django_ledger-0.5.6.3.dist-info → django_ledger-0.5.6.4.dist-info}/AUTHORS.md +0 -0
- {django_ledger-0.5.6.3.dist-info → django_ledger-0.5.6.4.dist-info}/LICENSE +0 -0
- {django_ledger-0.5.6.3.dist-info → django_ledger-0.5.6.4.dist-info}/WHEEL +0 -0
- {django_ledger-0.5.6.3.dist-info → django_ledger-0.5.6.4.dist-info}/top_level.txt +0 -0
django_ledger/__init__.py
CHANGED
django_ledger/admin/coa.py
CHANGED
|
@@ -84,7 +84,7 @@ class ChartOfAccountsInLine(TabularInline):
|
|
|
84
84
|
show_change_link = True
|
|
85
85
|
fields = [
|
|
86
86
|
'name',
|
|
87
|
-
'
|
|
87
|
+
'active',
|
|
88
88
|
'assign_as_default'
|
|
89
89
|
]
|
|
90
90
|
|
|
@@ -92,13 +92,13 @@ class ChartOfAccountsInLine(TabularInline):
|
|
|
92
92
|
class ChartOfAccountsModelAdmin(ModelAdmin):
|
|
93
93
|
list_filter = [
|
|
94
94
|
'entity__name',
|
|
95
|
-
'
|
|
95
|
+
'active'
|
|
96
96
|
]
|
|
97
97
|
list_display = [
|
|
98
98
|
'entity_name',
|
|
99
99
|
'name',
|
|
100
100
|
'slug',
|
|
101
|
-
'
|
|
101
|
+
'active',
|
|
102
102
|
'account_model_count'
|
|
103
103
|
]
|
|
104
104
|
search_fields = [
|
django_ledger/forms/account.py
CHANGED
django_ledger/forms/coa.py
CHANGED
|
@@ -9,19 +9,14 @@ class ChartOfAccountsModelForm(ModelForm):
|
|
|
9
9
|
class Meta:
|
|
10
10
|
model = ChartOfAccountModel
|
|
11
11
|
fields = [
|
|
12
|
-
# 'slug',
|
|
13
12
|
'name',
|
|
14
13
|
'description'
|
|
15
14
|
]
|
|
16
15
|
labels = {
|
|
17
|
-
'slug': _('CoA ID'),
|
|
18
16
|
'name': _('Name'),
|
|
19
17
|
'description': _('Description'),
|
|
20
18
|
}
|
|
21
19
|
widgets = {
|
|
22
|
-
# 'slug': TextInput(attrs={
|
|
23
|
-
# 'class': DJANGO_LEDGER_FORM_INPUT_CLASSES
|
|
24
|
-
# }),
|
|
25
20
|
'name': TextInput(attrs={
|
|
26
21
|
'class': DJANGO_LEDGER_FORM_INPUT_CLASSES
|
|
27
22
|
}),
|
|
@@ -36,7 +31,7 @@ class ChartOfAccountsModelUpdateForm(ModelForm):
|
|
|
36
31
|
model = ChartOfAccountModel
|
|
37
32
|
fields = [
|
|
38
33
|
'name',
|
|
39
|
-
'
|
|
34
|
+
'active'
|
|
40
35
|
]
|
|
41
36
|
labels = {
|
|
42
37
|
'name': _('Name'),
|
django_ledger/io/roles.py
CHANGED
|
@@ -119,48 +119,52 @@ ROOT_GROUP_LEVEL_2 = [
|
|
|
119
119
|
]
|
|
120
120
|
ROOT_GROUP_META = {
|
|
121
121
|
ROOT_COA: {
|
|
122
|
-
'code': '
|
|
122
|
+
'code': '00000000',
|
|
123
123
|
'title': 'CoA Root Node',
|
|
124
124
|
'balance_type': DEBIT
|
|
125
125
|
},
|
|
126
126
|
ROOT_ASSETS: {
|
|
127
|
-
'code': '
|
|
127
|
+
'code': '01000000',
|
|
128
128
|
'title': 'Asset Accounts Root Node',
|
|
129
129
|
'balance_type': DEBIT
|
|
130
130
|
},
|
|
131
131
|
ROOT_LIABILITIES: {
|
|
132
|
-
'code': '
|
|
132
|
+
'code': '02000000',
|
|
133
133
|
'title': 'Liability Accounts Root Node',
|
|
134
134
|
'balance_type': CREDIT
|
|
135
135
|
},
|
|
136
136
|
ROOT_CAPITAL: {
|
|
137
|
-
'code': '
|
|
137
|
+
'code': '03000000',
|
|
138
138
|
'title': 'Capital Accounts Root Node',
|
|
139
139
|
'balance_type': CREDIT
|
|
140
140
|
},
|
|
141
141
|
ROOT_INCOME: {
|
|
142
|
-
'code': '
|
|
142
|
+
'code': '04000000',
|
|
143
143
|
'title': 'Income Accounts Root Node',
|
|
144
144
|
'balance_type': CREDIT
|
|
145
145
|
},
|
|
146
146
|
ROOT_COGS: {
|
|
147
|
-
'code': '
|
|
147
|
+
'code': '05000000',
|
|
148
148
|
'title': 'COGS Accounts Root Node',
|
|
149
149
|
'balance_type': DEBIT
|
|
150
150
|
},
|
|
151
151
|
ROOT_EXPENSES: {
|
|
152
|
-
'code': '
|
|
152
|
+
'code': '06000000',
|
|
153
153
|
'title': 'Expense Accounts Root Node',
|
|
154
154
|
'balance_type': DEBIT
|
|
155
155
|
},
|
|
156
156
|
}
|
|
157
157
|
# ------> ROLE GROUPS <-------#
|
|
158
158
|
|
|
159
|
+
GROUP_ASSETS = list()
|
|
160
|
+
GROUP_ASSETS.append(ROOT_ASSETS)
|
|
161
|
+
|
|
159
162
|
# ASSET GROUPS...
|
|
160
163
|
GROUP_QUICK_ASSETS = [
|
|
161
164
|
ASSET_CA_CASH,
|
|
162
165
|
ASSET_CA_MKT_SECURITIES
|
|
163
166
|
]
|
|
167
|
+
GROUP_ASSETS += GROUP_QUICK_ASSETS
|
|
164
168
|
|
|
165
169
|
GROUP_CURRENT_ASSETS = [
|
|
166
170
|
ASSET_CA_CASH,
|
|
@@ -171,6 +175,7 @@ GROUP_CURRENT_ASSETS = [
|
|
|
171
175
|
ASSET_CA_UNCOLLECTIBLES,
|
|
172
176
|
ASSET_CA_OTHER
|
|
173
177
|
]
|
|
178
|
+
GROUP_ASSETS += GROUP_CURRENT_ASSETS
|
|
174
179
|
|
|
175
180
|
GROUP_NON_CURRENT_ASSETS = [
|
|
176
181
|
ASSET_LTI_NOTES_RECEIVABLE,
|
|
@@ -187,9 +192,13 @@ GROUP_NON_CURRENT_ASSETS = [
|
|
|
187
192
|
ASSET_ADJUSTMENTS
|
|
188
193
|
]
|
|
189
194
|
|
|
190
|
-
GROUP_ASSETS
|
|
195
|
+
GROUP_ASSETS += GROUP_NON_CURRENT_ASSETS
|
|
196
|
+
GROUP_ASSETS = list(set(GROUP_ASSETS))
|
|
191
197
|
|
|
192
198
|
# LIABILITY GROUPS....
|
|
199
|
+
GROUP_LIABILITIES = list()
|
|
200
|
+
GROUP_LIABILITIES.append(ROOT_LIABILITIES)
|
|
201
|
+
|
|
193
202
|
GROUP_CURRENT_LIABILITIES = [
|
|
194
203
|
LIABILITY_CL_ACC_PAYABLE,
|
|
195
204
|
LIABILITY_CL_DEFERRED_REVENUE,
|
|
@@ -200,17 +209,21 @@ GROUP_CURRENT_LIABILITIES = [
|
|
|
200
209
|
LIABILITY_CL_WAGES_PAYABLE,
|
|
201
210
|
LIABILITY_CL_TAXES_PAYABLE
|
|
202
211
|
]
|
|
212
|
+
GROUP_LIABILITIES += GROUP_CURRENT_LIABILITIES
|
|
203
213
|
|
|
204
214
|
GROUP_LT_LIABILITIES = [
|
|
205
215
|
LIABILITY_LTL_NOTES_PAYABLE,
|
|
206
216
|
LIABILITY_LTL_BONDS_PAYABLE,
|
|
207
217
|
LIABILITY_LTL_MORTGAGE_PAYABLE,
|
|
208
218
|
]
|
|
219
|
+
GROUP_LIABILITIES += GROUP_LT_LIABILITIES
|
|
209
220
|
|
|
210
|
-
GROUP_LIABILITIES =
|
|
221
|
+
GROUP_LIABILITIES = list(set(GROUP_LIABILITIES))
|
|
211
222
|
|
|
212
223
|
# CAPITAL/EQUITY...
|
|
224
|
+
|
|
213
225
|
GROUP_CAPITAL = [
|
|
226
|
+
ROOT_CAPITAL,
|
|
214
227
|
EQUITY_CAPITAL,
|
|
215
228
|
EQUITY_COMMON_STOCK,
|
|
216
229
|
EQUITY_PREFERRED_STOCK,
|
|
@@ -219,6 +232,7 @@ GROUP_CAPITAL = [
|
|
|
219
232
|
]
|
|
220
233
|
|
|
221
234
|
GROUP_INCOME = [
|
|
235
|
+
ROOT_INCOME,
|
|
222
236
|
INCOME_OPERATIONAL,
|
|
223
237
|
INCOME_PASSIVE,
|
|
224
238
|
INCOME_INTEREST,
|
|
@@ -227,10 +241,12 @@ GROUP_INCOME = [
|
|
|
227
241
|
]
|
|
228
242
|
|
|
229
243
|
GROUP_COGS = [
|
|
244
|
+
ROOT_COGS,
|
|
230
245
|
COGS
|
|
231
246
|
]
|
|
232
247
|
|
|
233
248
|
GROUP_EXPENSES = [
|
|
249
|
+
ROOT_EXPENSES,
|
|
234
250
|
EXPENSE_OPERATIONAL,
|
|
235
251
|
EXPENSE_INTEREST_ST,
|
|
236
252
|
EXPENSE_INTEREST_LT,
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# Generated by Django 5.0.3 on 2024-03-14 02:17
|
|
2
|
+
|
|
3
|
+
from django.db import migrations, models
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class Migration(migrations.Migration):
|
|
7
|
+
|
|
8
|
+
dependencies = [
|
|
9
|
+
('django_ledger', '0014_ledgermodel_ledger_xid_and_more'),
|
|
10
|
+
]
|
|
11
|
+
|
|
12
|
+
operations = [
|
|
13
|
+
migrations.RemoveField(
|
|
14
|
+
model_name='chartofaccountmodel',
|
|
15
|
+
name='locked',
|
|
16
|
+
),
|
|
17
|
+
migrations.AddField(
|
|
18
|
+
model_name='chartofaccountmodel',
|
|
19
|
+
name='active',
|
|
20
|
+
field=models.BooleanField(default=True, verbose_name='Is Active'),
|
|
21
|
+
),
|
|
22
|
+
]
|
django_ledger/models/accounts.py
CHANGED
|
@@ -242,8 +242,9 @@ class AccountModelManager(MP_NodeManager):
|
|
|
242
242
|
entity_slug=entity_slug,
|
|
243
243
|
coa_slug=coa_slug)
|
|
244
244
|
return qs.filter(
|
|
245
|
-
active=True
|
|
246
|
-
locked=False
|
|
245
|
+
Q(active=True) &
|
|
246
|
+
Q(locked=False) &
|
|
247
|
+
Q(coa_model__active=True)
|
|
247
248
|
)
|
|
248
249
|
|
|
249
250
|
def with_roles(self, roles: Union[list, str], entity_slug, user_model) -> AccountModelQuerySet:
|
|
@@ -581,7 +582,7 @@ class AccountModelAbstract(MP_Node, CreateUpdateMixIn):
|
|
|
581
582
|
return self.balance_type == CREDIT
|
|
582
583
|
|
|
583
584
|
def is_coa_root(self):
|
|
584
|
-
return self.role
|
|
585
|
+
return self.role == ROOT_COA
|
|
585
586
|
|
|
586
587
|
def is_asset(self) -> bool:
|
|
587
588
|
return self.role in GROUP_ASSETS
|
|
@@ -604,6 +605,9 @@ class AccountModelAbstract(MP_Node, CreateUpdateMixIn):
|
|
|
604
605
|
def is_active(self) -> bool:
|
|
605
606
|
return self.active is True
|
|
606
607
|
|
|
608
|
+
def is_locked(self) -> bool:
|
|
609
|
+
return self.locked is True
|
|
610
|
+
|
|
607
611
|
def can_activate(self):
|
|
608
612
|
return all([
|
|
609
613
|
self.active is False
|
|
@@ -656,10 +660,7 @@ class AccountModelAbstract(MP_Node, CreateUpdateMixIn):
|
|
|
656
660
|
return '5'
|
|
657
661
|
elif self.is_expense():
|
|
658
662
|
return '6'
|
|
659
|
-
|
|
660
|
-
return '0'
|
|
661
|
-
else:
|
|
662
|
-
raise AccountModelValidationError(f'Invalid role match for role {self.role}...')
|
|
663
|
+
raise AccountModelValidationError(f'Invalid role match for role {self.role}...')
|
|
663
664
|
|
|
664
665
|
def get_root_role(self) -> str:
|
|
665
666
|
if self.is_asset():
|
|
@@ -676,8 +677,7 @@ class AccountModelAbstract(MP_Node, CreateUpdateMixIn):
|
|
|
676
677
|
return ROOT_EXPENSES
|
|
677
678
|
elif self.is_coa_root():
|
|
678
679
|
return ROOT_COA
|
|
679
|
-
|
|
680
|
-
raise AccountModelValidationError(f'Invalid role match for role {self.role}...')
|
|
680
|
+
raise AccountModelValidationError(f'Invalid role match for role {self.role}...')
|
|
681
681
|
|
|
682
682
|
def get_account_move_choice_queryset(self):
|
|
683
683
|
return self.coa_model.accountmodel_set.filter(
|
django_ledger/models/coa.py
CHANGED
|
@@ -31,7 +31,7 @@ from django.contrib.auth import get_user_model
|
|
|
31
31
|
from django.core.exceptions import ValidationError
|
|
32
32
|
from django.db import models
|
|
33
33
|
from django.db.models import Q
|
|
34
|
-
from django.
|
|
34
|
+
from django.urls import reverse
|
|
35
35
|
from django.utils.translation import gettext_lazy as _
|
|
36
36
|
|
|
37
37
|
from django_ledger.io import (ROOT_COA, ROOT_GROUP_LEVEL_2, ROOT_GROUP_META, ROOT_ASSETS,
|
|
@@ -40,7 +40,6 @@ from django_ledger.io import (ROOT_COA, ROOT_GROUP_LEVEL_2, ROOT_GROUP_META, ROO
|
|
|
40
40
|
from django_ledger.models import lazy_loader
|
|
41
41
|
from django_ledger.models.accounts import AccountModel, AccountModelQuerySet
|
|
42
42
|
from django_ledger.models.mixins import CreateUpdateMixIn, SlugNameMixIn
|
|
43
|
-
from django_ledger.settings import logger
|
|
44
43
|
|
|
45
44
|
UserModel = get_user_model()
|
|
46
45
|
|
|
@@ -150,10 +149,10 @@ class ChartOfAccountModelAbstract(SlugNameMixIn, CreateUpdateMixIn):
|
|
|
150
149
|
entity: EntityModel
|
|
151
150
|
The EntityModel associated with this Chart of Accounts.
|
|
152
151
|
|
|
153
|
-
|
|
152
|
+
active: bool
|
|
154
153
|
This determines whether any changes can be done to the Chart of Accounts.
|
|
155
|
-
|
|
156
|
-
Default value is set to False (
|
|
154
|
+
Inactive Chart of Accounts will not be able to be used in new Transactions.
|
|
155
|
+
Default value is set to False (inactive).
|
|
157
156
|
|
|
158
157
|
description: str
|
|
159
158
|
A user generated description for this Chart of Accounts.
|
|
@@ -164,7 +163,7 @@ class ChartOfAccountModelAbstract(SlugNameMixIn, CreateUpdateMixIn):
|
|
|
164
163
|
editable=False,
|
|
165
164
|
verbose_name=_('Entity'),
|
|
166
165
|
on_delete=models.CASCADE)
|
|
167
|
-
|
|
166
|
+
active = models.BooleanField(default=True, verbose_name=_('Is Active'))
|
|
168
167
|
description = models.TextField(verbose_name=_('CoA Description'), null=True, blank=True)
|
|
169
168
|
objects = ChartOfAccountModelManager.from_queryset(queryset_class=ChartOfAccountModelQuerySet)()
|
|
170
169
|
|
|
@@ -194,7 +193,7 @@ class ChartOfAccountModelAbstract(SlugNameMixIn, CreateUpdateMixIn):
|
|
|
194
193
|
root_account_qs: Optional[AccountModelQuerySet] = None,
|
|
195
194
|
as_queryset: bool = False) -> Union[AccountModelQuerySet, AccountModel]:
|
|
196
195
|
|
|
197
|
-
if not account_model.
|
|
196
|
+
if not account_model.is_root_account():
|
|
198
197
|
|
|
199
198
|
if not root_account_qs:
|
|
200
199
|
root_account_qs = self.get_coa_root_accounts_qs()
|
|
@@ -262,8 +261,9 @@ class ChartOfAccountModelAbstract(SlugNameMixIn, CreateUpdateMixIn):
|
|
|
262
261
|
locked=True,
|
|
263
262
|
balance_type=role_meta['balance_type']
|
|
264
263
|
)
|
|
265
|
-
|
|
264
|
+
AccountModel.add_root(instance=root_account)
|
|
266
265
|
|
|
266
|
+
# must retrieve root model after added pero django-treebeard documentation...
|
|
267
267
|
coa_root_account_model = AccountModel.objects.get(uuid__exact=account_pk)
|
|
268
268
|
|
|
269
269
|
for root_role in ROOT_GROUP_LEVEL_2:
|
|
@@ -284,10 +284,11 @@ class ChartOfAccountModelAbstract(SlugNameMixIn, CreateUpdateMixIn):
|
|
|
284
284
|
))
|
|
285
285
|
|
|
286
286
|
def is_default(self) -> bool:
|
|
287
|
-
if self.entity_id is None:
|
|
288
|
-
return False
|
|
289
287
|
return self.entity.default_coa_id == self.uuid
|
|
290
288
|
|
|
289
|
+
def is_active(self) -> bool:
|
|
290
|
+
return self.active is True
|
|
291
|
+
|
|
291
292
|
def validate_account_model_qs(self, account_model_qs: AccountModelQuerySet):
|
|
292
293
|
if not isinstance(account_model_qs, AccountModelQuerySet):
|
|
293
294
|
raise ChartOfAccountsModelValidationError(
|
|
@@ -299,23 +300,72 @@ class ChartOfAccountModelAbstract(SlugNameMixIn, CreateUpdateMixIn):
|
|
|
299
300
|
message=f'Invalid root queryset for CoA {self.name}'
|
|
300
301
|
)
|
|
301
302
|
|
|
302
|
-
def
|
|
303
|
-
|
|
303
|
+
def allocate_account(self,
|
|
304
|
+
account_model: AccountModel,
|
|
305
|
+
root_account_qs: Optional[AccountModelQuerySet] = None):
|
|
306
|
+
"""
|
|
307
|
+
Allocates a given account model to the appropriate root account depending on the Account Model Role.
|
|
304
308
|
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
+
Parameters
|
|
310
|
+
----------
|
|
311
|
+
account_model: AccountModel
|
|
312
|
+
The Account Model to Allocate
|
|
313
|
+
root_account_qs:
|
|
314
|
+
The Root Account QuerySet of the Chart Of Accounts to use.
|
|
315
|
+
Will be validated against current CoA Model.
|
|
309
316
|
|
|
310
|
-
|
|
317
|
+
Returns
|
|
318
|
+
-------
|
|
319
|
+
AccountModel
|
|
320
|
+
The saved and allocated AccountModel.
|
|
321
|
+
"""
|
|
311
322
|
|
|
312
|
-
|
|
313
|
-
account_model
|
|
323
|
+
if account_model.coa_model_id:
|
|
324
|
+
if account_model.coa_model_id != self.uuid:
|
|
325
|
+
raise ChartOfAccountsModelValidationError(
|
|
326
|
+
message=f'Invalid Account Model {account_model} for CoA {self}'
|
|
327
|
+
)
|
|
328
|
+
|
|
329
|
+
if not root_account_qs:
|
|
330
|
+
root_account_qs = self.get_coa_root_accounts_qs()
|
|
331
|
+
else:
|
|
332
|
+
self.validate_account_model_qs(root_account_qs)
|
|
333
|
+
|
|
334
|
+
l2_root_node: AccountModel = self.get_coa_l2_root(
|
|
335
|
+
account_model=account_model,
|
|
336
|
+
root_account_qs=root_account_qs
|
|
337
|
+
)
|
|
338
|
+
|
|
339
|
+
account_model.coa_model = self
|
|
340
|
+
l2_root_node.add_child(instance=account_model)
|
|
341
|
+
coa_accounts_qs = self.get_non_root_coa_accounts_qs()
|
|
342
|
+
return coa_accounts_qs.get(uuid__exact=account_model.uuid)
|
|
343
|
+
|
|
344
|
+
def create_account(self,
|
|
345
|
+
code: str,
|
|
346
|
+
role: str,
|
|
347
|
+
name: str,
|
|
348
|
+
balance_type: str,
|
|
349
|
+
active: bool,
|
|
350
|
+
root_account_qs: Optional[AccountModelQuerySet] = None):
|
|
351
|
+
|
|
352
|
+
account_model = AccountModel(
|
|
353
|
+
code=code,
|
|
354
|
+
name=name,
|
|
355
|
+
role=role,
|
|
356
|
+
active=active,
|
|
357
|
+
balance_type=balance_type
|
|
358
|
+
)
|
|
359
|
+
account_model.clean()
|
|
360
|
+
|
|
361
|
+
account_model = self.allocate_account(
|
|
362
|
+
account_model=account_model,
|
|
363
|
+
root_account_qs=root_account_qs
|
|
364
|
+
)
|
|
314
365
|
return account_model
|
|
315
366
|
|
|
316
367
|
# ACTIONS -----
|
|
317
|
-
|
|
318
|
-
# todo: use these methods once multi CoA fetures are enabled...
|
|
368
|
+
# todo: use these methods once multi CoA features are enabled...
|
|
319
369
|
def lock_all_accounts(self) -> AccountModelQuerySet:
|
|
320
370
|
non_root_accounts_qs = self.get_non_root_coa_accounts_qs()
|
|
321
371
|
non_root_accounts_qs.update(locked=True)
|
|
@@ -326,25 +376,184 @@ class ChartOfAccountModelAbstract(SlugNameMixIn, CreateUpdateMixIn):
|
|
|
326
376
|
non_root_accounts_qs.update(locked=False)
|
|
327
377
|
return non_root_accounts_qs
|
|
328
378
|
|
|
329
|
-
def
|
|
330
|
-
|
|
379
|
+
def mark_as_default(self, commit: bool = False, raise_exception: bool = False, **kwargs):
|
|
380
|
+
"""
|
|
381
|
+
Marks the current Chart of Accounts instances as default for the EntityModel.
|
|
382
|
+
|
|
383
|
+
Parameters
|
|
384
|
+
----------
|
|
385
|
+
commit: bool
|
|
386
|
+
Commit the action into the Database. Default is False.
|
|
387
|
+
raise_exception: bool
|
|
388
|
+
Raises exception if Chart of Account model instance is already marked as default.
|
|
389
|
+
"""
|
|
390
|
+
if self.is_default():
|
|
391
|
+
if raise_exception:
|
|
392
|
+
raise ChartOfAccountsModelValidationError(
|
|
393
|
+
message=_(f'The Chart of Accounts {self.slug} is already default')
|
|
394
|
+
)
|
|
395
|
+
return
|
|
396
|
+
self.entity.default_coa_id = self.uuid
|
|
397
|
+
self.clean()
|
|
398
|
+
if commit:
|
|
399
|
+
self.entity.save(
|
|
400
|
+
update_fields=[
|
|
401
|
+
'default_coa_id',
|
|
402
|
+
'updated'
|
|
403
|
+
]
|
|
404
|
+
)
|
|
331
405
|
|
|
406
|
+
def mark_as_default_url(self) -> str:
|
|
407
|
+
"""
|
|
408
|
+
Returns the URL to mark the current Chart of Accounts instances as Default for the EntityModel.
|
|
332
409
|
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
410
|
+
Returns
|
|
411
|
+
-------
|
|
412
|
+
str
|
|
413
|
+
The URL as a String.
|
|
414
|
+
"""
|
|
415
|
+
return reverse(
|
|
416
|
+
viewname='django_ledger:coa-action-mark-as-default',
|
|
417
|
+
kwargs={
|
|
418
|
+
'entity_slug': self.entity.slug,
|
|
419
|
+
'coa_slug': self.slug
|
|
420
|
+
}
|
|
421
|
+
)
|
|
422
|
+
|
|
423
|
+
def can_activate(self) -> bool:
|
|
424
|
+
return self.active is False
|
|
425
|
+
|
|
426
|
+
def can_deactivate(self) -> bool:
|
|
427
|
+
return all([
|
|
428
|
+
self.is_active(),
|
|
429
|
+
not self.is_default()
|
|
430
|
+
])
|
|
431
|
+
|
|
432
|
+
def mark_as_active(self, commit: bool = False, raise_exception: bool = False, **kwargs):
|
|
433
|
+
"""
|
|
434
|
+
Marks the current Chart of Accounts as Active.
|
|
435
|
+
|
|
436
|
+
Parameters
|
|
437
|
+
----------
|
|
438
|
+
commit: bool
|
|
439
|
+
Commit the action into the Database. Default is False.
|
|
440
|
+
raise_exception: bool
|
|
441
|
+
Raises exception if Chart of Account model instance is already active. Default is False.
|
|
442
|
+
"""
|
|
443
|
+
if self.is_active():
|
|
444
|
+
if raise_exception:
|
|
445
|
+
raise ChartOfAccountsModelValidationError(
|
|
446
|
+
message=_('The Chart of Accounts is currently active.')
|
|
447
|
+
)
|
|
448
|
+
return
|
|
449
|
+
|
|
450
|
+
self.active = True
|
|
451
|
+
self.clean()
|
|
452
|
+
if commit:
|
|
453
|
+
self.save(
|
|
454
|
+
update_fields=[
|
|
455
|
+
'active',
|
|
456
|
+
'updated'
|
|
457
|
+
])
|
|
458
|
+
|
|
459
|
+
def mark_as_active_url(self) -> str:
|
|
460
|
+
"""
|
|
461
|
+
Returns the URL to mark the current Chart of Accounts instances as active.
|
|
462
|
+
|
|
463
|
+
Returns
|
|
464
|
+
-------
|
|
465
|
+
str
|
|
466
|
+
The URL as a String.
|
|
467
|
+
"""
|
|
468
|
+
return reverse(
|
|
469
|
+
viewname='django_ledger:coa-action-mark-as-active',
|
|
470
|
+
kwargs={
|
|
471
|
+
'entity_slug': self.entity.slug,
|
|
472
|
+
'coa_slug': self.slug
|
|
473
|
+
}
|
|
474
|
+
)
|
|
475
|
+
|
|
476
|
+
def mark_as_inactive(self, commit: bool = False, raise_exception: bool = False, **kwargs):
|
|
477
|
+
"""
|
|
478
|
+
Marks the current Chart of Accounts as Active.
|
|
479
|
+
|
|
480
|
+
Parameters
|
|
481
|
+
----------
|
|
482
|
+
commit: bool
|
|
483
|
+
Commit the action into the Database. Default is False.
|
|
484
|
+
raise_exception: bool
|
|
485
|
+
Raises exception if Chart of Account model instance is already active. Default is False.
|
|
486
|
+
"""
|
|
487
|
+
if not self.is_active():
|
|
488
|
+
if raise_exception:
|
|
489
|
+
raise ChartOfAccountsModelValidationError(
|
|
490
|
+
message=_('The Chart of Accounts is currently not active.')
|
|
491
|
+
)
|
|
492
|
+
return
|
|
337
493
|
|
|
494
|
+
self.active = False
|
|
495
|
+
self.clean()
|
|
496
|
+
if commit:
|
|
497
|
+
self.save(
|
|
498
|
+
update_fields=[
|
|
499
|
+
'active',
|
|
500
|
+
'updated'
|
|
501
|
+
])
|
|
338
502
|
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
503
|
+
def mark_as_inactive_url(self) -> str:
|
|
504
|
+
"""
|
|
505
|
+
Returns the URL to mark the current Chart of Accounts instances as inactive.
|
|
342
506
|
|
|
507
|
+
Returns
|
|
508
|
+
-------
|
|
509
|
+
str
|
|
510
|
+
The URL as a String.
|
|
511
|
+
"""
|
|
512
|
+
return reverse(
|
|
513
|
+
viewname='django_ledger:coa-action-mark-as-inactive',
|
|
514
|
+
kwargs={
|
|
515
|
+
'entity_slug': self.entity.slug,
|
|
516
|
+
'coa_slug': self.slug
|
|
517
|
+
}
|
|
518
|
+
)
|
|
519
|
+
|
|
520
|
+
def get_absolute_url(self) -> str:
|
|
521
|
+
return reverse(
|
|
522
|
+
viewname='django_ledger:coa-detail',
|
|
523
|
+
kwargs={
|
|
524
|
+
'coa_slug': self.slug,
|
|
525
|
+
'entity_slug': self.entity.slug
|
|
526
|
+
}
|
|
527
|
+
)
|
|
528
|
+
|
|
529
|
+
def get_account_list_url(self):
|
|
530
|
+
return reverse(
|
|
531
|
+
viewname='django_ledger:account-list-coa',
|
|
532
|
+
kwargs={
|
|
533
|
+
'entity_slug': self.entity.slug,
|
|
534
|
+
'coa_slug': self.slug
|
|
535
|
+
}
|
|
536
|
+
)
|
|
537
|
+
|
|
538
|
+
def get_create_coa_account_url(self):
|
|
539
|
+
return reverse(
|
|
540
|
+
viewname='django_ledger:account-create-coa',
|
|
541
|
+
kwargs={
|
|
542
|
+
'coa_slug': self.slug,
|
|
543
|
+
'entity_slug': self.entity.slug
|
|
544
|
+
}
|
|
545
|
+
)
|
|
343
546
|
|
|
344
|
-
def
|
|
345
|
-
|
|
346
|
-
|
|
547
|
+
def clean(self):
|
|
548
|
+
self.generate_slug()
|
|
549
|
+
|
|
550
|
+
if self.is_default() and not self.active:
|
|
551
|
+
raise ChartOfAccountsModelValidationError(
|
|
552
|
+
_('Default Chart of Accounts cannot be deactivated.')
|
|
553
|
+
)
|
|
347
554
|
|
|
348
555
|
|
|
349
|
-
|
|
350
|
-
|
|
556
|
+
class ChartOfAccountModel(ChartOfAccountModelAbstract):
|
|
557
|
+
"""
|
|
558
|
+
Base ChartOfAccounts Model
|
|
559
|
+
"""
|