I have been building a private web based app for my shopify store that caters more towards our business needs. While i am able to do a dump of "all-orders", or "all-products", etc to Mysql, i haven't been able to figure out executing the shopify order creation webhook to insert a new order when created in Shopify to a Mysql database.
Instead i would need to run my script every "x" times to see if there is a new order (This could if i'm not mistaken lead to exceeding my API limit if i am running other API calls concurrently).
I understand the process of events however i am struggling to execute!
1. New order created in Shopify by Customer &or Admin.
2. Triggers webhook and sends Json to desired url i.e(https://mydomain//new-order.php). -> [Struggling]
3. When this happens the Json is decoded. -> [Struggling]
4. Assigned to a variable. -> [This i can do]
5. Inserted into a Mysql database. -> [This i can do]
=> Question:
How do you once you have created the webhook (in Shopify) get it to trigger your code to run thereafter and execute?
below is the code that i have put together, but when i sent a test hook the database isn't being updated.
All in the [new-orders.php] file (Broken up to show my train of thought):
[1] Private app credentials for connecting to Shopify store.
<?php
$api_url = https://apikey:password#my-store.shopify.com';
$shopify = $api_url . '/admin/webhooks.json';
[2] Create an array for the webhook argumnets when the webhook is triggered & assign to variable $webhooks.
$arguments = array(
'topic' => 'order/creation',
'address' => 'https://mydomain//new-order.php'
);
$webhooks = $api_url . '/admin/webhooks.json', $arguments;
[3] Decode the webhook data.
$webhook_content = '';
$webhook = fopen('php://input' , 'rb');
while(!feof($webhook)){ //loop through the input stream while the end of file is not reached
$webhook_content .= fread($webhook, 4096); //append the content on the current iteration
}
fclose($webhook); //close the resource
$orders = json_decode($webhook_content, true); //convert the json to array
[4] Add the new order to the Mysql database table.
// not sure if a foreach loop is necessary in this case?
foreach($orders as $order){
$servername = "mysql.servername.com";
$database = "database_name";
$username = "user_name";
$password = "password";
$sql = "mysql:host=$servername;dbname=$database;";
// Create a new connection to the MySQL database using PDO, $my_Db_Connection is an object
try {
$db = new PDO($sql, $username, $password);
//echo "<p> DB Connect = Success.</p>";
} catch (PDOException $error) {
echo 'Connection error: ' . $error->getMessage();
}
$order_id = $order['id'];
$order_number = $order['name'];
$f_name = $order['billing_address']['name'];
$payment_gateway = $order['gateway'];
$financial_status = $order['financial_status'];
$order_value = $order['total_price'];
$order_status = $order['#'];
$shipping_province = $order['shipping_address']['province'];
$created_at = $order['created_at'];
$updated_at = $order['updated_at'];
$shipping_method = $order['shipping_lines'][0]['title'];
$stmt = $db->query("INSERT INTO orders(order_id, order_number, cust_fname, payment_gateway, financial_status, order_value, order_status, ship_to, created_at, updated_at, shipping_method)
VALUES ('$created_at', '$order_id', '$order_number', '$f_name', '$payment_gateway', '$financial_status', '$order_value', '$order_status', '$shipping_province', '$created_at', '$updated_at', '$shipping_method')");
}
?>
Any help would be greatly appreciated and i hope i have given enough context to the issue i am currently facing. If any other information is required i will try my best to explain why i have done something the way i have.
Regards,
Update, managed to figure this out and for those of you potentially struggling with the following this is how i solved.
There are 2 aspect here!
1. Setting up the webhook [Shopify -> Notifications -> webhooks].
2. The php file that processes the webhook.
1. -> Create Webhook in shopify and point to where you php url [example.com/Process-webhook.php]
2. -> Process-webhook.php
php code
// Load variables
$webhook_content = NULL;
// Get webhook content from the POST
$webhook = fopen('php://input' , 'rb');
while (!feof($webhook)) {
$webhook_content .= fread($webhook, 4096);
}
fclose($webhook);
// Decode Shopify POST
$webhook_content = json_decode($webhook_content, TRUE);
$servername = "server_name";
$database = "database";
$username = "user_name";
$password = "password";
$sql = "mysql:host=$servername;dbname=$database;";
// Create a new connection to the MySQL database using PDO, $my_Db_Connection is an object
try {
$db = new PDO($sql, $username, $password);
//echo "<p> DB Connect = Success.</p>";
} catch (PDOException $error) {
echo 'Connection error: ' . $error->getMessage();
}
//Assign to variable
$order_id = $webhook_content['id'];
$order_number = $webhook_content['name'];
$f_name = $webhook_content['billing_address']['name'];
$payment_gateway = $webhook_content['gateway'];
$financial_status = $webhook_content['financial_status'];
$pick_status = $webhook_content['NULL'];
$pack_status = $webhook_content['NULL'];
$fulfill_status = $webhook_content['NULL'];
$order_value = $webhook_content['total_price'];
$order_status = $webhook_content['NULL'];
$shipping_province = $webhook_content['shipping_address']['province'];
// I wanted to insert the variant_id's and quantity as a string in one column. With this i can unserialise and use when needed
$items = [];
foreach($webhook_content["line_items"] as $item) {
$items[$item["variant_id"]]['quantity'] = $item["quantity"];
}
$items = serialize($items);
$created_at = $webhook_content['created_at'];
$updated_at = $webhook_content['updated_at'];
$shipping_method = $webhook_content['shipping_lines'][0]['title'];
$stmt = $db->query("INSERT INTO orders(order_id,
order_number,
cust_fname,
payment_gateway,
financial_status,
order_value,
order_status,
ship_to,
items,
created_at,
updated_at,
shipping_method)
VALUES ('$order_id',
'$order_number',
'$f_name',
'$payment_gateway',
'$financial_status',
'$order_value',
'$order_status',
'$shipping_province',
'$items',
'$created_at',
'$updated_at',
'$shipping_method')");
?>
Related
\Stripe\Stripe::setApiKey
This API is working perfectly in the webhook and getting the perfection result. But when I used subcription api:
\Stripe\Subscription::retrieve
It give me test webhook error: 500.
This is my code:
$stripe_secret_key = '*****';
$dbname="****"; // database name
$usertable="*****"; // webhook table
require_once('wp-config.php');
$connection = mysql_connect(DB_HOST, DB_USER, DB_PASSWORD);
mysql_select_db($dbname, $connection);
require_once('webhook/vendor/autoload.php');
// Set your secret key: remember to change this to your live secret key in production
// See your keys here: https://dashboard.stripe.com/account/apikeys
\Stripe\Stripe::setApiKey($stripe_secret_key);
// Retrieve the request's body and parse it as JSON
$input = #file_get_contents("php://input");
$event_json = json_decode($input);
$event_type = $event_json->type;
$chargeId = $event_json->data->object->charge;
$subcriptionKey = $event_json->data->object->lines->data[0]->id;
$customerId = $event_json->data->object->customer;
$amoutDue = $event_json->data->object->amount_due;
$paidStatus = $event_json->data->object->paid;
$interval = $event_json->data->object->lines->data[0]->plan->interval_count;
//insert query
$sql = "INSERT INTO epti_webhook ".
"(subscription_id,charge_id, customer_id,event_type, month_interval, paidStatus, data_response) "."VALUES ".
"('$subcriptionKey','$chargeId','$customerId','$event_type','$interval','$paidStatus','$input')";
$retval = mysql_query( $sql, $connection );
if(! $retval ) {
die('Could not enter data: ' . mysql_error());
}
echo "Entered data successfully\n";
//count query
$result=mysql_query("SELECT count(*) as total from epti_webhook where subscription_id = '".$subcriptionKey."'");
$data=mysql_fetch_assoc($result);
echo $data['total'].'===';
if($data['total'] > '1'){
//issue is coming here
$sub = \Stripe\Subscription::retrieve("sub_A****");
$sub->cancel();
}
http_response_code(200); // PHP 5.4 or greater`
Need help guys. I have updated the latest stripe as well but it give me same error.
Thank you in advance
\Stripe\Stripe::setApiKey() simply sets the API key locally -- it does not actually send any request to Stripe's API.
There are many reasons why your code could fail when retrieving the subscription. For instance, if Stripe's API returns an error, this error will be raised as a \Stripe\Error\... exception. You should wrap all requests to Stripe's API in a try/catch block to properly handle errors.
You can read more about error handling here: https://stripe.com/docs/api/php#error_handling.
This code gets values from a database and forms a sms template and then passes the moble number and message to webservice to send the sms. It's part of a function wall().....
$name = $resultarr['name'];
$amount = $resultarr['amount'];
$transaction_id = $resultarr['trans_id'];
$date = $resultarr['time_paid'];
//message template
$message = "Dear $name we have received $amount from you. MPESA transaction Id $transaction_id on $date.";
$mobilenumber = $resultarr['msisdn']; // get mobile number from array
$message_sent = $message;
$serviceArguments = array(
"mobilenumber" => $mobilenumber,
"message" => $message_sent
);
$client = new SoapClient("http://59.38.606.10:8080/smsengine/smsws?WSDL");
$result = $client->process($serviceArguments);
grabdetails($message_sent, $mobilenumber);
return $result;
}
//I call the function wall() to send sms
wall();
$perm = wall();
$status = $sperm->return; //outputing the status
// Here I want to capture the $status variable and put it in a db below
echo "$status";
function grabdetails($messagee, $mobno)
{
$message_sent = $messagee;
$mobilenumber = $mobno;
$servername = "localhost";
$username = "root";
$password = "";
$dbname = "smsdb";
// Create connection
// Check connection
$sql = "INSERT INTO smsdb (sms_text, receiver_number, time_sent, status)
VALUES
('$message_sent', '$mobilenumber', NOW(), $status )";
Question is how do I grab $status ind insert it into the db since its not in the function? Kindly. help, anyone?
The code above is not complete, but I assume that the function on top where you do $client = new SoapClient("http://59.38.606.10:8080/smsengine/smsws?WSDL"); is actually the wall function. If so, then what that function returns, i.e. $result actually has the status you need. So with this code snippet (assuming $sperm is a typo and should actually be $perm, the response from the wall function), you get the response from wall(), which is an object and has the status you need.
$perm = wall();
$status = $sperm->return; //outputing the status
// Here I want to capture the $status variable and put it in a db below
echo "$status";
If that's right, then before calling grabdetails in the wall function, you actually have the status and you can send it to the function like this:
grabdetails($message_sent, $mobilenumber, $result->return);
And then change the definition of the grabdetails to receive the status as well and use it in the DB insert.
I am new to SOAP. For a project, I need to use "Force.com Toolkit for PHP".
I made the first call to open a Salesforce session and retrieve the session ID , which will be used to call the recovery service of customer information. ( It's ok, i have the ID session)
I know that the customer information flows is called using the session ID obtained with the first call, but i don't how to do the second call ! I also have another WSDL file ( CallInListCustomer.wsdl.xml )
I also the customers informations flow addresses (found in WSDL ). I'm not sure , but i must the call in "post" format...
can you help me ?
<?php
session_start();
define("USERNAME", "my_username");
define("PASSWORD", "my_password");
define("SECURITY_TOKEN", "my_token");
require_once ('soapclient/SforcePartnerClient.php');
$mySforceConnection = new SforcePartnerClient();
$mySforceConnection->createConnection("Partner.wsdl.xml");
$mySforceConnection->login(USERNAME, PASSWORD.SECURITY_TOKEN);
// Now we can save the connection info for the next page
$_SESSION['location'] = $mySforceConnection->getLocation();
$_SESSION['sessionId'] = $mySforceConnection->getSessionId();
$sessionId = $_SESSION['sessionId'];
echo $sessionId;
// Here, i don't know how to call the recovery service of customer information with allInListCustomer.wsdl.xml
?>
Thanks for all
Here is my code.
Create separate file to store salesforce org details.
SFConfig.php
<?php
/*----------------------------------------------------------------
* We will define salesforce user anem and password with token.
* This file we used / include in every time when we need to
* communicate withy salesforce.
* ---------------------------------------------------------------*/
$USERNAME = "Your salesforce user name";
$PASSWORD = "Your password with security token";
?>
Get account data from salesforce
GetAccountData.php
<?php
// SET SOAP LIB DIRCTORY PATH
define("SOAP_LIB_FILES_PATH", "/<Put Your file location>/soapclient");
// Access sf config file
require_once ('/<Put Your file location>/SFConfig.php');
// Access partner client php lib file
require_once (SOAP_LIB_FILES_PATH.'/SforcePartnerClient.php');
try {
echo "\n******** Inside the try *******\n";
// Sf connection using ( SOAP ) partner WSDL
$mySforceConnection = new SforcePartnerClient();
$mySforceConnection->createConnection(SOAP_LIB_FILES_PATH.'/YourWSDLName.wsdl.xml');
$mySforceConnection->login($USERNAME, $PASSWORD);
echo "\n******** Login with salesforce is done *******\n";
// query for featch Versand data with last run datetime
$query = "SELECT Id, Name
FROM Account;
// Send query to salesforce
$response = $mySforceConnection->query($query);
// Store the query result
$queryResult = new QueryResult($response);
$isError = false ;
echo "Results of query '$query'<br/><br/>\n";
// Show result array
for ($queryResult->rewind(); $queryResult->pointer < $queryResult->size; $queryResult->next()) {
$record = $queryResult->current();
// Id is on the $record, but other fields are accessed via
// the fields object
echo "\nVersand value : ".$record->Abmelder__c."\n";
}
} catch (Exception $e) {
$GLOBALS['isTimeEnter'] = true;
echo "entered catch****\n";
echo "Exception ".$e->faultstring."<br/><br/>\n";
}
?>
Also if you want to call another services then just call using "$mySforceConnection" variable as per above.
For Example: (Create Contact)
$records = array();
$records[0] = new SObject();
$records[0]->fields = array(
'FirstName' => 'John',
'LastName' => 'Smith',
'Phone' => '(510) 555-5555',
'BirthDate' => '1957-01-25'
);
$records[0]->type = 'Contact';
$records[1] = new SObject();
$records[1]->fields = array(
'FirstName' => 'Mary',
'LastName' => 'Jones',
'Phone' => '(510) 486-9969',
'BirthDate' => '1977-01-25'
);
$records[1]->type = 'Contact';
$response = $mySforceConnection->create($records);
$ids = array();
foreach ($response as $i => $result) {
echo $records[$i]->fields["FirstName"] . " "
. $records[$i]->fields["LastName"] . " "
. $records[$i]->fields["Phone"] . " created with id "
. $result->id . "<br/>\n";
array_push($ids, $result->id);
}
Please check below link for more details:
https://developer.salesforce.com/page/Getting_Started_with_the_Force.com_Toolkit_for_PHP
I find the solution, here my code :
<?php
// salesforce.com Username, Password and TOken
define("USERNAME", "My_username");
define("PASSWORD", "My_password");
define("SECURITY_TOKEN", "My_token");
// from PHP-toolkit ( https://developer.salesforce.com/page/Getting_Started_with_the_Force.com_Toolkit_for_PHP )
require_once ('soapclient/SforcePartnerClient.php');
$mySforceConnection = new SforcePartnerClient();
$mySforceConnection->createConnection("Partner.wsdl.xml");
$mySforceConnection->login(USERNAME, PASSWORD.SECURITY_TOKEN);
// I Get the IDSESSION
$sessionId = $mySforceConnection->getSessionId();
// I create a new soapClient with my WSDL
$objClient = new SoapClient("my_service.wsdl.xml", array('trace' => true));
// I create the header
$strHeaderComponent_Session = "<SessionHeader><sessionId>$sessionId</sessionId></SessionHeader>";
$objVar_Session_Inside = new SoapVar($strHeaderComponent_Session, XSD_ANYXML, null, null, null);
$objHeader_Session_Outside = new SoapHeader('https://xxxxx.salesforce.com/services/Soap/class/myservice', 'SessionHeader', $objVar_Session_Inside);
$objClient->__setSoapHeaders(array($objHeader_Session_Outside));
// i call the service
$objResponse = $objClient->getinfo(array ( 'Zone' => "123456"));
// here i get the result in Json
$json = json_encode( (array)$objResponse);
echo $json;
?>
We have a case where we need to check envelope status in two separate Docusign accounts. If we don't get status in the first, we want to check the second.
I'm having trouble getting the API to re-initialize with the credentials of our second account. I'm calling this snippet with the new variables:
require_once('docusign/SignatureApi.php');
$IntegratorsKey = "abcd";
$UserID = "dave#account.com";
$Password = "xxxxx";
$_apiEndpoint = $Endpoint;
$_apiWsdl = "docusign/api/APIService.wsdl";
$api_options = array('location'=>$_apiEndpoint,'trace'=>true,'features' => SOAP_SINGLE_ELEMENT_ARRAYS);
$api = new APIService($_apiWsdl, $api_options);
$api->setCredentials("[" . $IntegratorsKey . "]" . $UserID, $Password);
$res = RequestEnvelopStatuses($envelopes);
$envelopeStatuses = $res->RequestStatusesResult;
if(!count($envelopeStatuses->EnvelopeStatuses->EnvelopeStatus)){
// If we did not find envelopes, check other account
$IntegratorsKey = "wxyz";
$UserID = "fred#altaccount.com";
$Password = "xxxxx";
$api->setCredentials("[" . $IntegratorsKey . "]" . $UserID, $Password);
// retry request
$res = RequestEnvelopStatuses($envelopes);
$envelopeStatuses = $res->RequestStatusesResult;
}
It doesn't return an error, but won't return envelope status either. It seems to still use the first credentials (guessing). The second attempt always seems to return whatever the first attempt did.
Is there a better / preferred way to do this?
That does not look like the proper way to get the envelope status. Maybe that's why you are not finding them and trying to look again?
// Create a filter using account ID and today as a start time
$envStatusFilter = new EnvelopeStatusFilter();
$envStatusFilter->AccountId = $AccountID;
$beginDateTime = new EnvelopeStatusFilterBeginDateTime();
$beginDateTime->_ = todayXsdDate(); // note that this helper function
// is in CodeSnippets/include/utils.php
// in the PHP SDK
$envStatusFilter->BeginDateTime = $beginDateTime;
// Send
$requestStatusesparams = new RequestStatuses();
$requestStatusesparams->EnvelopeStatusFilter = $envStatusFilter;
$response = $api->RequestStatuses($requestStatusesparams);
I've been researching this and trying many variations based off my understanding of how to update a record in an SObject, but I keep getting the following error:
SoapFault exception: [sf:INVALID_TYPE] INVALID_TYPE: Must send a concrete entity type. in /home/public_html/soapclient/SforceBaseClient.php:509
I am able to login successfully to the page, but when I execute the code below, I am getting the error listed above.
$fieldsToUpdate = array (
"Name"=>$_POST['Name']
);
$sObject = new SObject();
$sObject->Id = $_POST['prospectID']; // this is the Id of the record
$sObject->fields = $fieldsToUpdate;
$sObject->type = 'Prospect__c'; // this is the API name of custom object
try {
$response = $mySforceConnection->update($sObject);
} catch (Exception $e) {
echo $e;
}
I am using PHP Toolkit 13.0 from the Force.com developer docs, but not able to get to the bottom of this error. Also, I am using the Enterprise WSDL in sandbox mode, and have the proper wsdl xml assigned.
Thanks.
sObject is the base type for all other Salesforce objects that can be updated. When using the enterprise API (SOAP), you'll need to pass instances that derive from sObject. (Lead, Contact, and Account are examples)
Here is the documentation for the update() method as well.
You need to supply an object type as the second update() argument. Also, the first argument of the update() method must be an array of objects you'd like to update:
$response = $mySforceConnection->update(array($object), 'Prospect__c');
Also, you do not need to use any object classes provided by the toolkit, a simple StdClass should work:
$prospect = new StdClass();
$prospect->Id = '006....';
$prospect->Name 'Foobar';
$response = $mySforceConnection->update(array($prospect), 'Prospect__c');
FYI, I have never found a way to update multiple object types at once, but you can update a batch of the same type of objects, hence why the first parameter needs to be an array. The Salesforce toolkit doesn't automatically account for someone passing a single object (i.e. it doesn't wrap it in an array for you). I have always used an abstraction layer between my application logic and Salesforce's SOAP toolkit, which provides conveniences like I just described.
if your are using Partner wsdl
<?php
// SOAP_CLIENT_BASEDIR - folder that contains the PHP Toolkit and your WSDL
// $USERNAME - variable that contains your Salesforce.com username (must be in the form of an email)
// $PASSWORD - variable that contains your Salesforce.com password
define("SOAP_CLIENT_BASEDIR", "../../soapclient");
require_once (SOAP_CLIENT_BASEDIR.'/SforcePartnerClient.php');
require_once ('../userAuth.php');
try {
$mySforceConnection = new SforcePartnerClient();
$mySoapClient = $mySforceConnection->createConnection(SOAP_CLIENT_BASEDIR.'/partner.wsdl.xml');
$mylogin = $mySforceConnection->login($USERNAME, $PASSWORD);
/*--------------------------------------------------------\
| Please manage the values for OBJECT ID from file
| userAuth.php
\--------------------------------------------------------*/
$fieldsToUpdate = array (
'FirstName' => 'testupdate',
'City' => 'testupdateCity',
'Country' => 'US'
);
$sObject1 = new SObject();
$sObject1->fields = $fieldsToUpdate;
$sObject1->type = 'Lead';
$sObject1->Id = $UPDATEOBJECTID1;
$fieldsToUpdate = array (
'FirstName' => 'testupdate',
'City' => 'testupdate',
'State' => 'testupdate',
'Country' => 'US'
);
$sObject2 = new SObject();
$sObject2->fields = $fieldsToUpdate;
$sObject2->type = 'Lead';
$sObject2->Id = $UPDATEOBJECTID2;
$sObject2->fieldsToNull = array('Fax', 'Email');
$response = $mySforceConnection->update(array ($sObject1, $sObject2));
print_r($response);
} catch (Exception $e) {
print_r($mySforceConnection->getLastRequest());
echo $e->faultstring;
}
?>
else for enterprises wsdl use
<?php
// SOAP_CLIENT_BASEDIR - folder that contains the PHP Toolkit and your WSDL
// $USERNAME - variable that contains your Salesforce.com username (must be in the form of an email)
// $PASSWORD - variable that contains your Salesforce.com password
define("SOAP_CLIENT_BASEDIR", "../../soapclient");
require_once (SOAP_CLIENT_BASEDIR.'/SforceEnterpriseClient.php');
require_once ('../userAuth.php');
try {
$mySforceConnection = new SforceEnterpriseClient();
$mySoapClient = $mySforceConnection->createConnection(SOAP_CLIENT_BASEDIR.'/enterprise.wsdl.xml');
$mylogin = $mySforceConnection->login($USERNAME, $PASSWORD);
/*--------------------------------------------------------\
| Please manage the values for OBJECT ID from file
| userAuth.php
\--------------------------------------------------------*/
$sObject1 = new stdclass();
$sObject1->Id = $UPDATEOBJECTID1;
$sObject1->FirstName = 'testupdate';
$sObject1->City = 'testupdateCity';
$sObject1->Country = 'US';
$sObject2 = new stdclass();
$sObject2->Id = $UPDATEOBJECTID2;
$sObject2->FirstName = 'testupdate';
$sObject2->City = 'testupdate';
$sObject2->State = 'testupdate';
$sObject2->Country = 'US';
$sObject2->fieldsToNull = array('Fax', 'Email');
$response = $mySforceConnection->update(array ($sObject1, $sObject2), 'Lead');
print_r($response);
} catch (Exception $e) {
print_r($mySforceConnection->getLastRequest());
echo $e->faultstring;
}
?>