I am facing a problem while adding a new invoice line in existing invoice from Mysql database.
I have synced the invoice from quickbook to MySql. Two-way sync is working between quickbook and mysql.
The problem is when I add a new invoicline in qb_invoice_invoicline table, It does not sync with Quickbook. Following error I received in qb_invoice table. qbsql_last_errnum 320 last_error_msg
Object "64-1518123234" specified in the request cannot be found. (here 64-1518123234 is the value in qb_invoice_invoiceline.TxnLineID coulmn).If I leave this field blank then there is a parsing error when syncing.
Following is the code I am using to sync.
<?php
error_reporting(E_ERROR | E_PARSE);
ini_set('display_errors', 1);
require_once dirname(__FILE__) . '/QuickBooks.php';
require_once 'Common/Constants.php';
require_once 'Common/Utility.php';
require_once 'Common/Hook.php';
if (function_exists('date_default_timezone_set'))
{
date_default_timezone_set(TIMEZONE);
}
if(!isset($_GET['companyId'])) {
trigger_error('Error! Parameter "CompanyId" missing in API.', E_USER_ERROR);
return;
}
$companyId = $_GET['companyId'];
$companyConfig = file_get_contents('config.json');
$companyData = json_decode($companyConfig, true);
if(!isset($companyData['company'][$companyId])) {
trigger_error('Error! Company detail not found in config file.', E_USER_ERROR);
return;
}
// The username and password the Web Connector will use to connect with
$username = $companyData['company'][$companyId]['web_connector_username'];
$password = $companyData['company'][$companyId]['web_connector_password'];
// get Company Database credentials
$db = $companyData['company'][$companyId];
$dsn = 'mysqli://' . $db['username'] . ':' . $db['password'] . '#' . $db['host'] . '/' . $db['db_name'];
// If the database has not been initialized, we need to initialize it (create
// schema and set up the username/password, etc.)
if (!QuickBooks_Utilities::initialized($dsn))
{
header('Content-Type: text/plain');
// It takes a really long time to build the schema...
set_time_limit(0);
$driver_options = array(
);
$init_options = array(
'quickbooks_sql_enabled' => true,
);
QuickBooks_Utilities::initialize($dsn, $driver_options, $init_options);
QuickBooks_Utilities::createUser($dsn, $username, $password);
exit;
}
$mode = QuickBooks_WebConnector_Server_SQL::MODE_READWRITE;
$conflicts = QuickBooks_WebConnector_Server_SQL::CONFLICT_LOG;
$delete = QuickBooks_WebConnector_Server_SQL::DELETE_FLAG; // Just flag it as deleted
$hook_obj = Hook::getInstance($companyId);
$hooks = array(
QuickBooks_SQL::HOOK_SQL_INSERT => array(
'preHookHandler',
array( $hook_obj, 'insertHook' ),
),
QuickBooks_SQL::HOOK_SQL_UPDATE => array(
'preHookHandler',
array( $hook_obj, 'updateHook' ),
),
);
function preHookHandler($requestID, $user, $hook, &$err, $hook_data, $callback_config)
{
return true;
}
$soap_options = array();
$handler_options = array(
'deny_concurrent_logins' => false,
'deny_reallyfast_logins' => false,
);
$driver_options = array();
$ops = array(
QUICKBOOKS_OBJECT_ACCOUNT,
QUICKBOOKS_OBJECT_SALESTAXITEM,
QUICKBOOKS_OBJECT_SALESTAXCODE,
QUICKBOOKS_OBJECT_CUSTOMER,
QUICKBOOKS_OBJECT_VENDOR,
QUICKBOOKS_OBJECT_INVENTORYITEM,
QUICKBOOKS_OBJECT_TEMPLATE,
QUICKBOOKS_OBJECT_CUSTOMERTYPE,
QUICKBOOKS_OBJECT_VENDORTYPE,
QUICKBOOKS_OBJECT_ESTIMATE,
QUICKBOOKS_OBJECT_INVOICE,
QUICKBOOKS_OBJECT_CLASS,
QUICKBOOKS_OBJECT_UNITOFMEASURESET,
QUICKBOOKS_ADD_UNITOFMEASURESET,
QUICKBOOKS_MOD_UNITOFMEASURESET,
QUICKBOOKS_QUERY_UNITOFMEASURESET,
QUICKBOOKS_IMPORT_UNITOFMEASURESET,
QUICKBOOKS_OBJECT_STANDARDTERMS,
QUICKBOOKS_OBJECT_INVENTORYITEM,
QUICKBOOKS_OBJECT_NONINVENTORYITEM,
QUICKBOOKS_OBJECT_SERVICEITEM,
QUICKBOOKS_OBJECT_SHIPMETHOD,
QUICKBOOKS_OBJECT_PAYMENTMETHOD,
QUICKBOOKS_OBJECT_TERMS,
QUICKBOOKS_OBJECT_PRICELEVEL,
QUICKBOOKS_OBJECT_ITEM,
QUICKBOOKS_ADD_SERVICEITEM,
QUICKBOOKS_MOD_SERVICEITEM,
QUICKBOOKS_QUERY_SERVICEITEM,
QUICKBOOKS_IMPORT_SERVICEITEM,
QUICKBOOKS_OBJECT_RECEIVEPAYMENT,
QUICKBOOKS_ADD_RECEIVE_PAYMENT,
QUICKBOOKS_MOD_RECEIVE_PAYMENT,
QUICKBOOKS_QUERY_RECEIVE_PAYMENT,
QUICKBOOKS_IMPORT_RECEIVE_PAYMENT,
QUICKBOOKS_DERIVE_RECEIVE_PAYMENT,
QUICKBOOKS_OBJECT_PAYMENTMETHOD,
QUICKBOOKS_OBJECT_COMPANY,
QUICKBOOKS_OBJECT_HOST,
QUICKBOOKS_OBJECT_PREFERENCES,
QUICKBOOKS_QUERY_DELETEDTRANSACTIONS,
QUICKBOOKS_OBJECT_SALESREP,
QUICKBOOKS_OBJECT_DATAEXT,
QUICKBOOKS_ADD_DATAEXT,
QUICKBOOKS_MOD_DATAEXT,
QUICKBOOKS_OBJECT_DATAEXTDEF,
QUICKBOOKS_ADD_DATAEXTDEF,
QUICKBOOKS_MOD_DATAEXTDEF
);
$ops_misc = array( // For fetching inventory levels, deleted transactions, etc.
QUICKBOOKS_DERIVE_INVENTORYLEVELS,
QUICKBOOKS_QUERY_DELETEDLISTS,
QUICKBOOKS_QUERY_DELETEDTRANSACTIONS
// 'nothing',
);
//
$sql_options = array(
'only_import' => $ops,
'only_add' => $ops,
'only_modify' => $ops,
'only_misc' => $ops_misc,
);
//
$callback_options = array();
$Server = new QuickBooks_WebConnector_Server_SQL(
$dsn,
'1 minute',
$mode,
$conflicts,
$delete,
$username,
array(),
array(),
$hooks,
QUICKBOOKS_LOG_DEVELOP,
QUICKBOOKS_SOAPSERVER_BUILTIN,
QUICKBOOKS_WSDL,
$soap_options,
$handler_options,
$driver_options,
$sql_options,
$callback_options);
$Server->handle(true, true);
To summarize the problem what value should be in (qb_invoice_invoiceline.TxnLineID) column to add a new invoiceline ?
If you are trying to just add a line, set the TxnLineID to -1 for all the new line items.
For example, if your Invoice has line items with IDs A/B/C, and you want to append another line, your mod should be something like:
...
<InvoiceLineMod><TxnLineID>A</TxnLineID><InvoiceLineMod>
<InvoiceLineMod><TxnLineID>B</TxnLineID><InvoiceLineMod>
<InvoiceLineMod><TxnLineID>C</TxnLineID><InvoiceLineMod>
<InvoiceLineMod>
<TxnLineID>-1</TxnLineID>
< ... other required values... >
<InvoiceLineMod>
...
If you wanted to delete line B, just send
<InvoiceLineMod><TxnLineID>A</TxnLineID><InvoiceLineMod>
<InvoiceLineMod><TxnLineID>C</TxnLineID><InvoiceLineMod>
Related
below is my we_connector file.php which is uploaded on server with customer add function
and my software is uploaded on a server. i want to add the online url but web connector is showing error "QuickBooks Web Connector could not verify the web application server certificate.".
error_reporting(E_ALL | E_STRICT);
ini_set('display_errors', 1);
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';
$user = 'quickbooks';
$pass = 'password';
$map = array(
QUICKBOOKS_ADD_CUSTOMER => array( '_quickbooks_customer_add_request', '_quickbooks_customer_add_response' ),
);
// 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
);
/*
function _quickbooks_hook_loginsuccess($requestID, $user, $hook, &$err, $hook_data, $callback_config)
{
// Do something whenever a successful login occurs...
}
*/
// Logging level
//$log_level = QUICKBOOKS_LOG_NORMAL;
//$log_level = QUICKBOOKS_LOG_VERBOSE;
$log_level = QUICKBOOKS_LOG_DEBUG;
//$log_level = QUICKBOOKS_LOG_DEVELOP; // Use this level until you're sure everything works!!!
// What SOAP server you're using
//$soapserver = QUICKBOOKS_SOAPSERVER_PHP; // The PHP SOAP extension, see: www.php.net/soap
$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://water_ways_user:zAEGQKI74YHyz6Do#localhost/water_ways';
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,$priority);
}
$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)
{
$myHost = "localhost"; // use your real host name
$myUserName = "water_ways_user"; // use your real login user name
$myPassword = "zAEGQKI74YHyz6Do"; // use your real login password
$myDataBaseName = "water_ways"; // use your real database name
$con = mysqli_connect( "$myHost", "$myUserName", "$myPassword", "$myDataBaseName" );
if( !$con ) // == null if creation of connection object failed
{
// report the error to the user, then exit program
die("connection object not created: ".mysqli_error($con));
}
if( mysqli_connect_errno() ) // returns false if no error occurred
{
// report the error to the user, then exit program
die("Connect failed: ".mysqli_connect_errno()." : ". mysqli_connect_error());
}
// Fetch your customer record from your database
$name='';
$company_name = '';
$address1='';
$address2 ='';
$phone = '';
$contact = '';
$email = '';
$row = mysqli_fetch_array(mysqli_query($con,"SELECT * FROM customer_info WHERE customer_info_id ='$ID'"));
//$sql=mysqli_query($con,"SELECT * FROM customer_info WHERE customer_info_id ='3'");
//if($row = mysqli_fetch_assoc($sql))
// {
// Create and return a qbXML request
$name=$row['customer_name'];
$company_name = $row['company_name'];
$address1=$row['address_1'];
$address2 =$row['address_2'];
$phone = $row['phone_number'];
$contact = $row['customer_name'];
$email = $row['email'];
$qbxml = '<?xml version="1.0" encoding="utf-8"?>
<?qbxml version="2.0"?>
<QBXML>
<QBXMLMsgsRq onError="stopOnError">
<CustomerAddRq requestID="'.$requestID.'">
<CustomerAdd>
<Name>' . $name . '</Name>
<CompanyName>' . $company_name . '</CompanyName>
<BillAddress>
<Addr1>' . $address1 . '</Addr1>
</BillAddress>
<ShipAddress>
<Addr1>' . $address2 . '</Addr1>
</ShipAddress>
<Phone>' . $phone . '</Phone>
<Email>' . $email . '</Email>
<Contact>' . $contact . '</Contact>
</CustomerAdd>
</CustomerAddRq>
</QBXMLMsgsRq>
</QBXML>';
return $qbxml;
}
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.
$myHost = "localhost"; // use your real host name
$myUserName = "water_ways_user"; // use your real login user name
$myPassword = "zAEGQKI74YHyz6Do"; // use your real login password
$myDataBaseName = "water_ways"; // use your real database name
$con = mysqli_connect( "$myHost", "$myUserName", "$myPassword", "$myDataBaseName" );
if( !$con ) // == null if creation of connection object failed
{
// report the error to the user, then exit program
die("connection object not created: ".mysqli_error($con));
}
if( mysqli_connect_errno() ) // returns false if no error occurred
{
// report the error to the user, then exit program
die("Connect failed: ".mysqli_connect_errno()." : ". mysqli_connect_error());
}
mysqli_query($con,"UPDATE customer_info SET quickbooks_listid = '" . mysqli_escape_string($con,$idents['ListID']) . "',edit_sequence = '" . mysqli_escape_string($con,$idents['EditSequence']) . "' WHERE customer_info_id = " . (int) $ID);
}
this is my .qwc file which is on my local machine.
<?xml version="1.0"?>
<QBWCXML>
<AppName>Water Ways</AppName>
<AppID></AppID>
<AppURL>https://pcits.co.in/water_ways/quickbooks-php-master/docs/web_connector/web_connector.php</AppURL>
<AppDescription></AppDescription>
<AppSupport>https://pcits.co.in/water_ways/</AppSupport>
<CertURL>https://pcits.co.in/water_ways</CertURL>
<UserName>quickbooks</UserName>
<OwnerID>{90A44FB7-33D9-4815-AC85-AC86A7E7D1EB}</OwnerID>
<FileID>{57F3B9B6-86F1-4fcc-B1FF-967DE1813D20}</FileID>
<QBType>QBFS</QBType>
<Scheduler>
<RunEveryNMinutes>5</RunEveryNMinutes>
</Scheduler>
<IsReadOnly>false</IsReadOnly>
</QBWCXML>
and i am getting error as "QuickBooks Web Connector could not verify the web application server certificate."
This error message:
QuickBooks Web Connector could not verify the web application server certificate.
Means that your domain name (e.g. the domain shown in the AppURL):
https://pcits.co.in/
Does not have a valid SSL/TLS certificate.
Talk to your website hosting company/administrator, and ask them to issue/install/configure a secure SSL certificate.
I am trying to implement two way syncing with quickbook using consolibyte library. I have used consolibyte example file "example_mysql_mirror.php". It creates around 139 tables and import data from Quickbook successfully.
When I made some changes in Quickbook and MySql database, Quickbook changes reflects in MySql database but MySql dabase changes does not appear in Quickbook.
I am using QuickBook enterprise 2018 and consolibyte stable build 2.0.0.
Fallowing are the content of "example_mysql_mirror.php" file.
error_reporting(E_ALL | E_STRICT);
ini_set('display_errors', 1);
require_once dirname(__FILE__) . '/../QuickBooks.php';
if (function_exists('date_default_timezone_set'))
{
date_default_timezone_set('America/New_York');
}
$username = 'Admin';
$password = '123456';
$dsn = 'mysqli://root:#localhost/quickbooks_sql';
if (!QuickBooks_Utilities::initialized($dsn))
{
header('Content-Type: text/plain');
set_time_limit(0);
$driver_options = array(
);
$init_options = array(
'quickbooks_sql_enabled' => true,
);
QuickBooks_Utilities::initialize($dsn, $driver_options, $init_options);
QuickBooks_Utilities::createUser($dsn, $username, $password);
exit;
}
$mode = QuickBooks_WebConnector_Server_SQL::MODE_READWRITE;
$conflicts = QuickBooks_WebConnector_Server_SQL::CONFLICT_LOG;
$delete = QuickBooks_WebConnector_Server_SQL::DELETE_FLAG;
$hooks = array();
$soap_options = array();
$handler_options = array(
'deny_concurrent_logins' => false,
);
$driver_options = array();
$ops = array(
QUICKBOOKS_OBJECT_SALESTAXITEM,
QUICKBOOKS_OBJECT_SALESTAXCODE,
QUICKBOOKS_OBJECT_CUSTOMER,
QUICKBOOKS_OBJECT_VENDOR,
QUICKBOOKS_OBJECT_INVENTORYITEM,
QUICKBOOKS_OBJECT_TEMPLATE,
QUICKBOOKS_OBJECT_CUSTOMERTYPE,
QUICKBOOKS_OBJECT_VENDORTYPE,
QUICKBOOKS_OBJECT_ESTIMATE,
QUICKBOOKS_OBJECT_INVOICE,
QUICKBOOKS_OBJECT_CLASS,
QUICKBOOKS_OBJECT_INVOICE,
QUICKBOOKS_OBJECT_PAYMENTMETHOD,
QUICKBOOKS_OBJECT_COMPANY,
QUICKBOOKS_OBJECT_HOST,
QUICKBOOKS_OBJECT_PREFERENCES,
);
$ops_misc = array(
QUICKBOOKS_DERIVE_INVENTORYLEVELS,
QUICKBOOKS_QUERY_DELETEDLISTS,
QUICKBOOKS_QUERY_DELETEDTRANSACTIONS,
// 'nothing',
);
$sql_options = array(
'only_import' => $ops,
'only_add' => $ops,
'only_modify' => $ops,
'only_misc' => $ops_misc,
);
$callback_options = array();
$Server = new QuickBooks_WebConnector_Server_SQL(
$dsn,
'1 minute',
$mode,
$conflicts,
$delete,
$username,
array(),
array(),
$hooks,
QUICKBOOKS_LOG_DEVELOP,
QUICKBOOKS_SOAPSERVER_BUILTIN,
QUICKBOOKS_WSDL,
$soap_options,
$handler_options,
$driver_options,
$sql_options,
$callback_options);
$Server->handle(true, true);
If your QuickBooks computer in this time zone?
if (function_exists('date_default_timezone_set'))
{
date_default_timezone_set('America/New_York');
}
If not, fix your code so that the timezone of this code matches the timezone of QuickBooks.
I want get all sale data date wise from Quickbooks Desktop. I have following code.
$xml = '<?xml version="1.0" encoding="utf-8"?>
<?qbxml version="13.0"?>
<QBXML>
<QBXMLMsgsRq onError="stopOnError">
<GeneralSummaryReportQueryRq requestID="' . $requestID . '">
<GeneralSummaryReportType>SalesByCustomerSummary</GeneralSummaryReportType>
<DisplayReport>false</DisplayReport>
<ReportPeriod>
<FromReportDate>2011-01-01</FromReportDate>
<ToReportDate>2017-09-15</ToReportDate>
</ReportPeriod>
</GeneralSummaryReportQueryRq>
</QBXMLMsgsRq>
</QBXML>';
return $xml;
When i replace SalesByCustomerSummary with
DailySalesDetail, then return error, and my second issue how i can stop communication between web connector and quicksbook because it inserts same records for multi time.
Thanks in advance
----------- CODE ------------
I have these two functions:
public function _quickbooks_import_daily_sale_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="13.0"?>
<QBXML>
<QBXMLMsgsRq onError="stopOnError">
<GeneralDetailReportQueryRq>
<GeneralDetailReportType>SalesByItemDetail</GeneralDetailReportType>
<DisplayReport>false</DisplayReport>
<ReportPeriod>
<FromReportDate>2011-01-01</FromReportDate>
<ToReportDate>2017-09-15</ToReportDate>
</ReportPeriod>
</GeneralDetailReportQueryRq>
</QBXMLMsgsRq>
</QBXML>';
return $xml;
}
public function _quickbooks_import_daily_sale_response($requestID, $user, $action, $ID, $extra, &$err, $last_action_time, $last_actionident_time, $xml, $idents)
{
$array = array(
'text' => $requestID.' <br />'.$xml
);
$this->db->insert('save_response', $array);
// echo "done";
return false;
}
--------------- FOR QUEUE -----------------------
//echo (__FILE__); exit;
$user = $this->config->item('quickbooks_user');
$pass = $this->config->item('quickbooks_pass');
// Memory limit
ini_set('memory_limit', $this->config->item('quickbooks_memorylimit'));
// 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($this->config->item('quickbooks_tz'));
}
// Map QuickBooks actions to handler functions
$map = array(
//QUICKBOOKS_IMPORT_CUSTOMER => array( array( $this, '_quickbooks_customer_import_request' ), array( $this, '_quickbooks_customer_import_response' ) ),
/*QUICKBOOKS_IMPORT_EMPLOYEE => array( array( $this, '_quickbooks_employee_import_request' ), array( $this, '_quickbooks_employee_import_response' ) ),*/
QUICKBOOKS_QUERY_INVOICE => array( array( $this, '_quickbooks_import_daily_sale_request' ), array( $this, '_quickbooks_import_daily_sale_response' ) ),
//QUICKBOOKS_IMPORT_CUSTOMER => array( '_quickbooks_customer_import_request', '_quickbooks_customer_import_response' ),
);
// Catch all errors that QuickBooks throws with this function
$errmap = array(
'*' => array( $this, '_catchallErrors' ),
);
// Call this method whenever the Web Connector connects
$hooks = array(
QuickBooks_WebConnector_Handlers::HOOK_LOGINSUCCESS => array( array( $this, '_loginSuccess' ) ), // Run this function whenever a successful login occurs
);
// An array of callback options
$callback_options = array();
// Logging level
$log_level = $this->config->item('quickbooks_loglevel');
// What SOAP server you're using
//$soapserver = QUICKBOOKS_SOAPSERVER_PHP; // The PHP SOAP extension, see: www.php.net/soap
$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(
'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' => 32000, // Limit the number of quickbooks_log entries to 1024
'max_queue_history' => 1024, // Limit the number of *successfully processed* quickbooks_queue entries to 64
);
// Build the database connection string
$dsn = 'mysqli://' . $this->db->username . ':' . $this->db->password . '#' . $this->db->hostname . '/' . $this->db->database;
// Check to make sure our database is set up
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);
}
// Set up our queue singleton
QuickBooks_WebConnector_Queue_Singleton::initialize($dsn);
// 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();
$Queue = new QuickBooks_WebConnector_Queue($dsn);
$Queue->enqueue(QUICKBOOKS_QUERY_INVOICE);
//exit;
//echo "<pre>"; print_r($response);
//echo "Mujtaba";
This is your problem:
$Queue = new QuickBooks_WebConnector_Queue($dsn);
$Queue->enqueue(QUICKBOOKS_QUERY_INVOICE);
The way the Web Connector works, for every single time the Web Connector connects to QuickBooks, it makes at least 2 HTTP requests. So, this script you have is going to run at least TWICE every single time things attempt to sync with QuickBooks.
That means that every single time you attempt to sync with QuickBooks, you're queuing up at least two requests to do the same thing.
The Web Connector does this:
HTTP request #1 - authenticate
(if there's stuff to do) HTTP request #2 - ask for the first thing to do
(if we got a response back from previous step) HTTP request #3 - send response from QuickBooks back to you
(if there's still more stuff to do) go back to step 2.
HTTP request #N - close the connection/log off
So, you need to change your code so that you only queue things up when it first connects vs. queueing things up on every single HTTP request.
There's an example of doing this here:
https://github.com/consolibyte/quickbooks-php/blob/master/docs/web_connector/example_web_connector_import.php#L125
Basically, you need register a callback function to be called whenever the Web Connector authenticates:
$hooks = array(
QuickBooks_WebConnector_Handlers::HOOK_LOGINSUCCESS => '_quickbooks_hook_loginsuccess', // call this whenever a successful login occurs
);
And do your queuing in that function instead:
function _quickbooks_hook_loginsuccess($requestID, $user, $hook, &$err, $hook_data, $callback_config)
{
// For new users, we need to set up a few things
// Fetch the queue instance
$Queue = QuickBooks_WebConnector_Queue_Singleton::getInstance();
$Queue->enqueue(... whatever you want to do here ...)
}
I'm currently attempting to update an internal tool to handle an upgrade of our exchange servers to office 365.
I'm using the most recent version of James Armas's PHP-EWS tool. jamesiarmes/php-ews
Here is the code snippet that is inside of a function that we use to get events for a certain date range.
$email = '*email#domain*';
$password = '*password*';
$server = 'outlook.office365.com';
// Define EWS
//$ews = EWSAutodiscover::getEWS($email, $password);
$ews = new Client($server, $email, $password);
// Set init class
$request = new FindItemType();
// Use this to search only the items in the parent directory in question or use ::SOFT_DELETED
// to identify "soft deleted" items, i.e. not visible and not in the trash can.
$request->Traversal = ItemQueryTraversalType::SHALLOW;
// This identifies the set of properties to return in an item or folder response
$request->ItemShape = new ItemResponseShapeType();
$request->ItemShape->BaseShape = DefaultShapeNamesType::ALL_PROPERTIES;
// Define the timeframe to load calendar items
$request->CalendarView = new CalendarViewType();
$request->CalendarView->StartDate = $start_date;// an ISO8601 date e.g. 2012-06-12T15:18:34+03:00
$request->CalendarView->EndDate = $end_date;// an ISO8601 date later than the above
// Only look in the "calendars folder"
$request->ParentFolderIds = new NonEmptyArrayOfBaseFolderIdsType();
$request->ParentFolderIds->DistinguishedFolderId = new DistinguishedFolderIdType();
$request->ParentFolderIds->DistinguishedFolderId->Id = DistinguishedFolderIdNameType::CALENDAR;
$request->ParentFolderIds->DistinguishedFolderId->Mailbox = new StdClass;
$request->ParentFolderIds->DistinguishedFolderId->Mailbox->EmailAddress = $email_address;
// Send request
$response = $ews->FindItem($request);
When this code is run, we get a 404 from the SOAP client:
Fatal error: Uncaught exception 'Exception' with message 'SOAP client returned status of 404.' in /*dirs*/Client.php:1650 Stack trace: #0 /*dirs*/Client.php(1633): jamesiarmes\PhpEws\Client->processResponse(NULL) #1 /*dirs*/Client.php(670): jamesiarmes\PhpEws\Client->makeRequest('FindItem', Object(jamesiarmes\PhpEws\Request\FindItemType)) #2 /*dirs*/index_dev.php(64): jamesiarmes\PhpEws\Client->FindItem(Object(jamesiarmes\PhpEws\Request\FindItemType)) #3 /*dirs*/index_dev.php(269): getEventHTML('email#domain...', '2017-07-18T02:0...', '2017-07-18T21:5...') #4 {main} thrown in /*dirs*/Client.php on line 1650
I believe that I do have the connection set up correctly, because when I alter the credentials, I do get a 401.
I have looked into this page: PHP-EWS “Soap client returned status of 404”
And I've tried the outlook.office365.com/EWS/Exchange.asmx endpoint as well, but I still get the SOAP 404.
Because of this, I thought this was enough of a separate question. (Although the more I research, the more that the REST client may be the next step)
I might be on the completely wrong track as well, so any help would be greatly appreciated!
I had a similar issue when we moved from an on-premises Exchange server to Office 365 and managed to trace the issue back to SoapClient.php under php-ntlm.
Going from the error that was thrown in your request:
Fatal error: Uncaught exception 'Exception' with message 'SOAP client returned status of 404.' .... thrown in /*dirs*/Client.php on line 1650
If we look at that line in Client.php the exception appears to come from the function that calls the aforementioned SoapClient.php script.
protected function processResponse($response)
{
// If the soap call failed then we need to throw an exception.
$code = $this->soap->getResponseCode();
if ($code != 200) {
throw new \Exception(
"SOAP client returned status of $code.",
$code
);
}
return $response;
}
I was able to resolve the issue by modifying the CURL request options in SoapClient.php (located around line 180).
Original Code:
protected function curlOptions($action, $request)
{
$options = $this->options['curlopts'] + array(
CURLOPT_SSL_VERIFYPEER => true,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => $this->buildHeaders($action),
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_HTTPAUTH => CURLAUTH_BASIC | CURLAUTH_NTLM,
CURLOPT_USERPWD => $this->options['user'] . ':'
. $this->options['password'],
);
// We shouldn't allow these options to be overridden.
$options[CURLOPT_HEADER] = true;
$options[CURLOPT_POST] = true;
$options[CURLOPT_POSTFIELDS] = $request;
return $options;
}
Modified Code:
protected function curlOptions($action, $request)
{
$cOpts = array(
CURLOPT_PROXY => "my.proxy.com:8080",
CURLOPT_PROXYUSERPWD => $this->options['user'] . ':'
. $this->options['password'],
CURLOPT_SSL_VERIFYPEER => false,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => $this->buildHeaders($action),
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_HTTPAUTH => CURLAUTH_BASIC | CURLAUTH_NTLM,
CURLOPT_USERPWD => $this->options['user'] . ':'
. $this->options['password'],
);
$options = $this->options['curlopts'] + $cOpts;
// We shouldn't allow these options to be overridden.
$options[CURLOPT_HEADER] = true;
$options[CURLOPT_POST] = true;
$options[CURLOPT_POSTFIELDS] = $request;
return $options;
}
I set CURLOPT_SSL_VERIFYPEER to false and also added proxy options to the request as the connection is made from inside a corporate network which requires proxy authentication to access any external sites.
In my mailing PHP script I create the client using the following code:
$server = 'outlook.office365.com';
$username = 'user#domain.com';
$password = 'myPassword';
$version = Client::VERSION_2016;
$client = new Client($server, $username, $password, $version);
Have you tried using the solution from https://github.com/jamesiarmes/php-ews/issues/196 eg change
$version = Client::VERSION_2016;
$ews = new Client($server, $email, $password,$version);
I can't make out what is wrong with your code but maybe the following helps. I'm using this script successfully to export my calendar regulary from o365.
Host and User are like this:
host = "outlook.office365.com"
username = "user#domain.com"
Script:
$start_date = new Datetime('today -1 months');
$end_date = new Datetime('today +1 months');
$timezone = 'W. Europe Standard Time';
$ini_array = parse_ini_file($credentials_ini);
$host = $ini_array['host'];
$username = $ini_array['username'];
$password = $ini_array['password'];
$version = Client::VERSION_2016;
$client = new Client($host, $username, $password, $version);
$client->setTimezone($timezone);
$request = new FindItemType();
$request->ParentFolderIds = new NonEmptyArrayOfBaseFolderIdsType();
$request->ItemShape = new ItemResponseShapeType();
$request->ItemShape->BaseShape = DefaultShapeNamesType::ALL_PROPERTIES;
$folder_id = new DistinguishedFolderIdType();
$folder_id->Id = DistinguishedFolderIdNameType::CALENDAR;
$request->ParentFolderIds->DistinguishedFolderId[] = $folder_id;
$request->Traversal = ItemQueryTraversalType::SHALLOW;
$request->CalendarView = new CalendarViewType();
$request->CalendarView->StartDate = $start_date->format('c');
$request->CalendarView->EndDate = $end_date->format('c');
$request->ConnectionTimeout = 60;
$response = $client->FindItem($request);
$response_messages = $response->ResponseMessages->FindItemResponseMessage;
foreach ($response_messages as $response_message) {
$items = $response_message->RootFolder->Items->CalendarItem;
foreach ($items as $event){
$id = $event->ItemId->Id;
$subject = $event->Subject;
$location = $event->Location;
// ...
// do something with it
}
}
This is written in CI and using the wooapi v2. The order is always being marked as completed, instead of manual renewal. The goal is that if the post status is already manual renewal, that it will not get marked completed, but stay manual renewal. Any help greatly appreciated. Somewhat new to CI.
function complete_order($orderid) {
$consumer_key = 'xxx'; // Add your own Consumer Key here
$consumer_secret = 'xxxx'; // Add your own Consumer Secret here
$store_url = 'xxx'; // Add the home URL to the store you want to connect to here
$options = array(
'debug' => true,
'return_as_array' => false,
'validate_url' => false,
'timeout' => 30,
'ssl_verify' => false,
);
$servername = "xxx";
$username = "xxx";
$password = "xxx";
$dbname = "xxx";
$conn = new mysqli($servername, $username, $password, $dbname);
$sql ="SELECT * FROM xxxxxx WHERE ID = '$orderid'";
$result = $conn->query($sql);
while($row = $result->fetch_assoc()) {
$poststatus= '. $row["post_status"].';
if ($poststatus = wc-manual-renewal-re){
$client = new WC_API_Client($store_url, $consumer_key, $consumer_secret, $options);
$client->orders->update_status($orderid, 'wc-manual-renewal-re');
}else{$client = new WC_API_Client($store_url, $consumer_key, $consumer_secret, $options);
$client->orders->update_status($orderid, 'wc-completed');
}
}
}
You have a couple of mistakes/typos in your code here
if ($poststatus = wc-manual-renewal-re){
$client = new WC_API_Client($store_url, $consumer_key, $consumer_secret, $options);
$client->orders->update_status($orderid, 'wc-manual-renewal-re');
}
You are assigning = instead of comparing === which will always return true, and I guess this should be a string, not a constant: wc-manual-renewal-re
if ($poststatus === 'wc-manual-renewal-re'){
$client = new WC_API_Client($store_url, $consumer_key, $consumer_secret, $options);
$client->orders->update_status($orderid, 'wc-manual-renewal-re');
}