django-ledger 0.6.0.2__py3-none-any.whl → 0.6.2__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of django-ledger might be problematic. Click here for more details.
- assets/node_modules/node-gyp/update-gyp.py +0 -0
- django_ledger/__init__.py +1 -1
- django_ledger/io/__init__.py +1 -3
- django_ledger/io/{io_digest.py → io_context.py} +8 -0
- django_ledger/io/io_core.py +3 -3
- django_ledger/models/entity.py +4 -2
- django_ledger/models/items.py +1 -3
- django_ledger/models/ledger.py +14 -9
- django_ledger/models/mixins.py +11 -7
- django_ledger/models/transactions.py +1 -32
- django_ledger/templates/django_ledger/financial_statements/tags/balance_sheet_statement.html +0 -1
- django_ledger/templatetags/django_ledger.py +1 -1
- django_ledger/views/entity.py +2 -2
- django_ledger/views/mixins.py +81 -45
- {django_ledger-0.6.0.2.dist-info → django_ledger-0.6.2.dist-info}/METADATA +1 -1
- {django_ledger-0.6.0.2.dist-info → django_ledger-0.6.2.dist-info}/RECORD +19 -19
- {django_ledger-0.6.0.2.dist-info → django_ledger-0.6.2.dist-info}/AUTHORS.md +0 -0
- {django_ledger-0.6.0.2.dist-info → django_ledger-0.6.2.dist-info}/LICENSE +0 -0
- {django_ledger-0.6.0.2.dist-info → django_ledger-0.6.2.dist-info}/WHEEL +0 -0
- {django_ledger-0.6.0.2.dist-info → django_ledger-0.6.2.dist-info}/top_level.txt +0 -0
|
File without changes
|
django_ledger/__init__.py
CHANGED
django_ledger/io/__init__.py
CHANGED
|
@@ -6,9 +6,7 @@ Contributions to this module:
|
|
|
6
6
|
Miguel Sanda <msanda@arrobalytics.com>
|
|
7
7
|
"""
|
|
8
8
|
|
|
9
|
-
from django_ledger.io.
|
|
9
|
+
from django_ledger.io.io_context import *
|
|
10
10
|
from django_ledger.io.io_middleware import *
|
|
11
11
|
from django_ledger.io.ratios import *
|
|
12
12
|
from django_ledger.io.roles import *
|
|
13
|
-
# due to circular import
|
|
14
|
-
# from django_ledger.io.io_library import IOLibrary
|
|
@@ -38,6 +38,10 @@ class IODigestContextManager:
|
|
|
38
38
|
def get_strftime_format(self):
|
|
39
39
|
return self.STRFTIME_FORMAT
|
|
40
40
|
|
|
41
|
+
@property
|
|
42
|
+
def from_datetime(self):
|
|
43
|
+
return self.get_from_datetime()
|
|
44
|
+
|
|
41
45
|
def get_from_datetime(self, as_str: bool = False, fmt=None) -> Optional[datetime]:
|
|
42
46
|
from_date = self.IO_DATA['from_date']
|
|
43
47
|
if from_date:
|
|
@@ -47,6 +51,10 @@ class IODigestContextManager:
|
|
|
47
51
|
return from_date.strftime(fmt)
|
|
48
52
|
return from_date
|
|
49
53
|
|
|
54
|
+
@property
|
|
55
|
+
def to_datetime(self):
|
|
56
|
+
return self.get_to_datetime()
|
|
57
|
+
|
|
50
58
|
def get_to_datetime(self, as_str: bool = False, fmt=None) -> datetime:
|
|
51
59
|
if as_str:
|
|
52
60
|
if not fmt:
|
django_ledger/io/io_core.py
CHANGED
|
@@ -36,7 +36,7 @@ from django.utils.translation import gettext_lazy as _
|
|
|
36
36
|
from django_ledger import settings
|
|
37
37
|
from django_ledger.exceptions import InvalidDateInputError, TransactionNotInBalanceError
|
|
38
38
|
from django_ledger.io import roles as roles_module
|
|
39
|
-
from django_ledger.io.
|
|
39
|
+
from django_ledger.io.io_context import IODigestContextManager
|
|
40
40
|
from django_ledger.io.io_middleware import (
|
|
41
41
|
AccountRoleIOMiddleware,
|
|
42
42
|
AccountGroupIOMiddleware,
|
|
@@ -343,7 +343,7 @@ class IODatabaseMixIn:
|
|
|
343
343
|
Returns results aggregated by accounting if needed. Defaults to False.
|
|
344
344
|
by_unit: bool
|
|
345
345
|
Returns results aggregated by unit if needed. Defaults to False.
|
|
346
|
-
|
|
346
|
+
use_closing_entries: bool
|
|
347
347
|
Overrides the DJANGO_LEDGER_USE_CLOSING_ENTRIES setting.
|
|
348
348
|
Returns
|
|
349
349
|
-------
|
|
@@ -587,7 +587,7 @@ class IODatabaseMixIn:
|
|
|
587
587
|
signs: bool
|
|
588
588
|
Changes the balance of an account to negative if it represents a "negative" for display purposes.
|
|
589
589
|
(i.e. Expense accounts will show balance as negative and Income accounts as positive.)
|
|
590
|
-
|
|
590
|
+
use_closing_entries: bool
|
|
591
591
|
Forces the use of closing entries if DJANGO_LEDGER_USE_CLOSING_ENTRIES setting is set to False.
|
|
592
592
|
force_queryset_sorting: bool
|
|
593
593
|
Forces sorting of the TransactionModelQuerySet before aggregation balances.
|
django_ledger/models/entity.py
CHANGED
|
@@ -116,7 +116,7 @@ class EntityModelManager(MP_NodeManager):
|
|
|
116
116
|
qs = EntityModelQuerySet(self.model, using=self._db).order_by('path')
|
|
117
117
|
return qs.order_by('path').select_related('admin', 'default_coa')
|
|
118
118
|
|
|
119
|
-
def for_user(self, user_model):
|
|
119
|
+
def for_user(self, user_model, authorized_superuser: bool = False):
|
|
120
120
|
"""
|
|
121
121
|
This QuerySet guarantees that Users do not access or operate on EntityModels that don't have access to.
|
|
122
122
|
This is the recommended initial QuerySet.
|
|
@@ -125,6 +125,8 @@ class EntityModelManager(MP_NodeManager):
|
|
|
125
125
|
----------
|
|
126
126
|
user_model
|
|
127
127
|
The Django User Model making the request.
|
|
128
|
+
authorized_superuser
|
|
129
|
+
Allows any superuser to access the EntityModel. Default is False.
|
|
128
130
|
|
|
129
131
|
Returns
|
|
130
132
|
-------
|
|
@@ -134,7 +136,7 @@ class EntityModelManager(MP_NodeManager):
|
|
|
134
136
|
2. Is a manager.
|
|
135
137
|
"""
|
|
136
138
|
qs = self.get_queryset()
|
|
137
|
-
if user_model.is_superuser:
|
|
139
|
+
if user_model.is_superuser and authorized_superuser:
|
|
138
140
|
return qs
|
|
139
141
|
return qs.filter(
|
|
140
142
|
Q(admin=user_model) |
|
django_ledger/models/items.py
CHANGED
|
@@ -881,8 +881,6 @@ class ItemTransactionModelManager(models.Manager):
|
|
|
881
881
|
|
|
882
882
|
def for_user(self, user_model):
|
|
883
883
|
qs = self.get_queryset()
|
|
884
|
-
if user_model.is_superuser:
|
|
885
|
-
return qs
|
|
886
884
|
return qs.filter(
|
|
887
885
|
Q(item_model__entity__admin=user_model) |
|
|
888
886
|
Q(item_model__entity__managers__in=[user_model])
|
|
@@ -891,7 +889,7 @@ class ItemTransactionModelManager(models.Manager):
|
|
|
891
889
|
def for_entity(self, user_model, entity_slug):
|
|
892
890
|
qs = self.for_user(user_model)
|
|
893
891
|
if isinstance(entity_slug, lazy_loader.get_entity_model()):
|
|
894
|
-
qs.filter(
|
|
892
|
+
return qs.filter(
|
|
895
893
|
Q(item_model__entity=entity_slug)
|
|
896
894
|
)
|
|
897
895
|
return qs.filter(
|
django_ledger/models/ledger.py
CHANGED
|
@@ -226,7 +226,6 @@ class LedgerModelAbstract(CreateUpdateMixIn, IOMixIn):
|
|
|
226
226
|
ledger_str = f'LedgerModel: {self.uuid}'
|
|
227
227
|
return f'{ledger_str} | Posted: {self.posted} | Locked: {self.locked}'
|
|
228
228
|
|
|
229
|
-
|
|
230
229
|
def has_wrapped_model_info(self):
|
|
231
230
|
if self.additional_info is not None:
|
|
232
231
|
return self._WRAPPED_MODEL_KEY in self.additional_info
|
|
@@ -523,7 +522,7 @@ class LedgerModelAbstract(CreateUpdateMixIn, IOMixIn):
|
|
|
523
522
|
je_model_qs.bulk_update(objs=je_model_qs, fields=['locked', 'updated'])
|
|
524
523
|
return je_model_qs
|
|
525
524
|
|
|
526
|
-
def unlock(self, commit: bool = False, **kwargs):
|
|
525
|
+
def unlock(self, commit: bool = False, raise_exception: bool = True, **kwargs):
|
|
527
526
|
"""
|
|
528
527
|
Un-locks the LedgerModel.
|
|
529
528
|
|
|
@@ -532,13 +531,19 @@ class LedgerModelAbstract(CreateUpdateMixIn, IOMixIn):
|
|
|
532
531
|
commit: bool
|
|
533
532
|
If True, saves the LedgerModel instance instantly. Defaults to False.
|
|
534
533
|
"""
|
|
535
|
-
if self.can_unlock():
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
534
|
+
if not self.can_unlock():
|
|
535
|
+
if raise_exception:
|
|
536
|
+
raise LedgerModelValidationError(
|
|
537
|
+
message=_(f'Ledger {self.name} cannot be un-locked. UUID: {self.uuid}')
|
|
538
|
+
)
|
|
539
|
+
return
|
|
540
|
+
|
|
541
|
+
self.locked = False
|
|
542
|
+
if commit:
|
|
543
|
+
self.save(update_fields=[
|
|
544
|
+
'locked',
|
|
545
|
+
'updated'
|
|
546
|
+
])
|
|
542
547
|
|
|
543
548
|
def hide(self, commit: bool = False, raise_exception: bool = True, **kwargs):
|
|
544
549
|
if not self.can_hide():
|
django_ledger/models/mixins.py
CHANGED
|
@@ -487,7 +487,8 @@ class AccrualMixIn(models.Model):
|
|
|
487
487
|
if ledger_model.locked:
|
|
488
488
|
if raise_exception:
|
|
489
489
|
raise ValidationError(f'Bill ledger {ledger_model.name} is already locked...')
|
|
490
|
-
|
|
490
|
+
return
|
|
491
|
+
ledger_model.lock(commit, raise_exception=raise_exception)
|
|
491
492
|
|
|
492
493
|
def unlock_ledger(self, commit: bool = False, raise_exception: bool = True, **kwargs):
|
|
493
494
|
"""
|
|
@@ -501,10 +502,11 @@ class AccrualMixIn(models.Model):
|
|
|
501
502
|
If True, raises ValidationError if LedgerModel already locked.
|
|
502
503
|
"""
|
|
503
504
|
ledger_model = self.ledger
|
|
504
|
-
if not ledger_model.
|
|
505
|
+
if not ledger_model.is_locked():
|
|
505
506
|
if raise_exception:
|
|
506
507
|
raise ValidationError(f'Bill ledger {ledger_model.name} is already unlocked...')
|
|
507
|
-
|
|
508
|
+
return
|
|
509
|
+
ledger_model.unlock(commit, raise_exception=raise_exception)
|
|
508
510
|
|
|
509
511
|
# POST/UNPOST Ledger...
|
|
510
512
|
def post_ledger(self, commit: bool = False, raise_exception: bool = True, **kwargs):
|
|
@@ -522,7 +524,8 @@ class AccrualMixIn(models.Model):
|
|
|
522
524
|
if ledger_model.posted:
|
|
523
525
|
if raise_exception:
|
|
524
526
|
raise ValidationError(f'Bill ledger {ledger_model.name} is already posted...')
|
|
525
|
-
|
|
527
|
+
return
|
|
528
|
+
ledger_model.post(commit, raise_exception=raise_exception)
|
|
526
529
|
|
|
527
530
|
def unpost_ledger(self, commit: bool = False, raise_exception: bool = True, **kwargs):
|
|
528
531
|
"""
|
|
@@ -536,13 +539,14 @@ class AccrualMixIn(models.Model):
|
|
|
536
539
|
If True, raises ValidationError if LedgerModel already locked.
|
|
537
540
|
"""
|
|
538
541
|
ledger_model = self.ledger
|
|
539
|
-
if not ledger_model.
|
|
542
|
+
if not ledger_model.is_posted():
|
|
540
543
|
if raise_exception:
|
|
541
544
|
raise ValidationError(f'Bill ledger {ledger_model.name} is not posted...')
|
|
542
|
-
|
|
545
|
+
return
|
|
546
|
+
ledger_model.post(commit, raise_exception=raise_exception)
|
|
543
547
|
|
|
544
548
|
def migrate_state(self,
|
|
545
|
-
# todo: remove usermodel param
|
|
549
|
+
# todo: remove usermodel param...?
|
|
546
550
|
user_model,
|
|
547
551
|
entity_slug: str,
|
|
548
552
|
itemtxs_qs: Optional[QuerySet] = None,
|
|
@@ -49,35 +49,6 @@ class TransactionModelQuerySet(QuerySet):
|
|
|
49
49
|
"""
|
|
50
50
|
A custom QuerySet class for TransactionModels implementing methods to effectively and safely read
|
|
51
51
|
TransactionModels from the database.
|
|
52
|
-
|
|
53
|
-
Methods
|
|
54
|
-
-------
|
|
55
|
-
posted() -> TransactionModelQuerySet:
|
|
56
|
-
Fetches a QuerySet of posted transactions only.
|
|
57
|
-
|
|
58
|
-
for_accounts(account_list: List[str or AccountModel]) -> TransactionModelQuerySet:
|
|
59
|
-
Fetches a QuerySet of TransactionModels which AccountModel has a specific role.
|
|
60
|
-
|
|
61
|
-
for_roles(role_list: Union[str, List[str]]) -> TransactionModelQuerySet:
|
|
62
|
-
Fetches a QuerySet of TransactionModels which AccountModel has a specific role.
|
|
63
|
-
|
|
64
|
-
for_unit(unit_slug: Union[str, EntityUnitModel]) -> TransactionModelQuerySet:
|
|
65
|
-
Fetches a QuerySet of TransactionModels associated with a specific EntityUnitModel.
|
|
66
|
-
|
|
67
|
-
for_activity(activity_list: Union[str, List[str]]) -> TransactionModelQuerySet:
|
|
68
|
-
Fetches a QuerySet of TransactionModels associated with a specific activity or list of activities.
|
|
69
|
-
|
|
70
|
-
to_date(to_date: Union[str, date, datetime]) -> TransactionModelQuerySet:
|
|
71
|
-
Fetches a QuerySet of TransactionModels associated with a maximum date or timestamp filter.
|
|
72
|
-
|
|
73
|
-
from_date(from_date: Union[str, date, datetime]) -> TransactionModelQuerySet:
|
|
74
|
-
Fetches a QuerySet of TransactionModels associated with a minimum date or timestamp filter.
|
|
75
|
-
|
|
76
|
-
not_closing_entry() -> TransactionModelQuerySet:
|
|
77
|
-
Fetches a QuerySet of TransactionModels that are not part of a closing entry.
|
|
78
|
-
|
|
79
|
-
is_closing_entry() -> TransactionModelQuerySet:
|
|
80
|
-
Fetches a QuerySet of TransactionModels that are part of a closing entry.
|
|
81
52
|
"""
|
|
82
53
|
|
|
83
54
|
def posted(self) -> QuerySet:
|
|
@@ -111,7 +82,7 @@ class TransactionModelQuerySet(QuerySet):
|
|
|
111
82
|
TransactionModelQuerySet
|
|
112
83
|
Returns a TransactionModelQuerySet with applied filters.
|
|
113
84
|
"""
|
|
114
|
-
if
|
|
85
|
+
if isinstance(account_list, list) > 0 and isinstance(account_list[0], str):
|
|
115
86
|
return self.filter(account__code__in=account_list)
|
|
116
87
|
return self.filter(account__in=account_list)
|
|
117
88
|
|
|
@@ -276,8 +247,6 @@ class TransactionModelManager(models.Manager):
|
|
|
276
247
|
ledger or the user is one of the managers of the entity associated with the transaction's ledger.
|
|
277
248
|
"""
|
|
278
249
|
qs = self.get_queryset()
|
|
279
|
-
if user_model.is_superuser:
|
|
280
|
-
return qs
|
|
281
250
|
return qs.filter(
|
|
282
251
|
Q(journal_entry__ledger__entity__admin=user_model) |
|
|
283
252
|
Q(journal_entry__ledger__entity__managers__in=[user_model])
|
|
@@ -137,7 +137,7 @@ def cash_flow_statement(context, io_model):
|
|
|
137
137
|
|
|
138
138
|
@register.inclusion_tag('django_ledger/financial_statements/tags/income_statement.html', takes_context=True)
|
|
139
139
|
def income_statement_table(context, io_model, from_date=None, to_date=None):
|
|
140
|
-
user_model
|
|
140
|
+
user_model = context['user']
|
|
141
141
|
activity = context['request'].GET.get('activity')
|
|
142
142
|
activity = validate_activity(activity, raise_404=True)
|
|
143
143
|
entity_slug = context['view'].kwargs.get('entity_slug')
|
django_ledger/views/entity.py
CHANGED
|
@@ -199,8 +199,8 @@ class EntityModelDetailBaseView(DjangoLedgerSecurityMixIn,
|
|
|
199
199
|
FETCH_UNPAID_BILLS = True
|
|
200
200
|
FETCH_UNPAID_INVOICES = True
|
|
201
201
|
|
|
202
|
-
|
|
203
|
-
|
|
202
|
+
IO_DIGEST_UNBOUNDED = True
|
|
203
|
+
IO_DIGEST_BOUNDED = True
|
|
204
204
|
|
|
205
205
|
def get_context_data(self, **kwargs):
|
|
206
206
|
context = super().get_context_data(**kwargs)
|
django_ledger/views/mixins.py
CHANGED
|
@@ -24,7 +24,18 @@ from django_ledger.models.entity import EntityModelFiscalPeriodMixIn
|
|
|
24
24
|
from django_ledger.settings import DJANGO_LEDGER_PDF_SUPPORT_ENABLED, DJANGO_LEDGER_AUTHORIZED_SUPERUSER
|
|
25
25
|
|
|
26
26
|
|
|
27
|
-
class
|
|
27
|
+
class ContextFromToDateMixin:
|
|
28
|
+
FROM_DATE_CONTEXT_NAME = 'from_date'
|
|
29
|
+
TO_DATE_CONTEXT_NAME = 'to_date'
|
|
30
|
+
|
|
31
|
+
def get_from_date_context_name(self) -> str:
|
|
32
|
+
return self.FROM_DATE_CONTEXT_NAME
|
|
33
|
+
|
|
34
|
+
def get_to_date_context_name(self) -> str:
|
|
35
|
+
return self.TO_DATE_CONTEXT_NAME
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
class YearlyReportMixIn(YearMixin, ContextFromToDateMixin, EntityModelFiscalPeriodMixIn):
|
|
28
39
|
|
|
29
40
|
def get_from_date(self, year: int = None, fy_start: int = None, **kwargs) -> date:
|
|
30
41
|
return self.get_year_start_date(year, fy_start)
|
|
@@ -58,16 +69,16 @@ class YearlyReportMixIn(YearMixin, EntityModelFiscalPeriodMixIn):
|
|
|
58
69
|
context['year_start'] = year_start
|
|
59
70
|
context['year_end'] = year_end
|
|
60
71
|
|
|
61
|
-
if
|
|
62
|
-
context[
|
|
63
|
-
if
|
|
64
|
-
context[
|
|
72
|
+
if self.get_from_date_context_name() not in context:
|
|
73
|
+
context[self.get_from_date_context_name()] = year_start
|
|
74
|
+
if self.get_to_date_context_name() not in context:
|
|
75
|
+
context[self.get_to_date_context_name()] = year_end
|
|
65
76
|
|
|
66
77
|
context['has_year'] = True
|
|
67
78
|
return context
|
|
68
79
|
|
|
69
80
|
|
|
70
|
-
class QuarterlyReportMixIn(YearMixin, EntityModelFiscalPeriodMixIn):
|
|
81
|
+
class QuarterlyReportMixIn(YearMixin, ContextFromToDateMixin, EntityModelFiscalPeriodMixIn):
|
|
71
82
|
quarter = None
|
|
72
83
|
quarter_url_kwarg = 'quarter'
|
|
73
84
|
|
|
@@ -137,10 +148,10 @@ class QuarterlyReportMixIn(YearMixin, EntityModelFiscalPeriodMixIn):
|
|
|
137
148
|
context['quarter_start'] = quarter_start
|
|
138
149
|
context['quarter_end'] = quarter_end
|
|
139
150
|
|
|
140
|
-
if
|
|
141
|
-
context[
|
|
142
|
-
if
|
|
143
|
-
context[
|
|
151
|
+
if self.get_from_date_context_name() not in context:
|
|
152
|
+
context[self.get_from_date_context_name()] = quarter_start
|
|
153
|
+
if self.get_to_date_context_name() not in context:
|
|
154
|
+
context[self.get_to_date_context_name()] = quarter_end
|
|
144
155
|
|
|
145
156
|
context['has_quarter'] = True
|
|
146
157
|
return context
|
|
@@ -154,7 +165,7 @@ class QuarterlyReportMixIn(YearMixin, EntityModelFiscalPeriodMixIn):
|
|
|
154
165
|
return quarter - 1
|
|
155
166
|
|
|
156
167
|
|
|
157
|
-
class MonthlyReportMixIn(YearlyReportMixIn, MonthMixin):
|
|
168
|
+
class MonthlyReportMixIn(YearlyReportMixIn, ContextFromToDateMixin, MonthMixin):
|
|
158
169
|
|
|
159
170
|
def get_from_date(self, month: int = None, year: int = None, **kwargs) -> date:
|
|
160
171
|
return self.get_month_start_date(month=month, year=year)
|
|
@@ -206,13 +217,17 @@ class MonthlyReportMixIn(YearlyReportMixIn, MonthMixin):
|
|
|
206
217
|
month_end = self.get_month_end_date(year=year, month=month)
|
|
207
218
|
context['month_start'] = month_start
|
|
208
219
|
context['month_end'] = month_end
|
|
209
|
-
|
|
210
|
-
|
|
220
|
+
|
|
221
|
+
if self.get_from_date_context_name() not in context:
|
|
222
|
+
context[self.get_from_date_context_name()] = month_start
|
|
223
|
+
if self.get_to_date_context_name() not in context:
|
|
224
|
+
context[self.get_to_date_context_name()] = month_end
|
|
225
|
+
|
|
211
226
|
context['has_month'] = True
|
|
212
227
|
return context
|
|
213
228
|
|
|
214
229
|
|
|
215
|
-
class DateReportMixIn(MonthlyReportMixIn, DayMixin):
|
|
230
|
+
class DateReportMixIn(MonthlyReportMixIn, ContextFromToDateMixin, DayMixin):
|
|
216
231
|
|
|
217
232
|
def get_context_data(self, **kwargs):
|
|
218
233
|
context = super(MonthlyReportMixIn, self).get_context_data(**kwargs)
|
|
@@ -221,8 +236,12 @@ class DateReportMixIn(MonthlyReportMixIn, DayMixin):
|
|
|
221
236
|
context['next_day'] = view_date + timedelta(days=1)
|
|
222
237
|
context['previous_day'] = view_date - timedelta(days=1)
|
|
223
238
|
context['view_date'] = view_date
|
|
224
|
-
|
|
225
|
-
|
|
239
|
+
|
|
240
|
+
if self.get_from_date_context_name() not in context:
|
|
241
|
+
context[self.get_from_date_context_name()] = view_date
|
|
242
|
+
if self.get_to_date_context_name() not in context:
|
|
243
|
+
context[self.get_to_date_context_name()] = view_date
|
|
244
|
+
|
|
226
245
|
return context
|
|
227
246
|
|
|
228
247
|
def get_date(self) -> date:
|
|
@@ -243,7 +262,8 @@ class DateReportMixIn(MonthlyReportMixIn, DayMixin):
|
|
|
243
262
|
return dt, dt
|
|
244
263
|
|
|
245
264
|
|
|
246
|
-
|
|
265
|
+
# todo: need to incorporate in base view...
|
|
266
|
+
class FromToDatesParseMixIn:
|
|
247
267
|
DJL_FROM_DATE_PARAM: str = 'from_date'
|
|
248
268
|
DJL_TO_DATE_PARAM: str = 'to_date'
|
|
249
269
|
DJL_NO_FROM_DATE_RAISE_404: bool = True
|
|
@@ -311,25 +331,20 @@ class DjangoLedgerSecurityMixIn(LoginRequiredMixin, PermissionRequiredMixin):
|
|
|
311
331
|
)
|
|
312
332
|
return self.ENTITY_SLUG_URL_KWARG
|
|
313
333
|
|
|
334
|
+
def get_superuser_authorization(self):
|
|
335
|
+
return self.AUTHORIZE_SUPERUSER
|
|
336
|
+
|
|
314
337
|
def has_permission(self):
|
|
338
|
+
has_perm = super().has_permission()
|
|
339
|
+
if not has_perm:
|
|
340
|
+
return False
|
|
341
|
+
|
|
315
342
|
entity_slug_kwarg = self.get_entity_slug_kwarg()
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
if entity_slug_kwarg in self.kwargs:
|
|
320
|
-
try:
|
|
321
|
-
entity_model_qs = self.get_authorized_entity_queryset()
|
|
322
|
-
self.AUTHORIZED_ENTITY_MODEL = entity_model_qs.get(slug__exact=self.kwargs[entity_slug_kwarg])
|
|
323
|
-
except ObjectDoesNotExist:
|
|
324
|
-
return False
|
|
325
|
-
return True
|
|
326
|
-
elif self.request.user.is_authenticated:
|
|
327
|
-
has_perm = super().has_permission()
|
|
328
|
-
if not has_perm:
|
|
329
|
-
return False
|
|
343
|
+
entity_model_qs = self.get_authorized_entity_queryset()
|
|
344
|
+
|
|
345
|
+
if self.request.user.is_authenticated:
|
|
330
346
|
if entity_slug_kwarg in self.kwargs:
|
|
331
347
|
try:
|
|
332
|
-
entity_model_qs = self.get_authorized_entity_queryset()
|
|
333
348
|
self.AUTHORIZED_ENTITY_MODEL = entity_model_qs.get(slug__exact=self.kwargs[entity_slug_kwarg])
|
|
334
349
|
except ObjectDoesNotExist:
|
|
335
350
|
return False
|
|
@@ -338,7 +353,9 @@ class DjangoLedgerSecurityMixIn(LoginRequiredMixin, PermissionRequiredMixin):
|
|
|
338
353
|
|
|
339
354
|
def get_authorized_entity_queryset(self):
|
|
340
355
|
return EntityModel.objects.for_user(
|
|
341
|
-
user_model=self.request.user
|
|
356
|
+
user_model=self.request.user,
|
|
357
|
+
authorized_superuser=self.get_superuser_authorization(),
|
|
358
|
+
).only(
|
|
342
359
|
'uuid', 'slug', 'name', 'default_coa', 'admin')
|
|
343
360
|
|
|
344
361
|
def get_authorized_entity_instance(self) -> Optional[EntityModel]:
|
|
@@ -372,8 +389,27 @@ class EntityUnitMixIn:
|
|
|
372
389
|
|
|
373
390
|
|
|
374
391
|
class DigestContextMixIn:
|
|
375
|
-
|
|
376
|
-
|
|
392
|
+
|
|
393
|
+
IO_DIGEST_UNBOUNDED = False
|
|
394
|
+
IO_DIGEST_BOUNDED = False
|
|
395
|
+
|
|
396
|
+
IO_DIGEST_UNBOUNDED_CONTEXT_NAME = 'tx_digest'
|
|
397
|
+
IO_MANAGER_UNBOUNDED_CONTEXT_NAME = 'tx_digest_context'
|
|
398
|
+
|
|
399
|
+
IO_DIGEST_BOUNDED_CONTEXT_NAME = 'equity_digest'
|
|
400
|
+
IO_MANAGER_BOUNDED_CONTEXT_NAME = 'equity_digest_context'
|
|
401
|
+
|
|
402
|
+
def get_io_digest_unbounded_context_name(self):
|
|
403
|
+
return self.IO_DIGEST_UNBOUNDED_CONTEXT_NAME
|
|
404
|
+
|
|
405
|
+
def get_io_manager_unbounded_context_name(self):
|
|
406
|
+
return self.IO_MANAGER_UNBOUNDED_CONTEXT_NAME
|
|
407
|
+
|
|
408
|
+
def get_io_digest_bounded_context_name(self):
|
|
409
|
+
return self.IO_DIGEST_BOUNDED_CONTEXT_NAME
|
|
410
|
+
|
|
411
|
+
def get_io_manager_bounded_context_name(self):
|
|
412
|
+
return self.IO_MANAGER_BOUNDED_CONTEXT_NAME
|
|
377
413
|
|
|
378
414
|
def get_context_data(self, **kwargs):
|
|
379
415
|
context = super(DigestContextMixIn, self).get_context_data(**kwargs)
|
|
@@ -385,8 +421,8 @@ class DigestContextMixIn:
|
|
|
385
421
|
to_date=None,
|
|
386
422
|
**kwargs):
|
|
387
423
|
|
|
388
|
-
if any([self.
|
|
389
|
-
self.
|
|
424
|
+
if any([self.IO_DIGEST_UNBOUNDED,
|
|
425
|
+
self.IO_DIGEST_BOUNDED]):
|
|
390
426
|
|
|
391
427
|
by_period = self.request.GET.get('by_period')
|
|
392
428
|
entity_model: EntityModel = self.object
|
|
@@ -401,7 +437,7 @@ class DigestContextMixIn:
|
|
|
401
437
|
else:
|
|
402
438
|
unit_slug = None
|
|
403
439
|
|
|
404
|
-
if self.
|
|
440
|
+
if self.IO_DIGEST_UNBOUNDED:
|
|
405
441
|
io_digest = entity_model.digest(user_model=self.request.user,
|
|
406
442
|
to_date=to_date,
|
|
407
443
|
unit_slug=unit_slug,
|
|
@@ -410,22 +446,22 @@ class DigestContextMixIn:
|
|
|
410
446
|
process_roles=True,
|
|
411
447
|
process_groups=True)
|
|
412
448
|
|
|
413
|
-
context[
|
|
414
|
-
context[
|
|
449
|
+
context[self.get_io_manager_unbounded_context_name()] = io_digest
|
|
450
|
+
context[self.get_io_digest_unbounded_context_name()] = io_digest.get_io_data()
|
|
415
451
|
|
|
416
|
-
if self.
|
|
452
|
+
if self.IO_DIGEST_BOUNDED:
|
|
417
453
|
io_digest_equity = entity_model.digest(user_model=self.request.user,
|
|
418
454
|
equity_only=True,
|
|
419
455
|
to_date=to_date,
|
|
420
456
|
from_date=from_date,
|
|
421
457
|
unit_slug=unit_slug,
|
|
422
458
|
by_period=True if by_period else False,
|
|
423
|
-
process_ratios=
|
|
424
|
-
process_roles=
|
|
459
|
+
process_ratios=True,
|
|
460
|
+
process_roles=True,
|
|
425
461
|
process_groups=True)
|
|
426
462
|
|
|
427
|
-
context[
|
|
428
|
-
context[
|
|
463
|
+
context[self.get_io_manager_bounded_context_name()] = io_digest_equity
|
|
464
|
+
context[self.get_io_digest_bounded_context_name()] = io_digest_equity.get_io_data()
|
|
429
465
|
|
|
430
466
|
# todo: how is this used??....
|
|
431
467
|
context['date_filter'] = to_date
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: django-ledger
|
|
3
|
-
Version: 0.6.
|
|
3
|
+
Version: 0.6.2
|
|
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,7 +48,7 @@ assets/node_modules/node-gyp/gyp/tools/pretty_gyp.py,sha256=2ZCRPW-MZfK7gdnCIaqh
|
|
|
48
48
|
assets/node_modules/node-gyp/gyp/tools/pretty_sln.py,sha256=b_Fxm-SXUCPL3Tix4EyNwZNmQ-zkeRIFFmuL0R5wFhw,5482
|
|
49
49
|
assets/node_modules/node-gyp/gyp/tools/pretty_vcproj.py,sha256=AwQrxK1F-jhjsbbT35XQjrvWNbc3IBFaKXoJogqMh_o,10633
|
|
50
50
|
assets/node_modules/node-gyp/test/fixtures/test-charmap.py,sha256=5raXzaQnO2eJnrlFtlDtWftryhZX7Fj0amFW3hdSnhE,547
|
|
51
|
-
django_ledger/__init__.py,sha256=
|
|
51
|
+
django_ledger/__init__.py,sha256=XWsm2GPCPw5ayJIKYpT2rO83Yxp4iYr5a0vNyC4ao3Y,456
|
|
52
52
|
django_ledger/apps.py,sha256=H-zEWUjKGakgSDSZmLIoXChZ2h6e0dth0ZO5SpoT-8U,163
|
|
53
53
|
django_ledger/exceptions.py,sha256=rML8sQQ0Hq-DYMLZ76dfw2RYSAsXWUoyHuyC_yP9o1o,491
|
|
54
54
|
django_ledger/settings.py,sha256=bZyPKgjmRcO_Rj7hDi4gGlW0VFr_LP2yKeUVIkmWgQM,6321
|
|
@@ -114,9 +114,9 @@ django_ledger/forms/transactions.py,sha256=DD2TJthArTKTuzd4A43ZbugepcB8iuJ4Q_PSR
|
|
|
114
114
|
django_ledger/forms/unit.py,sha256=rXUefjpuAmUU0vPOqu1ObO4k-bN-_Q6kOqHJ4kp_Vlg,1131
|
|
115
115
|
django_ledger/forms/utils.py,sha256=sgkwBZs15_rZ5NT7h-8Z7wi3-ItM1E1sqoVDo3NQ5Jc,513
|
|
116
116
|
django_ledger/forms/vendor.py,sha256=Nuh8MmSpz4ycMZwiVe--U9Ec6ezIsfACHDkhA2SyiZ4,2215
|
|
117
|
-
django_ledger/io/__init__.py,sha256=
|
|
118
|
-
django_ledger/io/
|
|
119
|
-
django_ledger/io/
|
|
117
|
+
django_ledger/io/__init__.py,sha256=8m5AoBRiG2ymrX0Y4LVjq0275i7I5Sk7YRa1BTzVofI,369
|
|
118
|
+
django_ledger/io/io_context.py,sha256=xgykRoB6hVSN2q20f62j_4zbOeAHU5ZgbZaSwRaSkOU,4444
|
|
119
|
+
django_ledger/io/io_core.py,sha256=b_-je0NNPkMOglkJwObxfKA6eWa0YvEod9LODm5RRIg,46922
|
|
120
120
|
django_ledger/io/io_generator.py,sha256=JF4plsABUkCIrtI2X-YD7o5eNghRIgLUseNcBIGOj3U,34613
|
|
121
121
|
django_ledger/io/io_library.py,sha256=vvQm3IQRLFdH7HS_DYX46Xe-U9IvgZ6MQnHjy0-fyjk,22480
|
|
122
122
|
django_ledger/io/io_middleware.py,sha256=c-vwpcjg2HbYbb4O36fdf6011dFOnoNsDHOAQXmJgB8,20052
|
|
@@ -152,15 +152,15 @@ django_ledger/models/coa.py,sha256=o-VM2XK64djM3px6pJlGrUVTXu5qNb4ENESS70I___0,2
|
|
|
152
152
|
django_ledger/models/coa_default.py,sha256=4Zj8OMhgBiYuREjM82cFfyGWd8uCAeqggVkeNhg4SLU,27338
|
|
153
153
|
django_ledger/models/customer.py,sha256=JQOktcYKUlENJv4frek9rAW6sRerrQ0xXHlC5KPmhWk,11807
|
|
154
154
|
django_ledger/models/data_import.py,sha256=2H-4oTVLa7qXq03m9fd7T5zSQLkZKOAn2OAeOQBzMPA,19477
|
|
155
|
-
django_ledger/models/entity.py,sha256=
|
|
155
|
+
django_ledger/models/entity.py,sha256=VFknz-7FQZu_gVDb5RWqPoCb3eXVzIMgmr4hatUlzBI,121876
|
|
156
156
|
django_ledger/models/estimate.py,sha256=-qB5t2cEdyYpFUq7tOUQnFqvE6EDUiVdTtzjEbESwEQ,55829
|
|
157
157
|
django_ledger/models/invoice.py,sha256=h5Jh5KOfYr31Eu9gFW1mdoGoVzx7nW8qBdx7vyiXnZU,61568
|
|
158
|
-
django_ledger/models/items.py,sha256=
|
|
158
|
+
django_ledger/models/items.py,sha256=Wh_zPBnYCdI393nHafT6xd4aSutKBQPwKSjDtXTTPNQ,55042
|
|
159
159
|
django_ledger/models/journal_entry.py,sha256=VfXXvm3tUFuy2Z6j3PLlDk9ndHqsZgn_PuhrxTNqaiY,50918
|
|
160
|
-
django_ledger/models/ledger.py,sha256=
|
|
161
|
-
django_ledger/models/mixins.py,sha256=
|
|
160
|
+
django_ledger/models/ledger.py,sha256=kPxyKo5u0-2viifCY87Ms3xglmgrfiDAg0oJgsOrDwc,23603
|
|
161
|
+
django_ledger/models/mixins.py,sha256=s8ZjEjYQfmU88cLyFNKoiFi79_g1rTe1knEccV2WUXw,52122
|
|
162
162
|
django_ledger/models/purchase_order.py,sha256=CDibi90e7Yhpv_UiyP32mMcsQ0EUElXJ2r8pLzuS7yE,42729
|
|
163
|
-
django_ledger/models/transactions.py,sha256=
|
|
163
|
+
django_ledger/models/transactions.py,sha256=kOL7s-hiRc6iqS7J62bVJY6ikja9Q8WdkRq0FT0zO2U,22722
|
|
164
164
|
django_ledger/models/unit.py,sha256=x5FFJXgOi1OdajQejIakW6wGY4DjrJhL3S0Pm5OimMk,8074
|
|
165
165
|
django_ledger/models/utils.py,sha256=3gkdCrfJp9qwN3Sf8R96AliilzwcKBm31UEao4WJO9o,8436
|
|
166
166
|
django_ledger/models/vendor.py,sha256=akJCO86GIwjlZ_jPUZCDXlMeuJe-8zKTm-52aJXGFpg,11320
|
|
@@ -275,7 +275,7 @@ django_ledger/templates/django_ledger/expense/tags/expense_item_table.html,sha25
|
|
|
275
275
|
django_ledger/templates/django_ledger/financial_statements/balance_sheet.html,sha256=rFzmK2-AjV_11fp7b6ou-KtMSwm7jN3vfpd4Ki_9-s0,2793
|
|
276
276
|
django_ledger/templates/django_ledger/financial_statements/cash_flow.html,sha256=zeu7OcXl2T_vDoFyJvb0htFIjQz0IfyJBiOcck2skus,3031
|
|
277
277
|
django_ledger/templates/django_ledger/financial_statements/income_statement.html,sha256=pfrv12Bu_PmU-MrL7JXYX7Wv4PZ06fKvOdydzzgeEnw,2731
|
|
278
|
-
django_ledger/templates/django_ledger/financial_statements/tags/balance_sheet_statement.html,sha256=
|
|
278
|
+
django_ledger/templates/django_ledger/financial_statements/tags/balance_sheet_statement.html,sha256=u2o3krlo_I7w-erXI9DO4gNChbYn0KpdeLRZs7UckOQ,6430
|
|
279
279
|
django_ledger/templates/django_ledger/financial_statements/tags/cash_flow_statement.html,sha256=elJsMVmVJHZbZVhuo-bSykrrLoSZrN0JpUYm0LukY80,8961
|
|
280
280
|
django_ledger/templates/django_ledger/financial_statements/tags/income_statement.html,sha256=kLmnxHN5G9H7xYKFANLbfM0jAtNsmfhIrdltW-bhoPY,10442
|
|
281
281
|
django_ledger/templates/django_ledger/includes/breadcrumbs.html,sha256=mSzAPpn7uCx33oXuNhbM-MQdam3QFOxl9TRH93hrS4w,183
|
|
@@ -353,7 +353,7 @@ django_ledger/templates/django_ledger/vendor/vendor_update.html,sha256=4kBUlGgrg
|
|
|
353
353
|
django_ledger/templates/django_ledger/vendor/includes/card_vendor.html,sha256=oCXyuqyF7CnJnDQdK0G0jdYLqtPWYSzwlv8oddyGJg8,1290
|
|
354
354
|
django_ledger/templates/django_ledger/vendor/tags/vendor_table.html,sha256=YC-3T5x4oua3VBg1q690CRzoogKL8qFgQRp5jTKLFgk,3400
|
|
355
355
|
django_ledger/templatetags/__init__.py,sha256=N7iaeMO5xTU-q7RXTVYUy-fu8nMZbiIJ9QEtDCjsTdI,205
|
|
356
|
-
django_ledger/templatetags/django_ledger.py,sha256=
|
|
356
|
+
django_ledger/templatetags/django_ledger.py,sha256=2fzaHJVc3O9t0UuQICx7YAwAPzsP2lv4rOYFPiRAlfA,31676
|
|
357
357
|
django_ledger/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
358
358
|
django_ledger/tests/base.py,sha256=Be7BS_bc_m-hCTkBRnvHYfvAfgCcVOsU-He9ON6rOCc,10279
|
|
359
359
|
django_ledger/tests/test_accounts.py,sha256=WznTiYkxGcmeZ0W75ATpMsZGWrtmNV4voe4oLMCpveo,717
|
|
@@ -401,7 +401,7 @@ django_ledger/views/coa.py,sha256=WnWQVz-4Ik9v28KHzD_WiKcgix7l6bBj1A60p4k-eos,49
|
|
|
401
401
|
django_ledger/views/customer.py,sha256=RoBsXBxZC9b79DSNNHaoSZtQ2AoXf7DJAGmZEO3xdxs,3672
|
|
402
402
|
django_ledger/views/data_import.py,sha256=_H8gjGRIE2Jm97ivvEQn0uEWrM3VvKkYQeXQ1GbKn3g,11950
|
|
403
403
|
django_ledger/views/djl_api.py,sha256=6ADX9fBK8DroTeg8UIeCf2x4wt6-AF5xLlDQnqXBfsM,4411
|
|
404
|
-
django_ledger/views/entity.py,sha256=
|
|
404
|
+
django_ledger/views/entity.py,sha256=f6Fd5YsGbym5Jf3XvbhYCQVm4o5odNLrqVmch8vpGsg,9468
|
|
405
405
|
django_ledger/views/estimate.py,sha256=ZFG0k2_nAV10EjO-p8yp7EVMa4x2qOcFSHl2xFpNDaM,12811
|
|
406
406
|
django_ledger/views/feedback.py,sha256=qoIN44fJnblPx-pJFe5yYeO-dMqp-FReFZiyw0qQb_s,2460
|
|
407
407
|
django_ledger/views/financial_statement.py,sha256=B4FE9qyBYs8tJvBJ1n9-7kR-pH2EJWn6SnjBdtbRfuE,7335
|
|
@@ -411,14 +411,14 @@ django_ledger/views/invoice.py,sha256=iUzTG-EbdYqNX-eYwHBnQRUD_1wTOGutw0BfDMKcI6
|
|
|
411
411
|
django_ledger/views/item.py,sha256=FY53vk_giTRgvJ47FRqChQ8vyDYPDp4DGTvVhGAb36E,21347
|
|
412
412
|
django_ledger/views/journal_entry.py,sha256=21kuiRBlhlkgv8xZKM4mj9djv0Fu0BhB80QOEOHCa-w,12135
|
|
413
413
|
django_ledger/views/ledger.py,sha256=Yk6uDoYhJs5vf5JRqsy8n0nUNDEHk7NzjR1PglyqaAM,12647
|
|
414
|
-
django_ledger/views/mixins.py,sha256=
|
|
414
|
+
django_ledger/views/mixins.py,sha256=SgsR9XWKgsJoQ2pCKkdHlNt93XiUa8bkTKTD0fjj8NI,23370
|
|
415
415
|
django_ledger/views/purchase_order.py,sha256=1J3u4QnCkM7z1Y6DePijVdM67x4CQgfmQJcs3Y4kclU,21082
|
|
416
416
|
django_ledger/views/transactions.py,sha256=5taQRGLSMkM_N8paQJ07HMspI_Nl7PawF8OohCiRmao,206
|
|
417
417
|
django_ledger/views/unit.py,sha256=_RgPJO9mR6v5ohBXlnL3T8nTWgS1lwlCvERQcHk0wHE,10232
|
|
418
418
|
django_ledger/views/vendor.py,sha256=gUdBPTFLeSwlNfdHSA1KFdE_y3QpwpkFhEB0r3-UYdI,3461
|
|
419
|
-
django_ledger-0.6.
|
|
420
|
-
django_ledger-0.6.
|
|
421
|
-
django_ledger-0.6.
|
|
422
|
-
django_ledger-0.6.
|
|
423
|
-
django_ledger-0.6.
|
|
424
|
-
django_ledger-0.6.
|
|
419
|
+
django_ledger-0.6.2.dist-info/AUTHORS.md,sha256=SRM2cynD89ZfEsL09zrbUVeO17r9zE2ZM7y6ReMqVRo,713
|
|
420
|
+
django_ledger-0.6.2.dist-info/LICENSE,sha256=ixuiBLtpoK3iv89l7ylKkg9rs2GzF9ukPH7ynZYzK5s,35148
|
|
421
|
+
django_ledger-0.6.2.dist-info/METADATA,sha256=hGmUnvHJ9byl1Du4AKDEwNxw5aWk1ibCATLKSjM2sDc,9641
|
|
422
|
+
django_ledger-0.6.2.dist-info/WHEEL,sha256=yQN5g4mg4AybRjkgi-9yy4iQEFibGQmlz78Pik5Or-A,92
|
|
423
|
+
django_ledger-0.6.2.dist-info/top_level.txt,sha256=0U3SjF63ND36grQNWDONVe-T9-T07lFl5e6QkG7bR2E,44
|
|
424
|
+
django_ledger-0.6.2.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|