cartify 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 (84) hide show
  1. checksums.yaml +7 -0
  2. data/MIT-LICENSE +20 -0
  3. data/README.md +69 -0
  4. data/Rakefile +32 -0
  5. data/app/assets/config/cartify_manifest.js +2 -0
  6. data/app/assets/javascripts/cartify/application.js +14 -0
  7. data/app/assets/javascripts/cartify/checkout.js +11 -0
  8. data/app/assets/javascripts/cartify/masks.js +10 -0
  9. data/app/assets/javascripts/cartify/orders.js +7 -0
  10. data/app/assets/stylesheets/cartify/application.css +15 -0
  11. data/app/concerns/cartify/authenticatable.rb +17 -0
  12. data/app/concerns/cartify/current_session.rb +52 -0
  13. data/app/concerns/cartify/showable.rb +41 -0
  14. data/app/concerns/cartify/updatable.rb +39 -0
  15. data/app/controllers/cartify/addresses_controller.rb +18 -0
  16. data/app/controllers/cartify/application_controller.rb +6 -0
  17. data/app/controllers/cartify/carts_controller.rb +20 -0
  18. data/app/controllers/cartify/checkout_controller.rb +29 -0
  19. data/app/controllers/cartify/order_items_controller.rb +35 -0
  20. data/app/controllers/cartify/orders_controller.rb +17 -0
  21. data/app/decorator/cartify/order_decorator.rb +39 -0
  22. data/app/forms/cartify/addresses_form.rb +71 -0
  23. data/app/helpers/cartify/application_helper.rb +18 -0
  24. data/app/helpers/cartify/carts_helper.rb +10 -0
  25. data/app/helpers/cartify/checkout_helper.rb +22 -0
  26. data/app/helpers/cartify/order_helper.rb +12 -0
  27. data/app/models/cartify/address.rb +23 -0
  28. data/app/models/cartify/application_record.rb +5 -0
  29. data/app/models/cartify/billing.rb +4 -0
  30. data/app/models/cartify/coupon.rb +10 -0
  31. data/app/models/cartify/credit_card.rb +25 -0
  32. data/app/models/cartify/delivery.rb +8 -0
  33. data/app/models/cartify/order.rb +64 -0
  34. data/app/models/cartify/order_item.rb +39 -0
  35. data/app/models/cartify/order_status.rb +18 -0
  36. data/app/models/cartify/shipping.rb +4 -0
  37. data/app/queries/cartify/orders_query.rb +17 -0
  38. data/app/views/cartify/addresses/index.haml +9 -0
  39. data/app/views/cartify/carts/_order_items.haml +17 -0
  40. data/app/views/cartify/carts/_order_summary.haml +15 -0
  41. data/app/views/cartify/carts/_quantity.haml +7 -0
  42. data/app/views/cartify/carts/_xs_order_items.haml +24 -0
  43. data/app/views/cartify/carts/show.html.haml +22 -0
  44. data/app/views/cartify/checkout/_order_summary.haml +4 -0
  45. data/app/views/cartify/checkout/_progress.haml +21 -0
  46. data/app/views/cartify/checkout/addresses.haml +35 -0
  47. data/app/views/cartify/checkout/complete.haml +19 -0
  48. data/app/views/cartify/checkout/confirm.haml +27 -0
  49. data/app/views/cartify/checkout/delivery.haml +11 -0
  50. data/app/views/cartify/checkout/login.haml +39 -0
  51. data/app/views/cartify/checkout/partials/_addresses_short.haml +12 -0
  52. data/app/views/cartify/checkout/partials/_delivery-lg.haml +22 -0
  53. data/app/views/cartify/checkout/partials/_delivery-xs.haml +22 -0
  54. data/app/views/cartify/checkout/partials/_list_of_items.haml +54 -0
  55. data/app/views/cartify/checkout/payment.haml +27 -0
  56. data/app/views/cartify/order_items/create.js.erb +5 -0
  57. data/app/views/cartify/order_items/destroy.js.erb +3 -0
  58. data/app/views/cartify/order_items/update.js.erb +3 -0
  59. data/app/views/cartify/orders/_filters.haml +16 -0
  60. data/app/views/cartify/orders/_orders-lg.haml +10 -0
  61. data/app/views/cartify/orders/_orders-xs.haml +23 -0
  62. data/app/views/cartify/orders/index.haml +21 -0
  63. data/app/views/cartify/orders/show.haml +28 -0
  64. data/app/views/cartify/shared/_address.haml +28 -0
  65. data/app/views/cartify/shared/_addresses_form.haml +31 -0
  66. data/app/views/cartify/shared/_checkout_summary_numbers.haml +15 -0
  67. data/app/views/cartify/shared/_order_summary_numbers.haml +15 -0
  68. data/config/locales/en.yml +135 -0
  69. data/config/routes.rb +9 -0
  70. data/db/migrate/20171005130857_create_cartify_coupons.rb +8 -0
  71. data/db/migrate/20171005131198_create_cartify_credit_cards.rb +12 -0
  72. data/db/migrate/20171005131199_create_cartify_deliveries.rb +9 -0
  73. data/db/migrate/20171005131200_create_cartify_order_statuses.rb +7 -0
  74. data/db/migrate/20171005131201_create_cartify_orders.rb +19 -0
  75. data/db/migrate/20171005131202_create_cartify_order_items.rb +14 -0
  76. data/db/migrate/20171006133037_create_cartify_addresses.rb +17 -0
  77. data/lib/cartify.rb +19 -0
  78. data/lib/cartify/engine.rb +30 -0
  79. data/lib/cartify/version.rb +5 -0
  80. data/lib/generators/initializer/USAGE +49 -0
  81. data/lib/generators/initializer/initializer_generator.rb +17 -0
  82. data/lib/generators/initializer/templates/initializer.rb +10 -0
  83. data/lib/tasks/cartify_tasks.rake +4 -0
  84. metadata +478 -0
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: b71def5e5689f3475d45ba454de57dd8b708cfa8
4
+ data.tar.gz: a571443560cf94bd88dc9e75a5c3ff18ed7840f5
5
+ SHA512:
6
+ metadata.gz: 4ecd656f411bc0f48c7c70b70bcde9f3aa18e84ec080f951de9b6527d6f5445be079cf8aea40e0dc2b49124bd2b86dd31ce95558627b1169a0dc30428fd440f3
7
+ data.tar.gz: ac08b1116714389beaf1e3aa0f5983f7e004ff3c1c062df12ff5434afde48c15af957ce73b3c30828716f8a84654ed53ce0cb9026fa5de81751c848ad345c51b
@@ -0,0 +1,20 @@
1
+ Copyright 2017 Eugene
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,69 @@
1
+ # Cartify
2
+ Shopping cart with a multi-step checkout, easily mounted into Rails application.
3
+
4
+ ## Usage
5
+ Run initializer:
6
+ ```bash
7
+ rails generate initializer
8
+ ```
9
+ Clone migrations:
10
+ ```bash
11
+ rake cartify:install:migrations
12
+ ```
13
+ Define associations in your "User" model:
14
+ ```ruby
15
+ has_many :orders, class_name: 'Cartify::Order', foreign_key: :user_id
16
+ has_one :billing, class_name: 'Cartify::Billing', foreign_key: :user_id
17
+ has_one :shipping, class_name: 'Cartify::Shipping', foreign_key: :user_id
18
+ has_many :addresses, class_name: 'Cartify::Address', foreign_key: :user_id
19
+ ```
20
+
21
+ ## Installation
22
+ Add this line to your application's Gemfile:
23
+
24
+ ```ruby
25
+ gem 'cartify'
26
+ ```
27
+
28
+ And then execute:
29
+ ```bash
30
+ $ bundle
31
+ ```
32
+
33
+ Or install it yourself as:
34
+ ```bash
35
+ $ gem install cartify
36
+ ```
37
+
38
+ ## Available helpers
39
+ #### Shop icon helper
40
+ ```ruby
41
+ shop_icon_quantity
42
+ ```
43
+ Will produce:
44
+ ```html
45
+ <span class="shop-icon">
46
+ <span class="shop-quantity">1</span>
47
+ </span>
48
+ ```
49
+ #### Add to cart link helper
50
+ ```ruby
51
+ add_to_cart(product, quantity, button_name)
52
+ # product - name of your selling product (required!)
53
+ # quantity - how many goods you with put into cart (default: 1)
54
+ # button_name - button name (default: "Add to cart")
55
+ ```
56
+ Or customize as you with:
57
+ ```ruby
58
+ 'helper link': cartify.order_items_path()
59
+ 'required params': order_item: {quantity: quantity, product_id: product.id}
60
+ 'use method': method: :post
61
+ 'asynchronously': remote: true
62
+
63
+ # Example:
64
+ link_to cartify.order_items_path(order_item: {quantity: 7, product_id: product.id}),
65
+ { method: :post, remote: true }
66
+ ```
67
+
68
+ ## License
69
+ The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
@@ -0,0 +1,32 @@
1
+ begin
2
+ require 'bundler/setup'
3
+ rescue LoadError
4
+ puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
5
+ end
6
+
7
+ require 'rdoc/task'
8
+
9
+ RDoc::Task.new(:rdoc) do |rdoc|
10
+ rdoc.rdoc_dir = 'rdoc'
11
+ rdoc.title = 'Cartify'
12
+ rdoc.options << '--line-numbers'
13
+ rdoc.rdoc_files.include('README.md')
14
+ rdoc.rdoc_files.include('lib/**/*.rb')
15
+ end
16
+
17
+ APP_RAKEFILE = File.expand_path('../spec/dummy/Rakefile', __FILE__)
18
+ load 'rails/tasks/engine.rake'
19
+
20
+ load 'rails/tasks/statistics.rake'
21
+
22
+ require 'bundler/gem_tasks'
23
+
24
+ require 'rake/testtask'
25
+
26
+ Rake::TestTask.new(:test) do |t|
27
+ t.libs << 'test'
28
+ t.pattern = 'test/**/*_test.rb'
29
+ t.verbose = false
30
+ end
31
+
32
+ task default: :test
@@ -0,0 +1,2 @@
1
+ //= link_directory ../javascripts/cartify .js
2
+ //= link_directory ../stylesheets/cartify .css
@@ -0,0 +1,14 @@
1
+ // This is a manifest file that'll be compiled into application.js, which will include all the files
2
+ // listed below.
3
+ //
4
+ // Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts,
5
+ // or any plugin's vendor/assets/javascripts directory can be referenced here using a relative path.
6
+ //
7
+ // It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
8
+ // compiled file. JavaScript code in this file should be added after the last require_* statement.
9
+ //
10
+ // Read Sprockets README (https://github.com/rails/sprockets#sprockets-directives) for details
11
+ // about supported directives.
12
+ //
13
+ //= require jquery.mask
14
+ //= require_tree .
@@ -0,0 +1,11 @@
1
+ $(document).ready(function() {
2
+ $(".clickable-step").click(function() {
3
+ window.location = $(this).data("href");
4
+ });
5
+
6
+ $(".clickable-step").css( 'cursor', 'pointer' );
7
+
8
+ $( "#use_billing" ).click(function() {
9
+ $("div.col-md-5.col-md-offset-1").toggle("slow");
10
+ });
11
+ });
@@ -0,0 +1,10 @@
1
+ $(function($){
2
+ $("#credit_card_mm_yy").mask("99/99",{placeholder:"MM/YY"});
3
+ $("#credit_card_cvv").mask("9999");
4
+ $("#credit_card_number").mask("0000 0000 0000 0000", {placeholder: "* * * *\t* * * *\t* * * *\t* * * *"});
5
+ $("#addresses_form_billing_phone").mask("+00 (000) 000-999999");
6
+ $("#addresses_form_shipping_phone").mask("+00 (000) 000-999999");
7
+ $("#addresses_form_billing_zip").mask("0009999999");
8
+ $("#addresses_form_shipping_zip").mask("0009999999");
9
+ });
10
+
@@ -0,0 +1,7 @@
1
+ $(document).ready(function() {
2
+ $(".clickable-row").click(function() {
3
+ window.location = $(this).data("href");
4
+ });
5
+
6
+ $('[data-toggle="tooltip"]').tooltip();
7
+ });
@@ -0,0 +1,15 @@
1
+ /*
2
+ * This is a manifest file that'll be compiled into application.css, which will include all the files
3
+ * listed below.
4
+ *
5
+ * Any CSS and SCSS file within this directory, lib/assets/stylesheets, vendor/assets/stylesheets,
6
+ * or any plugin's vendor/assets/stylesheets directory can be referenced here using a relative path.
7
+ *
8
+ * You're free to add application-wide styles to this file and they'll appear at the bottom of the
9
+ * compiled file so the styles you add here take precedence over styles defined in any other CSS/SCSS
10
+ * files in this directory. Styles in this file should be added after the last require_* statement.
11
+ * It is generally better to create a new file per style scope.
12
+ *
13
+ *= require_tree .
14
+ *= require_self
15
+ */
@@ -0,0 +1,17 @@
1
+ module Cartify::Authenticatable
2
+ extend ActiveSupport::Concern
3
+
4
+ included do
5
+ private
6
+
7
+ def fast_authentification!
8
+ return unless signed_in? and step != :login
9
+ jump_to(:login) unless signed_in?
10
+ end
11
+
12
+ def signed_in?
13
+ return unless respond_to?("#{Cartify.user_class}SignedIn?".underscore)
14
+ public_send "#{Cartify.user_class}SignedIn?".underscore
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,52 @@
1
+ module Cartify::CurrentSession
2
+ thread_mattr_accessor :user
3
+ extend ActiveSupport::Concern
4
+
5
+ included do
6
+ add_flash_types :danger, :warning, :success
7
+ helper_method :current_order, :cartify_current_user, :cartify_authenticate_user!
8
+ before_action :cartify_set_current_user
9
+
10
+ def after_sign_in_path_for(resource)
11
+ if cookies[:from_checkout]
12
+ cookies.delete :from_checkout
13
+ cartify.checkout_path(:addresses)
14
+ else
15
+ super
16
+ end
17
+ end
18
+ end
19
+
20
+ def current_order
21
+ @current_order ||= Cartify::Order.find_or_initialize_by(id: order_id).decorate
22
+ end
23
+
24
+ def cartify_current_user
25
+ return unless respond_to?(devise_current_user_method)
26
+ @cartify_current_user ||= public_send(devise_current_user_method)
27
+ end
28
+
29
+ def cartify_authenticate_user!
30
+ return unless respond_to?("Authenticate#{Cartify.user_class}!".underscore)
31
+ public_send "Authenticate#{Cartify.user_class}!".underscore
32
+ end
33
+
34
+ private
35
+
36
+ def cartify_set_current_user
37
+ Cartify::CurrentSession.user = cartify_current_user
38
+ end
39
+
40
+ def order_id
41
+ order_in_progress&.id || session[:order_id]
42
+ end
43
+
44
+ def order_in_progress
45
+ return unless cartify_current_user
46
+ cartify_current_user.orders.where_status('in_progress').first
47
+ end
48
+
49
+ def devise_current_user_method
50
+ "Current#{Cartify.user_class}".underscore
51
+ end
52
+ end
@@ -0,0 +1,41 @@
1
+ module Cartify::Showable
2
+ extend ActiveSupport::Concern
3
+
4
+ included do
5
+ private
6
+
7
+ def show_login
8
+ return jump_to(next_step) if signed_in?
9
+ cookies[:from_checkout] = { value: true, expires: 1.day.from_now }
10
+ end
11
+
12
+ def show_addresses
13
+ @addresses = Cartify::AddressesForm.new(show_addresses_params)
14
+ end
15
+
16
+ def show_delivery
17
+ return jump_to(previous_step) unless current_order.addresses.presence
18
+ @deliveries = Cartify::Delivery.all
19
+ end
20
+
21
+ def show_payment
22
+ return jump_to(previous_step) unless current_order.delivery
23
+ @credit_card = current_order.credit_card || Cartify::CreditCard.new
24
+ end
25
+
26
+ def show_confirm
27
+ return jump_to(previous_step) unless current_order.credit_card
28
+ show_addresses
29
+ end
30
+
31
+ def show_complete
32
+ return jump_to(previous_step) unless flash[:complete_order]
33
+ @order = cartify_current_user.orders.processing_order.decorate
34
+ end
35
+
36
+ def show_addresses_params # take data from settings if persist
37
+ return { user_id: cartify_current_user.id } if current_order.addresses.empty?
38
+ { order_id: current_order.id }
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,39 @@
1
+ module Cartify::Updatable
2
+ extend ActiveSupport::Concern
3
+
4
+ included do
5
+ private
6
+
7
+ def update_addresses
8
+ @addresses = Cartify::AddressesForm.new(addresses_params)
9
+ render_wizard unless @addresses.save
10
+ end
11
+
12
+ def update_delivery
13
+ current_order.update_attributes(order_params)
14
+ flash[:notice] = t('delivery.pickup') if current_order.delivery_id.nil?
15
+ end
16
+
17
+ def update_payment
18
+ @credit_card = Cartify::CreditCard.new(credit_card_params)
19
+ render_wizard unless @credit_card.save
20
+ end
21
+
22
+ def update_confirm
23
+ flash[:complete_order] = true
24
+ session[:order_id] = nil if current_order.finalize
25
+ end
26
+
27
+ def order_params
28
+ params.require(:order).permit(:delivery_id)
29
+ end
30
+
31
+ def credit_card_params
32
+ params.require(:credit_card).permit(:number, :name, :mm_yy, :cvv)
33
+ end
34
+
35
+ def addresses_params
36
+ params.require(:addresses_form)
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,18 @@
1
+ module Cartify
2
+ class AddressesController < ApplicationController
3
+ def index
4
+ @addresses = Cartify::AddressesForm.new(user_id: cartify_current_user.id)
5
+ end
6
+
7
+ def create
8
+ @addresses = Cartify::AddressesForm.new(addresses_params)
9
+ render :index, object: @addresses.errors
10
+ end
11
+
12
+ private
13
+
14
+ def addresses_params
15
+ params.require(:addresses_form)
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,6 @@
1
+ module Cartify
2
+ class ApplicationController < ::ApplicationController
3
+ protect_from_forgery with: :exception
4
+ include Cartify::Authenticatable
5
+ end
6
+ end
@@ -0,0 +1,20 @@
1
+ require_dependency 'cartify/application_controller'
2
+
3
+ module Cartify
4
+ class CartsController < ApplicationController
5
+ def show
6
+ @order_items = current_order.order_items
7
+ end
8
+
9
+ def update
10
+ current_order.update_attributes(coupon_id: coupon.id) if coupon
11
+ redirect_to cart_path, notice: coupon ? t('flash.coupon_applied') : t('flash.fake_coupon')
12
+ end
13
+
14
+ private
15
+
16
+ def coupon
17
+ @coupon ||= Cartify::Coupon.find_by(name: params[:name])
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,29 @@
1
+ require_dependency 'cartify/application_controller'
2
+
3
+ module Cartify
4
+ class CheckoutController < ApplicationController
5
+ before_action :fast_authentification!
6
+ include Wicked::Wizard
7
+ include Showable
8
+ include Updatable
9
+
10
+ steps :login, :addresses, :delivery, :payment, :confirm, :complete
11
+
12
+ def show
13
+ return redirect_to main_app.send(Cartify.empty_cart_path) if no_items_in_cart?
14
+ send("show_#{step}") unless step == 'wicked_finish'
15
+ render_wizard
16
+ end
17
+
18
+ def update
19
+ send("update_#{step}")
20
+ redirect_to next_wizard_path unless performed?
21
+ end
22
+
23
+ private
24
+
25
+ def no_items_in_cart?
26
+ current_order.order_items.empty? && step != :complete
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,35 @@
1
+ require_dependency 'cartify/application_controller'
2
+
3
+ module Cartify
4
+ class OrderItemsController < ApplicationController
5
+ def create
6
+ current_order.save
7
+ @order_item = current_order.order_items.find_or_initialize_by(product_id: order_item_params[:product_id])
8
+ session[:order_id] = current_order.id if update_quantity.save
9
+ end
10
+
11
+ def update
12
+ @order_item = current_order.order_items.find(params[:id])
13
+ @order_item.update_attributes(order_item_params)
14
+ @order_items = current_order.order_items
15
+ end
16
+
17
+ def destroy
18
+ @order_item = current_order.order_items.find(params[:id])
19
+ @order_item.destroy
20
+ @order_items = current_order.order_items
21
+ end
22
+
23
+ private
24
+
25
+ def order_item_params
26
+ params.require(:order_item).permit(:quantity, :product_id)
27
+ end
28
+
29
+ def update_quantity
30
+ qqty = order_item_params[:quantity].to_i
31
+ @order_item.quantity = qqty + @order_item.quantity.to_i
32
+ @order_item
33
+ end
34
+ end
35
+ end