Package: django-ledgers
django-ledgersv0.1.0Django app which implements ledgers to store cumulative data.DescriptionALedgeris an abstraction over Django ORM which consists of 2 tables:movements — stores periodic data about ledger's state change.totals — stores pre-calculated cumulative result for some period.Ledger's state is changed viaDocuments— an "atomic" abstraction over set of simultaneous changes.ExamplesWarehouse remainsItems:fromdjango.dbimportmodelsclassItem(models.Model):name=models.CharField(max_length=200,unique=True)can be stored at Warehouse:classWarehouse(models.Model):name=models.CharField()via Warehouse Balance Ledger:fromledgers.enumimportCumulativeLedgerRecordActionEnumfromledgers.ledgerimportCumulativeLedgerfromledgers.ledger.fieldsimportdimensions,resourcesclassBalanceAtWarehousesLedger(CumulativeLedger):warehouse=dimensions.ForeignKey(to=Warehouse,null=False,)item=dimensions.ForeignKey(to=Item,null=False,)amount=resources.Integer()comment=models.CharField(max_length=200,null=False,default='')@classmethoddefmovements_for_itemmovement(cls,doc):# noinspection PyCallingNonCallablereturn(cls.mvm_model(period=doc.execution_date,registrator=doc,line_index=0,action=CumulativeLedgerRecordActionEnum.OUTCOME,warehouse_id=doc.from_warehouse_id,item_id=doc.item_id,amount=doc.amount,),cls.mvm_model(period=doc.execution_date,registrator=doc,line_index=1,action=CumulativeLedgerRecordActionEnum.INCOME,warehouse_id=doc.to_warehouse_id,item_id=doc.item_id,amount=doc.amount,),)and changed via Item Movement:classItemMovement(Document):classDocumentMeta(Document.DocumentMeta):related_ledgers=[BalanceAtWarehousesLedger]default_prefix='MVM'from_warehouse=models.ForeignKey(Warehouse,on_delete=models.CASCADE,null=False,blank=False,related_name='+',)to_warehouse=models.ForeignKey(Warehouse,on_delete=models.CASCADE,null=False,blank=False,related_name='+',)item=models.ForeignKey(Item,on_delete=models.CASCADE,null=False,blank=False,)amount=models.IntegerField(null=False,blank=False,)Then, on creating an ItemMovement:fromledgers.enumimportDocumentStateEnum# prepare instancest_shirt=Item.objects.get_or_create(name='T-shirt')london_warehouse=Warehouse.objects.get_or_create(name='London')tokyo_warehouse=Warehouse.objects.get_or_create(name='Tokyo')# prepare and save documentdoc=ItemMovement(state=DocumentStateEnum.ACTIVE,item=t_shirt,from_warehouse=london_warehouse,to_warehouse=tokyo_warehouse,amount=100,)doc.save()Movements and totals tables will be updated, and actual remains for any period can be fetched:fromexample.exampleapp.modelsimportItem,Warehouse,BalanceAtWarehousesLedgerfromdatetimeimporttimedelta# prepare instancest_shirt=Item.objects.get_or_create(name='T-shirt')london_warehouse=Warehouse.objects.get_or_create(name='London')tokyo_warehouse=Warehouse.objects.get_or_create(name='Tokyo')remains_before_document_date=BalanceAtWarehousesLedger.remains_qs(period=doc.execution_date-timedelta(days=1),)remains_after_document_date=BalanceAtWarehousesLedger.remains_qs()print(list(remains_before_document_date))# [#   {#       'warehouse_id': 1,#       'item_id': 1,#       'amount_remains': 0#   },#   {#       'warehouse_id': 2,#       'item_id': 1,#       'amount_remains': 0#   }# ]print(list(remains_after_document_date))# [#   {#       'warehouse_id': 1,#       'item_id': 1,#       'amount_remains': -10#   },#   {#       'warehouse_id': 2,#       'item_id': 1,#       'amount_remains': 10#   }# ]Featuresdjango-ledgers@v0.1.0can:store push tokens from FCM or HMSlink push tokens with their users and applicationsstore push notificationsstore push notifications extra kwargs (e.g. deeplinks)compose recipients via UI based on user-specified conditionswatch notifications schedule on calendarsend scheduled push notificationsstore applications as swappable modelUsage exampleTODOexampleprojExample projectis a showcase django project.
You can reference to it for usage cases, examples, testing.
You must never deployexampleprojin production due to exposedSECRET_KEY.Getting StartedDependenciesPython packagesdjangodjango-cteInstallingUsing Python Package Indexmake sure to use latestpip:python3-mpipinstall--upgradepipinstalldjango-ledgers:python3-mpipinstalldjango-ledgersOR download package from releasesdownload release asset (.tar.gzor.whl)make sure to use latestpip:python3-mpipinstall--upgradepipinstalldjangoFCMfrom file:python3-mpipinstall/path/to/downloaded/asset.tar.gz# or .whlOR clone from repositoryclone project:gitclone\--depth=1\--branch=master\git@github.com:omelched/django-ledgers.git\</path/to/downloads>move/django-ledgers/ledgerssolely to folder containing django appsmv</path/to/downloads>/django-ledgers/ledgers\</path/to/django/project/apps>remove leftoversrm-rf</path/to/downloads>/django-ledgersConfiguringInstalling applicationAdddjango-ledgerstoINSTALLED_APPSin your Django projectsettings.py.If you installed packagethe third way,</path/to/django/project/apps>must be added toPYTHONPATH. If you not sure add code below in your Django projectmanage.pybefore callingmain():sys.path.append('</path/to/django/project/apps>')Subclassledgers.ledger.cumulative.CumulativeLedgerandledgers.models.documents.document.Document.MigrationsExecute database migrations:pythonexample/manage.pymigrateCollect static:pythonexample/manage.pycollectstaticAuthors@omelched(Denis Omelchenko)ContributorsChangelistdjango-ledgersversion history and changelist
available atreleasespage.LicenseThis project is licensed under theMITLicense - see theLICENSEfile for details.AcknowledgmentsThis project is inspired by 1C ORM. More on topic:https://its.1c.ru/db/pubapplied/content/123/hdoc(writing)https://its.1c.ru/db/pubapplied/content/130/hdoc(querying)