Class: Menard::PartnerPortalUploader
- Inherits:
-
Object
- Object
- Menard::PartnerPortalUploader
- Defined in:
- app/services/menard/partner_portal_uploader.rb
Overview
Uploads an inventory spreadsheet to the Menard partner portal via browser automation.
Uses playwright-ruby-client to log in, navigate to the inventory upload page,
attach the XLSX file, and submit the form.
The Menard portal is a JavaScript SPA — the login form is rendered dynamically
by main.bundle.js, not present in the initial HTML. Chromium must fully execute
JS in headless mode, which requires --no-sandbox and --disable-dev-shm-usage
when running from background processes (Sidekiq) or on Linux servers.
Credentials are read from Heatwave::Configuration (encrypted credentials):
menard:
portal_username:
portal_password:
Defined Under Namespace
Classes: Result
Constant Summary collapse
- PORTAL_BASE_URL =
'https://partners.menard-inc.com/partners'- LOGIN_URL =
"#{PORTAL_BASE_URL}/login.html".freeze
- INVENTORY_URL =
"#{PORTAL_BASE_URL}/viewInventoryUpdates.html".freeze
- NAVIGATION_TIMEOUT =
60_000- SPA_RENDER_TIMEOUT =
45_000
Instance Method Summary collapse
- #call ⇒ Object
-
#initialize(file_path:, headless: true) ⇒ PartnerPortalUploader
constructor
A new instance of PartnerPortalUploader.
Constructor Details
#initialize(file_path:, headless: true) ⇒ PartnerPortalUploader
Returns a new instance of PartnerPortalUploader.
31 32 33 34 35 |
# File 'app/services/menard/partner_portal_uploader.rb', line 31 def initialize(file_path:, headless: true) @file_path = file_path @headless = headless validate! end |
Instance Method Details
#call ⇒ Object
37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 |
# File 'app/services/menard/partner_portal_uploader.rb', line 37 def call require 'playwright' log('Starting browser automation', level: :info) Playwright.create(playwright_cli_executable_path: PlaywrightRuntime.cli_path) do |playwright| browser = playwright.chromium.launch(**) log("Browser launched (headless=#{@headless})", level: :info) context = browser.new_context( userAgent: 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 ' \ '(KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36' ) page = context.new_page attach_diagnostics(page) begin active_page = login(page) upload_inventory(active_page) rescue Playwright::Error, Playwright::TimeoutError => e dump_page_html(active_page || page, 'timeout_failure') log("Playwright error: #{e.class} — #{e.}", level: :error) Result.new(uploaded: false, message: "Browser automation failed: #{e.}") rescue StandardError => e dump_page_html(active_page || page, 'unexpected_failure') log("#{e.class}: #{e.}\n#{e.backtrace&.first(5)&.join("\n")}", level: :error) Result.new(uploaded: false, message: "Upload failed: #{e.}") end ensure browser&.close end rescue StandardError => e log("Fatal: #{e.class}: #{e.}", level: :error) Result.new(uploaded: false, message: "Upload failed: #{e.}") end |