Class: Contact

Inherits:
Party show all
Includes:
ContactDeactivationAndDefaults, ContactDisplay, ContactQueries, Memery
Defined in:
app/models/contact.rb

Overview

== Schema Information

Table name: parties
Database name: primary

id :integer not null, primary key
activities_count :integer default(0)
affiliations :text default([]), is an Array
annual_revenue :integer
authorization_code_required :boolean
available_credit :decimal(14, 2) default(0.0)
banner :text
best_time_to_call :string(255)
bill_shipping_to_customer :boolean
calculate_profiling :boolean default(FALSE), not null
can_pay_by_cod_business_check :boolean
consent_preferences :jsonb
contact_roles :string(255) is an Array
creation_method :integer default("crm"), not null
credit_limit :decimal(8, 2) default(0.0)
credit_score :integer
credit_score_date :datetime
currency :string(255)
default_payment_method :string
do_not_auto_assign :boolean default(FALSE), not null
dob :date
early_payment_discount :integer
early_payment_timescale :integer
estimated_landed_cost_ptg :float
force_logout :boolean default(FALSE), not null
full_name :string(255)
full_name_tsv :tsvector
gclid :string
gender :string(1)
inactive :boolean default(FALSE), not null
job_title :string(255)
lead_time :integer
lead_time_override :integer
lead_verification_score :integer
lead_verified_at :datetime
merged_from_ids :integer is an Array
name1 :string(255)
name2 :string(255)
name3 :string(255)
number_of_employees :integer
number_of_offices :string
on_hold :boolean default(FALSE), not null
on_hold_reason :text
open_sales_activity :boolean default(FALSE), not null
ordering_instructions :text
preferred_language :string
preferred_shipping_method :string(255)
prefix :string(10)
profile_info :text
projects_per_year :string
purchase_order_required :boolean default(FALSE), not null
qc_orders :boolean default(TRUE), not null
rating :string(255)
report_grouping :string(255)
requires_rma_reference :boolean
sales_priority_index :integer default(0)
send_statement :boolean default(FALSE), not null
send_statement_reason :string(255)
shipment_instructions :text
source_info :text
spiff_enrolled :boolean
state :string(255)
state_code :string(255)
suffix :string(10)
terms :string(255)
timezone_name :string
type :string(255)
uploads_count :integer default(0)
uuid :uuid not null
verbal_po :boolean default(FALSE), not null
watch :integer
created_at :datetime
updated_at :datetime
active_spiff_enrollment_id :integer
billing_address_id :integer
bot_id :string
business_unit_id :integer
buying_group_id :integer
catalog_id :integer
company_id :integer
creator_id :integer
customer_id :integer
gl_offset_account_id :integer
ledger_detail_project_id :integer
legacy_tier2_program_pricing_id :integer
local_sales_rep_id :integer
mailing_address_id :integer
original_source_id :integer
parent_id :integer
paypal_vault_customer_id :string
paypal_vault_token_id :string
primary_sales_rep_id :integer
profile_id :integer
profile_image_id :integer
secondary_sales_rep_id :integer
service_rep_id :integer
shipping_address_id :integer
source_id :integer
spiff_address_id :integer
spiff_payable_id :integer
stripe_customer_id :string
tier2_program_pricing_id :integer
updater_id :integer
visit_id :bigint

Indexes

idx_parties_full_name_trg (full_name) USING gin
idx_party_main_address (COALESCE(shipping_address_id, billing_address_id, mailing_address_id))
idx_state_type (state,type)
idx_type_billing_address_id (type,billing_address_id)
idx_type_creation_method_state (type,creation_method,state)
idx_type_customer_id (type,customer_id)
idx_type_id_credit_limit (type,id,credit_limit)
idx_type_inactive (type,inactive)
idx_type_primary_sales_rep_id_watch (type,primary_sales_rep_id,watch)
index_parties_on_affiliations (affiliations) USING gin
index_parties_on_billing_address_id (billing_address_id)
index_parties_on_bot_id (bot_id) WHERE (bot_id IS NOT NULL)
index_parties_on_catalog_id (catalog_id)
index_parties_on_company_id (company_id)
index_parties_on_full_name_tsv (full_name_tsv) USING gin
index_parties_on_gclid (gclid) WHERE (gclid IS NOT NULL)
index_parties_on_local_sales_rep_id (local_sales_rep_id)
index_parties_on_mailing_address_id (mailing_address_id)
index_parties_on_merged_from_ids (merged_from_ids) USING gin
index_parties_on_open_sales_activity (open_sales_activity)
index_parties_on_parent_id (parent_id)
index_parties_on_primary_sales_rep_id (primary_sales_rep_id)
index_parties_on_profile_image_id (profile_image_id) USING hash
index_parties_on_report_grouping (report_grouping)
index_parties_on_secondary_sales_rep_id (secondary_sales_rep_id)
index_parties_on_service_rep_id (service_rep_id)
index_parties_on_source_id (source_id)
index_parties_on_tier2_program_pricing_id (tier2_program_pricing_id)
index_parties_on_uuid (uuid) UNIQUE
index_parties_on_visit_id (visit_id) WHERE (visit_id IS NOT NULL) USING hash
index_parties_on_watch (watch)
parties_buying_group_id_idx (buying_group_id)
parties_customer_id_index (customer_id)
parties_profile_id_idx (profile_id)
parties_shipping_address_id_idx (shipping_address_id)
parties_spiff_address_id_idx (spiff_address_id)
parties_spiff_payable_id_idx (spiff_payable_id)

Foreign Keys

fk_rails_... (profile_image_id => digital_assets.id) ON DELETE => nullify
fk_rails_... (source_id => sources.id)
fk_rails_... (visit_id => visits.id) ON DELETE => nullify
parties_billing_address_id_fk (billing_address_id => addresses.id) ON DELETE => nullify
parties_buying_group_id_fk (buying_group_id => buying_groups.id)
parties_catalog_id_fk (catalog_id => catalogs.id)
parties_company_id_fk (company_id => companies.id)
parties_customer_id_fk (customer_id => parties.id) ON DELETE => cascade
parties_mailing_address_id_fk (mailing_address_id => addresses.id) ON DELETE => nullify
parties_parent_id_fk (parent_id => parties.id) ON DELETE => nullify
parties_primary_sales_rep_id_fk (primary_sales_rep_id => parties.id) ON DELETE => nullify
parties_profile_id_fk (profile_id => profiles.id)
parties_secondary_sales_rep_id_fk (secondary_sales_rep_id => parties.id) ON DELETE => nullify
parties_shipping_address_id_fk (shipping_address_id => addresses.id) ON DELETE => nullify
parties_source_id_fk (source_id => sources.id)
parties_spiff_address_id_fk (spiff_address_id => addresses.id) ON DELETE => nullify
parties_spiff_payable_id_fk (spiff_payable_id => parties.id) ON DELETE => nullify
parties_tier2_program_pricing_id_fk (tier2_program_pricing_id => coupons.id)

Contact person (parties.type = Contact) tied to a Customer or Supplier
through customer_id. Carries CRM communications, opportunities, certifications,
and service scheduling.

Constant Summary collapse

NAME_CANT_BE_BLANK =
"can't be blank (need at least one non-blank name)".freeze
CONTACT_ROLES =
%w[accounting administrative decision_maker designer engineer executive human_resources information_technology installer legal
logistics manager manufacturing marketing menard_associate_merchant menard_merchant menard_product_specialist sales].freeze

Constants inherited from Party

Party::PREFERRED_LANGUAGES

Constants included from Models::Auditable

Models::Auditable::ALWAYS_IGNORED

Instance Attribute Summary collapse

Attributes inherited from Party

#creation_method

Belongs to collapse

Methods inherited from Party

#catalog, #company, #gl_offset_account, #profile_image, #visit

Methods included from Models::Auditable

#creator, #updater

Has many collapse

Methods inherited from Party

#accounts, #activities, #addresses, #agreement_participants, #agreements, #assistant_conversations, #billing_credit_memos, #consignment_stores, #contact_points, #contacts, #credit_memos, #destination_call_logs, #destination_call_records, #inbound_communications, #notifications, #opportunity_participants, #origin_call_logs, #origin_call_records, #outbound_communications, #outgoing_payments, #party_topics, #purchase_orders, #queue_call_logs, #receipts, #recipient_sms_messages, #room_plans, #sender_sms_messages, #support_case_participants, #support_cases, #survey_enrollments, #uploads, #visit_events, #visits, #voucher_items, #vouchers

Delegated Instance Attributes collapse

Methods inherited from Party

#can?, #cannot?, #has_role?, #is_admin?, #is_document_maintainer?, #is_local_sales_rep?, #is_manager?, #is_marketing_manager?, #is_sales_manager?, #is_sales_rep?, #locale, #main_address

Class Method Summary collapse

Instance Method Summary collapse

Methods included from ContactQueries

#all_contact_points, #all_email_contact_points, #all_emails, #all_opportunities, #all_orders, #all_related_communications, #dependents

Methods included from ContactDisplay

#all_addresses, #build_default_contact_points, #colleagues, #country, #first_address, #guest?, #last_invoice_shipping_cost, #locale, #main_address, #open_activities_counter, #options_for_reports_to, #reference_number, #shipping_amount_last_30_days, #shipping_amount_last_month, #state, #supplier_contact?, #timezone, #to_label, #to_s

Methods included from ContactDeactivationAndDefaults

#deactivate, #ok_to_delete?, #open_support_case_participant?, #reactivate, #set_default_for_opportunity, #set_default_for_order, #support_case_participant?

Methods inherited from Party

#account, #digital_assets, #linked_activities, #product_lines, #set_full_name, #set_state_code, #set_timezone

Methods included from CrmLinkable

#crm_link, #crm_link_with_host

Methods included from PartyAccount

#ability, #build_account, #create_account, #online_account_invite, #refuse_silent_account_replacement!, search_for_authenticable_linked_party_by_email

Methods included from PartyCart

#all_uploads, #cart, #cart=, #cart?, #cart_id, #cart_info, #create_activity, #create_quote_builder_project, #load_cart, #store_original_source

Methods included from PartyIdentity

#active?, #admin?, #aka, #aka=, #all_activities, #blog_admin?, #broadcast_product_interest_changed, #can_be_certified?, #can_list_all_contact_resources?, #clear_individual_names, #clear_names, #contact?, #customer?, #determine_company_id, #direct_commercial?, #direct_pro?, #employee?, #first_name, #first_name=, #guest_individual_name?, #guest_name?, #homeowner?, #id_and_name, #last_name, #last_name=, #manager?, #middle_name, #middle_name=, #name, #name=, #organization?, #person?, #primary_party, #public_facing_full_name, #public_facing_full_name=, #show_name_four, #to_s, #update_product_interests

Methods included from PartyAddresses

#addresses_options_for_select, #can_change_country?, #catalog_country, #catalog_country_iso, #catalog_country_iso3, #city, #country, #country_iso, #country_iso3, #first_address, #flag, #location_name, #most_recent_visit, #new_address, #street1, #street2, #street3, #timezone, #unique_addresses, #visit_data, #visit_location, #zip

Methods included from PartyContactInfo

#all_support_cases, #call_records?, #cell_phone, #cell_phone=, #cell_phone_formatted, #contact_point_options_for_select, #contactable?, #email, #email=, #email_options_for_select, #email_with_name, #emails, #fax, #fax=, #fax_formatted, #fax_options_for_select, #first_callable_contact_point, #first_contact_point_by_category, #phone, #phone=, #phone_formatted, #phone_options_for_select, #set_email_from_account, #set_primary_contact_point, #sms_enabled_numbers, #sms_messages, #tracking_email_address, #tracking_email_prefix, #website, #website=, #website_options_for_select

Methods included from PartySearch

active, address_search, customer_or_contact, email_search, inactive, lookup, phone_search, ransackable_scopes, searchable, with_main_address

Methods included from Models::Notable

#quick_note

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

#full_nameObject (readonly)



235
# File 'app/models/contact.rb', line 235

validates :full_name, presence: { message: 'must be specified for this Contact.  First and last name.' }

#prefixObject (readonly)



237
# File 'app/models/contact.rb', line 237

validates :prefix, length: { maximum: 10 }

#suffixObject (readonly)



238
# File 'app/models/contact.rb', line 238

validates :suffix, length: { maximum: 10 }

Class Method Details

.contact_roles_for_selectArray<Array(String, String)>

Options for role pickers (human label + machine value).

Returns:

  • (Array<Array(String, String)>)

    pairs suitable for options_for_select



270
271
272
# File 'app/models/contact.rb', line 270

def self.contact_roles_for_select
  CONTACT_ROLES.map { |cr| [cr.titleize, cr] }
end

.verbal_po_contactsActiveRecord::Relation<Contact>

A relation of Contacts that are verbal po contacts. Active Record Scope

Returns:

  • (ActiveRecord::Relation<Contact>)

See Also:



231
# File 'app/models/contact.rb', line 231

scope :verbal_po_contacts, -> { where(verbal_po: true) }

Instance Method Details

#accounts_payable_credit_applicationsActiveRecord::Relation<CreditApplication>

Returns:

See Also:



221
222
# File 'app/models/contact.rb', line 221

has_many :accounts_payable_credit_applications, class_name: 'CreditApplication', foreign_key: :accounts_payable_contact_id,
inverse_of: :accounts_payable_contact, dependent: :nullify

#active_spiff_enrollmentSpiffEnrollment



202
# File 'app/models/contact.rb', line 202

belongs_to :active_spiff_enrollment, class_name: 'SpiffEnrollment', optional: true

#assign_chained_activities?Boolean

Whether chained activities should follow this contact (active contacts only).

Returns:

  • (Boolean)


296
297
298
# File 'app/models/contact.rb', line 296

def assign_chained_activities?
  !inactive
end

#billing_addressObject

Alias for Customer#billing_address

Returns:

  • (Object)

    Customer#billing_address

See Also:



247
# File 'app/models/contact.rb', line 247

delegate :billing_address, to: :customer, allow_nil: true

#certificationsActiveRecord::Relation<Certification>

Returns:

See Also:



225
# File 'app/models/contact.rb', line 225

has_many :certifications, foreign_key: 'party_id', dependent: :destroy, inverse_of: :contact

#contact_role?(roles) ⇒ Boolean

Whether this contact matches the given CRM role(s), or the check is unrestricted.

Returns true when contact_roles is blank, when roles is empty, or when
the intersection of stored roles and roles is non-empty.

Parameters:

  • roles (String, Array<String>, nil)

    role name(s) to match

Returns:

  • (Boolean)


289
290
291
# File 'app/models/contact.rb', line 289

def contact_role?(roles)
  contact_roles.blank? || roles.empty? || (contact_roles || []).intersect?([roles].flatten)
end

#contact_training_topicsActiveRecord::Relation<ContactTrainingTopic>

Returns:

See Also:



217
# File 'app/models/contact.rb', line 217

has_many :contact_training_topics, inverse_of: :contact, foreign_key: :party_id, dependent: :destroy

#course_enrollmentsActiveRecord::Relation<CourseEnrollment>

Returns:

See Also:



214
# File 'app/models/contact.rb', line 214

has_many :course_enrollments, foreign_key: 'party_id', dependent: :destroy, inverse_of: :party

#customerCustomer

inverse_of omitted: Party#contacts cannot name both :customer and :supplier (same FK).
rubocop:disable Rails/InverseOf

Returns:

See Also:



195
# File 'app/models/contact.rb', line 195

belongs_to :customer, class_name: 'Customer', optional: true

#is_homeowner?Object

Alias for Customer#is_homeowner?

Returns:

  • (Object)

    Customer#is_homeowner?

See Also:



233
# File 'app/models/contact.rb', line 233

delegate :store, :is_homeowner?, :is_organization?, :sales_rep, :primary_sales_rep, to: :customer

#is_organization?Object

Alias for Customer#is_organization?

Returns:

  • (Object)

    Customer#is_organization?

See Also:



233
# File 'app/models/contact.rb', line 233

delegate :store, :is_homeowner?, :is_organization?, :sales_rep, :primary_sales_rep, to: :customer

#managed_employeesActiveRecord::Relation<Contact>

Returns:

  • (ActiveRecord::Relation<Contact>)

See Also:



206
# File 'app/models/contact.rb', line 206

has_many :managed_employees, class_name: 'Contact', foreign_key: 'parent_id', dependent: :nullify, inverse_of: :manager

#managerContact

Returns:

See Also:



201
# File 'app/models/contact.rb', line 201

belongs_to :manager, class_name: 'Contact', foreign_key: 'parent_id', optional: true, inverse_of: :managed_employees

#opportunitiesActiveRecord::Relation<Opportunity>

Returns:

See Also:



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

has_many :opportunities, -> { order(:created_at).reverse_order }, inverse_of: :contact, dependent: :nullify,
before_add: :set_default_for_opportunity

#ordersActiveRecord::Relation<Order>

Returns:

  • (ActiveRecord::Relation<Order>)

See Also:



211
# File 'app/models/contact.rb', line 211

has_many :orders, -> { order(:created_at).reverse_order }, inverse_of: :contact, dependent: :nullify, before_add: :set_default_for_order

#original_sourceSource

rubocop:enable Rails/InverseOf

Returns:

See Also:



199
# File 'app/models/contact.rb', line 199

belongs_to :original_source, class_name: 'Source', optional: true

#owner_credit_applicationsActiveRecord::Relation<CreditApplication>

Returns:

See Also:



220
# File 'app/models/contact.rb', line 220

has_many :owner_credit_applications, class_name: 'CreditApplication', foreign_key: :owner_id, inverse_of: :owner, dependent: :nullify

#preset_jobsActiveRecord::Relation<PresetJob>

Returns:

See Also:



215
# File 'app/models/contact.rb', line 215

has_many :preset_jobs, -> { order(:created_at).reverse_order }, inverse_of: :contact, dependent: :nullify

#primary_contact_credit_applicationsActiveRecord::Relation<CreditApplication>

Returns:

See Also:



218
219
# File 'app/models/contact.rb', line 218

has_many :primary_contact_credit_applications, class_name: 'CreditApplication', foreign_key: :primary_contact_id,
inverse_of: :primary_contact, dependent: :nullify

#primary_sales_repObject

Alias for Customer#primary_sales_rep

Returns:

  • (Object)

    Customer#primary_sales_rep

See Also:



233
# File 'app/models/contact.rb', line 233

delegate :store, :is_homeowner?, :is_organization?, :sales_rep, :primary_sales_rep, to: :customer

#purchasing_agent_credit_applicationsActiveRecord::Relation<CreditApplication>

Returns:

See Also:



223
224
# File 'app/models/contact.rb', line 223

has_many :purchasing_agent_credit_applications, class_name: 'CreditApplication', foreign_key: :purchasing_agent_id,
inverse_of: :purchasing_agent, dependent: :nullify

#quotesActiveRecord::Relation<Quote>

Returns:

  • (ActiveRecord::Relation<Quote>)

See Also:



210
# File 'app/models/contact.rb', line 210

has_many :quotes, through: :opportunities

#resources_for_select(options = {}) ⇒ Object

Activity resources available for this contact’s customer (or self when no customer).

Parameters:

Returns:



278
279
280
# File 'app/models/contact.rb', line 278

def resources_for_select(options = {})
  Activity::ResourceList.new.process(customer || self, options)
end

#room_configurationsActiveRecord::Relation<RoomConfiguration>

Returns:

  • (ActiveRecord::Relation<RoomConfiguration>)

See Also:



209
# File 'app/models/contact.rb', line 209

has_many :room_configurations, through: :opportunities

#sales_repObject

Alias for Customer#sales_rep

Returns:

  • (Object)

    Customer#sales_rep

See Also:



233
# File 'app/models/contact.rb', line 233

delegate :store, :is_homeowner?, :is_organization?, :sales_rep, :primary_sales_rep, to: :customer

#service_jobsActiveRecord::Relation<ServiceJob>

Returns:

See Also:



216
# File 'app/models/contact.rb', line 216

has_many :service_jobs, -> { order(created_at: :desc) }, inverse_of: :contact, dependent: :nullify

#set_owner(party) ⇒ void

This method returns an undefined value.

rubocop:disable Naming/AccessorMethodName -- public API; assigns customer or supplier from a Party
Associates this contact with the given customer or supplier (same customer_id FK).

Parameters:



258
259
260
261
262
263
264
# File 'app/models/contact.rb', line 258

def set_owner(party)
  if party.is_a?(Customer)
    self.customer = party
  elsif party.is_a?(Supplier)
    self.supplier = party
  end
end

#sourceSource

Returns:

See Also:



200
# File 'app/models/contact.rb', line 200

belongs_to :source, optional: true

#spiffSpiff

Returns:

See Also:



204
# File 'app/models/contact.rb', line 204

belongs_to :spiff, optional: true

#spiff_addressAddress

Returns:

See Also:



203
# File 'app/models/contact.rb', line 203

belongs_to :spiff_address, class_name: 'Address', optional: true

#spiff_enrollmentsActiveRecord::Relation<SpiffEnrollment>

Returns:

See Also:



213
# File 'app/models/contact.rb', line 213

has_many :spiff_enrollments, dependent: :nullify, inverse_of: :contact

#spiff_ordersActiveRecord::Relation<Order>

Returns:

  • (ActiveRecord::Relation<Order>)

See Also:



212
# File 'app/models/contact.rb', line 212

has_many :spiff_orders, class_name: 'Order', foreign_key: 'spiff_rep_id', dependent: :nullify, inverse_of: :spiff_rep

#storeObject

Alias for Customer#store

Returns:

  • (Object)

    Customer#store

See Also:



233
# File 'app/models/contact.rb', line 233

delegate :store, :is_homeowner?, :is_organization?, :sales_rep, :primary_sales_rep, to: :customer

#supplierSupplier

Returns:

See Also:



196
# File 'app/models/contact.rb', line 196

belongs_to :supplier, class_name: 'Supplier', foreign_key: 'customer_id', optional: true