Module: Controllers::PriceEditable

Extended by:
ActiveSupport::Concern
Included in:
OrdersController
Defined in:
app/concerns/controllers/price_editable.rb

Instance Method Summary collapse

Instance Method Details

#price_editObject



6
7
8
9
10
11
12
13
14
15
# File 'app/concerns/controllers/price_editable.rb', line 6

def price_edit
  load_context
  authorize! :edit_prices, @context_object
  if %w[CO ST].include?(@context_object.order_type)
    render 'price_editable/price_edit'
  else
    flash[:error] = "#{@context_object.class.name} must be a CO or ST to allow price editing"
    redirect_to polymorphic_url(@context_object)
  end
end

#price_updateObject



17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
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
112
113
# File 'app/concerns/controllers/price_editable.rb', line 17

def price_update
  load_context
  authorize! :edit_prices, @context_object

  line_item_payload = params[:line_item]
  unless line_item_payload.respond_to?(:each)
    flash[:error] = 'No line item prices were submitted.'
    return render 'price_editable/price_edit'
  end

  applications = []
  line_item_payload.each do |line_item_id, values|
    next if values.blank?

    attrs = price_edit_line_item_attrs(values)
    discounted_raw = attrs['discounted_price'].to_s.strip
    price_raw = attrs['price'].to_s.strip

    line_item = @context_object.line_items.detect { |li| li.id == line_item_id.to_i }
    next unless line_item
    next if discounted_raw.blank? || price_raw.blank?

    new_taxable_raw = attrs['taxable_amount'].to_s.strip
    label = price_edit_line_item_label(line_item)
    row_invalid = false

    discounted_value = price_edit_parse_decimal(discounted_raw)
    if discounted_value.nil?
      line_item.errors.add(:discounted_price, 'is not a valid number')
      @context_object.errors.add(:base, "#{label}: unit discounted price is not a valid number")
      row_invalid = true
    end

    price_value = price_edit_parse_decimal(price_raw)
    if price_value.nil?
      line_item.errors.add(:price, 'is not a valid number')
      @context_object.errors.add(:base, "#{label}: unit MSRP is not a valid number")
      row_invalid = true
    end

    new_taxable_amount = nil
    if new_taxable_raw.present?
      tax_value = price_edit_parse_decimal(new_taxable_raw)
      if tax_value.nil?
        line_item.errors.add(:taxable_amount, 'is not a valid number')
        @context_object.errors.add(:base, "#{label}: unit taxable amount is not a valid number")
        row_invalid = true
      else
        new_taxable_amount = tax_value
      end
    end

    next if row_invalid

    applications << {
      line_item: line_item,
      discounted_price: discounted_value,
      price: price_value,
      taxable_amount: new_taxable_amount,
      tax_only: attrs['tax_only'].to_s == '1'
    }
  end

  if @context_object.errors.any?
    render 'price_editable/price_edit'
    return
  end

  applications.each do |app|
    li = app[:line_item]
    li.discounted_price = app[:discounted_price]
    li.price = app[:price]
    li.taxable_amount = app[:taxable_amount]
    li.tax_only = app[:tax_only]
  end

  if applications.any?
    # Saving with force_total_reset triggers set_totals → calculate_discounts, and
    # Coupon::ItemizableDiscountCalculator resets every line with discounted_price = price
    # (MSRP), wiping manual edits. Skip that path for this action only, then refresh
    # header totals via the same SQL used after a normal total reset.
    @context_object.do_not_set_totals = true if @context_object.respond_to?(:do_not_set_totals=)
    if @context_object.save
      @context_object.do_not_set_totals = false if @context_object.respond_to?(:do_not_set_totals=)
      @context_object.perform_db_total if @context_object.respond_to?(:perform_db_total)
      @context_object.reload
      redirect_to polymorphic_url(@context_object)
    else
      @context_object.do_not_set_totals = false if @context_object.respond_to?(:do_not_set_totals=)
      flash[:error] = @context_object.errors.full_messages.to_sentence.presence || 'Could not save price changes.'
      render 'price_editable/price_edit'
    end
  else
    flash[:error] = 'No prices were updated. Enter both unit discounted price and unit MSRP for each line you change.'
    render 'price_editable/price_edit'
  end
end