How can I discover an "object access flag" that is apparently needed when deleting a Quickbooks invoice data entension using QBSDK - vb.net

I am using the QuickBooks QBFC12 SDK, and specifically, I am attempting to delete a "data extension" on an invoice in QB.
Some of the time the following VB.NET code will work, but many times it doesn't:
Dim objRequest As IMsgSetRequest
Dim objDatExtAdder As IDataExtAdd
Dim objResponse As IMsgSetResponse
Dim objOurResponse As IResponse
Dim objInvoiceQuery As IInvoiceQuery
Dim objInvoiceRetList As IInvoiceRetList
Dim objInvoiceRet As IInvoiceRet
Dim szInvoiceTxnID As String = ""
Dim objDataExtDel As IDataExtDel
' Check to see if the invoice is already on file.
objInvoiceQuery = objRequest.AppendInvoiceQueryRq
objInvoiceQuery.ORInvoiceQuery.InvoiceFilter.MaxReturned.SetValue(1)
objInvoiceQuery.IncludeLineItems.SetValue(True)
objInvoiceQuery.IncludeLinkedTxns.SetValue(True)
objInvoiceQuery.ORInvoiceQuery.InvoiceFilter.ORRefNumberFilter.RefNumberFilter.MatchCriterion.SetValue(ENMatchCriterion.mcEndsWith)
objInvoiceQuery.ORInvoiceQuery.InvoiceFilter.ORRefNumberFilter.RefNumberFilter.RefNumber.SetValue(szQBInvoiceNumber)
objResponse = objSessionManager.DoRequests(objRequest)
objOurResponse = objResponse.ResponseList.GetAt(0)
If objOurResponse.StatusCode = 0 Then
' Lock onto the invoice.
objInvoiceRetList = objOurResponse.Detail
If objInvoiceRetList.Count > 0 Then
' The invoice already exists.
objInvoiceRet = objInvoiceRetList.GetAt(0)
szInvoiceTxnID = objInvoiceRet.TxnID.GetValue
End If
End If
objRequest.ClearRequests()
' Remove any previous value.
objRequest = objSessionManager.CreateMsgSetRequest("US", 11, 0)
objRequest.Attributes.OnError = ENRqOnError.roeStop
objDataExtDel = objRequest.AppendDataExtDelRq()
objDataExtDel.OwnerID.SetValue("0")
objDataExtDel.ORListTxn.TxnDataExt.TxnDataExtType.SetValue(ENTxnDataExtType.tdetInvoice)
objDataExtDel.ORListTxn.TxnDataExt.TxnID.SetValue(szInvoiceTxnID)
objDataExtDel.DataExtName.SetValue(szDataExtensionName)
objResponse = objSessionManager.DoRequests(objRequest)
objOurResponse = objResponse.ResponseList.GetAt(0)
If objOurResponse.StatusCode = 0 Then
Debug.Print("Worked")
Else
Debug.Print("Didn't work")
End If
On the occasions where it reports "Didn't Work," objourresponse.StatusMessage returns:
The necessary QuickBooks object access flag was not set in the attribute definition for an attribute. QuickBooks error message: Unknown Error
I have tried to understand what the "Object Access Flag" is and where it can be found, and I have searched on Google and the Intuit developer's site for more information, but I can't find anything.
Can someone help with understanding what this is, how I can get past this issue, and how I can consistently delete this data extension whenever necessary?

After a LOT of trial and error, I believe I have struck on a solution.
The particular extension was part of a drop-down selector that I have displayed on the invoice. Some of the valid values are "Printed" or "Shipped". Formerly, when I went to change the value in the extension, I was first deleting the extension using AppendDataExtDelRq, then adding it back in with the new value using AppendDataExtAddRq.
I was able to get the value to change if, instead of using the delete/add combination, I used AppendDataExtModRq and simply changed the value.
I still think there is a bug in the SDK like #InteXX suspects, but I also noticed that IF I set the extension to a pre-defined value in the drop-down, then all is good. BUT, if I try to set the extension to a value that isn't pre-defined in QB for that extension/drop-down, then I get the exact same error:
The necessary QuickBooks object access flag was not set in the attribute definition for an attribute. QuickBooks error message: Unknown Error
So the upshot is that it is working now by using the MOD and not the DELETE/ADD approach, but make sure you set the value to a pre-defined value.

Related

How to avoid runtime error 5152 when trying to add a URL as shape to a Word document

I am trying to place a QR code generated through an API (api.qrserver,com) in a Word table using VBA. For certain reasons, the option of simply using "DisplayBarcode" is not possible.
This is the call to the API:
sURL = "https://api.qrserver.com/v1/create-qr-code/?data=" & UTF8_URL_Encode(VBA.Replace(QR_Value, " ", "+")) & "&size=240x240"
It seems to work well. I tried with a GET command and retrieved a string that - as I interpret - contains the QR code in png format.
Now, when I try to add the picture as a shape using
Set objGrafik = ActiveDocument.Shapes.AddPicture(sURL, True)
the call fails with runtime error 5152. As far as I could determine until now, the Addpicture method expects a pure filename and does not allow any of the following characters: /|?*<>:".
I also tried to store the GET result in an object variable:
Set oQRCode = http.responseText
but there I get the error "object required".
Research on the internet regarding a solution to either make the URL assignment work or to store the result as a picture didn't retrieve any useful results. Thanks in advance for your support
I am not sure that any of the ways you could insert something into Word (e.g. Shapes.AddPicture, InlineShapes.AddPicture, Range.InsertFile etc. will let you do that from any old https Url, although it seems to work for some Urls.
However, as it happens, you can use an INCLUDEPICTURE field to do it. FOr example
{ INCLUDEPICTURE https://api.qrserver.com/v1/create-qr-code/?data=Test&size=100x100 }
Here's some sample VBA to do that
Sub insertqrcode()
Dim sUrl As String
Dim f As Word.Field
Dim r1 As Word.Range
Dim r2 As Word.Range
' This is just a test - plug your own Url in.
sUrl = "https://api.qrserver.com/v1/create-qr-code/?data=abcdef&size=100x100"
' Pick an empty test cell in a table
Set r1 = ActiveDocument.Tables(1).Cell(5, 4).Range
' We have to remove the end of cell character to add the field to the range
' Simplify
Set r2 = r1.Duplicate
r2.Collapse WdCollapseDirection.wdCollapseStart
Set f = r2.Fields.Add(r2, WdFieldType.wdFieldIncludePicture, sUrl, False)
' If you don't want the field code any more, do this
f.Unlink
' check that we have a new inline shape that we could work with more
' if necessary
Debug.Print r1.InlineShapes.count
Set f = Nothing
Set r2 = Nothing
Set r1 = Nothing
End Sub
Using INCLUDEPICTURE works even on the current version of Mac Word (although I haven't tested that specific piece of VBA on Mac).
The only other way I have seen to do it uses WinHTTP to get the result from the web service, ADODB to stream it out to a local disk file, then AddPicture or whatever to include that file, so much more complicated and won't work on Mac either.

MS Access: "Cannot open any more databases."

The Access error, "Cannot open any more databases.", has been discussed several times on StackOverflow[1, 2, 3, 4]. There's also an interesting discussion of the error on Bytes.com, in which Allen Brown and David Fenton weigh in on what can cause the error and argue about whether the limit behind it is about connections or table handles. None of the causes or solutions in those places apply to my situation, as far as I can tell.
I've got a complex database that was working well, but then started throwing this error. I've boiled down the VBA code and data structure to the following bare bones:
Option Explicit
Public Function TestFunction(ID_test_1 As Integer, nID_test_2 As Integer) As Variant
Dim oCurDb_Ftn As DAO.Database, oTestData As DAO.Recordset, sSQL As String, vTestCode As Variant
Set oCurDb_Ftn = CurrentDb()
sSQL = "SELECT * FROM t_test_2 WHERE ID_test_2 = " & nID_test_2 & ";"
Set oTestData = oCurDb_Ftn.OpenRecordset(sSQL)
vTestCode = oTestData![bValue]
oTestData.Close
Set oTestData = Nothing
Set oCurDb_Ftn = Nothing
TestFunction = vTestCode
End Function ' TestFunction
The numbers in the tables are arbitrary. The fields ID_test_n are primary keys. The code above is the entire contents of TestModule. The query TestQuery is:
SELECT t_test_1.ID_test_1, TestFunction(ID_test_1,3) AS [Test code]
FROM t_test_1;
When the query is opened, it at first appears to be okay. But if I scroll down through it, it throws the "cannot open any more" error:
I've discovered one way that I can get rid of the error. If I remove the first parameter of the function TestFunction(), so that it's definition becomes:
Public Function TestFunction(nID_test_2 As Integer) As Variant
...
and the call to it in the query becomes just:
TestFunction(3)
then I can scroll down and up through the query sheet multiple times without error. Those changes are possible because in the bare-bones code of the function, there is no reference to ID_test_1. But in the actual database, that parameter is passed for a reason and omitting it is not an option. Still, it is mysterious to me that whatever is causing the error does not happen if that parameter is not passed.
Can anyone see what's going on here, why I'm getting that error, and how to fix it without excluding parameters from the function?
Environment: Windows 10 Pro 64-bit, Access 2019.
This may be due to a bug in an Office update, about Jan 26, 2022. See Reddit post
Try system restore to roll back the update; or...
Go into Access, File Options, Trust center and add the local front end directory and then check the box to then add the backend data location as a trusted location.

Word automation failing on server, but dev station works great

I am automating a oft-used paper form by querying the user on a web page, then modifying a base Word document and feeding that modified doc file to the user's browser for hand-off to Word.
The code is Visual Basic, and I am using the Microsoft.Office.Interop module to manipulate the document by manipulating Word. Works fine on the development system (Visual Studio 2015) but not on the production server (IIS 8.5).
Both the Documents.Open() call and the doc.SaveAs() call fail with Message="Command failed" Source="Microsoft Word" HResult=0x800A1066
Things I've tried:
Added debugging out the whazoo: Single-stepping is not an option on the production machine, so I pinpointed the problem lines with debug output.
Googled and found that this problem has been reported as early as 2007, but no viable solutions were reported.
A couple sites mentioned timing issues, so I added several pauses and retries -- none helped.
Some mentioned privileging, so I tried changing file permissions & application pool users -- neither helped.
Enhanced my exception handling reports to show more details and include all inner exceptions. That yielded the magic number 800A1066 which led to many more google hits, but no answers.
Added fall-back code: if you can't open the main document, create a simple one. That's when I found the SaveAs() call also failing.
Dropped back to the development system several times to confirm that yes, the code does still work properly in the right environment.
Greatly condensed sample code does not include fallback logic. My Word document has a number of fields whose names match the XML tokens passed as parameters into this function. saveFields() is an array of those names.
Dim oWord As Word.Application
Dim oDoc As Word.Document
oWord = CreateObject("Word.Application")
oWord.Visible = True
oDoc = oWord.Documents.Open(docName)
Dim ev As String
For i = 0 To saveFields.Length - 1
Try
ev = dataXD.Elements(saveFields(i))(0).Value
Catch
ev = Nothing
End Try
If ev IsNot Nothing Then
Try
Dim field = oDoc.FormFields(saveFields(i))
If field IsNot Nothing Then
If field.Type = Word.WdFieldType.wdFieldFormTextInput Then
field.Result = ev
End If
End If
Catch e As Exception
ErrorOut("Caught exception! " & e.Message)
End Try
End If
Next
...
oDoc.SaveAs2(localDir & filename)
oDoc.Close()
oWord.Quit(0, 0, 0)
The code should generate a modified form (fields filled in with data from the parameters); instead it fails to open, and the fallback code fails to save the new document.
On my dev system the document gets modified as it should, and if I break at the right place and change the right variable, the fallback code runs and generates the alternate document successfully -- but on the production server both paths fail with the same error.
Barring any better answers here, my next steps are to examine and use OpenXML and/or DocX, but making a few changes to the existing code is far preferable to picking a new tool and starting over from scratch.
Unfortunately, Lex Li was absolutely correct, and of course, the link to the reason why is posted on a site my company considers off limits, thus never showed up in my google searches prior to coding this out.
None of the tools I tried were able to handle the form I was trying to automate either -- I needed to fill in named fields and check/uncheck checkboxes, abilities which seemed beyond (or terribly convoluted in) the tools I evaluated ...
Eventually I dug into the document.xml format myself; I developed a function to modify the XML to check a named checkbox, and manipulated the raw document.xml to replace text fields with *-delimited token names. This reduced all of the necessary changes to simple string manipulation -- the rest was trivial.
The tool is 100% home-grown, not dependent upon any non-System libraries and works 100% for this particular form. It is not a generic solution by any stretch, and I suspect the document.xml file will need manual changes if and when the document is ever revised.
But for this particular problem -- it is a solution.
This was the closest I got to a complicated part. This function will check (but not uncheck) a named checkbox from a document.xml if the given condition is true.
Private Shared Function markCheckbox(xmlString As String, cbName As String, checkValue As Boolean) As String
markCheckbox = xmlString
If checkValue Then ' Checkbox needs to be checked, proceed
Dim pos As Integer = markCheckbox.IndexOf("<w:ffData><w:name w:val=""" & cbName & """/>")
If pos > -1 Then ' We have a checkbox
Dim endPos As Integer = markCheckbox.IndexOf("</w:ffData>", pos+1)
Dim cbEnd As Integer = markCheckbox.IndexOf("</w:checkBox>", pos+1)
If endPos > cbEnd AndAlso cbEnd > -1 Then ' Have found the appropriate w:ffData element (pos -> endPos) and the included insert point (cbEnd)
markCheckbox = markCheckbox.Substring(0, cbEnd) & "<w:checked/>" & markCheckbox.Substring(cbEnd)
End If
' Any other logic conditions, return the original XML string unmangled.
End If
End If
End Function

Retrieve Lotus Notes Domino directoy groups and users

Using Studio 2013 VB.
I am attempting to retrieve group members from our Lotus Notes Domino directory - but I cannot get past this error: "A protocol error occurred. Failed, invalid authentication method specified." I was assuming (maybe incorrectly) that this could be done using DirectorySearcher as we do for our Active Directory.
I have tried retrieving various data with the same results. My research seems to indicate a problem with the ldapsettings but I am using the same alias and specific ldapsettings used by other in-house scripts (albeit written in perl). So the ldapsettings still might be the problem.
The line of code that fails is:
Dim result As SearchResult = searcher.FindOne
The value of searcher.Filter is (&(objectclass=dominoGroup)(cn=mydominogroup))
So this looks like it is build right.
Any help with errors in my code - or even suggestions to accomplish this task a better way are appreciated.
Here is my code:
dim grp as String = "mydominogroup"
Using dEntry As New DirectoryEntry("LDAP://mycompanyldapsettings")
dEntry.Username = myadminaccount
dEntry.Password = myadminpassword
Using searcher As New DirectorySearcher(dEntry)
searcher.Filter = String.Format("(&(objectclass=dominoGroup)(cn={0}))", grp)
Dim result As SearchResult = searcher.FindOne <--fails here
If result Is Nothing Then
"report group not found"
Else
Dim members As Object = result.GetDirectoryEntry.Invoke("Members", Nothing)
If members Is Nothing Then
"report no members found in group"
Else
For Each member As Object In CType(members, IEnumerable)
Dim currentMember As New DirectoryEntry(member)
If currentMember.SchemaClassName.ToLower = "user" Then
Dim props As PropertyCollection = currentMember.Properties
"get and list the user pros("someattribute").Value)"
End If
Next
End If
End If
End Using
End Using
Decided to call an external Process to solve this.

is there a way to query IEmployeePayrollInfo with QuickBooks SDK?

I am starting to work with the QuickBooks SDK, and so far I am able to query Employees no problem, like so:
_sessionManager.OpenConnection("", "<software>")
_sessionManager.BeginSession("", ENOpenMode.omDontCare)
Dim requestSet As IMsgSetRequest = GetLatestMsgSetRequest(_sessionManager)
' Initialize the message set request object
requestSet.Attributes.OnError = ENRqOnError.roeStop
Dim empQuery As IEmployeeQuery = requestSet.AppendEmployeeQueryRq()
' Do the request and get the response message set object
Dim responseSet As IMsgSetResponse = _sessionManager.DoRequests(requestSet)
Dim response As IResponse = responseSet.ResponseList.GetAt(0)
Dim empRetList As IEmployeeRetList = response.Detail
....
_sessionManager.EndSession()
_sessionManager.CloseConnection()
Which will give me a list of employees which I can iterate through. This works well for the basic employee data, such as name, date of birth, etc. but there is a EmployeePayrollInfo property that does not seem to be returned with the IEmployeeQuery.
I see that there is an interface IEmployeePayrollInfo but I have not as yet been able to figure out if there is a way to query it. I see that there are report related payroll info queries, but I am trying to query the EmployeePayrollInfo directly, to retrieve the vacation information. Is this something that can be done with QBFC?
EDIT
I was able to get this working, see accepted answer below.
Open Quickbooks.
Go to the Edit menu and click Preferences.
In the Preferences window, click Integrated Applications in the list on the left.
Click the Company Preferences tab.
Select the application with which you are connecting to QuickBooks.
Click Properties.
Check "Allow this application to access Social Security Numbers, customer credit card information, and other personal data"
The employee data should now include EmployeePayrollInfo. Please comment if this does not work.
For anyone searching for the same functionality, the only information I was able to find seems to indicate that Intuit has specifically excluded this functionality from the QuickBooks SDK for security reasons. What we ended up doing to solve our problem is create a custom report in QuickBooks that included all of the information that we needed, exported it as a CSV file, and then import it accordingly in our software. Same end result, but a couple more steps than we were originally hoping for. Hopefully Intuit will change their mind about excluding this from the SDK.
UPDATE
I have finally been able to query the EmployeePayrollInfo, what was needed was adding "EmployeePayrollInfo" to the query itself like so:
empQuery.IncludeRetElementList.Add("EmployeePayrollInfo")
So now the code looks like this:
Dim sessionManager As New QBSessionManager
sessionManager.OpenConnection2("", "<software>", ENConnectionType.ctLocalQBD)
sessionManager.BeginSession("", ENOpenMode.omDontCare)
Dim requestSet As IMsgSetRequest = sessionManager.CreateMsgSetRequest("US", 12, 0)
requestSet.Attributes.OnError = ENRqOnError.roeStop
Dim empQuery As IEmployeeQuery = requestSet.AppendEmployeeQueryRq()
empQuery.IncludeRetElementList.Add("EmployeePayrollInfo") ' this line did the trick!
Dim responseSet As IMsgSetResponse = sessionManager.DoRequests(requestSet)
Dim response As IResponse = responseSet.ResponseList.GetAt(0)
Dim empRetList As IEmployeeRetList = response.Detail
If empRetList.Count > 0 Then
For i As Integer = 0 To empRetList.Count - 1
Dim emp As IEmployeeRet = empRetList.GetAt(i)
If emp IsNot Nothing Then
' do something with the queried data
End If
Next
End If
sessionManager.EndSession()
sessionManager.CloseConnection()