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.

Files changed (51) hide show
  1. django_ledger/__init__.py +1 -1
  2. django_ledger/forms/account.py +45 -46
  3. django_ledger/forms/data_import.py +182 -63
  4. django_ledger/io/io_core.py +507 -374
  5. django_ledger/migrations/0026_stagedtransactionmodel_customer_model_and_more.py +56 -0
  6. django_ledger/models/__init__.py +2 -1
  7. django_ledger/models/bill.py +337 -300
  8. django_ledger/models/customer.py +47 -34
  9. django_ledger/models/data_import.py +770 -289
  10. django_ledger/models/entity.py +882 -637
  11. django_ledger/models/mixins.py +421 -280
  12. django_ledger/models/receipt.py +1083 -0
  13. django_ledger/models/transactions.py +105 -41
  14. django_ledger/models/unit.py +42 -30
  15. django_ledger/models/utils.py +12 -2
  16. django_ledger/models/vendor.py +85 -66
  17. django_ledger/settings.py +1 -0
  18. django_ledger/templates/django_ledger/components/period_navigator.html +5 -3
  19. django_ledger/templates/django_ledger/customer/customer_detail.html +87 -0
  20. django_ledger/templates/django_ledger/customer/customer_list.html +0 -1
  21. django_ledger/templates/django_ledger/customer/tags/customer_table.html +3 -1
  22. django_ledger/templates/django_ledger/data_import/tags/data_import_job_txs_imported.html +24 -3
  23. django_ledger/templates/django_ledger/data_import/tags/data_import_job_txs_table.html +26 -10
  24. django_ledger/templates/django_ledger/entity/entity_dashboard.html +2 -2
  25. django_ledger/templates/django_ledger/layouts/base.html +1 -1
  26. django_ledger/templates/django_ledger/layouts/content_layout_1.html +1 -1
  27. django_ledger/templates/django_ledger/receipt/customer_receipt_report.html +115 -0
  28. django_ledger/templates/django_ledger/receipt/receipt_delete.html +30 -0
  29. django_ledger/templates/django_ledger/receipt/receipt_detail.html +89 -0
  30. django_ledger/templates/django_ledger/receipt/receipt_list.html +134 -0
  31. django_ledger/templates/django_ledger/receipt/vendor_receipt_report.html +115 -0
  32. django_ledger/templates/django_ledger/vendor/tags/vendor_table.html +3 -2
  33. django_ledger/templates/django_ledger/vendor/vendor_detail.html +86 -0
  34. django_ledger/templatetags/django_ledger.py +338 -191
  35. django_ledger/urls/__init__.py +1 -0
  36. django_ledger/urls/customer.py +3 -0
  37. django_ledger/urls/data_import.py +3 -0
  38. django_ledger/urls/receipt.py +102 -0
  39. django_ledger/urls/vendor.py +1 -0
  40. django_ledger/views/__init__.py +1 -0
  41. django_ledger/views/customer.py +56 -14
  42. django_ledger/views/data_import.py +119 -66
  43. django_ledger/views/mixins.py +112 -86
  44. django_ledger/views/receipt.py +294 -0
  45. django_ledger/views/vendor.py +53 -14
  46. {django_ledger-0.8.0.dist-info → django_ledger-0.8.1.dist-info}/METADATA +1 -1
  47. {django_ledger-0.8.0.dist-info → django_ledger-0.8.1.dist-info}/RECORD +51 -40
  48. {django_ledger-0.8.0.dist-info → django_ledger-0.8.1.dist-info}/WHEEL +0 -0
  49. {django_ledger-0.8.0.dist-info → django_ledger-0.8.1.dist-info}/licenses/AUTHORS.md +0 -0
  50. {django_ledger-0.8.0.dist-info → django_ledger-0.8.1.dist-info}/licenses/LICENSE +0 -0
  51. {django_ledger-0.8.0.dist-info → django_ledger-0.8.1.dist-info}/top_level.txt +0 -0
@@ -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 uuid4, UUID
16
+ from uuid import UUID, uuid4
16
17
 
17
18
  from django.core.exceptions import ObjectDoesNotExist, ValidationError
18
- from django.db import models, transaction, IntegrityError
19
- from django.db.models import Q, F, QuerySet, Manager
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 ContactInfoMixIn, CreateUpdateMixIn, FinancialAccountInfoMixin, TaxInfoMixIn
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(self, entity_model: 'EntityModel | str | UUID' = None, **kwargs) -> VendorModelQuerySet:
123
+ def for_entity(
124
+ self, entity_model: 'EntityModel | str | UUID' = None, **kwargs
125
+ ) -> VendorModelQuerySet:
120
126
  """
121
- Filters the queryset for a given entity model.
122
-
123
- This method modifies the queryset to include only those records
124
- associated with the specified entity model. The entity model can
125
- be provided in various formats such as an instance of `EntityModel`,
126
- a string representing the entity's slug, or its UUID.
127
-
128
- If a deprecated parameter `user_model` is provided, it will issue
129
- a warning and may alter the behavior if the deprecated behavior flag
130
- `DJANGO_LEDGER_USE_DEPRECATED_BEHAVIOR` is set.
131
-
132
- Parameters
133
- ----------
134
- entity_model : EntityModel | str | UUID
135
- The entity model or its identifier (slug or UUID) to filter the
136
- queryset by.
137
-
138
- **kwargs
139
- Additional parameters for optional functionality. The parameter
140
- `user_model` is supported for backward compatibility but is
141
- deprecated and should be avoided.
142
-
143
- Returns
144
- -------
145
- VendorModelQuerySet
146
- A queryset filtered for the given entity model.
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(ContactInfoMixIn,
176
- FinancialAccountInfoMixin,
177
- TaxInfoMixIn,
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
- verbose_name='User defined vendor code.'
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('django_ledger.EntityModel',
232
- on_delete=models.CASCADE,
233
- verbose_name=_('Vendor Entity'),
234
- editable=False)
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(upload_to=vendor_picture_upload_to, null=True, blank=True)
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(**LOOKUP).select_for_update()
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-2 has-font-weight-medium">
7
+ <h2 class="is-size-4 has-font-weight-medium">
8
8
  {% if has_year %}Fiscal Year {{ to_date.year }}{% endif %}
9
- {% if has_month %}{{ to_date | date:"F Y" }}{% endif %}
10
- {% if has_quarter %}Q{{ quarter }} {{ year }}{% endif %}
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 %}
@@ -20,5 +20,4 @@
20
20
  {% customer_table %}
21
21
 
22
22
  </div>
23
- </div>
24
23
  {% 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
- <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 %}"
33
- class="button is-small is-primary">{% trans 'View JE' %}</a>
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 Split</th>
28
- <th>Add Split</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
- {{ txf.instance.get_prospect_je_activity_display }}
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 }}{% if txf.instance.is_children %}
65
- <span class="content is-small">{{ txf.instance.unit_model.name }}</span>
66
- {% endif %}
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-3 is-hidden-mobile is-hidden-tablet-only">
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 %}{% session_entity_name %} | {{ page_title }}{% endblock %}</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-3 is-hidden-mobile is-hidden-tablet-only">
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">