Class: SpreeCmCommissioner::TransitOrder::Create

Inherits:
Object
  • Object
show all
Includes:
Spree::ServiceModule::Base
Defined in:
app/services/spree_cm_commissioner/transit_order/create.rb

Instance Method Summary collapse

Instance Method Details

#build_guests_for!(line_item, seat_selections) ⇒ Object



96
97
98
99
100
101
102
103
104
105
106
107
108
# File 'app/services/spree_cm_commissioner/transit_order/create.rb', line 96

def build_guests_for!(line_item, seat_selections)
  block_ids = seat_selections.flat_map(&:block_ids)

  if block_ids.any? && block_ids.size != line_item.quantity
    raise StandardError, "Number of blocks (#{block_ids.size}) does not match quantity (#{line_item.quantity})"
  end

  Array.new(line_item.quantity) do |index|
    line_item.guests.new(block_id: block_ids[index])
  end

  line_item
end

#build_line_items_for!(leg, order, date) ⇒ Object



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
# File 'app/services/spree_cm_commissioner/transit_order/create.rb', line 67

def build_line_items_for!(leg, order, date)
  trip = SpreeCmCommissioner::Trip.find(leg.trip_id)
  trip_stops = trip.trip_stops.where(id: [leg.boarding_trip_stop_id, leg.drop_off_trip_stop_id]).index_by(&:id)

  from_date, to_date = calculate_line_item_duration!(
    date: date,
    departure_time: trip_stops[leg.boarding_trip_stop_id].departure_time,
    arrival_time: trip_stops[leg.drop_off_trip_stop_id].arrival_time
  )

  leg.seat_selections.group_by(&:variant_id).map do |variant_id, seat_selections|
    line_item = order.line_items.new(
      product_type: :transit,
      from_date: from_date,
      to_date: to_date,
      variant_id: variant_id,
      quantity: seat_selections.sum(&:quantity),
      private_metadata: {
        direction: leg.direction,
        trip_id: leg.trip_id.to_s,
        boarding_trip_stop_id: leg.boarding_trip_stop_id.to_s,
        drop_off_trip_stop_id: leg.drop_off_trip_stop_id.to_s
      }
    )

    build_guests_for!(line_item, seat_selections)
  end
end

#build_line_items_for_legs!(order:, legs:, initial_date:) ⇒ Object

Build line items for each leg, using the previous leg’s to_date as the next leg’s date, or the initial date for the first leg.



52
53
54
55
56
57
58
59
60
61
62
63
64
65
# File 'app/services/spree_cm_commissioner/transit_order/create.rb', line 52

def build_line_items_for_legs!(order:, legs:, initial_date:)
  all_line_items = []
  current_leg_date = initial_date

  legs.each do |leg|
    leg_line_items = build_line_items_for!(leg, order, current_leg_date)
    leg_line_items = insert_saved_guests_per_line_items_leg(leg_line_items)

    all_line_items.concat(leg_line_items)
    current_leg_date = leg_line_items.last.to_date.to_date if leg_line_items.any?
  end

  all_line_items
end

#calculate_line_item_duration!(date:, departure_time:, arrival_time:) ⇒ Object

Raises:

  • (StandardError)


121
122
123
124
125
126
127
128
129
130
131
132
133
134
# File 'app/services/spree_cm_commissioner/transit_order/create.rb', line 121

def calculate_line_item_duration!(date:, departure_time:, arrival_time:)
  raise StandardError, 'Departure or arrival time in trip stop is missing' if departure_time.blank? || arrival_time.blank?
  raise StandardError, 'Arrival time cannot be before departure time' if arrival_time < departure_time

  trip_duration_in_seconds = arrival_time - departure_time

  # The input `date` is in local time (e.g., 10-10-2022).
  # Combine it with the departure_time in Rails default timezone so that
  # the resulting from_date stays on the intended local calendar day when stored in UTC.
  from_date = Time.zone.local(date.year, date.month, date.day, departure_time.hour, departure_time.min, departure_time.sec)
  to_date = from_date + trip_duration_in_seconds.seconds

  [from_date, to_date]
end

#call(outbound_date:, inbound_date:, outbound_legs:, inbound_legs: [], user: nil) ⇒ Object



19
20
21
22
23
24
25
26
27
28
# File 'app/services/spree_cm_commissioner/transit_order/create.rb', line 19

def call(outbound_date:, inbound_date:, outbound_legs:, inbound_legs: [], user: nil)
  return failure(nil, 'Outbound legs are missing') if outbound_legs.blank?

  begin
    order = create_order!(outbound_date, inbound_date, outbound_legs, inbound_legs, user)
    success(order: order)
  rescue StandardError => e
    failure(nil, e.message)
  end
end

#create_order!(outbound_date, inbound_date, outbound_legs, inbound_legs, user) ⇒ Object

Raises:

  • (StandardError)


30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
# File 'app/services/spree_cm_commissioner/transit_order/create.rb', line 30

def create_order!(outbound_date, inbound_date, outbound_legs, inbound_legs, user)
  order = Spree::Order.new(state: 'cart', use_billing: true, user: user)

  outbound_line_items = build_line_items_for_legs!(order: order, legs: outbound_legs, initial_date: outbound_date)
  inbound_line_items = inbound_legs.blank? ? [] : build_line_items_for_legs!(order: order, legs: inbound_legs, initial_date: inbound_date)

  outbound_qty = outbound_line_items.sum(&:quantity)
  inbound_qty = inbound_line_items.sum(&:quantity)

  raise StandardError, 'Outbound & inbound line item quantities do not match' if inbound_line_items.any? && outbound_qty != inbound_qty

  trip_ids = (outbound_legs.map(&:trip_id) + inbound_legs.map(&:trip_id)).uniq
  order.preload_trip_ids = trip_ids

  raise StandardError, order.errors.full_messages.to_sentence unless order.save

  order.update_with_updater!
  order
end

#insert_saved_guests_per_line_items_leg(line_items) ⇒ Object



110
111
112
113
114
115
116
117
118
119
# File 'app/services/spree_cm_commissioner/transit_order/create.rb', line 110

def insert_saved_guests_per_line_items_leg(line_items)
  line_items.flat_map(&:guests).each_with_index do |guest, index|
    @saved_guests ||= []
    @saved_guests << SpreeCmCommissioner::SavedGuest.new if @saved_guests[index].blank?

    guest.saved_guest = @saved_guests[index]
  end

  line_items
end