Private/Save-NSPScanBridgeReceipt.ps1
|
function Save-NSPScanBridgeReceipt { [CmdletBinding()] param( [Parameter(Mandatory)][string]$PdfPath, [Parameter(Mandatory)][System.Collections.IDictionary]$Binding, [Parameter(Mandatory)][ValidateSet('Queued','Uploading','Uploaded','Review')][string]$State, [string]$RemoteId, [switch]$VerifiedReconciliation ) Assert-NSPScanBridgeJobBinding -Binding $Binding $pdf = Get-Item -LiteralPath $PdfPath -ErrorAction Stop $id = [IO.Path]::GetFileNameWithoutExtension($pdf.Name) if ($id -notmatch '^[0-9a-f]{32}$') { throw 'Invalid job ID.' } $receiptPath = [IO.Path]::ChangeExtension($pdf.FullName, '.json') $previous = $null if (Test-Path -LiteralPath $receiptPath) { $previous = Read-NSPScanBridgeReceipt -PdfPath $pdf.FullName -ReceiptPath $receiptPath -ExpectedBinding $Binding } $hash = (Get-FileHash -LiteralPath $pdf.FullName -Algorithm SHA256).Hash if ($previous -and ($previous.JobId -ne $id -or $previous.Hash -ne $hash)) { throw 'Job receipt does not match the PDF.' } if ($previous) { $allowed = @{ Queued = @('Queued','Uploading','Review') Uploading = @('Uploading','Uploaded','Review') Uploaded = @('Uploaded') Review = $(if ($VerifiedReconciliation) { @('Review','Uploaded') } else { @('Review') }) } if (-not $allowed.ContainsKey([string]$previous.State) -or $State -notin $allowed[[string]$previous.State]) { throw 'Invalid receipt state transition.' } if ($previous.State -eq 'Uploaded' -and $RemoteId -ne $previous.RemoteId) { throw 'An acknowledged remote item ID cannot change.' } } if ($State -eq 'Uploaded' -and -not $RemoteId) { throw 'Uploaded state requires remote item ID.' } $receipt = @{ Version = 2 Destination = $Binding JobId = $id State = $State Hash = $hash Size = [long]$pdf.Length TimestampUtc = [DateTime]::UtcNow.ToString('o') RemoteId = $RemoteId } $temp = $receiptPath + '.new' try { [IO.File]::WriteAllText($temp, ($receipt | ConvertTo-Json -Depth 5 -Compress)) if (Test-Path -LiteralPath $receiptPath) { [IO.File]::Replace($temp, $receiptPath, [NullString]::Value) } else { [IO.File]::Move($temp, $receiptPath) } } finally { if (Test-Path -LiteralPath $temp) { Remove-Item -LiteralPath $temp -Force } } } |