django-ledger 0.7.10__py3-none-any.whl → 0.8.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/context.py +12 -0
- django_ledger/forms/bill.py +0 -4
- django_ledger/forms/closing_entry.py +13 -1
- django_ledger/forms/data_import.py +1 -1
- django_ledger/forms/estimate.py +3 -6
- django_ledger/forms/invoice.py +3 -7
- django_ledger/forms/item.py +10 -18
- django_ledger/forms/purchase_order.py +2 -4
- django_ledger/io/io_core.py +25 -32
- django_ledger/io/io_generator.py +7 -6
- django_ledger/io/io_library.py +1 -2
- django_ledger/migrations/0024_billmodel_entity_model_invoicemodel_entity_model.py +24 -0
- django_ledger/migrations/0025_alter_billmodel_cash_account_and_more.py +70 -0
- django_ledger/models/accounts.py +109 -69
- django_ledger/models/bank_account.py +40 -23
- django_ledger/models/bill.py +89 -63
- django_ledger/models/chart_of_accounts.py +173 -105
- django_ledger/models/closing_entry.py +99 -48
- django_ledger/models/customer.py +60 -39
- django_ledger/models/data_import.py +55 -41
- django_ledger/models/deprecations.py +61 -0
- django_ledger/models/entity.py +18 -16
- django_ledger/models/estimate.py +57 -28
- django_ledger/models/invoice.py +58 -28
- django_ledger/models/items.py +503 -142
- django_ledger/models/journal_entry.py +61 -47
- django_ledger/models/ledger.py +106 -42
- django_ledger/models/mixins.py +16 -10
- django_ledger/models/purchase_order.py +39 -17
- django_ledger/models/transactions.py +152 -113
- django_ledger/models/unit.py +57 -30
- django_ledger/models/vendor.py +75 -43
- django_ledger/report/core.py +2 -14
- django_ledger/settings.py +56 -71
- django_ledger/static/django_ledger/bundle/djetler.bundle.js +1 -1
- django_ledger/static/django_ledger/bundle/djetler.bundle.js.LICENSE.txt +25 -0
- django_ledger/static/django_ledger/bundle/styles.bundle.js +1 -1
- django_ledger/static/django_ledger/css/djl_styles.css +273 -0
- django_ledger/templates/django_ledger/bills/includes/card_bill.html +2 -2
- django_ledger/templates/django_ledger/components/menu.html +41 -26
- django_ledger/templates/django_ledger/customer/tags/customer_table.html +5 -5
- django_ledger/templates/django_ledger/entity/includes/card_entity.html +12 -6
- django_ledger/templates/django_ledger/financial_statements/balance_sheet.html +1 -1
- django_ledger/templates/django_ledger/financial_statements/cash_flow.html +4 -1
- django_ledger/templates/django_ledger/financial_statements/income_statement.html +4 -1
- django_ledger/templates/django_ledger/financial_statements/tags/balance_sheet_statement.html +27 -3
- django_ledger/templates/django_ledger/financial_statements/tags/cash_flow_statement.html +16 -4
- django_ledger/templates/django_ledger/financial_statements/tags/income_statement.html +73 -18
- django_ledger/templates/django_ledger/includes/widget_ratios.html +18 -24
- django_ledger/templates/django_ledger/invoice/includes/card_invoice.html +3 -3
- django_ledger/templates/django_ledger/layouts/base.html +6 -1
- django_ledger/templates/django_ledger/vendor/tags/vendor_table.html +9 -5
- django_ledger/tests/test_accounts.py +1 -2
- django_ledger/tests/test_io.py +17 -0
- django_ledger/tests/test_purchase_order.py +3 -3
- django_ledger/tests/test_transactions.py +1 -2
- django_ledger/urls/__init__.py +0 -4
- django_ledger/views/bill.py +8 -13
- django_ledger/views/chart_of_accounts.py +6 -4
- django_ledger/views/closing_entry.py +11 -7
- django_ledger/views/customer.py +13 -17
- django_ledger/views/data_import.py +7 -6
- django_ledger/views/djl_api.py +3 -5
- django_ledger/views/entity.py +2 -4
- django_ledger/views/estimate.py +3 -7
- django_ledger/views/inventory.py +3 -5
- django_ledger/views/invoice.py +4 -6
- django_ledger/views/item.py +7 -11
- django_ledger/views/journal_entry.py +1 -2
- django_ledger/views/mixins.py +25 -19
- django_ledger/views/purchase_order.py +24 -35
- django_ledger/views/unit.py +1 -2
- django_ledger/views/vendor.py +1 -2
- {django_ledger-0.7.10.dist-info → django_ledger-0.8.0.dist-info}/METADATA +43 -75
- {django_ledger-0.7.10.dist-info → django_ledger-0.8.0.dist-info}/RECORD +80 -108
- {django_ledger-0.7.10.dist-info → django_ledger-0.8.0.dist-info}/WHEEL +1 -1
- django_ledger-0.8.0.dist-info/top_level.txt +1 -0
- django_ledger/contrib/django_ledger_graphene/__init__.py +0 -0
- django_ledger/contrib/django_ledger_graphene/accounts/schema.py +0 -33
- django_ledger/contrib/django_ledger_graphene/api.py +0 -42
- django_ledger/contrib/django_ledger_graphene/apps.py +0 -6
- django_ledger/contrib/django_ledger_graphene/auth/mutations.py +0 -49
- django_ledger/contrib/django_ledger_graphene/auth/schema.py +0 -6
- django_ledger/contrib/django_ledger_graphene/bank_account/mutations.py +0 -61
- django_ledger/contrib/django_ledger_graphene/bank_account/schema.py +0 -34
- django_ledger/contrib/django_ledger_graphene/bill/mutations.py +0 -0
- django_ledger/contrib/django_ledger_graphene/bill/schema.py +0 -34
- django_ledger/contrib/django_ledger_graphene/coa/mutations.py +0 -0
- django_ledger/contrib/django_ledger_graphene/coa/schema.py +0 -30
- django_ledger/contrib/django_ledger_graphene/customers/__init__.py +0 -0
- django_ledger/contrib/django_ledger_graphene/customers/mutations.py +0 -71
- django_ledger/contrib/django_ledger_graphene/customers/schema.py +0 -43
- django_ledger/contrib/django_ledger_graphene/data_import/mutations.py +0 -0
- django_ledger/contrib/django_ledger_graphene/data_import/schema.py +0 -0
- django_ledger/contrib/django_ledger_graphene/entity/mutations.py +0 -0
- django_ledger/contrib/django_ledger_graphene/entity/schema.py +0 -94
- django_ledger/contrib/django_ledger_graphene/item/mutations.py +0 -0
- django_ledger/contrib/django_ledger_graphene/item/schema.py +0 -31
- django_ledger/contrib/django_ledger_graphene/journal_entry/mutations.py +0 -0
- django_ledger/contrib/django_ledger_graphene/journal_entry/schema.py +0 -35
- django_ledger/contrib/django_ledger_graphene/ledger/mutations.py +0 -0
- django_ledger/contrib/django_ledger_graphene/ledger/schema.py +0 -32
- django_ledger/contrib/django_ledger_graphene/purchase_order/mutations.py +0 -0
- django_ledger/contrib/django_ledger_graphene/purchase_order/schema.py +0 -31
- django_ledger/contrib/django_ledger_graphene/transaction/mutations.py +0 -0
- django_ledger/contrib/django_ledger_graphene/transaction/schema.py +0 -36
- django_ledger/contrib/django_ledger_graphene/unit/mutations.py +0 -0
- django_ledger/contrib/django_ledger_graphene/unit/schema.py +0 -27
- django_ledger/contrib/django_ledger_graphene/vendor/mutations.py +0 -0
- django_ledger/contrib/django_ledger_graphene/vendor/schema.py +0 -37
- django_ledger/contrib/django_ledger_graphene/views.py +0 -12
- django_ledger-0.7.10.dist-info/top_level.txt +0 -4
- {django_ledger-0.7.10.dist-info → django_ledger-0.8.0.dist-info/licenses}/AUTHORS.md +0 -0
- {django_ledger-0.7.10.dist-info → django_ledger-0.8.0.dist-info/licenses}/LICENSE +0 -0
|
@@ -26,12 +26,13 @@ class ImportJobModelViewBaseView(DjangoLedgerSecurityMixIn):
|
|
|
26
26
|
def get_queryset(self):
|
|
27
27
|
if self.queryset is None:
|
|
28
28
|
self.queryset = ImportJobModel.objects.for_entity(
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
29
|
+
entity_model=self.AUTHORIZED_ENTITY_MODEL,
|
|
30
|
+
).order_by('-created').select_related(
|
|
31
|
+
'bank_account_model',
|
|
32
|
+
'bank_account_model__entity_model',
|
|
33
|
+
'bank_account_model__account_model',
|
|
34
|
+
'bank_account_model__account_model__coa_model'
|
|
35
|
+
)
|
|
35
36
|
return self.queryset
|
|
36
37
|
|
|
37
38
|
|
django_ledger/views/djl_api.py
CHANGED
|
@@ -73,8 +73,7 @@ class PayableNetAPIView(DjangoLedgerSecurityMixIn, EntityUnitMixIn, View):
|
|
|
73
73
|
def get(self, request, *args, **kwargs):
|
|
74
74
|
if request.user.is_authenticated:
|
|
75
75
|
bill_qs = BillModel.objects.for_entity(
|
|
76
|
-
|
|
77
|
-
user_model=request.user,
|
|
76
|
+
entity_model=self.AUTHORIZED_ENTITY_MODEL
|
|
78
77
|
).unpaid()
|
|
79
78
|
|
|
80
79
|
# todo: implement this...
|
|
@@ -105,9 +104,8 @@ class ReceivableNetAPIView(DjangoLedgerSecurityMixIn, EntityUnitMixIn, View):
|
|
|
105
104
|
def get(self, request, *args, **kwargs):
|
|
106
105
|
if request.user.is_authenticated:
|
|
107
106
|
invoice_qs = InvoiceModel.objects.for_entity(
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
).unpaid()
|
|
107
|
+
entity_model=self.kwargs['entity_slug']
|
|
108
|
+
).for_user(self.request.user).unpaid()
|
|
111
109
|
|
|
112
110
|
# todo: implement this...
|
|
113
111
|
# unit_slug = self.get_unit_slug()
|
django_ledger/views/entity.py
CHANGED
|
@@ -146,13 +146,11 @@ class EntityDeleteView(DjangoLedgerSecurityMixIn, EntityModelModelViewQuerySetMi
|
|
|
146
146
|
entity_model.save(update_fields=['default_coa'])
|
|
147
147
|
|
|
148
148
|
ItemTransactionModel.objects.for_entity(
|
|
149
|
-
|
|
150
|
-
entity_slug=self.kwargs['entity_slug']
|
|
149
|
+
entity_model=self.AUTHORIZED_ENTITY_MODEL
|
|
151
150
|
).delete()
|
|
152
151
|
|
|
153
152
|
TransactionModel.objects.for_entity(
|
|
154
|
-
|
|
155
|
-
entity_slug=self.kwargs['entity_slug']
|
|
153
|
+
entity_model=self.kwargs['entity_slug']
|
|
156
154
|
).delete()
|
|
157
155
|
|
|
158
156
|
return super().form_valid(form=form)
|
django_ledger/views/estimate.py
CHANGED
|
@@ -6,7 +6,6 @@ Contributions to this module:
|
|
|
6
6
|
* Miguel Sanda <msanda@arrobalytics.com>
|
|
7
7
|
"""
|
|
8
8
|
|
|
9
|
-
|
|
10
9
|
from django.contrib import messages
|
|
11
10
|
from django.core.exceptions import ValidationError, ImproperlyConfigured
|
|
12
11
|
from django.http import HttpResponseRedirect, HttpResponseForbidden
|
|
@@ -102,20 +101,17 @@ class EstimateModelDetailView(DjangoLedgerSecurityMixIn, EstimateModelModelViewQ
|
|
|
102
101
|
|
|
103
102
|
# PO Model Queryset...
|
|
104
103
|
po_qs = ce_model.purchaseordermodel_set.for_entity(
|
|
105
|
-
|
|
106
|
-
entity_slug=self.kwargs['entity_slug']
|
|
104
|
+
entity_model=self.kwargs['entity_slug']
|
|
107
105
|
) if ce_model.is_approved() else ce_model.purchaseordermodel_set.none()
|
|
108
106
|
context['estimate_po_model_queryset'] = po_qs
|
|
109
107
|
|
|
110
108
|
invoice_qs = ce_model.invoicemodel_set.for_entity(
|
|
111
|
-
|
|
112
|
-
entity_slug=self.kwargs['entity_slug']
|
|
109
|
+
entity_model=self.kwargs['entity_slug']
|
|
113
110
|
) if ce_model.is_approved() else ce_model.invoicemodel_set.none()
|
|
114
111
|
context['estimate_invoice_model_queryset'] = invoice_qs
|
|
115
112
|
|
|
116
113
|
bill_qs = ce_model.billmodel_set.for_entity(
|
|
117
|
-
|
|
118
|
-
entity_slug=self.kwargs['entity_slug']
|
|
114
|
+
entity_model=self.kwargs['entity_slug']
|
|
119
115
|
) if ce_model.is_approved() else ce_model.billmodel_set.none()
|
|
120
116
|
context['estimate_bill_model_queryset'] = bill_qs
|
|
121
117
|
|
django_ledger/views/inventory.py
CHANGED
|
@@ -51,7 +51,7 @@ class InventoryListView(DjangoLedgerSecurityMixIn, ListView):
|
|
|
51
51
|
def get_queryset(self):
|
|
52
52
|
if self.queryset is None:
|
|
53
53
|
self.queryset = ItemTransactionModel.objects.inventory_pipeline_aggregate(
|
|
54
|
-
|
|
54
|
+
entity_model=self.AUTHORIZED_ENTITY_MODEL
|
|
55
55
|
)
|
|
56
56
|
return super().get_queryset()
|
|
57
57
|
|
|
@@ -69,12 +69,10 @@ class InventoryRecountView(DjangoLedgerSecurityMixIn, DetailView):
|
|
|
69
69
|
return super().get_queryset()
|
|
70
70
|
|
|
71
71
|
def counted_inventory(self):
|
|
72
|
-
|
|
73
|
-
return ItemTransactionModel.objects.inventory_count(entity_slug=entity_slug)
|
|
72
|
+
return ItemTransactionModel.objects.inventory_count(entity_model=self.AUTHORIZED_ENTITY_MODEL)
|
|
74
73
|
|
|
75
74
|
def recorded_inventory(self, queryset=None, as_values=True):
|
|
76
|
-
entity_model: EntityModel = self.
|
|
77
|
-
user_model = self.request.user
|
|
75
|
+
entity_model: EntityModel = self.AUTHORIZED_ENTITY_MODEL
|
|
78
76
|
recorded_qs = entity_model.recorded_inventory(item_qs=queryset)
|
|
79
77
|
return recorded_qs
|
|
80
78
|
|
django_ledger/views/invoice.py
CHANGED
|
@@ -33,8 +33,7 @@ class InvoiceModelModelViewQuerySetMixIn:
|
|
|
33
33
|
def get_queryset(self):
|
|
34
34
|
if self.queryset is None:
|
|
35
35
|
self.queryset = InvoiceModel.objects.for_entity(
|
|
36
|
-
|
|
37
|
-
user_model=self.request.user
|
|
36
|
+
entity_model=self.kwargs['entity_slug']
|
|
38
37
|
).select_related('customer', 'ledger').order_by('-created')
|
|
39
38
|
return super().get_queryset()
|
|
40
39
|
|
|
@@ -97,8 +96,7 @@ class InvoiceModelCreateView(DjangoLedgerSecurityMixIn, InvoiceModelModelViewQue
|
|
|
97
96
|
'ce_pk': self.kwargs['ce_pk']
|
|
98
97
|
})
|
|
99
98
|
estimate_qs = EstimateModel.objects.for_entity(
|
|
100
|
-
|
|
101
|
-
user_model=self.request.user
|
|
99
|
+
entity_model=self.AUTHORIZED_ENTITY_MODEL,
|
|
102
100
|
).select_related('customer')
|
|
103
101
|
estimate_model = get_object_or_404(estimate_qs, uuid__exact=self.kwargs['ce_pk'])
|
|
104
102
|
context['estimate_model'] = estimate_model
|
|
@@ -138,8 +136,8 @@ class InvoiceModelCreateView(DjangoLedgerSecurityMixIn, InvoiceModelModelViewQue
|
|
|
138
136
|
if self.for_estimate:
|
|
139
137
|
ce_pk = self.kwargs['ce_pk']
|
|
140
138
|
estimate_model_qs = EstimateModel.objects.for_entity(
|
|
141
|
-
|
|
142
|
-
|
|
139
|
+
entity_model=self.AUTHORIZED_ENTITY_MODEL,
|
|
140
|
+
)
|
|
143
141
|
|
|
144
142
|
estimate_model = get_object_or_404(estimate_model_qs, uuid__exact=ce_pk)
|
|
145
143
|
invoice_model.bind_estimate(estimate_model=estimate_model, commit=False)
|
django_ledger/views/item.py
CHANGED
|
@@ -21,21 +21,21 @@ from django_ledger.forms.item import (
|
|
|
21
21
|
ExpenseItemCreateForm, ExpenseItemUpdateForm, InventoryItemCreateForm, InventoryItemUpdateForm,
|
|
22
22
|
ServiceCreateForm, ServiceUpdateForm
|
|
23
23
|
)
|
|
24
|
-
from django_ledger.models import ItemModel, UnitOfMeasureModel, EntityModel
|
|
24
|
+
from django_ledger.models import ItemModel, UnitOfMeasureModel, EntityModel, UnitOfMeasureModelQuerySet
|
|
25
25
|
from django_ledger.views.mixins import DjangoLedgerSecurityMixIn
|
|
26
26
|
|
|
27
27
|
|
|
28
28
|
# todo: Create delete views...
|
|
29
29
|
|
|
30
|
-
# UNIT OF MEASURE VIEWS
|
|
30
|
+
# UNIT OF MEASURE VIEWS...
|
|
31
31
|
class UnitOfMeasureModelModelBaseView(DjangoLedgerSecurityMixIn):
|
|
32
|
-
queryset = None
|
|
32
|
+
queryset: UnitOfMeasureModelQuerySet = None
|
|
33
33
|
|
|
34
34
|
def get_queryset(self):
|
|
35
35
|
if self.queryset is None:
|
|
36
36
|
entity_model: EntityModel = self.get_authorized_entity_instance()
|
|
37
37
|
self.queryset = entity_model.unitofmeasuremodel_set.all()
|
|
38
|
-
return
|
|
38
|
+
return self.queryset
|
|
39
39
|
|
|
40
40
|
|
|
41
41
|
class UnitOfMeasureModelListView(UnitOfMeasureModelModelBaseView, ListView):
|
|
@@ -75,9 +75,7 @@ class UnitOfMeasureModelCreateView(UnitOfMeasureModelModelBaseView, CreateView):
|
|
|
75
75
|
instance: UnitOfMeasureModel = form.save(commit=False)
|
|
76
76
|
entity_slug = self.kwargs['entity_slug']
|
|
77
77
|
try:
|
|
78
|
-
entity_model: EntityModel =
|
|
79
|
-
user_model=self.request.user
|
|
80
|
-
).get(slug__iexact=entity_slug)
|
|
78
|
+
entity_model: EntityModel = self.AUTHORIZED_ENTITY_MODEL
|
|
81
79
|
instance.entity = entity_model
|
|
82
80
|
except ObjectDoesNotExist:
|
|
83
81
|
add_message(self.request,
|
|
@@ -227,8 +225,7 @@ class ProductUpdateView(ProductItemModelModelBaseView, UpdateView):
|
|
|
227
225
|
|
|
228
226
|
def get_queryset(self):
|
|
229
227
|
return ItemModel.objects.for_entity(
|
|
230
|
-
|
|
231
|
-
user_model=self.request.user
|
|
228
|
+
entity_model=self.AUTHORIZED_ENTITY_MODEL
|
|
232
229
|
).products()
|
|
233
230
|
|
|
234
231
|
def get_form(self, form_class=None):
|
|
@@ -348,8 +345,7 @@ class ServiceUpdateView(ServiceItemModelModelBaseView, UpdateView):
|
|
|
348
345
|
|
|
349
346
|
def get_queryset(self):
|
|
350
347
|
return ItemModel.objects.for_entity(
|
|
351
|
-
|
|
352
|
-
user_model=self.request.user
|
|
348
|
+
entity_model=self.kwargs['entity_slug']
|
|
353
349
|
).services()
|
|
354
350
|
|
|
355
351
|
def get_form(self, form_class=None):
|
|
@@ -259,8 +259,7 @@ class BaseJournalEntryActionView(
|
|
|
259
259
|
|
|
260
260
|
def get_queryset(self):
|
|
261
261
|
return JournalEntryModel.objects.for_entity(
|
|
262
|
-
|
|
263
|
-
user_model=self.request.user
|
|
262
|
+
entity_model=self.AUTHORIZED_ENTITY_MODEL
|
|
264
263
|
).for_ledger(ledger_pk=self.kwargs['ledger_pk'])
|
|
265
264
|
|
|
266
265
|
def get_redirect_url(self, *args, **kwargs):
|
django_ledger/views/mixins.py
CHANGED
|
@@ -19,9 +19,9 @@ from django.utils.dateparse import parse_date
|
|
|
19
19
|
from django.utils.translation import gettext_lazy as _
|
|
20
20
|
from django.views.generic.dates import YearMixin, MonthMixin, DayMixin
|
|
21
21
|
|
|
22
|
-
from django_ledger.models import EntityModel, InvoiceModel, BillModel
|
|
22
|
+
from django_ledger.models import EntityModel, InvoiceModel, BillModel, LedgerModel
|
|
23
23
|
from django_ledger.models.entity import EntityModelFiscalPeriodMixIn
|
|
24
|
-
from django_ledger.settings import
|
|
24
|
+
from django_ledger.settings import DJANGO_LEDGER_AUTHORIZED_SUPERUSER
|
|
25
25
|
|
|
26
26
|
|
|
27
27
|
class ContextFromToDateMixin:
|
|
@@ -424,11 +424,13 @@ class DigestContextMixIn:
|
|
|
424
424
|
to_date=None,
|
|
425
425
|
**kwargs):
|
|
426
426
|
|
|
427
|
-
if any([
|
|
428
|
-
|
|
427
|
+
if any([
|
|
428
|
+
self.IO_DIGEST_UNBOUNDED,
|
|
429
|
+
self.IO_DIGEST_BOUNDED
|
|
430
|
+
]):
|
|
429
431
|
|
|
430
432
|
by_period = self.request.GET.get('by_period')
|
|
431
|
-
|
|
433
|
+
io_model: EntityModel | LedgerModel = self.object
|
|
432
434
|
if not to_date:
|
|
433
435
|
to_date = context['to_date']
|
|
434
436
|
if not from_date:
|
|
@@ -441,19 +443,22 @@ class DigestContextMixIn:
|
|
|
441
443
|
unit_slug = None
|
|
442
444
|
|
|
443
445
|
if self.IO_DIGEST_UNBOUNDED:
|
|
444
|
-
io_digest =
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
446
|
+
io_digest = io_model.digest(
|
|
447
|
+
user_model=self.request.user,
|
|
448
|
+
entity_slug=io_model.entity_slug if isinstance(io_model, LedgerModel) else None,
|
|
449
|
+
to_date=to_date,
|
|
450
|
+
unit_slug=unit_slug,
|
|
451
|
+
by_period=True if by_period else False,
|
|
452
|
+
process_ratios=True,
|
|
453
|
+
process_roles=True,
|
|
454
|
+
process_groups=True
|
|
455
|
+
)
|
|
451
456
|
|
|
452
457
|
context[self.get_io_manager_unbounded_context_name()] = io_digest
|
|
453
458
|
context[self.get_io_digest_unbounded_context_name()] = io_digest.get_io_data()
|
|
454
459
|
|
|
455
460
|
if self.IO_DIGEST_BOUNDED:
|
|
456
|
-
io_digest_equity =
|
|
461
|
+
io_digest_equity = io_model.digest(
|
|
457
462
|
user_model=self.request.user,
|
|
458
463
|
equity_only=True,
|
|
459
464
|
to_date=to_date,
|
|
@@ -489,8 +494,9 @@ class UnpaidElementsMixIn:
|
|
|
489
494
|
to_date = context['to_date'] if not to_date else to_date
|
|
490
495
|
|
|
491
496
|
qs = InvoiceModel.objects.for_entity(
|
|
492
|
-
|
|
493
|
-
|
|
497
|
+
entity_model=self.kwargs['entity_slug']
|
|
498
|
+
).for_user(
|
|
499
|
+
user_model=self.request.user
|
|
494
500
|
).approved().filter(
|
|
495
501
|
Q(date_approved__gte=from_date) &
|
|
496
502
|
Q(date_approved__lte=to_date)
|
|
@@ -508,14 +514,16 @@ class UnpaidElementsMixIn:
|
|
|
508
514
|
to_date = context['to_date'] if not to_date else to_date
|
|
509
515
|
|
|
510
516
|
qs = BillModel.objects.for_entity(
|
|
511
|
-
|
|
512
|
-
|
|
517
|
+
entity_model=self.kwargs['entity_slug']
|
|
518
|
+
).for_user(
|
|
519
|
+
user_model=self.request.user
|
|
513
520
|
).unpaid().filter(
|
|
514
521
|
Q(date_approved__gte=from_date) &
|
|
515
522
|
Q(date_approved__lte=to_date)
|
|
516
523
|
).select_related('vendor').order_by('date_due')
|
|
517
524
|
|
|
518
525
|
unit_slug = self.get_unit_slug()
|
|
526
|
+
|
|
519
527
|
if unit_slug:
|
|
520
528
|
qs = qs.filter(ledger__journal_entries__entity_unit__slug__exact=unit_slug)
|
|
521
529
|
|
|
@@ -595,8 +603,6 @@ class PDFReportMixIn:
|
|
|
595
603
|
return ctx['to_date']
|
|
596
604
|
|
|
597
605
|
def get_pdf_response(self) -> HttpResponse:
|
|
598
|
-
if not DJANGO_LEDGER_PDF_SUPPORT_ENABLED:
|
|
599
|
-
return HttpResponseNotFound(content='PDF format is not supported')
|
|
600
606
|
pdf = self.get_pdf()
|
|
601
607
|
response = HttpResponse(
|
|
602
608
|
bytes(pdf.output()),
|
|
@@ -23,21 +23,18 @@ from django_ledger.models import PurchaseOrderModel, ItemTransactionModel, Estim
|
|
|
23
23
|
from django_ledger.views.mixins import DjangoLedgerSecurityMixIn
|
|
24
24
|
|
|
25
25
|
|
|
26
|
-
class PurchaseOrderModelModelViewQuerySetMixIn:
|
|
26
|
+
class PurchaseOrderModelModelViewQuerySetMixIn(DjangoLedgerSecurityMixIn):
|
|
27
27
|
queryset = None
|
|
28
28
|
|
|
29
29
|
def get_queryset(self):
|
|
30
30
|
if self.queryset is None:
|
|
31
31
|
self.queryset = PurchaseOrderModel.objects.for_entity(
|
|
32
|
-
|
|
33
|
-
user_model=self.request.user
|
|
32
|
+
entity_model=self.AUTHORIZED_ENTITY_MODEL,
|
|
34
33
|
).select_related('entity', 'ce_model')
|
|
35
34
|
return super().get_queryset()
|
|
36
35
|
|
|
37
36
|
|
|
38
|
-
class PurchaseOrderModelListView(
|
|
39
|
-
PurchaseOrderModelModelViewQuerySetMixIn,
|
|
40
|
-
ArchiveIndexView):
|
|
37
|
+
class PurchaseOrderModelListView(PurchaseOrderModelModelViewQuerySetMixIn, ArchiveIndexView):
|
|
41
38
|
template_name = 'django_ledger/purchase_order/po_list.html'
|
|
42
39
|
context_object_name = 'po_list'
|
|
43
40
|
PAGE_TITLE = _('PO List')
|
|
@@ -76,9 +73,7 @@ class PurchaseOrderModelMonthListView(MonthArchiveView,
|
|
|
76
73
|
date_list_period = 'year'
|
|
77
74
|
|
|
78
75
|
|
|
79
|
-
class PurchaseOrderModelCreateView(
|
|
80
|
-
PurchaseOrderModelModelViewQuerySetMixIn,
|
|
81
|
-
CreateView):
|
|
76
|
+
class PurchaseOrderModelCreateView(PurchaseOrderModelModelViewQuerySetMixIn, CreateView):
|
|
82
77
|
template_name = 'django_ledger/purchase_order/po_create.html'
|
|
83
78
|
PAGE_TITLE = _('Create Purchase Order')
|
|
84
79
|
extra_context = {
|
|
@@ -92,8 +87,7 @@ class PurchaseOrderModelCreateView(DjangoLedgerSecurityMixIn,
|
|
|
92
87
|
response = super(PurchaseOrderModelCreateView, self).get(request, entity_slug, **kwargs)
|
|
93
88
|
if self.for_estimate and 'ce_pk' in self.kwargs:
|
|
94
89
|
estimate_qs = EstimateModel.objects.for_entity(
|
|
95
|
-
|
|
96
|
-
user_model=self.request.user
|
|
90
|
+
entity_model=self.AUTHORIZED_ENTITY_MODEL,
|
|
97
91
|
)
|
|
98
92
|
estimate_model: EstimateModel = get_object_or_404(estimate_qs, uuid__exact=self.kwargs['ce_pk'])
|
|
99
93
|
if not estimate_model.can_bind():
|
|
@@ -110,8 +104,7 @@ class PurchaseOrderModelCreateView(DjangoLedgerSecurityMixIn,
|
|
|
110
104
|
'ce_pk': self.kwargs['ce_pk']
|
|
111
105
|
})
|
|
112
106
|
estimate_qs = EstimateModel.objects.for_entity(
|
|
113
|
-
|
|
114
|
-
user_model=self.request.user
|
|
107
|
+
entity_model=self.AUTHORIZED_ENTITY_MODEL
|
|
115
108
|
).select_related('customer')
|
|
116
109
|
estimate_model = get_object_or_404(estimate_qs, uuid__exact=self.kwargs['ce_pk'])
|
|
117
110
|
context['estimate_model'] = estimate_model
|
|
@@ -125,23 +118,25 @@ class PurchaseOrderModelCreateView(DjangoLedgerSecurityMixIn,
|
|
|
125
118
|
|
|
126
119
|
def get_form(self, form_class=None):
|
|
127
120
|
entity_slug = self.kwargs['entity_slug']
|
|
128
|
-
form = PurchaseOrderModelCreateForm(
|
|
129
|
-
|
|
130
|
-
|
|
121
|
+
form = PurchaseOrderModelCreateForm(
|
|
122
|
+
entity_slug=entity_slug,
|
|
123
|
+
user_model=self.request.user,
|
|
124
|
+
**self.get_form_kwargs()
|
|
125
|
+
)
|
|
131
126
|
return form
|
|
132
127
|
|
|
133
128
|
def form_valid(self, form):
|
|
134
129
|
po_model: PurchaseOrderModel = form.save(commit=False)
|
|
135
130
|
po_model = po_model.configure(
|
|
136
131
|
entity_slug=self.kwargs['entity_slug'],
|
|
137
|
-
user_model=self.request.user
|
|
132
|
+
user_model=self.request.user
|
|
133
|
+
)
|
|
138
134
|
|
|
139
135
|
if self.for_estimate:
|
|
140
136
|
ce_pk = self.kwargs['ce_pk']
|
|
141
137
|
estimate_model_qs = EstimateModel.objects.for_entity(
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
)
|
|
138
|
+
entity_model=self.AUTHORIZED_ENTITY_MODEL,
|
|
139
|
+
).for_user(user_model=self.request.user)
|
|
145
140
|
estimate_model = get_object_or_404(estimate_model_qs, uuid__exact=ce_pk)
|
|
146
141
|
po_model.action_bind_estimate(estimate_model=estimate_model, commit=False)
|
|
147
142
|
return super().form_valid(form=form)
|
|
@@ -162,9 +157,7 @@ class PurchaseOrderModelCreateView(DjangoLedgerSecurityMixIn,
|
|
|
162
157
|
})
|
|
163
158
|
|
|
164
159
|
|
|
165
|
-
class PurchaseOrderModelUpdateView(
|
|
166
|
-
PurchaseOrderModelModelViewQuerySetMixIn,
|
|
167
|
-
UpdateView):
|
|
160
|
+
class PurchaseOrderModelUpdateView(PurchaseOrderModelModelViewQuerySetMixIn, UpdateView):
|
|
168
161
|
slug_url_kwarg = 'po_pk'
|
|
169
162
|
slug_field = 'uuid'
|
|
170
163
|
context_object_name = 'po_model'
|
|
@@ -322,8 +315,7 @@ class PurchaseOrderModelUpdateView(DjangoLedgerSecurityMixIn,
|
|
|
322
315
|
|
|
323
316
|
if form.has_changed():
|
|
324
317
|
po_items_qs = ItemTransactionModel.objects.for_po(
|
|
325
|
-
|
|
326
|
-
user_model=self.request.user,
|
|
318
|
+
entity_model=self.kwargs['entity_slug'],
|
|
327
319
|
po_pk=po_model.uuid,
|
|
328
320
|
).select_related('bill_model')
|
|
329
321
|
|
|
@@ -360,9 +352,7 @@ class PurchaseOrderModelUpdateView(DjangoLedgerSecurityMixIn,
|
|
|
360
352
|
return super().form_valid(form)
|
|
361
353
|
|
|
362
354
|
|
|
363
|
-
class PurchaseOrderModelDetailView(
|
|
364
|
-
PurchaseOrderModelModelViewQuerySetMixIn,
|
|
365
|
-
DetailView):
|
|
355
|
+
class PurchaseOrderModelDetailView(PurchaseOrderModelModelViewQuerySetMixIn, DetailView):
|
|
366
356
|
slug_url_kwarg = 'po_pk'
|
|
367
357
|
slug_field = 'uuid'
|
|
368
358
|
context_object_name = 'po_model'
|
|
@@ -390,9 +380,7 @@ class PurchaseOrderModelDetailView(DjangoLedgerSecurityMixIn,
|
|
|
390
380
|
return context
|
|
391
381
|
|
|
392
382
|
|
|
393
|
-
class PurchaseOrderModelDeleteView(
|
|
394
|
-
PurchaseOrderModelModelViewQuerySetMixIn,
|
|
395
|
-
DeleteView):
|
|
383
|
+
class PurchaseOrderModelDeleteView(PurchaseOrderModelModelViewQuerySetMixIn, DeleteView):
|
|
396
384
|
slug_url_kwarg = 'po_pk'
|
|
397
385
|
slug_field = 'uuid'
|
|
398
386
|
context_object_name = 'po_model'
|
|
@@ -436,10 +424,11 @@ class PurchaseOrderModelDeleteView(DjangoLedgerSecurityMixIn,
|
|
|
436
424
|
|
|
437
425
|
|
|
438
426
|
# ACTIONS...
|
|
439
|
-
class BasePurchaseOrderActionActionView(
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
427
|
+
class BasePurchaseOrderActionActionView(
|
|
428
|
+
PurchaseOrderModelModelViewQuerySetMixIn,
|
|
429
|
+
RedirectView,
|
|
430
|
+
SingleObjectMixin
|
|
431
|
+
):
|
|
443
432
|
http_method_names = ['get']
|
|
444
433
|
pk_url_kwarg = 'po_pk'
|
|
445
434
|
action_name = None
|
django_ledger/views/unit.py
CHANGED
|
@@ -28,8 +28,7 @@ class EntityUnitModelModelBaseView(DjangoLedgerSecurityMixIn):
|
|
|
28
28
|
def get_queryset(self):
|
|
29
29
|
if self.queryset is None:
|
|
30
30
|
self.queryset = EntityUnitModel.objects.for_entity(
|
|
31
|
-
|
|
32
|
-
user_model=self.request.user
|
|
31
|
+
entity_model=self.get_authorized_entity_instance()
|
|
33
32
|
).select_related('entity')
|
|
34
33
|
return super().get_queryset()
|
|
35
34
|
|
django_ledger/views/vendor.py
CHANGED
|
@@ -22,8 +22,7 @@ class VendorModelModelBaseView(DjangoLedgerSecurityMixIn):
|
|
|
22
22
|
def get_queryset(self):
|
|
23
23
|
if self.queryset is None:
|
|
24
24
|
self.queryset = VendorModel.objects.for_entity(
|
|
25
|
-
|
|
26
|
-
user_model=self.request.user
|
|
25
|
+
entity_model=self.kwargs['entity_slug']
|
|
27
26
|
).order_by('-updated')
|
|
28
27
|
return super().get_queryset()
|
|
29
28
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
2
|
Name: django-ledger
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.8.0
|
|
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>
|
|
@@ -18,26 +18,18 @@ Classifier: Framework :: Django :: 5.0
|
|
|
18
18
|
Classifier: Intended Audience :: Financial and Insurance Industry
|
|
19
19
|
Classifier: Intended Audience :: End Users/Desktop
|
|
20
20
|
Classifier: License :: OSI Approved :: GNU General Public License v3 or later (GPLv3+)
|
|
21
|
-
Requires-Python: >=3.
|
|
21
|
+
Requires-Python: >=3.11
|
|
22
22
|
Description-Content-Type: text/markdown
|
|
23
23
|
License-File: LICENSE
|
|
24
24
|
License-File: AUTHORS.md
|
|
25
|
-
Requires-Dist:
|
|
26
|
-
Requires-Dist: django>=
|
|
27
|
-
Requires-Dist:
|
|
28
|
-
Requires-Dist:
|
|
29
|
-
Requires-Dist: markdown>=3.
|
|
25
|
+
Requires-Dist: django>=4.2
|
|
26
|
+
Requires-Dist: django-treebeard>=4.7.1
|
|
27
|
+
Requires-Dist: faker>=37.6.0
|
|
28
|
+
Requires-Dist: fpdf2>=2.8.4
|
|
29
|
+
Requires-Dist: markdown>=3.9
|
|
30
30
|
Requires-Dist: ofxtools>=0.9.5
|
|
31
|
-
Requires-Dist: pillow>=
|
|
32
|
-
|
|
33
|
-
Requires-Dist: six>=1.16.0; python_version >= "2.7" and python_version not in "3.0, 3.1, 3.2, 3.3"
|
|
34
|
-
Requires-Dist: sqlparse>=0.4.3; python_version >= "3.5"
|
|
35
|
-
Provides-Extra: dev
|
|
36
|
-
Requires-Dist: sphinx~=4.5.0; extra == "dev"
|
|
37
|
-
Requires-Dist: behave~=1.2.6; extra == "dev"
|
|
38
|
-
Requires-Dist: pipenv-setup; extra == "dev"
|
|
39
|
-
Requires-Dist: pylint; extra == "dev"
|
|
40
|
-
Requires-Dist: furo; extra == "dev"
|
|
31
|
+
Requires-Dist: pillow>=11.3.0
|
|
32
|
+
Dynamic: license-file
|
|
41
33
|
|
|
42
34
|

|
|
43
35
|
|
|
@@ -72,8 +64,11 @@ Created and developed by [Miguel Sanda](https://www.miguelsanda.com).
|
|
|
72
64
|
|
|
73
65
|
## Getting Involved
|
|
74
66
|
|
|
75
|
-
All pull requests are welcome, as long as they address bugfixes, enhancements, new ideas, or add value to the project in
|
|
76
|
-
|
|
67
|
+
All pull requests are welcome, as long as they address bugfixes, enhancements, new ideas, or add value to the project in
|
|
68
|
+
any shape or form.
|
|
69
|
+
|
|
70
|
+
Please refrain from submitting pull requests that focus solely on code linting, auto-generated code,
|
|
71
|
+
refactoring, or similar cosmetic non-value add changes.
|
|
77
72
|
|
|
78
73
|
- **Feature Requests/Bug Reports**: Open an issue in the repository
|
|
79
74
|
- **For software customization, advanced features and consulting services**:
|
|
@@ -100,56 +95,12 @@ is [here](https://docs.djangoproject.com/en/4.2/intro/tutorial01/#creating-a-pro
|
|
|
100
95
|
Make sure you refer to the django version you are using.
|
|
101
96
|
|
|
102
97
|
The easiest way to start is to use the zero-config Django Ledger starter template. See
|
|
103
|
-
details [here](https://github.com/arrobalytics/django-ledger-starter).
|
|
104
|
-
project from scratch.
|
|
105
|
-
|
|
106
|
-
To create a new Django Ledger project:
|
|
107
|
-
|
|
108
|
-
* Make sure you have the latest version of python [here](https://www.python.org/) (recommended).
|
|
109
|
-
|
|
110
|
-
* Install Django:
|
|
111
|
-
|
|
112
|
-
```shell
|
|
113
|
-
pip install django
|
|
114
|
-
```
|
|
115
|
-
|
|
116
|
-
* Install Python [Pipenv](https://pipenv.pypa.io/en/latest/) (python package manager):
|
|
117
|
-
|
|
118
|
-
```shell script
|
|
119
|
-
pip install pipenv
|
|
120
|
-
```
|
|
98
|
+
details [here](https://github.com/arrobalytics/django-ledger-starter).
|
|
99
|
+
Otherwise, you may create your project from scratch.
|
|
121
100
|
|
|
122
|
-
|
|
101
|
+
## Adding Django Ledger to an existing project.
|
|
123
102
|
|
|
124
|
-
|
|
125
|
-
django-admin startproject django_ledger_project && cd django_ledger_project
|
|
126
|
-
```
|
|
127
|
-
|
|
128
|
-
* Install Django on you virtual environment.
|
|
129
|
-
|
|
130
|
-
```shell
|
|
131
|
-
pipenv install django
|
|
132
|
-
```
|
|
133
|
-
|
|
134
|
-
* Install Django Ledger
|
|
135
|
-
|
|
136
|
-
```shell script
|
|
137
|
-
pipenv install "django-ledger[graphql,pdf]"
|
|
138
|
-
```
|
|
139
|
-
|
|
140
|
-
Alternatively, you can use:
|
|
141
|
-
|
|
142
|
-
```shell script
|
|
143
|
-
pipenv install django-ledger\[graphql,pdf\]
|
|
144
|
-
```
|
|
145
|
-
|
|
146
|
-
* Activate your new virtual environment:
|
|
147
|
-
|
|
148
|
-
```shell
|
|
149
|
-
pipenv shell
|
|
150
|
-
```
|
|
151
|
-
|
|
152
|
-
* Add django_ledger to INSTALLED_APPS in you new Django Project.
|
|
103
|
+
### Add django_ledger to INSTALLED_APPS in you new Django Project.
|
|
153
104
|
|
|
154
105
|
```python
|
|
155
106
|
INSTALLED_APPS = [
|
|
@@ -159,16 +110,25 @@ INSTALLED_APPS = [
|
|
|
159
110
|
]
|
|
160
111
|
```
|
|
161
112
|
|
|
162
|
-
|
|
113
|
+
### Add Django Ledger Context Preprocessor
|
|
163
114
|
|
|
164
|
-
```
|
|
165
|
-
|
|
115
|
+
```python
|
|
116
|
+
TEMPLATES = [
|
|
117
|
+
{
|
|
118
|
+
'OPTIONS': {
|
|
119
|
+
'context_processors': [
|
|
120
|
+
'...',
|
|
121
|
+
'django_ledger.context.django_ledger_context' # Add this line to a context_processors list..
|
|
122
|
+
],
|
|
123
|
+
},
|
|
124
|
+
},
|
|
125
|
+
]
|
|
166
126
|
```
|
|
167
127
|
|
|
168
|
-
|
|
128
|
+
### Perform database migrations:
|
|
169
129
|
|
|
170
130
|
```shell
|
|
171
|
-
python manage.py
|
|
131
|
+
python manage.py migrate
|
|
172
132
|
```
|
|
173
133
|
|
|
174
134
|
* Add URLs to your project's __urls.py__:
|
|
@@ -183,7 +143,7 @@ urlpatterns = [
|
|
|
183
143
|
]
|
|
184
144
|
```
|
|
185
145
|
|
|
186
|
-
|
|
146
|
+
### Run your project:
|
|
187
147
|
|
|
188
148
|
```shell
|
|
189
149
|
python manage.py runserver
|
|
@@ -194,7 +154,15 @@ python manage.py runserver
|
|
|
194
154
|
if you followed this installation guide).
|
|
195
155
|
* Use your superuser credentials to login.
|
|
196
156
|
|
|
197
|
-
|
|
157
|
+
## Deprecated behavior setting (v0.8.0+)
|
|
158
|
+
|
|
159
|
+
Starting with version v0.8.0, Django Ledger introduces the DJANGO_LEDGER_USE_DEPRECATED_BEHAVIOR setting to control
|
|
160
|
+
access to deprecated features and legacy behaviors.
|
|
161
|
+
|
|
162
|
+
- Default: False (deprecated features are disabled by default)
|
|
163
|
+
- To temporarily keep using deprecated features while you transition, set this to True in your Django settings.
|
|
164
|
+
|
|
165
|
+
## Setting Up Django Ledger for Development
|
|
198
166
|
|
|
199
167
|
Django Ledger comes with a basic development environment already configured under __dev_env/__ folder not to be used
|
|
200
168
|
for production environments. If you want to contribute to the project perform the following steps:
|