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:
tanshu committed 2023-07-23 08:12:21 +05:30
1 parent d2d26ab1ae
commit 22cac61761
344 files changed
+3247 -2370

No files matched your search

+1
View File
@@ -1,3 +1,4 @@
[alembic]
# path to migration scripts
script_location = alembic
prepend_sys_path = .
+2 -3
View File
@@ -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 ###
+3 -3
View File
@@ -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(
+5 -6
View File
@@ -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:
+2 -3
View File
@@ -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:
+6 -3
View File
@@ -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
+3 -2
View File
@@ -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
+3 -1
View File
@@ -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"])
+6 -6
View File
@@ -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)
+24 -31
View File
@@ -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:
+22 -10
View File
@@ -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_")
+16 -16
View File
@@ -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 -2
View File
@@ -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)),
+18 -18
View File
@@ -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:
+15 -16
View File
@@ -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
+17 -18
View File
@@ -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
+12 -12
View File
@@ -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_
+13 -13
View File
@@ -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
+14 -14
View File
@@ -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_
+16 -17
View File
@@ -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)
+17 -19
View File
@@ -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_
+10 -12
View File
@@ -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:
+13 -15
View File
@@ -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
+16 -19
View File
@@ -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
+20 -23
View File
@@ -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_
+13 -18
View File
@@ -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
+9 -18
View File
@@ -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
+10 -14
View File
@@ -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_
+22 -24
View File
@@ -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
+11 -13
View File
@@ -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_
+21 -23
View File
@@ -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
+12 -15
View File
@@ -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
+25 -49
View File
@@ -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"
)
+13 -33
View File
@@ -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_
+17
View File
@@ -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"))
+30
View File
@@ -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
),
)
+12 -19
View File
@@ -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]
)
+11 -13
View File
@@ -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)
+1
View File
@@ -4,3 +4,4 @@ import enum
class SettingType(enum.IntEnum):
VOUCHER_LOCK = 0
MAINTENANCE_MODE = 1
RECIPE_TEMPLATE = 2
+20 -20
View File
@@ -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
+25
View File
@@ -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"
)
-47
View File
@@ -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)
+29 -24
View File
@@ -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:
+11 -13
View File
@@ -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)
+32 -30
View File
@@ -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
+5 -6
View File
@@ -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,
+14 -15
View File
@@ -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))
+2 -4
View File
@@ -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()
+3 -3
View File
@@ -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)
+3 -5
View File
@@ -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
+3 -5
View File
@@ -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)
+5 -8
View File
@@ -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)
+2 -4
View File
@@ -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 = []
+2 -4
View File
@@ -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()
+2 -3
View File
@@ -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)
+4 -5
View File
@@ -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 []
+7 -8
View File
@@ -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 = (
+10 -11
View File
@@ -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
+5 -6
View File
@@ -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
+11 -12
View File
@@ -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)
+16 -17
View File
@@ -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)
+4 -5
View File
@@ -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)
+5 -6
View File
@@ -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":
+7 -9
View File
@@ -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 -2
View File
@@ -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:
+2 -4
View File
@@ -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()
+2 -4
View File
@@ -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()
+13 -16
View File
@@ -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")
+2 -4
View File
@@ -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)
+9 -10
View File
@@ -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_
)
+8 -9
View File
@@ -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(
+4 -6
View File
@@ -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 -3
View File
@@ -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
View File
@@ -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=[],
+109
View File
@@ -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
)
+2 -3
View File
@@ -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
+2 -3
View File
@@ -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 -2
View File
@@ -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 = (
+16 -16
View File
@@ -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
+3 -5
View File
@@ -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 -2
View File
@@ -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]
+5 -6
View File
@@ -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)
+8 -10
View File
@@ -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,
+8 -10
View File
@@ -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)
+6 -7
View File
@@ -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