django-ledger 0.7.11__py3-none-any.whl → 0.8.1__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/account.py +45 -46
- django_ledger/forms/bill.py +0 -4
- django_ledger/forms/closing_entry.py +13 -1
- django_ledger/forms/data_import.py +182 -63
- 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 +515 -400
- django_ledger/io/io_generator.py +7 -6
- django_ledger/io/io_library.py +1 -2
- django_ledger/migrations/0025_alter_billmodel_cash_account_and_more.py +70 -0
- django_ledger/migrations/0026_stagedtransactionmodel_customer_model_and_more.py +56 -0
- django_ledger/models/__init__.py +2 -1
- django_ledger/models/accounts.py +109 -69
- django_ledger/models/bank_account.py +40 -23
- django_ledger/models/bill.py +386 -333
- django_ledger/models/chart_of_accounts.py +173 -105
- django_ledger/models/closing_entry.py +99 -48
- django_ledger/models/customer.py +100 -66
- django_ledger/models/data_import.py +818 -323
- django_ledger/models/deprecations.py +61 -0
- django_ledger/models/entity.py +891 -644
- django_ledger/models/estimate.py +57 -28
- django_ledger/models/invoice.py +46 -26
- 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 +424 -281
- django_ledger/models/purchase_order.py +39 -17
- django_ledger/models/receipt.py +1083 -0
- django_ledger/models/transactions.py +242 -139
- django_ledger/models/unit.py +93 -54
- django_ledger/models/utils.py +12 -2
- django_ledger/models/vendor.py +121 -70
- django_ledger/report/core.py +2 -14
- django_ledger/settings.py +57 -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/components/period_navigator.html +5 -3
- django_ledger/templates/django_ledger/customer/customer_detail.html +87 -0
- django_ledger/templates/django_ledger/customer/customer_list.html +0 -1
- django_ledger/templates/django_ledger/customer/tags/customer_table.html +8 -6
- django_ledger/templates/django_ledger/data_import/tags/data_import_job_txs_imported.html +24 -3
- django_ledger/templates/django_ledger/data_import/tags/data_import_job_txs_table.html +26 -10
- django_ledger/templates/django_ledger/entity/entity_dashboard.html +2 -2
- 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 +7 -2
- django_ledger/templates/django_ledger/layouts/content_layout_1.html +1 -1
- django_ledger/templates/django_ledger/receipt/customer_receipt_report.html +115 -0
- django_ledger/templates/django_ledger/receipt/receipt_delete.html +30 -0
- django_ledger/templates/django_ledger/receipt/receipt_detail.html +89 -0
- django_ledger/templates/django_ledger/receipt/receipt_list.html +134 -0
- django_ledger/templates/django_ledger/receipt/vendor_receipt_report.html +115 -0
- django_ledger/templates/django_ledger/vendor/tags/vendor_table.html +12 -7
- django_ledger/templates/django_ledger/vendor/vendor_detail.html +86 -0
- django_ledger/templatetags/django_ledger.py +338 -191
- 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 +1 -4
- django_ledger/urls/customer.py +3 -0
- django_ledger/urls/data_import.py +3 -0
- django_ledger/urls/receipt.py +102 -0
- django_ledger/urls/vendor.py +1 -0
- django_ledger/views/__init__.py +1 -0
- django_ledger/views/bill.py +8 -11
- django_ledger/views/chart_of_accounts.py +6 -4
- django_ledger/views/closing_entry.py +11 -7
- django_ledger/views/customer.py +68 -30
- django_ledger/views/data_import.py +120 -66
- 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 +125 -93
- django_ledger/views/purchase_order.py +24 -35
- django_ledger/views/receipt.py +294 -0
- django_ledger/views/unit.py +1 -2
- django_ledger/views/vendor.py +54 -16
- {django_ledger-0.7.11.dist-info → django_ledger-0.8.1.dist-info}/METADATA +43 -75
- {django_ledger-0.7.11.dist-info → django_ledger-0.8.1.dist-info}/RECORD +104 -122
- {django_ledger-0.7.11.dist-info → django_ledger-0.8.1.dist-info}/WHEEL +1 -1
- django_ledger-0.8.1.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.11.dist-info/top_level.txt +0 -4
- {django_ledger-0.7.11.dist-info → django_ledger-0.8.1.dist-info/licenses}/AUTHORS.md +0 -0
- {django_ledger-0.7.11.dist-info → django_ledger-0.8.1.dist-info/licenses}/LICENSE +0 -0
django_ledger/models/items.py
CHANGED
|
@@ -18,8 +18,10 @@ ItemsTransactionModels constitute the way multiple items and used resources are
|
|
|
18
18
|
Purchase Orders and Estimates. Each transaction will record the unit of measure and quantity of each resource.
|
|
19
19
|
Totals will be calculated and associated with the containing model at the time of update.
|
|
20
20
|
"""
|
|
21
|
+
import warnings
|
|
21
22
|
from decimal import Decimal
|
|
22
23
|
from string import ascii_lowercase, digits
|
|
24
|
+
from typing import Dict
|
|
23
25
|
from uuid import uuid4, UUID
|
|
24
26
|
|
|
25
27
|
from django.core.exceptions import ValidationError, ObjectDoesNotExist
|
|
@@ -29,11 +31,14 @@ from django.db.models import Q, Sum, F, ExpressionWrapper, DecimalField, Value,
|
|
|
29
31
|
from django.db.models.functions import Coalesce
|
|
30
32
|
from django.utils.translation import gettext_lazy as _
|
|
31
33
|
|
|
34
|
+
from django_ledger.models.deprecations import deprecated_entity_slug_behavior
|
|
32
35
|
from django_ledger.models.mixins import CreateUpdateMixIn
|
|
33
36
|
from django_ledger.models.utils import lazy_loader
|
|
34
|
-
from django_ledger.settings import (
|
|
35
|
-
|
|
36
|
-
|
|
37
|
+
from django_ledger.settings import (
|
|
38
|
+
DJANGO_LEDGER_TRANSACTION_MAX_TOLERANCE, DJANGO_LEDGER_DOCUMENT_NUMBER_PADDING,
|
|
39
|
+
DJANGO_LEDGER_EXPENSE_NUMBER_PREFIX, DJANGO_LEDGER_INVENTORY_NUMBER_PREFIX,
|
|
40
|
+
DJANGO_LEDGER_PRODUCT_NUMBER_PREFIX, DJANGO_LEDGER_USE_DEPRECATED_BEHAVIOR
|
|
41
|
+
)
|
|
37
42
|
|
|
38
43
|
ITEM_LIST_RANDOM_SLUG_SUFFIX = ascii_lowercase + digits
|
|
39
44
|
|
|
@@ -43,65 +48,83 @@ class ItemModelValidationError(ValidationError):
|
|
|
43
48
|
|
|
44
49
|
|
|
45
50
|
class UnitOfMeasureModelQuerySet(QuerySet):
|
|
46
|
-
|
|
51
|
+
|
|
52
|
+
def for_user(self, user_model) -> 'UnitOfMeasureModelQuerySet':
|
|
53
|
+
return self.filter(
|
|
54
|
+
(
|
|
55
|
+
Q(entity__admin=user_model) |
|
|
56
|
+
Q(entity__managers__in=[user_model])
|
|
57
|
+
)
|
|
58
|
+
)
|
|
47
59
|
|
|
48
60
|
|
|
49
61
|
# UNIT OF MEASURES MODEL....
|
|
50
62
|
class UnitOfMeasureModelManager(Manager):
|
|
51
63
|
"""
|
|
52
|
-
A custom
|
|
64
|
+
A custom-defined QuerySet Manager for the UnitOfMeasureModel.
|
|
53
65
|
"""
|
|
54
66
|
|
|
55
|
-
def
|
|
67
|
+
def get_queryset(self) -> UnitOfMeasureModelQuerySet:
|
|
68
|
+
return UnitOfMeasureModelQuerySet(self.model, using=self._db)
|
|
69
|
+
|
|
70
|
+
@deprecated_entity_slug_behavior
|
|
71
|
+
def for_entity(self, entity_model: 'EntityModel | str | UUID' = None, **kwargs) -> UnitOfMeasureModelQuerySet:
|
|
56
72
|
"""
|
|
57
73
|
Fetches the UnitOfMeasureModels associated with the provided EntityModel and UserModel.
|
|
58
74
|
|
|
59
75
|
Parameters
|
|
60
76
|
----------
|
|
61
|
-
|
|
77
|
+
entity_model: str or EntityModel
|
|
62
78
|
The EntityModel slug or EntityModel used to filter the QuerySet.
|
|
63
|
-
user_model: UserModel
|
|
64
|
-
The Django UserModel to check permissions.
|
|
65
79
|
|
|
66
80
|
Returns
|
|
67
81
|
-------
|
|
68
82
|
QuerySet
|
|
69
83
|
A QuerySet with applied filters.
|
|
70
84
|
"""
|
|
85
|
+
|
|
86
|
+
EntityModel = lazy_loader.get_entity_model()
|
|
71
87
|
qs = self.get_queryset()
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
88
|
+
|
|
89
|
+
if 'user_model' in kwargs:
|
|
90
|
+
warnings.warn(
|
|
91
|
+
'user_model parameter is deprecated and will be removed in a future release. '
|
|
92
|
+
'Use for_user(user_model).for_entity(entity_model) instead to keep current behavior.',
|
|
93
|
+
DeprecationWarning,
|
|
94
|
+
stacklevel=2
|
|
79
95
|
)
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
96
|
+
if DJANGO_LEDGER_USE_DEPRECATED_BEHAVIOR:
|
|
97
|
+
qs = qs.for_user(kwargs['user_model'])
|
|
98
|
+
|
|
99
|
+
if isinstance(entity_model, EntityModel):
|
|
100
|
+
qs = qs.filter(entity=entity_model)
|
|
101
|
+
elif isinstance(entity_model, str):
|
|
102
|
+
qs = qs.filter(entity__slug=entity_model)
|
|
103
|
+
elif isinstance(entity_model, UUID):
|
|
104
|
+
qs = qs.filter(entity_id=entity_model)
|
|
105
|
+
else:
|
|
106
|
+
raise ItemModelValidationError(
|
|
107
|
+
message='Must pass EntityModel, slug or UUID'
|
|
85
108
|
)
|
|
86
|
-
|
|
109
|
+
return qs
|
|
87
110
|
|
|
88
|
-
|
|
111
|
+
@deprecated_entity_slug_behavior
|
|
112
|
+
def for_entity_active(
|
|
113
|
+
self, entity_model: 'EntityModel | str | UUID' = None,
|
|
114
|
+
**kwargs) -> UnitOfMeasureModelQuerySet:
|
|
89
115
|
"""
|
|
90
116
|
Fetches the Active UnitOfMeasureModels associated with the provided EntityModel and UserModel.
|
|
91
117
|
|
|
92
118
|
Parameters
|
|
93
119
|
----------
|
|
94
|
-
|
|
120
|
+
entity_model: str or EntityModel
|
|
95
121
|
The EntityModel slug or EntityModel used to filter the QuerySet.
|
|
96
|
-
user_model: UserModel
|
|
97
|
-
The Django UserModel to check permissions.
|
|
98
|
-
|
|
99
122
|
Returns
|
|
100
123
|
-------
|
|
101
124
|
QuerySet
|
|
102
125
|
A QuerySet with applied filters.
|
|
103
126
|
"""
|
|
104
|
-
qs = self.for_entity(
|
|
127
|
+
qs = self.for_entity(entity_model=entity_model, **kwargs)
|
|
105
128
|
return qs.filter(is_active=True)
|
|
106
129
|
|
|
107
130
|
|
|
@@ -154,6 +177,14 @@ class ItemModelQuerySet(QuerySet):
|
|
|
154
177
|
A custom-defined ItemModelQuerySet that implements custom QuerySet methods related to the ItemModel.
|
|
155
178
|
"""
|
|
156
179
|
|
|
180
|
+
def for_user(self, user_model) -> 'ItemModelQuerySet':
|
|
181
|
+
if user_model.is_superuser:
|
|
182
|
+
return self
|
|
183
|
+
return self.filter(
|
|
184
|
+
Q(entity__managers__in=[user_model]) |
|
|
185
|
+
Q(entity__admin=user_model)
|
|
186
|
+
)
|
|
187
|
+
|
|
157
188
|
def active(self):
|
|
158
189
|
"""
|
|
159
190
|
Filters the QuerySet to only active Item Models.
|
|
@@ -165,7 +196,7 @@ class ItemModelQuerySet(QuerySet):
|
|
|
165
196
|
"""
|
|
166
197
|
return self.filter(is_active=True)
|
|
167
198
|
|
|
168
|
-
def products(self):
|
|
199
|
+
def products(self) -> 'ItemModelQuerySet':
|
|
169
200
|
"""
|
|
170
201
|
Filters the QuerySet to ItemModels that only qualify as products.
|
|
171
202
|
|
|
@@ -182,7 +213,7 @@ class ItemModelQuerySet(QuerySet):
|
|
|
182
213
|
Q(item_role=ItemModel.ITEM_ROLE_PRODUCT)
|
|
183
214
|
)
|
|
184
215
|
|
|
185
|
-
def services(self):
|
|
216
|
+
def services(self) -> 'ItemModelQuerySet':
|
|
186
217
|
"""
|
|
187
218
|
Filters the QuerySet to ItemModels that only qualify as services.
|
|
188
219
|
|
|
@@ -199,7 +230,7 @@ class ItemModelQuerySet(QuerySet):
|
|
|
199
230
|
Q(item_role=ItemModel.ITEM_ROLE_SERVICE)
|
|
200
231
|
)
|
|
201
232
|
|
|
202
|
-
def expenses(self):
|
|
233
|
+
def expenses(self) -> 'ItemModelQuerySet':
|
|
203
234
|
"""
|
|
204
235
|
Filters the QuerySet to ItemModels that only qualify as expenses.
|
|
205
236
|
|
|
@@ -215,7 +246,7 @@ class ItemModelQuerySet(QuerySet):
|
|
|
215
246
|
) | Q(item_role=ItemModel.ITEM_ROLE_EXPENSE)
|
|
216
247
|
)
|
|
217
248
|
|
|
218
|
-
def inventory_wip(self):
|
|
249
|
+
def inventory_wip(self) -> 'ItemModelQuerySet':
|
|
219
250
|
"""
|
|
220
251
|
Filters the QuerySet to ItemModels that only qualify as inventory.
|
|
221
252
|
These types of items cannot be sold as they are not considered a finished product.
|
|
@@ -232,7 +263,7 @@ class ItemModelQuerySet(QuerySet):
|
|
|
232
263
|
) | Q(item_role=ItemModel.ITEM_ROLE_INVENTORY)
|
|
233
264
|
)
|
|
234
265
|
|
|
235
|
-
def inventory_all(self):
|
|
266
|
+
def inventory_all(self) -> 'ItemModelQuerySet':
|
|
236
267
|
"""
|
|
237
268
|
Filters the QuerySet to ItemModels that only qualify as inventory.
|
|
238
269
|
These types of items may be finished or unfinished.
|
|
@@ -260,7 +291,7 @@ class ItemModelQuerySet(QuerySet):
|
|
|
260
291
|
)
|
|
261
292
|
)
|
|
262
293
|
|
|
263
|
-
def bills(self):
|
|
294
|
+
def bills(self) -> 'ItemModelQuerySet':
|
|
264
295
|
"""
|
|
265
296
|
Filters the QuerySet to ItemModels that are eligible only for bills..
|
|
266
297
|
|
|
@@ -277,13 +308,13 @@ class ItemModelQuerySet(QuerySet):
|
|
|
277
308
|
Q(for_inventory=True)
|
|
278
309
|
)
|
|
279
310
|
|
|
280
|
-
def invoices(self):
|
|
311
|
+
def invoices(self) -> 'ItemModelQuerySet':
|
|
281
312
|
return self.filter(is_product_or_service=True)
|
|
282
313
|
|
|
283
|
-
def estimates(self):
|
|
314
|
+
def estimates(self) -> 'ItemModelQuerySet':
|
|
284
315
|
return self.invoices()
|
|
285
316
|
|
|
286
|
-
def purchase_orders(self):
|
|
317
|
+
def purchase_orders(self) -> 'ItemModelQuerySet':
|
|
287
318
|
return self.inventory_all()
|
|
288
319
|
|
|
289
320
|
|
|
@@ -292,61 +323,87 @@ class ItemModelManager(Manager):
|
|
|
292
323
|
A custom defined ItemModelManager that implement custom QuerySet methods related to the ItemModel
|
|
293
324
|
"""
|
|
294
325
|
|
|
295
|
-
def
|
|
326
|
+
def get_queryset(self) -> ItemModelQuerySet:
|
|
327
|
+
return ItemModelQuerySet(self.model, using=self._db).select_related('uom')
|
|
328
|
+
|
|
329
|
+
@deprecated_entity_slug_behavior
|
|
330
|
+
def for_entity(self, entity_model: 'EntityModel | str | UUID' = None, **kwargs) -> ItemModelQuerySet:
|
|
296
331
|
"""
|
|
297
|
-
|
|
298
|
-
|
|
332
|
+
Marks the `for_entity` method as deprecated in behavior and provides an updated usage approach.
|
|
333
|
+
|
|
334
|
+
This method allows querying a `QuerySet` filtered by various representations of an entity, such as an
|
|
335
|
+
instance of `EntityModel`, a string slug, or a UUID. Leveraging this method with deprecated parameters
|
|
336
|
+
may lead to a warning and compatibility concerns in future releases.
|
|
299
337
|
|
|
300
338
|
Parameters
|
|
301
339
|
----------
|
|
302
|
-
|
|
303
|
-
The entity
|
|
304
|
-
|
|
305
|
-
|
|
340
|
+
entity_model : EntityModel | str | UUID, optional
|
|
341
|
+
The entity to filter the queryset by. Can be an instance of `EntityModel`, a slug (`str`), or
|
|
342
|
+
a unique identifier (`UUID`). If not provided, no filtering is applied.
|
|
343
|
+
kwargs : dict
|
|
344
|
+
Additional keyword arguments, though currently only the `user_model` parameter is recognized but
|
|
345
|
+
deprecated. The `user_model` behavior will be removed in future releases.
|
|
306
346
|
|
|
307
347
|
Returns
|
|
308
348
|
-------
|
|
309
349
|
ItemModelQuerySet
|
|
310
|
-
A
|
|
350
|
+
A filtered queryset corresponding to the specified entity.
|
|
351
|
+
|
|
352
|
+
Raises
|
|
353
|
+
------
|
|
354
|
+
ItemModelValidationError
|
|
355
|
+
If the `entity_model` parameter is not of type `EntityModel`, `str`, or `UUID`.
|
|
356
|
+
DeprecationWarning
|
|
357
|
+
When the `user_model` parameter is used, indicating behavior slated for future removal.
|
|
311
358
|
"""
|
|
359
|
+
EntityModel = lazy_loader.get_entity_model()
|
|
312
360
|
qs = self.get_queryset()
|
|
313
|
-
if
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
(
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
361
|
+
if 'user_model' in kwargs:
|
|
362
|
+
warnings.warn(
|
|
363
|
+
'user_model parameter is deprecated and will be removed in a future release. '
|
|
364
|
+
'Use for_user(user_model).for_entity(entity_model) instead to keep current behavior.',
|
|
365
|
+
DeprecationWarning,
|
|
366
|
+
stacklevel=2
|
|
367
|
+
)
|
|
368
|
+
if DJANGO_LEDGER_USE_DEPRECATED_BEHAVIOR:
|
|
369
|
+
qs = qs.for_user(kwargs['user_model'])
|
|
370
|
+
|
|
371
|
+
if isinstance(entity_model, EntityModel):
|
|
372
|
+
qs = qs.filter(entity=entity_model)
|
|
373
|
+
elif isinstance(entity_model, str):
|
|
374
|
+
qs = qs.filter(entity__slug__exact=entity_model)
|
|
375
|
+
elif isinstance(entity_model, UUID):
|
|
376
|
+
qs = qs.filter(entity_id=entity_model)
|
|
377
|
+
else:
|
|
378
|
+
raise ItemModelValidationError(
|
|
379
|
+
message='entity_model parameter must be of type str or EntityModel or UUID'
|
|
326
380
|
)
|
|
327
|
-
|
|
381
|
+
return qs
|
|
328
382
|
|
|
329
|
-
|
|
383
|
+
@deprecated_entity_slug_behavior
|
|
384
|
+
def for_entity_active(self, entity_model: 'EntityModel | str | UUID' = None, **kwargs) -> ItemModelQuerySet:
|
|
330
385
|
"""
|
|
331
386
|
Returns a QuerySet of Active ItemModel associated with a specific EntityModel & UserModel.
|
|
332
387
|
May pass an instance of EntityModel or a String representing the EntityModel slug.
|
|
333
388
|
|
|
334
389
|
Parameters
|
|
335
390
|
----------
|
|
336
|
-
|
|
391
|
+
entity_model: str or EntityModel
|
|
337
392
|
The entity slug or EntityModel used for filtering the QuerySet.
|
|
338
|
-
user_model
|
|
339
|
-
The request UserModel to check for privileges.
|
|
340
393
|
|
|
341
394
|
Returns
|
|
342
395
|
-------
|
|
343
396
|
ItemModelQuerySet
|
|
344
397
|
A Filtered ItemModelQuerySet.
|
|
345
398
|
"""
|
|
346
|
-
qs = self.for_entity(
|
|
399
|
+
qs = self.for_entity(
|
|
400
|
+
entity_model=entity_model,
|
|
401
|
+
**kwargs
|
|
402
|
+
)
|
|
347
403
|
return qs.filter(is_active=True)
|
|
348
404
|
|
|
349
|
-
|
|
405
|
+
@deprecated_entity_slug_behavior
|
|
406
|
+
def for_invoice(self, entity_model: 'EntityModel | str | UUID' = None, **kwargs) -> ItemModelQuerySet:
|
|
350
407
|
"""
|
|
351
408
|
Returns a QuerySet of ItemModels that can only be used for InvoiceModels for a specific EntityModel &
|
|
352
409
|
UserModel. These types of items qualify as products or services sold.
|
|
@@ -354,20 +411,19 @@ class ItemModelManager(Manager):
|
|
|
354
411
|
|
|
355
412
|
Parameters
|
|
356
413
|
----------
|
|
357
|
-
|
|
414
|
+
entity_model: str or EntityModel
|
|
358
415
|
The entity slug or EntityModel used for filtering the QuerySet.
|
|
359
|
-
user_model
|
|
360
|
-
The request UserModel to check for privileges.
|
|
361
416
|
|
|
362
417
|
Returns
|
|
363
418
|
-------
|
|
364
419
|
ItemModelQuerySet
|
|
365
420
|
A Filtered ItemModelQuerySet.
|
|
366
421
|
"""
|
|
367
|
-
qs = self.for_entity_active(
|
|
422
|
+
qs = self.for_entity_active(entity_model=entity_model, **kwargs)
|
|
368
423
|
return qs.filter(is_product_or_service=True)
|
|
369
424
|
|
|
370
|
-
|
|
425
|
+
@deprecated_entity_slug_behavior
|
|
426
|
+
def for_bill(self, entity_model: 'EntityModel | str | UUID' = None, **kwargs) -> ItemModelQuerySet:
|
|
371
427
|
"""
|
|
372
428
|
Returns a QuerySet of ItemModels that can only be used for BillModels for a specific EntityModel &
|
|
373
429
|
UserModel. These types of items qualify as expenses or inventory purchases.
|
|
@@ -375,10 +431,8 @@ class ItemModelManager(Manager):
|
|
|
375
431
|
|
|
376
432
|
Parameters
|
|
377
433
|
----------
|
|
378
|
-
|
|
434
|
+
entity_model: str or EntityModel
|
|
379
435
|
The entity slug or EntityModel used for filtering the QuerySet.
|
|
380
|
-
user_model
|
|
381
|
-
The request UserModel to check for privileges.
|
|
382
436
|
|
|
383
437
|
Returns
|
|
384
438
|
-------
|
|
@@ -386,8 +440,8 @@ class ItemModelManager(Manager):
|
|
|
386
440
|
A Filtered ItemModelQuerySet.
|
|
387
441
|
"""
|
|
388
442
|
qs = self.for_entity_active(
|
|
389
|
-
|
|
390
|
-
|
|
443
|
+
entity_model=entity_model,
|
|
444
|
+
**kwargs
|
|
391
445
|
)
|
|
392
446
|
return qs.filter(
|
|
393
447
|
(
|
|
@@ -397,7 +451,8 @@ class ItemModelManager(Manager):
|
|
|
397
451
|
Q(for_inventory=True)
|
|
398
452
|
)
|
|
399
453
|
|
|
400
|
-
|
|
454
|
+
@deprecated_entity_slug_behavior
|
|
455
|
+
def for_po(self, entity_model: 'EntityModel | str | UUID' = None, **kwargs) -> ItemModelQuerySet:
|
|
401
456
|
"""
|
|
402
457
|
Returns a QuerySet of ItemModels that can only be used for PurchaseOrders for a specific EntityModel &
|
|
403
458
|
UserModel. These types of items qualify as inventory purchases.
|
|
@@ -405,20 +460,19 @@ class ItemModelManager(Manager):
|
|
|
405
460
|
|
|
406
461
|
Parameters
|
|
407
462
|
----------
|
|
408
|
-
|
|
463
|
+
entity_model: str or EntityModel
|
|
409
464
|
The entity slug or EntityModel used for filtering the QuerySet.
|
|
410
|
-
user_model
|
|
411
|
-
The request UserModel to check for privileges.
|
|
412
465
|
|
|
413
466
|
Returns
|
|
414
467
|
-------
|
|
415
468
|
ItemModelQuerySet
|
|
416
469
|
A Filtered ItemModelQuerySet.
|
|
417
470
|
"""
|
|
418
|
-
qs = self.for_entity(
|
|
471
|
+
qs = self.for_entity(entity_model=entity_model, **kwargs)
|
|
419
472
|
return qs.inventory_all()
|
|
420
473
|
|
|
421
|
-
|
|
474
|
+
@deprecated_entity_slug_behavior
|
|
475
|
+
def for_estimate(self, entity_model: 'EntityModel | str | UUID' = None, **kwargs) -> ItemModelQuerySet:
|
|
422
476
|
"""
|
|
423
477
|
Returns a QuerySet of ItemModels that can only be used for EstimateModels for a specific EntityModel &
|
|
424
478
|
UserModel. These types of items qualify as products.
|
|
@@ -426,17 +480,15 @@ class ItemModelManager(Manager):
|
|
|
426
480
|
|
|
427
481
|
Parameters
|
|
428
482
|
----------
|
|
429
|
-
|
|
483
|
+
entity_model: str or EntityModel
|
|
430
484
|
The entity slug or EntityModel used for filtering the QuerySet.
|
|
431
|
-
user_model
|
|
432
|
-
The request UserModel to check for privileges.
|
|
433
485
|
|
|
434
486
|
Returns
|
|
435
487
|
-------
|
|
436
488
|
ItemModelQuerySet
|
|
437
489
|
A Filtered ItemModelQuerySet.
|
|
438
490
|
"""
|
|
439
|
-
qs = self.for_entity_active(
|
|
491
|
+
qs = self.for_entity_active(entity_model=entity_model, **kwargs)
|
|
440
492
|
return qs.products()
|
|
441
493
|
|
|
442
494
|
|
|
@@ -849,25 +901,110 @@ class ItemModelAbstract(CreateUpdateMixIn):
|
|
|
849
901
|
|
|
850
902
|
|
|
851
903
|
# ITEM TRANSACTION MODELS...
|
|
904
|
+
|
|
905
|
+
class ItemTransactionModelValidationError(ValidationError):
|
|
906
|
+
pass
|
|
907
|
+
|
|
908
|
+
|
|
852
909
|
class ItemTransactionModelQuerySet(QuerySet):
|
|
910
|
+
"""
|
|
911
|
+
QuerySet class for handling ItemTransactionModel-specific database queries.
|
|
912
|
+
|
|
913
|
+
This class extends Django's QuerySet to provide additional methods
|
|
914
|
+
to filter and retrieve specific subsets of ItemTransactionModel entries
|
|
915
|
+
based on various criteria such as user permissions, transaction status,
|
|
916
|
+
or custom aggregate calculations.
|
|
917
|
+
"""
|
|
918
|
+
|
|
919
|
+
def for_user(self, user_model) -> 'ItemTransactionModelQuerySet':
|
|
920
|
+
"""
|
|
921
|
+
Filters the queryset based on the provided user model.
|
|
853
922
|
|
|
854
|
-
|
|
923
|
+
This method restricts the queryset to items associated with the specified
|
|
924
|
+
user. If the user is a superuser, all items in the queryset are returned.
|
|
925
|
+
Otherwise, only items managed or administered by the user are included.
|
|
926
|
+
|
|
927
|
+
Parameters
|
|
928
|
+
----------
|
|
929
|
+
user_model : UserModel
|
|
930
|
+
The user model instance used to filter the queryset.
|
|
931
|
+
|
|
932
|
+
Returns
|
|
933
|
+
-------
|
|
934
|
+
ItemTransactionModelQuerySet
|
|
935
|
+
The filtered queryset containing items accessible by the given user.
|
|
936
|
+
"""
|
|
937
|
+
if user_model.is_superuser:
|
|
938
|
+
return self
|
|
939
|
+
return self.filter(
|
|
940
|
+
Q(item_model__entity__admin=user_model) |
|
|
941
|
+
Q(item_model__entity__managers__in=[user_model])
|
|
942
|
+
)
|
|
943
|
+
|
|
944
|
+
def is_received(self) -> 'ItemTransactionModelQuerySet':
|
|
945
|
+
"""
|
|
946
|
+
Filters the queryset to include only items with the status 'received'.
|
|
947
|
+
|
|
948
|
+
Returns
|
|
949
|
+
-------
|
|
950
|
+
ItemTransactionModelQuerySet
|
|
951
|
+
A queryset containing only the items with the status 'received'.
|
|
952
|
+
"""
|
|
855
953
|
return self.filter(po_item_status=ItemTransactionModel.STATUS_RECEIVED)
|
|
856
954
|
|
|
857
|
-
def in_transit(self):
|
|
955
|
+
def in_transit(self) -> 'ItemTransactionModelQuerySet':
|
|
956
|
+
"""
|
|
957
|
+
Filters and retrieves items in the "in transit" status.
|
|
958
|
+
|
|
959
|
+
Returns
|
|
960
|
+
-------
|
|
961
|
+
ItemTransactionModelQuerySet
|
|
962
|
+
A queryset containing items whose status is "in transit".
|
|
963
|
+
"""
|
|
858
964
|
return self.filter(po_item_status=ItemTransactionModel.STATUS_IN_TRANSIT)
|
|
859
965
|
|
|
860
|
-
def is_ordered(self):
|
|
966
|
+
def is_ordered(self) -> 'ItemTransactionModelQuerySet':
|
|
967
|
+
"""
|
|
968
|
+
Filters the queryset to include only items with the status "ORDERED".
|
|
969
|
+
|
|
970
|
+
Returns
|
|
971
|
+
-------
|
|
972
|
+
ItemTransactionModelQuerySet
|
|
973
|
+
A filtered queryset containing items with the status "ORDERED".
|
|
974
|
+
"""
|
|
861
975
|
return self.filter(po_item_status=ItemTransactionModel.STATUS_ORDERED)
|
|
862
976
|
|
|
863
|
-
def is_orphan(self):
|
|
977
|
+
def is_orphan(self) -> 'ItemTransactionModelQuerySet':
|
|
978
|
+
"""
|
|
979
|
+
Filters the query set for items that are considered "orphan", meaning
|
|
980
|
+
they are not linked to any bill, purchase order, or cost estimate models.
|
|
981
|
+
|
|
982
|
+
Returns
|
|
983
|
+
-------
|
|
984
|
+
ItemTransactionModelQuerySet
|
|
985
|
+
A filtered query set containing only the orphan items.
|
|
986
|
+
"""
|
|
864
987
|
return self.filter(
|
|
865
988
|
Q(bill_model_id__isnull=True) &
|
|
866
989
|
Q(po_model_id__isnull=True) &
|
|
867
990
|
Q(ce_model_id__isnull=True)
|
|
868
991
|
)
|
|
869
992
|
|
|
870
|
-
def get_estimate_aggregate(self):
|
|
993
|
+
def get_estimate_aggregate(self) -> Dict[str, int]:
|
|
994
|
+
"""
|
|
995
|
+
Calculate aggregated estimates for cost, revenue, and total items.
|
|
996
|
+
|
|
997
|
+
This method computes the sum of `ce_cost_estimate` and `ce_revenue_estimate`
|
|
998
|
+
for all elements in the iterable, as well as the total number of items.
|
|
999
|
+
|
|
1000
|
+
Returns
|
|
1001
|
+
-------
|
|
1002
|
+
Dict[str, int]
|
|
1003
|
+
A dictionary containing the following keys:
|
|
1004
|
+
- 'ce_cost_estimate__sum': The total sum of all `ce_cost_estimate` values.
|
|
1005
|
+
- 'ce_revenue_estimate__sum': The total sum of all `ce_revenue_estimate` values.
|
|
1006
|
+
- 'total_items': The total count of items in the iterable.
|
|
1007
|
+
"""
|
|
871
1008
|
return {
|
|
872
1009
|
'ce_cost_estimate__sum': sum(i.ce_cost_estimate for i in self),
|
|
873
1010
|
'ce_revenue_estimate__sum': sum(i.ce_revenue_estimate for i in self),
|
|
@@ -877,51 +1014,260 @@ class ItemTransactionModelQuerySet(QuerySet):
|
|
|
877
1014
|
|
|
878
1015
|
class ItemTransactionModelManager(Manager):
|
|
879
1016
|
|
|
880
|
-
def
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
1017
|
+
def get_queryset(self) -> ItemTransactionModelQuerySet:
|
|
1018
|
+
"""
|
|
1019
|
+
Provides a custom queryset for the related ItemTransactionModel.
|
|
1020
|
+
|
|
1021
|
+
This method ensures that the queryset returned is an instance of the custom
|
|
1022
|
+
ItemTransactionModelQuerySet configured for operations on the specific model.
|
|
1023
|
+
|
|
1024
|
+
Returns
|
|
1025
|
+
-------
|
|
1026
|
+
ItemTransactionModelQuerySet
|
|
1027
|
+
An instance of ItemTransactionModelQuerySet customized for the model.
|
|
1028
|
+
"""
|
|
1029
|
+
return ItemTransactionModelQuerySet(self.model, using=self._db)
|
|
1030
|
+
|
|
1031
|
+
@deprecated_entity_slug_behavior
|
|
1032
|
+
def for_entity(self, entity_model: 'EntityModel | str | UUID' = None, **kwargs) -> ItemTransactionModelQuerySet:
|
|
1033
|
+
"""
|
|
1034
|
+
A method to filter the queryset for a specified entity. The filtering can be performed
|
|
1035
|
+
using an entity model, a slug string, or a UUID. Older deprecated parameters can still
|
|
1036
|
+
be utilized if certain conditions are met. This method applies the necessary filters
|
|
1037
|
+
to the queryset based on the entity information provided.
|
|
1038
|
+
|
|
1039
|
+
Parameters
|
|
1040
|
+
----------
|
|
1041
|
+
entity_model : EntityModel | str | UUID, optional
|
|
1042
|
+
The entity for which the queryset is being filtered. It can be an instance of
|
|
1043
|
+
EntityModel, a string representing the entity slug, or a UUID corresponding to
|
|
1044
|
+
the entity's identifier.
|
|
1045
|
+
**kwargs :
|
|
1046
|
+
Arbitrary keyword arguments. A specific argument, `user_model`, is deprecated
|
|
1047
|
+
and will trigger a warning if used.
|
|
886
1048
|
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
1049
|
+
Returns
|
|
1050
|
+
-------
|
|
1051
|
+
ItemTransactionModelQuerySet
|
|
1052
|
+
The queryset filtered for the specified entity.
|
|
1053
|
+
|
|
1054
|
+
Raises
|
|
1055
|
+
------
|
|
1056
|
+
ItemTransactionModelValidationError
|
|
1057
|
+
Raised when `entity_model` is not an instance of EntityModel, a string, or a UUID.
|
|
1058
|
+
|
|
1059
|
+
Warnings
|
|
1060
|
+
--------
|
|
1061
|
+
DeprecationWarning
|
|
1062
|
+
Issued if `user_model` parameter is passed via kwargs. Users are encouraged to update
|
|
1063
|
+
their implementation to utilize `for_user(user_model).for_entity(entity_model)`
|
|
1064
|
+
to avoid this warning.
|
|
1065
|
+
|
|
1066
|
+
Notes
|
|
1067
|
+
-----
|
|
1068
|
+
- Deprecation behavior of certain parameters depends on the `DJANGO_LEDGER_USE_DEPRECATED_BEHAVIOR` flag.
|
|
1069
|
+
- If `entity_model` is None, the method raises an error as entity identification is required.
|
|
1070
|
+
"""
|
|
1071
|
+
EntityModel = lazy_loader.get_entity_model()
|
|
1072
|
+
|
|
1073
|
+
qs = self.get_queryset()
|
|
1074
|
+
if 'user_model' in kwargs:
|
|
1075
|
+
warnings.warn(
|
|
1076
|
+
'user_model parameter is deprecated and will be removed in a future release. '
|
|
1077
|
+
'Use for_user(user_model).for_entity(entity_model) instead to keep current behavior.',
|
|
1078
|
+
DeprecationWarning,
|
|
1079
|
+
stacklevel=2
|
|
892
1080
|
)
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
1081
|
+
if DJANGO_LEDGER_USE_DEPRECATED_BEHAVIOR:
|
|
1082
|
+
qs = qs.for_user(kwargs['user_model'])
|
|
1083
|
+
|
|
1084
|
+
if isinstance(entity_model, EntityModel):
|
|
1085
|
+
qs = qs.filter(item_model__entity=entity_model)
|
|
1086
|
+
elif isinstance(entity_model, str):
|
|
1087
|
+
qs = qs.filter(item_model__entity__slug__exact=entity_model)
|
|
1088
|
+
elif isinstance(entity_model, UUID):
|
|
1089
|
+
qs = qs.filter(item_model__entity_id=entity_model)
|
|
1090
|
+
else:
|
|
1091
|
+
raise ItemTransactionModelValidationError(
|
|
1092
|
+
message='Must pass EntityModel, slug or UUID'
|
|
1093
|
+
)
|
|
1094
|
+
return qs
|
|
1095
|
+
|
|
1096
|
+
@deprecated_entity_slug_behavior
|
|
1097
|
+
def for_bill(self, bill_pk: UUID, entity_model: 'EntityModel | str | UUID' = None, **kwargs, ):
|
|
1098
|
+
"""
|
|
1099
|
+
This function provides filters for fetching data related to a specific bill, based on a given
|
|
1100
|
+
bill primary key, along with optional parameters for an associated entity model.
|
|
1101
|
+
|
|
1102
|
+
Parameters
|
|
1103
|
+
----------
|
|
1104
|
+
bill_pk : UUID
|
|
1105
|
+
The primary key of the bill to filter.
|
|
1106
|
+
entity_model : EntityModel | str | UUID.
|
|
1107
|
+
Represents the associated entity model, which could be provided as an instance,
|
|
1108
|
+
identifier, or string.
|
|
1109
|
+
**kwargs : dict
|
|
1110
|
+
Additional filtering or query parameters.
|
|
896
1111
|
|
|
897
|
-
|
|
898
|
-
|
|
1112
|
+
Returns
|
|
1113
|
+
-------
|
|
1114
|
+
QuerySet
|
|
1115
|
+
A filtered queryset containing data relevant to the specified bill and optional entity
|
|
1116
|
+
constraints.
|
|
1117
|
+
|
|
1118
|
+
Deprecated
|
|
1119
|
+
----------
|
|
1120
|
+
This function is deprecated in favor of using entity behavior. Please refer to the
|
|
1121
|
+
documentation for updated usage guidelines.
|
|
1122
|
+
"""
|
|
1123
|
+
qs = self.for_entity(entity_model=entity_model, **kwargs)
|
|
899
1124
|
return qs.filter(bill_model_id__exact=bill_pk)
|
|
900
1125
|
|
|
901
|
-
|
|
902
|
-
|
|
1126
|
+
@deprecated_entity_slug_behavior
|
|
1127
|
+
def for_invoice(self, invoice_pk: UUID, entity_model: 'EntityModel | str | UUID' = None, **kwargs):
|
|
1128
|
+
"""
|
|
1129
|
+
Marks the behavior as deprecated when filtering queries for a specific invoice.
|
|
1130
|
+
|
|
1131
|
+
This method provides functionality to filter a queryset based on a specified
|
|
1132
|
+
invoice primary key and an entity model. It is marked as deprecated in favor
|
|
1133
|
+
of other entity behavior methods.
|
|
1134
|
+
|
|
1135
|
+
Parameters
|
|
1136
|
+
----------
|
|
1137
|
+
invoice_pk : UUID
|
|
1138
|
+
The primary key of the invoice to filter the queryset by.
|
|
1139
|
+
entity_model : EntityModel | str | UUID
|
|
1140
|
+
The entity to filter the queryset for. This can be an instance of
|
|
1141
|
+
EntityModel, a UUID, or a string representation of the entity.
|
|
1142
|
+
**kwargs : dict
|
|
1143
|
+
Additional filtering parameters to apply to the queryset.
|
|
1144
|
+
|
|
1145
|
+
Returns
|
|
1146
|
+
-------
|
|
1147
|
+
QuerySet
|
|
1148
|
+
A filtered queryset containing objects associated with the specified invoice.
|
|
1149
|
+
|
|
1150
|
+
Raises
|
|
1151
|
+
------
|
|
1152
|
+
Any exceptions raised during the call to `for_entity` or filtering process.
|
|
1153
|
+
|
|
1154
|
+
Notes
|
|
1155
|
+
-----
|
|
1156
|
+
The method is slated for deprecation and should be replaced with preferred
|
|
1157
|
+
methods for filtering querysets by entity behavior in the future.
|
|
1158
|
+
"""
|
|
1159
|
+
qs = self.for_entity(entity_model=entity_model, **kwargs)
|
|
903
1160
|
return qs.filter(invoice_model_id__exact=invoice_pk)
|
|
904
1161
|
|
|
905
|
-
|
|
906
|
-
|
|
1162
|
+
@deprecated_entity_slug_behavior
|
|
1163
|
+
def for_po(self, po_pk: UUID, entity_model: 'EntityModel | str | UUID' = None, **kwargs):
|
|
1164
|
+
"""
|
|
1165
|
+
Filters and retrieves entity records associated with a specific purchase order (PO) and entity model.
|
|
1166
|
+
|
|
1167
|
+
This method applies additional filtering to an existing queryset by matching the given PO primary
|
|
1168
|
+
key (UUID) with records tied to the corresponding PO model. It leverages an extended filter for
|
|
1169
|
+
entity behavior but is marked deprecated in favor of using alternative entity filtering methods.
|
|
1170
|
+
|
|
1171
|
+
Parameters
|
|
1172
|
+
----------
|
|
1173
|
+
po_pk : UUID
|
|
1174
|
+
The primary key identifier for the purchase order.
|
|
1175
|
+
entity_model : EntityModel or str or UUID
|
|
1176
|
+
The model representing the associated entity. If not provided, an alternate behavior based on
|
|
1177
|
+
`kwargs` or contextual settings will apply.
|
|
1178
|
+
**kwargs : dict, optional
|
|
1179
|
+
Additional keyword arguments provided for extended filtering.
|
|
1180
|
+
|
|
1181
|
+
Returns
|
|
1182
|
+
-------
|
|
1183
|
+
QuerySet
|
|
1184
|
+
A filtered queryset containing records that match the specified PO `po_pk` and entity model
|
|
1185
|
+
criteria.
|
|
1186
|
+
|
|
1187
|
+
Raises
|
|
1188
|
+
------
|
|
1189
|
+
None explicitly documented; refer to underlying methods (`for_entity`) for any potential errors.
|
|
1190
|
+
|
|
1191
|
+
Warnings
|
|
1192
|
+
--------
|
|
1193
|
+
This method is deprecated and may be removed in future versions. Use alternative entity filtering
|
|
1194
|
+
methods where applicable.
|
|
1195
|
+
"""
|
|
1196
|
+
qs = self.for_entity(entity_model=entity_model, **kwargs)
|
|
907
1197
|
return qs.filter(po_model__uuid__exact=po_pk)
|
|
908
1198
|
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
1199
|
+
@deprecated_entity_slug_behavior
|
|
1200
|
+
def for_estimate(self, cj_pk: UUID, entity_model: 'EntityModel | str | UUID' = None, **kwargs):
|
|
1201
|
+
"""
|
|
1202
|
+
Marks the method as deprecated for estimating behavior in relation to an entity.
|
|
1203
|
+
|
|
1204
|
+
This method is intended to filter a queryset based on a specific entity and a unique
|
|
1205
|
+
identifier (`cj_pk`). It's discouraged to use this method in new implementations as
|
|
1206
|
+
it has been marked deprecated.
|
|
912
1207
|
|
|
913
|
-
|
|
1208
|
+
Parameters
|
|
1209
|
+
----------
|
|
1210
|
+
cj_pk : UUID
|
|
1211
|
+
The unique identifier for the entity model to filter on.
|
|
1212
|
+
entity_model : EntityModel | str | UUID
|
|
1213
|
+
The entity model, which may be provided either as an `EntityModel` instance,
|
|
1214
|
+
a string representing its identifier, or a `UUID`. Defaults to `None`.
|
|
1215
|
+
**kwargs : dict
|
|
1216
|
+
Additional keyword arguments to pass to the entity filtering mechanism.
|
|
1217
|
+
|
|
1218
|
+
Returns
|
|
1219
|
+
-------
|
|
1220
|
+
QuerySet
|
|
1221
|
+
The filtered queryset based on the provided `cj_pk` and the optional
|
|
1222
|
+
`entity_model`.
|
|
1223
|
+
|
|
1224
|
+
Raises
|
|
1225
|
+
------
|
|
1226
|
+
TypeError
|
|
1227
|
+
If the input parameters are invalid or incompatible with the filtering process.
|
|
914
1228
|
"""
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
1229
|
+
qs = self.for_entity(entity_model=entity_model, **kwargs)
|
|
1230
|
+
return qs.filter(ce_model_id__exact=cj_pk)
|
|
1231
|
+
|
|
1232
|
+
@deprecated_entity_slug_behavior
|
|
1233
|
+
def for_contract(self, ce_pk: UUID, entity_model: 'EntityModel | str | UUID' = None, **kwargs):
|
|
920
1234
|
"""
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
1235
|
+
Provides a method to filter querysets based on the contract entity model to which they are associated.
|
|
1236
|
+
|
|
1237
|
+
Methods
|
|
1238
|
+
-------
|
|
1239
|
+
for_contract(ce_pk: UUID, entity_model: 'EntityModel | str | UUID' = None, **kwargs)
|
|
1240
|
+
Filters a queryset to include records associated with a specific contract entity
|
|
1241
|
+
model by its primary key and optionally narrows it down further using an entity model
|
|
1242
|
+
and additional query parameters.
|
|
1243
|
+
|
|
1244
|
+
Parameters
|
|
1245
|
+
----------
|
|
1246
|
+
ce_pk : UUID
|
|
1247
|
+
The unique identifier (primary key) of the contract entity model to filter by.
|
|
1248
|
+
entity_model : 'EntityModel | str | UUID'
|
|
1249
|
+
An optional entity model object, string representation, or primary key to use
|
|
1250
|
+
for filtering the queryset.
|
|
1251
|
+
**kwargs : dict
|
|
1252
|
+
Additional keyword arguments that can be passed to further refine the filtered queryset.
|
|
1253
|
+
|
|
1254
|
+
Returns
|
|
1255
|
+
-------
|
|
1256
|
+
qs : QuerySet
|
|
1257
|
+
A filtered queryset containing records associated with the specified contract entity
|
|
1258
|
+
model and additional filter conditions.
|
|
1259
|
+
|
|
1260
|
+
Raises
|
|
1261
|
+
------
|
|
1262
|
+
Exception
|
|
1263
|
+
Any exception raised while applying additional filters to the queryset or querying
|
|
1264
|
+
against the database.
|
|
1265
|
+
|
|
1266
|
+
Deprecated
|
|
1267
|
+
----------
|
|
1268
|
+
This function is deprecated for entity behavior.
|
|
1269
|
+
"""
|
|
1270
|
+
qs = self.for_entity(entity_model=entity_model, **kwargs)
|
|
925
1271
|
return qs.filter(
|
|
926
1272
|
Q(ce_model_id__exact=ce_pk) |
|
|
927
1273
|
Q(po_model__ce_model_id__exact=ce_pk) |
|
|
@@ -930,14 +1276,23 @@ class ItemTransactionModelManager(Manager):
|
|
|
930
1276
|
)
|
|
931
1277
|
|
|
932
1278
|
# INVENTORY METHODS....
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
1279
|
+
@deprecated_entity_slug_behavior
|
|
1280
|
+
def for_entity_inventory(self, entity_model: 'EntityModel | str | UUID' = None, **kwargs):
|
|
1281
|
+
EntityModel = lazy_loader.get_entity_model()
|
|
1282
|
+
|
|
1283
|
+
qs = self.for_entity(entity_model=entity_model, **kwargs)
|
|
1284
|
+
if isinstance(entity_model, EntityModel):
|
|
1285
|
+
qs = qs.filter(item_model__entity=entity_model)
|
|
1286
|
+
elif isinstance(entity_model, str):
|
|
1287
|
+
qs = qs.filter(item_model__entity__slug__exact=entity_model)
|
|
1288
|
+
elif isinstance(entity_model, UUID):
|
|
1289
|
+
qs = qs.filter(item_model__entity_id=entity_model)
|
|
1290
|
+
return qs
|
|
1291
|
+
|
|
1292
|
+
@deprecated_entity_slug_behavior
|
|
1293
|
+
def inventory_count(self, entity_model: 'EntityModel | str | UUID' = None, **kwargs):
|
|
939
1294
|
PurchaseOrderModel = lazy_loader.get_purchase_order_model()
|
|
940
|
-
qs = self.for_entity_inventory(
|
|
1295
|
+
qs = self.for_entity_inventory(entity_model=entity_model, **kwargs)
|
|
941
1296
|
qs = qs.filter(
|
|
942
1297
|
Q(item_model__for_inventory=True) &
|
|
943
1298
|
(
|
|
@@ -983,8 +1338,9 @@ class ItemTransactionModelManager(Manager):
|
|
|
983
1338
|
output_field=DecimalField(decimal_places=3)), Value(0.0), output_field=DecimalField())
|
|
984
1339
|
)
|
|
985
1340
|
|
|
986
|
-
|
|
987
|
-
|
|
1341
|
+
@deprecated_entity_slug_behavior
|
|
1342
|
+
def inventory_pipeline(self, entity_model: 'EntityModel | str | UUID' = None, **kwargs):
|
|
1343
|
+
qs = self.for_entity_inventory(entity_model=entity_model, **kwargs)
|
|
988
1344
|
return qs.filter(
|
|
989
1345
|
Q(item_model__for_inventory=True) &
|
|
990
1346
|
Q(bill_model__isnull=False) &
|
|
@@ -995,8 +1351,9 @@ class ItemTransactionModelManager(Manager):
|
|
|
995
1351
|
])
|
|
996
1352
|
)
|
|
997
1353
|
|
|
998
|
-
|
|
999
|
-
|
|
1354
|
+
@deprecated_entity_slug_behavior
|
|
1355
|
+
def inventory_pipeline_aggregate(self, entity_model: 'EntityModel | str | UUID' = None, **kwargs):
|
|
1356
|
+
qs = self.inventory_pipeline(entity_model=entity_model, **kwargs)
|
|
1000
1357
|
return qs.values(
|
|
1001
1358
|
'item_model__name',
|
|
1002
1359
|
'item_model__uom__name',
|
|
@@ -1005,20 +1362,24 @@ class ItemTransactionModelManager(Manager):
|
|
|
1005
1362
|
total_value=Sum('total_amount')
|
|
1006
1363
|
)
|
|
1007
1364
|
|
|
1008
|
-
|
|
1009
|
-
|
|
1365
|
+
@deprecated_entity_slug_behavior
|
|
1366
|
+
def inventory_pipeline_ordered(self, entity_model: 'EntityModel | str | UUID' = None, **kwargs):
|
|
1367
|
+
qs = self.inventory_pipeline(entity_model=entity_model)
|
|
1010
1368
|
return qs.filter(po_item_status=ItemTransactionModel.STATUS_ORDERED)
|
|
1011
1369
|
|
|
1012
|
-
|
|
1013
|
-
|
|
1370
|
+
@deprecated_entity_slug_behavior
|
|
1371
|
+
def inventory_pipeline_in_transit(self, entity_model: 'EntityModel | str | UUID' = None, **kwargs):
|
|
1372
|
+
qs = self.inventory_pipeline(entity_model=entity_model)
|
|
1014
1373
|
return qs.filter(po_item_status=ItemTransactionModel.STATUS_IN_TRANSIT)
|
|
1015
1374
|
|
|
1016
|
-
|
|
1017
|
-
|
|
1375
|
+
@deprecated_entity_slug_behavior
|
|
1376
|
+
def inventory_pipeline_received(self, entity_model: 'EntityModel | str | UUID' = None, **kwargs):
|
|
1377
|
+
qs = self.inventory_pipeline(entity_model=entity_model)
|
|
1018
1378
|
return qs.filter(po_item_status=ItemTransactionModel.STATUS_RECEIVED)
|
|
1019
1379
|
|
|
1020
|
-
|
|
1021
|
-
|
|
1380
|
+
@deprecated_entity_slug_behavior
|
|
1381
|
+
def inventory_invoiced(self, entity_model: 'EntityModel | str | UUID' = None, **kwargs):
|
|
1382
|
+
qs = self.for_entity_inventory(entity_model=entity_model, **kwargs)
|
|
1022
1383
|
return qs.filter(
|
|
1023
1384
|
Q(item_model__for_inventory=True) &
|
|
1024
1385
|
Q(invoice_model__isnull=False)
|