Excel desktop POC: direct SQL via VBA, safe mode launcher
- 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>
This commit is contained in:
@@ -1,28 +1,36 @@
|
||||
Attribute VB_Name = "GLAccountsExcelApi"
|
||||
Option Explicit
|
||||
|
||||
' Finaccount-like Excel API POC for GL ACCOUNTS FUNCTIONS.
|
||||
' 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.
|
||||
' 5. Edit GL_API_CONNECTION_STRING below (or use a named DSN).
|
||||
'
|
||||
' Example:
|
||||
' =GetAccountAmount("COMPANY01","400000","USD",DATE(2026,5,31))
|
||||
' 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=localhost;" & _
|
||||
"Server=vps107.geneva.hosting;" & _
|
||||
"Port=5432;" & _
|
||||
"Database=tradon;" & _
|
||||
"Uid=tradon_readonly;" & _
|
||||
"Pwd=change_me;"
|
||||
"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
|
||||
@@ -35,6 +43,8 @@ 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
|
||||
@@ -62,15 +72,87 @@ Public Sub CloseGLApiConnection()
|
||||
Set gConnection = Nothing
|
||||
End Sub
|
||||
|
||||
Private Function SqlDate(ByVal valueDate As Variant) As String
|
||||
SqlDate = Format$(CDate(valueDate), "yyyy-mm-dd")
|
||||
End Function
|
||||
' ---- Main macro ----
|
||||
|
||||
Private Function SqlText(ByVal value As Variant) As String
|
||||
SqlText = Replace(CStr(value), "'", "''")
|
||||
End Function
|
||||
' 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
|
||||
|
||||
Private Function QueryScalar( _
|
||||
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, _
|
||||
@@ -84,7 +166,7 @@ Private Function QueryScalar( _
|
||||
& "|" & CStr(currencyIso) & "|" & SqlDate(valueDate)
|
||||
|
||||
If ApiCache.Exists(key) Then
|
||||
QueryScalar = ApiCache(key)
|
||||
RunQuery = ApiCache(key)
|
||||
Exit Function
|
||||
End If
|
||||
|
||||
@@ -102,13 +184,13 @@ RetryQuery:
|
||||
rs.Open sql, DbConnection, 0, 1
|
||||
|
||||
If rs.EOF Or IsNull(rs.Fields(0).Value) Then
|
||||
QueryScalar = Empty
|
||||
RunQuery = Empty
|
||||
Else
|
||||
QueryScalar = rs.Fields(0).Value
|
||||
RunQuery = rs.Fields(0).Value
|
||||
End If
|
||||
rs.Close
|
||||
|
||||
ApiCache.Add key, QueryScalar
|
||||
ApiCache.Add key, RunQuery
|
||||
Exit Function
|
||||
|
||||
ErrorHandler:
|
||||
@@ -120,16 +202,41 @@ ErrorHandler:
|
||||
ResetDbConnection
|
||||
Resume RetryQuery
|
||||
End If
|
||||
QueryScalar = "#ERR " & Err.Number & ": " & Err.Description
|
||||
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
|
||||
GetAccountBaseAmount = QueryScalar("get_account_base_amount", _
|
||||
companyKey, accountCode, currencyIso, valueDate)
|
||||
If Not gApiEnabled Then GetAccountBaseAmount = "#GLAPI_OFF": Exit Function
|
||||
GetAccountBaseAmount = RunQuery("get_account_base_amount", companyKey, accountCode, currencyIso, valueDate)
|
||||
End Function
|
||||
|
||||
Public Function GetAccountRealBaseAmount( _
|
||||
@@ -137,8 +244,8 @@ Public Function GetAccountRealBaseAmount( _
|
||||
ByVal accountCode As Variant, _
|
||||
ByVal currencyIso As Variant, _
|
||||
ByVal valueDate As Variant) As Variant
|
||||
GetAccountRealBaseAmount = QueryScalar("get_account_real_base_amount", _
|
||||
companyKey, accountCode, currencyIso, valueDate)
|
||||
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( _
|
||||
@@ -146,8 +253,8 @@ Public Function GetAccountAmount( _
|
||||
ByVal accountCode As Variant, _
|
||||
ByVal currencyIso As Variant, _
|
||||
ByVal valueDate As Variant) As Variant
|
||||
GetAccountAmount = QueryScalar("get_account_amount", _
|
||||
companyKey, accountCode, currencyIso, valueDate)
|
||||
If Not gApiEnabled Then GetAccountAmount = "#GLAPI_OFF": Exit Function
|
||||
GetAccountAmount = RunQuery("get_account_amount", companyKey, accountCode, currencyIso, valueDate)
|
||||
End Function
|
||||
|
||||
Public Function GetAccountAbbr( _
|
||||
@@ -155,8 +262,8 @@ Public Function GetAccountAbbr( _
|
||||
ByVal accountCode As Variant, _
|
||||
ByVal currencyIso As Variant, _
|
||||
ByVal valueDate As Variant) As Variant
|
||||
GetAccountAbbr = QueryScalar("get_account_abbr", _
|
||||
companyKey, accountCode, currencyIso, valueDate)
|
||||
If Not gApiEnabled Then GetAccountAbbr = "#GLAPI_OFF": Exit Function
|
||||
GetAccountAbbr = RunQuery("get_account_abbr", companyKey, accountCode, currencyIso, valueDate)
|
||||
End Function
|
||||
|
||||
Public Function GetAccountName( _
|
||||
@@ -164,8 +271,8 @@ Public Function GetAccountName( _
|
||||
ByVal accountCode As Variant, _
|
||||
ByVal currencyIso As Variant, _
|
||||
ByVal valueDate As Variant) As Variant
|
||||
GetAccountName = QueryScalar("get_account_name", _
|
||||
companyKey, accountCode, currencyIso, valueDate)
|
||||
If Not gApiEnabled Then GetAccountName = "#GLAPI_OFF": Exit Function
|
||||
GetAccountName = RunQuery("get_account_name", companyKey, accountCode, currencyIso, valueDate)
|
||||
End Function
|
||||
|
||||
Public Function GetAccountContact( _
|
||||
@@ -173,6 +280,24 @@ Public Function GetAccountContact( _
|
||||
ByVal accountCode As Variant, _
|
||||
ByVal currencyIso As Variant, _
|
||||
ByVal valueDate As Variant) As Variant
|
||||
GetAccountContact = QueryScalar("get_account_contact", _
|
||||
companyKey, accountCode, currencyIso, valueDate)
|
||||
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
|
||||
|
||||
Reference in New Issue
Block a user