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



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

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



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

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



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

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



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

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)


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

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

#calculate_total_amountObject



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

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

#can_be_completed?Boolean

Returns:

  • (Boolean)


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

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



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

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)


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

def delivery?
  fulfillment_type == "delivery"
end

#mark_splitting!Object



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

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

#mark_waiting_retailer_confirmation!Object



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

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

#mark_waiting_supplier_confirmation!Object



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

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

#requires_delivery_order?Boolean

Returns:

  • (Boolean)


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

def requires_delivery_order?
  delivery? && !completed?
end

#retailer_can_confirm?Boolean

Returns:

  • (Boolean)


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

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

#self_pickup?Boolean

Fulfillment type methods

Returns:

  • (Boolean)


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

def self_pickup?
  fulfillment_type == "self_pickup"
end

#supplierObject



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

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

#supplier_confirmation_complete?Boolean

Returns:

  • (Boolean)


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

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



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

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)


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

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

#validation_summaryObject



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

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