Class: CatalogItemPresenter

Inherits:
BasePresenter show all
Includes:
Presenters::StandardOperationsForRecord
Defined in:
app/presenters/catalog_item_presenter.rb

Overview

Presenter: catalog item presenter.

Instance Attribute Summary

Attributes inherited from BasePresenter

#current_account, #options, #url_helper

Delegated Instance Attributes collapse

Methods inherited from BasePresenter

#can?, #capture, #concat, #content_tag, #fa_icon, #link_to, #number_to_currency, #simple_format

Instance Method Summary collapse

Methods inherited from BasePresenter

#h, #initialize, #present, presents, #r, #safe_present, #u

Constructor Details

This class inherits a constructor from BasePresenter

Instance Method Details

#actionsObject



231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
# File 'app/presenters/catalog_item_presenter.rb', line 231

def actions
  links = []
  return links unless can?(:update, r)

  links << link_to('Edit', h.edit_catalog_item_path(r))
  links += h.available_events_links(r)
  if r.parent_catalog_item.present?
    links << link_to('Reset Price', h.reset_price_to_parent_discount_catalog_item_path(r), data: { turbo_method: :post, turbo_confirm: 'This will reset the price to the parent catalog item and apply the catalog item discount' })
  end
  links << :separator
  if can?(:create, EdiCommunicationLog)
    links << link_to('Push Inventory', h.push_inventory_message_catalog_item_path(r), data: { turbo_method: :post, turbo_confirm: 'This will push the inventory to EDI/API partners linked to this catalog item' }) if r.inventory_message_enabled?
    links << link_to('Push Pricing', h.push_price_message_catalog_item_path(r), data: { turbo_method: :post, turbo_confirm: 'This will push the pricing to EDI/API partners linked to this catalog item' }) if r.price_message_enabled?
    links << link_to('Push Listing Data', h.amazon_listing_data_catalog_item_path(r)) if r.listing_message_enabled?
    if r.listing_message_enabled? || r.walmart_catalog_item?
      links << link_to('Delete Listing', h.delete_amazon_listing_data_catalog_item_path(r), data: { turbo_method: :delete, turbo_confirm: 'This will delete/retire the listing on the marketplace' })
    end
    links << :separator
  end
  if h.can?(:destroy, r)
    links << if r.ok_to_destroy?
               link_to('Delete', h.catalog_item_path(r), data: { turbo_method: :delete })
             else
               { content: 'Cannot be deleted' }
             end
  end
  links
end

#actions_combo_buttonObject



260
261
262
# File 'app/presenters/catalog_item_presenter.rb', line 260

def actions_combo_button
  h.render_combo_drop_down actions, main_link_class: 'btn-primary', main_link_style: 'padding-left: 2em; padding-right: 2em'
end

#advertised_price_map_violation?Boolean

MAP violation for the advertised/retail price displayed in CRM.
We treat this as a violation whenever retail_price < map_price (when both present),
regardless of retailer_type, because marketplaces are the primary use case.

Returns:

  • (Boolean)


195
196
197
198
199
# File 'app/presenters/catalog_item_presenter.rb', line 195

def advertised_price_map_violation?
  return false unless retail_price.present? && map_price.present?

  retail_price < map_price
end

#advertised_price_percent_off_msrp_humanObject



157
158
159
# File 'app/presenters/catalog_item_presenter.rb', line 157

def advertised_price_percent_off_msrp_human
  percent_off_msrp_human(retail_price)
end

#amazon_business_price_with_currencyObject



81
82
83
# File 'app/presenters/catalog_item_presenter.rb', line 81

def amazon_business_price_with_currency
  h.number_to_currency(amazon_business_price_with_tax, unit: amount_currency_symbol) if amazon_business_price_with_tax
end

#amazon_maximum_seller_allowed_price_with_currencyObject



89
90
91
# File 'app/presenters/catalog_item_presenter.rb', line 89

def amazon_maximum_seller_allowed_price_with_currency
  h.number_to_currency(amazon_maximum_seller_allowed_price_with_tax, unit: amount_currency_symbol) if amazon_maximum_seller_allowed_price_with_tax
end

#amazon_minimum_seller_allowed_price_with_currencyObject



85
86
87
# File 'app/presenters/catalog_item_presenter.rb', line 85

def amazon_minimum_seller_allowed_price_with_currency
  h.number_to_currency(amazon_minimum_seller_allowed_price_with_tax, unit: amount_currency_symbol) if amazon_minimum_seller_allowed_price_with_tax
end

#amount_with_currencyObject



109
110
111
# File 'app/presenters/catalog_item_presenter.rb', line 109

def amount_with_currency
  h.number_to_currency amount, unit: amount_currency_symbol if amount
end

#amz_min_seller_price_override_exceeds_max_discount?Boolean

Returns:

  • (Boolean)


97
98
99
100
101
102
103
# File 'app/presenters/catalog_item_presenter.rb', line 97

def amz_min_seller_price_override_exceeds_max_discount?
  return false unless amz_min_seller_price_override.present? && amount.present? && amount.positive?
  return false if max_discount_allowed_percentage.blank?

  discount_percentage = ((amount - amz_min_seller_price_override) / amount) * 100
  discount_percentage > max_discount_allowed_percentage
end

#amz_min_seller_price_override_with_currencyObject



93
94
95
# File 'app/presenters/catalog_item_presenter.rb', line 93

def amz_min_seller_price_override_with_currency
  h.number_to_currency(amz_min_seller_price_override, unit: amount_currency_symbol) if amz_min_seller_price_override
end


14
15
16
# File 'app/presenters/catalog_item_presenter.rb', line 14

def breadcrumb_all_catalogs
  h.(:li, h.link_to('Catalogs', h.catalogs_path), class: 'breadcrumb-item')
end


28
29
30
# File 'app/presenters/catalog_item_presenter.rb', line 28

def breadcrumb_catalog_item
  h.(:li, h.link_to("#{sku} (CI)", h.catalog_item_path(id)), class: 'breadcrumb-item') unless new_record?
end


24
25
26
# File 'app/presenters/catalog_item_presenter.rb', line 24

def breadcrumb_current_catalog
  h.(:li, h.link_to(catalog.name, h.catalog_path(catalog_id)), class: 'breadcrumb-item')
end


8
9
10
11
12
# File 'app/presenters/catalog_item_presenter.rb', line 8

def breadcrumb_item
  return unless catalog_item.store_item&.item

  h.(:li, h.link_to(catalog_item.item.sku, h.item_path(catalog_item.item.id)), class: 'breadcrumb-item')
end


18
19
20
21
22
# File 'app/presenters/catalog_item_presenter.rb', line 18

def breadcrumb_parent_catalog
  return unless (parent_catalog = catalog.parent_catalog)

  h.(:li, h.link_to(parent_catalog.name, h.catalog_path(parent_catalog)), class: 'breadcrumb-item')
end


32
33
34
# File 'app/presenters/catalog_item_presenter.rb', line 32

def breadcrumb_parent_catalog_item
  h.(:li, h.link_to("#{sku} (CI)", h.catalog_item_path(parent_catalog_item.id)), class: 'breadcrumb-item') if parent_catalog_item
end


44
45
46
47
48
49
50
51
52
53
# File 'app/presenters/catalog_item_presenter.rb', line 44

def breadcrumbs
  h.capture do
    h.concat breadcrumb_item
    h.concat breadcrumb_all_catalogs
    h.concat breadcrumb_parent_catalog
    h.concat breadcrumb_parent_catalog_item
    h.concat breadcrumb_current_catalog
    h.concat breadcrumb_catalog_item
  end
end

#catalog_item_tab_optionsObject



264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
# File 'app/presenters/catalog_item_presenter.rb', line 264

def catalog_item_tab_options
  tab_hsh = {
    main: { remote_href: h.tab_main_catalog_item_path(self) },
    price_history: { remote_href: h.tab_price_history_catalog_item_path(self) },
    descriptions: { remote_href: h.tab_descriptions_catalog_item_path(self) },
    specs: { remote_href: h.tab_specs_catalog_item_path(self) },
    images: { remote_href: h.tab_images_catalog_item_path(self) },
    dependents: { remote_href: h.tab_dependents_catalog_item_path(self) },
    siblings: { remote_href: h.show_siblings_catalog_item_path(self) },
    edi: { remote_href: h.show_edi_catalog_item_path(self) }
  }
  tab_hsh[:amazon] = { remote_href: h.show_amazon_catalog_item_path(self) } if amazon_catalog_item?
  tab_hsh[:wayfair] = { remote_href: h.show_wayfair_catalog_item_path(self) } if wayfair_catalog_item?
  tab_hsh[:retailer_probes] = { remote_href: h.tab_retailer_probes_catalog_item_path(self) } if catalog.external_price_check_enabled?
  tab_hsh[:sibling_retailers] = { remote_href: h.tab_sibling_retailers_catalog_item_path(self), label: 'Sibling Retailers' }
  tab_hsh
end


36
37
38
# File 'app/presenters/catalog_item_presenter.rb', line 36

def destroy_catalog_item_link(options = {})
  destroy_record_button(catalog_item, options)
end


40
41
42
# File 'app/presenters/catalog_item_presenter.rb', line 40

def edit_catalog_item_link(options = {})
  edit_record_button(catalog_item, options)
end

#identifiersObject



55
56
57
58
59
60
61
62
63
# File 'app/presenters/catalog_item_presenter.rb', line 55

def identifiers
  ids = {}
  ids['Supplier SKUs'] = item.supplier_skus.join(', ') if item.supplier_skus.present?
  ids['ASIN'] = amazon_asin if amazon_asin.present?
  ids['TPPN'] = third_party_part_number if third_party_part_number.present?
  ids['TPSKU'] = third_party_sku if third_party_sku.present? && third_party_sku != item.sku
  ids['UPC'] = item.upc if item.upc.present?
  ids
end

#image_profile_marketplaceObject

Determines which image profile marketplace to show for this catalog item



283
284
285
286
287
288
289
290
291
292
# File 'app/presenters/catalog_item_presenter.rb', line 283

def image_profile_marketplace
  catalog_id = catalog.id
  if CatalogConstants::AMAZON_CATALOG_IDS.include?(catalog_id)
    'AMZ'
  elsif CatalogConstants::WALMART_CATALOGS.include?(catalog_id)
    'WAL'
  else
    'WYS'
  end
end

#map_price_percent_off_msrp_humanObject



161
162
163
# File 'app/presenters/catalog_item_presenter.rb', line 161

def map_price_percent_off_msrp_human
  percent_off_msrp_human(map_price)
end

#map_price_with_currencyObject



145
146
147
# File 'app/presenters/catalog_item_presenter.rb', line 145

def map_price_with_currency
  h.number_to_currency map_price, unit: retail_price_currency_symbol if map_price
end

#map_price_with_percent_offObject



180
181
182
# File 'app/presenters/catalog_item_presenter.rb', line 180

def map_price_with_percent_off
  price_with_percent_off_from_msrp(map_price_with_currency, map_price_percent_off_msrp_human)
end

#max_discount_humanObject



221
222
223
224
225
# File 'app/presenters/catalog_item_presenter.rb', line 221

def max_discount_human
  return unless max_discount

  h.number_to_percentage(max_discount, strip_insignificant_zeros: true)
end

#msrp_with_currencyObject



149
150
151
152
153
154
155
# File 'app/presenters/catalog_item_presenter.rb', line 149

def msrp_with_currency
  return unless msrp

  # Use parent_catalog's currency if available, otherwise fall back to current catalog's currency
  currency_symbol = parent_catalog_currency_symbol || retail_price_currency_symbol
  h.number_to_currency msrp, unit: currency_symbol
end

#new_price_with_currencyObject



117
118
119
# File 'app/presenters/catalog_item_presenter.rb', line 117

def new_price_with_currency
  h.number_to_currency new_price, unit: amount_currency_symbol if new_price
end

#new_sale_price_with_currencyObject



129
130
131
# File 'app/presenters/catalog_item_presenter.rb', line 129

def new_sale_price_with_currency
  h.number_to_currency new_sale_price, unit: amount_currency_symbol if new_sale_price
end

#new_sale_price_with_vat_and_currencyObject



137
138
139
# File 'app/presenters/catalog_item_presenter.rb', line 137

def new_sale_price_with_vat_and_currency
  h.number_to_currency new_sale_price_with_vat, unit: amount_currency_symbol if new_sale_price_with_vat
end

#old_amount_with_currencyObject



113
114
115
# File 'app/presenters/catalog_item_presenter.rb', line 113

def old_amount_with_currency
  h.number_to_currency old_amount, unit: amount_currency_symbol if old_amount
end

#parent_catalog_item_discountObject



201
202
203
204
205
206
207
208
209
210
211
212
213
# File 'app/presenters/catalog_item_presenter.rb', line 201

def parent_catalog_item_discount
  return unless parent_catalog_item
  return unless effective_price

  parent_amount = parent_catalog_item.amount
  if parent_amount == effective_price
    0
  elsif parent_amount&.positive?
    ((1 - (effective_price / parent_amount)) * 100).round(2)
  else
    100
  end
end

#parent_catalog_item_discount_humanObject



215
216
217
218
219
# File 'app/presenters/catalog_item_presenter.rb', line 215

def parent_catalog_item_discount_human
  return unless (pcid = parent_catalog_item_discount)

  h.number_to_percentage(pcid, strip_insignificant_zeros: true)
end

#parent_catalog_price_with_currencyObject



73
74
75
# File 'app/presenters/catalog_item_presenter.rb', line 73

def parent_catalog_price_with_currency
  h.number_to_currency parent_catalog_item_amount, unit: parent_catalog_item.amount_currency_symbol if parent_catalog_item&.amount
end

#percent_off_msrp_human(value) ⇒ Object



184
185
186
187
188
189
190
# File 'app/presenters/catalog_item_presenter.rb', line 184

def percent_off_msrp_human(value)
  return unless msrp.present? && msrp.to_d.positive?
  return if value.blank?

  pct = (1 - (value.to_d / msrp.to_d)) * 100
  h.number_to_percentage(pct, precision: 0, strip_insignificant_zeros: true)
end

#price_with_percent_off_from_msrp(price_with_currency, percent_off_human) ⇒ Object



165
166
167
168
169
170
171
172
173
174
# File 'app/presenters/catalog_item_presenter.rb', line 165

def price_with_percent_off_from_msrp(price_with_currency, percent_off_human)
  return price_with_currency if percent_off_human.blank?

  h.safe_join(
    [
      price_with_currency,
      h.tag.small("(#{percent_off_human} off)", class: 'text-muted ms-1')
    ]
  )
end

#price_with_vat_and_currencyObject



121
122
123
# File 'app/presenters/catalog_item_presenter.rb', line 121

def price_with_vat_and_currency
  h.number_to_currency price_with_vat, unit: amount_currency_symbol if price_with_vat
end

#qty_availableObject

Alias for Store_item#qty_available

Returns:

  • (Object)

    Store_item#qty_available

See Also:



71
# File 'app/presenters/catalog_item_presenter.rb', line 71

delegate :qty_available, to: :store_item

#qty_on_handObject

Alias for Store_item#qty_on_hand

Returns:

  • (Object)

    Store_item#qty_on_hand

See Also:



69
# File 'app/presenters/catalog_item_presenter.rb', line 69

delegate :qty_on_hand, to: :store_item

#retail_price_with_currencyObject



141
142
143
# File 'app/presenters/catalog_item_presenter.rb', line 141

def retail_price_with_currency
  h.number_to_currency retail_price, unit: retail_price_currency_symbol if retail_price
end

#retail_price_with_percent_offObject



176
177
178
# File 'app/presenters/catalog_item_presenter.rb', line 176

def retail_price_with_percent_off
  price_with_percent_off_from_msrp(retail_price_with_currency, advertised_price_percent_off_msrp_human)
end

#retailer_requested_cost_with_currencyObject



105
106
107
# File 'app/presenters/catalog_item_presenter.rb', line 105

def retailer_requested_cost_with_currency
  h.number_to_currency(retailer_requested_cost, unit: amount_currency_symbol) if retailer_requested_cost
end

#sale_price_with_currencyObject



125
126
127
# File 'app/presenters/catalog_item_presenter.rb', line 125

def sale_price_with_currency
  h.number_to_currency sale_price, unit: amount_currency_symbol if sale_price
end

#sale_price_with_vat_and_currencyObject



133
134
135
# File 'app/presenters/catalog_item_presenter.rb', line 133

def sale_price_with_vat_and_currency
  h.number_to_currency sale_price_with_vat, unit: amount_currency_symbol if sale_price_with_vat
end

#status_labelObject



227
228
229
# File 'app/presenters/catalog_item_presenter.rb', line 227

def status_label
  h.catalog_item_state_badge(r)
end

#store_item_cost_with_currencyObject



77
78
79
# File 'app/presenters/catalog_item_presenter.rb', line 77

def store_item_cost_with_currency
  h.number_to_currency store_item.unit_cogs.round(4), unit: parent_catalog_item.amount_currency_symbol if store_item&.unit_cogs
end

#store_nameObject



65
66
67
# File 'app/presenters/catalog_item_presenter.rb', line 65

def store_name
  store_item.store.name
end