Private/PayrollPosting.ps1
|
# Recoverable payroll posting. An immutable plan in payslips/posting/payNNNN.txt # is written before the verification and reserves its number, so an interrupted # Invoke-LedgerPayrollPosting can be completed by repeating it. function Get-LedgerPayslipPostingPath { [CmdletBinding()] param ( [Parameter(Mandatory)] [string]$JournalPath, [Parameter(Mandatory)] [int]$PayslipNumber ) Join-Path $JournalPath 'payslips' 'posting' (Get-LedgerPayslipFileName -PayslipNumber $PayslipNumber) } function Read-LedgerPayslipPosting { [CmdletBinding()] param ([Parameter(Mandatory)] [string]$Path) $fields = @{} foreach ($line in Get-Content -LiteralPath $Path -Encoding UTF8 -ErrorAction Stop) { if ([string]::IsNullOrWhiteSpace($line) -or $line.StartsWith(';')) { continue } if ($line -notmatch '^([A-Za-z]+):\t(.+)$' -or $fields.ContainsKey($Matches[1])) { throw "Invalid payslip posting record '$Path': malformed or duplicate field." } $fields[$Matches[1]] = $Matches[2] } $id = [guid]::Empty $payslipNumber = 0 $verificationNumber = 0 if ($fields.FormatVersion -ne '1' -or -not [guid]::TryParseExact([string]$fields.OperationId, 'D', [ref]$id) -or $id -eq [guid]::Empty -or -not [int]::TryParse([string]$fields.PayslipNumber, [ref]$payslipNumber) -or $payslipNumber -le 0 -or -not [int]::TryParse([string]$fields.VerificationNumber, [ref]$verificationNumber) -or $verificationNumber -le 0 -or [string]::IsNullOrWhiteSpace($fields.FiscalYear) -or $fields.PayslipHash -cnotmatch '^[0-9a-f]{64}$' -or $fields.VerificationHash -cnotmatch '^[0-9a-f]{64}$') { throw "Invalid payslip posting record '$Path': missing or invalid identity, reservation or hash." } $null = Assert-LedgerSafeLeafName -Name $fields.FiscalYear -Kind 'fiscal year' if ((Split-Path $Path -Leaf) -ne (Get-LedgerPayslipFileName -PayslipNumber $payslipNumber)) { throw "Invalid payslip posting record '$Path': identity does not match its filename." } [pscustomobject]@{ OperationId = $id; PayslipNumber = $payslipNumber; FiscalYear = $fields.FiscalYear VerificationNumber = $verificationNumber; PayslipHash = $fields.PayslipHash; VerificationHash = $fields.VerificationHash } } function Get-LedgerPayslipPostingOperation { [CmdletBinding()] param ([Parameter(Mandatory)] [string]$JournalPath) $directory = Join-Path $JournalPath 'payslips' 'posting' if (-not (Test-Path -LiteralPath $directory)) { return } foreach ($file in Get-ChildItem -LiteralPath $directory -Filter 'pay*.txt' -File -ErrorAction Stop) { Read-LedgerPayslipPosting -Path $file.FullName } } function Save-LedgerPayslipPosting { [CmdletBinding()] param ( [Parameter(Mandatory)] [string]$Path, [Parameter(Mandatory)] [psobject]$Operation ) $null = New-Item -ItemType Directory -Path (Split-Path $Path -Parent) -Force -ErrorAction Stop Set-LedgerFileContent -Path $Path -NoClobber -Value @( '; PSLedger payslip posting' "FormatVersion:`t1" "OperationId:`t$($Operation.OperationId)" "PayslipNumber:`t$($Operation.PayslipNumber)" "FiscalYear:`t$($Operation.FiscalYear)" "VerificationNumber:`t$($Operation.VerificationNumber)" "PayslipHash:`t$($Operation.PayslipHash)" "VerificationHash:`t$($Operation.VerificationHash)" ) } |