stay_commerce 0.1.0

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 (496) hide show
  1. checksums.yaml +7 -0
  2. data/MIT-LICENSE +20 -0
  3. data/README.md +53 -0
  4. data/Rakefile +8 -0
  5. data/app/assets/config/stay_manifest.js +1 -0
  6. data/app/assets/fonts/bootstrap-icons.woff +0 -0
  7. data/app/assets/fonts/bootstrap-icons.woff2 +0 -0
  8. data/app/assets/images/chevron-down.svg +3 -0
  9. data/app/assets/images/circle-fill.svg +3 -0
  10. data/app/assets/images/circle.svg +3 -0
  11. data/app/assets/images/plus-circle.svg +4 -0
  12. data/app/assets/images/save.svg +3 -0
  13. data/app/assets/images/store.svg +3 -0
  14. data/app/assets/javascripts/stay/admin/address.js +165 -0
  15. data/app/assets/javascripts/stay/admin/ckeditor.min.js +7 -0
  16. data/app/assets/javascripts/stay/admin/flatpickr.min.js +2 -0
  17. data/app/assets/javascripts/stay/admin/index.js +28 -0
  18. data/app/assets/javascripts/stay/admin/property.js +37 -0
  19. data/app/assets/javascripts/stay/admin/select2.min.js +2 -0
  20. data/app/assets/javascripts/stay/application.js +14 -0
  21. data/app/assets/javascripts/stay/bootstrap.bundle.min.js +7 -0
  22. data/app/assets/javascripts/stay/ckeditor.js +11 -0
  23. data/app/assets/javascripts/stay/custom.js +56 -0
  24. data/app/assets/javascripts/stay/jquery-ui.min.js +13 -0
  25. data/app/assets/javascripts/stay/jquery.min.js +2 -0
  26. data/app/assets/stylesheets/stay/admin/flatpickr.min.css +13 -0
  27. data/app/assets/stylesheets/stay/admin/index.css +100 -0
  28. data/app/assets/stylesheets/stay/admin/select2.min.css +1 -0
  29. data/app/assets/stylesheets/stay/application.css +24 -0
  30. data/app/assets/stylesheets/stay/badges.css +72 -0
  31. data/app/assets/stylesheets/stay/bootstrap-icons.min.css +5 -0
  32. data/app/assets/stylesheets/stay/bootstrap-icons_fix.css +5 -0
  33. data/app/assets/stylesheets/stay/common.css +283 -0
  34. data/app/assets/stylesheets/stay/jquery-ui.css +1311 -0
  35. data/app/assets/stylesheets/stay/webpixels.css +7 -0
  36. data/app/channels/chat_channel.rb +13 -0
  37. data/app/controllers/concerns/stay/booking_validations.rb +86 -0
  38. data/app/controllers/concerns/stay/stripe_concern.rb +72 -0
  39. data/app/controllers/stay/admin/addresses_controller.rb +76 -0
  40. data/app/controllers/stay/admin/amenities_controller.rb +52 -0
  41. data/app/controllers/stay/admin/amenity_categories_controller.rb +52 -0
  42. data/app/controllers/stay/admin/base_controller.rb +38 -0
  43. data/app/controllers/stay/admin/bed_types_controller.rb +51 -0
  44. data/app/controllers/stay/admin/bookings_controller.rb +54 -0
  45. data/app/controllers/stay/admin/cancellation_policies_controller.rb +51 -0
  46. data/app/controllers/stay/admin/chats_controller.rb +53 -0
  47. data/app/controllers/stay/admin/cities_controller.rb +66 -0
  48. data/app/controllers/stay/admin/confirmations_controller.rb +30 -0
  49. data/app/controllers/stay/admin/countries_controller.rb +53 -0
  50. data/app/controllers/stay/admin/dashboard_controller.rb +8 -0
  51. data/app/controllers/stay/admin/features_controller.rb +54 -0
  52. data/app/controllers/stay/admin/home_controller.rb +15 -0
  53. data/app/controllers/stay/admin/house_rules_controller.rb +51 -0
  54. data/app/controllers/stay/admin/messages_controller.rb +53 -0
  55. data/app/controllers/stay/admin/passwords_controller.rb +32 -0
  56. data/app/controllers/stay/admin/payment_methods_controller.rb +53 -0
  57. data/app/controllers/stay/admin/payments_controller.rb +63 -0
  58. data/app/controllers/stay/admin/properties_controller.rb +118 -0
  59. data/app/controllers/stay/admin/property_categories_controller.rb +51 -0
  60. data/app/controllers/stay/admin/property_types_controller.rb +51 -0
  61. data/app/controllers/stay/admin/registrations_controller.rb +19 -0
  62. data/app/controllers/stay/admin/reviews_Controller.rb +63 -0
  63. data/app/controllers/stay/admin/roles_controller.rb +54 -0
  64. data/app/controllers/stay/admin/room_amenities_controller.rb +43 -0
  65. data/app/controllers/stay/admin/room_types_controller.rb +58 -0
  66. data/app/controllers/stay/admin/rooms_controller.rb +62 -0
  67. data/app/controllers/stay/admin/sessions_controller.rb +29 -0
  68. data/app/controllers/stay/admin/states_controller.rb +68 -0
  69. data/app/controllers/stay/admin/stores_controller.rb +132 -0
  70. data/app/controllers/stay/admin/taxes_controller.rb +51 -0
  71. data/app/controllers/stay/admin/users_controller.rb +85 -0
  72. data/app/controllers/stay/api/v1/amenities_controller.rb +13 -0
  73. data/app/controllers/stay/api/v1/amenity_categories_controller.rb +13 -0
  74. data/app/controllers/stay/api/v1/bed_types_controller.rb +9 -0
  75. data/app/controllers/stay/api/v1/booking_queries_controller.rb +205 -0
  76. data/app/controllers/stay/api/v1/bookings_controller.rb +299 -0
  77. data/app/controllers/stay/api/v1/cancellation_policies_controller.rb +10 -0
  78. data/app/controllers/stay/api/v1/chats_controller.rb +116 -0
  79. data/app/controllers/stay/api/v1/credit_cards_controller.rb +62 -0
  80. data/app/controllers/stay/api/v1/features_controller.rb +21 -0
  81. data/app/controllers/stay/api/v1/house_rules_controller.rb +9 -0
  82. data/app/controllers/stay/api/v1/invoices_controller.rb +47 -0
  83. data/app/controllers/stay/api/v1/messages_controller.rb +144 -0
  84. data/app/controllers/stay/api/v1/payments_controller.rb +61 -0
  85. data/app/controllers/stay/api/v1/profiles_controller.rb +23 -0
  86. data/app/controllers/stay/api/v1/properties_controller.rb +233 -0
  87. data/app/controllers/stay/api/v1/property_categories_controller.rb +14 -0
  88. data/app/controllers/stay/api/v1/property_types_controller.rb +14 -0
  89. data/app/controllers/stay/api/v1/room_types_controller.rb +14 -0
  90. data/app/controllers/stay/api/v1/rooms_controller.rb +23 -0
  91. data/app/controllers/stay/api/v1/user_paypal_controller.rb +53 -0
  92. data/app/controllers/stay/api/v1/users_controller.rb +17 -0
  93. data/app/controllers/stay/application_controller.rb +44 -0
  94. data/app/controllers/stay/base_api_controller.rb +14 -0
  95. data/app/controllers/stay/bookings_controller.rb +29 -0
  96. data/app/controllers/stay/payments_controller.rb +50 -0
  97. data/app/controllers/stay/profiles_controller.rb +26 -0
  98. data/app/controllers/stay/properties_controller.rb +15 -0
  99. data/app/controllers/stay/rooms_controller.rb +22 -0
  100. data/app/controllers/stay/users/confirmations_controller.rb +30 -0
  101. data/app/controllers/stay/users/omniauth_callbacks_controller.rb +30 -0
  102. data/app/controllers/stay/users/passwords_controller.rb +51 -0
  103. data/app/controllers/stay/users/registrations_controller.rb +62 -0
  104. data/app/controllers/stay/users/sessions_controller.rb +27 -0
  105. data/app/controllers/stay/users/unlocks_controller.rb +30 -0
  106. data/app/helpers/stay/admin/cities_helper.rb +4 -0
  107. data/app/helpers/stay/admin/countries_helper.rb +4 -0
  108. data/app/helpers/stay/admin/states_helper.rb +4 -0
  109. data/app/helpers/stay/admin/stores_helper.rb +25 -0
  110. data/app/helpers/stay/application_helper.rb +63 -0
  111. data/app/helpers/stay/currency_helper.rb +34 -0
  112. data/app/helpers/stay/locale_helper.rb +107 -0
  113. data/app/jobs/stay/application_job.rb +4 -0
  114. data/app/mailers/stay/application_mailer.rb +6 -0
  115. data/app/mailers/stay/user_mailer.rb +13 -0
  116. data/app/models/concerns/stay/translatable_resource.rb +25 -0
  117. data/app/models/stay/additional_rule.rb +5 -0
  118. data/app/models/stay/address.rb +40 -0
  119. data/app/models/stay/amenity.rb +13 -0
  120. data/app/models/stay/amenity_category.rb +6 -0
  121. data/app/models/stay/application_record.rb +5 -0
  122. data/app/models/stay/bed_type.rb +7 -0
  123. data/app/models/stay/booking.rb +199 -0
  124. data/app/models/stay/booking_query.rb +23 -0
  125. data/app/models/stay/cancellation_policy.rb +6 -0
  126. data/app/models/stay/chat.rb +23 -0
  127. data/app/models/stay/city.rb +9 -0
  128. data/app/models/stay/country.rb +23 -0
  129. data/app/models/stay/credit_card.rb +6 -0
  130. data/app/models/stay/discount.rb +4 -0
  131. data/app/models/stay/expense.rb +4 -0
  132. data/app/models/stay/feature.rb +11 -0
  133. data/app/models/stay/house_rule.rb +4 -0
  134. data/app/models/stay/invoice.rb +23 -0
  135. data/app/models/stay/line_item.rb +7 -0
  136. data/app/models/stay/message.rb +30 -0
  137. data/app/models/stay/payment.rb +54 -0
  138. data/app/models/stay/payment_method.rb +13 -0
  139. data/app/models/stay/price.rb +18 -0
  140. data/app/models/stay/property.rb +243 -0
  141. data/app/models/stay/property_amenity.rb +6 -0
  142. data/app/models/stay/property_category.rb +6 -0
  143. data/app/models/stay/property_feature.rb +6 -0
  144. data/app/models/stay/property_house_rule.rb +6 -0
  145. data/app/models/stay/property_tax.rb +6 -0
  146. data/app/models/stay/property_type.rb +15 -0
  147. data/app/models/stay/review.rb +5 -0
  148. data/app/models/stay/role.rb +11 -0
  149. data/app/models/stay/role_user.rb +6 -0
  150. data/app/models/stay/room.rb +93 -0
  151. data/app/models/stay/room_amenity.rb +6 -0
  152. data/app/models/stay/room_feature.rb +6 -0
  153. data/app/models/stay/room_type.rb +7 -0
  154. data/app/models/stay/state.rb +13 -0
  155. data/app/models/stay/store.rb +139 -0
  156. data/app/models/stay/store_property.rb +9 -0
  157. data/app/models/stay/tax.rb +8 -0
  158. data/app/models/stay/user.rb +111 -0
  159. data/app/models/stay/user_paypal.rb +5 -0
  160. data/app/serializers/amenity_category_serializer.rb +13 -0
  161. data/app/serializers/amenity_serializer.rb +3 -0
  162. data/app/serializers/bed_type_serializer.rb +5 -0
  163. data/app/serializers/booking_query_serializer.rb +6 -0
  164. data/app/serializers/booking_serializer.rb +68 -0
  165. data/app/serializers/cancellation_policy_serializer.rb +3 -0
  166. data/app/serializers/chat_serializer.rb +63 -0
  167. data/app/serializers/credit_card_serializer.rb +7 -0
  168. data/app/serializers/house_rules_serializer.rb +3 -0
  169. data/app/serializers/invoice_serializer.rb +41 -0
  170. data/app/serializers/last_5_messages_serializer.rb +7 -0
  171. data/app/serializers/line_item_serializer.rb +6 -0
  172. data/app/serializers/message_serializer.rb +44 -0
  173. data/app/serializers/property_category_serializer.rb +7 -0
  174. data/app/serializers/property_feature_serializer.rb +5 -0
  175. data/app/serializers/property_listing_serializer.rb +13 -0
  176. data/app/serializers/property_serializer.rb +77 -0
  177. data/app/serializers/property_type_serializer.rb +7 -0
  178. data/app/serializers/room_serializer.rb +36 -0
  179. data/app/serializers/room_type_serializer.rb +5 -0
  180. data/app/serializers/user_listing_serializer.rb +23 -0
  181. data/app/serializers/user_serializer.rb +41 -0
  182. data/app/services/stay/bookings/create_booking_service.rb +49 -0
  183. data/app/services/stay/bookings/create_line_item_service.rb +15 -0
  184. data/app/services/stay/bookings/existing_booking_service.rb +50 -0
  185. data/app/services/stay/chat/chat_messaging_service.rb +82 -0
  186. data/app/services/stay/chat/query_messaging_service.rb +56 -0
  187. data/app/services/stay/seeds/all.rb +27 -0
  188. data/app/services/stay/seeds/cancellation_policy.rb +21 -0
  189. data/app/services/stay/seeds/countries.rb +33 -0
  190. data/app/services/stay/seeds/roles.rb +9 -0
  191. data/app/services/stay/seeds/states.rb +63 -0
  192. data/app/services/stay/seeds/stores.rb +34 -0
  193. data/app/views/devise/mailer/reset_password_instructions.html.rb +10 -0
  194. data/app/views/kaminari/_first_page.html.erb +3 -0
  195. data/app/views/kaminari/_gap.html.erb +3 -0
  196. data/app/views/kaminari/_last_page.html.erb +3 -0
  197. data/app/views/kaminari/_next_page.html.erb +3 -0
  198. data/app/views/kaminari/_page.html.erb +9 -0
  199. data/app/views/kaminari/_paginator.html.erb +17 -0
  200. data/app/views/kaminari/_prev_page.html.erb +3 -0
  201. data/app/views/layouts/stay/admin.html.erb +45 -0
  202. data/app/views/layouts/stay/application.html.erb +34 -0
  203. data/app/views/stay/admin/addresses/_form.html.erb +49 -0
  204. data/app/views/stay/admin/addresses/edit.html.erb +5 -0
  205. data/app/views/stay/admin/addresses/index.html.erb +68 -0
  206. data/app/views/stay/admin/addresses/new.html.erb +5 -0
  207. data/app/views/stay/admin/addresses/show.html.erb +40 -0
  208. data/app/views/stay/admin/amenities/_form.html.erb +38 -0
  209. data/app/views/stay/admin/amenities/edit.html.erb +14 -0
  210. data/app/views/stay/admin/amenities/index.html.erb +58 -0
  211. data/app/views/stay/admin/amenities/new.html.erb +14 -0
  212. data/app/views/stay/admin/amenities/show.html.erb +19 -0
  213. data/app/views/stay/admin/amenity_categories/_form.html.erb +29 -0
  214. data/app/views/stay/admin/amenity_categories/edit.html.erb +14 -0
  215. data/app/views/stay/admin/amenity_categories/index.html.erb +53 -0
  216. data/app/views/stay/admin/amenity_categories/new.html.erb +14 -0
  217. data/app/views/stay/admin/amenity_categories/show.html.erb +18 -0
  218. data/app/views/stay/admin/bed_types/_form.html.erb +29 -0
  219. data/app/views/stay/admin/bed_types/edit.html.erb +14 -0
  220. data/app/views/stay/admin/bed_types/index.html.erb +56 -0
  221. data/app/views/stay/admin/bed_types/new.html.erb +14 -0
  222. data/app/views/stay/admin/bed_types/show.html.erb +0 -0
  223. data/app/views/stay/admin/bookings/_booking_invoice.html.erb +37 -0
  224. data/app/views/stay/admin/bookings/_booking_summary.html.erb +61 -0
  225. data/app/views/stay/admin/bookings/_form.html.erb +59 -0
  226. data/app/views/stay/admin/bookings/edit.html.erb +14 -0
  227. data/app/views/stay/admin/bookings/index.html.erb +74 -0
  228. data/app/views/stay/admin/bookings/new.html.erb +14 -0
  229. data/app/views/stay/admin/bookings/show.html.erb +80 -0
  230. data/app/views/stay/admin/cancellation_policies/_form.html.erb +38 -0
  231. data/app/views/stay/admin/cancellation_policies/edit.html.erb +14 -0
  232. data/app/views/stay/admin/cancellation_policies/index.html.erb +58 -0
  233. data/app/views/stay/admin/cancellation_policies/new.html.erb +14 -0
  234. data/app/views/stay/admin/cancellation_policies/show.html.erb +0 -0
  235. data/app/views/stay/admin/chats/_form.html.erb +31 -0
  236. data/app/views/stay/admin/chats/edit.html.erb +5 -0
  237. data/app/views/stay/admin/chats/index.html.erb +58 -0
  238. data/app/views/stay/admin/chats/new.html.erb +5 -0
  239. data/app/views/stay/admin/chats/show.html.erb +19 -0
  240. data/app/views/stay/admin/cities/_form.html.erb +30 -0
  241. data/app/views/stay/admin/cities/edit.html.erb +14 -0
  242. data/app/views/stay/admin/cities/index.html.erb +62 -0
  243. data/app/views/stay/admin/cities/new.html.erb +14 -0
  244. data/app/views/stay/admin/countries/_form.html.erb +64 -0
  245. data/app/views/stay/admin/countries/edit.html.erb +14 -0
  246. data/app/views/stay/admin/countries/index.html.erb +62 -0
  247. data/app/views/stay/admin/countries/new.html.erb +14 -0
  248. data/app/views/stay/admin/countries/show.html.erb +23 -0
  249. data/app/views/stay/admin/dashboard/index.html.erb +1 -0
  250. data/app/views/stay/admin/features/_form.html.erb +38 -0
  251. data/app/views/stay/admin/features/edit.html.erb +14 -0
  252. data/app/views/stay/admin/features/index.html.erb +58 -0
  253. data/app/views/stay/admin/features/new.html.erb +14 -0
  254. data/app/views/stay/admin/features/show.html.erb +19 -0
  255. data/app/views/stay/admin/house_rules/_form.html.erb +29 -0
  256. data/app/views/stay/admin/house_rules/edit.html.erb +14 -0
  257. data/app/views/stay/admin/house_rules/index.html.erb +54 -0
  258. data/app/views/stay/admin/house_rules/new.html.erb +14 -0
  259. data/app/views/stay/admin/house_rules/show.html.erb +18 -0
  260. data/app/views/stay/admin/mailer/confirmation_instructions.html.erb +5 -0
  261. data/app/views/stay/admin/mailer/email_changed.html.erb +7 -0
  262. data/app/views/stay/admin/mailer/password_change.html.erb +3 -0
  263. data/app/views/stay/admin/mailer/reset_password_instructions.html.erb +7 -0
  264. data/app/views/stay/admin/messages/_form.html.erb +36 -0
  265. data/app/views/stay/admin/messages/edit.html.erb +5 -0
  266. data/app/views/stay/admin/messages/index.html.erb +60 -0
  267. data/app/views/stay/admin/messages/new.html.erb +5 -0
  268. data/app/views/stay/admin/messages/show.html.erb +24 -0
  269. data/app/views/stay/admin/passwords/edit.html.erb +37 -0
  270. data/app/views/stay/admin/passwords/new.html.erb +28 -0
  271. data/app/views/stay/admin/payment_methods/_form.html.erb +22 -0
  272. data/app/views/stay/admin/payment_methods/edit.html.erb +14 -0
  273. data/app/views/stay/admin/payment_methods/index.html.erb +54 -0
  274. data/app/views/stay/admin/payment_methods/new.html.erb +14 -0
  275. data/app/views/stay/admin/payment_methods/show.html.erb +18 -0
  276. data/app/views/stay/admin/payments/_form.html.erb +36 -0
  277. data/app/views/stay/admin/payments/edit.html.erb +5 -0
  278. data/app/views/stay/admin/payments/index.html.erb +60 -0
  279. data/app/views/stay/admin/payments/new.html.erb +5 -0
  280. data/app/views/stay/admin/payments/show.html.erb +24 -0
  281. data/app/views/stay/admin/properties/_amenities.html.erb +38 -0
  282. data/app/views/stay/admin/properties/_calendar.html.erb +37 -0
  283. data/app/views/stay/admin/properties/_description.html.erb +126 -0
  284. data/app/views/stay/admin/properties/_details.html.erb +75 -0
  285. data/app/views/stay/admin/properties/_features.html.erb +39 -0
  286. data/app/views/stay/admin/properties/_form.html.erb +118 -0
  287. data/app/views/stay/admin/properties/_images.html.erb +48 -0
  288. data/app/views/stay/admin/properties/_location.html.erb +55 -0
  289. data/app/views/stay/admin/properties/_price.html.erb +88 -0
  290. data/app/views/stay/admin/properties/_sidebar.html.erb +47 -0
  291. data/app/views/stay/admin/properties/edit.html.erb +17 -0
  292. data/app/views/stay/admin/properties/index.html.erb +82 -0
  293. data/app/views/stay/admin/properties/new.html.erb +14 -0
  294. data/app/views/stay/admin/properties/show.html.erb +149 -0
  295. data/app/views/stay/admin/property_categories/_form.html.erb +29 -0
  296. data/app/views/stay/admin/property_categories/edit.html.erb +14 -0
  297. data/app/views/stay/admin/property_categories/index.html.erb +57 -0
  298. data/app/views/stay/admin/property_categories/new.html.erb +14 -0
  299. data/app/views/stay/admin/property_categories/show.html.erb +18 -0
  300. data/app/views/stay/admin/property_types/_form.html.erb +29 -0
  301. data/app/views/stay/admin/property_types/edit.html.erb +14 -0
  302. data/app/views/stay/admin/property_types/index.html.erb +56 -0
  303. data/app/views/stay/admin/property_types/new.html.erb +14 -0
  304. data/app/views/stay/admin/property_types/show.html.erb +18 -0
  305. data/app/views/stay/admin/registrations/edit.html.erb +43 -0
  306. data/app/views/stay/admin/registrations/new.html.erb +35 -0
  307. data/app/views/stay/admin/reviews/_form.html.erb +37 -0
  308. data/app/views/stay/admin/reviews/edit.html.erb +14 -0
  309. data/app/views/stay/admin/reviews/index.html.erb +58 -0
  310. data/app/views/stay/admin/reviews/new.html.erb +14 -0
  311. data/app/views/stay/admin/reviews/show.html.erb +20 -0
  312. data/app/views/stay/admin/roles/_form.html.erb +24 -0
  313. data/app/views/stay/admin/roles/edit.html.erb +14 -0
  314. data/app/views/stay/admin/roles/index.html.erb +55 -0
  315. data/app/views/stay/admin/roles/new.html.erb +14 -0
  316. data/app/views/stay/admin/roles/show.html.erb +18 -0
  317. data/app/views/stay/admin/room_types/_form.html.erb +37 -0
  318. data/app/views/stay/admin/room_types/edit.html.erb +14 -0
  319. data/app/views/stay/admin/room_types/index.html.erb +58 -0
  320. data/app/views/stay/admin/room_types/new.html.erb +14 -0
  321. data/app/views/stay/admin/room_types/show.html.erb +19 -0
  322. data/app/views/stay/admin/rooms/_form.html.erb +136 -0
  323. data/app/views/stay/admin/rooms/edit.html.erb +14 -0
  324. data/app/views/stay/admin/rooms/index.html.erb +69 -0
  325. data/app/views/stay/admin/rooms/new.html.erb +14 -0
  326. data/app/views/stay/admin/rooms/show.html.erb +25 -0
  327. data/app/views/stay/admin/sessions/new.html.erb +36 -0
  328. data/app/views/stay/admin/shared/_common-table.html.erb +334 -0
  329. data/app/views/stay/admin/shared/_error_messages.html.erb +15 -0
  330. data/app/views/stay/admin/shared/_header.html.erb +55 -0
  331. data/app/views/stay/admin/shared/_links.html.erb +15 -0
  332. data/app/views/stay/admin/shared/_sidebar.html.erb +154 -0
  333. data/app/views/stay/admin/shared/_store_switcher.html.erb +30 -0
  334. data/app/views/stay/admin/states/_form.html.erb +39 -0
  335. data/app/views/stay/admin/states/edit.html.erb +14 -0
  336. data/app/views/stay/admin/states/index.html.erb +61 -0
  337. data/app/views/stay/admin/states/new.html.erb +14 -0
  338. data/app/views/stay/admin/states/show.html.erb +0 -0
  339. data/app/views/stay/admin/stores/_form.html.erb +30 -0
  340. data/app/views/stay/admin/stores/_tabs.html.erb +17 -0
  341. data/app/views/stay/admin/stores/edit.html.erb +14 -0
  342. data/app/views/stay/admin/stores/form/_basic.html.erb +35 -0
  343. data/app/views/stay/admin/stores/form/_emails.html.erb +34 -0
  344. data/app/views/stay/admin/stores/form/_footer.html.erb +28 -0
  345. data/app/views/stay/admin/stores/form/_internationalization.html.erb +52 -0
  346. data/app/views/stay/admin/stores/form/_seo.html.erb +42 -0
  347. data/app/views/stay/admin/stores/form/_social.html.erb +34 -0
  348. data/app/views/stay/admin/stores/index.html.erb +66 -0
  349. data/app/views/stay/admin/stores/new.html.erb +14 -0
  350. data/app/views/stay/admin/stores/translations.html.erb +8 -0
  351. data/app/views/stay/admin/taxes/_form.html.erb +29 -0
  352. data/app/views/stay/admin/taxes/edit.html.erb +14 -0
  353. data/app/views/stay/admin/taxes/index.html.erb +56 -0
  354. data/app/views/stay/admin/taxes/new.html.erb +14 -0
  355. data/app/views/stay/admin/taxes/show.html.erb +18 -0
  356. data/app/views/stay/admin/users/_address.html.erb +57 -0
  357. data/app/views/stay/admin/users/_address_form.html.erb +29 -0
  358. data/app/views/stay/admin/users/_form.html.erb +73 -0
  359. data/app/views/stay/admin/users/_sidebar.html.erb +12 -0
  360. data/app/views/stay/admin/users/addresses.html.erb +17 -0
  361. data/app/views/stay/admin/users/edit.html.erb +17 -0
  362. data/app/views/stay/admin/users/index.html.erb +74 -0
  363. data/app/views/stay/admin/users/new.html.erb +14 -0
  364. data/app/views/stay/admin/users/show.html.erb +23 -0
  365. data/app/views/stay/bookings/new.html.erb +92 -0
  366. data/app/views/stay/payments/_payment.js.erb +127 -0
  367. data/app/views/stay/payments/new.html.erb +187 -0
  368. data/app/views/stay/properties/index.html.erb +56 -0
  369. data/app/views/stay/properties/show.html.erb +137 -0
  370. data/app/views/stay/shared/_navbar.html.erb +35 -0
  371. data/app/views/stay/user_mailer/new_host_signup.html.erb +12 -0
  372. data/app/views/stay/user_mailer/welcome_email.html.erb +9 -0
  373. data/app/views/stay/users/confirmations/new.html.erb +16 -0
  374. data/app/views/stay/users/mailer/confirmation_instructions.html.erb +5 -0
  375. data/app/views/stay/users/mailer/email_changed.html.erb +7 -0
  376. data/app/views/stay/users/mailer/password_change.html.erb +3 -0
  377. data/app/views/stay/users/mailer/reset_password_instructions.html.erb +7 -0
  378. data/app/views/stay/users/mailer/unlock_instructions.html.erb +7 -0
  379. data/app/views/stay/users/passwords/edit.html.erb +37 -0
  380. data/app/views/stay/users/passwords/new.html.erb +28 -0
  381. data/app/views/stay/users/registrations/edit.html.erb +43 -0
  382. data/app/views/stay/users/registrations/new.html.erb +42 -0
  383. data/app/views/stay/users/sessions/new.html.erb +43 -0
  384. data/app/views/stay/users/shared/_error_messages.html.erb +15 -0
  385. data/app/views/stay/users/shared/_links.html.erb +25 -0
  386. data/app/views/stay/users/unlocks/new.html.erb +16 -0
  387. data/config/initializers/devise.rb +358 -0
  388. data/config/initializers/friendly_id.rb +107 -0
  389. data/config/initializers/geocoder.rb +4 -0
  390. data/config/initializers/kaminari_config.rb +14 -0
  391. data/config/initializers/mobility.rb +17 -0
  392. data/config/initializers/stripe.rb +8 -0
  393. data/config/locales/devise.en.yml +65 -0
  394. data/config/locales/devise_api.en.yml +23 -0
  395. data/config/locales/en.yml +38 -0
  396. data/config/routes.rb +187 -0
  397. data/db/migrate/20240912073149_devise_create_stay_users.rb +50 -0
  398. data/db/migrate/20240912073248_create_devise_api_tables.rb +29 -0
  399. data/db/migrate/20240912092842_create_stay_roles.rb +9 -0
  400. data/db/migrate/20240912093003_create_stay_role_users.rb +10 -0
  401. data/db/migrate/20240912093151_create_stay_properties.rb +16 -0
  402. data/db/migrate/20240912093213_create_stay_rooms.rb +12 -0
  403. data/db/migrate/20240912093240_create_stay_bookings.rb +15 -0
  404. data/db/migrate/20240912093346_create_stay_payment_methods.rb +9 -0
  405. data/db/migrate/20240912093408_create_stay_payments.rb +12 -0
  406. data/db/migrate/20240912093603_create_stay_reviews.rb +11 -0
  407. data/db/migrate/20240912093644_create_stay_chats.rb +11 -0
  408. data/db/migrate/20240912093717_create_stay_messages.rb +12 -0
  409. data/db/migrate/20240912093759_create_stay_countries.rb +14 -0
  410. data/db/migrate/20240912093824_create_stay_states.rb +11 -0
  411. data/db/migrate/20240912093903_create_stay_cities.rb +10 -0
  412. data/db/migrate/20240912094149_create_stay_addresses.rb +19 -0
  413. data/db/migrate/20240916071141_create_active_storage_tables.rb +57 -0
  414. data/db/migrate/20240918080551_add_columns_to_stay_bookings.rb +12 -0
  415. data/db/migrate/20240918101502_add_columns_to_stay_payments.rb +16 -0
  416. data/db/migrate/20240918110958_create_stay_prices.rb +13 -0
  417. data/db/migrate/20240918112045_add_columns_to_stay_rooms.rb +5 -0
  418. data/db/migrate/20240918114609_add_payment_intent_in_bookings.rb +6 -0
  419. data/db/migrate/20240919045205_add_user_to_stay_addresses.rb +5 -0
  420. data/db/migrate/20240919063400_create_stay_room_types.rb +10 -0
  421. data/db/migrate/20240919070423_rename_room_type_to_room_type_id_in_stay_rooms.rb +5 -0
  422. data/db/migrate/20240919071642_rename_status_to_state_in_stay_payments.rb +5 -0
  423. data/db/migrate/20240919100508_remove_room_id_from_stay_properties.rb +5 -0
  424. data/db/migrate/20240919111801_create_stay_line_items.rb +16 -0
  425. data/db/migrate/20240919124704_remove_room_id_from_stay_bookings.rb +5 -0
  426. data/db/migrate/20240924053658_add_is_master_in_stay_rooms.rb +5 -0
  427. data/db/migrate/20240925063733_add_zipcode_required_in_countries.rb +5 -0
  428. data/db/migrate/20240926055951_remove_city_reference_from_stay_addresses.rb +5 -0
  429. data/db/migrate/20240927055935_change_price_per_night_to_decimal_in_stay_rooms.rb +5 -0
  430. data/db/migrate/20240927063023_add_first_name_to_stay_addresses.rb +8 -0
  431. data/db/migrate/20240927070538_change_description_to_text_in_stay_properties.rb +6 -0
  432. data/db/migrate/20240927111110_create_stay_stores.rb +33 -0
  433. data/db/migrate/20240930095921_create_stay_cancellation_policies.rb +9 -0
  434. data/db/migrate/20240930100157_add_cancellation_id_to_stay_properties.rb +5 -0
  435. data/db/migrate/20240930152331_create_stay_store_translations.rb +22 -0
  436. data/db/migrate/20240930162337_create_stay_store_properties.rb +10 -0
  437. data/db/migrate/20241001101816_create_stay_property_categories.rb +8 -0
  438. data/db/migrate/20241001102646_add_property_category_id_to_property.rb +5 -0
  439. data/db/migrate/20241001103758_create_stay_property_types.rb +9 -0
  440. data/db/migrate/20241001111306_add_store_id_to_stay_bookings.rb +5 -0
  441. data/db/migrate/20241001160330_add_deleted_at_to_stay_store_translations.rb +5 -0
  442. data/db/migrate/20241004061647_add_field_to_stay_properties.rb +20 -0
  443. data/db/migrate/20241004062057_create_stay_bed_types.rb +9 -0
  444. data/db/migrate/20241004062251_add_details_to_stay_rooms.rb +9 -0
  445. data/db/migrate/20241004070456_add_property_type_id_to_stay_property_categories.rb +6 -0
  446. data/db/migrate/20241004105821_create_stay_amenity_categories.rb +8 -0
  447. data/db/migrate/20241004112600_create_stay_amenities.rb +9 -0
  448. data/db/migrate/20241004115207_create_stay_house_rules.rb +8 -0
  449. data/db/migrate/20241004115317_create_stay_additional_rules.rb +9 -0
  450. data/db/migrate/20241004115608_create_stay_property_amenities.rb +9 -0
  451. data/db/migrate/20241004115615_create_stay_room_amenities.rb +9 -0
  452. data/db/migrate/20241007051646_add_preferences_to_stay_users.rb +5 -0
  453. data/db/migrate/20241007165530_create_stay_creates.rb +10 -0
  454. data/db/migrate/20241008111346_add_deleted_at_to_stay_users.rb +7 -0
  455. data/db/migrate/20241008151958_add_price_per_night_in_stay_properties.rb +5 -0
  456. data/db/migrate/20241010071855_add_zipcode_to_stay_property.rb +8 -0
  457. data/db/migrate/20241014085441_add_amenity_type_in_amenities.rb +5 -0
  458. data/db/migrate/20241015055940_create_stay_features.rb +10 -0
  459. data/db/migrate/20241015060804_create_stay_property_features.rb +9 -0
  460. data/db/migrate/20241015060854_create_stay_room_features.rb +9 -0
  461. data/db/migrate/20241016055948_create_stay_tax.rb +9 -0
  462. data/db/migrate/20241016060354_create_stay_property_tax.rb +11 -0
  463. data/db/migrate/20241016091120_remove_column_from_stay_properties_categories.rb +6 -0
  464. data/db/migrate/20241016091829_add_column_to_stay_property.rb +5 -0
  465. data/db/migrate/20241016112707_add_country_to_stay_properties.rb +6 -0
  466. data/db/migrate/20241016153847_add_state_to_properties.rb +7 -0
  467. data/db/migrate/20241016170528_up_date_price_column_in_stay_property.rb +5 -0
  468. data/db/migrate/20241017031520_add_new_field_to_stay_properties.rb +8 -0
  469. data/db/migrate/20241017051450_add_column_to_stay_chat.rb +7 -0
  470. data/db/migrate/20241018090158_create_stay_stay_credit_cards.rb +16 -0
  471. data/db/migrate/20241021090444_create_stay_stay_user_paypals.rb +9 -0
  472. data/db/migrate/20241024065949_add_stay_property_to_stay_b0okings.rb +5 -0
  473. data/db/migrate/20241027062126_add_events_to_stay_messages.rb +8 -0
  474. data/db/migrate/20241028105007_create_stay_invoices.rb +15 -0
  475. data/db/migrate/20241028105323_create_stay_expenses.rb +10 -0
  476. data/db/migrate/20241028105331_create_stay_discounts.rb +10 -0
  477. data/db/migrate/20241101044618_create_stay_booking_queries.rb +17 -0
  478. data/db/migrate/20241101093057_add_read_at_to_stay_messages.rb +5 -0
  479. data/db/migrate/20241113061248_modify_cancellation_policy_on_properties.rb +7 -0
  480. data/db/migrate/20241118064033_rename_columns_in_stay_properties.rb +7 -0
  481. data/db/migrate/20241127060541_add_new_fields_to_property.rb +11 -0
  482. data/db/migrate/20241128111832_add_name_to_stay_rooms.rb +5 -0
  483. data/db/migrate/20241129063922_change_amenity_category_null_on_stay_amenities.rb +5 -0
  484. data/db/migrate/20241205092935_add_slug_to_stay_properties.rb +6 -0
  485. data/db/migrate/20241205092943_create_friendly_id_slugs.rb +21 -0
  486. data/db/migrate/20241217044817_add_deleted_atto_stay_property.rb +6 -0
  487. data/db/migrate/20241230064432_modify_property_category_on_properties.rb +7 -0
  488. data/db/seeds.rb +1 -0
  489. data/lib/stay/controller_helpers/currency.rb +54 -0
  490. data/lib/stay/controller_helpers/store.rb +37 -0
  491. data/lib/stay/engine.rb +16 -0
  492. data/lib/stay/money.rb +77 -0
  493. data/lib/stay/version.rb +3 -0
  494. data/lib/stay.rb +16 -0
  495. data/lib/tasks/stay_tasks.rake +4 -0
  496. metadata +967 -0
@@ -0,0 +1,205 @@
1
+ class Stay::Api::V1::BookingQueriesController < Stay::BaseApiController
2
+ before_action :authenticate_devise_api_token!
3
+ before_action :set_property, except: [ :index, :show, :host_query ]
4
+ before_action :booking_availability, only: [ :create, :update ]
5
+ before_action :set_query, only: [ :update, :show ]
6
+ before_action :restrict_multiple_query, only: [ :create ]
7
+ before_action :check_booking_validation, only: [ :create ]
8
+
9
+ def index
10
+ begin
11
+ page = params[:page].to_i > 0 ? params[:page].to_i : 1
12
+ per_page = params[:per_page].to_i > 0 ? params[:per_page].to_i : 10
13
+
14
+ cumulative_per_page = page * per_page
15
+ query = current_devise_api_user.booking_queries.ongoing
16
+ @booking_queries = query.order(created_at: :desc).limit(cumulative_per_page)
17
+
18
+ total_count = query.count
19
+ total_pages = (total_count.to_f / per_page).ceil
20
+
21
+ return render json: { success: false, error: "Query not found" }, status: :not_found if @booking_queries.empty?
22
+
23
+ render json: {
24
+ success: true,
25
+ booking_queries: ActiveModelSerializers::SerializableResource.new(@booking_queries, each_serializer: BookingQuerySerializer),
26
+ meta: {
27
+ total_pages: total_pages,
28
+ current_page: page,
29
+ next_page: page < total_pages ? page + 1 : nil,
30
+ prev_page: page > 1 ? page - 1 : nil,
31
+ total_count: total_count
32
+ }
33
+ }, status: :ok
34
+ rescue ActiveRecord::RecordNotFound => e
35
+ render json: { success: false, error: "Query not found", message: e.message }, status: :not_found
36
+ rescue ArgumentError => e
37
+ render json: { success: false, error: "Invalid pagination parameters", message: e.message }, status: :bad_request
38
+ rescue StandardError => e
39
+ render json: { success: false, error: "Internal server error", message: e.message }, status: :internal_server_error
40
+ end
41
+ end
42
+
43
+ def host_query
44
+ begin
45
+ page = params[:page].to_i > 0 ? params[:page].to_i : 1
46
+ per_page = params[:per_page].to_i > 0 ? params[:per_page].to_i : 10
47
+
48
+ cumulative_per_page = page * per_page
49
+ query = Stay::BookingQuery.joins(:property).where(stay_properties: { user_id: current_devise_api_user&.id }).ongoing.order(created_at: :desc)
50
+ @booking_queries = query.limit(cumulative_per_page).uniq
51
+
52
+ total_count = query.count
53
+ total_pages = (total_count.to_f / per_page).ceil
54
+
55
+ return render json: { success: false, error: "Query not found" }, status: :not_found if @booking_queries.empty?
56
+
57
+ render json: {
58
+ success: true,
59
+ booking_queries: ActiveModelSerializers::SerializableResource.new(@booking_queries, each_serializer: BookingQuerySerializer),
60
+ meta: {
61
+ total_pages: total_pages,
62
+ current_page: page,
63
+ next_page: page < total_pages ? page + 1 : nil,
64
+ prev_page: page > 1 ? page - 1 : nil,
65
+ total_count: total_count
66
+ }
67
+ }, status: :ok
68
+ rescue ActiveRecord::RecordNotFound => e
69
+ render json: { success: false, error: "Query not found", message: e.message }, status: :not_found
70
+ rescue ArgumentError => e
71
+ render json: { success: false, error: "Invalid pagination parameters", message: e.message }, status: :bad_request
72
+ rescue StandardError => e
73
+ render json: { success: false, error: "Internal server error", message: e.message }, status: :internal_server_error
74
+ end
75
+ end
76
+
77
+ def create
78
+ ActiveRecord::Base.transaction do
79
+ return render json: { error: "you can not query for your own property", success: false }, status: :unprocessable_entity if current_devise_api_user == @property.user
80
+
81
+ chat = create_chat(current_devise_api_user, @property)
82
+ if chat.persisted?
83
+ booking_query = chat.build_booking_query(booking_query_params.merge(property: @property, user: current_devise_api_user))
84
+ if booking_query.save
85
+ Stay::Chat::QueryMessagingService.new(booking_query, current_devise_api_user).perform
86
+ render json: { success: true, booking_query: BookingQuerySerializer.new(booking_query) }, status: :created
87
+ else
88
+ raise ActiveRecord::Rollback
89
+ end
90
+ else
91
+ raise ActiveRecord::Rollback, "Failed to create chat"
92
+ end
93
+ end
94
+
95
+ rescue ActiveRecord::Rollback => e
96
+ render json: { success: false, errors: e.message || booking_query.errors.full_messages }, status: :unprocessable_entity
97
+ end
98
+
99
+ def show
100
+ last_five = @booking_query.chat&.messages.order(created_at: :desc).limit(5)
101
+ render json: {
102
+ success: true,
103
+ booking_query: BookingQuerySerializer.new(@booking_query),
104
+ booking: @booking_query.booking ? BookingSerializer.new(@booking_query.booking) : nil,
105
+ messages: ActiveModelSerializers::SerializableResource.new(last_five, each_serializer: MessageSerializer)
106
+ }, status: :ok
107
+ end
108
+
109
+
110
+ def update
111
+ if %w[request_change booking_invitation accepted rejected].include?(booking_query_params[:state])
112
+ @booking_query.update(state: booking_query_params[:state].to_sym)
113
+ Stay::Chat::QueryMessagingService.new(@booking_query, current_devise_api_user).perform
114
+ end
115
+
116
+ unless @booking_query.update(booking_query_params)
117
+ return render json: { success: false, errors: @booking_query.errors.full_messages }, status: :unprocessable_entity
118
+ end
119
+
120
+ last_five = @booking_query.chat&.messages.order(created_at: :desc).limit(5)
121
+
122
+ if @booking_query.accepted?
123
+ if @booking_query.booking.present?
124
+ render json: { success: false, message: "Booking already created for this query" }, status: :unprocessable_entity
125
+ else
126
+ result = Stay::Bookings::CreateBookingService.new(@booking_query).perform
127
+ if result[:success]
128
+ render json: {
129
+ message: "Booking created successfully",
130
+ success: true,
131
+ booking_query: BookingQuerySerializer.new(@booking_query),
132
+ booking: @booking_query.booking ? BookingSerializer.new(@booking_query.booking) : nil,
133
+ messages: ActiveModelSerializers::SerializableResource.new(last_five, each_serializer: MessageSerializer)
134
+ }, status: :ok
135
+ else
136
+ render json: { success: false, errors: result[:errors] }, status: :unprocessable_entity
137
+ end
138
+ end
139
+ else
140
+ render json: {
141
+ success: true,
142
+ booking_query: BookingQuerySerializer.new(@booking_query),
143
+ booking: @booking_query.booking ? BookingSerializer.new(@booking_query.booking) : nil,
144
+ messages: ActiveModelSerializers::SerializableResource.new(last_five, each_serializer: MessageSerializer)
145
+ }, status: :ok, status: :ok
146
+ end
147
+ end
148
+
149
+ private
150
+
151
+ def set_property
152
+ @property = Stay::Property.find_by(id: params[:property_id])
153
+ render json: { success: false, error: "Property not found" }, status: :not_found unless @property
154
+ end
155
+
156
+ def create_chat(user, property)
157
+ host = property.user
158
+ Stay::Chat.between(current_devise_api_user.id, host.id).create!(sender: user, receiver: host, property: property)
159
+ end
160
+
161
+ def set_query
162
+ begin
163
+ @booking_query = Stay::BookingQuery.find(params[:id])
164
+ rescue ActiveRecord::RecordNotFound => e
165
+ render json: { success: false, error: "Query not found" }, status: :not_found
166
+ end
167
+ end
168
+
169
+ def booking_query_params
170
+ params.require(:booking_query).permit(:chat_id, :user_id, :check_in_date, :check_out_date, :query, :booking_id, :state, :guest_count, :property_id, query_for: {})
171
+ end
172
+
173
+ def booking_availability
174
+ if @property.user.nil?
175
+ render json: { success: false, error: "Property Host not active." }, status: :not_found
176
+ end
177
+ end
178
+
179
+ def check_booking_validation
180
+ check_in_date = booking_query_params[:check_in_date].to_date
181
+ check_out_date = booking_query_params[:check_out_date].to_date
182
+
183
+ month_diff = (check_in_date.year * 12 + check_in_date.month) - (check_out_date.to_date.year * 12 + check_out_date.to_date.month)
184
+ if @property&.minimum_months_of_booking && month_diff > @property.minimum_months_of_booking
185
+ render json: { success: false, error: "minimum month for booking is #{@property.minimum_months_of_booking}" }, status: :unprocessable_entity
186
+ end
187
+ end
188
+
189
+ def restrict_multiple_query
190
+ existing_query = Stay::BookingQuery
191
+ .joins(:property)
192
+ .date_range(booking_query_params[:check_in_date], booking_query_params[:check_out_date])
193
+ .without_booking
194
+ .for_current_user(current_devise_api_user)
195
+ .where(stay_properties: { id: @property.id })
196
+ .exists?
197
+
198
+ if existing_query
199
+ render json: {
200
+ error: "You already raised a query for this property. Visit the booking query section for updates.",
201
+ success: false
202
+ }, status: :unprocessable_entity
203
+ end
204
+ end
205
+ end
@@ -0,0 +1,299 @@
1
+ class Stay::Api::V1::BookingsController < Stay::BaseApiController
2
+ before_action :set_booking, only: [ :show, :update, :delete_line_item, :booking_chat ]
3
+ before_action :authenticate_devise_api_token!
4
+ include Stay::BookingValidations
5
+
6
+ def index
7
+ begin
8
+ page = params[:page].to_i > 0 ? params[:page].to_i : 1
9
+ per_page = params[:per_page].to_i > 0 ? params[:per_page].to_i : 10
10
+
11
+ cumulative_per_page = page * per_page
12
+
13
+ @bookings = current_devise_api_user.bookings&.confirmed
14
+ .order(created_at: :desc)
15
+ .limit(cumulative_per_page)
16
+
17
+ total_count = current_devise_api_user.bookings&.confirmed.count
18
+ total_pages = (total_count.to_f / per_page).ceil
19
+
20
+ if @bookings.empty?
21
+ return render json: { error: "No bookings found", bookings: [], success: false }, status: :ok
22
+ end
23
+
24
+ render json: {
25
+ data: "Bookings Found",
26
+ bookings: ActiveModelSerializers::SerializableResource.new(@bookings, each_serializer: BookingSerializer),
27
+ success: true,
28
+ meta: {
29
+ total_pages: total_pages,
30
+ current_page: page,
31
+ next_page: page < total_pages ? page + 1 : nil,
32
+ prev_page: page > 1 ? page - 1 : nil,
33
+ total_count: total_count
34
+ }
35
+ }, status: :ok
36
+ rescue ActiveRecord::RecordNotFound => e
37
+ render json: { success: false, error: "Bookings not found", message: e.message }, status: :not_found
38
+ rescue ArgumentError => e
39
+ render json: { success: false, error: "Invalid pagination parameters", message: e.message }, status: :bad_request
40
+ rescue StandardError => e
41
+ render json: { success: false, error: "Internal server error", message: e.message }, status: :internal_server_error
42
+ end
43
+ end
44
+
45
+ def host_booking
46
+ begin
47
+ page = params[:page].to_i > 0 ? params[:page].to_i : 1
48
+ per_page = params[:per_page].to_i > 0 ? params[:per_page].to_i : 10
49
+
50
+ cumulative_per_page = page * per_page
51
+ @request = Stay::Booking.joins(:property).where(stay_properties: { user_id: current_devise_api_user&.id }).confirmed
52
+ @bookings = @request.order(created_at: :desc).limit(cumulative_per_page)
53
+
54
+ total_count = @request.count
55
+ total_pages = (total_count.to_f / per_page).ceil
56
+
57
+ if @bookings.empty?
58
+ return render json: { error: "No bookings found", bookings: [], success: false }, status: :ok
59
+ end
60
+
61
+ render json: {
62
+ data: "Bookings Found",
63
+ bookings: ActiveModelSerializers::SerializableResource.new(@bookings, each_serializer: BookingSerializer),
64
+ success: true,
65
+ meta: {
66
+ total_pages: total_pages,
67
+ current_page: page,
68
+ next_page: page < total_pages ? page + 1 : nil,
69
+ prev_page: page > 1 ? page - 1 : nil,
70
+ total_count: total_count
71
+ }
72
+ }, status: :ok
73
+ rescue ActiveRecord::RecordNotFound => e
74
+ render json: { success: false, error: "Bookings not found", message: e.message }, status: :not_found
75
+ rescue ArgumentError => e
76
+ render json: { success: false, error: "Invalid pagination parameters", message: e.message }, status: :bad_request
77
+ rescue StandardError => e
78
+ render json: { success: false, error: "Internal server error", message: e.message }, status: :internal_server_error
79
+ end
80
+ end
81
+
82
+ def host_request
83
+ begin
84
+ page = params[:page].to_i > 0 ? params[:page].to_i : 1
85
+ per_page = params[:per_page].to_i > 0 ? params[:per_page].to_i : 10
86
+
87
+ cumulative_per_page = page * per_page
88
+ @request = Stay::Booking.joins(:property).where(stay_properties: { user_id: current_devise_api_user&.id }).where.not(status: "confirmed")
89
+ @bookings = @request.order(created_at: :desc).limit(cumulative_per_page)
90
+
91
+ total_count = @request.count
92
+ total_pages = (total_count.to_f / per_page).ceil
93
+
94
+ if @bookings.empty?
95
+ return render json: { error: "No bookings found", bookings: [], success: false }, status: :ok
96
+ end
97
+
98
+ render json: {
99
+ data: "Bookings Found",
100
+ bookings: ActiveModelSerializers::SerializableResource.new(@bookings, each_serializer: BookingSerializer),
101
+ success: true,
102
+ meta: {
103
+ total_pages: total_pages,
104
+ current_page: page,
105
+ next_page: page < total_pages ? page + 1 : nil,
106
+ prev_page: page > 1 ? page - 1 : nil,
107
+ total_count: total_count
108
+ }
109
+ }, status: :ok
110
+ rescue ActiveRecord::RecordNotFound => e
111
+ render json: { success: false, error: "Bookings not found", message: e.message }, status: :not_found
112
+ rescue ArgumentError => e
113
+ render json: { success: false, error: "Invalid pagination parameters", message: e.message }, status: :bad_request
114
+ rescue StandardError => e
115
+ render json: { success: false, error: "Internal server error", message: e.message }, status: :internal_server_error
116
+ end
117
+ end
118
+
119
+ def create
120
+ booking = find_incomplete_booking
121
+
122
+ property = Stay::Property.friendly.find_by(slug: booking_params[:property_id])
123
+ return render json: { error: "property not found", success: false }, status: :unprocessable_entity if property.nil?
124
+ if booking.any?
125
+ handle_existing_booking(booking)
126
+ else
127
+ create_new_booking(property)
128
+ end
129
+ end
130
+
131
+ def my_reservation
132
+ begin
133
+ page = params[:page].to_i > 0 ? params[:page].to_i : 1
134
+ per_page = params[:per_page].to_i > 0 ? params[:per_page].to_i : 10
135
+
136
+ cumulative_per_page = page * per_page
137
+ @bookings = current_devise_api_user.bookings.incomplete
138
+ .order(created_at: :desc)
139
+ .limit(cumulative_per_page)
140
+
141
+ total_count = current_devise_api_user.bookings.incomplete&.count
142
+ total_pages = (total_count.to_f / per_page).ceil
143
+
144
+ if @bookings.empty?
145
+ return render json: { error: "No bookings found", bookings: [], success: false }, status: :ok
146
+ end
147
+
148
+ render json: {
149
+ data: "Bookings Found",
150
+ bookings: ActiveModelSerializers::SerializableResource.new(@bookings, each_serializer: BookingSerializer),
151
+ success: true,
152
+ meta: {
153
+ total_pages: total_pages,
154
+ current_page: page,
155
+ next_page: page < total_pages ? page + 1 : nil,
156
+ prev_page: page > 1 ? page - 1 : nil,
157
+ total_count: total_count
158
+ }
159
+ }, status: :ok
160
+ rescue ActiveRecord::RecordNotFound => e
161
+ render json: { success: false, error: "Bookings not found", message: e.message }, status: :not_found
162
+ rescue ArgumentError => e
163
+ render json: { success: false, error: "Invalid pagination parameters", message: e.message }, status: :bad_request
164
+ rescue StandardError => e
165
+ render json: { success: false, error: "Internal server error", message: e.message }, status: :internal_server_error
166
+ end
167
+ end
168
+
169
+
170
+ def booking_chat
171
+ @chat = @booking.chat
172
+ if @chat.present? && @chat.messages.any?
173
+ @messages = @chat.messages.page(params[:page]).per(params[:per_page] || 10)
174
+ render json: {
175
+ booking: BookingSerializer.new(@booking),
176
+ chat: ChatSerializer.new(@booking.chat, scope: { current_user: current_devise_api_user }),
177
+ messages: ActiveModelSerializers::SerializableResource.new(@messages, each_serializer: MessageSerializer),
178
+ success: true,
179
+ meta: {
180
+ total_pages: @messages.total_pages,
181
+ current_page: @messages.current_page,
182
+ next_page: @messages.next_page,
183
+ prev_page: @messages.prev_page,
184
+ total_count: @messages.total_count
185
+ }
186
+ }, status: :ok
187
+ else
188
+ render json: { error: "no chat found", success: false }, status: :unprocessable_entity
189
+ end
190
+ end
191
+
192
+ def show
193
+ render json: { booking: BookingSerializer.new(@booking), booking_query: @booking&.booking_query.present? ? BookingQuerySerializer.new(@booking&.booking_query) : nil, success: true }, status: :ok
194
+ end
195
+
196
+ def update
197
+ if @booking.payment_state == "failed" && params[:booking][:status] == "confirmed"
198
+ return render json: { error: "Booking cannot be confirmed due to failed payment." }, status: :unprocessable_entity
199
+ end
200
+ if @booking.update(booking_params)
201
+ if @booking.saved_change_to_status?
202
+ @booking.update_columns(canceler_id: current_devise_api_user.id, canceled_at: Time.current) if @booking.canceled?
203
+ Stay::Chat::ChatMessagingService.new(@booking).send_initial_messages
204
+ end
205
+ render json: { data: BookingSerializer.new(@booking, scope: { current_user: current_devise_api_user }), success: true }, status: :ok
206
+ else
207
+ render json: { error: @booking.errors.full_messages }, status: :unprocessable_entity
208
+ end
209
+ end
210
+
211
+ def delete_line_item
212
+ room = @booking.line_items.find_by(room_id: params[:room_id])
213
+ if room&.destroy
214
+ unless @booking.line_items.exists?
215
+ @booking.destroy
216
+ return render json: { message: "Booking deleted successfully", success: true }, status: :ok
217
+ end
218
+ render json: { message: "Room deleted successfully", data: BookingSerializer.new(@booking), success: true }, status: :ok
219
+ else
220
+ render json: { error: room ? room.errors.full_messages : "Room not found" }, status: :unprocessable_entity
221
+ end
222
+ end
223
+
224
+ private
225
+
226
+ def booking_params
227
+ params.require(:booking).permit(
228
+ :check_in_date, :check_out_date, :number_of_guests, :total_amount, :property_id, :status, :payment_intent_id,
229
+ line_items_attributes: [ :id, :room_id, :price, :quantity, :property_id ],
230
+ payments_attributes: [ :id, :payment_method_id, :amount, :state, :transaction_id, :intent_client_key ],
231
+ invoice_attributes: [
232
+ :id, :total, :invoice_period, :invoice_type, :billing_type, :status, :_destroy,
233
+ discounts_attributes: [ :id, :amount, :description, :_destroy ],
234
+ expenses_attributes: [ :id, :amount, :category, :_destroy ]
235
+ ]
236
+ )
237
+ end
238
+
239
+ def find_incomplete_booking
240
+ booking = current_devise_api_user.bookings.joins(:property).where(property: { slug: booking_params[:property_id] }).incomplete
241
+ end
242
+
243
+ def handle_existing_booking(booking)
244
+ @booking = booking.last
245
+ @booking.line_items.destroy_all if @booking.line_items
246
+ result = Stay::Bookings::ExistingBookingService.new(@booking, booking_params).perform
247
+ if result[:success]
248
+ if @booking.check_in_date != booking_params[:check_in_date].to_date && @booking.check_out_date != booking_params[:check_out_date].to_date
249
+ Stay::Chat::ChatMessagingService.new(@booking).send_initial_messages
250
+ end
251
+ render json: { data: BookingSerializer.new(@booking), success: true }, status: :ok
252
+ else
253
+ render json: { success: false, errors: result[:errors] }, status: :unprocessable_entity
254
+ end
255
+ end
256
+
257
+ def create_new_booking(property)
258
+ @booking = current_devise_api_user.bookings.new(booking_params)
259
+ unless property.shared_property
260
+ @booking.line_items = []
261
+ room_numbers = property.rooms.pluck(:id)
262
+ build_line_items(room_numbers, @booking)
263
+ end
264
+ @booking.property = property
265
+ if @booking.save
266
+ Stay::Chat::ChatMessagingService.new(@booking).send_initial_messages
267
+ @booking.calculate_totals
268
+ render json: { data: BookingSerializer.new(@booking), success: true }, status: :created
269
+ else
270
+ render json: { error: @booking.errors.full_messages }, status: :unprocessable_entity
271
+ end
272
+ end
273
+
274
+
275
+ def build_line_items(room_numbers, booking)
276
+ room_numbers.map do |room_number|
277
+ room = Stay::Room.find_by(id: room_number)
278
+ next unless room
279
+ booking.line_items.new(
280
+ room: room,
281
+ price: room.price.to_s,
282
+ quantity: 1
283
+ )
284
+ end
285
+ end
286
+
287
+ def set_room
288
+ @room = Stay::Room.find(params[:room_id])
289
+ end
290
+
291
+ def render_error(message, status)
292
+ render json: { error: message, success: false }, status: status
293
+ end
294
+
295
+ def set_booking
296
+ @booking = Stay::Booking.find_by(id: params[:id])
297
+ render json: { error: "no booking found", success: false }, status: :unprocessable_entity if @booking.nil?
298
+ end
299
+ end
@@ -0,0 +1,10 @@
1
+ class Stay::Api::V1::CancellationPoliciesController < Stay::BaseApiController
2
+ def index
3
+ policies = Stay::CancellationPolicy.all
4
+ render json: { data:ActiveModelSerializers::SerializableResource.new(policies, each_serializer: CancellationPolicySerializer), success: true }, status: :ok
5
+ rescue ActiveRecord::RecordNotFound
6
+ render json: { error: "Cancellation policies not found" }, status: :not_found
7
+ rescue StandardError => e
8
+ render json: { error: "An unexpected error occurred", details: e.message }, status: :internal_server_error
9
+ end
10
+ end
@@ -0,0 +1,116 @@
1
+ class Stay::Api::V1::ChatsController < ApplicationController
2
+ before_action :authenticate_devise_api_token!
3
+ before_action :check_admin_access, only: :index
4
+
5
+ def index
6
+ begin
7
+ page = params[:page].to_i > 0 ? params[:page].to_i : 1
8
+ per_page = params[:per_page].to_i > 0 ? params[:per_page].to_i : 15
9
+ cumulative_per_page = page * per_page
10
+
11
+ chats = Stay::Chat.joins(:messages, :property).where(stay_properties: { user: current_devise_api_user })
12
+ chats = params[:unread].present? ? chats.get_unread_messages_chat : chats.get_all_messages
13
+ chats = chats.order_by_latest_messages
14
+ return render json: { error: "No chats found", success: false }, status: :unprocessable_entity if chats.empty?
15
+
16
+ total_count = chats.length
17
+ chats = chats.limit(cumulative_per_page)
18
+ total_pages = (total_count.to_f / per_page).ceil
19
+
20
+ data = {
21
+ message: "Chats Found",
22
+ chats: ActiveModelSerializers::SerializableResource.new(chats, each_serializer: ChatSerializer, scope: { current_user: current_devise_api_user }),
23
+ success: true,
24
+ meta: {
25
+ total_pages: total_pages,
26
+ current_page: page,
27
+ next_page: page < total_pages ? page + 1 : nil,
28
+ prev_page: page > 1 ? page - 1 : nil,
29
+ total_count: total_count
30
+ }
31
+ }
32
+ render json: { data: data }, status: :ok
33
+ rescue ActiveRecord::RecordNotFound => e
34
+ render json: { success: false, error: "Properties not found", message: e.message }, status: :not_found
35
+ rescue ArgumentError => e
36
+ render json: { success: false, error: "Invalid pagination parameters", message: e.message }, status: :bad_request
37
+ rescue StandardError => e
38
+ render json: { success: false, error: "Internal server error", message: e.message }, status: :internal_server_error
39
+ end
40
+ end
41
+
42
+ def create
43
+ begin
44
+ @chat = Stay::Chat.between(current_devise_api_user&.id, params[:receiver_id]).create!(chat_params.merge(sender_id: current_devise_api_user&.id))
45
+ render json: {
46
+ data: "Chat Created",
47
+ chat: ActiveModelSerializers::SerializableResource.new(@chat, serializer: ChatSerializer, scope: { current_user: current_devise_api_user }),
48
+ success: true
49
+ }, status: :ok
50
+ rescue ActiveRecord::RecordInvalid => e
51
+ render json: { error: e.message, success: false }, status: :unprocessable_entity
52
+ rescue StandardError => e
53
+ render json: { error: "An error occurred: #{e.message}", success: false }, status: :internal_server_error
54
+ end
55
+ end
56
+
57
+ def user_chat
58
+ begin
59
+ page = params[:page].to_i > 0 ? params[:page].to_i : 1
60
+ per_page = params[:per_page].to_i > 0 ? params[:per_page].to_i : 15
61
+
62
+ cumulative_per_page = page * per_page
63
+ @chats = Stay::Chat.for_user(current_devise_api_user)
64
+
65
+ @chats = params[:unread].present? ? @chats.get_unread_messages_chat : @chats.get_all_messages
66
+ @chats = @chats.order_by_latest_messages
67
+ return render json: { error: "No chats found", success: false }, status: :unprocessable_entity if @chats.empty?
68
+
69
+ total_count = @chats.length
70
+ @chats = @chats.limit(cumulative_per_page)
71
+ total_pages = (total_count.to_f / per_page).ceil
72
+
73
+ data = {
74
+ message: @chats.any? ? "Chats Found" : "No Chat Found",
75
+ chats: @chats.any? ? ActiveModelSerializers::SerializableResource.new(@chats, each_serializer: ChatSerializer, scope: { current_user: current_devise_api_user }) : [],
76
+ success: @chats.any? ? true : false,
77
+ meta: {
78
+ total_pages: total_pages,
79
+ current_page: page,
80
+ next_page: page < total_pages ? page + 1 : nil,
81
+ prev_page: page > 1 ? page - 1 : nil,
82
+ total_count: total_count
83
+ }
84
+ }
85
+ render json: { data: data }, status: :ok
86
+ rescue ActiveRecord::RecordNotFound => e
87
+ render json: { success: false, error: "Chat not found", message: e.message }, status: :not_found
88
+ rescue ArgumentError => e
89
+ render json: { success: false, error: "Invalid pagination parameters", message: e.message }, status: :bad_request
90
+ rescue StandardError => e
91
+ render json: { success: false, error: "Internal server error", message: e.message }, status: :internal_server_error
92
+ end
93
+ end
94
+
95
+ def chat_messages
96
+ begin
97
+ @chat = Stay::Chat.find(params[:id])
98
+ @messages = @chat.messages
99
+ render json: { messages: @messages, success: true }, status: :ok
100
+ rescue ActiveRecord::RecordNotFound
101
+ render json: { error: "Chat not found", success: false }, status: :not_found
102
+ rescue StandardError => e
103
+ render json: { error: e.message, success: false }, status: :internal_server_error
104
+ end
105
+ end
106
+
107
+ private
108
+
109
+ def check_admin_access
110
+ render json: { error: "not authorize to see this chat", success: false }, status: :unprocessable_entity unless current_devise_api_user.stay_host?
111
+ end
112
+
113
+ def chat_params
114
+ params.require(:chat).permit(:sender_id, :receiver_id, :property_id, :booking_id, :chat_event, :event_message)
115
+ end
116
+ end
@@ -0,0 +1,62 @@
1
+ class Stay::Api::V1::CreditCardsController < Stay::BaseApiController
2
+ before_action :authenticate_devise_api_token!
3
+ before_action :set_credit_card, only: %i[show edit update]
4
+
5
+ def index
6
+ @credit_cards = current_devise_api_user.credit_cards
7
+ if @credit_cards.any?
8
+ render json: {
9
+ message: "Credit cards found",
10
+ data: CreditCardSerializer.new(@credit_cards.last),
11
+ success: true },
12
+ status: :ok
13
+ else
14
+ render json: { error: "No credit cards found", success: false }, status: :unprocessable_entity
15
+ end
16
+ end
17
+
18
+ def show
19
+ render json: { data: CreditCardSerializer.new(@credit_card), success: true }, status: :ok
20
+ end
21
+
22
+ def new
23
+ @credit_card = current_devise_api_user.credit_cards.build
24
+ render json: { data: @credit_card, success: true }, status: :ok
25
+ end
26
+
27
+ def create
28
+ @credit_card = current_devise_api_user.credit_cards.build(credit_card_params)
29
+ if @credit_card.save
30
+ render json: { message: "Credit card saved successfully", data: CreditCardSerializer.new(@credit_card), success: true }, status: :ok
31
+ else
32
+ render json: { error: "Credit card not saved", success: false, errors: @credit_card.errors.full_messages }, status: :unprocessable_entity
33
+ end
34
+ end
35
+
36
+ def edit
37
+ render json: { data: @credit_card, success: true }, status: :ok
38
+ end
39
+
40
+ def update
41
+ if @credit_card.update(credit_card_params)
42
+ render json: { message: "Credit card updated successfully", data: CreditCardSerializer.new(@credit_card), success: true }, status: :ok
43
+ else
44
+ render json: { error: "Credit card not updated", success: false, errors: @credit_card.errors.full_messages }, status: :unprocessable_entity
45
+ end
46
+ end
47
+
48
+ # def destroy
49
+ # @credit_card.destroy
50
+ # render json: { message: "Credit card successfully deleted", success: true }, status: :ok
51
+ # end
52
+
53
+ private
54
+
55
+ def set_credit_card
56
+ @credit_card = current_devise_api_user.credit_cards.find(params[:id])
57
+ end
58
+
59
+ def credit_card_params
60
+ params.require(:credit_card).permit(:month, :year, :cc_number, :cc_type, :name)
61
+ end
62
+ end