app/models/shoppe/order/delivery.rb in shoppe-0.0.19 vs app/models/shoppe/order/delivery.rb in shoppe-0.0.20

- old
+ new

@@ -26,18 +26,19 @@ order.validates :delivery_address3, :presence => true order.validates :delivery_address4, :presence => true order.validates :delivery_postcode, :presence => true order.validates :delivery_country, :presence => true end + validate do if self.delivery_required? if self.delivery_service.nil? errors.add :delivery_service_id, "must be specified" return end - if self.delivery_service && !available_delivery_services.include?(self.delivery_service) + unless self.valid_delivery_service? errors.add :delivery_service_id, "is not suitable for this order" end end end @@ -45,18 +46,22 @@ # Ensure that before we confirm the order that the delivery service which has been selected # is appropritae for the contents of the order. if self.delivery_required? && !self.valid_delivery_service? raise Shoppe::Errors::InappropriateDeliveryService, :order => self end - - # Store the delivery prices with the order - if self.delivery_service - write_attribute :delivery_service_id, self.delivery_service.id - write_attribute :delivery_price, self.delivery_price - write_attribute :delivery_cost_price, self.delivery_cost_price - write_attribute :delivery_tax_amount, self.delivery_tax_amount - write_attribute :delivery_tax_rate, self.delivery_tax_rate + cache_delivery_pricing + end + + # If an order has been received and something changes the delivery service or the delivery price + # is cleared, we will re-cache all the delivery pricing so that we have the latest. + before_save do + if received? && (delivery_service_id_changed? || (self.delivery_price_changed? && read_attribute(:delivery_price).blank?)) + self.delivery_price = nil + self.delivery_cost_price = nil + self.delivery_tax_rate = nil + self.delivery_tax_amount = nil + cache_delivery_pricing end end # If there isn't a seperate address needed, clear all the fields back to nil before_validation do @@ -77,10 +82,32 @@ define_method(f) do separate_delivery_address? ? super() : send(f.to_s.gsub('delivery_', 'billing_')) end end + # Cache delivery prices for the order + def cache_delivery_pricing + if self.delivery_service + write_attribute :delivery_service_id, self.delivery_service.id + write_attribute :delivery_price, self.delivery_price + write_attribute :delivery_cost_price, self.delivery_cost_price + write_attribute :delivery_tax_rate, self.delivery_tax_rate + else + write_attribute :delivery_service_id, nil + write_attribute :delivery_price, nil + write_attribute :delivery_cost_price, nil + write_attribute :delivery_tax_rate, nil + write_attribute :delivery_tax_amount, nil + end + end + + # Cache prices and save the order + def cache_delivery_pricing! + cache_delivery_pricing + save! + end + # Has this order been shipped? # # @return [Boolean] def shipped? !!self.shipped_at? @@ -88,11 +115,11 @@ # The total weight of the order # # @return [BigDecimal] def total_weight - order_items.inject(BigDecimal(0)) { |t,i| t + i.weight} + order_items.inject(BigDecimal(0)) { |t,i| t + i.total_weight} end # Is delivery required for this order? # # @return [Boolean] @@ -103,27 +130,24 @@ # An array of all the delivery services which are suitable for this order in it's # current state (based on its current weight) # # @return [Array] an array of Shoppe::DeliveryService objects def available_delivery_services - @available_delivery_services ||= begin - delivery_service_prices.map(&:delivery_service).uniq - end + delivery_service_prices.map(&:delivery_service).uniq end # An array of all the delivery service prices which can be applied to this order. # # @return [Array] an array of Shoppe:DeliveryServicePrice objects def delivery_service_prices - @delivery_service_prices ||= begin - if delivery_required? - prices = Shoppe::DeliveryServicePrice.joins(:delivery_service).where(:shoppe_delivery_services => {:active => true}).order("`default` desc, price asc").for_weight(total_weight) - prices = prices.select { |p| p.countries.empty? || p.country?(self.delivery_country) } - prices - else - [] - end + if delivery_required? + prices = Shoppe::DeliveryServicePrice.joins(:delivery_service).where(:shoppe_delivery_services => {:active => true}).order(:price).for_weight(total_weight) + prices = prices.select { |p| p.countries.empty? || p.country?(self.delivery_country) } + prices = prices.group_by { |dsp| dsp.delivery_service.default? } + (prices[true] || []) | (prices[false] || []) + else + [] end end # The recommended delivery service for this order # @@ -134,54 +158,49 @@ # Return the delivery price for this order in its current state # # @return [BigDecimal] def delivery_service_price - @delivery_service_price ||= self.delivery_service && self.delivery_service.delivery_service_prices.for_weight(self.total_weight).first + self.delivery_service && self.delivery_service.delivery_service_prices.for_weight(self.total_weight).first end # The price for delivering this order in its current state # # @return [BigDecimal] def delivery_price - @delivery_price ||= read_attribute(:delivery_price) || delivery_service_price.try(:price) || 0.0 + read_attribute(:delivery_price) || delivery_service_price.try(:price) || BigDecimal(0) end # The cost of delivering this order in its current state # # @return [BigDecimal] def delivery_cost_price - @delivery_cost_price ||= read_attribute(:delivery_cost_price) || delivery_service_price.try(:cost_price) || 0.0 + read_attribute(:delivery_cost_price) || delivery_service_price.try(:cost_price) || BigDecimal(0) end # The tax amount due for the delivery of this order in its current state # # @return [BigDecimal] def delivery_tax_amount - @delivery_tax_amount ||= begin - read_attribute(:delivery_tax_amount) || - delivery_price / BigDecimal(100) * delivery_tax_rate || - 0.0 - end + read_attribute(:delivery_tax_amount) || + delivery_price / BigDecimal(100) * delivery_tax_rate end # The tax rate for the delivery of this order in its current state # # @return [BigDecimal] def delivery_tax_rate - @delivery_tax_rate ||= begin - read_attribute(:delivery_tax_rate) || - delivery_service_price.try(:tax_rate).try(:rate_for, self) || - 0.0 - end + read_attribute(:delivery_tax_rate) || + delivery_service_price.try(:tax_rate).try(:rate_for, self) || + BigDecimal(0) end # Is the currently assigned delivery service appropriate for this order? # # @return [Boolean] def valid_delivery_service? - self.delivery_service && self.available_delivery_services.include?(self.delivery_service) + self.delivery_service ? self.available_delivery_services.include?(self.delivery_service) : !self.delivery_required? end # Remove the associated delivery service if it's invalid def remove_delivery_service_if_invalid unless self.valid_delivery_service? @@ -197,13 +216,13 @@ return nil if self.shipped_at.blank? || self.consignment_number.blank? @courier_tracking_url ||= self.delivery_service.tracking_url_for(self) end # Mark this order as shipped - def ship!(user, consignment_number) + def ship!(consignment_number, user = nil) run_callbacks :ship do self.shipped_at = Time.now - self.shipped_by = user.id + self.shipper = user if user self.status = 'shipped' self.consignment_number = consignment_number self.save! Shoppe::OrderMailer.shipped(self).deliver end