86 lines
3.1 KiB
Python
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
|