diff --git a/client/src/clients/api/meeting.ts b/client/src/clients/api/meeting.ts index 7a61205ba..f7f6f9c71 100644 --- a/client/src/clients/api/meeting.ts +++ b/client/src/clients/api/meeting.ts @@ -14,7 +14,7 @@ export class MeetingApi extends ApiClientBase { list(query?: any) { return this.unwrap( - () => this.$http.get>(this.getUrl('', query)), + () => this.$http.get>(this.getUrl('', query)), { transform: (d) => d.results } diff --git a/client/src/components/CalenderComponent.vue b/client/src/components/CalenderComponent.vue new file mode 100644 index 000000000..5df9eaa64 --- /dev/null +++ b/client/src/components/CalenderComponent.vue @@ -0,0 +1,435 @@ + + + + + diff --git a/client/src/components/calender.vue b/client/src/components/calender.vue deleted file mode 100644 index 87ef51361..000000000 --- a/client/src/components/calender.vue +++ /dev/null @@ -1,510 +0,0 @@ - - - - diff --git a/client/src/components/cards/vacationCard.vue b/client/src/components/cards/vacationCard.vue index b683296bf..15955b025 100644 --- a/client/src/components/cards/vacationCard.vue +++ b/client/src/components/cards/vacationCard.vue @@ -17,7 +17,7 @@ - Update + Update Delete @@ -29,7 +29,7 @@

Applying User : {{ - vacation.user.full_name + vacation.applying_user.full_name }}

@@ -80,10 +80,16 @@ import { computed, ref, watch } from 'vue'; import { useApi } from '@/hooks' import { useAsyncState } from '@vueuse/core' import { ApiClientBase } from '@/clients/api/base' +import type { PropType } from 'vue'; export default { name: 'vacationCard', - props: ['vacation'], + props: { + vacation: { + type: Object as PropType, + required: true, + } + }, emits: { 'close-dialog': (item: Boolean) => item, 'update-vacation': (item: any) => item, @@ -132,6 +138,7 @@ export default { const couldUpdate = computed(() => { if (user.value) { if (props.vacation.status == 'pending') { + // could update if user signed in is the same user applied for vacation if (props.vacation.isUpdated && user.value.fullUser.id == props.vacation.applying_user) { return true } @@ -150,16 +157,21 @@ export default { const couldApprove = computed(() => { if (user.value) { + // only admins or supervisors could approve vacation if ( user.value.fullUser.user_type === 'Admin' || user.value.fullUser.user_type === 'Supervisor' ) { - if (props.vacation.user.id == user.value.fullUser.id) { + // Could approve if user signed in is the same user applied for vacation + if (props.vacation.applying_user.id == user.value.fullUser.id) { return true } + // Could approve if applying user reports to the supervisor or admin logged in + // and works from the same office if ( - props.vacation.user.reporting_to[0]?.id === props.vacation.user?.id && - props.vacation.user.location.name === user.value.fullUser.location.name + props.vacation.applying_user.reporting_to && + props.vacation.applying_user.reporting_to[0]?.id === props.vacation.applying_user?.id && + props.vacation.applying_user.location.name === user.value.fullUser.location.name ) { return true } @@ -225,7 +237,7 @@ export default { async function updateVacation() { const actualDays = await calculateActualDays() - useAsyncState( + await useAsyncState( $api.vacations.edit.update(props.vacation.id, { reason: leaveReason.value.reason, from_date: startDate.value, diff --git a/client/src/components/requests/eventRequest.vue b/client/src/components/requests/eventRequest.vue index d254c2e97..0bbd264f5 100644 --- a/client/src/components/requests/eventRequest.vue +++ b/client/src/components/requests/eventRequest.vue @@ -1,13 +1,33 @@ diff --git a/client/src/components/requests/meetingRequest.vue b/client/src/components/requests/meetingRequest.vue index 9e6e5afd4..ec6730ae8 100644 --- a/client/src/components/requests/meetingRequest.vue +++ b/client/src/components/requests/meetingRequest.vue @@ -59,7 +59,14 @@ - Submit + + Submit +
@@ -82,6 +89,7 @@ export default { const location = ref('') const form = ref() const meetingTime = ref() + const requesting = ref(false) const meetingDateTime = computed(() => { let val = new Date(startDate.value) @@ -94,7 +102,8 @@ export default { }) async function createMeeting() { - useAsyncState( + requesting.value = true + await useAsyncState( $api.meeting.create({ date: meetingDateTime.value, meeting_link: meetingLink.value, @@ -107,6 +116,7 @@ export default { } } ) + requesting.value = false } return { @@ -115,6 +125,7 @@ export default { location, form, meetingTime, + requesting, fieldRequired, createMeeting } diff --git a/client/src/router/index.ts b/client/src/router/index.ts index 019015b99..ca24a0256 100644 --- a/client/src/router/index.ts +++ b/client/src/router/index.ts @@ -6,6 +6,7 @@ const router = createRouter({ routes: [ { path: '/login', component: () => import('@/views/LoginView.vue') }, { path: '/', component: () => import('@/views/CalendarView.vue') }, + { path: '/test', component: () => import('@/views/TestView.vue') }, { path: '/notifications', component: () => import('@/views/NotificationsView.vue') }, { path: '/team', component: () => import('@/views/TeamView.vue') }, { path: '/users', name: 'users', component: () => import('@/views/UsersView.vue') }, diff --git a/client/src/types/api.ts b/client/src/types/api.ts index 4c54fb026..58569ad49 100644 --- a/client/src/types/api.ts +++ b/client/src/types/api.ts @@ -40,7 +40,7 @@ export module Api { actual_days: number applying_user: number | any approval_user: number - user?: Api.User + applying_user_full_name?: string; isUpdated?: boolean } @@ -52,7 +52,8 @@ export module Api { export interface Certificate {} export interface Salary {} - export interface Meetings { + export interface Meeting { + type: string; id: number invited_users: any[] date: any @@ -70,7 +71,16 @@ export module Api { } location: string } + export interface Event { + id: number + name: string + type: string; + description: string; + from_date: string; + end_date: string; + } export interface User { + type: string; id: number first_name: string last_name: string @@ -84,6 +94,7 @@ export module Api { mobile_number: string reporting_to: number[] birthday: string + date: string location: { id: number name: string @@ -143,7 +154,7 @@ export module Api { export type Meeting = MsgRes export type Profile = MsgRes - export type AllMeetings = MsgRes + export type AllMeetings = MsgRes export type Login = MsgRes<{ id: number @@ -243,6 +254,7 @@ export module Api { } } export interface Holiday { + type: string id: number location: { id: number @@ -256,7 +268,7 @@ export module Api { export interface Home { id: number - title: string + type: string className: string eventName: string vacation?: any diff --git a/client/src/types/index.ts b/client/src/types/index.ts index 9687ee7b6..6b57a8f9e 100644 --- a/client/src/types/index.ts +++ b/client/src/types/index.ts @@ -1,20 +1,28 @@ export * from './api' - export interface Country { - id: number - country: string + id: number + country: string } export interface JWTokenObject { - token_type: string - exp: number - iat: number - jti: string - user_id: number + token_type: string + exp: number + iat: number + jti: string + user_id: number } export enum Selection { - ME = "me", - ANOTHERUSER = "anotheruser", - } \ No newline at end of file + ME = 'me', + ANOTHERUSER = 'anotheruser' +} + +export enum CalendarEventSelection { + PublicHoliday = 'Public Holiday', + Birthday = 'Birthday', + Vacation = 'Vacation', + Event = 'Event', + Meeting = 'Meeting', + NewEvent = 'New Event' +} diff --git a/client/src/utils/helpers.ts b/client/src/utils/helpers.ts index 2ed5bd648..7aa6f3d7c 100644 --- a/client/src/utils/helpers.ts +++ b/client/src/utils/helpers.ts @@ -65,17 +65,18 @@ export function handelDates(start: any, end: any): any { } -export function normalizeEvent(e: Api.Inputs.Event): any { +export function normalizeEvent(e: Api.Event): any { const dates = handelDates(e.from_date, e.end_date) return { + type: e.type, title: 'Event', classNames: ['cshr-event'], color: '#47a2ff', start: dates.start, end: dates.end, backgroundColor: '#47a2ff', - id: e.name, + id: e.type + e.id.toString(), allDay: true } } @@ -83,12 +84,13 @@ export function normalizeVacation(v: Api.Vacation) { const dates = handelDates(v.from_date, v.end_date) return { - title: `${v.user!.full_name}'s Vacation`, + type: v.type, + title: `${v.applying_user_full_name ? v.applying_user_full_name : v.applying_user.full_name }'s Vacation`, color: '#fcd091', start: dates.start, end: dates.end, backgroundColor: '#fcd091', - id: v.id.toString(), + id: v.type + v.id.toString(), allDay: true } } @@ -97,40 +99,43 @@ export function normalizeHoliday(h: Api.Holiday) { const dates = handelDates(h.holiday_date, h.holiday_date) return { + type: h.type, title: `Public Holiday`, color: '#5effb4', start: dates.start, end: dates.end, backgroundColor: '#5effb4', - id: h.id.toString(), + id: h.type + h.id.toString(), allDay: true } } export function normalizedBirthday(u: Api.User) { - const dates = handelDates(u.birthday, u.birthday) + const dates = handelDates(u.date, u.date) return { + type: u.type, title: `Birthday`, color: '#e0adf0', start: dates.start, end: dates.end, backgroundColor: '#e0adf0', - id: u.id.toString(), + id: u.type + u.id.toString(), allDay: true } } -export function normalizeMeeting(m: Api.Meetings): any { +export function normalizeMeeting(m: Api.Meeting): any { const dates = handelDates(m.date, m.date) return { + type: m.type, title: 'Meeting', color: '#efeaea', start: dates.start, end: dates.end, backgroundColor: '#efeaea', - id: m.id, + id: m.type + m.id.toString(), allDay: true } } @@ -168,7 +173,7 @@ export function isValidToken(token: string): boolean { export async function listUsers($api: ApiClient, page: number, count: number): Promise<{ page: number, count: number, users: any[]}> { const res = await $api.users.admin.office_users.list({ page }); - let users: any[] = []; + const users: any[] = []; if (res.count) { count = Math.ceil(res.count / 10) } else { diff --git a/client/src/views/CalendarView.vue b/client/src/views/CalendarView.vue index b03b8667e..09b8d2f46 100644 --- a/client/src/views/CalendarView.vue +++ b/client/src/views/CalendarView.vue @@ -1,21 +1,13 @@ diff --git a/client/src/views/TestView.vue b/client/src/views/TestView.vue new file mode 100644 index 000000000..99c82e111 --- /dev/null +++ b/client/src/views/TestView.vue @@ -0,0 +1,82 @@ + + + diff --git a/server/cshr/serializers/event.py b/server/cshr/serializers/event.py index 50d2e3945..5a0592ca3 100644 --- a/server/cshr/serializers/event.py +++ b/server/cshr/serializers/event.py @@ -10,6 +10,7 @@ class Meta: fields = [ # "people", # "custom_people", + "id", "name", "description", # "location", diff --git a/server/cshr/services/event.py b/server/cshr/services/event.py index 66bd0c9fd..f92102c7a 100644 --- a/server/cshr/services/event.py +++ b/server/cshr/services/event.py @@ -1,10 +1,9 @@ """This file contains everything related to the Event model.""" import datetime from cshr.models.event import Event -from typing import Any, Dict, List +from typing import List from cshr.models.users import User -from cshr.serializers.event import EventSerializer def get_event_by_id(id: str) -> Event: @@ -36,31 +35,3 @@ def filter_events_by_day(day: int) -> List[Event]: return Event.objects.filter( from_date__year=today.year, from_date__month=today.month, from_date__day=day ) - - -def send_event_to_calendar(event: Event) -> Dict[str, Any]: - from cshr.services.landing_page import ( - LandingPageClassNameEnum, - LandingPageTypeEnum, - ) - - """ - Takes the standerd event, then update it with calendar values. - calendar pattern: - - { - "title": str(event), - "date": date(from_date), - "len": int(len(end_date - from_date)), - "className": str(--task-warning), - "eventName": str(event) - } - """ - response: Dict(str, Any) = {} - response["len"] = (event.end_date - event.from_date).days + 1 - response["date"] = event.from_date - response["title"] = LandingPageTypeEnum.Event.value - response["className"] = LandingPageClassNameEnum.Event.value - response["isBottom"] = True - response["eventName"] = LandingPageTypeEnum.Event.value - response["event"] = [EventSerializer(event).data] - return response diff --git a/server/cshr/services/landing_page.py b/server/cshr/services/landing_page.py index 3e28c96cc..a987f3830 100644 --- a/server/cshr/services/landing_page.py +++ b/server/cshr/services/landing_page.py @@ -1,149 +1,59 @@ """This file contains everything related to the landing page functionalty.""" -import datetime -from cshr.api.response import CustomResponse -from cshr.models.event import Event -from cshr.models.meetings import Meetings + from cshr.models.users import User -from cshr.models.vacations import PublicHoliday, Vacation -from cshr.serializers.event import EventSerializer -from cshr.serializers.meetings import MeetingsSerializer -from cshr.serializers.public_holidays import PublicHolidaySerializer -from cshr.serializers.users import BaseUserSerializer -from cshr.serializers.vacations import LandingPageVacationsSerializer from cshr.services.event import filter_events_by_month_and_year from cshr.services.meetings import filter_meetings_by_month_and_year from cshr.services.public_holidays import ( filter_public_holidays_by_month_and_year, ) -from cshr.services.users import filter_users_by_berithday_month +from cshr.services.users import filter_users_by_birth_month from cshr.services.vacations import filter_vacations_by_month_and_year -from typing import Any, List, Dict, Union -from itertools import chain -from enum import Enum - - -class LandingPageTypeEnum(Enum): - VACATION = "vacation" - PUBLIC_HOLIDAY = "public_holiday" - BIRTHDAY = "birthday" - MEETING = "meeting" - Event = "event" +from typing import Any, List + +from cshr.utils.wrappers import ( + wrap_birthday_event, + wrap_event_request, + wrap_holiday_request, + wrap_meeting_request, + wrap_vacation_request, +) -class LandingPageClassNameEnum(Enum): - PUBLIC_HOLIDAY = "task--success" - VACATION = "task--warning" - BIRTHDAY = "task--primary" - MEETING = "task--danger" - Event = "task--info" +def landing_page_calendar_functionality(user: User, month: str, year: str) -> List[Any]: + response: List[Any] = [] + # Fetch vacations + vacations = filter_vacations_by_month_and_year(month, year).order_by("-created_at") + for vacation in vacations: + vacation_data = wrap_vacation_request(vacation) + response.append(vacation_data) -def landing_page_calendar_functionality(user: User, month: str, year: str): - """ - This function will filter all of events based on its yesr, month. - """ - vacations: List[Vacation] = filter_vacations_by_month_and_year( - month, year - ).order_by("-created_at") - meetings: List[Meetings] = filter_meetings_by_month_and_year( - user, month, year - ).order_by("-created_at") - events: List[Event] = filter_events_by_month_and_year(user, month, year).order_by( + # Fetch meetings + meetings = filter_meetings_by_month_and_year(user, month, year).order_by( "-created_at" ) - users_birthdates: List[User] = filter_users_by_berithday_month(month).order_by( + for meeting in meetings: + meeting_data = wrap_meeting_request(meeting) + response.append(meeting_data) + + # Fetch events + events = filter_events_by_month_and_year(user, month, year).order_by("-created_at") + for event in events: + event_data = wrap_event_request(event) + response.append(event_data) + + # Fetch users' birthdays + users_birthdates = filter_users_by_birth_month(month).order_by("-created_at") + for birthday_user in users_birthdates: + birthday_data = wrap_birthday_event(birthday_user) + response.append(birthday_data) + + # Fetch public holidays + public_holidays = filter_public_holidays_by_month_and_year(year, month).order_by( "-created_at" ) - public_holidays: PublicHoliday = filter_public_holidays_by_month_and_year( - year, month - ).order_by("-created_at") - - objects: Union[List[Any], None] = list( - chain(public_holidays, vacations, events, meetings, users_birthdates) - ) - - response: List[Any] = [] - - for object in objects: - obj: Dict = {} - obj["id"] = object.id - if isinstance(object, Vacation): - obj["title"] = LandingPageTypeEnum.VACATION.value - obj["className"] = LandingPageClassNameEnum.VACATION.value - obj["eventName"] = LandingPageTypeEnum.VACATION.value - obj["vacation"] = LandingPageVacationsSerializer( - vacations.filter( - from_date__day=object.from_date.day, - from_date__month=object.from_date.month, - ), - many=True, - ).data - elif isinstance(object, PublicHoliday): - obj["title"] = LandingPageTypeEnum.PUBLIC_HOLIDAY.value - obj["className"] = LandingPageClassNameEnum.PUBLIC_HOLIDAY.value - obj["eventName"] = LandingPageTypeEnum.PUBLIC_HOLIDAY.value - obj["holidays"] = PublicHolidaySerializer( - public_holidays.filter( - holiday_date__day=object.holiday_date.day, - holiday_date__month=object.holiday_date.month, - ), - many=True, - ).data - obj["date"] = object.holiday_date - obj["len"] = 1 - elif isinstance(object, Meetings): - obj["title"] = LandingPageTypeEnum.MEETING.value - obj["date"] = object.date - obj["len"] = 1 - obj["vlen"] = 2 - obj["className"] = LandingPageClassNameEnum.MEETING.value - obj["eventName"] = LandingPageTypeEnum.MEETING.value - obj["meeting"] = MeetingsSerializer( - meetings.filter( - date__day=object.date.day, date__month=object.date.month - ), - many=True, - ).data - elif isinstance(object, Event): - obj["len"] = (object.end_date - object.from_date).days + 1 - obj["date"] = object.from_date - obj["title"] = LandingPageTypeEnum.Event.value - obj["className"] = LandingPageClassNameEnum.Event.value - obj["isBottom"] = True - obj["eventName"] = LandingPageTypeEnum.Event.value - obj["event"] = EventSerializer( - events.filter( - from_date__day=object.from_date.day, - from_date__month=object.from_date.month, - from_date__year=object.from_date.year, - ), - many=True, - ).data - elif isinstance(object, User): - today = datetime.datetime.now() - obj["title"] = LandingPageTypeEnum.BIRTHDAY.value - obj["className"] = LandingPageClassNameEnum.BIRTHDAY.value - obj["eventName"] = LandingPageTypeEnum.BIRTHDAY.value - obj["date"] = f"{today.year}-{object.birthday.month}-{object.birthday.day}" - obj["len"] = 1 - obj["vlen"] = 2 - obj["users"] = BaseUserSerializer( - users_birthdates.filter( - birthday__day=object.birthday.day, - birthday__month=object.birthday.month, - ), - many=True, - ).data - else: - return CustomResponse.bad_request(message="Unknown landing page type") - - if ( - hasattr(object, "from_date") - and hasattr(object, "end_date") - and not isinstance(object, Event) - ): - obj["len"] = (object.end_date - object.from_date).days + 1 - obj["date"] = object.from_date - response.append(obj) + for holiday in public_holidays: + holiday_data = wrap_holiday_request(holiday) + response.append(holiday_data) return response diff --git a/server/cshr/services/meetings.py b/server/cshr/services/meetings.py index e6df87834..d182db85d 100644 --- a/server/cshr/services/meetings.py +++ b/server/cshr/services/meetings.py @@ -1,9 +1,8 @@ """This file contains everything related to the Meetings model.""" from cshr.models.meetings import Meetings -from typing import Any, Dict, List +from typing import List from cshr.models.users import User -from cshr.serializers.meetings import MeetingsSerializer def get_meeting_by_id(id: str) -> Meetings: @@ -32,30 +31,3 @@ def filter_meetings_by_month_and_year(user: User, month: str, year: str) -> Meet def filter_meetings_by_day(year: int, month: int, day: int) -> List[Meetings]: """Filter all users by birthdates""" return Meetings.objects.filter(date__year=year, date__month=month, date__day=day) - - -def send_meeting_to_calendar(meeting: Meetings) -> Dict[str, Any]: - from cshr.services.landing_page import ( - LandingPageClassNameEnum, - LandingPageTypeEnum, - ) - - """ - Takes the standerd meeting, then update it with calendar values. - calendar pattern: - - { - "title": str(meeting), - "date": date(from_date), - "len": int(len(end_date - from_date)), - "className": str(--task-warning), - "eventName": str(meeting) - } - """ - response: Dict(str, Any) = {} - response["title"] = LandingPageTypeEnum.MEETING.value - response["className"] = LandingPageClassNameEnum.MEETING.value - response["eventName"] = LandingPageTypeEnum.MEETING.value - response["meeting"] = [MeetingsSerializer(meeting).data] - response["len"] = 1 - response["date"] = meeting.date - return response diff --git a/server/cshr/services/users.py b/server/cshr/services/users.py index 6685b8603..6f2e552ab 100644 --- a/server/cshr/services/users.py +++ b/server/cshr/services/users.py @@ -62,7 +62,7 @@ def get_user_type_by_id(id: str) -> User: return None -def filter_users_by_berithday_month(month: str) -> User: +def filter_users_by_birth_month(month: str) -> User: """Filter users based on birthdayes.""" users: List[User] = User.objects.filter(birthday__month=month) return users @@ -102,7 +102,7 @@ def get_admin_office_users(admin: User) -> User: ) -def get_or_create_skill_by_name(name: str) -> UserSkills or bool: +def get_or_create_skill_by_name(name: str) -> UserSkills or bool: # type: ignore """Return a skill by name""" return UserSkills.objects.get_or_create(name=name.lower()) diff --git a/server/cshr/services/vacations.py b/server/cshr/services/vacations.py index 894f9ba12..7320badba 100644 --- a/server/cshr/services/vacations.py +++ b/server/cshr/services/vacations.py @@ -3,9 +3,7 @@ from cshr.models.users import User from cshr.models.vacations import Vacation, VacationBalance from django.db.models import Q -from typing import Any, Dict, List - -from cshr.serializers.vacations import LandingPageVacationsSerializer +from typing import List def filter_vacations_by_month_and_year(month: str, year: str) -> Vacation: @@ -16,12 +14,10 @@ def filter_vacations_by_month_and_year(month: str, year: str) -> Vacation: Q( from_date__month=month, from_date__year=year, - status__in=[STATUS_CHOICES.PENDING, STATUS_CHOICES.APPROVED], ) | Q( end_date__month=month, end_date__year=year, - status__in=[STATUS_CHOICES.PENDING, STATUS_CHOICES.APPROVED], ) ) return vacations @@ -90,30 +86,3 @@ def filter_user_vacations_by_pending_status(user: User) -> Vacation: def filter_user_vacations(user: User) -> Vacation: """Return all vacations that has pending status and related to user""" return Vacation.objects.filter(applying_user=user).order_by("created_at") - - -def send_vacation_to_calendar(vacation: Vacation) -> Dict[str, Any]: - from cshr.services.landing_page import ( - LandingPageClassNameEnum, - LandingPageTypeEnum, - ) - - """ - Takes the standerd vacation, then update it with calendar values. - calendar pattern: - - { - "title": str(Vacation), - "date": date(from_date), - "len": int(len(end_date - from_date)), - "className": str(--task-warning), - "eventName": str(Vacation) - } - """ - response: Dict(str, Any) = {} - response["title"] = LandingPageTypeEnum.VACATION.value - response["className"] = LandingPageClassNameEnum.VACATION.value - response["eventName"] = LandingPageTypeEnum.VACATION.value - response["vacation"] = [LandingPageVacationsSerializer(vacation).data] - response["len"] = (vacation.end_date - vacation.from_date).days + 1 - response["date"] = vacation.from_date - return response diff --git a/server/cshr/utils/wrappers.py b/server/cshr/utils/wrappers.py new file mode 100644 index 000000000..8bfa261b9 --- /dev/null +++ b/server/cshr/utils/wrappers.py @@ -0,0 +1,63 @@ +import datetime +from cshr.models.users import User +from cshr.models.vacations import Vacation, PublicHoliday +from cshr.models.meetings import Meetings +from cshr.models.event import Event +from cshr.serializers.event import EventSerializer +from cshr.serializers.public_holidays import PublicHolidaySerializer +from cshr.serializers.users import BaseUserSerializer +from cshr.serializers.vacations import LandingPageVacationsSerializer +from cshr.serializers.meetings import MeetingsSerializer +from enum import Enum + + +class LandingPageTypeEnum(Enum): + VACATION = "vacation" + PUBLIC_HOLIDAY = "holiday" + BIRTHDAY = "birthday" + MEETING = "meeting" + EVENT = "event" + + +""" +Wrap the vacation request with [type: string] field, to be ready to be sent to the calendar as the `type` field is required there. +""" +def wrap_vacation_request(vacation: Vacation) -> LandingPageVacationsSerializer : # type: ignore + vacation_data = LandingPageVacationsSerializer(vacation).data + vacation_data["type"] = LandingPageTypeEnum.VACATION.value + vacation_data["applying_user_full_name"] = vacation.applying_user.full_name + return vacation_data + +""" +Wrap the meeting request with [type: string] field, to be ready to be sent to the calendar as the `type` field is required there. +""" +def wrap_meeting_request(meeting: Meetings) -> MeetingsSerializer : # type: ignore + meeting_data = MeetingsSerializer(meeting).data + meeting_data["type"] = LandingPageTypeEnum.MEETING.value + return meeting_data + +""" +Wrap the event request with [type: string] field, to be ready to be sent to the calendar as the `type` field is required there. +""" +def wrap_event_request(event: Event) -> EventSerializer : # type: ignore + event_data = EventSerializer(event).data + event_data["type"] = LandingPageTypeEnum.EVENT.value + return event_data + +""" +Wrap the event request with [type: string] field, to be ready to be sent to the calendar as the `type` field is required there. +""" +def wrap_holiday_request(holiday: PublicHoliday) -> PublicHolidaySerializer : # type: ignore + holiday_data = PublicHolidaySerializer(holiday).data + holiday_data["type"] = LandingPageTypeEnum.PUBLIC_HOLIDAY.value + return holiday_data + +""" +Wrap the birthday request with [type: string] field, to be ready to be sent to the calendar as the `type` field is required there. +""" +def wrap_birthday_event(birthday: User) -> BaseUserSerializer : # type: ignore + today = datetime.datetime.now() + birthday_data = BaseUserSerializer(birthday).data + birthday_data["type"] = LandingPageTypeEnum.BIRTHDAY.value + birthday_data["date"] = f"{today.year}-{birthday.birthday.month}-{birthday.birthday.day}" + return birthday_data diff --git a/server/cshr/views/event.py b/server/cshr/views/event.py index a3eeba810..2fbfeb598 100644 --- a/server/cshr/views/event.py +++ b/server/cshr/views/event.py @@ -6,12 +6,12 @@ filter_events_by_day, get_all_events, get_event_by_id, - send_event_to_calendar, ) from rest_framework.generics import GenericAPIView, ListAPIView from rest_framework.request import Request from rest_framework.response import Response from cshr.api.response import CustomResponse +from cshr.utils.wrappers import wrap_event_request class BaseEventsAPIView(ListAPIView, GenericAPIView): @@ -23,7 +23,7 @@ def post(self, request: Request) -> Response: serializer = self.get_serializer(data=request.data) if serializer.is_valid(): saved = serializer.save() - response_date: Dict = send_event_to_calendar(saved) + response_date: Dict = wrap_event_request(saved) return CustomResponse.success( data=response_date, message="event is created successfully", diff --git a/server/cshr/views/meetings.py b/server/cshr/views/meetings.py index 770bfcff2..1f439e4db 100644 --- a/server/cshr/views/meetings.py +++ b/server/cshr/views/meetings.py @@ -7,12 +7,12 @@ filter_meetings_by_day, get_all_meetings, get_meeting_by_id, - send_meeting_to_calendar, ) from rest_framework.generics import GenericAPIView, ListAPIView from rest_framework.request import Request from rest_framework.response import Response from cshr.api.response import CustomResponse +from cshr.utils.wrappers import wrap_meeting_request class BaseMeetingsApiView(ListAPIView, GenericAPIView): @@ -31,8 +31,10 @@ def post(self, request: Request) -> Response: return CustomResponse.bad_request( message='Ensure that the "host_user" field is included in the payload.' ) - saved = serializer.save(host_user=current_user, invited_users=[]) - response_date: Dict = send_meeting_to_calendar(saved) + + event = serializer.save(host_user=current_user, invited_users=[]) + + response_date: Dict = wrap_meeting_request(event) return CustomResponse.success( data=response_date, message="meeting is created successfully", diff --git a/server/cshr/views/vacations.py b/server/cshr/views/vacations.py index 3b55882ee..72b41b0a7 100644 --- a/server/cshr/views/vacations.py +++ b/server/cshr/views/vacations.py @@ -30,7 +30,6 @@ filter_balances_by_users, get_vacation_by_id, get_all_vacations, - send_vacation_to_calendar, ) from rest_framework.generics import GenericAPIView, ListAPIView from rest_framework.request import Request @@ -61,6 +60,7 @@ set_notification_request_redis, set_notification_reply_redis, ) +from cshr.utils.wrappers import wrap_vacation_request class GetAdminVacationBalanceApiView(GenericAPIView): @@ -250,55 +250,55 @@ def post(self, request: Request) -> Response: ], }, ) + else: + curr_balance = getattr(user_reason_balance, reason) - curr_balance = getattr(user_reason_balance, reason) + pending_vacations = Vacation.objects.filter( + status=STATUS_CHOICES.PENDING, + applying_user=applying_user, + reason=reason, + ).values_list("actual_days", flat=True) - pending_vacations = Vacation.objects.filter( - status=STATUS_CHOICES.PENDING, - applying_user=applying_user, - reason=reason, - ).values_list("actual_days", flat=True) + chcked_balance = curr_balance - sum(pending_vacations) - chcked_balance = curr_balance - sum(pending_vacations) + if curr_balance < vacation_days: + return CustomResponse.bad_request( + message=f"You only have {curr_balance} days left of reason '{reason.capitalize().replace('_', ' ')}'" + ) - if curr_balance < vacation_days: - return CustomResponse.bad_request( - message=f"You only have {curr_balance} days left of reason '{reason.capitalize().replace('_', ' ')}'" - ) + if chcked_balance < vacation_days: + return CustomResponse.bad_request( + message=f"You have an additional pending request that deducts {sum(pending_vacations)} days from your balance even though the current balance for the '{reason.capitalize().replace('_', ' ')}' category is only {curr_balance} days." + ) - if chcked_balance < vacation_days: - return CustomResponse.bad_request( - message=f"You have an additional pending request that deducts {sum(pending_vacations)} days from your balance even though the current balance for the '{reason.capitalize().replace('_', ' ')}' category is only {curr_balance} days." + vacation = serializer.save( + type=TYPE_CHOICES.VACATIONS, + status=STATUS_CHOICES.PENDING, + applying_user=applying_user, + actual_days=vacation_days, ) - saved = serializer.save( - type=TYPE_CHOICES.VACATIONS, - status=STATUS_CHOICES.PENDING, - applying_user=applying_user, - actual_days=vacation_days, - ) - - # msg = get_vacation_request_email_template( - # request.user, serializer.data, saved.id - # ) + # msg = get_vacation_request_email_template( + # request.user, serializer.data, vacation.id + # ) - try: - ping_redis() - except: - return http_ensure_redis_error() + try: + ping_redis() + except: + return http_ensure_redis_error() - set_notification_request_redis(serializer.data) + set_notification_request_redis(serializer.data) - # sent = send_email_for_request(request.user.id, msg, "Vacation request") - # if not sent: - # return CustomResponse.bad_request(message="Error in sending email, can not sent email with this request.") + # sent = send_email_for_request(request.user.id, msg, "Vacation request") + # if not sent: + # return CustomResponse.bad_request(message="Error in sending email, can not sent email with this request.") - response_data: Dict = send_vacation_to_calendar(saved) - return CustomResponse.success( - status_code=201, - message="The vacation has been posted successfully.", - data=response_data, - ) + vacation_data: Dict = wrap_vacation_request(vacation) + return CustomResponse.success( + status_code=201, + message="The vacation has been posted successfully.", + data=vacation_data, + ) return CustomResponse.bad_request(error=serializer.errors) def get_queryset(self) -> Response: @@ -330,8 +330,8 @@ def delete(self, request: Request, id, format=None) -> Response: vacation = get_vacation_by_id(id=id) if vacation is not None: vacation.delete() - return CustomResponse.success(message="Hr Letter deleted", status_code=204) - return CustomResponse.not_found(message="Hr Letter not found", status_code=404) + return CustomResponse.success(message="The vacation has been deleted successfully.", status_code=204) + return CustomResponse.not_found(message="The vacation is not found.", status_code=404) class VacationUserApiView(ListAPIView, GenericAPIView): @@ -879,6 +879,6 @@ def post(self, request: Request, user_id: str) -> Response: saved_vacation.save() # set_notification_request_redis(serializer.data) - response_data: Dict = send_vacation_to_calendar(saved_vacation) + response_data: Dict = wrap_vacation_request(saved_vacation) return CustomResponse.success(message=message, data=response_data) return CustomResponse.bad_request(message="Please make sure that you entered a valid data.", error=serializer.errors) \ No newline at end of file