Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[16.0] [ADD] recurring_payment_stripe module #1151

Open
wants to merge 45 commits into
base: 16.0
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 11 commits
Commits
Show all changes
45 commits
Select commit Hold shift + click to select a range
e97eaf9
[ADD] Add recurring payments with stripe
mjavint Nov 14, 2024
e47bd6c
[FIX] Fixed recurring payments
mjavint Nov 14, 2024
e72ee4b
[FIX] Resolved all suggestion
mjavint Nov 28, 2024
ea7a9b2
[ADD] Add precommit rules
mjavint Nov 28, 2024
fa09388
Merge pull request #2 from BinhexTeam/16.0-dev
mjavint Nov 28, 2024
6007122
[ADD] Add stripe library
mjavint Dec 3, 2024
d21d398
[ADD] Add stripe library
mjavint Dec 3, 2024
02b0b61
Merge pull request #4 from BinhexTeam/16.0-dev
mjavint Dec 3, 2024
ea94dbd
[FIX] Fixed precommit error
mjavint Dec 3, 2024
b87b473
[FIX] Fixed precommit error
mjavint Dec 3, 2024
e0d75a0
[FIX] Fixed precommit flake error
mjavint Dec 3, 2024
ec6d741
[FIX] Fixed translation error in account_move.py and spaces inside su…
mjavint Dec 6, 2024
d359985
[FIX] Fixed translation error in account_move.py and spaces inside su…
mjavint Dec 6, 2024
75ac6af
[FIX] Fixed payment transaction and design modular
mjavint Dec 27, 2024
ea45267
[FIX] Fixed payment transaction and design modular (#6)
mjavint Dec 27, 2024
deb9ee4
[FIX] Fixed test implementation
mjavint Dec 30, 2024
02fa75e
[FIX] Fixed test implementation
mjavint Dec 30, 2024
a386028
16.0 dev (#7)
mjavint Dec 30, 2024
2c48daa
[FIX] Fixed test implementation
mjavint Dec 30, 2024
988f4b7
Merge remote-tracking branch 'origin/16.0-add-recurring_payments_stri…
mjavint Dec 30, 2024
71175d7
16.0 dev (#8)
mjavint Dec 30, 2024
5024bfa
Merge remote-tracking branch 'origin/16.0-add-recurring_payments_stri…
mjavint Dec 30, 2024
94b7070
[FIX] Fixed test implementation
mjavint Dec 30, 2024
1f8580c
16.0 dev (#9)
mjavint Dec 30, 2024
2e59f9b
[FIX] Fixed test implementation
mjavint Dec 30, 2024
d466972
Merge remote-tracking branch 'origin/16.0-add-recurring_payments_stri…
mjavint Dec 30, 2024
eee35fd
16.0 dev (#10)
mjavint Dec 30, 2024
4616bf8
[FIX] Fixed precommit
mjavint Dec 30, 2024
a3016a5
Merge remote-tracking branch 'origin/16.0-add-recurring_payments_stri…
mjavint Dec 30, 2024
db73567
16.0 dev (#11)
mjavint Dec 30, 2024
917df24
[FIX] Fixed implementation
mjavint Dec 30, 2024
dec7546
Merge remote-tracking branch 'origin/16.0-add-recurring_payments_stri…
mjavint Dec 30, 2024
81d188b
16.0 dev (#12)
mjavint Dec 30, 2024
b438fcb
16.0 dev (#13)
mjavint Jan 6, 2025
64530b6
Merge remote-tracking branch 'origin/16.0-add-recurring_payments_stri…
mjavint Jan 6, 2025
6042cd0
[FIX] Fixed implementation tests
mjavint Jan 6, 2025
866ef26
Merge branch '16.0-dev' into 16.0-add-recurring_payments_stripe
mjavint Jan 6, 2025
5329d7c
[FIX] Fixed implementation tests branch
mjavint Jan 6, 2025
0b8a36e
# This is a combination of 12 commits.
mjavint Nov 14, 2024
4a83366
[FIX] Fixed and squash old commit
mjavint Jan 21, 2025
8cc3e3d
[FIX] Implementations used payment.token stripe
mjavint Jan 31, 2025
8f9012a
[FIX] Fixed precommit
mjavint Jan 31, 2025
e284c64
[FIX] Fixed test
mjavint Jan 31, 2025
501c0d3
[FIX] Fixed test
mjavint Jan 31, 2025
60fda87
[FIX] Fixed test create payment
mjavint Jan 31, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ addon | version | maintainers | summary
[contract_variable_quantity](contract_variable_quantity/) | 16.0.1.1.0 | | Variable quantity in contract recurrent invoicing
[product_contract](product_contract/) | 16.0.1.0.0 | [![sbejaoui](https://github.com/sbejaoui.png?size=30px)](https://github.com/sbejaoui) | Recurring - Product Contract
[subscription_oca](subscription_oca/) | 16.0.1.0.0 | | Generate recurring invoices.
[recurring_payments_stripe](recurring_payments_stripe/) | 16.0.1.0.0 | | Pay automatically with Stripe

[//]: # (end addons)

Expand Down
2 changes: 1 addition & 1 deletion contract_sale/README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ Contract from Sale
!! This file is generated by oca-gen-addon-readme !!
!! changes will be overwritten. !!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! source digest: sha256:00fb3cdc565442ffcd3351e97d0516ce6f4ceb55402981b183f7e717a1e23173
!! source digest: sha256:c2e49dd78cebc553bbe7e5bfa2c8658e29e120878e688512e9599b43144815dd
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

.. |badge1| image:: https://img.shields.io/badge/maturity-Production%2FStable-green.png
Expand Down
Empty file.
Empty file.
Empty file.
Empty file.
Empty file.
Empty file.
13 changes: 8 additions & 5 deletions contract_sale/static/description/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,11 @@

/*
:Author: David Goodger ([email protected])
:Id: $Id: html4css1.css 8954 2022-01-20 10:10:25Z milde $
:Id: $Id: html4css1.css 9511 2024-01-13 09:50:07Z milde $
:Copyright: This stylesheet has been placed in the public domain.

Default cascading style sheet for the HTML output of Docutils.
Despite the name, some widely supported CSS2 features are used.

See https://docutils.sourceforge.io/docs/howto/html-stylesheets.html for how to
customize this style sheet.
Expand Down Expand Up @@ -274,7 +275,7 @@
margin-left: 2em ;
margin-right: 2em }

pre.code .ln { color: grey; } /* line numbers */
pre.code .ln { color: gray; } /* line numbers */
pre.code, code { background-color: #eeeeee }
pre.code .comment, code .comment { color: #5C6576 }
pre.code .keyword, code .keyword { color: #3B0D06; font-weight: bold }
Expand All @@ -300,7 +301,7 @@
span.pre {
white-space: pre }

span.problematic {
span.problematic, pre.problematic {
color: red }

span.section-subtitle {
Expand Down Expand Up @@ -366,7 +367,7 @@ <h1 class="title">Contract from Sale</h1>
!! This file is generated by oca-gen-addon-readme !!
!! changes will be overwritten. !!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! source digest: sha256:00fb3cdc565442ffcd3351e97d0516ce6f4ceb55402981b183f7e717a1e23173
!! source digest: sha256:c2e49dd78cebc553bbe7e5bfa2c8658e29e120878e688512e9599b43144815dd
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -->
<p><a class="reference external image-reference" href="https://odoo-community.org/page/development-status"><img alt="Production/Stable" src="https://img.shields.io/badge/maturity-Production%2FStable-green.png" /></a> <a class="reference external image-reference" href="http://www.gnu.org/licenses/agpl-3.0-standalone.html"><img alt="License: AGPL-3" src="https://img.shields.io/badge/licence-AGPL--3-blue.png" /></a> <a class="reference external image-reference" href="https://github.com/OCA/contract/tree/16.0/contract_sale"><img alt="OCA/contract" src="https://img.shields.io/badge/github-OCA%2Fcontract-lightgray.png?logo=github" /></a> <a class="reference external image-reference" href="https://translation.odoo-community.org/projects/contract-16-0/contract-16-0-contract_sale"><img alt="Translate me on Weblate" src="https://img.shields.io/badge/weblate-Translate%20me-F47D42.png" /></a> <a class="reference external image-reference" href="https://runboat.odoo-community.org/builds?repo=OCA/contract&amp;target_branch=16.0"><img alt="Try me on Runboat" src="https://img.shields.io/badge/runboat-Try%20me-875A7B.png" /></a></p>
<p>This module allows access to contracts for sale employees without account
Expand Down Expand Up @@ -428,7 +429,9 @@ <h2><a class="toc-backref" href="#toc-entry-5">Contributors</a></h2>
<div class="section" id="maintainers">
<h2><a class="toc-backref" href="#toc-entry-6">Maintainers</a></h2>
<p>This module is maintained by the OCA.</p>
<a class="reference external image-reference" href="https://odoo-community.org"><img alt="Odoo Community Association" src="https://odoo-community.org/logo.png" /></a>
<a class="reference external image-reference" href="https://odoo-community.org">
<img alt="Odoo Community Association" src="https://odoo-community.org/logo.png" />
</a>
<p>OCA, or the Odoo Community Association, is a nonprofit organization whose
mission is to support the collaborative development of Odoo features and
promote its widespread use.</p>
Expand Down
78 changes: 78 additions & 0 deletions recurring_payments_stripe/README.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
==============================
Recurring Payments with Stripe
==============================

..
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! This file is generated by oca-gen-addon-readme !!
!! changes will be overwritten. !!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! source digest: sha256:7aacc5b46917b14e43404143f0ccd1519d1411d580330b8eb8a8ef608fe3a5a1
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

.. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png
:target: https://odoo-community.org/page/development-status
:alt: Beta
.. |badge2| image:: https://img.shields.io/badge/licence-AGPL--3-blue.png
:target: http://www.gnu.org/licenses/agpl-3.0-standalone.html
:alt: License: AGPL-3
.. |badge3| image:: https://img.shields.io/badge/github-OCA%2Fcontract-lightgray.png?logo=github
:target: https://github.com/OCA/contract/tree/16.0/recurring_payments_stripe
:alt: OCA/contract
.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png
:target: https://translation.odoo-community.org/projects/contract-16-0/contract-16-0-recurring_payments_stripe
:alt: Translate me on Weblate
.. |badge5| image:: https://img.shields.io/badge/runboat-Try%20me-875A7B.png
:target: https://runboat.odoo-community.org/builds?repo=OCA/contract&target_branch=16.0
:alt: Try me on Runboat

|badge1| |badge2| |badge3| |badge4| |badge5|


**Table of contents**

.. contents::
:local:

Bug Tracker
===========

Bugs are tracked on `GitHub Issues <https://github.com/OCA/contract/issues>`_.
In case of trouble, please check there if your issue has already been reported.
If you spotted it first, help us to smash it by providing a detailed and welcomed
`feedback <https://github.com/OCA/contract/issues/new?body=module:%20recurring_payments_stripe%0Aversion:%2016.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**>`_.

Do not contact contributors directly about support or help with technical issues.

Credits
=======

Authors
~~~~~~~

* Binhex

Maintainers
~~~~~~~~~~~

This module is maintained by the OCA.

.. image:: https://odoo-community.org/logo.png
:alt: Odoo Community Association
:target: https://odoo-community.org

OCA, or the Odoo Community Association, is a nonprofit organization whose
mission is to support the collaborative development of Odoo features and
promote its widespread use.

.. |maintainer-mjavint| image:: https://github.com/mjavint.png?size=40px
:target: https://github.com/mjavint
:alt: mjavint

Current `maintainer <https://odoo-community.org/page/maintainer-role>`__:

|maintainer-mjavint|

This module is part of the `OCA/contract <https://github.com/OCA/contract/tree/16.0/recurring_payments_stripe>`_ project on GitHub.

You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.
1 change: 1 addition & 0 deletions recurring_payments_stripe/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from . import models
18 changes: 18 additions & 0 deletions recurring_payments_stripe/__manifest__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
{
"name": "Recurring Payments with Stripe",
"version": "16.0.1.0.0",
"summary": """ Recurring Payments with Stripe """,

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure about the spacing before and after the """.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed spaces before and after within summary content

"author": "Binhex, Odoo Community Association (OCA)",
"website": "https://github.com/OCA/contract",
"license": "AGPL-3",
"category": "Subscription Management",
"depends": ["subscription_oca", "payment_stripe", "payment"],
"data": [
"views/sale_subscription_views.xml",
"data/ir_cron.xml",
],
"installable": True,
"auto_install": False,
"external_dependencies": {"python": ["stripe"]},
"maintainers": ["mjavint"],
}
13 changes: 13 additions & 0 deletions recurring_payments_stripe/data/ir_cron.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<odoo noupdate="1">
<!-- Cron Job para Procesar Facturas Vencidas Diariamente -->
<record id="ir_cron_process_due_invoices" model="ir.cron">
<field name="name">Process Overdue Invoices for Subscriptions</field>
<field name="model_id" ref="recurring_payments_stripe.model_account_move" />
<field name="state">code</field>
<field name="code">model.cron_process_due_invoices()</field>
<field name="interval_number">1</field>
<field name="interval_type">days</field>
<field name="numbercall">-1</field>
<field name="active">True</field>
</record>
</odoo>
2 changes: 2 additions & 0 deletions recurring_payments_stripe/models/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
from . import sale_subscription
from . import account_move
94 changes: 94 additions & 0 deletions recurring_payments_stripe/models/account_move.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
import logging

import stripe

from odoo import _, api, models
from odoo.exceptions import UserError

_logger = logging.getLogger(__name__)


class AccountMove(models.Model):
_inherit = "account.move"

def action_register_payment(self):
"""
Override `action_register_payment` to automatically process Stripe
payment on subscriptions.
"""
for invoice in self:
# Find the subscription associated with the invoice, if it exists
subscription = invoice.subscription_id

Check warning on line 21 in recurring_payments_stripe/models/account_move.py

View check run for this annotation

Codecov / codecov/patch

recurring_payments_stripe/models/account_move.py#L21

Added line #L21 was not covered by tests

# Check if the subscription is recurring and has a payment method
if subscription and subscription.charge_automatically:
provider = subscription.provider_id
stripe.api_key = provider.stripe_secret_key
token = self.env["payment.token"].search(

Check warning on line 27 in recurring_payments_stripe/models/account_move.py

View check run for this annotation

Codecov / codecov/patch

recurring_payments_stripe/models/account_move.py#L25-L27

Added lines #L25 - L27 were not covered by tests
[("provider_id", "=", provider.id)]
)
try:

Check warning on line 30 in recurring_payments_stripe/models/account_move.py

View check run for this annotation

Codecov / codecov/patch

recurring_payments_stripe/models/account_move.py#L30

Added line #L30 was not covered by tests
# Create the PaymentIntent and confirm it immediately
payment_intent = stripe.PaymentIntent.create(

Check warning on line 32 in recurring_payments_stripe/models/account_move.py

View check run for this annotation

Codecov / codecov/patch

recurring_payments_stripe/models/account_move.py#L32

Added line #L32 was not covered by tests
# Stripe usa centavos
amount=int(invoice.amount_total * 100),
currency=invoice.currency_id.name.lower(),
customer=token.provider_ref,
payment_method=token.stripe_payment_method,
# Para pagos automáticos sin intervención del usuario
off_session=True,
# Confirmar el PaymentIntent inmediatamente
confirm=True,
metadata={"odoo_invoice_id": str(invoice.id)},
)

# Manejar el resultado del PaymentIntent

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comments should be in English.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed translation problem in the comment

if payment_intent["status"] == "succeeded":
# If the payment is successful, record the payment on the invoice
Payment = self.env["account.payment"].sudo()
payment_vals = {

Check warning on line 49 in recurring_payments_stripe/models/account_move.py

View check run for this annotation

Codecov / codecov/patch

recurring_payments_stripe/models/account_move.py#L48-L49

Added lines #L48 - L49 were not covered by tests
"journal_id": self.env["account.journal"]
.search([("type", "=", "bank")], limit=1)
.id,
"amount": invoice.amount_total,
"payment_type": "inbound",
"partner_type": "customer",
"partner_id": invoice.partner_id.id,
"payment_method_id": self.env.ref(
"account.account_payment_method_manual_in"
).id,
"ref": f"Stripe PaymentIntent {payment_intent['id']}",
}
payment = Payment.create(payment_vals)
payment.action_post()
invoice.payment_state = "paid"

Check warning on line 64 in recurring_payments_stripe/models/account_move.py

View check run for this annotation

Codecov / codecov/patch

recurring_payments_stripe/models/account_move.py#L62-L64

Added lines #L62 - L64 were not covered by tests
elif payment_intent["status"] == "requires_action":
raise UserError(

Check warning on line 66 in recurring_payments_stripe/models/account_move.py

View check run for this annotation

Codecov / codecov/patch

recurring_payments_stripe/models/account_move.py#L66

Added line #L66 was not covered by tests
_("Payment requires additional authentication (3D Secure).")
)
else:
raise UserError(

Check warning on line 70 in recurring_payments_stripe/models/account_move.py

View check run for this annotation

Codecov / codecov/patch

recurring_payments_stripe/models/account_move.py#L70

Added line #L70 was not covered by tests
f"Stripe payment error: {payment_intent['status']}"
)

except stripe.StripeError as e:
raise UserError(f"Stripe error: {e}") from e

Check warning on line 75 in recurring_payments_stripe/models/account_move.py

View check run for this annotation

Codecov / codecov/patch

recurring_payments_stripe/models/account_move.py#L74-L75

Added lines #L74 - L75 were not covered by tests

else:
return super(AccountMove, self).action_register_payment()

Check warning on line 78 in recurring_payments_stripe/models/account_move.py

View check run for this annotation

Codecov / codecov/patch

recurring_payments_stripe/models/account_move.py#L78

Added line #L78 was not covered by tests

@api.model
def cron_process_due_invoices(self):
"""Process payment of overdue invoices for recurring subscriptions."""

for invoice in self:
# Find the subscription associated with the invoice
subscription = invoice.subscription_id

Check warning on line 86 in recurring_payments_stripe/models/account_move.py

View check run for this annotation

Codecov / codecov/patch

recurring_payments_stripe/models/account_move.py#L86

Added line #L86 was not covered by tests

# Check if it's a recurring subscription with Stripe
if subscription and subscription.charge_automatically:
try:

Check warning on line 90 in recurring_payments_stripe/models/account_move.py

View check run for this annotation

Codecov / codecov/patch

recurring_payments_stripe/models/account_move.py#L90

Added line #L90 was not covered by tests
# Register the payment
invoice.action_register_payment()
except Exception as e:
_logger.error(f"Error Processing Due Invoices: {str(e)}")

Check warning on line 94 in recurring_payments_stripe/models/account_move.py

View check run for this annotation

Codecov / codecov/patch

recurring_payments_stripe/models/account_move.py#L92-L94

Added lines #L92 - L94 were not covered by tests
35 changes: 35 additions & 0 deletions recurring_payments_stripe/models/sale_subscription.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import stripe

from odoo import api, fields, models


class SaleSubscription(models.Model):
_inherit = "sale.subscription"

charge_automatically = fields.Boolean()
stripe_customer = fields.Char("Stripe Customer ID")
provider_id = fields.Many2one(
string="Provider_id",
domain=[("code", "=", "stripe")],
comodel_name="payment.provider",
)

def create_stripe_customer(self):
provider = self.provider_id

Check warning on line 18 in recurring_payments_stripe/models/sale_subscription.py

View check run for this annotation

Codecov / codecov/patch

recurring_payments_stripe/models/sale_subscription.py#L18

Added line #L18 was not covered by tests
if provider:
stripe.api_key = provider.stripe_secret_key

Check warning on line 20 in recurring_payments_stripe/models/sale_subscription.py

View check run for this annotation

Codecov / codecov/patch

recurring_payments_stripe/models/sale_subscription.py#L20

Added line #L20 was not covered by tests

if not self.stripe_customer:
customer = stripe.Customer.create(

Check warning on line 23 in recurring_payments_stripe/models/sale_subscription.py

View check run for this annotation

Codecov / codecov/patch

recurring_payments_stripe/models/sale_subscription.py#L23

Added line #L23 was not covered by tests
email=self.env.user.email,
name=self.env.user.name,
metadata={"odoo_subscription": str(self.id)},
)
self.stripe_customer = customer["id"]
return self.stripe_customer

Check warning on line 29 in recurring_payments_stripe/models/sale_subscription.py

View check run for this annotation

Codecov / codecov/patch

recurring_payments_stripe/models/sale_subscription.py#L28-L29

Added lines #L28 - L29 were not covered by tests

@api.onchange("charge_automatically")
def _onchange_charge_automatically(self):
for record in self:
if record.charge_automatically:
record.create_stripe_customer()

Check warning on line 35 in recurring_payments_stripe/models/sale_subscription.py

View check run for this annotation

Codecov / codecov/patch

recurring_payments_stripe/models/sale_subscription.py#L35

Added line #L35 was not covered by tests
Empty file.
Empty file.
Empty file.
Empty file.
Empty file.
Empty file.
Empty file.
Empty file.
Empty file.
Loading
Loading