- GLAccountsExcelApi.bas: RefreshGLApi reads Setup!B6:B9 directly, calls PostgreSQL via ADODB without sheet.Evaluate or live UDF formulas - Connection string pointed to vps107.geneva.hosting / postgres - GL_Accounts_Client_Template.xlsx: fixed formula text cell refs (B6 not B7) - Ouvrir_Excel_SafeMode.bat: launches Excel /safe with template to bypass print spooler freeze (splwow64 deadlock on edit mode entry) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
304 lines
10 KiB
QBasic
304 lines
10 KiB
QBasic
Attribute VB_Name = "GLAccountsExcelApi"
|
|
Option Explicit
|
|
|
|
' Excel API POC for GL ACCOUNTS FUNCTIONS.
|
|
'
|
|
' Setup:
|
|
' 1. Install PostgreSQL ODBC driver.
|
|
' 2. Apply notes/accounting/excel_api/gl_accounts_sql_poc.sql.
|
|
' 3. In Excel: Developer > Visual Basic > File > Import File...
|
|
' 4. Import this .bas module.
|
|
' 5. Edit GL_API_CONNECTION_STRING below (or use a named DSN).
|
|
'
|
|
' Usage:
|
|
' - On the Setup sheet, fill in B6 (company), B7 (account), B8 (currency), B9 (date).
|
|
' - Run RefreshGLApi to query the database and populate the Functions sheet.
|
|
' - Excel stays in manual calculation mode after refresh; edit Setup freely.
|
|
'
|
|
' DSN example:
|
|
' "DSN=TradonGLApi;Uid=tradon_readonly;Pwd=change_me;"
|
|
|
|
Private Const GL_API_CONNECTION_STRING As String = _
|
|
"Driver={PostgreSQL Unicode(x64)};" & _
|
|
"Server=vps107.geneva.hosting;" & _
|
|
"Port=5432;" & _
|
|
"Database=tradon;" & _
|
|
"Uid=postgres;" & _
|
|
"Pwd=dsproject;"
|
|
|
|
Private gConnection As Object
|
|
Private gCache As Object
|
|
Private gApiEnabled As Boolean
|
|
|
|
' ---- Connection helpers ----
|
|
|
|
Private Function ApiCache() As Object
|
|
If gCache Is Nothing Then
|
|
Set gCache = CreateObject("Scripting.Dictionary")
|
|
End If
|
|
Set ApiCache = gCache
|
|
End Function
|
|
|
|
Private Function DbConnection() As Object
|
|
If gConnection Is Nothing Then
|
|
Set gConnection = CreateObject("ADODB.Connection")
|
|
gConnection.ConnectionString = GL_API_CONNECTION_STRING
|
|
gConnection.ConnectionTimeout = 5
|
|
gConnection.CommandTimeout = 30
|
|
gConnection.Open
|
|
ElseIf gConnection.State = 0 Then
|
|
gConnection.Open
|
|
End If
|
|
Set DbConnection = gConnection
|
|
End Function
|
|
|
|
Private Sub ResetDbConnection()
|
|
On Error Resume Next
|
|
If Not gConnection Is Nothing Then
|
|
If gConnection.State <> 0 Then gConnection.Close
|
|
End If
|
|
Set gConnection = Nothing
|
|
On Error GoTo 0
|
|
End Sub
|
|
|
|
Public Sub ClearGLApiCache()
|
|
If Not gCache Is Nothing Then gCache.RemoveAll
|
|
End Sub
|
|
|
|
Public Sub CloseGLApiConnection()
|
|
If Not gConnection Is Nothing Then
|
|
If gConnection.State <> 0 Then gConnection.Close
|
|
End If
|
|
Set gConnection = Nothing
|
|
End Sub
|
|
|
|
' ---- Main macro ----
|
|
|
|
' Reads Setup!B6:B9, queries the database directly, writes plain values to Functions!C6:C13.
|
|
' Excel stays in xlCalculationManual after this runs -- edit Setup cells freely,
|
|
' then run RefreshGLApi again when you want fresh results.
|
|
Public Sub RefreshGLApi()
|
|
Dim wsSetup As Worksheet
|
|
Dim wsFunctions As Worksheet
|
|
|
|
On Error Resume Next
|
|
Set wsSetup = ThisWorkbook.Worksheets("Setup")
|
|
Set wsFunctions = ThisWorkbook.Worksheets("Functions")
|
|
On Error GoTo 0
|
|
|
|
If wsSetup Is Nothing Then
|
|
MsgBox "Sheet 'Setup' not found.", vbExclamation
|
|
Exit Sub
|
|
End If
|
|
If wsFunctions Is Nothing Then
|
|
MsgBox "Sheet 'Functions' not found.", vbExclamation
|
|
Exit Sub
|
|
End If
|
|
|
|
Application.EnableEvents = False
|
|
Application.ScreenUpdating = False
|
|
Application.Calculation = xlCalculationManual
|
|
|
|
Dim company As String
|
|
Dim account As String
|
|
Dim currency As String
|
|
Dim valueDate As Variant
|
|
|
|
company = CStr(wsSetup.Range("B6").Value)
|
|
account = CStr(wsSetup.Range("B7").Value)
|
|
currency = CStr(wsSetup.Range("B8").Value)
|
|
valueDate = wsSetup.Range("B9").Value
|
|
|
|
ClearGLApiCache
|
|
|
|
On Error GoTo RefreshError
|
|
|
|
wsFunctions.Range("C6").Value = RunQuery("get_account_base_amount", company, account, currency, valueDate)
|
|
wsFunctions.Range("C7").Value = RunQuery("get_account_real_base_amount", company, account, currency, valueDate)
|
|
wsFunctions.Range("C8").Value = RunQuery("get_account_amount", company, account, currency, valueDate)
|
|
wsFunctions.Range("C9").Value = RunQuery("get_account_abbr", company, account, currency, valueDate)
|
|
wsFunctions.Range("C10").Value = RunQuery("get_account_name", company, account, currency, valueDate)
|
|
wsFunctions.Range("C11").Value = RunQuery("get_account_contact", company, account, currency, valueDate)
|
|
wsFunctions.Range("C12").Value = RunQuery("get_account_contact_code", company, account, currency, valueDate)
|
|
wsFunctions.Range("C13").Value = RunQuery("get_account_contact_name", company, account, currency, valueDate)
|
|
|
|
CloseGLApiConnection
|
|
GoTo RefreshDone
|
|
|
|
RefreshError:
|
|
MsgBox "RefreshGLApi error: " & Err.Description, vbExclamation
|
|
|
|
RefreshDone:
|
|
Application.ScreenUpdating = True
|
|
Application.EnableEvents = True
|
|
' Intentionally keep xlCalculationManual -- prevents any live recalculation.
|
|
End Sub
|
|
|
|
' Resets Functions!C6:C13 to placeholder text.
|
|
Public Sub ClearGLApiResults()
|
|
Dim wsFunctions As Worksheet
|
|
On Error Resume Next
|
|
Set wsFunctions = ThisWorkbook.Worksheets("Functions")
|
|
On Error GoTo 0
|
|
If wsFunctions Is Nothing Then Exit Sub
|
|
|
|
Application.EnableEvents = False
|
|
Dim r As Long
|
|
For r = 6 To 13
|
|
wsFunctions.Cells(r, 3).Value = "-"
|
|
Next r
|
|
Application.EnableEvents = True
|
|
End Sub
|
|
|
|
' ---- Core SQL runner ----
|
|
|
|
Private Function RunQuery( _
|
|
ByVal functionName As String, _
|
|
ByVal companyKey As Variant, _
|
|
ByVal accountCode As Variant, _
|
|
ByVal currencyIso As Variant, _
|
|
ByVal valueDate As Variant) As Variant
|
|
|
|
On Error GoTo ErrorHandler
|
|
|
|
Dim key As String
|
|
key = functionName & "|" & CStr(companyKey) & "|" & CStr(accountCode) _
|
|
& "|" & CStr(currencyIso) & "|" & SqlDate(valueDate)
|
|
|
|
If ApiCache.Exists(key) Then
|
|
RunQuery = ApiCache(key)
|
|
Exit Function
|
|
End If
|
|
|
|
Dim sql As String
|
|
sql = "select excel_api." & functionName & "('" _
|
|
& SqlText(companyKey) & "','" _
|
|
& SqlText(accountCode) & "','" _
|
|
& SqlText(currencyIso) & "','" _
|
|
& SqlDate(valueDate) & "'::date)"
|
|
|
|
Dim rs As Object
|
|
Dim attempt As Integer
|
|
RetryQuery:
|
|
Set rs = CreateObject("ADODB.Recordset")
|
|
rs.Open sql, DbConnection, 0, 1
|
|
|
|
If rs.EOF Or IsNull(rs.Fields(0).Value) Then
|
|
RunQuery = Empty
|
|
Else
|
|
RunQuery = rs.Fields(0).Value
|
|
End If
|
|
rs.Close
|
|
|
|
ApiCache.Add key, RunQuery
|
|
Exit Function
|
|
|
|
ErrorHandler:
|
|
If attempt = 0 Then
|
|
attempt = 1
|
|
If Not rs Is Nothing Then
|
|
If rs.State <> 0 Then rs.Close
|
|
End If
|
|
ResetDbConnection
|
|
Resume RetryQuery
|
|
End If
|
|
RunQuery = "#ERR " & Err.Number & ": " & Err.Description
|
|
End Function
|
|
|
|
Private Function SqlDate(ByVal valueDate As Variant) As String
|
|
SqlDate = Format$(CDate(valueDate), "yyyy-mm-dd")
|
|
End Function
|
|
|
|
Private Function SqlText(ByVal value As Variant) As String
|
|
SqlText = Replace(CStr(value), "'", "''")
|
|
End Function
|
|
|
|
' ---- UDF functions (optional, for manual formula use) ----
|
|
'
|
|
' These functions are NOT called by RefreshGLApi.
|
|
' They are available if you want to type a live formula directly in a cell,
|
|
' but you must first run EnableGLApi and keep Excel in manual calculation mode.
|
|
' Warning: live UDF formulas in cells can freeze Excel on recalculation.
|
|
|
|
Public Sub EnableGLApi()
|
|
gApiEnabled = True
|
|
Application.Calculation = xlCalculationManual
|
|
End Sub
|
|
|
|
Public Sub DisableGLApi()
|
|
gApiEnabled = False
|
|
CloseGLApiConnection
|
|
End Sub
|
|
|
|
Public Function GetAccountBaseAmount( _
|
|
ByVal companyKey As Variant, _
|
|
ByVal accountCode As Variant, _
|
|
ByVal currencyIso As Variant, _
|
|
ByVal valueDate As Variant) As Variant
|
|
If Not gApiEnabled Then GetAccountBaseAmount = "#GLAPI_OFF": Exit Function
|
|
GetAccountBaseAmount = RunQuery("get_account_base_amount", companyKey, accountCode, currencyIso, valueDate)
|
|
End Function
|
|
|
|
Public Function GetAccountRealBaseAmount( _
|
|
ByVal companyKey As Variant, _
|
|
ByVal accountCode As Variant, _
|
|
ByVal currencyIso As Variant, _
|
|
ByVal valueDate As Variant) As Variant
|
|
If Not gApiEnabled Then GetAccountRealBaseAmount = "#GLAPI_OFF": Exit Function
|
|
GetAccountRealBaseAmount = RunQuery("get_account_real_base_amount", companyKey, accountCode, currencyIso, valueDate)
|
|
End Function
|
|
|
|
Public Function GetAccountAmount( _
|
|
ByVal companyKey As Variant, _
|
|
ByVal accountCode As Variant, _
|
|
ByVal currencyIso As Variant, _
|
|
ByVal valueDate As Variant) As Variant
|
|
If Not gApiEnabled Then GetAccountAmount = "#GLAPI_OFF": Exit Function
|
|
GetAccountAmount = RunQuery("get_account_amount", companyKey, accountCode, currencyIso, valueDate)
|
|
End Function
|
|
|
|
Public Function GetAccountAbbr( _
|
|
ByVal companyKey As Variant, _
|
|
ByVal accountCode As Variant, _
|
|
ByVal currencyIso As Variant, _
|
|
ByVal valueDate As Variant) As Variant
|
|
If Not gApiEnabled Then GetAccountAbbr = "#GLAPI_OFF": Exit Function
|
|
GetAccountAbbr = RunQuery("get_account_abbr", companyKey, accountCode, currencyIso, valueDate)
|
|
End Function
|
|
|
|
Public Function GetAccountName( _
|
|
ByVal companyKey As Variant, _
|
|
ByVal accountCode As Variant, _
|
|
ByVal currencyIso As Variant, _
|
|
ByVal valueDate As Variant) As Variant
|
|
If Not gApiEnabled Then GetAccountName = "#GLAPI_OFF": Exit Function
|
|
GetAccountName = RunQuery("get_account_name", companyKey, accountCode, currencyIso, valueDate)
|
|
End Function
|
|
|
|
Public Function GetAccountContact( _
|
|
ByVal companyKey As Variant, _
|
|
ByVal accountCode As Variant, _
|
|
ByVal currencyIso As Variant, _
|
|
ByVal valueDate As Variant) As Variant
|
|
If Not gApiEnabled Then GetAccountContact = "#GLAPI_OFF": Exit Function
|
|
GetAccountContact = RunQuery("get_account_contact", companyKey, accountCode, currencyIso, valueDate)
|
|
End Function
|
|
|
|
Public Function GetAccountContactCode( _
|
|
ByVal companyKey As Variant, _
|
|
ByVal accountCode As Variant, _
|
|
ByVal currencyIso As Variant, _
|
|
ByVal valueDate As Variant) As Variant
|
|
If Not gApiEnabled Then GetAccountContactCode = "#GLAPI_OFF": Exit Function
|
|
GetAccountContactCode = RunQuery("get_account_contact_code", companyKey, accountCode, currencyIso, valueDate)
|
|
End Function
|
|
|
|
Public Function GetAccountContactName( _
|
|
ByVal companyKey As Variant, _
|
|
ByVal accountCode As Variant, _
|
|
ByVal currencyIso As Variant, _
|
|
ByVal valueDate As Variant) As Variant
|
|
If Not gApiEnabled Then GetAccountContactName = "#GLAPI_OFF": Exit Function
|
|
GetAccountContactName = RunQuery("get_account_contact_name", companyKey, accountCode, currencyIso, valueDate)
|
|
End Function
|