Class: LineItem
- Inherits:
-
ApplicationRecord
- Object
- ActiveRecord::Base
- ApplicationRecord
- LineItem
- Includes:
- Models::Auditable, Models::InventoryCommittable, Models::Lineage, Models::LiquidMethods, Models::Reservable, Models::TaxableLine
- Defined in:
- app/models/line_item.rb
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 =
Line item tax classes.
{ g: 'GOODS', svc: 'SERVICE', shp: 'FREIGHT', none: 'NONE' }.freeze
- LINE_ITEM_TAX_CLASSES_SORT_ORDER =
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
Constants included from Models::Schedulable
Models::Schedulable::SIMPLE_FORM_OPTIONS
Instance Attribute Summary collapse
-
#business_unit_id ⇒ Object
readonly
Ledger company account id.
-
#cm_category ⇒ Object
readonly
Cm category.
-
#discounted_price ⇒ Object
readonly
Discounted price.
-
#force_catalog_validation ⇒ Object
Returns the value of attribute force_catalog_validation.
-
#item_id ⇒ Object
readonly
Item id.
-
#item_name ⇒ Object
Returns the value of attribute item_name.
-
#ledger_company_account_id ⇒ Object
readonly
Ledger company account id.
-
#original_delivery_id ⇒ Object
Returns the value of attribute original_delivery_id.
-
#qty_available ⇒ Object
Returns the value of attribute qty_available.
-
#quantity ⇒ Object
readonly
Quantity.
-
#sku_override ⇒ Object
Returns the value of attribute sku_override.
-
#tax_class ⇒ Object
readonly
Tax class.
-
#taxable_amount ⇒ Object
readonly
Tax class.
-
#unit_cogs ⇒ Object
readonly
Unit cogs.
Attributes included from Models::TaxableLine
Belongs to collapse
-
#business_unit ⇒ BusinessUnit
Business unit.
-
#catalog_item ⇒ CatalogItem
Catalog item.
-
#credit_memo ⇒ CreditMemo
Credit memo.
-
#credit_order_line_item ⇒ LineItem
Credit order line item.
-
#credit_rma_item ⇒ RmaItem
Credit rma item.
-
#delivery ⇒ Delivery
Delivery.
-
#direct_store_item ⇒ StoreItem
Direct store item.
-
#invoice ⇒ Invoice
Invoice.
-
#item ⇒ Item
Item.
-
#ledger_company_account ⇒ LedgerCompanyAccount
Ledger company account.
-
#order ⇒ Order
The following makes join easier.
-
#quote ⇒ Quote
Quote.
-
#replacement_rma_item ⇒ RmaItem
Replacement rma item.
-
#resource ⇒ Resource
Resource.
-
#room_configuration ⇒ RoomConfiguration
Room configuration.
-
#serial_number ⇒ SerialNumber
Serial number.
-
#shipping_cost ⇒ ShippingCost
Shipping cost.
Methods included from Models::TaxableLine
#destination_state, #origin_state, #resource_tax_rate
Methods included from Models::Auditable
Has one collapse
-
#preset_job ⇒ PresetJob
Preset job.
-
#purchase_order_item ⇒ PurchaseOrderItem
Purchase order item.
-
#review ⇒ Review
Review.
Has many collapse
-
#discounts ⇒ ActiveRecord::Relation<Discount>
Discounts.
-
#inventory_commits ⇒ ActiveRecord::Relation<InventoryCommit>
Inventory commits.
-
#line_discounts ⇒ ActiveRecord::Relation<LineDiscount>
Line discounts.
-
#rma_items ⇒ ActiveRecord::Relation<RmaItem>
Rma items.
-
#shipment_contents ⇒ ActiveRecord::Relation<ShipmentContent>
Shipment contents.
Methods included from Models::Reservable
Delegated Instance Attributes collapse
-
#category_name ⇒ Object
Alias for Item#category_name.
-
#image_path ⇒ Object
Alias for Item#image_path.
-
#image_url ⇒ Object
Alias for Item#image_url.
-
#is_cork? ⇒ Object
Alias for Item#is_cork?.
-
#is_floor_heating_product? ⇒ Object
Alias for Item#is_floor_heating_product?.
-
#is_legacy_relay? ⇒ Object
Alias for Item#is_legacy_relay?.
-
#is_oj_programmable_tstat? ⇒ Object
Alias for Item#is_oj_programmable_tstat?.
-
#is_publication? ⇒ Object
Alias for Item#is_publication?.
-
#is_relay_panel? ⇒ Object
Alias for Item#is_relay_panel?.
-
#is_reviewable? ⇒ Object
Alias for Item#is_reviewable?.
-
#is_smartstat? ⇒ Object
Alias for Item#is_smartstat?.
-
#is_snow_melting_product? ⇒ Object
Alias for Item#is_snow_melting_product?.
-
#maximum_current ⇒ Object
Alias for Item#maximum_current.
-
#msrp ⇒ Object
Alias for Catalog_item#msrp.
-
#msrp_with_vat ⇒ Object
Alias for Catalog_item#msrp_with_vat.
-
#num_poles ⇒ Object
Alias for Item#num_poles.
-
#oversize? ⇒ Object
Alias for Item#oversize?.
-
#price_with_vat ⇒ Object
Alias for Catalog_item#price_with_vat.
-
#product_line_for_review ⇒ Object
Alias for Item#product_line_for_review.
-
#product_tax_code ⇒ Object
Alias for Item#product_tax_code.
-
#root_catalog_item ⇒ Object
Alias for Catalog_item#root_catalog_item.
-
#sale_price_with_vat ⇒ Object
Alias for Catalog_item#sale_price_with_vat.
-
#ships_via_freight? ⇒ Object
Alias for Item#ships_via_freight?.
-
#thumbnail_url ⇒ Object
Alias for Item#thumbnail_url.
Class Method Summary collapse
-
.accessories ⇒ ActiveRecord::Relation<LineItem>
A relation of LineItems that are accessories.
-
.availability_hash(line_items) ⇒ Object
Availability hash.
-
.bstock ⇒ ActiveRecord::Relation<LineItem>
A relation of LineItems that are bstock.
-
.by_product_category_path ⇒ ActiveRecord::Relation<LineItem>
A relation of LineItems that are by product category path.
-
.by_product_category_url ⇒ ActiveRecord::Relation<LineItem>
A relation of LineItems that are by product category url.
-
.by_product_line_path ⇒ ActiveRecord::Relation<LineItem>
A relation of LineItems that are by product line path.
-
.by_product_line_url ⇒ ActiveRecord::Relation<LineItem>
A relation of LineItems that are by product line url.
-
.cold_leads ⇒ ActiveRecord::Relation<LineItem>
A relation of LineItems that are cold leads.
-
.collect_product_lines(line_items) ⇒ Object
Collect product lines.
-
.compare(source_line_items, target_line_items) ⇒ Object
Compare.
-
.controls ⇒ ActiveRecord::Relation<LineItem>
A relation of LineItems that are controls.
-
.countertop_heaters ⇒ ActiveRecord::Relation<LineItem>
A relation of LineItems that are countertop heaters.
-
.custom_mats ⇒ ActiveRecord::Relation<LineItem>
A relation of LineItems that are custom mats.
-
.dropship ⇒ ActiveRecord::Relation<LineItem>
A relation of LineItems that are dropship.
-
.easystats ⇒ ActiveRecord::Relation<LineItem>
A relation of LineItems that are easystats.
-
.electrical_plan_controls ⇒ ActiveRecord::Relation<LineItem>
A relation of LineItems that are electrical plan controls.
-
.floor_heating_elements ⇒ ActiveRecord::Relation<LineItem>
A relation of LineItems that are floor heating elements.
-
.goods ⇒ ActiveRecord::Relation<LineItem>
A relation of LineItems that are goods.
-
.group_by_category(line_items) ⇒ Object
Group by category.
-
.has_floor_sensor ⇒ ActiveRecord::Relation<LineItem>
A relation of LineItems that are has floor sensor.
-
.heating_elements ⇒ ActiveRecord::Relation<LineItem>
A relation of LineItems that are heating elements.
-
.install_kits ⇒ ActiveRecord::Relation<LineItem>
A relation of LineItems that are install kits.
-
.insulations ⇒ ActiveRecord::Relation<LineItem>
A relation of LineItems that are insulations.
-
.integration_kits ⇒ ActiveRecord::Relation<LineItem>
A relation of LineItems that are integration kits.
-
.inventory_check(container) ⇒ Object
Inventory check.
-
.kits ⇒ ActiveRecord::Relation<LineItem>
A relation of LineItems that are kits.
-
.membranes ⇒ ActiveRecord::Relation<LineItem>
A relation of LineItems that are membranes.
-
.must_be_shipped_insured ⇒ ActiveRecord::Relation<LineItem>
A relation of LineItems that are must be shipped insured.
-
.no_tax_class ⇒ ActiveRecord::Relation<LineItem>
A relation of LineItems that are no tax class.
-
.non_dropship ⇒ ActiveRecord::Relation<LineItem>
A relation of LineItems that are non dropship.
-
.non_shipping ⇒ ActiveRecord::Relation<LineItem>
A relation of LineItems that are non shipping.
-
.oj_programmable_tstats ⇒ ActiveRecord::Relation<LineItem>
A relation of LineItems that are oj programmable tstats.
-
.oj_tstats ⇒ ActiveRecord::Relation<LineItem>
A relation of LineItems that are oj tstats.
-
.order_by_spec ⇒ ActiveRecord::Relation<LineItem>
A relation of LineItems that are order by spec.
-
.power_modules ⇒ ActiveRecord::Relation<LineItem>
A relation of LineItems that are power modules.
-
.powers ⇒ ActiveRecord::Relation<LineItem>
A relation of LineItems that are powers.
-
.product_category_sorted ⇒ ActiveRecord::Relation<LineItem>
A relation of LineItems that are product category sorted.
-
.relay_panels ⇒ ActiveRecord::Relation<LineItem>
A relation of LineItems that are relay panels.
-
.reservable ⇒ ActiveRecord::Relation<LineItem>
A relation of LineItems that are reservable.
-
.rough_in_kits ⇒ ActiveRecord::Relation<LineItem>
A relation of LineItems that are rough in kits.
-
.sensors ⇒ ActiveRecord::Relation<LineItem>
A relation of LineItems that are sensors.
-
.services ⇒ ActiveRecord::Relation<LineItem>
A relation of LineItems that are services.
-
.shipping_only ⇒ ActiveRecord::Relation<LineItem>
A relation of LineItems that are shipping only.
-
.sku_and_aliases_search ⇒ ActiveRecord::Relation<LineItem>
A relation of LineItems that are sku and aliases search.
-
.smartfit_items ⇒ ActiveRecord::Relation<LineItem>
A relation of LineItems that are smartfit items.
-
.smartfix_items ⇒ ActiveRecord::Relation<LineItem>
A relation of LineItems that are smartfix items.
-
.smartguide_items ⇒ ActiveRecord::Relation<LineItem>
A relation of LineItems that are smartguide items.
-
.smartinstall_items ⇒ ActiveRecord::Relation<LineItem>
A relation of LineItems that are smartinstall items.
-
.smartpresets ⇒ ActiveRecord::Relation<LineItem>
A relation of LineItems that are smartpresets.
-
.smartservice_items ⇒ ActiveRecord::Relation<LineItem>
A relation of LineItems that are smartservice items.
-
.smartstats ⇒ ActiveRecord::Relation<LineItem>
A relation of LineItems that are smartstats.
-
.snow_melting_elements ⇒ ActiveRecord::Relation<LineItem>
A relation of LineItems that are snow melting elements.
-
.sort_for_plan ⇒ ActiveRecord::Relation<LineItem>
A relation of LineItems that are sort for plan.
-
.sort_for_room_display(line_items) ⇒ Object
Customer-facing room ordering for the online quote (/ql/) and the per-room breakdown: heating element(s) first, then thermostat(s), then accessories — each bucket sorted by line total high → low (most expensive first).
-
.tempzone_only ⇒ ActiveRecord::Relation<LineItem>
A relation of LineItems that are tempzone only.
-
.tempzone_or_environ_heating_elements ⇒ ActiveRecord::Relation<LineItem>
A relation of LineItems that are tempzone or environ heating elements.
-
.thermostats ⇒ ActiveRecord::Relation<LineItem>
A relation of LineItems that are thermostats.
-
.total_of_collection(line_items) ⇒ Object
Total of collection.
-
.underlayments ⇒ ActiveRecord::Relation<LineItem>
A relation of LineItems that are underlayments.
-
.with_associations ⇒ ActiveRecord::Relation<LineItem>
A relation of LineItems that are with associations.
-
.with_positive_qty ⇒ ActiveRecord::Relation<LineItem>
A relation of LineItems that are with positive qty.
-
.with_product_specification ⇒ ActiveRecord::Relation<LineItem>
A relation of LineItems that are with product specification.
-
.with_reserved_serial_numbers_count ⇒ ActiveRecord::Relation<LineItem>
A relation of LineItems that are with reserved serial numbers count.
-
.with_serial_numbers_count ⇒ ActiveRecord::Relation<LineItem>
A relation of LineItems that are with serial numbers count.
-
.without_children ⇒ ActiveRecord::Relation<LineItem>
A relation of LineItems that are without children.
Instance Method Summary collapse
-
#all_quantities_allocated_to_shipments? ⇒ Boolean
Whether all quantities allocated to shipments.
-
#as_json ⇒ Object
As json.
-
#calculated_tax_class ⇒ Object
Calculated tax class.
-
#children_description(short = false, with_brackets = false) ⇒ Object
Children description.
-
#cogs_markup ⇒ Object
Cogs markup.
-
#company_account_ref ⇒ Object
Company account ref.
-
#copy_discounted_price ⇒ Object
protected
Copy discounted price.
-
#coupon_amount ⇒ Object
Coupon amount.
-
#credit_percentage ⇒ Object
Credit percentage.
-
#currency ⇒ Object
Delegators.
-
#currency_symbol ⇒ Object
Currency symbol.
-
#current_line_cogs ⇒ Object
Current line cogs.
-
#current_line_profit ⇒ Object
Current line profit.
-
#current_line_profit_margin ⇒ Object
To find the margin, divide gross profit by the revenue.
-
#current_line_profit_markup ⇒ Object
To write the markup as a percentage, divide the gross profit by the COGS.
-
#deep_dup ⇒ Object
Deep dup.
-
#detail_url ⇒ Object
Detail url.
-
#discounted_total ⇒ Object
Discounted total.
-
#discounts_total ⇒ Object
Discounts total.
-
#dropship? ⇒ Boolean
Whether dropship.
-
#effective_discount ⇒ Object
Effective discount.
-
#estimated_line_cost ⇒ Object
Estimated line cost.
-
#fulfillment_origin_address ⇒ Object
Fulfillment origin address.
-
#fulfillment_origin_address_id ⇒ Object
Fulfillment origin address id.
-
#get_item_id ⇒ Object
Get item id.
-
#handling_charge ⇒ Object
Handling charge.
-
#has_children? ⇒ Boolean
Whether has children.
-
#has_linked_unvoided_rma_item? ⇒ Boolean
Whether has linked unvoided rma item.
-
#in_stock? ⇒ Boolean
Whether in stock.
-
#is_discounted? ⇒ Boolean
Whether is discounted.
-
#is_fulfillable? ⇒ Boolean
Whether is fulfillable.
-
#is_goods? ⇒ Boolean
Whether is goods.
-
#is_kit? ⇒ Boolean
Whether is kit.
-
#is_linked_to_same_resource_as_delivery ⇒ Object
Is linked to same resource as delivery.
-
#is_not_a_kit ⇒ Object
Is not a kit.
-
#is_onsite_service? ⇒ Boolean
Whether is onsite service.
-
#is_related_smart_service?(sku) ⇒ Boolean
Whether is related smart service.
-
#is_remote_service? ⇒ Boolean
Whether is remote service.
-
#is_service? ⇒ Boolean
Whether is service.
-
#is_shipping? ⇒ Boolean
Whether is shipping.
-
#is_smart_service? ⇒ Boolean
Whether is smart service.
-
#is_smartinstall_service? ⇒ Boolean
Whether is smartinstall service.
-
#is_spare_parts? ⇒ Boolean
Whether is spare parts.
-
#is_tax_unclassed? ⇒ Boolean
Whether is tax unclassed.
-
#item_in_stock_in_store ⇒ Object
protected
Item in stock in store.
-
#kit_component? ⇒ Boolean
A kit-component child line: it lives under an expanded kit parent (the
expand_kitDB trigger inserts these at price 0) and its price is owned by the parent, not editable on its own. -
#ledger_description ⇒ Object
Ledger description.
-
#line_locked? ⇒ Boolean
Whether line locked.
-
#line_total_with_tax ⇒ Object
Line total with tax.
-
#linear_ft_total ⇒ Object
Linear ft total.
-
#linked_to_credit_memo ⇒ Object
Linked to credit memo.
-
#linked_to_invoice ⇒ Object
Linked to invoice.
-
#linked_to_st_order ⇒ Object
Linked to st order.
-
#linked_to_standalone_credit_memo ⇒ Object
Linked to standalone credit memo.
-
#linked_to_standalone_credit_memo_or_invoice ⇒ Object
Linked to standalone credit memo or invoice.
-
#linked_to_standalone_invoice ⇒ Object
Linked to standalone invoice.
-
#max_discount ⇒ Object
Determine the max discount in effect for this line item Only for quote or order.
-
#msrp_total ⇒ Object
Msrp total.
-
#name ⇒ Object
Name.
-
#parent_quantity_factor ⇒ Object
Determines the parent line quantity.
-
#price_editable?(account = nil) ⇒ Boolean
Whether price editable.
-
#price_total ⇒ Object
Price total.
-
#quantities_indicator_visible? ⇒ Boolean
Whether quantities indicator visible.
-
#remaining_quantity_to_allocate_to_shipments ⇒ Object
Remaining quantity to allocate to shipments.
-
#reported_category_name ⇒ Object
Reported category name.
-
#require_serial_number? ⇒ Boolean
Whether require serial number.
-
#set_cogs ⇒ Object
protected
Set cogs.
-
#set_cogs_for_store_transfer ⇒ Object
protected
Set cogs for store transfer.
-
#shipping_name ⇒ Object
Shipping name.
-
#shipping_weight ⇒ Object
Shipping weight.
-
#show_out_of_stock?(item_availability = {}) ⇒ Boolean
Whether show out of stock.
-
#single_origin_or_warehouse_pickup? ⇒ Boolean
Whether single origin or warehouse pickup.
-
#sku ⇒ Object
Sku.
-
#sort_priority ⇒ Object
Sort priority.
-
#sq_ft_total ⇒ Object
Sq ft total.
-
#stock_status ⇒ Object
Stock status.
-
#store_item ⇒ Object
Store item.
-
#supplier_skus ⇒ Object
Supplier skus.
-
#taxable_total ⇒ Object
Taxable total.
-
#taxes_grouped_by_type ⇒ Object
Taxes grouped by type.
-
#total ⇒ Object
Total.
-
#total_shipping_weight ⇒ Object
Total shipping weight.
-
#unit_supplier_purchase_cost ⇒ Object
def total=(value) end.
-
#unit_value_for_commercial_invoice ⇒ Object
Unit value for commercial invoice.
-
#unlimited_inventory? ⇒ Boolean
Whether unlimited inventory.
-
#validate_quantity_limit ⇒ Object
Validate quantity limit.
-
#void ⇒ Object
Void.
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::Schedulable
Methods included from Models::AfterCommittable
Methods included from Models::EventPublishable
Instance Attribute Details
#business_unit_id ⇒ Object (readonly)
Ledger company account id.
Validations:
- Presence ({ if: proc { |li| (li.cm_category == 'Misc') && li.linked_to_standalone_credit_memo } })
159 |
# File 'app/models/line_item.rb', line 159 validates :ledger_company_account_id, :business_unit_id, presence: { if: proc { |li| (li.cm_category == 'Misc') && li.linked_to_standalone_credit_memo } } |
#cm_category ⇒ Object (readonly)
Cm category.
Validations:
- Presence ({ if: proc { |li| li.linked_to_credit_memo || li.linked_to_invoice } })
- Inclusion ({ in: CreditMemo::LINE_ITEM_CATEGORIES.pluck(:name), message: 'is not a valid category', if: :linked_to_credit_memo })
- Inclusion ({ in: Invoice::LINE_ITEM_CATEGORIES.pluck(:name), message: 'is not a valid category', if: :linked_to_invoice })
157 |
# File 'app/models/line_item.rb', line 157 validates :cm_category, presence: { if: proc { |li| li.linked_to_credit_memo || li.linked_to_invoice } } |
#discounted_price ⇒ Object (readonly)
Discounted price.
Validations:
- Numericality ({ equal_to: 0, if: :tax_only?, message: 'must be equal to 0 for tax only lines' })
171 |
# File 'app/models/line_item.rb', line 171 validates :discounted_price, numericality: { equal_to: 0, if: :tax_only?, message: 'must be equal to 0 for tax only lines' } |
#force_catalog_validation ⇒ Object
Returns the value of attribute force_catalog_validation.
261 262 263 |
# File 'app/models/line_item.rb', line 261 def force_catalog_validation @force_catalog_validation end |
#item_id ⇒ Object (readonly)
Item id.
Validations:
- Presence ({ if: proc { |li| (li.cm_category == 'Item') && li.linked_to_standalone_invoice } })
163 |
# File 'app/models/line_item.rb', line 163 validates :item_id, presence: { if: proc { |li| (li.cm_category == 'Item') && li.linked_to_standalone_invoice } } |
#item_name ⇒ Object
Returns the value of attribute item_name.
261 262 263 |
# File 'app/models/line_item.rb', line 261 def item_name @item_name end |
#ledger_company_account_id ⇒ Object (readonly)
Ledger company account id.
Validations:
- Presence ({ if: proc { |li| (li.cm_category == 'Misc') && li.linked_to_standalone_credit_memo } })
- Presence ({ if: proc { |li| (li.cm_category == 'Misc') && li.linked_to_invoice } })
159 |
# File 'app/models/line_item.rb', line 159 validates :ledger_company_account_id, :business_unit_id, presence: { if: proc { |li| (li.cm_category == 'Misc') && li.linked_to_standalone_credit_memo } } |
#original_delivery_id ⇒ Object
Returns the value of attribute original_delivery_id.
261 262 263 |
# File 'app/models/line_item.rb', line 261 def original_delivery_id @original_delivery_id end |
#qty_available ⇒ Object
Returns the value of attribute qty_available.
261 262 263 |
# File 'app/models/line_item.rb', line 261 def qty_available @qty_available end |
#quantity ⇒ Object (readonly)
Quantity.
Validations:
168 |
# File 'app/models/line_item.rb', line 168 validates :quantity, presence: true |
#sku_override ⇒ Object
Returns the value of attribute sku_override.
261 262 263 |
# File 'app/models/line_item.rb', line 261 def sku_override @sku_override end |
#tax_class ⇒ Object (readonly)
Tax class.
Validations:
- Presence ({ if: :linked_to_standalone_credit_memo_or_invoice })
- Inclusion ({ in: ['shp'], message: 'must be set to Freight for freight coupons', if: proc { |li| li.cm_category == 'Coupon (Freight)' } })
161 |
# File 'app/models/line_item.rb', line 161 validates :tax_class, :taxable_amount, presence: { if: :linked_to_standalone_credit_memo_or_invoice } |
#taxable_amount ⇒ Object (readonly)
Tax class.
Validations:
- Presence ({ if: :linked_to_standalone_credit_memo_or_invoice })
- Numericality ({ greater_than_or_equal_to: 0, if: :linked_to_standalone_credit_memo_or_invoice })
161 |
# File 'app/models/line_item.rb', line 161 validates :tax_class, :taxable_amount, presence: { if: :linked_to_standalone_credit_memo_or_invoice } |
#unit_cogs ⇒ Object (readonly)
Unit cogs.
Validations:
- Presence ({ if: proc { |li| (li.cm_category == 'Item') && li.linked_to_invoice } })
165 |
# File 'app/models/line_item.rb', line 165 validates :unit_cogs, presence: { if: proc { |li| (li.cm_category == 'Item') && li.linked_to_invoice } } |
Class Method Details
.accessories ⇒ ActiveRecord::Relation<LineItem>
A relation of LineItems that are accessories. Active Record Scope
195 |
# File 'app/models/line_item.rb', line 195 scope :accessories, -> { joins(:item).merge(Item.accessories) } |
.availability_hash(line_items) ⇒ Object
Availability hash.
681 682 683 684 685 686 687 688 689 690 691 692 |
# File 'app/models/line_item.rb', line 681 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 |
.bstock ⇒ ActiveRecord::Relation<LineItem>
A relation of LineItems that are bstock. Active Record Scope
249 |
# File 'app/models/line_item.rb', line 249 scope :bstock, -> { joins(:item).where(items: { condition: 'refurbished' }) } |
.by_product_category_path ⇒ ActiveRecord::Relation<LineItem>
A relation of LineItems that are by product category path. Active Record Scope
232 |
# File 'app/models/line_item.rb', line 232 scope :by_product_category_path, ->(slug_path) { joins(:item).merge(Item.by_product_category_path(slug_path)) } |
.by_product_category_url ⇒ ActiveRecord::Relation<LineItem>
A relation of LineItems that are by product category url. Active Record Scope
228 |
# File 'app/models/line_item.rb', line 228 scope :by_product_category_url, ->(url) { joins(:item).merge(Item.by_product_category_url(url)) } |
.by_product_line_path ⇒ ActiveRecord::Relation<LineItem>
A relation of LineItems that are by product line path. Active Record Scope
231 |
# File 'app/models/line_item.rb', line 231 scope :by_product_line_path, ->(slug_path) { joins(:item).merge(Item.by_product_line_path(slug_path)) } |
.by_product_line_url ⇒ ActiveRecord::Relation<LineItem>
A relation of LineItems that are by product line url. Active Record Scope
229 |
# File 'app/models/line_item.rb', line 229 scope :by_product_line_url, ->(url) { joins(:item).merge(Item.by_product_line_url(url)) } |
.cold_leads ⇒ ActiveRecord::Relation<LineItem>
A relation of LineItems that are cold leads. Active Record Scope
214 |
# File 'app/models/line_item.rb', line 214 scope :cold_leads, -> { joins(:item).merge(Item.cold_leads) } |
.collect_product_lines(line_items) ⇒ Object
Collect product lines.
302 303 304 |
# File 'app/models/line_item.rb', line 302 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
Compare.
477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 |
# File 'app/models/line_item.rb', line 477 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 |
.controls ⇒ ActiveRecord::Relation<LineItem>
A relation of LineItems that are controls. Active Record Scope
196 |
# File 'app/models/line_item.rb', line 196 scope :controls, -> { joins(:item).merge(Item.controls) } |
.countertop_heaters ⇒ ActiveRecord::Relation<LineItem>
A relation of LineItems that are countertop heaters. Active Record Scope
227 |
# File 'app/models/line_item.rb', line 227 scope :countertop_heaters, -> { joins(:item).merge(Item.countertop_heaters) } |
.custom_mats ⇒ ActiveRecord::Relation<LineItem>
A relation of LineItems that are custom mats. Active Record Scope
226 |
# File 'app/models/line_item.rb', line 226 scope :custom_mats, -> { joins(:item).merge(Item.custom_mats) } |
.dropship ⇒ ActiveRecord::Relation<LineItem>
A relation of LineItems that are dropship. Active Record Scope
208 |
# File 'app/models/line_item.rb', line 208 scope :dropship, -> { joins(:item).merge(Item.dropships) } |
.easystats ⇒ ActiveRecord::Relation<LineItem>
A relation of LineItems that are easystats. Active Record Scope
204 |
# File 'app/models/line_item.rb', line 204 scope :easystats, -> { joins(:item).merge(Item.easystats) } |
.electrical_plan_controls ⇒ ActiveRecord::Relation<LineItem>
A relation of LineItems that are electrical plan controls. Active Record Scope
198 |
# File 'app/models/line_item.rb', line 198 scope :electrical_plan_controls, -> { joins(:item).merge(Item.electrical_plan_controls) } |
.floor_heating_elements ⇒ ActiveRecord::Relation<LineItem>
A relation of LineItems that are floor heating elements. Active Record Scope
193 |
# File 'app/models/line_item.rb', line 193 scope :floor_heating_elements, -> { joins(:item).merge(Item.floor_heating_elements) } |
.goods ⇒ ActiveRecord::Relation<LineItem>
A relation of LineItems that are goods. Active Record Scope
217 |
# File 'app/models/line_item.rb', line 217 scope :goods, -> { where(tax_class: 'g') } |
.group_by_category(line_items) ⇒ Object
Group by category.
382 383 384 385 386 387 388 389 390 391 |
# File 'app/models/line_item.rb', line 382 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_sensor ⇒ ActiveRecord::Relation<LineItem>
A relation of LineItems that are has floor sensor. Active Record Scope
220 |
# File 'app/models/line_item.rb', line 220 scope :has_floor_sensor, -> { joins(:item).merge(Item.has_floor_sensor) } |
.heating_elements ⇒ ActiveRecord::Relation<LineItem>
A relation of LineItems that are heating elements. Active Record Scope
190 |
# File 'app/models/line_item.rb', line 190 scope :heating_elements, -> { joins(:item).merge(Item.heating_elements) } |
.install_kits ⇒ ActiveRecord::Relation<LineItem>
A relation of LineItems that are install kits. Active Record Scope
223 |
# File 'app/models/line_item.rb', line 223 scope :install_kits, -> { joins(:item).merge(Item.install_kits) } |
.insulations ⇒ ActiveRecord::Relation<LineItem>
A relation of LineItems that are insulations. Active Record Scope
224 |
# File 'app/models/line_item.rb', line 224 scope :insulations, -> { joins(:item).merge(Item.insulations) } |
.integration_kits ⇒ ActiveRecord::Relation<LineItem>
A relation of LineItems that are integration kits. Active Record Scope
206 |
# File 'app/models/line_item.rb', line 206 scope :integration_kits, -> { joins(:item).merge(Item.integration_kits) } |
.inventory_check(container) ⇒ Object
Inventory check.
316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 |
# File 'app/models/line_item.rb', line 316 def self.inventory_check(container) lines = container.line_items.non_shipping .includes(:item, :direct_store_item, :inventory_commits, { catalog_item: :store_item }) # Per-line check: handles dropship, unlimited inventory, fully-committed lines, negative qty. return :none unless lines.all?(&:is_fulfillable?) # Aggregate check: multiple non-shipping lines targeting the same SKU — whether duplicate # standalone lines or kit component children overlapping with standalone lines — must not # together exceed the shared qty_available pool. The per-line check misses this because # each line independently sees the full pool without deducting the other lines' demand. # # Cache from_store_id once: all lines share the same resource (container). This mirrors # the stock_status StoreItem routing (line_item.rb#stock_status) without an association # load per line. from_store_id = container.respond_to?(:from_store_id) ? container.from_store_id : nil # Key demand and store_items by store_item ID so that all lines drawing from the same # physical stock pool are always aggregated together, regardless of which catalog_item # they arrived through. This also handles from_store_id and cross-catalog edge cases. uncommitted_demand = Hash.new(0) store_item_by_id = {} lines.each do |li| next unless li.catalog_item_id next if li.quantity.negative? # Route through the per-line helper so that RoomConfiguration resources (which always # return false from single_origin_or_warehouse_pickup?) are handled identically to the # per-line check. In practice, container.line_items only returns Order-resource lines, # but this keeps the logic consistent with stock_status. next if li.dropship? && !li.single_origin_or_warehouse_pickup? next if li.unlimited_inventory? committed_quantity = li.inventory_commits.sum(&:quantity) # Already fully reserved — committed units have already reduced qty_available globally. next if committed_quantity >= li.quantity # Add only the truly uncommitted portion. Committed units are already subtracted from # qty_available globally, so adding the full quantity would double-count the committed # share against the same pool it was already deducted from. uncommitted_qty = li.quantity - committed_quantity # Mirror stock_status's StoreItem routing so the aggregate compares against the correct # store's pool. For store-transfer orders (from_store_id set), this fires one SQL query # per line — consistent with the existing per-line behavior in stock_status. si = if from_store_id StoreItem.where(store_id: from_store_id, item_id: li.item_id, location: 'AVAILABLE').first else li.store_item end next unless si uncommitted_demand[si.id] += uncommitted_qty store_item_by_id[si.id] ||= si end store_item_by_id.each do |si_id, si| return :none if si.qty_available < uncommitted_demand[si_id] end :ok end |
.kits ⇒ ActiveRecord::Relation<LineItem>
A relation of LineItems that are kits. Active Record Scope
243 |
# File 'app/models/line_item.rb', line 243 scope :kits, -> { joins(:item).merge(Item.kits) } |
.membranes ⇒ ActiveRecord::Relation<LineItem>
A relation of LineItems that are membranes. Active Record Scope
225 |
# File 'app/models/line_item.rb', line 225 scope :membranes, -> { joins(:item).merge(Item.membranes) } |
.must_be_shipped_insured ⇒ ActiveRecord::Relation<LineItem>
A relation of LineItems that are must be shipped insured. Active Record Scope
233 |
# File 'app/models/line_item.rb', line 233 scope :must_be_shipped_insured, -> { with_associations.where('store_items.must_be_shipped_insured IS TRUE') } |
.no_tax_class ⇒ ActiveRecord::Relation<LineItem>
A relation of LineItems that are no tax class. Active Record Scope
219 |
# File 'app/models/line_item.rb', line 219 scope :no_tax_class, -> { where(tax_class: 'none') } |
.non_dropship ⇒ ActiveRecord::Relation<LineItem>
A relation of LineItems that are non dropship. Active Record Scope
209 |
# File 'app/models/line_item.rb', line 209 scope :non_dropship, -> { joins(:item).merge(Item.non_dropships) } |
.non_shipping ⇒ ActiveRecord::Relation<LineItem>
A relation of LineItems that are non shipping. Active Record Scope
215 |
# File 'app/models/line_item.rb', line 215 scope :non_shipping, -> { where(tax_class: %w[g svc none]) } |
.oj_programmable_tstats ⇒ ActiveRecord::Relation<LineItem>
A relation of LineItems that are oj programmable tstats. Active Record Scope
202 |
# File 'app/models/line_item.rb', line 202 scope :oj_programmable_tstats, -> { joins(:item).merge(Item.oj_programmable_tstats) } |
.oj_tstats ⇒ ActiveRecord::Relation<LineItem>
A relation of LineItems that are oj tstats. Active Record Scope
201 |
# File 'app/models/line_item.rb', line 201 scope :oj_tstats, -> { joins(:item).merge(Item.oj_tstats) } |
.order_by_spec ⇒ ActiveRecord::Relation<LineItem>
A relation of LineItems that are order by spec. Active Record Scope
192 |
# File 'app/models/line_item.rb', line 192 scope :order_by_spec, ->(spec, datatype = 'varchar', direction = 'asc') { joins(:item).merge(Item.order_by_spec(spec, datatype, direction)) } |
.power_modules ⇒ ActiveRecord::Relation<LineItem>
A relation of LineItems that are power modules. Active Record Scope
205 |
# File 'app/models/line_item.rb', line 205 scope :power_modules, -> { joins(:item).merge(Item.power_modules) } |
.powers ⇒ ActiveRecord::Relation<LineItem>
A relation of LineItems that are powers. Active Record Scope
197 |
# File 'app/models/line_item.rb', line 197 scope :powers, -> { joins(:item).merge(Item.powers) } |
.product_category_sorted ⇒ ActiveRecord::Relation<LineItem>
A relation of LineItems that are product category sorted. Active Record Scope
188 |
# File 'app/models/line_item.rb', line 188 scope :product_category_sorted, -> { includes(item: :product_category).joins(item: :product_category).order(ProductCategory[:priority]) } |
.relay_panels ⇒ ActiveRecord::Relation<LineItem>
A relation of LineItems that are relay panels. Active Record Scope
211 |
# File 'app/models/line_item.rb', line 211 scope :relay_panels, -> { joins(:item).merge(Item.relay_panels) } |
.reservable ⇒ ActiveRecord::Relation<LineItem>
A relation of LineItems that are reservable. Active Record Scope
221 |
# File 'app/models/line_item.rb', line 221 scope :reservable, -> { joins(:item).merge(Item.reservable) } |
.rough_in_kits ⇒ ActiveRecord::Relation<LineItem>
A relation of LineItems that are rough in kits. Active Record Scope
222 |
# File 'app/models/line_item.rb', line 222 scope :rough_in_kits, -> { joins(:item).merge(Item.rough_in_kits) } |
.sensors ⇒ ActiveRecord::Relation<LineItem>
A relation of LineItems that are sensors. Active Record Scope
207 |
# File 'app/models/line_item.rb', line 207 scope :sensors, -> { joins(:item).merge(Item.sensors) } |
.services ⇒ ActiveRecord::Relation<LineItem>
A relation of LineItems that are services. Active Record Scope
218 |
# File 'app/models/line_item.rb', line 218 scope :services, -> { where(tax_class: 'svc') } |
.shipping_only ⇒ ActiveRecord::Relation<LineItem>
A relation of LineItems that are shipping only. Active Record Scope
216 |
# File 'app/models/line_item.rb', line 216 scope :shipping_only, -> { where(tax_class: 'shp') } |
.sku_and_aliases_search ⇒ ActiveRecord::Relation<LineItem>
A relation of LineItems that are sku and aliases search. Active Record Scope
250 |
# File 'app/models/line_item.rb', line 250 scope :sku_and_aliases_search, ->(sku) { joins(:item).merge(Item.sku_and_aliases_search(sku)) } |
.smartfit_items ⇒ ActiveRecord::Relation<LineItem>
A relation of LineItems that are smartfit items. Active Record Scope
238 |
# File 'app/models/line_item.rb', line 238 scope :smartfit_items, -> { by_product_line_path(LtreePaths::PL_SERVICES_SMARTFIT) } |
.smartfix_items ⇒ ActiveRecord::Relation<LineItem>
A relation of LineItems that are smartfix items. Active Record Scope
240 |
# File 'app/models/line_item.rb', line 240 scope :smartfix_items, -> { by_product_line_path(LtreePaths::PL_SERVICES_SMARTFIX) } |
.smartguide_items ⇒ ActiveRecord::Relation<LineItem>
A relation of LineItems that are smartguide items. Active Record Scope
241 |
# File 'app/models/line_item.rb', line 241 scope :smartguide_items, -> { by_product_line_path(LtreePaths::PL_SERVICES_SMARTGUIDE) } |
.smartinstall_items ⇒ ActiveRecord::Relation<LineItem>
A relation of LineItems that are smartinstall items. Active Record Scope
239 |
# File 'app/models/line_item.rb', line 239 scope :smartinstall_items, -> { by_product_line_path(LtreePaths::PL_SERVICES_SMARTINSTALL) } |
.smartpresets ⇒ ActiveRecord::Relation<LineItem>
A relation of LineItems that are smartpresets. Active Record Scope
213 |
# File 'app/models/line_item.rb', line 213 scope :smartpresets, -> { joins(:item).merge(Item.smartpresets) } |
.smartservice_items ⇒ ActiveRecord::Relation<LineItem>
A relation of LineItems that are smartservice items. Active Record Scope
242 |
# File 'app/models/line_item.rb', line 242 scope :smartservice_items, -> { joins(:item).merge(Item.smart_services) } |
.smartstats ⇒ ActiveRecord::Relation<LineItem>
A relation of LineItems that are smartstats. Active Record Scope
203 |
# File 'app/models/line_item.rb', line 203 scope :smartstats, -> { joins(:item).merge(Item.smartstats) } |
.snow_melting_elements ⇒ ActiveRecord::Relation<LineItem>
A relation of LineItems that are snow melting elements. Active Record Scope
194 |
# File 'app/models/line_item.rb', line 194 scope :snow_melting_elements, -> { joins(:item).merge(Item.snow_melting_elements) } |
.sort_for_plan ⇒ ActiveRecord::Relation<LineItem>
A relation of LineItems that are sort for plan. Active Record Scope
199 |
# File 'app/models/line_item.rb', line 199 scope :sort_for_plan, -> { order_by_spec('amps', 'decimal', 'asc') } |
.sort_for_room_display(line_items) ⇒ Object
Customer-facing room ordering for the online quote (/ql/) and the per-room
breakdown: heating element(s) first, then thermostat(s), then accessories —
each bucket sorted by line total high → low (most expensive first). Items
with no known category fall to the accessories bucket. Pure in-memory sort
on an already-loaded collection.
400 401 402 403 404 405 406 407 408 409 |
# File 'app/models/line_item.rb', line 400 def self.sort_for_room_display(line_items) line_items.to_a.each_with_index.sort_by do |li, idx| item = li.item || li.catalog_item&.item bucket = if item&.is_heating_element? then 0 elsif item&.is_thermostat? then 1 else 2 end [bucket, -(li.total || 0).to_f, idx] # idx keeps the sort stable on ties end.map(&:first) end |
.tempzone_only ⇒ ActiveRecord::Relation<LineItem>
A relation of LineItems that are tempzone only. Active Record Scope
200 |
# File 'app/models/line_item.rb', line 200 scope :tempzone_only, -> { joins(:item).merge(Item.tempzones) } |
.tempzone_or_environ_heating_elements ⇒ ActiveRecord::Relation<LineItem>
A relation of LineItems that are tempzone or environ heating elements. Active Record Scope
234 235 236 237 |
# File 'app/models/line_item.rb', line 234 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))) } |
.thermostats ⇒ ActiveRecord::Relation<LineItem>
A relation of LineItems that are thermostats. Active Record Scope
210 |
# File 'app/models/line_item.rb', line 210 scope :thermostats, -> { joins(:item).merge(Item.thermostats) } |
.total_of_collection(line_items) ⇒ Object
Total of collection.
309 310 311 |
# File 'app/models/line_item.rb', line 309 def self.total_of_collection(line_items) line_items.to_a.sum(&:total).round(2) end |
.underlayments ⇒ ActiveRecord::Relation<LineItem>
A relation of LineItems that are underlayments. Active Record Scope
212 |
# File 'app/models/line_item.rb', line 212 scope :underlayments, -> { joins(:item).merge(Item.underlayments) } |
.with_associations ⇒ ActiveRecord::Relation<LineItem>
A relation of LineItems that are with associations. Active Record Scope
189 |
# File 'app/models/line_item.rb', line 189 scope :with_associations, -> { includes(:item, catalog_item: { store_item: :item }).references(:item, catalog_item: { store_item: :item }) } |
.with_positive_qty ⇒ ActiveRecord::Relation<LineItem>
A relation of LineItems that are with positive qty. Active Record Scope
248 |
# File 'app/models/line_item.rb', line 248 scope :with_positive_qty, -> { where('quantity > 0') } |
.with_product_specification ⇒ ActiveRecord::Relation<LineItem>
A relation of LineItems that are with product specification. Active Record Scope
191 |
# File 'app/models/line_item.rb', line 191 scope :with_product_specification, ->(token, value, grouping = nil) { joins(:item).merge(Item.with_product_specification(token, value, grouping)) } |
.with_reserved_serial_numbers_count ⇒ ActiveRecord::Relation<LineItem>
A relation of LineItems that are with reserved serial numbers count. Active Record Scope
247 |
# File 'app/models/line_item.rb', line 247 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_count ⇒ ActiveRecord::Relation<LineItem>
A relation of LineItems that are with serial numbers count. Active Record Scope
246 |
# File 'app/models/line_item.rb', line 246 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_children ⇒ ActiveRecord::Relation<LineItem>
A relation of LineItems that are without children. Active Record Scope
244 |
# File 'app/models/line_item.rb', line 244 scope :without_children, -> { where(children_count: [nil, 0]) } |
Instance Method Details
#all_quantities_allocated_to_shipments? ⇒ Boolean
Whether all quantities allocated to shipments.
509 510 511 |
# File 'app/models/line_item.rb', line 509 def all_quantities_allocated_to_shipments? remaining_quantity_to_allocate_to_shipments == 0 end |
#as_json ⇒ Object
As json.
1072 1073 1074 |
# File 'app/models/line_item.rb', line 1072 def as_json super(methods: %i[name sku get_item_id]) end |
#business_unit ⇒ BusinessUnit
Business unit.
132 |
# File 'app/models/line_item.rb', line 132 belongs_to :business_unit, optional: true |
#calculated_tax_class ⇒ Object
Calculated tax class.
565 566 567 568 569 |
# File 'app/models/line_item.rb', line 565 def calculated_tax_class return tax_class if tax_class item.nil? ? tax_class : item.tax_class end |
#catalog_item ⇒ CatalogItem
Catalog item.
101 |
# File 'app/models/line_item.rb', line 101 belongs_to :catalog_item, inverse_of: :line_items, optional: true |
#category_name ⇒ Object
Alias for Item#category_name
265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 |
# File 'app/models/line_item.rb', line 265 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
Children description.
787 788 789 790 791 792 793 794 795 796 797 |
# File 'app/models/line_item.rb', line 787 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.map { |child| "#{child.quantity} x #{child.item.sku}" }.to_sentence(last_word_connector: ' and ') contents = "(#{contents})" if with_brackets end contents end |
#cogs_markup ⇒ Object
Cogs markup.
934 935 936 |
# File 'app/models/line_item.rb', line 934 def cogs_markup 1.1 # 10% markup for packaging and unapplied landed cost end |
#company_account_ref ⇒ Object
Company account ref.
559 560 561 |
# File 'app/models/line_item.rb', line 559 def company_account_ref ledger_company_account&.identifier end |
#copy_discounted_price ⇒ Object (protected)
Copy discounted price.
1170 1171 1172 |
# File 'app/models/line_item.rb', line 1170 def copy_discounted_price self.price = discounted_price end |
#coupon_amount ⇒ Object
Coupon amount.
503 504 505 |
# File 'app/models/line_item.rb', line 503 def coupon_amount line_discounts.sum(:amount) end |
#credit_memo ⇒ CreditMemo
Credit memo.
111 |
# File 'app/models/line_item.rb', line 111 belongs_to :credit_memo, -> { joins(:line_items).where(line_items: { resource_type: 'CreditMemo' }) }, foreign_key: :resource_id, optional: true |
#credit_order_line_item ⇒ LineItem
Credit order line item.
126 |
# File 'app/models/line_item.rb', line 126 belongs_to :credit_order_line_item, class_name: 'LineItem', optional: true |
#credit_percentage ⇒ Object
Credit percentage.
579 580 581 582 583 584 585 586 587 |
# File 'app/models/line_item.rb', line 579 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_item ⇒ RmaItem
Credit rma item.
122 |
# File 'app/models/line_item.rb', line 122 belongs_to :credit_rma_item, class_name: 'RmaItem', optional: true |
#currency ⇒ Object
Delegators
497 498 499 |
# File 'app/models/line_item.rb', line 497 def currency resource.try(:currency) end |
#currency_symbol ⇒ Object
Currency symbol.
801 802 803 |
# File 'app/models/line_item.rb', line 801 def currency_symbol (resource || delivery).currency_symbol end |
#current_line_cogs ⇒ Object
Current line cogs.
917 918 919 920 921 922 923 924 925 926 927 928 929 930 |
# File 'app/models/line_item.rb', line 917 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_profit ⇒ Object
Current line profit.
950 951 952 953 954 955 956 |
# File 'app/models/line_item.rb', line 950 def current_line_profit if estimated_line_cost && (dt = discounted_total) dt - estimated_line_cost else BigDecimal('0.00') end end |
#current_line_profit_margin ⇒ Object
To find the margin, divide gross profit by the revenue.
968 969 970 971 972 973 974 975 |
# File 'app/models/line_item.rb', line 968 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_markup ⇒ Object
To write the markup as a percentage, divide the gross profit by the COGS.
959 960 961 962 963 964 965 |
# File 'app/models/line_item.rb', line 959 def current_line_profit_markup cogs = estimated_line_cost gross_profit = current_line_profit return 0.0 if cogs == 0 gross_profit / cogs end |
#deep_dup ⇒ Object
Deep dup.
89 90 91 |
# File 'app/models/line_item.rb', line 89 def deep_dup deep_clone(include: %i[serial_numbers line_discounts]) end |
#delivery ⇒ Delivery
Delivery.
116 |
# File 'app/models/line_item.rb', line 116 belongs_to :delivery, inverse_of: :line_items, optional: true |
#detail_url ⇒ Object
Detail url.
1158 1159 1160 1161 1162 1163 1164 |
# File 'app/models/line_item.rb', line 1158 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_item ⇒ StoreItem
Direct store item.
114 |
# File 'app/models/line_item.rb', line 114 belongs_to :direct_store_item, class_name: 'StoreItem', foreign_key: :store_item_id, optional: true |
#discounted_total ⇒ Object
Discounted total.
807 808 809 810 811 812 813 814 815 816 |
# File 'app/models/line_item.rb', line 807 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.sum(&:amount) end |
#discounts ⇒ ActiveRecord::Relation<Discount>
Discounts.
150 |
# File 'app/models/line_item.rb', line 150 has_many :discounts, through: :line_discounts |
#discounts_total ⇒ Object
Discounts total.
828 829 830 |
# File 'app/models/line_item.rb', line 828 def discounts_total price_total - discounted_total end |
#dropship? ⇒ Boolean
Whether dropship.
655 656 657 |
# File 'app/models/line_item.rb', line 655 def dropship? item.present? && item.dropship? end |
#effective_discount ⇒ Object
Effective discount.
864 865 866 867 |
# File 'app/models/line_item.rb', line 864 def effective_discount d = price_total - discounted_total price_total.positive? && d.positive? ? ((d * 100) / price_total).to_i : 0 end |
#estimated_line_cost ⇒ Object
Estimated line cost.
940 941 942 943 944 945 946 |
# File 'app/models/line_item.rb', line 940 def estimated_line_cost if is_shipping? price else current_line_cogs end end |
#fulfillment_origin_address ⇒ Object
Fulfillment origin address.
1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 |
# File 'app/models/line_item.rb', line 1030 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_id ⇒ Object
Fulfillment origin address id.
1024 1025 1026 |
# File 'app/models/line_item.rb', line 1024 def fulfillment_origin_address_id fulfillment_origin_address&.id end |
#get_item_id ⇒ Object
Get item id.
649 650 651 |
# File 'app/models/line_item.rb', line 649 def get_item_id item&.id end |
#handling_charge ⇒ Object
Handling charge.
992 993 994 |
# File 'app/models/line_item.rb', line 992 def handling_charge catalog_item&.store_item&.handling_charge end |
#has_children? ⇒ Boolean
Whether has children.
768 769 770 |
# File 'app/models/line_item.rb', line 768 def has_children? children_count.present? && (children_count > 0) end |
#has_linked_unvoided_rma_item? ⇒ Boolean
Whether has linked unvoided rma item.
553 554 555 |
# File 'app/models/line_item.rb', line 553 def has_linked_unvoided_rma_item? credit_rma_item.present? && !credit_rma_item.voided? end |
#image_path ⇒ Object
Alias for Item#image_path
265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 |
# File 'app/models/line_item.rb', line 265 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_url ⇒ Object
Alias for Item#image_url
265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 |
# File 'app/models/line_item.rb', line 265 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
Whether in stock.
696 697 698 699 700 701 702 |
# File 'app/models/line_item.rb', line 696 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_commits ⇒ ActiveRecord::Relation<InventoryCommit>
Inventory commits.
152 |
# File 'app/models/line_item.rb', line 152 has_many :inventory_commits, dependent: :destroy |
#invoice ⇒ Invoice
Invoice.
109 |
# File 'app/models/line_item.rb', line 109 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?
265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 |
# File 'app/models/line_item.rb', line 265 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
Whether is discounted.
871 872 873 |
# File 'app/models/line_item.rb', line 871 def is_discounted? effective_discount > 0 end |
#is_floor_heating_product? ⇒ Object
Alias for Item#is_floor_heating_product?
265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 |
# File 'app/models/line_item.rb', line 265 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
Whether is fulfillable.
756 757 758 |
# File 'app/models/line_item.rb', line 756 def is_fulfillable? %i[ok low na].include?(stock_status) end |
#is_goods? ⇒ Boolean
Whether is goods.
1078 1079 1080 |
# File 'app/models/line_item.rb', line 1078 def is_goods? tax_class.present? ? tax_class == 'g' : item&.is_goods?&.to_b end |
#is_kit? ⇒ Boolean
Whether is kit.
539 540 541 |
# File 'app/models/line_item.rb', line 539 def is_kit? item&.is_kit? end |
#is_legacy_relay? ⇒ Object
Alias for Item#is_legacy_relay?
265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 |
# File 'app/models/line_item.rb', line 265 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_delivery ⇒ Object
Is linked to same resource as delivery.
531 532 533 534 535 |
# File 'app/models/line_item.rb', line 531 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_kit ⇒ Object
Is not a kit.
545 546 547 548 549 |
# File 'app/models/line_item.rb', line 545 def is_not_a_kit return unless is_kit? errors.add(: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?
265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 |
# File 'app/models/line_item.rb', line 265 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
Whether is onsite service.
1102 1103 1104 |
# File 'app/models/line_item.rb', line 1102 def is_onsite_service? is_service? && item.sku.include?('ONSITE') end |
#is_publication? ⇒ Object
Alias for Item#is_publication?
265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 |
# File 'app/models/line_item.rb', line 265 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_related_smart_service?(sku) ⇒ Boolean
Whether is related smart service.
1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 |
# File 'app/models/line_item.rb', line 1133 def (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?
265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 |
# File 'app/models/line_item.rb', line 265 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
Whether is remote service.
1096 1097 1098 |
# File 'app/models/line_item.rb', line 1096 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?
265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 |
# File 'app/models/line_item.rb', line 265 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
Whether is service.
1090 1091 1092 |
# File 'app/models/line_item.rb', line 1090 def is_service? tax_class.present? ? tax_class == 'svc' : item&.is_service?&.to_b end |
#is_shipping? ⇒ Boolean
Whether is shipping.
1114 1115 1116 |
# File 'app/models/line_item.rb', line 1114 def is_shipping? tax_class.present? ? tax_class == 'shp' : item&.is_shipping?&.to_b end |
#is_smart_service? ⇒ Boolean
Whether is smart service.
1126 1127 1128 |
# File 'app/models/line_item.rb', line 1126 def is_smart_service? item&.pl_descendant_of_path?(LtreePaths::PL_SERVICES) end |
#is_smartinstall_service? ⇒ Boolean
Whether is smartinstall service.
1120 1121 1122 |
# File 'app/models/line_item.rb', line 1120 def is_smartinstall_service? item&.pl_descendant_of_path?(LtreePaths::PL_SERVICES_SMARTINSTALL) end |
#is_smartstat? ⇒ Object
Alias for Item#is_smartstat?
265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 |
# File 'app/models/line_item.rb', line 265 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?
265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 |
# File 'app/models/line_item.rb', line 265 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
Whether is spare parts.
1084 1085 1086 |
# File 'app/models/line_item.rb', line 1084 def is_spare_parts? item&.is_spare_parts?&.to_b end |
#is_tax_unclassed? ⇒ Boolean
Whether is tax unclassed.
1108 1109 1110 |
# File 'app/models/line_item.rb', line 1108 def is_tax_unclassed? tax_class == 'none' end |
#item_in_stock_in_store ⇒ Object (protected)
Item in stock in store.
1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 |
# File 'app/models/line_item.rb', line 1176 def item_in_stock_in_store return unless get_item_id && resource&.store_id store_item = StoreItem.available.where(item_id: get_item_id, store_id: resource.store_id).first if store_item.nil? errors.add(:item_id, 'is not available in selected store') elsif quantity && (store_item.qty_available < quantity) errors.add(:quantity, 'is more than quantity available in selected store') end end |
#kit_component? ⇒ Boolean
A kit-component child line: it lives under an expanded kit parent (the
expand_kit DB trigger inserts these at price 0) and its price is owned by
the parent, not editable on its own. On line items, lineage is only ever
kit expansion, so a present parent_id is the invariant. See
#enforce_zero_price_on_kit_component for the save-time enforcement.
779 780 781 |
# File 'app/models/line_item.rb', line 779 def kit_component? parent_id.present? end |
#ledger_company_account ⇒ LedgerCompanyAccount
Ledger company account.
130 |
# File 'app/models/line_item.rb', line 130 belongs_to :ledger_company_account, optional: true |
#ledger_description ⇒ Object
Ledger description.
639 640 641 642 643 644 645 |
# File 'app/models/line_item.rb', line 639 def ledger_description if cm_category.nil? || ((cm_category == 'Item') && sku.present?) sku else "#{cm_category} #{description}" end end |
#line_discounts ⇒ ActiveRecord::Relation<LineDiscount>
Line discounts.
148 |
# File 'app/models/line_item.rb', line 148 has_many :line_discounts, dependent: :destroy, inverse_of: :line_item, autosave: true |
#line_locked? ⇒ Boolean
Whether line locked.
661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 |
# File 'app/models/line_item.rb', line 661 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.respond_to?(:room_configuration_ids) && resource.room_configuration_ids.exclude?(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_tax ⇒ Object
Line total with tax.
820 821 822 823 824 |
# File 'app/models/line_item.rb', line 820 def line_total_with_tax discounted_total + (tax_total || 0.0) rescue StandardError 0 end |
#linear_ft_total ⇒ Object
Linear ft total.
858 859 860 |
# File 'app/models/line_item.rb', line 858 def linear_ft_total quantity * (item.length.to_f / 12) end |
#linked_to_credit_memo ⇒ Object
Linked to credit memo.
573 574 575 |
# File 'app/models/line_item.rb', line 573 def linked_to_credit_memo resource_type == 'CreditMemo' end |
#linked_to_invoice ⇒ Object
Linked to invoice.
591 592 593 |
# File 'app/models/line_item.rb', line 591 def linked_to_invoice resource_type == 'Invoice' end |
#linked_to_st_order ⇒ Object
Linked to st order.
615 616 617 |
# File 'app/models/line_item.rb', line 615 def linked_to_st_order (resource_type == 'Order') && (resource.try(:order_type) == 'ST') end |
#linked_to_standalone_credit_memo ⇒ Object
Linked to standalone credit memo.
597 598 599 |
# File 'app/models/line_item.rb', line 597 def linked_to_standalone_credit_memo (resource_type == 'CreditMemo') && (resource.try(:category) == 'standalone') end |
#linked_to_standalone_credit_memo_or_invoice ⇒ Object
Linked to standalone credit memo or invoice.
609 610 611 |
# File 'app/models/line_item.rb', line 609 def linked_to_standalone_credit_memo_or_invoice linked_to_standalone_credit_memo || linked_to_standalone_invoice end |
#linked_to_standalone_invoice ⇒ Object
Linked to standalone invoice.
603 604 605 |
# File 'app/models/line_item.rb', line 603 def linked_to_standalone_invoice (resource_type == 'Invoice') && [Invoice::MI].include?(resource.try(:invoice_type)) end |
#max_discount ⇒ Object
Determine the max discount in effect for this line item
Only for quote or order
413 414 415 416 417 418 419 420 |
# File 'app/models/line_item.rb', line 413 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_current ⇒ Object
Alias for Item#maximum_current
265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 |
# File 'app/models/line_item.rb', line 265 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 |
#msrp ⇒ Object
Alias for Catalog_item#msrp
287 288 289 290 291 292 293 |
# File 'app/models/line_item.rb', line 287 delegate :price_with_vat, :sale_price_with_vat, :msrp, :msrp_with_vat, :root_catalog_item, to: :catalog_item, allow_nil: true |
#msrp_total ⇒ Object
Msrp total.
842 843 844 845 846 847 848 |
# File 'app/models/line_item.rb', line 842 def msrp_total return 0.0 if parent_id.present? (msrp || 0.0) * quantity rescue StandardError 0.0 end |
#msrp_with_vat ⇒ Object
Alias for Catalog_item#msrp_with_vat
287 288 289 290 291 292 293 |
# File 'app/models/line_item.rb', line 287 delegate :price_with_vat, :sale_price_with_vat, :msrp, :msrp_with_vat, :root_catalog_item, to: :catalog_item, allow_nil: true |
#name ⇒ Object
Name.
633 634 635 |
# File 'app/models/line_item.rb', line 633 def name description || item.try(:name) || item_name end |
#num_poles ⇒ Object
Alias for Item#num_poles
265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 |
# File 'app/models/line_item.rb', line 265 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 |
#order ⇒ Order
The following makes join easier
105 |
# File 'app/models/line_item.rb', line 105 belongs_to :order, -> { joins(:line_items).where(line_items: { resource_type: 'Order' }) }, foreign_key: :resource_id, optional: true |
#oversize? ⇒ Object
Alias for Item#oversize?
265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 |
# File 'app/models/line_item.rb', line 265 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_factor ⇒ Object
Determines the parent line quantity
423 424 425 426 427 428 429 430 431 432 433 434 |
# File 'app/models/line_item.rb', line 423 def parent_quantity_factor return unless 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_job ⇒ PresetJob
Preset job.
141 |
# File 'app/models/line_item.rb', line 141 has_one :preset_job, dependent: :destroy |
#price_editable?(account = nil) ⇒ Boolean
Whether price editable.
1006 1007 1008 1009 1010 1011 1012 |
# File 'app/models/line_item.rb', line 1006 def price_editable?(account = nil) account.has_role?('sales_manager') || account.has_role?('admin') || (begin catalog_item.price_editable rescue StandardError false end) end |
#price_total ⇒ Object
Price total.
834 835 836 837 838 |
# File 'app/models/line_item.rb', line 834 def price_total (price || 0.0) * quantity rescue StandardError 0.0 end |
#price_with_vat ⇒ Object
Alias for Catalog_item#price_with_vat
287 288 289 290 291 292 293 |
# File 'app/models/line_item.rb', line 287 delegate :price_with_vat, :sale_price_with_vat, :msrp, :msrp_with_vat, :root_catalog_item, to: :catalog_item, allow_nil: true |
#product_line_for_review ⇒ Object
Alias for Item#product_line_for_review
265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 |
# File 'app/models/line_item.rb', line 265 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_code ⇒ Object
Alias for Item#product_tax_code
265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 |
# File 'app/models/line_item.rb', line 265 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_item ⇒ PurchaseOrderItem
Purchase order item.
139 |
# File 'app/models/line_item.rb', line 139 has_one :purchase_order_item, dependent: :restrict_with_error |
#quantities_indicator_visible? ⇒ Boolean
Whether quantities indicator visible.
1016 1017 1018 1019 1020 |
# File 'app/models/line_item.rb', line 1016 def quantities_indicator_visible? item.quantities_indicator_visible? rescue StandardError true end |
#quote ⇒ Quote
Quote.
107 |
# File 'app/models/line_item.rb', line 107 belongs_to :quote, -> { joins(:line_items).where(line_items: { resource_type: 'Quote' }) }, foreign_key: :resource_id, optional: true |
#remaining_quantity_to_allocate_to_shipments ⇒ Object
Remaining quantity to allocate to shipments.
515 516 517 |
# File 'app/models/line_item.rb', line 515 def remaining_quantity_to_allocate_to_shipments quantity - shipment_contents.sum(:quantity) end |
#replacement_rma_item ⇒ RmaItem
Replacement rma item.
124 |
# File 'app/models/line_item.rb', line 124 belongs_to :replacement_rma_item, class_name: 'RmaItem', optional: true |
#reported_category_name ⇒ Object
Reported category name.
1152 1153 1154 |
# File 'app/models/line_item.rb', line 1152 def reported_category_name item&.primary_product_line&. || 'unknown' end |
#require_serial_number? ⇒ Boolean
Whether require serial number.
998 999 1000 1001 |
# File 'app/models/line_item.rb', line 998 def require_serial_number? false # catalog_item.store_item.requires_serial_number? rescue false end |
#resource ⇒ Resource
Resource.
103 |
# File 'app/models/line_item.rb', line 103 belongs_to :resource, polymorphic: true, inverse_of: :line_items, optional: true |
#review ⇒ Review
Review.
143 |
# File 'app/models/line_item.rb', line 143 has_one :review, dependent: :restrict_with_error |
#rma_items ⇒ ActiveRecord::Relation<RmaItem>
Rma items.
146 |
# File 'app/models/line_item.rb', line 146 has_many :rma_items, foreign_key: 'returned_line_item_id', dependent: :destroy, inverse_of: :returned_line_item |
#room_configuration ⇒ RoomConfiguration
Room configuration.
120 |
# File 'app/models/line_item.rb', line 120 belongs_to :room_configuration, optional: true |
#root_catalog_item ⇒ Object
Alias for Catalog_item#root_catalog_item
287 288 289 290 291 292 293 |
# File 'app/models/line_item.rb', line 287 delegate :price_with_vat, :sale_price_with_vat, :msrp, :msrp_with_vat, :root_catalog_item, to: :catalog_item, allow_nil: true |
#sale_price_with_vat ⇒ Object
Alias for Catalog_item#sale_price_with_vat
287 288 289 290 291 292 293 |
# File 'app/models/line_item.rb', line 287 delegate :price_with_vat, :sale_price_with_vat, :msrp, :msrp_with_vat, :root_catalog_item, to: :catalog_item, allow_nil: true |
#serial_number ⇒ SerialNumber
Serial number.
118 |
# File 'app/models/line_item.rb', line 118 belongs_to :serial_number, optional: true |
#set_cogs ⇒ Object (protected)
Set cogs.
1189 1190 1191 1192 1193 1194 1195 1196 1197 |
# File 'app/models/line_item.rb', line 1189 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_transfer ⇒ Object (protected)
Set cogs for store transfer.
1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 |
# File 'app/models/line_item.rb', line 1201 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_contents ⇒ ActiveRecord::Relation<ShipmentContent>
Shipment contents.
154 |
# File 'app/models/line_item.rb', line 154 has_many :shipment_contents, dependent: :destroy |
#shipping_cost ⇒ ShippingCost
Shipping cost.
134 |
# File 'app/models/line_item.rb', line 134 belongs_to :shipping_cost, optional: true |
#shipping_name ⇒ Object
Shipping name.
1146 1147 1148 |
# File 'app/models/line_item.rb', line 1146 def shipping_name delivery&.retrieve_shipping_description_for_shipping_cost(shipping_cost) || name end |
#shipping_weight ⇒ Object
Shipping weight.
979 980 981 982 |
# File 'app/models/line_item.rb', line 979 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?
265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 |
# File 'app/models/line_item.rb', line 265 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
Whether show out of stock.
707 708 709 710 711 712 713 714 715 716 717 |
# File 'app/models/line_item.rb', line 707 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
Whether single origin or warehouse pickup.
721 722 723 724 725 |
# File 'app/models/line_item.rb', line 721 def single_origin_or_warehouse_pickup? return false if resource.is_a?(RoomConfiguration) resource.single_origin? || resource.is_warehouse_pickup? end |
#sku ⇒ Object
Sku.
621 622 623 |
# File 'app/models/line_item.rb', line 621 def sku item&.sku || sku_override end |
#sort_priority ⇒ Object
Sort priority.
449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 |
# File 'app/models/line_item.rb', line 449 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_total ⇒ Object
Sq ft total.
852 853 854 |
# File 'app/models/line_item.rb', line 852 def sq_ft_total quantity * item.sqft.to_f end |
#stock_status ⇒ Object
Stock status.
729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 |
# File 'app/models/line_item.rb', line 729 def stock_status return :none unless catalog_item return :na if quantity < 0 # not applicable for credit orders return :ok if dropship? && !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(&: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_item ⇒ Object
Store item.
762 763 764 |
# File 'app/models/line_item.rb', line 762 def store_item direct_store_item || catalog_item&.store_item end |
#supplier_skus ⇒ Object
Supplier skus.
627 628 629 |
# File 'app/models/line_item.rb', line 627 def supplier_skus item&.supplier_skus || [] end |
#taxable_total ⇒ Object
Taxable total.
877 878 879 880 881 882 883 |
# File 'app/models/line_item.rb', line 877 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_type ⇒ Object
Taxes grouped by type.
438 439 440 441 442 443 444 445 |
# File 'app/models/line_item.rb', line 438 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_url ⇒ Object
Alias for Item#thumbnail_url
265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 |
# File 'app/models/line_item.rb', line 265 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 |
#total ⇒ Object
Total.
887 888 889 |
# File 'app/models/line_item.rb', line 887 def total discounted_total end |
#total_shipping_weight ⇒ Object
Total shipping weight.
986 987 988 |
# File 'app/models/line_item.rb', line 986 def total_shipping_weight (shipping_weight * quantity) end |
#unit_supplier_purchase_cost ⇒ Object
def total=(value)
end
893 894 895 |
# File 'app/models/line_item.rb', line 893 def unit_supplier_purchase_cost item.try(:supplier_items)&.last&.current_price&.purchasing_cost end |
#unit_value_for_commercial_invoice ⇒ Object
Unit value for commercial invoice.
899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 |
# File 'app/models/line_item.rb', line 899 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
Whether unlimited inventory.
750 751 752 |
# File 'app/models/line_item.rb', line 750 def unlimited_inventory? store_item&.unlimited_inventory? end |
#validate_quantity_limit ⇒ Object
Validate quantity limit.
521 522 523 524 525 526 527 |
# File 'app/models/line_item.rb', line 521 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 |
#void ⇒ Object
Void.
1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 |
# File 'app/models/line_item.rb', line 1056 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 |