import { Inject, Injectable } from '@nestjs/common'; import { Pothos, PothosRef, PothosSchema, SchemaBuilderToken, } from '@smatch-corp/nestjs-pothos'; import { Builder } from '../Graphql/graphql.builder'; import { PrismaService } from '../Prisma/prisma.service'; import { OrderStatus } from '@prisma/client'; @Injectable() export class OrderSchema extends PothosSchema { constructor( @Inject(SchemaBuilderToken) private readonly builder: Builder, private readonly prisma: PrismaService, ) { super(); } // Types section @PothosRef() order() { return this.builder.prismaObject('Order', { description: 'An order in the system.', fields: (t) => ({ id: t.exposeID('id', { description: 'The ID of the order.', }), userId: t.exposeID('userId', { description: 'The ID of the user.', }), paymentId: t.exposeString('paymentId', { description: 'The ID of the payment.', }), serviceId: t.exposeID('serviceId', { description: 'The ID of the service.', }), status: t.expose('status', { type: OrderStatus, description: 'The status of the order.', }), total: t.exposeInt('total', { description: 'The total price of the order.', }), scheduleId: t.exposeID('scheduleId', { description: 'The ID of the schedule.', }), createdAt: t.expose('createdAt', { type: 'DateTime', description: 'The date and time the order was created.', }), updatedAt: t.expose('updatedAt', { type: 'DateTime', description: 'The date and time the order was updated.', }), user: t.relation('user', { description: 'The user who made the order.', }), payment: t.relation('payment', { description: 'The payment for the order.', }), service: t.relation('service', { description: 'The service for the order.', }), refundTicket: t.relation('refundTicket', { description: 'The refund ticket for the order.', }), schedule: t.relation('schedule', { description: 'The schedule for the order.', }), }), }); } @Pothos() init(): void { // query section this.builder.queryFields((t) => ({ orders: t.prismaField({ type: [this.order()], description: 'Retrieve a list of orders with optional filtering, ordering, and pagination.', args: this.builder.generator.findManyArgs('Order'), resolve: async (query, root, args, ctx, info) => { return await this.prisma.order.findMany({ ...query, take: args.take ?? undefined, skip: args.skip ?? undefined, orderBy: args.orderBy ?? undefined, where: args.filter ?? undefined, }); }, }), order: t.prismaField({ type: this.order(), args: this.builder.generator.findUniqueArgs('Order'), description: 'Retrieve a single order by its unique identifier.', resolve: async (query, root, args, ctx, info) => { return await this.prisma.order.findUnique({ ...query, where: args.where, }); }, }), })); // mutation section this.builder.mutationFields((t) => ({ createOrder: t.prismaField({ type: this.order(), description: 'Create a new order.', args: { data: t.arg({ type: this.builder.generator.getCreateInput('Order', [ 'id', 'user', 'paymentId', 'payment', 'refundTicket', 'status', 'total', 'createdAt', 'updatedAt', ]), required: true, }), }, resolve: async (query, root, args, ctx, info) => { return this.prisma.$transaction(async (prisma) => { const order = await prisma.order.create({ ...query, data: args.data, }); // check if service is valid if (!args.data.service.connect) { throw new Error('Service not found'); } // check if service price is free if (args.data.service.connect.price === 0) { return order; } // generate payment code by prefix 'EPESS' + 6 hex digits const paymentCode = 'EPESS' + Math.random().toString(16).slice(2, 8); // create payment await prisma.payment.create({ data: { orderId: order.id, amount: args.data.service.connect.price as number, paymentCode: paymentCode, expiredAt: new Date(Date.now() + 1000 * 60 * 60 * 24), }, }); return order; }); }, }), deleteOrder: t.prismaField({ type: this.order(), description: 'Delete an existing order.', args: { where: t.arg({ type: this.builder.generator.getWhereUnique('Order'), required: true, }), }, resolve: async (query, root, args, ctx, info) => { return await this.prisma.order.delete({ ...query, where: args.where, }); }, }), updateOrder: t.prismaField({ type: this.order(), description: 'Update an existing order.', args: { data: t.arg({ type: this.builder.generator.getUpdateInput('Order', [ 'status', 'total', ]), required: true, }), where: t.arg({ type: this.builder.generator.getWhereUnique('Order'), required: true, }), }, resolve: async (query, root, args, ctx, info) => { return await this.prisma.order.update({ ...query, data: args.data, where: args.where, }); }, }), })); } }