<commit_before>module Pay
  module Braintree
    module Billable
      extend ActiveSupport::Concern

      included do
        scope :braintree, -> { where(processor: :braintree) }
      end

      # Handles Billable#customer
      #
      # Returns Braintree::Customer
      def braintree_customer
        if processor_id?
          gateway.customer.find(processor_id)
        else
          result = gateway.customer.create(
            email: email,
            first_name: try(:first_name),
            last_name: try(:last_name),
            payment_method_nonce: card_token
          )
          raise BraintreeError.new(result), result.message unless result.success?

          update(processor: "braintree", processor_id: result.customer.id)

          if card_token.present?
            update_braintree_card_on_file result.customer.payment_methods.last
          end

          result.customer
        end
      rescue ::Braintree::AuthorizationError
        raise BraintreeAuthorizationError
      rescue ::Braintree::BraintreeError => e
        raise BraintreeError, e.message
      end

      # Handles Billable#charge
      #
      # Returns a Pay::Charge
      def create_braintree_charge(amount, options = {})
        args = {
          amount: amount.to_i / 100.0,
          customer_id: customer.id,
          options: {submit_for_settlement: true}
        }.merge(options)

        result = gateway.transaction.sale(args)
        raise BraintreeError.new(result), result.message unless result.success?

        save_braintree_transaction(result.transaction)
      rescue ::Braintree::AuthorizationError
        raise BraintreeAuthorizationError
      rescue ::Braintree::BraintreeError => e
        raise BraintreeError, e.message
      end

      # Handles Billable#subscribe
      #
      # Returns Pay::Subscription
      def create_braintree_subscription(name, plan, options = {})
        token = customer.payment_methods.find(&:default?).try(:token)
        raise Pay::Error, "Customer has no default payment method" if token.nil?

        # Standardize the trial period options
        if (trial_period_days = options.delete(:trial_period_days)) && trial_period_days > 0
          options.merge!(trial_period: true, trial_duration: trial_period_days, trial_duration_unit: :day)
        end

        subscription_options = options.merge(
          payment_method_token: token,
          plan_id: plan
        )

        result = gateway.subscription.create(subscription_options)
        raise BraintreeError.new(result), result.message unless result.success?

        create_subscription(result.subscription, "braintree", name, plan, status: :active)
      rescue ::Braintree::AuthorizationError
        raise BraintreeAuthorizationError
      rescue ::Braintree::BraintreeError => e
        raise BraintreeError, e.message
      end

      # Handles Billable#update_card
      #
      # Returns true if successful
      def update_braintree_card(token)
        result = gateway.payment_method.create(
          customer_id: processor_id,
          payment_method_nonce: token,
          options: {
            make_default: true,
            verify_card: true
          }
        )
        raise BraintreeError.new(result), result.message unless result.success?

        update_braintree_card_on_file result.payment_method
        update_subscriptions_to_payment_method(result.payment_method.token)
        true
      rescue ::Braintree::AuthorizationError
        raise BraintreeAuthorizationError
      rescue ::Braintree::BraintreeError => e
        raise BraintreeError, e.message
      end

      def update_braintree_email!
        braintree_customer.update(
          email: email,
          first_name: try(:first_name),
          last_name: try(:last_name)
        )
      end

      def braintree_trial_end_date(subscription)
        return unless subscription.trial_period
        # Braintree returns dates without time zones, so we'll assume they're UTC
        subscription.first_billing_date.end_of_day
      end

      def update_subscriptions_to_payment_method(token)
        subscriptions.braintree.each do |subscription|
          if subscription.active?
            gateway.subscription.update(subscription.processor_id, {payment_method_token: token})
          end
        end
      end

      def braintree_subscription(subscription_id, options = {})
        gateway.subscription.find(subscription_id)
      end

      def braintree_invoice!(options = {})
        # pass
      end

      def braintree_upcoming_invoice
        # pass
      end

      def save_braintree_transaction(transaction)
        attrs = card_details_for_braintree_transaction(transaction)
        attrs[:amount] = transaction.amount.to_f * 100

        charge = charges.find_or_initialize_by(
          processor: :braintree,
          processor_id: transaction.id
        )
        charge.update(attrs)
        charge
      end

      private

      def gateway
        Pay.braintree_gateway
      end

      def update_braintree_card_on_file(payment_method)
        case payment_method
        when ::Braintree::CreditCard
          update!(
            card_type: payment_method.card_type,
            card_last4: payment_method.last_4,
            card_exp_month: payment_method.expiration_month,
            card_exp_year: payment_method.expiration_year
          )

        when ::Braintree::PayPalAccount
          update!(
            card_type: "PayPal",
            card_last4: payment_method.email
          )
        end

        # Clear the card token so we don't accidentally update twice
        self.card_token = nil
      end

      def card_details_for_braintree_transaction(transaction)
        case transaction.payment_instrument_type
        when "credit_card", "samsung_pay_card", "masterpass_card", "samsung_pay_card", "visa_checkout_card"
          payment_method = transaction.send("#{transaction.payment_instrument_type}_details")
          {
            card_type: payment_method.card_type,
            card_last4: payment_method.last_4,
            card_exp_month: payment_method.expiration_month,
            card_exp_year: payment_method.expiration_year
          }

        when "paypal_account"
          {
            card_type: "PayPal",
            card_last4: transaction.paypal_details.payer_email,
            card_exp_month: nil,
            card_exp_year: nil
          }

        when "android_pay_card"
          payment_method = transaction.android_pay_details
          {
            card_type: payment_method.source_card_type,
            card_last4: payment_method.source_card_last_4,
            card_exp_month: payment_method.expiration_month,<commit_msg>Remove duplicate when condition<commit_after>module Pay
  module Braintree
    module Billable
      extend ActiveSupport::Concern

      included do
        scope :braintree, -> { where(processor: :braintree) }
      end

      # Handles Billable#customer
      #
      # Returns Braintree::Customer
      def braintree_customer
        if processor_id?
          gateway.customer.find(processor_id)
        else
          result = gateway.customer.create(
            email: email,
            first_name: try(:first_name),
            last_name: try(:last_name),
            payment_method_nonce: card_token
          )
          raise BraintreeError.new(result), result.message unless result.success?

          update(processor: "braintree", processor_id: result.customer.id)

          if card_token.present?
            update_braintree_card_on_file result.customer.payment_methods.last
          end

          result.customer
        end
      rescue ::Braintree::AuthorizationError
        raise BraintreeAuthorizationError
      rescue ::Braintree::BraintreeError => e
        raise BraintreeError, e.message
      end

      # Handles Billable#charge
      #
      # Returns a Pay::Charge
      def create_braintree_charge(amount, options = {})
        args = {
          amount: amount.to_i / 100.0,
          customer_id: customer.id,
          options: {submit_for_settlement: true}
        }.merge(options)

        result = gateway.transaction.sale(args)
        raise BraintreeError.new(result), result.message unless result.success?

        save_braintree_transaction(result.transaction)
      rescue ::Braintree::AuthorizationError
        raise BraintreeAuthorizationError
      rescue ::Braintree::BraintreeError => e
        raise BraintreeError, e.message
      end

      # Handles Billable#subscribe
      #
      # Returns Pay::Subscription
      def create_braintree_subscription(name, plan, options = {})
        token = customer.payment_methods.find(&:default?).try(:token)
        raise Pay::Error, "Customer has no default payment method" if token.nil?

        # Standardize the trial period options
        if (trial_period_days = options.delete(:trial_period_days)) && trial_period_days > 0
          options.merge!(trial_period: true, trial_duration: trial_period_days, trial_duration_unit: :day)
        end

        subscription_options = options.merge(
          payment_method_token: token,
          plan_id: plan
        )

        result = gateway.subscription.create(subscription_options)
        raise BraintreeError.new(result), result.message unless result.success?

        create_subscription(result.subscription, "braintree", name, plan, status: :active)
      rescue ::Braintree::AuthorizationError
        raise BraintreeAuthorizationError
      rescue ::Braintree::BraintreeError => e
        raise BraintreeError, e.message
      end

      # Handles Billable#update_card
      #
      # Returns true if successful
      def update_braintree_card(token)
        result = gateway.payment_method.create(
          customer_id: processor_id,
          payment_method_nonce: token,
          options: {
            make_default: true,
            verify_card: true
          }
        )
        raise BraintreeError.new(result), result.message unless result.success?

        update_braintree_card_on_file result.payment_method
        update_subscriptions_to_payment_method(result.payment_method.token)
        true
      rescue ::Braintree::AuthorizationError
        raise BraintreeAuthorizationError
      rescue ::Braintree::BraintreeError => e
        raise BraintreeError, e.message
      end

      def update_braintree_email!
        braintree_customer.update(
          email: email,
          first_name: try(:first_name),
          last_name: try(:last_name)
        )
      end

      def braintree_trial_end_date(subscription)
        return unless subscription.trial_period
        # Braintree returns dates without time zones, so we'll assume they're UTC
        subscription.first_billing_date.end_of_day
      end

      def update_subscriptions_to_payment_method(token)
        subscriptions.braintree.each do |subscription|
          if subscription.active?
            gateway.subscription.update(subscription.processor_id, {payment_method_token: token})
          end
        end
      end

      def braintree_subscription(subscription_id, options = {})
        gateway.subscription.find(subscription_id)
      end

      def braintree_invoice!(options = {})
        # pass
      end

      def braintree_upcoming_invoice
        # pass
      end

      def save_braintree_transaction(transaction)
        attrs = card_details_for_braintree_transaction(transaction)
        attrs[:amount] = transaction.amount.to_f * 100

        charge = charges.find_or_initialize_by(
          processor: :braintree,
          processor_id: transaction.id
        )
        charge.update(attrs)
        charge
      end

      private

      def gateway
        Pay.braintree_gateway
      end

      def update_braintree_card_on_file(payment_method)
        case payment_method
        when ::Braintree::CreditCard
          update!(
            card_type: payment_method.card_type,
            card_last4: payment_method.last_4,
            card_exp_month: payment_method.expiration_month,
            card_exp_year: payment_method.expiration_year
          )

        when ::Braintree::PayPalAccount
          update!(
            card_type: "PayPal",
            card_last4: payment_method.email
          )
        end

        # Clear the card token so we don't accidentally update twice
        self.card_token = nil
      end

      def card_details_for_braintree_transaction(transaction)
        case transaction.payment_instrument_type
        when "credit_card", "samsung_pay_card", "masterpass_card", "visa_checkout_card"
          payment_method = transaction.send("#{transaction.payment_instrument_type}_details")
          {
            card_type: payment_method.card_type,
            card_last4: payment_method.last_4,
            card_exp_month: payment_method.expiration_month,
            card_exp_year: payment_method.expiration_year
          }

        when "paypal_account"
          {
            card_type: "PayPal",
            card_last4: transaction.paypal_details.payer_email,
            card_exp_month: nil,
            card_exp_year: nil
          }

        when "android_pay_card"
          payment_method = transaction.android_pay_details
          {
            card_type: payment_method.source_card_type,
            card_last4: payment_method.source_card_last_4,
            card_exp_month: payment_method.expiration_month,
{'fraction_non_alphanumeric': 0.06894243641231593, 'fraction_numerical': 0.002379889930090733, 'mean_word_length': 2.3744040150564616, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 15, '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': '5423395', 'n_tokens_mistral': 3715, 'n_tokens_neox': 3670, 'n_words': 713}