django-ledger 0.7.11__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.

Files changed (114) hide show
  1. django_ledger/__init__.py +1 -1
  2. django_ledger/context.py +12 -0
  3. django_ledger/forms/bill.py +0 -4
  4. django_ledger/forms/closing_entry.py +13 -1
  5. django_ledger/forms/data_import.py +1 -1
  6. django_ledger/forms/estimate.py +3 -6
  7. django_ledger/forms/invoice.py +3 -7
  8. django_ledger/forms/item.py +10 -18
  9. django_ledger/forms/purchase_order.py +2 -4
  10. django_ledger/io/io_core.py +8 -26
  11. django_ledger/io/io_generator.py +7 -6
  12. django_ledger/io/io_library.py +1 -2
  13. django_ledger/migrations/0025_alter_billmodel_cash_account_and_more.py +70 -0
  14. django_ledger/models/accounts.py +109 -69
  15. django_ledger/models/bank_account.py +40 -23
  16. django_ledger/models/bill.py +79 -63
  17. django_ledger/models/chart_of_accounts.py +173 -105
  18. django_ledger/models/closing_entry.py +99 -48
  19. django_ledger/models/customer.py +60 -39
  20. django_ledger/models/data_import.py +55 -41
  21. django_ledger/models/deprecations.py +61 -0
  22. django_ledger/models/entity.py +18 -16
  23. django_ledger/models/estimate.py +57 -28
  24. django_ledger/models/invoice.py +46 -26
  25. django_ledger/models/items.py +503 -142
  26. django_ledger/models/journal_entry.py +61 -47
  27. django_ledger/models/ledger.py +106 -42
  28. django_ledger/models/mixins.py +5 -3
  29. django_ledger/models/purchase_order.py +39 -17
  30. django_ledger/models/transactions.py +152 -113
  31. django_ledger/models/unit.py +57 -30
  32. django_ledger/models/vendor.py +75 -43
  33. django_ledger/report/core.py +2 -14
  34. django_ledger/settings.py +56 -71
  35. django_ledger/static/django_ledger/bundle/djetler.bundle.js +1 -1
  36. django_ledger/static/django_ledger/bundle/djetler.bundle.js.LICENSE.txt +25 -0
  37. django_ledger/static/django_ledger/bundle/styles.bundle.js +1 -1
  38. django_ledger/static/django_ledger/css/djl_styles.css +273 -0
  39. django_ledger/templates/django_ledger/bills/includes/card_bill.html +2 -2
  40. django_ledger/templates/django_ledger/components/menu.html +41 -26
  41. django_ledger/templates/django_ledger/customer/tags/customer_table.html +5 -5
  42. django_ledger/templates/django_ledger/entity/includes/card_entity.html +12 -6
  43. django_ledger/templates/django_ledger/financial_statements/balance_sheet.html +1 -1
  44. django_ledger/templates/django_ledger/financial_statements/cash_flow.html +4 -1
  45. django_ledger/templates/django_ledger/financial_statements/income_statement.html +4 -1
  46. django_ledger/templates/django_ledger/financial_statements/tags/balance_sheet_statement.html +27 -3
  47. django_ledger/templates/django_ledger/financial_statements/tags/cash_flow_statement.html +16 -4
  48. django_ledger/templates/django_ledger/financial_statements/tags/income_statement.html +73 -18
  49. django_ledger/templates/django_ledger/includes/widget_ratios.html +18 -24
  50. django_ledger/templates/django_ledger/invoice/includes/card_invoice.html +3 -3
  51. django_ledger/templates/django_ledger/layouts/base.html +6 -1
  52. django_ledger/templates/django_ledger/vendor/tags/vendor_table.html +9 -5
  53. django_ledger/tests/test_accounts.py +1 -2
  54. django_ledger/tests/test_io.py +17 -0
  55. django_ledger/tests/test_purchase_order.py +3 -3
  56. django_ledger/tests/test_transactions.py +1 -2
  57. django_ledger/urls/__init__.py +0 -4
  58. django_ledger/views/bill.py +8 -11
  59. django_ledger/views/chart_of_accounts.py +6 -4
  60. django_ledger/views/closing_entry.py +11 -7
  61. django_ledger/views/customer.py +13 -17
  62. django_ledger/views/data_import.py +7 -6
  63. django_ledger/views/djl_api.py +3 -5
  64. django_ledger/views/entity.py +2 -4
  65. django_ledger/views/estimate.py +3 -7
  66. django_ledger/views/inventory.py +3 -5
  67. django_ledger/views/invoice.py +4 -6
  68. django_ledger/views/item.py +7 -11
  69. django_ledger/views/journal_entry.py +1 -2
  70. django_ledger/views/mixins.py +25 -19
  71. django_ledger/views/purchase_order.py +24 -35
  72. django_ledger/views/unit.py +1 -2
  73. django_ledger/views/vendor.py +1 -2
  74. {django_ledger-0.7.11.dist-info → django_ledger-0.8.0.dist-info}/METADATA +43 -75
  75. {django_ledger-0.7.11.dist-info → django_ledger-0.8.0.dist-info}/RECORD +79 -108
  76. {django_ledger-0.7.11.dist-info → django_ledger-0.8.0.dist-info}/WHEEL +1 -1
  77. django_ledger-0.8.0.dist-info/top_level.txt +1 -0
  78. django_ledger/contrib/django_ledger_graphene/__init__.py +0 -0
  79. django_ledger/contrib/django_ledger_graphene/accounts/schema.py +0 -33
  80. django_ledger/contrib/django_ledger_graphene/api.py +0 -42
  81. django_ledger/contrib/django_ledger_graphene/apps.py +0 -6
  82. django_ledger/contrib/django_ledger_graphene/auth/mutations.py +0 -49
  83. django_ledger/contrib/django_ledger_graphene/auth/schema.py +0 -6
  84. django_ledger/contrib/django_ledger_graphene/bank_account/mutations.py +0 -61
  85. django_ledger/contrib/django_ledger_graphene/bank_account/schema.py +0 -34
  86. django_ledger/contrib/django_ledger_graphene/bill/mutations.py +0 -0
  87. django_ledger/contrib/django_ledger_graphene/bill/schema.py +0 -34
  88. django_ledger/contrib/django_ledger_graphene/coa/mutations.py +0 -0
  89. django_ledger/contrib/django_ledger_graphene/coa/schema.py +0 -30
  90. django_ledger/contrib/django_ledger_graphene/customers/__init__.py +0 -0
  91. django_ledger/contrib/django_ledger_graphene/customers/mutations.py +0 -71
  92. django_ledger/contrib/django_ledger_graphene/customers/schema.py +0 -43
  93. django_ledger/contrib/django_ledger_graphene/data_import/mutations.py +0 -0
  94. django_ledger/contrib/django_ledger_graphene/data_import/schema.py +0 -0
  95. django_ledger/contrib/django_ledger_graphene/entity/mutations.py +0 -0
  96. django_ledger/contrib/django_ledger_graphene/entity/schema.py +0 -94
  97. django_ledger/contrib/django_ledger_graphene/item/mutations.py +0 -0
  98. django_ledger/contrib/django_ledger_graphene/item/schema.py +0 -31
  99. django_ledger/contrib/django_ledger_graphene/journal_entry/mutations.py +0 -0
  100. django_ledger/contrib/django_ledger_graphene/journal_entry/schema.py +0 -35
  101. django_ledger/contrib/django_ledger_graphene/ledger/mutations.py +0 -0
  102. django_ledger/contrib/django_ledger_graphene/ledger/schema.py +0 -32
  103. django_ledger/contrib/django_ledger_graphene/purchase_order/mutations.py +0 -0
  104. django_ledger/contrib/django_ledger_graphene/purchase_order/schema.py +0 -31
  105. django_ledger/contrib/django_ledger_graphene/transaction/mutations.py +0 -0
  106. django_ledger/contrib/django_ledger_graphene/transaction/schema.py +0 -36
  107. django_ledger/contrib/django_ledger_graphene/unit/mutations.py +0 -0
  108. django_ledger/contrib/django_ledger_graphene/unit/schema.py +0 -27
  109. django_ledger/contrib/django_ledger_graphene/vendor/mutations.py +0 -0
  110. django_ledger/contrib/django_ledger_graphene/vendor/schema.py +0 -37
  111. django_ledger/contrib/django_ledger_graphene/views.py +0 -12
  112. django_ledger-0.7.11.dist-info/top_level.txt +0 -4
  113. {django_ledger-0.7.11.dist-info → django_ledger-0.8.0.dist-info/licenses}/AUTHORS.md +0 -0
  114. {django_ledger-0.7.11.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
- entity_slug=self.kwargs['entity_slug'],
30
- user_model=self.request.user
31
- ).order_by('-created').select_related('bank_account_model',
32
- 'bank_account_model__entity_model',
33
- 'bank_account_model__account_model',
34
- 'bank_account_model__account_model__coa_model')
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
 
@@ -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
- entity_slug=self.kwargs['entity_slug'],
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
- entity_slug=self.kwargs['entity_slug'],
109
- user_model=request.user,
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()
@@ -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
- user_model=self.request.user,
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
- user_model=self.request.user,
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)
@@ -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
- user_model=self.request.user,
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
- user_model=self.request.user,
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
- user_model=self.request.user,
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
 
@@ -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
- entity_slug=self.kwargs['entity_slug'],
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
- entity_slug = self.kwargs['entity_slug']
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.get_object()
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
 
@@ -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
- entity_slug=self.kwargs['entity_slug'],
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
- entity_slug=self.kwargs['entity_slug'],
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
- entity_slug=self.kwargs['entity_slug'],
142
- user_model=self.request.user)
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)
@@ -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 super().get_queryset()
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 = EntityModel.objects.for_user(
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
- entity_slug=self.AUTHORIZED_ENTITY_MODEL,
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
- entity_slug=self.kwargs['entity_slug'],
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
- entity_slug=self.get_authorized_entity_instance(),
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):
@@ -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 DJANGO_LEDGER_PDF_SUPPORT_ENABLED, DJANGO_LEDGER_AUTHORIZED_SUPERUSER
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([self.IO_DIGEST_UNBOUNDED,
428
- self.IO_DIGEST_BOUNDED]):
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
- entity_model: EntityModel = self.object
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 = entity_model.digest(user_model=self.request.user,
445
- to_date=to_date,
446
- unit_slug=unit_slug,
447
- by_period=True if by_period else False,
448
- process_ratios=True,
449
- process_roles=True,
450
- process_groups=True)
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 = entity_model.digest(
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
- user_model=self.request.user,
493
- entity_slug=self.kwargs['entity_slug']
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
- user_model=self.request.user,
512
- entity_slug=self.kwargs['entity_slug']
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
- entity_slug=self.kwargs['entity_slug'],
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(DjangoLedgerSecurityMixIn,
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(DjangoLedgerSecurityMixIn,
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
- entity_slug=entity_slug,
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
- entity_slug=self.kwargs['entity_slug'],
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(entity_slug=entity_slug,
129
- user_model=self.request.user,
130
- **self.get_form_kwargs())
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
- entity_slug=self.kwargs['entity_slug'],
143
- user_model=self.request.user
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(DjangoLedgerSecurityMixIn,
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
- entity_slug=self.kwargs['entity_slug'],
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(DjangoLedgerSecurityMixIn,
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(DjangoLedgerSecurityMixIn,
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(DjangoLedgerSecurityMixIn,
440
- PurchaseOrderModelModelViewQuerySetMixIn,
441
- RedirectView,
442
- SingleObjectMixin):
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
@@ -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
- entity_slug=self.kwargs['entity_slug'],
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
 
@@ -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
- entity_slug=self.kwargs['entity_slug'],
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.2
1
+ Metadata-Version: 2.4
2
2
  Name: django-ledger
3
- Version: 0.7.11
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.10
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: asgiref>=3.5.2; python_version >= "3.7"
26
- Requires-Dist: django>=2.2
27
- Requires-Dist: django-treebeard>=4.5.1
28
- Requires-Dist: faker>=15.3.3
29
- Requires-Dist: markdown>=3.4.1
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>=9.3.0
32
- Requires-Dist: python-dateutil>=2.8.2; python_version >= "2.7" and python_version not in "3.0, 3.1, 3.2, 3.3"
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
  ![django ledger logo](https://us-east-1.linodeobjects.com/django-ledger/logo/django-ledger-logo@2x.png)
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 any shape or form.
76
- Please refrain from submitting pull requests that focus solely on code linting, refactoring, or similar cosmetic changes.
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). Otherwise, you may create your
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
- * Go to your desired development folder and create a new django project:
101
+ ## Adding Django Ledger to an existing project.
123
102
 
124
- ```shell
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
- * Perform database migrations:
113
+ ### Add Django Ledger Context Preprocessor
163
114
 
164
- ```shell
165
- python manage.py migrate
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
- * Add Django SuperUser and follow the prompts.
128
+ ### Perform database migrations:
169
129
 
170
130
  ```shell
171
- python manage.py createsuperuser
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
- * Run your project:
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
- # How To Set Up Django Ledger for Development
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: