<commit_before>class PaymentController extends KDController

  sanitizeRecurlyErrors = (fields, inputs, err) ->
    ERRORS =
      address1             :
        input              : inputs.address1
        field              : fields.address1
      address2             :
        input              : inputs.address2
        field              : fields.address2
      city                 :
        input              : inputs.city
        field              : fields.city
      state                :
        input              : inputs.state
        field              : fields.state
      country              :
        input              : inputs.country
        field              : fields.country
      first_name           :
        input              : inputs.cardFirstName
        field              : fields.cardFirstName
      last_name            :
        input              : inputs.cardLastName
        field              : fields.cardLastName
      number               :
        input              : inputs.cardNumber
        field              : fields.cardNumber
      zip                  :
        input              : inputs.zip
        field              : fields.zip
      verification_value   :
        input              : inputs.cardCV
        field              : fields.cardCV

    for key, val of ERRORS
      val.input.giveValidationFeedback no

    for e in err
      if e.field in ['account.base', 'billing_info.base']
        val.input.showValidationError e.message
        if e.message.indexOf('card') > -1
          inputs.cardNumber.giveValidationFeedback yes
      else
        for key, val of ERRORS
          if e.field.indexOf(key) > -1
            val.input.giveValidationFeedback yes
            inputName = if val.input.inputLabel
              val.input.inputLabel.getTitle()
            else
              inputEl = val.input.$()[0]
              inputEl.getAttribute("placeholder") or inputEl.getAttribute("name") or ""

            val.input.showValidationError "#{inputName} #{e.message}"

  required = (msg)->
    rules    : required  : yes
    messages : required  : msg

  addPaymentMethod:(form, callback) ->
    formData = form.getFormData()

    delete formData.cardNumber  if formData.cardNumber.indexOf('...') > -1
    delete formData.cardCV      if formData.cardCV == 'XXX'


    KD.remote.api.JPayment.setAccount formData, (err, res) =>
      if err
        sanitizeRecurlyErrors form.fields, form.inputs, err
        callback? yes
      else
        sanitizeRecurlyErrors form.fields, form.inputs, []
        KD.remote.api.JPayment.getAccount {}, (e, r) =>
          unless e
            for k, v of r when form.inputs[k]
              form.inputs[k].setValue v
        callback? no

  validatePaymentMethodForm:(formData, callback)->

    return unless @modal

    form    = @modal.modalTabs.forms["Billing Info"]
    button  = @modal.buttons.Save
    onError = (err)->
      warn err
      sanitizeRecurlyErrors form.fields, form.inputs, err
      button.hideLoader()
    onSuccess = @modal.destroy.bind @modal
    callback formData, onError, onSuccess

  createPaymentMethodModal:(data, callback) ->

    creditCardPattern = 
    doesValidate  = /((^4[0-9]{12}(?:[0-9]{3})?$)|(^5[1-5][0-9]{14}$)|(^3[47][0-9]{13}$)|(^3(?:0[0-5]|[68][0-9])[0-9]{11}$)|(^6(?:011|5[0-9]{2})[0-9]{12}$)|(^(?:2131|1800|35\d{3})\d{11}$))?/

    @modal = modal = new KDModalViewWithForms
      title                       : "Billing Information"
      width                       : 520
      height                      : "auto"
      cssClass                    : "payments-modal"
      overlay                     : yes
      buttons                     :
        Save                      :
          title                   : "Save"
          style                   : "modal-clean-green"
          type                    : "button"
          loader                  : { color : "#ffffff", diameter : 12 }
          callback                : -> modal.modalTabs.forms["Billing Info"].submit()
      tabs                        :
        navigable                 : yes
        goToNextFormOnSubmit      : no
        forms                     :
          "Billing Info"          :
            callback              : (formData)=>
              @validatePaymentMethodForm formData, callback
            fields                :
              cardFirstName       :
                label             : "Name"
                name              : "cardFirstName"
                placeholder       : "<NAME>"
                defaultValue      : KD.whoami().profile.firstName
                validate          : required "First name is required!"
                nextElementFlat   :
                  cardLastName    :
                    name          : "cardLastName"
                    placeholder   : "<NAME>"
                    defaultValue  : KD.whoami().profile.lastName
                    validate      : required "Last name is required!"
              cardNumber          :
                label             : "Card Number"
                name              : "cardNumber"
                placeholder       : 'Card Number'
                defaultValue      : ''
                validate          :
                  event           : "blur"
                  rules           :
                    regExp        : creditCardPattern
                nextElementFlat   :
                  cardCV          :
                    # tooltip       :
                    #   placement   : 'right'
                    #   direction   : 'center'
                    #   title       : 'The location of this verification number depends on the issuer of your credit card'
                    name          : "cardCV"
                    placeholder   : "CV Number"
                    defaultValue  : ""
                    validate      :
                      rules       :
                        regExp    : /[0-9]*/
                      messages    :
                        required  : "Card security code is required! (CVV)"
                        minLength : "Card security code needs to be at least 3 digits!"
                        regExp    : "Card security code should be a number!"
              cardMonth           :
                label             : "Expire Date"
                itemClass         : KDSelectBox
                name              : "cardMonth"
                selectOptions     : __utils.getMonthOptions()
                defaultValue      : (new Date().getMonth())+2
                nextElementFlat   :
                  cardYear        :
                    itemClass     : KDSelectBox
                    name          : "cardYear"
                    selectOptions : __utils.getYearOptions((new Date().getFullYear()),(new Date().getFullYear()+25))
                    defaultValue  : (new Date().getFullYear())
              address1            :
                label             : "Address"
                name              : "address1"
                placeholder       : "Street Name & Number"
                defaultValue      : ""
                validate          : required "First address field is required!"
              address2            :
                label             : " "
                name              : "address2"
                placeholder       : "Apartment/Suite Number"
              city                :
                label             : "City & State"
                name              : "city"
                placeholder       : "City Name"
                defaultValue      : ""
                validate          : required "City is required!"
                nextElementFlat   :
                  state           :
                    name          : "state"
                    placeholder   : "State"
                    defaultValue  : ""
              zip                 :
                label             : "ZIP & Country"
                name              : "zipCode"
                placeholder       : "ZIP Code"
                defaultValue      : ""
                validate          : required "Zip code is required!"
                nextElementFlat   :
                  country         :
                    name          : "country"
                    placeholder   : "Country"
                    defaultValue  : "USA"
                    validate      : required "First address field is required!"

    form = modal.modalTabs.forms["Billing Info"]

    # Credit card icon
    form.fields['cardNumber'].addSubView icon = new KDCustomHTMLView tagName : "span", cssClass : "icon"

    form.inputs['cardNumber'].on "CreditCardTypeIdentified", (type)=>
      cardType = type.toLowerCase()
      $icon = icon.$()
      unless $icon.hasClass cardType
        $icon.removeClass "visa mastercard discover amex"
        $icon.addClass cardType

    form.on "FormValidationFailed", => modal.buttons.Save.hideLoader()

    for k, v of data
      if form.inputs[k]
        if k is "cardNumber" or k is "cardCV"
          form.inputs[k].setPlaceHolder v
        else
          form.inputs[k].setValue v

    modal.on "KDObjectWillBeDestroyed", => delete @modal

    return modal

  deleteAccountPaymentMethod:(callback) ->

    @deleteModal = new KDModalView
      title        : "Warning"
      content      : "<div class='modalformline'>Are you sure you want to delete your billing information?</div>"
      height       : "auto"
      overlay      : yes
      buttons      :
        Yes        :
          loader   :
            color  : "#ffffff"
            diameter : 16
          style    : "modal-clean-gray"
          callback : ->
            KD.remote.api.JPayment.deleteAccountPaymentMethod {}, (err, res) ->
              modal.destroy()
              callback?()

  getBalance: (type, group, cb)->
    if type is 'user'
      KD.remote.api.JRecurlyPlan.getUserBalance cb
    else
      KD.remote.api.JRecurlyPlan.getGroupBalance group, cb

  setBillingInfo: (type, group, cb)->
    @createPaymentMethodModal {}, (newData, onError, onSuccess)->
      if type is 'group'
        group.setBillingInfo newData, (err, result)->
          if err
            onError err
          else
            onSuccess result
            cb yes
      else if type is 'expensed'
        group.setBillingInfo newData, (err, result)->
          if err
            onError err
          else
            onSuccess result
            cb yes
      else
        KD.remote.api.JRecurlyPlan.setUserAccount newData, (err, result)->
          if err
            onError err
          else
            onSuccess result
            cb yes

  getBillingInfo: (type, group, cb)->
    if type in ['group', 'expensed']
      group.getBillingInfo (e,a)->
        cb e, a
    else
      KD.remote.api.JRecurlyPlan.getUserAccount cb

  createPaymentConfirmationModal: (options, cb)->
    {type, group, plan, needBilling, balance, amount, subscription} = options

    content = @paymentWarning balance, amount, subscription, type

    if type is 'expensed' and needBilling and 'admin' not in KD.config.roles
      content = "Group admins have not defined a payment for this group."

    modal           = new KDModalView
      title         : "Confirm VM Creation"
      content       : "<div class='modalformline'>#{content}</div>"
      cssClass      : "vm-new"
      overlay       : yes
      buttons       :
        No          :
          title     : "Close"
          cssClass  : "modal-clean-gray"
          callback  : =>
            modal.destroy()
        ReActivate  :
          title     : "Re-activate Plan"
          cssClass  : "modal-clean-green hidden"
          callback  : =>
            subscription.resume ->
              modal.buttons.ReActivate.hide()
              modal.buttons.Yes.show()
        Billing     :
          title     : "Enter Billing Info"
          cssClass  : "modal-clean-green hidden"
          callback  : =>
            @setBillingInfo type, group, (success)->
              if success
                if subscription.status is "canceled"
                  modal.buttons.ReActivate.show()
                else
                  modal.buttons.Yes.show()
                modal.buttons.Billing.hide()<commit_msg>Correct warning message.<commit_after>class PaymentController extends KDController

  sanitizeRecurlyErrors = (fields, inputs, err) ->
    ERRORS =
      address1             :
        input              : inputs.address1
        field              : fields.address1
      address2             :
        input              : inputs.address2
        field              : fields.address2
      city                 :
        input              : inputs.city
        field              : fields.city
      state                :
        input              : inputs.state
        field              : fields.state
      country              :
        input              : inputs.country
        field              : fields.country
      first_name           :
        input              : inputs.cardFirstName
        field              : fields.cardFirstName
      last_name            :
        input              : inputs.cardLastName
        field              : fields.cardLastName
      number               :
        input              : inputs.cardNumber
        field              : fields.cardNumber
      zip                  :
        input              : inputs.zip
        field              : fields.zip
      verification_value   :
        input              : inputs.cardCV
        field              : fields.cardCV

    for key, val of ERRORS
      val.input.giveValidationFeedback no

    for e in err
      if e.field in ['account.base', 'billing_info.base']
        val.input.showValidationError e.message
        if e.message.indexOf('card') > -1
          inputs.cardNumber.giveValidationFeedback yes
      else
        for key, val of ERRORS
          if e.field.indexOf(key) > -1
            val.input.giveValidationFeedback yes
            inputName = if val.input.inputLabel
              val.input.inputLabel.getTitle()
            else
              inputEl = val.input.$()[0]
              inputEl.getAttribute("placeholder") or inputEl.getAttribute("name") or ""

            val.input.showValidationError "#{inputName} #{e.message}"

  required = (msg)->
    rules    : required  : yes
    messages : required  : msg

  addPaymentMethod:(form, callback) ->
    formData = form.getFormData()

    delete formData.cardNumber  if formData.cardNumber.indexOf('...') > -1
    delete formData.cardCV      if formData.cardCV == 'XXX'


    KD.remote.api.JPayment.setAccount formData, (err, res) =>
      if err
        sanitizeRecurlyErrors form.fields, form.inputs, err
        callback? yes
      else
        sanitizeRecurlyErrors form.fields, form.inputs, []
        KD.remote.api.JPayment.getAccount {}, (e, r) =>
          unless e
            for k, v of r when form.inputs[k]
              form.inputs[k].setValue v
        callback? no

  validatePaymentMethodForm:(formData, callback)->

    return unless @modal

    form    = @modal.modalTabs.forms["Billing Info"]
    button  = @modal.buttons.Save
    onError = (err)->
      warn err
      sanitizeRecurlyErrors form.fields, form.inputs, err
      button.hideLoader()
    onSuccess = @modal.destroy.bind @modal
    callback formData, onError, onSuccess

  createPaymentMethodModal:(data, callback) ->

    creditCardPattern = 
    doesValidate  = /((^4[0-9]{12}(?:[0-9]{3})?$)|(^5[1-5][0-9]{14}$)|(^3[47][0-9]{13}$)|(^3(?:0[0-5]|[68][0-9])[0-9]{11}$)|(^6(?:011|5[0-9]{2})[0-9]{12}$)|(^(?:2131|1800|35\d{3})\d{11}$))?/

    @modal = modal = new KDModalViewWithForms
      title                       : "Billing Information"
      width                       : 520
      height                      : "auto"
      cssClass                    : "payments-modal"
      overlay                     : yes
      buttons                     :
        Save                      :
          title                   : "Save"
          style                   : "modal-clean-green"
          type                    : "button"
          loader                  : { color : "#ffffff", diameter : 12 }
          callback                : -> modal.modalTabs.forms["Billing Info"].submit()
      tabs                        :
        navigable                 : yes
        goToNextFormOnSubmit      : no
        forms                     :
          "Billing Info"          :
            callback              : (formData)=>
              @validatePaymentMethodForm formData, callback
            fields                :
              cardFirstName       :
                label             : "Name"
                name              : "cardFirstName"
                placeholder       : "First Name"
                defaultValue      : KD.whoami().profile.firstName
                validate          : required "First name is required!"
                nextElementFlat   :
                  cardLastName    :
                    name          : "cardLastName"
                    placeholder   : "<NAME>"
                    defaultValue  : KD.whoami().profile.lastName
                    validate      : required "Last name is required!"
              cardNumber          :
                label             : "Card Number"
                name              : "cardNumber"
                placeholder       : 'Card Number'
                defaultValue      : ''
                validate          :
                  event           : "blur"
                  rules           :
                    regExp        : creditCardPattern
                nextElementFlat   :
                  cardCV          :
                    # tooltip       :
                    #   placement   : 'right'
                    #   direction   : 'center'
                    #   title       : 'The location of this verification number depends on the issuer of your credit card'
                    name          : "cardCV"
                    placeholder   : "CV Number"
                    defaultValue  : ""
                    validate      :
                      rules       :
                        regExp    : /[0-9]*/
                      messages    :
                        required  : "Card security code is required! (CVV)"
                        minLength : "Card security code needs to be at least 3 digits!"
                        regExp    : "Card security code should be a number!"
              cardMonth           :
                label             : "Expire Date"
                itemClass         : KDSelectBox
                name              : "cardMonth"
                selectOptions     : __utils.getMonthOptions()
                defaultValue      : (new Date().getMonth())+2
                nextElementFlat   :
                  cardYear        :
                    itemClass     : KDSelectBox
                    name          : "cardYear"
                    selectOptions : __utils.getYearOptions((new Date().getFullYear()),(new Date().getFullYear()+25))
                    defaultValue  : (new Date().getFullYear())
              address1            :
                label             : "Address"
                name              : "address1"
                placeholder       : "Street Name & Number"
                defaultValue      : ""
                validate          : required "First address field is required!"
              address2            :
                label             : " "
                name              : "address2"
                placeholder       : "Apartment/Suite Number"
              city                :
                label             : "City & State"
                name              : "city"
                placeholder       : "City Name"
                defaultValue      : ""
                validate          : required "City is required!"
                nextElementFlat   :
                  state           :
                    name          : "state"
                    placeholder   : "State"
                    defaultValue  : ""
              zip                 :
                label             : "ZIP & Country"
                name              : "zipCode"
                placeholder       : "ZIP Code"
                defaultValue      : ""
                validate          : required "Zip code is required!"
                nextElementFlat   :
                  country         :
                    name          : "country"
                    placeholder   : "Country"
                    defaultValue  : "USA"
                    validate      : required "First address field is required!"

    form = modal.modalTabs.forms["Billing Info"]

    # Credit card icon
    form.fields['cardNumber'].addSubView icon = new KDCustomHTMLView tagName : "span", cssClass : "icon"

    form.inputs['cardNumber'].on "CreditCardTypeIdentified", (type)=>
      cardType = type.toLowerCase()
      $icon = icon.$()
      unless $icon.hasClass cardType
        $icon.removeClass "visa mastercard discover amex"
        $icon.addClass cardType

    form.on "FormValidationFailed", => modal.buttons.Save.hideLoader()

    for k, v of data
      if form.inputs[k]
        if k is "cardNumber" or k is "cardCV"
          form.inputs[k].setPlaceHolder v
        else
          form.inputs[k].setValue v

    modal.on "KDObjectWillBeDestroyed", => delete @modal

    return modal

  deleteAccountPaymentMethod:(callback) ->

    @deleteModal = new KDModalView
      title        : "Warning"
      content      : "<div class='modalformline'>Are you sure you want to delete your billing information?</div>"
      height       : "auto"
      overlay      : yes
      buttons      :
        Yes        :
          loader   :
            color  : "#ffffff"
            diameter : 16
          style    : "modal-clean-gray"
          callback : ->
            KD.remote.api.JPayment.deleteAccountPaymentMethod {}, (err, res) ->
              modal.destroy()
              callback?()

  getBalance: (type, group, cb)->
    if type is 'user'
      KD.remote.api.JRecurlyPlan.getUserBalance cb
    else
      KD.remote.api.JRecurlyPlan.getGroupBalance group, cb

  setBillingInfo: (type, group, cb)->
    @createPaymentMethodModal {}, (newData, onError, onSuccess)->
      if type is 'group'
        group.setBillingInfo newData, (err, result)->
          if err
            onError err
          else
            onSuccess result
            cb yes
      else if type is 'expensed'
        group.setBillingInfo newData, (err, result)->
          if err
            onError err
          else
            onSuccess result
            cb yes
      else
        KD.remote.api.JRecurlyPlan.setUserAccount newData, (err, result)->
          if err
            onError err
          else
            onSuccess result
            cb yes

  getBillingInfo: (type, group, cb)->
    if type in ['group', 'expensed']
      group.getBillingInfo (e,a)->
        cb e, a
    else
      KD.remote.api.JRecurlyPlan.getUserAccount cb

  createPaymentConfirmationModal: (options, cb)->
    {type, group, plan, needBilling, balance, amount, subscription} = options

    content = @paymentWarning balance, amount, subscription, type

    if type is 'expensed' and needBilling and 'admin' not in KD.config.roles
      content = "Group admins have not defined a payment method for this group."

    modal           = new KDModalView
      title         : "Confirm VM Creation"
      content       : "<div class='modalformline'>#{content}</div>"
      cssClass      : "vm-new"
      overlay       : yes
      buttons       :
        No          :
          title     : "Close"
          cssClass  : "modal-clean-gray"
          callback  : =>
            modal.destroy()
        ReActivate  :
          title     : "Re-activate Plan"
          cssClass  : "modal-clean-green hidden"
          callback  : =>
            subscription.resume ->
              modal.buttons.ReActivate.hide()
              modal.buttons.Yes.show()
        Billing     :
          title     : "Enter Billing Info"
          cssClass  : "modal-clean-green hidden"
          callback  : =>
            @setBillingInfo type, group, (success)->
              if success
                if subscription.status is "canceled"
                  modal.buttons.ReActivate.show()
                else
                  modal.buttons.Yes.show()
                modal.buttons.Billing.hide()
{'fraction_non_alphanumeric': 0.08610000815727221, 'fraction_numerical': 0.007015254099029284, 'mean_word_length': 1.170975739330618, 'pattern_counts': {'":': 0, '<': 14, '<?xml version=': 0, '>': 80, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2390802', 'n_tokens_mistral': 6226, 'n_tokens_neox': 5876, 'n_words': 1451}