mirror of
https://github.com/mauriceboe/TREK.git
synced 2026-10-18 21:16:47 +00:00
fix(reservations): link a cost created on a booking update on its insert
syncBudgetOnUpdate created the expense and then set its reservation_id in a second statement, inside a try that logs and swallows the failure. Running inside updateWithCost, a failed back-link committed an expense that was not linked to its booking. The expense is now created through linkBudgetItemToReservation, which writes the link on the insert, the same way syncBudgetOnCreate does.
This commit is contained in:
@@ -17,7 +17,7 @@
|
||||
"src/nest/places/places.service.ts": 2020,
|
||||
"src/nest/plugins/plugin-runtime.service.ts": 1463,
|
||||
"src/nest/plugins/runtime/plugin-sdk.ts": 1094,
|
||||
"src/nest/reservations/reservations.service.ts": 1248,
|
||||
"src/nest/reservations/reservations.service.ts": 1247,
|
||||
"src/nest/trips/trips.service.ts": 1013,
|
||||
"src/nest/vacay/vacay.service.ts": 1440
|
||||
}
|
||||
|
||||
@@ -1192,9 +1192,8 @@ export class ReservationsService {
|
||||
const updated = await this.budget.updateBudgetItem(existing.id, tripId, { name: itemName, category, total_price: entry.total_price });
|
||||
this.sendCost(tripId, { event: 'budget:updated', payload: { item: updated } }, socketId, collect);
|
||||
} else {
|
||||
const item = await this.budget.createBudgetItem(tripId, { name: itemName, category, total_price: entry.total_price });
|
||||
await this.budgetItemsRepo.setReservationId(item.id, id);
|
||||
item.reservation_id = Number(id);
|
||||
// The link travels on the insert, so a cost is never written without its booking.
|
||||
const item = await this.budget.linkBudgetItemToReservation(tripId, Number(id), { name: itemName, category, total_price: entry.total_price! });
|
||||
this.sendCost(tripId, { event: 'budget:created', payload: { item } }, socketId, collect);
|
||||
}
|
||||
} catch (err) {
|
||||
|
||||
@@ -695,16 +695,16 @@ describe('ReservationsService (DI-native, real SQL)', () => {
|
||||
expect(broadcast).toHaveBeenCalledWith(String(trip.id), 'budget:updated', { item: { id: item.id } }, 'sock');
|
||||
});
|
||||
|
||||
it('creates + links a new item when none exists, using the current title fallback', async () => {
|
||||
it('creates a new item linked on its insert when none exists, using the current title fallback', async () => {
|
||||
const { trip } = ownerTrip();
|
||||
const res = createReservation(testDb, trip.id);
|
||||
const created = createBudgetItem(testDb, trip.id); // the row the mocked create "returns"
|
||||
budget.createBudgetItem.mockReturnValue({ id: created.id });
|
||||
budget.linkBudgetItemToReservation.mockReturnValue({ id: 31, reservation_id: res.id });
|
||||
await svc.syncBudgetOnUpdate(String(trip.id), String(res.id), '', undefined, 'Old title', 'flight', { total_price: 120 }, 'sock');
|
||||
expect(budget.createBudgetItem).toHaveBeenCalledWith(String(trip.id), { name: 'Old title', category: 'flight', total_price: 120 });
|
||||
// The service back-links the created item to the reservation itself.
|
||||
expect(testDb.prepare('SELECT reservation_id FROM budget_items WHERE id = ?').get(created.id)).toEqual({ reservation_id: res.id });
|
||||
expect(broadcast).toHaveBeenCalledWith(String(trip.id), 'budget:created', { item: { id: created.id, reservation_id: res.id } }, 'sock');
|
||||
// One statement carries the link: no unlinked insert followed by a separate
|
||||
// back-link that a swallowed failure inside updateWithCost could leave half done.
|
||||
expect(budget.linkBudgetItemToReservation).toHaveBeenCalledWith(String(trip.id), res.id, { name: 'Old title', category: 'flight', total_price: 120 });
|
||||
expect(budget.createBudgetItem).not.toHaveBeenCalled();
|
||||
expect(broadcast).toHaveBeenCalledWith(String(trip.id), 'budget:created', { item: { id: 31, reservation_id: res.id } }, 'sock');
|
||||
});
|
||||
|
||||
it('RESV-TX-001: updateWithCost rolls the booking edit back when its cost write fails', async () => {
|
||||
|
||||
Reference in New Issue
Block a user