Class: Crm::Reports::InventoryPlanningController

Inherits:
ReportsController
  • Object
show all
Defined in:
app/controllers/crm/reports/inventory_planning_controller.rb

Overview

Controller: inventory planning.

Instance Method Summary collapse

Instance Method Details

#generate_poObject

Generates a purchase order or store transfer draft from the selected
reorder items, stashing it server-side and redirecting to the builder.



48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
# File 'app/controllers/crm/reports/inventory_planning_controller.rb', line 48

def generate_po
  errors = []
  selected_items = params[:items].to_h.select { |_item_id, details| details['order'].to_b }
  errors << 'Must select one or more items' if selected_items.empty?
  errors << 'Must specify reorder quantity for selected items' if selected_items.any? { |_item_id, details| details['quantity'].blank? }
  if params[:commit] == 'Generate Purchase Order'
    supplier_ids = Item.where(id: selected_items.keys).distinct.pluck(:preferred_supplier_id)
    errors << 'Items selected must all be for the same supplier' if supplier_ids.length > 1
    render_errors(errors) and return if errors.any?

    supplier = Supplier.find(supplier_ids[0])
    date = Date.current.to_s
    po_params = { company_id: Company::USA, store_id: Store::WARMLYYOURS_US_ID,
      po_type: 'purchase', supplier_id: supplier.id,
      carrier_id: supplier.id, terms: supplier.terms, currency: supplier.currency,
      order_date: date, request_date: date }
    item_params = {}
    selected_items.each_with_index do |(item_id, details), index|
      si = supplier.supplier_items.where(item_id: item_id).first
      qty = si.uom_quantity.to_f.zero? ? 0 : (details['quantity'].to_i / si.uom_quantity.to_f).ceil
      unit_quantity = si.uom_quantity.to_f.zero? ? 0 : (details['quantity'].to_i / si.uom_quantity.to_f).ceil * si.uom_quantity
      unit_cost = si.current_price.try(:purchasing_cost)
      unit_weight = si.item.base_weight * si.uom_quantity
      item_params[index] = {
        stock_item: '1',
        sku: si.item.sku,
        item_id: item_id,
        description: si.item.name,
        supplier_sku: si.supplier_sku,
        supplier_description: si.supplier_description,
        uom: si.uom,
        quantity: qty,
        unit_quantity: unit_quantity,
        unit_weight: unit_weight,
        total_weight: (unit_weight * qty).round(2),
        unit_cost: unit_cost.to_s,
        total_cost: (unit_cost * qty).round(2),
        auto_receive: si.auto_receive? ? 1 : 0
      }
    end
    po_params[:purchase_order_items_attributes] = item_params

    # Stash the draft server-side and redirect so Turbo Drive performs a
    # proper navigation. Can't pass the full nested payload via query string
    # (risks exceeding URL limits for larger orders) and purchase_orders#new
    # already builds from params[:purchase_order].
    session[:inventory_planning_po_draft] = po_params
    # ApplicationController#redirect_to auto-promotes to 303 on POSTs.
    redirect_to new_purchase_order_path
  elsif params[:commit] == 'Generate Store Transfer'
    store = Store.find(Store::WARMLYYOURS_US_ID)
    new_store = Store.find(Store::WARMLYYOURS_CA_ID)
    # Stash items_list server-side so we don't risk 414 URI Too Long when
    # the user selected many SKUs. item_ledger_entries#store_transfer picks
    # the draft up if no items_list is present on the URL.
    session[:inventory_planning_store_transfer_draft] =
      selected_items.transform_values { |details| details['quantity'].to_i }
    redirect_to store_transfer_item_ledger_entries_path(options: {
                  store_id: store.id,
                  new_store_id: new_store.id,
                  destination_address_id: new_store.consignee_party.addresses.first&.id
                }.compact)
  end
end

#refresh_forecastObject

Enqueues the item demand forecast refresh worker.



28
29
30
31
# File 'app/controllers/crm/reports/inventory_planning_controller.rb', line 28

def refresh_forecast
  job_id = RefreshInventoryReportWorker.perform_async
  redirect_to_job_or_fallback(job_id, reports_inventory_planning_report_path)
end

#refresh_reportObject

Enqueues the inventory plan refresh worker.



34
35
36
37
# File 'app/controllers/crm/reports/inventory_planning_controller.rb', line 34

def refresh_report
  job_id = RefreshInventoryPlanWorker.perform_async
  redirect_to_job_or_fallback(job_id, reports_inventory_planning_report_path)
end

#render_errors(errors) ⇒ void

This method returns an undefined value.

Re-renders #show with the given errors flashed.

Parameters:

  • errors (Array<String>)

    error messages to flash



117
118
119
120
121
122
123
# File 'app/controllers/crm/reports/inventory_planning_controller.rb', line 117

def render_errors(errors)
  flash.now[:error] = errors.join(', ')
  params[:q] = params[:q].nil? ? nil : YAML.load(params[:q].gsub('=>', ':')).symbolize_keys
  params[:report_command] = params[:report_command].nil? ? nil : YAML.load(params[:report_command].gsub('=>', ':')).symbolize_keys
  show
  render :show, status: :unprocessable_content
end

#showObject

Runs the inventory planning report, or (if forecast data hasn't been
generated yet) surfaces the in-progress refresh job.



8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
# File 'app/controllers/crm/reports/inventory_planning_controller.rb', line 8

def show
  if ItemDemandForecast.any?
    params[:q] ||= {}
    params[:report_command] ||= {}
    params[:q][:product_category_ids_overlap_array] = params[:report_command][:product_category_ids]
    params[:q][:product_line_ids_overlap_array] = params[:report_command][:product_line_ids]
    @report_command = ::Report::InventoryPlanningCommand.new(params[:report_command])
    @q = @report_command.execute.ransack(params[:q])
    @q.sorts = 'item_sku asc' if @q.sorts.blank?
    @inventory_plans = @q.result
    @country = @report_command.country
    @country_only = @country.gsub('_st', '')
  else
    @report_refreshing = true
    # report is being refreshed, so find the job, could be working or still queued
    @job_id = BackgroundJobStatus.search(worker_klass: 'RefreshInventoryReportWorker').first&.jid
  end
end

#show_chartObject

Renders a single item's demand chart, layout-free (for a modal/panel).



40
41
42
43
44
# File 'app/controllers/crm/reports/inventory_planning_controller.rb', line 40

def show_chart
  @item = Item.find(params[:item_id])
  @country = params[:country]
  render layout: false
end