Class: Dscf::Marketplace::Quotation

Inherits:
ApplicationRecord show all
Defined in:
app/models/dscf/marketplace/quotation.rb

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.ransackable_associations(_auth_object = nil) ⇒ Object



32
33
34
# File 'app/models/dscf/marketplace/quotation.rb', line 32

def self.ransackable_associations(_auth_object = nil)
  %w[request_for_quotation business quotation_items order]
end

.ransackable_attributes(_auth_object = nil) ⇒ Object

Ransack configuration for secure filtering



28
29
30
# File 'app/models/dscf/marketplace/quotation.rb', line 28

def self.ransackable_attributes(_auth_object = nil)
  %w[id request_for_quotation_id business_id total_price delivery_date valid_until status notes created_at updated_at]
end

Instance Method Details

#accept!(options = {}) ⇒ Object



73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
# File 'app/models/dscf/marketplace/quotation.rb', line 73

def accept!(options = {})
  return false unless sent?
  return false if within_validity_period? == false

  # Close other quotations for this RFQ first
  request_for_quotation.quotations.where.not(id: id).update_all(status: "rejected")

  update_columns(status: "accepted")
  request_for_quotation.update!(status: "selected", selected_quotation: self)

  # Create order from accepted quotation
  create_order_from_quotation(options)

  true
end

#accepted?Boolean

Returns:

  • (Boolean)


49
50
51
# File 'app/models/dscf/marketplace/quotation.rb', line 49

def accepted?
  status == "accepted"
end

#build_from_rfq_items(items_attributes) ⇒ Object



153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
# File 'app/models/dscf/marketplace/quotation.rb', line 153

def build_from_rfq_items(items_attributes)
  items_attributes.each do |item_attrs|
    rfq_item = request_for_quotation.rfq_items.find_by(id: item_attrs[:rfq_item_id])
    next unless rfq_item

    quotation_items.build(
      rfq_item: rfq_item,
      product: rfq_item.product,
      unit: item_attrs[:unit_id] ? Dscf::Marketplace::Unit.find(item_attrs[:unit_id]) : rfq_item.unit,
      quantity: [ item_attrs[:quantity].to_i, rfq_item.quantity ].min,
      unit_price: item_attrs[:unit_price].to_f,
      notes: item_attrs[:notes] || ""
    )
  end
  valid? # To trigger validations
end

#complete?Boolean

Returns:

  • (Boolean)


116
117
118
# File 'app/models/dscf/marketplace/quotation.rb', line 116

def complete?
  quotation_items.exists? && quotation_items.all? { |item| item.unit_price.present? }
end

#create_order_from_quotation(options = {}) ⇒ Object



120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
# File 'app/models/dscf/marketplace/quotation.rb', line 120

def create_order_from_quotation(options = {})
  return if order.present?

  fulfillment_type = options[:fulfillment_type] || "self_pickup"
  dropoff_address = options[:dropoff_address]

  order = Dscf::Marketplace::Order.create!(
    order_type: :rfq_based,
    status: :processing,
    fulfillment_type: fulfillment_type,
    quotation: self,
    user: request_for_quotation.user, # Keep for backward compatibility
    ordered_by: request_for_quotation.user,
    ordered_to: business,
    dropoff_address: dropoff_address,
    total_amount: total_price
  )

  quotation_items.each do |item|
    Dscf::Marketplace::OrderItem.create!(
      order: order,
      quotation_item: item,
      product: item.product,
      unit: item.unit,
      quantity: item.quantity,
      unit_price: item.unit_price,
      status: :pending
    )
  end

  order
end

#days_until_expiryObject



103
104
105
106
107
108
# File 'app/models/dscf/marketplace/quotation.rb', line 103

def days_until_expiry
  return nil unless valid_until

  days = ((valid_until - Time.current) / 1.day).ceil
  days.negative? ? nil : days
end

#delivery_in_daysObject



110
111
112
113
114
# File 'app/models/dscf/marketplace/quotation.rb', line 110

def delivery_in_days
  return nil unless delivery_date

  ((delivery_date.to_time - Time.current) / 1.day).ceil
end

#draft?Boolean

Returns:

  • (Boolean)


61
62
63
# File 'app/models/dscf/marketplace/quotation.rb', line 61

def draft?
  status == "draft"
end

#expired!Object



69
70
71
# File 'app/models/dscf/marketplace/quotation.rb', line 69

def expired!
  update_columns(status: "expired") if valid_until <= Time.current
end

#expired?Boolean

Returns:

  • (Boolean)


57
58
59
# File 'app/models/dscf/marketplace/quotation.rb', line 57

def expired?
  status == "expired"
end

#reject!Object



89
90
91
92
93
# File 'app/models/dscf/marketplace/quotation.rb', line 89

def reject!
  return false unless sent?

  update!(status: "rejected")
end

#rejected?Boolean

Returns:

  • (Boolean)


53
54
55
# File 'app/models/dscf/marketplace/quotation.rb', line 53

def rejected?
  status == "rejected"
end

#send_quotation!Object



95
96
97
98
99
100
101
# File 'app/models/dscf/marketplace/quotation.rb', line 95

def send_quotation!
  return false unless draft?

  update!(status: "sent")
  request_for_quotation.update!(status: "responded") if request_for_quotation.sent? || request_for_quotation.draft?
  true
end

#sent?Boolean

Returns:

  • (Boolean)


45
46
47
# File 'app/models/dscf/marketplace/quotation.rb', line 45

def sent?
  status == "sent"
end

#update_total_price!Object



40
41
42
43
# File 'app/models/dscf/marketplace/quotation.rb', line 40

def update_total_price!
  calculate_total_price
  save!
end

#within_validity_period?Boolean

Returns:

  • (Boolean)


65
66
67
# File 'app/models/dscf/marketplace/quotation.rb', line 65

def within_validity_period?
  valid_until > Time.current && !expired?
end