improvement: a flow added for owner users to make it possible for them to participate in treatments or tasks.

This commit is contained in:
2026-07-12 15:11:50 +03:30
parent 4208d15efb
commit 39935688ad
20 changed files with 1122 additions and 154 deletions

View File

@@ -13,6 +13,9 @@ import {
type WorkingHoursBlockInput,
} from '../../common/working-hours';
import { UpsertWorkingHoursDto } from './dto/upsert-working-hours.dto';
import {
hasEffectivePermission,
} from '../../common/membership-permissions';
@Injectable()
export class StaffWorkingHoursService {
@@ -21,7 +24,7 @@ export class StaffWorkingHoursService {
async getWorkingHours(actorUserId: string, organizationId: string, membershipId: string) {
await this.assertCanViewStaff(actorUserId, organizationId);
const membership = await this.findMembership(membershipId, organizationId);
const membership = await this.findStaffMembership(membershipId, organizationId);
const schedule = await this.prisma.staffWorkingHoursSchedule.findUnique({
where: { membershipId: membership.id },
include: {
@@ -63,7 +66,62 @@ export class StaffWorkingHoursService {
) {
await this.assertCanEditStaff(actorUserId, organizationId);
const membership = await this.findMembership(membershipId, organizationId);
const membership = await this.findStaffMembership(membershipId, organizationId);
return this.persistWorkingHours(membership, organizationId, dto);
}
async getMyWorkingHours(userId: string, organizationId: string) {
const membership = await this.findOwnerMembership(userId, organizationId);
await this.assertOwnerCanManageWorkingHours(membership);
const schedule = await this.prisma.staffWorkingHoursSchedule.findUnique({
where: { membershipId: membership.id },
include: {
blocks: { orderBy: [{ dayOfWeek: 'asc' }, { sortOrder: 'asc' }, { startMinute: 'asc' }] },
},
});
if (!schedule) {
return {
success: true,
data: {
autoRepeatWeekly: true,
blocks: [],
hasWorkingHours: false,
},
};
}
return {
success: true,
data: {
autoRepeatWeekly: schedule.autoRepeatWeekly,
blocks: schedule.blocks.map((b) => ({
dayOfWeek: b.dayOfWeek,
startMinute: b.startMinute,
endMinute: b.endMinute,
sortOrder: b.sortOrder,
})),
hasWorkingHours: schedule.blocks.length > 0,
},
};
}
async upsertMyWorkingHours(
userId: string,
organizationId: string,
dto: UpsertWorkingHoursDto,
) {
const membership = await this.findOwnerMembership(userId, organizationId);
await this.assertOwnerCanManageWorkingHours(membership);
return this.persistWorkingHours(membership, organizationId, dto);
}
private async persistWorkingHours(
membership: { id: string; userId: string },
organizationId: string,
dto: UpsertWorkingHoursDto,
) {
const validationError = validateWorkingHoursBlocks(dto.blocks);
if (validationError) {
throw new BadRequestException(validationError);
@@ -205,7 +263,7 @@ export class StaffWorkingHoursService {
);
}
private async findMembership(membershipId: string, organizationId: string) {
private async findStaffMembership(membershipId: string, organizationId: string) {
const membership = await this.prisma.membership.findFirst({
where: { id: membershipId, organizationId },
select: { id: true, isOwner: true, userId: true },
@@ -219,6 +277,32 @@ export class StaffWorkingHoursService {
return membership;
}
private async findOwnerMembership(userId: string, organizationId: string) {
const membership = await this.prisma.membership.findFirst({
where: { userId, organizationId, isOwner: true },
include: {
permissions: { include: { permission: true } },
organization: { include: { type: true, plan: true } },
},
});
if (!membership) {
throw new ForbiddenException('Only organization owners can manage their working hours');
}
return membership;
}
private async assertOwnerCanManageWorkingHours(membership: {
isOwner: boolean;
permissions: { permission: { name: string } }[];
organization: { type: { name: string }; plan?: { name: string } | null; planId?: string | null };
}) {
if (!hasEffectivePermission(membership, 'TAB_TREATMENT_EDIT')) {
throw new ForbiddenException(
'Enable treatment participation before setting working hours',
);
}
}
private async assertCanViewStaff(userId: string, organizationId: string) {
const actor = await this.getActorMembership(userId, organizationId);
if (!actor || !this.canViewStaff(actor)) {