97 lines
3.1 KiB
TypeScript
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 };
|
|
});
|
|
}
|
|
}
|