# Prove the key, then land a sheet of stock as one sync. Windows PowerShell 5.1 or later. # # $env:FREEPORT_KEY = 'fp_test_...' # .\sync-sheet.ps1 -Sheet stock-sheet-template.csv param([string]$Sheet = 'stock-sheet-template.csv') $ErrorActionPreference = 'Stop' $base = if ($env:FREEPORT_API) { $env:FREEPORT_API } else { 'https://sandbox-api.freeport.gg/v1' } if (-not $env:FREEPORT_KEY) { throw 'set FREEPORT_KEY to your fp_test_ or fp_live_ key' } $headers = @{ Authorization = "Bearer $env:FREEPORT_KEY" } $numbers = 'price_per_qty', 'min_qty', 'max_qty', 'stock_qty', 'low_stock_alert_qty', 'delivery_eta_minutes' function Invoke-Freeport { param([string]$Method, [string]$Path, $Body, [hashtable]$Extra = @{}) $params = @{ Method = $Method; Uri = "$base$Path"; Headers = ($headers + $Extra); ContentType = 'application/json' } if ($null -ne $Body) { $params.Body = ($Body | ConvertTo-Json -Depth 10 -Compress) } try { return Invoke-RestMethod @params } catch { $problem = $_.ErrorDetails.Message | ConvertFrom-Json throw "$Method $Path`: $($problem.error.code) $($problem.error.message)" } } # 1. Who am I? Invoke-Freeport GET '/ping' | ConvertTo-Json -Depth 5 # 2. The sheet, one line per row. Tiers are "min_qty:price;min_qty:price". $lines = foreach ($row in Import-Csv $Sheet) { $line = @{} foreach ($property in $row.PSObject.Properties) { if ([string]::IsNullOrEmpty($property.Value) -or $property.Name -eq 'tiers') { continue } $line[$property.Name] = if ($numbers -contains $property.Name) { [int]$property.Value } else { $property.Value } } if ($row.tiers) { $line.tiers = @($row.tiers -split ';' | ForEach-Object { $parts = $_ -split ':'; @{ min_qty = [int]$parts[0]; price = $parts[1] } }) } $line } # 3. Open, stage (up to a thousand a call), commit with an idempotency key. $sync = Invoke-Freeport POST '/stock/syncs' @{ mode = 'replace' } for ($start = 0; $start -lt $lines.Count; $start += 1000) { $chunk = @($lines[$start..([Math]::Min($start + 999, $lines.Count - 1))]) $staged = Invoke-Freeport PUT "/stock/syncs/$($sync.id)/lines" @{ lines = $chunk } $refused = @($staged.results | Where-Object status -ne 'staged') Write-Host "staged $($staged.results.Count - $refused.Count), refused $($refused.Count)" } Invoke-Freeport POST "/stock/syncs/$($sync.id)/commit" $null @{ 'Idempotency-Key' = "commit-$($sync.id)" } | Out-Null # 4. The worker applies it; poll the sync, not the listings. do { Start-Sleep -Seconds 1 $state = Invoke-Freeport GET "/stock/syncs/$($sync.id)" } while ($state.status -eq 'committing') $state.summary | ConvertTo-Json # 5. Any line that failed says why. (Invoke-Freeport GET "/stock/syncs/$($sync.id)/lines?action=failed").data | ForEach-Object { Write-Host "$($_.external_id): $($_.error.code) $($_.error.message)" }