Delivery.ps1
|
Set-StrictMode -Version Latest $RequestCodes = @{ hold = 0 create = 10 update = 20 save_bol = 30 save_drop = 40 status = 90 cancel = 99 } $StageCodes = @{ assigned = 10 driving_to_load = 20 arrived_at_load = 30 loading = 40 driving_to_drop = 50 arrived_at_drop = 60 dropping = 70 completed_drop = 80 complete = 90 } $StateNames = @{ X00 = 'pending' X40 = 'rejected' X80 = 'reconciled' X90 = 'sent' } function Get-RequestJson($request) { if ($request.PSObject.Properties['payload_json']) { return $request.payload_json } ConvertTo-Json -InputObject $request.payload -Depth 12 -Compress } function ConvertTo-CompactJson($json) { ConvertTo-Json -InputObject (ConvertFrom-Json $json -Depth 64 -DateKind String -NoEnumerate) -Depth 64 -Compress } function Get-RequestHash($baseUrl, $request, $tenant, $destinationTenant) { $json = Get-RequestJson $request $bytes = [Text.Encoding]::UTF8.GetBytes("$($baseUrl.TrimEnd('/'))|$Tenant|$DestinationTenant|$($request.path)|$json") [Convert]::ToHexString([Security.Cryptography.SHA256]::HashData($bytes)).ToLower() } function Get-MessageKey($request) { if ($request.PSObject.Properties['message_key']) { return $request.message_key } switch ($request.kind) { save_bol { "save_bol|$($request.payload.bol_number)|$($request.payload.terminal.source_id)" } save_drop { "save_drop|$($request.payload.site.source_id)" } default { $request.kind } } } function Write-DeliveryItem($path, $item) { $temp = "$path.tmp" try { $item | ConvertTo-Json -Depth 16 | Set-Content -LiteralPath $temp -Encoding utf8 -ErrorAction Stop [IO.File]::Move($temp, $path, $true) } finally { if (Test-Path -LiteralPath $temp) { Remove-Item -LiteralPath $temp } } } function Get-ReceiptKey($data) { "$($data.base_url)|$($data.tenant)|$($data.destination_tenant)|$($data.order_number)|$($data.message_key)" } function Get-CreatedKey($data) { "$($data.base_url)|$($data.tenant)|$($data.destination_tenant)|$($data.order_number)" } function Get-DeliveryIndex($cacheDir, [switch]$Prune) { $legacy = @{} $terminal = @{} $pendingByHash = @{} $pending = [Collections.Generic.List[object]]::new() $receipts = @{} $created = @{} $terminalItems = [Collections.Generic.List[object]]::new() $oldFormat = $false foreach ($file in @(Get-ChildItem $cacheDir -File | Sort-Object Name)) { if ($file.Extension -eq '.cache') { $oldFormat = $true $legacy[$file.BaseName] = $true continue } if ($file.Name -notmatch '\.X(?<state>00|40|80|90)\.(?<hash>[0-9a-f]{64})\.json$') { continue } $state = $Matches.state $item = [pscustomobject]@{ file = $file.FullName data = Get-Content $file.FullName -Raw | ConvertFrom-Json -Depth 64 -DateKind String } # Match receipts from before numeric padding was removed. $compact = [pscustomobject]@{ path = $item.data.path; payload_json = ConvertTo-CompactJson (Get-RequestJson $item.data) } $item | Add-Member hashes @($item.data.hash, (Get-RequestHash $item.data.base_url $compact $item.data.tenant $item.data.destination_tenant)) if (-not $item.data.PSObject.Properties['payload_json']) { $oldFormat = $true } if ($state -ne '00') { $terminalItems.Add($item) if ($item.data.kind -eq 'create' -and $state -eq '90' -and $item.data.status -eq 'synced') { $created[(Get-CreatedKey $item.data)] = $item } $key = Get-ReceiptKey $item.data if ($receipts.ContainsKey($key)) { $old = $receipts[$key] foreach ($hash in $old.hashes) { $terminal.Remove($hash) } } $receipts[$key] = $item foreach ($hash in $item.hashes) { $terminal[$hash] = $true } continue } $pendingByHash[$item.data.hash] = $item $pending.Add($item) } if ($Prune) { $keep = @{} foreach ($item in @($receipts.Values) + @($created.Values)) { $keep[$item.file] = $true } foreach ($item in $terminalItems) { if (-not $keep.ContainsKey($item.file)) { Remove-Item -LiteralPath $item.file } } } foreach ($item in @($pending)) { if (-not @($item.hashes.Where({$terminal.ContainsKey($_)})).Count) { continue } $pendingByHash.Remove($item.data.hash) $null = $pending.Remove($item) if ($Prune) { Remove-Item -LiteralPath $item.file } } [pscustomobject]@{ legacy = $legacy terminal = $terminal pending_by_hash = $pendingByHash pending = $pending receipts = $receipts created = $created old_format = $oldFormat } } function New-DeliveryItem($order, $request, $hash, $messageKey, $baseUrl, $cacheDir, $tenant, $destinationTenant, $stateCode = 'X00', $status = $null, $response = $null) { $updated = [datetime]$order.updated_date $stage = if ($request.kind -eq 'cancel') { 99 } else { [int]$StageCodes["$($order.progress)"] } $requestCode = [int]$RequestCodes[$request.kind] $stamp = $updated.ToString('yyyyMMddTHHmmssfff') $file = Join-Path $cacheDir "$stamp.$($order.order_number).S$($stage.ToString('00')).R$($requestCode.ToString('00')).$stateCode.$hash.json" $data = [pscustomobject][ordered]@{ order_number = $order.order_number source_updated = $updated.ToString('yyyy-MM-ddTHH:mm:ss.fff') stage_code = $stage request_code = $requestCode state = $StateNames[$stateCode] message_key = $messageKey hash = $hash base_url = $baseUrl.TrimEnd('/') tenant = $Tenant destination_tenant = $DestinationTenant kind = $request.kind path = $request.path payload_json = Get-RequestJson $request attempted_at = $null http = $null status = $status response = $response } [pscustomobject]@{ file = $file; data = $data } } function Get-CrossroadsDeliverySummary($cacheDir = (Join-Path $PWD 'cache')) { $files = @(if (Test-Path -LiteralPath $cacheDir) { Get-ChildItem -LiteralPath $cacheDir -File -Force -ErrorAction Stop }) $counts = @{ X00 = 0; X40 = 0; X80 = 0; X90 = 0 } $bytes = 0L $oldest = $null $cursor = $null foreach ($file in $files) { $bytes += $file.Length if ($file.Name -match '^(\d{8}T\d{9})\..+\.S\d+\.R\d+\.(X00|X40|X80|X90)\.[0-9a-f]{64}\.json$') { $stamp, $state = $Matches[1], $Matches[2] $counts[$state]++ if ($state -eq 'X00' -and ($null -eq $oldest -or $stamp -lt $oldest)) { $oldest = $stamp } } elseif ($file.Name -match '^(\d{8}T\d{9})\.cursor$') { if ($null -eq $cursor -or $Matches[1] -gt $cursor) { $cursor = $Matches[1] } } } [pscustomobject][ordered]@{ Pending = $counts.X00 Rejected = $counts.X40 Reconciled = $counts.X80 Sent = $counts.X90 TotalFiles = $files.Count SizeMB = [math]::Round($bytes / 1MB, 2) OldestPendingSourceUpdate = if ($oldest) { [datetime]::ParseExact($oldest, 'yyyyMMddTHHmmssfff', [Globalization.CultureInfo]::InvariantCulture) } else { $null } Cursor = if ($cursor) { [datetime]::ParseExact($cursor, 'yyyyMMddTHHmmssfff', [Globalization.CultureInfo]::InvariantCulture) } else { $null } } } function Initialize-CrossroadsDelivery($cacheDir = (Join-Path $PWD 'cache')) { $null = Initialize-Delivery $cacheDir } function Initialize-Delivery($cacheDir) { New-Item -ItemType Directory -Path $cacheDir -Force | Out-Null $index = Get-DeliveryIndex $cacheDir -Prune foreach ($item in @($index.receipts.Values)) { if ($item.data.state -ne 'rejected' -or $item.data.status -ne 'pending' -or $item.data.http -lt 200 -or $item.data.http -ge 300) { continue } $key = Get-ReceiptKey $item.data if (@($index.pending.Where({(Get-ReceiptKey $_.data) -eq $key -and [datetime]$_.data.source_updated -ge [datetime]$item.data.source_updated})).Count) { continue } $old = $item.file $item.file = $old -replace '\.X40\.', '.X00.' $item.data.state = 'pending' Write-DeliveryItem $item.file $item.data Remove-Item -LiteralPath $old $index.receipts.Remove($key) foreach ($hash in $item.hashes) { $index.terminal.Remove($hash) } $index.pending.Add($item) $index.pending_by_hash[$item.data.hash] = $item } $protected = @{} foreach ($item in $index.created.Values) { $protected[$item.file] = $true } $required = @{} foreach ($item in $index.pending) { if (-not $item.data.PSObject.Properties['requires']) { continue } foreach ($hash in @($item.data.requires)) { if ($hash) { $required[$hash] = $true } } } foreach ($item in $index.receipts.Values) { if (@($item.hashes.Where({$required.ContainsKey($_)})).Count) { $protected[$item.file] = $true } } $purge = @(Get-ChildItem $cacheDir -File | Where-Object { ($_.Extension -eq '.cache' -or $_.Name -match '\.X(40|80|90)\.[0-9a-f]{64}\.json$') -and -not $protected.ContainsKey($_.FullName) }) Push-Location $cacheDir try { if ($purge.Count) { $null = Clear-Files ([pscustomobject]@{ keepdays = 1; purgefiles = $purge.Name -join ',' }) } } finally { Pop-Location } if ($purge.Count) { Get-DeliveryIndex $cacheDir -Prune } else { $index } } function Get-CrossroadsDeliveryCursor($cacheDir = (Join-Path $PWD 'cache')) { $cursor = @(Get-ChildItem $cacheDir -Filter '*.cursor' -File | Sort-Object Name | Select-Object -Last 1) if ($cursor.Count -eq 0) { return } [datetime]::ParseExact($cursor[0].BaseName, 'yyyyMMddTHHmmssfff', [Globalization.CultureInfo]::InvariantCulture) } function Set-CrossroadsDeliveryCursor($cacheDir = (Join-Path $PWD 'cache'), $current, $rows) { $latest = @($rows.updated_date | ForEach-Object { [datetime]$_ } | Sort-Object)[-1] if ($null -eq $current -or $latest -gt $current) { $stamp = $latest.ToString('yyyyMMddTHHmmssfff') $null > (Join-Path $cacheDir "$stamp.cursor") Get-ChildItem $cacheDir -Filter '*.cursor' -File | Where-Object BaseName -ne $stamp | Remove-Item return $latest } $current } function Add-CrossroadsDelivery($orders, [Parameter(Mandatory)] [ValidateNotNullOrWhiteSpace()] [string]$baseUrl, $cacheDir = (Join-Path $PWD 'cache'), $persist, [Parameter(Mandatory)] [ValidateNotNullOrEmpty()] [string]$Tenant, [Parameter(Mandatory)] [ValidateNotNullOrEmpty()] [string]$DestinationTenant) { Add-Delivery $orders $baseUrl $cacheDir $persist $Tenant $DestinationTenant (Get-DeliveryIndex $cacheDir) } function Add-Delivery($orders, $baseUrl, $cacheDir, $persist, $Tenant, $DestinationTenant, $index) { if (@($orders | Group-Object order_number | Where-Object Count -gt 1).Count) { throw 'Supply one complete latest snapshot per order in each batch.' } $baseUrl = $baseUrl.TrimEnd('/') $staged = [Collections.Generic.List[object]]::new() foreach ($order in $orders) { if ($null -eq $order.updated_date) { throw "Crossroads: $($order.order_number) has no updated date" } $updated = [datetime]$order.updated_date $requests = @(foreach ($request in @($order.requests)) { $hash = Get-RequestHash $baseUrl $request $Tenant $DestinationTenant $priorHash = $hash # Old receipts used normalized object JSON, not the SQL string. if ($index.old_format -and $request.PSObject.Properties['payload_json']) { $prior = [pscustomobject]@{ path = $request.path; payload = ConvertFrom-Json $request.payload_json -Depth 64 -DateKind String } $priorHash = Get-RequestHash $baseUrl $prior $Tenant $DestinationTenant } [pscustomobject]@{ request = $request hash = $hash prior_hash = $priorHash key = Get-MessageKey $request } }) $current = @{} foreach ($item in $requests) { $current[$item.key] = @($item.hash, $item.prior_hash) } if ($persist) { foreach ($old in @($index.pending.Where({ "$($_.data.order_number)" -eq "$($order.order_number)" -and $_.data.base_url.TrimEnd('/') -eq $baseUrl -and $_.data.tenant -ceq $Tenant -and $_.data.destination_tenant -ceq $DestinationTenant -and [datetime]$_.data.source_updated -le $updated }))) { if ($current.ContainsKey($old.data.message_key) -and $current[$old.data.message_key] -contains $old.data.hash) { continue } Remove-Item -LiteralPath $old.file $index.pending_by_hash.Remove($old.data.hash) $null = $index.pending.Remove($old) } } $cancel = @($order.requests | Where-Object kind -eq 'cancel').Count -gt 0 if (-not [string]::IsNullOrWhiteSpace($order.hold) -and -not $cancel) { $request = [pscustomobject]@{ kind = 'hold' path = $null payload = [pscustomobject][ordered]@{ order_number = $order.order_number reason = $order.hold } } $hash = Get-RequestHash $baseUrl $request $Tenant $DestinationTenant if (-not $index.terminal.ContainsKey($hash)) { $item = New-DeliveryItem $order $request $hash 'hold' $baseUrl $cacheDir $Tenant $DestinationTenant 'X40' 'held' ([pscustomobject]@{ source = 'local'; message = $order.hold }) if ($persist) { Write-DeliveryItem $item.file $item.data } $index.terminal[$hash] = $true $staged.Add($item) } } $requires = @($requests | Where-Object {$_.request.kind -in @('save_bol','save_drop')} | ForEach-Object hash) foreach ($requestItem in $requests) { $completion = $requestItem.request.kind -eq 'status' -and $order.progress -eq 'complete' $hashes = @($requestItem.hash, $requestItem.prior_hash) if (@($hashes.Where({ $index.terminal.ContainsKey($_) -or ($requestItem.request.kind -eq 'create' -and $index.legacy.ContainsKey($_)) })).Count) { continue } $pendingHash = $hashes.Where({$index.pending_by_hash.ContainsKey($_)}, 'First') if ($pendingHash.Count) { $item = $index.pending_by_hash[$pendingHash[0]] if ($completion -and [datetime]$item.data.source_updated -le $updated) { $item.data | Add-Member requires $requires -Force if ($persist) { Write-DeliveryItem $item.file $item.data } } $staged.Add($item) continue } $item = New-DeliveryItem $order $requestItem.request $requestItem.hash $requestItem.key $baseUrl $cacheDir $Tenant $DestinationTenant if ($completion) { $item.data | Add-Member requires $requires } if ($persist) { Write-DeliveryItem $item.file $item.data } $index.pending_by_hash[$requestItem.hash] = $item $index.pending.Add($item) $staged.Add($item) } } @($staged) } function Set-DeliveryResult($item, $stateCode, $http, $status, $response, $index) { $item.data.attempted_at = (Get-Date).ToUniversalTime().ToString('o') $item.data.http = $http $item.data.status = $status $item.data.response = $response $item.data.state = $StateNames[$stateCode] $destination = $item.file -replace '\.X00\.', ".$stateCode." Write-DeliveryItem $destination $item.data if ($stateCode -eq 'X00') { return } Remove-Item -LiteralPath $item.file $item.file = $destination $key = Get-ReceiptKey $item.data $createdKey = Get-CreatedKey $item.data if ($index.receipts.ContainsKey($key)) { $old = $index.receipts[$key] $confirmation = $index.created[$createdKey] if ($old.file -ne $destination -and ($null -eq $confirmation -or $old.file -ne $confirmation.file)) { Remove-Item -LiteralPath $old.file } } $index.receipts[$key] = $item if ($item.data.kind -eq 'create' -and $stateCode -eq 'X90' -and $status -eq 'synced') { if ($index.created.ContainsKey($createdKey) -and $index.created[$createdKey].file -ne $destination) { Remove-Item -LiteralPath $index.created[$createdKey].file } $index.created[$createdKey] = $item } } function Get-DeliveryResponse($response, $kind, $orderNumber) { $http = if ($null -eq $response.http) { 0 } else { [int]$response.http } $parseError = if ($response.PSObject.Properties['parse_error']) { $response.parse_error } else { $null } $responseText = if ($null -eq $response.data) { '' } else { ConvertTo-Json -InputObject $response.data -Depth 12 -Compress } $responseStatus = if ($null -ne $response.data -and $response.data.PSObject.Properties['status']) { "$($response.data.status)" } else { '' } $errorCode = $response.data foreach ($field in @('log', 'detail', 'error')) { $errorCode = if ($null -ne $errorCode -and $errorCode.PSObject.Properties[$field]) { $errorCode.$field } else { $null } } $accepted = -not $parseError -and $http -ge 200 -and $http -lt 300 $duplicate = -not $parseError -and $kind -eq 'create' -and ($accepted -or $http -eq 422) -and $( if ($errorCode) { $errorCode -eq 'request.order_already_exists' } else { $http -eq 422 -and $null -ne $response.data -and $response.data.PSObject.Properties['detail'] -and $response.data.detail -ceq "Duplicate order: An order with number '$orderNumber' already exists for this tenant." } ) $alreadyApplied = $duplicate -or ( -not $parseError -and $kind -eq 'update' -and $responseText -match '(?i)order is already loaded|order (?:has )?already been updated' ) $unconfirmedCreate = $accepted -and $kind -eq 'create' -and [string]::IsNullOrWhiteSpace($responseStatus) $sent = $accepted -and -not $unconfirmedCreate -and ([string]::IsNullOrWhiteSpace($responseStatus) -or $responseStatus -eq 'synced') $wrappedRetry = $responseText -match '(?i)too many requests|error code:\s*(?:408|429|5\d\d)\b|internal server error|timed? out|temporar(?:y|ily) unavailable' $retryable = ($accepted -and $responseStatus -eq 'pending') -or $unconfirmedCreate -or ($parseError -and $http -ge 200 -and $http -lt 300) -or $http -eq 0 -or $http -in @(401, 403, 408, 429) -or $http -ge 500 -or ($http -ge 300 -and $http -lt 400) -or $wrappedRetry $rejected = -not $sent -and -not $alreadyApplied -and -not $retryable $stateCode = if ($alreadyApplied) { 'X80' } elseif ($sent) { 'X90' } elseif ($rejected) { 'X40' } else { 'X00' } $status = if ($duplicate) { 'duplicate' } elseif ($alreadyApplied) { 'already_applied' } elseif ($parseError) { 'invalid_response' } elseif ($unconfirmedCreate) { 'unconfirmed' } elseif (-not [string]::IsNullOrWhiteSpace($responseStatus)) { $responseStatus } elseif ($rejected) { 'rejected' } else { 'pending' } $message = if ($null -ne $response.data -and $response.data.PSObject.Properties['message']) { "$($response.data.message)" } else { '' } $errorMessage = if ($stateCode -in @('X80', 'X90')) { '' } elseif ($parseError) { "$parseError" } elseif (-not [string]::IsNullOrWhiteSpace($message)) { $message } else { $responseText } [pscustomobject]@{ http = $http; state_code = $stateCode; status = $status; error_code = $errorCode; error = $errorMessage } } function Confirm-DestinationCreation($item, $token, $cacheDir, $index) { $data = $item.data $request = [pscustomobject]@{ kind='create'; path='/v1/order/get'; payload=@{order_number="$($data.order_number)"} } $read = Invoke-CrossroadsRequest -BaseUrl $data.base_url -Path $request.path -Body $request.payload ` -Token $token -Tenant $data.tenant -DestinationTenant $data.destination_tenant -ReadOnly if ($read.http -lt 200 -or $read.http -ge 300 -or $null -eq $read.data) { return $false } $body = $read.data if (-not $body.PSObject.Properties['status'] -or $body.status -ne 'synced' -or -not $body.PSObject.Properties['origin_order'] -or -not $body.PSObject.Properties['destination_order']) { return $false } $origin = $body.origin_order $destination = $body.destination_order if ($null -eq $origin -or $null -eq $destination -or -not $origin.PSObject.Properties['origin_order_number'] -or -not $destination.PSObject.Properties['origin_order_number'] -or -not $destination.PSObject.Properties['destination_order_number']) { return $false } if ("$($origin.origin_order_number)" -cne "$($data.order_number)" -or "$($destination.origin_order_number)" -cne "$($data.order_number)" -or [string]::IsNullOrWhiteSpace("$($destination.destination_order_number)")) { return $false } $order = [pscustomobject]@{order_number=$data.order_number; updated_date=$data.source_updated; progress='assigned'} $hash = Get-RequestHash $data.base_url $request $data.tenant $data.destination_tenant $proof = New-DeliveryItem $order $request $hash 'creation_confirmation' $data.base_url $cacheDir $data.tenant $data.destination_tenant 'X90' 'synced' ` ([pscustomobject]@{verified_by='order_get';destination_order_number=$destination.destination_order_number}) Write-DeliveryItem $proof.file $proof.data $index.created[(Get-CreatedKey $data)] = $proof return $true } function Send-CrossroadsDelivery( [Parameter(Mandatory)] [ValidateNotNullOrWhiteSpace()] [string]$baseUrl, $clientId, $clientSecret, $cacheDir = (Join-Path $PWD 'cache'), [Parameter(Mandatory)] [ValidateNotNullOrEmpty()] [string]$Tenant, [Parameter(Mandatory)] [ValidateNotNullOrEmpty()] [string]$DestinationTenant) { $baseUrl = $baseUrl.TrimEnd('/') $index = Get-DeliveryIndex $cacheDir $pending = @($index.pending.Where({ $_.data.base_url.TrimEnd('/') -eq $baseUrl -and $_.data.tenant -ceq $Tenant -and $_.data.destination_tenant -ceq $DestinationTenant })) if ($pending.Count -eq 0) { return } if ([string]::IsNullOrWhiteSpace($clientId) -or [string]::IsNullOrWhiteSpace($clientSecret)) { throw 'Crossroads: missing credentials' } $token = $null foreach ($group in ($pending | Group-Object { $_.data.order_number })) { $blocked = $false $created = $false $confirmed = $index.created.ContainsKey((Get-CreatedKey $group.Group[0].data)) $creates = @($group.Group.Where({$_.data.kind -eq 'create'})) if (-not $confirmed -and ($creates.Count -eq 0 -or @($creates.Where({$_.data.attempted_at})).Count)) { if (-not $token) { $token = Get-CrossroadsToken -BaseUrl $baseUrl -TokenPath '/auth/token' -ClientId $clientId -ClientSecret $clientSecret -GrantType 'password' } $confirmed = Confirm-DestinationCreation $group.Group[0] $token $cacheDir $index } $reported = $false foreach ($item in @($group.Group | Sort-Object { if ($_.data.kind -eq 'create') { 0 } else { 1 } }, { $_.data.stage_code }, { $_.data.request_code }, file)) { if ($blocked) { continue } if ($item.data.kind -ne 'create' -and -not $confirmed) { if (-not $reported) { [pscustomobject]@{ order_number = $item.data.order_number; kind = 'create'; http = $null; ok = $false; synced = $false; state = 'pending'; status = 'waiting_for_create'; error = 'Dependent requests await confirmed destination creation.' } $reported = $true } continue } if ($item.data.kind -eq 'update' -and $created) { Set-DeliveryResult $item 'X90' $null 'not_required' $null $index [pscustomobject]@{ order_number = $item.data.order_number; kind = $item.data.kind; http = $null; ok = $true; synced = $true; state = 'sent'; status = 'not_required'; error = '' } continue } if ($item.data.kind -eq 'status' -and $item.data.stage_code -eq 90) { $sent = @{} foreach ($receipt in $index.receipts.Values) { if ($receipt.data.state -ne 'sent') { continue } $sent[$receipt.data.hash] = $true if ($receipt.PSObject.Properties['hashes']) { foreach ($hash in $receipt.hashes) { $sent[$hash] = $true } } } if (-not $item.data.PSObject.Properties['requires'] -or @($item.data.requires.Where({-not $sent.ContainsKey($_)})).Count) { [pscustomobject]@{ order_number=$item.data.order_number; kind='status'; http=$null; ok=$false; synced=$false; state='pending'; status='waiting_for_details'; error='Completion awaits confirmed BOL and drop delivery.' } continue } } if (-not $token) { $token = Get-CrossroadsToken -BaseUrl $baseUrl -TokenPath '/auth/token' ` -ClientId $clientId -ClientSecret $clientSecret -GrantType 'password' } $response = Invoke-CrossroadsRequest -BaseUrl $baseUrl -Path $item.data.path ` -Body (Get-RequestJson $item.data) -RawJson -Token $token -Tenant $item.data.tenant ` -DestinationTenant $item.data.destination_tenant -AllowWrite $result = Get-DeliveryResponse $response $item.data.kind $item.data.order_number Set-DeliveryResult $item $result.state_code $result.http $result.status $response.data $index if ($item.data.kind -eq 'create' -and $result.state_code -eq 'X90' -and $result.status -eq 'synced') { $created = $true; $confirmed = $true } $blocked = $result.state_code -eq 'X00' -or ($item.data.kind -eq 'create' -and -not $confirmed) $synced = $result.state_code -in @('X80', 'X90') [pscustomobject]@{ order_number = $item.data.order_number kind = $item.data.kind http = $result.http ok = $synced synced = $synced state = $StateNames[$result.state_code] status = $result.status error_code = $result.error_code error = $result.error } } } } |