Class: SpreeCmCommissioner::Integrations::BookMeBusV1::Resources::SeatLayout
- Inherits:
-
Object
- Object
- SpreeCmCommissioner::Integrations::BookMeBusV1::Resources::SeatLayout
- Defined in:
- app/services/spree_cm_commissioner/integrations/book_me_bus_v1/resources/seat_layout.rb
Overview
SeatLayout resource wraps BookMeBus seat layout API response
This class provides methods to extract and transform seat layout data from the BookMeBus API into a format suitable for BookMe+ internal models.
BookMeBus API Structure:
layouts: Hash keyed by stop_id (e.g., "233")
Each stop contains layers (e.g., "BUS", "UPPER_DECK")
Each layer is a 2D array [rows][columns]
Each cell is either a seat object or null (aisle)
Example API Response:
{
"id" => "2adea8ac4cf6a75db037f698a9126914",
"attributes" => {
"from_stop_id" => 233,
"to_stop_id" => 237,
"layouts" => {
"233" => {
"BUS" => [
[{"label" => "1", "seat_type" => 0, "status" => 0}, {"label" => "2"}, nil, {"label" => "3"}],
[{"label" => "5"}, {"label" => "6"}, nil, {"label" => "7"}]
]
}
}
}
}
Visual Layout Example (2 rows × 4 columns with aisle):
Row 0: [1] [2] [aisle] [3] [4]
Row 1: [5] [6] [aisle] [7] [8]
Constant Summary collapse
- BLOCK_WIDTH =
Layout rendering constants
50- BLOCK_HEIGHT =
50- BLOCK_GAP =
10- LAYER_Y_OFFSET =
1000- DEFAULT_CANVAS_WIDTH =
400- DEFAULT_CANVAS_HEIGHT =
400
Instance Attribute Summary collapse
-
#duration ⇒ Object
readonly
Returns the value of attribute duration.
-
#from_stop_id ⇒ Object
readonly
Returns the value of attribute from_stop_id.
-
#id ⇒ Object
readonly
Returns the value of attribute id.
-
#layouts ⇒ Object
readonly
Returns the value of attribute layouts.
-
#min_number_of_seats_remaining ⇒ Object
readonly
Returns the value of attribute min_number_of_seats_remaining.
-
#number_of_seats_remaining ⇒ Object
readonly
Returns the value of attribute number_of_seats_remaining.
-
#on_date ⇒ Object
readonly
Returns the value of attribute on_date.
-
#stop_times ⇒ Object
readonly
Returns the value of attribute stop_times.
-
#to_stop_id ⇒ Object
readonly
Returns the value of attribute to_stop_id.
-
#trip ⇒ Object
readonly
Returns the value of attribute trip.
Class Method Summary collapse
Instance Method Summary collapse
-
#available_seats_count ⇒ Integer
Get count of available seats (status = 0).
-
#column_count ⇒ Integer
Get the number of columns in the layout (including aisles).
-
#initialize(data) ⇒ SeatLayout
constructor
Initialize seat layout from BookMeBus API response.
-
#primary_layout ⇒ Hash
Get the primary layout (from first stop).
-
#row_count ⇒ Integer
Get the number of rows in the layout.
-
#seat_types ⇒ Array<Integer>
Get unique seat types present in the layout.
-
#seats ⇒ Array<Seat>
Get all seats from the primary layout as a flat array.
-
#seats_by_type ⇒ Hash<Integer, Array<Seat>>
Get seats grouped by their seat_type.
-
#to_internal_blocks_attributes(seat_layout) ⇒ Array<Hash>
Convert BookMeBus seat layout to BookMe+ Block attributes.
Constructor Details
#initialize(data) ⇒ SeatLayout
Initialize seat layout from BookMeBus API response
Example:
data = {
'id' => '2adea8ac4cf6a75db037f698a9126914',
'attributes' => {
'from_stop_id' => 233,
'layouts' => {"233" => {"BUS" => [[...]]}}
}
}
seat_layout = SeatLayout.new(data)
65 66 67 68 69 70 71 72 73 74 75 76 77 78 |
# File 'app/services/spree_cm_commissioner/integrations/book_me_bus_v1/resources/seat_layout.rb', line 65 def initialize(data) attributes = data['attributes'] || data @id = data['id'] @from_stop_id = attributes['from_stop_id'] @to_stop_id = attributes['to_stop_id'] @on_date = attributes['on_date'] @duration = attributes['duration'] @min_number_of_seats_remaining = attributes['min_number_of_seats_remaining'] @number_of_seats_remaining = attributes['number_of_seats_remaining'] || {} @layouts = attributes['layouts'] || {} @stop_times = attributes['stop_times'] || [] @trip = attributes['trip'] || {} end |
Instance Attribute Details
#duration ⇒ Object (readonly)
Returns the value of attribute duration.
47 48 49 |
# File 'app/services/spree_cm_commissioner/integrations/book_me_bus_v1/resources/seat_layout.rb', line 47 def duration @duration end |
#from_stop_id ⇒ Object (readonly)
Returns the value of attribute from_stop_id.
47 48 49 |
# File 'app/services/spree_cm_commissioner/integrations/book_me_bus_v1/resources/seat_layout.rb', line 47 def from_stop_id @from_stop_id end |
#id ⇒ Object (readonly)
Returns the value of attribute id.
47 48 49 |
# File 'app/services/spree_cm_commissioner/integrations/book_me_bus_v1/resources/seat_layout.rb', line 47 def id @id end |
#layouts ⇒ Object (readonly)
Returns the value of attribute layouts.
47 48 49 |
# File 'app/services/spree_cm_commissioner/integrations/book_me_bus_v1/resources/seat_layout.rb', line 47 def layouts @layouts end |
#min_number_of_seats_remaining ⇒ Object (readonly)
Returns the value of attribute min_number_of_seats_remaining.
47 48 49 |
# File 'app/services/spree_cm_commissioner/integrations/book_me_bus_v1/resources/seat_layout.rb', line 47 def min_number_of_seats_remaining @min_number_of_seats_remaining end |
#number_of_seats_remaining ⇒ Object (readonly)
Returns the value of attribute number_of_seats_remaining.
47 48 49 |
# File 'app/services/spree_cm_commissioner/integrations/book_me_bus_v1/resources/seat_layout.rb', line 47 def number_of_seats_remaining @number_of_seats_remaining end |
#on_date ⇒ Object (readonly)
Returns the value of attribute on_date.
47 48 49 |
# File 'app/services/spree_cm_commissioner/integrations/book_me_bus_v1/resources/seat_layout.rb', line 47 def on_date @on_date end |
#stop_times ⇒ Object (readonly)
Returns the value of attribute stop_times.
47 48 49 |
# File 'app/services/spree_cm_commissioner/integrations/book_me_bus_v1/resources/seat_layout.rb', line 47 def stop_times @stop_times end |
#to_stop_id ⇒ Object (readonly)
Returns the value of attribute to_stop_id.
47 48 49 |
# File 'app/services/spree_cm_commissioner/integrations/book_me_bus_v1/resources/seat_layout.rb', line 47 def to_stop_id @to_stop_id end |
#trip ⇒ Object (readonly)
Returns the value of attribute trip.
47 48 49 |
# File 'app/services/spree_cm_commissioner/integrations/book_me_bus_v1/resources/seat_layout.rb', line 47 def trip @trip end |
Class Method Details
.from_json_api_single(data) ⇒ Object
80 81 82 83 84 |
# File 'app/services/spree_cm_commissioner/integrations/book_me_bus_v1/resources/seat_layout.rb', line 80 def self.from_json_api_single(data) return nil unless data.is_a?(Hash) && data['data'].is_a?(Hash) new(data['data']) end |
Instance Method Details
#available_seats_count ⇒ Integer
Get count of available seats (status = 0)
Example:
# 45 total seats, 5 booked (status=1)
seat_layout.available_seats_count # => 40
# All seats available
seat_layout.available_seats_count # => 45
216 217 218 |
# File 'app/services/spree_cm_commissioner/integrations/book_me_bus_v1/resources/seat_layout.rb', line 216 def available_seats_count seats.count(&:available?) end |
#column_count ⇒ Integer
Get the number of columns in the layout (including aisles)
Example:
# Layout: [seat, seat, aisle, seat, seat]
seat_layout.column_count # => 5
# Layout: [seat, seat, aisle, seat]
seat_layout.column_count # => 4
200 201 202 203 |
# File 'app/services/spree_cm_commissioner/integrations/book_me_bus_v1/resources/seat_layout.rb', line 200 def column_count first_row = primary_layout.values.first&.first first_row&.size || 0 end |
#primary_layout ⇒ Hash
Get the primary layout (from first stop)
Example:
seat_layout.layouts
# => {"233" => {"BUS" => [[seat1, seat2, nil, seat3], [seat5, seat6, nil, seat7]]}}
seat_layout.primary_layout
# => {"BUS" => [[seat1, seat2, nil, seat3], [seat5, seat6, nil, seat7]]}
Visual:
BUS Layer:
Row 0: [1] [2] [aisle] [3] [4]
Row 1: [5] [6] [aisle] [7] [8]
102 103 104 105 106 |
# File 'app/services/spree_cm_commissioner/integrations/book_me_bus_v1/resources/seat_layout.rb', line 102 def primary_layout return {} if layouts.empty? layouts[layouts.keys.first] || {} end |
#row_count ⇒ Integer
Get the number of rows in the layout
Example:
# Layout with 12 rows:
# Row 0: [1] [2] [aisle] [3] [4]
# Row 1: [5] [6] [aisle] [7] [8]
# ...
# Row 11: [45] [46] [aisle] [47] [48]
seat_layout.row_count # => 12
185 186 187 |
# File 'app/services/spree_cm_commissioner/integrations/book_me_bus_v1/resources/seat_layout.rb', line 185 def row_count primary_layout.values.first&.size || 0 end |
#seat_types ⇒ Array<Integer>
Get unique seat types present in the layout
Seat Types:
0 = Regular seat
1 = VIP/Sleeper seat
2 = Premium seat
Example:
# Layout with mixed seat types
seat_layout.seat_types # => [0, 1, 2]
# Layout with only regular seats
seat_layout.seat_types # => [0]
147 148 149 |
# File 'app/services/spree_cm_commissioner/integrations/book_me_bus_v1/resources/seat_layout.rb', line 147 def seat_types seats.map(&:seat_type).uniq.sort end |
#seats ⇒ Array<Seat>
Get all seats from the primary layout as a flat array
Extracts all seat objects from the 2D layout, skipping aisles (nil values). Each seat is enriched with row and column position.
Example:
seat_layout.seats
# => [
# #<Seat label="1", row=0, column=0, seat_type=0, status=0>,
# #<Seat label="2", row=0, column=1, seat_type=0, status=0>,
# #<Seat label="3", row=0, column=3, seat_type=0, status=0>, # column 2 was aisle
# #<Seat label="5", row=1, column=0, seat_type=0, status=0>,
# ...
# ]
seat_layout.seats.count # => 45 (total seats, excluding aisles)
127 128 129 |
# File 'app/services/spree_cm_commissioner/integrations/book_me_bus_v1/resources/seat_layout.rb', line 127 def seats @seats ||= extract_seats_from_layout(primary_layout) end |
#seats_by_type ⇒ Hash<Integer, Array<Seat>>
Get seats grouped by their seat_type
Useful for processing different seat types separately or counting seats per type.
Example:
seat_layout.seats_by_type
# => {
# 0 => [seat1, seat2, seat3, ...], # 40 regular seats
# 1 => [seat41, seat42, ...] # 5 VIP seats
# }
# Count seats per type
seat_layout.seats_by_type.transform_values(&:count)
# => {0 => 40, 1 => 5}
168 169 170 |
# File 'app/services/spree_cm_commissioner/integrations/book_me_bus_v1/resources/seat_layout.rb', line 168 def seats_by_type seats.group_by(&:seat_type) end |
#to_internal_blocks_attributes(seat_layout) ⇒ Array<Hash>
Convert BookMeBus seat layout to BookMe+ Block attributes
Transforms the 2D seat layout into an array of block hashes ready for creating SpreeCmCommissioner::Block records. Each seat becomes a block with calculated x,y coordinates based on its row/column position.
Coordinate Calculation:
x = column_index * (block_width + gap)
y = row_index * (block_height + gap)
Example:
internal_layout = SpreeCmCommissioner::SeatLayout.create!(
name: "VIP Bus Layout",
layoutable: vehicle_type
)
blocks_attrs = external_seat_layout.to_internal_blocks_attributes(internal_layout)
# => [
# {
# label: "1",
# block_type: :seat,
# width: 50, height: 50,
# x: 0, y: 0, # Row 0, Column 0
# rotation: 0,
# seat_layout: internal_layout
# },
# {
# label: "2",
# block_type: :seat,
# width: 50, height: 50,
# x: 60, y: 0, # Row 0, Column 1 (50 + 10 gap)
# rotation: 0,
# seat_layout: internal_layout
# },
# # Column 2 (aisle) is skipped
# {
# label: "3",
# block_type: :seat,
# width: 50, height: 50,
# x: 180, y: 0, # Row 0, Column 3
# rotation: 0,
# seat_layout: internal_layout
# }
# ]
# Create blocks
blocks_attrs.each { |attrs| SpreeCmCommissioner::Block.create!(attrs) }
Visual Layout:
(0,0) (60,0) (180,0) (240,0)
[1] [2] [aisle] [3] [4]
(0,60) (60,60) (180,60) (240,60)
[5] [6] [aisle] [7] [8]
278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 |
# File 'app/services/spree_cm_commissioner/integrations/book_me_bus_v1/resources/seat_layout.rb', line 278 def to_internal_blocks_attributes(seat_layout) blocks = [] offsets = calculate_centering_offsets(seat_layout) current_layer_offset = 0 primary_layout.each do |layer_name, rows| process_layer_rows(rows, layer_name, blocks, offsets, current_layer_offset, seat_layout) # Offset next layer by 1000px to prevent overlap # This allows double-decker buses to have separate visual layers current_layer_offset += LAYER_Y_OFFSET end blocks end |