django-ledger 0.8.0__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/forms/account.py +45 -46
- django_ledger/forms/data_import.py +182 -63
- django_ledger/io/io_core.py +507 -374
- django_ledger/migrations/0026_stagedtransactionmodel_customer_model_and_more.py +56 -0
- django_ledger/models/__init__.py +2 -1
- django_ledger/models/bill.py +337 -300
- django_ledger/models/customer.py +47 -34
- django_ledger/models/data_import.py +770 -289
- django_ledger/models/entity.py +882 -637
- django_ledger/models/mixins.py +421 -280
- django_ledger/models/receipt.py +1083 -0
- django_ledger/models/transactions.py +105 -41
- django_ledger/models/unit.py +42 -30
- django_ledger/models/utils.py +12 -2
- django_ledger/models/vendor.py +85 -66
- django_ledger/settings.py +1 -0
- 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 +3 -1
- 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/layouts/base.html +1 -1
- 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 +3 -2
- django_ledger/templates/django_ledger/vendor/vendor_detail.html +86 -0
- django_ledger/templatetags/django_ledger.py +338 -191
- django_ledger/urls/__init__.py +1 -0
- 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/customer.py +56 -14
- django_ledger/views/data_import.py +119 -66
- django_ledger/views/mixins.py +112 -86
- django_ledger/views/receipt.py +294 -0
- django_ledger/views/vendor.py +53 -14
- {django_ledger-0.8.0.dist-info → django_ledger-0.8.1.dist-info}/METADATA +1 -1
- {django_ledger-0.8.0.dist-info → django_ledger-0.8.1.dist-info}/RECORD +51 -40
- {django_ledger-0.8.0.dist-info → django_ledger-0.8.1.dist-info}/WHEEL +0 -0
- {django_ledger-0.8.0.dist-info → django_ledger-0.8.1.dist-info}/licenses/AUTHORS.md +0 -0
- {django_ledger-0.8.0.dist-info → django_ledger-0.8.1.dist-info}/licenses/LICENSE +0 -0
- {django_ledger-0.8.0.dist-info → django_ledger-0.8.1.dist-info}/top_level.txt +0 -0
django_ledger/models/vendor.py
CHANGED
|
@@ -10,23 +10,29 @@ Vendors can be flagged as active/inactive or hidden. Vendors who no longer condu
|
|
|
10
10
|
whether temporarily or indefinitely may be flagged as inactive (i.e. active is False). Hidden Vendors will not show up
|
|
11
11
|
as an option in the UI, but can still be used programmatically (via API).
|
|
12
12
|
"""
|
|
13
|
+
|
|
13
14
|
import os
|
|
14
15
|
import warnings
|
|
15
|
-
from uuid import
|
|
16
|
+
from uuid import UUID, uuid4
|
|
16
17
|
|
|
17
18
|
from django.core.exceptions import ObjectDoesNotExist, ValidationError
|
|
18
|
-
from django.db import models, transaction
|
|
19
|
-
from django.db.models import
|
|
19
|
+
from django.db import IntegrityError, models, transaction
|
|
20
|
+
from django.db.models import F, Manager, Q, QuerySet
|
|
20
21
|
from django.utils.text import slugify
|
|
21
22
|
from django.utils.translation import gettext_lazy as _
|
|
22
23
|
|
|
23
24
|
from django_ledger.models.deprecations import deprecated_entity_slug_behavior
|
|
24
|
-
from django_ledger.models.mixins import
|
|
25
|
+
from django_ledger.models.mixins import (
|
|
26
|
+
ContactInfoMixIn,
|
|
27
|
+
CreateUpdateMixIn,
|
|
28
|
+
FinancialAccountInfoMixin,
|
|
29
|
+
TaxInfoMixIn,
|
|
30
|
+
)
|
|
25
31
|
from django_ledger.models.utils import lazy_loader
|
|
26
32
|
from django_ledger.settings import (
|
|
27
33
|
DJANGO_LEDGER_DOCUMENT_NUMBER_PADDING,
|
|
34
|
+
DJANGO_LEDGER_USE_DEPRECATED_BEHAVIOR,
|
|
28
35
|
DJANGO_LEDGER_VENDOR_NUMBER_PREFIX,
|
|
29
|
-
DJANGO_LEDGER_USE_DEPRECATED_BEHAVIOR
|
|
30
36
|
)
|
|
31
37
|
|
|
32
38
|
|
|
@@ -52,8 +58,8 @@ class VendorModelQuerySet(QuerySet):
|
|
|
52
58
|
if user_model.is_superuser:
|
|
53
59
|
return self
|
|
54
60
|
return self.filter(
|
|
55
|
-
Q(entity_model__admin=user_model)
|
|
56
|
-
Q(entity_model__managers__in=[user_model])
|
|
61
|
+
Q(entity_model__admin=user_model)
|
|
62
|
+
| Q(entity_model__managers__in=[user_model])
|
|
57
63
|
)
|
|
58
64
|
|
|
59
65
|
def active(self) -> 'VendorModelQuerySet':
|
|
@@ -102,9 +108,7 @@ class VendorModelQuerySet(QuerySet):
|
|
|
102
108
|
VendorModelQuerySet
|
|
103
109
|
A QuerySet of visible Vendors.
|
|
104
110
|
"""
|
|
105
|
-
return self.filter(
|
|
106
|
-
Q(hidden=False) & Q(active=True)
|
|
107
|
-
)
|
|
111
|
+
return self.filter(Q(hidden=False) & Q(active=True))
|
|
108
112
|
|
|
109
113
|
|
|
110
114
|
class VendorModelManager(Manager):
|
|
@@ -116,34 +120,36 @@ class VendorModelManager(Manager):
|
|
|
116
120
|
"""
|
|
117
121
|
|
|
118
122
|
@deprecated_entity_slug_behavior
|
|
119
|
-
def for_entity(
|
|
123
|
+
def for_entity(
|
|
124
|
+
self, entity_model: 'EntityModel | str | UUID' = None, **kwargs
|
|
125
|
+
) -> VendorModelQuerySet:
|
|
120
126
|
"""
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
127
|
+
Filters the queryset for a given entity model.
|
|
128
|
+
|
|
129
|
+
This method modifies the queryset to include only those records
|
|
130
|
+
associated with the specified entity model. The entity model can
|
|
131
|
+
be provided in various formats, such as an instance of `EntityModel`,
|
|
132
|
+
a string representing the entity's slug, or its UUID.
|
|
133
|
+
|
|
134
|
+
If a deprecated parameter `user_model` is provided, it will issue
|
|
135
|
+
a warning and may alter the behavior if the deprecated behavior flag
|
|
136
|
+
`DJANGO_LEDGER_USE_DEPRECATED_BEHAVIOR` is set.
|
|
137
|
+
|
|
138
|
+
Parameters
|
|
139
|
+
----------
|
|
140
|
+
entity_model : EntityModel | str | UUID
|
|
141
|
+
The entity model or its identifier (slug or UUID) to filter the
|
|
142
|
+
queryset by.
|
|
143
|
+
|
|
144
|
+
**kwargs
|
|
145
|
+
Additional parameters for optional functionality. The parameter
|
|
146
|
+
`user_model` is supported for backward compatibility but is
|
|
147
|
+
deprecated and should be avoided.
|
|
148
|
+
|
|
149
|
+
Returns
|
|
150
|
+
-------
|
|
151
|
+
VendorModelQuerySet
|
|
152
|
+
A queryset filtered for the given entity model.
|
|
147
153
|
"""
|
|
148
154
|
EntityModel = lazy_loader.get_entity_model()
|
|
149
155
|
|
|
@@ -153,7 +159,7 @@ class VendorModelManager(Manager):
|
|
|
153
159
|
'user_model parameter is deprecated and will be removed in a future release. '
|
|
154
160
|
'Use for_user(user_model).for_entity(entity_model) instead to keep current behavior.',
|
|
155
161
|
DeprecationWarning,
|
|
156
|
-
stacklevel=2
|
|
162
|
+
stacklevel=2,
|
|
157
163
|
)
|
|
158
164
|
|
|
159
165
|
if DJANGO_LEDGER_USE_DEPRECATED_BEHAVIOR:
|
|
@@ -172,10 +178,9 @@ class VendorModelManager(Manager):
|
|
|
172
178
|
return qs
|
|
173
179
|
|
|
174
180
|
|
|
175
|
-
class VendorModelAbstract(
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
CreateUpdateMixIn):
|
|
181
|
+
class VendorModelAbstract(
|
|
182
|
+
ContactInfoMixIn, FinancialAccountInfoMixin, TaxInfoMixIn, CreateUpdateMixIn
|
|
183
|
+
):
|
|
179
184
|
"""
|
|
180
185
|
This is the main abstract class which the VendorModel database will inherit from.
|
|
181
186
|
The VendorModel inherits functionality from the following MixIns:
|
|
@@ -214,28 +219,33 @@ class VendorModelAbstract(ContactInfoMixIn,
|
|
|
214
219
|
|
|
215
220
|
|
|
216
221
|
"""
|
|
222
|
+
|
|
217
223
|
uuid = models.UUIDField(default=uuid4, editable=False, primary_key=True)
|
|
218
224
|
vendor_code = models.SlugField(
|
|
219
|
-
max_length=50,
|
|
225
|
+
max_length=50, null=True, blank=True, verbose_name='User defined vendor code.'
|
|
226
|
+
)
|
|
227
|
+
vendor_number = models.CharField(
|
|
228
|
+
max_length=30,
|
|
220
229
|
null=True,
|
|
221
230
|
blank=True,
|
|
222
|
-
|
|
231
|
+
editable=False,
|
|
232
|
+
verbose_name=_('Vendor Number'),
|
|
233
|
+
help_text='System generated vendor number.',
|
|
223
234
|
)
|
|
224
|
-
vendor_number = models.CharField(max_length=30,
|
|
225
|
-
null=True,
|
|
226
|
-
blank=True,
|
|
227
|
-
editable=False,
|
|
228
|
-
verbose_name=_('Vendor Number'), help_text='System generated vendor number.')
|
|
229
235
|
vendor_name = models.CharField(max_length=100)
|
|
230
236
|
|
|
231
|
-
entity_model = models.ForeignKey(
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
237
|
+
entity_model = models.ForeignKey(
|
|
238
|
+
'django_ledger.EntityModel',
|
|
239
|
+
on_delete=models.CASCADE,
|
|
240
|
+
verbose_name=_('Vendor Entity'),
|
|
241
|
+
editable=False,
|
|
242
|
+
)
|
|
235
243
|
description = models.TextField()
|
|
236
244
|
active = models.BooleanField(default=True)
|
|
237
245
|
hidden = models.BooleanField(default=False)
|
|
238
|
-
picture = models.ImageField(
|
|
246
|
+
picture = models.ImageField(
|
|
247
|
+
upload_to=vendor_picture_upload_to, null=True, blank=True
|
|
248
|
+
)
|
|
239
249
|
|
|
240
250
|
additional_info = models.JSONField(null=True, blank=True, default=dict)
|
|
241
251
|
|
|
@@ -251,9 +261,7 @@ class VendorModelAbstract(ContactInfoMixIn,
|
|
|
251
261
|
models.Index(fields=['active']),
|
|
252
262
|
models.Index(fields=['hidden']),
|
|
253
263
|
]
|
|
254
|
-
unique_together = [
|
|
255
|
-
('entity_model', 'vendor_number')
|
|
256
|
-
]
|
|
264
|
+
unique_together = [('entity_model', 'vendor_number')]
|
|
257
265
|
abstract = True
|
|
258
266
|
|
|
259
267
|
def __str__(self):
|
|
@@ -261,6 +269,20 @@ class VendorModelAbstract(ContactInfoMixIn,
|
|
|
261
269
|
f'Unknown Vendor: {self.vendor_name}'
|
|
262
270
|
return f'{self.vendor_number}: {self.vendor_name}'
|
|
263
271
|
|
|
272
|
+
def validate_for_entity(self, entity_model: 'EntityModel | str | UUID'):
|
|
273
|
+
EntityModel = lazy_loader.get_entity_model()
|
|
274
|
+
if isinstance(entity_model, str):
|
|
275
|
+
is_valid = entity_model == self.entity_model.slug
|
|
276
|
+
elif isinstance(entity_model, EntityModel):
|
|
277
|
+
is_valid = entity_model == self.entity_model
|
|
278
|
+
elif isinstance(entity_model, UUID):
|
|
279
|
+
is_valid = entity_model == self.entity_model_id
|
|
280
|
+
|
|
281
|
+
if not is_valid:
|
|
282
|
+
raise VendorModelValidationError(
|
|
283
|
+
'EntityModel does not belong to this Vendor'
|
|
284
|
+
)
|
|
285
|
+
|
|
264
286
|
def can_generate_vendor_number(self) -> bool:
|
|
265
287
|
"""
|
|
266
288
|
Determines if the VendorModel can be issued a Vendor Number.
|
|
@@ -271,10 +293,7 @@ class VendorModelAbstract(ContactInfoMixIn,
|
|
|
271
293
|
bool
|
|
272
294
|
True if the vendor number can be generated, else False.
|
|
273
295
|
"""
|
|
274
|
-
return all([
|
|
275
|
-
self.entity_model_id,
|
|
276
|
-
not self.vendor_number
|
|
277
|
-
])
|
|
296
|
+
return all([self.entity_model_id, not self.vendor_number])
|
|
278
297
|
|
|
279
298
|
def _get_next_state_model(self, raise_exception: bool = True):
|
|
280
299
|
"""
|
|
@@ -296,10 +315,12 @@ class VendorModelAbstract(ContactInfoMixIn,
|
|
|
296
315
|
try:
|
|
297
316
|
LOOKUP = {
|
|
298
317
|
'entity_model_id__exact': self.entity_model_id,
|
|
299
|
-
'key__exact': EntityStateModel.KEY_VENDOR
|
|
318
|
+
'key__exact': EntityStateModel.KEY_VENDOR,
|
|
300
319
|
}
|
|
301
320
|
|
|
302
|
-
state_model_qs = EntityStateModel.objects.filter(
|
|
321
|
+
state_model_qs = EntityStateModel.objects.filter(
|
|
322
|
+
**LOOKUP
|
|
323
|
+
).select_for_update()
|
|
303
324
|
state_model = state_model_qs.get()
|
|
304
325
|
state_model.sequence = F('sequence') + 1
|
|
305
326
|
state_model.save()
|
|
@@ -307,13 +328,12 @@ class VendorModelAbstract(ContactInfoMixIn,
|
|
|
307
328
|
|
|
308
329
|
return state_model
|
|
309
330
|
except ObjectDoesNotExist:
|
|
310
|
-
|
|
311
331
|
LOOKUP = {
|
|
312
332
|
'entity_model_id': self.entity_model_id,
|
|
313
333
|
'entity_unit_id': None,
|
|
314
334
|
'fiscal_year': None,
|
|
315
335
|
'key': EntityStateModel.KEY_VENDOR,
|
|
316
|
-
'sequence': 1
|
|
336
|
+
'sequence': 1,
|
|
317
337
|
}
|
|
318
338
|
state_model = EntityStateModel.objects.create(**LOOKUP)
|
|
319
339
|
return state_model
|
|
@@ -338,7 +358,6 @@ class VendorModelAbstract(ContactInfoMixIn,
|
|
|
338
358
|
"""
|
|
339
359
|
if self.can_generate_vendor_number():
|
|
340
360
|
with transaction.atomic(durable=True):
|
|
341
|
-
|
|
342
361
|
state_model = None
|
|
343
362
|
while not state_model:
|
|
344
363
|
state_model = self._get_next_state_model(raise_exception=False)
|
django_ledger/settings.py
CHANGED
|
@@ -34,6 +34,7 @@ DJANGO_LEDGER_PO_NUMBER_PREFIX = getattr(settings, 'DJANGO_LEDGER_PO_NUMBER_PREF
|
|
|
34
34
|
DJANGO_LEDGER_ESTIMATE_NUMBER_PREFIX = getattr(settings, 'DJANGO_LEDGER_ESTIMATE_NUMBER_PREFIX', 'E')
|
|
35
35
|
DJANGO_LEDGER_INVOICE_NUMBER_PREFIX = getattr(settings, 'DJANGO_LEDGER_INVOICE_NUMBER_PREFIX', 'I')
|
|
36
36
|
DJANGO_LEDGER_BILL_NUMBER_PREFIX = getattr(settings, 'DJANGO_LEDGER_BILL_NUMBER_PREFIX', 'B')
|
|
37
|
+
DJANGO_LEDGER_RECEIPT_NUMBER_PREFIX = getattr(settings, 'DJANGO_LEDGER_BILL_NUMBER_PREFIX', 'R')
|
|
37
38
|
DJANGO_LEDGER_VENDOR_NUMBER_PREFIX = getattr(settings, 'DJANGO_LEDGER_VENDOR_NUMBER_PREFIX', 'V')
|
|
38
39
|
DJANGO_LEDGER_CUSTOMER_NUMBER_PREFIX = getattr(settings, 'DJANGO_LEDGER_CUSTOMER_NUMBER_PREFIX', 'C')
|
|
39
40
|
DJANGO_LEDGER_EXPENSE_NUMBER_PREFIX = getattr(settings, 'DJANGO_LEDGER_EXPENSE_NUMBER_PREFIX', 'IEX')
|
|
@@ -4,10 +4,12 @@
|
|
|
4
4
|
<div class="card">
|
|
5
5
|
<div class="card-content">
|
|
6
6
|
<div class="has-text-centered">
|
|
7
|
-
<h2 class="is-size-
|
|
7
|
+
<h2 class="is-size-4 has-font-weight-medium">
|
|
8
8
|
{% if has_year %}Fiscal Year {{ to_date.year }}{% endif %}
|
|
9
|
-
|
|
10
|
-
|
|
9
|
+
</h2>
|
|
10
|
+
<h2 class="is-size-5">
|
|
11
|
+
{% if has_month %}{{ to_date | date:"F" }}{% endif %}
|
|
12
|
+
{% if has_quarter %}Q{{ quarter }}{% endif %}
|
|
11
13
|
{% if has_date %}{{ to_date | date }}{% endif %}
|
|
12
14
|
</h2>
|
|
13
15
|
</div>
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
{% extends 'django_ledger/layouts/content_layout_1.html' %}
|
|
2
|
+
{% load i18n %}
|
|
3
|
+
{% load django_ledger %}
|
|
4
|
+
|
|
5
|
+
{% block view_content %}
|
|
6
|
+
|
|
7
|
+
<div class="box">
|
|
8
|
+
<div class="columns">
|
|
9
|
+
<div class="column is-one-third">
|
|
10
|
+
{% include 'django_ledger/customer/includes/card_customer.html' with customer=customer %}
|
|
11
|
+
</div>
|
|
12
|
+
<div class="column">
|
|
13
|
+
<div class="content">
|
|
14
|
+
<h3 class="title is-4">
|
|
15
|
+
<span class="icon is-small">{% icon 'mdi:receipt-text' 24 %}</span>
|
|
16
|
+
{% trans 'Receipts' %}
|
|
17
|
+
</h3>
|
|
18
|
+
{% if receipts %}
|
|
19
|
+
<div class="table-container">
|
|
20
|
+
<table class="table is-fullwidth is-narrow is-striped is-bordered">
|
|
21
|
+
<thead>
|
|
22
|
+
<tr>
|
|
23
|
+
<th class="has-text-centered">{% trans 'Receipt Number' %}</th>
|
|
24
|
+
<th class="has-text-centered">{% trans 'Date' %}</th>
|
|
25
|
+
<th class="has-text-centered">{% trans 'Type' %}</th>
|
|
26
|
+
<th class="has-text-centered">{% trans 'Actions' %}</th>
|
|
27
|
+
</tr>
|
|
28
|
+
</thead>
|
|
29
|
+
<tbody>
|
|
30
|
+
{% for receipt in receipts %}
|
|
31
|
+
<tr class="has-text-centered">
|
|
32
|
+
<td>
|
|
33
|
+
<a href="{{ receipt.get_absolute_url }}">{{ receipt.receipt_number }}</a>
|
|
34
|
+
</td>
|
|
35
|
+
<td>{{ receipt.receipt_date }}</td>
|
|
36
|
+
<td>{{ receipt.receipt_type|title }}</td>
|
|
37
|
+
<td>
|
|
38
|
+
{% if receipt.get_import_job_url %}
|
|
39
|
+
<a class="button is-small is-primary"
|
|
40
|
+
href="{{ receipt.get_import_job_url }}">{% trans 'Bank Feed Job' %}</a>
|
|
41
|
+
{% endif %}
|
|
42
|
+
</td>
|
|
43
|
+
</tr>
|
|
44
|
+
{% endfor %}
|
|
45
|
+
</tbody>
|
|
46
|
+
</table>
|
|
47
|
+
</div>
|
|
48
|
+
{% else %}
|
|
49
|
+
<p class="has-text-grey">{% trans 'No receipts found for this customer.' %}</p>
|
|
50
|
+
{% endif %}
|
|
51
|
+
|
|
52
|
+
<hr>
|
|
53
|
+
|
|
54
|
+
<h3 class="title is-4">
|
|
55
|
+
<span class="icon is-small">{% icon 'mdi:file-document-edit-outline' 24 %}</span>
|
|
56
|
+
{% trans 'Invoices' %}
|
|
57
|
+
</h3>
|
|
58
|
+
{% if invoices %}
|
|
59
|
+
<div class="table-container">
|
|
60
|
+
<table class="table is-fullwidth is-narrow is-striped is-bordered">
|
|
61
|
+
<thead>
|
|
62
|
+
<tr>
|
|
63
|
+
<th class="has-text-centered">{% trans 'Invoice Number' %}</th>
|
|
64
|
+
<th class="has-text-centered">{% trans 'Status' %}</th>
|
|
65
|
+
</tr>
|
|
66
|
+
</thead>
|
|
67
|
+
<tbody>
|
|
68
|
+
{% for invoice in invoices %}
|
|
69
|
+
<tr class="has-text-centered">
|
|
70
|
+
<td><a href="{{ invoice.get_absolute_url }}">{{ invoice.invoice_number }}</a>
|
|
71
|
+
</td>
|
|
72
|
+
<td>{{ invoice.get_invoice_status_display }}</td>
|
|
73
|
+
</tr>
|
|
74
|
+
{% endfor %}
|
|
75
|
+
</tbody>
|
|
76
|
+
</table>
|
|
77
|
+
</div>
|
|
78
|
+
{% else %}
|
|
79
|
+
<p class="has-text-grey">{% trans 'No invoices found for this customer.' %}</p>
|
|
80
|
+
{% endif %}
|
|
81
|
+
|
|
82
|
+
</div>
|
|
83
|
+
</div>
|
|
84
|
+
</div>
|
|
85
|
+
</div>
|
|
86
|
+
|
|
87
|
+
{% endblock %}
|
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
{% for customer in customers %}
|
|
19
19
|
<tr class="has-text-centered">
|
|
20
20
|
<td>{{ customer.customer_number }}</td>
|
|
21
|
-
<td>{{ customer.customer_name }}</td>
|
|
21
|
+
<td><a href="{% url 'django_ledger:customer-detail' entity_slug=view.kwargs.entity_slug customer_pk=customer.uuid %}">{{ customer.customer_name }}</a></td>
|
|
22
22
|
<td>{% if customer.address_1 %}{{ customer.address_1 }}{% endif %}</td>
|
|
23
23
|
<td>{% if customer.customer_code %}{{ customer.customer_code }}{% endif %}</td>
|
|
24
24
|
<td>
|
|
@@ -61,6 +61,8 @@
|
|
|
61
61
|
id="dropdown-menu-{{ customer.uuid }}"
|
|
62
62
|
role="menu">
|
|
63
63
|
<div class="dropdown-content">
|
|
64
|
+
<a href="{% url 'django_ledger:customer-detail' entity_slug=view.kwargs.entity_slug customer_pk=customer.uuid %}"
|
|
65
|
+
class="dropdown-item has-text-weight-bold has-text-success">{% trans 'View' %}</a>
|
|
64
66
|
<a href="{% url 'django_ledger:customer-update' entity_slug=view.kwargs.entity_slug customer_pk=customer.uuid %}"
|
|
65
67
|
class="dropdown-item has-text-weight-bold has-text-info">{% trans 'Update' %}</a>
|
|
66
68
|
</div>
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
</thead>
|
|
18
18
|
<tbody>
|
|
19
19
|
{% for imported_tx in imported_txs %}
|
|
20
|
-
<tr>
|
|
20
|
+
<tr id="staged-tx-{{ imported_tx.uuid }}">
|
|
21
21
|
<td>{{ imported_tx.date_posted }}</td>
|
|
22
22
|
<td>{{ imported_tx.name }}</td>
|
|
23
23
|
<td class="{% if imported_tx.get_amount < 0.00 %}has-text-danger{% endif %} has-text-centered">
|
|
@@ -29,8 +29,29 @@
|
|
|
29
29
|
<td>{{ imported_tx.account_model }}</td>
|
|
30
30
|
<td>{{ imported_tx.transaction_model }}</td>
|
|
31
31
|
<td class="has-text-centered">
|
|
32
|
-
<
|
|
33
|
-
|
|
32
|
+
<div class="dropdown is-hoverable is-right">
|
|
33
|
+
<div class="dropdown-trigger">
|
|
34
|
+
<button class="button is-small" aria-haspopup="true" aria-controls="actions-{{ imported_tx.uuid }}">
|
|
35
|
+
<span>{% trans 'Actions' %}</span>
|
|
36
|
+
<span class="icon is-small">{% icon 'mdi:chevron-down' 14 %}</span>
|
|
37
|
+
</button>
|
|
38
|
+
</div>
|
|
39
|
+
<div class="dropdown-menu" id="actions-{{ imported_tx.uuid }}" role="menu">
|
|
40
|
+
<div class="dropdown-content">
|
|
41
|
+
<a href="{% url 'django_ledger:je-detail' entity_slug=import_job_model.entity_slug ledger_pk=imported_tx.transaction_model.journal_entry.ledger_id je_pk=imported_tx.transaction_model.journal_entry_id %}"
|
|
42
|
+
class="dropdown-item">{% trans 'View JE' %}</a>
|
|
43
|
+
{% if imported_tx.has_receipt %}
|
|
44
|
+
<a href="{% url 'django_ledger:receipt-detail' entity_slug=import_job_model.entity_slug receipt_pk=imported_tx.receiptmodel.uuid %}"
|
|
45
|
+
class="dropdown-item">{% trans 'View Receipt' %}</a>
|
|
46
|
+
{% endif %}
|
|
47
|
+
<hr class="dropdown-divider">
|
|
48
|
+
<form method="post" action="{% url 'django_ledger:data-import-staged-tx-undo' entity_slug=import_job_model.entity_slug job_pk=import_job_model.uuid staged_tx_pk=imported_tx.uuid %}">
|
|
49
|
+
{% csrf_token %}
|
|
50
|
+
<button type="submit" class="dropdown-item has-text-danger">{% trans 'Undo Import' %}</button>
|
|
51
|
+
</form>
|
|
52
|
+
</div>
|
|
53
|
+
</div>
|
|
54
|
+
</div>
|
|
34
55
|
</td>
|
|
35
56
|
</tr>
|
|
36
57
|
{% endfor %}
|
|
@@ -5,9 +5,9 @@
|
|
|
5
5
|
<form method="post">
|
|
6
6
|
|
|
7
7
|
{{ staged_txs_formset.non_form_errors }}
|
|
8
|
-
{% if staged_txs_formset.errors %}
|
|
9
|
-
{{ staged_txs_formset.errors }}
|
|
10
|
-
{% endif %}
|
|
8
|
+
{# {% if staged_txs_formset.errors %}#}
|
|
9
|
+
{# {{ staged_txs_formset.errors }}#}
|
|
10
|
+
{# {% endif %}#}
|
|
11
11
|
{{ staged_txs_formset.management_form }}
|
|
12
12
|
|
|
13
13
|
{% csrf_token %}
|
|
@@ -23,9 +23,11 @@
|
|
|
23
23
|
<th>Split Amount</th>
|
|
24
24
|
<th>Map To</th>
|
|
25
25
|
<th>Unit</th>
|
|
26
|
+
<th>Receipt Type</th>
|
|
27
|
+
<th>Customer/Vendor</th>
|
|
26
28
|
<th>Import</th>
|
|
27
|
-
<th>Bundle
|
|
28
|
-
<th>
|
|
29
|
+
<th>Bundle</th>
|
|
30
|
+
<th>Split</th>
|
|
29
31
|
<th>Delete</th>
|
|
30
32
|
</tr>
|
|
31
33
|
</thead>
|
|
@@ -33,7 +35,7 @@
|
|
|
33
35
|
<tbody>
|
|
34
36
|
|
|
35
37
|
{% for txf in staged_txs_formset %}
|
|
36
|
-
<tr class="{% if txf.instance.is_children %}has-background-primary{% elif txf.instance.has_children %}has-background-primary-light{% endif %}">
|
|
38
|
+
<tr id="staged-tx-{{ txf.instance.uuid }}" class="{% if txf.instance.is_children %}has-background-primary{% elif txf.instance.has_children %}has-background-primary-light{% endif %}">
|
|
37
39
|
<td>{{ forloop.counter }}</td>
|
|
38
40
|
{% for hidden_field in txf.hidden_fields %}{{ hidden_field }}{% endfor %}
|
|
39
41
|
{% if txf.instance.is_children %}
|
|
@@ -54,16 +56,30 @@
|
|
|
54
56
|
|
|
55
57
|
<td>
|
|
56
58
|
{% if txf.instance.get_prospect_je_activity_display %}
|
|
59
|
+
<span class="has-text-success">{% icon 'lets-icons:check-fill' 16 %}</span>
|
|
57
60
|
<span class="is-italic">{% trans 'Transaction Activity' %}:</span>
|
|
58
61
|
<span class="has-text-weight-bold">
|
|
59
|
-
|
|
62
|
+
{{ txf.instance.get_prospect_je_activity_display }}
|
|
60
63
|
</span>
|
|
64
|
+
{% elif not txf.instance.is_children %}
|
|
65
|
+
<span class="has-text-danger">{% icon 'ooui:block' 16 %}</span>
|
|
66
|
+
<span>Invalid or Pending Account Mapping.</span>
|
|
61
67
|
{% endif %}
|
|
62
68
|
{{ txf.account_model }}
|
|
69
|
+
{% if txf.errors %}
|
|
70
|
+
{% for i,err in txf.errors.items %}
|
|
71
|
+
<span class="has-text-danger">{{ err }}</span>
|
|
72
|
+
{% endfor %}
|
|
73
|
+
{% endif %}
|
|
63
74
|
</td>
|
|
64
|
-
<td>{{ txf.unit_model }}
|
|
65
|
-
|
|
66
|
-
|
|
75
|
+
<td>{{ txf.unit_model }}</td>
|
|
76
|
+
<td>{{ txf.receipt_type }}</td>
|
|
77
|
+
<td class="has-text-centered">
|
|
78
|
+
{% if txf.SHOW_CUSTOMER_FIELD %}
|
|
79
|
+
{{ txf.customer_model }}
|
|
80
|
+
{% elif txf.SHOW_VENDOR_FIELD %}
|
|
81
|
+
{{ txf.vendor_model }}
|
|
82
|
+
{% endif %}
|
|
67
83
|
</td>
|
|
68
84
|
<td class="has-text-centered">{{ txf.tx_import }}</td>
|
|
69
85
|
<td class="has-text-centered">{{ txf.bundle_split }}</td>
|
|
@@ -7,7 +7,8 @@
|
|
|
7
7
|
<section class="section">
|
|
8
8
|
<div class="container is-fluid p-0">
|
|
9
9
|
<div class="columns">
|
|
10
|
-
<div class="column is-
|
|
10
|
+
<div class="column is-2 is-hidden-mobile is-hidden-tablet-only">
|
|
11
|
+
|
|
11
12
|
<div class="columns is-multiline">
|
|
12
13
|
<div class="column is-12">
|
|
13
14
|
{% if view.kwargs.unit_slug or request.GET.unit %}
|
|
@@ -21,7 +22,6 @@
|
|
|
21
22
|
</div>
|
|
22
23
|
</div>
|
|
23
24
|
|
|
24
|
-
|
|
25
25
|
</div>
|
|
26
26
|
<div class="column">
|
|
27
27
|
<div class="columns is-multiline is-centered">
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
<head>
|
|
8
8
|
<meta charset="utf-8">
|
|
9
9
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
10
|
-
<title>{% block page_title %}{
|
|
10
|
+
<title>{% block page_title %}{{ page_title }} | {{ entity_model.name | default:'' }}{% endblock %}</title>
|
|
11
11
|
|
|
12
12
|
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bulma@1.0.4/css/bulma.min.css">
|
|
13
13
|
<link rel="stylesheet" href="{% static 'django_ledger/css/djl_styles.css' %}">
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
|
|
9
9
|
{# SIDE MENU #}
|
|
10
10
|
{% if not hide_menu %}
|
|
11
|
-
<div class="column is-
|
|
11
|
+
<div class="column is-2 is-hidden-mobile is-hidden-tablet-only">
|
|
12
12
|
<div class="columns is-multiline">
|
|
13
13
|
{% block aux_menu %}{% endblock %}
|
|
14
14
|
<div class="column is-12">
|