如何在 Authenticate for Quickbooks Web Connector 中设置响应的 .QBW 文件路径?

How to set .QBW file path for response in Authenticate for Quickbooks Web Connector?

好的,我正在使用 Keith Palmers excellent 类,位于此处:https://github.com/consolibyte/quickbooks-php,Web 连接器工作正常,但只有当我打开 Quickbooks 并单击文件时 - >在 Web 连接器运行的服务器中更新 Web 服务。一旦我退出服务器,甚至关闭 Quickbooks 应用程序,Web 连接器就不再工作。我是 运行 Quickbooks Enterprise,读到我需要从 authenticate() 方法发送响应,我猜 Web 连接器服务器 (https) 需要发送,这是 <AppURL> 来自 .QWC 文件。唯一的问题是,我不完全理解 Keith 的代码是如何工作的,甚至不确定 authenticate() 方法在哪里运行。而且这个选项可能已经在 Class and/or Function/Hook 中可用,QB Classes 中似乎有很多。

现在,我的服务器只有很少的标记,看起来像这样:

<?php

/**
 * Example QuickBooks SOAP Server / Web Service
 * 
 * This is an example Web Service which adds customers to QuickBooks desktop 
 * editions via the QuickBooks Web Connector. 
 * 
 * MAKE SURE YOU READ OUR QUICK-START GUIDE:
 *  http://wiki.consolibyte.com/wiki/doku.php/quickbooks_integration_php_consolibyte_webconnector_quickstart
 *  http://wiki.consolibyte.com/wiki/doku.php/quickbooks
 * 
 * You should copy this file and use this file as a reference for when you are 
 * creating your own Web Service to add, modify, query, or delete data from 
 * desktop versions of QuickBooks software. 
 * 
 * The basic idea behind this method of integration with QuickBooks desktop 
 * editions is to host this web service on your server and have the QuickBooks 
 * Web Connector connect to it and pass messages to QuickBooks. So, every time 
 * that an action occurs on your website which you wish to communicate to 
 * QuickBooks, you'll queue up a request (shown below, using the 
 * QuickBooks_Queue class). 
 * 
 * You'll write request handlers which generate qbXML requests for each type of 
 * action you queue up. Those qbXML requests will be passed by the Web 
 * Connector to QuickBooks, which will then process the requests and send back 
 * the responses. Your response handler will then process the response (you'll 
 * probably want to at least store the returned ListID or TxnID of anything you 
 * create within QuickBooks) and this pattern will continue until there are no 
 * more requests in the queue for QuickBooks to process. 
 * 
 * @author Keith Palmer <keith@consolibyte.com>
 * 
 * @package QuickBooks
 * @subpackage Documentation
 */

// I always program in E_STRICT error mode... 
error_reporting(E_ALL | E_STRICT);
ini_set('display_errors', 1);

// We need to make sure the correct timezone is set, or some PHP installations will complain
if (function_exists('date_default_timezone_set'))
{
    // * MAKE SURE YOU SET THIS TO THE CORRECT TIMEZONE! *
    // List of valid timezones is here: http://us3.php.net/manual/en/timezones.php
    date_default_timezone_set('America/New_York');
}

// Require the framework
require_once(dirname(__FILE__) . '/../QuickBooks.php');

$user = 'quickbooks';
$pass = 'password';

// Map QuickBooks actions to handler functions
$map = array(
    QUICKBOOKS_ADD_CUSTOMER => array( '_quickbooks_customer_add_request', '_quickbooks_customer_add_response' ),
    QUICKBOOKS_QUERY_CUSTOMER => array('_quickbooks_query_customer_request', '_quickbooks_query_customer_response'),
    // ... more action handlers here ...
    );

// This is entirely optional, use it to trigger actions when an error is returned by QuickBooks
$errmap = array(
    // 3070 => '_quickbooks_error_stringtoolong',               // Whenever a string is too long to fit in a field, call this function: _quickbooks_error_stringtolong()
    // 'CustomerAdd' => '_quickbooks_error_customeradd',    // Whenever an error occurs while trying to perform an 'AddCustomer' action, call this function: _quickbooks_error_customeradd()
    'CustomerQuery' => '_quickbooks_error_customer_query',
    '*' => '_quickbooks_error_catchall',                // Using a key value of '*' will catch any errors which were not caught by another error handler
    // ... more error handlers here ...
    );

// An array of callback hooks
$hooks = array(
    // There are many hooks defined which allow you to run your own functions/methods when certain events happen within the framework
    // QuickBooks_WebConnector_Handlers::HOOK_LOGINSUCCESS => '_quickbooks_hook_loginsuccess',  // Run this function whenever a successful login occurs
    );

function _quickbooks_error_customer_query($requestID, $user, $action, $ID, $extra, &$err, $xml, $errnum, $errmsg)
{
    file_put_contents(dirname(__FILE__) . '/customer_query_error.txt', "Error Number " . $errnum . PHP_EOL . $errmsg . PHP_EOL, FILE_APPEND | LOCK_EX);
}

function _quickbooks_error_catchall($requestID, $user, $action, $ID, $extra, &$err, $xml, $errnum, $errmsg)
{
    mysql_query("
        UPDATE 
            my_customer_table 
        SET 
            quickbooks_errnum = '" . mysql_real_escape_string($errnum) . "', 
            quickbooks_errmsg = '" . mysql_real_escape_string($errmsg) . "'
        WHERE 
            id = " . (int) $ID);
}

// Logging level
$log_level = QUICKBOOKS_LOG_DEBUG;              
$soapserver = QUICKBOOKS_SOAPSERVER_BUILTIN;

$soap_options = array(      // See http://www.php.net/soap
    );

$handler_options = array(
    //'authenticate' => ' *** YOU DO NOT NEED TO PROVIDE THIS CONFIGURATION VARIABLE TO USE THE DEFAULT AUTHENTICATION METHOD FOR THE DRIVER YOU'RE USING (I.E.: MYSQL) *** '
    //'authenticate' => 'your_function_name_here', 
    //'authenticate' => array( 'YourClassName', 'YourStaticMethod' ),
    'deny_concurrent_logins' => false, 
    'deny_reallyfast_logins' => false, 
    );      // See the comments in the QuickBooks/Server/Handlers.php file

$driver_options = array(        // See the comments in the QuickBooks/Driver/<YOUR DRIVER HERE>.php file ( i.e. 'Mysql.php', etc. )
    //'max_log_history' => 1024,    // Limit the number of quickbooks_log entries to 1024
    //'max_queue_history' => 64,    // Limit the number of *successfully processed* quickbooks_queue entries to 64
    );

$callback_options = array(
    );

$dsn = 'mysql://{my_db_name}:{my_db_password}@localhost/{my_db}';

// Create a new server and tell it to handle the requests
// __construct($dsn_or_conn, $map, $errmap = array(), $hooks = array(), $log_level = QUICKBOOKS_LOG_NORMAL, $soap = QUICKBOOKS_SOAPSERVER_PHP, $wsdl = QUICKBOOKS_WSDL, $soap_options = array(), $handler_options = array(), $driver_options = array(), $callback_options = array()
$Server = new QuickBooks_WebConnector_Server($dsn, $map, $errmap, $hooks, $log_level, $soapserver, QUICKBOOKS_WSDL, $soap_options, $handler_options, $driver_options, $callback_options);
$response = $Server->handle(true, true);


function _quickbooks_customer_add_request($requestID, $user, $action, $ID, $extra, &$err, $last_action_time, $last_actionident_time, $version, $locale)
{
    // Grab the data from our MySQL database
    $arr = mysql_fetch_assoc(mysql_query("SELECT * FROM my_customer_table WHERE id = " . (int) $ID));

    $xml = '<?xml version="1.0" encoding="utf-8"?>
        <?qbxml version="2.0"?>
        <QBXML>
            <QBXMLMsgsRq onError="stopOnError">
                <CustomerAddRq requestID="' . $requestID . '">
                    <CustomerAdd>
                        <Name>' . $arr['name'] . '</Name>
                        <CompanyName>' . $arr['name'] . '</CompanyName>
                        <FirstName>' . $arr['fname'] . '</FirstName>
                        <LastName>' . $arr['lname'] . '</LastName>
                    </CustomerAdd>
                </CustomerAddRq>
            </QBXMLMsgsRq>
        </QBXML>';

    return $xml;
}


function _quickbooks_customer_add_response($requestID, $user, $action, $ID, $extra, &$err, $last_action_time, $last_actionident_time, $xml, $idents)
{   
    mysql_query("UPDATE my_customer_table SET quickbooks_listid = '" . mysql_escape_string($idents['ListID']) . "' WHERE id = " . (int) $ID);

}

// Get all Customers!
function _quickbooks_query_customer_request($requestID, $user, $action, $ID, $extra, &$err, $last_action_time, $last_actionident_time, $version, $locale) {
    $xml = '<?xml version="1.0" encoding="utf-8"?>
        <?qbxml version="11.0"?>
        <QBXML>
            <QBXMLMsgsRq onError="stopOnError">
                <CustomerQueryRq requestID="' . $requestID . '">
                    <MaxReturned>10000</MaxReturned>
                    <ActiveStatus>All</ActiveStatus>
                </CustomerQueryRq>
            </QBXMLMsgsRq>
        </QBXML>';

    return $xml;
}

function add_quotes($value)
{
    if (is_string($value))
        return sprintf("'%s'", mysql_escape_string($value));
    else
        return $value;
}

function _quickbooks_query_customer_response($requestID, $user, $action, $ID, $extra, &$err, $last_action_time, $last_actionident_time, $xml, $idents)
{
    $customers = json_decode(json_encode(simplexml_load_string($xml, "SimpleXMLElement", LIBXML_NOCDATA)), true);

    if (!empty($customers['QBXMLMsgsRs']) && !empty($customers['QBXMLMsgsRs']['CustomerQueryRs']) && !empty($customers['QBXMLMsgsRs']['CustomerQueryRs']['CustomerRet']))
    {
        foreach($customers['QBXMLMsgsRs']['CustomerQueryRs']['CustomerRet'] as $customer_data)
        {
            $customer_info = array();
            foreach($customer_data as $attribute => $info)
            {
                if ($attribute == 'BillAddressBlock') continue;

                if ($attribute == 'IsActive')
                    $info = $info == 'true' ? 1 : 0;

                if ($attribute == 'Sublevel')
                {
                    $info = (int) $info;
                    if (empty($info))
                        $info = 0;
                }

                if (is_array($info))
                {
                    foreach($info as $key => $value)
                    {
                        if (!is_array($value))
                            $customer_info[$attribute . '_' . $key] = stripslashes($value); // Magic Quotes being on, should check magic quotes before using stripslashes tho
                    }
                }
                else
                    $customer_info[$attribute] = stripslashes($info); // Magic Quotes being on, should check magic quotes before using stripslashes tho
            }

            if (!empty($customer_info))
            {
                $columns = implode(', ', array_keys($customer_info));
                $values = implode(', ', array_map('add_quotes', $customer_info));

                $sql = 'INSERT INTO quickbooks_customers (' . $columns . ') VALUES (' . $values . ')';

                // file_put_contents(dirname(__FILE__) . '/sql.txt', var_export($sql, true) . PHP_EOL, FILE_APPEND | LOCK_EX);
                // Insert this customer into the database now:
                mysql_query($sql);
            }
        }
    }
}


function _quickbooks_error_stringtoolong($requestID, $user, $action, $ID, $extra, &$err, $xml, $errnum, $errmsg)
{
    mail('your-email@your-domain.com', 
        'QuickBooks error occured!', 
        'QuickBooks thinks that ' . $action . ': ' . $ID . ' has a value which will not fit in a QuickBooks field...');
}
?>

不知道在哪里设置 QBW 文件的完整路径。任何帮助将不胜感激。如果有帮助,我的 <QBType> 设置为 QBFS

我正在使用以下方法来排队操作:

$Queue = new QuickBooks_WebConnector_Queue($connection_string);
$Queue->enqueue(QUICKBOOKS_QUERY_CUSTOMER, $random_unique_id);

但是如何放入.QBW文件路径?它应该在 $soap_options 或 $handler_options 中,还是与我可以通过服务发送的任何参数分开存在?如果我能看到有人使用此 API 正确链接 QBW 文件的示例,那将是最有帮助的。我知道服务器上 .QBW 文件的路径,只需要将它作为响应发回,现在完全确定如何使用 Keith Palmers 代码来做到这一点,如果它甚至可以在其中轻松完成 API...?

Not sure where to set Full Path of QBW file here.

Copy/pasted 来自我们的 wiki:

You can tell the framework to connect to QuickBooks even if QuickBooks is not open by setting the 'qb_company_file' field in the 'quickbooks_user' SQL table to the full path of the company file. That means that for QuickBooks financial editions (i.e. Pro, Premier, Enterprise editions), you should be doing:

UPDATE quickbooks_user SET qb_company_file = 'C:\path\to\your\file.QBW' WHERE qb_username = 'your-web-connector-username'