glysellin 0.4.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +15 -0
- data/MIT-LICENSE +20 -0
- data/README.md +100 -0
- data/Rakefile +29 -0
- data/app/assets/javascripts/glysellin/address.coffee +38 -0
- data/app/assets/javascripts/glysellin/async-cart.coffee +139 -0
- data/app/assets/javascripts/glysellin/base.js +6 -0
- data/app/assets/javascripts/glysellin/cart.coffee +54 -0
- data/app/assets/javascripts/glysellin/main.coffee +0 -0
- data/app/assets/javascripts/glysellin/product.coffee +0 -0
- data/app/assets/stylesheets/glysellin/application.css +13 -0
- data/app/assets/stylesheets/glysellin/orders.css +4 -0
- data/app/assets/stylesheets/glysellin/products.css +4 -0
- data/app/controllers/glysellin/cart/addresses_controller.rb +17 -0
- data/app/controllers/glysellin/cart/discount_code_controller.rb +10 -0
- data/app/controllers/glysellin/cart/payment_method_controller.rb +17 -0
- data/app/controllers/glysellin/cart/products_controller.rb +37 -0
- data/app/controllers/glysellin/cart/shipping_method_controller.rb +18 -0
- data/app/controllers/glysellin/cart/state_controller.rb +15 -0
- data/app/controllers/glysellin/cart_controller.rb +53 -0
- data/app/controllers/glysellin/orders_controller.rb +53 -0
- data/app/controllers/glysellin/products_controller.rb +12 -0
- data/app/helpers/glysellin/application_helper.rb +4 -0
- data/app/helpers/glysellin/cart_helper.rb +21 -0
- data/app/helpers/glysellin/orders_helper.rb +35 -0
- data/app/helpers/glysellin/products_helper.rb +4 -0
- data/app/mailers/glysellin/order_admin_mailer.rb +17 -0
- data/app/mailers/glysellin/order_customer_mailer.rb +27 -0
- data/app/models/glysellin/address.rb +35 -0
- data/app/models/glysellin/brand.rb +14 -0
- data/app/models/glysellin/discount_code.rb +36 -0
- data/app/models/glysellin/discount_type.rb +9 -0
- data/app/models/glysellin/order.rb +243 -0
- data/app/models/glysellin/order_adjustment.rb +19 -0
- data/app/models/glysellin/order_item.rb +38 -0
- data/app/models/glysellin/orderer.rb +28 -0
- data/app/models/glysellin/payment.rb +46 -0
- data/app/models/glysellin/payment_method.rb +36 -0
- data/app/models/glysellin/product.rb +136 -0
- data/app/models/glysellin/product_image.rb +11 -0
- data/app/models/glysellin/product_property.rb +22 -0
- data/app/models/glysellin/product_property_type.rb +11 -0
- data/app/models/glysellin/product_type.rb +11 -0
- data/app/models/glysellin/shipping_method.rb +22 -0
- data/app/models/glysellin/taxonomy.rb +35 -0
- data/app/models/glysellin/variant.rb +100 -0
- data/app/views/glysellin/cart/_added_to_cart_warning.html.erb +21 -0
- data/app/views/glysellin/cart/_cart.html.erb +13 -0
- data/app/views/glysellin/cart/_navigation.html.erb +11 -0
- data/app/views/glysellin/cart/_products.html.erb +125 -0
- data/app/views/glysellin/cart/_recap.html.erb +16 -0
- data/app/views/glysellin/cart/recap/_addresses.html.erb +13 -0
- data/app/views/glysellin/cart/recap/_products.html.erb +63 -0
- data/app/views/glysellin/cart/show.html.erb +13 -0
- data/app/views/glysellin/cart/states/_addresses.html.erb +25 -0
- data/app/views/glysellin/cart/states/_choose_payment_method.html.erb +14 -0
- data/app/views/glysellin/cart/states/_choose_shipping_method.html.erb +14 -0
- data/app/views/glysellin/cart/states/_filled.html.erb +3 -0
- data/app/views/glysellin/cart/states/_init.html.erb +5 -0
- data/app/views/glysellin/cart/states/_ready.html.erb +1 -0
- data/app/views/glysellin/order_admin_mailer/_order_header.text.erb +5 -0
- data/app/views/glysellin/order_admin_mailer/send_check_order_created_email.text.erb +8 -0
- data/app/views/glysellin/order_admin_mailer/send_order_paid_email.text.erb +8 -0
- data/app/views/glysellin/order_customer_mailer/_order_footer.text.erb +3 -0
- data/app/views/glysellin/order_customer_mailer/_order_header.text.erb +5 -0
- data/app/views/glysellin/order_customer_mailer/send_order_created_email.text.erb +7 -0
- data/app/views/glysellin/order_customer_mailer/send_order_paid_email.text.erb +7 -0
- data/app/views/glysellin/order_customer_mailer/send_order_shipped_email.text.erb +8 -0
- data/app/views/glysellin/orders/_addresses_fields.html.erb +29 -0
- data/app/views/glysellin/orders/_order.html.erb +18 -0
- data/app/views/glysellin/orders/_payment_canceled.html.erb +13 -0
- data/app/views/glysellin/orders/_payment_successful.html.erb +6 -0
- data/app/views/glysellin/orders/payment_response.html.erb +5 -0
- data/app/views/glysellin/payment_methods/_paypal-integral.html.erb +22 -0
- data/app/views/glysellin/products/_add_to_cart.html.erb +16 -0
- data/app/views/glysellin/products/_item.html.erb +21 -0
- data/app/views/glysellin/products/filter.html.erb +0 -0
- data/app/views/glysellin/products/index.html.erb +3 -0
- data/app/views/glysellin/products/show.html.erb +3 -0
- data/app/views/glysellin/shared/_address.html.erb +11 -0
- data/app/views/glysellin/shared/_address.text.erb +7 -0
- data/app/views/glysellin/shared/_order.text.erb +56 -0
- data/app/views/glysellin/shared/mailer/_footer.text.erb +2 -0
- data/app/views/layouts/glysellin/application.html.erb +14 -0
- data/config/locales/glysellin.en.yml +113 -0
- data/config/locales/glysellin.fr.yml +119 -0
- data/db/migrate/20120206115004_create_glysellin_orders.rb +16 -0
- data/db/migrate/20120206115132_create_glysellin_customers.rb +8 -0
- data/db/migrate/20120206115657_create_glysellin_addresses.rb +22 -0
- data/db/migrate/20120206124505_create_glysellin_products.rb +20 -0
- data/db/migrate/20120206124545_create_glysellin_order_items.rb +15 -0
- data/db/migrate/20120206124630_create_glysellin_product_images.rb +10 -0
- data/db/migrate/20120206125210_add_attachment_image_to_product_image.rb +15 -0
- data/db/migrate/20120206130920_create_glysellin_payments.rb +13 -0
- data/db/migrate/20120206131042_create_glysellin_payment_methods.rb +10 -0
- data/db/migrate/20120207175050_create_glysellin_taxonomies.rb +11 -0
- data/db/migrate/20120207175158_create_products_taxonomies_table.rb +12 -0
- data/db/migrate/20120515143231_create_brands.rb +9 -0
- data/db/migrate/20120515143233_add_attachment_image_to_brands.rb +15 -0
- data/db/migrate/20120620151705_create_product_properties.rb +12 -0
- data/db/migrate/20130204121211_create_glysellin_discount_types.rb +10 -0
- data/db/migrate/20130204121228_create_glysellin_discount_codes.rb +15 -0
- data/db/migrate/20130204125310_create_glysellin_order_adjustments.rb +13 -0
- data/db/migrate/20130204202102_create_glysellin_shipping_methods.rb +12 -0
- data/db/migrate/20130204202109_add_shipping_method_id_to_glysellin_orders.rb +5 -0
- data/db/migrate/20130205110036_add_weight_to_glysellin_products.rb +5 -0
- data/db/migrate/20130205120541_add_weight_to_glysellin_order_items.rb +5 -0
- data/db/migrate/20130208162813_create_glysellin_variants.rb +17 -0
- data/db/migrate/20130208165020_create_glysellin_product_property_types.rb +7 -0
- data/db/migrate/20130211105557_add_type_id_to_glysellin_product_properties.rb +5 -0
- data/db/migrate/20130211112302_add_variant_id_to_glysellin_product_properties.rb +13 -0
- data/db/migrate/20130211152651_add_product_id_to_glysellin_variants.rb +5 -0
- data/db/migrate/20130212131658_add_weight_to_glysellin_variants.rb +5 -0
- data/db/migrate/20130212132253_remove_variant_columns_from_glysellin_products.rb +15 -0
- data/db/migrate/20130212154943_remove_eot_price_from_glysellin_products.rb +9 -0
- data/db/migrate/20130214184204_create_glysellin_product_types.rb +9 -0
- data/db/migrate/20130214184352_create_product_type_behavior.rb +15 -0
- data/db/migrate/20130221102200_add_unmarked_price_to_glysellin_variants.rb +5 -0
- data/db/migrate/20130311135842_add_addressable_to_glysellin_addresses.rb +6 -0
- data/db/migrate/20130314114048_change_addressable_associations_in_glysellin_addresses.rb +15 -0
- data/db/migrate/20130325113903_remove_address_ids_from_glysellin_orders.rb +11 -0
- data/db/seeds/shipping_carrier/rates/colissimo.csv +16 -0
- data/db/seeds/shipping_carrier/rates/lettre-max.csv +9 -0
- data/lib/active_model/model.rb +101 -0
- data/lib/generators/glysellin/install/USAGE +8 -0
- data/lib/generators/glysellin/install/install_generator.rb +50 -0
- data/lib/generators/glysellin/install/templates/initializer.rb +119 -0
- data/lib/generators/glysellin/install/templates/order_observer.rb +12 -0
- data/lib/generators/glysellin/install/utils.rb +11 -0
- data/lib/glysellin.rb +124 -0
- data/lib/glysellin/acts_as_sellable.rb +14 -0
- data/lib/glysellin/cart.rb +21 -0
- data/lib/glysellin/cart/address.rb +16 -0
- data/lib/glysellin/cart/adjustment.rb +17 -0
- data/lib/glysellin/cart/adjustment/base.rb +41 -0
- data/lib/glysellin/cart/adjustment/discount_code.rb +43 -0
- data/lib/glysellin/cart/adjustment/shipping_method.rb +31 -0
- data/lib/glysellin/cart/basket.rb +482 -0
- data/lib/glysellin/cart/customer.rb +36 -0
- data/lib/glysellin/cart/model_wrapper.rb +90 -0
- data/lib/glysellin/cart/nested_resource.rb +39 -0
- data/lib/glysellin/cart/payment_method.rb +8 -0
- data/lib/glysellin/cart/product.rb +16 -0
- data/lib/glysellin/cart/select.rb +31 -0
- data/lib/glysellin/cart/serializable.rb +30 -0
- data/lib/glysellin/cart/shipping_method.rb +8 -0
- data/lib/glysellin/discount_type_calculator.rb +7 -0
- data/lib/glysellin/discount_type_calculator/base.rb +30 -0
- data/lib/glysellin/discount_type_calculator/order_percentage.rb +16 -0
- data/lib/glysellin/engine.rb +14 -0
- data/lib/glysellin/engine/routes.rb +61 -0
- data/lib/glysellin/gateway.rb +16 -0
- data/lib/glysellin/gateway/atos.rb +111 -0
- data/lib/glysellin/gateway/base.rb +43 -0
- data/lib/glysellin/gateway/check.rb +34 -0
- data/lib/glysellin/gateway/paypal_integral.rb +71 -0
- data/lib/glysellin/helpers.rb +15 -0
- data/lib/glysellin/helpers/controller.rb +22 -0
- data/lib/glysellin/helpers/countries.rb +261 -0
- data/lib/glysellin/helpers/views.rb +28 -0
- data/lib/glysellin/product_methods.rb +66 -0
- data/lib/glysellin/products_list.rb +72 -0
- data/lib/glysellin/property_finder.rb +13 -0
- data/lib/glysellin/shipping_carrier.rb +14 -0
- data/lib/glysellin/shipping_carrier/base.rb +55 -0
- data/lib/glysellin/shipping_carrier/colissimo.rb +19 -0
- data/lib/glysellin/shipping_carrier/flat_rate.rb +19 -0
- data/lib/glysellin/shipping_carrier/free_shipping.rb +14 -0
- data/lib/glysellin/shipping_carrier/helpers/country_weight_table.rb +65 -0
- data/lib/glysellin/shipping_carrier/lettre_max.rb +19 -0
- data/lib/glysellin/version.rb +3 -0
- data/lib/tasks/glysellin_tasks.rake +37 -0
- metadata +341 -0
checksums.yaml
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
---
|
2
|
+
!binary "U0hBMQ==":
|
3
|
+
metadata.gz: !binary |-
|
4
|
+
NTc3ZmMwNGU1YTk5ODFhMDAxZTgwMjBiNDk1Njk5OGZlYzJmOGJmMQ==
|
5
|
+
data.tar.gz: !binary |-
|
6
|
+
YzY4Y2U4NmE1NDEzODQ2NmEwNjVlNWE3NmYzN2NjMDNlYWZlMmIyYw==
|
7
|
+
!binary "U0hBNTEy":
|
8
|
+
metadata.gz: !binary |-
|
9
|
+
MmZjMzA5YTRiOWUzN2Y5ZjgxYWZiZmUzOWI3NDQ3ODI0ZDA1YzJmZDBkYzBk
|
10
|
+
MjYzMGE2NThkYWE5NDc4NTM2NDlkMmJmMzU4NmE4ZGI2ZGQxMmU1MTM5OGQ5
|
11
|
+
MTU3NTYyMjg5ZGQxMzEwNTEwM2ZjMmE2YjQxMDRmYjcxZDZmZjE=
|
12
|
+
data.tar.gz: !binary |-
|
13
|
+
MTU1ZjBiY2M0ZjlkNDBmYzdiYThhNzViMDY3N2M0YjY4ODI5Zjk2OTE5MGQ3
|
14
|
+
NzQ4ZjRmNzdmMGNkMDhiNzVhNWJkMzAxY2YyMGVjMjZlYTc3MDNkNmM3MWJm
|
15
|
+
MmM4NjAwYTA3YmE5NDc5N2ZhN2QxZGIwODAwYTE4MTg0MWY5OGM=
|
data/MIT-LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright 2012 Valentin Ballestrino
|
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.
|
data/README.md
ADDED
@@ -0,0 +1,100 @@
|
|
1
|
+
# Glysellin
|
2
|
+
|
3
|
+
Glysellin is a Rails lightweight e-commerce solution that helps you get simple products, orders and payment gateways without the whole set of functionalities a real e-commerce needs.
|
4
|
+
|
5
|
+
In order to stay simple, we choosed for now to keep with some strong dependencies that may not fit to your app.
|
6
|
+
|
7
|
+
Also, no admin interface is provided so you can integrate it, but we always use [RailsAdmin](https://github.com/sferik/rails_admin).
|
8
|
+
|
9
|
+
|
10
|
+
## Dependencies
|
11
|
+
|
12
|
+
* [Devise](https://github.com/plataformatec/devise)
|
13
|
+
* [Paperclip](https://github.com/thoughtbot/paperclip)
|
14
|
+
* [Simple Form](https://github.com/plataformatec/simple_form)
|
15
|
+
|
16
|
+
|
17
|
+
## Disclaimer
|
18
|
+
|
19
|
+
Glysellin is under development and can now be used, but documentation is poor, there are no tests and API can change quickly while we don't have tested it within enough projects.
|
20
|
+
|
21
|
+
|
22
|
+
## Installing
|
23
|
+
|
24
|
+
To process to glysellin's installation, you shall use the install generator which will :
|
25
|
+
|
26
|
+
* Create an initializer file to configure the shop's behavior
|
27
|
+
* Copy all needed migrations
|
28
|
+
* Migrate and seed default data
|
29
|
+
* Mount the engine
|
30
|
+
* Copy the actions and mailers views to be overriden
|
31
|
+
|
32
|
+
The install generator command :
|
33
|
+
|
34
|
+
```bash
|
35
|
+
rails generate glysellin:install
|
36
|
+
```
|
37
|
+
|
38
|
+
|
39
|
+
## Using the Cart
|
40
|
+
|
41
|
+
The shopping cart contents are stored in user's cookies, with the key `glysellin.cart`
|
42
|
+
|
43
|
+
|
44
|
+
### Displaying the cart
|
45
|
+
|
46
|
+
To display the cart you must render it's partial in your layout :
|
47
|
+
|
48
|
+
```erb
|
49
|
+
<%= render_cart(current_cart) %>
|
50
|
+
```
|
51
|
+
|
52
|
+
|
53
|
+
### Filling the cart
|
54
|
+
|
55
|
+
To fill the cart, you can use the pre-built helper to create a simple "Add to cart" form that asynchronously updates user's cart contents.
|
56
|
+
You must pass the helper a `Glysellin::Product` instance in order to make it work :
|
57
|
+
|
58
|
+
```erb
|
59
|
+
<%= add_to_cart_form(@product) %>
|
60
|
+
```
|
61
|
+
|
62
|
+
|
63
|
+
## Managing orders
|
64
|
+
|
65
|
+
By default, being bound to Devise, Glysellin automatically generates anonymous users to bind orders to. You can choose to keep this behavior alone, or add real subscription in the ordering process or remove the default behavior to force users to create an account by switching off the default functionality in the initializer (default parameter is commented) :
|
66
|
+
|
67
|
+
```ruby
|
68
|
+
# config/initializers/glysellin.rb
|
69
|
+
Glysellin.config do |config|
|
70
|
+
# Allows creating fake accounts for customers with automatic random
|
71
|
+
# password generation
|
72
|
+
# Defaults to true
|
73
|
+
#
|
74
|
+
config.allow_anonymous_orders = true
|
75
|
+
end
|
76
|
+
```
|
77
|
+
|
78
|
+
|
79
|
+
## Customizing Order behavior
|
80
|
+
|
81
|
+
Since the Order object is implemented with the [state_machine gem](), it emits state transition events.
|
82
|
+
On install, a sample observer is copied to `app/models/order_observer.rb` in your application.
|
83
|
+
To be able to use it, you must configure your app to allow the `OrderObserver` to listen to `Order` state transitions by uncommenting and editing the following `active_record.observers` config line in your `application.rb` file :
|
84
|
+
|
85
|
+
```ruby
|
86
|
+
# config/application.rb
|
87
|
+
|
88
|
+
# Activate observers that should always be running.
|
89
|
+
config.active_record.observers = :order_observer
|
90
|
+
```
|
91
|
+
|
92
|
+
|
93
|
+
## Gateway integration
|
94
|
+
|
95
|
+
The routes to redirect the payments gateways to are :
|
96
|
+
|
97
|
+
* For the automatic Server to Server response : `http://yourapp.com/<glysellin_mount_point>/orders/gateway/:gateway` where :gateway is the gateway slug
|
98
|
+
* For the "Return to shop" redirections :
|
99
|
+
* Success response : `http://yourapp.com/<glysellin_mount_point>/orders/gateway/response/paid`
|
100
|
+
* Error response : `http://yourapp.com/<glysellin_mount_point>/orders/gateway/response/cancel`
|
data/Rakefile
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
#!/usr/bin/env rake
|
2
|
+
begin
|
3
|
+
require 'bundler/setup'
|
4
|
+
rescue LoadError
|
5
|
+
puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
|
6
|
+
end
|
7
|
+
begin
|
8
|
+
require 'rdoc/task'
|
9
|
+
rescue LoadError
|
10
|
+
require 'rdoc/rdoc'
|
11
|
+
require 'rake/rdoctask'
|
12
|
+
RDoc::Task = Rake::RDocTask
|
13
|
+
end
|
14
|
+
|
15
|
+
RDoc::Task.new(:rdoc) do |rdoc|
|
16
|
+
rdoc.rdoc_dir = 'rdoc'
|
17
|
+
rdoc.title = 'Glysellin'
|
18
|
+
rdoc.options << '--line-numbers'
|
19
|
+
rdoc.rdoc_files.include('README.rdoc')
|
20
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
21
|
+
end
|
22
|
+
|
23
|
+
APP_RAKEFILE = File.expand_path("../test/dummy/Rakefile", __FILE__)
|
24
|
+
load 'rails/tasks/engine.rake'
|
25
|
+
|
26
|
+
|
27
|
+
|
28
|
+
Bundler::GemHelper.install_tasks
|
29
|
+
|
@@ -0,0 +1,38 @@
|
|
1
|
+
class GlysellinAddress
|
2
|
+
defaults =
|
3
|
+
onUpdated: null
|
4
|
+
|
5
|
+
constructor: (@container) ->
|
6
|
+
@shipping_address_container = @container.find('.shipping-address-container')
|
7
|
+
@billing_address_container = @container.find('.billing-address-container')
|
8
|
+
@toggle_shipping_address = @container.find('[data-toggle="address"]')
|
9
|
+
@shipping_address_fields = @shipping_address_container.clone()
|
10
|
+
@bindAll()
|
11
|
+
|
12
|
+
bindAll: () ->
|
13
|
+
@toggle_shipping_address.on "change", =>
|
14
|
+
@switchAddress()
|
15
|
+
|
16
|
+
switchAddress: () ->
|
17
|
+
if @toggle_shipping_address.is(':checked')
|
18
|
+
@shipping_address_container.html(@shipping_address_fields)
|
19
|
+
|
20
|
+
for attr in ['first_name', 'last_name', 'address', 'zip', 'city', 'tel']
|
21
|
+
if @shipping_address_container.find("[name*='[#{ attr }]']").val() == ""
|
22
|
+
@shipping_address_container.find("[name*='[#{ attr }]']").val(@billing_address_container.find("[name*='[#{ attr }]']").val())
|
23
|
+
|
24
|
+
# Country
|
25
|
+
val = @billing_address_container.find("[name*='country']").val()
|
26
|
+
if @shipping_address_container.find("[name*='country']").val() == ""
|
27
|
+
@shipping_address_container.find("[name*='country']").val(val)
|
28
|
+
@shipping_address_container.find("[name*='country']").change()
|
29
|
+
|
30
|
+
else
|
31
|
+
@shipping_address_fields = @shipping_address_container.clone()
|
32
|
+
@shipping_address_container.html('')
|
33
|
+
|
34
|
+
|
35
|
+
$.fn.glysellinAddress = () ->
|
36
|
+
@each ->
|
37
|
+
address = new GlysellinAddress($(this))
|
38
|
+
address.switchAddress()
|
@@ -0,0 +1,139 @@
|
|
1
|
+
class AsyncCart
|
2
|
+
constructor: (@container) ->
|
3
|
+
@defaultPostOptions = {
|
4
|
+
utf8: @container.find('input[name="utf8"]').val(),
|
5
|
+
authenticity_token: @container.find('input[name="authenticity_token"]').val()
|
6
|
+
}
|
7
|
+
|
8
|
+
$totalRow = @container.find('.products-total-row')
|
9
|
+
@totals = {
|
10
|
+
eot: $totalRow.find('.total-eot-price')
|
11
|
+
total: $totalRow.find('.total-price')
|
12
|
+
}
|
13
|
+
|
14
|
+
@subtotalsRow = @container.find('.products-subtotal-row')
|
15
|
+
@subtotals = {
|
16
|
+
eot: @subtotalsRow.find('.eot-subtotal'),
|
17
|
+
total: @subtotalsRow.find('.subtotal')
|
18
|
+
}
|
19
|
+
|
20
|
+
@adjustmentRow = @container.find('.adjustment-row[data-type=discount-code]')
|
21
|
+
@adjustment = {
|
22
|
+
name: @adjustmentRow.find('.adjustment-name'),
|
23
|
+
value: @adjustmentRow.find('.adjustment-value')
|
24
|
+
}
|
25
|
+
|
26
|
+
@discountCode = @container.find('#glysellin_cart_basket_discount_code')
|
27
|
+
|
28
|
+
@cart_path = @container.data("cart-url")
|
29
|
+
|
30
|
+
@bindAll()
|
31
|
+
|
32
|
+
bindAll: ->
|
33
|
+
@container.find('.quantity-input')
|
34
|
+
.on('change', (e) => @quantityChanged(e.currentTarget))
|
35
|
+
.on 'keyup', (e) =>
|
36
|
+
@handleEnterKey(e)
|
37
|
+
|
38
|
+
@discountCode.on 'keyup', (e) =>
|
39
|
+
@handleEnterKey(e)
|
40
|
+
|
41
|
+
@container.find('.update-discount-code-btn').on 'click', (e) =>
|
42
|
+
@discountCodeUpdated()
|
43
|
+
|
44
|
+
@discountCode.on 'change', (e) =>
|
45
|
+
@discountCodeUpdated()
|
46
|
+
|
47
|
+
@adjustmentRow.find('.remove-discount-btn').on 'click', (e) =>
|
48
|
+
@resetDiscountCode(); false
|
49
|
+
|
50
|
+
@container.on "submit", (e, force = false) -> force
|
51
|
+
|
52
|
+
@container.find("[name=submit_order]").on "click", (e) =>
|
53
|
+
if e.clientX != 0 && e.clientY != 0
|
54
|
+
@container.trigger("submit", [true])
|
55
|
+
|
56
|
+
handleEnterKey: (e) ->
|
57
|
+
$(e.currentTarget).trigger('change') if e.which == 13
|
58
|
+
false
|
59
|
+
|
60
|
+
quantityChanged: (el) ->
|
61
|
+
$el = $(el)
|
62
|
+
quantity = parseInt($el.val(), 10)
|
63
|
+
|
64
|
+
# Ensure we have an int > 0 or use 1
|
65
|
+
unless $.isNumeric(quantity) && quantity > 0
|
66
|
+
quantity = 1
|
67
|
+
$el.val(quantity)
|
68
|
+
|
69
|
+
@update(
|
70
|
+
"products/#{ $el.data('id') }",
|
71
|
+
{ _method: "put", quantity: quantity}
|
72
|
+
(resp) => @remoteQuantityUpdated(resp, $el)
|
73
|
+
)
|
74
|
+
|
75
|
+
remoteQuantityUpdated: (resp, $el) ->
|
76
|
+
# Current product row update handling
|
77
|
+
$tr = $el.closest('tr')
|
78
|
+
$el.val(resp.quantity)
|
79
|
+
$tr.find('.product-eot-price').text(resp.eot_price)
|
80
|
+
$tr.find('.product-price').text(resp.price)
|
81
|
+
|
82
|
+
# Total row handling
|
83
|
+
@setTotals(resp)
|
84
|
+
@setDiscountValues(resp)
|
85
|
+
|
86
|
+
@container.trigger('quantity-updated.glysellin')
|
87
|
+
|
88
|
+
discountCodeUpdated: ->
|
89
|
+
@update(
|
90
|
+
"discount_code"
|
91
|
+
{ _method: "put", code: @discountCode.val() }
|
92
|
+
(resp) => @remoteAdjustmentUpdated(resp)
|
93
|
+
)
|
94
|
+
|
95
|
+
resetDiscountCode: ->
|
96
|
+
@update(
|
97
|
+
'update-discount-code'
|
98
|
+
{ _method: "put", code: '' }
|
99
|
+
(resp) => @remoteAdjustmentUpdated(resp)
|
100
|
+
)
|
101
|
+
|
102
|
+
remoteAdjustmentUpdated: (resp) ->
|
103
|
+
discount = resp.discount_name
|
104
|
+
if discount
|
105
|
+
@setDiscountValues(resp)
|
106
|
+
@subtotalsRow.fadeIn(200)
|
107
|
+
@adjustmentRow.fadeIn(200)
|
108
|
+
else
|
109
|
+
@subtotalsRow.fadeOut(200) unless $('.adjustment-row').length > 1
|
110
|
+
@adjustmentRow.fadeOut(200, => @setDiscountValues(resp))
|
111
|
+
|
112
|
+
# Total row handling when
|
113
|
+
@setTotals(resp)
|
114
|
+
|
115
|
+
@container.trigger('discount-updated.glysellin', [discount])
|
116
|
+
|
117
|
+
update: (action, options, callback) ->
|
118
|
+
$.post(
|
119
|
+
"#{ @cart_path }/#{ action }",
|
120
|
+
$.extend({}, @defaultPostOptions, options),
|
121
|
+
callback,
|
122
|
+
'json'
|
123
|
+
)
|
124
|
+
|
125
|
+
setDiscountValues: (totals) ->
|
126
|
+
@adjustment.name.text(totals.discount_name)
|
127
|
+
@adjustment.value.text(totals.discount_value)
|
128
|
+
|
129
|
+
setTotals: (totals) ->
|
130
|
+
@subtotals.eot.text(totals.eot_subtotal)
|
131
|
+
@subtotals.total.text(totals.subtotal)
|
132
|
+
@totals.eot.text(totals.total_eot_price)
|
133
|
+
@totals.total.text(totals.total_price)
|
134
|
+
|
135
|
+
$.fn.glysellinAsyncCart = (options = {})->
|
136
|
+
@each ->
|
137
|
+
$cart = $(this)
|
138
|
+
data = $cart.data('glysellin.async-cart')
|
139
|
+
$cart.data('glysellin.async-cart', new AsyncCart $cart, options) unless data
|
@@ -0,0 +1,54 @@
|
|
1
|
+
class GlysellinCart
|
2
|
+
defaults =
|
3
|
+
onUpdated: null
|
4
|
+
|
5
|
+
constructor: (@container, options) ->
|
6
|
+
@options = $.extend({}, defaults, options)
|
7
|
+
@add_to_cart_forms = $('[data-add-to-cart-form]')
|
8
|
+
@bindAll()
|
9
|
+
|
10
|
+
bindAll: ->
|
11
|
+
@add_to_cart_forms.on 'ajax:success', (e, resp) =>
|
12
|
+
@update(resp)
|
13
|
+
|
14
|
+
update: (markup) ->
|
15
|
+
$markup = $(markup)
|
16
|
+
$cart = $markup.find('.cart-container')
|
17
|
+
$warning = $markup.find('.added-to-cart-warning').remove()
|
18
|
+
|
19
|
+
@container.html($cart.html())
|
20
|
+
|
21
|
+
if $warning.length > 0
|
22
|
+
$warning.prependTo('body')
|
23
|
+
if ($default_modal = $warning.filter("[data-warning]"))
|
24
|
+
@handleDefaultModal($default_modal)
|
25
|
+
|
26
|
+
@updated()
|
27
|
+
|
28
|
+
updated: ->
|
29
|
+
# Allow app to update cart handlers when content updated
|
30
|
+
@container.trigger('updated.glysellin')
|
31
|
+
# Trigger update callback if passed
|
32
|
+
@options.onUpdated(this) if $.isFunction(@options.onUpdated)
|
33
|
+
|
34
|
+
# Default model handling
|
35
|
+
handleDefaultModal: ($modal) ->
|
36
|
+
$body = $('body')
|
37
|
+
|
38
|
+
closeFromBody = (e) ->
|
39
|
+
if $(e.target).closest("[data-warning]").length == 0
|
40
|
+
close()
|
41
|
+
|
42
|
+
close = ->
|
43
|
+
$modal.fadeOut(200, -> $modal.remove());
|
44
|
+
$body.off "click", closeFromBody
|
45
|
+
false
|
46
|
+
|
47
|
+
$modal.on "click", "[data-dismiss=warning]", close
|
48
|
+
$body.on "click", closeFromBody
|
49
|
+
|
50
|
+
$.fn.glysellinCart = (options) ->
|
51
|
+
@each ->
|
52
|
+
$cart = $(this)
|
53
|
+
data = $cart.data('glysellin.cart')
|
54
|
+
$cart.data('glysellin.cart', new GlysellinCart($cart, options)) unless data
|
File without changes
|
File without changes
|
@@ -0,0 +1,13 @@
|
|
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 vendor/assets/stylesheets of plugins, if any, 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 top of the
|
9
|
+
* compiled file, but it's generally better to create a new file per style scope.
|
10
|
+
*
|
11
|
+
*= require_self
|
12
|
+
*= require_tree .
|
13
|
+
*/
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module Glysellin
|
2
|
+
module Cart
|
3
|
+
class AddressesController < CartController
|
4
|
+
def update
|
5
|
+
current_cart.update(params[:glysellin_cart_basket])
|
6
|
+
|
7
|
+
if current_cart.valid?
|
8
|
+
current_cart.addresses_filled!
|
9
|
+
redirect_to cart_path
|
10
|
+
else
|
11
|
+
current_cart.state = "addresses"
|
12
|
+
render "glysellin/cart/show"
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|