Moving to FastAPI
Config is not properly working with .env file as of now Cost Centre is mostly working, going to work on Accounts now
This commit is contained in:
1 parent
72044476a8
commit
fe74ef44bf
89 files changed
+1516
-2421
No files matched your search
@@ -0,0 +1,9 @@
|
||||
HOST=0.0.0.0
|
||||
PORT=9998
|
||||
LOG_LEVEL=info
|
||||
DEBUG=true
|
||||
DB_URL=postgresql://postgres:123456@localhost:5432/hops
|
||||
MODULE_NAME=brewman.main
|
||||
SERVER_NAME=localhost
|
||||
SERVER_HOST=localhost
|
||||
PROJECT_NAME=bifrost
|
||||
@@ -1,5 +1,6 @@
|
||||
*.pyc
|
||||
env
|
||||
venv
|
||||
.project
|
||||
.pydevproject
|
||||
*/__pycache__/
|
||||
|
||||
+1
-1
@@ -1,2 +1,2 @@
|
||||
include *.txt *.ini *.cfg *.rst
|
||||
include *.txt *.ini *.cfg *.rst .env
|
||||
recursive-include brewman *.ico *.png *.css *.gif *.jpg *.txt *.js *.html *.map *.eot *.svg *.ttf *.woff
|
||||
@@ -1,38 +1,3 @@
|
||||
import os
|
||||
from pyramid.config import Configurator
|
||||
|
||||
from pyramid.session import SignedCookieSessionFactory
|
||||
from brewman.renderers import json_renderer, CSVRenderer
|
||||
from brewman.transactional_view_deriver import transactional_view
|
||||
|
||||
|
||||
def main(global_config, **settings):
|
||||
""" This function returns a Pyramid WSGI application.
|
||||
"""
|
||||
if 'sqlalchemy.url' not in settings:
|
||||
DB_NAME = os.environ['DB_NAME']
|
||||
DB_USER = os.environ['DB_USER']
|
||||
DB_PASS = os.environ['DB_PASS']
|
||||
DB_URI = 'postgresql://{0}:{1}@postgres:5432/{2}'.format(
|
||||
DB_USER, DB_PASS, DB_NAME
|
||||
)
|
||||
settings['sqlalchemy.url']= DB_URI
|
||||
|
||||
SECRET_KEY = os.environ.get('SECRET_KEY', settings.get('secret_key', ''))
|
||||
session_factory = SignedCookieSessionFactory(SECRET_KEY)
|
||||
|
||||
|
||||
config = Configurator(
|
||||
settings=settings,
|
||||
session_factory=session_factory
|
||||
)
|
||||
config.include('.security')
|
||||
config.include('.models')
|
||||
config.include('.routes')
|
||||
config.add_view_deriver(transactional_view)
|
||||
config.add_renderer(name='json', factory=json_renderer)
|
||||
config.add_renderer(name='csv', factory=CSVRenderer)
|
||||
config.scan()
|
||||
|
||||
return config.make_wsgi_app()
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
from brewman.main import init
|
||||
|
||||
init()
|
||||
@@ -0,0 +1,12 @@
|
||||
from environs import Env
|
||||
|
||||
env = Env()
|
||||
env.read_env() # read .env file, if it exists
|
||||
|
||||
|
||||
class Settings:
|
||||
debug: bool = env("DEBUG")
|
||||
host: str = env("HOST")
|
||||
port: int = env.int("PORT")
|
||||
db_url: str = env("DB_URL")
|
||||
log_level: str = env("LOG_LEVEL")
|
||||
File renamed without changes.
@@ -0,0 +1,52 @@
|
||||
import secrets
|
||||
from typing import Any, Dict, List, Optional, Union
|
||||
|
||||
from pydantic import AnyHttpUrl, BaseSettings, PostgresDsn, validator
|
||||
|
||||
|
||||
class Settings(BaseSettings):
|
||||
API_V1_STR: str = "/api/v1"
|
||||
SECRET_KEY: str = secrets.token_urlsafe(32)
|
||||
# 60 minutes * 24 hours * 8 days = 8 days
|
||||
ACCESS_TOKEN_EXPIRE_MINUTES: int = 60 * 24 * 8
|
||||
SERVER_NAME: str = "localhost"
|
||||
SERVER_HOST: AnyHttpUrl = "http://localhost:9998"
|
||||
# BACKEND_CORS_ORIGINS is a JSON-formatted list of origins
|
||||
# e.g: '["http://localhost", "http://localhost:4200", "http://localhost:3000", \
|
||||
# "http://localhost:8080", "http://local.dockertoolbox.tiangolo.com"]'
|
||||
BACKEND_CORS_ORIGINS: List[AnyHttpUrl] = []
|
||||
|
||||
@validator("BACKEND_CORS_ORIGINS", pre=True)
|
||||
def assemble_cors_origins(cls, v: Union[str, List[str]]) -> Union[List[str], str]:
|
||||
if isinstance(v, str) and not v.startswith("["):
|
||||
return [i.strip() for i in v.split(",")]
|
||||
elif isinstance(v, (list, str)):
|
||||
return v
|
||||
raise ValueError(v)
|
||||
|
||||
PROJECT_NAME: str = "bifrost"
|
||||
|
||||
POSTGRES_SERVER: str = "localhost"
|
||||
POSTGRES_USER: str = "postgres"
|
||||
POSTGRES_PASSWORD: str = "123456"
|
||||
POSTGRES_DB: str = "hops"
|
||||
SQLALCHEMY_DATABASE_URI: Optional[PostgresDsn] = None
|
||||
|
||||
@validator("SQLALCHEMY_DATABASE_URI", pre=True)
|
||||
def assemble_db_connection(cls, v: Optional[str], values: Dict[str, Any]) -> Any:
|
||||
if isinstance(v, str):
|
||||
return v
|
||||
return PostgresDsn.build(
|
||||
scheme="postgresql",
|
||||
user=values.get("POSTGRES_USER"),
|
||||
password=values.get("POSTGRES_PASSWORD"),
|
||||
host=values.get("POSTGRES_SERVER"),
|
||||
path=f"/{values.get('POSTGRES_DB') or ''}",
|
||||
)
|
||||
|
||||
class Config:
|
||||
case_sensitive = True
|
||||
env_file = '.env'
|
||||
|
||||
|
||||
settings = Settings()
|
||||
@@ -0,0 +1,122 @@
|
||||
import uuid
|
||||
from datetime import datetime, timedelta
|
||||
from typing import List
|
||||
from jwt import PyJWTError
|
||||
|
||||
from fastapi import Depends, HTTPException, status, Security
|
||||
from fastapi.security import OAuth2PasswordBearer, SecurityScopes
|
||||
from pydantic import BaseModel, ValidationError
|
||||
from sqlalchemy.orm import Session
|
||||
from jose import jwt
|
||||
|
||||
from brewman.models.auth import User as UserModel
|
||||
from ..db.session import SessionLocal
|
||||
|
||||
|
||||
# to get a string like this run:
|
||||
# openssl rand -hex 32
|
||||
SECRET_KEY = "8546a61262dab7c05ccf2e26abe30bc10966904df6dfd29259ea85dd0844a8e7"
|
||||
ALGORITHM = "HS256"
|
||||
ACCESS_TOKEN_EXPIRE_MINUTES = 30
|
||||
|
||||
|
||||
oauth2_scheme = OAuth2PasswordBearer(
|
||||
tokenUrl="/token",
|
||||
scopes={}
|
||||
)
|
||||
|
||||
|
||||
class Token(BaseModel):
|
||||
access_token: str
|
||||
token_type: str
|
||||
|
||||
|
||||
class TokenData(BaseModel):
|
||||
username: str = None
|
||||
scopes: List[str] = []
|
||||
|
||||
|
||||
class User(BaseModel):
|
||||
id_: uuid.UUID
|
||||
name: str
|
||||
locked_out: bool = None
|
||||
password: str
|
||||
|
||||
|
||||
def f7(seq):
|
||||
seen = set()
|
||||
seen_add = seen.add
|
||||
return [x for x in seq if not (x in seen or seen_add(x))]
|
||||
|
||||
|
||||
# Dependency
|
||||
def get_db():
|
||||
try:
|
||||
db = SessionLocal()
|
||||
yield db
|
||||
finally:
|
||||
db.close()
|
||||
|
||||
|
||||
def create_access_token(*, data: dict, expires_delta: timedelta = None):
|
||||
to_encode = data.copy()
|
||||
if expires_delta:
|
||||
expire = datetime.utcnow() + expires_delta
|
||||
else:
|
||||
expire = datetime.utcnow() + timedelta(minutes=15)
|
||||
to_encode.update({"exp": expire})
|
||||
encoded_jwt = jwt.encode(to_encode, SECRET_KEY, algorithm=ALGORITHM)
|
||||
return encoded_jwt
|
||||
|
||||
|
||||
def get_user(username: str, db: Session):
|
||||
user = db.query(UserModel).filter(UserModel.name.ilike(username)).first()
|
||||
if user:
|
||||
return User(id_=user.id, name=user.name, locked_out=user.locked_out, password=user.password)
|
||||
|
||||
|
||||
def authenticate_user(username: str, password: str, db: Session):
|
||||
found, user = UserModel.auth(username, password, db)
|
||||
if not found:
|
||||
return False
|
||||
return user
|
||||
|
||||
|
||||
async def get_current_user(security_scopes: SecurityScopes, token: str = Depends(oauth2_scheme), db: Session = Depends(get_db)):
|
||||
if security_scopes.scopes:
|
||||
authenticate_value = f'Bearer scope="{security_scopes.scope_str}"'
|
||||
else:
|
||||
authenticate_value = f"Bearer"
|
||||
credentials_exception = HTTPException(
|
||||
status_code=status.HTTP_401_UNAUTHORIZED,
|
||||
detail="Could not validate credentials",
|
||||
headers={"WWW-Authenticate": authenticate_value},
|
||||
)
|
||||
try:
|
||||
payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM])
|
||||
username: str = payload.get("sub")
|
||||
if username is None:
|
||||
raise credentials_exception
|
||||
token_scopes = payload.get("scopes", [])
|
||||
token_data = TokenData(scopes=token_scopes, username=username)
|
||||
except (PyJWTError, ValidationError):
|
||||
raise credentials_exception
|
||||
user = get_user(username=token_data.username, db=db)
|
||||
if user is None:
|
||||
raise credentials_exception
|
||||
for scope in security_scopes.scopes:
|
||||
if scope not in token_data.scopes:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_401_UNAUTHORIZED,
|
||||
detail="Not enough permissions",
|
||||
headers={"WWW-Authenticate": authenticate_value},
|
||||
)
|
||||
return user
|
||||
|
||||
|
||||
async def get_current_active_user(current_user: User = Security(get_current_user, scopes=["authenticated"])):
|
||||
if current_user.locked_out:
|
||||
raise HTTPException(status_code=400, detail="Inactive user")
|
||||
return current_user
|
||||
|
||||
|
||||
File renamed without changes.
@@ -0,0 +1,31 @@
|
||||
# Import all the models, so that Base has them before being
|
||||
# imported by Alembic
|
||||
from brewman.db.base_class import Base # noqa
|
||||
from brewman.models import (
|
||||
Client,
|
||||
user_group,
|
||||
role_group,
|
||||
User,
|
||||
LoginHistory,
|
||||
Group,
|
||||
Role,
|
||||
Product,
|
||||
AttendanceType,
|
||||
CostCentre,
|
||||
Employee,
|
||||
Account,
|
||||
AccountBase,
|
||||
AccountType,
|
||||
ProductGroup,
|
||||
Recipe,
|
||||
RecipeItem,
|
||||
Attendance,
|
||||
Batch,
|
||||
Fingerprint,
|
||||
Inventory,
|
||||
Journal,
|
||||
Product,
|
||||
SalaryDeduction,
|
||||
Voucher,
|
||||
VoucherType,
|
||||
) # noqa
|
||||
@@ -0,0 +1,16 @@
|
||||
from sqlalchemy.ext.declarative import declarative_base
|
||||
from sqlalchemy.schema import MetaData
|
||||
|
||||
# Recommended naming convention used by Alembic, as various different database
|
||||
# providers will autogenerate vastly different names making migrations more
|
||||
# difficult. See: http://alembic.zzzcomputing.com/en/latest/naming.html
|
||||
NAMING_CONVENTION = {
|
||||
"ix": "ix_%(column_0_label)s",
|
||||
"uq": "uq_%(table_name)s_%(column_0_name)s",
|
||||
"ck": "ck_%(table_name)s_%(constraint_name)s",
|
||||
"fk": "fk_%(table_name)s_%(column_0_name)s_%(referred_table_name)s",
|
||||
"pk": "pk_%(table_name)s",
|
||||
}
|
||||
|
||||
metadata = MetaData(naming_convention=NAMING_CONVENTION)
|
||||
Base = declarative_base(metadata=metadata)
|
||||
@@ -0,0 +1,25 @@
|
||||
from sqlalchemy.orm import Session
|
||||
|
||||
from app import crud, schemas
|
||||
from brewman.core.config import settings
|
||||
from brewman.db import base # noqa: F401
|
||||
|
||||
# make sure all SQL Alchemy models are imported (app.db.base) before initializing DB
|
||||
# otherwise, SQL Alchemy might fail to initialize relationships properly
|
||||
# for more details: https://github.com/tiangolo/full-stack-fastapi-postgresql/issues/28
|
||||
|
||||
|
||||
def init_db(db: Session) -> None:
|
||||
# Tables should be created with Alembic migrations
|
||||
# But if you don't want to use migrations, create
|
||||
# the tables un-commenting the next line
|
||||
# Base.metadata.create_all(bind=engine)
|
||||
|
||||
user = crud.user.get_by_email(db, email=settings.FIRST_SUPERUSER)
|
||||
if not user:
|
||||
user_in = schemas.UserCreate(
|
||||
email=settings.FIRST_SUPERUSER,
|
||||
password=settings.FIRST_SUPERUSER_PASSWORD,
|
||||
is_superuser=True,
|
||||
)
|
||||
user = crud.user.create(db, obj_in=user_in) # noqa: F841
|
||||
@@ -0,0 +1,7 @@
|
||||
from sqlalchemy import create_engine
|
||||
from sqlalchemy.orm import sessionmaker
|
||||
|
||||
from brewman.core.config import settings
|
||||
|
||||
engine = create_engine(settings.SQLALCHEMY_DATABASE_URI, pool_pre_ping=True)
|
||||
SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)
|
||||
@@ -0,0 +1,50 @@
|
||||
import uvicorn
|
||||
from fastapi import FastAPI
|
||||
|
||||
from .routers import (
|
||||
account,
|
||||
account_types,
|
||||
attendance_types,
|
||||
attendance,
|
||||
employee_attendance,
|
||||
attendance_report,
|
||||
cost_centre,
|
||||
employee,
|
||||
fingerprint,
|
||||
product,
|
||||
product_group,
|
||||
recipe,
|
||||
login
|
||||
)
|
||||
from .routers.auth import client, user, group
|
||||
from .db.base_class import Base
|
||||
from .config import Settings as settings
|
||||
from .db.session import SessionLocal, engine
|
||||
|
||||
Base.metadata.create_all(bind=engine)
|
||||
|
||||
app = FastAPI()
|
||||
|
||||
|
||||
# app.include_router(brewman.routers, prefix="/api/db-image", tags=["db-image"])
|
||||
app.include_router(login.router, tags=["login"])
|
||||
app.include_router(account.router, prefix="/api/accounts", tags=["accounts"])
|
||||
app.include_router(account_types.router, prefix="/api/account-types", tags=["accounts"])
|
||||
app.include_router(attendance.router, prefix="/api/attendance", tags=["attendance"])
|
||||
app.include_router(attendance_types.router, prefix="/api/attendance-types", tags=["attendance"])
|
||||
app.include_router(employee_attendance.router, prefix="/api/employee-attendance", tags=["attendance"])
|
||||
app.include_router(employee_attendance.router, prefix="/api/employee-attendance", tags=["attendance"])
|
||||
app.include_router(attendance_report.router, prefix="/api/attendance-report", tags=["attendance"])
|
||||
app.include_router(cost_centre.router, prefix="/api/cost-centres", tags=["cost-centres"])
|
||||
app.include_router(employee.router, prefix="/api/employees", tags=["employees"])
|
||||
app.include_router(fingerprint.router, prefix="/api/fingerprint", tags=["employees"])
|
||||
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(client.router, prefix="/api/clients", tags=["users"])
|
||||
app.include_router(group.router, prefix="/api/groups", tags=["users"])
|
||||
app.include_router(user.router, prefix="/api/users", tags=["users"])
|
||||
|
||||
def init():
|
||||
uvicorn.run(app, host=settings.host, port=settings.port)
|
||||
+19
-12
@@ -1,20 +1,17 @@
|
||||
from sqlalchemy import engine_from_config
|
||||
from sqlalchemy.orm import sessionmaker
|
||||
from sqlalchemy.orm import configure_mappers
|
||||
import zope.sqlalchemy
|
||||
|
||||
# import or define all models here to ensure they are attached to the
|
||||
# Base.metadata prior to any initialization routines
|
||||
from .voucher import (
|
||||
Attendance,
|
||||
Batch,
|
||||
Fingerprint,
|
||||
Inventory,
|
||||
Journal,
|
||||
Product,
|
||||
SalaryDeduction,
|
||||
Voucher,
|
||||
VoucherType,
|
||||
from .auth import (
|
||||
Client,
|
||||
user_group,
|
||||
role_group,
|
||||
User,
|
||||
LoginHistory,
|
||||
Group,
|
||||
Role
|
||||
)
|
||||
from .master import (
|
||||
Product,
|
||||
@@ -28,7 +25,17 @@ from .master import (
|
||||
Recipe,
|
||||
RecipeItem,
|
||||
)
|
||||
from .auth import Client, Group, Role, User, role_group, user_group, LoginHistory
|
||||
from .voucher import (
|
||||
Attendance,
|
||||
Batch,
|
||||
Fingerprint,
|
||||
Inventory,
|
||||
Journal,
|
||||
Product,
|
||||
SalaryDeduction,
|
||||
Voucher,
|
||||
VoucherType,
|
||||
)
|
||||
|
||||
# run configure_mappers after defining all of the models to ensure
|
||||
# all relationships can be setup
|
||||
|
||||
@@ -108,7 +108,7 @@ class User(Base):
|
||||
self.id = id
|
||||
|
||||
@classmethod
|
||||
def auth(cls, name, password, dbsession):
|
||||
def auth(cls, name, password, dbsession) -> (bool, any):
|
||||
if password is None:
|
||||
return False, None
|
||||
user = dbsession.query(User).filter(User.name.ilike(name)).first()
|
||||
|
||||
@@ -1,55 +0,0 @@
|
||||
import csv
|
||||
from decimal import Decimal
|
||||
from io import StringIO
|
||||
import uuid
|
||||
|
||||
from pyramid.renderers import JSON
|
||||
|
||||
|
||||
class CSVRenderer(object):
|
||||
def __init__(self, info):
|
||||
pass
|
||||
|
||||
def __call__(self, value, system):
|
||||
csv_data = StringIO()
|
||||
writer = csv.writer(csv_data, delimiter=",", quoting=csv.QUOTE_MINIMAL)
|
||||
|
||||
if "header" in value:
|
||||
writer.writerow(value["header"])
|
||||
if "rows" in value:
|
||||
writer.writerows(value["rows"])
|
||||
if "footer" in value:
|
||||
writer.writerows(value["footer"])
|
||||
|
||||
request = system.get("request")
|
||||
if request is not None:
|
||||
response = request.response
|
||||
ct = response.content_type
|
||||
if ct == response.default_content_type:
|
||||
response.content_type = "text/csv"
|
||||
filename = value["filename"] if "filename" in value else "report.csv"
|
||||
response.content_disposition = 'attachment;filename="{0}"'.format(filename)
|
||||
return csv_data.getvalue()
|
||||
|
||||
|
||||
json_renderer = JSON()
|
||||
|
||||
|
||||
class DecimalAsFloatHack(float):
|
||||
def __init__(self, d):
|
||||
self.d = d
|
||||
|
||||
def __repr__(self):
|
||||
return str(self.d)
|
||||
|
||||
|
||||
def decimal_adaptor(obj, request):
|
||||
return DecimalAsFloatHack(obj)
|
||||
|
||||
|
||||
def uuid_adaptor(obj, request):
|
||||
return str(obj)
|
||||
|
||||
|
||||
json_renderer.add_adapter(Decimal, decimal_adaptor)
|
||||
json_renderer.add_adapter(uuid.UUID, uuid_adaptor)
|
||||
File renamed without changes.
+1
-9
@@ -1,16 +1,8 @@
|
||||
from pyramid.view import view_config
|
||||
from sqlalchemy import func, distinct, over, desc
|
||||
import transaction
|
||||
|
||||
from brewman.models.voucher import Attendance
|
||||
|
||||
|
||||
@view_config(
|
||||
request_method="POST",
|
||||
route_name="api_db_integrity",
|
||||
renderer="json",
|
||||
permission="Authenticated",
|
||||
)
|
||||
@router.post("/api/db-integrity") # "Authenticated"
|
||||
def post_check_db(request):
|
||||
info = {}
|
||||
|
||||
@@ -1,9 +1,6 @@
|
||||
import datetime
|
||||
import uuid
|
||||
from decimal import Decimal
|
||||
|
||||
import transaction
|
||||
from pyramid.view import view_config
|
||||
from sqlalchemy import func, and_, distinct
|
||||
from sqlalchemy.orm import aliased, joinedload_all
|
||||
|
||||
@@ -22,13 +19,7 @@ from brewman.models.voucher import (
|
||||
)
|
||||
|
||||
|
||||
@view_config(
|
||||
request_method="POST",
|
||||
route_name="api_rebase",
|
||||
renderer="json",
|
||||
permission="Rebase",
|
||||
trans=True,
|
||||
)
|
||||
@router.post("/api/rebase/{date}") # "Rebase"
|
||||
def rebase(request):
|
||||
# request.dbsession.execute('SET statement_timeout TO 300000;') # 5 minutes
|
||||
date = request.matchdict.get("date", None)
|
||||
@@ -1,28 +1,9 @@
|
||||
import datetime
|
||||
|
||||
import pkg_resources
|
||||
import transaction
|
||||
from pyramid.response import FileResponse
|
||||
from pyramid.view import view_config
|
||||
|
||||
from brewman.models.auth import User
|
||||
from brewman.models.master import DbSetting
|
||||
|
||||
|
||||
@view_config(route_name="settings", permission="Authenticated")
|
||||
def html(request):
|
||||
package, resource = "brewman:static/index.html".split(":", 1)
|
||||
file = pkg_resources.resource_filename(package, resource)
|
||||
return FileResponse(file, request=request)
|
||||
|
||||
|
||||
@view_config(
|
||||
request_method="POST",
|
||||
route_name="api_lock_information",
|
||||
renderer="json",
|
||||
permission="Lock Date",
|
||||
trans=True,
|
||||
)
|
||||
@router.post("/api/lock-information") # "Lock Date"
|
||||
def set_lock_info(request):
|
||||
start_locked = request.json_body["lockOlder"]
|
||||
finish_locked = request.json_body["lockNewer"]
|
||||
@@ -59,13 +40,7 @@ def set_lock_info(request):
|
||||
return get_lock_info(request)
|
||||
|
||||
|
||||
@view_config(
|
||||
request_method="DELETE",
|
||||
route_name="api_lock_information",
|
||||
renderer="json",
|
||||
permission="Lock Date",
|
||||
trans=True,
|
||||
)
|
||||
@router.delete("/api/lock-information") # "Lock Date"
|
||||
def clear_lock_info(request):
|
||||
lock_date = (
|
||||
request.dbsession.query(DbSetting).filter(DbSetting.name == "Lock Info").first()
|
||||
@@ -76,12 +51,7 @@ def clear_lock_info(request):
|
||||
return {}
|
||||
|
||||
|
||||
@view_config(
|
||||
request_method="GET",
|
||||
route_name="api_lock_information",
|
||||
renderer="json",
|
||||
permission="Authenticated",
|
||||
)
|
||||
@router.get("/api/lock-information") # "Authenticated"
|
||||
def get_lock_info(request):
|
||||
data = (
|
||||
request.dbsession.query(DbSetting).filter(DbSetting.name == "Lock Info").first()
|
||||
@@ -106,12 +76,7 @@ def get_lock_info(request):
|
||||
return info
|
||||
|
||||
|
||||
@view_config(
|
||||
request_method="GET",
|
||||
route_name="api_maintenance",
|
||||
renderer="json",
|
||||
permission="Authenticated",
|
||||
)
|
||||
@router.get("/api/maintenance") # "Authenticated"
|
||||
def get_maintenance(request):
|
||||
data = (
|
||||
request.dbsession.query(DbSetting)
|
||||
@@ -124,13 +89,7 @@ def get_maintenance(request):
|
||||
return {"enabled": True, "user": user.name}
|
||||
|
||||
|
||||
@view_config(
|
||||
request_method="POST",
|
||||
route_name="api_maintenance",
|
||||
renderer="json",
|
||||
permission="Maintenance",
|
||||
trans=True,
|
||||
)
|
||||
@router.post("/api/maintenance") # "Maintenance"
|
||||
def set_maintenance(request):
|
||||
status = request.json_body["enabled"]
|
||||
maintenance = (
|
||||
@@ -2,22 +2,13 @@ import datetime
|
||||
from decimal import Decimal
|
||||
import uuid
|
||||
|
||||
from pyramid.view import view_config
|
||||
from sqlalchemy import func
|
||||
import transaction
|
||||
|
||||
from brewman.models.master import AccountBase, CostCentre, Product
|
||||
from brewman.models.validation_exception import ValidationError
|
||||
from brewman.models.voucher import Journal, Voucher, VoucherType, Batch, Inventory
|
||||
|
||||
|
||||
@view_config(
|
||||
request_method="POST",
|
||||
route_name="api_reset_stock",
|
||||
renderer="json",
|
||||
permission="Reset Stock",
|
||||
trans=True,
|
||||
)
|
||||
@router.post("/api/reset-stock/{id}") # "Reset Stock"
|
||||
def rebase(request):
|
||||
user_id = uuid.UUID(request.authenticated_userid)
|
||||
product = (
|
||||
@@ -4,37 +4,15 @@ from datetime import date, datetime, timedelta, time
|
||||
from decimal import Decimal
|
||||
from io import BytesIO
|
||||
|
||||
import pkg_resources
|
||||
from pyramid.httpexceptions import HTTPForbidden, HTTPFound
|
||||
from pyramid.response import FileResponse, Response
|
||||
from pyramid.view import view_config
|
||||
|
||||
from brewman.models.master import DbSetting
|
||||
from brewman.models.voucher import DbImage
|
||||
|
||||
from fastapi import APIRouter
|
||||
|
||||
@view_config(route_name="home")
|
||||
@view_config(request_method="GET", route_name="login")
|
||||
def home(request):
|
||||
package, resource = "brewman:static/index.html".split(":", 1)
|
||||
file = pkg_resources.resource_filename(package, resource)
|
||||
return FileResponse(file, request=request)
|
||||
router = APIRouter()
|
||||
|
||||
|
||||
@view_config(context=HTTPForbidden)
|
||||
def forbidden_json(request):
|
||||
if request.accept.quality("application/json") == 1:
|
||||
response = Response("Forbidden")
|
||||
response.status_int = 401
|
||||
return response
|
||||
else:
|
||||
ret = HTTPFound(
|
||||
location=request.route_url("login", _query={"returnUrl": request.path_qs})
|
||||
)
|
||||
return ret
|
||||
|
||||
|
||||
@view_config(route_name="db_image")
|
||||
@router.get("/{id}/{type}")
|
||||
def db_image(request):
|
||||
item = (
|
||||
request.dbsession.query(DbImage)
|
||||
@@ -0,0 +1,243 @@
|
||||
import uuid
|
||||
from datetime import datetime
|
||||
|
||||
from fastapi import APIRouter, Depends, Security
|
||||
from pydantic import ValidationError
|
||||
from sqlalchemy import func
|
||||
from sqlalchemy.orm import joinedload_all, Session
|
||||
|
||||
from ..core.security import User, get_current_active_user as get_user
|
||||
from ..db.session import SessionLocal
|
||||
from ..models.master import CostCentre, Account, AccountType, AccountBase
|
||||
from ..models.validation_exception import ValidationError
|
||||
from ..models.voucher import Voucher, Journal, VoucherType
|
||||
from ..schemas.master import Account as AccountSchema
|
||||
router = APIRouter()
|
||||
|
||||
|
||||
# Dependency
|
||||
def get_db():
|
||||
try:
|
||||
db = SessionLocal()
|
||||
yield db
|
||||
finally:
|
||||
db.close()
|
||||
|
||||
|
||||
@router.post("/")
|
||||
def save(data: AccountSchema, db: Session = Depends(get_db), user: User = Security(get_user, scopes=["accounts"])):
|
||||
try:
|
||||
item = Account(
|
||||
code=0,
|
||||
name=data.name,
|
||||
type=data.type,
|
||||
is_starred=data.is_starred,
|
||||
is_active=data.is_active,
|
||||
is_reconcilable=data.is_reconcilable,
|
||||
cost_centre_id=data.cost_centre.id_,
|
||||
).create(db)
|
||||
db.commit()
|
||||
return account_info(item.id, db)
|
||||
except:
|
||||
db.rollback()
|
||||
finally:
|
||||
db.close()
|
||||
|
||||
|
||||
@router.put("/{id_}")
|
||||
def update(id_: uuid.UUID, db: Session = Depends(get_db), user: User = Security(get_user, scopes=["accounts"])):
|
||||
item = (
|
||||
db.query(Account)
|
||||
.filter(Account.id == id_)
|
||||
.first()
|
||||
)
|
||||
if item.is_fixture:
|
||||
raise ValidationError(
|
||||
"{0} is a fixture and cannot be edited or deleted.".format(item.name)
|
||||
)
|
||||
new_type = int(request.json_body["type"])
|
||||
if not item.type == new_type:
|
||||
item.code = Account.get_code(new_type, request.dbsession)
|
||||
item.type = new_type
|
||||
item.name = request.json_body["name"]
|
||||
item.is_active = request.json_body["isActive"]
|
||||
item.is_reconcilable = request.json_body["isReconcilable"]
|
||||
item.is_starred = request.json_body["isStarred"]
|
||||
item.cost_centre_id = uuid.UUID(request.json_body["costCentre"]["id"])
|
||||
transaction.commit()
|
||||
return account_info(item.id, request.dbsession)
|
||||
|
||||
|
||||
@router.delete("/{id}") # "Accounts"
|
||||
def delete(id_: uuid.UUID, db: Session = Depends(get_db), user: User = Security(get_user, scopes=["accounts"])):
|
||||
account = (
|
||||
db.query(Account)
|
||||
.filter(Account.id == id_)
|
||||
.first()
|
||||
)
|
||||
can_delete, reason = account.can_delete(request.has_permission("Advanced Delete"))
|
||||
if can_delete:
|
||||
delete_with_data(account, db)
|
||||
transaction.commit()
|
||||
return account_info(None, db)
|
||||
else:
|
||||
transaction.abort()
|
||||
response = Response("Cannot delete account because {0}".format(reason))
|
||||
response.status_int = 500
|
||||
return response
|
||||
|
||||
|
||||
@router.get("/list") # "Authenticated"
|
||||
async def show_list(db: Session = Depends(get_db), user: User = Depends(get_user)):
|
||||
list_ = (
|
||||
db.query(Account)
|
||||
.order_by(Account.type)
|
||||
.order_by(Account.name)
|
||||
.order_by(Account.code)
|
||||
.all()
|
||||
)
|
||||
accounts = []
|
||||
for item in list_:
|
||||
accounts.append(
|
||||
{
|
||||
"id": item.id,
|
||||
"name": item.name,
|
||||
"type": item.type_object.name,
|
||||
"isActive": item.is_active,
|
||||
"isReconcilable": item.is_reconcilable,
|
||||
"isStarred": item.is_starred,
|
||||
"costCentre": item.cost_centre.name,
|
||||
"isFixture": item.is_fixture,
|
||||
}
|
||||
)
|
||||
return accounts
|
||||
|
||||
|
||||
@router.get("/query") # "Authenticated"
|
||||
async def show_term(q: str, t: int = None, r: bool = None, a: bool = None, c: int = None,
|
||||
db: Session = Depends(get_db), current_user: User = Depends(get_user)):
|
||||
count = c
|
||||
|
||||
list_ = []
|
||||
for index, item in enumerate(AccountBase.list(t, q, r, a, db)):
|
||||
list_.append({"id": item.id, "name": item.name})
|
||||
if count is not None and index == count - 1:
|
||||
break
|
||||
return {"user": current_user.name, "list": list_}
|
||||
|
||||
|
||||
@router.get("/{id_}/balance") # "Authenticated"
|
||||
async def show_balance(id_: uuid.UUID, d: str = None, db: Session = Depends(get_db), user: User = Depends(get_user)):
|
||||
date = (
|
||||
None
|
||||
if d is None or d == ""
|
||||
else datetime.datetime.strptime(d, "%d-%b-%Y")
|
||||
)
|
||||
return {"date": balance(id_, date, db), "total": balance(id_, None, db)}
|
||||
|
||||
|
||||
@router.get("/{id_}") # "Accounts"
|
||||
def show_id(id_: uuid.UUID, db: Session = Depends(get_db), user: User = Security(get_user, scopes=["accounts"])):
|
||||
return account_info(id_, db)
|
||||
|
||||
|
||||
def balance(id_: uuid.UUID, date, dbsession: Session):
|
||||
account = dbsession.query(AccountBase).filter(AccountBase.id == id_).first()
|
||||
if not account.type_object.balance_sheet:
|
||||
return 0
|
||||
|
||||
bal = dbsession.query(func.sum(Journal.amount * Journal.debit)).join(
|
||||
Journal.voucher
|
||||
)
|
||||
if date is not None:
|
||||
bal = bal.filter(Voucher.date <= date)
|
||||
|
||||
bal = (
|
||||
bal.filter(Voucher.type != VoucherType.by_name("Issue").id)
|
||||
.filter(Journal.account_id == id_)
|
||||
.scalar()
|
||||
)
|
||||
return 0 if bal is None else bal
|
||||
|
||||
|
||||
@router.get("/") # "Accounts"
|
||||
def show_blank(db: Session = Depends(get_db), user: User = Security(get_user, scopes=["accounts"])):
|
||||
return account_info(None, db)
|
||||
|
||||
|
||||
def account_info(id_, db):
|
||||
if id_ is None:
|
||||
account = {
|
||||
"code": "(Auto)",
|
||||
"type": AccountType.by_name("Creditors").id,
|
||||
"isActive": True,
|
||||
"isReconcilable": False,
|
||||
"isStarred": False,
|
||||
"costCentre": CostCentre.overall(),
|
||||
}
|
||||
else:
|
||||
account = db.query(Account).filter(Account.id == id_).first()
|
||||
account = {
|
||||
"id": account.id,
|
||||
"code": account.code,
|
||||
"name": account.name,
|
||||
"type": account.type,
|
||||
"isActive": account.is_active,
|
||||
"isReconcilable": account.is_reconcilable,
|
||||
"isStarred": account.is_starred,
|
||||
"isFixture": account.is_fixture,
|
||||
"costCentre": {
|
||||
"id": account.cost_centre_id,
|
||||
"name": account.cost_centre.name,
|
||||
},
|
||||
}
|
||||
return account
|
||||
|
||||
|
||||
def delete_with_data(account, db):
|
||||
suspense_account = (
|
||||
db.query(Account).filter(Account.id == Account.suspense()).first()
|
||||
)
|
||||
query = (
|
||||
db.query(Voucher)
|
||||
.options(joinedload_all(Voucher.journals, Journal.account, innerjoin=True))
|
||||
.filter(Voucher.journals.any(Journal.account_id == account.id))
|
||||
.all()
|
||||
)
|
||||
|
||||
for voucher in query:
|
||||
others, sus_jnl, acc_jnl = False, None, None
|
||||
for journal in voucher.journals:
|
||||
if journal.account_id == account.id:
|
||||
acc_jnl = journal
|
||||
elif journal.account_id == Account.suspense():
|
||||
sus_jnl = journal
|
||||
else:
|
||||
others = True
|
||||
if not others:
|
||||
db.delete(voucher)
|
||||
else:
|
||||
if sus_jnl is None:
|
||||
acc_jnl.account = suspense_account
|
||||
voucher.narration += "\nSuspense \u20B9{0:,.2f} is {1}".format(
|
||||
acc_jnl.amount, account.name
|
||||
)
|
||||
else:
|
||||
amount = (sus_jnl.debit * sus_jnl.amount) + (
|
||||
acc_jnl.debit * acc_jnl.amount
|
||||
)
|
||||
db.delete(acc_jnl)
|
||||
if amount == 0:
|
||||
db.delete(sus_jnl)
|
||||
else:
|
||||
sus_jnl.amount = abs(amount)
|
||||
sus_jnl.debit = -1 if amount < 0 else 1
|
||||
voucher.narration += "\nDeleted \u20B9{0:,.2f} of {1}".format(
|
||||
acc_jnl.amount * acc_jnl.debit, account.name
|
||||
)
|
||||
if voucher.type in (
|
||||
VoucherType.by_name("Payment").id,
|
||||
VoucherType.by_name("Receipt").id,
|
||||
):
|
||||
voucher.type = VoucherType.by_name("Journal")
|
||||
db.delete(account)
|
||||
@@ -0,0 +1,12 @@
|
||||
from brewman.models.master import AccountType
|
||||
from fastapi import APIRouter
|
||||
|
||||
router = APIRouter()
|
||||
|
||||
|
||||
@router.get("/") # "Authenticated"
|
||||
def account_type_list(request):
|
||||
account_types = []
|
||||
for item in AccountType.list():
|
||||
account_types.append({"id": item.id, "name": item.name})
|
||||
return account_types
|
||||
@@ -0,0 +1,101 @@
|
||||
import datetime
|
||||
import uuid
|
||||
|
||||
from sqlalchemy import or_
|
||||
|
||||
from brewman.models.master import Employee
|
||||
from brewman.models.voucher import Attendance
|
||||
from brewman.routers.fingerprint import get_prints
|
||||
from brewman.routers.services.session import session_current_date
|
||||
|
||||
from fastapi import APIRouter
|
||||
|
||||
router = APIRouter()
|
||||
|
||||
|
||||
@router.get("/") # "Attendance"
|
||||
def attendance_blank(request):
|
||||
return {"date": session_current_date(request), "body": []}
|
||||
|
||||
|
||||
@router.get("/{date}") # "Attendance"
|
||||
def attendance_date(request):
|
||||
date = request.matchdict.get("date", None)
|
||||
return attendance_date_report(date, request.dbsession)
|
||||
|
||||
|
||||
def attendance_date_report(date, dbsession):
|
||||
report = {"date": date, "body": []}
|
||||
date = datetime.datetime.strptime(date, "%d-%b-%Y")
|
||||
employees = (
|
||||
dbsession.query(Employee)
|
||||
.filter(Employee.joining_date <= date)
|
||||
.filter(or_(Employee.is_active, Employee.leaving_date >= date))
|
||||
.order_by(Employee.cost_centre_id)
|
||||
.order_by(Employee.designation)
|
||||
.order_by(Employee.name)
|
||||
.all()
|
||||
)
|
||||
for item in employees:
|
||||
att = (
|
||||
dbsession.query(Attendance)
|
||||
.filter(Attendance.employee_id == item.id)
|
||||
.filter(Attendance.date == date)
|
||||
.filter(Attendance.is_valid == True)
|
||||
.first()
|
||||
)
|
||||
att = 0 if att is None else att.attendance_type
|
||||
|
||||
prints, hours, worked = get_prints(item.id, date, dbsession)
|
||||
report["body"].append(
|
||||
{
|
||||
"id": item.id,
|
||||
"code": item.code,
|
||||
"name": item.name,
|
||||
"designation": item.designation,
|
||||
"department": item.cost_centre.name,
|
||||
"attendanceType": {"id": att},
|
||||
"prints": prints,
|
||||
"hours": hours,
|
||||
"worked": worked,
|
||||
}
|
||||
)
|
||||
return report
|
||||
|
||||
|
||||
@router.post("/{date}") # "Attendance"
|
||||
def save(request):
|
||||
user_id = uuid.UUID(request.authenticated_userid)
|
||||
date = request.matchdict.get("date", None)
|
||||
date_object = datetime.datetime.strptime(date, "%d-%b-%Y")
|
||||
|
||||
for item in request.json_body["body"]:
|
||||
employee_id = uuid.UUID(item["id"])
|
||||
attendance_type = item["attendanceType"]["id"]
|
||||
if attendance_type != 0:
|
||||
attendance = Attendance(
|
||||
employee_id=employee_id,
|
||||
date=date_object,
|
||||
attendance_type=attendance_type,
|
||||
user_id=user_id,
|
||||
)
|
||||
attendance.create(request.dbsession)
|
||||
transaction.commit()
|
||||
return attendance_date_report(date, request.dbsession)
|
||||
|
||||
|
||||
def daterange(start, stop, step=datetime.timedelta(days=1), inclusive=False):
|
||||
# inclusive=False to behave like range by default
|
||||
if step.days > 0:
|
||||
while start < stop:
|
||||
yield start
|
||||
start = start + step
|
||||
# not +=! don't modify object passed in if it's mutable
|
||||
# since this function is not restricted to
|
||||
# only types from datetime module
|
||||
elif step.days < 0:
|
||||
while start > stop:
|
||||
yield start
|
||||
start = start + step
|
||||
if inclusive and start == stop:
|
||||
yield start
|
||||
@@ -1,13 +1,15 @@
|
||||
import datetime
|
||||
from pyramid.view import view_config
|
||||
from sqlalchemy import or_
|
||||
from ..models.master import AttendanceType, Employee
|
||||
from ..models.voucher import Attendance
|
||||
from .attendance import daterange
|
||||
from .services.session import session_period_start, session_period_finish
|
||||
|
||||
from fastapi import APIRouter
|
||||
|
||||
@view_config(route_name="attendance_report", renderer="csv", permission="Attendance")
|
||||
router = APIRouter()
|
||||
|
||||
@router.get("/") # "Attendance", renderer="csv"
|
||||
def get_report(request):
|
||||
start_date = request.GET.get("StartDate", session_period_start(request))
|
||||
finish_date = request.GET.get("FinishDate", session_period_finish(request))
|
||||
@@ -0,0 +1,14 @@
|
||||
from brewman.models.master import AttendanceType, Employee
|
||||
|
||||
from fastapi import APIRouter
|
||||
|
||||
router = APIRouter()
|
||||
|
||||
|
||||
@router.get("/") # "Authenticated"
|
||||
def show_list(request):
|
||||
list_ = AttendanceType.list()
|
||||
attendance_types = []
|
||||
for item in list_:
|
||||
attendance_types.append({"id": item.id, "name": item.name, "value": item.value})
|
||||
return attendance_types
|
||||
File renamed without changes.
@@ -1,29 +1,13 @@
|
||||
import uuid
|
||||
|
||||
import pkg_resources
|
||||
from pyramid.response import Response, FileResponse
|
||||
from pyramid.view import view_config
|
||||
from sqlalchemy import desc
|
||||
import transaction
|
||||
|
||||
from brewman.models.auth import Client, LoginHistory
|
||||
|
||||
from fastapi import APIRouter
|
||||
|
||||
@view_config(request_method="GET", route_name="clients_list", permission="Clients")
|
||||
@view_config(request_method="GET", route_name="clients_id", permission="Clients")
|
||||
def html(request):
|
||||
package, resource = "brewman:static/index.html".split(":", 1)
|
||||
file = pkg_resources.resource_filename(package, resource)
|
||||
return FileResponse(file, request=request)
|
||||
router = APIRouter()
|
||||
|
||||
|
||||
@view_config(
|
||||
request_method="PUT",
|
||||
route_name="api_clients_id",
|
||||
renderer="json",
|
||||
permission="Clients",
|
||||
trans=True,
|
||||
)
|
||||
@router.put("/{id}") # "Clients"
|
||||
def update(request):
|
||||
item = (
|
||||
request.dbsession.query(Client)
|
||||
@@ -38,13 +22,7 @@ def update(request):
|
||||
return {}
|
||||
|
||||
|
||||
@view_config(
|
||||
request_method="DELETE",
|
||||
route_name="api_clients_id",
|
||||
renderer="json",
|
||||
permission="Clients",
|
||||
trans=True,
|
||||
)
|
||||
@router.delete("/{id}") # "Clients"
|
||||
def delete(request):
|
||||
id_ = request.matchdict.get("id", None)
|
||||
if id_ is None:
|
||||
@@ -61,14 +39,8 @@ def delete(request):
|
||||
return {}
|
||||
|
||||
|
||||
@view_config(
|
||||
request_method="GET",
|
||||
route_name="api_clients_list",
|
||||
request_param="l",
|
||||
renderer="json",
|
||||
permission="Clients",
|
||||
)
|
||||
def show_list(request):
|
||||
@router.get("/") # "Clients"
|
||||
async def show_list(l: bool):
|
||||
list_ = request.dbsession.query(Client).order_by(Client.name).all()
|
||||
clients = []
|
||||
for item in list_:
|
||||
@@ -97,12 +69,7 @@ def show_list(request):
|
||||
return clients
|
||||
|
||||
|
||||
@view_config(
|
||||
request_method="GET",
|
||||
route_name="api_clients_id",
|
||||
renderer="json",
|
||||
permission="Clients",
|
||||
)
|
||||
@router.get("/{id}") # "Clients"
|
||||
def show_id(request):
|
||||
item = (
|
||||
request.dbsession.query(Client)
|
||||
@@ -1,29 +1,12 @@
|
||||
import uuid
|
||||
|
||||
import pkg_resources
|
||||
import transaction
|
||||
from pyramid.response import Response, FileResponse
|
||||
from pyramid.view import view_config
|
||||
|
||||
from brewman.models.auth import Group, Role
|
||||
|
||||
from fastapi import APIRouter
|
||||
|
||||
@view_config(request_method="GET", route_name="groups_new", permission="Users")
|
||||
@view_config(request_method="GET", route_name="groups_id", permission="Users")
|
||||
@view_config(route_name="groups_list", permission="Users")
|
||||
def html(request):
|
||||
package, resource = "brewman:static/index.html".split(":", 1)
|
||||
file = pkg_resources.resource_filename(package, resource)
|
||||
return FileResponse(file, request=request)
|
||||
router = APIRouter()
|
||||
|
||||
|
||||
@view_config(
|
||||
request_method="POST",
|
||||
route_name="api_groups_new",
|
||||
renderer="json",
|
||||
permission="Users",
|
||||
trans=True,
|
||||
)
|
||||
@router.post("/new") # "Users"
|
||||
def save(request):
|
||||
group = Group(request.json_body["name"])
|
||||
request.dbsession.add(group)
|
||||
@@ -32,13 +15,7 @@ def save(request):
|
||||
return group_info(group.id, request.dbsession)
|
||||
|
||||
|
||||
@view_config(
|
||||
request_method="PUT",
|
||||
route_name="api_groups_id",
|
||||
renderer="json",
|
||||
permission="Users",
|
||||
trans=True,
|
||||
)
|
||||
@router.put("/{id}") # "Users"
|
||||
def update(request):
|
||||
id_ = request.matchdict.get("id", None)
|
||||
group = request.dbsession.query(Group).filter(Group.id == uuid.UUID(id_)).one()
|
||||
@@ -59,12 +36,7 @@ def add_permissions(group, permissions, dbsession):
|
||||
group.roles.remove(gp)
|
||||
|
||||
|
||||
@view_config(
|
||||
request_method="DELETE",
|
||||
route_name="api_groups_id",
|
||||
renderer="json",
|
||||
permission="Users",
|
||||
)
|
||||
@router.delete("/{id}") # "Users"
|
||||
def delete(request):
|
||||
id_ = request.matchdict.get("id", None)
|
||||
if id_ is None:
|
||||
@@ -77,28 +49,18 @@ def delete(request):
|
||||
return response
|
||||
|
||||
|
||||
@view_config(
|
||||
request_method="GET", route_name="api_groups_id", renderer="json", permission="Users"
|
||||
)
|
||||
@router.get("/{id}") # "Users"
|
||||
def show_id(request):
|
||||
return group_info(uuid.UUID(request.matchdict.get("id", None)), request.dbsession)
|
||||
|
||||
|
||||
@view_config(
|
||||
request_method="GET", route_name="api_groups_new", renderer="json", permission="Users"
|
||||
)
|
||||
@router.get("/new") # "Users"
|
||||
def show_blank(request):
|
||||
return group_info(None, request.dbsession)
|
||||
|
||||
|
||||
@view_config(
|
||||
request_method="GET",
|
||||
route_name="api_groups_list",
|
||||
renderer="json",
|
||||
request_param="l",
|
||||
permission="Users",
|
||||
)
|
||||
def show_list(request):
|
||||
@router.get("/") # "Users"
|
||||
async def show_list(l: bool):
|
||||
list_ = request.dbsession.query(Group).order_by(Group.name).all()
|
||||
|
||||
groups = []
|
||||
@@ -1,14 +1,12 @@
|
||||
import re
|
||||
import uuid
|
||||
|
||||
import pkg_resources
|
||||
import transaction
|
||||
from pyramid.response import Response, FileResponse
|
||||
from pyramid.view import view_config
|
||||
|
||||
from brewman.models.auth import User, Group
|
||||
from brewman.models.validation_exception import ValidationError
|
||||
|
||||
from fastapi import APIRouter
|
||||
|
||||
router = APIRouter()
|
||||
|
||||
|
||||
class UserView(object):
|
||||
def __init__(self, request):
|
||||
@@ -22,21 +20,7 @@ class UserView(object):
|
||||
.one()
|
||||
)
|
||||
|
||||
@view_config(request_method="GET", route_name="users_new", permission="Users")
|
||||
@view_config(request_method="GET", route_name="users_id", permission="Authenticated")
|
||||
@view_config(route_name="users_list", permission="Users")
|
||||
def html(self):
|
||||
package, resource = "brewman:static/index.html".split(":", 1)
|
||||
file = pkg_resources.resource_filename(package, resource)
|
||||
return FileResponse(file, request=self.request)
|
||||
|
||||
@view_config(
|
||||
request_method="POST",
|
||||
route_name="api_users_new",
|
||||
renderer="json",
|
||||
permission="Users",
|
||||
trans=True,
|
||||
)
|
||||
@router.post("/new") # "Users"
|
||||
def save(self):
|
||||
return self.save_user()
|
||||
|
||||
@@ -51,13 +35,7 @@ class UserView(object):
|
||||
transaction.commit()
|
||||
return self.user_info(user.id)
|
||||
|
||||
@view_config(
|
||||
request_method="PUT",
|
||||
route_name="api_users_id",
|
||||
renderer="json",
|
||||
permission="Authenticated",
|
||||
trans=True,
|
||||
)
|
||||
@router.put("/{id}") # "Authenticated"
|
||||
def update(self):
|
||||
id_ = self.request.matchdict["id"]
|
||||
p = re.compile(
|
||||
@@ -91,12 +69,7 @@ class UserView(object):
|
||||
transaction.commit()
|
||||
return self.user_info(user.id)
|
||||
|
||||
@view_config(
|
||||
request_method="DELETE",
|
||||
route_name="api_users_id",
|
||||
renderer="json",
|
||||
permission="Users",
|
||||
)
|
||||
@router.delete("/{id}") # "Users"
|
||||
def delete(self):
|
||||
id_ = self.request.matchdict.get("id", None)
|
||||
if id_ is None:
|
||||
@@ -108,12 +81,7 @@ class UserView(object):
|
||||
response.status_int = 500
|
||||
return response
|
||||
|
||||
@view_config(
|
||||
request_method="GET",
|
||||
route_name="api_users_id",
|
||||
renderer="json",
|
||||
permission="Authenticated",
|
||||
)
|
||||
@router.get("/{id}") # "Authenticated"
|
||||
def show_id(self):
|
||||
id_ = self.request.matchdict["id"]
|
||||
p = re.compile(
|
||||
@@ -123,20 +91,12 @@ class UserView(object):
|
||||
id_ = uuid.UUID(id_)
|
||||
return self.user_info(id_)
|
||||
|
||||
@view_config(
|
||||
request_method="GET", route_name="api_users_new", renderer="json", permission="Users"
|
||||
)
|
||||
@router.get("/new") # "Users"
|
||||
def show_blank(self):
|
||||
return self.user_info(None)
|
||||
|
||||
@view_config(
|
||||
request_method="GET",
|
||||
route_name="api_users_list",
|
||||
renderer="json",
|
||||
request_param="l",
|
||||
permission="Users",
|
||||
)
|
||||
def show_list(self):
|
||||
@router.get("/") # "Users"
|
||||
async def show_list(l: bool):
|
||||
list_ = self.request.dbsession.query(User).order_by(User.name).all()
|
||||
users = []
|
||||
for item in list_:
|
||||
@@ -148,14 +108,8 @@ class UserView(object):
|
||||
users.append(user)
|
||||
return users
|
||||
|
||||
@view_config(
|
||||
request_method="GET",
|
||||
route_name="api_users_list",
|
||||
renderer="json",
|
||||
request_param="n",
|
||||
permission="Authenticated",
|
||||
)
|
||||
def show_name(self):
|
||||
@router.get("/") # "Authenticated"
|
||||
async def show_name(n: bool):
|
||||
list_ = (
|
||||
self.request.dbsession.query(User)
|
||||
.filter(User.locked_out == False)
|
||||
@@ -0,0 +1,148 @@
|
||||
import traceback
|
||||
import uuid
|
||||
from typing import List, Optional
|
||||
|
||||
from sqlalchemy.exc import SQLAlchemyError
|
||||
|
||||
import brewman.schemas.master as schemas
|
||||
|
||||
from fastapi import APIRouter, HTTPException, status, Depends, Security
|
||||
from sqlalchemy.orm import Session
|
||||
|
||||
from ..core.security import User, get_current_active_user as get_user
|
||||
from ..db.session import SessionLocal
|
||||
from ..models.master import CostCentre
|
||||
|
||||
|
||||
router = APIRouter()
|
||||
|
||||
|
||||
# Dependency
|
||||
def get_db():
|
||||
try:
|
||||
db = SessionLocal()
|
||||
yield db
|
||||
finally:
|
||||
db.close()
|
||||
|
||||
|
||||
@router.post("/", response_model=schemas.CostCentre)
|
||||
def save(
|
||||
data: schemas.CostCentreSaveUpdate,
|
||||
db: Session = Depends(get_db),
|
||||
user: User = Security(get_user, scopes=["cost-centres"]),
|
||||
):
|
||||
try:
|
||||
item = CostCentre(data.name)
|
||||
db.add(item)
|
||||
db.commit()
|
||||
return cost_centre_info(item, db)
|
||||
except Exception:
|
||||
db.rollback()
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
||||
detail=traceback.format_exc(),
|
||||
)
|
||||
|
||||
|
||||
@router.put("/{id_}", response_model=schemas.CostCentre)
|
||||
def update(
|
||||
id_: uuid.UUID,
|
||||
data: schemas.CostCentreSaveUpdate,
|
||||
db: Session = Depends(get_db),
|
||||
user: User = Security(get_user, scopes=["cost-centres"]),
|
||||
):
|
||||
try:
|
||||
item = db.query(CostCentre).filter(CostCentre.id == id_).first()
|
||||
if item.is_fixture:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
||||
detail=f"{item.name} is a fixture and cannot be edited or deleted.",
|
||||
)
|
||||
item.name = data.name
|
||||
db.commit()
|
||||
return cost_centre_info(item, db)
|
||||
except SQLAlchemyError as e:
|
||||
db.rollback()
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
||||
detail=str(e),
|
||||
)
|
||||
except Exception:
|
||||
db.rollback()
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
||||
detail=traceback.format_exc(),
|
||||
)
|
||||
|
||||
|
||||
@router.delete("/{id_}")
|
||||
def delete(
|
||||
id_: uuid.UUID,
|
||||
db: Session = Depends(get_db),
|
||||
user: User = Security(get_user, scopes=["cost-centres"]),
|
||||
):
|
||||
try:
|
||||
item = db.query(CostCentre).filter(CostCentre.id == id_).first()
|
||||
|
||||
if item is None:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
||||
detail="Cost Centre not found",
|
||||
)
|
||||
elif item.is_fixture:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
||||
detail=f"{item.name} is a fixture and cannot be edited or deleted.",
|
||||
)
|
||||
else:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
||||
detail="Cost Centre deletion not implemented",
|
||||
)
|
||||
except Exception:
|
||||
db.rollback()
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
||||
detail=traceback.format_exc(),
|
||||
)
|
||||
|
||||
|
||||
@router.get("/")
|
||||
def show_blank(
|
||||
db: Session = Depends(get_db),
|
||||
user: User = Security(get_user, scopes=["cost-centres"]),
|
||||
):
|
||||
return cost_centre_info(None, db)
|
||||
|
||||
|
||||
@router.get("/list", response_model=List[schemas.CostCentre])
|
||||
async def show_list(db: Session = Depends(get_db), user: User = Depends(get_user)):
|
||||
return [
|
||||
{"id": item.id, "name": item.name, "isFixture": item.is_fixture}
|
||||
for item in db.query(CostCentre).order_by(CostCentre.name).all()
|
||||
]
|
||||
|
||||
|
||||
@router.get("/{id_}", response_model=schemas.CostCentre)
|
||||
def show_id(
|
||||
id_: uuid.UUID,
|
||||
db: Session = Depends(get_db),
|
||||
user: User = Security(get_user, scopes=["cost-centres"]),
|
||||
):
|
||||
item = db.query(CostCentre).filter(CostCentre.id == id_).first()
|
||||
return cost_centre_info(item, db)
|
||||
|
||||
|
||||
def cost_centre_info(item: Optional[CostCentre], db: Session):
|
||||
if item is None:
|
||||
return {
|
||||
"name": "",
|
||||
"isFixture": False,
|
||||
}
|
||||
else:
|
||||
return {
|
||||
"id": item.id,
|
||||
"name": item.name,
|
||||
"isFixture": item.is_fixture,
|
||||
}
|
||||
@@ -2,38 +2,20 @@ import datetime
|
||||
import uuid
|
||||
from decimal import Decimal
|
||||
|
||||
import pkg_resources
|
||||
import transaction
|
||||
from pyramid.response import Response, FileResponse
|
||||
from pyramid.view import view_config
|
||||
from sqlalchemy import desc
|
||||
from sqlalchemy.orm import joinedload_all
|
||||
|
||||
from brewman.models.master import CostCentre, Employee, AccountBase, Account
|
||||
from brewman.models.validation_exception import ValidationError
|
||||
from brewman.models.voucher import Voucher, Journal, VoucherType
|
||||
from brewman.views import to_uuid
|
||||
from brewman.routers import to_uuid
|
||||
|
||||
from fastapi import APIRouter
|
||||
|
||||
router = APIRouter()
|
||||
|
||||
|
||||
@view_config(request_method="GET", route_name="employees_new", permission="Employees")
|
||||
@view_config(request_method="GET", route_name="employees_id", permission="Employees")
|
||||
@view_config(route_name="employees_list", permission="Authenticated")
|
||||
@view_config(
|
||||
request_method="GET", route_name="employee_functions", permission="Employees"
|
||||
)
|
||||
def html(request):
|
||||
package, resource = "brewman:static/index.html".split(":", 1)
|
||||
file = pkg_resources.resource_filename(package, resource)
|
||||
return FileResponse(file, request=request)
|
||||
|
||||
|
||||
@view_config(
|
||||
request_method="POST",
|
||||
route_name="api_employees_new",
|
||||
renderer="json",
|
||||
permission="Employees",
|
||||
trans=True,
|
||||
)
|
||||
@router.post("/new") # "Employees"
|
||||
def save(request):
|
||||
name = request.json_body.get("name", "").strip()
|
||||
if name == "":
|
||||
@@ -93,13 +75,7 @@ def save(request):
|
||||
return employee_info(item.id, request.dbsession)
|
||||
|
||||
|
||||
@view_config(
|
||||
request_method="PUT",
|
||||
route_name="api_employees_id",
|
||||
renderer="json",
|
||||
permission="Employees",
|
||||
trans=True,
|
||||
)
|
||||
@router.put("/{id}") # "Employees"
|
||||
def update(request):
|
||||
item = (
|
||||
request.dbsession.query(Employee)
|
||||
@@ -157,13 +133,7 @@ def update(request):
|
||||
return employee_info(item.id, request.dbsession)
|
||||
|
||||
|
||||
@view_config(
|
||||
request_method="DELETE",
|
||||
route_name="api_employees_id",
|
||||
renderer="json",
|
||||
permission="Employees",
|
||||
trans=True,
|
||||
)
|
||||
@router.delete("/{id}") # "Employees"
|
||||
def delete(request):
|
||||
employee = (
|
||||
request.dbsession.query(Employee)
|
||||
@@ -182,13 +152,7 @@ def delete(request):
|
||||
return response
|
||||
|
||||
|
||||
@view_config(
|
||||
request_method="GET",
|
||||
route_name="api_employees_id",
|
||||
renderer="json",
|
||||
permission="Employees",
|
||||
trans=True,
|
||||
)
|
||||
@router.get("/{id}") # "Employees"
|
||||
def show_id(request):
|
||||
id_ = to_uuid(request.matchdict["id"])
|
||||
if id_ is None:
|
||||
@@ -196,24 +160,13 @@ def show_id(request):
|
||||
return employee_info(id_, request.dbsession)
|
||||
|
||||
|
||||
@view_config(
|
||||
request_method="GET",
|
||||
route_name="api_employees_new",
|
||||
renderer="json",
|
||||
permission="Employees",
|
||||
)
|
||||
@router.get("/new") # "Employees"
|
||||
def show_blank(request):
|
||||
return employee_info(None, request.dbsession)
|
||||
|
||||
|
||||
@view_config(
|
||||
request_method="GET",
|
||||
route_name="api_employees_list",
|
||||
request_param="l",
|
||||
renderer="json",
|
||||
permission="Authenticated",
|
||||
)
|
||||
def show_list(request):
|
||||
@router.get("/") # "Authenticated"
|
||||
async def show_list(l: bool):
|
||||
list_ = (
|
||||
request.dbsession.query(Employee)
|
||||
.order_by(desc(Employee.is_active))
|
||||
@@ -244,14 +197,8 @@ def show_list(request):
|
||||
return accounts
|
||||
|
||||
|
||||
@view_config(
|
||||
request_method="GET",
|
||||
route_name="api_employees_list",
|
||||
renderer="json",
|
||||
request_param="q",
|
||||
permission="Authenticated",
|
||||
)
|
||||
def show_term(request):
|
||||
@router.get("/", ) # "Authenticated"
|
||||
async def show_term(q: str):
|
||||
filter_ = request.GET.get("q", None)
|
||||
filter_ = None if filter_ == "" else filter_
|
||||
count = request.GET.get("c", None)
|
||||
@@ -0,0 +1,124 @@
|
||||
import datetime
|
||||
import uuid
|
||||
|
||||
from sqlalchemy import or_
|
||||
|
||||
from brewman.models.master import Employee
|
||||
from brewman.models.validation_exception import ValidationError
|
||||
from brewman.models.voucher import Attendance
|
||||
from brewman.routers.fingerprint import get_prints
|
||||
from brewman.routers.services.session import (
|
||||
session_period_start,
|
||||
session_period_finish,
|
||||
session_current_date,
|
||||
)
|
||||
|
||||
from fastapi import APIRouter
|
||||
|
||||
router = APIRouter()
|
||||
|
||||
|
||||
@router.get("/") # "Attendance"
|
||||
def employee_attendance_blank(request):
|
||||
return {
|
||||
"startDate": session_period_start(request),
|
||||
"finishDate": session_period_finish(request),
|
||||
"employee": None,
|
||||
"body": [],
|
||||
}
|
||||
|
||||
|
||||
@router.get("/{id}") # "Attendance"
|
||||
def employee_attendance_report(request):
|
||||
employee = (
|
||||
request.dbsession.query(Employee)
|
||||
.filter(Employee.id == uuid.UUID(request.matchdict["id"]))
|
||||
.first()
|
||||
)
|
||||
if employee is None:
|
||||
raise ValidationError("Employee id is wrong")
|
||||
start_date = request.GET.get("s", session_period_start(request))
|
||||
finish_date = request.GET.get("f", session_period_finish(request))
|
||||
info = {
|
||||
"startDate": start_date,
|
||||
"finishDate": finish_date,
|
||||
"employee": {"id": employee.id, "name": employee.name},
|
||||
}
|
||||
start_date = datetime.datetime.strptime(start_date, "%d-%b-%Y")
|
||||
finish_date = datetime.datetime.strptime(finish_date, "%d-%b-%Y")
|
||||
start_date = (
|
||||
employee.joining_date if employee.joining_date > start_date else start_date
|
||||
)
|
||||
finish_date = (
|
||||
employee.leaving_date
|
||||
if not employee.is_active and employee.leaving_date < finish_date
|
||||
else finish_date
|
||||
)
|
||||
info["body"] = employee_attendance(
|
||||
employee, start_date, finish_date, request.dbsession
|
||||
)
|
||||
return info
|
||||
|
||||
|
||||
def employee_attendance(employee, start_date, finish_date, dbsession):
|
||||
if not isinstance(start_date, datetime.datetime):
|
||||
start_date = datetime.datetime.strptime(start_date, "%d-%b-%Y")
|
||||
if not isinstance(finish_date, datetime.datetime):
|
||||
finish_date = datetime.datetime.strptime(finish_date, "%d-%b-%Y")
|
||||
list_ = []
|
||||
for item in daterange(start_date, finish_date, inclusive=True):
|
||||
att = (
|
||||
dbsession.query(Attendance)
|
||||
.filter(Attendance.employee_id == employee.id)
|
||||
.filter(Attendance.date == item)
|
||||
.filter(Attendance.is_valid == True)
|
||||
.first()
|
||||
)
|
||||
att = 0 if att is None else att.attendance_type
|
||||
prints, hours, worked = get_prints(employee.id, item, dbsession)
|
||||
list_.append(
|
||||
{
|
||||
"date": item.strftime("%d-%b-%Y"),
|
||||
"attendanceType": {"id": att},
|
||||
"prints": prints,
|
||||
"hours": hours,
|
||||
"worked": worked,
|
||||
}
|
||||
)
|
||||
return list_
|
||||
|
||||
|
||||
@router.post("/{id}") # "Attendance"
|
||||
def save_employee_attendance(request):
|
||||
start_date = None
|
||||
finish_date = None
|
||||
user_id = uuid.UUID(request.authenticated_userid)
|
||||
employee = (
|
||||
request.dbsession.query(Employee)
|
||||
.filter(Employee.id == uuid.UUID(request.matchdict["id"]))
|
||||
.first()
|
||||
)
|
||||
for item in request.json_body["body"]:
|
||||
if start_date is None:
|
||||
start_date = item["date"]
|
||||
finish_date = item["date"]
|
||||
|
||||
attendance_type = item["attendanceType"]["id"]
|
||||
if attendance_type != 0:
|
||||
date = datetime.datetime.strptime(item["date"], "%d-%b-%Y")
|
||||
attendance = Attendance(
|
||||
employee_id=employee.id,
|
||||
date=date,
|
||||
attendance_type=attendance_type,
|
||||
user_id=user_id,
|
||||
)
|
||||
attendance.create(request.dbsession)
|
||||
transaction.commit()
|
||||
return {
|
||||
"startDate": start_date,
|
||||
"finishDate": finish_date,
|
||||
"employee": {"id": employee.id, "name": employee.name},
|
||||
"body": employee_attendance(
|
||||
employee, start_date, finish_date, request.dbsession
|
||||
),
|
||||
}
|
||||
@@ -3,24 +3,20 @@ import datetime
|
||||
import uuid
|
||||
from io import StringIO
|
||||
|
||||
import transaction
|
||||
from pyramid.view import view_config
|
||||
from sqlalchemy import bindparam, select, exists, and_
|
||||
from sqlalchemy.dialects.postgresql import insert as pg_insert
|
||||
from zope.sqlalchemy import mark_changed
|
||||
# from zope.sqlalchemy import mark_changed
|
||||
|
||||
from brewman.models.master import Employee
|
||||
from brewman.models.voucher import Fingerprint
|
||||
from brewman.views import get_lock_info
|
||||
from brewman.routers import get_lock_info
|
||||
|
||||
from fastapi import APIRouter
|
||||
|
||||
router = APIRouter()
|
||||
|
||||
|
||||
@view_config(
|
||||
request_method="POST",
|
||||
route_name="api_fingerprint",
|
||||
renderer="json",
|
||||
permission="Authenticated",
|
||||
trans=True,
|
||||
)
|
||||
@router.post("/") # "Authenticated"
|
||||
def upload_prints(request):
|
||||
fingerprints_file = request.POST["uploadedFile"].file
|
||||
start, finish = get_lock_info(request.dbsession)
|
||||
@@ -0,0 +1,54 @@
|
||||
from datetime import timedelta
|
||||
|
||||
from fastapi import APIRouter, Depends, HTTPException, status
|
||||
from fastapi.security import OAuth2PasswordRequestForm
|
||||
from sqlalchemy.orm import Session
|
||||
from ..core.security import (
|
||||
Token,
|
||||
authenticate_user,
|
||||
ACCESS_TOKEN_EXPIRE_MINUTES,
|
||||
create_access_token,
|
||||
)
|
||||
from ..db.session import SessionLocal
|
||||
|
||||
router = APIRouter()
|
||||
|
||||
|
||||
# Dependency
|
||||
def get_db():
|
||||
try:
|
||||
db = SessionLocal()
|
||||
yield db
|
||||
finally:
|
||||
db.close()
|
||||
|
||||
|
||||
@router.post("/token", response_model=Token)
|
||||
async def login_for_access_token(
|
||||
form_data: OAuth2PasswordRequestForm = Depends(), db: Session = Depends(get_db)
|
||||
):
|
||||
user = authenticate_user(form_data.username, form_data.password, db)
|
||||
if not user:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_401_UNAUTHORIZED,
|
||||
detail="Incorrect username or password",
|
||||
headers={"WWW-Authenticate": "Bearer"},
|
||||
)
|
||||
access_token_expires = timedelta(minutes=ACCESS_TOKEN_EXPIRE_MINUTES)
|
||||
access_token = create_access_token(
|
||||
data={
|
||||
"sub": user.name,
|
||||
"scopes": ["authenticated"]
|
||||
+ list(
|
||||
set(
|
||||
[
|
||||
p.name.replace(" ", "-").lower()
|
||||
for g in user.groups
|
||||
for p in g.roles
|
||||
]
|
||||
)
|
||||
),
|
||||
},
|
||||
expires_delta=access_token_expires,
|
||||
)
|
||||
return {"access_token": access_token, "token_type": "bearer"}
|
||||
@@ -1,10 +1,6 @@
|
||||
import uuid
|
||||
from decimal import Decimal, InvalidOperation
|
||||
|
||||
import pkg_resources
|
||||
import transaction
|
||||
from pyramid.response import Response, FileResponse
|
||||
from pyramid.view import view_config
|
||||
from sqlalchemy import desc
|
||||
from sqlalchemy.orm import joinedload_all
|
||||
|
||||
@@ -12,23 +8,12 @@ from brewman.models.master import Product, Account
|
||||
from brewman.models.validation_exception import ValidationError
|
||||
from brewman.models.voucher import Voucher, Batch, Inventory, VoucherType
|
||||
|
||||
from fastapi import APIRouter
|
||||
|
||||
@view_config(request_method="GET", route_name="products_new", permission="Products")
|
||||
@view_config(request_method="GET", route_name="products_id", permission="Products")
|
||||
@view_config(route_name="products_list", permission="Authenticated")
|
||||
def html(request):
|
||||
package, resource = "brewman:static/index.html".split(":", 1)
|
||||
file = pkg_resources.resource_filename(package, resource)
|
||||
return FileResponse(file, request=request)
|
||||
router = APIRouter()
|
||||
|
||||
|
||||
@view_config(
|
||||
request_method="POST",
|
||||
route_name="api_products_new",
|
||||
renderer="json",
|
||||
permission="Products",
|
||||
trans=True,
|
||||
)
|
||||
@router.post("/new") # "Products"
|
||||
def save(request):
|
||||
json = request.json_body
|
||||
|
||||
@@ -92,13 +77,7 @@ def save(request):
|
||||
return product_info(item.id, request.dbsession)
|
||||
|
||||
|
||||
@view_config(
|
||||
request_method="PUT",
|
||||
route_name="api_products_id",
|
||||
renderer="json",
|
||||
permission="Products",
|
||||
trans=True,
|
||||
)
|
||||
@router.put("/{id}") # "Products"
|
||||
def update(request):
|
||||
item = (
|
||||
request.dbsession.query(Product)
|
||||
@@ -148,13 +127,7 @@ def update(request):
|
||||
return product_info(item.id, request.dbsession)
|
||||
|
||||
|
||||
@view_config(
|
||||
request_method="DELETE",
|
||||
route_name="api_products_id",
|
||||
renderer="json",
|
||||
permission="Products",
|
||||
trans=True,
|
||||
)
|
||||
@router.delete("/{id}") # "Products"
|
||||
def delete(request):
|
||||
product = (
|
||||
request.dbsession.query(Product)
|
||||
@@ -174,34 +147,18 @@ def delete(request):
|
||||
return response
|
||||
|
||||
|
||||
@view_config(
|
||||
request_method="GET",
|
||||
route_name="api_products_id",
|
||||
renderer="json",
|
||||
permission="Products",
|
||||
)
|
||||
@router.get("/{id}") # "Products"
|
||||
def show_id(request):
|
||||
return product_info(uuid.UUID(request.matchdict.get("id", None)), request.dbsession)
|
||||
|
||||
|
||||
@view_config(
|
||||
request_method="GET",
|
||||
route_name="api_products_new",
|
||||
renderer="json",
|
||||
permission="Products",
|
||||
)
|
||||
@router.get("/new") # "Products"
|
||||
def show_blank(request):
|
||||
return product_info(None, request.dbsession)
|
||||
|
||||
|
||||
@view_config(
|
||||
request_method="GET",
|
||||
route_name="api_products_list",
|
||||
request_param="l",
|
||||
renderer="json",
|
||||
permission="Authenticated",
|
||||
)
|
||||
def show_list(request):
|
||||
@router.get("/", ) # "Authenticated"
|
||||
def show_list(l: bool):
|
||||
list_ = (
|
||||
request.dbsession.query(Product)
|
||||
.order_by(desc(Product.is_active))
|
||||
@@ -232,16 +189,10 @@ def show_list(request):
|
||||
return products
|
||||
|
||||
|
||||
@view_config(
|
||||
request_method="GET",
|
||||
route_name="api_products_list",
|
||||
renderer="json",
|
||||
request_param="t",
|
||||
permission="Authenticated",
|
||||
)
|
||||
def show_term(request):
|
||||
@router.get("/") # "Authenticated"
|
||||
async def show_term(t: str):
|
||||
term = request.GET.get("t", None)
|
||||
term = term.strip() if term is not None and term.strip() is not "" else None
|
||||
term = term.strip() if term is not None and term.strip() != "" else None
|
||||
active = request.GET.get("a", None)
|
||||
active = active if active is not None else None
|
||||
count = request.GET.get("c", None)
|
||||
@@ -1,30 +1,13 @@
|
||||
import uuid
|
||||
import pkg_resources
|
||||
from pyramid.response import Response, FileResponse
|
||||
|
||||
from pyramid.view import view_config
|
||||
import transaction
|
||||
|
||||
from brewman.models.master import ProductGroup
|
||||
from brewman.models.validation_exception import ValidationError
|
||||
from fastapi import APIRouter
|
||||
|
||||
router = APIRouter()
|
||||
|
||||
|
||||
@view_config(request_method="GET", route_name="product_groups_new", permission="Product Groups")
|
||||
@view_config(request_method="GET", route_name="product_groups_id", permission="Product Groups")
|
||||
@view_config(route_name="product_groups_list", permission="Authenticated")
|
||||
def html(request):
|
||||
package, resource = "brewman:static/index.html".split(":", 1)
|
||||
file = pkg_resources.resource_filename(package, resource)
|
||||
return FileResponse(file, request=request)
|
||||
|
||||
|
||||
@view_config(
|
||||
request_method="POST",
|
||||
route_name="api_product_groups_new",
|
||||
renderer="json",
|
||||
permission="Product Groups",
|
||||
trans=True,
|
||||
)
|
||||
@router.post("/new") # "Product Groups"
|
||||
def save(request):
|
||||
item = ProductGroup(request.json_body["name"])
|
||||
request.dbsession.add(item)
|
||||
@@ -32,13 +15,7 @@ def save(request):
|
||||
return product_group_info(item.id, request.dbsession)
|
||||
|
||||
|
||||
@view_config(
|
||||
request_method="PUT",
|
||||
route_name="api_product_groups_id",
|
||||
renderer="json",
|
||||
permission="Product Groups",
|
||||
trans=True,
|
||||
)
|
||||
@router.put("/{id}") # "Product Groups"
|
||||
def update(request):
|
||||
item = (
|
||||
request.dbsession.query(ProductGroup)
|
||||
@@ -54,12 +31,7 @@ def update(request):
|
||||
return product_group_info(item.id, request.dbsession)
|
||||
|
||||
|
||||
@view_config(
|
||||
request_method="DELETE",
|
||||
route_name="api_product_groups_id",
|
||||
renderer="json",
|
||||
permission="Product Groups",
|
||||
)
|
||||
@router.delete("/{id}") # "Product Groups"
|
||||
def delete(request):
|
||||
item = (
|
||||
request.dbsession.query(ProductGroup)
|
||||
@@ -81,36 +53,20 @@ def delete(request):
|
||||
return response
|
||||
|
||||
|
||||
@view_config(
|
||||
request_method="GET",
|
||||
route_name="api_product_groups_id",
|
||||
renderer="json",
|
||||
permission="Product Groups",
|
||||
)
|
||||
@router.get("/{id}") # "Product Groups"
|
||||
def show_id(request):
|
||||
return product_group_info(
|
||||
uuid.UUID(request.matchdict.get("id", None)), request.dbsession
|
||||
)
|
||||
|
||||
|
||||
@view_config(
|
||||
request_method="GET",
|
||||
route_name="api_product_groups_new",
|
||||
renderer="json",
|
||||
permission="Product Groups",
|
||||
)
|
||||
@router.get("/new") # "Product Groups"
|
||||
def show_blank(request):
|
||||
return product_group_info(None, request.dbsession)
|
||||
|
||||
|
||||
@view_config(
|
||||
request_method="GET",
|
||||
route_name="api_product_groups_list",
|
||||
request_param="l",
|
||||
renderer="json",
|
||||
permission="Authenticated",
|
||||
)
|
||||
def show_list(request):
|
||||
@router.get("/") # "Authenticated"
|
||||
async def show_list(l: bool):
|
||||
list_ = request.dbsession.query(ProductGroup).order_by(ProductGroup.name).all()
|
||||
product_groups = []
|
||||
for item in list_:
|
||||
@@ -3,45 +3,22 @@ import datetime
|
||||
import time
|
||||
from decimal import Decimal, InvalidOperation
|
||||
|
||||
import pkg_resources
|
||||
from pyramid.response import FileResponse
|
||||
from pyramid.view import view_config
|
||||
|
||||
from sqlalchemy import desc, or_, func
|
||||
import transaction
|
||||
|
||||
from brewman.models.master import Recipe, Product, RecipeItem, CostCentre
|
||||
from brewman.models.validation_exception import ValidationError
|
||||
from brewman.models.voucher import Voucher, Inventory, VoucherType, Journal
|
||||
from brewman.views.services.session import (
|
||||
from brewman.routers.services.session import (
|
||||
session_period_start,
|
||||
session_period_finish,
|
||||
session_period_set,
|
||||
)
|
||||
from fastapi import APIRouter
|
||||
|
||||
router = APIRouter()
|
||||
|
||||
|
||||
@view_config(request_method="GET", route_name="recipes_new", permission="Recipes")
|
||||
@view_config(request_method="GET", route_name="recipes_id", permission="Recipes")
|
||||
@view_config(route_name="recipes_list", permission="Recipes")
|
||||
def html(request):
|
||||
package, resource = "brewman:static/index.html".split(":", 1)
|
||||
file = pkg_resources.resource_filename(package, resource)
|
||||
return FileResponse(file, request=request)
|
||||
|
||||
|
||||
@view_config(
|
||||
request_method="POST",
|
||||
route_name="api_recipes_new",
|
||||
renderer="json",
|
||||
permission="Recipes",
|
||||
)
|
||||
@view_config(
|
||||
request_method="POST",
|
||||
route_name="api_recipes_id",
|
||||
renderer="json",
|
||||
permission="Recipes",
|
||||
trans=True,
|
||||
)
|
||||
# @router.post("/new") # "Recipes"
|
||||
@router.post("/{id}") # "Recipes"
|
||||
def save(request):
|
||||
json = request.json_body
|
||||
recipe_product = (
|
||||
@@ -283,12 +260,7 @@ def update_old_rows(product_id, valid_from, valid_to, effective_date, dbsession)
|
||||
dbsession.add(item)
|
||||
|
||||
|
||||
@view_config(
|
||||
request_method="DELETE",
|
||||
route_name="api_recipes_id",
|
||||
renderer="json",
|
||||
permission="Recipes",
|
||||
)
|
||||
@router.delete("/{id}") # "Recipes"
|
||||
def delete(request):
|
||||
recipe = (
|
||||
request.dbsession.query(Recipe)
|
||||
@@ -304,31 +276,18 @@ def delete(request):
|
||||
return recipe_info(None, request)
|
||||
|
||||
|
||||
@view_config(
|
||||
request_method="GET",
|
||||
route_name="api_recipes_id",
|
||||
renderer="json",
|
||||
permission="Recipes",
|
||||
)
|
||||
@router.get("/{id}") # "Recipes"
|
||||
def show_id(request):
|
||||
return recipe_info(uuid.UUID(request.matchdict["id"]), request)
|
||||
|
||||
|
||||
@view_config(
|
||||
request_method="GET", route_name="api_recipes_new", renderer="json", permission="Recipes"
|
||||
)
|
||||
@router.get("/new") # "Recipes"
|
||||
def show_blank(request):
|
||||
return recipe_info(None, request)
|
||||
|
||||
|
||||
@view_config(
|
||||
request_method="GET",
|
||||
route_name="api_recipes_list",
|
||||
renderer="json",
|
||||
request_param="list",
|
||||
permission="Authenticated",
|
||||
)
|
||||
def show_list(request):
|
||||
@router.get("/") # "Authenticated"
|
||||
async def show_list(l: bool):
|
||||
list_ = (
|
||||
request.dbsession.query(Recipe)
|
||||
.join(Recipe.product)
|
||||
Whitespace-only changes.
@@ -1,50 +1,28 @@
|
||||
import datetime
|
||||
import pkg_resources
|
||||
from pyramid.response import FileResponse
|
||||
from sqlalchemy.sql.expression import func, desc
|
||||
|
||||
from pyramid.view import view_config
|
||||
|
||||
from brewman.models.master import AccountType, AccountBase
|
||||
|
||||
from brewman.models.voucher import Voucher, Journal, VoucherType
|
||||
from brewman.views.reports.closing_stock import get_closing_stock
|
||||
from brewman.views.reports.profit_loss import get_accumulated_profit
|
||||
from brewman.views.services.session import (
|
||||
from brewman.routers.reports.closing_stock import get_closing_stock
|
||||
from brewman.routers.reports.profit_loss import get_accumulated_profit
|
||||
from brewman.routers.services.session import (
|
||||
session_period_set,
|
||||
session_period_start,
|
||||
session_period_finish,
|
||||
)
|
||||
|
||||
from fastapi import APIRouter
|
||||
|
||||
@view_config(
|
||||
request_method="GET", route_name="balance_sheet", permission="Balance Sheet"
|
||||
)
|
||||
@view_config(
|
||||
request_method="GET", route_name="balance_sheet_date", permission="Balance Sheet"
|
||||
)
|
||||
def html(request):
|
||||
package, resource = "brewman:static/index.html".split(":", 1)
|
||||
file = pkg_resources.resource_filename(package, resource)
|
||||
return FileResponse(file, request=request)
|
||||
router = APIRouter()
|
||||
|
||||
|
||||
@view_config(
|
||||
request_method="GET",
|
||||
route_name="api_balance_sheet",
|
||||
renderer="json",
|
||||
permission="Balance Sheet",
|
||||
)
|
||||
@router.get("/api/balance-sheet") # "Balance Sheet"
|
||||
def report_blank(request):
|
||||
return {"date": session_period_finish(request), "body": [], "footer": []}
|
||||
|
||||
|
||||
@view_config(
|
||||
request_method="GET",
|
||||
route_name="api_balance_sheet_date",
|
||||
renderer="json",
|
||||
permission="Balance Sheet",
|
||||
)
|
||||
@router.get("/api/balance-sheet/{date}") # "Balance Sheet"
|
||||
def report_data(request):
|
||||
date = request.matchdict.get("date", None)
|
||||
body, footer = build_balance_sheet(date, request.dbsession)
|
||||
@@ -1,34 +1,22 @@
|
||||
import datetime
|
||||
|
||||
import pkg_resources
|
||||
from pyramid.response import FileResponse
|
||||
from sqlalchemy.orm.util import aliased
|
||||
from sqlalchemy.sql.expression import func, desc
|
||||
from pyramid.view import view_config
|
||||
|
||||
from brewman.models.master import AccountBase, AccountType
|
||||
from brewman.models.voucher import Voucher, Journal, VoucherType
|
||||
from brewman.views.services.session import (
|
||||
from brewman.routers.services.session import (
|
||||
session_period_set,
|
||||
session_period_start,
|
||||
session_period_finish,
|
||||
)
|
||||
|
||||
from fastapi import APIRouter
|
||||
|
||||
@view_config(request_method="GET", route_name="cash_flow", permission="Cash Flow")
|
||||
@view_config(request_method="GET", route_name="cash_flow_id", permission="Cash Flow")
|
||||
def get_html(request):
|
||||
package, resource = "brewman:static/index.html".split(":", 1)
|
||||
file = pkg_resources.resource_filename(package, resource)
|
||||
return FileResponse(file, request=request)
|
||||
router = APIRouter()
|
||||
|
||||
|
||||
@view_config(
|
||||
request_method="GET",
|
||||
route_name="api_cash_flow",
|
||||
renderer="json",
|
||||
permission="Cash Flow",
|
||||
)
|
||||
@router.get("/api/cash-flow") # "Cash Flow"
|
||||
def report_blank(request):
|
||||
return {
|
||||
"startDate": session_period_start(request),
|
||||
@@ -38,13 +26,7 @@ def report_blank(request):
|
||||
}
|
||||
|
||||
|
||||
@view_config(
|
||||
request_method="GET",
|
||||
route_name="api_cash_flow",
|
||||
request_param=["s", "f"],
|
||||
renderer="json",
|
||||
permission="Cash Flow",
|
||||
)
|
||||
@router.get("/api/cash-flow", request_param=["s", "f"], permission="Cash Flow")
|
||||
def report_data(request):
|
||||
start_date = request.GET["s"]
|
||||
finish_date = request.GET["f"]
|
||||
@@ -58,13 +40,7 @@ def report_data(request):
|
||||
}
|
||||
|
||||
|
||||
@view_config(
|
||||
request_method="GET",
|
||||
route_name="api_cash_flow_id",
|
||||
request_param=["s", "f"],
|
||||
renderer="json",
|
||||
permission="Cash Flow",
|
||||
)
|
||||
@router.get("/api/cash-flow/{id}", request_param=["s", "f"], permission="Cash Flow")
|
||||
def get_cash_flow_id(request):
|
||||
id_ = request.matchdict["id"]
|
||||
start_date = request.GET["s"]
|
||||
@@ -1,47 +1,26 @@
|
||||
import datetime
|
||||
|
||||
import pkg_resources
|
||||
from pyramid.response import FileResponse
|
||||
from pyramid.view import view_config
|
||||
from sqlalchemy.sql.expression import func
|
||||
|
||||
from brewman.models.master import Product, CostCentre
|
||||
from brewman.models.voucher import Voucher, Journal, Inventory
|
||||
from brewman.views.services.session import (
|
||||
from brewman.routers.services.session import (
|
||||
session_period_set,
|
||||
session_period_start,
|
||||
session_period_finish,
|
||||
)
|
||||
|
||||
from fastapi import APIRouter
|
||||
|
||||
@view_config(
|
||||
request_method="GET", route_name="closing_stock", permission="Closing Stock"
|
||||
)
|
||||
@view_config(
|
||||
request_method="GET", route_name="closing_stock_date", permission="Closing Stock"
|
||||
)
|
||||
def html(request):
|
||||
package, resource = "brewman:static/index.html".split(":", 1)
|
||||
file = pkg_resources.resource_filename(package, resource)
|
||||
return FileResponse(file, request=request)
|
||||
router = APIRouter()
|
||||
|
||||
|
||||
@view_config(
|
||||
request_method="GET",
|
||||
route_name="api_closing_stock",
|
||||
renderer="json",
|
||||
permission="Closing Stock",
|
||||
)
|
||||
@router.get("/api/closing-stock") # "Closing Stock"
|
||||
def report_blank(request):
|
||||
return {"date": session_period_finish(request), "body": []}
|
||||
|
||||
|
||||
@view_config(
|
||||
request_method="GET",
|
||||
route_name="api_closing_stock_date",
|
||||
renderer="json",
|
||||
permission="Closing Stock",
|
||||
)
|
||||
@router.get("/api/closing-stock/{date}") # "Closing Stock"
|
||||
def report_data(request):
|
||||
date = request.matchdict.get("date", None)
|
||||
session_period_set(session_period_start(request), date, request)
|
||||
@@ -1,32 +1,21 @@
|
||||
import datetime
|
||||
|
||||
import pkg_resources
|
||||
from pyramid.response import FileResponse
|
||||
from pyramid.view import view_config
|
||||
from sqlalchemy.orm import joinedload_all
|
||||
|
||||
from brewman.models.voucher import Voucher, Journal, VoucherType
|
||||
from brewman.views.services.session import (
|
||||
from brewman.routers.services.session import (
|
||||
session_period_set,
|
||||
session_period_start,
|
||||
session_period_finish,
|
||||
)
|
||||
from brewman.views.services.voucher import get_edit_url
|
||||
from brewman.routers.services.voucher import get_edit_url
|
||||
|
||||
from fastapi import APIRouter
|
||||
|
||||
router = APIRouter()
|
||||
|
||||
|
||||
@view_config(request_method="GET", route_name="daybook", permission="Daybook")
|
||||
def daybook_get(request):
|
||||
package, resource = "brewman:static/index.html".split(":", 1)
|
||||
file = pkg_resources.resource_filename(package, resource)
|
||||
return FileResponse(file, request=request)
|
||||
|
||||
|
||||
@view_config(
|
||||
request_method="GET",
|
||||
route_name="api_daybook",
|
||||
renderer="json",
|
||||
permission="Daybook",
|
||||
)
|
||||
@router.get("/api/daybook") # "Daybook"
|
||||
def report_blank(request):
|
||||
return {
|
||||
"startDate": session_period_start(request),
|
||||
@@ -35,13 +24,7 @@ def report_blank(request):
|
||||
}
|
||||
|
||||
|
||||
@view_config(
|
||||
request_method="GET",
|
||||
route_name="api_daybook",
|
||||
request_param=["s", "f"],
|
||||
renderer="json",
|
||||
permission="Daybook",
|
||||
)
|
||||
@router.get("/api/daybook", request_param=["s", "f"], permission="Daybook")
|
||||
def report_data(request):
|
||||
start_date = request.GET["s"]
|
||||
finish_date = request.GET["f"]
|
||||
@@ -1,33 +1,24 @@
|
||||
import datetime
|
||||
import uuid
|
||||
|
||||
import pkg_resources
|
||||
from pyramid.response import FileResponse
|
||||
from sqlalchemy.orm import joinedload_all
|
||||
from sqlalchemy.sql.expression import func
|
||||
from pyramid.view import view_config
|
||||
|
||||
from brewman.models.master import AccountBase
|
||||
from brewman.models.voucher import Voucher, Journal, VoucherType
|
||||
from brewman.views.services.session import (
|
||||
from brewman.routers.services.session import (
|
||||
session_period_set,
|
||||
session_period_start,
|
||||
session_period_finish,
|
||||
)
|
||||
from brewman.views.services.voucher import get_edit_url
|
||||
from brewman.routers.services.voucher import get_edit_url
|
||||
|
||||
from fastapi import APIRouter
|
||||
|
||||
router = APIRouter()
|
||||
|
||||
|
||||
@view_config(request_method="GET", route_name="ledger_id", permission="Ledger")
|
||||
@view_config(request_method="GET", route_name="ledger", permission="Ledger")
|
||||
def html(request):
|
||||
package, resource = "brewman:static/index.html".split(":", 1)
|
||||
file = pkg_resources.resource_filename(package, resource)
|
||||
return FileResponse(file, request=request)
|
||||
|
||||
|
||||
@view_config(
|
||||
request_method="GET", route_name="api_ledger", renderer="json", permission="Ledger"
|
||||
)
|
||||
@router.get("/api/ledger") # "Ledger"
|
||||
def show_blank(request):
|
||||
return {
|
||||
"startDate": session_period_start(request),
|
||||
@@ -37,12 +28,7 @@ def show_blank(request):
|
||||
}
|
||||
|
||||
|
||||
@view_config(
|
||||
request_method="GET",
|
||||
route_name="api_ledger_id",
|
||||
renderer="json",
|
||||
permission="Ledger",
|
||||
)
|
||||
@router.get("/api/ledger/{id}") # "Ledger"
|
||||
def show_data(request):
|
||||
account = (
|
||||
request.dbsession.query(AccountBase)
|
||||
+5
-25
@@ -1,35 +1,21 @@
|
||||
import datetime
|
||||
import pkg_resources
|
||||
from pyramid.response import FileResponse
|
||||
from sqlalchemy.sql.expression import func, desc
|
||||
|
||||
from pyramid.view import view_config
|
||||
|
||||
from brewman.models.master import AccountBase
|
||||
|
||||
from brewman.models.voucher import Voucher, Journal, VoucherType
|
||||
from brewman.views.services.session import (
|
||||
from brewman.routers.services.session import (
|
||||
session_period_set,
|
||||
session_period_start,
|
||||
session_period_finish,
|
||||
)
|
||||
|
||||
from fastapi import APIRouter
|
||||
|
||||
@view_config(
|
||||
request_method="GET", route_name="net_transactions", permission="Net Transactions"
|
||||
)
|
||||
def html(request):
|
||||
package, resource = "brewman:static/index.html".split(":", 1)
|
||||
file = pkg_resources.resource_filename(package, resource)
|
||||
return FileResponse(file, request=request)
|
||||
router = APIRouter()
|
||||
|
||||
|
||||
@view_config(
|
||||
request_method="GET",
|
||||
route_name="api_net_transactions",
|
||||
renderer="json",
|
||||
permission="Net Transactions",
|
||||
)
|
||||
@router.get("/api/net-transactions") # "Net Transactions"
|
||||
def show_blank(request):
|
||||
return {
|
||||
"startDate": session_period_start(request),
|
||||
@@ -38,13 +24,7 @@ def show_blank(request):
|
||||
}
|
||||
|
||||
|
||||
@view_config(
|
||||
request_method="GET",
|
||||
route_name="api_net_transactions",
|
||||
request_param=["s", "f"],
|
||||
renderer="json",
|
||||
permission="Net Transactions",
|
||||
)
|
||||
@router.get("/api/net-transactions", request_param=["s", "f"], permission="Net Transactions")
|
||||
def show_data(request):
|
||||
start_date = request.GET["s"]
|
||||
finish_date = request.GET["f"]
|
||||
+8
-30
@@ -1,41 +1,24 @@
|
||||
import datetime
|
||||
|
||||
import pkg_resources
|
||||
from pyramid.response import FileResponse
|
||||
from pyramid.view import view_config
|
||||
from sqlalchemy.orm import joinedload
|
||||
from sqlalchemy.sql.expression import func
|
||||
|
||||
from brewman.models.master import Product, CostCentre
|
||||
from brewman.models.validation_exception import ValidationError
|
||||
from brewman.models.voucher import Voucher, Journal, VoucherType, Inventory
|
||||
from brewman.views import to_uuid
|
||||
from brewman.views.services.session import (
|
||||
from brewman.routers import to_uuid
|
||||
from brewman.routers.services.session import (
|
||||
session_period_set,
|
||||
session_period_start,
|
||||
session_period_finish,
|
||||
)
|
||||
from brewman.views.services.voucher import get_edit_url
|
||||
from brewman.routers.services.voucher import get_edit_url
|
||||
from fastapi import APIRouter
|
||||
|
||||
router = APIRouter()
|
||||
|
||||
|
||||
@view_config(
|
||||
request_method="GET", route_name="product_ledger_id", permission="Product Ledger"
|
||||
)
|
||||
@view_config(
|
||||
request_method="GET", route_name="product_ledger", permission="Product Ledger"
|
||||
)
|
||||
def html(request):
|
||||
package, resource = "brewman:static/index.html".split(":", 1)
|
||||
file = pkg_resources.resource_filename(package, resource)
|
||||
return FileResponse(file, request=request)
|
||||
|
||||
|
||||
@view_config(
|
||||
request_method="GET",
|
||||
route_name="api_product_ledger",
|
||||
renderer="json",
|
||||
permission="Product Ledger",
|
||||
)
|
||||
@router.get("/api/product-ledger") # "Product Ledger"
|
||||
def show_blank(request):
|
||||
return {
|
||||
"startDate": session_period_start(request),
|
||||
@@ -45,12 +28,7 @@ def show_blank(request):
|
||||
}
|
||||
|
||||
|
||||
@view_config(
|
||||
request_method="GET",
|
||||
route_name="api_product_ledger_id",
|
||||
renderer="json",
|
||||
permission="Product Ledger",
|
||||
)
|
||||
@router.get("/api/product-ledger/{id}") # "Product Ledger"
|
||||
def show_data(request):
|
||||
id_ = to_uuid(request.matchdict["id"])
|
||||
if id_ is None:
|
||||
@@ -1,33 +1,22 @@
|
||||
import datetime
|
||||
|
||||
import pkg_resources
|
||||
from pyramid.response import FileResponse
|
||||
from pyramid.view import view_config
|
||||
from sqlalchemy.sql.expression import func, desc
|
||||
|
||||
from brewman.models.master import AccountType, AccountBase
|
||||
from brewman.models.voucher import Voucher, Journal, VoucherType
|
||||
from brewman.views.reports.closing_stock import get_opening_stock, get_closing_stock
|
||||
from brewman.views.services.session import (
|
||||
from brewman.routers.reports.closing_stock import get_opening_stock, get_closing_stock
|
||||
from brewman.routers.services.session import (
|
||||
session_period_set,
|
||||
session_period_start,
|
||||
session_period_finish,
|
||||
)
|
||||
|
||||
from fastapi import APIRouter
|
||||
|
||||
@view_config(request_method="GET", route_name="profit_loss", permission="Profit & Loss")
|
||||
def html(request):
|
||||
package, resource = "brewman:static/index.html".split(":", 1)
|
||||
file = pkg_resources.resource_filename(package, resource)
|
||||
return FileResponse(file, request=request)
|
||||
router = APIRouter()
|
||||
|
||||
|
||||
@view_config(
|
||||
request_method="GET",
|
||||
route_name="api_profit_loss",
|
||||
renderer="json",
|
||||
permission="Profit & Loss",
|
||||
)
|
||||
@router.get("/api/profit-loss", permission="Profit & Loss")
|
||||
def report_blank(request):
|
||||
return {
|
||||
"startDate": session_period_start(request),
|
||||
@@ -37,13 +26,7 @@ def report_blank(request):
|
||||
}
|
||||
|
||||
|
||||
@view_config(
|
||||
request_method="GET",
|
||||
route_name="api_profit_loss",
|
||||
request_param=["s", "f"],
|
||||
renderer="json",
|
||||
permission="Profit & Loss",
|
||||
)
|
||||
@router.get("/api/profit-loss", request_param=["s", "f"], permission="Profit & Loss")
|
||||
def report_data(request):
|
||||
start_date = request.GET["s"]
|
||||
finish_date = request.GET["f"]
|
||||
+8
-28
@@ -1,33 +1,19 @@
|
||||
import datetime
|
||||
|
||||
import pkg_resources
|
||||
from pyramid.response import FileResponse
|
||||
from pyramid.view import view_config
|
||||
|
||||
from brewman.models.voucher import Voucher, VoucherType
|
||||
from brewman.views.services.session import (
|
||||
from brewman.routers.services.session import (
|
||||
session_period_set,
|
||||
session_period_start,
|
||||
session_period_finish,
|
||||
)
|
||||
from brewman.views.services.voucher import get_edit_url
|
||||
from brewman.routers.services.voucher import get_edit_url
|
||||
|
||||
from fastapi import APIRouter
|
||||
|
||||
router = APIRouter()
|
||||
|
||||
|
||||
@view_config(
|
||||
request_method="GET", route_name="purchase_entries", permission="Purchase Entries"
|
||||
)
|
||||
def html(request):
|
||||
package, resource = "brewman:static/index.html".split(":", 1)
|
||||
file = pkg_resources.resource_filename(package, resource)
|
||||
return FileResponse(file, request=request)
|
||||
|
||||
|
||||
@view_config(
|
||||
request_method="GET",
|
||||
route_name="api_purchase_entries",
|
||||
renderer="json",
|
||||
permission="Purchase Entries",
|
||||
)
|
||||
@router.get("/api/purchase-entries") # "Purchase Entries"
|
||||
def report_blank(request):
|
||||
return {
|
||||
"startDate": session_period_start(request),
|
||||
@@ -36,13 +22,7 @@ def report_blank(request):
|
||||
}
|
||||
|
||||
|
||||
@view_config(
|
||||
request_method="GET",
|
||||
route_name="api_purchase_entries",
|
||||
request_param=["s", "f"],
|
||||
renderer="json",
|
||||
permission="Purchase Entries",
|
||||
)
|
||||
@router.get("/api/purchase-entries", request_param=["s", "f"], permission="Purchase Entries")
|
||||
def report_data(request):
|
||||
start_date = request.GET["s"]
|
||||
finish_date = request.GET["f"]
|
||||
@@ -1,32 +1,21 @@
|
||||
import datetime
|
||||
|
||||
import pkg_resources
|
||||
from pyramid.response import FileResponse
|
||||
from pyramid.view import view_config
|
||||
from sqlalchemy.sql.expression import func, desc
|
||||
|
||||
from brewman.models.master import CostCentre, Product
|
||||
from brewman.models.voucher import Voucher, Journal, Inventory, VoucherType
|
||||
from brewman.views.services.session import (
|
||||
from brewman.routers.services.session import (
|
||||
session_period_set,
|
||||
session_period_start,
|
||||
session_period_finish,
|
||||
)
|
||||
|
||||
from fastapi import APIRouter
|
||||
|
||||
@view_config(request_method="GET", route_name="purchases", permission="Purchases")
|
||||
def html(request):
|
||||
package, resource = "brewman:static/index.html".split(":", 1)
|
||||
file = pkg_resources.resource_filename(package, resource)
|
||||
return FileResponse(file, request=request)
|
||||
router = APIRouter()
|
||||
|
||||
|
||||
@view_config(
|
||||
request_method="GET",
|
||||
route_name="api_purchases",
|
||||
renderer="json",
|
||||
permission="Purchases",
|
||||
)
|
||||
@router.get("/api/purchases") # "Purchases"
|
||||
def report_blank(request):
|
||||
return {
|
||||
"startDate": session_period_start(request),
|
||||
@@ -36,13 +25,7 @@ def report_blank(request):
|
||||
}
|
||||
|
||||
|
||||
@view_config(
|
||||
request_method="GET",
|
||||
route_name="api_purchases",
|
||||
request_param=["s", "f"],
|
||||
renderer="json",
|
||||
permission="Purchases",
|
||||
)
|
||||
@router.get("/api/purchases", request_param=["s", "f"], permission="Purchases")
|
||||
def report_data(request):
|
||||
start_date = request.GET["s"]
|
||||
finish_date = request.GET["f"]
|
||||
+6
-36
@@ -1,40 +1,22 @@
|
||||
import datetime
|
||||
import uuid
|
||||
|
||||
import pkg_resources
|
||||
from pyramid.response import FileResponse
|
||||
from pyramid.view import view_config
|
||||
from sqlalchemy.sql.expression import func, case
|
||||
|
||||
from brewman.models.master import AccountBase, CostCentre, Product, ProductGroup
|
||||
from brewman.models.voucher import Voucher, Journal, Inventory
|
||||
from brewman.views.services.session import (
|
||||
from brewman.routers.services.session import (
|
||||
session_period_set,
|
||||
session_period_start,
|
||||
session_period_finish,
|
||||
)
|
||||
|
||||
from fastapi import APIRouter
|
||||
|
||||
@view_config(
|
||||
request_method="GET", route_name="raw_material_cost", permission="Raw Material Cost"
|
||||
)
|
||||
@view_config(
|
||||
request_method="GET",
|
||||
route_name="raw_material_cost_id",
|
||||
permission="Raw Material Cost",
|
||||
)
|
||||
def get_html(request):
|
||||
package, resource = "brewman:static/index.html".split(":", 1)
|
||||
file = pkg_resources.resource_filename(package, resource)
|
||||
return FileResponse(file, request=request)
|
||||
router = APIRouter()
|
||||
|
||||
|
||||
@view_config(
|
||||
request_method="GET",
|
||||
route_name="api_raw_material_cost",
|
||||
renderer="json",
|
||||
permission="Raw Material Cost",
|
||||
)
|
||||
@router.get("/api/raw-material-cost") # "Raw Material Cost"
|
||||
def report_blank(request):
|
||||
return {
|
||||
"startDate": session_period_start(request),
|
||||
@@ -44,13 +26,7 @@ def report_blank(request):
|
||||
}
|
||||
|
||||
|
||||
@view_config(
|
||||
request_method="GET",
|
||||
route_name="api_raw_material_cost",
|
||||
request_param=["s", "f"],
|
||||
renderer="json",
|
||||
permission="Raw Material Cost",
|
||||
)
|
||||
@router.get("/api/raw-material-cost", request_param=["s", "f"], permission="Raw Material Cost")
|
||||
def report_data(request):
|
||||
start_date = request.GET["s"]
|
||||
finish_date = request.GET["f"]
|
||||
@@ -64,13 +40,7 @@ def report_data(request):
|
||||
}
|
||||
|
||||
|
||||
@view_config(
|
||||
request_method="GET",
|
||||
route_name="api_raw_material_cost_id",
|
||||
request_param=["s", "f"],
|
||||
renderer="json",
|
||||
permission="Raw Material Cost",
|
||||
)
|
||||
@router.get("/api/raw-material-cost/{id}", request_param=["s", "f"], permission="Raw Material Cost")
|
||||
def report_id(request):
|
||||
id_ = request.matchdict["id"]
|
||||
start_date = request.GET["s"]
|
||||
@@ -1,37 +1,23 @@
|
||||
import datetime
|
||||
import uuid
|
||||
|
||||
import pkg_resources
|
||||
import transaction
|
||||
from pyramid.response import FileResponse
|
||||
from pyramid.view import view_config
|
||||
from sqlalchemy.orm import joinedload_all
|
||||
from sqlalchemy.sql.expression import func, or_, and_
|
||||
|
||||
from brewman.models.master import AccountBase
|
||||
from brewman.models.voucher import Voucher, Journal, VoucherType
|
||||
from brewman.views.services.session import (
|
||||
from brewman.routers.services.session import (
|
||||
session_period_set,
|
||||
session_period_start,
|
||||
session_period_finish,
|
||||
)
|
||||
from brewman.views.services.voucher import get_edit_url
|
||||
from brewman.routers.services.voucher import get_edit_url
|
||||
|
||||
from fastapi import APIRouter
|
||||
|
||||
router = APIRouter()
|
||||
|
||||
|
||||
@view_config(request_method="GET", route_name="reconcile_id", permission="Reconcile")
|
||||
@view_config(request_method="GET", route_name="reconcile", permission="Reconcile")
|
||||
def html(request):
|
||||
package, resource = "brewman:static/index.html".split(":", 1)
|
||||
file = pkg_resources.resource_filename(package, resource)
|
||||
return FileResponse(file, request=request)
|
||||
|
||||
|
||||
@view_config(
|
||||
request_method="GET",
|
||||
route_name="api_reconcile",
|
||||
renderer="json",
|
||||
permission="Reconcile",
|
||||
)
|
||||
@router.get("/api/reconcile") # "Reconcile"
|
||||
def show_blank(request):
|
||||
return {
|
||||
"startDate": session_period_start(request),
|
||||
@@ -41,13 +27,7 @@ def show_blank(request):
|
||||
}
|
||||
|
||||
|
||||
@view_config(
|
||||
request_method="GET",
|
||||
route_name="api_reconcile_id",
|
||||
renderer="json",
|
||||
permission="Reconcile",
|
||||
trans=True,
|
||||
)
|
||||
@router.get("/api/reconcile/{id}") # "Reconcile"
|
||||
def show_data(request):
|
||||
account = (
|
||||
request.dbsession.query(AccountBase)
|
||||
@@ -160,12 +140,7 @@ def opening_balance(account_id, start_date, dbsession):
|
||||
}
|
||||
|
||||
|
||||
@view_config(
|
||||
request_method="POST",
|
||||
route_name="api_reconcile_id",
|
||||
renderer="json",
|
||||
permission="Reconcile",
|
||||
)
|
||||
@router.post("/api/reconcile/{id}") # "Reconcile"
|
||||
def save(request):
|
||||
account = (
|
||||
request.dbsession.query(AccountBase)
|
||||
+5
-24
@@ -1,34 +1,21 @@
|
||||
import datetime
|
||||
|
||||
import pkg_resources
|
||||
from pyramid.response import FileResponse
|
||||
from pyramid.view import view_config
|
||||
from sqlalchemy.sql.expression import func
|
||||
|
||||
from brewman.models.master import Product, CostCentre
|
||||
from brewman.models.voucher import Voucher, Journal, VoucherType, Inventory
|
||||
from brewman.views.services.session import (
|
||||
from brewman.routers.services.session import (
|
||||
session_period_set,
|
||||
session_period_start,
|
||||
session_period_finish,
|
||||
)
|
||||
|
||||
from fastapi import APIRouter
|
||||
|
||||
@view_config(
|
||||
request_method="GET", route_name="stock_movement", permission="Stock Movement"
|
||||
)
|
||||
def html(request):
|
||||
package, resource = "brewman:static/index.html".split(":", 1)
|
||||
file = pkg_resources.resource_filename(package, resource)
|
||||
return FileResponse(file, request=request)
|
||||
router = APIRouter()
|
||||
|
||||
|
||||
@view_config(
|
||||
request_method="GET",
|
||||
route_name="api_stock_movement",
|
||||
renderer="json",
|
||||
permission="Stock Movement",
|
||||
)
|
||||
@router.get("/api/stock-movement") # "Stock Movement"
|
||||
def report_blank(request):
|
||||
return {
|
||||
"startDate": session_period_start(request),
|
||||
@@ -37,13 +24,7 @@ def report_blank(request):
|
||||
}
|
||||
|
||||
|
||||
@view_config(
|
||||
request_method="GET",
|
||||
route_name="api_stock_movement",
|
||||
request_param=["s", "f"],
|
||||
renderer="json",
|
||||
permission="Stock Movement",
|
||||
)
|
||||
@router.get("/api/stock-movement", request_param=["s", "f"], permission="Stock Movement")
|
||||
def report_data(request):
|
||||
start_date = request.GET["s"]
|
||||
finish_date = request.GET["f"]
|
||||
@@ -1,47 +1,26 @@
|
||||
import datetime
|
||||
|
||||
import pkg_resources
|
||||
from pyramid.response import FileResponse
|
||||
from pyramid.view import view_config
|
||||
from sqlalchemy.sql.expression import func
|
||||
|
||||
from brewman.models.master import AccountBase
|
||||
from brewman.models.voucher import Voucher, Journal, VoucherType
|
||||
from brewman.views.services.session import (
|
||||
from brewman.routers.services.session import (
|
||||
session_period_set,
|
||||
session_period_start,
|
||||
session_period_finish,
|
||||
)
|
||||
|
||||
from fastapi import APIRouter
|
||||
|
||||
@view_config(
|
||||
request_method="GET", route_name="trial_balance", permission="Trial Balance"
|
||||
)
|
||||
@view_config(
|
||||
request_method="GET", route_name="trial_balance_date", permission="Trial Balance"
|
||||
)
|
||||
def html(request):
|
||||
package, resource = "brewman:static/index.html".split(":", 1)
|
||||
file = pkg_resources.resource_filename(package, resource)
|
||||
return FileResponse(file, request=request)
|
||||
router = APIRouter()
|
||||
|
||||
|
||||
@view_config(
|
||||
request_method="GET",
|
||||
route_name="api_trial_balance",
|
||||
renderer="json",
|
||||
permission="Trial Balance",
|
||||
)
|
||||
@router.get("/api/trial-balance") # "Trial Balance"
|
||||
def report_blank(request):
|
||||
return {"date": session_period_finish(request), "body": []}
|
||||
|
||||
|
||||
@view_config(
|
||||
request_method="GET",
|
||||
route_name="api_trial_balance_date",
|
||||
renderer="json",
|
||||
permission="Trial Balance",
|
||||
)
|
||||
@router.get("/api/trial-balance/{date}") # "Trial Balance"
|
||||
def report_data(request):
|
||||
date = request.matchdict.get("date", None)
|
||||
session_period_set(session_period_start(request), date, request)
|
||||
@@ -1,25 +1,14 @@
|
||||
import pkg_resources
|
||||
from pyramid.response import FileResponse
|
||||
from pyramid.view import view_config
|
||||
from sqlalchemy.orm import joinedload_all
|
||||
|
||||
from brewman.models.voucher import Voucher, Journal, VoucherType
|
||||
from brewman.views.services.voucher import get_edit_url
|
||||
from brewman.routers.services.voucher import get_edit_url
|
||||
|
||||
from fastapi import APIRouter
|
||||
|
||||
router = APIRouter()
|
||||
|
||||
|
||||
@view_config(request_method="GET", route_name="unposted", permission="Post Vouchers")
|
||||
def html(request):
|
||||
package, resource = "brewman:static/index.html".split(":", 1)
|
||||
file = pkg_resources.resource_filename(package, resource)
|
||||
return FileResponse(file, request=request)
|
||||
|
||||
|
||||
@view_config(
|
||||
request_method="GET",
|
||||
route_name="api_unposted",
|
||||
renderer="json",
|
||||
permission="Post Vouchers",
|
||||
)
|
||||
@router.get("/api/unposted") # "Post Vouchers"
|
||||
def report_data(request):
|
||||
return build_report(request)
|
||||
|
||||
Whitespace-only changes.
@@ -1,16 +1,9 @@
|
||||
import datetime
|
||||
|
||||
from pyramid.view import view_config
|
||||
|
||||
from brewman.models.voucher import Batch
|
||||
|
||||
|
||||
@view_config(
|
||||
request_method="GET",
|
||||
route_name="api_batch",
|
||||
renderer="json",
|
||||
permission="Authenticated",
|
||||
)
|
||||
@router.get("/api/batch") # "Authenticated"
|
||||
def batch_term(request):
|
||||
filter_ = request.GET.get("t", None)
|
||||
filter_ = filter_ if filter_ is not None and filter_.strip() is not "" else None
|
||||
@@ -1,14 +1,11 @@
|
||||
import datetime
|
||||
|
||||
from pyramid.view import view_config
|
||||
from sqlalchemy.orm.util import aliased
|
||||
|
||||
from brewman.models.voucher import Voucher, Journal, VoucherType
|
||||
|
||||
|
||||
@view_config(
|
||||
route_name="api_issue_grid", renderer="json", permission="Issue", trans=True
|
||||
)
|
||||
@router.get("/api/issue-grid/{date}") # "Issue"
|
||||
def grid_date(request):
|
||||
date = datetime.datetime.strptime(request.matchdict["date"], "%d-%b-%Y")
|
||||
return get_grid(date, request.dbsession)
|
||||
@@ -1,11 +1,5 @@
|
||||
import uuid
|
||||
from datetime import date, timedelta
|
||||
|
||||
from pyramid.view import view_config
|
||||
|
||||
from brewman.models.auth import User
|
||||
from brewman.security import f7
|
||||
|
||||
|
||||
def session_current_date(request):
|
||||
session = request.session
|
||||
@@ -44,25 +38,6 @@ def session_period_set(start, finish, request):
|
||||
)
|
||||
|
||||
|
||||
@view_config(route_name="api_auth", renderer="json")
|
||||
def user_permission(request):
|
||||
user_id = request.authenticated_userid
|
||||
if user_id is None:
|
||||
auth = {"isAuthenticated": False, "perms": {}}
|
||||
elif "auth" in request.session:
|
||||
auth = request.session["auth"]
|
||||
else:
|
||||
user = request.dbsession.query(User).filter(User.id == uuid.UUID(user_id)).one()
|
||||
auth = {
|
||||
"id": user.id,
|
||||
"name": user.name,
|
||||
"isAuthenticated": True,
|
||||
"perms": sorted(f7([p.name for g in user.groups for p in g.roles])),
|
||||
}
|
||||
request.session["auth"] = auth
|
||||
return auth
|
||||
|
||||
|
||||
def get_first_day(dt, d_years=0, d_months=0):
|
||||
# d_years, d_months are "deltas" to apply to dt
|
||||
y, m = dt.year + d_years, dt.month + d_months
|
||||
+4
-50
@@ -1,11 +1,6 @@
|
||||
import datetime
|
||||
import uuid
|
||||
from decimal import Decimal
|
||||
|
||||
import pkg_resources
|
||||
import transaction
|
||||
from pyramid.response import Response, FileResponse
|
||||
from pyramid.view import view_config
|
||||
from sqlalchemy import func, or_
|
||||
|
||||
from brewman.models.auth import User
|
||||
@@ -25,7 +20,7 @@ from brewman.models.voucher import (
|
||||
Attendance,
|
||||
Journal,
|
||||
)
|
||||
from brewman.views import get_lock_info
|
||||
from brewman.routers import get_lock_info
|
||||
from .issue import issue_create_voucher, issue_update_voucher
|
||||
from .journal import journal_update_voucher, journal_create_voucher
|
||||
from .purchase import purchase_create_voucher, purchase_update_voucher
|
||||
@@ -33,44 +28,7 @@ from .service_charge import service_charge_create_voucher, service_charge_update
|
||||
from ..session import get_first_day
|
||||
|
||||
|
||||
@view_config(request_method="GET", route_name="journal_id", permission="Journal")
|
||||
@view_config(request_method="GET", route_name="journal", permission="Journal")
|
||||
@view_config(request_method="GET", route_name="payment_id", permission="Payment")
|
||||
@view_config(request_method="GET", route_name="payment", permission="Payment")
|
||||
@view_config(request_method="GET", route_name="receipt_id", permission="Receipt")
|
||||
@view_config(request_method="GET", route_name="receipt", permission="Receipt")
|
||||
@view_config(request_method="GET", route_name="purchase_id", permission="Purchase")
|
||||
@view_config(request_method="GET", route_name="purchase", permission="Purchase")
|
||||
@view_config(
|
||||
request_method="GET", route_name="purchase_return_id", permission="Purchase Return"
|
||||
)
|
||||
@view_config(
|
||||
request_method="GET", route_name="purchase_return", permission="Purchase Return"
|
||||
)
|
||||
@view_config(request_method="GET", route_name="issue_id", permission="Issue")
|
||||
@view_config(request_method="GET", route_name="issue", permission="Issue")
|
||||
@view_config(
|
||||
request_method="GET", route_name="employee_benefits_id", permission="Issue"
|
||||
)
|
||||
@view_config(request_method="GET", route_name="employee_benefits", permission="Issue")
|
||||
@view_config(
|
||||
request_method="GET", route_name="incentive_id", permission="Service Charge"
|
||||
)
|
||||
@view_config(request_method="GET", route_name="incentive", permission="Service Charge")
|
||||
def journal_get(request):
|
||||
package, resource = "brewman:static/index.html".split(":", 1)
|
||||
file = pkg_resources.resource_filename(package, resource)
|
||||
return FileResponse(file, request=request)
|
||||
|
||||
|
||||
@view_config(
|
||||
request_method="POST",
|
||||
route_name="api_voucher_id",
|
||||
request_param="p",
|
||||
renderer="json",
|
||||
permission="Post Vouchers",
|
||||
trans=True,
|
||||
)
|
||||
@router.post("/api/voucher/{id}", request_param="p") # "Post Vouchers"
|
||||
def voucher_post(request):
|
||||
user = (
|
||||
request.dbsession.query(User)
|
||||
@@ -140,9 +98,7 @@ def check_delete_permissions(request, voucher):
|
||||
return response
|
||||
|
||||
|
||||
@view_config(
|
||||
request_method="DELETE", route_name="api_voucher_id", renderer="json", trans=True
|
||||
)
|
||||
@router.delete("/api/voucher/{id}")
|
||||
def delete(request):
|
||||
voucher = (
|
||||
request.dbsession.query(Voucher)
|
||||
@@ -211,9 +167,7 @@ def delete(request):
|
||||
return blank_voucher(info=json_voucher, dbsession=request.dbsession)
|
||||
|
||||
|
||||
@view_config(
|
||||
request_method="GET", route_name="api_voucher_id", renderer="json", trans=True
|
||||
)
|
||||
@router.get("/api/voucher/{id}")
|
||||
def get_old(request):
|
||||
id_ = request.matchdict.get("id", None)
|
||||
voucher = (
|
||||
+1
-10
@@ -2,23 +2,14 @@ import calendar
|
||||
import datetime
|
||||
import uuid
|
||||
|
||||
from pyramid.view import view_config
|
||||
from sqlalchemy import or_
|
||||
import transaction
|
||||
|
||||
from ....models.auth import User
|
||||
from ....models.master import Employee, AttendanceType, Account
|
||||
from ....models.voucher import Voucher, VoucherType, Attendance, Journal
|
||||
from ..session import get_first_day, get_last_day
|
||||
|
||||
|
||||
@view_config(
|
||||
request_method="POST",
|
||||
route_name="api_credit_salary",
|
||||
renderer="json",
|
||||
permission="Attendance",
|
||||
trans=True,
|
||||
)
|
||||
@router.post("/api/credit-salary") # "Attendance"
|
||||
def credit_salary(request):
|
||||
user = (
|
||||
request.dbsession.query(User)
|
||||
+10
-12
@@ -1,40 +1,38 @@
|
||||
from pyramid.view import view_config, view_defaults
|
||||
from brewman.views.services.session import session_current_date
|
||||
from brewman.views.services.voucher import blank_voucher
|
||||
from brewman.routers.services.session import session_current_date
|
||||
from brewman.routers.services.voucher import blank_voucher
|
||||
|
||||
|
||||
@view_defaults(request_method="GET", route_name="api_voucher", renderer="json")
|
||||
class EmptyVoucher(object):
|
||||
def __init__(self, request):
|
||||
self.request = request
|
||||
|
||||
@view_config(request_param="t=Journal", permission="Journal")
|
||||
@router.get("/api/voucher", request_param="t=Journal") # "Journal"
|
||||
def journal(self):
|
||||
return self.get_blank()
|
||||
|
||||
@view_config(request_param="t=Payment", permission="Payment")
|
||||
@router.get("/api/voucher", request_param="t=Payment") # "Payment"
|
||||
def payment(self):
|
||||
account = self.request.GET.get("a", None)
|
||||
return self.get_blank({"account": account})
|
||||
|
||||
@view_config(request_param="t=Receipt", permission="Receipt")
|
||||
@router.get("/api/voucher", request_param="t=Receipt") # "Receipt"
|
||||
def receipt(self):
|
||||
account = self.request.GET.get("a", None)
|
||||
return self.get_blank({"account": account})
|
||||
|
||||
@view_config(request_param="t=Purchase", permission="Purchase")
|
||||
@router.get("/api/voucher", request_param="t=Purchase") # "Purchase"
|
||||
def purchase(self):
|
||||
return self.get_blank()
|
||||
|
||||
@view_config(request_param="t=Purchase Return", permission="Purchase Return")
|
||||
@router.get("/api/voucher", request_param="t=Purchase Return") # "Purchase Return"
|
||||
def purchase_return(self):
|
||||
return self.get_blank()
|
||||
|
||||
@view_config(request_param="t=Salary Deduction", permission="Purchase Return")
|
||||
@router.get("/api/voucher", request_param="t=Salary Deduction") # "Purchase Return"
|
||||
def purchase_return(self):
|
||||
return self.get_blank()
|
||||
|
||||
@view_config(request_param="t=Issue", permission="Issue")
|
||||
@router.get("/api/voucher", request_param="t=Issue") # "Issue"
|
||||
def issue(self):
|
||||
voucher_type = self.request.GET.get("t", None)
|
||||
date = self.request.GET.get("date", None)
|
||||
@@ -53,7 +51,7 @@ class EmptyVoucher(object):
|
||||
else:
|
||||
return self.get_blank()
|
||||
|
||||
@view_config(request_param="t=Service Charge", permission="Service Charge")
|
||||
@router.get("/api/voucher", request_param="t=Service Charge") # "Service Charge"
|
||||
def service_charge(self):
|
||||
voucher_type = self.request.GET.get("t", None)
|
||||
date = self.request.GET.get("d", None)
|
||||
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
+1
-1
@@ -5,7 +5,7 @@ from brewman.models.master import AccountBase, Employee
|
||||
from brewman.models.operations import journals_valid
|
||||
from brewman.models.validation_exception import ValidationError
|
||||
from brewman.models.voucher import Journal, Voucher, VoucherType, SalaryDeduction
|
||||
from brewman.views.services.session import get_last_day
|
||||
from brewman.routers.services.session import get_last_day
|
||||
|
||||
|
||||
def salary_deduction_create_voucher(json, user, dbsession):
|
||||
+11
-17
@@ -1,15 +1,11 @@
|
||||
import uuid
|
||||
from json import loads
|
||||
import datetime
|
||||
|
||||
from pyramid.view import view_defaults, view_config
|
||||
import transaction
|
||||
|
||||
from brewman.models.auth import User
|
||||
from brewman.models.validation_exception import ValidationError
|
||||
from brewman.models.voucher import Voucher
|
||||
from brewman.views import get_lock_info
|
||||
from brewman.views.services.session import session_current_date_set
|
||||
from brewman.routers import get_lock_info
|
||||
from brewman.routers.services.session import session_current_date_set
|
||||
from . import (
|
||||
voucher_info,
|
||||
journal_create_voucher,
|
||||
@@ -21,9 +17,7 @@ from .purchase_return import purchase_return_create_voucher
|
||||
from .salary_deduction import salary_deduction_create_voucher
|
||||
|
||||
|
||||
@view_defaults(
|
||||
request_method="POST", route_name="api_voucher", renderer="json", trans=True
|
||||
)
|
||||
@router.post("/api/voucher")
|
||||
class SaveVoucher(object):
|
||||
def __init__(self, request):
|
||||
def parse_post(req):
|
||||
@@ -51,35 +45,35 @@ class SaveVoucher(object):
|
||||
self.start, self.finish = get_lock_info(request.dbsession)
|
||||
self.voucher_date = datetime.datetime.strptime(self.json["date"], "%d-%b-%Y")
|
||||
|
||||
@view_config(request_param="t=Journal", permission="Journal")
|
||||
@router.get("/api/voucher", request_param="t=Journal") # "Journal"
|
||||
def journal(self):
|
||||
return self.save()
|
||||
|
||||
@view_config(request_param="t=Payment", permission="Payment")
|
||||
@router.get("/api/voucher", request_param="t=Payment") # "Payment"
|
||||
def payment(self):
|
||||
return self.save()
|
||||
|
||||
@view_config(request_param="t=Receipt", permission="Receipt")
|
||||
@router.get("/api/voucher", request_param="t=Receipt") # "Receipt"
|
||||
def receipt(self):
|
||||
return self.save()
|
||||
|
||||
@view_config(request_param="t=Purchase", permission="Purchase")
|
||||
@router.get("/api/voucher", request_param="t=Purchase") # "Purchase"
|
||||
def purchase(self):
|
||||
return self.save()
|
||||
|
||||
@view_config(request_param="t=Purchase Return", permission="Purchase Return")
|
||||
@router.get("/api/voucher", request_param="t=Purchase Return") # "Purchase Return"
|
||||
def purchase_return(self):
|
||||
return self.save()
|
||||
|
||||
@view_config(request_param="t=Issue", permission="Issue")
|
||||
@router.get("/api/voucher", request_param="t=Issue") # "Issue"
|
||||
def issue(self):
|
||||
return self.save()
|
||||
|
||||
@view_config(request_param="t=Salary Deduction", permission="Salary Deduction")
|
||||
@router.get("/api/voucher", request_param="t=Salary Deduction") # "Salary Deduction"
|
||||
def salary_deduction(self):
|
||||
return self.save()
|
||||
|
||||
@view_config(request_param="t=Service Charge", permission="Service Charge")
|
||||
@router.get("/api/voucher", request_param="t=Service Charge") # "Service Charge"
|
||||
def salary_deduction(self):
|
||||
return self.save()
|
||||
|
||||
+1
-1
@@ -13,7 +13,7 @@ from brewman.models.voucher import (
|
||||
Attendance,
|
||||
ServiceCharge,
|
||||
)
|
||||
from brewman.views.services.session import get_first_day
|
||||
from brewman.routers.services.session import get_first_day
|
||||
|
||||
|
||||
def service_charge_create_voucher(json, user, dbsession):
|
||||
+12
-17
@@ -1,15 +1,13 @@
|
||||
import datetime
|
||||
import transaction
|
||||
import uuid
|
||||
|
||||
from json import loads
|
||||
from pyramid.response import Response
|
||||
from pyramid.view import view_defaults, view_config
|
||||
|
||||
from brewman.models.auth import User
|
||||
from brewman.models.voucher import Voucher
|
||||
from brewman.views import get_lock_info
|
||||
from brewman.views.services.session import session_current_date_set
|
||||
from brewman.routers import get_lock_info
|
||||
from brewman.routers.services.session import session_current_date_set
|
||||
from . import (
|
||||
voucher_info,
|
||||
issue_update_voucher,
|
||||
@@ -17,17 +15,14 @@ from . import (
|
||||
journal_update_voucher,
|
||||
)
|
||||
from . import service_charge_update_voucher
|
||||
from brewman.views.services.voucher.purchase_return import (
|
||||
from brewman.routers.services.voucher.purchase_return import (
|
||||
purchase_return_update_voucher,
|
||||
)
|
||||
from brewman.views.services.voucher.salary_deduction import (
|
||||
from brewman.routers.services.voucher.salary_deduction import (
|
||||
salary_deduction_update_voucher,
|
||||
)
|
||||
|
||||
|
||||
@view_defaults(
|
||||
request_method="POST", route_name="api_voucher_id", renderer="json", trans=True
|
||||
)
|
||||
class UpdateVoucher(object):
|
||||
def __init__(self, request):
|
||||
def parse_post(request):
|
||||
@@ -95,35 +90,35 @@ class UpdateVoucher(object):
|
||||
else:
|
||||
self.error = None
|
||||
|
||||
@view_config(request_param="t=Journal", permission="Journal")
|
||||
@router.get("/api/voucher/{id}", request_param="t=Journal") # "Journal"
|
||||
def journal(self):
|
||||
return self.update()
|
||||
|
||||
@view_config(request_param="t=Payment", permission="Payment")
|
||||
@router.get("/api/voucher/{id}", request_param="t=Payment") # "Payment"
|
||||
def payment(self):
|
||||
return self.update()
|
||||
|
||||
@view_config(request_param="t=Receipt", permission="Receipt")
|
||||
@router.get("/api/voucher/{id}", request_param="t=Receipt") # "Receipt"
|
||||
def receipt(self):
|
||||
return self.update()
|
||||
|
||||
@view_config(request_param="t=Purchase", permission="Purchase")
|
||||
@router.get("/api/voucher/{id}", request_param="t=Purchase") # "Purchase"
|
||||
def purchase(self):
|
||||
return self.update()
|
||||
|
||||
@view_config(request_param="t=Purchase Return", permission="Purchase Return")
|
||||
@router.get("/api/voucher/{id}", request_param="t=Purchase Return") # "Purchase Return"
|
||||
def purchase_return(self):
|
||||
return self.update()
|
||||
|
||||
@view_config(request_param="t=Issue", permission="Issue")
|
||||
@router.get("/api/voucher/{id}", request_param="t=Issue") # "Issue"
|
||||
def issue(self):
|
||||
return self.update()
|
||||
|
||||
@view_config(request_param="t=Salary Deduction", permission="Salary Deduction")
|
||||
@router.get("/api/voucher/{id}", request_param="t=Salary Deduction") # "Salary Deduction"
|
||||
def salary_deduction(self):
|
||||
return self.update()
|
||||
|
||||
@view_config(request_param="t=Service Charge", permission="Service Charge")
|
||||
@router.get("/api/voucher/{id}", request_param="t=Service Charge") # "Service Charge"
|
||||
def service_charge(self):
|
||||
return self.update()
|
||||
|
||||
@@ -1,183 +0,0 @@
|
||||
def includeme(config):
|
||||
config.add_route("api_db_integrity", "/api/db-integrity")
|
||||
config.add_route("api_login", "/api/login")
|
||||
config.add_route("login", "/login")
|
||||
config.add_route("logout", "/logout")
|
||||
config.add_route("api_logout", "/api/logout")
|
||||
|
||||
config.add_route("home", "/")
|
||||
|
||||
config.add_route("api_account_type_list", "/api/account-types")
|
||||
|
||||
config.add_route("cost_centres_new", "/cost-centres/new")
|
||||
config.add_route("cost_centres_id", "/cost-centres/{id}")
|
||||
config.add_route("cost_centres_list", "/cost-centres")
|
||||
config.add_route("api_cost_centres_new", "/api/cost-centres/new")
|
||||
config.add_route("api_cost_centres_id", "/api/cost-centres/{id}")
|
||||
config.add_route("api_cost_centres_list", "/api/cost-centres")
|
||||
|
||||
config.add_route("accounts_new", "/accounts/new")
|
||||
config.add_route("accounts_id", "/accounts/{id}")
|
||||
config.add_route("accounts_list", "/accounts")
|
||||
config.add_route("api_accounts_new", "/api/accounts/new")
|
||||
config.add_route("api_accounts_id", "/api/accounts/{id}")
|
||||
config.add_route("api_accounts_list", "/api/accounts")
|
||||
|
||||
config.add_route("employees_new", "/employees/new")
|
||||
config.add_route("employees_id", "/employees/{id}")
|
||||
config.add_route("employees_list", "/employees")
|
||||
config.add_route("api_employees_new", "/api/employees/new")
|
||||
config.add_route("api_employees_id", "/api/employees/{id}")
|
||||
config.add_route("api_employees_list", "/api/employees")
|
||||
|
||||
config.add_route("users_new", "/users/new")
|
||||
config.add_route("users_id", "/users/{id}")
|
||||
config.add_route("users_list", "/users")
|
||||
config.add_route("api_users_new", "/api/users/new")
|
||||
config.add_route("api_users_id", "/api/users/{id}")
|
||||
config.add_route("api_users_list", "/api/users")
|
||||
|
||||
config.add_route("groups_new", "/groups/new")
|
||||
config.add_route("groups_id", "/groups/{id}")
|
||||
config.add_route("groups_list", "/groups")
|
||||
config.add_route("api_groups_new", "/api/groups/new")
|
||||
config.add_route("api_groups_id", "/api/groups/{id}")
|
||||
config.add_route("api_groups_list", "/api/groups")
|
||||
|
||||
config.add_route("clients_id", "/clients/{id}")
|
||||
config.add_route("clients_list", "/clients")
|
||||
config.add_route("api_clients_id", "/api/clients/{id}")
|
||||
config.add_route("api_clients_list", "/api/clients")
|
||||
|
||||
config.add_route("products_new", "/products/new")
|
||||
config.add_route("products_id", "/products/{id}")
|
||||
config.add_route("products_list", "/products")
|
||||
config.add_route("api_products_new", "/api/products/new")
|
||||
config.add_route("api_products_id", "/api/products/{id}")
|
||||
config.add_route("api_products_list", "/api/products")
|
||||
|
||||
config.add_route("recipes_new", "/recipes/new")
|
||||
config.add_route("recipes_id", "/recipes/{id}")
|
||||
config.add_route("recipes_list", "/recipes")
|
||||
config.add_route("api_recipes_new", "/api/recipes/new")
|
||||
config.add_route("api_recipes_id", "/api/recipes/{id}")
|
||||
config.add_route("api_recipes_list", "/api/recipes")
|
||||
|
||||
config.add_route("product_groups_new", "/product-groups/new")
|
||||
config.add_route("product_groups_id", "/product-groups/{id}")
|
||||
config.add_route("product_groups_list", "/product-groups")
|
||||
config.add_route("api_product_groups_new", "/api/product-groups/new")
|
||||
config.add_route("api_product_groups_id", "/api/product-groups/{id}")
|
||||
config.add_route("api_product_groups_list", "/api/product-groups")
|
||||
|
||||
config.add_route("journal_id", "/journal/{id}")
|
||||
config.add_route("journal", "/journal")
|
||||
config.add_route("purchase_id", "/purchase/{id}")
|
||||
config.add_route("purchase", "/purchase")
|
||||
config.add_route("purchase_return_id", "/return/{id}")
|
||||
config.add_route("purchase_return", "/return")
|
||||
config.add_route("payment_id", "/payment/{id}")
|
||||
config.add_route("payment", "/payment")
|
||||
config.add_route("receipt_id", "/receipt/{id}")
|
||||
config.add_route("receipt", "/receipt")
|
||||
config.add_route("issue_id", "/issue/{id}")
|
||||
config.add_route("issue", "/issue")
|
||||
config.add_route("api_issue_grid", "/api/issue-grid/{date}")
|
||||
config.add_route("employee_benefits_id", "/employee-benefits/{id}")
|
||||
config.add_route("employee_benefits", "/employee-benefits")
|
||||
config.add_route("incentive_id", "/incentive/{id}")
|
||||
config.add_route("incentive", "/incentive")
|
||||
config.add_route("db_image", "/api/db-image/{id}/{type}")
|
||||
|
||||
config.add_route("api_voucher_id", "/api/voucher/{id}")
|
||||
config.add_route("api_voucher", "/api/voucher")
|
||||
|
||||
config.add_route("settings", "/settings")
|
||||
config.add_route("api_lock_information", "/api/lock-information")
|
||||
config.add_route("api_maintenance", "/api/maintenance")
|
||||
|
||||
config.add_route("attendance_date", "/attendance/{date}")
|
||||
config.add_route("attendance", "/attendance")
|
||||
config.add_route("api_attendance_date", "/api/attendance/{date}")
|
||||
config.add_route("api_attendance", "/api/attendance")
|
||||
|
||||
config.add_route("api_attendance_types", "/api/attendance-types")
|
||||
|
||||
config.add_route("employee_attendance_id", "/employee-attendance/{id}")
|
||||
config.add_route("employee_attendance", "/employee-attendance")
|
||||
config.add_route("api_employee_attendance_id", "/api/employee-attendance/{id}")
|
||||
config.add_route("api_employee_attendance", "/api/employee-attendance")
|
||||
|
||||
config.add_route("attendance_report", "/attendance-report")
|
||||
config.add_route("api_credit_salary", "/api/credit-salary")
|
||||
config.add_route("employee_functions", "/employee-functions")
|
||||
config.add_route("api_fingerprint", "/api/fingerprint")
|
||||
|
||||
config.add_route("ledger_id", "/ledger/{id}")
|
||||
config.add_route("ledger", "/ledger")
|
||||
config.add_route("api_ledger_id", "/api/ledger/{id}")
|
||||
config.add_route("api_ledger", "/api/ledger")
|
||||
|
||||
config.add_route("reconcile_id", "/reconcile/{id}")
|
||||
config.add_route("reconcile", "/reconcile")
|
||||
config.add_route("api_reconcile_id", "/api/reconcile/{id}")
|
||||
config.add_route("api_reconcile", "/api/reconcile")
|
||||
|
||||
config.add_route("product_ledger_id", "/product-ledger/{id}")
|
||||
config.add_route("product_ledger", "/product-ledger")
|
||||
config.add_route("api_product_ledger_id", "/api/product-ledger/{id}")
|
||||
config.add_route("api_product_ledger", "/api/product-ledger")
|
||||
|
||||
config.add_route("trial_balance_date", "/trial-balance/{date}")
|
||||
config.add_route("trial_balance", "/trial-balance")
|
||||
config.add_route("api_trial_balance_date", "/api/trial-balance/{date}")
|
||||
config.add_route("api_trial_balance", "/api/trial-balance")
|
||||
|
||||
config.add_route("net_transactions", "/net-transactions")
|
||||
config.add_route("api_net_transactions", "/api/net-transactions")
|
||||
|
||||
config.add_route("purchases", "/purchases")
|
||||
config.add_route("api_purchases", "/api/purchases")
|
||||
|
||||
config.add_route("closing_stock_date", "/closing-stock/{date}")
|
||||
config.add_route("closing_stock", "/closing-stock")
|
||||
config.add_route("api_closing_stock_date", "/api/closing-stock/{date}")
|
||||
config.add_route("api_closing_stock", "/api/closing-stock")
|
||||
|
||||
config.add_route("cash_flow_id", "/cash-flow/{id}")
|
||||
config.add_route("cash_flow", "/cash-flow")
|
||||
config.add_route("api_cash_flow_id", "/api/cash-flow/{id}")
|
||||
config.add_route("api_cash_flow", "/api/cash-flow")
|
||||
|
||||
config.add_route("raw_material_cost_id", "/raw-material-cost/{id}")
|
||||
config.add_route("raw_material_cost", "/raw-material-cost")
|
||||
config.add_route("api_raw_material_cost_id", "/api/raw-material-cost/{id}")
|
||||
config.add_route("api_raw_material_cost", "/api/raw-material-cost")
|
||||
|
||||
config.add_route("api_daybook", "/api/daybook")
|
||||
config.add_route("daybook", "/daybook")
|
||||
|
||||
config.add_route("unposted", "/unposted")
|
||||
config.add_route("api_unposted", "/api/unposted")
|
||||
|
||||
config.add_route("profit_loss", "/profit-loss")
|
||||
config.add_route("api_profit_loss", "/api/profit-loss")
|
||||
|
||||
config.add_route("stock_movement", "/stock-movement")
|
||||
config.add_route("api_stock_movement", "/api/stock-movement")
|
||||
|
||||
config.add_route("balance_sheet_date", "/balance-sheet/{date}")
|
||||
config.add_route("balance_sheet", "/balance-sheet")
|
||||
config.add_route("api_balance_sheet_date", "/api/balance-sheet/{date}")
|
||||
config.add_route("api_balance_sheet", "/api/balance-sheet")
|
||||
|
||||
config.add_route("purchase_entries", "/purchase-entries")
|
||||
config.add_route("api_purchase_entries", "/api/purchase-entries")
|
||||
|
||||
config.add_route("api_auth", "/api/auth")
|
||||
config.add_route("api_rebase", "/api/rebase/{date}")
|
||||
config.add_route("api_reset_stock", "/api/reset-stock/{id}")
|
||||
|
||||
config.add_route("api_batch", "/api/batch")
|
||||
|
||||
config.add_static_view("", "brewman:static")
|
||||
Whitespace-only changes.
@@ -0,0 +1,36 @@
|
||||
import uuid
|
||||
from datetime import datetime
|
||||
from pydantic import BaseModel
|
||||
|
||||
|
||||
class Client(BaseModel):
|
||||
id_: uuid.UUID
|
||||
code: int
|
||||
name: str
|
||||
enabled: bool
|
||||
otp: int
|
||||
creation_date: datetime
|
||||
|
||||
|
||||
class User(BaseModel):
|
||||
id_: uuid.UUID
|
||||
name: str
|
||||
password: str
|
||||
locked_out: bool
|
||||
|
||||
|
||||
class LoginHistory(BaseModel):
|
||||
id_: uuid.UUID
|
||||
user_id: uuid.UUID
|
||||
client_id: uuid.UUID
|
||||
date: datetime
|
||||
|
||||
|
||||
class Group(BaseModel):
|
||||
id_: uuid.UUID
|
||||
name: str
|
||||
|
||||
|
||||
class Role(BaseModel):
|
||||
id_: uuid.UUID
|
||||
name: str
|
||||
@@ -0,0 +1,88 @@
|
||||
import uuid
|
||||
from datetime import date
|
||||
from decimal import Decimal
|
||||
|
||||
from pydantic import BaseModel, Field
|
||||
|
||||
|
||||
class Product(BaseModel):
|
||||
id_: uuid.UUID
|
||||
code: int
|
||||
name: str
|
||||
units: str
|
||||
fraction: Decimal
|
||||
fraction_units: str
|
||||
product_yield: Decimal
|
||||
product_group_id: uuid.UUID
|
||||
account_id: uuid.UUID
|
||||
price: Decimal
|
||||
sale_price: Decimal
|
||||
is_active: bool
|
||||
is_fixture: bool
|
||||
is_purchased: bool
|
||||
is_sold: bool
|
||||
|
||||
|
||||
class Recipe(BaseModel):
|
||||
id_: uuid.UUID
|
||||
product_id: uuid.UUID
|
||||
|
||||
quantity: Decimal
|
||||
cost_price: Decimal
|
||||
sale_price: Decimal
|
||||
notes: str
|
||||
|
||||
valid_from: date
|
||||
valid_to: date
|
||||
|
||||
effective_from: date
|
||||
effective_to: date
|
||||
|
||||
|
||||
class RecipeItem(BaseModel):
|
||||
id_: uuid.UUID
|
||||
recipe_id: uuid.UUID
|
||||
product_id: uuid.UUID
|
||||
quantity: int
|
||||
price: int
|
||||
|
||||
|
||||
class ProductGroup(BaseModel):
|
||||
id_: uuid.UUID
|
||||
name: str
|
||||
is_fixture: bool
|
||||
|
||||
|
||||
class CostCentreSaveUpdate(BaseModel):
|
||||
name: str
|
||||
|
||||
|
||||
class CostCentre(CostCentreSaveUpdate):
|
||||
id_: uuid.UUID = Field(alias="id")
|
||||
is_fixture: bool = Field(alias="isFixture")
|
||||
|
||||
|
||||
class Account(BaseModel):
|
||||
id_: uuid.UUID
|
||||
code: int
|
||||
name: str
|
||||
type: int
|
||||
is_starred: bool
|
||||
is_active: bool
|
||||
is_reconcilable: bool
|
||||
cost_centre: CostCentre
|
||||
is_fixture: bool
|
||||
|
||||
|
||||
class Employee(Account):
|
||||
designation: str
|
||||
salary: int
|
||||
service_points: Decimal
|
||||
joining_date: date
|
||||
leaving_date: date
|
||||
|
||||
|
||||
class DbSetting(BaseModel):
|
||||
id_: uuid.UUID
|
||||
name: str
|
||||
data: bytes
|
||||
@@ -0,0 +1,96 @@
|
||||
import uuid
|
||||
from datetime import datetime, date
|
||||
from decimal import Decimal
|
||||
|
||||
from pydantic import BaseModel
|
||||
|
||||
|
||||
class Voucher(BaseModel):
|
||||
id: uuid.UUID
|
||||
date: date
|
||||
narration: str
|
||||
is_reconciled: bool
|
||||
reconcile_date: datetime
|
||||
is_starred: bool
|
||||
creation_date: datetime
|
||||
last_edit_date: datetime
|
||||
_type: int
|
||||
user_id: uuid.UUID
|
||||
posted: bool
|
||||
poster_id: uuid.UUID
|
||||
|
||||
|
||||
class Journal(BaseModel):
|
||||
id: uuid.UUID
|
||||
debit: int
|
||||
amount: Decimal
|
||||
voucher_id: uuid.UUID
|
||||
account_id: uuid.UUID
|
||||
cost_centre_id: uuid.UUID
|
||||
|
||||
|
||||
class SalaryDeduction(BaseModel):
|
||||
id: uuid.UUID
|
||||
voucher_id: uuid.UUID
|
||||
journal_id: uuid.UUID
|
||||
gross_salary: int
|
||||
days_worked: int
|
||||
esi_ee: int
|
||||
pf_ee: int
|
||||
esi_er: int
|
||||
pf_er: int
|
||||
|
||||
|
||||
class ServiceCharge(BaseModel):
|
||||
id: uuid.UUID
|
||||
voucher_id: uuid.UUID
|
||||
journal_id: uuid.UUID
|
||||
days_worked: int
|
||||
points: Decimal
|
||||
|
||||
|
||||
class Inventory(BaseModel):
|
||||
id: uuid.UUID
|
||||
voucher_id: uuid.UUID
|
||||
product_id: uuid.UUID
|
||||
batch_id: uuid.UUID
|
||||
quantity: Decimal
|
||||
rate: Decimal
|
||||
tax: Decimal
|
||||
discount: Decimal
|
||||
|
||||
|
||||
class Batch(BaseModel):
|
||||
id: uuid.UUID
|
||||
name: datetime
|
||||
product_id: uuid.UUID
|
||||
quantity_remaining: Decimal
|
||||
rate: Decimal
|
||||
tax: Decimal
|
||||
discount: Decimal
|
||||
|
||||
|
||||
class Attendance(BaseModel):
|
||||
id: uuid.UUID
|
||||
employee_id: uuid.UUID
|
||||
date: date
|
||||
attendance_type: int
|
||||
amount: Decimal
|
||||
creation_date: datetime
|
||||
user_id: uuid.UUID
|
||||
is_valid: bool
|
||||
|
||||
|
||||
class Fingerprint(BaseModel):
|
||||
id: uuid.UUID
|
||||
employee_id: uuid.UUID
|
||||
date: date
|
||||
|
||||
|
||||
class DbImage(BaseModel):
|
||||
id: uuid.UUID
|
||||
resource_id: uuid.UUID
|
||||
resource_type: str
|
||||
image: bytearray
|
||||
thumbnail: bytearray
|
||||
creation_date: datetime
|
||||
@@ -1,42 +0,0 @@
|
||||
import uuid
|
||||
from pyramid.authentication import AuthTktAuthenticationPolicy
|
||||
from brewman.security.permission_authorization_policy import (
|
||||
PermissionAuthorizationPolicy,
|
||||
)
|
||||
from ..models.auth import User
|
||||
|
||||
|
||||
def get_user(request):
|
||||
user_id = request.unauthenticated_userid
|
||||
if user_id is not None:
|
||||
user = request.dbsession.query(User).get(user_id)
|
||||
return user
|
||||
|
||||
|
||||
def groupfinder(user_id, request):
|
||||
if "perms" in request.session:
|
||||
perms = request.session["perms"]
|
||||
else:
|
||||
perms = []
|
||||
user = request.dbsession.query(User).filter(User.id == uuid.UUID(user_id)).one()
|
||||
for item in user.groups:
|
||||
for perm in item.roles:
|
||||
perms.append(perm.name)
|
||||
perms = sorted(f7(perms))
|
||||
request.session["perms"] = perms
|
||||
return perms
|
||||
|
||||
|
||||
def f7(seq):
|
||||
seen = set()
|
||||
seen_add = seen.add
|
||||
return [x for x in seq if x not in seen and not seen_add(x)]
|
||||
|
||||
|
||||
def includeme(config):
|
||||
authn_policy = AuthTktAuthenticationPolicy(
|
||||
"brewman", timeout=900, reissue_time=90, callback=groupfinder
|
||||
)
|
||||
config.set_authentication_policy(authn_policy)
|
||||
config.set_authorization_policy(PermissionAuthorizationPolicy())
|
||||
config.add_request_method(get_user, "user", reify=True)
|
||||
@@ -1,19 +0,0 @@
|
||||
from zope.interface import implementer
|
||||
|
||||
from pyramid.interfaces import IAuthorizationPolicy
|
||||
|
||||
|
||||
@implementer(IAuthorizationPolicy)
|
||||
class PermissionAuthorizationPolicy(object):
|
||||
def permits(self, context, principals, permission):
|
||||
if permission == "Authenticated":
|
||||
permission = "system.Authenticated"
|
||||
if permission == "Everyone":
|
||||
permission = "system.Everyone"
|
||||
allowed = permission in principals
|
||||
return allowed
|
||||
|
||||
def principals_allowed_by_permission(self, context, permission):
|
||||
allowed = set()
|
||||
allowed.add(permission)
|
||||
return allowed
|
||||
@@ -1,18 +0,0 @@
|
||||
import unittest
|
||||
|
||||
from pyramid import testing
|
||||
|
||||
|
||||
class ViewTests(unittest.TestCase):
|
||||
def setUp(self):
|
||||
self.config = testing.setUp()
|
||||
|
||||
def tearDown(self):
|
||||
testing.tearDown()
|
||||
|
||||
def test_my_view(self):
|
||||
from .views import my_view
|
||||
|
||||
request = testing.DummyRequest()
|
||||
info = my_view(request)
|
||||
self.assertEqual(info["project"], "brewman")
|
||||
@@ -1,33 +0,0 @@
|
||||
from pyramid.response import Response
|
||||
from sqlalchemy.exc import OperationalError, IntegrityError, DBAPIError
|
||||
import transaction
|
||||
from brewman.models.validation_exception import ValidationError
|
||||
|
||||
|
||||
def transactional_view(view, info):
|
||||
if info.options.get("trans"):
|
||||
|
||||
def wrapper_view(context, request):
|
||||
try:
|
||||
response = view(context, request)
|
||||
except (
|
||||
ValidationError,
|
||||
ValueError,
|
||||
KeyError,
|
||||
AttributeError,
|
||||
TypeError,
|
||||
OperationalError,
|
||||
IntegrityError,
|
||||
DBAPIError,
|
||||
) as ex:
|
||||
transaction.abort()
|
||||
response = Response("Failed validation: {0}".format(str(ex)))
|
||||
response.status_int = 500
|
||||
finally:
|
||||
return response
|
||||
|
||||
return wrapper_view
|
||||
return view
|
||||
|
||||
|
||||
transactional_view.options = ("trans",)
|
||||
@@ -1,310 +0,0 @@
|
||||
import datetime
|
||||
import uuid
|
||||
|
||||
import pkg_resources
|
||||
import transaction
|
||||
from pyramid.response import Response, FileResponse
|
||||
from pyramid.view import view_config
|
||||
from sqlalchemy import func
|
||||
from sqlalchemy.orm import joinedload_all
|
||||
|
||||
from brewman.models.master import CostCentre, Account, AccountType, AccountBase
|
||||
from brewman.models.validation_exception import ValidationError
|
||||
from brewman.models.voucher import Voucher, Journal, VoucherType
|
||||
|
||||
|
||||
@view_config(request_method="GET", route_name="accounts_new", permission="Accounts")
|
||||
@view_config(request_method="GET", route_name="accounts_id", permission="Accounts")
|
||||
@view_config(route_name="accounts_list", permission="Accounts")
|
||||
def html(request):
|
||||
package, resource = "brewman:static/index.html".split(":", 1)
|
||||
file = pkg_resources.resource_filename(package, resource)
|
||||
return FileResponse(file, request=request)
|
||||
|
||||
|
||||
@view_config(
|
||||
request_method="POST",
|
||||
route_name="api_accounts_new",
|
||||
renderer="json",
|
||||
permission="Accounts",
|
||||
trans=True,
|
||||
)
|
||||
def save(request):
|
||||
json = request.json_body
|
||||
item = Account(
|
||||
code=0,
|
||||
name=json["name"],
|
||||
type=int(json["type"]),
|
||||
is_starred=json["isStarred"],
|
||||
is_active=json["isActive"],
|
||||
is_reconcilable=json["isReconcilable"],
|
||||
cost_centre_id=uuid.UUID(json["costCentre"]["id"]),
|
||||
).create(request.dbsession)
|
||||
transaction.commit()
|
||||
return account_info(item.id, request.dbsession)
|
||||
|
||||
|
||||
@view_config(
|
||||
request_method="PUT",
|
||||
route_name="api_accounts_id",
|
||||
renderer="json",
|
||||
permission="Accounts",
|
||||
trans=True,
|
||||
)
|
||||
def update(request):
|
||||
item = (
|
||||
request.dbsession.query(Account)
|
||||
.filter(Account.id == uuid.UUID(request.matchdict["id"]))
|
||||
.first()
|
||||
)
|
||||
if item.is_fixture:
|
||||
raise ValidationError(
|
||||
"{0} is a fixture and cannot be edited or deleted.".format(item.name)
|
||||
)
|
||||
new_type = int(request.json_body["type"])
|
||||
if not item.type == new_type:
|
||||
item.code = Account.get_code(new_type, request.dbsession)
|
||||
item.type = new_type
|
||||
item.name = request.json_body["name"]
|
||||
item.is_active = request.json_body["isActive"]
|
||||
item.is_reconcilable = request.json_body["isReconcilable"]
|
||||
item.is_starred = request.json_body["isStarred"]
|
||||
item.cost_centre_id = uuid.UUID(request.json_body["costCentre"]["id"])
|
||||
transaction.commit()
|
||||
return account_info(item.id, request.dbsession)
|
||||
|
||||
|
||||
@view_config(
|
||||
request_method="DELETE",
|
||||
route_name="api_accounts_id",
|
||||
renderer="json",
|
||||
permission="Accounts",
|
||||
)
|
||||
def delete(request):
|
||||
account = (
|
||||
request.dbsession.query(Account)
|
||||
.filter(Account.id == uuid.UUID(request.matchdict["id"]))
|
||||
.first()
|
||||
)
|
||||
can_delete, reason = account.can_delete(request.has_permission("Advanced Delete"))
|
||||
if can_delete:
|
||||
delete_with_data(account, request.dbsession)
|
||||
transaction.commit()
|
||||
return account_info(None, request.dbsession)
|
||||
else:
|
||||
transaction.abort()
|
||||
response = Response("Cannot delete account because {0}".format(reason))
|
||||
response.status_int = 500
|
||||
return response
|
||||
|
||||
|
||||
@view_config(
|
||||
request_method="GET",
|
||||
route_name="api_accounts_id",
|
||||
renderer="json",
|
||||
request_param="b",
|
||||
permission="Authenticated",
|
||||
)
|
||||
def show_balance(request):
|
||||
date = request.GET.get("d", None)
|
||||
date = (
|
||||
None
|
||||
if date is None or date == ""
|
||||
else datetime.datetime.strptime(date, "%d-%b-%Y")
|
||||
)
|
||||
id_ = uuid.UUID(request.matchdict["id"])
|
||||
return {
|
||||
"date": balance(id_, date, request.dbsession),
|
||||
"total": balance(id_, None, request.dbsession),
|
||||
}
|
||||
|
||||
|
||||
def balance(id_, date, dbsession):
|
||||
account = dbsession.query(AccountBase).filter(AccountBase.id == id_).first()
|
||||
if not account.type_object.balance_sheet:
|
||||
return 0
|
||||
|
||||
bal = dbsession.query(func.sum(Journal.amount * Journal.debit)).join(
|
||||
Journal.voucher
|
||||
)
|
||||
if date is not None:
|
||||
bal = bal.filter(Voucher.date <= date)
|
||||
|
||||
bal = (
|
||||
bal.filter(Voucher.type != VoucherType.by_name("Issue").id)
|
||||
.filter(Journal.account_id == id_)
|
||||
.scalar()
|
||||
)
|
||||
return 0 if bal is None else bal
|
||||
|
||||
|
||||
@view_config(
|
||||
request_method="GET",
|
||||
route_name="api_accounts_id",
|
||||
renderer="json",
|
||||
permission="Accounts",
|
||||
)
|
||||
def show_id(request):
|
||||
return account_info(uuid.UUID(request.matchdict["id"]), request.dbsession)
|
||||
|
||||
|
||||
@view_config(
|
||||
request_method="GET",
|
||||
route_name="api_accounts_new",
|
||||
renderer="json",
|
||||
permission="Accounts",
|
||||
)
|
||||
def show_blank(request):
|
||||
return account_info(None, request.dbsession)
|
||||
|
||||
|
||||
@view_config(
|
||||
request_method="GET",
|
||||
route_name="api_accounts_list",
|
||||
renderer="json",
|
||||
request_param="l",
|
||||
permission="Authenticated",
|
||||
)
|
||||
def show_list(request):
|
||||
list_ = (
|
||||
request.dbsession.query(Account)
|
||||
.order_by(Account.type)
|
||||
.order_by(Account.name)
|
||||
.order_by(Account.code)
|
||||
.all()
|
||||
)
|
||||
accounts = []
|
||||
for item in list_:
|
||||
accounts.append(
|
||||
{
|
||||
"id": item.id,
|
||||
"name": item.name,
|
||||
"type": item.type_object.name,
|
||||
"isActive": item.is_active,
|
||||
"isReconcilable": item.is_reconcilable,
|
||||
"isStarred": item.is_starred,
|
||||
"costCentre": item.cost_centre.name,
|
||||
"isFixture": item.is_fixture,
|
||||
}
|
||||
)
|
||||
return accounts
|
||||
|
||||
|
||||
@view_config(
|
||||
request_method="GET",
|
||||
route_name="api_accounts_list",
|
||||
renderer="json",
|
||||
request_param="q",
|
||||
permission="Authenticated",
|
||||
)
|
||||
def show_term(request):
|
||||
type_ = request.GET.get("t", None)
|
||||
type_ = int(type_) if type_ is not None else None
|
||||
filter_ = request.GET.get("q", None)
|
||||
filter_ = filter_ if filter_ is not None and filter_ is not "" else None
|
||||
reconcilable = request.GET.get("r", None)
|
||||
reconcilable = reconcilable if reconcilable is not None else None
|
||||
active = request.GET.get("a", None)
|
||||
active = active if active is not None else None
|
||||
count = request.GET.get("c", None)
|
||||
count = None if count is None or count == "" else int(count)
|
||||
|
||||
list_ = []
|
||||
for index, item in enumerate(
|
||||
AccountBase.list(type_, filter_, reconcilable, active, request.dbsession)
|
||||
):
|
||||
list_.append({"id": item.id, "name": item.name})
|
||||
if count is not None and index == count - 1:
|
||||
break
|
||||
return list_
|
||||
|
||||
|
||||
@view_config(
|
||||
request_method="GET",
|
||||
route_name="api_account_type_list",
|
||||
renderer="json",
|
||||
permission="Authenticated",
|
||||
)
|
||||
def account_type_list(request):
|
||||
account_types = []
|
||||
for item in AccountType.list():
|
||||
account_types.append({"id": item.id, "name": item.name})
|
||||
return account_types
|
||||
|
||||
|
||||
def account_info(id_, dbsession):
|
||||
if id_ is None:
|
||||
account = {
|
||||
"code": "(Auto)",
|
||||
"type": AccountType.by_name("Creditors").id,
|
||||
"isActive": True,
|
||||
"isReconcilable": False,
|
||||
"isStarred": False,
|
||||
"costCentre": CostCentre.overall(),
|
||||
}
|
||||
else:
|
||||
account = dbsession.query(Account).filter(Account.id == id_).first()
|
||||
account = {
|
||||
"id": account.id,
|
||||
"code": account.code,
|
||||
"name": account.name,
|
||||
"type": account.type,
|
||||
"isActive": account.is_active,
|
||||
"isReconcilable": account.is_reconcilable,
|
||||
"isStarred": account.is_starred,
|
||||
"isFixture": account.is_fixture,
|
||||
"costCentre": {
|
||||
"id": account.cost_centre_id,
|
||||
"name": account.cost_centre.name,
|
||||
},
|
||||
}
|
||||
return account
|
||||
|
||||
|
||||
def delete_with_data(account, dbsession):
|
||||
suspense_account = (
|
||||
dbsession.query(Account).filter(Account.id == Account.suspense()).first()
|
||||
)
|
||||
query = (
|
||||
dbsession.query(Voucher)
|
||||
.options(joinedload_all(Voucher.journals, Journal.account, innerjoin=True))
|
||||
.filter(Voucher.journals.any(Journal.account_id == account.id))
|
||||
.all()
|
||||
)
|
||||
|
||||
for voucher in query:
|
||||
others, sus_jnl, acc_jnl = False, None, None
|
||||
for journal in voucher.journals:
|
||||
if journal.account_id == account.id:
|
||||
acc_jnl = journal
|
||||
elif journal.account_id == Account.suspense():
|
||||
sus_jnl = journal
|
||||
else:
|
||||
others = True
|
||||
if not others:
|
||||
dbsession.delete(voucher)
|
||||
else:
|
||||
if sus_jnl is None:
|
||||
acc_jnl.account = suspense_account
|
||||
voucher.narration += "\nSuspense \u20B9{0:,.2f} is {1}".format(
|
||||
acc_jnl.amount, account.name
|
||||
)
|
||||
else:
|
||||
amount = (sus_jnl.debit * sus_jnl.amount) + (
|
||||
acc_jnl.debit * acc_jnl.amount
|
||||
)
|
||||
dbsession.delete(acc_jnl)
|
||||
if amount == 0:
|
||||
dbsession.delete(sus_jnl)
|
||||
else:
|
||||
sus_jnl.amount = abs(amount)
|
||||
sus_jnl.debit = -1 if amount < 0 else 1
|
||||
voucher.narration += "\nDeleted \u20B9{0:,.2f} of {1}".format(
|
||||
acc_jnl.amount * acc_jnl.debit, account.name
|
||||
)
|
||||
if voucher.type in (
|
||||
VoucherType.by_name("Payment").id,
|
||||
VoucherType.by_name("Receipt").id,
|
||||
):
|
||||
voucher.type = VoucherType.by_name("Journal")
|
||||
dbsession.delete(account)
|
||||
@@ -1,274 +0,0 @@
|
||||
import datetime
|
||||
import uuid
|
||||
|
||||
import pkg_resources
|
||||
import transaction
|
||||
from pyramid.response import FileResponse
|
||||
from pyramid.view import view_config
|
||||
from sqlalchemy import or_
|
||||
|
||||
from brewman.models.master import AttendanceType, Employee
|
||||
from brewman.models.validation_exception import ValidationError
|
||||
from brewman.models.voucher import Attendance
|
||||
from brewman.views.fingerprint import get_prints
|
||||
from brewman.views.services.session import (
|
||||
session_period_start,
|
||||
session_period_finish,
|
||||
session_current_date,
|
||||
)
|
||||
|
||||
|
||||
@view_config(
|
||||
request_method="GET", route_name="attendance_date", permission="Attendance"
|
||||
)
|
||||
@view_config(request_method="GET", route_name="attendance", permission="Attendance")
|
||||
@view_config(
|
||||
request_method="GET", route_name="employee_attendance_id", permission="Attendance"
|
||||
)
|
||||
@view_config(
|
||||
request_method="GET", route_name="employee_attendance", permission="Attendance"
|
||||
)
|
||||
def html(request):
|
||||
package, resource = "brewman:static/index.html".split(":", 1)
|
||||
file = pkg_resources.resource_filename(package, resource)
|
||||
return FileResponse(file, request=request)
|
||||
|
||||
|
||||
@view_config(
|
||||
request_method="GET",
|
||||
route_name="api_attendance_types",
|
||||
renderer="json",
|
||||
permission="Authenticated",
|
||||
)
|
||||
def show_list(request):
|
||||
list_ = AttendanceType.list()
|
||||
attendance_types = []
|
||||
for item in list_:
|
||||
attendance_types.append({"id": item.id, "name": item.name, "value": item.value})
|
||||
return attendance_types
|
||||
|
||||
|
||||
@view_config(
|
||||
request_method="GET",
|
||||
route_name="api_attendance",
|
||||
renderer="json",
|
||||
permission="Attendance",
|
||||
)
|
||||
def attendance_blank(request):
|
||||
return {"date": session_current_date(request), "body": []}
|
||||
|
||||
|
||||
@view_config(
|
||||
request_method="GET",
|
||||
route_name="api_attendance_date",
|
||||
renderer="json",
|
||||
permission="Attendance",
|
||||
)
|
||||
def attendance_date(request):
|
||||
date = request.matchdict.get("date", None)
|
||||
return attendance_date_report(date, request.dbsession)
|
||||
|
||||
|
||||
def attendance_date_report(date, dbsession):
|
||||
report = {"date": date, "body": []}
|
||||
date = datetime.datetime.strptime(date, "%d-%b-%Y")
|
||||
employees = (
|
||||
dbsession.query(Employee)
|
||||
.filter(Employee.joining_date <= date)
|
||||
.filter(or_(Employee.is_active, Employee.leaving_date >= date))
|
||||
.order_by(Employee.cost_centre_id)
|
||||
.order_by(Employee.designation)
|
||||
.order_by(Employee.name)
|
||||
.all()
|
||||
)
|
||||
for item in employees:
|
||||
att = (
|
||||
dbsession.query(Attendance)
|
||||
.filter(Attendance.employee_id == item.id)
|
||||
.filter(Attendance.date == date)
|
||||
.filter(Attendance.is_valid == True)
|
||||
.first()
|
||||
)
|
||||
att = 0 if att is None else att.attendance_type
|
||||
|
||||
prints, hours, worked = get_prints(item.id, date, dbsession)
|
||||
report["body"].append(
|
||||
{
|
||||
"id": item.id,
|
||||
"code": item.code,
|
||||
"name": item.name,
|
||||
"designation": item.designation,
|
||||
"department": item.cost_centre.name,
|
||||
"attendanceType": {"id": att},
|
||||
"prints": prints,
|
||||
"hours": hours,
|
||||
"worked": worked,
|
||||
}
|
||||
)
|
||||
return report
|
||||
|
||||
|
||||
@view_config(
|
||||
request_method="POST",
|
||||
route_name="api_attendance_date",
|
||||
renderer="json",
|
||||
permission="Attendance",
|
||||
trans=True,
|
||||
)
|
||||
def save(request):
|
||||
user_id = uuid.UUID(request.authenticated_userid)
|
||||
date = request.matchdict.get("date", None)
|
||||
date_object = datetime.datetime.strptime(date, "%d-%b-%Y")
|
||||
|
||||
for item in request.json_body["body"]:
|
||||
employee_id = uuid.UUID(item["id"])
|
||||
attendance_type = item["attendanceType"]["id"]
|
||||
if attendance_type != 0:
|
||||
attendance = Attendance(
|
||||
employee_id=employee_id,
|
||||
date=date_object,
|
||||
attendance_type=attendance_type,
|
||||
user_id=user_id,
|
||||
)
|
||||
attendance.create(request.dbsession)
|
||||
transaction.commit()
|
||||
return attendance_date_report(date, request.dbsession)
|
||||
|
||||
|
||||
@view_config(
|
||||
request_method="GET",
|
||||
route_name="api_employee_attendance",
|
||||
renderer="json",
|
||||
permission="Attendance",
|
||||
)
|
||||
def employee_attendance_blank(request):
|
||||
return {
|
||||
"startDate": session_period_start(request),
|
||||
"finishDate": session_period_finish(request),
|
||||
"employee": None,
|
||||
"body": [],
|
||||
}
|
||||
|
||||
|
||||
@view_config(
|
||||
request_method="GET",
|
||||
route_name="api_employee_attendance_id",
|
||||
renderer="json",
|
||||
permission="Attendance",
|
||||
)
|
||||
def employee_attendance_report(request):
|
||||
employee = (
|
||||
request.dbsession.query(Employee)
|
||||
.filter(Employee.id == uuid.UUID(request.matchdict["id"]))
|
||||
.first()
|
||||
)
|
||||
if employee is None:
|
||||
raise ValidationError("Employee id is wrong")
|
||||
start_date = request.GET.get("s", session_period_start(request))
|
||||
finish_date = request.GET.get("f", session_period_finish(request))
|
||||
info = {
|
||||
"startDate": start_date,
|
||||
"finishDate": finish_date,
|
||||
"employee": {"id": employee.id, "name": employee.name},
|
||||
}
|
||||
start_date = datetime.datetime.strptime(start_date, "%d-%b-%Y")
|
||||
finish_date = datetime.datetime.strptime(finish_date, "%d-%b-%Y")
|
||||
start_date = (
|
||||
employee.joining_date if employee.joining_date > start_date else start_date
|
||||
)
|
||||
finish_date = (
|
||||
employee.leaving_date
|
||||
if not employee.is_active and employee.leaving_date < finish_date
|
||||
else finish_date
|
||||
)
|
||||
info["body"] = employee_attendance(
|
||||
employee, start_date, finish_date, request.dbsession
|
||||
)
|
||||
return info
|
||||
|
||||
|
||||
def employee_attendance(employee, start_date, finish_date, dbsession):
|
||||
if not isinstance(start_date, datetime.datetime):
|
||||
start_date = datetime.datetime.strptime(start_date, "%d-%b-%Y")
|
||||
if not isinstance(finish_date, datetime.datetime):
|
||||
finish_date = datetime.datetime.strptime(finish_date, "%d-%b-%Y")
|
||||
list_ = []
|
||||
for item in daterange(start_date, finish_date, inclusive=True):
|
||||
att = (
|
||||
dbsession.query(Attendance)
|
||||
.filter(Attendance.employee_id == employee.id)
|
||||
.filter(Attendance.date == item)
|
||||
.filter(Attendance.is_valid == True)
|
||||
.first()
|
||||
)
|
||||
att = 0 if att is None else att.attendance_type
|
||||
prints, hours, worked = get_prints(employee.id, item, dbsession)
|
||||
list_.append(
|
||||
{
|
||||
"date": item.strftime("%d-%b-%Y"),
|
||||
"attendanceType": {"id": att},
|
||||
"prints": prints,
|
||||
"hours": hours,
|
||||
"worked": worked,
|
||||
}
|
||||
)
|
||||
return list_
|
||||
|
||||
|
||||
@view_config(
|
||||
request_method="POST",
|
||||
route_name="api_employee_attendance_id",
|
||||
renderer="json",
|
||||
permission="Attendance",
|
||||
trans=True,
|
||||
)
|
||||
def save_employee_attendance(request):
|
||||
start_date = None
|
||||
finish_date = None
|
||||
user_id = uuid.UUID(request.authenticated_userid)
|
||||
employee = (
|
||||
request.dbsession.query(Employee)
|
||||
.filter(Employee.id == uuid.UUID(request.matchdict["id"]))
|
||||
.first()
|
||||
)
|
||||
for item in request.json_body["body"]:
|
||||
if start_date is None:
|
||||
start_date = item["date"]
|
||||
finish_date = item["date"]
|
||||
|
||||
attendance_type = item["attendanceType"]["id"]
|
||||
if attendance_type != 0:
|
||||
date = datetime.datetime.strptime(item["date"], "%d-%b-%Y")
|
||||
attendance = Attendance(
|
||||
employee_id=employee.id,
|
||||
date=date,
|
||||
attendance_type=attendance_type,
|
||||
user_id=user_id,
|
||||
)
|
||||
attendance.create(request.dbsession)
|
||||
transaction.commit()
|
||||
return {
|
||||
"startDate": start_date,
|
||||
"finishDate": finish_date,
|
||||
"employee": {"id": employee.id, "name": employee.name},
|
||||
"body": employee_attendance(
|
||||
employee, start_date, finish_date, request.dbsession
|
||||
),
|
||||
}
|
||||
|
||||
|
||||
def daterange(start, stop, step=datetime.timedelta(days=1), inclusive=False):
|
||||
# inclusive=False to behave like range by default
|
||||
if step.days > 0:
|
||||
while start < stop:
|
||||
yield start
|
||||
start = start + step
|
||||
# not +=! don't modify object passed in if it's mutable
|
||||
# since this function is not restricted to
|
||||
# only types from datetime module
|
||||
elif step.days < 0:
|
||||
while start > stop:
|
||||
yield start
|
||||
start = start + step
|
||||
if inclusive and start == stop:
|
||||
yield start
|
||||
@@ -1,132 +0,0 @@
|
||||
import uuid
|
||||
import pkg_resources
|
||||
from pyramid.response import Response, FileResponse
|
||||
|
||||
from pyramid.view import view_config
|
||||
import transaction
|
||||
|
||||
from brewman.models.master import CostCentre
|
||||
from brewman.models.validation_exception import ValidationError
|
||||
|
||||
|
||||
@view_config(request_method="GET", route_name="cost_centres_new", permission="Cost Centres")
|
||||
@view_config(request_method="GET", route_name="cost_centres_id", permission="Cost Centres")
|
||||
@view_config(route_name="cost_centres_list", permission="Authenticated")
|
||||
def html(request):
|
||||
package, resource = "brewman:static/index.html".split(":", 1)
|
||||
file = pkg_resources.resource_filename(package, resource)
|
||||
return FileResponse(file, request=request)
|
||||
|
||||
|
||||
@view_config(
|
||||
request_method="POST",
|
||||
route_name="api_cost_centres_new",
|
||||
renderer="json",
|
||||
permission="Cost Centres",
|
||||
trans=True,
|
||||
)
|
||||
def save(request):
|
||||
item = CostCentre(request.json_body["name"])
|
||||
request.dbsession.add(item)
|
||||
transaction.commit()
|
||||
return cost_centre_info(item.id, request.dbsession)
|
||||
|
||||
|
||||
@view_config(
|
||||
request_method="PUT",
|
||||
route_name="api_cost_centres_id",
|
||||
renderer="json",
|
||||
permission="Cost Centres",
|
||||
trans=True,
|
||||
)
|
||||
def update(request):
|
||||
item = (
|
||||
request.dbsession.query(CostCentre)
|
||||
.filter(CostCentre.id == uuid.UUID(request.matchdict["id"]))
|
||||
.first()
|
||||
)
|
||||
if item.is_fixture:
|
||||
raise ValidationError(
|
||||
"{0} is a fixture and cannot be edited or deleted.".format(item.name)
|
||||
)
|
||||
item.name = request.json_body["name"]
|
||||
transaction.commit()
|
||||
return cost_centre_info(item.id, request.dbsession)
|
||||
|
||||
|
||||
@view_config(
|
||||
request_method="DELETE",
|
||||
route_name="api_cost_centres_id",
|
||||
renderer="json",
|
||||
permission="Cost Centres",
|
||||
)
|
||||
def delete(request):
|
||||
item = (
|
||||
request.dbsession.query(CostCentre)
|
||||
.filter(CostCentre.id == uuid.UUID(request.matchdict["id"]))
|
||||
.first()
|
||||
)
|
||||
|
||||
if item is None:
|
||||
response = Response("Cost Centre not found")
|
||||
response.status_int = 500
|
||||
return response
|
||||
elif item.is_fixture:
|
||||
raise ValidationError(
|
||||
"{0} is a fixture and cannot be edited or deleted.".format(item.name)
|
||||
)
|
||||
else:
|
||||
response = Response("Cost Centre deletion not implemented")
|
||||
response.status_int = 500
|
||||
return response
|
||||
|
||||
|
||||
@view_config(
|
||||
request_method="GET",
|
||||
route_name="api_cost_centres_id",
|
||||
renderer="json",
|
||||
permission="Cost Centres",
|
||||
)
|
||||
def show_id(request):
|
||||
return cost_centre_info(
|
||||
uuid.UUID(request.matchdict.get("id", None)), request.dbsession
|
||||
)
|
||||
|
||||
|
||||
@view_config(
|
||||
request_method="GET",
|
||||
route_name="api_cost_centres_new",
|
||||
renderer="json",
|
||||
permission="Cost Centres",
|
||||
)
|
||||
def show_blank(request):
|
||||
return cost_centre_info(None, request.dbsession)
|
||||
|
||||
|
||||
@view_config(
|
||||
request_method="GET",
|
||||
route_name="api_cost_centres_list",
|
||||
request_param="l",
|
||||
renderer="json",
|
||||
permission="Authenticated",
|
||||
)
|
||||
def show_list(request):
|
||||
list_ = request.dbsession.query(CostCentre).order_by(CostCentre.name).all()
|
||||
cost_centres = []
|
||||
for item in list_:
|
||||
cost_centres.append(
|
||||
{"id": item.id, "name": item.name, "isFixture": item.is_fixture}
|
||||
)
|
||||
return cost_centres
|
||||
|
||||
|
||||
def cost_centre_info(id_, dbsession):
|
||||
if id_ is None:
|
||||
return {}
|
||||
else:
|
||||
cost_centre = dbsession.query(CostCentre).filter(CostCentre.id == id_).first()
|
||||
return {
|
||||
"id": cost_centre.id,
|
||||
"name": cost_centre.name,
|
||||
"isFixture": cost_centre.is_fixture,
|
||||
}
|
||||
@@ -1,155 +0,0 @@
|
||||
from datetime import datetime, timedelta
|
||||
|
||||
import transaction
|
||||
from pyramid.httpexceptions import HTTPFound
|
||||
from pyramid.response import Response
|
||||
from pyramid.security import remember, forget
|
||||
from pyramid.view import view_config
|
||||
from sqlalchemy import and_
|
||||
|
||||
from brewman.models.auth import User, Client, LoginHistory
|
||||
from brewman.security import f7
|
||||
|
||||
|
||||
@view_config(route_name="logout")
|
||||
def logout(request):
|
||||
request.session.invalidate()
|
||||
headers = forget(request)
|
||||
return HTTPFound(location=request.route_url("home"), headers=headers)
|
||||
|
||||
|
||||
@view_config(request_method="POST", route_name="api_logout", renderer="json")
|
||||
def api_logout(request):
|
||||
request.session.invalidate()
|
||||
request.response.headers = forget(request)
|
||||
return {"isAuthenticated": False, "perms": {}}
|
||||
|
||||
|
||||
@view_config(request_method="POST", route_name="api_login", renderer="json", trans=True)
|
||||
def login(request):
|
||||
username = request.json_body.get("name", None)
|
||||
password = request.json_body.get("password", None)
|
||||
found, user = User.auth(username, password, request.dbsession)
|
||||
|
||||
client = Client.by_code(request.cookies.get("ClientID", None), request.dbsession)
|
||||
otp = request.json_body.get("otp", None)
|
||||
client_name = request.json_body.get("clientName", None)
|
||||
if user is not None:
|
||||
allowed, client, response = check_client(
|
||||
client, otp, client_name, user, request.dbsession
|
||||
)
|
||||
|
||||
if found and allowed:
|
||||
headers = remember(request, str(user.id))
|
||||
request.response.headers = headers
|
||||
request.response.set_cookie(
|
||||
"ClientID", value=str(client.code), max_age=365 * 24 * 60 * 60
|
||||
)
|
||||
record_login(user.id, client, request.dbsession)
|
||||
transaction.commit()
|
||||
|
||||
return {
|
||||
"id": user.id,
|
||||
"name": user.name,
|
||||
"isAuthenticated": True,
|
||||
"perms": sorted(f7([p.name for g in user.groups for p in g.roles])),
|
||||
}
|
||||
elif not found:
|
||||
response = Response("Login failed")
|
||||
response.status_int = 403
|
||||
transaction.commit()
|
||||
return response
|
||||
else:
|
||||
transaction.commit()
|
||||
return response
|
||||
|
||||
|
||||
def check_client(client, otp, client_name, user, dbsession):
|
||||
outside_login_allowed = False
|
||||
for group in user.groups:
|
||||
for perm in group.roles:
|
||||
if perm.name == "Clients":
|
||||
outside_login_allowed = True
|
||||
|
||||
if (
|
||||
dbsession.query(Client).filter(Client.enabled == True).count() == 0
|
||||
and outside_login_allowed
|
||||
):
|
||||
client = Client.create(dbsession)
|
||||
client.otp = None
|
||||
client.name = "Created on login by " + user.name
|
||||
client.enabled = True
|
||||
return True, client, None
|
||||
|
||||
if client is None:
|
||||
if outside_login_allowed:
|
||||
client = Client.create(dbsession)
|
||||
return True, client, None
|
||||
else:
|
||||
client = Client.create(dbsession)
|
||||
response = Response("Unknown Client")
|
||||
response.status_int = 403
|
||||
response.set_cookie(
|
||||
"ClientID", value=str(client.code), max_age=10 * 365 * 24 * 60 * 60
|
||||
)
|
||||
return False, None, response
|
||||
|
||||
if client.enabled or outside_login_allowed:
|
||||
return True, client, None
|
||||
|
||||
if client.otp is None:
|
||||
response = Response("Client is Forbidden")
|
||||
response.status_int = 403
|
||||
return False, None, response
|
||||
|
||||
if otp is None:
|
||||
response = Response("OTP not supplied")
|
||||
response.status_int = 403
|
||||
return False, None, response
|
||||
elif client.otp != int(otp):
|
||||
response = Response("OTP is wrong")
|
||||
response.status_int = 403
|
||||
return False, None, response
|
||||
else:
|
||||
client.otp = None
|
||||
client.enabled = True
|
||||
client.name = client_name
|
||||
return True, client, None
|
||||
|
||||
|
||||
def record_login(user_id, client, dbsession):
|
||||
history = LoginHistory(user_id)
|
||||
history.client = client
|
||||
dbsession.add(history)
|
||||
|
||||
recent_logins = (
|
||||
dbsession.query(LoginHistory.client_id.distinct())
|
||||
.filter(LoginHistory.date > datetime.utcnow() - timedelta(days=30))
|
||||
.subquery()
|
||||
)
|
||||
|
||||
deletable_clients = (
|
||||
dbsession.query(Client.id)
|
||||
.filter(Client.creation_date < datetime.utcnow() - timedelta(days=3))
|
||||
.filter(Client.enabled == False)
|
||||
.subquery()
|
||||
)
|
||||
|
||||
dbsession.execute(
|
||||
LoginHistory.__table__.delete(
|
||||
and_(
|
||||
~LoginHistory.client_id.in_(recent_logins),
|
||||
LoginHistory.client_id.in_(deletable_clients),
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
dbsession.execute(
|
||||
Client.__table__.delete(
|
||||
and_(
|
||||
Client.creation_date < datetime.utcnow() - timedelta(days=3),
|
||||
Client.enabled == False,
|
||||
~Client.id.in_(recent_logins),
|
||||
)
|
||||
)
|
||||
)
|
||||
@@ -1,51 +0,0 @@
|
||||
[app:main]
|
||||
use = egg:brewman
|
||||
|
||||
pyramid.reload_templates = false
|
||||
pyramid.debug_authorization = false
|
||||
pyramid.debug_notfound = false
|
||||
pyramid.debug_routematch = false
|
||||
pyramid.default_locale_name = en
|
||||
# sqlalchemy.url = postgresql://hops:123456@localhost:7654/hops
|
||||
sqlalchemy.url = postgresql://postgres:123456@localhost:5432/hops
|
||||
|
||||
[server:main]
|
||||
use = egg:waitress#main
|
||||
host = 0.0.0.0
|
||||
port = 6543
|
||||
|
||||
# Begin logging configuration
|
||||
|
||||
[loggers]
|
||||
keys = root, brewman, sqlalchemy.engine.base
|
||||
|
||||
[handlers]
|
||||
keys = console
|
||||
|
||||
[formatters]
|
||||
keys = generic
|
||||
|
||||
[logger_root]
|
||||
level = WARNING
|
||||
handlers = console
|
||||
|
||||
[logger_brewman]
|
||||
level = WARNING
|
||||
handlers =
|
||||
qualname = brewman
|
||||
|
||||
[logger_sqlalchemy.engine.base]
|
||||
level = DEBUG
|
||||
handlers =
|
||||
qualname = sqlalchemy.engine.base
|
||||
|
||||
[handler_console]
|
||||
class = StreamHandler
|
||||
args = (sys.stderr,)
|
||||
level = NOTSET
|
||||
formatter = generic
|
||||
|
||||
[formatter_generic]
|
||||
format = %(asctime)s %(levelname)-5.5s [%(name)s][%(threadName)s] %(message)s
|
||||
|
||||
# End logging configuration
|
||||
@@ -1,44 +0,0 @@
|
||||
[app:main]
|
||||
use = egg:brewman
|
||||
|
||||
pyramid.reload_templates = false
|
||||
pyramid.debug_authorization = false
|
||||
pyramid.debug_notfound = false
|
||||
pyramid.debug_routematch = false
|
||||
pyramid.default_locale_name = en
|
||||
|
||||
[server:main]
|
||||
use = egg:waitress#main
|
||||
host = 0.0.0.0
|
||||
port = 6543
|
||||
|
||||
# Begin logging configuration
|
||||
|
||||
[loggers]
|
||||
keys = root, brewman
|
||||
|
||||
[handlers]
|
||||
keys = console
|
||||
|
||||
[formatters]
|
||||
keys = generic
|
||||
|
||||
[logger_root]
|
||||
level = WARN
|
||||
handlers = console
|
||||
|
||||
[logger_brewman]
|
||||
level = WARN
|
||||
handlers =
|
||||
qualname = brewman
|
||||
|
||||
[handler_console]
|
||||
class = StreamHandler
|
||||
args = (sys.stderr,)
|
||||
level = NOTSET
|
||||
formatter = generic
|
||||
|
||||
[formatter_generic]
|
||||
format = %(asctime)s %(levelname)-5.5s [%(name)s][%(threadName)s] %(message)s
|
||||
|
||||
# End logging configuration
|
||||
+8
-7
@@ -1,7 +1,8 @@
|
||||
pyramid
|
||||
waitress
|
||||
transaction
|
||||
zope.sqlalchemy
|
||||
SQLAlchemy
|
||||
psycopg2-binary
|
||||
|
||||
uvicorn
|
||||
fastapi
|
||||
environs
|
||||
python-jose[cryptography]
|
||||
passlib[bcrypt]
|
||||
psycopg2
|
||||
python-multipart
|
||||
pyjwt
|
||||
@@ -3,20 +3,12 @@ import os
|
||||
from setuptools import setup, find_packages
|
||||
|
||||
here = os.path.abspath(os.path.dirname(__file__))
|
||||
with open(os.path.join(here, 'README.txt')) as f:
|
||||
README = f.read()
|
||||
with open(os.path.join(here, 'CHANGES.txt')) as f:
|
||||
CHANGES = f.read()
|
||||
|
||||
requires = [
|
||||
'pyramid',
|
||||
'waitress',
|
||||
'pyramid_tm',
|
||||
'transaction',
|
||||
'zope.sqlalchemy',
|
||||
'SQLAlchemy',
|
||||
'psycopg2-binary',
|
||||
]
|
||||
with open(os.path.join(here, 'README.txt'), "r") as r:
|
||||
README = r.read()
|
||||
with open(os.path.join(here, 'CHANGES.txt'), "r") as c:
|
||||
CHANGES = c.read()
|
||||
with open(os.path.join(here, 'requirements.txt'), "r") as r:
|
||||
requires = r.read().splitlines()
|
||||
|
||||
setup(name='brewman',
|
||||
version='6.0',
|
||||
|
||||
Reference in new issue
Block a user