Class: Company

Inherits:
ApplicationRecord show all
Includes:
Models::Auditable
Defined in:
app/models/company.rb

Overview

== Schema Information

Table name: companies
Database name: primary

id :integer not null, primary key
consolidated_currency :string(3)
country_iso3 :string(255)
currency :string(255)
default_email_sender :string(50)
legal_name :string(255)
market_zone :string
name :string(100)
number :integer
short_name :string(255)
tax_info :string(255)
accounting_business_unit_id :integer
address_id :integer
administration_business_unit_id :integer
default_business_unit_id :integer
ledger_project_id :integer
parent_company_id :integer
sales_business_unit_id :integer

Indexes

companies_address_id_idx (address_id)
companies_parent_company_id_idx (parent_company_id)
companies_sales_business_unit_id_idx (sales_business_unit_id)
idx_company_number (number)
index_companies_on_ledger_project_id (ledger_project_id)
index_companies_on_market_zone (market_zone)

Foreign Keys

companies_address_id_fk (address_id => addresses.id) ON DELETE => nullify
companies_parent_company_id_fk (parent_company_id => companies.id) ON DELETE => nullify
companies_sales_business_unit_id_fk (sales_business_unit_id => business_units.id) ON DELETE => nullify

Constant Summary collapse

USA =
1
CAN =
2
IND =
3
NLD =
4
WORKING_HOURS_CONFIG =

Working hours configuration for this company
Default is Mon-Fri 8:30am-5:30pm

{
  mon: { '08:30' => '17:30' },
  tue: { '08:30' => '17:30' },
  wed: { '08:30' => '17:30' },
  thu: { '08:30' => '17:30' },
  fri: { '08:30' => '17:30' }
}.freeze
WORKING_HOURS_TIMEZONES =

Timezone for working hours by company
Future: Could be moved to Store model when we have multiple warehouses per country

{
  USA => 'America/Chicago',
  CAN => 'America/Toronto',
  IND => 'Asia/Kolkata',
  NLD => 'Europe/Amsterdam'
}.freeze

Constants included from Models::Auditable

Models::Auditable::ALWAYS_IGNORED

Instance Attribute Summary collapse

Belongs to collapse

Methods included from Models::Auditable

#creator, #updater

Has one collapse

Has many collapse

Delegated Instance Attributes collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Models::Auditable

#all_skipped_columns, #audit_reference_data, #should_not_save_version, #stamp_record

Methods inherited from ApplicationRecord

ransackable_associations, ransackable_attributes, ransackable_scopes, ransortable_attributes, #to_relation

Methods included from Models::EventPublishable

#publish_event

Instance Attribute Details

#currencyObject (readonly)



77
# File 'app/models/company.rb', line 77

validates :short_name, :name, :number, :default_email_sender, :currency, presence: true

#default_email_senderObject (readonly)



77
# File 'app/models/company.rb', line 77

validates :short_name, :name, :number, :default_email_sender, :currency, presence: true

#nameObject (readonly)



77
# File 'app/models/company.rb', line 77

validates :short_name, :name, :number, :default_email_sender, :currency, presence: true

#numberObject (readonly)



77
# File 'app/models/company.rb', line 77

validates :short_name, :name, :number, :default_email_sender, :currency, presence: true

#short_nameObject (readonly)



77
# File 'app/models/company.rb', line 77

validates :short_name, :name, :number, :default_email_sender, :currency, presence: true

Class Method Details

.market_zone_euActiveRecord::Relation<Company>

A relation of Companies that are market zone eu. Active Record Scope

Returns:

  • (ActiveRecord::Relation<Company>)

See Also:



82
# File 'app/models/company.rb', line 82

scope :market_zone_eu, -> { where(market_zone: 'EU').order(:id) }

.market_zone_naActiveRecord::Relation<Company>

A relation of Companies that are market zone na. Active Record Scope

Returns:

  • (ActiveRecord::Relation<Company>)

See Also:



81
# File 'app/models/company.rb', line 81

scope :market_zone_na, -> { where(market_zone: 'NA').order(:id) }

.sales_companiesActiveRecord::Relation<Company>

A relation of Companies that are sales companies. Active Record Scope

Returns:

  • (ActiveRecord::Relation<Company>)

See Also:



80
# File 'app/models/company.rb', line 80

scope :sales_companies, -> { where(id: [USA, CAN, NLD]).order(:id) }

.schema_dot_org_aggregate_ratingObject



246
247
248
249
# File 'app/models/company.rb', line 246

def self.schema_dot_org_aggregate_rating
  # Reviews migrated to Reviews.io - aggregate rating now fetched from Reviews.io API
  nil
end

.select_optionsObject



181
182
183
# File 'app/models/company.rb', line 181

def self.select_options
  Company.all.order(:id).pluck(:name, :id)
end

.select_options_sales_companiesObject



185
186
187
# File 'app/models/company.rb', line 185

def self.select_options_sales_companies
  Company.sales_companies.pluck(:name, :id)
end

Instance Method Details

#accounting_business_unitBusinessUnit



53
# File 'app/models/company.rb', line 53

belongs_to :accounting_business_unit, class_name: 'BusinessUnit', optional: true

#activity_type_assignment_queuesActiveRecord::Relation<ActivityTypeAssignmentQueue>

Returns:

See Also:



68
# File 'app/models/company.rb', line 68

has_many :activity_type_assignment_queues, inverse_of: :company

#addressAddress

Returns:

See Also:



49
# File 'app/models/company.rb', line 49

belongs_to :address, optional: true

#administration_business_unitBusinessUnit



51
# File 'app/models/company.rb', line 51

belongs_to :administration_business_unit, class_name: 'BusinessUnit', optional: true

#assign_next_credit_memo_numberObject



266
267
268
269
270
271
272
273
274
275
276
277
# File 'app/models/company.rb', line 266

def assign_next_credit_memo_number
  next_seq = Company.next_sequence_value("next_credit_memo_number_#{id}")
  seq_year = next_seq.to_s.first(2).to_i
  current_year = Date.current.strftime('%y').to_i
  if seq_year != current_year
    new_seq = "#{current_year}00001".to_i
    ActiveRecord::Base.connection.execute("select setval('next_credit_memo_number_#{id}',#{new_seq})")
    next_seq = new_seq
  end
  seq = "#{id}#{next_seq}".to_i
  '%09i' % seq # To force 9 digit numbers, adding leading zeros if necessary
end

#assign_next_invoice_numberObject



253
254
255
256
257
258
259
260
261
262
263
264
# File 'app/models/company.rb', line 253

def assign_next_invoice_number
  next_seq = Company.next_sequence_value("next_invoice_number_#{id}")
  seq_year = next_seq.to_s.first(2).to_i
  current_year = Date.current.strftime('%y').to_i
  if seq_year != current_year
    new_seq = "#{current_year}00001".to_i
    ActiveRecord::Base.connection.execute("select setval('next_invoice_number_#{id}',#{new_seq})")
    next_seq = new_seq
  end
  seq = "#{id}#{next_seq}".to_i
  '%09i' % seq # To force 9 digit numbers, adding leading zeros if necessary
end

#budgetsActiveRecord::Relation<Budget>

Returns:

  • (ActiveRecord::Relation<Budget>)

See Also:



70
# File 'app/models/company.rb', line 70

has_many :budgets

#business_unit_for(dept) ⇒ Object



211
212
213
214
215
216
217
218
219
220
221
222
# File 'app/models/company.rb', line 211

def business_unit_for(dept)
  case dept
  when 'default'
    default_business_unit
  when 'sales'
    sales_business_unit
  when 'administration'
    administration_business_unit
  when 'accounting'
    accounting_business_unit
  end
end

#business_unitsActiveRecord::Relation<BusinessUnit>

Returns:

See Also:



72
# File 'app/models/company.rb', line 72

has_many :business_units

#canada?Boolean

Returns:

  • (Boolean)


228
229
230
# File 'app/models/company.rb', line 228

def canada?
  id == CAN
end

#catalogsActiveRecord::Relation<Catalog>

Returns:

  • (ActiveRecord::Relation<Catalog>)

See Also:



73
# File 'app/models/company.rb', line 73

has_many :catalogs, inverse_of: :company

#cc_bank_accountBankAccount



58
# File 'app/models/company.rb', line 58

has_one :cc_bank_account, class_name: 'BankAccount', foreign_key: 'cc_company_id'

#company_holidaysActiveRecord::Relation<CompanyHoliday>

Returns:

See Also:



71
# File 'app/models/company.rb', line 71

has_many :company_holidays, dependent: :destroy

#company_labelObject



193
194
195
# File 'app/models/company.rb', line 193

def company_label
  "#{country_iso3} #{country_iso3166.emoji_flag}"
end

#countryCountry

Returns:

See Also:



54
# File 'app/models/company.rb', line 54

belongs_to :country, foreign_key: 'country_iso3', primary_key: 'iso3', optional: true

#country_iso3166Object



189
190
191
# File 'app/models/company.rb', line 189

def country_iso3166
  ISO3166::Country.find_country_by_alpha3(country_iso3)
end

#currency_symbolObject



207
208
209
# File 'app/models/company.rb', line 207

def currency_symbol
  Money::Currency.new(currency).symbol
end

#customerCustomer

Returns:

See Also:



56
# File 'app/models/company.rb', line 56

has_one :customer

#default_business_unitBusinessUnit



50
# File 'app/models/company.rb', line 50

belongs_to :default_business_unit, class_name: 'BusinessUnit', optional: true

#email_templatesActiveRecord::Relation<EmailTemplate>

Returns:

See Also:



69
# File 'app/models/company.rb', line 69

has_many :email_templates, as: :resource

#holiday_datesArray<Date>

Get all holiday dates for this company

Returns:

  • (Array<Date>)

    List of holiday dates



134
135
136
# File 'app/models/company.rb', line 134

def holiday_dates
  company_holidays.pluck(:holiday_date)
end

#invoicesActiveRecord::Relation<Invoice>

Returns:

  • (ActiveRecord::Relation<Invoice>)

See Also:



65
# File 'app/models/company.rb', line 65

has_many :invoices

#ledger_company_accountsActiveRecord::Relation<LedgerCompanyAccount>

Returns:

See Also:



63
# File 'app/models/company.rb', line 63

has_many :ledger_company_accounts

#ledger_transactionsActiveRecord::Relation<LedgerTransaction>

Returns:

See Also:



64
# File 'app/models/company.rb', line 64

has_many :ledger_transactions

#localeObject



197
198
199
# File 'app/models/company.rb', line 197

def locale
  { USA => :'en-US', CAN => :'en-CA', NLD => :'nl-NL' }[id] || :'en-US'
end

#netherland?Boolean

Returns:

  • (Boolean)


232
233
234
# File 'app/models/company.rb', line 232

def netherland?
  id == NLD
end

#next_business_day(date) ⇒ Date

Find the next business day on or after the given date
Skips weekends and company holidays

Parameters:

  • date (Date)

    Starting date

Returns:

  • (Date)

    The next business day on or after the given date



159
160
161
162
163
164
165
166
167
168
169
# File 'app/models/company.rb', line 159

def next_business_day(date)
  time = date.to_time.in_time_zone(working_hours_timezone).beginning_of_day

  with_working_hours_config do
    if WorkingHours.working_day?(date)
      date
    else
      WorkingHours.advance_to_working_time(time).to_date
    end
  end
end

#next_valid_ship_dateDate

Calculate the next valid ship date for this company
Accounts for weekends and company holidays

Returns:

  • (Date)

    The next valid date we can ship



142
143
144
145
146
147
148
149
150
151
152
# File 'app/models/company.rb', line 142

def next_valid_ship_date
  now = Time.current.in_time_zone(working_hours_timezone)

  with_working_hours_config do
    if now.in_working_hours?
      now.to_date
    else
      WorkingHours.advance_to_working_time(now).to_date
    end
  end
end

#open_on_a_day?(date) ⇒ Boolean

Returns:

  • (Boolean)


84
85
86
# File 'app/models/company.rb', line 84

def open_on_a_day?(date)
  company_holidays.where(holiday_date: date).exists?
end

#outgoing_paymentsActiveRecord::Relation<OutgoingPayment>

Returns:

See Also:



67
# File 'app/models/company.rb', line 67

has_many :outgoing_payments

#parent_companyCompany

Returns:

See Also:



48
# File 'app/models/company.rb', line 48

belongs_to :parent_company, class_name: 'Company', optional: true

#paypal_bank_accountBankAccount



59
# File 'app/models/company.rb', line 59

has_one :paypal_bank_account, class_name: 'BankAccount', foreign_key: 'paypal_company_id'

#rma_inspect_emailObject

at some point these can be database editable fields



237
238
239
240
241
242
243
244
# File 'app/models/company.rb', line 237

def rma_inspect_email
  case id
  when CAN
    'rma_inspection_can@warmlyyours.com'
  else
    'rma_inspection_usa@warmlyyours.com'
  end
end

#rmasActiveRecord::Relation<Rma>

Returns:

  • (ActiveRecord::Relation<Rma>)

See Also:



66
# File 'app/models/company.rb', line 66

has_many :rmas

#sales_business_unitBusinessUnit



52
# File 'app/models/company.rb', line 52

belongs_to :sales_business_unit, class_name: 'BusinessUnit', optional: true

#schema_dot_org_aggregate_ratingObject

Alias for Class#schema_dot_org_aggregate_rating

Returns:

  • (Object)

    Class#schema_dot_org_aggregate_rating

See Also:



251
# File 'app/models/company.rb', line 251

delegate :schema_dot_org_aggregate_rating, to: :class

#storesActiveRecord::Relation<Store>

Returns:

  • (ActiveRecord::Relation<Store>)

See Also:



61
# File 'app/models/company.rb', line 61

has_many :stores

#summary_nameObject Also known as: to_s



201
202
203
# File 'app/models/company.rb', line 201

def summary_name
  "#{number} #{name}"
end

#supplierSupplier

Returns:

See Also:



57
# File 'app/models/company.rb', line 57

has_one :supplier

#tax_ratesActiveRecord::Relation<TaxRate>

Returns:

  • (ActiveRecord::Relation<TaxRate>)

See Also:



62
# File 'app/models/company.rb', line 62

has_many :tax_rates

#usa?Boolean

Returns:

  • (Boolean)


224
225
226
# File 'app/models/company.rb', line 224

def usa?
  id == USA
end

#with_working_hours_config { ... } ⇒ Object

Execute a block with working hours configured for this company's holidays and timezone
This is the preferred way to do business day calculations

Examples:

Company.find(1).with_working_hours_config do
  1.working.day.from_now
end

Yields:

  • Block to execute with configured working hours

Returns:

  • (Object)

    Result of the block



123
124
125
126
127
128
129
130
# File 'app/models/company.rb', line 123

def with_working_hours_config(&)
  WorkingHours::Config.with_config(
    working_hours: WORKING_HOURS_CONFIG,
    holidays: holiday_dates,
    time_zone: working_hours_timezone,
    &
  )
end

#working_day?(date) ⇒ Boolean

Check if a given date is a working day for this company

Parameters:

  • date (Date)

    The date to check

Returns:

  • (Boolean)

    true if the date is a working day



175
176
177
178
179
# File 'app/models/company.rb', line 175

def working_day?(date)
  with_working_hours_config do
    WorkingHours.working_day?(date)
  end
end

#working_hours_timezoneString

Get the timezone for this company's warehouse operations

Returns:

  • (String)

    IANA timezone identifier



109
110
111
# File 'app/models/company.rb', line 109

def working_hours_timezone
  WORKING_HOURS_TIMEZONES[id] || 'America/Chicago'
end