mirror of
https://gitlab.com/hibou-io/hibou-odoo/suite.git
synced 2025-01-20 12:37:31 +02:00
[IMP][H4547] website_sale_signifyd: API v3 (WIP)
This commit is contained in:
27
website_sale_signifyd/data/signifyd_coverage.xml
Normal file
27
website_sale_signifyd/data/signifyd_coverage.xml
Normal 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>
|
||||||
@@ -1,9 +1,12 @@
|
|||||||
# Part of Hibou Suite Professional. See LICENSE_PROFESSIONAL file for full copyright and licensing details.
|
# Part of Hibou Suite Professional. See LICENSE_PROFESSIONAL file for full copyright and licensing details.
|
||||||
|
|
||||||
|
from . import delivery_carrier
|
||||||
from . import partner
|
from . import partner
|
||||||
from . import payment
|
from . import payment
|
||||||
|
from . import product_template
|
||||||
from . import sale_order
|
from . import sale_order
|
||||||
from . import signifyd
|
from . import signifyd_case
|
||||||
|
from . import signifyd_coverage
|
||||||
from . import signifyd_connector
|
from . import signifyd_connector
|
||||||
from . import stock
|
from . import stock
|
||||||
from . import website
|
from . import website
|
||||||
|
|||||||
21
website_sale_signifyd/models/delivery_carrier.py
Normal file
21
website_sale_signifyd/models/delivery_carrier.py
Normal 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
|
||||||
@@ -6,9 +6,12 @@ from odoo import api, fields, models
|
|||||||
class PaymentAcquirer(models.Model):
|
class PaymentAcquirer(models.Model):
|
||||||
_inherit = 'payment.acquirer'
|
_inherit = 'payment.acquirer'
|
||||||
|
|
||||||
|
# TODO: remove options no longer available in api v3
|
||||||
signifyd_case_type = fields.Selection([
|
signifyd_case_type = fields.Selection([
|
||||||
('', 'No Case'),
|
('', 'No Case'),
|
||||||
('SCORE', 'Score'),
|
('SCORE', 'Score'),
|
||||||
('DECISION', 'Decision'),
|
('DECISION', 'Decision'),
|
||||||
('GUARANTEE', 'Guarantee'),
|
('GUARANTEE', 'Guarantee'),
|
||||||
], string='Signifyd Case Creation', default='')
|
], string='Signifyd Case Creation', default='')
|
||||||
|
|
||||||
|
signify_coverage_types = fields.Many2many('signifyd.coverage', string='Signifyd Coverage Types')
|
||||||
|
|||||||
8
website_sale_signifyd/models/product_template.py
Normal file
8
website_sale_signifyd/models/product_template.py
Normal 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
|
||||||
@@ -37,11 +37,19 @@ class SaleOrder(models.Model):
|
|||||||
def _should_post_signifyd(self):
|
def _should_post_signifyd(self):
|
||||||
# If we have no transaction/acquirer we will still send!
|
# If we have no transaction/acquirer we will still send!
|
||||||
# this case is useful for admin or free orders but could be customized here.
|
# 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)
|
case_required = bool(self.website_id.signifyd_connector_id.signifyd_case_type)
|
||||||
a_case_types = self.transaction_ids.mapped('acquirer_id.signifyd_case_type')
|
case_required = self.website_id.signifyd_connector_id.signifyd_case_type not in [
|
||||||
if a_case_types:
|
self.env.ref('website_sale_signifyd.signifyd_coverage_none').id,
|
||||||
case_required = any(a_case_types)
|
False
|
||||||
return self.state in ('sale', 'done') and not self.signifyd_case_id and case_required
|
]
|
||||||
|
coverage_types = self.transaction_ids.signifyd_coverage_ids
|
||||||
|
|
||||||
|
|
||||||
def post_signifyd_case(self):
|
def post_signifyd_case(self):
|
||||||
if not self.website_id.signifyd_connector_id:
|
if not self.website_id.signifyd_connector_id:
|
||||||
@@ -93,6 +101,47 @@ class SaleOrder(models.Model):
|
|||||||
'error': 'ERROR',
|
'error': 'ERROR',
|
||||||
}
|
}
|
||||||
recipients = self.partner_invoice_id + self.partner_shipping_id
|
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 = {
|
new_case_vals = {
|
||||||
'decisionRequest': {
|
'decisionRequest': {
|
||||||
'paymentFraud': decision_request,
|
'paymentFraud': decision_request,
|
||||||
|
|||||||
@@ -11,6 +11,8 @@ 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)
|
||||||
|
|
||||||
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')
|
||||||
@@ -53,6 +55,9 @@ class SignifydCase(models.Model):
|
|||||||
('REJECT', 'Reject'),
|
('REJECT', 'Reject'),
|
||||||
], string='Checkpoint Action')
|
], string='Checkpoint Action')
|
||||||
|
|
||||||
|
coverage_ids = fields.Many2many('signifyd.coverage', string='Requested Coverage Types')
|
||||||
|
# TODO add to view
|
||||||
|
|
||||||
def _get_connector(self):
|
def _get_connector(self):
|
||||||
return self.order_id.website_id.signifyd_connector_id
|
return self.order_id.website_id.signifyd_connector_id
|
||||||
|
|
||||||
@@ -19,6 +19,7 @@ class SignifydConnector(models.Model):
|
|||||||
webhooks_registered = fields.Boolean(string='Successfully Registered Webhooks')
|
webhooks_registered = fields.Boolean(string='Successfully Registered Webhooks')
|
||||||
notify_user_ids = fields.Many2many('res.users', string='Receive decline notifications')
|
notify_user_ids = fields.Many2many('res.users', string='Receive decline notifications')
|
||||||
website_ids = fields.One2many('website', 'signifyd_connector_id', string='Used on Websites')
|
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([
|
signifyd_case_type = fields.Selection([
|
||||||
('', 'No Case'),
|
('', 'No Case'),
|
||||||
('SCORE', 'Score'),
|
('SCORE', 'Score'),
|
||||||
@@ -26,10 +27,11 @@ class SignifydConnector(models.Model):
|
|||||||
('GUARANTEE', 'Guarantee'),
|
('GUARANTEE', 'Guarantee'),
|
||||||
], string='Default Case Creation', help='Used for internal/admin orders, overridden by payment acquirer.',
|
], string='Default Case Creation', help='Used for internal/admin orders, overridden by payment acquirer.',
|
||||||
required=True, default='')
|
required=True, default='')
|
||||||
|
signifyd_coverage_ids = fields.Many2many('signifyd.coverage', string='Available Coverage Types')
|
||||||
|
|
||||||
# TODO ideally this would be a regular constant
|
# TODO ideally this would be a regular constant
|
||||||
# however other entities currently use this by reference
|
# 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):
|
def get_headers(self):
|
||||||
self.ensure_one()
|
self.ensure_one()
|
||||||
|
|||||||
10
website_sale_signifyd/models/signifyd_coverage.py
Normal file
10
website_sale_signifyd/models/signifyd_coverage.py
Normal 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)
|
||||||
@@ -7,3 +7,4 @@ manage_signifyd_case,manage_signifyd_case,model_signifyd_case,base.group_erp_man
|
|||||||
access_signifyd_case,access_signifyd_case,model_signifyd_case,base.group_user,1,0,0,0
|
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
|
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
|
||||||
|
|||||||
|
@@ -7,7 +7,8 @@
|
|||||||
<field name="inherit_id" ref="website_payment.acquirer_form_website"/>
|
<field name="inherit_id" ref="website_payment.acquirer_form_website"/>
|
||||||
<field name="arch" type="xml">
|
<field name="arch" type="xml">
|
||||||
<xpath expr="//field[@name='website_id']" position="after">
|
<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>
|
</xpath>
|
||||||
</field>
|
</field>
|
||||||
</record>
|
</record>
|
||||||
|
|||||||
@@ -106,7 +106,8 @@
|
|||||||
<group>
|
<group>
|
||||||
<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" /> -->
|
||||||
|
<field name="signifyd_coverage_type_ids"/>
|
||||||
<p class="text-muted">
|
<p class="text-muted">
|
||||||
Optional: Add users to be notified if a sale order is declined by Signifyd.
|
Optional: Add users to be notified if a sale order is declined by Signifyd.
|
||||||
</p>
|
</p>
|
||||||
|
|||||||
Reference in New Issue
Block a user