barker/barker/barker/routers/reports/tax_report.py

86 lines
3.1 KiB
Python

import re
from datetime import date, datetime, time, timedelta
from decimal import Decimal
from typing import List
from fastapi import APIRouter, Depends, Security
from sqlalchemy import func, select
from sqlalchemy.orm import Session
from ...core.config import settings
from ...core.security import get_current_active_user as get_user
from ...db.session import SessionFuture
from ...models.inventory import Inventory
from ...models.kot import Kot
from ...models.tax import Tax
from ...models.voucher import Voucher
from ...models.voucher_type import VoucherType
from ...schemas.tax_report import TaxReport, TaxReportItem
from ...schemas.user_token import UserToken
from . import check_audit_permission, report_finish_date, report_start_date
router = APIRouter()
@router.get("", response_model=TaxReport)
def get_tax_report(
start_date: date = Depends(report_start_date),
finish_date: date = Depends(report_finish_date),
user: UserToken = Security(get_user, scopes=["tax-report"]),
) -> TaxReport:
check_audit_permission(start_date, user.permissions)
with SessionFuture() as db:
return TaxReport(
startDate=start_date.strftime("%d-%b-%Y"),
finishDate=finish_date.strftime("%d-%b-%Y"),
amounts=get_tax(start_date, finish_date, db),
)
def get_tax(s: date, f: date, db: Session) -> List[TaxReportItem]:
start_date = datetime.combine(s, time()) + timedelta(
minutes=settings.NEW_DAY_OFFSET_MINUTES - settings.TIMEZONE_OFFSET_MINUTES
)
finish_date = datetime.combine(f, time()) + timedelta(
days=1, minutes=settings.NEW_DAY_OFFSET_MINUTES - settings.TIMEZONE_OFFSET_MINUTES
)
amounts = db.execute(
select(
Tax.name,
Inventory.tax_rate,
func.coalesce(func.sum(Inventory.net), 0),
func.coalesce(func.sum(Inventory.tax_amount), 0),
)
.join(Voucher.kots)
.join(Kot.inventories)
.join(Inventory.tax)
.where(
Voucher.date >= start_date,
Voucher.date <= finish_date,
Voucher.voucher_type == VoucherType.REGULAR_BILL,
)
.group_by(Tax.name, Inventory.tax_rate)
.order_by(Tax.name, Inventory.tax_rate)
).all()
return sum([get_tax_item(*i) for i in amounts], [])
def get_tax_item(name: str, rate: Decimal, net: Decimal, amount: Decimal) -> List[TaxReportItem]:
items = name.split(";")
if len(items) == 1:
return [TaxReportItem(name=name, taxRate=rate, saleAmount=net, amount=amount)]
else:
r = []
for i, item in enumerate(it.strip() for it in items):
match = re.match(r"(^.*)\s+\((.*?)/(.*?)\)[^(]*$", item)
if not match or len(match.groups()) != 3:
raise Exception("Error in tax as it has multiple items, but the format is wrong.")
ratio = Decimal(match.group(2)) / Decimal(match.group(3))
sub_net = round(net * ratio, 2)
sub_amount = round(amount * ratio, 2)
r.append(TaxReportItem(name=f"{match.group(1)}", taxRate=rate, saleAmount=sub_net, amount=sub_amount))
return r