param( [string]$GatewayBaseUrl = 'http://8.163.30.128:9000', [string]$PlatformUsername = 'platform_admin', [string]$MerchantUsername = 'merchant_admin', [string]$PlatformPassword = 'ChangeMe123!', [string]$MerchantPassword = 'ChangeMe123!', [long]$TenantId = 10001, [string]$ImageDirectory = 'C:\Users\BY-OY\Desktop\上传图片包\测量图片\测量图片', [long]$ExistingInboundId = 0, [long]$ExistingOrderId = 0, [string]$ExistingInboundCode = '', [int]$ExistingCartonCount = 0, [switch]$OcrOnly, [switch]$OcrProbeOnly, [string]$OutputPath = '' ) $ErrorActionPreference = 'Stop' $repoRoot = Split-Path -Parent (Split-Path -Parent $MyInvocation.MyCommand.Path) $stamp = Get-Date -Format 'yyyyMMddHHmmss' $marker = "DIM-OCR-PRICE-$stamp" if ([string]::IsNullOrWhiteSpace($OutputPath)) { $OutputPath = Join-Path $repoRoot "reports\尺寸OCR渠道计费测试环境验收-$stamp.json" } $originWarehouseId = '193000000000200001' $destinationWarehouseId = '193000000000200003' $customerId = '191000000000000001' $successfulImages = @( 'orig_030e8fd8-8ff3-4713-81f1-33b964887844.jpg', 'orig_192da04f-1cfb-415b-ae2d-4b4f63fda871.JPG', 'orig_f4525683-4ceb-4175-92a3-c3f66c8a9423.jpg' ) $failedImage = 'orig_168c6cb6-ed65-49cc-b799-84c8855be97a.jpg' $probeImages = @( 'orig_052f3c40-2dc8-432f-8f23-6961415bcac5.jpg', 'orig_07220408-d9a6-4950-9c30-e813d4e9d575.jpg', 'orig_0977314f-330e-4044-9f9c-0697c7af1c9e.jpg', 'orig_1064d1c3-0d84-43b4-b19d-62e6c4f2d65a.jpg', 'orig_15925407-b2f6-4c79-a5bc-e96ece7314ed.jpg', 'orig_172ff266-2e8a-49d1-8cc2-892ff23fbf3b.jpg', 'orig_1e091ecb-c3c1-46b3-95f4-727f81bfb2fb.jpg', 'orig_28149aa5-11bf-44d3-a3e6-6d457d5fd188.jpg', 'orig_31802a7b-294a-476a-ac5b-4c92a87df18e.jpg', 'orig_3c1f4815-a058-4cdd-9662-094d5a2e1ba7.jpg', 'orig_435124c6-d380-4f7a-aed8-75388a88685e.jpg', 'orig_490ac151-87b9-4bc6-8958-8c1aa9ff6cdd.jpg' ) $scanDimensions = @( @{ length = 10; width = 10; height = 10; expectedOuter = @(34, 24, 24) }, @{ length = 35; width = 25; height = 25; expectedOuter = @(44, 34, 34) }, @{ length = 45; width = 35; height = 35; expectedOuter = @(54, 44, 44) }, @{ length = 55; width = 45; height = 45; expectedOuter = @(64, 54, 54) } ) $steps = [System.Collections.Generic.List[object]]::new() $runs = [System.Collections.Generic.List[object]]::new() $tempRoot = Join-Path ([System.IO.Path]::GetTempPath()) "baiyue-dim-ocr-$stamp-$([guid]::NewGuid().ToString('N'))" $null = New-Item -ItemType Directory -Path $tempRoot function New-Key([string]$Action) { return "$marker-$Action-$([guid]::NewGuid().ToString('N'))" } function Invoke-Api( [string]$Method, [string]$Path, [string]$Token = '', [object]$Body = $null, [hashtable]$ExtraHeaders = @{} ) { $headers = @{} if (-not [string]::IsNullOrWhiteSpace($Token)) { $headers.Authorization = "Bearer $Token" } foreach ($entry in $ExtraHeaders.GetEnumerator()) { $headers[$entry.Key] = $entry.Value } $args = @{ Method = $Method Uri = "$GatewayBaseUrl$Path" Headers = $headers TimeoutSec = 45 SkipHttpErrorCheck = $true } if ($null -ne $Body) { $args.ContentType = 'application/json; charset=utf-8' $jsonText = $Body | ConvertTo-Json -Depth 30 -Compress $args.Body = [Text.Encoding]::UTF8.GetBytes($jsonText) } $response = Invoke-WebRequest @args $json = $null if (-not [string]::IsNullOrWhiteSpace($response.Content)) { try { $json = $response.Content | ConvertFrom-Json } catch { } } return [pscustomobject]@{ http = [int]$response.StatusCode body = $json raw = if ($null -eq $json) { [string]$response.Content } else { $null } requestId = if ($null -ne $json) { $json.requestId } else { $response.Headers['X-Request-Id'] } traceId = if ($null -ne $json) { $json.traceId } else { $response.Headers['X-Trace-Id'] } } } function Invoke-Multipart( [string]$Path, [string]$Token, [string]$FilePath, [object]$Data = $null ) { $responsePath = Join-Path $tempRoot "$([guid]::NewGuid().ToString('N')).json" $curlArgs = @('-sS', '-X', 'POST', "$GatewayBaseUrl$Path", '-H', "Authorization: Bearer $Token") if ($null -ne $Data) { $dataPath = Join-Path $tempRoot "$([guid]::NewGuid().ToString('N')).json" $Data | ConvertTo-Json -Depth 20 -Compress | Set-Content -LiteralPath $dataPath -Encoding utf8NoBOM $curlArgs += @('-F', "data=@$dataPath;type=application/json") } $file = Get-Item -LiteralPath $FilePath $curlArgs += @('-F', "$(if ($null -eq $Data) { 'file' } else { 'image' })=@$($file.FullName);type=image/jpeg") $curlArgs += @('-o', $responsePath, '-w', '%{http_code}') $httpText = & curl.exe @curlArgs if ($LASTEXITCODE -ne 0) { throw "multipart 请求传输失败:$Path" } $content = Get-Content -LiteralPath $responsePath -Raw $json = $null if (-not [string]::IsNullOrWhiteSpace($content)) { try { $json = $content | ConvertFrom-Json } catch { } } return [pscustomobject]@{ http = [int]$httpText body = $json raw = if ($null -eq $json) { $content } else { $null } requestId = if ($null -ne $json) { $json.requestId } else { $null } traceId = if ($null -ne $json) { $json.traceId } else { $null } } } function Add-Step([string]$Run, [string]$Name, $Response, [bool]$Passed, [string]$Evidence = '') { $step = [pscustomobject]@{ run = $Run name = $Name passed = $Passed http = $Response.http code = if ($null -ne $Response.body) { [string]$Response.body.code } else { $null } message = if ($null -ne $Response.body) { [string]$Response.body.message } else { [string]$Response.raw } requestId = $Response.requestId traceId = $Response.traceId evidence = $Evidence } $steps.Add($step) Write-Host "[$(if ($Passed) { 'PASS' } else { 'FAIL' })][$Run] $Name $Evidence" } function Require-Success([string]$Run, [string]$Name, $Response, [string]$Evidence = '') { $passed = $Response.http -eq 200 -and [string]$Response.body.code -eq '200' Add-Step $Run $Name $Response $passed $Evidence if (-not $passed) { throw "$Run / $Name failed: HTTP=$($Response.http), code=$($Response.body.code), message=$($Response.body.message)" } return $Response.body.data } function New-Cargo([int]$Index) { $dimension = $scanDimensions[$Index - 1] return [ordered]@{ cargoName = "测试产品$Index" cargoNameEn = "Dimension Test Product $Index" hsCode = '8518210000' customsHsCode = '8518210000' packageType = 'CARTON' packageCount = 1 grossWeightKg = 5 netWeightKg = 4.5 volumeCbm = [decimal]($dimension.length * $dimension.width * $dimension.height / 1000000) lengthCm = $dimension.length widthCm = $dimension.width heightCm = $dimension.height declaredValue = 100 unitDeclaredValue = 100 currency = 'USD' dangerousGoods = $false cargoRemark = "$marker tier-$Index" skuNo = "SKU-$stamp-$Index" upcNo = "UPC-$stamp-$Index" unitsPerPackage = 1 totalQuantity = 1 material = '塑料 / Plastic' usage = '测试 / Test' model = "DIM-$Index" brand = 'BAIYUE-E2E' } } function New-OrderPayload([string]$PricingTaxMode) { $cargoes = @() 1..4 | ForEach-Object { $cargoes += New-Cargo $_ } return [ordered]@{ customerId = $customerId customerName = '深圳示例贸易有限公司' transportMode = 'SEA' tradeTerm = 'FOB' destinationCountryCode = 'US' destinationWarehouseId = $destinationWarehouseId destinationWarehouseName = '洛杉矶仓' expectedShipDate = (Get-Date).AddDays(10).ToString('yyyy-MM-dd') customerRemark = "$marker $PricingTaxMode" sender = [ordered]@{ companyName = '深圳示例贸易有限公司' contactName = '测试员' phone = '13800138000' email = 'e2e@example.com' countryCode = 'CN' province = '浙江省' city = '义乌市' district = '义乌市' addressLine = '测试环境全链路地址' postalCode = '322000' } receiver = $null cargoes = $cargoes pickupMethod = 'PICKUP' receivingWarehouseId = $originWarehouseId receivingWarehouseName = '义乌仓' channelCode = 'EXX_TRUCK' channelName = 'EXX_TRUCK' carrierId = $null carrierName = $null taxMode = 'BUY_DECLARATION' pricingTaxMode = $PricingTaxMode containerMode = 'LCL' customsInspection = $false destinationType = 'OVERSEAS' amazonWarehouseCode = $null shipmentId = "SHIP-$stamp" referenceId = "$marker-$PricingTaxMode" } } function Create-ApprovedInbound([string]$RunName, [string]$MerchantToken, [string]$PlatformToken, [string]$PricingTaxMode) { $create = Invoke-Api POST '/api/merchant/v1/orders/first-leg' $MerchantToken (New-OrderPayload $PricingTaxMode) @{ 'Idempotency-Key' = New-Key "create-$PricingTaxMode" } $orderId = [string](Require-Success $RunName '创建订单' $create) $submit = Invoke-Api POST "/api/merchant/v1/orders/first-leg/$orderId/submit" $MerchantToken $null @{ 'Idempotency-Key' = New-Key "submit-$PricingTaxMode" } $null = Require-Success $RunName '提交订单' $submit "orderId=$orderId" $approve = Invoke-Api POST "/api/platform/v1/orders/first-leg/$orderId/approve?tenantId=$TenantId" $PlatformToken $null = Require-Success $RunName '审核订单' $approve "orderId=$orderId" $detail = $null $detailResponse = $null for ($attempt = 1; $attempt -le 20; $attempt++) { $detailResponse = Invoke-Api GET "/api/platform/v1/orders/$orderId`?tenantId=$TenantId" $PlatformToken if ($detailResponse.http -eq 200 -and [string]$detailResponse.body.code -eq '200' -and $null -ne $detailResponse.body.data.summary.inboundId) { $detail = $detailResponse.body.data break } Start-Sleep -Seconds 3 } $ready = $null -ne $detail -and $null -ne $detail.summary.inboundId Add-Step $RunName '生成入库单' $detailResponse $ready $(if ($ready) { "inboundId=$($detail.summary.inboundId)" } else { '60秒内未生成' }) if (-not $ready) { throw "$RunName 入库单未生成" } return [pscustomobject]@{ orderId = $orderId inboundId = [string]$detail.summary.inboundId inboundCode = [string]$detail.summary.inboundCode } } function Initialize-CartonLabels([string]$RunName, [string]$PlatformToken, [string]$InboundId) { $response = Invoke-WebRequest -Method POST -Uri "$GatewayBaseUrl/api/platform/inbounds/$InboundId/carton-label-pdf?tenantId=$TenantId" ` -Headers @{ Authorization = "Bearer $PlatformToken" } -TimeoutSec 60 -SkipHttpErrorCheck $contentType = [string]$response.Headers['Content-Type'] $passed = [int]$response.StatusCode -eq 200 -and $contentType.StartsWith('application/pdf') $fakeResponse = [pscustomobject]@{ http = [int]$response.StatusCode body = $null raw = if ($passed) { $null } else { [string]$response.Content } requestId = $response.Headers['X-Request-Id'] traceId = $response.Headers['X-Trace-Id'] } Add-Step $RunName '生成并冻结箱码' $fakeResponse $passed "contentType=$contentType" if (-not $passed) { throw "$RunName 箱码 PDF 生成失败" } } function Scan-Cartons([string]$RunName, [string]$PlatformToken, [string]$InboundId, [string]$InboundCode, [int]$TotalCartons = 4) { $results = @() for ($index = 1; $index -le 4; $index++) { $dimension = $scanDimensions[$index - 1] $imageName = if ($index -le 3) { $successfulImages[$index - 1] } else { $failedImage } $scan = Invoke-Multipart "/api/platform/v1/first-leg/inbounds/$InboundId/measurement/carton-scans?tenantId=$TenantId" ` $PlatformToken (Join-Path $ImageDirectory $imageName) @{ boxCode = "$InboundCode#$TotalCartons-$index" length = $dimension.length width = $dimension.width height = $dimension.height weight = 5 + $index machineNo = 'MOJIA-E2E-01' measuredAt = (Get-Date).ToString('yyyy-MM-ddTHH:mm:ss') } $saved = Require-Success $RunName "墨家箱测量-$index" $scan "boxCode=$InboundCode#$TotalCartons-$index" $results += $saved } return $results } function Set-RepresentativeCartonCounts([string]$RunName, [string]$PlatformToken, [string]$InboundId, [object[]]$Scans, [int]$TotalCartons) { if ($TotalCartons -eq $Scans.Count) { return } if ($TotalCartons % $Scans.Count -ne 0) { throw "总箱数 $TotalCartons 不能平均分配给 $($Scans.Count) 条测量记录" } $representativeCount = [int]($TotalCartons / $Scans.Count) $detailResponse = Invoke-Api GET "/api/platform/v1/first-leg/inbounds/$InboundId/measurement?tenantId=$TenantId" $PlatformToken $detail = Require-Success $RunName '读取箱数确认前测量版本' $detailResponse $version = [int]$detail.version foreach ($scan in $Scans) { $update = Invoke-Api PUT "/api/platform/v1/first-leg/inbounds/$InboundId/measurement/items/$($scan.itemId)/confirmed-package-count?tenantId=$TenantId" ` $PlatformToken @{ measurementVersion = $version; confirmedPackageCount = $representativeCount } $updated = Require-Success $RunName "确认代表箱数-$($scan.boxCode)" $update "confirmedPackageCount=$representativeCount" $version = [int]$updated.measurementVersion } } function Upload-And-ConfirmWeight([string]$RunName, [string]$PlatformToken, [string]$InboundId, [string]$ImageName, [object]$ManualWeight) { $upload = Invoke-Multipart "/api/platform/v1/files/measurements/$TenantId/$InboundId" $PlatformToken ` (Join-Path $ImageDirectory $ImageName) $uploaded = Require-Success $RunName "OCR-$ImageName" $upload $ocrEvidence = "status=$($uploaded.recognitionStatus), weight=$($uploaded.weightValue), confidence=$($uploaded.confidence), error=$($uploaded.error)" Add-Step $RunName "OCR结果-$ImageName" $upload ($uploaded.recognitionStatus -in @('RECOGNIZED', 'FAILED')) $ocrEvidence if ($uploaded.recognitionStatus -eq 'FAILED') { $retry = Invoke-Api POST "/api/platform/v1/files/measurements/$TenantId/$InboundId/$($uploaded.fileId)/recognize" $PlatformToken $retried = Require-Success $RunName "OCR重试-$ImageName" $retry Add-Step $RunName "OCR重试结果-$ImageName" $retry ($retried.recognitionStatus -in @('RECOGNIZED', 'FAILED')) ` "status=$($retried.recognitionStatus), error=$($retried.error)" $uploaded = $retried } $create = Invoke-Api POST "/api/platform/v1/first-leg/inbounds/$InboundId/weight-results?tenantId=$TenantId" $PlatformToken @{ fileId = [string]$uploaded.fileId ocrProvider = 'BAIDU_OCR_TEST_ENV' ocrRawText = if ($uploaded.ocrRawText) { [string]$uploaded.ocrRawText } else { [string]$uploaded.error } ocrWeightValue = $uploaded.weightValue ocrWeightUnit = $uploaded.weightUnit confidence = $uploaded.confidence } $weight = Require-Success $RunName "登记重量-$ImageName" $create $confirmBody = @{ version = [int]$weight.version } if ($null -ne $ManualWeight) { $confirmBody.adjustedWeightValue = [decimal]$ManualWeight $confirmBody.adjustedWeightUnit = 'KG' $confirmBody.adjustmentReason = "$marker OCR失败人工读数" } $confirm = Invoke-Api POST "/api/platform/v1/first-leg/inbounds/$InboundId/weight-results/$($weight.id)/confirm?tenantId=$TenantId" ` $PlatformToken $confirmBody return Require-Success $RunName "确认重量-$ImageName" $confirm } function Probe-Ocr([string]$PlatformToken, [string]$InboundId, [string]$ImageName) { $upload = Invoke-Multipart "/api/platform/v1/files/measurements/$TenantId/$InboundId" $PlatformToken ` (Join-Path $ImageDirectory $ImageName) $uploaded = Require-Success 'OCR-PROBE' "OCR-$ImageName" $upload $evidence = "status=$($uploaded.recognitionStatus), weight=$($uploaded.weightValue), confidence=$($uploaded.confidence), raw=$($uploaded.ocrRawText), error=$($uploaded.error)" Add-Step 'OCR-PROBE' "OCR结果-$ImageName" $upload ($uploaded.recognitionStatus -in @('RECOGNIZED', 'FAILED')) $evidence return $uploaded } function Complete-MeasurementAndPrice([string]$RunName, [string]$PlatformToken, [string]$MerchantToken, $Reference, [string[]]$WeightImages, [object]$ManualWeight, [bool]$AllowPricingFailure = $false) { foreach ($image in $WeightImages) { $manual = if ($image -eq $failedImage) { $ManualWeight } else { $null } $null = Upload-And-ConfirmWeight $RunName $PlatformToken $Reference.inboundId $image $manual } $measurementResponse = Invoke-Api GET "/api/platform/v1/first-leg/inbounds/$($Reference.inboundId)/measurement?tenantId=$TenantId" $PlatformToken $measurement = Require-Success $RunName '读取测量汇总' $measurementResponse $outer = @($measurement.items | Sort-Object boxCode | ForEach-Object { @([decimal]$_.outerLengthCm, [decimal]$_.outerWidthCm, [decimal]$_.outerHeightCm) }) $expectedOuter = @($scanDimensions | ForEach-Object { $_.expectedOuter }) $weighted = ($outer | ConvertTo-Json -Compress) -eq ($expectedOuter | ConvertTo-Json -Compress) Add-Step $RunName '验证四档尺寸加权' $measurementResponse $weighted ` "actualOuter=$($outer | ConvertTo-Json -Compress), expectedOuter=$($expectedOuter | ConvertTo-Json -Compress), actualVolumeCbm=$($measurement.actualVolumeCbm)" $submit = Invoke-Api POST "/api/platform/v1/first-leg/inbounds/$($Reference.inboundId)/measurement/submit?tenantId=$TenantId" ` $PlatformToken @{ measurementId = [string]$measurement.measurementId; version = [int]$measurement.version } $submitted = Require-Success $RunName '提交测量审核' $submit $inboundResponse = Invoke-Api GET "/api/platform/inbounds/$($Reference.inboundId)?tenantId=$TenantId" $PlatformToken $inbound = Require-Success $RunName '读取待审核入库单' $inboundResponse $approve = Invoke-Api POST "/api/platform/v1/inbounds/$($Reference.inboundId)/measurements/approve?tenantId=$TenantId" ` $PlatformToken @{ measurementId = [string]$measurement.measurementId expectedVersion = [int]$inbound.summary.version reason = $null } @{ 'Idempotency-Key' = New-Key "measurement-approve-$RunName" } $null = Require-Success $RunName '审核测量' $approve $feeResponse = Invoke-Api POST "/api/platform/v1/inbounds/$($Reference.inboundId)/fees/calculate?tenantId=$TenantId" ` $PlatformToken @{} @{ 'Idempotency-Key' = New-Key "fee-$RunName" } $feePassed = $feeResponse.http -eq 200 -and [string]$feeResponse.body.code -eq '200' Add-Step $RunName '渠道计费' $feeResponse $feePassed $(if ($feePassed) { "chargeUnit=$($feeResponse.body.data.chargeUnit), quantity=$($feeResponse.body.data.chargeableQuantity), total=$($feeResponse.body.data.totalAmount)" } else { "code=$($feeResponse.body.code), message=$($feeResponse.body.message)" }) if (-not $feePassed -and -not $AllowPricingFailure) { throw "$RunName / 渠道计费 failed: code=$($feeResponse.body.code), message=$($feeResponse.body.message)" } $fee = if ($feePassed) { $feeResponse.body.data } else { $null } $billing = $null if ($feePassed) { $confirmResponse = Invoke-Api POST "/api/platform/v1/inbounds/$($Reference.inboundId)/fees/confirm?tenantId=$TenantId" ` $PlatformToken $null @{ 'Idempotency-Key' = New-Key "fee-confirm-$RunName" } $confirmedFee = Require-Success $RunName '确认费用' $confirmResponse if ([string]$confirmedFee.feeStatus -ne 'CONFIRMED') { throw "$RunName / 确认费用状态异常: feeStatus=$($confirmedFee.feeStatus)" } $sendResponse = Invoke-Api POST "/api/platform/v1/inbounds/$($Reference.inboundId)/fees/send?tenantId=$TenantId" ` $PlatformToken $null @{ 'Idempotency-Key' = New-Key "fee-send-$RunName" } $fee = Require-Success $RunName '发布费用' $sendResponse if ([string]$fee.feeStatus -ne 'SENT') { throw "$RunName / 发布费用状态异常: feeStatus=$($fee.feeStatus)" } $billingResponse = Invoke-Api GET "/api/merchant/v1/first-leg/orders/$($Reference.orderId)/inbound-billing" $MerchantToken $billing = Require-Success $RunName '客户费用快照' $billingResponse } return [pscustomobject]@{ orderId = $Reference.orderId inboundId = $Reference.inboundId inboundCode = $Reference.inboundCode measurement = $measurement submitted = $submitted fee = $fee billing = $billing dimensionWeightingPassed = $weighted } } $fatal = $null try { $requiredImages = if ($OcrProbeOnly) { $probeImages } else { @($successfulImages + $failedImage) } foreach ($imageName in $requiredImages) { $imagePath = Join-Path $ImageDirectory $imageName if (-not (Test-Path -LiteralPath $imagePath)) { throw "找不到测试图片:$imagePath" } } $platformLogin = Invoke-Api POST '/api/auth/login' '' @{ username = $PlatformUsername; password = $PlatformPassword } $platform = Require-Success 'GLOBAL' '平台登录' $platformLogin $merchantLogin = Invoke-Api POST '/api/auth/login' '' @{ username = $MerchantUsername; password = $MerchantPassword } $merchant = Require-Success 'GLOBAL' '客户登录' $merchantLogin if ($OcrProbeOnly) { if ($ExistingInboundId -le 0) { throw 'OCR probe 模式必须提供 ExistingInboundId' } $ocrResults = @() foreach ($image in $probeImages) { $ocrResults += Probe-Ocr $platform.accessToken ([string]$ExistingInboundId) $image } $runs.Add([pscustomobject]@{ inboundId = [string]$ExistingInboundId ocrResults = $ocrResults }) } elseif ($OcrOnly) { if ($ExistingInboundId -le 0) { throw 'OCR-only 模式必须提供 ExistingInboundId' } $weightResults = @() foreach ($image in @($successfulImages + $failedImage)) { $manual = if ($image -eq $failedImage) { [decimal]128 } else { $null } $weightResults += Upload-And-ConfirmWeight 'OCR' $platform.accessToken ([string]$ExistingInboundId) $image $manual } $measurementResponse = Invoke-Api GET "/api/platform/v1/first-leg/inbounds/$ExistingInboundId/measurement?tenantId=$TenantId" $platform.accessToken $measurement = Require-Success 'OCR' '读取确认后重量汇总' $measurementResponse $runs.Add([pscustomobject]@{ inboundId = [string]$ExistingInboundId weightResults = $weightResults actualGrossWeightKg = $measurement.actualGrossWeightKg measurement = $measurement }) } elseif ($ExistingInboundId -gt 0) { if ($ExistingOrderId -le 0 -or [string]::IsNullOrWhiteSpace($ExistingInboundCode) -or $ExistingCartonCount -lt 4) { throw '恢复模式必须同时提供 ExistingOrderId、ExistingInboundCode 和至少 4 箱的 ExistingCartonCount' } $reference = [pscustomobject]@{ orderId = [string]$ExistingOrderId inboundId = [string]$ExistingInboundId inboundCode = $ExistingInboundCode } Initialize-CartonLabels 'EXISTING' $platform.accessToken $reference.inboundId $scans = @(Scan-Cartons 'EXISTING' $platform.accessToken $reference.inboundId ` $reference.inboundCode $ExistingCartonCount) Set-RepresentativeCartonCounts 'EXISTING' $platform.accessToken $reference.inboundId $scans $ExistingCartonCount $existingRun = Complete-MeasurementAndPrice 'EXISTING' $platform.accessToken $merchant.accessToken $reference ` @($successfulImages + $failedImage) ([decimal]128) $true $runs.Add($existingRun) } else { $kgReference = Create-ApprovedInbound 'KG' $merchant.accessToken $platform.accessToken 'TAX_INCLUDED' Initialize-CartonLabels 'KG' $platform.accessToken $kgReference.inboundId $null = Scan-Cartons 'KG' $platform.accessToken $kgReference.inboundId $kgReference.inboundCode $kgRun = Complete-MeasurementAndPrice 'KG' $platform.accessToken $merchant.accessToken $kgReference ` $successfulImages $null $runs.Add($kgRun) $cbmReference = Create-ApprovedInbound 'CBM' $merchant.accessToken $platform.accessToken 'TAX_EXCLUDED' Initialize-CartonLabels 'CBM' $platform.accessToken $cbmReference.inboundId $null = Scan-Cartons 'CBM' $platform.accessToken $cbmReference.inboundId $cbmReference.inboundCode $cbmRun = Complete-MeasurementAndPrice 'CBM' $platform.accessToken $merchant.accessToken $cbmReference ` @($failedImage) ([decimal]128) $runs.Add($cbmRun) } } catch { $fatal = $_.Exception.Message Write-Host "[FATAL] $fatal" } finally { $report = [ordered]@{ marker = $marker gateway = $GatewayBaseUrl tenantId = [string]$TenantId generatedAt = (Get-Date).ToString('o') success = $null -eq $fatal -and @($steps | Where-Object { -not $_.passed }).Count -eq 0 fatal = $fatal runs = $runs steps = $steps } $reportDirectory = Split-Path -Parent $OutputPath if (-not (Test-Path -LiteralPath $reportDirectory)) { $null = New-Item -ItemType Directory -Path $reportDirectory } $report | ConvertTo-Json -Depth 40 | Set-Content -LiteralPath $OutputPath -Encoding utf8NoBOM if ((Resolve-Path -LiteralPath $tempRoot).Path.StartsWith([System.IO.Path]::GetTempPath(), [System.StringComparison]::OrdinalIgnoreCase)) { Remove-Item -LiteralPath $tempRoot -Recurse -Force } Write-Host "REPORT=$OutputPath" } if ($null -ne $fatal) { exit 1 } if (@($steps | Where-Object { -not $_.passed }).Count -gt 0) { exit 2 }