Public/Export-LedgerVatDeclaration.ps1
|
<# .SYNOPSIS Exports a VAT declaration (momsdeklaration) as a Skatteverket eSKD file. .DESCRIPTION Builds the VAT report for a period (via Get-LedgerVatReport) and writes it as an electronic tax declaration file (eSKD) that can be uploaded in Skatteverket's e-service for VAT (Lämna momsdeklaration via fil). The file is XML with an <eSKDUpload Version="6.0"> root, the company organisation number and a <Moms> section holding the declaration period and one element per declaration box (ruta). Amounts are reported in whole kronor (rounded). The following boxes are written: Ruta 05 (ForsMomsEjAnnan) — Momspliktig försäljning Ruta 10 (MomsUtgHog) — Utgående moms 25 % Ruta 11 (MomsUtgMedel) — Utgående moms 12 % Ruta 12 (MomsUtgLag) — Utgående moms 6 % Ruta 48 (MomsIngaende) — Ingående moms Ruta 49 (MomsBetala) — Moms att betala eller få tillbaka Box 49 (MomsBetala) is computed from the rounded box values as (10 + 11 + 12) - 48, matching how Skatteverket sums the declaration. A positive value is VAT to pay; a negative value is VAT to reclaim. The file is written with ISO-8859-1 encoding, as required by the eSKD format. .PARAMETER JournalPath The path to an existing journal directory. .PARAMETER FiscalYear The fiscal year identifier (e.g. '2024-01_2024-12'). .PARAMETER FromDate Start of the VAT reporting period (inclusive). .PARAMETER ToDate End of the VAT reporting period (inclusive). .PARAMETER Path Destination path for the eSKD file. Conventionally uses the .xml extension. .PARAMETER Period The declaration period as YYYYMM (e.g. '202403'). Defaults to the month of -ToDate. .PARAMETER Force Overwrite the destination file if it already exists. .EXAMPLE Export-LedgerVatDeclaration -JournalPath .\MinFirma.ledger -FiscalYear '2024-01_2024-12' -FromDate '2024-01-01' -ToDate '2024-03-31' -Path .\moms-2024-q1.xml Exports the Q1 2024 VAT declaration as an eSKD file. .EXAMPLE Export-LedgerVatDeclaration -JournalPath .\Konsult.ledger -FiscalYear '2024-01_2024-12' -FromDate '2024-06-01' -ToDate '2024-06-30' -Period '202406' -Path C:\Moms\konsult-2024-06.xml -Force Exports the June 2024 declaration with an explicit period, overwriting any existing file. #> function Export-LedgerVatDeclaration { [CmdletBinding(SupportsShouldProcess)] param ( [Parameter()] [string]$JournalPath, [Parameter(ValueFromPipelineByPropertyName)] [Alias('Name')] [string]$FiscalYear, [Parameter(Mandatory)] [datetime]$FromDate, [Parameter(Mandatory)] [datetime]$ToDate, [Parameter(Mandatory)] [string]$Path, [Parameter()] [ValidatePattern('^\d{6}$')] [string]$Period, [switch]$Force ) process { $JournalPath = Resolve-LedgerJournalPath -JournalPath $JournalPath $FiscalYear = Resolve-LedgerFiscalYear -FiscalYear $FiscalYear -JournalPath $JournalPath if ($ToDate -lt $FromDate) { throw "ToDate ($($ToDate.ToString('yyyy-MM-dd'))) must not be earlier than FromDate ($($FromDate.ToString('yyyy-MM-dd')))." } $DestPath = $ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($Path) if ((Test-Path -LiteralPath $DestPath) -and -not $Force) { throw "Destination file already exists: $DestPath. Use -Force to overwrite." } $journal = Get-LedgerJournal -Path $JournalPath $orgNr = $journal.OrgNumber if (-not $orgNr) { throw "Journal has no OrgNumber; set one with Set-LedgerJournal before exporting a VAT declaration." } if (-not $Period) { $Period = $ToDate.ToString('yyyyMM') } $report = @(Get-LedgerVatReport -JournalPath $JournalPath -FiscalYear $FiscalYear ` -FromDate $FromDate -ToDate $ToDate) # Round every box to whole kronor (Skatteverket declarations use integers). $boxAmount = @{} foreach ($box in $report) { $boxAmount[[int]$box.Box] = [long][Math]::Round([decimal]$box.Amount, 0, [System.MidpointRounding]::AwayFromZero) } # Box 49 is derived from the rounded output/input boxes so it always # reconciles with the individual rows the way Skatteverket sums them. $outputVat = 0L foreach ($b in 10, 11, 12) { if ($boxAmount.ContainsKey($b)) { $outputVat += $boxAmount[$b] } } $inputVat = if ($boxAmount.ContainsKey(48)) { $boxAmount[48] } else { 0L } $boxAmount[49] = $outputVat - $inputVat $tagMap = Get-VatEskdTagMap $sb = New-Object System.Text.StringBuilder $nl = "`r`n" $append = { param($line) [void]$sb.Append($line) [void]$sb.Append($nl) } & $append '<?xml version="1.0" encoding="ISO-8859-1"?>' & $append '<eSKDUpload Version="6.0">' & $append " <OrgNr>$orgNr</OrgNr>" & $append ' <Moms>' & $append " <Period>$Period</Period>" foreach ($map in $tagMap) { $box = [int]$map.Box $value = if ($boxAmount.ContainsKey($box)) { $boxAmount[$box] } else { 0L } & $append " <$($map.Tag)>$value</$($map.Tag)>" } & $append ' </Moms>' & $append '</eSKDUpload>' if (-not $PSCmdlet.ShouldProcess($DestPath, "Export VAT declaration for $Period")) { return } $encoding = [System.Text.Encoding]::GetEncoding('ISO-8859-1') [System.IO.File]::WriteAllText($DestPath, $sb.ToString(), $encoding) [PSCustomObject]@{ Path = $DestPath OrgNumber = $orgNr Period = $Period Boxes = [PSCustomObject]@{ '05' = $boxAmount[5] '10' = $boxAmount[10] '11' = $boxAmount[11] '12' = $boxAmount[12] '48' = $boxAmount[48] '49' = $boxAmount[49] } } } } |