Skip to content

Instantly share code, notes, and snippets.

@jamiepittock
Forked from Tam/BPlugin.php
Created March 14, 2018 13:31
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jamiepittock/007d3869ba05c86e899e01fe051e7b6a to your computer and use it in GitHub Desktop.
Save jamiepittock/007d3869ba05c86e899e01fe051e7b6a to your computer and use it in GitHub Desktop.
<?php
namespace Craft;
class B_DeleteGoogleProductTask extends BaseTask
{
public function getDescription ()
{
return 'Updating Google Shopping';
}
public function getTotalSteps ()
{
return count($this->getSettings()->productIds);
}
public function runStep ($step)
{
$product = craft()->commerce_products->getProductById($this->getSettings()->productIds[$step]);
try {
craft()->b_google->onProductDelete($product);
} catch (\Exception $e) {}
return true;
}
// Protected
// =========================================================================
protected function defineSettings ()
{
return [
'productIds' => AttributeType::Mixed
];
}
}
<?php
namespace Craft;
set_error_handler(function($errno, $errstr, $errfile, $errline ){
throw new \ErrorException($errstr, $errno, 0, $errfile, $errline);
});
class B_GoogleService extends BaseApplicationComponent
{
private $_client;
private $_service;
private $_keyFilename = '[NameOfKeyFile]';
private $_merchantId = '[MerchantId]';
private function _initGoogleClient ()
{
if (!empty($this->_client) && !empty($this->_service)) return;
// This assumes the keyfile is in the `craft/config/` directory
// (i.e. `craft/config/myKeyFile.json`)
$path = CRAFT_CONFIG_PATH;
putenv("GOOGLE_APPLICATION_CREDENTIALS={$path}{$this->_keyFilename}.json");
$this->_client = new \Google_Client();
$this->_client->useApplicationDefaultCredentials();
$this->_client->setScopes(['https://www.googleapis.com/auth/content']);
$this->_service = new \Google_Service_ShoppingContent($this->_client);
}
/**
* @param Commerce_ProductModel $product
*
* @return bool
*/
public function onProductSave (Commerce_ProductModel $product)
{
$this->_initGoogleClient();
if (
!filter_var($product->availableOnline, FILTER_VALIDATE_BOOLEAN)
|| !$product->enabled
) return true;
foreach ($product->variants as $variant) {
$gProduct = new \Google_Service_ShoppingContent_Product();
$gProduct->setId($product->slug . '_' . $variant->id);
// If we don't have a valid GTIN number, skip since Google won't allow it.
if (!$this->_checkGTIN($variant->sku))
continue;
$gProduct->setGtin($variant->sku);
$gProduct->setTitle($product->getTitle());
$gProduct->setDescription(strip_tags($product->productDetails));
$gProduct->setProductType($product->productCategory->last()->getTitle());
$url = $product->getUrl();
if (!$variant->isDefault)
$url .= '/' . $variant->id;
$gProduct->setLink($url);
$gProduct->setImageLink($variant->gallery->first()->getUrl('gallery'));
$gProduct->setCondition('new');
$gProduct->setAvailability($variant->stock > 0 || $variant->unlimitedStock ? 'in stock' : 'out of stock');
// If we don't have a brand, skip since Google won't allow it.
if (!$product->brand->first())
continue;
$gProduct->setBrand($product->brand->first()->getTitle());
$gProduct->setChannel($product->availableOnline ? 'online' : 'local');
$gProduct->setContentLanguage('EN');
$gProduct->setOfferId("P{$product->id}V{$variant->id}");
$gProduct->setTargetCountry('GB');
// TODO: Find a way to not have to hard-code shipping values
$shipping_price = new \Google_Service_ShoppingContent_Price();
if ($product->getShippingCategory()->handle == 'aquaOak') {
$shipping_price->setValue(50.00);
} else {
$shipping_price->setValue(
$variant->price > 49.99 || $product->freeShipping
? '0.00'
: '5.95'
);
}
$shipping_price->setCurrency('GBP');
$shipping = new \Google_Service_ShoppingContent_ProductShipping();
$shipping->setPrice($shipping_price);
$shipping->setCountry('GB');
$shipping->setService('Standard shipping');
$gProduct->setShipping([$shipping]);
$price = new \Google_Service_ShoppingContent_Price();
$price->setCurrency('GBP');
$price->setValue($variant->price);
$gProduct->setPrice($price);
if ($variant->getOnSale()) {
$salePrice = new \Google_Service_ShoppingContent_Price();
$salePrice->setCurrency('GBP');
$salePrice->setValue($variant->getSalePrice());
$gProduct->setSalePrice($salePrice);
}
try {
$this->_service->products->insert(
$this->_merchantId,
$gProduct,
['dryRun' => craft()->config->get('devMode')]
);
}
catch (\Google_Service_Exception $e)
{
$message = "[Product ID {$product->id}] [Variant ID {$variant->id}] ";
if (!empty($e->getErrors()) && array_key_exists('message', $e->getErrors()[0]))
$message .= $e->getErrors()[0]['message'];
BPlugin::log(print_r($message, true), LogLevel::Error, true);
}
}
return true;
}
/**
* @param Commerce_ProductModel $product
*
* @return bool
*/
public function onProductDelete (Commerce_ProductModel $product)
{
$this->_initGoogleClient();
if (!$product->availableOnline) return true;
foreach ($product->variants as $variant) {
try {
$this->_service->products->delete($this->_merchantId, $product->slug . '_' . $variant->id);
}
catch (\Exception $e)
{
BPlugin::log(print_r($e, true), LogLevel::Error, true);
return true; // Fail silently to stop clogging up tasks
}
}
return true;
}
// Private
// =========================================================================
# Check length of barcode for validity
function _checkGTIN ($gtin) {
# Check that GTIN provided is a certain length
if (!$this->_checkBasics($gtin))
return false;
# Define fixed variables
$CheckDigitArray = [];
$gtinMaths = [3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3];
$modifier = 17 - (strlen($gtin) - 1); // Gets the position to place first digit in array
$gtinCheckDigit = substr($gtin, -1); // Get provided check digit
$BarcodeArray = str_split($gtin); // Split barcode at each digit into array
$gtinLength = strlen($gtin);
$tmpCheckDigit = 0;
$tmpCheckSum = 0;
$tmpMath = 0;
# Run through and put digits into multiplication table
for ($i=0; $i < ($gtinLength - 1); $i++) {
$CheckDigitArray[$modifier + $i] = $BarcodeArray[$i]; // Add barcode digits to Multiplication Table
// Catch if part of GTIN is not a number
if (!is_numeric($CheckDigitArray[$modifier + $i]))
return false;
}
# Calculate "Sum" of barcode digits
for ($i=$modifier; $i < 17; $i++) {
$tmpCheckSum += ($CheckDigitArray[$i] * $gtinMaths[$i]);
}
# Difference from Rounded-Up-To-Nearest-10 - Fianl Check Digit Calculation
$tmpCheckDigit = (ceil($tmpCheckSum / 10) * 10) - $tmpCheckSum;
# Check if last digit is same as calculated check digit
if ($gtinCheckDigit == $tmpCheckDigit)
return true;
return false;
}
# Checks the length of the GTIN
function _checkBasics ($gtin) {
# Check length is ok
if (strlen($gtin) < 8 || strlen($gtin) > 14)
return false;
# Check whether is a number
preg_match("/\d+/", $gtin, $m, PREG_OFFSET_CAPTURE, 0);
if (empty($m))
return false;
# Is valid, return true
return true;
}
}
<?php
namespace Craft;
class B_UpdateGoogleProductTask extends BaseTask
{
public function getDescription ()
{
return 'Updating Google Shopping';
}
public function getTotalSteps ()
{
return count($this->getSettings()->productIds);
}
public function runStep ($step)
{
$product = craft()->commerce_products->getProductById($this->getSettings()->productIds[$step]);
try {
craft()->b_google->onProductSave($product);
} catch (\Exception $e) {}
return true;
}
// Protected
// =========================================================================
protected function defineSettings ()
{
return [
'productIds' => AttributeType::Mixed
];
}
}
<?php
// Stripped down for brevity
class BPlugin {
public function init () {
// Trigger Google Shopping updates
// =====================================================================
if (!craft()->config->get('devMode')) {
craft()->on('commerce_products.onSaveProduct',
function (Event $event) {
craft()->tasks->createTask('B_UpdateGoogleProduct', null, [
'productIds' => [$event->params['product']->id],
]);
});
craft()->on('commerce_products.onBeforeDeleteProduct',
function (Event $event) {
craft()->tasks->createTask('B_DeleteGoogleProduct', null, [
'productIds' => [$event->params['product']->id],
]);
});
craft()->on('commerce_variants.onOrderVariant',
function (Event $event) {
craft()->tasks->createTask('B_UpdateGoogleProduct', null, [
'productIds' => [$event->params['variant']->productId],
]);
});
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment