mirror of
https://gitlab.com/hibou-io/hibou-odoo/suite.git
synced 2025-01-20 12:37:31 +02:00
169 lines
6.6 KiB
Python
169 lines
6.6 KiB
Python
# Part of Hibou Suite Professional. See LICENSE_PROFESSIONAL file for full copyright and licensing details.
|
|
|
|
import requests
|
|
from datetime import datetime as dt
|
|
from base64 import b64encode
|
|
import json
|
|
|
|
from odoo import api, fields, models
|
|
|
|
|
|
class SignifydConnector(models.Model):
|
|
_name = 'signifyd.connector'
|
|
_description = 'Interact with Signifyd API'
|
|
|
|
name = fields.Char(string='Connector Name', required=True)
|
|
test_mode = fields.Boolean(string='Test Mode')
|
|
secret_key = fields.Char(string='API Key', required=True)
|
|
secret_key_test = fields.Char(string='TEST API Key')
|
|
webhooks_registered = fields.Boolean(string='Successfully Registered Webhooks')
|
|
notify_user_ids = fields.Many2many('res.users', string='Receive decline notifications')
|
|
website_ids = fields.One2many('website', 'signifyd_connector_id', string='Used on Websites')
|
|
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='')
|
|
|
|
# TODO ideally this would be a regular constant
|
|
# however other entities currently use this by reference
|
|
API_URL = 'https://api.signifyd.com/v2'
|
|
|
|
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 register_webhooks(self):
|
|
self.ensure_one()
|
|
headers = self.get_headers()
|
|
# This should come from the website...
|
|
# we may need a better way to link the connector to the website.
|
|
base_url = None
|
|
website = self.env['website'].search([('signifyd_connector_id', '=', self.id)], limit=1)
|
|
if website and website.domain:
|
|
base_url = website.domain
|
|
if base_url.find('://') <= 0: # documentation says if no protocol use http
|
|
base_url = 'http://' + base_url
|
|
if not base_url:
|
|
base_url = self.env['ir.config_parameter'].sudo().get_param('web.base.url')
|
|
values = {
|
|
"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_REVIEW",
|
|
"url": base_url + "/signifyd/cases/update"
|
|
},
|
|
{
|
|
"event": "GUARANTEE_COMPLETION",
|
|
"url": base_url + "/signifyd/cases/update"
|
|
},
|
|
{
|
|
"event": "DECISION_MADE",
|
|
"url": base_url + "/signifyd/cases/update"
|
|
},
|
|
]
|
|
}
|
|
data = json.dumps(values, indent=4)
|
|
r = requests.post(
|
|
self.API_URL + '/teams/webhooks',
|
|
headers=headers,
|
|
data=data,
|
|
)
|
|
# r.raise_for_status()
|
|
return r
|
|
|
|
def action_register_webhooks(self):
|
|
notification = {
|
|
'type': 'ir.actions.client',
|
|
'tag': 'display_notification',
|
|
'params': {
|
|
'title': ('Signifyd Connector'),
|
|
'sticky': True,
|
|
},
|
|
}
|
|
|
|
res = self.register_webhooks()
|
|
|
|
if 200 <= res.status_code < 300:
|
|
notification['params']['type'] = 'success'
|
|
notification['params']['message'] = 'Successfully registered webhooks with Signifyd.'
|
|
self.webhooks_registered = True
|
|
return notification
|
|
|
|
else:
|
|
notification['params']['type'] = 'danger'
|
|
notification['params']['message'] = res.content.decode('utf-8')
|
|
try:
|
|
# trying to make a better error, not be exhaustive with error handling.
|
|
object = json.loads(notification['params']['message'])
|
|
notification['params']['message'] = '\n'.join([e[0] for e in (object.get('errors') or {}).values()])
|
|
except:
|
|
pass
|
|
self.webhooks_registered = False
|
|
return notification
|
|
|
|
def process_post_values(self, post):
|
|
# Construct dict from request data for endpoints
|
|
uuid = post.get('uuid')
|
|
case_id = post.get('caseId')
|
|
team_name = post.get('teamName')
|
|
team_id = post.get('teamId')
|
|
review_disposition = post.get('reviewDisposition')
|
|
guarantee_disposition = post.get('guaranteeDisposition')
|
|
order_outcome = post.get('orderOutcome')
|
|
status = post.get('status')
|
|
score = post.get('score')
|
|
disposition_reason = post.get('dispositionReason')
|
|
disposition = post.get('disposition')
|
|
checkpoint_action = post.get('checkpointAction', '')
|
|
if not checkpoint_action and guarantee_disposition:
|
|
if guarantee_disposition == 'APPROVED':
|
|
checkpoint_action = 'ACCEPT'
|
|
elif guarantee_disposition == 'DECLINED':
|
|
checkpoint_action = 'REJECT'
|
|
else:
|
|
checkpoint_action = 'HOLD'
|
|
last_update = str(dt.now())
|
|
|
|
values = {}
|
|
|
|
# Validate that the order and case match the request
|
|
values.update({'uuid': uuid}) if uuid else ''
|
|
values.update({'team_name': team_name}) if team_name else ''
|
|
values.update({'team_id': team_id}) if team_id else ''
|
|
values.update({'review_disposition': review_disposition}) if review_disposition else ''
|
|
values.update({'guarantee_disposition': guarantee_disposition}) if guarantee_disposition else ''
|
|
values.update({'order_outcome': order_outcome}) if order_outcome else ''
|
|
values.update({'status': status}) if status else ''
|
|
values.update({'score': score}) if score else ''
|
|
values.update({'case_id': case_id}) if case_id else ''
|
|
values.update({'disposition_reason': disposition_reason}) if disposition_reason else ''
|
|
values.update({'disposition': disposition}) if disposition else ''
|
|
values.update({'last_update': last_update})
|
|
values.update({'checkpoint_action': checkpoint_action})
|
|
|
|
return values
|