Summary:

Becuase this application contains sensitive data, I cannot share a demo. Below, the table names have been omitted for security purposes. This application features Shopify, and Salesforce connectivity via their REST APIs. It also features loyalty tracking, Inventory tracking, and automated subscription tracking. This was one of my favorite projects because of its highly complex nature. Laravel is also one of the best PHP frameworks available. (The best in my opinion).

PHP


        namespace App\Http\Controllers\Shopify;
        use App\Models\Tier;
        use App\Models\Order;
        use App\Models\Dealer;
        use Carbon\Carbon;

        use DB;
        use Illuminate\Http\Request;
        use App\Http\Controllers\Controller;

        use Illuminate\Support\Facades\Log;

        use Mail;
        use Illuminate\Mail\ExpirationNotification;

        class ShopifyOrdersController extends Controller
        {

        	public function delete( Request $request )
        	{

        		define( 'SHOPIFY_APP_SECRET', config( '###' ) );

        		function verify_webhook( $data, $hmac_header )
        		{

        			$calculated_hmac = base64_encode( hash_hmac( 'sha256', $data, SHOPIFY_APP_SECRET, true ) );
        			return ( $hmac_header == $calculated_hmac );

        		}

        		// Process the shopify call
        		$hmac_header = $_SERVER[ 'HTTP_X_SHOPIFY_HMAC_SHA256' ];
        		$data = file_get_contents( 'php://input' );
        		$verified = verify_webhook( $data, $hmac_header );

        		if( $verified )
        		{

        			$dataFile = json_decode( $data );

        			$orderId = DB::table( '###' )
        				->where( 'shopify_order_id', '=', $dataFile->id )
        				->select( 'id' )
        				->first();

        			if( count( $orderId ) > 0 )
        			{
        				$order = DB::table( '###' )
        					->where( 'shopify_order_id', '=', $dataFile->id )
        					->first();

        				DB::table( '###' )
        					->where( 'shopify_order_id', '=', $dataFile->id )
        					->update( [ "deleted_at" => date( "Y-m-d H:i:s") ] );

        				DB::table( '###' )
        					->where( 'order_id', '=', $order->id )
        					->update( [ "deleted_at" => date( "Y-m-d H:i:s") ] );

        				DB::table( '###' )
        					->where( 'shopify_id', '=', $order->dealer_id )
        					->decrement( 'accrued_points', $dataFile->subtotal_price );

        			} else
        			{

        				$data = 'There was no data found for this order. It never existed in the database';

        			}

        			header( 'Status: 200' );

        		} else
        		{

        			$data = '[error]: Verification Failed. Please the webhooks token should match the SHOPIFY_APP_SECRET. ---- ' . date( "m-d-Y_H-i-s" ) . '\nIf the problem persists the Webhook in Shopify will be deleted automatically';

        		}
        	}

        	public function orders( Request $request )
        	{

        		// Define the shopify secret variable
        		define( 'SHOPIFY_APP_SECRET', config( 'constants.shopify_app_secret' ) );

        		function verify_webhook( $data, $hmac_header )
        		{

        			$calculated_hmac = base64_encode( hash_hmac( 'sha256', $data, SHOPIFY_APP_SECRET, true ) );
        			return ( $hmac_header == $calculated_hmac );

        		}

        		// Process the shopify call
        		$hmac_header = $_SERVER[ 'HTTP_X_SHOPIFY_HMAC_SHA256' ];
        		$data = file_get_contents( 'php://input' );
        		$verified = verify_webhook( $data, $hmac_header );

        		if( $verified )
        		{

        			// Decode the json string to a json object
        			$dataFile = json_decode( $data );

        			// ORDER INFORMATION
        				// Order Variables
        				$orderId				= $dataFile->id; // Order ID
        				$orderToken				= $dataFile->token; // Order Token
        				$orderCartToken			= $dataFile->cart_token; // Order Cart Token
        				$orderNumber			= $dataFile->order_number; // Order Number
        				$orderCheckoutId		= $dataFile->checkout_id; // Order Checkout ID
        				$orderStatusUrl			= $dataFile->order_status_url; // Order Receipt URL

        				// DEALER VARIABLES
        				$dealerInfo = DB::table( '###' )
        					->where( 'shopify_id', '=', $dataFile->customer->id )
        					->select( 'shopify_id' )
        					->first();

        				$getPreviousId = DB::table( '###' )
        					->where( 'shopify_order_id', '=', $orderId )
        					->select( 'shopify_order_id' )
        					->get();

        				if( count( $getPreviousId ) > 0 ) {
        					header( 'Status: 200 ');
        					die();

        				} else {

        			// DEALER INFORMATION
        				// Dealer Variables
        				$shopify_id				= $dataFile->customer->id; // Dealer ID
        				$dealerEmail			= $dataFile->customer->email; // Dealer Email
        				// Save the orignal .json feed to a file
        				$public_path = public_path();
        				file_put_contents( $public_path . '/json_logs/' . $dealerInfo->shopify_id . "-" . $orderId . '.json', $data );

        				// Order Query
        				try {
        					$orderTableId = DB::table( '###' )
        						->insertGetId( array(
        							"dealer_id"			=> $dataFile->customer->id,
        							"receipt_url"		=> $orderStatusUrl,
        							"shopify_order_id"	=> $orderId,
        						) );
        				}
        				catch ( Exception $e ) {
        				}

        				// Order Items Array
        				$itemsArray = array();
        				foreach( $dataFile->line_items as $items_key => $items_value ) :

        					$itemsArray[ $items_key ][ 'order_id' ] = $orderTableId;
        					$itemsArray[ $items_key ][ 'item_id' ] = $items_value->id;
        					$itemsArray[ $items_key ][ 'variant_id' ] = $items_value->variant_id;
        					$itemsArray[ $items_key ][ 'quantity' ] = $items_value->quantity;
        					$itemsArray[ $items_key ][ 'order_points' ] = $items_value->price;
        					$itemsArray[ $items_key ][ 'item_sku' ] = $items_value->sku;
        					$itemsArray[ $items_key ][ 'product_id' ] = $items_value->product_id;
        					$itemsArray[ $items_key ][ 'item_name' ] = $items_value->name;

        				endforeach;

        				// insert order items
        				DB::table( '###' )
        					->insert( $itemsArray );

        				// CALCULATE TIER | POINTS | AFTER PURCHASE
        				$purchasePts = floatval( $dataFile->subtotal_price );


        				// CALCULATE TIER | POINTS | AFTER PURCHASE
        				$dealerLvl = DB::table( '###' )
        					->leftJoin( '###', '###.id', '=', '###.tier_id' )
        					->where( '###.shopify_id', '=', $dealerInfo->shopify_id )
        					->select( [
        						'###.tier_id',
        						DB::raw( 'SUM( ###.accrued_points + ' . $purchasePts . ' ) as tiers_total' )
        					] )
        					->first();
        				$dealer_level = floatval( $dealerLvl->tiers_total );

        				// DEALER TIER | NEW
        				$dealerNewLvl = DB::table( '###' )
        					->where( 'tiers.trigger', '<=', $dealer_level )
        					->select( [
        						'tiers.id',
        						'tiers.trigger',
        					] )
        					->orderBy( 'tiers.trigger', 'DESC' )
        					->first();

        				// Set the array for the dealer update
        				$dealerUpdate = array( 'dealers.accrued_points' => $dealer_level );

        				// Check if the 'tier' id changed
        				if(	$dealerNewLvl->id != $dealerLvl->tier_id &&	$dealerNewLvl->id > $dealerLvl->tier_id	)
        				{

        					// Add the new tier level tot he 'dealerUpdate' array
        					$dealerUpdate['dealers.tier_id'] = $dealerNewLvl->id;

        				}

        				// Update the 'dealers' record with the new 'accured_points' total
        				DB::table( '###' )
        					->where( '###.shopify_id', $dealerInfo->shopify_id )
        					->update( $dealerUpdate );

        				//CALCULATE THE ON HAND ITEMS PURCHASED FROM ORDER_ITEMS AND REGISTERED CUSTOMERS.
        				$dealerId = DB::table( '###' )
        					->where( 'shopify_id', '=', $dealerInfo->shopify_id )
        					->select( 'id' )
        					->first();

        				$customers = DB::table( '###' )
        					->where( '###.dealer_id', '=', $dealerId->id )
        					->count();

        				$ordersItems = DB::table( '###' )
        					->leftJoin( '###', 'orders.id', '=', '###.order_id' )
        					->leftJoin( '###', '###.shopify_id', '=', '###.dealer_id' )
        					->where( '###.id', '=', $dealerId->id )
        					->where( '###.item_sku', 'like', 'SU%' )
        					->sum( 'quantity' );

        				$reconciled = $ordersItems - $customers;

        				DB::table( '###' )
        					->where( 'dealers.id', '=', $dealerId->id )
        					->update( [
        						'on_hand' => $reconciled
        					] );

        				$dealer = Dealer::all()->where( 'id', '=', $dealerId->id )->first();
        				$shopify = new EndpointsController;
        				$call = $shopify->updateDealer( $dealer );

        				// SYNC SALESFORCE POINTS WITH APP POINTS.
        				if( $dealer->salesforce_id != NULL || $dealer->salesforce_id != '' )
        				{

        					//GET THE LAST TOKEN FROM THE DATABASE
        					$token = DB::table( '###' )
        						->select( 'token' )
        						->orderBy( 'id', 'desc' )
        						->first();

        					//SET QUERY TOKEN VARIABLE
        					$query_token = $token->token;

        					//SET UP HTTP HEADERS
        					$headers = array(
        						"Authorization: OAuth $query_token",
        						"Content-type: application/json"
        					);

        					//START THE CURL CALL
        					$curl = curl_init();

        					//PUT ARGS INTO AN ARRAY
        					curl_setopt_array(
        						$curl,
        						array(
        							CURLOPT_RETURNTRANSFER => TRUE,
        							CURLOPT_URL            => config( 'salesforce.credentials.loginURL' ) . "/services/oauth2/token", // URL FOR REFRESHING ACESS_TOKEN
        							CURLOPT_POST           => TRUE,
        							CURLOPT_POSTFIELDS     => http_build_query(
        								array(
        									'grant_type'    => 'password',
        									'client_id'     => config( '###' ),
        									'client_secret' => config( '###' ),
        									'username'      => config( '###' ),
        									'password'      => config( '###' ),
        								)
        							)
        						)
        					);

        					$plain_response = curl_exec( $curl );// GET RESPONSE
        					$response = json_decode( $plain_response ); // JSON DECODE RESPONSE IN THE CASE OF AN ERROR

        					// CLOSE THE CURL
        					curl_close( $curl );

        					//IF THE TOKEN ISN'T SET LOG THE ERROR IN LARAVEL.LOG
        					app( 'log' )->useDailyFiles( storage_path() . '/laravel.log' );
        					$access_token = ( isset( $response->access_token ) && $response->access_token != "" ) ? $response->access_token : app( 'log' )->critical( "line 274: access_token= was not set." . $plain_response );

        					//IF THE INSTANCE_URL ISN'T SET LOG THE ERROR IN LARAVEL.LOG
        					$instance_url = ( isset( $response->instance_url ) && $response->instance_url != "") ? $response->instance_url : app( 'log' )->critical( "line 275: instance_url was not set." . $plain_response );

        					//SET VARIABLES FOR QUERYING THE ACCOUNT INFORMATION
        					$instance_url = config( 'salesforce.credentials.loginURL');
        					$updateUrl = "$instance_url/services/data/v20.0/sobjects/Account/$dealer->salesforce_id";
        					$user = urlencode( config( 'salesforce.credentials.user' ) );
        					$pass = config( 'salesforce.credentials.pass' );

        					//SET THE FIELDS YOU WANT TO UPDATE IN SALESFORCE
        					$content = json_encode( array( "DEALER_POINTS__C" => $dealer_level ) );

        					//START CURL.
        					$curl = curl_init( $updateUrl );

        					//SET UP HEADER ARGUMENTS
        					curl_setopt( $curl, CURLOPT_HEADER, false );
        					curl_setopt( $curl, CURLOPT_HTTPHEADER,
        							array("Authorization: OAuth $access_token",
        								"Content-type: application/json"));

        					//PATCH CUSTOMREQUEST TO UPDATE DEALER POINTS IN SALESFORCE
        					curl_setopt( $curl, CURLOPT_CUSTOMREQUEST, "PATCH" );
        					curl_setopt( $curl, CURLOPT_POSTFIELDS, $content );

        					// CAPTURE SALESFORCE RESPONSE
        					$response = curl_exec( $curl );

        					// CAPTURE HTTP STATUS CODE
        					$status = curl_getinfo( $curl, CURLINFO_HTTP_CODE );

        					// IF NOT SUCCESSFUL LOG THE ERROR
        					if( $status != 204 )
        					{

        						app( 'log' )->useDailyFiles( storage_path() . '/laravel.log' );
        						app( 'log' )->critical( "line 305 | Error: call to URL $instance_url failed with status $status, curl_error " . curl_error( $curl ) . ", curl_errno " . curl_errno( $curl ) );

        						//SEND AN EMAIL TO THE ADMIN
        						\Mail::raw( 'Salesforce Connected App Failed check laravel.log and ShopifyOrdersController for errors', function( $message )
        						{
        							$message->to( config( 'constants.admin_email' ) );
        							$message->subject( 'Salesforce Connected App Error' );
        						} );

        					}

        					//CLOSE CURL
        					curl_close( $curl );

        				}

        				// ENABLED QUERY LOG TO WATCH WHICH QUERIES ARE BEING MADE
        				DB::enableQueryLog();

        				//SHOW SHOPIFY RETURN STATUS OF 200
        				header( 'Status: 200' );
        			}

        		} else // IF SHOPIFY WEBHOOK DOESN'T VERIFY
        		{

        			//CRITICAL ERRORING
        			app( 'log' )->critical( '[error]: Verification Failed. Please the webhooks token should match the SHOPIFY_APP_SECRET. ---- ' . date( "m-d-Y_H-i-s" ) . '\nIf the problem persists the Webhook in Shopify will be deleted automatically.' );

        			// ALERT TO ADMIN
        			\Mail::raw( 'Shopify Verifiation Failed check SPEQ ShopifyOrdersController for errors', function( $message )
        				{
        					$message->to( config( 'constants.admin_email' ) );
        					$message->subject( 'Shopify Verification Error' );
        				} );

        			//RETURN 200 TO PREVENT SHOPIFY DELETING THE WEBHOOK
        			header( 'Status: 200' );

        		}

        	}

        }