Version Notes
- Configurable cron schedule
- Support for websites with Flat Catalog disabled
Download this release
Release Info
| Developer | Digital Pianism |
| Extension | DigitalPianism_Abandonedcarts |
| Version | 0.1.13 |
| Comparing to | |
| See all releases | |
Code changes from version 0.1.12 to 0.1.13
- app/code/community/DigitalPianism/Abandonedcarts/Helper/Data.php +3 -3
- app/code/community/DigitalPianism/Abandonedcarts/Model/Observer.php +211 -145
- app/code/community/DigitalPianism/Abandonedcarts/etc/config.xml +10 -13
- app/code/community/DigitalPianism/Abandonedcarts/etc/system.xml +8 -0
- package.xml +7 -9
app/code/community/DigitalPianism/Abandonedcarts/Helper/Data.php
CHANGED
|
@@ -21,7 +21,7 @@ class DigitalPianism_Abandonedcarts_Helper_Data extends Mage_Core_Helper_Abstrac
|
|
| 21 |
*/
|
| 22 |
public function isEnabled()
|
| 23 |
{
|
| 24 |
-
return Mage::
|
| 25 |
}
|
| 26 |
|
| 27 |
/**
|
|
@@ -29,7 +29,7 @@ class DigitalPianism_Abandonedcarts_Helper_Data extends Mage_Core_Helper_Abstrac
|
|
| 29 |
*/
|
| 30 |
public function isSaleEnabled()
|
| 31 |
{
|
| 32 |
-
return Mage::
|
| 33 |
}
|
| 34 |
|
| 35 |
/**
|
|
@@ -37,7 +37,7 @@ class DigitalPianism_Abandonedcarts_Helper_Data extends Mage_Core_Helper_Abstrac
|
|
| 37 |
*/
|
| 38 |
public function getDryRun()
|
| 39 |
{
|
| 40 |
-
return Mage::
|
| 41 |
}
|
| 42 |
|
| 43 |
/**
|
| 21 |
*/
|
| 22 |
public function isEnabled()
|
| 23 |
{
|
| 24 |
+
return Mage::getStoreConfig('abandonedcartsconfig/options/enable');
|
| 25 |
}
|
| 26 |
|
| 27 |
/**
|
| 29 |
*/
|
| 30 |
public function isSaleEnabled()
|
| 31 |
{
|
| 32 |
+
return Mage::getStoreConfig('abandonedcartsconfig/options/enable_sale');
|
| 33 |
}
|
| 34 |
|
| 35 |
/**
|
| 37 |
*/
|
| 38 |
public function getDryRun()
|
| 39 |
{
|
| 40 |
+
return Mage::getStoreConfig('abandonedcartsconfig/options/dryrun');
|
| 41 |
}
|
| 42 |
|
| 43 |
/**
|
app/code/community/DigitalPianism/Abandonedcarts/Model/Observer.php
CHANGED
|
@@ -232,7 +232,7 @@ class DigitalPianism_Abandonedcarts_Model_Observer extends Mage_Core_Model_Abstr
|
|
| 232 |
// Save only if dryrun is false or if the test email is set and found
|
| 233 |
if (!$dryrun || (isset($testemail) && $email == $testemail))
|
| 234 |
{
|
| 235 |
-
|
| 236 |
}
|
| 237 |
}
|
| 238 |
}
|
|
@@ -305,7 +305,7 @@ class DigitalPianism_Abandonedcarts_Model_Observer extends Mage_Core_Model_Abstr
|
|
| 305 |
// Save only if dryrun is false or if the test email is set and found
|
| 306 |
if (!$dryrun || (isset($testemail) && $email == $testemail))
|
| 307 |
{
|
| 308 |
-
|
| 309 |
}
|
| 310 |
}
|
| 311 |
}
|
|
@@ -333,6 +333,11 @@ class DigitalPianism_Abandonedcarts_Model_Observer extends Mage_Core_Model_Abstr
|
|
| 333 |
// Get the attribute id for the status attribute
|
| 334 |
$eavAttribute = Mage::getModel('eav/entity_attribute');
|
| 335 |
$statusId = $eavAttribute->getIdByCode('catalog_product', 'status');
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 336 |
|
| 337 |
// Loop through the stores
|
| 338 |
foreach (Mage::app()->getWebsites() as $website) {
|
|
@@ -351,93 +356,122 @@ class DigitalPianism_Abandonedcarts_Model_Observer extends Mage_Core_Model_Abstr
|
|
| 351 |
// Get the product collection
|
| 352 |
$collection = Mage::getResourceModel('catalog/product_collection')->setStore($storeId);
|
| 353 |
|
| 354 |
-
//
|
| 355 |
-
|
| 356 |
-
$
|
| 357 |
-
|
| 358 |
-
|
| 359 |
-
|
| 360 |
-
|
| 361 |
-
|
| 362 |
-
|
| 363 |
-
|
| 364 |
-
|
| 365 |
-
|
| 366 |
-
|
| 367 |
-
|
| 368 |
-
|
| 369 |
-
|
| 370 |
-
|
| 371 |
-
|
| 372 |
-
|
| 373 |
-
|
| 374 |
-
|
| 375 |
-
|
| 376 |
-
|
| 377 |
-
|
| 378 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 379 |
)
|
| 380 |
-
|
| 381 |
-
|
| 382 |
-
|
| 383 |
-
|
| 384 |
-
|
| 385 |
-
|
| 386 |
-
|
| 387 |
-
|
| 388 |
-
|
| 389 |
-
|
| 390 |
-
|
| 391 |
-
|
| 392 |
-
|
| 393 |
-
|
| 394 |
-
|
| 395 |
-
|
| 396 |
-
|
| 397 |
-
|
| 398 |
-
|
| 399 |
-
|
| 400 |
-
|
| 401 |
-
|
| 402 |
-
|
| 403 |
-
|
| 404 |
-
|
| 405 |
-
|
| 406 |
-
|
| 407 |
-
|
| 408 |
-
|
| 409 |
-
|
| 410 |
-
|
| 411 |
-
|
| 412 |
-
|
| 413 |
-
|
| 414 |
-
|
| 415 |
-
|
| 416 |
-
|
| 417 |
-
|
| 418 |
-
|
| 419 |
-
|
| 420 |
-
|
| 421 |
-
|
| 422 |
-
|
| 423 |
-
->joinInner(
|
| 424 |
-
array('catalog_special_to' => Mage::getSingleton("core/resource")->getTableName('catalog_product_entity_datetime')),
|
| 425 |
-
'catalog_special_to.entity_id = e.entity_id
|
| 426 |
-
AND attribute_id = (SELECT attribute_id FROM eav_attribute LEFT JOIN "eav_entity_type" ON eav_attribute.entity_type_id = eav_entity_type.entity_type_id WHERE eav_attribute.attribute_code = "special_to" AND eav_entity_type.entity_type_code = "catalog_product")
|
| 427 |
-
AND catalog_special_to.store_id = '.$storeId,
|
| 428 |
-
null)
|
| 429 |
-
*/
|
| 430 |
-
->joinInner(
|
| 431 |
-
array('catalog_enabled' => Mage::getSingleton("core/resource")->getTableName('catalog_product_entity_int')),
|
| 432 |
-
'catalog_enabled.entity_id = e.entity_id AND catalog_enabled.attribute_id = '.$statusId.' AND catalog_enabled.value = 1',
|
| 433 |
-
null)
|
| 434 |
-
->joinInner(
|
| 435 |
-
array('inventory' => Mage::getSingleton("core/resource")->getTableName('cataloginventory_stock_status')),
|
| 436 |
-
'inventory.product_id = e.entity_id AND inventory.stock_status = 1 AND inventory.website_id = '.$websiteId,
|
| 437 |
-
null)
|
| 438 |
-
->order('quote_table.updated_at DESC');
|
| 439 |
|
| 440 |
-
|
| 441 |
$collection->load();
|
| 442 |
|
| 443 |
// Skip the rest of the code if the collection is empty
|
|
@@ -492,9 +526,11 @@ class DigitalPianism_Abandonedcarts_Model_Observer extends Mage_Core_Model_Abstr
|
|
| 492 |
$delay = date('Y-m-d H:i:s', strtotime("+7 day"));
|
| 493 |
}
|
| 494 |
|
| 495 |
-
// Get the attribute id for
|
| 496 |
$eavAttribute = Mage::getModel('eav/entity_attribute');
|
| 497 |
$statusId = $eavAttribute->getIdByCode('catalog_product', 'status');
|
|
|
|
|
|
|
| 498 |
|
| 499 |
// Loop through the stores
|
| 500 |
foreach (Mage::app()->getWebsites() as $website) {
|
|
@@ -512,65 +548,95 @@ class DigitalPianism_Abandonedcarts_Model_Observer extends Mage_Core_Model_Abstr
|
|
| 512 |
// Get the product collection
|
| 513 |
$collection = Mage::getResourceModel('catalog/product_collection')->setStore($storeId);
|
| 514 |
|
| 515 |
-
//
|
| 516 |
-
|
| 517 |
-
|
| 518 |
-
|
| 519 |
-
|
| 520 |
-
|
| 521 |
-
|
| 522 |
-
|
| 523 |
-
|
| 524 |
-
|
| 525 |
-
|
| 526 |
-
|
| 527 |
-
|
| 528 |
-
|
| 529 |
-
|
| 530 |
-
|
| 531 |
-
|
| 532 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 533 |
)
|
| 534 |
-
|
| 535 |
-
|
| 536 |
-
|
| 537 |
-
|
| 538 |
-
|
| 539 |
-
|
| 540 |
-
|
| 541 |
-
|
| 542 |
-
|
| 543 |
-
|
| 544 |
-
|
| 545 |
-
|
| 546 |
-
|
| 547 |
-
|
| 548 |
-
|
| 549 |
-
|
| 550 |
-
|
| 551 |
-
|
| 552 |
-
|
| 553 |
-
|
| 554 |
-
|
| 555 |
-
|
| 556 |
-
|
| 557 |
-
|
| 558 |
-
|
| 559 |
-
|
| 560 |
-
|
| 561 |
-
|
| 562 |
-
*/
|
| 563 |
-
->joinInner(
|
| 564 |
-
array('catalog_enabled' => Mage::getSingleton("core/resource")->getTableName('catalog_product_entity_int')),
|
| 565 |
-
'catalog_enabled.entity_id = e.entity_id AND catalog_enabled.attribute_id = '.$statusId.' AND catalog_enabled.value = 1',
|
| 566 |
-
null)
|
| 567 |
-
->joinInner(
|
| 568 |
-
array('inventory' => Mage::getSingleton("core/resource")->getTableName('cataloginventory_stock_status')),
|
| 569 |
-
'inventory.product_id = e.entity_id AND inventory.stock_status = 1 AND website_id = '.$websiteId,
|
| 570 |
-
null)
|
| 571 |
-
->order('quote_table.updated_at DESC');
|
| 572 |
|
| 573 |
-
|
| 574 |
$collection->load();
|
| 575 |
|
| 576 |
// Call iterator walk method with collection query string and callback method as parameters
|
| 232 |
// Save only if dryrun is false or if the test email is set and found
|
| 233 |
if (!$dryrun || (isset($testemail) && $email == $testemail))
|
| 234 |
{
|
| 235 |
+
$quote->getResource()->saveAttribute($quote,array('abandoned_sale_notified'));
|
| 236 |
}
|
| 237 |
}
|
| 238 |
}
|
| 305 |
// Save only if dryrun is false or if the test email is set and found
|
| 306 |
if (!$dryrun || (isset($testemail) && $email == $testemail))
|
| 307 |
{
|
| 308 |
+
$quote->getResource()->saveAttribute($quote,array('abandoned_notified'));
|
| 309 |
}
|
| 310 |
}
|
| 311 |
}
|
| 333 |
// Get the attribute id for the status attribute
|
| 334 |
$eavAttribute = Mage::getModel('eav/entity_attribute');
|
| 335 |
$statusId = $eavAttribute->getIdByCode('catalog_product', 'status');
|
| 336 |
+
$nameId = $eavAttribute->getIdByCode('catalog_product', 'name');
|
| 337 |
+
$priceId = $eavAttribute->getIdByCode('catalog_product', 'price');
|
| 338 |
+
$spriceId = $eavAttribute->getIdByCode('catalog_product', 'special_price');
|
| 339 |
+
$spfromId = $eavAttribute->getIdByCode('catalog_product', 'special_from_date');
|
| 340 |
+
$sptoId = $eavAttribute->getIdByCode('catalog_product', 'special_to_date');
|
| 341 |
|
| 342 |
// Loop through the stores
|
| 343 |
foreach (Mage::app()->getWebsites() as $website) {
|
| 356 |
// Get the product collection
|
| 357 |
$collection = Mage::getResourceModel('catalog/product_collection')->setStore($storeId);
|
| 358 |
|
| 359 |
+
// Database TableNams
|
| 360 |
+
$eavEntityType = Mage::getSingleton("core/resource")->getTableName('eav_entity_type');
|
| 361 |
+
$eavAttribute = Mage::getSingleton("core/resource")->getTableName('eav_attribute');
|
| 362 |
+
|
| 363 |
+
// If flat catalog is enabled
|
| 364 |
+
if (Mage::helper('catalog/product_flat')->isEnabled())
|
| 365 |
+
{
|
| 366 |
+
// First collection: carts with products that became on sale
|
| 367 |
+
// Join the collection with the required tables
|
| 368 |
+
$collection->getSelect()
|
| 369 |
+
->reset(Zend_Db_Select::COLUMNS)
|
| 370 |
+
->columns(array('e.entity_id AS product_id',
|
| 371 |
+
'e.sku',
|
| 372 |
+
'catalog_flat.name as product_name',
|
| 373 |
+
'catalog_flat.price as product_price',
|
| 374 |
+
'catalog_flat.special_price as product_special_price',
|
| 375 |
+
'catalog_flat.special_from_date as product_special_from_date',
|
| 376 |
+
'catalog_flat.special_to_date as product_special_to_date',
|
| 377 |
+
'quote_table.entity_id as cart_id',
|
| 378 |
+
'quote_table.updated_at as cart_updated_at',
|
| 379 |
+
'quote_table.abandoned_sale_notified as has_been_notified',
|
| 380 |
+
'quote_items.price as product_price_in_cart',
|
| 381 |
+
'quote_table.customer_email as customer_email',
|
| 382 |
+
'quote_table.customer_firstname as customer_firstname',
|
| 383 |
+
'quote_table.customer_lastname as customer_lastname'
|
| 384 |
+
)
|
| 385 |
+
)
|
| 386 |
+
->joinInner(
|
| 387 |
+
array('quote_items' => Mage::getSingleton("core/resource")->getTableName('sales_flat_quote_item')),
|
| 388 |
+
'quote_items.product_id = e.entity_id AND quote_items.price > 0.00',
|
| 389 |
+
null)
|
| 390 |
+
->joinInner(
|
| 391 |
+
array('quote_table' => Mage::getSingleton("core/resource")->getTableName('sales_flat_quote')),
|
| 392 |
+
'quote_items.quote_id = quote_table.entity_id AND quote_table.items_count > 0 AND quote_table.is_active = 1 AND quote_table.customer_email IS NOT NULL AND quote_table.abandoned_sale_notified = 0 AND quote_table.store_id = '.$storeId,
|
| 393 |
+
null)
|
| 394 |
+
->joinInner(
|
| 395 |
+
array('catalog_flat' => Mage::getSingleton("core/resource")->getTableName('catalog_product_flat_'.$storeId)),
|
| 396 |
+
'catalog_flat.entity_id = e.entity_id',
|
| 397 |
+
null)
|
| 398 |
+
->joinInner(
|
| 399 |
+
array('catalog_enabled' => Mage::getSingleton("core/resource")->getTableName('catalog_product_entity_int')),
|
| 400 |
+
'catalog_enabled.entity_id = e.entity_id AND catalog_enabled.attribute_id = '.$statusId.' AND catalog_enabled.value = 1',
|
| 401 |
+
null)
|
| 402 |
+
->joinInner(
|
| 403 |
+
array('inventory' => Mage::getSingleton("core/resource")->getTableName('cataloginventory_stock_status')),
|
| 404 |
+
'inventory.product_id = e.entity_id AND inventory.stock_status = 1 AND inventory.website_id = '.$websiteId,
|
| 405 |
+
null)
|
| 406 |
+
->order('quote_table.updated_at DESC');
|
| 407 |
+
}
|
| 408 |
+
else
|
| 409 |
+
{
|
| 410 |
+
// First collection: carts with products that became on sale
|
| 411 |
+
// Join the collection with the required tables
|
| 412 |
+
$collection->getSelect()
|
| 413 |
+
->reset(Zend_Db_Select::COLUMNS)
|
| 414 |
+
->columns(array('e.entity_id AS product_id',
|
| 415 |
+
'e.sku',
|
| 416 |
+
'catalog_name.value as product_name',
|
| 417 |
+
'catalog_price.value as product_price',
|
| 418 |
+
'catalog_sprice.value as product_special_price',
|
| 419 |
+
'catalog_spfrom.value as product_special_from_date',
|
| 420 |
+
'catalog_spto.value as product_special_to_date',
|
| 421 |
+
'quote_table.entity_id as cart_id',
|
| 422 |
+
'quote_table.updated_at as cart_updated_at',
|
| 423 |
+
'quote_table.abandoned_sale_notified as has_been_notified',
|
| 424 |
+
'quote_items.price as product_price_in_cart',
|
| 425 |
+
'quote_table.customer_email as customer_email',
|
| 426 |
+
'quote_table.customer_firstname as customer_firstname',
|
| 427 |
+
'quote_table.customer_lastname as customer_lastname'
|
| 428 |
+
)
|
| 429 |
)
|
| 430 |
+
// Name
|
| 431 |
+
->joinInner(
|
| 432 |
+
array('catalog_name' => Mage::getSingleton("core/resource")->getTableName('catalog_product_entity_varchar')),
|
| 433 |
+
"catalog_name.entity_id = e.entity_id AND catalog_name.attribute_id = $nameId",
|
| 434 |
+
null)
|
| 435 |
+
// Price
|
| 436 |
+
->joinInner(
|
| 437 |
+
array('catalog_price' => Mage::getSingleton("core/resource")->getTableName('catalog_product_entity_decimal')),
|
| 438 |
+
"catalog_price.entity_id = e.entity_id AND catalog_price.attribute_id = $priceId",
|
| 439 |
+
null)
|
| 440 |
+
// Special Price
|
| 441 |
+
->joinInner(
|
| 442 |
+
array('catalog_sprice' => Mage::getSingleton("core/resource")->getTableName('catalog_product_entity_decimal')),
|
| 443 |
+
"catalog_sprice.entity_id = e.entity_id AND catalog_sprice.attribute_id = $spriceId",
|
| 444 |
+
null)
|
| 445 |
+
// Special From Date
|
| 446 |
+
->joinInner(
|
| 447 |
+
array('catalog_spfrom' => Mage::getSingleton("core/resource")->getTableName('catalog_product_entity_datetime')),
|
| 448 |
+
"catalog_spfrom.entity_id = e.entity_id AND catalog_spfrom.attribute_id = $spfromId",
|
| 449 |
+
null)
|
| 450 |
+
// Special To Date
|
| 451 |
+
->joinInner(
|
| 452 |
+
array('catalog_spto' => Mage::getSingleton("core/resource")->getTableName('catalog_product_entity_datetime')),
|
| 453 |
+
"catalog_spto.entity_id = e.entity_id AND catalog_spto.attribute_id = $sptoId",
|
| 454 |
+
null)
|
| 455 |
+
->joinInner(
|
| 456 |
+
array('quote_items' => Mage::getSingleton("core/resource")->getTableName('sales_flat_quote_item')),
|
| 457 |
+
'quote_items.product_id = e.entity_id AND quote_items.price > 0.00',
|
| 458 |
+
null)
|
| 459 |
+
->joinInner(
|
| 460 |
+
array('quote_table' => Mage::getSingleton("core/resource")->getTableName('sales_flat_quote')),
|
| 461 |
+
'quote_items.quote_id = quote_table.entity_id AND quote_table.items_count > 0 AND quote_table.is_active = 1 AND quote_table.customer_email IS NOT NULL AND quote_table.abandoned_sale_notified = 0 AND quote_table.store_id = '.$storeId,
|
| 462 |
+
null)
|
| 463 |
+
->joinInner(
|
| 464 |
+
array('catalog_enabled' => Mage::getSingleton("core/resource")->getTableName('catalog_product_entity_int')),
|
| 465 |
+
'catalog_enabled.entity_id = e.entity_id AND catalog_enabled.attribute_id = '.$statusId.' AND catalog_enabled.value = 1',
|
| 466 |
+
null)
|
| 467 |
+
->joinInner(
|
| 468 |
+
array('inventory' => Mage::getSingleton("core/resource")->getTableName('cataloginventory_stock_status')),
|
| 469 |
+
'inventory.product_id = e.entity_id AND inventory.stock_status = 1 AND inventory.website_id = '.$websiteId,
|
| 470 |
+
null)
|
| 471 |
+
->order('quote_table.updated_at DESC');
|
| 472 |
+
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 473 |
|
| 474 |
+
//$collection->printlogquery(true,true);
|
| 475 |
$collection->load();
|
| 476 |
|
| 477 |
// Skip the rest of the code if the collection is empty
|
| 526 |
$delay = date('Y-m-d H:i:s', strtotime("+7 day"));
|
| 527 |
}
|
| 528 |
|
| 529 |
+
// Get the attribute id for several attributes
|
| 530 |
$eavAttribute = Mage::getModel('eav/entity_attribute');
|
| 531 |
$statusId = $eavAttribute->getIdByCode('catalog_product', 'status');
|
| 532 |
+
$nameId = $eavAttribute->getIdByCode('catalog_product', 'name');
|
| 533 |
+
$priceId = $eavAttribute->getIdByCode('catalog_product', 'price');
|
| 534 |
|
| 535 |
// Loop through the stores
|
| 536 |
foreach (Mage::app()->getWebsites() as $website) {
|
| 548 |
// Get the product collection
|
| 549 |
$collection = Mage::getResourceModel('catalog/product_collection')->setStore($storeId);
|
| 550 |
|
| 551 |
+
// If flat catalog is enabled
|
| 552 |
+
if (Mage::helper('catalog/product_flat')->isEnabled())
|
| 553 |
+
{
|
| 554 |
+
// First collection: carts with products that became on sale
|
| 555 |
+
// Join the collection with the required tables
|
| 556 |
+
$collection->getSelect()
|
| 557 |
+
->reset(Zend_Db_Select::COLUMNS)
|
| 558 |
+
->columns(array('e.entity_id AS product_id',
|
| 559 |
+
'e.sku',
|
| 560 |
+
'catalog_flat.name as product_name',
|
| 561 |
+
'catalog_flat.price as product_price',
|
| 562 |
+
'quote_table.entity_id as cart_id',
|
| 563 |
+
'quote_table.updated_at as cart_updated_at',
|
| 564 |
+
'quote_table.abandoned_notified as has_been_notified',
|
| 565 |
+
'quote_table.customer_email as customer_email',
|
| 566 |
+
'quote_table.customer_firstname as customer_firstname',
|
| 567 |
+
'quote_table.customer_lastname as customer_lastname'
|
| 568 |
+
)
|
| 569 |
+
)
|
| 570 |
+
->joinInner(
|
| 571 |
+
array('quote_items' => Mage::getSingleton("core/resource")->getTableName('sales_flat_quote_item')),
|
| 572 |
+
'quote_items.product_id = e.entity_id AND quote_items.price > 0.00',
|
| 573 |
+
null)
|
| 574 |
+
->joinInner(
|
| 575 |
+
array('quote_table' => Mage::getSingleton("core/resource")->getTableName('sales_flat_quote')),
|
| 576 |
+
'quote_items.quote_id = quote_table.entity_id AND quote_table.items_count > 0 AND quote_table.is_active = 1 AND quote_table.customer_email IS NOT NULL AND quote_table.abandoned_notified = 0 AND quote_table.updated_at < "'.$delay.'" AND quote_table.store_id = '.$storeId,
|
| 577 |
+
null)
|
| 578 |
+
->joinInner(
|
| 579 |
+
array('catalog_flat' => Mage::getSingleton("core/resource")->getTableName('catalog_product_flat_'.$storeId)),
|
| 580 |
+
'catalog_flat.entity_id = e.entity_id',
|
| 581 |
+
null)
|
| 582 |
+
->joinInner(
|
| 583 |
+
array('catalog_enabled' => Mage::getSingleton("core/resource")->getTableName('catalog_product_entity_int')),
|
| 584 |
+
'catalog_enabled.entity_id = e.entity_id AND catalog_enabled.attribute_id = '.$statusId.' AND catalog_enabled.value = 1',
|
| 585 |
+
null)
|
| 586 |
+
->joinInner(
|
| 587 |
+
array('inventory' => Mage::getSingleton("core/resource")->getTableName('cataloginventory_stock_status')),
|
| 588 |
+
'inventory.product_id = e.entity_id AND inventory.stock_status = 1 AND website_id = '.$websiteId,
|
| 589 |
+
null)
|
| 590 |
+
->order('quote_table.updated_at DESC');
|
| 591 |
+
}
|
| 592 |
+
else
|
| 593 |
+
{
|
| 594 |
+
// First collection: carts with products that became on sale
|
| 595 |
+
// Join the collection with the required tables
|
| 596 |
+
$collection->getSelect()
|
| 597 |
+
->reset(Zend_Db_Select::COLUMNS)
|
| 598 |
+
->columns(array('e.entity_id AS product_id',
|
| 599 |
+
'e.sku',
|
| 600 |
+
'catalog_name.value as product_name',
|
| 601 |
+
'catalog_price.value as product_price',
|
| 602 |
+
'quote_table.entity_id as cart_id',
|
| 603 |
+
'quote_table.updated_at as cart_updated_at',
|
| 604 |
+
'quote_table.abandoned_notified as has_been_notified',
|
| 605 |
+
'quote_table.customer_email as customer_email',
|
| 606 |
+
'quote_table.customer_firstname as customer_firstname',
|
| 607 |
+
'quote_table.customer_lastname as customer_lastname'
|
| 608 |
+
)
|
| 609 |
)
|
| 610 |
+
// Name
|
| 611 |
+
->joinInner(
|
| 612 |
+
array('catalog_name' => Mage::getSingleton("core/resource")->getTableName('catalog_product_entity_varchar')),
|
| 613 |
+
"catalog_name.entity_id = e.entity_id AND catalog_name.attribute_id = $nameId",
|
| 614 |
+
null)
|
| 615 |
+
// Price
|
| 616 |
+
->joinInner(
|
| 617 |
+
array('catalog_price' => Mage::getSingleton("core/resource")->getTableName('catalog_product_entity_decimal')),
|
| 618 |
+
"catalog_price.entity_id = e.entity_id AND catalog_price.attribute_id = $priceId",
|
| 619 |
+
null)
|
| 620 |
+
->joinInner(
|
| 621 |
+
array('quote_items' => Mage::getSingleton("core/resource")->getTableName('sales_flat_quote_item')),
|
| 622 |
+
'quote_items.product_id = e.entity_id AND quote_items.price > 0.00',
|
| 623 |
+
null)
|
| 624 |
+
->joinInner(
|
| 625 |
+
array('quote_table' => Mage::getSingleton("core/resource")->getTableName('sales_flat_quote')),
|
| 626 |
+
'quote_items.quote_id = quote_table.entity_id AND quote_table.items_count > 0 AND quote_table.is_active = 1 AND quote_table.customer_email IS NOT NULL AND quote_table.abandoned_notified = 0 AND quote_table.updated_at < "'.$delay.'" AND quote_table.store_id = '.$storeId,
|
| 627 |
+
null)
|
| 628 |
+
->joinInner(
|
| 629 |
+
array('catalog_enabled' => Mage::getSingleton("core/resource")->getTableName('catalog_product_entity_int')),
|
| 630 |
+
'catalog_enabled.entity_id = e.entity_id AND catalog_enabled.attribute_id = '.$statusId.' AND catalog_enabled.value = 1',
|
| 631 |
+
null)
|
| 632 |
+
->joinInner(
|
| 633 |
+
array('inventory' => Mage::getSingleton("core/resource")->getTableName('cataloginventory_stock_status')),
|
| 634 |
+
'inventory.product_id = e.entity_id AND inventory.stock_status = 1 AND website_id = '.$websiteId,
|
| 635 |
+
null)
|
| 636 |
+
->order('quote_table.updated_at DESC');
|
| 637 |
+
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 638 |
|
| 639 |
+
//$collection->printlogquery(true,true);
|
| 640 |
$collection->load();
|
| 641 |
|
| 642 |
// Call iterator walk method with collection query string and callback method as parameters
|
app/code/community/DigitalPianism/Abandonedcarts/etc/config.xml
CHANGED
|
@@ -4,7 +4,7 @@
|
|
| 4 |
|
| 5 |
<modules>
|
| 6 |
<DigitalPianism_Abandonedcarts>
|
| 7 |
-
<version>0.1.
|
| 8 |
</DigitalPianism_Abandonedcarts>
|
| 9 |
</modules>
|
| 10 |
|
|
@@ -65,24 +65,23 @@
|
|
| 65 |
<abandonedcarts>
|
| 66 |
<class>DigitalPianism_Abandonedcarts_Model</class>
|
| 67 |
</abandonedcarts>
|
| 68 |
-
|
| 69 |
-
|
| 70 |
-
|
| 71 |
-
|
| 72 |
-
|
| 73 |
-
</sales_resource>
|
| 74 |
</models>
|
| 75 |
|
| 76 |
<template>
|
| 77 |
<email>
|
| 78 |
<abandonedcartsconfig_options_email_template translate="label" module="abandonedcarts">
|
| 79 |
<label>Abandoned Cart Template</label>
|
| 80 |
-
<file>digitalpianism/
|
| 81 |
<type>html</type>
|
| 82 |
</abandonedcartsconfig_options_email_template>
|
| 83 |
<abandonedcartsconfig_options_email_template_sale translate="label" module="abandonedcarts">
|
| 84 |
<label>Abandoned Cart Sale Template</label>
|
| 85 |
-
<file>digitalpianism/
|
| 86 |
<type>html</type>
|
| 87 |
</abandonedcartsconfig_options_email_template_sale>
|
| 88 |
</email>
|
|
@@ -115,7 +114,7 @@
|
|
| 115 |
<jobs>
|
| 116 |
<digitalpianism_abandonedcarts_send>
|
| 117 |
<schedule>
|
| 118 |
-
<
|
| 119 |
</schedule>
|
| 120 |
<run>
|
| 121 |
<model>abandonedcarts/observer::sendAbandonedCartsEmail</model>
|
|
@@ -128,9 +127,7 @@
|
|
| 128 |
<default>
|
| 129 |
<abandonedcartsconfig>
|
| 130 |
<options>
|
| 131 |
-
<
|
| 132 |
-
<enable_sale>0</enable_sale>
|
| 133 |
-
<dryrun>0</dryrun>
|
| 134 |
<notify_delay>20</notify_delay>
|
| 135 |
<email_template>abandonedcartsconfig_options_email_template</email_template>
|
| 136 |
<email_template_sale>abandonedcartsconfig_options_email_template_sale</email_template_sale>
|
| 4 |
|
| 5 |
<modules>
|
| 6 |
<DigitalPianism_Abandonedcarts>
|
| 7 |
+
<version>0.1.13</version>
|
| 8 |
</DigitalPianism_Abandonedcarts>
|
| 9 |
</modules>
|
| 10 |
|
| 65 |
<abandonedcarts>
|
| 66 |
<class>DigitalPianism_Abandonedcarts_Model</class>
|
| 67 |
</abandonedcarts>
|
| 68 |
+
<sales_resource>
|
| 69 |
+
<rewrite>
|
| 70 |
+
<quote>DigitalPianism_Abandonedcarts_Model_Sales_Resource_Quote</quote>
|
| 71 |
+
</rewrite>
|
| 72 |
+
</sales_resource>
|
|
|
|
| 73 |
</models>
|
| 74 |
|
| 75 |
<template>
|
| 76 |
<email>
|
| 77 |
<abandonedcartsconfig_options_email_template translate="label" module="abandonedcarts">
|
| 78 |
<label>Abandoned Cart Template</label>
|
| 79 |
+
<file>digitalpianism/sales_abandonedcarts.html</file>
|
| 80 |
<type>html</type>
|
| 81 |
</abandonedcartsconfig_options_email_template>
|
| 82 |
<abandonedcartsconfig_options_email_template_sale translate="label" module="abandonedcarts">
|
| 83 |
<label>Abandoned Cart Sale Template</label>
|
| 84 |
+
<file>digitalpianism/sales_abandonedcarts_sale.html</file>
|
| 85 |
<type>html</type>
|
| 86 |
</abandonedcartsconfig_options_email_template_sale>
|
| 87 |
</email>
|
| 114 |
<jobs>
|
| 115 |
<digitalpianism_abandonedcarts_send>
|
| 116 |
<schedule>
|
| 117 |
+
<config_path>abandonedcartsconfig/options/cron_expr</config_path>
|
| 118 |
</schedule>
|
| 119 |
<run>
|
| 120 |
<model>abandonedcarts/observer::sendAbandonedCartsEmail</model>
|
| 127 |
<default>
|
| 128 |
<abandonedcartsconfig>
|
| 129 |
<options>
|
| 130 |
+
<cron_expr>0 1 * * *</cron_expr>
|
|
|
|
|
|
|
| 131 |
<notify_delay>20</notify_delay>
|
| 132 |
<email_template>abandonedcartsconfig_options_email_template</email_template>
|
| 133 |
<email_template_sale>abandonedcartsconfig_options_email_template_sale</email_template_sale>
|
app/code/community/DigitalPianism/Abandonedcarts/etc/system.xml
CHANGED
|
@@ -32,6 +32,14 @@
|
|
| 32 |
<show_in_website>1</show_in_website>
|
| 33 |
<show_in_store>1</show_in_store>
|
| 34 |
</enable>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 35 |
<name translate="label">
|
| 36 |
<label>Sender Name</label>
|
| 37 |
<frontend_type>text</frontend_type>
|
| 32 |
<show_in_website>1</show_in_website>
|
| 33 |
<show_in_store>1</show_in_store>
|
| 34 |
</enable>
|
| 35 |
+
<cron_expr translate="label">
|
| 36 |
+
<label>Cron Schedule</label>
|
| 37 |
+
<frontend_type>text</frontend_type>
|
| 38 |
+
<sort_order>15</sort_order>
|
| 39 |
+
<show_in_default>1</show_in_default>
|
| 40 |
+
<show_in_website>1</show_in_website>
|
| 41 |
+
<show_in_store>1</show_in_store>
|
| 42 |
+
</cron_expr>
|
| 43 |
<name translate="label">
|
| 44 |
<label>Sender Name</label>
|
| 45 |
<frontend_type>text</frontend_type>
|
package.xml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
| 1 |
<?xml version="1.0"?>
|
| 2 |
<package>
|
| 3 |
<name>DigitalPianism_Abandonedcarts</name>
|
| 4 |
-
<version>0.1.
|
| 5 |
<stability>stable</stability>
|
| 6 |
<license uri="http://opensource.org/licenses/osl-3.0.php">OSL v3.0</license>
|
| 7 |
<channel>community</channel>
|
|
@@ -39,8 +39,6 @@ Follow this link and log in to finalize your purchase with the new special price
|
|
| 39 |

|
| 40 |
<h2>Configuration</h2>
|
| 41 |

|
| 42 |
-
<p>For this module to work properly, you need to enable Flat Catalog Product under System &gt; Configuration &gt; Catalog &gt; Catalog.</p>
|
| 43 |
-

|
| 44 |
<h3>Emails Design</h3>
|
| 45 |

|
| 46 |
<ol>
|
|
@@ -57,6 +55,7 @@ Access the module configuration under System &gt; Configuration &gt; Dig
|
|
| 57 |

|
| 58 |
<ul>
|
| 59 |
<li>Enable Abandoned Carts Notification: setting this option to Yes will enabled the email notification for customers who abandoned their carts.</li>
|
|
|
|
| 60 |
<li>Sender Name: here you can provide the sender name of the notification email</li>
|
| 61 |
<li>Sender Email: here you can provide the sender email of the notification email</li>
|
| 62 |
<li>Email Template for Unaltered Abandoned Carts: here you have to choose the email template you created previously for the "Abandoned Carts" email.</li>
|
|
@@ -74,8 +73,6 @@ Access the module configuration under System &gt; Configuration &gt; Dig
|
|
| 74 |

|
| 75 |
Save the configuration.
|
| 76 |

|
| 77 |
-
<p>The emails are sent everyday at midnight via a cron job.</p>
|
| 78 |
-

|
| 79 |
<h3>Email Variables</h3>
|
| 80 |

|
| 81 |
<p>The following variables are being used in the email templates that come with the extension.</p>
|
|
@@ -98,11 +95,12 @@ Save the configuration.
|
|
| 98 |

|
| 99 |
<p>To manually trigger the notification system, please access System &gt; Configuration &gt; Digital Pianism &gt; Abandoned carts email and click on the "Send" button</p>
|
| 100 |
<p>Please note that this functionality will send abandoned carts notification regardless the delay you provided, all possible abandoned carts emails will be sent.</p></description>
|
| 101 |
-
<notes>-
|
|
|
|
| 102 |
<authors><author><name>Digital Pianism</name><user>digitalpianism</user><email>contact@digital-pianism.com</email></author></authors>
|
| 103 |
-
<date>2015-07-
|
| 104 |
-
<time>
|
| 105 |
-
<contents><target name="magecommunity"><dir name="DigitalPianism"><dir name="Abandonedcarts"><dir name="Block"><dir name="Adminhtml"><dir name="System"><dir name="Config"><dir name="Form"><file name="Button.php" hash="d5a6f33d47d067fc09a7b7fe8eacd287"/></dir></dir></dir></dir></dir><dir name="Helper"><file name="Data.php" hash="
|
| 106 |
<compatible/>
|
| 107 |
<dependencies><required><php><min>4.1.0</min><max>6.0.0</max></php></required></dependencies>
|
| 108 |
</package>
|
| 1 |
<?xml version="1.0"?>
|
| 2 |
<package>
|
| 3 |
<name>DigitalPianism_Abandonedcarts</name>
|
| 4 |
+
<version>0.1.13</version>
|
| 5 |
<stability>stable</stability>
|
| 6 |
<license uri="http://opensource.org/licenses/osl-3.0.php">OSL v3.0</license>
|
| 7 |
<channel>community</channel>
|
| 39 |

|
| 40 |
<h2>Configuration</h2>
|
| 41 |

|
|
|
|
|
|
|
| 42 |
<h3>Emails Design</h3>
|
| 43 |

|
| 44 |
<ol>
|
| 55 |

|
| 56 |
<ul>
|
| 57 |
<li>Enable Abandoned Carts Notification: setting this option to Yes will enabled the email notification for customers who abandoned their carts.</li>
|
| 58 |
+
<li>Cron Schedule: here you can change the cron schedule time, it is set to 1AM by default.</li>
|
| 59 |
<li>Sender Name: here you can provide the sender name of the notification email</li>
|
| 60 |
<li>Sender Email: here you can provide the sender email of the notification email</li>
|
| 61 |
<li>Email Template for Unaltered Abandoned Carts: here you have to choose the email template you created previously for the "Abandoned Carts" email.</li>
|
| 73 |

|
| 74 |
Save the configuration.
|
| 75 |

|
|
|
|
|
|
|
| 76 |
<h3>Email Variables</h3>
|
| 77 |

|
| 78 |
<p>The following variables are being used in the email templates that come with the extension.</p>
|
| 95 |

|
| 96 |
<p>To manually trigger the notification system, please access System &gt; Configuration &gt; Digital Pianism &gt; Abandoned carts email and click on the "Send" button</p>
|
| 97 |
<p>Please note that this functionality will send abandoned carts notification regardless the delay you provided, all possible abandoned carts emails will be sent.</p></description>
|
| 98 |
+
<notes>- Configurable cron schedule
|
| 99 |
+
- Support for websites with Flat Catalog disabled</notes>
|
| 100 |
<authors><author><name>Digital Pianism</name><user>digitalpianism</user><email>contact@digital-pianism.com</email></author></authors>
|
| 101 |
+
<date>2015-07-22</date>
|
| 102 |
+
<time>11:41:57</time>
|
| 103 |
+
<contents><target name="magecommunity"><dir name="DigitalPianism"><dir name="Abandonedcarts"><dir name="Block"><dir name="Adminhtml"><dir name="System"><dir name="Config"><dir name="Form"><file name="Button.php" hash="d5a6f33d47d067fc09a7b7fe8eacd287"/></dir></dir></dir></dir></dir><dir name="Helper"><file name="Data.php" hash="4eda7b865d023206a58a4178f7db81a5"/></dir><dir name="Model"><file name="Observer.php" hash="bbf901e5e623244b0a60cf3362c80628"/><dir name="Sales"><dir name="Resource"><file name="Quote.php" hash="3b2f9f24a74a6ea3b6851d64bd6ae5ba"/></dir></dir></dir><dir name="controllers"><dir name="Adminhtml"><file name="AbandonedcartsController.php" hash="ca68e31a5e41f036451a409a7eeaaa16"/></dir></dir><dir name="etc"><file name="adminhtml.xml" hash="8ddca513c0ed7e034c476f3e026ceda8"/><file name="config.xml" hash="f62c5c11a0e1c99b1a03da4d0de4eec6"/><file name="system.xml" hash="d54fa8ad3607a7f54809f967ebff6ce6"/></dir><dir name="sql"><dir name="abandonedcarts_setup"><file name="install-0.0.1.php" hash="851338e4a710b5d94fead688b065f4b5"/><file name="upgrade-0.0.1-0.0.2.php" hash="0227c009e49b97bcf3f34f84c49f0927"/></dir></dir></dir></dir></target><target name="mageetc"><dir name="modules"><file name="DigitalPianism_Abandonedcarts.xml" hash="8a7657855486c68d548db4ba48e083d2"/></dir></target><target name="magedesign"><dir name="adminhtml"><dir name="default"><dir name="default"><dir name="template"><dir name="digitalpianism"><dir name="abandonedcarts"><dir name="system"><dir name="config"><file name="button.phtml" hash="8f7e673ea52cd81b616cac01b1022990"/></dir></dir></dir></dir></dir></dir></dir></dir></target><target name="magelocale"><dir name="en_US"><dir name="template"><dir name="email"><dir name="digitalpianism"><dir name="abandonedcarts"><file name="sales_abandonedcarts.html" hash="30565f91c47913465fd184a214c14b23"/><file name="sales_abandonedcarts_sale.html" hash="3cdee557727cb0166741062e5fdcf06f"/></dir></dir></dir></dir><file name="DigitalPianism_Abandonedcarts.csv" hash="4e17b6cae58dd1cdcd43b1113e2e09f4"/></dir></target></contents>
|
| 104 |
<compatible/>
|
| 105 |
<dependencies><required><php><min>4.1.0</min><max>6.0.0</max></php></required></dependencies>
|
| 106 |
</package>
|
