app/models/plugins/ecommerce/cart.rb in camaleon_ecommerce-0.0.4 vs app/models/plugins/ecommerce/cart.rb in camaleon_ecommerce-1.1
- old
+ new
@@ -4,37 +4,161 @@
Email: owenperedo@gmail.com
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.
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.
See the GNU Affero General Public License (GPLv3) for more details.
=end
-class Plugins::Ecommerce::Cart < CamaleonCms::TermTaxonomy
- default_scope { where(taxonomy: :ecommerce_cart) }
- has_many :products, foreign_key: :objectid, through: :term_relationships, :source => :objects
- belongs_to :site, :class_name => "CamaleonCms::Site", foreign_key: :parent_id
+class Plugins::Ecommerce::Cart < ActiveRecord::Base
+ self.table_name = 'plugins_ecommerce_orders'
+ default_scope { where(kind: 'cart') }
+ include CamaleonCms::Metas
- def add_product(object)
- post_id = defined?(object.id) ? object.id : object.to_i
- term_relationships.where(objectid: post_id).first_or_create if post_id > 0
+ has_many :product_items, foreign_key: :order_id, class_name: 'Plugins::Ecommerce::ProductItem', dependent: :destroy
+ has_many :products, foreign_key: :order_id, through: :product_items
+
+ belongs_to :site, :class_name => "CamaleonCms::Site", foreign_key: :site_id
+ belongs_to :user, :class_name => "CamaleonCms::User", foreign_key: :user_id
+ after_create :generate_slug
+
+ def add_product(product, qty = 1)
+ pi = product_items.where(product_id: product.id).first
+ if pi.present?
+ pi.update_column(:qty, qty)
+ else
+ pi = product_items.create(product_id: product.id, qty: qty)
+ end
+ pi
end
- def remove_product(object)
- post_id = defined?(object.id) ? object.id : object.to_i
- term_relationships.where(objectid: post_id).destroy_all if post_id > 0
+
+ def remove_product(product_id)
+ product_items.where(product_id: product_id).destroy_all
end
- def the_items_count
- options.map{|k, p| p[:qty].to_i}.inject{|sum,x| sum + x } || 0
+ # return the product titles in array format
+ def products_title
+ products.decorate.each{|p| p.the_title }.join(', ')
end
- def the_amount_total
- options.map{|k, p| (p[:price].to_f + p[:tax])* p[:qty].to_f}.inject{|sum,x| sum + x } || 0
+ def items_total
+ product_items.map{|item| item.qty }.inject{|sum,x| sum + x } || 0
end
+ # price of all products (no include taxes)
+ def sub_total
+ # product_items.map{|item| product = item.product.decorate; (product.price + product.tax) * item.qty }.inject{|sum,x| sum + x } || 0
+ product_items.map{|item| product = item.product.decorate; (product.price) * item.qty }.inject{|sum,x| sum + x } || 0
+ end
+ def tax_total
+ product_items.map{|item| product = item.product.decorate; (product.tax) * item.qty }.inject{|sum,x| sum + x } || 0
+ end
+
+ def weight_total
+ product_items.map{|item| product = item.product.decorate; (product.weight) * item.qty }.inject{|sum,x| sum + x } || 0
+ end
+
+ # verify an return {error: (error code), discount: amount of discount} coupon for current cart
+ # price: the total price including shipping price (used for free discount type)
+ def discount_for(coupon_code, price = nil)
+ coupon = site.coupons.find_by_slug(coupon_code)
+ res = {error: '', discount: 0, coupon: coupon}
+ if coupon.present?
+ opts = coupon.options
+ if coupon.expired?
+ res[:error] = 'coupon_expired'
+ elsif !coupon.active?
+ res[:error] = 'inactive_coupon'
+ elsif coupon.used_times_exceeded?
+ res[:error] = 'times_exceeded'
+ elsif !coupon.valid_min_price?(sub_total)
+ res[:error] = 'required_minimum_price'
+ else
+ case opts[:discount_type]
+ when 'free_ship'
+ res[:discount] = price || sub_total
+ when 'percent'
+ res[:discount] = sub_total * opts[:amount].to_f / 100
+ when 'money'
+ res[:discount] = opts[:amount].to_f
+ end
+ end
+ else
+ res[:error] = 'coupon_not_found'
+ end
+ res
+ end
+
+ # convert into order current cart
+ def make_order!
+ self.update_columns(kind: 'order', created_at: Time.current)
+ site.orders.find(self.id)
+ end
+
+ def shipping_method
+ Plugins::Ecommerce::ShippingMethod.find_by_id(self.shipping_method_id)
+ end
+
+ # return the total price without coupon price
+ def total_to_pay_without_discounts
+ sub_total + tax_total + total_shipping
+ end
+ alias_method :partial_total, :total_to_pay_without_discounts
+
+ # include all costs and discounts
+ def total_amount
+ payment_amount = partial_total
+ if self.coupon.present?
+ res_coupon = self.discount_for(self.coupon, payment_amount)
+ payment_amount = payment_amount - res_coupon[:discount] unless res_coupon[:error].present?
+ end
+ payment_amount < 0 ? 0 : payment_amount
+ end
+
+ # return total of discounts
+ def total_discounts
+ if self.coupon.present?
+ self.discount_for(self.coupon, partial_total)[:discount] || 0
+ else
+ 0
+ end
+ end
+
+ # return the total price of shipping
+ def total_shipping
+ shipping_method.present? ? shipping_method.get_price_from_weight(weight_total) : 0
+ end
+
# set user in filter
def self.set_user(user)
user_id = defined?(user.id) ? user.id : user.to_i
self.where(user_id: user_id)
end
+ # check if the price of the cart is 0, including prices for products, discounts, shipping
+ def free_cart?
+ total_amount <= 0
+ end
+ # return order object
+ def make_paid!(status = 'paid')
+ product_items.decorate.each do |item|
+ p = item.product.decorate
+ 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)
+ end
+
+ if self.coupon.present?
+ res_coupon = self.discount_for(self.coupon, total_to_pay_without_discounts)
+ unless res_coupon[:error].present?
+ update_columns(the_coupon_amount: res_coupon[:coupon].decorate.the_amount, coupon_amount: res_coupon[:discount])
+ res_coupon[:coupon].mark_as_used(user)
+ end
+ end
+ c = self.decorate
+ 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)
+ make_order!
+ end
+
+
+ private
+ def generate_slug
+ self.update_column(:slug, "#{Time.current.to_i}-#{self.id}")
+ end
end
-#Cart = Plugins::Ecommerce::Cart