module Returnly class Refunder include Returnly::RefundsConfiguration attr_accessor :order, :line_items, :product_refund_amount, :shipping_refund_amount, :customer_return, :return_item_amount_calculator, :return_item_restock_policy, :refund_calculator def initialize(order:, line_items:, product_refund_amount:, shipping_refund_amount:) self.order = order self.line_items = line_items self.product_refund_amount = product_refund_amount self.shipping_refund_amount = shipping_refund_amount configure end def process_return_items each_return_item do |return_item| return_item.amount = return_item_amount_calculator.return_item_refund_amount return_item return_item.additional_tax_total = 0 return_item.resellable = return_item_restock_policy.should_return_item? return_item end end def proceed! return proceed_without_line_items if line_items.empty? return proceed_with_product_zero_amount if product_refund_amount.to_d.zero? process_return_items if customer_return.save! perform_reimbursement RefundPresenter.present_refund(self) end end def refund_available_amount @available_amount ||= Money.from_amount(product_available_amount) end def reimbursement @_reimbursement ||= Spree::Reimbursement.build_from_customer_return(customer_return) end def product_available_amount total = order.total - (order.shipment_total + refund_calculator.shipping_tax + refunds) [total, product_refund_amount.to_d].min end private def add_shipping_amount! ::ReimbursementShipping.new(reimbursement).update!(shipping_refund_amount.to_d) end def refunds order.refunds.sum(&:amount).to_d.round(2, :down) end def configure self.return_item_amount_calculator = return_item_amount_calculator_class.new(self) self.return_item_restock_policy = return_item_restock_policy_class.new(self) self.refund_calculator = refund_calculator_class.new(order, line_items) end def proceed_without_line_items self.customer_return = Returnly::Builders::CustomerReturn.build_by_stock_location(stock_location) reimburse_without_items! RefundPresenter.present_refund(self) end def proceed_with_product_zero_amount Returnly::Services::MarkItemsAsReturned.new(order, line_items).perform! RefundPresenter.present_refund_with_zero_amount(self) end def perform_reimbursement Returnly::Services::CreateReimbursement.new(reimbursement).perform! add_shipping_amount! end def reimburse_without_items! reimbursement_total = product_refund_amount.to_d + shipping_refund_amount.to_d @_reimbursement = Spree::Reimbursement.new( order: order, total: reimbursement_total.round(2, :down) ) reimbursement.save! ::ReimbursementType::OriginalPaymentNoItems.reimburse(reimbursement, nil, false) end def each_return_item return_items = refund_calculator.line_items_return_items.values.flatten self.customer_return = Returnly::Builders::CustomerReturn.build_by_return_items(return_items) return_items.each do |return_item| yield return_item end end def stock_location order.shipments.last.stock_location end end end