public BookEventResponse BookEvent(long hostId, BookEventRequest value, out string status) { BookEventResponse result = null; //Validate if customer exist CustomerServices customerServices = new CustomerServices(); var customer = customerServices.GetCustomerByRef(hostId, value.CustomerReferenceId); if (customer == null) { status = BookEventStatuses.CustomerNotFound; return(null); } //Validate if event and tier exist EventsServices eventsServices = new EventsServices(); EventInfo eventInfo = eventsServices.GetEventByRef(hostId, value.EventReferenceId); if (eventInfo == null) { status = BookEventStatuses.EventNotFound; return(null); } List <EventTierInfo> eventTiers = eventsServices.GetEventTiersByEventId(eventInfo.EventId.Value); if (eventTiers == null && eventTiers.Count == 0) { status = BookEventStatuses.EventNotFound; return(null); } //Validate event status if (eventInfo.Status != "Active") { status = BookEventStatuses.EventNotActive; return(null); } //Validate if event has already started if (DateTime.UtcNow >= eventInfo.StartDate) { status = BookEventStatuses.EventHasAlreadyStarted; return(null); } //Validate if all requested tiers exist List <string> allAvailableEventTiers = eventTiers.Select(x => x.ReferenceId).ToList(); List <string> requestedEventTiers = value.Tickets.Select(x => x.EventTierReferenceId).ToList(); bool contained = !requestedEventTiers.Except(allAvailableEventTiers).Any(); if (!contained) { status = BookEventStatuses.TierNotFound; return(null); } //Validate requested ticket quantities (must be more than zero) if (value.Tickets.Where(x => x.Quantity < 1).Count() > 0) { status = BookEventStatuses.InvalidTicketQuantity; return(null); } //Validate if tickets are still available for the requested quantities foreach (var ticket in value.Tickets) { var tier = eventTiers.Where(x => x.ReferenceId == ticket.EventTierReferenceId).ToList()[0]; if (tier.AvailableTickets < ticket.Quantity) { status = BookEventStatuses.InsufficientTickets; return(null); } } //Calculate total cost decimal totalCost = 0; foreach (var ticket in value.Tickets) { var tier = eventTiers.Where(x => x.ReferenceId == ticket.EventTierReferenceId).ToList()[0]; totalCost += (ticket.Quantity * tier.Price.Value); } //Check customer wallet balance if (customer.WalletBalance < totalCost) { status = BookEventStatuses.CustomerInsufficientFunds; return(null); } //TODO: Transaction lock for thread safety string bookingConfirmation = null; string ticketNumber = null; string ticketUniqueId = null; List <KeyValuePair <long, string> > tierTicketNumbers = new List <KeyValuePair <long, string> >(); //Insert customer booking bookingConfirmation = GenerateBookingConfirmation(hostId); long bookingId = InsertUserBooking(customer.CustomerId.Value, eventInfo.EventId.Value, bookingConfirmation); //Perform transaction WalletServices walletService = new WalletServices(); walletService.Transfer(customer.WalletAddress, eventInfo.WalletAddress, totalCost, bookingId, "Booking"); //Insert customer tickets foreach (var ticketPurchase in value.Tickets) { var tier = eventTiers.Where(x => x.ReferenceId == ticketPurchase.EventTierReferenceId).ToList()[0]; for (int i = 0; i < ticketPurchase.Quantity; i++) { ticketNumber = GenerateTicketNumber(eventInfo.EventId.Value); ticketUniqueId = HashUtility.GenerateHash(); InsertUserTicket(customer.CustomerId.Value, bookingId, eventInfo.EventId.Value, tier.TierId.Value, ticketNumber, tier.Price.Value, "Active", ticketUniqueId); tierTicketNumbers.Add(new KeyValuePair <long, string>(tier.TierId.Value, ticketNumber)); } } //Update tickets availability foreach (var ticket in value.Tickets) { var tier = eventTiers.Where(x => x.ReferenceId == ticket.EventTierReferenceId).ToList()[0]; UpdateAvailableTickets(tier.TierId.Value, tier.AvailableTickets.Value - ticket.Quantity); } //Commit to blockchain ContractApi blockchainContract = new ContractApi(); for (int i = 0; i < value.Tickets.Count; i++) { var ticket = value.Tickets[i]; var tier = eventTiers .Where(x => x.ReferenceId == ticket.EventTierReferenceId).ToList()[0]; List <string> ticketNumbers = tierTicketNumbers .Where(x => x.Key == tier.TierId.Value) .Select(x => x.Value).ToList(); // Update: Use BookEventV2 method on smart contract //blockchainContract.BookEvent(customer.CustomerAddress, eventInfo.EventUniqueId, tier.TierUniqueId, ticketNumbers); foreach (string number in ticketNumbers) { blockchainContract.BookEventV2(customer.CustomerAddress, eventInfo.EventUniqueId, tier.TierUniqueId, number); } } result = new BookEventResponse(); result.ConfirmationNumber = bookingConfirmation; result.TicketNumbers = tierTicketNumbers.Select(x => x.Value).ToList(); status = BookEventStatuses.Success; return(result); }
//TODO: performance optimize this method to cancel tickets in bulk public CancelTicketResponse CancelAndRefundTicket(long hostId, long ticketId, out string status) { CancelTicketResponse result = null; AdmissionServices admissionServices = new AdmissionServices(); //Get ticket info var ticket = admissionServices.GetTicketById(ticketId); if (ticket == null) { status = CancelTicketStatuses.TicketNotFound; return(null); } if (ticket.Status == TicketStatuses.Used) { status = CancelTicketStatuses.TicketAlreadyUsed; return(null); } if (ticket.Status == TicketStatuses.Cancelled) { status = CancelTicketStatuses.TicketAlreadyCancelled; return(null); } //Get event info var eventInfo = GetEventByRef(hostId, ticket.EventReferenceId); if (eventInfo == null) { status = CancelTicketStatuses.EventNotFound; return(null); } //Validate event status if (eventInfo.Status != EventStatuses.Active) { status = CancelTicketStatuses.EventNotActive; return(null); } //Validate if event start date is over if (DateTime.UtcNow >= eventInfo.StartDate) { status = CancelTicketStatuses.EventHasAlreadyStarted; return(null); } //Get event tier EventsServices eventsServices = new EventsServices(); var eventTier = eventsServices.GetEventTiersByRef(hostId, ticket.TierReferenceId); if (eventTier == null) { status = CancelTicketStatuses.TierNotFound; return(null); } //Get customer info CustomerServices customerServices = new CustomerServices(); var customer = customerServices.GetCustomerByRef(hostId, ticket.CustomerReferenceId); if (customer == null) { status = CancelTicketStatuses.CustomerNotFound; return(null); } //Refund the customer using funds from the event address WalletServices walletServices = new WalletServices(); walletServices.Transfer(eventInfo.WalletAddress, customer.WalletAddress, ticket.PaidPrice.Value, ticket.BookingId, "Refund"); //Update ticket status to cancelled admissionServices.UpdateTicketStatus(ticketId, TicketStatuses.Cancelled); //Update ticket availability BookingServices bookingServices = new BookingServices(); bookingServices.UpdateAvailableTickets(eventTier.TierId.Value, eventTier.AvailableTickets.Value + 1); //Commit to blockchain ContractApi blockchainContract = new ContractApi(); blockchainContract.CancelTicket(ticket.TicketNo); status = CancelEventStatuses.Success; result = new CancelTicketResponse(); result.EventTitle = ticket.EventTitle; result.TierTitle = ticket.TierTitle; result.PaidPrice = ticket.PaidPrice; result.NewTicketStatus = TicketStatuses.Cancelled; return(result); }