feat: time tracking in minutes
This commit is contained in:
		@@ -47,5 +47,5 @@ class PaymentRecord(BaseModel):
 | 
				
			|||||||
    payroll_scheme_key: Mapped[int] = mapped_column(ForeignKey("payroll_schemas.key"), nullable=False)
 | 
					    payroll_scheme_key: Mapped[int] = mapped_column(ForeignKey("payroll_schemas.key"), nullable=False)
 | 
				
			||||||
    payroll_scheme: Mapped["PayrollScheme"] = relationship()
 | 
					    payroll_scheme: Mapped["PayrollScheme"] = relationship()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    work_units: Mapped[int] = mapped_column(nullable=False)
 | 
					    work_units: Mapped[float] = mapped_column(nullable=False)
 | 
				
			||||||
    amount: Mapped[float] = mapped_column(Double, nullable=False)
 | 
					    amount: Mapped[float] = mapped_column(Double, nullable=False)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -11,7 +11,7 @@ class PaymentRecordSchemaBase(BaseSchema):
 | 
				
			|||||||
    start_date: datetime.date
 | 
					    start_date: datetime.date
 | 
				
			||||||
    end_date: datetime.date
 | 
					    end_date: datetime.date
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    work_units: int
 | 
					    work_units: float
 | 
				
			||||||
    user: UserSchema
 | 
					    user: UserSchema
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -23,7 +23,7 @@ class PaymentRecordGetSchema(PaymentRecordSchemaBase):
 | 
				
			|||||||
    id: int
 | 
					    id: int
 | 
				
			||||||
    created_by_user: UserSchema
 | 
					    created_by_user: UserSchema
 | 
				
			||||||
    payroll_scheme: PayrollSchemeSchema
 | 
					    payroll_scheme: PayrollSchemeSchema
 | 
				
			||||||
    amount: int
 | 
					    amount: float
 | 
				
			||||||
    created_at: datetime.datetime
 | 
					    created_at: datetime.datetime
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -8,13 +8,13 @@ from schemas.user import UserSchema
 | 
				
			|||||||
# region Entities
 | 
					# region Entities
 | 
				
			||||||
class TimeTrackingData(BaseSchema):
 | 
					class TimeTrackingData(BaseSchema):
 | 
				
			||||||
    date: datetime.date
 | 
					    date: datetime.date
 | 
				
			||||||
    hours: int
 | 
					    hours: float
 | 
				
			||||||
    amount: int
 | 
					    amount: float
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class TimeTrackingRecord(BaseSchema):
 | 
					class TimeTrackingRecord(BaseSchema):
 | 
				
			||||||
    user: UserSchema
 | 
					    user: UserSchema
 | 
				
			||||||
    total_amount: int
 | 
					    total_amount: float
 | 
				
			||||||
    data: List[TimeTrackingData]
 | 
					    data: List[TimeTrackingData]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -30,7 +30,7 @@ class GetTimeTrackingRecordsRequest(BaseSchema):
 | 
				
			|||||||
class UpdateTimeTrackingRecordRequest(BaseSchema):
 | 
					class UpdateTimeTrackingRecordRequest(BaseSchema):
 | 
				
			||||||
    user_id: int
 | 
					    user_id: int
 | 
				
			||||||
    date: datetime.date
 | 
					    date: datetime.date
 | 
				
			||||||
    hours: int
 | 
					    hours: float
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# endregion
 | 
					# endregion
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -170,7 +170,7 @@ class PayrollService(BaseService):
 | 
				
			|||||||
    def get_amount(
 | 
					    def get_amount(
 | 
				
			||||||
            self,
 | 
					            self,
 | 
				
			||||||
            user: User,
 | 
					            user: User,
 | 
				
			||||||
            work_units: int
 | 
					            work_units: float
 | 
				
			||||||
    ):
 | 
					    ):
 | 
				
			||||||
        pay_rate: PayRate = user.pay_rate
 | 
					        pay_rate: PayRate = user.pay_rate
 | 
				
			||||||
        overtime_threshold = 0
 | 
					        overtime_threshold = 0
 | 
				
			||||||
@@ -185,7 +185,7 @@ class PayrollService(BaseService):
 | 
				
			|||||||
            base_units = work_units
 | 
					            base_units = work_units
 | 
				
			||||||
            overtime_units = 0
 | 
					            overtime_units = 0
 | 
				
			||||||
        else:
 | 
					        else:
 | 
				
			||||||
            overtime_units = max(0, work_units - overtime_threshold)
 | 
					            overtime_units = max(0.0, work_units - overtime_threshold)
 | 
				
			||||||
            base_units = work_units - overtime_units
 | 
					            base_units = work_units - overtime_units
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return pay_rate.base_rate * base_units + overtime_rate * overtime_units
 | 
					        return pay_rate.base_rate * base_units + overtime_rate * overtime_units
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -10,6 +10,7 @@ from schemas.work_shifts import StartShiftResponse, FinishShiftResponse, ActiveW
 | 
				
			|||||||
    FinishShiftByIdResponse
 | 
					    FinishShiftByIdResponse
 | 
				
			||||||
from services.base import BaseService
 | 
					from services.base import BaseService
 | 
				
			||||||
from services.time_tracking import TimeTrackingService
 | 
					from services.time_tracking import TimeTrackingService
 | 
				
			||||||
 | 
					from utils.work_time import hours_to_hours_and_minutes
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class WorkShiftsService(BaseService):
 | 
					class WorkShiftsService(BaseService):
 | 
				
			||||||
@@ -59,7 +60,7 @@ class WorkShiftsService(BaseService):
 | 
				
			|||||||
        await self.session.commit()
 | 
					        await self.session.commit()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        diff: timedelta = work_shift.finished_at - work_shift.started_at
 | 
					        diff: timedelta = work_shift.finished_at - work_shift.started_at
 | 
				
			||||||
        hours = int(diff.total_seconds() // 3600)
 | 
					        hours = diff.total_seconds() / 3600
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        data = UpdateTimeTrackingRecordRequest(
 | 
					        data = UpdateTimeTrackingRecordRequest(
 | 
				
			||||||
            user_id=user_id,
 | 
					            user_id=user_id,
 | 
				
			||||||
@@ -68,7 +69,8 @@ class WorkShiftsService(BaseService):
 | 
				
			|||||||
        )
 | 
					        )
 | 
				
			||||||
        await TimeTrackingService(self.session).update_record(user, data)
 | 
					        await TimeTrackingService(self.session).update_record(user, data)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return FinishShiftResponse(ok=True, message=f"Смена закончена. Отработано {hours} ч.")
 | 
					        hours, minutes = hours_to_hours_and_minutes(hours)
 | 
				
			||||||
 | 
					        return FinishShiftResponse(ok=True, message=f"Смена закончена. Отработано {hours} ч. {minutes} мин.")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    async def finish_shift_by_id(self, user: User, shift_id: int) -> FinishShiftByIdResponse:
 | 
					    async def finish_shift_by_id(self, user: User, shift_id: int) -> FinishShiftByIdResponse:
 | 
				
			||||||
        work_shift = await self.session.get(WorkShift, shift_id)
 | 
					        work_shift = await self.session.get(WorkShift, shift_id)
 | 
				
			||||||
@@ -80,7 +82,7 @@ class WorkShiftsService(BaseService):
 | 
				
			|||||||
        await self.session.commit()
 | 
					        await self.session.commit()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        diff: timedelta = work_shift.finished_at - work_shift.started_at
 | 
					        diff: timedelta = work_shift.finished_at - work_shift.started_at
 | 
				
			||||||
        hours = int(diff.total_seconds() // 3600)
 | 
					        hours = diff.total_seconds() / 3600
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        data = UpdateTimeTrackingRecordRequest(
 | 
					        data = UpdateTimeTrackingRecordRequest(
 | 
				
			||||||
            user_id=work_shift.user_id,
 | 
					            user_id=work_shift.user_id,
 | 
				
			||||||
@@ -89,7 +91,8 @@ class WorkShiftsService(BaseService):
 | 
				
			|||||||
        )
 | 
					        )
 | 
				
			||||||
        await TimeTrackingService(self.session).update_record(user, data)
 | 
					        await TimeTrackingService(self.session).update_record(user, data)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return FinishShiftByIdResponse(ok=True, message=f"Смена закончена. Отработано {hours} ч.")
 | 
					        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_active_shifts(self) -> ActiveWorkShiftsResponse:
 | 
				
			||||||
        stmt = (
 | 
					        stmt = (
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										7
									
								
								utils/work_time.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								utils/work_time.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,7 @@
 | 
				
			|||||||
 | 
					from math import floor
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def hours_to_hours_and_minutes(hours: float) -> tuple[int, int]:
 | 
				
			||||||
 | 
					    res_hours = int(floor(hours))
 | 
				
			||||||
 | 
					    minutes = int(round((hours - res_hours) * 60))
 | 
				
			||||||
 | 
					    return res_hours, minutes
 | 
				
			||||||
		Reference in New Issue
	
	Block a user