diff --git a/website_sale_signifyd/__manifest__.py b/website_sale_signifyd/__manifest__.py
index 56702d3c..801c350f 100644
--- a/website_sale_signifyd/__manifest__.py
+++ b/website_sale_signifyd/__manifest__.py
@@ -8,10 +8,9 @@ Automate Order Fraud Detection with the Signifyd API.
""",
'website': 'https://hibou.io/',
'depends': [
- 'delivery',
'hibou_professional',
'stock',
- 'website_sale',
+ 'website_sale_delivery',
'website_payment',
],
'data': [
diff --git a/website_sale_signifyd/models/sale_order.py b/website_sale_signifyd/models/sale_order.py
index 5832e943..66ae5331 100644
--- a/website_sale_signifyd/models/sale_order.py
+++ b/website_sale_signifyd/models/sale_order.py
@@ -43,20 +43,23 @@ class SaleOrder(models.Model):
return True
def post_signifyd_case(self):
- if not self.website_id.signifyd_connector_id:
+ signifyd_api = self.website_id.signifyd_connector_id.get_connection()
+ if not signifyd_api:
return
+
+
browser_ip_address = request.httprequest.environ['REMOTE_ADDR']
if request.session:
checkout_token = request.session.session_token
order_session_id = checkout_token
else:
checkout_token = ''
+
# Session values for Signifyd post
sig_vals = self._prepare_signifyd_case_values(order_session_id, checkout_token, browser_ip_address)
- case = self.env['signifyd.case'].post_case(self.website_id.signifyd_connector_id, sig_vals)
-
- success_response = case.get('investigationId')
+ response = signifyd_api.post_case(sig_vals)
+ success_response = response.get('signifydId')
if success_response:
new_case = self.env['signifyd.case'].create({
'order_id': self.id,
@@ -77,7 +80,7 @@ class SaleOrder(models.Model):
if coverage_all in acquirer_coverage_types:
return coverage_all
# 'NONE' if specified by all acquirers
- if all(self.transaction_ids.acquirer_id.mapped(lambda a: a.signifyd_coverage_ids) == coverage_none):
+ if all(self.transaction_ids.acquirer_id.mapped(lambda a: a.signifyd_coverage_ids == coverage_none)):
return coverage_none
# Specific acquirer-level coverage types
if acquirer_coverage_types - coverage_none:
@@ -116,7 +119,7 @@ class SaleOrder(models.Model):
# FIXME: UUID?
'orderId': self.id,
'purchase': {
- 'createdAt': self.date_order.isoformat(timespec='seconds'),
+ 'createdAt': self.date_order.isoformat(timespec='seconds') + '+00:00',
'orderChannel': 'WEB',
'totalPrice': self.amount_total,
'totalShippingCost': self.amount_delivery,
@@ -143,8 +146,8 @@ class SaleOrder(models.Model):
'fulfillmentMethod': carrier.signifyd_fulfillment_method,
} for carrier in self.carrier_id
],
- 'coverageRequests': coverage_codes,
},
+ 'coverageRequests': coverage_codes,
'transactions': [
{
'parentTransactionId': None,
diff --git a/website_sale_signifyd/models/signifyd_api.py b/website_sale_signifyd/models/signifyd_api.py
new file mode 100644
index 00000000..ee21e773
--- /dev/null
+++ b/website_sale_signifyd/models/signifyd_api.py
@@ -0,0 +1,36 @@
+from base64 import b64encode
+import requests
+
+API_URL = 'https://api.signifyd.com/v3'
+
+
+class SignifydAPI:
+ _teamid = None
+ _key = None
+
+ def __init__(self, key, teamid):
+ self._key = b64encode(key.encode()).decode().strip('=')
+ self._teamid = teamid
+
+ def _get_headers(self):
+ headers = {
+ 'Authorization': 'Basic ' + self._key,
+ 'Content-Type': 'application/json',
+ }
+
+ def _request(self, method, path, headers=None, json=None):
+ headers = headers or {}
+ headers.update(self._get_headers())
+ request = requests.request(method, API_URL + path, headers=headers, json=json)
+ return request
+
+ def get(self, path, headers=None):
+ return self._request('GET', path, headers=headers)
+
+ def post(self, path, headers=None, json=None):
+ return self._request('POST', path, headers=headers, json=json)
+
+ def post_case(self, connector, values):
+ # data = json.dumps(values, indent=4, sort_keys=True, default=str)
+ r = self._post('/orders/events/sales', json=values)
+ return r.json()
diff --git a/website_sale_signifyd/models/signifyd_case.py b/website_sale_signifyd/models/signifyd_case.py
index d5b5133f..b3045061 100644
--- a/website_sale_signifyd/models/signifyd_case.py
+++ b/website_sale_signifyd/models/signifyd_case.py
@@ -78,18 +78,14 @@ class SignifydCase(models.Model):
subtype_xmlid='website_sale_signifyd.disposition_change')
return res
- @api.model
- def post_case(self, connector, values):
- headers = connector.get_headers()
- data = json.dumps(values, indent=4, sort_keys=True, default=str)
-
- # TODO this should be in `signifyd.connector`
- r = requests.post(
- connector.API_URL + '/cases',
- headers=headers,
- data=data,
- )
- return r.json()
+ # @api.model
+ # def post_case(self, connector, values):
+ # headers = connector.get_headers()
+ # # data = json.dumps(values, indent=4, sort_keys=True, default=str)
+ # url = connector.API_URL + '/orders/events/sales'
+ # # TODO this should be in `signifyd.connector`
+ # r = requests.post(url=url, headers=headers, json=values)
+ # return r.json()
def get_case(self):
self.ensure_one()
diff --git a/website_sale_signifyd/models/signifyd_connector.py b/website_sale_signifyd/models/signifyd_connector.py
index 392a4e91..ffaa2610 100644
--- a/website_sale_signifyd/models/signifyd_connector.py
+++ b/website_sale_signifyd/models/signifyd_connector.py
@@ -6,6 +6,7 @@ from base64 import b64encode
import json
from odoo import api, fields, models
+from .signifyd_api import SignifydAPI
class SignifydConnector(models.Model):
@@ -20,40 +21,26 @@ class SignifydConnector(models.Model):
notify_user_ids = fields.Many2many('res.users', string='Receive decline notifications')
website_ids = fields.One2many('website', 'signifyd_connector_id', string='Used on Websites')
# TODO: remove options no longer available in api v3
- signifyd_case_type = fields.Selection([
- ('', 'No Case'),
- ('SCORE', 'Score'),
- ('DECISION', 'Decision'),
- ('GUARANTEE', 'Guarantee'),
- ], string='Default Case Creation', help='Used for internal/admin orders, overridden by payment acquirer.',
- required=True, default='')
+ # signifyd_case_type = fields.Selection([
+ # ('', 'No Case'),
+ # ('SCORE', 'Score'),
+ # ('DECISION', 'Decision'),
+ # ('GUARANTEE', 'Guarantee'),
+ # ], string='Default Case Creation', help='Used for internal/admin orders, overridden by payment acquirer.',
+ # required=True, default='')
signifyd_coverage_ids = fields.Many2many('signifyd.coverage', string='Available Coverage Types',
help='Note that exclusive coverage types will only allow one to be selected.')
+ teamid = fields.Char(string='Signifyd Team ID')
@api.onchange('signifyd_coverage_ids')
def _onchange_signifyd_coverage_ids(self):
self.signifyd_coverage_ids = self.signifyd_coverage_ids._apply_exclusivity()
- # TODO ideally this would be a regular constant
- # however other entities currently use this by reference
- API_URL = 'https://api.signifyd.com/v3'
- def get_headers(self):
- self.ensure_one()
- # Check for prod or test mode
- if self.test_mode:
- api_key = self.secret_key_test
- else:
- api_key = self.secret_key
-
- b64_auth_key = b64encode(api_key.encode()).decode().replace('=', '')
-
- headers = {
- 'Authorization': 'Basic ' + b64_auth_key,
- 'Content-Type': 'application/json',
- }
-
- return headers
+ def get_connection(self):
+ if not self:
+ return
+ return SignifydAPI(self.name, self.secret_key, self.teamid)
def register_webhooks(self):
self.ensure_one()
@@ -69,27 +56,27 @@ class SignifydConnector(models.Model):
if not base_url:
base_url = self.env['ir.config_parameter'].sudo().get_param('web.base.url')
values = {
- "webhooks": [
+ 'webhooks': [
# Given we are creating the cases, we do not need to know about it
# {
# "event": "CASE_CREATION",
# "url": base_url + "/signifyd/cases/update"
# },
{
- "event": "CASE_RESCORE",
- "url": base_url + "/signifyd/cases/update"
+ 'event': 'CASE_RESCORE',
+ 'url': base_url + '/signifyd/cases/update'
},
{
- "event": "CASE_REVIEW",
- "url": base_url + "/signifyd/cases/update"
+ 'event': 'CASE_REVIEW',
+ 'url': base_url + '/signifyd/cases/update'
},
{
- "event": "GUARANTEE_COMPLETION",
- "url": base_url + "/signifyd/cases/update"
+ 'event': 'GUARANTEE_COMPLETION',
+ 'url': base_url + '/signifyd/cases/update'
},
{
- "event": "DECISION_MADE",
- "url": base_url + "/signifyd/cases/update"
+ 'event': 'DECISION_MADE',
+ 'url': base_url + '/signifyd/cases/update'
},
]
}
diff --git a/website_sale_signifyd/views/signifyd_views.xml b/website_sale_signifyd/views/signifyd_views.xml
index 1f6844cf..558fd1f8 100644
--- a/website_sale_signifyd/views/signifyd_views.xml
+++ b/website_sale_signifyd/views/signifyd_views.xml
@@ -107,7 +107,7 @@
Optional: Add users to be notified if a sale order is declined by Signifyd.