Class: Edi::Amazon::APlusContentProcessor

Inherits:
BaseEdiService show all
Defined in:
app/services/edi/amazon/a_plus_content_processor.rb

Constant Summary

Constants included from Edi::AddressAbbreviator

Edi::AddressAbbreviator::MAX_LENGTH

Instance Attribute Summary

Attributes inherited from BaseEdiService

#orchestrator

Instance Method Summary collapse

Methods inherited from BaseEdiService

#duplicate_po_already_notified?, #initialize, #mark_duplicate_po_as_notified, #report_order_creation_issues, #safe_process_edi_communication_log

Methods included from Edi::AddressAbbreviator

#abbreviate_street, #collect_street_originals, #record_address_abbreviation_notes

Methods inherited from BaseService

#initialize, #log_debug, #log_error, #log_info, #log_warning, #logger, #options, #tagged_logger

Constructor Details

This class inherits a constructor from Edi::BaseEdiService

Instance Method Details

#compress_image(image_data, max_size) ⇒ Object



133
134
135
136
137
138
139
140
141
# File 'app/services/edi/amazon/a_plus_content_processor.rb', line 133

def compress_image(image_data, max_size)
  # Use Vips to compress the image to fit within the size limit
  compressed_data = compress_image_with_vips(image_data, max_size)
  return compressed_data if compressed_data

  # If Vips fails, we can't proceed
  Rails.logger.error 'Failed to compress image to acceptable size'
  nil
end

#compress_image_with_vips(image_data, max_size) ⇒ Object



143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
# File 'app/services/edi/amazon/a_plus_content_processor.rb', line 143

def compress_image_with_vips(image_data, max_size)
  # Compress image using Vips
  require 'vips'

  begin
    # Create a temporary file from the image data
    temp_file = Tempfile.new(['image', '.jpg'])
    temp_file.binmode
    temp_file.write(image_data)
    temp_file.close

    # Load with Vips
    image = Vips::Image.new_from_file(temp_file.path)

    # Resize if the image is very large (width > 1500px)
    if image.width > 1500
      scale = 1500.0 / image.width
      image = image.resize(scale)
    end

    # Start with quality 95 and reduce if needed
    quality = 95
    max_attempts = 8

    max_attempts.times do |attempt|
      # Create compressed version
      compressed_file = Tempfile.new(['compressed', '.jpg'])
      compressed_file.close

      begin
        # Write as JPEG with current quality
        image.write_to_file(compressed_file.path, Q: quality, strip: true)

        # Check the size
        compressed_size = File.size(compressed_file.path)

        if compressed_size <= max_size
          # Success! Read the compressed data
          compressed_data = File.binread(compressed_file.path)
          compressed_file.unlink
          temp_file.unlink
          return compressed_data
        else
          # Reduce quality and try again
          quality = (quality * 0.75).to_i
          quality = [quality, 20].max # Don't go below 20% quality
          compressed_file.unlink
        end
      rescue StandardError => e
        Rails.logger.error "Error during image compression attempt #{attempt + 1}: #{e.message}"
        compressed_file.unlink if compressed_file
        quality = (quality * 0.75).to_i
      end
    end

    # If we get here, compression failed
    temp_file.unlink
    Rails.logger.error "Failed to compress image to acceptable size after #{max_attempts} attempts"
    nil
  rescue StandardError => e
    Rails.logger.error "Error compressing image with Vips: #{e.message}"
    temp_file.unlink if temp_file
    nil
  end
end

#copy_content_to_destination(source_content, target_marketplace_id:, target_locale:) ⇒ Object



61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
# File 'app/services/edi/amazon/a_plus_content_processor.rb', line 61

def copy_content_to_destination(source_content, target_marketplace_id:, target_locale:)
  Rails.logger.info "Starting A+ content copy process for content reference key: #{source_content.content_reference_key}"

  @error_messages = [] # Initialize error collection

  begin
    # Step 1: Fetch the original content document using contentReferenceKey
    source_marketplace_id = source_content.marketplace_id || orchestrator.marketplace
    content_document = fetch_content_document(source_content.content_reference_key, source_marketplace_id)
    unless content_document
      error_msg = "Failed to fetch content document for key: #{source_content.content_reference_key}"
      @error_messages << error_msg
      raise StandardError, error_msg
    end

    # Step 2: Create upload destinations for any images in the content
    upload_destinations = create_upload_destinations_for_images(content_document, target_marketplace_id)
    # Check if upload_destinations is nil (failed) or empty (no images found)
    if upload_destinations.nil?
      error_msg = 'Failed to create upload destinations for images'
      @error_messages << error_msg
      raise StandardError, error_msg
    elsif upload_destinations.empty?
      Rails.logger.info 'No images found in content document, skipping image upload step'
    end

    # Step 3: Upload images (if any)
    if upload_destinations.empty?
      Rails.logger.info 'Skipping image upload step - no images to upload'
    else
      unless upload_images(content_document, upload_destinations)
        error_msg = 'Failed to upload images for content copy'
        @error_messages << error_msg
        raise StandardError, error_msg
      end
    end

    # Step 4: Validate the content document before creating it
    unless validate_content_document(content_document, target_marketplace_id)
      error_msg = 'Content document validation failed'
      @error_messages << error_msg
      raise StandardError, error_msg
    end

    # Step 5: Create the new content document
    new_content_reference_key = create_content_document(content_document, target_marketplace_id, target_locale)
    unless new_content_reference_key
      error_msg = 'Failed to create new content document'
      @error_messages << error_msg
      raise StandardError, error_msg
    end

    # Step 6: Add ASINs to the content document
    # SKIP FOR NOW
    # target_asin = source_content.asin
    # raise StandardError, 'Failed to add ASINs to content document' unless add_asins_to_content_document(new_content_reference_key, target_marketplace_id, [target_asin])

    # Rails.logger.info "Successfully copied A+ content. New content reference key: #{new_content_reference_key}"
    true
  rescue StandardError => e
    error_msg = "Error during A+ content copy: #{e.message}"
    @error_messages << error_msg
    Rails.logger.error error_msg
    Rails.logger.error e.backtrace.join("\n")
    false
  end
end

#error_messagesObject



129
130
131
# File 'app/services/edi/amazon/a_plus_content_processor.rb', line 129

def error_messages
  @error_messages || []
end

#process(ecl, catalog_item: nil, locale: nil) ⇒ Object



5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
# File 'app/services/edi/amazon/a_plus_content_processor.rb', line 5

def process(ecl, catalog_item: nil, locale: nil)
  res = false

  if ecl&.data.present? && (json_hash = JSON.parse(ecl.data).with_indifferent_access).present?
    Rails.logger.debug { "Edi::Amazon::APlusContentProcessor#process, json_hash: #{json_hash}" }

    # Find the catalog item if we don't have it from the arguments
    asin = ecl.file_info[:asin]
    catalog_item ||= ecl.orchestrator.customer.catalog.catalog_items.amazons_with_asins.find_by(items: { amazon_asin: asin })

    return false unless catalog_item

    # Get marketplace info
    marketplace_id = orchestrator.marketplace
    marketplace = catalog_item.amazon_marketplace

    # Process publish records
    publish_records = json_hash['publishRecordList'] || []

    publish_records.each do |record|
      next unless record['contentReferenceKey'].present?

      # Use the ASIN from the record, not from file_info
      record_asin = record['asin']

      # Find or create the A+ content record
      a_plus_content = AmazonAPlusContent.find_or_initialize_by(
        asin: record_asin,
        marketplace_id: marketplace_id,
        locale: locale || 'en_US'
      )

      # Update with simplified data
      a_plus_content.assign_attributes(
        catalog_item: catalog_item,
        amazon_marketplace: marketplace,
        content_reference_key: record['contentReferenceKey'],
        content_type: record['contentType'],
        content_sub_type: record['contentSubType'],
        page_name: record['contentType'], # Use content type as page name for now
        content_data: json_hash, # Keep the full response for reference
        status: 'approved' # Assume approved since it's published
      )

      if a_plus_content.save
        res = true
        Rails.logger.info "Successfully saved A+ content for ASIN #{asin}, content reference key: #{record['contentReferenceKey']}"
      else
        Rails.logger.error "Failed to save A+ content for ASIN #{asin}: #{a_plus_content.errors.full_messages.join(', ')}"
      end
    end
  end

  res
end