Skip to content

Instantly share code, notes, and snippets.

@khadzhinov
Created October 16, 2014 18:06
Show Gist options
  • Save khadzhinov/954b28b3937f549b19cd to your computer and use it in GitHub Desktop.
Save khadzhinov/954b28b3937f549b19cd to your computer and use it in GitHub Desktop.
class Organization < VersionableModel
belongs_to :user
belongs_to :country
belongs_to :organization_economic_type
has_many :purchases
has_many :all_subscriptions, :class_name => "Subscription", :dependent => :destroy
has_many :subscriptions, -> { where {(activated_at != nil) & (valid_through >= my{Time.zone.today}) & (valid_from <= my{Time.zone.today})}.order("valid_from ASC") }
has_one :organization_responsible_person, :dependent => :destroy , :inverse_of => :organization
has_one :organization_custom_requisite, :dependent => :destroy , :inverse_of => :organization
has_one :organization_document, :dependent => :destroy , :inverse_of => :organization
has_many :organization_bank_accounts, :dependent => :destroy , :inverse_of => :organization
has_many :organization_branches, :dependent => :destroy , :inverse_of => :organization
has_many :departments, :dependent => :destroy , :inverse_of => :organization
has_many :employees, :dependent => :destroy
has_many :calendar_days, :dependent => :destroy
has_many :reports, :dependent => :destroy
has_many :payments, :dependent => :destroy
has_many :events, :dependent => :destroy
has_many :feeds, :dependent => :nullify
has_many :invites, :dependent => :destroy
has_many :users_organizations, :dependent => :destroy
has_many :users, :through => :users_organizations
has_many :consultant_services, :dependent => :destroy, :foreign_key => :consultant_id
has_many :outgoing_contracts, :dependent => :destroy, :class_name => 'Contract'
has_many :incoming_contracts, :dependent => :destroy, :class_name => 'Contract', :foreign_key => :contractor_id
has_many :incoming_partnerships, :dependent => :destroy, :class_name => 'Partnership', :as => :partner
has_many :outgoing_partnerships, :dependent => :destroy, :class_name => 'Partnership', :inverse_of => :organization
has_many :external_organizations, :dependent => :destroy
has_many :organization_addresses, -> { order("address_type DESC") }, :dependent => :destroy
has_many :pattern_numbers, :dependent => :destroy
has_one :reports_settings, :dependent => :destroy
has_many :incoming_documents, :dependent => :destroy
# Warehouse module
has_many :warehouses, :dependent => :destroy
has_many :nomenclatures, :dependent => :destroy
has_many :nomenclature_categories, :dependent => :destroy
has_many :stocks, :through => :warehouses
has_many :measure_types, :dependent => :destroy
has_many :incoming_waybills, :dependent => :destroy
has_many :outgoing_waybills, :dependent => :destroy
has_many :write_off_acts, :dependent => :destroy
has_many :inventory_of_materials, :dependent => :destroy
has_many :movement_waybills, :dependent => :destroy
has_many :account_entries, :dependent => :destroy
has_many :closing_account_entries, :dependent => :destroy
has_many :account_rests, :dependent => :destroy
has_many :balances, :dependent => :destroy
has_one :stocktake_settings, :dependent => :destroy
# Stocktake > Documents
has_many :cash_in_orders, :dependent => :destroy
has_many :cash_out_orders, :dependent => :destroy
has_many :incoming_payments, :dependent => :destroy
has_many :outgoing_payments
has_many :outgoing_invoices, :dependent => :destroy
has_many :invoices, :dependent => :destroy
has_many :service_acts, :dependent => :destroy
has_many :power_of_attorneys, :dependent => :destroy
has_many :payrolls, :dependent => :destroy
has_many :payroll_expenses, :dependent => :destroy
has_many :bank_statements, :dependent => :destroy
has_many :advance_statements, :dependent => :destroy
has_many :reconciliation_acts, :dependent => :destroy
has_many :agreements, :dependent => :destroy
has_many :agreement_templates, :dependent => :destroy
has_many :agreement_comments, :dependent => :destroy
# Stocktake > Assets
has_many :fixed_assets, :dependent => :destroy
has_many :fixed_asset_receipts, :dependent => :destroy
has_many :fixed_asset_acceptances, :dependent => :destroy
has_many :fixed_asset_transfers, :dependent => :destroy
has_many :fixed_asset_movements, :dependent => :destroy
has_many :fixed_asset_renewals, :dependent => :destroy
has_many :fixed_asset_writeoffs, :dependent => :destroy
has_many :intangible_assets, :dependent => :destroy
has_many :intangible_asset_receipts, :dependent => :destroy
has_many :intangible_asset_acceptances, :dependent => :destroy
has_many :intangible_asset_transfers, :dependent => :destroy
has_many :intangible_asset_writeoffs, :dependent => :destroy
accepts_nested_attributes_for :organization_responsible_person, :organization_custom_requisite, :organization_document, :allow_destroy => true, :update_only => true
accepts_nested_attributes_for :organization_bank_accounts, :organization_branches, :departments, :organization_addresses, :consultant_services, :allow_destroy => true
enable_paths
scope :unverified, -> { where { verification_status != "verified" } }
scope :verified, -> { where { verification_status == "verified" } }
scope :expired, -> { verified.where("verification_date_to < ?", Time.now) }
scope :expires_during_dates, -> (date) { verified.where({:verification_date_to => Time.now..date})}
scope :consultants, -> () { where(:is_consultant => true) }
ORGANIZATION_TYPES = %w(pe llp)
VERIFICATION_STATUSES = %w(unverified pending_verify_sms waiting_sms_code pending_hsm_verification verified)
CREATE_USER_QUEUE = "front.#{Rails.env}_create_user"
APPROVE_USER_QUEUE = "front.#{Rails.env}_approve_create_user"
after_create do
Feed.delay.organization_feed(self, User.current_user, { :feed_code => "create_organization" })
Feed.delay.organization_feed(self, User.current_user, { :feed_code => "new_consultant"}) if self.is_consultant
create_pattern_numbers
add_default_calendar_days
create_default_warehouse
add_calendar_events
calculate_current_indicators
update_browser_data
end
after_update do
if @skip_feed
@skip_feed = false
else
Feed.delay.organization_feed(self, User.current_user, {feed_code: "update_organization"})
Feed.delay.organization_feed(self, User.current_user, {feed_code: "new_consultant"}) if self.is_consultant_changed? && self.is_consultant
update_browser_data
end
end
before_destroy do
Feed.organization_feed(self, User.current_user, {feed_code: "destroy_organization"})
end
after_destroy :update_browser_data
before_save :check_addresses
after_save do
ExternalOrganization.react_to_verification_of(self) if verification_status_changed? && is_verified?
end
attr_accessible :name,
:organization_type,
:is_consultant,
:consultant_aggrement,
:tic,
:coordinates_latitude,
:coordinates_longitude,
:phone,
:email,
:has_branch,
:has_accountant,
:matches_address,
:tax_system,
:organization_economic_type_id,
:verification_status,
:verification_date_from,
:verification_date_to,
:vat_payer,
:organization_responsible_person_attributes,
:organization_document_attributes,
:organization_custom_requisite_attributes,
:user,
:user_id,
:are_responsible_persons_real,
:organization_bank_accounts_attributes,
:organization_branches_attributes,
:departments_attributes,
:tic_scan_link_cache,
:remove_tic_scan_link,
:organization_addresses_attributes,
:consultant_services_attributes
validate :check_unverified_organizations_count
validates :name, :verification_status, :organization_type, :tax_system, :organization_economic_type_id, :user_id, :presence => true
validates :name, :length => { :maximum => 64 }
validates :organization_type, :inclusion => { :in => ORGANIZATION_TYPES }
validates :tic, :numericality => { :only_integer => true }, :length => { :is => 12 }, :allow_blank => true
validates :verification_status, :inclusion => { :in => VERIFICATION_STATUSES }
validates :phone, :numericality => { :only_integer => true }, :length => { :minimum => 9 }, :allow_blank => true
validates :email, :email => true, :length => { :maximum => 32 }, :allow_blank => true
validates :is_consultant, :inclusion => { :in => [true, false] }
mount_uploader :tic_scan_link, ScanUploader
def partnerships(scopes_list = [:correct], direction = :all)
scopes_list = [scopes_list] unless scopes_list.is_a?(Array)
records = []
associations = []
associations << :outgoing_partnerships unless direction == :incoming
associations << :incoming_partnerships unless direction == :outgoing
associations.each do |association|
relation = self.send(association)
scopes_list.each { |s|
s = (association == :outgoing_partnerships ? :verified_for_initiator : :verified_for_partner) if s == :verified
relation = relation.send(s)
}
records += relation
end
records
end
def expiry_months
expiry_months = {}
Purchasable.subscriptions.each do |purchasable|
purchase_item = PurchaseItem.last_actual_purchase_item(id, purchasable.id)
expiry_months.merge!({purchasable.code_within_category.to_sym => purchase_item ? purchase_item.expiry_at : nil })
end
expiry_months
end
def primary_bank
#organization_bank_accounts.first
organization_bank_accounts.primary.first
end
def organization_type_valid?
is_pe? || is_llp?
end
def is_pe?
organization_type == "pe"
end
alias is_pe is_pe?
def is_llp?
organization_type == "llp"
end
alias is_llp is_llp?
def is_verified?
verification_status == "verified"
end
alias is_verified is_verified?
def is_paid?
purchases.joins{purchase_items}.where{(purchase_items.expiry_at > Date.today)}.any?
end
alias is_paid is_paid?
def set_as_unverified!
update_attributes!({verification_status: "unverified", verification_date_from: nil, verification_date_to: nil})
end
def address_string(type)
res = []
addr =
organization_addresses.select{ |a| a.address_type == type }.first
loc = nil
if addr
res << addr.zip_code if addr.zip_code
res << addr.country.name if addr.country
loc = addr.region if addr.region
loc = addr.location if addr.location
loc = addr.city if addr.city
loc = addr.locality if addr.locality
res << Location.location_full_addr(loc.id) if loc
[:street, :house, :building, :apartment].each do |address_part|
res << "#{I18n.t("activerecord.attributes.organization_address.#{address_part}")} #{addr[address_part]}" if addr[address_part]
end
end
res.join ", "
end
def legal_address
address_string "legal"
end
def actual_address
address_string "actual"
end
def responsible_persons_full_name
organization_responsible_person.andand.boss_fio
end
def id_number
return nil unless organization_type_valid?
if is_pe?
iin
elsif is_llp?
bin
end
end
def iin
organization_custom_requisite.andand.iin
end
def bin
organization_custom_requisite.andand.bin
end
def sending_on_hsm_base_data
requisites = is_llp? ? { :bin => bin } : { :iin => iin }
{ :org_type => organization_type, :tic => tic, :phone => user.mobile_phone, :fio => user.fio, :org => name }.merge!(requisites)
end
def send_eds_on_hsm(eds = "")
unless is_verified?
begin
data = self.sending_on_hsm_base_data.merge!({:eds => eds.read, :routing_key => CREATE_USER_QUEUE})
RabbitMQProducer.publish(data.to_json, :routing_key => "hsm.create_user", :persistent => true)
update_attributes!({verification_status: "pending_verify_sms"})
rescue
set_as_unverified!
end
end
end
def self.find_organization_by_hsm_payload(payload)
case payload["org_type"]
when "llp"
self.select("*").joins(:organization_custom_requisite).where({organization_type: payload["org_type"], organization_custom_requisites: {bin: payload["bin"]} }).first
when "pe"
self.select("*").joins(:organization_custom_requisite).where({organization_type: payload["org_type"], organization_custom_requisites: {iin: payload["iin"]} }).first
else
false
end
end
def self.on_create_eds(payload)
User.current_user = User.system_user
organization = self.find_organization_by_hsm_payload(payload)
if organization
organization.update_attributes!({verification_status: payload["verification_status"]})
FayeClient.publish "/users/#{organization.user_id}/hsm", payload
end
end
def send_verification_code!(smscode = "")
begin
data = self.sending_on_hsm_base_data.merge!({:smscode => smscode, :routing_key => APPROVE_USER_QUEUE})
RabbitMQProducer.publish(data.to_json, :routing_key => "hsm.approve_create_user", :persistent => true)
self.update_attributes!({verification_status: "pending_hsm_verification"})
rescue
self.update_attributes!({verification_status: "waiting_sms_code"})
end
end
def self.on_verify_create_eds(payload)
User.current_user = User.system_user
organization = self.find_organization_by_hsm_payload(payload)
if organization
if payload["verification_status"] == "verified"
organization.update_attributes!({verification_status: payload["verification_status"], verification_date_from: payload["verification_date_from"].to_date, verification_date_to: payload["verification_date_to"].to_date})
SystemMailer.delay.success_eds_verification_result_message(organization, payload["msg"])
else
organization.update_attributes!({verification_status: payload["verification_status"]})
end
FayeClient.publish "/users/#{organization.user_id}/hsm", payload
end
end
def add_calendar_events
num = events.size
add_salary_events
add_tax_events
add_report_events
if num < events.size
FayeClient.publish(model_path + "/events",
{:action => :fetch},
{:force => true})
end
end
def add_salary_events
return if stocktake_settings.andand.pay_day.blank?
pay_time = DateTime.current.change(:day => stocktake_settings.pay_day.to_i).beginning_of_day
Event.where({
organization_id: id,
start_date: pay_time - 3.day,
end_date: pay_time,
eventable_type: "Salary",
event_type_id: EventType.find_by_code("charge_salary").id
}).first_or_create!
end
def add_tax_events
tax_periods = TaxPeriod.all
time_now = Time.now.utc
tax_periods.each do | period |
Event.joins(:event_type).where({
organization_id: self.id,
start_date: DateTime.new(time_now.year, time_now.month, period.start_month_day),
end_date: DateTime.new(time_now.year, time_now.month, period.end_month_day),
eventable_type: "Tax",
event_type_id: EventType.find_by_code("pay_#{period.tax_type.code}").id
}).first_or_create!
end
end
def add_report_events
quarter = (Date.today.month - 1) / 3 + 1
report_periods = ReportPeriod.includes(:report_type).where({quarter: quarter}).to_a
time_now = Time.now.utc
report_periods.each do | period |
unless self.reports.joins(:report_type).where({quarter_number: quarter, quarter_year: time_now.year, report_type: { name: period.report_type.name }}).first
Event.joins(:event_type).where({
organization_id: self.id,
start_date: period.start_date,
end_date: period.end_date,
eventable_type: "Report",
event_type_id: EventType.find_by_code("create_report_#{period.report_type.name}").id
}).first_or_create!
end
end
end
def organization_number_name
if self.is_llp?
on = I18n.t("activerecord.attributes.organization_custom_requisite.bin")
elsif self.is_pe?
on = I18n.t("activerecord.attributes.organization_custom_requisite.iin")
else
on = nil
end
on
end
def organization_type_name
if %w(llp pe).include?(organization_type)
I18n.t("activerecord.attributes.organization.organization_types.#{organization_type}")
end
end
def organization_full_name
[self.organization_type_name, self.name].reject{|v| v.blank?}.join(" ").strip
end
def may_be_consulted
!is_consultant? && Ability.current.can?(:create, Contract.new(:organization_id => id))
end
alias :may_be_consulted? :may_be_consulted
def consulting_status
return "consultant" if is_consultant
contracts = outgoing_contracts.to_a
if contracts.detect { |c| c.is_active? }
"being_consulted"
elsif contracts.detect { |c| c.is_being_negotiated? }
"requested_consulting"
else
""
end
end
def calculate_current_indicators
indicators = {
:balance_cash_deck => nil,
:balance_bank => nil,
:arrears_employees => nil,
:arrears_other => nil,
:stock_warehouse => indicators_stock_warehouse.to_s,
:stock_assortment => indicators_stock_assortment.to_s,
:employees_salaries => indicators_employees_salaries.to_s,
:employees_active => indicators_employees_active.to_s,
:employees_total => indicators_employees_total.to_s
}
if current_indicators.blank? || current_indicators.symbolize_keys != indicators
@skip_feed = true
self.current_indicators = indicators
save!
FayeClient.publish(model_path + "/current_indicators",
{:action => :fetch},
{:force => true})
end
end
protected
# Current indicators block
def indicators_stock_warehouse
warehouses.inject(0) do |sum, warehouse|
sum + warehouse.balance
end
end
def indicators_stock_assortment
nomenclatures.where(:nomenclature_type_id => (1..2)).size
end
def indicators_employees_salaries
employees.where({
:is_dismissed => false
}).inject(0) do |sum, employee|
sum + (employee.employee_salary ? employee.employee_salary.rate : 0)
end
end
def indicators_employees_active
employees.where({
:is_dismissed => false
}).count do |employee|
employee.status == "is_on_work"
end
end
def indicators_employees_total
employees.where({
:is_dismissed => false
}).count
end
def check_unverified_organizations_count
return if user.andand.is_admin
if new_record? && user.andand.organizations.andand.unverified.andand.size.to_i >= 3
errors.add(:flash, "activerecord.errors.organization.unverified_limit_reached")
end
end
def check_addresses
if self.matches_address
attrs = self.organization_addresses.select{ |a| a.address_type == "legal" }.first.attributes.dup
attrs.delete "id"
attrs.delete "geom"
attrs.delete "last_change"
attrs.delete "is_deleted"
attrs["address_type"] = "actual"
if self.organization_addresses.size == 1
self.organization_addresses << OrganizationAddress.new(attrs)
else
self.organization_addresses.select{ |a| a.address_type == "actual" }.first.update_attributes attrs
end
end
end
def create_default_warehouse
warehouses.create(name: I18n.t("views.warehouse.default_name"))
end
def create_pattern_numbers
pattern_numbers = AccDocumentType.select('id, default_mask').where('default_mask is not null').to_a
PatternNumber.transaction do
pattern_numbers.each do |pattern|
PatternNumber.create!(organization_id: self.id, acc_document_type_id: pattern.id, counter: 1, mask: pattern.default_mask)
end
end
end
def add_default_calendar_days
DefaultCalendarDay.all.each { |day| calendar_days.create(day.attributes.slice("date", "mark")) }
end
def update_browser_data
FayeClient.publish(model_root_path,
{:action => :fetch},
{:force => true})
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment