1- import { eq } from "drizzle-orm" ;
21import { GraphQLError } from "graphql" ;
32
43import { builder } from "~/builder" ;
@@ -8,16 +7,20 @@ import {
87 userTicketsSchema ,
98} from "~/datasources/db/schema" ;
109import { applicationError , ServiceErrors } from "~/errors" ;
11- import { sendTicketInvitationEmails } from "~/notifications/tickets" ;
10+ import {
11+ sendActualUserTicketQREmails ,
12+ sendTicketInvitationEmails ,
13+ } from "~/notifications/tickets" ;
1214import { createInitialPurchaseOrder } from "~/schema/purchaseOrder/helpers" ;
1315import { UserTicketRef } from "~/schema/shared/refs" ;
1416import { ticketsFetcher } from "~/schema/ticket/ticketsFetcher" ;
1517
1618const GiftTicketsToUserInput = builder . inputType ( "GiftTicketsToUserInput" , {
1719 fields : ( t ) => ( {
18- ticketId : t . string ( { required : true } ) ,
20+ ticketIds : t . stringList ( { required : true } ) ,
1921 userIds : t . stringList ( { required : true } ) ,
2022 allowMultipleTicketsPerUsers : t . boolean ( { required : true } ) ,
23+ autoApproveTickets : t . boolean ( { required : true } ) ,
2124 notifyUsers : t . boolean ( { required : true } ) ,
2225 } ) ,
2326} ) ;
@@ -43,8 +46,13 @@ builder.mutationField("giftTicketsToUsers", (t) =>
4346 throw new GraphQLError ( "User not found" ) ;
4447 }
4548
46- const { ticketId, allowMultipleTicketsPerUsers, notifyUsers } = input ;
47- let userIds = input . userIds ;
49+ const {
50+ ticketIds,
51+ allowMultipleTicketsPerUsers,
52+ notifyUsers,
53+ autoApproveTickets,
54+ userIds,
55+ } = input ;
4856
4957 if ( userIds . length === 0 ) {
5058 throw applicationError (
@@ -54,46 +62,92 @@ builder.mutationField("giftTicketsToUsers", (t) =>
5462 ) ;
5563 }
5664
57- const tickets = await ticketsFetcher . searchTickets ( {
65+ const actualTickets = await ticketsFetcher . searchTickets ( {
5866 DB ,
5967 search : {
60- ticketIds : [ ticketId ] ,
68+ ticketIds,
6169 } ,
6270 } ) ;
71+ const actualTicketIds = actualTickets . map ( ( ticket ) => ticket . id ) ;
6372
64- const ticket = tickets [ 0 ] ;
73+ const usersWithTickets = await DB . query . userTicketsSchema . findMany ( {
74+ where : ( u , { and, inArray } ) =>
75+ and (
76+ inArray ( u . userId , userIds ) ,
77+ inArray ( u . ticketTemplateId , actualTicketIds ) ,
78+ ) ,
79+ } ) ;
6580
66- if ( ! ticket ) {
81+ let ticketTemplatesUsersMap = new Map < string , Set < string > > ( ) ;
82+
83+ for ( const ticket of actualTickets ) {
84+ ticketTemplatesUsersMap . set ( ticket . id , new Set ( ) ) ;
85+ }
86+
87+ usersWithTickets . forEach ( ( userWithTicket ) => {
88+ if ( userWithTicket . userId ) {
89+ ticketTemplatesUsersMap
90+ . get ( userWithTicket . ticketTemplateId )
91+ ?. add ( userWithTicket . userId ) ;
92+ }
93+ } ) ;
94+
95+ if ( ticketTemplatesUsersMap . size === 0 ) {
6796 throw applicationError (
6897 "Ticket not found" ,
6998 ServiceErrors . NOT_FOUND ,
7099 logger ,
71100 ) ;
72101 }
73102
103+ if ( ! allowMultipleTicketsPerUsers ) {
104+ const clearedTicketTemplatesUserMap = new Map < string , Set < string > > ( ) ;
105+
106+ ticketTemplatesUsersMap . forEach ( ( existingUserSet , ticketTemplateId ) => {
107+ const newUserSet = new Set < string > ( ) ;
108+
109+ userIds . forEach ( ( userId ) => {
110+ if ( ! existingUserSet . has ( userId ) ) {
111+ newUserSet . add ( userId ) ;
112+ }
113+ } ) ;
114+
115+ clearedTicketTemplatesUserMap . set ( ticketTemplateId , newUserSet ) ;
116+ } ) ;
117+
118+ ticketTemplatesUsersMap = clearedTicketTemplatesUserMap ;
119+ }
120+
121+ if ( userIds . length === 0 ) {
122+ throw applicationError (
123+ "All provided users already have tickets" ,
124+ ServiceErrors . INVALID_ARGUMENT ,
125+ logger ,
126+ ) ;
127+ }
128+
74129 const purchaseOrder = await createInitialPurchaseOrder ( {
75130 DB ,
76131 logger,
77132 userId : USER . id ,
78133 } ) ;
79134
80- if ( ! allowMultipleTicketsPerUsers ) {
81- const usersWithTickets = await DB . query . userTicketsSchema . findMany ( {
82- where : ( u , { and, inArray } ) =>
83- and ( inArray ( u . userId , userIds ) , eq ( u . ticketTemplateId , ticket . id ) ) ,
84- columns : {
85- userId : true ,
86- } ,
87- } ) ;
135+ const ticketsToInsert : ( typeof insertUserTicketsSchema . _type ) [ ] = [ ] ;
88136
89- const userIdsWithTickets = new Set (
90- usersWithTickets . map ( ( user ) => user . userId ) ,
91- ) ;
137+ ticketTemplatesUsersMap . forEach ( ( userSet , ticketTemplateId ) => {
138+ userSet . forEach ( ( userId ) => {
139+ const parsedData = insertUserTicketsSchema . parse ( {
140+ userId,
141+ ticketTemplateId,
142+ purchaseOrderId : purchaseOrder . id ,
143+ approvalStatus : autoApproveTickets ? "approved" : "gifted" ,
144+ } ) ;
92145
93- userIds = userIds . filter ( ( userId ) => ! userIdsWithTickets . has ( userId ) ) ;
94- }
146+ ticketsToInsert . push ( parsedData ) ;
147+ } ) ;
148+ } ) ;
95149
96- if ( userIds . length === 0 ) {
150+ if ( ! ticketsToInsert . length ) {
97151 throw applicationError (
98152 "All provided users already have tickets" ,
99153 ServiceErrors . INVALID_ARGUMENT ,
@@ -102,29 +156,29 @@ builder.mutationField("giftTicketsToUsers", (t) =>
102156 }
103157
104158 const createdUserTickets = await DB . insert ( userTicketsSchema )
105- . values (
106- userIds . map ( ( userId ) =>
107- insertUserTicketsSchema . parse ( {
108- userId,
109- ticketTemplateId : ticket . id ,
110- purchaseOrderId : purchaseOrder . id ,
111- approvalStatus : "gifted" ,
112- } ) ,
113- ) ,
114- )
159+ . values ( ticketsToInsert )
115160 . returning ( ) ;
116161
117162 if ( notifyUsers ) {
118163 const userTicketIds = createdUserTickets . map (
119164 ( userTicket ) => userTicket . id ,
120165 ) ;
121166
122- await sendTicketInvitationEmails ( {
123- DB ,
124- logger,
125- userTicketIds,
126- RPC_SERVICE_EMAIL ,
127- } ) ;
167+ if ( autoApproveTickets ) {
168+ await sendActualUserTicketQREmails ( {
169+ DB ,
170+ logger,
171+ userTicketIds,
172+ RPC_SERVICE_EMAIL ,
173+ } ) ;
174+ } else {
175+ await sendTicketInvitationEmails ( {
176+ DB ,
177+ logger,
178+ userTicketIds,
179+ RPC_SERVICE_EMAIL ,
180+ } ) ;
181+ }
128182 }
129183
130184 return createdUserTickets . map ( ( userTicket ) =>
0 commit comments