Source: ZEventsApiEventTickets/ZEventsApiEventTickets.js

import ifPromise from 'onyx-common/ifPromise'
import hasKey from 'onyx-common/hasKey'
import normalizeCurrency from 'onyx-common/normalizeCurrency'
import formatCurrency from 'onyx-common/formatCurrency'

const ZEventsApiEventTickets = ({ prototype }) => {
  prototype.mapApiStatus = function (status) {
    const statusMap = this.API_STATUS_MAP

    if (!hasKey(statusMap, status)) return undefined

    return statusMap[status]
  }

  prototype._checkinPhysicalEventTicket = function ({ id, ...rest }) {
    const payload = {
      url: this.getUrl(`/api/v1/event_tickets/${id}/checkin/physical`),
      method: 'POST',
      requestType: 'json',
      data: rest
    }

    return this.authenticatedFetchWrap(payload)
  }

  /**
   * @function checkinPhysicalEventTicket
   * @param {object} payload - The payload
   * @param {number} payload.id - ticket id
   * @param {number} payload.credentialsId - credentials to tag the ticket with
   * @returns {void}
   * @example
   *
   * checkinPhysicalEventTicket({
   *   id: 2,
   *   credentialsId: 894848
   * })
   */

  prototype.checkinPhysicalEventTicket = function (payload) {
    const finalPayload = {
      id: payload.id
    }

    if (hasKey(payload, 'credentialsId')) finalPayload.credentials_id = payload.credentialsId

    const raw = ifPromise(payload, () => this._checkinPhysicalEventTicket(finalPayload))
    return raw
      .catch(error => this.onError('checkinPhysicalEventTicket', error))
  }

  prototype._checkinVirtualEventTicket = function ({ id }) {
    const payload = {
      url: this.getUrl(`/api/v1/event_tickets/${id}/checkin/virtual`),
      method: 'POST'
    }

    return this.authenticatedFetchWrap(payload)
  }

  /**
   * @function checkinVirtualEventTicket
   * @param {object} payload - The payload
   * @param {number} payload.id - ticket id
   * @returns {void}
   * @example
   *
   * checkinVirtualEventTicket({
   *   id: 2
   * })
   */

  prototype.checkinVirtualEventTicket = function (payload) {
    const finalPayload = {
      id: payload.id
    }

    const raw = ifPromise(payload, () => this._checkinVirtualEventTicket(finalPayload))
    return raw
      .catch(error => this.onError('checkinVirtualEventTicket', error))
  }

  prototype._claimEventTicket = function ({ id, ...rest }) {
    const payload = {
      url: this.getUrl(`/api/v1/event_tickets/${id}/claim`),
      method: 'POST',
      requestType: 'json',
      data: rest
    }

    return this.authenticatedFetchWrap(payload)
  }

  /**
   * @function claimEventTicket
   * @param {object} payload - The payload
   * @param {number} payload.id - ticket id
   * @param {string} payload.giftToken - token needed to claim ticket
   * @returns {void}
   * @example
   *
   * claimEventTicket({
   *   id: 2,
   *   giftToken: '282828282asdfdsafjalsdfj8'
   * })
   */

  prototype.claimEventTicket = function (payload) {
    const finalPayload = {
      id: payload.id,
      gift_token: payload.giftToken
    }

    const raw = ifPromise(payload, () => this._claimEventTicket(finalPayload))
    return raw
      .catch(error => {
        const mapErrors = {
          'Ticket is already claimed': 'EVENT_TICKET_ALREADY_CLAIMED'
        }
        return this.onError('claimEventTicket', error, mapErrors)
      })
  }

  prototype.normalizeClaimEventTicketDetails = function (_data) {
    const data = this.normalizeData(_data)

    const ret = {
      giftedUserEmail: data.gifted_user_email,
      ticketType: parseInt(data.type) === 1 ? 'vip' : 'ga',
      isExistingAccount: !!data['gifted_email_user_exists?'],
      eventData: {
        id: data.event.id,
        description: data.event.description_plain_text,
        descriptionHtml: data.event.description_rich_text,
        startDate: data.event.start_date,
        endDate: data.event.end_date,
        title: data.event.name,
        eventImageUrl: data.event.event_image_url,
        hasImage: !!data.event.has_image,
        promotionalVideoUrl: data.event.embed_code,
        learnMoreUrl: data.event.learn_more_url
      }
    }

    return ret
  }

  prototype._getClaimEventTicketDetails = function ({ id, ...rest }) {
    const payload = {
      url: this.getUrl(`/api/v1/event_tickets/${id}/claim`),
      method: 'GET',
      requestType: 'json',
      data: rest
    }

    return this.fetchWrap(payload)
  }

  /**
   * @typedef {object} EventTicketClaimEvent
   * @property {number} id - event id
   * @property {string} title - event title
   * @property {string} description - event description, plain text
   * @property {string} descriptionHtml - event description, html
   * @property {string} startDate - event start date
   * @property {string} endDate - event end date
   * @property {string} eventImageUrl - cover image for event
   * @property {string} promotionalVideoUrl - url for promo video, takes precedence over cover image if provided
   * @property {boolean} hasImage - eventImageUrl will always return something valid, but does the event have an intentionally added image tied to it?
   */

  /**
   * @typedef {object} ClaimEventTicketDetails
   * @property {string} giftedUserEmail - email address attached to claim
   * @property {boolean} isExistingUser - is this email address tied to an existing kwivrr user?
   * @property {EventTicketClaimEvent} eventData - EventTicketClaimEvent entity
   */

  /**
   * @function getClaimEventTicketDetails
   * @param {object} payload - The payload
   * @param {object} payload.id - The ticket id
   * @param {string} payload.giftToken - gift token hash tied to claim event
   * @returns {ClaimEventTicketDetails} - getClaimEventTicketDetailsReturn
   * @example
   *
   * getClaimEventTicketDetails({
   *   id: 123,
   *   giftToken: 223gfsdfger
   * })
   */
  prototype.getClaimEventTicketDetails = function (payload) {
    const finalPayload = {
      id: payload.ticketId,
      gift_token: payload.giftToken
    }

    const raw = ifPromise(payload, () => this._getClaimEventTicketDetails(finalPayload))
    return raw
      .then(res => this.normalizeClaimEventTicketDetails(res.data))
      .catch(error => {
        const mapErrors = {
          'Invalid gift_token parameter': 'EVENT_TICKET_GIFT_TOKEN_INVALID',
          'Ticket is already claimed': 'EVENT_TICKET_ALREADY_CLAIMED'
        }
        return this.onError('getClaimEventTicketDetails', error, mapErrors)
      })
  }

  prototype._directTransferEventTicket = function ({ id, ...rest }) {
    const payload = {
      url: this.getUrl(`/api/v1/event_tickets/${id}/transfer_direct`),
      method: 'POST',
      requestType: 'json',
      data: rest
    }

    return this.authenticatedFetchWrap(payload)
  }

  /**
   * @function directTransferEventTicket
   * @param {object} payload - The payload
   * @param {number} payload.id - ticket id
   * @param {number} payload.userId - user to transfer ticket to
   * @returns {void}
   * @example
   *
   * directTransferEventTicket({
   *   id: 2,
   *   userId: 1503
   * })
   */

  prototype.directTransferEventTicket = function (payload) {
    const finalPayload = {
      id: payload.id,
      user_id: payload.userId
    }

    const raw = ifPromise(payload, () => this._directTransferEventTicket(finalPayload))
    return raw
      .catch(error => this.onError('directTransferEventTicket', error))
  }

  prototype.normalizeEventTicket = function (_data) {
    const data = this.normalizeData(_data)

    const ticketState = this.mapApiStatus(data.api_status)
    const ret = {
      isCheckedIn: !!data.is_checked_in,
      ticketState,
      currentVipPrice: normalizeCurrency(data.event.vip_ticket_price),
      currentGeneralPrice: normalizeCurrency(data.event.general_ticket_price),
      id: parseInt(data.id),
      orderId: parseInt(data.order_id),
      currentTicketHolder: data.ticket_holder.email,
      userName: `${data.buyer.firstname} ${data.buyer.lastname}`,
      userEmail: data.buyer.email,
      refund: 0,
      credit: 0,
      ticketType: data.type,
      qrCode: data.qr_code,
      chargeInfo: {
        individualCharges: [
          {
            id: hasKey(data.event_order, 'payment_source') ? data.event_order.payment_source.sourceable.id : -1,
            ticketType: data.type,
            numTickets: parseInt(data.event_order.event_tickets.length),
            ticketTotal: normalizeCurrency(data.event_order.sub_total),
            formattedTicketTotal: formatCurrency(normalizeCurrency(data.event_order.sub_total)),
            subtotal: normalizeCurrency(data.event_order.sub_total),
            formattedSubtotal: formatCurrency(normalizeCurrency(data.event_order.sub_total)),
            serviceFee: normalizeCurrency(data.event_order.service_fee),
            formattedServiceFee: formatCurrency(normalizeCurrency(data.event_order.service_fee)),
            tax: normalizeCurrency(data.event_order.tax_total),
            formattedTax: formatCurrency(normalizeCurrency(data.event_order.tax_total)),
            total: normalizeCurrency(data.event_order.total_price),
            formattedTotal: formatCurrency(normalizeCurrency(data.event_order.total_price)),
            purchaseDate: this.normalizeDate(data.purchased_datetime),
            paymentDetails: {
              nameOnCard: hasKey(data.event_order, 'payment_source') ? data.event_order.payment_source.sourceable.name_on_card : `${data.buyer.firstname} ${data.buyer.lastname}`,
              lastFourDigits: hasKey(data.event_order, 'payment_source') ? data.event_order.payment_source.sourceable.last_four : '(credit applied)'
            }
          }
        ]
      }
    }

    ret.isVip = ret.ticketType === 'vip'
    ret.isGeneral = !ret.isVip
    ret.hasVip = ret.currentVipPrice > 0
    ret.isActive = this.isActiveTicket(ret)
    ret.isTransferred = this.isTransferredTicket(ret)
    ret.isCheckInable = this.isCheckInableTicket(ret)
    ret.isUncheckInable = this.isUncheckInableTicket(ret)
    ret.isUpgradeable = this.isUpgradeableTicket(ret)
    ret.isTransferrable = this.isTransferrableTicket(ret)
    ret.isReclaimable = this.isReclaimableTicket(ret)
    ret.isSetCredentialsable = this.isSetCredentialsableTicket(ret)
    ret.isRevokable = this.isRevokableTicket(ret)
    ret.isPendingTransfer = this.isPendingTransferTicket(ret)
    ret.isRefunded = this.isRefundedTicket(ret)
    ret.isParticallyRefunded = this.isPartiallyRefundedTicket(ret)
    ret.isRevoked = this.isRevokedTicket(ret)
    return ret
  }

  prototype._getEventTicket = function ({ id, ...rest }) {
    const payload = {
      url: this.getUrl(`/api/v1/event_tickets/${id}`),
      method: 'GET',
      requestType: 'json',
      data: rest
    }

    return this.authenticatedFetchWrap(payload)
  }

  prototype.getEventTicket = function (payload) {
    const finalPayload = {
      id: payload.id
    }

    const raw = ifPromise(payload, () => this._getEventTicket(finalPayload))
    return raw
      .then(res => this.normalizeEventTicket(res.data))
      .catch(error => this.onError('getEventTicket', error))
  }

  prototype._reclaimEventTicket = function ({ id, ...rest }) {
    const payload = {
      url: this.getUrl(`/api/v1/event_tickets/${id}/reclaim`),
      method: 'POST',
      requestType: 'json',
      data: rest
    }

    return this.authenticatedFetchWrap(payload)
  }

  /**
   * @function reclaimEventTicket
   * @param {object} payload - The payload
   * @param {number} payload.id - ticket id
   * @returns {void}
   * @example
   *
   * reclaimEventTicket({
   *   id: 2
   * })
   */

  prototype.reclaimEventTicket = function (payload) {
    const finalPayload = {
      id: payload.id
    }
    const raw = ifPromise(payload, () => this._reclaimEventTicket(finalPayload))
    return raw
      .catch(error => this.onError('reclaimEventTicket', error))
  }

  prototype.normalizeRevokeEventTicket = function (data) {
    const ret = {
      refundBreakdown: {
        kwivrrCredit: normalizeCurrency(data.refund_breakdown.kwivrr_credit),
        ...(hasKey(data.refund_breakdown, 'credit_card') ? { creditCard: normalizeCurrency(data.refund_breakdown.credit_card) } : {}),
        ...(hasKey(data.refund_breakdown, 'echeck') ? { echeck: normalizeCurrency(data.refund_breakdown.echeck) } : {})
      }
    }

    ret.refundBreakdown.totalRefund = ret.refundBreakdown.kwivrrCredit
    if (hasKey(data.refund_breakdown, 'credit_card')) ret.refundBreakdown.totalRefund = ret.refundBreakdown.totalRefund + ret.refundBreakdown.creditCard
    if (hasKey(data.refund_breakdown, 'echeck')) ret.refundBreakdown.totalRefund = ret.refundBreakdown.totalRefund + ret.refundBreakdown.echeck

    if (hasKey(data, 'credit_card')) {
      ret.creditCard = {
        lastFour: data.credit_card.last_four,
        cardType: data.credit_card.type
      }
    } else if (hasKey(data, 'echeck')) {
      ret.echeck = {
        lastFour: data.echeck.masked_bank_account_number
      }
    }

    return ret
  }

  prototype._revokeEventTicket = function ({ id, ...rest }) {
    const payload = {
      url: this.getUrl(`/api/v1/event_tickets/${id}/revoke`),
      method: 'POST',
      requestType: 'json',
      data: rest
    }

    return this.authenticatedFetchWrap(payload)
  }

  /**
   * @typedef {object} revokeEventTicketRefundBreakdown
   * @property {number} kwivrrCredit - how much refund went to kwivrr credit
   * @property {number} totalRefund - how much refund combined across credit and real payments
   * @property {number} [creditCard] - if payment used was credit card, this is how much went back to  that source.
   * @property {number} [echeck] - if payment used was echeck, this is how much went back to that source.
   */

  /**
   * @typedef {object} echeckRefundBreakdownItem
   * @property {number} lastFour - last four of bank account number
   */

  /**
   * @typedef {object} creditCardRefundBreakdownItem
   * @property {number} lastFour - last four of credit card
   * @property {string} cardType - card type used (visa/mc/discover/amex)
   */

  /**
   * @typedef {object} revokeEventTicketReturn
   * @property {revokeEventTicketRefundBreakdown} refundBreakdown - how refund was allocated
   * @property {creditCardRefundBreakdownItem} [creditCard] - if refund is to credit card, this is the entity
   * @property {echeckRefundBreakdownItem} [echeck] - if refund is to echeck, this is the entity
   */

  /**
   * @function revokeEventTicket
   * @param {object} payload - The payload
   * @param {number} payload.id - ticket id
   * @param {string} [payload.refundType='default'] - none, default, kwivrrCredit
   * @returns {revokeEventTicketReturn}
   * @example
   *
   * revokeEventTicket({
   *   id: 2
   * })
   */

  prototype.revokeEventTicket = function (payload) {
    const finalPayload = {
      id: payload.id,
      refund_type: payload.refundType ? payload.refundType : 'default'
    }

    const raw = ifPromise(payload, () => this._revokeEventTicket(finalPayload))
    return raw
      .then(res => this.normalizeRevokeEventTicket(res.data))
      .catch(error => this.onError('revokeEventTicket', error))
  }

  prototype._getRevokeEventTicketRefundBreakdown = function ({ id }) {
    const payload = {
      url: this.getUrl(`/api/v1/event_tickets/${id}/revoke`),
      method: 'GET'
    }

    return this.authenticatedFetchWrap(payload)
  }

  /**
   * @function getRevokeEventTicketRefundBreakdown
   * @param {object} payload - The payload
   * @param {number} payload.id - ticket id
   * @returns {revokeEventTicketReturn}
   * @example
   *
   * getRevokeEventTicketRefundBreakdown({
   *   id: 2
   * })
   */

  prototype.getRevokeEventTicketRefundBreakdown = function (payload) {
    const finalPayload = {
      id: payload.id
    }

    const raw = ifPromise(payload, () => this._getRevokeEventTicketRefundBreakdown(finalPayload))
    return raw
      .then(res => this.normalizeRevokeEventTicket(res.data))
      .catch(error => this.onError('getRevokeTicketRefundBreakdown', error))
  }

  prototype._transferEventTicket = function ({ id, ...rest }) {
    const payload = {
      url: this.getUrl(`/api/v1/event_tickets/${id}/transfer`),
      method: 'POST',
      requestType: 'json',
      data: rest
    }

    return this.authenticatedFetchWrap(payload)
  }

  /**
   * @function transferEventTicket
   * @param {object} payload - The payload
   * @param {number} payload.id - ticket id
   * @param {string} payload.email - email address to transfer ticket to
   * @returns {void}
   * @example
   *
   * transferEventTicket({
   *   id: 2,
   *   email: 'jim.bob@test.com'
   * })
   */

  prototype.transferEventTicket = function (payload) {
    const finalPayload = {
      id: payload.id,
      email: payload.email
    }

    const raw = ifPromise(payload, () => this._transferEventTicket(finalPayload))
    return raw
      .catch(error => this.onError('transferEventTicket', error))
  }

  prototype._unCheckinEventTicket = function ({ id }) {
    const payload = {
      url: this.getUrl(`/api/v1/event_tickets/${id}/uncheckin`),
      method: 'POST'
    }

    return this.authenticatedFetchWrap(payload)
  }

  /**
   * @function unCheckinEventTicket
   * @param {object} payload - The payload
   * @param {number} payload.id - ticket id
   * @returns {void}
   * @example
   *
   * unCheckinEventTicket({
   *   id: 2
   * })
   */

  prototype.unCheckinEventTicket = function (payload) {
    const finalPayload = {
      id: payload.id
    }

    const raw = ifPromise(payload, () => this._unCheckinEventTicket(finalPayload))
    return raw
      .catch(error => this.onError('uncheckinEventTicket', error))
  }

  prototype._getUpgradeEventTicketDetails = function ({ id }) {
    const payload = {
      url: this.getUrl(`/api/v1/event_tickets/${id}/upgrade`),
      method: 'GET'
    }

    return this.authenticatedFetchWrap(payload)
  }

  prototype.normalizeUpgradeEventTicketDetails = function (_data) {
    const data = this.normalizeData(_data)

    const ret = {
      vipTicketPrice: normalizeCurrency(data.vip_price),
      gaTicketPricePaid: normalizeCurrency(data.general_price),
      subtotal: normalizeCurrency(data.sub_total),
      serviceFee: normalizeCurrency(data.service_fee),
      tax: normalizeCurrency(data.tax_total),
      total: normalizeCurrency(data.total_price)
    }

    ret.formattedVipTicketPrice = formatCurrency(ret.vipTicketPrice)
    ret.formattedGaTicketPricePaid = formatCurrency(ret.gaTicketPricePaid)
    ret.formattedSubtotal = formatCurrency(ret.subtotal)
    ret.formattedServiceFee = formatCurrency(ret.serviceFee)
    ret.formattedTax = formatCurrency(ret.tax)
    ret.formattedTotal = formatCurrency(ret.total)

    return ret
  }

  /**
   * @function getUpgradeEventTicketDetails
   * @param {object} payload - The payload
   * @param {number} payload.id - ticket id
   * @returns {void}
   * @example
   *
   * getUpgradeEventTicketDetails({
   *   id: 2
   * })
   */

  prototype.getUpgradeEventTicketDetails = function (payload) {
    const finalPayload = {
      id: payload.id
    }

    const raw = ifPromise(payload, () => this._getUpgradeEventTicketDetails(finalPayload))
    return raw
      .then(res => this.normalizeUpgradeEventTicketDetails(res.data))
      .catch(error => this.onError('getUpgradeEventTicketDetails', error))
  }

  prototype._setEventTicketCredentials = function ({ id, ...rest }) {
    const payload = {
      url: this.getUrl(`/api/v1/event_tickets/${id}/set_credentials`),
      method: 'POST',
      requestType: 'json',
      data: rest
    }

    return this.authenticatedFetchWrap(payload)
  }

  /**
   * @function setEventTicketCredentials
   * @param {object} payload - The payload
   * @param {number} payload.id - ticket id
   * @param {number} payload.credentialsId - credentials to assign
   * @returns {void} - ticket id
   * @example
   *
   * setEventTicketCredentials({
   *   id: 1000,
   *   credentialsId: 292929
   * })
   */

  prototype.setEventTicketCredentials = function (payload) {
    const finalPayload = {
      id: payload.id,
      credentials_id: payload.credentialsId
    }

    const raw = ifPromise(payload, () => this._setEventTicketCredentials(finalPayload))
    return raw
      .catch(error => this.onError('setEventTicketCredentials', error))
  }

  /**
   * @function getTicketIdFromQrCode
   * @param {object} payload - The payload
   * @param {string} payload.text - text from qr code reader
   * @returns {string} - ticket id
   * @example
   *
   * getTicketIdFromQrCode({
   *   text: scan_ticket_6655
   * })
   */
  prototype.getTicketIdFromQrCode = function (payload) {
    const id = payload.text.split('_')[2]
    return id
  }

  prototype.normalizeEventTicketHistoryEntry = function (_data) {
    const data = this.normalizeData(_data)

    const ret = {
      id: parseInt(data.id),
      action: this.mapApiStatus(data.api_status),
      actionDate: this.normalizeDate(data.modified_date),
      text: data.message
    }

    return ret
  }

  prototype._getEventTicketHistory = function ({ id }) {
    const payload = {
      url: this.getUrl(`/api/v1/event_tickets/${id}/history`),
      method: 'GET'
    }

    return this.authenticatedFetchWrap(payload)
  }

  /**
   * @typedef {object} EventTicketHistoryEntry
   * @property {string} action - action happening to ticket, see api_status options
   * @property {string} datePerformed - date history event occurred
   * @property {string} text - text description of event
   */

  /**
   * @function getEventTicketHistory
   * @param {object} payload - The payload
   * @param {number} payload.id - ticket id
   * @returns {EventTicketHistoryEntry[]} entries
   * @example
   *
   * getEventTicketHistory({
   *   id: 2
   * })
   */

  prototype.getEventTicketHistory = function (payload) {
    const finalPayload = {
      id: payload.id
    }

    const raw = ifPromise(payload, () => this._getEventTicketHistory(finalPayload))
    return raw
      .then(res => this.normalizeListData(res.data, this.normalizeEventTicketHistoryEntry))
      .catch(error => this.onError('getEventTicketHistory', error))
  }

  prototype._upgradeEventTicket = function ({ id, ...rest }) {
    const payload = {
      url: this.getUrl(`/api/v1/event_tickets/${id}/upgrade`),
      method: 'POST',
      requestType: 'json',
      data: rest
    }

    return this.authenticatedFetchWrap(payload)
  }

  /**
   * @function upgradeEventTicket
   * @param {object} payload - The payload
   * @param {number} payload.id - ticket id
   * @param {number} payload.credentialsId - credentials to assign
   * @returns {void}
   * @example
   *
   * upgradeEventTicket({
   *   id: 1000,
   *   credentialsId: 292929
   * })
   */

  prototype.upgradeEventTicket = function (payload) {
    const finalPayload = {
      id: payload.id,
      zevents_event_order: {
        vip_ticket_count: 1
      },
      apply_credits: false,
      payment: this.normalizePayment(payload.payment, false)
    }

    const raw = ifPromise(payload, () => this._upgradeEventTicket(finalPayload))
    return raw
      .catch(error => this.onError('upgradeEventTicket', error))
  }
}

export default ZEventsApiEventTickets