All files / apps/web/src/handlers/receipt-participants remove.ts

100% Statements 21/21
100% Branches 10/10
100% Functions 5/5
100% Lines 21/21

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94              6x                         6x 6x           6x 1x         5x 1x         4x           4x 1x         3x 1x         2x           2x 1x         1x 1x     1x 1x               1x     1x                
import { TRPCError } from "@trpc/server";
import { z } from "zod";
 
import { getReceiptParticipant } from "~web/handlers/receipt-participants/utils";
import { authProcedure } from "~web/handlers/trpc";
import { peerIdSchema, receiptIdSchema } from "~web/handlers/validation";
 
export const procedure = authProcedure
	.meta({
		title: "Remove receipt participant",
		description:
			"Removes a peerId as a participant of a given receipt, along with their item consumptions.",
	})
	.input(
		z.strictObject({
			receiptId: receiptIdSchema,
			peerId: peerIdSchema,
		}),
	)
	.mutation(async ({ input, ctx }) => {
		const { database } = ctx;
		const receipt = await database
			.selectFrom("receipts")
			.select(["ownerUserId"])
			.where("id", "=", input.receiptId)
			.limit(1)
			.executeTakeFirst();
		if (!receipt) {
			throw new TRPCError({
				code: "NOT_FOUND",
				message: `Receipt "${input.receiptId}" does not exist.`,
			});
		}
		if (receipt.ownerUserId !== ctx.auth.userId) {
			throw new TRPCError({
				code: "FORBIDDEN",
				message: `Not enough rights to remove participant from receipt "${input.receiptId}".`,
			});
		}
		const peer = await database
			.selectFrom("peers")
			.select("ownerUserId")
			.where("id", "=", input.peerId)
			.limit(1)
			.executeTakeFirst();
		if (!peer) {
			throw new TRPCError({
				code: "NOT_FOUND",
				message: `Peer "${input.peerId}" does not exist.`,
			});
		}
		if (peer.ownerUserId !== ctx.auth.userId) {
			throw new TRPCError({
				code: "FORBIDDEN",
				message: `Peer "${input.peerId}" is not owned by "${ctx.auth.email}".`,
			});
		}
		const receiptParticipant = await getReceiptParticipant(
			database,
			input.peerId,
			input.receiptId,
			["peerId"],
		);
		if (!receiptParticipant) {
			throw new TRPCError({
				code: "CONFLICT",
				message: `Peer "${input.peerId}" does not participate in receipt "${input.receiptId}".`,
			});
		}
		await database.transaction().execute(async (tx) => {
			await tx
				.deleteFrom("receiptItemConsumers")
				.where((eb) =>
					eb("peerId", "=", input.peerId).and("itemId", "in", (ebb) =>
						ebb
							.selectFrom("receiptItems")
							.where("receiptId", "=", input.receiptId)
							.select("id"),
					),
				)
 
				.executeTakeFirst();
			await tx
				.deleteFrom("receiptParticipants")
				.where((eb) =>
					eb.and({
						receiptId: input.receiptId,
						peerId: input.peerId,
					}),
				)
				.executeTakeFirst();
		});
	});