14 Commits
12 changed files with 76 additions and 32 deletions
+11
View File
@@ -0,0 +1,11 @@
# BTCPay Server payment gateway for Odoo 16 and 17
## Accept bitcoin payments on Odoo 16 and 17
This odoo addon allows you to accept bitcoin and Lightning Network (and other cryptocurrency) payments in your Odoo e-commerce store.
![BTCPay Server Banner](https://raw.githubusercontent.com/btcpayserver/odoo/17.0/payment_btcpay/static/description/BTCPay-Odoo-17-featured.png)
## How to install
Please find the installation instructions here:
- [Odoo 17 documentation](https://github.com/btcpayserver/odoo/blob/17.0/payment_btcpay/README.md)
- [Odoo 16 documentation](https://github.com/btcpayserver/odoo/blob/16.0/payment_btcpay/README.md)
+19 -10
View File
@@ -1,12 +1,16 @@
# payment_btcpay # BTCPay Server payment gateway for Odoo 17
# BTCPay Server payment gateway for Odoo 16.0
## This is the module to connect Odoo 16.0 and BTCPay ## This is the module to connect Odoo 17 and BTCPay Server
This module allows you to accept bitcoin (and other cryptocurrency) payments in your Odoo e-commerce store. This module allows you to accept bitcoin (and other cryptocurrency) payments in your Odoo e-commerce store.
![BTCPay Server Website](../payment_btcpay/static/description/BTCPayServer_org.png) ![BTCPay Server Banner](https://raw.githubusercontent.com/btcpayserver/odoo/17.0/payment_btcpay/static/description/BTCPay-Odoo-17-featured.png)
:::tip
If you use Odoo 16 you can find the documentation [here](https://github.com/btcpayserver/odoo/blob/16.0/payment_btcpay/README.md).
:::
## Install the module ## Install the module
* Clone our [repository](https://github.com/btcpayserver/odoo) or download the .zip from the [releases page](https://github.com/btcpayserver/odoo/releases * Clone our [repository](https://github.com/btcpayserver/odoo) or download the .zip from the [releases page](https://github.com/btcpayserver/odoo/releases)
* Make sure you are on branch `17.0` or downloaded a release tagged with version v17.x
* Place the `payment_btcpay` directory in your Odoo addons directory * Place the `payment_btcpay` directory in your Odoo addons directory
* Install dependencies by running `pip install -r requirements.txt` (from inside the `payment_btcpay` directory) * Install dependencies by running `pip install -r requirements.txt` (from inside the `payment_btcpay` directory)
* Restart Odoo * Restart Odoo
@@ -21,7 +25,6 @@ This module allows you to accept bitcoin (and other cryptocurrency) payments in
In the BTCPay settings form, tab "Credentials": In the BTCPay settings form, tab "Credentials":
* Set field "State" to enabled * Set field "State" to enabled
* Set field "BTCPay Server URL" as test or live URL including https://. Example URL: https://testnet.demo.btcpayserver.org * Set field "BTCPay Server URL" as test or live URL including https://. Example URL: https://testnet.demo.btcpayserver.org
* Set field "Confirmation URL" where the customer will return after payment
* Get a pairing code from your BTCPay Server store: Settings -> Access Tokens * Get a pairing code from your BTCPay Server store: Settings -> Access Tokens
* Click on "Create Token" button * Click on "Create Token" button
* Label: enter e.g. "My odoo store" * Label: enter e.g. "My odoo store"
@@ -34,16 +37,22 @@ In the BTCPay settings form, tab "Credentials":
* Field Facade, keep default 'merchant'. * Field Facade, keep default 'merchant'.
On the tab "Configuration": On the tab "Configuration":
* Set field "Payment Journal" to "Bank", you can click the dropdown and click on the suggestion "Bank" * Make sure field "Payment Journal" is set to "Bank", otherwise you can click the dropdown and click on the suggestion "Bank"
* Now you can **save** the settings * Now you can **save** the settings
![Payment Provider Settings](../payment_btcpay/static/description/BTCPayPaymentSettings.png) Check the payment method is enabled:
* Go to **Website** -> **Configuration** -> **Payment Methods**
* Make sure "Pay with Bitcoin / Lightning Network" is active
Congrats, all done. Do some testing to be sure all works.
![Payment Provider Settings](https://raw.githubusercontent.com/btcpayserver/odoo/17.0/payment_btcpay/static/description/BTCPayPaymentSettings.png)
## How does the payment page look? ## How does the payment page look?
During the checkout the customers will have the option to select the payment method "Pay with Bitcoin / Lightning Network". After selecting they will be redirected to the BTCPay checkout page as shown below. During the checkout the customers will have the option to select the payment method "Pay with Bitcoin / Lightning Network". After selecting they will be redirected to the BTCPay checkout page as shown below.
![Payment Provider](../payment_btcpay/static/description/BTCPayLooksLike.png) ![Checkout page example](https://raw.githubusercontent.com/btcpayserver/odoo/17.0/payment_btcpay/static/description/BTCPayLooksLike.png)
## Transaction BTCPay Details ## Transaction BTCPay Details
@@ -52,4 +61,4 @@ In transaction object, you will find more technical information about this metho
* Invoice Id: the id of the invoice for which you want to fetch an event token * Invoice Id: the id of the invoice for which you want to fetch an event token
* Transaction Status: That indicates state of transaction * Transaction Status: That indicates state of transaction
![Transaction Btcpay Details](../payment_btcpay/static/description/BtcpayTxDetails.png) ![Transaction details of BTCPay](https://raw.githubusercontent.com/btcpayserver/odoo/17.0/payment_btcpay/static/description/BtcpayTxDetails.png)
+4 -4
View File
@@ -6,9 +6,9 @@ from . import models
from odoo.addons.payment import setup_provider, reset_payment_provider from odoo.addons.payment import setup_provider, reset_payment_provider
def post_init_hook(cr, registry): def post_init_hook(env):
setup_provider(cr, registry, 'btcpay') setup_provider(env, 'btcpay')
def uninstall_hook(cr, registry): def uninstall_hook(env):
reset_payment_provider(cr, registry, 'btcpay') reset_payment_provider(env, 'btcpay')
+3 -3
View File
@@ -1,7 +1,7 @@
#****************************************************************************** #******************************************************************************
# PAYMENT BTCPAY FOR ODOO # PAYMENT BTCPAY FOR ODOO
# #
# Copyright (C) 2023 Susanna Fort <susannafm@gmail.com> # Copyright (C) 2024 Susanna Fort <susannafm@gmail.com>, ndeet
# #
#****************************************************************************** #******************************************************************************
# #
@@ -21,11 +21,11 @@
{ {
'name': 'Payment Provider: BTCPay', 'name': 'Payment Provider: BTCPay',
'summary': 'This module integrates BTCPAY - pay with Bitcoin - with Odoo v16.0', 'summary': 'This module integrates BTCPAY - pay with Bitcoin - with Odoo v17.0',
'author': 'Vandekul', 'author': 'Vandekul',
'website': 'https://github.com/btcpayserver/odoo', 'website': 'https://github.com/btcpayserver/odoo',
'category': 'Accounting/Payment Providers', 'category': 'Accounting/Payment Providers',
'version': '16.0.0', 'version': '17.0.1.1',
'license': 'GPL-3', 'license': 'GPL-3',
'application': False, 'application': False,
'installable': True, 'installable': True,
+18 -5
View File
@@ -42,6 +42,7 @@ _logger = logging.getLogger(__name__)
class BTCPayController(http.Controller): class BTCPayController(http.Controller):
_checkout_url = '/btcpay/checkout' _checkout_url = '/btcpay/checkout'
_notify_url = '/payment/btcpay/ipn' _notify_url = '/payment/btcpay/ipn'
_return_url = '/payment/btcpay/return'
@http.route(_checkout_url, type='http', auth='public', csrf=False, website=True) @http.route(_checkout_url, type='http', auth='public', csrf=False, website=True)
def checkout(self, **data): def checkout(self, **data):
@@ -49,24 +50,26 @@ class BTCPayController(http.Controller):
_logger.info("CHECKOUT: notification received from BTCPay with data:\n%s", pprint.pformat(data)) _logger.info("CHECKOUT: notification received from BTCPay with data:\n%s", pprint.pformat(data))
tx_sudo = request.env['payment.transaction'].sudo()._get_tx_from_notification_data('btcpay', data) tx_sudo = request.env['payment.transaction'].sudo()._get_tx_from_notification_data('btcpay', data)
provider = tx_sudo.provider_id provider = tx_sudo.provider_id
notificationURL = str(data.get('notify_url')).replace("http://", "https://") notification_url = str(data.get('notify_url')).replace("http://", "https://")
base_url = request.env['ir.config_parameter'].sudo().get_param('web.base.url')
redirect_url = urls.url_join(base_url, self._return_url)
client = BTCPayClient(host=provider.btcpay_location, pem=provider.btcpay_privateKey, tokens={provider.btcpay_facade: provider.btcpay_token}) client = BTCPayClient(host=provider.btcpay_location, pem=provider.btcpay_privateKey, tokens={provider.btcpay_facade: provider.btcpay_token})
invoice = client.create_invoice( invoice = client.create_invoice(
{"price": data.get('amount'), {"price": data.get('amount'),
"currency": data.get('currency_id'), "currency": data.get('currency_id'),
"orderId": data.get('reference'), "orderId": data.get('reference'),
"token": provider.btcpay_token, "token": provider.btcpay_token,
"redirectURL": provider.btcpay_confirmationURL, "redirectURL": redirect_url,
"notificationURL": notificationURL, "notificationURL": notification_url,
"extendedNotifications": True, "extendedNotifications": True,
"buyer": {"email": data.get('email'), "buyer": {"email": data.get('email') or 'noemailavailable@example.com',
"name": data.get('name'), "name": data.get('name'),
"address1": data.get('street'), "address1": data.get('street'),
"locality": data.get('city'), "locality": data.get('city'),
"postalCode": data.get('zip'), "postalCode": data.get('zip'),
"country": data.get('country'), "country": data.get('country'),
"notify": False}}) "notify": False}})
_logger.info('Invoice %s \n NOTIFY URL: %s', invoice, notificationURL) _logger.info('Invoice %s \n NOTIFY URL: %s', invoice, notification_url)
return werkzeug.utils.redirect(invoice['url']) return werkzeug.utils.redirect(invoice['url'])
@http.route(_notify_url, type='json', auth='public', csrf=False) @http.route(_notify_url, type='json', auth='public', csrf=False)
@@ -97,3 +100,13 @@ class BTCPayController(http.Controller):
except ValidationError: # Acknowledge the notification to avoid getting spammed except ValidationError: # Acknowledge the notification to avoid getting spammed
_logger.exception("Unable to handle the notification data; skipping to acknowledge") _logger.exception("Unable to handle the notification data; skipping to acknowledge")
return '' return ''
@http.route(_return_url, type='http', auth="public", methods=['GET'], crsf=False, save_session=False)
def btcpay_return_from_redirect(self, **data):
""" BTCPay return
We could process and check the invoice status here but there is no need to as the status get's updated via
IPN anyway, so just show the user the order confirmation / payment status page.
"""
_logger.info("BTCPay: user returned to shop after payment")
return request.redirect('/payment/status')
+15 -2
View File
@@ -1,13 +1,26 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<odoo noupdate="1"> <odoo noupdate="1">
<record id="payment_method_btcpay" model="payment.method">
<field name="name">Pay with Bitcoin / Lightning Network</field>
<field name="code">btcpay</field>
<field name="active">True</field>
<field name="image" type="base64" file="payment_btcpay/static/description/icon.png"/>
<field name="support_tokenization">False</field>
<field name="support_express_checkout">False</field>
</record>
<record id="payment_provider_btcpay" model="payment.provider"> <record id="payment_provider_btcpay" model="payment.provider">
<field name="name">BTCPay payments</field> <field name="name">BTCPay payments</field>
<field name="display_as">Pay with Bitcoin / Lightning Network</field>
<field name="code">btcpay</field> <field name="code">btcpay</field>
<field name="image_128" type="base64" file="payment_btcpay/static/description/icon.png"/> <field name="image_128" type="base64" file="payment_btcpay/static/description/icon.png"/>
<field name="module_id" ref="base.module_payment_btcpay"/>
<field name="redirect_form_view_id" ref="redirect_form"/> <field name="redirect_form_view_id" ref="redirect_form"/>
<field name="module_id" ref="base.module_payment_btcpay"/>
<field name="payment_method_ids"
eval="[Command.set([
ref('payment_btcpay.payment_method_btcpay'),
])]"
/>
</record> </record>
</odoo> </odoo>
@@ -14,7 +14,6 @@ class PaymentProvider(models.Model):
selection_add=[('btcpay', "BTCPay")], ondelete={'btcpay': 'set default'}) selection_add=[('btcpay', "BTCPay")], ondelete={'btcpay': 'set default'})
btcpay_location = fields.Char(string='BTCPay Server URL', size=64, help='URL where your BTCPay Server instance is reachable (where you log into your BTCPay Server).', default='https://testnet.demo.btcpayserver.org') btcpay_location = fields.Char(string='BTCPay Server URL', size=64, help='URL where your BTCPay Server instance is reachable (where you log into your BTCPay Server).', default='https://testnet.demo.btcpayserver.org')
btcpay_confirmationURL = fields.Char(string='Confirmation URL', help='Confirmation URL to return after BTCPay payment', default='http://yourdomain/shop/confirmation')
btcpay_pairingCode = fields.Char(string='Pairing Code', help='Create paring Code in your BTCPay server and put here') btcpay_pairingCode = fields.Char(string='Pairing Code', help='Create paring Code in your BTCPay server and put here')
btcpay_token = fields.Char(string='Token', help='Access Token to BTCPay. Leave empty, will be autogenerated during pairing.') btcpay_token = fields.Char(string='Token', help='Access Token to BTCPay. Leave empty, will be autogenerated during pairing.')
+3 -3
View File
@@ -115,15 +115,15 @@ class PaymentTransaction(models.Model):
self.btcpay_txid = notification_data.get('txid') self.btcpay_txid = notification_data.get('txid')
self.btcpay_status = notification_data.get('status') self.btcpay_status = notification_data.get('status')
if self.btcpay_status in ['paid']: if self.btcpay_status in ['paid','processing']:
self._set_pending(state_message=notification_data.get('pending_reason')) self._set_pending(state_message=notification_data.get('pending_reason'))
elif self.btcpay_status in ['confirmed']: elif self.btcpay_status in ['confirmed', 'complete']:
self._set_done() self._set_done()
confirmed_orders = self._check_amount_and_confirm_order() confirmed_orders = self._check_amount_and_confirm_order()
confirmed_orders._send_order_confirmation_mail() confirmed_orders._send_order_confirmation_mail()
elif self.btcpay_status in ['new']: elif self.btcpay_status in ['new']:
self.btcpay_invoiceId = notification_data.get('invoiceID') self.btcpay_invoiceId = notification_data.get('invoiceID')
elif self.btcpay_status in ['cancel']: elif self.btcpay_status in ['cancel','cancelled']:
self._set_canceled() self._set_canceled()
elif self.btcpay_status in ['invalid']: elif self.btcpay_status in ['invalid']:
_logger.info( _logger.info(
Binary file not shown.

After

Width:  |  Height:  |  Size: 154 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 107 KiB

After

Width:  |  Height:  |  Size: 109 KiB

+1 -1
View File
@@ -4,7 +4,7 @@
<section class="oe_container"> <section class="oe_container">
<div class="oe_row oe_spaced"> <div class="oe_row oe_spaced">
<h2 class="oe_slogan">BTCPay Gateway</h2> <h2 class="oe_slogan">BTCPay Gateway</h2>
<h3 class="oe_slogan">This is the module to connect Odoo 16.0 and Btcpay</h3> <h3 class="oe_slogan">This is the module to connect Odoo 17.0 and BTCPay</h3>
<div class="oe_span6"> <div class="oe_span6">
<div class="oe_bg_img"> <div class="oe_bg_img">
<img src="BTCPayServer_org.png" class="oe_picture oe_screenshot"> <img src="BTCPayServer_org.png" class="oe_picture oe_screenshot">
@@ -7,12 +7,11 @@
<field name="inherit_id" ref="payment.payment_provider_form"/> <field name="inherit_id" ref="payment.payment_provider_form"/>
<field name="arch" type="xml"> <field name="arch" type="xml">
<group name="provider_credentials" position='inside'> <group name="provider_credentials" position='inside'>
<group attrs="{'invisible': [('code', '!=', 'btcpay')]}"> <group invisible="code != 'btcpay'">
<field name="btcpay_location"/> <field name="btcpay_location"/>
<field name="btcpay_confirmationURL"/>
<field name="btcpay_pairingCode"/> <field name="btcpay_pairingCode"/>
</group> </group>
<group attrs="{'invisible': [('code', '!=', 'btcpay')]}"> <group invisible="code != 'btcpay'">
<field name="btcpay_token"/> <field name="btcpay_token"/>
<field name="btcpay_privateKey"/> <field name="btcpay_privateKey"/>
<field name="btcpay_facade"/> <field name="btcpay_facade"/>