I try to implement example_web_connector via QB Web Connector
I added App to QBWC, password, authenticate passed, but QBWC got error "0x80045242: QBPOSXML: Unknown request version"
In which side I must to "watch"?
QB POS 2013
QBSDK 13.0
QBC
<?xml version="1.0"?>
<QBWCXML>
<AppName>QB</AppName>
<AppID>IDNTS_POS_1</AppID>
<AppURL>http://localhost/</AppURL>
<AppDescription>QB</AppDescription>
<AppSupport>http://localhost/dashboard/</AppSupport>
<UserName>test</UserName>
<OwnerID>{A91CC425-ABC4-4972-9FC6-D5F6B90F0472}</OwnerID>
<FileID>{349C0857-7A5D-428c-B0B9-E0AC9377EE14}</FileID>
<QBType>QBPOS</QBType>
<Style>Document</Style>
</QBWCXML>
example code of index.php from http://localhost/
php
// 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 'quickbooks-php-master/QuickBooks.php';
$user = 'test';
$pass = 'test';
// Map QuickBooks actions to handler functions
$map = array(
QUICKBOOKS_ADD_CUSTOMER => array( '_quickbooks_customer_add_request', '_quickbooks_customer_add_response' ),
//QUICKBOOKS_ADD_SALESRECEIPT => array( '_quickbooks_salesreceipt_add_request', '_quickbooks_salesreceipt_add_response' ),
//'*' => array( '_quickbooks_customer_add_request', '_quickbooks_customer_add_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()
// '*' => '_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
);
$log_level = QUICKBOOKS_LOG_DEBUG;
$soapserver = QUICKBOOKS_SOAPSERVER_BUILTIN; // A pure-PHP SOAP server (no PHP ext/soap extension required, also makes debugging easier)
$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 = 'mysqli://root:#localhost/qb';
if (!QuickBooks_Utilities::initialized($dsn))
{
// Initialize creates the neccessary database schema for queueing up requests and logging
QuickBooks_Utilities::initialize($dsn);
// This creates a username and password which is used by the Web Connector to authenticate
QuickBooks_Utilities::createUser($dsn, $user, $pass);
}
$primary_key_of_your_customer = 5;
$Queue = new QuickBooks_WebConnector_Queue($dsn);
$Queue->enqueue(QUICKBOOKS_ADD_CUSTOMER, $primary_key_of_your_customer);
$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)
{
$xml = '<?xml version="1.0" encoding="utf-8"?>
<?qbxml version="2.0"?>
<QBXML>
<QBXMLMsgsRq onError="stopOnError">
<CustomerAddRq requestID="' . $requestID . '">
<CustomerAdd>
<Name>ConsoliBYTE, LLC (' . mt_rand() . ')</Name>
<CompanyName>ConsoliBYTE, LLC</CompanyName>
<FirstName>Keith</FirstName>
<LastName>Palmer</LastName>
<BillAddress>
<Addr1>ConsoliBYTE, LLC</Addr1>
<Addr2>134 Stonemill Road</Addr2>
<City>Mansfield</City>
<State>CT</State>
<PostalCode>06268</PostalCode>
<Country>United States</Country>
</BillAddress>
<Phone>860-634-1602</Phone>
<AltPhone>860-429-0021</AltPhone>
<Fax>860-429-5183</Fax>
<Email>Keith#ConsoliBYTE.com</Email>
<Contact>Keith Palmer</Contact>
</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)
{
// Great, customer $ID has been added to QuickBooks with a QuickBooks
// ListID value of: $idents['ListID']
//
// We probably want to store that ListID in our database, so we can use it
// later. (You'll need to refer to the customer by either ListID or Name
// in other requests, say, to update the customer or to add an invoice for
// the customer.
/*
mysql_query("UPDATE your_customer_table SET quickbooks_listid = '" . mysql_escape_string($idents['ListID']) . "' WHERE your_customer_ID_field = " . (int) $ID);
*/
}
function _quickbooks_salesreceipt_add_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="2.0"?>
<QBXML>
<QBXMLMsgsRq onError="stopOnError">
<SalesReceiptAddRq requestID="' . $requestID . '">
<SalesReceiptAdd>
<CustomerRef>
<FullName>Keith Palmer Jr.</FullName>
</CustomerRef>
<TxnDate>2009-01-09</TxnDate>
<RefNumber>16466</RefNumber>
<BillAddress>
<Addr1>Keith Palmer Jr.</Addr1>
<Addr3>134 Stonemill Road</Addr3>
<City>Storrs-Mansfield</City>
<State>CT</State>
<PostalCode>06268</PostalCode>
<Country>United States</Country>
</BillAddres>
<SalesReceiptLineAdd>
<ItemRef>
<FullName>Gift Certificate</FullName>
</ItemRef>
<Desc>$25.00 gift certificate</Desc>
<Quantity>1</Quantity>
<Rate>25.00</Rate>
<SalesTaxCodeRef>
<FullName>NON</FullName>
</SalesTaxCodeRef>
</SalesReceiptLineAdd>
<SalesReceiptLineAdd>
<ItemRef>
<FullName>Book</FullName>
</ItemRef>
<Desc>The Hitchhiker\'s Guide to the Galaxy</Desc>
<Amount>19.95</Amount>
<SalesTaxCodeRef>
<FullName>TAX</FullName>
</SalesTaxCodeRef>
</SalesReceiptLineAdd>
</SalesReceiptAdd>
</SalesReceiptAddRq>
</QBXMLMsgsRq>
</QBXML>';
return $xml;
}
function _quickbooks_salesreceipt_add_response($requestID, $user, $action, $ID, $extra, &$err, $last_action_time, $last_actionident_time, $xml, $idents)
{
// Great, sales receipt $ID has been added to QuickBooks with a QuickBooks
// TxnID value of: $idents['TxnID']
//
// The QuickBooks EditSequence is: $idents['EditSequence']
//
// We probably want to store that TxnID in our database, so we can use it
// later. You might also want to store the EditSequence. If you wanted to
// issue a SalesReceiptMod to modify the sales receipt somewhere down the
// road, you'd need to refer to the sales receipt using the TxnID and
// EditSequence
}
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...');
}
Also I installed only QB POS Server Workstation
You're getting this error message:
0x80045242: QBPOSXML: Unknown request version
Because you're sending requests for the wrong version. These requests:
$xml = '<?xml version="1.0" encoding="utf-8"?>
<?qbxml version="2.0"?>
<QBXML>
<QBXMLMsgsRq onError="stopOnError">
<CustomerAddRq requestID="' . $requestID . '">
<CustomerAdd>
Are for QuickBooks Pro/Premier/Enterprise. They are not QuickBooks Point of Sale requests at all. QuickBooks Point of Sale is a different product family than QuickBooks Pro/Premier/Enterprise.
The library you're using:
https://github.com/consolibyte/quickbooks-php
Has an example that is specifically for QuickBooks Point of Sale:
https://github.com/consolibyte/quickbooks-php/blob/master/docs/web_connector/example_web_connector_point_of_sale.php
And you can see the requests are structured differently (and have different versions and XML headers):
// We're just testing, so we'll just use a static test request:
$xml = '
<?xml version="1.0" encoding="utf-8"?>
<?qbposxml version="3.0"?>
<QBPOSXML>
<QBPOSXMLMsgsRq onError="stopOnError">
<CustomerAddRq>
You can also see the documentation here, which shows these requests:
https://developer.intuit.com/app/developer/qbdesktop/docs/get-started/get-started-with-the-quickbooks-pos-sdk#download-and-install-the-quickbooks-pos-sdk
Related
I'm adding receive payments using php devkit here https://github.com/consolibyte/quickbooks-php.
The problem is no response from the quickbooks and also there is no issue. I checked the web connector logs and php log files.
But response function is not called ever.
I'm pretty sure this was working well until few days ago.
I have no idea what the exact problem is.
qbxml version: 10.0
request xml:
<?xml version="1.0" encoding="utf-8"?>
<?qbxml version="10.0"?>
<QBXML>
<QBXMLMsgsRq onError="continueOnError">
<ReceivePaymentAddRq requestID="153">
<ReceivePaymentAdd>
<CustomerRef >
<FullName >Duncan, Dave</FullName>
</CustomerRef>
<TxnDate >2023-12-15</TxnDate>
<RefNumber>Wire</RefNumber>
<TotalAmount>2585.00</TotalAmount>
<PaymentMethodRef><FullName>Check</FullName></PaymentMethodRef>
<Memo>Paid In Full</Memo>
<AppliedToTxnAdd>
<TxnID>28CA9-1702576301</TxnID>
<PaymentAmount >2585.00</PaymentAmount>
</AppliedToTxnAdd>
</ReceivePaymentAdd>
</ReceivePaymentAddRq>
</QBXMLMsgsRq>
</QBXML>
php scripts:
$map = array(
QUICKBOOKS_ADD_RECEIVE_PAYMENT => array( '_quickbooks_payment_add_request', '_quickbooks_payment_add_response' ));
$errmap = array(
// QUICKBOOKS_IMPORT_CUSTOMER => '_quickbooks_customer_query_error',
'*' => '_quickbooks_error_catchall', // Catch any other errors that might occur
..
$hooks = array(
QuickBooks_WebConnector_Handlers::HOOK_LOGINSUCCESS => '_quickbooks_sync_to_qb', // call this whenever a successful login occurs
);
function _quickbooks_sync_to_qb($requestID, $user, $hook, &$err, $hook_data, $callback_config)
{
$database = new Database();
$db = $database->getConnection();
$Queue = new QuickBooks_WebConnector_Queue($database->dsn);
$payment = new Payment($db);
$payment->needSync = true;
$stmt = $payment->read();
$num = $stmt->rowCount();
if ($num > 0) {
while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
$Queue->enqueue(QUICKBOOKS_ADD_RECEIVE_PAYMENT, $row['id']);
}
}
$database->destroy();
}
function _quickbooks_payment_add_request($requestID, $user, $action, $ID, $extra, &$err, $last_action_time, $last_actionident_time, $version, $locale)
{error_log('start from here');
$database = new Database();
$db = $database->getConnection();
// Grab the data from our MySQL database
$payment = new Payment($db);
$payment->id = (int) $ID;
error_log('1');
// Validation
$stmt = $payment->read();
$num = $stmt->rowCount();
if ($num > 0) {error_log('2');
while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
extract($row);
// get trasaction id from invoice
$invoice = new Invoice($db);
$invoice->refNumber = $invoice_ref_number;
error_log('21');
$xml = '<?xml version="1.0" encoding="utf-8"?>
<?qbxml version="10.0"?>
<QBXML>
<QBXMLMsgsRq onError="continueOnError">
<ReceivePaymentAddRq>
<ReceivePaymentAdd>';
if ($customer_ref_listid != '' || $customer_ref_fullname != '') {
$xml .= '<CustomerRef >';
if ($customer_ref_listid != '') {
$xml .= '<ListID >' . $customer_ref_listid . '</ListID>';
// invoice customer ref listid
$invoice->customerRefListID = $customer_ref_listid;
}
if ($customer_ref_fullname != '') {
$xml .= '<FullName >' . $customer_ref_fullname . '</FullName>';
// invoice customer ref fullname
$invoice->customerRefFullName = $customer_ref_fullname;
}
$xml .= '</CustomerRef>';
}
$stmt = $invoice->read();
$num = $stmt->rowCount();
$txnID = '';
$txnDate = '';
if ($num > 0) {
while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
$txnID = $row['txn_id'];
$txnDate = date_format(date_create($row['txn_date']), 'Y-m-d');
}
}
$xml .= '<TxnDate >' . $txnDate . '</TxnDate>
<RefNumber>' . $ref_number . '</RefNumber>
<TotalAmount>' . $total_amount . '</TotalAmount>
<PaymentMethodRef>';
if (!empty($payment_method_ref_listid)) {
$xml .= '<ListID>' . $payment_method_ref_listid . '</FullName>';
}
if (!empty($payment_method_ref_fullname)) {
$xml .= '<FullName>' . $payment_method_ref_fullname . '</FullName>';
}
$xml .= '</PaymentMethodRef>
<Memo>' . $memo . '</Memo>
<AppliedToTxnAdd>
<TxnID>' . $txnID . '</TxnID>
<PaymentAmount >' . $total_amount . '</PaymentAmount>
</AppliedToTxnAdd>
</ReceivePaymentAdd>
</ReceivePaymentAddRq>
</QBXMLMsgsRq>
</QBXML>';
error_log('22');
}
error_log('3');
$database->destroy();
error_log('4');
error_log($xml);
return $xml;
}
error_log('5');
$database->destroy();
return false;
}
This function seems not called even it is registered properly.
function _quickbooks_payment_add_response($requestID, $user, $action, $ID, $extra, &$err, $last_action_time, $last_actionident_time, $xml, $idents)
{error_log('_quickbooks_payment_add_response');
$database = new Database();
EDIT:
VERBOSE LOG
20190327.20:42:17 UTC : QBWebConnector.SOAPWebService.do_sendRequestXML() : qbNationality="US"
20190327.20:42:17 UTC : QBWebConnector.SOAPWebService.do_sendRequestXML() : qbXMLMajorVers="13"
20190327.20:42:17 UTC : QBWebConnector.SOAPWebService.do_sendRequestXML() : qbXMLMinorVers="0"
20190327.20:42:17 UTC : QBWebConnector.SOAPWebService.do_sendRequestXML() : Received from sendRequestXML() following parameter:
20190327.20:42:17 UTC : QBWebConnector.SOAPWebService.do_sendRequestXML() : strRequestXML =
20190327.20:42:17 UTC : QBWebConnector.SOAPWebService.do_sendRequestXML() : XML dump follows: -
<?xml version="1.0" encoding="utf-8"?>
<?qbxml version="10.0"?>
<QBXML>
<QBXMLMsgsRq onError="continueOnError">
<ReceivePaymentAddRq requestID="158">
<ReceivePaymentAdd><CustomerRef ><FullName >Duncan, Dave</FullName></CustomerRef><RefNumber>Wire</RefNumber>
<TotalAmount>2585.00</TotalAmount>
<PaymentMethodRef><FullName>Check</FullName></PaymentMethodRef>
<Memo>Paid In Full</Memo>
<AppliedToTxnAdd>
<TxnID>28CA9-1702576301</TxnID>
<PaymentAmount >2585.00</PaymentAmount>
</AppliedToTxnAdd>
</ReceivePaymentAdd>
</ReceivePaymentAddRq>
</QBXMLMsgsRq>
</QBXML>
20190327.20:42:17 UTC : QBWebConnector.SOAPWebService.do_sendRequestXML() : Request xml received.
20190327.20:42:17 UTC : QBWebConnector.SOAPWebService.ProcessRequestXML() : Processing request #1
20190327.20:42:17 UTC : QBWebConnector.SOAPWebService.ProcessRequestXML() : REQUEST: received from application: size (bytes) = 666
20190327.20:42:17 UTC : QBWebConnector.SOAPWebService.ProcessRequestXML() : Sending request to QuickBooks.
20190327.20:42:17 UTC : QBWebConnector.SOAPWebService.ProcessRequestXML() : Response received from QuickBooks: size (bytes) = 245
20190327.20:42:17 UTC : QBWebConnector.SOAPWebService.ProcessRequestXML() : Sending response back to application.
20190327.20:42:17 UTC : QBWebConnector.SOAPWebService.do_receiveResponseXML() : *** Calling receiveResponseXML() with following parameters:
20190327.20:42:17 UTC : QBWebConnector.SOAPWebService.do_receiveResponseXML() : wcTicket="35382423-f97d-5fc4-3935-d4a7629367a8"
20190327.20:42:17 UTC : QBWebConnector.SOAPWebService.do_receiveResponseXML() : response =
20190327.20:42:17 UTC : QBWebConnector.SOAPWebService.do_receiveResponseXML() : XML dump follows: -
<?xml version="1.0" ?>
<QBXML>
<QBXMLMsgsRs>
<ReceivePaymentAddRs requestID="158" statusCode="3120" statusSeverity="Error" statusMessage="Object "28CA9-1702576301" specified in the request cannot be found. " />
</QBXMLMsgsRs>
</QBXML>
20190327.20:42:17 UTC : QBWebConnector.SOAPWebService.do_receiveResponseXML() : hresult=""
20190327.20:42:17 UTC : QBWebConnector.SOAPWebService.do_receiveResponseXML() : message=""
20190327.20:42:17 UTC : QBWebConnector.SOAPWebService.do_receiveResponseXML() : Received from receiveResponseXML() following parameters:
20190327.20:42:17 UTC : QBWebConnector.SOAPWebService.do_receiveResponseXML() : more="100">
20190327.20:42:17 UTC : QBWebConnector.SOAPWebService.do_receiveResponseXML() : Done. No more to process.
It's hard to tell without seeing the logs (Web Connector logs in VERBOSE mode and also the quickbooks_log SQL table output) exactly what's wrong here, but here's at least a few things to check:
1. Are you SURE you're not getting a response from QuickBooks?
You indicate "The problem is no response from the quickbooks" but that may not be the actual case here.
Have you verified that you're not getting a response in the actual logs? For example, if an error were to occur (e.g. maybe the customer or the invoice does not exist) then QuickBooks will send back an error but your response function won't get called -- an error handler will get called instead.
Do you have something like this in your code?
$errmap = array(
3070 => '_quickbooks_error_stringtoolong', // Whenever a string is too long to fit in a field, call this function: _quickbooks_error_stringtolong()
// ... more error handlers here ...
);
(from https://github.com/consolibyte/quickbooks-php/blob/master/docs/web_connector/example_web_connector.php )
Maybe an error handler is getting called instead of your response function?
2. You aren't passing a requestID="..." attribute
The Web Connector uses a requestID="..." attribute in the XML to be able to match up the outgoing requests with the incoming responses. You're not using it, but should be.
Change this:
<ReceivePaymentAddRq>
To this:
<ReceivePaymentAddRq requestID="' . $requestID . '">
Read more:
http://wiki.consolibyte.com/wiki/doku.php/quickbooks_integration_php_consolibyte#i_m_getting_the_error_messageno_registered_functions_for_action
3. You're not XML encoding values
For this:
<Memo>' . $memo . '</Memo>
If $memo is set to bla bla <something> bla bla then you're going to end up with malformed XML:
<Memo>bla bla <something bla bla</Memo>
You should be XML-encoding these values.
4. The $memo variable is undefined
You're saying that your resulting XML looks like this:
<Memo>Paid In Full</Memo>
But when I look at your code, $memo is undefined. This makes me suspect that the XML you pasted here is not the actual XML you're sending to QuickBooks.
Where does that variable get set to Paid In Full? It doesn't get set anywhere in the code you pasted.
This should also be causing a PHP error/warning about an undefined variable, which could be breaking things.
5. Make sure your Web Connector is in VERBOSE mode
VERBOSE mode in the Web Connector shows a lot more data. You should be able to easily find the request in question and analyze/post the relevant logs.
6. Check the quickbooks_log and quickbooks_queue tables
What do they show/say?
What is the status (qb_status field) and message on the queued up record (quickbooks_queue SQL table)?
I want to exchange data(customer,invoice,order etc) between Quickbook Desktop and my website using REST API . I am using quickbook web connector and Consolibyte PHP SDK (https://github.com/consolibyte/quickbooks-php) for this purpose. I have installed web connector and configured PHP SDK also load example.qwc in web connector with my configuration.
Now I am able to create new customer to Quickbook Desktop when new customer is added to my website using this file and folder of PHP SDK(quickbooks-php/docs/web_connector). This is working fine Now I am looking for whenever new record(customer,invoice etc) is created on Quickbook Desktop that should be created on my website.How can I send this data to my website
Issues:
Is web connector automatically maintain two way communication or I need to write some PHP Soap web services code to read data from quickbook desktop.
How I know new customer,invoice, order is created on Quick book Desktop.and then how can I send this new data to my website.
1.Is web connector automatically maintain two way communication
The Web Connector does not automatically do ANYTHING.
Anything you want to happen, you need to write code for. The SDK handles a lot of the hard protocol stuff for you, but you still need to write some code.
2.How I know new customer,invoice, order is created on Quick book Desktop
You need to query QuickBooks for that data. There are examples that show you how to do this:
https://github.com/consolibyte/quickbooks-php/blob/master/docs/web_connector/example_web_connector_import.php
Basically, you're going to:
1. Add something new to your $map variable:
`QUICKBOOKS_IMPORT_INVOICE => array( '_quickbooks_invoice_import_request', '_quickbooks_invoice_import_response' ),`
2. Write those two new functions that the $map variable references.
The request function is going to return a qbXML request to query for new invoices, and the response function is going to handle the big list of new invoices that QuickBooks returns to you (in the example below, it stores them in a MySQL database):
/**
* Build a request to import invoices already in QuickBooks into our application
*/
function _quickbooks_invoice_import_request($requestID, $user, $action, $ID, $extra, &$err, $last_action_time, $last_actionident_time, $version, $locale)
{
// Iterator support (break the result set into small chunks)
$attr_iteratorID = '';
$attr_iterator = ' iterator="Start" ';
if (empty($extra['iteratorID']))
{
// This is the first request in a new batch
$last = _quickbooks_get_last_run($user, $action);
_quickbooks_set_last_run($user, $action); // Update the last run time to NOW()
// Set the current run to $last
_quickbooks_set_current_run($user, $action, $last);
}
else
{
// This is a continuation of a batch
$attr_iteratorID = ' iteratorID="' . $extra['iteratorID'] . '" ';
$attr_iterator = ' iterator="Continue" ';
$last = _quickbooks_get_current_run($user, $action);
}
// Build the request
$xml = '<?xml version="1.0" encoding="utf-8"?>
<?qbxml version="' . $version . '"?>
<QBXML>
<QBXMLMsgsRq onError="stopOnError">
<InvoiceQueryRq ' . $attr_iterator . ' ' . $attr_iteratorID . ' requestID="' . $requestID . '">
<MaxReturned>' . QB_QUICKBOOKS_MAX_RETURNED . '</MaxReturned>
<ModifiedDateRangeFilter>
<FromModifiedDate>' . $last . '</FromModifiedDate>
</ModifiedDateRangeFilter>
<IncludeLineItems>true</IncludeLineItems>
<OwnerID>0</OwnerID>
</InvoiceQueryRq>
</QBXMLMsgsRq>
</QBXML>';
return $xml;
}
/**
* Handle a response from QuickBooks
*/
function _quickbooks_invoice_import_response($requestID, $user, $action, $ID, $extra, &$err, $last_action_time, $last_actionident_time, $xml, $idents)
{
if (!empty($idents['iteratorRemainingCount']))
{
// Queue up another request
$Queue = QuickBooks_WebConnector_Queue_Singleton::getInstance();
$Queue->enqueue(QUICKBOOKS_IMPORT_INVOICE, null, QB_PRIORITY_INVOICE, array( 'iteratorID' => $idents['iteratorID'] ));
}
// This piece of the response from QuickBooks is now stored in $xml. You
// can process the qbXML response in $xml in any way you like. Save it to
// a file, stuff it in a database, parse it and stuff the records in a
// database, etc. etc. etc.
//
// The following example shows how to use the built-in XML parser to parse
// the response and stuff it into a database.
// Import all of the records
$errnum = 0;
$errmsg = '';
$Parser = new QuickBooks_XML_Parser($xml);
if ($Doc = $Parser->parse($errnum, $errmsg))
{
$Root = $Doc->getRoot();
$List = $Root->getChildAt('QBXML/QBXMLMsgsRs/InvoiceQueryRs');
foreach ($List->children() as $Invoice)
{
$arr = array(
'TxnID' => $Invoice->getChildDataAt('InvoiceRet TxnID'),
'TimeCreated' => $Invoice->getChildDataAt('InvoiceRet TimeCreated'),
'TimeModified' => $Invoice->getChildDataAt('InvoiceRet TimeModified'),
'RefNumber' => $Invoice->getChildDataAt('InvoiceRet RefNumber'),
'Customer_ListID' => $Invoice->getChildDataAt('InvoiceRet CustomerRef ListID'),
'Customer_FullName' => $Invoice->getChildDataAt('InvoiceRet CustomerRef FullName'),
'ShipAddress_Addr1' => $Invoice->getChildDataAt('InvoiceRet ShipAddress Addr1'),
'ShipAddress_Addr2' => $Invoice->getChildDataAt('InvoiceRet ShipAddress Addr2'),
'ShipAddress_City' => $Invoice->getChildDataAt('InvoiceRet ShipAddress City'),
'ShipAddress_State' => $Invoice->getChildDataAt('InvoiceRet ShipAddress State'),
'ShipAddress_PostalCode' => $Invoice->getChildDataAt('InvoiceRet ShipAddress PostalCode'),
'BalanceRemaining' => $Invoice->getChildDataAt('InvoiceRet BalanceRemaining'),
);
QuickBooks_Utilities::log(QB_QUICKBOOKS_DSN, 'Importing invoice #' . $arr['RefNumber'] . ': ' . print_r($arr, true));
foreach ($arr as $key => $value)
{
$arr[$key] = mysql_real_escape_string($value);
}
// Store the invoices in MySQL
mysql_query("
REPLACE INTO
qb_example_invoice
(
" . implode(", ", array_keys($arr)) . "
) VALUES (
'" . implode("', '", array_values($arr)) . "'
)") or die(trigger_error(mysql_error()));
// Remove any old line items
mysql_query("DELETE FROM qb_example_invoice_lineitem WHERE TxnID = '" . mysql_real_escape_string($arr['TxnID']) . "' ") or die(trigger_error(mysql_error()));
// Process the line items
foreach ($Invoice->children() as $Child)
{
if ($Child->name() == 'InvoiceLineRet')
{
$InvoiceLine = $Child;
$lineitem = array(
'TxnID' => $arr['TxnID'],
'TxnLineID' => $InvoiceLine->getChildDataAt('InvoiceLineRet TxnLineID'),
'Item_ListID' => $InvoiceLine->getChildDataAt('InvoiceLineRet ItemRef ListID'),
'Item_FullName' => $InvoiceLine->getChildDataAt('InvoiceLineRet ItemRef FullName'),
'Descrip' => $InvoiceLine->getChildDataAt('InvoiceLineRet Desc'),
'Quantity' => $InvoiceLine->getChildDataAt('InvoiceLineRet Quantity'),
'Rate' => $InvoiceLine->getChildDataAt('InvoiceLineRet Rate'),
);
foreach ($lineitem as $key => $value)
{
$lineitem[$key] = mysql_real_escape_string($value);
}
// Store the lineitems in MySQL
mysql_query("
INSERT INTO
qb_example_invoice_lineitem
(
" . implode(", ", array_keys($lineitem)) . "
) VALUES (
'" . implode("', '", array_values($lineitem)) . "'
) ") or die(trigger_error(mysql_error()));
}
}
}
}
return true;
}
3. Make sure that every time the Web Connector connects, you automatically send it that query to get those new invoices.
Register a hook like this:
// An array of callback hooks
$hooks = array(
QuickBooks_WebConnector_Handlers::HOOK_LOGINSUCCESS => '_quickbooks_hook_loginsuccess', // call this whenever a successful login occurs
);
That always queues up a request to get invoices:
function _quickbooks_hook_loginsuccess($requestID, $user, $hook, &$err, $hook_data, $callback_config)
{
$Queue->enqueue(QUICKBOOKS_IMPORT_INVOICE, 1, QB_PRIORITY_INVOICE);
}
You'll want to make sure to look at the example I linked above for a few of the helper functions if you're going to re-use the code I pasted above.
If you have trouble, please POST YOUR CODE so we can see what you're tried so far.
Hello guys I'm following this tutorial 'QuickBooks OAuth – PHP Example' to set up the api and get the data from the quickbooks. I have successfully setup the api but the problem that I'm facing now is that I'm unable to get the data from the quick books. It always returns me null even though their is alot of data present over there
Here is the code to what I'm doing.
config.php
<?php
// setting up session
/* note: This is not a secure way to store oAuth tokens. You should use a secure
* data sore. We use this for simplicity in this example.
*/
// session_save_path('./abc/temp');
session_save_path('./abc/temp');
session_start();
echo "<h4>If you see a Session warning above you need to run the command: 'chmod 777 temp' in the terminal on the code page. </h4>";
define('OAUTH_CONSUMER_KEY', 'some key');
define('OAUTH_CONSUMER_SECRET', 'some key');
if(strlen(OAUTH_CONSUMER_KEY) < 5 OR strlen(OAUTH_CONSUMER_SECRET) < 5 ){
echo "<h3>Set the consumer key and secret in the config.php file before you run this example</h3>";
}
?>
index.php
<?php
require_once("./config.php");
?>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>My Connect Page</title>
<script type="text/javascript" src="https://appcenter.intuit.com/Content/IA/intuit.ipp.anywhere.js"></script>
<script>
// Runnable uses dynamic URLs so we need to detect our current //
// URL to set the grantUrl value ########################### //
/*######*/ var parser = document.createElement('a');/*#########*/
/*######*/parser.href = document.url;/*########################*/
// end runnable specific code snipit ##########################//
intuit.ipp.anywhere.setup({
menuProxy: '',
grantUrl: 'http://'+parser.hostname+'/QuickbooksTest/oauth.php?start=t'
// outside runnable you can point directly to the oauth.php page
});
</script>
</head>
</head>
<body>
<?php
require_once('./v3-php-sdk-2.3.0/config.php'); // Default V3 PHP SDK (v2.0.1) from IPP
require_once(PATH_SDK_ROOT . 'Core/ServiceContext.php');
require_once(PATH_SDK_ROOT . 'DataService/DataService.php');
require_once(PATH_SDK_ROOT . 'PlatformService/PlatformService.php');
require_once(PATH_SDK_ROOT . 'Utility/Configuration/ConfigurationManager.php');
error_reporting(E_ERROR | E_PARSE);
// print connect to QuickBooks button to the page
echo "<ipp:connectToIntuit></ipp:connectToIntuit><br />";
// After the oauth process the oauth token and secret
// are storred in session variables.
if(!isset($_SESSION['token'])){
echo "<h3>You are not currently authenticated</h3>";
} else {
$token = unserialize($_SESSION['token']);
$requestValidator = new OAuthRequestValidator(
$token['oauth_token'], $token['oauth_token_secret'], OAUTH_CONSUMER_KEY, OAUTH_CONSUMER_SECRET);
$realmId = $_SESSION['realmId'];
// uncomment any of these to see more information
//echo "realmId: $realmId <br />";
//echo "oauth token: ". $token['oauth_token'] . "<br />";
//echo "oauth secret: ". $token['oauth_token'] . "<br />";
/*echo "<pre><h2>Session Variables</h2>";
var_dump($_SESSION);
echo "</pre>"; */
$serviceType = $_SESSION['dataSource'];
$serviceContext = new ServiceContext($realmId, $serviceType, $requestValidator);
$dataService = new DataService($serviceContext);
// $startPosition = 1;
// $maxResults = 10;
// $allCustomers = $dataService->FindAll('Customer', $startPosition, $maxResults);
$allCustomers = $dataService->Query("SELECT * FROM Customer");
echo "<pre><h2>Customers List</h2>";
var_dump($allCustomers);
echo "</pre>";
}
?>
</body>
</html>
UPDATED INDEx
<?php
require_once("./config.php");
?>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>My Connect Page</title>
<script type="text/javascript" src="https://appcenter.intuit.com/Content/IA/intuit.ipp.anywhere.js"></script>
<script>
// Runnable uses dynamic URLs so we need to detect our current //
// URL to set the grantUrl value ########################### //
/*######*/ var parser = document.createElement('a');/*#########*/
/*######*/parser.href = document.url;/*########################*/
// end runnable specific code snipit ##########################//
intuit.ipp.anywhere.setup({
menuProxy: '',
grantUrl: 'http://'+parser.hostname+'/testProject/oauth.php?start=t'
// outside runnable you can point directly to the oauth.php page
});
</script>
</head>
</head>
<body>
<intuit>
<ipp>
<logger>
<!-- To enable/disable Request and Response log-->
<requestLog enableRequestResponseLogging="true" requestResponseLoggingDirectory="C:\IdsLogs" />
</logger>
</ipp>
</intuit>
<?php
require_once('./v3-php-sdk-2.3.0/config.php'); // Default V3 PHP SDK (v2.0.1) from IPP
require_once(PATH_SDK_ROOT . 'Core/ServiceContext.php');
require_once(PATH_SDK_ROOT . 'DataService/DataService.php');
require_once(PATH_SDK_ROOT . 'PlatformService/PlatformService.php');
require_once(PATH_SDK_ROOT . 'Utility/Configuration/ConfigurationManager.php');
require_once(PATH_SDK_ROOT . 'QueryFilter/QueryMessage.php');
error_reporting(E_ERROR | E_PARSE);
// print connect to QuickBooks button to the page
echo "<ipp:connectToIntuit></ipp:connectToIntuit><br />";
// After the oauth process the oauth token and secret
// are storred in session variables.
if(!isset($_SESSION['token'])){
echo "<h3>You are not currently authenticated</h3>";
} else {
$token = unserialize($_SESSION['token']);
$requestValidator = new OAuthRequestValidator(
$token['oauth_token'], $token['oauth_token_secret'], OAUTH_CONSUMER_KEY, OAUTH_CONSUMER_SECRET);
$realmId = $_SESSION['realmId'];
error_log($realmId);
// uncomment any of these to see more information
//echo "realmId: $realmId <br />";
//echo "oauth token: ". $token['oauth_token'] . "<br />";
//echo "oauth secret: ". $token['oauth_token'] . "<br />";
/*echo "<pre><h2>Session Variables</h2>";
var_dump($_SESSION);
echo "</pre>"; */
// error_log("Value in dataSource session is: " . $_SESSION['dataSource']);
// $serviceType = $_SESSION['dataSource']; //5:15 PM
$serviceType = IntuitServicesType::QBO; //5:16 PM
$serviceContext = new ServiceContext($realmId, $serviceType, $requestValidator);
$dataService = new DataService($serviceContext);
// $startPosition = 1;
// $maxResults = 10;
// $allCustomers = $dataService->FindAll('Customer', $startPosition, $maxResults);
// $allCustomers = $dataService->Query("SELECT * FROM Customer");
$allCustomers = $dataService->FindAll('Customer');
// $oneQuery = new QueryMessage();
// $oneQuery->sql = "SELECT";
// $oneQuery->entity = "Customer";
// $oneQuery->orderByClause = "FamilyName";
// Run a query
// $queryString = $oneQuery->getString();
// $allCustomers = $dataService->Query($queryString);
// $ch = curl_init("http://www.example.com/");
// $fp = fopen("example_homepage.txt", "w");
// curl_setopt($ch, CURLOPT_FILE, $fp);
// curl_setopt($ch, CURLOPT_HEADER, 0);
// curl_exec($ch);
// curl_close($ch);
// fclose($fp);
echo "<pre><h2>Customers List</h2>";
var_dump($allCustomers);
echo "</pre>";
}
?>
</body>
</html>
***APP.CONFIG*
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<intuit>
<ipp>
<!--Json serialization not supported in PHP SDK v2.0.0 -->
<message>
<request serializationFormat="Xml" compressionFormat="None"/>
<response serializationFormat="Xml" compressionFormat="None"/>
</message>
<service>
<baseUrl qbd="https://quickbooks.api.intuit.com/" qbo="https://quickbooks.api.intuit.com/" ipp="https://appcenter.intuit.com/api/" />
</service>
<logger>
<!-- To enable/disable Request and Response log-->
<requestLog enableRequestResponseLogging="true" requestResponseLoggingDirectory="./IdsLogs" />
</logger>
</ipp>
</intuit>
</configuration>
I am trying to do force download using ZF2. Here is the snippet to my code
use Zend\Http\Request;
.....
public function downloadAction() {
$response = new Request();
$response->setHeaders(Request::fromString("Content-Type: application/octet-stream\r\nContent-Length: 9\r\nContent-Disposition: attachment; filename=\"ultimate_remedy_readme.txt\""));
}
now i am getting this error
/var/www/whowantsmymoney/vendor/zendframework/zendframework/library/Zend/Http/Request.php:88
Message:
A valid request line was not found in the provided string
Stack trace:
#0 /var/www/whowantsmymoney/module/Admin/src/Admin/Controller/LanguageController.php(93): Zend\Http\Request::fromString('Content-Type: a...')
This code should help you for a simple file download.
public function downloadAction() {
$fileName = 'somefile';
if(!is_file($fileName)) {
//do something
}
$fileContents = file_get_contents($fileName);
$response = $this->getResponse();
$response->setContent($fileContents);
$headers = $response->getHeaders();
$headers->clearHeaders()
->addHeaderLine('Content-Type', 'whatever your content type is')
->addHeaderLine('Content-Disposition', 'attachment; filename="' . $fileName . '"')
->addHeaderLine('Content-Length', strlen($fileContents));
return $this->response;
}
I imagine this code leaves a lot to be desired, but should work in simple cases, as was mine. I'm not sure how you might handle reading the file in chunks. Maybe somebody else could shed some light?
Edit - Sending streams
I've added this here for informational purposes. It is probably the better way to force downloads as it will use much less memory.
public function downloadAction() {
$fileName = 'somefile';
$response = new \Zend\Http\Response\Stream();
$response->setStream(fopen($fileName, 'r'));
$response->setStatusCode(200);
$headers = new \Zend\Http\Headers();
$headers->addHeaderLine('Content-Type', 'whatever your content type is')
->addHeaderLine('Content-Disposition', 'attachment; filename="' . $fileName . '"')
->addHeaderLine('Content-Length', filesize($fileName));
$response->setHeaders($headers);
return $response;
Thanks to #Aydin Hassan for response, but several important headers are missing in his answer. Be careful of that.
Full headers stack:
public function downloadAction() {
$file = 'path/to/file';
$response = new \Zend\Http\Response\Stream();
$response->setStream(fopen($file, 'r'));
$response->setStatusCode(200);
$response->setStreamName(basename($file));
$headers = new \Zend\Http\Headers();
$headers->addHeaders(array(
'Content-Disposition' => 'attachment; filename="' . basename($file) .'"',
'Content-Type' => 'application/octet-stream',
'Content-Length' => filesize($file),
'Expires' => '#0', // #0, because zf2 parses date as string to \DateTime() object
'Cache-Control' => 'must-revalidate',
'Pragma' => 'public'
));
$response->setHeaders($headers);
return $response;
}
I was using basic auth to send tweets from a server every time a song changed. Now they have blocked basic auth and I am not sure how to incorporate it. I have a server at home that updates an html file on the webserver and then calls the following script to tweet out from that file. Any ideas on how to accomplish this simply?
<?php
//====================================================
// CONFIGURATION
//====================================================
// YOUR TWITTER USERNAME AND PASSWORD
$username = '#####';
$password = '#####';
DEFINE(htmlfile, '/homec/public_html/site.com/twitter.html');
$stationURL = "http://www.site.com";
$maxLimit = "139";
$da="";
$f=#fopen(htmlfile, "r");
if ($f!=0)
{
$da=#fread($f, 4096);
fclose($f);
}
else
{
exit;
}
$da=str_replace("\r", "\n", $da);
$da=str_replace("\n\n", "\n", $da);
$d=explode("\n", $da);
$d[0]=trim($d[0], "|"); // title
$d[1]=trim($d[1], "|"); // artist
//====================================================
if ($d[0]=="" || $d[1]=="")
{
// IF WE COULD NOT GRAB THE ARTIST AND
// SONG TITLE FROM THE SAM-GENERATED HTML FILE,
// WE'LL BAIL OUT NOW WITHOUT SUBMITTING ANY TEXT
// TO TWITTER.
exit;
}
else
{
// SUCCESS IN GETTING ARTIST AND TITLE!
// WE'LL PROCEED WITH BUILDING A TEXT STRING TO SUBMIT TO TWITTER.
$message = urlencode('' . $d[1] . ' - ' . $d[0] . ' #bandradio #nowplaying ');
$stationURL = urlencode(' ' . $stationURL);
if ((strlen($message) + strlen($stationURL)) > $maxLimit)
{
// We have to truncate the artist-title string to make room for the station URL string.
$message = substr($message, 0, (($maxLimit - 2) - strlen($stationURL)));
$message .= ".." . $stationURL;
}
else
{
// No need to truncate, it all fits.
$message = $message . $stationURL;
}
} // if ($d[0]=="" || $d[1]=="")
//====================================================
// The twitter API address
$url = 'http://twitter.com/statuses/update.json';
// Set up and execute the curl process
$curl_handle = curl_init();
curl_setopt($curl_handle, CURLOPT_URL, "$url");
curl_setopt($curl_handle, CURLOPT_CONNECTTIMEOUT, 2);
curl_setopt($curl_handle, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($curl_handle, CURLOPT_POST, 1);
//curl_setopt($curl_handle, CURLOPT_POSTFIELDS, "status=$message");
//curl_setopt($curl_handle, CURLOPT_USERPWD, "$username:$password");
$buffer = curl_exec($curl_handle);
$resultArray = curl_getinfo($curl_handle);
curl_close($curl_handle);
Download the latest version of TwitterOAuth from http://github.com/abraham/twitteroauth/downloads Unpack the download and place the twitteroauth.php and OAuth.php files in the same directory as a file with the following code. Register an application at http://dev.twitter.com/apps and from your new apps details page click on "my access token" to get your access token. Fill the four required variables into the script below and you can then run it to post new tweets.
<?php
require_once('twitteroauth.php');
$connection = new TwitterOAuth('app consumer key', 'app consumer secret', 'my access token', 'my access token secret');
$connection->post('statuses/update', array('status' => 'text to be tweeted'));