Initial commit
This commit is contained in:
327
app/models/member.rb
Normal file
327
app/models/member.rb
Normal file
@@ -0,0 +1,327 @@
|
||||
# encoding: UTF-8
|
||||
# frozen_string_literal: true
|
||||
|
||||
require 'securerandom'
|
||||
|
||||
class Member < ApplicationRecord
|
||||
include ModelCaching
|
||||
MAX_GROUP = 4
|
||||
has_many :orders
|
||||
has_many :accounts
|
||||
has_many :stats_member_pnl
|
||||
has_many :payment_addresses
|
||||
has_many :withdraws, -> { order(id: :desc) }
|
||||
has_many :deposits, -> { order(id: :desc) }
|
||||
has_many :beneficiaries, -> { order(id: :desc) }
|
||||
has_many :bonus
|
||||
|
||||
serialize :cards, Array
|
||||
serialize :ibans, Array
|
||||
|
||||
scope :enabled, -> { where(state: 'active') }
|
||||
|
||||
before_validation :downcase_email
|
||||
|
||||
validates :uid, length: { maximum: 32 }
|
||||
validates :referral_uid, length: { maximum: 32 }
|
||||
validates :email, presence: true, uniqueness: true, email: true
|
||||
validates :level, numericality: { greater_than_or_equal_to: 0 }
|
||||
validates :role, inclusion: { in: ::Ability.roles }
|
||||
|
||||
before_create { self.group = self.group.strip.downcase }
|
||||
|
||||
class << self
|
||||
def groups
|
||||
TradingFee.distinct.pluck(:group)
|
||||
end
|
||||
|
||||
|
||||
def group_name_by_number(number)
|
||||
"vip-#{number}"
|
||||
end
|
||||
|
||||
def min_max_group(group_name)
|
||||
return [ENV.fetch('VIP_4_AMOUNT').to_d, 0] if group_name == 'vip-4'
|
||||
|
||||
return [ENV.fetch('VIP_3_AMOUNT').to_d, ENV.fetch('VIP_4_AMOUNT').to_d] if group_name == 'vip-3'
|
||||
|
||||
return [ENV.fetch('VIP_2_AMOUNT').to_d, ENV.fetch('VIP_3_AMOUNT').to_d] if group_name == 'vip-2'
|
||||
|
||||
return [ENV.fetch('VIP_1_AMOUNT').to_d, ENV.fetch('VIP_2_AMOUNT').to_d] if group_name == 'vip-1'
|
||||
|
||||
return [0, ENV.fetch('VIP_1_AMOUNT').to_d] if group_name == 'vip-0'
|
||||
end
|
||||
end
|
||||
|
||||
def group_update(order)
|
||||
|
||||
|
||||
return true if self.group == 'bot'
|
||||
|
||||
return true unless self.group.include?('vip')
|
||||
|
||||
all = self.trades.last_month.inject(0){ |sum, x| sum + x.rls }
|
||||
|
||||
return self.update(group: 'vip-4') if all > ENV.fetch('VIP_4_AMOUNT').to_d
|
||||
|
||||
return self.update(group: 'vip-3') if all > ENV.fetch('VIP_3_AMOUNT').to_d
|
||||
|
||||
return self.update(group: 'vip-2') if all > ENV.fetch('VIP_2_AMOUNT').to_d
|
||||
|
||||
return self.update(group: 'vip-1') if all > ENV.fetch('VIP_1_AMOUNT').to_d
|
||||
|
||||
self.update(group: 'vip-0')
|
||||
|
||||
end
|
||||
|
||||
|
||||
def next_group
|
||||
return group if group == Member.group_name_by_number(MAX_GROUP)
|
||||
|
||||
Member.group_name_by_number(group[4].to_i + 1)
|
||||
end
|
||||
|
||||
def trades
|
||||
Trade.where('maker_id = ? OR taker_id = ?', id, id)
|
||||
end
|
||||
|
||||
def role
|
||||
super&.inquiry
|
||||
end
|
||||
|
||||
def admin?
|
||||
role == "admin"
|
||||
end
|
||||
|
||||
def get_account(model_or_id_or_code)
|
||||
if model_or_id_or_code.is_a?(String) || model_or_id_or_code.is_a?(Symbol)
|
||||
accounts.find_or_create_by(currency_id: model_or_id_or_code)
|
||||
elsif model_or_id_or_code.is_a?(Currency)
|
||||
accounts.find_or_create_by(currency: model_or_id_or_code)
|
||||
end
|
||||
# Thread Safe Account creation
|
||||
rescue ActiveRecord::RecordNotUnique
|
||||
if model_or_id_or_code.is_a?(String) || model_or_id_or_code.is_a?(Symbol)
|
||||
accounts.find_by(currency_id: model_or_id_or_code)
|
||||
elsif model_or_id_or_code.is_a?(Currency)
|
||||
accounts.find_by(currency: model_or_id_or_code)
|
||||
end
|
||||
end
|
||||
|
||||
def referral_user
|
||||
self.class.find_by(uid: referral_uid) if referral_uid.present?
|
||||
end
|
||||
|
||||
# @deprecated
|
||||
def touch_accounts
|
||||
Currency.find_each do |currency|
|
||||
next if accounts.where(currency: currency).exists?
|
||||
accounts.create!(currency: currency)
|
||||
end
|
||||
end
|
||||
|
||||
def balance_for(currency:, kind:)
|
||||
account_code = Operations::Account.find_by(
|
||||
type: :liability,
|
||||
kind: kind,
|
||||
currency_type: currency.type
|
||||
).code
|
||||
liabilities = Operations::Liability.where(member_id: id, currency: currency, code: account_code)
|
||||
liabilities.sum('credit - debit')
|
||||
end
|
||||
|
||||
def legacy_balance_for(currency:, kind:)
|
||||
if kind.to_sym == :main
|
||||
get_account(currency).balance
|
||||
elsif kind.to_sym == :locked
|
||||
get_account(currency).locked
|
||||
else
|
||||
raise Operations::Exception, "Account for #{options} doesn't exists."
|
||||
end
|
||||
end
|
||||
|
||||
def revert_trading_activity!(trades)
|
||||
trades.each(&:revert_trade!)
|
||||
end
|
||||
|
||||
def payment_address(wallet_id, remote = false)
|
||||
wallet = Wallet.find(wallet_id)
|
||||
|
||||
return if wallet.blank?
|
||||
|
||||
pa = PaymentAddress.find_by(member: self, wallet: wallet, remote: remote)
|
||||
|
||||
if pa.blank?
|
||||
pa = payment_addresses.create!(wallet: wallet)
|
||||
elsif pa.address.blank?
|
||||
pa.enqueue_address_generation
|
||||
end
|
||||
|
||||
pa
|
||||
end
|
||||
|
||||
# Attempts to create additional deposit address for account.
|
||||
def payment_address!(wallet_id, remote = false)
|
||||
wallet = Wallet.find(wallet_id)
|
||||
|
||||
return if wallet.blank?
|
||||
|
||||
pa = PaymentAddress.find_by(member: self, wallet: wallet)
|
||||
|
||||
# The address generation process is in progress.
|
||||
if pa.present? && pa.address.blank?
|
||||
pa
|
||||
else
|
||||
# allows user to have multiple addresses
|
||||
pa = payment_addresses.create!(wallet: wallet, remote: remote)
|
||||
end
|
||||
pa
|
||||
end
|
||||
|
||||
def as_json_for_event_api
|
||||
{
|
||||
uid: uid,
|
||||
email: email,
|
||||
role: role,
|
||||
level: level,
|
||||
otp: otp,
|
||||
state: state,
|
||||
referral_uid: referral_uid
|
||||
}
|
||||
end
|
||||
|
||||
def sync_beneficiaries
|
||||
fiat_currency = Currency.find('irt')
|
||||
fiat_beneficiaries = beneficiaries.active_to_member.where(currency: fiat_currency)
|
||||
array_beneficiaries = fiat_beneficiaries.map { |beneficiary| beneficiary&.data.dig('account_number') }&.compact
|
||||
|
||||
# delete extra beneficiary that was deleted in the Dalan
|
||||
fiat_beneficiaries.each { |b| b.delete unless b.data.dig('account_number')&.in?(flat_cards + flat_ibans) }
|
||||
|
||||
# add beneficiary that was added in the Dalan
|
||||
cards&.each { |c| create_beneficiary('card', c&.keys&.last, c&.values&.last, fiat_currency) unless c&.values&.last.in? (array_beneficiaries) }
|
||||
ibans&.each { |i| create_beneficiary('iban', i&.keys&.last, i&.values&.last, fiat_currency) unless i&.values&.last.in? (array_beneficiaries) }
|
||||
end
|
||||
|
||||
def flat_cards
|
||||
return [] unless cards.present?
|
||||
|
||||
cards.map(&:values).flatten
|
||||
end
|
||||
|
||||
def flat_ibans
|
||||
return [] unless ibans.present?
|
||||
|
||||
ibans.map(&:values).flatten
|
||||
end
|
||||
|
||||
def create_beneficiary(kind, name, data, currency, state: 'active')
|
||||
beneficiaries.create!(currency: currency,
|
||||
data: { full_name: name, account_number: data, kind: kind },
|
||||
name: name, state: state)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def downcase_email
|
||||
self.email = email.try(:downcase)
|
||||
end
|
||||
|
||||
class << self
|
||||
def uid(member_id)
|
||||
Member.find_by(id: member_id)&.uid
|
||||
end
|
||||
|
||||
def find_by_username_or_uid(uid_or_username)
|
||||
if Member.find_by(uid: uid_or_username).present?
|
||||
Member.find_by(uid: uid_or_username)
|
||||
elsif Member.find_by(username: uid_or_username).present?
|
||||
Member.find_by(username: uid_or_username)
|
||||
end
|
||||
end
|
||||
|
||||
def from_payload(p)
|
||||
params = filter_payload(p)
|
||||
validate_payload(params)
|
||||
member = ::Member.find_or_create_by(uid: p[:uid]) do |m|
|
||||
m.email = params[:email]
|
||||
m.username = params[:username]
|
||||
m.role = params[:role]
|
||||
m.state = params[:state]
|
||||
m.level = params[:level]
|
||||
m.referral_uid = params.dig(:referral_uid)
|
||||
m.last_change_pass = params.dig(:last_change_pass)
|
||||
m.cards = params.dig(:cards)
|
||||
m.ibans = params.dig(:ibans)
|
||||
m.otp = params.dig(:otp)
|
||||
end
|
||||
member.assign_attributes(params)
|
||||
# comment if dont want sync beneficiary
|
||||
# flag_beneficiary = member.ibans_changed? || member.cards_changed? ? true : false
|
||||
member.save! if member.changed?
|
||||
# member.reload.sync_beneficiaries if flag_beneficiary
|
||||
member
|
||||
end
|
||||
|
||||
|
||||
# Filter and validate payload params
|
||||
def filter_payload(payload)
|
||||
payload.slice(:email, :username, :uid, :role, :state, :level, :referral_uid, :last_change_pass, :cards, :ibans, :otp)
|
||||
end
|
||||
|
||||
def validate_payload(p)
|
||||
fetch_email(p)
|
||||
p.fetch(:uid).tap { |uid| raise(Peatio::Auth::Error, 'UID is blank.') if uid.blank? }
|
||||
p.fetch(:role).tap { |role| raise(Peatio::Auth::Error, 'Role is blank.') if role.blank? }
|
||||
p.fetch(:level).tap { |level| raise(Peatio::Auth::Error, 'Level is blank.') if level.blank? }
|
||||
p.fetch(:state).tap do |state|
|
||||
raise(Peatio::Auth::Error, 'State is blank.') if state.blank?
|
||||
raise(Peatio::Auth::Error, 'State is not active.') unless state == 'active'
|
||||
end
|
||||
end
|
||||
|
||||
def fetch_email(payload)
|
||||
payload[:email].to_s.tap do |email|
|
||||
raise(Peatio::Auth::Error, 'E-Mail is blank.') if email.blank?
|
||||
raise(Peatio::Auth::Error, 'E-Mail is invalid.') unless EmailValidator.valid?(email)
|
||||
end
|
||||
end
|
||||
|
||||
def search(field: nil, term: nil)
|
||||
term = "%#{term}%"
|
||||
case field
|
||||
when 'email'
|
||||
where("email LIKE ?", term)
|
||||
when 'uid'
|
||||
where('uid LIKE ?', term)
|
||||
when 'wallet_address'
|
||||
joins(:payment_addresses).where('payment_addresses.address LIKE ?', term)
|
||||
else
|
||||
all
|
||||
end.order(:id).reverse_order
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# == Schema Information
|
||||
# Schema version: 20201207134745
|
||||
#
|
||||
# Table name: members
|
||||
#
|
||||
# id :integer not null, primary key
|
||||
# uid :string(32) not null
|
||||
# email :string(255) not null
|
||||
# username :string(255)
|
||||
# level :integer not null
|
||||
# role :string(16) not null
|
||||
# group :string(32) default("vip-0"), not null
|
||||
# state :string(16) not null
|
||||
# created_at :datetime not null
|
||||
# updated_at :datetime not null
|
||||
#
|
||||
# Indexes
|
||||
#
|
||||
# index_members_on_email (email) UNIQUE
|
||||
# index_members_on_uid (uid) UNIQUE
|
||||
# index_members_on_username (username) UNIQUE
|
||||
#
|
||||
Reference in New Issue
Block a user