Commit 26f24a97 by houdelin

change models

parent 8bea813e
module OrganizationUserable module CrmUc
extend ActiveSupport::Concern module OrganizationUserable
extend ActiveSupport::Concern
included do included do
end end
def all_staffs def all_staffs
if AppSettings.uc_enabled? if AppSettings.uc_enabled?
users users
else else
users.where(locked_at: nil) users.where(locked_at: nil)
end
end end
end
def strictly_staffs def strictly_staffs
users.leaves.with_organization_staff_state users.leaves.with_organization_staff_state
end end
def all_active_staffs def all_active_staffs
if AppSettings.uc_enabled? if AppSettings.uc_enabled?
all_staffs.joins(:user_extra).where(user_extras: {last_sign_in_at: 6.months.ago..Time.now}) all_staffs.joins(:user_extra).where(user_extras: {last_sign_in_at: 6.months.ago..Time.now})
else else
all_staffs.where(last_sign_in_at: 6.months.ago..Time.now) all_staffs.where(last_sign_in_at: 6.months.ago..Time.now)
end
end end
end
def all_inactive_staffs def all_inactive_staffs
if AppSettings.uc_enabled? if AppSettings.uc_enabled?
all_staffs.joins(:user_extra).where("user_extras.last_sign_in_at < ?", 6.months.ago) all_staffs.joins(:user_extra).where("user_extras.last_sign_in_at < ?", 6.months.ago)
else else
all_staffs.where("last_sign_in_at < ?", 6.months.ago) all_staffs.where("last_sign_in_at < ?", 6.months.ago)
end
end end
end
module ClassMethods module ClassMethods
end
end end
end end
class Department < ActiveRecord::Base class Department < ActiveRecord::Base
self.table_name = AppSettings.table_name('departments') self.table_name = AppSettings.table_name('departments')
include DepartmentOwnerable
include DepartmentUserable
include TreeDescendantable
include CrmUc::UserCenterable include CrmUc::UserCenterable
tree_depth_as 20
status_scope_as true
extend ActsAsTree::TreeWalker
include ActsAsTree
enum status: [:hide, :visible]
belongs_to :organization
has_many :users_departments
has_many :users, -> { paranoia_scope }, through: :users_departments
has_many :admins_departments
has_many :admins, through: :admins_departments
after_commit -> { Cache::DepartmentService.update_cache_key(self) }
default_scope { visible }
scope :stateless, -> { unscope(where: :status) }
scope :with_path_deep, -> (path_deep = 1) {
path_deep_calcul_sql = %Q{ROUND ( (LENGTH(path) - LENGTH(REPLACE(path, '/', ''))) / LENGTH('/') )}
where("(#{path_deep_calcul_sql}) = ?", path_deep)
}
scope :descendants_for, -> (department_id) {
where("#{self.table_name}.path like ?", "%/#{department_id}/%")
}
scope :self_and_descendants_for, -> (department_id) {
where("(#{self.table_name}.path like ?) or (#{self.table_name}.path rlike ?)", "%/#{department_id}/%", "\/#{department_id}$")
}
scope :self_and_parents_and_descendants_for, -> (department) {
where("(#{self.table_name}.id in (?)) or (#{self.table_name}.path like ?) or (#{self.table_name}.path rlike ?)", department.path.to_s.split('/').map(&:to_i), "%/#{department.id}/%", "\/#{department.id}$")
}
scope :self_and_ancestors_for, -> (department) {
where(id: department.path.to_s.split('/').map(&:to_i))
}
acts_as_tree order: "position asc"
# acts_as_list scope: [:parent_id, :organization_id, "deleted_at"], add_new_at: :bottom
#TODO change single quote to double quotes
acts_as_list scope: '#{parent_id.present? ? %Q{parent_id = #{parent_id}} : %q{parent_id is null}} and #{organization_id.present? ? %Q{organization_id = #{organization_id}} : %q{organization_id is null}} and deleted_at is null', add_new_at: :bottom
validates_associated :organization
acts_as_paranoid
has_one :ding_department
attr_accessor :position_action
delegate :in_ding_exist?, to: :ding_department, allow_nil: true
def can_destroy_this?
!self.users.exists?
end
def parent
return if parent_id.blank?
self.class.stateless.find_by(id: parent_id)
end
def deep_length
tree_depth
end
def descendant_departments
descendant_entities
end
def descendant_department_ids
descendant_entity_ids
end
def self_and_descendant_departments
self_and_descendant_entities
end
def self_and_descendant_department_ids
self_and_descendant_entity_ids
end
def self_and_parent_departments
self_and_ancestor_entities
end
def self_and_parent_and_descendant_departments
Department.where(organization_id: organization_id).self_and_parents_and_descendants_for(self)
end
def child_department_ids
self_and_descendant_entity_ids
end
def to_s
name || id.to_s
end
def can_be_deleted?
! User.stateless.where(deleted_at: nil).joins(:users_department).exists?(["#{UsersDepartment.table_name}.department_id in(?)", self_and_descendant_entities.stateless.select(:id)])
end
alias :is_delete_department :can_be_deleted?
class << self
# :key [:symbol] every node key was node.send(key)
# :fields [:array] every node value
# :proc if block_given? exec proc.call(children_list)
# else will wrappen node's child list to {children: children_list}
def children_tree_data(child, key = :id, fields = [:id ,:name], descendants = nil, &proc)
tree_hash = HashWithIndifferentAccess.new({})
fields = fields.map(&:to_s)
key_val = child.send(key)
#_tree_hash = {key_val => child.attributes.select{|k,_| fields.include?("#{k}")} }
_fields_data = {}
fields.each do |f|
value = child.send(f) rescue nil
_fields_data.reverse_merge! f => value
end
_tree_hash = HashWithIndifferentAccess.new({key_val => _fields_data })
_children = if descendants.is_a?(Array)
descendants.select{|d| d.parent_id == child.id }
else
child.children
end
if _children.present?
children_tree = HashWithIndifferentAccess.new({})
_children.each do |_child|
children_tree.merge! children_tree_data(_child, key, fields, descendants, &proc)
end
if block_given?
_tree_hash[key_val].merge! proc.call(children_tree)
else
_tree_hash[key_val][:children] = children_tree
end
end
tree_hash.merge! _tree_hash
end
def walk_tree_department(departments, level = 0, parent_id = nil, &block)
departments.select{|department| department.parent_id == parent_id}.each do |department|
block.call(department, level)
walk_tree_department(departments, (level + 1), department.id, &block)
end
end
def self_and_descendant_department_ids_by_departments(departments = [])
return [] if departments.blank?
department_ids = []
departments.compact.each do |department|
_ids = department.self_and_descendant_department_ids
next if _ids.blank?
department_ids.concat(_ids)
end
department_ids = department_ids.compact.uniq
department_ids
rescue
[]
end
end
end end
class Organization < ActiveRecord::Base class Organization < ActiveRecord::Base
self.table_name = AppSettings.table_name('organizations') self.table_name = AppSettings.table_name('organizations')
include OrganizationPartitionTableable
include OrganizationSettingable
include OrganizationKnowledgeBaseable
include CrmUc::OrganizationRoleable include CrmUc::OrganizationRoleable
include CrmUc::OrganizationUserable include CrmUc::OrganizationUserable
include OrganizationOwnerable
include CommonEntityOwnershipish::Ownerable
include OrganizationCustomerCommonOwnerable
include OrganizationLeadCommonOwnerable
include OrganizationScheduleReportable
include OrganizationBuildable
include OrganizationToCBuildable
include OrganizationIndustryBuildable
include OrganizationDatasyncable
include OrganizationCounterable
include OrganizationRevisitLogRankable
include OrganizationStatusable
include OrganizationCallCenterable
include OrganizationInvoicable
unless AppSettings.uc_enabled?
include Rankable
rankable
end
# connect to cms#client load delegate some method to client
include OrganizationCmsClientPatchable
include Crm::OrgClientPatchable
include OrganizationContractable
include OrganizationApprovable
include OrganizationDingOrganizationable
include OrganizationLiteappable
include OrganizationSmsable
include CustomDuplicateCheck
include CustomFeatureSetable
include OrganizationFeatureable
include OrganizationNoviceTaskable
include CrmUc::UserCenterable include CrmUc::UserCenterable
# organization 扩展表
include OrganizationExtrable
scope :has_entities_data, -> { joins(:organization_extra).where("
organization_extras.customers_count > 0 or
organization_extras.contacts_count > 0 or
organization_extras.leads_count > 0 or
organization_extras.opportunities_count > 0 or
organization_extras.contracts_count > 0")
}
scope :with_activity, -> (datetime) {
where(activity_at: datetime.beginning_of_day..Time.now.end_of_day)
}
belongs_to :owner, class_name: :User, primary_key: :id, foreign_key: :user_id
has_many :users, -> { paranoia_scope }
has_many :user_extras
has_many :departments, -> { order("position asc") }
has_many :common_entity_owners, dependent: :delete_all
has_many :common_ownerables, -> { order('id DESC') }, as: :ownerable, class_name: "CommonEntityOwner"
has_many :attachments
has_many :audios
has_many :contacts
has_many :contracts
has_many :received_payments, dependent: :delete_all
has_many :customers
has_many :opportunities
has_many :events, dependent: :delete_all
has_many :leads
has_many :lead_extras
has_many :products
has_many :product_categories
has_many :product_assets
has_many :import_histories, dependent: :delete_all
has_many :field_maps
has_many :field_values
has_many :custom_field_settings
has_many :custom_fields
has_many :notifications, dependent: :delete_all
has_many :reminders, dependent: :delete_all
has_many :operation_logs, dependent: :delete_all
has_many :login_logs, dependent: :delete_all
has_many :ip_whitelists, dependent: :delete_all
has_many :roles
has_many :report_rank_roles
has_many :announcements, dependent: :delete_all
has_many :knowledge_catalogs
has_many :knowledge_entities
has_many :checkins, dependent: :delete_all
has_many :sales_activities, dependent: :delete_all
has_many :sales_goal_yearlies, dependent: :delete_all
has_many :schedule_reports, class_name: "ScheduleReport::Base", dependent: :delete_all
has_many :revisit_logs, dependent: :delete_all
has_many :reminders, dependent: :delete_all
has_many :data_reports, dependent: :delete_all
has_many :data_report_areas, dependent: :delete_all
has_many :data_report_stores, dependent: :delete_all
has_many :custom_reports, dependent: :delete_all
# ik_invoicing_data
has_many :ik_invoicing_users
has_many :ik_invoicing_customers, through: :customers
has_many :ik_invoicing_product_categories, through: :product_categories
has_many :ik_invoicing_products, through: :products
#sales_circle
has_many :sales_circles, dependent: :delete_all
has_many :markings, dependent: :delete_all
has_many :sales_activity_comments, through: :users, dependent: :delete_all
has_one :cross_site_entity, -> { order('id DESC') }, as: :cross_siteable, class_name: "CrossSiteEntity"
has_one :logo, -> { where(sub_type: 'logo').order(id: :desc) } , class_name: 'Attachment', as: :attachmentable
has_one :king_organization
has_many :knowledge_sections, dependent: :delete_all
has_many :knowledge_articles, through: :knowledge_sections, dependent: :delete_all
has_many :liteapp_subscribes, dependent: :delete_all
has_many :ik_tags, dependent: :delete_all
has_many :received_payment_plans
has_many :invoiced_payments
has_many :expenses
has_many :expense_accounts
has_many :payslip_stats, dependent: :delete_all
has_many :payslips, dependent: :delete_all
has_many :stations, dependent: :delete_all
has_many :commission_rules, dependent: :delete_all
has_many :commission_stats, dependent: :delete_all
has_many :performance_indicators, dependent: :delete_all
has_many :performance_monthly_stats, dependent: :delete_all
has_one :business_query_account
has_many :business_query_orders
has_many :business_query_subscriptions
has_many :cms_materials
has_many :print_templates
has_many :custom_field_templates
has_many :custom_field_template_roles
has_many :soukebox_accounts
has_many :master_soukebox_accounts, ->{master}, class_name: SoukeboxAccount.name
has_many :agent_soukebox_accounts, ->{agent}, class_name: SoukeboxAccount.name
has_many :slave_soukebox_accounts, ->{slave}, class_name: SoukeboxAccount.name
has_many :novice_task_maps, dependent: :destroy
has_many :novice_task_item_maps, dependent: :delete_all
has_many :labels, dependent: :delete_all
has_many :label_groups, -> { order(:position) }, dependent: :delete_all
has_one :organization_setting, dependent: :destroy
# 旧社交推广-后期需要移除
has_many :social_shares, dependent: :delete_all
# 社交推广相关
has_many :social_promotions, dependent: :delete_all
has_many :social_promotion_records, dependent: :delete_all
has_one :organization_setting, dependent: :destroy
has_many :sms_identities
has_many :external_customers
def super_user
self.owner || self.super_users.first
end
def logo_url
self.try(:corp_logo_url) || self.logo.try(:file_url)
end
def largess_sms_novice_task_map
if novice_task_maps.present?
novice_task_maps.joins(:novice_task).where(novice_tasks: {largess_type: 0}).take
end
end
def user_with_role(role_arg = nil)
users.joins(:role).where("roles.id" => role_arg)
end
def user_with_department(department_arg = nil)
users.joins(:users_department).where("#{UsersDepartment.table_name}.department_id" => department_arg)
end
def opportunity_stage_values
field_maps.find_by(field_name:'stage', klass_name: 'Opportunity').field_values
end
def department_tree_data
depts = departments
if AppSettings.dingtalk?
depts = depts.includes(:ding_department)
end
depts = depts.order("position asc")
depts = depts.map do |dept|
_dept_hash = {
children: [],
deep_length: dept.deep_length,
id: dept.id,
is_delete_department: dept.is_delete_department,
name: dept.name,
parent_id: dept.parent_id,
position: dept.position
}
_dept_hash[:in_wx_exist?] = AppSettings.wxwork? && dept.in_wx_exist?
_dept_hash[:in_ding_exist?] = AppSettings.dingtalk? && dept.in_ding_exist?
_dept_hash
end
depts.each do |dept|
dept[:children] = depts.select{|_dept| _dept[:parent_id] == dept[:id]}
end
depts.select{|dept| dept[:parent_id].blank? }.each do |dept|
department_children_data(dept, depts)
end
end
def department_children_data(dept, depts)
dept[:children].each do |child_dept|
child_dept[:children] = depts.detect{|_dept| _dept[:id] == child_dept[:id]}[:children] rescue []
department_children_data(child_dept, depts)
end if dept[:children]
end
def data_report_area_tree_data(key = :id ,fields = [:id, :name], &proc)
tree_hash = HashWithIndifferentAccess.new({})
data_report_areas.roots.each do |child|
if block_given?
_tree_hash = DataReportArea.children_tree_data(child, key, fields, &proc)
else
_tree_hash = DataReportArea.children_tree_data(child, key, fields)
end
tree_hash.merge!(_tree_hash) if _tree_hash.present?
end
tree_hash
end
def field_map_values_sync
map = field_maps.find_by(klass_name: 'Lead', field_name: 'source')
return unless map
values = field_values.joins(:field_map).where('field_maps.klass_name in (?) and field_maps.field_name = ?', ['Customer', 'Opportunity', 'Lead'], 'source')
values.map(&:value).uniq.each_with_index do |value, i|
puts "sync_field_map_values organization id: #{id}, value: #{value}"
field_value = map.field_values.find_or_initialize_by(value: value, position: i)
field_value.save_and_sync
end
end
def expires_days
(expires_at.to_date - Date.today).to_i rescue 0
end
def is_near_expire?(date = Date.today)
return false if expires_at.blank?
((date.to_date - expires_at.to_date).to_i rescue 0) >= 0
end
def first_super_user
super_role_ids = roles.select { |role|
role.is_super_user?
}.map(&:id)
users.joins(:roles_user).find_by(RolesUser.table_name => {role_id: super_role_ids})
end
def birthday_enabled?
Contact.enabled_custom_fields_by_organization(self.id)
.map(&:name)
.include?('birth_date')
end
def joined?
%w(dingtalk aliyun_dingtalk_one wxwork).include?(AppSettings[:app_type]) ? super : false
end
def risk_packages
if client.present?
(client.risk_packages.active.send(client.product_type) +
RiskPackage.all_clients.active.send(client.product_type)
)
.sort { |x,y| y.position <=> x.position }
.uniq { |o| o.id }
else
[]
end
end
def ding_host
@ding_host ||= CrossSites.ding_host(organization: self)
end
def max_customer_common_setting_count
_setting = (organization_setting || OrganizationSetting.new(organization: self))
_setting.customer_common_setting_limit
end
def org_version
if AppSettings.uc_enabled?
package = UserCenter::Services::PackageServices.cache_info(self.oid)
if package[:version].eql?(1)
'normal'
elsif package[:version].eql?(2)
'simplify'
elsif package[:version].eql?(3)
'professional'
end
else
org_client.present? ? org_client.version : "normal"
end
end
def unenable_moudles(disable_name)
case org_version
when 'simplify'
APP_CONFIG["simplify_version_" + "#{disable_name}"] || []
else
[]
end
end
def wx_corp_id
UserCenter::Services::Wx::TransferIdServices.get_wx_corp_id_by_oid(oid)
end
def platform_corp_id
if AppSettings.ikcrm?
corp_id
elsif AppSettings.wxwork?
wx_corp_id
elsif AppSettings.dingtalk?
# TODO 对接用户中心之后改为调接口
ding_organization.corp_id
end
end
# 励销已对接用户中心,可以用此方法获取试用状态,钉钉需对接用户中心之后调用此方法才能正常使用
def can_trial?
if AppSettings.wxwork?
Bms::Trials::TrialService.can_trial?({ app_type: 'lixiaocrm', organization_id: id })
elsif AppSettings.dingtalk?
Bms::Trials::TrialService.can_trial?({ app_type: 'ikcrm_dingtalk', organization_id: id })
else
false
end
end
# 励销已对接用户中心,可以用此方法获取试用状态,钉钉需对接用户中心之后调用此方法才能正常使用
def on_trial?
if AppSettings.uc_enabled?
UserCenter::Services::PackageServices.cache_info(oid)[:license_type].eql?(3)
elsif AppSettings.dingtalk?
Bms::Trials::TrialService.on_trial?({ app_type: 'ikcrm_dingtalk', organization_id: id })
end
end
def init_complated?
extra.set_up_status.blank? || extra.set_up_status == 'completed'
end
class << self
def find_by_wx_corp_id(wx_corp_id)
Organization.find_by(oid: UserCenter::Services::Wx::TransferIdServices.get_oid_by_wx_corp_id(wx_corp_id))
end
def find_by_platform_corp_id(corp_id)
if AppSettings.ikcrm?
Organization.find_by(corp_id: corp_id)
elsif AppSettings.wxwork?
Organization.find_by_wx_corp_id(corp_id)
elsif AppSettings.dingtalk?
# TODO 对接用户中心之后修改
DingOrganization.find_by(corp_id: corp_id).organization
end
end
end
end end
class RolesUser < ActiveRecord::Base class RolesUser < ActiveRecord::Base
self.table_name = AppSettings.table_name('roles_users') self.table_name = AppSettings.table_name('roles_users')
belongs_to :role
belongs_to :user
after_commit :enqueue_reset_customers_flow_time
def enqueue_reset_customers_flow_time
if Role.super.where(id: previous_changes[:role_id]).present?
CustomerCommons::UserFlowTimeWorker.perform_async(user_id)
end
end
end end
class User < ActiveRecord::Base class User < ActiveRecord::Base
self.table_name = AppSettings.table_name('users') self.table_name = AppSettings.table_name('users')
has_secure_password(validations: false)
include Queryable
include Searchable
include Grantish::Grantee
include UserOwnerable
include EntitiesAssistUserish::AssistUserable
include CommonEntityOwnershipish::Ownerable
include UserVisible
include UserInstructionable
include UserSecureTokenable
include UserOwnerScopeable
include UserDepartmentable
include UserPermissionable
include UserSuperiorable
include UserConfirmPhoneable
include UserPasswordable
include UserDestroyable
unless AppSettings.uc_enabled?
include UserWorkflowable
end
include UserOrganizationBuildable
include UserScheduleReportable
include UserSettingable
include UserStatusable
include UserSalesGoalable
include ReportReminderConfigurable
include UserWechatable
include UserDingUserable
include UserSmsHistoryable
include UserSmsable
include UserRoleable
include UserWxUserable
include UserMinaable
# 用户扩展字段
include UserExtrable
include CrmUc::UserCenterable include CrmUc::UserCenterable
include Queryable::Selectable
# 如果要判断user是不是独立版用户,请用User#ikcrm_user?方法
enum user_type: {
normal_user: 0,
dingtalk_user: 1,
kingdee_user: 2,
wechat_user: 3,
wx_user: 4
}
enum status: [:hide, :visible]
if AppSettings.uc_enabled?
enum permission: [:deny, :edit, :show]
end
default_scope { usable }
scope :stateless, -> { unscope(where: [:status, :locked_at, :usable]) }
scope :visible, -> { stateless.where(status: statuses[:visible]) }
scope :usable, -> {
if AppSettings.uc_enabled?
where(usable: true)
else
where(status: statuses[:visible], locked_at: nil)
end
}
scope :preload_avatar, -> {
case AppSettings[:app_type]
when "ikcrm"
preload(:attachment, :uc_account)
when "dingtalk"
preload(:ding_user, :attachment)
when "wxwork"
preload(:attachment)
end
}
scope :order_by_checkin_count, -> { joins("LEFT JOIN checkins on checkins.user_id = #{User.table_name}.id").group(:id).order('count(1) desc') }
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable and :omniauthable
unless AppSettings.uc_enabled?
# devise :timeoutable
# devise :database_authenticatable, :registerable, :lockable,
# :recoverable, :trackable, :validatable#, :confirmable
end
base_search_fields_on :name, :email, :phone
belongs_to :organization
belongs_to :organization_extra, foreign_key: :organization_id
if AppSettings.uc_enabled?
belongs_to :uc_account, foreign_key: :account_aid, primary_key: :aid
delegate :gender, to: :uc_account, allow_nil: true
end
has_one :roles_user, dependent: :destroy
accepts_nested_attributes_for :roles_user, allow_destroy: true
has_one :role, through: :roles_user
has_one :api_key
has_many :permissions, through: :role
has_one :users_department, dependent: :destroy
has_one :department, -> { stateless }, through: :users_department
has_many :users_assist_departments, dependent: :destroy
has_many :assist_departments, -> { stateless }, through: :users_assist_departments, source: :department
accepts_nested_attributes_for :users_department, :users_assist_departments, allow_destroy: true
attr_accessor :before_department_ids
has_many :admins_departments, dependent: :destroy
has_many :admin_departments, through: :admins_departments
has_many :custom_columns, dependent: :delete_all
has_one :contract_columns, -> { where(model_klass: 'Contract') }, class_name: 'CustomColumn'
has_one :customer_columns, -> { where(model_klass: 'Customer') }, class_name: 'CustomColumn'
has_one :customer_common_columns, -> { where(model_klass: 'CustomerCommon') }, class_name: 'CustomColumn'
has_one :contact_columns, -> { where(model_klass: 'Contact') }, class_name: 'CustomColumn'
has_one :opportunity_columns, -> { where(model_klass: 'Opportunity') }, class_name: 'CustomColumn'
has_one :lead_columns, -> { where(model_klass: 'Lead') }, class_name: 'CustomColumn'
has_one :product_columns, -> { where(model_klass: 'Product') }, class_name: 'CustomColumn'
has_one :received_payment_plan_columns, -> { where(model_klass: 'ReceivedPaymentPlan') }, class_name: 'CustomColumn'
has_one :invoiced_payment_columns, -> { where(model_klass: 'InvoicedPayment') }, class_name: 'CustomColumn'
has_one :received_payment_columns, -> { where(model_klass: 'ReceivedPayment') }, class_name: 'CustomColumn'
has_one :expense_account_columns, -> { where(model_klass: 'ExpenseAccount') }, class_name: 'CustomColumn'
has_many :schedule_reports, class_name: 'ScheduleReport::Base'
has_many :marking_reports, class_name: 'ScheduleReport::Base', foreign_key: :marking_user_id
has_many :markings
has_many :customers
has_many :opportunities
has_many :contacts
has_many :contracts
has_many :leads
#creator_resources 表示resources是用户作为创建者自己创建的,不是转过来的
has_many :creator_customers, foreign_key: :creator_id, class_name: Customer.name
has_many :creator_opportunities, foreign_key: :creator_id, class_name: Opportunity.name
has_many :creator_contacts, foreign_key: :creator_id, class_name: Contact.name
has_many :creator_contracts, foreign_key: :creator_id, class_name: Contract.name
has_many :creator_leads, foreign_key: :creator_id, class_name: Lead.name
has_many :event_users, dependent: :delete_all
has_many :events, through: :event_users, dependent: :destroy
has_many :revisit_logs
has_many :user_devices, dependent: :destroy
has_many :grants, as: :grantee
has_one :attachment, as: :attachmentable
accepts_nested_attributes_for :attachment, allow_destroy: true
validates_acceptance_of :tos_agreement, :allow_nil => true, :on => :create
has_many :sales_activities
has_many :login_logs
has_many :checkins
has_many :attachments
has_many :import_histories
has_many :data_report_contents
has_many :data_report_readers, dependent: :destroy
has_many :data_reports, through: :data_report_readers
has_many :report_reminder_configs, dependent: :destroy
has_many :approvals
has_many :sales_activity_comments
has_many :sales_circles, ->(u) { where(organization_id: u.organization_id) }
has_many :sales_circle_comments
has_many :sales_circle_msgs, foreign_key: :send_to_id
has_many :likes
has_many :ats
has_one :ding_user
has_one :wechat_user
has_many :knowledge_articles
has_many :ding_upgrade_notice_logs
has_many :notifications, foreign_key: 'notifiable_id', dependent: :delete_all
has_many :upgrade_notice_logs, dependent: :delete_all
has_one :call_agent
has_many :call_records
has_many :custom_reports, dependent: :destroy
has_many :dial_logs
has_many :sms_records
has_many :sms_user_quotas
has_many :sms_quotas, through: :sms_user_quotas
has_one :ik_invoicing_user, dependent: :destroy
has_many :payslips
has_one :business_query_account
has_many :expenses
has_many :expense_accounts
has_many :cms_material_users
has_many :custom_field_template_roles, through: :role
has_one :soukebox_account
# 社交推广相关
has_many :social_promotions, dependent: :delete_all
def open_api_enabled?
oauth_applications.present?
end
attr_accessor :login
attr_accessor :want_unlock_access, :want_lock_access, :switch_access_status
attr_accessor :want_phone
attr_accessor :department_id, :append_admin_department_id
attr_accessor :skip_cache_and_queue
attr_accessor :have_new_feature_on_sales_circle, :sales_circle_msg_count
attr_accessor :has_policy_for_model_action
unless AppSettings.uc_enabled?
validates_uniqueness_of :phone, conditions: -> { paranoia_scope }, allow_nil: true, allow_blank: true
validates_uniqueness_of :email, conditions: -> { paranoia_scope }, allow_nil: true, allow_blank: true
validate :validate_email_phone_presence
end
delegate :in_ding_exist?, to: :ding_user, allow_nil: true
delegate :enabled_number_hidden_dispose?, to: :role, allow_nil: true
alias enabled_number_hidden_dispose enabled_number_hidden_dispose?
def unbind_soukbox
_account = self.soukebox_account
if _account.present?
unless _account.out_biz_uid.nil?
# 已经验证过账号的,还需要去搜客宝那边进行解绑
_soukebox_service = SoukeboxServices::Services::App.new(_account)
_data = _soukebox_service.unbind
if _data['error_code'].to_s == '0'
_account.update!(user_id: nil, uid: nil, out_biz_uid: nil, status: 0, bind_phone: nil)
if AppSettings.uc_enabled?
SoukeboxAccount.where(parent_account_id: _account.id,level: 2).delete_all
_account.delete
end
end
else
# 这个肯定是没有验证过的情况,只要把user置空就行,暂时无需记录 TODO 需要和产品说明情况
_account.update!(user_id: nil, uid: nil, status: 0, bind_phone: nil )
_account.delete if AppSettings.uc_enabled?
end
end
end
def parent
return if superior_id.blank?
self.class.stateless.find_by(id: superior_id)
end
def locked_at
if AppSettings.uc_enabled?
usable? ? nil : Time.now
else
self.attributes['locked_at']
end
end
def ikcrm_user?
AppSettings.ikcrm?
end
if AppSettings.wxwork?
def phone
self.attributes["phone"].gsub(/^lxjxc/, "") if self.attributes["phone"]
end
def email
self.attributes["email"].gsub(/^lxjxc/, "") if self.attributes["email"]
end
end
def secret_phone
phone[0..2] + "*"*4 + phone[-4..-1]
end
def validate_email_phone_presence
if AppSettings.normal_ikcrm? && phone.blank? && email.blank?
self.errors.add(:phone, "邮箱或者手机必须填")
end
end
def to_s
name || email
end
def my_announcements
if try(:organization_owner?)
organization.announcements
else
Announcement.
joins("join grants on grants.subject_id = announcements.id and grants.subject_type = 'Announcement'").
where("(grants.grantee_type = 'Department' and grants.grantee_id in (:department_id)) or (grants.grantee_type = 'Role' and grants.grantee_id in (:role_id)) or (grants.grantee_type = 'Organization' and grants.grantee_id = :organization_id)", department_id: all_joined_department_ids, role_id: role.try(:id), organization_id: organization_id)
end
end
def organization_owner?
self.organization.try(:user_id) == self.id
end
alias :org_creator? :organization_owner?
def email_required?
false
end
def password_required?
false
end
def email_changed?
false
end
GENDERS = HashWithIndifferentAccess.new(I18n.t("enums.user.gender"))
def gender_display
GENDERS[self.gender.to_sym] if self.gender
end
def default_avatar_url
self.class.default_avatar_url(gender)
end
def avatar_thumbnail(thumbnail = :medium)
case thumbnail
when :small
"50x50"
when :medium
"100x100"
when :large
"200x200"
else
"500x500"
end
end
# http://developer.qiniu.com/docs/v6/api/reference/fop/image/imagemogr2.html#imageMogr2-thumbnail-spec
# /thumbnail/<Width>x<Height>!
# 限定目标图片宽高值,忽略原图宽高比例,按照指定宽高值强行缩略,可能导致目标图片变形。
# 取值范围不限,但若宽高超过10000只能缩不能放
#
# /strip
# 去除图片中的元信息
def qiniu_image_path(source, thumbnail = :medium)
thumbnail = "#{avatar_thumbnail(thumbnail)}"
source += "?imageMogr2"
source += "/thumbnail/!#{thumbnail}r" if thumbnail
source += "/crop/!#{thumbnail}"
source += "/format/jpg/auto-orient"
source
end
def avatar_url(thumbnail = :medium, specify_gender = nil)
if AppSettings.uc_enabled? && uc_account&.avatar_url.present?
qiniu_image_path(uc_account.avatar_url, thumbnail)
elsif attachment
qiniu_image_path(attachment.file.url, thumbnail)
elsif dingtalk_user?
ding_user.try(:avatar).presence || default_avatar_url
elsif wechat_user? && wechat_user.headimage_url.present?
wechat_user.headimage_url
else
default_avatar_url
end
end
def department_name
department.try(:name)
end
def organization_name
organization.try(:name)
end
def superior_name
superior.try(:name)
end
# -- signup/auth related
accepts_nested_attributes_for :organization
before_validation do
begin
if self.login
self.phone ||= self.login if self.login =~ /^1\d{10,10}$/
self.email ||= self.login if self.login =~ /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\z/i
end
self.gender ||= :male if respond_to?(:gender)
rescue
end
end
before_save do
self.name_pinyin = PinYin.of_string(self.name).join('').first(255)
end
delegate :entity_grant_scope, to: :role, allow_nil: nil
delegate :is_mananger?, to: :role, allow_nil: true
alias :user_role :entity_grant_scope
def users_by_entity_grant_scope
self_and_subordinate_and_department_users
end
alias :users_by_user_role :users_by_entity_grant_scope
deprecate users_by_user_role: "use 'users_from_subordinate_user_and_department' instead", users_by_entity_grant_scope: "use 'users_from_subordinate_user_and_department' instead"
def users_by_user_role_export_administrator
organization.users.reject{|u| u.is_super_user? }
end
alias :readers_for_data_report :self_and_subordinate_and_department_users
deprecate readers_for_data_report: "use 'self_and_subordinate_and_department_users' instead"
def clear_export_task
$redis.del self.task_total_redis_key
$redis.del EntityLoader::Service.current_async_task_redis_key(self.id)
end
def task_total_redis_key
"task:total:#{id}"
end
def task_total
total = $redis.get(task_total_redis_key).to_i
total <= 0 ? 0 : total
end
def ding_or_king?
!!(AppSettings[:app_type].to_s =~ /dingtalk|kingdee/)
end
def exterior_user?
!!(AppSettings[:app_type].to_s =~ /dingtalk|wxwork|kingdee/)
end
def in_ding_or_king_exist?
in_ding_exist?
end
# 是不是没有下属 数据权限也是自己
def is_self_data_policy?
role.self_own? && !children.exists?
end
def unread_ding_upgrade_notices
CmsService::UpgradeNotices.notice_class.where.not(id: ding_upgrade_notice_logs.pluck(:notice_id)).order(created_at: :desc)
end
def current_view_uuid_key
"current:view:uuid:#{id}"
end
def current_view_uuid
$redis.get(current_view_uuid_key)
end
def call_number_match(call_type, number)
return if number.blank?
_custom_field_proc = proc{|klass|
klass.cached_enabled_custom_fields_by_organization(organization_id).select{|custom_field|
custom_field.field_type.in?(%w(mobile_field tel_field))
}
}
[Contact, Customer, Lead].each do |klass|
_fields = _custom_field_proc.call(klass).map(&:name)
entity = all_own_for(klass).eq_any_fields_entity_assets(query: number, keys: _fields, organization: organization).take
return entity if entity
end
return unless call_type.eql?(:incoming)
[Contact, Customer, Lead].each do |klass|
association = Organization.reflect_on_association(klass.table_name)
_fields = _custom_field_proc.call(klass).map(&:name)
entity = organization.send(association.name).eq_any_fields_entity_assets(query: number, keys: _fields, organization: organization).first
return entity if entity
end
return nil
end
def missed_calls_call_records
organization.incoming_call_records.missed.latest.where(user_id: id)
end
def unread_missed_calls_count
call_records = missed_calls_call_records.today
Rails.cache.fetch("unread_missed_calls_count:#{organization_id}:#{id}", expires_in: 1.minute) do
call_records = call_records.from("`#{organization.partitioned_table(IncomingCallRecord)}` AS `#{IncomingCallRecord.table_name}`")
call_records.count
end
end
def api_token
return @api_token if defined?(@api_token)
cache_key = ApiKey.api_token_cache_key(id)
@api_token = Rails.cache.fetch(cache_key, expires_in: 5.minutes, raw: true) do
@api_key ||= ApiKey.where(user_id: id).first_or_create
@api_key.access_token
end
end
def first_enter_social_share_key
"first:enter:social_share:#{id}"
end
def first_enter_social_share!
$redis.set(first_enter_social_share_key, 1)
end
def is_first_enter_social_share?(first_enter = nil)
return false if $redis.exists(first_enter_social_share_key)
!!first_enter && first_enter_social_share! == 'OK'
end
def be_staff_transfer_key
"be:staff:transfer:#{id}"
end
def be_staff_transfer?
$redis.exists(be_staff_transfer_key)
end
def be_staff_transfer!
$redis.set(be_staff_transfer_key, Time.now.strftime('%F %T'), ex: 15.minutes)
end
def restore_be_staff_transfer!
$redis.del(be_staff_transfer_key)
end
def timeout_in
if AppSettings.ikcrm?
login_invalid_time = organization.cached_password_regulations.login_invalid_time rescue {}
if login_invalid_time[:interval_time].present? && login_invalid_time[:type].present?
login_invalid_time[:interval_time].to_i.send(login_invalid_time[:type])
end
else
super
end
end
def station
extra.station
end
def commission_rules
extra.commission_rules
end
def wx_userid
get_wx_userid_key = "#{uid}_to_wx_userid"
$redis.set(get_wx_userid_key, UserCenter::Services::Wx::TransferIdServices.get_wx_userid_by_uid(organization.oid, uid), ex: 7.days) if $redis.get(get_wx_userid_key).blank?
$redis.get(get_wx_userid_key)
end
def userid
if AppSettings.wxwork?
wx_userid
elsif AppSettings.dingtalk?
# TODO
ding_user.userid
end
end
class << self
# ADD 实时解绑那些被冻结的用户
def batch_unbind_soukebox_account(users)
users.each do |user|
user.unbind_soukbox if user.present?
end
end
def default_avatar_url(specify_gender = nil)
assets_path = "#{CrossSites.base_host}/assets"
if GENDERS.keys.include? specify_gender.to_s
"#{assets_path}/#{specify_gender}_uc.jpg"
else
"#{assets_path}/male_uc.jpg"
end
end
def find_for_database_authentication(warden_conditions)
with_database_authentication(warden_conditions).first
end
def with_database_authentication(warden_conditions)
conditions = warden_conditions.dup
if login = conditions.delete(:login)
login_feild = login.include?('@') ? :email : :phone
conditions[login_feild] = login
end
paranoia_scope.where(conditions)
end
def find_by_oid_and_userid(oid:, userid:)
if AppSettings.wxwork?
get_uid_key = "wx_#{userid}_to_uid"
$redis.set(get_uid_key, UserCenter::Services::Wx::TransferIdServices.get_uid_by_wx_userid(oid, userid), ex: 7.days) if $redis.get(get_uid_key).blank?
elsif AppSettings.dingtalk?
# TODO 对接用户中心之后修改
get_uid_key = "ding_#{userid}_to_uid"
end
User.find_by(uid: $redis.get(get_uid_key).to_i)
end
end
end end
class UsersAssistDepartment < ActiveRecord::Base class UsersAssistDepartment < ActiveRecord::Base
self.table_name = AppSettings.table_name('users_assist_departments') self.table_name = AppSettings.table_name('users_assist_departments')
belongs_to :user
belongs_to :department
include CrmUc::UserCenterable include CrmUc::UserCenterable
end end
...@@ -2,26 +2,4 @@ class UsersDepartment < ActiveRecord::Base ...@@ -2,26 +2,4 @@ class UsersDepartment < ActiveRecord::Base
self.table_name = AppSettings.table_name('users_departments') self.table_name = AppSettings.table_name('users_departments')
include CrmUc::UserCenterable include CrmUc::UserCenterable
belongs_to :user
belongs_to :department
before_update :exchange_assist_department
after_commit :enqueue_reset_customers_flow_time
def enqueue_reset_customers_flow_time
CustomerCommons::UserFlowTimeWorker.perform_async(user_id)
end
def exchange_assist_department
if department_id_changed? && department_id_was
unscoped_user = User.stateless.find_by(id: user_id)
if unscoped_user
unscoped_user.users_assist_departments.find_or_create_by(department_id: department_id_was)
unscoped_user.users_assist_departments.find_by(department_id: department_id).try(:destroy)
end
end
end
end end
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment