# frozen_string_literal: true class SolidusAdmin::StockItems::Index::Component < SolidusAdmin::UI::Pages::Index::Component def model_class Spree::StockItem end def search_key :variant_product_name_or_variant_sku_or_variant_option_values_name_or_variant_option_values_presentation_cont end def search_url solidus_admin.stock_items_path end def row_url(stock_item) solidus_admin.edit_stock_item_path(stock_item, _turbo_frame: :edit_stock_item_modal) end def scopes [ { label: t('.scopes.all_stock_items'), name: 'all', default: true }, { label: t('.scopes.back_orderable'), name: 'back_orderable' }, { label: t('.scopes.out_of_stock'), name: 'out_of_stock' }, { label: t('.scopes.low_stock'), name: 'low_stock' }, { label: t('.scopes.in_stock'), name: 'in_stock' }, ] end def filters [ { label: t('.filters.stock_locations'), combinator: 'or', attribute: "stock_location_id", predicate: "eq", options: Spree::StockLocation.all.map do |stock_location| [ stock_location.name.titleize, stock_location.id ] end }, { label: t('.filters.variants'), combinator: 'or', attribute: "variant_id", predicate: "eq", options: Spree::Variant.all.map do |variant| [ variant.descriptive_name, variant.id ] end }, ] end def columns [ image_column, name_column, sku_column, variant_column, stock_location_column, back_orderable_column, count_on_hand_column, stock_movements_column, ] end def image_column { col: { class: "w-[72px]" }, header: tag.span('aria-label': Spree::Image.model_name.human, role: 'text'), data: ->(stock_item) do image = stock_item.variant.gallery.images.first or return render( component('ui/thumbnail').new( src: image.url(:small), alt: stock_item.variant.name ) ) end } end def name_column { header: :name, data: ->(stock_item) do content_tag :div, stock_item.variant.name end } end def sku_column { header: :sku, data: ->(stock_item) do content_tag :div, stock_item.variant.sku end } end def variant_column { header: :variant, data: ->(stock_item) do content_tag(:div, class: "space-y-0.5") do safe_join( stock_item.variant.option_values.sort_by(&:option_type_name).map do |option_value| render(component('ui/badge').new(name: "#{option_value.option_type_presentation}: #{option_value.presentation}")) end ) end end } end def stock_location_column { header: :stock_location, data: ->(stock_item) { stock_item.stock_location.name }, } end # Cache the stock movement counts to avoid N+1 queries def stock_movement_counts @stock_movement_counts ||= Spree::StockMovement.where(stock_item_id: @page.records.ids).group(:stock_item_id).count end def stock_movements_column { header: :stock_movements, data: -> do count = stock_movement_counts[_1.id] || 0 link_to( "#{count} #{Spree::StockMovement.model_name.human(count: count).downcase}", spree.admin_stock_location_stock_movements_path( _1.stock_location.id, q: { variant_sku_eq: _1.variant.sku }, ), class: 'body-link' ) end } end def back_orderable_column { header: :back_orderable, data: ->(stock_item) do stock_item.backorderable? ? component('ui/badge').yes : component('ui/badge').no end } end def count_on_hand_column { header: :count_on_hand, data: ->(stock_item) do content_tag :div, stock_item.count_on_hand end } end def turbo_frames %w[edit_stock_item_modal] end end