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