riskified_magento - Version 1.0.5.4

Version Notes

* validations fix to support shopgate

Download this release

Release Info

Developer Riskified_Mage
Extension riskified_magento
Version 1.0.5.4
Comparing to
See all releases


Version 1.0.5.4

Files changed (75) hide show
  1. app/code/community/Riskified/Full/Helper/Data.php +61 -0
  2. app/code/community/Riskified/Full/Helper/Debug.php +58 -0
  3. app/code/community/Riskified/Full/Helper/Log.php +14 -0
  4. app/code/community/Riskified/Full/Helper/Order.php +500 -0
  5. app/code/community/Riskified/Full/Helper/Order/Invoice.php +31 -0
  6. app/code/community/Riskified/Full/Helper/Order/Status.php +44 -0
  7. app/code/community/Riskified/Full/Model/Authorizenet.php +47 -0
  8. app/code/community/Riskified/Full/Model/Cron.php +86 -0
  9. app/code/community/Riskified/Full/Model/Observer.php +340 -0
  10. app/code/community/Riskified/Full/Model/Resource/Retry.php +9 -0
  11. app/code/community/Riskified/Full/Model/Resource/Retry/Collection.php +9 -0
  12. app/code/community/Riskified/Full/Model/Retry.php +9 -0
  13. app/code/community/Riskified/Full/Model/System/Config/Source/CaptureCase.php +15 -0
  14. app/code/community/Riskified/Full/Model/System/Config/Source/Env.php +13 -0
  15. app/code/community/Riskified/Full/Test/Config/General.php +59 -0
  16. app/code/community/Riskified/Full/Test/Helper/General.php +25 -0
  17. app/code/community/Riskified/Full/Test/Helper/General/fixtures/extensionConfigEnabled.yaml +7 -0
  18. app/code/community/Riskified/Full/Test/Model/Environments.php +22 -0
  19. app/code/community/Riskified/Full/controllers/Adminhtml/FullController.php +22 -0
  20. app/code/community/Riskified/Full/controllers/ResponseController.php +50 -0
  21. app/code/community/Riskified/Full/etc/config.xml +293 -0
  22. app/code/community/Riskified/Full/etc/system.xml +112 -0
  23. app/code/community/Riskified/Full/sql/riskified_full_setup/mysql4-install-1.0.1.php +14 -0
  24. app/code/community/Riskified/Full/sql/riskified_full_setup/mysql4-install-1.0.2.1.php +14 -0
  25. app/code/community/Riskified/Full/sql/riskified_full_setup/mysql4-upgrade-1.0.4-1.0.5.0.php +39 -0
  26. app/design/adminhtml/default/default/layout/full.xml +8 -0
  27. app/design/adminhtml/default/default/template/full/jsinit.phtml +251 -0
  28. app/design/frontend/base/default/layout/full.xml +9 -0
  29. app/design/frontend/base/default/template/full/riskified.phtml +19 -0
  30. app/etc/modules/Riskified_Full.xml +9 -0
  31. lib/riskified_php_sdk/.gitignore +3 -0
  32. lib/riskified_php_sdk/README.md +46 -0
  33. lib/riskified_php_sdk/sample/callback.php +63 -0
  34. lib/riskified_php_sdk/sample/order_webhook.php +215 -0
  35. lib/riskified_php_sdk/sample/run_callback_server.sh +20 -0
  36. lib/riskified_php_sdk/sample/upload_historical.php +83 -0
  37. lib/riskified_php_sdk/src/Riskified/Common/Env.php +31 -0
  38. lib/riskified_php_sdk/src/Riskified/Common/Exception/BaseException.php +17 -0
  39. lib/riskified_php_sdk/src/Riskified/Common/Riskified.php +82 -0
  40. lib/riskified_php_sdk/src/Riskified/Common/Signature/HttpDataSignature.php +40 -0
  41. lib/riskified_php_sdk/src/Riskified/DecisionNotification/Exception/AuthorizationException.php +38 -0
  42. lib/riskified_php_sdk/src/Riskified/DecisionNotification/Exception/BadHeaderException.php +35 -0
  43. lib/riskified_php_sdk/src/Riskified/DecisionNotification/Exception/BadPostJsonException.php +22 -0
  44. lib/riskified_php_sdk/src/Riskified/DecisionNotification/Exception/NotificationException.php +45 -0
  45. lib/riskified_php_sdk/src/Riskified/DecisionNotification/Model/Notification.php +87 -0
  46. lib/riskified_php_sdk/src/Riskified/OrderWebhook/Exception/ClassMismatchPropertyException.php +22 -0
  47. lib/riskified_php_sdk/src/Riskified/OrderWebhook/Exception/CurlException.php +24 -0
  48. lib/riskified_php_sdk/src/Riskified/OrderWebhook/Exception/FormatMismatchPropertyException.php +22 -0
  49. lib/riskified_php_sdk/src/Riskified/OrderWebhook/Exception/InvalidPropertyException.php +22 -0
  50. lib/riskified_php_sdk/src/Riskified/OrderWebhook/Exception/MalformedJsonException.php +41 -0
  51. lib/riskified_php_sdk/src/Riskified/OrderWebhook/Exception/MissingPropertyException.php +22 -0
  52. lib/riskified_php_sdk/src/Riskified/OrderWebhook/Exception/MultiplePropertiesException.php +42 -0
  53. lib/riskified_php_sdk/src/Riskified/OrderWebhook/Exception/PropertyException.php +73 -0
  54. lib/riskified_php_sdk/src/Riskified/OrderWebhook/Exception/TypeMismatchPropertyException.php +22 -0
  55. lib/riskified_php_sdk/src/Riskified/OrderWebhook/Exception/UnsuccessfulActionException.php +45 -0
  56. lib/riskified_php_sdk/src/Riskified/OrderWebhook/Model/AbstractModel.php +284 -0
  57. lib/riskified_php_sdk/src/Riskified/OrderWebhook/Model/Address.php +42 -0
  58. lib/riskified_php_sdk/src/Riskified/OrderWebhook/Model/Attribute.php +28 -0
  59. lib/riskified_php_sdk/src/Riskified/OrderWebhook/Model/ClientDetails.php +31 -0
  60. lib/riskified_php_sdk/src/Riskified/OrderWebhook/Model/Customer.php +43 -0
  61. lib/riskified_php_sdk/src/Riskified/OrderWebhook/Model/DiscountCode.php +28 -0
  62. lib/riskified_php_sdk/src/Riskified/OrderWebhook/Model/Fulfillment.php +39 -0
  63. lib/riskified_php_sdk/src/Riskified/OrderWebhook/Model/LineItem.php +50 -0
  64. lib/riskified_php_sdk/src/Riskified/OrderWebhook/Model/Order.php +81 -0
  65. lib/riskified_php_sdk/src/Riskified/OrderWebhook/Model/OrderCancellation.php +29 -0
  66. lib/riskified_php_sdk/src/Riskified/OrderWebhook/Model/PaymentDetails.php +39 -0
  67. lib/riskified_php_sdk/src/Riskified/OrderWebhook/Model/Refund.php +28 -0
  68. lib/riskified_php_sdk/src/Riskified/OrderWebhook/Model/RefundDetails.php +32 -0
  69. lib/riskified_php_sdk/src/Riskified/OrderWebhook/Model/ShippingLine.php +32 -0
  70. lib/riskified_php_sdk/src/Riskified/OrderWebhook/Model/TaxLine.php +29 -0
  71. lib/riskified_php_sdk/src/Riskified/OrderWebhook/Transport/AbstractTransport.php +151 -0
  72. lib/riskified_php_sdk/src/Riskified/OrderWebhook/Transport/CurlTransport.php +81 -0
  73. lib/riskified_php_sdk/src/Riskified/autoloader.php +29 -0
  74. package.xml +20 -0
  75. skin/adminhtml/default/default/images/riskified/logo.jpg +0 -0
app/code/community/Riskified/Full/Helper/Data.php ADDED
@@ -0,0 +1,61 @@
1
+ <?php
2
+
3
+ require_once(Mage::getBaseDir('lib') . DIRECTORY_SEPARATOR . 'riskified_php_sdk' . DIRECTORY_SEPARATOR . 'src' . DIRECTORY_SEPARATOR . 'Riskified' . DIRECTORY_SEPARATOR . 'autoloader.php');
4
+
5
+ class Riskified_Full_Helper_Data extends Mage_Core_Helper_Abstract {
6
+
7
+ public function getAdminUrl(){
8
+ $out = null;
9
+ $match = preg_match("/(.*)full\/response\/getresponse.*/i", Mage::helper('adminhtml')->getUrl('full/response/getresponse'),$out);
10
+ if ($match){
11
+ return $out[1];
12
+ }else{
13
+ return "";
14
+ }
15
+ }
16
+
17
+ public function getAuthToken(){
18
+ return Mage::getStoreConfig('fullsection/full/key',Mage::app()->getStore());
19
+ }
20
+
21
+ public function getConfigStatusControlActive(){
22
+ return Mage::getStoreConfig('fullsection/full/order_status_sync');
23
+ }
24
+
25
+ public function getConfigEnv(){
26
+ return 'Riskified\Common\Env::' . Mage::getStoreConfig('fullsection/full/env');
27
+ }
28
+
29
+ public function getConfigBeaconUrl(){
30
+ return Mage::getStoreConfig('fullsection/full/beaconurl');
31
+ }
32
+
33
+ public function getShopDomain(){
34
+ return Mage::getStoreConfig('fullsection/full/domain');
35
+ }
36
+
37
+ public function getExtensionVersion(){
38
+ return (string) Mage::getConfig()->getNode()->modules->Riskified_Full->version;
39
+ }
40
+
41
+ public function getSessionId(){
42
+ $visitorData = Mage::getSingleton('core/session')->getVisitorData();
43
+ return $visitorData['session_id'];
44
+ }
45
+
46
+ /**
47
+ * @return string
48
+ */
49
+ public function getSdkVersion()
50
+ {
51
+ return Riskified\Common\Riskified::VERSION;
52
+ }
53
+
54
+ /**
55
+ * @return string
56
+ */
57
+ public function getSdkApiVersion()
58
+ {
59
+ return Riskified\Common\Riskified::API_VERSION;
60
+ }
61
+ }
app/code/community/Riskified/Full/Helper/Debug.php ADDED
@@ -0,0 +1,58 @@
1
+ <?php
2
+
3
+ class Riskified_Full_Helper_Debug extends Mage_Core_Helper_Abstract
4
+ {
5
+ const ALERT_EMAIL = 'assaf@riskified.com';
6
+ const CONFIG_SECTION = 'fullsection';
7
+
8
+ /**
9
+ * Send all relevant debug info to riskified
10
+ *
11
+ * @return void
12
+ */
13
+ public function sendDebugInfoToRiskified()
14
+ {
15
+ $debugData = $this->_getDebugData();
16
+
17
+ $mail = new Zend_Mail();
18
+ $mail->setBodyHtml(print_r($debugData, true))
19
+ ->setFrom(Mage::getStoreConfig('trans_email/ident_general/email'), Mage::getStoreConfig('trans_email/ident_general/name'))
20
+ ->addTo(self::ALERT_EMAIL)
21
+ ->setSubject('Magento Extension Debug Info for ' . Mage::getBaseUrl());
22
+
23
+ try {
24
+ $mail->send();
25
+ }
26
+ catch (Exception $e) {
27
+ Mage::helper('full/log')->logException($e);
28
+ }
29
+ }
30
+
31
+ /**
32
+ * @return array
33
+ */
34
+ protected function _getDebugData()
35
+ {
36
+ $helper = Mage::helper('full');
37
+
38
+ // Relevant version numbers
39
+ $data = array(
40
+ 'magentoVersion' => Mage::getVersion(),
41
+ 'magentoExtensionVersion' => $helper->getExtensionVersion(),
42
+ 'magentoBaseUrl' => Mage::getBaseUrl(),
43
+ 'sdkVersion' => $helper->getSdkVersion(),
44
+ 'sdkApiVersion' => $helper->getSdkApiVersion()
45
+ );
46
+
47
+ // All Riskified config values
48
+ $configGroups = Mage::getStoreConfig(self::CONFIG_SECTION);
49
+
50
+ foreach($configGroups as $groupName => $group) {
51
+ foreach($group as $fieldName => $field) {
52
+ $data['magentoConfig-' . self::CONFIG_SECTION . '/' . $groupName . '/' . $fieldName] = $field;
53
+ }
54
+ }
55
+
56
+ return $data;
57
+ }
58
+ }
app/code/community/Riskified/Full/Helper/Log.php ADDED
@@ -0,0 +1,14 @@
1
+ <?php
2
+
3
+ class Riskified_Full_Helper_Log extends Mage_Core_Helper_Abstract
4
+ {
5
+ public function log($message, $level = null)
6
+ {
7
+ Mage::log($message, $level, 'riskified_full.log');
8
+ }
9
+
10
+ public function logException($e)
11
+ {
12
+ $this->log("Riskified extension had an exception: " . $e->getMessage());
13
+ }
14
+ }
app/code/community/Riskified/Full/Helper/Order.php ADDED
@@ -0,0 +1,500 @@
1
+ <?php
2
+
3
+ require_once(Mage::getBaseDir('lib') . DIRECTORY_SEPARATOR . 'riskified_php_sdk' . DIRECTORY_SEPARATOR . 'src' . DIRECTORY_SEPARATOR . 'Riskified' . DIRECTORY_SEPARATOR . 'autoloader.php');
4
+ use Riskified\Common\Riskified;
5
+ use Riskified\Common\Signature;
6
+ use Riskified\OrderWebhook\Model;
7
+ use Riskified\OrderWebhook\Transport;
8
+ use Riskified\DecisionNotification\Model\Notification as DecisionNotification;
9
+
10
+
11
+ class Riskified_Full_Helper_Order extends Mage_Core_Helper_Abstract {
12
+ const ACTION_CREATE = 'create';
13
+ const ACTION_UPDATE = 'update';
14
+ const ACTION_SUBMIT = 'submit';
15
+ const ACTION_CANCEL = 'cancel';
16
+
17
+ public function __construct() {
18
+ $this->initSdk();
19
+ }
20
+
21
+ /**
22
+ * Submit an order to Riskified.
23
+ *
24
+ * @param Mage_Sales_Model_Order $order
25
+ * @param string $action - one of self::ACTION_*
26
+ * @return stdClass
27
+ * @throws Exception
28
+ */
29
+ public function postOrder($order, $action) {
30
+ $transport = $this->getTransport();
31
+ $headers = $this->getHeaders();
32
+
33
+ Mage::helper('full/log')->log('postOrder ' . serialize($headers) . ' - ' . $action);
34
+
35
+ $eventData = array(
36
+ 'order' => $order,
37
+ 'action' => $action
38
+ );
39
+
40
+ try {
41
+ switch ($action) {
42
+ case self::ACTION_CREATE:
43
+ $orderForTransport = $this->getOrder($order);
44
+ $response = $transport->createOrder($orderForTransport);
45
+
46
+ break;
47
+ case self::ACTION_UPDATE:
48
+ $orderForTransport = $this->getOrder($order);
49
+ $response = $transport->updateOrder($orderForTransport);
50
+
51
+ break;
52
+ case self::ACTION_SUBMIT:
53
+ $orderForTransport = $this->getOrder($order);
54
+ $response = $transport->submitOrder($orderForTransport);
55
+
56
+ break;
57
+ case self::ACTION_CANCEL:
58
+ $orderForTransport = $this->getOrderCancellation($order);
59
+ $response = $transport->cancelOrder($orderForTransport);
60
+
61
+ break;
62
+ }
63
+
64
+ $eventData['response'] = $response;
65
+
66
+ Mage::dispatchEvent(
67
+ 'riskified_full_post_order_success',
68
+ $eventData
69
+ );
70
+ } catch(\Riskified\OrderWebhook\Exception\CurlException $curlException) {
71
+ Mage::helper('full/log')->logException($curlException);
72
+ Mage::getSingleton('adminhtml/session')->addError('Riskified extension: ' . $curlException->getMessage());
73
+
74
+ $this->updateOrder($order, 'error', 'Error transferring order data to Riskified');
75
+ $this->scheduleSubmissionRetry($order, $action);
76
+
77
+ Mage::dispatchEvent(
78
+ 'riskified_full_post_order_error',
79
+ $eventData
80
+ );
81
+
82
+ throw $curlException;
83
+ }
84
+ catch (Exception $e) {
85
+ Mage::helper('full/log')->logException($e);
86
+ Mage::getSingleton('adminhtml/session')->addError('Riskified extension: ' . $e->getMessage());
87
+
88
+ Mage::dispatchEvent(
89
+ 'riskified_full_post_order_error',
90
+ $eventData
91
+ );
92
+
93
+ throw $e;
94
+ }
95
+
96
+ return $response;
97
+ }
98
+
99
+ public function postHistoricalOrders($models) {
100
+ $orders = array();
101
+ foreach ($models as $model) {
102
+ $orders[] = $this->getOrder($model);
103
+ }
104
+
105
+ $msgs = $this->getTransport()->sendHistoricalOrders($orders);
106
+ return "Successfully uploaded ".count($msgs)." orders.".PHP_EOL;
107
+ }
108
+
109
+ /**
110
+ * Dispatch events for order update handling
111
+ *
112
+ * Possible events are:
113
+ * - riskified_order_update
114
+ * - riskified_order_update_approved
115
+ * - riskified_order_update_declined
116
+ * - riskified_order_update_submitted
117
+ * - riskified_order_update_captured
118
+ * - riskified_order_update_error
119
+ * - riskified_order_update_?
120
+ *
121
+ * @param Mage_Sales_Model_Order $order
122
+ * @param string $status
123
+ * @param string $description
124
+ * @return void
125
+ */
126
+ public function updateOrder($order, $status, $description) {
127
+ Mage::helper('full/log')->log('Dispatching event for order ' . $order->getId() . ' with status "' . $status . '" and description "' . $description . '"');
128
+
129
+ $eventData = array(
130
+ 'order' => $order,
131
+ 'status' => $status,
132
+ 'description' => $description
133
+ );
134
+
135
+ // A generic event for all updates
136
+ Mage::dispatchEvent(
137
+ 'riskified_full_order_update',
138
+ $eventData
139
+ );
140
+
141
+ // A status-specific event
142
+ $eventIdentifier = preg_replace("/[^a-z]/", '_', strtolower($status));
143
+
144
+ Mage::dispatchEvent(
145
+ 'riskified_full_order_update_' . $eventIdentifier,
146
+ $eventData
147
+ );
148
+
149
+ return;
150
+ }
151
+
152
+ public function getRiskifiedDomain() {
153
+ return Riskified::getHostByEnv();
154
+ }
155
+
156
+ public function parseRequest($request) {
157
+ $header_name = Signature\HttpDataSignature::HMAC_HEADER_NAME;
158
+ $headers = array($header_name => $request->getHeader($header_name));
159
+ $body = $request->getRawBody();
160
+ Mage::helper('full/log')->log("Received new notification request with headers: " . json_encode($headers) . " and body: $body. Trying to parse.");
161
+ return new
162
+ DecisionNotification(new Signature\HttpDataSignature(), $headers, $body);
163
+ }
164
+
165
+ private $version;
166
+
167
+ private function initSdk() {
168
+ $helper = Mage::helper('full');
169
+ $authToken = $helper->getAuthToken();
170
+ $env = constant($helper->getConfigEnv());
171
+ $shopDomain = $helper->getShopDomain();
172
+ $this->version = $helper->getExtensionVersion();
173
+ $sdkVersion = Riskified::VERSION;
174
+
175
+ Mage::helper('full/log')->log("Riskified initSdk() - shop: $shopDomain, env: $env, token: $authToken, extension_version: $this->version, sdk_version: $sdkVersion");
176
+ Riskified::init($shopDomain, $authToken, $env, \Riskified\Common\Validations::SKIP);
177
+ }
178
+
179
+ private function getHeaders() {
180
+ return array('headers' => array('X_RISKIFIED_VERSION:'.$this->version));
181
+ }
182
+
183
+ private function getTransport() {
184
+ $transport = new Transport\CurlTransport(new Signature\HttpDataSignature());
185
+ $transport->timeout = 15;
186
+ return $transport;
187
+ }
188
+
189
+ private function getOrderCancellation($model) {
190
+ $orderCancellation = new Model\OrderCancellation(array_filter(array(
191
+ 'id' => $model->getId(),
192
+ 'cancelled_at' => $this->formatDateAsIso8601($this->getCancelledAt($model)),
193
+ 'cancel_reason' => 'Cancelled by merchant'
194
+ )));
195
+
196
+ Mage::helper('full/log')->log("getOrderCancellation(): ".PHP_EOL.json_encode(json_decode($orderCancellation->toJson())));
197
+
198
+ return $orderCancellation;
199
+ }
200
+
201
+ private function getOrder($model) {
202
+ $order = new Model\Order(array_filter(array(
203
+ 'id' => $model->getId(),
204
+ 'name' => $model->getIncrementId(),
205
+ 'email' => $model->getCustomerEmail(),
206
+ 'created_at' => $this->formatDateAsIso8601($model->getCreatedAt()),
207
+ 'currency' => $model->getOrderCurrencyCode(), // was getBaseCurrencyCode() before by mistake
208
+ 'updated_at' => $this->formatDateAsIso8601($model->getUpdatedAt()),
209
+ 'gateway' => $model->getPayment()->getMethod(),
210
+ 'browser_ip' => $this->getRemoteIp($model),
211
+ 'cart_token' => Mage::helper('full')->getSessionId(),
212
+ 'note' => $model->getCustomerNote(),
213
+ 'total_price' => $model->getGrandTotal(),
214
+ 'total_discounts' => $model->getDiscountAmount(),
215
+ 'subtotal_price' => $model->getBaseSubtotalInclTax(),
216
+ 'discount_codes' =>$this->getDiscountCodes($model),
217
+ 'taxes_included' => true,
218
+ 'total_tax' => $model->getBaseTaxAmount(),
219
+ 'total_weight' => $model->getWeight(),
220
+ 'cancelled_at' => $this->formatDateAsIso8601($this->getCancelledAt($model)),
221
+ 'financial_status' => $model->getState()
222
+ ),'strlen'));
223
+
224
+ $order->customer = $this->getCustomer($model);
225
+ $order->shipping_address = $this->getShippingAddress($model);
226
+ $order->billing_address = $this->getBillingAddress($model);
227
+ $order->payment_details = $this->getPaymentDetails($model);
228
+ $order->line_items = $this->getLineItems($model);
229
+ $order->shipping_lines = $this->getShippingLines($model);
230
+ $order->client_details = $this->getClientDetails($model);
231
+
232
+ Mage::helper('full/log')->log("getOrder(): ".PHP_EOL.json_encode(json_decode($order->toJson())));
233
+
234
+ return $order;
235
+ }
236
+
237
+ private function getCustomer($model) {
238
+ $customer_id = $model->getCustomerId();
239
+ $customer_props = array(
240
+ 'id' => $customer_id,
241
+ 'email' => $model->getCustomerEmail(),
242
+ 'first_name' => $model->getCustomerFirstname(),
243
+ 'last_name' => $model->getCustomerLastname(),
244
+ 'note' => $model->getCustomerNote(),
245
+ );
246
+
247
+ if ($customer_id) {
248
+ $customer_details = Mage::getModel('customer/customer')->load($customer_id);
249
+ $customer_props['created_at'] = $this->formatDateAsIso8601($customer_details->getCreatedAt());
250
+ $customer_props['updated_at'] = $this->formatDateAsIso8601($customer_details->getUpdatedAt());
251
+
252
+ $customer_orders = Mage::getModel('sales/order')->getCollection()->addFieldToFilter('customer_id', $customer_id);
253
+ $customer_orders_count = $customer_orders->count();
254
+
255
+ $customer_props['orders_count'] = $customer_orders_count;
256
+ if ($customer_orders_count) {
257
+ $customer_props['last_order_id'] = $customer_orders->getLastItem()->getId();
258
+ $customer_props['total_spent'] = array_sum($customer_orders->getColumnValues('base_grand_total'));
259
+ }
260
+ }
261
+
262
+ return new Model\Customer(array_filter($customer_props,'strlen'));
263
+ }
264
+
265
+ private function getShippingAddress($model) {
266
+ $mageAddr = $model->getShippingAddress();
267
+ return $this->getAddress($mageAddr);
268
+ }
269
+
270
+ private function getBillingAddress($model) {
271
+ $mageAddr = $model->getBillingAddress();
272
+ return $this->getAddress($mageAddr);
273
+ }
274
+
275
+ private function getPaymentDetails($model) {
276
+ $payment = $model->getPayment();
277
+ if(!$payment) {
278
+ return null;
279
+ }
280
+
281
+ $transactionId = $payment->getTransactionId();
282
+
283
+ $gateway_name = $payment->getMethod();
284
+ switch ($gateway_name) {
285
+ case 'authorizenet':
286
+ $cards_data = array_values($payment->getAdditionalInformation('authorize_cards'));
287
+ $card_data = $cards_data[0];
288
+ $avs_result_code = $card_data['cc_avs_result_code']; // getAvsResultCode
289
+ $cvv_result_code = $card_data['cc_response_code']; // getCardCodeResponseCode
290
+ $credit_card_number = $card_data['cc_last4'];
291
+ $credit_card_company = $card_data['cc_type'];
292
+ break;
293
+ case 'paypal_express':
294
+ case 'paypaluk_express':
295
+ $payer_email = $payment->getAdditionalInformation('paypal_payer_email');
296
+ $payer_status = $payment->getAdditionalInformation('paypal_payer_status');
297
+ $payer_address_status = $payment->getAdditionalInformation('paypal_address_status');
298
+ $protection_eligibility = $payment->getAdditionalInformation('paypal_protection_eligibility');
299
+ $payment_status = $payment->getAdditionalInformation('paypal_payment_status');
300
+ $pending_reason = $payment->getAdditionalInformation('paypal_pending_reason');
301
+
302
+ return new Model\PaymentDetails(array_filter(array(
303
+ 'authorization_id' => $transactionId,
304
+ 'payer_email' => $payer_email,
305
+ 'payer_status' => $payer_status,
306
+ 'payer_address_status' => $payer_address_status,
307
+ 'protection_eligibility' => $protection_eligibility,
308
+ 'payment_status' => $payment_status,
309
+ 'pending_reason' => $pending_reason
310
+ ),'strlen'));
311
+
312
+ case 'paypal_direct':
313
+ case 'paypaluk_direct':
314
+ $avs_result_code = $payment->getAdditionalInformation('paypal_avs_code');
315
+ $cvv_result_code = $payment->getAdditionalInformation('paypal_cvv2_match');
316
+ $credit_card_number = $payment->getCcLast4();
317
+ $credit_card_company = $payment->getCcType();
318
+ break;
319
+
320
+ case 'sagepaydirectpro':
321
+ $sage = $model->getSagepayInfo();
322
+ $avs_result_code = $sage->getData('address_result');
323
+ $cvv_result_code = $sage->getData('cv2result');
324
+ $credit_card_number = $sage->getData('last_four_digits');
325
+ $credit_card_company = $sage->getData('card_type');
326
+ break;
327
+
328
+ default:
329
+ Mage::helper('full/log')->log("unknown gateway:". $gateway_name);
330
+ break;
331
+ }
332
+
333
+ if (!$cvv_result_code) {
334
+ $cvv_result_code = $payment->getCcCidStatus();
335
+ }
336
+ if (!$credit_card_number) {
337
+ $credit_card_number = $payment->getCcLast4();
338
+ }
339
+ if (!$credit_card_company) {
340
+ $credit_card_company = $payment->getCcType();
341
+ }
342
+ if (!$avs_result_code) {
343
+ $avs_result_code = $payment->getCcAvsStatus();
344
+ }
345
+
346
+ if($credit_card_number) {
347
+ $credit_card_number = "XXXX-XXXX-XXXX-" . $credit_card_number;
348
+ }
349
+ $credit_card_bin = $payment->getAdditionalInformation('riskified_cc_bin');
350
+
351
+ return new Model\PaymentDetails(array_filter(array(
352
+ 'authorization_id' => $transactionId,
353
+ 'avs_result_code' => $avs_result_code,
354
+ 'cvv_result_code' => $cvv_result_code,
355
+ 'credit_card_number' => $credit_card_number,
356
+ 'credit_card_company' => $credit_card_company,
357
+ 'credit_card_bin' => $credit_card_bin
358
+ ),'strlen'));
359
+ }
360
+
361
+ private function getLineItems($model) {
362
+ $line_items = array();
363
+ //foreach ($model->getItemsCollection() as $key => $val) {
364
+ foreach ($model->getAllVisibleItems() as $key => $val) {
365
+ $line_items[] = new Model\LineItem(array_filter(array(
366
+ 'price' => $val->getPrice(),
367
+ 'quantity' => intval($val->getQtyOrdered()),
368
+ 'title' => $val->getName(),
369
+ 'sku' => $val->getSku(),
370
+ 'product_id' => $val->getItemId(),
371
+ 'grams' => $val->getWeight(),
372
+ 'vendor' => $model->getStoreName()
373
+ ),'strlen'));
374
+ }
375
+ return $line_items;
376
+ }
377
+
378
+ private function getShippingLines($model) {
379
+ return new Model\ShippingLine(array_filter(array(
380
+ 'price' => $model->getShippingAmount(),
381
+ 'title' => $model->getShippingDescription(),
382
+ 'code' => $model->getShippingMethod()
383
+ ),'strlen'));
384
+ }
385
+
386
+ private function getClientDetails($model) {
387
+ return new Model\ClientDetails(array_filter(array(
388
+ 'accept_language' => Mage::app()->getLocale()->getLocaleCode(),
389
+ 'browser_ip' => $this->getRemoteIp($model),
390
+ 'user_agent' => Mage::helper('core/http')->getHttpUserAgent()
391
+ ),'strlen'));
392
+ }
393
+
394
+ private function getAddress($address) {
395
+ if(!$address) {
396
+ return null;
397
+ }
398
+
399
+ $street = $address->getStreet();
400
+ $address_1 = (!is_null($street) && array_key_exists('0', $street)) ? $street['0'] : null;
401
+ $address_2 = (!is_null($street) && array_key_exists('1', $street)) ? $street['1'] : null;
402
+
403
+ $addrArray = array_filter(array(
404
+ 'first_name' => $address->getFirstname(),
405
+ 'last_name' => $address->getLastname(),
406
+ 'name' => $address->getFirstname() . " " . $address->getLastname(),
407
+ 'company' => $address->getCompany(),
408
+ 'address1' => $address_1,
409
+ 'address2' => $address_2,
410
+ 'city' => $address->getCity(),
411
+ 'country_code' => $address->getCountryId(),
412
+ 'country' => Mage::getModel('directory/country')->load($address->getCountryId())->getName(),
413
+ 'province' => $address->getRegion(),
414
+ 'zip' => $address->getPostcode(),
415
+ 'phone' => $address->getTelephone(),
416
+ ), 'strlen');
417
+
418
+ if(!$addrArray) {
419
+ return null;
420
+ }
421
+ return new Model\Address($addrArray);
422
+ }
423
+
424
+ private function getDiscountCodes($model) {
425
+ $code = $model->getDiscountDescription();
426
+ $amount = $model->getDiscountAmount();
427
+ if ($amount && $code)
428
+ return new Model\DiscountCode(array_filter(array(
429
+ 'code' => $code,
430
+ 'amount' => $amount
431
+ )));
432
+ return null;
433
+ }
434
+
435
+ private function getCancelledAt($model) {
436
+ $commentCollection = $model->getStatusHistoryCollection();
437
+ foreach ($commentCollection as $comment) {
438
+ if ($comment->getStatus() == Mage_Sales_Model_Order::STATE_CANCELED) {
439
+ return 'now';
440
+ }
441
+ }
442
+ return null;
443
+ }
444
+
445
+ private function formatDateAsIso8601($dateStr) {
446
+ return ($dateStr==NULL) ? NULL : date('c',strtotime($dateStr));
447
+ }
448
+
449
+ private function getRemoteIp($model) {
450
+ Mage::helper('full/log')->log("remote ip: " . $model->getRemoteIp() . ", x-forwarded-ip: " . $model->getXForwardedFor());
451
+
452
+ $forwardedIp = $model->getXForwardedFor();
453
+ $forwardeds = preg_split("/,/",$forwardedIp, -1, PREG_SPLIT_NO_EMPTY);
454
+ if (!empty($forwardeds)) {
455
+ return trim($forwardeds[0]);
456
+ }
457
+ $remoteIp = $model->getRemoteIp();
458
+ $remotes = preg_split("/,/",$remoteIp, -1, PREG_SPLIT_NO_EMPTY);
459
+ if (!empty($remotes)) {
460
+ return trim($remotes[0]);
461
+ }
462
+
463
+ return $remoteIp;
464
+ }
465
+
466
+ /**
467
+ * Schedule an attempt to retry this order submission. This should be called any time a submission attempt fails.
468
+ *
469
+ * @param Mage_Sales_Model_Order $order
470
+ * @param string $action - one of self::ACTION_*
471
+ * @return void
472
+ */
473
+ public function scheduleSubmissionRetry(Mage_Sales_Model_Order $order, $action)
474
+ {
475
+ Mage::helper('full/log')->log("Scheduling submission retry for order " . $order->getId());
476
+
477
+ try {
478
+ $existingRetries = Mage::getModel('full/retry')->getCollection()
479
+ ->addfieldtofilter('order_id', $order->getId())
480
+ ->addfieldtofilter('action', $action);
481
+
482
+ // Only schedule a retry if one doesn't exist for this order/action combination.
483
+ // If one already exists it will be updated in Riskified_Full_Model_Cron::retrySubmissions() so
484
+ // there is no need to do anything here (eg update the existing retry).
485
+ if ($existingRetries->count() == 0) {
486
+ Mage::getModel('full/retry')
487
+ ->addData(array(
488
+ 'order_id' => $order->getId(),
489
+ 'action' => $action,
490
+ 'updated_at' => Mage::getSingleton('core/date')->gmtDate()
491
+ ))
492
+ ->save();
493
+
494
+ Mage::helper('full/log')->log("New retry scheduled successfully");
495
+ }
496
+ } catch (Exception $e) {
497
+ Mage::helper('full/log')->logException($e);
498
+ }
499
+ }
500
+ }
app/code/community/Riskified/Full/Helper/Order/Invoice.php ADDED
@@ -0,0 +1,31 @@
1
+ <?php
2
+
3
+ class Riskified_Full_Helper_Order_Invoice extends Mage_Core_Helper_Abstract
4
+ {
5
+
6
+ /**
7
+ * Has this user enabled auto-invoicing when orders are approved?
8
+ *
9
+ * @return bool
10
+ */
11
+ public function isAutoInvoiceEnabled()
12
+ {
13
+ return (bool) Mage::getStoreConfig('fullsection/full/auto_invoice_enabled');
14
+ }
15
+
16
+ /**
17
+ * Get the capture case to be used during auto-invoicing
18
+ *
19
+ * @return string
20
+ */
21
+ public function getCaptureCase()
22
+ {
23
+ $case = Mage::getStoreConfig('fullsection/full/auto_invoice_capture_case');
24
+
25
+ if (!in_array($case, array(Mage_Sales_Model_Order_Invoice::CAPTURE_ONLINE, Mage_Sales_Model_Order_Invoice::CAPTURE_OFFLINE))) {
26
+ $case = Mage_Sales_Model_Order_Invoice::CAPTURE_ONLINE;
27
+ }
28
+
29
+ return $case;
30
+ }
31
+ }
app/code/community/Riskified/Full/Helper/Order/Status.php ADDED
@@ -0,0 +1,44 @@
1
+ <?php
2
+
3
+ class Riskified_Full_Helper_Order_Status extends Mage_Core_Helper_Abstract
4
+ {
5
+ /**
6
+ * Get Riskified's custom "on hold for review" status code
7
+ *
8
+ * @return string
9
+ */
10
+ public function getOnHoldStatusCode()
11
+ {
12
+ return 'riskified_holded';
13
+ }
14
+
15
+ /**
16
+ * Get Riskified's custom "on hold for review" status label
17
+ *
18
+ * @return string
19
+ */
20
+ public function getOnHoldStatusLabel()
21
+ {
22
+ return 'On Hold (Riskified)';
23
+ }
24
+
25
+ /**
26
+ * Get Riskified's custom "on hold due to transport error" status code
27
+ *
28
+ * @return string
29
+ */
30
+ public function getTransportErrorStatusCode()
31
+ {
32
+ return 'riskified_trans_error';
33
+ }
34
+
35
+ /**
36
+ * Get Riskified's custom "on hold due to transport error" status label
37
+ *
38
+ * @return string
39
+ */
40
+ public function getTransportErrorStatusLabel()
41
+ {
42
+ return 'On Hold (Riskified Transport Error)';
43
+ }
44
+ }
app/code/community/Riskified/Full/Model/Authorizenet.php ADDED
@@ -0,0 +1,47 @@
1
+ <?php
2
+ /**
3
+ * Magento
4
+ *
5
+ * NOTICE OF LICENSE
6
+ *
7
+ * This source file is subject to the Open Software License (OSL 3.0)
8
+ * that is bundled with this package in the file LICENSE.txt.
9
+ * It is also available through the world-wide-web at this URL:
10
+ * http://opensource.org/licenses/osl-3.0.php
11
+ * If you did not receive a copy of the license and are unable to
12
+ * obtain it through the world-wide-web, please send an email
13
+ * to license@magentocommerce.com so we can send you a copy immediately.
14
+ *
15
+ * DISCLAIMER
16
+ *
17
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
18
+ * versions in the future. If you wish to customize Magento for your
19
+ * needs please refer to http://www.magentocommerce.com for more information.
20
+ *
21
+ * @category Mage
22
+ * @package Mage_Paygate
23
+ * @copyright Copyright (c) 2012 Magento Inc. (http://www.magentocommerce.com)
24
+ * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
25
+ */
26
+
27
+
28
+ class Riskified_Full_Model_Authorizenet extends Mage_Paygate_Model_Authorizenet
29
+ {
30
+ /**
31
+ * it sets card`s data into additional information of payment model
32
+ *
33
+ * @param mage_paygate_model_authorizenet_result $response
34
+ * @param mage_sales_model_order_payment $payment
35
+ * @return varien_object
36
+ */
37
+ protected function _registercard(varien_object $response, mage_sales_model_order_payment $payment)
38
+ {
39
+ Mage::helper('full/log')->log( "in inherited _registercard." );
40
+ $card=parent::_registercard($response,$payment);
41
+ $card->setCcAvsResultCode($response->getAvsResultCode());
42
+ $card->setCcResponseCode($response->getCardCodeResponseCode());
43
+ $payment->setCcAvsStatus($response->getAvsResultCode());
44
+ $payment->setCcCidStatus($response->getCardCodeResponseCode());
45
+ return $card;
46
+ }
47
+ }
app/code/community/Riskified/Full/Model/Cron.php ADDED
@@ -0,0 +1,86 @@
1
+ <?php
2
+
3
+ class Riskified_Full_Model_Cron
4
+ {
5
+ /**
6
+ * Maximum number of times we'll attempt to resubmit an order
7
+ */
8
+ const MAX_ATTEMPTS = 7;
9
+
10
+ /**
11
+ * The base for calculating the exponential backoff
12
+ */
13
+ const INTERVAL_BASE = 3;
14
+
15
+ /**
16
+ * The maximum number of orders to try per cron run
17
+ */
18
+ const BATCH_SIZE = 10;
19
+
20
+ /**
21
+ * Attempt to retry order submissions
22
+ */
23
+ public function retrySubmissions()
24
+ {
25
+ Mage::helper('full/log')->log("Retrying failed order submissions");
26
+
27
+ // Load all retries that haven't reached the max number of attempts and are past due to run.
28
+ // Past due is calculated as self::INTERVAL_BASE ^ attempts. This results in an exponential backoff
29
+ // if this submission continues to fail.
30
+ $retries = Mage::getModel('full/retry')->getCollection()
31
+ //->addExpressionFieldToSelect(
32
+ // 'minutes_late',
33
+ // "TIMESTAMPDIFF(MINUTE, `updated_at`, '" . Mage::getSingleton('core/date')->gmtDate() . "') - POW(" . self::INTERVAL_BASE . ", attempts)",
34
+ // array()
35
+ //)
36
+ ->addfieldtofilter('attempts',
37
+ array(
38
+ array('lt' => self::MAX_ATTEMPTS)
39
+ )
40
+ );
41
+
42
+ $select = $retries->getSelect();
43
+ $adapter = $select->getAdapter();
44
+ $select
45
+ ->where(sprintf(
46
+ "TIMESTAMPDIFF(MINUTE, `updated_at`, %s) - POW(%s, attempts) > 0"
47
+ , $adapter->quote(Mage::getSingleton('core/date')->gmtDate())
48
+ , $adapter->quote(self::INTERVAL_BASE)
49
+ ))
50
+ ->order('updated_at ASC')
51
+ ->limit(self::BATCH_SIZE)
52
+ ;
53
+
54
+ foreach($retries as $retry) {
55
+ Mage::helper('full/log')->log("Retrying order " . $retry->getOrderId());
56
+
57
+ $order = Mage::getModel('sales/order')->load($retry->getOrderId());
58
+
59
+ if (!$order) {
60
+ Mage::helper('full/log')->log("Order doesn't exist, skipping");
61
+
62
+ $retry->delete();
63
+ continue;
64
+ }
65
+
66
+ try {
67
+ Mage::helper('full/order')->postOrder($order, $retry->getAction());
68
+
69
+ // There is no need to delete the retry here. postOrder() dispatches a success event which
70
+ // results in all retries for this order getting deleted.
71
+ }
72
+ // Log the exception, store the backtrace and increment the counter
73
+ catch (Exception $e) {
74
+ Mage::helper('full/log')->logException($e);
75
+
76
+ $retry
77
+ ->setLastError("Exception Message: " . $e->getMessage() . "\n\n" . Varien_Debug::backtrace(true, false))
78
+ ->setAttempts($retry->getAttempts() + 1)
79
+ ->setUpdatedAt(Mage::getSingleton('core/date')->gmtDate())
80
+ ->save();
81
+ }
82
+ }
83
+
84
+ Mage::helper('full/log')->log("Done retrying failed order submissions");
85
+ }
86
+ }
app/code/community/Riskified/Full/Model/Observer.php ADDED
@@ -0,0 +1,340 @@
1
+ <?php
2
+
3
+ class Riskified_Full_Model_Observer {
4
+
5
+ public function saveOrderBefore($evt) {
6
+ Mage::helper('full/log')->log("saveOrderBefore");
7
+
8
+ $payment = $evt->getPayment();
9
+ $cc_bin = substr($payment->getCcNumber(),0,6);
10
+
11
+ if ($cc_bin) {
12
+ $payment->setAdditionalInformation('riskified_cc_bin', $cc_bin);
13
+ }
14
+ }
15
+
16
+ public function salesOrderPaymentPlaceEnd($evt) {
17
+ Mage::helper('full/log')->log("salesOrderPaymentPlaceEnd");
18
+
19
+ //$order = $evt->getPayment()->getOrder();
20
+
21
+ //try {
22
+ // Mage::helper('full/order')->postOrder($order, Riskified_Full_Helper_Order::ACTION_CREATE);
23
+ //} catch (Exception $e) {
24
+ // There is no need to do anything here. The exception has already been handled and a retry scheduled.
25
+ // We catch this exception so that the order is still saved in Magento.
26
+ //}
27
+ }
28
+
29
+ public function salesOrderPaymentVoid($evt) {
30
+ Mage::helper('full/log')->log("salesOrderPaymentVoid");
31
+ //$order = $evt->getPayment()->getOrder();
32
+ //Mage::helper('full/order')->postOrder($order,'cancel');
33
+ }
34
+
35
+ public function salesOrderPaymentRefund($evt) {
36
+ Mage::helper('full/log')->log("salesOrderPaymentRefund");
37
+ //$order = $evt->getPayment()->getOrder();
38
+ //Mage::helper('full/order')->postOrder($order,'cancel');
39
+ }
40
+
41
+ public function salesOrderPaymentCancel($evt) {
42
+ Mage::helper('full/log')->log("salesOrderPaymentCancel");
43
+ //$order = $evt->getPayment()->getOrder();
44
+ //Mage::helper('full/order')->postOrder($order,'cancel');
45
+ }
46
+
47
+ public function salesOrderPlaceBefore($evt) {
48
+ Mage::helper('full/log')->log("salesOrderPlaceBefore");
49
+ }
50
+
51
+ public function salesOrderPlaceAfter($evt) {
52
+ Mage::helper('full/log')->log("salesOrderPlaceAfter");
53
+ }
54
+
55
+ public function salesOrderSaveBefore($evt) {
56
+ Mage::helper('full/log')->log("salesOrderSaveBefore");
57
+ }
58
+
59
+ public function salesOrderSaveAfter($evt) {
60
+ Mage::helper('full/log')->log("salesOrderSaveAfter");
61
+
62
+ $order = $evt->getOrder();
63
+ if(!$order) {
64
+ return;
65
+ }
66
+
67
+ $newState = $order->getState();
68
+
69
+ if ($order->dataHasChangedFor('state')) {
70
+ Mage::helper('full/log')->log("Order: " . $order->getId() . " state changed from: " . $order->getOrigData('state') . " to: " . $newState);
71
+
72
+ // if we posted we should not re post
73
+ if($order->riskifiedInSave) {
74
+ Mage::helper('full/log')->log("Order : " . $order->getId() . " is already riskifiedInSave");
75
+ return;
76
+ }
77
+ // Flag order to indicate that we are posting
78
+ $order->riskifiedInSave = true;
79
+
80
+ try {
81
+ Mage::helper('full/order')->postOrder($order, Riskified_Full_Helper_Order::ACTION_UPDATE);
82
+ } catch (Exception $e) {
83
+ // There is no need to do anything here. The exception has already been handled and a retry scheduled.
84
+ // We catch this exception so that the order is still saved in Magento.
85
+ }
86
+ } else {
87
+ Mage::helper('full/log')->log("Order: '" . $order->getId() . "' state didn't change on save - not posting again: " . $newState);
88
+ }
89
+ }
90
+
91
+ public function salesOrderCancel($evt) {
92
+ Mage::helper('full/log')->log("salesOrderCancel");
93
+
94
+ $order = $evt->getOrder();
95
+
96
+ // TODO not sure if this is still required - saveAfter should be enough
97
+
98
+ try {
99
+ Mage::helper('full/order')->postOrder($order, Riskified_Full_Helper_Order::ACTION_CANCEL);
100
+ } catch (Exception $e) {
101
+ // There is no need to do anything here. The exception has already been handled and a retry scheduled.
102
+ // We catch this exception so that the order is still saved in Magento.
103
+ }
104
+ }
105
+
106
+ public function postOrderIds($order_ids) {
107
+ foreach ($order_ids as $order_id) {
108
+ $order = Mage::getModel('sales/order')->load($order_id);
109
+
110
+ try {
111
+ Mage::helper('full/order')->postOrder($order, Riskified_Full_Helper_Order::ACTION_SUBMIT);
112
+ } catch (Exception $e) {
113
+ // There is no need to do anything here. The exception has already been handled and a retry scheduled.
114
+ // We catch this exception so that the order is still saved in Magento.
115
+ }
116
+ }
117
+ }
118
+
119
+ public function addMassAction($observer) {
120
+ $block = $observer->getEvent()->getBlock();
121
+ if(get_class($block) =='Mage_Adminhtml_Block_Widget_Grid_Massaction'
122
+ && $block->getRequest()->getControllerName() == 'sales_order')
123
+ {
124
+ $block->addItem('full', array(
125
+ 'label' => 'Submit to Riskified',
126
+ 'url' => Mage::app()->getStore()->getUrl('full/adminhtml_full/riskimass'),
127
+ ));
128
+ }
129
+ }
130
+
131
+ public function blockHtmlBefore($observer) {
132
+ $block = $observer->getEvent()->getBlock();
133
+ if ($block->getType() == 'adminhtml/sales_order_view') {
134
+ $message = Mage::helper('sales')->__('Are you sure you want to submit this order to Riskified?');
135
+ $url = $block->getUrl('full/adminhtml_full/riski');
136
+ $block->addButton('riski_submit', array(
137
+ 'label' => Mage::helper('sales')->__('Submit to Riskified'),
138
+ 'onclick' => "deleteConfirm('$message', '$url')",
139
+ ));
140
+ }
141
+ }
142
+
143
+ /**
144
+ * Update the order state and status when it's been updated
145
+ *
146
+ * @param Varien_Event_Observer $observer
147
+ */
148
+ public function updateOrderState(Varien_Event_Observer $observer)
149
+ {
150
+ $riskifiedOrderStatusHelper = Mage::helper('full/order_status');
151
+ $riskifiedInvoiceHelper = Mage::helper('full/order_invoice');
152
+ $order = $observer->getOrder();
153
+ $status = (string) $observer->getStatus();
154
+ $description = (string) $observer->getDescription();
155
+ $newState = $newStatus = null;
156
+ $currentState = $order->getState();
157
+ $currentStatus = $order->getStatus();
158
+
159
+ Mage::helper('full/log')->log("Checking if should update order '" . $order->getId() . "' from state: '$currentState' and status: '$currentStatus'");
160
+
161
+ switch ($status) {
162
+ case 'approved':
163
+ if ($currentState == Mage_Sales_Model_Order::STATE_HOLDED
164
+ && ($currentStatus == $riskifiedOrderStatusHelper->getOnHoldStatusCode()
165
+ || $currentStatus == $riskifiedOrderStatusHelper->getTransportErrorStatusCode())) {
166
+ $newState = Mage_Sales_Model_Order::STATE_PROCESSING;
167
+ $newStatus = TRUE;
168
+ }
169
+
170
+ break;
171
+ case 'declined':
172
+ if ($currentState == Mage_Sales_Model_Order::STATE_HOLDED
173
+ && ($currentStatus == $riskifiedOrderStatusHelper->getOnHoldStatusCode()
174
+ || $currentStatus == $riskifiedOrderStatusHelper->getTransportErrorStatusCode())) {
175
+ $newState = Mage_Sales_Model_Order::STATE_CANCELED;
176
+ $newStatus = Mage_Sales_Model_Order::STATUS_FRAUD;
177
+ }
178
+
179
+ break;
180
+ case 'submitted':
181
+ if ($currentState == Mage_Sales_Model_Order::STATE_PROCESSING
182
+ || ($currentState == Mage_Sales_Model_Order::STATE_HOLDED
183
+ && $currentStatus == $riskifiedOrderStatusHelper->getTransportErrorStatusCode())) {
184
+ $newState = Mage_Sales_Model_Order::STATE_HOLDED;
185
+ $newStatus = $riskifiedOrderStatusHelper->getOnHoldStatusCode();
186
+ }
187
+
188
+ break;
189
+ case 'error':
190
+ if ($currentState == Mage_Sales_Model_Order::STATE_PROCESSING
191
+ && $riskifiedInvoiceHelper->isAutoInvoiceEnabled()) {
192
+ $newState = Mage_Sales_Model_Order::STATE_HOLDED;
193
+ $newStatus = $riskifiedOrderStatusHelper->getTransportErrorStatusCode();
194
+ }
195
+ }
196
+
197
+ $changed = false;
198
+
199
+ // if newState exists and new state/status are different from current and config is set to status-sync
200
+ if ($newState
201
+ && ($newState != $currentState || $newStatus != $currentStatus)
202
+ && Mage::helper('full')->getConfigStatusControlActive()) {
203
+ $order->setState($newState, $newStatus, $description);
204
+ Mage::helper('full/log')->log("Updating order '" . $order->getId() . "' to: state: '$newState', status: '$newStatus', description: '$description'");
205
+ $changed=true;
206
+ } elseif ($description) {
207
+ Mage::helper('full/log')->log("Updating order " . $order->getId() . " history comment to: " . $description);
208
+ $order->addStatusHistoryComment($description);
209
+ $changed=true;
210
+ }
211
+
212
+ if ($changed) {
213
+ try {
214
+ $order->save();
215
+ } catch (Exception $e) {
216
+ Mage::helper('full/log')->log("Error saving order: " . $e->getMessage());
217
+ return;
218
+ }
219
+ }
220
+ }
221
+
222
+ /**
223
+ * Create an invoice when the order is approved
224
+ *
225
+ * @param Varien_Event_Observer $observer
226
+ */
227
+ public function autoInvoice(Varien_Event_Observer $observer)
228
+ {
229
+ $riskifiedInvoiceHelper = Mage::helper('full/order_invoice');
230
+
231
+ if (!$riskifiedInvoiceHelper->isAutoInvoiceEnabled()) {
232
+ return;
233
+ }
234
+
235
+ $order = $observer->getOrder();
236
+
237
+ // Sanity check
238
+ if (!$order || !$order->getId()) {
239
+ return;
240
+ }
241
+
242
+ Mage::helper('full/log')->log("Auto-invoicing order " . $order->getId());
243
+
244
+ if (!$order->canInvoice()) {
245
+ Mage::helper('full/log')->log("Order cannot be invoiced");
246
+ return;
247
+ }
248
+
249
+ $invoice = Mage::getModel('sales/service_order', $order)->prepareInvoice();
250
+
251
+ if (!$invoice->getTotalQty()) {
252
+ Mage::helper('full/log')->log("Cannot create an invoice without products");
253
+ return;
254
+ }
255
+
256
+ try {
257
+ $invoice
258
+ ->setRequestedCaptureCase($riskifiedInvoiceHelper->getCaptureCase())
259
+ ->addComment(
260
+ 'Invoice automatically created by Riskified when order was approved',
261
+ false,
262
+ false
263
+ )
264
+ ->register();
265
+ } catch (Exception $e) {
266
+ Mage::helper('full/log')->log("Error creating invoice: " . $e->getMessage());
267
+ return;
268
+ }
269
+
270
+ try {
271
+ Mage::getModel('core/resource_transaction')
272
+ ->addObject($invoice)
273
+ ->addObject($order)
274
+ ->save();
275
+ } catch (Exception $e) {
276
+ Mage::helper('full/log')->log("Error creating transaction: " . $e->getMessage());
277
+ return;
278
+ }
279
+
280
+ Mage::helper('full/log')->log("Transaction saved");
281
+ }
282
+
283
+ /**
284
+ * Clear all submission retries for an order that have the same action.
285
+ * This event observer is only called after a successful submission.
286
+ *
287
+ * @param Varien_Event_Observer $observer
288
+ */
289
+ public function clearRetriesForOrder(Varien_Event_Observer $observer)
290
+ {
291
+ $order = $observer->getOrder();
292
+
293
+ // Sanity check
294
+ if (!$order || !$order->getId()) {
295
+ return;
296
+ }
297
+
298
+ $retries = Mage::getModel('full/retry')->getCollection()
299
+ ->addfieldtofilter('order_id', $order->getId())
300
+ ->addFieldToFilter('action', $observer->getAction());
301
+
302
+ foreach($retries as $retry) {
303
+ $retry->delete();
304
+ }
305
+ }
306
+
307
+ /**
308
+ * Process the response from a successful post to Riskified.
309
+ *
310
+ * @param Varien_Event_Observer $observer
311
+ */
312
+ public function processSuccessfulPost(Varien_Event_Observer $observer)
313
+ {
314
+ /* @var Mage_Sales_Model_Order $order */
315
+ $order = $observer->getOrder();
316
+
317
+ /* @var stdClass $response */
318
+ $response = $observer->getResponse();
319
+
320
+ if (isset($response->order)) {
321
+ $orderId = $response->order->id;
322
+ $status = $response->order->status;
323
+ $description = $response->order->description;
324
+
325
+ if (!$description) {
326
+ $description = "Riskified Status: $status";
327
+ }
328
+
329
+ if ($orderId && $status) {
330
+ Mage::helper('full/order')->updateOrder($order, $status, $description);
331
+ }
332
+
333
+ $origId = $order->getId();
334
+
335
+ Mage::getSingleton('adminhtml/session')->addSuccess(Mage::helper('adminhtml')->__("Order #$origId was successfully updated at Riskified"));
336
+ } else {
337
+ Mage::getSingleton('adminhtml/session')->addError(Mage::helper('adminhtml')->__("Malformed response from Riskified"));
338
+ }
339
+ }
340
+ }
app/code/community/Riskified/Full/Model/Resource/Retry.php ADDED
@@ -0,0 +1,9 @@
1
+ <?php
2
+
3
+ class Riskified_Full_Model_Resource_Retry extends Mage_Core_Model_Resource_Db_Abstract
4
+ {
5
+ protected function _construct()
6
+ {
7
+ $this->_init('full/retry', 'retry_id');
8
+ }
9
+ }
app/code/community/Riskified/Full/Model/Resource/Retry/Collection.php ADDED
@@ -0,0 +1,9 @@
1
+ <?php
2
+
3
+ class Riskified_Full_Model_Resource_Retry_Collection extends Mage_Core_Model_Resource_Db_Collection_Abstract
4
+ {
5
+ public function _construct()
6
+ {
7
+ $this->_init('full/retry');
8
+ }
9
+ }
app/code/community/Riskified/Full/Model/Retry.php ADDED
@@ -0,0 +1,9 @@
1
+ <?php
2
+
3
+ class Riskified_Full_Model_Retry extends Mage_Core_Model_Abstract
4
+ {
5
+ protected function _construct()
6
+ {
7
+ $this->_init('full/retry');
8
+ }
9
+ }
app/code/community/Riskified/Full/Model/System/Config/Source/CaptureCase.php ADDED
@@ -0,0 +1,15 @@
1
+ <?php
2
+
3
+ class Riskified_Full_Model_System_Config_Source_CaptureCase
4
+ {
5
+ /**
6
+ * @return array
7
+ */
8
+ public function toOptionArray()
9
+ {
10
+ return array(
11
+ array('value' => Mage_Sales_Model_Order_Invoice::CAPTURE_ONLINE, 'label' => Mage::helper('full')->__('Capture Online')),
12
+ array('value' => Mage_Sales_Model_Order_Invoice::CAPTURE_OFFLINE, 'label' => Mage::helper('full')->__('Capture Offline'))
13
+ );
14
+ }
15
+ }
app/code/community/Riskified/Full/Model/System/Config/Source/Env.php ADDED
@@ -0,0 +1,13 @@
1
+ <?php
2
+
3
+ class Riskified_Full_Model_System_Config_Source_Env
4
+ {
5
+ public function toOptionArray()
6
+ {
7
+ return array(
8
+ array('value' => 'PROD', 'label' => Mage::helper('full')->__('Production')),
9
+ array('value' => 'SANDBOX', 'label' => Mage::helper('full')->__('Sandbox')),
10
+ array('value' => 'DEV', 'label' => Mage::helper('full')->__('Dev'))
11
+ );
12
+ }
13
+ }
app/code/community/Riskified/Full/Test/Config/General.php ADDED
@@ -0,0 +1,59 @@
1
+ <?php
2
+
3
+ class Riskified_Full_Test_Config_General extends EcomDev_PHPUnit_Test_Case_Config
4
+ {
5
+
6
+ /**
7
+ * Make sure all of our rewrites are in effect
8
+ *
9
+ * @test
10
+ */
11
+ public function testRewrites()
12
+ {
13
+ $this->assertModelAlias('paygate/authorizenet', 'Riskified_Full_Model_Authorizenet');
14
+ }
15
+
16
+ /**
17
+ * Make sure layout files are defined
18
+ *
19
+ * @test
20
+ */
21
+ public function testLayouts()
22
+ {
23
+ $this->assertLayoutFileDefined(
24
+ 'frontend', 'full.xml'
25
+ );
26
+
27
+ $this->assertLayoutFileDefined(
28
+ 'adminhtml', 'full.xml'
29
+ );
30
+ }
31
+
32
+ /**
33
+ * Make sure event observers related to status are properly defined
34
+ *
35
+ * @test
36
+ */
37
+ public function testStatusSyncEventObservers()
38
+ {
39
+ $this->assertEventObserverDefined(
40
+ 'global', 'riskified_full_order_update', 'full/observer', 'updateOrderState'
41
+ );
42
+ }
43
+
44
+ /**
45
+ * Make sure event observers related to auto-invoicing are properly defined
46
+ *
47
+ * @test
48
+ */
49
+ public function testAutoInvoiceEventObservers()
50
+ {
51
+ $this->assertEventObserverDefined(
52
+ 'global', 'riskified_full_order_update_approved', 'full/observer', 'autoInvoice'
53
+ );
54
+
55
+ $this->assertEventObserverDefined(
56
+ 'global', 'riskified_full_order_update_captured', 'full/observer', 'autoInvoice'
57
+ );
58
+ }
59
+ }
app/code/community/Riskified/Full/Test/Helper/General.php ADDED
@@ -0,0 +1,25 @@
1
+ <?php
2
+
3
+ class Riskified_Full_Test_Helper_General extends EcomDev_PHPUnit_Test_Case
4
+ {
5
+ /**
6
+ * An example test that configures the extension before making any assertions
7
+ *
8
+ * @test
9
+ * @loadFixture extensionConfigEnabled
10
+ */
11
+ public function testConfigurationValuesLoaded()
12
+ {
13
+ $helper = Mage::helper('full');
14
+
15
+ $this->assertEquals(
16
+ $helper->getConfigStatusControlActive(),
17
+ 1
18
+ );
19
+
20
+ $this->assertEquals(
21
+ $helper->getConfigEnv(),
22
+ 'Riskified\Common\Env::DEV'
23
+ );
24
+ }
25
+ }
app/code/community/Riskified/Full/Test/Helper/General/fixtures/extensionConfigEnabled.yaml ADDED
@@ -0,0 +1,7 @@
1
+ config:
2
+ default/fullsection/full/order_status_sync: 1
3
+ default/fullsection/full/env: DEV
4
+ default/fullsection/full/domain: dev.riskified.com
5
+ default/fullsection/full/key: 123456789
6
+ default/fullsection/full/auto_invoice_enabled: 1
7
+ default/fullsection/full/auto_invoice_capture_case: offline
app/code/community/Riskified/Full/Test/Model/Environments.php ADDED
@@ -0,0 +1,22 @@
1
+ <?php
2
+
3
+ require_once(Mage::getBaseDir('lib') . DIRECTORY_SEPARATOR . 'riskified_php_sdk' . DIRECTORY_SEPARATOR . 'src' . DIRECTORY_SEPARATOR . 'Riskified' . DIRECTORY_SEPARATOR . 'autoloader.php');
4
+
5
+ class Riskified_Full_Test_Model_Environments extends EcomDev_PHPUnit_Test_Case
6
+ {
7
+ /**
8
+ * Test to make sure our environment options exist
9
+ *
10
+ * @test
11
+ */
12
+ public function testEnvironmentsExist()
13
+ {
14
+ $model = Mage::getModel('full/env');
15
+ $environments = $model->toOptionArray();
16
+
17
+ $this->assertEquals(
18
+ count($environments),
19
+ 3
20
+ );
21
+ }
22
+ }
app/code/community/Riskified/Full/controllers/Adminhtml/FullController.php ADDED
@@ -0,0 +1,22 @@
1
+ <?php
2
+
3
+ class Riskified_Full_Adminhtml_FullController extends Mage_Adminhtml_Controller_Action
4
+ {
5
+
6
+ public function riskiAction()
7
+ {
8
+ $id = $this->getRequest()->getParam('order_id');
9
+ $call = Mage::getModel('full/observer');
10
+ $call->postOrderIds(array($id));
11
+
12
+ Mage::app()->getResponse()->setRedirect(Mage::helper('adminhtml')->getUrl("adminhtml/sales_order/index", array('id'=>$id)));
13
+ }
14
+
15
+ public function riskimassAction()
16
+ {
17
+ $order_ids = $this->getRequest()->getParam('order_ids');
18
+ $call = Mage::getModel('full/observer');
19
+ $call->postOrderIds($order_ids);
20
+ Mage::app()->getResponse()->setRedirect(Mage::helper('adminhtml')->getUrl("adminhtml/sales_order/index"));
21
+ }
22
+ }
app/code/community/Riskified/Full/controllers/ResponseController.php ADDED
@@ -0,0 +1,50 @@
1
+ <?php
2
+
3
+ class Riskified_Full_ResponseController extends Mage_Core_Controller_Front_Action
4
+ {
5
+ public function getresponseAction()
6
+ {
7
+ $request = $this->getRequest();
8
+ $response = $this->getResponse();
9
+ $helper = Mage::helper('full/order');
10
+ $logger = Mage::helper('full/log');
11
+ $statusCode = 200;
12
+ $id = null;
13
+ $msg = null;
14
+
15
+ try {
16
+ $notification = $helper->parseRequest($request);
17
+ $id = $notification->id;
18
+
19
+ Mage::helper('full/log')->log("Notification received: ", serialize($notification));
20
+
21
+ $order = Mage::getModel('sales/order')->load($id);
22
+ if (!$order || !$order->getId()) {
23
+ $logger->log("ERROR: Unable to load order (" . $id . ")");
24
+ $statusCode = 400;
25
+ $msg = 'Could not find order to update.';
26
+ } else {
27
+ $helper->updateOrder($order, $notification->status, $notification->description);
28
+ $statusCode = 200;
29
+ $msg = 'Order-Update event triggered.';
30
+ }
31
+ } catch (Riskified\DecisionNotification\Exception\AuthorizationException $e) {
32
+ $logger->logException($e);
33
+ $statusCode = 401;
34
+ $msg = 'Authentication Failed.';
35
+ } catch (\Riskified\DecisionNotification\Exception\BadPostJsonException $e) {
36
+ $logger->logException($e);
37
+ $statusCode = 400;
38
+ $msg = "JSON Parsing Error.";
39
+ } catch (Exception $e) {
40
+ $logger->log("ERROR: while processing notification for order $id");
41
+ $statusCode = 500;
42
+ $msg = "Internal Error";
43
+ }
44
+
45
+ $response->setHttpResponseCode($statusCode);
46
+ $response->setHeader('Content-Type', 'application/json');
47
+ $response->setBody('{ "order" : { "id" : "' . $id . '", "description" : "' . $msg .'" } }');
48
+
49
+ }
50
+ }
app/code/community/Riskified/Full/etc/config.xml ADDED
@@ -0,0 +1,293 @@
1
+ <?xml version="1.0"?>
2
+ <config>
3
+ <modules>
4
+ <Riskified_Full>
5
+ <version>1.0.5.4</version>
6
+ </Riskified_Full>
7
+ </modules>
8
+
9
+ <global>
10
+ <models>
11
+ <paygate>
12
+ <rewrite>
13
+ <authorizenet>Riskified_Full_Model_Authorizenet</authorizenet>
14
+ </rewrite>
15
+ </paygate>
16
+ <full>
17
+ <class>Riskified_Full_Model</class>
18
+ <resourceModel>riskified_full_resource</resourceModel>
19
+ </full>
20
+ <riskified_full_resource>
21
+ <class>Riskified_Full_Model_Resource</class>
22
+ <entities>
23
+ <retry>
24
+ <table>riskified_full_retry</table>
25
+ </retry>
26
+ </entities>
27
+ </riskified_full_resource>
28
+ </models>
29
+ <resources>
30
+ <riskified_full_setup>
31
+ <setup>
32
+ <module>Riskified_Full</module>
33
+ </setup>
34
+ </riskified_full_setup>
35
+ </resources>
36
+ <helpers>
37
+ <full>
38
+ <class>Riskified_Full_Helper</class>
39
+ </full>
40
+ </helpers>
41
+ <events>
42
+ <sales_order_payment_place_start>
43
+ <observers>
44
+ <riskified_full>
45
+ <type>singleton</type>
46
+ <class>full/observer</class>
47
+ <method>saveOrderBefore</method>
48
+ </riskified_full>
49
+ </observers>
50
+ </sales_order_payment_place_start>
51
+ <sales_order_payment_place_end>
52
+ <observers>
53
+ <riskified_full>
54
+ <type>singleton</type>
55
+ <class>full/observer</class>
56
+ <method>salesOrderPaymentPlaceEnd</method>
57
+ </riskified_full>
58
+ </observers>
59
+ </sales_order_payment_place_end>
60
+ <sales_order_payment_void>
61
+ <observers>
62
+ <riskified_full>
63
+ <type>singleton</type>
64
+ <class>full/observer</class>
65
+ <method>salesOrderPaymentVoid</method>
66
+ </riskified_full>
67
+ </observers>
68
+ </sales_order_payment_void>
69
+ <sales_order_payment_refund>
70
+ <observers>
71
+ <riskified_full>
72
+ <type>singleton</type>
73
+ <class>full/observer</class>
74
+ <method>salesOrderPaymentRefund</method>
75
+ </riskified_full>
76
+ </observers>
77
+ </sales_order_payment_refund>
78
+ <sales_order_payment_cancel>
79
+ <observers>
80
+ <riskified_full>
81
+ <type>singleton</type>
82
+ <class>full/observer</class>
83
+ <method>salesOrderPaymentCancel</method>
84
+ </riskified_full>
85
+ </observers>
86
+ </sales_order_payment_cancel>
87
+ <sales_order_place_before>
88
+ <observers>
89
+ <riskified_full>
90
+ <type>singleton</type>
91
+ <class>full/observer</class>
92
+ <method>salesOrderPlaceBefore</method>
93
+ </riskified_full>
94
+ </observers>
95
+ </sales_order_place_before>
96
+ <sales_order_place_after>
97
+ <observers>
98
+ <riskified_full>
99
+ <type>singleton</type>
100
+ <class>full/observer</class>
101
+ <method>salesOrderPlaceAfter</method>
102
+ </riskified_full>
103
+ </observers>
104
+ </sales_order_place_after>
105
+ <sales_order_save_before>
106
+ <observers>
107
+ <riskified_full>
108
+ <type>singleton</type>
109
+ <class>full/observer</class>
110
+ <method>salesOrderSaveBefore</method>
111
+ </riskified_full>
112
+ </observers>
113
+ </sales_order_save_before>
114
+ <sales_order_save_after>
115
+ <observers>
116
+ <riskified_full>
117
+ <type>singleton</type>
118
+ <class>full/observer</class>
119
+ <method>salesOrderSaveAfter</method>
120
+ </riskified_full>
121
+ </observers>
122
+ </sales_order_save_after>
123
+ <order_cancel_after>
124
+ <observers>
125
+ <riskified_full>
126
+ <type>singleton</type>
127
+ <class>full/observer</class>
128
+ <method>salesOrderCancel</method>
129
+ </riskified_full>
130
+ </observers>
131
+ </order_cancel_after>
132
+ <adminhtml_widget_container_html_before>
133
+ <observers>
134
+ <module>
135
+ <type>singleton</type>
136
+ <class>full/observer</class>
137
+ <method>blockHtmlBefore</method>
138
+ </module>
139
+ </observers>
140
+ </adminhtml_widget_container_html_before>
141
+ <riskified_full_order_update>
142
+ <observers>
143
+ <riskified_full_handle_order_update>
144
+ <class>full/observer</class>
145
+ <method>updateOrderState</method>
146
+ </riskified_full_handle_order_update>
147
+ </observers>
148
+ </riskified_full_order_update>
149
+ <riskified_full_order_update_approved>
150
+ <observers>
151
+ <riskified_full_handle_order_update_approved>
152
+ <class>full/observer</class>
153
+ <method>autoInvoice</method>
154
+ </riskified_full_handle_order_update_approved>
155
+ </observers>
156
+ </riskified_full_order_update_approved>
157
+ <riskified_full_order_update_captured>
158
+ <observers>
159
+ <riskified_full_handle_order_update_captured>
160
+ <class>full/observer</class>
161
+ <method>autoInvoice</method>
162
+ </riskified_full_handle_order_update_captured>
163
+ </observers>
164
+ </riskified_full_order_update_captured>
165
+ <riskified_full_post_order_success>
166
+ <observers>
167
+ <riskified_full_clear_retries>
168
+ <class>full/observer</class>
169
+ <method>clearRetriesForOrder</method>
170
+ </riskified_full_clear_retries>
171
+ <riskified_full_process_successful_post>
172
+ <class>full/observer</class>
173
+ <method>processSuccessfulPost</method>
174
+ </riskified_full_process_successful_post>
175
+ </observers>
176
+ </riskified_full_post_order_success>
177
+ </events>
178
+ </global>
179
+
180
+ <frontend>
181
+ <routers>
182
+ <full>
183
+ <use>standard</use>
184
+ <args>
185
+ <module>Riskified_Full</module>
186
+ <frontName>full</frontName>
187
+ </args>
188
+ </full>
189
+ </routers>
190
+ <layout>
191
+ <updates>
192
+ <full>
193
+ <file>full.xml</file>
194
+ </full>
195
+ </updates>
196
+ </layout>
197
+ </frontend>
198
+
199
+ <admin>
200
+ <routers>
201
+ <full>
202
+ <use>admin</use>
203
+ <args>
204
+ <module>Riskified_Full</module>
205
+ <frontName>full</frontName>
206
+ </args>
207
+ </full>
208
+ </routers>
209
+ </admin>
210
+
211
+ <adminhtml>
212
+ <acl>
213
+ <resources>
214
+ <all>
215
+ <title>Allow Everything</title>
216
+ </all>
217
+ <admin>
218
+ <children>
219
+ <Riskified_Full>
220
+ <title>Full Module</title>
221
+ <sort_order>10</sort_order>
222
+ </Riskified_Full>
223
+ <system>
224
+ <children>
225
+ <config>
226
+ <children>
227
+ <fullsection translate="title"
228
+ module="full"> <!-- This is name of the section created by us -->
229
+ <title>Riskified</title>
230
+ <!-- Title as shown in User->Roles->Permissions Window -->
231
+ <sort_order>99</sort_order>
232
+ </fullsection>
233
+ </children>
234
+ </config>
235
+ </children>
236
+ </system>
237
+ </children>
238
+ </admin>
239
+ </resources>
240
+ </acl>
241
+ <layout>
242
+ <updates>
243
+ <full>
244
+ <file>full.xml</file>
245
+ </full>
246
+ </updates>
247
+ </layout>
248
+ <events>
249
+ <core_block_abstract_prepare_layout_before>
250
+ <observers>
251
+ <before_grid_prep>
252
+ <type>singleton</type>
253
+ <class>Riskified_Full_Model_Observer</class>
254
+ <method>addMassAction</method>
255
+ </before_grid_prep>
256
+ </observers>
257
+ </core_block_abstract_prepare_layout_before>
258
+ </events>
259
+ </adminhtml>
260
+
261
+ <crontab>
262
+ <jobs>
263
+ <riskified_full_retry_submission>
264
+ <schedule>
265
+ <cron_expr>*/5 * * * *</cron_expr>
266
+ </schedule>
267
+ <run>
268
+ <model>full/cron::retrySubmissions</model>
269
+ </run>
270
+ </riskified_full_retry_submission>
271
+ </jobs>
272
+ </crontab>
273
+
274
+ <phpunit>
275
+ <suite>
276
+ <modules>
277
+ <Riskified_Full />
278
+ </modules>
279
+ </suite>
280
+ </phpunit>
281
+
282
+ <default>
283
+ <fullsection>
284
+ <full>
285
+ <order_status_sync>0</order_status_sync>
286
+ <env>PROD</env>
287
+ <beaconurl>beacon.riskified.com</beaconurl>
288
+ <auto_invoice_enabled>0</auto_invoice_enabled>
289
+ <auto_invoice_capture_case>online</auto_invoice_capture_case>
290
+ </full>
291
+ </fullsection>
292
+ </default>
293
+ </config>
app/code/community/Riskified/Full/etc/system.xml ADDED
@@ -0,0 +1,112 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <config>
3
+ <tabs>
4
+ <newtab translate="label" module="full">
5
+ <label>Riskified</label>
6
+ <sort_order>999</sort_order>
7
+ </newtab>
8
+ </tabs>
9
+
10
+ <sections>
11
+ <fullsection translate="label" module="full">
12
+ <class>separator-top</class>
13
+ <label>Settings</label>
14
+ <tab>newtab</tab>
15
+ <sort_order>130</sort_order>
16
+ <show_in_default>1</show_in_default>
17
+ <show_in_website>1</show_in_website>
18
+ <show_in_store>1</show_in_store>
19
+ <groups>
20
+ <full translate="label">
21
+ <label>API settings</label>
22
+ <sort_order>10</sort_order>
23
+ <show_in_default>1</show_in_default>
24
+ <show_in_website>0</show_in_website>
25
+ <show_in_store>0</show_in_store>
26
+ <fields>
27
+ <order_status_sync translate="label comment">
28
+ <label>Order Status Sync</label>
29
+ <comment><![CDATA[ Enable/Disable automatic changes to Order status by Riskified's review process.
30
+ <br>Requires the <i>Order notification endpoint</i> to be configured correctly in your Riskified Settings page.
31
+ <br>Using the following mapping:
32
+ <br>'submit' => 'on hold' <br>'approve' => 'processing'<br>'decline' => 'canceled'
33
+ <br><b>Important:</b> Might affect other extensions that are dependent on an Order's status.
34
+ ]]></comment>
35
+ <frontend_type>select</frontend_type>
36
+ <sort_order>1</sort_order>
37
+ <show_in_default>1</show_in_default>
38
+ <show_in_website>1</show_in_website>
39
+ <show_in_store>1</show_in_store>
40
+ <source_model>adminhtml/system_config_source_enabledisable</source_model>
41
+ </order_status_sync>
42
+ <env translate="label comment">
43
+ <label>Riskified environment</label>
44
+ <frontend_type>select</frontend_type>
45
+ <source_model>full/system_config_source_env</source_model>
46
+ <sort_order>2</sort_order>
47
+ <show_in_default>1</show_in_default>
48
+ <show_in_website>1</show_in_website>
49
+ <show_in_store>1</show_in_store>
50
+ <comment><![CDATA[Select Riskified's environment.<br> You can use sandbox for testing.
51
+ <br>If you don't have a sandbox account please contact support@riskified.com ]]></comment>
52
+ </env>
53
+ <!--<activationstatus>
54
+ <comment></comment>
55
+ <frontend_type>text</frontend_type>
56
+ <sort_order>4</sort_order>
57
+ <class>riskified_activationstatus</class>
58
+ <show_in_default>1</show_in_default>
59
+ <show_in_website>1</show_in_website>
60
+ <show_in_store>1</show_in_store>
61
+ </activationstatus>-->
62
+ <domain translate="label comment">
63
+ <label>Shop Domain</label>
64
+ <frontend_type>Text</frontend_type>
65
+ <sort_order>5</sort_order>
66
+ <show_in_default>1</show_in_default>
67
+ <show_in_website>1</show_in_website>
68
+ <show_in_store>1</show_in_store>
69
+ <comment><![CDATA[This is your Riskified's account username]]></comment>
70
+ </domain>
71
+ <key translate="label comment">
72
+ <label>Auth token</label>
73
+ <frontend_type>Text</frontend_type>
74
+ <sort_order>6</sort_order>
75
+ <show_in_default>1</show_in_default>
76
+ <show_in_website>1</show_in_website>
77
+ <show_in_store>1</show_in_store>
78
+ <comment><![CDATA[ Your <i>secret</i> auth token can be found in your Riskified Settings page. ]]></comment>
79
+ </key>
80
+
81
+ <auto_invoice_enabled translate="label comment">
82
+ <label>Enable Auto-Invoice</label>
83
+ <frontend_type>select</frontend_type>
84
+ <source_model>adminhtml/system_config_source_yesno</source_model>
85
+ <sort_order>110</sort_order>
86
+ <show_in_default>1</show_in_default>
87
+ <show_in_website>0</show_in_website>
88
+ <show_in_store>0</show_in_store>
89
+ <comment><![CDATA[Should an invoice automatically be created when Riskified approves this order?]]></comment>
90
+ <depends>
91
+ <order_status_sync>1</order_status_sync>
92
+ </depends>
93
+ </auto_invoice_enabled>
94
+ <auto_invoice_capture_case translate="label comment">
95
+ <label>Auto-Invoice Capture Case</label>
96
+ <frontend_type>select</frontend_type>
97
+ <source_model>full/system_config_source_captureCase</source_model>
98
+ <sort_order>120</sort_order>
99
+ <show_in_default>1</show_in_default>
100
+ <show_in_website>0</show_in_website>
101
+ <show_in_store>0</show_in_store>
102
+ <comment><![CDATA[Should this invoice be captured online or offline?]]></comment>
103
+ <depends>
104
+ <order_status_sync>1</order_status_sync>
105
+ </depends>
106
+ </auto_invoice_capture_case>
107
+ </fields>
108
+ </full>
109
+ </groups>
110
+ </fullsection>
111
+ </sections>
112
+ </config>
app/code/community/Riskified/Full/sql/riskified_full_setup/mysql4-install-1.0.1.php ADDED
@@ -0,0 +1,14 @@
1
+ <?php
2
+ /* @var $installer Mage_Core_Model_Resource_Setup */
3
+ $installer = $this;
4
+
5
+ $installer->startSetup();
6
+
7
+ $helper = Mage::helper('full/order_status');
8
+
9
+ Mage::getModel('sales/order_status')
10
+ ->setStatus($helper->getOnHoldStatusCode())->setLabel($helper->getOnHoldStatusLabel())
11
+ ->assignState(Mage_Sales_Model_Order::STATE_HOLDED)
12
+ ->save();
13
+
14
+ $installer->endSetup();