import { UploadedFileTypes } from '@/common/enums/enums' import { RedisKeyMaker } from '@/common/utils/redisKeyMaker' import { GoodSelect, GoodWhereInput } from '@/generated/prisma/models' import { AdminGuildCacheInvalidationService } from '@/modules/admin/guilds/cache/admin-guild-cache-invalidation.service' import { UploaderService } from '@/modules/uploader/uploader.service' import { PrismaService } from '@/prisma/prisma.service' import { RedisService } from '@/redis/redis.service' import { Injectable } from '@nestjs/common' import { ResponseMapper } from 'common/response/response-mapper' import { CreateGuildGoodDto, UpdateGuildGoodDto } from './dto/create-good.dto' @Injectable() export class GoodsService { constructor( private prisma: PrismaService, private readonly uploaderService: UploaderService, private readonly redisService: RedisService, private readonly cacheInvalidationService: AdminGuildCacheInvalidationService, ) {} private readonly listCacheTtlSeconds = 300 private readonly defaultSelect: GoodSelect = { id: true, name: true, pricing_model: true, image_url: true, description: true, sku: { select: { id: true, name: true, code: true, }, }, measure_unit: { select: { id: true, name: true, code: true, }, }, category: { select: { id: true, name: true, }, }, } private readonly defaultWhere = (guild_id: string): GoodWhereInput => ({ is_default_guild_good: true, category: { guild_id, }, }) async findAll(guildId: string) { const cacheKey = RedisKeyMaker.guildGoodsList(guildId) return this.redisService.getAndSet( cacheKey, 'paginate', async () => { const [goods, total] = await this.prisma.$transaction([ this.prisma.good.findMany({ where: this.defaultWhere(guildId), select: this.defaultSelect, }), this.prisma.good.count(), ]) return { items: goods, total } }, this.listCacheTtlSeconds, ) } async findOne(guild_id: string, id: string) { const good = await this.prisma.good.findUnique({ where: { id, ...(this.defaultWhere(guild_id) as any), }, select: this.defaultSelect, }) return ResponseMapper.single(good) } async create(guildId: string, data: CreateGuildGoodDto, file: Express.Multer.File) { const { category_id, measure_unit_id, sku_id, ...rest } = data const good = await this.prisma.$transaction(async tx => { let image_url = '' if (file) { const uploadedUrl = await this.uploaderService.uploadFile( file, UploadedFileTypes.GOOD, ) image_url = uploadedUrl || '' } return await tx.good.create({ data: { ...rest, is_default_guild_good: true, image_url, sku: { connect: { id: sku_id, }, }, measure_unit: { connect: { id: measure_unit_id, }, }, category: { connect: { id: category_id, }, }, }, select: this.defaultSelect, }) }) await this.cacheInvalidationService.invalidateGoodsList(guildId) return ResponseMapper.create(good) } async update( guildId: string, id: string, data: UpdateGuildGoodDto, file: Express.Multer.File, ) { const { category_id, measure_unit_id, sku_id, ...rest } = data const good = await this.prisma.$transaction(async tx => { let image_url = undefined as string | undefined if (file) { const uploadedUrl = await this.uploaderService.uploadFile( file, UploadedFileTypes.GOOD, ) image_url = uploadedUrl || '' } const prevImage = await tx.good.findUnique({ where: { id }, select: { image_url: true }, }) if (image_url && prevImage?.image_url) { this.uploaderService.deleteFile(prevImage.image_url, UploadedFileTypes.GOOD) } return await tx.good.update({ where: { id }, data: { ...rest, is_default_guild_good: true, image_url, sku: { connect: { id: sku_id, }, }, measure_unit: { connect: { id: measure_unit_id, }, }, category: { connect: { id: category_id, }, }, }, select: this.defaultSelect, }) }) await this.cacheInvalidationService.invalidateGoodsList(guildId) return ResponseMapper.create(good) } }