Skip to content

Latest commit

 

History

History
260 lines (221 loc) · 8.71 KB

File metadata and controls

260 lines (221 loc) · 8.71 KB
class TicketManagement {
  constructor(db) {
    this.db = db;
    this.g_max_person_id = null;
    this.g_min_person_id = null;
  }

async sellTickets(person_id, event_id, quantity = 1) {
  const notEnoughSeats = new Error('not_enough_seats');
  const p_person_id = person_id;
  const p_event_id = event_id;
  const p_quantity = quantity;

  let r_seat_level, r_seat_section, r_seat_row;
  let event_rec;

  try {
    event_rec = await this.get_event_details(p_event_id);

    const seatData = await this.db.collection('sportingEventTicket').aggregate([
      { $match: { sportingEventId: p_event_id, ticketholderId: null } },
      { $group: { _id: { seatLevel: "$seatLevel", seatSection: "$seatSection", seatRow: "$seatRow" }, count: { $sum: 1 } } },
      { $match: { count: { $gte: p_quantity } } },
      { $limit: 1 },
      { $project: { _id: 0, seatLevel: "$_id.seatLevel", seatSection: "$_id.seatSection", seatRow: "$_id.seatRow" } }
    ]).toArray();

    if (seatData.length === 0) throw notEnoughSeats;

    r_seat_level = seatData[0].seatLevel;
    r_seat_section = seatData[0].seatSection;
    r_seat_row = seatData[0].seatRow;

    const adjacentSeatsCursor = this.db.collection('sportingEventTicket').find({
      sportingEventId: p_event_id,
      seatLevel: r_seat_level,
      seatSection: r_seat_section,
      seatRow: r_seat_row
    }).sort({ seatLevel: 1, seatSection: 1, seatRow: 1 });

    for (let i = 0; i < p_quantity; i++) {
      const cur_ticket = await adjacentSeatsCursor.next();
      if (!cur_ticket) throw notEnoughSeats;

      await this.db.collection('sportingEventTicket').updateOne(
        { _id: cur_ticket._id },
        { $set: { ticketholderId: p_person_id } }
      );

      await this.db.collection('ticketPurchaseHist').insertOne({
        sportingEventTicketId: cur_ticket.id,
        purchasedById: p_person_id,
        transactionDateTime: new Date(),
        purchasePrice: cur_ticket.ticketPrice
      });
    }

  } catch (err) {
    if (err === notEnoughSeats) {
      console.log(`Sorry, there aren't ${p_quantity} adjacent seats for event:`);
      console.log(`   ${event_rec.home_team_name} VS ${event_rec.away_team_name}   (${event_rec.sport_name})`);
      console.log(`   ${event_rec.home_field}:  ${event_rec.date_time.toLocaleString('en-GB', { day: '2-digit', month: 'short', year: 'numeric', hour: '2-digit', minute: '2-digit' })}`);
    } else {
      throw err;
    }
  }
}

async $transferTicket(ticket_id, new_ticketholder_id, transfer_all = false, price = null) {
  const p_ticket_id = ticket_id;
  const p_new_ticketholder_id = new_ticketholder_id;
  const p_price = price;
  const xferall = transfer_all ? 1 : 0;

  try {
    const ticket = await this.db.collection('sportingEventTicket').findOne({ id: p_ticket_id });
    if (!ticket) throw new Error('Ticket not found');

    const lastTransaction = await this.db.collection('ticketPurchaseHist').aggregate([
      { $match: { purchased_by_id: ticket.ticketholderId, $or: [{ sporting_event_ticket_id: p_ticket_id }, { xferall: 1 }] } },
      { $group: { _id: '$ticketholderId', last_txn_date: { $max: '$transaction_date_time' } } }
    ]).toArray();

    if (lastTransaction.length === 0) throw new Error('No transaction found');

    const old_ticketholder_id = ticket.ticketholderId;
    const last_txn_date = lastTransaction[0].last_txn_date;

    const transactions = await this.db.collection('ticketPurchaseHist').find({
      purchased_by_id: old_ticketholder_id,
      transaction_date_time: last_txn_date
    }).toArray();

    for (const xrec of transactions) {
      await this.db.collection('sportingEventTicket').updateOne(
        { id: xrec.sporting_event_ticket_id },
        { $set: { ticketholderId: p_new_ticketholder_id } }
      );

      await this.db.collection('ticketPurchaseHist').insertOne({
        sporting_event_ticket_id: xrec.sporting_event_ticket_id,
        purchased_by_id: p_new_ticketholder_id,
        transferred_from_id: old_ticketholder_id,
        transaction_date_time: new Date(),
        purchase_price: p_price !== null ? p_price : xrec.purchase_price
      });
    }
  } catch (error) {
    console.error(error);
    throw error;
  }
}

async generateTicketActivity(transaction_delay, max_transactions = 1000) {
  let txn_count = 0;
  while (txn_count < max_transactions) {
    await this.sellRandomTickets();
    txn_count += 1;
    await new Promise(resolve => setTimeout(resolve, transaction_delay * 1000));
  }
}

async generateTransferActivity(transaction_delay = 5, max_transactions = 100) {
  let txn_count = 0;
  let min_tik_id, max_tik_id, tik_id, new_ticketholder, xfer_all, chg_price, new_price;

  while (txn_count < max_transactions) {
    const minMaxResult = await this.db.collection('ticketPurchaseHist').aggregate([
      {
        $group: {
          _id: null,
          min_tik_id: { $min: "$sportingEventTicketId" },
          max_tik_id: { $max: "$sportingEventTicketId" }
        }
      }
    ]).toArray();

    if (minMaxResult.length === 0) {
      console.log('No tickets available to transfer.');
      return;
    }

    min_tik_id = minMaxResult[0].min_tik_id;
    max_tik_id = minMaxResult[0].max_tik_id;

    const tikResult = await this.db.collection('ticketPurchaseHist').aggregate([
      {
        $match: {
          sportingEventTicketId: { $lte: Math.random() * (max_tik_id - min_tik_id) + min_tik_id }
        }
      },
      {
        $group: {
          _id: null,
          tik_id: { $max: "$sportingEventTicketId" }
        }
      }
    ]).toArray();

    if (tikResult.length === 0) {
      console.log('No tickets available to transfer.');
      return;
    }

    tik_id = tikResult[0].tik_id;

    new_ticketholder = Math.floor(Math.random() * (this.g_max_person_id - this.g_min_person_id) + this.g_min_person_id);

    xfer_all = Math.round(Math.random() * 4) < 4;

    new_price = null;

    chg_price = Math.round(Math.random() * 2) === 0;
    if (chg_price) {
      const priceResult = await this.db.collection('sportingEventTicket').findOne({ id: tik_id });
      new_price = Math.random() * (1.2 - 0.8) + 0.8 * priceResult.ticketPrice;
    }

    await this.transferTicket(tik_id, new_ticketholder, xfer_all, new_price);

    txn_count++;
    await new Promise(resolve => setTimeout(resolve, transaction_delay * 1000));
  }
}

async $get_event_details(event_id) {
  const p_event_id = event_id;
  const result = await this.db.collection('sportingEvent').aggregate([
    {
      $match: { id: p_event_id }
    },
    {
      $lookup: {
        from: 'sportTeam',
        localField: 'homeTeamId',
        foreignField: 'id',
        as: 'home_team'
      }
    },
    {
      $lookup: {
        from: 'sportTeam',
        localField: 'awayTeamId',
        foreignField: 'id',
        as: 'away_team'
      }
    },
    {
      $lookup: {
        from: 'sportLocation',
        localField: 'locationId',
        foreignField: 'id',
        as: 'location'
      }
    },
    {
      $unwind: '$home_team'
    },
    {
      $unwind: '$away_team'
    },
    {
      $unwind: '$location'
    },
    {
      $project: {
        sport_name: '$sportTypeName',
        home_team_name: '$home_team.name',
        away_team_name: '$away_team.name',
        home_field: '$location.name',
        date_time: '$startDateTime'
      }
    }
  ]).toArray();

  if (result.length === 0) {
    throw new Error('Event not found');
  }

  return result[0];
}

async sellRandomTickets() {
  const eventTab = await this.get_open_events();
  const row_ct = eventTab.length;
  const event_idx = Math.floor(Math.random() * row_ct);
  const event_id = eventTab[event_idx].id;
  const ticket_holder = Math.floor(Math.random() * (this.g_max_person_id - this.g_min_person_id + 1)) + this.g_min_person_id;
  const quantity = Math.floor(Math.random() * 6) + 1;
  await this.sellTickets(ticket_holder, event_id, quantity);
}

async get_open_events() {
  const openEvents = await this.db.collection('sportingEvent').find({ soldOut: 0 }).sort({ startDateTime: 1 }).toArray();
  return openEvents;
}
}