Feature: Adding recipe templates to print recipes.
Feautre: Recipe export to xlsx Chore: Python 11 style type annotations Chore: Moved to sqlalchemy 2.0 Chore: Minimum python is 3.11 Fix: Fix nullability of a lot of fields in the database.
This commit is contained in:
1 parent
d2d26ab1ae
commit
22cac61761
344 files changed
+3247
-2370
No files matched your search
@@ -1,3 +1,4 @@
|
||||
[alembic]
|
||||
# path to migration scripts
|
||||
script_location = alembic
|
||||
prepend_sys_path = .
|
||||
@@ -2,6 +2,7 @@ import logging
|
||||
|
||||
from alembic import context
|
||||
from brewman.core.config import settings
|
||||
from brewman.db.base import reg
|
||||
from sqlalchemy import create_engine, pool
|
||||
|
||||
|
||||
@@ -12,10 +13,8 @@ logging.getLogger("alembic").setLevel(settings.ALEMBIC_LOG_LEVEL)
|
||||
# Interpret the config file for Python logging.
|
||||
# This line sets up loggers basically.
|
||||
|
||||
from brewman.db.base import User # noqa
|
||||
|
||||
|
||||
target_metadata = User.metadata
|
||||
target_metadata = reg.metadata
|
||||
|
||||
# other values from the config, defined by the needs of env.py,
|
||||
# can be acquired:
|
||||
|
||||
@@ -295,8 +295,8 @@ def upgrade():
|
||||
)
|
||||
op.create_table(
|
||||
"stock_keeping_units",
|
||||
sa.Column("id", postgresql.UUID(as_uuid=True), nullable=False),
|
||||
sa.Column("product_id", postgresql.UUID(as_uuid=True), nullable=False),
|
||||
sa.Column("id", postgresql.Uuid, nullable=False),
|
||||
sa.Column("product_id", postgresql.Uuid, nullable=False),
|
||||
sa.Column("units", sa.Unicode(length=255), nullable=False),
|
||||
sa.Column("fraction", sa.Numeric(precision=15, scale=5), nullable=False),
|
||||
sa.Column("product_yield", sa.Numeric(precision=15, scale=5), nullable=False),
|
||||
@@ -368,7 +368,7 @@ def upgrade():
|
||||
)
|
||||
op.create_table(
|
||||
"periods",
|
||||
sa.Column("id", postgresql.UUID(as_uuid=True), nullable=False),
|
||||
sa.Column("id", postgresql.Uuid, nullable=False),
|
||||
sa.Column("valid_from", sa.Date(), nullable=False),
|
||||
sa.Column("valid_till", sa.Date(), nullable=False),
|
||||
sa.PrimaryKeyConstraint("id", name=op.f("pk_periods")),
|
||||
@@ -392,7 +392,7 @@ def upgrade():
|
||||
sa.Column("cost_price", sa.Numeric(precision=15, scale=2), nullable=False),
|
||||
sa.Column("sale_price", sa.Numeric(precision=15, scale=2), nullable=False),
|
||||
sa.Column("notes", sa.Unicode(length=255), nullable=True),
|
||||
sa.Column("period_id", postgresql.UUID(as_uuid=True), nullable=False),
|
||||
sa.Column("period_id", postgresql.Uuid, nullable=False),
|
||||
sa.ForeignKeyConstraint(
|
||||
["sku_id"],
|
||||
["stock_keeping_units.id"],
|
||||
@@ -493,13 +493,13 @@ def upgrade():
|
||||
)
|
||||
op.create_table(
|
||||
"rate_contracts",
|
||||
sa.Column("id", postgresql.UUID(as_uuid=True), nullable=False),
|
||||
sa.Column("id", postgresql.Uuid, nullable=False),
|
||||
sa.Column("date", sa.Date(), nullable=False),
|
||||
sa.Column("vendor_id", postgresql.UUID(as_uuid=True), nullable=False),
|
||||
sa.Column("vendor_id", postgresql.Uuid, nullable=False),
|
||||
sa.Column("valid_from", sa.Date(), nullable=True),
|
||||
sa.Column("valid_till", sa.Date(), nullable=True),
|
||||
sa.Column("narration", sa.Unicode(length=1000), nullable=False),
|
||||
sa.Column("user_id", postgresql.UUID(as_uuid=True), nullable=False),
|
||||
sa.Column("user_id", postgresql.Uuid, nullable=False),
|
||||
sa.Column("creation_date", sa.DateTime(), nullable=False),
|
||||
sa.Column("last_edit_date", sa.DateTime(), nullable=False),
|
||||
sa.ForeignKeyConstraint(["user_id"], ["users.id"], name=op.f("fk_rate_contracts_user_id_users")),
|
||||
@@ -509,9 +509,9 @@ def upgrade():
|
||||
op.create_index(op.f("ix_rate_contracts_date"), "rate_contracts", ["date"], unique=False)
|
||||
op.create_table(
|
||||
"rate_contract_items",
|
||||
sa.Column("id", postgresql.UUID(as_uuid=True), nullable=False),
|
||||
sa.Column("rate_contract_id", postgresql.UUID(as_uuid=True), nullable=False),
|
||||
sa.Column("sku_id", postgresql.UUID(as_uuid=True), nullable=False),
|
||||
sa.Column("id", postgresql.Uuid, nullable=False),
|
||||
sa.Column("rate_contract_id", postgresql.Uuid, nullable=False),
|
||||
sa.Column("sku_id", postgresql.Uuid, nullable=False),
|
||||
sa.Column("cost_price", sa.Numeric(precision=15, scale=2), nullable=False),
|
||||
sa.ForeignKeyConstraint(
|
||||
["sku_id"], ["stock_keeping_units.id"], name=op.f("fk_rate_contract_items_sku_id_stock_keeping_units")
|
||||
@@ -529,10 +529,10 @@ def upgrade():
|
||||
)
|
||||
op.create_table(
|
||||
"closing_stocks",
|
||||
sa.Column("id", postgresql.UUID(as_uuid=True), nullable=False),
|
||||
sa.Column("id", postgresql.Uuid, nullable=False),
|
||||
sa.Column("date", sa.Date(), nullable=False),
|
||||
sa.Column("cost_centre_id", postgresql.UUID(as_uuid=True), nullable=False),
|
||||
sa.Column("sku_id", postgresql.UUID(as_uuid=True), nullable=False),
|
||||
sa.Column("cost_centre_id", postgresql.Uuid, nullable=False),
|
||||
sa.Column("sku_id", postgresql.Uuid, nullable=False),
|
||||
sa.Column("quantity", sa.Numeric(precision=15, scale=2), nullable=False),
|
||||
sa.ForeignKeyConstraint(
|
||||
["cost_centre_id"], ["cost_centres.id"], name=op.f("fk_closing_stocks_cost_centre_id_cost_centres")
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
"""recipe templates
|
||||
|
||||
Revision ID: 12262aadbc08
|
||||
Revises: a1372ed99c45
|
||||
Create Date: 2023-04-14 07:50:22.110724
|
||||
|
||||
"""
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
from sqlalchemy.dialects import postgresql
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
revision = '12262aadbc08'
|
||||
down_revision = 'a1372ed99c45'
|
||||
branch_labels = None
|
||||
depends_on = None
|
||||
|
||||
|
||||
def upgrade():
|
||||
# ### commands auto generated by Alembic - please adjust! ###
|
||||
op.create_table('recipe_templates',
|
||||
sa.Column('id', sa.Uuid(), nullable=False),
|
||||
sa.Column('name', sa.Unicode(), nullable=False),
|
||||
sa.Column('date', sa.Date(), nullable=False),
|
||||
sa.Column('text', sa.Unicode(), nullable=False),
|
||||
sa.Column('selected', sa.Boolean(), nullable=False),
|
||||
sa.PrimaryKeyConstraint('id', name=op.f('pk_recipe_templates')),
|
||||
sa.UniqueConstraint('name', name=op.f('uq_recipe_templates_name'))
|
||||
)
|
||||
op.create_index('only_one_selected_template', 'recipe_templates', ['selected'], unique=True, postgresql_where=sa.text('selected = true'))
|
||||
op.alter_column('recipes', 'notes',
|
||||
existing_type=sa.VARCHAR(length=255),
|
||||
type_=sa.Text(),
|
||||
existing_nullable=False)
|
||||
# ### end Alembic commands ###
|
||||
|
||||
|
||||
def downgrade():
|
||||
# ### commands auto generated by Alembic - please adjust! ###
|
||||
op.alter_column('recipes', 'notes',
|
||||
existing_type=sa.Text(),
|
||||
type_=sa.VARCHAR(length=255),
|
||||
existing_nullable=False)
|
||||
op.drop_index('only_one_selected_template', table_name='recipe_templates', postgresql_where=sa.text('selected = true'))
|
||||
op.drop_table('recipe_templates')
|
||||
# ### end Alembic commands ###
|
||||
@@ -329,14 +329,14 @@ def add_all_permissions_to_owner():
|
||||
r = table("roles", column("id", postgresql.UUID()), column("name", sa.String))
|
||||
p = table(
|
||||
"permissions",
|
||||
column("id", postgresql.UUID(as_uuid=True)),
|
||||
column("id", postgresql.Uuid),
|
||||
column("name", sa.Unicode(length=255)),
|
||||
)
|
||||
rp = table(
|
||||
"role_permissions",
|
||||
column("id", postgresql.UUID(as_uuid=True)),
|
||||
column("permission_id", postgresql.UUID(as_uuid=True)),
|
||||
column("role_id", postgresql.UUID(as_uuid=True)),
|
||||
column("id", postgresql.Uuid),
|
||||
column("permission_id", postgresql.Uuid),
|
||||
column("role_id", postgresql.Uuid),
|
||||
)
|
||||
op.execute(
|
||||
insert(rp).from_select(
|
||||
@@ -357,9 +357,9 @@ def add_all_roles_to_admin():
|
||||
r = table("roles", column("id", postgresql.UUID()), column("name", sa.String))
|
||||
ur = table(
|
||||
"user_roles",
|
||||
column("id", postgresql.UUID(as_uuid=True)),
|
||||
column("user_id", postgresql.UUID(as_uuid=True)),
|
||||
column("role_id", postgresql.UUID(as_uuid=True)),
|
||||
column("id", postgresql.Uuid),
|
||||
column("user_id", postgresql.Uuid),
|
||||
column("role_id", postgresql.Uuid),
|
||||
)
|
||||
op.execute(
|
||||
insert(ur).from_select(
|
||||
|
||||
@@ -0,0 +1,174 @@
|
||||
"""Recipe upgrade
|
||||
|
||||
Revision ID: a1372ed99c45
|
||||
Revises: 185c674cc392
|
||||
Create Date: 2023-03-31 05:03:40.408240
|
||||
|
||||
"""
|
||||
import sqlalchemy as sa
|
||||
|
||||
from alembic import op
|
||||
from sqlalchemy.dialects import postgresql
|
||||
from sqlalchemy import func
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
revision = "a1372ed99c45"
|
||||
down_revision = "185c674cc392"
|
||||
branch_labels = None
|
||||
depends_on = None
|
||||
|
||||
|
||||
def upgrade():
|
||||
# ### commands auto generated by Alembic - please adjust! ###
|
||||
op.create_table(
|
||||
"tags",
|
||||
sa.Column("id", sa.Uuid(), nullable=False),
|
||||
sa.Column("name", sa.Unicode(), nullable=False),
|
||||
sa.PrimaryKeyConstraint("id", name=op.f("pk_tags")),
|
||||
sa.UniqueConstraint("name", name=op.f("uq_tags_name")),
|
||||
)
|
||||
op.create_table(
|
||||
"recipe_tags",
|
||||
sa.Column("id", sa.Uuid(), nullable=False),
|
||||
sa.Column("recipe_id", sa.Uuid(), nullable=False),
|
||||
sa.Column("tag_id", sa.Uuid(), nullable=False),
|
||||
sa.ForeignKeyConstraint(["recipe_id"], ["recipes.id"], name=op.f("fk_recipe_tags_recipe_id_recipes")),
|
||||
sa.ForeignKeyConstraint(["tag_id"], ["tags.id"], name=op.f("fk_recipe_tags_tag_id_tags")),
|
||||
sa.PrimaryKeyConstraint("id", name=op.f("pk_recipe_tags")),
|
||||
sa.UniqueConstraint("recipe_id", "tag_id", name=op.f("uq_recipe_tags_recipe_id")),
|
||||
)
|
||||
op.alter_column("attendances", "employee_id", existing_type=sa.UUID(), nullable=False)
|
||||
op.alter_column("attendances", "attendance_type", existing_type=sa.INTEGER(), nullable=False)
|
||||
op.alter_column("attendances", "amount", existing_type=sa.NUMERIC(precision=5, scale=2), nullable=False)
|
||||
op.alter_column("attendances", "creation_date", existing_type=postgresql.TIMESTAMP(), nullable=False)
|
||||
op.alter_column("attendances", "user_id", existing_type=sa.UUID(), nullable=False)
|
||||
op.alter_column("attendances", "is_valid", existing_type=sa.BOOLEAN(), nullable=False)
|
||||
op.alter_column("cost_centres", "name", existing_type=sa.VARCHAR(length=255), nullable=False)
|
||||
op.alter_column("employee_benefit", "gross_salary", existing_type=sa.INTEGER(), nullable=False)
|
||||
op.alter_column("employee_benefit", "days_worked", existing_type=sa.INTEGER(), nullable=False)
|
||||
op.alter_column("employee_benefit", "esi_employee", existing_type=sa.INTEGER(), nullable=False)
|
||||
op.alter_column("employee_benefit", "pf_employee", existing_type=sa.INTEGER(), nullable=False)
|
||||
op.alter_column("employee_benefit", "esi_employer", existing_type=sa.INTEGER(), nullable=False)
|
||||
op.alter_column("employee_benefit", "pf_employer", existing_type=sa.INTEGER(), nullable=False)
|
||||
op.alter_column("fingerprints", "employee_id", existing_type=sa.UUID(), nullable=False)
|
||||
op.alter_column("fingerprints", "date", existing_type=postgresql.TIMESTAMP(), nullable=False)
|
||||
op.alter_column("permissions", "name", existing_type=sa.VARCHAR(length=255), nullable=False)
|
||||
op.alter_column("product_groups", "name", existing_type=sa.VARCHAR(length=255), nullable=False)
|
||||
op.add_column("products", sa.Column("description", sa.Text(), nullable=True))
|
||||
op.alter_column("products", "code", existing_type=sa.INTEGER(), nullable=False)
|
||||
op.add_column("recipes", sa.Column("date", sa.Date(), nullable=False, server_default=func.now()))
|
||||
op.add_column("recipes", sa.Column("source", sa.Text(), nullable=False, server_default=""))
|
||||
op.add_column("recipes", sa.Column("instructions", sa.Text(), nullable=False, server_default=""))
|
||||
op.add_column("recipes", sa.Column("garnishing", sa.Text(), nullable=False, server_default=""))
|
||||
op.add_column("recipes", sa.Column("plating", sa.Text(), nullable=False, server_default=""))
|
||||
op.alter_column("recipes", "notes", existing_type=sa.VARCHAR(length=255),type=sa.Text(), nullable=False)
|
||||
op.create_unique_constraint(op.f('uq_recipes_sku_id'), 'recipes', ['sku_id', 'date'])
|
||||
op.create_index(op.f("ix_recipes_date"), "recipes", ["date"], unique=False)
|
||||
op.drop_constraint(op.f("uq_recipes_sku_id"), "recipes", type_="unique")
|
||||
op.drop_constraint("fk_recipes_period_id_periods", "recipes", type_="foreignkey")
|
||||
op.drop_column("recipes", "period_id")
|
||||
op.drop_column('recipes', 'sale_price')
|
||||
op.drop_column('recipes', 'cost_price')
|
||||
op.add_column('recipe_items', sa.Column('description', sa.Text(), nullable=False, server_default=""))
|
||||
op.drop_column('recipe_items', 'price')
|
||||
op.alter_column("role_permissions", "permission_id", existing_type=sa.UUID(), nullable=False)
|
||||
op.alter_column("role_permissions", "role_id", existing_type=sa.UUID(), nullable=False)
|
||||
op.create_unique_constraint(
|
||||
op.f("uq_role_permissions_permission_id"), "role_permissions", ["permission_id", "role_id"]
|
||||
)
|
||||
op.alter_column("roles", "name", existing_type=sa.VARCHAR(length=255), nullable=False)
|
||||
op.alter_column("settings", "data", existing_type=postgresql.BYTEA(), nullable=False)
|
||||
op.alter_column("user_roles", "user_id", existing_type=sa.UUID(), nullable=False)
|
||||
op.alter_column("user_roles", "role_id", existing_type=sa.UUID(), nullable=False)
|
||||
op.create_unique_constraint(op.f("uq_user_roles_user_id"), "user_roles", ["user_id", "role_id"])
|
||||
op.alter_column("users", "username", existing_type=sa.VARCHAR(length=255), nullable=False)
|
||||
op.alter_column("users", "password", existing_type=sa.VARCHAR(length=60), nullable=False)
|
||||
op.alter_column("users", "disabled", existing_type=sa.BOOLEAN(), nullable=False)
|
||||
# ### end Alembic commands ###
|
||||
|
||||
|
||||
def downgrade():
|
||||
# ### commands auto generated by Alembic - please adjust! ###
|
||||
op.alter_column(
|
||||
"vouchers",
|
||||
"voucher_type",
|
||||
existing_type=sa.Enum(
|
||||
"JOURNAL",
|
||||
"PURCHASE",
|
||||
"ISSUE",
|
||||
"PAYMENT",
|
||||
"RECEIPT",
|
||||
"PURCHASE_RETURN",
|
||||
"OPENING_ACCOUNTS",
|
||||
"OPENING_BATCHES",
|
||||
"CLOSING_STOCK",
|
||||
"OPENING_BALANCE",
|
||||
"CLOSING_BALANCE",
|
||||
"EMPLOYEE_BENEFIT",
|
||||
"INCENTIVE",
|
||||
name="vouchertype",
|
||||
),
|
||||
type_=postgresql.ENUM(
|
||||
"JOURNAL",
|
||||
"PURCHASE",
|
||||
"ISSUE",
|
||||
"PAYMENT",
|
||||
"RECEIPT",
|
||||
"PURCHASE_RETURN",
|
||||
"OPENING_ACCOUNTS",
|
||||
"OPENING_BATCHES",
|
||||
"CLOSING_STOCK",
|
||||
"OPENING_BALANCE",
|
||||
"CLOSING_BALANCE",
|
||||
"EMPLOYEE_BENEFIT",
|
||||
"INCENTIVE",
|
||||
name="voucher_type",
|
||||
),
|
||||
existing_nullable=False,
|
||||
)
|
||||
op.alter_column("users", "disabled", existing_type=sa.BOOLEAN(), nullable=True)
|
||||
op.alter_column("users", "username", existing_type=sa.VARCHAR(length=255), nullable=True)
|
||||
op.drop_constraint(op.f("uq_user_roles_user_id"), "user_roles", type_="unique")
|
||||
op.alter_column("user_roles", "role_id", existing_type=sa.UUID(), nullable=True)
|
||||
op.alter_column("user_roles", "user_id", existing_type=sa.UUID(), nullable=True)
|
||||
op.alter_column(
|
||||
"settings",
|
||||
"setting_type",
|
||||
existing_type=sa.Enum("VOUCHER_LOCK", "MAINTENANCE_MODE", name="settingtype"),
|
||||
type_=postgresql.ENUM("VOUCHER_LOCK", name="setting_type"),
|
||||
existing_nullable=False,
|
||||
)
|
||||
op.alter_column("settings", "data", existing_type=postgresql.BYTEA(), nullable=True)
|
||||
op.alter_column("roles", "name", existing_type=sa.VARCHAR(length=255), nullable=True)
|
||||
op.drop_constraint(op.f("uq_role_permissions_permission_id"), "role_permissions", type_="unique")
|
||||
op.alter_column("role_permissions", "role_id", existing_type=sa.UUID(), nullable=True)
|
||||
op.alter_column("role_permissions", "permission_id", existing_type=sa.UUID(), nullable=True)
|
||||
op.drop_index(op.f("ix_recipes_date"), table_name="recipes")
|
||||
op.alter_column("recipes", "notes", existing_type=sa.VARCHAR(length=255), nullable=True)
|
||||
op.drop_column("recipes", "plating")
|
||||
op.drop_column("recipes", "garnishing")
|
||||
op.drop_column("recipes", "instructions")
|
||||
op.drop_column("recipes", "source")
|
||||
op.drop_column("recipes", "date")
|
||||
op.alter_column("products", "code", existing_type=sa.INTEGER(), nullable=True)
|
||||
op.drop_column("products", "description")
|
||||
op.alter_column("product_groups", "name", existing_type=sa.VARCHAR(length=255), nullable=True)
|
||||
op.alter_column("permissions", "name", existing_type=sa.VARCHAR(length=255), nullable=True)
|
||||
op.alter_column("fingerprints", "date", existing_type=postgresql.TIMESTAMP(), nullable=True)
|
||||
op.alter_column("fingerprints", "employee_id", existing_type=sa.UUID(), nullable=True)
|
||||
op.alter_column("employee_benefit", "pf_employer", existing_type=sa.INTEGER(), nullable=True)
|
||||
op.alter_column("employee_benefit", "esi_employer", existing_type=sa.INTEGER(), nullable=True)
|
||||
op.alter_column("employee_benefit", "pf_employee", existing_type=sa.INTEGER(), nullable=True)
|
||||
op.alter_column("employee_benefit", "esi_employee", existing_type=sa.INTEGER(), nullable=True)
|
||||
op.alter_column("employee_benefit", "days_worked", existing_type=sa.INTEGER(), nullable=True)
|
||||
op.alter_column("employee_benefit", "gross_salary", existing_type=sa.INTEGER(), nullable=True)
|
||||
op.alter_column("cost_centres", "name", existing_type=sa.VARCHAR(length=255), nullable=True)
|
||||
op.alter_column("attendances", "is_valid", existing_type=sa.BOOLEAN(), nullable=True)
|
||||
op.alter_column("attendances", "user_id", existing_type=sa.UUID(), nullable=True)
|
||||
op.alter_column("attendances", "creation_date", existing_type=postgresql.TIMESTAMP(), nullable=True)
|
||||
op.alter_column("attendances", "amount", existing_type=sa.NUMERIC(precision=5, scale=2), nullable=True)
|
||||
op.alter_column("attendances", "attendance_type", existing_type=sa.INTEGER(), nullable=True)
|
||||
op.alter_column("attendances", "employee_id", existing_type=sa.UUID(), nullable=True)
|
||||
op.drop_table("recipe_tags")
|
||||
op.drop_table("tags")
|
||||
# ### end Alembic commands ###
|
||||
@@ -1,6 +1,6 @@
|
||||
import secrets
|
||||
|
||||
from typing import Any, Dict, Optional
|
||||
from typing import Any
|
||||
|
||||
from dotenv import load_dotenv
|
||||
from pydantic import BaseSettings, PostgresDsn, validator
|
||||
@@ -20,10 +20,10 @@ class Settings(BaseSettings):
|
||||
POSTGRES_USER: str = "postgres"
|
||||
POSTGRES_PASSWORD: str = ""
|
||||
POSTGRES_DB: str = ""
|
||||
SQLALCHEMY_DATABASE_URI: Optional[str] = None
|
||||
SQLALCHEMY_DATABASE_URI: str | None = None
|
||||
|
||||
@validator("SQLALCHEMY_DATABASE_URI", pre=True)
|
||||
def assemble_db_connection(cls, v: Optional[str], values: Dict[str, Any]) -> Any:
|
||||
def assemble_db_connection(cls, v: str | None, values: dict[str, Any]) -> Any:
|
||||
if isinstance(v, str):
|
||||
return v
|
||||
return PostgresDsn.build(
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import uuid
|
||||
|
||||
from datetime import datetime, timedelta
|
||||
from typing import List, Optional, Tuple
|
||||
|
||||
from fastapi import Depends, HTTPException, Security, status
|
||||
from fastapi.security import OAuth2PasswordBearer, SecurityScopes
|
||||
@@ -30,7 +29,7 @@ class Token(BaseModel):
|
||||
|
||||
class TokenData(BaseModel):
|
||||
username: str
|
||||
scopes: List[str] = []
|
||||
scopes: list[str] = []
|
||||
|
||||
|
||||
def f7(seq):
|
||||
@@ -50,7 +49,7 @@ def create_access_token(*, data: dict, expires_delta: timedelta = None):
|
||||
return encoded_jwt
|
||||
|
||||
|
||||
def get_user(username: str, id_: str, locked_out: bool, scopes: List[str]) -> UserToken:
|
||||
def get_user(username: str, id_: str, locked_out: bool, scopes: list[str]) -> UserToken:
|
||||
return UserToken(
|
||||
id_=uuid.UUID(id_),
|
||||
name=username,
|
||||
@@ -60,13 +59,13 @@ def get_user(username: str, id_: str, locked_out: bool, scopes: List[str]) -> Us
|
||||
)
|
||||
|
||||
|
||||
def authenticate_user(username: str, password: str, db: Session) -> Optional[UserModel]:
|
||||
def authenticate_user(username: str, password: str, db: Session) -> UserModel | None:
|
||||
user = UserModel.auth(username, password, db)
|
||||
return user
|
||||
|
||||
|
||||
def client_allowed(user: UserModel, client_id: int, otp: Optional[int], db: Session) -> Tuple[bool, Client]:
|
||||
client: Optional[Client] = (
|
||||
def client_allowed(user: UserModel, client_id: int, otp: int | None, db: Session) -> tuple[bool, Client]:
|
||||
client: Client | None = (
|
||||
db.execute(select(Client).where(Client.code == client_id)).scalar_one_or_none() if client_id else None
|
||||
)
|
||||
if client is None:
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
from datetime import date, timedelta
|
||||
from typing import Union
|
||||
|
||||
|
||||
def get_date(session: dict) -> str:
|
||||
@@ -8,7 +7,7 @@ def get_date(session: dict) -> str:
|
||||
return session["date"] # type: ignore[no-any-return]
|
||||
|
||||
|
||||
def set_date(date_: Union[str, date], session: dict) -> None:
|
||||
def set_date(date_: str | date, session: dict) -> None:
|
||||
session["date"] = date_ if isinstance(date_, str) else date_.strftime("%d-%b-%Y")
|
||||
|
||||
|
||||
@@ -24,7 +23,7 @@ def get_finish_date(session: dict) -> str:
|
||||
return session["finish"] # type: ignore[no-any-return]
|
||||
|
||||
|
||||
def set_period(start: Union[str, date], finish: Union[str, date], session: dict) -> None:
|
||||
def set_period(start: str | date, finish: str | date, session: dict) -> None:
|
||||
if start is not None:
|
||||
session["start"] = start if isinstance(start, str) else start.strftime("%d-%b-%Y")
|
||||
if finish is not None:
|
||||
|
||||
@@ -25,11 +25,14 @@ from ..models.rate_contract import RateContract # noqa: F401
|
||||
from ..models.rate_contract_item import RateContractItem # noqa: F401
|
||||
from ..models.recipe import Recipe # noqa: F401
|
||||
from ..models.recipe_item import RecipeItem # noqa: F401
|
||||
from ..models.recipe_tag import RecipeTag # noqa: F401
|
||||
from ..models.recipe_template import RecipeTemplate # noqa: F401
|
||||
from ..models.role import Role # noqa: F401
|
||||
from ..models.role_permission import role_permission # noqa: F401
|
||||
from ..models.role_permission import RolePermission # noqa: F401
|
||||
from ..models.stock_keeping_unit import StockKeepingUnit # noqa: F401
|
||||
from ..models.tag import Tag # noqa: F401
|
||||
from ..models.user import User # noqa: F401
|
||||
from ..models.user_role import user_role # noqa: F401
|
||||
from ..models.user_role import UserRole # noqa: F401
|
||||
from ..models.voucher import Voucher # noqa: F401
|
||||
from ..models.voucher_type import VoucherType # noqa: F401
|
||||
from .base_class import Base # noqa: F401
|
||||
from .base_class import reg # noqa: F401
|
||||
@@ -1,4 +1,4 @@
|
||||
from sqlalchemy.ext.declarative import declarative_base
|
||||
from sqlalchemy.orm import registry
|
||||
from sqlalchemy.schema import MetaData
|
||||
|
||||
|
||||
@@ -14,4 +14,5 @@ NAMING_CONVENTION = {
|
||||
}
|
||||
|
||||
metadata = MetaData(naming_convention=NAMING_CONVENTION)
|
||||
Base = declarative_base(metadata=metadata)
|
||||
reg = registry()
|
||||
reg.metadata = metadata
|
||||
@@ -4,7 +4,7 @@ from fastapi import FastAPI
|
||||
from starlette.middleware.sessions import SessionMiddleware
|
||||
|
||||
from .core.config import settings
|
||||
from .db.base import Base # noqa: F401
|
||||
from .db.base import reg # noqa: F401
|
||||
from .routers import (
|
||||
account,
|
||||
account_types,
|
||||
@@ -38,6 +38,7 @@ from .routers import (
|
||||
rate_contract,
|
||||
rebase,
|
||||
recipe,
|
||||
recipe_template,
|
||||
role,
|
||||
user,
|
||||
voucher,
|
||||
@@ -86,6 +87,7 @@ app.include_router(fingerprint.router, prefix="/api/fingerprint", tags=["employe
|
||||
app.include_router(product.router, prefix="/api/products", tags=["products"])
|
||||
app.include_router(product_group.router, prefix="/api/product-groups", tags=["products"])
|
||||
app.include_router(recipe.router, prefix="/api/recipes", tags=["products"])
|
||||
app.include_router(recipe_template.router, prefix="/api/recipe-templates", tags=["products"])
|
||||
app.include_router(period.router, prefix="/api/periods", tags=["periods"])
|
||||
|
||||
app.include_router(client.router, prefix="/api/clients", tags=["clients"])
|
||||
|
||||
@@ -1,24 +1,24 @@
|
||||
from typing import TYPE_CHECKING, List, Tuple
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from sqlalchemy.orm import relationship
|
||||
from sqlalchemy.orm import Mapped, relationship
|
||||
|
||||
from ..db.base_class import reg
|
||||
from .account_base import AccountBase
|
||||
|
||||
|
||||
if TYPE_CHECKING:
|
||||
# if the target of the relationship is in another module
|
||||
# that cannot normally be imported at runtime
|
||||
from .product import Product
|
||||
|
||||
|
||||
@reg.mapped_as_dataclass(unsafe_hash=True)
|
||||
class Account(AccountBase):
|
||||
__mapper_args__ = {"polymorphic_identity": ""} # type: ignore
|
||||
|
||||
products: List["Product"] = relationship(
|
||||
products: Mapped[list["Product"]] = relationship(
|
||||
"Product", primaryjoin="Account.id==Product.account_id", back_populates="account"
|
||||
)
|
||||
|
||||
def can_delete(self, advanced_delete: bool) -> Tuple[bool, str]:
|
||||
def can_delete(self, advanced_delete: bool) -> tuple[bool, str]:
|
||||
if len(self.products) > 0:
|
||||
return False, "Account has products"
|
||||
return super(Account, self).can_delete(advanced_delete)
|
||||
@@ -1,57 +1,50 @@
|
||||
import uuid
|
||||
|
||||
from typing import TYPE_CHECKING, List, Optional, Tuple
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from sqlalchemy import Boolean, Column, ForeignKey, Integer, Unicode, func, select
|
||||
from sqlalchemy.dialects.postgresql import UUID
|
||||
from sqlalchemy.orm import Mapped, Session, relationship
|
||||
from sqlalchemy import Boolean, ForeignKey, Integer, Unicode, Uuid, func, select
|
||||
from sqlalchemy.orm import Mapped, Session, mapped_column, relationship
|
||||
|
||||
from ..db.base_class import Base
|
||||
from ..db.base_class import reg
|
||||
from ..schemas.account import AccountLink
|
||||
from .account_type import AccountType
|
||||
|
||||
|
||||
if TYPE_CHECKING:
|
||||
# if the target of the relationship is in another module
|
||||
# that cannot normally be imported at runtime
|
||||
from .cost_centre import CostCentre
|
||||
from .journal import Journal
|
||||
from .product import Product
|
||||
from .rate_contract import RateContract
|
||||
|
||||
|
||||
class AccountBase(Base):
|
||||
@reg.mapped_as_dataclass(unsafe_hash=True)
|
||||
class AccountBase:
|
||||
__tablename__ = "accounts"
|
||||
|
||||
id: uuid.UUID = Column("id", UUID(as_uuid=True), primary_key=True, default=uuid.uuid4)
|
||||
code: int = Column("code", Integer, nullable=False)
|
||||
name: str = Column("name", Unicode(255), unique=True, nullable=False)
|
||||
type_id: int = Column("type", Integer, ForeignKey("account_types.id"), nullable=False)
|
||||
account_type: str = Column("account_type", Unicode(50), nullable=False)
|
||||
is_starred: bool = Column("is_starred", Boolean, nullable=False)
|
||||
is_active: bool = Column("is_active", Boolean, nullable=False)
|
||||
is_reconcilable: bool = Column("is_reconcilable", Boolean, nullable=False)
|
||||
cost_centre_id: uuid.UUID = Column(
|
||||
"cost_centre_id",
|
||||
UUID(as_uuid=True),
|
||||
id: Mapped[uuid.UUID] = mapped_column(Uuid, primary_key=True, insert_default=uuid.uuid4)
|
||||
code: Mapped[int] = mapped_column(Integer, nullable=False)
|
||||
name: Mapped[str] = mapped_column(Unicode, unique=True, nullable=False)
|
||||
type_id: Mapped[int] = mapped_column("type", Integer, ForeignKey("account_types.id"), nullable=False)
|
||||
account_type: Mapped[str] = mapped_column(Unicode, nullable=False)
|
||||
is_starred: Mapped[bool] = mapped_column(Boolean, nullable=False)
|
||||
is_active: Mapped[bool] = mapped_column(Boolean, nullable=False)
|
||||
is_reconcilable: Mapped[bool] = mapped_column(Boolean, nullable=False)
|
||||
cost_centre_id: Mapped[uuid.UUID] = mapped_column(
|
||||
Uuid,
|
||||
ForeignKey("cost_centres.id"),
|
||||
nullable=False,
|
||||
)
|
||||
is_fixture: bool = Column("is_fixture", Boolean, nullable=False)
|
||||
is_fixture: Mapped[bool] = mapped_column(Boolean, nullable=False)
|
||||
|
||||
__mapper_args__ = {"polymorphic_on": account_type}
|
||||
|
||||
type_: AccountType = relationship("AccountType")
|
||||
type_: Mapped[AccountType] = relationship("AccountType", back_populates="accounts")
|
||||
|
||||
journals: List["Journal"] = relationship("Journal", back_populates="account")
|
||||
journals: Mapped[list["Journal"]] = relationship("Journal", back_populates="account")
|
||||
cost_centre: Mapped["CostCentre"] = relationship("CostCentre", back_populates="accounts")
|
||||
products: List["Product"] = relationship("Product", back_populates="account")
|
||||
products: Mapped[list["Product"]] = relationship("Product", back_populates="account")
|
||||
|
||||
rate_contracts: List["RateContract"] = relationship("RateContract", back_populates="vendor")
|
||||
|
||||
@property
|
||||
def __name__(self) -> str:
|
||||
return self.name
|
||||
rate_contracts: Mapped[list["RateContract"]] = relationship("RateContract", back_populates="vendor")
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
@@ -61,8 +54,8 @@ class AccountBase(Base):
|
||||
is_active: bool,
|
||||
is_reconcilable: bool,
|
||||
cost_centre_id: uuid.UUID,
|
||||
code: Optional[int] = None,
|
||||
id_: Optional[uuid.UUID] = None,
|
||||
code: int | None = None,
|
||||
id_: uuid.UUID | None = None,
|
||||
is_fixture: bool = False,
|
||||
) -> None:
|
||||
if code is not None:
|
||||
@@ -84,7 +77,7 @@ class AccountBase(Base):
|
||||
db.add(self)
|
||||
return self
|
||||
|
||||
def can_delete(self, advanced_delete: bool) -> Tuple[bool, str]:
|
||||
def can_delete(self, advanced_delete: bool) -> tuple[bool, str]:
|
||||
if self.is_fixture:
|
||||
return False, f"{self.name} is a fixture and cannot be edited or deleted."
|
||||
if self.is_active:
|
||||
|
||||
@@ -1,15 +1,27 @@
|
||||
from sqlalchemy import Boolean, Column, Integer, Unicode
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from ..db.base_class import Base
|
||||
from sqlalchemy import Boolean, Integer, Unicode
|
||||
from sqlalchemy.orm import Mapped, mapped_column, relationship
|
||||
|
||||
from ..db.base_class import reg
|
||||
|
||||
|
||||
class AccountType(Base):
|
||||
if TYPE_CHECKING:
|
||||
# if the target of the relationship is in another module
|
||||
# that cannot normally be imported at runtime
|
||||
from .account import AccountBase
|
||||
|
||||
|
||||
@reg.mapped_as_dataclass(unsafe_hash=True)
|
||||
class AccountType:
|
||||
__tablename__ = "account_types"
|
||||
|
||||
id: int = Column("id", Integer, primary_key=True)
|
||||
name: str = Column("name", Unicode(255), unique=True, nullable=False)
|
||||
balance_sheet: bool = Column("balance_sheet", Boolean, nullable=False)
|
||||
debit: bool = Column("debit", Boolean, nullable=False)
|
||||
cash_flow_classification: str = Column("cash_flow_classification", Unicode(255), nullable=False)
|
||||
order: int = Column("order", Integer, nullable=False)
|
||||
show_in_list: bool = Column("show_in_list", Boolean, nullable=False)
|
||||
id: Mapped[int] = mapped_column(Integer, primary_key=True)
|
||||
name: Mapped[str] = mapped_column(Unicode, unique=True, nullable=False)
|
||||
balance_sheet: Mapped[bool] = mapped_column(Boolean, nullable=False)
|
||||
debit: Mapped[bool] = mapped_column(Boolean, nullable=False)
|
||||
cash_flow_classification: Mapped[str] = mapped_column(Unicode, nullable=False)
|
||||
order: Mapped[int] = mapped_column(Integer, nullable=False)
|
||||
show_in_list: Mapped[bool] = mapped_column(Boolean, nullable=False)
|
||||
|
||||
accounts: Mapped[list["AccountBase"]] = relationship("AccountBase", back_populates="type_")
|
||||
@@ -2,23 +2,22 @@ import datetime
|
||||
import uuid
|
||||
|
||||
from decimal import Decimal
|
||||
from typing import TYPE_CHECKING, Optional
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from sqlalchemy import (
|
||||
Boolean,
|
||||
Column,
|
||||
Date,
|
||||
DateTime,
|
||||
ForeignKey,
|
||||
Index,
|
||||
Integer,
|
||||
Numeric,
|
||||
Uuid,
|
||||
select,
|
||||
)
|
||||
from sqlalchemy.dialects.postgresql import UUID
|
||||
from sqlalchemy.orm import Mapped, Session, relationship
|
||||
from sqlalchemy.orm import Mapped, Session, mapped_column, relationship
|
||||
|
||||
from ..db.base_class import Base
|
||||
from ..db.base_class import reg
|
||||
|
||||
|
||||
if TYPE_CHECKING:
|
||||
@@ -28,16 +27,17 @@ if TYPE_CHECKING:
|
||||
from .user import User
|
||||
|
||||
|
||||
class Attendance(Base):
|
||||
@reg.mapped_as_dataclass(unsafe_hash=True)
|
||||
class Attendance:
|
||||
__tablename__ = "attendances"
|
||||
id: uuid.UUID = Column("id", UUID(as_uuid=True), primary_key=True, default=uuid.uuid4)
|
||||
employee_id: uuid.UUID = Column("employee_id", UUID(as_uuid=True), ForeignKey("employees.id"))
|
||||
date: datetime.date = Column("date", Date, nullable=False)
|
||||
attendance_type: int = Column("attendance_type", Integer)
|
||||
amount: Decimal = Column("amount", Numeric(precision=5, scale=2))
|
||||
creation_date: datetime.datetime = Column("creation_date", DateTime())
|
||||
user_id: uuid.UUID = Column("user_id", UUID(as_uuid=True), ForeignKey("users.id"))
|
||||
is_valid: bool = Column("is_valid", Boolean)
|
||||
id: Mapped[uuid.UUID] = mapped_column(Uuid, primary_key=True, insert_default=uuid.uuid4)
|
||||
employee_id: Mapped[uuid.UUID] = mapped_column(Uuid, ForeignKey("employees.id"), nullable=False)
|
||||
date: Mapped[datetime.date] = mapped_column(Date, nullable=False)
|
||||
attendance_type: Mapped[int] = mapped_column(Integer, nullable=False)
|
||||
amount: Mapped[Decimal] = mapped_column(Numeric(precision=5, scale=2), nullable=False)
|
||||
creation_date: Mapped[datetime.datetime] = mapped_column(DateTime(), nullable=False)
|
||||
user_id: Mapped[uuid.UUID] = mapped_column(Uuid, ForeignKey("users.id"), nullable=False)
|
||||
is_valid: Mapped[bool] = mapped_column(Boolean, nullable=False)
|
||||
|
||||
__table_args__ = (
|
||||
Index(
|
||||
@@ -58,9 +58,9 @@ class Attendance(Base):
|
||||
attendance_type: int,
|
||||
user_id: uuid.UUID,
|
||||
amount: Decimal = Decimal(0),
|
||||
creation_date: Optional[datetime.datetime] = None,
|
||||
creation_date: datetime.datetime | None = None,
|
||||
is_valid: bool = True,
|
||||
id_: Optional[uuid.UUID] = None,
|
||||
id_: uuid.UUID | None = None,
|
||||
):
|
||||
self.employee_id = employee_id
|
||||
self.date = date
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
from decimal import Decimal
|
||||
from typing import List
|
||||
|
||||
|
||||
class AttendanceType:
|
||||
@@ -13,7 +12,7 @@ class AttendanceType:
|
||||
self.value = value
|
||||
|
||||
@classmethod
|
||||
def list(cls) -> List["AttendanceType"]:
|
||||
def list(cls) -> list["AttendanceType"]:
|
||||
return [
|
||||
AttendanceType(0, "Not Set", Decimal(0)),
|
||||
AttendanceType(1, "Present", Decimal(1)),
|
||||
|
||||
@@ -1,35 +1,35 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import uuid
|
||||
|
||||
from datetime import date
|
||||
from decimal import Decimal
|
||||
from typing import TYPE_CHECKING, List, Optional
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from sqlalchemy import Column, Date, ForeignKey, Numeric
|
||||
from sqlalchemy.dialects.postgresql import UUID
|
||||
from sqlalchemy.orm import Mapped, relationship
|
||||
from sqlalchemy import Date, ForeignKey, Numeric, Uuid
|
||||
from sqlalchemy.orm import Mapped, mapped_column, relationship
|
||||
|
||||
from ..db.base_class import Base
|
||||
from ..db.base_class import reg
|
||||
|
||||
|
||||
if TYPE_CHECKING:
|
||||
# if the target of the relationship is in another module
|
||||
# that cannot normally be imported at runtime
|
||||
from .inventory import Inventory
|
||||
from .stock_keeping_unit import StockKeepingUnit
|
||||
|
||||
|
||||
class Batch(Base):
|
||||
@reg.mapped_as_dataclass(unsafe_hash=True)
|
||||
class Batch:
|
||||
__tablename__ = "batches"
|
||||
|
||||
id: uuid.UUID = Column("id", UUID(as_uuid=True), primary_key=True, default=uuid.uuid4)
|
||||
name: date = Column("name", Date, nullable=False)
|
||||
sku_id: uuid.UUID = Column("sku_id", UUID(as_uuid=True), ForeignKey("stock_keeping_units.id"), nullable=False)
|
||||
quantity_remaining: Decimal = Column("quantity_remaining", Numeric(precision=15, scale=2), nullable=False)
|
||||
rate: Decimal = Column("rate", Numeric(precision=15, scale=2), nullable=False)
|
||||
tax: Decimal = Column("tax", Numeric(precision=15, scale=5), nullable=False)
|
||||
discount: Decimal = Column("discount", Numeric(precision=15, scale=5), nullable=False)
|
||||
id: Mapped[uuid.UUID] = mapped_column(Uuid, primary_key=True, insert_default=uuid.uuid4)
|
||||
name: Mapped[date] = mapped_column(Date, nullable=False)
|
||||
sku_id: Mapped[uuid.UUID] = mapped_column(Uuid, ForeignKey("stock_keeping_units.id"), nullable=False)
|
||||
quantity_remaining: Mapped[Decimal] = mapped_column(Numeric(precision=15, scale=2), nullable=False)
|
||||
rate: Mapped[Decimal] = mapped_column(Numeric(precision=15, scale=2), nullable=False)
|
||||
tax: Mapped[Decimal] = mapped_column(Numeric(precision=15, scale=5), nullable=False)
|
||||
discount: Mapped[Decimal] = mapped_column(Numeric(precision=15, scale=5), nullable=False)
|
||||
|
||||
inventories: List["Inventory"] = relationship("Inventory", back_populates="batch")
|
||||
inventories: Mapped[list["Inventory"]] = relationship("Inventory", back_populates="batch")
|
||||
sku: Mapped["StockKeepingUnit"] = relationship("StockKeepingUnit", back_populates="batches")
|
||||
|
||||
def __init__(
|
||||
@@ -39,8 +39,8 @@ class Batch(Base):
|
||||
rate: Decimal,
|
||||
tax: Decimal,
|
||||
discount: Decimal,
|
||||
sku_id: Optional[uuid.UUID] = None,
|
||||
sku: Optional["StockKeepingUnit"] = None,
|
||||
sku_id: uuid.UUID | None = None,
|
||||
sku: StockKeepingUnit | None = None,
|
||||
):
|
||||
self.name = name
|
||||
if sku_id is not None and sku is None:
|
||||
|
||||
@@ -5,27 +5,26 @@ import string
|
||||
import uuid
|
||||
|
||||
from datetime import datetime
|
||||
from typing import List, Optional
|
||||
|
||||
from sqlalchemy import Boolean, Column, DateTime, Integer, Unicode, desc
|
||||
from sqlalchemy.dialects.postgresql import UUID
|
||||
from sqlalchemy.orm import Session, relationship
|
||||
from sqlalchemy import Boolean, DateTime, Integer, Unicode, Uuid, desc
|
||||
from sqlalchemy.orm import Mapped, Session, mapped_column, relationship
|
||||
|
||||
from ..db.base_class import Base
|
||||
from ..db.base_class import reg
|
||||
from .login_history import LoginHistory
|
||||
|
||||
|
||||
class Client(Base):
|
||||
@reg.mapped_as_dataclass(unsafe_hash=True)
|
||||
class Client:
|
||||
__tablename__ = "clients"
|
||||
|
||||
id: uuid.UUID = Column("id", UUID(as_uuid=True), primary_key=True, default=uuid.uuid4)
|
||||
code: int = Column("code", Integer, unique=True, nullable=False)
|
||||
name: str = Column("name", Unicode(255), unique=True, nullable=False)
|
||||
enabled: bool = Column("enabled", Boolean, nullable=False)
|
||||
otp: Optional[int] = Column("otp", Integer)
|
||||
creation_date: datetime = Column("creation_date", DateTime(), nullable=False)
|
||||
id: Mapped[uuid.UUID] = mapped_column(Uuid, primary_key=True, insert_default=uuid.uuid4)
|
||||
code: Mapped[int] = mapped_column(Integer, unique=True, nullable=False)
|
||||
name: Mapped[str] = mapped_column(Unicode, unique=True, nullable=False)
|
||||
enabled: Mapped[bool] = mapped_column(Boolean, nullable=False)
|
||||
otp: Mapped[int | None] = mapped_column(Integer, nullable=True)
|
||||
creation_date: Mapped[datetime] = mapped_column(DateTime(), nullable=False)
|
||||
|
||||
login_history: List["LoginHistory"] = relationship(
|
||||
login_history: Mapped[list["LoginHistory"]] = relationship(
|
||||
"LoginHistory", order_by=desc(LoginHistory.date), back_populates="client"
|
||||
)
|
||||
|
||||
@@ -34,9 +33,9 @@ class Client(Base):
|
||||
code: int,
|
||||
name: str,
|
||||
enabled: bool,
|
||||
otp: Optional[int],
|
||||
creation_date: Optional[datetime] = None,
|
||||
id_: Optional[uuid.UUID] = None,
|
||||
otp: int | None,
|
||||
creation_date: datetime | None = None,
|
||||
id_: uuid.UUID | None = None,
|
||||
) -> None:
|
||||
self.code = code
|
||||
self.name = name
|
||||
|
||||
@@ -1,36 +1,35 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import datetime
|
||||
import uuid
|
||||
|
||||
from decimal import Decimal
|
||||
from typing import TYPE_CHECKING, Optional
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from sqlalchemy import Column, Date, ForeignKey, Numeric, UniqueConstraint
|
||||
from sqlalchemy.dialects.postgresql import UUID
|
||||
from sqlalchemy.orm import Mapped, relationship
|
||||
from sqlalchemy import Date, ForeignKey, Numeric, UniqueConstraint, Uuid
|
||||
from sqlalchemy.orm import Mapped, mapped_column, relationship
|
||||
|
||||
from ..db.base_class import Base
|
||||
from ..db.base_class import reg
|
||||
|
||||
|
||||
if TYPE_CHECKING:
|
||||
# if the target of the relationship is in another module
|
||||
# that cannot normally be imported at runtime
|
||||
from .cost_centre import CostCentre
|
||||
from .stock_keeping_unit import StockKeepingUnit
|
||||
|
||||
|
||||
class ClosingStock(Base):
|
||||
@reg.mapped_as_dataclass(unsafe_hash=True)
|
||||
class ClosingStock:
|
||||
__tablename__ = "closing_stocks"
|
||||
__table_args__ = (UniqueConstraint("date", "cost_centre_id", "sku_id"),)
|
||||
id: uuid.UUID = Column("id", UUID(as_uuid=True), primary_key=True, default=uuid.uuid4)
|
||||
date_: datetime.date = Column("date", Date, nullable=False)
|
||||
cost_centre_id: uuid.UUID = Column(
|
||||
"cost_centre_id",
|
||||
UUID(as_uuid=True),
|
||||
id: Mapped[uuid.UUID] = mapped_column(Uuid, primary_key=True, insert_default=uuid.uuid4)
|
||||
date_: Mapped[datetime.date] = mapped_column("date", Date, nullable=False)
|
||||
cost_centre_id: Mapped[uuid.UUID] = mapped_column(
|
||||
Uuid,
|
||||
ForeignKey("cost_centres.id"),
|
||||
nullable=False,
|
||||
)
|
||||
sku_id: uuid.UUID = Column("sku_id", UUID(as_uuid=True), ForeignKey("stock_keeping_units.id"), nullable=False)
|
||||
quantity: Decimal = Column("quantity", Numeric(precision=15, scale=2), nullable=False)
|
||||
sku_id: Mapped[uuid.UUID] = mapped_column(Uuid, ForeignKey("stock_keeping_units.id"), nullable=False)
|
||||
quantity: Mapped[Decimal] = mapped_column(Numeric(precision=15, scale=2), nullable=False)
|
||||
|
||||
cost_centre: Mapped["CostCentre"] = relationship("CostCentre")
|
||||
sku: Mapped["StockKeepingUnit"] = relationship("StockKeepingUnit")
|
||||
@@ -40,9 +39,9 @@ class ClosingStock(Base):
|
||||
date_: datetime.date,
|
||||
cost_centre_id: uuid.UUID,
|
||||
quantity: Decimal,
|
||||
sku_id: Optional[uuid.UUID] = None,
|
||||
sku: Optional["StockKeepingUnit"] = None,
|
||||
id_: Optional[uuid.UUID] = None,
|
||||
sku_id: uuid.UUID | None = None,
|
||||
sku: "StockKeepingUnit" | None = None,
|
||||
id_: uuid.UUID | None = None,
|
||||
):
|
||||
self.date_ = date_
|
||||
self.cost_centre_id = cost_centre_id
|
||||
|
||||
@@ -1,12 +1,11 @@
|
||||
import uuid
|
||||
|
||||
from typing import TYPE_CHECKING, List, Optional
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from sqlalchemy import Boolean, Column, Unicode
|
||||
from sqlalchemy.dialects.postgresql import UUID
|
||||
from sqlalchemy.orm import relationship
|
||||
from sqlalchemy import Boolean, Unicode, Uuid
|
||||
from sqlalchemy.orm import Mapped, mapped_column, relationship
|
||||
|
||||
from ..db.base_class import Base
|
||||
from ..db.base_class import reg
|
||||
from ..schemas.cost_centre import CostCentreLink
|
||||
|
||||
|
||||
@@ -17,21 +16,22 @@ if TYPE_CHECKING:
|
||||
from .journal import Journal
|
||||
|
||||
|
||||
class CostCentre(Base):
|
||||
@reg.mapped_as_dataclass(unsafe_hash=True)
|
||||
class CostCentre:
|
||||
__tablename__ = "cost_centres"
|
||||
|
||||
id: uuid.UUID = Column("id", UUID(as_uuid=True), primary_key=True, default=uuid.uuid4)
|
||||
name: str = Column("name", Unicode(255), unique=True)
|
||||
is_fixture: bool = Column("is_fixture", Boolean, nullable=False)
|
||||
id: Mapped[uuid.UUID] = mapped_column(Uuid, primary_key=True, insert_default=uuid.uuid4)
|
||||
name: Mapped[str] = mapped_column(Unicode, unique=True, nullable=False)
|
||||
is_fixture: Mapped[bool] = mapped_column(Boolean, nullable=False)
|
||||
|
||||
accounts: List["AccountBase"] = relationship("AccountBase", back_populates="cost_centre")
|
||||
journals: List["Journal"] = relationship("Journal", back_populates="cost_centre")
|
||||
accounts: Mapped[list["AccountBase"]] = relationship("AccountBase", back_populates="cost_centre")
|
||||
journals: Mapped[list["Journal"]] = relationship("Journal", back_populates="cost_centre")
|
||||
|
||||
@property
|
||||
def __name__(self) -> str:
|
||||
return self.name
|
||||
|
||||
def __init__(self, name: str, id_: Optional[uuid.UUID] = None, is_fixture: bool = False) -> None:
|
||||
def __init__(self, name: str, id_: uuid.UUID | None = None, is_fixture: bool = False) -> None:
|
||||
self.name = name
|
||||
if id_ is not None:
|
||||
self.id = id_
|
||||
|
||||
@@ -1,23 +1,23 @@
|
||||
import uuid
|
||||
|
||||
from datetime import datetime
|
||||
from typing import Optional
|
||||
|
||||
from sqlalchemy import Column, DateTime, Unicode
|
||||
from sqlalchemy.dialects.postgresql import BYTEA, UUID
|
||||
from sqlalchemy import DateTime, LargeBinary, Unicode, Uuid
|
||||
from sqlalchemy.orm import Mapped, mapped_column
|
||||
|
||||
from ..db.base_class import Base
|
||||
from ..db.base_class import reg
|
||||
|
||||
|
||||
class DbImage(Base):
|
||||
@reg.mapped_as_dataclass(unsafe_hash=True)
|
||||
class DbImage:
|
||||
__tablename__ = "images"
|
||||
|
||||
id: uuid.UUID = Column("id", UUID(as_uuid=True), primary_key=True, default=uuid.uuid4)
|
||||
resource_id: uuid.UUID = Column("resource_id", UUID(as_uuid=True), nullable=False)
|
||||
resource_type: str = Column("resource_type", Unicode(255), nullable=False)
|
||||
image: bytes = Column("image", BYTEA, nullable=False)
|
||||
thumbnail: bytes = Column("thumbnail", BYTEA, nullable=False)
|
||||
creation_date: datetime = Column("creation_date", DateTime(), nullable=False)
|
||||
id: Mapped[uuid.UUID] = mapped_column(Uuid, primary_key=True, insert_default=uuid.uuid4)
|
||||
resource_id: Mapped[uuid.UUID] = mapped_column(Uuid, nullable=False)
|
||||
resource_type: Mapped[str] = mapped_column(Unicode, nullable=False)
|
||||
image: Mapped[bytes] = mapped_column(LargeBinary, nullable=False)
|
||||
thumbnail: Mapped[bytes] = mapped_column(LargeBinary, nullable=False)
|
||||
creation_date: Mapped[datetime] = mapped_column(DateTime(), nullable=False)
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
@@ -25,8 +25,8 @@ class DbImage(Base):
|
||||
resource_type: str,
|
||||
image: bytes,
|
||||
thumbnail: bytes,
|
||||
creation_date: Optional[datetime] = None,
|
||||
id_: Optional[uuid.UUID] = None,
|
||||
creation_date: datetime | None = None,
|
||||
id_: uuid.UUID | None = None,
|
||||
) -> None:
|
||||
self.resource_id = resource_id
|
||||
self.resource_type = resource_type
|
||||
|
||||
@@ -1,34 +1,34 @@
|
||||
import uuid
|
||||
|
||||
from datetime import date
|
||||
from typing import Optional
|
||||
|
||||
from sqlalchemy import Column, Date, Enum, PickleType, Unicode
|
||||
from sqlalchemy.dialects.postgresql import UUID
|
||||
from sqlalchemy import Date, Enum, PickleType, Unicode, Uuid
|
||||
from sqlalchemy.orm import Mapped, mapped_column
|
||||
|
||||
from ..db.base_class import Base
|
||||
from ..db.base_class import reg
|
||||
from .setting_type import SettingType
|
||||
|
||||
|
||||
class DbSetting(Base):
|
||||
@reg.mapped_as_dataclass(unsafe_hash=True)
|
||||
class DbSetting:
|
||||
__tablename__ = "settings"
|
||||
|
||||
id: uuid.UUID = Column("id", UUID(as_uuid=True), primary_key=True, default=uuid.uuid4)
|
||||
name: str = Column("name", Unicode(255), unique=True, nullable=False)
|
||||
data: dict = Column("data", PickleType)
|
||||
setting_type: SettingType = Column("setting_type", Enum(SettingType), nullable=False)
|
||||
id: Mapped[uuid.UUID] = mapped_column(Uuid, primary_key=True, insert_default=uuid.uuid4)
|
||||
name: Mapped[str] = mapped_column(Unicode, unique=True, nullable=False)
|
||||
data: Mapped[dict] = mapped_column(PickleType)
|
||||
setting_type: Mapped[SettingType] = mapped_column(Enum(SettingType), nullable=False)
|
||||
|
||||
valid_from: Optional[date] = Column("valid_from", Date(), nullable=True)
|
||||
valid_till: Optional[date] = Column("valid_till", Date(), nullable=True)
|
||||
valid_from: Mapped[date | None] = mapped_column(Date(), nullable=True)
|
||||
valid_till: Mapped[date | None] = mapped_column(Date(), nullable=True)
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
setting_type: SettingType,
|
||||
name: str,
|
||||
data: dict,
|
||||
valid_from: Optional[date] = None,
|
||||
valid_till: Optional[date] = None,
|
||||
id_: Optional[uuid.UUID] = None,
|
||||
valid_from: date | None = None,
|
||||
valid_till: date | None = None,
|
||||
id_: uuid.UUID | None = None,
|
||||
) -> None:
|
||||
if id_ is not None:
|
||||
self.id = id_
|
||||
|
||||
@@ -2,39 +2,38 @@ import uuid
|
||||
|
||||
from datetime import date
|
||||
from decimal import Decimal
|
||||
from typing import TYPE_CHECKING, List, Optional, Tuple
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from sqlalchemy import Column, Date, ForeignKey, Integer, Numeric, Unicode, func, select
|
||||
from sqlalchemy.dialects.postgresql import UUID
|
||||
from sqlalchemy.orm import Session, relationship
|
||||
from sqlalchemy import Date, ForeignKey, Integer, Numeric, Unicode, Uuid, func, select
|
||||
from sqlalchemy.orm import Mapped, Session, mapped_column, relationship
|
||||
|
||||
from ..db.base_class import reg
|
||||
from .account_base import AccountBase
|
||||
|
||||
|
||||
if TYPE_CHECKING:
|
||||
# if the target of the relationship is in another module
|
||||
# that cannot normally be imported at runtime
|
||||
from .attendance import Attendance
|
||||
from .fingerprint import Fingerprint
|
||||
|
||||
|
||||
@reg.mapped_as_dataclass(unsafe_hash=True)
|
||||
class Employee(AccountBase):
|
||||
__tablename__ = "employees"
|
||||
__mapper_args__ = {"polymorphic_identity": "employees"} # type: ignore
|
||||
|
||||
id: uuid.UUID = Column("id", UUID(as_uuid=True), ForeignKey("accounts.id"), primary_key=True)
|
||||
designation: str = Column("designation", Unicode(255), nullable=False)
|
||||
salary: int = Column("salary", Integer, nullable=False)
|
||||
points: Decimal = Column("points", Numeric(precision=5, scale=2), nullable=False)
|
||||
joining_date: date = Column("joining_date", Date, nullable=False)
|
||||
leaving_date: Optional[date] = Column("leaving_date", Date, nullable=True)
|
||||
id: Mapped[uuid.UUID] = mapped_column(Uuid, ForeignKey("accounts.id"), primary_key=True)
|
||||
designation: Mapped[str] = mapped_column(Unicode, nullable=False)
|
||||
salary: Mapped[int] = mapped_column(Integer, nullable=False)
|
||||
points: Mapped[Decimal] = mapped_column(Numeric(precision=5, scale=2), nullable=False)
|
||||
joining_date: Mapped[date] = mapped_column(Date, nullable=False)
|
||||
leaving_date: Mapped[date | None] = mapped_column(Date, nullable=True)
|
||||
|
||||
attendances: List["Attendance"] = relationship("Attendance", back_populates="employee")
|
||||
fingerprints: List["Fingerprint"] = relationship("Fingerprint", back_populates="employee")
|
||||
attendances: Mapped[list["Attendance"]] = relationship("Attendance", back_populates="employee")
|
||||
fingerprints: Mapped[list["Fingerprint"]] = relationship("Fingerprint", back_populates="employee")
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
code: Optional[int],
|
||||
code: int | None,
|
||||
name: str,
|
||||
is_starred: bool,
|
||||
is_active: bool,
|
||||
@@ -43,7 +42,7 @@ class Employee(AccountBase):
|
||||
salary: int,
|
||||
points: Decimal,
|
||||
joining_date: date,
|
||||
leaving_date: Optional[date] = None,
|
||||
leaving_date: date | None = None,
|
||||
) -> None:
|
||||
self.designation = designation
|
||||
self.salary = salary
|
||||
@@ -68,5 +67,5 @@ class Employee(AccountBase):
|
||||
db.add(self)
|
||||
return self
|
||||
|
||||
def can_delete(self, advanced_delete: bool) -> Tuple[bool, str]:
|
||||
def can_delete(self, advanced_delete: bool) -> tuple[bool, str]:
|
||||
return super(Employee, self).can_delete(advanced_delete)
|
||||
@@ -1,31 +1,29 @@
|
||||
import uuid
|
||||
|
||||
from typing import TYPE_CHECKING, Optional
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from sqlalchemy import Column, ForeignKey, Integer
|
||||
from sqlalchemy.dialects.postgresql import UUID
|
||||
from sqlalchemy.orm import Mapped, relationship
|
||||
from sqlalchemy import ForeignKey, Integer, Uuid
|
||||
from sqlalchemy.orm import Mapped, mapped_column, relationship
|
||||
|
||||
from ..db.base_class import Base
|
||||
from ..db.base_class import reg
|
||||
|
||||
|
||||
if TYPE_CHECKING:
|
||||
# if the target of the relationship is in another module
|
||||
# that cannot normally be imported at runtime
|
||||
from .journal import Journal
|
||||
|
||||
|
||||
class EmployeeBenefit(Base):
|
||||
@reg.mapped_as_dataclass(unsafe_hash=True)
|
||||
class EmployeeBenefit:
|
||||
__tablename__ = "employee_benefit"
|
||||
id: uuid.UUID = Column("id", UUID(as_uuid=True), primary_key=True, default=uuid.uuid4)
|
||||
voucher_id: uuid.UUID = Column("voucher_id", UUID(as_uuid=True), ForeignKey("vouchers.id"), nullable=False)
|
||||
journal_id: uuid.UUID = Column("journal_id", UUID(as_uuid=True), ForeignKey("journals.id"), nullable=False)
|
||||
gross_salary: int = Column("gross_salary", Integer)
|
||||
days_worked: int = Column("days_worked", Integer)
|
||||
esi_ee: int = Column("esi_employee", Integer)
|
||||
pf_ee: int = Column("pf_employee", Integer)
|
||||
esi_er: int = Column("esi_employer", Integer)
|
||||
pf_er: int = Column("pf_employer", Integer)
|
||||
id: Mapped[uuid.UUID] = mapped_column(Uuid, primary_key=True, insert_default=uuid.uuid4)
|
||||
voucher_id: Mapped[uuid.UUID] = mapped_column(Uuid, ForeignKey("vouchers.id"), nullable=False)
|
||||
journal_id: Mapped[uuid.UUID] = mapped_column(Uuid, ForeignKey("journals.id"), nullable=False)
|
||||
gross_salary: Mapped[int] = mapped_column(Integer, nullable=False)
|
||||
days_worked: Mapped[int] = mapped_column(Integer, nullable=False)
|
||||
esi_ee: Mapped[int] = mapped_column("esi_employee", Integer, nullable=False)
|
||||
pf_ee: Mapped[int] = mapped_column("pf_employee", Integer, nullable=False)
|
||||
esi_er: Mapped[int] = mapped_column("esi_employer", Integer, nullable=False)
|
||||
pf_er: Mapped[int] = mapped_column("pf_employer", Integer, nullable=False)
|
||||
|
||||
journal: Mapped["Journal"] = relationship("Journal", back_populates="employee_benefit")
|
||||
|
||||
@@ -38,8 +36,8 @@ class EmployeeBenefit(Base):
|
||||
esi_er: int,
|
||||
pf_er: int,
|
||||
journal: "Journal",
|
||||
voucher_id: Optional[uuid.UUID] = None,
|
||||
id_: Optional[uuid.UUID] = None,
|
||||
voucher_id: uuid.UUID | None = None,
|
||||
id_: uuid.UUID | None = None,
|
||||
) -> None:
|
||||
if id_ is not None:
|
||||
self.id = id_
|
||||
|
||||
@@ -1,31 +1,29 @@
|
||||
import uuid
|
||||
|
||||
from datetime import datetime
|
||||
from typing import TYPE_CHECKING, Optional
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from sqlalchemy import Column, DateTime, ForeignKey
|
||||
from sqlalchemy.dialects.postgresql import UUID
|
||||
from sqlalchemy.orm import Mapped, relationship
|
||||
from sqlalchemy import DateTime, ForeignKey, Uuid
|
||||
from sqlalchemy.orm import Mapped, mapped_column, relationship
|
||||
|
||||
from ..db.base_class import Base
|
||||
from ..db.base_class import reg
|
||||
|
||||
|
||||
if TYPE_CHECKING:
|
||||
# if the target of the relationship is in another module
|
||||
# that cannot normally be imported at runtime
|
||||
from .employee import Employee
|
||||
|
||||
|
||||
class Fingerprint(Base):
|
||||
@reg.mapped_as_dataclass(unsafe_hash=True)
|
||||
class Fingerprint:
|
||||
__tablename__ = "fingerprints"
|
||||
|
||||
id: uuid.UUID = Column("id", UUID(as_uuid=True), primary_key=True, default=uuid.uuid4)
|
||||
employee_id: uuid.UUID = Column("employee_id", UUID(as_uuid=True), ForeignKey("employees.id"))
|
||||
date: datetime = Column("date", DateTime)
|
||||
id: Mapped[uuid.UUID] = mapped_column(Uuid, primary_key=True, insert_default=uuid.uuid4)
|
||||
employee_id: Mapped[uuid.UUID] = mapped_column(Uuid, ForeignKey("employees.id"), nullable=False)
|
||||
date: Mapped[datetime] = mapped_column(DateTime, nullable=False)
|
||||
|
||||
employee: Mapped["Employee"] = relationship("Employee", back_populates="fingerprints")
|
||||
|
||||
def __init__(self, employee_id: uuid.UUID, date: datetime, id_: Optional[uuid.UUID] = None) -> None:
|
||||
def __init__(self, employee_id: uuid.UUID, date: datetime, id_: uuid.UUID | None = None) -> None:
|
||||
self.employee_id = employee_id
|
||||
self.date = date
|
||||
if id_ is not None:
|
||||
|
||||
@@ -1,28 +1,26 @@
|
||||
import uuid
|
||||
|
||||
from decimal import Decimal
|
||||
from typing import TYPE_CHECKING, Optional
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from sqlalchemy import Column, ForeignKey, Numeric
|
||||
from sqlalchemy.dialects.postgresql import UUID
|
||||
from sqlalchemy.orm import Mapped, relationship
|
||||
from sqlalchemy import ForeignKey, Numeric, Uuid
|
||||
from sqlalchemy.orm import Mapped, mapped_column, relationship
|
||||
|
||||
from ..db.base_class import Base
|
||||
from ..db.base_class import reg
|
||||
|
||||
|
||||
if TYPE_CHECKING:
|
||||
# if the target of the relationship is in another module
|
||||
# that cannot normally be imported at runtime
|
||||
from .journal import Journal
|
||||
|
||||
|
||||
class Incentive(Base):
|
||||
@reg.mapped_as_dataclass(unsafe_hash=True)
|
||||
class Incentive:
|
||||
__tablename__ = "incentives"
|
||||
id: uuid.UUID = Column("id", UUID(as_uuid=True), primary_key=True, default=uuid.uuid4)
|
||||
voucher_id: uuid.UUID = Column("voucher_id", UUID(as_uuid=True), ForeignKey("vouchers.id"), nullable=False)
|
||||
journal_id: uuid.UUID = Column("journal_id", UUID(as_uuid=True), ForeignKey("journals.id"), nullable=False)
|
||||
days_worked: Decimal = Column("days_worked", Numeric(precision=5, scale=1), nullable=False)
|
||||
points: Decimal = Column("points", Numeric(precision=5, scale=2), nullable=False)
|
||||
id: Mapped[uuid.UUID] = mapped_column(Uuid, primary_key=True, insert_default=uuid.uuid4)
|
||||
voucher_id: Mapped[uuid.UUID] = mapped_column(Uuid, ForeignKey("vouchers.id"), nullable=False)
|
||||
journal_id: Mapped[uuid.UUID] = mapped_column(Uuid, ForeignKey("journals.id"), nullable=False)
|
||||
days_worked: Mapped[Decimal] = mapped_column(Numeric(precision=5, scale=1), nullable=False)
|
||||
points: Mapped[Decimal] = mapped_column(Numeric(precision=5, scale=2), nullable=False)
|
||||
|
||||
journal: Mapped["Journal"] = relationship("Journal", back_populates="incentive")
|
||||
|
||||
@@ -31,8 +29,8 @@ class Incentive(Base):
|
||||
journal: "Journal",
|
||||
days_worked: Decimal,
|
||||
points: Decimal,
|
||||
voucher_id: Optional[uuid.UUID] = None,
|
||||
id_: Optional[uuid.UUID] = None,
|
||||
voucher_id: uuid.UUID | None = None,
|
||||
id_: uuid.UUID | None = None,
|
||||
) -> None:
|
||||
self.journal = journal
|
||||
self.days_worked = days_worked
|
||||
|
||||
@@ -1,39 +1,36 @@
|
||||
import uuid
|
||||
|
||||
from decimal import Decimal
|
||||
from typing import TYPE_CHECKING, Optional
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from sqlalchemy import Column, ForeignKey, Numeric, UniqueConstraint
|
||||
from sqlalchemy.dialects.postgresql import UUID
|
||||
from sqlalchemy import ForeignKey, Numeric, UniqueConstraint, Uuid
|
||||
from sqlalchemy.ext.hybrid import hybrid_property
|
||||
from sqlalchemy.orm import Mapped, relationship
|
||||
from sqlalchemy.orm import Mapped, mapped_column, relationship
|
||||
|
||||
from ..db.base_class import Base
|
||||
from ..db.base_class import reg
|
||||
|
||||
|
||||
if TYPE_CHECKING:
|
||||
# if the target of the relationship is in another module
|
||||
# that cannot normally be imported at runtime
|
||||
from .batch import Batch
|
||||
from .voucher import Voucher
|
||||
|
||||
|
||||
class Inventory(Base):
|
||||
@reg.mapped_as_dataclass(unsafe_hash=True)
|
||||
class Inventory:
|
||||
__tablename__ = "inventories"
|
||||
__table_args__ = (UniqueConstraint("voucher_id", "batch_id"),)
|
||||
id: uuid.UUID = Column("id", UUID(as_uuid=True), primary_key=True, default=uuid.uuid4)
|
||||
voucher_id: uuid.UUID = Column(
|
||||
"voucher_id",
|
||||
UUID(as_uuid=True),
|
||||
id: Mapped[uuid.UUID] = mapped_column(Uuid, primary_key=True, insert_default=uuid.uuid4)
|
||||
voucher_id: Mapped[uuid.UUID] = mapped_column(
|
||||
Uuid,
|
||||
ForeignKey("vouchers.id"),
|
||||
nullable=False,
|
||||
index=True,
|
||||
)
|
||||
batch_id: uuid.UUID = Column("batch_id", UUID(as_uuid=True), ForeignKey("batches.id"), nullable=False)
|
||||
quantity: Decimal = Column("quantity", Numeric(precision=15, scale=2), nullable=False)
|
||||
rate: Decimal = Column("rate", Numeric(precision=15, scale=2), nullable=False)
|
||||
tax: Decimal = Column("tax", Numeric(precision=15, scale=5), nullable=False)
|
||||
discount: Decimal = Column("discount", Numeric(precision=15, scale=5), nullable=False)
|
||||
batch_id: Mapped[uuid.UUID] = mapped_column(Uuid, ForeignKey("batches.id"), nullable=False)
|
||||
quantity: Mapped[Decimal] = mapped_column(Numeric(precision=15, scale=2), nullable=False)
|
||||
rate: Mapped[Decimal] = mapped_column(Numeric(precision=15, scale=2), nullable=False)
|
||||
tax: Mapped[Decimal] = mapped_column(Numeric(precision=15, scale=5), nullable=False)
|
||||
discount: Mapped[Decimal] = mapped_column(Numeric(precision=15, scale=5), nullable=False)
|
||||
|
||||
voucher: Mapped["Voucher"] = relationship("Voucher", back_populates="inventories")
|
||||
batch: Mapped["Batch"] = relationship("Batch", back_populates="inventories")
|
||||
@@ -45,8 +42,8 @@ class Inventory(Base):
|
||||
tax: Decimal,
|
||||
discount: Decimal,
|
||||
batch: "Batch",
|
||||
voucher_id: Optional[uuid.UUID] = None,
|
||||
id_: Optional[uuid.UUID] = None,
|
||||
voucher_id: uuid.UUID | None = None,
|
||||
id_: uuid.UUID | None = None,
|
||||
) -> None:
|
||||
self.batch = batch
|
||||
self.quantity = quantity
|
||||
|
||||
@@ -1,19 +1,16 @@
|
||||
import uuid
|
||||
|
||||
from decimal import Decimal
|
||||
from typing import TYPE_CHECKING, Optional
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from sqlalchemy import Column, ForeignKey, Integer, Numeric
|
||||
from sqlalchemy.dialects.postgresql import UUID
|
||||
from sqlalchemy import ForeignKey, Integer, Numeric, Uuid
|
||||
from sqlalchemy.ext.hybrid import hybrid_property
|
||||
from sqlalchemy.orm import Mapped, relationship
|
||||
from sqlalchemy.orm import Mapped, mapped_column, relationship
|
||||
|
||||
from ..db.base_class import Base
|
||||
from ..db.base_class import reg
|
||||
|
||||
|
||||
if TYPE_CHECKING:
|
||||
# if the target of the relationship is in another module
|
||||
# that cannot normally be imported at runtime
|
||||
from .account import AccountBase
|
||||
from .cost_centre import CostCentre
|
||||
from .employee_benefit import EmployeeBenefit
|
||||
@@ -21,23 +18,22 @@ if TYPE_CHECKING:
|
||||
from .voucher import Voucher
|
||||
|
||||
|
||||
class Journal(Base):
|
||||
@reg.mapped_as_dataclass(unsafe_hash=True)
|
||||
class Journal:
|
||||
__tablename__ = "journals"
|
||||
|
||||
id: uuid.UUID = Column("id", UUID(as_uuid=True), primary_key=True, default=uuid.uuid4)
|
||||
debit: int = Column("debit", Integer, nullable=False)
|
||||
amount: Decimal = Column("amount", Numeric(precision=15, scale=2), nullable=False)
|
||||
voucher_id: uuid.UUID = Column(
|
||||
"voucher_id",
|
||||
UUID(as_uuid=True),
|
||||
id: Mapped[uuid.UUID] = mapped_column(Uuid, primary_key=True, insert_default=uuid.uuid4)
|
||||
debit: Mapped[int] = mapped_column(Integer, nullable=False)
|
||||
amount: Mapped[Decimal] = mapped_column(Numeric(precision=15, scale=2), nullable=False)
|
||||
voucher_id: Mapped[uuid.UUID] = mapped_column(
|
||||
Uuid,
|
||||
ForeignKey("vouchers.id"),
|
||||
nullable=False,
|
||||
index=True,
|
||||
)
|
||||
account_id: uuid.UUID = Column("account_id", UUID(as_uuid=True), ForeignKey("accounts.id"), nullable=False)
|
||||
cost_centre_id: uuid.UUID = Column(
|
||||
"cost_centre_id",
|
||||
UUID(as_uuid=True),
|
||||
account_id: Mapped[uuid.UUID] = mapped_column(Uuid, ForeignKey("accounts.id"), nullable=False)
|
||||
cost_centre_id: Mapped[uuid.UUID] = mapped_column(
|
||||
Uuid,
|
||||
ForeignKey("cost_centres.id"),
|
||||
nullable=False,
|
||||
)
|
||||
@@ -49,11 +45,12 @@ class Journal(Base):
|
||||
incentive: Mapped["Incentive"] = relationship("Incentive", back_populates="journal")
|
||||
|
||||
@hybrid_property
|
||||
def _signed_amount(self) -> Decimal:
|
||||
def signed_amount(self) -> Decimal:
|
||||
return self.debit * self.amount
|
||||
|
||||
@_signed_amount.expression
|
||||
def signed_amount(cls) -> Decimal:
|
||||
@signed_amount.inplace.expression
|
||||
@classmethod
|
||||
def _signed_amount_expression(cls):
|
||||
return cls.debit * cls.amount
|
||||
|
||||
def __init__(
|
||||
@@ -62,8 +59,8 @@ class Journal(Base):
|
||||
amount: Decimal,
|
||||
account_id: uuid.UUID,
|
||||
cost_centre_id: uuid.UUID,
|
||||
voucher_id: Optional[uuid.UUID] = None,
|
||||
id_: Optional[uuid.UUID] = None,
|
||||
voucher_id: uuid.UUID | None = None,
|
||||
id_: uuid.UUID | None = None,
|
||||
) -> None:
|
||||
if id_ is not None:
|
||||
self.id = id_
|
||||
|
||||
@@ -1,37 +1,32 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import datetime
|
||||
import uuid
|
||||
|
||||
from typing import TYPE_CHECKING, Optional
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from sqlalchemy import Column, DateTime, UniqueConstraint
|
||||
from sqlalchemy.dialects.postgresql import UUID
|
||||
from sqlalchemy.orm import Mapped, relationship
|
||||
from sqlalchemy import DateTime, UniqueConstraint, Uuid
|
||||
from sqlalchemy.orm import Mapped, mapped_column, relationship
|
||||
from sqlalchemy.schema import ForeignKey
|
||||
|
||||
from ..db.base_class import Base
|
||||
from ..db.base_class import reg
|
||||
|
||||
|
||||
if TYPE_CHECKING:
|
||||
# if the target of the relationship is in another module
|
||||
# that cannot normally be imported at runtime
|
||||
from .client import Client
|
||||
from .user import User
|
||||
|
||||
|
||||
class LoginHistory(Base):
|
||||
@reg.mapped_as_dataclass(unsafe_hash=True)
|
||||
class LoginHistory:
|
||||
__tablename__ = "login_history"
|
||||
__table_args__ = (UniqueConstraint("user_id", "client_id", "date"),)
|
||||
id: uuid.UUID = Column("id", UUID(as_uuid=True), primary_key=True, default=uuid.uuid4)
|
||||
user_id: uuid.UUID = Column("user_id", UUID(as_uuid=True), ForeignKey("users.id"), nullable=False)
|
||||
client_id: uuid.UUID = Column(
|
||||
"client_id",
|
||||
UUID(as_uuid=True),
|
||||
id: Mapped[uuid.UUID] = mapped_column(Uuid, primary_key=True, insert_default=uuid.uuid4)
|
||||
user_id: Mapped[uuid.UUID] = mapped_column(Uuid, ForeignKey("users.id"), nullable=False)
|
||||
client_id: Mapped[uuid.UUID] = mapped_column(
|
||||
Uuid,
|
||||
ForeignKey("clients.id"),
|
||||
nullable=False,
|
||||
)
|
||||
date: datetime.datetime = Column("date", DateTime(), nullable=False)
|
||||
date: Mapped[datetime.datetime] = mapped_column(DateTime(), nullable=False)
|
||||
|
||||
user: Mapped["User"] = relationship("User", back_populates="login_history")
|
||||
client: Mapped["Client"] = relationship("Client", back_populates="login_history")
|
||||
@@ -40,8 +35,8 @@ class LoginHistory(Base):
|
||||
self,
|
||||
user_id: uuid.UUID,
|
||||
client_id: uuid.UUID,
|
||||
date: Optional[datetime.datetime] = None,
|
||||
id_: Optional[uuid.UUID] = None,
|
||||
date: datetime.datetime | None = None,
|
||||
id_: uuid.UUID | None = None,
|
||||
) -> None:
|
||||
self.user_id = user_id
|
||||
self.client_id = client_id
|
||||
|
||||
@@ -1,41 +1,32 @@
|
||||
import datetime
|
||||
import uuid
|
||||
|
||||
from typing import TYPE_CHECKING, List, Optional
|
||||
|
||||
from sqlalchemy import Column, Date, func, text
|
||||
from sqlalchemy import Date, Uuid, func, text
|
||||
from sqlalchemy.dialects import postgresql
|
||||
from sqlalchemy.dialects.postgresql import UUID
|
||||
from sqlalchemy.orm import relationship
|
||||
from sqlalchemy.orm import Mapped, mapped_column
|
||||
|
||||
from ..db.base_class import Base
|
||||
from ..db.base_class import reg
|
||||
|
||||
|
||||
if TYPE_CHECKING:
|
||||
# if the target of the relationship is in another module
|
||||
# that cannot normally be imported at runtime
|
||||
from .recipe import Recipe
|
||||
|
||||
|
||||
class Period(Base):
|
||||
@reg.mapped_as_dataclass(unsafe_hash=True)
|
||||
class Period:
|
||||
__tablename__ = "periods"
|
||||
|
||||
id: uuid.UUID = Column("id", UUID(as_uuid=True), primary_key=True, default=uuid.uuid4)
|
||||
valid_from: datetime.date = Column("valid_from", Date, nullable=False)
|
||||
valid_till: datetime.date = Column("valid_till", Date, nullable=False)
|
||||
id: Mapped[uuid.UUID] = mapped_column(Uuid, primary_key=True, insert_default=uuid.uuid4)
|
||||
valid_from: Mapped[datetime.date] = mapped_column(Date, nullable=False)
|
||||
valid_till: Mapped[datetime.date] = mapped_column(Date, nullable=False)
|
||||
|
||||
__table_args__ = (
|
||||
postgresql.ExcludeConstraint(
|
||||
(func.daterange(valid_from, valid_till, text("'[]'")), "&&"),
|
||||
),
|
||||
)
|
||||
recipes: List["Recipe"] = relationship("Recipe", back_populates="period")
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
valid_from: datetime.date,
|
||||
valid_till: datetime.date,
|
||||
id_: Optional[uuid.UUID] = None,
|
||||
id_: uuid.UUID | None = None,
|
||||
) -> None:
|
||||
self.valid_from = valid_from
|
||||
self.valid_till = valid_till
|
||||
|
||||
@@ -1,27 +1,23 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import uuid
|
||||
|
||||
from typing import List, Optional
|
||||
from sqlalchemy import Unicode, Uuid
|
||||
from sqlalchemy.orm import Mapped, mapped_column, relationship
|
||||
|
||||
from sqlalchemy import Column, Unicode
|
||||
from sqlalchemy.dialects.postgresql import UUID
|
||||
from sqlalchemy.orm import relationship
|
||||
|
||||
from ..db.base_class import Base
|
||||
from ..db.base_class import reg
|
||||
from .role import Role
|
||||
from .role_permission import role_permission
|
||||
from .role_permission import RolePermission
|
||||
|
||||
|
||||
class Permission(Base):
|
||||
@reg.mapped_as_dataclass(unsafe_hash=True)
|
||||
class Permission:
|
||||
__tablename__ = "permissions"
|
||||
|
||||
id: uuid.UUID = Column("id", UUID(as_uuid=True), primary_key=True, default=uuid.uuid4)
|
||||
name: str = Column("name", Unicode(255), unique=True)
|
||||
id: Mapped[uuid.UUID] = mapped_column(Uuid, primary_key=True, insert_default=uuid.uuid4)
|
||||
name: Mapped[str] = mapped_column(Unicode, unique=True, nullable=False)
|
||||
|
||||
roles: List[Role] = relationship("Role", secondary=role_permission, back_populates="permissions")
|
||||
roles: Mapped[list[Role]] = relationship(secondary=RolePermission.__table__, back_populates="permissions") # type: ignore[attr-defined]
|
||||
|
||||
def __init__(self, name: str, id_: Optional[uuid.UUID] = None) -> None:
|
||||
def __init__(self, name: str, id_: uuid.UUID | None = None) -> None:
|
||||
self.name = name
|
||||
if id_ is not None:
|
||||
self.id = id_
|
||||
@@ -1,42 +1,40 @@
|
||||
import uuid
|
||||
|
||||
from typing import TYPE_CHECKING, List, Optional
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from sqlalchemy import Boolean, Column, ForeignKey, Integer, Unicode
|
||||
from sqlalchemy.dialects.postgresql import UUID
|
||||
from sqlalchemy.orm import Mapped, relationship
|
||||
from sqlalchemy import Boolean, ForeignKey, Integer, Text, Unicode, Uuid
|
||||
from sqlalchemy.orm import Mapped, mapped_column, relationship
|
||||
|
||||
from ..db.base_class import Base
|
||||
from ..db.base_class import reg
|
||||
|
||||
|
||||
if TYPE_CHECKING:
|
||||
# if the target of the relationship is in another module
|
||||
# that cannot normally be imported at runtime
|
||||
from .account import Account
|
||||
from .product_group import ProductGroup
|
||||
from .stock_keeping_unit import StockKeepingUnit
|
||||
|
||||
|
||||
class Product(Base):
|
||||
@reg.mapped_as_dataclass(unsafe_hash=True)
|
||||
class Product:
|
||||
__tablename__ = "products"
|
||||
|
||||
id: uuid.UUID = Column("id", UUID(as_uuid=True), primary_key=True, default=uuid.uuid4)
|
||||
code: int = Column("code", Integer, unique=True)
|
||||
name: str = Column("name", Unicode(255), nullable=False, unique=True)
|
||||
fraction_units: str = Column("fraction_units", Unicode(255), nullable=False)
|
||||
product_group_id: uuid.UUID = Column(
|
||||
"product_group_id",
|
||||
UUID(as_uuid=True),
|
||||
id: Mapped[uuid.UUID] = mapped_column(Uuid, primary_key=True, insert_default=uuid.uuid4)
|
||||
code: Mapped[int] = mapped_column(Integer, unique=True, nullable=False)
|
||||
name: Mapped[str] = mapped_column(Unicode, nullable=False, unique=True)
|
||||
description: Mapped[str | None] = mapped_column(Text, nullable=True)
|
||||
fraction_units: Mapped[str] = mapped_column(Unicode, nullable=False)
|
||||
product_group_id: Mapped[uuid.UUID] = mapped_column(
|
||||
Uuid,
|
||||
ForeignKey("product_groups.id"),
|
||||
nullable=False,
|
||||
)
|
||||
account_id: uuid.UUID = Column("account_id", UUID(as_uuid=True), ForeignKey("accounts.id"), nullable=False)
|
||||
is_active: bool = Column("is_active", Boolean, nullable=False)
|
||||
is_fixture: bool = Column("is_fixture", Boolean, nullable=False)
|
||||
is_purchased: bool = Column("is_purchased", Boolean, nullable=False)
|
||||
is_sold: bool = Column("is_sold", Boolean, nullable=False)
|
||||
account_id: Mapped[uuid.UUID] = mapped_column(Uuid, ForeignKey("accounts.id"), nullable=False)
|
||||
is_active: Mapped[bool] = mapped_column(Boolean, nullable=False)
|
||||
is_fixture: Mapped[bool] = mapped_column(Boolean, nullable=False)
|
||||
is_purchased: Mapped[bool] = mapped_column(Boolean, nullable=False)
|
||||
is_sold: Mapped[bool] = mapped_column(Boolean, nullable=False)
|
||||
|
||||
skus: List["StockKeepingUnit"] = relationship("StockKeepingUnit", back_populates="product")
|
||||
skus: Mapped[list["StockKeepingUnit"]] = relationship("StockKeepingUnit", back_populates="product")
|
||||
product_group: Mapped["ProductGroup"] = relationship("ProductGroup", back_populates="products")
|
||||
account: Mapped["Account"] = relationship("Account", back_populates="products")
|
||||
|
||||
@@ -49,9 +47,9 @@ class Product(Base):
|
||||
is_active: bool,
|
||||
is_purchased: bool,
|
||||
is_sold: bool,
|
||||
code: Optional[int] = None,
|
||||
id_: Optional[uuid.UUID] = None,
|
||||
is_fixture: Optional[bool] = False,
|
||||
code: int | None = None,
|
||||
id_: uuid.UUID | None = None,
|
||||
is_fixture: bool | None = False,
|
||||
) -> None:
|
||||
if code is not None:
|
||||
self.code = code
|
||||
|
||||
@@ -1,30 +1,28 @@
|
||||
import uuid
|
||||
|
||||
from typing import TYPE_CHECKING, List, Optional
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from sqlalchemy import Boolean, Column, Unicode
|
||||
from sqlalchemy.dialects.postgresql import UUID
|
||||
from sqlalchemy.orm import relationship
|
||||
from sqlalchemy import Boolean, Unicode, Uuid
|
||||
from sqlalchemy.orm import Mapped, mapped_column, relationship
|
||||
|
||||
from ..db.base_class import Base
|
||||
from ..db.base_class import reg
|
||||
|
||||
|
||||
if TYPE_CHECKING:
|
||||
# if the target of the relationship is in another module
|
||||
# that cannot normally be imported at runtime
|
||||
from .product import Product
|
||||
|
||||
|
||||
class ProductGroup(Base):
|
||||
@reg.mapped_as_dataclass(unsafe_hash=True)
|
||||
class ProductGroup:
|
||||
__tablename__ = "product_groups"
|
||||
|
||||
id: uuid.UUID = Column("id", UUID(as_uuid=True), primary_key=True, default=uuid.uuid4)
|
||||
name: str = Column("name", Unicode(255), unique=True)
|
||||
is_fixture: bool = Column("is_fixture", Boolean, nullable=False)
|
||||
id: Mapped[uuid.UUID] = mapped_column(Uuid, primary_key=True, insert_default=uuid.uuid4)
|
||||
name: Mapped[str] = mapped_column(Unicode, unique=True, nullable=False)
|
||||
is_fixture: Mapped[bool] = mapped_column(Boolean, nullable=False)
|
||||
|
||||
products: List["Product"] = relationship("Product", back_populates="product_group")
|
||||
products: Mapped[list["Product"]] = relationship("Product", back_populates="product_group")
|
||||
|
||||
def __init__(self, name: str, id_: Optional[uuid.UUID] = None, is_fixture: Optional[bool] = False) -> None:
|
||||
def __init__(self, name: str, id_: uuid.UUID | None = None, is_fixture: bool | None = False) -> None:
|
||||
self.name = name
|
||||
if id_ is not None:
|
||||
self.id = id_
|
||||
|
||||
@@ -1,52 +1,50 @@
|
||||
import datetime
|
||||
import uuid
|
||||
|
||||
from typing import TYPE_CHECKING, List, Optional
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from sqlalchemy import Column, Date, DateTime, ForeignKey, Unicode
|
||||
from sqlalchemy.dialects.postgresql import UUID
|
||||
from sqlalchemy.orm import Mapped, relationship
|
||||
from sqlalchemy import Date, DateTime, ForeignKey, Unicode, Uuid
|
||||
from sqlalchemy.orm import Mapped, mapped_column, relationship
|
||||
|
||||
from ..db.base_class import Base
|
||||
from ..db.base_class import reg
|
||||
|
||||
|
||||
if TYPE_CHECKING:
|
||||
# if the target of the relationship is in another module
|
||||
# that cannot normally be imported at runtime
|
||||
from .account_base import AccountBase
|
||||
from .rate_contract_item import RateContractItem
|
||||
from .user import User
|
||||
|
||||
|
||||
class RateContract(Base):
|
||||
@reg.mapped_as_dataclass(unsafe_hash=True)
|
||||
class RateContract:
|
||||
__tablename__ = "rate_contracts"
|
||||
|
||||
id: uuid.UUID = Column("id", UUID(as_uuid=True), primary_key=True, default=uuid.uuid4)
|
||||
date: datetime.date = Column("date", Date, nullable=False, index=True)
|
||||
vendor_id: uuid.UUID = Column("vendor_id", UUID(as_uuid=True), ForeignKey("accounts.id"), nullable=False)
|
||||
valid_from: Optional[datetime.date] = Column("valid_from", Date(), nullable=True)
|
||||
valid_till: Optional[datetime.date] = Column("valid_till", Date(), nullable=True)
|
||||
narration: str = Column("narration", Unicode(1000), nullable=False)
|
||||
id: Mapped[uuid.UUID] = mapped_column(Uuid, primary_key=True, insert_default=uuid.uuid4)
|
||||
date: Mapped[datetime.date] = mapped_column(Date, nullable=False, index=True)
|
||||
vendor_id: Mapped[uuid.UUID] = mapped_column(Uuid, ForeignKey("accounts.id"), nullable=False)
|
||||
valid_from: Mapped[datetime.date | None] = mapped_column(Date(), nullable=True)
|
||||
valid_till: Mapped[datetime.date | None] = mapped_column(Date(), nullable=True)
|
||||
narration: Mapped[str] = mapped_column(Unicode, nullable=False)
|
||||
|
||||
user_id: uuid.UUID = Column("user_id", UUID(as_uuid=True), ForeignKey("users.id"), nullable=False)
|
||||
creation_date: datetime.datetime = Column("creation_date", DateTime(), nullable=False)
|
||||
last_edit_date: datetime.datetime = Column("last_edit_date", DateTime(), nullable=False)
|
||||
user_id: Mapped[uuid.UUID] = mapped_column(Uuid, ForeignKey("users.id"), nullable=False)
|
||||
creation_date: Mapped[datetime.datetime] = mapped_column(DateTime(), nullable=False)
|
||||
last_edit_date: Mapped[datetime.datetime] = mapped_column(DateTime(), nullable=False)
|
||||
|
||||
user: Mapped["User"] = relationship("User")
|
||||
vendor: Mapped["AccountBase"] = relationship("AccountBase", back_populates="rate_contracts")
|
||||
items: List["RateContractItem"] = relationship("RateContractItem", back_populates="rate_contract")
|
||||
items: Mapped[list["RateContractItem"]] = relationship("RateContractItem", back_populates="rate_contract")
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
date: datetime.date,
|
||||
vendor_id: uuid.UUID,
|
||||
valid_from: Optional[datetime.date],
|
||||
valid_till: Optional[datetime.date],
|
||||
valid_from: datetime.date | None,
|
||||
valid_till: datetime.date | None,
|
||||
user_id: uuid.UUID,
|
||||
narration: str = "",
|
||||
creation_date: Optional[datetime.datetime] = None,
|
||||
last_edit_date: Optional[datetime.datetime] = None,
|
||||
id_: Optional[uuid.UUID] = None,
|
||||
creation_date: datetime.datetime | None = None,
|
||||
last_edit_date: datetime.datetime | None = None,
|
||||
id_: uuid.UUID | None = None,
|
||||
):
|
||||
self.date = date
|
||||
self.vendor_id = vendor_id
|
||||
|
||||
@@ -1,36 +1,33 @@
|
||||
import uuid
|
||||
|
||||
from decimal import Decimal
|
||||
from typing import TYPE_CHECKING, Optional
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from sqlalchemy import Column, ForeignKey, Numeric, UniqueConstraint
|
||||
from sqlalchemy.dialects.postgresql import UUID
|
||||
from sqlalchemy.orm import Mapped, relationship
|
||||
from sqlalchemy import ForeignKey, Numeric, UniqueConstraint, Uuid
|
||||
from sqlalchemy.orm import Mapped, mapped_column, relationship
|
||||
|
||||
from ..db.base_class import Base
|
||||
from ..db.base_class import reg
|
||||
|
||||
|
||||
if TYPE_CHECKING:
|
||||
# if the target of the relationship is in another module
|
||||
# that cannot normally be imported at runtime
|
||||
from .rate_contract import RateContract
|
||||
from .stock_keeping_unit import StockKeepingUnit
|
||||
|
||||
|
||||
class RateContractItem(Base):
|
||||
@reg.mapped_as_dataclass(unsafe_hash=True)
|
||||
class RateContractItem:
|
||||
__tablename__ = "rate_contract_items"
|
||||
__table_args__ = (UniqueConstraint("rate_contract_id", "sku_id"),)
|
||||
|
||||
id: uuid.UUID = Column("id", UUID(as_uuid=True), primary_key=True, default=uuid.uuid4)
|
||||
rate_contract_id: uuid.UUID = Column(
|
||||
"rate_contract_id",
|
||||
UUID(as_uuid=True),
|
||||
id: Mapped[uuid.UUID] = mapped_column(Uuid, primary_key=True, insert_default=uuid.uuid4)
|
||||
rate_contract_id: Mapped[uuid.UUID] = mapped_column(
|
||||
Uuid,
|
||||
ForeignKey("rate_contracts.id"),
|
||||
nullable=False,
|
||||
index=True,
|
||||
)
|
||||
sku_id: uuid.UUID = Column("sku_id", UUID(as_uuid=True), ForeignKey("stock_keeping_units.id"), nullable=False)
|
||||
price: Decimal = Column("cost_price", Numeric(precision=15, scale=2), nullable=False)
|
||||
sku_id: Mapped[uuid.UUID] = mapped_column(Uuid, ForeignKey("stock_keeping_units.id"), nullable=False)
|
||||
price: Mapped[Decimal] = mapped_column("cost_price", Numeric(precision=15, scale=2), nullable=False)
|
||||
|
||||
rate_contract: Mapped["RateContract"] = relationship("RateContract", back_populates="items")
|
||||
sku: Mapped["StockKeepingUnit"] = relationship("StockKeepingUnit")
|
||||
@@ -40,7 +37,7 @@ class RateContractItem(Base):
|
||||
rate_contract_id: uuid.UUID,
|
||||
sku_id: uuid.UUID,
|
||||
price: Decimal,
|
||||
id_: Optional[uuid.UUID] = None,
|
||||
id_: uuid.UUID | None = None,
|
||||
) -> None:
|
||||
self.rate_contract_id = rate_contract_id
|
||||
self.sku_id = sku_id
|
||||
|
||||
@@ -1,66 +1,42 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import datetime
|
||||
import uuid
|
||||
|
||||
from decimal import Decimal
|
||||
from typing import TYPE_CHECKING, List, Optional
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from sqlalchemy import Column, ForeignKey, Numeric, Unicode, UniqueConstraint
|
||||
from sqlalchemy.dialects.postgresql import UUID
|
||||
from sqlalchemy.orm import Mapped, relationship
|
||||
from sqlalchemy import Date, ForeignKey, Numeric, Text, UniqueConstraint, Uuid
|
||||
from sqlalchemy.orm import Mapped, mapped_column, relationship
|
||||
|
||||
from ..db.base_class import Base
|
||||
from ..db.base_class import reg
|
||||
from .recipe_tag import RecipeTag
|
||||
|
||||
|
||||
if TYPE_CHECKING:
|
||||
# if the target of the relationship is in another module
|
||||
# that cannot normally be imported at runtime
|
||||
from .period import Period
|
||||
from .recipe_item import RecipeItem
|
||||
from .stock_keeping_unit import StockKeepingUnit
|
||||
from .tag import Tag
|
||||
|
||||
|
||||
class Recipe(Base):
|
||||
@reg.mapped_as_dataclass(unsafe_hash=True)
|
||||
class Recipe:
|
||||
__tablename__ = "recipes"
|
||||
__table_args__ = (UniqueConstraint("sku_id", "period_id"),)
|
||||
__table_args__ = (UniqueConstraint("sku_id", "date"),)
|
||||
|
||||
id: uuid.UUID = Column("id", UUID(as_uuid=True), primary_key=True, default=uuid.uuid4)
|
||||
sku_id: uuid.UUID = Column("sku_id", UUID(as_uuid=True), ForeignKey("stock_keeping_units.id"), nullable=False)
|
||||
id: Mapped[uuid.UUID] = mapped_column(Uuid, primary_key=True, insert_default=uuid.uuid4)
|
||||
sku_id: Mapped[uuid.UUID] = mapped_column(Uuid, ForeignKey("stock_keeping_units.id"), nullable=False)
|
||||
date: Mapped[datetime.date] = mapped_column(Date, nullable=False, index=True)
|
||||
source: Mapped[str] = mapped_column(Text, nullable=False)
|
||||
instructions: Mapped[str] = mapped_column(Text, nullable=False)
|
||||
garnishing: Mapped[str] = mapped_column(Text, nullable=False)
|
||||
plating: Mapped[str] = mapped_column(Text, nullable=False)
|
||||
notes: Mapped[str] = mapped_column(Text, nullable=False)
|
||||
|
||||
recipe_yield: Decimal = Column("recipe_yield", Numeric(precision=15, scale=2), nullable=False)
|
||||
cost_price: Decimal = Column("cost_price", Numeric(precision=15, scale=2), nullable=False)
|
||||
sale_price: Decimal = Column("sale_price", Numeric(precision=15, scale=2), nullable=False)
|
||||
notes: str = Column("notes", Unicode(255))
|
||||
recipe_yield: Mapped[Decimal] = mapped_column(Numeric(precision=15, scale=2), nullable=False)
|
||||
|
||||
period_id: uuid.UUID = Column("period_id", UUID(as_uuid=True), ForeignKey("periods.id"), nullable=False)
|
||||
|
||||
items: List["RecipeItem"] = relationship("RecipeItem", back_populates="recipe")
|
||||
items: Mapped[list["RecipeItem"]] = relationship("RecipeItem", back_populates="recipe")
|
||||
sku: Mapped["StockKeepingUnit"] = relationship("StockKeepingUnit", back_populates="recipes")
|
||||
period: Mapped["Period"] = relationship("Period", back_populates="recipes")
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
recipe_yield: Decimal,
|
||||
cost_price: Decimal,
|
||||
sale_price: Decimal,
|
||||
period_id: Optional[uuid.UUID] = None,
|
||||
period: Optional["Period"] = None,
|
||||
notes: str = "",
|
||||
sku_id: Optional[uuid.UUID] = None,
|
||||
sku: Optional["StockKeepingUnit"] = None,
|
||||
id_: Optional[uuid.UUID] = None,
|
||||
) -> None:
|
||||
if sku_id is not None:
|
||||
self.sku_id = sku_id
|
||||
self.recipe_yield = recipe_yield
|
||||
self.cost_price = cost_price
|
||||
self.sale_price = sale_price
|
||||
if period_id is not None:
|
||||
self.period_id = period_id
|
||||
if period is not None:
|
||||
self.period_id = period.id
|
||||
self.period = period
|
||||
self.notes = notes
|
||||
if id_ is not None:
|
||||
self.id = id_
|
||||
if sku is not None:
|
||||
self.sku_id = sku.id
|
||||
self.sku = sku
|
||||
tags: Mapped[list["Tag"]] = relationship(
|
||||
"Tag", secondary=RecipeTag.__table__, order_by="Tag.name", back_populates="recipes"
|
||||
)
|
||||
@@ -1,51 +1,31 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import uuid
|
||||
|
||||
from decimal import Decimal
|
||||
from typing import TYPE_CHECKING, Optional
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from sqlalchemy import Column, ForeignKey, Numeric, UniqueConstraint
|
||||
from sqlalchemy.dialects.postgresql import UUID
|
||||
from sqlalchemy.orm import Mapped, relationship
|
||||
from sqlalchemy import ForeignKey, Numeric, Text, UniqueConstraint, Uuid
|
||||
from sqlalchemy.orm import Mapped, mapped_column, relationship
|
||||
|
||||
from ..db.base_class import Base
|
||||
from ..db.base_class import reg
|
||||
|
||||
|
||||
if TYPE_CHECKING:
|
||||
# if the target of the relationship is in another module
|
||||
# that cannot normally be imported at runtime
|
||||
from .product import Product
|
||||
from .recipe import Recipe
|
||||
|
||||
|
||||
class RecipeItem(Base):
|
||||
@reg.mapped_as_dataclass(unsafe_hash=True)
|
||||
class RecipeItem:
|
||||
__tablename__ = "recipe_items"
|
||||
__table_args__ = (UniqueConstraint("recipe_id", "product_id"),)
|
||||
|
||||
id: uuid.UUID = Column("id", UUID(as_uuid=True), primary_key=True, default=uuid.uuid4)
|
||||
recipe_id: uuid.UUID = Column("recipe_id", UUID(as_uuid=True), ForeignKey("recipes.id"), nullable=False)
|
||||
product_id: uuid.UUID = Column("product_id", UUID(as_uuid=True), ForeignKey("products.id"), nullable=False)
|
||||
quantity: Decimal = Column("quantity", Numeric(precision=15, scale=2), nullable=False)
|
||||
price: Decimal = Column("price", Numeric(precision=15, scale=5), nullable=False)
|
||||
id: Mapped[uuid.UUID] = mapped_column(Uuid, primary_key=True, insert_default=uuid.uuid4)
|
||||
recipe_id: Mapped[uuid.UUID] = mapped_column(Uuid, ForeignKey("recipes.id"), nullable=False)
|
||||
product_id: Mapped[uuid.UUID] = mapped_column(Uuid, ForeignKey("products.id"), nullable=False)
|
||||
quantity: Mapped[Decimal] = mapped_column(Numeric(precision=15, scale=2), nullable=False)
|
||||
description: Mapped[str] = mapped_column(Text, nullable=False)
|
||||
|
||||
recipe: Mapped["Recipe"] = relationship("Recipe", back_populates="items")
|
||||
product: Mapped["Product"] = relationship("Product")
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
product_id: uuid.UUID,
|
||||
quantity: Decimal,
|
||||
price: Decimal,
|
||||
recipe: Optional["Recipe"] = None,
|
||||
recipe_id: Optional[uuid.UUID] = None,
|
||||
id_: Optional[uuid.UUID] = None,
|
||||
) -> None:
|
||||
if recipe_id is not None:
|
||||
self.recipe_id = recipe_id
|
||||
self.product_id = product_id
|
||||
self.quantity = quantity
|
||||
self.price = price
|
||||
if recipe is not None:
|
||||
self.recipe_id = recipe.id
|
||||
self.recipe = recipe
|
||||
if id_ is not None:
|
||||
self.id = id_
|
||||
@@ -0,0 +1,17 @@
|
||||
import uuid
|
||||
|
||||
from sqlalchemy import UniqueConstraint, Uuid
|
||||
from sqlalchemy.orm import Mapped, mapped_column
|
||||
from sqlalchemy.schema import ForeignKey
|
||||
|
||||
from ..db.base_class import reg
|
||||
|
||||
|
||||
@reg.mapped_as_dataclass(unsafe_hash=True)
|
||||
class RecipeTag:
|
||||
__tablename__ = "recipe_tags"
|
||||
__table_args__ = (UniqueConstraint("recipe_id", "tag_id"),)
|
||||
|
||||
id: Mapped[uuid.UUID] = mapped_column(Uuid, primary_key=True, insert_default=uuid.uuid4)
|
||||
recipe_id: Mapped[uuid.UUID] = mapped_column(Uuid, ForeignKey("recipes.id"))
|
||||
tag_id: Mapped[uuid.UUID] = mapped_column(Uuid, ForeignKey("tags.id"))
|
||||
@@ -0,0 +1,30 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import uuid
|
||||
|
||||
from datetime import datetime
|
||||
|
||||
from sqlalchemy import Boolean, Date, Index, Unicode, Uuid
|
||||
from sqlalchemy.orm import Mapped, mapped_column
|
||||
|
||||
from ..db.base_class import reg
|
||||
|
||||
|
||||
@reg.mapped_as_dataclass(unsafe_hash=True)
|
||||
class RecipeTemplate:
|
||||
__tablename__ = "recipe_templates"
|
||||
|
||||
id: Mapped[uuid.UUID] = mapped_column(Uuid, primary_key=True, insert_default=uuid.uuid4)
|
||||
name: Mapped[str] = mapped_column(Unicode, unique=True, nullable=False)
|
||||
date: Mapped[datetime.date] = mapped_column(Date, nullable=False)
|
||||
text: Mapped[str] = mapped_column(Unicode, nullable=False)
|
||||
selected: Mapped[bool] = mapped_column(Boolean, nullable=False)
|
||||
|
||||
__table_args__ = (
|
||||
Index(
|
||||
"only_one_selected_template",
|
||||
"selected",
|
||||
unique=True,
|
||||
postgresql_where=(selected == True), # noqa: E712
|
||||
),
|
||||
)
|
||||
@@ -1,32 +1,25 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import uuid
|
||||
|
||||
from typing import TYPE_CHECKING, List, Optional
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from sqlalchemy import Column, Unicode
|
||||
from sqlalchemy.dialects.postgresql import UUID
|
||||
from sqlalchemy.orm import relationship
|
||||
from sqlalchemy import Unicode, Uuid
|
||||
from sqlalchemy.orm import Mapped, mapped_column, relationship
|
||||
|
||||
from ..db.base_class import Base
|
||||
from .role_permission import role_permission
|
||||
from ..db.base_class import reg
|
||||
from .role_permission import RolePermission
|
||||
|
||||
|
||||
if TYPE_CHECKING:
|
||||
# if the target of the relationship is in another module
|
||||
# that cannot normally be imported at runtime
|
||||
from .permission import Permission
|
||||
|
||||
|
||||
class Role(Base):
|
||||
@reg.mapped_as_dataclass(unsafe_hash=True)
|
||||
class Role:
|
||||
__tablename__ = "roles"
|
||||
|
||||
id: uuid.UUID = Column("id", UUID(as_uuid=True), primary_key=True, default=uuid.uuid4)
|
||||
name: str = Column("name", Unicode(255), unique=True)
|
||||
id: Mapped[uuid.UUID] = mapped_column(Uuid, primary_key=True, insert_default=uuid.uuid4)
|
||||
name: Mapped[str] = mapped_column(Unicode, unique=True)
|
||||
|
||||
permissions: List["Permission"] = relationship("Permission", secondary=role_permission, back_populates="roles")
|
||||
|
||||
def __init__(self, name: str, id_: Optional[uuid.UUID] = None) -> None:
|
||||
self.name = name
|
||||
if id_ is not None:
|
||||
self.id = id_
|
||||
permissions: Mapped[list["Permission"]] = relationship(
|
||||
"Permission", secondary=RolePermission.__table__, back_populates="roles" # type: ignore[attr-defined]
|
||||
)
|
||||
@@ -1,18 +1,16 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import uuid
|
||||
|
||||
from sqlalchemy import Column
|
||||
from sqlalchemy.dialects.postgresql import UUID
|
||||
from sqlalchemy.schema import ForeignKey, Table
|
||||
from sqlalchemy import ForeignKey, UniqueConstraint, Uuid
|
||||
from sqlalchemy.orm import Mapped, mapped_column
|
||||
|
||||
from ..db.base_class import Base
|
||||
from ..db.base_class import reg
|
||||
|
||||
|
||||
role_permission = Table(
|
||||
"role_permissions",
|
||||
Base.metadata,
|
||||
Column("id", UUID(as_uuid=True), primary_key=True, default=uuid.uuid4),
|
||||
Column("permission_id", UUID(as_uuid=True), ForeignKey("permissions.id")),
|
||||
Column("role_id", UUID(as_uuid=True), ForeignKey("roles.id")),
|
||||
)
|
||||
@reg.mapped_as_dataclass(unsafe_hash=True)
|
||||
class RolePermission:
|
||||
__tablename__ = "role_permissions"
|
||||
__table_args__ = (UniqueConstraint("permission_id", "role_id"),)
|
||||
|
||||
id: Mapped[uuid.UUID] = mapped_column(Uuid, primary_key=True, insert_default=uuid.uuid4)
|
||||
permission_id: Mapped[uuid.UUID] = mapped_column(Uuid, ForeignKey("permissions.id"), nullable=False)
|
||||
role_id: Mapped[uuid.UUID] = mapped_column(Uuid, ForeignKey("roles.id"), nullable=False)
|
||||
@@ -4,3 +4,4 @@ import enum
|
||||
class SettingType(enum.IntEnum):
|
||||
VOUCHER_LOCK = 0
|
||||
MAINTENANCE_MODE = 1
|
||||
RECIPE_TEMPLATE = 2
|
||||
@@ -1,38 +1,38 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import uuid
|
||||
|
||||
from decimal import Decimal
|
||||
from typing import TYPE_CHECKING, List, Optional
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from sqlalchemy import Column, ForeignKey, Numeric, Unicode, UniqueConstraint
|
||||
from sqlalchemy.dialects.postgresql import UUID
|
||||
from sqlalchemy.orm import Mapped, relationship
|
||||
from sqlalchemy import ForeignKey, Numeric, Unicode, UniqueConstraint, Uuid
|
||||
from sqlalchemy.orm import Mapped, mapped_column, relationship
|
||||
|
||||
from ..db.base_class import Base
|
||||
from ..db.base_class import reg
|
||||
|
||||
|
||||
if TYPE_CHECKING:
|
||||
# if the target of the relationship is in another module
|
||||
# that cannot normally be imported at runtime
|
||||
from .batch import Batch
|
||||
from .product import Product
|
||||
from .recipe import Recipe
|
||||
|
||||
|
||||
class StockKeepingUnit(Base):
|
||||
@reg.mapped_as_dataclass(unsafe_hash=True)
|
||||
class StockKeepingUnit:
|
||||
__tablename__ = "stock_keeping_units"
|
||||
__table_args__ = (UniqueConstraint("product_id", "units"),)
|
||||
|
||||
id: uuid.UUID = Column("id", UUID(as_uuid=True), primary_key=True, default=uuid.uuid4)
|
||||
product_id: uuid.UUID = Column("product_id", UUID(as_uuid=True), ForeignKey("products.id"), nullable=False)
|
||||
units: str = Column("units", Unicode(255), nullable=False)
|
||||
fraction: Decimal = Column("fraction", Numeric(precision=15, scale=5), nullable=False)
|
||||
product_yield: Decimal = Column("product_yield", Numeric(precision=15, scale=5), nullable=False)
|
||||
cost_price: Decimal = Column("cost_price", Numeric(precision=15, scale=2), nullable=False)
|
||||
sale_price: Decimal = Column("sale_price", Numeric(precision=15, scale=2), nullable=False)
|
||||
id: Mapped[uuid.UUID] = mapped_column(Uuid, primary_key=True, insert_default=uuid.uuid4)
|
||||
product_id: Mapped[uuid.UUID] = mapped_column(Uuid, ForeignKey("products.id"), nullable=False)
|
||||
units: Mapped[str] = mapped_column(Unicode, nullable=False)
|
||||
fraction: Mapped[Decimal] = mapped_column(Numeric(precision=15, scale=5), nullable=False)
|
||||
product_yield: Mapped[Decimal] = mapped_column(Numeric(precision=15, scale=5), nullable=False)
|
||||
cost_price: Mapped[Decimal] = mapped_column(Numeric(precision=15, scale=2), nullable=False)
|
||||
sale_price: Mapped[Decimal] = mapped_column(Numeric(precision=15, scale=2), nullable=False)
|
||||
|
||||
product: Mapped["Product"] = relationship("Product", back_populates="skus")
|
||||
batches: List["Batch"] = relationship("Batch", back_populates="sku")
|
||||
recipes: List["Recipe"] = relationship("Recipe", back_populates="sku")
|
||||
batches: Mapped[list["Batch"]] = relationship("Batch", back_populates="sku")
|
||||
recipes: Mapped[list["Recipe"]] = relationship("Recipe", back_populates="sku")
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
@@ -41,9 +41,9 @@ class StockKeepingUnit(Base):
|
||||
product_yield: Decimal,
|
||||
cost_price: Decimal,
|
||||
sale_price: Decimal,
|
||||
product_id: Optional[uuid.UUID] = None,
|
||||
product: Optional["Product"] = None,
|
||||
id_: Optional[uuid.UUID] = None,
|
||||
product_id: uuid.UUID | None = None,
|
||||
product: "Product" | None = None,
|
||||
id_: uuid.UUID | None = None,
|
||||
) -> None:
|
||||
if product_id is not None:
|
||||
self.product_id = product_id
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
import uuid
|
||||
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from sqlalchemy import Unicode, Uuid
|
||||
from sqlalchemy.orm import Mapped, mapped_column, relationship
|
||||
|
||||
from ..db.base_class import reg
|
||||
from .recipe_tag import RecipeTag
|
||||
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from .recipe import Recipe
|
||||
|
||||
|
||||
@reg.mapped_as_dataclass(unsafe_hash=True)
|
||||
class Tag:
|
||||
__tablename__ = "tags"
|
||||
|
||||
id: Mapped[uuid.UUID] = mapped_column(Uuid, primary_key=True, insert_default=uuid.uuid4)
|
||||
name: Mapped[str] = mapped_column(Unicode, unique=True, nullable=False)
|
||||
|
||||
recipes: Mapped[list["Recipe"]] = relationship(
|
||||
"Recipe", secondary=RecipeTag.__table__, order_by="Recipe.date", back_populates="tags"
|
||||
)
|
||||
@@ -1,47 +0,0 @@
|
||||
from datetime import datetime, timedelta, tzinfo
|
||||
|
||||
|
||||
ZERO = timedelta(0)
|
||||
HOUR = timedelta(hours=1)
|
||||
|
||||
|
||||
# A UTC class.
|
||||
|
||||
|
||||
class UTC(tzinfo):
|
||||
"""UTC"""
|
||||
|
||||
def utcoffset(self, dt):
|
||||
return ZERO
|
||||
|
||||
def tzname(self, dt):
|
||||
return "UTC"
|
||||
|
||||
def dst(self, dt):
|
||||
return ZERO
|
||||
|
||||
|
||||
utc = UTC()
|
||||
|
||||
|
||||
def get_age(old_date, now=None) -> str:
|
||||
def is_naive(date) -> bool:
|
||||
return date.tzinfo is None or date.tzinfo.utcoffset(date) is None
|
||||
|
||||
if now is None:
|
||||
now = datetime.utcnow().replace(tzinfo=utc)
|
||||
if is_naive(old_date) == is_naive(now):
|
||||
pass
|
||||
elif is_naive(old_date):
|
||||
old_date = old_date.replace(tzinfo=utc)
|
||||
else:
|
||||
now = now.replace(tzinfo=utc)
|
||||
|
||||
delta = now - old_date
|
||||
if delta.days > 0:
|
||||
return "{0} days".format(delta.days)
|
||||
if delta.seconds > 3600:
|
||||
return "{0} hours".format(delta.seconds // 3600)
|
||||
if delta.seconds > 60:
|
||||
return "{0} minutes".format(delta.seconds // 60)
|
||||
return "{0} seconds".format(delta.seconds)
|
||||
@@ -3,34 +3,38 @@ from __future__ import annotations
|
||||
import uuid
|
||||
|
||||
from hashlib import md5
|
||||
from typing import List, Optional
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from sqlalchemy import Boolean, Column, Unicode, desc, select
|
||||
from sqlalchemy.dialects.postgresql import UUID
|
||||
from sqlalchemy.orm import Session, relationship, synonym
|
||||
from sqlalchemy import Boolean, Unicode, Uuid, desc, select
|
||||
from sqlalchemy.ext.hybrid import hybrid_property
|
||||
from sqlalchemy.orm import Mapped, Session, mapped_column, relationship
|
||||
|
||||
from ..db.base_class import Base
|
||||
from ..db.base_class import reg
|
||||
from .login_history import LoginHistory
|
||||
from .role import Role
|
||||
from .user_role import user_role
|
||||
from .user_role import UserRole
|
||||
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from .role import Role
|
||||
from .voucher import Voucher
|
||||
|
||||
|
||||
def encrypt(val: str) -> str:
|
||||
return md5(val.encode("utf-8") + "Salt".encode("utf-8")).hexdigest()
|
||||
|
||||
|
||||
class User(Base):
|
||||
@reg.mapped_as_dataclass(unsafe_hash=True)
|
||||
class User:
|
||||
__tablename__ = "users"
|
||||
|
||||
id: uuid.UUID = Column("id", UUID(as_uuid=True), primary_key=True, default=uuid.uuid4)
|
||||
name: str = Column("username", Unicode(255), unique=True)
|
||||
_password: str = Column("password", Unicode(60))
|
||||
locked_out: bool = Column("disabled", Boolean)
|
||||
id: Mapped[uuid.UUID] = mapped_column(Uuid, primary_key=True, insert_default=uuid.uuid4)
|
||||
name: Mapped[str] = mapped_column("username", Unicode, unique=True, nullable=False)
|
||||
_password: Mapped[str] = mapped_column("password", Unicode, nullable=False)
|
||||
locked_out: Mapped[bool] = mapped_column("disabled", Boolean, nullable=False)
|
||||
|
||||
roles: List[Role] = relationship("Role", secondary=user_role)
|
||||
login_history: List[LoginHistory] = relationship(
|
||||
"LoginHistory", order_by=desc(LoginHistory.date), back_populates="user"
|
||||
)
|
||||
roles: Mapped[list[Role]] = relationship(secondary=UserRole.__table__) # type: ignore[attr-defined]
|
||||
login_history: Mapped[list[LoginHistory]] = relationship(order_by=desc(LoginHistory.date), back_populates="user")
|
||||
vouchers: Mapped[list[Voucher]] = relationship("Voucher", foreign_keys="Voucher.user_id", back_populates="user")
|
||||
|
||||
def _get_password(self) -> str:
|
||||
return self._password
|
||||
@@ -38,14 +42,15 @@ class User(Base):
|
||||
def _set_password(self, password: str) -> None:
|
||||
self._password = encrypt(password)
|
||||
|
||||
password = property(_get_password, _set_password) # type: ignore
|
||||
password = synonym("_password", descriptor=password)
|
||||
@hybrid_property
|
||||
def password(self) -> str:
|
||||
return self._password
|
||||
|
||||
@property
|
||||
def __name__(self) -> str:
|
||||
return self.name
|
||||
@password.inplace.setter
|
||||
def _password_setter(self, password: str) -> None:
|
||||
self._password = encrypt(password)
|
||||
|
||||
def __init__(self, name: str, password: str, locked_out: bool, id_: Optional[uuid.UUID] = None) -> None:
|
||||
def __init__(self, name: str, password: str, locked_out: bool, id_: uuid.UUID | None = None) -> None:
|
||||
self.name = name
|
||||
self.password = password
|
||||
self.locked_out = locked_out
|
||||
@@ -53,10 +58,10 @@ class User(Base):
|
||||
self.id = id_
|
||||
|
||||
@classmethod
|
||||
def auth(cls, name: str, password: str, db: Session) -> Optional[User]:
|
||||
def auth(cls, name: str, password: str, db: Session) -> "User" | None:
|
||||
if password is None:
|
||||
return None
|
||||
user: Optional[User] = db.execute(select(cls).where(cls.name.ilike(name))).scalars().one_or_none()
|
||||
user: User | None = db.execute(select(cls).where(cls.name.ilike(name))).scalars().one_or_none()
|
||||
if not user:
|
||||
return None
|
||||
if user.password != encrypt(password) or user.locked_out:
|
||||
|
||||
@@ -1,18 +1,16 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import uuid
|
||||
|
||||
from sqlalchemy import Column
|
||||
from sqlalchemy.dialects.postgresql import UUID
|
||||
from sqlalchemy.schema import ForeignKey, Table
|
||||
from sqlalchemy import ForeignKey, UniqueConstraint, Uuid
|
||||
from sqlalchemy.orm import Mapped, mapped_column
|
||||
|
||||
from ..db.base_class import Base
|
||||
from ..db.base_class import reg
|
||||
|
||||
|
||||
user_role = Table(
|
||||
"user_roles",
|
||||
Base.metadata,
|
||||
Column("id", UUID(as_uuid=True), primary_key=True, default=uuid.uuid4),
|
||||
Column("user_id", UUID(as_uuid=True), ForeignKey("users.id")),
|
||||
Column("role_id", UUID(as_uuid=True), ForeignKey("roles.id")),
|
||||
)
|
||||
@reg.mapped_as_dataclass(unsafe_hash=True)
|
||||
class UserRole:
|
||||
__tablename__ = "user_roles"
|
||||
__table_args__ = (UniqueConstraint("user_id", "role_id"),)
|
||||
|
||||
id: Mapped[uuid.UUID] = mapped_column(Uuid, primary_key=True, insert_default=uuid.uuid4)
|
||||
user_id: Mapped[uuid.UUID] = mapped_column(Uuid, ForeignKey("users.id"), nullable=False)
|
||||
role_id: Mapped[uuid.UUID] = mapped_column(Uuid, ForeignKey("roles.id"), nullable=False)
|
||||
@@ -1,19 +1,16 @@
|
||||
import datetime
|
||||
import uuid
|
||||
|
||||
from typing import TYPE_CHECKING, List, Optional
|
||||
from typing import TYPE_CHECKING, Optional
|
||||
|
||||
from sqlalchemy import Boolean, Column, Date, DateTime, Enum, ForeignKey, Unicode
|
||||
from sqlalchemy.dialects.postgresql import UUID
|
||||
from sqlalchemy.orm import Mapped, relationship
|
||||
from sqlalchemy import Boolean, Date, DateTime, Enum, ForeignKey, Unicode, Uuid
|
||||
from sqlalchemy.orm import Mapped, mapped_column, relationship
|
||||
|
||||
from ..db.base_class import Base
|
||||
from ..db.base_class import reg
|
||||
from .voucher_type import VoucherType
|
||||
|
||||
|
||||
if TYPE_CHECKING:
|
||||
# if the target of the relationship is in another module
|
||||
# that cannot normally be imported at runtime
|
||||
from .employee_benefit import EmployeeBenefit
|
||||
from .incentive import Incentive
|
||||
from .inventory import Inventory
|
||||
@@ -21,34 +18,39 @@ if TYPE_CHECKING:
|
||||
from .user import User
|
||||
|
||||
|
||||
class Voucher(Base):
|
||||
@reg.mapped_as_dataclass(unsafe_hash=True)
|
||||
class Voucher:
|
||||
__tablename__ = "vouchers"
|
||||
|
||||
id: uuid.UUID = Column("id", UUID(as_uuid=True), primary_key=True, default=uuid.uuid4)
|
||||
date: datetime.date = Column("date", Date, nullable=False, index=True)
|
||||
narration: str = Column("narration", Unicode(1000), nullable=False)
|
||||
is_reconciled: bool = Column("is_reconciled", Boolean, nullable=False)
|
||||
reconcile_date: datetime.date = Column("reconcile_date", Date, nullable=False)
|
||||
is_starred: bool = Column("is_starred", Boolean, nullable=False)
|
||||
creation_date: datetime.datetime = Column("creation_date", DateTime(), nullable=False)
|
||||
last_edit_date: datetime.datetime = Column("last_edit_date", DateTime(), nullable=False)
|
||||
voucher_type: VoucherType = Column("voucher_type", Enum(VoucherType), nullable=False)
|
||||
user_id: uuid.UUID = Column("user_id", UUID(as_uuid=True), ForeignKey("users.id"), nullable=False)
|
||||
posted: bool = Column("is_posted", Boolean, nullable=False)
|
||||
poster_id: uuid.UUID = Column("poster_id", UUID(as_uuid=True), ForeignKey("users.id"))
|
||||
id: Mapped[uuid.UUID] = mapped_column(Uuid, primary_key=True, insert_default=uuid.uuid4)
|
||||
date: Mapped[datetime.date] = mapped_column(Date, nullable=False, index=True)
|
||||
narration: Mapped[str] = mapped_column(Unicode, nullable=False)
|
||||
is_reconciled: Mapped[bool] = mapped_column(Boolean, nullable=False)
|
||||
reconcile_date: Mapped[datetime.date] = mapped_column(Date, nullable=False)
|
||||
is_starred: Mapped[bool] = mapped_column(Boolean, nullable=False)
|
||||
creation_date: Mapped[datetime.datetime] = mapped_column(DateTime(), nullable=False)
|
||||
last_edit_date: Mapped[datetime.datetime] = mapped_column(DateTime(), nullable=False)
|
||||
voucher_type: Mapped[VoucherType] = mapped_column(Enum(VoucherType), nullable=False)
|
||||
user_id: Mapped[uuid.UUID] = mapped_column(Uuid, ForeignKey("users.id"), nullable=False)
|
||||
posted: Mapped[bool] = mapped_column("is_posted", Boolean, nullable=False)
|
||||
poster_id: Mapped[uuid.UUID | None] = mapped_column(Uuid, ForeignKey("users.id"), nullable=True)
|
||||
|
||||
user: Mapped["User"] = relationship("User", primaryjoin="User.id==Voucher.user_id")
|
||||
poster: Mapped["User"] = relationship("User", primaryjoin="User.id==Voucher.poster_id")
|
||||
user: Mapped["User"] = relationship("User", foreign_keys=[user_id], back_populates="vouchers")
|
||||
poster: Mapped[Optional["User"]] = relationship("User", foreign_keys=[poster_id])
|
||||
|
||||
journals: List["Journal"] = relationship("Journal", cascade="delete, delete-orphan", back_populates="voucher")
|
||||
journals: Mapped[list["Journal"]] = relationship(
|
||||
"Journal", cascade="delete, delete-orphan", back_populates="voucher"
|
||||
)
|
||||
|
||||
inventories: List["Inventory"] = relationship(
|
||||
inventories: Mapped[list["Inventory"]] = relationship(
|
||||
"Inventory", cascade="delete, delete-orphan", back_populates="voucher"
|
||||
)
|
||||
employee_benefits: List["EmployeeBenefit"] = relationship(
|
||||
employee_benefits: Mapped[list["EmployeeBenefit"]] = relationship(
|
||||
"EmployeeBenefit", cascade="delete, delete-orphan", backref="voucher"
|
||||
)
|
||||
incentives: List["Incentive"] = relationship("Incentive", cascade="delete, delete-orphan", backref="voucher")
|
||||
incentives: Mapped[list["Incentive"]] = relationship(
|
||||
"Incentive", cascade="delete, delete-orphan", backref="voucher"
|
||||
)
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
@@ -59,10 +61,10 @@ class Voucher(Base):
|
||||
is_starred: bool = False,
|
||||
posted: bool = False,
|
||||
is_reconciled: bool = False,
|
||||
reconcile_date: Optional[datetime.date] = None,
|
||||
poster_id: Optional[uuid.UUID] = None,
|
||||
creation_date: Optional[datetime.datetime] = None,
|
||||
last_edit_date: Optional[datetime.datetime] = None,
|
||||
reconcile_date: datetime.date | None = None,
|
||||
poster_id: uuid.UUID | None = None,
|
||||
creation_date: datetime.datetime | None = None,
|
||||
last_edit_date: datetime.datetime | None = None,
|
||||
):
|
||||
self.date = date
|
||||
self.is_reconciled = is_reconciled
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
from datetime import date, timedelta
|
||||
from typing import List, Optional, Tuple
|
||||
|
||||
from sqlalchemy import or_, select
|
||||
from sqlalchemy.orm import Session
|
||||
@@ -16,12 +15,12 @@ from ..schemas.settings import (
|
||||
|
||||
|
||||
def get_lock_info(
|
||||
voucher_dates: List[date], voucher_type: VoucherType, account_types: List[int], db: Session
|
||||
) -> Tuple[bool, str]:
|
||||
voucher_dates: list[date], voucher_type: VoucherType, account_types: list[int], db: Session
|
||||
) -> tuple[bool, str]:
|
||||
date_ = date.today()
|
||||
start: Optional[date]
|
||||
finish: Optional[date]
|
||||
data: List = (
|
||||
start: date | None
|
||||
finish: date | None
|
||||
data: list = (
|
||||
db.execute(
|
||||
select(DbSetting.data).where(
|
||||
DbSetting.setting_type == SettingType.VOUCHER_LOCK,
|
||||
|
||||
@@ -2,7 +2,6 @@ import uuid
|
||||
|
||||
from datetime import date, datetime
|
||||
from decimal import Decimal
|
||||
from typing import List, Optional
|
||||
|
||||
import brewman.schemas.account as schemas
|
||||
|
||||
@@ -111,8 +110,8 @@ def show_blank(
|
||||
return account_blank(db)
|
||||
|
||||
|
||||
@router.get("/list", response_model=List[schemas.Account])
|
||||
async def show_list(user: UserToken = Depends(get_user)) -> List[schemas.Account]:
|
||||
@router.get("/list", response_model=list[schemas.Account])
|
||||
async def show_list(user: UserToken = Depends(get_user)) -> list[schemas.Account]:
|
||||
with SessionFuture() as db:
|
||||
return [
|
||||
account_info(item)
|
||||
@@ -124,16 +123,16 @@ async def show_list(user: UserToken = Depends(get_user)) -> List[schemas.Account
|
||||
]
|
||||
|
||||
|
||||
@router.get("/query", response_model=List[schemas.AccountLink])
|
||||
@router.get("/query", response_model=list[schemas.AccountLink])
|
||||
async def show_term(
|
||||
q: str,
|
||||
t: Optional[int] = None, # AccountType
|
||||
r: Optional[bool] = None, # Reconcilable
|
||||
a: Optional[bool] = None, # Active
|
||||
c: Optional[int] = None, # Count
|
||||
t: int | None = None, # AccountType
|
||||
r: bool | None = None, # Reconcilable
|
||||
a: bool | None = None, # Active
|
||||
c: int | None = None, # Count
|
||||
current_user: UserToken = Depends(get_user),
|
||||
) -> List[schemas.AccountLink]:
|
||||
list_: List[schemas.AccountLink] = []
|
||||
) -> list[schemas.AccountLink]:
|
||||
list_: list[schemas.AccountLink] = []
|
||||
with SessionFuture() as db:
|
||||
query_ = select(AccountBase)
|
||||
if t is not None:
|
||||
@@ -148,7 +147,7 @@ async def show_term(
|
||||
query_ = query_.order_by(AccountBase.name)
|
||||
if c is not None:
|
||||
query_ = query_.limit(c)
|
||||
data: List[AccountBase] = db.execute(query_).scalars().all()
|
||||
data: list[AccountBase] = db.execute(query_).scalars().all()
|
||||
|
||||
for item in data:
|
||||
list_.append(schemas.AccountLink(id=item.id, name=item.name))
|
||||
@@ -158,7 +157,7 @@ async def show_term(
|
||||
@router.get("/{id_}/balance", response_model=AccountBalance)
|
||||
async def show_balance(
|
||||
id_: uuid.UUID,
|
||||
d: Optional[str] = None,
|
||||
d: str | None = None,
|
||||
user: UserToken = Depends(get_user),
|
||||
) -> AccountBalance:
|
||||
date_ = None if d is None or d == "" else datetime.strptime(d, "%d-%b-%Y")
|
||||
@@ -176,7 +175,7 @@ def show_id(
|
||||
return account_info(item)
|
||||
|
||||
|
||||
def balance(id_: uuid.UUID, date_: Optional[date], db: Session) -> Decimal:
|
||||
def balance(id_: uuid.UUID, date_: date | None, db: Session) -> Decimal:
|
||||
account: AccountBase = db.execute(select(AccountBase).where(AccountBase.id == id_)).scalar_one()
|
||||
if not account.type_.balance_sheet:
|
||||
return Decimal(0)
|
||||
@@ -186,7 +185,7 @@ def balance(id_: uuid.UUID, date_: Optional[date], db: Session) -> Decimal:
|
||||
bal = bal.where(Voucher.date <= date_)
|
||||
|
||||
bal = bal.where(Voucher.voucher_type != VoucherType.ISSUE).where(Journal.account_id == id_)
|
||||
result: Optional[Decimal] = db.execute(bal).scalar_one_or_none()
|
||||
result: Decimal | None = db.execute(bal).scalar_one_or_none()
|
||||
return Decimal(0) if result is None else result
|
||||
|
||||
|
||||
@@ -221,7 +220,7 @@ def account_blank(db: Session) -> schemas.AccountBlank:
|
||||
|
||||
def delete_with_data(account: Account, db: Session) -> None:
|
||||
suspense_account = db.execute(select(Account).where(Account.id == Account.suspense())).scalar_one()
|
||||
query: List[Voucher] = (
|
||||
query: list[Voucher] = (
|
||||
db.execute(
|
||||
select(Voucher)
|
||||
.options(joinedload(Voucher.journals, innerjoin=True).joinedload(Journal.account, innerjoin=True))
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
from typing import List
|
||||
|
||||
import brewman.schemas.account_type as schemas
|
||||
|
||||
from fastapi import APIRouter, Depends
|
||||
@@ -14,8 +12,8 @@ from ..schemas.user import UserToken
|
||||
router = APIRouter()
|
||||
|
||||
|
||||
@router.get("", response_model=List[schemas.AccountType])
|
||||
def account_type_list(user: UserToken = Depends(get_user)) -> List[schemas.AccountType]:
|
||||
@router.get("", response_model=list[schemas.AccountType])
|
||||
def account_type_list(user: UserToken = Depends(get_user)) -> list[schemas.AccountType]:
|
||||
with SessionFuture() as db:
|
||||
return [
|
||||
schemas.AccountType(id=item.id, name=item.name) for item in db.execute(select(AccountType)).scalars().all()
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
from datetime import date, datetime, timedelta
|
||||
from typing import Generator, List
|
||||
from typing import Generator
|
||||
|
||||
import brewman.schemas.attendance as schemas
|
||||
|
||||
@@ -41,8 +41,8 @@ def attendance_date(
|
||||
)
|
||||
|
||||
|
||||
def attendance_date_report(date_: date, db: Session) -> List[schemas.AttendanceItem]:
|
||||
body: List[schemas.AttendanceItem] = []
|
||||
def attendance_date_report(date_: date, db: Session) -> list[schemas.AttendanceItem]:
|
||||
body: list[schemas.AttendanceItem] = []
|
||||
employees = (
|
||||
db.execute(
|
||||
select(Employee)
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
from typing import List
|
||||
|
||||
import brewman.schemas.attendance_type as schemas
|
||||
|
||||
from fastapi import APIRouter, Depends
|
||||
@@ -12,10 +10,10 @@ from ..schemas.user import UserToken
|
||||
router = APIRouter()
|
||||
|
||||
|
||||
@router.get("", response_model=List[schemas.AttendanceType])
|
||||
async def show_list(user: UserToken = Depends(get_user)) -> List[schemas.AttendanceType]:
|
||||
@router.get("", response_model=list[schemas.AttendanceType])
|
||||
async def show_list(user: UserToken = Depends(get_user)) -> list[schemas.AttendanceType]:
|
||||
list_ = AttendanceType.list()
|
||||
attendance_types: List[schemas.AttendanceType] = []
|
||||
attendance_types: list[schemas.AttendanceType] = []
|
||||
for item in list_:
|
||||
attendance_types.append(schemas.AttendanceType(id=item.id, name=item.name, value=item.value))
|
||||
return attendance_types
|
||||
@@ -1,7 +1,5 @@
|
||||
import datetime
|
||||
|
||||
from typing import List
|
||||
|
||||
import brewman.schemas.batch as schemas
|
||||
|
||||
from fastapi import APIRouter, Depends
|
||||
@@ -19,14 +17,14 @@ from ..schemas.user import UserToken
|
||||
router = APIRouter()
|
||||
|
||||
|
||||
@router.get("", response_model=List[schemas.Batch])
|
||||
@router.get("", response_model=list[schemas.Batch])
|
||||
def batch_term(
|
||||
q: str,
|
||||
d: str,
|
||||
current_user: UserToken = Depends(get_user),
|
||||
) -> List[schemas.Batch]:
|
||||
) -> list[schemas.Batch]:
|
||||
date_ = datetime.datetime.strptime(d, "%d-%b-%Y")
|
||||
list_: List[schemas.Batch] = []
|
||||
list_: list[schemas.Batch] = []
|
||||
with SessionFuture() as db:
|
||||
query = (
|
||||
select(Batch)
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
import uuid
|
||||
|
||||
from typing import List
|
||||
|
||||
import brewman.schemas.batch_integrity as schemas
|
||||
|
||||
from fastapi import APIRouter, Security
|
||||
@@ -24,11 +22,10 @@ from .issue import refresh_voucher
|
||||
router = APIRouter()
|
||||
|
||||
|
||||
@router.post("", response_model=List[schemas.BatchIntegrity])
|
||||
@router.post("", response_model=list[schemas.BatchIntegrity])
|
||||
def post_check_batch_integrity(
|
||||
user: UserToken = Security(get_user, scopes=["product-ledger"])
|
||||
) -> List[schemas.BatchIntegrity]:
|
||||
|
||||
) -> list[schemas.BatchIntegrity]:
|
||||
with SessionFuture() as db:
|
||||
info = negative_batches(db) + batch_dates(db)
|
||||
fix_batch_prices(db)
|
||||
@@ -36,7 +33,7 @@ def post_check_batch_integrity(
|
||||
return info
|
||||
|
||||
|
||||
def negative_batches(db: Session) -> List[schemas.BatchIntegrity]:
|
||||
def negative_batches(db: Session) -> list[schemas.BatchIntegrity]:
|
||||
inv_sum = func.sum(Inventory.quantity * Journal.debit).label("quantity")
|
||||
list_ = db.execute(
|
||||
select(Batch, Product.name, inv_sum)
|
||||
@@ -71,7 +68,7 @@ def negative_batches(db: Session) -> List[schemas.BatchIntegrity]:
|
||||
return issue
|
||||
|
||||
|
||||
def batch_details(batch_id: uuid.UUID, db: Session) -> List[schemas.BatchIntegrityItem]:
|
||||
def batch_details(batch_id: uuid.UUID, db: Session) -> list[schemas.BatchIntegrityItem]:
|
||||
list_ = db.execute(
|
||||
select(Voucher.id, Voucher.date, Voucher.voucher_type, Inventory.quantity, Inventory.rate)
|
||||
.join(Inventory.voucher)
|
||||
@@ -93,7 +90,7 @@ def batch_details(batch_id: uuid.UUID, db: Session) -> List[schemas.BatchIntegri
|
||||
]
|
||||
|
||||
|
||||
def batch_dates(db: Session) -> List[schemas.BatchIntegrity]:
|
||||
def batch_dates(db: Session) -> list[schemas.BatchIntegrity]:
|
||||
list_ = (
|
||||
db.execute(
|
||||
select(Batch)
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
import uuid
|
||||
|
||||
from typing import List
|
||||
|
||||
import brewman.schemas.client as schemas
|
||||
|
||||
from fastapi import APIRouter, HTTPException, Security, status
|
||||
@@ -57,10 +55,10 @@ def delete_route(
|
||||
)
|
||||
|
||||
|
||||
@router.get("/list", response_model=List[schemas.ClientList])
|
||||
@router.get("/list", response_model=list[schemas.ClientList])
|
||||
async def show_list(
|
||||
user: UserToken = Security(get_user, scopes=["clients"]),
|
||||
) -> List[schemas.ClientList]:
|
||||
) -> list[schemas.ClientList]:
|
||||
with SessionFuture() as db:
|
||||
list_ = db.execute(select(Client).order_by(Client.name)).scalars().all()
|
||||
clients = []
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
import uuid
|
||||
|
||||
from typing import List
|
||||
|
||||
import brewman.schemas.cost_centre as schemas
|
||||
|
||||
from fastapi import APIRouter, Depends, HTTPException, Security, status
|
||||
@@ -94,8 +92,8 @@ def show_blank(
|
||||
return cost_centre_blank()
|
||||
|
||||
|
||||
@router.get("/list", response_model=List[schemas.CostCentre])
|
||||
async def show_list(user: UserToken = Depends(get_user)) -> List[schemas.CostCentre]:
|
||||
@router.get("/list", response_model=list[schemas.CostCentre])
|
||||
async def show_list(user: UserToken = Depends(get_user)) -> list[schemas.CostCentre]:
|
||||
with SessionFuture() as db:
|
||||
return [
|
||||
cost_centre_info(item) for item in db.execute(select(CostCentre).order_by(CostCentre.name)).scalars().all()
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
from calendar import monthrange
|
||||
from datetime import date, datetime
|
||||
from decimal import Decimal
|
||||
from typing import List
|
||||
|
||||
from fastapi import APIRouter, Body, HTTPException, Security, status
|
||||
from sqlalchemy import or_, select
|
||||
@@ -49,10 +48,10 @@ def credit_salary(
|
||||
return Message(message="Salary Entry created")
|
||||
|
||||
|
||||
def salary_journals(start_date: date, finish_date: date, db: Session) -> List[Journal]:
|
||||
def salary_journals(start_date: date, finish_date: date, db: Session) -> list[Journal]:
|
||||
days = monthrange(start_date.year, start_date.month)[1]
|
||||
amount = Decimal(0)
|
||||
journals: List[Journal] = []
|
||||
journals: list[Journal] = []
|
||||
employees = (
|
||||
db.execute(
|
||||
select(Employee)
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import uuid
|
||||
|
||||
from io import BytesIO
|
||||
from typing import List
|
||||
|
||||
import brewman.schemas.image_upload as output
|
||||
|
||||
@@ -28,7 +27,7 @@ def db_image(id_: uuid.UUID, type_: str) -> StreamingResponse:
|
||||
return StreamingResponse(item, media_type="image/jpeg")
|
||||
|
||||
|
||||
def save_files(voucher_id: uuid.UUID, i: List[bytes], t: List[bytes], db: Session) -> None:
|
||||
def save_files(voucher_id: uuid.UUID, i: list[bytes], t: list[bytes], db: Session) -> None:
|
||||
i = i or []
|
||||
t = t or []
|
||||
for index, value in enumerate(i):
|
||||
@@ -37,9 +36,9 @@ def save_files(voucher_id: uuid.UUID, i: List[bytes], t: List[bytes], db: Sessio
|
||||
|
||||
def update_files(
|
||||
voucher_id: uuid.UUID,
|
||||
data: List[output.ImageUpload],
|
||||
i: List[bytes],
|
||||
t: List[bytes],
|
||||
data: list[output.ImageUpload],
|
||||
i: list[bytes],
|
||||
t: list[bytes],
|
||||
db: Session,
|
||||
) -> None:
|
||||
i = i or []
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import uuid
|
||||
|
||||
from datetime import datetime
|
||||
from typing import List, Optional
|
||||
|
||||
import brewman.schemas.employee as schemas
|
||||
|
||||
@@ -111,8 +110,8 @@ def show_blank(
|
||||
return employee_blank()
|
||||
|
||||
|
||||
@router.get("/list", response_model=List[schemas.Employee])
|
||||
async def show_list(user: UserToken = Depends(get_user)) -> List[schemas.Employee]:
|
||||
@router.get("/list", response_model=list[schemas.Employee])
|
||||
async def show_list(user: UserToken = Depends(get_user)) -> list[schemas.Employee]:
|
||||
with SessionFuture() as db:
|
||||
return [
|
||||
employee_info(item)
|
||||
@@ -128,13 +127,13 @@ async def show_list(user: UserToken = Depends(get_user)) -> List[schemas.Employe
|
||||
]
|
||||
|
||||
|
||||
@router.get("/query", response_model=List[schemas.EmployeeLink])
|
||||
@router.get("/query", response_model=list[schemas.EmployeeLink])
|
||||
async def show_term(
|
||||
q: str,
|
||||
c: Optional[int] = None,
|
||||
c: int | None = None,
|
||||
current_user: UserToken = Depends(get_user),
|
||||
) -> List[schemas.EmployeeLink]:
|
||||
list_: List[schemas.EmployeeLink] = []
|
||||
) -> list[schemas.EmployeeLink]:
|
||||
list_: list[schemas.EmployeeLink] = []
|
||||
with SessionFuture() as db:
|
||||
query_ = select(Employee)
|
||||
if q is not None:
|
||||
@@ -143,7 +142,7 @@ async def show_term(
|
||||
query_ = query_.order_by(Employee.name)
|
||||
if c is not None:
|
||||
query_ = query_.limit(c)
|
||||
data: List[Employee] = db.execute(query_).scalars().all()
|
||||
data: list[Employee] = db.execute(query_).scalars().all()
|
||||
|
||||
for item in data:
|
||||
list_.append(
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import uuid
|
||||
|
||||
from datetime import date, datetime
|
||||
from typing import List, Optional
|
||||
|
||||
import brewman.schemas.employee_attendance as schemas
|
||||
|
||||
@@ -39,8 +38,8 @@ def show_blank(
|
||||
def employee_attendance_report(
|
||||
id_: uuid.UUID,
|
||||
request: Request,
|
||||
s: Optional[str] = None,
|
||||
f: Optional[str] = None,
|
||||
s: str | None = None,
|
||||
f: str | None = None,
|
||||
user: UserToken = Security(get_user, scopes=["attendance"]),
|
||||
) -> schemas.EmployeeAttendance:
|
||||
with SessionFuture() as db:
|
||||
@@ -62,7 +61,7 @@ def employee_attendance_report(
|
||||
|
||||
def employee_attendance(
|
||||
employee: Employee, start_date: date, finish_date: date, db: Session
|
||||
) -> List[schemas.EmployeeAttendanceItem]:
|
||||
) -> list[schemas.EmployeeAttendanceItem]:
|
||||
list_ = []
|
||||
for item in date_range(start_date, finish_date, inclusive=True):
|
||||
att = (
|
||||
|
||||
@@ -3,7 +3,6 @@ import uuid
|
||||
from datetime import date, datetime
|
||||
from decimal import Decimal
|
||||
from math import ceil
|
||||
from typing import List, Tuple
|
||||
|
||||
import brewman.schemas.input as schema_in
|
||||
import brewman.schemas.voucher as output
|
||||
@@ -38,8 +37,8 @@ router = APIRouter()
|
||||
def save_route(
|
||||
request: Request,
|
||||
data: schema_in.EmployeeBenefitIn = Depends(schema_in.EmployeeBenefitIn.load_form),
|
||||
i: List[bytes] = File(None),
|
||||
t: List[bytes] = File(None),
|
||||
i: list[bytes] = File(None),
|
||||
t: list[bytes] = File(None),
|
||||
user: UserToken = Security(get_user, scopes=["employee-benefit"]),
|
||||
) -> output.Voucher:
|
||||
try:
|
||||
@@ -91,10 +90,10 @@ def save(data: schema_in.EmployeeBenefitIn, date_: date, user: UserToken, db: Se
|
||||
|
||||
def save_employee_benefits(
|
||||
voucher: Voucher,
|
||||
employee_benefits: List[EmployeeBenefitSchema],
|
||||
employee_benefits: list[EmployeeBenefitSchema],
|
||||
days_in_month: int,
|
||||
db: Session,
|
||||
) -> Tuple[int, int]:
|
||||
) -> tuple[int, int]:
|
||||
total_exp, total_total = 0, 0
|
||||
for item in employee_benefits:
|
||||
account = db.execute(select(Employee).where(Employee.id == item.employee.id_)).scalar_one()
|
||||
@@ -152,8 +151,8 @@ def update_route(
|
||||
id_: uuid.UUID,
|
||||
request: Request,
|
||||
data: schema_in.EmployeeBenefitIn = Depends(schema_in.EmployeeBenefitIn.load_form),
|
||||
i: List[bytes] = File(None),
|
||||
t: List[bytes] = File(None),
|
||||
i: list[bytes] = File(None),
|
||||
t: list[bytes] = File(None),
|
||||
user: UserToken = Security(get_user, scopes=["employee-benefit"]),
|
||||
) -> output.Voucher:
|
||||
try:
|
||||
@@ -210,10 +209,10 @@ def update_voucher(id_: uuid.UUID, data: schema_in.EmployeeBenefitIn, user: User
|
||||
|
||||
def update_employee_benefits(
|
||||
voucher: Voucher,
|
||||
employee_benefits: List[EmployeeBenefitSchema],
|
||||
employee_benefits: list[EmployeeBenefitSchema],
|
||||
days_in_month: int,
|
||||
db: Session,
|
||||
) -> Tuple[int, int]:
|
||||
) -> tuple[int, int]:
|
||||
exp, total = 0, 0
|
||||
for i in range(len(voucher.employee_benefits), 0, -1):
|
||||
item = voucher.employee_benefits[i - 1]
|
||||
@@ -262,7 +261,7 @@ def show_blank(
|
||||
return blank_voucher(additional_info, db)
|
||||
|
||||
|
||||
def esi_contribution(gross_salary: int, days_worked: int, days_in_month: int) -> Tuple[int, int, int]:
|
||||
def esi_contribution(gross_salary: int, days_worked: int, days_in_month: int) -> tuple[int, int, int]:
|
||||
limit = 21000
|
||||
employee_rate = 0.0175
|
||||
employer_rate = 0.0475
|
||||
@@ -271,7 +270,7 @@ def esi_contribution(gross_salary: int, days_worked: int, days_in_month: int) ->
|
||||
return employee, employer, employee + employer
|
||||
|
||||
|
||||
def pf_contribution(gross_salary: int, days_worked: int, days_in_month: int) -> Tuple[int, int, int]:
|
||||
def pf_contribution(gross_salary: int, days_worked: int, days_in_month: int) -> tuple[int, int, int]:
|
||||
limit = 15000
|
||||
employee_rate = 0.12
|
||||
employer_rate = 0.12 + 0.011 + 0.005 + 0.0001
|
||||
|
||||
@@ -4,7 +4,6 @@ import uuid
|
||||
|
||||
from datetime import date, datetime, time, timedelta
|
||||
from io import StringIO
|
||||
from typing import Dict, List, Tuple
|
||||
|
||||
import brewman.schemas.fingerprint as schemas
|
||||
|
||||
@@ -33,7 +32,7 @@ def upload_prints(
|
||||
with SessionFuture() as db:
|
||||
start = date.today() - timedelta(days=90)
|
||||
finish = date.today() + timedelta(days=7)
|
||||
employees: Dict[int, uuid.UUID] = {}
|
||||
employees: dict[int, uuid.UUID] = {}
|
||||
for id_, code in db.execute(select(Employee.id, Employee.code)).all():
|
||||
employees[code] = id_
|
||||
file_data = read_file(fingerprints)
|
||||
@@ -80,8 +79,8 @@ def read_file(input_file: UploadFile) -> io.StringIO:
|
||||
return StringIO(output.decode(encoding))
|
||||
|
||||
|
||||
def fp(file_data: StringIO, employees: Dict[int, uuid.UUID]) -> List[schemas.Fingerprint]:
|
||||
fingerprints: List[schemas.Fingerprint] = []
|
||||
def fp(file_data: StringIO, employees: dict[int, uuid.UUID]) -> list[schemas.Fingerprint]:
|
||||
fingerprints: list[schemas.Fingerprint] = []
|
||||
reader = csv.reader(file_data, delimiter="\t")
|
||||
header = next(reader)
|
||||
employee_column = 2
|
||||
@@ -104,7 +103,7 @@ def fp(file_data: StringIO, employees: Dict[int, uuid.UUID]) -> List[schemas.Fin
|
||||
return fingerprints
|
||||
|
||||
|
||||
def get_prints(employee_id: uuid.UUID, date_: date, db: Session) -> Tuple[str, str, bool]:
|
||||
def get_prints(employee_id: uuid.UUID, date_: date, db: Session) -> tuple[str, str, bool]:
|
||||
prints = (
|
||||
db.execute(
|
||||
select(Fingerprint)
|
||||
@@ -144,7 +143,7 @@ def get_prints(employee_id: uuid.UUID, date_: date, db: Session) -> Tuple[str, s
|
||||
)
|
||||
|
||||
|
||||
def working_hours(delta: timedelta) -> Tuple[str, bool]:
|
||||
def working_hours(delta: timedelta) -> tuple[str, bool]:
|
||||
minutes = (delta.seconds // 60) % 60
|
||||
minutes = int(5 * round(float(minutes) / 5))
|
||||
hours = delta.seconds // 3600
|
||||
|
||||
@@ -2,7 +2,6 @@ import uuid
|
||||
|
||||
from datetime import date, datetime
|
||||
from decimal import Decimal
|
||||
from typing import List, Optional
|
||||
|
||||
import brewman.schemas.input as schema_in
|
||||
import brewman.schemas.voucher as output
|
||||
@@ -88,7 +87,7 @@ def save(data: schema_in.IncentiveIn, user: UserToken, db: Session) -> Voucher:
|
||||
|
||||
def save_incentives(
|
||||
voucher: Voucher,
|
||||
employees: List[schema_in.IncentiveEmployee],
|
||||
employees: list[schema_in.IncentiveEmployee],
|
||||
point_value: Decimal,
|
||||
db: Session,
|
||||
) -> None:
|
||||
@@ -170,7 +169,7 @@ def update_voucher(id_: uuid.UUID, data: schema_in.IncentiveIn, user: UserToken,
|
||||
|
||||
def update_incentives(
|
||||
voucher: Voucher,
|
||||
employees: List[schema_in.IncentiveEmployee],
|
||||
employees: list[schema_in.IncentiveEmployee],
|
||||
point_value: Decimal,
|
||||
db: Session,
|
||||
) -> None:
|
||||
@@ -206,7 +205,7 @@ def get_id(
|
||||
@router.get("", response_model=output.Voucher)
|
||||
def show_blank(
|
||||
request: Request,
|
||||
d: Optional[str] = None,
|
||||
d: str | None = None,
|
||||
user: UserToken = Security(get_user, scopes=["incentive"]),
|
||||
) -> output.Voucher:
|
||||
additional_info = BlankVoucherInfo(date=d or get_date(request.session), type=VoucherType.INCENTIVE)
|
||||
@@ -217,10 +216,10 @@ def show_blank(
|
||||
def get_employees(
|
||||
start_date: date,
|
||||
finish_date: date,
|
||||
incentives: List[IncentiveSchema],
|
||||
journals: Optional[List[Journal]],
|
||||
incentives: list[IncentiveSchema],
|
||||
journals: list[Journal] | None,
|
||||
db: Session,
|
||||
) -> List[schema_in.IncentiveEmployee]:
|
||||
) -> list[schema_in.IncentiveEmployee]:
|
||||
details = []
|
||||
employees = (
|
||||
db.execute(
|
||||
@@ -260,7 +259,7 @@ def get_employees(
|
||||
return details
|
||||
|
||||
|
||||
def balance(date_: date, voucher_id: Optional[uuid.UUID], db: Session) -> Decimal:
|
||||
def balance(date_: date, voucher_id: uuid.UUID | None, db: Session) -> Decimal:
|
||||
amount = (
|
||||
select(func.sum(Journal.amount * Journal.debit))
|
||||
.join(Journal.voucher)
|
||||
@@ -278,14 +277,14 @@ def balance(date_: date, voucher_id: Optional[uuid.UUID], db: Session) -> Decima
|
||||
)
|
||||
if voucher_id is not None:
|
||||
amount = amount.where(Voucher.id != voucher_id)
|
||||
result: Optional[Decimal] = db.execute(amount).scalar_one_or_none()
|
||||
result: Decimal | None = db.execute(amount).scalar_one_or_none()
|
||||
return Decimal(0) if result is None else result * -1
|
||||
|
||||
|
||||
def check_if_employees_changed(
|
||||
json: List[IncentiveSchema],
|
||||
db: List[Employee],
|
||||
voucher: Optional[List[Journal]],
|
||||
json: list[IncentiveSchema],
|
||||
db: list[Employee],
|
||||
voucher: list[Journal] | None,
|
||||
) -> None:
|
||||
json_ids = set(x.employee_id for x in json)
|
||||
db_ids = set(x.id for x in db)
|
||||
|
||||
@@ -2,7 +2,6 @@ import uuid
|
||||
|
||||
from datetime import datetime
|
||||
from decimal import Decimal
|
||||
from typing import List, Optional, Tuple
|
||||
|
||||
import brewman.schemas.input as schema_in
|
||||
import brewman.schemas.voucher as output
|
||||
@@ -46,8 +45,8 @@ router = APIRouter()
|
||||
def save_route(
|
||||
request: Request,
|
||||
data: schema_in.IssueIn = Depends(schema_in.IssueIn.load_form),
|
||||
i: List[bytes] = File(None),
|
||||
t: List[bytes] = File(None),
|
||||
i: list[bytes] = File(None),
|
||||
t: list[bytes] = File(None),
|
||||
user: UserToken = Security(get_user, scopes=["issue"]),
|
||||
) -> output.Voucher:
|
||||
try:
|
||||
@@ -69,7 +68,7 @@ def save_route(
|
||||
)
|
||||
|
||||
|
||||
def save(data: schema_in.IssueIn, user: UserToken, db: Session) -> Tuple[Voucher, Optional[bool]]:
|
||||
def save(data: schema_in.IssueIn, user: UserToken, db: Session) -> tuple[Voucher, bool | None]:
|
||||
product_accounts = (
|
||||
select(Product.account_id)
|
||||
.join(Product.skus)
|
||||
@@ -98,7 +97,7 @@ def save(data: schema_in.IssueIn, user: UserToken, db: Session) -> Tuple[Voucher
|
||||
detail="Source cannot be the same as destination",
|
||||
)
|
||||
|
||||
batch_consumed: Optional[bool]
|
||||
batch_consumed: bool | None
|
||||
if data.source.id_ == CostCentre.cost_centre_purchase():
|
||||
batch_consumed = True
|
||||
elif data.destination.id_ == CostCentre.cost_centre_purchase():
|
||||
@@ -110,8 +109,8 @@ def save(data: schema_in.IssueIn, user: UserToken, db: Session) -> Tuple[Voucher
|
||||
|
||||
def save_inventories(
|
||||
voucher: Voucher,
|
||||
inventories: List[InventorySchema],
|
||||
batch_consumed: Optional[bool],
|
||||
inventories: list[InventorySchema],
|
||||
batch_consumed: bool | None,
|
||||
db: Session,
|
||||
) -> Decimal:
|
||||
amount: Decimal = Decimal(0)
|
||||
@@ -179,8 +178,8 @@ def update_route(
|
||||
id_: uuid.UUID,
|
||||
request: Request,
|
||||
data: schema_in.IssueIn = Depends(schema_in.IssueIn.load_form),
|
||||
i: List[bytes] = File(None),
|
||||
t: List[bytes] = File(None),
|
||||
i: list[bytes] = File(None),
|
||||
t: list[bytes] = File(None),
|
||||
user: UserToken = Security(get_user, scopes=["issue"]),
|
||||
) -> output.Voucher:
|
||||
try:
|
||||
@@ -204,7 +203,7 @@ def update_route(
|
||||
|
||||
def update_voucher(
|
||||
id_: uuid.UUID, data: schema_in.IssueIn, user: UserToken, db: Session
|
||||
) -> Tuple[Voucher, Optional[bool]]:
|
||||
) -> tuple[Voucher, bool | None]:
|
||||
voucher: Voucher = db.execute(select(Voucher).where(Voucher.id == id_)).scalar_one()
|
||||
product_accounts = (
|
||||
select(Product.account_id)
|
||||
@@ -243,7 +242,7 @@ def update_voucher(
|
||||
else:
|
||||
source = item.cost_centre_id
|
||||
|
||||
old_batch_consumed: Optional[bool]
|
||||
old_batch_consumed: bool | None
|
||||
if source == CostCentre.cost_centre_purchase():
|
||||
old_batch_consumed = True
|
||||
elif destination == CostCentre.cost_centre_purchase():
|
||||
@@ -251,7 +250,7 @@ def update_voucher(
|
||||
else:
|
||||
old_batch_consumed = None
|
||||
|
||||
new_batch_consumed: Optional[bool]
|
||||
new_batch_consumed: bool | None
|
||||
if data.source.id_ == CostCentre.cost_centre_purchase():
|
||||
new_batch_consumed = True
|
||||
elif data.destination.id_ == CostCentre.cost_centre_purchase():
|
||||
@@ -269,8 +268,8 @@ def update_voucher(
|
||||
|
||||
def update_inventories(
|
||||
voucher: Voucher,
|
||||
inventories: List[InventorySchema],
|
||||
batch_consumed: Optional[bool],
|
||||
inventories: list[InventorySchema],
|
||||
batch_consumed: bool | None,
|
||||
db: Session,
|
||||
) -> Decimal:
|
||||
amount: Decimal = Decimal(0)
|
||||
@@ -381,9 +380,9 @@ def get_id(
|
||||
@router.get("", response_model=output.Voucher)
|
||||
def show_blank(
|
||||
request: Request,
|
||||
date: Optional[str] = None,
|
||||
source: Optional[uuid.UUID] = None,
|
||||
destination: Optional[uuid.UUID] = None,
|
||||
date: str | None = None,
|
||||
source: uuid.UUID | None = None,
|
||||
destination: uuid.UUID | None = None,
|
||||
user: UserToken = Security(get_user, scopes=["issue"]),
|
||||
) -> output.Voucher:
|
||||
date_ = date or get_date(request.session)
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
from datetime import date, datetime
|
||||
from typing import List
|
||||
|
||||
from fastapi import APIRouter, Security
|
||||
from sqlalchemy import select
|
||||
@@ -16,18 +15,18 @@ from ..schemas.user import UserToken
|
||||
router = APIRouter()
|
||||
|
||||
|
||||
@router.get("/{date_}", response_model=List[IssueGridItem])
|
||||
@router.get("/{date_}", response_model=list[IssueGridItem])
|
||||
def grid_date(
|
||||
date_: str,
|
||||
user: UserToken = Security(get_user, scopes=["issue"]),
|
||||
) -> List[IssueGridItem]:
|
||||
) -> list[IssueGridItem]:
|
||||
date_obj = datetime.strptime(date_, "%d-%b-%Y")
|
||||
with SessionFuture() as db:
|
||||
return get_grid(date_obj, db)
|
||||
|
||||
|
||||
def get_grid(date_: date, db: Session) -> List[IssueGridItem]:
|
||||
list_: List[IssueGridItem] = []
|
||||
def get_grid(date_: date, db: Session) -> list[IssueGridItem]:
|
||||
list_: list[IssueGridItem] = []
|
||||
query = (
|
||||
db.execute(
|
||||
select(Voucher)
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import uuid
|
||||
|
||||
from datetime import datetime
|
||||
from typing import List, Optional
|
||||
|
||||
import brewman.schemas.input as schema_in
|
||||
import brewman.schemas.voucher as output
|
||||
@@ -34,8 +33,8 @@ router = APIRouter()
|
||||
def save_route(
|
||||
request: Request,
|
||||
data: schema_in.JournalIn = Depends(schema_in.JournalIn.load_form),
|
||||
i: List[bytes] = File(None),
|
||||
t: List[bytes] = File(None),
|
||||
i: list[bytes] = File(None),
|
||||
t: list[bytes] = File(None),
|
||||
user: UserToken = Security(get_user, scopes=["journal"]),
|
||||
) -> output.Voucher:
|
||||
try:
|
||||
@@ -95,8 +94,8 @@ def update_route(
|
||||
id_: uuid.UUID,
|
||||
request: Request,
|
||||
data: schema_in.JournalIn = Depends(schema_in.JournalIn.load_form),
|
||||
i: List[bytes] = File(None),
|
||||
t: List[bytes] = File(None),
|
||||
i: list[bytes] = File(None),
|
||||
t: list[bytes] = File(None),
|
||||
user: UserToken = Security(get_user, scopes=["journal"]),
|
||||
) -> output.Voucher:
|
||||
try:
|
||||
@@ -190,7 +189,7 @@ def get_id(
|
||||
@router.get("", response_model=output.Voucher)
|
||||
def show_blank(
|
||||
request: Request,
|
||||
a: Optional[uuid.UUID] = None,
|
||||
a: uuid.UUID | None = None,
|
||||
user: UserToken = Security(get_user, scopes=["journal"]),
|
||||
) -> output.Voucher:
|
||||
if request.scope.get("path") == "/api/payment":
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
import uuid
|
||||
|
||||
from typing import List
|
||||
|
||||
from fastapi import APIRouter, Security
|
||||
from sqlalchemy import delete, select
|
||||
from sqlalchemy.orm import Session
|
||||
@@ -24,11 +22,11 @@ from ..schemas.user import UserToken
|
||||
router = APIRouter()
|
||||
|
||||
|
||||
@router.post("", response_model=List[LockInformation])
|
||||
@router.post("", response_model=list[LockInformation])
|
||||
def post(
|
||||
data_in: LockInformation,
|
||||
user: UserToken = Security(get_user, scopes=["lock-date"]),
|
||||
) -> List[LockInformation]:
|
||||
) -> list[LockInformation]:
|
||||
id_ = uuid.uuid4()
|
||||
data_in.id_ = id_
|
||||
data_dict = data_in.dict()
|
||||
@@ -49,26 +47,26 @@ def post(
|
||||
return get_info(db)
|
||||
|
||||
|
||||
@router.delete("/{id_}", response_model=List[LockInformation])
|
||||
@router.delete("/{id_}", response_model=list[LockInformation])
|
||||
def delete_route(
|
||||
id_: uuid.UUID,
|
||||
user: UserToken = Security(get_user, scopes=["lock-date"]),
|
||||
) -> List[LockInformation]:
|
||||
) -> list[LockInformation]:
|
||||
with SessionFuture() as db:
|
||||
db.execute(delete(DbSetting).where(DbSetting.id == id_))
|
||||
db.commit()
|
||||
return get_info(db)
|
||||
|
||||
|
||||
@router.get("", response_model=List[LockInformation])
|
||||
@router.get("", response_model=list[LockInformation])
|
||||
def get(
|
||||
user: UserToken = Security(get_user),
|
||||
) -> List[LockInformation]:
|
||||
) -> list[LockInformation]:
|
||||
with SessionFuture() as db:
|
||||
return get_info(db)
|
||||
|
||||
|
||||
def get_info(db: Session) -> List[LockInformation]:
|
||||
def get_info(db: Session) -> list[LockInformation]:
|
||||
data = db.execute(select(DbSetting.data).where(DbSetting.setting_type == SettingType.VOUCHER_LOCK)).scalars().all()
|
||||
return [
|
||||
LockInformation(
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
from datetime import datetime, timedelta
|
||||
from typing import Union
|
||||
|
||||
from fastapi import (
|
||||
APIRouter,
|
||||
@@ -39,7 +38,7 @@ async def login_for_access_token(
|
||||
form_data: OAuth2PasswordRequestForm = Depends(),
|
||||
client_id: int = Cookie(None),
|
||||
otp: int = Form(None),
|
||||
) -> Union[Token, JSONResponse]:
|
||||
) -> Token | JSONResponse:
|
||||
with SessionFuture() as db:
|
||||
user = authenticate_user(form_data.username, form_data.password, db)
|
||||
if not user:
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
from typing import Optional
|
||||
|
||||
from fastapi import APIRouter, Security
|
||||
from sqlalchemy import select
|
||||
from sqlalchemy.orm import Session
|
||||
@@ -31,7 +29,7 @@ def set_maintenance(
|
||||
user: UserToken = Security(get_user, scopes=["maintenance"]),
|
||||
) -> Maintenance:
|
||||
with SessionFuture() as db:
|
||||
maintenance: Optional[DbSetting] = db.execute(
|
||||
maintenance: DbSetting | None = db.execute(
|
||||
select(DbSetting).where(DbSetting.name == "Maintenance")
|
||||
).scalar_one_or_none()
|
||||
if maintenance is None:
|
||||
@@ -51,7 +49,7 @@ def set_maintenance(
|
||||
return info(maintenance, db)
|
||||
|
||||
|
||||
def info(data: Optional[DbSetting], db: Session) -> Maintenance:
|
||||
def info(data: DbSetting | None, db: Session) -> Maintenance:
|
||||
if data is None:
|
||||
return Maintenance(enabled=False, user="")
|
||||
user = db.execute(select(User).where(User.id == data.data["id"])).scalar_one()
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
import uuid
|
||||
|
||||
from typing import List
|
||||
|
||||
import brewman.schemas.period as schemas
|
||||
|
||||
from fastapi import APIRouter, Depends, HTTPException, Request, Security, status
|
||||
@@ -75,8 +73,8 @@ def show_blank(
|
||||
return period_blank(request)
|
||||
|
||||
|
||||
@router.get("/list", response_model=List[schemas.Period])
|
||||
async def show_list(user: UserToken = Depends(get_user)) -> List[schemas.Period]:
|
||||
@router.get("/list", response_model=list[schemas.Period])
|
||||
async def show_list(user: UserToken = Depends(get_user)) -> list[schemas.Period]:
|
||||
with SessionFuture() as db:
|
||||
return [
|
||||
period_info(item) for item in db.execute(select(Period).order_by(desc(Period.valid_from))).scalars().all()
|
||||
|
||||
@@ -2,14 +2,13 @@ import uuid
|
||||
|
||||
from datetime import datetime
|
||||
from decimal import Decimal
|
||||
from typing import List, Optional
|
||||
|
||||
import brewman.schemas.product as schemas
|
||||
|
||||
from fastapi import APIRouter, Depends, HTTPException, Security, status
|
||||
from sqlalchemy import delete, desc, func, or_, select
|
||||
from sqlalchemy.exc import SQLAlchemyError
|
||||
from sqlalchemy.orm import Session, contains_eager, joinedload
|
||||
from sqlalchemy.orm import Session, contains_eager
|
||||
|
||||
from ..core.security import get_current_active_user as get_user
|
||||
from ..db.session import SessionFuture
|
||||
@@ -166,8 +165,8 @@ def show_blank(
|
||||
return product_blank()
|
||||
|
||||
|
||||
@router.get("/list", response_model=List[schemas.Product])
|
||||
def show_list(user: UserToken = Depends(get_user)) -> List[schemas.Product]:
|
||||
@router.get("/list", response_model=list[schemas.Product])
|
||||
def show_list(user: UserToken = Depends(get_user)) -> list[schemas.Product]:
|
||||
with SessionFuture() as db:
|
||||
return [
|
||||
product_info(item)
|
||||
@@ -179,8 +178,6 @@ def show_list(user: UserToken = Depends(get_user)) -> List[schemas.Product]:
|
||||
.order_by(Product.product_group_id)
|
||||
.order_by(Product.name)
|
||||
.options(
|
||||
joinedload(Product.skus, innerjoin=True),
|
||||
joinedload(Product.product_group, innerjoin=True),
|
||||
contains_eager(Product.skus),
|
||||
contains_eager(Product.product_group),
|
||||
)
|
||||
@@ -191,15 +188,15 @@ def show_list(user: UserToken = Depends(get_user)) -> List[schemas.Product]:
|
||||
]
|
||||
|
||||
|
||||
@router.get("/q-sku", response_model=List[ProductSku])
|
||||
@router.get("/q-sku", response_model=list[ProductSku])
|
||||
async def show_term_sku(
|
||||
q: Optional[str] = None, # Query
|
||||
a: Optional[bool] = None, # Active
|
||||
p: Optional[bool] = None, # Is Purchased?
|
||||
v: Optional[uuid.UUID] = None, # Vendor
|
||||
d: Optional[str] = None, # Date
|
||||
q: str | None = None, # Query
|
||||
a: bool | None = None, # Active
|
||||
p: bool | None = None, # Is Purchased?
|
||||
v: uuid.UUID | None = None, # Vendor
|
||||
d: str | None = None, # Date
|
||||
current_user: UserToken = Depends(get_user),
|
||||
) -> List[ProductSku]:
|
||||
) -> list[ProductSku]:
|
||||
list_ = []
|
||||
with SessionFuture() as db:
|
||||
query_ = select(Product).join(Product.skus).options(contains_eager(Product.skus))
|
||||
@@ -231,13 +228,13 @@ async def show_term_sku(
|
||||
return list_
|
||||
|
||||
|
||||
@router.get("/q-product", response_model=List[ProductSku])
|
||||
@router.get("/q-product", response_model=list[ProductSku])
|
||||
async def show_term_product(
|
||||
q: str | None = None, # Query
|
||||
a: bool | None = None, # Active
|
||||
p: bool | None = None, # Is Purchased?
|
||||
current_user: UserToken = Depends(get_user),
|
||||
) -> List[ProductSku]:
|
||||
) -> list[ProductSku]:
|
||||
list_ = []
|
||||
with SessionFuture() as db:
|
||||
query_ = select(Product)
|
||||
@@ -312,7 +309,7 @@ def product_blank() -> schemas.ProductBlank:
|
||||
)
|
||||
|
||||
|
||||
def get_rc_price(id_: uuid.UUID, d: Optional[str], v: Optional[uuid.UUID], db: Session) -> Optional[Decimal]:
|
||||
def get_rc_price(id_: uuid.UUID, d: str | None, v: uuid.UUID | None, db: Session) -> Decimal | None:
|
||||
if d is None or v is None:
|
||||
return None
|
||||
date_ = datetime.strptime(d, "%d-%b-%Y")
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
import uuid
|
||||
|
||||
from typing import List
|
||||
|
||||
import brewman.schemas.product_group as schemas
|
||||
|
||||
from fastapi import APIRouter, Depends, HTTPException, Security, status
|
||||
@@ -91,8 +89,8 @@ def show_blank(
|
||||
return product_group_blank()
|
||||
|
||||
|
||||
@router.get("/list", response_model=List[schemas.ProductGroup])
|
||||
async def show_list(user: UserToken = Depends(get_user)) -> List[schemas.ProductGroup]:
|
||||
@router.get("/list", response_model=list[schemas.ProductGroup])
|
||||
async def show_list(user: UserToken = Depends(get_user)) -> list[schemas.ProductGroup]:
|
||||
with SessionFuture() as db:
|
||||
return [
|
||||
product_group_info(item)
|
||||
|
||||
@@ -2,7 +2,6 @@ import uuid
|
||||
|
||||
from datetime import date, datetime
|
||||
from decimal import Decimal
|
||||
from typing import Dict, List, Optional
|
||||
|
||||
import brewman.schemas.input as schema_in
|
||||
import brewman.schemas.voucher as output
|
||||
@@ -47,8 +46,8 @@ router = APIRouter()
|
||||
def save_route(
|
||||
request: Request,
|
||||
data: schema_in.PurchaseIn = Depends(schema_in.PurchaseIn.load_form),
|
||||
i: List[bytes] = File(None),
|
||||
t: List[bytes] = File(None),
|
||||
i: list[bytes] = File(None),
|
||||
t: list[bytes] = File(None),
|
||||
user: UserToken = Security(get_user, scopes=["purchase"]),
|
||||
) -> output.Voucher:
|
||||
try:
|
||||
@@ -105,7 +104,7 @@ def save(data: schema_in.PurchaseIn, user: UserToken, db: Session) -> Voucher:
|
||||
return voucher
|
||||
|
||||
|
||||
def save_inventories(voucher: Voucher, vendor_id: uuid.UUID, inventories: List[InventorySchema], db: Session) -> None:
|
||||
def save_inventories(voucher: Voucher, vendor_id: uuid.UUID, inventories: list[InventorySchema], db: Session) -> None:
|
||||
for item in inventories:
|
||||
sku: StockKeepingUnit = db.execute(
|
||||
select(StockKeepingUnit).where(StockKeepingUnit.id == item.batch.sku.id_)
|
||||
@@ -143,7 +142,7 @@ def save_inventories(voucher: Voucher, vendor_id: uuid.UUID, inventories: List[I
|
||||
|
||||
def save_journals(voucher: Voucher, ven: schema_in.AccountLink, db: Session) -> None:
|
||||
vendor = db.execute(select(AccountBase).where(AccountBase.id == ven.id_)).scalar_one()
|
||||
journals: Dict[uuid.UUID, Journal] = {}
|
||||
journals: dict[uuid.UUID, Journal] = {}
|
||||
amount = 0
|
||||
for i_item in voucher.inventories:
|
||||
account_id, cc_id = db.execute(
|
||||
@@ -178,8 +177,8 @@ def update_route(
|
||||
id_: uuid.UUID,
|
||||
request: Request,
|
||||
data: schema_in.PurchaseIn = Depends(schema_in.PurchaseIn.load_form),
|
||||
i: List[bytes] = File(None),
|
||||
t: List[bytes] = File(None),
|
||||
i: list[bytes] = File(None),
|
||||
t: list[bytes] = File(None),
|
||||
user: UserToken = Security(get_user, scopes=["purchase"]),
|
||||
) -> output.Voucher:
|
||||
try:
|
||||
@@ -236,7 +235,7 @@ def update_voucher(id_: uuid.UUID, data: schema_in.PurchaseIn, user: UserToken,
|
||||
return voucher
|
||||
|
||||
|
||||
def update_inventory(voucher: Voucher, vendor_id: uuid.UUID, inventories: List[InventorySchema], db: Session) -> None:
|
||||
def update_inventory(voucher: Voucher, vendor_id: uuid.UUID, inventories: list[InventorySchema], db: Session) -> None:
|
||||
for it in range(len(voucher.inventories), 0, -1):
|
||||
item = voucher.inventories[it - 1]
|
||||
quantity_consumed = -1 * get_batch_quantity(item.batch_id, voucher.id, db)
|
||||
@@ -298,7 +297,7 @@ def update_inventory(voucher: Voucher, vendor_id: uuid.UUID, inventories: List[I
|
||||
|
||||
def update_journals(voucher: Voucher, ven: schema_in.AccountLink, db: Session) -> None:
|
||||
vendor = db.execute(select(AccountBase).where(AccountBase.id == ven.id_)).scalar_one()
|
||||
journals: Dict[uuid.UUID, Journal] = {}
|
||||
journals: dict[uuid.UUID, Journal] = {}
|
||||
amount = Decimal(0)
|
||||
for i_item in voucher.inventories:
|
||||
account_id, cc_id = db.execute(
|
||||
@@ -365,7 +364,7 @@ def show_blank(
|
||||
return blank_voucher(additional_info, db)
|
||||
|
||||
|
||||
def rate_contract_price(id_: uuid.UUID, vendor_id: uuid.UUID, date_: date, db: Session) -> Optional[Decimal]:
|
||||
def rate_contract_price(id_: uuid.UUID, vendor_id: uuid.UUID, date_: date, db: Session) -> Decimal | None:
|
||||
contracts = select(RateContract.id).where(
|
||||
RateContract.vendor_id == vendor_id, RateContract.valid_from <= date_, RateContract.valid_till >= date_
|
||||
)
|
||||
|
||||
@@ -2,7 +2,6 @@ import uuid
|
||||
|
||||
from datetime import datetime
|
||||
from decimal import Decimal
|
||||
from typing import Dict, List
|
||||
|
||||
import brewman.schemas.input as schema_in
|
||||
import brewman.schemas.voucher as output
|
||||
@@ -44,8 +43,8 @@ router = APIRouter()
|
||||
def save_route(
|
||||
request: Request,
|
||||
data: schema_in.PurchaseIn = Depends(schema_in.PurchaseIn.load_form),
|
||||
i: List[bytes] = File(None),
|
||||
t: List[bytes] = File(None),
|
||||
i: list[bytes] = File(None),
|
||||
t: list[bytes] = File(None),
|
||||
user: UserToken = Security(get_user, scopes=["purchase-return"]),
|
||||
) -> output.Voucher:
|
||||
try:
|
||||
@@ -102,7 +101,7 @@ def save(data: schema_in.PurchaseIn, user: UserToken, db: Session) -> Voucher:
|
||||
return voucher
|
||||
|
||||
|
||||
def save_inventories(voucher: Voucher, inventories: List[InventorySchema], db: Session) -> None:
|
||||
def save_inventories(voucher: Voucher, inventories: list[InventorySchema], db: Session) -> None:
|
||||
for d_item in inventories:
|
||||
batch = db.execute(select(Batch).where(Batch.id == d_item.batch.id_)).scalar_one()
|
||||
|
||||
@@ -133,7 +132,7 @@ def save_inventories(voucher: Voucher, inventories: List[InventorySchema], db: S
|
||||
|
||||
def save_journals(voucher: Voucher, ven: schema_in.AccountLink, db: Session) -> None:
|
||||
vendor = db.execute(select(AccountBase).where(AccountBase.id == ven.id_)).scalar_one()
|
||||
journals: Dict[uuid.UUID, Journal] = {}
|
||||
journals: dict[uuid.UUID, Journal] = {}
|
||||
amount = Decimal(0)
|
||||
for v_item in voucher.inventories:
|
||||
account_id, cc_id = db.execute(
|
||||
@@ -168,8 +167,8 @@ def update_route(
|
||||
id_: uuid.UUID,
|
||||
request: Request,
|
||||
data: schema_in.PurchaseIn = Depends(schema_in.PurchaseIn.load_form),
|
||||
i: List[bytes] = File(None),
|
||||
t: List[bytes] = File(None),
|
||||
i: list[bytes] = File(None),
|
||||
t: list[bytes] = File(None),
|
||||
user: UserToken = Security(get_user, scopes=["purchase-return"]),
|
||||
) -> output.Voucher:
|
||||
try:
|
||||
@@ -229,7 +228,7 @@ def update_voucher(id_: uuid.UUID, data: schema_in.PurchaseIn, user: UserToken,
|
||||
return voucher
|
||||
|
||||
|
||||
def update_inventory(voucher: Voucher, new_inventories: List[InventorySchema], db: Session) -> None:
|
||||
def update_inventory(voucher: Voucher, new_inventories: list[InventorySchema], db: Session) -> None:
|
||||
for it in range(len(voucher.inventories), 0, -1):
|
||||
item = voucher.inventories[it - 1]
|
||||
batch = db.execute(select(Batch).where(Batch.id == item.batch_id)).scalar_one()
|
||||
@@ -264,7 +263,7 @@ def update_inventory(voucher: Voucher, new_inventories: List[InventorySchema], d
|
||||
|
||||
def update_journals(voucher: Voucher, ven: schema_in.AccountLink, db: Session) -> None:
|
||||
vendor = db.execute(select(AccountBase).where(AccountBase.id == ven.id_)).scalar_one()
|
||||
journals: Dict[uuid.UUID, Journal] = {}
|
||||
journals: dict[uuid.UUID, Journal] = {}
|
||||
amount = Decimal(0)
|
||||
for v_item in voucher.inventories:
|
||||
account_id, cc_id = db.execute(
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
import uuid
|
||||
|
||||
from typing import List
|
||||
|
||||
from fastapi import APIRouter, HTTPException, Request, Security, status
|
||||
from sqlalchemy import delete, select
|
||||
from sqlalchemy.exc import SQLAlchemyError
|
||||
@@ -59,7 +57,7 @@ async def save(
|
||||
)
|
||||
|
||||
|
||||
def add_items(rate_contract: RateContract, items: List[RateContractItemSchema], db: Session) -> None:
|
||||
def add_items(rate_contract: RateContract, items: list[RateContractItemSchema], db: Session) -> None:
|
||||
for item in items:
|
||||
rci = RateContractItem(rate_contract_id=rate_contract.id, sku_id=item.sku.id_, price=item.price)
|
||||
rate_contract.items.append(rci)
|
||||
@@ -94,7 +92,7 @@ async def update_route(
|
||||
)
|
||||
|
||||
|
||||
def update_items(rate_contract: RateContract, items: List[RateContractItemSchema], db: Session) -> None:
|
||||
def update_items(rate_contract: RateContract, items: list[RateContractItemSchema], db: Session) -> None:
|
||||
for it in range(len(rate_contract.items), 0, -1):
|
||||
item = rate_contract.items[it - 1]
|
||||
index = next((idx for (idx, d) in enumerate(items) if d.id_ == item.id), None)
|
||||
@@ -129,10 +127,10 @@ async def show_blank(
|
||||
return rate_contract_blank(request.session)
|
||||
|
||||
|
||||
@router.get("/list", response_model=List[RateContractSchema])
|
||||
@router.get("/list", response_model=list[RateContractSchema])
|
||||
async def show_list(
|
||||
user: UserToken = Security(get_user),
|
||||
) -> List[RateContractSchema]:
|
||||
) -> list[RateContractSchema]:
|
||||
with SessionFuture() as db:
|
||||
return [
|
||||
rate_contract_info(item)
|
||||
|
||||
@@ -2,7 +2,6 @@ import uuid
|
||||
|
||||
from datetime import date, datetime, timedelta
|
||||
from decimal import Decimal
|
||||
from typing import List
|
||||
|
||||
from fastapi import APIRouter, Security
|
||||
from sqlalchemy import and_, delete, distinct, func, select
|
||||
@@ -57,7 +56,7 @@ def rebase(
|
||||
db.commit()
|
||||
|
||||
|
||||
def save_starred(date_: date, db: Session) -> List[Voucher]:
|
||||
def save_starred(date_: date, db: Session) -> list[Voucher]:
|
||||
accounts = [
|
||||
i.id for i in db.execute(select(AccountBase.id).where(AccountBase.is_starred == True)).all() # noqa: E712
|
||||
]
|
||||
@@ -205,7 +204,7 @@ def opening_batches(date_: date, user_id: uuid.UUID, db: Session) -> Voucher:
|
||||
return voucher
|
||||
|
||||
|
||||
def delete_data(date_: date, vouchers: List[Voucher], db: Session) -> None:
|
||||
def delete_data(date_: date, vouchers: list[Voucher], db: Session) -> None:
|
||||
sub_voucher = aliased(Voucher)
|
||||
sub_query = select(sub_voucher.id).where(sub_voucher.date < date_).subquery()
|
||||
|
||||
|
||||
+196
-174
@@ -1,30 +1,30 @@
|
||||
import subprocess
|
||||
import tempfile
|
||||
import uuid
|
||||
|
||||
from collections import defaultdict
|
||||
from datetime import date
|
||||
from decimal import Decimal
|
||||
from typing import List, Optional
|
||||
from io import BytesIO
|
||||
|
||||
import brewman.schemas.recipe as schemas
|
||||
import brewman.schemas.recipe_item
|
||||
import brewman.schemas.recipe_item as rischemas
|
||||
|
||||
from fastapi import APIRouter, Depends, HTTPException, Request, Security, status
|
||||
from sqlalchemy import delete, desc, func, select
|
||||
from fastapi.responses import FileResponse, StreamingResponse
|
||||
from openpyxl import Workbook
|
||||
from openpyxl.styles import Alignment, Border, Font, NamedStyle, PatternFill, Side
|
||||
from sqlalchemy import delete, func, select
|
||||
from sqlalchemy.exc import SQLAlchemyError
|
||||
from sqlalchemy.orm import Session, contains_eager
|
||||
from sqlalchemy.orm import Session, contains_eager, joinedload
|
||||
|
||||
from ..core.security import get_current_active_user as get_user
|
||||
from ..db.session import SessionFuture
|
||||
from ..models.batch import Batch
|
||||
from ..models.inventory import Inventory
|
||||
from ..models.period import Period
|
||||
from ..models.product import Product
|
||||
from ..models.recipe import Recipe
|
||||
from ..models.recipe_item import RecipeItem
|
||||
from ..models.recipe_template import RecipeTemplate
|
||||
from ..models.stock_keeping_unit import StockKeepingUnit
|
||||
from ..models.voucher import Voucher
|
||||
from ..schemas.product_sku import ProductSku
|
||||
from ..schemas.user import UserToken
|
||||
from .reports import report_finish_date, report_start_date
|
||||
|
||||
|
||||
router = APIRouter()
|
||||
@@ -38,9 +38,7 @@ def save(
|
||||
) -> schemas.Recipe:
|
||||
try:
|
||||
with SessionFuture() as db:
|
||||
recipe_sku: StockKeepingUnit = db.execute(
|
||||
select(StockKeepingUnit).where(StockKeepingUnit.id == data.sku.id_)
|
||||
).scalar_one()
|
||||
recipe_sku = db.execute(select(StockKeepingUnit).where(StockKeepingUnit.id == data.sku.id_)).scalar_one()
|
||||
|
||||
if recipe_sku.product_id in set(i.product.id_ for i in data.items):
|
||||
raise HTTPException(
|
||||
@@ -52,37 +50,26 @@ def save(
|
||||
status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
|
||||
detail="Recipe has no ingredients",
|
||||
)
|
||||
period: Period = db.execute(select(Period).where(Period.id == data.period.id_)).scalar_one()
|
||||
recipe = Recipe(
|
||||
date=data.date_,
|
||||
source=data.source,
|
||||
instructions=data.instructions,
|
||||
garnishing=data.garnishing,
|
||||
plating=data.plating,
|
||||
sku=recipe_sku,
|
||||
recipe_yield=round(data.recipe_yield, 2),
|
||||
sale_price=round(data.sale_price, 2),
|
||||
period_id=data.period.id_,
|
||||
cost_price=Decimal(0),
|
||||
)
|
||||
recipe_cost = Decimal(0)
|
||||
for item in data.items:
|
||||
product: Product = db.execute(select(Product).where(Product.id == item.product.id_)).scalar_one()
|
||||
quantity = round(item.quantity, 2)
|
||||
if product.is_purchased:
|
||||
ingredient_cost = get_purchased_product_cost(product, period.valid_from, period.valid_till, db)
|
||||
else:
|
||||
ingredient_cost = get_sub_product_cost(product, period.id, db)
|
||||
# ingredient_cost = get_purchased_product_cost(product.id, period.valid_from, period.valid_till, db)
|
||||
recipe_cost += round(ingredient_cost * quantity, 2)
|
||||
recipe.items.append(RecipeItem(product.id, quantity, ingredient_cost))
|
||||
|
||||
recipe.cost_price = round(recipe_cost / recipe.recipe_yield, 2)
|
||||
recipe_sku.cost_price = round(recipe.cost_price / recipe.recipe_yield, 2)
|
||||
if recipe_sku.product.is_sold:
|
||||
recipe_sku.sale_price = recipe.sale_price
|
||||
recipe.items.append(RecipeItem(product_id=product.id, quantity=quantity, description=item.description))
|
||||
|
||||
db.add(recipe)
|
||||
for r_item in recipe.items:
|
||||
r_item.recipe_id = recipe.id
|
||||
db.add(r_item)
|
||||
|
||||
check_recursion(recipe_sku.product_id, recipe, db)
|
||||
check_recursion(set([recipe_sku.product_id]), set(), recipe, db)
|
||||
db.commit()
|
||||
return recipe_info(recipe)
|
||||
except SQLAlchemyError as e:
|
||||
@@ -112,14 +99,13 @@ async def update_route(
|
||||
detail="Product cannot also be an ingredient",
|
||||
)
|
||||
|
||||
period: Period = db.execute(select(Period).where(Period.id == data.period.id_)).scalar_one()
|
||||
recipe.sku = sku
|
||||
recipe.recipe_yield = round(data.recipe_yield, 2)
|
||||
recipe.sale_price = round(data.sale_price, 2)
|
||||
recipe.period = period
|
||||
|
||||
recipe_cost = Decimal(0)
|
||||
|
||||
recipe.date = data.date_
|
||||
recipe.source = data.source
|
||||
recipe.instructions = data.instructions
|
||||
recipe.garnishing = data.garnishing
|
||||
recipe.plating = data.plating
|
||||
for i in range(len(recipe.items), 0, -1):
|
||||
item = recipe.items[i - 1]
|
||||
index = next((idx for (idx, d) in enumerate(data.items) if d.id_ == item.id), None)
|
||||
@@ -129,31 +115,18 @@ async def update_route(
|
||||
product = db.execute(select(Product).where(Product.id == new_item.product.id_)).scalar_one()
|
||||
item.product_id = new_item.product.id_
|
||||
item.quantity = round(new_item.quantity, 2)
|
||||
if product.is_purchased:
|
||||
ingredient_cost = get_purchased_product_cost(product, period.valid_from, period.valid_till, db)
|
||||
else:
|
||||
ingredient_cost = get_sub_product_cost(product, period.id, db)
|
||||
# ingredient_cost = get_purchased_product_cost(product.id, period.valid_from, period.valid_till, db)
|
||||
item.price = ingredient_cost
|
||||
recipe_cost += round(ingredient_cost * item.quantity, 2)
|
||||
item.description = new_item.description
|
||||
else:
|
||||
recipe.items.remove(item)
|
||||
|
||||
for d_item in data.items:
|
||||
product = db.execute(select(Product).where(Product.id == d_item.product.id_)).scalar_one()
|
||||
quantity = round(d_item.quantity, 2)
|
||||
if product.is_purchased:
|
||||
ingredient_cost = get_purchased_product_cost(product, period.valid_from, period.valid_till, db)
|
||||
else:
|
||||
ingredient_cost = get_sub_product_cost(product, period.id, db)
|
||||
# ingredient_cost = get_purchased_product_cost(product.id, period.valid_from, period.valid_till, db)
|
||||
recipe.items.append(
|
||||
RecipeItem(product_id=product.id, quantity=quantity, description=d_item.description)
|
||||
)
|
||||
|
||||
recipe_cost += round(ingredient_cost * quantity, 2)
|
||||
recipe.items.append(RecipeItem(product.id, quantity, ingredient_cost))
|
||||
|
||||
recipe.cost_price = round(recipe_cost / recipe.recipe_yield, 2)
|
||||
sku.cost_price = round(recipe.cost_price / recipe.recipe_yield, 2)
|
||||
check_recursion(sku.product_id, recipe, db)
|
||||
check_recursion(set([sku.product_id]), set(), db)
|
||||
db.commit()
|
||||
return recipe_info(recipe)
|
||||
except SQLAlchemyError as e:
|
||||
@@ -163,75 +136,26 @@ async def update_route(
|
||||
)
|
||||
|
||||
|
||||
def check_recursion(product_id: uuid.UUID, recipe: Recipe, db: Session) -> None:
|
||||
for item in recipe.items:
|
||||
item_recipes: List[Recipe] = (
|
||||
db.execute(
|
||||
select(Recipe)
|
||||
.join(Recipe.sku)
|
||||
.join(Recipe.items)
|
||||
.where(
|
||||
StockKeepingUnit.product_id == item.product_id,
|
||||
Recipe.period_id == recipe.period_id,
|
||||
)
|
||||
.options(contains_eager(Recipe.sku), contains_eager(Recipe.items))
|
||||
)
|
||||
.unique()
|
||||
.scalars()
|
||||
.all()
|
||||
)
|
||||
for sub_recipe in item_recipes:
|
||||
if sub_recipe.sku.product_id == product_id:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
|
||||
detail="Recipe recursion. Some ingredient recipe contains parent recipe.",
|
||||
)
|
||||
check_recursion(product_id, sub_recipe, db)
|
||||
|
||||
|
||||
def get_purchased_product_cost(product: Product, start_date: date, finish_date: date, db: Session) -> Decimal:
|
||||
query = (
|
||||
select(Batch)
|
||||
.join(Batch.inventories)
|
||||
.join(Inventory.voucher)
|
||||
.join(Batch.sku)
|
||||
.join(StockKeepingUnit.product)
|
||||
.where(Product.id == product.id, Voucher.date >= start_date, Voucher.date <= finish_date)
|
||||
def check_recursion(products: set[uuid.UUID], visited: set[uuid.UUID], db: Session) -> None:
|
||||
sq = (
|
||||
select(func.distinct(RecipeItem.product_id))
|
||||
.join(Recipe.items)
|
||||
.join(Recipe.sku)
|
||||
.where(StockKeepingUnit.product_id.in_(products))
|
||||
)
|
||||
batches: List[Batch] = db.execute(query).unique().scalars().all()
|
||||
skus: List[StockKeepingUnit] = (
|
||||
db.execute(select(StockKeepingUnit).where(StockKeepingUnit.product_id == product.id)).scalars().all()
|
||||
)
|
||||
price: List[Decimal] = []
|
||||
for batch in batches:
|
||||
price.append(batch.rate / batch.sku.fraction / batch.sku.product_yield)
|
||||
else:
|
||||
for sku in skus:
|
||||
price.append(sku.cost_price / sku.fraction / sku.product_yield)
|
||||
return round(sum(price) / len(price), 5) # type: ignore[return-value]
|
||||
|
||||
|
||||
def get_sub_product_cost(product: Product, period_id: uuid.UUID, db: Session) -> Decimal:
|
||||
recipe: Optional[Recipe] = (
|
||||
db.execute(
|
||||
select(Recipe)
|
||||
.join(Recipe.sku)
|
||||
.where(
|
||||
StockKeepingUnit.product_id == product.id,
|
||||
Recipe.period_id == period_id,
|
||||
)
|
||||
)
|
||||
ingredient_product_ids = (
|
||||
db.execute(select(StockKeepingUnit.product_id).join(Recipe.sku).where(StockKeepingUnit.product_id.in_(sq)))
|
||||
.scalars()
|
||||
.one_or_none()
|
||||
.all()
|
||||
)
|
||||
|
||||
if recipe is None:
|
||||
if len(ingredient_product_ids) == 0:
|
||||
return
|
||||
if (visited | products) & set(ingredient_product_ids):
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
|
||||
detail=f"Ingredient {product.name} is not bought and also does not have a recipe for the period.",
|
||||
detail="Recipe recursion. Some ingredient recipe contains parent recipe.",
|
||||
)
|
||||
|
||||
return round(recipe.cost_price / recipe.sku.fraction / recipe.sku.product_yield, 5)
|
||||
check_recursion(set(ingredient_product_ids), visited | products, db)
|
||||
|
||||
|
||||
@router.delete("/{id_}", response_model=None)
|
||||
@@ -242,14 +166,13 @@ def delete_route(
|
||||
) -> None:
|
||||
with SessionFuture() as db:
|
||||
recipe: Recipe = db.execute(select(Recipe).where(Recipe.id == id_)).scalar_one()
|
||||
recipe_ids: List[uuid.UUID] = (
|
||||
recipe_ids: list[uuid.UUID] = (
|
||||
db.execute(
|
||||
select(func.distinct(RecipeItem.recipe_id)).where(
|
||||
RecipeItem.product_id
|
||||
== select(StockKeepingUnit.product_id)
|
||||
.where(StockKeepingUnit.id == select(Recipe.sku_id).where(Recipe.id == id_).scalar_subquery())
|
||||
.scalar_subquery(),
|
||||
RecipeItem.recipe_id.in_(select(Recipe.id).where(Recipe.period_id == recipe.period_id)),
|
||||
)
|
||||
)
|
||||
.scalars()
|
||||
@@ -272,73 +195,168 @@ def show_blank(
|
||||
request: Request,
|
||||
user: UserToken = Security(get_user, scopes=["recipes"]),
|
||||
) -> schemas.RecipeBlank:
|
||||
with SessionFuture() as db:
|
||||
period_id: uuid.UUID = db.execute(select(Period.id).order_by(desc(Period.valid_till)).limit(1)).scalar_one()
|
||||
return recipe_blank(period_id)
|
||||
return recipe_blank()
|
||||
|
||||
|
||||
@router.get("/list", response_model=List[schemas.Recipe])
|
||||
@router.get("/list", response_model=list[schemas.Recipe])
|
||||
async def show_list(
|
||||
p: uuid.UUID, # period_id
|
||||
user: UserToken = Depends(get_user),
|
||||
) -> List[schemas.Recipe]:
|
||||
) -> list[schemas.Recipe]:
|
||||
with SessionFuture() as db:
|
||||
list_: List[Recipe] = (
|
||||
db.execute(select(Recipe).join(Recipe.sku).where(Recipe.period_id == p).order_by(Recipe.sku_id))
|
||||
list_: list[Recipe] = (
|
||||
db.execute(
|
||||
select(Recipe)
|
||||
.options(joinedload(Recipe.sku, innerjoin=True).joinedload(StockKeepingUnit.product, innerjoin=True))
|
||||
.order_by(Recipe.sku_id)
|
||||
)
|
||||
.scalars()
|
||||
.all()
|
||||
)
|
||||
return [
|
||||
schemas.Recipe(
|
||||
id=item.id,
|
||||
period=schemas.PeriodLink(id=item.period.id),
|
||||
sku=schemas.ProductLink(id=item.sku.id, name=f"{item.sku.product.name} ({item.sku.units})"),
|
||||
sku=schemas.ProductLink(id=item.sku.id, name=item.sku.product.name),
|
||||
date=item.date,
|
||||
source=item.source,
|
||||
instructions=item.instructions,
|
||||
garnishing=item.garnishing,
|
||||
plating=item.plating,
|
||||
recipeYield=item.recipe_yield,
|
||||
costPrice=item.cost_price,
|
||||
salePrice=item.sale_price,
|
||||
notes=str(item.sku.product.product_group_id),
|
||||
notes=item.notes,
|
||||
productGroupId=item.sku.product.product_group_id,
|
||||
units=item.sku.units,
|
||||
items=[],
|
||||
)
|
||||
for item in list_
|
||||
]
|
||||
|
||||
|
||||
@router.get("/ingredient-details/{id_}", response_model=ProductSku)
|
||||
def show_ingredient_id(
|
||||
# @router.get("/ingredient-details/{id_}", response_model=ProductSku)
|
||||
# def show_ingredient_id(
|
||||
# id_: uuid.UUID,
|
||||
# user: UserToken = Security(get_user, scopes=["recipes"]),
|
||||
# ) -> ProductSku:
|
||||
# with SessionFuture() as db:
|
||||
# product: Product = db.execute(select(Product).join(Product.skus).where(Product.id == id_)).unique().scalar_one()
|
||||
# return ProductSku(
|
||||
# id=id_,
|
||||
# name=product.name,
|
||||
# fractionUnits=product.fraction_units,
|
||||
# isRateContracted=False,
|
||||
# )
|
||||
|
||||
|
||||
@router.get("/pdf/{id_}", response_class=FileResponse)
|
||||
def show_pdf(
|
||||
id_: uuid.UUID,
|
||||
start_date: Optional[date] = Depends(report_start_date),
|
||||
finish_date: Optional[date] = Depends(report_finish_date),
|
||||
user: UserToken = Security(get_user, scopes=["recipes"]),
|
||||
) -> ProductSku:
|
||||
) -> schemas.Recipe:
|
||||
with SessionFuture() as db:
|
||||
query = (
|
||||
select(Batch)
|
||||
.join(Batch.inventories)
|
||||
.join(Inventory.voucher)
|
||||
.join(Batch.sku)
|
||||
# template = db.execute(select(RecipeTemplate.text).where(RecipeTemplate.selected == True)).scalar_one()
|
||||
# with tempfile.TemporaryDirectory() as tmpdir:
|
||||
# with open(tmpdir + "/recipe.tex", 'w') as rt:
|
||||
# rt.write(template)
|
||||
# subprocess.run(f"docker run -i --rm --name latex --volume \"{tmpdir}\":/data -w /data --user $(id -u):$(id -g) texlive/texlive:latest pdflatex recipe.tex")
|
||||
item: Recipe = db.execute(select(Recipe).where(Recipe.id == id_)).scalar_one()
|
||||
return recipe_info(item)
|
||||
|
||||
|
||||
@router.get("/xlsx", response_class=StreamingResponse)
|
||||
def get_report(
|
||||
p: uuid.UUID | None = None,
|
||||
) -> StreamingResponse:
|
||||
with SessionFuture() as db:
|
||||
q = (
|
||||
select(Recipe)
|
||||
.join(Recipe.sku)
|
||||
.join(StockKeepingUnit.product)
|
||||
.where(Product.id == id_)
|
||||
)
|
||||
if start_date is not None:
|
||||
query = query.where(Voucher.date >= start_date)
|
||||
if finish_date is not None:
|
||||
query = query.where(Voucher.date <= finish_date)
|
||||
batches: List[Batch] = db.execute(query).unique().scalars().all()
|
||||
product: Product = db.execute(select(Product).join(Product.skus).where(Product.id == id_)).unique().scalar_one()
|
||||
price: List[Decimal] = []
|
||||
for batch in batches:
|
||||
price.append(batch.rate / batch.sku.fraction / batch.sku.product_yield)
|
||||
else:
|
||||
for sku in product.skus:
|
||||
price.append(sku.cost_price / sku.fraction / sku.product_yield)
|
||||
return ProductSku(
|
||||
id=id_,
|
||||
name=product.name,
|
||||
fractionUnits=product.fraction_units,
|
||||
costPrice=round(sum(price) / len(price), 2),
|
||||
salePrice=0,
|
||||
isRateContracted=False,
|
||||
.join(Product.product_group)
|
||||
.options(
|
||||
joinedload(Recipe.items, innerjoin=True).joinedload(RecipeItem.product, innerjoin=True),
|
||||
contains_eager(Recipe.sku, StockKeepingUnit.product, Product.product_group),
|
||||
)
|
||||
)
|
||||
if p is not None:
|
||||
q = q.where(Recipe.sku, StockKeepingUnit.product, Product.product_group_id == p)
|
||||
list_: list[Recipe] = db.execute(q).unique().scalars().all()
|
||||
e = excel(sorted(list_, key=lambda r: r.sku.product.name))
|
||||
e.seek(0)
|
||||
|
||||
headers = {"Content-Disposition": "attachment; filename = recipe.xlsx"}
|
||||
return StreamingResponse(e, media_type="text/xlsx", headers=headers)
|
||||
|
||||
|
||||
def excel(recipes: list[Recipe]) -> None:
|
||||
wb = Workbook()
|
||||
wb.active.title = "Rate List"
|
||||
pgs = set([x.sku.product.product_group.name for x in recipes])
|
||||
for pg in pgs:
|
||||
wb.create_sheet(pg)
|
||||
rows = defaultdict(lambda: 1)
|
||||
register_styles(wb)
|
||||
for recipe in recipes:
|
||||
ws = wb[recipe.sku.product.product_group.name]
|
||||
row = rows[recipe.sku.product.product_group.name]
|
||||
ings = len(recipe.items)
|
||||
ing_from = row + 2
|
||||
ing_till = ing_from + ings - 1
|
||||
ws.cell(row=row, column=1, value=recipe.sku.product.name).style = "recipe_name"
|
||||
# ws.cell(row=row, column=3, value=f"Yeild = {recipe.recipe_yield} {recipe.sku.units}")
|
||||
ws.cell(row=row, column=2, value=recipe.sku.units).style = "recipe_unit"
|
||||
ws.cell(row=row, column=3, value=recipe.recipe_yield).style = "recipe_name"
|
||||
ws.cell(row=row, column=4).style = "recipe_name"
|
||||
ws.cell(row=row, column=5, value=f"=SUM(E{ing_from}:E{ing_till})").style = "recipe_name"
|
||||
row += 1
|
||||
ws.cell(row=row, column=1, value="Ingredients").style = "header"
|
||||
ws.cell(row=row, column=2, value="Unit").style = "header"
|
||||
ws.cell(row=row, column=3, value="Qty").style = "header"
|
||||
ws.cell(row=row, column=4, value="Rate").style = "header"
|
||||
ws.cell(row=row, column=5, value="Amount").style = "header"
|
||||
for item in recipe.items:
|
||||
row += 1
|
||||
ws.cell(row=row, column=1, value=item.product.name).style = "ing"
|
||||
ws.cell(row=row, column=2, value=item.product.fraction_units).style = "unit"
|
||||
ws.cell(row=row, column=3, value=item.quantity).style = "ing"
|
||||
ws.cell(row=row, column=4, value="=VLOOKUP(A:A,'Rate List'!A:G,7,0)").style = "ing"
|
||||
ws.cell(row=row, column=5, value=f"=C{row}*D{row}").style = "ing"
|
||||
rows[recipe.sku.product.product_group.name] = row + 1
|
||||
virtual_workbook = BytesIO()
|
||||
wb.save(virtual_workbook)
|
||||
return virtual_workbook
|
||||
|
||||
|
||||
def register_styles(wb: Workbook):
|
||||
bd = Side(style="thin", color="000000")
|
||||
|
||||
recipe_name = NamedStyle(name="recipe_name")
|
||||
recipe_name.font = Font(bold=True)
|
||||
recipe_name.border = Border(left=bd, top=bd, right=bd, bottom=bd)
|
||||
recipe_name.fill = PatternFill(fill_type=None, start_color="FFFF00", end_color="FFFF00", patternType="solid")
|
||||
wb.add_named_style(recipe_name)
|
||||
|
||||
recipe_unit = NamedStyle(name="recipe_unit")
|
||||
recipe_unit.font = Font(bold=True)
|
||||
recipe_unit.border = Border(left=bd, top=bd, right=bd, bottom=bd)
|
||||
recipe_unit.fill = PatternFill(fill_type=None, start_color="FFFF00", end_color="FFFF00", patternType="solid")
|
||||
recipe_unit.alignment = Alignment(horizontal="center")
|
||||
wb.add_named_style(recipe_unit)
|
||||
|
||||
header = NamedStyle(name="header")
|
||||
header.font = Font(bold=True)
|
||||
header.border = Border(left=bd, top=bd, right=bd, bottom=bd)
|
||||
header.fill = PatternFill(fill_type=None, start_color="92D050", end_color="92D050", patternType="solid")
|
||||
header.alignment = Alignment(horizontal="center")
|
||||
wb.add_named_style(header)
|
||||
|
||||
ing = NamedStyle(name="ing")
|
||||
ing.border = Border(left=bd, top=bd, right=bd, bottom=bd)
|
||||
wb.add_named_style(ing)
|
||||
|
||||
unit = NamedStyle(name="unit")
|
||||
unit.border = Border(left=bd, top=bd, right=bd, bottom=bd)
|
||||
unit.alignment = Alignment(horizontal="center")
|
||||
wb.add_named_style(unit)
|
||||
return recipe_name, recipe_unit, header, ing, unit
|
||||
|
||||
|
||||
@router.get("/{id_}", response_model=schemas.Recipe)
|
||||
@@ -358,32 +376,36 @@ def recipe_info(recipe: Recipe) -> schemas.Recipe:
|
||||
id=recipe.sku_id,
|
||||
name=f"{recipe.sku.product.name} ({recipe.sku.units})",
|
||||
),
|
||||
period=schemas.PeriodLink(id=recipe.period_id),
|
||||
date=recipe.date,
|
||||
source=recipe.source,
|
||||
instructions=recipe.instructions,
|
||||
garnishing=recipe.garnishing,
|
||||
plating=recipe.plating,
|
||||
recipeYield=recipe.recipe_yield,
|
||||
salePrice=recipe.sale_price,
|
||||
costPrice=recipe.cost_price,
|
||||
notes="",
|
||||
items=[
|
||||
brewman.schemas.recipe_item.RecipeItem(
|
||||
rischemas.RecipeItem(
|
||||
id=item.id,
|
||||
product=schemas.ProductLink(
|
||||
id=item.product.id,
|
||||
name=f"{item.product.name} ({item.product.fraction_units})",
|
||||
),
|
||||
quantity=round(item.quantity, 2),
|
||||
price=round(item.price, 5),
|
||||
description=item.description,
|
||||
)
|
||||
for item in recipe.items
|
||||
],
|
||||
)
|
||||
|
||||
|
||||
def recipe_blank(period_id: uuid.UUID) -> schemas.RecipeBlank:
|
||||
def recipe_blank() -> schemas.RecipeBlank:
|
||||
return schemas.RecipeBlank(
|
||||
period=schemas.PeriodLink(id=period_id),
|
||||
date=date.today(),
|
||||
source="",
|
||||
instructions="",
|
||||
garnishing="",
|
||||
plating="",
|
||||
recipeYield=1,
|
||||
costPrice=0,
|
||||
salePrice=0,
|
||||
isLocked=False,
|
||||
notes="",
|
||||
items=[],
|
||||
|
||||
@@ -0,0 +1,109 @@
|
||||
import datetime
|
||||
import uuid
|
||||
|
||||
import brewman.schemas.recipe_template as schemas
|
||||
|
||||
from fastapi import APIRouter, HTTPException, Security, status
|
||||
from sqlalchemy import delete, select, update
|
||||
from sqlalchemy.exc import SQLAlchemyError
|
||||
|
||||
from ..core.security import get_current_active_user as get_user
|
||||
from ..db.session import SessionFuture
|
||||
from ..models.recipe_template import RecipeTemplate
|
||||
from ..schemas.user import UserToken
|
||||
|
||||
|
||||
router = APIRouter()
|
||||
|
||||
|
||||
@router.post("", response_model=None)
|
||||
def save(
|
||||
data: schemas.RecipeTemplateIn,
|
||||
user: UserToken = Security(get_user, scopes=["recipes"]),
|
||||
) -> None:
|
||||
try:
|
||||
with SessionFuture() as db:
|
||||
date_ = data.date_ if data.date_ is not None else datetime.date.today()
|
||||
if data.selected:
|
||||
db.execute(update(RecipeTemplate).values(selected=False))
|
||||
item = RecipeTemplate(id=None, name=data.name, date=date_, text=data.text, selected=data.selected)
|
||||
db.add(item)
|
||||
db.commit()
|
||||
return None
|
||||
except SQLAlchemyError as e:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
||||
detail=str(e),
|
||||
)
|
||||
|
||||
|
||||
@router.put("/{id_}", response_model=None)
|
||||
def update_route(
|
||||
id_: uuid.UUID,
|
||||
data: schemas.RecipeTemplateIn,
|
||||
user: UserToken = Security(get_user, scopes=["recipes"]),
|
||||
) -> None:
|
||||
try:
|
||||
with SessionFuture() as db:
|
||||
date_ = data.date_ if data.date_ is not None else datetime.date.today()
|
||||
item = db.execute(select(RecipeTemplate).where(RecipeTemplate.id == id_)).scalar_one()
|
||||
if data.selected and not item.selected:
|
||||
db.execute(update(RecipeTemplate).where(RecipeTemplate.id != id_).values(selected=False))
|
||||
item.name = data.name
|
||||
item.text = data.text
|
||||
item.selected = data.selected
|
||||
item.date = date_
|
||||
db.commit()
|
||||
return None
|
||||
except SQLAlchemyError as e:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
||||
detail=str(e),
|
||||
)
|
||||
|
||||
|
||||
@router.delete("/{id_}", response_model=None)
|
||||
def delete_route(
|
||||
id_: uuid.UUID,
|
||||
user: UserToken = Security(get_user, scopes=["recipes"]),
|
||||
) -> None:
|
||||
try:
|
||||
with SessionFuture() as db:
|
||||
db.execute(delete(RecipeTemplate).where(RecipeTemplate.id == id_))
|
||||
db.commit()
|
||||
return None
|
||||
except SQLAlchemyError as e:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
||||
detail=str(e),
|
||||
)
|
||||
|
||||
|
||||
@router.get("", response_model=schemas.RecipeTemplateIn)
|
||||
def show_blank(
|
||||
user: UserToken = Security(get_user, scopes=["recipes"]),
|
||||
) -> schemas.RecipeTemplateIn:
|
||||
return schemas.RecipeTemplateIn(name="", date=datetime.date.today(), text="", selected=False)
|
||||
|
||||
|
||||
@router.get("/list", response_model=list[schemas.RecipeTemplate])
|
||||
async def show_list(
|
||||
user: UserToken = Security(get_user, scopes=["recipes"]),
|
||||
) -> list[schemas.RecipeTemplate]:
|
||||
with SessionFuture() as db:
|
||||
list_ = db.execute(select(RecipeTemplate).order_by(RecipeTemplate.name)).scalars().all()
|
||||
return [
|
||||
schemas.RecipeTemplate(id=i.id, name=i.name, date=i.date, text=i.text, selected=i.selected) for i in list_
|
||||
]
|
||||
|
||||
|
||||
@router.get("/{id_}", response_model=schemas.RecipeTemplate)
|
||||
def show_id(
|
||||
id_: uuid.UUID,
|
||||
user: UserToken = Security(get_user, scopes=["recipes"]),
|
||||
) -> schemas.RecipeTemplate:
|
||||
with SessionFuture() as db:
|
||||
item = db.execute(select(RecipeTemplate).where(RecipeTemplate.id == id_)).scalar_one()
|
||||
return schemas.RecipeTemplate(
|
||||
id=item.id, name=item.name, date=item.date, text=item.text, selected=item.selected
|
||||
)
|
||||
@@ -1,12 +1,11 @@
|
||||
from datetime import date, datetime
|
||||
from typing import Optional
|
||||
|
||||
|
||||
def report_start_date(s: Optional[str] = None) -> Optional[date]:
|
||||
def report_start_date(s: str | None = None) -> date | None:
|
||||
return None if s is None else datetime.strptime(s, "%d-%b-%Y").date()
|
||||
|
||||
|
||||
def report_finish_date(f: Optional[str] = None) -> Optional[date]:
|
||||
def report_finish_date(f: str | None = None) -> date | None:
|
||||
return None if f is None else datetime.strptime(f, "%d-%b-%Y").date()
|
||||
|
||||
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
from datetime import date, datetime
|
||||
from decimal import Decimal
|
||||
from typing import Dict, List, Tuple
|
||||
|
||||
import brewman.schemas.balance_sheet as schemas
|
||||
|
||||
@@ -45,12 +44,12 @@ def report_data(
|
||||
return schemas.BalanceSheet(date=date_, body=body, footer=footer)
|
||||
|
||||
|
||||
def build_balance_sheet(date_: date, db: Session) -> Tuple[List[schemas.BalanceSheetItem], schemas.BalanceSheetItem]:
|
||||
def build_balance_sheet(date_: date, db: Session) -> tuple[list[schemas.BalanceSheetItem], schemas.BalanceSheetItem]:
|
||||
type_list = (
|
||||
db.execute(select(AccountType.id).where(AccountType.balance_sheet == True)).scalars().all() # noqa: E712
|
||||
)
|
||||
report: List[schemas.BalanceSheetItem] = []
|
||||
groups: Dict[int, schemas.BalanceSheetItem] = {}
|
||||
report: list[schemas.BalanceSheetItem] = []
|
||||
groups: dict[int, schemas.BalanceSheetItem] = {}
|
||||
# Add Net Profit / Loss
|
||||
closing_stock = round(get_closing_stock(date_, db), 2)
|
||||
net_profit = round(get_accumulated_profit(date_, db), 2) - closing_stock
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
from datetime import date, datetime
|
||||
from typing import List, Tuple
|
||||
|
||||
import brewman.schemas.cash_flow as schemas
|
||||
|
||||
@@ -78,7 +77,7 @@ def report_id(
|
||||
|
||||
def build_report(
|
||||
start_date: date, finish_date: date, db: Session
|
||||
) -> Tuple[schemas.CashFlowBody, List[schemas.CashFlowItem]]:
|
||||
) -> tuple[schemas.CashFlowBody, list[schemas.CashFlowItem]]:
|
||||
sub_query = (
|
||||
select(Voucher.id)
|
||||
.join(Voucher.journals)
|
||||
@@ -158,7 +157,7 @@ def build_report(
|
||||
|
||||
def build_report_id(
|
||||
account_type: int, start_date: date, finish_date: date, db: Session
|
||||
) -> Tuple[schemas.CashFlowBody, List[schemas.CashFlowItem]]:
|
||||
) -> tuple[schemas.CashFlowBody, list[schemas.CashFlowItem]]:
|
||||
cf: schemas.CashFlowBody = schemas.CashFlowBody(operating=[], investing=[], financing=[], details=[])
|
||||
details = cf.details
|
||||
sub_query = (
|
||||
|
||||
@@ -2,7 +2,6 @@ import uuid
|
||||
|
||||
from datetime import date, datetime
|
||||
from decimal import Decimal
|
||||
from typing import List, Optional
|
||||
|
||||
import brewman.schemas.closing_stock as schemas
|
||||
|
||||
@@ -50,7 +49,7 @@ def report_blank(
|
||||
def report_data(
|
||||
date_: str,
|
||||
request: Request,
|
||||
d: Optional[uuid.UUID] = None,
|
||||
d: uuid.UUID | None = None,
|
||||
user: UserToken = Security(get_user, scopes=["closing-stock"]),
|
||||
) -> schemas.ClosingStock:
|
||||
set_period(get_start_date(request.session), date_, request.session)
|
||||
@@ -61,7 +60,7 @@ def report_data(
|
||||
@router.delete("/{date_}")
|
||||
def delete_voucher(
|
||||
date_: str,
|
||||
d: Optional[uuid.UUID] = None,
|
||||
d: uuid.UUID | None = None,
|
||||
user: UserToken = Security(get_user, scopes=["closing-stock"]),
|
||||
) -> None:
|
||||
try:
|
||||
@@ -136,7 +135,7 @@ def full_report(date_: date, cost_centre_id: uuid.UUID, db: Session) -> schemas.
|
||||
)
|
||||
|
||||
|
||||
def build_report(date_: date, cost_centre_id: uuid.UUID, db: Session) -> List[schemas.ClosingStockItem]:
|
||||
def build_report(date_: date, cost_centre_id: uuid.UUID, db: Session) -> list[schemas.ClosingStockItem]:
|
||||
amount_sum = func.sum(Journal.debit * Inventory.quantity * Inventory.rate * (1 + Inventory.tax)).label("amount")
|
||||
quantity_sum = func.sum(Journal.debit * Inventory.quantity).label("quantity")
|
||||
query = db.execute(
|
||||
@@ -200,7 +199,7 @@ def build_report(date_: date, cost_centre_id: uuid.UUID, db: Session) -> List[sc
|
||||
|
||||
|
||||
def get_opening_stock(date_: date, db: Session) -> Decimal:
|
||||
opening_stock: Optional[Decimal] = db.execute(
|
||||
opening_stock: Decimal | None = db.execute(
|
||||
select(func.sum(Inventory.quantity * Inventory.rate * (1 + Inventory.tax) * Journal.debit))
|
||||
.join(Journal.voucher)
|
||||
.join(Journal.account)
|
||||
@@ -211,7 +210,7 @@ def get_opening_stock(date_: date, db: Session) -> Decimal:
|
||||
|
||||
|
||||
def get_closing_stock(date_: date, db: Session) -> Decimal:
|
||||
closing_stock: Optional[Decimal] = db.execute(
|
||||
closing_stock: Decimal | None = db.execute(
|
||||
select(func.sum(Inventory.quantity * Inventory.rate * (1 + Inventory.tax) * Journal.debit))
|
||||
.join(Journal.voucher)
|
||||
.join(Journal.account)
|
||||
@@ -286,7 +285,7 @@ def save_cs(data: schemas.ClosingStock, db: Session) -> None:
|
||||
db.add(cs)
|
||||
|
||||
|
||||
def save(date_: date, items: List[schemas.ClosingStockItem], user: UserToken, db: Session) -> Voucher:
|
||||
def save(date_: date, items: list[schemas.ClosingStockItem], user: UserToken, db: Session) -> Voucher:
|
||||
product_accounts = (
|
||||
select(Product.account_id).join(Product.skus).where(StockKeepingUnit.id.in_([i.product.id_ for i in items]))
|
||||
)
|
||||
@@ -310,7 +309,7 @@ def save(date_: date, items: List[schemas.ClosingStockItem], user: UserToken, db
|
||||
return voucher
|
||||
|
||||
|
||||
def save_inventories(voucher: Voucher, items: List[schemas.ClosingStockItem], db: Session) -> None:
|
||||
def save_inventories(voucher: Voucher, items: list[schemas.ClosingStockItem], db: Session) -> None:
|
||||
for item in items:
|
||||
batches = (
|
||||
db.execute(
|
||||
@@ -353,7 +352,7 @@ def save_journals(
|
||||
db.add(d)
|
||||
|
||||
|
||||
def update_cs(date_: date, cost_centre_id: uuid.UUID, items: List[schemas.ClosingStockItem], db: Session) -> None:
|
||||
def update_cs(date_: date, cost_centre_id: uuid.UUID, items: list[schemas.ClosingStockItem], db: Session) -> None:
|
||||
old = (
|
||||
db.execute(
|
||||
select(ClosingStock).where(ClosingStock.date_ == date_, ClosingStock.cost_centre_id == cost_centre_id)
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
from datetime import date, datetime
|
||||
from typing import List
|
||||
|
||||
import brewman.schemas.daybook as schemas
|
||||
|
||||
@@ -46,7 +45,7 @@ def report_data(
|
||||
return schemas.Daybook(startDate=start_date, finishDate=finish_date, body=body)
|
||||
|
||||
|
||||
def build_report(start_date: date, finish_date: date, db: Session) -> List[schemas.DaybookItem]:
|
||||
def build_report(start_date: date, finish_date: date, db: Session) -> list[schemas.DaybookItem]:
|
||||
body = []
|
||||
|
||||
query = (
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
from datetime import date, datetime, time, timedelta
|
||||
from typing import List, Optional, Tuple
|
||||
|
||||
import brewman.schemas.entries as schemas
|
||||
|
||||
from fastapi import APIRouter, Depends, Security
|
||||
from sqlalchemy import desc, not_, or_, select
|
||||
from sqlalchemy.orm import Session, contains_eager, joinedload
|
||||
from sqlalchemy.orm import Session, contains_eager
|
||||
from sqlalchemy.sql.functions import count
|
||||
|
||||
from ...core.security import get_current_active_user as get_user
|
||||
@@ -22,22 +21,22 @@ router = APIRouter()
|
||||
|
||||
|
||||
def build_report(
|
||||
start_date: Optional[date],
|
||||
finish_date: Optional[date],
|
||||
posted: Optional[bool],
|
||||
start_date: date | None,
|
||||
finish_date: date | None,
|
||||
posted: bool | None,
|
||||
issue: bool,
|
||||
page_size: int,
|
||||
page_index: int,
|
||||
active_sort: str,
|
||||
sort_direction: str,
|
||||
db: Session,
|
||||
) -> Tuple[int, List[Voucher]]:
|
||||
) -> tuple[int, list[Voucher]]:
|
||||
query = (
|
||||
select(Voucher)
|
||||
.join(Voucher.user)
|
||||
.join(Voucher.journals)
|
||||
.join(Journal.account)
|
||||
.options(
|
||||
joinedload(Voucher.user, innerjoin=True),
|
||||
joinedload(Voucher.journals, innerjoin=True).joinedload(Journal.account, innerjoin=True),
|
||||
contains_eager(Voucher.user),
|
||||
contains_eager(Voucher.journals, Journal.account),
|
||||
)
|
||||
@@ -78,19 +77,20 @@ def build_report(
|
||||
sq = sq.limit(page_size)
|
||||
if page_index:
|
||||
sq = sq.offset(page_size * page_index)
|
||||
print("Counts:", counts, "\n\n\n\n", "Query:", query)
|
||||
return db.execute(counts).scalar_one(), db.execute(query.where(Voucher.id.in_(sq))).unique().scalars().all()
|
||||
|
||||
|
||||
@router.get("", response_model=schemas.Report)
|
||||
def report_data(
|
||||
start_date: Optional[date] = Depends(report_start_date),
|
||||
finish_date: Optional[date] = Depends(report_finish_date),
|
||||
p: Optional[bool] = None, # Posted
|
||||
ps: Optional[int] = 50, # Page Size
|
||||
pi: Optional[int] = 0, # Page Index
|
||||
a: Optional[str] = "date", # Active Sort
|
||||
d: Optional[str] = "desc", # Sort Direction
|
||||
i: Optional[bool] = False, # Show issue vouchers
|
||||
start_date: date | None = Depends(report_start_date),
|
||||
finish_date: date | None = Depends(report_finish_date),
|
||||
p: bool | None = None, # Posted
|
||||
ps: int | None = 50, # Page Size
|
||||
pi: int | None = 0, # Page Index
|
||||
a: str | None = "date", # Active Sort
|
||||
d: str | None = "desc", # Sort Direction
|
||||
i: bool | None = False, # Show issue vouchers
|
||||
user: UserToken = Security(get_user, scopes=["ledger"]),
|
||||
) -> schemas.Report:
|
||||
assert i is not None and ps is not None and pi is not None and a is not None and d is not None
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
import datetime
|
||||
import uuid
|
||||
|
||||
from typing import List, Optional
|
||||
|
||||
import brewman.schemas.ledger as schemas
|
||||
|
||||
from fastapi import APIRouter, Request, Security
|
||||
@@ -40,8 +38,8 @@ def show_blank(
|
||||
def show_data(
|
||||
id_: uuid.UUID,
|
||||
request: Request,
|
||||
s: Optional[str] = None,
|
||||
f: Optional[str] = None,
|
||||
s: str | None = None,
|
||||
f: str | None = None,
|
||||
user: UserToken = Security(get_user, scopes=["ledger"]),
|
||||
) -> schemas.Ledger:
|
||||
with SessionFuture() as db:
|
||||
@@ -58,7 +56,7 @@ def show_data(
|
||||
)
|
||||
|
||||
|
||||
def build_report(account_id: uuid.UUID, start_date: str, finish_date: str, db: Session) -> List[schemas.LedgerItem]:
|
||||
def build_report(account_id: uuid.UUID, start_date: str, finish_date: str, db: Session) -> list[schemas.LedgerItem]:
|
||||
body = []
|
||||
opening = opening_balance(account_id, start_date, db)
|
||||
body.append(opening)
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
from datetime import date, datetime
|
||||
from typing import List
|
||||
|
||||
import brewman.schemas.net_transactions as schemas
|
||||
|
||||
@@ -53,7 +52,7 @@ def show_data(
|
||||
)
|
||||
|
||||
|
||||
def build_report(start_date: date, finish_date: date, db: Session) -> List[schemas.NetTransactionsItem]:
|
||||
def build_report(start_date: date, finish_date: date, db: Session) -> list[schemas.NetTransactionsItem]:
|
||||
amount_sum = func.sum(Journal.amount * Journal.debit).label("amount")
|
||||
query = db.execute(
|
||||
select(AccountBase, amount_sum)
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
from typing import List
|
||||
|
||||
import brewman.schemas.non_contract_purchase as schemas
|
||||
|
||||
from brewman.core.security import get_current_active_user as get_user
|
||||
@@ -21,17 +19,16 @@ from sqlalchemy.orm import Session, contains_eager, joinedload
|
||||
router = APIRouter()
|
||||
|
||||
|
||||
@router.post("", response_model=List[schemas.NonContractPurchase])
|
||||
@router.post("", response_model=list[schemas.NonContractPurchase])
|
||||
def non_contract_purchases(
|
||||
user: UserToken = Security(get_user, scopes=["product-ledger"])
|
||||
) -> List[schemas.NonContractPurchase]:
|
||||
|
||||
) -> list[schemas.NonContractPurchase]:
|
||||
with SessionFuture() as db:
|
||||
return report(db)
|
||||
|
||||
|
||||
def report(db: Session) -> List[schemas.NonContractPurchase]:
|
||||
rcs: List[RateContract] = (
|
||||
def report(db: Session) -> list[schemas.NonContractPurchase]:
|
||||
rcs: list[RateContract] = (
|
||||
db.execute(
|
||||
select(RateContract)
|
||||
.join(RateContract.vendor)
|
||||
@@ -47,7 +44,7 @@ def report(db: Session) -> List[schemas.NonContractPurchase]:
|
||||
.scalars()
|
||||
.all()
|
||||
)
|
||||
list_: List[schemas.NonContractPurchase] = []
|
||||
list_: list[schemas.NonContractPurchase] = []
|
||||
for rc in rcs:
|
||||
for item in rc.items:
|
||||
invs = db.execute(
|
||||
|
||||
@@ -2,7 +2,6 @@ import uuid
|
||||
|
||||
from datetime import date, datetime
|
||||
from decimal import Decimal
|
||||
from typing import List, Optional, Tuple
|
||||
|
||||
import brewman.schemas.product_ledger as schemas
|
||||
|
||||
@@ -44,8 +43,8 @@ def show_blank(
|
||||
def show_data(
|
||||
id_: uuid.UUID,
|
||||
request: Request,
|
||||
s: Optional[str] = None,
|
||||
f: Optional[str] = None,
|
||||
s: str | None = None,
|
||||
f: str | None = None,
|
||||
user: UserToken = Security(get_user, scopes=["product-ledger"]),
|
||||
) -> schemas.ProductLedger:
|
||||
with SessionFuture() as db:
|
||||
@@ -69,7 +68,7 @@ def show_data(
|
||||
|
||||
def build_report(
|
||||
product_id: uuid.UUID, start_date: date, finish_date: date, db: Session
|
||||
) -> List[schemas.ProductLedgerItem]:
|
||||
) -> list[schemas.ProductLedgerItem]:
|
||||
running_total_q, running_total_a, opening = opening_balance(product_id, start_date, db)
|
||||
body = opening
|
||||
|
||||
@@ -141,7 +140,7 @@ def build_report(
|
||||
|
||||
def opening_balance(
|
||||
product_id: uuid.UUID, start_date: date, db: Session
|
||||
) -> Tuple[Decimal, Decimal, List[schemas.ProductLedgerItem]]:
|
||||
) -> tuple[Decimal, Decimal, list[schemas.ProductLedgerItem]]:
|
||||
row = db.execute(
|
||||
select(
|
||||
StockKeepingUnit.units,
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
from datetime import date, datetime
|
||||
from decimal import Decimal
|
||||
from typing import List, Optional, Tuple
|
||||
|
||||
import brewman.schemas.profit_loss as schemas
|
||||
|
||||
@@ -59,11 +58,11 @@ def report_data(
|
||||
|
||||
def build_profit_loss(
|
||||
start_date: date, finish_date: date, db: Session
|
||||
) -> Tuple[List[schemas.ProfitLossItem], schemas.ProfitLossItem]:
|
||||
) -> tuple[list[schemas.ProfitLossItem], schemas.ProfitLossItem]:
|
||||
profit_type_list = (
|
||||
db.execute(select(AccountType.id).where(AccountType.balance_sheet == False)).scalars().all() # noqa: E712
|
||||
)
|
||||
report: List[schemas.ProfitLossItem] = []
|
||||
report: list[schemas.ProfitLossItem] = []
|
||||
groups = {}
|
||||
|
||||
amount_sum = func.sum(Journal.amount * Journal.debit)
|
||||
@@ -139,7 +138,7 @@ def get_accumulated_profit(finish_date: date, db: Session) -> Decimal:
|
||||
db.execute(select(AccountType.id).where(AccountType.balance_sheet == False)).scalars().all() # noqa: E712
|
||||
)
|
||||
|
||||
accumulated_profit: Optional[Decimal] = db.execute(
|
||||
accumulated_profit: Decimal | None = db.execute(
|
||||
select(func.sum(Journal.amount * Journal.debit))
|
||||
.join(Journal.voucher)
|
||||
.join(Journal.account)
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
from datetime import date, datetime
|
||||
from typing import List
|
||||
|
||||
import brewman.schemas.purchase_entries as schemas
|
||||
|
||||
@@ -49,9 +48,9 @@ def report_data(
|
||||
return schemas.PurchaseEntries(startDate=start, finishDate=finish, body=body)
|
||||
|
||||
|
||||
def build_report(start_date: date, finish_date: date, db: Session) -> List[schemas.PurchaseEntriesItem]:
|
||||
def build_report(start_date: date, finish_date: date, db: Session) -> list[schemas.PurchaseEntriesItem]:
|
||||
body = []
|
||||
query: List[Voucher] = (
|
||||
query: list[Voucher] = (
|
||||
db.execute(
|
||||
select(Voucher)
|
||||
.join(Voucher.journals)
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
from datetime import datetime
|
||||
from typing import List, Tuple
|
||||
|
||||
import brewman.schemas.purchases as schemas
|
||||
|
||||
@@ -58,7 +57,7 @@ def report_data(
|
||||
|
||||
def build_report(
|
||||
start_date: str, finish_date: str, db: Session
|
||||
) -> Tuple[List[schemas.PurchasesItem], schemas.PurchasesItem]:
|
||||
) -> tuple[list[schemas.PurchasesItem], schemas.PurchasesItem]:
|
||||
body = []
|
||||
quantity_sum = func.sum(Journal.debit * Inventory.quantity).label("quantity")
|
||||
amount_sum = func.sum(Journal.debit * Inventory.quantity * Inventory.rate * (1 + Inventory.tax)).label("amount")
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import uuid
|
||||
|
||||
from datetime import date, datetime
|
||||
from typing import Dict, List, Tuple
|
||||
|
||||
import brewman.schemas.raw_material_cost as schemas
|
||||
|
||||
@@ -84,10 +83,10 @@ def report_id(
|
||||
|
||||
def build_report(
|
||||
start_date: date, finish_date: date, db: Session
|
||||
) -> Tuple[List[schemas.RawMaterialCostItem], schemas.RawMaterialCostItem]:
|
||||
) -> tuple[list[schemas.RawMaterialCostItem], schemas.RawMaterialCostItem]:
|
||||
body = []
|
||||
sum_issue = func.sum(case([(AccountBase.type_id == 2, Journal.signed_amount)], else_=0)).label("issue")
|
||||
sum_sale = func.sum(case([(AccountBase.type_id == 3, Journal.signed_amount * -1)], else_=0)).label("sale")
|
||||
sum_issue = func.sum(case((AccountBase.type_id == 2, Journal.signed_amount), else_=0)).label("issue")
|
||||
sum_sale = func.sum(case((AccountBase.type_id == 3, Journal.signed_amount * -1), else_=0)).label("sale")
|
||||
|
||||
query = db.execute(
|
||||
select(CostCentre, sum_issue, sum_sale)
|
||||
@@ -127,7 +126,7 @@ def build_report(
|
||||
|
||||
def build_report_id(
|
||||
cost_centre_id: uuid.UUID, start_date: date, finish_date: date, db: Session
|
||||
) -> List[schemas.RawMaterialCostItem]:
|
||||
) -> list[schemas.RawMaterialCostItem]:
|
||||
sum_quantity = func.sum(Inventory.quantity * Journal.debit).label("quantity")
|
||||
sum_net = func.sum(Inventory.rate * Inventory.quantity * Journal.debit).label("net")
|
||||
sum_gross = func.sum(Inventory.amount * Journal.debit).label("gross")
|
||||
@@ -150,9 +149,9 @@ def build_report_id(
|
||||
.order_by(ProductGroup.name, sum_net.desc())
|
||||
).all()
|
||||
|
||||
groups: Dict[uuid.UUID, schemas.RawMaterialCostItem] = {}
|
||||
groups: dict[uuid.UUID, schemas.RawMaterialCostItem] = {}
|
||||
counter = 0
|
||||
list_: List[schemas.RawMaterialCostItem] = []
|
||||
list_: list[schemas.RawMaterialCostItem] = []
|
||||
for product, pg, quantity, net, gross in query:
|
||||
if pg.id in groups:
|
||||
group = groups[pg.id]
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import uuid
|
||||
|
||||
from datetime import date, datetime
|
||||
from typing import List, Optional
|
||||
|
||||
import brewman.schemas.reconcile as schemas
|
||||
|
||||
@@ -40,8 +39,8 @@ def show_blank(
|
||||
def show_data(
|
||||
id_: uuid.UUID,
|
||||
request: Request,
|
||||
s: Optional[str] = None,
|
||||
f: Optional[str] = None,
|
||||
s: str | None = None,
|
||||
f: str | None = None,
|
||||
user: UserToken = Security(get_user, scopes=["reconcile"]),
|
||||
) -> schemas.Reconcile:
|
||||
with SessionFuture() as db:
|
||||
@@ -60,7 +59,7 @@ def show_data(
|
||||
|
||||
def build_report(
|
||||
account_id: uuid.UUID, start_date: date, finish_date: date, db: Session
|
||||
) -> List[schemas.ReconcileItem]:
|
||||
) -> list[schemas.ReconcileItem]:
|
||||
opening = opening_balance(account_id, start_date, db)
|
||||
body = [opening]
|
||||
|
||||
@@ -152,8 +151,8 @@ def save(
|
||||
id_: uuid.UUID,
|
||||
data: schemas.Reconcile,
|
||||
request: Request,
|
||||
s: Optional[str] = None,
|
||||
f: Optional[str] = None,
|
||||
s: str | None = None,
|
||||
f: str | None = None,
|
||||
user: UserToken = Security(get_user, scopes=["reconcile"]),
|
||||
) -> schemas.Reconcile:
|
||||
with SessionFuture() as db:
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
from datetime import date, datetime
|
||||
from decimal import Decimal
|
||||
from typing import List
|
||||
|
||||
import brewman.schemas.stock_movement as schemas
|
||||
|
||||
@@ -52,7 +51,7 @@ def report_data(
|
||||
return schemas.StockMovement(startDate=start, finishDate=finish, body=body)
|
||||
|
||||
|
||||
def build_stock_movement(start_date: date, finish_date: date, db: Session) -> List[schemas.StockMovementItem]:
|
||||
def build_stock_movement(start_date: date, finish_date: date, db: Session) -> list[schemas.StockMovementItem]:
|
||||
dict_ = {}
|
||||
quantity_sum = func.sum(Journal.debit * Inventory.quantity).label("quantity")
|
||||
openings = db.execute(
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
from datetime import date, datetime
|
||||
from typing import List
|
||||
|
||||
import brewman.schemas.trial_balance as schemas
|
||||
|
||||
@@ -44,7 +43,7 @@ def report_data(
|
||||
)
|
||||
|
||||
|
||||
def build_report(date_: date, db: Session) -> List[schemas.TrialBalanceItem]:
|
||||
def build_report(date_: date, db: Session) -> list[schemas.TrialBalanceItem]:
|
||||
amount_sum = func.sum(Journal.amount * Journal.debit).label("amount")
|
||||
query = db.execute(
|
||||
select(AccountBase, amount_sum)
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
import uuid
|
||||
|
||||
from typing import List
|
||||
|
||||
import brewman.schemas.role as schemas
|
||||
|
||||
from fastapi import APIRouter, HTTPException, Security, status
|
||||
@@ -14,8 +12,8 @@ from ..core.security import get_current_active_user as get_user
|
||||
from ..db.session import SessionFuture
|
||||
from ..models.permission import Permission
|
||||
from ..models.role import Role
|
||||
from ..models.role_permission import role_permission
|
||||
from ..models.user_role import user_role
|
||||
from ..models.role_permission import RolePermission
|
||||
from ..models.user_role import UserRole
|
||||
from ..schemas.user import UserToken
|
||||
|
||||
|
||||
@@ -61,7 +59,7 @@ def update_route(
|
||||
)
|
||||
|
||||
|
||||
def add_permissions(role: Role, permissions: List[schemas.PermissionItem], db: Session) -> None:
|
||||
def add_permissions(role: Role, permissions: list[schemas.PermissionItem], db: Session) -> None:
|
||||
for permission in permissions:
|
||||
gp = next((p for p in role.permissions if p.id == permission.id_), None)
|
||||
if permission.enabled and gp is None:
|
||||
@@ -76,12 +74,12 @@ def delete_route(
|
||||
user: UserToken = Security(get_user, scopes=["users"]),
|
||||
) -> schemas.RoleBlank:
|
||||
with SessionFuture() as db:
|
||||
if db.execute(select(count(user_role.c.id)).where(user_role.c.role_id == id_)).scalar_one() > 0:
|
||||
if db.execute(select(count(UserRole.id)).where(UserRole.role_id == id_)).scalar_one() > 0:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
||||
detail="This Role has been assigned to users and cannot be deleted.",
|
||||
)
|
||||
if db.execute(select(count(role_permission.c.id)).where(role_permission.c.role_id == id_)).scalar_one() > 0:
|
||||
if db.execute(select(count(RolePermission.id)).where(RolePermission.role_id == id_)).scalar_one() > 0:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
||||
detail="This Role has permissions and cannot be deleted.",
|
||||
@@ -101,12 +99,12 @@ def show_blank(
|
||||
return role_blank(db)
|
||||
|
||||
|
||||
@router.get("/list", response_model=List[schemas.RoleList])
|
||||
@router.get("/list", response_model=list[schemas.RoleList])
|
||||
async def show_list(
|
||||
user: UserToken = Security(get_user, scopes=["users"]),
|
||||
) -> List[schemas.RoleList]:
|
||||
) -> list[schemas.RoleList]:
|
||||
with SessionFuture() as db:
|
||||
roles: List[Role] = db.execute(select(Role).order_by(Role.name)).scalars().all()
|
||||
roles: list[Role] = db.execute(select(Role).order_by(Role.name)).scalars().all()
|
||||
return [
|
||||
schemas.RoleList(
|
||||
id=item.id,
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
import uuid
|
||||
|
||||
from typing import List
|
||||
|
||||
import brewman.schemas.user as schemas
|
||||
|
||||
from fastapi import APIRouter, Depends, HTTPException, Security, status
|
||||
@@ -15,7 +13,7 @@ from ..models.attendance import Attendance
|
||||
from ..models.login_history import LoginHistory
|
||||
from ..models.role import Role
|
||||
from ..models.user import User
|
||||
from ..models.user_role import user_role
|
||||
from ..models.user_role import UserRole
|
||||
from ..models.voucher import Voucher
|
||||
from ..schemas.user import UserToken
|
||||
|
||||
@@ -97,7 +95,7 @@ def update_route(
|
||||
)
|
||||
|
||||
|
||||
def add_roles(user: User, roles: List[schemas.RoleItem], db: Session) -> None:
|
||||
def add_roles(user: User, roles: list[schemas.RoleItem], db: Session) -> None:
|
||||
for role in roles:
|
||||
ug = next((g for g in user.roles if g.id == role.id_), None)
|
||||
if role.enabled and ug is None:
|
||||
@@ -122,7 +120,7 @@ def delete_route(
|
||||
db.execute(update(Voucher).where(Voucher.user_id == item.id).values(user_id=admin.id))
|
||||
db.execute(update(Attendance).where(Attendance.user_id == item.id).values(user_id=admin.id))
|
||||
db.execute(delete(LoginHistory).where(LoginHistory.user_id == item.id))
|
||||
db.execute(delete(user_role).where(user_role.c.user_id == item.id))
|
||||
db.execute(delete(UserRole).where(UserRole.user_id == item.id))
|
||||
db.execute(delete(User).where(User.id == item.id))
|
||||
db.commit()
|
||||
|
||||
@@ -135,12 +133,12 @@ def show_blank(
|
||||
return user_blank(db)
|
||||
|
||||
|
||||
@router.get("/list", response_model=List[schemas.UserList])
|
||||
@router.get("/list", response_model=list[schemas.UserList])
|
||||
async def show_list(
|
||||
user: UserToken = Security(get_user, scopes=["users"]),
|
||||
) -> List[schemas.UserList]:
|
||||
) -> list[schemas.UserList]:
|
||||
with SessionFuture() as db:
|
||||
users: List[User] = db.execute(select(User).order_by(User.name)).scalars().all()
|
||||
users: list[User] = db.execute(select(User).order_by(User.name)).scalars().all()
|
||||
return [
|
||||
schemas.UserList(
|
||||
id=item.id,
|
||||
@@ -154,8 +152,8 @@ async def show_list(
|
||||
]
|
||||
|
||||
|
||||
@router.get("/active", response_model=List[schemas.UserBlank])
|
||||
async def show_active(user: UserToken = Depends(get_user)) -> List[schemas.UserBlank]:
|
||||
@router.get("/active", response_model=list[schemas.UserBlank])
|
||||
async def show_active(user: UserToken = Depends(get_user)) -> list[schemas.UserBlank]:
|
||||
with SessionFuture() as db:
|
||||
return [
|
||||
schemas.UserBlank(name=name)
|
||||
|
||||
@@ -2,7 +2,6 @@ import uuid
|
||||
|
||||
from datetime import date
|
||||
from decimal import Decimal
|
||||
from typing import List, Optional, Tuple
|
||||
|
||||
import brewman.schemas.voucher as output
|
||||
|
||||
@@ -121,7 +120,7 @@ def delete_voucher(
|
||||
else:
|
||||
source = j_item.cost_centre_id
|
||||
|
||||
batch_consumed: Optional[bool]
|
||||
batch_consumed: bool | None
|
||||
if source == CostCentre.cost_centre_purchase():
|
||||
batch_consumed = True
|
||||
elif destination == CostCentre.cost_centre_purchase():
|
||||
@@ -357,10 +356,10 @@ def blank_voucher(info: BlankVoucherInfo, db: Session) -> output.Voucher:
|
||||
return json_voucher
|
||||
|
||||
|
||||
def incentive_employees(date_: date, db: Session) -> Tuple[List[output.Incentive], Decimal]:
|
||||
def incentive_employees(date_: date, db: Session) -> tuple[list[output.Incentive], Decimal]:
|
||||
start_date = get_first_day(date_)
|
||||
finish_date = date_
|
||||
details: List[output.Incentive] = []
|
||||
details: list[output.Incentive] = []
|
||||
employees = (
|
||||
db.execute(
|
||||
select(Employee)
|
||||
@@ -374,7 +373,7 @@ def incentive_employees(date_: date, db: Session) -> Tuple[List[output.Incentive
|
||||
.all()
|
||||
)
|
||||
for employee in employees:
|
||||
att: List[Attendance] = (
|
||||
att: list[Attendance] = (
|
||||
db.execute(
|
||||
select(Attendance).where(
|
||||
Attendance.employee_id == employee.id,
|
||||
@@ -398,7 +397,7 @@ def incentive_employees(date_: date, db: Session) -> Tuple[List[output.Incentive
|
||||
)
|
||||
)
|
||||
|
||||
amount: Optional[Decimal] = db.execute(
|
||||
amount: Decimal | None = db.execute(
|
||||
select(func.sum(Journal.amount * Journal.debit))
|
||||
.join(Journal.voucher)
|
||||
.where(
|
||||
@@ -430,7 +429,7 @@ def check_voucher_edit_allowed(voucher: Voucher, user: UserToken) -> None:
|
||||
)
|
||||
|
||||
|
||||
def get_batch_quantity(id_: uuid.UUID, voucher_id: Optional[uuid.UUID], db: Session) -> Decimal:
|
||||
def get_batch_quantity(id_: uuid.UUID, voucher_id: uuid.UUID | None, db: Session) -> Decimal:
|
||||
query = (
|
||||
select(func.sum(Inventory.quantity * Journal.debit))
|
||||
.join(Inventory.voucher)
|
||||
|
||||
Loaded 100 of 344 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user