brewman/brewman/brewman/schemas/voucher.py

287 lines
7.3 KiB
Python

import json
import uuid
from datetime import date, datetime
from decimal import Decimal
from typing import Any, List, Optional
from brewman.schemas import to_camel
from brewman.schemas.master import (
AccountLink,
CostCentreLink,
EmployeeLink,
ProductLink,
)
from fastapi import Form
from pydantic import BaseModel, Field, validator
class ImageUpload(BaseModel):
id_: Optional[uuid.UUID]
resized: Optional[str]
thumbnail: Optional[str]
class Config:
alias_generator = to_camel
class UserLink(BaseModel):
id_: uuid.UUID
name: str
class Config:
alias_generator = to_camel
class Journal(BaseModel):
id_: Optional[uuid.UUID]
debit: int = Field(ge=-1, le=1, multiple_of=1)
amount: Decimal = Field(ge=0, multiple_of=0.01)
account: AccountLink
cost_centre: Optional[CostCentreLink]
class Config:
anystr_strip_whitespace = True
alias_generator = to_camel
class Batch(BaseModel):
id_: uuid.UUID
name: str
product: ProductLink
quantity_remaining: Decimal
rate: Decimal
tax: Decimal
discount: Decimal
class Config:
alias_generator = to_camel
class Inventory(BaseModel):
id_: Optional[uuid.UUID]
product: ProductLink
batch: Optional[Batch]
quantity: Decimal = Field(ge=0, multiple_of=0.01)
rate: Decimal = Field(ge=0, multiple_of=0.01)
tax: Decimal = Field(ge=0, multiple_of=0.00001, le=5)
discount: Decimal = Field(ge=0, multiple_of=0.00001, le=1)
amount: Optional[Decimal]
class Config:
alias_generator = to_camel
class EmployeeBenefit(BaseModel):
id_: Optional[uuid.UUID]
employee: Optional[EmployeeLink]
gross_salary: int = Field(ge=0)
days_worked: int = Field(ge=0)
esi_employee: Optional[int] = Field(ge=0)
pf_employee: Optional[int] = Field(ge=0)
esi_employer: Optional[int] = Field(ge=0)
pf_employer: Optional[int] = Field(ge=0)
class Config:
alias_generator = to_camel
class Incentive(BaseModel):
employee_id: uuid.UUID
name: str
designation: str
department: str
days_worked: Decimal = Field(ge=0, multiple_of=0.5)
points: Decimal = Field(ge=0, multiple_of=0.01)
class Config:
alias_generator = to_camel
class VoucherIn(BaseModel):
date_: date
narration: str
is_starred: bool
type_: str
files: List[ImageUpload]
@classmethod
def load_form(cls, data: str = Form(...)):
json_data = json.loads(data)
return cls.parse_obj(json_data)
class Voucher(VoucherIn):
id_: Optional[uuid.UUID]
is_reconciled: Optional[bool]
reconcile_date: Optional[date]
creation_date: Optional[datetime]
last_edit_date: Optional[datetime]
user: Optional[UserLink]
posted: Optional[bool]
poster_id: Optional[uuid.UUID]
journals: List[Journal]
inventories: List[Inventory]
vendor: Optional[AccountLink]
source: Optional[CostCentreLink]
destination: Optional[CostCentreLink]
incentives: Optional[List[Incentive]]
incentive: Optional[Decimal]
employee_benefits: List[EmployeeBenefit]
files: List[ImageUpload]
class Config:
anystr_strip_whitespace = True
alias_generator = to_camel
json_encoders = {
date: lambda v: v.strftime("%d-%b-%Y"),
datetime: lambda v: v.strftime("%d-%b-%Y %H:%I"),
}
@validator("date_", pre=True)
def parse_date(cls, value):
if isinstance(value, date):
return value
return datetime.strptime(value, "%d-%b-%Y").date()
@validator("creation_date", pre=True)
def parse_creation_date(cls, value):
if isinstance(value, datetime):
return value
return datetime.strptime(value, "%d-%b-%Y %H:%M")
@validator("last_edit_date", pre=True)
def parse_last_edit_date(cls, value):
if isinstance(value, datetime):
return value
return datetime.strptime(value, "%d-%b-%Y %H:%M")
@validator("reconcile_date", pre=True)
def parse_reconcile_date(cls, value):
if value is None or value == "":
return None
elif isinstance(value, date):
return value
return datetime.strptime(value, "%d-%b-%Y").date()
# @validator("journals")
# def validate_enough_journals(cls, value: List[Journal]):
# if 0 < len(value) < 2:
# raise ValueError("Not enough journals")
# return value
#
@validator("journals")
def validate_signed_amount(cls, value: List[Journal]):
if sum(x.debit * x.amount for x in value) != 0:
raise ValueError("Journal amounts do no match")
return value
@validator("journals")
def is_distinct(cls, value: List[Journal]):
journal_set = set(
hash(x.account.id_)
^ hash(None if x.cost_centre is None else x.cost_centre.id_)
for x in value
)
if len(value) != len(journal_set):
raise ValueError("Duplicate journals")
return value
class AttendanceType(BaseModel):
id_: int
name: Optional[str]
value: Optional[Decimal]
class Config:
alias_generator = to_camel
class AttendanceItem(BaseModel):
id_: uuid.UUID
code: int
name: str
designation: str
department: str
attendance_type: AttendanceType
prints: str
hours_worked: str
full_day: Optional[bool]
class Config:
alias_generator = to_camel
class Attendance(BaseModel):
date_: Optional[date]
body: List[AttendanceItem]
@validator("date_", pre=True)
def parse_date(cls, value):
if isinstance(value, date):
return value
return datetime.strptime(value, "%d-%b-%Y").date()
class Config:
anystr_strip_whitespace = True
alias_generator = to_camel
json_encoders = {date: lambda v: v.strftime("%d-%b-%Y")}
class EmployeeAttendanceItem(BaseModel):
date_: date
attendance_type: AttendanceType
prints: str
hours_worked: str
full_day: Optional[bool]
@validator("date_", pre=True)
def parse_date(cls, value):
if isinstance(value, date):
return value
return datetime.strptime(value, "%d-%b-%Y").date()
class Config:
anystr_strip_whitespace = True
alias_generator = to_camel
json_encoders = {date: lambda v: v.strftime("%d-%b-%Y")}
class EmployeeAttendance(BaseModel):
start_date: Optional[date]
finish_date: Optional[date]
employee: Optional[AccountLink]
body: List[EmployeeAttendanceItem]
@validator("start_date", pre=True)
def parse_start_date(cls, value):
if isinstance(value, date):
return value
return datetime.strptime(value, "%d-%b-%Y").date()
@validator("finish_date", pre=True)
def parse_finish_date(cls, value):
if isinstance(value, date):
return value
return datetime.strptime(value, "%d-%b-%Y").date()
class Config:
anystr_strip_whitespace = True
alias_generator = to_camel
json_encoders = {date: lambda v: v.strftime("%d-%b-%Y")}
class Fingerprint(BaseModel):
id: uuid.UUID
employee_id: uuid.UUID
date: date
class DbImage(BaseModel):
id: uuid.UUID
resource_id: uuid.UUID
resource_type: str
image: bytes
thumbnail: bytes
creation_date: datetime