manicanldes-backend/src/catalog/variant.store.ts

58 lines
1.8 KiB
TypeScript

import { Injectable } from '@nestjs/common';
import { AccessStore } from '../identity/access.store';
import { recordAudit } from '../identity/audit';
import type { Principal } from '../identity/identity.types';
import { AppError } from '../common/errors/app-error';
import { editableProduct } from './catalog.helpers';
import type { VariantInput } from './catalog.schemas';
@Injectable()
export class VariantStore {
constructor(private readonly access: AccessStore) {}
save(actor: Principal, productId: string, input: VariantInput, id?: string) {
return this.access.mutate(actor, 'catalog.manage', async (tx) => {
const product = await editableProduct(
tx,
actor.organizationId,
productId,
);
if (
id &&
!(await tx.productVariant.findFirst({
where: { id, productId, organizationId: actor.organizationId },
}))
) {
throw new AppError('VARIANT_NOT_FOUND');
}
if (
!id &&
(await tx.productVariant.count({ where: { productId } })) >= 100
)
throw new AppError('VARIANT_LIMIT');
if (
id &&
!input.active &&
product.status === 'PUBLISHED' &&
!(await tx.productVariant.count({
where: { productId, active: true, id: { not: id } },
}))
) {
throw new AppError('VARIANT_REQUIRED');
}
const variant = id
? await tx.productVariant.update({ where: { id }, data: input })
: await tx.productVariant.create({
data: { ...input, productId, organizationId: actor.organizationId },
});
await recordAudit(
tx,
actor.organizationId,
actor.userId,
id ? 'variant.updated' : 'variant.created',
variant.id,
);
return variant;
});
}
}