This commit is contained in:
gsinghpal
2026-04-29 03:35:33 -04:00
parent 6ac6d24da6
commit a2fe1fcbcc
61 changed files with 4655 additions and 667 deletions

View File

@@ -100,7 +100,7 @@
name="action_sync_terminals"
class="btn-secondary"
icon="fa-refresh"
invisible="not clover_merchant_id or (not clover_rest_api_token and not clover_api_key)"
invisible="not clover_merchant_id or (not clover_rest_api_token and not clover_api_key and not clover_oauth_access_token)"
colspan="2"/>
</xpath>
</field>

View File

@@ -1,7 +1,14 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<!-- Inline payment form template for Clover -->
<!-- Inline payment form template for Clover.
The card data fields are RENDERED BY CLOVER in iframes mounted
into the empty <div id="clover-card-*"> containers below. Card
data NEVER touches Odoo - the Clover iframe SDK posts directly
to Clover's tokenization endpoint and returns a clv_xxx token
which is what we then send to the backend. This is the only
way to keep Westin / NEXA out of PCI SAQ-D scope. -->
<template id="inline_form">
<t t-set="inline_form_values"
t-value="provider_sudo._clover_get_inline_form_values(
@@ -16,8 +23,10 @@
class="o_clover_payment_form"
t-att-data-clover-inline-form-values="inline_form_values">
<!-- Terminal toggle -->
<div class="mb-3 form-check">
<!-- Terminal toggle (back-office staff or in-person checkout) -->
<div class="mb-3 form-check"
name="o_clover_terminal_toggle_wrapper"
style="display:none;">
<input type="checkbox" class="form-check-input"
id="clover_use_terminal" name="use_terminal"/>
<label class="form-check-label" for="clover_use_terminal">
@@ -26,7 +35,6 @@
</label>
</div>
<!-- Terminal select (hidden by default) -->
<div class="mb-3" id="clover_terminal_select_wrapper" style="display:none;">
<label class="form-label" for="clover_terminal_select">Select Terminal</label>
<select class="form-select" id="clover_terminal_select" name="terminal_id">
@@ -34,53 +42,51 @@
</select>
</div>
<!-- Card number input -->
<div class="mb-3">
<label class="form-label" for="clover_card_number">Card Number</label>
<input type="text" class="form-control"
id="clover_card_number"
name="card_number"
placeholder="4111 1111 1111 1111"
maxlength="19"
autocomplete="cc-number"
required="required"/>
</div>
<!-- Expiry and CVV row -->
<div class="row mb-3">
<div class="col-6">
<label class="form-label" for="clover_expiry">Expiry Date</label>
<input type="text" class="form-control"
id="clover_expiry"
name="expiry"
placeholder="MM/YY"
maxlength="5"
autocomplete="cc-exp"
required="required"/>
<!-- Clover.js iframe mount points (card data lives inside these
iframes, never in our DOM). -->
<div class="o_clover_iframe_form" name="o_clover_iframe_form">
<div class="mb-3">
<label class="form-label" for="clover-card-number">Card Number</label>
<div id="clover-card-number" class="form-control"
style="height:42px; padding:0;"/>
<div class="invalid-feedback d-block"
id="clover-card-number-errors" role="alert"/>
</div>
<div class="col-6">
<label class="form-label" for="clover_cvv">CVV</label>
<input type="password" class="form-control"
id="clover_cvv"
name="cvv"
placeholder="123"
maxlength="4"
autocomplete="cc-csc"
required="required"/>
<div class="row mb-3">
<div class="col-6">
<label class="form-label" for="clover-card-date">Expiry (MM/YY)</label>
<div id="clover-card-date" class="form-control"
style="height:42px; padding:0;"/>
<div class="invalid-feedback d-block"
id="clover-card-date-errors" role="alert"/>
</div>
<div class="col-6">
<label class="form-label" for="clover-card-cvv">CVV</label>
<div id="clover-card-cvv" class="form-control"
style="height:42px; padding:0;"/>
<div class="invalid-feedback d-block"
id="clover-card-cvv-errors" role="alert"/>
</div>
</div>
<div class="mb-3">
<label class="form-label" for="clover-card-postal-code">Postal Code</label>
<div id="clover-card-postal-code" class="form-control"
style="height:42px; padding:0;"/>
<div class="invalid-feedback d-block"
id="clover-card-postal-code-errors" role="alert"/>
</div>
<div class="alert alert-warning d-none"
id="clover-sdk-error" role="alert">
<i class="fa fa-exclamation-triangle me-1"/>
<span id="clover-sdk-error-message">
Could not load the Clover payment form.
</span>
</div>
</div>
<!-- Cardholder name -->
<div class="mb-3">
<label class="form-label" for="clover_cardholder">Cardholder Name</label>
<input type="text" class="form-control"
id="clover_cardholder"
name="cardholder_name"
placeholder="John Doe"
autocomplete="cc-name"/>
</div>
<!-- Card type selector -->
<!-- Card type selector (only visible if surcharge is on AND the
iframe SDK couldn't auto-detect the brand from the typed
card number, e.g. for "Other"). -->
<div class="mb-3 o_clover_card_type_section" style="display:none;">
<label class="form-label">Card Type</label>
<div class="d-flex gap-2 flex-wrap">
@@ -107,7 +113,6 @@
</div>
</div>
<!-- Surcharge notice -->
<div class="mb-3 o_clover_surcharge_notice" style="display:none;">
<div class="alert alert-info py-2 mb-0">
<small>

View File

@@ -23,24 +23,40 @@
<field name="clover_rest_api_token"
password="True"
placeholder="From Clover Dashboard: Setup > API Tokens"/>
<separator string="OAuth (Optional)"/>
<separator string="Nexa Developer App (OAuth)"/>
<field name="clover_app_id"
placeholder="App ID (for OAuth flow)"/>
placeholder="App ID from Clover Developer Dashboard"/>
<label for="clover_app_secret"/>
<div class="o_row" col="2">
<field name="clover_app_secret" password="True"/>
</div>
<field name="clover_remote_app_id"
placeholder="Remote App ID (RAID) - X-POS-Id header"/>
<separator string="OAuth Status (auto-populated by Connect to Clover)"/>
<field name="clover_oauth_access_token"
string="Access Token Status"
readonly="1"
password="True"/>
<field name="clover_oauth_token_expiry" readonly="1"/>
</group>
</group>
<group name="provider_credentials" position="after">
<group string="Clover Actions"
invisible="code != 'clover'" name="clover_actions"
col="4">
<button string="Connect to Clover"
type="object"
name="action_clover_oauth_connect"
class="btn-primary"
icon="fa-link"
invisible="not clover_app_id or not clover_app_secret"
colspan="2"
help="Redirects you to Clover to authorise this Odoo to act on the merchant's behalf. Required for terminal payments and webhooks."/>
<button string="Test Connection"
type="object"
name="action_clover_test_connection"
class="btn-primary"
invisible="not clover_merchant_id or (not clover_api_key and not clover_rest_api_token)"
class="btn-secondary"
invisible="not clover_merchant_id or (not clover_api_key and not clover_rest_api_token and not clover_oauth_access_token)"
colspan="2"/>
</group>
<group string="Terminal Settings"

View File

@@ -10,107 +10,63 @@
<app data-string="Fusion Clover" string="Fusion Clover" name="fusion_clover"
groups="fusion_clover.group_fusion_clover_admin">
<h2>Credit Card Surcharge</h2>
<div class="row mt-4 o_settings_container">
<div class="col-12 col-lg-6 o_setting_box">
<div class="o_setting_left_pane">
<field name="clover_surcharge_enabled"/>
</div>
<div class="o_setting_right_pane">
<span class="o_form_label">Credit Card Processing Fee</span>
<div class="text-muted">
Automatically add a surcharge line to invoices when collecting payment
via Clover. The fee is calculated as a percentage of the invoice total.
<block title="Credit Card Surcharge"
help="Automatically add a credit card processing fee to invoices when collecting payment via Clover.">
<setting id="fusion_clover_surcharge"
string="Enable Surcharge"
help="When enabled, a percentage-based fee line is added to the invoice before the Clover charge is created. The percentage depends on the card brand selected.">
<field name="clover_surcharge_enabled"/>
<div class="content-group" invisible="not clover_surcharge_enabled">
<div class="row mt16">
<label for="clover_surcharge_visa_rate"
string="Visa (%)"
class="col-lg-5 o_light_label"/>
<field name="clover_surcharge_visa_rate"/>
</div>
</div>
</div>
</div>
<div class="row mt-4 o_settings_container"
invisible="not clover_surcharge_enabled">
<div class="col-12 col-lg-6 o_setting_box">
<div class="o_setting_right_pane">
<span class="o_form_label">Surcharge Rates by Card Type</span>
<div class="text-muted mb-2">
Configure the processing fee percentage for each card brand.
<div class="row">
<label for="clover_surcharge_mastercard_rate"
string="Mastercard (%)"
class="col-lg-5 o_light_label"/>
<field name="clover_surcharge_mastercard_rate"/>
</div>
<div class="mt-2">
<div class="row mb-2">
<label for="clover_surcharge_visa_rate"
class="col-5 col-form-label">Visa</label>
<div class="col-4">
<field name="clover_surcharge_visa_rate" class="o_input"/>
</div>
<div class="col-1 col-form-label">%</div>
</div>
<div class="row mb-2">
<label for="clover_surcharge_mastercard_rate"
class="col-5 col-form-label">Mastercard</label>
<div class="col-4">
<field name="clover_surcharge_mastercard_rate" class="o_input"/>
</div>
<div class="col-1 col-form-label">%</div>
</div>
<div class="row mb-2">
<label for="clover_surcharge_amex_rate"
class="col-5 col-form-label">American Express</label>
<div class="col-4">
<field name="clover_surcharge_amex_rate" class="o_input"/>
</div>
<div class="col-1 col-form-label">%</div>
</div>
<div class="row mb-2">
<label for="clover_surcharge_debit_rate"
class="col-5 col-form-label">Debit</label>
<div class="col-4">
<field name="clover_surcharge_debit_rate" class="o_input"/>
</div>
<div class="col-1 col-form-label">%</div>
</div>
<div class="row mb-2">
<label for="clover_surcharge_other_rate"
class="col-5 col-form-label">Other Cards</label>
<div class="col-4">
<field name="clover_surcharge_other_rate" class="o_input"/>
</div>
<div class="col-1 col-form-label">%</div>
</div>
<div class="row">
<label for="clover_surcharge_amex_rate"
string="Amex (%)"
class="col-lg-5 o_light_label"/>
<field name="clover_surcharge_amex_rate"/>
</div>
</div>
</div>
<div class="col-12 col-lg-6 o_setting_box">
<div class="o_setting_right_pane">
<span class="o_form_label">Surcharge Product</span>
<div class="text-muted mb-2">
The service product used for the processing fee invoice line.
<div class="row">
<label for="clover_surcharge_debit_rate"
string="Debit (%)"
class="col-lg-5 o_light_label"/>
<field name="clover_surcharge_debit_rate"/>
</div>
<div class="mt-2">
<div class="row">
<label for="clover_surcharge_other_rate"
string="Other (%)"
class="col-lg-5 o_light_label"/>
<field name="clover_surcharge_other_rate"/>
</div>
<div class="row mt16">
<label for="clover_surcharge_product_id"
string="Fee Product"
class="col-lg-5 o_light_label"/>
<field name="clover_surcharge_product_id"
domain="[('type', '=', 'service')]"/>
domain="[('type', '=', 'service')]"
options="{'no_create': True, 'no_open': True}"/>
</div>
</div>
</div>
</div>
<h2>Quick Links</h2>
<div class="row mt-4 o_settings_container">
<div class="col-12 col-lg-6 o_setting_box">
<div class="o_setting_right_pane">
<span class="o_form_label">Payment Provider</span>
<div class="text-muted mb-2">
Configure your Clover API credentials and merchant ID.
</div>
<div class="mt-2">
<button name="action_open_clover_provider"
type="object"
string="Configure Payment Provider"
class="btn-link"
icon="fa-arrow-right"/>
</div>
</div>
</div>
</div>
</setting>
<setting id="fusion_clover_provider_link"
string="Payment Provider"
help="Open the Clover payment provider record to configure your Merchant ID, Ecommerce API tokens and REST API token.">
<button name="action_open_clover_provider"
type="object"
string="Configure Clover"
class="btn-link"
icon="oi-arrow-right"/>
</setting>
</block>
</app>
</xpath>