[IMP][H4547] website_sale_signifyd: API v3 (WIP)

This commit is contained in:
Milan Cosnefroy
2024-09-24 22:05:00 +02:00
parent 4f2049e976
commit 7bee4c8a39
12 changed files with 140 additions and 9 deletions

View File

@@ -0,0 +1,27 @@
<odoo>
<record id="signifyd_coverage_fraud" model="signifyd.coverage">
<field name="name">Fraud</field>
<field name="description">Use when you need a financial guarantee for Payment Fraud.</field>
<field name="code">FRAUD</field>
</record>
<record id="signifyd_coverage_inr" model="signifyd.coverage">
<field name="name">Item not received</field>
<field name="description">Use when you need a financial guarantee for Item Not Received.</field>
<field name="code">INR</field>
</record>
<record id="signifyd_coverage_snad" model="signifyd.coverage">
<field name="name">Significantly Not As Described</field>
<field name="description">Use when you need a financial guarantee for fraud alleging items are Significantly Not As Described. </field>
<field name="code">SNAD</field>
</record>
<record id="signifyd_coverage_all" model="signifyd.coverage">
<field name="name">All</field>
<field name="description">Use when you need a financial guarantee on all chargebacks.</field>
<field name="code">ALL</field>
</record>
<record id="signifyd_coverage_none" model="signifyd.coverage">
<field name="name">None</field>
<field name="description">Use when you do not need a financial guarantee.</field>
<field name="code">NONE</field>
</record>
</odoo>

View File

@@ -1,9 +1,12 @@
# Part of Hibou Suite Professional. See LICENSE_PROFESSIONAL file for full copyright and licensing details.
from . import delivery_carrier
from . import partner
from . import payment
from . import product_template
from . import sale_order
from . import signifyd
from . import signifyd_case
from . import signifyd_coverage
from . import signifyd_connector
from . import stock
from . import website

View File

@@ -0,0 +1,21 @@
from odoo import fields, models
class DeliveryCarrier(models.Model):
_inherit = 'delivery.carrier'
signifyd_fulfillment_method = fields.Selection(
[
("DELIVERY", "Delivery"),
("COUNTER_PICKUP", "Counter Pickup"),
("CURBSIDE_PICKUP", "Curbside Pickup"),
("LOCKER_PICKUP", "Locker Pickup"),
("STANDARD_SHIPPING", "Standard Shipping"),
("EXPEDITED_SHIPPING", "Expedited Shipping"),
("GAS_PICKUP", "Gas Pickup"),
("SCHEDULED_DELIVERY", "Scheduled Delivery")
],
string='Signifyd integration Fullfillment Method',
default='STANDARD_SHIPPING'
)
# TODO add to view

View File

@@ -6,9 +6,12 @@ from odoo import api, fields, models
class PaymentAcquirer(models.Model):
_inherit = 'payment.acquirer'
# TODO: remove options no longer available in api v3
signifyd_case_type = fields.Selection([
('', 'No Case'),
('SCORE', 'Score'),
('DECISION', 'Decision'),
('GUARANTEE', 'Guarantee'),
], string='Signifyd Case Creation', default='')
signify_coverage_types = fields.Many2many('signifyd.coverage', string='Signifyd Coverage Types')

View File

@@ -0,0 +1,8 @@
from odoo import fields, models
class ProductTemplate(models.Model):
_inherit = 'product.template'
is_digital = fields.Boolean(help='Used in Signifyd case creation.')
# TODO add to view

View File

@@ -37,11 +37,19 @@ class SaleOrder(models.Model):
def _should_post_signifyd(self):
# If we have no transaction/acquirer we will still send!
# this case is useful for admin or free orders but could be customized here.
# case_required = bool(self.website_id.signifyd_connector_id.signifyd_case_type)
# a_case_types = self.transaction_ids.mapped('acquirer_id.signifyd_case_type')
# if a_case_types:
# case_required = any(a_case_types)
# return self.state in ('sale', 'done') and not self.signifyd_case_id and case_required
case_required = bool(self.website_id.signifyd_connector_id.signifyd_case_type)
a_case_types = self.transaction_ids.mapped('acquirer_id.signifyd_case_type')
if a_case_types:
case_required = any(a_case_types)
return self.state in ('sale', 'done') and not self.signifyd_case_id and case_required
case_required = self.website_id.signifyd_connector_id.signifyd_case_type not in [
self.env.ref('website_sale_signifyd.signifyd_coverage_none').id,
False
]
coverage_types = self.transaction_ids.signifyd_coverage_ids
def post_signifyd_case(self):
if not self.website_id.signifyd_connector_id:
@@ -93,6 +101,47 @@ class SaleOrder(models.Model):
'error': 'ERROR',
}
recipients = self.partner_invoice_id + self.partner_shipping_id
new_case_vals = {
# FIXME: UUID?
'orderId': self.id,
'purchase': {
'createdAt': self.date_order.isoformat(timespec='seconds'),
'orderChannel': 'WEB',
'totalPrice': self.amount_total,
'totalShippingCost': self.amount_delivery,
# TODO: check - previously used partner_id.currency_id, but then wouldn't the amount_total be in the wrong currency?
'currency': self.currency_id.name,
'confirmationEmail': self.partner_id.email,
'confirmationPhone': self.partner_id.phone,
'products': [
'itemName': line.product_id.name,
'itemPrice': line.price_unit,
'itemQuantity': line.product_uom_qty,
'itemIsDigital': line.product_id.is_digital,
'itemCategory': line.product_id.categ_id.name,
# 'itemSubCategory'?
'itemId': line.product_id.id,
'itemUrl': line.product_id.website_url,
'itemWeight': line.product_id.weight,
for line in self.order_line if line.product_id
],
'shipments': [
{
'carrier': carrier.name,
'fulfillmentMethod': carrier.signifyd_fulfillment_method,
} for carrier in self.carrier_id
],
'coverageRequests'
}
for line in new_case_vals['purchase']['products']:
optional_keys = ['itemUrl', 'itemWeight']
for key in optional_keys:
if not line[key]:
line.pop(key)
new_case_vals = {
'decisionRequest': {
'paymentFraud': decision_request,

View File

@@ -11,6 +11,8 @@ class SignifydCase(models.Model):
_name = 'signifyd.case'
_description = 'Stores Signifyd case information on orders.'
# flow_type = fields.Selection([('pre', 'PreAuth'), ('post', 'PostAuth')], default='post', required=True)
order_id = fields.Many2one('sale.order', required=True)
partner_id = fields.Many2one('res.partner')
case_id = fields.Char(string='Case ID')
@@ -53,6 +55,9 @@ class SignifydCase(models.Model):
('REJECT', 'Reject'),
], string='Checkpoint Action')
coverage_ids = fields.Many2many('signifyd.coverage', string='Requested Coverage Types')
# TODO add to view
def _get_connector(self):
return self.order_id.website_id.signifyd_connector_id

View File

@@ -19,6 +19,7 @@ class SignifydConnector(models.Model):
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')
# TODO: remove options no longer available in api v3
signifyd_case_type = fields.Selection([
('', 'No Case'),
('SCORE', 'Score'),
@@ -26,10 +27,11 @@ class SignifydConnector(models.Model):
('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')
# TODO ideally this would be a regular constant
# however other entities currently use this by reference
API_URL = 'https://api.signifyd.com/v2'
API_URL = 'https://api.signifyd.com/v3'
def get_headers(self):
self.ensure_one()

View File

@@ -0,0 +1,10 @@
from odoo import fields, models
class SignifydCoverage(models.Model):
_name = 'signifyd.coverage'
_description = 'Signifyd Coverage type'
name = fields.Char(required=True)
description = fields.Char()
code = fields.Char(required=True)

View File

@@ -6,4 +6,5 @@ portal_signifyd_connector,portal_signifyd_connector,model_signifyd_connector,bas
manage_signifyd_case,manage_signifyd_case,model_signifyd_case,base.group_erp_manager,1,1,1,1
access_signifyd_case,access_signifyd_case,model_signifyd_case,base.group_user,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
1 id name model_id:id group_id:id perm_read perm_write perm_create perm_unlink
6 manage_signifyd_case manage_signifyd_case model_signifyd_case base.group_erp_manager 1 1 1 1
7 access_signifyd_case access_signifyd_case model_signifyd_case base.group_user 1 0 0 0
8 public_signifyd_case public_signifyd_case model_signifyd_case base.group_public 1 0 0 0
9 portal_signifyd_case portal_signifyd_case model_signifyd_case base.group_portal 1 0 0 0
10 access_signifyd_coverage access_signifyd_coverage model_signifyd_coverage base.group_user 1 0 0 0

View File

@@ -7,7 +7,8 @@
<field name="inherit_id" ref="website_payment.acquirer_form_website"/>
<field name="arch" type="xml">
<xpath expr="//field[@name='website_id']" position="after">
<field name="signifyd_case_type"/>
<!-- <field name="signifyd_case_type"/> -->
<field name="signifyd_coverage_type_ids"/>
</xpath>
</field>
</record>

View File

@@ -106,7 +106,8 @@
<group>
<field name="secret_key" 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" /> -->
<field name="signifyd_coverage_type_ids"/>
<p class="text-muted">
Optional: Add users to be notified if a sale order is declined by Signifyd.
</p>