62 lines
2.8 KiB
TypeScript
62 lines
2.8 KiB
TypeScript
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<Set<number>> {
|
|
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<Order> {
|
|
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<OrderWithLinesInput['lines']> {
|
|
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;
|
|
});
|
|
}
|
|
}
|