2020-05-17 10:08:13 +00:00
|
|
|
import json
|
2020-10-07 15:18:43 +00:00
|
|
|
import uuid
|
2020-05-17 10:08:13 +00:00
|
|
|
|
2020-10-07 15:18:43 +00:00
|
|
|
from datetime import date, datetime
|
|
|
|
from decimal import Decimal
|
|
|
|
from typing import Any, List, Optional
|
2020-05-14 16:19:22 +00:00
|
|
|
|
|
|
|
from brewman.schemas import to_camel
|
2020-05-23 04:15:02 +00:00
|
|
|
from brewman.schemas.master import (
|
|
|
|
AccountLink,
|
|
|
|
CostCentreLink,
|
|
|
|
EmployeeLink,
|
2020-10-07 15:18:43 +00:00
|
|
|
ProductLink,
|
2020-05-23 04:15:02 +00:00
|
|
|
)
|
2020-10-07 15:18:43 +00:00
|
|
|
from fastapi import Form
|
|
|
|
from pydantic import BaseModel, Field, validator
|
2020-05-08 04:52:25 +00:00
|
|
|
|
|
|
|
|
2020-05-29 20:28:17 +00:00
|
|
|
class ImageUpload(BaseModel):
|
|
|
|
id_: Optional[uuid.UUID]
|
|
|
|
resized: Optional[str]
|
|
|
|
thumbnail: Optional[str]
|
|
|
|
|
|
|
|
class Config:
|
|
|
|
alias_generator = to_camel
|
|
|
|
|
|
|
|
|
2020-05-21 07:41:47 +00:00
|
|
|
class UserLink(BaseModel):
|
|
|
|
id_: uuid.UUID
|
|
|
|
name: str
|
|
|
|
|
|
|
|
class Config:
|
|
|
|
alias_generator = to_camel
|
|
|
|
|
|
|
|
|
2020-05-17 10:08:13 +00:00
|
|
|
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]
|
2020-05-08 04:52:25 +00:00
|
|
|
|
2020-05-17 10:08:13 +00:00
|
|
|
class Config:
|
|
|
|
anystr_strip_whitespace = True
|
|
|
|
alias_generator = to_camel
|
2020-05-08 04:52:25 +00:00
|
|
|
|
2020-05-17 10:08:13 +00:00
|
|
|
|
2020-05-21 07:41:47 +00:00
|
|
|
class Batch(BaseModel):
|
2020-05-17 10:08:13 +00:00
|
|
|
id_: uuid.UUID
|
2020-05-21 07:41:47 +00:00
|
|
|
name: str
|
2020-05-17 10:08:13 +00:00
|
|
|
product: ProductLink
|
2020-05-21 07:41:47 +00:00
|
|
|
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]
|
2020-05-17 10:08:13 +00:00
|
|
|
quantity: Decimal = Field(ge=0, multiple_of=0.01)
|
|
|
|
rate: Decimal = Field(ge=0, multiple_of=0.01)
|
2020-05-21 07:41:47 +00:00
|
|
|
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]
|
2020-05-17 10:08:13 +00:00
|
|
|
|
|
|
|
class Config:
|
|
|
|
alias_generator = to_camel
|
2020-05-08 04:52:25 +00:00
|
|
|
|
|
|
|
|
2020-05-21 07:41:47 +00:00
|
|
|
class EmployeeBenefit(BaseModel):
|
2020-05-22 04:40:45 +00:00
|
|
|
id_: Optional[uuid.UUID]
|
2020-05-23 04:15:02 +00:00
|
|
|
employee: Optional[EmployeeLink]
|
2020-05-22 04:40:45 +00:00
|
|
|
gross_salary: int = Field(ge=0)
|
|
|
|
days_worked: int = Field(ge=0)
|
2020-05-23 04:15:02 +00:00
|
|
|
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)
|
2020-05-22 04:40:45 +00:00
|
|
|
|
|
|
|
class Config:
|
|
|
|
alias_generator = to_camel
|
2020-05-08 04:52:25 +00:00
|
|
|
|
|
|
|
|
2020-05-12 15:22:07 +00:00
|
|
|
class Incentive(BaseModel):
|
2020-05-23 04:15:02 +00:00
|
|
|
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
|
2020-05-08 04:52:25 +00:00
|
|
|
|
|
|
|
|
2020-05-21 07:41:47 +00:00
|
|
|
class VoucherIn(BaseModel):
|
|
|
|
date_: date
|
|
|
|
narration: str
|
|
|
|
is_starred: bool
|
|
|
|
type_: str
|
2020-05-29 20:28:17 +00:00
|
|
|
files: List[ImageUpload]
|
2020-05-21 07:41:47 +00:00
|
|
|
|
|
|
|
@classmethod
|
|
|
|
def load_form(cls, data: str = Form(...)):
|
|
|
|
json_data = json.loads(data)
|
|
|
|
return cls.parse_obj(json_data)
|
2020-05-08 04:52:25 +00:00
|
|
|
|
|
|
|
|
2020-05-21 07:41:47 +00:00
|
|
|
class Voucher(VoucherIn):
|
2020-05-17 10:08:13 +00:00
|
|
|
id_: Optional[uuid.UUID]
|
|
|
|
is_reconciled: Optional[bool]
|
|
|
|
reconcile_date: Optional[date]
|
|
|
|
creation_date: Optional[datetime]
|
|
|
|
last_edit_date: Optional[datetime]
|
2020-05-23 04:15:02 +00:00
|
|
|
user: Optional[UserLink]
|
2020-05-17 10:08:13 +00:00
|
|
|
posted: Optional[bool]
|
|
|
|
poster_id: Optional[uuid.UUID]
|
|
|
|
journals: List[Journal]
|
|
|
|
inventories: List[Inventory]
|
2020-05-21 07:41:47 +00:00
|
|
|
vendor: Optional[AccountLink]
|
2020-05-21 19:45:25 +00:00
|
|
|
source: Optional[CostCentreLink]
|
|
|
|
destination: Optional[CostCentreLink]
|
2020-05-23 04:15:02 +00:00
|
|
|
incentives: Optional[List[Incentive]]
|
|
|
|
incentive: Optional[Decimal]
|
|
|
|
employee_benefits: List[EmployeeBenefit]
|
2020-05-29 20:28:17 +00:00
|
|
|
files: List[ImageUpload]
|
2020-05-17 10:08:13 +00:00
|
|
|
|
|
|
|
class Config:
|
|
|
|
anystr_strip_whitespace = True
|
|
|
|
alias_generator = to_camel
|
|
|
|
json_encoders = {
|
|
|
|
date: lambda v: v.strftime("%d-%b-%Y"),
|
2020-05-23 04:15:02 +00:00
|
|
|
datetime: lambda v: v.strftime("%d-%b-%Y %H:%I"),
|
2020-05-17 10:08:13 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
@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
|
2020-05-23 04:15:02 +00:00
|
|
|
return datetime.strptime(value, "%d-%b-%Y").date()
|
2020-05-17 10:08:13 +00:00
|
|
|
|
2020-05-30 05:41:52 +00:00
|
|
|
# @validator("journals")
|
|
|
|
# def validate_enough_journals(cls, value: List[Journal]):
|
|
|
|
# if 0 < len(value) < 2:
|
|
|
|
# raise ValueError("Not enough journals")
|
|
|
|
# return value
|
|
|
|
#
|
2020-05-17 10:08:13 +00:00
|
|
|
@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]):
|
2020-05-23 04:15:02 +00:00
|
|
|
journal_set = set(
|
2020-10-07 16:59:24 +00:00
|
|
|
hash(x.account.id_)
|
|
|
|
^ hash(None if x.cost_centre is None else x.cost_centre.id_)
|
|
|
|
for x in value
|
2020-05-23 04:15:02 +00:00
|
|
|
)
|
2020-05-17 10:08:13 +00:00
|
|
|
if len(value) != len(journal_set):
|
|
|
|
raise ValueError("Duplicate journals")
|
|
|
|
return value
|
|
|
|
|
|
|
|
|
2020-05-12 15:22:07 +00:00
|
|
|
class AttendanceType(BaseModel):
|
|
|
|
id_: int
|
2020-05-14 16:19:22 +00:00
|
|
|
name: Optional[str]
|
|
|
|
value: Optional[Decimal]
|
|
|
|
|
|
|
|
class Config:
|
|
|
|
alias_generator = to_camel
|
2020-05-12 15:22:07 +00:00
|
|
|
|
|
|
|
|
|
|
|
class AttendanceItem(BaseModel):
|
2020-05-14 16:19:22 +00:00
|
|
|
id_: uuid.UUID
|
|
|
|
code: int
|
|
|
|
name: str
|
|
|
|
designation: str
|
|
|
|
department: str
|
2020-05-12 15:22:07 +00:00
|
|
|
attendance_type: AttendanceType
|
2020-05-14 16:19:22 +00:00
|
|
|
prints: str
|
|
|
|
hours_worked: str
|
|
|
|
full_day: Optional[bool]
|
2020-05-08 04:52:25 +00:00
|
|
|
|
2020-05-14 16:19:22 +00:00
|
|
|
class Config:
|
|
|
|
alias_generator = to_camel
|
2020-05-08 04:52:25 +00:00
|
|
|
|
2020-05-14 16:43:34 +00:00
|
|
|
|
|
|
|
class Attendance(BaseModel):
|
|
|
|
date_: Optional[date]
|
2020-05-12 15:22:07 +00:00
|
|
|
body: List[AttendanceItem]
|
|
|
|
|
2020-05-14 16:43:34 +00:00
|
|
|
@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")}
|
|
|
|
|
2020-05-12 15:22:07 +00:00
|
|
|
|
|
|
|
class EmployeeAttendanceItem(BaseModel):
|
2020-05-14 16:43:34 +00:00
|
|
|
date_: date
|
2020-05-12 15:22:07 +00:00
|
|
|
attendance_type: AttendanceType
|
2020-05-14 16:43:34 +00:00
|
|
|
prints: str
|
|
|
|
hours_worked: str
|
|
|
|
full_day: Optional[bool]
|
2020-05-12 15:22:07 +00:00
|
|
|
|
2020-05-14 16:43:34 +00:00
|
|
|
@validator("date_", pre=True)
|
|
|
|
def parse_date(cls, value):
|
|
|
|
if isinstance(value, date):
|
|
|
|
return value
|
|
|
|
return datetime.strptime(value, "%d-%b-%Y").date()
|
2020-05-12 15:22:07 +00:00
|
|
|
|
2020-05-14 16:43:34 +00:00
|
|
|
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]
|
2020-05-12 15:22:07 +00:00
|
|
|
body: List[EmployeeAttendanceItem]
|
|
|
|
|
2020-05-14 16:43:34 +00:00
|
|
|
@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")}
|
|
|
|
|
2020-05-12 15:22:07 +00:00
|
|
|
|
2020-05-08 04:52:25 +00:00
|
|
|
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
|
2020-05-12 15:22:07 +00:00
|
|
|
image: bytes
|
|
|
|
thumbnail: bytes
|
2020-05-08 04:52:25 +00:00
|
|
|
creation_date: datetime
|