├── LICENSE.txt ├── aoe-logo.png ├── skin └── adminhtml │ └── default │ └── default │ └── css │ └── aoe_fraudmanager.css ├── app ├── code │ └── local │ │ └── Aoe │ │ └── FraudManager │ │ ├── Model │ │ ├── Config │ │ │ └── Source │ │ │ │ └── Order │ │ │ │ ├── HoldStatuses.php │ │ │ │ └── HoldStatusesNone.php │ │ ├── HoldRule.php │ │ ├── BlacklistRule.php │ │ ├── Form │ │ │ └── Element │ │ │ │ ├── Renderer │ │ │ │ ├── Conditions.php │ │ │ │ ├── Newchild.php │ │ │ │ └── Editable.php │ │ │ │ └── Select.php │ │ ├── Rule │ │ │ ├── Condition │ │ │ │ ├── Order │ │ │ │ │ ├── BillingAddress │ │ │ │ │ │ └── Attribute.php │ │ │ │ │ ├── ShippingAddress │ │ │ │ │ │ └── Attribute.php │ │ │ │ │ ├── Item │ │ │ │ │ │ ├── Combine.php │ │ │ │ │ │ ├── Attribute.php │ │ │ │ │ │ └── Found.php │ │ │ │ │ ├── Address │ │ │ │ │ │ ├── Attribute.php │ │ │ │ │ │ └── Compare.php │ │ │ │ │ └── Attribute.php │ │ │ │ ├── Root.php │ │ │ │ ├── Interface.php │ │ │ │ ├── Abstract.php │ │ │ │ ├── Attribute.php │ │ │ │ └── Combine.php │ │ │ └── Abstract.php │ │ └── Observer.php │ │ ├── controllers │ │ ├── FraudManager │ │ │ ├── HoldRuleController.php │ │ │ └── BlacklistRuleController.php │ │ └── Sales │ │ │ └── OrderController.php │ │ ├── Helper │ │ ├── Data.php │ │ ├── Condition.php │ │ ├── HoldRule.php │ │ ├── BlacklistRule.php │ │ ├── FraudFlag.php │ │ └── AbstractRule.php │ │ ├── Resource │ │ ├── HoldRule │ │ │ └── Collection.php │ │ ├── BlacklistRule │ │ │ └── Collection.php │ │ ├── HoldRule.php │ │ ├── BlacklistRule.php │ │ ├── Abstract.php │ │ └── Collection │ │ │ └── Abstract.php │ │ ├── sql │ │ └── Aoe_FraudManager │ │ │ ├── install-0.1.0.php │ │ │ └── upgrade-0.1.0-0.2.0.php │ │ ├── Test │ │ └── Model │ │ │ ├── HoldRule.php │ │ │ └── BlacklistRule.php │ │ ├── Controller │ │ └── RuleController.php │ │ └── etc │ │ ├── adminhtml.xml │ │ ├── config.xml │ │ └── system.xml ├── locale │ └── en_US │ │ ├── template │ │ └── email │ │ │ └── aoe_fraudmanager │ │ │ └── notification_email.txt │ │ └── Aoe_FraudManager.csv ├── etc │ └── modules │ │ └── Aoe_FraudManager.xml └── design │ └── adminhtml │ └── default │ └── default │ ├── template │ └── aoe_fraudmanager │ │ ├── rule │ │ ├── fieldset.phtml │ │ ├── form.phtml │ │ └── js.phtml │ │ └── sales │ │ └── order │ │ └── view │ │ └── info.phtml │ └── layout │ └── Aoe_FraudManager.xml ├── modman ├── README.md ├── composer.json ├── .travis.yml ├── phpcs.xml └── run_tests.sh /LICENSE.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AOEpeople/Aoe_FraudManager/HEAD/LICENSE.txt -------------------------------------------------------------------------------- /aoe-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AOEpeople/Aoe_FraudManager/HEAD/aoe-logo.png -------------------------------------------------------------------------------- /skin/adminhtml/default/default/css/aoe_fraudmanager.css: -------------------------------------------------------------------------------- 1 | #order_status_fraud { 2 | color: #FF0000; 3 | font-weight: bold; 4 | text-transform: uppercase; 5 | } 6 | -------------------------------------------------------------------------------- /app/code/local/Aoe/FraudManager/Model/Config/Source/Order/HoldStatuses.php: -------------------------------------------------------------------------------- 1 | _setResourceModel('Aoe_FraudManager/HoldRule', 'Aoe_FraudManager/HoldRule_Collection'); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /app/code/local/Aoe/FraudManager/Model/BlacklistRule.php: -------------------------------------------------------------------------------- 1 | _setResourceModel('Aoe_FraudManager/BlacklistRule', 'Aoe_FraudManager/BlacklistRule_Collection'); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /app/code/local/Aoe/FraudManager/controllers/FraudManager/HoldRuleController.php: -------------------------------------------------------------------------------- 1 | 2 | Details 3 | =========== 4 | Quote: {{var order.quote_id}} 5 | Order: {{var order.increment_id}} 6 | Value: {{var order.base_grand_total}} {{var order.base_currency_code}} 7 | Customer: {{var order.customer_name}} ({{var order.customer_email}}) 8 | 9 | Messages 10 | =========== 11 | {{var message}} 12 | -------------------------------------------------------------------------------- /app/code/local/Aoe/FraudManager/controllers/FraudManager/BlacklistRuleController.php: -------------------------------------------------------------------------------- 1 | getUrl($route, $params); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /modman: -------------------------------------------------------------------------------- 1 | app/etc/modules/Aoe_FraudManager.xml 2 | app/code/local/Aoe/FraudManager 3 | app/design/adminhtml/default/default/layout/Aoe_FraudManager.xml 4 | app/design/adminhtml/default/default/template/aoe_fraudmanager 5 | skin/adminhtml/default/default/css/aoe_fraudmanager.css 6 | #skin/adminhtml/default/default/js/aoe_fraudmanager 7 | #skin/adminhtml/default/default/images/aoe_fraudmanager 8 | app/locale/en_US/Aoe_FraudManager.csv 9 | app/locale/en_US/template/email/aoe_fraudmanager 10 | -------------------------------------------------------------------------------- /app/etc/modules/Aoe_FraudManager.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | true 6 | local 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /app/code/local/Aoe/FraudManager/Model/Config/Source/Order/HoldStatusesNone.php: -------------------------------------------------------------------------------- 1 | '', 'label' => Mage::helper('Aoe_FraudManager')->__('-- None --')]); 11 | 12 | return $options; 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /app/code/local/Aoe/FraudManager/Model/Form/Element/Renderer/Conditions.php: -------------------------------------------------------------------------------- 1 | getValue(); 9 | if ($conditions instanceof Aoe_FraudManager_Model_Rule_Condition_Root) { 10 | return $conditions->getHtml(); 11 | } 12 | 13 | return ''; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![AOE](aoe-logo.png)](http://www.aoe.com) 2 | 3 | # Aoe_FraudManager Magento Module 4 | 5 | [![Build Status](https://travis-ci.org/AOEpeople/Aoe_FraudManager.svg?branch=master)](https://travis-ci.org/AOEpeople/Aoe_FraudManager) 6 | 7 | ## License 8 | [OSL v3.0](http://opensource.org/licenses/OSL-3.0) 9 | 10 | ## Contributors 11 | * [Lee Saferite](https://github.com/LeeSaferite) (AOE) 12 | 13 | ## Compatability 14 | * Template Rewrites 15 | * app/design/adminhtml/default/default/template/sales/order/view/info.phtml 16 | * Module Dependencies 17 | * Mage_Core 18 | * Mage_Adminhtml 19 | * Mage_Sales 20 | * Aoe_Layout 21 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "aoepeople/aoe_fraudmanager", 3 | "description": "Rule based fraud management for Magento", 4 | "authors": [ 5 | { 6 | "name": "Lee Saferite", 7 | "email": "lee.saferite@aoe.com" 8 | } 9 | ], 10 | "license": "OSL-3.0", 11 | "type": "magento-module", 12 | "require": { 13 | "php": ">=5.4", 14 | "magento-hackathon/magento-composer-installer": "*", 15 | "aoepeople/aoe_layout": ">=2.1.1" 16 | }, 17 | "require-dev": { 18 | "ecomdev/ecomdev_phpunit": "*", 19 | "squizlabs/php_codesniffer": "*", 20 | "phpmd/phpmd": "*" 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /app/locale/en_US/Aoe_FraudManager.csv: -------------------------------------------------------------------------------- 1 | "Marked order as fraud","Marked order as fraud" 2 | "Marked order as NOT fraud","Marked order as NOT fraud" 3 | "Set Fraud Flag","Set Fraud Flag" 4 | "Remove Fraud Flag","Remove Fraud Flag" 5 | "Fraud","Fraud" 6 | "Mark Fraud","Mark Fraud" 7 | "Unmark Fraud","Unmark Fraud" 8 | "Mark Order #%s as Fraud","Mark Order #%s as Fraud" 9 | "Mark Order #%s as NOT Fraud","Mark Order #%s as NOT Fraud" 10 | "AOE Fraud Manager","AOE Fraud Manager" 11 | "Fraud Flag","Fraud Flag" 12 | "Active","Active" 13 | "Require a comment when setting/removing the flag","Require a comment when setting/removing the flag" 14 | "Blacklist Rules","Blacklist Rules" 15 | "Hold Rules","Hold Rules" 16 | -------------------------------------------------------------------------------- /app/code/local/Aoe/FraudManager/Resource/HoldRule/Collection.php: -------------------------------------------------------------------------------- 1 | _init('Aoe_FraudManager/HoldRule'); 8 | } 9 | 10 | public function filterValidForOrder(Mage_Sales_Model_Order $order, $includeInactive = false) 11 | { 12 | if (!$includeInactive) { 13 | $this->addFieldToFilter('is_active', '1'); 14 | } 15 | $this->addFieldToFilter('website_ids', ['finset' => $order->getStore()->getWebsiteId()]); 16 | $this->addOrder('sort_order', 'DESC'); 17 | 18 | return $this; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /app/code/local/Aoe/FraudManager/sql/Aoe_FraudManager/install-0.1.0.php: -------------------------------------------------------------------------------- 1 | getNode('global/resources/sales_setup/setup'); 3 | $setupClass = $setupConfig->getClassName(); 4 | $setupClass = ($setupClass ? $setupClass : 'Mage_Sales_Model_Resource_Setup'); 5 | $setup = new $setupClass('sales_setup'); 6 | /* @var Mage_Sales_Model_Resource_Setup $setup */ 7 | 8 | $setup->startSetup(); 9 | 10 | $setup->addAttribute( 11 | Mage_Sales_Model_Order::ENTITY, 12 | 'is_fraud', 13 | [ 14 | 'type' => Varien_Db_Ddl_Table::TYPE_BOOLEAN, 15 | 'required' => true, 16 | 'comment' => 'Fraud flag', 17 | 'grid' => true, 18 | ] 19 | ); 20 | 21 | $setup->endSetup(); 22 | -------------------------------------------------------------------------------- /app/code/local/Aoe/FraudManager/Resource/BlacklistRule/Collection.php: -------------------------------------------------------------------------------- 1 | _init('Aoe_FraudManager/BlacklistRule'); 8 | } 9 | 10 | public function filterValidForOrder(Mage_Sales_Model_Order $order, $includeInactive = false) 11 | { 12 | if (!$includeInactive) { 13 | $this->addFieldToFilter('is_active', '1'); 14 | } 15 | $this->addFieldToFilter('website_ids', ['finset' => $order->getStore()->getWebsiteId()]); 16 | $this->addOrder('sort_order', 'DESC'); 17 | 18 | return $this; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | sudo: false 2 | language: php 3 | php: 4 | - 5.4 5 | - 5.5 6 | env: 7 | matrix: 8 | - MAGENTO_VERSION=magento-mirror-1.9.1.1 9 | - MAGENTO_VERSION=magento-mirror-1.9.1.0 10 | - MAGENTO_VERSION=magento-mirror-1.9.0.1 11 | - MAGENTO_VERSION=magento-mirror-1.8.1.0 12 | branches: 13 | except: 14 | - /^\d+\.\d+\.\d+$/ 15 | addons: 16 | hosts: 17 | - magento.local 18 | before_script: 19 | - curl -OL https://squizlabs.github.io/PHP_CodeSniffer/phpcs.phar 20 | script: 21 | # Code Style 22 | - php phpcs.phar --standard=./phpcs.xml --encoding=utf-8 --report-width=180 ./app 23 | # Unit Tests 24 | - bash ./run_tests.sh 25 | notifications: 26 | email: 27 | recipients: [ clemens.queissner@aoe.com ] 28 | on_failure: always 29 | -------------------------------------------------------------------------------- /app/code/local/Aoe/FraudManager/Resource/HoldRule.php: -------------------------------------------------------------------------------- 1 | [ 7 | '[]', 8 | [], 9 | false, 10 | ['Aoe_FraudManager_Resource_HoldRule', 'implodeArray'], 11 | ['Aoe_FraudManager_Resource_HoldRule', 'explodeArray'], 12 | ], 13 | 'conditions' => [ 14 | '[]', 15 | [], 16 | false, 17 | ['Zend_Json', 'encode'], 18 | ['Zend_Json', 'decode'], 19 | ], 20 | ]; 21 | 22 | public function _construct() 23 | { 24 | $this->_init('Aoe_FraudManager/HoldRule', 'id'); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /app/code/local/Aoe/FraudManager/Resource/BlacklistRule.php: -------------------------------------------------------------------------------- 1 | [ 7 | '[]', 8 | [], 9 | false, 10 | ['Aoe_FraudManager_Resource_BlacklistRule', 'implodeArray'], 11 | ['Aoe_FraudManager_Resource_BlacklistRule', 'explodeArray'], 12 | ], 13 | 'conditions' => [ 14 | '[]', 15 | [], 16 | false, 17 | ['Zend_Json', 'encode'], 18 | ['Zend_Json', 'decode'], 19 | ], 20 | ]; 21 | 22 | public function _construct() 23 | { 24 | $this->_init('Aoe_FraudManager/BlacklistRule', 'id'); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /app/code/local/Aoe/FraudManager/Model/Rule/Condition/Order/BillingAddress/Attribute.php: -------------------------------------------------------------------------------- 1 | setType('Aoe_FraudManager/Rule_Condition_Order_BillingAddress_Attribute'); 9 | $this->setName('Billing Address'); 10 | } 11 | 12 | public function validate(Varien_Object $object) 13 | { 14 | /** @var Mage_Sales_Model_Order_Address $object */ 15 | if (!$object instanceof Mage_Sales_Model_Order_Address && is_callable([$object, 'getBillingAddress'])) { 16 | $object = $object->getBillingAddress(); 17 | } 18 | 19 | return parent::validate($object); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /app/design/adminhtml/default/default/template/aoe_fraudmanager/rule/fieldset.phtml: -------------------------------------------------------------------------------- 1 | getElement() ?> 2 |
3 |
4 |

getLegend() ?>

5 |
6 |
serialize(['class']) ?>> 7 | getComment()): ?> 8 |

escapeHtml($fieldset->getComment()) ?>

9 | 10 | getChildrenHtml() ?> 11 |
12 |
13 | 16 | -------------------------------------------------------------------------------- /app/code/local/Aoe/FraudManager/Model/Rule/Condition/Order/ShippingAddress/Attribute.php: -------------------------------------------------------------------------------- 1 | setType('Aoe_FraudManager/Rule_Condition_Order_ShippingAddress_Attribute'); 9 | $this->setName('Shipping Address'); 10 | } 11 | 12 | public function validate(Varien_Object $object) 13 | { 14 | /** @var Mage_Sales_Model_Order_Address $object */ 15 | if (!$object instanceof Mage_Sales_Model_Order_Address && is_callable([$object, 'getShippingAddress'])) { 16 | $object = $object->getShippingAddress(); 17 | } 18 | 19 | return parent::validate($object); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /app/code/local/Aoe/FraudManager/Model/Rule/Condition/Root.php: -------------------------------------------------------------------------------- 1 | setParentType($this->getType()); 13 | 14 | $this->setId('root'); 15 | $this->setType('Aoe_FraudManager/Rule_Condition_Root'); 16 | } 17 | 18 | public function getSelfType() 19 | { 20 | return $this->getParentType(); 21 | } 22 | 23 | //================================================== 24 | //=[ HTML Generation ]============================== 25 | //================================================== 26 | 27 | public function getRemoveLinkHtml() 28 | { 29 | return ''; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /app/code/local/Aoe/FraudManager/Model/Form/Element/Renderer/Newchild.php: -------------------------------------------------------------------------------- 1 | addClass('element-value-changer'); 8 | 9 | $html = ' '; 10 | 11 | $html .= ''; 12 | $src = Mage::getDesign()->getSkinUrl('images/rule_component_add.gif'); 13 | $html .= ''; 14 | $html .= ''; 15 | 16 | $html .= ''; 17 | $html .= $element->getElementHtml(); 18 | $html .= ''; 19 | 20 | $html .= ' '; 21 | 22 | return $html; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /app/code/local/Aoe/FraudManager/Model/Rule/Condition/Order/Item/Combine.php: -------------------------------------------------------------------------------- 1 | setType('Aoe_FraudManager/Rule_Condition_Order_Item_Combine'); 12 | $this->setName('Conditions Combination'); 13 | } 14 | 15 | /** 16 | * Get conditions selectors 17 | * 18 | * @return array 19 | */ 20 | public function getNewChildOptions() 21 | { 22 | $conditions = ['' => $this->translate('Please choose a condition to add...')]; 23 | 24 | // Fire an event to add conditions 25 | $container = new Varien_Object(); 26 | Mage::dispatchEvent('aoe_fraudmanager_rule_condition_order_item_combine_conditions', ['parent' => $this, 'container' => $container]); 27 | if ($additional = $container->getConditions()) { 28 | $conditions = array_merge($conditions, $additional); 29 | } 30 | 31 | return $conditions; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /app/code/local/Aoe/FraudManager/Model/Form/Element/Select.php: -------------------------------------------------------------------------------- 1 | getValues(); 8 | if (empty($values)) { 9 | $options = $this->getOptions(); 10 | if (is_array($options)) { 11 | $values = $this->convertOptionsToValues($options); 12 | } elseif (is_string($options)) { 13 | $values = [['value' => $options, 'label' => $options]]; 14 | } 15 | $this->setValues($values); 16 | } 17 | } 18 | 19 | protected function convertOptionsToValues(array $options) 20 | { 21 | $values = []; 22 | 23 | foreach ($options as $value => $label) { 24 | if (is_array($label)) { 25 | $values[] = [ 26 | 'label' => $value, 27 | 'value' => $this->convertOptionsToValues($label), 28 | ]; 29 | } else { 30 | $values[] = [ 31 | 'label' => $label, 32 | 'value' => $value, 33 | ]; 34 | } 35 | } 36 | 37 | return $values; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /phpcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | Magento extension ruleset based on PSR-2 but modified for Magento 1 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /app/code/local/Aoe/FraudManager/Model/Rule/Condition/Interface.php: -------------------------------------------------------------------------------- 1 | 27 |
28 | getFormHtml() ?> 29 |
30 | 38 | -------------------------------------------------------------------------------- /app/code/local/Aoe/FraudManager/Model/Rule/Condition/Order/Item/Attribute.php: -------------------------------------------------------------------------------- 1 | ['SKU', ['==', '!=', '{}', '!{}', 'RE']], 7 | 'qty_ordered' => ['Qty', ['==', '!=', '<', '<=', '>', '>=']], 8 | 'weight' => ['Weight', ['==', '!=', '<', '<=', '>', '>=']], 9 | 'row_weight' => ['Row Weight', ['==', '!=', '<', '<=', '>', '>=']], 10 | 'price' => ['Price', ['==', '!=', '<', '<=', '>', '>=']], 11 | 'original_price' => ['Original Price', ['==', '!=', '<', '<=', '>', '>=']], 12 | 'tax_percent' => ['Tax Percent', ['==', '!=', '<', '<=', '>', '>=']], 13 | 'tax_amount' => ['Tax Amount', ['==', '!=', '<', '<=', '>', '>=']], 14 | 'discount_percent' => ['Discount Percent', ['==', '!=', '<', '<=', '>', '>=']], 15 | 'discount_amount' => ['Discount Amount', ['==', '!=', '<', '<=', '>', '>=']], 16 | 'row_total' => ['Row Total', ['==', '!=', '<', '<=', '>', '>=']], 17 | 'row_total_incl_tax' => ['Row Total w/Tax', ['==', '!=', '<', '<=', '>', '>=']], 18 | ]; 19 | 20 | protected function _construct() 21 | { 22 | parent::_construct(); 23 | $this->setType('Aoe_FraudManager/Rule_Condition_Order_Item_Attribute'); 24 | $this->setName('Order Item'); 25 | } 26 | 27 | public function validate(Varien_Object $object) 28 | { 29 | /** @var Mage_Sales_Model_Order_Item $object */ 30 | if (!$object instanceof Mage_Sales_Model_Order_Item) { 31 | return false; 32 | } 33 | 34 | return parent::validate($object); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /app/code/local/Aoe/FraudManager/Test/Model/HoldRule.php: -------------------------------------------------------------------------------- 1 | 5 | * @since 2015-08-06 6 | */ 7 | class Aoe_FraudManager_Test_Model_HoldRule extends EcomDev_PHPUnit_Test_Case 8 | { 9 | /** 10 | * @test 11 | */ 12 | public function getModel() 13 | { 14 | /** @var Aoe_FraudManager_Model_HoldRule $model */ 15 | $model = Mage::getModel('Aoe_FraudManager/HoldRule'); 16 | $this->assertInstanceOf('Aoe_FraudManager_Model_HoldRule', $model); 17 | 18 | return $model; 19 | } 20 | 21 | /** 22 | * @test 23 | * 24 | * @depends getModel 25 | * 26 | * @param Aoe_FraudManager_Model_HoldRule $model 27 | */ 28 | public function getModelResource(Aoe_FraudManager_Model_HoldRule $model) 29 | { 30 | /** @var Aoe_FraudManager_Resource_HoldRule $resource */ 31 | $resource = $model->getResource(); 32 | $this->assertInstanceOf('Aoe_FraudManager_Resource_HoldRule', $resource); 33 | 34 | /** @var Aoe_FraudManager_Resource_HoldRule $resource */ 35 | $resource = Mage::getResourceModel('Aoe_FraudManager/HoldRule'); 36 | $this->assertInstanceOf('Aoe_FraudManager_Resource_HoldRule', $resource); 37 | } 38 | 39 | /** 40 | * @test 41 | * 42 | * @depends getModel 43 | * 44 | * @param Aoe_FraudManager_Model_HoldRule $model 45 | */ 46 | public function getModelCollection(Aoe_FraudManager_Model_HoldRule $model) 47 | { 48 | /** @var Aoe_FraudManager_Resource_HoldRule_Collection $collection */ 49 | $collection = $model->getResourceCollection(); 50 | $this->assertInstanceOf('Aoe_FraudManager_Resource_HoldRule_Collection', $collection); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /app/code/local/Aoe/FraudManager/Test/Model/BlacklistRule.php: -------------------------------------------------------------------------------- 1 | 5 | * @since 2015-08-06 6 | */ 7 | class Aoe_FraudManager_Test_Model_BlacklistRule extends EcomDev_PHPUnit_Test_Case 8 | { 9 | /** 10 | * @test 11 | */ 12 | public function getModel() 13 | { 14 | /** @var Aoe_FraudManager_Model_BlacklistRule $model */ 15 | $model = Mage::getModel('Aoe_FraudManager/BlacklistRule'); 16 | $this->assertInstanceOf('Aoe_FraudManager_Model_BlacklistRule', $model); 17 | 18 | return $model; 19 | } 20 | 21 | /** 22 | * @test 23 | * 24 | * @depends getModel 25 | * 26 | * @param Aoe_FraudManager_Model_BlacklistRule $model 27 | */ 28 | public function getModelResource(Aoe_FraudManager_Model_BlacklistRule $model) 29 | { 30 | /** @var Aoe_FraudManager_Resource_BlacklistRule $resource */ 31 | $resource = $model->getResource(); 32 | $this->assertInstanceOf('Aoe_FraudManager_Resource_BlacklistRule', $resource); 33 | 34 | /** @var Aoe_FraudManager_Resource_BlacklistRule $resource */ 35 | $resource = Mage::getResourceModel('Aoe_FraudManager/BlacklistRule'); 36 | $this->assertInstanceOf('Aoe_FraudManager_Resource_BlacklistRule', $resource); 37 | } 38 | 39 | /** 40 | * @test 41 | * 42 | * @depends getModel 43 | * 44 | * @param Aoe_FraudManager_Model_BlacklistRule $model 45 | */ 46 | public function getModelCollection(Aoe_FraudManager_Model_BlacklistRule $model) 47 | { 48 | /** @var Aoe_FraudManager_Resource_BlacklistRule_Collection $collection */ 49 | $collection = $model->getResourceCollection(); 50 | $this->assertInstanceOf('Aoe_FraudManager_Resource_BlacklistRule_Collection', $collection); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /app/design/adminhtml/default/default/template/aoe_fraudmanager/rule/js.phtml: -------------------------------------------------------------------------------- 1 | 27 | 46 | -------------------------------------------------------------------------------- /app/code/local/Aoe/FraudManager/Model/Rule/Condition/Order/Address/Attribute.php: -------------------------------------------------------------------------------- 1 | ['Full Name', ['==', '!=', '{}', '!{}', 'RE']], 7 | 'firstname' => ['First Name', ['==', '!=', '{}', '!{}', 'RE']], 8 | 'lastname' => ['Last Name', ['==', '!=', '{}', '!{}', 'RE']], 9 | 'street_full' => ['Street', ['==', '!=', '{}', '!{}', 'RE']], 10 | 'city' => ['City', ['==', '!=', '{}', '!{}', 'RE']], 11 | 'region' => ['Region', ['==', '!=', '{}', '!{}', 'RE']], 12 | 'country_id' => ['Country', ['==', '!=', 'RE']], 13 | 'all' => ['All', ['==', '!=', '{}', '!{}', 'RE']], 14 | ]; 15 | 16 | protected function getAttributeValue(Varien_Object $object) 17 | { 18 | $attribute = $this->getAttribute(); 19 | if (empty($attribute)) { 20 | return null; 21 | } 22 | 23 | /** @var Mage_Sales_Model_Order_Address $object */ 24 | if ($object instanceof Mage_Sales_Model_Order_Address && $attribute === 'all') { 25 | $value = $object->format("text"); 26 | } else { 27 | $value = $object->getDataUsingMethod($attribute); 28 | } 29 | 30 | if (is_scalar($value)) { 31 | // Convert 2+ spaces in a row into a single space 32 | $value = preg_replace('/ {2,}/u', ' ', $value); 33 | 34 | // Remove leading/trailing spaces 35 | $value = trim($value); 36 | } 37 | 38 | return $value; 39 | } 40 | 41 | public function validate(Varien_Object $object) 42 | { 43 | /** @var Mage_Sales_Model_Order_Address $object */ 44 | if (!$object instanceof Mage_Sales_Model_Order_Address) { 45 | return false; 46 | } 47 | 48 | return parent::validate($object); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /app/code/local/Aoe/FraudManager/Model/Form/Element/Renderer/Editable.php: -------------------------------------------------------------------------------- 1 | addClass('element-value-changer'); 8 | $valueName = $element->getLabel(); 9 | 10 | if ($valueName === '' || $valueName === null) { 11 | $valueName = '...'; 12 | } 13 | 14 | if ($element->getShowAsText()) { 15 | $html = ' ' 17 | . htmlspecialchars($valueName) . ' '; 18 | } else { 19 | $html = ' '; 20 | 21 | /** @var Mage_Core_Model_Translate_Inline $translate */ 22 | $translate = Mage::getSingleton('core/translate_inline'); 23 | if ($translate->isAllowed()) { 24 | $valueName = Mage::helper('core/string')->truncate($valueName, 33, '...'); 25 | } 26 | 27 | $html .= ''; 28 | $html .= Mage::helper('core')->escapeHtml($valueName); 29 | $html .= ''; 30 | 31 | $html .= ' '; 32 | $html .= $element->getElementHtml(); 33 | if ($element->getExplicitApply()) { 34 | /** @var Aoe_FraudManager_Helper_Data $helper */ 35 | $helper = Mage::helper('Aoe_FraudManager/Data'); 36 | $url = $helper->getConditionApplyImageUrl(); 37 | $label = $helper->getConditionApplyLabel(); 38 | 39 | $html .= ' '; 40 | $html .= '' . $label . ''; 41 | $html .= ' '; 42 | } 43 | $html .= ''; 44 | 45 | $html .= ' '; 46 | } 47 | 48 | return $html; 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /app/code/local/Aoe/FraudManager/Model/Rule/Condition/Order/Attribute.php: -------------------------------------------------------------------------------- 1 | ['Grand Total', ['==', '!=', '<=', '<', '>=', '>']], 7 | 'customer_email' => ['Email Address', ['==', '!=', '{}', '!{}', 'RE']], 8 | 'email_domain' => ['Email Domain', ['()', '!()', 'RE']], 9 | 'remote_ip' => ['Remote IP', ['()', '!()']], 10 | 'shipping_method' => ['Shipping Method', ['{}', '!{}', '()', '!()', 'RE']], 11 | ]; 12 | 13 | protected $attributeOptions = null; 14 | 15 | /** 16 | * Internal constructor not depended on params. Can be used for object initialization 17 | */ 18 | protected function _construct() 19 | { 20 | parent::_construct(); 21 | $this->setType('Aoe_FraudManager/Rule_Condition_Order_Attribute'); 22 | $this->setName('Order'); 23 | } 24 | 25 | public function validate(Varien_Object $object) 26 | { 27 | if (!$object instanceof Mage_Sales_Model_Order) { 28 | if (is_callable([$object, 'getOrder'])) { 29 | $object = $object->getOrder(); 30 | if (!$object instanceof Mage_Sales_Model_Order) { 31 | return false; 32 | } 33 | } else { 34 | return false; 35 | } 36 | } 37 | 38 | return parent::validate($object); 39 | } 40 | 41 | protected function getAttributeValue(Varien_Object $object) 42 | { 43 | switch ($this->getAttribute()) { 44 | case 'email_domain': 45 | $emailAddress = $object->getDataUsingMethod('customer_email'); 46 | $emailDomain = substr($emailAddress, strpos($emailAddress, '@') + 1); 47 | $emailDomain = trim(strtolower($emailDomain)); 48 | 49 | return $emailDomain; 50 | break; 51 | case 'remote_ip': 52 | $ipList = explode(',', $object->getDataUsingMethod('x_forwarded_for')); 53 | $ipList[] = $object->getDataUsingMethod('remote_ip'); 54 | $ipList = array_unique(array_filter(array_map('trim', $ipList))); 55 | 56 | return $ipList; 57 | break; 58 | default: 59 | return parent::getAttributeValue($object); 60 | } 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /app/code/local/Aoe/FraudManager/Model/Rule/Condition/Order/Item/Found.php: -------------------------------------------------------------------------------- 1 | setType('Aoe_FraudManager/Rule_Condition_Order_Item_Found'); 13 | $this->setName('Product Attribute Combination'); 14 | } 15 | 16 | 17 | /** 18 | * Load value options 19 | * 20 | * @return $this 21 | */ 22 | public function getValueOptions() 23 | { 24 | return [ 25 | 1 => Mage::helper('salesrule')->__('FOUND'), 26 | 0 => Mage::helper('salesrule')->__('NOT FOUND'), 27 | ]; 28 | } 29 | 30 | public function getConditionConfigHtml() 31 | { 32 | $html = $this->translate( 33 | 'If an item is %s in the order with %s of these conditions true:', 34 | $this->getValueElement()->getHtml(), 35 | $this->getAggregatorElement()->getHtml() 36 | ); 37 | 38 | return $html; 39 | } 40 | 41 | /** 42 | * @param Varien_Object $object 43 | * 44 | * @return bool 45 | */ 46 | public function validate(Varien_Object $object) 47 | { 48 | /** @var Mage_Sales_Model_Order $object */ 49 | if (!$object instanceof Mage_Sales_Model_Order) { 50 | return false; 51 | } 52 | 53 | $conditions = $this->getConditions(); 54 | if (empty($conditions)) { 55 | return true; 56 | } 57 | 58 | $all = ($this->getAggregator() === 'all'); 59 | $true = (bool)$this->getValue(); 60 | 61 | $found = false; 62 | foreach ($object->getAllItems() as $item) { 63 | /** @var Mage_Sales_Model_Order_Item $item */ 64 | $found = $all; 65 | foreach ($conditions as $cond) { 66 | $validated = $cond->validate($item); 67 | if ($all !== $validated) { 68 | $found = $validated; 69 | break; 70 | } 71 | } 72 | 73 | if ($found) { 74 | break; 75 | } 76 | } 77 | 78 | // found an item and we're looking for existing one 79 | if ($found && $true) { 80 | return true; 81 | } // not found and we're making sure it doesn't exist 82 | elseif (!$found && !$true) { 83 | return true; 84 | } 85 | 86 | return false; 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /run_tests.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -e 3 | 4 | # check if this is a travis environment 5 | if [ -n "${TRAVIS_BUILD_DIR}" ] ; then 6 | WORKSPACE=${TRAVIS_BUILD_DIR} 7 | fi 8 | 9 | if [ -z "${WORKSPACE}" ] ; then 10 | echo "No workspace configured, please set your WORKSPACE environment" 11 | exit 12 | fi 13 | 14 | # Create a working directory that is removed on exit 15 | function cleanup { 16 | if [ -z "${SKIP_CLEANUP}" -a -n "${BUILDENV}" ]; then 17 | echo "Removing build directory ${BUILDENV}" 18 | rm -rf "${BUILDENV}" 19 | fi 20 | } 21 | trap cleanup EXIT 22 | BUILDENV=`mktemp -d /tmp/buildenv.XXXXXXXX` 23 | echo "Using build directory ${BUILDENV}" 24 | 25 | # Grab the composer package name for the package we are testing 26 | COMPOSER_PACKAGE_NAME=`jq -r '.name' "${WORKSPACE}/composer.json"` 27 | 28 | # Initialize git 29 | echo "Setting git user information" 30 | if [ -z "`git config --get user.name`" ] ; then 31 | git config --global user.name "CI System" 32 | fi 33 | if [ -z "`git config --get user.email`" ] ; then 34 | git config --global user.email "ci@aoe.com" 35 | fi 36 | 37 | # Add a fake version into the composer.json of the package we are testing 38 | jq '. |= .+ {version:"dev-current"}' "${WORKSPACE}/composer.json" > "${WORKSPACE}/composer.json.new" 39 | mv -f "${WORKSPACE}/composer.json.new" "${WORKSPACE}/composer.json" 40 | 41 | # Create artifact with update composer.json 42 | ARTIFACT_NAME=`echo ${COMPOSER_PACKAGE_NAME} | tr / -` 43 | git stash 44 | cd "${WORKSPACE}" 45 | mkdir "${BUILDENV}/artifacts" 46 | git archive -o "${BUILDENV}/artifacts/${ARTIFACT_NAME}.zip" stash@{0} 47 | git stash drop 48 | 49 | # Checkout the testing framework 50 | TESTSTAND="${BUILDENV}/teststand" 51 | mkdir "${TESTSTAND}" 52 | echo "Cloning AOEpeople/MageTestStand into ${TESTSTAND}" 53 | git clone https://github.com/AOEpeople/MageTestStand.git "${TESTSTAND}" 54 | 55 | # Add testing framework to PATH 56 | PATH="${TESTSTAND}/tools:${TESTSTAND}/bin:${PATH}" 57 | 58 | # Update n98-magerun 59 | n98-magerun.phar self-update 60 | 61 | # Update composer 62 | composer.phar self-update 63 | 64 | # Add the artifact repository to the testing framework 65 | echo "Add the artifact repository to the testing framework" 66 | jq ".repositories |= .+ [{type:\"artifact\", url:\"${BUILDENV}/artifacts\"}]" "${TESTSTAND}/composer.json" > "${TESTSTAND}/composer.json.new" 67 | mv -f "${TESTSTAND}/composer.json.new" "${TESTSTAND}/composer.json" 68 | 69 | # Use composer to require the package being tested 70 | cd "${TESTSTAND}" 71 | composer.phar require --no-interaction --no-progress ${COMPOSER_PACKAGE_NAME}:dev-current 72 | 73 | # Use modman to deploy any Magento modules 74 | cd "${TESTSTAND}" 75 | echo "Installing Magento Test Framework" 76 | bash ./install.sh 77 | 78 | # Run PHPUnit 79 | cd "${TESTSTAND}/htdocs" 80 | phpunit --colors -d display_errors=1 81 | -------------------------------------------------------------------------------- /app/code/local/Aoe/FraudManager/Model/Rule/Condition/Order/Address/Compare.php: -------------------------------------------------------------------------------- 1 | ['Full Name', ['==', '!=']], 7 | 'firstname' => ['First Name', ['==', '!=']], 8 | 'lastname' => ['Last Name', ['==', '!=']], 9 | 'street_full' => ['Street', ['==', '!=']], 10 | 'city' => ['City', ['==', '!=']], 11 | 'region' => ['Region', ['==', '!=']], 12 | 'country_id' => ['Country', ['==', '!=']], 13 | 'all' => ['All', ['==', '!=']], 14 | ]; 15 | 16 | protected function _construct() 17 | { 18 | parent::_construct(); 19 | $this->setType('Aoe_FraudManager/Rule_Condition_Order_Address_Compare'); 20 | $this->setName('Compare Billing and Shipping Addresses'); 21 | } 22 | 23 | public function validate(Varien_Object $object) 24 | { 25 | if ($object instanceof Mage_Sales_Model_Order) { 26 | $order = $object; 27 | } elseif ($object instanceof Mage_Sales_Model_Order_Address) { 28 | $order = $object->getOrder(); 29 | } else { 30 | // Cannot test 31 | return false; 32 | } 33 | 34 | /** @var Mage_Sales_Model_Order_Address $object */ 35 | $billingAddress = $order->getBillingAddress(); 36 | $shippingAddress = $order->getShippingAddress(); 37 | 38 | if (!$billingAddress || !$shippingAddress) { 39 | // Cannot test 40 | return false; 41 | } 42 | 43 | $attribute = $this->getAttribute(); 44 | if (empty($attribute)) { 45 | // Cannot test 46 | return false; 47 | } 48 | 49 | return Mage::helper('Aoe_FraudManager/Condition')->validateValue($this->getOperator(), $this->getAttributeValue($billingAddress), $this->getAttributeValue($shippingAddress)); 50 | } 51 | 52 | /** 53 | * @return array 54 | */ 55 | public function getOperatorOptions() 56 | { 57 | $allowedOperators = parent::getOperatorOptions(); 58 | 59 | if (isset($allowedOperators['=='])) { 60 | $allowedOperators['=='] = Mage::helper('Aoe_FraudManager')->__('is the same'); 61 | } 62 | 63 | if (isset($allowedOperators['!='])) { 64 | $allowedOperators['!='] = Mage::helper('Aoe_FraudManager')->__('is not the same'); 65 | } 66 | 67 | return $allowedOperators; 68 | } 69 | 70 | public function getConditionConfigHtml() 71 | { 72 | $html = $this->translate('Billing and Shipping') . ' '; 73 | $html .= $this->getAttributeElement()->getHtml(); 74 | $html .= $this->getOperatorElement()->getHtml(); 75 | $html .= $this->getChooserContainerHtml(); 76 | 77 | return $html; 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /app/code/local/Aoe/FraudManager/Controller/RuleController.php: -------------------------------------------------------------------------------- 1 | getRequest()->getParam('order', $this->getRequest()->getParam('order_id')); 8 | 9 | /** @var Mage_Sales_Model_Order $order */ 10 | $order = Mage::getModel('sales/order')->load($id); 11 | if ($order->isObjectNew()) { 12 | $e = new Mage_Core_Controller_Varien_Exception(); 13 | throw $e->prepareForward('noroute'); 14 | } 15 | 16 | /** @var Aoe_FraudManager_Helper_AbstractRule $helper */ 17 | $helper = $this->getHelper(); 18 | $helper->setCurrentOrder($order); 19 | 20 | $this->loadLayout(); 21 | $this->renderLayout(); 22 | } 23 | 24 | public function conditionAction() 25 | { 26 | if (!$this->getRequest()->isAjax()) { 27 | $this->_forward('noroute'); 28 | 29 | return; 30 | } 31 | 32 | $id = $this->getRequest()->getParam('id'); 33 | $type = explode('|', str_replace('-', '/', $this->getRequest()->getParam('type'))); 34 | 35 | /** @var Aoe_FraudManager_Model_Rule_Condition_Interface $condition */ 36 | $condition = Mage::getModel($type[0]); 37 | if (!$condition instanceof Aoe_FraudManager_Model_Rule_Condition_Interface) { 38 | $this->_forward('noroute'); 39 | 40 | return; 41 | } 42 | 43 | /** @var Aoe_FraudManager_Model_Rule_Abstract $rule */ 44 | $rule = $this->getHelper()->getModel(); 45 | 46 | $condition->setId($id); 47 | $condition->setRule($rule); 48 | if (is_callable([$condition, 'setJsFormObject'])) { 49 | $condition->setJsFormObject($this->getRequest()->getParam('form')); 50 | } 51 | if (isset($type[1]) && is_callable([$condition, 'setAttribute'])) { 52 | $condition->setAttribute($type[1]); 53 | } 54 | 55 | $this->getResponse()->setBody($condition->getHtml()); 56 | } 57 | 58 | /** 59 | * Pre-process the POST data before adding to the model 60 | * 61 | * @param array $postData 62 | * 63 | * @return array 64 | */ 65 | protected function preprocessPostData(array $postData) 66 | { 67 | $postData = parent::preprocessPostData($postData); 68 | 69 | if (isset($postData['rule']) && is_array($postData['rule'])) { 70 | $rule = $this->getHelper()->convertFlatToRecursive($postData['rule'], ['conditions']); 71 | unset($postData['rule']); 72 | if (isset($rule['conditions'])) { 73 | $postData['conditions'] = reset($rule['conditions']); 74 | } 75 | } 76 | 77 | return $postData; 78 | } 79 | 80 | protected function getAclActionName() 81 | { 82 | $action = Aoe_Layout_Controller_Model::getAclActionName(); 83 | 84 | if ($action === 'testOrder') { 85 | $action = 'test'; 86 | } elseif ($action !== 'view') { 87 | $action = 'edit'; 88 | } 89 | 90 | return $action; 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /app/code/local/Aoe/FraudManager/Model/Rule/Abstract.php: -------------------------------------------------------------------------------- 1 | getData('conditions'); 27 | if (!$conditions instanceof Aoe_FraudManager_Model_Rule_Condition_Root) { 28 | if (is_array($conditions) && isset($conditions['type'])) { 29 | $root = Mage::getModel($conditions['type']); 30 | if (!$root instanceof Aoe_FraudManager_Model_Rule_Condition_Root) { 31 | Mage::throwException('Invalid parameter'); 32 | } 33 | $root->setRule($this); 34 | $root->loadArray($conditions); 35 | } else { 36 | $root = Mage::getModel('Aoe_FraudManager/Rule_Condition_Root'); 37 | $root->setRule($this); 38 | } 39 | 40 | $this->setData('conditions', $root); 41 | $conditions = $root; 42 | } 43 | 44 | return $conditions; 45 | } 46 | 47 | /** 48 | * Set rule combine conditions model 49 | * 50 | * @param Aoe_FraudManager_Model_Rule_Condition_Root|array $conditions 51 | * 52 | * @return $this 53 | */ 54 | public function setConditions($conditions) 55 | { 56 | if ($conditions instanceof Aoe_FraudManager_Model_Rule_Condition_Root) { 57 | $this->root = $conditions; 58 | $this->setData('conditions', $this->root); 59 | } elseif (is_array($conditions)) { 60 | $this->setData('conditions', $conditions); 61 | $this->getConditions(); 62 | } else { 63 | Mage::throwException('Invalid parameter'); 64 | } 65 | 66 | return $this; 67 | } 68 | 69 | /** 70 | * Rule form getter 71 | * 72 | * @return Varien_Data_Form 73 | */ 74 | public function getConditionsForm() 75 | { 76 | if (!$this->conditionsForm) { 77 | $this->conditionsForm = new Varien_Data_Form(); 78 | $this->conditionsForm->setHtmlIdPrefix('rule__conditions__'); 79 | $this->conditionsForm->setFieldNameSuffix('rule[conditions]'); 80 | $this->conditionsForm->addType('select', Mage::getConfig()->getModelClassName('Aoe_FraudManager/Form_Element_Select')); 81 | } 82 | 83 | return $this->conditionsForm; 84 | } 85 | 86 | /** 87 | * Validate rule conditions to determine if rule can run 88 | * 89 | * @param Varien_Object $object 90 | * 91 | * @return bool 92 | */ 93 | public function validate(Varien_Object $object) 94 | { 95 | return $this->getConditions()->validate($object); 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /app/code/local/Aoe/FraudManager/sql/Aoe_FraudManager/upgrade-0.1.0-0.2.0.php: -------------------------------------------------------------------------------- 1 | startSetup(); 4 | 5 | $this->getConnection()->dropTable($this->getTable('Aoe_FraudManager/BlacklistRule')); 6 | $this->getConnection()->dropTable($this->getTable('Aoe_FraudManager/HoldRule')); 7 | 8 | $table = $this->getConnection()->newTable($this->getTable('Aoe_FraudManager/BlacklistRule')); 9 | $table->addColumn( 10 | 'id', 11 | Varien_Db_Ddl_Table::TYPE_INTEGER, 12 | null, 13 | [ 14 | 'primary' => true, 15 | 'identity' => true, 16 | 'unsigned' => true, 17 | 'nullable' => false, 18 | ] 19 | ); 20 | $table->addColumn( 21 | 'name', 22 | Varien_Db_Ddl_Table::TYPE_TEXT, 23 | pow(2, 8) - 1, 24 | ['nullable' => false] 25 | ); 26 | $table->addColumn( 27 | 'description', 28 | Varien_Db_Ddl_Table::TYPE_TEXT, 29 | pow(2, 16) - 1 30 | ); 31 | $table->addColumn( 32 | 'message', 33 | Varien_Db_Ddl_Table::TYPE_TEXT, 34 | pow(2, 16) - 1 35 | ); 36 | $table->addColumn( 37 | 'stop_processing', 38 | Varien_Db_Ddl_Table::TYPE_BOOLEAN, 39 | null, 40 | ['nullable' => false] 41 | ); 42 | $table->addColumn( 43 | 'is_active', 44 | Varien_Db_Ddl_Table::TYPE_BOOLEAN, 45 | null, 46 | ['nullable' => false] 47 | ); 48 | $table->addColumn( 49 | 'conditions', 50 | Varien_Db_Ddl_Table::TYPE_TEXT, 51 | pow(2, 32) - 1 52 | ); 53 | $table->addColumn( 54 | 'website_ids', 55 | Varien_Db_Ddl_Table::TYPE_TEXT, 56 | pow(2, 16) - 1 57 | ); 58 | $table->addColumn( 59 | 'sort_order', 60 | Varien_Db_Ddl_Table::TYPE_INTEGER, 61 | null, 62 | ['nullable' => false] 63 | ); 64 | $table->addIndex( 65 | $this->getIdxName('Aoe_FraudManager/BlacklistRule', ['is_active']), 66 | ['is_active'] 67 | ); 68 | $this->getConnection()->createTable($table); 69 | 70 | $table = $this->getConnection()->newTable($this->getTable('Aoe_FraudManager/HoldRule')); 71 | $table->addColumn( 72 | 'id', 73 | Varien_Db_Ddl_Table::TYPE_INTEGER, 74 | null, 75 | [ 76 | 'primary' => true, 77 | 'identity' => true, 78 | 'unsigned' => true, 79 | 'nullable' => false, 80 | ] 81 | ); 82 | $table->addColumn( 83 | 'name', 84 | Varien_Db_Ddl_Table::TYPE_TEXT, 85 | pow(2, 8) - 1, 86 | ['nullable' => false] 87 | ); 88 | $table->addColumn( 89 | 'description', 90 | Varien_Db_Ddl_Table::TYPE_TEXT, 91 | pow(2, 16) - 1 92 | ); 93 | $table->addColumn( 94 | 'status', 95 | Varien_Db_Ddl_Table::TYPE_TEXT, 96 | 32, 97 | ['nullable' => true] 98 | ); 99 | $table->addColumn( 100 | 'stop_processing', 101 | Varien_Db_Ddl_Table::TYPE_BOOLEAN, 102 | null, 103 | ['nullable' => false] 104 | ); 105 | $table->addColumn( 106 | 'is_active', 107 | Varien_Db_Ddl_Table::TYPE_BOOLEAN, 108 | null, 109 | ['nullable' => false] 110 | ); 111 | $table->addColumn( 112 | 'conditions', 113 | Varien_Db_Ddl_Table::TYPE_TEXT, 114 | pow(2, 32) - 1 115 | ); 116 | $table->addColumn( 117 | 'website_ids', 118 | Varien_Db_Ddl_Table::TYPE_TEXT, 119 | pow(2, 16) - 1 120 | ); 121 | $table->addColumn( 122 | 'sort_order', 123 | Varien_Db_Ddl_Table::TYPE_INTEGER, 124 | null, 125 | ['nullable' => false] 126 | ); 127 | $table->addIndex( 128 | $this->getIdxName('Aoe_FraudManager/HoldRule', ['is_active']), 129 | ['is_active'] 130 | ); 131 | $this->getConnection()->createTable($table); 132 | 133 | $this->endSetup(); 134 | -------------------------------------------------------------------------------- /app/code/local/Aoe/FraudManager/controllers/Sales/OrderController.php: -------------------------------------------------------------------------------- 1 | getHelper(); 11 | $order = $this->initOrder(); 12 | try { 13 | if ($this->getRequest()->isPost() || !$helper->isSetFlagCommentRequired($order)) { 14 | $comment = trim($this->getRequest()->getPost('comment')); 15 | if ($helper->setFlag($order, $comment)) { 16 | $this->_getSession()->addSuccess($this->__('Marked order as fraud')); 17 | } 18 | $this->redirectToOrderView($order); 19 | } else { 20 | $this->loadLayout(); 21 | $this->_setActiveMenu('sales/order'); 22 | $this->_addBreadcrumb($this->__('Sales'), $this->__('Sales')); 23 | $this->_addBreadcrumb($this->__('Orders'), $this->__('Orders')); 24 | $this->renderLayout(); 25 | } 26 | } catch (Exception $e) { 27 | Mage::logException($e); 28 | $this->_getSession()->addError($e->getMessage()); 29 | $this->redirectToOrderView($order); 30 | } 31 | } 32 | 33 | public function removeFraudFlagAction() 34 | { 35 | $helper = $this->getHelper(); 36 | $order = $this->initOrder(); 37 | try { 38 | if ($this->getRequest()->isPost() || !$helper->isRemoveFlagCommentRequired($order)) { 39 | $comment = trim($this->getRequest()->getPost('comment')); 40 | if ($helper->removeFlag($order, $comment)) { 41 | $this->_getSession()->addSuccess($this->__('Marked order as NOT fraud')); 42 | } 43 | $this->redirectToOrderView($order); 44 | } else { 45 | $this->loadLayout(); 46 | $this->_setActiveMenu('sales/order'); 47 | $this->_addBreadcrumb($this->__('Sales'), $this->__('Sales')); 48 | $this->_addBreadcrumb($this->__('Orders'), $this->__('Orders')); 49 | $this->renderLayout(); 50 | } 51 | } catch (Exception $e) { 52 | Mage::logException($e); 53 | $this->_getSession()->addError($e->getMessage()); 54 | $this->redirectToOrderView($order); 55 | } 56 | } 57 | 58 | /** 59 | * @return Mage_Sales_Model_Order 60 | * 61 | * @throws Mage_Core_Controller_Varien_Exception 62 | */ 63 | protected function initOrder() 64 | { 65 | $id = $this->getRequest()->getParam('order', $this->getRequest()->getParam('order_id')); 66 | 67 | /** @var Mage_Sales_Model_Order $order */ 68 | $order = Mage::getModel('sales/order')->load($id); 69 | if ($order->isObjectNew()) { 70 | $e = new Mage_Core_Controller_Varien_Exception(); 71 | throw $e->prepareForward('noroute'); 72 | } 73 | 74 | $this->getHelper()->setCurrentOrder($order); 75 | 76 | return $order; 77 | } 78 | 79 | /** 80 | * Issue a redirect to the order view page 81 | * 82 | * @param Mage_Sales_Model_Order $order 83 | * 84 | * @return $this 85 | */ 86 | protected function redirectToOrderView(Mage_Sales_Model_Order $order) 87 | { 88 | return $this->_redirect('adminhtml/sales_order/view', ['order_id' => $order->getId()]); 89 | } 90 | 91 | /** 92 | * @return Aoe_FraudManager_Helper_FraudFlag 93 | */ 94 | protected function getHelper() 95 | { 96 | return Mage::helper('Aoe_FraudManager/FraudFlag'); 97 | } 98 | 99 | /** 100 | * ACL check 101 | * 102 | * @return bool 103 | */ 104 | protected function _isAllowed() 105 | { 106 | $order = $this->initOrder(); 107 | $allowed = false; 108 | 109 | $action = lcfirst($this->getRequest()->getActionName()); 110 | switch ($action) { 111 | case 'setFraudFlag': 112 | $allowed = $this->getHelper()->isSetFlagActionAllowed($order); 113 | break; 114 | case 'removeFraudFlag': 115 | $allowed = $this->getHelper()->isRemoveFlagActionAllowed($order); 116 | break; 117 | } 118 | 119 | return $allowed; 120 | } 121 | } 122 | -------------------------------------------------------------------------------- /app/code/local/Aoe/FraudManager/Model/Rule/Condition/Abstract.php: -------------------------------------------------------------------------------- 1 | getData('type'); 24 | } 25 | 26 | public function getName() 27 | { 28 | return $this->getData('name'); 29 | } 30 | 31 | /** 32 | * @return Aoe_FraudManager_Model_Rule_Abstract 33 | */ 34 | public function getRule() 35 | { 36 | return parent::getRule(); 37 | } 38 | 39 | /** 40 | * @param Aoe_FraudManager_Model_Rule_Abstract $rule 41 | * 42 | * @return $this 43 | */ 44 | public function setRule(Aoe_FraudManager_Model_Rule_Abstract $rule) 45 | { 46 | return parent::setRule($rule); 47 | } 48 | 49 | /** 50 | * @return Varien_Data_Form 51 | */ 52 | public function getForm() 53 | { 54 | return $this->getRule()->getConditionsForm(); 55 | } 56 | 57 | /** 58 | * @param Varien_Object $object 59 | * 60 | * @return bool 61 | */ 62 | abstract public function validate(Varien_Object $object); 63 | 64 | //================================================== 65 | //=[ HTML Generation ]============================== 66 | //================================================== 67 | 68 | public function getHtml() 69 | { 70 | $html = $this->getTypeElement()->getHtml(); 71 | $html .= $this->getConditionConfigHtml(); 72 | $html .= $this->getRemoveLinkHtml(); 73 | 74 | return $html; 75 | } 76 | 77 | public function getTypeElement() 78 | { 79 | $element = $this->getForm()->addField( 80 | $this->getId() . '__type', 81 | 'hidden', 82 | [ 83 | 'name' => $this->getId() . '[type]', 84 | 'value' => $this->getType(), 85 | 'no_span' => true, 86 | 'class' => 'hidden', 87 | ] 88 | ); 89 | 90 | return $element; 91 | } 92 | 93 | abstract public function getConditionConfigHtml(); 94 | 95 | public function getRemoveLinkHtml() 96 | { 97 | $src = Mage::getDesign()->getSkinUrl('images/rule_component_remove.gif'); 98 | $html = ' '; 99 | 100 | return $html; 101 | } 102 | 103 | //================================================== 104 | //=[ Serialization / Deserialization ]============== 105 | //================================================== 106 | 107 | public function toArray(array $attributes = []) 108 | { 109 | $out = []; 110 | 111 | foreach ($this->arrayKeys as $key) { 112 | $out[$key] = $this->getDataUsingMethod($key); 113 | } 114 | 115 | return $out; 116 | } 117 | 118 | public function loadArray(array $data) 119 | { 120 | if (isset($data['type'])) { 121 | if ($data['type'] != $this->getType()) { 122 | Mage::throwException('Invalid parameter'); 123 | } 124 | unset($data['type']); 125 | } 126 | 127 | foreach ($this->arrayKeys as $key) { 128 | if (array_key_exists($key, $data)) { 129 | $this->setDataUsingMethod($key, $data[$key]); 130 | } 131 | } 132 | 133 | return $this; 134 | } 135 | 136 | //================================================== 137 | //=[ Extras ]======================================= 138 | //================================================== 139 | 140 | /** 141 | * Translate 142 | * 143 | * @return string 144 | */ 145 | protected function translate() 146 | { 147 | if (!$this->moduleName) { 148 | $class = get_class($this); 149 | $this->moduleName = substr($class, 0, strpos($class, '_Model')); 150 | } 151 | 152 | $args = func_get_args(); 153 | $expr = new Mage_Core_Model_Translate_Expr(array_shift($args), $this->moduleName); 154 | array_unshift($args, $expr); 155 | 156 | return Mage::app()->getTranslator()->translate($args); 157 | } 158 | } 159 | -------------------------------------------------------------------------------- /app/code/local/Aoe/FraudManager/Resource/Abstract.php: -------------------------------------------------------------------------------- 1 | serializeFields($object); 13 | } 14 | 15 | /** 16 | * Serialize serializable fields of the object 17 | * 18 | * @param Mage_Core_Model_Abstract $object 19 | */ 20 | public function serializeFields(Mage_Core_Model_Abstract $object) 21 | { 22 | foreach ($this->_serializableFields as $field => $parameters) { 23 | if (count($parameters) >= 2) { 24 | $serializeDefault = $parameters[0]; 25 | if (count($parameters) > 3) { 26 | $unsetEmpty = (bool)$parameters[2]; 27 | $callback = $parameters[3]; 28 | } else { 29 | $unsetEmpty = isset($parameters[2]); 30 | $callback = null; 31 | } 32 | $this->_serializeField($object, $field, $serializeDefault, $unsetEmpty, $callback); 33 | } 34 | } 35 | } 36 | 37 | 38 | /** 39 | * Unserialize serializable object fields 40 | * 41 | * @param Mage_Core_Model_Abstract $object 42 | */ 43 | public function unserializeFields(Mage_Core_Model_Abstract $object) 44 | { 45 | foreach ($this->_serializableFields as $field => $parameters) { 46 | if (count($parameters) >= 2) { 47 | $unserializeDefault = $parameters[1]; 48 | if (count($parameters) > 4) { 49 | $callback = $parameters[4]; 50 | } else { 51 | $callback = null; 52 | } 53 | $this->_unserializeField($object, $field, $unserializeDefault, $callback); 54 | } 55 | } 56 | } 57 | 58 | public static function implodeArray($value) 59 | { 60 | if (is_array($value)) { 61 | $value = implode(",", $value); 62 | } else { 63 | $value = (string)$value; 64 | } 65 | 66 | return $value; 67 | } 68 | 69 | public static function explodeArray($value) 70 | { 71 | if (is_string($value)) { 72 | $value = array_filter(array_map('trim', explode(",", $value))); 73 | } else { 74 | $value = []; 75 | } 76 | 77 | return $value; 78 | } 79 | 80 | /** 81 | * Serialize specified field in an object 82 | * 83 | * @param Varien_Object $object 84 | * @param string $field 85 | * @param null $defaultValue 86 | * @param bool $unsetEmpty 87 | * @param callable $callback 88 | * 89 | * @return $this 90 | */ 91 | protected function _serializeField(Varien_Object $object, $field, $defaultValue = null, $unsetEmpty = false, $callback = null) 92 | { 93 | if (!is_callable($callback)) { 94 | $callback = 'serialize'; 95 | } 96 | 97 | $value = $object->getData($field); 98 | if (empty($value)) { 99 | if ($unsetEmpty) { 100 | $object->unsetData($field); 101 | } else { 102 | if (is_object($defaultValue) || is_array($defaultValue)) { 103 | $defaultValue = call_user_func($callback, $defaultValue); 104 | } 105 | $object->setData($field, $defaultValue); 106 | } 107 | } elseif (is_array($value) || is_object($value)) { 108 | $object->setData($field, call_user_func($callback, $value)); 109 | } 110 | 111 | return $this; 112 | } 113 | 114 | /** 115 | * Unserialize Varien_Object field in an object 116 | * 117 | * @param Varien_Object $object 118 | * @param string $field 119 | * @param mixed $defaultValue 120 | * @param callable $callback 121 | */ 122 | protected function _unserializeField(Varien_Object $object, $field, $defaultValue = null, $callback = null) 123 | { 124 | if (!is_callable($callback)) { 125 | $callback = 'unserialize'; 126 | } 127 | 128 | $value = $object->getData($field); 129 | if (empty($value)) { 130 | $object->setData($field, $defaultValue); 131 | } elseif (!is_array($value) && !is_object($value)) { 132 | $object->setData($field, call_user_func($callback, $value)); 133 | } 134 | } 135 | 136 | /** 137 | * Prepare data for save 138 | * 139 | * @param Mage_Core_Model_Abstract $object 140 | * 141 | * @return array 142 | */ 143 | protected function _prepareDataForSave(Mage_Core_Model_Abstract $object) 144 | { 145 | $currentTime = Varien_Date::now(); 146 | if ((!$object->getId() || $object->isObjectNew()) && !$object->getCreatedAt()) { 147 | $object->setCreatedAt($currentTime); 148 | } 149 | $object->setUpdatedAt($currentTime); 150 | $data = parent::_prepareDataForSave($object); 151 | 152 | return $data; 153 | } 154 | } 155 | -------------------------------------------------------------------------------- /app/code/local/Aoe/FraudManager/etc/adminhtml.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | AOE Fraud Manager 8 | 35 9 | 10 | 11 | Blacklist Rules 12 | adminhtml/fraudManager_blacklistRule 13 | 100 14 | 15 | 16 | Hold Rules 17 | adminhtml/fraudManager_holdRule 18 | 200 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | Set Fraud Flag 37 | 38 | 39 | Remove Fraud Flag 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | AOE Fraud Manager 51 | 35 52 | 53 | 54 | Blacklist Rules 55 | 100 56 | 57 | 58 | View 59 | 100 60 | 61 | 62 | Edit 63 | 200 64 | 65 | 66 | Test 67 | 300 68 | 69 | 70 | 71 | 72 | Hold Rules 73 | 200 74 | 75 | 76 | View 77 | 100 78 | 79 | 80 | Edit 81 | 200 82 | 83 | 84 | Test 85 | 300 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | AOE Fraud Manager 95 | 9999 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | -------------------------------------------------------------------------------- /app/code/local/Aoe/FraudManager/etc/config.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 1.1.0 6 | 7 | 8 | 9 | 10 | 11 | Aoe_FraudManager_Helper 12 | 13 | 14 | 15 | 16 | Aoe_FraudManager_Block 17 | 18 | 19 | 20 | 21 | Aoe_FraudManager_Model 22 | Aoe_FraudManager_Resource 23 | 24 | 25 | Aoe_FraudManager_Resource 26 | 27 | 28 | aoe_fraudmanager_blacklist_rule
29 |
30 | 31 | aoe_fraudmanager_hold_rule
32 |
33 |
34 |
35 |
36 | 37 | 38 | 39 | Aoe_FraudManager 40 | 41 | 42 | 43 | 57 |
58 | 59 | 60 | 61 | 62 | 63 | Aoe_FraudManager 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | Aoe_FraudManager.csv 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | Aoe_FraudManager.xml 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | Aoe_FraudManager/Observer 91 | addOrderConditions 92 | 93 | 94 | 95 | 96 | 97 | 98 | Aoe_FraudManager/Observer 99 | addOrderItemConditions 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | Aoe_FraudManager/Observer 111 | checkQuoteSubmitBefore 112 | 113 | 114 | 115 | 116 | 117 | 118 | Aoe_FraudManager/Observer 119 | checkQuoteSubmitSuccess 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | An error occurred while placing your order. 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 |
140 | -------------------------------------------------------------------------------- /app/code/local/Aoe/FraudManager/Helper/Condition.php: -------------------------------------------------------------------------------- 1 | getSkinUrl('images/rule_component_apply.gif'); 10 | } 11 | 12 | public function getConditionApplyLabel() 13 | { 14 | return $this->__('Apply'); 15 | } 16 | 17 | public function getOperators(array $filter = []) 18 | { 19 | if ($this->operators === null) { 20 | $this->operators = [ 21 | '==' => $this->__('is'), 22 | '!=' => $this->__('is not'), 23 | '>=' => $this->__('equals or greater than'), 24 | '<=' => $this->__('equals or less than'), 25 | '>' => $this->__('greater than'), 26 | '<' => $this->__('less than'), 27 | '{}' => $this->__('contains'), 28 | '!{}' => $this->__('does not contain'), 29 | '()' => $this->__('is one of'), 30 | '!()' => $this->__('is not one of'), 31 | 'RE' => $this->__('matches regex pattern'), 32 | ]; 33 | } 34 | 35 | if (empty($filter)) { 36 | return $this->operators; 37 | } else { 38 | $operators = $this->operators; 39 | $operators = array_intersect_key($operators, array_flip($filter)); 40 | 41 | return $operators; 42 | } 43 | } 44 | 45 | /** 46 | * @param $operator 47 | * @param $expectedValue 48 | * @param $actualValue 49 | * 50 | * @return bool 51 | */ 52 | public function validateValue($operator, $expectedValue, $actualValue) 53 | { 54 | $result = false; 55 | $invertResult = false; 56 | 57 | switch ($operator) { 58 | case '!=': 59 | $invertResult = true; 60 | // Fall-through 61 | case '==': 62 | if (is_array($expectedValue)) { 63 | if (is_array($actualValue)) { 64 | $result = array_intersect($expectedValue, $actualValue); 65 | $result = !empty($result); 66 | } else { 67 | return false; 68 | } 69 | } else { 70 | if (is_array($actualValue)) { 71 | $result = count($actualValue) == 1 && array_shift($actualValue) == $expectedValue; 72 | } else { 73 | $result = $this->compareValues($actualValue, $expectedValue); 74 | } 75 | } 76 | break; 77 | 78 | case '>': 79 | $invertResult = true; 80 | // Fall-through 81 | case '<=': 82 | if (!is_scalar($actualValue)) { 83 | return false; 84 | } 85 | $result = $actualValue <= $expectedValue; 86 | break; 87 | 88 | case '<': 89 | $invertResult = true; 90 | // Fall-through 91 | case '>=': 92 | if (!is_scalar($actualValue)) { 93 | return false; 94 | } 95 | $result = $actualValue >= $expectedValue; 96 | break; 97 | 98 | case '!{}': 99 | $invertResult = true; 100 | // Fall-through 101 | case '{}': 102 | // We don't support non-scalar values for the expected value on a 'contains' comparison 103 | if (!is_scalar($expectedValue)) { 104 | return false; 105 | } 106 | if (is_array($actualValue)) { 107 | foreach ($actualValue as $currentActualValue) { 108 | if ($this->compareValues($expectedValue, $currentActualValue, false)) { 109 | $result = true; 110 | break; 111 | } 112 | } 113 | } else { 114 | $result = $this->compareValues($expectedValue, $actualValue, false); 115 | } 116 | break; 117 | 118 | case '!()': 119 | $invertResult = true; 120 | // Fall-through 121 | case '()': 122 | if (is_array($actualValue)) { 123 | $result = (count(array_intersect($actualValue, (array)$expectedValue)) > 0); 124 | } else { 125 | $expectedValue = (array)$expectedValue; 126 | foreach ($expectedValue as $item) { 127 | if ($this->compareValues($item, $actualValue)) { 128 | $result = true; 129 | break; 130 | } 131 | } 132 | } 133 | break; 134 | 135 | case 'RE': 136 | $result = preg_match($expectedValue, $actualValue); 137 | if ($result === false) { 138 | Mage::throwException('Error running regex pattern (' . preg_last_error() . ').'); 139 | } 140 | $result = (bool)$result; 141 | break; 142 | } 143 | 144 | if ($invertResult) { 145 | $result = !$result; 146 | } 147 | 148 | return $result; 149 | } 150 | 151 | /** 152 | * Case and type insensitive comparison of values 153 | * 154 | * @param string|int|float $expectedValue 155 | * @param string|int|float $actualValue 156 | * 157 | * @return bool 158 | */ 159 | protected function compareValues($expectedValue, $actualValue, $strict = true) 160 | { 161 | if ($strict && is_numeric($expectedValue) && is_numeric($actualValue)) { 162 | return $expectedValue == $actualValue; 163 | } else { 164 | $validatePattern = preg_quote($expectedValue, '~'); 165 | if ($strict) { 166 | $validatePattern = '^' . $validatePattern . '$'; 167 | } 168 | 169 | return (bool)preg_match('~' . $validatePattern . '~iu', $actualValue); 170 | } 171 | } 172 | } 173 | -------------------------------------------------------------------------------- /app/code/local/Aoe/FraudManager/Helper/HoldRule.php: -------------------------------------------------------------------------------- 1 | getAdminSession()->isAllowed(self::ACL_PREFIX . trim($action, ' /')); 34 | } 35 | 36 | /** 37 | * @return string 38 | */ 39 | public function getCurrentRecordKey() 40 | { 41 | return 'aoe_fraudmanager_hold_rule_CURRENT'; 42 | } 43 | 44 | /** 45 | * Get a model instance 46 | * 47 | * @return Aoe_FraudManager_Model_HoldRule 48 | */ 49 | public function getModel() 50 | { 51 | return Mage::getModel('Aoe_FraudManager/HoldRule'); 52 | } 53 | 54 | /** 55 | * @return Varien_Data_Form 56 | */ 57 | public function getMainForm($rule = null) 58 | { 59 | $form = parent::getMainForm($rule); 60 | 61 | /** @var Aoe_FraudManager_Model_HoldRule $rule */ 62 | if (!$rule) { 63 | $rule = $this->getCurrentRecord(); 64 | } 65 | 66 | /** @var Varien_Data_Form_Element_Fieldset $fieldset */ 67 | $fieldset = $form->getElement('base_fieldset'); 68 | 69 | $fieldset->addField( 70 | 'status', 71 | 'select', 72 | [ 73 | 'label' => $this->__('Status'), 74 | 'title' => $this->__('Status'), 75 | 'name' => 'status', 76 | 'required' => true, 77 | 'options' => $this->getSourceModelHash('Aoe_FraudManager/Config_Source_Order_HoldStatuses'), 78 | ], 79 | 'description' 80 | ); 81 | 82 | $form->addValues($rule->getData()); 83 | 84 | return $form; 85 | } 86 | 87 | /** 88 | * Test an order against all of the rules 89 | * 90 | * @param Mage_Sales_Model_Order $order 91 | * 92 | * @return Varien_Data_Collection 93 | */ 94 | public function testOrder(Mage_Sales_Model_Order $order) 95 | { 96 | $collection = new Varien_Data_Collection(); 97 | 98 | /** @var Aoe_FraudManager_Resource_HoldRule_Collection $rules */ 99 | $rules = Mage::getSingleton('Aoe_FraudManager/HoldRule') 100 | ->getCollection() 101 | ->filterValidForOrder($order, true); 102 | 103 | /** @var Mage_Sales_Model_Order_Config $salesConfig */ 104 | $salesConfig = Mage::getSingleton('sales/order_config'); 105 | 106 | $skip = false; 107 | foreach ($rules as $rule) { 108 | /** @var Aoe_FraudManager_Model_HoldRule $rule */ 109 | 110 | $timing = microtime(true); 111 | $rule->setData('triggered', $rule->validate($order)); 112 | $timing = microtime(true) - $timing; 113 | 114 | $rule->setData('timing', round($timing * 1000)); 115 | 116 | $status = $rule->getData('status'); 117 | $allowedStatuses = $salesConfig->getStateStatuses(Mage_Sales_Model_Order::STATE_HOLDED, false); 118 | if (!in_array($status, $allowedStatuses)) { 119 | $status = $salesConfig->getStateDefaultStatus(Mage_Sales_Model_Order::STATE_HOLDED); 120 | } 121 | $rule->setData('status', $status); 122 | 123 | $rule->setData('skipped', $skip); 124 | 125 | $collection->addItem($collection->getNewEmptyItem()->setData($rule->toArray())); 126 | 127 | $skip = $skip || ((bool)$rule->getData('stop_processing') && $rule->getData('triggered')); 128 | } 129 | 130 | return $collection; 131 | } 132 | 133 | /** 134 | * Email notification for hold rule activation 135 | * 136 | * @param string $message 137 | * @param array $extraVariables 138 | * @param int|string|null $store 139 | * 140 | * @return $this 141 | */ 142 | public function notify($message, array $extraVariables = [], $store = null) 143 | { 144 | $store = Mage::app()->getStore($store); 145 | 146 | // Sender identity code 147 | $sender = Mage::getStoreConfig(self::XML_PATH_NOTIFICATION_EMAIL_SENDER, $store); 148 | if (!$sender) { 149 | return $this; 150 | } 151 | 152 | // Receiver identity code 153 | $receiver = Mage::getStoreConfig(self::XML_PATH_NOTIFICATION_EMAIL_RECEIVER, $store); 154 | if (!$receiver) { 155 | return $this; 156 | } 157 | 158 | // Template ID 159 | $templateId = Mage::getStoreConfig(self::XML_PATH_NOTIFICATION_EMAIL_TEMPLATE, $store); 160 | if (!$templateId) { 161 | return $this; 162 | } 163 | 164 | /** @var Mage_Core_Model_Email_Info $emailInfo */ 165 | $emailInfo = Mage::getModel('core/email_info'); 166 | $emailInfo->addTo( 167 | Mage::getStoreConfig("trans_email/ident_{$receiver}/email", $store), 168 | Mage::getStoreConfig("trans_email/ident_{$receiver}/name", $store) 169 | ); 170 | 171 | /** @var $mailer Mage_Core_Model_Email_Template_Mailer */ 172 | $mailer = Mage::getModel('core/email_template_mailer'); 173 | $mailer->addEmailInfo($emailInfo); 174 | 175 | // Set all required params and send emails 176 | $mailer->setStoreId($store->getId()); 177 | $mailer->setSender($sender); 178 | $mailer->setTemplateId($templateId); 179 | $mailer->setTemplateParams($extraVariables + ['message' => $message]); 180 | $mailer->send(); 181 | 182 | return $this; 183 | } 184 | } 185 | -------------------------------------------------------------------------------- /app/code/local/Aoe/FraudManager/Helper/BlacklistRule.php: -------------------------------------------------------------------------------- 1 | getStore($store); 26 | 27 | /** @var Varien_Filter_Template $filter */ 28 | $filter = Mage::getModel(Mage::getStoreConfig(self::XML_PATH_FILTER_MODEL, $store)); 29 | if (!$filter instanceof Varien_Filter_Template) { 30 | $filter = Mage::getModel('core/email_template_filter'); 31 | } 32 | if (method_exists($filter, 'setStoreId')) { 33 | $filter->setStoreId($store->getId()); 34 | } 35 | 36 | return $filter->filter($message); 37 | } 38 | 39 | /** 40 | * Get the frontname and controller portion of the route 41 | * 42 | * @return string 43 | */ 44 | protected function getControllerRoute() 45 | { 46 | return 'adminhtml/fraudManager_blacklistRule'; 47 | } 48 | 49 | /** 50 | * @param $action 51 | * 52 | * @return bool 53 | */ 54 | public function getAclPermission($action) 55 | { 56 | return $this->getAdminSession()->isAllowed(self::ACL_PREFIX . trim($action, ' /')); 57 | } 58 | 59 | /** 60 | * @return string 61 | */ 62 | public function getCurrentRecordKey() 63 | { 64 | return 'aoe_fraudmanager_blacklist_rule_CURRENT'; 65 | } 66 | 67 | /** 68 | * Get a model instance 69 | * 70 | * @return Aoe_FraudManager_Model_BlacklistRule 71 | */ 72 | public function getModel() 73 | { 74 | return Mage::getModel('Aoe_FraudManager/BlacklistRule'); 75 | } 76 | 77 | /** 78 | * @return Varien_Data_Form 79 | */ 80 | public function getMainForm($rule = null) 81 | { 82 | $form = parent::getMainForm($rule); 83 | 84 | /** @var Aoe_FraudManager_Model_BlacklistRule $rule */ 85 | if (!$rule) { 86 | $rule = $this->getCurrentRecord(); 87 | } 88 | 89 | /** @var Varien_Data_Form_Element_Fieldset $fieldset */ 90 | $fieldset = $form->getElement('base_fieldset'); 91 | 92 | $fieldset->addField( 93 | 'message', 94 | 'textarea', 95 | [ 96 | 'name' => 'message', 97 | 'label' => $this->__('Message'), 98 | 'title' => $this->__('Message'), 99 | 'comment' => $this->__('Message sent to customer when this rule is activated'), 100 | 'style' => 'height: 100px;', 101 | 'required' => false, 102 | ], 103 | 'description' 104 | ); 105 | 106 | $form->addValues($rule->getData()); 107 | 108 | return $form; 109 | } 110 | 111 | /** 112 | * Test an order against all of the rules 113 | * 114 | * @param Mage_Sales_Model_Order $order 115 | * 116 | * @return Varien_Data_Collection 117 | */ 118 | public function testOrder(Mage_Sales_Model_Order $order) 119 | { 120 | $collection = new Varien_Data_Collection(); 121 | 122 | /** @var Aoe_FraudManager_Helper_BlacklistRule $helper */ 123 | $helper = Mage::helper('Aoe_FraudManager/BlacklistRule'); 124 | 125 | /** @var Aoe_FraudManager_Resource_BlacklistRule_Collection $rules */ 126 | $rules = Mage::getSingleton('Aoe_FraudManager/BlacklistRule') 127 | ->getCollection() 128 | ->filterValidForOrder($order, true); 129 | 130 | foreach ($rules as $rule) { 131 | /** @var Aoe_FraudManager_Model_BlacklistRule $rule */ 132 | 133 | $timing = microtime(true); 134 | $rule->setData('triggered', $rule->validate($order)); 135 | $timing = microtime(true) - $timing; 136 | 137 | $rule->setData('timing', round($timing * 1000)); 138 | 139 | $message = $rule->getData('message'); 140 | if (empty($message)) { 141 | $message = $helper->getDefaultMessage($order->getStoreId()); 142 | } 143 | $rule->setData('message', $message); 144 | 145 | $collection->addItem($collection->getNewEmptyItem()->setData($rule->toArray())); 146 | } 147 | 148 | return $collection; 149 | } 150 | 151 | /** 152 | * Email notification for blacklist activation 153 | * 154 | * @param string $message 155 | * @param array $extraVariables 156 | * @param int|string|null $store 157 | * 158 | * @return $this 159 | */ 160 | public function notify($message, array $extraVariables = [], $store = null) 161 | { 162 | $store = Mage::app()->getStore($store); 163 | 164 | // Sender identity code 165 | $sender = Mage::getStoreConfig(self::XML_PATH_NOTIFICATION_EMAIL_SENDER, $store); 166 | if (!$sender) { 167 | return $this; 168 | } 169 | 170 | // Receiver identity code 171 | $receiver = Mage::getStoreConfig(self::XML_PATH_NOTIFICATION_EMAIL_RECEIVER, $store); 172 | if (!$receiver) { 173 | return $this; 174 | } 175 | 176 | // Template ID 177 | $templateId = Mage::getStoreConfig(self::XML_PATH_NOTIFICATION_EMAIL_TEMPLATE, $store); 178 | if (!$templateId) { 179 | return $this; 180 | } 181 | 182 | /** @var Mage_Core_Model_Email_Info $emailInfo */ 183 | $emailInfo = Mage::getModel('core/email_info'); 184 | $emailInfo->addTo( 185 | Mage::getStoreConfig("trans_email/ident_{$receiver}/email", $store), 186 | Mage::getStoreConfig("trans_email/ident_{$receiver}/name", $store) 187 | ); 188 | 189 | /** @var $mailer Mage_Core_Model_Email_Template_Mailer */ 190 | $mailer = Mage::getModel('core/email_template_mailer'); 191 | $mailer->addEmailInfo($emailInfo); 192 | 193 | // Set all required params and send emails 194 | $mailer->setStoreId($store->getId()); 195 | $mailer->setSender($sender); 196 | $mailer->setTemplateId($templateId); 197 | $mailer->setTemplateParams($extraVariables + ['message' => $message]); 198 | $mailer->send(); 199 | 200 | return $this; 201 | } 202 | } 203 | -------------------------------------------------------------------------------- /app/code/local/Aoe/FraudManager/Resource/Collection/Abstract.php: -------------------------------------------------------------------------------- 1 | _items as $item) { 15 | /** @var Mage_Core_Model_Abstract $item */ 16 | $this->getResource()->unserializeFields($item); 17 | $item->afterLoad(); 18 | $item->setOrigData(); 19 | if ($this->_resetItemsDataChanged) { 20 | $item->setDataChanges(false); 21 | } 22 | } 23 | 24 | Mage::dispatchEvent('core_collection_abstract_load_after', ['collection' => $this]); 25 | 26 | if ($this->_eventPrefix && $this->_eventObject) { 27 | Mage::dispatchEvent($this->_eventPrefix . '_load_after', [$this->_eventObject => $this]); 28 | } 29 | 30 | return $this; 31 | } 32 | 33 | /** 34 | * Join table to collection select 35 | * 36 | * @param string $table 37 | * @param string $cond 38 | * @param string $cols 39 | * 40 | * @return Mage_Core_Model_Resource_Db_Collection_Abstract 41 | */ 42 | public function join($table, $cond, $cols = '*') 43 | { 44 | if (is_array($table)) { 45 | foreach ($table as $k => $v) { 46 | $alias = $k; 47 | $table = $v; 48 | break; 49 | } 50 | } else { 51 | $alias = $table; 52 | } 53 | 54 | if (!isset($this->_joinedTables[$alias])) { 55 | $this->getSelect()->join( 56 | [$alias => $this->getTable($table)], 57 | $cond, 58 | $cols 59 | ); 60 | $this->_joinedTables[$alias] = true; 61 | } 62 | 63 | return $this; 64 | } 65 | 66 | /** 67 | * Join table to collection select 68 | * 69 | * @param string $table 70 | * @param string $cond 71 | * @param string $cols 72 | * 73 | * @return Mage_Core_Model_Resource_Db_Collection_Abstract 74 | */ 75 | public function joinLeft($table, $cond, $cols = '*') 76 | { 77 | if (is_array($table)) { 78 | foreach ($table as $k => $v) { 79 | $alias = $k; 80 | $table = $v; 81 | break; 82 | } 83 | } else { 84 | $alias = $table; 85 | } 86 | 87 | if (!isset($this->_joinedTables[$alias])) { 88 | $this->getSelect()->joinLeft( 89 | [$alias => $this->getTable($table)], 90 | $cond, 91 | $cols 92 | ); 93 | $this->_joinedTables[$alias] = true; 94 | } 95 | 96 | return $this; 97 | } 98 | 99 | /** 100 | * Get SQL for get record count 101 | * 102 | * NB: This varies from standard Magento in that is uses a sub-select if grouping is being used 103 | * 104 | * @return Varien_Db_Select 105 | */ 106 | public function getSelectCountSql() 107 | { 108 | $this->_renderFilters(); 109 | 110 | $countSelect = clone $this->getSelect(); 111 | $countSelect->reset(Zend_Db_Select::ORDER); 112 | $countSelect->reset(Zend_Db_Select::LIMIT_COUNT); 113 | $countSelect->reset(Zend_Db_Select::LIMIT_OFFSET); 114 | 115 | // Fix problem with mixing COUNT and GROUP BY or HAVING 116 | $groups = $countSelect->getPart(Zend_Db_Select::GROUP); 117 | $having = $countSelect->getPart(Zend_Db_Select::HAVING); 118 | if (count($groups) || count($having)) { 119 | $countSelect = $this->_conn->select()->from($countSelect, 'COUNT(*)'); 120 | } else { 121 | $countSelect->reset(Zend_Db_Select::COLUMNS); 122 | $countSelect->columns('COUNT(*)'); 123 | } 124 | 125 | return $countSelect; 126 | } 127 | 128 | /** 129 | * Add filter to Map 130 | * 131 | * @param string $filter 132 | * @param string $alias 133 | * @param string $group default 'fields' 134 | * 135 | * @return Varien_Data_Collection_Db 136 | */ 137 | public function addFilterToMap($filter, $alias, $group = 'fields') 138 | { 139 | if (is_null($this->_map)) { 140 | $this->_map = [$group => []]; 141 | } else { 142 | if (!isset($this->_map[$group])) { 143 | $this->_map[$group] = []; 144 | } 145 | } 146 | $this->_map[$group][$filter] = $alias; 147 | 148 | return $this; 149 | } 150 | 151 | public function addFilterToHavingMap($filter) 152 | { 153 | return $this->addFilterToMap($filter, true, 'having'); 154 | } 155 | 156 | /** 157 | * Add field filter to collection 158 | * 159 | * @see self::_getConditionSql for $condition 160 | * 161 | * @param string|array $field 162 | * @param null|string|array $condition 163 | * @param bool $having 164 | * 165 | * @return Mage_Eav_Model_Entity_Collection_Abstract 166 | */ 167 | public function addFieldToFilter($field, $condition = null, $having = false) 168 | { 169 | $mapper = $this->_getMapper(); 170 | if (!is_array($field)) { 171 | if (isset($mapper['having'][$field])) { 172 | $having = true; 173 | } 174 | $resultCondition = $this->_translateCondition($field, $condition); 175 | } else { 176 | $conditions = []; 177 | foreach ($field as $key => $currField) { 178 | if (isset($mapper['having'][$currField])) { 179 | $having = true; 180 | } 181 | $conditions[] = $this->_translateCondition( 182 | $currField, 183 | isset($condition[$key]) ? $condition[$key] : null 184 | ); 185 | } 186 | 187 | $resultCondition = '(' . join(') ' . Zend_Db_Select::SQL_OR . ' (', $conditions) . ')'; 188 | } 189 | 190 | if ($having) { 191 | $this->_select->having($resultCondition); 192 | } else { 193 | $this->_select->where($resultCondition); 194 | } 195 | 196 | return $this; 197 | } 198 | 199 | /** 200 | * @inheritdoc 201 | */ 202 | protected function _toOptionArray($valueField = null, $labelField = 'name', $additional = []) 203 | { 204 | if ($valueField === null) { 205 | $valueField = $this->getResource()->getIdFieldName(); 206 | if ($valueField === null) { 207 | $valueField = 'id'; 208 | } 209 | } 210 | 211 | return parent::_toOptionArray($valueField, $labelField, $additional); 212 | } 213 | 214 | /** 215 | * @inheritdoc 216 | */ 217 | protected function _toOptionHash($valueField = null, $labelField = 'name') 218 | { 219 | if ($valueField === null) { 220 | $valueField = $this->getResource()->getIdFieldName(); 221 | if ($valueField === null) { 222 | $valueField = 'id'; 223 | } 224 | } 225 | 226 | return parent::_toOptionHash($valueField, $labelField); 227 | } 228 | } 229 | -------------------------------------------------------------------------------- /app/code/local/Aoe/FraudManager/Helper/FraudFlag.php: -------------------------------------------------------------------------------- 1 | resolveOrder($order); 18 | if (!$order instanceof Mage_Sales_Model_Order || $order->isObjectNew()) { 19 | return false; 20 | } 21 | 22 | if (!$this->isActive($order->getStoreId())) { 23 | return false; 24 | } 25 | 26 | return Mage::getStoreConfigFlag(self::XML_PATH_COMMENT_REQUIRED, $order->getStoreId()); 27 | } 28 | 29 | public function isRemoveFlagCommentRequired($order = null) 30 | { 31 | $order = $this->resolveOrder($order); 32 | if (!$order instanceof Mage_Sales_Model_Order || $order->isObjectNew()) { 33 | return false; 34 | } 35 | 36 | if (!$this->isActive($order->getStoreId())) { 37 | return false; 38 | } 39 | 40 | return Mage::getStoreConfigFlag(self::XML_PATH_COMMENT_REQUIRED, $order->getStoreId()); 41 | } 42 | 43 | public function getAutoHoldStatus($store = null) 44 | { 45 | return Mage::getStoreConfig(self::XML_PATH_AUTO_HOLD_STATUS, $store); 46 | } 47 | 48 | public function isFlagged($order = null) 49 | { 50 | $order = $this->resolveOrder($order); 51 | 52 | if ($order instanceof Mage_Sales_Model_Order && (bool)$order->getIsFraud()) { 53 | return true; 54 | } 55 | 56 | return false; 57 | } 58 | 59 | public function isSetFlagActionAllowed($order = null) 60 | { 61 | $order = $this->resolveOrder($order); 62 | if (!$order instanceof Mage_Sales_Model_Order || $order->isObjectNew()) { 63 | return false; 64 | } 65 | 66 | if (!$this->isActive($order->getStoreId())) { 67 | return false; 68 | } 69 | 70 | if ($this->isFlagged($order)) { 71 | return false; 72 | } 73 | 74 | return $this->getAdminSession()->isAllowed(self::ACL_PREFIX . 'set_fraud_flag'); 75 | } 76 | 77 | public function isRemoveFlagActionAllowed($order = null) 78 | { 79 | $order = $this->resolveOrder($order); 80 | if (!$order instanceof Mage_Sales_Model_Order || $order->isObjectNew()) { 81 | return false; 82 | } 83 | 84 | if (!$this->isActive($order->getStoreId())) { 85 | return false; 86 | } 87 | 88 | if (!$this->isFlagged($order)) { 89 | return false; 90 | } 91 | 92 | return $this->getAdminSession()->isAllowed(self::ACL_PREFIX . 'remove_fraud_flag'); 93 | } 94 | 95 | public function getSetFlagUrl($order = null) 96 | { 97 | $order = $this->resolveOrder($order); 98 | 99 | if ($order instanceof Mage_Sales_Model_Order && $order->getId()) { 100 | return $this->getUrl('adminhtml/sales_order/setFraudFlag', ['order_id' => $order->getId()]); 101 | } 102 | 103 | return false; 104 | } 105 | 106 | public function getRemoveFlagUrl($order = null) 107 | { 108 | $order = $this->resolveOrder($order); 109 | 110 | if ($order instanceof Mage_Sales_Model_Order && $order->getId()) { 111 | return $this->getUrl('adminhtml/sales_order/removeFraudFlag', ['order_id' => $order->getId()]); 112 | } 113 | 114 | return false; 115 | } 116 | 117 | public function setFlag($order = null, $message = '') 118 | { 119 | $order = $this->resolveOrder($order); 120 | 121 | if ($order instanceof Mage_Sales_Model_Order && $order->getId() && !$order->getIsFraud()) { 122 | $order->setIsFraud(1); 123 | $comment = trim($this->__('Marked order as fraud') . "\n\n" . $message); 124 | $holdStatus = $this->getAutoHoldStatus($order->getStore()); 125 | if ($holdStatus && $order->canHold()) { 126 | $order->setHoldBeforeState($order->getState()); 127 | $order->setHoldBeforeStatus($order->getStatus()); 128 | $order->setState(Mage_Sales_Model_Order::STATE_HOLDED, $holdStatus, $comment); 129 | } else { 130 | $order->addStatusHistoryComment($comment); 131 | } 132 | $order->save(); 133 | 134 | return true; 135 | } 136 | 137 | return false; 138 | } 139 | 140 | public function removeFlag($order = null, $message = '') 141 | { 142 | $order = $this->resolveOrder($order); 143 | 144 | if ($order instanceof Mage_Sales_Model_Order && $order->getId() && $order->getIsFraud()) { 145 | $order->setIsFraud(0); 146 | $comment = trim($this->__('Marked order as NOT fraud') . "\n\n" . $message); 147 | $holdStatus = $this->getAutoHoldStatus($order->getStore()); 148 | if ($holdStatus && $order->canUnhold() && $order->getStatus() === $holdStatus) { 149 | $order->setState($order->getHoldBeforeState(), $order->getHoldBeforeStatus(), $comment); 150 | $order->setHoldBeforeState(null); 151 | $order->setHoldBeforeStatus(null); 152 | } else { 153 | $order->addStatusHistoryComment($comment); 154 | } 155 | $order->save(); 156 | 157 | return true; 158 | } 159 | 160 | return false; 161 | } 162 | 163 | public function getCommentForm($order = null) 164 | { 165 | $order = $this->resolveOrder($order); 166 | if (!$order instanceof Mage_Sales_Model_Order) { 167 | return null; 168 | } 169 | 170 | $form = new Varien_Data_Form(); 171 | $form->setId('edit_form'); 172 | $form->setMethod('post'); 173 | $form->setUseContainer(true); 174 | 175 | $fieldset = $form->addFieldset('base_fieldset', ['legend' => $this->__('Order')]); 176 | 177 | $fieldset->addField( 178 | 'comment', 179 | 'textarea', 180 | [ 181 | 'id' => 'comment', 182 | 'name' => 'comment', 183 | 'label' => $this->__('Comment'), 184 | 'class' => 'required-entry', 185 | 'required' => true, 186 | ] 187 | ); 188 | 189 | return $form; 190 | } 191 | 192 | /** 193 | * Return the current order or an empty order 194 | * 195 | * @return Mage_Sales_Model_Order 196 | */ 197 | public function getCurrentOrder() 198 | { 199 | $order = Mage::registry('current_order'); 200 | if ($order instanceof Mage_Sales_Model_Order) { 201 | return $order; 202 | } else { 203 | Mage::getModel('sales/order'); 204 | } 205 | } 206 | 207 | /** 208 | * 209 | * @param Mage_Sales_Model_Order $order 210 | * 211 | * @return $this 212 | */ 213 | public function setCurrentOrder(Mage_Sales_Model_Order $order = null) 214 | { 215 | Mage::unregister('sales_order'); 216 | Mage::unregister('current_order'); 217 | 218 | Mage::register('sales_order', $order); 219 | Mage::register('current_order', $order); 220 | 221 | return $this; 222 | } 223 | 224 | protected function resolveOrder($order = null) 225 | { 226 | if ($order instanceof Mage_Sales_Model_Order) { 227 | return $order; 228 | } elseif ($order) { 229 | return Mage::getModel('sales/order')->load($order); 230 | } else { 231 | return $this->getCurrentOrder(); 232 | } 233 | } 234 | } 235 | -------------------------------------------------------------------------------- /app/code/local/Aoe/FraudManager/etc/system.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | service 7 | text 8 | 9999 9 | 1 10 | 1 11 | 1 12 | 13 | 14 | 15 | text 16 | 100 17 | 1 18 | 1 19 | 1 20 | 21 | 22 | 23 | select 24 | adminhtml/system_config_source_yesno 25 | 100 26 | 1 27 | 1 28 | 1 29 | 30 | 31 | 32 | select 33 | adminhtml/system_config_source_yesno 34 | 200 35 | 1 36 | 1 37 | 1 38 | 39 | 40 | 41 | select 42 | Aoe_FraudManager/Config_Source_Order_HoldStatusesNone 43 | 300 44 | 1 45 | 1 46 | 1 47 | 48 | 49 | 50 | 51 | 52 | text 53 | 200 54 | 1 55 | 1 56 | 1 57 | 58 | 59 | 60 | select 61 | adminhtml/system_config_source_yesno 62 | 100 63 | 1 64 | 1 65 | 1 66 | 67 | 68 | 69 | select 70 | adminhtml/system_config_source_email_template 71 | 200 72 | 1 73 | 1 74 | 1 75 | 76 | 77 | 78 | select 79 | adminhtml/system_config_source_email_identity 80 | 210 81 | 1 82 | 1 83 | 1 84 | 85 | 86 | 87 | select 88 | adminhtml/system_config_source_email_identity 89 | 220 90 | 1 91 | 1 92 | 1 93 | 94 | 95 | 96 | textarea 97 | 300 98 | 1 99 | 1 100 | 1 101 | 102 | 103 | 104 | 105 | 106 | text 107 | 300 108 | 1 109 | 1 110 | 1 111 | 112 | 113 | 114 | select 115 | adminhtml/system_config_source_yesno 116 | 100 117 | 1 118 | 1 119 | 1 120 | 121 | 122 | 123 | select 124 | adminhtml/system_config_source_email_template 125 | 200 126 | 1 127 | 1 128 | 1 129 | 130 | 131 | 132 | select 133 | adminhtml/system_config_source_email_identity 134 | 210 135 | 1 136 | 1 137 | 1 138 | 139 | 140 | 141 | select 142 | adminhtml/system_config_source_email_identity 143 | 220 144 | 1 145 | 1 146 | 1 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | -------------------------------------------------------------------------------- /app/code/local/Aoe/FraudManager/Helper/AbstractRule.php: -------------------------------------------------------------------------------- 1 | getCollection(); 8 | } 9 | 10 | /** 11 | * @return Varien_Data_Form 12 | */ 13 | public function getForm($rule = null) 14 | { 15 | /** @var Aoe_FraudManager_Model_Rule_Abstract $rule */ 16 | if (!$rule) { 17 | $rule = $this->getCurrentRecord(); 18 | } 19 | 20 | $form = new Varien_Data_Form( 21 | [ 22 | 'id' => 'edit_form', 23 | 'action' => $this->getEditUrl($rule), 24 | 'method' => 'post', 25 | 'use_container' => true, 26 | ] 27 | ); 28 | 29 | return $form; 30 | } 31 | 32 | /** 33 | * @return Varien_Data_Form 34 | */ 35 | public function getMainForm($rule = null) 36 | { 37 | /** @var Aoe_FraudManager_Model_Rule_Abstract $rule */ 38 | if (!$rule) { 39 | $rule = $this->getCurrentRecord(); 40 | } 41 | 42 | $form = new Varien_Data_Form(); 43 | $form->setHtmlIdPrefix('rule_'); 44 | 45 | $fieldset = $form->addFieldset( 46 | 'base_fieldset', 47 | ['legend' => $this->__('General Information')] 48 | ); 49 | 50 | $fieldset->addField( 51 | 'name', 52 | 'text', 53 | [ 54 | 'name' => 'name', 55 | 'label' => $this->__('Rule Name'), 56 | 'title' => $this->__('Rule Name'), 57 | 'required' => true, 58 | ] 59 | ); 60 | 61 | $fieldset->addField( 62 | 'description', 63 | 'textarea', 64 | [ 65 | 'name' => 'description', 66 | 'label' => $this->__('Description'), 67 | 'title' => $this->__('Description'), 68 | 'style' => 'height: 100px;', 69 | ] 70 | ); 71 | 72 | $fieldset->addField( 73 | 'stop_processing', 74 | 'select', 75 | [ 76 | 'name' => 'stop_processing', 77 | 'label' => $this->__('Stop Processing'), 78 | 'title' => $this->__('Stop Processing'), 79 | 'comment' => $this->__('Stop further rules processing is this rule matches'), 80 | 'required' => true, 81 | 'options' => $this->getSourceModelHash('adminhtml/system_config_source_yesno'), 82 | ] 83 | ); 84 | 85 | $fieldset->addField( 86 | 'is_active', 87 | 'select', 88 | [ 89 | 'name' => 'is_active', 90 | 'label' => $this->__('Active'), 91 | 'title' => $this->__('Active'), 92 | 'required' => true, 93 | 'options' => $this->getSourceModelHash('adminhtml/system_config_source_yesno'), 94 | ] 95 | ); 96 | 97 | if ($this->getIsSingleStoreMode()) { 98 | $websiteId = Mage::app()->getStore(true)->getWebsiteId(); 99 | $fieldset->addField( 100 | 'website_ids', 101 | 'hidden', 102 | [ 103 | 'name' => 'website_ids[]', 104 | 'value' => $websiteId, 105 | ] 106 | ); 107 | $rule->setWebsiteIds($websiteId); 108 | } else { 109 | $fieldset->addField( 110 | 'website_ids', 111 | 'multiselect', 112 | [ 113 | 'name' => 'website_ids[]', 114 | 'label' => $this->__('Websites'), 115 | 'title' => $this->__('Websites'), 116 | 'required' => true, 117 | 'values' => $this->getSourceModelArray('core/website', true), 118 | ] 119 | ); 120 | } 121 | 122 | $fieldset->addField( 123 | 'sort_order', 124 | 'text', 125 | [ 126 | 'name' => 'sort_order', 127 | 'label' => $this->__('Sort Order'), 128 | 'comment' => $this->__('High numbers are processed first'), 129 | ] 130 | ); 131 | 132 | $form->addValues($rule->getData()); 133 | 134 | return $form; 135 | } 136 | 137 | /** 138 | * @return Varien_Data_Form 139 | */ 140 | public function getConditionsForm($rule = null) 141 | { 142 | /** @var Aoe_FraudManager_Model_Rule_Abstract $rule */ 143 | if (!$rule) { 144 | $rule = $this->getCurrentRecord(); 145 | } 146 | 147 | $form = new Varien_Data_Form(); 148 | 149 | $form->setHtmlIdPrefix('rule_'); 150 | 151 | $fieldset = $form->addFieldset('conditions_fieldset', ['legend' => $this->__('Apply the rule only if the following conditions are met')]); 152 | 153 | $renderer = clone $form->getFieldsetRenderer(); 154 | $renderer->setTemplate('promo/fieldset.phtml'); 155 | $renderer->setNewChildUrl($this->getUrl('*/*/condition', ['form' => $fieldset->getHtmlId()])); 156 | $fieldset->setRenderer($renderer); 157 | 158 | $conditionsElement = $fieldset->addField( 159 | 'conditions', 160 | 'text', 161 | [ 162 | 'name' => 'conditions', 163 | 'label' => $this->__('Conditions'), 164 | 'title' => $this->__('Conditions'), 165 | ] 166 | ); 167 | $conditionsElement->setRenderer(Mage::getSingleton('Aoe_FraudManager/Form_Element_Renderer_Conditions')); 168 | 169 | $form->addValues(['conditions' => $rule->getConditions()]); 170 | 171 | return $form; 172 | } 173 | 174 | /** 175 | * @param array $original 176 | * 177 | * @return array 178 | */ 179 | public function convertFlatToRecursive(array $original, array $keys) 180 | { 181 | $result = []; 182 | 183 | foreach ($original as $key => $value) { 184 | if (in_array($key, $keys) && is_array($value)) { 185 | foreach ($value as $id => $data) { 186 | $path = explode('--', $id); 187 | $node =& $result; 188 | for ($i = 0, $l = sizeof($path); $i < $l; $i++) { 189 | if (!isset($node[$key][$path[$i]])) { 190 | $node[$key][$path[$i]] = []; 191 | } 192 | $node =& $node[$key][$path[$i]]; 193 | } 194 | foreach ($data as $k => $v) { 195 | $node[$k] = $v; 196 | } 197 | } 198 | } else { 199 | $result[$key] = $value; 200 | } 201 | } 202 | 203 | return $result; 204 | } 205 | 206 | public function getTestOrderUrl($order = null) 207 | { 208 | $order = $this->resolveOrder($order); 209 | 210 | if ($order instanceof Mage_Sales_Model_Order && $order->getId()) { 211 | return $this->getUrl($this->getControllerRoute() . '/testOrder', ['order_id' => $order->getId()]); 212 | } 213 | 214 | return false; 215 | } 216 | 217 | public function getOrderViewUrl($order = null) 218 | { 219 | $order = $this->resolveOrder($order); 220 | 221 | if ($order instanceof Mage_Sales_Model_Order && $order->getId()) { 222 | return $this->getUrl('*/sales_order/view', ['order_id' => $order->getId()]); 223 | } 224 | 225 | return false; 226 | } 227 | 228 | public function canTest() 229 | { 230 | return $this->getAclPermission('test'); 231 | } 232 | 233 | /** 234 | * Return the current order or an empty order 235 | * 236 | * @return Mage_Sales_Model_Order 237 | */ 238 | public function getCurrentOrder() 239 | { 240 | $order = Mage::registry('current_order'); 241 | if ($order instanceof Mage_Sales_Model_Order) { 242 | return $order; 243 | } else { 244 | Mage::getModel('sales/order'); 245 | } 246 | } 247 | 248 | /** 249 | * 250 | * @param Mage_Sales_Model_Order $order 251 | * 252 | * @return $this 253 | */ 254 | public function setCurrentOrder(Mage_Sales_Model_Order $order = null) 255 | { 256 | Mage::unregister('sales_order'); 257 | Mage::unregister('current_order'); 258 | 259 | Mage::register('sales_order', $order); 260 | Mage::register('current_order', $order); 261 | 262 | return $this; 263 | } 264 | 265 | protected function resolveOrder($order = null) 266 | { 267 | if ($order instanceof Mage_Sales_Model_Order) { 268 | return $order; 269 | } elseif ($order) { 270 | return Mage::getModel('sales/order')->load($order); 271 | } else { 272 | return $this->getCurrentOrder(); 273 | } 274 | } 275 | 276 | /** 277 | * Test an order against all of the rules 278 | * 279 | * @param Mage_Sales_Model_Order $order 280 | * 281 | * @return Varien_Data_Collection 282 | */ 283 | abstract public function testOrder(Mage_Sales_Model_Order $order); 284 | } 285 | -------------------------------------------------------------------------------- /app/code/local/Aoe/FraudManager/Model/Observer.php: -------------------------------------------------------------------------------- 1 | getParent(); 12 | if (!$parent instanceof Aoe_FraudManager_Model_Rule_Condition_Interface) { 13 | return; 14 | } 15 | 16 | /** @var Varien_Object $container */ 17 | $container = $observer->getContainer(); 18 | if (!$container instanceof Varien_Object) { 19 | return; 20 | } 21 | 22 | $conditions = $container->getConditions(); 23 | if (!is_array($conditions)) { 24 | $conditions = []; 25 | } 26 | 27 | /** @var Aoe_FraudManager_Model_Rule_Condition_Order_Attribute $condition */ 28 | $condition = Mage::getModel('Aoe_FraudManager/Rule_Condition_Order_Attribute'); 29 | $conditionName = $helper->__($condition->getName()); 30 | foreach ($condition->getAttributeOptions() as $attribute => $label) { 31 | $conditions[$conditionName][$condition->getType() . '|' . $attribute] = $label; 32 | } 33 | 34 | /** @var Aoe_FraudManager_Model_Rule_Condition_Order_BillingAddress_Attribute $condition */ 35 | $condition = Mage::getModel('Aoe_FraudManager/Rule_Condition_Order_BillingAddress_Attribute'); 36 | $conditionName = $helper->__($condition->getName()); 37 | foreach ($condition->getAttributeOptions() as $attribute => $label) { 38 | $conditions[$conditionName][$condition->getType() . '|' . $attribute] = $label; 39 | } 40 | 41 | /** @var Aoe_FraudManager_Model_Rule_Condition_Order_ShippingAddress_Attribute $condition */ 42 | $condition = Mage::getModel('Aoe_FraudManager/Rule_Condition_Order_ShippingAddress_Attribute'); 43 | $conditionName = $helper->__($condition->getName()); 44 | foreach ($condition->getAttributeOptions() as $attribute => $label) { 45 | $conditions[$conditionName][$condition->getType() . '|' . $attribute] = $label; 46 | } 47 | 48 | /** @var Aoe_FraudManager_Model_Rule_Condition_Order_Address_Compare $condition */ 49 | $condition = Mage::getModel('Aoe_FraudManager/Rule_Condition_Order_Address_Compare'); 50 | $conditionName = $helper->__($condition->getName()); 51 | foreach ($condition->getAttributeOptions() as $attribute => $label) { 52 | $conditions[$conditionName][$condition->getType() . '|' . $attribute] = $label; 53 | } 54 | 55 | /** @var Aoe_FraudManager_Model_Rule_Condition_Order_Item_Found $condition */ 56 | $condition = Mage::getModel('Aoe_FraudManager/Rule_Condition_Order_Item_Found'); 57 | $conditions[$condition->getType()] = $helper->__($condition->getName()); 58 | 59 | $container->setConditions($conditions); 60 | } 61 | 62 | public function addOrderItemConditions(Varien_Event_Observer $observer) 63 | { 64 | /** @var Aoe_FraudManager_Helper_Data $helper */ 65 | $helper = Mage::helper('Aoe_FraudManager/Data'); 66 | 67 | /** @var Aoe_FraudManager_Model_Rule_Condition_Interface $parent */ 68 | $parent = $observer->getData('parent'); 69 | if (!$parent instanceof Aoe_FraudManager_Model_Rule_Condition_Interface) { 70 | return; 71 | } 72 | 73 | /** @var Varien_Object $container */ 74 | $container = $observer->getData('container'); 75 | if (!$container instanceof Varien_Object) { 76 | return; 77 | } 78 | 79 | $conditions = $container->getData('conditions'); 80 | if (!is_array($conditions)) { 81 | $conditions = []; 82 | } 83 | 84 | /** @var Aoe_FraudManager_Model_Rule_Condition_Order_Item_Combine $condition */ 85 | $condition = Mage::getModel('Aoe_FraudManager/Rule_Condition_Order_Item_Combine'); 86 | $conditions[$condition->getType()] = $helper->__($condition->getName()); 87 | 88 | /** @var Aoe_FraudManager_Model_Rule_Condition_Order_Item_Attribute $condition */ 89 | $condition = Mage::getModel('Aoe_FraudManager/Rule_Condition_Order_Item_Attribute'); 90 | $conditionName = $helper->__($condition->getName()); 91 | foreach ($condition->getAttributeOptions() as $attribute => $label) { 92 | $conditions[$conditionName][$condition->getType() . '|' . $attribute] = $label; 93 | } 94 | 95 | $container->setData('conditions', $conditions); 96 | } 97 | 98 | public function checkQuoteSubmitBefore(Varien_Event_Observer $observer) 99 | { 100 | /** @var Mage_Sales_Model_Order $order */ 101 | $order = $observer->getOrder(); 102 | if (!$order instanceof Mage_Sales_Model_Order) { 103 | return; 104 | } 105 | 106 | /** @var Aoe_FraudManager_Helper_BlacklistRule $helper */ 107 | $helper = Mage::helper('Aoe_FraudManager/BlacklistRule'); 108 | if (!$helper->isActive($order->getStoreId())) { 109 | return; 110 | } 111 | 112 | /** @var Aoe_FraudManager_Resource_BlacklistRule_Collection $rules */ 113 | $rules = Mage::getSingleton('Aoe_FraudManager/BlacklistRule') 114 | ->getCollection() 115 | ->filterValidForOrder($order); 116 | 117 | $messages = []; 118 | $notifications = []; 119 | foreach ($rules as $rule) { 120 | /** @var Aoe_FraudManager_Model_BlacklistRule $rule */ 121 | if ($rule->validate($order)) { 122 | $notification = sprintf('Preventing order due to rules check: %s / %s / %s', $rule->getName(), $order->getIncrementId(), $order->getQuoteId()); 123 | $notifications[] = $notification; 124 | Mage::log($notification, Zend_Log::WARN, 'fraud.log'); 125 | 126 | $message = $rule->getMessage(); 127 | if (empty($message)) { 128 | $message = $helper->getDefaultMessage($order->getStoreId()); 129 | } 130 | 131 | $messages[] = $helper->__($helper->filterMessage($message, $order->getStoreId())); 132 | 133 | if ($rule->getStopProcessing()) { 134 | break; 135 | } 136 | } 137 | } 138 | 139 | if (count($notifications)) { 140 | try { 141 | $helper->notify(implode("\n", $notifications), ['order' => $order], $order->getStoreId()); 142 | } catch (Exception $e) { 143 | Mage::logException($e); 144 | } 145 | } 146 | 147 | if (count($messages)) { 148 | throw new Mage_Payment_Model_Info_Exception(nl2br(implode("\n", $messages))); 149 | } 150 | } 151 | 152 | public function checkQuoteSubmitSuccess(Varien_Event_Observer $observer) 153 | { 154 | /** @var Mage_Sales_Model_Order $order */ 155 | $order = $observer->getOrder(); 156 | if (!$order instanceof Mage_Sales_Model_Order) { 157 | return; 158 | } 159 | 160 | /** @var Aoe_FraudManager_Helper_HoldRule $helper */ 161 | $helper = Mage::helper('Aoe_FraudManager/HoldRule'); 162 | if (!$helper->isActive($order->getStoreId())) { 163 | return; 164 | } 165 | 166 | // Exit early if the order cannot be held 167 | if (!$order->canHold()) { 168 | return; 169 | } 170 | 171 | /** @var Aoe_FraudManager_Resource_HoldRule_Collection $rules */ 172 | $rules = Mage::getSingleton('Aoe_FraudManager/HoldRule') 173 | ->getCollection() 174 | ->filterValidForOrder($order); 175 | 176 | $notifications = []; 177 | foreach ($rules as $rule) { 178 | /** @var Aoe_FraudManager_Model_HoldRule $rule */ 179 | if ($rule->validate($order)) { 180 | $notification = sprintf('Holding order due to rules check: %s / %s / %s', $rule->getName(), $order->getIncrementId(), $order->getQuoteId()); 181 | $notifications[] = $notification; 182 | Mage::log($notification, Zend_Log::INFO, 'fraud.log'); 183 | 184 | if ($order->canHold()) { 185 | $order->setHoldBeforeState($order->getState()); 186 | $order->setHoldBeforeStatus($order->getStatus()); 187 | } 188 | 189 | $status = $rule->getStatus(); 190 | /** @var Mage_Sales_Model_Order_Config $salesConfig */ 191 | $salesConfig = Mage::getSingleton('sales/order_config'); 192 | $allowedStatuses = $salesConfig->getStateStatuses(Mage_Sales_Model_Order::STATE_HOLDED, false); 193 | if (!in_array($status, $allowedStatuses)) { 194 | $status = true; 195 | } 196 | 197 | $order->setState(Mage_Sales_Model_Order::STATE_HOLDED, $status, sprintf('Holding order due to rules check: %s', $rule->getName())); 198 | 199 | if ($rule->getStopProcessing()) { 200 | break; 201 | } 202 | } 203 | } 204 | 205 | if (count($notifications)) { 206 | try { 207 | $helper->notify(implode("\n", $notifications), ['order' => $order], $order->getStoreId()); 208 | } catch (Exception $e) { 209 | Mage::logException($e); 210 | } 211 | } 212 | 213 | $order->save(); 214 | } 215 | } 216 | -------------------------------------------------------------------------------- /app/design/adminhtml/default/default/template/aoe_fraudmanager/sales/order/view/info.phtml: -------------------------------------------------------------------------------- 1 | 27 | getOrder() ?> 28 | formatDate($_order->getCreatedAtDate(), 'medium', true); 30 | $orderStoreDate = $this->formatDate($_order->getCreatedAtStoreDate(), 'medium', true); 31 | ?> 32 |
33 | 34 |
35 | getEmailSent()): 36 | $_email = Mage::helper('sales')->__('the order confirmation email was sent'); 37 | else: 38 | $_email = Mage::helper('sales')->__('the order confirmation email is not sent'); 39 | endif; ?> 40 |
41 | getNoUseOrderLink()): ?> 42 | 43 | 44 | __('Order # %s', $_order->getRealOrderId()) ?> 45 | () 46 | 47 |
48 |
49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 68 | 69 | 70 | 71 | 72 | 73 | getRelationChildId()): ?> 74 | 75 | 76 | 79 | 80 | 81 | getRelationParentId()): ?> 82 | 83 | 84 | 87 | 88 | 89 | getRemoteIp() && $this->shouldDisplayCustomerIp()): ?> 90 | 91 | 92 | 94 | 95 | 96 | getGlobalCurrencyCode() != $_order->getBaseCurrencyCode()): ?> 97 | 98 | 99 | 100 | 101 | 102 | getBaseCurrencyCode() != $_order->getOrderCurrencyCode()): ?> 103 | 104 | 105 | 106 | 107 | 108 |
63 | getStatusLabel() ?> 64 | getIsFraud()): ?> 65 | / __('Fraud') ?> 66 | 67 |
getOrderStoreName() ?>
77 | getRelationChildRealId() ?> 78 |
85 | getRelationParentRealId() ?> 86 |
getRemoteIp(); 93 | echo ($_order->getXForwardedFor()) ? ' (' . $this->escapeHtml($_order->getXForwardedFor()) . ')' : ''; ?>
getBaseToGlobalRate() ?>
getBaseToOrderRate() ?>
109 |
110 |
111 |
112 |
113 | 114 |
115 |
116 | 117 | 118 |
getAccountEditLink() ?>
119 |
120 |
121 |
122 | 123 | 124 | 125 | 132 | 133 | 134 | 135 | 136 | 137 | getCustomerGroupName()) : ?> 138 | 139 | 140 | 141 | 142 | 143 | getCustomerAccountData() as $data): ?> 144 | 145 | 146 | 147 | 148 | 149 |
126 | getCustomerViewUrl()) : ?> 127 | escapeHtml($_order->getCustomerName()) ?> 128 | 129 | escapeHtml($_order->getCustomerName()) ?> 130 | 131 |
getCustomerEmail() ?>
150 |
151 |
152 |
153 |
154 |
155 | 156 |
157 | 158 |
159 |
160 |

__('Billing Address') ?>

161 | 162 |
getAddressEditLink($_order->getBillingAddress()) ?>
163 |
164 |
165 |
getBillingAddress()->getFormated(true) ?>
166 |
167 |
168 |
169 | getOrder()->getIsVirtual()): ?> 170 |
171 | 172 |
173 |
174 |

__('Shipping Address') ?>

175 | 176 |
getAddressEditLink($_order->getShippingAddress()) ?>
177 |
178 |
179 |
getShippingAddress()->getFormated(true) ?>
180 |
181 |
182 |
183 |
184 | 185 | -------------------------------------------------------------------------------- /app/code/local/Aoe/FraudManager/Model/Rule/Condition/Attribute.php: -------------------------------------------------------------------------------- 1 | arrayKeys[] = 'attribute'; 20 | $this->arrayKeys[] = 'operator'; 21 | $this->arrayKeys[] = 'value'; 22 | } 23 | 24 | /** 25 | * @return array|false 26 | */ 27 | public function getAttributeOptions() 28 | { 29 | if ($this->attributeOptions === null) { 30 | $this->attributeOptions = array_map([$this, 'translate'], array_map('reset', $this->attributes)); 31 | if (empty($this->attributeOptions)) { 32 | $this->attributeOptions = false; 33 | } 34 | } 35 | 36 | return $this->attributeOptions; 37 | } 38 | 39 | /** 40 | * @return string|null 41 | */ 42 | public function getAttribute() 43 | { 44 | return $this->getData('attribute'); 45 | } 46 | 47 | /** 48 | * @param string $attribute 49 | * 50 | * @return $this 51 | */ 52 | public function setAttribute($attribute) 53 | { 54 | return $this->setData('attribute', $attribute); 55 | } 56 | 57 | public function getAttributeName() 58 | { 59 | $attribute = $this->getAttribute(); 60 | 61 | if (is_null($attribute) || '' === $attribute) { 62 | return '...'; 63 | } 64 | 65 | $options = $this->getAttributeOptions(); 66 | if ($options === false || empty($options)) { 67 | return $attribute; 68 | } 69 | 70 | if (array_key_exists($attribute, $options)) { 71 | return $options[$attribute]; 72 | } 73 | 74 | return ''; 75 | } 76 | 77 | /** 78 | * @return array 79 | */ 80 | public function getOperatorOptions() 81 | { 82 | $allowedOperators = []; 83 | if (isset($this->attributes[$this->getAttribute()]) && isset($this->attributes[$this->getAttribute()][1])) { 84 | $allowedOperators = $this->attributes[$this->getAttribute()][1]; 85 | } 86 | 87 | return Mage::helper('Aoe_FraudManager/Condition')->getOperators($allowedOperators); 88 | } 89 | 90 | /** 91 | * @return string|null 92 | */ 93 | public function getOperator() 94 | { 95 | if (is_null($this->getData('operator'))) { 96 | $options = array_keys($this->getOperatorOptions()); 97 | $this->setOperator(reset($options)); 98 | } 99 | 100 | return $this->getData('operator'); 101 | } 102 | 103 | /** 104 | * @param string $operator 105 | * 106 | * @return $this 107 | */ 108 | public function setOperator($operator) 109 | { 110 | return $this->setData('operator', $operator); 111 | } 112 | 113 | /** 114 | * @return string 115 | */ 116 | public function getOperatorName() 117 | { 118 | $options = $this->getOperatorOptions(); 119 | 120 | return (isset($options[$this->getOperator()]) ? $options[$this->getOperator()] : ''); 121 | } 122 | 123 | /** 124 | * Check if value should be array 125 | * 126 | * Depends on operator input type 127 | * 128 | * @return bool 129 | */ 130 | public function getOperatorIsArrayType() 131 | { 132 | return in_array($this->getOperator(), $this->arrayOperators); 133 | } 134 | 135 | /** 136 | * @return array|false 137 | */ 138 | public function getValueOptions() 139 | { 140 | return false; 141 | } 142 | 143 | /** 144 | * @return string|null 145 | */ 146 | public function getValue() 147 | { 148 | return $this->getData('value'); 149 | } 150 | 151 | /** 152 | * @param string $value 153 | * 154 | * @return $this 155 | */ 156 | public function setValue($value) 157 | { 158 | return $this->setData('value', $value); 159 | } 160 | 161 | public function getValueParsed() 162 | { 163 | $value = $this->getValue(); 164 | 165 | if ($this->getOperatorIsArrayType() && is_string($value)) { 166 | $value = preg_split('#\s*[,;]\s*#', $value, null, PREG_SPLIT_NO_EMPTY); 167 | } 168 | 169 | return $value; 170 | } 171 | 172 | public function getValueName() 173 | { 174 | $value = $this->getValue(); 175 | 176 | if (is_null($value) || '' === $value) { 177 | return '...'; 178 | } 179 | 180 | $options = $this->getValueOptions(); 181 | if ($options === false) { 182 | return $value; 183 | } 184 | 185 | if (is_array($value)) { 186 | $valueLabels = []; 187 | foreach ($options as $k => $v) { 188 | if (in_array($k, $value)) { 189 | $valueLabels[] = $v; 190 | } 191 | } 192 | 193 | return implode(', ', $valueLabels); 194 | } elseif (array_key_exists($value, $options)) { 195 | return $options[$value]; 196 | } 197 | 198 | return ''; 199 | } 200 | 201 | //================================================== 202 | //=[ HTML Generation ]============================== 203 | //================================================== 204 | 205 | public function getConditionConfigHtml() 206 | { 207 | $html = $this->translate($this->getName()) . ' '; 208 | $html .= $this->getAttributeElement()->getHtml(); 209 | $html .= $this->getOperatorElement()->getHtml(); 210 | $html .= $this->getValueElement()->getHtml(); 211 | $html .= $this->getChooserContainerHtml(); 212 | 213 | return $html; 214 | } 215 | 216 | /** 217 | * @return Varien_Data_Form_Element_Abstract 218 | */ 219 | public function getAttributeElement() 220 | { 221 | $attribute = $this->getAttribute(); 222 | $options = $this->getAttributeOptions(); 223 | 224 | if (is_array($options) && empty($attribute)) { 225 | $element = $this->getForm()->addField( 226 | $this->getId() . '__attribute', 227 | 'select', 228 | [ 229 | 'name' => $this->getId() . '[attribute]', 230 | 'options' => $this->getAttributeOptions(), 231 | 'value' => $this->getAttribute(), 232 | 'label' => $this->getAttributeName(), 233 | ] 234 | ); 235 | } else { 236 | $element = $this->getForm()->addField( 237 | $this->getId() . '__attribute', 238 | 'text', 239 | [ 240 | 'name' => $this->getId() . '[attribute]', 241 | 'value' => $this->getAttribute(), 242 | 'label' => $this->getAttributeName(), 243 | 'show_as_text' => true, 244 | ] 245 | ); 246 | } 247 | 248 | $element->setRenderer(Mage::getSingleton('Aoe_FraudManager/Form_Element_Renderer_Editable')); 249 | 250 | return $element; 251 | } 252 | 253 | /** 254 | * @return Varien_Data_Form_Element_Abstract 255 | */ 256 | public function getOperatorElement() 257 | { 258 | $element = $this->getForm()->addField( 259 | $this->getId() . '__operator', 260 | 'select', 261 | [ 262 | 'name' => $this->getId() . '[operator]', 263 | 'options' => $this->getOperatorOptions(), 264 | 'value' => $this->getOperator(), 265 | 'label' => $this->getOperatorName(), 266 | ] 267 | ); 268 | 269 | $element->setRenderer(Mage::getSingleton('Aoe_FraudManager/Form_Element_Renderer_Editable')); 270 | 271 | return $element; 272 | } 273 | 274 | 275 | /** 276 | * Value element type will define renderer for condition value element 277 | * 278 | * @see Varien_Data_Form_Element 279 | * @return string 280 | */ 281 | public function getValueElementType() 282 | { 283 | return 'text'; 284 | } 285 | 286 | /** 287 | * Retrieve input type 288 | * 289 | * @return string 290 | */ 291 | public function getValueElementInputType() 292 | { 293 | return 'string'; 294 | } 295 | 296 | public function getValueElement() 297 | { 298 | $elementParams = [ 299 | 'name' => $this->getId() . '[value]', 300 | 'value' => $this->getValue(), 301 | 'options' => $this->getValueOptions(), 302 | 'label' => $this->getValueName(), 303 | ]; 304 | 305 | $options = $this->getValueOptions(); 306 | if (is_array($options)) { 307 | $elementParams['options'] = $options; 308 | } 309 | 310 | if ($this->getValueElementType() == 'date') { 311 | // date format intentionally hard-coded 312 | $elementParams['input_format'] = Varien_Date::DATE_INTERNAL_FORMAT; 313 | $elementParams['format'] = Varien_Date::DATE_INTERNAL_FORMAT; 314 | } 315 | 316 | $element = $this->getForm()->addField($this->getId() . '__value', $this->getValueElementType(), $elementParams); 317 | 318 | $element->setRenderer(Mage::getSingleton('Aoe_FraudManager/Form_Element_Renderer_Editable')); 319 | 320 | return $element; 321 | } 322 | 323 | public function getChooserContainerHtml() 324 | { 325 | $html = ''; 326 | 327 | $url = $this->getValueElementChooserUrl(); 328 | if ($url) { 329 | $html = '
'; 330 | } 331 | 332 | return $html; 333 | } 334 | 335 | public function validate(Varien_Object $object) 336 | { 337 | $attribute = $this->getAttribute(); 338 | if (empty($attribute)) { 339 | return false; 340 | } 341 | 342 | return Mage::helper('Aoe_FraudManager/Condition')->validateValue($this->getOperator(), $this->getValueParsed(), $this->getAttributeValue($object)); 343 | } 344 | 345 | protected function getAttributeValue(Varien_Object $object) 346 | { 347 | $attribute = $this->getAttribute(); 348 | if (!empty($attribute)) { 349 | return $object->getDataUsingMethod($attribute); 350 | } else { 351 | return null; 352 | } 353 | } 354 | } 355 | -------------------------------------------------------------------------------- /app/code/local/Aoe/FraudManager/Model/Rule/Condition/Combine.php: -------------------------------------------------------------------------------- 1 | setType('Aoe_FraudManager/Rule_Condition_Combine'); 11 | $this->setName('Conditions Combination'); 12 | $this->arrayKeys[] = 'aggregator'; 13 | $this->arrayKeys[] = 'value'; 14 | } 15 | 16 | /** 17 | * @return string 18 | */ 19 | public function getSelfType() 20 | { 21 | return $this->getType(); 22 | } 23 | 24 | /** 25 | * @return string|null 26 | */ 27 | public function getAggregator() 28 | { 29 | if (is_null($this->getData('aggregator'))) { 30 | $options = array_keys($this->getAggregatorOptions()); 31 | $this->setAggregator(reset($options)); 32 | } 33 | 34 | return $this->getData('aggregator'); 35 | } 36 | 37 | /** 38 | * @param string $aggregator 39 | * 40 | * @return $this; 41 | */ 42 | public function setAggregator($aggregator) 43 | { 44 | return $this->setData('aggregator', $aggregator); 45 | } 46 | 47 | /** 48 | * @return string|null 49 | */ 50 | public function getValue() 51 | { 52 | if (is_null($this->getData('value'))) { 53 | $options = array_keys($this->getValueOptions()); 54 | $this->setValue(reset($options)); 55 | } 56 | 57 | return $this->getData('value'); 58 | } 59 | 60 | /** 61 | * @param string $value 62 | * 63 | * @return $this; 64 | */ 65 | public function setValue($value) 66 | { 67 | return $this->setData('value', $value); 68 | } 69 | 70 | /** 71 | * @return Aoe_FraudManager_Model_Rule_Condition_Interface[] 72 | */ 73 | public function getConditions() 74 | { 75 | if (!is_array($this->getData('conditions'))) { 76 | $this->setConditions([]); 77 | } 78 | 79 | return $this->getData('conditions'); 80 | } 81 | 82 | /** 83 | * Set conditions, if current prefix is undefined use 'conditions' key 84 | * 85 | * @param Aoe_FraudManager_Model_Rule_Condition_Interface[] $conditions 86 | * 87 | * @return $this 88 | */ 89 | public function setConditions(array $conditions) 90 | { 91 | return $this->setData('conditions', $conditions); 92 | } 93 | 94 | /** 95 | * @param Aoe_FraudManager_Model_Rule_Condition_Interface $condition 96 | * 97 | * @return $this 98 | */ 99 | public function addCondition(Aoe_FraudManager_Model_Rule_Condition_Interface $condition) 100 | { 101 | $condition->setRule($this->getRule()); 102 | 103 | $conditions = $this->getConditions(); 104 | if (!$condition->getId()) { 105 | $id = uniqid($this->getId() . '--'); 106 | while (isset($conditions[$id])) { 107 | $id = uniqid($this->getId() . '--'); 108 | } 109 | $condition->setId($id); 110 | } 111 | 112 | $conditions[$condition->getId()] = $condition; 113 | 114 | $this->setConditions($conditions); 115 | 116 | return $this; 117 | } 118 | 119 | public function removeCondition(Aoe_FraudManager_Model_Rule_Condition_Interface $condition) 120 | { 121 | $conditions = $this->getConditions(); 122 | unset($conditions[$condition->getId()]); 123 | $this->setConditions($conditions); 124 | 125 | return $this; 126 | } 127 | 128 | /** 129 | * @param Varien_Object $object 130 | * 131 | * @return bool 132 | */ 133 | public function validate(Varien_Object $object) 134 | { 135 | $conditions = $this->getConditions(); 136 | 137 | if (empty($conditions)) { 138 | return true; 139 | } 140 | 141 | $all = ($this->getAggregator() === 'all'); 142 | $true = (bool)$this->getValue(); 143 | 144 | foreach ($conditions as $condition) { 145 | $validated = $condition->validate($object); 146 | if ($all && $validated !== $true) { 147 | return false; 148 | } elseif (!$all && $validated === $true) { 149 | return true; 150 | } 151 | } 152 | 153 | return $all; 154 | } 155 | 156 | //================================================== 157 | //=[ HTML Generation ]============================== 158 | //================================================== 159 | 160 | public function getHtml() 161 | { 162 | $html = parent::getHtml(); 163 | 164 | $htmlId = $this->getForm()->getHtmlIdPrefix() . $this->getId() . '__children' . $this->getForm()->getHtmlIdSuffix(); 165 | $html .= ''; 174 | 175 | return $html; 176 | } 177 | 178 | public function getConditionConfigHtml() 179 | { 180 | return $this->translate( 181 | 'If %s of these conditions are %s:', 182 | $this->getAggregatorElement()->getHtml(), 183 | $this->getValueElement()->getHtml() 184 | ); 185 | } 186 | 187 | public function getAggregatorOptions() 188 | { 189 | $options = [ 190 | 'all' => $this->translate('ALL'), 191 | 'any' => $this->translate('ANY'), 192 | ]; 193 | 194 | return $options; 195 | } 196 | 197 | public function getAggregatorName() 198 | { 199 | $options = $this->getAggregatorOptions(); 200 | 201 | return (isset($options[$this->getAggregator()]) ? $options[$this->getAggregator()] : ''); 202 | } 203 | 204 | public function getAggregatorElement() 205 | { 206 | $element = $this->getForm()->addField( 207 | $this->getId() . '__aggregator', 208 | 'select', 209 | [ 210 | 'name' => $this->getId() . '[aggregator]', 211 | 'value' => $this->getAggregator(), 212 | 'label' => $this->getAggregatorName(), 213 | 'options' => $this->getAggregatorOptions(), 214 | ] 215 | ); 216 | 217 | $element->setRenderer(Mage::getSingleton('Aoe_FraudManager/Form_Element_Renderer_Editable')); 218 | 219 | return $element; 220 | } 221 | 222 | public function getValueOptions() 223 | { 224 | $options = [ 225 | '1' => $this->translate('TRUE'), 226 | '0' => $this->translate('FALSE'), 227 | ]; 228 | 229 | return $options; 230 | } 231 | 232 | public function getValueName() 233 | { 234 | $options = $this->getValueOptions(); 235 | 236 | return (isset($options[$this->getValue()]) ? $options[$this->getValue()] : ''); 237 | } 238 | 239 | public function getValueElement() 240 | { 241 | $element = $this->getForm()->addField( 242 | $this->getId() . '__value', 243 | 'select', 244 | [ 245 | 'name' => $this->getId() . '[value]', 246 | 'value' => $this->getValue(), 247 | 'label' => $this->getValueName(), 248 | 'options' => $this->getValueOptions(), 249 | ] 250 | ); 251 | 252 | $element->setRenderer(Mage::getSingleton('Aoe_FraudManager/Form_Element_Renderer_Editable')); 253 | 254 | return $element; 255 | } 256 | 257 | /** 258 | * Get conditions selectors 259 | * 260 | * @return array 261 | */ 262 | public function getNewChildOptions() 263 | { 264 | $conditions = ['' => $this->translate('Please choose a condition to add...')]; 265 | 266 | // Add self reference for recursive combinations 267 | $conditions[$this->getSelfType()] = $this->translate($this->getName()); 268 | 269 | // Fire an event to add additional conditions 270 | $container = new Varien_Object(); 271 | Mage::dispatchEvent('aoe_fraudmanager_rule_condition_combine_additional', ['parent' => $this, 'container' => $container]); 272 | if ($additional = $container->getConditions()) { 273 | $conditions = array_merge($conditions, $additional); 274 | } 275 | 276 | return $conditions; 277 | } 278 | 279 | public function getNewChildName() 280 | { 281 | return $this->translate('Add'); 282 | } 283 | 284 | public function getNewChildElement() 285 | { 286 | $element = $this->getForm()->addField( 287 | $this->getId() . '__new_child', 288 | 'select', 289 | [ 290 | 'name' => $this->getId() . '[new_child]', 291 | 'label' => $this->getNewChildName(), 292 | 'options' => $this->getNewChildOptions(), 293 | ] 294 | ); 295 | 296 | $element->setRenderer(Mage::getSingleton('Aoe_FraudManager/Form_Element_Renderer_Newchild')); 297 | 298 | return $element; 299 | } 300 | 301 | //================================================== 302 | //=[ Serialization / Deserialization ]============== 303 | //================================================== 304 | public function toArray() 305 | { 306 | $out = parent::toArray(); 307 | 308 | foreach ($this->getConditions() as $condition) { 309 | $out['conditions'][] = $condition->toArray(); 310 | } 311 | 312 | return $out; 313 | } 314 | 315 | public function loadArray(array $data) 316 | { 317 | parent::loadArray($data); 318 | 319 | if (array_key_exists('conditions', $data) && is_array($data['conditions'])) { 320 | foreach ($data['conditions'] as $conditionData) { 321 | try { 322 | $modelClass = $conditionData['type']; 323 | if (empty($modelClass)) { 324 | continue; 325 | } 326 | 327 | $model = Mage::getSingleton($modelClass); 328 | if (!$model || !$model instanceof Aoe_FraudManager_Model_Rule_Condition_Interface) { 329 | continue; 330 | } 331 | 332 | $condition = clone $model; 333 | if ($condition) { 334 | $this->addCondition($condition); 335 | $condition->loadArray($conditionData); 336 | if ($condition instanceof Aoe_FraudManager_Model_Rule_Condition_Combine) { 337 | $conditions = $condition->getConditions(); 338 | if (empty($conditions)) { 339 | $this->removeCondition($condition); 340 | } 341 | } 342 | } 343 | } catch (Exception $e) { 344 | Mage::logException($e); 345 | } 346 | } 347 | } 348 | 349 | return $this; 350 | } 351 | } 352 | -------------------------------------------------------------------------------- /app/design/adminhtml/default/default/layout/Aoe_FraudManager.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | css/aoe_fraudmanager.css 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | Blacklist Rules 17 | 18 | 19 | 20 | aoe_fraudmanager_blacklistrule_grid 21 | 22 | 23 | 1 24 | 25 | 26 | 27 | 28 | 29 | id 30 | 31 | id 32 | number 33 |
ID
34 | 50px 35 | right 36 |
37 |
38 | 39 | name 40 | 41 |
Name
42 | name 43 | text 44 |
45 |
46 | 47 | stop_processing 48 | 49 | stop_processing 50 |
Stop Processing
51 | options 52 | 53 | adminhtml/system_config_source_yesno 54 | 55 |
56 |
57 | 58 | is_active 59 | 60 | is_active 61 |
Active
62 | options 63 | 64 | adminhtml/system_config_source_yesno 65 | 66 |
67 |
68 | 69 | website_ids 70 | 71 | website_ids 72 |
Websites
73 | options 74 | 0 75 | 100px 76 | 77 | core/website 78 | 1 79 | 80 |
81 |
82 | 83 | sort_order 84 | 85 | sort_order 86 | number 87 |
Sort Order
88 | 50px 89 | right 90 |
91 |
92 | 93 | 94 | 95 | 96 | 97 | {{id}} 98 | 99 | 100 | 101 | id 102 | 103 | 104 | desc 105 | 106 |
107 |
108 |
109 |
110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 1 120 | 121 | 122 | 1 123 | 124 | 125 | 126 | 127 | 128 | New Rule 129 | 130 | 131 | 132 |
133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | aoe_fraudmanager_blacklistrule_edit_tabs 141 | 142 | 143 | edit_form 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | main 158 | main 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | conditions 170 | conditions 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | Edit Rule 181 | 182 | 183 | delete 184 | 185 | 186 | 187 | deleteConfirm('%s', '%s') 188 | Are you sure you want to do this? 189 | 190 | 191 | 192 | 193 | delete 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | Testing Order #%s Against All Blacklist Rules 205 | 206 | 207 | increment_id 208 | 209 | 210 | 211 | 212 | add 213 | 214 | 215 | back 216 | 217 | 218 | 219 | setLocation('%s') 220 | 221 | 222 | back 223 | 224 | 225 | 226 | 227 | aoe_fraudmanager_blacklistrule_testorder_grid 228 | 229 | 230 | 0 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 0 239 | 240 | 241 | 0 242 | 243 | 244 | id 245 | 246 | id 247 | number 248 |
ID
249 | 50px 250 | right 251 |
252 |
253 | 254 | name 255 | 256 |
Name
257 | name 258 | text 259 |
260 |
261 | 262 | is_active 263 | 264 | is_active 265 |
Active
266 | options 267 | 268 | adminhtml/system_config_source_yesno 269 | 270 |
271 |
272 | 273 | triggered 274 | 275 | triggered 276 |
Triggered
277 | options 278 | 279 | adminhtml/system_config_source_yesno 280 | 281 |
282 |
283 | 284 | timing 285 | 286 | timing 287 | number 288 |
Timing (ms)
289 | 50px 290 | right 291 |
292 |
293 | 294 | message 295 | 296 | message 297 | text 298 |
Message
299 | right 300 |
301 |
302 | 303 | 304 | 305 | 306 | 307 | {{id}} 308 | 309 | 310 |
311 |
312 |
313 |
314 | 315 | 316 | 317 | 318 | 319 | 320 | Hold Rules 321 | 322 | 323 | 324 | aoe_fraudmanager_holdrule_grid 325 | 326 | 327 | 1 328 | 329 | 330 | 331 | 332 | 333 | id 334 | 335 | id 336 | number 337 |
ID
338 | 50px 339 | right 340 |
341 |
342 | 343 | name 344 | 345 |
Name
346 | name 347 | text 348 |
349 |
350 | 351 | stop_processing 352 | 353 | stop_processing 354 |
Stop Processing
355 | options 356 | 357 | adminhtml/system_config_source_yesno 358 | 359 |
360 |
361 | 362 | is_active 363 | 364 | is_active 365 |
Active
366 | options 367 | 368 | adminhtml/system_config_source_yesno 369 | 370 |
371 |
372 | 373 | sort_order 374 | 375 | sort_order 376 | number 377 |
Sort Order
378 | 50px 379 | right 380 |
381 |
382 | 383 | 384 | 385 | 386 | 387 | {{id}} 388 | 389 | 390 | 391 | id 392 | 393 | 394 | desc 395 | 396 |
397 |
398 |
399 |
400 | 401 | 402 | 403 | 404 | 405 | 406 | 407 | 408 | 409 | 1 410 | 411 | 412 | 1 413 | 414 | 415 | 416 | 417 | 418 | New Rule 419 | 420 | 421 | 422 | 423 | 424 | 425 | 426 | 427 | 428 | 429 | 430 | aoe_fraudmanager_holdrule_edit_tabs 431 | 432 | 433 | edit_form 434 | 435 | 436 | 437 | 438 | 439 | 440 | 441 | 442 | 443 | 444 | 445 | 446 | 447 | main 448 | main 449 | 450 | 451 | 452 | 453 | 454 | 455 | 456 | 457 | 458 | 459 | conditions 460 | conditions 461 | 462 | 463 | 464 | 465 | 466 | 467 | 468 | 469 | 470 | Edit Rule 471 | 472 | 473 | delete 474 | 475 | 476 | 477 | deleteConfirm('%s', '%s') 478 | Are you sure you want to do this? 479 | 480 | 481 | 482 | 483 | delete 484 | 485 | 486 | 487 | 488 | 489 | 490 | 491 | 492 | 493 | 494 | Testing Order #%s Against All Hold Rules 495 | 496 | 497 | increment_id 498 | 499 | 500 | 501 | 502 | add 503 | 504 | 505 | back 506 | 507 | 508 | 509 | setLocation('%s') 510 | 511 | 512 | back 513 | 514 | 515 | 516 | 517 | aoe_fraudmanager_holdrule_testorder_grid 518 | 519 | 520 | 0 521 | 522 | 523 | 524 | 525 | 526 | 527 | 528 | 0 529 | 530 | 531 | 0 532 | 533 | 534 | id 535 | 536 | id 537 | number 538 |
ID
539 | 50px 540 | right 541 |
542 |
543 | 544 | name 545 | 546 |
Name
547 | name 548 | text 549 |
550 |
551 | 552 | is_active 553 | 554 | is_active 555 |
Active
556 | options 557 | 558 | adminhtml/system_config_source_yesno 559 | 560 |
561 |
562 | 563 | triggered 564 | 565 | triggered 566 |
Triggered
567 | options 568 | 569 | adminhtml/system_config_source_yesno 570 | 571 |
572 |
573 | 574 | skipped 575 | 576 | skipped 577 |
Skipped
578 | options 579 | 580 | adminhtml/system_config_source_yesno 581 | 582 |
583 |
584 | 585 | timing 586 | 587 | timing 588 | number 589 |
Timing (ms)
590 | 50px 591 | right 592 |
593 |
594 | 595 | status 596 | 597 | status 598 |
Status
599 | options 600 | 601 | adminhtml/system_config_source_order_status 602 | 603 |
604 |
605 | 606 | 607 | 608 | 609 | 610 | {{id}} 611 | 612 | 613 |
614 |
615 |
616 |
617 | 618 | 619 | 620 | 621 | 622 | 623 | 624 | 625 | 626 | 627 | 628 | is_fraud 629 | 630 | is_fraud 631 | options 632 |
Fraud
633 | 70px 634 | 635 | adminhtml/system_config_source_yesno 636 | 637 |
638 | status 639 |
640 |
641 |
642 | 643 | 644 | 645 | 646 | 647 | 648 | 649 | 650 | 651 | 652 | set_fraud_flag 653 | 654 | 655 | 656 | setLocation('%s') 657 | 658 | 659 | 660 | 661 | 662 | remove_fraud_flag 663 | 664 | 665 | 666 | setLocation('%s') 667 | 668 | 669 | 670 | 671 | 672 | test_blacklist_rules 673 | 674 | 675 | 676 | setLocation('%s') 677 | 678 | 679 | go 680 | 681 | 10 682 | 683 | 684 | test_hold_rules 685 | 686 | 687 | 688 | setLocation('%s') 689 | 690 | 691 | go 692 | 693 | 10 694 | 695 | 696 | 697 | 698 | 699 | 700 | 701 | 702 | 703 | Mark Order #%s as Fraud 704 | 705 | 706 | increment_id 707 | 708 | 709 | 710 | 711 | 712 | 713 | 714 | 715 | action 716 | 717 | 718 | 719 | 720 | 721 | 722 | 723 | 724 | 725 | 726 | 727 | Mark Order #%s as NOT Fraud 728 | 729 | 730 | increment_id 731 | 732 | 733 | 734 | 735 | 736 | 737 | 738 | 739 | action 740 | 741 | 742 | 743 | 744 | 745 | 746 | 747 | --------------------------------------------------------------------------------