feat: add delete user and change password functioality
CI / build-and-test (push) Canceled after 0s

This commit is contained in:
2026-10-22 23:19:56 +02:00
parent 48ad82acd1
commit 383ba32935
14 changed files with 477 additions and 82 deletions
+50 -2
View File
@@ -1,11 +1,17 @@
import { Injectable } from '@nestjs/common';
import { ConflictException, Injectable, NotFoundException } from '@nestjs/common';
import { v4 as uuidv4 } from 'uuid';
import { PrismaService } from '../prisma/prisma.service';
import { RealtimeService } from '../realtime/realtime.service';
import { customerNameKey } from '../planned-tabs/customer-name';
import { tabSummary } from './tab-state';
import { VenueLedger } from './venue-ledger';
@Injectable()
export class TabsService {
constructor(private prisma: PrismaService) {}
constructor(
private prisma: PrismaService,
private realtime: RealtimeService,
) {}
/** The venue's open tabs as the server holds them; every terminal shows the same. */
async findAll(venueId: string) {
@@ -30,4 +36,46 @@ export class TabsService {
}),
};
}
/**
* Deletes a tab without settling it, as tab_deleted does on a terminal: what is still on it is not paid and stays
* out of the stock. The terminals drop it on their next sync; one that still has unsent drinks for it brings it
* back, so no sale is lost. [expectedVersion] refuses a tab that changed since it was shown.
*/
async remove(venueId: string, tabId: string, expectedVersion: number | undefined, user: { id: string }) {
await this.prisma.$transaction(async (tx) => {
const now = new Date();
const ledger = await VenueLedger.open(tx, venueId);
const tab = ledger.tabs.get(tabId);
if (!tab) {
throw new NotFoundException({ code: 'tab_not_found', message: 'This tab is no longer open' });
}
if (expectedVersion !== undefined && tab.version !== expectedVersion) {
throw new ConflictException({
code: 'version_mismatch',
message: 'The tab has changed since it was loaded. Refresh and try again.',
});
}
const { customerName, totalInCents, items } = tabSummary({ ...tab, updatedAt: now });
ledger.tabs.remove(tabId);
await ledger.save(tx, now);
await tx.auditLog.create({
data: {
id: uuidv4(),
venueId,
actorType: 'client_user',
actorId: user.id,
action: 'tab_deleted',
details: JSON.stringify({ tabId, customerName, amountInCents: totalInCents, items }),
},
});
});
this.realtime.notify(venueId, 'tabs');
return { ok: true };
}
}