django-ledger 0.6.2__py3-none-any.whl → 0.6.4__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 (65) hide show
  1. django_ledger/__init__.py +1 -1
  2. django_ledger/admin/coa.py +1 -2
  3. django_ledger/admin/ledger.py +1 -0
  4. django_ledger/forms/account.py +22 -11
  5. django_ledger/forms/data_import.py +2 -1
  6. django_ledger/io/ofx.py +3 -2
  7. django_ledger/io/roles.py +6 -0
  8. django_ledger/models/accounts.py +523 -196
  9. django_ledger/models/bill.py +28 -14
  10. django_ledger/models/closing_entry.py +8 -0
  11. django_ledger/models/entity.py +12 -5
  12. django_ledger/models/estimate.py +93 -21
  13. django_ledger/models/invoice.py +44 -14
  14. django_ledger/models/journal_entry.py +112 -49
  15. django_ledger/models/ledger.py +32 -0
  16. django_ledger/models/purchase_order.py +34 -3
  17. django_ledger/models/signals.py +58 -0
  18. django_ledger/report/cash_flow_statement.py +1 -1
  19. django_ledger/report/core.py +1 -1
  20. django_ledger/static/.DS_Store +0 -0
  21. django_ledger/static/django_ledger/.DS_Store +0 -0
  22. django_ledger/static/django_ledger/logo_2/.DS_Store +0 -0
  23. django_ledger/static/django_ledger/logo_2/django_ledger_logo_dark.png +0 -0
  24. django_ledger/static/django_ledger/logo_2/django_ledger_logo_dark@0.5x.png +0 -0
  25. django_ledger/static/django_ledger/logo_2/django_ledger_logo_dark@2x.png +0 -0
  26. django_ledger/static/django_ledger/logo_2/django_ledger_logo_dark@3x.png +0 -0
  27. django_ledger/static/django_ledger/logo_2/djl-full-vert.png +0 -0
  28. django_ledger/static/django_ledger/logo_2/djl-full-vert@0.5x.png +0 -0
  29. django_ledger/static/django_ledger/logo_2/djl-full-vert@2x.png +0 -0
  30. django_ledger/static/django_ledger/logo_2/djl-full-vert@3x.png +0 -0
  31. django_ledger/static/django_ledger/logo_2/djl-logo-full-horiz.png +0 -0
  32. django_ledger/static/django_ledger/logo_2/djl-logo-full-horiz@0.5x.png +0 -0
  33. django_ledger/static/django_ledger/logo_2/djl-logo-full-horiz@2x.png +0 -0
  34. django_ledger/static/django_ledger/logo_2/djl-logo-full-horiz@3x.png +0 -0
  35. django_ledger/static/django_ledger/logo_2/djl-logo-full-vert.png +0 -0
  36. django_ledger/static/django_ledger/logo_2/djl-logo-full-vert@0.5x.png +0 -0
  37. django_ledger/static/django_ledger/logo_2/djl-logo-full-vert@2x.png +0 -0
  38. django_ledger/static/django_ledger/logo_2/djl-logo-full-vert@3x.png +0 -0
  39. django_ledger/static/django_ledger/logo_2/djl-logo.png +0 -0
  40. django_ledger/static/django_ledger/logo_2/djl-logo@0.5x.png +0 -0
  41. django_ledger/static/django_ledger/logo_2/djl-logo@2x.png +0 -0
  42. django_ledger/static/django_ledger/logo_2/djl-logo@3x.png +0 -0
  43. django_ledger/static/django_ledger/logo_2/djl-txt-full-horiz.png +0 -0
  44. django_ledger/static/django_ledger/logo_2/djl-txt-full-horiz@0.5x.png +0 -0
  45. django_ledger/static/django_ledger/logo_2/djl-txt-full-horiz@2x.png +0 -0
  46. django_ledger/static/django_ledger/logo_2/djl-txt-full-horiz@3x.png +0 -0
  47. django_ledger/static/django_ledger/logo_2/djl-txt-full-vert.png +0 -0
  48. django_ledger/static/django_ledger/logo_2/djl-txt-full-vert@0.5x.png +0 -0
  49. django_ledger/static/django_ledger/logo_2/djl-txt-full-vert@2x.png +0 -0
  50. django_ledger/static/django_ledger/logo_2/djl-txt-full-vert@3x.png +0 -0
  51. django_ledger/static/django_ledger/logo_2/djl-txt-horiz.png +0 -0
  52. django_ledger/static/django_ledger/logo_2/djl-txt-horiz@0.5x.png +0 -0
  53. django_ledger/static/django_ledger/logo_2/djl-txt-horiz@2x.png +0 -0
  54. django_ledger/static/django_ledger/logo_2/djl-txt-horiz@3x.png +0 -0
  55. django_ledger/templates/django_ledger/financial_statements/balance_sheet.html +2 -2
  56. django_ledger/tests/test_io_ofx/__init__.py +0 -0
  57. django_ledger/tests/test_io_ofx/tests.py +52 -0
  58. django_ledger/views/account.py +1 -1
  59. django_ledger/views/bill.py +1 -1
  60. {django_ledger-0.6.2.dist-info → django_ledger-0.6.4.dist-info}/METADATA +1 -1
  61. {django_ledger-0.6.2.dist-info → django_ledger-0.6.4.dist-info}/RECORD +65 -27
  62. {django_ledger-0.6.2.dist-info → django_ledger-0.6.4.dist-info}/top_level.txt +0 -1
  63. {django_ledger-0.6.2.dist-info → django_ledger-0.6.4.dist-info}/AUTHORS.md +0 -0
  64. {django_ledger-0.6.2.dist-info → django_ledger-0.6.4.dist-info}/LICENSE +0 -0
  65. {django_ledger-0.6.2.dist-info → django_ledger-0.6.4.dist-info}/WHEEL +0 -0
@@ -4,7 +4,6 @@ Copyright© EDMA Group Inc licensed under the GPLv3 Agreement.
4
4
 
5
5
  Contributions to this module:
6
6
  * Miguel Sanda <msanda@arrobalytics.com>
7
- * Pranav P Tulshyan <ptulshyan77@gmail.com>
8
7
 
9
8
  This module implements the BillModel, which represents an Invoice received from a Supplier/Vendor, on which
10
9
  the Vendor states the amount owed by the recipient for the purposes of supplying goods and/or services.
@@ -39,6 +38,14 @@ from django_ledger.models.entity import EntityModel
39
38
  from django_ledger.models.items import ItemTransactionModelQuerySet, ItemTransactionModel, ItemModel, ItemModelQuerySet
40
39
  from django_ledger.models.mixins import (CreateUpdateMixIn, AccrualMixIn, MarkdownNotesMixIn,
41
40
  PaymentTermsMixIn, ItemizeMixIn)
41
+ from django_ledger.models.signals import (
42
+ bill_status_draft,
43
+ bill_status_in_review,
44
+ bill_status_approved,
45
+ bill_status_paid,
46
+ bill_status_canceled,
47
+ bill_status_void,
48
+ )
42
49
  from django_ledger.models.utils import lazy_loader
43
50
  from django_ledger.settings import (DJANGO_LEDGER_DOCUMENT_NUMBER_PADDING, DJANGO_LEDGER_BILL_NUMBER_PREFIX)
44
51
 
@@ -612,9 +619,8 @@ class BillModelAbstract(
612
619
  account_unit_total=Sum('total_amount')
613
620
  )
614
621
 
615
- def update_amount_due(self,
616
- itemtxs_qs: Optional[Union[ItemTransactionModelQuerySet, List[ItemTransactionModel]]] = None
617
- ) -> ItemTransactionModelQuerySet:
622
+ def update_amount_due(self, itemtxs_qs: Optional[
623
+ Union[ItemTransactionModelQuerySet, List[ItemTransactionModel]]] = None) -> ItemTransactionModelQuerySet:
618
624
  """
619
625
  Updates the BillModel amount due.
620
626
 
@@ -1071,6 +1077,9 @@ class BillModelAbstract(
1071
1077
  'updated'
1072
1078
  ]
1073
1079
  )
1080
+ bill_status_draft.send_robust(sender=self.__class__,
1081
+ instance=self,
1082
+ commited=commit, **kwargs)
1074
1083
 
1075
1084
  def get_mark_as_draft_html_id(self) -> str:
1076
1085
  """
@@ -1176,6 +1185,9 @@ class BillModelAbstract(
1176
1185
  'updated'
1177
1186
  ]
1178
1187
  )
1188
+ bill_status_in_review.send_robust(sender=self.__class__,
1189
+ instance=self,
1190
+ commited=commit, **kwargs)
1179
1191
 
1180
1192
  def get_mark_as_review_html_id(self) -> str:
1181
1193
  """
@@ -1283,6 +1295,9 @@ class BillModelAbstract(
1283
1295
  force_migrate=self.accrue
1284
1296
  )
1285
1297
  self.ledger.post(commit=commit, raise_exception=raise_exception)
1298
+ bill_status_approved.send_robust(sender=self.__class__,
1299
+ instance=self,
1300
+ commited=commit, **kwargs)
1286
1301
 
1287
1302
  def get_mark_as_approved_html_id(self) -> str:
1288
1303
  """
@@ -1406,6 +1421,9 @@ class BillModelAbstract(
1406
1421
  force_migrate=True
1407
1422
  )
1408
1423
  self.lock_ledger(commit=True)
1424
+ bill_status_paid.send_robust(sender=self.__class__,
1425
+ instance=self,
1426
+ commited=commit, **kwargs)
1409
1427
 
1410
1428
  def get_mark_as_paid_html_id(self) -> str:
1411
1429
  """
@@ -1507,6 +1525,9 @@ class BillModelAbstract(
1507
1525
  force_migrate=True)
1508
1526
  self.save()
1509
1527
  self.lock_ledger(commit=False, raise_exception=False)
1528
+ bill_status_void.send_robust(sender=self.__class__,
1529
+ instance=self,
1530
+ commited=commit, **kwargs)
1510
1531
 
1511
1532
  def get_mark_as_void_html_id(self) -> str:
1512
1533
  """
@@ -1574,6 +1595,9 @@ class BillModelAbstract(
1574
1595
  self.clean()
1575
1596
  if commit:
1576
1597
  self.save()
1598
+ bill_status_canceled.send_robust(sender=self.__class__,
1599
+ instance=self,
1600
+ commited=commit, **kwargs)
1577
1601
 
1578
1602
  def get_mark_as_canceled_html_id(self) -> str:
1579
1603
  """
@@ -1890,13 +1914,3 @@ def billmodel_presave(instance: BillModel, **kwargs):
1890
1914
 
1891
1915
 
1892
1916
  pre_save.connect(receiver=billmodel_presave, sender=BillModel)
1893
-
1894
- # def billmodel_predelete(instance: BillModel, **kwargs):
1895
- # ledger_model = instance.ledger
1896
- # ledger_model.unpost(commit=False)
1897
- # ledger_model.remove_wrapped_model_info()
1898
- # ledger_model.itemtransactonmodel_set.all().delete()
1899
- # instance.ledger.delete()
1900
- #
1901
- #
1902
- # pre_delete.connect(receiver=billmodel_predelete, sender=BillModel)
@@ -1,3 +1,11 @@
1
+ """
2
+ Django Ledger created by Miguel Sanda <msanda@arrobalytics.com>.
3
+ Copyright© EDMA Group Inc licensed under the GPLv3 Agreement.
4
+
5
+ Contributions to this module:
6
+ * Miguel Sanda <msanda@arrobalytics.com>
7
+ """
8
+
1
9
  from datetime import datetime, time
2
10
  from decimal import Decimal
3
11
  from itertools import groupby, chain
@@ -1292,12 +1292,19 @@ class EntityModelAbstract(MP_Node,
1292
1292
  """
1293
1293
 
1294
1294
  if not coa_model:
1295
- account_model_qs = self.default_coa.accountmodel_set.all().select_related(
1296
- 'coa_model', 'coa_model__entity').not_coa_root()
1297
- else:
1295
+ coa_model = self.default_coa
1296
+ elif isinstance(coa_model, UUID):
1297
+ coa_model = self.chartofaccountmodel_set.get(uuid__exact=coa_model)
1298
+ elif isinstance(coa_model, str):
1299
+ coa_model = self.chartofaccountmodel_set.get(slug__exact=coa_model)
1300
+ elif isinstance(coa_model, ChartOfAccountModel):
1298
1301
  self.validate_chart_of_accounts_for_entity(coa_model=coa_model)
1299
- account_model_qs = coa_model.accountmodel_set.select_related(
1300
- 'coa_model', 'coa_model__entity').not_coa_root()
1302
+ else:
1303
+ raise EntityModelValidationError(
1304
+ f'CoA Model {coa_model} must be an instance of ChartOfAccountModel, UUID, str or None.'
1305
+ )
1306
+
1307
+ account_model_qs = coa_model.accountmodel_set.select_related('coa_model', 'coa_model__entity').not_coa_root()
1301
1308
 
1302
1309
  if active:
1303
1310
  account_model_qs = account_model_qs.active()
@@ -36,6 +36,14 @@ from django_ledger.models.entity import EntityModel, EntityStateModel
36
36
  from django_ledger.models.items import ItemTransactionModelQuerySet, ItemTransactionModel, ItemModelQuerySet, ItemModel
37
37
  from django_ledger.models.mixins import CreateUpdateMixIn, MarkdownNotesMixIn, ItemizeMixIn
38
38
  from django_ledger.models.purchase_order import PurchaseOrderModelQuerySet
39
+ from django_ledger.models.signals import (
40
+ estimate_status_void,
41
+ estimate_status_draft,
42
+ estimate_status_approved,
43
+ estimate_status_canceled,
44
+ estimate_status_completed,
45
+ estimate_status_in_review
46
+ )
39
47
  from django_ledger.settings import DJANGO_LEDGER_DOCUMENT_NUMBER_PADDING, DJANGO_LEDGER_ESTIMATE_NUMBER_PREFIX
40
48
 
41
49
  ESTIMATE_NUMBER_CHARS = ascii_uppercase + digits
@@ -610,7 +618,7 @@ class EstimateModelAbstract(CreateUpdateMixIn,
610
618
 
611
619
  # Actions...
612
620
  # DRAFT...
613
- def mark_as_draft(self, commit: bool = False):
621
+ def mark_as_draft(self, commit: bool = False, raise_exception: bool = True, **kwargs):
614
622
  """
615
623
  Marks the current EstimateModel instance as Draft.
616
624
 
@@ -620,7 +628,9 @@ class EstimateModelAbstract(CreateUpdateMixIn,
620
628
  Commits transaction into current EstimateModel instance.
621
629
  """
622
630
  if not self.can_draft():
623
- raise EstimateModelValidationError(f'Estimate {self.estimate_number} cannot be marked as draft...')
631
+ if raise_exception:
632
+ raise EstimateModelValidationError(f'Estimate {self.estimate_number} cannot be marked as draft...')
633
+ return
624
634
  self.status = self.CONTRACT_STATUS_DRAFT
625
635
  self.clean()
626
636
  if commit:
@@ -628,6 +638,10 @@ class EstimateModelAbstract(CreateUpdateMixIn,
628
638
  'status',
629
639
  'updated'
630
640
  ])
641
+ estimate_status_draft.send_robust(sender=self.__class__,
642
+ instance=self,
643
+ commited=commit,
644
+ **kwargs)
631
645
 
632
646
  def get_mark_as_draft_html_id(self):
633
647
  """
@@ -670,7 +684,10 @@ class EstimateModelAbstract(CreateUpdateMixIn,
670
684
  def mark_as_review(self,
671
685
  itemtxs_qs: Optional[ItemTransactionModelQuerySet] = None,
672
686
  date_in_review: Optional[date] = None,
673
- commit: bool = True):
687
+ raise_exception: bool = True,
688
+ commit: bool = True,
689
+ **kwargs):
690
+
674
691
  """
675
692
  Marks the current EstimateModel instance as In Review.
676
693
 
@@ -685,7 +702,9 @@ class EstimateModelAbstract(CreateUpdateMixIn,
685
702
  Optional date when EstimateModel instance is In Review. Defaults to localdate().
686
703
  """
687
704
  if not self.can_review():
688
- raise ValidationError(f'Estimate {self.estimate_number} cannot be marked as In Review...')
705
+ if raise_exception:
706
+ raise ValidationError(f'Estimate {self.estimate_number} cannot be marked as In Review...')
707
+ return
689
708
 
690
709
  if not itemtxs_qs:
691
710
  itemtxs_qs = self.itemtransactionmodel_set.all()
@@ -710,6 +729,10 @@ class EstimateModelAbstract(CreateUpdateMixIn,
710
729
  'status',
711
730
  'updated'
712
731
  ])
732
+ estimate_status_in_review.send_robust(sender=self.__class__,
733
+ instance=self,
734
+ commited=commit,
735
+ **kwargs)
713
736
 
714
737
  def get_mark_as_review_html_id(self):
715
738
  """
@@ -749,7 +772,11 @@ class EstimateModelAbstract(CreateUpdateMixIn,
749
772
  return _('Do you want to mark Estimate %s as In Review?') % self.estimate_number
750
773
 
751
774
  # APPROVED
752
- def mark_as_approved(self, commit=False, date_approved: Optional[date] = None):
775
+ def mark_as_approved(self,
776
+ commit=False,
777
+ date_approved: Optional[date] = None,
778
+ raise_exception: bool = True,
779
+ **kwargs):
753
780
  """
754
781
  Marks the current EstimateModel instance as Approved.
755
782
 
@@ -761,9 +788,12 @@ class EstimateModelAbstract(CreateUpdateMixIn,
761
788
  Optional date when EstimateModel instance is Approved. Defaults to localdate().
762
789
  """
763
790
  if not self.can_approve():
764
- raise EstimateModelValidationError(
765
- f'Estimate {self.estimate_number} cannot be marked as approved.'
766
- )
791
+ if raise_exception:
792
+ raise EstimateModelValidationError(
793
+ f'Estimate {self.estimate_number} cannot be marked as approved.'
794
+ )
795
+ return
796
+
767
797
  if not date_approved:
768
798
  date_approved = get_localdate()
769
799
  self.date_approved = date_approved
@@ -775,6 +805,10 @@ class EstimateModelAbstract(CreateUpdateMixIn,
775
805
  'date_approved',
776
806
  'updated'
777
807
  ])
808
+ estimate_status_approved.send_robust(sender=self.__class__,
809
+ instance=self,
810
+ commited=commit,
811
+ **kwargs)
778
812
 
779
813
  def get_mark_as_approved_html_id(self):
780
814
  """
@@ -814,7 +848,11 @@ class EstimateModelAbstract(CreateUpdateMixIn,
814
848
  return _('Do you want to mark Estimate %s as Approved?') % self.estimate_number
815
849
 
816
850
  # COMPLETED
817
- def mark_as_completed(self, commit=False, date_completed: Optional[date] = None):
851
+ def mark_as_completed(self,
852
+ commit=False,
853
+ date_completed: Optional[date] = None,
854
+ raise_exception: bool = True,
855
+ **kwargs):
818
856
  """
819
857
  Marks the current EstimateModel instance as Completed.
820
858
 
@@ -826,7 +864,9 @@ class EstimateModelAbstract(CreateUpdateMixIn,
826
864
  Optional date when EstimateModel instance is completed. Defaults to localdate().
827
865
  """
828
866
  if not self.can_complete():
829
- raise EstimateModelValidationError(f'Estimate {self.estimate_number} cannot be marked as completed.')
867
+ if raise_exception:
868
+ raise EstimateModelValidationError(f'Estimate {self.estimate_number} cannot be marked as completed.')
869
+ return
830
870
  if not date_completed:
831
871
  date_completed = get_localdate()
832
872
  self.date_completed = date_completed
@@ -834,11 +874,18 @@ class EstimateModelAbstract(CreateUpdateMixIn,
834
874
  self.clean()
835
875
  if commit:
836
876
  self.clean()
837
- self.save(update_fields=[
838
- 'status',
839
- 'date_completed',
840
- 'updated'
841
- ])
877
+ self.save(
878
+ update_fields=[
879
+ 'status',
880
+ 'date_completed',
881
+ 'updated'
882
+ ])
883
+ estimate_status_completed.send_robust(
884
+ sender=self.__class__,
885
+ instance=self,
886
+ commited=commit,
887
+ **kwargs
888
+ )
842
889
 
843
890
  def get_mark_as_completed_html_id(self):
844
891
  """
@@ -878,7 +925,11 @@ class EstimateModelAbstract(CreateUpdateMixIn,
878
925
  return _('Do you want to mark Estimate %s as Completed?') % self.estimate_number
879
926
 
880
927
  # CANCEL
881
- def mark_as_canceled(self, commit: bool = False, date_canceled: Optional[date] = None):
928
+ def mark_as_canceled(self,
929
+ commit: bool = False,
930
+ date_canceled: Optional[date] = None,
931
+ raise_exception: bool = True,
932
+ **kwargs):
882
933
  """
883
934
  Marks the current EstimateModel instance as Canceled.
884
935
 
@@ -890,7 +941,9 @@ class EstimateModelAbstract(CreateUpdateMixIn,
890
941
  Optional date when EstimateModel instance is canceled. Defaults to localdate().
891
942
  """
892
943
  if not self.can_cancel():
893
- raise EstimateModelValidationError(f'Estimate {self.estimate_number} cannot be canceled...')
944
+ if raise_exception:
945
+ raise EstimateModelValidationError(f'Estimate {self.estimate_number} cannot be canceled...')
946
+ return
894
947
  if not date_canceled:
895
948
  date_canceled = get_localdate()
896
949
  self.date_canceled = date_canceled
@@ -902,6 +955,12 @@ class EstimateModelAbstract(CreateUpdateMixIn,
902
955
  'date_canceled',
903
956
  'updated'
904
957
  ])
958
+ estimate_status_canceled.send_robust(
959
+ sender=self.__class__,
960
+ instance=self,
961
+ commited=commit,
962
+ **kwargs
963
+ )
905
964
 
906
965
  def get_mark_as_canceled_html_id(self):
907
966
  """
@@ -941,7 +1000,12 @@ class EstimateModelAbstract(CreateUpdateMixIn,
941
1000
  return _('Do you want to mark Estimate %s as Canceled?') % self.estimate_number
942
1001
 
943
1002
  # VOID
944
- def mark_as_void(self, commit: bool = False, date_void: Optional[date] = None):
1003
+ def mark_as_void(self,
1004
+ commit: bool = False,
1005
+ date_void: Optional[date] = None,
1006
+ raise_exception: bool = True,
1007
+ **kwargs):
1008
+
945
1009
  """
946
1010
  Marks the current EstimateModel instance as Void.
947
1011
 
@@ -953,7 +1017,10 @@ class EstimateModelAbstract(CreateUpdateMixIn,
953
1017
  Optional date when EstimateModel instance is void. Defaults to localdate().
954
1018
  """
955
1019
  if not self.can_void():
956
- raise EstimateModelValidationError(f'Estimate {self.estimate_number} cannot be void...')
1020
+ if raise_exception:
1021
+ raise EstimateModelValidationError(f'Estimate {self.estimate_number} cannot be void...')
1022
+ return
1023
+
957
1024
  if not date_void:
958
1025
  date_void = get_localdate()
959
1026
  self.date_void = date_void
@@ -965,6 +1032,12 @@ class EstimateModelAbstract(CreateUpdateMixIn,
965
1032
  'date_void',
966
1033
  'updated'
967
1034
  ])
1035
+ estimate_status_void.send_robust(
1036
+ sender=self.__class__,
1037
+ instance=self,
1038
+ commited=commit,
1039
+ **kwargs
1040
+ )
968
1041
 
969
1042
  def get_mark_as_void_html_id(self):
970
1043
  """
@@ -1167,8 +1240,7 @@ class EstimateModelAbstract(CreateUpdateMixIn,
1167
1240
  'updated'
1168
1241
  ])
1169
1242
 
1170
- def update_state(self,
1171
- itemtxs_qs: Optional[Union[ItemTransactionModelQuerySet, List[ItemTransactionModel]]] = None):
1243
+ def update_state(self, itemtxs_qs: Optional[Union[ItemTransactionModelQuerySet, List[ItemTransactionModel]]] = None):
1172
1244
  itemtxs_qs, _ = self.get_itemtxs_data(queryset=itemtxs_qs)
1173
1245
  self.update_cost_estimate(itemtxs_qs)
1174
1246
  self.update_revenue_estimate(itemtxs_qs)
@@ -38,8 +38,21 @@ from django_ledger.io import ASSET_CA_CASH, ASSET_CA_RECEIVABLES, LIABILITY_CL_D
38
38
  from django_ledger.io.io_core import get_localtime, get_localdate
39
39
  from django_ledger.models import lazy_loader, ItemTransactionModelQuerySet, ItemModelQuerySet, ItemModel
40
40
  from django_ledger.models.entity import EntityModel
41
- from django_ledger.models.mixins import CreateUpdateMixIn, AccrualMixIn, MarkdownNotesMixIn, PaymentTermsMixIn, \
41
+ from django_ledger.models.mixins import (
42
+ CreateUpdateMixIn, AccrualMixIn,
43
+ MarkdownNotesMixIn, PaymentTermsMixIn,
42
44
  ItemizeMixIn
45
+ )
46
+
47
+ from django_ledger.models.signals import (
48
+ invoice_status_draft,
49
+ invoice_status_in_review,
50
+ invoice_status_approved,
51
+ invoice_status_paid,
52
+ invoice_status_canceled,
53
+ invoice_status_void
54
+ )
55
+
43
56
  from django_ledger.settings import DJANGO_LEDGER_DOCUMENT_NUMBER_PADDING, DJANGO_LEDGER_INVOICE_NUMBER_PREFIX
44
57
 
45
58
  UserModel = get_user_model()
@@ -446,7 +459,7 @@ class InvoiceModelAbstract(
446
459
 
447
460
  if self.can_generate_invoice_number():
448
461
  self.generate_invoice_number(commit=commit)
449
- ledger_model.ledger_xid=f'invoice-{self.invoice_number.lower()}-{str(ledger_model.entity_id)[-5:]}'
462
+ ledger_model.ledger_xid = f'invoice-{self.invoice_number.lower()}-{str(ledger_model.entity_id)[-5:]}'
450
463
  ledger_model.save(update_fields=['ledger_xid'])
451
464
 
452
465
  self.clean()
@@ -1002,6 +1015,9 @@ class InvoiceModelAbstract(
1002
1015
  'invoice_status',
1003
1016
  'updated'
1004
1017
  ])
1018
+ invoice_status_draft.send_robust(sender=self.__class__,
1019
+ instance=self,
1020
+ commited=commit, **kwargs)
1005
1021
 
1006
1022
  def get_mark_as_draft_html_id(self):
1007
1023
  """
@@ -1050,7 +1066,8 @@ class InvoiceModelAbstract(
1050
1066
  def mark_as_review(self,
1051
1067
  date_in_review: date = None,
1052
1068
  itemtxs_qs=None,
1053
- commit: bool = False, **kwargs):
1069
+ commit: bool = False,
1070
+ **kwargs):
1054
1071
  """
1055
1072
  Marks InvoiceModel as In Review.
1056
1073
 
@@ -1088,6 +1105,10 @@ class InvoiceModelAbstract(
1088
1105
  'date_in_review',
1089
1106
  'updated'
1090
1107
  ])
1108
+ invoice_status_in_review.send_robust(sender=self.__class__,
1109
+ instance=self,
1110
+ commited=commit,
1111
+ **kwargs)
1091
1112
 
1092
1113
  def get_mark_as_review_html_id(self):
1093
1114
  """
@@ -1189,6 +1210,10 @@ class InvoiceModelAbstract(
1189
1210
  force_migrate=self.accrue
1190
1211
  )
1191
1212
  self.ledger.post(commit=commit, raise_exception=raise_exception)
1213
+ invoice_status_approved.send_robust(sender=self.__class__,
1214
+ instance=self,
1215
+ commited=commit,
1216
+ **kwargs)
1192
1217
 
1193
1218
  def get_mark_as_approved_html_id(self):
1194
1219
  """
@@ -1292,6 +1317,10 @@ class InvoiceModelAbstract(
1292
1317
  je_timestamp=date_paid
1293
1318
  )
1294
1319
  self.lock_ledger(commit=True)
1320
+ invoice_status_paid.send_robust(sender=self.__class__,
1321
+ instance=self,
1322
+ commited=commit,
1323
+ **kwargs)
1295
1324
 
1296
1325
  def get_mark_as_paid_html_id(self):
1297
1326
  """
@@ -1398,6 +1427,10 @@ class InvoiceModelAbstract(
1398
1427
  )
1399
1428
  self.save()
1400
1429
  self.lock_ledger(commit=True, raise_exception=False)
1430
+ invoice_status_void.send_robust(sender=self.__class__,
1431
+ instance=self,
1432
+ commited=commit,
1433
+ **kwargs)
1401
1434
 
1402
1435
  def get_mark_as_void_html_id(self):
1403
1436
  """
@@ -1442,7 +1475,10 @@ class InvoiceModelAbstract(
1442
1475
  return _('Do you want to mark Invoice %s as Void?') % self.invoice_number
1443
1476
 
1444
1477
  # CANCEL
1445
- def mark_as_canceled(self, date_canceled: date = None, commit: bool = False, **kwargs):
1478
+ def mark_as_canceled(self,
1479
+ date_canceled: date = None,
1480
+ commit: bool = False,
1481
+ **kwargs):
1446
1482
  """
1447
1483
  Mark InvoiceModel as Canceled.
1448
1484
 
@@ -1465,6 +1501,10 @@ class InvoiceModelAbstract(
1465
1501
  self.unlock_ledger(commit=True, raise_exception=False)
1466
1502
  self.unpost_ledger(commit=True, raise_exception=False)
1467
1503
  self.save()
1504
+ invoice_status_canceled.send_robust(sender=self.__class__,
1505
+ instance=self,
1506
+ commited=commit,
1507
+ **kwargs)
1468
1508
 
1469
1509
  def get_mark_as_canceled_html_id(self):
1470
1510
  """
@@ -1787,13 +1827,3 @@ def invoicemodel_presave(instance: InvoiceModel, **kwargs):
1787
1827
 
1788
1828
 
1789
1829
  pre_save.connect(receiver=invoicemodel_presave, sender=InvoiceModel)
1790
-
1791
- # def invoicemodel_predelete(instance: InvoiceModel, **kwargs):
1792
- # ledger_model = instance.ledger
1793
- # ledger_model.unpost(commit=False)
1794
- # ledger_model.remove_wrapped_model_info()
1795
- # ledger_model.itemtransactonmodel_set.all().delete()
1796
- # instance.ledger.delete()
1797
- #
1798
- #
1799
- # pre_delete.connect(receiver=invoicemodel_predelete, sender=InvoiceModel)