【问题标题】:Quickbooks PHP Dev Kit Web Connector SalesRep ImportQuickbooks PHP 开发工具包 Web 连接器 SalesRep 导入
【发布时间】:2017-01-27 02:28:57
【问题描述】:

我正在使用 Consolibyte 提供的优秀 Quickbooks PHP 开发工具包,我正在将销售代表导入数据库。下面的代码是我对请求 xml 的代码。 Quickbooks 文件有超过 3000 名销售代表,并且响应 xml 无效。我知道我可以使用元数据来获取计数并使用 MaxReturned 来获取有限的记录。不确定是否在迭代器中?

我将 xml 传递给 mssql 数据库并在那里解析它。问题是当 xml 无效时,它会导致 sqlserver 在查询运行时挂起 - 所以我需要在将 xml 传递给 sql 之前以某种方式对其进行验证。

任何帮助将不胜感激。

$xml = '<?xml version="1.0" encoding="utf-8"?>
            <?qbxml version="' . $version . '"?>
            <QBXML>
                <QBXMLMsgsRq onError="stopOnError">
                    <SalesRepQueryRq>
                        <ActiveStatus>ActiveOnly</ActiveStatus>
                        <FromModifiedDate>' . $last . '</FromModifiedDate>
                        <IncludeRetElement>ListID</IncludeRetElement>
                        <IncludeRetElement>SalesRepEntityRef</IncludeRetElement>
                    </SalesRepQueryRq>
                </QBXMLMsgsRq>
            </QBXML>';

    return $xml;

----用下面的代码更新--- @keith - 感谢您抽出宝贵时间回复。以下是我的请求/响应功能

   //sales rep list import request
function _quickbooks_salesrep_import_request($requestID, $user, $action, $ID, $extra, &$err, $last_action_time, $last_actionident_time, $version, $locale)
{
    $last = _quickbooks_get_last_run($user, $action); //get last run time
    _quickbooks_set_last_run($user, $action); //set current run

    // Build the request
    $xml = '<?xml version="1.0" encoding="utf-8"?>
            <?qbxml version="' . $version . '"?>
            <QBXML>
                <QBXMLMsgsRq onError="stopOnError">
                    <SalesRepQueryRq>
                        <ActiveStatus>ActiveOnly</ActiveStatus>
                        <FromModifiedDate>' . $last . '</FromModifiedDate>
                        <IncludeRetElement>ListID</IncludeRetElement>
                        <IncludeRetElement>SalesRepEntityRef</IncludeRetElement>
                    </SalesRepQueryRq>
                </QBXMLMsgsRq>
            </QBXML>';

    return $xml;
}

//sales rep list import response
function _quickbooks_salesrep_import_response ($requestID, $user, $action, $ID, $extra, &$err, $last_action_time, $last_actionident_time, $xml, $idents)
{
      global $conn;
      $sql = '{call dbo.spQBAddUpdateSalesRep (?)}';
      $params = array($xml);
      $stmt = dbQuery($sql,$conn,$params);
      dbCloseQuery($stmt);
    //QuickBooks_Utilities::log(QB_QUICKBOOKS_DSN, 'rep xml - ' . $xml);
    return true;
}

这是我在传递 xml 的存储过程中的内容

@strXML XML --- this is passed as parameter

BEGIN TRY
BEGIN TRANSACTION

UPDATE dbo.qb_salesrep SET
             TimeCreated = SUB.TimeCreated
            ,TimeModified = SUB.TimeModified
            ,EditSequence = SUB.EditSequence
            ,Initial = SUB.Initial
            ,IsActive = SUB.IsActive
            ,SalesRepEntityRef_ListID = SUB.SalesRepEntityRef_ListID
            ,SalesRepEntityRef_FullName = SUB.SalesRepEntityRef_FullName
        FROM
            (SELECT
                 ListID = x.c.value('ListID[1]','VARCHAR(36)')
                ,TimeCreated = x.c.value('TimeCreated[1]','DATETIME')
                ,TimeModified = x.c.value('TimeModified[1]','DATETIME')
                ,EditSequence = x.c.value('EditSequence[1]','VARCHAR(16)')
                ,Initial = x.c.value('Initial[1]','VARCHAR(5)')
                ,IsActive = x.c.value('IsActive[1]','BIT')
                ,SalesRepEntityRef_ListID = x.c.value('SalesRepEntityRef[1]/ListID[1]','VARCHAR(36)')
                ,SalesRepEntityRef_FullName = x.c.value('SalesRepEntityRef[1]/FullName[1]','VARCHAR(41)')
            FROM
                @strXML.nodes('QBXML/QBXMLMsgsRs/SalesRepQueryRs/SalesRepRet') x(c)) AS SUB
        WHERE
            dbo.qb_salesrep.ListID = SUB.ListID 

INSERT INTO dbo.qb_salesrep (
                 ListID
                ,TimeCreated
                ,TimeModified
                ,EditSequence
                ,Initial
                ,IsActive
                ,SalesRepEntityRef_ListID
                ,SalesRepEntityRef_FullName
            )
            SELECT
                 ListID = x.c.value('ListID[1]','VARCHAR(36)')
                ,TimeCreated = x.c.value('TimeCreated[1]','DATETIME')
                ,TimeModified = x.c.value('TimeModified[1]','DATETIME')
                ,EditSequence = x.c.value('EditSequence[1]','VARCHAR(16)')
                ,Initial = x.c.value('Initial[1]','VARCHAR(5)')
                ,IsActive = x.c.value('IsActive[1]','BIT')
                ,SalesRepEntityRef_ListID = x.c.value('SalesRepEntityRef[1]/ListID[1]','VARCHAR(36)')
                ,SalesRepEntityRef_FullName = x.c.value('SalesRepEntityRef[1]/FullName[1]','VARCHAR(41)')
            FROM
                @strXML.nodes('QBXML/QBXMLMsgsRs/SalesRepQueryRs/SalesRepRet') x(c)
            WHERE
                x.c.value('ListID[1]','VARCHAR(36)') NOT IN (SELECT ListID FROM dbo.qb_salesrep) 

COMMIT TRANSACTION
END TRY
BEGIN CATCH
ROLLBACK TRANSACTION
RETURN
END CATCH

--所以发生的事情是从 quickbooks 返回的响应不是格式良好的 xml - 它最终被切断了。我猜是因为 xml 中的数据太多。因此,当这被传递给 sql 存储过程时 - 它会锁定插入/更新,因为它的 xml 格式不正确。所以我希望以某种方式验证 xml 并能够检索小块。

我使用 SalesRepQueryRq 中的元数据获得了总记录数。如果我在请求中将 MaxReturned 设置为 50,则一切正常。

这是来自网络连接器的消息

说明: QBWC1042:ReceiveResponseXML 失败 错误消息:操作已超时 有关详细信息,请参阅 QWCLog。记得开启登录功能。

我使用了 QUICKBOOKS_LOG_DEVELOP,最后几行是 接收响应XML()

Incoming XML response: <?xml version="1.0" ?> <QBXML> <QBXMLMsgsRs> <SalesRepQueryRs requestID="6" statusCode="0" statusSeverity="Info" statusMessage="Status OK"> <SalesRepRet> <ListID>31A0000-1193779738</ListID> <SalesRepEntityRef> <ListID>60F0002-1193780133</ListID> <FullName>*BRANDT&apos;S</FullName> </SalesRepEntityRef> </SalesRepRet>
.....
.....
</Sales

xml 就是这样结束的

【问题讨论】:

  • 发布您的代码。发布日志。发布确切的错误消息。我怀疑你严重误解了实际发生的事情,但你并没有真正发布足够的信息让任何人帮助你。

标签: sql-server xml quickbooks


【解决方案1】:

--所以发生的事情是从 quickbooks 返回的响应不是格式良好的 xml

不,这不是正在发生的事情。返回的 XML QuickBooks 完全没问题。

我猜是因为 xml 中的数据太多。

您的问题与存在大量数据有关......但它实际上与 QuickBooks 中的无效 XML 无关。

因此,当它被传递给 sql 存储过程时 - 它会锁定插入/更新,因为它的 xml 格式不正确。

不,这不是事情爆炸的原因。

所以我希望以某种方式验证 xml 并能够检索小块。

无需验证 XML。返回的 XML QuickBooks 完全有效。

但是,将结果分成更小的块一个好主意。

如果我在请求中将 MaxReturned 设置为 50,则一切正常。

这是一个很大的提示。它与无效的 XML 无关...您的问题与 XML 中返回的结果数有关

描述:QBWC1042:ReceiveResponseXML failed 错误消息:操作已超时 有关详细信息,请参阅 QWCLog。记得开启登录功能。

现在我们处于重要位置!

这是关键:

  • 操作已超时

很遗憾,您没有发布 Web 连接器日志文件的其余部分,因此我们没有获得其他真正有用的信息。

Web 连接器有一个硬编码的 2 分钟超时。如果您发布了其余日志,我想我们会看到 Web 连接器日志中的时间戳显示 Web 连接器开始向您发送数据与连接关闭并显示错误之间有 2 分钟的间隔在日志中。

我敢打赌,如果您对代码进行基准测试,您还会发现您的代码需要超过 2 分钟的时间来处理来自 QuickBooks 的响应。

我使用了QUICKBOOKS_LOG_DEVELOP,最后几行是receiveResponseXML()

我假设您是从quickbooks_log SQL 表中提取的。我敢打赌,如果您检查了列类型,您会发现列上的最大长度只是切断了 XML,因为它无法将所有数据都放入列中。

不确定是否存在迭代器?

此时可以查看文档:

并且很容易确定不,SalesRepQueryRq 不支持迭代器。

然而,您可以通过查询数据块来伪造迭代器。例如,使用NameRangeFilter

<NameRangeFilter> <!-- optional -->
<FromName >STRTYPE</FromName> <!-- optional -->
<ToName >STRTYPE</ToName> <!-- optional -->
</NameRangeFilter>

检索从AaAz 的所有内容。然后对BaBz 执行相同的操作。然后对于CaCz,等等等等。你最终会得到所有的数据,但是是更小的块。

TLDR:查看您的其余日志。下次,从日志中发布整个相关部分。您的代码很可能花费的时间太长,导致 Web 连接器 2 分钟超时。

【讨论】:

  • 谢谢基思!你说得对,网络连接器超时 - 我将使用名称范围过滤器来实现迭代器,以获取数据的小子集。
  • 没问题,很高兴能帮上忙!
【解决方案2】:

嗯,这在 SQL-Server 中有效:

declare @xml xml=
   '<?xml version="1.0" encoding="utf-8"?>
    <?qbxml version="3"?>
    <QBXML>
        <QBXMLMsgsRq onError="stopOnError">
            <SalesRepQueryRq>
                <ActiveStatus>ActiveOnly</ActiveStatus>
                <FromModifiedDate>2017-01-27T08:30:15</FromModifiedDate>
                <IncludeRetElement>ListID</IncludeRetElement>
                <IncludeRetElement>SalesRepEntityRef</IncludeRetElement>
            </SalesRepQueryRq>
        </QBXMLMsgsRq>
    </QBXML>';
select @xml;

您如何将其传递给 MS-Sql-Server?这是related answer,它解释了编码和参数类型的可能问题来源。

提示:让 SQL-Server 中的参数为 NVARCHAR(MAX) 类型。我将开始在没有&lt;? ... ?&gt; 的情况下传递 XML(处理指令)。剪掉第一行,让它从&lt;QBXML&gt;开始。并确保您填入 . $ last . 的日期是 ISO8601 (2017-01-27T08:30:15)。

在 SQL Server 中,您可以将传入的字符串分配给 XML 类型的变量。

【讨论】:

  • 感谢您的响应 - 我将 xml 作为参数传递给存储过程 - 它的 XML 数据类型 DECLARE @strXML XML 在我用于在 MSSQL 中进行插入/更新之前是否有办法确保 - 我正在使用 SQL服务器 2008 R2
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多