mirror of
https://gitlab.com/hibou-io/hibou-odoo/suite.git
synced 2025-01-20 12:37:31 +02:00
[WIP] signifyd v3
This commit is contained in:
@@ -11,3 +11,8 @@ def migrate(cr, version):
|
|||||||
WHERE signifyd_case_type IS NOT NULL
|
WHERE signifyd_case_type IS NOT NULL
|
||||||
SET signifyd_case_required = TRUE;
|
SET signifyd_case_required = TRUE;
|
||||||
''')
|
''')
|
||||||
|
|
||||||
|
cr.execute('''
|
||||||
|
ALTER TABLE signifyd_case
|
||||||
|
RENAME COLUMN uuid TO ref;
|
||||||
|
''')
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ from . import payment_acquirer
|
|||||||
from . import product_template
|
from . import product_template
|
||||||
from . import sale_order
|
from . import sale_order
|
||||||
from . import signifyd_case
|
from . import signifyd_case
|
||||||
|
from . import signifyd_case_coverage
|
||||||
from . import signifyd_coverage
|
from . import signifyd_coverage
|
||||||
from . import signifyd_connector
|
from . import signifyd_connector
|
||||||
from . import stock_picking
|
from . import stock_picking
|
||||||
|
|||||||
@@ -3,12 +3,13 @@
|
|||||||
from odoo import api, fields, models
|
from odoo import api, fields, models
|
||||||
from odoo.exceptions import UserError
|
from odoo.exceptions import UserError
|
||||||
from odoo.http import request
|
from odoo.http import request
|
||||||
|
import logging
|
||||||
|
_logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
class SaleOrder(models.Model):
|
class SaleOrder(models.Model):
|
||||||
_inherit = 'sale.order'
|
_inherit = 'sale.order'
|
||||||
|
|
||||||
# Source IP for case creation - determination attempted at order creation and if necessary at confirmation
|
# Source IP for case creation - determination attempted at order creation and, if necessary, at confirmation
|
||||||
def _get_source_ip(self):
|
def _get_source_ip(self):
|
||||||
if request:
|
if request:
|
||||||
return request.httprequest.environ['REMOTE_ADDR']
|
return request.httprequest.environ['REMOTE_ADDR']
|
||||||
@@ -49,35 +50,45 @@ class SaleOrder(models.Model):
|
|||||||
acquirers = self.transaction_ids.acquirer_id
|
acquirers = self.transaction_ids.acquirer_id
|
||||||
if acquirers and not any(acquirers.mapped('signifyd_case_required')):
|
if acquirers and not any(acquirers.mapped('signifyd_case_required')):
|
||||||
return False
|
return False
|
||||||
|
if not self.website_id.signifyd_connector_id:
|
||||||
|
return False
|
||||||
|
if not self.source_ip:
|
||||||
|
_logger.warning(f'{self.name}: no source IP for Signifyd Case creation')
|
||||||
|
return False
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def post_signifyd_case(self):
|
def post_signifyd_case(self):
|
||||||
self.ensure_one()
|
self.ensure_one()
|
||||||
signifyd_api = self.website_id.signifyd_connector_id.get_connection()
|
signifyd_api = self.website_id.signifyd_connector_id.get_connection()
|
||||||
if not signifyd_api or not self.source_ip:
|
|
||||||
return
|
# Session values for Signifyd post
|
||||||
if request and request.session:
|
if request and request.session:
|
||||||
checkout_token = request.session.session_token
|
checkout_token = request.session.session_token
|
||||||
order_session_id = checkout_token
|
order_session_id = checkout_token
|
||||||
else:
|
else:
|
||||||
checkout_token = ''
|
checkout_token = ''
|
||||||
|
|
||||||
# Session values for Signifyd post
|
|
||||||
sig_vals = self._prepare_signifyd_case_values(order_session_id, checkout_token, self.source_ip)
|
sig_vals = self._prepare_signifyd_case_values(order_session_id, checkout_token, self.source_ip)
|
||||||
|
|
||||||
response = signifyd_api.post_case(sig_vals)
|
response = signifyd_api.post_case(sig_vals)
|
||||||
success_response = response.get('signifydId')
|
case_id = response.get('signifydId')
|
||||||
if success_response:
|
|
||||||
|
if not case_id:
|
||||||
|
_logger.warning(f'{self.name}: Signifyd Case creation failed')
|
||||||
|
return None
|
||||||
|
|
||||||
new_case = self.env['signifyd.case'].create({
|
new_case = self.env['signifyd.case'].create({
|
||||||
|
'connector_id': self.website_id.signifyd_connector_id.id,
|
||||||
'order_id': self.id,
|
'order_id': self.id,
|
||||||
'case_id': success_response,
|
|
||||||
'name': success_response,
|
|
||||||
'partner_id': self.partner_id.id,
|
'partner_id': self.partner_id.id,
|
||||||
|
'name': f'{self.name} ({case_id})',
|
||||||
|
'case_id': case_id,
|
||||||
|
'ref': response.get('orderId'),
|
||||||
|
# Unused response fields in async mode:
|
||||||
|
# decision
|
||||||
|
# coverage
|
||||||
})
|
})
|
||||||
self.write({'signifyd_case_id': new_case.id})
|
self.write({'signifyd_case_id': new_case.id})
|
||||||
return new_case
|
return new_case
|
||||||
# TODO do we need to raise an exception?
|
|
||||||
return None
|
|
||||||
|
|
||||||
def _get_coverage_types(self):
|
def _get_coverage_types(self):
|
||||||
coverage_none = self.env.ref('website_sale_signifyd.signifyd_coverage_none')
|
coverage_none = self.env.ref('website_sale_signifyd.signifyd_coverage_none')
|
||||||
@@ -87,7 +98,7 @@ class SaleOrder(models.Model):
|
|||||||
if coverage_all in acquirer_coverage_types:
|
if coverage_all in acquirer_coverage_types:
|
||||||
return coverage_all
|
return coverage_all
|
||||||
# 'NONE' if specified by all acquirers
|
# 'NONE' if specified by all acquirers
|
||||||
if all(self.transaction_ids.acquirer_id.mapped(lambda a: a.signifyd_coverage_ids == coverage_none)):
|
if acquirer_coverage_types and all(self.transaction_ids.acquirer_id.mapped(lambda a: a.signifyd_coverage_ids == coverage_none)):
|
||||||
return coverage_none
|
return coverage_none
|
||||||
# Specific acquirer-level coverage types
|
# Specific acquirer-level coverage types
|
||||||
if acquirer_coverage_types - coverage_none:
|
if acquirer_coverage_types - coverage_none:
|
||||||
@@ -123,8 +134,7 @@ class SaleOrder(models.Model):
|
|||||||
|
|
||||||
# API v3 WIP
|
# API v3 WIP
|
||||||
new_case_vals = {
|
new_case_vals = {
|
||||||
# FIXME: UUID?
|
'orderId': self.name,
|
||||||
'orderId': self.id,
|
|
||||||
'purchase': {
|
'purchase': {
|
||||||
'createdAt': self.date_order.isoformat(timespec='seconds') + '+00:00',
|
'createdAt': self.date_order.isoformat(timespec='seconds') + '+00:00',
|
||||||
'orderChannel': 'WEB',
|
'orderChannel': 'WEB',
|
||||||
@@ -147,12 +157,24 @@ class SaleOrder(models.Model):
|
|||||||
'itemWeight': line.product_id.weight,
|
'itemWeight': line.product_id.weight,
|
||||||
} for line in self.order_line if line.product_id
|
} for line in self.order_line if line.product_id
|
||||||
],
|
],
|
||||||
'shipments': [
|
'shipments': [{
|
||||||
{
|
'destination': {
|
||||||
'carrier': carrier.name,
|
'fullName': self.partner_shipping_id.name,
|
||||||
'fulfillmentMethod': carrier.signifyd_fulfillment_method,
|
'organization': self.partner_shipping_id.commercial_partner_id.name or '',
|
||||||
} for carrier in self.carrier_id
|
# 'email': self.partner_shipping_id.email,
|
||||||
],
|
# 'phone': self.partner_shipping_id.phone,
|
||||||
|
'address': {
|
||||||
|
'streetAddress': self.partner_shipping_id.street or '',
|
||||||
|
'unit': self.partner_shipping_id.street2 or '',
|
||||||
|
'postalCode': self.partner_shipping_id.zip or '',
|
||||||
|
'city': self.partner_shipping_id.city or '',
|
||||||
|
'provinceCode': self.partner_shipping_id.state_id.code or '',
|
||||||
|
'countryCode': self.partner_shipping_id.country_id.code or ''
|
||||||
|
}
|
||||||
|
},
|
||||||
|
'carrier': self.carrier_id.name or '',
|
||||||
|
'fulfillmentMethod': self.carrier_id.signifyd_fulfillment_method,
|
||||||
|
}],
|
||||||
},
|
},
|
||||||
'coverageRequests': coverage_codes,
|
'coverageRequests': coverage_codes,
|
||||||
'transactions': [
|
'transactions': [
|
||||||
|
|||||||
@@ -17,11 +17,14 @@ class SignifydAPI:
|
|||||||
'Authorization': 'Basic ' + self._key,
|
'Authorization': 'Basic ' + self._key,
|
||||||
'Content-Type': 'application/json',
|
'Content-Type': 'application/json',
|
||||||
}
|
}
|
||||||
|
return headers
|
||||||
|
|
||||||
def _request(self, method, path, headers=None, json=None):
|
def _request(self, method, path, headers=None, json=None):
|
||||||
headers = headers or {}
|
request_headers = {
|
||||||
headers.update(self._get_headers())
|
**(headers or {}),
|
||||||
request = requests.request(method, API_URL + path, headers=headers, json=json)
|
**self._get_headers()
|
||||||
|
}
|
||||||
|
request = requests.request(method, API_URL + path, headers=request_headers, json=json)
|
||||||
return request
|
return request
|
||||||
|
|
||||||
def get(self, path, headers=None):
|
def get(self, path, headers=None):
|
||||||
@@ -30,7 +33,17 @@ class SignifydAPI:
|
|||||||
def post(self, path, headers=None, json=None):
|
def post(self, path, headers=None, json=None):
|
||||||
return self._request('POST', path, headers=headers, json=json)
|
return self._request('POST', path, headers=headers, json=json)
|
||||||
|
|
||||||
def post_case(self, connector, values):
|
def post_case(self, values):
|
||||||
# data = json.dumps(values, indent=4, sort_keys=True, default=str)
|
# data = json.dumps(values, indent=4, sort_keys=True, default=str)
|
||||||
r = self._post('/orders/events/sales', json=values)
|
r = self.post('/orders/events/sales', json=values)
|
||||||
return r.json()
|
return r.json()
|
||||||
|
|
||||||
|
def get_decision(self, case_id):
|
||||||
|
return self.get(f'/orders/{case_id}/decision')
|
||||||
|
|
||||||
|
def register_webhook(self, url):
|
||||||
|
return self.post(f"/teams/{self._teamid}/webhooks", json={'url': url})
|
||||||
|
|
||||||
|
def test_webhook(self, url):
|
||||||
|
# https://api.signifyd.com/v3/webhooks/tests
|
||||||
|
return self.post('/webhooks/tests', json={'url': url})
|
||||||
@@ -11,12 +11,11 @@ class SignifydCase(models.Model):
|
|||||||
_name = 'signifyd.case'
|
_name = 'signifyd.case'
|
||||||
_description = 'Stores Signifyd case information on orders.'
|
_description = 'Stores Signifyd case information on orders.'
|
||||||
|
|
||||||
# flow_type = fields.Selection([('pre', 'PreAuth'), ('post', 'PostAuth')], default='post', required=True)
|
connector_id = fields.Many2one('signifyd.connector', string='Signifyd Connector')
|
||||||
|
|
||||||
order_id = fields.Many2one('sale.order', required=True)
|
order_id = fields.Many2one('sale.order', required=True)
|
||||||
partner_id = fields.Many2one('res.partner')
|
partner_id = fields.Many2one('res.partner')
|
||||||
case_id = fields.Char(string='Case ID')
|
case_id = fields.Char(string='Case ID')
|
||||||
uuid = fields.Char(string='Unique ID')
|
ref = fields.Char(string='Reference', help="Signifyd Order ID, set to the sale order's name for new cases. Previously Unique ID.")
|
||||||
status = fields.Selection([
|
status = fields.Selection([
|
||||||
('OPEN', 'Open'),
|
('OPEN', 'Open'),
|
||||||
('DISMISSED', 'Dismissed'),
|
('DISMISSED', 'Dismissed'),
|
||||||
@@ -54,12 +53,8 @@ class SignifydCase(models.Model):
|
|||||||
('HOLD', 'Hold'),
|
('HOLD', 'Hold'),
|
||||||
('REJECT', 'Reject'),
|
('REJECT', 'Reject'),
|
||||||
], string='Checkpoint Action')
|
], string='Checkpoint Action')
|
||||||
|
coverage_ids = fields.Many2many('signifyd.coverage', string='Coverage', help='Accepted Coverage Types')
|
||||||
coverage_ids = fields.Many2many('signifyd.coverage', string='Requested Coverage Types')
|
coverage_line_ids = fields.One2many('signifyd.case.coverage', 'case_id')
|
||||||
# TODO add to view
|
|
||||||
|
|
||||||
def _get_connector(self):
|
|
||||||
return self.order_id.website_id.signifyd_connector_id
|
|
||||||
|
|
||||||
@api.model
|
@api.model
|
||||||
def _compute_signifyd_url(self):
|
def _compute_signifyd_url(self):
|
||||||
@@ -87,17 +82,62 @@ class SignifydCase(models.Model):
|
|||||||
# r = requests.post(url=url, headers=headers, json=values)
|
# r = requests.post(url=url, headers=headers, json=values)
|
||||||
# return r.json()
|
# return r.json()
|
||||||
|
|
||||||
def get_case(self):
|
# def get_case(self):
|
||||||
|
# self.ensure_one()
|
||||||
|
# if not self.case_id:
|
||||||
|
# raise UserError(_('Case not represented in Signifyd.'))
|
||||||
|
# connector = self._get_connector()
|
||||||
|
# headers = connector.get_headers()
|
||||||
|
# r = requests.get(
|
||||||
|
# connector.API_URL + '/cases/' + str(self.case_id),
|
||||||
|
# headers=headers
|
||||||
|
# )
|
||||||
|
# return r.json()
|
||||||
|
def get_decision_vals(self):
|
||||||
self.ensure_one()
|
self.ensure_one()
|
||||||
if not self.case_id:
|
api = self.connector_id.get_connection()
|
||||||
raise UserError(_('Case not represented in Signifyd.'))
|
response = api.get_decision(self.ref)
|
||||||
connector = self._get_connector()
|
response.raise_for_status()
|
||||||
headers = connector.get_headers()
|
data = response.json()
|
||||||
r = requests.get(
|
|
||||||
connector.API_URL + '/cases/' + str(self.case_id),
|
decision = data['decision']
|
||||||
headers=headers
|
case_vals = {
|
||||||
)
|
'last_update': decision.get('createdAt'),
|
||||||
return r.json()
|
'checkpoint_action': decision.get('checkpointAction'),
|
||||||
|
'score': decision.get('score'),
|
||||||
|
'coverage_line_ids': []
|
||||||
|
}
|
||||||
|
|
||||||
|
coverage = data.get('coverage')
|
||||||
|
if coverage:
|
||||||
|
coverage_map = {
|
||||||
|
'inrChargebacks': self.env.ref('website_sale_signifyd.signifyd_coverage_inr').id,
|
||||||
|
'fraudChargebacks': self.env.ref('website_sale_signifyd.signifyd_coverage_fraud').id,
|
||||||
|
'snadChargebacks': self.env.ref('website_sale_signifyd.signifyd_coverage_snad').id,
|
||||||
|
'allChargebacks': self.env.ref('website_sale_signifyd.signifyd_coverage_all').id
|
||||||
|
}
|
||||||
|
# coverage_ids = []
|
||||||
|
# if coverage.get('inrChargebacks'):
|
||||||
|
# coverage_ids += self.env.ref('website_sale_signifyd.signifyd_coverage_inr').ids
|
||||||
|
# if coverage.get('fraudChargebacks'):
|
||||||
|
# coverage_ids += self.env.ref('website_sale_signifyd.signifyd_coverage_fraud').ids
|
||||||
|
# if coverage.get('snadChargebacks'):
|
||||||
|
# coverage_ids += self.env.ref('website_sale_signifyd.signifyd_coverage_snad').ids
|
||||||
|
# if coverage.get('allChargebacks'):
|
||||||
|
# coverage_ids = self.env.ref('website_sale_signifyd.signifyd_coverage_all').ids
|
||||||
|
# vals['coverage_ids'] = coverage_ids
|
||||||
|
for name, vals in coverage.items():
|
||||||
|
if not vals:
|
||||||
|
continue
|
||||||
|
case_vals['coverage_line_ids'] += [(0, 0, {
|
||||||
|
# 'case_id': self.id,
|
||||||
|
'coverage_type_id': coverage_map[name],
|
||||||
|
'amount': vals.get('amount'),
|
||||||
|
'currency_id': self.env['res.currency'].search(
|
||||||
|
[('name', '=ilike', vals.get('currency'))], limit=1).id,
|
||||||
|
})]
|
||||||
|
|
||||||
|
return {k: v for k, v in case_vals.items() if v}
|
||||||
|
|
||||||
def action_force_update_case(self):
|
def action_force_update_case(self):
|
||||||
for record in self:
|
for record in self:
|
||||||
@@ -108,42 +148,42 @@ class SignifydCase(models.Model):
|
|||||||
if not self.case_id:
|
if not self.case_id:
|
||||||
raise UserError(_('Case not represented in Signifyd.'))
|
raise UserError(_('Case not represented in Signifyd.'))
|
||||||
if not vals:
|
if not vals:
|
||||||
case = self.get_case()
|
vals = self.get_decision_vals()
|
||||||
case_id = case.get('caseId')
|
# case_id = case.get('caseId')
|
||||||
if not case_id:
|
# if not case_id:
|
||||||
raise ValueError(_('Signifyd Case has no ID?'))
|
# raise ValueError(_('Signifyd Case has no ID?'))
|
||||||
team_id = case.get('teamId', self.team_id)
|
# team_id = case.get('teamId', self.team_id)
|
||||||
team_name = case.get('teamName', self.team_name)
|
# team_name = case.get('teamName', self.team_name)
|
||||||
uuid = case.get('uuid', self.uuid)
|
# ref = case.get('ref', self.ref)
|
||||||
status = case.get('status', self.status)
|
# status = case.get('status', self.status)
|
||||||
review_disposition = case.get('reviewDisposition', self.review_disposition)
|
# review_disposition = case.get('reviewDisposition', self.review_disposition)
|
||||||
order_outcome = case.get('orderOutcome', self.order_outcome)
|
# order_outcome = case.get('orderOutcome', self.order_outcome)
|
||||||
guarantee_disposition = case.get('guaranteeDisposition', self.guarantee_disposition)
|
# guarantee_disposition = case.get('guaranteeDisposition', self.guarantee_disposition)
|
||||||
adjusted_score = case.get('adjustedScore', self.adjusted_score)
|
# adjusted_score = case.get('adjustedScore', self.adjusted_score)
|
||||||
score = case.get('score', self.score)
|
# score = case.get('score', self.score)
|
||||||
checkpoint_action = case.get('checkpointAction', self.checkpoint_action)
|
# checkpoint_action = case.get('checkpointAction', self.checkpoint_action)
|
||||||
if not checkpoint_action and guarantee_disposition:
|
# if not checkpoint_action and guarantee_disposition:
|
||||||
if guarantee_disposition == 'APPROVED':
|
# if guarantee_disposition == 'APPROVED':
|
||||||
checkpoint_action = 'ACCEPT'
|
# checkpoint_action = 'ACCEPT'
|
||||||
elif guarantee_disposition == 'DECLINED':
|
# elif guarantee_disposition == 'DECLINED':
|
||||||
checkpoint_action = 'REJECT'
|
# checkpoint_action = 'REJECT'
|
||||||
else:
|
# else:
|
||||||
checkpoint_action = 'HOLD'
|
# checkpoint_action = 'HOLD'
|
||||||
|
|
||||||
vals = {
|
# vals = {
|
||||||
'case_id': case_id,
|
# 'case_id': case_id,
|
||||||
'team_id': team_id,
|
# 'team_id': team_id,
|
||||||
'team_name': team_name,
|
# 'team_name': team_name,
|
||||||
'uuid': uuid,
|
# 'ref': ref,
|
||||||
'status': status,
|
# 'status': status,
|
||||||
'review_disposition': review_disposition,
|
# 'review_disposition': review_disposition,
|
||||||
'order_outcome': order_outcome,
|
# 'order_outcome': order_outcome,
|
||||||
'adjusted_score': adjusted_score,
|
# 'adjusted_score': adjusted_score,
|
||||||
'guarantee_disposition': guarantee_disposition,
|
# 'guarantee_disposition': guarantee_disposition,
|
||||||
'score': score,
|
# 'score': score,
|
||||||
'last_update': dt.now(), # why not just use
|
# 'last_update': dt.now(), # why not just use
|
||||||
'checkpoint_action': checkpoint_action,
|
# 'checkpoint_action': checkpoint_action,
|
||||||
}
|
# }
|
||||||
|
|
||||||
outcome = vals.get('guarantee_disposition')
|
outcome = vals.get('guarantee_disposition')
|
||||||
checkpoint_action = vals.get('checkpoint_action')
|
checkpoint_action = vals.get('checkpoint_action')
|
||||||
@@ -152,7 +192,7 @@ class SignifydCase(models.Model):
|
|||||||
for user in connector.notify_user_ids:
|
for user in connector.notify_user_ids:
|
||||||
self.create_notification(user, outcome or checkpoint_action)
|
self.create_notification(user, outcome or checkpoint_action)
|
||||||
|
|
||||||
self.write(vals)
|
self.sudo().write(vals)
|
||||||
|
|
||||||
def create_notification(self, user, outcome):
|
def create_notification(self, user, outcome):
|
||||||
self.ensure_one()
|
self.ensure_one()
|
||||||
|
|||||||
10
website_sale_signifyd/models/signifyd_case_coverage.py
Normal file
10
website_sale_signifyd/models/signifyd_case_coverage.py
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
from odoo import fields, models
|
||||||
|
|
||||||
|
|
||||||
|
class SignifydCaseCoverage(models.Model):
|
||||||
|
_name = 'signifyd.case.coverage'
|
||||||
|
|
||||||
|
case_id = fields.Many2one('signifyd.case', required=True)
|
||||||
|
coverage_type_id = fields.Many2one('signifyd.coverage', required=True)
|
||||||
|
amount = fields.Float()
|
||||||
|
currency_id = fields.Many2one('res.currency')
|
||||||
@@ -40,12 +40,10 @@ class SignifydConnector(models.Model):
|
|||||||
def get_connection(self):
|
def get_connection(self):
|
||||||
if not self:
|
if not self:
|
||||||
return
|
return
|
||||||
return SignifydAPI(self.name, self.secret_key, self.teamid)
|
return SignifydAPI(self.secret_key, self.teamid)
|
||||||
|
|
||||||
def register_webhooks(self):
|
def register_webhooks(self):
|
||||||
self.ensure_one()
|
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.
|
# we may need a better way to link the connector to the website.
|
||||||
base_url = None
|
base_url = None
|
||||||
website = self.env['website'].search([('signifyd_connector_id', '=', self.id)], limit=1)
|
website = self.env['website'].search([('signifyd_connector_id', '=', self.id)], limit=1)
|
||||||
@@ -55,38 +53,9 @@ class SignifydConnector(models.Model):
|
|||||||
base_url = 'http://' + base_url
|
base_url = 'http://' + base_url
|
||||||
if not base_url:
|
if not base_url:
|
||||||
base_url = self.env['ir.config_parameter'].sudo().get_param('web.base.url')
|
base_url = self.env['ir.config_parameter'].sudo().get_param('web.base.url')
|
||||||
values = {
|
api = self.get_connection()
|
||||||
'webhooks': [
|
r = api.register_webhook(base_url + '/signifyd/cases/update')
|
||||||
# Given we are creating the cases, we do not need to know about it
|
r.raise_for_status()
|
||||||
# {
|
|
||||||
# "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
|
return r
|
||||||
|
|
||||||
def action_register_webhooks(self):
|
def action_register_webhooks(self):
|
||||||
|
|||||||
@@ -8,3 +8,5 @@ access_signifyd_case,access_signifyd_case,model_signifyd_case,base.group_user,1,
|
|||||||
public_signifyd_case,public_signifyd_case,model_signifyd_case,base.group_public,1,0,0,0
|
public_signifyd_case,public_signifyd_case,model_signifyd_case,base.group_public,1,0,0,0
|
||||||
portal_signifyd_case,portal_signifyd_case,model_signifyd_case,base.group_portal,1,0,0,0
|
portal_signifyd_case,portal_signifyd_case,model_signifyd_case,base.group_portal,1,0,0,0
|
||||||
access_signifyd_coverage,access_signifyd_coverage,model_signifyd_coverage,base.group_user,1,0,0,0
|
access_signifyd_coverage,access_signifyd_coverage,model_signifyd_coverage,base.group_user,1,0,0,0
|
||||||
|
manage_signifyd_case_coverage,manage_signifyd_case,model_signifyd_case_coverage,base.group_erp_manager,1,1,1,1
|
||||||
|
access_signifyd_case_coverage,access_signifyd_case_coverage,model_signifyd_case_coverage,base.group_user,1,0,0,0
|
||||||
|
|||||||
|
@@ -32,23 +32,34 @@
|
|||||||
<h1>
|
<h1>
|
||||||
<field name="name" readonly="1"/>
|
<field name="name" readonly="1"/>
|
||||||
</h1>
|
</h1>
|
||||||
<field name="signifyd_url" widget="url"/>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<group>
|
<group>
|
||||||
<group>
|
<group>
|
||||||
<field name="checkpoint_action"/>
|
<field name="checkpoint_action"/>
|
||||||
<field name="last_update"/>
|
<field name="last_update"/>
|
||||||
<field name="uuid"/>
|
|
||||||
<field name="case_id"/>
|
|
||||||
<field name="status"/>
|
<field name="status"/>
|
||||||
<field name="order_outcome"/>
|
<field name="order_outcome"/>
|
||||||
<field name="review_disposition"/>
|
<field name="review_disposition"/>
|
||||||
<field name="guarantee_disposition"/>
|
<field name="guarantee_disposition"/>
|
||||||
|
<field name="coverage_ids" widget="many2many_tags" readonly="1"/>
|
||||||
<field name="disposition_reason"/>
|
<field name="disposition_reason"/>
|
||||||
</group>
|
</group>
|
||||||
|
<group>
|
||||||
|
<field name="connector_id"/>
|
||||||
|
<field name="ref" attrs="{'readonly': [('ref', '=', False)]}"/>
|
||||||
|
<field name="case_id"/>
|
||||||
|
<field name="signifyd_url" widget="url"/>
|
||||||
|
<field name="order_id" />
|
||||||
</group>
|
</group>
|
||||||
|
</group>
|
||||||
|
<field name="coverage_line_ids" readonly="1">
|
||||||
|
<tree>
|
||||||
|
<field name="coverage_type_id"/>
|
||||||
|
<field name="amount" widget="monetary" options="{'currency_field': 'currency_id'}"/>
|
||||||
|
<field name="currency_id" invisible="1"/>
|
||||||
|
</tree>
|
||||||
|
</field>
|
||||||
</sheet>
|
</sheet>
|
||||||
</form>
|
</form>
|
||||||
</field>
|
</field>
|
||||||
@@ -104,6 +115,7 @@
|
|||||||
|
|
||||||
<group>
|
<group>
|
||||||
<group>
|
<group>
|
||||||
|
<field name="teamid" required="1"/>
|
||||||
<field name="secret_key" attrs="{'invisible': [('test_mode', '=', True)]}"/>
|
<field name="secret_key" attrs="{'invisible': [('test_mode', '=', True)]}"/>
|
||||||
<field name="secret_key_test" attrs="{'invisible': [('test_mode', '!=', True)]}"/>
|
<field name="secret_key_test" attrs="{'invisible': [('test_mode', '!=', True)]}"/>
|
||||||
<!-- <field name="signifyd_case_type" /> -->
|
<!-- <field name="signifyd_case_type" /> -->
|
||||||
|
|||||||
Reference in New Issue
Block a user