diff --git a/sale_recurring_payment/__manifest__.py b/sale_recurring_payment/__manifest__.py
index 4205846..21b2eae 100644
--- a/sale_recurring_payment/__manifest__.py
+++ b/sale_recurring_payment/__manifest__.py
@@ -8,8 +8,7 @@
"depends": ["subscription_oca", "account_payment"],
"data": [
"security/ir.model.access.csv",
- "data/update_payment_provider_subscription_cron.xml",
- "data/terminate_payment_provider_subscription_cron.xml",
+ "data/update_payment_provider_payments_cron.xml",
"views/sale_subscription_view.xml",
"views/payment_provider_view.xml",
],
diff --git a/sale_recurring_payment/data/terminate_payment_provider_subscription_cron.xml b/sale_recurring_payment/data/terminate_payment_provider_subscription_cron.xml
deleted file mode 100644
index f050857..0000000
--- a/sale_recurring_payment/data/terminate_payment_provider_subscription_cron.xml
+++ /dev/null
@@ -1,14 +0,0 @@
-
-
-
- Terminate Payment Provider Subscription for Subscriptions
-
- code
- model.cron_terminate_payment_provider_subscriptions()
-
- 1
- days
- -1
-
-
-
diff --git a/sale_recurring_payment/data/update_payment_provider_subscription_cron.xml b/sale_recurring_payment/data/update_payment_provider_payments_cron.xml
similarity index 61%
rename from sale_recurring_payment/data/update_payment_provider_subscription_cron.xml
rename to sale_recurring_payment/data/update_payment_provider_payments_cron.xml
index 10e438e..1dccc07 100644
--- a/sale_recurring_payment/data/update_payment_provider_subscription_cron.xml
+++ b/sale_recurring_payment/data/update_payment_provider_payments_cron.xml
@@ -1,10 +1,10 @@
-
- Update Payment Provider Subscription for Subscriptions
+
+ Update Payment Provider Payments for Subscriptions
code
- model.cron_update_payment_provider_subscriptions()
+ model.cron_update_payment_provider_payments()
1
days
diff --git a/sale_recurring_payment/models/__init__.py b/sale_recurring_payment/models/__init__.py
index 764962c..f3641ce 100644
--- a/sale_recurring_payment/models/__init__.py
+++ b/sale_recurring_payment/models/__init__.py
@@ -1,5 +1,5 @@
from . import sale_subscription
from . import sale_subscription_line
-from . import payment_provider_subscription
+from . import payment_provider_mandate
from . import payment_provider
from . import payment_transaction
diff --git a/sale_recurring_payment/models/payment_provider_subscription.py b/sale_recurring_payment/models/payment_provider_mandate.py
similarity index 57%
rename from sale_recurring_payment/models/payment_provider_subscription.py
rename to sale_recurring_payment/models/payment_provider_mandate.py
index 4444e32..560772a 100644
--- a/sale_recurring_payment/models/payment_provider_subscription.py
+++ b/sale_recurring_payment/models/payment_provider_mandate.py
@@ -1,24 +1,24 @@
from odoo import fields, models
-class PaymentProviderSubscription(models.Model):
- """The payment provider subscription is attached to a sale subscription and represents a
- subscription that is created with payment providers to accept recurring
+class PaymentProviderMandate(models.Model):
+ """The payment provider mandate is attached to a sale subscription and represents a
+ mandate that is created with payment providers to accept recurring
payments for sale subscriptions
"""
- _name = "payment.provider.subscription"
- _description = "Payment Provider Subscription"
+ _name = "payment.provider.mandate"
+ _description = "Payment Provider Mandate"
_rec_name = "reference"
reference = fields.Char(
- help="The reference of the subscription",
+ help="The reference of the mandate",
readonly=True,
required=True,
)
payment_transaction_ids = fields.One2many(
"payment.transaction",
- "payment_provider_subscription_id",
+ "payment_provider_mandate_id",
string="Payment Transactions",
readonly=True,
)
diff --git a/sale_recurring_payment/models/payment_transaction.py b/sale_recurring_payment/models/payment_transaction.py
index 1a0d3ca..4bc7644 100644
--- a/sale_recurring_payment/models/payment_transaction.py
+++ b/sale_recurring_payment/models/payment_transaction.py
@@ -1,12 +1,13 @@
from odoo import api, fields, models
+from odoo.fields import Command
class PaymentTransaction(models.Model):
_inherit = "payment.transaction"
- payment_provider_subscription_id = fields.Many2one(
- "payment.provider.subscription",
- string="Payment Provider Subscription",
+ payment_provider_mandate_id = fields.Many2one(
+ "payment.provider.mandate",
+ string="Payment Provider Mandate",
readonly=True,
)
@@ -24,13 +25,13 @@ def _process_notification_data(self, data):
create_sub_for_invoice = (
self.invoice_ids
and self.invoice_ids[0].subscription_id
- and not self.invoice_ids[0].subscription_id.payment_provider_subscription_id
+ and not self.invoice_ids[0].subscription_id.payment_provider_mandate_id
)
if not create_sub_for_sale_order and not create_sub_for_invoice:
return res
payment_data = self._provider_get_payment_data()
- if not self._must_create_subscription(payment_data):
+ if not self._must_create_mandate(payment_data):
return res
if create_sub_for_sale_order:
@@ -44,79 +45,62 @@ def _process_notification_data(self, data):
invoice = self.invoice_ids[0]
subscription = invoice.subscription_id
# pylint: disable=assignment-from-none
- subscription_for_payment_provider = (
- self._create_subscription_for_payment_provider(subscription, payment_data)
+ mandate_for_payment_provider = self._get_mandate_reference_for_payment_provider(
+ payment_data
)
- payment_provider_subscription = self._create_payment_provider_subscription(
- subscription_for_payment_provider
+ payment_provider_mandate = self._create_payment_provider_mandate(
+ mandate_for_payment_provider
)
- subscription.payment_provider_subscription_id = payment_provider_subscription.id
- self.payment_provider_subscription_id = payment_provider_subscription.id
+ subscription.payment_provider_mandate_id = payment_provider_mandate.id
+ self.payment_provider_mandate_id = payment_provider_mandate.id
def _provider_get_payment_data(self):
self.ensure_one()
return {}
- def _must_create_subscription(self, data):
+ def _must_create_mandate(self, data):
# This method needs to be extended in each provider module
self.ensure_one()
return False
- def _create_subscription_for_payment_provider(self, subscription, payment_data):
- # This method needs to be extended in each provider module.
- # We expect to receive a data structure containing the payment data;
- # We expect to return a data structure (depending on the payment provider implementation) describing the payment provider subscription
+ def _get_mandate_reference_for_payment_provider(self, payment):
+ # This method needs to be extended in each provider module
self.ensure_one()
- return None
+ return False
- def _create_payment_provider_subscription(self, subscription):
- # This method needs to be extended in each provider module.
- # We expect to receive the payment provider subscription;
- # This method processes them in order to create an Odoo payment.provider.subscription
- self.ensure_one()
- return self.env["payment.provider.subscription"]
+ def _create_payment_provider_mandate(self, mandate_reference):
+ # We expect to receive the payment provider mandate reference;
+ # This method processes them in order to create an Odoo payment.provider.mandate
+ return self.env["payment.provider.mandate"].create(
+ {"reference": mandate_reference, "provider_id": self.provider_id.id}
+ )
- def _process_payment_provider_subscription_recurring_payment(
- self, subscription, payment
- ):
+ def _process_payment_provider_recurring_payment(self, subscription, invoice):
# This method needs to be extended in each provider module.
# This method should process payment transactions(recurring payments) for subscription invoices
- payment_transaction = self._get_payment_transaction(subscription, payment)
- done_payment_transaction = (
- payment_transaction.update_state_recurring_payment_transaction(
- subscription.payment_provider_subscription_id.provider_id, payment
- )
+ payment_transaction = self._get_payment_transaction_by_mandate_id_for_invoice(
+ invoice.id,
+ subscription.payment_provider_mandate_id.id,
)
- if done_payment_transaction:
- unpaid_invoices = subscription.invoice_ids.filtered(
- lambda i: i.payment_state == "not_paid"
- ).sorted("invoice_date")
- unpaid_invoice = unpaid_invoices and unpaid_invoices[0]
- if not unpaid_invoice:
- subscription.generate_invoice()
- unpaid_invoice = subscription.invoice_ids.filtered(
- lambda i: i.payment_state == "not_paid"
- ).sorted("invoice_date")[0]
- done_payment_transaction.invoice_ids = [(6, 0, unpaid_invoice.ids)]
- done_payment_transaction._reconcile_after_done()
- return None
+ return payment_transaction
- def _get_payment_transaction(self, subscription, payment):
+ def create_provider_recurring_payment(self, subscription):
# This method needs to be extended in each provider module.
- # This method should search for payment transaction if not found should create one with provided details
- return self.env["payment.transaction"]
+ # This method should create recurring payments at the provider end
+ # We expect to receive a data structure containing the payment data(depending on the payment provider implementation)
+ return None
def _prepare_vals_for_recurring_payment_transaction_for_subscription(
- self, provider_reference, amount, subscription, currency
+ self, invoice, subscription
):
# This method should return the vals for creating payment transactions
vals = {
- "amount": amount,
- "currency_id": currency.id or subscription.currency_id.id,
- "provider_reference": provider_reference,
+ "amount": invoice.amount_residual,
+ "currency_id": subscription.currency_id.id,
"partner_id": subscription.partner_id.id,
- "payment_provider_subscription_id": subscription.payment_provider_subscription_id.id,
- "provider_id": subscription.payment_provider_subscription_id.provider_id.id,
+ "payment_provider_mandate_id": subscription.payment_provider_mandate_id.id,
+ "provider_id": subscription.payment_provider_mandate_id.provider_id.id,
+ "invoice_ids": [Command.set([invoice.id])],
}
return vals
@@ -126,14 +110,14 @@ def update_state_recurring_payment_transaction(self, provider, payment):
# This method should update the state of payment transactions and return done payment transactions if any
return self.env["payment.transaction"]
- def _get_payment_transaction_by_provider_reference(
- self, provider_reference, provider_id
+ def _get_payment_transaction_by_mandate_id_for_invoice(
+ self, invoice_id, payment_provider_mandate_id
):
- # This method should search for payment transaction with provider reference provided
+ # This method should search for payment transaction with payment_provider_mandate_id and invoice provided
return self.search(
[
- ("provider_reference", "=", provider_reference),
- ("provider_id", "=", provider_id),
+ ("payment_provider_mandate_id", "=", payment_provider_mandate_id),
+ ("invoice_ids", "in", invoice_id),
],
limit=1,
)
diff --git a/sale_recurring_payment/models/sale_subscription.py b/sale_recurring_payment/models/sale_subscription.py
index 3d08280..9d7949e 100644
--- a/sale_recurring_payment/models/sale_subscription.py
+++ b/sale_recurring_payment/models/sale_subscription.py
@@ -13,17 +13,17 @@
class SaleSubscription(models.Model):
_inherit = "sale.subscription"
- payment_provider_subscription_id = fields.Many2one(
- "payment.provider.subscription",
- string="Payment Provider Subscription",
+ payment_provider_mandate_id = fields.Many2one(
+ "payment.provider.mandate",
+ string="Payment Provider Mandate",
readonly=True,
)
- is_payment_provider_subscription_terminated = fields.Boolean()
+ is_payment_provider_mandate_terminated = fields.Boolean()
last_date_invoiced = fields.Date(
- help="Date when last invoice was generated for the subscription",
+ help="Date when last invoice was generated for the mandate",
)
paid_for_date = fields.Date(
- help="The date until the subscription is paid for (invoice date + recurring rule)",
+ help="The date until the mandate is paid for (invoice date + recurring rule)",
compute="_compute_paid_for_date",
store=True,
)
@@ -45,13 +45,13 @@ def _compute_paid_for_date(self):
sub.paid_for_date = paid_for_date
@api.model
- def cron_update_payment_provider_subscriptions(self):
+ def cron_update_payment_provider_payments(self):
date_ref = fields.Date.context_today(self)
sale_subscriptions = self.search(
[
("template_id.invoicing_mode", "!=", "sale_and_invoice"),
- ("payment_provider_subscription_id", "!=", False),
- ("is_payment_provider_subscription_terminated", "=", False),
+ ("payment_provider_mandate_id", "!=", False),
+ ("is_payment_provider_mandate_terminated", "=", False),
"|",
("recurring_next_date", "<=", date_ref),
("last_date_invoiced", "=", date_ref),
@@ -65,37 +65,16 @@ def cron_update_payment_provider_subscriptions(self):
).with_company(company)
for sale_subscription in sale_subscriptions_to_update:
try:
- sale_subscription.update_sale_subscription_payments_and_subscription_status(
- date_ref
- )
+ sale_subscription.update_sale_subscription_payments(date_ref)
except Exception as exception:
sale_subscription._log_provider_exception(
exception, "updating subscription"
)
return True
- def update_sale_subscription_payments_and_subscription_status(self, date_ref):
+ def update_sale_subscription_payments(self, date_ref):
# This method needs to be extended in each provider module.
- # This method updates the payments, their status and subscription status for sale subscriptions
- return True
-
- @api.model
- def cron_terminate_payment_provider_subscriptions(self):
- date_ref = fields.Date.context_today(self)
- sale_subscriptions = self.search(
- [
- ("payment_provider_subscription_id", "!=", False),
- ("is_payment_provider_subscription_terminated", "=", False),
- ("date", "<=", date_ref),
- ]
- )
- for sale_subscription in sale_subscriptions:
- try:
- sale_subscription.terminate_payment_provider_subscription()
- except Exception as exception:
- sale_subscription._log_provider_exception(
- exception, "terminating subscription"
- )
+ # This method updates the payments and their status for sale subscriptions
return True
def generate_invoice(self):
@@ -109,25 +88,15 @@ def write(self, values):
if (
record.stage_id
and record.stage_id.type == "post"
- and record.payment_provider_subscription_id
- and record.is_payment_provider_subscription_terminated
+ and record.payment_provider_mandate_id
+ and record.is_payment_provider_mandate_terminated
):
raise UserError(
_(
- "Terminated subscriptions with payment provider subscription also terminated cannot be "
+ "Terminated subscriptions with payment provider mandate also terminated cannot be "
"updated. Please generate a new subscription"
)
)
- if "sale_subscription_line_ids" in values:
- # Don't allow changes on in-progress subs because atm it will not be reflected in the payment provider (e.g. Mollie)
- if self.filtered(
- lambda sub: sub.payment_provider_subscription_id and sub.in_progress
- ):
- raise UserError(
- _(
- "Cannot change in-progress subscriptions. Please close this one and create a new one."
- )
- )
res = super().write(values)
if "stage_id" in values:
@@ -135,16 +104,16 @@ def write(self, values):
if (
record.stage_id
and record.stage_id.type == "post"
- and record.payment_provider_subscription_id
- and not record.is_payment_provider_subscription_terminated
+ and record.payment_provider_mandate_id
+ and not record.is_payment_provider_mandate_terminated
):
- record.terminate_payment_provider_subscription()
+ record.terminate_payment_provider_mandate()
return res
@api.model
- def terminate_payment_provider_subscription(self):
+ def terminate_payment_provider_mandate(self):
# This method cancels/terminates the subscription
- # This method needs to be extended in each provider module to end the subscriptions on provider end.
+ # This method needs to be extended in each provider module to end the mandates on provider end.
vals = {"date": datetime.today(), "recurring_next_date": False}
stage = self.stage_id
closed_stage = self.env["sale.subscription.stage"].search(
@@ -160,7 +129,7 @@ def _log_provider_exception(self, exception, process):
_logger.warning(
_("Payment Provider %(name)s: Error " "while %(process)s"),
dict(
- name=self.payment_provider_subscription_id.provider_id.name,
+ name=self.payment_provider_mandate_id.provider_id.name,
process=process,
),
exc_info=True,
@@ -171,7 +140,7 @@ def _log_provider_exception(self, exception, process):
" while {process} - {exception}. See server logs for "
"more details."
).format(
- name=self.payment_provider_subscription_id.provider_id.name,
+ name=self.payment_provider_mandate_id.provider_id.name,
process=process,
exception=escape(str(exception)) or _("N/A"),
),
diff --git a/sale_recurring_payment/models/sale_subscription_line.py b/sale_recurring_payment/models/sale_subscription_line.py
index 3640d95..edb9bf9 100644
--- a/sale_recurring_payment/models/sale_subscription_line.py
+++ b/sale_recurring_payment/models/sale_subscription_line.py
@@ -7,10 +7,10 @@ class SaleSubscriptionLine(models.Model):
def create(self, vals):
record = super().create(vals)
- if self.sale_subscription_id.payment_provider_subscription_id:
+ if self.sale_subscription_id.payment_provider_mandate_id:
raise ValidationError(
_(
- "New subscription line cannot be added for subscription with ongoing payment provider subscription"
+ "New subscription line cannot be added for subscription with ongoing payment provider mandate"
)
)
return record
diff --git a/sale_recurring_payment/security/ir.model.access.csv b/sale_recurring_payment/security/ir.model.access.csv
index 81d1be0..0dba5d2 100644
--- a/sale_recurring_payment/security/ir.model.access.csv
+++ b/sale_recurring_payment/security/ir.model.access.csv
@@ -1,4 +1,4 @@
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
-payment_provider_subscription_all,payment.provider.subscription.all,model_payment_provider_subscription,,1,0,0,0
-payment_provider_subscription_system,payment.provider.subscription.system,model_payment_provider_subscription,base.group_system,1,1,1,1
-payment_provider_subscription_user,payment.provider.subscription.user,model_payment_provider_subscription,base.group_user,1,1,1,0
+payment_provider_mandate_all,payment.provider.mandate.all,model_payment_provider_mandate,,1,0,0,0
+payment_provider_mandate_system,payment.provider.mandate.system,model_payment_provider_mandate,base.group_system,1,1,1,1
+payment_provider_mandate_user,payment.provider.mandate.user,model_payment_provider_mandate,base.group_user,1,1,1,0
diff --git a/sale_recurring_payment/tests/test_fields.py b/sale_recurring_payment/tests/test_fields.py
index 079b9b6..f8fa425 100644
--- a/sale_recurring_payment/tests/test_fields.py
+++ b/sale_recurring_payment/tests/test_fields.py
@@ -42,7 +42,7 @@ def test_paid_for_date(self):
self.assertFalse(sub.paid_for_date)
# Needs sale_recurring_payment_mollie e.g. installed to work, we can't do this here
- # self.env["payment.transaction"]._process_payment_provider_subscription_recurring_payment(
+ # self.env["payment.transaction"]._process_payment_provider_mandate_recurring_payment(
# sub
# )
diff --git a/sale_recurring_payment/views/sale_subscription_view.xml b/sale_recurring_payment/views/sale_subscription_view.xml
index 231230a..99db04b 100644
--- a/sale_recurring_payment/views/sale_subscription_view.xml
+++ b/sale_recurring_payment/views/sale_subscription_view.xml
@@ -5,7 +5,7 @@
-
+
diff --git a/sale_recurring_payment_mollie/__manifest__.py b/sale_recurring_payment_mollie/__manifest__.py
index 5f54c7d..1bb3244 100644
--- a/sale_recurring_payment_mollie/__manifest__.py
+++ b/sale_recurring_payment_mollie/__manifest__.py
@@ -1,9 +1,9 @@
{
- "name": "Website Sale - Recurring Payment Mollie",
+ "name": "Sale - Recurring Payment Mollie",
"version": "16.0.0.1",
"category": "eCommerce",
"license": "LGPL-3",
- "summary": "Website Sale - Recurring Payment Mollie",
+ "summary": "Sale - Recurring Payment Mollie",
"website": "https://www.onestein.nl",
"depends": ["payment_mollie_official", "sale_recurring_payment"],
"data": [
diff --git a/sale_recurring_payment_mollie/models/__init__.py b/sale_recurring_payment_mollie/models/__init__.py
index ffb5f2f..bf0bd89 100644
--- a/sale_recurring_payment_mollie/models/__init__.py
+++ b/sale_recurring_payment_mollie/models/__init__.py
@@ -1,4 +1,3 @@
-# from . import mollie_payment
from . import sale_subscription
from . import payment_provider
from . import payment_transaction
diff --git a/sale_recurring_payment_mollie/models/payment_provider.py b/sale_recurring_payment_mollie/models/payment_provider.py
index beaff46..974789d 100644
--- a/sale_recurring_payment_mollie/models/payment_provider.py
+++ b/sale_recurring_payment_mollie/models/payment_provider.py
@@ -29,7 +29,7 @@ def _mollie_get_supported_methods(
methods = super(PaymentAcquirerMollie, self)._mollie_get_supported_methods(
order, invoice, amount, currency, partner_id
)
- if order and order.group_subscription_lines():
+ if (order and order.group_subscription_lines()) or (invoice and invoice.subscription_id):
methods = methods.filtered(
lambda m: m.method_code in ["creditcard", "ideal"]
)
diff --git a/sale_recurring_payment_mollie/models/payment_transaction.py b/sale_recurring_payment_mollie/models/payment_transaction.py
index c557a55..f8730b9 100644
--- a/sale_recurring_payment_mollie/models/payment_transaction.py
+++ b/sale_recurring_payment_mollie/models/payment_transaction.py
@@ -1,7 +1,6 @@
import logging
from odoo import _, models
-from odoo.exceptions import ValidationError
_logger = logging.getLogger(__name__)
@@ -29,11 +28,10 @@ def _get_transaction_customer_id(self):
partner_obj.write({"mollie_customer_id": mollie_customer_id})
return mollie_customer_id
- def _must_create_subscription(self, payment_data):
+ def _must_create_mandate(self, payment_data):
# This method needs to be extended in each provider module
if self.provider_code != "mollie":
- return super()._must_create_subscription(payment_data)
-
+ return super()._must_create_mandate(payment_data)
payment_status = payment_data.get("status")
if payment_status == "paid":
return True
@@ -42,7 +40,6 @@ def _must_create_subscription(self, payment_data):
def _process_notification_data(self, data):
if self.provider_code != "mollie":
return super()._process_notification_data(data)
-
self._process_refund_transactions_status()
if not self.state == "done":
return super()._process_notification_data(data)
@@ -83,7 +80,20 @@ def _mollie_prepare_payment_payload(self, api_type):
"sequenceType": "first",
}
)
-
+ if self._context.get("recurring_mollie_payment"):
+ name = (
+ self.sale_order_ids
+ and self.sale_order_ids.name
+ or self.invoice_ids
+ and self.invoice_ids.name
+ )
+ payment_data.update(
+ {
+ "description": f"Payment for {name}",
+ "sequenceType": "recurring",
+ "mandateId": self._context.get("mandate_id"),
+ }
+ )
mollie_customer_id = self._get_transaction_customer_id()
if api_type == "order":
payment_data["payment"]["customerId"] = mollie_customer_id
@@ -92,84 +102,60 @@ def _mollie_prepare_payment_payload(self, api_type):
return payment_data, params
- def _create_subscription_for_payment_provider(self, subscription, payment_data):
+ def _get_mandate_reference_for_payment_provider(self, payment):
if self.provider_code != "mollie":
- return super()._create_subscription_for_payment_provider(payment_data)
-
- mollie = self.env.ref("payment.payment_provider_mollie")
- mollie_client = mollie._api_mollie_get_client()
- amount = {
- "currency": self.currency_id.name,
- "value": "%.2f" % (self.amount + self.fees),
- }
- subscription_template = subscription.template_id
- interval = "%s %s" % (
- subscription_template.recurring_interval,
- subscription_template.recurring_rule_type,
- )
- description = subscription.name
- # webhook_url = urls.url_join(mollie.get_base_url(), MollieController._webhook_url)
- mollie_customer_id = self._get_transaction_customer_id()
- customer = mollie_client.customers.get(mollie_customer_id)
-
- data = {
- "amount": amount or "",
- "interval": interval or "",
- "description": description or "",
- # 'webhookUrl': webhook_url,
- "startDate": subscription.recurring_next_date.strftime("%Y-%m-%d"),
- "mandateId": payment_data and payment_data["mandateId"] or "",
- }
- try:
- subscription = customer.subscriptions.create(
- data
- ) # Uncomment this when ready (issue is that localhost doesn't work with Mollie)
- except Exception as e:
- raise ValidationError(_(str(e))) from e
- # subscription = {'resource': 'subscription', 'subscriptions_id': 'Test ID: %s' % (datetime.datetime.now())}
-
- return subscription
+ return super()._get_mandate_reference_for_payment_provider(payment)
+ return payment and payment["mandateId"] or ""
def _provider_get_payment_data(self):
if self.provider_code != "mollie":
return super()._provider_get_payment_data()
return self.provider_id._api_mollie_get_payment_data(self.provider_reference)
- def _create_payment_provider_subscription(self, subscription):
- res = super()._create_payment_provider_subscription(subscription)
- if self.provider_code == "mollie":
- res = self.env["payment.provider.subscription"].create(
- {"reference": subscription["id"], "provider_id": self.provider_id.id}
- )
- return res
-
- def _get_payment_transaction(self, subscription, payment):
- payment_transaction = super()._get_payment_transaction(subscription, payment)
- if subscription.payment_provider_subscription_id.provider_id.code == "mollie":
- payment_transaction = self._get_payment_transaction_by_provider_reference(
- payment["id"],
- subscription.payment_provider_subscription_id.provider_id.id,
- )
- if not payment_transaction:
- provider_reference = payment["id"]
- amount = payment.get("amount", {}).get("value", 0.0)
- currency = (
- self.env["res.currency"].search(
- [("name", "=", payment.get("amount", {}).get("currency", ""))],
- limit=1,
- )
- if payment.get("amount", {}).get("currency", "")
- else subscription.currency_id
- )
+ def _process_payment_provider_recurring_payment(self, subscription, invoice):
+ payment_transaction = super()._process_payment_provider_recurring_payment(
+ subscription, invoice
+ )
+ if not payment_transaction:
+ if subscription.payment_provider_mandate_id.provider_id.code == "mollie":
payment_transaction = self.create(
self._prepare_vals_for_recurring_payment_transaction_for_subscription(
- provider_reference, amount, subscription, currency
+ invoice, subscription
+ )
+ )
+ payment = payment_transaction.create_provider_recurring_payment(
+ subscription
+ )
+ payment_transaction.write({"provider_reference": payment["id"]})
+ done_payment_transaction = (
+ payment_transaction.update_state_recurring_payment_transaction(
+ subscription.payment_provider_mandate_id.provider_id, payment
)
)
+ if done_payment_transaction:
+ done_payment_transaction._reconcile_after_done()
return payment_transaction
+ def create_provider_recurring_payment(self, subscription):
+ provider_payment = super().create_provider_recurring_payment(subscription)
+ if subscription.payment_provider_mandate_id.provider_id.code == "mollie":
+ mollie = self.env.ref("payment.payment_provider_mollie")
+ mollie_client = mollie._api_mollie_get_client()
+ mollie_payment_vals, params = self.with_context(
+ recurring_mollie_payment=True,
+ mandate_id=subscription.payment_provider_mandate_id.reference,
+ )._mollie_prepare_payment_payload("payment")
+ mollie_payment_vals.pop("redirectUrl")
+ mollie_payment_vals.pop("method")
+ mollie_payment_vals.pop("customerId")
+ customer = mollie_client.customers.get(self.partner_id.mollie_customer_id)
+ provider_payment = customer.payments.create(mollie_payment_vals)
+ return provider_payment
+
def update_state_recurring_payment_transaction(self, provider, payment):
- payment_transaction = super()._get_payment_transaction(provider, payment)
+ payment_transaction = super().update_state_recurring_payment_transaction(
+ provider, payment
+ )
if provider.code == "mollie":
payment_status = payment.get("status")
if payment_status == "paid":
diff --git a/sale_recurring_payment_mollie/models/sale_subscription.py b/sale_recurring_payment_mollie/models/sale_subscription.py
index 9f669ef..ab00af0 100644
--- a/sale_recurring_payment_mollie/models/sale_subscription.py
+++ b/sale_recurring_payment_mollie/models/sale_subscription.py
@@ -1,7 +1,6 @@
import logging
-from datetime import datetime
-from odoo import _, api, models
+from odoo import _, api, fields, models
_logger = logging.getLogger(__name__)
@@ -9,84 +8,54 @@
class SaleSubscription(models.Model):
_inherit = "sale.subscription"
- def update_sale_subscription_payments_and_subscription_status(self, date_ref):
- # This method updates the subscription status/payments from mollie
- if self.payment_provider_subscription_id.provider_id.code != "mollie":
- return super().update_sale_subscription_payments_and_subscription_status(
- date_ref
- )
+ def update_sale_subscription_payments(self, date_ref):
+ # This method updates the payments and their status for mollie
+ if self.payment_provider_mandate_id.provider_id.code != "mollie":
+ return super().update_sale_subscription_payments(date_ref)
mollie = self.env.ref("payment.payment_provider_mollie")
payment_transaction_obj = self.env["payment.transaction"]
mollie_client = mollie._api_mollie_get_client()
mollie_customer_id = self.partner_id.mollie_customer_id
if mollie_customer_id:
customer = mollie_client.customers.get(mollie_customer_id)
- subscription = customer.subscriptions.get(
- self.payment_provider_subscription_id.reference
- )
- if subscription:
- if subscription.get("STATUS_CANCELED", False) and subscription.get(
- "STATUS_CANCELED", ""
- ) == subscription.get("status", ""):
- # As the subscription is cancelled, end the subscription
- if "canceledAt" in subscription.keys():
- cancelled_date = datetime.strptime(
- subscription.get("canceledAt")[0:19], "%Y-%m-%dT%H:%M:%S"
- ).date()
- else:
- cancelled_date = date_ref
- vals = {
- "date": cancelled_date,
- "recurring_next_date": False,
- "is_payment_provider_subscription_terminated": True,
- }
- stage = self.stage_id
- closed_stage = self.env["sale.subscription.stage"].search(
- [("type", "=", "post")], limit=1
+ mandate = customer.mandates.get(self.payment_provider_mandate_id.reference)
+ if mandate:
+ invoices = self.invoice_ids.filtered(
+ lambda i: i.invoice_date == date_ref
+ )
+ if not invoices:
+ self.generate_invoice()
+ unpaid_invoice = self.invoice_ids.filtered(
+ lambda i: i.invoice_date == date_ref
+ and i.payment_state == "not_paid"
)
- if stage != closed_stage:
- vals["stage_id"]: closed_stage.id
- self.write(vals)
- msg = _(
- "The mollie subscription for this subscription has been terminated on %(cancelled_date)s",
- cancelled_date=cancelled_date,
+ else:
+ unpaid_invoice = invoices.filtered(
+ lambda i: i.payment_state == "not_paid"
)
- self.sudo().message_post(body=msg)
- subscription_payments = subscription.payments.list()
- if subscription_payments and subscription_payments.get("_embedded"):
- payment_list = subscription_payments["_embedded"].get(
- "payments", []
+ if unpaid_invoice:
+ payment_transaction_obj._process_payment_provider_recurring_payment(
+ self, unpaid_invoice
)
- for payment in payment_list:
- payment_transaction_obj._process_payment_provider_subscription_recurring_payment(
- self, payment
- )
return True
@api.model
- def terminate_payment_provider_subscription(self):
- # This method terminates the subscription on mollie
- if self.payment_provider_subscription_id.provider_id.code != "mollie":
- return super().terminate_payment_provider_subscription()
+ def terminate_payment_provider_mandate(self):
+ # This method terminates the mandate on mollie
+ if self.payment_provider_mandate_id.provider_id.code != "mollie":
+ return super().terminate_payment_provider_mandate()
else:
- vals = super().terminate_payment_provider_subscription()
+ vals = super().terminate_payment_provider_mandate()
mollie = self.env.ref("payment.payment_provider_mollie")
mollie_client = mollie._api_mollie_get_client()
customer = mollie_client.customers.get(self.partner_id.mollie_customer_id)
- subscription = customer.subscriptions.delete(
- self.payment_provider_subscription_id.reference
+ customer.mandates.delete(self.payment_provider_mandate_id.reference)
+ cancelled_date = fields.Date.context_today(self)
+ msg = _(
+ "The mollie mandate for this subscription has been terminated on %(cancelled_date)s",
+ cancelled_date=cancelled_date,
)
- if subscription:
- cancelled_date = False
- if "canceledAt" in subscription.keys():
- cancelled_date = datetime.strptime(
- subscription.get("canceledAt")[0:19], "%Y-%m-%dT%H:%M:%S"
- )
- msg = _(
- "The mollie subscription for this subscription has been terminated on %(cancelled_date)s",
- cancelled_date=cancelled_date,
- )
- self.sudo().message_post(body=msg)
- vals["is_payment_provider_subscription_terminated"] = True
+ self.sudo().message_post(body=msg)
+ vals["is_payment_provider_mandate_terminated"] = True
self.write(vals)
return True