spree_cm_commissioner 2.0.3.pre.pre5 → 2.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (202) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/test_and_build_gem.yml +2 -16
  3. data/.gitignore +1 -2
  4. data/Gemfile.lock +1 -28
  5. data/Rakefile +4 -33
  6. data/app/assets/stylesheets/spree_cm_commissioner/backend/calendar.scss +11 -8
  7. data/app/controllers/concerns/spree_cm_commissioner/transit/taxon_bitwise.rb +44 -0
  8. data/app/controllers/spree/admin/stock_managements_controller.rb +1 -63
  9. data/app/controllers/spree/api/v2/operator/event_charts_controller.rb +2 -8
  10. data/app/controllers/spree/api/v2/storefront/accommodations_controller.rb +31 -14
  11. data/app/controllers/spree/api/v2/storefront/queue_cart/line_items_controller.rb +2 -2
  12. data/app/finders/spree_cm_commissioner/line_items/find_by_variant_decorator.rb +20 -0
  13. data/app/jobs/spree_cm_commissioner/application_job.rb +0 -20
  14. data/app/jobs/spree_cm_commissioner/application_unique_job.rb +0 -20
  15. data/app/models/concerns/spree_cm_commissioner/line_item_durationable.rb +15 -18
  16. data/app/models/concerns/spree_cm_commissioner/line_item_guests_concern.rb +15 -29
  17. data/app/models/concerns/spree_cm_commissioner/option_type_attr_type.rb +12 -2
  18. data/app/models/concerns/spree_cm_commissioner/order_state_machine.rb +0 -39
  19. data/app/models/concerns/spree_cm_commissioner/product_delegation.rb +3 -1
  20. data/app/models/concerns/spree_cm_commissioner/product_type.rb +0 -10
  21. data/app/models/concerns/spree_cm_commissioner/route_type.rb +1 -1
  22. data/app/models/concerns/spree_cm_commissioner/taxon_kind.rb +1 -1
  23. data/app/models/spree_cm_commissioner/address_decorator.rb +2 -22
  24. data/app/models/spree_cm_commissioner/branch.rb +12 -0
  25. data/app/models/spree_cm_commissioner/guest.rb +0 -35
  26. data/app/models/spree_cm_commissioner/line_item_decorator.rb +78 -47
  27. data/app/models/spree_cm_commissioner/line_item_seat.rb +10 -0
  28. data/app/models/spree_cm_commissioner/notification_taxon.rb +1 -1
  29. data/app/models/spree_cm_commissioner/option_type_decorator.rb +11 -1
  30. data/app/models/spree_cm_commissioner/option_value_vehicle_type.rb +8 -0
  31. data/app/models/spree_cm_commissioner/order_decorator.rb +1 -31
  32. data/app/models/spree_cm_commissioner/place.rb +4 -1
  33. data/app/models/spree_cm_commissioner/product_decorator.rb +6 -10
  34. data/app/models/spree_cm_commissioner/service_calendar.rb +2 -0
  35. data/app/models/spree_cm_commissioner/state_decorator.rb +1 -0
  36. data/app/models/spree_cm_commissioner/stock/availability_checker.rb +25 -26
  37. data/app/models/spree_cm_commissioner/stock/availability_validator_decorator.rb +1 -2
  38. data/app/models/spree_cm_commissioner/stock/line_item_availability_checker.rb +3 -3
  39. data/app/models/spree_cm_commissioner/stock_item_decorator.rb +0 -17
  40. data/app/models/spree_cm_commissioner/stop.rb +23 -0
  41. data/app/models/spree_cm_commissioner/taxon_decorator.rb +1 -0
  42. data/app/models/spree_cm_commissioner/taxonomy_decorator.rb +6 -0
  43. data/app/models/spree_cm_commissioner/trip.rb +10 -17
  44. data/app/models/spree_cm_commissioner/trip_connection.rb +5 -5
  45. data/app/models/spree_cm_commissioner/trip_stop.rb +21 -10
  46. data/app/models/spree_cm_commissioner/variant_decorator.rb +47 -37
  47. data/app/models/spree_cm_commissioner/variant_options.rb +23 -0
  48. data/app/models/spree_cm_commissioner/vehicle.rb +16 -11
  49. data/app/models/spree_cm_commissioner/vehicle_seat.rb +11 -0
  50. data/app/models/spree_cm_commissioner/vehicle_type.rb +76 -0
  51. data/app/models/spree_cm_commissioner/vendor_decorator.rb +14 -11
  52. data/app/models/spree_cm_commissioner/vendor_place.rb +3 -13
  53. data/app/models/spree_cm_commissioner/vendor_stop.rb +10 -0
  54. data/app/queries/spree_cm_commissioner/trip_query.rb +131 -110
  55. data/app/queries/spree_cm_commissioner/trip_search_query.rb +76 -0
  56. data/app/queries/spree_cm_commissioner/variant_availability/non_permanent_stock_query.rb +45 -0
  57. data/app/queries/spree_cm_commissioner/variant_availability/permanent_stock_query.rb +55 -0
  58. data/app/queries/spree_cm_commissioner/vendor_stop_place_query.rb +54 -0
  59. data/app/request_schemas/spree_cm_commissioner/accommodation_request_schema.rb +0 -3
  60. data/app/request_schemas/spree_cm_commissioner/application_request_schema.rb +1 -1
  61. data/app/serializers/spree/v2/storefront/accommodation_serializer.rb +0 -2
  62. data/app/serializers/spree/v2/storefront/line_item_serializer_decorator.rb +0 -1
  63. data/app/services/spree_cm_commissioner/vehicle_option_value_creator.rb +11 -0
  64. data/app/views/spree/admin/stock_managements/_variant_stock_items.html.erb +2 -7
  65. data/app/views/spree/admin/stock_managements/index.html.erb +6 -55
  66. data/config/initializers/spree_permitted_attributes.rb +0 -5
  67. data/config/routes.rb +2 -24
  68. data/db/migrate/20240202080634_update_counter_cache_of_vehicle_type.rb +1 -3
  69. data/docker-compose.yml +1 -1
  70. data/lib/cm_app_logger.rb +4 -11
  71. data/lib/generators/spree_cm_commissioner/install/install_generator.rb +11 -14
  72. data/lib/generators/spree_cm_commissioner/install/templates/app/javascript/{spree_dashboard/spree_cm_commissioner → spree_cm_commissioner}/utilities.js +0 -4
  73. data/lib/spree_cm_commissioner/calendar_event.rb +1 -11
  74. data/lib/spree_cm_commissioner/test_helper/factories/branch_factory.rb +12 -0
  75. data/lib/spree_cm_commissioner/test_helper/factories/departure_time_option_type_factory.rb +8 -0
  76. data/lib/spree_cm_commissioner/test_helper/factories/duration_option_type_factory.rb +8 -0
  77. data/lib/spree_cm_commissioner/test_helper/factories/guest_factory.rb +0 -10
  78. data/lib/spree_cm_commissioner/test_helper/factories/homepage_section_relatable_factory.rb +1 -1
  79. data/lib/spree_cm_commissioner/test_helper/factories/line_item_factory.rb +1 -1
  80. data/lib/spree_cm_commissioner/test_helper/factories/line_item_seat_factory.rb +7 -0
  81. data/lib/spree_cm_commissioner/test_helper/factories/option_type_factory.rb +30 -6
  82. data/lib/spree_cm_commissioner/test_helper/factories/order_factory.rb +36 -0
  83. data/lib/spree_cm_commissioner/test_helper/factories/product_factory.rb +34 -18
  84. data/lib/spree_cm_commissioner/test_helper/factories/stock_location_factory.rb +2 -2
  85. data/lib/spree_cm_commissioner/test_helper/factories/stop_factory.rb +14 -0
  86. data/lib/spree_cm_commissioner/test_helper/factories/transit_place_factory.rb +8 -0
  87. data/lib/spree_cm_commissioner/test_helper/factories/trip_factory.rb +3 -11
  88. data/lib/spree_cm_commissioner/test_helper/factories/variant_factory.rb +19 -41
  89. data/lib/spree_cm_commissioner/test_helper/factories/vehicle_factory.rb +1 -1
  90. data/lib/spree_cm_commissioner/test_helper/factories/vehicle_option_type_factory.rb +8 -0
  91. data/lib/spree_cm_commissioner/test_helper/factories/vehicle_type_factory.rb +96 -0
  92. data/lib/spree_cm_commissioner/test_helper/factories/vendor_factory.rb +1 -6
  93. data/lib/spree_cm_commissioner/test_helper/factories/vendor_place_factory.rb +1 -13
  94. data/lib/spree_cm_commissioner/trip_query_result.rb +0 -16
  95. data/lib/spree_cm_commissioner/trip_result.rb +10 -12
  96. data/lib/spree_cm_commissioner/trip_seat_layout_result.rb +11 -0
  97. data/lib/spree_cm_commissioner/version.rb +1 -1
  98. data/lib/spree_cm_commissioner.rb +1 -37
  99. data/spree_cm_commissioner.gemspec +0 -7
  100. metadata +28 -163
  101. data/app/controllers/spree/admin/inventory_items_controller.rb +0 -83
  102. data/app/controllers/spree/api/v2/storefront/accommodations/variants_controller.rb +0 -42
  103. data/app/controllers/spree/api/v2/storefront/trip_search_controller.rb +0 -60
  104. data/app/finders/spree_cm_commissioner/accommodations/find.rb +0 -37
  105. data/app/finders/spree_cm_commissioner/accommodations/find_variant.rb +0 -32
  106. data/app/interactors/spree_cm_commissioner/ensure_correct_product_type.rb +0 -40
  107. data/app/interactors/spree_cm_commissioner/inventory_item_syncer.rb +0 -25
  108. data/app/interactors/spree_cm_commissioner/stock/inventory_item_resetter.rb +0 -44
  109. data/app/interactors/spree_cm_commissioner/stock/inventory_items_adjuster.rb +0 -13
  110. data/app/interactors/spree_cm_commissioner/stock/inventory_items_generator.rb +0 -15
  111. data/app/interactors/spree_cm_commissioner/stock/permanent_inventory_items_generator.rb +0 -75
  112. data/app/interactors/spree_cm_commissioner/stock/stock_movement_creator.rb +0 -32
  113. data/app/interactors/spree_cm_commissioner/taxi_trip_creator.rb +0 -66
  114. data/app/interactors/spree_cm_commissioner/transit/draft_order_creator.rb +0 -119
  115. data/app/interactors/spree_cm_commissioner/variant_block_updater.rb +0 -62
  116. data/app/interactors/spree_cm_commissioner/vehicle_updater.rb +0 -41
  117. data/app/jobs/spree_cm_commissioner/ensure_correct_product_type_job.rb +0 -7
  118. data/app/jobs/spree_cm_commissioner/inventory_item_syncer_job.rb +0 -7
  119. data/app/jobs/spree_cm_commissioner/stock/inventory_items_adjuster_job.rb +0 -11
  120. data/app/jobs/spree_cm_commissioner/stock/inventory_items_generator_job.rb +0 -11
  121. data/app/jobs/spree_cm_commissioner/stock/permanent_inventory_items_generator_job.rb +0 -9
  122. data/app/models/concerns/spree_cm_commissioner/line_item_transitable.rb +0 -89
  123. data/app/models/concerns/spree_cm_commissioner/order_seatable.rb +0 -44
  124. data/app/models/concerns/spree_cm_commissioner/vehicle_type.rb +0 -11
  125. data/app/models/spree_cm_commissioner/block.rb +0 -43
  126. data/app/models/spree_cm_commissioner/inventory.rb +0 -11
  127. data/app/models/spree_cm_commissioner/inventory_item.rb +0 -69
  128. data/app/models/spree_cm_commissioner/price_decorator.rb +0 -9
  129. data/app/models/spree_cm_commissioner/redis_stock/cached_inventory_items_builder.rb +0 -41
  130. data/app/models/spree_cm_commissioner/redis_stock/inventory_updater.rb +0 -126
  131. data/app/models/spree_cm_commissioner/redis_stock/line_items_cached_inventory_items_builder.rb +0 -36
  132. data/app/models/spree_cm_commissioner/redis_stock/variant_cached_inventory_items_builder.rb +0 -25
  133. data/app/models/spree_cm_commissioner/reserved_block.rb +0 -30
  134. data/app/models/spree_cm_commissioner/saved_guest.rb +0 -13
  135. data/app/models/spree_cm_commissioner/seat_layout.rb +0 -20
  136. data/app/models/spree_cm_commissioner/seat_section.rb +0 -16
  137. data/app/models/spree_cm_commissioner/seats/blocks_canceler.rb +0 -30
  138. data/app/models/spree_cm_commissioner/seats/blocks_holder.rb +0 -53
  139. data/app/models/spree_cm_commissioner/seats/blocks_reserver.rb +0 -49
  140. data/app/models/spree_cm_commissioner/seats/errors/blocks_are_on_hold_by_other_guest.rb +0 -4
  141. data/app/models/spree_cm_commissioner/seats/errors/blocks_are_reserved_by_other_guest.rb +0 -4
  142. data/app/models/spree_cm_commissioner/seats/errors/blocks_are_reserved_by_same_guest.rb +0 -4
  143. data/app/models/spree_cm_commissioner/seats/errors/unable_to_save_reserved_block_record.rb +0 -4
  144. data/app/models/spree_cm_commissioner/stock/order_availability_checker.rb +0 -44
  145. data/app/models/spree_cm_commissioner/variant_block.rb +0 -17
  146. data/app/request_schemas/spree_cm_commissioner/trip_search_request_schema.rb +0 -20
  147. data/app/request_schemas/spree_cm_commissioner/variant_request_schema.rb +0 -19
  148. data/app/serializers/spree/v2/storefront/amenity_serializer.rb +0 -15
  149. data/app/serializers/spree/v2/storefront/trip_query_result_serializer.rb +0 -14
  150. data/app/serializers/spree/v2/storefront/trip_result_serializer.rb +0 -16
  151. data/app/serializers/spree/v2/storefront/trip_vehicle_serializer.rb +0 -11
  152. data/app/serializers/spree/v2/storefront/trip_vendor_serializer.rb +0 -13
  153. data/app/views/spree/admin/inventory_items/show.html.erb +0 -72
  154. data/app/views/spree/admin/stock_managements/calendar.html.erb +0 -56
  155. data/config/initializers/paper_trail.rb +0 -1
  156. data/db/migrate/20250122000000_move_route_type_from_vehicles_to_trips.rb +0 -7
  157. data/db/migrate/20250304293518_create_cm_inventory_items.rb +0 -21
  158. data/db/migrate/20250429094228_add_lock_version_to_cm_inventory_items.rb +0 -5
  159. data/db/migrate/20250502025848_add_index_to_spree_products.rb +0 -5
  160. data/db/migrate/20250502030001_add_product_type_to_spree_variants.rb +0 -5
  161. data/db/migrate/20250502030002_add_product_type_to_spree_line_items.rb +0 -5
  162. data/db/migrate/20250603035256_add_inventory_item_to_spree_prices.rb +0 -7
  163. data/db/migrate/20250619073724_drop_table_cm_line_item_seats.rb +0 -5
  164. data/db/migrate/20250619073812_drop_table_cm_vehicle_seats.rb +0 -5
  165. data/db/migrate/20250619073844_drop_table_cm_vehicle_types.rb +0 -9
  166. data/db/migrate/20250619073957_drop_table_cm_option_value_vehicle_types.rb +0 -5
  167. data/db/migrate/20250619082354_remove_unnecessary_fields_from_cm_places.rb +0 -9
  168. data/db/migrate/20250619082736_remove_route_type_from_spree_products.rb +0 -5
  169. data/db/migrate/20250619083055_remove_unnecessary_fields_from_spree_taxons.rb +0 -5
  170. data/db/migrate/20250620083055_remove_variant_id_from_cm_trips.rb +0 -5
  171. data/db/migrate/20250620090000_update_cm_trip_connections_to_use_cm_trips.rb +0 -6
  172. data/db/migrate/20250620090001_create_cm_seat_layouts.rb +0 -17
  173. data/db/migrate/20250620090002_create_cm_seat_sections.rb +0 -18
  174. data/db/migrate/20250620090003_create_cm_blocks.rb +0 -18
  175. data/db/migrate/20250624091005_create_cm_reserved_blocks.rb +0 -29
  176. data/db/migrate/20250626083642_create_cm_variant_blocks.rb +0 -24
  177. data/db/migrate/20250627023314_add_block_id_to_cm_guests.rb +0 -13
  178. data/db/migrate/20250716022821_add_location_reference_to_cm_vendor_places.rb +0 -5
  179. data/db/migrate/20250716031743_drop_table_cm_vendor_stops.rb +0 -5
  180. data/db/migrate/20250717023824_add_vendor_reference_to_cm_trips.rb +0 -5
  181. data/db/migrate/20250717041414_add_location_place_reference_to_cm_trip_stops.rb +0 -5
  182. data/db/migrate/20250717042539_rename_cm_trip_stops_stop_id_column_to_stop_place_id.rb +0 -7
  183. data/db/migrate/20250717042707_rename_cm_trips_origin_and_destination_to_origin_place_and_destination_place.rb +0 -11
  184. data/db/migrate/20250721080738_add_vehicle_type_to_cm_vehicles.rb +0 -7
  185. data/db/migrate/20250725092713_add_block_type_to_cm_blocks.rb +0 -5
  186. data/db/migrate/20250731062816_add_departure_time_and_arrival_time_to_trip_stop.rb +0 -6
  187. data/db/migrate/20250807033035_create_spree_cm_commissioner_saved_guests.rb +0 -23
  188. data/db/migrate/20250808054835_add_saved_guest_reference_to_cm_blocks.rb +0 -5
  189. data/lib/spree_cm_commissioner/cached_inventory_item.rb +0 -23
  190. data/lib/spree_cm_commissioner/test_helper/factories/block_factory.rb +0 -16
  191. data/lib/spree_cm_commissioner/test_helper/factories/inventory_item_factory.rb +0 -9
  192. data/lib/spree_cm_commissioner/test_helper/factories/reserved_block_factory.rb +0 -27
  193. data/lib/spree_cm_commissioner/test_helper/factories/seat_layout_factory.rb +0 -11
  194. data/lib/spree_cm_commissioner/test_helper/factories/seat_section_factory.rb +0 -16
  195. data/lib/spree_cm_commissioner/test_helper/factories/trip_connection_factory.rb +0 -6
  196. data/lib/spree_cm_commissioner/test_helper/factories/trip_stop_factory.rb +0 -13
  197. data/lib/spree_cm_commissioner/test_helper/factories/variant_block_factory.rb +0 -7
  198. data/lib/spree_cm_commissioner/transit/leg.rb +0 -23
  199. data/lib/spree_cm_commissioner/transit/seat_selection.rb +0 -19
  200. data/lib/tasks/create_default_non_permanent_inventory_items.rake +0 -16
  201. data/lib/tasks/ensure_correct_product_type.rake +0 -7
  202. data/lib/tasks/generate_inventory_items.rake +0 -7
@@ -1,21 +1,13 @@
1
- # Number of guests are depend on the variant, but user is allowed to input custom number of guests
2
- # which will be stored in public_metadata.
3
- #
4
- # metadata {
5
- # 'number_of_adults': 2,
6
- # 'number_of_kids': 1,
7
- # }
8
1
  module SpreeCmCommissioner
9
2
  module LineItemGuestsConcern
10
3
  extend ActiveSupport::Concern
11
4
 
12
5
  included do
13
- validate :validate_total_adults, if: -> { valid_integer_metadata?('number_of_adults') }
14
- validate :validate_total_kids, if: -> { valid_integer_metadata?('number_of_kids') }
6
+ validate :validate_total_adults, if: -> { public_metadata[:number_of_adults].present? }
7
+ validate :validate_total_kids, if: -> { public_metadata[:number_of_kids].present? }
15
8
  end
16
9
 
17
- def number_of_adults = public_metadata['number_of_adults']&.to_i || (variant.number_of_adults * quantity)
18
- def number_of_kids = public_metadata['number_of_kids']&.to_i || (variant.number_of_kids * quantity)
10
+ def remaining_total_guests = [number_of_guests - guests.size, 0].max
19
11
  def number_of_guests = number_of_adults + number_of_kids
20
12
 
21
13
  def allowed_extra_adults = variant.allowed_extra_adults * quantity
@@ -24,7 +16,8 @@ module SpreeCmCommissioner
24
16
  def allowed_total_adults = (variant.number_of_adults * quantity) + allowed_extra_adults
25
17
  def allowed_total_kids = (variant.number_of_kids * quantity) + allowed_extra_kids
26
18
 
27
- def remaining_total_guests = [number_of_guests - guests.size, 0].max
19
+ def number_of_adults = public_metadata[:number_of_adults] || (variant.number_of_adults * quantity)
20
+ def number_of_kids = public_metadata[:number_of_kids] || (variant.number_of_kids * quantity)
28
21
 
29
22
  def generate_remaining_guests
30
23
  return if remaining_total_guests.zero?
@@ -35,17 +28,15 @@ module SpreeCmCommissioner
35
28
  end
36
29
 
37
30
  def extra_adults
38
- return 0 unless valid_integer_metadata?('number_of_adults')
39
31
  return 0 unless extra_adults?
40
32
 
41
- public_metadata['number_of_adults'].to_i - (variant.number_of_adults * quantity)
33
+ public_metadata[:number_of_adults] - (variant.number_of_adults * quantity)
42
34
  end
43
35
 
44
36
  def extra_kids
45
- return 0 unless valid_integer_metadata?('number_of_kids')
46
37
  return 0 unless extra_kids?
47
38
 
48
- public_metadata['number_of_kids'].to_i - (variant.number_of_kids * quantity)
39
+ public_metadata[:number_of_kids] - (variant.number_of_kids * quantity)
49
40
  end
50
41
 
51
42
  def guest_options
@@ -64,30 +55,25 @@ module SpreeCmCommissioner
64
55
  end
65
56
 
66
57
  def extra_adults?
67
- return false unless valid_integer_metadata?('number_of_adults')
68
-
69
- public_metadata['number_of_adults'].to_i > variant.number_of_adults * quantity
58
+ public_metadata[:number_of_adults].present? && public_metadata[:number_of_adults] > variant.number_of_adults * quantity
70
59
  end
71
60
 
72
61
  def extra_kids?
73
- return false unless valid_integer_metadata?('number_of_kids')
74
-
75
- public_metadata['number_of_kids'].to_i > variant.number_of_kids * quantity
62
+ public_metadata[:number_of_kids].present? && public_metadata[:number_of_kids] > variant.number_of_kids * quantity
76
63
  end
77
64
 
78
65
  private
79
66
 
80
- def valid_integer_metadata?(key)
81
- value = public_metadata[key.to_s]
82
- value.present? && value.to_s.match?(/\A-?\d+\z/)
83
- end
84
-
85
67
  def validate_total_adults
86
- errors.add(:quantity, 'exceed_total_adults') if public_metadata['number_of_adults'].to_i > allowed_total_adults
68
+ return if public_metadata[:number_of_adults] <= allowed_total_adults
69
+
70
+ errors.add(:quantity, 'exceed_total_adults')
87
71
  end
88
72
 
89
73
  def validate_total_kids
90
- errors.add(:quantity, 'exceed_total_kids') if public_metadata['number_of_kids'].to_i > allowed_total_kids
74
+ return if public_metadata[:number_of_kids] <= allowed_total_kids
75
+
76
+ errors.add(:quantity, 'exceed_total_kids')
91
77
  end
92
78
  end
93
79
  end
@@ -14,6 +14,13 @@ module SpreeCmCommissioner
14
14
  state_selection
15
15
  payment_option
16
16
  delivery_option
17
+ amenity
18
+ departure_time
19
+ duration
20
+ vehicle_id
21
+ origin
22
+ destination
23
+ place_id
17
24
  ].freeze
18
25
 
19
26
  RESERVED_OPTIONS = {
@@ -41,8 +48,11 @@ module SpreeCmCommissioner
41
48
  'bib-display-prefix' => 'boolean',
42
49
  'bib-pre-generation-on-create' => 'boolean',
43
50
  'seat-number-positions' => 'array',
44
- 'seat-type' => 'string',
45
- 'intercity-taxi' => 'string'
51
+ 'origin' => 'place_id',
52
+ 'destination' => 'place_id',
53
+ 'departure-time' => 'time',
54
+ 'vehicle' => 'vehicle_id',
55
+ 'allow-seat-selection' => 'boolean'
46
56
  }.freeze
47
57
 
48
58
  included do
@@ -5,8 +5,6 @@ module SpreeCmCommissioner
5
5
  extend ActiveSupport::Concern
6
6
 
7
7
  included do
8
- state_machine.before_transition to: :payment, do: :hold_blocks!
9
-
10
8
  state_machine.before_transition to: :complete, do: :request, if: :need_confirmation?
11
9
  state_machine.before_transition to: :complete, do: :generate_bib_number
12
10
 
@@ -16,14 +14,10 @@ module SpreeCmCommissioner
16
14
  state_machine.after_transition to: :complete, do: :send_order_complete_telegram_alert_to_vendors, unless: :need_confirmation?
17
15
  state_machine.after_transition to: :complete, do: :send_order_complete_telegram_alert_to_store, unless: :need_confirmation?
18
16
 
19
- state_machine.around_transition to: :complete, do: :unstock_inventory!
20
-
21
17
  state_machine.after_transition to: :complete, do: :send_transaction_email_to_user, if: :user_has_email?
22
18
  state_machine.after_transition to: :resumed, do: :precalculate_conversion
23
- state_machine.around_transition to: :resumed, do: :unstock_inventory!
24
19
 
25
20
  state_machine.after_transition to: :canceled, do: :precalculate_conversion
26
- state_machine.after_transition to: :canceled, do: :restock_inventory!
27
21
 
28
22
  scope :accepted, -> { where(request_state: 'accepted') }
29
23
 
@@ -73,39 +67,6 @@ module SpreeCmCommissioner
73
67
  end
74
68
  end
75
69
 
76
- def unstock_inventory!
77
- ActiveRecord::Base.transaction do
78
- yield # Equal to block.call
79
-
80
- # After the transition is complete, the following code will execute first before proceeding to other `after_transition` callbacks.
81
- # This ensures that if `reserve_blocks!` or `unstock_inventory_in_redis!` fails, the state will be rolled back,
82
- # and neither the `finalize!` method nor any notifications will be triggered.
83
- # The payment will be reversed in vPago gem, and `Spree::Checkout::Complete` will be called, which checks `order.reload.complete?`.
84
- # This is critical because if the order state is complete, the payment will be marked as paid.
85
-
86
- reserve_blocks!
87
- unstock_inventory_in_redis!
88
-
89
- # We rollback only order state, and we keep payment state as it is.
90
- # We implement payment in vPago gem, and it will be reversed in the gem.
91
- # Some bank has api for refund, but some don't have the api to refund yet. So we keep the payment state as it is and refund manually.
92
- end
93
- rescue StandardError => e
94
- CmAppLogger.log(
95
- label: 'SpreeCmCommissioner::OrderStateMachine#reserve_inventory failed',
96
- data: { order_id: id, error: e.message, type: e.class.name, backtrace: e.backtrace&.first(5)&.join("\n") }
97
- )
98
-
99
- raise e
100
- end
101
-
102
- def restock_inventory!
103
- ActiveRecord::Base.transaction do
104
- cancel_blocks!
105
- restock_inventory_in_redis!
106
- end
107
- end
108
-
109
70
  def generate_bib_number
110
71
  line_items.find_each(&:generate_remaining_guests)
111
72
 
@@ -3,10 +3,12 @@ module SpreeCmCommissioner
3
3
  extend ActiveSupport::Concern
4
4
 
5
5
  included do
6
- delegate :subscribable?,
6
+ delegate :product_type,
7
+ :subscribable?,
7
8
  :allowed_upload_later?,
8
9
  :need_confirmation?, :need_confirmation,
9
10
  :allow_anonymous_booking,
11
+ :accommodation?, :service?, :ecommerce?,
10
12
  :allow_self_check_in,
11
13
  :allow_self_check_in?,
12
14
  :required_self_check_in_location,
@@ -6,20 +6,10 @@ module SpreeCmCommissioner
6
6
  extend ActiveSupport::Concern
7
7
 
8
8
  PRODUCT_TYPES = %i[accommodation service ecommerce transit].freeze
9
- PERMANENT_STOCK_PRODUCT_TYPES = %w[accommodation service transit].freeze
10
- PRE_INVENTORY_DAYS = { 'transit' => 90, 'accommodation' => 365, 'service' => 30 }.freeze
11
9
 
12
10
  included do
13
11
  enum product_type: PRODUCT_TYPES if table_exists? && column_names.include?('product_type')
14
12
  enum primary_product_type: PRODUCT_TYPES if table_exists? && column_names.include?('primary_product_type')
15
13
  end
16
-
17
- def permanent_stock?
18
- PERMANENT_STOCK_PRODUCT_TYPES.include?(product_type)
19
- end
20
-
21
- def pre_inventory_days
22
- PRE_INVENTORY_DAYS[product_type]
23
- end
24
14
  end
25
15
  end
@@ -2,7 +2,7 @@ module SpreeCmCommissioner
2
2
  module RouteType
3
3
  extend ActiveSupport::Concern
4
4
 
5
- ROUTE_TYPES = %i[bus intercity_taxi airport_shuttle rails ferry].freeze
5
+ ROUTE_TYPES = %i[automobile subway rails ferry].freeze
6
6
 
7
7
  included do
8
8
  enum route_type: ROUTE_TYPES if table_exists? && column_names.include?('route_type')
@@ -3,7 +3,7 @@ module SpreeCmCommissioner
3
3
  extend ActiveSupport::Concern
4
4
 
5
5
  included do
6
- enum kind: { category: 0, cms: 1, event: 2, occupation: 3, nationality: 4, organization: 5 }
6
+ enum kind: { category: 0, cms: 1, event: 2, occupation: 3, nationality: 4, organization: 5, transit: 6 }
7
7
  end
8
8
  end
9
9
  end
@@ -1,30 +1,10 @@
1
1
  module SpreeCmCommissioner
2
2
  module AddressDecorator
3
3
  def self.prepended(base)
4
+ # Field is not mandatory
4
5
  base.enum gender: { :not_selected => 0, :male => 1, :female => 2, :other => 3 }
5
-
6
- base.validates :address1, presence: true, if: :require_address1?
7
- base.validates :city, presence: true, if: :require_city?
8
- base.validates :country, presence: true, if: :require_country?
9
- end
10
-
11
- def require_address1?
12
- false
13
- end
14
-
15
- def require_city?
16
- false
17
- end
18
-
19
- def require_country?
20
- false
21
6
  end
22
7
  end
23
8
  end
24
9
 
25
- unless Spree::Address.included_modules.include?(SpreeCmCommissioner::AddressDecorator)
26
- # remove validators for the specified attributes
27
- %i[address1 city country].each { |attr| Spree::Address._validators.delete(attr) }
28
-
29
- Spree::Address.prepend(SpreeCmCommissioner::AddressDecorator)
30
- end
10
+ Spree::Address.prepend(SpreeCmCommissioner::AddressDecorator) unless Spree::Address.included_modules.include?(SpreeCmCommissioner::AddressDecorator)
@@ -0,0 +1,12 @@
1
+ require_dependency 'spree_cm_commissioner'
2
+
3
+ module SpreeCmCommissioner
4
+ class Branch < SpreeCmCommissioner::Place
5
+ belongs_to :state, class_name: 'Spree::State', optional: true
6
+ belongs_to :vendor, class_name: 'Spree::Vendor'
7
+
8
+ def validate_reference?
9
+ false
10
+ end
11
+ end
12
+ end
@@ -24,17 +24,10 @@ module SpreeCmCommissioner
24
24
  scope :none_bib, -> { where(bib_prefix: [nil, '']) }
25
25
 
26
26
  belongs_to :line_item, class_name: 'Spree::LineItem'
27
-
28
27
  has_one :variant, class_name: 'Spree::Variant', through: :line_item
29
-
30
28
  belongs_to :user, class_name: 'Spree::User'
31
29
  belongs_to :occupation, class_name: 'Spree::Taxon'
32
30
  belongs_to :nationality, class_name: 'Spree::Taxon'
33
- belongs_to :block, class_name: 'SpreeCmCommissioner::Block', optional: true
34
- belongs_to :saved_guest, class_name: 'SpreeCmCommissioner::SavedGuest', optional: true
35
-
36
- has_one :reserved_block, class_name: 'SpreeCmCommissioner::ReservedBlock'
37
-
38
31
  scope :checked_ins, -> { joins(:check_in) }
39
32
  scope :no_show, -> { left_outer_joins(:check_in).where(cm_check_ins: { id: nil }) }
40
33
 
@@ -55,15 +48,9 @@ module SpreeCmCommissioner
55
48
 
56
49
  before_create :generate_bib, if: -> { line_item.reload && variant.bib_pre_generation_on_create? }
57
50
 
58
- after_create :preload_order_block_ids, if: -> { block_id.present? }
59
- after_update :preload_order_block_ids, if: :saved_change_to_block_id?
60
- after_destroy :preload_order_block_ids
61
-
62
51
  validates :seat_number, uniqueness: { scope: :event_id }, allow_nil: true, if: -> { event_id.present? }
63
52
  validates :bib_index, uniqueness: true, allow_nil: true
64
53
 
65
- validate :validate_block, if: :should_validate_block?
66
-
67
54
  self.whitelisted_ransackable_associations = %w[id_card event line_item]
68
55
  self.whitelisted_ransackable_attributes = %w[first_name last_name phone_number gender contact occupation_id card_type created_at check_in_status]
69
56
 
@@ -296,28 +283,6 @@ module SpreeCmCommissioner
296
283
  filled_bib_number
297
284
  end
298
285
  end
299
-
300
- # validate only if block_id is present AND (new record OR block_id is changing)
301
- # goal: don't bother re-validating when block_id stays the same
302
- def should_validate_block?
303
- block_id.present? && (new_record? || will_save_change_to_block_id?)
304
- end
305
-
306
- def validate_block
307
- return if block_id.blank?
308
- return if line_item.blank? || line_item.variant.blank?
309
- return if line_item.variant.variant_blocks.exists?(block_id: block_id)
310
-
311
- errors.add(:block, "does not exist in variant #{line_item.variant_id}")
312
- end
313
-
314
- def preload_order_block_ids
315
- return if line_item.blank?
316
- return if line_item.order.blank?
317
-
318
- block_ids = line_item.order.blocks.pluck(:id)
319
- line_item.order.update(preload_block_ids: block_ids)
320
- end
321
286
  end
322
287
  end
323
288
  # rubocop:enable Metrics/ClassLength
@@ -1,6 +1,6 @@
1
1
  module SpreeCmCommissioner
2
2
  module LineItemDecorator
3
- def self.prepended(base) # rubocop:disable Metrics/MethodLength,Metrics/AbcSize
3
+ def self.prepended(base) # rubocop:disable Metrics/MethodLength
4
4
  include_modules(base)
5
5
 
6
6
  base.belongs_to :accepter, class_name: 'Spree::User', optional: true
@@ -10,32 +10,31 @@ module SpreeCmCommissioner
10
10
  base.has_one :google_wallet, class_name: 'SpreeCmCommissioner::GoogleWallet', through: :product
11
11
 
12
12
  base.has_many :option_types, through: :product
13
-
14
- base.has_many :inventory_items, lambda { |line_item|
15
- where(inventory_date: nil).or(where(inventory_date: line_item.date_range))
16
- }, through: :variant
17
-
18
13
  base.has_many :taxons, class_name: 'Spree::Taxon', through: :product
19
14
  base.has_many :guests, class_name: 'SpreeCmCommissioner::Guest', dependent: :destroy
20
- base.has_many :guests_with_blocks, -> { where.not(block_id: nil) }, class_name: 'SpreeCmCommissioner::Guest'
21
- base.has_many :reserved_blocks, through: :guests, class_name: 'SpreeCmCommissioner::ReservedBlock'
22
15
  base.has_many :pending_guests, pending_guests_query, class_name: 'SpreeCmCommissioner::Guest', dependent: :destroy
23
16
  base.has_many :product_completion_steps, class_name: 'SpreeCmCommissioner::ProductCompletionStep', through: :product
17
+ base.has_many :line_item_seats, class_name: 'SpreeCmCommissioner::LineItemSeat', dependent: :destroy
24
18
 
25
19
  base.before_save :update_vendor_id
20
+ base.before_save :update_quantity, if: :transit?
21
+
22
+ base.validate :validate_seats_reservation, if: :transit?
26
23
 
27
24
  base.before_create :add_due_date, if: :subscription?
28
- base.before_save -> { self.product_type = variant.product_type }, if: -> { product_type.nil? }
29
25
 
30
26
  base.validate :ensure_not_exceed_max_quantity_per_order, if: -> { variant&.max_quantity_per_order.present? }
31
27
 
32
28
  base.whitelisted_ransackable_associations |= %w[guests order]
33
29
  base.whitelisted_ransackable_attributes |= %w[number to_date from_date vendor_id]
34
30
 
35
- base.delegate :delivery_required?, :high_demand,
31
+ base.delegate :delivery_required?, :permanent_stock?, :high_demand, :transit?,
36
32
  to: :variant
33
+ base.delegate :discontinue_on, :product_type, :accommodation?, :service?, :ecommerce?, :need_confirmation,
34
+ to: :product
37
35
 
38
36
  base.accepts_nested_attributes_for :guests, allow_destroy: true
37
+ base.accepts_nested_attributes_for :line_item_seats, allow_destroy: true
39
38
 
40
39
  def base.json_api_columns
41
40
  json_api_columns = column_names.reject { |c| c.match(/_id$|id|preferences|(.*)password|(.*)token|(.*)api_key/) }
@@ -43,10 +42,6 @@ module SpreeCmCommissioner
43
42
  json_api_columns << :vendor_id
44
43
  end
45
44
 
46
- def discontinue_on
47
- variant.discontinue_on || product.discontinue_on
48
- end
49
-
50
45
  def base.search_by_qr_data!(data)
51
46
  matches = data.match(/(R\d+)-([A-Za-z0-9_\-]+)-(L\d+)/)&.captures
52
47
 
@@ -65,8 +60,6 @@ module SpreeCmCommissioner
65
60
  base.include SpreeCmCommissioner::LineItemDurationable
66
61
  base.include SpreeCmCommissioner::LineItemsFilterScope
67
62
  base.include SpreeCmCommissioner::LineItemGuestsConcern
68
- base.include SpreeCmCommissioner::LineItemTransitable
69
- base.include SpreeCmCommissioner::ProductType
70
63
  base.include SpreeCmCommissioner::ProductDelegation
71
64
  base.include SpreeCmCommissioner::KycBitwise
72
65
  end
@@ -82,39 +75,24 @@ module SpreeCmCommissioner
82
75
  }
83
76
  end
84
77
 
85
- # override to calculate price per date for permanent stock
86
- def update_price_from_modifier(currency, opts)
87
- self.currency = currency
88
-
89
- # these fields can be null during this process below.
90
- # it is needed for permanent_stock?, date_range to work.
91
- self.product_type = variant.product_type
92
- self.from_date = opts.delete(:from_date)&.to_datetime
93
- self.to_date = opts.delete(:to_date)&.to_datetime
94
-
95
- base_price = variant.price_in(currency)
96
-
97
- self.price = if permanent_stock?
98
- date_range.map do |date|
99
- selected_price = variant.price_for_date(date: date, currency: currency) || base_price
100
- (selected_price.amount || 0) + variant.price_modifier_amount_in(currency, opts.merge(date: date))
101
- end.sum
102
- else
103
- (base_price.amount || 0) + variant.price_modifier_amount_in(currency, opts)
104
- end
78
+ def reservation?
79
+ date_present? && !subscription?
105
80
  end
106
81
 
107
- # override to calculate price per date for permanent stock
108
- def update_price
109
- base_price = variant.price_in(order.currency)
110
- self.price = if permanent_stock?
111
- date_range.map do |date|
112
- selected_price = variant.price_for_date(date: date, currency: order.currency) || base_price
113
- selected_price.amount || 0
114
- end.sum
115
- else
116
- base_price.amount || 0
117
- end
82
+ # date_unit could be number of nights, or days or hours depending on usecases
83
+ # For example:
84
+ # - accomodation uses number of nights.
85
+ # - appointment uses number of hours, etc.
86
+ #
87
+ # override
88
+ def amount
89
+ base_price = price * quantity
90
+
91
+ if permanent_stock? && date_unit.present?
92
+ base_price * date_unit
93
+ else
94
+ base_price
95
+ end
118
96
  end
119
97
 
120
98
  def allowed_self_check_in?
@@ -201,6 +179,8 @@ module SpreeCmCommissioner
201
179
 
202
180
  # override
203
181
  def sufficient_stock?
182
+ return transit_sufficient_stock? if variant.product.product_type == 'transit'
183
+
204
184
  SpreeCmCommissioner::Stock::LineItemAvailabilityChecker.new(self).can_supply?(quantity)
205
185
  end
206
186
 
@@ -219,6 +199,18 @@ module SpreeCmCommissioner
219
199
  errors.add(:quantity, 'exceeded_max_quantity_per_order') if quantity > variant.max_quantity_per_order
220
200
  end
221
201
 
202
+ def transit_sufficient_stock?
203
+ return selected_seats_available? if reservation_trip.allow_seat_selection
204
+
205
+ seat_quantity_available?(reservation_trip)
206
+ end
207
+
208
+ def update_quantity
209
+ return if line_item_seats.blank?
210
+
211
+ self.quantity = line_item_seats.size
212
+ end
213
+
222
214
  def update_vendor_id
223
215
  self.vendor_id = variant.vendor_id
224
216
  end
@@ -241,6 +233,45 @@ module SpreeCmCommissioner
241
233
 
242
234
  from_date + variant.month.month + day.days
243
235
  end
236
+
237
+ def validate_seats_reservation
238
+ if reservation_trip.allow_seat_selection && !selected_seats_available?
239
+ errors.add(:base, :some_seats_are_booked, message: 'Some seats are already booked')
240
+ elsif !reservation_trip.allow_seat_selection && !seat_quantity_available?(reservation_trip)
241
+ errors.add(:quantity, :exceeded_available_quantity, message: 'exceeded available quantity')
242
+ end
243
+ end
244
+
245
+ def selected_seats_available?
246
+ selected_seat_ids = line_item_seats.map(&:seat_id)
247
+ !selected_seat_ids_occupied?(selected_seat_ids)
248
+ end
249
+
250
+ def seat_quantity_available?(trip)
251
+ booked_quantity = Spree::LineItem.joins(:order)
252
+ .where(variant_id: variant_id, date: date, spree_orders: { state: 'complete' })
253
+ .where.not(spree_line_items: { id: id })
254
+ .sum(:quantity)
255
+ remaining_quantity = trip.vehicle.number_of_seats - booked_quantity
256
+ remaining_quantity >= quantity
257
+ end
258
+
259
+ def reservation_trip
260
+ return @trip if defined? @trip
261
+
262
+ route = Spree::Variant.find_by(id: variant_id).product
263
+ @trip = route.trip
264
+ end
265
+
266
+ def selected_seat_ids_occupied?(selected_seat_ids)
267
+ # check to see if there are any selected_ids exist in the line_item_seats and belongs to completed order
268
+ SpreeCmCommissioner::LineItemSeat.joins(line_item: :order)
269
+ .where(seat_id: selected_seat_ids, date: date, variant_id: variant_id, spree_orders: { state: 'complete',
270
+ canceled_at: nil
271
+ }
272
+ )
273
+ .present?
274
+ end
244
275
  end
245
276
  end
246
277
 
@@ -0,0 +1,10 @@
1
+ require_dependency 'spree_cm_commissioner'
2
+ module SpreeCmCommissioner
3
+ class LineItemSeat < SpreeCmCommissioner::Base
4
+ belongs_to :line_item, class_name: 'Spree::LineItem'
5
+ belongs_to :seat, class_name: 'SpreeCmCommissioner::VehicleSeat'
6
+ belongs_to :variant, class_name: 'Spree::Variant'
7
+
8
+ validates :date, presence: true
9
+ end
10
+ end
@@ -1,5 +1,5 @@
1
1
  module SpreeCmCommissioner
2
- class NotificationTaxon < Base
2
+ class NotificationTaxon < SpreeCmCommissioner::Base
3
3
  belongs_to :customer_notification, class_name: 'SpreeCmCommissioner::CustomerNotification'
4
4
  belongs_to :taxon, class_name: 'Spree::Taxon'
5
5
  end
@@ -6,7 +6,7 @@ module SpreeCmCommissioner
6
6
  base.include SpreeCmCommissioner::ParameterizeName
7
7
  base.include SpreeCmCommissioner::OptionTypeAttrType
8
8
 
9
- base.enum kind: %i[variant product vendor vehicle]
9
+ base.enum kind: %i[variant product vendor vehicle_type transit]
10
10
 
11
11
  base.validates :name, presence: true
12
12
 
@@ -19,6 +19,16 @@ module SpreeCmCommissioner
19
19
  base.scope :promoted, -> { where(promoted: true) }
20
20
  base.whitelisted_ransackable_attributes = %w[kind]
21
21
 
22
+ def base.amenities
23
+ Spree::OptionType.where(kind: 'vehicle_type', name: 'amenities', presentation: 'Amenities', attr_type: 'amenity').first_or_create
24
+ end
25
+
26
+ def base.vehicle
27
+ Spree::OptionType.where(presentation: 'vehicle', attr_type: 'vehicle_id', kind: 'variant',
28
+ name: 'vehicle'
29
+ ).first_or_create
30
+ end
31
+
22
32
  def base.rules_option_type
23
33
  Spree::OptionType.find_by(name: RULES_OPTION_TYPE_NAME)
24
34
  end
@@ -0,0 +1,8 @@
1
+ require_dependency 'spree_cm_commissioner'
2
+
3
+ module SpreeCmCommissioner
4
+ class OptionValueVehicleType < ApplicationRecord
5
+ belongs_to :vehicle_type, class_name: 'SpreeCmCommissioner::VehicleType', dependent: :destroy
6
+ belongs_to :option_value, class_name: 'Spree::OptionValue', dependent: :destroy
7
+ end
8
+ end
@@ -2,7 +2,6 @@ module SpreeCmCommissioner
2
2
  module OrderDecorator
3
3
  def self.prepended(base) # rubocop:disable Metrics/MethodLength,Metrics/AbcSize
4
4
  base.include SpreeCmCommissioner::PhoneNumberSanitizer
5
- base.include SpreeCmCommissioner::OrderSeatable
6
5
  base.include SpreeCmCommissioner::OrderStateMachine
7
6
 
8
7
  base.scope :subscription, -> { where.not(subscription_id: nil) }
@@ -43,9 +42,6 @@ module SpreeCmCommissioner
43
42
  base.has_many :vendors, through: :products, class_name: 'Spree::Vendor'
44
43
  base.has_many :taxons, through: :products, class_name: 'Spree::Taxon'
45
44
  base.has_many :guests, through: :line_items, class_name: 'SpreeCmCommissioner::Guest'
46
- base.has_many :saved_guests, -> { distinct }, through: :guests, class_name: 'SpreeCmCommissioner::SavedGuest'
47
- base.has_many :blocks, through: :guests, class_name: 'SpreeCmCommissioner::Block', source: :block
48
- base.has_many :reserved_blocks, through: :guests, class_name: 'SpreeCmCommissioner::ReservedBlock'
49
45
  base.has_many :guest_card_classes, class_name: 'SpreeCmCommissioner::GuestCardClass', through: :variants
50
46
 
51
47
  base.delegate :customer, to: :user, allow_nil: true
@@ -62,13 +58,6 @@ module SpreeCmCommissioner
62
58
  end
63
59
  end
64
60
 
65
- # override
66
- # spree use this method to check stock availability & consider whether :order can continue to next state.
67
- def insufficient_stock_lines
68
- checker = SpreeCmCommissioner::Stock::OrderAvailabilityChecker.new(self)
69
- checker.insufficient_stock_lines
70
- end
71
-
72
61
  def ticket_seller_user?
73
62
  return false if user.nil?
74
63
 
@@ -117,14 +106,7 @@ module SpreeCmCommissioner
117
106
  end
118
107
 
119
108
  def mark_as_archive
120
- blocks_canceled = begin
121
- cancel_blocks!
122
- true
123
- rescue StandardError
124
- false
125
- end
126
-
127
- update(archived_at: Time.current) if blocks_canceled
109
+ update(archived_at: Time.current)
128
110
  end
129
111
 
130
112
  # overrided
@@ -217,18 +199,6 @@ module SpreeCmCommissioner
217
199
 
218
200
  private
219
201
 
220
- def unstock_inventory_in_redis!
221
- CmAppLogger.log(label: "#{self.class.name}#unstock_inventory_in_redis!", data: { order_id: id }) do
222
- SpreeCmCommissioner::RedisStock::InventoryUpdater.new(line_item_ids).unstock!
223
- end
224
- end
225
-
226
- def restock_inventory_in_redis!
227
- CmAppLogger.log(label: "#{self.class.name}#restock_inventory_in_redis!", data: { order_id: id }) do
228
- SpreeCmCommissioner::RedisStock::InventoryUpdater.new(line_item_ids).restock!
229
- end
230
- end
231
-
232
202
  # override :spree_api
233
203
  def webhook_payload_body
234
204
  resource_serializer.new(