django-ledger 0.8.2.1__py3-none-any.whl → 0.8.2.2__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.

@@ -76,8 +76,7 @@ class ReceiptModelQuerySet(QuerySet):
76
76
  manage.
77
77
  """
78
78
  return self.filter(
79
- Q(ledger_model__entity__admin=user_model)
80
- | Q(ledger_model__entity__managers__in=[user_model])
79
+ Q(ledger_model__entity__admin=user_model) | Q(ledger_model__entity__managers__in=[user_model])
81
80
  )
82
81
 
83
82
  def for_dates(self, from_date, to_date) -> 'ReceiptModelQuerySet':
@@ -97,9 +96,7 @@ class ReceiptModelQuerySet(QuerySet):
97
96
  """
98
97
  return self.filter(receipt_date__gte=from_date, receipt_date__lte=to_date)
99
98
 
100
- def for_vendor(
101
- self, vendor_model: VendorModel | str | UUID
102
- ) -> 'ReceiptModelQuerySet':
99
+ def for_vendor(self, vendor_model: VendorModel | str | UUID) -> 'ReceiptModelQuerySet':
103
100
  """Filter receipts tied to a specific vendor.
104
101
 
105
102
  Parameters
@@ -134,14 +131,10 @@ class ReceiptModelQuerySet(QuerySet):
134
131
  customer_model__isnull=True,
135
132
  )
136
133
  raise ReceiptModelValidationError(
137
- 'Invalid Vendor Model: {}, must be instance of VendorModel, UUID, str'.format(
138
- vendor_model
139
- )
134
+ 'Invalid Vendor Model: {}, must be instance of VendorModel, UUID, str'.format(vendor_model)
140
135
  )
141
136
 
142
- def for_customer(
143
- self, customer_model: CustomerModel | str | UUID
144
- ) -> 'ReceiptModelQuerySet':
137
+ def for_customer(self, customer_model: CustomerModel | str | UUID) -> 'ReceiptModelQuerySet':
145
138
  """Filter receipts tied to a specific customer.
146
139
 
147
140
  Parameters
@@ -176,9 +169,7 @@ class ReceiptModelQuerySet(QuerySet):
176
169
  vendor_model__isnull=True,
177
170
  )
178
171
  raise ReceiptModelValidationError(
179
- 'Invalid Customer Model: {}, must be instance of CustomerModel, UUID, str'.format(
180
- customer_model
181
- )
172
+ 'Invalid Customer Model: {}, must be instance of CustomerModel, UUID, str'.format(customer_model)
182
173
  )
183
174
 
184
175
 
@@ -202,9 +193,7 @@ class ReceiptModelManager(Manager):
202
193
  )
203
194
  )
204
195
 
205
- def for_entity(
206
- self, entity_model: EntityModel | str | UUID
207
- ) -> ReceiptModelQuerySet:
196
+ def for_entity(self, entity_model: EntityModel | str | UUID) -> ReceiptModelQuerySet:
208
197
  """Filter receipts for a specific entity.
209
198
 
210
199
  Parameters
@@ -250,6 +239,7 @@ class ReceiptModelAbstract(CreateUpdateMixIn, MarkdownNotesMixIn, IOMixIn):
250
239
  EXPENSE_RECEIPT = 'expense'
251
240
  EXPENSE_REFUND = 'expense_refund'
252
241
  TRANSFER_RECEIPT = 'transfer'
242
+ DEBT_PAYMENT = 'debt_paydown'
253
243
 
254
244
  RECEIPT_TYPES = [
255
245
  (SALES_RECEIPT, 'Sales Receipt'),
@@ -257,15 +247,14 @@ class ReceiptModelAbstract(CreateUpdateMixIn, MarkdownNotesMixIn, IOMixIn):
257
247
  (EXPENSE_RECEIPT, 'Expense Receipt'),
258
248
  (EXPENSE_REFUND, 'Expense Refund'),
259
249
  (TRANSFER_RECEIPT, 'Transfer Receipt'),
250
+ (DEBT_PAYMENT, 'Debt Paydown Receipt'),
260
251
  ]
261
252
  RECEIPT_TYPES_MAP = dict(RECEIPT_TYPES)
262
253
 
263
254
  uuid = models.UUIDField(default=uuid4, editable=False, primary_key=True)
264
255
  receipt_number = models.CharField(_('Receipt Number'), max_length=255)
265
256
  receipt_date = models.DateField(_('Receipt Date'))
266
- receipt_type = models.CharField(
267
- choices=RECEIPT_TYPES, verbose_name=_('Receipt Type')
268
- )
257
+ receipt_type = models.CharField(choices=RECEIPT_TYPES, max_length=15, verbose_name=_('Receipt Type'))
269
258
 
270
259
  ledger_model = models.ForeignKey(
271
260
  'django_ledger.LedgerModel',
@@ -278,9 +267,7 @@ class ReceiptModelAbstract(CreateUpdateMixIn, MarkdownNotesMixIn, IOMixIn):
278
267
  'django_ledger.EntityUnitModel',
279
268
  on_delete=models.PROTECT,
280
269
  verbose_name=_('Unit Model'),
281
- help_text=_(
282
- 'Helps segregate receipts and transactions into different classes or departments.'
283
- ),
270
+ help_text=_('Helps segregate receipts and transactions into different classes or departments.'),
284
271
  null=True,
285
272
  blank=True,
286
273
  )
@@ -304,9 +291,7 @@ class ReceiptModelAbstract(CreateUpdateMixIn, MarkdownNotesMixIn, IOMixIn):
304
291
  'django_ledger.AccountModel',
305
292
  on_delete=models.PROTECT,
306
293
  verbose_name=_('Charge Account'),
307
- help_text=_(
308
- 'The financial account (cash or credit) where this transaction was made.'
309
- ),
294
+ help_text=_('The financial account (cash or credit) where this transaction was made.'),
310
295
  related_name='charge_receiptmodel_set',
311
296
  )
312
297
 
@@ -314,9 +299,9 @@ class ReceiptModelAbstract(CreateUpdateMixIn, MarkdownNotesMixIn, IOMixIn):
314
299
  'django_ledger.AccountModel',
315
300
  on_delete=models.PROTECT,
316
301
  verbose_name=_('PnL Account'),
317
- help_text=_(
318
- 'The income or expense account where this transaction will be reflected'
319
- ),
302
+ help_text=_('The income or expense account where this transaction will be reflected'),
303
+ null=True,
304
+ blank=True,
320
305
  )
321
306
 
322
307
  amount = models.DecimalField(
@@ -324,7 +309,7 @@ class ReceiptModelAbstract(CreateUpdateMixIn, MarkdownNotesMixIn, IOMixIn):
324
309
  max_digits=20,
325
310
  verbose_name=_('Receipt Amount'),
326
311
  help_text=_('Amount of the receipt.'),
327
- validators=[MinValueValidator(0)],
312
+ validators=[MinValueValidator(limit_value=0)],
328
313
  )
329
314
 
330
315
  staged_transaction_model = models.OneToOneField(
@@ -333,9 +318,7 @@ class ReceiptModelAbstract(CreateUpdateMixIn, MarkdownNotesMixIn, IOMixIn):
333
318
  null=True,
334
319
  blank=True,
335
320
  verbose_name=_('Staged Transaction Model'),
336
- help_text=_(
337
- 'The staged transaction associated with the receipt from bank feeds.'
338
- ),
321
+ help_text=_('The staged transaction associated with the receipt from bank feeds.'),
339
322
  )
340
323
 
341
324
  objects = ReceiptModelManager.from_queryset(queryset_class=ReceiptModelQuerySet)()
@@ -438,9 +421,7 @@ class ReceiptModelAbstract(CreateUpdateMixIn, MarkdownNotesMixIn, IOMixIn):
438
421
  ]
439
422
  )
440
423
 
441
- def delete(
442
- self, using=None, keep_parents=False, delete_ledger: bool = True, **kwargs
443
- ):
424
+ def delete(self, using=None, keep_parents=False, delete_ledger: bool = True, **kwargs):
444
425
  """Delete the receipt and related journal entries if allowed.
445
426
 
446
427
  Parameters
@@ -467,9 +448,7 @@ class ReceiptModelAbstract(CreateUpdateMixIn, MarkdownNotesMixIn, IOMixIn):
467
448
  """
468
449
  if not self.can_delete():
469
450
  raise ReceiptModelValidationError(
470
- message=_(
471
- 'Receipt cannot be deleted because it falls within a closed period.'
472
- ),
451
+ message=_('Receipt cannot be deleted because it falls within a closed period.'),
473
452
  )
474
453
  ledger = self.ledger_model
475
454
  with transaction.atomic():
@@ -556,9 +535,7 @@ class ReceiptModelAbstract(CreateUpdateMixIn, MarkdownNotesMixIn, IOMixIn):
556
535
  if self.vendor_model_id:
557
536
  return self.EXPENSE_REFUND if float(amount) > 0 else self.EXPENSE_RECEIPT
558
537
 
559
- raise ReceiptModelValidationError(
560
- message='Cannot determine receipt type without a customer or vendor.'
561
- )
538
+ raise ReceiptModelValidationError(message='Cannot determine receipt type without a customer or vendor.')
562
539
 
563
540
  def is_configured(self) -> bool:
564
541
  """Whether the receipt has enough data to operate.
@@ -612,9 +589,7 @@ class ReceiptModelAbstract(CreateUpdateMixIn, MarkdownNotesMixIn, IOMixIn):
612
589
 
613
590
  try:
614
591
  state_model_qs = (
615
- EntityStateModel.objects.filter(**LOOKUP)
616
- .select_related('entity_model')
617
- .select_for_update()
592
+ EntityStateModel.objects.filter(**LOOKUP).select_related('entity_model').select_for_update()
618
593
  )
619
594
 
620
595
  state_model = state_model_qs.get()
@@ -656,9 +631,7 @@ class ReceiptModelAbstract(CreateUpdateMixIn, MarkdownNotesMixIn, IOMixIn):
656
631
  state_model = self._get_next_state_model(raise_exception=False)
657
632
 
658
633
  seq = str(state_model.sequence).zfill(DJANGO_LEDGER_DOCUMENT_NUMBER_PADDING)
659
- self.receipt_number = (
660
- f'{DJANGO_LEDGER_RECEIPT_NUMBER_PREFIX}-{state_model.fiscal_year}-{seq}'
661
- )
634
+ self.receipt_number = f'{DJANGO_LEDGER_RECEIPT_NUMBER_PREFIX}-{state_model.fiscal_year}-{seq}'
662
635
 
663
636
  if commit:
664
637
  self.save(update_fields=['receipt_number', 'updated'])
@@ -668,9 +641,7 @@ class ReceiptModelAbstract(CreateUpdateMixIn, MarkdownNotesMixIn, IOMixIn):
668
641
  def configure(
669
642
  self,
670
643
  entity_model: EntityModel | str | UUID,
671
- receipt_type: Literal[
672
- SALES_RECEIPT, SALES_REFUND, EXPENSE_RECEIPT, EXPENSE_REFUND
673
- ],
644
+ receipt_type: Literal[SALES_RECEIPT, SALES_REFUND, EXPENSE_RECEIPT, EXPENSE_REFUND, TRANSFER_RECEIPT],
674
645
  amount: int | float | Decimal,
675
646
  unit_model: Optional[EntityUnitModel | str | UUID] = None,
676
647
  receipt_date: Optional[datetime | str] = None,
@@ -719,9 +690,7 @@ class ReceiptModelAbstract(CreateUpdateMixIn, MarkdownNotesMixIn, IOMixIn):
719
690
  if not self.is_configured():
720
691
  with transaction.atomic():
721
692
  if amount < 0:
722
- raise ReceiptModelValidationError(
723
- message='Receipt amount must be greater than zero'
724
- )
693
+ raise ReceiptModelValidationError(message='Receipt amount must be greater than zero')
725
694
  if isinstance(entity_model, EntityModel):
726
695
  pass
727
696
  elif isinstance(entity_model, UUID):
@@ -729,48 +698,58 @@ class ReceiptModelAbstract(CreateUpdateMixIn, MarkdownNotesMixIn, IOMixIn):
729
698
  elif isinstance(entity_model, str):
730
699
  entity_model = EntityModel.objects.get(slug__exact=entity_model)
731
700
 
732
- if all([vendor_model, customer_model]):
733
- raise ReceiptModelValidationError(
734
- message='Must pass VendorModel or CustomerModel, not both.',
735
- )
701
+ self.receipt_type = receipt_type
702
+ self.amount = amount
703
+ self.receipt_date = localdate() if not receipt_date else receipt_date
704
+ self.charge_account = charge_account
705
+ self.receipt_account = receipt_account
706
+ self.unit_model = unit_model
707
+ self.staged_transaction_model = staged_transaction_model
736
708
 
737
- if not any([vendor_model, customer_model]):
738
- raise ReceiptModelValidationError(
739
- message='Must pass VendorModel or CustomerModel.',
740
- )
709
+ if self.is_transfer_receipt():
710
+ if any([vendor_model, customer_model]):
711
+ raise ReceiptModelValidationError(
712
+ message='Transfer receipts do not require a vendor model or customer model',
713
+ )
714
+ else:
715
+ if all([vendor_model, customer_model]):
716
+ raise ReceiptModelValidationError(
717
+ message='Must pass VendorModel or CustomerModel, not both.',
718
+ )
741
719
 
742
- # checks if a vendor model has been previously assigned....
743
- if all(
744
- [
745
- vendor_model is not None,
746
- self.vendor_model_id is not None,
747
- ]
748
- ):
749
- raise ReceiptModelValidationError(
750
- message='Vendor Model already set.'
751
- )
720
+ if not any([vendor_model, customer_model]):
721
+ raise ReceiptModelValidationError(
722
+ message='Must pass VendorModel or CustomerModel.',
723
+ )
752
724
 
753
- # checks if a customer model has been previously assigned....
754
- if all(
755
- [
756
- customer_model is not None,
757
- self.customer_model_id is not None,
758
- ]
759
- ):
760
- raise ReceiptModelValidationError(
761
- message='Customer Model already set.'
762
- )
725
+ # checks if a vendor model has been previously assigned....
726
+ if all(
727
+ [
728
+ vendor_model is not None,
729
+ self.vendor_model_id is not None,
730
+ ]
731
+ ):
732
+ raise ReceiptModelValidationError(message='Vendor Model already set.')
733
+
734
+ # checks if a customer model has been previously assigned....
735
+ if all(
736
+ [
737
+ customer_model is not None,
738
+ self.customer_model_id is not None,
739
+ ]
740
+ ):
741
+ raise ReceiptModelValidationError(message='Customer Model already set.')
763
742
 
764
743
  # get vendor model...
765
744
  if vendor_model:
766
745
  if isinstance(vendor_model, str):
767
- vendor_model = VendorModel.objects.for_entity(
768
- entity_model=entity_model
769
- ).get(vendor_number__iexact=vendor_model)
746
+ vendor_model = VendorModel.objects.for_entity(entity_model=entity_model).get(
747
+ vendor_number__iexact=vendor_model
748
+ )
770
749
  elif isinstance(customer_model, UUID):
771
- vendor_model = VendorModel.objects.for_entity(
772
- entity_model=entity_model
773
- ).get(uuid__exact=vendor_model)
750
+ vendor_model = VendorModel.objects.for_entity(entity_model=entity_model).get(
751
+ uuid__exact=vendor_model
752
+ )
774
753
  elif isinstance(vendor_model, VendorModel):
775
754
  vendor_model.validate_for_entity(entity_model=entity_model)
776
755
  else:
@@ -782,13 +761,13 @@ class ReceiptModelAbstract(CreateUpdateMixIn, MarkdownNotesMixIn, IOMixIn):
782
761
  # get customer model
783
762
  if customer_model:
784
763
  if isinstance(customer_model, str):
785
- customer_model = CustomerModel.objects.for_entity(
786
- entity_model=customer_model
787
- ).get(customer_number__iexact=customer_model)
764
+ customer_model = CustomerModel.objects.for_entity(entity_model=customer_model).get(
765
+ customer_number__iexact=customer_model
766
+ )
788
767
  elif isinstance(customer_model, UUID):
789
- customer_model = CustomerModel.objects.for_entity(
790
- entity_model=customer_model
791
- ).get(uuid__exact=customer_model)
768
+ customer_model = CustomerModel.objects.for_entity(entity_model=customer_model).get(
769
+ uuid__exact=customer_model
770
+ )
792
771
  elif isinstance(customer_model, CustomerModel):
793
772
  customer_model.validate_for_entity(entity_model=entity_model)
794
773
  else:
@@ -799,33 +778,27 @@ class ReceiptModelAbstract(CreateUpdateMixIn, MarkdownNotesMixIn, IOMixIn):
799
778
 
800
779
  if unit_model:
801
780
  if isinstance(unit_model, str):
802
- unit_model = EntityUnitModel.objects.for_entity(
803
- entity_model=entity_model
804
- ).get(slug__exact=unit_model)
781
+ unit_model = EntityUnitModel.objects.for_entity(entity_model=entity_model).get(
782
+ slug__exact=unit_model
783
+ )
805
784
  elif isinstance(unit_model, UUID):
806
- unit_model = EntityUnitModel.objects.for_entity(
807
- entity_model=entity_model
808
- ).get(uuid__exact=unit_model)
785
+ unit_model = EntityUnitModel.objects.for_entity(entity_model=entity_model).get(
786
+ uuid__exact=unit_model
787
+ )
809
788
  elif isinstance(unit_model, EntityUnitModel):
810
789
  unit_model.validate_for_entity(entity_model=entity_model)
811
790
 
812
- self.receipt_type = receipt_type
813
- self.amount = amount
814
- self.receipt_date = localdate() if not receipt_date else receipt_date
815
- self.charge_account = charge_account
816
- self.receipt_account = receipt_account
817
- self.unit_model = unit_model
818
- self.staged_transaction_model = staged_transaction_model
819
-
820
791
  self.ledger_model = entity_model.create_ledger(
821
792
  name=entity_model.name,
822
793
  posted=True,
823
794
  commit=False,
824
795
  )
825
- receipt_number = self.generate_receipt_number(commit=True)
796
+
797
+ receipt_number = self.generate_receipt_number(commit=False)
798
+
826
799
  self.ledger_model.name = receipt_number
827
800
  self.ledger_model.save()
828
- self.full_clean()
801
+ self.clean()
829
802
 
830
803
  if commit:
831
804
  self.save()
@@ -841,10 +814,12 @@ class ReceiptModelAbstract(CreateUpdateMixIn, MarkdownNotesMixIn, IOMixIn):
841
814
  return all(
842
815
  [
843
816
  self.receipt_date is not None,
817
+ self.amount > 0.00,
818
+ self.charge_account_id is not None,
844
819
  any(
845
820
  [
846
- self.vendor_model_id is not None,
847
- self.customer_model_id is not None,
821
+ self.vendor_model_id is not None if not self.is_transfer_receipt() else True,
822
+ self.customer_model_id is not None if not self.is_transfer_receipt() else True,
848
823
  ]
849
824
  ),
850
825
  ]
@@ -910,9 +885,7 @@ class ReceiptModelAbstract(CreateUpdateMixIn, MarkdownNotesMixIn, IOMixIn):
910
885
  str
911
886
  URL string for listing receipts of the same entity.
912
887
  """
913
- return reverse(
914
- 'django_ledger:receipt-list', kwargs={'entity_slug': self.entity_slug}
915
- )
888
+ return reverse('django_ledger:receipt-list', kwargs={'entity_slug': self.entity_slug})
916
889
 
917
890
  def get_delete_url(self) -> str:
918
891
  """URL for the receipt delete view.
@@ -1039,16 +1012,12 @@ class ReceiptModelAbstract(CreateUpdateMixIn, MarkdownNotesMixIn, IOMixIn):
1039
1012
  """
1040
1013
  if self.is_sales_receipt():
1041
1014
  if not self.customer_model_id:
1042
- raise ReceiptModelValidationError(
1043
- message=_('Sales receipt must have a customer model.')
1044
- )
1015
+ raise ReceiptModelValidationError(message=_('Sales receipt must have a customer model.'))
1045
1016
  self.vendor_model = None
1046
1017
 
1047
1018
  if self.is_expense_receipt():
1048
1019
  if not self.vendor_model_id:
1049
- raise ReceiptModelValidationError(
1050
- message=_('Expense receipt must have a vendor model.')
1051
- )
1020
+ raise ReceiptModelValidationError(message=_('Expense receipt must have a vendor model.'))
1052
1021
  self.customer_model = None
1053
1022
 
1054
1023
 
@@ -10,6 +10,12 @@
10
10
  <h1 class="is-size-2">{% trans 'Pending Transactions' %}</h1>
11
11
  {% data_import_job_txs_pending staged_txs_formset %}
12
12
  </div>
13
+ <div class="column is-12 has-text-centered">
14
+ <form action="{{ import_job.get_data_import_reset_url }}" method="post">
15
+ {% csrf_token %}
16
+ <button class="button is-warning is-large">Reset Job</button>
17
+ </form>
18
+ </div>
13
19
  <div class="column is-12">
14
20
  <h2 class="is-size-2">{% trans 'Imported Transactions' %}</h2>
15
21
  {% data_import_job_txs_imported import_job %}
@@ -16,44 +16,74 @@
16
16
  </tr>
17
17
  </thead>
18
18
  <tbody>
19
- {% for imported_tx in imported_txs %}
20
- <tr id="staged-tx-{{ imported_tx.uuid }}">
21
- <td>{{ imported_tx.date_posted }}</td>
22
- <td>{{ imported_tx.name }}</td>
23
- <td class="{% if imported_tx.get_amount < 0.00 %}has-text-danger{% endif %} has-text-centered">
24
- {% currency_symbol %}{{ imported_tx.get_amount }}</td>
25
- <td>{% if imported_tx.activity %}
26
- {{ imported_tx.get_activity_display }}
27
- {% endif %}</td>
28
- <td>{% if imported_tx.entity_unit %}{{ imported_tx.entity_unit }}{% endif %}</td>
29
- <td>{{ imported_tx.account_model }}</td>
30
- <td>{{ imported_tx.transaction_model }}</td>
31
- <td class="has-text-centered">
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>
19
+ {% regroup imported_txs by group_uuid as bundled_groups %}
20
+ {% for group in bundled_groups %}
21
+ <tr class="has-background-light">
22
+ <td colspan="8" class="has-text-weight-bold">
23
+ {% trans 'Bundle' %} {{ forloop.counter }}
24
+ {% trans 'Parent' %}:
25
+ {% with parent_tx=group.list.0.parent|default:group.list.0 %}
26
+ {{ parent_tx.date_posted }} · {{ parent_tx.name }} ·
27
+ {% currency_symbol %}{{ parent_tx.get_amount }}
28
+ {% if parent_tx.get_activity_display %} · {{ parent_tx.get_activity_display }}{% endif %}
29
+ {% endwith %}
30
+ <span class="tag is-info is-light" style="margin-left: .5rem;">
31
+ {% if group.list.0.is_bundled %}{% trans 'Bundled' %}{% else %}
32
+ {% trans 'Not Bundled' %}{% endif %}
33
+ </span>
55
34
  </td>
56
35
  </tr>
36
+ {% for imported_tx in group.list %}
37
+ <tr id="staged-tx-{{ imported_tx.uuid }}" class="{% if imported_tx.is_children %}is-dark{% endif %}">
38
+ <td>{{ imported_tx.date_posted }}</td>
39
+ <td>
40
+ {% if imported_tx.is_children %}
41
+ <span class="tag is-primary is-light">{% trans 'Child' %}</span>
42
+ {% else %}
43
+ <span class="tag is-dark is-light">{% trans 'Parent' %}</span>
44
+ {% endif %}
45
+ {{ imported_tx.name }}
46
+ </td>
47
+ <td class="{% if imported_tx.get_amount < 0.00 %}has-text-danger{% endif %} has-text-centered">
48
+ {% currency_symbol %}{{ imported_tx.get_amount }}</td>
49
+ <td>{% if imported_tx.activity %}
50
+ {{ imported_tx.get_activity_display }}
51
+ {% endif %}</td>
52
+ <td>{% if imported_tx.entity_unit %}{{ imported_tx.entity_unit }}{% endif %}</td>
53
+ <td>{{ imported_tx.account_model }}</td>
54
+ <td>{{ imported_tx.transaction_model }}</td>
55
+ <td class="has-text-centered">
56
+ <div class="dropdown is-hoverable is-right">
57
+ <div class="dropdown-trigger">
58
+ <button class="button is-small" aria-haspopup="true"
59
+ aria-controls="actions-{{ imported_tx.uuid }}">
60
+ <span>{% trans 'Actions' %}</span>
61
+ <span class="icon is-small">{% icon 'mdi:chevron-down' 14 %}</span>
62
+ </button>
63
+ </div>
64
+ <div class="dropdown-menu" id="actions-{{ imported_tx.uuid }}" role="menu">
65
+ <div class="dropdown-content">
66
+ <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 %}"
67
+ class="dropdown-item">{% trans 'View JE' %}</a>
68
+ {% if imported_tx.has_receipt %}
69
+ <a href="{% url 'django_ledger:receipt-detail' entity_slug=import_job_model.entity_slug receipt_pk=imported_tx.receiptmodel.uuid %}"
70
+ class="dropdown-item">{% trans 'View Receipt' %}</a>
71
+ {% endif %}
72
+ <hr class="dropdown-divider">
73
+ {% if imported_tx.can_undo_import %}
74
+ <form method="post"
75
+ 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 %}">
76
+ {% csrf_token %}
77
+ <button type="submit"
78
+ class="dropdown-item has-text-danger">{% trans 'Undo Import' %}</button>
79
+ </form>
80
+ {% endif %}
81
+ </div>
82
+ </div>
83
+ </div>
84
+ </td>
85
+ </tr>
86
+ {% endfor %}
57
87
  {% endfor %}
58
88
  </tbody>
59
89
  </table>
@@ -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 %}
@@ -35,7 +35,8 @@
35
35
  <tbody>
36
36
 
37
37
  {% for txf in staged_txs_formset %}
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 %}">
38
+ <tr id="staged-tx-{{ txf.instance.uuid }}"
39
+ class="{% if txf.instance.is_children %}has-background-primary{% elif txf.instance.has_children %}has-background-primary-light{% endif %}">
39
40
  <td>{{ forloop.counter }}</td>
40
41
  {% for hidden_field in txf.hidden_fields %}{{ hidden_field }}{% endfor %}
41
42
  {% if txf.instance.is_children %}
@@ -61,7 +62,7 @@
61
62
  <span class="has-text-weight-bold">
62
63
  {{ txf.instance.get_prospect_je_activity_display }}
63
64
  </span>
64
- {% elif not txf.instance.is_children %}
65
+ {% elif not txf.instance.is_children and txf.instance.bundle_split %}
65
66
  <span class="has-text-danger">{% icon 'ooui:block' 16 %}</span>
66
67
  <span>Invalid or Pending Account Mapping.</span>
67
68
  {% endif %}
@@ -75,11 +76,10 @@
75
76
  <td>{{ txf.unit_model }}</td>
76
77
  <td>{{ txf.receipt_type }}</td>
77
78
  <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 %}
79
+ {{ txf.customer_model }}
80
+ {{ txf.vendor_model }}
81
+ {# {{ txf.instance.can_migrate }}#}
82
+ {# {{ txf.instance.ready_to_import }}#}
83
83
  </td>
84
84
  <td class="has-text-centered">{{ txf.tx_import }}</td>
85
85
  <td class="has-text-centered">{{ txf.bundle_split }}</td>
@@ -18,6 +18,9 @@ urlpatterns = [
18
18
  path('<slug:entity_slug>/jobs/<uuid:job_pk>/txs/',
19
19
  views.DataImportJobDetailView.as_view(),
20
20
  name='data-import-job-txs'),
21
+ path('<slug:entity_slug>/jobs/<uuid:job_pk>/reset/',
22
+ views.ImportJobModelResetView.as_view(),
23
+ name='data-import-job-txs-undo'),
21
24
  path('<slug:entity_slug>/jobs/<uuid:job_pk>/txs/<uuid:staged_tx_pk>/undo/',
22
25
  views.StagedTransactionUndoView.as_view(),
23
26
  name='data-import-staged-tx-undo'),