namespace :exchanges do desc %q{Takes unreturned exchanged items and creates a new order to charge the customer for not returning them} task charge_unreturned_items: :environment do unreturned_return_items = Spree::ReturnItem.awaiting_return.exchange_processed.joins(:exchange_inventory_unit).where([ "spree_inventory_units.created_at < :days_ago", days_ago: Spree::Config[:expedited_exchanges_days_window].days.ago ]).to_a # Determine that a return item has already been deemed unreturned and therefore charged # by the fact that its exchange inventory unit has popped off to a different order unreturned_return_items.select! { |ri| ri.inventory_unit.order_id == ri.exchange_inventory_unit.order_id } failed_orders = [] unreturned_return_items.group_by(&:exchange_shipment).each do |shipment, return_items| begin inventory_units = return_items.map(&:exchange_inventory_unit) original_order = shipment.order order_attributes = { bill_address: original_order.bill_address, ship_address: original_order.ship_address, email: original_order.email } order_attributes[:store_id] = original_order.store_id order = Spree::Order.create!(order_attributes) order.associate_user!(original_order.user) if original_order.user return_items.group_by(&:exchange_variant).map do |variant, variant_return_items| variant_inventory_units = variant_return_items.map(&:exchange_inventory_unit) line_item = Spree::LineItem.create!(variant: variant, quantity: variant_return_items.count, order: order) variant_inventory_units.each { |i| i.update_attributes!(line_item_id: line_item.id, order_id: order.id) } end order.reload.update! while order.state != order.checkout_steps[-2] && order.next; end unless order.payments.present? card_to_reuse = original_order.valid_credit_cards.first card_to_reuse = original_order.user.credit_cards.default.first if !card_to_reuse && original_order.user Spree::Payment.create!(order: order, payment_method_id: card_to_reuse.try(:payment_method_id), source: card_to_reuse, amount: order.total) end # the order builds a shipment on its own on transition to delivery, but we want # the original exchange shipment, not the built one order.shipments.destroy_all shipment.update_attributes!(order_id: order.id) order.update_attributes!(state: "confirm") order.reload.next! order.update! order.finalize! failed_orders << order unless order.completed? && order.valid? rescue failed_orders << order end end failure_message = failed_orders.map { |o| "#{o.number} - #{o.errors.full_messages}" }.join(", ") raise UnableToChargeForUnreturnedItems.new(failure_message) if failed_orders.present? end end class UnableToChargeForUnreturnedItems < StandardError; end