Class: Dscf::Marketplace::Order

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

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.create_from_listing(listing, user, quantity, dropoff_address = nil, payment_method = nil) ⇒ Object



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
114
115
116
117
118
# File 'app/models/dscf/marketplace/order.rb', line 89

def self.create_from_listing(listing, user, quantity, dropoff_address = nil, payment_method = nil)
  return nil unless listing.visible? && quantity <= listing.quantity

  attributes = {
    order_type: :direct_listing,
    status: :validating,
    fulfillment_type: dropoff_address.present? ? :delivery : :self_pickup,
    listing: listing,
    user: user, # Keep for backward compatibility
    ordered_by: user,
    ordered_to: listing.business,
    dropoff_address: dropoff_address,
    total_amount: listing.price * quantity
  }
  attributes[:payment_method] = payment_method if payment_method.present?

  order = create!(attributes)

  order.order_items.create!(
    listing: listing,
    product: listing.supplier_product.product,
    unit: listing.supplier_product.product.unit,
    quantity: quantity,
    unit_price: listing.price,
    status: :pending,
    validation_status: :validated
  )

  order
end

.create_from_quotation(quotation, dropoff_address = nil, payment_method = nil) ⇒ Object



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
# File 'app/models/dscf/marketplace/order.rb', line 55

def self.create_from_quotation(quotation, dropoff_address = nil, payment_method = nil)
  return nil unless quotation.accepted?

  attributes = {
    order_type: :rfq_based,
    status: :validating,
    fulfillment_type: dropoff_address.present? ? :delivery : :self_pickup,
    quotation: quotation,
    user: quotation.request_for_quotation.user, # Keep for backward compatibility
    ordered_by: quotation.request_for_quotation.user,
    ordered_to: quotation.business,
    dropoff_address: dropoff_address,
    total_amount: quotation.total_price
  }
  attributes[:payment_method] = payment_method if payment_method.present?

  order = create!(attributes)

  quotation.quotation_items.each do |item|
    order.order_items.create!(
      quotation_item: item,
      product: item.product,
      unit: item.unit,
      quantity: item.quantity,
      unit_price: item.unit_price,
      status: :pending,
      validation_status: :validated # initial from accepted quote; validation can re-run
    )
  end

  order
end

.ransackable_associations(_auth_object = nil) ⇒ Object



51
52
53
# File 'app/models/dscf/marketplace/order.rb', line 51

def self.ransackable_associations(_auth_object = nil)
  %w[quotation listing user ordered_by ordered_to delivery_order dropoff_address order_items]
end

.ransackable_attributes(_auth_object = nil) ⇒ Object

Ransack configuration for secure filtering



47
48
49
# File 'app/models/dscf/marketplace/order.rb', line 47

def self.ransackable_attributes(_auth_object = nil)
  %w[id quotation_id listing_id user_id ordered_by_id ordered_to_id delivery_order_id dropoff_address_id order_type status fulfillment_type payment_method received_bank_name transaction_reference total_amount created_at updated_at]
end

Instance Method Details

#all_items_validated?Boolean

Returns:

  • (Boolean)


180
181
182
# File 'app/models/dscf/marketplace/order.rb', line 180

def all_items_validated?
  order_items.all? { |i| i.validation_status == "validated" }
end

#calculate_total_amountObject



171
172
173
# File 'app/models/dscf/marketplace/order.rb', line 171

def calculate_total_amount
  self.total_amount = order_items.sum { |item| item.quantity * item.unit_price }
end

#can_be_completed?Boolean

Returns:

  • (Boolean)


152
153
154
155
156
157
158
159
160
# File 'app/models/dscf/marketplace/order.rb', line 152

def can_be_completed?
  if self_pickup?
    # Self-pickup orders can be completed immediately after confirmation
    confirmed? || processing?
  else
    # Delivery orders require delivery_order association
    delivery_order.present? && delivery_order.delivered?
  end
end

#confirm!Object



162
163
164
165
166
167
168
169
# File 'app/models/dscf/marketplace/order.rb', line 162

def confirm!
  return false unless pending?

  update!(status: :confirmed)
  # Update order items without reloading to avoid association issues
  order_items.update_all(status: OrderItem.statuses[:confirmed])
  true
end

#delivery?Boolean

Returns:

  • (Boolean)


144
145
146
# File 'app/models/dscf/marketplace/order.rb', line 144

def delivery?
  fulfillment_type == "delivery"
end

#mark_splitting!Object



188
189
190
# File 'app/models/dscf/marketplace/order.rb', line 188

def mark_splitting!
  update!(status: :splitting)
end

#mark_waiting_retailer_confirmation!Object



196
197
198
# File 'app/models/dscf/marketplace/order.rb', line 196

def mark_waiting_retailer_confirmation!
  update!(status: :waiting_retailer_confirmation)
end

#mark_waiting_supplier_confirmation!Object



192
193
194
# File 'app/models/dscf/marketplace/order.rb', line 192

def mark_waiting_supplier_confirmation!
  update!(status: :waiting_supplier_confirmation)
end

#requires_delivery_order?Boolean

Returns:

  • (Boolean)


148
149
150
# File 'app/models/dscf/marketplace/order.rb', line 148

def requires_delivery_order?
  delivery? && !completed?
end

#retailer_can_confirm?Boolean

Returns:

  • (Boolean)


200
201
202
# File 'app/models/dscf/marketplace/order.rb', line 200

def retailer_can_confirm?
  waiting_retailer_confirmation? || confirmed? # allow re-confirm safety
end

#self_pickup?Boolean

Fulfillment type methods

Returns:

  • (Boolean)


140
141
142
# File 'app/models/dscf/marketplace/order.rb', line 140

def self_pickup?
  fulfillment_type == "self_pickup"
end

#supplierObject



131
132
133
134
135
136
137
# File 'app/models/dscf/marketplace/order.rb', line 131

def supplier
  if rfq_based?
    quotation&.business
  elsif direct_listing?
    listing&.business
  end
end

#supplier_confirmation_complete?Boolean

Returns:

  • (Boolean)


204
205
206
207
# File 'app/models/dscf/marketplace/order.rb', line 204

def supplier_confirmation_complete?
  # simplistic: all items have source and are confirmed or cancelled
  order_items.all? { |i| i.source_id.present? && (i.status.to_s == "confirmed" || i.status.to_s == "cancelled") }
end

#total_amountObject



121
122
123
124
125
126
127
128
129
# File 'app/models/dscf/marketplace/order.rb', line 121

def total_amount
  # Return stored value if it exists and is greater than 0, otherwise calculate
  stored_value = super
  calculated_value = order_items.sum { |item| item.quantity * item.unit_price }

  # Return stored value if it's set and valid, otherwise return calculated value
  return stored_value if stored_value.present? && stored_value > 0
  calculated_value
end

#validating?Boolean

Workflow helpers for Sprint 2 order validation + splitting

Returns:

  • (Boolean)


176
177
178
# File 'app/models/dscf/marketplace/order.rb', line 176

def validating?
  pending? || status.to_s == "processing"
end

#validation_summaryObject



184
185
186
# File 'app/models/dscf/marketplace/order.rb', line 184

def validation_summary
  order_items.group_by(&:validation_status).transform_values(&:count)
end