django-ledger 0.5.6.3__py3-none-any.whl → 0.5.6.5__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of django-ledger might be problematic. Click here for more details.
- django_ledger/__init__.py +1 -1
- django_ledger/admin/coa.py +3 -3
- django_ledger/admin/entity.py +14 -0
- django_ledger/forms/account.py +14 -5
- 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 +261 -50
- 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/account_update.html +18 -16
- 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 +59 -10
- django_ledger/views/coa.py +83 -9
- django_ledger/views/mixins.py +10 -5
- {django_ledger-0.5.6.3.dist-info → django_ledger-0.5.6.5.dist-info}/METADATA +1 -1
- {django_ledger-0.5.6.3.dist-info → django_ledger-0.5.6.5.dist-info}/RECORD +33 -28
- {django_ledger-0.5.6.3.dist-info → django_ledger-0.5.6.5.dist-info}/AUTHORS.md +0 -0
- {django_ledger-0.5.6.3.dist-info → django_ledger-0.5.6.5.dist-info}/LICENSE +0 -0
- {django_ledger-0.5.6.3.dist-info → django_ledger-0.5.6.5.dist-info}/WHEEL +0 -0
- {django_ledger-0.5.6.3.dist-info → django_ledger-0.5.6.5.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/admin/entity.py
CHANGED
|
@@ -53,11 +53,13 @@ class EntityModelAdmin(ModelAdmin):
|
|
|
53
53
|
list_display = [
|
|
54
54
|
'slug',
|
|
55
55
|
'name',
|
|
56
|
+
'admin',
|
|
56
57
|
'accrual_method',
|
|
57
58
|
'last_closing_date',
|
|
58
59
|
'hidden',
|
|
59
60
|
'get_coa_count',
|
|
60
61
|
'add_ledger_link',
|
|
62
|
+
'dashboard_link',
|
|
61
63
|
'balance_sheet_link',
|
|
62
64
|
'income_statement_link',
|
|
63
65
|
'cash_flow_statement_link'
|
|
@@ -166,6 +168,18 @@ class EntityModelAdmin(ModelAdmin):
|
|
|
166
168
|
|
|
167
169
|
cash_flow_statement_link.short_description = 'Cash Flow'
|
|
168
170
|
|
|
171
|
+
def dashboard_link(self, obj: EntityModel):
|
|
172
|
+
add_ledger_url = reverse(
|
|
173
|
+
viewname='django_ledger:entity-dashboard',
|
|
174
|
+
kwargs={
|
|
175
|
+
'entity_slug': obj.slug
|
|
176
|
+
})
|
|
177
|
+
return format_html('<a class="viewlink" href="{url}">View</a>',
|
|
178
|
+
url=add_ledger_url,
|
|
179
|
+
slug=obj.slug)
|
|
180
|
+
|
|
181
|
+
dashboard_link.short_description = 'Dashboard'
|
|
182
|
+
|
|
169
183
|
def add_code_of_accounts(self, request, queryset):
|
|
170
184
|
lt = get_localtime().isoformat()
|
|
171
185
|
for entity_model in queryset:
|
django_ledger/forms/account.py
CHANGED
|
@@ -31,8 +31,9 @@ class AccountModelCreateForm(ModelForm):
|
|
|
31
31
|
balance_type: Need to be selected from drop down as "Debit" or Credit"
|
|
32
32
|
"""
|
|
33
33
|
|
|
34
|
-
def __init__(self,
|
|
35
|
-
self.
|
|
34
|
+
def __init__(self, entity_model, coa_model, user_model, *args, **kwargs):
|
|
35
|
+
self.ENTITY = entity_model
|
|
36
|
+
self.COA_MODEL = coa_model
|
|
36
37
|
self.USER_MODEL = user_model
|
|
37
38
|
super().__init__(*args, **kwargs)
|
|
38
39
|
self.fields['role'].choices = ACCOUNT_CHOICES_NO_ROOT
|
|
@@ -44,6 +45,13 @@ class AccountModelCreateForm(ModelForm):
|
|
|
44
45
|
return None
|
|
45
46
|
return role_default
|
|
46
47
|
|
|
48
|
+
def clean_code(self):
|
|
49
|
+
code = self.cleaned_data['code']
|
|
50
|
+
is_code_valid = not self.COA_MODEL.accountmodel_set.filter(code=code).exists()
|
|
51
|
+
if not is_code_valid:
|
|
52
|
+
raise ValidationError(message=_('Code {} already exists for CoA {}').format(code, self.COA_MODEL.slug))
|
|
53
|
+
return code
|
|
54
|
+
|
|
47
55
|
class Meta:
|
|
48
56
|
model = AccountModel
|
|
49
57
|
fields = [
|
|
@@ -53,7 +61,7 @@ class AccountModelCreateForm(ModelForm):
|
|
|
53
61
|
'role_default',
|
|
54
62
|
'balance_type',
|
|
55
63
|
'active',
|
|
56
|
-
'
|
|
64
|
+
'active'
|
|
57
65
|
]
|
|
58
66
|
widgets = {
|
|
59
67
|
'code': TextInput(attrs={
|
|
@@ -92,8 +100,9 @@ class AccountModelUpdateForm(MoveNodeForm):
|
|
|
92
100
|
'class': DJANGO_LEDGER_FORM_INPUT_CLASSES
|
|
93
101
|
}))
|
|
94
102
|
|
|
95
|
-
def __init__(self,
|
|
96
|
-
self.
|
|
103
|
+
def __init__(self, entity_model, coa_model, user_model, *args, **kwargs):
|
|
104
|
+
self.ENTITY = entity_model
|
|
105
|
+
self.COA_MODEL = coa_model
|
|
97
106
|
self.USER_MODEL = user_model
|
|
98
107
|
super().__init__(*args, **kwargs)
|
|
99
108
|
# self.fields['_ref_node_id'].choices = self.mk_dropdown_tree_choices()
|
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(
|