django-ledger 0.6.2__py3-none-any.whl → 0.6.3__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/admin/ledger.py +1 -0
- django_ledger/forms/data_import.py +2 -1
- django_ledger/io/ofx.py +3 -2
- django_ledger/models/bill.py +28 -14
- django_ledger/models/closing_entry.py +8 -0
- django_ledger/models/estimate.py +93 -21
- django_ledger/models/invoice.py +44 -14
- django_ledger/models/journal_entry.py +112 -49
- django_ledger/models/ledger.py +32 -0
- django_ledger/models/purchase_order.py +34 -3
- django_ledger/models/signals.py +58 -0
- django_ledger/report/core.py +1 -1
- django_ledger/templates/django_ledger/financial_statements/balance_sheet.html +2 -2
- django_ledger/tests/test_io_ofx/__init__.py +0 -0
- django_ledger/tests/test_io_ofx/tests.py +52 -0
- django_ledger/views/account.py +1 -1
- django_ledger/views/bill.py +1 -1
- {django_ledger-0.6.2.dist-info → django_ledger-0.6.3.dist-info}/METADATA +1 -1
- {django_ledger-0.6.2.dist-info → django_ledger-0.6.3.dist-info}/RECORD +24 -21
- {django_ledger-0.6.2.dist-info → django_ledger-0.6.3.dist-info}/AUTHORS.md +0 -0
- {django_ledger-0.6.2.dist-info → django_ledger-0.6.3.dist-info}/LICENSE +0 -0
- {django_ledger-0.6.2.dist-info → django_ledger-0.6.3.dist-info}/WHEEL +0 -0
- {django_ledger-0.6.2.dist-info → django_ledger-0.6.3.dist-info}/top_level.txt +0 -0
django_ledger/__init__.py
CHANGED
django_ledger/admin/ledger.py
CHANGED
django_ledger/io/ofx.py
CHANGED
|
@@ -34,8 +34,9 @@ class OFXFileManager:
|
|
|
34
34
|
def get_accounts(self):
|
|
35
35
|
return [
|
|
36
36
|
{
|
|
37
|
-
|
|
38
|
-
'
|
|
37
|
+
# conditionally return the bank and fid if they are provided by the vendor
|
|
38
|
+
'bank': self.ofx_data.fi.org if hasattr(self.ofx_data.fi, 'org') else None,
|
|
39
|
+
'fid': self.ofx_data.fi.fid if hasattr(self.ofx_data.fi, 'fid') else None,
|
|
39
40
|
'account_type': acc.accttype,
|
|
40
41
|
'account_number': acc.acctid,
|
|
41
42
|
'routing_number': acc.bankid,
|
django_ledger/models/bill.py
CHANGED
|
@@ -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
|
-
|
|
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
|
django_ledger/models/estimate.py
CHANGED
|
@@ -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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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,
|
|
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
|
-
|
|
765
|
-
|
|
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,
|
|
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
|
-
|
|
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(
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
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,
|
|
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
|
-
|
|
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,
|
|
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
|
-
|
|
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)
|
django_ledger/models/invoice.py
CHANGED
|
@@ -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
|
|
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,
|
|
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,
|
|
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)
|
|
@@ -45,17 +45,28 @@ from django.utils.timezone import localtime
|
|
|
45
45
|
from django.utils.translation import gettext_lazy as _
|
|
46
46
|
|
|
47
47
|
from django_ledger.io.io_core import get_localtime
|
|
48
|
-
from django_ledger.io.roles import (
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
48
|
+
from django_ledger.io.roles import (
|
|
49
|
+
ASSET_CA_CASH, GROUP_CFS_FIN_DIVIDENDS, GROUP_CFS_FIN_ISSUING_EQUITY,
|
|
50
|
+
GROUP_CFS_FIN_LT_DEBT_PAYMENTS, GROUP_CFS_FIN_ST_DEBT_PAYMENTS,
|
|
51
|
+
GROUP_CFS_INVESTING_AND_FINANCING, GROUP_CFS_INVESTING_PPE,
|
|
52
|
+
GROUP_CFS_INVESTING_SECURITIES, validate_roles
|
|
53
|
+
)
|
|
52
54
|
from django_ledger.models.accounts import CREDIT, DEBIT
|
|
53
55
|
from django_ledger.models.entity import EntityStateModel, EntityModel
|
|
54
56
|
from django_ledger.models.mixins import CreateUpdateMixIn
|
|
57
|
+
from django_ledger.models.signals import (
|
|
58
|
+
journal_entry_unlocked,
|
|
59
|
+
journal_entry_locked,
|
|
60
|
+
journal_entry_posted,
|
|
61
|
+
journal_entry_unposted
|
|
62
|
+
)
|
|
55
63
|
from django_ledger.models.transactions import TransactionModelQuerySet, TransactionModel
|
|
56
64
|
from django_ledger.models.utils import lazy_loader
|
|
57
|
-
from django_ledger.settings import (
|
|
58
|
-
|
|
65
|
+
from django_ledger.settings import (
|
|
66
|
+
DJANGO_LEDGER_JE_NUMBER_PREFIX,
|
|
67
|
+
DJANGO_LEDGER_DOCUMENT_NUMBER_PADDING,
|
|
68
|
+
DJANGO_LEDGER_JE_NUMBER_NO_UNIT_PREFIX
|
|
69
|
+
)
|
|
59
70
|
|
|
60
71
|
|
|
61
72
|
class JournalEntryValidationError(ValidationError):
|
|
@@ -588,31 +599,48 @@ class JournalEntryModelAbstract(CreateUpdateMixIn):
|
|
|
588
599
|
"""
|
|
589
600
|
if verify and not self.is_verified():
|
|
590
601
|
txs_qs, verified = self.verify()
|
|
591
|
-
|
|
592
602
|
if not len(txs_qs):
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
603
|
+
if raise_exception:
|
|
604
|
+
raise JournalEntryValidationError(
|
|
605
|
+
message=_('Cannot post an empty Journal Entry.')
|
|
606
|
+
)
|
|
607
|
+
return
|
|
596
608
|
|
|
597
609
|
if force_lock and not self.is_locked():
|
|
598
|
-
|
|
610
|
+
try:
|
|
611
|
+
self.mark_as_locked(commit=False, raise_exception=True)
|
|
612
|
+
except JournalEntryValidationError as e:
|
|
613
|
+
if raise_exception:
|
|
614
|
+
raise e
|
|
615
|
+
return
|
|
599
616
|
|
|
600
617
|
if not self.can_post(ignore_verify=False):
|
|
601
618
|
if raise_exception:
|
|
602
619
|
raise JournalEntryValidationError(f'Journal Entry {self.uuid} cannot post.'
|
|
603
620
|
f' Is verified: {self.is_verified()}')
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
621
|
+
return
|
|
622
|
+
|
|
623
|
+
if not self.is_posted():
|
|
624
|
+
self.posted = True
|
|
625
|
+
if self.is_posted():
|
|
626
|
+
if commit:
|
|
627
|
+
self.save(verify=False,
|
|
628
|
+
update_fields=[
|
|
629
|
+
'posted',
|
|
630
|
+
'locked',
|
|
631
|
+
'activity',
|
|
632
|
+
'updated'
|
|
633
|
+
])
|
|
634
|
+
journal_entry_posted.send_robust(sender=self.__class__,
|
|
635
|
+
instance=self,
|
|
636
|
+
commited=commit,
|
|
637
|
+
**kwargs)
|
|
638
|
+
|
|
639
|
+
def post(self, **kwargs):
|
|
640
|
+
"""
|
|
641
|
+
Proxy function for `mark_as_posted` method.
|
|
642
|
+
"""
|
|
643
|
+
return self.mark_as_posted(**kwargs)
|
|
616
644
|
|
|
617
645
|
def mark_as_unposted(self, commit: bool = False, raise_exception: bool = False, **kwargs):
|
|
618
646
|
"""
|
|
@@ -632,18 +660,30 @@ class JournalEntryModelAbstract(CreateUpdateMixIn):
|
|
|
632
660
|
if not self.can_unpost():
|
|
633
661
|
if raise_exception:
|
|
634
662
|
raise JournalEntryValidationError(f'Journal Entry {self.uuid} cannot unpost.')
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
663
|
+
return
|
|
664
|
+
if self.is_posted():
|
|
665
|
+
self.posted = False
|
|
666
|
+
self.activity = None
|
|
667
|
+
if not self.is_posted():
|
|
668
|
+
if commit:
|
|
669
|
+
self.save(
|
|
670
|
+
verify=False,
|
|
671
|
+
update_fields=[
|
|
672
|
+
'posted',
|
|
673
|
+
'activity',
|
|
674
|
+
'updated'
|
|
675
|
+
]
|
|
676
|
+
)
|
|
677
|
+
journal_entry_unposted.send_robust(sender=self.__class__,
|
|
678
|
+
instance=self,
|
|
679
|
+
commited=commit,
|
|
680
|
+
**kwargs)
|
|
681
|
+
|
|
682
|
+
def unpost(self, **kwargs):
|
|
683
|
+
"""
|
|
684
|
+
Proxy function for `mark_as_unposted` method.
|
|
685
|
+
"""
|
|
686
|
+
return self.mark_as_unposted(**kwargs)
|
|
647
687
|
|
|
648
688
|
def mark_as_locked(self, commit: bool = False, raise_exception: bool = False, **kwargs):
|
|
649
689
|
"""
|
|
@@ -662,14 +702,26 @@ class JournalEntryModelAbstract(CreateUpdateMixIn):
|
|
|
662
702
|
"""
|
|
663
703
|
if not self.can_lock():
|
|
664
704
|
if raise_exception:
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
705
|
+
if raise_exception:
|
|
706
|
+
raise JournalEntryValidationError(f'Journal Entry {self.uuid} is already locked.')
|
|
707
|
+
return
|
|
708
|
+
|
|
709
|
+
if not self.is_locked():
|
|
710
|
+
self.generate_activity(force_update=True)
|
|
711
|
+
self.locked = True
|
|
712
|
+
if self.is_locked():
|
|
713
|
+
if commit:
|
|
714
|
+
self.save(verify=False)
|
|
715
|
+
journal_entry_locked.send_robust(sender=self.__class__,
|
|
716
|
+
instance=self,
|
|
717
|
+
commited=commit,
|
|
718
|
+
**kwargs)
|
|
719
|
+
|
|
720
|
+
def lock(self, **kwargs):
|
|
721
|
+
"""
|
|
722
|
+
Proxy function for `mark_as_locked` method.
|
|
723
|
+
"""
|
|
724
|
+
return self.mark_as_locked(**kwargs)
|
|
673
725
|
|
|
674
726
|
def mark_as_unlocked(self, commit: bool = False, raise_exception: bool = False, **kwargs):
|
|
675
727
|
"""
|
|
@@ -687,12 +739,23 @@ class JournalEntryModelAbstract(CreateUpdateMixIn):
|
|
|
687
739
|
if not self.can_unlock():
|
|
688
740
|
if raise_exception:
|
|
689
741
|
raise JournalEntryValidationError(f'Journal Entry {self.uuid} is already unlocked.')
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
742
|
+
return
|
|
743
|
+
|
|
744
|
+
if self.is_locked():
|
|
745
|
+
self.locked = False
|
|
746
|
+
if not self.is_locked():
|
|
747
|
+
if commit:
|
|
748
|
+
self.save(verify=False)
|
|
749
|
+
journal_entry_unlocked.send_robust(sender=self.__class__,
|
|
750
|
+
instance=self,
|
|
751
|
+
commited=commit,
|
|
752
|
+
**kwargs)
|
|
753
|
+
|
|
754
|
+
def unlock(self, **kwargs):
|
|
755
|
+
"""
|
|
756
|
+
Proxy function for `mark_as_unlocked` method.
|
|
757
|
+
"""
|
|
758
|
+
return self.mark_as_unlocked(**kwargs)
|
|
696
759
|
|
|
697
760
|
def get_transaction_queryset(self, select_accounts: bool = True) -> TransactionModelQuerySet:
|
|
698
761
|
"""
|
django_ledger/models/ledger.py
CHANGED
|
@@ -37,6 +37,14 @@ from django.db import models
|
|
|
37
37
|
from django.db.models import Q, Min, F, Count
|
|
38
38
|
from django.urls import reverse
|
|
39
39
|
from django.utils.translation import gettext_lazy as _
|
|
40
|
+
from django_ledger.models.signals import (
|
|
41
|
+
ledger_posted,
|
|
42
|
+
ledger_unposted,
|
|
43
|
+
ledger_locked,
|
|
44
|
+
ledger_unlocked,
|
|
45
|
+
ledger_hidden,
|
|
46
|
+
ledger_unhidden
|
|
47
|
+
)
|
|
40
48
|
|
|
41
49
|
from django_ledger.io.io_core import IOMixIn
|
|
42
50
|
from django_ledger.models import lazy_loader
|
|
@@ -456,6 +464,10 @@ class LedgerModelAbstract(CreateUpdateMixIn, IOMixIn):
|
|
|
456
464
|
'posted',
|
|
457
465
|
'updated'
|
|
458
466
|
])
|
|
467
|
+
ledger_posted.send_robust(sender=self.__class__,
|
|
468
|
+
instance=self,
|
|
469
|
+
commited=commit,
|
|
470
|
+
**kwargs)
|
|
459
471
|
|
|
460
472
|
def post_journal_entries(self, commit: bool = True, **kwargs):
|
|
461
473
|
je_model_qs = self.journal_entries.unposted()
|
|
@@ -488,6 +500,10 @@ class LedgerModelAbstract(CreateUpdateMixIn, IOMixIn):
|
|
|
488
500
|
'posted',
|
|
489
501
|
'updated'
|
|
490
502
|
])
|
|
503
|
+
ledger_unposted.send_robust(sender=self.__class__,
|
|
504
|
+
instance=self,
|
|
505
|
+
commited=commit,
|
|
506
|
+
**kwargs)
|
|
491
507
|
|
|
492
508
|
def lock(self, commit: bool = False, raise_exception: bool = True, **kwargs):
|
|
493
509
|
"""
|
|
@@ -513,6 +529,10 @@ class LedgerModelAbstract(CreateUpdateMixIn, IOMixIn):
|
|
|
513
529
|
'locked',
|
|
514
530
|
'updated'
|
|
515
531
|
])
|
|
532
|
+
ledger_locked.send_robust(sender=self.__class__,
|
|
533
|
+
instance=self,
|
|
534
|
+
commited=commit,
|
|
535
|
+
**kwargs)
|
|
516
536
|
|
|
517
537
|
def lock_journal_entries(self, commit: bool = True, **kwargs):
|
|
518
538
|
je_model_qs = self.journal_entries.unlocked()
|
|
@@ -544,6 +564,10 @@ class LedgerModelAbstract(CreateUpdateMixIn, IOMixIn):
|
|
|
544
564
|
'locked',
|
|
545
565
|
'updated'
|
|
546
566
|
])
|
|
567
|
+
ledger_unlocked.send_robust(sender=self.__class__,
|
|
568
|
+
instance=self,
|
|
569
|
+
commited=commit,
|
|
570
|
+
**kwargs)
|
|
547
571
|
|
|
548
572
|
def hide(self, commit: bool = False, raise_exception: bool = True, **kwargs):
|
|
549
573
|
if not self.can_hide():
|
|
@@ -558,6 +582,10 @@ class LedgerModelAbstract(CreateUpdateMixIn, IOMixIn):
|
|
|
558
582
|
'hidden',
|
|
559
583
|
'updated'
|
|
560
584
|
])
|
|
585
|
+
ledger_hidden.send_robust(sender=self.__class__,
|
|
586
|
+
instance=self,
|
|
587
|
+
commited=commit,
|
|
588
|
+
**kwargs)
|
|
561
589
|
|
|
562
590
|
def unhide(self, commit: bool = False, raise_exception: bool = True, **kwargs):
|
|
563
591
|
if not self.can_unhide():
|
|
@@ -572,6 +600,10 @@ class LedgerModelAbstract(CreateUpdateMixIn, IOMixIn):
|
|
|
572
600
|
'hidden',
|
|
573
601
|
'updated'
|
|
574
602
|
])
|
|
603
|
+
ledger_unhidden.send_robust(sender=self.__class__,
|
|
604
|
+
instance=self,
|
|
605
|
+
commited=commit,
|
|
606
|
+
**kwargs)
|
|
575
607
|
|
|
576
608
|
def delete(self, **kwargs):
|
|
577
609
|
if not self.can_delete():
|
|
@@ -39,6 +39,14 @@ from django_ledger.models.items import ItemTransactionModel, ItemTransactionMode
|
|
|
39
39
|
from django_ledger.models.mixins import CreateUpdateMixIn, MarkdownNotesMixIn, ItemizeMixIn
|
|
40
40
|
from django_ledger.models.utils import lazy_loader
|
|
41
41
|
from django_ledger.settings import DJANGO_LEDGER_DOCUMENT_NUMBER_PADDING, DJANGO_LEDGER_PO_NUMBER_PREFIX
|
|
42
|
+
from django_ledger.models.signals import (
|
|
43
|
+
po_status_draft,
|
|
44
|
+
po_status_void,
|
|
45
|
+
po_status_fulfilled,
|
|
46
|
+
po_status_approved,
|
|
47
|
+
po_status_canceled,
|
|
48
|
+
po_status_in_review
|
|
49
|
+
)
|
|
42
50
|
|
|
43
51
|
PO_NUMBER_CHARS = ascii_uppercase + digits
|
|
44
52
|
|
|
@@ -403,9 +411,8 @@ class PurchaseOrderModelAbstract(CreateUpdateMixIn,
|
|
|
403
411
|
} if not lazy_agg else None
|
|
404
412
|
|
|
405
413
|
# ### ItemizeMixIn implementation END...
|
|
406
|
-
def update_state(self,
|
|
407
|
-
|
|
408
|
-
) -> Tuple:
|
|
414
|
+
def update_state(self, itemtxs_qs: Optional[
|
|
415
|
+
Union[ItemTransactionModelQuerySet, List[ItemTransactionModel]]] = None) -> Tuple:
|
|
409
416
|
|
|
410
417
|
"""
|
|
411
418
|
Updates the state of the PurchaseOrderModel.
|
|
@@ -696,6 +703,10 @@ class PurchaseOrderModelAbstract(CreateUpdateMixIn,
|
|
|
696
703
|
'po_status',
|
|
697
704
|
'updated'
|
|
698
705
|
])
|
|
706
|
+
po_status_draft.send_robust(sender=self.__class__,
|
|
707
|
+
instance=self,
|
|
708
|
+
commited=commit,
|
|
709
|
+
**kwargs)
|
|
699
710
|
|
|
700
711
|
def get_mark_as_draft_html_id(self):
|
|
701
712
|
"""
|
|
@@ -765,6 +776,10 @@ class PurchaseOrderModelAbstract(CreateUpdateMixIn,
|
|
|
765
776
|
'date_in_review',
|
|
766
777
|
'updated'
|
|
767
778
|
])
|
|
779
|
+
po_status_in_review.send_robust(sender=self.__class__,
|
|
780
|
+
instance=self,
|
|
781
|
+
commited=commit,
|
|
782
|
+
**kwargs)
|
|
768
783
|
|
|
769
784
|
def get_mark_as_review_html_id(self):
|
|
770
785
|
"""
|
|
@@ -828,6 +843,10 @@ class PurchaseOrderModelAbstract(CreateUpdateMixIn,
|
|
|
828
843
|
'po_status',
|
|
829
844
|
'updated'
|
|
830
845
|
])
|
|
846
|
+
po_status_approved.send_robust(sender=self.__class__,
|
|
847
|
+
instance=self,
|
|
848
|
+
commited=commit,
|
|
849
|
+
**kwargs)
|
|
831
850
|
|
|
832
851
|
def get_mark_as_approved_html_id(self):
|
|
833
852
|
"""
|
|
@@ -890,6 +909,10 @@ class PurchaseOrderModelAbstract(CreateUpdateMixIn,
|
|
|
890
909
|
'date_canceled',
|
|
891
910
|
'updated'
|
|
892
911
|
])
|
|
912
|
+
po_status_canceled.send_robust(sender=self.__class__,
|
|
913
|
+
instance=self,
|
|
914
|
+
commited=commit,
|
|
915
|
+
**kwargs)
|
|
893
916
|
|
|
894
917
|
def get_mark_as_canceled_html_id(self):
|
|
895
918
|
"""
|
|
@@ -983,6 +1006,10 @@ class PurchaseOrderModelAbstract(CreateUpdateMixIn,
|
|
|
983
1006
|
'po_status',
|
|
984
1007
|
'updated'
|
|
985
1008
|
])
|
|
1009
|
+
po_status_fulfilled.send_robust(sender=self.__class__,
|
|
1010
|
+
instance=self,
|
|
1011
|
+
commited=commit,
|
|
1012
|
+
**kwargs)
|
|
986
1013
|
|
|
987
1014
|
def get_mark_as_fulfilled_html_id(self):
|
|
988
1015
|
"""
|
|
@@ -1057,6 +1084,10 @@ class PurchaseOrderModelAbstract(CreateUpdateMixIn,
|
|
|
1057
1084
|
'po_status',
|
|
1058
1085
|
'updated'
|
|
1059
1086
|
])
|
|
1087
|
+
po_status_void.send_robust(sender=self.__class__,
|
|
1088
|
+
instance=self,
|
|
1089
|
+
commited=commit,
|
|
1090
|
+
**kwargs)
|
|
1060
1091
|
|
|
1061
1092
|
def get_mark_as_void_html_id(self):
|
|
1062
1093
|
"""
|
|
@@ -0,0 +1,58 @@
|
|
|
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
|
+
The signals module provide the means to notify listeners about important events or states in the models,
|
|
9
|
+
such as a ledger model being posted or a bill status changing.
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
from django.dispatch import Signal
|
|
13
|
+
|
|
14
|
+
# Ledger Model Signals...
|
|
15
|
+
ledger_posted = Signal()
|
|
16
|
+
ledger_unposted = Signal()
|
|
17
|
+
ledger_locked = Signal()
|
|
18
|
+
ledger_unlocked = Signal()
|
|
19
|
+
ledger_hidden = Signal()
|
|
20
|
+
ledger_unhidden = Signal()
|
|
21
|
+
|
|
22
|
+
# Journal Entry Model Signals...
|
|
23
|
+
journal_entry_posted = Signal()
|
|
24
|
+
journal_entry_unposted = Signal()
|
|
25
|
+
journal_entry_locked = Signal()
|
|
26
|
+
journal_entry_unlocked = Signal()
|
|
27
|
+
|
|
28
|
+
# Bill Model Signals...
|
|
29
|
+
bill_status_draft = Signal()
|
|
30
|
+
bill_status_in_review = Signal()
|
|
31
|
+
bill_status_approved = Signal()
|
|
32
|
+
bill_status_paid = Signal()
|
|
33
|
+
bill_status_canceled = Signal()
|
|
34
|
+
bill_status_void = Signal()
|
|
35
|
+
|
|
36
|
+
# Invoice Model Signals...
|
|
37
|
+
invoice_status_draft = Signal()
|
|
38
|
+
invoice_status_in_review = Signal()
|
|
39
|
+
invoice_status_approved = Signal()
|
|
40
|
+
invoice_status_paid = Signal()
|
|
41
|
+
invoice_status_canceled = Signal()
|
|
42
|
+
invoice_status_void = Signal()
|
|
43
|
+
|
|
44
|
+
# PO Model Signals...
|
|
45
|
+
po_status_draft = Signal()
|
|
46
|
+
po_status_in_review = Signal()
|
|
47
|
+
po_status_approved = Signal()
|
|
48
|
+
po_status_fulfilled = Signal()
|
|
49
|
+
po_status_canceled = Signal()
|
|
50
|
+
po_status_void = Signal()
|
|
51
|
+
|
|
52
|
+
# Estimate Model Signals...
|
|
53
|
+
estimate_status_draft = Signal()
|
|
54
|
+
estimate_status_in_review = Signal()
|
|
55
|
+
estimate_status_approved = Signal()
|
|
56
|
+
estimate_status_completed = Signal()
|
|
57
|
+
estimate_status_canceled = Signal()
|
|
58
|
+
estimate_status_void = Signal()
|
django_ledger/report/core.py
CHANGED
|
@@ -3,7 +3,7 @@ from typing import Optional, Dict
|
|
|
3
3
|
from django.contrib.staticfiles import finders
|
|
4
4
|
from django.core.exceptions import ValidationError
|
|
5
5
|
|
|
6
|
-
from django_ledger.io.
|
|
6
|
+
from django_ledger.io.io_context import IODigestContextManager
|
|
7
7
|
from django_ledger.models.ledger import LedgerModel
|
|
8
8
|
from django_ledger.models.unit import EntityUnitModel
|
|
9
9
|
from django_ledger.settings import DJANGO_LEDGER_PDF_SUPPORT_ENABLED
|
|
@@ -44,10 +44,10 @@
|
|
|
44
44
|
{% balance_sheet_statement io_model=object %}
|
|
45
45
|
{% if entity %}
|
|
46
46
|
<a class="button is-fullwidth is-dark mb-1"
|
|
47
|
-
href="{% url 'django_ledger:
|
|
47
|
+
href="{% url 'django_ledger:entity-dashboard' entity_slug=view.kwargs.entity_slug %}">{% trans 'Go Back' %}</a>
|
|
48
48
|
{% elif ledger %}
|
|
49
49
|
<a class="button is-fullwidth is-dark my-2"
|
|
50
|
-
href="{% url 'django_ledger:
|
|
50
|
+
href="{% url 'django_ledger:ledger-list' entity_slug=view.kwargs.entity_slug %}">{% trans 'Go Back' %}</a>
|
|
51
51
|
{% endif %}
|
|
52
52
|
<a class="button is-fullwidth is-light my-2"
|
|
53
53
|
href="?by_unit=1">{% trans 'By Unit' %}</a>
|
|
File without changes
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import os
|
|
2
|
+
from decimal import Decimal
|
|
3
|
+
|
|
4
|
+
from django_ledger.io.ofx import OFXFileManager
|
|
5
|
+
from django_ledger.tests.base import DjangoLedgerBaseTest
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class SimpleOFXTest(DjangoLedgerBaseTest):
|
|
9
|
+
BASE_PATH = "django_ledger/tests/test_io_ofx/samples/"
|
|
10
|
+
|
|
11
|
+
def get_sample_ofx(self, ofx_sample_name: str):
|
|
12
|
+
ofx = OFXFileManager(ofx_file_or_path=os.path.join(self.BASE_PATH, ofx_sample_name))
|
|
13
|
+
|
|
14
|
+
return ofx
|
|
15
|
+
|
|
16
|
+
def test_ofx_v1_with_intu_bid_field(self):
|
|
17
|
+
"""
|
|
18
|
+
OFX v1 with <INTU.BID> field. These are ofx files that are exported for Quickbooks.
|
|
19
|
+
This field can be used to identify the bank in the absence of the <FI.ORG> fields.
|
|
20
|
+
"""
|
|
21
|
+
ofx = self.get_sample_ofx("v1_with_intu_bid.ofx")
|
|
22
|
+
accounts = ofx.get_accounts()
|
|
23
|
+
|
|
24
|
+
# The bank and fid fields are not provided in this ofx file.
|
|
25
|
+
self.assertIsNone(accounts[0]["fid"])
|
|
26
|
+
self.assertIsNone(accounts[0]["bank"])
|
|
27
|
+
# balance observed from the ofx file
|
|
28
|
+
self.assertEqual(ofx.ofx_data.statements[0].balance.balamt, Decimal("123456.49"))
|
|
29
|
+
|
|
30
|
+
def test_ofx_v1_with_open_tags(self):
|
|
31
|
+
"""
|
|
32
|
+
OFX v1 with open tags like `<DTSERVER>20211015063225[-5:EST]` instead of `<DTSERVER>20230510120000</DTSERVER>`
|
|
33
|
+
"""
|
|
34
|
+
ofx = self.get_sample_ofx("v1_with_open_tags.ofx")
|
|
35
|
+
accounts = ofx.get_accounts()
|
|
36
|
+
account = accounts[0]
|
|
37
|
+
|
|
38
|
+
self.assertIsNone(account["fid"])
|
|
39
|
+
self.assertIsNone(account["bank"])
|
|
40
|
+
self.assertEqual(ofx.ofx_data.statements[0].balance.balamt, Decimal("1868.27"))
|
|
41
|
+
|
|
42
|
+
def test_ofx_v2_good(self):
|
|
43
|
+
"""
|
|
44
|
+
ofx v2 uses XML rather than SGML. This is a good ofx v2 file.
|
|
45
|
+
"""
|
|
46
|
+
ofx = self.get_sample_ofx("v2_good.ofx")
|
|
47
|
+
accounts = ofx.get_accounts()
|
|
48
|
+
account = accounts[0]
|
|
49
|
+
|
|
50
|
+
self.assertEqual(account["fid"], "123456789")
|
|
51
|
+
self.assertEqual(account["bank"], "BANK NAME")
|
|
52
|
+
self.assertEqual(ofx.ofx_data.statements[0].balance.balamt, Decimal("5000.00"))
|
django_ledger/views/account.py
CHANGED
|
@@ -210,7 +210,7 @@ class AccountModelYearDetailView(DjangoLedgerSecurityMixIn,
|
|
|
210
210
|
context['header_title'] = f'Account {account.code} - {account.name}'
|
|
211
211
|
context['page_title'] = f'Account {account.code} - {account.name}'
|
|
212
212
|
account_model: AccountModel = self.object
|
|
213
|
-
txs_qs = account_model.transactionmodel_set.posted().order_by(
|
|
213
|
+
txs_qs = account_model.transactionmodel_set.all().posted().order_by(
|
|
214
214
|
'journal_entry__timestamp').select_related(
|
|
215
215
|
'journal_entry', 'journal_entry__entity_unit')
|
|
216
216
|
txs_qs = txs_qs.from_date(self.get_from_date())
|
django_ledger/views/bill.py
CHANGED
|
@@ -3,7 +3,7 @@ Django Ledger created by Miguel Sanda <msanda@arrobalytics.com>.
|
|
|
3
3
|
Copyright© EDMA Group Inc licensed under the GPLv3 Agreement.
|
|
4
4
|
|
|
5
5
|
Contributions to this module:
|
|
6
|
-
Miguel Sanda <msanda@arrobalytics.com>
|
|
6
|
+
* Miguel Sanda <msanda@arrobalytics.com>
|
|
7
7
|
"""
|
|
8
8
|
|
|
9
9
|
from django.contrib import messages
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: django-ledger
|
|
3
|
-
Version: 0.6.
|
|
3
|
+
Version: 0.6.3
|
|
4
4
|
Summary: Double entry accounting system built on the Django Web Framework.
|
|
5
5
|
Author-email: Miguel Sanda <msanda@arrobalytics.com>
|
|
6
6
|
Maintainer-email: Miguel Sanda <msanda@arrobalytics.com>
|
|
@@ -48,7 +48,7 @@ assets/node_modules/node-gyp/gyp/tools/pretty_gyp.py,sha256=2ZCRPW-MZfK7gdnCIaqh
|
|
|
48
48
|
assets/node_modules/node-gyp/gyp/tools/pretty_sln.py,sha256=b_Fxm-SXUCPL3Tix4EyNwZNmQ-zkeRIFFmuL0R5wFhw,5482
|
|
49
49
|
assets/node_modules/node-gyp/gyp/tools/pretty_vcproj.py,sha256=AwQrxK1F-jhjsbbT35XQjrvWNbc3IBFaKXoJogqMh_o,10633
|
|
50
50
|
assets/node_modules/node-gyp/test/fixtures/test-charmap.py,sha256=5raXzaQnO2eJnrlFtlDtWftryhZX7Fj0amFW3hdSnhE,547
|
|
51
|
-
django_ledger/__init__.py,sha256=
|
|
51
|
+
django_ledger/__init__.py,sha256=YIkeEEOhmF8tF2yAy5LrIeaNAzkX8i-oaFluYzjuH9I,456
|
|
52
52
|
django_ledger/apps.py,sha256=H-zEWUjKGakgSDSZmLIoXChZ2h6e0dth0ZO5SpoT-8U,163
|
|
53
53
|
django_ledger/exceptions.py,sha256=rML8sQQ0Hq-DYMLZ76dfw2RYSAsXWUoyHuyC_yP9o1o,491
|
|
54
54
|
django_ledger/settings.py,sha256=bZyPKgjmRcO_Rj7hDi4gGlW0VFr_LP2yKeUVIkmWgQM,6321
|
|
@@ -56,7 +56,7 @@ django_ledger/utils.py,sha256=l8xq-uSvUdJNpyDjC_0UrsSfjeEpwf7B-tavbnt40a8,4305
|
|
|
56
56
|
django_ledger/admin/__init__.py,sha256=MipzxmBhXswpx63uf3Ai2amyBMAP5fZL7mKXKxjNRIY,458
|
|
57
57
|
django_ledger/admin/coa.py,sha256=BcBsvNs4Z1hOyZy4YqCtIfk1aw8DejrI1bAEH93Tkjc,3542
|
|
58
58
|
django_ledger/admin/entity.py,sha256=DhH-6o3kjUdkhVPHzwOSF3crtvf5MCzcc1vPCk9O2Bk,6287
|
|
59
|
-
django_ledger/admin/ledger.py,sha256=
|
|
59
|
+
django_ledger/admin/ledger.py,sha256=WKJCKDT54B_OWtAGlPKKAOBRZAqJ-SPNYiuvV-Wa9y8,7936
|
|
60
60
|
django_ledger/contrib/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
61
61
|
django_ledger/contrib/django_ledger_graphene/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
62
62
|
django_ledger/contrib/django_ledger_graphene/api.py,sha256=exrsmMcX21-Vhpe2_9X0eRLcdlnoE2ut0KUxBLu-TM8,871
|
|
@@ -101,7 +101,7 @@ django_ledger/forms/bill.py,sha256=aTAlMWtVA3eI-w0e9Vuxk2GSVey7pmAropPzrQ4OzcI,1
|
|
|
101
101
|
django_ledger/forms/closing_entry.py,sha256=AwEEhphjQ-D4pQ6lRk2zGSmMSMkoamIVICnUY8rgqKU,1494
|
|
102
102
|
django_ledger/forms/coa.py,sha256=-w0GbVde1ve0lEgWCc7kAIfDDVP_nBYgrxykfC301Gw,1312
|
|
103
103
|
django_ledger/forms/customer.py,sha256=4Ce0J2d3hH5vfT1kdJbspUveIPEsRX_JktzIIu4rNks,2502
|
|
104
|
-
django_ledger/forms/data_import.py,sha256=
|
|
104
|
+
django_ledger/forms/data_import.py,sha256=VF4oJNcWNVW3r0VEGT6MFAC5jN5Aqff5qU35NdO9Wj0,5674
|
|
105
105
|
django_ledger/forms/entity.py,sha256=b0QirmsFSnaM8YWDO4V6GQXfFgR_MLmdq27I2q2sGQ0,6880
|
|
106
106
|
django_ledger/forms/estimate.py,sha256=AotWILz-XYiDHEIpey-KQTFfqcLr_CubtzCoaDm3SL4,5171
|
|
107
107
|
django_ledger/forms/feedback.py,sha256=WUT-kI4uT6q5aqEYaDYwyIFfhXpmtwMv6qf9BFSYsDo,1850
|
|
@@ -120,7 +120,7 @@ django_ledger/io/io_core.py,sha256=b_-je0NNPkMOglkJwObxfKA6eWa0YvEod9LODm5RRIg,4
|
|
|
120
120
|
django_ledger/io/io_generator.py,sha256=JF4plsABUkCIrtI2X-YD7o5eNghRIgLUseNcBIGOj3U,34613
|
|
121
121
|
django_ledger/io/io_library.py,sha256=vvQm3IQRLFdH7HS_DYX46Xe-U9IvgZ6MQnHjy0-fyjk,22480
|
|
122
122
|
django_ledger/io/io_middleware.py,sha256=c-vwpcjg2HbYbb4O36fdf6011dFOnoNsDHOAQXmJgB8,20052
|
|
123
|
-
django_ledger/io/ofx.py,sha256=
|
|
123
|
+
django_ledger/io/ofx.py,sha256=tsggMXfAz9rslCTUcxlandPapcHXbGqLO9Diel5z_jE,1677
|
|
124
124
|
django_ledger/io/ratios.py,sha256=dsuCv9-r73SMLv3OrxeoT5JebfRmrDsRKG_YzHggWFw,3542
|
|
125
125
|
django_ledger/io/roles.py,sha256=J9Z8WtunOQShKORCY97HpFtlAHG4N4hPfBkpUtRQDIY,20223
|
|
126
126
|
django_ledger/management/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
@@ -146,20 +146,21 @@ django_ledger/migrations/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZ
|
|
|
146
146
|
django_ledger/models/__init__.py,sha256=8mn-OGhAVgLs8YASEBwo8dpX6tHyGtMxRHVPGDGECVU,793
|
|
147
147
|
django_ledger/models/accounts.py,sha256=0OWMrv89fUdec7RF1EiWE6xZdJMOdEpgYPWechAJYrM,28881
|
|
148
148
|
django_ledger/models/bank_account.py,sha256=0-eTBxxRyvUKOVVNcGqWV1kiOKcXA2KPQIdiVHDUDCY,7678
|
|
149
|
-
django_ledger/models/bill.py,sha256=
|
|
150
|
-
django_ledger/models/closing_entry.py,sha256=
|
|
149
|
+
django_ledger/models/bill.py,sha256=0JaSDu6pA07VVMRjPRiZnMldn50QkPFDbj5MbzDNuXk,64569
|
|
150
|
+
django_ledger/models/closing_entry.py,sha256=s5DvvWnv5SogWtlUdtpdDgKce80FBSjJ6YWQnQxqwV0,17959
|
|
151
151
|
django_ledger/models/coa.py,sha256=o-VM2XK64djM3px6pJlGrUVTXu5qNb4ENESS70I___0,27154
|
|
152
152
|
django_ledger/models/coa_default.py,sha256=4Zj8OMhgBiYuREjM82cFfyGWd8uCAeqggVkeNhg4SLU,27338
|
|
153
153
|
django_ledger/models/customer.py,sha256=JQOktcYKUlENJv4frek9rAW6sRerrQ0xXHlC5KPmhWk,11807
|
|
154
154
|
django_ledger/models/data_import.py,sha256=2H-4oTVLa7qXq03m9fd7T5zSQLkZKOAn2OAeOQBzMPA,19477
|
|
155
155
|
django_ledger/models/entity.py,sha256=VFknz-7FQZu_gVDb5RWqPoCb3eXVzIMgmr4hatUlzBI,121876
|
|
156
|
-
django_ledger/models/estimate.py,sha256
|
|
157
|
-
django_ledger/models/invoice.py,sha256=
|
|
156
|
+
django_ledger/models/estimate.py,sha256=i88GtPqJ4k_Nzgyj7uzbI3tWgALkCuHLaV_Cjg-_mE0,58304
|
|
157
|
+
django_ledger/models/invoice.py,sha256=bdyeyngKuaJ0nA9N0L25-m7QbB7AEK43v1TKJkFWsOY,62896
|
|
158
158
|
django_ledger/models/items.py,sha256=Wh_zPBnYCdI393nHafT6xd4aSutKBQPwKSjDtXTTPNQ,55042
|
|
159
|
-
django_ledger/models/journal_entry.py,sha256=
|
|
160
|
-
django_ledger/models/ledger.py,sha256=
|
|
159
|
+
django_ledger/models/journal_entry.py,sha256=2MwSAYjlSn8YVNM0riVBQWALD2lukGyf_gEHAIrn5UU,52788
|
|
160
|
+
django_ledger/models/ledger.py,sha256=CjUVi_KufNsSYKo_ZC5T3j8rioRQXhEl16zf_ipzcLg,24997
|
|
161
161
|
django_ledger/models/mixins.py,sha256=s8ZjEjYQfmU88cLyFNKoiFi79_g1rTe1knEccV2WUXw,52122
|
|
162
|
-
django_ledger/models/purchase_order.py,sha256=
|
|
162
|
+
django_ledger/models/purchase_order.py,sha256=Se62XFyrbDbQzFH_almroIaSZ3y27QcsI2xkYXvPIGc,44184
|
|
163
|
+
django_ledger/models/signals.py,sha256=YfGwq-DUC0dtJEru2Q7MJH5zvPkhmPEb3vQoRJiYc34,1639
|
|
163
164
|
django_ledger/models/transactions.py,sha256=kOL7s-hiRc6iqS7J62bVJY6ikja9Q8WdkRq0FT0zO2U,22722
|
|
164
165
|
django_ledger/models/unit.py,sha256=x5FFJXgOi1OdajQejIakW6wGY4DjrJhL3S0Pm5OimMk,8074
|
|
165
166
|
django_ledger/models/utils.py,sha256=3gkdCrfJp9qwN3Sf8R96AliilzwcKBm31UEao4WJO9o,8436
|
|
@@ -172,7 +173,7 @@ django_ledger/models/schemas/pnl.py,sha256=_M5qZtgXca4LQLsjS0weUAzLX98M4-5HCCGM0
|
|
|
172
173
|
django_ledger/report/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
173
174
|
django_ledger/report/balance_sheet.py,sha256=iw8VOcJfJJHcKwFmdR9p2uYj5iKyX6avUjVSBrT0nZc,8436
|
|
174
175
|
django_ledger/report/cash_flow_statement.py,sha256=GosnBzMZWlqNGitOlxvDiHxkT4JrNm0FH3uXfjmXPG8,8717
|
|
175
|
-
django_ledger/report/core.py,sha256=
|
|
176
|
+
django_ledger/report/core.py,sha256=MSWOHvYrAfAJJtm1_vXv7vZxgAja6ycKxknoaIvJT_g,7436
|
|
176
177
|
django_ledger/report/income_statement.py,sha256=m4pG0Yjpl7SELx3-yYKT4dCluKt6nT2bkD9gay9tNKI,11156
|
|
177
178
|
django_ledger/static/django_ledger/bundle/djetler.bundle.js,sha256=1UzHryjoKN43wUa5b6N2ia2yoE-TCrtfNMnuPIf9Im8,547613
|
|
178
179
|
django_ledger/static/django_ledger/bundle/styles.bundle.js,sha256=myDLVMYHwKTxypheUretM6MZ4HhK8Yn0BqB_OGUW3KU,506543
|
|
@@ -272,7 +273,7 @@ django_ledger/templates/django_ledger/expense/expense_create.html,sha256=ozRliR0
|
|
|
272
273
|
django_ledger/templates/django_ledger/expense/expense_list.html,sha256=d7IwuA2qrDPYKmg8a0b4T2CIzIfHB6ximk8Ak4VR4xY,867
|
|
273
274
|
django_ledger/templates/django_ledger/expense/expense_update.html,sha256=7YTGqytGb1KFAiP7x3jZ-ljkXziqir6KnMiFrl_s8Kk,1439
|
|
274
275
|
django_ledger/templates/django_ledger/expense/tags/expense_item_table.html,sha256=uKUB-1eIvA5KWKZ7kwu0hGf-64ly_onjWgKokQ0S9dI,1962
|
|
275
|
-
django_ledger/templates/django_ledger/financial_statements/balance_sheet.html,sha256=
|
|
276
|
+
django_ledger/templates/django_ledger/financial_statements/balance_sheet.html,sha256=_trd5e282eMsC5VfzP9tL7zPJ_kTGMxlrh77RWwLlY4,2793
|
|
276
277
|
django_ledger/templates/django_ledger/financial_statements/cash_flow.html,sha256=zeu7OcXl2T_vDoFyJvb0htFIjQz0IfyJBiOcck2skus,3031
|
|
277
278
|
django_ledger/templates/django_ledger/financial_statements/income_statement.html,sha256=pfrv12Bu_PmU-MrL7JXYX7Wv4PZ06fKvOdydzzgeEnw,2731
|
|
278
279
|
django_ledger/templates/django_ledger/financial_statements/tags/balance_sheet_statement.html,sha256=u2o3krlo_I7w-erXI9DO4gNChbYn0KpdeLRZs7UckOQ,6430
|
|
@@ -367,6 +368,8 @@ django_ledger/tests/test_purchase_order.py,sha256=vPjPthS6nS8Q1KmZW5zUFogqQKR1MZ
|
|
|
367
368
|
django_ledger/tests/test_transactions.py,sha256=qeIJr0q43IpI_9YrzjVcnltnk_7puGvdhmH-hDePgEc,11721
|
|
368
369
|
django_ledger/tests/bdd/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
369
370
|
django_ledger/tests/bdd/features/steps/README.py,sha256=4HMdVjjflcKQBf0LeZbc5i3TXbe5qGxYBcGmHn4i3jU,599
|
|
371
|
+
django_ledger/tests/test_io_ofx/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
372
|
+
django_ledger/tests/test_io_ofx/tests.py,sha256=v-2xY410a6Tr2TwG5oqc_UkFzXBIAFxWYasZkeiXAfE,1993
|
|
370
373
|
django_ledger/urls/__init__.py,sha256=98Dk0iQPeK2chSTY8H-7yuk9OycoUoZJdbpuR0Wv2rw,1994
|
|
371
374
|
django_ledger/urls/account.py,sha256=9G6m2mkki8sNtC_mlNIHcn2SCSoG7ienbQ5qg2kHWg0,2399
|
|
372
375
|
django_ledger/urls/auth.py,sha256=8dY2h6PQkMayUL81guu9JCxm--Tj0rglvvxg9Qh03aY,230
|
|
@@ -392,10 +395,10 @@ django_ledger/urls/transactions.py,sha256=e_x_z5qbkR6i7o8OWWdXshDiY_WVmu9WVhR9A9
|
|
|
392
395
|
django_ledger/urls/unit.py,sha256=QEVKrgcw2dqMaaXsUHfqYecTa5-iaPlS9smrYJ1QsgM,1506
|
|
393
396
|
django_ledger/urls/vendor.py,sha256=ODHpAwe5lomluj8ZCqbMtugTeeRsv0Yo9SqkZEmfYaw,393
|
|
394
397
|
django_ledger/views/__init__.py,sha256=l5Pm2_oAW6Q_jJbXf-BiHA3ilCbiGb6gkXCm73K5DGY,1158
|
|
395
|
-
django_ledger/views/account.py,sha256=
|
|
398
|
+
django_ledger/views/account.py,sha256=cz9bgEyTY05lN997Zln7M4xwBzh45CXo0OTgqnXtdEY,10529
|
|
396
399
|
django_ledger/views/auth.py,sha256=-zTjMlLpyxHGPlY9EXFQyeVHMmyeJ2H9RptcW7PDeDg,771
|
|
397
400
|
django_ledger/views/bank_account.py,sha256=bMgqrDydz6WuXina4L27uV-cmQicW0_JoPaXxlO7uN4,5176
|
|
398
|
-
django_ledger/views/bill.py,sha256
|
|
401
|
+
django_ledger/views/bill.py,sha256=AaDdb1RLJDbHhuRdWXaYAIkCOVMtW2U3KcNgDKJKm8Y,23093
|
|
399
402
|
django_ledger/views/closing_entry.py,sha256=y78azZesVgdUoQmaSEYiP7MBaPRE45qAAHPDlcThlUs,8103
|
|
400
403
|
django_ledger/views/coa.py,sha256=WnWQVz-4Ik9v28KHzD_WiKcgix7l6bBj1A60p4k-eos,4934
|
|
401
404
|
django_ledger/views/customer.py,sha256=RoBsXBxZC9b79DSNNHaoSZtQ2AoXf7DJAGmZEO3xdxs,3672
|
|
@@ -416,9 +419,9 @@ django_ledger/views/purchase_order.py,sha256=1J3u4QnCkM7z1Y6DePijVdM67x4CQgfmQJc
|
|
|
416
419
|
django_ledger/views/transactions.py,sha256=5taQRGLSMkM_N8paQJ07HMspI_Nl7PawF8OohCiRmao,206
|
|
417
420
|
django_ledger/views/unit.py,sha256=_RgPJO9mR6v5ohBXlnL3T8nTWgS1lwlCvERQcHk0wHE,10232
|
|
418
421
|
django_ledger/views/vendor.py,sha256=gUdBPTFLeSwlNfdHSA1KFdE_y3QpwpkFhEB0r3-UYdI,3461
|
|
419
|
-
django_ledger-0.6.
|
|
420
|
-
django_ledger-0.6.
|
|
421
|
-
django_ledger-0.6.
|
|
422
|
-
django_ledger-0.6.
|
|
423
|
-
django_ledger-0.6.
|
|
424
|
-
django_ledger-0.6.
|
|
422
|
+
django_ledger-0.6.3.dist-info/AUTHORS.md,sha256=SRM2cynD89ZfEsL09zrbUVeO17r9zE2ZM7y6ReMqVRo,713
|
|
423
|
+
django_ledger-0.6.3.dist-info/LICENSE,sha256=ixuiBLtpoK3iv89l7ylKkg9rs2GzF9ukPH7ynZYzK5s,35148
|
|
424
|
+
django_ledger-0.6.3.dist-info/METADATA,sha256=hSjmos-2S46tN0421i8xYk_7M6zhPmQBMlYyCTfTL1s,9641
|
|
425
|
+
django_ledger-0.6.3.dist-info/WHEEL,sha256=yQN5g4mg4AybRjkgi-9yy4iQEFibGQmlz78Pik5Or-A,92
|
|
426
|
+
django_ledger-0.6.3.dist-info/top_level.txt,sha256=0U3SjF63ND36grQNWDONVe-T9-T07lFl5e6QkG7bR2E,44
|
|
427
|
+
django_ledger-0.6.3.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|