manicanldes-backend/src/checkout/cart.store.ts

97 lines
3.1 KiB
TypeScript

import { Injectable } from '@nestjs/common';
import { AccessStore } from '../identity/access.store';
import type { Principal } from '../identity/identity.types';
import { AppError } from '../common/errors/app-error';
@Injectable()
export class CartStore {
constructor(private readonly access: AccessStore) {}
get(actor: Principal) {
return this.access.mutate(actor, null, async (tx) => {
const cart = await tx.cart.upsert({
where: {
userId_organizationId: {
userId: actor.userId,
organizationId: actor.organizationId,
},
},
create: { userId: actor.userId, organizationId: actor.organizationId },
update: {},
});
const lines = await tx.cartLine.findMany({
where: { cartId: cart.id },
orderBy: { id: 'asc' },
select: {
variantId: true,
quantity: true,
variant: {
select: {
name: true,
sku: true,
price: true,
currency: true,
active: true,
product: { select: { name: true, status: true } },
},
},
},
});
return { version: cart.version, lines };
});
}
set(actor: Principal, variantId: string, version: number, quantity: number) {
return this.access.mutate(actor, null, async (tx) => {
const cart = await tx.cart.upsert({
where: {
userId_organizationId: {
userId: actor.userId,
organizationId: actor.organizationId,
},
},
create: { userId: actor.userId, organizationId: actor.organizationId },
update: {},
});
if (cart.version !== version) throw new AppError('CART_CHANGED');
if (quantity === 0) {
await tx.cartLine.deleteMany({ where: { cartId: cart.id, variantId } });
} else {
const variant = await tx.productVariant.findFirst({
where: {
id: variantId,
organizationId: actor.organizationId,
active: true,
product: { status: 'PUBLISHED' },
},
});
if (!variant) throw new AppError('CART_ITEM_UNAVAILABLE');
const lines = await tx.cartLine.findMany({
where: { cartId: cart.id },
include: { variant: true },
});
if (lines.some((line) => line.variant.currency !== variant.currency))
throw new AppError('CART_CURRENCY');
if (
lines.length >= 20 &&
!lines.some((line) => line.variantId === variantId)
)
throw new AppError('CART_LIMIT');
await tx.cartLine.upsert({
where: { cartId_variantId: { cartId: cart.id, variantId } },
create: {
cartId: cart.id,
organizationId: actor.organizationId,
variantId,
quantity,
},
update: { quantity },
});
}
await tx.cart.update({
where: { id: cart.id },
data: { version: { increment: 1 } },
});
return { version: version + 1 };
});
}
}