Created
January 20, 2020 15:48
-
-
Save berniechiu/8e113e555fd30b54b4b7d16492adad66 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
require_dependency Rails.root.join('app/models/platform_api/sync_service/error_handlers') | |
module PlatformApi | |
module SyncService | |
class ProductsSync | |
BATCH_IMPORT_CONFIG = { | |
on_duplicate_key_update: { | |
conflict_target: [:identifier, :platform_product_id, :company_id, :store_id], | |
columns: [:name, :length, :width, :height, :weight, :cost_price, :cost_price_currency, :selling_price, :selling_price_currency, :image_url] | |
}, | |
validate: true | |
}.freeze | |
BATCH_UPDATE_CONFIG = { | |
on_duplicate_key_update: { | |
conflict_target: [:id], | |
columns: [:name, :length, :width, :height, :weight, :identifier, :platform_product_id, :cost_price, :cost_price_currency, :selling_price, :selling_price_currency, :image_url] | |
}, | |
validate: true | |
}.freeze | |
attr_reader :store, :report, :platform_connection, :error | |
def initialize(store, user: nil, report: nil) | |
@store = store | |
@user = user || User.find_by(id: @store.company.owner&.id) | |
@report = report || Report.new(user: @user, store: @store, job_type: :api_upload) | |
@platform_connection = PlatformApi::StoreAdapter.new(store: @store) | |
@error = nil | |
end | |
def process | |
@report.calculate! | |
# TODO: Can think of a thread-safe parallel requests for faster processing | |
platform_connection.fetch_all_products do |batch| | |
normalized_products = Array(platform_connection.products_fetch_service.normalize(batch)) | |
normalized_products = build_existing_identifier_products(normalized_products) | |
existing_products, new_products = normalized_products.partition { |data| data.id.present? } | |
updated_result = Product.import(existing_products, BATCH_UPDATE_CONFIG) | |
imported_result = Product.import(new_products, BATCH_IMPORT_CONFIG) | |
generate_report_records(updated_result) | |
generate_report_records(imported_result) | |
end | |
@report.complete! | |
rescue => e | |
raise @error = SyncError.new(e, store_id: store.id, store_name: store.name, platform: store.platform.name, report_id: report.id) | |
end | |
def build_existing_identifier_products(normalized_products) | |
existing_products = store.products.where(identifier: normalized_products.map(&:identifier), platform_product_id: nil).pluck(:identifier, :id).to_h | |
normalized_products.map { |product| product.id = existing_products[product.identifier]; product } | |
end | |
def generate_report_records(import_result) | |
successes = import_result.ids.map do |product_id| | |
@report.report_records.new(product_id: product_id, state: ::ReportRecord::SUCCEEDED) | |
end | |
failed = import_result.failed_instances.map do |product| | |
@report.report_records.new(state: ::ReportRecord::FAILED, log: { errors: product.errors.messages, data: product.attributes.compact }) | |
end | |
import_records = successes.concat(failed) | |
@report.total ||= 0 | |
@report.total += import_records.size | |
ReportRecord.import(import_records) | |
end | |
end | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment