fix: fetch document lines via $expand instead of standalone queries
The BC API v2.0 requires line entities (salesInvoiceLines, etc.) to be accessed through their parent document - they cannot be queried directly. Use OData $expand on parent documents to include lines inline, e.g. salesInvoices?$expand=salesInvoiceLines Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -18,22 +18,12 @@ $bcCompanyName = $env:BC_COMPANY_NAME # optional: filter to specific company
|
|||||||
|
|
||||||
$baseUrl = "https://api.businesscentral.dynamics.com/v2.0/$tenantId/$environmentName/api/v2.0"
|
$baseUrl = "https://api.businesscentral.dynamics.com/v2.0/$tenantId/$environmentName/api/v2.0"
|
||||||
|
|
||||||
# Entities to extract - critical business data
|
# Standalone entities to extract
|
||||||
$entities = @(
|
$entities = @(
|
||||||
"accounts",
|
"accounts",
|
||||||
"customers",
|
"customers",
|
||||||
"vendors",
|
"vendors",
|
||||||
"items",
|
"items",
|
||||||
"salesInvoices",
|
|
||||||
"salesInvoiceLines",
|
|
||||||
"salesOrders",
|
|
||||||
"salesOrderLines",
|
|
||||||
"salesCreditMemos",
|
|
||||||
"salesCreditMemoLines",
|
|
||||||
"purchaseInvoices",
|
|
||||||
"purchaseInvoiceLines",
|
|
||||||
"purchaseOrders",
|
|
||||||
"purchaseOrderLines",
|
|
||||||
"generalLedgerEntries",
|
"generalLedgerEntries",
|
||||||
"bankAccounts",
|
"bankAccounts",
|
||||||
"employees",
|
"employees",
|
||||||
@@ -46,6 +36,16 @@ $entities = @(
|
|||||||
"countriesRegions"
|
"countriesRegions"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# Document entities with line items - fetched with $expand to include lines
|
||||||
|
# Lines cannot be queried standalone; they require a parent document ID
|
||||||
|
$documentEntities = @{
|
||||||
|
"salesInvoices" = "salesInvoiceLines"
|
||||||
|
"salesOrders" = "salesOrderLines"
|
||||||
|
"salesCreditMemos" = "salesCreditMemoLines"
|
||||||
|
"purchaseInvoices" = "purchaseInvoiceLines"
|
||||||
|
"purchaseOrders" = "purchaseOrderLines"
|
||||||
|
}
|
||||||
|
|
||||||
function Write-Log {
|
function Write-Log {
|
||||||
param([string]$Message, [string]$Level = "INFO")
|
param([string]$Message, [string]$Level = "INFO")
|
||||||
$timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
|
$timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
|
||||||
@@ -158,6 +158,48 @@ function Export-EntityData {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function Export-DocumentWithLines {
|
||||||
|
param(
|
||||||
|
[string]$Token,
|
||||||
|
[string]$CompanyId,
|
||||||
|
[string]$CompanyName,
|
||||||
|
[string]$DocumentEntity,
|
||||||
|
[string]$LineEntity,
|
||||||
|
[string]$OutputDir
|
||||||
|
)
|
||||||
|
|
||||||
|
$entityUrl = "$baseUrl/companies($CompanyId)/$DocumentEntity" + '?$expand=' + $LineEntity
|
||||||
|
|
||||||
|
Write-Log " Exporting $DocumentEntity (with $LineEntity)..."
|
||||||
|
|
||||||
|
try {
|
||||||
|
$data = Get-BCData -Token $Token -Url $entityUrl
|
||||||
|
$docCount = 0
|
||||||
|
$lineCount = 0
|
||||||
|
if ($data) {
|
||||||
|
$docCount = $data.Count
|
||||||
|
foreach ($doc in $data) {
|
||||||
|
if ($doc.$LineEntity) {
|
||||||
|
$lineCount += $doc.$LineEntity.Count
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# Save the documents (with lines embedded)
|
||||||
|
$outputFile = Join-Path $OutputDir "$DocumentEntity.json"
|
||||||
|
$data | ConvertTo-Json -Depth 10 | Out-File -FilePath $outputFile -Encoding utf8
|
||||||
|
|
||||||
|
Write-Log " $DocumentEntity : $docCount documents, $lineCount lines"
|
||||||
|
return ($docCount + $lineCount)
|
||||||
|
}
|
||||||
|
catch {
|
||||||
|
Write-Log " Failed to export ${DocumentEntity} with lines: $_" "WARN"
|
||||||
|
$outputFile = Join-Path $OutputDir "$DocumentEntity.json"
|
||||||
|
"[]" | Out-File -FilePath $outputFile -Encoding utf8
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
# Main execution
|
# Main execution
|
||||||
try {
|
try {
|
||||||
Write-Log "========================================="
|
Write-Log "========================================="
|
||||||
@@ -165,7 +207,7 @@ try {
|
|||||||
Write-Log "========================================="
|
Write-Log "========================================="
|
||||||
Write-Log "Environment: $environmentName"
|
Write-Log "Environment: $environmentName"
|
||||||
Write-Log "Output Path: $OutputPath"
|
Write-Log "Output Path: $OutputPath"
|
||||||
Write-Log "Entities to extract: $($entities.Count)"
|
Write-Log "Entities to extract: $($entities.Count + $documentEntities.Count) ($($documentEntities.Count) with line items)"
|
||||||
|
|
||||||
# Create output directory
|
# Create output directory
|
||||||
$exportDir = $OutputPath
|
$exportDir = $OutputPath
|
||||||
@@ -217,6 +259,7 @@ try {
|
|||||||
New-Item -ItemType Directory -Path $companyDir -Force | Out-Null
|
New-Item -ItemType Directory -Path $companyDir -Force | Out-Null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Export standalone entities
|
||||||
foreach ($entity in $entities) {
|
foreach ($entity in $entities) {
|
||||||
$count = Export-EntityData `
|
$count = Export-EntityData `
|
||||||
-Token $token `
|
-Token $token `
|
||||||
@@ -232,6 +275,26 @@ try {
|
|||||||
$failedEntities += "$companyName/$entity"
|
$failedEntities += "$companyName/$entity"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Export document entities with their line items via $expand
|
||||||
|
foreach ($docEntity in $documentEntities.Keys) {
|
||||||
|
$lineEntity = $documentEntities[$docEntity]
|
||||||
|
|
||||||
|
$count = Export-DocumentWithLines `
|
||||||
|
-Token $token `
|
||||||
|
-CompanyId $companyId `
|
||||||
|
-CompanyName $companyName `
|
||||||
|
-DocumentEntity $docEntity `
|
||||||
|
-LineEntity $lineEntity `
|
||||||
|
-OutputDir $companyDir
|
||||||
|
|
||||||
|
$totalRecords += $count
|
||||||
|
$totalEntities++
|
||||||
|
|
||||||
|
if ($count -eq 0) {
|
||||||
|
$failedEntities += "$companyName/$docEntity"
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
# Save export metadata
|
# Save export metadata
|
||||||
|
|||||||
Reference in New Issue
Block a user