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

Update website_sale_recurring_payment modules #13

Closed
Closed
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
27 changes: 14 additions & 13 deletions website_sale_recurring_payment/__manifest__.py
Original file line number Diff line number Diff line change
@@ -1,17 +1,18 @@
{
"name": "Website Sale - Recurring Payment",
"version": "16.0.0.1",
"category": "eCommerce",
"author": "Onestein",
"website": "https://www.onestein.nl",
"license": "LGPL-3",
"summary": "Website Sale - Recurring Payment",
"depends": ["contract", "payment", "product_contract", "website_sale"],
"data": [
'name': 'Website Sale - Recurring Payment',
'version': '16.0.0.1',
'category': 'eCommerce',
'license': 'LGPL-3',
'summary': 'Website Sale - Recurring Payment',
'depends': [
"subscription_oca",
"website_sale"
],
'data': [
"security/ir.model.access.csv",
"data/update_contract_payment_subscription_cron.xml",
"data/terminate_provider_subscription_cron.xml",
"views/contract_view.xml",
"views/payment_provider.xml",
"data/update_payment_provider_subscription_cron.xml",
"data/terminate_payment_provider_subscription_cron.xml",
"views/sale_subscription_view.xml",
"views/payment_provider_view.xml",
],
}
9 changes: 4 additions & 5 deletions website_sale_recurring_payment/controllers/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,13 @@


class WebsiteSale(WebsiteSale):

def _get_shop_payment_values(self, order, **kwargs):
"""
show only payment methods who allow for recurring payment, if the order is a contract
show only payment methods who allow for recurring payment, if the order is a subscription
"""
values = super(WebsiteSale, self)._get_shop_payment_values(order, **kwargs)
if order:
if order.is_contract:
values["providers"] = values["providers"].filtered(
lambda x: x.allows_recurring_payment
)
if order.group_subscription_lines():
values['providers'] = values['providers'].filtered(lambda x: x.allows_recurring_payment)
return values
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<?xml version="1.0" encoding="utf-8" ?>
<odoo noupdate="1">
<record model="ir.cron" id="terminate_payment_provider_subscription_for_sale_subscription_cron">
<field name="name">Terminate Payment Provider Subscription for Subscriptions</field>
<field name="model_id" ref="subscription_oca.model_sale_subscription" />
<field name="state">code</field>
<field name="code">model.cron_terminate_payment_provider_subscriptions()</field>
<field name="user_id" ref="base.user_root" />
<field name="interval_number">1</field>
<field name="interval_type">days</field>
<field name="numbercall">-1</field>
<field eval="False" name="doall" />
</record>
</odoo>
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<?xml version="1.0" encoding="utf-8" ?>
<odoo noupdate="1">
<record model="ir.cron" id="update_payment_provider_subscription_for_sale_subscription_cron">
<field name="name">Update Payment Provider Subscription for Subscriptions</field>
<field name="model_id" ref="subscription_oca.model_sale_subscription" />
<field name="state">code</field>
<field name="code">model.cron_update_payment_provider_subscriptions()</field>
<field name="user_id" ref="base.user_root" />
<field name="interval_number">1</field>
<field name="interval_type">days</field>
<field name="numbercall">-1</field>
<field eval="False" name="doall" />
</record>
</odoo>
6 changes: 3 additions & 3 deletions website_sale_recurring_payment/models/__init__.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
from . import contract
from . import contract_line
from . import contract_payment_subscription
from . import sale_subscription
from . import sale_subscription_line
from . import payment_provider_subscription
from . import payment_provider
from . import payment_transaction
3 changes: 1 addition & 2 deletions website_sale_recurring_payment/models/payment_provider.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@


class PaymentProvider(models.Model):
_inherit = "payment.provider"
_inherit = 'payment.provider'

allows_recurring_payment = fields.Boolean()
payment_mode_id = fields.Many2one("account.payment.mode")
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
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
payments for sale subscriptions
"""

_name = "payment.provider.subscription"
_description = "Payment Provider Subscription"
_rec_name = "reference"

reference = fields.Char(
string="Reference", help="The reference of the subscription", readonly=True,
required=True)
payment_transaction_ids = fields.One2many("payment.transaction",
"payment_provider_subscription_id",
string="Payment Transactions",
readonly=True)
provider_id = fields.Many2one(string="Provider", comodel_name='payment.provider', required=True)

_sql_constraints = [
("reference_uniq", "unique(reference)", "Reference must be unique!"),
]
122 changes: 51 additions & 71 deletions website_sale_recurring_payment/models/payment_transaction.py
Original file line number Diff line number Diff line change
@@ -1,120 +1,100 @@
from datetime import timedelta, date
from dateutil.relativedelta import relativedelta

from odoo import fields, models


class PaymentTransaction(models.Model):
_inherit = "payment.transaction"
_inherit = 'payment.transaction'

contract_payment_subscription_id = fields.Many2one(
"contract.payment.subscription",
string="Contract Payment Subscription",
readonly=True,
)
payment_provider_subscription_id = fields.Many2one("payment.provider.subscription",
string="Payment Provider Subscription",
readonly=True)

def _process_notification_data(self, data):
# If the transaction concerns a contract SO, which was not processed yet and which doesn't have a related contract yet,
# If the transaction concerns a subscription SO, which was not processed yet and which doesn't have a related subscription yet,
# depending on the data we receive (to be interpreted specifically for the provider of the transaction) we may want to
# get it confirmed and create a contract (functionality to create a contract from the SO is provided in OCA module product_contract).
# get it confirmed and create a subscription (functionality to create a subscription from the SO is provided in OCA module subscription_oca).
self.ensure_one()
if (
self.sale_order_ids
and self.sale_order_ids[0].is_contract
and not self.sale_order_ids[0].contract_count
):
if self.sale_order_ids and self.sale_order_ids[0].group_subscription_lines() and not self.sale_order_ids[0].subscriptions_count:
payment_data = self._provider_get_payment_data()
if self._must_create_contract(payment_data):
self.sale_order_ids[0].action_create_contract()
contract = self.sale_order_ids[0].mapped("order_line.contract_id")[0]
contract.line_recurrence = True
contract.contract_line_ids.date_end = False
subscription = self._create_provider_subscription(payment_data)
contract_payment_subscription = (
self._create_contract_payment_subscription(subscription)
)
contract.contract_payment_subscription_id = (
contract_payment_subscription.id
)
self.contract_payment_subscription_id = contract_payment_subscription.id
invoice = contract.recurring_create_invoice()
if self._must_create_subscription(payment_data):
sale_order = self.sale_order_ids[0]
sale_order.action_confirm()
subscription = sale_order.subscription_ids[0]
invoice = sale_order._create_invoices()
subscription.invoice_ids = [(4, invoice.id)]

Check warning on line 26 in website_sale_recurring_payment/models/payment_transaction.py

View check run for this annotation

Codecov / codecov/patch

website_sale_recurring_payment/models/payment_transaction.py#L22-L26

Added lines #L22 - L26 were not covered by tests
self.invoice_ids = [(6, 0, invoice.ids)]
subscription_for_payment_provider = self._create_subscription_for_payment_provider(subscription,

Check warning on line 28 in website_sale_recurring_payment/models/payment_transaction.py

View check run for this annotation

Codecov / codecov/patch

website_sale_recurring_payment/models/payment_transaction.py#L28

Added line #L28 was not covered by tests
payment_data)
payment_provider_subscription = self._create_payment_provider_subscription(subscription_for_payment_provider)
subscription.payment_provider_subscription_id = payment_provider_subscription.id
self.payment_provider_subscription_id = payment_provider_subscription.id

Check warning on line 32 in website_sale_recurring_payment/models/payment_transaction.py

View check run for this annotation

Codecov / codecov/patch

website_sale_recurring_payment/models/payment_transaction.py#L30-L32

Added lines #L30 - L32 were not covered by tests
return super(PaymentTransaction, self)._process_notification_data(data)

def _provider_get_payment_data(self):
self.ensure_one()
return {}

def _must_create_contract(self, data):
def _must_create_subscription(self, data):
# This method needs to be extended in each provider module
self.ensure_one()
return False

def _create_provider_subscription(self, payment_data):
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 from the provider implementation) describing the provider subscription
# We expect to return a data structure (depending on the payment provider implementation) describing the payment provider subscription
self.ensure_one()
return {}
return None

Check warning on line 49 in website_sale_recurring_payment/models/payment_transaction.py

View check run for this annotation

Codecov / codecov/patch

website_sale_recurring_payment/models/payment_transaction.py#L49

Added line #L49 was not covered by tests

def _create_contract_payment_subscription(self, subscription):
def _create_payment_provider_subscription(self, subscription):
# This method needs to be extended in each provider module.
# We expect to receive the provider subscription;
# This method processes them in order to create an Odoo contract.payment.subscription
# 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["contract.payment.subscription"]
return self.env['payment.provider.subscription']

Check warning on line 56 in website_sale_recurring_payment/models/payment_transaction.py

View check run for this annotation

Codecov / codecov/patch

website_sale_recurring_payment/models/payment_transaction.py#L56

Added line #L56 was not covered by tests

def _process_subscription_recurring_payment(self, contract, payment):
def _process_payment_provider_subscription_recurring_payment(self, subscription, payment):
# This method needs to be extended in each provider module.
# This method should process payment transaction(recurring payment) for contract invoices
payment_transaction = self._get_payment_transaction(contract, payment)
done_payment_transaction = (
payment_transaction.update_state_recurring_payment_transaction(
contract.contract_payment_subscription_id.provider_id, payment
)
)
# 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(

Check warning on line 62 in website_sale_recurring_payment/models/payment_transaction.py

View check run for this annotation

Codecov / codecov/patch

website_sale_recurring_payment/models/payment_transaction.py#L61-L62

Added lines #L61 - L62 were not covered by tests
subscription.payment_provider_subscription_id.provider_id, payment)
if done_payment_transaction:
contract_invoices = contract._get_related_invoices()
unpaid_invoice = self.env["account.move"]
for invoice in contract_invoices:
if invoice.payment_state == "not_paid":
unpaid_invoice = invoice
continue
unpaid_invoices = subscription.invoice_ids.filtered(lambda i: i.payment_state == 'not_paid')
unpaid_invoice = unpaid_invoices and unpaid_invoices[0]

Check warning on line 66 in website_sale_recurring_payment/models/payment_transaction.py

View check run for this annotation

Codecov / codecov/patch

website_sale_recurring_payment/models/payment_transaction.py#L66

Added line #L66 was not covered by tests
if not unpaid_invoice:
unpaid_invoice = contract.recurring_create_invoice()
subscription.generate_invoice()

Check warning on line 68 in website_sale_recurring_payment/models/payment_transaction.py

View check run for this annotation

Codecov / codecov/patch

website_sale_recurring_payment/models/payment_transaction.py#L68

Added line #L68 was not covered by tests
unpaid_invoice = subscription.invoice_ids.filtered(lambda i: i.payment_state == 'not_paid')[0]
done_payment_transaction.invoice_ids = [(6, 0, unpaid_invoice.ids)]
done_payment_transaction._reconcile_after_done()
return None

def _get_payment_transaction(self, contract, payment):
def _get_payment_transaction(self, subscription, payment):
# 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"]
return self.env['payment.transaction']

Check warning on line 77 in website_sale_recurring_payment/models/payment_transaction.py

View check run for this annotation

Codecov / codecov/patch

website_sale_recurring_payment/models/payment_transaction.py#L77

Added line #L77 was not covered by tests

def _prepare_vals_for_recurring_payment_transaction_for_subscription(
self, provider_reference, amount, contract, currency
):
def _prepare_vals_for_recurring_payment_transaction_for_subscription(self, provider_reference, amount, subscription,
currency):
# This method should return the vals for creating payment transactions
vals = {
"amount": amount,
"currency_id": currency.id or contract.currency_id.id,
"currency_id": currency.id or subscription.currency_id.id,
"provider_reference": provider_reference,
"partner_id": contract.partner_id.id,
"contract_payment_subscription_id": contract.contract_payment_subscription_id.id,
"provider_id": contract.contract_payment_subscription_id.provider_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
}
return vals

def update_state_recurring_payment_transaction(self, provider, payment):
def update_state_recurring_payment_transaction(self,provider , payment):
# This method needs to be extended in each provider module.
# This method should update the state of payment transactions and return done payment transactions if any
return self.env["payment.transaction"]
return self.env['payment.transaction']

Check warning on line 95 in website_sale_recurring_payment/models/payment_transaction.py

View check run for this annotation

Codecov / codecov/patch

website_sale_recurring_payment/models/payment_transaction.py#L95

Added line #L95 was not covered by tests

def _get_payment_transaction_by_provider_reference(
self, provider_reference, provider_id
):
def _get_payment_transaction_by_provider_reference(self, provider_reference, provider_id):
# This method should search for payment transaction with provider reference provided
return self.search(
[
("provider_reference", "=", provider_reference),
("provider_id", "=", provider_id),
],
limit=1,
)
return self.search([('provider_reference', '=', provider_reference), (

Check warning on line 99 in website_sale_recurring_payment/models/payment_transaction.py

View check run for this annotation

Codecov / codecov/patch

website_sale_recurring_payment/models/payment_transaction.py#L99

Added line #L99 was not covered by tests
'provider_id', '=', provider_id)], limit=1)
Loading
Loading