def migrate_invoices(apps, schema_editor): from systori.apps.company.models import Company from systori.apps.document.models import Invoice from systori.apps.task.models import Job from systori.apps.accounting.report import create_invoice_report from systori.apps.accounting.constants import TAX_RATE from systori.lib.accounting.tools import Amount for company in Company.objects.all(): company.activate() for invoice in Invoice.objects.all(): invoice.json["debit"] = Amount(invoice.json["debit_net"], invoice.json["debit_tax"]) if "debits" not in invoice.json: invoice.json["jobs"] = [] invoice.save() continue invoice.json["jobs"] = invoice.json["debits"] del invoice.json["debits"] jobs = Job.objects.filter( id__in=[job["job.id"] for job in invoice.json["jobs"]]) tdate = date( *map(int, invoice.json["transactions"][-1]["date"].split("-"))) new_json = create_invoice_report(invoice.transaction, jobs, tdate) if (company.schema == "mehr_handwerk" and invoice.id not in [86, 111]) or ( company.schema == "montageservice_grad" and invoice.id not in [1]): assert new_json["debit"].gross == invoice.json["debit"].gross assert new_json["invoiced"].gross == invoice.json[ "debited_gross"] invoice.json.update(new_json) for job in invoice.json["jobs"]: taskgroup_total = Decimal("0.00") for taskgroup in job["taskgroups"]: taskgroup_total += taskgroup["total"] job["progress"] = Amount.from_net(taskgroup_total, TAX_RATE) invoiced_total = Amount.zero() for debit in invoice.json["job_debits"].get(job["job.id"], []): invoiced_total += debit["amount"] job["invoiced"] = invoiced_total job["debit"] = Amount(job["amount_net"], job["amount_tax"]) job["balance"] = Amount(job["balance_net"], job["balance_tax"]) job["estimate"] = Amount.from_net(job["estimate_net"], TAX_RATE) job["is_itemized"] = job["invoiced"].gross == job[ "progress"].gross invoice.save()
def calculate_accounting_state(self, state): state.paid_amount = self.job.account.paid.negate state.invoiced_amount = self.job.account.invoiced state.invoiced_diff_amount = state.invoiced_amount - state.paid_amount state.progress_amount = Amount.from_net(self.job.progress, TAX_RATE) state.progress_diff_amount = state.progress_amount - state.invoiced_amount
def calculate_accounting_state(self, state): state.estimate_amount = Amount.from_net(self.job.estimate, TAX_RATE) state.progress_amount = Amount.from_net(self.job.progress, TAX_RATE) state.progress_percent = self.job.progress_percent state.invoiced_amount = self.job.account.invoiced state.invoiced_percent = 0 if state.progress_amount.net > 0: state.invoiced_percent = ( state.invoiced_amount.net / state.progress_amount.net * 100 ) state.balance_amount = self.job.account.balance state.itemized_amount = state.progress_amount - state.invoiced_amount if state.itemized_amount.gross < 0: state.itemized_amount = Amount.zero()
def calculate_accounting_state(self, state): # Paid Column state.paid_amount = self.job.account.paid.negate # Invoiced Column state.invoiced_amount = self.job.account.invoiced state.invoiced_diff_amount = state.invoiced_amount - state.paid_amount # Billable Column state.progress_amount = Amount.from_net(self.job.progress, TAX_RATE) state.progress_diff_amount = state.progress_amount - state.invoiced_amount
def test_project_143_having_open_claim_2016_04_06(self): txn = debit_jobs( [ (self.job, Amount.from_net(D("22721.38"), TAX_RATE), Entry.WORK_DEBIT), (self.job2, Amount.from_net(D("3400.05"), TAX_RATE), Entry.WORK_DEBIT), ], transacted_on=days_ago(8), ) self.assertEqual( self.tbl(txn, [self.job, self.job2]), [ ("", "net", "tax", "gross"), ("progress", "26121.43", "4963.07", "31084.50"), ("debit", "26121.43", "4963.07", "31084.50"), ], ) credit_jobs( [ (self.job, A("26227.29"), A("811.15"), A()), (self.job2, A("1572.71"), A("48.64"), A("2424.71")), ], D("27800.00"), transacted_on=days_ago(7), ) txn = debit_jobs( [ (self.job, Amount.from_net(D("8500"), TAX_RATE), Entry.WORK_DEBIT), (self.job2, Amount.from_net(D("4000"), TAX_RATE), Entry.WORK_DEBIT), (self.job3, Amount.from_net(D("1000"), TAX_RATE), Entry.WORK_DEBIT), ], transacted_on=days_ago(6), ) self.assertEqual( self.tbl(txn, [self.job, self.job2, self.job3]), [ ("", "net", "tax", "gross"), ("progress", "37583.86", "7140.93", "44724.79"), ("payment", "-23361.35", "-4438.65", "-27800.00"), ("discount", "-722.51", "-137.28", "-859.79"), ("debit", "13500.00", "2565.00", "16065.00"), ], ) credit_jobs( [ (self.job, A("9811.55"), A("303.45"), A()), (self.job2, A("3188.45"), A("98.61"), A("1472.94")), ], D("13000.00"), transacted_on=days_ago(5), ) txn = debit_jobs( [ (self.job2, Amount.from_net(D("11895.04"), TAX_RATE), Entry.WORK_DEBIT), (self.job3, Amount.from_net(D("1628.86"), TAX_RATE), Entry.WORK_DEBIT), (self.job4, Amount.from_net(D("358.31"), TAX_RATE), Entry.WORK_DEBIT), ], transacted_on=days_ago(4), ) self.assertEqual( self.tbl(txn, [self.job, self.job2, self.job3, self.job4]), [ ("", "net", "tax", "gross"), ("progress", "50228.31", "9543.37", "59771.68"), ("payment", "-23361.35", "-4438.65", "-27800.00"), ("discount", "-722.51", "-137.28", "-859.79"), ("payment", "-10924.37", "-2075.63", "-13000.00"), ("discount", "-337.87", "-64.19", "-402.06"), ("unpaid", "-1000.00", "-190.00", "-1190.00"), ("debit", "13882.21", "2637.62", "16519.83"), ], ) credit_jobs( [ (self.job2, A("6585.27"), A("203.67"), A("7366.16")), (self.job3, A("1938.34"), A("59.95"), A()), (self.job4, A("426.39"), A("13.19"), A()), ], D("8950.00"), transacted_on=days_ago(3), ) # Initial Case: Due to an underpaid job, invoice shows 'open claim'. dtxn = debit_jobs( [ (self.job2, Amount.from_net(D("17790.25"), TAX_RATE), Entry.WORK_DEBIT), (self.job5, Amount.from_net(D("6377.68"), TAX_RATE), Entry.WORK_DEBIT), (self.job3, Amount.from_net(D("2034.90"), TAX_RATE), Entry.WORK_DEBIT), (self.job4, Amount.from_net(D("716.62"), TAX_RATE), Entry.WORK_DEBIT), ], transacted_on=days_ago(1), ) self.assertEqual( self.tbl(dtxn, [self.job, self.job2, self.job3, self.job4, self.job5]), [ ("", "net", "tax", "gross"), ("progress", "70957.71", "13481.96", "84439.67"), ("payment", "-23361.35", "-4438.65", "-27800.00"), ("discount", "-722.51", "-137.28", "-859.79"), ("payment", "-10924.37", "-2075.63", "-13000.00"), ("discount", "-337.87", "-64.19", "-402.06"), ("payment", "-7521.01", "-1428.99", "-8950.00"), ("discount", "-232.61", "-44.20", "-276.81"), ("unpaid", "-938.54", "-178.32", "-1116.86"), # <-- open claim ("debit", "26919.45", "5114.70", "32034.15"), ], ) dtxn.delete() # Adjusted Case: We adjust two jobs, no open claim, but progress is high due to over invoiced job. atxn = adjust_jobs( [ (self.job3, A(n="-949.62", t="-180.43")), (self.job4, A(n="11.08", t="2.11")), ], transacted_on=days_ago(1), ) dtxn = debit_jobs( [ (self.job2, Amount.from_net(D("17790.25"), TAX_RATE), Entry.WORK_DEBIT), (self.job5, Amount.from_net(D("6377.68"), TAX_RATE), Entry.WORK_DEBIT), (self.job3, Amount.from_net(D("2984.52"), TAX_RATE), Entry.WORK_DEBIT), (self.job4, Amount.from_net(D("705.54"), TAX_RATE), Entry.WORK_DEBIT), ], transacted_on=days_ago(3), ) self.assertEqual( self.tbl(dtxn, [self.job, self.job2, self.job3, self.job4, self.job5]), [ ("", "net", "tax", "gross"), ("progress", "70957.71", "13481.96", "84439.67"), ("payment", "-23361.35", "-4438.65", "-27800.00"), ("discount", "-722.51", "-137.28", "-859.79"), ("payment", "-10924.37", "-2075.63", "-13000.00"), ("discount", "-337.87", "-64.19", "-402.06"), ("payment", "-7521.01", "-1428.99", "-8950.00"), ("discount", "-232.61", "-44.20", "-276.81"), # ('unpaid', '-938.54', '-178.32', '-1116.86'), <-- consumed into debit below ("debit", "27857.99", "5293.02", "33151.01"), ], ) atxn.delete() dtxn.delete() # Adjusted Case II: We adjust three jobs, now invoice progress is correct and there is no open claim. atxn = adjust_jobs( [ (self.job, A(n="-4678.55", t="-888.92")), (self.job3, A(n="-949.62", t="-180.43")), (self.job4, A(n="11.08", t="2.11")), ], transacted_on=days_ago(1), ) dtxn = debit_jobs( [ (self.job2, Amount.from_net(D("17790.25"), TAX_RATE), Entry.WORK_DEBIT), (self.job5, Amount.from_net(D("6377.68"), TAX_RATE), Entry.WORK_DEBIT), (self.job3, Amount.from_net(D("2984.52"), TAX_RATE), Entry.WORK_DEBIT), (self.job4, Amount.from_net(D("705.54"), TAX_RATE), Entry.WORK_DEBIT), ], transacted_on=days_ago(3), ) self.assertEqual( self.tbl(dtxn, [self.job, self.job2, self.job3, self.job4, self.job5]), [ ("", "net", "tax", "gross"), ("progress", "66279.16", "12593.04", "78872.20"), ("payment", "-23361.35", "-4438.65", "-27800.00"), ("discount", "-722.51", "-137.28", "-859.79"), ("payment", "-10924.37", "-2075.63", "-13000.00"), ("discount", "-337.87", "-64.19", "-402.06"), ("payment", "-7521.01", "-1428.99", "-8950.00"), ("discount", "-232.61", "-44.20", "-276.81"), ("debit", "27857.99", "5293.02", "33151.01"), ], ) atxn.delete() dtxn.delete() # Adjusted & Refund Case: We adjust three jobs as before but also issue a refund. # Just making sure refund does not change the invoice in anyway. atxn = adjust_jobs( [ (self.job, A(n="-4678.55", t="-888.92")), (self.job3, A(n="-949.62", t="-180.43")), (self.job4, A(n="11.08", t="2.11")), ], transacted_on=days_ago(1), ) rtxn = refund_jobs( [ (self.job, A(n="4678.55", t="888.92"), A()), (self.job2, A(), A(n="4678.55", t="888.92")), ], transacted_on=days_ago(1), ) dtxn = debit_jobs( [ (self.job2, Amount.from_net(D("17790.25"), TAX_RATE), Entry.WORK_DEBIT), (self.job5, Amount.from_net(D("6377.68"), TAX_RATE), Entry.WORK_DEBIT), (self.job3, Amount.from_net(D("2984.52"), TAX_RATE), Entry.WORK_DEBIT), (self.job4, Amount.from_net(D("705.54"), TAX_RATE), Entry.WORK_DEBIT), ], transacted_on=days_ago(3), ) self.assertEqual( self.tbl(dtxn, [self.job, self.job2, self.job3, self.job4, self.job5]), [ ("", "net", "tax", "gross"), ("progress", "66279.16", "12593.04", "78872.20"), ("payment", "-23361.35", "-4438.65", "-27800.00"), ("discount", "-722.51", "-137.28", "-859.79"), ("payment", "-10924.37", "-2075.63", "-13000.00"), ("discount", "-337.87", "-64.19", "-402.06"), ("payment", "-7521.01", "-1428.99", "-8950.00"), ("discount", "-232.61", "-44.20", "-276.81"), ("debit", "27857.99", "5293.02", "33151.01"), ], ) atxn.delete() rtxn.delete() dtxn.delete()
def migrate_proposals(apps, schema_editor): from systori.apps.company.models import Company from systori.apps.task.models import Job from systori.apps.document.models import Proposal from systori.apps.accounting.constants import TAX_RATE from systori.lib.accounting.tools import Amount for company in Company.objects.all(): company.activate() for proposal in Proposal.objects.all(): try: if "total_base" not in proposal.json and "jobs" not in proposal.json: proposal.json["date"] = proposal.document_date proposal.json["estimate_total"] = Amount( proposal.json["total_net"], proposal.json["total_gross"] - proposal.json["total_net"], ) proposal.json["jobs"] = [] else: proposal.json["estimate_total"] = Amount( proposal.json["total_base"], proposal.json["total_tax"]) del proposal.json["total_base"], proposal.json[ "total_tax"], proposal.json["total_gross"] proposal.json["id"] = proposal.id proposal.json["title"] = _("Proposal") for job in proposal.json["jobs"]: if "id" in job: job["job.id"] = job["id"] del job["id"] else: job_obj = Job.objects.filter(project=proposal.project, name=job["name"]).get() job["job.id"] = job_obj.id job_estimate_net = Decimal("0.00") for group in job["taskgroups"]: group["estimate_net"] = group["total"] del group["total"] job_estimate_net += Decimal(group["estimate_net"]) for task in group["tasks"]: task["estimate_net"] = task["total"] del task["total"] job["estimate"] = Amount.from_net(job_estimate_net, TAX_RATE) proposal.save() except: if proposal.status == proposal.DECLINED: proposal.delete() else: raise
def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.estimate_amount = Amount.from_net(self.job.estimate, TAX_RATE)