fairmondo/fairmondo

View on GitHub
app/models/user.rb

Summary

Maintainability
B
5 hrs
Test Coverage
#   Copyright (c) 2012-2017, Fairmondo eG.  This file is
#   licensed under the GNU Affero General Public License version 3 or later.
#   See the COPYRIGHT file for details.

class User < ApplicationRecord
  extend Memoist
  extend Tokenize
  extend RailsAdminStatistics

  # Friendly_id for beautiful links
  extend FriendlyId

  friendly_id :nickname, use: [:slugged, :finders]

  include UserConcerns::Associations
  include UserConcerns::ExtendedAttributes
  include UserConcerns::Validations
  include UserConcerns::State
  include UserConcerns::Ratings
  include UserConcerns::Scopes

  include Assets::Normalizer # for cancellation form

  # Include default devise modules. Others available are: :rememberable,
  # :token_authenticatable, :encryptable, :lockable,  and :omniauthable
  devise :database_authenticatable, :registerable, :timeoutable,
         :recoverable, :trackable, :validatable, :confirmable

  after_create :create_default_library

  ####################################################
  # Scopes
  #
  ####################################################
  scope :sorted_ngo, -> { order(:nickname).where(ngo: true) }
  scope :ngo_with_profile_image, -> { where(ngo: true).joins(:image).limit(8) }
  scope :banned, -> { where(banned: true) }
  scope :unbanned, -> { where('banned = ? OR banned IS NULL', false) }

  ####################################################
  # Methods
  #
  ####################################################

  # Return first_name plus last_name
  # @api public
  # @return [String]
  def fullname
    "#{standard_address_first_name} #{standard_address_last_name}"
  end
  # memoize :fullname

  # Return user nickname
  # @api return
  # @public [String]
  def name
    nickname
  end

  # Return user first name
  # @api return
  # @public [String]
  def first_name
    standard_address_first_name
  end

  # Compare IDs of users
  # @api public
  # @param user [User] Usually current_user
  def is?(user)
    user && self.id == user.id
  end

  # Check if user was created before Sept 24th 2013
  # @api public
  # @param user [User] Usually current_user
  def is_pioneer?
    self.created_at < Time.parse('2013-09-23 23:59:59.000000 CEST +02:00')
  end

  # Static method to get admin status even if current_user is nil
  # @api public
  # @param user [User, nil] Usually current_user
  def self.is_admin?(user)
    user && user.admin?
  end

  # Get generated customer number
  # @api public
  # @return [String] 8-digit number
  def customer_nr
    id.to_s.rjust 8, '0'
  end

  # Get url for user image
  # @api public
  # @param symbol [Symbol] which type
  # @return [String] URL
  def image_url(symbol)
    image ? image.image.url(symbol) : ActionController::Base.helpers.asset_path('missing.png')
  end

  # Return a formatted address
  # @api public
  # @return [String]
  def address
    string = ''
    string += "#{standard_address_address_line_1}, "
    string += "#{standard_address_address_line_2}, " if standard_address_address_line_2.present?
    string += "#{standard_address_zip} #{standard_address_city}"
    string
  end

  # get ngo status
  # @api public
  def is_ngo?
    self.ngo
  end

  # get all users with ngo status but not current
  def self.sorted_ngo_without_current(current_user)
    self.order(:nickname).where('ngo = ? AND id != ?', true, current_user.id)
  end

  # get hearted libraries of current user
  def self.hearted_libraries_current(current_user)
    if current_user
      current_user.hearted_libraries.published
        .no_admins.min_elem(2).where('users.id != ?', current_user.id)
        .reorder('hearts.created_at DESC')
    end
  end

  def has_articles?
    Article.unscoped.where(seller: self).limit(1).present?
  end

  def bank_account_exists?
    self.bank_account_owner? && self.iban? && self.bic?
  end

  def bank_details_valid?
    KontoAPI.valid?(iban: iban, bic: bic)
  end

  # If a legal Entity hasn't accepted direct debit but has any articles
  def requires_direct_debit_mandate?
    is_a?(LegalEntity) &&
    !has_active_direct_debit_mandate? &&
    !direct_debit_exemption &&
    has_articles?
  end

  def has_active_direct_debit_mandate?
    active_direct_debit_mandate.present?
  end

  # Returns the first active direct debit mandate available
  def active_direct_debit_mandate
    direct_debit_mandates.where(state: 'active').first
  end

  def increase_direct_debit_mandate_number
    number = self.next_direct_debit_mandate_number
    self.next_direct_debit_mandate_number += 1
    number
  end

  def needs_to_be_billed?
    if self.is_a?(LegalEntity) && !self.is_ngo? && !self.marketplace_owner_account
      true
    else
      false
    end
  end

  def payment_method
    if has_active_direct_debit_mandate? && !bankaccount_warning
      :payment_by_direct_debit
    else
      :payment_by_invoice
    end
  end

  # checks if User may offer debit payment. restrict to fairmondo accounts for now by checking direct_debit_exemption
  def can_offer_debit_payment?
    if self.is_a?(LegalEntity) && direct_debit_exemption
      true
    else
      false
    end
  end

  def paypal_account_exists?
    self.paypal_account?
  end

  # checks if user passes all neccessary validations before he can sell
  def can_sell?
    self.wants_to_sell = true
    can_sell = self.valid?
    self.wants_to_sell = false
    can_sell
  end

  # hashes the ip-addresses which are stored by devise :trackable
  def last_sign_in_ip= value
    if value.present?
      super Digest::MD5.hexdigest(value)
    else
      super
    end
  end

  def current_sign_in_ip= value
    if value.present?
      super Digest::MD5.hexdigest(value)
    else
      super
    end
  end

  # FastBill: this method checks if a user already has fastbill profile
  def has_fastbill_profile?
    fastbill_id && fastbill_subscription_id
  end

  # FastBill
  # only update Fastbill profile if user is a Legal Entity
  def update_fastbill_profile
    if self.is_a?(LegalEntity) && self.has_fastbill_profile?
      FastbillUpdateUserWorker.perform_async self.id
    end
  end

  def count_value_of_goods
    value_of_goods_cents = self.articles.active.sum('price_cents * quantity')
    self.update_attribute(:value_of_goods_cents, value_of_goods_cents)
  end

  # Should work with has_many :article_templates, -> { where(state: :template) }, class_name: 'Article'
  # but it does not!
  def article_templates
    Article.unscoped.where(state: :template, seller: self.id)
  end

  def save_already_validated_standard_address!
    if self.standard_address
      self.standard_address = self.standard_address.duplicate_if_referenced!
      self.standard_address.save!(validate: false) # Already validates with validates_associates in user model
      self.update_column(:standard_address_id, self.standard_address.id)
    end
  end

  def build_standard_address_from address_params
    self.standard_address ||= self.addresses.build if address_params.select { |_param, value| !value.empty? }.any?
    self.standard_address.assign_attributes(address_params) if self.standard_address
  end

  def unified_transport_available?
    self.unified_transport_provider.present? &&
    self.unified_transport_maximum_articles.present? &&
    self.unified_transport_maximum_articles > 1 &&
    self.unified_transport_price_cents.present?
  end

  # used to get the right time for bike delivery
  def pickup_time
    times = []
    day_of_week = DateTime.now.cwday - 1 # array starts with 0
    weekend = day_of_week > 4 # is it Saturday or Sunday
    day_of_week = 0 if weekend
    days = %w(Mo Di Mi Do Fr)
    (0..4).each do |iterator| # iterate through the next days
      day = (iterator + day_of_week) % 5 # returns the place in the array for the day
      start_time = (iterator == 0 && !weekend) ? (Time.now.hour + 3) : 8 # on the current day we start later
      for hour in start_time..19 do
        times.push "#{ days[day] } #{ hour }:00  bis #{ hour + 1 }:00"
      end
    end
    times
  end

  def email_for_invoicing
    if self.is_a?(LegalEntity) && invoicing_email.present?
      invoicing_email
    else
      email
    end
  end

  def email_for_order_notifications
    if self.is_a?(LegalEntity) && order_notifications_email.present?
      order_notifications_email
    else
      email
    end
  end

  private

  # @api private
  def create_default_library
    if self.libraries.empty?
      Library.create(name: I18n.t('library.default'), public: false, user_id: self.id)
    end
  end

  def wants_to_sell?
    self.wants_to_sell
  end

  def is_german?
    self.standard_address && self.standard_address.country == 'Deutschland'
  end
end