Browse Source
[ADD] bond and loan issues management
[ADD] bond and loan issues management
[ADD] bond and loan issues management module skeleton [IMP] change increase menu sequence [IMP] add models, fields and views [IMP] add xml declaration in head of file [ADD] add easy_my_coop_loan_website - WIP [IMP] add access rights [IMP] this raise inconsistency so replace id by default_code. [IMP] change import openerp to odoo [IMP] add website loan module [FIX] put website display in loan [FIX] fix import [FIX] fix function [IMP] use correct name [IMP] make the loan and bond visible [IMP] add js, field and logic to set amount limit per subscription [IMP] remove dependency on recaptcha as user is logged to subscribe [IMP] add fields [IMP] save loan issue subscription still in WIP [IMP] remove alert pop up [IMP] add dependency to easy_my_coop_website [IMP] remove force send for sub request creation email notification [IMP] add mail templates [IMP] save subscription in the corresponding loan issue. add email notif [FIX] fix loan issue line view [FIX] add related field to loan issue. It is where the data stand [IMP] move term_view up [FIX] fix js error when false is returned [FIX] fix function when loan_issue_id in None [IMP] add actions and button [FIX] fix action [FIX] fix mail template [IMP] set noupdate=1 [IMP] change order [IMP] display loan issue lines on partner form [IMP] add loan view in partner form [IMP] add face value on loan issue and line add face value on loan issue and line. add as well the quantity and computation of the amount [FIX] missing id overriding values wasn't working [IMP] getting bond face value and setting it as step. [IMP] subscribed_amount computed field is the sum of the amount lines [IMP] allow a waiting payment to be cancelled [IMP] make field required [REFACT] move loan issue line code to dedicated file [IMP] add interest calculation and model [ADD] bond and loan issues management module skeleton [IMP] add models, fields and views [IMP] allow creation by hand [IMP] adding partner related field [IMP] put code in separate function [FIX] pass it to get method [IMP] routes consistent form [FIX] fix eof [FIX] GET is working for ajax call [IMP] website page for loan issue subscriptionpull/24/head
houssine
5 years ago
committed by
robin.keunen
27 changed files with 968 additions and 23 deletions
-
2easy_my_coop/models/coop.py
-
28easy_my_coop/views/email_template_view.xml
-
3easy_my_coop/views/operation_request_view.xml
-
1easy_my_coop/views/product_view.xml
-
1easy_my_coop/views/res_company_view.xml
-
2easy_my_coop/views/res_partner_view.xml
-
4easy_my_coop/views/subscription_request_view.xml
-
1easy_my_coop_loan/__init__.py
-
27easy_my_coop_loan/__manifest__.py
-
112easy_my_coop_loan/data/mail_template_data.xml
-
4easy_my_coop_loan/models/__init__.py
-
59easy_my_coop_loan/models/interest_line.py
-
186easy_my_coop_loan/models/loan.py
-
95easy_my_coop_loan/models/loan_issue_line.py
-
9easy_my_coop_loan/models/partner.py
-
9easy_my_coop_loan/security/ir.model.access.csv
-
163easy_my_coop_loan/views/loan_view.xml
-
23easy_my_coop_loan/views/partner_view.xml
-
40easy_my_coop_loan/views/term_view.xml
-
1easy_my_coop_loan_website/__init__.py
-
26easy_my_coop_loan_website/__manifest__.py
-
1easy_my_coop_loan_website/controllers/__init__.py
-
93easy_my_coop_loan_website/controllers/main.py
-
16easy_my_coop_loan_website/data/website_loan_data.xml
-
23easy_my_coop_loan_website/static/src/js/loan_issue.js
-
54easy_my_coop_loan_website/template/loan_issue_template.xml
-
8easy_my_coop_website/controllers/main.py
@ -1,16 +1,16 @@ |
|||||
|
<?xml version="1.0" encoding="utf-8"?> |
||||
<odoo> |
<odoo> |
||||
<data> |
|
||||
<menuitem name="Configuration" id="menu_easy_my_coop_config" parent="menu_main_easy_my_coop" sequence="20"/> |
|
||||
|
|
||||
<record model="ir.actions.act_window" id="action_easy_my_coop_email_templates"> |
|
||||
<field name="name">Mail Templates</field> |
|
||||
<field name="res_model">mail.template</field> |
|
||||
<field name="view_type">form</field> |
|
||||
<field name="view_mode">form,tree</field> |
|
||||
<field name="view_id" ref="mail.email_template_tree" /> |
|
||||
<field name="search_view_id" ref="mail.view_email_template_search"/> |
|
||||
</record> |
|
||||
|
|
||||
<menuitem id="menu_easy_my_coop_templates" parent="menu_easy_my_coop_config" action="action_easy_my_coop_email_templates" sequence="10" groups="group_easy_my_coop_manager"/> |
|
||||
</data> |
|
||||
|
<menuitem name="Configuration" id="menu_easy_my_coop_config" parent="menu_main_easy_my_coop" sequence="80" /> |
||||
|
|
||||
|
<record model="ir.actions.act_window" |
||||
|
id="action_easy_my_coop_email_templates"> |
||||
|
<field name="name">Mail Templates</field> |
||||
|
<field name="res_model">mail.template</field> |
||||
|
<field name="view_type">form</field> |
||||
|
<field name="view_mode">form,tree</field> |
||||
|
<field name="view_id" ref="mail.email_template_tree" /> |
||||
|
<field name="search_view_id" ref="mail.view_email_template_search" /> |
||||
|
</record> |
||||
|
|
||||
|
<menuitem id="menu_easy_my_coop_templates" parent="menu_easy_my_coop_config" action="action_easy_my_coop_email_templates" sequence="10" groups="group_easy_my_coop_manager" /> |
||||
</odoo> |
</odoo> |
@ -0,0 +1 @@ |
|||||
|
from . import models |
@ -0,0 +1,27 @@ |
|||||
|
# Copyright 2019 Coop IT Easy SCRLfs (<http://www.coopiteasy.be>) |
||||
|
# - Houssine BAKKALI - <houssine@coopiteasy.be> |
||||
|
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html). |
||||
|
|
||||
|
{ |
||||
|
"name": "Easy My Coop Bond and Subordinated Loan Issues", |
||||
|
"version": "12.0.1.0.1", |
||||
|
"depends": [ |
||||
|
"easy_my_coop", |
||||
|
], |
||||
|
"author": "Coop IT Easy SCRLfs", |
||||
|
"category": "Cooperative management", |
||||
|
"website": "http://www.coopiteasy.be", |
||||
|
"license": "AGPL-3", |
||||
|
"description": """ |
||||
|
This module allows to manage the bonds and subordinated loans subscription |
||||
|
life cycle. |
||||
|
""", |
||||
|
'data': [ |
||||
|
'security/ir.model.access.csv', |
||||
|
'views/term_view.xml', |
||||
|
'views/loan_view.xml', |
||||
|
'views/partner_view.xml', |
||||
|
'data/mail_template_data.xml', |
||||
|
], |
||||
|
'installable': True, |
||||
|
} |
@ -0,0 +1,112 @@ |
|||||
|
<?xml version="1.0" encoding="utf-8"?> |
||||
|
<odoo> |
||||
|
<!-- Mail template are declared in a NOUPDATE block |
||||
|
so users can freely customize/delete them --> |
||||
|
<data noupdate="1"> |
||||
|
<!--<data>--> |
||||
|
<record id="loan_subscription_confirmation" model="mail.template"> |
||||
|
<field name="name">Loan Subscription Confirmation Email</field> |
||||
|
<field name="email_from">${(object.company_id.coop_email_contact or object.loan_issue_id.user_id.email)|safe}</field> |
||||
|
<field name="subject">${object.company_id.name} Loan subscription confirmation (Ref ${object.loan_issue_id.name or 'n/a'})</field> |
||||
|
<field name="email_to">${object.partner_id.email}</field> |
||||
|
<field name="reply_to">${(object.company_id.coop_email_contact or object.loan_issue_id.user_id.email)|safe}</field> |
||||
|
<field name="model_id" ref="easy_my_coop_loan.model_loan_issue_line"/> |
||||
|
<field name="auto_delete" eval="True"/> |
||||
|
<field name="lang">${object.partner_id.lang}</field> |
||||
|
<field name="body_html"><![CDATA[ |
||||
|
<div style="font-family: 'Lucica Grande', Ubuntu, Arial, Verdana, sans-serif; font-size: 12px; color: rgb(34, 34, 34); background-color: #FFF; "> |
||||
|
|
||||
|
<p>Hello ${object.partner_id.name},</p> |
||||
|
|
||||
|
<p>Your request will be soon processed by our team. If all the provided info are correct you will soon receive the payment information in another email</p> |
||||
|
|
||||
|
<br/> |
||||
|
<p>If you have any question, do not hesitate to contact us.</p> |
||||
|
<br/> |
||||
|
|
||||
|
<p>Sustainably your,</p> |
||||
|
<p>${object.company_id.name}.</p> |
||||
|
|
||||
|
% if object.company_id.street: |
||||
|
${object.company_id.street} |
||||
|
% endif |
||||
|
% if object.company_id.street2: |
||||
|
${object.company_id.street2}<br/> |
||||
|
% endif |
||||
|
% if object.company_id.city or object.company_id.zip: |
||||
|
${object.company_id.zip} ${object.company_id.city}<br/> |
||||
|
% endif |
||||
|
% if object.company_id.country_id: |
||||
|
${object.company_id.state_id and ('%s, ' % object.company_id.state_id.name) or ''} ${object.company_id.country_id.name or ''}<br/> |
||||
|
% endif |
||||
|
% if object.company_id.phone: |
||||
|
Phone: ${object.company_id.phone} |
||||
|
% endif |
||||
|
|
||||
|
% if object.company_id.website: |
||||
|
<div> |
||||
|
Web : <a href="${object.company_id.website}">${object.company_id.website}</a> |
||||
|
</div> |
||||
|
%endif |
||||
|
|
||||
|
<div> |
||||
|
<img src=${object.company_id.logo_url}> |
||||
|
</div> |
||||
|
</div> |
||||
|
]]></field> |
||||
|
</record> |
||||
|
<!--Request the payment of the subscribed loan issue --> |
||||
|
<record id="loan_issue_payment_request" model="mail.template"> |
||||
|
<field name="name">Loan Issue Payment Request - Send by Email</field> |
||||
|
<field name="email_from">${(object.company_id.coop_email_contact or object.loan_issue_id.user_id.email)|safe}</field> |
||||
|
<field name="subject">${object.company_id.name} Payment request (Ref ${object.loan_issue_id.name or 'n/a'})</field> |
||||
|
<field name="partner_to">${object.partner_id.id}</field> |
||||
|
<field name="reply_to">${(object.company_id.coop_email_contact or object.loan_issue_id.user_id.email)|safe}</field> |
||||
|
<field name="model_id" ref="easy_my_coop_loan.model_loan_issue_line"/> |
||||
|
<field name="auto_delete" eval="True"/> |
||||
|
<field name="lang">${object.partner_id.lang}</field> |
||||
|
<field name="body_html"><![CDATA[ |
||||
|
<div style="font-family: 'Lucica Grande', Ubuntu, Arial, Verdana, sans-serif; font-size: 12px; color: rgb(34, 34, 34); background-color: #FFF; "> |
||||
|
|
||||
|
<p>Hello ${object.partner_id.name},</p> |
||||
|
|
||||
|
<p>Find here after the necessary information for the payment. We kindly remind you that your subscription will be effective only once we received the payment.</p> |
||||
|
|
||||
|
<p>Amount: ${object.amount} ${object.loan_issue_id.company_currency_id.symbol}</p> |
||||
|
<p>Account number: ${object.company_id.partner_id.bank_ids[0].sanitized_acc_number}</p> |
||||
|
<p>Communication: ${object.loan_issue_id.name} + ${object.partner_id.name}</p> |
||||
|
|
||||
|
<p>Sustainably your,</p> |
||||
|
<p>${object.company_id.name}.</p> |
||||
|
|
||||
|
% if object.company_id.street: |
||||
|
${object.company_id.street} |
||||
|
% endif |
||||
|
% if object.company_id.street2: |
||||
|
${object.company_id.street2}<br/> |
||||
|
% endif |
||||
|
% if object.company_id.city or object.company_id.zip: |
||||
|
${object.company_id.zip} ${object.company_id.city}<br/> |
||||
|
% endif |
||||
|
% if object.company_id.country_id: |
||||
|
${object.company_id.state_id and ('%s, ' % object.company_id.state_id.name) or ''} ${object.company_id.country_id.name or ''}<br/> |
||||
|
% endif |
||||
|
% if object.company_id.phone: |
||||
|
Phone: ${object.company_id.phone} |
||||
|
% endif |
||||
|
|
||||
|
% if object.company_id.website: |
||||
|
<div> |
||||
|
Web : <a href="${object.company_id.website}">${object.company_id.website}</a> |
||||
|
</div> |
||||
|
%endif |
||||
|
|
||||
|
<div> |
||||
|
<img src=${object.company_id.logo_url}> |
||||
|
</div> |
||||
|
</div> |
||||
|
]]></field> |
||||
|
</record> |
||||
|
|
||||
|
</data> |
||||
|
</odoo> |
@ -0,0 +1,4 @@ |
|||||
|
from . import loan |
||||
|
from . import loan_issue_line |
||||
|
from . import interest_line |
||||
|
from . import partner |
@ -0,0 +1,59 @@ |
|||||
|
from odoo import fields, models |
||||
|
|
||||
|
|
||||
|
class LoanInterestLine(models.Model): |
||||
|
_name = 'loan.interest.line' |
||||
|
|
||||
|
name = fields.Integer(string="Year", |
||||
|
required=True) |
||||
|
issue_line = fields.Many2one('loan.issue.line', |
||||
|
string="Subscribed loan", |
||||
|
required=True) |
||||
|
partner_id = fields.Many2one(related='issue_line.partner_id', |
||||
|
store=True, |
||||
|
readlonly=True) |
||||
|
amount = fields.Monetary(related='issue_line.amount', |
||||
|
string="Subscribed amount", |
||||
|
currency_field='company_currency_id', |
||||
|
readonly=True) |
||||
|
interest = fields.Monetary(string="Gross interest amount", |
||||
|
currency_field='company_currency_id', |
||||
|
readonly=True) |
||||
|
net_interest = fields.Monetary(string="Net interest amount", |
||||
|
currency_field='company_currency_id', |
||||
|
readonly=True) |
||||
|
taxes_rate = fields.Float(string="Taxes on interest", |
||||
|
required=True) |
||||
|
taxes_amount = fields.Monetary(string="Taxes amount", |
||||
|
currency_field='company_currency_id', |
||||
|
readonly=True) |
||||
|
accrued_amount = fields.Monetary(string="Accrued amount", |
||||
|
currency_field='company_currency_id', |
||||
|
readonly=True) |
||||
|
accrued_interest = fields.Monetary(string="Accrued gross interest", |
||||
|
currency_field='company_currency_id', |
||||
|
readonly=True) |
||||
|
accrued_net_interest = fields.Monetary( |
||||
|
string="Accrued net interest", |
||||
|
currency_field='company_currency_id', |
||||
|
readonly=True) |
||||
|
accrued_taxes = fields.Monetary(string="Accrued taxes to pay", |
||||
|
currency_field='company_currency_id', |
||||
|
readonly=True) |
||||
|
due_date = fields.Date(string="Due date") |
||||
|
company_currency_id = fields.Many2one('res.currency', |
||||
|
related='company_id.currency_id', |
||||
|
string="Company Currency", |
||||
|
readonly=True) |
||||
|
company_id = fields.Many2one('res.company', |
||||
|
related='issue_line.company_id', |
||||
|
string="Company", |
||||
|
readonly=True) |
||||
|
state = fields.Selection([('draft', 'Draft'), |
||||
|
('due', 'Due'), |
||||
|
('requested', 'Payment requested'), |
||||
|
('donation', 'Donation'), |
||||
|
('paid', 'Paid') |
||||
|
], |
||||
|
string="State", |
||||
|
default="draft") |
@ -0,0 +1,186 @@ |
|||||
|
import logging |
||||
|
|
||||
|
from odoo import api, fields, models |
||||
|
|
||||
|
_logger = logging.getLogger(__name__) |
||||
|
|
||||
|
|
||||
|
class LoanTerm(models.Model): |
||||
|
_name = 'loan.term' |
||||
|
|
||||
|
name = fields.Char(string="Name", |
||||
|
required=True) |
||||
|
term = fields.Float(string="Term", |
||||
|
required=True) |
||||
|
|
||||
|
|
||||
|
class LoanIssue(models.Model): |
||||
|
_name = 'loan.issue' |
||||
|
|
||||
|
@api.multi |
||||
|
def _compute_subscribed_amount(self): |
||||
|
for issue in self: |
||||
|
susbscribed_amount = 0.0 |
||||
|
for line in issue.loan_issue_lines.filtered( |
||||
|
lambda record: record.state != 'cancelled'): |
||||
|
susbscribed_amount += line.amount |
||||
|
issue.subscribed_amount = susbscribed_amount |
||||
|
|
||||
|
name = fields.Char(string="Name") |
||||
|
is_bond = fields.Boolean(string="Is a bond issue?") |
||||
|
is_loan = fields.Boolean(string="Is a subordinated loan issue?") |
||||
|
default_issue = fields.Boolean(string="Default issue") |
||||
|
subscription_start_date = fields.Date(string="Start date") |
||||
|
subscription_end_date = fields.Date(string="End date") |
||||
|
user_id = fields.Many2one('res.users', |
||||
|
string="Responsible") |
||||
|
term_date = fields.Date(string="Term date") |
||||
|
rate = fields.Float(string="Interest rate") |
||||
|
face_value = fields.Monetary(string="Facial value", |
||||
|
currency_field='company_currency_id', |
||||
|
required=True) |
||||
|
minimum_amount = fields.Monetary(string="Minimum amount", |
||||
|
currency_field='company_currency_id') |
||||
|
maximum_amount = fields.Monetary(string="Maximum amount", |
||||
|
currency_field='company_currency_id') |
||||
|
maximum_amount_per_sub = fields.Monetary( |
||||
|
string="Maximum amount per subscription", |
||||
|
currency_field='company_currency_id') |
||||
|
subscribed_amount = fields.Monetary(string="Subscribed amount", |
||||
|
compute="_compute_subscribed_amount", |
||||
|
currency_field='company_currency_id') |
||||
|
interest_payment = fields.Selection([('end', 'End'), |
||||
|
('yearly', 'Yearly')], |
||||
|
string="Interest payment") |
||||
|
term = fields.Many2one('loan.term', |
||||
|
string="term of the loan") |
||||
|
loan_issue_lines = fields.One2many('loan.issue.line', |
||||
|
'loan_issue_id', |
||||
|
string="Loan issue lines") |
||||
|
state = fields.Selection([('draft', 'Draft'), |
||||
|
('confirmed', 'Confirmed'), |
||||
|
('cancelled', 'Cancelled'), |
||||
|
('ongoing', 'Ongoing'), |
||||
|
('closed', 'Closed')], |
||||
|
string="State", |
||||
|
default='draft') |
||||
|
company_currency_id = fields.Many2one('res.currency', |
||||
|
related='company_id.currency_id', |
||||
|
string="Company Currency", |
||||
|
readonly=True) |
||||
|
company_id = fields.Many2one('res.company', |
||||
|
string='Company', |
||||
|
required=True, |
||||
|
readonly=True, |
||||
|
default=lambda self: self.env['res.company']._company_default_get()) #noqa |
||||
|
by_company = fields.Boolean(string="By company") |
||||
|
by_individual = fields.Boolean(string='By individuals') |
||||
|
display_on_website = fields.Boolean(sting='Display on website') |
||||
|
taxes_rate = fields.Float(string="Taxes on interest", |
||||
|
required=True) |
||||
|
|
||||
|
@api.multi |
||||
|
def toggle_display(self): |
||||
|
for loan_issue in self: |
||||
|
loan_issue.display_on_website = not loan_issue.display_on_website |
||||
|
|
||||
|
@api.multi |
||||
|
def get_web_loan_issues(self, is_company): |
||||
|
loan_issues = self.search([ |
||||
|
('is_loan', '=', True), |
||||
|
('display_on_website', '=', True), |
||||
|
('state', '=', 'ongoing') |
||||
|
]) |
||||
|
if is_company is True: |
||||
|
return loan_issues.filtered('by_company') |
||||
|
else: |
||||
|
return loan_issues.filtered('by_individual') |
||||
|
|
||||
|
@api.multi |
||||
|
def get_web_bond_issues(self, is_company): |
||||
|
bond_issues = self.search([ |
||||
|
('is_bond', '=', True), |
||||
|
('display_on_website', '=', True), |
||||
|
('state', '=', 'ongoing') |
||||
|
]) |
||||
|
if is_company is True: |
||||
|
return bond_issues.filtered('by_company') |
||||
|
else: |
||||
|
return bond_issues.filtered('by_company') |
||||
|
|
||||
|
@api.multi |
||||
|
def get_web_issues(self, is_company): |
||||
|
issues = self.get_web_loan_issues(is_company) |
||||
|
issues = issues + self.get_web_bond_issues(is_company) |
||||
|
return issues |
||||
|
|
||||
|
@api.multi |
||||
|
def action_confirm(self): |
||||
|
self.ensure_one() |
||||
|
self.write({'state': 'confirmed'}) |
||||
|
|
||||
|
@api.multi |
||||
|
def action_open(self): |
||||
|
self.ensure_one() |
||||
|
self.write({'state': 'ongoing'}) |
||||
|
|
||||
|
@api.multi |
||||
|
def action_draft(self): |
||||
|
self.ensure_one() |
||||
|
self.write({'state': 'draft'}) |
||||
|
|
||||
|
@api.multi |
||||
|
def action_cancel(self): |
||||
|
self.ensure_one() |
||||
|
self.write({'state': 'cancelled'}) |
||||
|
|
||||
|
@api.multi |
||||
|
def action_close(self): |
||||
|
self.ensure_one() |
||||
|
self.write({'state': 'closed'}) |
||||
|
|
||||
|
def get_interest_vals(self, line, vals): |
||||
|
interest_obj = self.env['loan.interest.line'] |
||||
|
accrued_amount = line.amount |
||||
|
accrued_interest = 0 |
||||
|
accrued_net_interest = 0 |
||||
|
accrued_taxes = 0 |
||||
|
for year in range(1, int(self.term.term) + 1): |
||||
|
interest = accrued_amount * (line.loan_issue_id.rate / 100) |
||||
|
accrued_amount += interest |
||||
|
taxes_amount = interest * (self.taxes_rate / 100) |
||||
|
net_interest = interest - taxes_amount |
||||
|
accrued_interest += interest |
||||
|
accrued_net_interest += net_interest |
||||
|
accrued_taxes += taxes_amount |
||||
|
vals['interest'] = interest |
||||
|
vals['net_interest'] = net_interest |
||||
|
vals['taxes_amount'] = taxes_amount |
||||
|
vals['accrued_amount'] = accrued_amount |
||||
|
vals['accrued_interest'] = accrued_interest |
||||
|
vals['accrued_net_interest'] = accrued_net_interest |
||||
|
vals['accrued_taxes'] = accrued_taxes |
||||
|
vals['name'] = year |
||||
|
interest_obj.create(vals) |
||||
|
|
||||
|
@api.multi |
||||
|
def compute_loan_interest(self): |
||||
|
self.ensure_one() |
||||
|
|
||||
|
if self.interest_payment == 'end': |
||||
|
due_date = self.term_date |
||||
|
for line in self.loan_issue_lines: |
||||
|
# TODO remove this line |
||||
|
line.interest_lines.unlink() |
||||
|
# Please Do not Forget |
||||
|
vals = { |
||||
|
'issue_line': line.id, |
||||
|
'due_date': due_date, |
||||
|
'taxes_rate': self.taxes_rate |
||||
|
} |
||||
|
self.get_interest_vals(line, vals) |
||||
|
|
||||
|
rounded_term = int(self.term.term) |
||||
|
if self.term.term - rounded_term > 0: |
||||
|
# TODO Handle this case |
||||
|
_logger.info("todo") |
@ -0,0 +1,95 @@ |
|||||
|
|
||||
|
from datetime import datetime |
||||
|
|
||||
|
from odoo import api, fields, models |
||||
|
|
||||
|
|
||||
|
class LoanIssueLine(models.Model): |
||||
|
_name = 'loan.issue.line' |
||||
|
_order = 'date desc, id' |
||||
|
|
||||
|
@api.multi |
||||
|
@api.depends('quantity', 'face_value') |
||||
|
def _compute_amount(self): |
||||
|
for line in self: |
||||
|
line.amount = line.face_value * line.quantity |
||||
|
|
||||
|
name = fields.Char(string="Reference") |
||||
|
loan_issue_id = fields.Many2one('loan.issue', |
||||
|
string="Loan issue", |
||||
|
required=True) |
||||
|
interest_lines = fields.One2many('loan.interest.line', |
||||
|
'issue_line', |
||||
|
string="Interest lines") |
||||
|
quantity = fields.Integer(string='quantity', |
||||
|
required=True) |
||||
|
face_value = fields.Monetary(related='loan_issue_id.face_value', |
||||
|
currency_field='company_currency_id', |
||||
|
store=True, |
||||
|
readonly=True) |
||||
|
partner_id = fields.Many2one('res.partner', |
||||
|
string="Subscriber", |
||||
|
required=True) |
||||
|
date = fields.Date(string="Subscription date", |
||||
|
default=lambda self: datetime.strftime(datetime.now(), |
||||
|
'%Y-%m-%d'), |
||||
|
required=True) |
||||
|
amount = fields.Monetary(string="Subscribed amount", |
||||
|
currency_field='company_currency_id', |
||||
|
compute='_compute_amount', |
||||
|
store=True) |
||||
|
state = fields.Selection([('draft', 'Draft'), |
||||
|
('subscribed', 'Subscribed'), |
||||
|
('waiting', 'Waiting payment'), |
||||
|
('paid', 'paid'), |
||||
|
('cancelled', 'Cancelled'), |
||||
|
('ended', 'Ended')], |
||||
|
string="State", |
||||
|
required=True, |
||||
|
default="draft") |
||||
|
company_currency_id = fields.Many2one('res.currency', |
||||
|
related='company_id.currency_id', |
||||
|
string="Company Currency", |
||||
|
readonly=True) |
||||
|
company_id = fields.Many2one('res.company', |
||||
|
related='loan_issue_id.company_id', |
||||
|
string="Company", |
||||
|
readonly=True) |
||||
|
|
||||
|
def create(self, vals): |
||||
|
mail_template = 'easy_my_coop_loan.loan_subscription_confirmation' |
||||
|
confirmation_mail_template = self.env.ref(mail_template, False) |
||||
|
|
||||
|
line = super(LoanIssueLine, self).create(vals) |
||||
|
confirmation_mail_template.send_mail(line.id) |
||||
|
|
||||
|
return line |
||||
|
|
||||
|
@api.multi |
||||
|
def action_draft(self): |
||||
|
for line in self: |
||||
|
line.write({'state': 'draft'}) |
||||
|
|
||||
|
@api.multi |
||||
|
def action_validate(self): |
||||
|
for line in self: |
||||
|
line.write({'state': 'subscribed'}) |
||||
|
|
||||
|
@api.multi |
||||
|
def action_request_payment(self): |
||||
|
mail_template = 'easy_my_coop_loan.loan_issue_payment_request' |
||||
|
pay_req_mail_template = self.env.ref(mail_template, False) |
||||
|
|
||||
|
for line in self: |
||||
|
pay_req_mail_template.send_mail(line.id) |
||||
|
line.write({'state': 'waiting'}) |
||||
|
|
||||
|
@api.multi |
||||
|
def action_cancel(self): |
||||
|
for line in self: |
||||
|
line.write({'state': 'cancelled'}) |
||||
|
|
||||
|
@api.multi |
||||
|
def action_paid(self): |
||||
|
for line in self: |
||||
|
line.write({'state': 'paid'}) |
@ -0,0 +1,9 @@ |
|||||
|
from odoo import fields, models |
||||
|
|
||||
|
|
||||
|
class ResPartner(models.Model): |
||||
|
_inherit = 'res.partner' |
||||
|
|
||||
|
loan_line_ids = fields.One2many('loan.issue.line', |
||||
|
'partner_id', |
||||
|
string="Name") |
@ -0,0 +1,9 @@ |
|||||
|
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink |
||||
|
access_loan_issue_user,loan.issue,model_loan_issue,base.group_user,1,0,0,0 |
||||
|
access_loan_issue_manager,loan.issue,model_loan_issue,easy_my_coop.group_easy_my_coop_manager,1,1,1,0 |
||||
|
access_loan_issue_line_user,loan.issue.line,model_loan_issue_line,base.group_user,1,0,0,0 |
||||
|
access_loan_issue_line_manager,loan.issue.line,model_loan_issue_line,easy_my_coop.group_easy_my_coop_manager,1,1,1,0 |
||||
|
access_loan_term_user,loan.term,model_loan_term,base.group_user,1,0,0,0 |
||||
|
access_loan_term_manager,loan.term,model_loan_term,easy_my_coop.group_easy_my_coop_manager,1,1,1,0 |
||||
|
access_loan_interest_line_user,loan.interest.line,model_loan_interest_line,base.group_user,1,0,0,0 |
||||
|
access_loan_interest_line_manager,loan.interest.line,model_loan_interest_line,easy_my_coop.group_easy_my_coop_manager,1,1,1,1 |
@ -0,0 +1,163 @@ |
|||||
|
<?xml version="1.0" encoding="utf-8"?> |
||||
|
<odoo> |
||||
|
<menuitem name="Loan Issue" id="menu_easy_my_coop_main_loan_issue" parent="easy_my_coop.menu_main_easy_my_coop" sequence="20" groups="easy_my_coop.group_easy_my_coop_user"/> |
||||
|
<record id="view_loan_issue_tree" model="ir.ui.view"> |
||||
|
<field name="name">loan.issue.tree</field> |
||||
|
<field name="model">loan.issue</field> |
||||
|
<field name="arch" type="xml"> |
||||
|
<tree string="Loan issues"> |
||||
|
<field name="name" /> |
||||
|
<field name="subscription_start_date" /> |
||||
|
<field name="subscription_end_date" /> |
||||
|
<field name="term_date" /> |
||||
|
<field name="term" /> |
||||
|
<field name="rate" /> |
||||
|
<field name="minimum_amount" /> |
||||
|
<field name="maximum_amount" /> |
||||
|
<field name="subscribed_amount" /> |
||||
|
<field name="user_id" /> |
||||
|
<field name="state" /> |
||||
|
</tree> |
||||
|
</field> |
||||
|
</record> |
||||
|
|
||||
|
<record id="view_loan_issue_form" model="ir.ui.view"> |
||||
|
<field name="name">loan.issue.form</field> |
||||
|
<field name="model">loan.issue</field> |
||||
|
<field name="arch" type="xml"> |
||||
|
<form string="Loan issue"> |
||||
|
<header> |
||||
|
<button name="action_confirm" string="Confirm" type="object" states="draft" |
||||
|
groups="easy_my_coop.group_easy_my_coop_manager"/> |
||||
|
<button name="action_cancel" string="Cancel" type="object" states="draft,ongoing" |
||||
|
confirm="Are you sure you want to cancel this loan issue?" |
||||
|
groups="easy_my_coop.group_easy_my_coop_manager"/> |
||||
|
<button name="action_open" string="Open" type="object" |
||||
|
states="confirmed" groups="easy_my_coop.group_easy_my_coop_manager"/> |
||||
|
<button name="action_close" string="Close" type="object" states="ongoing" |
||||
|
confirm="Are you sure you want to close this loan issue?" |
||||
|
groups="easy_my_coop.group_easy_my_coop_manager"/> |
||||
|
<button name="action_draft" string="Set to draft" |
||||
|
type="object" states="confirmed,cancelled" |
||||
|
groups="easy_my_coop.group_easy_my_coop_manager"/> |
||||
|
<button name="compute_loan_interest" string="Compute interest" |
||||
|
type="object" states="closed,ongoing" |
||||
|
groups="easy_my_coop.group_easy_my_coop_manager"/> |
||||
|
|
||||
|
<field name="state" widget="statusbar" statusbar_visible="draft,confirmed,ongoing,closed"/> |
||||
|
</header> |
||||
|
<sheet> |
||||
|
<div class="oe_button_box" name="button_box"> |
||||
|
<button name="toggle_display" type="object" |
||||
|
class="oe_stat_button" icon="fa-globe"> |
||||
|
<field name="display_on_website" widget="website_button"/> |
||||
|
</button> |
||||
|
</div> |
||||
|
<group> |
||||
|
<group> |
||||
|
<field name="name" /> |
||||
|
<field name="is_loan" /> |
||||
|
<field name="is_bond" /> |
||||
|
<field name="default_issue" /> |
||||
|
<field name="face_value" /> |
||||
|
<field name="minimum_amount" /> |
||||
|
<field name="maximum_amount" /> |
||||
|
<field name="maximum_amount_per_sub" /> |
||||
|
<field name="subscribed_amount" /> |
||||
|
<field name="by_individual" /> |
||||
|
<field name="by_company" /> |
||||
|
</group> |
||||
|
<group> |
||||
|
<field name="user_id" widget="selection" /> |
||||
|
<field name="rate" /> |
||||
|
<field name="taxes_rate" /> |
||||
|
<field name="subscription_start_date" /> |
||||
|
<field name="subscription_end_date" /> |
||||
|
<field name="term_date" /> |
||||
|
<field name="term" widget="selection"/> |
||||
|
<field name="interest_payment" widget="selection" /> |
||||
|
</group> |
||||
|
</group> |
||||
|
<notebook> |
||||
|
<page string="Lines"> |
||||
|
<field name="loan_issue_lines"> |
||||
|
<tree delete="false"> |
||||
|
<field name="name" /> |
||||
|
<field name="partner_id" /> |
||||
|
<field name="date" /> |
||||
|
<field name="quantity" /> |
||||
|
<field name="face_value" /> |
||||
|
<field name="amount" /> |
||||
|
<field name="state" /> |
||||
|
</tree> |
||||
|
</field> |
||||
|
</page> |
||||
|
</notebook> |
||||
|
</sheet> |
||||
|
</form> |
||||
|
</field> |
||||
|
</record> |
||||
|
|
||||
|
<record id="action_loan_issue" model="ir.actions.act_window"> |
||||
|
<field name="name">Loan issue</field> |
||||
|
<field name="type">ir.actions.act_window</field> |
||||
|
<field name="res_model">loan.issue</field> |
||||
|
<field name="view_type">form</field> |
||||
|
<field name="view_mode">tree,form</field> |
||||
|
</record> |
||||
|
|
||||
|
<menuitem action="action_loan_issue" id="loan_issue_menu" parent="menu_easy_my_coop_main_loan_issue" sequence="25" /> |
||||
|
|
||||
|
<record id="view_loan_issue_line_form" model="ir.ui.view"> |
||||
|
<field name="name">loan.issue.line.form</field> |
||||
|
<field name="model">loan.issue.line</field> |
||||
|
<field name="arch" type="xml"> |
||||
|
<form string="Loan issue"> |
||||
|
<header> |
||||
|
<button name="action_validate" string="Validate" |
||||
|
type="object" states="draft" /> |
||||
|
<button name="action_request_payment" string="Request Payment" |
||||
|
type="object" states="subscribed" /> |
||||
|
<button name="action_cancel" string="Cancel" type="object" |
||||
|
states="draft,subscribed,waiting" |
||||
|
confirm="Are you sure you want to cancel this loan subscription ?" /> |
||||
|
<button name="action_draft" string="Set to draft" |
||||
|
type="object" states="cancelled" /> |
||||
|
<button name="action_paid" string="Paid" |
||||
|
type="object" states="waiting" /> |
||||
|
<field name="state" widget="statusbar" /> |
||||
|
</header> |
||||
|
<sheet> |
||||
|
<group> |
||||
|
<group> |
||||
|
<field name="name" /> |
||||
|
<field name="quantity" /> |
||||
|
<field name="face_value" /> |
||||
|
</group> |
||||
|
<group> |
||||
|
<field name="date" /> |
||||
|
<field name="partner_id" /> |
||||
|
<field name="amount" /> |
||||
|
</group> |
||||
|
</group> |
||||
|
<notebook> |
||||
|
<page string="Interst lines"> |
||||
|
<field name="interest_lines"> |
||||
|
<tree delete="false" create="false"> |
||||
|
<field name="name" /> |
||||
|
<field name="amount" /> |
||||
|
<field name="accrued_amount" /> |
||||
|
<field name="interest" /> |
||||
|
<field name="net_interest" /> |
||||
|
<field name="taxes_amount" /> |
||||
|
<field name="due_date" /> |
||||
|
<field name="state" /> |
||||
|
</tree> |
||||
|
</field> |
||||
|
</page> |
||||
|
</notebook> |
||||
|
</sheet> |
||||
|
</form> |
||||
|
</field> |
||||
|
</record> |
||||
|
</odoo> |
@ -0,0 +1,23 @@ |
|||||
|
<odoo> |
||||
|
<record id="view_partner_form_loan_issue" model="ir.ui.view"> |
||||
|
<field name="name">res.partner.form.loan.issue</field> |
||||
|
<field name="model">res.partner</field> |
||||
|
<field name="inherit_id" ref="easy_my_coop.view_partner_form_easy_my_coop"/> |
||||
|
<field name="arch" type="xml"> |
||||
|
<page name="share_subscription" position="after"> |
||||
|
<page string="Loan issue lines" name="loan_issue_lines" groups="easy_my_coop.group_easy_my_coop_user"> |
||||
|
<field name="loan_line_ids"> |
||||
|
<tree create="false" delete="false" edit="false"> |
||||
|
<field name="loan_issue_id"/> |
||||
|
<field name="date"/> |
||||
|
<field name="quantity"/> |
||||
|
<field name="face_value"/> |
||||
|
<field name="amount"/> |
||||
|
<field name="state"/> |
||||
|
</tree> |
||||
|
</field> |
||||
|
</page> |
||||
|
</page> |
||||
|
</field> |
||||
|
</record> |
||||
|
</odoo> |
@ -0,0 +1,40 @@ |
|||||
|
<?xml version="1.0" encoding="utf-8"?> |
||||
|
<odoo> |
||||
|
<record id="view_loan_term_tree" model="ir.ui.view"> |
||||
|
<field name="name">loan.term.tree</field> |
||||
|
<field name="model">loan.term</field> |
||||
|
<field name="arch" type="xml"> |
||||
|
<tree string="Loan terms"> |
||||
|
<field name="name" /> |
||||
|
<field name="term" /> |
||||
|
</tree> |
||||
|
</field> |
||||
|
</record> |
||||
|
|
||||
|
<record id="view_loan_term_form" model="ir.ui.view"> |
||||
|
<field name="name">loan.term.form</field> |
||||
|
<field name="model">loan.term</field> |
||||
|
<field name="arch" type="xml"> |
||||
|
<form string="Loan terms"> |
||||
|
<group> |
||||
|
<group> |
||||
|
<field name="name" /> |
||||
|
</group> |
||||
|
<group> |
||||
|
<field name="term" /> |
||||
|
</group> |
||||
|
</group> |
||||
|
</form> |
||||
|
</field> |
||||
|
</record> |
||||
|
|
||||
|
<record id="action_loan_term" model="ir.actions.act_window"> |
||||
|
<field name="name">Loan term</field> |
||||
|
<field name="type">ir.actions.act_window</field> |
||||
|
<field name="res_model">loan.term</field> |
||||
|
<field name="view_type">form</field> |
||||
|
<field name="view_mode">tree,form</field> |
||||
|
</record> |
||||
|
|
||||
|
<menuitem action="action_loan_term" id="loan_term_menu" parent="easy_my_coop.menu_easy_my_coop_config" sequence="5" /> |
||||
|
</odoo> |
@ -0,0 +1 @@ |
|||||
|
from . import controllers |
@ -0,0 +1,26 @@ |
|||||
|
# Copyright 2019 Coop IT Easy SCRLfs (<http://www.coopiteasy.be>) |
||||
|
# - Houssine BAKKALI - <houssine@coopiteasy.be> |
||||
|
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html). |
||||
|
|
||||
|
{ |
||||
|
"name": "Easy My Coop Loan Issues Website", |
||||
|
"version": "12.0.1.0.1", |
||||
|
"depends": [ |
||||
|
"easy_my_coop_loan", |
||||
|
"easy_my_coop_website", |
||||
|
"website", |
||||
|
], |
||||
|
"author": "Coop IT Easy SCRLfs", |
||||
|
"category": "Cooperative management", |
||||
|
"website": "http://www.coopiteasy.be", |
||||
|
"license": "AGPL-3", |
||||
|
"description": """ |
||||
|
This module implements the subscription page for bonds and |
||||
|
subordinated loans. |
||||
|
""", |
||||
|
'data': [ |
||||
|
'data/website_loan_data.xml', |
||||
|
'template/loan_issue_template.xml' |
||||
|
], |
||||
|
'installable': True, |
||||
|
} |
@ -0,0 +1 @@ |
|||||
|
from . import main |
@ -0,0 +1,93 @@ |
|||||
|
from odoo import http |
||||
|
from odoo.http import request |
||||
|
|
||||
|
from odoo.tools.translate import _ |
||||
|
|
||||
|
|
||||
|
class WebsiteLoanIssueSubscription(http.Controller): |
||||
|
|
||||
|
@http.route(['/subscription/get_loan_issue'], |
||||
|
type='json', |
||||
|
auth="user", |
||||
|
methods=['POST'], website=True) |
||||
|
def get_loan_issue(self, loan_issue_id, **kw): |
||||
|
loan_issue_obj = request.env['loan.issue'] |
||||
|
if loan_issue_id: |
||||
|
loan_issue = loan_issue_obj.sudo().browse(int(loan_issue_id)) |
||||
|
return { |
||||
|
loan_issue.id: { |
||||
|
'max_amount': loan_issue.maximum_amount_per_sub, |
||||
|
'face_value': loan_issue.face_value, |
||||
|
} |
||||
|
} |
||||
|
else: |
||||
|
return False |
||||
|
|
||||
|
@http.route(['/subscription/loan_issue_form'], |
||||
|
type='http', auth="user", website=True) |
||||
|
def display_loan_issue_subscription_page(self, **kwargs): |
||||
|
values = {} |
||||
|
partner = request.env.user.partner_id |
||||
|
is_company = partner.is_company |
||||
|
|
||||
|
values = self.fill_values(values, is_company) |
||||
|
values.update(kwargs=kwargs.items()) |
||||
|
return request.render( |
||||
|
"easy_my_coop_loan_website.loanissuesubscription", |
||||
|
values) |
||||
|
|
||||
|
def get_loan_issues(self, is_company): |
||||
|
loan_obj = request.env['loan.issue'] |
||||
|
loan_issues = loan_obj.sudo().get_web_issues(is_company) |
||||
|
|
||||
|
return loan_issues |
||||
|
|
||||
|
def fill_values(self, values, is_company): |
||||
|
company = request.website.company_id |
||||
|
loan_issues = self.get_loan_issues(is_company) |
||||
|
|
||||
|
values['loan_issues'] = loan_issues |
||||
|
values['company'] = company |
||||
|
|
||||
|
if not values.get('loan_issue_id'): |
||||
|
for loan_issue in loan_issues: |
||||
|
if loan_issue.default_issue is True: |
||||
|
values['loan_issue_id'] = loan_issue.id |
||||
|
break |
||||
|
if not values.get('loan_issue_id', False) and loan_issues: |
||||
|
values['loan_issue_id'] = loan_issues[0].id |
||||
|
|
||||
|
return values |
||||
|
|
||||
|
def validation(self, loan_issue, kwargs): |
||||
|
sub_amount = kwargs.get('subscription_amount') |
||||
|
redirect = "easy_my_coop_loan_website.loanissuesubscription" |
||||
|
|
||||
|
values = {} |
||||
|
if not loan_issue: |
||||
|
values["error_msg"] = _("The selected loan issue is not found") |
||||
|
return request.render(redirect, values) |
||||
|
if sub_amount: |
||||
|
values["error_msg"] = _("The amount shoud be of monetary type") |
||||
|
return request.render(redirect, values) |
||||
|
return True |
||||
|
|
||||
|
@http.route(['/subscription/subscribe_loan_issue'], |
||||
|
type='http', |
||||
|
auth="user", website=True) |
||||
|
def loan_issue_subscription(self, **kwargs): |
||||
|
loan_obj = request.env['loan.issue'] |
||||
|
loan_obj_line = request.env['loan.issue.line'] |
||||
|
|
||||
|
loan_issue = loan_obj.sudo().browse(kwargs.get('loan_issue_id')) |
||||
|
partner = request.env.user.partner_id |
||||
|
|
||||
|
if self.validation(loan_issue, kwargs): |
||||
|
values = { |
||||
|
'loan_issue_id': loan_issue.id, |
||||
|
'partner_id': partner.id, |
||||
|
'amount': kwargs['subscription_amount'], |
||||
|
'state': 'subscribed' |
||||
|
} |
||||
|
loan_obj_line.sudo().create(values) |
||||
|
return request.render("easy_my_coop_website.cooperator_thanks", values) |
@ -0,0 +1,16 @@ |
|||||
|
<?xml version="1.0" encoding="utf-8"?> |
||||
|
<odoo> |
||||
|
<data> |
||||
|
<record id="menu_subscribeloanissue" model="website.menu"> |
||||
|
<field name="name">Subscribe to loan issue</field> |
||||
|
<field name="url">/subscription/loan_issue_form</field> |
||||
|
<field name="parent_id" ref="website.main_menu"/> |
||||
|
<field name="sequence" type="int">65</field> |
||||
|
</record> |
||||
|
<record id="subscribe_loan_issue_page" model="website.page"> |
||||
|
<field name="website_published">True</field> |
||||
|
<field name="url">/subscription/loan_issue_form</field> |
||||
|
<field name="view_id" ref="menu_subscribeloanissue"/> |
||||
|
</record> |
||||
|
</data> |
||||
|
</odoo> |
@ -0,0 +1,23 @@ |
|||||
|
odoo.define('easy_my_coop_loan_website.oe_easymy_coop_loan', function (require) { |
||||
|
$(document).ready(function () { |
||||
|
"use strict"; |
||||
|
var ajax = require('web.ajax'); |
||||
|
|
||||
|
$('.oe_easymy_coop_loan').each(function () { |
||||
|
var oe_easymy_coop_loan = this; |
||||
|
$('#loan_issue').change(function () { |
||||
|
var loan_issue_id = $("#loan_issue").val(); |
||||
|
ajax.jsonRpc("/subscription/get_loan_issue", 'call', { |
||||
|
'loan_issue_id': loan_issue_id |
||||
|
}) |
||||
|
.then(function (data) { |
||||
|
if (data !== false) { |
||||
|
$("#subscription_amount").prop('max',data[loan_issue_id].maximum_amount_per_sub); |
||||
|
$("#subscription_amount").prop('step',data[loan_issue_id].face_value); |
||||
|
} |
||||
|
}); |
||||
|
}); |
||||
|
$('#loan_issue').trigger('change'); |
||||
|
}); |
||||
|
}); |
||||
|
}); |
@ -0,0 +1,54 @@ |
|||||
|
<?xml version="1.0" encoding="utf-8"?> |
||||
|
<odoo> |
||||
|
<template id="assets_frontend" inherit_id="web.assets_frontend" name="Coop"> |
||||
|
<xpath expr="." position="inside"> |
||||
|
<script type="text/javascript" src="/easy_my_coop_loan_website/static/src/js/loan_issue.js"></script> |
||||
|
</xpath> |
||||
|
</template> |
||||
|
|
||||
|
<template id="loanissuesubscription" name="Loan Issue Subscription"> |
||||
|
<t t-call="website.layout"> |
||||
|
<div id="wrap"> |
||||
|
<div class="oe_structure"/> |
||||
|
<div class="container oe_easymy_coop_loan"> |
||||
|
<h2 class="energie">Subscribe to Loan Issue</h2><br/> |
||||
|
<div class="row"> |
||||
|
<div class="col-md-8"> |
||||
|
<form action="/subscription/subscribe_loan_issue" method="post" class="form-horizontal mt32" enctype="multipart/form-data"> |
||||
|
<p style="color:red;"><t t-esc="error_msg"/></p> |
||||
|
<input type="hidden" name="csrf_token" t-att-value="request.csrf_token()"/> |
||||
|
|
||||
|
<div t-attf-class="form-group #{error and 'loan_issue_id' in error and 'has-error' or ''}"> |
||||
|
<label class="col-md-3 col-sm-4 control-label" style="width:25%" for="share_product_id">Loan issue</label> |
||||
|
<select id="loan_issue" name="loan_issue_id" class="col-md-7 col-sm-8 form-control" style="width:54%;margin-left:15px"> |
||||
|
<t t-foreach="loan_issues or []" t-as="loan_issue"> |
||||
|
<option t-att-value="loan_issue.id" t-att-selected="loan_issue.id == int(loan_issue_id)"><t t-esc="loan_issue.name"/></option> |
||||
|
</t> |
||||
|
</select> |
||||
|
</div> |
||||
|
<div t-attf-class="form-group #{error and 'subscription_amount' in error and 'has-error' or ''}"> |
||||
|
<label class="col-md-3 col-sm-4 control-label" style="width:25%" for="subscription_amount">Amount</label> |
||||
|
<input id="subscription_amount" type="number" class="col-md-7 col-sm-8 form-control total" name="subscription_amount" min="0" step="100" max="5000"/> |
||||
|
</div> |
||||
|
<table style="margin-left:195px"> |
||||
|
<tr> |
||||
|
<!--<td width="80%"> |
||||
|
<div class="g-recaptcha" t-att-data-sitekey="website.recaptcha_key_site" data-theme="green"/><br/> |
||||
|
</td>--> |
||||
|
<td> |
||||
|
<div class="form-group"> |
||||
|
<div class="col-md-offset-3 col-sm-offset-4 col-sm-8 col-md-7"> |
||||
|
<button class="btn btn-primary btn-lg">Send</button> |
||||
|
</div> |
||||
|
</div> |
||||
|
</td> |
||||
|
</tr> |
||||
|
</table> |
||||
|
</form> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
</t> |
||||
|
</template> |
||||
|
</odoo> |
Write
Preview
Loading…
Cancel
Save
Reference in new issue