flowcommerce_spree 0.0.3 → 0.0.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +35 -6
- data/app/controllers/concerns/current_zone_loader_decorator.rb +11 -17
- data/app/controllers/flowcommerce_spree/inventory_controller.rb +23 -0
- data/app/controllers/flowcommerce_spree/orders_controller.rb +20 -0
- data/app/controllers/flowcommerce_spree/webhooks_controller.rb +16 -18
- data/app/controllers/users/sessions_controller_decorator.rb +19 -2
- data/app/helpers/spree/core/controller_helpers/flow_io_order_helper_decorator.rb +0 -16
- data/app/models/flowcommerce_spree/settings.rb +1 -0
- data/app/models/spree/address_decorator.rb +1 -1
- data/app/models/spree/calculator/flow_io.rb +24 -12
- data/app/models/spree/calculator/shipping/flow_io.rb +5 -2
- data/app/models/spree/flow_io_credit_card_decorator.rb +21 -0
- data/app/models/spree/flow_io_order_decorator.rb +181 -0
- data/app/models/spree/flow_io_product_decorator.rb +5 -0
- data/app/models/spree/flow_io_variant_decorator.rb +16 -6
- data/app/models/spree/gateway/flow_io.rb +61 -24
- data/app/models/spree/{credit_card_decorator.rb → payment_capture_event_decorator.rb} +1 -1
- data/app/models/spree/zones/flow_io_product_zone_decorator.rb +4 -0
- data/app/overrides/spree/admin/order_sidebar_summary_flow_link.rb +13 -0
- data/app/overrides/spree/admin/products/order_price_flow_message.rb +9 -0
- data/app/serializers/api/v2/order_serializer_decorator.rb +20 -0
- data/app/services/flowcommerce_spree/import_experience_items.rb +1 -21
- data/app/services/flowcommerce_spree/import_item.rb +45 -0
- data/app/services/flowcommerce_spree/order_sync.rb +50 -222
- data/app/services/flowcommerce_spree/order_updater.rb +78 -0
- data/app/services/flowcommerce_spree/webhooks/capture_upserted_v2.rb +76 -0
- data/app/services/flowcommerce_spree/webhooks/card_authorization_upserted_v2.rb +66 -0
- data/app/services/flowcommerce_spree/webhooks/experience_upserted_v2.rb +25 -0
- data/app/services/flowcommerce_spree/webhooks/fraud_status_changed.rb +35 -0
- data/app/services/flowcommerce_spree/webhooks/local_item_upserted.rb +40 -0
- data/app/views/spree/admin/payments/source_views/_flow_io_gateway.html.erb +21 -0
- data/app/workers/flowcommerce_spree/import_item_worker.rb +24 -0
- data/config/routes.rb +3 -1
- data/db/migrate/20201021755957_add_meta_to_spree_tables.rb +6 -4
- data/lib/flow/simple_gateway.rb +0 -36
- data/lib/flowcommerce_spree.rb +6 -2
- data/lib/flowcommerce_spree/engine.rb +6 -1
- data/lib/flowcommerce_spree/experience_service.rb +1 -27
- data/lib/flowcommerce_spree/logging_http_client.rb +29 -13
- data/lib/flowcommerce_spree/session.rb +5 -25
- data/lib/flowcommerce_spree/version.rb +1 -1
- data/lib/tasks/flowcommerce_spree.rake +4 -1
- metadata +77 -28
- data/app/mailers/spree/spree_order_mailer_decorator.rb +0 -24
- data/app/models/spree/line_item_decorator.rb +0 -15
- data/app/models/spree/order_decorator.rb +0 -244
- data/app/views/spree/order_mailer/confirm_email.html.erb +0 -86
- data/app/views/spree/order_mailer/confirm_email.text.erb +0 -38
- data/lib/flow/error.rb +0 -73
- data/lib/flow/pay_pal.rb +0 -25
- data/lib/flowcommerce_spree/webhook_service.rb +0 -184
- data/lib/simple_csv_writer.rb +0 -44
| @@ -0,0 +1,78 @@ | |
| 1 | 
            +
            # frozen_string_literal: true
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            module FlowcommerceSpree
         | 
| 4 | 
            +
              class OrderUpdater
         | 
| 5 | 
            +
                def initialize(order:)
         | 
| 6 | 
            +
                  unless order&.zone&.flow_io_active_or_archiving_experience?
         | 
| 7 | 
            +
                    raise(ArgumentError, 'Experience not defined or not active')
         | 
| 8 | 
            +
                  end
         | 
| 9 | 
            +
             | 
| 10 | 
            +
                  @experience = order.flow_io_experience_key
         | 
| 11 | 
            +
                  @order = order
         | 
| 12 | 
            +
                  @client = FlowcommerceSpree.client
         | 
| 13 | 
            +
                end
         | 
| 14 | 
            +
             | 
| 15 | 
            +
                def upsert_data(flow_io_order = nil)
         | 
| 16 | 
            +
                  return if @order.state == 'complete'
         | 
| 17 | 
            +
             | 
| 18 | 
            +
                  flow_io_order ||= @client.orders.get_by_number(FlowcommerceSpree::ORGANIZATION, @order.number).to_hash
         | 
| 19 | 
            +
             | 
| 20 | 
            +
                  @order.flow_data['order'] = flow_io_order
         | 
| 21 | 
            +
                  return if @order.flow_data.dig('order', 'submitted_at').blank?
         | 
| 22 | 
            +
             | 
| 23 | 
            +
                  attrs_to_update = { meta: @order.meta.to_json, email: @order.flow_customer_email, payment_state: 'pending' }
         | 
| 24 | 
            +
                  attrs_to_update.merge!(@order.prepare_flow_addresses)
         | 
| 25 | 
            +
                  @order.update_columns(attrs_to_update)
         | 
| 26 | 
            +
                  @order.state = 'delivery'
         | 
| 27 | 
            +
                  @order.save!
         | 
| 28 | 
            +
                  @order.create_proposed_shipments
         | 
| 29 | 
            +
                  @order.shipment.update_amounts
         | 
| 30 | 
            +
                  @order.line_items.each(&:store_ets)
         | 
| 31 | 
            +
                  @order.charge_taxes
         | 
| 32 | 
            +
             | 
| 33 | 
            +
                  @order.state = 'payment'
         | 
| 34 | 
            +
                  @order.save!
         | 
| 35 | 
            +
                end
         | 
| 36 | 
            +
             | 
| 37 | 
            +
                def finalize_order
         | 
| 38 | 
            +
                  @order.reload
         | 
| 39 | 
            +
                  @order.finalize!
         | 
| 40 | 
            +
                  @order.update_totals
         | 
| 41 | 
            +
                  @order.save
         | 
| 42 | 
            +
                  @order.after_completed_order
         | 
| 43 | 
            +
                end
         | 
| 44 | 
            +
             | 
| 45 | 
            +
                def complete_checkout
         | 
| 46 | 
            +
                  upsert_data
         | 
| 47 | 
            +
                  map_payments_to_spree
         | 
| 48 | 
            +
                  finalize_order if @order.state == 'complete'
         | 
| 49 | 
            +
                end
         | 
| 50 | 
            +
             | 
| 51 | 
            +
                def map_payments_to_spree
         | 
| 52 | 
            +
                  @order.flow_io_payments&.each do |p|
         | 
| 53 | 
            +
                    payment =
         | 
| 54 | 
            +
                      @order.payments.find_or_initialize_by(response_code: p['reference'], payment_method_id: payment_method_id)
         | 
| 55 | 
            +
                    next unless payment.new_record?
         | 
| 56 | 
            +
             | 
| 57 | 
            +
                    payment.amount = p.dig('total', 'amount')
         | 
| 58 | 
            +
                    payment.pend
         | 
| 59 | 
            +
             | 
| 60 | 
            +
                    # For now this additional update is overwriting the generated identifier with flow.io payment identifier.
         | 
| 61 | 
            +
                    # TODO: Check and possibly refactor in Spree 3.0, where the `before_create :set_unique_identifier`
         | 
| 62 | 
            +
                    # has been removed.
         | 
| 63 | 
            +
                    payment.update_column(:identifier, p['id'])
         | 
| 64 | 
            +
                  end
         | 
| 65 | 
            +
             | 
| 66 | 
            +
                  return if @order.payments.sum(:amount) < @order.amount || @order.state == 'complete'
         | 
| 67 | 
            +
             | 
| 68 | 
            +
                  @order.state = 'confirm'
         | 
| 69 | 
            +
                  @order.save!
         | 
| 70 | 
            +
                  @order.state = 'complete'
         | 
| 71 | 
            +
                  @order.save!
         | 
| 72 | 
            +
                end
         | 
| 73 | 
            +
             | 
| 74 | 
            +
                def payment_method_id
         | 
| 75 | 
            +
                  @payment_method_id ||= Spree::PaymentMethod.find_by(active: true, type: 'Spree::Gateway::FlowIo').id
         | 
| 76 | 
            +
                end
         | 
| 77 | 
            +
              end
         | 
| 78 | 
            +
            end
         | 
| @@ -0,0 +1,76 @@ | |
| 1 | 
            +
            # frozen_string_literal: true
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            module FlowcommerceSpree
         | 
| 4 | 
            +
              module Webhooks
         | 
| 5 | 
            +
                class CaptureUpsertedV2
         | 
| 6 | 
            +
                  attr_reader :errors
         | 
| 7 | 
            +
                  alias full_messages errors
         | 
| 8 | 
            +
             | 
| 9 | 
            +
                  def self.process(data)
         | 
| 10 | 
            +
                    new(data).process
         | 
| 11 | 
            +
                  end
         | 
| 12 | 
            +
             | 
| 13 | 
            +
                  def initialize(data)
         | 
| 14 | 
            +
                    @data = data
         | 
| 15 | 
            +
                    @errors = []
         | 
| 16 | 
            +
                  end
         | 
| 17 | 
            +
             | 
| 18 | 
            +
                  def process
         | 
| 19 | 
            +
                    errors << { message: 'Capture param missing' } && (return self) unless (capture = @data['capture']&.to_hash)
         | 
| 20 | 
            +
             | 
| 21 | 
            +
                    order_number = capture.dig('authorization', 'order', 'number')
         | 
| 22 | 
            +
                    errors << { message: 'Order number param missing' } && (return self) unless order_number
         | 
| 23 | 
            +
             | 
| 24 | 
            +
                    if (order = Spree::Order.find_by(number: order_number))
         | 
| 25 | 
            +
                      upsert_order_captures(order, capture)
         | 
| 26 | 
            +
                      payments = order.flow_io_payments
         | 
| 27 | 
            +
                      map_payment_captures_to_spree(order, payments) if payments.present?
         | 
| 28 | 
            +
                      order
         | 
| 29 | 
            +
                    else
         | 
| 30 | 
            +
                      errors << { message: "Order #{order_number} not found" }
         | 
| 31 | 
            +
                      self
         | 
| 32 | 
            +
                    end
         | 
| 33 | 
            +
                  end
         | 
| 34 | 
            +
             | 
| 35 | 
            +
                  private
         | 
| 36 | 
            +
             | 
| 37 | 
            +
                  def upsert_order_captures(order, capture)
         | 
| 38 | 
            +
                    order.flow_data ||= {}
         | 
| 39 | 
            +
                    order.flow_data['captures'] ||= []
         | 
| 40 | 
            +
                    order_captures = order.flow_data['captures']
         | 
| 41 | 
            +
                    order_captures.delete_if { |c| c['id'] == capture['id'] }
         | 
| 42 | 
            +
                    order_captures << capture
         | 
| 43 | 
            +
                    order.update_column(:meta, order.meta.to_json)
         | 
| 44 | 
            +
                  end
         | 
| 45 | 
            +
             | 
| 46 | 
            +
                  def map_payment_captures_to_spree(order, payments)
         | 
| 47 | 
            +
                    order.flow_data['captures']&.each do |c|
         | 
| 48 | 
            +
                      next unless (payment = captured_payment(payments, c))
         | 
| 49 | 
            +
             | 
| 50 | 
            +
                      payment.capture_events.create!(amount: c['amount'], meta: { 'flow_data' => { 'id' => c['id'] } })
         | 
| 51 | 
            +
                      return if payment.completed? || payment.capture_events.sum(:amount) < payment.amount
         | 
| 52 | 
            +
             | 
| 53 | 
            +
                      payment.complete
         | 
| 54 | 
            +
                    end
         | 
| 55 | 
            +
             | 
| 56 | 
            +
                    return if order.completed?
         | 
| 57 | 
            +
                    return unless order.flow_io_captures_sum >= order.flow_io_total_amount && order.flow_io_balance_amount <= 0
         | 
| 58 | 
            +
             | 
| 59 | 
            +
                    FlowcommerceSpree::OrderUpdater.new(order: order).finalize_order
         | 
| 60 | 
            +
                  end
         | 
| 61 | 
            +
             | 
| 62 | 
            +
                  def captured_payment(flow_order_payments, capture)
         | 
| 63 | 
            +
                    return unless capture['status'] == 'succeeded'
         | 
| 64 | 
            +
             | 
| 65 | 
            +
                    auth = capture.dig('authorization', 'id')
         | 
| 66 | 
            +
                    return unless flow_order_payments&.find { |p| p['reference'] == auth }
         | 
| 67 | 
            +
             | 
| 68 | 
            +
                    return unless (payment = Spree::Payment.find_by(response_code: auth))
         | 
| 69 | 
            +
             | 
| 70 | 
            +
                    return if Spree::PaymentCaptureEvent.where("meta -> 'flow_data' ->> 'id' = ?", capture['id']).exists?
         | 
| 71 | 
            +
             | 
| 72 | 
            +
                    payment
         | 
| 73 | 
            +
                  end
         | 
| 74 | 
            +
                end
         | 
| 75 | 
            +
              end
         | 
| 76 | 
            +
            end
         | 
| @@ -0,0 +1,66 @@ | |
| 1 | 
            +
            # frozen_string_literal: true
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            module FlowcommerceSpree
         | 
| 4 | 
            +
              module Webhooks
         | 
| 5 | 
            +
                class CardAuthorizationUpsertedV2
         | 
| 6 | 
            +
                  attr_reader :errors
         | 
| 7 | 
            +
                  alias full_messages errors
         | 
| 8 | 
            +
             | 
| 9 | 
            +
                  def self.process(data)
         | 
| 10 | 
            +
                    new(data).process
         | 
| 11 | 
            +
                  end
         | 
| 12 | 
            +
             | 
| 13 | 
            +
                  def initialize(data)
         | 
| 14 | 
            +
                    @data = data['authorization']&.to_hash
         | 
| 15 | 
            +
                    @data&.[]('method')&.delete('images')
         | 
| 16 | 
            +
                    @errors = []
         | 
| 17 | 
            +
                  end
         | 
| 18 | 
            +
             | 
| 19 | 
            +
                  def process
         | 
| 20 | 
            +
                    errors << { message: 'Authorization param missing' } && (return self) unless @data
         | 
| 21 | 
            +
             | 
| 22 | 
            +
                    errors << { message: 'Card param missing' } && (return self) unless (flow_io_card = @data.delete('card'))
         | 
| 23 | 
            +
             | 
| 24 | 
            +
                    if (order_number = @data.dig('order', 'number'))
         | 
| 25 | 
            +
                      if (order = Spree::Order.find_by(number: order_number))
         | 
| 26 | 
            +
                        card = upsert_card(flow_io_card, order)
         | 
| 27 | 
            +
             | 
| 28 | 
            +
                        order.payments.where(response_code: @data['id'])
         | 
| 29 | 
            +
                             .update_all(source_id: card.id, source_type: 'Spree::CreditCard')
         | 
| 30 | 
            +
             | 
| 31 | 
            +
                        return card
         | 
| 32 | 
            +
                      else
         | 
| 33 | 
            +
                        errors << { message: "Order #{order_number} not found" }
         | 
| 34 | 
            +
                      end
         | 
| 35 | 
            +
                    else
         | 
| 36 | 
            +
                      errors << { message: 'Order number param missing' }
         | 
| 37 | 
            +
                    end
         | 
| 38 | 
            +
             | 
| 39 | 
            +
                    self
         | 
| 40 | 
            +
                  end
         | 
| 41 | 
            +
             | 
| 42 | 
            +
                  private
         | 
| 43 | 
            +
             | 
| 44 | 
            +
                  def upsert_card(flow_io_card, order)
         | 
| 45 | 
            +
                    flow_io_card_expiration = flow_io_card.delete('expiration')
         | 
| 46 | 
            +
             | 
| 47 | 
            +
                    card = Spree::CreditCard.find_or_initialize_by(month: flow_io_card_expiration['month'].to_s,
         | 
| 48 | 
            +
                                                                   year: flow_io_card_expiration['year'].to_s,
         | 
| 49 | 
            +
                                                                   cc_type: flow_io_card.delete('type'),
         | 
| 50 | 
            +
                                                                   last_digits: flow_io_card.delete('last4'),
         | 
| 51 | 
            +
                                                                   name: flow_io_card.delete('name'),
         | 
| 52 | 
            +
                                                                   user_id: order.user&.id)
         | 
| 53 | 
            +
                    card.flow_data ||= {}
         | 
| 54 | 
            +
                    if card.new_record?
         | 
| 55 | 
            +
                      card.flow_data.merge!(flow_io_card.except('discriminator'))
         | 
| 56 | 
            +
                      card.imported = true
         | 
| 57 | 
            +
                    end
         | 
| 58 | 
            +
             | 
| 59 | 
            +
                    card.push_authorization(@data.except('discriminator'))
         | 
| 60 | 
            +
                    card.new_record? ? card.save : card.update_column(:meta, card.meta.to_json)
         | 
| 61 | 
            +
             | 
| 62 | 
            +
                    card
         | 
| 63 | 
            +
                  end
         | 
| 64 | 
            +
                end
         | 
| 65 | 
            +
              end
         | 
| 66 | 
            +
            end
         | 
| @@ -0,0 +1,25 @@ | |
| 1 | 
            +
            # frozen_string_literal: true
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            module FlowcommerceSpree
         | 
| 4 | 
            +
              module Webhooks
         | 
| 5 | 
            +
                class ExperienceUpsertedV2
         | 
| 6 | 
            +
                  attr_accessor :errors
         | 
| 7 | 
            +
                  alias full_messages errors
         | 
| 8 | 
            +
             | 
| 9 | 
            +
                  def self.process(data, opts = {})
         | 
| 10 | 
            +
                    new(data, opts).process
         | 
| 11 | 
            +
                  end
         | 
| 12 | 
            +
             | 
| 13 | 
            +
                  def initialize(data, opts = {})
         | 
| 14 | 
            +
                    @data = data
         | 
| 15 | 
            +
                    @opts = opts
         | 
| 16 | 
            +
                    @errors = []
         | 
| 17 | 
            +
                  end
         | 
| 18 | 
            +
             | 
| 19 | 
            +
                  def process
         | 
| 20 | 
            +
                    experience = @data['experience']
         | 
| 21 | 
            +
                    Spree::Zones::Product.find_or_initialize_by(name: experience['key'].titleize).store_flow_io_data(experience)
         | 
| 22 | 
            +
                  end
         | 
| 23 | 
            +
                end
         | 
| 24 | 
            +
              end
         | 
| 25 | 
            +
            end
         | 
| @@ -0,0 +1,35 @@ | |
| 1 | 
            +
            # frozen_string_literal: true
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            module FlowcommerceSpree
         | 
| 4 | 
            +
              module Webhooks
         | 
| 5 | 
            +
                class FraudStatusChanged
         | 
| 6 | 
            +
                  attr_accessor :errors
         | 
| 7 | 
            +
                  alias full_messages errors
         | 
| 8 | 
            +
             | 
| 9 | 
            +
                  def self.process(data, opts = {})
         | 
| 10 | 
            +
                    new(data, opts).process
         | 
| 11 | 
            +
                  end
         | 
| 12 | 
            +
             | 
| 13 | 
            +
                  def initialize(data, opts = {})
         | 
| 14 | 
            +
                    @data = data
         | 
| 15 | 
            +
                    @opts = opts
         | 
| 16 | 
            +
                    @errors = []
         | 
| 17 | 
            +
                  end
         | 
| 18 | 
            +
             | 
| 19 | 
            +
                  def process
         | 
| 20 | 
            +
                    order_number = @data.dig('order', 'number')
         | 
| 21 | 
            +
                    errors << { message: 'Order number param missing' } && (return self) unless order_number
         | 
| 22 | 
            +
             | 
| 23 | 
            +
                    order = Spree::Order.find_by(number: order_number)
         | 
| 24 | 
            +
                    errors << { message: "Order #{order_number} not found" } && (return self) unless order
         | 
| 25 | 
            +
             | 
| 26 | 
            +
                    if @data['status'] == 'declined'
         | 
| 27 | 
            +
                      order.update_columns(fraudulent: true)
         | 
| 28 | 
            +
                      order.cancel!
         | 
| 29 | 
            +
                    end
         | 
| 30 | 
            +
             | 
| 31 | 
            +
                    order
         | 
| 32 | 
            +
                  end
         | 
| 33 | 
            +
                end
         | 
| 34 | 
            +
              end
         | 
| 35 | 
            +
            end
         | 
| @@ -0,0 +1,40 @@ | |
| 1 | 
            +
            # frozen_string_literal: true
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            module FlowcommerceSpree
         | 
| 4 | 
            +
              module Webhooks
         | 
| 5 | 
            +
                class LocalItemUpserted
         | 
| 6 | 
            +
                  attr_accessor :errors
         | 
| 7 | 
            +
                  alias full_messages errors
         | 
| 8 | 
            +
             | 
| 9 | 
            +
                  def self.process(data, opts = {})
         | 
| 10 | 
            +
                    new(data, opts).process
         | 
| 11 | 
            +
                  end
         | 
| 12 | 
            +
             | 
| 13 | 
            +
                  def initialize(data, opts = {})
         | 
| 14 | 
            +
                    @data = data
         | 
| 15 | 
            +
                    @opts = opts
         | 
| 16 | 
            +
                    @errors = []
         | 
| 17 | 
            +
                  end
         | 
| 18 | 
            +
             | 
| 19 | 
            +
                  def process
         | 
| 20 | 
            +
                    errors << { message: 'Local item param missing' } && (return self) unless (local_item = @data['local_item'])
         | 
| 21 | 
            +
             | 
| 22 | 
            +
                    errors << { message: 'SKU param missing' } && (return self) unless (flow_sku = local_item.dig('item', 'number'))
         | 
| 23 | 
            +
             | 
| 24 | 
            +
                    if (variant = Spree::Variant.find_by(sku: flow_sku))
         | 
| 25 | 
            +
                      variant.add_flow_io_experience_data(
         | 
| 26 | 
            +
                        local_item.dig('experience', 'key'),
         | 
| 27 | 
            +
                        'prices' => [local_item.dig('pricing', 'price')], 'status' => local_item['status']
         | 
| 28 | 
            +
                      )
         | 
| 29 | 
            +
             | 
| 30 | 
            +
                      variant.update_column(:meta, variant.meta.to_json)
         | 
| 31 | 
            +
                      return variant
         | 
| 32 | 
            +
                    else
         | 
| 33 | 
            +
                      errors << { message: "Variant with sku [#{flow_sku}] not found!" }
         | 
| 34 | 
            +
                    end
         | 
| 35 | 
            +
             | 
| 36 | 
            +
                    self
         | 
| 37 | 
            +
                  end
         | 
| 38 | 
            +
                end
         | 
| 39 | 
            +
              end
         | 
| 40 | 
            +
            end
         | 
| @@ -0,0 +1,21 @@ | |
| 1 | 
            +
            <fieldset data-hook="credit_card">
         | 
| 2 | 
            +
              <legend align="center"><%= Spree.t(:credit_card) %></legend>
         | 
| 3 | 
            +
             | 
| 4 | 
            +
              <div class="row">
         | 
| 5 | 
            +
                <div class="alpha six columns">
         | 
| 6 | 
            +
                  <dl>
         | 
| 7 | 
            +
                    <dt><%= Spree.t(:name_on_card) %>:</dt>
         | 
| 8 | 
            +
                    <dd><%= payment.source&.name %></dd>
         | 
| 9 | 
            +
             | 
| 10 | 
            +
                    <dt><%= Spree.t(:card_type) %>:</dt>
         | 
| 11 | 
            +
                    <dd><%= payment.source&.cc_type %></dd>
         | 
| 12 | 
            +
             | 
| 13 | 
            +
                    <dt><%= Spree.t(:card_number) %>:</dt>
         | 
| 14 | 
            +
                    <dd><%= payment.source&.display_number %></dd>
         | 
| 15 | 
            +
             | 
| 16 | 
            +
                    <dt><%= Spree.t(:expiration) %>:</dt>
         | 
| 17 | 
            +
                    <dd><%= payment.source&.month %>/<%= payment.source&.year %></dd>
         | 
| 18 | 
            +
                  </dl>
         | 
| 19 | 
            +
                </div>
         | 
| 20 | 
            +
              </div>
         | 
| 21 | 
            +
            </fieldset>
         | 
| @@ -0,0 +1,24 @@ | |
| 1 | 
            +
            # frozen_string_literal: true
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            module FlowcommerceSpree
         | 
| 4 | 
            +
              class ImportItemWorker
         | 
| 5 | 
            +
                include Sidekiq::Worker
         | 
| 6 | 
            +
                sidekiq_options retry: 3, queue: :flow_io
         | 
| 7 | 
            +
             | 
| 8 | 
            +
                sidekiq_retries_exhausted do |message, exception|
         | 
| 9 | 
            +
                  Rails.logger.warn("[!] FlowcommerceSpree::ImportItemWorker max attempts reached: #{message} - #{exception}")
         | 
| 10 | 
            +
                  notification_setting = FlowcommerceSpree::Config.notification_setting
         | 
| 11 | 
            +
                  return unless notification_setting[:slack].present?
         | 
| 12 | 
            +
             | 
| 13 | 
            +
                  slack_message = "[#{Rails.env}] #{message}"
         | 
| 14 | 
            +
                  Slack_client.chat_postMessage(channel: notification_setting[:slack][:channel], text: slack_message)
         | 
| 15 | 
            +
                end
         | 
| 16 | 
            +
             | 
| 17 | 
            +
                def perform(variant_sku)
         | 
| 18 | 
            +
                  variant = Spree::Variant.find_by sku: variant_sku
         | 
| 19 | 
            +
                  return unless variant
         | 
| 20 | 
            +
             | 
| 21 | 
            +
                  FlowcommerceSpree::ImportItem.run(variant)
         | 
| 22 | 
            +
                end
         | 
| 23 | 
            +
              end
         | 
| 24 | 
            +
            end
         | 
    
        data/config/routes.rb
    CHANGED
    
    | @@ -1,5 +1,7 @@ | |
| 1 1 | 
             
            # frozen_string_literal: true
         | 
| 2 2 |  | 
| 3 3 | 
             
            FlowcommerceSpree::Engine.routes.draw do
         | 
| 4 | 
            -
              post '/event-target', to: 'webhooks# | 
| 4 | 
            +
              post '/event-target', to: 'webhooks#handle_flow_io_event'
         | 
| 5 | 
            +
              get '/order-completed', to: 'orders#order_completed'
         | 
| 6 | 
            +
              post '/online-stock-availability', to: 'inventory#online_stock_availability'
         | 
| 5 7 | 
             
            end
         | 
| @@ -5,13 +5,15 @@ class AddMetaToSpreeTables < ActiveRecord::Migration | |
| 5 5 | 
             
                add_column :spree_orders, :meta, :jsonb, default: '{}' unless column_exists?(:spree_orders, :meta)
         | 
| 6 6 | 
             
                add_column :spree_promotions, :meta, :jsonb, default: '{}' unless column_exists?(:spree_promotions, :meta)
         | 
| 7 7 | 
             
                add_column :spree_credit_cards, :meta, :jsonb, default: '{}' unless column_exists?(:spree_credit_cards, :meta)
         | 
| 8 | 
            +
                add_column :spree_payment_capture_events, :meta, :jsonb, default: '{}' unless column_exists?(:spree_payment_capture_events, :meta)
         | 
| 8 9 | 
             
              end
         | 
| 9 10 |  | 
| 10 11 | 
             
              def down
         | 
| 11 | 
            -
                remove_column : | 
| 12 | 
            -
                remove_column :spree_variants, :meta if column_exists?(:spree_variants, :meta)
         | 
| 13 | 
            -
                remove_column :spree_orders, :meta if column_exists?(:spree_orders, :meta)
         | 
| 14 | 
            -
                remove_column :spree_promotions, :meta if column_exists?(:spree_promotions, :meta)
         | 
| 12 | 
            +
                remove_column :spree_payment_capture_events, :meta if column_exists?(:spree_payment_capture_events, :meta)
         | 
| 15 13 | 
             
                remove_column :spree_credit_cards, :meta if column_exists?(:spree_credit_cards, :meta)
         | 
| 14 | 
            +
                remove_column :spree_promotions, :meta if column_exists?(:spree_promotions, :meta)
         | 
| 15 | 
            +
                remove_column :spree_orders, :meta if column_exists?(:spree_orders, :meta)
         | 
| 16 | 
            +
                remove_column :spree_variants, :meta if column_exists?(:spree_variants, :meta)
         | 
| 17 | 
            +
                remove_column :spree_products, :meta if column_exists?(:spree_products, :meta)
         | 
| 16 18 | 
             
              end
         | 
| 17 19 | 
             
            end
         | 
    
        data/lib/flow/simple_gateway.rb
    CHANGED
    
    | @@ -34,42 +34,6 @@ module Flow | |
| 34 34 | 
             
                  error_response(e)
         | 
| 35 35 | 
             
                end
         | 
| 36 36 |  | 
| 37 | 
            -
                # capture authorised funds
         | 
| 38 | 
            -
                def cc_capture
         | 
| 39 | 
            -
                  # GET /:organization/authorizations, order_number: abc
         | 
| 40 | 
            -
                  data = @order.flow_data['authorization']
         | 
| 41 | 
            -
             | 
| 42 | 
            -
                  raise ArgumentError, 'No Authorization data, please authorize first' unless data
         | 
| 43 | 
            -
             | 
| 44 | 
            -
                  capture_form = ::Io::Flow::V0::Models::CaptureForm.new(data)
         | 
| 45 | 
            -
                  response = FlowcommerceSpree.client.captures.post(FlowcommerceSpree::ORGANIZATION, capture_form)
         | 
| 46 | 
            -
             | 
| 47 | 
            -
                  return ActiveMerchant::Billing::Response.new false, 'error', response: response unless response.id
         | 
| 48 | 
            -
             | 
| 49 | 
            -
                  @order.update_column :flow_data, @order.flow_data.merge('capture': response.to_hash)
         | 
| 50 | 
            -
                  @order.flow_finalize!
         | 
| 51 | 
            -
             | 
| 52 | 
            -
                  ActiveMerchant::Billing::Response.new true, 'success', response: response
         | 
| 53 | 
            -
                rescue StandardError => e
         | 
| 54 | 
            -
                  error_response(e)
         | 
| 55 | 
            -
                end
         | 
| 56 | 
            -
             | 
| 57 | 
            -
                def cc_refund
         | 
| 58 | 
            -
                  raise ArgumentError, 'capture info is not available' unless @order.flow_data['capture']
         | 
| 59 | 
            -
             | 
| 60 | 
            -
                  # we allways have capture ID, so we use it
         | 
| 61 | 
            -
                  refund_data = { capture_id: @order.flow_data['capture']['id'] }
         | 
| 62 | 
            -
                  refund_form = ::Io::Flow::V0::Models::RefundForm.new(refund_data)
         | 
| 63 | 
            -
                  response    = FlowcommerceSpree.client.refunds.post(FlowcommerceSpree::ORGANIZATION, refund_form)
         | 
| 64 | 
            -
             | 
| 65 | 
            -
                  return ActiveMerchant::Billing::Response.new false, 'error', response: response unless response.id
         | 
| 66 | 
            -
             | 
| 67 | 
            -
                  @order.update_column :flow_data, @order.flow_data.merge('refund': response.to_hash)
         | 
| 68 | 
            -
                  ActiveMerchant::Billing::Response.new true, 'success', response: response
         | 
| 69 | 
            -
                rescue StandardError => e
         | 
| 70 | 
            -
                  error_response(e)
         | 
| 71 | 
            -
                end
         | 
| 72 | 
            -
             | 
| 73 37 | 
             
                private
         | 
| 74 38 |  | 
| 75 39 | 
             
                # if order is not in flow, we use local Spree settings
         |