TSK-791: Handle department's public holidays + add stats for it (#2735)

Signed-off-by: Vyacheslav Tumanov <me@slavatumanov.me>
This commit is contained in:
Vyacheslav Tumanov 2023-03-16 09:20:11 +05:00 committed by GitHub
parent 0b5e7858eb
commit 6c18d7e474
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 336 additions and 83 deletions

View File

@ -13,17 +13,18 @@
// limitations under the License.
-->
<script lang="ts">
import hr, { Request, RequestType } from '@hcengineering/hr'
import hr, { Department, Request, RequestType, Staff } from '@hcengineering/hr'
import { getClient } from '@hcengineering/presentation'
import { closeTooltip, getPlatformColor, Icon, isWeekend, showPopup } from '@hcengineering/ui'
import { ContextMenu } from '@hcengineering/view-resources'
import { isHoliday } from '../utils'
import { getHolidayDatesForEmployee, isHoliday } from '../utils'
import { Ref } from '@hcengineering/core'
export let requests: Request[]
export let date: Date
export let editable: boolean = false
export let holidays: Date[] | undefined
export let holidays: Map<Ref<Department>, Date[]>
export let employee: Staff
const client = getClient()
export let noWeekendHolidayType: Ref<RequestType>[]
@ -51,12 +52,13 @@
closeTooltip()
showPopup(ContextMenu, { object: request }, e.target as HTMLElement)
}
export let staffDepartmentMap: Map<Ref<Staff>, Department[]>
</script>
<div class="w-full h-full relative p-1 flex">
{#each requests as request}
{#await getType(request) then type}
{#if type && !(isWeekend(date) || (isHoliday(holidays, date) && noWeekendHolidayType.includes(type._id)))}
{#if type && !(isWeekend(date) || (isHoliday(getHolidayDatesForEmployee(staffDepartmentMap, employee._id, holidays), date) && noWeekendHolidayType.includes(type._id)))}
<!-- svelte-ignore a11y-click-events-have-key-events -->
<div
class="request flex-center"

View File

@ -17,7 +17,7 @@
import { Employee, EmployeeAccount } from '@hcengineering/contact'
import { DocumentQuery, getCurrentAccount, Ref } from '@hcengineering/core'
import { Department, fromTzDate, Request, RequestType, Staff } from '@hcengineering/hr'
import { createQuery } from '@hcengineering/presentation'
import { createQuery, getClient } from '@hcengineering/presentation'
import tracker, { Issue } from '@hcengineering/tracker'
import { Label } from '@hcengineering/ui'
import hr from '../plugin'
@ -25,6 +25,8 @@
import MonthTableView from './schedule/MonthTableView.svelte'
import MonthView from './schedule/MonthView.svelte'
import YearView from './schedule/YearView.svelte'
import { groupBy } from '@hcengineering/view-resources'
import contact from '@hcengineering/contact-resources/src/plugin'
export let department: Ref<Department>
export let descendants: Map<Ref<Department>, Department[]>
@ -221,7 +223,7 @@
}
}
)
let holidays: Date[] | undefined = undefined
let holidays: Map<Ref<Department>, Date[]> = new Map()
const holidaysQuery = createQuery()
$: holidaysQuery.query(
hr.class.PublicHoliday,
@ -230,32 +232,85 @@
'date.year': currentDate.getFullYear()
},
(res) => {
holidays = res.map((holiday) => new Date(fromTzDate(holiday.date)))
const group = groupBy(res, 'department')
holidays = new Map()
for (const groupKey in group) {
holidays.set(
groupKey,
group[groupKey].map((holiday) => new Date(fromTzDate(holiday.date)))
)
}
}
)
async function getHolidays (month: Date): Promise<Map<Ref<Department>, Date[]>> {
const result = await client.findAll(hr.class.PublicHoliday, {
'date.month': month.getMonth(),
'date.year': month.getFullYear()
})
const group = groupBy(result, 'department')
const rMap = new Map()
for (const groupKey in group) {
rMap.set(
groupKey,
group[groupKey].map((holiday) => new Date(fromTzDate(holiday.date)))
)
}
return rMap
}
const client = getClient()
async function getDepartmentsForEmployee (departmentStaff: Staff[]): Promise<Map<Ref<Staff>, Department[]>> {
const map = new Map<Ref<Staff>, Department[]>()
if (departmentStaff && departmentStaff.length > 0) {
const ids = departmentStaff.map((staff) => staff._id)
const staffs = await client.findAll(contact.class.EmployeeAccount, { employee: { $in: ids } })
const departments = await client.findAll(hr.class.Department, {
members: { $in: staffs.map((staff) => staff._id) }
})
staffs.forEach((staff) => {
const filteredDepartments = departments.filter((department) => department.members.includes(staff._id))
map.set(staff.employee as Ref<Staff>, filteredDepartments as Department[])
})
}
return map
}
</script>
{#if departmentStaff.length}
{#if mode === CalendarMode.Year}
<YearView {departmentStaff} {employeeRequests} {types} {currentDate} {holidays} />
{:else if mode === CalendarMode.Month}
{#if display === 'chart'}
<MonthView
{departmentStaff}
{employeeRequests}
{types}
{startDate}
{endDate}
{editableList}
{currentDate}
{timeReports}
{holidays}
{department}
/>
{:else if display === 'stats'}
<MonthTableView {departmentStaff} {employeeRequests} {types} {currentDate} {timeReports} {holidays} />
{#await getDepartmentsForEmployee(departmentStaff) then staffDepartmentMap}
{#if mode === CalendarMode.Year}
<YearView {departmentStaff} {employeeRequests} {types} {currentDate} {holidays} {staffDepartmentMap} />
{:else if mode === CalendarMode.Month}
{#if display === 'chart'}
<MonthView
{departmentStaff}
{employeeRequests}
{types}
{startDate}
{endDate}
{editableList}
{currentDate}
{timeReports}
{holidays}
{department}
{staffDepartmentMap}
/>
{:else if display === 'stats'}
<MonthTableView
{departmentStaff}
{employeeRequests}
{types}
{currentDate}
{timeReports}
{holidays}
{staffDepartmentMap}
{getHolidays}
/>
{/if}
{/if}
{/if}
{/await}
{:else}
<div class="flex-center h-full w-full flex-grow fs-title">
<Label label={hr.string.NoEmployeesInDepartment} />

View File

@ -13,8 +13,8 @@
// limitations under the License.
-->
<script lang="ts">
import presentation, { Card, getClient } from '@hcengineering/presentation'
import { Button, DateRangePresenter, EditBox } from '@hcengineering/ui'
import presentation, { Card, getClient, SpaceSelector } from '@hcengineering/presentation'
import { Button, DateRangePresenter, EditBox, Label } from '@hcengineering/ui'
import hr from '../../plugin'
import core, { Data, Ref } from '@hcengineering/core'
import { toTzDate, PublicHoliday, Department } from '@hcengineering/hr'
@ -33,6 +33,7 @@
if (existingHoliday !== undefined) {
title = existingHoliday.title
description = existingHoliday.description
department = existingHoliday.department
}
}
@ -76,6 +77,10 @@
<div class="flex-grow mt-4">
<DateRangePresenter bind:value={date} />
</div>
<svelte:fragment slot="pool">
<Label label={hr.string.Department} />
<SpaceSelector _class={hr.class.Department} label={hr.string.ParentDepartmentLabel} bind:space={department} />
</svelte:fragment>
<svelte:fragment slot="buttons">
{#if existingHoliday}
<Button label={presentation.string.Remove} kind="transparent" on:click={() => deleteHoliday()} />

View File

@ -0,0 +1,27 @@
<!--
// Copyright © 2023 Hardcore Engineering Inc.
//
// Licensed under the Eclipse Public License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License. You may
// obtain a copy of the License at https://www.eclipse.org/legal/epl-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//
// See the License for the specific language governing permissions and
// limitations under the License.
-->
<script lang="ts">
import { Staff } from '@hcengineering/hr'
export let value: Staff
export let month: Date
export let display: (staff: Staff, month: Date) => number | string
// $: _value = display(value)
</script>
{#await display(value, month) then _value}
<span class="select-text flex lines-limit-2">{_value}</span>
{/await}

View File

@ -30,6 +30,7 @@
import hr from '../../plugin'
import {
EmployeeReports,
getHolidayDatesForEmployee,
getEndDate,
getMonth,
getRequestDates,
@ -41,6 +42,8 @@
} from '../../utils'
import StatPresenter from './StatPresenter.svelte'
import ReportPresenter from './ReportPresenter.svelte'
import HolidayPresenter from './HolidayPresenter.svelte'
import { Department } from '@hcengineering/hr'
export let currentDate: Date = new Date()
@ -49,13 +52,21 @@
export let employeeRequests: Map<Ref<Staff>, Request[]>
export let timeReports: Map<Ref<Employee>, EmployeeReports>
export let holidays: Date[] | undefined = undefined
export let holidays: Map<Ref<Department>, Date[]> = new Map<Ref<Department>, Date[]>()
export let getHolidays: (month: Date) => Promise<Map<Ref<Department>, Date[]>>
$: month = getStartDate(currentDate.getFullYear(), currentDate.getMonth()) // getMonth(currentDate, currentDate.getMonth())
$: wDays = weekDays(month.getFullYear(), month.getMonth())
function getDateRange (request: Request): string {
const ds = getRequestDates(request, types, month.getFullYear(), month.getMonth(), holidays)
export let staffDepartmentMap: Map<Ref<Staff>, Department[]>
function getDateRange (request: Request, staff: Staff): string {
const ds = getRequestDates(
request,
types,
month.getFullYear(),
month.getMonth(),
getHolidayDatesForEmployee(staffDepartmentMap, staff._id, holidays)
)
return ds.join(' ')
}
@ -75,10 +86,10 @@
presenter: StatPresenter,
props: {
month: month ?? getStartDate(currentDate.getFullYear(), currentDate.getMonth()),
display: (req: Request[]) =>
display: (req: Request[], staff: Staff) =>
req
.filter((r) => r.type === it._id)
.map((it) => getDateRange(it))
.map((it) => getDateRange(it, staff))
.join(' '),
getStatRequests
}
@ -87,7 +98,8 @@
)
}
function getOverrideConfig (startDate: Date): Map<string, BuildModelKey> {
async function getOverrideConfig (startDate: Date): Promise<Map<string, BuildModelKey>> {
const holidays = await getHolidays(startDate)
const typevals = getTypeVals(startDate)
const endDate = getEndDate(startDate.getFullYear(), startDate.getMonth())
@ -111,13 +123,29 @@
presenter: StatPresenter,
props: {
month: startDate ?? getStartDate(currentDate.getFullYear(), currentDate.getMonth()),
display: (req: Request[]) => wDays + getTotal(req, startDate, endDate, types, holidays),
display: (req: Request[], staff: Staff) => {
const dates = getHolidayDatesForEmployee(staffDepartmentMap, staff._id, holidays)
const total = getTotal(req, startDate, endDate, types, dates)
return wDays + total - dates.length
},
getStatRequests
},
sortingKey: '@wdCount',
sortingFunction: (a: Doc, b: Doc) =>
getTotal(getStatRequests(b._id as Ref<Staff>, startDate), startDate, endDate, types, holidays) -
getTotal(getStatRequests(a._id as Ref<Staff>, startDate), startDate, endDate, types, holidays)
getTotal(
getStatRequests(b._id as Ref<Staff>, startDate),
startDate,
endDate,
types,
getHolidayDatesForEmployee(staffDepartmentMap, b._id as Ref<Staff>, holidays)
) -
getTotal(
getStatRequests(a._id as Ref<Staff>, startDate),
startDate,
endDate,
types,
getHolidayDatesForEmployee(staffDepartmentMap, a._id as Ref<Staff>, holidays)
)
}
],
[
@ -134,6 +162,22 @@
sortingFunction: (a: Doc, b: Doc) => getReport(b._id).value - getReport(a._id).value
}
],
[
'@wdCountPublicHolidays',
{
key: '',
label: getEmbeddedLabel('Public holidays'),
presenter: ReportPresenter,
props: {
month: startDate ?? getStartDate(currentDate.getFullYear(), currentDate.getMonth()),
display: (staff: Staff) => getHolidayDatesForEmployee(staffDepartmentMap, staff._id, holidays).length
},
sortingKey: '@wdCountPublicHolidays',
sortingFunction: (a: Doc, b: Doc) =>
getHolidayDatesForEmployee(staffDepartmentMap, b._id as Ref<Staff>, holidays).length -
getHolidayDatesForEmployee(staffDepartmentMap, a._id as Ref<Staff>, holidays).length
}
],
[
'@wdTaskCountReported',
{
@ -170,17 +214,34 @@
presenter: StatPresenter,
props: {
month: startDate ?? getMonth(currentDate, currentDate.getMonth()),
display: (req: Request[]) =>
getTotal(req, startDate, endDate, types, holidays, (a) => (a < 0 ? Math.abs(a) : 0)),
display: (req: Request[], staff: Staff) =>
getTotal(
req,
startDate,
endDate,
types,
getHolidayDatesForEmployee(staffDepartmentMap, staff._id, holidays),
(a) => (a < 0 ? Math.abs(a) : 0)
),
getStatRequests
},
sortingKey: '@ptoCount',
sortingFunction: (a: Doc, b: Doc) =>
getTotal(getStatRequests(b._id as Ref<Staff>, startDate), startDate, endDate, types, holidays, (a) =>
a < 0 ? Math.abs(a) : 0
getTotal(
getStatRequests(b._id as Ref<Staff>, startDate),
startDate,
endDate,
types,
getHolidayDatesForEmployee(staffDepartmentMap, b._id as Ref<Staff>, holidays),
(a) => (a < 0 ? Math.abs(a) : 0)
) -
getTotal(getStatRequests(a._id as Ref<Staff>, startDate), startDate, endDate, types, holidays, (a) =>
a < 0 ? Math.abs(a) : 0
getTotal(
getStatRequests(a._id as Ref<Staff>, startDate),
startDate,
endDate,
types,
getHolidayDatesForEmployee(staffDepartmentMap, a._id as Ref<Staff>, holidays),
(a) => (a < 0 ? Math.abs(a) : 0)
)
}
],
@ -192,20 +253,52 @@
presenter: StatPresenter,
props: {
month: startDate ?? getMonth(currentDate, currentDate.getMonth()),
display: (req: Request[]) =>
getTotal(req, startDate, endDate, types, holidays, (a) => (a > 0 ? Math.abs(a) : 0)),
display: (req: Request[], staff: Staff) =>
getTotal(
req,
startDate,
endDate,
types,
getHolidayDatesForEmployee(staffDepartmentMap, staff._id, holidays),
(a) => (a > 0 ? Math.abs(a) : 0)
),
getStatRequests
},
sortingKey: '@extraCount',
sortingFunction: (a: Doc, b: Doc) =>
getTotal(getStatRequests(b._id as Ref<Staff>, startDate), startDate, endDate, types, holidays, (a) =>
a > 0 ? Math.abs(a) : 0
getTotal(
getStatRequests(b._id as Ref<Staff>, startDate),
startDate,
endDate,
types,
getHolidayDatesForEmployee(staffDepartmentMap, b._id as Ref<Staff>, holidays),
(a) => (a > 0 ? Math.abs(a) : 0)
) -
getTotal(getStatRequests(a._id as Ref<Staff>, startDate), startDate, endDate, types, holidays, (a) =>
a > 0 ? Math.abs(a) : 0
getTotal(
getStatRequests(a._id as Ref<Staff>, startDate),
startDate,
endDate,
types,
getHolidayDatesForEmployee(staffDepartmentMap, a._id as Ref<Staff>, holidays),
(a) => (a > 0 ? Math.abs(a) : 0)
)
}
],
[
'@publicHoliday',
{
key: '',
label: getEmbeddedLabel('Public holiday'),
presenter: HolidayPresenter,
props: {
month: startDate ?? getMonth(currentDate, currentDate.getMonth()),
display: async (staff: Staff, month: Date) =>
getHolidayDatesForEmployee(staffDepartmentMap, staff._id, await getHolidays(month))
.map((date) => date.getDate())
.join(' ')
}
}
],
...typevals
])
}
@ -245,14 +338,14 @@
})
}
function createConfig (
async function createConfig (
descr: Viewlet,
preference: ViewletPreference | undefined,
month: Date
): (string | BuildModelKey)[] {
): Promise<(string | BuildModelKey)[]> {
const base = preference?.config ?? descr.config
const result: (string | BuildModelKey)[] = []
const overrideConfig = getOverrideConfig(month)
const overrideConfig = await getOverrideConfig(month)
for (const key of [...base, ...overrideConfig.values()]) {
if (typeof key === 'string') {
@ -298,13 +391,15 @@
}}
/>
</div>
<Table
tableId={'exportableData'}
_class={hr.mixin.Staff}
query={{ _id: { $in: departmentStaff.map((it) => it._id) } }}
config={createConfig(descr, preference, month)}
options={descr.options}
/>
{#await createConfig(descr, preference, month) then config}
<Table
tableId={'exportableData'}
_class={hr.mixin.Staff}
query={{ _id: { $in: departmentStaff.map((it) => it._id) } }}
{config}
options={descr.options}
/>
{/await}
{/if}
{/if}
</div>

View File

@ -35,7 +35,7 @@
tooltip
} from '@hcengineering/ui'
import hr from '../../plugin'
import { EmployeeReports, getRequests, getTotal } from '../../utils'
import { EmployeeReports, getHolidayDatesForEmployee, getRequests, getTotal, isHoliday } from '../../utils'
import CreateRequest from '../CreateRequest.svelte'
import RequestsPopup from '../RequestsPopup.svelte'
import ScheduleRequests from '../ScheduleRequests.svelte'
@ -81,9 +81,16 @@
const noWeekendHolidayType: Ref<RequestType>[] = [hr.ids.PTO, hr.ids.PTO2, hr.ids.Vacation]
function getTooltip (requests: Request[], day: Date): LabelAndProps | undefined {
function getTooltip (requests: Request[], day: Date, staff: Staff): LabelAndProps | undefined {
if (requests.length === 0) return
if (day && isWeekend(day) && requests.some((req) => noWeekendHolidayType.includes(req.type))) return
if (
day &&
(isWeekend(day) ||
(holidays?.size > 0 && isHoliday(getHolidayDatesForEmployee(staffDepartmentMap, staff._id, holidays), day))) &&
requests.some((req) => noWeekendHolidayType.includes(req.type))
) {
return
}
return {
component: RequestsPopup,
props: { requests: requests.map((it) => it._id) }
@ -124,10 +131,8 @@
showPopup(CreatePublicHoliday, { date, department })
}
export let holidays: Date[] | undefined = undefined
function isHoliday (holidays: Date[], day: Date): boolean {
return holidays && holidays.some((date) => areDatesEqual(day, date))
}
export let staffDepartmentMap: Map<Ref<Staff>, Department[]>
export let holidays: Map<Ref<Department>, Date[]>
</script>
{#if departmentStaff.length}
@ -144,7 +149,7 @@
{@const day = getDay(startDate, value)}
<th
class:today={areDatesEqual(todayDate, day)}
class:holiday={isHoliday(holidays, day)}
class:holiday={isHoliday([...holidays.values()].flat(), day)}
class:weekend={isWeekend(day)}
class:hoveredCell={hoveredColumn === i}
on:mousemove={() => {
@ -174,7 +179,13 @@
class:firstLine={row === 0}
class:lastLine={row === departmentStaff.length - 1}
>
{getTotal(requests, startDate, endDate, types, holidays)}
{getTotal(
requests,
startDate,
endDate,
types,
getHolidayDatesForEmployee(staffDepartmentMap, employee._id, holidays)
)}
</td>
<!-- svelte-ignore a11y-click-events-have-key-events -->
<td
@ -192,14 +203,16 @@
{@const day = getDay(startDate, value)}
{@const requests = getRequests(employeeRequests, day, day, employee._id)}
{@const editable = isEditable(employee)}
{@const tooltipValue = getTooltip(requests)}
{@const tooltipValue = getTooltip(requests, day, employee)}
{@const ww = findReports(employee, day, timeReports)}
{#key [tooltipValue, editable]}
<!-- svelte-ignore a11y-click-events-have-key-events -->
<td
class="w-9 max-w-9 min-w-9"
class:today={areDatesEqual(todayDate, day)}
class:weekend={isWeekend(day) || isHoliday(holidays, day)}
class:holiday={isHoliday(getHolidayDatesForEmployee(staffDepartmentMap, employee._id, holidays), day)}
class:weekend={isWeekend(day) ||
isHoliday(getHolidayDatesForEmployee(staffDepartmentMap, employee._id, holidays), day)}
class:cursor-pointer={editable}
class:hovered={i === hoveredIndex}
class:firstLine={row === 0}
@ -215,7 +228,15 @@
>
<div class:worked={ww > 0} class="h-full w-full">
{#if requests.length}
<ScheduleRequests {requests} {editable} date={day} {holidays} {noWeekendHolidayType} />
<ScheduleRequests
{requests}
{editable}
date={day}
{noWeekendHolidayType}
{holidays}
{employee}
{staffDepartmentMap}
/>
{/if}
</div>
</td>
@ -230,7 +251,13 @@
<Label label={hr.string.Summary} />
</td>
<td class="flex-center p-1 whitespace-nowrap text-center summary">
{getTotal(Array.from(employeeRequests.values()).flat(), startDate, endDate, types, holidays)}
{getTotal(
Array.from(employeeRequests.values()).flat(),
startDate,
endDate,
types,
[...holidays.values()].flat()
)}
</td>
<td class="p-1 text-center summary">
{floorFractionDigits(
@ -242,11 +269,10 @@
</td>
{#each values as value, i}
{@const day = getDay(startDate, value)}
{@const requests = getRequests(employeeRequests, day)}
<td
class="p-1 text-center summary"
class:hovered={i === hoveredIndex}
class:weekend={isWeekend(day) || isHoliday(holidays, day)}
class:weekend={isWeekend(day)}
class:today={areDatesEqual(todayDate, day)}
on:mousemove={() => {
hoveredColumn = i
@ -255,7 +281,7 @@
hoveredColumn = -1
}}
>
{getTotal(requests, day, day, types, holidays)}
{getTotal([...employeeRequests.values()].flat(), day, day, types, [...holidays.values()].flat())}
</td>
{/each}
</tr>
@ -329,6 +355,9 @@
&.weekend:not(.today) {
background-color: var(--accent-bg-color);
}
&.holiday:not(.today) {
background-color: var(--system-error-60-color);
}
}
td:not(:last-child) {
border-right: 1px solid var(--divider-color);

View File

@ -18,12 +18,12 @@
import { Request, Staff } from '@hcengineering/hr'
export let value: Staff
export let display: (requests: Request[]) => number | string
export let display: (requests: Request[], staff: Staff) => number | string
export let month: Date
export let getStatRequests: (employee: Ref<Staff>, date: Date) => Request[]
$: reqs = getStatRequests(value._id, month)
$: _value = display(reqs)
$: _value = display(reqs, value)
</script>
<span class="select-text flex lines-limit-2">{_value}</span>

View File

@ -19,8 +19,17 @@
import type { Request, RequestType, Staff } from '@hcengineering/hr'
import { Label, LabelAndProps, Scroller, tableHRscheduleY, tooltip } from '@hcengineering/ui'
import hr from '../../plugin'
import { getEndDate, getRequests, getStartDate, getTotal, isToday, weekDays } from '../../utils'
import {
getHolidayDatesForEmployee,
getEndDate,
getRequests,
getStartDate,
getTotal,
isToday,
weekDays
} from '../../utils'
import RequestsPopup from '../RequestsPopup.svelte'
import { Department } from '@hcengineering/hr'
export let currentDate: Date = new Date()
@ -29,7 +38,8 @@
export let employeeRequests: Map<Ref<Staff>, Request[]>
export let holidays: Date[] | undefined = undefined
export let holidays: Map<Ref<Department>, Date[]>
export let staffDepartmentMap: Map<Ref<Staff>, Department[]>
function getTooltip (requests: Request[]): LabelAndProps | undefined {
if (requests.length === 0) return
@ -102,7 +112,13 @@
{#key tooltipValue}
<td class:today={isToday(startDate)} class="fixed td-body" use:tooltip={tooltipValue}>
<div class="flex-center">
{getTotal(requests, startDate, endDate, types, holidays)}
{getTotal(
requests,
startDate,
endDate,
types,
getHolidayDatesForEmployee(staffDepartmentMap, employee._id, holidays)
)}
</div>
</td>
{/key}
@ -116,10 +132,15 @@
{#each values as value, i}
{@const startDate = getStartDate(currentDate.getFullYear(), value)}
{@const endDate = getEndDate(currentDate.getFullYear(), value)}
{@const requests = getRequests(employeeRequests, startDate, endDate)}
<td class:today={isToday(startDate)} class="fixed td-body summary">
<div class="flex-center">
{getTotal(requests, startDate, endDate, types, holidays)}
{getTotal(
[...employeeRequests.values()].flat(),
startDate,
endDate,
types,
[...holidays.values()].flat()
)}
</div>
</td>
{/each}

View File

@ -226,6 +226,25 @@ export function tableToCSV (tableId: string, separator = ','): string {
return csv.join('\n')
}
export function getHolidayDatesForEmployee (
departmentMap: Map<Ref<Staff>, Department[]>,
employee: Ref<Staff>,
holidays: Map<Ref<Department>, Date[]>
): Date[] {
if (departmentMap === undefined || departmentMap.size === 0) return []
const deps = departmentMap.get(employee)
if (deps === undefined) return []
if (holidays.size === 0) return []
const dates = []
for (const dep of deps) {
const depDates = holidays?.get(dep._id)
if (depDates !== undefined) {
dates.push(...depDates)
}
}
return dates
}
export interface EmployeeReports {
reports: TimeSpendReport[]
tasks: Map<Ref<Issue>, Issue>