Quickbooks PHP 开发工具包 Web 连接器 SalesRep 导入
Quickbooks PHP Dev Kit Web Connector SalesRep Import
我正在使用 Consolibyte 提供的出色的 Quickbooks PHP 开发工具包,并且正在将销售代表导入数据库。下面的代码是我对请求 xml 的代码。 Quickbooks 文件有 3000 多个销售代表,响应 xml 无效。我知道我可以使用元数据来获取计数并使用 MaxReturned 来获取有限的记录。通过不确定迭代器中是否存在?
我正在将 xml 传递给 mssql 数据库并在那里进行解析。问题是当 xml 无效时,它会导致 sql 服务器挂起,因为查询是 运行 - 所以我需要在传递它之前以某种方式验证 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 - 感谢您花时间回复。以下是我对 request/response 函数
的了解
//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 存储过程时 - 它锁定在 insert/update 上,因为它的格式不正确 xml。所以我希望以某种方式验证 xml 并能够检索小块。
我使用 SalesRepQueryRq 中的元数据获得了总记录数。如果我在请求中将 MaxReturned 设置为 50,则一切正常。
这是来自网络连接器的消息
说明:
QBWC1042:ReceiveResponseXML 失败
错误消息:操作已超时有关更多详细信息,请参阅 QWCLog。记得开启登录。
我用了 QUICKBOOKS_LOG_DEVELOP 最后几行是
receiveResponseXML()
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'S</FullName> </SalesRepEntityRef> </SalesRepRet>
.....
.....
</Sales
xml 就这样结束了
好吧,这适用于 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?这是一个 ,它解释了编码和参数类型问题的可能来源。
提示:设SQL-Server中的参数为NVARCHAR(MAX)
类型。我会开始通过 XML 而没有 <? ... ?>
( 处理指令 )。剪掉第一行,让它从 <QBXML>
开始。并确保您填入 . $ last .
的日期是 ISO8601 (2017-01-27T08:30:15
).
在 SQL 服务器中,您可以将传入的字符串分配给 XML-typed 变量。
--so whats happening is response returned from quickbooks is not well formed xml
不,事实并非如此。 XML QuickBooks 正在返回,完全没问题。
I am guessing because of too much data in xml.
您的问题与大量数据有关...但实际上不与无效[=88=有关] 来自 QuickBooks。
So when this is passed over to sql stored procedure - it locks up on insert/update because its not well formed xml.
不,这不是事情爆发的原因。
So I was hoping to validate xml somehow and be able to retrieve small chunks.
无需验证 XML。 XML 返回的 QuickBooks 完全有效。
但是,将结果分成更小的块是一个好主意。
If i set MaxReturned to 50 in request, everything works without an issue.
这是一个很大的提示。它与无效 XML 无关...您的问题与 XML 中返回了多少结果有关。
Description: QBWC1042: ReceiveResponseXML failed Error message: The operation has timed out See QWCLog for more details. Remember to turn logging on.
现在到了关键时刻!
这是关键:
- 操作超时
很遗憾,您没有 post Web 连接器日志文件的其余部分,因此我们没有获得本来有用的其他真正有用的信息。
Web 连接器有一个 hard-coded,2 分钟超时。如果您 post 编辑了其余的日志,我想我们会看到 Web 连接器日志中的时间戳显示 Web 连接器开始向您发送数据的时间和连接断开的时间之间有 2 分钟的间隔关闭并且错误显示在日志中。
我敢打赌,如果您对代码进行基准测试,您还会发现您的代码需要超过 2 分钟的时间来处理来自 QuickBooks 的响应。
I used QUICKBOOKS_LOG_DEVELOP and the last lines are receiveResponseXML()
我假设您是从 quickbooks_log
SQL table 中提取的。我敢打赌,如果您检查了您的列类型,您会发现该列的最大长度恰好截断了 XML,因为它无法将所有数据放入该列。
by not sure if there in iterator?
此时可以查看文档:
并且很容易确定不,SalesRepQueryRq
不支持迭代器。
但是,您可以通过查询数据块来伪造迭代器。例如,使用 NameRangeFilter
:
<NameRangeFilter> <!-- optional -->
<FromName >STRTYPE</FromName> <!-- optional -->
<ToName >STRTYPE</ToName> <!-- optional -->
</NameRangeFilter>
检索从 Aa
到 Az
的所有内容。然后对 Ba
到 Bz
执行相同的操作。然后 Ca
到 Cz
,等等等等。你最终会得到所有的数据,但是是小块的。
TLDR:查看您的其余日志。下一次,post 日志中的整个相关部分。您的代码很可能花费的时间太长,导致 Web 连接器超时 2 分钟。
我正在使用 Consolibyte 提供的出色的 Quickbooks PHP 开发工具包,并且正在将销售代表导入数据库。下面的代码是我对请求 xml 的代码。 Quickbooks 文件有 3000 多个销售代表,响应 xml 无效。我知道我可以使用元数据来获取计数并使用 MaxReturned 来获取有限的记录。通过不确定迭代器中是否存在?
我正在将 xml 传递给 mssql 数据库并在那里进行解析。问题是当 xml 无效时,它会导致 sql 服务器挂起,因为查询是 运行 - 所以我需要在传递它之前以某种方式验证 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 - 感谢您花时间回复。以下是我对 request/response 函数
的了解 //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 存储过程时 - 它锁定在 insert/update 上,因为它的格式不正确 xml。所以我希望以某种方式验证 xml 并能够检索小块。
我使用 SalesRepQueryRq 中的元数据获得了总记录数。如果我在请求中将 MaxReturned 设置为 50,则一切正常。
这是来自网络连接器的消息
说明: QBWC1042:ReceiveResponseXML 失败 错误消息:操作已超时有关更多详细信息,请参阅 QWCLog。记得开启登录。
我用了 QUICKBOOKS_LOG_DEVELOP 最后几行是 receiveResponseXML()
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'S</FullName> </SalesRepEntityRef> </SalesRepRet>
.....
.....
</Sales
xml 就这样结束了
好吧,这适用于 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?这是一个
提示:设SQL-Server中的参数为NVARCHAR(MAX)
类型。我会开始通过 XML 而没有 <? ... ?>
( 处理指令 )。剪掉第一行,让它从 <QBXML>
开始。并确保您填入 . $ last .
的日期是 ISO8601 (2017-01-27T08:30:15
).
在 SQL 服务器中,您可以将传入的字符串分配给 XML-typed 变量。
--so whats happening is response returned from quickbooks is not well formed xml
不,事实并非如此。 XML QuickBooks 正在返回,完全没问题。
I am guessing because of too much data in xml.
您的问题与大量数据有关...但实际上不与无效[=88=有关] 来自 QuickBooks。
So when this is passed over to sql stored procedure - it locks up on insert/update because its not well formed xml.
不,这不是事情爆发的原因。
So I was hoping to validate xml somehow and be able to retrieve small chunks.
无需验证 XML。 XML 返回的 QuickBooks 完全有效。
但是,将结果分成更小的块是一个好主意。
If i set MaxReturned to 50 in request, everything works without an issue.
这是一个很大的提示。它与无效 XML 无关...您的问题与 XML 中返回了多少结果有关。
Description: QBWC1042: ReceiveResponseXML failed Error message: The operation has timed out See QWCLog for more details. Remember to turn logging on.
现在到了关键时刻!
这是关键:
- 操作超时
很遗憾,您没有 post Web 连接器日志文件的其余部分,因此我们没有获得本来有用的其他真正有用的信息。
Web 连接器有一个 hard-coded,2 分钟超时。如果您 post 编辑了其余的日志,我想我们会看到 Web 连接器日志中的时间戳显示 Web 连接器开始向您发送数据的时间和连接断开的时间之间有 2 分钟的间隔关闭并且错误显示在日志中。
我敢打赌,如果您对代码进行基准测试,您还会发现您的代码需要超过 2 分钟的时间来处理来自 QuickBooks 的响应。
I used QUICKBOOKS_LOG_DEVELOP and the last lines are receiveResponseXML()
我假设您是从 quickbooks_log
SQL table 中提取的。我敢打赌,如果您检查了您的列类型,您会发现该列的最大长度恰好截断了 XML,因为它无法将所有数据放入该列。
by not sure if there in iterator?
此时可以查看文档:
并且很容易确定不,SalesRepQueryRq
不支持迭代器。
但是,您可以通过查询数据块来伪造迭代器。例如,使用 NameRangeFilter
:
<NameRangeFilter> <!-- optional -->
<FromName >STRTYPE</FromName> <!-- optional -->
<ToName >STRTYPE</ToName> <!-- optional -->
</NameRangeFilter>
检索从 Aa
到 Az
的所有内容。然后对 Ba
到 Bz
执行相同的操作。然后 Ca
到 Cz
,等等等等。你最终会得到所有的数据,但是是小块的。
TLDR:查看您的其余日志。下一次,post 日志中的整个相关部分。您的代码很可能花费的时间太长,导致 Web 连接器超时 2 分钟。