# Sets the CBS business date - the date Fineract stamps on every transaction. # # The business date is NOT the computer clock. It lives in m_business_date and only moves when # something advances it, so it drifts behind real time and transactions keep landing on the old day. # That drift is what makes a Demand Draft dated today look like a future date, and what stops the # day's interest from accruing. # # Usage (from the backend folder): # .\set-business-date.ps1 # today # .\set-business-date.ps1 2026-09-10 # a specific day, for testing # .\set-business-date.ps1 +1 # move forward one day # .\set-business-date.ps1 -1 # move back one day # .\set-business-date.ps1 -Show # just show what it is now # # Restart is NOT needed: the date is read per request. param( [Parameter(Position = 0)] [string]$Date = '', [switch]$Show ) $ErrorActionPreference = 'Stop' # Same defaults as application.properties; override with env vars if your setup differs. $PgHost = if ($env:FINERACT_DEFAULT_TENANTDB_HOSTNAME) { $env:FINERACT_DEFAULT_TENANTDB_HOSTNAME } else { 'localhost' } $PgPort = if ($env:FINERACT_DEFAULT_TENANTDB_PORT) { $env:FINERACT_DEFAULT_TENANTDB_PORT } else { '5432' } $PgUser = if ($env:FINERACT_DEFAULT_TENANTDB_UID) { $env:FINERACT_DEFAULT_TENANTDB_UID } else { 'postgres' } $PgDb = if ($env:FINERACT_DEFAULT_TENANTDB_NAME) { $env:FINERACT_DEFAULT_TENANTDB_NAME } else { 'fineract_default' } if (-not $env:PGPASSWORD) { if ($env:FINERACT_DEFAULT_TENANTDB_PWD) { $env:PGPASSWORD = $env:FINERACT_DEFAULT_TENANTDB_PWD } else { Write-Host "Set PGPASSWORD (or FINERACT_DEFAULT_TENANTDB_PWD) first:" -ForegroundColor Yellow Write-Host ' $env:PGPASSWORD = "your-db-password"' -ForegroundColor Yellow exit 1 } } $psql = Get-Command psql -ErrorAction SilentlyContinue if ($psql) { $psqlExe = $psql.Source } else { $psqlExe = Get-ChildItem 'C:\Program Files\PostgreSQL\*\bin\psql.exe' -ErrorAction SilentlyContinue | Sort-Object FullName -Descending | Select-Object -First 1 -ExpandProperty FullName } if (-not $psqlExe) { Write-Host "psql.exe not found. Install the PostgreSQL client or add it to PATH." -ForegroundColor Red exit 1 } function Invoke-Psql([string]$Sql) { & $psqlExe -h $PgHost -p $PgPort -U $PgUser -d $PgDb -A -F'|' -t -c $Sql if ($LASTEXITCODE -ne 0) { throw "psql failed (exit $LASTEXITCODE)" } } function Show-Current { $rows = Invoke-Psql "SELECT type || ' = ' || date FROM m_business_date ORDER BY type;" $rows | Where-Object { $_ -and $_.Trim() } | ForEach-Object { Write-Host " $($_.Trim())" } $enabled = (Invoke-Psql "SELECT enabled FROM c_configuration WHERE name = 'enable-business-date';") -join '' if ($enabled.Trim() -ne 't') { Write-Host " (enable-business-date is OFF, so the real clock is used and this date is ignored)" -ForegroundColor DarkGray } } if ($Show -or $Date -eq '-Show') { Write-Host "`nCurrent business date:" -ForegroundColor Cyan Show-Current Write-Host '' exit 0 } # Work out the target date. if ($Date -eq '') { $targetSql = 'CURRENT_DATE' $label = "today ($(Get-Date -Format 'yyyy-MM-dd'))" } elseif ($Date -match '^[+-][0-9]+$') { $days = [int]$Date $targetSql = "(SELECT date + $days FROM m_business_date WHERE type = 'BUSINESS_DATE')" $label = "$(if ($days -ge 0) { "+$days" } else { $days }) day(s) from the current business date" } elseif ($Date -match '^\d{4}-\d{2}-\d{2}$') { try { [datetime]::ParseExact($Date, 'yyyy-MM-dd', $null) | Out-Null } catch { Write-Host "Not a real date: $Date" -ForegroundColor Red; exit 1 } $targetSql = "DATE '$Date'" $label = $Date } else { Write-Host "Bad argument: '$Date'. Use yyyy-MM-dd, +N, -N, or nothing for today." -ForegroundColor Red exit 1 } Write-Host "`nBefore:" -ForegroundColor Cyan Show-Current # COB_DATE moves with BUSINESS_DATE: leaving it behind makes close-of-business work on a day that # has already passed, which reads as a stuck batch rather than a date setting. Invoke-Psql "UPDATE m_business_date SET date = $targetSql WHERE type IN ('BUSINESS_DATE', 'COB_DATE');" | Out-Null Write-Host "`nAfter ($label):" -ForegroundColor Green Show-Current Write-Host "`nNo restart needed - the next request picks this up.`n" -ForegroundColor DarkGray