mirror of
https://github.com/hcengineering/platform.git
synced 2024-12-23 03:22:19 +03:00
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:
parent
0b5e7858eb
commit
6c18d7e474
@ -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"
|
||||
|
@ -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} />
|
||||
|
@ -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()} />
|
||||
|
@ -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}
|
@ -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>
|
||||
|
@ -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);
|
||||
|
@ -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>
|
||||
|
@ -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}
|
||||
|
@ -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>
|
||||
|
Loading…
Reference in New Issue
Block a user