camaleon_ecommerce 1.1 → 1.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (70) hide show
  1. checksums.yaml +4 -4
  2. data/app/assets/javascripts/plugins/ecommerce/admin_product.js.coffee +83 -0
  3. data/app/assets/javascripts/plugins/ecommerce/cart.js +3 -0
  4. data/app/controllers/plugins/ecommerce/admin/coupons_controller.rb +6 -12
  5. data/app/controllers/plugins/ecommerce/admin/orders_controller.rb +2 -8
  6. data/app/controllers/plugins/ecommerce/admin/payment_methods_controller.rb +7 -12
  7. data/app/controllers/plugins/ecommerce/admin/prices_controller.rb +0 -8
  8. data/app/controllers/plugins/ecommerce/admin/settings_controller.rb +0 -8
  9. data/app/controllers/plugins/ecommerce/admin/shipping_methods_controller.rb +6 -14
  10. data/app/controllers/plugins/ecommerce/admin/tax_rates_controller.rb +6 -12
  11. data/app/controllers/plugins/ecommerce/admin_controller.rb +27 -8
  12. data/app/controllers/plugins/ecommerce/front/checkout_controller.rb +42 -75
  13. data/app/controllers/plugins/ecommerce/front/orders_controller.rb +2 -10
  14. data/app/controllers/plugins/ecommerce/front_controller.rb +0 -8
  15. data/app/decorators/plugins/ecommerce/coupon_decorator.rb +0 -8
  16. data/app/decorators/plugins/ecommerce/product_decorator.rb +86 -35
  17. data/app/decorators/plugins/ecommerce/product_item_decorator.rb +27 -3
  18. data/app/decorators/plugins/ecommerce/product_variation_decorator.rb +18 -0
  19. data/app/helpers/plugins/ecommerce/ecommerce_email_helper.rb +11 -13
  20. data/app/helpers/plugins/ecommerce/ecommerce_functions_helper.rb +25 -11
  21. data/app/helpers/plugins/ecommerce/ecommerce_helper.rb +22 -27
  22. data/app/helpers/plugins/ecommerce/ecommerce_payment_helper.rb +1 -56
  23. data/app/models/plugins/ecommerce/attribute.rb +9 -0
  24. data/app/models/plugins/ecommerce/cart.rb +46 -28
  25. data/app/models/plugins/ecommerce/coupon.rb +0 -8
  26. data/app/models/plugins/ecommerce/legacy_cart.rb +50 -0
  27. data/app/models/plugins/ecommerce/legacy_order.rb +48 -0
  28. data/app/models/plugins/ecommerce/order.rb +0 -8
  29. data/app/models/plugins/ecommerce/order_detail.rb +0 -9
  30. data/app/models/plugins/ecommerce/payment_method.rb +0 -8
  31. data/app/models/plugins/ecommerce/product_item.rb +3 -10
  32. data/app/models/plugins/ecommerce/product_variation.rb +9 -0
  33. data/app/models/plugins/ecommerce/shipping_method.rb +0 -8
  34. data/app/models/plugins/ecommerce/tax_rate.rb +0 -8
  35. data/app/services/plugins/ecommerce/cart_service.rb +149 -0
  36. data/app/services/plugins/ecommerce/order_service.rb +26 -0
  37. data/app/services/plugins/ecommerce/product_item_service.rb +29 -0
  38. data/app/services/plugins/ecommerce/product_service.rb +17 -0
  39. data/app/services/plugins/ecommerce/site_service.rb +21 -0
  40. data/app/services/plugins/ecommerce/user_cart_service.rb +12 -0
  41. data/app/services/plugins/ecommerce/user_product_service.rb +29 -0
  42. data/app/services/plugins/ecommerce/util_service.rb +5 -0
  43. data/app/views/plugins/ecommerce/admin/orders/form.html.erb +28 -16
  44. data/app/views/plugins/ecommerce/admin/orders/index.html.erb +7 -1
  45. data/app/views/plugins/ecommerce/admin/payment_methods/form.html.erb +11 -1
  46. data/app/views/plugins/ecommerce/admin/product_attributes.html.erb +95 -0
  47. data/app/views/plugins/ecommerce/admin/products/_variations.html.erb +72 -0
  48. data/app/views/plugins/ecommerce/front/checkout/cart_index.html.erb +5 -5
  49. data/app/views/plugins/ecommerce/front/orders/show.html.erb +96 -89
  50. data/app/views/plugins/ecommerce/partials/_cart_widget.html.erb +3 -3
  51. data/app/views/plugins/ecommerce/partials/checkout/_details.html.erb +1 -1
  52. data/app/views/plugins/ecommerce/partials/checkout/_payments.html.erb +6 -1
  53. data/app/views/plugins/ecommerce/partials/checkout/_products_detail.html.erb +1 -1
  54. data/app/views/plugins/ecommerce/partials/checkout/_user_info.html.erb +26 -22
  55. data/app/views/post_types/commerce/single.html.erb +28 -12
  56. data/config/camaleon_plugin.json +4 -12
  57. data/config/custom_models.rb +10 -0
  58. data/config/locales/en.yml +3 -0
  59. data/config/locales/es.yml +112 -54
  60. data/config/routes.rb +2 -0
  61. data/db/migrate/20160527184747_add_new_cart_structure.rb +7 -4
  62. data/db/migrate/20160620200501_add_product_attributes_structure.rb +21 -0
  63. data/db/migrate/20160825174848_set_cama_post_decorator_class.rb +13 -0
  64. data/db/migrate/20160825232739_migrate_order_data.rb +87 -0
  65. data/lib/ecommerce/version.rb +1 -1
  66. metadata +22 -7
  67. data/app/assets/javascripts/plugins/ecommerce/admin.js +0 -0
  68. data/app/assets/javascripts/plugins/ecommerce/fix_form.js +0 -7
  69. data/config/currency_en.json +0 -154
  70. data/config/currency_es.json +0 -154
@@ -1,61 +1,6 @@
1
1
  module Plugins::Ecommerce::EcommercePaymentHelper
2
- include Plugins::Ecommerce::EcommerceHelper
3
-
4
- def payment_pay_by_credit_card_authorize_net(order, payment_method)
5
- billing_address = order.get_meta("billing_address")
6
- details = order.get_meta("details")
7
- amount = commerce_to_cents(order.total_amount)
8
- payment_params = {
9
- :order_id => order.slug,
10
- :currency => current_site.currency_code,
11
- :email => order.user.email,
12
- :billing_address => {:name => "#{order.user.fullname}",
13
- :address1 => billing_address[:address1],
14
- :address2 => billing_address[:address2],
15
- :city => billing_address[:city],
16
- :state => billing_address[:state],
17
- :country => billing_address[:country],
18
- :zip => billing_address[:zip]
19
- },
20
- :description => 'Buy Products',
21
- :ip => request.remote_ip
22
- }
23
-
24
- authorize_net_options = {
25
- :login => payment_method.options[:authorize_net_login_id],
26
- :password => payment_method.options[:authorize_net_transaction_key]
27
- }
28
-
29
- ActiveMerchant::Billing::Base.mode = payment_method.options[:authorize_net_sandbox].to_s.to_bool ? :test : :production
30
-
31
- credit_card = ActiveMerchant::Billing::CreditCard.new(
32
- :first_name => params[:firstName],
33
- :last_name => params[:lastName],
34
- :number => params[:cardNumber],
35
- :month => params[:expMonth],
36
- :year => "20#{params[:expYear]}",
37
- :verification_value => params[:cvCode]
38
- )
39
- if credit_card.validate.empty?
40
- gateway = ActiveMerchant::Billing::AuthorizeNetGateway.new(authorize_net_options)
41
- response = gateway.purchase(amount, credit_card, payment_params)
42
- if response.success?
43
- order.set_meta('pay_authorize_net', payment_params)
44
- return {}
45
- else
46
- return {error: response.message}
47
- end
48
- else
49
- return {error: credit_card.validate.map{|k, v| "#{k}: #{v.join(', ')}"}.join('<br>')}
50
- end
51
- end
52
-
53
2
  def commerce_to_cents(money)
54
- (money*100).round
55
- end
56
-
57
- def commerce_current_currency
58
- current_site.get_meta("_setting_ecommerce", {})[:current_unit] || 'USD'
3
+ Plugins::Ecommerce::UtilService.ecommerce_money_to_cents(money)
59
4
  end
60
5
 
61
6
  end
@@ -0,0 +1,9 @@
1
+ class Plugins::Ecommerce::Attribute < ActiveRecord::Base
2
+ self.table_name='plugins_ecommerce_attributes'
3
+ belongs_to :site
4
+ has_many :values, class_name: 'Plugins::Ecommerce::Attribute', foreign_key: :parent_id, dependent: :destroy
5
+ belongs_to :product_attribute, class_name: 'Plugins::Ecommerce::Attribute', foreign_key: :parent_id
6
+ scope :only_group, ->{ where(parent_id: nil) }
7
+ scope :only_value, ->{ where.not(parent_id: nil) }
8
+ default_scope ->{ order(position: :ASC) }
9
+ end
@@ -1,11 +1,3 @@
1
- =begin
2
- Camaleon CMS is a content management system
3
- Copyright (C) 2015 by Owen Peredo Diaz
4
- Email: owenperedo@gmail.com
5
- This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
6
- This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
7
- See the GNU Affero General Public License (GPLv3) for more details.
8
- =end
9
1
  class Plugins::Ecommerce::Cart < ActiveRecord::Base
10
2
  self.table_name = 'plugins_ecommerce_orders'
11
3
  default_scope { where(kind: 'cart') }
@@ -16,25 +8,23 @@ class Plugins::Ecommerce::Cart < ActiveRecord::Base
16
8
 
17
9
  belongs_to :site, :class_name => "CamaleonCms::Site", foreign_key: :site_id
18
10
  belongs_to :user, :class_name => "CamaleonCms::User", foreign_key: :user_id
11
+ scope :active_cart, ->{ where("#{Plugins::Ecommerce::Cart.table_name}.updated_at >= ?", 24.hours.ago) }
12
+
19
13
  after_create :generate_slug
20
14
 
21
- def add_product(product, qty = 1)
22
- pi = product_items.where(product_id: product.id).first
15
+ def add_product(product, qty = 1, variation_id = nil)
16
+ pi = product_items.where(product_id: product.id, variation_id: variation_id).first
23
17
  if pi.present?
24
18
  pi.update_column(:qty, qty)
25
19
  else
26
- pi = product_items.create(product_id: product.id, qty: qty)
20
+ pi = product_items.create(product_id: product.id, qty: qty, variation_id: variation_id)
27
21
  end
28
22
  pi
29
23
  end
30
24
 
31
- def remove_product(product_id)
32
- product_items.where(product_id: product_id).destroy_all
33
- end
34
-
35
25
  # return the product titles in array format
36
26
  def products_title
37
- products.decorate.each{|p| p.the_title }.join(', ')
27
+ product_items.map{|i| p=i.product.decorate; p.the_variation_title(i.variation_id) }.join(', ')
38
28
  end
39
29
 
40
30
  def items_total
@@ -43,16 +33,15 @@ class Plugins::Ecommerce::Cart < ActiveRecord::Base
43
33
 
44
34
  # price of all products (no include taxes)
45
35
  def sub_total
46
- # product_items.map{|item| product = item.product.decorate; (product.price + product.tax) * item.qty }.inject{|sum,x| sum + x } || 0
47
- product_items.map{|item| product = item.product.decorate; (product.price) * item.qty }.inject{|sum,x| sum + x } || 0
36
+ product_items.map{|item| product = item.product.decorate; (product.price(item.variation_id)) * item.qty }.inject{|sum,x| sum + x } || 0
48
37
  end
49
38
 
50
39
  def tax_total
51
- product_items.map{|item| product = item.product.decorate; (product.tax) * item.qty }.inject{|sum,x| sum + x } || 0
40
+ product_items.map{|item| product = item.product.decorate; (product.tax(item.variation_id)) * item.qty }.inject{|sum,x| sum + x } || 0
52
41
  end
53
42
 
54
43
  def weight_total
55
- product_items.map{|item| product = item.product.decorate; (product.weight) * item.qty }.inject{|sum,x| sum + x } || 0
44
+ product_items.map{|item| product = item.product.decorate; (product.weight(item.variation_id)) * item.qty }.inject{|sum,x| sum + x } || 0
56
45
  end
57
46
 
58
47
  # verify an return {error: (error code), discount: amount of discount} coupon for current cart
@@ -72,8 +61,10 @@ class Plugins::Ecommerce::Cart < ActiveRecord::Base
72
61
  res[:error] = 'required_minimum_price'
73
62
  else
74
63
  case opts[:discount_type]
75
- when 'free_ship'
64
+ when 'free'
76
65
  res[:discount] = price || sub_total
66
+ when 'free_ship'
67
+ res[:discount] = total_shipping
77
68
  when 'percent'
78
69
  res[:discount] = sub_total * opts[:amount].to_f / 100
79
70
  when 'money'
@@ -86,8 +77,17 @@ class Plugins::Ecommerce::Cart < ActiveRecord::Base
86
77
  res
87
78
  end
88
79
 
80
+ def prepare_to_pay
81
+ self.class.transaction do
82
+ self.update_columns(
83
+ status: 'qtys_taken',
84
+ )
85
+ self.product_items.decorate.each{|p_item| p_item.decrement_qty! }
86
+ end
87
+ end
88
+
89
89
  # convert into order current cart
90
- def make_order!
90
+ def convert_to_order
91
91
  self.update_columns(kind: 'order', created_at: Time.current)
92
92
  site.orders.find(self.id)
93
93
  end
@@ -137,23 +137,41 @@ class Plugins::Ecommerce::Cart < ActiveRecord::Base
137
137
  total_amount <= 0
138
138
  end
139
139
 
140
- # return order object
141
- def make_paid!(status = 'paid')
140
+ def update_amounts
142
141
  product_items.decorate.each do |item|
143
142
  p = item.product.decorate
144
- item.update_columns(cache_the_price: item.the_price, cache_the_title: p.the_title, cache_the_tax: p.the_tax, cache_the_sub_total: item.the_sub_total)
143
+ item.update_columns(
144
+ cache_the_price: p.the_price(item.variation_id),
145
+ cache_the_title: p.the_variation_title(item.variation_id),
146
+ cache_the_tax: p.the_tax(item.variation_id),
147
+ cache_the_sub_total: item.the_sub_total,
148
+ )
145
149
  end
146
150
 
147
151
  if self.coupon.present?
148
152
  res_coupon = self.discount_for(self.coupon, total_to_pay_without_discounts)
149
153
  unless res_coupon[:error].present?
150
- update_columns(the_coupon_amount: res_coupon[:coupon].decorate.the_amount, coupon_amount: res_coupon[:discount])
154
+ update_columns(the_coupon_amount: res_coupon[:coupon].decorate.the_amount)
151
155
  res_coupon[:coupon].mark_as_used(user)
152
156
  end
153
157
  end
154
158
  c = self.decorate
155
- self.update_columns(status: status, paid_at: Time.current, amount: total_amount, cache_the_total: c.the_price, cache_the_sub_total: c.the_sub_total, cache_the_tax: c.the_tax_total, cache_the_weight: c.the_weight_total, cache_the_discounts: c.the_total_discounts, cache_the_shipping: c.the_total_shipping)
156
- make_order!
159
+ self.update_columns(
160
+ amount: total_amount,
161
+ cache_the_total: c.the_price,
162
+ cache_the_sub_total: c.the_sub_total,
163
+ cache_the_tax: c.the_tax_total,
164
+ cache_the_weight: c.the_weight_total,
165
+ cache_the_discounts: c.the_total_discounts,
166
+ cache_the_shipping: c.the_total_shipping,
167
+ )
168
+ end
169
+
170
+ def mark_paid(status = 'paid')
171
+ self.update_columns(
172
+ status: status,
173
+ paid_at: Time.current,
174
+ )
157
175
  end
158
176
 
159
177
 
@@ -1,11 +1,3 @@
1
- =begin
2
- Camaleon CMS is a content management system
3
- Copyright (C) 2015 by Owen Peredo Diaz
4
- Email: owenperedo@gmail.com
5
- This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
6
- This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
7
- See the GNU Affero General Public License (GPLv3) for more details.
8
- =end
9
1
  class Plugins::Ecommerce::Coupon < CamaleonCms::TermTaxonomy
10
2
  default_scope { where(taxonomy: :ecommerce_coupon) }
11
3
  belongs_to :site, :class_name => "CamaleonCms::Site", foreign_key: :parent_id
@@ -0,0 +1,50 @@
1
+ class Plugins::Ecommerce::LegacyCart < CamaleonCms::TermTaxonomy
2
+ default_scope { where(taxonomy: :ecommerce_cart) }
3
+ has_many :products, foreign_key: :objectid, through: :term_relationships, :source => :objects
4
+ belongs_to :site, :class_name => "CamaleonCms::Site", foreign_key: :parent_id
5
+
6
+ def add_product(object)
7
+ post_id = defined?(object.id) ? object.id : object.to_i
8
+ term_relationships.where(objectid: post_id).first_or_create if post_id > 0
9
+ end
10
+
11
+ # update or set product quantity
12
+ # return true if it is possible to add the quantity
13
+ # return false if quantity is not enough
14
+ def set_product_qty(product, qty)
15
+ _options = self.get_option("product_#{product.id}")
16
+ if qty.to_f <= product.the_qty_real.to_f
17
+ _options['qty'] = qty
18
+ self.set_option("product_#{product.id}", _options)
19
+ true
20
+ else
21
+ false
22
+ end
23
+ end
24
+
25
+ def remove_product(object)
26
+ post_id = defined?(object.id) ? object.id : object.to_i
27
+ term_relationships.where(objectid: post_id).destroy_all if post_id > 0
28
+ end
29
+
30
+ def the_items_count
31
+ options.map{|k, p| p[:qty].to_i}.inject{|sum,x| sum + x } || 0 rescue 0
32
+ end
33
+
34
+ def the_amount_total
35
+ options.map{|k, p| (p[:price].to_f + p[:tax])* p[:qty].to_f}.inject{|sum,x| sum + x } || 0 rescue 0
36
+ end
37
+
38
+ # return the price of current cart ($10)
39
+ def the_price
40
+ "#{self.site.decorate.current_unit}#{sprintf('%.2f', the_amount_total)}"
41
+ end
42
+
43
+ # set user in filter
44
+ def self.set_user(user)
45
+ user_id = defined?(user.id) ? user.id : user.to_i
46
+ self.where(user_id: user_id)
47
+ end
48
+
49
+
50
+ end
@@ -0,0 +1,48 @@
1
+ class Plugins::Ecommerce::LegacyOrder < CamaleonCms::TermTaxonomy
2
+ default_scope { where(taxonomy: :ecommerce_order) }
3
+ has_one :details, class_name: "Plugins::Ecommerce::OrderDetail", foreign_key: :order_id, dependent: :destroy
4
+ has_many :products, foreign_key: :objectid, through: :term_relationships, :source => :objects
5
+ belongs_to :customer, class_name: "CamaleonCms::User", foreign_key: :user_id
6
+
7
+ def add_product(object)
8
+ post_id = defined?(object.id) ? object.id : object.to_i
9
+ term_relationships.where(objectid: post_id).first_or_create if post_id > 0
10
+ end
11
+ def remove_product(object)
12
+ post_id = defined?(object.id) ? object.id : object.to_i
13
+ term_relationships.where(objectid: post_id).destroy_all if post_id > 0
14
+ end
15
+
16
+ def payment_method
17
+ Plugins::Ecommerce::PaymentMethod.find_by_id get_meta("payment")[:payment_id]
18
+ end
19
+
20
+ def payment
21
+ payment = get_meta("payment")
22
+ get_meta("pay_#{payment[:type]}".to_sym)
23
+ end
24
+
25
+ def shipping_method
26
+ Plugins::Ecommerce::ShippingMethod.find_by_id get_meta("payment", {})[:shipping_method]
27
+ end
28
+
29
+ def canceled?
30
+ status == 'canceled'
31
+ end
32
+ def unpaid?
33
+ status == 'unpaid'
34
+ end
35
+
36
+ def paid?
37
+ payment.present?
38
+ end
39
+
40
+
41
+ # set user in filter
42
+ def self.set_user(user)
43
+ user_id = defined?(user.id) ? user.id : user.to_i
44
+ self.where(user_id: user_id)
45
+ end
46
+
47
+
48
+ end
@@ -1,11 +1,3 @@
1
- =begin
2
- Camaleon CMS is a content management system
3
- Copyright (C) 2015 by Owen Peredo Diaz
4
- Email: owenperedo@gmail.com
5
- This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
6
- This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
7
- See the GNU Affero General Public License (GPLv3) for more details.
8
- =end
9
1
  class Plugins::Ecommerce::Order < Plugins::Ecommerce::Cart
10
2
  self.table_name = 'plugins_ecommerce_orders'
11
3
  has_many :metas, ->{ where(object_class: 'Plugins::Ecommerce::Cart')}, :class_name => "CamaleonCms::Meta", foreign_key: :objectid, dependent: :delete_all
@@ -1,13 +1,4 @@
1
- =begin
2
- Camaleon CMS is a content management system
3
- Copyright (C) 2015 by Owen Peredo Diaz
4
- Email: owenperedo@gmail.com
5
- This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
6
- This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
7
- See the GNU Affero General Public License (GPLv3) for more details.
8
- =end
9
1
  class Plugins::Ecommerce::OrderDetail < ActiveRecord::Base
10
2
  self.table_name = "plugins_order_details"
11
- attr_accessible :order_id, :customer, :email, :phone, :status, :received_at, :accepted_at, :shipped_at, :closed_at
12
3
  belongs_to :order, class_name: "Plugins::Ecommerce::Order", foreign_key: :order_id
13
4
  end
@@ -1,11 +1,3 @@
1
- =begin
2
- Camaleon CMS is a content management system
3
- Copyright (C) 2015 by Owen Peredo Diaz
4
- Email: owenperedo@gmail.com
5
- This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
6
- This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
7
- See the GNU Affero General Public License (GPLv3) for more details.
8
- =end
9
1
  class Plugins::Ecommerce::PaymentMethod < CamaleonCms::TermTaxonomy
10
2
  default_scope { where(taxonomy: :ecommerce_payment_method) }
11
3
  belongs_to :site, :class_name => "CamaleonCms::Site", foreign_key: :parent_id
@@ -1,20 +1,13 @@
1
- =begin
2
- Camaleon CMS is a content management system
3
- Copyright (C) 2015 by Owen Peredo Diaz
4
- Email: owenperedo@gmail.com
5
- This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
6
- This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
7
- See the GNU Affero General Public License (GPLv3) for more details.
8
- =end
9
1
  class Plugins::Ecommerce::ProductItem < ActiveRecord::Base
10
2
  include CamaleonCms::Metas
11
3
  self.table_name = 'plugins_ecommerce_products'
12
- belongs_to :cart, class_name: 'Plugins::Ecommerce::Cart', foreign_key: :order_id
4
+ belongs_to :cart, class_name: 'Plugins::Ecommerce::Cart', foreign_key: :order_id, touch: true
13
5
  belongs_to :order, class_name: 'Plugins::Ecommerce::Order'
14
6
  belongs_to :product, foreign_key: :product_id, class_name: 'CamaleonCms::Post'
7
+ belongs_to :product_variation, class_name: 'Plugins::Ecommerce::ProductVariation', foreign_key: :variation_id
15
8
 
16
9
  def sub_total
17
10
  p = self.product.decorate
18
- (p.price + p.tax) * self.qty
11
+ (p.price(self.variation_id) + p.tax(self.variation_id)) * self.qty
19
12
  end
20
13
  end
@@ -0,0 +1,9 @@
1
+ class Plugins::Ecommerce::ProductVariation < ActiveRecord::Base
2
+ self.table_name='plugins_ecommerce_product_variations'
3
+ belongs_to :product, class_name: "CamaleonCms::Post"
4
+
5
+ # return all attribute values assigned to this product
6
+ def attribute_values
7
+ Plugins::Ecommerce::Attribute.only_value.where(id: self.attribute_ids.to_s.split(','))
8
+ end
9
+ end
@@ -1,11 +1,3 @@
1
- =begin
2
- Camaleon CMS is a content management system
3
- Copyright (C) 2015 by Owen Peredo Diaz
4
- Email: owenperedo@gmail.com
5
- This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
6
- This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
7
- See the GNU Affero General Public License (GPLv3) for more details.
8
- =end
9
1
  class Plugins::Ecommerce::ShippingMethod < CamaleonCms::TermTaxonomy
10
2
  default_scope { where(taxonomy: :ecommerce_shipping_method) }
11
3
  belongs_to :site, :class_name => "CamaleonCms::Site", foreign_key: :parent_id
@@ -1,11 +1,3 @@
1
- =begin
2
- Camaleon CMS is a content management system
3
- Copyright (C) 2015 by Owen Peredo Diaz
4
- Email: owenperedo@gmail.com
5
- This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
6
- This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
7
- See the GNU Affero General Public License (GPLv3) for more details.
8
- =end
9
1
  class Plugins::Ecommerce::TaxRate < CamaleonCms::TermTaxonomy
10
2
  default_scope { where(taxonomy: :ecommerce_tax_rate) }
11
3
  belongs_to :site, :class_name => "CamaleonCms::Site", foreign_key: :parent_id
@@ -0,0 +1,149 @@
1
+ class Plugins::Ecommerce::CartService
2
+ def initialize(site, cart)
3
+ @site = site
4
+ @cart = cart
5
+ end
6
+
7
+ attr_reader :site, :cart
8
+
9
+ def pay_with_authorize_net(options={})
10
+ payment_method = options[:payment_method] || site_service.payment_method('authorize_net')
11
+ billing_address = cart.get_meta("billing_address")
12
+ details = cart.get_meta("details")
13
+ amount = Plugins::Ecommerce::UtilService.ecommerce_money_to_cents(cart.total_amount)
14
+ payment_params = {
15
+ order_id: cart.slug,
16
+ currency: site.currency_code,
17
+ email: cart.user.email,
18
+ billing_address: {name: "#{cart.user.fullname}",
19
+ address1: billing_address[:address1],
20
+ address2: billing_address[:address2],
21
+ city: billing_address[:city],
22
+ state: billing_address[:state],
23
+ country: billing_address[:country],
24
+ zip: billing_address[:zip]
25
+ },
26
+ description: 'Buy Products',
27
+ ip: options[:ip]
28
+ }
29
+
30
+ if options[:ip]
31
+ payment_params[:ip] = options[:ip]
32
+ end
33
+
34
+ authorize_net_options = {
35
+ login: payment_method.options[:authorize_net_login_id],
36
+ password: payment_method.options[:authorize_net_transaction_key]
37
+ }
38
+
39
+ ActiveMerchant::Billing::Base.mode = payment_method.options[:authorize_net_sandbox].to_s.to_bool ? :test : :production
40
+
41
+ credit_card = ActiveMerchant::Billing::CreditCard.new(
42
+ first_name: options[:first_name],
43
+ last_name: options[:last_name],
44
+ number: options[:number],
45
+ month: options[:exp_month],
46
+ year: "20#{options[:exp_year]}",
47
+ verification_value: options[:cvc]
48
+ )
49
+ if credit_card.validate.empty?
50
+ gateway = ActiveMerchant::Billing::AuthorizeNetGateway.new(authorize_net_options)
51
+ response = gateway.purchase(amount, credit_card, payment_params)
52
+ if response.success?
53
+ cart.set_meta('pay_authorize_net', payment_params)
54
+ return {}
55
+ else
56
+ return {error: response.message}
57
+ end
58
+ else
59
+ return {error: credit_card.validate.map{|k, v| "#{k}: #{v.join(', ')}"}.join('<br>')}
60
+ end
61
+ end
62
+
63
+ def pay_with_paypal(options={})
64
+ payment_method = options[:payment_method] || site_service.payment_method('paypal')
65
+ billing_address = cart.get_meta("billing_address")
66
+ ActiveMerchant::Billing::Base.mode = payment_method.options[:paypal_sandbox].to_s.to_bool ? :test : :production
67
+ paypal_options = {
68
+ login: payment_method.options[:paypal_login],
69
+ password: payment_method.options[:paypal_password],
70
+ signature: payment_method.options[:paypal_signature]
71
+ }
72
+ gateway = ActiveMerchant::Billing::PaypalExpressGateway.new(paypal_options)
73
+ amount_in_cents = Plugins::Ecommerce::UtilService.ecommerce_money_to_cents(cart.total_amount)
74
+ gateway_request = {
75
+ brand_name: site.name,
76
+ items: [{
77
+ number: cart.slug,
78
+ name: "Buy Products from #{site.the_title}: #{cart.products_title}",
79
+ amount: amount_in_cents,
80
+ }],
81
+ order_id: cart.slug,
82
+ currency: site.currency_code,
83
+ email: cart.user.email,
84
+ billing_address: {name: "#{billing_address[:first_name]} #{billing_address[:last_name]}",
85
+ address1: billing_address[:address1],
86
+ address2: billing_address[:address2],
87
+ city: billing_address[:city],
88
+ state: billing_address[:state],
89
+ country: billing_address[:country],
90
+ zip: billing_address[:zip]
91
+ },
92
+ description: "Buy Products from #{site.the_title}: #{cart.total_amount}",
93
+ ip: options[:ip],
94
+ return_url: options[:return_url],
95
+ cancel_return_url: options[:cancel_return_url]
96
+ }
97
+
98
+ if options[:ip]
99
+ gateway_request[:ip] = options[:ip]
100
+ end
101
+
102
+ response = gateway.setup_purchase(amount_in_cents, gateway_request)
103
+ # TODO handle errors
104
+ {redirect_url: gateway.redirect_url_for(response.token)}
105
+ end
106
+
107
+ def pay_with_stripe(options)
108
+ require 'stripe'
109
+ payment_method = options[:payment_method] || site_service.payment_method('stripe')
110
+ Stripe.api_key = payment_method.options[:stripe_id]
111
+ customer = Stripe::Customer.create(
112
+ email: options[:email], source: options[:stripe_token])
113
+ amount_in_cents = Plugins::Ecommerce::UtilService.ecommerce_money_to_cents(cart.total_amount)
114
+ begin
115
+ charge = Stripe::Charge.create(
116
+ customer: customer.id,
117
+ amount: amount_in_cents,
118
+ description: "Payment Products: #{cart.products_title}",
119
+ currency: site_service.currency,
120
+ )
121
+ payment_data = {
122
+ email: options[:email],
123
+ customer: customer.id,
124
+ charge: charge.id,
125
+ }
126
+ cart.set_meta("payment_data", payment_data)
127
+ {}
128
+ rescue Stripe::CardError => e
129
+ {error: e.message, payment_error: true}
130
+ rescue => e
131
+ {error: e.message}
132
+ end
133
+ end
134
+
135
+ def convert_to_order(status = 'paid')
136
+ Plugins::Ecommerce::Cart.transaction do
137
+ cart.prepare_to_pay
138
+ cart.update_amounts
139
+ cart.mark_paid(status)
140
+ cart.convert_to_order
141
+ end
142
+ end
143
+
144
+ private
145
+
146
+ def site_service
147
+ @site_service ||= Plugins::Ecommerce::SiteService.new(site)
148
+ end
149
+ end