Version Notes
First stable release.
Download this release
Release Info
Developer | Seg |
Extension | seg |
Version | 1.0.0.0 |
Comparing to | |
See all releases |
Version 1.0.0.0
- app/code/community/Koan/.DS_Store +0 -0
- app/code/community/Koan/Seg/Block/Adminhtml/Exporter.php +95 -0
- app/code/community/Koan/Seg/Block/Adminhtml/Exporter/Grid.php +88 -0
- app/code/community/Koan/Seg/Block/Adminhtml/Exporter/Grid/Renderer/Status.php +25 -0
- app/code/community/Koan/Seg/Block/Header.php +21 -0
- app/code/community/Koan/Seg/Block/Track.php +284 -0
- app/code/community/Koan/Seg/Helper/Data.php +179 -0
- app/code/community/Koan/Seg/Model/Batch/Status.php +145 -0
- app/code/community/Koan/Seg/Model/Exception/Handler.php +26 -0
- app/code/community/Koan/Seg/Model/Logger.php +13 -0
- app/code/community/Koan/Seg/Model/Observer.php +83 -0
- app/code/community/Koan/Seg/Model/Resource/Batch/Status.php +9 -0
- app/code/community/Koan/Seg/Model/Resource/Batch/Status/Collection.php +10 -0
- app/code/community/Koan/Seg/Model/Seg/Basket.php +87 -0
- app/code/community/Koan/Seg/Model/Seg/Client.php +239 -0
- app/code/community/Koan/Seg/Model/Seg/Customer.php +71 -0
- app/code/community/Koan/Seg/Model/Seg/Exporter.php +384 -0
- app/code/community/Koan/Seg/Model/Seg/Order.php +78 -0
- app/code/community/Koan/Seg/Model/Seg/Order/Line.php +125 -0
- app/code/community/Koan/Seg/Model/Seg/Product.php +69 -0
- app/code/community/Koan/Seg/Model/Seg/Quote/Line.php +139 -0
- app/code/community/Koan/Seg/Model/Seg/Range.php +45 -0
- app/code/community/Koan/Seg/controllers/Adminhtml/SegController.php +123 -0
- app/code/community/Koan/Seg/controllers/IndexController.php +11 -0
- app/code/community/Koan/Seg/etc/adminhtml.xml +47 -0
- app/code/community/Koan/Seg/etc/config.xml +133 -0
- app/code/community/Koan/Seg/etc/system.xml +104 -0
- app/code/community/Koan/Seg/lib/Rollbar.php +986 -0
- app/code/community/Koan/Seg/sql/koan_seg_setup/install-1.0.0.0.php +14 -0
- app/code/community/Koan/Seg/sql/koan_seg_setup/upgrade-1.0.0.0-1.0.0.1.php +35 -0
- app/code/community/Koan/Seg/sql/koan_seg_setup/upgrade-1.0.0.1-1.0.0.2.php +16 -0
- app/design/adminhtml/default/default/layout/seg.xml +8 -0
- app/design/frontend/base/default/layout/seg.xml +12 -0
- app/design/frontend/base/default/template/seg/config.phtml +9 -0
- app/design/frontend/base/default/template/seg/tracking.phtml +23 -0
- app/etc/modules/Koan_Seg.xml +8 -0
- package.xml +41 -0
app/code/community/Koan/.DS_Store
ADDED
Binary file
|
app/code/community/Koan/Seg/Block/Adminhtml/Exporter.php
ADDED
@@ -0,0 +1,95 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
class Koan_Seg_Block_Adminhtml_Exporter extends Mage_Adminhtml_Block_Widget_Grid_Container
|
4 |
+
{
|
5 |
+
|
6 |
+
private function _getOrderBatchUrl()
|
7 |
+
{
|
8 |
+
$orderBatchUrl = Mage::getModel('adminhtml/url')->getUrl(
|
9 |
+
'adminhtml/seg/createBatchOrder',
|
10 |
+
array('order_date_from' => 'NO_FILTER')
|
11 |
+
);
|
12 |
+
|
13 |
+
return $orderBatchUrl;
|
14 |
+
}
|
15 |
+
|
16 |
+
public function __construct()
|
17 |
+
{
|
18 |
+
$this->_controller = 'adminhtml_exporter';
|
19 |
+
$this->_blockGroup = 'koan_seg';
|
20 |
+
$this->_headerText = Mage::helper('koan_seg')->__('Seg Exporter');
|
21 |
+
$this->_addButtonLabel = Mage::helper('koan_seg')->__('Export');
|
22 |
+
parent::__construct();
|
23 |
+
$this->_removeButton('add');
|
24 |
+
|
25 |
+
$customerUrl = Mage::getModel('adminhtml/url')->getUrl(
|
26 |
+
'adminhtml/seg/createBatchCustomer',
|
27 |
+
null
|
28 |
+
);
|
29 |
+
|
30 |
+
|
31 |
+
$this->addButton(
|
32 |
+
'start_order_batch',
|
33 |
+
array(
|
34 |
+
'label' => Mage::helper('koan_seg')->__('Start New Orders Export Batch'),
|
35 |
+
'onclick' => 'getOrderBatchUrl()',
|
36 |
+
'class' => 'add',
|
37 |
+
'before_html' => $this->_getDateSelectorHtml()
|
38 |
+
)
|
39 |
+
);
|
40 |
+
|
41 |
+
$this->addButton(
|
42 |
+
'start_customer_batch',
|
43 |
+
array(
|
44 |
+
'label' => Mage::helper('koan_seg')->__('Start New Customers Export Batch'),
|
45 |
+
'onclick' => 'setLocation(\'' . $customerUrl . '\')',
|
46 |
+
'class' => 'add',
|
47 |
+
'style' => 'margin-right:20px;'
|
48 |
+
)
|
49 |
+
);
|
50 |
+
}
|
51 |
+
|
52 |
+
private function _getDateSelectorHtml()
|
53 |
+
{
|
54 |
+
$element = new Varien_Data_Form_Element_Date(
|
55 |
+
array(
|
56 |
+
'name' => 'order_date_filter',
|
57 |
+
'label' => Mage::helper('koan_seg')->__('Date'),
|
58 |
+
'tabindex' => 1,
|
59 |
+
'image' => $this->getSkinUrl('images/grid-cal.gif'),
|
60 |
+
'format' => Varien_Date::DATE_INTERNAL_FORMAT,
|
61 |
+
'value' => null
|
62 |
+
)
|
63 |
+
);
|
64 |
+
|
65 |
+
$element->setForm(new Varien_Data_Form());
|
66 |
+
$element->setId('order_date_filter');
|
67 |
+
|
68 |
+
return '<label for="order_date_filter">Filter orders from date: </label>' . $element->getElementHtml();
|
69 |
+
}
|
70 |
+
|
71 |
+
private function _getDateFilterJs()
|
72 |
+
{
|
73 |
+
$js = '<script>';
|
74 |
+
$js .= 'function getOrderBatchUrl(){';
|
75 |
+
$js .= 'var url=\'' . $this->_getOrderBatchUrl() . '\';';
|
76 |
+
$js .= 'var dtFilter = $("order_date_filter").getValue();';
|
77 |
+
$js .= 'if(dtFilter){url = url.sub("NO_FILTER", JSON.stringify({"date":dtFilter}));}';
|
78 |
+
//$js .= 'if(dtFilter){url = url.sub("NO_FILTER", dtFilter);}';
|
79 |
+
$js .= 'setLocation(url);';
|
80 |
+
$js .= '}';
|
81 |
+
$js .= '</script>';
|
82 |
+
|
83 |
+
return $js;
|
84 |
+
}
|
85 |
+
|
86 |
+
protected function _toHtml()
|
87 |
+
{
|
88 |
+
$html = parent::_toHtml();
|
89 |
+
$html .= $this->_getDateFilterJs();
|
90 |
+
|
91 |
+
return $html;
|
92 |
+
}
|
93 |
+
|
94 |
+
|
95 |
+
}
|
app/code/community/Koan/Seg/Block/Adminhtml/Exporter/Grid.php
ADDED
@@ -0,0 +1,88 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
class Koan_Seg_Block_Adminhtml_Exporter_Grid extends Mage_Adminhtml_Block_Widget_Grid
|
4 |
+
{
|
5 |
+
|
6 |
+
public function __construct()
|
7 |
+
{
|
8 |
+
parent::__construct();
|
9 |
+
|
10 |
+
$this->setId('segExporterGrid');
|
11 |
+
$this->setDefaultSort('id');
|
12 |
+
$this->setDefaultDir('ASC');
|
13 |
+
$this->setSaveParametersInSession(true);
|
14 |
+
}
|
15 |
+
|
16 |
+
protected function _prepareCollection()
|
17 |
+
{
|
18 |
+
$collection = Mage::getResourceModel('koan_seg/batch_status_collection');
|
19 |
+
$this->setCollection($collection);
|
20 |
+
return parent::_prepareCollection();
|
21 |
+
}
|
22 |
+
|
23 |
+
protected function _prepareColumns()
|
24 |
+
{
|
25 |
+
$this->addColumn('id', array(
|
26 |
+
'header' => Mage::helper('koan_seg')->__('Id'),
|
27 |
+
'align' => 'right',
|
28 |
+
'width' => '40px',
|
29 |
+
'index' => 'id',
|
30 |
+
));
|
31 |
+
|
32 |
+
$this->addColumn('entity_type', array(
|
33 |
+
'header' => Mage::helper('koan_seg')->__('Entity Type'),
|
34 |
+
'align' => 'left',
|
35 |
+
'index' => 'entity_type',
|
36 |
+
));
|
37 |
+
|
38 |
+
$this->addColumn('start_time', array(
|
39 |
+
'header' => Mage::helper('koan_seg')->__('Start Time'),
|
40 |
+
'align' => 'left',
|
41 |
+
'index' => 'start_time',
|
42 |
+
));
|
43 |
+
|
44 |
+
$this->addColumn('end_time', array(
|
45 |
+
'header' => Mage::helper('koan_seg')->__('End Time'),
|
46 |
+
'align' => 'left',
|
47 |
+
'index' => 'end_time',
|
48 |
+
));
|
49 |
+
$this->addColumn('total_row_count', array(
|
50 |
+
'header' => Mage::helper('koan_seg')->__('Total Items Count'),
|
51 |
+
'align' => 'left',
|
52 |
+
'index' => 'total_row_count',
|
53 |
+
));
|
54 |
+
$this->addColumn('num_rows_processed', array(
|
55 |
+
'header' => Mage::helper('koan_seg')->__('Items Processed'),
|
56 |
+
'align' => 'left',
|
57 |
+
'index' => 'num_rows_processed',
|
58 |
+
));
|
59 |
+
|
60 |
+
$this->addColumn('current_status', array(
|
61 |
+
'header' => Mage::helper('koan_seg')->__('Current Status'),
|
62 |
+
'align' => 'left',
|
63 |
+
'index' => 'current_status',
|
64 |
+
'renderer' => 'koan_seg/adminhtml_exporter_grid_renderer_status',
|
65 |
+
));
|
66 |
+
$this->addColumn('comment', array(
|
67 |
+
'header' => Mage::helper('koan_seg')->__('Comment'),
|
68 |
+
'align' => 'left',
|
69 |
+
'index' => 'comment',
|
70 |
+
));
|
71 |
+
|
72 |
+
return parent::_prepareColumns();
|
73 |
+
}
|
74 |
+
|
75 |
+
protected function _prepareMassaction()
|
76 |
+
{
|
77 |
+
$this->setMassactionIdField('id');
|
78 |
+
$this->getMassactionBlock()->setFormFieldName('batch_id');
|
79 |
+
|
80 |
+
$this->getMassactionBlock()->addItem('delete', array(
|
81 |
+
'label' => Mage::helper('koan_seg')->__('Delete'),
|
82 |
+
'url' => $this->getUrl('*/*/massDelete'),
|
83 |
+
'confirm' => Mage::helper('koan_seg')->__('Are you sure?')
|
84 |
+
));
|
85 |
+
|
86 |
+
return $this;
|
87 |
+
}
|
88 |
+
}
|
app/code/community/Koan/Seg/Block/Adminhtml/Exporter/Grid/Renderer/Status.php
ADDED
@@ -0,0 +1,25 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
class Koan_Seg_Block_Adminhtml_Exporter_Grid_Renderer_Status extends Mage_Adminhtml_Block_Widget_Grid_Column_Renderer_Abstract
|
4 |
+
{
|
5 |
+
|
6 |
+
private function getStatusText($status)
|
7 |
+
{
|
8 |
+
$statuses = array(
|
9 |
+
Koan_Seg_Model_Seg_Exporter::BATCH_STATUS_NOT_STARTED => 'Export not started yet',
|
10 |
+
Koan_Seg_Model_Seg_Exporter::BATCH_STATUS_STARTING => 'Export starting in progress',
|
11 |
+
Koan_Seg_Model_Seg_Exporter::BATCH_STATUS_PROCESSING_ROWS => 'Processing rows',
|
12 |
+
Koan_Seg_Model_Seg_Exporter::BATCH_STATUS_COMPLETE => 'Export completed',
|
13 |
+
Koan_Seg_Model_Seg_Exporter::BATCH_STATUS_ERROR => 'Error'
|
14 |
+
);
|
15 |
+
|
16 |
+
return isset($statuses[$status]) ? $statuses[$status] : $status;
|
17 |
+
}
|
18 |
+
|
19 |
+
public function render(Varien_Object $row)
|
20 |
+
{
|
21 |
+
$value = $row->getData($this->getColumn()->getIndex());
|
22 |
+
return $this->getStatusText($value);
|
23 |
+
|
24 |
+
}
|
25 |
+
}
|
app/code/community/Koan/Seg/Block/Header.php
ADDED
@@ -0,0 +1,21 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/**
|
4 |
+
* @category Koan
|
5 |
+
* @package Seg
|
6 |
+
* @author Seg <hello@getseg.com, http://getseg.com>
|
7 |
+
* @copyright Seg <http://getseg.com>
|
8 |
+
* @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
|
9 |
+
*/
|
10 |
+
class Koan_Seg_Block_Header extends Mage_Core_Block_Template
|
11 |
+
{
|
12 |
+
protected function _beforeToHtml()
|
13 |
+
{
|
14 |
+
$websiteId = $this->helper('koan_seg')->getWebsiteId();
|
15 |
+
if (empty($websiteId)) {
|
16 |
+
$this->_template = null;
|
17 |
+
}
|
18 |
+
return $this;
|
19 |
+
}
|
20 |
+
|
21 |
+
}
|
app/code/community/Koan/Seg/Block/Track.php
ADDED
@@ -0,0 +1,284 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/**
|
4 |
+
* @category Koan
|
5 |
+
* @package Seg
|
6 |
+
* @author Seg <hello@getseg.com, http://getseg.com>
|
7 |
+
* @copyright Seg <http://getseg.com>
|
8 |
+
* @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
|
9 |
+
*/
|
10 |
+
class Koan_Seg_Block_Track extends Mage_Core_Block_Template
|
11 |
+
{
|
12 |
+
const PAGE_TYPE_PRODUCT_VIEW = 1;
|
13 |
+
const PAGE_TYPE_CATEGORY = 2;
|
14 |
+
const PAGE_TYPE_DEFAULT = 3;
|
15 |
+
const PAGE_TYPE_CHECKOUT_SUCCESS = 4;
|
16 |
+
|
17 |
+
public function getCustomerData()
|
18 |
+
{
|
19 |
+
if (!$customer = $this->getCustomer()) {
|
20 |
+
return null;
|
21 |
+
}
|
22 |
+
|
23 |
+
if (!$email = $customer->getEmail()) {
|
24 |
+
return null;
|
25 |
+
}
|
26 |
+
|
27 |
+
$result = array('Email' => $email);
|
28 |
+
|
29 |
+
$id = $customer->getId();
|
30 |
+
if (!empty($id)) {
|
31 |
+
$result['Id'] = $id;
|
32 |
+
}
|
33 |
+
|
34 |
+
$title = $customer->getPrefix();
|
35 |
+
if (!empty($title)) {
|
36 |
+
$result['Title'] = $title;
|
37 |
+
}
|
38 |
+
|
39 |
+
$firstname = $customer->getFirstname();
|
40 |
+
if (!empty($firstname)) {
|
41 |
+
$result['FirstName'] = $firstname;
|
42 |
+
}
|
43 |
+
|
44 |
+
$lastname = $customer->getLastname();
|
45 |
+
if (!empty($lastname)) {
|
46 |
+
$result['LastName'] = $lastname;
|
47 |
+
}
|
48 |
+
|
49 |
+
$address = $customer->getPrimaryBillingAddress();
|
50 |
+
if (!$address) {
|
51 |
+
$address = $customer->getPrimaryShippingAddress();
|
52 |
+
}
|
53 |
+
|
54 |
+
$country = null;
|
55 |
+
if ($address AND $address->getId()) {
|
56 |
+
$country = $address->getCountry();
|
57 |
+
}
|
58 |
+
|
59 |
+
if (!empty($country)) {
|
60 |
+
$result['CountryCode'] = $country;
|
61 |
+
}
|
62 |
+
|
63 |
+
$gender = $this->_getAttributeText($customer, 'gender');
|
64 |
+
if (!empty($gender)) {
|
65 |
+
$result['Gender'] = $gender;
|
66 |
+
}
|
67 |
+
|
68 |
+
if ($result AND is_array($result) and count($result)) {
|
69 |
+
return json_encode($result);
|
70 |
+
}
|
71 |
+
|
72 |
+
return null;
|
73 |
+
}
|
74 |
+
|
75 |
+
public function getCustomerDob()
|
76 |
+
{
|
77 |
+
if (!$customer = $this->getCustomer()) {
|
78 |
+
return null;
|
79 |
+
}
|
80 |
+
|
81 |
+
$dob = $customer->getDob();
|
82 |
+
if (!empty($dob)) {
|
83 |
+
return date('Y-m-d', strtotime($dob));
|
84 |
+
}
|
85 |
+
|
86 |
+
return null;
|
87 |
+
}
|
88 |
+
|
89 |
+
public function getPageData()
|
90 |
+
{
|
91 |
+
$result = array('type' => self::PAGE_TYPE_DEFAULT);
|
92 |
+
|
93 |
+
$request = $moduleName = Mage::app()->getRequest();
|
94 |
+
if (!$request) {
|
95 |
+
return $result;
|
96 |
+
}
|
97 |
+
|
98 |
+
$moduleName = $request->getModuleName();
|
99 |
+
$controllerName = $request->getControllerName();
|
100 |
+
$actionName = $request->getActionName();
|
101 |
+
|
102 |
+
$product = Mage::registry('current_product');
|
103 |
+
$category = Mage::registry('current_category');
|
104 |
+
|
105 |
+
if ($moduleName == 'catalog' AND $controllerName == 'product' AND ($product AND $product->getId())) {
|
106 |
+
|
107 |
+
$result['type'] = self::PAGE_TYPE_PRODUCT_VIEW;
|
108 |
+
$result['data'] = $product;
|
109 |
+
return $result;
|
110 |
+
}
|
111 |
+
|
112 |
+
if ($moduleName == 'catalog' AND $controllerName == 'category' AND ($category && $category->getId())) {
|
113 |
+
$result['type'] = self::PAGE_TYPE_CATEGORY;
|
114 |
+
$result['data'] = $category;
|
115 |
+
return $result;
|
116 |
+
}
|
117 |
+
|
118 |
+
if ($moduleName == 'checkout' AND $controllerName == 'onepage' AND $actionName == 'success') {
|
119 |
+
$result['type'] = self::PAGE_TYPE_CHECKOUT_SUCCESS;
|
120 |
+
return $result;
|
121 |
+
}
|
122 |
+
|
123 |
+
return $result;
|
124 |
+
}
|
125 |
+
|
126 |
+
protected function _beforeToHtml()
|
127 |
+
{
|
128 |
+
$websiteId = $this->helper('koan_seg')->getWebsiteId();
|
129 |
+
if (empty($websiteId)) {
|
130 |
+
$this->_template = null;
|
131 |
+
return $this;
|
132 |
+
}
|
133 |
+
|
134 |
+
if ($pageData = $this->getPageData()) {
|
135 |
+
if (isset($pageData['type']) AND $pageData['type'] == self::PAGE_TYPE_CHECKOUT_SUCCESS) {
|
136 |
+
$this->_prepareLastOrder();
|
137 |
+
}
|
138 |
+
}
|
139 |
+
|
140 |
+
return parent::_beforeToHtml();
|
141 |
+
}
|
142 |
+
|
143 |
+
protected function _prepareLastOrder()
|
144 |
+
{
|
145 |
+
$orderId = Mage::getSingleton('checkout/session')->getLastOrderId();
|
146 |
+
if ($orderId) {
|
147 |
+
$order = Mage::getModel('sales/order')->load($orderId);
|
148 |
+
if ($order->getId()) {
|
149 |
+
$this->addData(array(
|
150 |
+
'order_id' => $order->getId(),
|
151 |
+
));
|
152 |
+
}
|
153 |
+
}
|
154 |
+
}
|
155 |
+
|
156 |
+
public function getTrackingEventCode()
|
157 |
+
{
|
158 |
+
try {
|
159 |
+
//Check if we have addToCart event in session
|
160 |
+
//and return add to cart event
|
161 |
+
$quoteItemId = Mage::getSingleton('customer/session')->getItemAddedToCart();
|
162 |
+
|
163 |
+
if ($quoteItemId) {
|
164 |
+
Mage::getSingleton('customer/session')->unsItemAddedToCart();
|
165 |
+
return $this->_getAddToCartEventCode($quoteItemId);
|
166 |
+
}
|
167 |
+
|
168 |
+
$pageData = $this->getPageData();
|
169 |
+
$pageType = isset($pageData['type']) ? $pageData['type'] : self::PAGE_TYPE_DEFAULT;
|
170 |
+
|
171 |
+
switch ($pageType) {
|
172 |
+
case self::PAGE_TYPE_PRODUCT_VIEW:
|
173 |
+
|
174 |
+
$product = isset($pageData['data']) ? $pageData['data'] : null;
|
175 |
+
|
176 |
+
if (!$product) {
|
177 |
+
Mage::throwException($this->_getHelper()->__('Product doesn\'t exists!'));
|
178 |
+
}
|
179 |
+
|
180 |
+
return $this->_getProductViewEventCode($product);
|
181 |
+
break;
|
182 |
+
|
183 |
+
case self::PAGE_TYPE_CATEGORY:
|
184 |
+
|
185 |
+
$category = isset($pageData['data']) ? $pageData['data'] : null;
|
186 |
+
|
187 |
+
if (!$category) {
|
188 |
+
Mage::throwException($this->_getHelper()->__('Category doesn\'t exists!'));
|
189 |
+
}
|
190 |
+
|
191 |
+
return $this->_getRangeViewEventCode($category);
|
192 |
+
break;
|
193 |
+
|
194 |
+
case self::PAGE_TYPE_CHECKOUT_SUCCESS:
|
195 |
+
|
196 |
+
$orderId = $this->getOrderId();
|
197 |
+
$order = Mage::getModel('sales/order')->load($orderId);
|
198 |
+
|
199 |
+
if (!$order OR !$order->getId()) {
|
200 |
+
Mage::throwException($this->_getHelper()->__('Order doesn\'t exists!'));
|
201 |
+
}
|
202 |
+
|
203 |
+
return $this->_getOrderSuccessEventCode($order);
|
204 |
+
break;
|
205 |
+
|
206 |
+
default:
|
207 |
+
return array('event' => 'PageView', 'data' => null);
|
208 |
+
break;
|
209 |
+
}
|
210 |
+
|
211 |
+
} Catch (Exception $e) {
|
212 |
+
Mage::getSingleton('koan_seg/exception_handler')->handle('Magento: error in frontend tracking - getTrackingEventCode', $e);
|
213 |
+
}
|
214 |
+
|
215 |
+
return null;
|
216 |
+
}
|
217 |
+
|
218 |
+
private function _getAddToCartEventCode($itemId)
|
219 |
+
{
|
220 |
+
$cartData = Mage::getModel('koan_seg/seg_basket')->prepare($itemId);
|
221 |
+
$result = array(
|
222 |
+
'event' => 'AddedToBasket',
|
223 |
+
'data' => json_encode($cartData)
|
224 |
+
);
|
225 |
+
|
226 |
+
return $result;
|
227 |
+
}
|
228 |
+
|
229 |
+
private function _getRangeViewEventCode($category)
|
230 |
+
{
|
231 |
+
$categoryData = Mage::getModel('koan_seg/seg_range')->prepare($category);
|
232 |
+
|
233 |
+
$result = array(
|
234 |
+
'event' => 'RangeView',
|
235 |
+
'data' => json_encode($categoryData)
|
236 |
+
);
|
237 |
+
|
238 |
+
return $result;
|
239 |
+
}
|
240 |
+
|
241 |
+
private function _getProductViewEventCode($product)
|
242 |
+
{
|
243 |
+
$productData = Mage::getModel('koan_seg/seg_product')->prepare($product);
|
244 |
+
|
245 |
+
$result = array(
|
246 |
+
'event' => 'ProductView',
|
247 |
+
'data' => json_encode($productData)
|
248 |
+
);
|
249 |
+
|
250 |
+
return $result;
|
251 |
+
}
|
252 |
+
|
253 |
+
private function _getOrderSuccessEventCode($order)
|
254 |
+
{
|
255 |
+
$orderData = Mage::getModel('koan_seg/seg_order')->prepare($order);
|
256 |
+
|
257 |
+
$result = array(
|
258 |
+
'event' => 'OrderPlaced',
|
259 |
+
'data' => json_encode($orderData)
|
260 |
+
);
|
261 |
+
|
262 |
+
return $result;
|
263 |
+
}
|
264 |
+
|
265 |
+
|
266 |
+
private function getCustomer()
|
267 |
+
{
|
268 |
+
return Mage::getSingleton('customer/session')->getCustomer();
|
269 |
+
}
|
270 |
+
|
271 |
+
private function _getAttributeText($customer, $attribute)
|
272 |
+
{
|
273 |
+
return $customer->getResource()
|
274 |
+
->getAttribute($attribute)
|
275 |
+
->getFrontend()
|
276 |
+
->getValue($customer);
|
277 |
+
}
|
278 |
+
|
279 |
+
private function _getHelper()
|
280 |
+
{
|
281 |
+
return Mage::helper('koan_seg');
|
282 |
+
}
|
283 |
+
|
284 |
+
}
|
app/code/community/Koan/Seg/Helper/Data.php
ADDED
@@ -0,0 +1,179 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
class Koan_Seg_Helper_Data extends Mage_Core_Helper_Abstract
|
4 |
+
{
|
5 |
+
const SEG_WEBSITE_ID_PATH = 'koan_seg/general/seg_website_id';
|
6 |
+
|
7 |
+
const SEG_ORDER_HISTORY_ENDPOINT_URL_PATH = 'koan_seg/endpoint/order_history';
|
8 |
+
const SEG_UPDATE_CUSTOMERS_ENDPOINT_URL_PATH = 'koan_seg/endpoint/update_customers';
|
9 |
+
const SEG_ORDER_PLACED_ENDPOINT_URL_PATH = 'koan_seg/endpoint/order_placed';
|
10 |
+
|
11 |
+
const SEG_ORDERS_EXPORT_BATCH_SIZE_PATH = 'koan_seg/general/orders_export_batch_size';
|
12 |
+
const SEG_CUSTOMERS_EXPORT_BATCH_SIZE_PATH = 'koan_seg/general/customers_export_batch_size';
|
13 |
+
|
14 |
+
const SEG_PRODUCT_BRAND_ATTRIBUTE_CODE_PATH = 'koan_seg/general/brand_attr_code';
|
15 |
+
const SEG_ROLLBAR_LOG_REQUEST_INFO = 'koan_seg/general/rollbar_report_params';
|
16 |
+
|
17 |
+
const SEG_EXPORT_CRON_ENABLED = 'koan_seg/general/export_cron_enable';
|
18 |
+
|
19 |
+
const SEG_EXPORTER_PHP_MEMORY_LIMIT = 'koan_seg/advanced/php_memory_limit';
|
20 |
+
|
21 |
+
public function getExporterPhpMemoryLimit()
|
22 |
+
{
|
23 |
+
return Mage::getStoreConfig(self::SEG_EXPORTER_PHP_MEMORY_LIMIT, null);
|
24 |
+
}
|
25 |
+
|
26 |
+
public function isExportCronEnabled()
|
27 |
+
{
|
28 |
+
return Mage::getStoreConfigFlag(self::SEG_EXPORT_CRON_ENABLED, null);
|
29 |
+
}
|
30 |
+
|
31 |
+
public function getWebsiteId($storeId = null)
|
32 |
+
{
|
33 |
+
return Mage::getStoreConfig(self::SEG_WEBSITE_ID_PATH, $storeId);
|
34 |
+
}
|
35 |
+
|
36 |
+
public function getOrderHistoryUrl()
|
37 |
+
{
|
38 |
+
return Mage::getStoreConfig(self::SEG_ORDER_HISTORY_ENDPOINT_URL_PATH);
|
39 |
+
}
|
40 |
+
|
41 |
+
public function getUpdateCustomersUrl()
|
42 |
+
{
|
43 |
+
return Mage::getStoreConfig(self::SEG_UPDATE_CUSTOMERS_ENDPOINT_URL_PATH);
|
44 |
+
}
|
45 |
+
|
46 |
+
public function getOrderPlacedUrl()
|
47 |
+
{
|
48 |
+
return Mage::getStoreConfig(self::SEG_ORDER_PLACED_ENDPOINT_URL_PATH);
|
49 |
+
}
|
50 |
+
|
51 |
+
public function getOrdersExportBatchSize()
|
52 |
+
{
|
53 |
+
return Mage::getStoreConfig(self::SEG_ORDERS_EXPORT_BATCH_SIZE_PATH);
|
54 |
+
}
|
55 |
+
|
56 |
+
public function getCustomersExportBatchSize()
|
57 |
+
{
|
58 |
+
return Mage::getStoreConfig(self::SEG_CUSTOMERS_EXPORT_BATCH_SIZE_PATH);
|
59 |
+
}
|
60 |
+
|
61 |
+
public function getBrandAttributeCode($storeId = null)
|
62 |
+
{
|
63 |
+
return Mage::getStoreConfig(self::SEG_PRODUCT_BRAND_ATTRIBUTE_CODE_PATH, $storeId);
|
64 |
+
}
|
65 |
+
|
66 |
+
public function logRequestInfo($storeId = null)
|
67 |
+
{
|
68 |
+
return Mage::getStoreConfigFlag(self::SEG_ROLLBAR_LOG_REQUEST_INFO, $storeId);
|
69 |
+
}
|
70 |
+
|
71 |
+
public function includeRollBar()
|
72 |
+
{
|
73 |
+
if (strpos(get_include_path(), Mage::getModuleDir(null, 'Koan_Seg')) == false) {
|
74 |
+
set_include_path(get_include_path() . PATH_SEPARATOR . Mage::getModuleDir(null, 'Koan_Seg') . DS . 'lib');
|
75 |
+
}
|
76 |
+
|
77 |
+
require_once('Rollbar.php');
|
78 |
+
}
|
79 |
+
|
80 |
+
public function initRollbar()
|
81 |
+
{
|
82 |
+
$this->includeRollBar();
|
83 |
+
|
84 |
+
if (!Rollbar::$instance) {
|
85 |
+
Rollbar::init(array(
|
86 |
+
|
87 |
+
'access_token' => '39591143a2524b08b29a18a653897f95',
|
88 |
+
'environment' => Mage::getBaseUrl(Mage_Core_Model_Store::URL_TYPE_WEB),
|
89 |
+
'root' => Mage::getBaseDir(),
|
90 |
+
'batched' => 0,
|
91 |
+
|
92 |
+
));
|
93 |
+
}
|
94 |
+
}
|
95 |
+
|
96 |
+
public function getProductBrands($product, $storeId)
|
97 |
+
{
|
98 |
+
$brandAttributeCode = $this->getBrandAttributeCode($storeId);
|
99 |
+
$brandAttributeType = null;
|
100 |
+
|
101 |
+
if ($brandAttributeCode) {
|
102 |
+
$brandAttributeType = $this->_getBrandAttributeType($brandAttributeCode);
|
103 |
+
}
|
104 |
+
|
105 |
+
//Try to determine product brand
|
106 |
+
if (is_null($brandAttributeType)) {
|
107 |
+
$brandAttributeType = 'text';
|
108 |
+
}
|
109 |
+
|
110 |
+
$getBrand = 'get' . $this->_camelize($brandAttributeCode);
|
111 |
+
|
112 |
+
if ($brandAttributeType == 'select') {
|
113 |
+
|
114 |
+
$resultBrand = null;
|
115 |
+
$brandValue = $product->$getBrand();
|
116 |
+
|
117 |
+
if (!empty($brandValue)) {
|
118 |
+
$product->setStoreId($storeId)
|
119 |
+
->setData(
|
120 |
+
$brandAttributeCode,
|
121 |
+
$brandValue
|
122 |
+
);
|
123 |
+
$resultBrand = $product->getAttributeText($brandAttributeCode);
|
124 |
+
}
|
125 |
+
|
126 |
+
} else if ($brandAttributeType == 'multiselect') {
|
127 |
+
|
128 |
+
$productBrandIds = null;
|
129 |
+
$resultBrand = array();
|
130 |
+
|
131 |
+
$brandValueList = $product->$getBrand();
|
132 |
+
if ($brandValueList) {
|
133 |
+
$productBrandValsArray = explode(',', $brandValueList);
|
134 |
+
if ($productBrandValsArray AND is_array($productBrandValsArray) AND count($productBrandValsArray)) {
|
135 |
+
foreach ($productBrandValsArray as $brandValue) {
|
136 |
+
if (!empty($brandValue)) {
|
137 |
+
$product->setStoreId($storeId)
|
138 |
+
->setData(
|
139 |
+
$brandAttributeCode,
|
140 |
+
$brandValue
|
141 |
+
);
|
142 |
+
$resultBrand[] = $product->getAttributeText($brandAttributeCode);
|
143 |
+
}
|
144 |
+
}
|
145 |
+
}
|
146 |
+
}
|
147 |
+
|
148 |
+
} else {
|
149 |
+
$resultBrand = $product->$getBrand();
|
150 |
+
}
|
151 |
+
|
152 |
+
$brand = $resultBrand ? $resultBrand : null;
|
153 |
+
|
154 |
+
if (!$brand) {
|
155 |
+
return null;
|
156 |
+
}
|
157 |
+
|
158 |
+
if (!is_array($brand)) {
|
159 |
+
$brand = array($brand);
|
160 |
+
}
|
161 |
+
|
162 |
+
return $brand;
|
163 |
+
}
|
164 |
+
|
165 |
+
private function _getBrandAttributeType($brandAttributeCode)
|
166 |
+
{
|
167 |
+
$attribute = Mage::getModel('eav/entity_attribute')->loadByCode('catalog_product', $brandAttributeCode);
|
168 |
+
if ($attribute) {
|
169 |
+
return $attribute->getFrontendInput();
|
170 |
+
}
|
171 |
+
|
172 |
+
return 'text';
|
173 |
+
}
|
174 |
+
|
175 |
+
protected function _camelize($name)
|
176 |
+
{
|
177 |
+
return uc_words($name, '');
|
178 |
+
}
|
179 |
+
}
|
app/code/community/Koan/Seg/Model/Batch/Status.php
ADDED
@@ -0,0 +1,145 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
class Koan_Seg_Model_Batch_Status extends Mage_Core_Model_Abstract
|
4 |
+
{
|
5 |
+
public function _construct()
|
6 |
+
{
|
7 |
+
parent::_construct();
|
8 |
+
$this->_init('koan_seg/batch_status');
|
9 |
+
}
|
10 |
+
|
11 |
+
public function createNew($entityType = null, $filter = null)
|
12 |
+
{
|
13 |
+
$data = array(
|
14 |
+
'entity_type' => $entityType,
|
15 |
+
'start_time' => null,
|
16 |
+
'end_time' => null,
|
17 |
+
'total_row_count' => 0,
|
18 |
+
'num_rows_processed' => 0,
|
19 |
+
'current_status' => 0,
|
20 |
+
'comment' => 'Waiting for start ...',
|
21 |
+
'num_retried' => 0
|
22 |
+
);
|
23 |
+
|
24 |
+
if ($filter) {
|
25 |
+
$data['filter'] = $filter;
|
26 |
+
}
|
27 |
+
|
28 |
+
$this->setData(
|
29 |
+
$data
|
30 |
+
);
|
31 |
+
|
32 |
+
try {
|
33 |
+
$this->save();
|
34 |
+
} Catch (Exception $e) {
|
35 |
+
throw $e;
|
36 |
+
}
|
37 |
+
|
38 |
+
|
39 |
+
return $this;
|
40 |
+
}
|
41 |
+
|
42 |
+
public function setStartingStatus($rowCount, $currentStatus)
|
43 |
+
{
|
44 |
+
$this->addData(
|
45 |
+
array(
|
46 |
+
'start_time' => Varien_Date::now(),
|
47 |
+
'total_row_count' => $rowCount,
|
48 |
+
'current_status' => $currentStatus,
|
49 |
+
'comment' => 'Starting new export ...',
|
50 |
+
)
|
51 |
+
);
|
52 |
+
|
53 |
+
try {
|
54 |
+
$this->save();
|
55 |
+
} Catch (Exception $e) {
|
56 |
+
throw $e;
|
57 |
+
}
|
58 |
+
|
59 |
+
return $this;
|
60 |
+
}
|
61 |
+
|
62 |
+
public function setProcessingStatus($currentStatus)
|
63 |
+
{
|
64 |
+
$this->addData(
|
65 |
+
array(
|
66 |
+
'current_status' => $currentStatus,
|
67 |
+
'comment' => 'Processing rows ...',
|
68 |
+
)
|
69 |
+
);
|
70 |
+
|
71 |
+
try {
|
72 |
+
$this->save();
|
73 |
+
} Catch (Exception $e) {
|
74 |
+
throw $e;
|
75 |
+
}
|
76 |
+
|
77 |
+
return $this;
|
78 |
+
}
|
79 |
+
|
80 |
+
public function setBatchError($message)
|
81 |
+
{
|
82 |
+
$numRetried = is_null($this->getNumRetried()) ? 0 : $this->getNumRetried();
|
83 |
+
$numRetried++;
|
84 |
+
|
85 |
+
$data = array(
|
86 |
+
'num_retried' => $numRetried,
|
87 |
+
'comment' => $message,
|
88 |
+
);
|
89 |
+
|
90 |
+
if ($numRetried >= 3) {
|
91 |
+
$data['current_status'] = Koan_Seg_Model_Seg_Exporter::BATCH_STATUS_ERROR;
|
92 |
+
}
|
93 |
+
|
94 |
+
$this->addData(
|
95 |
+
$data
|
96 |
+
);
|
97 |
+
|
98 |
+
try {
|
99 |
+
$this->save();
|
100 |
+
} Catch (Exception $e) {
|
101 |
+
throw $e;
|
102 |
+
}
|
103 |
+
}
|
104 |
+
|
105 |
+
public function setCompleteStatus($currentStatus)
|
106 |
+
{
|
107 |
+
$this->addData(
|
108 |
+
array(
|
109 |
+
'current_status' => $currentStatus,
|
110 |
+
'comment' => 'Processing complete.',
|
111 |
+
'end_time' => Varien_Date::now(),
|
112 |
+
)
|
113 |
+
);
|
114 |
+
|
115 |
+
try {
|
116 |
+
$this->save();
|
117 |
+
} Catch (Exception $e) {
|
118 |
+
throw $e;
|
119 |
+
}
|
120 |
+
|
121 |
+
return $this;
|
122 |
+
}
|
123 |
+
|
124 |
+
public function updateNumRowsProcessed($rowCount = null, $numRowsProcessed)
|
125 |
+
{
|
126 |
+
$newNumProcessed = (int)$numRowsProcessed + (int)$this->getNumRowsProcessed();
|
127 |
+
|
128 |
+
$data = array(
|
129 |
+
'num_rows_processed' => $newNumProcessed,
|
130 |
+
);
|
131 |
+
|
132 |
+
if ($rowCount) {
|
133 |
+
$data['total_row_count'] = $rowCount;
|
134 |
+
}
|
135 |
+
|
136 |
+
$this->addData($data);
|
137 |
+
|
138 |
+
try {
|
139 |
+
$this->save();
|
140 |
+
} Catch (Exception $e) {
|
141 |
+
throw $e;
|
142 |
+
}
|
143 |
+
}
|
144 |
+
|
145 |
+
}
|
app/code/community/Koan/Seg/Model/Exception/Handler.php
ADDED
@@ -0,0 +1,26 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
Mage::helper('koan_seg')->includeRollBar();
|
4 |
+
|
5 |
+
class Koan_Seg_Model_Exception_Handler
|
6 |
+
{
|
7 |
+
public function handle($action, Exception $e)
|
8 |
+
{
|
9 |
+
$data = array(
|
10 |
+
'code' => $e->getCode(),
|
11 |
+
'message' => $e->getMessage(),
|
12 |
+
);
|
13 |
+
|
14 |
+
Mage::getSingleton('koan_seg/logger')->log($action, 'error', $data);
|
15 |
+
}
|
16 |
+
|
17 |
+
public function handleHttpResponseError($action, $code, $message)
|
18 |
+
{
|
19 |
+
$data = array(
|
20 |
+
'code' => $code,
|
21 |
+
'message' => $message,
|
22 |
+
);
|
23 |
+
|
24 |
+
Mage::getSingleton('koan_seg/logger')->log($action, 'error', $data);
|
25 |
+
}
|
26 |
+
}
|
app/code/community/Koan/Seg/Model/Logger.php
ADDED
@@ -0,0 +1,13 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
Mage::helper('koan_seg')->includeRollBar();
|
4 |
+
|
5 |
+
class Koan_Seg_Model_Logger
|
6 |
+
{
|
7 |
+
public function log($action, $level = 'error', $data)
|
8 |
+
{
|
9 |
+
$data['site_id'] = Mage::helper('koan_seg')->getWebsiteId();
|
10 |
+
Rollbar::report_message($action, $level, $data);
|
11 |
+
}
|
12 |
+
|
13 |
+
}
|
app/code/community/Koan/Seg/Model/Observer.php
ADDED
@@ -0,0 +1,83 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
class Koan_Seg_Model_Observer
|
4 |
+
{
|
5 |
+
public function cronprocess()
|
6 |
+
{
|
7 |
+
if (!Mage::helper('koan_seg')->isExportCronEnabled()) {
|
8 |
+
return $this;
|
9 |
+
}
|
10 |
+
|
11 |
+
$exporter = Mage::getSingleton('koan_seg/seg_exporter');
|
12 |
+
|
13 |
+
if ($exporter->hasCustomersToProcess()) {
|
14 |
+
Mage::getSingleton('koan_seg/seg_exporter')->exportCustomers();
|
15 |
+
return $this;
|
16 |
+
}
|
17 |
+
|
18 |
+
if ($exporter->hasOrdersToProcess()) {
|
19 |
+
Mage::getSingleton('koan_seg/seg_exporter')->exportHistoryOrders();
|
20 |
+
}
|
21 |
+
|
22 |
+
return $this;
|
23 |
+
}
|
24 |
+
|
25 |
+
public function checkoutCartProductAddAfter($observer)
|
26 |
+
{
|
27 |
+
$quoteItem = $observer->getEvent()->getQuoteItem();
|
28 |
+
$quoteItem->setAddedToCartFlag(true);
|
29 |
+
|
30 |
+
return $observer;
|
31 |
+
}
|
32 |
+
|
33 |
+
public function cartItemAfterSave($observer)
|
34 |
+
{
|
35 |
+
$quoteItem = $observer->getEvent()->getItem();
|
36 |
+
|
37 |
+
if ($children = $quoteItem->getChildren()) {
|
38 |
+
foreach ($children as $childItem) {
|
39 |
+
if ($childItem->getAddedToCartFlag() == true) {
|
40 |
+
$quoteItem = $childItem;
|
41 |
+
break;
|
42 |
+
}
|
43 |
+
|
44 |
+
}
|
45 |
+
}
|
46 |
+
|
47 |
+
if ($quoteItem->getAddedToCartFlag()) {
|
48 |
+
if ($quoteItem->getParentItemId()) {
|
49 |
+
Mage::getSingleton('customer/session')->setItemAddedToCart($quoteItem->getParentItemId());
|
50 |
+
$quoteItem->unsAddedToCartFlag();
|
51 |
+
} else if ($quoteItem->hasId()) {
|
52 |
+
Mage::getSingleton('customer/session')->setItemAddedToCart($quoteItem->getId());
|
53 |
+
$quoteItem->unsAddedToCartFlag();
|
54 |
+
}
|
55 |
+
|
56 |
+
return $observer;
|
57 |
+
}
|
58 |
+
|
59 |
+
return $observer;
|
60 |
+
}
|
61 |
+
|
62 |
+
public function orderPlaceAfter($observer)
|
63 |
+
{
|
64 |
+
$order = $observer->getEvent()->getOrder();
|
65 |
+
if (!$order) {
|
66 |
+
return $observer;
|
67 |
+
}
|
68 |
+
|
69 |
+
if (!$order->getId()) {
|
70 |
+
return $observer;
|
71 |
+
}
|
72 |
+
|
73 |
+
try {
|
74 |
+
$orderData = Mage::getModel('koan_seg/seg_order')->prepare($order);
|
75 |
+
Mage::getModel('koan_seg/seg_client')->exportNewOrder($orderData);
|
76 |
+
} Catch (Exception $e) {
|
77 |
+
Mage::getSingleton('koan_seg/exception_handler')->handle('Magento: error in orderPlaceAfter observer - exportNewOrder', $e);
|
78 |
+
}
|
79 |
+
|
80 |
+
return $observer;
|
81 |
+
}
|
82 |
+
|
83 |
+
}
|
app/code/community/Koan/Seg/Model/Resource/Batch/Status.php
ADDED
@@ -0,0 +1,9 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
class Koan_Seg_Model_Resource_Batch_Status extends Mage_Core_Model_Resource_Db_Abstract
|
4 |
+
{
|
5 |
+
public function _construct()
|
6 |
+
{
|
7 |
+
$this->_init('koan_seg/batch_status', 'id');
|
8 |
+
}
|
9 |
+
}
|
app/code/community/Koan/Seg/Model/Resource/Batch/Status/Collection.php
ADDED
@@ -0,0 +1,10 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
class Koan_Seg_Model_Resource_Batch_Status_Collection extends Mage_Core_Model_Resource_Db_Collection_Abstract
|
4 |
+
{
|
5 |
+
public function _construct()
|
6 |
+
{
|
7 |
+
parent::_construct();
|
8 |
+
$this->_init('koan_seg/batch_status');
|
9 |
+
}
|
10 |
+
}
|
app/code/community/Koan/Seg/Model/Seg/Basket.php
ADDED
@@ -0,0 +1,87 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
class Koan_Seg_Model_Seg_Basket extends Varien_Object
|
4 |
+
{
|
5 |
+
public function prepare($itemId)
|
6 |
+
{
|
7 |
+
$item = Mage::getModel('sales/quote_item')->load($itemId);
|
8 |
+
if (!$item OR !$item->getId()) {
|
9 |
+
Mage::throwException($this->_getHelper()->__('Quote Item with this id does not exists!'));
|
10 |
+
}
|
11 |
+
|
12 |
+
$quoteId = $item->getQuoteId();
|
13 |
+
if (!$quoteId) {
|
14 |
+
Mage::throwException($this->_getHelper()->__('Quote id does not exists!'));
|
15 |
+
}
|
16 |
+
|
17 |
+
$quote = Mage::getModel('sales/quote')->load($quoteId);
|
18 |
+
if (!$quote) {
|
19 |
+
Mage::throwException('Quote is not valid!');
|
20 |
+
}
|
21 |
+
|
22 |
+
if (!$quoteId = $quote->getId()) {
|
23 |
+
Mage::throwException('Missing Quote Id');
|
24 |
+
}
|
25 |
+
|
26 |
+
$item->setQuote($quote);
|
27 |
+
$revenue = is_null($quote->getBaseGrandTotal()) ? 0 : $quote->getBaseGrandTotal();
|
28 |
+
|
29 |
+
$resultAttributes = array(
|
30 |
+
'Discount',
|
31 |
+
'Id',
|
32 |
+
'OrderLines',
|
33 |
+
//'_p',
|
34 |
+
'Revenue'
|
35 |
+
);
|
36 |
+
|
37 |
+
$shippingAddress = $quote->getShippingAddress();
|
38 |
+
|
39 |
+
$shippingMethod = $shippingAddress->getShippingDescription();
|
40 |
+
if (!empty($shippingMethod)) {
|
41 |
+
$this->setData('DeliveryMethod', $shippingMethod);
|
42 |
+
$resultAttributes[] = 'DeliveryMethod';
|
43 |
+
}
|
44 |
+
|
45 |
+
$deliveryRevenue = $shippingAddress->getBaseShippingInclTax();
|
46 |
+
if (!is_null($deliveryRevenue)) {
|
47 |
+
$this->setData('DeliveryRevenue', number_format($deliveryRevenue, 2, '.', ''));
|
48 |
+
$resultAttributes[] = 'DeliveryRevenue';
|
49 |
+
}
|
50 |
+
|
51 |
+
$discountAmount = $shippingAddress->getBaseDiscountAmount();
|
52 |
+
if (!is_null($discountAmount)) {
|
53 |
+
$this->setData('Discount', number_format($discountAmount, 2, '.', ''));
|
54 |
+
$resultAttributes[] = 'Discount';
|
55 |
+
}
|
56 |
+
|
57 |
+
$this->setData('Id', $quoteId);
|
58 |
+
$this->setData('OrderLines', $this->_prepareQuoteLines($quote, $itemId));
|
59 |
+
|
60 |
+
$this->setData('Revenue', number_format($revenue, 2, '.', ''));
|
61 |
+
|
62 |
+
return $this->toArray($resultAttributes);
|
63 |
+
}
|
64 |
+
|
65 |
+
private function _prepareQuoteLines($quote, $addedItemId)
|
66 |
+
{
|
67 |
+
$quoteItems = $quote->getAllVisibleItems();
|
68 |
+
$result = array();
|
69 |
+
if ($quoteItems AND count($quoteItems)) {
|
70 |
+
foreach ($quoteItems as $item) {
|
71 |
+
if ($item->getId() == $addedItemId) {
|
72 |
+
$result[] = Mage::getModel('koan_seg/seg_quote_line')->prepare($item, true);
|
73 |
+
} else {
|
74 |
+
$result[] = Mage::getModel('koan_seg/seg_quote_line')->prepare($item);
|
75 |
+
}
|
76 |
+
|
77 |
+
}
|
78 |
+
}
|
79 |
+
|
80 |
+
return $result;
|
81 |
+
}
|
82 |
+
|
83 |
+
private function _getHelper()
|
84 |
+
{
|
85 |
+
return Mage::helper('koan_seg');
|
86 |
+
}
|
87 |
+
}
|
app/code/community/Koan/Seg/Model/Seg/Client.php
ADDED
@@ -0,0 +1,239 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
Mage::helper('koan_seg')->includeRollBar();
|
4 |
+
|
5 |
+
class Koan_Seg_Model_Seg_Client extends Varien_Http_Client
|
6 |
+
{
|
7 |
+
const REQUEST_TIMEOUT = 30;
|
8 |
+
|
9 |
+
public function __construct()
|
10 |
+
{
|
11 |
+
//$this->_getHelper()->initRollbar();
|
12 |
+
|
13 |
+
$this->config['useragent'] = 'Koan_Seg_Model_Seg_Client';
|
14 |
+
parent::__construct();
|
15 |
+
}
|
16 |
+
|
17 |
+
public function exportCustomers($customers)
|
18 |
+
{
|
19 |
+
if (!$customers) {
|
20 |
+
Mage::throwException($this->__('Customers data does not exists!'));
|
21 |
+
}
|
22 |
+
|
23 |
+
if (!is_array($customers) OR !count($customers)) {
|
24 |
+
Mage::throwException($this->__('Invalid customers data!'));
|
25 |
+
}
|
26 |
+
|
27 |
+
$params = json_encode($customers);
|
28 |
+
|
29 |
+
$url = $this->_getExportCustomerUrl();
|
30 |
+
|
31 |
+
$this->_init();
|
32 |
+
$this->setUri($url);
|
33 |
+
|
34 |
+
$this->setRawData($params, 'application/json');
|
35 |
+
|
36 |
+
if ($this->_getHelper()->logRequestInfo()) {
|
37 |
+
Mage::getSingleton('koan_seg/logger')->log('Magento: posting customers to Seg', 'info', array('customers' => $params, 'endpoint' => $url));
|
38 |
+
}
|
39 |
+
|
40 |
+
try {
|
41 |
+
$response = $this->request();
|
42 |
+
} Catch (Exception $e) {
|
43 |
+
throw $e;
|
44 |
+
}
|
45 |
+
|
46 |
+
try {
|
47 |
+
$this->__handleResponse($response, 'exportCustomers');
|
48 |
+
} Catch (Exception $e) {
|
49 |
+
Mage::throwException('[exportCustomers]::__handleResponse: ' . $e->getMessage());
|
50 |
+
}
|
51 |
+
|
52 |
+
return $this;
|
53 |
+
}
|
54 |
+
|
55 |
+
public function exportHistoryOrders($orders)
|
56 |
+
{
|
57 |
+
if (!$orders) {
|
58 |
+
Mage::throwException($this->__('Order data does not exists!'));
|
59 |
+
}
|
60 |
+
|
61 |
+
if (!is_array($orders) OR !count($orders)) {
|
62 |
+
Mage::throwException($this->__('Invalid order data!'));
|
63 |
+
}
|
64 |
+
|
65 |
+
$params = json_encode($orders);
|
66 |
+
|
67 |
+
$url = $this->_getExportOrderHistoryUrl();
|
68 |
+
|
69 |
+
$this->_init();
|
70 |
+
$this->setUri($url);
|
71 |
+
|
72 |
+
$this->setRawData($params, 'application/json');
|
73 |
+
|
74 |
+
if ($this->_getHelper()->logRequestInfo()) {
|
75 |
+
|
76 |
+
$batchSize = 20;
|
77 |
+
$total = count($orders);
|
78 |
+
|
79 |
+
$numBatches = floor(floatval($total) / floatval($batchSize)) + (floatval($total) % floatval($batchSize));
|
80 |
+
$batchCounter = 0;
|
81 |
+
|
82 |
+
$batch = array();
|
83 |
+
|
84 |
+
$counter = 0;
|
85 |
+
foreach ($orders as $order) {
|
86 |
+
$counter++;
|
87 |
+
|
88 |
+
if ($counter >= $total) {
|
89 |
+
$batchCounter++;
|
90 |
+
$logData = json_encode($batch);
|
91 |
+
Mage::getSingleton('koan_seg/logger')->log(
|
92 |
+
'Magento: posting history orders to Seg', 'info', array('orders' => $logData, 'endpoint' => $url, 'batch' => $batchCounter, 'batches' => $numBatches));
|
93 |
+
|
94 |
+
break;
|
95 |
+
}
|
96 |
+
|
97 |
+
if (count($batch) < $batchSize) {
|
98 |
+
$batch[] = $order;
|
99 |
+
} else {
|
100 |
+
$batchCounter++;
|
101 |
+
$logData = json_encode($batch);
|
102 |
+
|
103 |
+
Mage::getSingleton('koan_seg/logger')->log(
|
104 |
+
'Magento: posting history orders to Seg', 'info', array('orders' => $logData, 'endpoint' => $url, 'batch' => $batchCounter, 'batches' => $numBatches));
|
105 |
+
|
106 |
+
$batch = array();
|
107 |
+
}
|
108 |
+
|
109 |
+
}
|
110 |
+
|
111 |
+
}
|
112 |
+
|
113 |
+
try {
|
114 |
+
$response = $this->request();
|
115 |
+
} Catch (Exception $e) {
|
116 |
+
throw $e;
|
117 |
+
}
|
118 |
+
|
119 |
+
try {
|
120 |
+
$this->__handleResponse($response, 'posting history orders to Seg');
|
121 |
+
} Catch (Exception $e) {
|
122 |
+
Mage::throwException('[exportHistoryOrders]::__handleResponse: ' . $e->getMessage());
|
123 |
+
}
|
124 |
+
|
125 |
+
return $this;
|
126 |
+
}
|
127 |
+
|
128 |
+
public function exportNewOrder($orderData)
|
129 |
+
{
|
130 |
+
if (!$orderData) {
|
131 |
+
Mage::throwException($this->__('Order data does not exists!'));
|
132 |
+
}
|
133 |
+
|
134 |
+
if (!is_array($orderData)) {
|
135 |
+
Mage::throwException($this->__('Invalid order data!'));
|
136 |
+
}
|
137 |
+
|
138 |
+
$params = json_encode($orderData);
|
139 |
+
|
140 |
+
$url = $this->_getOrderPlacedUrl();
|
141 |
+
|
142 |
+
$this->_init();
|
143 |
+
$this->setUri($url);
|
144 |
+
|
145 |
+
$this->setRawData($params, 'application/json');
|
146 |
+
|
147 |
+
if ($this->_getHelper()->logRequestInfo()) {
|
148 |
+
Mage::getSingleton('koan_seg/logger')->log('Magento: posting new order to Seg', 'info', array('order' => $params, 'endpoint' => $url));
|
149 |
+
}
|
150 |
+
|
151 |
+
try {
|
152 |
+
$response = $this->request();
|
153 |
+
} Catch (Exception $e) {
|
154 |
+
throw $e;
|
155 |
+
}
|
156 |
+
|
157 |
+
try {
|
158 |
+
$this->__handleResponse($response, 'posting new order to Seg');
|
159 |
+
} Catch (Exception $e) {
|
160 |
+
Mage::throwException('[exportHistoryOrders]::__handleResponse: ' . $e->getMessage());
|
161 |
+
}
|
162 |
+
|
163 |
+
return $this;
|
164 |
+
}
|
165 |
+
|
166 |
+
private function __handleResponse($response, $msg = '')
|
167 |
+
{
|
168 |
+
/** @var Zend_Http_Response $response */
|
169 |
+
if ($response->isSuccessful()) {
|
170 |
+
if ($this->_getHelper()->logRequestInfo()) {
|
171 |
+
Mage::getSingleton('koan_seg/logger')->log(sprintf('Magento: %s - response from Seg', $msg), 'info',
|
172 |
+
array('response' => 'ResponseOK: ' . $response->getBody()));
|
173 |
+
}
|
174 |
+
return true;
|
175 |
+
}
|
176 |
+
|
177 |
+
if ($response->isError()) {
|
178 |
+
$code = $response->getStatus();
|
179 |
+
$message = $response->getMessage();
|
180 |
+
Mage::getSingleton('koan_seg/exception_handler')->handleHttpResponseError(sprintf('Magento: error in \'%s\' HTTP request: %s', $msg, $message), $code, $message);
|
181 |
+
}
|
182 |
+
|
183 |
+
return false;
|
184 |
+
}
|
185 |
+
|
186 |
+
private function _init()
|
187 |
+
{
|
188 |
+
$this->setConfig($this->_getHttpConfig());
|
189 |
+
$this->setMethod(Zend_Http_Client::POST);
|
190 |
+
|
191 |
+
if ($headers = $this->_getHttpHeaders()) {
|
192 |
+
$this->setHeaders($headers);
|
193 |
+
}
|
194 |
+
return $this;
|
195 |
+
}
|
196 |
+
|
197 |
+
private function _getExportCustomerUrl()
|
198 |
+
{
|
199 |
+
return sprintf($this->_getHelper()->getUpdateCustomersUrl(), $this->_getHelper()->getWebsiteId());
|
200 |
+
}
|
201 |
+
|
202 |
+
private function _getExportOrderHistoryUrl()
|
203 |
+
{
|
204 |
+
return sprintf($this->_getHelper()->getOrderHistoryUrl(), $this->_getHelper()->getWebsiteId());
|
205 |
+
}
|
206 |
+
|
207 |
+
private function _getOrderPlacedUrl()
|
208 |
+
{
|
209 |
+
return sprintf($this->_getHelper()->getOrderPlacedUrl(), $this->_getHelper()->getWebsiteId());
|
210 |
+
}
|
211 |
+
|
212 |
+
private function _getHttpHeaders()
|
213 |
+
{
|
214 |
+
return array('accept' => 'application/json');
|
215 |
+
}
|
216 |
+
|
217 |
+
private function _getHttpConfig()
|
218 |
+
{
|
219 |
+
return array(
|
220 |
+
'timeout' => $this->_getTimeout(),
|
221 |
+
//'proxy' => '127.0.0.1:8888' //For development purposes only
|
222 |
+
);
|
223 |
+
}
|
224 |
+
|
225 |
+
private function _getTimeout()
|
226 |
+
{
|
227 |
+
return self::REQUEST_TIMEOUT;
|
228 |
+
}
|
229 |
+
|
230 |
+
private function _getHelper()
|
231 |
+
{
|
232 |
+
return Mage::helper('koan_seg');
|
233 |
+
}
|
234 |
+
|
235 |
+
private function __($text)
|
236 |
+
{
|
237 |
+
return $this->_getHelper()->__($text);
|
238 |
+
}
|
239 |
+
}
|
app/code/community/Koan/Seg/Model/Seg/Customer.php
ADDED
@@ -0,0 +1,71 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/**
|
4 |
+
* @category Koan
|
5 |
+
* @package Seg
|
6 |
+
* @author Seg <hello@getseg.com, http://getseg.com>
|
7 |
+
* @copyright Seg <http://getseg.com>
|
8 |
+
* @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
|
9 |
+
*/
|
10 |
+
class Koan_Seg_Model_Seg_Customer extends Varien_Object
|
11 |
+
{
|
12 |
+
public function prepare($customer)
|
13 |
+
{
|
14 |
+
if (!$customer) {
|
15 |
+
Mage::throwException('Customer is not valid!');
|
16 |
+
}
|
17 |
+
|
18 |
+
if (!$customerId = $customer->getId()) {
|
19 |
+
Mage::throwException('Missing Customer Id');
|
20 |
+
}
|
21 |
+
|
22 |
+
$attributes = array(
|
23 |
+
'Email',
|
24 |
+
);
|
25 |
+
|
26 |
+
$email = $customer->getEmail();
|
27 |
+
if (empty($email)) {
|
28 |
+
Mage::throwException($this->__('Customer email is missing!'));
|
29 |
+
}
|
30 |
+
|
31 |
+
$this->setData('Email', $email);
|
32 |
+
|
33 |
+
$title = $customer->getPrefix();
|
34 |
+
if (!empty($title)) {
|
35 |
+
$this->setData('Title', $title);
|
36 |
+
$attributes[] = 'Title';
|
37 |
+
}
|
38 |
+
|
39 |
+
$firstName = $customer->getFirstname();
|
40 |
+
// if (empty($firstName)) {
|
41 |
+
// $firstName = $email;
|
42 |
+
// }
|
43 |
+
|
44 |
+
if (!empty($firstName)) {
|
45 |
+
$this->setData('FirstName', $firstName);
|
46 |
+
$attributes[] = 'FirstName';
|
47 |
+
}
|
48 |
+
|
49 |
+
$lastName = $customer->getLastname();
|
50 |
+
if (!empty($lastName)) {
|
51 |
+
$this->setData('LastName', $lastName);
|
52 |
+
$attributes[] = 'LastName';
|
53 |
+
}
|
54 |
+
|
55 |
+
$address = $customer->getPrimaryBillingAddress();
|
56 |
+
if (!$address) {
|
57 |
+
$address = $customer->getPrimaryShippingAddress();
|
58 |
+
}
|
59 |
+
|
60 |
+
$country = null;
|
61 |
+
if ($address AND $address->getId()) {
|
62 |
+
$country = $address->getCountry();
|
63 |
+
}
|
64 |
+
if (!empty($country)) {
|
65 |
+
$this->setData('CountryCode', $country);
|
66 |
+
$attributes[] = 'CountryCode';
|
67 |
+
}
|
68 |
+
|
69 |
+
return $this->toArray($attributes);
|
70 |
+
}
|
71 |
+
}
|
app/code/community/Koan/Seg/Model/Seg/Exporter.php
ADDED
@@ -0,0 +1,384 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
class Koan_Seg_Model_Seg_Exporter
|
4 |
+
{
|
5 |
+
const BATCH_STATUS_NOT_STARTED = 0;
|
6 |
+
const BATCH_STATUS_STARTING = 1;
|
7 |
+
const BATCH_STATUS_PROCESSING_ROWS = 2;
|
8 |
+
|
9 |
+
const BATCH_STATUS_COMPLETE = 5;
|
10 |
+
const BATCH_STATUS_ERROR = 6;
|
11 |
+
|
12 |
+
const BATCH_ENTITY_TYPE_HISTORY_ORDERS = 'history_orders';
|
13 |
+
const BATCH_ENTITY_TYPE_CUSTOMERS = 'customers';
|
14 |
+
|
15 |
+
public static $_exportHistoryOrdersGenerateCron = false;
|
16 |
+
public static $_exportHistoryOrdersCron = false;
|
17 |
+
|
18 |
+
public static $_exportCustomersGenerateCron = false;
|
19 |
+
public static $_exportCustomersCron = false;
|
20 |
+
|
21 |
+
private $_historyOrdersCollection = null;
|
22 |
+
|
23 |
+
private $_customersCollection = null;
|
24 |
+
|
25 |
+
/**************************************** CUSTOMERS ******************************************/
|
26 |
+
|
27 |
+
//Prepare new customers batch to export
|
28 |
+
public function generateCustomersExportBatch()
|
29 |
+
{
|
30 |
+
if (self::$_exportCustomersGenerateCron == true) {
|
31 |
+
return $this;
|
32 |
+
}
|
33 |
+
|
34 |
+
$this->_getHelper()->initRollbar();
|
35 |
+
|
36 |
+
try {
|
37 |
+
$this->_exportCustomers(true);
|
38 |
+
} Catch (Exception $e) {
|
39 |
+
Mage::getSingleton('koan_seg/exception_handler')->handle('Magento: error in generateCustomersExportBatch', $e);
|
40 |
+
}
|
41 |
+
|
42 |
+
self::$_exportCustomersGenerateCron = true;
|
43 |
+
return $this;
|
44 |
+
}
|
45 |
+
|
46 |
+
//Export prepared batches of customers (if any)
|
47 |
+
public function exportCustomers()
|
48 |
+
{
|
49 |
+
if (self::$_exportCustomersCron == true) {
|
50 |
+
return $this;
|
51 |
+
}
|
52 |
+
|
53 |
+
$this->_getHelper()->initRollbar();
|
54 |
+
|
55 |
+
try {
|
56 |
+
|
57 |
+
if ($limit = $this->_getHelper()->getExporterPhpMemoryLimit()) {
|
58 |
+
if (!empty($limit)) {
|
59 |
+
ini_set('memory_limit', $limit);
|
60 |
+
}
|
61 |
+
}
|
62 |
+
|
63 |
+
$this->_exportCustomers();
|
64 |
+
} Catch (Exception $e) {
|
65 |
+
Mage::getSingleton('koan_seg/exception_handler')->handle('Magento: error in batch exporter - exportCustomers', $e);
|
66 |
+
}
|
67 |
+
|
68 |
+
self::$_exportCustomersCron = true;
|
69 |
+
return $this;
|
70 |
+
}
|
71 |
+
|
72 |
+
private function _exportCustomers($createNew = false)
|
73 |
+
{
|
74 |
+
if ($createNew == true) {
|
75 |
+
Mage::getModel('koan_seg/batch_status')->createNew(self::BATCH_ENTITY_TYPE_CUSTOMERS);
|
76 |
+
return $this;
|
77 |
+
}
|
78 |
+
|
79 |
+
$batchRows = $this->_getBatchRows(self::BATCH_ENTITY_TYPE_CUSTOMERS);
|
80 |
+
//We can use count here as there should be only few rows
|
81 |
+
if (!$numRows = count($batchRows)) {
|
82 |
+
return $this;
|
83 |
+
}
|
84 |
+
|
85 |
+
foreach ($batchRows as $batch) {
|
86 |
+
|
87 |
+
try {
|
88 |
+
$currentStatus = $batch->getCurrentStatus();
|
89 |
+
|
90 |
+
switch ($currentStatus) {
|
91 |
+
case self::BATCH_STATUS_NOT_STARTED:
|
92 |
+
$totalItemsCount = $this->_getCustomersCollectionSize();
|
93 |
+
$batch->setStartingStatus($totalItemsCount, self::BATCH_STATUS_STARTING);
|
94 |
+
case self::BATCH_STATUS_STARTING:
|
95 |
+
$batch->setProcessingStatus(self::BATCH_STATUS_PROCESSING_ROWS);
|
96 |
+
case self::BATCH_STATUS_PROCESSING_ROWS:
|
97 |
+
$this->_processExportCustomers($batch);
|
98 |
+
$batch->setCompleteStatus(self::BATCH_STATUS_COMPLETE);
|
99 |
+
}
|
100 |
+
|
101 |
+
} Catch (Exception $e) {
|
102 |
+
$batch->setBatchError($e->getMessage());
|
103 |
+
throw $e;
|
104 |
+
}
|
105 |
+
|
106 |
+
}
|
107 |
+
|
108 |
+
return $this;
|
109 |
+
}
|
110 |
+
|
111 |
+
public function _getCustomersCollectionSize()
|
112 |
+
{
|
113 |
+
$collection = $this->_getCustomersCollection();
|
114 |
+
return $collection->getSize();
|
115 |
+
}
|
116 |
+
|
117 |
+
public function _getCustomersCollection()
|
118 |
+
{
|
119 |
+
if (!$this->_customersCollection) {
|
120 |
+
$collection = Mage::getResourceModel('customer/customer_collection')
|
121 |
+
->addAttributeToSelect('*')
|
122 |
+
->joinAttribute('billing_country_id', 'customer_address/country_id', 'default_billing', null, 'left')
|
123 |
+
->joinAttribute('shipping_country_id', 'customer_address/country_id', 'default_shipping', null, 'left');
|
124 |
+
//->load();
|
125 |
+
|
126 |
+
$this->_customersCollection = $collection;
|
127 |
+
}
|
128 |
+
|
129 |
+
return $this->_customersCollection;
|
130 |
+
}
|
131 |
+
|
132 |
+
private function _processExportCustomers($batch)
|
133 |
+
{
|
134 |
+
$numProcTotal = is_null($batch->getNumRowsProcessed()) ? 0 : intval($batch->getNumRowsProcessed());
|
135 |
+
$totalRows = is_null($batch->getTotalRowCount()) ? 0 : intval($batch->getTotalRowCount());
|
136 |
+
|
137 |
+
if ($numProcTotal < $totalRows) {
|
138 |
+
|
139 |
+
$break = false;
|
140 |
+
|
141 |
+
do {
|
142 |
+
|
143 |
+
$collection = clone $this->_getCustomersCollection();
|
144 |
+
$collection->setOrder('entity_id', 'ASC');
|
145 |
+
$collection->getSelect()->limit($this->_getExportCustomersPageSize(), $numProcTotal);
|
146 |
+
$collection->load();
|
147 |
+
|
148 |
+
$numProcessed = 0;
|
149 |
+
|
150 |
+
$customers = array();
|
151 |
+
foreach ($collection as $customer) {
|
152 |
+
|
153 |
+
$customers[] = Mage::getModel('koan_seg/seg_customer')->prepare($customer);
|
154 |
+
$numProcessed++;
|
155 |
+
}
|
156 |
+
|
157 |
+
Mage::getModel('koan_seg/seg_client')->exportCustomers($customers);
|
158 |
+
|
159 |
+
unset($customers);
|
160 |
+
$customers = array();
|
161 |
+
|
162 |
+
$numProcTotal += $numProcessed;
|
163 |
+
$batch->updateNumRowsProcessed(null, $numProcessed);
|
164 |
+
|
165 |
+
if ($numProcTotal >= $totalRows) {
|
166 |
+
//Update total rows
|
167 |
+
$batch->updateNumRowsProcessed($numProcTotal, 0);
|
168 |
+
$break = true;
|
169 |
+
}
|
170 |
+
|
171 |
+
} while (!$break);
|
172 |
+
|
173 |
+
}
|
174 |
+
|
175 |
+
}
|
176 |
+
|
177 |
+
private function _getExportCustomersPageSize()
|
178 |
+
{
|
179 |
+
return Mage::helper('koan_seg')->getCustomersExportBatchSize();
|
180 |
+
}
|
181 |
+
|
182 |
+
/**************************************** END CUSTOMERS ******************************************/
|
183 |
+
|
184 |
+
/**************************************** ORDERS ******************************************/
|
185 |
+
|
186 |
+
//Prepare new history orders batch to export
|
187 |
+
public function generateHistoryOrdersExportBatch($orderDateFilter = null)
|
188 |
+
{
|
189 |
+
if (self::$_exportHistoryOrdersGenerateCron == true) {
|
190 |
+
return $this;
|
191 |
+
}
|
192 |
+
|
193 |
+
$this->_getHelper()->initRollbar();
|
194 |
+
|
195 |
+
try {
|
196 |
+
$this->_exportHistoryOrders(true, $orderDateFilter);
|
197 |
+
} Catch (Exception $e) {
|
198 |
+
Mage::getSingleton('koan_seg/exception_handler')->handle('Magento: error in generateHistoryOrdersExportBatch', $e);
|
199 |
+
}
|
200 |
+
|
201 |
+
self::$_exportHistoryOrdersGenerateCron = true;
|
202 |
+
return $this;
|
203 |
+
}
|
204 |
+
|
205 |
+
//Export prepared batches of history orders (if any)
|
206 |
+
public function exportHistoryOrders()
|
207 |
+
{
|
208 |
+
if (self::$_exportHistoryOrdersCron == true) {
|
209 |
+
return $this;
|
210 |
+
}
|
211 |
+
|
212 |
+
$this->_getHelper()->initRollbar();
|
213 |
+
|
214 |
+
try {
|
215 |
+
|
216 |
+
if ($limit = $this->_getHelper()->getExporterPhpMemoryLimit()) {
|
217 |
+
if (!empty($limit)) {
|
218 |
+
ini_set('memory_limit', $limit);
|
219 |
+
}
|
220 |
+
}
|
221 |
+
|
222 |
+
$this->_exportHistoryOrders();
|
223 |
+
} Catch (Exception $e) {
|
224 |
+
Mage::getSingleton('koan_seg/exception_handler')->handle('Magento: error in batch exporter - exportHistoryOrders', $e);
|
225 |
+
}
|
226 |
+
|
227 |
+
self::$_exportHistoryOrdersCron = true;
|
228 |
+
return $this;
|
229 |
+
}
|
230 |
+
|
231 |
+
private function _exportHistoryOrders($createNew = false, $orderDateFilter = null)
|
232 |
+
{
|
233 |
+
if ($createNew == true) {
|
234 |
+
Mage::getModel('koan_seg/batch_status')->createNew(self::BATCH_ENTITY_TYPE_HISTORY_ORDERS, $orderDateFilter);
|
235 |
+
return $this;
|
236 |
+
}
|
237 |
+
|
238 |
+
$batchRows = $this->_getBatchRows(self::BATCH_ENTITY_TYPE_HISTORY_ORDERS);
|
239 |
+
//We can use count here as there should be only few rows
|
240 |
+
if (!$numRows = count($batchRows)) {
|
241 |
+
return $this;
|
242 |
+
}
|
243 |
+
|
244 |
+
foreach ($batchRows as $batch) {
|
245 |
+
try {
|
246 |
+
$currentStatus = $batch->getCurrentStatus();
|
247 |
+
|
248 |
+
switch ($currentStatus) {
|
249 |
+
case self::BATCH_STATUS_NOT_STARTED:
|
250 |
+
$totalItemsCount = $this->_getHistoryOrdersCollectionSize($batch);
|
251 |
+
$batch->setStartingStatus($totalItemsCount, self::BATCH_STATUS_STARTING);
|
252 |
+
case self::BATCH_STATUS_STARTING:
|
253 |
+
$batch->setProcessingStatus(self::BATCH_STATUS_PROCESSING_ROWS);
|
254 |
+
case self::BATCH_STATUS_PROCESSING_ROWS:
|
255 |
+
$this->_processExportHistoryOrders($batch);
|
256 |
+
$batch->setCompleteStatus(self::BATCH_STATUS_COMPLETE);
|
257 |
+
}
|
258 |
+
|
259 |
+
} Catch (Exception $e) {
|
260 |
+
$batch->setBatchError($e->getMessage());
|
261 |
+
throw $e;
|
262 |
+
}
|
263 |
+
|
264 |
+
}
|
265 |
+
|
266 |
+
return $this;
|
267 |
+
}
|
268 |
+
|
269 |
+
private function _processExportHistoryOrders($batch)
|
270 |
+
{
|
271 |
+
$numProcTotal = is_null($batch->getNumRowsProcessed()) ? 0 : intval($batch->getNumRowsProcessed());
|
272 |
+
$totalRows = is_null($batch->getTotalRowCount()) ? 0 : intval($batch->getTotalRowCount());
|
273 |
+
|
274 |
+
if ($numProcTotal < $totalRows) {
|
275 |
+
|
276 |
+
$break = false;
|
277 |
+
|
278 |
+
do {
|
279 |
+
|
280 |
+
$collection = clone $this->_getHistoryOrdersCollection($batch);
|
281 |
+
$collection->setOrder('entity_id', 'ASC');
|
282 |
+
$collection->getSelect()->limit($this->_getExportHistoryPageSize(), $numProcTotal);
|
283 |
+
$collection->load();
|
284 |
+
|
285 |
+
$numProcessed = 0;
|
286 |
+
|
287 |
+
$orders = array();
|
288 |
+
foreach ($collection as $order) {
|
289 |
+
|
290 |
+
//TODO: Handle collection export
|
291 |
+
$orders[] = Mage::getModel('koan_seg/seg_order')->prepare($order);
|
292 |
+
$numProcessed++;
|
293 |
+
}
|
294 |
+
|
295 |
+
Mage::getModel('koan_seg/seg_client')->exportHistoryOrders($orders);
|
296 |
+
|
297 |
+
unset($orders);
|
298 |
+
$orders = array();
|
299 |
+
|
300 |
+
$numProcTotal += $numProcessed;
|
301 |
+
$batch->updateNumRowsProcessed(null, $numProcessed);
|
302 |
+
|
303 |
+
if ($numProcTotal >= $totalRows) {
|
304 |
+
$batch->updateNumRowsProcessed($numProcTotal, 0);
|
305 |
+
$break = true;
|
306 |
+
}
|
307 |
+
|
308 |
+
} while (!$break);
|
309 |
+
|
310 |
+
}
|
311 |
+
|
312 |
+
}
|
313 |
+
|
314 |
+
private function _getExportHistoryPageSize()
|
315 |
+
{
|
316 |
+
return Mage::helper('koan_seg')->getOrdersExportBatchSize();
|
317 |
+
}
|
318 |
+
|
319 |
+
public function hasCustomersToProcess()
|
320 |
+
{
|
321 |
+
$rows = $this->_getBatchRows(self::BATCH_ENTITY_TYPE_CUSTOMERS);
|
322 |
+
if ($rows AND count($rows)) {
|
323 |
+
return true;
|
324 |
+
}
|
325 |
+
|
326 |
+
return false;
|
327 |
+
}
|
328 |
+
|
329 |
+
public function hasOrdersToProcess()
|
330 |
+
{
|
331 |
+
$rows = $this->_getBatchRows(self::BATCH_ENTITY_TYPE_HISTORY_ORDERS);
|
332 |
+
if ($rows AND count($rows)) {
|
333 |
+
return true;
|
334 |
+
}
|
335 |
+
|
336 |
+
return false;
|
337 |
+
}
|
338 |
+
|
339 |
+
private function _getBatchRows($entityType)
|
340 |
+
{
|
341 |
+
$allowedStages = array(
|
342 |
+
self::BATCH_STATUS_NOT_STARTED,
|
343 |
+
self::BATCH_STATUS_STARTING,
|
344 |
+
self::BATCH_STATUS_PROCESSING_ROWS
|
345 |
+
);
|
346 |
+
|
347 |
+
$collection = Mage::getResourceModel('koan_seg/batch_status_collection');
|
348 |
+
$collection->addFieldToFilter('current_status', array('in' => $allowedStages));
|
349 |
+
$collection->addFieldToFilter('entity_type', $entityType);
|
350 |
+
$collection->setOrder('current_status', 'ASC');
|
351 |
+
|
352 |
+
return $collection;
|
353 |
+
}
|
354 |
+
|
355 |
+
public function _getHistoryOrdersCollectionSize($batch = null)
|
356 |
+
{
|
357 |
+
return $this->_getHistoryOrdersCollection($batch)->getSize();
|
358 |
+
}
|
359 |
+
|
360 |
+
public function _getHistoryOrdersCollection($batch = null)
|
361 |
+
{
|
362 |
+
if (!$this->_historyOrdersCollection) {
|
363 |
+
$collection = Mage::getResourceModel('sales/order_collection');
|
364 |
+
$collection->addFieldToFilter('state', 'complete');
|
365 |
+
|
366 |
+
if ($batch AND $filter = $batch->getFilter()) {
|
367 |
+
$collection->addFieldToFilter('created_at', array('from' => $filter));
|
368 |
+
}
|
369 |
+
|
370 |
+
$this->_historyOrdersCollection = $collection;
|
371 |
+
}
|
372 |
+
|
373 |
+
return $this->_historyOrdersCollection;
|
374 |
+
}
|
375 |
+
|
376 |
+
/**************************************** END ORDERS ******************************************/
|
377 |
+
|
378 |
+
|
379 |
+
public function _getHelper()
|
380 |
+
{
|
381 |
+
return Mage::helper('koan_seg');
|
382 |
+
}
|
383 |
+
|
384 |
+
}
|
app/code/community/Koan/Seg/Model/Seg/Order.php
ADDED
@@ -0,0 +1,78 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
class Koan_Seg_Model_Seg_Order extends Varien_Object
|
4 |
+
{
|
5 |
+
public function prepare($order, $includeMailAndDate = true)
|
6 |
+
{
|
7 |
+
if (!$order) {
|
8 |
+
Mage::throwException($this->_getHelper()->__('Order is not valid!'));
|
9 |
+
}
|
10 |
+
|
11 |
+
if (!$orderId = $order->getId()) {
|
12 |
+
Mage::throwException($this->_getHelper()->__('Missing Order Id'));
|
13 |
+
}
|
14 |
+
|
15 |
+
$baseGrandTotal = is_null($order->getBaseGrandTotal()) ? 0 : $order->getBaseGrandTotal();
|
16 |
+
$baseTotalRefunded = is_null($order->getBaseTotalRefunded()) ? 0 : $order->getBaseTotalRefunded();
|
17 |
+
|
18 |
+
$revenue = $baseGrandTotal - $baseTotalRefunded;
|
19 |
+
|
20 |
+
$shippingMethod = $order->getShippingDescription();
|
21 |
+
if (empty($shippingMethod)) {
|
22 |
+
$shippingMethod = 'VIRTUAL ORDER';
|
23 |
+
}
|
24 |
+
|
25 |
+
$customerEmail = is_null($order->getCustomerEmail()) ? 'unknown@mail.com' : $order->getCustomerEmail();
|
26 |
+
$createdAt = is_null($order->getCreatedAt()) ? '0000-00-00 0:00:00' : $order->getCreatedAt();
|
27 |
+
|
28 |
+
$params = array(
|
29 |
+
'DeliveryMethod',
|
30 |
+
'DeliveryRevenue',
|
31 |
+
'Discount',
|
32 |
+
'Id',
|
33 |
+
'OrderLines',
|
34 |
+
//'_p',
|
35 |
+
'Revenue'
|
36 |
+
);
|
37 |
+
|
38 |
+
if ($includeMailAndDate) {
|
39 |
+
$this->setData('email', $customerEmail);
|
40 |
+
$this->setData('date', $createdAt);
|
41 |
+
|
42 |
+
$params[] = 'email';
|
43 |
+
$params[] = 'date';
|
44 |
+
}
|
45 |
+
|
46 |
+
$this->setData('DeliveryMethod', $shippingMethod);
|
47 |
+
$this->setData('DeliveryRevenue', number_format($order->getBaseShippingAmount(), 2, '.', ''));
|
48 |
+
$this->setData('Discount', number_format($order->getBaseDiscountAmount() * (-1), 2, '.', ''));
|
49 |
+
$this->setData('Id', $orderId);
|
50 |
+
$this->setData('OrderLines', $this->_prepareOrderLines($order));
|
51 |
+
//$this->setData('_p', $order->getBaseGrandTotal());
|
52 |
+
$this->setData('Revenue', number_format($revenue, 2, '.', ''));
|
53 |
+
|
54 |
+
return $this->toArray($params);
|
55 |
+
|
56 |
+
//return prepared array structure for sending via HTTP request
|
57 |
+
}
|
58 |
+
|
59 |
+
private function _prepareOrderLines($order)
|
60 |
+
{
|
61 |
+
$orderItems = $order->getAllVisibleItems();
|
62 |
+
|
63 |
+
$result = array();
|
64 |
+
if ($orderItems AND count($orderItems)) {
|
65 |
+
foreach ($orderItems as $item) {
|
66 |
+
$result[] = Mage::getModel('koan_seg/seg_order_line')->prepare($item);
|
67 |
+
}
|
68 |
+
}
|
69 |
+
|
70 |
+
return $result;
|
71 |
+
}
|
72 |
+
|
73 |
+
private function _getHelper()
|
74 |
+
{
|
75 |
+
return Mage::helper('koan_seg');
|
76 |
+
}
|
77 |
+
|
78 |
+
}
|
app/code/community/Koan/Seg/Model/Seg/Order/Line.php
ADDED
@@ -0,0 +1,125 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
class Koan_Seg_Model_Seg_Order_Line extends Varien_Object
|
4 |
+
{
|
5 |
+
|
6 |
+
public function prepare($item)
|
7 |
+
{
|
8 |
+
$qty = $item->getQtyOrdered();
|
9 |
+
|
10 |
+
//Product is configurable parent
|
11 |
+
if (count($item->getChildrenItems())) {
|
12 |
+
$children = $item->getChildrenItems();
|
13 |
+
$product = $children[0]->getProduct();
|
14 |
+
//Product is simple
|
15 |
+
} else {
|
16 |
+
$product = $item->getProduct();
|
17 |
+
}
|
18 |
+
|
19 |
+
$product->load($product->getId());
|
20 |
+
|
21 |
+
if ($parent = $item->getParentItem()) {
|
22 |
+
$subtotal = $parent->getBaseRowTotalInclTax();
|
23 |
+
$discount = is_null($parent->getBaseDiscountAmount()) ? 0 : $parent->getBaseDiscountAmount();
|
24 |
+
$subtotal -= $discount;
|
25 |
+
} else {
|
26 |
+
$subtotal = $item->getBaseRowTotalInclTax();
|
27 |
+
$discount = is_null($item->getBaseDiscountAmount()) ? 0 : $item->getBaseDiscountAmount();
|
28 |
+
$subtotal -= $discount;
|
29 |
+
}
|
30 |
+
|
31 |
+
if ($parent = $item->getParentItem()) {
|
32 |
+
$originalPrice = $parent->getBasePriceInclTax();
|
33 |
+
} else {
|
34 |
+
$originalPrice = $item->getBasePriceInclTax();
|
35 |
+
}
|
36 |
+
|
37 |
+
if ($discount > 0) {
|
38 |
+
$price = $subtotal / $item->getQtyOrdered();
|
39 |
+
} else {
|
40 |
+
$price = $originalPrice;
|
41 |
+
}
|
42 |
+
|
43 |
+
$this->setData('Quantity', number_format($qty, 2, '.', ''));
|
44 |
+
$this->setData('Id', $item->getProductId());
|
45 |
+
$this->setData('ImageUrl', $product->getImageUrl());
|
46 |
+
|
47 |
+
//TODO: Check this parameter for configurable products and Bundle products etc
|
48 |
+
$this->setData('Name', $item->getName());
|
49 |
+
|
50 |
+
$this->setData('OriginalPrice', number_format($originalPrice, 2, '.', ''));
|
51 |
+
$this->setData('Price', number_format($price, 2, '.', ''));
|
52 |
+
|
53 |
+
$optionsResult = array();
|
54 |
+
|
55 |
+
if ($options = $item->getProductOptions()) {
|
56 |
+
if (isset($options['options'])) {
|
57 |
+
$optionsResult = array_merge($optionsResult, $options['options']);
|
58 |
+
}
|
59 |
+
if (isset($options['additional_options'])) {
|
60 |
+
$optionsResult = array_merge($optionsResult, $options['additional_options']);
|
61 |
+
}
|
62 |
+
if (!empty($options['attributes_info'])) {
|
63 |
+
$optionsResult = array_merge($options['attributes_info'], $optionsResult);
|
64 |
+
}
|
65 |
+
|
66 |
+
$variantName = '';
|
67 |
+
$i = 0;
|
68 |
+
|
69 |
+
foreach ($optionsResult as $option) {
|
70 |
+
if ($i > 0) {
|
71 |
+
$variantName .= ', ';
|
72 |
+
}
|
73 |
+
|
74 |
+
$variantName .= sprintf('%s: %s', $option['label'], $option['value']);
|
75 |
+
$i++;
|
76 |
+
}
|
77 |
+
|
78 |
+
$this->setData('VariantName', $variantName);
|
79 |
+
}
|
80 |
+
|
81 |
+
$outputAttributes = array(
|
82 |
+
'Quantity',
|
83 |
+
'Id',
|
84 |
+
'ImageUrl',
|
85 |
+
'Name',
|
86 |
+
'OriginalPrice',
|
87 |
+
'Price',
|
88 |
+
);
|
89 |
+
|
90 |
+
$brands = $this->_getHelper()->getProductBrands($product, $item->getStoreId());
|
91 |
+
if (!empty($brands)) {
|
92 |
+
$this->setData('Brands', $brands);
|
93 |
+
$outputAttributes[] = 'Brands';
|
94 |
+
}
|
95 |
+
|
96 |
+
if (!empty($variantName)) {
|
97 |
+
$outputAttributes[] = 'VariantName';
|
98 |
+
}
|
99 |
+
|
100 |
+
$catIds = $product->getCategoryIds();
|
101 |
+
$categoriesResult = array();
|
102 |
+
if ($catIds AND is_array($catIds) AND count($catIds)) {
|
103 |
+
foreach ($catIds as $catId) {
|
104 |
+
$category = Mage::getModel('catalog/category')
|
105 |
+
->setStoreId($item->getStoreId())
|
106 |
+
->load($catId);
|
107 |
+
|
108 |
+
if ($category AND $category->getId()) {
|
109 |
+
$categoriesResult[] = $category->getName();
|
110 |
+
}
|
111 |
+
}
|
112 |
+
}
|
113 |
+
if (count($categoriesResult)) {
|
114 |
+
$this->setData('Categories', $categoriesResult);
|
115 |
+
$outputAttributes[] = 'Categories';
|
116 |
+
}
|
117 |
+
|
118 |
+
return $this->toArray($outputAttributes);
|
119 |
+
}
|
120 |
+
|
121 |
+
private function _getHelper()
|
122 |
+
{
|
123 |
+
return Mage::helper('koan_seg');
|
124 |
+
}
|
125 |
+
}
|
app/code/community/Koan/Seg/Model/Seg/Product.php
ADDED
@@ -0,0 +1,69 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/**
|
4 |
+
* @category Koan
|
5 |
+
* @package Seg
|
6 |
+
* @author Seg <hello@getseg.com, http://getseg.com>
|
7 |
+
* @copyright Seg <http://getseg.com>
|
8 |
+
* @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
|
9 |
+
*/
|
10 |
+
class Koan_Seg_Model_Seg_Product extends Varien_Object
|
11 |
+
{
|
12 |
+
public function prepare($product)
|
13 |
+
{
|
14 |
+
if (!$product) {
|
15 |
+
Mage::throwException('Product is not valid!');
|
16 |
+
}
|
17 |
+
|
18 |
+
if (!$productId = $product->getId()) {
|
19 |
+
Mage::throwException('Missing Product Id');
|
20 |
+
}
|
21 |
+
|
22 |
+
$storeId = Mage::app()->getStore()->getId();
|
23 |
+
|
24 |
+
$outputAttributes = array(
|
25 |
+
'Id', 'ImageUrl', 'Name', 'OriginalPrice', 'Price'
|
26 |
+
);
|
27 |
+
|
28 |
+
$productData = array(
|
29 |
+
'Id' => $productId,
|
30 |
+
'ImageUrl' => $product->getImageUrl(),
|
31 |
+
'Name' => $product->getName(),
|
32 |
+
'OriginalPrice' => Mage::helper('tax')->getPrice($product, $product->getPrice()),
|
33 |
+
'Price' => Mage::helper('tax')->getPrice($product, $product->getFinalPrice()),
|
34 |
+
);
|
35 |
+
|
36 |
+
$this->setData($productData);
|
37 |
+
|
38 |
+
$catIds = $product->getCategoryIds();
|
39 |
+
$categoriesResult = array();
|
40 |
+
if ($catIds AND is_array($catIds) AND count($catIds)) {
|
41 |
+
foreach ($catIds as $catId) {
|
42 |
+
$category = Mage::getModel('catalog/category')
|
43 |
+
->setStoreId($storeId)
|
44 |
+
->load($catId);
|
45 |
+
|
46 |
+
if ($category AND $category->getId()) {
|
47 |
+
$categoriesResult[] = $category->getName();
|
48 |
+
}
|
49 |
+
}
|
50 |
+
}
|
51 |
+
if (count($categoriesResult)) {
|
52 |
+
$this->setData('Categories', $categoriesResult);
|
53 |
+
$outputAttributes[] = 'Categories';
|
54 |
+
}
|
55 |
+
|
56 |
+
$brands = $this->_getHelper()->getProductBrands($product, $storeId);
|
57 |
+
if (!empty($brands)) {
|
58 |
+
$this->setData('Brands', $brands);
|
59 |
+
$outputAttributes[] = 'Brands';
|
60 |
+
}
|
61 |
+
|
62 |
+
return $this->toArray($outputAttributes);
|
63 |
+
}
|
64 |
+
|
65 |
+
private function _getHelper()
|
66 |
+
{
|
67 |
+
return Mage::helper('koan_seg');
|
68 |
+
}
|
69 |
+
}
|
app/code/community/Koan/Seg/Model/Seg/Quote/Line.php
ADDED
@@ -0,0 +1,139 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/**
|
4 |
+
* @category Koan
|
5 |
+
* @package Seg
|
6 |
+
* @author Seg <hello@getseg.com, http://getseg.com>
|
7 |
+
* @copyright Seg <http://getseg.com>
|
8 |
+
* @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
|
9 |
+
*/
|
10 |
+
class Koan_Seg_Model_Seg_Quote_Line extends Varien_Object
|
11 |
+
{
|
12 |
+
|
13 |
+
public function prepare($item, $isAdded = false)
|
14 |
+
{
|
15 |
+
$qty = $item->getQty();
|
16 |
+
$parentProduct = null;
|
17 |
+
|
18 |
+
//Product is configurable parent
|
19 |
+
if (count($item->getChildren())) {
|
20 |
+
$children = $item->getChildren();
|
21 |
+
$product = $children[0]->getProduct();
|
22 |
+
$parentProduct = $item->getProduct();
|
23 |
+
//Product is simple
|
24 |
+
} else {
|
25 |
+
$product = $item->getProduct();
|
26 |
+
}
|
27 |
+
|
28 |
+
$product->load($product->getId());
|
29 |
+
|
30 |
+
if ($parent = $item->getParentItem()) {
|
31 |
+
$subtotal = $parent->getBaseRowTotalInclTax();
|
32 |
+
$discount = is_null($parent->getBaseDiscountAmount()) ? 0 : $parent->getBaseDiscountAmount();
|
33 |
+
$subtotal -= $discount;
|
34 |
+
} else {
|
35 |
+
$subtotal = $item->getBaseRowTotalInclTax();
|
36 |
+
$discount = is_null($item->getBaseDiscountAmount()) ? 0 : $item->getBaseDiscountAmount();
|
37 |
+
$subtotal -= $discount;
|
38 |
+
}
|
39 |
+
|
40 |
+
if ($parent = $item->getParentItem()) {
|
41 |
+
$originalPrice = $parent->getBasePriceInclTax();
|
42 |
+
} else {
|
43 |
+
$originalPrice = $item->getBasePriceInclTax();
|
44 |
+
}
|
45 |
+
|
46 |
+
if ($discount > 0) {
|
47 |
+
$price = $subtotal / $item->getQty();
|
48 |
+
} else {
|
49 |
+
$price = $originalPrice;
|
50 |
+
}
|
51 |
+
|
52 |
+
$this->setData('Quantity', number_format($qty, 2, '.', ''));
|
53 |
+
$this->setData('Id', $item->getProductId());
|
54 |
+
$this->setData('ImageUrl', $product->getImageUrl());
|
55 |
+
|
56 |
+
//TODO: Check this parameter for configurable products and Bundle products etc
|
57 |
+
$this->setData('Name', $item->getName());
|
58 |
+
|
59 |
+
$this->setData('OriginalPrice', number_format($originalPrice, 2, '.', ''));
|
60 |
+
$this->setData('Price', number_format($price, 2, '.', ''));
|
61 |
+
|
62 |
+
$optionsResult = array();
|
63 |
+
|
64 |
+
$helper = Mage::helper('catalog/product_configuration');
|
65 |
+
|
66 |
+
if ($parentProduct) {
|
67 |
+
$typeId = $parentProduct->getTypeId();
|
68 |
+
if ($typeId AND $typeId == Mage_Catalog_Model_Product_Type_Configurable::TYPE_CODE) {
|
69 |
+
$optionsResult = $helper->getConfigurableOptions($item);
|
70 |
+
|
71 |
+
if ($optionsResult) {
|
72 |
+
$variantName = '';
|
73 |
+
$i = 0;
|
74 |
+
foreach ($optionsResult as $option) {
|
75 |
+
if ($i > 0) {
|
76 |
+
$variantName .= ', ';
|
77 |
+
}
|
78 |
+
|
79 |
+
$variantName .= sprintf('%s: %s', $option['label'], $option['value']);
|
80 |
+
$i++;
|
81 |
+
}
|
82 |
+
|
83 |
+
$this->setData('VariantName', $variantName);
|
84 |
+
}
|
85 |
+
|
86 |
+
}
|
87 |
+
|
88 |
+
}
|
89 |
+
|
90 |
+
$outputAttributes = array(
|
91 |
+
'Quantity',
|
92 |
+
'Id',
|
93 |
+
'ImageUrl',
|
94 |
+
'Name',
|
95 |
+
'OriginalPrice',
|
96 |
+
'Price',
|
97 |
+
);
|
98 |
+
|
99 |
+
$brands = $this->_getHelper()->getProductBrands($product, $item->getStoreId());
|
100 |
+
if (!empty($brands)) {
|
101 |
+
$this->setData('Brands', $brands);
|
102 |
+
$outputAttributes[] = 'Brands';
|
103 |
+
}
|
104 |
+
|
105 |
+
if (!empty($variantName)) {
|
106 |
+
$outputAttributes[] = 'VariantName';
|
107 |
+
}
|
108 |
+
|
109 |
+
$catIds = $product->getCategoryIds();
|
110 |
+
$categoriesResult = array();
|
111 |
+
if ($catIds AND is_array($catIds) AND count($catIds)) {
|
112 |
+
foreach ($catIds as $catId) {
|
113 |
+
$category = Mage::getModel('catalog/category')
|
114 |
+
->setStoreId($item->getStoreId())
|
115 |
+
->load($catId);
|
116 |
+
|
117 |
+
if ($category AND $category->getId()) {
|
118 |
+
$categoriesResult[] = $category->getName();
|
119 |
+
}
|
120 |
+
}
|
121 |
+
}
|
122 |
+
if (count($categoriesResult)) {
|
123 |
+
$this->setData('Categories', $categoriesResult);
|
124 |
+
$outputAttributes[] = 'Categories';
|
125 |
+
}
|
126 |
+
|
127 |
+
if ($isAdded == true) {
|
128 |
+
$this->setData('Added', true);
|
129 |
+
array_unshift($outputAttributes, 'Added');
|
130 |
+
}
|
131 |
+
|
132 |
+
return $this->toArray($outputAttributes);
|
133 |
+
}
|
134 |
+
|
135 |
+
private function _getHelper()
|
136 |
+
{
|
137 |
+
return Mage::helper('koan_seg');
|
138 |
+
}
|
139 |
+
}
|
app/code/community/Koan/Seg/Model/Seg/Range.php
ADDED
@@ -0,0 +1,45 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/**
|
4 |
+
* @category Koan
|
5 |
+
* @package Seg
|
6 |
+
* @author Seg <hello@getseg.com, http://getseg.com>
|
7 |
+
* @copyright Seg <http://getseg.com>
|
8 |
+
* @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
|
9 |
+
*/
|
10 |
+
class Koan_Seg_Model_Seg_Range extends Varien_Object
|
11 |
+
{
|
12 |
+
public function prepare($category)
|
13 |
+
{
|
14 |
+
if (!$category) {
|
15 |
+
Mage::throwException('Category is not valid!');
|
16 |
+
}
|
17 |
+
|
18 |
+
if (!$categoryId = $category->getId()) {
|
19 |
+
Mage::throwException('Missing Category Id');
|
20 |
+
}
|
21 |
+
|
22 |
+
$categoryData = array('Categories');
|
23 |
+
|
24 |
+
$lastCatName = $category->getName();
|
25 |
+
$lastCategoryAdjust = 1;
|
26 |
+
|
27 |
+
if ($path = $category->getPath()) {
|
28 |
+
$path = explode('/', $path);
|
29 |
+
|
30 |
+
for ($i = 2; $i < count($path) - $lastCategoryAdjust; $i++) {
|
31 |
+
|
32 |
+
$cat = Mage::getModel('catalog/category')->load($path[$i]);
|
33 |
+
if ($cat && $cat->getIsActive()) {
|
34 |
+
|
35 |
+
$categoryData['Categories'][] = $cat->getName();
|
36 |
+
}
|
37 |
+
}
|
38 |
+
|
39 |
+
$categoryData['Categories'][] = $lastCatName;
|
40 |
+
}
|
41 |
+
|
42 |
+
$this->setData($categoryData);
|
43 |
+
return $this->toArray(array('Categories'));
|
44 |
+
}
|
45 |
+
}
|
app/code/community/Koan/Seg/controllers/Adminhtml/SegController.php
ADDED
@@ -0,0 +1,123 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
class Koan_Seg_Adminhtml_SegController extends Mage_Adminhtml_Controller_Action
|
4 |
+
{
|
5 |
+
private function _checkIfCronActivated()
|
6 |
+
{
|
7 |
+
|
8 |
+
$isCronActive = Mage::helper('koan_seg')->isExportCronEnabled();
|
9 |
+
if (!$isCronActive) {
|
10 |
+
|
11 |
+
Mage::getSingleton('adminhtml/session')->addWarning($this->__('Exporter CRON operation is set to INACTIVE in config and export will not work.
|
12 |
+
Please navigate to System -> Configuration -> Koan -> Seg Options and set "Enable export CRON value to YES"'));
|
13 |
+
}
|
14 |
+
|
15 |
+
return $this;
|
16 |
+
|
17 |
+
}
|
18 |
+
|
19 |
+
public function exporterAction()
|
20 |
+
{
|
21 |
+
$this->_checkIfCronActivated();
|
22 |
+
|
23 |
+
$this->loadLayout();
|
24 |
+
$this->_setActiveMenu('seg');
|
25 |
+
$this->renderLayout();
|
26 |
+
}
|
27 |
+
|
28 |
+
public function createBatchCustomerAction()
|
29 |
+
{
|
30 |
+
$exporter = Mage::getSingleton('koan_seg/seg_exporter');
|
31 |
+
|
32 |
+
$batchCollection = Mage::getResourceModel('koan_seg/batch_status_collection');
|
33 |
+
$batchCollection->addFieldToFilter('entity_type', 'customers');
|
34 |
+
$batchCollection->addFieldToFilter('current_status',
|
35 |
+
array('nin' => array(Koan_Seg_Model_Seg_Exporter::BATCH_STATUS_COMPLETE, Koan_Seg_Model_Seg_Exporter::BATCH_STATUS_ERROR)
|
36 |
+
));
|
37 |
+
|
38 |
+
try {
|
39 |
+
|
40 |
+
$isRunning = $batchCollection->getSize();
|
41 |
+
if ($isRunning) {
|
42 |
+
Mage::throwException('Can not start new batch while one is still running. Please try again later!');
|
43 |
+
return;
|
44 |
+
}
|
45 |
+
|
46 |
+
$exporter->generateCustomersExportBatch();
|
47 |
+
$msg = Mage::helper('koan_seg')->__('New batch has been scheduled successfully. Export will start with new CRON job in several minutes.');
|
48 |
+
|
49 |
+
Mage::getSingleton('adminhtml/session')->addSuccess($msg);
|
50 |
+
} catch (Exception $e) {
|
51 |
+
Mage::getSingleton('adminhtml/session')->addError($e->getMessage());
|
52 |
+
}
|
53 |
+
|
54 |
+
$this->_redirect('adminhtml/seg/exporter');
|
55 |
+
return;
|
56 |
+
}
|
57 |
+
|
58 |
+
public function createBatchOrderAction()
|
59 |
+
{
|
60 |
+
$orderDateFilter = null;
|
61 |
+
|
62 |
+
$fromDateFiter = $this->getRequest()->getParam('order_date_from');
|
63 |
+
if ($fromDateFiter AND $fromDateFiter != 'NO_FILTER') {
|
64 |
+
$filter = @json_decode($fromDateFiter, true);
|
65 |
+
if ($filter AND is_array($filter) AND isset($filter['date'])) {
|
66 |
+
$orderDateFilter = $filter['date'];
|
67 |
+
}
|
68 |
+
}
|
69 |
+
|
70 |
+
$exporter = Mage::getSingleton('koan_seg/seg_exporter');
|
71 |
+
|
72 |
+
$batchCollection = Mage::getResourceModel('koan_seg/batch_status_collection');
|
73 |
+
$batchCollection->addFieldToFilter('entity_type', 'history_orders');
|
74 |
+
$batchCollection->addFieldToFilter('current_status',
|
75 |
+
array('nin' => array(Koan_Seg_Model_Seg_Exporter::BATCH_STATUS_COMPLETE, Koan_Seg_Model_Seg_Exporter::BATCH_STATUS_ERROR)
|
76 |
+
));
|
77 |
+
|
78 |
+
try {
|
79 |
+
|
80 |
+
$isRunning = $batchCollection->getSize();
|
81 |
+
if ($isRunning) {
|
82 |
+
Mage::throwException('Can not start new batch while one is still running. Please try again later!');
|
83 |
+
return;
|
84 |
+
}
|
85 |
+
|
86 |
+
$exporter->generateHistoryOrdersExportBatch($orderDateFilter);
|
87 |
+
$msg = Mage::helper('koan_seg')->__('New batch has been scheduled successfully. Export will start with new CRON job in several minutes.');
|
88 |
+
|
89 |
+
Mage::getSingleton('adminhtml/session')->addSuccess($msg);
|
90 |
+
} catch (Exception $e) {
|
91 |
+
Mage::getSingleton('adminhtml/session')->addError($e->getMessage());
|
92 |
+
}
|
93 |
+
|
94 |
+
$this->_redirect('adminhtml/seg/exporter');
|
95 |
+
return;
|
96 |
+
}
|
97 |
+
|
98 |
+
public function massDeleteAction()
|
99 |
+
{
|
100 |
+
$batchIds = $this->getRequest()->getParam('batch_id', null);
|
101 |
+
if (is_null($batchIds) OR !is_array($batchIds) OR count($batchIds) < 1) {
|
102 |
+
Mage::getSingleton('adminhtml/session')->addError(Mage::helper('adminhtml')->__('Please select batch(es)'));
|
103 |
+
} else {
|
104 |
+
try {
|
105 |
+
foreach ($batchIds as $batchId) {
|
106 |
+
$batch = Mage::getModel('koan_seg/batch_status')->load($batchId);
|
107 |
+
if ($batch AND $batch->getId()) {
|
108 |
+
$batch->delete();
|
109 |
+
}
|
110 |
+
}
|
111 |
+
Mage::getSingleton('adminhtml/session')->addSuccess(
|
112 |
+
Mage::helper('adminhtml')->__(
|
113 |
+
'Total of %d rows(s) were successfully deleted', count($batchIds)
|
114 |
+
)
|
115 |
+
);
|
116 |
+
} catch (Exception $e) {
|
117 |
+
Mage::getSingleton('adminhtml/session')->addError($e->getMessage());
|
118 |
+
}
|
119 |
+
}
|
120 |
+
$this->_redirect('adminhtml/seg/exporter');
|
121 |
+
}
|
122 |
+
|
123 |
+
}
|
app/code/community/Koan/Seg/controllers/IndexController.php
ADDED
@@ -0,0 +1,11 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
class Koan_Seg_IndexController extends Mage_Core_Controller_Front_Action
|
4 |
+
{
|
5 |
+
|
6 |
+
public function indexAction()
|
7 |
+
{
|
8 |
+
exit;
|
9 |
+
}
|
10 |
+
|
11 |
+
}
|
app/code/community/Koan/Seg/etc/adminhtml.xml
ADDED
@@ -0,0 +1,47 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?xml version="1.0"?>
|
2 |
+
<config>
|
3 |
+
<acl>
|
4 |
+
<resources>
|
5 |
+
<all>
|
6 |
+
<title>Allow Everything</title>
|
7 |
+
</all>
|
8 |
+
<admin>
|
9 |
+
<children>
|
10 |
+
<system>
|
11 |
+
<children>
|
12 |
+
<config>
|
13 |
+
<children>
|
14 |
+
<koan_seg translate="title">
|
15 |
+
<title>Seg</title>
|
16 |
+
<sort_order>100</sort_order>
|
17 |
+
</koan_seg>
|
18 |
+
</children>
|
19 |
+
</config>
|
20 |
+
</children>
|
21 |
+
</system>
|
22 |
+
<seg translate="title" module="koan_seg">
|
23 |
+
<children>
|
24 |
+
<exporter>
|
25 |
+
<title>Exporter</title>
|
26 |
+
</exporter>
|
27 |
+
</children>
|
28 |
+
<sort_order>1</sort_order>
|
29 |
+
</seg>
|
30 |
+
</children>
|
31 |
+
</admin>
|
32 |
+
</resources>
|
33 |
+
</acl>
|
34 |
+
<menu>
|
35 |
+
<seg module="koan_seg">
|
36 |
+
<title>Seg</title>
|
37 |
+
<sort_order>100</sort_order>
|
38 |
+
<children>
|
39 |
+
<exporter module="koan_seg">
|
40 |
+
<title>Exporter</title>
|
41 |
+
<sort_order>1</sort_order>
|
42 |
+
<action>adminhtml/seg/exporter</action>
|
43 |
+
</exporter>
|
44 |
+
</children>
|
45 |
+
</seg>
|
46 |
+
</menu>
|
47 |
+
</config>
|
app/code/community/Koan/Seg/etc/config.xml
ADDED
@@ -0,0 +1,133 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?xml version="1.0"?>
|
2 |
+
<config>
|
3 |
+
<modules>
|
4 |
+
<Koan_Seg>
|
5 |
+
<version>1.0.0.2</version>
|
6 |
+
</Koan_Seg>
|
7 |
+
</modules>
|
8 |
+
<global>
|
9 |
+
<helpers>
|
10 |
+
<koan_seg>
|
11 |
+
<class>Koan_Seg_Helper</class>
|
12 |
+
</koan_seg>
|
13 |
+
</helpers>
|
14 |
+
<models>
|
15 |
+
<koan_seg>
|
16 |
+
<class>Koan_Seg_Model</class>
|
17 |
+
<resourceModel>koan_seg_resource</resourceModel>
|
18 |
+
</koan_seg>
|
19 |
+
<koan_seg_resource>
|
20 |
+
<class>Koan_Seg_Model_Resource</class>
|
21 |
+
<entities>
|
22 |
+
<batch_status>
|
23 |
+
<table>seg_batch_status</table>
|
24 |
+
</batch_status>
|
25 |
+
</entities>
|
26 |
+
</koan_seg_resource>
|
27 |
+
</models>
|
28 |
+
<blocks>
|
29 |
+
<koan_seg>
|
30 |
+
<class>Koan_Seg_Block</class>
|
31 |
+
</koan_seg>
|
32 |
+
</blocks>
|
33 |
+
<resources>
|
34 |
+
<koan_seg_setup>
|
35 |
+
<setup>
|
36 |
+
<module>Koan_Seg</module>
|
37 |
+
</setup>
|
38 |
+
</koan_seg_setup>
|
39 |
+
</resources>
|
40 |
+
</global>
|
41 |
+
<frontend>
|
42 |
+
<routers>
|
43 |
+
<koan_seg>
|
44 |
+
<use>standard</use>
|
45 |
+
<args>
|
46 |
+
<module>Koan_Seg</module>
|
47 |
+
<frontName>seg</frontName>
|
48 |
+
</args>
|
49 |
+
</koan_seg>
|
50 |
+
</routers>
|
51 |
+
<events>
|
52 |
+
<checkout_cart_product_add_after>
|
53 |
+
<observers>
|
54 |
+
<koan_seg>
|
55 |
+
<class>koan_seg/observer</class>
|
56 |
+
<method>checkoutCartProductAddAfter</method>
|
57 |
+
</koan_seg>
|
58 |
+
</observers>
|
59 |
+
</checkout_cart_product_add_after>
|
60 |
+
<sales_quote_item_save_after>
|
61 |
+
<observers>
|
62 |
+
<koan_seg>
|
63 |
+
<class>koan_seg/observer</class>
|
64 |
+
<method>cartItemAfterSave</method>
|
65 |
+
</koan_seg>
|
66 |
+
</observers>
|
67 |
+
</sales_quote_item_save_after>
|
68 |
+
<sales_order_place_after>
|
69 |
+
<observers>
|
70 |
+
<koan_seg>
|
71 |
+
<class>koan_seg/observer</class>
|
72 |
+
<method>orderPlaceAfter</method>
|
73 |
+
</koan_seg>
|
74 |
+
</observers>
|
75 |
+
</sales_order_place_after>
|
76 |
+
</events>
|
77 |
+
<layout>
|
78 |
+
<updates>
|
79 |
+
<koan_seg>
|
80 |
+
<file>seg.xml</file>
|
81 |
+
</koan_seg>
|
82 |
+
</updates>
|
83 |
+
</layout>
|
84 |
+
</frontend>
|
85 |
+
<admin>
|
86 |
+
<routers>
|
87 |
+
<adminhtml>
|
88 |
+
<args>
|
89 |
+
<modules>
|
90 |
+
<Koan_Seg before="Mage_Adminhtml">Koan_Seg_Adminhtml</Koan_Seg>
|
91 |
+
</modules>
|
92 |
+
</args>
|
93 |
+
</adminhtml>
|
94 |
+
</routers>
|
95 |
+
</admin>
|
96 |
+
<adminhtml>
|
97 |
+
<layout>
|
98 |
+
<updates>
|
99 |
+
<integration>
|
100 |
+
<file>seg.xml</file>
|
101 |
+
</integration>
|
102 |
+
</updates>
|
103 |
+
</layout>
|
104 |
+
</adminhtml>
|
105 |
+
<crontab>
|
106 |
+
<jobs>
|
107 |
+
<seg_export>
|
108 |
+
<schedule>
|
109 |
+
<!--<cron_expr>*/5 * * * *</cron_expr>-->
|
110 |
+
<cron_expr>* * * * *</cron_expr>
|
111 |
+
</schedule>
|
112 |
+
<run>
|
113 |
+
<model>koan_seg/observer::cronprocess</model>
|
114 |
+
</run>
|
115 |
+
</seg_export>
|
116 |
+
</jobs>
|
117 |
+
</crontab>
|
118 |
+
<default>
|
119 |
+
<koan_seg>
|
120 |
+
<endpoint>
|
121 |
+
<order_history>https://tracker.segapp.com/magento/%s/order-history</order_history>
|
122 |
+
<update_customers>https://tracker.segapp.com/magento/%s/update-customers</update_customers>
|
123 |
+
<order_placed>https://tracker.segapp.com/magento/%s/order-placed</order_placed>
|
124 |
+
</endpoint>
|
125 |
+
<general>
|
126 |
+
<orders_export_batch_size>200</orders_export_batch_size>
|
127 |
+
<customers_export_batch_size>500</customers_export_batch_size>
|
128 |
+
<rollbar_report_params>0</rollbar_report_params>
|
129 |
+
<export_cron_enable>1</export_cron_enable>
|
130 |
+
</general>
|
131 |
+
</koan_seg>
|
132 |
+
</default>
|
133 |
+
</config>
|
app/code/community/Koan/Seg/etc/system.xml
ADDED
@@ -0,0 +1,104 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?xml version="1.0" encoding="UTF-8"?>
|
2 |
+
<config>
|
3 |
+
<tabs>
|
4 |
+
<koan_seg translate="label" module="koan_seg">
|
5 |
+
<label>Seg</label>
|
6 |
+
<sort_order>100</sort_order>
|
7 |
+
</koan_seg>
|
8 |
+
</tabs>
|
9 |
+
<sections>
|
10 |
+
<koan_seg translate="label" module="koan_seg">
|
11 |
+
<label>Settings</label>
|
12 |
+
<tab>koan_seg</tab>
|
13 |
+
<sort_order>1000</sort_order>
|
14 |
+
<show_in_default>1</show_in_default>
|
15 |
+
<show_in_website>0</show_in_website>
|
16 |
+
<show_in_store>0</show_in_store>
|
17 |
+
<groups>
|
18 |
+
<general translate="label" module="koan_seg">
|
19 |
+
<label>General settings</label>
|
20 |
+
<frontend_type>text</frontend_type>
|
21 |
+
<sort_order>100</sort_order>
|
22 |
+
<show_in_default>1</show_in_default>
|
23 |
+
<show_in_website>1</show_in_website>
|
24 |
+
<show_in_store>0</show_in_store>
|
25 |
+
<fields>
|
26 |
+
<seg_website_id translate="label">
|
27 |
+
<label>Seg Website Id</label>
|
28 |
+
<frontend_type>text</frontend_type>
|
29 |
+
<sort_order>100</sort_order>
|
30 |
+
<show_in_default>1</show_in_default>
|
31 |
+
<show_in_website>0</show_in_website>
|
32 |
+
<show_in_store>0</show_in_store>
|
33 |
+
<comment><![CDATA[<a href="https://www.segapp.com/signup" target="_blank">Not yet registered with Seg? Click here to create account</a>]]></comment>
|
34 |
+
</seg_website_id>
|
35 |
+
<orders_export_batch_size translate="label">
|
36 |
+
<label>Orders export batch size</label>
|
37 |
+
<frontend_type>text</frontend_type>
|
38 |
+
<sort_order>110</sort_order>
|
39 |
+
<show_in_default>1</show_in_default>
|
40 |
+
<show_in_website>0</show_in_website>
|
41 |
+
<show_in_store>0</show_in_store>
|
42 |
+
</orders_export_batch_size>
|
43 |
+
<customers_export_batch_size translate="label">
|
44 |
+
<label>Customers export batch size</label>
|
45 |
+
<frontend_type>text</frontend_type>
|
46 |
+
<sort_order>120</sort_order>
|
47 |
+
<show_in_default>1</show_in_default>
|
48 |
+
<show_in_website>0</show_in_website>
|
49 |
+
<show_in_store>0</show_in_store>
|
50 |
+
</customers_export_batch_size>
|
51 |
+
<brand_attr_code translate="label">
|
52 |
+
<label>"Brand" attribute code</label>
|
53 |
+
<frontend_type>text</frontend_type>
|
54 |
+
<sort_order>130</sort_order>
|
55 |
+
<show_in_default>1</show_in_default>
|
56 |
+
<show_in_website>0</show_in_website>
|
57 |
+
<show_in_store>0</show_in_store>
|
58 |
+
<comment>Code of attribute which represents product brand</comment>
|
59 |
+
</brand_attr_code>
|
60 |
+
<rollbar_report_params translate="label">
|
61 |
+
<label>Enable diagnostics logging</label>
|
62 |
+
<frontend_type>select</frontend_type>
|
63 |
+
<source_model>adminhtml/system_config_source_yesno</source_model>
|
64 |
+
<sort_order>140</sort_order>
|
65 |
+
<show_in_default>1</show_in_default>
|
66 |
+
<show_in_website>0</show_in_website>
|
67 |
+
<show_in_store>0</show_in_store>
|
68 |
+
<comment>Only enable if instructed to do so by the Seg team.</comment>
|
69 |
+
</rollbar_report_params>
|
70 |
+
<export_cron_enable>
|
71 |
+
<label>Enable export CRON</label>
|
72 |
+
<frontend_type>select</frontend_type>
|
73 |
+
<source_model>adminhtml/system_config_source_yesno</source_model>
|
74 |
+
<sort_order>150</sort_order>
|
75 |
+
<show_in_default>1</show_in_default>
|
76 |
+
<show_in_website>0</show_in_website>
|
77 |
+
<show_in_store>0</show_in_store>
|
78 |
+
<comment>This CRON is needed for exporter. Disable this option after successful export of Customers and History orders.</comment>
|
79 |
+
</export_cron_enable>
|
80 |
+
</fields>
|
81 |
+
</general>
|
82 |
+
<advanced>
|
83 |
+
<label>Advanced settings</label>
|
84 |
+
<frontend_type>text</frontend_type>
|
85 |
+
<sort_order>150</sort_order>
|
86 |
+
<show_in_default>1</show_in_default>
|
87 |
+
<show_in_website>0</show_in_website>
|
88 |
+
<show_in_store>0</show_in_store>
|
89 |
+
<fields>
|
90 |
+
<php_memory_limit>
|
91 |
+
<label>Exporter PHP Memory limit override</label>
|
92 |
+
<frontend_type>text</frontend_type>
|
93 |
+
<sort_order>160</sort_order>
|
94 |
+
<show_in_default>1</show_in_default>
|
95 |
+
<show_in_website>0</show_in_website>
|
96 |
+
<show_in_store>0</show_in_store>
|
97 |
+
<comment>This is advanced value. Please do not change unless don't know what are you doing! Leave empty or 0 to turn Off</comment>
|
98 |
+
</php_memory_limit>
|
99 |
+
</fields>
|
100 |
+
</advanced>
|
101 |
+
</groups>
|
102 |
+
</koan_seg>
|
103 |
+
</sections>
|
104 |
+
</config>
|
app/code/community/Koan/Seg/lib/Rollbar.php
ADDED
@@ -0,0 +1,986 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* Singleton-style wrapper around RollbarNotifier
|
4 |
+
*
|
5 |
+
* Unless you need multiple RollbarNotifier instances in the same project, use this.
|
6 |
+
*/
|
7 |
+
class Rollbar {
|
8 |
+
/** @var RollbarNotifier */
|
9 |
+
public static $instance = null;
|
10 |
+
|
11 |
+
public static function init($config = array(), $set_exception_handler = true, $set_error_handler = true, $report_fatal_errors = true) {
|
12 |
+
// Heroku support
|
13 |
+
// Use env vars for configuration, if set
|
14 |
+
if (isset($_ENV['ROLLBAR_ACCESS_TOKEN']) && !isset($config['access_token'])) {
|
15 |
+
$config['access_token'] = $_ENV['ROLLBAR_ACCESS_TOKEN'];
|
16 |
+
}
|
17 |
+
if (isset($_ENV['ROLLBAR_ENDPOINT']) && !isset($config['endpoint'])) {
|
18 |
+
$config['endpoint'] = $_ENV['ROLLBAR_ENDPOINT'];
|
19 |
+
}
|
20 |
+
if (isset($_ENV['HEROKU_APP_DIR']) && !isset($config['root'])) {
|
21 |
+
$config['root'] = $_ENV['HEROKU_APP_DIR'];
|
22 |
+
}
|
23 |
+
|
24 |
+
self::$instance = new RollbarNotifier($config);
|
25 |
+
|
26 |
+
if ($set_exception_handler) {
|
27 |
+
set_exception_handler('Rollbar::report_exception');
|
28 |
+
}
|
29 |
+
if ($set_error_handler) {
|
30 |
+
set_error_handler('Rollbar::report_php_error');
|
31 |
+
}
|
32 |
+
if ($report_fatal_errors) {
|
33 |
+
register_shutdown_function('Rollbar::report_fatal_error');
|
34 |
+
}
|
35 |
+
|
36 |
+
if (self::$instance->batched) {
|
37 |
+
register_shutdown_function('Rollbar::flush');
|
38 |
+
}
|
39 |
+
}
|
40 |
+
|
41 |
+
public static function report_exception($exc, $extra_data = null, $payload_data = null) {
|
42 |
+
if (self::$instance == null) {
|
43 |
+
return;
|
44 |
+
}
|
45 |
+
return self::$instance->report_exception($exc, $extra_data, $payload_data);
|
46 |
+
}
|
47 |
+
|
48 |
+
public static function report_message($message, $level = 'error', $extra_data = null, $payload_data = null) {
|
49 |
+
if (self::$instance == null) {
|
50 |
+
return;
|
51 |
+
}
|
52 |
+
return self::$instance->report_message($message, $level, $extra_data, $payload_data);
|
53 |
+
}
|
54 |
+
|
55 |
+
public static function report_fatal_error() {
|
56 |
+
// Catch any fatal errors that are causing the shutdown
|
57 |
+
$last_error = error_get_last();
|
58 |
+
if (!is_null($last_error)) {
|
59 |
+
switch ($last_error['type']) {
|
60 |
+
case E_PARSE:
|
61 |
+
case E_ERROR:
|
62 |
+
self::$instance->report_php_error($last_error['type'], $last_error['message'], $last_error['file'], $last_error['line']);
|
63 |
+
break;
|
64 |
+
}
|
65 |
+
}
|
66 |
+
}
|
67 |
+
|
68 |
+
// This function must return false so that the default php error handler runs
|
69 |
+
public static function report_php_error($errno, $errstr, $errfile, $errline) {
|
70 |
+
if (self::$instance != null) {
|
71 |
+
self::$instance->report_php_error($errno, $errstr, $errfile, $errline);
|
72 |
+
}
|
73 |
+
return false;
|
74 |
+
}
|
75 |
+
|
76 |
+
public static function flush() {
|
77 |
+
self::$instance->flush();
|
78 |
+
}
|
79 |
+
}
|
80 |
+
|
81 |
+
// Send errors that have these levels
|
82 |
+
if (!defined('ROLLBAR_INCLUDED_ERRNO_BITMASK')) {
|
83 |
+
define('ROLLBAR_INCLUDED_ERRNO_BITMASK', E_ERROR | E_WARNING | E_PARSE | E_CORE_ERROR | E_USER_ERROR | E_RECOVERABLE_ERROR);
|
84 |
+
}
|
85 |
+
|
86 |
+
class RollbarNotifier {
|
87 |
+
const VERSION = "0.14.0";
|
88 |
+
|
89 |
+
// required
|
90 |
+
public $access_token = '';
|
91 |
+
|
92 |
+
// optional / defaults
|
93 |
+
public $base_api_url = 'https://api.rollbar.com/api/1/';
|
94 |
+
public $batch_size = 50;
|
95 |
+
public $batched = true;
|
96 |
+
public $branch = null;
|
97 |
+
public $capture_error_backtraces = true;
|
98 |
+
public $code_version = null;
|
99 |
+
public $environment = 'production';
|
100 |
+
public $error_sample_rates = array();
|
101 |
+
// available handlers: blocking, agent
|
102 |
+
public $handler = 'blocking';
|
103 |
+
public $agent_log_location = '/var/tmp';
|
104 |
+
public $host = null;
|
105 |
+
/** @var iRollbarLogger */
|
106 |
+
public $logger = null;
|
107 |
+
public $included_errno = ROLLBAR_INCLUDED_ERRNO_BITMASK;
|
108 |
+
public $person = null;
|
109 |
+
public $person_fn = null;
|
110 |
+
public $root = '';
|
111 |
+
public $scrub_fields = array('passwd', 'pass', 'password', 'secret', 'confirm_password',
|
112 |
+
'password_confirmation', 'auth_token', 'csrf_token');
|
113 |
+
public $shift_function = true;
|
114 |
+
public $timeout = 3;
|
115 |
+
public $report_suppressed = false;
|
116 |
+
public $use_error_reporting = false;
|
117 |
+
public $proxy = null;
|
118 |
+
|
119 |
+
private $config_keys = array('access_token', 'base_api_url', 'batch_size', 'batched', 'branch',
|
120 |
+
'capture_error_backtraces', 'code_version', 'environment', 'error_sample_rates', 'handler',
|
121 |
+
'agent_log_location', 'host', 'logger', 'included_errno', 'person', 'person_fn', 'root',
|
122 |
+
'scrub_fields', 'shift_function', 'timeout', 'report_suppressed', 'use_error_reporting', 'proxy');
|
123 |
+
|
124 |
+
// cached values for request/server/person data
|
125 |
+
private $_request_data = null;
|
126 |
+
private $_server_data = null;
|
127 |
+
private $_person_data = null;
|
128 |
+
|
129 |
+
// payload queue, used when $batched is true
|
130 |
+
private $_queue = array();
|
131 |
+
|
132 |
+
// file handle for agent log
|
133 |
+
private $_agent_log = null;
|
134 |
+
|
135 |
+
private $_iconv_available = null;
|
136 |
+
|
137 |
+
private $_mt_randmax;
|
138 |
+
|
139 |
+
private $_curl_ipresolve_supported;
|
140 |
+
|
141 |
+
public function __construct($config) {
|
142 |
+
foreach ($this->config_keys as $key) {
|
143 |
+
if (isset($config[$key])) {
|
144 |
+
$this->$key = $config[$key];
|
145 |
+
}
|
146 |
+
}
|
147 |
+
|
148 |
+
if (!$this->access_token && $this->handler != 'agent') {
|
149 |
+
$this->log_error('Missing access token');
|
150 |
+
}
|
151 |
+
|
152 |
+
// fill in missing values in error_sample_rates
|
153 |
+
$levels = array(E_WARNING, E_NOTICE, E_USER_ERROR, E_USER_WARNING,
|
154 |
+
E_USER_NOTICE, E_STRICT, E_RECOVERABLE_ERROR);
|
155 |
+
|
156 |
+
// PHP 5.3.0
|
157 |
+
if (defined('E_DEPRECATED')) {
|
158 |
+
$levels = array_merge($levels, array(E_DEPRECATED, E_USER_DEPRECATED));
|
159 |
+
}
|
160 |
+
|
161 |
+
// PHP 5.3.0
|
162 |
+
$this->_curl_ipresolve_supported = defined('CURLOPT_IPRESOLVE');
|
163 |
+
|
164 |
+
$curr = 1;
|
165 |
+
for ($i = 0, $num = count($levels); $i < $num; $i++) {
|
166 |
+
$level = $levels[$i];
|
167 |
+
if (isset($this->error_sample_rates[$level])) {
|
168 |
+
$curr = $this->error_sample_rates[$level];
|
169 |
+
} else {
|
170 |
+
$this->error_sample_rates[$level] = $curr;
|
171 |
+
}
|
172 |
+
}
|
173 |
+
|
174 |
+
// cache this value
|
175 |
+
$this->_mt_randmax = mt_getrandmax();
|
176 |
+
}
|
177 |
+
|
178 |
+
public function report_exception($exc, $extra_data = null, $payload_data = null) {
|
179 |
+
try {
|
180 |
+
if (!$exc instanceof Exception) {
|
181 |
+
throw new Exception('Report exception requires an instance of Exception.');
|
182 |
+
}
|
183 |
+
|
184 |
+
return $this->_report_exception($exc, $extra_data, $payload_data);
|
185 |
+
} catch (Exception $e) {
|
186 |
+
try {
|
187 |
+
$this->log_error("Exception while reporting exception");
|
188 |
+
} catch (Exception $e) {
|
189 |
+
// swallow
|
190 |
+
}
|
191 |
+
}
|
192 |
+
}
|
193 |
+
|
194 |
+
public function report_message($message, $level = 'error', $extra_data = null, $payload_data = null) {
|
195 |
+
try {
|
196 |
+
return $this->_report_message($message, $level, $extra_data, $payload_data);
|
197 |
+
} catch (Exception $e) {
|
198 |
+
try {
|
199 |
+
$this->log_error("Exception while reporting message");
|
200 |
+
} catch (Exception $e) {
|
201 |
+
// swallow
|
202 |
+
}
|
203 |
+
}
|
204 |
+
}
|
205 |
+
|
206 |
+
public function report_php_error($errno, $errstr, $errfile, $errline) {
|
207 |
+
try {
|
208 |
+
return $this->_report_php_error($errno, $errstr, $errfile, $errline);
|
209 |
+
} catch (Exception $e) {
|
210 |
+
try {
|
211 |
+
$this->log_error("Exception while reporting php error");
|
212 |
+
} catch (Exception $e) {
|
213 |
+
// swallow
|
214 |
+
}
|
215 |
+
}
|
216 |
+
}
|
217 |
+
|
218 |
+
/**
|
219 |
+
* Flushes the queue.
|
220 |
+
* Called internally when the queue exceeds $batch_size, and by Rollbar::flush
|
221 |
+
* on shutdown.
|
222 |
+
*/
|
223 |
+
public function flush() {
|
224 |
+
$queue_size = $this->queueSize();
|
225 |
+
if ($queue_size > 0) {
|
226 |
+
$this->log_info('Flushing queue of size ' . $queue_size);
|
227 |
+
$this->send_batch($this->_queue);
|
228 |
+
$this->_queue = array();
|
229 |
+
}
|
230 |
+
}
|
231 |
+
|
232 |
+
/**
|
233 |
+
* Returns the current queue size.
|
234 |
+
*/
|
235 |
+
public function queueSize() {
|
236 |
+
return count($this->_queue);
|
237 |
+
}
|
238 |
+
|
239 |
+
/**
|
240 |
+
* @param Exception $exc
|
241 |
+
*/
|
242 |
+
protected function _report_exception(Exception $exc, $extra_data = null, $payload_data = null) {
|
243 |
+
if (!$this->check_config()) {
|
244 |
+
return;
|
245 |
+
}
|
246 |
+
|
247 |
+
if (error_reporting() === 0 && !$this->report_suppressed) {
|
248 |
+
// ignore
|
249 |
+
return;
|
250 |
+
}
|
251 |
+
|
252 |
+
$data = $this->build_base_data();
|
253 |
+
|
254 |
+
$trace_chain = $this->build_exception_trace_chain($exc, $extra_data);
|
255 |
+
|
256 |
+
if (count($trace_chain) > 1) {
|
257 |
+
$data['body']['trace_chain'] = $trace_chain;
|
258 |
+
} else {
|
259 |
+
$data['body']['trace'] = $trace_chain[0];
|
260 |
+
}
|
261 |
+
|
262 |
+
// request, server, person data
|
263 |
+
$data['request'] = $this->build_request_data();
|
264 |
+
$data['server'] = $this->build_server_data();
|
265 |
+
$data['person'] = $this->build_person_data();
|
266 |
+
|
267 |
+
// merge $payload_data into $data
|
268 |
+
// (overriding anything already present)
|
269 |
+
if ($payload_data !== null && is_array($payload_data)) {
|
270 |
+
foreach ($payload_data as $key => $val) {
|
271 |
+
$data[$key] = $val;
|
272 |
+
}
|
273 |
+
}
|
274 |
+
|
275 |
+
$data = $this->_sanitize_keys($data);
|
276 |
+
array_walk_recursive($data, array($this, '_sanitize_utf8'));
|
277 |
+
|
278 |
+
$payload = $this->build_payload($data);
|
279 |
+
$this->send_payload($payload);
|
280 |
+
|
281 |
+
return $data['uuid'];
|
282 |
+
}
|
283 |
+
|
284 |
+
protected function _sanitize_utf8(&$value) {
|
285 |
+
if (!isset($this->_iconv_available)) {
|
286 |
+
$this->_iconv_available = function_exists('iconv');
|
287 |
+
}
|
288 |
+
if (is_string($value) && $this->_iconv_available) {
|
289 |
+
$value = @iconv('UTF-8', 'UTF-8//IGNORE', $value);
|
290 |
+
}
|
291 |
+
}
|
292 |
+
|
293 |
+
protected function _sanitize_keys(array $data) {
|
294 |
+
$response = array();
|
295 |
+
foreach ($data as $key => $value) {
|
296 |
+
$this->_sanitize_utf8($key);
|
297 |
+
if (is_array($value)) {
|
298 |
+
$response[$key] = $this->_sanitize_keys($value);
|
299 |
+
} else {
|
300 |
+
$response[$key] = $value;
|
301 |
+
}
|
302 |
+
}
|
303 |
+
|
304 |
+
return $response;
|
305 |
+
}
|
306 |
+
|
307 |
+
protected function _report_php_error($errno, $errstr, $errfile, $errline) {
|
308 |
+
if (!$this->check_config()) {
|
309 |
+
return;
|
310 |
+
}
|
311 |
+
|
312 |
+
if (error_reporting() === 0 && !$this->report_suppressed) {
|
313 |
+
// ignore
|
314 |
+
return;
|
315 |
+
}
|
316 |
+
|
317 |
+
if ($this->use_error_reporting && (error_reporting() & $errno) === 0) {
|
318 |
+
// ignore
|
319 |
+
return;
|
320 |
+
}
|
321 |
+
|
322 |
+
if ($this->included_errno != -1 && ($errno & $this->included_errno) != $errno) {
|
323 |
+
// ignore
|
324 |
+
return;
|
325 |
+
}
|
326 |
+
|
327 |
+
if (isset($this->error_sample_rates[$errno])) {
|
328 |
+
// get a float in the range [0, 1)
|
329 |
+
// mt_rand() is inclusive, so add 1 to mt_randmax
|
330 |
+
$float_rand = mt_rand() / ($this->_mt_randmax + 1);
|
331 |
+
if ($float_rand > $this->error_sample_rates[$errno]) {
|
332 |
+
// skip
|
333 |
+
return;
|
334 |
+
}
|
335 |
+
}
|
336 |
+
|
337 |
+
$data = $this->build_base_data();
|
338 |
+
|
339 |
+
// set error level and error constant name
|
340 |
+
$level = 'info';
|
341 |
+
$constant = '#' . $errno;
|
342 |
+
switch ($errno) {
|
343 |
+
case 1:
|
344 |
+
$level = 'error';
|
345 |
+
$constant = 'E_ERROR';
|
346 |
+
break;
|
347 |
+
case 2:
|
348 |
+
$level = 'warning';
|
349 |
+
$constant = 'E_WARNING';
|
350 |
+
break;
|
351 |
+
case 8:
|
352 |
+
$level = 'info';
|
353 |
+
$constant = 'E_NOTICE';
|
354 |
+
break;
|
355 |
+
case 256:
|
356 |
+
$level = 'error';
|
357 |
+
$constant = 'E_USER_ERROR';
|
358 |
+
break;
|
359 |
+
case 512:
|
360 |
+
$level = 'warning';
|
361 |
+
$constant = 'E_USER_WARNING';
|
362 |
+
break;
|
363 |
+
case 1024:
|
364 |
+
$level = 'info';
|
365 |
+
$constant = 'E_USER_NOTICE';
|
366 |
+
break;
|
367 |
+
case 2048:
|
368 |
+
$level = 'info';
|
369 |
+
$constant = 'E_STRICT';
|
370 |
+
break;
|
371 |
+
case 4096:
|
372 |
+
$level = 'error';
|
373 |
+
$constant = 'E_RECOVERABLE_ERROR';
|
374 |
+
break;
|
375 |
+
case 8192:
|
376 |
+
$level = 'info';
|
377 |
+
$constant = 'E_DEPRECATED';
|
378 |
+
break;
|
379 |
+
case 16384:
|
380 |
+
$level = 'info';
|
381 |
+
$constant = 'E_USER_DEPRECATED';
|
382 |
+
break;
|
383 |
+
}
|
384 |
+
$data['level'] = $level;
|
385 |
+
|
386 |
+
// use the whole $errstr. may want to split this by colon for better de-duping.
|
387 |
+
$error_class = $constant . ': ' . $errstr;
|
388 |
+
|
389 |
+
// build something that looks like an exception
|
390 |
+
$data['body'] = array(
|
391 |
+
'trace' => array(
|
392 |
+
'frames' => $this->build_error_frames($errfile, $errline),
|
393 |
+
'exception' => array(
|
394 |
+
'class' => $error_class
|
395 |
+
)
|
396 |
+
)
|
397 |
+
);
|
398 |
+
|
399 |
+
// request, server, person data
|
400 |
+
$data['request'] = $this->build_request_data();
|
401 |
+
$data['server'] = $this->build_server_data();
|
402 |
+
$data['person'] = $this->build_person_data();
|
403 |
+
|
404 |
+
array_walk_recursive($data, array($this, '_sanitize_utf8'));
|
405 |
+
|
406 |
+
$payload = $this->build_payload($data);
|
407 |
+
$this->send_payload($payload);
|
408 |
+
|
409 |
+
return $data['uuid'];
|
410 |
+
}
|
411 |
+
|
412 |
+
protected function _report_message($message, $level, $extra_data, $payload_data) {
|
413 |
+
if (!$this->check_config()) {
|
414 |
+
return;
|
415 |
+
}
|
416 |
+
|
417 |
+
$data = $this->build_base_data();
|
418 |
+
$data['level'] = strtolower($level);
|
419 |
+
|
420 |
+
$message_obj = array('body' => $message);
|
421 |
+
if ($extra_data !== null && is_array($extra_data)) {
|
422 |
+
// merge keys from $extra_data to $message_obj
|
423 |
+
foreach ($extra_data as $key => $val) {
|
424 |
+
if ($key == 'body') {
|
425 |
+
// rename to 'body_' to avoid clobbering
|
426 |
+
$key = 'body_';
|
427 |
+
}
|
428 |
+
$message_obj[$key] = $val;
|
429 |
+
}
|
430 |
+
}
|
431 |
+
$data['body']['message'] = $message_obj;
|
432 |
+
|
433 |
+
$data['request'] = $this->build_request_data();
|
434 |
+
$data['server'] = $this->build_server_data();
|
435 |
+
$data['person'] = $this->build_person_data();
|
436 |
+
|
437 |
+
// merge $payload_data into $data
|
438 |
+
// (overriding anything already present)
|
439 |
+
if ($payload_data !== null && is_array($payload_data)) {
|
440 |
+
foreach ($payload_data as $key => $val) {
|
441 |
+
$data[$key] = $val;
|
442 |
+
}
|
443 |
+
}
|
444 |
+
|
445 |
+
array_walk_recursive($data, array($this, '_sanitize_utf8'));
|
446 |
+
|
447 |
+
$payload = $this->build_payload($data);
|
448 |
+
$this->send_payload($payload);
|
449 |
+
|
450 |
+
return $data['uuid'];
|
451 |
+
}
|
452 |
+
|
453 |
+
protected function check_config() {
|
454 |
+
return $this->handler == 'agent' || ($this->access_token && strlen($this->access_token) == 32);
|
455 |
+
}
|
456 |
+
|
457 |
+
protected function build_request_data() {
|
458 |
+
if ($this->_request_data === null) {
|
459 |
+
$request = array(
|
460 |
+
'url' => $this->scrub_url($this->current_url()),
|
461 |
+
'user_ip' => $this->user_ip(),
|
462 |
+
'headers' => $this->headers(),
|
463 |
+
'method' => isset($_SERVER['REQUEST_METHOD']) ? $_SERVER['REQUEST_METHOD'] : null,
|
464 |
+
);
|
465 |
+
|
466 |
+
if ($_GET) {
|
467 |
+
$request['GET'] = $this->scrub_request_params($_GET);
|
468 |
+
}
|
469 |
+
if ($_POST) {
|
470 |
+
$request['POST'] = $this->scrub_request_params($_POST);
|
471 |
+
}
|
472 |
+
if (isset($_SESSION) && $_SESSION) {
|
473 |
+
$request['session'] = $this->scrub_request_params($_SESSION);
|
474 |
+
}
|
475 |
+
$this->_request_data = $request;
|
476 |
+
}
|
477 |
+
|
478 |
+
return $this->_request_data;
|
479 |
+
}
|
480 |
+
|
481 |
+
protected function scrub_url($url) {
|
482 |
+
$url_query = parse_url($url, PHP_URL_QUERY);
|
483 |
+
if (!$url_query) return $url;
|
484 |
+
parse_str($url_query, $parsed_output);
|
485 |
+
// using x since * requires URL-encoding
|
486 |
+
$scrubbed_params = $this->scrub_request_params($parsed_output, 'x');
|
487 |
+
$scrubbed_url = str_replace($url_query, http_build_query($scrubbed_params), $url);
|
488 |
+
return $scrubbed_url;
|
489 |
+
}
|
490 |
+
|
491 |
+
protected function scrub_request_params($params, $replacement = '*') {
|
492 |
+
$scrubbed = array();
|
493 |
+
$potential_regex_filters = array_filter($this->scrub_fields, function($field) {
|
494 |
+
return strpos($field, '/') === 0;
|
495 |
+
});
|
496 |
+
foreach ($params as $k => $v) {
|
497 |
+
if ($this->_key_should_be_scrubbed($k, $potential_regex_filters)) {
|
498 |
+
$scrubbed[$k] = $this->_scrub($v, $replacement);
|
499 |
+
} elseif (is_array($v)) {
|
500 |
+
// recursively handle array params
|
501 |
+
$scrubbed[$k] = $this->scrub_request_params($v, $replacement);
|
502 |
+
} else {
|
503 |
+
$scrubbed[$k] = $v;
|
504 |
+
}
|
505 |
+
}
|
506 |
+
|
507 |
+
return $scrubbed;
|
508 |
+
}
|
509 |
+
|
510 |
+
protected function _key_should_be_scrubbed($key, $potential_regex_filters) {
|
511 |
+
if (in_array($key, $this->scrub_fields)) return true;
|
512 |
+
foreach ($potential_regex_filters as $potential_regex) {
|
513 |
+
if (@preg_match($potential_regex, $key)) return true;
|
514 |
+
}
|
515 |
+
return false;
|
516 |
+
}
|
517 |
+
|
518 |
+
protected function _scrub($value, $replacement = '*') {
|
519 |
+
$count = is_array($value) ? count($value) : strlen($value);
|
520 |
+
return str_repeat($replacement, $count);
|
521 |
+
}
|
522 |
+
|
523 |
+
protected function headers() {
|
524 |
+
$headers = array();
|
525 |
+
foreach ($this->scrub_request_params($_SERVER) as $key => $val) {
|
526 |
+
if (substr($key, 0, 5) == 'HTTP_') {
|
527 |
+
// convert HTTP_CONTENT_TYPE to Content-Type, HTTP_HOST to Host, etc.
|
528 |
+
$name = strtolower(substr($key, 5));
|
529 |
+
if (strpos($name, '_') != -1) {
|
530 |
+
$name = preg_replace('/ /', '-', ucwords(preg_replace('/_/', ' ', $name)));
|
531 |
+
} else {
|
532 |
+
$name = ucfirst($name);
|
533 |
+
}
|
534 |
+
$headers[$name] = $val;
|
535 |
+
}
|
536 |
+
}
|
537 |
+
|
538 |
+
if (count($headers) > 0) {
|
539 |
+
return $headers;
|
540 |
+
} else {
|
541 |
+
// serializes to emtpy json object
|
542 |
+
return new stdClass;
|
543 |
+
}
|
544 |
+
}
|
545 |
+
|
546 |
+
protected function current_url() {
|
547 |
+
if (!empty($_SERVER['HTTP_X_FORWARDED_PROTO'])) {
|
548 |
+
$proto = strtolower($_SERVER['HTTP_X_FORWARDED_PROTO']);
|
549 |
+
} else if (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == 'on') {
|
550 |
+
$proto = 'https';
|
551 |
+
} else {
|
552 |
+
$proto = 'http';
|
553 |
+
}
|
554 |
+
|
555 |
+
if (!empty($_SERVER['HTTP_X_FORWARDED_HOST'])) {
|
556 |
+
$host = $_SERVER['HTTP_X_FORWARDED_HOST'];
|
557 |
+
} else if (!empty($_SERVER['HTTP_HOST'])) {
|
558 |
+
$parts = explode(':', $_SERVER['HTTP_HOST']);
|
559 |
+
$host = $parts[0];
|
560 |
+
} else if (!empty($_SERVER['SERVER_NAME'])) {
|
561 |
+
$host = $_SERVER['SERVER_NAME'];
|
562 |
+
} else {
|
563 |
+
$host = 'unknown';
|
564 |
+
}
|
565 |
+
|
566 |
+
if (!empty($_SERVER['HTTP_X_FORWARDED_PORT'])) {
|
567 |
+
$port = $_SERVER['HTTP_X_FORWARDED_PORT'];
|
568 |
+
} else if (!empty($_SERVER['SERVER_PORT'])) {
|
569 |
+
$port = $_SERVER['SERVER_PORT'];
|
570 |
+
} else {
|
571 |
+
$port = 80;
|
572 |
+
}
|
573 |
+
|
574 |
+
$path = isset($_SERVER['REQUEST_URI']) ? $_SERVER['REQUEST_URI'] : '/';
|
575 |
+
|
576 |
+
$url = $proto . '://' . $host;
|
577 |
+
|
578 |
+
if (($proto == 'https' && $port != 443) || ($proto == 'http' && $port != 80)) {
|
579 |
+
$url .= ':' . $port;
|
580 |
+
}
|
581 |
+
|
582 |
+
$url .= $path;
|
583 |
+
|
584 |
+
return $url;
|
585 |
+
}
|
586 |
+
|
587 |
+
protected function user_ip() {
|
588 |
+
$forwardfor = isset($_SERVER['HTTP_X_FORWARDED_FOR']) ? $_SERVER['HTTP_X_FORWARDED_FOR'] : null;
|
589 |
+
if ($forwardfor) {
|
590 |
+
// return everything until the first comma
|
591 |
+
$parts = explode(',', $forwardfor);
|
592 |
+
return $parts[0];
|
593 |
+
}
|
594 |
+
$realip = isset($_SERVER['HTTP_X_REAL_IP']) ? $_SERVER['HTTP_X_REAL_IP'] : null;
|
595 |
+
if ($realip) {
|
596 |
+
return $realip;
|
597 |
+
}
|
598 |
+
return isset($_SERVER['REMOTE_ADDR']) ? $_SERVER['REMOTE_ADDR'] : null;
|
599 |
+
}
|
600 |
+
|
601 |
+
/**
|
602 |
+
* @param Exception $exc
|
603 |
+
* @param mixed $extra_data
|
604 |
+
* @return array
|
605 |
+
*/
|
606 |
+
protected function build_exception_trace(Exception $exc, $extra_data = null)
|
607 |
+
{
|
608 |
+
$message = $exc->getMessage();
|
609 |
+
|
610 |
+
$trace = array(
|
611 |
+
'frames' => $this->build_exception_frames($exc),
|
612 |
+
'exception' => array(
|
613 |
+
'class' => get_class($exc),
|
614 |
+
'message' => !empty($message) ? $message : 'unknown',
|
615 |
+
),
|
616 |
+
);
|
617 |
+
|
618 |
+
if ($extra_data !== null) {
|
619 |
+
$trace['extra'] = $extra_data;
|
620 |
+
}
|
621 |
+
|
622 |
+
return $trace;
|
623 |
+
}
|
624 |
+
|
625 |
+
/**
|
626 |
+
* @param Exception $exc
|
627 |
+
* @param array $extra_data
|
628 |
+
* @return array
|
629 |
+
*/
|
630 |
+
protected function build_exception_trace_chain(Exception $exc, $extra_data = null)
|
631 |
+
{
|
632 |
+
$chain = array();
|
633 |
+
$chain[] = $this->build_exception_trace($exc, $extra_data);
|
634 |
+
|
635 |
+
$previous = $exc->getPrevious();
|
636 |
+
|
637 |
+
while ($previous instanceof Exception) {
|
638 |
+
$chain[] = $this->build_exception_trace($previous);
|
639 |
+
$previous = $previous->getPrevious();
|
640 |
+
}
|
641 |
+
|
642 |
+
return $chain;
|
643 |
+
}
|
644 |
+
|
645 |
+
/**
|
646 |
+
* @param Exception $exc
|
647 |
+
* @return array
|
648 |
+
*/
|
649 |
+
protected function build_exception_frames(Exception $exc) {
|
650 |
+
$frames = array();
|
651 |
+
|
652 |
+
foreach ($exc->getTrace() as $frame) {
|
653 |
+
$frames[] = array(
|
654 |
+
'filename' => isset($frame['file']) ? $frame['file'] : '<internal>',
|
655 |
+
'lineno' => isset($frame['line']) ? $frame['line'] : 0,
|
656 |
+
'method' => $frame['function']
|
657 |
+
// TODO include args? need to sanitize first.
|
658 |
+
);
|
659 |
+
}
|
660 |
+
|
661 |
+
// rollbar expects most recent call to be last, not first
|
662 |
+
$frames = array_reverse($frames);
|
663 |
+
|
664 |
+
// add top-level file and line to end of the reversed array
|
665 |
+
$frames[] = array(
|
666 |
+
'filename' => $exc->getFile(),
|
667 |
+
'lineno' => $exc->getLine()
|
668 |
+
);
|
669 |
+
|
670 |
+
$this->shift_method($frames);
|
671 |
+
|
672 |
+
return $frames;
|
673 |
+
}
|
674 |
+
|
675 |
+
protected function shift_method(&$frames) {
|
676 |
+
if ($this->shift_function) {
|
677 |
+
// shift 'method' values down one frame, so they reflect where the call
|
678 |
+
// occurs (like Rollbar expects), instead of what is being called.
|
679 |
+
for ($i = count($frames) - 1; $i > 0; $i--) {
|
680 |
+
$frames[$i]['method'] = $frames[$i - 1]['method'];
|
681 |
+
}
|
682 |
+
$frames[0]['method'] = '<main>';
|
683 |
+
}
|
684 |
+
}
|
685 |
+
|
686 |
+
protected function build_error_frames($errfile, $errline) {
|
687 |
+
if ($this->capture_error_backtraces) {
|
688 |
+
$frames = array();
|
689 |
+
$backtrace = debug_backtrace();
|
690 |
+
foreach ($backtrace as $frame) {
|
691 |
+
// skip frames in this file
|
692 |
+
if (isset($frame['file']) && $frame['file'] == __FILE__) {
|
693 |
+
continue;
|
694 |
+
}
|
695 |
+
// skip the confusing set_error_handler frame
|
696 |
+
if ($frame['function'] == 'report_php_error' && count($frames) == 0) {
|
697 |
+
continue;
|
698 |
+
}
|
699 |
+
|
700 |
+
$frames[] = array(
|
701 |
+
// Sometimes, file and line are not set. See:
|
702 |
+
// http://stackoverflow.com/questions/4581969/why-is-debug-backtrace-not-including-line-number-sometimes
|
703 |
+
'filename' => isset($frame['file']) ? $frame['file'] : "<internal>",
|
704 |
+
'lineno' => isset($frame['line']) ? $frame['line'] : 0,
|
705 |
+
'method' => $frame['function']
|
706 |
+
);
|
707 |
+
}
|
708 |
+
|
709 |
+
// rollbar expects most recent call last, not first
|
710 |
+
$frames = array_reverse($frames);
|
711 |
+
|
712 |
+
// add top-level file and line to end of the reversed array
|
713 |
+
$frames[] = array(
|
714 |
+
'filename' => $errfile,
|
715 |
+
'lineno' => $errline
|
716 |
+
);
|
717 |
+
|
718 |
+
$this->shift_method($frames);
|
719 |
+
|
720 |
+
return $frames;
|
721 |
+
} else {
|
722 |
+
return array(
|
723 |
+
array(
|
724 |
+
'filename' => $errfile,
|
725 |
+
'lineno' => $errline
|
726 |
+
)
|
727 |
+
);
|
728 |
+
}
|
729 |
+
}
|
730 |
+
|
731 |
+
protected function build_server_data() {
|
732 |
+
if ($this->_server_data === null) {
|
733 |
+
$server_data = array();
|
734 |
+
|
735 |
+
if ($this->host === null) {
|
736 |
+
// PHP 5.3.0
|
737 |
+
if (function_exists('gethostname')) {
|
738 |
+
$this->host = gethostname();
|
739 |
+
} else {
|
740 |
+
$this->host = php_uname('n');
|
741 |
+
}
|
742 |
+
}
|
743 |
+
$server_data['host'] = $this->host;
|
744 |
+
|
745 |
+
if ($this->branch) {
|
746 |
+
$server_data['branch'] = $this->branch;
|
747 |
+
}
|
748 |
+
if ($this->root) {
|
749 |
+
$server_data['root'] = $this->root;
|
750 |
+
}
|
751 |
+
$this->_server_data = $server_data;
|
752 |
+
}
|
753 |
+
return $this->_server_data;
|
754 |
+
}
|
755 |
+
|
756 |
+
protected function build_person_data() {
|
757 |
+
// return cached value if non-null
|
758 |
+
// it *is* possible for it to really be null (i.e. user is not logged in)
|
759 |
+
// but we'll keep trying anyway until we get a logged-in user value.
|
760 |
+
if ($this->_person_data == null) {
|
761 |
+
// first priority: try to use $this->person
|
762 |
+
if ($this->person && is_array($this->person)) {
|
763 |
+
if (isset($this->person['id'])) {
|
764 |
+
$this->_person_data = $this->person;
|
765 |
+
return $this->_person_data;
|
766 |
+
}
|
767 |
+
}
|
768 |
+
|
769 |
+
// second priority: try to use $this->person_fn
|
770 |
+
if ($this->person_fn && is_callable($this->person_fn)) {
|
771 |
+
$data = @call_user_func($this->person_fn);
|
772 |
+
if (isset($data['id'])) {
|
773 |
+
$this->_person_data = $data;
|
774 |
+
return $this->_person_data;
|
775 |
+
}
|
776 |
+
}
|
777 |
+
} else {
|
778 |
+
return $this->_person_data;
|
779 |
+
}
|
780 |
+
|
781 |
+
return null;
|
782 |
+
}
|
783 |
+
|
784 |
+
protected function build_base_data($level = 'error') {
|
785 |
+
$data = array(
|
786 |
+
'timestamp' => time(),
|
787 |
+
'environment' => $this->environment,
|
788 |
+
'level' => $level,
|
789 |
+
'language' => 'php',
|
790 |
+
'framework' => 'php',
|
791 |
+
'notifier' => array(
|
792 |
+
'name' => 'rollbar-php',
|
793 |
+
'version' => self::VERSION
|
794 |
+
),
|
795 |
+
'uuid' => $this->uuid4()
|
796 |
+
);
|
797 |
+
|
798 |
+
if ($this->code_version) {
|
799 |
+
$data['code_version'] = $this->code_version;
|
800 |
+
}
|
801 |
+
|
802 |
+
return $data;
|
803 |
+
}
|
804 |
+
|
805 |
+
protected function build_payload($data) {
|
806 |
+
$payload = array(
|
807 |
+
'data' => $data
|
808 |
+
);
|
809 |
+
|
810 |
+
if ($this->access_token) {
|
811 |
+
$payload['access_token'] = $this->access_token;
|
812 |
+
}
|
813 |
+
|
814 |
+
return $payload;
|
815 |
+
}
|
816 |
+
|
817 |
+
protected function send_payload($payload) {
|
818 |
+
if ($this->batched) {
|
819 |
+
if ($this->queueSize() >= $this->batch_size) {
|
820 |
+
// flush queue before adding payload to queue
|
821 |
+
$this->flush();
|
822 |
+
}
|
823 |
+
$this->_queue[] = $payload;
|
824 |
+
} else {
|
825 |
+
$this->_send_payload($payload);
|
826 |
+
}
|
827 |
+
}
|
828 |
+
|
829 |
+
/**
|
830 |
+
* Sends a single payload to the /item endpoint.
|
831 |
+
* $payload - php array
|
832 |
+
*/
|
833 |
+
protected function _send_payload($payload) {
|
834 |
+
if ($this->handler == 'agent') {
|
835 |
+
$this->_send_payload_agent($payload);
|
836 |
+
} else {
|
837 |
+
$this->_send_payload_blocking($payload);
|
838 |
+
}
|
839 |
+
}
|
840 |
+
|
841 |
+
protected function _send_payload_blocking($payload) {
|
842 |
+
$this->log_info("Sending payload");
|
843 |
+
$access_token = $payload['access_token'];
|
844 |
+
$post_data = json_encode($payload);
|
845 |
+
$this->make_api_call('item', $access_token, $post_data);
|
846 |
+
}
|
847 |
+
|
848 |
+
protected function _send_payload_agent($payload) {
|
849 |
+
// Only open this the first time
|
850 |
+
if (empty($this->_agent_log)) {
|
851 |
+
$this->load_agent_file();
|
852 |
+
}
|
853 |
+
$this->log_info("Writing payload to file");
|
854 |
+
fwrite($this->_agent_log, json_encode($payload) . "\n");
|
855 |
+
}
|
856 |
+
|
857 |
+
/**
|
858 |
+
* Sends a batch of payloads to the /batch endpoint.
|
859 |
+
* A batch is just an array of standalone payloads.
|
860 |
+
* $batch - php array of payloads
|
861 |
+
*/
|
862 |
+
protected function send_batch($batch) {
|
863 |
+
if ($this->handler == 'agent') {
|
864 |
+
$this->send_batch_agent($batch);
|
865 |
+
} else {
|
866 |
+
$this->send_batch_blocking($batch);
|
867 |
+
}
|
868 |
+
}
|
869 |
+
|
870 |
+
protected function send_batch_agent($batch) {
|
871 |
+
$this->log_info("Writing batch to file");
|
872 |
+
|
873 |
+
// Only open this the first time
|
874 |
+
if (empty($this->_agent_log)) {
|
875 |
+
$this->load_agent_file();
|
876 |
+
}
|
877 |
+
|
878 |
+
foreach ($batch as $item) {
|
879 |
+
fwrite($this->_agent_log, json_encode($item) . "\n");
|
880 |
+
}
|
881 |
+
}
|
882 |
+
|
883 |
+
protected function send_batch_blocking($batch) {
|
884 |
+
$this->log_info("Sending batch");
|
885 |
+
$access_token = $batch[0]['access_token'];
|
886 |
+
$post_data = json_encode($batch);
|
887 |
+
$this->make_api_call('item_batch', $access_token, $post_data);
|
888 |
+
}
|
889 |
+
|
890 |
+
protected function make_api_call($action, $access_token, $post_data) {
|
891 |
+
$url = $this->base_api_url . $action . '/';
|
892 |
+
|
893 |
+
$ch = curl_init();
|
894 |
+
curl_setopt($ch, CURLOPT_URL, $url);
|
895 |
+
curl_setopt($ch, CURLOPT_POST, true);
|
896 |
+
curl_setopt($ch, CURLOPT_POSTFIELDS, $post_data);
|
897 |
+
curl_setopt($ch, CURLOPT_VERBOSE, false);
|
898 |
+
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
|
899 |
+
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
900 |
+
curl_setopt($ch, CURLOPT_TIMEOUT, $this->timeout);
|
901 |
+
curl_setopt($ch, CURLOPT_HTTPHEADER, array('X-Rollbar-Access-Token: ' . $access_token));
|
902 |
+
|
903 |
+
if ($this->proxy) {
|
904 |
+
$proxy = is_array($this->proxy) ? $this->proxy : array('address' => $this->proxy);
|
905 |
+
|
906 |
+
if (isset($proxy['address'])) {
|
907 |
+
curl_setopt($ch, CURLOPT_PROXY, $proxy['address']);
|
908 |
+
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
|
909 |
+
}
|
910 |
+
|
911 |
+
if (isset($proxy['username']) && isset($proxy['password'])) {
|
912 |
+
curl_setopt($ch, CURLOPT_PROXYUSERPWD, $proxy['username'] . ':' . $proxy['password']);
|
913 |
+
}
|
914 |
+
}
|
915 |
+
|
916 |
+
if ($this->_curl_ipresolve_supported) {
|
917 |
+
curl_setopt($ch, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4);
|
918 |
+
}
|
919 |
+
|
920 |
+
$result = curl_exec($ch);
|
921 |
+
$status_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
|
922 |
+
curl_close($ch);
|
923 |
+
|
924 |
+
if ($status_code != 200) {
|
925 |
+
$this->log_warning('Got unexpected status code from Rollbar API ' . $action .
|
926 |
+
': ' .$status_code);
|
927 |
+
$this->log_warning('Output: ' .$result);
|
928 |
+
} else {
|
929 |
+
$this->log_info('Success');
|
930 |
+
}
|
931 |
+
}
|
932 |
+
|
933 |
+
/* Logging */
|
934 |
+
|
935 |
+
protected function log_info($msg) {
|
936 |
+
$this->log_message("INFO", $msg);
|
937 |
+
}
|
938 |
+
|
939 |
+
protected function log_warning($msg) {
|
940 |
+
$this->log_message("WARNING", $msg);
|
941 |
+
}
|
942 |
+
|
943 |
+
protected function log_error($msg) {
|
944 |
+
$this->log_message("ERROR", $msg);
|
945 |
+
}
|
946 |
+
|
947 |
+
protected function log_message($level, $msg) {
|
948 |
+
if ($this->logger !== null) {
|
949 |
+
$this->logger->log($level, $msg);
|
950 |
+
}
|
951 |
+
}
|
952 |
+
|
953 |
+
// from http://www.php.net/manual/en/function.uniqid.php#94959
|
954 |
+
protected function uuid4() {
|
955 |
+
mt_srand();
|
956 |
+
return sprintf('%04x%04x-%04x-%04x-%04x-%04x%04x%04x',
|
957 |
+
// 32 bits for "time_low"
|
958 |
+
mt_rand(0, 0xffff), mt_rand(0, 0xffff),
|
959 |
+
|
960 |
+
// 16 bits for "time_mid"
|
961 |
+
mt_rand(0, 0xffff),
|
962 |
+
|
963 |
+
// 16 bits for "time_hi_and_version",
|
964 |
+
// four most significant bits holds version number 4
|
965 |
+
mt_rand(0, 0x0fff) | 0x4000,
|
966 |
+
|
967 |
+
// 16 bits, 8 bits for "clk_seq_hi_res",
|
968 |
+
// 8 bits for "clk_seq_low",
|
969 |
+
// two most significant bits holds zero and one for variant DCE1.1
|
970 |
+
mt_rand(0, 0x3fff) | 0x8000,
|
971 |
+
|
972 |
+
// 48 bits for "node"
|
973 |
+
mt_rand(0, 0xffff), mt_rand(0, 0xffff), mt_rand(0, 0xffff)
|
974 |
+
);
|
975 |
+
}
|
976 |
+
|
977 |
+
protected function load_agent_file() {
|
978 |
+
$this->_agent_log = fopen($this->agent_log_location . '/rollbar-relay.' . getmypid() . '.' . microtime(true) . '.rollbar', 'a');
|
979 |
+
}
|
980 |
+
}
|
981 |
+
|
982 |
+
interface iRollbarLogger {
|
983 |
+
public function log($level, $msg);
|
984 |
+
}
|
985 |
+
|
986 |
+
class Ratchetio extends Rollbar {}
|
app/code/community/Koan/Seg/sql/koan_seg_setup/install-1.0.0.0.php
ADDED
@@ -0,0 +1,14 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/**
|
4 |
+
* @category Koan
|
5 |
+
* @package Seg
|
6 |
+
* @author Seg <hello@getseg.com, http://getseg.com>
|
7 |
+
* @copyright Seg <http://getseg.com>
|
8 |
+
* @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
|
9 |
+
*/
|
10 |
+
|
11 |
+
$installer = $this;
|
12 |
+
|
13 |
+
$installer->startSetup();
|
14 |
+
$installer->endSetup();
|
app/code/community/Koan/Seg/sql/koan_seg_setup/upgrade-1.0.0.0-1.0.0.1.php
ADDED
@@ -0,0 +1,35 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
$installer = $this;
|
4 |
+
$installer->startSetup();
|
5 |
+
|
6 |
+
$table = $installer->getConnection()
|
7 |
+
->newTable($installer->getTable('koan_seg/batch_status'))
|
8 |
+
->addColumn('id', Varien_Db_Ddl_Table::TYPE_INTEGER, null, array(
|
9 |
+
'identity' => true,
|
10 |
+
'unsigned' => true,
|
11 |
+
'nullable' => false,
|
12 |
+
'primary' => true
|
13 |
+
))
|
14 |
+
->addColumn('entity_type', Varien_Db_Ddl_Table::TYPE_TEXT, 50, array(
|
15 |
+
'nullable' => false
|
16 |
+
))
|
17 |
+
->addColumn('start_time', Varien_Db_Ddl_Table::TYPE_TIMESTAMP, null, array(), 'Start Time')
|
18 |
+
->addColumn('end_time', Varien_Db_Ddl_Table::TYPE_TIMESTAMP, null, array(), 'End Time')
|
19 |
+
->addColumn('total_row_count', Varien_Db_Ddl_Table::TYPE_INTEGER, null, array(
|
20 |
+
'nullable' => false
|
21 |
+
))
|
22 |
+
->addColumn('num_rows_processed', Varien_Db_Ddl_Table::TYPE_INTEGER, null, array(
|
23 |
+
'nullable' => false
|
24 |
+
))
|
25 |
+
->addColumn('current_status', Varien_Db_Ddl_Table::TYPE_INTEGER, null, array(
|
26 |
+
'nullable' => false,
|
27 |
+
'default' => '0'
|
28 |
+
))
|
29 |
+
->addColumn('comment', Varien_Db_Ddl_Table::TYPE_TEXT, null, array(
|
30 |
+
'nullable' => false
|
31 |
+
))
|
32 |
+
->addColumn('num_retried', Varien_Db_Ddl_Table::TYPE_INTEGER, null, array(
|
33 |
+
'nullable' => false
|
34 |
+
));
|
35 |
+
$installer->getConnection()->createTable($table);
|
app/code/community/Koan/Seg/sql/koan_seg_setup/upgrade-1.0.0.1-1.0.0.2.php
ADDED
@@ -0,0 +1,16 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
$installer = $this;
|
4 |
+
$installer->startSetup();
|
5 |
+
|
6 |
+
$installer->getConnection()->addColumn(
|
7 |
+
$installer->getTable('koan_seg/batch_status'),
|
8 |
+
'filter',
|
9 |
+
array(
|
10 |
+
'type' => Varien_Db_Ddl_Table::TYPE_TEXT,
|
11 |
+
'length' => 255,
|
12 |
+
'nullable' => true,
|
13 |
+
'default' => null,
|
14 |
+
'comment' => 'Date filter for orders'
|
15 |
+
)
|
16 |
+
);
|
app/design/adminhtml/default/default/layout/seg.xml
ADDED
@@ -0,0 +1,8 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?xml version="1.0"?>
|
2 |
+
<layout>
|
3 |
+
<adminhtml_seg_exporter>
|
4 |
+
<reference name="content">
|
5 |
+
<block type="koan_seg/adminhtml_exporter" name="exporter"/>
|
6 |
+
</reference>
|
7 |
+
</adminhtml_seg_exporter>
|
8 |
+
</layout>
|
app/design/frontend/base/default/layout/seg.xml
ADDED
@@ -0,0 +1,12 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?xml version="1.0"?>
|
2 |
+
|
3 |
+
<layout>
|
4 |
+
<default>
|
5 |
+
<reference name="head">
|
6 |
+
<block type="koan_seg/header" name="seg.tracking" template="seg/config.phtml"/>
|
7 |
+
</reference>
|
8 |
+
<reference name="before_body_end">
|
9 |
+
<block type="koan_seg/track" name="seg.track" template="seg/tracking.phtml"/>
|
10 |
+
</reference>
|
11 |
+
</default>
|
12 |
+
</layout>
|
app/design/frontend/base/default/template/seg/config.phtml
ADDED
@@ -0,0 +1,9 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<script type="text/javascript">
|
2 |
+
;(function () { var a, b, c, e = window, f = document, g = arguments, h = "script", i = ["config", "track", "identify", "callback"], j = function () { var a, b = this; for (b._s = [], a = 0; a < i.length; a++) !function (a) { b[a] = function () { return b._s.push([a].concat(Array.prototype.slice.call(arguments, 0))), b } }(i[a]) }; for (e._seg = e._seg || {}, a = 0; g.length > a; a++) e._seg[g[a]] = e[g[a]] = e[g[a]] || new j; b = f.createElement(h), b.async = 1, b.src = "https://segapp.blob.core.windows.net/release/seg-analytics.min.js", c = f.getElementsByTagName(h)[0], c.parentNode.insertBefore(b, c) }("seg"));
|
3 |
+
|
4 |
+
<?php $currentStore = Mage::app()->getStore()->getId() ?>
|
5 |
+
// Unique website identifying code
|
6 |
+
seg.config({
|
7 |
+
site: "<?php echo Mage::helper('koan_seg')->getWebsiteId($currentStore) ?>"
|
8 |
+
});
|
9 |
+
</script>
|
app/design/frontend/base/default/template/seg/tracking.phtml
ADDED
@@ -0,0 +1,23 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<script>
|
2 |
+
<?php if($customerData = $this->getCustomerData()): ?>
|
3 |
+
seg.identify(<?php echo $customerData ?>);
|
4 |
+
<?php endif; ?>
|
5 |
+
<?php if($dob = $this->getCustomerDob()): ?>
|
6 |
+
seg.identify("DateOfBirth", new Date("<?php echo $dob ?>"));
|
7 |
+
<?php endif; ?>
|
8 |
+
|
9 |
+
<?php $trackingEventCode = $this->getTrackingEventCode() ?>
|
10 |
+
<?php if ($trackingEventCode AND is_array($trackingEventCode)): ?>
|
11 |
+
<?php if (array_key_exists('event', $trackingEventCode) AND array_key_exists('data', $trackingEventCode)): ?>
|
12 |
+
<?php if (is_null($trackingEventCode['data'])): ?>
|
13 |
+
seg.track();
|
14 |
+
<?php else: ?>
|
15 |
+
seg.track("<?php echo $trackingEventCode['event'] ?>", <?php echo $trackingEventCode['data'] ?>);
|
16 |
+
<?php endif; ?>
|
17 |
+
<?php else: ?>
|
18 |
+
seg.track();
|
19 |
+
<?php endif; ?>
|
20 |
+
<?php else: ?>
|
21 |
+
seg.track();
|
22 |
+
<?php endif; ?>
|
23 |
+
</script>
|
app/etc/modules/Koan_Seg.xml
ADDED
@@ -0,0 +1,8 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<config>
|
2 |
+
<modules>
|
3 |
+
<Koan_Seg>
|
4 |
+
<active>true</active>
|
5 |
+
<codePool>community</codePool>
|
6 |
+
</Koan_Seg>
|
7 |
+
</modules>
|
8 |
+
</config>
|
package.xml
ADDED
@@ -0,0 +1,41 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?xml version="1.0"?>
|
2 |
+
<package>
|
3 |
+
<name>seg</name>
|
4 |
+
<version>1.0.0.0</version>
|
5 |
+
<stability>stable</stability>
|
6 |
+
<license uri="http://opensource.org/licenses/osl-3.0.php">Open Software License (OSL 3.0)</license>
|
7 |
+
<channel>community</channel>
|
8 |
+
<extends/>
|
9 |
+
<summary>Easily and automatically make more revenue from MailChimp by understanding customer preferences and behaviour.</summary>
|
10 |
+
<description>Seg makes Magento and MailChimp really work together. If you run an Magento store and use MailChimp, you really need to use Seg; it will transform the effectiveness of your email marketing campaigns in MailChimp. 
|
11 |
+

|
12 |
+
= What does Seg do? = 
|
13 |
+
Seg for Magento + MailChimp captures all your visitors behaviour from their email, web browsing and orders and turns that into rich profiles of their preferences for your categories & products, and how likely they are to respond to emails, offers and more. 
|
14 |
+

|
15 |
+
You can then create your campaign in MailChimp as normal, but you use Seg to target the right customers for your content based on a wide range of factors including: 
|
16 |
+
- How much money you want to make from your campaign (we predict that too!) 
|
17 |
+
- How relevant the content is to your customers (customers who have "shown an interest" vs. "love" category/brand X) 
|
18 |
+
- Whether they've bought recently 
|
19 |
+
- Whether they've visited recently 
|
20 |
+
- And so much more. 
|
21 |
+

|
22 |
+
You can also: 
|
23 |
+
- See how much revenue and profit your MailChimp campaigns have made in detail 
|
24 |
+
- See your customers in real time and what they are doing on your website 
|
25 |
+
- See a detailed profile for every customer that has ever visited or bought from your store and what their preferences are 
|
26 |
+
- See exactly how you can improve your email marketing (through MailChimp), inlcuding how much money you could make 
|
27 |
+
- See your campaign performance over time via our email analytics system 
|
28 |
+

|
29 |
+
Seg automatically does this for you: 
|
30 |
+
- Tracks all customers behaviour and orders 
|
31 |
+
- Protects you from over-emailing your customers (you set the limit) 
|
32 |
+
- Predicts the revenue you will make from a campaign (knowing individual customer's behaviours and preferences) so you can tailor the audience to make the most money 
|
33 |
+
- Rates each campaign (as 1-5 stars) so you can easily find the best campaigns and improve them / resend them / use for inspiration in the future</description>
|
34 |
+
<notes>First stable release.</notes>
|
35 |
+
<authors><author><name>Seg</name><user>KoanLeeroy</user><email>Lee@koan.is</email></author></authors>
|
36 |
+
<date>2015-07-31</date>
|
37 |
+
<time>13:30:44</time>
|
38 |
+
<contents><target name="magecommunity"><dir name="Koan"><dir name="Seg"><dir name="Block"><dir name="Adminhtml"><dir name="Exporter"><dir name="Grid"><dir name="Renderer"><file name="Status.php" hash="bab35c7c04bfb7b2ca628a08f9d0b9cf"/></dir></dir><file name="Grid.php" hash="5c4d9013851c80b14d9240e800cc5f54"/></dir><file name="Exporter.php" hash="c8ad547a58f8bd3b56d1d18627389e32"/></dir><file name="Header.php" hash="bd07e0f326730dd7ccb796eb2f33a1c7"/><file name="Track.php" hash="b04e1d5090b6c6f9e2d34a46ac31c9ae"/></dir><dir name="Helper"><file name="Data.php" hash="147ac05f825ce5dcf11f104ea629d0c4"/></dir><dir name="Model"><dir name="Batch"><file name="Status.php" hash="1eebea45e69dbf320a871ef535c49772"/></dir><dir name="Exception"><file name="Handler.php" hash="60cef7aef2b276fbd42d17f5406a4d64"/></dir><file name="Logger.php" hash="d2f267ea04603190d30dbcf185b6651f"/><file name="Observer.php" hash="faad57341c555ba99061605c0562a907"/><dir name="Resource"><dir name="Batch"><dir name="Status"><file name="Collection.php" hash="814df925981a77007df1d7710d407ec5"/></dir><file name="Status.php" hash="f96826a954f09bc9fc67e97f14dec207"/></dir></dir><dir name="Seg"><file name="Basket.php" hash="00c1c6b1ddeb5300b5d79d7793a4e7c9"/><file name="Client.php" hash="8c0563b5e1103a9b7991a13c5f8051d3"/><file name="Customer.php" hash="fc8c59e8cd5daaa7fd6a839c3be8ab11"/><file name="Exporter.php" hash="8201cddf650385f0371a41b5654a5176"/><dir name="Order"><file name="Line.php" hash="c2acaea156dcaedf8dbe50f3c98987e2"/></dir><file name="Order.php" hash="d3af49ea2c8a5c09829ff3f712c0058d"/><file name="Product.php" hash="dba1f75f98972013113392df55273922"/><dir name="Quote"><file name="Line.php" hash="352335afd649295052173e4c4d177e3c"/></dir><file name="Range.php" hash="81b1eed35211554c2a76df4160ff992a"/></dir></dir><dir name="controllers"><dir name="Adminhtml"><file name="SegController.php" hash="5c3fa5c56c91dff79a46fe862baf94fe"/></dir><file name="IndexController.php" hash="5d4a841c4f1bb1d3de2dfe1a325abe0f"/></dir><dir name="etc"><file name="adminhtml.xml" hash="0f44123ff295e29dc1f53967a1e5eff4"/><file name="config.xml" hash="7cca137d8acbc54de7ae46e86922aee1"/><file name="system.xml" hash="2a732cb77e3bba5d8d1d1caf8a146faf"/></dir><dir name="lib"><file name="Rollbar.php" hash="b93689fd5505f34a686cb5b979d0fdca"/></dir><dir name="sql"><dir name="koan_seg_setup"><file name="install-1.0.0.0.php" hash="983531e5fb85bdff121a5d0d74b34025"/><file name="upgrade-1.0.0.0-1.0.0.1.php" hash="9c91352527e09881251fd92766ac7a6f"/><file name="upgrade-1.0.0.1-1.0.0.2.php" hash="3a664531053ec11f56688527105cf8cd"/></dir></dir></dir><file name=".DS_Store" hash="194577a7e20bdcc7afbb718f502c134c"/></dir></target><target name="magedesign"><dir name="adminhtml"><dir name="default"><dir name="default"><dir name="layout"><file name="seg.xml" hash="4980a411970cde4aacae7d2a3c1815bb"/></dir></dir></dir></dir><dir name="frontend"><dir name="base"><dir name="default"><dir name="layout"><file name="seg.xml" hash="017d053269b5e2741eb58370696b1669"/></dir><dir name="template"><dir name="seg"><file name="config.phtml" hash="079d1614bcc44acc0766d9f43f5131a3"/><file name="tracking.phtml" hash="8085abd78c95b8eace352f64a07738ab"/></dir></dir></dir></dir></dir></target><target name="mageetc"><dir name="modules"><file name="Koan_Seg.xml" hash="7bea24d633fd1e53870ecc7fe19b4e41"/></dir></target></contents>
|
39 |
+
<compatible/>
|
40 |
+
<dependencies><required><php><min>5.1.0</min><max>6.0.0</max></php></required></dependencies>
|
41 |
+
</package>
|