diff --git a/src/modules/expenses/controllers/expense.controller.ts b/src/modules/expenses/controllers/expense.controller.ts index 2359b7a..bb37634 100644 --- a/src/modules/expenses/controllers/expense.controller.ts +++ b/src/modules/expenses/controllers/expense.controller.ts @@ -1,10 +1,21 @@ -import { Controller } from "@nestjs/common"; +import { Body, Controller, Param, ParseIntPipe, Post } from "@nestjs/common"; import { PrismaService } from "src/prisma/prisma.service"; +import { ExpenseDto } from "../dtos/expense.dto"; +import { CreateResult, ExpenseUpsertService } from "../services/expense-upsert.service"; @Controller('expense') export class ExpenseController { - constructor(private readonly prisma: PrismaService){} + constructor( + private readonly prisma: PrismaService, + private readonly upsert_service: ExpenseUpsertService, + ){} - + + // @Post(':timesheet_id') + // create( + // @Param('timesheet_id', ParseIntPipe) timesheet_id: number, + // @Body() dto: ExpenseDto): Promise{ + // return this.upsert_service.createExpense(timesheet_id, dto); + // } } \ No newline at end of file diff --git a/src/modules/expenses/dtos/expense.dto.ts b/src/modules/expenses/dtos/expense.dto.ts index e69de29..51cc174 100644 --- a/src/modules/expenses/dtos/expense.dto.ts +++ b/src/modules/expenses/dtos/expense.dto.ts @@ -0,0 +1,14 @@ +import { IsBoolean, IsInt, IsOptional, IsString, MaxLength } from "class-validator"; + +export class ExpenseDto { + @IsInt() bank_code_id!: number; + @IsInt() timesheet_id!: number; + @IsString() @IsOptional() attachment?: string; + + @IsString() date!: string; + @IsInt() @IsOptional() amount?: number; + @IsInt() @IsOptional() mileage?: number; + @IsString() @MaxLength(280) comment!: string; + @IsBoolean() is_approved!: boolean; + @IsString() @MaxLength(280) @IsOptional() supervisor_comment?: string +} \ No newline at end of file diff --git a/src/modules/expenses/dtos/get-expense.dto.ts b/src/modules/expenses/dtos/get-expense.dto.ts index e69de29..6c3056e 100644 --- a/src/modules/expenses/dtos/get-expense.dto.ts +++ b/src/modules/expenses/dtos/get-expense.dto.ts @@ -0,0 +1,11 @@ +export class GetExpenseDto { + timesheet_id: number; + bank_code_id: number; + attachment?: string; + date: string; + comment: string; + mileage?: number; + amount?: number; + supervisor_comment?: string; + is_approved: boolean; +} \ No newline at end of file diff --git a/src/modules/expenses/dtos/update-expense.dto.ts b/src/modules/expenses/dtos/update-expense.dto.ts index e69de29..fc709bb 100644 --- a/src/modules/expenses/dtos/update-expense.dto.ts +++ b/src/modules/expenses/dtos/update-expense.dto.ts @@ -0,0 +1,6 @@ +import { OmitType, PartialType } from "@nestjs/swagger"; +import { ExpenseDto } from "./expense.dto"; + +export class updateExpenseDto extends PartialType ( + OmitType(ExpenseDto, ['is_approved', 'timesheet_id'] as const) +){} \ No newline at end of file diff --git a/src/modules/expenses/helpers/expenses-date-time-helpers.ts b/src/modules/expenses/helpers/expenses-date-time-helpers.ts new file mode 100644 index 0000000..ce14e69 --- /dev/null +++ b/src/modules/expenses/helpers/expenses-date-time-helpers.ts @@ -0,0 +1,3 @@ +export const toDateFromString = (ymd: string): Date => { + return new Date(`${ymd}T00:00:00:000Z`); +} \ No newline at end of file diff --git a/src/modules/expenses/services/expense-upsert.service.ts b/src/modules/expenses/services/expense-upsert.service.ts new file mode 100644 index 0000000..5e47a1e --- /dev/null +++ b/src/modules/expenses/services/expense-upsert.service.ts @@ -0,0 +1,46 @@ +import { Injectable } from "@nestjs/common"; +import { PrismaService } from "src/prisma/prisma.service"; +import { GetExpenseDto } from "../dtos/get-expense.dto"; +import { updateExpenseDto } from "../dtos/update-expense.dto"; +import { ExpenseDto } from "../dtos/expense.dto"; +import { toDateFromString } from "../helpers/expenses-date-time-helpers"; + +type Normalized = { date: Date; comment: string; supervisor_comment: string; }; + +export type CreateResult = { ok: true; data: GetExpenseDto } | { ok: false; error: any }; +export type UpdatePayload = { id: number; dto: updateExpenseDto }; +export type UpdateResult = { ok: true; id: number; data: GetExpenseDto } | { ok: false; id: number; error: any }; +export type DeleteResult = { ok: true; id: number; } | { ok: false; id: number; error: any }; + +type NormedOk = { dto: GetExpenseDto; normed: Normalized }; +type NormedErr = { error: any }; + +@Injectable() +export class ExpenseUpsertService { + constructor(private readonly prisma: PrismaService){} + + //_________________________________________________________________ + // CREATE + //_________________________________________________________________ + //normalized frontend data to match DB + async createExpense(timesheet_id: number, dto: ExpenseDto){ + const normed_expense = this.normalizeExpenseDto(dto) + + + } + + //_________________________________________________________________ + // LOCAL HELPERS + //_________________________________________________________________ + private normalizeExpenseDto(dto: ExpenseDto): Normalized { + const date = toDateFromString(dto.date); + const comment = this.truncate280(dto.comment); + const supervisor_comment = this.truncate280(dto.supervisor_comment? dto.supervisor_comment : ''); + return { date, comment, supervisor_comment }; + } + + //makes sure that a string cannot exceed 280 chars + private truncate280 = (input: string): string => { + return input.length > 280 ? input.slice(0, 280) : input; + } +} \ No newline at end of file diff --git a/src/modules/shifts/services/shifts-upsert.service.ts b/src/modules/shifts/services/shifts-upsert.service.ts index 9ed8457..e63380b 100644 --- a/src/modules/shifts/services/shifts-upsert.service.ts +++ b/src/modules/shifts/services/shifts-upsert.service.ts @@ -333,7 +333,7 @@ export class ShiftsUpsertService { //_________________________________________________________________ // DELETE //_________________________________________________________________ - //finds shift using shit_ids + //finds shifts using shit_ids //recalc overtime shifts after delete //blocs deletion if approved async deleteShift(shift_id: number) {