module SolidusReturnly class Calculator attr_accessor :line_items, :order def self.process(order, line_items) new(order, line_items).calculated_estimate end def initialize(order, line_items) self.line_items = line_items self.order = order end def calculated_estimate total = line_items_return_items.values.sum{|iu| iu.sum(&:pre_tax_amount) } tax_amount = returnable_inventory_units.sum do |inventory_unit| calculate_tax inventory_unit end { total_amount: total, subtotal_amount: total - tax_amount, tax_amount: tax_amount, discount_amount: order.promo_total, shipping_amount: order.shipment_total, line_items: present_line_items } end def present_line_items line_items_return_items.map do| line_item_id, inventory_units| line_item = line_item(line_item_id) { order_line_item_id: line_item.id, quantity: inventory_units.size, total_amount: inventory_units.sum(&:amount), tax_amount: line_item.included_tax_total, discount_amount: line_item.adjustment_total, } end end def calculate_tax(inventory_unit) return_item = Spree::ReturnItem.from_inventory_unit(inventory_unit) (return_item.amount <= 0) ? 0 : return_item.amount / Spree::ReturnItem.refund_amount_calculator.new.compute(return_item) end def line_items_return_items found_return_items = {} self.line_items.each do |line_item| quantity = line_item[:quantity].to_i if quantity > 0 available_inventory_units = line_item_inventory_unit(line_item).slice(0, quantity) available_inventory_units.each do |inventory_unit| found_return_items[line_item[:order_line_item_id]] ||= [] found_return_items[line_item[:order_line_item_id]] << Spree::ReturnItem.new({amount: inventory_unit.line_item.price, acceptance_status: 'accepted', inventory_unit_id: inventory_unit.id, reception_status_event: 'receive' }) end end end found_return_items end def line_item_inventory_unit(line_item) returnable_inventory_units.select{|iu| iu.line_item_id == line_item[:order_line_item_id].to_i } end def line_item(id) returnable_line_items.select{|i| i.id == id.to_i }.first end def returnable_inventory_units @_inventory_units ||= order.inventory_units.includes(:line_item) .where(line_item_id: requested_line_items) .where('state is not "returned"') end def returnable_line_items @_line_items ||= returnable_inventory_units.map(&:line_item) end def requested_line_items line_items.map { |item| item[:order_line_item_id] } end end end