feat: work shifts history

This commit is contained in:
2024-11-28 18:00:53 +04:00
parent 41c54d7bb7
commit 96998a4c05
5 changed files with 58 additions and 25 deletions

View File

@@ -29,7 +29,7 @@ class Expense(BaseModel):
amount: Mapped[float] = mapped_column()
created_by_user_id: Mapped[int] = mapped_column(ForeignKey("users.id"), nullable=False)
created_by_user: Mapped["User"] = relationship(foreign_keys=[created_by_user_id])
created_by_user: Mapped["User"] = relationship(foreign_keys=[created_by_user_id], lazy="selectin")
tags: Mapped[list["ExpenseTag"]] = relationship(
secondary=expenses_expense_tags,

View File

@@ -27,4 +27,5 @@ class WorkShift(BaseModel):
user: Mapped["User"] = relationship(
"User",
back_populates="work_shifts",
lazy="selectin",
)

View File

@@ -2,10 +2,9 @@ from io import BytesIO
from fastapi import APIRouter, Response
from backend.dependecies import SessionDependency, CurrentUserDependency
from backend.dependecies import SessionDependency, CurrentUserDependency, PaginationDependency
from generators.work_shifts_qr_code_generator import WorkShiftsQRCodeGenerator
from schemas.work_shifts import StartShiftResponse, FinishShiftResponse, ActiveWorkShiftsResponse, DeleteShiftResponse, \
FinishShiftByIdResponse
from schemas.work_shifts import *
from services.work_shifts import WorkShiftsService
work_shifts_router = APIRouter(
@@ -65,14 +64,16 @@ async def finish_work_shift_by_id(
@work_shifts_router.get(
"/get-active-shifts",
response_model=ActiveWorkShiftsResponse,
operation_id="get_active_shifts",
"/get-shifts/{is_active}",
response_model=GetWorkShiftsResponse,
operation_id="get_shifts",
)
async def get_active_shifts(
async def get_shifts(
session: SessionDependency,
pagination: PaginationDependency,
is_active: bool,
):
return await WorkShiftsService(session).get_active_shifts()
return await WorkShiftsService(session).get_shifts(is_active, pagination)
@work_shifts_router.delete(

View File

@@ -1,15 +1,17 @@
from datetime import datetime
from typing import List
from typing import List, Optional
from schemas.base import OkMessageSchema, BaseSchema
from schemas.base import OkMessageSchema, BaseSchema, PaginationInfoSchema
from schemas.user import UserSchema
# region Entities
class ActiveWorkShiftSchema(BaseSchema):
class WorkShiftSchema(BaseSchema):
id: int
started_at: datetime
finished_at: Optional[datetime] = None
hours: Optional[float] = None
user: UserSchema
@@ -29,8 +31,9 @@ class FinishShiftByIdResponse(OkMessageSchema):
pass
class ActiveWorkShiftsResponse(BaseSchema):
shifts: List[ActiveWorkShiftSchema]
class GetWorkShiftsResponse(BaseSchema):
shifts: List[WorkShiftSchema]
pagination_info: PaginationInfoSchema
class DeleteShiftResponse(OkMessageSchema):

View File

@@ -1,15 +1,17 @@
from datetime import datetime, date, timedelta
from datetime import date, timedelta
from sqlalchemy import select, delete
import math
from fastapi import HTTPException, status
from sqlalchemy import select, delete, func
from sqlalchemy.orm import joinedload
from models import WorkShift, User
from schemas.base import PaginationSchema
from schemas.time_tracking import UpdateTimeTrackingRecordRequest
from schemas.user import *
from schemas.work_shifts import StartShiftResponse, FinishShiftResponse, ActiveWorkShiftsResponse, DeleteShiftResponse, \
FinishShiftByIdResponse
from schemas.work_shifts import *
from services.base import BaseService
from services.time_tracking import TimeTrackingService
from utils.dependecies import is_valid_pagination
from utils.work_time import hours_to_hours_and_minutes
@@ -100,18 +102,44 @@ class WorkShiftsService(BaseService):
hours, minutes = hours_to_hours_and_minutes(hours)
return FinishShiftByIdResponse(ok=True, message=f"Смена закончена. Отработано {hours} ч. {minutes} мин.")
async def get_active_shifts(self) -> ActiveWorkShiftsResponse:
async def get_shifts(self, is_active: bool, pagination: PaginationSchema) -> GetWorkShiftsResponse:
if not is_valid_pagination(pagination):
raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail='Invalid pagination')
page = max(0, pagination.page - 1)
total_shifts = await self.session.scalar(
select(func.count())
.select_from(WorkShift)
.where(WorkShift.finished_at.is_(None) if is_active else WorkShift.finished_at.is_not(None))
)
if not total_shifts:
return GetWorkShiftsResponse(
shifts=[],
pagination_info=PaginationInfoSchema(
total_pages=0,
total_items=0
)
)
total_pages = math.ceil(total_shifts / pagination.items_per_page)
stmt = (
select(WorkShift)
.options(joinedload(WorkShift.user))
.where(WorkShift.finished_at == None)
.where(WorkShift.finished_at.is_(None) if is_active else WorkShift.finished_at.is_not(None))
.order_by(WorkShift.started_at.desc())
.offset(page * pagination.items_per_page)
.limit(pagination.items_per_page)
)
shifts = (await self.session.execute(stmt)).scalars().all()
shifts = await self.session.execute(stmt)
shifts = shifts.scalars().all()
response = ActiveWorkShiftsResponse(shifts=shifts)
return response
return GetWorkShiftsResponse(
shifts=shifts,
pagination_info=PaginationInfoSchema(
total_pages=total_pages,
total_items=total_shifts,
)
)
async def delete_shift(self, shift_id: int) -> DeleteShiftResponse:
stmt = (