Skip to content

Commit

Permalink
Affiche le nb de congés payés restants
Browse files Browse the repository at this point in the history
  • Loading branch information
florimondmanca committed Jun 28, 2024
1 parent 26b471a commit 35072a1
Show file tree
Hide file tree
Showing 14 changed files with 184 additions and 3 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { IQuery } from 'src/Application/IQuery';
import { User } from 'src/Domain/HumanResource/User/User.entity';

export class GetLeaveRequestsOverviewQuery implements IQuery {
constructor(public readonly date: Date, public readonly user: User) {}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import { Inject } from '@nestjs/common';
import { QueryHandler } from '@nestjs/cqrs';
import { GetLeaveRequestsOverviewQuery } from './GetLeaveRequestsOverviewQuery';
import { ILeaveRequestsOverview } from 'src/Domain/HumanResource/Leave/ILeaveRequestsOverview';
import { IDateUtils } from 'src/Application/IDateUtils';
import { ILeaveRepository } from 'src/Domain/HumanResource/Leave/Repository/ILeaveRepository';

@QueryHandler(GetLeaveRequestsOverviewQuery)
export class GetLeaveRequestsOverviewQueryHandler {
constructor(
@Inject('IDateUtils')
private readonly dateUtils: IDateUtils,
@Inject('ILeaveRepository')
private readonly leaveRepository: ILeaveRepository
) {}

public async execute(
query: GetLeaveRequestsOverviewQuery
): Promise<ILeaveRequestsOverview> {
const [startDate, endDate] = this.dateUtils.getLeaveReferencePeriodDays(
query.date
);

const numDaysPerWeek = this.dateUtils.getWorkedDaysPerWeek();
const numWeeks = this.dateUtils.getNumberOfPaidLeaveWeeks();
const daysPerYear = numWeeks * numDaysPerWeek;
const totalDurationTaken = await this.leaveRepository.getSumOfDurationsBetween(
startDate,
endDate,
query.user
);
const daysTaken = this.dateUtils.getLeaveDurationAsDays(totalDurationTaken);
const daysRemaining = daysPerYear - daysTaken;

return {
daysPerYear,
daysTaken,
daysRemaining
};
}
}
4 changes: 4 additions & 0 deletions src/Application/IDateUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,17 @@ export interface IDateUtils {
getWorkedDaysDuringAPeriod(start: Date, end: Date): Date[];
isAWorkingDay(date: Date): boolean;
getWorkedFreeDays(year: number): Date[];
getWorkedDaysPerWeek(): number;
getNumberOfPaidLeaveWeeks(): number;
getEasterDate(year: number): Date;
getLeaveDuration(
startDate: string,
isStartsAllDay: boolean,
endDate: string,
isEndsAllDay: boolean
): number;
getLeaveDurationAsDays(duration: number);
getLeaveReferencePeriodDays(date: Date): [Date, Date];
addDaysToDate(date: Date, days: number): Date;
getYear(date: Date): number;
getMonth(date: Date): MonthDate;
Expand Down
5 changes: 5 additions & 0 deletions src/Domain/HumanResource/Leave/ILeaveRequestsOverview.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
export interface ILeaveRequestsOverview {
daysPerYear: number;
daysTaken: number;
daysRemaining: number;
}
5 changes: 5 additions & 0 deletions src/Domain/HumanResource/Leave/Repository/ILeaveRepository.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,9 @@ export interface ILeaveRepository {
endDate: string
): Promise<number>;
sumOfDurationLeaveByUserAndDate(user: User, date: string): Promise<number>;
getSumOfDurationsBetween(
startDate: Date,
endDate: Date,
user: User
): Promise<number>;
}
34 changes: 34 additions & 0 deletions src/Infrastructure/Adapter/DateUtilsAdapter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -207,4 +207,38 @@ export class DateUtilsAdapter implements IDateUtils {

return duration;
}

/**
* @param duration Duration in minutes
* @returns Duration in days
*/
public getLeaveDurationAsDays(duration: number) {
return duration / 420;

Check warning on line 216 in src/Infrastructure/Adapter/DateUtilsAdapter.ts

View check run for this annotation

Codecov / codecov/patch

src/Infrastructure/Adapter/DateUtilsAdapter.ts#L215-L216

Added lines #L215 - L216 were not covered by tests
}

getLeaveReferencePeriodDays(date: Date): [Date, Date] {

Check warning on line 219 in src/Infrastructure/Adapter/DateUtilsAdapter.ts

View check run for this annotation

Codecov / codecov/patch

src/Infrastructure/Adapter/DateUtilsAdapter.ts#L219

Added line #L219 was not covered by tests
// Reference period is between June 1st and May 31st.

let startDate = this.makeDate(this.getYear(date), 6, 1);

Check warning on line 222 in src/Infrastructure/Adapter/DateUtilsAdapter.ts

View check run for this annotation

Codecov / codecov/patch

src/Infrastructure/Adapter/DateUtilsAdapter.ts#L222

Added line #L222 was not covered by tests

if (startDate > date) {
startDate = this.makeDate(this.getYear(date) - 1, 6, 1);

Check warning on line 225 in src/Infrastructure/Adapter/DateUtilsAdapter.ts

View check run for this annotation

Codecov / codecov/patch

src/Infrastructure/Adapter/DateUtilsAdapter.ts#L225

Added line #L225 was not covered by tests
}

let endDate = this.makeDate(this.getYear(date), 5, 31);

Check warning on line 228 in src/Infrastructure/Adapter/DateUtilsAdapter.ts

View check run for this annotation

Codecov / codecov/patch

src/Infrastructure/Adapter/DateUtilsAdapter.ts#L228

Added line #L228 was not covered by tests

if (endDate < date) {
endDate = this.makeDate(this.getYear(date) + 1, 5, 31);

Check warning on line 231 in src/Infrastructure/Adapter/DateUtilsAdapter.ts

View check run for this annotation

Codecov / codecov/patch

src/Infrastructure/Adapter/DateUtilsAdapter.ts#L231

Added line #L231 was not covered by tests
}

return [startDate, endDate];

Check warning on line 234 in src/Infrastructure/Adapter/DateUtilsAdapter.ts

View check run for this annotation

Codecov / codecov/patch

src/Infrastructure/Adapter/DateUtilsAdapter.ts#L234

Added line #L234 was not covered by tests
}

getWorkedDaysPerWeek(): number {
return 5;

Check warning on line 238 in src/Infrastructure/Adapter/DateUtilsAdapter.ts

View check run for this annotation

Codecov / codecov/patch

src/Infrastructure/Adapter/DateUtilsAdapter.ts#L237-L238

Added lines #L237 - L238 were not covered by tests
}

getNumberOfPaidLeaveWeeks(): number {
return 7;

Check warning on line 242 in src/Infrastructure/Adapter/DateUtilsAdapter.ts

View check run for this annotation

Codecov / codecov/patch

src/Infrastructure/Adapter/DateUtilsAdapter.ts#L241-L242

Added lines #L241 - L242 were not covered by tests
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,17 @@ import { Pagination } from 'src/Application/Common/Pagination';
import { LeaveRequestView } from 'src/Application/HumanResource/Leave/View/LeaveRequestView';
import { LoggedUser } from '../../User/Decorator/LoggedUser';
import { LeaveRequestTableFactory } from '../Table/LeaveRequestTableFactory';
import { LeaveRequestsOverviewTableFactory } from '../Table/LeaveRequestOverviewTableFactory';
import { GetLeaveRequestsOverviewQuery } from 'src/Application/HumanResource/Leave/Query/GetLeaveRequestsOverviewQuery';

@Controller('app/people/leave_requests')
@UseGuards(IsAuthenticatedGuard)
export class ListLeaveRequestsController {
constructor(
@Inject('IQueryBus')
private readonly queryBus: IQueryBus,
private readonly tableFactory: LeaveRequestTableFactory
private readonly tableFactory: LeaveRequestTableFactory,
private readonly overviewTableFactory: LeaveRequestsOverviewTableFactory
) {}

@Get()
Expand All @@ -39,6 +42,16 @@ export class ListLeaveRequestsController {

const table = this.tableFactory.create(pagination.items, user.getId());

return { table, pagination, currentPage: paginationDto.page };
const overview = await this.queryBus.execute(
new GetLeaveRequestsOverviewQuery(new Date(), user)
);
const overviewTable = this.overviewTableFactory.create(overview);

return {
table,
overviewTable,
pagination,
currentPage: paginationDto.page
};
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { ILeaveRepository } from 'src/Domain/HumanResource/Leave/Repository/ILea
import { Leave } from 'src/Domain/HumanResource/Leave/Leave.entity';
import { User, UserRole } from 'src/Domain/HumanResource/User/User.entity';
import { IDateUtils } from 'src/Application/IDateUtils';
import { Type } from 'src/Domain/HumanResource/Leave/LeaveRequest.entity';

export class LeaveRepository implements ILeaveRepository {
constructor(
Expand Down Expand Up @@ -68,4 +69,23 @@ export class LeaveRepository implements ILeaveRepository {

return Number(result.time) || 0;
}

public async getSumOfDurationsBetween(
startDate: Date,
endDate: Date,
user: User

Check warning on line 76 in src/Infrastructure/HumanResource/Leave/Repository/LeaveRepository.ts

View check run for this annotation

Codecov / codecov/patch

src/Infrastructure/HumanResource/Leave/Repository/LeaveRepository.ts#L76

Added line #L76 was not covered by tests
): Promise<number> {
const result = await this.repository

Check warning on line 78 in src/Infrastructure/HumanResource/Leave/Repository/LeaveRepository.ts

View check run for this annotation

Codecov / codecov/patch

src/Infrastructure/HumanResource/Leave/Repository/LeaveRepository.ts#L78

Added line #L78 was not covered by tests
.createQueryBuilder('leave')
.select('SUM(leave.time) as time')
.innerJoin('leave.leaveRequest', 'leaveRequest')
.innerJoin('leaveRequest.user', 'user')
.where('leave.date >= :startDate', { startDate })
.andWhere('leave.date < :endDate', { endDate })
.andWhere('leaveRequest.type = :type', { type: Type.PAID })
.andWhere('user.id = :user', { user: user.getId() })
.getRawOne();

return Number(result.time) || 0;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { Injectable } from '@nestjs/common';
import { ILeaveRequestsOverview } from 'src/Domain/HumanResource/Leave/ILeaveRequestsOverview';
import { Table } from 'src/Infrastructure/Tables';
import { RowFactory } from 'src/Infrastructure/Tables/RowFactory';

@Injectable()
export class LeaveRequestsOverviewTableFactory {
constructor(private rowFactory: RowFactory) {}

public create(overview: ILeaveRequestsOverview): Table {
const columns = [];
const rowBuilder = this.rowFactory.createBuilder();

for (const type in overview) {
columns.push(`leaves-overview-${type}`);
rowBuilder.template('pages/leave_requests/_overview_badge.njk', {
type,
days: overview[type]
});
}

const row = rowBuilder.build();

return new Table(columns, [row]);
}
}
4 changes: 4 additions & 0 deletions src/Infrastructure/HumanResource/humanResource.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,8 @@ import { ListMealTicketsController } from './MealTicket/Controller/ListMealTicke
import { MealTicketTableFactory } from './MealTicket/Table/MealTicketTableFactory';
import { AddMealTicketRemovalController } from './MealTicket/Controller/AddMealTicketRemovalController';
import { ExportLeavesCalendarController } from './Leave/Controller/ExportLeavesCalendarController';
import { LeaveRequestsOverviewTableFactory } from './Leave/Table/LeaveRequestOverviewTableFactory';
import { GetLeaveRequestsOverviewQueryHandler } from 'src/Application/HumanResource/Leave/Query/GetLeaveRequestsOverviewQueryHandler';

@Module({
imports: [
Expand Down Expand Up @@ -181,6 +183,8 @@ import { ExportLeavesCalendarController } from './Leave/Controller/ExportLeavesC
IncreaseUserSavingsRecordCommandHandler,
UserTableFactory,
LeaveRequestTableFactory,
GetLeaveRequestsOverviewQueryHandler,
LeaveRequestsOverviewTableFactory,
PayrollElementsTableFactory,
MealTicketTableFactory
]
Expand Down
9 changes: 9 additions & 0 deletions src/assets/styles/variables.css
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,15 @@
--event-other-border: rgb(244, 245, 247);
--event-other-text: rgb(36, 38, 45);
--event-today: #fcf8e3;
--leave-daysPerYear-background: rgb(244, 245, 247);
--leave-daysPerYear-border: rgb(244, 245, 247);
--leave-daysPerYear-text: rgb(36, 38, 45);
--leave-daysTaken-background: rgb(253, 246, 178);
--leave-daysTaken-border: rgb(253, 246, 178);
--leave-daysTaken-text: rgb(142, 75, 16);
--leave-daysRemaining-background: rgb(222, 247, 236);
--leave-daysRemaining-border: rgb(222, 247, 236);
--leave-daysRemaining-text: rgb(4, 108, 78);
--header-height-desktop: 56px;
}

Expand Down
3 changes: 3 additions & 0 deletions src/templates/pages/leave_requests/_overview_badge.njk
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
<span class="pc-badge pc-bold" style="--badge-color: var(--leave-{{ type }}-text); --badge-background: var(--leave-{{ type }}-background)">
{{ 'leaves-overview-days'|trans({ days: days }) }}
</span>
5 changes: 4 additions & 1 deletion src/templates/pages/leave_requests/list.njk
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,10 @@
{{ links.add(path('people_leave_requests_add'), text='leave-requests-add-title'|trans) }}
</div>

{% table table %}
<div class="pc-stack">
{% table overviewTable, { attr: {class: 'pc-table--center pc-table--no-shadow'} } %}
{% table table %}
</div>

{% set paginationUrl = path('people_leave_requests_list') %}
{% include 'includes/pagination.njk' %}
Expand Down
8 changes: 8 additions & 0 deletions src/translations/fr-FR.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,14 @@ leave-requests-delete-yes = Oui, annuler
leave-requests-delete-no = Non, ne pas annuler
leaves-calendar-url-title = Lien d'abonnement au calendrier
leaves-overview-daysPerYear = Congés payés par an
leaves-overview-daysTaken = Congés payés pris
leaves-overview-daysRemaining = Congés payés restants (estimation)
leaves-overview-days = {$days ->
[0] 0
[1] 1 jour
*[other] {$days} jours
}
payroll-elements-title = Éléments de paie
payroll-elements-page-title = Éléments de paie {DATETIME($date, month: "long", year: "numeric")}
Expand Down

0 comments on commit 35072a1

Please sign in to comment.