shoppper 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 (267) hide show
  1. checksums.yaml +7 -0
  2. data/MIT-LICENSE +20 -0
  3. data/README.md +28 -0
  4. data/Rakefile +22 -0
  5. data/app/assets/config/shopper_manifest.js +2 -0
  6. data/app/assets/javascripts/shopper/application.js +15 -0
  7. data/app/assets/stylesheets/shopper/application.css +15 -0
  8. data/app/commands/shopper/cart_page/add_product.rb +16 -0
  9. data/app/commands/shopper/cart_page/update_cart.rb +21 -0
  10. data/app/commands/shopper/cart_page/update_coupon.rb +51 -0
  11. data/app/commands/shopper/cart_page/update_order_items.rb +31 -0
  12. data/app/commands/shopper/checkout_page/add_checkout_addresses.rb +62 -0
  13. data/app/commands/shopper/checkout_page/add_checkout_delivery.rb +18 -0
  14. data/app/commands/shopper/checkout_page/add_checkout_payment.rb +19 -0
  15. data/app/commands/shopper/checkout_page/place_order.rb +40 -0
  16. data/app/commands/shopper/checkout_page/proceed_checkout.rb +14 -0
  17. data/app/commands/shopper/orders_page/get_orders.rb +34 -0
  18. data/app/controllers/shopper/cart_controller.rb +29 -0
  19. data/app/controllers/shopper/checkout_controller.rb +68 -0
  20. data/app/controllers/shopper/order_item_controller.rb +12 -0
  21. data/app/controllers/shopper/orders_controller.rb +19 -0
  22. data/app/controllers/shopper/shopper_controller.rb +4 -0
  23. data/app/decorators/concerns/shopper/caller_attachable.rb +24 -0
  24. data/app/decorators/concerns/shopper/view_helpers.rb +15 -0
  25. data/app/decorators/shopper/cart_page/coupon_decorator.rb +23 -0
  26. data/app/decorators/shopper/checkout_page/credit_card_decorator.rb +9 -0
  27. data/app/decorators/shopper/checkout_page/delivery_decorator.rb +28 -0
  28. data/app/decorators/shopper/items_table/item_decorator.rb +46 -0
  29. data/app/decorators/shopper/order_details/address_decorator.rb +19 -0
  30. data/app/decorators/shopper/order_details/order_decorator.rb +45 -0
  31. data/app/decorators/shopper/order_summary/order_decorator.rb +38 -0
  32. data/app/decorators/shopper/orders_page/order_decorator.rb +31 -0
  33. data/app/forms/shopper/address_form.rb +32 -0
  34. data/app/forms/shopper/coupon_form.rb +12 -0
  35. data/app/forms/shopper/credit_card_form.rb +36 -0
  36. data/app/helpers/shopper/application_helper.rb +4 -0
  37. data/app/jobs/shopper/application_job.rb +4 -0
  38. data/app/mailers/shopper/checkout_mailer.rb +9 -0
  39. data/app/models/concerns/shopper/order_aasm.rb +35 -0
  40. data/app/models/concerns/shopper/order_arithmetic_helpers.rb +24 -0
  41. data/app/models/concerns/shopper/order_item_arithmetic_helpers.rb +7 -0
  42. data/app/models/concerns/shopper/order_number.rb +13 -0
  43. data/app/models/concerns/shopper/order_product_helpers.rb +15 -0
  44. data/app/models/shopper/address.rb +12 -0
  45. data/app/models/shopper/application_record.rb +5 -0
  46. data/app/models/shopper/billing_address.rb +4 -0
  47. data/app/models/shopper/country.rb +11 -0
  48. data/app/models/shopper/coupon.rb +13 -0
  49. data/app/models/shopper/credit_card.rb +9 -0
  50. data/app/models/shopper/delivery.rb +24 -0
  51. data/app/models/shopper/order.rb +27 -0
  52. data/app/models/shopper/order_item.rb +18 -0
  53. data/app/models/shopper/shipping_address.rb +4 -0
  54. data/app/presenters/shopper/cart_page/cart_presenter.rb +34 -0
  55. data/app/presenters/shopper/checkout_page/address_step_presenter.rb +55 -0
  56. data/app/presenters/shopper/checkout_page/complete_step_presenter.rb +34 -0
  57. data/app/presenters/shopper/checkout_page/confirm_step_presenter.rb +20 -0
  58. data/app/presenters/shopper/checkout_page/delivery_step_presenter.rb +16 -0
  59. data/app/presenters/shopper/checkout_page/payment_step_presenter.rb +16 -0
  60. data/app/presenters/shopper/checkout_page/progress_presenter.rb +37 -0
  61. data/app/presenters/shopper/orders_page/order_presenter.rb +28 -0
  62. data/app/presenters/shopper/orders_page/orders_presenter.rb +17 -0
  63. data/app/services/shopper/checkout_manager.rb +55 -0
  64. data/app/validators/shopper/phone_validator.rb +11 -0
  65. data/app/views/shopper/cart/add_product.js.haml +3 -0
  66. data/app/views/shopper/cart/show.html.haml +22 -0
  67. data/app/views/shopper/checkout/_address_fields.html.haml +7 -0
  68. data/app/views/shopper/checkout/_layout.html.haml +12 -0
  69. data/app/views/shopper/checkout/address.html.haml +37 -0
  70. data/app/views/shopper/checkout/complete.html.haml +17 -0
  71. data/app/views/shopper/checkout/confirm.html.haml +6 -0
  72. data/app/views/shopper/checkout/delivery.html.haml +35 -0
  73. data/app/views/shopper/checkout/payment.html.haml +20 -0
  74. data/app/views/shopper/checkout_mailer/complete.html.haml +5 -0
  75. data/app/views/shopper/order_item/_table.html.haml +4 -0
  76. data/app/views/shopper/order_item/_table_desktop.html.haml +40 -0
  77. data/app/views/shopper/order_item/_table_phone.html.haml +30 -0
  78. data/app/views/shopper/orders/_details.html.haml +21 -0
  79. data/app/views/shopper/orders/_summary.html.haml +27 -0
  80. data/app/views/shopper/orders/index.html.haml +32 -0
  81. data/app/views/shopper/orders/show.html.haml +4 -0
  82. data/config/routes.rb +11 -0
  83. data/db/migrate/20170126000000_create_shopper_countries.rb +11 -0
  84. data/db/migrate/20170127194802_create_shopper_addresses.rb +19 -0
  85. data/db/migrate/20170127194999_create_shopper_deliveries.rb +12 -0
  86. data/db/migrate/20170129160931_create_shopper_orders.rb +14 -0
  87. data/db/migrate/20170129162148_create_shopper_order_items.rb +14 -0
  88. data/db/migrate/20170220181741_create_shopper_coupons.rb +11 -0
  89. data/db/migrate/20170224112113_add_state_to_shopper_orders.rb +5 -0
  90. data/db/migrate/20170224174654_create_shopper_credit_cards.rb +15 -0
  91. data/lib/shopper.rb +18 -0
  92. data/lib/shopper/checkout_wizard.rb +43 -0
  93. data/lib/shopper/configuration.rb +22 -0
  94. data/lib/shopper/current_order.rb +47 -0
  95. data/lib/shopper/engine.rb +21 -0
  96. data/lib/shopper/model_methods.rb +35 -0
  97. data/lib/shopper/version.rb +3 -0
  98. data/lib/tasks/shopper_tasks.rake +4 -0
  99. data/spec/commands/add_product_spec.rb +39 -0
  100. data/spec/controllers/cart_controller_spec.rb +34 -0
  101. data/spec/controllers/order_item_controller_spec.rb +18 -0
  102. data/spec/dummy/Rakefile +6 -0
  103. data/spec/dummy/app/assets/config/manifest.js +5 -0
  104. data/spec/dummy/app/assets/images/fallback/product_default.png +0 -0
  105. data/spec/dummy/app/assets/javascripts/application.js +15 -0
  106. data/spec/dummy/app/assets/javascripts/cable.js +13 -0
  107. data/spec/dummy/app/assets/stylesheets/application.css +15 -0
  108. data/spec/dummy/app/channels/application_cable/channel.rb +4 -0
  109. data/spec/dummy/app/channels/application_cable/connection.rb +4 -0
  110. data/spec/dummy/app/controllers/application_controller.rb +20 -0
  111. data/spec/dummy/app/helpers/application_helper.rb +2 -0
  112. data/spec/dummy/app/jobs/application_job.rb +2 -0
  113. data/spec/dummy/app/mailers/application_mailer.rb +4 -0
  114. data/spec/dummy/app/models/ability.rb +7 -0
  115. data/spec/dummy/app/models/application_record.rb +3 -0
  116. data/spec/dummy/app/models/customer.rb +3 -0
  117. data/spec/dummy/app/models/product.rb +21 -0
  118. data/spec/dummy/app/views/layouts/application.html.haml +17 -0
  119. data/spec/dummy/app/views/layouts/mailer.html.erb +13 -0
  120. data/spec/dummy/app/views/layouts/mailer.text.erb +1 -0
  121. data/spec/dummy/app/views/root/index.html +1 -0
  122. data/spec/dummy/bin/bundle +3 -0
  123. data/spec/dummy/bin/rails +4 -0
  124. data/spec/dummy/bin/rake +4 -0
  125. data/spec/dummy/bin/setup +34 -0
  126. data/spec/dummy/bin/update +29 -0
  127. data/spec/dummy/config.ru +5 -0
  128. data/spec/dummy/config/application.rb +21 -0
  129. data/spec/dummy/config/boot.rb +5 -0
  130. data/spec/dummy/config/cable.yml +9 -0
  131. data/spec/dummy/config/database.ci.yml +7 -0
  132. data/spec/dummy/config/database.yml +22 -0
  133. data/spec/dummy/config/environment.rb +5 -0
  134. data/spec/dummy/config/environments/development.rb +54 -0
  135. data/spec/dummy/config/environments/production.rb +86 -0
  136. data/spec/dummy/config/environments/test.rb +42 -0
  137. data/spec/dummy/config/initializers/application_controller_renderer.rb +6 -0
  138. data/spec/dummy/config/initializers/assets.rb +11 -0
  139. data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
  140. data/spec/dummy/config/initializers/cookies_serializer.rb +5 -0
  141. data/spec/dummy/config/initializers/filter_parameter_logging.rb +4 -0
  142. data/spec/dummy/config/initializers/inflections.rb +16 -0
  143. data/spec/dummy/config/initializers/mime_types.rb +4 -0
  144. data/spec/dummy/config/initializers/new_framework_defaults.rb +24 -0
  145. data/spec/dummy/config/initializers/session_store.rb +3 -0
  146. data/spec/dummy/config/initializers/simple_form.rb +169 -0
  147. data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
  148. data/spec/dummy/config/locales/en.yml +23 -0
  149. data/spec/dummy/config/locales/simple_form.en.yml +31 -0
  150. data/spec/dummy/config/puma.rb +47 -0
  151. data/spec/dummy/config/routes.rb +4 -0
  152. data/spec/dummy/config/secrets.yml +22 -0
  153. data/spec/dummy/config/spring.rb +6 -0
  154. data/spec/dummy/db/migrate/20170405091757_create_products.rb +10 -0
  155. data/spec/dummy/db/migrate/20170405160406_create_customers.rb +11 -0
  156. data/spec/dummy/db/schema.rb +33 -0
  157. data/spec/dummy/lib/templates/erb/scaffold/_form.html.erb +13 -0
  158. data/spec/dummy/log/development.log +378 -0
  159. data/spec/dummy/public/404.html +67 -0
  160. data/spec/dummy/public/422.html +67 -0
  161. data/spec/dummy/public/500.html +66 -0
  162. data/spec/dummy/public/apple-touch-icon-precomposed.png +0 -0
  163. data/spec/dummy/public/apple-touch-icon.png +0 -0
  164. data/spec/dummy/public/favicon.ico +0 -0
  165. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/-5/-5Q4Ub_11IMVDpGB1eI8cCVFFsUlJ8XHRzneSdfWwvA.cache +0 -0
  166. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/-u/-uuoXn7BP51SPd9jCpfonUaE46sb8x-w0b34wwdHt9E.cache +1 -0
  167. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/0T/0T0Tt9dfVU3GpS08jbSmEA-3V9YEKDfIoSeIPwG-V5M.cache +2 -0
  168. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/0X/0XswbOgGjXmH1fo5xq93jNgHe48bthciRdbD6tnWCvo.cache +3 -0
  169. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/1c/1ctUiWcG10n8KMVoiqAlIapKLbW5MDV1opGFwHsx34o.cache +1 -0
  170. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/2Z/2ZWFIlXKLDgIwGlnU7FU5aLf_Y1-m4KLYDXG0GdOvcc.cache +0 -0
  171. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/2c/2cgrQmg7ldfRivjXyyPNEH2O9Kps6UbeJH-Y9H1GmAs.cache +1 -0
  172. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/2l/2ltamKE3DUsifk0Gd4gmMxsgm5yKUZiNdhnSVHq_rVs.cache +0 -0
  173. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/31/312SvTp1rlNjttuCrjMR-sOiWZ8_7XmiagVfUeNAWfU.cache +1 -0
  174. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/4G/4GIZLDG2a1lnDZF2QESc0VLN9oHXztGnjE-LhJAssbk.cache +1 -0
  175. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/4R/4RE2lQ9Q_Khn7V4lGNDAW4xVGALXbiqnfOx-mXE831Q.cache +2 -0
  176. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/6U/6UKVmfPR7t8yUajbBceuWKaXogETyIV6Tbp0Mo8sR8A.cache +2 -0
  177. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/6Z/6Zs5ocm3aNgIQhqxQonxR7DfNzImkwFVBFsFSoXJ9nM.cache +1 -0
  178. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/6b/6bbfebueG2G5YjKNjtH5pwuc1LEJjKmfpIL4IREIArw.cache +1 -0
  179. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/7n/7ncqaz_mmyCQD_AQHpvMs2GXmVS9ETbTrWhH7RWvuYg.cache +2 -0
  180. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/7v/7vrAes6c_ihwe8jMx1yxyRDgWgAmDYBRMlsqqjlOA24.cache +3 -0
  181. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/8t/8tcTiIy9nbujTSsrbowd_m1ZDK-XWxe5KBzu4iWULdg.cache +1 -0
  182. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/9H/9H8beH0fozTusUWWhP9agRzmmCJigE63QS3yN6USIVY.cache +1 -0
  183. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/BX/BXeClZZ7pe07EVX5rjMY_bO_Ec1T114oejXtrS7DYLY.cache +1 -0
  184. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/DN/DN6DwzYk58CqQliQANOOcf4LZ9NfwuROLMpG_aIn1iA.cache +0 -0
  185. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/EF/EFDkZUV83NReWDmYJPAbH4QssV1WH7dhLAafE0jMdLE.cache +0 -0
  186. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/F4/F4HRhWWKLcUlE_9fUDcNFndpclhItP7pzduMZ0u0zEg.cache +0 -0
  187. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/F9/F95lTcrn4OEdV2-8CpWRA7Vo_g8Cyy46-JWOiLmNuZ8.cache +1 -0
  188. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/G5/G52PYwE_K5U0GKtgEfZMMMxYvZn20YV8JnDsE8miA8U.cache +0 -0
  189. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/GY/GYoI8lC94xLeXahTKQmXCYQmEcBTeJVY3rw4Ow29mAk.cache +1 -0
  190. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/HI/HIQD3918XDGcbRA7DQnrUx7Ij6_KmqX7A6-Xg8cTgvs.cache +1 -0
  191. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/IG/IGBxZd8bfUKXZ0qApnsHIDYrpmlGh4_stvNLwNClo-Q.cache +0 -0
  192. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/JZ/JZvskjPGda8b9BWf--ABB7K8u8eZWLEY_IGmIwN-lsM.cache +0 -0
  193. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/LZ/LZtqwTyBeV780reoWMqU06rIHTuSggj_moLE9aZl4zc.cache +1 -0
  194. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/MH/MHuhgGwsUMEUsXy-NMZLnq_3FmpwQ6Hr-x9Pj2Lg6jQ.cache +1 -0
  195. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/MW/MWqLf-tbtXiYTRmuVMVRXCVjAEX6LaEZGlVxS74nM-E.cache +0 -0
  196. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/OK/OKLY4QbXl_c1lHz1gm6tyYrpRIFU-014RSUQpb9fwyw.cache +1 -0
  197. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/Ok/OkpxMmj1ovAbbyXiexCJnj0apz54kz8iqahL4c1aXDo.cache +1 -0
  198. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/QI/QI3sr401dtpp_Wc_mTpdvAI5bpraLUIIf8Mv2feBvEw.cache +1 -0
  199. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/R0/R0TSIcvnfF3-QoBBBWQ32DiJLIR8D676f-SkUhprDK8.cache +0 -0
  200. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/RU/RUX4wpSRbADt7-aSjvb97ICl-fCJjPZxe1MNF6pcGOo.cache +1 -0
  201. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/To/To0QY39VWI3mZb6XXZAgOQCJcEj0tv0BJmIiu2oNdbg.cache +1 -0
  202. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/W9/W9krhTTy1IFXT5Q_rF4CifVRj4AVwKeE_F6pln8Rcmg.cache +1 -0
  203. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/Ws/Wsgy75qmOuCK1Vp25X17Py-pML-11GG3F3e-OYOsfGk.cache +4 -0
  204. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/Yb/YbBCKCjwVLMTjLflIx-p2w001jnZ2kVbDwnbDTh20ps.cache +1 -0
  205. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/Zi/ZiHXd8AlVOwGmpnKoVXVS3EKEBdo1Ac-Zcp4eiCPnRQ.cache +2 -0
  206. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/_C/_CHENopb4h3hRBPr0mRRTtNBvd64WDGI5v5hMC7PYgs.cache +0 -0
  207. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/a9/a94GSaPUyrAw0VlSAmwgl4iwDPatPtP7tsesOf07Fuo.cache +1 -0
  208. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/bk/bkyxSPKtV8sC84dH7iq0OkFMQzLCJ7DjdUoC6wYHaAA.cache +1 -0
  209. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/cE/cEQDNdSRl1tLTsWUUnyDWWXECh-MtIchaMG7PA2kuM8.cache +0 -0
  210. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/ch/chgbSC87FkXFMbNWMZJAtU_euvqnCKdUcV4CAjuRZXg.cache +1 -0
  211. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/dG/dGcYyTZ1x7nZldIv9CU9P6FILL3BZ_pHeJUEBXOFDtk.cache +1 -0
  212. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/eH/eHNL12KXLctBrvH2X9flxNGA4GRJGoyLwqRrxOWLHss.cache +1 -0
  213. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/fm/fmL1Nfucs6nwuozNi61KJ6nEHU8mb3F2SieWSl1sgeY.cache +1 -0
  214. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/gg/ggoM7JVi5PFoOTHQGrMmhFwnOSjd_RsNYmV9SpLGNPY.cache +2 -0
  215. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/iH/iHBHhxxOEBtpSeS0MFX4NL9vEfZMaQ72PxSXtbLy4pQ.cache +3 -0
  216. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/kQ/kQZ9KBvn5nS686f0v-15x3q-XPK9Puu03Od4FRDV_DY.cache +1 -0
  217. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/ln/ln7-McEMuq67tYE86JS_5anWVQE-o7kjVzTfmJ-pfYU.cache +0 -0
  218. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/n9/n9fyL8DlM6Ze117bMHweLE2x-4YM5aAW8cT3XYw-de8.cache +0 -0
  219. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/nM/nMZGQCxEPqJUI3praZMAm-YNu7TdqkdDhx3WG6J1KLY.cache +1 -0
  220. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/n_/n_xYqQYhwEMQknb3jFQnjlxxBE9TzMNHCdJ-bEyZFIw.cache +2 -0
  221. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/nx/nxTv3sKVUQZADJyM3dPaVmUA78MIsMLD_K279yN_GsI.cache +2 -0
  222. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/op/opCcAQpH-enBbSXpi0u1AEuA_O2KBuVSFHXlgdw8dNg.cache +1 -0
  223. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/qC/qCvelfVAvK45T3Goi7dqiicmsAKQoF9MkLAZtA4LVC0.cache +0 -0
  224. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/qI/qIdIIo1-efJi3gqwWbkhmcDlc4qTwuolMYutSBGYrxw.cache +2 -0
  225. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/qP/qPmv5snMrDw830S6hSICDcnIy7kVEWoFKXhGKT38lG4.cache +2 -0
  226. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/qx/qxYROkyCYJzti8DI00LfLhgV7FZgHCmaUnCjB3ayfWM.cache +1 -0
  227. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/wd/wdwXC49DcebjF5LPaEs1vqDXCWlq-32hHXfiKvjifno.cache +1 -0
  228. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/wg/wgn7xxwAmTkEhfWm8ujbjnId_c4MherEJuyXwkipOIg.cache +1 -0
  229. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/x7/x7PYh8DJvPykcEqpVab2vcY9-GFz-3cqtoMlRAu94Uc.cache +2 -0
  230. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/xg/xgrrLe9BN5muIDu9b9ADzAJHJtZFmr-PlDUBSkdJTDM.cache +3 -0
  231. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/z7/z79WysQah2YzrP7757RmZSO9M_8yzxDJPheGOhMjyXU.cache +1 -0
  232. data/spec/factories/addresses.rb +14 -0
  233. data/spec/factories/countries.rb +9 -0
  234. data/spec/factories/coupons.rb +10 -0
  235. data/spec/factories/credit_cards.rb +9 -0
  236. data/spec/factories/customer.rb +12 -0
  237. data/spec/factories/deliveries.rb +8 -0
  238. data/spec/factories/order_items.rb +7 -0
  239. data/spec/factories/orders.rb +42 -0
  240. data/spec/factories/product.rb +6 -0
  241. data/spec/features/cart_spec.rb +66 -0
  242. data/spec/features/checkout_spec.rb +53 -0
  243. data/spec/forms/credit_card_form_spec.rb +56 -0
  244. data/spec/models/customer_spec.rb +9 -0
  245. data/spec/models/product_spec.rb +7 -0
  246. data/spec/models/shopper/address_spec.rb +14 -0
  247. data/spec/models/shopper/billing_address_spec.rb +7 -0
  248. data/spec/models/shopper/country_spec.rb +10 -0
  249. data/spec/models/shopper/coupon_spec.rb +9 -0
  250. data/spec/models/shopper/credit_card_spec.rb +7 -0
  251. data/spec/models/shopper/delivery_spec.rb +28 -0
  252. data/spec/models/shopper/order_item_spec.rb +18 -0
  253. data/spec/models/shopper/order_spec.rb +105 -0
  254. data/spec/models/shopper/shipping_address_spec.rb +7 -0
  255. data/spec/rails_helper.rb +52 -0
  256. data/spec/services/checkout_manager_spec.rb +106 -0
  257. data/spec/spec_helper.rb +99 -0
  258. data/spec/support/capybara.rb +23 -0
  259. data/spec/support/database_cleaner.rb +44 -0
  260. data/spec/support/factory_girl.rb +3 -0
  261. data/spec/support/macroses/shared_macroses.rb +32 -0
  262. data/spec/support/macroses/stub_current_order.rb +18 -0
  263. data/spec/support/rails-controller-testing.rb +7 -0
  264. data/spec/support/shared_examples/addressable.rb +22 -0
  265. data/spec/support/shoulda_matchers.rb +4 -0
  266. data/spec/support/show_me_the_cookies.rb +3 -0
  267. metadata +855 -0
@@ -0,0 +1,9 @@
1
+ FactoryGirl.define do
2
+ sequence :country_name { |n| "country_name#{n}" }
3
+ sequence :country_code { |n| "country_code#{n}" }
4
+
5
+ factory :country, class: 'Shopper::Country' do
6
+ name { generate(:country_name) }
7
+ code { generate(:country_code) }
8
+ end
9
+ end
@@ -0,0 +1,10 @@
1
+ FactoryGirl.define do
2
+ sequence :coupon_code do |n|
3
+ n.to_s.rjust(5, '0')
4
+ end
5
+
6
+ factory :coupon, class: 'Shopper::Coupon' do
7
+ code { generate :coupon_code }
8
+ discount { rand(100) }
9
+ end
10
+ end
@@ -0,0 +1,9 @@
1
+ FactoryGirl.define do
2
+ factory :credit_card, class: 'Shopper::CreditCard' do
3
+ number { CreditCardValidations::Factory.random :visa }
4
+ cvv '123'
5
+ expiration_date { Time.current + 1.year }
6
+ name { FFaker::Name.name }
7
+ order
8
+ end
9
+ end
@@ -0,0 +1,12 @@
1
+ FactoryGirl.define do
2
+ factory :customer do
3
+ email { FFaker::Internet.email }
4
+
5
+ trait :with_addresses do
6
+ after(:create) do |user|
7
+ create(:billing_address, addressable: user)
8
+ create(:shipping_address, addressable: user)
9
+ end
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,8 @@
1
+ FactoryGirl.define do
2
+ factory :delivery, class: 'Shopper::Delivery' do
3
+ title { FFaker::DizzleIpsum.words.join(' ') }
4
+ min_days 1
5
+ max_days 5
6
+ price { FFaker.numerify('#.##') }
7
+ end
8
+ end
@@ -0,0 +1,7 @@
1
+ FactoryGirl.define do
2
+ factory :order_item, class: 'Shopper::OrderItem' do
3
+ quantity 1
4
+ order
5
+ association :product
6
+ end
7
+ end
@@ -0,0 +1,42 @@
1
+ FactoryGirl.define do
2
+ factory :order, class: 'Shopper::Order' do
3
+ trait :with_items do
4
+ transient do
5
+ number_of_items 3
6
+ end
7
+
8
+ after(:create) do |order, evaluator|
9
+ create_list :order_item, evaluator.number_of_items, order: order
10
+ end
11
+ end
12
+
13
+ trait :with_addresses do
14
+ after(:create) do |order|
15
+ create(:billing_address, addressable: order)
16
+ create(:shipping_address, addressable: order)
17
+ end
18
+ end
19
+
20
+ trait :with_delivery do
21
+ after(:create) do |order|
22
+ order.delivery = create(:delivery)
23
+ order.save
24
+ end
25
+ end
26
+
27
+ trait :with_credit_card do
28
+ after(:create) do |order|
29
+ order.credit_card = create(:credit_card)
30
+ order.save
31
+ end
32
+ end
33
+
34
+ trait :use_billing do
35
+ use_billing true
36
+
37
+ after(:create) do |order|
38
+ create(:billing_address, addressable: order)
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,6 @@
1
+ FactoryGirl.define do
2
+ factory :product, class: 'Product' do
3
+ title 'Title'
4
+ price { FFaker.numerify('#.##') }
5
+ end
6
+ end
@@ -0,0 +1,66 @@
1
+ feature 'Cart page:' do
2
+ before { create_list :product, 10 }
3
+ let(:coupon) { create :coupon }
4
+ let(:valid_code) { coupon.code }
5
+ let(:invalid_code) { 'invalid' }
6
+
7
+ context 'cart empty' do
8
+ let(:order) { create(:order) }
9
+ before { stub_current_order_with(order) }
10
+ before { visit shopper.cart_path }
11
+
12
+ it 'can add coupon' do
13
+ fill_in 'coupon_code', with: valid_code
14
+ click_button 'Update Cart'
15
+ expect(page).to have_content 'Cart was updated successfully'
16
+ expect(find('#coupon_code').value).to eq valid_code
17
+ expect(order.reload.coupon.code).to eq valid_code
18
+ end
19
+
20
+ it 'dont attach if coupon invalid' do
21
+ fill_in 'coupon_code', with: invalid_code
22
+ click_button 'Update Cart'
23
+ expect(page).to have_current_path shopper.cart_path
24
+ expect(page).to have_content 'Invalid coupon code'
25
+ expect(order.reload.coupon).to eq nil
26
+ end
27
+ end
28
+
29
+ context 'cart with items and coupon' do
30
+ let(:order) { create(:order, :with_items, coupon: coupon) }
31
+ before { stub_current_order_with(order) }
32
+ before { visit shopper.cart_path }
33
+
34
+ it 'can deattach coupon' do
35
+ fill_in 'coupon_code', with: ''
36
+ click_on 'Update Cart'
37
+ expect(page).to have_content 'Cart was updated successfully'
38
+ expect(find('#coupon_code').value).to eq ''
39
+ expect(order.reload.coupon).to eq nil
40
+ end
41
+
42
+ it 'can change items quantity' do
43
+ new_quantity = 4
44
+ page.execute_script("$('.quantity-input').first().val(#{new_quantity})")
45
+ click_button 'Update Cart'
46
+ expect(page).to have_content 'Cart was updated successfully'
47
+ expect(order.reload.order_items.first.quantity).to eq new_quantity
48
+ end
49
+
50
+ it 'dont change items quantity if invalid' do
51
+ target = order.order_items.first
52
+ new_quantity = 0
53
+ old_quantity = target.quantity
54
+ page.execute_script("$('.quantity-input').first().val(#{new_quantity})")
55
+ click_button 'Update Cart'
56
+ expect(page).not_to have_content 'Cart was updated successfully'
57
+ expect(target.reload.quantity).to eq old_quantity
58
+ end
59
+
60
+ it 'can remove items' do
61
+ expect do
62
+ first('.close').click
63
+ end.to change { Shopper::OrderItem.count }.by(-1)
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,53 @@
1
+ feature 'Checkout page:' do
2
+ before { create_list :product, 10 }
3
+ let!(:countries) { create_list :country, 10 }
4
+
5
+ describe 'Address step' do
6
+ context 'without order items' do
7
+ it 'should not allow to checkout page' do
8
+ visit shopper.checkout_path(:address)
9
+ expect(page).to have_current_path shopper.cart_path
10
+ end
11
+ end
12
+
13
+ context 'with order items' do
14
+ let(:order) { create :order, :with_items }
15
+ before { stub_current_order_with(order) }
16
+ before { visit shopper.checkout_path(:address) }
17
+
18
+ before do
19
+ within '.edit_order' do
20
+ fill_address(:order, :billing, attributes_for(:address), countries.first)
21
+ fill_address(:order, :shipping, attributes_for(:address), countries.second)
22
+ end
23
+ end
24
+
25
+ context 'when all fields valid' do
26
+ it 'should show next step' do
27
+ expect(Shopper::Address.all.count).to eq 0
28
+ click_button I18n.t('simple_form.titles.save_and_continue')
29
+ expect(page).to have_current_path shopper.checkout_path(:delivery)
30
+ expect(Shopper::Address.all.count).to eq 2
31
+ end
32
+ end
33
+
34
+ context 'when have invalid fields' do
35
+ before do
36
+ within '.edit_order' do
37
+ fill_in 'order[billing][first_name]', with: ''
38
+ end
39
+ end
40
+
41
+ it 'should show errors' do
42
+ expect {
43
+ click_button I18n.t('simple_form.titles.save_and_continue')
44
+ }.not_to change {
45
+ Shopper::Address.count
46
+ }
47
+ expect(page).to have_current_path shopper.checkout_path(:address)
48
+ expect(page).to have_content 'can\'t be blank'
49
+ end
50
+ end
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,56 @@
1
+ require 'rails_helper'
2
+
3
+ def format_expiration_date(date)
4
+ date.strftime(Shopper::CreditCardForm::DATE_FORMAT)
5
+ end
6
+
7
+ module Shopper
8
+ RSpec.describe CreditCardForm do
9
+ let(:attributes) do
10
+ attrs = attributes_for(:credit_card)
11
+ attrs[:expiration_date] = format_expiration_date(attrs[:expiration_date])
12
+ attrs
13
+ end
14
+
15
+ subject { CreditCardForm.from_params(attributes) }
16
+
17
+ describe 'expiration date' do
18
+ it 'valid' do
19
+ is_expected.to be_valid
20
+ end
21
+
22
+ it 'parse date from ##/## form' do
23
+ subject.expiration_date = '02/18'
24
+ is_expected.to be_valid
25
+ date = subject.expiration_date
26
+ expect(date.year).to eq(2018)
27
+ expect(date.month).to eq(2)
28
+ expect(date.day).to eq(1)
29
+ end
30
+
31
+ it 'is invalid if month is greater than 12' do
32
+ subject.expiration_date = '13/18'
33
+ is_expected.not_to be_valid
34
+ expect(subject.expiration_date).to be nil
35
+ end
36
+
37
+ describe 'expiration validator' do
38
+ it 'is invalid when in past' do
39
+ subject.expiration_date = format_expiration_date(Time.current - 1.year)
40
+ is_expected.not_to be_valid
41
+ end
42
+ it 'is valid when in future' do
43
+ subject.expiration_date = format_expiration_date(Time.current + 1.year)
44
+ is_expected.to be_valid
45
+ end
46
+ end
47
+ end
48
+
49
+ describe 'subject number' do
50
+ it 'is invalid if number is not real' do
51
+ subject.number = '1234 5678 8765 4321'
52
+ expect(subject).not_to be_valid
53
+ end
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,9 @@
1
+ require 'rails_helper'
2
+
3
+ RSpec.describe Customer, type: :model do
4
+ describe 'Associations' do
5
+ it { should have_many(:orders).dependent(:destroy) }
6
+ end
7
+
8
+ it_behaves_like 'addressable'
9
+ end
@@ -0,0 +1,7 @@
1
+ require 'rails_helper'
2
+
3
+ RSpec.describe Product, type: :model do
4
+ context 'Associations' do
5
+ it { should have_many(:order_items).dependent(:destroy) }
6
+ end
7
+ end
@@ -0,0 +1,14 @@
1
+ require 'rails_helper'
2
+
3
+ module Shopper
4
+ RSpec.describe Address, type: :model do
5
+ describe 'Validation' do
6
+ it { should validate_presence_of(:country) }
7
+ end
8
+
9
+ describe 'Associations' do
10
+ it { should belong_to(:country) }
11
+ it { should belong_to(:addressable) }
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,7 @@
1
+ require 'rails_helper'
2
+
3
+ module Shopper
4
+ RSpec.describe BillingAddress, type: :model do
5
+ it { expect(BillingAddress.superclass).to eq(Address) }
6
+ end
7
+ end
@@ -0,0 +1,10 @@
1
+ require 'rails_helper'
2
+
3
+ module Shopper
4
+ RSpec.describe Country, type: :model do
5
+ context 'Validation' do
6
+ it { should validate_presence_of(:name) }
7
+ it { should validate_presence_of(:code) }
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,9 @@
1
+ require 'rails_helper'
2
+
3
+ module Shopper
4
+ RSpec.describe Coupon, type: :model do
5
+ context 'Validation' do
6
+ it { should belong_to(:order) }
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,7 @@
1
+ require 'rails_helper'
2
+
3
+ module Shopper
4
+ RSpec.describe CreditCard, type: :model do
5
+ it { should belong_to :order }
6
+ end
7
+ end
@@ -0,0 +1,28 @@
1
+ require 'rails_helper'
2
+
3
+ module Shopper
4
+ RSpec.describe Delivery, type: :model do
5
+ describe 'Associations' do
6
+ it { should have_many(:orders) }
7
+ end
8
+
9
+ describe 'Validation' do
10
+ it { should validate_presence_of(:price) }
11
+ it { should validate_presence_of(:min_days) }
12
+ it { should validate_presence_of(:max_days) }
13
+
14
+ it 'min days < max_days' do
15
+ subject = create(:delivery)
16
+ expect(subject.valid?).to eq true
17
+
18
+ subject.min_days = 1
19
+ subject.max_days = 1
20
+ expect(subject.valid?).to eq true
21
+
22
+ subject.min_days = 3
23
+ subject.max_days = 1
24
+ expect(subject.valid?).to eq false
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,18 @@
1
+ require 'rails_helper'
2
+
3
+ module Shopper
4
+ RSpec.describe OrderItem, type: :model do
5
+ describe 'Associations' do
6
+ it { should belong_to(:order) }
7
+ it { should belong_to(:product) }
8
+ end
9
+
10
+ describe 'Validation' do
11
+ it { should validate_presence_of(:order) }
12
+ it { should validate_presence_of(:product) }
13
+ it { should validate_presence_of(:quantity) }
14
+
15
+ it { should validate_numericality_of(:quantity).only_integer.is_greater_than_or_equal_to(1) }
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,105 @@
1
+ require 'rails_helper'
2
+
3
+ module Shopper
4
+ RSpec.describe Order, type: :model do
5
+ describe 'Associations' do
6
+ it { should belong_to(:customer) }
7
+ it { should belong_to(:delivery) }
8
+
9
+ it { should have_one(:credit_card).dependent(:destroy) }
10
+ it { should have_many(:order_items).dependent(:destroy) }
11
+ end
12
+ it { should have_db_column(:use_billing) }
13
+
14
+ it_behaves_like 'addressable'
15
+
16
+ describe '#generate_number' do
17
+ it '...' do
18
+ number = Order.create.number
19
+ expect(number).to start_with('#R')
20
+ expect(number.length).to eq 10
21
+ end
22
+ end
23
+
24
+ describe 'States' do
25
+ subject { create :order, :with_items, :with_addresses }
26
+
27
+ describe '#place_order' do
28
+ it 'expect to allow transition from :in_progress to :processing' do
29
+ subject.place_order
30
+ is_expected.to be_processing
31
+ end
32
+
33
+ it 'expect to allow transition from :in_progress to :processing' do
34
+ subject.place_order
35
+ is_expected.to be_processing
36
+ end
37
+ end
38
+
39
+ describe '#sent_to_client' do
40
+ subject { create(:order, state: :processing) }
41
+
42
+ it 'expect to allow transition from :processing to :in_delivery' do
43
+ subject.sent_to_client
44
+ is_expected.to be_in_delivery
45
+ end
46
+ end
47
+
48
+ describe '#end_delivery' do
49
+ subject { create(:order, state: :in_delivery) }
50
+
51
+ it 'expect to allow transition from :in_delivery to :delivered' do
52
+ subject.end_delivery
53
+ is_expected.to be_delivered
54
+ end
55
+ end
56
+ end
57
+
58
+ describe '#create_or_increment_product' do
59
+ let(:product) { create(:product) }
60
+ subject { create :order }
61
+
62
+ it 'create order item if item doest exits' do
63
+ item = subject.create_or_increment_product('Product', product.id, 10)
64
+ expect(item).to be_persisted
65
+ expect(item.quantity).to eq 10
66
+ end
67
+
68
+ it 'increment item quantity if item exits' do
69
+ subject.order_items.create(product: product, quantity: 1)
70
+ item = subject.create_or_increment_product('Product', product.id, 10)
71
+ expect(item).to be_persisted
72
+ expect(item.quantity).to eq 11
73
+ end
74
+
75
+ it 'return false if invalid product' do
76
+ item = subject.create_or_increment_product('Product', 1000, 10)
77
+ expect(item).to eq false
78
+ end
79
+ end
80
+
81
+
82
+ describe '#create_or_update_product' do
83
+ let(:product) { create(:product) }
84
+ subject { create :order }
85
+
86
+ it 'create order item if item doest exits' do
87
+ item = subject.create_or_update_product('Product', product.id, 10)
88
+ expect(item).to be_persisted
89
+ expect(item.quantity).to eq 10
90
+ end
91
+
92
+ it 'increment item quantity if item exits' do
93
+ subject.order_items.create(product: product, quantity: 1)
94
+ item = subject.create_or_update_product('Product', product.id, 10)
95
+ expect(item).to be_persisted
96
+ expect(item.quantity).to eq 10
97
+ end
98
+
99
+ it 'return false if invalid product' do
100
+ item = subject.create_or_update_product('Product', 1000, 10)
101
+ expect(item).to eq false
102
+ end
103
+ end
104
+ end
105
+ end