Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
12 changes: 6 additions & 6 deletions subscription_oca/README.rst
Original file line number Diff line number Diff line change
@@ -1,7 +1,3 @@
.. image:: https://odoo-community.org/readme-banner-image
:target: https://odoo-community.org/get-involved?utm_source=readme
:alt: Odoo Community Association

=======================
Subscription management
=======================
Expand All @@ -17,7 +13,7 @@ Subscription management
.. |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/license-AGPL--3-blue.png
.. |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
Expand Down Expand Up @@ -112,7 +108,11 @@ Contributors
- Valentin Vinagre
- Alberto Martínez

- Dennis Sluijk <d.sluijk@onestein.nl>
- `Binhex <https://www.binhex.cloud>`__:

- Adasat Torres de León <a.torres@binhex.cloud>

- Chris Mann

Maintainers
-----------
Expand Down
88 changes: 86 additions & 2 deletions subscription_oca/models/sale_subscription.py
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,37 @@ class SaleSubscription(models.Model):
ondelete="restrict",
)

payment_token_id = fields.Many2one(
comodel_name="payment.token",
string="Payment Token",
store=True,
compute="_compute_payment_token_id",
domain="[('partner_id', '=', partner_id)]",
)
invoicing_mode = fields.Selection(related="template_id.invoicing_mode")

@api.depends("partner_id", "template_id")
def _compute_payment_token_id(self):
for record in self:
if record.template_id.invoicing_mode not in [
"invoice_and_payment",
]:
record.payment_token_id = False
continue
payment_token = (
self.env["payment.token"]
.sudo()
.with_company(record.company_id)
.search(
[
("partner_id", "=", record.partner_id.id),
],
limit=1,
order="write_date desc",
)
)
record.payment_token_id = payment_token.id if payment_token else False

@api.model
def _read_group_stage_ids(self, stages, domain):
stage_ids = stages.search([], order=stages._order)
Expand Down Expand Up @@ -328,12 +359,18 @@ def create_sale_order(self):

def generate_invoice(self):
invoice_number = ""
message_body = ""
msg_static = self.env._("Created invoice with reference")
if self.template_id.invoicing_mode in ["draft", "invoice", "invoice_send"]:
if self.template_id.invoicing_mode in [
"draft",
"invoice",
"invoice_send",
"invoice_and_payment",
]:
invoice = self.create_invoice()
if self.template_id.invoicing_mode != "draft":
invoice.action_post()
if self.template_id.invoicing_mode == "invoice_and_payment":
self.create_payment(invoice)
mail_template = self.template_id.invoice_mail_template_id
self.env["account.move.send"]._generate_and_send_invoices(
invoice, mail_template=mail_template, sending_methods=["email"]
Expand Down Expand Up @@ -487,3 +524,50 @@ def create(self, vals_list):
.id
)
return super().create(vals_list)

def create_payment(self, invoice):
invoice.ensure_one()
if not self.payment_token_id:
self.message_post(
body=self.env._(
f"No payment token found for partner {invoice.partner_id.name}"
)
)
return
provider = self.payment_token_id.provider_id
method_line = self.env["account.payment.method.line"].search(
[
("payment_method_id.code", "=", provider.code),
("company_id", "=", invoice.company_id.id),
],
limit=1,
)

if not method_line:
self.message_post(
body=self.env._(
f"No payment method line found for payment provider {provider.name}"
)
)
return
payment_register = self.env["account.payment.register"]
payment_vals = {
"currency_id": invoice.currency_id.id,
"journal_id": provider.journal_id.id,
"company_id": invoice.company_id.id,
"partner_id": invoice.partner_id.id,
"communication": invoice.name,
"payment_type": "inbound",
"partner_type": "customer",
"payment_difference_handling": "open",
"writeoff_label": "Write-Off",
"payment_date": fields.Date.today(),
"amount": invoice.amount_total,
"payment_method_line_id": method_line.id,
"payment_token_id": self.payment_token_id.id,
}
payment_register.with_context(
active_model="account.move",
active_ids=invoice.ids,
active_id=invoice.id,
).create(payment_vals).action_create_payments()
1 change: 1 addition & 0 deletions subscription_oca/models/sale_subscription_template.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ class SaleSubscriptionTemplate(models.Model):
("invoice", "Invoice"),
("invoice_send", "Invoice & send"),
("sale_and_invoice", "Sale order & Invoice"),
("invoice_and_payment", "Invoice & Recurring Payment"),
],
)
code = fields.Char()
Expand Down
4 changes: 3 additions & 1 deletion subscription_oca/readme/CONTRIBUTORS.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,6 @@
- Harald Panten
- Valentin Vinagre
- Alberto Martínez
- Dennis Sluijk \<<d.sluijk@onestein.nl>\>
- [Binhex](https://www.binhex.cloud):
- Adasat Torres de León \<<a.torres@binhex.cloud>\>
- Chris Mann <chrisandrewmann>
34 changes: 16 additions & 18 deletions subscription_oca/static/description/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta name="generator" content="Docutils: https://docutils.sourceforge.io/" />
<title>README.rst</title>
<title>Subscription management</title>
<style type="text/css">

/*
Expand Down Expand Up @@ -360,21 +360,16 @@
</style>
</head>
<body>
<div class="document">
<div class="document" id="subscription-management">
<h1 class="title">Subscription management</h1>


<a class="reference external image-reference" href="https://odoo-community.org/get-involved?utm_source=readme">
<img alt="Odoo Community Association" src="https://odoo-community.org/readme-banner-image" />
</a>
<div class="section" id="subscription-management">
<h1>Subscription management</h1>
<!-- !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! This file is generated by oca-gen-addon-readme !!
!! changes will be overwritten. !!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! source digest: sha256:ab6023e140886cb5c4fe2d8e969d404ab4a58de4701d6b906c424c9521d1b5d1
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -->
<p><a class="reference external image-reference" href="https://odoo-community.org/page/development-status"><img alt="Beta" src="https://img.shields.io/badge/maturity-Beta-yellow.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/license-AGPL--3-blue.png" /></a> <a class="reference external image-reference" href="https://github.com/OCA/contract/tree/18.0/subscription_oca"><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-18-0/contract-18-0-subscription_oca"><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=18.0"><img alt="Try me on Runboat" src="https://img.shields.io/badge/runboat-Try%20me-875A7B.png" /></a></p>
<p><a class="reference external image-reference" href="https://odoo-community.org/page/development-status"><img alt="Beta" src="https://img.shields.io/badge/maturity-Beta-yellow.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/18.0/subscription_oca"><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-18-0/contract-18-0-subscription_oca"><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=18.0"><img alt="Try me on Runboat" src="https://img.shields.io/badge/runboat-Try%20me-875A7B.png" /></a></p>
<p>This module allows creating subscriptions that generate recurring
invoices or orders. It also enables the sale of products that generate
subscriptions.</p>
Expand All @@ -393,7 +388,7 @@ <h1>Subscription management</h1>
</ul>
</div>
<div class="section" id="usage">
<h2><a class="toc-backref" href="#toc-entry-1">Usage</a></h2>
<h1><a class="toc-backref" href="#toc-entry-1">Usage</a></h1>
<p>To make a subscription:</p>
<ol class="arabic simple">
<li>Go to <em>Subscriptions &gt; Configuration &gt; Subscription templates</em>.</li>
Expand Down Expand Up @@ -423,32 +418,32 @@ <h2><a class="toc-backref" href="#toc-entry-1">Usage</a></h2>
</ol>
</div>
<div class="section" id="known-issues-roadmap">
<h2><a class="toc-backref" href="#toc-entry-2">Known issues / Roadmap</a></h2>
<h1><a class="toc-backref" href="#toc-entry-2">Known issues / Roadmap</a></h1>
<ul class="simple">
<li>Refactor all the onchanges that have business logic to computed
write-able fields when possible. Keep onchanges only for UI purposes.</li>
<li>Add tests.</li>
</ul>
</div>
<div class="section" id="bug-tracker">
<h2><a class="toc-backref" href="#toc-entry-3">Bug Tracker</a></h2>
<h1><a class="toc-backref" href="#toc-entry-3">Bug Tracker</a></h1>
<p>Bugs are tracked on <a class="reference external" href="https://github.com/OCA/contract/issues">GitHub Issues</a>.
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
<a class="reference external" href="https://github.com/OCA/contract/issues/new?body=module:%20subscription_oca%0Aversion:%2018.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**">feedback</a>.</p>
<p>Do not contact contributors directly about support or help with technical issues.</p>
</div>
<div class="section" id="credits">
<h2><a class="toc-backref" href="#toc-entry-4">Credits</a></h2>
<h1><a class="toc-backref" href="#toc-entry-4">Credits</a></h1>
<div class="section" id="authors">
<h3><a class="toc-backref" href="#toc-entry-5">Authors</a></h3>
<h2><a class="toc-backref" href="#toc-entry-5">Authors</a></h2>
<ul class="simple">
<li>Domatix</li>
<li>Onestein</li>
</ul>
</div>
<div class="section" id="contributors">
<h3><a class="toc-backref" href="#toc-entry-6">Contributors</a></h3>
<h2><a class="toc-backref" href="#toc-entry-6">Contributors</a></h2>
<ul class="simple">
<li>Carlos Martínez &lt;<a class="reference external" href="mailto:carlos&#64;domatix.com">carlos&#64;domatix.com</a>&gt;</li>
<li>Carolina Ferrer &lt;<a class="reference external" href="mailto:carolina&#64;domatix.com">carolina&#64;domatix.com</a>&gt;</li>
Expand All @@ -462,11 +457,15 @@ <h3><a class="toc-backref" href="#toc-entry-6">Contributors</a></h3>
<li>Alberto Martínez</li>
</ul>
</li>
<li>Dennis Sluijk &lt;<a class="reference external" href="mailto:d.sluijk&#64;onestein.nl">d.sluijk&#64;onestein.nl</a>&gt;</li>
<li><a class="reference external" href="https://www.binhex.cloud">Binhex</a>:<ul>
<li>Adasat Torres de León &lt;<a class="reference external" href="mailto:a.torres&#64;binhex.cloud">a.torres&#64;binhex.cloud</a>&gt;</li>
</ul>
</li>
<li>Chris Mann</li>
</ul>
</div>
<div class="section" id="maintainers">
<h3><a class="toc-backref" href="#toc-entry-7">Maintainers</a></h3>
<h2><a class="toc-backref" href="#toc-entry-7">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" />
Expand All @@ -479,6 +478,5 @@ <h3><a class="toc-backref" href="#toc-entry-7">Maintainers</a></h3>
</div>
</div>
</div>
</div>
</body>
</html>
93 changes: 92 additions & 1 deletion subscription_oca/tests/test_subscription_oca.py
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,13 @@ def setUpClass(cls):
"recurring_rule_type": "days",
}
)
cls.tmpl6 = cls.create_sub_template(
{
"recurring_rule_boundary": "unlimited",
"invoicing_mode": "invoice_and_payment",
"recurring_rule_type": "years",
}
)

cls.stage = cls.env["sale.subscription.stage"].create(
{
Expand Down Expand Up @@ -195,6 +202,13 @@ def setUpClass(cls):
"recurring_rule_boundary": True,
}
)
cls.sub10 = cls.create_sub(
{
"template_id": cls.tmpl6.id,
"recurring_rule_boundary": False,
"date_start": fields.Date.today(),
}
)

cls.sub_line = cls.create_sub_line(cls.sub1)
cls.sub_line2 = cls.env["sale.subscription.line"].create(
Expand All @@ -213,6 +227,7 @@ def setUpClass(cls):
cls.sub_line52 = cls.create_sub_line(cls.sub5, cls.product_2.id)
cls.sub_line71 = cls.create_sub_line(cls.sub7)
cls.sub_line72 = cls.create_sub_line(cls.sub7, cls.product_2.id)
cls.sub_line102 = cls.create_sub_line(cls.sub10, cls.product_2.id)

cls.close_reason = cls.env["sale.subscription.close.reason"].create(
{
Expand Down Expand Up @@ -540,7 +555,7 @@ def test_subscription_oca_sub_stage(self):

def test_x_subscription_oca_pricelist_related(self):
res = self.partner.read(["subscription_count", "subscription_ids"])
self.assertEqual(res[0]["subscription_count"], 9)
self.assertEqual(res[0]["subscription_count"], 10)
res = self.partner.action_view_subscription_ids()
self.assertIsInstance(res, dict)
sale_order = self.sub1.create_sale_order()
Expand Down Expand Up @@ -683,3 +698,79 @@ def _collect_all_sub_test_results(self, subscription):
)
test_res.append(group_stage_ids)
return test_res

def test_subscription_invoice_and_payment(self):
payment_method_unknown = self.env.ref("payment.payment_method_unknown")

account_payment_method = self.env["account.payment.method"].create(
{
"name": "Test Payment Method",
"code": "none",
"payment_type": "inbound",
}
)

account_payment_method_line = self.env["account.payment.method.line"].create(
{
"payment_method_id": account_payment_method.id,
"company_id": self.env.ref("base.main_company").id,
"name": "Test Method Line",
}
)

journal = self.env["account.journal"].create(
{
"name": "Test Journal",
"type": "bank",
"company_id": self.env.ref("base.main_company").id,
"code": "TESTJNL",
}
)

provider_test = self.env["payment.provider"].create(
{
"name": "Test Provider for Subscriptions",
"code": "none",
"company_id": self.env.ref("base.main_company").id,
"journal_id": journal.id,
"state": "test",
}
)

subscription = self.sub10
subscription.generate_invoice()
error_count = len(
self.sub10.message_ids.filtered(
lambda msg: "No payment token found for partner" in msg.body
)
)
self.assertEqual(error_count, 1)
self.assertEqual(len(subscription.invoice_ids), 1)
self.assertEqual(subscription.invoice_ids.state, "posted")
self.sub10.payment_token_id = self.env["payment.token"].create(
{
"payment_details": "1234",
"provider_id": provider_test.id,
"partner_id": self.partner.id,
"payment_method_id": payment_method_unknown.id,
"provider_ref": "provider Ref (TEST)",
"active": True,
}
)
subscription.generate_invoice()
self.assertEqual(len(subscription.invoice_ids), 2)
last_invoice = subscription.invoice_ids[-1]
self.assertEqual(last_invoice.state, "posted")
error_count = len(
self.sub10.message_ids.filtered(
lambda msg: "No payment method line found for payment provider"
in msg.body
)
)
journal.write(
{"inbound_payment_method_line_ids": [(4, account_payment_method_line.id)]}
)
subscription.generate_invoice()
self.assertEqual(len(subscription.invoice_ids), 3)
last_invoice = subscription.invoice_ids[-1]
self.assertEqual(last_invoice.state, "posted")
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@
<field name="invoicing_mode" widget="radio" />
<field
name="invoice_mail_template_id"
invisible="invoicing_mode != 'invoice_send'"
invisible="invoicing_mode not in ['invoice_send', 'invoice_and_payment']"
required="invoicing_mode == 'invoice_send'"
/>
</group>
Expand Down
Loading