import { Injectable } from '@nestjs/common'; import { PrismaService } from '../../prisma/prisma.service'; import { Order } from '../../prisma/generated/client'; import { OrderWithLinesInput } from '../../prisma/customObjects/prisma.custom.object'; import { OrderStatus } from '../models/orderStatus'; /** Database access to orders. Hiboutik sales are matched by `hiboutikSaleId`. */ @Injectable() export class OrderDatabaseRepository { constructor(private readonly prisma: PrismaService) {} /** Among `hiboutikSaleIds`, the ones already stored as completed orders. */ async getCompletedSaleIds(hiboutikSaleIds: number[]): Promise> { if (hiboutikSaleIds.length === 0) return new Set(); const orders = await this.prisma.order.findMany({ where: { hiboutikSaleId: { in: hiboutikSaleIds }, status: OrderStatus.COMPLETED }, select: { hiboutikSaleId: true }, }); return new Set(orders.map((order) => order.hiboutikSaleId).filter((id): id is number => id !== null)); } /** * Creates or updates the order with the same `hiboutikSaleId`, replacing all its lines (atomically). * Each line is linked to the current product version matching its Hiboutik product and size, if it still exists. * On update, `source` is kept: a website order sent to Hiboutik stays WEB. */ async upsert(order: OrderWithLinesInput): Promise { if (order.hiboutikSaleId == null) throw new Error('Cannot upsert an order without hiboutikSaleId'); const { lines, source, ...orderFields } = order; const linkedLines = await this.linkToProductVersions(lines); return this.prisma.order.upsert({ where: { hiboutikSaleId: order.hiboutikSaleId }, create: { ...orderFields, source, lines: { create: linkedLines } }, update: { ...orderFields, // an undefined relation is ignored by Prisma on update: explicitly unlink a customer removed from the sale customer: orderFields.customer ?? { disconnect: true }, lines: { deleteMany: {}, create: linkedLines }, }, }); } private async linkToProductVersions(lines: OrderWithLinesInput['lines']): Promise { if (lines.length === 0) return lines; const versions = await this.prisma.productVersion.findMany({ where: { OR: lines.map((line) => ({ hiboutikSizeId: line.hiboutikSizeId, product: { hiboutikId: line.hiboutikProductId } })), }, select: { id: true, hiboutikSizeId: true, product: { select: { hiboutikId: true } } }, }); const versionIds = new Map(versions.map((version) => [`${version.product.hiboutikId}:${version.hiboutikSizeId}`, version.id])); return lines.map((line) => { const versionId = versionIds.get(`${line.hiboutikProductId}:${line.hiboutikSizeId}`); return versionId ? { ...line, productVersion: { connect: { id: versionId } } } : line; }); } }