---
# System prepended metadata

title: Untitled

---

```ruby=
module PartnerProducts
  class ProcessBatchUploadOfficer
    attr_reader :params, :current_row, :success_row, :error_params,:errors

    def initialize(params)
      @params       = params
      @current_row  = 0
      @success_row  = 0
      @result       = { total_row: 0, partner_product_ids: [] }
      @errors       = []
      @error_params = {}
      @validated_file_url = nil
    end

    def perform
      send("parse_#{params[:action_type]}_data!")

      save_batch_upload_result!
      broadcast_progress!(@current_row, @success_row)

      true
    rescue StandardError => e
      ExceptionNotifier.notify_exception(e, data: { params: params, current_row: current_row })
      Rails.logger.error "#{self.class} params: #{@params} current_row: #{current_row} errors: #{e}"
      @errors << Phoenix::ResponseMessage::MESSAGES[:RUNTIME_ERROR][I18n.locale.upcase]
      false
    end

    private

    def parse_create_data!
      sheet_1 = user_file_excel.sheet(0).to_a.drop(3) # skip 3 first row
      sheet_2 = user_file_excel.sheet(1).to_a.drop(3) # skip 3 first row
      sheet_3 = user_file_excel.sheet(2).to_a.drop(3) # skip 3 first row
      new_sheet_1 = []
      new_sheet_2 = []
      new_sheet_3 = []

      @result[:total_row] = sheet_1.size
      @result[:partner_product_ids] = []

      broadcast_progress!
			# 1/ 10 row
			# 
      sheet_1.each_with_index do |item, idx|
        @current_row += 1

        item_sku_price = sheet_2.find { |row| row[1] == item[2] }
        distributions = sheet_3.select { |row| row[1] == item[2] }

        if item_sku_price.present? && distributions.present?
          insert_params = {
            user: user,
            partner: partner,
            batch_upload: batch_upload,
            index: idx,
            item: item,
            item_sku_price: item_sku_price,
            distributions: distributions
          }

          officer = PartnerProducts::CreateOfficer.new(insert_params)

          if officer.valid?
            officer.perform

            @result[:partner_product_ids] << officer.partner_product.id

            @success_row += 1
          else
            new_sheet_1 << officer.item
            new_sheet_2 << officer.item_sku_price
            new_sheet_3 += officer.distributions
          end

          broadcast_progress!(@current_row, @success_row) unless @current_row == @total_row
        end
      end

      error_params[:data] = { sheet_1: new_sheet_1, sheet_2: new_sheet_2, sheet_3: new_sheet_3  }
      error_params[:partner_id] = params[:partner_id]
      error_params[:user_id] = params[:user_id]
      generate_error_excel!(error_params) if new_sheet_1.present? || new_sheet_2.present? || new_sheet_3.present?
    end

    def parse_update_basic_info_data!
    end

    def parse_update_price_warehouse_data!
      sheet_1 = user_file_excel.sheet(0).to_a.drop(3) # skip 3 first row
      sheet_2 = user_file_excel.sheet(1).to_a.drop(3) # skip 3 first row
      new_sheet_1 = []
      new_sheet_2 = []

      @result[:total_row] = sheet_1.size
      @result[:partner_product_ids] = []

      broadcast_progress!

      sheet_1.each_with_index do |item_sku_price, idx|
        @current_row = idx + 1

        distributions = sheet_2.select { |row| row[1] == item_sku_price[1] }

        insert_params = {
          user: user,
          partner: partner,
          batch_upload: batch_upload,
          index: idx,
          item_sku_price: item_sku_price,
          distributions: distributions
        }
        officer = PartnerProducts::UpdatePriceWarehouseOfficer.new(insert_params)

        if officer.valid?
          officer.perform

          @result['partner_product_ids'] << officer.partner_product.id

          @success_row += 1
        else
          new_sheet_1 << officer.item_sku_price
          new_sheet_2 << officer.distributions
        end

        broadcast_progress!(@current_row, @success_row)
      end
    end

    def save_batch_upload_result!
      batch_upload.result = @result
      batch_upload.validated_file_url = @validated_file_url
      batch_upload.save!
    end

    def generate_error_excel!(params)
      officer = Excel::PartnerProductTemplate::CreateOfficer.new(params)
      officer.perform

      @validated_file_url = officer.excel_file_url

      # 1. generate data error validation => done
      # 2. generate file excel with error validation => done
      # 3. upload to s3 => done
      # 4. update to validated_file_url on table batch_upload_partner_products
      # 5. broadcast
    end

    def partner
      @partner ||= Phoenix::Partner.find(params[:partner_id])
    end

    def user
      @user ||= batch_upload.user
    end

    def user_file_excel
      @user_file_excel ||= Roo::Excelx.new(user_excel_file_path)
    end

    def batch_upload
      @batch_upload ||= partner.batch_upload_partner_products.find_by(request_id: params[:request_id])
    end

    def broadcast_progress!(current_row = 0, success_row = 0)
      Phoenix::PartnerProducts::RecalculateStatsOfficer.new(partner).perform

      friday_params = {
        user_id: batch_upload.user_id,
        request_id: batch_upload.request_id,
        current_row: current_row,
        success_row: success_row,
        total_row: @result[:total_row],
        validated_file_url: batch_upload.validated_file_url
      }
      BroadcastFriday::ProgressUploadPartnerProductsOfficer.new(friday_params).perform
    end

    def user_excel_file_path
      @user_excel_file_path ||= begin
        file_path = temp_path.join("#{batch_upload.request_id}.xlsx")

        FileUtils.mkdir_p(temp_path)

        File.open(file_path, 'wb') do |file|
          file.write URI.parse(batch_upload.user_file_url).read
        end

        file_path
      end
    end

    def temp_path
      @temp_path ||= Rails.root.join("tmp/batch_upload_partner_products/#{batch_upload.id}")
    end
  end
end
```