diff --git a/bruno/Common Cents/Expenses/LOC POST Expense.bru b/bruno/Common Cents/Expenses/LOC POST Expense.bru index 53b9456..695b207 100644 --- a/bruno/Common Cents/Expenses/LOC POST Expense.bru +++ b/bruno/Common Cents/Expenses/LOC POST Expense.bru @@ -13,9 +13,14 @@ post { body:json { { "date": "2026-01-03", - "cents": 101111, - "note": "Gas", - "categoryId": "db21acbb-0e3e-4ea1-89e1-3d52e5d72cb4", - "merchantId": "b9028a32-1305-4699-8611-d8fd812ebc04" + "cents": 12345, + "category": { + "id": "852f2391-27a3-4d84-a9c7-0cd0b2efd899", + "name": "Groceries:Food" + }, + "merchant": { + "id": "f5216666-b022-4ddb-a4b1-f940e5d4f8f2", + "name": "Walmart" + } } } diff --git a/bruno/Common Cents/Expenses/LOC PUT Expense.bru b/bruno/Common Cents/Expenses/LOC PUT Expense.bru index 7042846..e700a8d 100644 --- a/bruno/Common Cents/Expenses/LOC PUT Expense.bru +++ b/bruno/Common Cents/Expenses/LOC PUT Expense.bru @@ -11,11 +11,23 @@ put { } body:json { - { - "id": "0254a07d-9dfa-4c06-b7b3-48d30efff991", - "description": "Cat, no sub-cat or merchant", - "category": { - "id": "db434e98-5f32-4202-b69c-eb7d1d248b3e" + { + "id": "271342fa-94c5-43e2-96f8-6d45668af567", + "date": "2026-01-03", + "cents": 4554, + "category": { + "id": "3b1e6730-29e2-4e51-bee0-4208d8997962", + "name": "Auto:Gas" + }, + "merchant": { + "id": "decb74e6-d680-4124-81b2-08e0fd9fa94c", + "name": "Casey's" + }, + "tags": [ + { + "id": "0ac325ca-ee13-4185-906c-257afa48c4ee", + "name": "Tundra" } - } + ] + } } diff --git a/src/expenses/dto/get-expense.dto.ts b/src/expenses/dto/get-expense.dto.ts index 724578d..96c2182 100644 --- a/src/expenses/dto/get-expense.dto.ts +++ b/src/expenses/dto/get-expense.dto.ts @@ -28,12 +28,12 @@ export class GetExpenseDto { @ApiPropertyOptional({ description: 'Note about expense' }) - note: string; + note: string | null; @ApiPropertyOptional({ description: 'Merchant for the expense' }) - merchant: Merchant; + merchant: Merchant | null; @ApiPropertyOptional({ type: [Tag], diff --git a/src/expenses/entities/expense.entity.ts b/src/expenses/entities/expense.entity.ts index 55fc1c5..b4f6a7a 100644 --- a/src/expenses/entities/expense.entity.ts +++ b/src/expenses/entities/expense.entity.ts @@ -32,12 +32,12 @@ export class Expense { @ManyToOne(() => Category, { eager: true }) category: Category; - @Column({ nullable: true }) - note: string; - @ManyToOne(() => Merchant, { nullable: true, eager: true }) merchant: Merchant; + @Column({ nullable: true }) + note: string; + @ManyToMany(() => Tag, { nullable: true, eager: true }) @JoinTable() tags: Tag[]; diff --git a/src/expenses/expense-data.service.ts b/src/expenses/expense-data.service.ts index 7dcb6c6..95160ef 100644 --- a/src/expenses/expense-data.service.ts +++ b/src/expenses/expense-data.service.ts @@ -25,10 +25,9 @@ export class ExpenseDataService { return await this.expenses.save(expense as Expense); } - // public async update(expense: UpdateExpense): Promise { - // await this.expenses.save(expense); - // return await this.expenses.findOneBy({ id: expense.id }) as Expense; - // } + public async update(expense: UpdateExpense): Promise { + return await this.expenses.save(expense as Expense); + } public async delete(id: string): Promise { await this.expenses.delete({ id }); @@ -41,8 +40,8 @@ export interface CreateExpense { day: number; cents: number; category: Category; - note: string; - merchant: Merchant; + merchant: Merchant | null; + note: string | null; tags: Tag[]; } diff --git a/src/expenses/expenses.controller.ts b/src/expenses/expenses.controller.ts index 2377c45..abfdd65 100644 --- a/src/expenses/expenses.controller.ts +++ b/src/expenses/expenses.controller.ts @@ -58,15 +58,16 @@ export class ExpensesController { } } - // @Put() - // @HttpCode(HttpStatus.OK) - // public async update(@Body() expense: UpdateExpenseDto): Promise { - // if (!expense.id) { - // throw new BadRequestException('Expense ID cannot be empty.'); - // } - // - // return await this.expensesService.update(expense); - // } + @Put() + @HttpCode(HttpStatus.OK) + public async update(@Body() expense: UpdateExpenseDto): Promise { + if (!expense.id) { + throw new BadRequestException('Expense ID cannot be empty.'); + } + // TODO: Validate date/cents/category exist... + + return await this.expensesService.update(expense); + } @Delete(':id') @HttpCode(HttpStatus.NO_CONTENT) diff --git a/src/expenses/expenses.service.ts b/src/expenses/expenses.service.ts index 2985d9c..9088e25 100644 --- a/src/expenses/expenses.service.ts +++ b/src/expenses/expenses.service.ts @@ -4,7 +4,6 @@ import { UpdateExpenseDto } from './dto/update-expense.dto'; import { ExpenseDataService } from './expense-data.service'; import { GetExpenseDto } from './dto/get-expense.dto'; import { Temporal } from '@js-temporal/polyfill'; -import { Expense } from './entities/expense.entity'; @Injectable() export class ExpensesService { @@ -61,31 +60,37 @@ export class ExpensesService { date: new Temporal.PlainDate(exp.year, exp.month, exp.day), cents: exp.cents, category: exp.category, - merchant: exp.merchant, - note: exp.note, + merchant: exp.merchant ?? null, + note: exp.note ?? null, tags: exp.tags }; } - // public async update(updateExpense: UpdateExpenseDto): Promise { - // const date = updateExpense.date.toString(); - // const category = { id: updateExpense.categoryId }; - // const merchant = updateExpense.merchantId ? { id: updateExpense.merchantId } : undefined; - // const tags = updateExpense.tagIds?.map(id => { - // return { id }; - // }) - // const expense = await this.expenseDataService.update({ - // id: updateExpense.id, - // date, - // cents: updateExpense.cents, - // note: updateExpense.note, - // category, - // merchant, - // tags - // }); - // - // return { ...expense, date: Temporal.PlainDate.from(expense.date) }; - // } + public async update(updateExpense: UpdateExpenseDto): Promise { + const date = updateExpense.date.toString().split('-'); + const exp = await this.expenseDataService.update({ + id: updateExpense.id, + year: Number(date[0]), + month: Number(date[1]), + day: Number(date[2]), + cents: updateExpense.cents, + category: updateExpense.category, + merchant: updateExpense.merchant ?? null, + note: updateExpense.note ?? null, + tags: updateExpense.tags + }); + + return { + id: exp.id, + date: new Temporal.PlainDate(exp.year, exp.month, exp.day), + cents: exp.cents, + category: exp.category, + merchant: exp.merchant, + note: exp.note, + tags: exp.tags + }; + + } public async remove(id: string): Promise { await this.expenseDataService.delete(id);