Auto-add missing entity.json keys as null; null now means ignore, not error

On each run the engine compares entity.json against the full set of known
keys, adds any that are absent with a null value, and writes the file back -
so nobody has to hand-type key names (the typo class of config error goes
away). A null/blank value now means "this entity doesn't use this": files
that would need it are ignored with a yellow notice and left in place,
instead of counting as failures. Insurance-unconfigured no longer skips the
patient step for that practice (was continue, now else-branch).
This commit is contained in:
2026-07-05 20:19:34 -05:00
parent 1c452d2802
commit 1a249c3caa
2 changed files with 77 additions and 48 deletions
+61 -35
View File
@@ -76,6 +76,39 @@ if (-not (Test-Path $entityConfigFile)) {
}
$entityConfig = Get-Content $entityConfigFile -Raw | ConvertFrom-Json
# Add any missing keys to entity.json as null so they never have to be typed
# by hand (a null value means "not used - ignore"). Writes the file back only
# when something was actually added.
$configTemplate = [ordered]@{
workflow = $null
insurance_file_type = $null
ftps = [ordered]@{ host = $null; port = $null; tls = $null; username = $null; password = $null; tiff_path = $null; pdf_path = $null }
sftp = [ordered]@{ host = $null; port = $null; username = $null; password = $null; patient_path = $null }
}
$addedKeys = @()
foreach ($topKey in $configTemplate.Keys) {
if ($null -eq $entityConfig.PSObject.Properties[$topKey]) {
$value = if ($configTemplate[$topKey] -is [System.Collections.Specialized.OrderedDictionary]) {
[PSCustomObject]$configTemplate[$topKey]
} else { $configTemplate[$topKey] }
$entityConfig | Add-Member -NotePropertyName $topKey -NotePropertyValue $value
$addedKeys += $topKey
} elseif ($configTemplate[$topKey] -is [System.Collections.Specialized.OrderedDictionary]) {
foreach ($subKey in $configTemplate[$topKey].Keys) {
if ($null -eq $entityConfig.$topKey.PSObject.Properties[$subKey]) {
$entityConfig.$topKey | Add-Member -NotePropertyName $subKey -NotePropertyValue $null
$addedKeys += "$topKey.$subKey"
}
}
}
}
if ($addedKeys.Count -gt 0) {
$entityConfig | ConvertTo-Json -Depth 10 | Set-Content -Path $entityConfigFile -Encoding UTF8
Write-Host "Added missing key(s) to entity.json (as null = ignored): $($addedKeys -join ', ')" -ForegroundColor Yellow
Write-Info "CONFIG added missing keys to entity.json: $($addedKeys -join ',')"
}
$workflow = $entityConfig.workflow
$insuranceExt = if ($entityConfig.insurance_file_type) { $entityConfig.insurance_file_type.TrimStart(".") } else { "pdf" }
$export1 = Join-Path $EntityDir "Export1"
@@ -269,39 +302,35 @@ foreach ($practice in $practices) {
$missing = Get-MissingFields $config.ftps "ftps" @("host", "username", "password", "tiff_path", "pdf_path")
if (($insFiles.Count -gt 0 -or $ptStmts.Count -gt 0) -and $missing.Count -gt 0) {
Write-Host " CONFIG ERROR: entity.json is missing or has blank: $($missing -join ', ')" -ForegroundColor Red
Write-Host " Check spelling of those keys in entity.json (and practice.json if present)." -ForegroundColor Yellow
Write-Log "error" "CONFIG entity=$entityName practice=$pracName missing=$($missing -join ',')"
$totalFail += $insFiles.Count + $ptStmts.Count
Write-Host " $today\ left for retry." -ForegroundColor Yellow
continue
}
Write-Host " Insurance upload not configured ($($missing -join ', ') is null/blank) - $($insFiles.Count + $ptStmts.Count) file(s) ignored, left in place." -ForegroundColor Yellow
Write-Info "IGNORE entity=$entityName practice=$pracName reason=unconfigured fields=$($missing -join ',')"
} else {
if ($insFiles.Count -gt 0) {
Write-Host " Insurance ($($insFiles.Count)) -> $insPath" -ForegroundColor White
$r = Invoke-FTPSUpload $config.ftps $insFiles $insPath $entityName $pracName
$insResult.Ok += $r.Ok; $insResult.Fail += $r.Fail
}
if ($ptStmts.Count -gt 0) {
Write-Host " PT STMT ($($ptStmts.Count)) -> $pdfPath" -ForegroundColor White
$r = Invoke-FTPSUpload $config.ftps $ptStmts $pdfPath $entityName $pracName
$insResult.Ok += $r.Ok; $insResult.Fail += $r.Fail
}
if ($insFiles.Count -gt 0) {
Write-Host " Insurance ($($insFiles.Count)) -> $insPath" -ForegroundColor White
$r = Invoke-FTPSUpload $config.ftps $insFiles $insPath $entityName $pracName
$insResult.Ok += $r.Ok; $insResult.Fail += $r.Fail
}
if ($ptStmts.Count -gt 0) {
Write-Host " PT STMT ($($ptStmts.Count)) -> $pdfPath" -ForegroundColor White
$r = Invoke-FTPSUpload $config.ftps $ptStmts $pdfPath $entityName $pracName
$insResult.Ok += $r.Ok; $insResult.Fail += $r.Fail
}
$totalUploaded = $insFiles.Count + $ptStmts.Count
if ($insResult.Fail -eq 0 -and $totalUploaded -gt 0) {
$archive = Get-ArchiveDir $practice.FullName "Archive sent to FTP"
Move-Item -Path $dateDir -Destination (Join-Path $archive $today) -Force
Write-Host " $today\ archived." -ForegroundColor Green
Write-Info "ARCHIVE entity=$entityName practice=$pracName folder=$today"
} elseif ($insResult.Fail -gt 0) {
Write-Host " $($insResult.Fail) failed - $today\ left for retry." -ForegroundColor Yellow
} elseif ($totalUploaded -eq 0) {
Write-Host " No .$insuranceExt files in $today\." -ForegroundColor Gray
Write-Info "SKIP entity=$entityName practice=$pracName reason=no .$insuranceExt files in date folder"
}
$totalUploaded = $insFiles.Count + $ptStmts.Count
if ($insResult.Fail -eq 0 -and $totalUploaded -gt 0) {
$archive = Get-ArchiveDir $practice.FullName "Archive sent to FTP"
Move-Item -Path $dateDir -Destination (Join-Path $archive $today) -Force
Write-Host " $today\ archived." -ForegroundColor Green
Write-Info "ARCHIVE entity=$entityName practice=$pracName folder=$today"
} elseif ($insResult.Fail -gt 0) {
Write-Host " $($insResult.Fail) failed - $today\ left for retry." -ForegroundColor Yellow
} elseif ($totalUploaded -eq 0) {
Write-Host " No .$insuranceExt files in $today\." -ForegroundColor Gray
Write-Info "SKIP entity=$entityName practice=$pracName reason=no .$insuranceExt files in date folder"
$totalOk += $insResult.Ok; $totalFail += $insResult.Fail
}
$totalOk += $insResult.Ok; $totalFail += $insResult.Fail
}
# -- Patient files -> SFTP -------------------------------------------------
@@ -326,11 +355,8 @@ foreach ($practice in $practices) {
Write-Host " No txt/tif files in $($ptFolder.Name)\ - skipping." -ForegroundColor Gray
Write-Info "SKIP entity=$entityName practice=$pracName reason=no txt/tif files"
} elseif (($sftpMissing = Get-MissingFields $config.sftp "sftp" @("host", "username", "password", "patient_path")).Count -gt 0) {
Write-Host " CONFIG ERROR: entity.json is missing or has blank: $($sftpMissing -join ', ')" -ForegroundColor Red
Write-Host " Check spelling of those keys in entity.json (and practice.json if present)." -ForegroundColor Yellow
Write-Log "error" "CONFIG entity=$entityName practice=$pracName missing=$($sftpMissing -join ',')"
$totalFail += $patFiles.Count
Write-Host " $($ptFolder.Name)\ left for retry." -ForegroundColor Yellow
Write-Host " Patient upload not configured ($($sftpMissing -join ', ') is null/blank) - $($patFiles.Count) file(s) ignored, left in place." -ForegroundColor Yellow
Write-Info "IGNORE entity=$entityName practice=$pracName reason=unconfigured fields=$($sftpMissing -join ',')"
} else {
$patPath = Expand-Path $config.sftp.patient_path $pracName
Write-Host " Patient ($($patFiles.Count)) -> $patPath" -ForegroundColor White