jsgoupil/quickbooks-sync

Support QBXml 14.

jsgoupil opened this issue · 11 comments

The new version is out and the difference can be found here:

https://static.developer.intuit.com/resources/ReleaseNotes_QBXMLSDK_14_0.pdf

The main things we should fix is to add the QBXml 14 Schema. change the VERSION to 14. Update the Objects.

And potentially fix the issue they mention here

In a VehicleMileageQuery, if you specify time values (for example, 2002-06-05T10:21:10) in any of the date range filters, you get a statuscode error 3020 statusSeverity="Error" statusMessage="There was an error when converting the date value...”
The reason for this is that Vehicle Mileage supports only Date values, not DateTime values, despite what the OSR says. The
workaround is to use only date values, as follows: 2002-06-05.

Meanwile schema 16 has been released, would it be an idea to upgrade? I did a quick compare and it doesn't seem like a lot of breaking changes, just new fields.

I understand, I think the concept here is that do we want to support older version as we go forward? probably not because the library is not "big enough"
So I think we can say if you bring in QbXML 16 then it's a hard "dependency" on the version.

According to QB the qbXML spec is backwards compatible: https://developer.intuit.com/app/developer/qbdesktop/docs/get-started/sdk-compatibility-with-quickbooks-releases

I can't speak for other users, but all our customers, about 75, are using at least QB2022+, I'm not sure if there is a compelling reason to even support older versions of the SDK as older versions of QB would miss critical tax upgrades and stuff.

You would be surprised! Some people are using it very much just to keep a book of in/outs.
I have a good 25% of people still on 2019 for me.
So the thing to do would be to update these XML, regenerate the Objects and add a QbXML override support.

Are you able to share these XML? Somehow, I tried to download 2023 on NFR and it's just not working, the auth doesn't work.

Yes for sure, I had to pull them out the QB16 SDK too.
QBSDK16 XML.zip

Let me know if you want me to share the complete 16 SDK.

I'll work on this today.
Do you have the path where you download this usually? or is it part of the QB2023?

I get it from here:
https://developer.intuit.com/app/developer/qbdesktop/docs/get-started/download-and-install-the-sdk
You will need an account, don't think you need a specific type of account.

This is a direct link to the latest version:
https://developer.intuit.com/app/developer/logged-in-content/QBSDK160_x64.exe

Since the VERSION field is static and public on QbXmlRequest at the moment, could we just pass it in directly?

public virtual async Task<string?> SendXMLAsync(IAuthenticatedTicket authenticatedTicket)
{
    var requestObject = await CreateRequestAsync(authenticatedTicket);
    if (requestObject != null)
    {
        if (await ExecuteRequestAsync(authenticatedTicket, requestObject))
        {
            var qbXmlRequest = new QbXmlRequest(QbXmlRequest.VERSION);
            qbXmlRequest.AddToSingle(requestObject);

            return qbXmlRequest.GetRequest();
        }
    }

    return null;
}

Edit: Oh wait. I just realized there is an empty constructor for QbXmlRequest that already grabs the default version from that static property. So do we even need to pass anything in? It seems like it would work just fine as is, unless I am missing something.

Or if it might potentially be changed depending on the environment, I wonder if it is possible to add the version information onto the ticket? Since the authenticated ticket is passed around, it might be possible to save the version information into the ticket then retrieve it for use in the step query requests?

public interface IAuthenticatedTicket
{
    /// <summary>
    /// Ticket exchanged with the WebConnector. It acts as a session identifier.
    /// </summary>
    string Ticket { get; set; }

    /// <summary>
    /// State indicating what to exchange with the Web Connector.
    /// </summary>
    string CurrentStep { get; set; }

    /// <summary>
    /// Simple boolean indicating if the ticket is authenticated.
    /// </summary>
    bool Authenticated { get; set; }

    /// <summary>
    /// Quickbooks version string
    /// </summary>
    Version QbVersion { get; set; }

}
public virtual async Task<string?> SendXMLAsync(IAuthenticatedTicket authenticatedTicket)
{
    var requestObject = await CreateRequestAsync(authenticatedTicket);
    if (requestObject != null)
    {
        if (await ExecuteRequestAsync(authenticatedTicket, requestObject))
        {
            var qbXmlRequest = new QbXmlRequest(authenticatedTicket.QbVersion);
            qbXmlRequest.AddToSingle(requestObject);

            return qbXmlRequest.GetRequest();
        }
    }

    return null;
}

Being in the ticket makes sense but it's saved in the DB. It's not a bad idea I could pick up the work I had started next week.