Class: LineItem

Overview

== Schema Information

Table name: line_items
Database name: primary

id :integer not null, primary key
children_count :integer
cm_category :string(255)
description :text
destination_state_code :string(255)
discounted_price :decimal(10, 2) default(0.0), not null
edi_line_number :integer
edi_reference :string
edi_unit_cost :decimal(10, 2)
ignore_tax :boolean
origin_state_code :string(255)
price :decimal(10, 2) not null
qty_shipped :integer
quantity :integer not null
redemption_code :string(255)
resource_type :string(255)
reviewed :boolean default(FALSE), not null
sequence :integer
tax_class :string(255)
tax_only :boolean
tax_rate :decimal(10, 6)
tax_total :decimal(10, 2)
tax_type :string
taxable_amount :decimal(12, 2)
total_cogs :decimal(10, 4)
unit_cogs :decimal(10, 4)
created_at :datetime
updated_at :datetime
backup_catalog_item_id :integer
business_unit_id :integer
catalog_item_id :integer
creator_id :integer
credit_order_line_item_id :integer
credit_rma_item_id :integer
delivery_id :integer
item_id :integer
ledger_company_account_id :integer
legacy_iq_room_line_item_option_group_id :integer
parent_id :integer
replacement_rma_item_id :integer
resource_id :integer
resource_tax_rate_id :integer
room_configuration_id :integer
serial_number_id :integer
shipping_cost_id :integer
store_item_id :integer
updater_id :integer

Indexes

idx_catalog_item_id_delivery_id (catalog_item_id,delivery_id)
idx_delivery_id_item_id_tax_class (delivery_id,item_id,tax_class)
idx_resource_type_resource_id_ci_id (resource_type,resource_id,catalog_item_id)
index_line_items_on_credit_rma_item_id (credit_rma_item_id) WHERE (credit_rma_item_id IS NOT NULL) USING hash
index_line_items_on_delivery_id (delivery_id) WHERE (delivery_id IS NOT NULL) USING hash
index_line_items_on_parent_id (parent_id) USING hash
index_line_items_on_replacement_rma_item_id (replacement_rma_item_id) WHERE (replacement_rma_item_id IS NOT NULL) USING hash
index_line_items_on_resource_type_and_item_id (resource_type,item_id)
index_line_items_on_room_configuration_id (room_configuration_id) WHERE (room_configuration_id IS NOT NULL) USING hash
index_line_items_on_shipping_cost_id (shipping_cost_id) WHERE (shipping_cost_id IS NOT NULL) USING hash
line_items_delivery_id_dup_idx (resource_type,resource_id,item_id,delivery_id) UNIQUE WHERE ((tax_class)::text = 'shp'::text)
line_items_resource_id_index (resource_id)

Foreign Keys

fk_rails_... (catalog_item_id => catalog_items.id)
line_items_catalog_item_id_fk (catalog_item_id => catalog_items.id)
line_items_delivery_id_fk (delivery_id => deliveries.id) ON DELETE => nullify
line_items_room_configuration_id_fk (room_configuration_id => room_configurations.id) ON DELETE => nullify
line_items_shipping_costs_id_fk (shipping_cost_id => shipping_costs.id) ON DELETE => cascade

Constant Summary collapse

LINE_ITEM_TAX_CLASSES =
{ g: 'GOODS', svc: 'SERVICE', shp: 'FREIGHT', none: 'NONE' }.freeze
LINE_ITEM_TAX_CLASSES_SORT_ORDER =
%i[g svc shp none].freeze

Constants included from Models::InventoryCommittable

Models::InventoryCommittable::STATES_WITH_NO_EXPIRATION

Constants included from Models::Auditable

Models::Auditable::ALWAYS_IGNORED

Instance Attribute Summary collapse

Attributes included from Models::TaxableLine

#do_not_calculate_tax

Belongs to collapse

Methods included from Models::TaxableLine

#destination_state, #origin_state, #resource_tax_rate

Methods included from Models::Auditable

#creator, #updater

Has one collapse

Has many collapse

Methods included from Models::Reservable

#reserved_serial_numbers

Delegated Instance Attributes collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Models::Lineage

#ancestors, #ancestors_ids, #children_and_roots, #descendants, #descendants_ids, #ensure_non_recursive_lineage, #family_members, #generate_full_name, #generate_full_name_array, #lineage, #lineage_array, #lineage_simple, #root, #root_id, #self_ancestors_and_descendants, #self_ancestors_and_descendants_ids, #self_and_ancestors, #self_and_ancestors_ids, #self_and_children, #self_and_descendants, #self_and_descendants_ids, #self_and_siblings, #self_and_siblings_ids, #siblings, #siblings_ids

Methods included from Models::TaxableLine

#calculate_tax, #has_tax?, #is_international?, #set_initial_tax_rate, #update_tax_rate

Methods included from Models::InventoryCommittable

#can_be_committed?, #can_be_uncommitted?, #commit_line_items, #determine_commit_expiration_date, #has_committed_line_items?, #uncommit_line_items

Methods included from Models::Reservable

#all_reserved_serial_numbers, #all_reserved_serial_numbers_available?, #auto_reserve_serial_numbers, #available_serial_numbers, #commit_reserved_serial_numbers, #fully_reserved?, #kit_components_requires_reservation?, #link_serial_numbers, #rejoin_serial_numbers, #require_reservation?, #reservable_item, #reservable_store_item, #serial_numbers, #show_serial_number_toggle?, #skip_reservation_screen?, #split_serial_numbers, #total_reserved_serial_numbers, #uncommit_reserved_serial_numbers, #unlink_serial_numbers, #update_serial_numbers_shipped_count

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

#business_unit_idObject (readonly)



129
# File 'app/models/line_item.rb', line 129

validates :ledger_company_account_id, :business_unit_id, presence: { if: proc { |li| (li.cm_category == 'Misc') && li.linked_to_standalone_credit_memo } }

#cm_categoryObject (readonly)



128
# File 'app/models/line_item.rb', line 128

validates :cm_category, presence: { if: proc { |li| li.linked_to_credit_memo || li.linked_to_invoice } }

#company_account_refObject

Returns the value of attribute company_account_ref.



219
220
221
# File 'app/models/line_item.rb', line 219

def 
  @company_account_ref
end

#discounted_priceObject (readonly)



136
# File 'app/models/line_item.rb', line 136

validates :discounted_price, numericality: { equal_to: 0, if: proc { |li| li.tax_only? }, message: 'must be equal to 0 for tax only lines' }

#force_catalog_validationObject

Returns the value of attribute force_catalog_validation.



219
220
221
# File 'app/models/line_item.rb', line 219

def force_catalog_validation
  @force_catalog_validation
end

#item_idObject (readonly)



131
# File 'app/models/line_item.rb', line 131

validates :item_id, presence: { if: proc { |li| (li.cm_category == 'Item') && li.linked_to_standalone_invoice } }

#item_nameObject

Returns the value of attribute item_name.



219
220
221
# File 'app/models/line_item.rb', line 219

def item_name
  @item_name
end

#ledger_company_account_idObject (readonly)



129
# File 'app/models/line_item.rb', line 129

validates :ledger_company_account_id, :business_unit_id, presence: { if: proc { |li| (li.cm_category == 'Misc') && li.linked_to_standalone_credit_memo } }

#original_delivery_idObject

Returns the value of attribute original_delivery_id.



219
220
221
# File 'app/models/line_item.rb', line 219

def original_delivery_id
  @original_delivery_id
end

#qty_availableObject

Returns the value of attribute qty_available.



219
220
221
# File 'app/models/line_item.rb', line 219

def qty_available
  @qty_available
end

#quantityObject (readonly)



134
# File 'app/models/line_item.rb', line 134

validates :quantity, presence: true

#skuObject

Returns the value of attribute sku.



219
220
221
# File 'app/models/line_item.rb', line 219

def sku
  @sku
end

#sku_overrideObject

Returns the value of attribute sku_override.



219
220
221
# File 'app/models/line_item.rb', line 219

def sku_override
  @sku_override
end

#tax_classObject (readonly)



130
# File 'app/models/line_item.rb', line 130

validates :tax_class, :taxable_amount, presence: { if: :linked_to_standalone_credit_memo_or_invoice }

#taxable_amountObject (readonly)



130
# File 'app/models/line_item.rb', line 130

validates :tax_class, :taxable_amount, presence: { if: :linked_to_standalone_credit_memo_or_invoice }

#unit_cogsObject (readonly)



132
# File 'app/models/line_item.rb', line 132

validates :unit_cogs, presence: { if: proc { |li| (li.cm_category == 'Item') && li.linked_to_invoice } }

Class Method Details

.accessoriesActiveRecord::Relation<LineItem>

A relation of LineItems that are accessories. Active Record Scope

Returns:

See Also:



154
# File 'app/models/line_item.rb', line 154

scope :accessories, -> { joins(:item).merge(Item.accessories) }

.availability_hash(line_items) ⇒ Object



494
495
496
497
498
499
500
501
502
503
504
505
# File 'app/models/line_item.rb', line 494

def self.availability_hash(line_items)
  result = {}
  line_items.each do |li|
    next unless li.catalog_item

    cat_item_id = li.catalog_item.id
    result[cat_item_id] ||= { 'available' => li.catalog_item.qty_available, 'ordered' => 0, 'in_stock' => li.catalog_item.qty_available.positive? }
    result[cat_item_id]['ordered'] += li.quantity
    result[cat_item_id]['in_stock'] = false if result[cat_item_id]['ordered'] > result[cat_item_id]['available']
  end
  result
end

.bstockActiveRecord::Relation<LineItem>

A relation of LineItems that are bstock. Active Record Scope

Returns:

See Also:



208
# File 'app/models/line_item.rb', line 208

scope :bstock, -> { joins(:item).where(items: { condition: 'refurbished' }) }

.by_product_category_pathActiveRecord::Relation<LineItem>

A relation of LineItems that are by product category path. Active Record Scope

Returns:

See Also:



191
# File 'app/models/line_item.rb', line 191

scope :by_product_category_path, ->(slug_path) { joins(:item).merge(Item.by_product_category_path(slug_path)) }

.by_product_category_urlActiveRecord::Relation<LineItem>

A relation of LineItems that are by product category url. Active Record Scope

Returns:

See Also:



187
# File 'app/models/line_item.rb', line 187

scope :by_product_category_url, ->(url) { joins(:item).merge(Item.by_product_category_url(url)) }

.by_product_line_pathActiveRecord::Relation<LineItem>

A relation of LineItems that are by product line path. Active Record Scope

Returns:

See Also:



190
# File 'app/models/line_item.rb', line 190

scope :by_product_line_path, ->(slug_path) { joins(:item).merge(Item.by_product_line_path(slug_path)) }

.by_product_line_urlActiveRecord::Relation<LineItem>

A relation of LineItems that are by product line url. Active Record Scope

Returns:

See Also:



188
# File 'app/models/line_item.rb', line 188

scope :by_product_line_url, ->(url) { joins(:item).merge(Item.by_product_line_url(url)) }

.cold_leadsActiveRecord::Relation<LineItem>

A relation of LineItems that are cold leads. Active Record Scope

Returns:

See Also:



173
# File 'app/models/line_item.rb', line 173

scope :cold_leads, -> { joins(:item).merge(Item.cold_leads) }

.collect_product_lines(line_items) ⇒ Object



255
256
257
# File 'app/models/line_item.rb', line 255

def self.collect_product_lines(line_items)
  line_items.filter_map { |li| li&.item&.product_lines }.flatten.uniq
end

.compare(source_line_items, target_line_items) ⇒ Object



340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
# File 'app/models/line_item.rb', line 340

def self.compare(source_line_items, target_line_items)
  report = {}
  all_matched_line_ids = []
  source_line_items.each do |source_line|
    matched_lines_in_target = target_line_items.select { |target_line| target_line.catalog_item_id == source_line.catalog_item_id }
    if matched_lines_in_target.empty?
      report[source_line] = { status: :not_found, note: 'No matching lines found in target', matching_line_ids: [] }
    else
      matched_line_ids = matched_lines_in_target.map(&:id)
      all_matched_line_ids += matched_line_ids
      report[source_line] = { status: :ok, note: "Found similar line at line id #{matched_line_ids.join(',')}", matching_line_ids: matched_line_ids }
    end
  end
  # Anything left?
  leftover_line_ids = target_line_items.reject { |tl| all_matched_line_ids.include? tl.id }.map(&:id)
  report['extra_lines'] = { status: :extra, note: "Found extra lines id #{leftover_line_ids.join(',')}", matching_line_ids: leftover_line_ids } unless leftover_line_ids.empty?
  report
end

.controlsActiveRecord::Relation<LineItem>

A relation of LineItems that are controls. Active Record Scope

Returns:

See Also:



155
# File 'app/models/line_item.rb', line 155

scope :controls, -> { joins(:item).merge(Item.controls) }

.countertop_heatersActiveRecord::Relation<LineItem>

A relation of LineItems that are countertop heaters. Active Record Scope

Returns:

See Also:



186
# File 'app/models/line_item.rb', line 186

scope :countertop_heaters, -> { joins(:item).merge(Item.countertop_heaters) }

.custom_matsActiveRecord::Relation<LineItem>

A relation of LineItems that are custom mats. Active Record Scope

Returns:

See Also:



185
# File 'app/models/line_item.rb', line 185

scope :custom_mats, -> { joins(:item).merge(Item.custom_mats) }

.dropshipActiveRecord::Relation<LineItem>

A relation of LineItems that are dropship. Active Record Scope

Returns:

See Also:



167
# File 'app/models/line_item.rb', line 167

scope :dropship, -> { joins(:item).merge(Item.dropships) }

.easystatsActiveRecord::Relation<LineItem>

A relation of LineItems that are easystats. Active Record Scope

Returns:

See Also:



163
# File 'app/models/line_item.rb', line 163

scope :easystats, -> { joins(:item).merge(Item.easystats) }

.electrical_plan_controlsActiveRecord::Relation<LineItem>

A relation of LineItems that are electrical plan controls. Active Record Scope

Returns:

See Also:



157
# File 'app/models/line_item.rb', line 157

scope :electrical_plan_controls, -> { joins(:item).merge(Item.electrical_plan_controls) }

.floor_heating_elementsActiveRecord::Relation<LineItem>

A relation of LineItems that are floor heating elements. Active Record Scope

Returns:

See Also:



152
# File 'app/models/line_item.rb', line 152

scope :floor_heating_elements, -> { joins(:item).merge(Item.floor_heating_elements) }

.goodsActiveRecord::Relation<LineItem>

A relation of LineItems that are goods. Active Record Scope

Returns:

See Also:



176
# File 'app/models/line_item.rb', line 176

scope :goods,    -> { where(tax_class: 'g') }

.group_by_category(line_items) ⇒ Object



271
272
273
274
275
276
277
278
279
280
# File 'app/models/line_item.rb', line 271

def self.group_by_category(line_items)
  line_items = line_items.to_a.sort_by(&:sort_priority)
  all_items = line_items.group_by { |li| li.item&.product_category_name || 'Not Categorized' }

  # Use cached priorities from ProductCategoryConstants
  all_items.sort_by do |name, items|
    category_id = items.first&.item&.product_category_id
    ProductCategoryConstants.priority_for(category_id)
  end
end

.has_floor_sensorActiveRecord::Relation<LineItem>

A relation of LineItems that are has floor sensor. Active Record Scope

Returns:

See Also:



179
# File 'app/models/line_item.rb', line 179

scope :has_floor_sensor, -> { joins(:item).merge(Item.has_floor_sensor) }

.heating_elementsActiveRecord::Relation<LineItem>

A relation of LineItems that are heating elements. Active Record Scope

Returns:

See Also:



149
# File 'app/models/line_item.rb', line 149

scope :heating_elements, -> { joins(:item).merge(Item.heating_elements) }

.install_kitsActiveRecord::Relation<LineItem>

A relation of LineItems that are install kits. Active Record Scope

Returns:

See Also:



182
# File 'app/models/line_item.rb', line 182

scope :install_kits, -> { joins(:item).merge(Item.install_kits) }

.insulationsActiveRecord::Relation<LineItem>

A relation of LineItems that are insulations. Active Record Scope

Returns:

See Also:



183
# File 'app/models/line_item.rb', line 183

scope :insulations, -> { joins(:item).merge(Item.insulations) }

.integration_kitsActiveRecord::Relation<LineItem>

A relation of LineItems that are integration kits. Active Record Scope

Returns:

See Also:



165
# File 'app/models/line_item.rb', line 165

scope :integration_kits, -> { joins(:item).merge(Item.integration_kits) }

.inventory_check(container) ⇒ Object



263
264
265
266
267
268
269
# File 'app/models/line_item.rb', line 263

def self.inventory_check(container)
  lines = container.line_items.non_shipping
                   .includes(:item, :direct_store_item, :inventory_commits, { catalog_item: :store_item })
  return :ok if lines.all?(&:is_fulfillable?)

  :none
end

.kitsActiveRecord::Relation<LineItem>

A relation of LineItems that are kits. Active Record Scope

Returns:

See Also:



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

scope :kits, -> { joins(:item).merge(Item.kits) }

.membranesActiveRecord::Relation<LineItem>

A relation of LineItems that are membranes. Active Record Scope

Returns:

See Also:



184
# File 'app/models/line_item.rb', line 184

scope :membranes, -> { joins(:item).merge(Item.membranes) }

.must_be_shipped_insuredActiveRecord::Relation<LineItem>

A relation of LineItems that are must be shipped insured. Active Record Scope

Returns:

See Also:



192
# File 'app/models/line_item.rb', line 192

scope :must_be_shipped_insured, -> { with_associations.where('store_items.must_be_shipped_insured IS TRUE') }

.no_tax_classActiveRecord::Relation<LineItem>

A relation of LineItems that are no tax class. Active Record Scope

Returns:

See Also:



178
# File 'app/models/line_item.rb', line 178

scope :no_tax_class, -> { where(tax_class: 'none') }

.non_dropshipActiveRecord::Relation<LineItem>

A relation of LineItems that are non dropship. Active Record Scope

Returns:

See Also:



168
# File 'app/models/line_item.rb', line 168

scope :non_dropship, -> { joins(:item).merge(Item.non_dropships) }

.non_shippingActiveRecord::Relation<LineItem>

A relation of LineItems that are non shipping. Active Record Scope

Returns:

See Also:



174
# File 'app/models/line_item.rb', line 174

scope :non_shipping, -> { where(tax_class: %w[g svc none]) }

.oj_programmable_tstatsActiveRecord::Relation<LineItem>

A relation of LineItems that are oj programmable tstats. Active Record Scope

Returns:

See Also:



161
# File 'app/models/line_item.rb', line 161

scope :oj_programmable_tstats, -> { joins(:item).merge(Item.oj_programmable_tstats) }

.oj_tstatsActiveRecord::Relation<LineItem>

A relation of LineItems that are oj tstats. Active Record Scope

Returns:

See Also:



160
# File 'app/models/line_item.rb', line 160

scope :oj_tstats, -> { joins(:item).merge(Item.oj_tstats) }

.order_by_specActiveRecord::Relation<LineItem>

A relation of LineItems that are order by spec. Active Record Scope

Returns:

See Also:



151
# File 'app/models/line_item.rb', line 151

scope :order_by_spec, ->(spec, datatype = 'varchar', direction = 'asc') { joins(:item).merge(Item.order_by_spec(spec, datatype, direction)) }

.power_modulesActiveRecord::Relation<LineItem>

A relation of LineItems that are power modules. Active Record Scope

Returns:

See Also:



164
# File 'app/models/line_item.rb', line 164

scope :power_modules, -> { joins(:item).merge(Item.power_modules) }

.powersActiveRecord::Relation<LineItem>

A relation of LineItems that are powers. Active Record Scope

Returns:

See Also:



156
# File 'app/models/line_item.rb', line 156

scope :powers, -> { joins(:item).merge(Item.powers) }

.product_category_sortedActiveRecord::Relation<LineItem>

A relation of LineItems that are product category sorted. Active Record Scope

Returns:

See Also:



147
# File 'app/models/line_item.rb', line 147

scope :product_category_sorted, -> { includes(item: :product_category).joins(item: :product_category).order(ProductCategory[:priority]) }

.relay_panelsActiveRecord::Relation<LineItem>

A relation of LineItems that are relay panels. Active Record Scope

Returns:

See Also:



170
# File 'app/models/line_item.rb', line 170

scope :relay_panels, -> { joins(:item).merge(Item.relay_panels) }

.reservableActiveRecord::Relation<LineItem>

A relation of LineItems that are reservable. Active Record Scope

Returns:

See Also:



180
# File 'app/models/line_item.rb', line 180

scope :reservable, -> { joins(:item).merge(Item.reservable) }

.rough_in_kitsActiveRecord::Relation<LineItem>

A relation of LineItems that are rough in kits. Active Record Scope

Returns:

See Also:



181
# File 'app/models/line_item.rb', line 181

scope :rough_in_kits, -> { joins(:item).merge(Item.rough_in_kits) }

.sensorsActiveRecord::Relation<LineItem>

A relation of LineItems that are sensors. Active Record Scope

Returns:

See Also:



166
# File 'app/models/line_item.rb', line 166

scope :sensors, -> { joins(:item).merge(Item.sensors) }

.servicesActiveRecord::Relation<LineItem>

A relation of LineItems that are services. Active Record Scope

Returns:

See Also:



177
# File 'app/models/line_item.rb', line 177

scope :services, -> { where(tax_class: 'svc') }

.shipping_onlyActiveRecord::Relation<LineItem>

A relation of LineItems that are shipping only. Active Record Scope

Returns:

See Also:



175
# File 'app/models/line_item.rb', line 175

scope :shipping_only, -> { where(tax_class: 'shp') }

.sku_and_aliases_searchActiveRecord::Relation<LineItem>

A relation of LineItems that are sku and aliases search. Active Record Scope

Returns:

See Also:



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

scope :sku_and_aliases_search, ->(sku) { joins(:item).merge(Item.sku_and_aliases_search(sku)) }

.smartfit_itemsActiveRecord::Relation<LineItem>

A relation of LineItems that are smartfit items. Active Record Scope

Returns:

See Also:



197
# File 'app/models/line_item.rb', line 197

scope :smartfit_items, -> { by_product_line_path(LtreePaths::PL_SERVICES_SMARTFIT) }

.smartfix_itemsActiveRecord::Relation<LineItem>

A relation of LineItems that are smartfix items. Active Record Scope

Returns:

See Also:



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

scope :smartfix_items, -> { by_product_line_path(LtreePaths::PL_SERVICES_SMARTFIX) }

.smartguide_itemsActiveRecord::Relation<LineItem>

A relation of LineItems that are smartguide items. Active Record Scope

Returns:

See Also:



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

scope :smartguide_items, -> { by_product_line_path(LtreePaths::PL_SERVICES_SMARTGUIDE) }

.smartinstall_itemsActiveRecord::Relation<LineItem>

A relation of LineItems that are smartinstall items. Active Record Scope

Returns:

See Also:



198
# File 'app/models/line_item.rb', line 198

scope :smartinstall_items, -> { by_product_line_path(LtreePaths::PL_SERVICES_SMARTINSTALL) }

.smartpresetsActiveRecord::Relation<LineItem>

A relation of LineItems that are smartpresets. Active Record Scope

Returns:

See Also:



172
# File 'app/models/line_item.rb', line 172

scope :smartpresets, -> { joins(:item).merge(Item.smartpresets) }

.smartservice_itemsActiveRecord::Relation<LineItem>

A relation of LineItems that are smartservice items. Active Record Scope

Returns:

See Also:



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

scope :smartservice_items, -> { joins(:item).merge(Item.smart_services) }

.smartstatsActiveRecord::Relation<LineItem>

A relation of LineItems that are smartstats. Active Record Scope

Returns:

See Also:



162
# File 'app/models/line_item.rb', line 162

scope :smartstats, -> { joins(:item).merge(Item.smartstats) }

.snow_melting_elementsActiveRecord::Relation<LineItem>

A relation of LineItems that are snow melting elements. Active Record Scope

Returns:

See Also:



153
# File 'app/models/line_item.rb', line 153

scope :snow_melting_elements, -> { joins(:item).merge(Item.snow_melting_elements) }

.sort_for_planActiveRecord::Relation<LineItem>

A relation of LineItems that are sort for plan. Active Record Scope

Returns:

See Also:



158
# File 'app/models/line_item.rb', line 158

scope :sort_for_plan, -> { order_by_spec('amps', 'decimal', 'asc') }

.tempzone_onlyActiveRecord::Relation<LineItem>

A relation of LineItems that are tempzone only. Active Record Scope

Returns:

See Also:



159
# File 'app/models/line_item.rb', line 159

scope :tempzone_only, -> { joins(:item).merge(Item.tempzones) }

.tempzone_or_environ_heating_elementsActiveRecord::Relation<LineItem>

A relation of LineItems that are tempzone or environ heating elements. Active Record Scope

Returns:

See Also:



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

scope :tempzone_or_environ_heating_elements, -> {
  heating_elements.joins(:item).where(Item[:primary_pl_path_slugs].ltree_descendant(LtreePaths::PL_FLOOR_HEATING_TEMPZONE))
                  .or(heating_elements.joins(:item).where(Item[:primary_pl_path_slugs].ltree_descendant(LtreePaths::PL_FLOOR_HEATING_ENVIRON)))
}

.thermostatsActiveRecord::Relation<LineItem>

A relation of LineItems that are thermostats. Active Record Scope

Returns:

See Also:



169
# File 'app/models/line_item.rb', line 169

scope :thermostats, -> { joins(:item).merge(Item.thermostats) }

.total_of_collection(line_items) ⇒ Object



259
260
261
# File 'app/models/line_item.rb', line 259

def self.total_of_collection(line_items)
  line_items.to_a.sum(&:total).round(2)
end

.underlaymentsActiveRecord::Relation<LineItem>

A relation of LineItems that are underlayments. Active Record Scope

Returns:

See Also:



171
# File 'app/models/line_item.rb', line 171

scope :underlayments, -> { joins(:item).merge(Item.underlayments) }

.with_associationsActiveRecord::Relation<LineItem>

A relation of LineItems that are with associations. Active Record Scope

Returns:

See Also:



148
# File 'app/models/line_item.rb', line 148

scope :with_associations, -> { includes(:item, catalog_item: { store_item: :item }).references(:item, catalog_item: { store_item: :item }) }

.with_positive_qtyActiveRecord::Relation<LineItem>

A relation of LineItems that are with positive qty. Active Record Scope

Returns:

See Also:



207
# File 'app/models/line_item.rb', line 207

scope :with_positive_qty, -> { where('quantity > 0') }

.with_product_specificationActiveRecord::Relation<LineItem>

A relation of LineItems that are with product specification. Active Record Scope

Returns:

See Also:



150
# File 'app/models/line_item.rb', line 150

scope :with_product_specification, ->(token, value, grouping = nil) { joins(:item).merge(Item.with_product_specification(token, value, grouping)) }

.with_reserved_serial_numbers_countActiveRecord::Relation<LineItem>

A relation of LineItems that are with reserved serial numbers count. Active Record Scope

Returns:

See Also:



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

scope :with_reserved_serial_numbers_count, -> { all.select_append('(select count(rsn.id) from reserved_serial_numbers rsn where rsn.line_item_id = line_items.id) as reserved_serial_numbers_count') }

.with_serial_numbers_countActiveRecord::Relation<LineItem>

A relation of LineItems that are with serial numbers count. Active Record Scope

Returns:

See Also:



205
# File 'app/models/line_item.rb', line 205

scope :with_serial_numbers_count, -> { all.select_append('(select count(sn.id) from serial_numbers sn where sn.line_item_id = line_items.id) as serial_numbers_count') }

.without_childrenActiveRecord::Relation<LineItem>

A relation of LineItems that are without children. Active Record Scope

Returns:

See Also:



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

scope :without_children, -> { where(children_count: [nil, 0]) }

Instance Method Details

#all_quantities_allocated_to_shipments?Boolean

Returns:

  • (Boolean)


369
370
371
# File 'app/models/line_item.rb', line 369

def all_quantities_allocated_to_shipments?
  remaining_quantity_to_allocate_to_shipments == 0
end

#as_jsonObject



803
804
805
# File 'app/models/line_item.rb', line 803

def as_json
  super(methods: %i[name sku get_item_id])
end

#business_unitBusinessUnit



113
# File 'app/models/line_item.rb', line 113

belongs_to :business_unit, optional: true

#calculated_tax_classObject



409
410
411
412
413
# File 'app/models/line_item.rb', line 409

def calculated_tax_class
  return tax_class if tax_class

  item.nil? ? tax_class : item.tax_class
end

#catalog_itemCatalogItem



95
# File 'app/models/line_item.rb', line 95

belongs_to :catalog_item, inverse_of: :line_items, optional: true

#category_nameObject

Alias for Item#category_name

Returns:

  • (Object)

    Item#category_name

See Also:



221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
# File 'app/models/line_item.rb', line 221

delegate :is_oj_programmable_tstat?,
:is_smartstat?,
:is_cork?,
:is_relay_panel?,
:is_legacy_relay?,
:is_publication?,
:maximum_current,
:num_poles,
:category_name,
:image_path,
:image_url,
:thumbnail_url,
:is_floor_heating_product?,
:oversize?,
:ships_via_freight?,
:product_tax_code,
:is_snow_melting_product?,
:is_reviewable?,
:product_line_for_review,
to: :item,
allow_nil: true

#children_description(short = false, with_brackets = false) ⇒ Object



570
571
572
573
574
575
576
577
578
579
580
# File 'app/models/line_item.rb', line 570

def children_description(short = false, with_brackets = false)
  contents = nil
  if children.any?
    contents = ''
    contents += "The #{sku} is " unless short
    contents += 'composed of '
    contents += children.collect { |child| "#{child.quantity} x #{child.item.sku}" }.to_sentence(last_word_connector: ' and ')
    contents = "(#{contents})" if with_brackets
  end
  contents
end

#cogs_markupObject



688
689
690
# File 'app/models/line_item.rb', line 688

def cogs_markup
  1.1 # 10% markup for packaging and unapplied landed cost
end

#copy_discounted_priceObject (protected)



872
873
874
# File 'app/models/line_item.rb', line 872

def copy_discounted_price
  self.price = discounted_price
end

#coupon_amountObject



365
366
367
# File 'app/models/line_item.rb', line 365

def coupon_amount
  line_discounts.sum(:amount)
end

#credit_memoCreditMemo

Returns:

See Also:



101
# File 'app/models/line_item.rb', line 101

belongs_to :credit_memo, -> { joins(:line_items).where(line_items: { resource_type: 'CreditMemo' }) }, foreign_key: :resource_id, optional: true

#credit_order_line_itemLineItem

Returns:

See Also:



110
# File 'app/models/line_item.rb', line 110

belongs_to :credit_order_line_item, class_name: 'LineItem', optional: true

#credit_percentageObject



419
420
421
422
423
424
425
426
427
# File 'app/models/line_item.rb', line 419

def credit_percentage
  return nil if credit_rma_item.nil? && credit_order_line_item.nil?

  if credit_rma_item
    credit_rma_item.credit_percentage
  elsif credit_order_line_item.try(:credit_rma_item)
    credit_order_line_item.credit_rma_item.credit_percentage
  end
end

#credit_rma_itemRmaItem

Returns:

See Also:



108
# File 'app/models/line_item.rb', line 108

belongs_to :credit_rma_item, class_name: 'RmaItem', optional: true

#currencyObject

Delegators



361
362
363
# File 'app/models/line_item.rb', line 361

def currency
  resource.try(:currency)
end

#currency_symbolObject



582
583
584
# File 'app/models/line_item.rb', line 582

def currency_symbol
  (resource || delivery).currency_symbol
end

#current_line_cogsObject



673
674
675
676
677
678
679
680
681
682
683
684
685
686
# File 'app/models/line_item.rb', line 673

def current_line_cogs
  # Catalog cogs first
  uc = unit_cogs if unit_cogs && unit_cogs > 0
  uc ||= catalog_item.try(:unit_cogs)
  uc ||= begin
    SupplierItem.order(:id).reverse_order.find_by(item_id:).current_price.unit_cost * cogs_markup
  rescue StandardError
    nil
  end

  return if uc.nil?

  uc * quantity
end

#current_line_profitObject



700
701
702
703
704
705
706
# File 'app/models/line_item.rb', line 700

def current_line_profit
  if estimated_line_cost && (dt = discounted_total)
    dt - estimated_line_cost
  else
    BigDecimal('0.00')
  end
end

#current_line_profit_marginObject

To find the margin, divide gross profit by the revenue.



720
721
722
723
724
725
726
727
# File 'app/models/line_item.rb', line 720

def current_line_profit_margin
  gross_profit = current_line_profit
  revenue = discounted_total
  return 0.0 if gross_profit == 0
  return -1.0 if revenue == 0

  gross_profit / revenue
end

#current_line_profit_markupObject

To write the markup as a percentage, divide the gross profit by the COGS.



709
710
711
712
713
714
715
716
717
# File 'app/models/line_item.rb', line 709

def current_line_profit_markup
  cogs = estimated_line_cost
  gross_profit = current_line_profit
  if cogs == 0
    return 0.0
  end # Technically infinity but let's not raise any exception, cogs should never be zero

  gross_profit / cogs
end

#deep_dupObject



86
87
88
# File 'app/models/line_item.rb', line 86

def deep_dup
  deep_clone(include: [:serial_numbers, :line_discounts])
end

#deliveryDelivery

Returns:

See Also:



105
# File 'app/models/line_item.rb', line 105

belongs_to :delivery, inverse_of: :line_items, optional: true

#detail_urlObject



862
863
864
865
866
867
868
# File 'app/models/line_item.rb', line 862

def detail_url
  i = item
  return unless i&.canonical_path

  locale = resource.try(:store_id) == 2 ? 'en-CA' : 'en-US'
  "https://#{WEB_HOSTNAME}#{i.canonical_url(locale: locale)}"
end

#direct_store_itemStoreItem

Returns:

See Also:



104
# File 'app/models/line_item.rb', line 104

belongs_to :direct_store_item, class_name: 'StoreItem', foreign_key: :store_item_id, optional: true

#discounted_totalObject



586
587
588
589
590
591
592
593
594
595
# File 'app/models/line_item.rb', line 586

def discounted_total
  # ALL itemizables: use line_discounts for exact totals (prevents rounding errors)
  # For example: -$50.00 / 3 qty = -$16.67 per unit, but -16.67 × 3 = -50.01 ❌
  # Using line_discounts ensures: price × qty + line_discounts = exact total ✓
  # This keeps Ruby calculations in sync with SQL calculate_itemizable_total function
  #
  # Use Ruby sum (map + sum) instead of ActiveRecord sum(:column) to leverage
  # preloaded line_discounts and avoid N+1 SUM queries during batch operations.
  price_total + line_discounts.map(&:amount).sum
end

#discountsActiveRecord::Relation<Discount>

Returns:

See Also:



124
# File 'app/models/line_item.rb', line 124

has_many :discounts, through: :line_discounts

#discounts_totalObject



603
604
605
# File 'app/models/line_item.rb', line 603

def discounts_total
  price_total - discounted_total
end

#dropship?Boolean

Returns:

  • (Boolean)


473
474
475
# File 'app/models/line_item.rb', line 473

def dropship?
  item.present? && item.dropship?
end

#effective_discountObject



629
630
631
632
# File 'app/models/line_item.rb', line 629

def effective_discount
  d = price_total - discounted_total
  price_total.positive? && d.positive? ? ((d * 100) / price_total).to_i : 0
end

#estimated_line_costObject



692
693
694
695
696
697
698
# File 'app/models/line_item.rb', line 692

def estimated_line_cost
  if is_shipping?
    price
  else
    current_line_cogs
  end
end

#fulfillment_origin_addressObject



765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
# File 'app/models/line_item.rb', line 765

def fulfillment_origin_address
  # TBD we need to properly populate this at store_item level, for drop shipping from a supplier with multiple addresses, e.g. HeatLay or HeatTrack  or WY office vs WY warehouse, etc.
  if is_service?
    if is_remote_service?
      res = resource.store.warehouse_service_address
    else
      res = delivery&.destination_address
      res ||= resource&.shipping_address
    end
  elsif is_shipping?
    res = delivery.origin_address if delivery
    res ||= resource.store.warehouse_address
    # logger.info "line item, fulfillment_origin_address: #{self.name}, shipping line, fulfillment_origin_address.id: #{res.id}"
  else
    res = store_item&.store&.warehouse_address
  end
  if item.dropship
    res = item.supplier_item.supplier.shipping_address
    # puts "line item: #{self.name}, dropship, fulfillment_origin_address.id: #{res.id}"
  end
  # puts "line item: #{self.name}, fulfillment_origin_address.id: #{res.id rescue NONE}"
  res
end

#fulfillment_origin_address_idObject



761
762
763
# File 'app/models/line_item.rb', line 761

def fulfillment_origin_address_id
  fulfillment_origin_address&.id
end

#get_item_idObject



469
470
471
# File 'app/models/line_item.rb', line 469

def get_item_id
  item.nil? ? nil : item.id
end

#handling_chargeObject



738
739
740
# File 'app/models/line_item.rb', line 738

def handling_charge
  catalog_item&.store_item&.handling_charge
end

#has_children?Boolean

Returns:

  • (Boolean)


566
567
568
# File 'app/models/line_item.rb', line 566

def has_children?
  children_count.present? && (children_count > 0)
end

#has_linked_unvoided_rma_item?Boolean

Returns:

  • (Boolean)


401
402
403
# File 'app/models/line_item.rb', line 401

def has_linked_unvoided_rma_item?
  credit_rma_item.present? && !credit_rma_item.voided?
end

#image_pathObject

Alias for Item#image_path

Returns:

  • (Object)

    Item#image_path

See Also:



221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
# File 'app/models/line_item.rb', line 221

delegate :is_oj_programmable_tstat?,
:is_smartstat?,
:is_cork?,
:is_relay_panel?,
:is_legacy_relay?,
:is_publication?,
:maximum_current,
:num_poles,
:category_name,
:image_path,
:image_url,
:thumbnail_url,
:is_floor_heating_product?,
:oversize?,
:ships_via_freight?,
:product_tax_code,
:is_snow_melting_product?,
:is_reviewable?,
:product_line_for_review,
to: :item,
allow_nil: true

#image_urlObject

Alias for Item#image_url

Returns:

  • (Object)

    Item#image_url

See Also:



221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
# File 'app/models/line_item.rb', line 221

delegate :is_oj_programmable_tstat?,
:is_smartstat?,
:is_cork?,
:is_relay_panel?,
:is_legacy_relay?,
:is_publication?,
:maximum_current,
:num_poles,
:category_name,
:image_path,
:image_url,
:thumbnail_url,
:is_floor_heating_product?,
:oversize?,
:ships_via_freight?,
:product_tax_code,
:is_snow_melting_product?,
:is_reviewable?,
:product_line_for_review,
to: :item,
allow_nil: true

#in_stock?Boolean

Returns:

  • (Boolean)


507
508
509
510
511
512
513
# File 'app/models/line_item.rb', line 507

def in_stock?
  if catalog_item # coupons don't have the same data as line items
    catalog_item.qty_available >= quantity
  else
    true
  end
end

#inventory_commitsActiveRecord::Relation<InventoryCommit>

Returns:

See Also:



125
# File 'app/models/line_item.rb', line 125

has_many :inventory_commits, dependent: :destroy

#invoiceInvoice

Returns:

See Also:



100
# File 'app/models/line_item.rb', line 100

belongs_to :invoice, -> { joins(:line_items).where(line_items: { resource_type: 'Invoice' }) }, foreign_key: :resource_id, optional: true

#is_cork?Object

Alias for Item#is_cork?

Returns:

  • (Object)

    Item#is_cork?

See Also:



221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
# File 'app/models/line_item.rb', line 221

delegate :is_oj_programmable_tstat?,
:is_smartstat?,
:is_cork?,
:is_relay_panel?,
:is_legacy_relay?,
:is_publication?,
:maximum_current,
:num_poles,
:category_name,
:image_path,
:image_url,
:thumbnail_url,
:is_floor_heating_product?,
:oversize?,
:ships_via_freight?,
:product_tax_code,
:is_snow_melting_product?,
:is_reviewable?,
:product_line_for_review,
to: :item,
allow_nil: true

#is_discounted?Boolean

Returns:

  • (Boolean)


634
635
636
# File 'app/models/line_item.rb', line 634

def is_discounted?
  effective_discount > 0
end

#is_floor_heating_product?Object

Alias for Item#is_floor_heating_product?

Returns:

  • (Object)

    Item#is_floor_heating_product?

See Also:



221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
# File 'app/models/line_item.rb', line 221

delegate :is_oj_programmable_tstat?,
:is_smartstat?,
:is_cork?,
:is_relay_panel?,
:is_legacy_relay?,
:is_publication?,
:maximum_current,
:num_poles,
:category_name,
:image_path,
:image_url,
:thumbnail_url,
:is_floor_heating_product?,
:oversize?,
:ships_via_freight?,
:product_tax_code,
:is_snow_melting_product?,
:is_reviewable?,
:product_line_for_review,
to: :item,
allow_nil: true

#is_fulfillable?Boolean

Returns:

  • (Boolean)


558
559
560
# File 'app/models/line_item.rb', line 558

def is_fulfillable?
  %i[ok low na].include?(stock_status)
end

#is_goods?Boolean

Returns:

  • (Boolean)


807
808
809
# File 'app/models/line_item.rb', line 807

def is_goods?
  tax_class.present? ? tax_class == 'g' : item&.is_goods?&.to_b
end

#is_kit?Boolean

Returns:

  • (Boolean)


391
392
393
# File 'app/models/line_item.rb', line 391

def is_kit?
  item&.is_kit?
end

#is_legacy_relay?Object

Alias for Item#is_legacy_relay?

Returns:

  • (Object)

    Item#is_legacy_relay?

See Also:



221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
# File 'app/models/line_item.rb', line 221

delegate :is_oj_programmable_tstat?,
:is_smartstat?,
:is_cork?,
:is_relay_panel?,
:is_legacy_relay?,
:is_publication?,
:maximum_current,
:num_poles,
:category_name,
:image_path,
:image_url,
:thumbnail_url,
:is_floor_heating_product?,
:oversize?,
:ships_via_freight?,
:product_tax_code,
:is_snow_melting_product?,
:is_reviewable?,
:product_line_for_review,
to: :item,
allow_nil: true

#is_linked_to_same_resource_as_deliveryObject



385
386
387
388
389
# File 'app/models/line_item.rb', line 385

def is_linked_to_same_resource_as_delivery
  return unless delivery&.resource && resource&.persisted? && delivery&.resource&.persisted? && resource.id != delivery.resource.id

  errors.add(:resource_id, 'is not the same as Delivery resource')
end

#is_not_a_kitObject



395
396
397
398
399
# File 'app/models/line_item.rb', line 395

def is_not_a_kit
  return unless is_kit?

  errors[:catalog_item_id] << "#{sku} is a kit. Kits are not permitted on store transfers, please add kit components instead"
end

#is_oj_programmable_tstat?Object

Alias for Item#is_oj_programmable_tstat?

Returns:

  • (Object)

    Item#is_oj_programmable_tstat?

See Also:



221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
# File 'app/models/line_item.rb', line 221

delegate :is_oj_programmable_tstat?,
:is_smartstat?,
:is_cork?,
:is_relay_panel?,
:is_legacy_relay?,
:is_publication?,
:maximum_current,
:num_poles,
:category_name,
:image_path,
:image_url,
:thumbnail_url,
:is_floor_heating_product?,
:oversize?,
:ships_via_freight?,
:product_tax_code,
:is_snow_melting_product?,
:is_reviewable?,
:product_line_for_review,
to: :item,
allow_nil: true

#is_onsite_service?Boolean

Returns:

  • (Boolean)


823
824
825
# File 'app/models/line_item.rb', line 823

def is_onsite_service?
  is_service? && item.sku.include?('ONSITE')
end

#is_publication?Object

Alias for Item#is_publication?

Returns:

  • (Object)

    Item#is_publication?

See Also:



221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
# File 'app/models/line_item.rb', line 221

delegate :is_oj_programmable_tstat?,
:is_smartstat?,
:is_cork?,
:is_relay_panel?,
:is_legacy_relay?,
:is_publication?,
:maximum_current,
:num_poles,
:category_name,
:image_path,
:image_url,
:thumbnail_url,
:is_floor_heating_product?,
:oversize?,
:ships_via_freight?,
:product_tax_code,
:is_snow_melting_product?,
:is_reviewable?,
:product_line_for_review,
to: :item,
allow_nil: true

Returns:

  • (Boolean)


843
844
845
846
847
848
849
850
851
852
# File 'app/models/line_item.rb', line 843

def is_related_smart_service?(sku)
  res = false
  # check if our SKU is the corresponding _PER_SQFT or _FIXRATE to the input SKU
  if sku.index('_FIXRATE') && is_smartinstall_service? && item.sku.index('_PER_SQFT') && item.sku.split('_PER_SQFT').first == sku.split('_FIXRATE')
    res = true
  elsif sku.index('_PER_SQFT') && is_smartinstall_service? && item.sku.index('_FIXRATE') && item.sku.split('_FIXRATE').first == sku.split('_PER_SQFT')
    res = true
  end
  res
end

#is_relay_panel?Object

Alias for Item#is_relay_panel?

Returns:

  • (Object)

    Item#is_relay_panel?

See Also:



221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
# File 'app/models/line_item.rb', line 221

delegate :is_oj_programmable_tstat?,
:is_smartstat?,
:is_cork?,
:is_relay_panel?,
:is_legacy_relay?,
:is_publication?,
:maximum_current,
:num_poles,
:category_name,
:image_path,
:image_url,
:thumbnail_url,
:is_floor_heating_product?,
:oversize?,
:ships_via_freight?,
:product_tax_code,
:is_snow_melting_product?,
:is_reviewable?,
:product_line_for_review,
to: :item,
allow_nil: true

#is_remote_service?Boolean

Returns:

  • (Boolean)


819
820
821
# File 'app/models/line_item.rb', line 819

def is_remote_service?
  (is_service? && item.sku.include?('REMOTE')) || (is_service? && resource.line_items.any? { |a| a.sku.include?('REMOTE') })
end

#is_reviewable?Object

Alias for Item#is_reviewable?

Returns:

  • (Object)

    Item#is_reviewable?

See Also:



221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
# File 'app/models/line_item.rb', line 221

delegate :is_oj_programmable_tstat?,
:is_smartstat?,
:is_cork?,
:is_relay_panel?,
:is_legacy_relay?,
:is_publication?,
:maximum_current,
:num_poles,
:category_name,
:image_path,
:image_url,
:thumbnail_url,
:is_floor_heating_product?,
:oversize?,
:ships_via_freight?,
:product_tax_code,
:is_snow_melting_product?,
:is_reviewable?,
:product_line_for_review,
to: :item,
allow_nil: true

#is_service?Boolean

Returns:

  • (Boolean)


815
816
817
# File 'app/models/line_item.rb', line 815

def is_service?
  tax_class.present? ? tax_class == 'svc' : item&.is_service?&.to_b
end

#is_shipping?Boolean

Returns:

  • (Boolean)


831
832
833
# File 'app/models/line_item.rb', line 831

def is_shipping?
  tax_class.present? ? tax_class == 'shp' : item&.is_shipping?&.to_b
end

#is_smart_service?Boolean

Returns:

  • (Boolean)


839
840
841
# File 'app/models/line_item.rb', line 839

def is_smart_service?
  item&.pl_descendant_of_path?(LtreePaths::PL_SERVICES)
end

#is_smartinstall_service?Boolean

Returns:

  • (Boolean)


835
836
837
# File 'app/models/line_item.rb', line 835

def is_smartinstall_service?
  item&.pl_descendant_of_path?(LtreePaths::PL_SERVICES_SMARTINSTALL)
end

#is_smartstat?Object

Alias for Item#is_smartstat?

Returns:

  • (Object)

    Item#is_smartstat?

See Also:



221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
# File 'app/models/line_item.rb', line 221

delegate :is_oj_programmable_tstat?,
:is_smartstat?,
:is_cork?,
:is_relay_panel?,
:is_legacy_relay?,
:is_publication?,
:maximum_current,
:num_poles,
:category_name,
:image_path,
:image_url,
:thumbnail_url,
:is_floor_heating_product?,
:oversize?,
:ships_via_freight?,
:product_tax_code,
:is_snow_melting_product?,
:is_reviewable?,
:product_line_for_review,
to: :item,
allow_nil: true

#is_snow_melting_product?Object

Alias for Item#is_snow_melting_product?

Returns:

  • (Object)

    Item#is_snow_melting_product?

See Also:



221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
# File 'app/models/line_item.rb', line 221

delegate :is_oj_programmable_tstat?,
:is_smartstat?,
:is_cork?,
:is_relay_panel?,
:is_legacy_relay?,
:is_publication?,
:maximum_current,
:num_poles,
:category_name,
:image_path,
:image_url,
:thumbnail_url,
:is_floor_heating_product?,
:oversize?,
:ships_via_freight?,
:product_tax_code,
:is_snow_melting_product?,
:is_reviewable?,
:product_line_for_review,
to: :item,
allow_nil: true

#is_spare_parts?Boolean

Returns:

  • (Boolean)


811
812
813
# File 'app/models/line_item.rb', line 811

def is_spare_parts?
  item&.is_spare_parts?&.to_b
end

#is_tax_unclassed?Boolean

Returns:

  • (Boolean)


827
828
829
# File 'app/models/line_item.rb', line 827

def is_tax_unclassed?
  tax_class == 'none'
end

#itemItem

Returns:

See Also:



111
# File 'app/models/line_item.rb', line 111

belongs_to :item, optional: true

#item_in_stock_in_storeObject (protected)



876
877
878
879
880
881
882
883
884
885
# File 'app/models/line_item.rb', line 876

def item_in_stock_in_store
  return unless get_item_id && resource && resource.store_id

  store_item = StoreItem.available.where(item_id: get_item_id, store_id: resource.store_id).first
  if store_item.nil?
    errors[:item_id] << 'is not available in selected store'
  elsif quantity && (store_item.qty_available < quantity)
    errors[:quantity] << 'is more than quantity available in selected store'
  end
end

#ledger_company_accountLedgerCompanyAccount



112
# File 'app/models/line_item.rb', line 112

belongs_to :ledger_company_account, optional: true

#ledger_descriptionObject



461
462
463
464
465
466
467
# File 'app/models/line_item.rb', line 461

def ledger_description
  if cm_category.nil? || ((cm_category == 'Item') && sku.present?)
    sku
  else
    "#{cm_category} #{description}"
  end
end

#line_discountsActiveRecord::Relation<LineDiscount>

Returns:

See Also:



123
# File 'app/models/line_item.rb', line 123

has_many :line_discounts, dependent: :destroy, inverse_of: :line_item, autosave: true

#line_locked?Boolean

Returns:

  • (Boolean)


477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
# File 'app/models/line_item.rb', line 477

def line_locked?
  return true if resource&.respond_to?(:editing_locked?) && resource.editing_locked?
  # If an item is not plan sensitive, we don't care
  return false unless item.plan_sensitive?

  # If line item is linked to a room within a resource, we do a sanity check to ensure that
  # room is also part of the resource's room configurations
  return false unless room_configuration
  # If the line item is linked to a room not in the resource, don't lock it and do as you please
  return false if resource && resource&.respond_to?(:room_configuration_ids) && !resource.room_configuration_ids.include?(room_configuration.id)

  # Otherwise the room dictates the locking status of that item
  room_configuration.editing_locked?

  # Not relevant edit as you wish
end

#line_total_with_taxObject



597
598
599
600
601
# File 'app/models/line_item.rb', line 597

def line_total_with_tax
  discounted_total + (tax_total || 0.0)
rescue StandardError
  0
end

#linear_ft_totalObject



625
626
627
# File 'app/models/line_item.rb', line 625

def linear_ft_total
  quantity * (item.length.to_f / 12)
end

#linked_to_credit_memoObject



415
416
417
# File 'app/models/line_item.rb', line 415

def linked_to_credit_memo
  resource_type == 'CreditMemo'
end

#linked_to_invoiceObject



429
430
431
# File 'app/models/line_item.rb', line 429

def linked_to_invoice
  resource_type == 'Invoice'
end

#linked_to_st_orderObject



445
446
447
# File 'app/models/line_item.rb', line 445

def linked_to_st_order
  (resource_type == 'Order') && (resource.try(:order_type) == 'ST')
end

#linked_to_standalone_credit_memoObject



433
434
435
# File 'app/models/line_item.rb', line 433

def linked_to_standalone_credit_memo
  (resource_type == 'CreditMemo') && (resource.try(:category) == 'standalone')
end

#linked_to_standalone_credit_memo_or_invoiceObject



441
442
443
# File 'app/models/line_item.rb', line 441

def linked_to_standalone_credit_memo_or_invoice
  linked_to_standalone_credit_memo || linked_to_standalone_invoice
end

#linked_to_standalone_invoiceObject



437
438
439
# File 'app/models/line_item.rb', line 437

def linked_to_standalone_invoice
  (resource_type == 'Invoice') && [Invoice::MI].include?(resource.try(:invoice_type))
end

#max_discountObject

Determine the max discount in effect for this line item
Only for quote or order



284
285
286
287
288
289
290
291
# File 'app/models/line_item.rb', line 284

def max_discount
  md = nil
  if (discountable_resource = quote || order)
    md = discountable_resource.max_discount_override
  end
  md = catalog_item.max_discount if md.nil? && catalog_item
  md
end

#maximum_currentObject

Alias for Item#maximum_current

Returns:

  • (Object)

    Item#maximum_current

See Also:



221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
# File 'app/models/line_item.rb', line 221

delegate :is_oj_programmable_tstat?,
:is_smartstat?,
:is_cork?,
:is_relay_panel?,
:is_legacy_relay?,
:is_publication?,
:maximum_current,
:num_poles,
:category_name,
:image_path,
:image_url,
:thumbnail_url,
:is_floor_heating_product?,
:oversize?,
:ships_via_freight?,
:product_tax_code,
:is_snow_melting_product?,
:is_reviewable?,
:product_line_for_review,
to: :item,
allow_nil: true

#msrpObject

Alias for Catalog_item#msrp

Returns:

  • (Object)

    Catalog_item#msrp

See Also:



243
244
245
246
247
248
249
# File 'app/models/line_item.rb', line 243

delegate :price_with_vat,
:sale_price_with_vat,
:msrp,
:msrp_with_vat,
:root_catalog_item,
to: :catalog_item,
allow_nil: true

#msrp_totalObject



613
614
615
616
617
618
619
# File 'app/models/line_item.rb', line 613

def msrp_total
  return 0.0 if parent_id.present?

  (msrp || 0.0) * quantity
rescue StandardError
  0.0
end

#msrp_with_vatObject

Alias for Catalog_item#msrp_with_vat

Returns:

  • (Object)

    Catalog_item#msrp_with_vat

See Also:



243
244
245
246
247
248
249
# File 'app/models/line_item.rb', line 243

delegate :price_with_vat,
:sale_price_with_vat,
:msrp,
:msrp_with_vat,
:root_catalog_item,
to: :catalog_item,
allow_nil: true

#nameObject



457
458
459
# File 'app/models/line_item.rb', line 457

def name
  description || item.try(:name) || item_name
end

#num_polesObject

Alias for Item#num_poles

Returns:

  • (Object)

    Item#num_poles

See Also:



221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
# File 'app/models/line_item.rb', line 221

delegate :is_oj_programmable_tstat?,
:is_smartstat?,
:is_cork?,
:is_relay_panel?,
:is_legacy_relay?,
:is_publication?,
:maximum_current,
:num_poles,
:category_name,
:image_path,
:image_url,
:thumbnail_url,
:is_floor_heating_product?,
:oversize?,
:ships_via_freight?,
:product_tax_code,
:is_snow_melting_product?,
:is_reviewable?,
:product_line_for_review,
to: :item,
allow_nil: true

#orderOrder

The following makes join easier

Returns:

See Also:



98
# File 'app/models/line_item.rb', line 98

belongs_to :order, -> { joins(:line_items).where(line_items: { resource_type: 'Order' }) }, foreign_key: :resource_id, optional: true

#oversize?Object

Alias for Item#oversize?

Returns:

  • (Object)

    Item#oversize?

See Also:



221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
# File 'app/models/line_item.rb', line 221

delegate :is_oj_programmable_tstat?,
:is_smartstat?,
:is_cork?,
:is_relay_panel?,
:is_legacy_relay?,
:is_publication?,
:maximum_current,
:num_poles,
:category_name,
:image_path,
:image_url,
:thumbnail_url,
:is_floor_heating_product?,
:oversize?,
:ships_via_freight?,
:product_tax_code,
:is_snow_melting_product?,
:is_reviewable?,
:product_line_for_review,
to: :item,
allow_nil: true

#parent_quantity_factorObject

Determines the parent line quantity



294
295
296
297
298
299
300
301
302
303
304
305
# File 'app/models/line_item.rb', line 294

def parent_quantity_factor
  return unless parent && parent.quantity

  # what type of item is the parent
  # parent_item = parent.item
  # how many of this component item are normally in the parent item
  # tir = parent_item.kit_target_item_relations.where(target_item_id: item_id).first
  # component_quantity = tir.quantity
  (quantity / parent.quantity).to_i
  # How many quantity in this line item
  # component_quantity
end

#preset_jobPresetJob

Returns:

See Also:



119
# File 'app/models/line_item.rb', line 119

has_one :preset_job, dependent: :destroy

#price_editable?(account = nil) ⇒ Boolean

Returns:

  • (Boolean)


747
748
749
750
751
752
753
# File 'app/models/line_item.rb', line 747

def price_editable?( = nil)
  .has_role?('sales_manager') || .has_role?('admin') || (begin
    catalog_item.price_editable
  rescue StandardError
    false
  end)
end

#price_totalObject



607
608
609
610
611
# File 'app/models/line_item.rb', line 607

def price_total
  (price || 0.0) * quantity
rescue StandardError
  0.0
end

#price_with_vatObject

Alias for Catalog_item#price_with_vat

Returns:

  • (Object)

    Catalog_item#price_with_vat

See Also:



243
244
245
246
247
248
249
# File 'app/models/line_item.rb', line 243

delegate :price_with_vat,
:sale_price_with_vat,
:msrp,
:msrp_with_vat,
:root_catalog_item,
to: :catalog_item,
allow_nil: true

#product_line_for_reviewObject

Alias for Item#product_line_for_review

Returns:

  • (Object)

    Item#product_line_for_review

See Also:



221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
# File 'app/models/line_item.rb', line 221

delegate :is_oj_programmable_tstat?,
:is_smartstat?,
:is_cork?,
:is_relay_panel?,
:is_legacy_relay?,
:is_publication?,
:maximum_current,
:num_poles,
:category_name,
:image_path,
:image_url,
:thumbnail_url,
:is_floor_heating_product?,
:oversize?,
:ships_via_freight?,
:product_tax_code,
:is_snow_melting_product?,
:is_reviewable?,
:product_line_for_review,
to: :item,
allow_nil: true

#product_tax_codeObject

Alias for Item#product_tax_code

Returns:

  • (Object)

    Item#product_tax_code

See Also:



221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
# File 'app/models/line_item.rb', line 221

delegate :is_oj_programmable_tstat?,
:is_smartstat?,
:is_cork?,
:is_relay_panel?,
:is_legacy_relay?,
:is_publication?,
:maximum_current,
:num_poles,
:category_name,
:image_path,
:image_url,
:thumbnail_url,
:is_floor_heating_product?,
:oversize?,
:ships_via_freight?,
:product_tax_code,
:is_snow_melting_product?,
:is_reviewable?,
:product_line_for_review,
to: :item,
allow_nil: true

#purchase_order_itemPurchaseOrderItem



118
# File 'app/models/line_item.rb', line 118

has_one :purchase_order_item, dependent: :restrict_with_error

#quantities_indicator_visible?Boolean

Returns:

  • (Boolean)


755
756
757
758
759
# File 'app/models/line_item.rb', line 755

def quantities_indicator_visible?
  item.quantities_indicator_visible?
rescue StandardError
  true
end

#quoteQuote

Returns:

See Also:



99
# File 'app/models/line_item.rb', line 99

belongs_to :quote, -> { joins(:line_items).where(line_items: { resource_type: 'Quote' }) }, foreign_key: :resource_id, optional: true

#remaining_quantity_to_allocate_to_shipmentsObject



373
374
375
# File 'app/models/line_item.rb', line 373

def remaining_quantity_to_allocate_to_shipments
  quantity - shipment_contents.sum(:quantity)
end

#replacement_rma_itemRmaItem

Returns:

See Also:



109
# File 'app/models/line_item.rb', line 109

belongs_to :replacement_rma_item, class_name: 'RmaItem', optional: true

#reported_category_nameObject



858
859
860
# File 'app/models/line_item.rb', line 858

def reported_category_name
  item&.primary_product_line&.lineage_expanded || 'unknown'
end

#require_serial_number?Boolean

Returns:

  • (Boolean)


742
743
744
745
# File 'app/models/line_item.rb', line 742

def require_serial_number?
  false
  # catalog_item.store_item.requires_serial_number? rescue false
end

#resourceResource

Returns:

  • (Resource)

See Also:



96
# File 'app/models/line_item.rb', line 96

belongs_to :resource, polymorphic: true, inverse_of: :line_items, optional: true

#reviewReview

Returns:

See Also:



120
# File 'app/models/line_item.rb', line 120

has_one :review, dependent: :restrict_with_error

#rma_itemsActiveRecord::Relation<RmaItem>

Returns:

  • (ActiveRecord::Relation<RmaItem>)

See Also:



122
# File 'app/models/line_item.rb', line 122

has_many :rma_items, foreign_key: 'returned_line_item_id', dependent: :destroy, inverse_of: :returned_line_item

#roomRoom

Returns:

  • (Room)

See Also:



102
# File 'app/models/line_item.rb', line 102

belongs_to :room, -> { joins(:line_items).where(line_items: { resource_type: 'RoomConfiguration' }) }, foreign_key: :resource_id, optional: true

#room_configurationRoomConfiguration

Returns:

  • (RoomConfiguration)

See Also:



107
# File 'app/models/line_item.rb', line 107

belongs_to :room_configuration, optional: true

#root_catalog_itemObject

Alias for Catalog_item#root_catalog_item

Returns:

  • (Object)

    Catalog_item#root_catalog_item

See Also:



243
244
245
246
247
248
249
# File 'app/models/line_item.rb', line 243

delegate :price_with_vat,
:sale_price_with_vat,
:msrp,
:msrp_with_vat,
:root_catalog_item,
to: :catalog_item,
allow_nil: true

#sale_price_with_vatObject

Alias for Catalog_item#sale_price_with_vat

Returns:

  • (Object)

    Catalog_item#sale_price_with_vat

See Also:



243
244
245
246
247
248
249
# File 'app/models/line_item.rb', line 243

delegate :price_with_vat,
:sale_price_with_vat,
:msrp,
:msrp_with_vat,
:root_catalog_item,
to: :catalog_item,
allow_nil: true

#serial_numberSerialNumber



106
# File 'app/models/line_item.rb', line 106

belongs_to :serial_number, optional: true

#set_cogsObject (protected)



887
888
889
890
891
892
893
894
895
# File 'app/models/line_item.rb', line 887

def set_cogs
  return unless !quantity.nil? && unit_cogs.nil? && resource.store_id.present?

  store_item = StoreItem.available.where(item_id: get_item_id, store_id: resource.store_id).first
  return if store_item.nil?

  self.unit_cogs = store_item.unit_cogs
  self.total_cogs = store_item.unit_cogs * quantity
end

#set_cogs_for_store_transferObject (protected)



897
898
899
900
901
902
903
904
905
906
# File 'app/models/line_item.rb', line 897

def set_cogs_for_store_transfer
  return unless resource.try(:is_store_transfer?)
  return if unit_cogs.present? || quantity.nil?

  store_item = self.store_item
  return if store_item.nil?

  self.unit_cogs = store_item.unit_cogs
  self.total_cogs = store_item.unit_cogs * quantity if store_item.unit_cogs.present?
end

#shipment_contentsActiveRecord::Relation<ShipmentContent>

Returns:

See Also:



126
# File 'app/models/line_item.rb', line 126

has_many :shipment_contents, dependent: :destroy

#shipping_costShippingCost



114
# File 'app/models/line_item.rb', line 114

belongs_to :shipping_cost, optional: true

#shipping_nameObject



854
855
856
# File 'app/models/line_item.rb', line 854

def shipping_name
  delivery&.retrieve_shipping_description_for_shipping_cost(shipping_cost) || name
end

#shipping_weightObject



729
730
731
732
# File 'app/models/line_item.rb', line 729

def shipping_weight
  # important: item.base_weight is the better quality number and means Net Unit Weight so the correct number to use when calculating item weight because tare weight (of the box, pallet, crate etc) is added after
  item&.base_weight || 0.0
end

#ships_via_freight?Object

Alias for Item#ships_via_freight?

Returns:

  • (Object)

    Item#ships_via_freight?

See Also:



221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
# File 'app/models/line_item.rb', line 221

delegate :is_oj_programmable_tstat?,
:is_smartstat?,
:is_cork?,
:is_relay_panel?,
:is_legacy_relay?,
:is_publication?,
:maximum_current,
:num_poles,
:category_name,
:image_path,
:image_url,
:thumbnail_url,
:is_floor_heating_product?,
:oversize?,
:ships_via_freight?,
:product_tax_code,
:is_snow_melting_product?,
:is_reviewable?,
:product_line_for_review,
to: :item,
allow_nil: true

#show_out_of_stock?(item_availability = {}) ⇒ Boolean

Returns:

  • (Boolean)


515
516
517
518
519
520
521
522
523
524
525
# File 'app/models/line_item.rb', line 515

def show_out_of_stock?(item_availability = {})
  if dropship? && resource.respond_to?(:single_origin?) && resource.single_origin?
    !in_stock?
  elsif dropship? || item.try(:always_available_online?)
    false
  elsif !item_availability.empty? && item_availability[catalog_item_id].present?
    !item_availability[catalog_item_id]['in_stock']
  else
    !in_stock?
  end
end

#single_origin_or_warehouse_pickup?Boolean

Returns:

  • (Boolean)


527
528
529
530
531
# File 'app/models/line_item.rb', line 527

def single_origin_or_warehouse_pickup?
  return false if resource.is_a?(RoomConfiguration)

  resource.single_origin? || resource.is_warehouse_pickup?
end

#sort_priorityObject



316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
# File 'app/models/line_item.rb', line 316

def sort_priority
  i = item || catalog_item&.store_item&.item
  return [0, 0, 0, 0] unless i

  s1 = i.product_category_priority
  if i.is_heating_element?
    s2 = -begin
      i.width.to_i
    rescue StandardError
      0
    end
    s3 = -begin
      i.length.to_i
    rescue StandardError
      0
    end
  else
    s2 = 0
    s3 = 0
  end
  s4 = i.sku
  [s1, s2, s3, s4]
end

#sq_ft_totalObject



621
622
623
# File 'app/models/line_item.rb', line 621

def sq_ft_total
  quantity * item.sqft.to_f
end

#stock_statusObject



533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
# File 'app/models/line_item.rb', line 533

def stock_status
  return :none unless catalog_item
  return :na if quantity < 0 # not applicable for credit orders
  if dropship? && !single_origin_or_warehouse_pickup?
    return :ok
  end # regular dropship returns ok, must be in stock if single origin or warehouse pickup
  return :ok if unlimited_inventory?

  # Check if this specific line item has enough commits to fulfill its quantity.
  # Use Enumerable#sum (block form) so preloaded inventory_commits are used in-memory
  # without firing a SQL SUM aggregate per line item.
  committed_quantity = inventory_commits.sum { |ic| ic.quantity }
  return :ok if committed_quantity >= quantity

  si = resource.respond_to?(:from_store_id) && resource.from_store_id ? StoreItem.where(store_id: resource.from_store_id, item_id:, location: 'AVAILABLE').first : store_item
  return :oos if si.qty_available < quantity
  return :low if item.qty_warn_on_stock && (si.qty_available <= item.qty_warn_on_stock)

  :ok
end

#store_itemObject



562
563
564
# File 'app/models/line_item.rb', line 562

def store_item
  direct_store_item || catalog_item&.store_item
end

#supplier_skusObject



453
454
455
# File 'app/models/line_item.rb', line 453

def supplier_skus
  item&.supplier_skus || []
end

#taxable_totalObject



638
639
640
641
642
643
644
# File 'app/models/line_item.rb', line 638

def taxable_total
  if invoice&.invoice_type == Invoice::CI
    discounted_total
  else
    taxable_amount.present? ? (taxable_amount * quantity) : discounted_total
  end
end

#taxes_grouped_by_typeObject



307
308
309
310
311
312
313
314
# File 'app/models/line_item.rb', line 307

def taxes_grouped_by_type
  tax_grouped = {}
  if tax_rate.present? && tax_type.present?
    rate_percentage = (tax_rate * 100)
    tax_grouped[tax_type] = { tax_amount: tax_total, name: "#{TaxRate.description_for(tax_type)} #{rate_percentage}%", rate: rate_percentage }
  end
  tax_grouped
end

#thumbnail_urlObject

Alias for Item#thumbnail_url

Returns:

  • (Object)

    Item#thumbnail_url

See Also:



221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
# File 'app/models/line_item.rb', line 221

delegate :is_oj_programmable_tstat?,
:is_smartstat?,
:is_cork?,
:is_relay_panel?,
:is_legacy_relay?,
:is_publication?,
:maximum_current,
:num_poles,
:category_name,
:image_path,
:image_url,
:thumbnail_url,
:is_floor_heating_product?,
:oversize?,
:ships_via_freight?,
:product_tax_code,
:is_snow_melting_product?,
:is_reviewable?,
:product_line_for_review,
to: :item,
allow_nil: true

#totalObject



646
647
648
# File 'app/models/line_item.rb', line 646

def total
  discounted_total
end

#total_shipping_weightObject



734
735
736
# File 'app/models/line_item.rb', line 734

def total_shipping_weight
  (shipping_weight * quantity)
end

#unit_supplier_purchase_costObject

def total=(value)
end



653
654
655
# File 'app/models/line_item.rb', line 653

def unit_supplier_purchase_cost
  item.try(:supplier_items)&.last&.current_price&.purchasing_cost
end

#unit_value_for_commercial_invoiceObject



657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
# File 'app/models/line_item.rb', line 657

def unit_value_for_commercial_invoice
  is_intra_company_or_electronic_ci_st = delivery&.order&.is_store_transfer? && (delivery&.order&.shipping_address&.is_warehouse_by_distance? || delivery&.electronic_ship_ci_pdf.present? || delivery&.should_have_electronic_commercial_invoice?) # test that we should use minimized customs value when not visible to end customer, that is, an intra-company ST or an ST shipped with electronic CI
  min_unit_value_arr = []
  min_unit_value_arr << discounted_price if discounted_price&.positive? # skip $0 here
  min_unit_value_arr << unit_supplier_purchase_cost if unit_supplier_purchase_cost&.positive? # skip $0 here
  min_unit_value_arr << unit_cogs if unit_cogs&.positive? # skip $0 here
  min_unit_value = min_unit_value_arr.min # now minimun will choose minimum of these three non-zero unit costs
  effective_price = discounted_price
  effective_price = unit_cogs unless effective_price&.positive? # have a fallback
  effective_price = unit_supplier_purchase_cost unless effective_price&.positive? # have a fallback
  effective_price = price unless effective_price&.positive? # have a fallback
  # For intra-company store transfers, use min_unit_value if available, otherwise fall back to effective_price
  # This handles cases where all three values (discounted_price, unit_supplier_purchase_cost, unit_cogs) are nil or not positive
  (is_intra_company_or_electronic_ci_st ? (min_unit_value || effective_price) : effective_price)
end

#unlimited_inventory?Boolean

Returns:

  • (Boolean)


554
555
556
# File 'app/models/line_item.rb', line 554

def unlimited_inventory?
  store_item&.unlimited_inventory?
end

#validate_quantity_limitObject



377
378
379
380
381
382
383
# File 'app/models/line_item.rb', line 377

def validate_quantity_limit
  return unless quantity && ql = store_item&.quantity_limit

  return unless quantity > ql

  errors.add(:quantity, "quantity limit #{ql} exceeded for this item")
end

#voidObject



789
790
791
792
793
794
795
796
797
798
799
800
801
# File 'app/models/line_item.rb', line 789

def void
  puts 'line_item.void'
  if resource.line_items.goods.length == 1
    # here we do an RMA cancel since this is the only time that this is called.
    resource.rma_cancel
  else
    order = resource
    destroy
    # try to mark the credit order as returned
    order.reload
    order.returned
  end
end