init
62
.gitignore
vendored
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
# sphinx build directories
|
||||||
|
_build/
|
||||||
|
|
||||||
|
# dotfiles
|
||||||
|
|
||||||
|
.*
|
||||||
|
!.gitignore
|
||||||
|
!.github
|
||||||
|
!.gitea
|
||||||
|
!.mailmap
|
||||||
|
# compiled python files
|
||||||
|
*.py[co]
|
||||||
|
__pycache__/
|
||||||
|
# setup.py egg_info
|
||||||
|
*.egg-info
|
||||||
|
# emacs backup files
|
||||||
|
*~
|
||||||
|
# hg stuff
|
||||||
|
*.orig
|
||||||
|
status
|
||||||
|
# odoo filestore
|
||||||
|
odoo/filestore
|
||||||
|
# maintenance migration scripts
|
||||||
|
odoo/addons/base/maintenance
|
||||||
|
# window installation config file
|
||||||
|
/odoo.conf
|
||||||
|
/*.conf
|
||||||
|
# generated for windows installer?
|
||||||
|
install/win32/*.bat
|
||||||
|
install/win32/meta.py
|
||||||
|
|
||||||
|
# needed only when building for win32
|
||||||
|
setup/win32/static/less/
|
||||||
|
setup/win32/static/wkhtmltopdf/
|
||||||
|
setup/win32/static/postgresql*.exe
|
||||||
|
|
||||||
|
# js tooling
|
||||||
|
node_modules
|
||||||
|
jsconfig.json
|
||||||
|
tsconfig.json
|
||||||
|
package-lock.json
|
||||||
|
package.json
|
||||||
|
.husky
|
||||||
|
# various virtualenv
|
||||||
|
/bin/
|
||||||
|
/build/
|
||||||
|
/dist/
|
||||||
|
/include/
|
||||||
|
/lib/
|
||||||
|
/man/
|
||||||
|
/share/
|
||||||
|
/src/
|
||||||
|
/deployment/postgresql/*
|
||||||
|
/venv*/
|
||||||
|
/deployment/backup/*.zip
|
||||||
|
/extra-addons/
|
||||||
|
*.pyc
|
||||||
|
/pragtech_hotel_management_addons/
|
||||||
|
pragtech_hotel_management_addons
|
||||||
|
*cache.json
|
||||||
|
odoo_backups
|
||||||
|
*.log
|
@ -26,7 +26,6 @@ class LoanTypes(models.Model):
|
|||||||
"""Create different types of Loans, And can wisely choose while requesting
|
"""Create different types of Loans, And can wisely choose while requesting
|
||||||
for loan"""
|
for loan"""
|
||||||
_name = 'loan.type'
|
_name = 'loan.type'
|
||||||
_inherit = ['mail.thread']
|
|
||||||
_description = 'Loan Type'
|
_description = 'Loan Type'
|
||||||
|
|
||||||
name = fields.Char(string='Name', help="LoanType Name", required=True)
|
name = fields.Char(string='Name', help="LoanType Name", required=True)
|
||||||
|
@ -43,7 +43,7 @@ class ResPartner(models.Model):
|
|||||||
'type': 'ir.actions.act_window',
|
'type': 'ir.actions.act_window',
|
||||||
'name': 'Loans',
|
'name': 'Loans',
|
||||||
'view_mode': 'tree',
|
'view_mode': 'tree',
|
||||||
'res_model': 'loan.request',
|
'res_model': 'loan.request',
|
||||||
'domain': [('partner_id', '=', self.id)],
|
'domain': [('partner_id', '=', self.id)],
|
||||||
'context': "{'create': False}"
|
'context': "{'create': False}"
|
||||||
}
|
}
|
||||||
|
@ -2,4 +2,5 @@
|
|||||||
|
|
||||||
from . import controllers
|
from . import controllers
|
||||||
from . import models
|
from . import models
|
||||||
from . import wizard
|
from . import security
|
||||||
|
|
||||||
|
@ -18,7 +18,7 @@ Long description of module's purpose
|
|||||||
'version': '0.1',
|
'version': '0.1',
|
||||||
|
|
||||||
# any module necessary for this one to work correctly
|
# any module necessary for this one to work correctly
|
||||||
'depends': ['base'],
|
'depends': ['base','contacts'],
|
||||||
|
|
||||||
# always loaded
|
# always loaded
|
||||||
'data': [
|
'data': [
|
||||||
|
@ -7,7 +7,6 @@ class MyReport(models.AbstractModel):
|
|||||||
def _get_report_values(self, docids, data=None):
|
def _get_report_values(self, docids, data=None):
|
||||||
# Lấy tất cả bản ghi employee.profile
|
# Lấy tất cả bản ghi employee.profile
|
||||||
docs = self.env['employee.profile'].browse(docids)
|
docs = self.env['employee.profile'].browse(docids)
|
||||||
|
|
||||||
return {
|
return {
|
||||||
'doc_model': 'employee.profile',
|
'doc_model': 'employee.profile',
|
||||||
'docs': docs,
|
'docs': docs,
|
||||||
|
@ -7,7 +7,6 @@
|
|||||||
<field name="description">Access rights for employee management</field>
|
<field name="description">Access rights for employee management</field>
|
||||||
<field name="sequence">10</field>
|
<field name="sequence">10</field>
|
||||||
</record>
|
</record>
|
||||||
|
|
||||||
<!-- Admin Group -->
|
<!-- Admin Group -->
|
||||||
<record id="group_employee_admin" model="res.groups">
|
<record id="group_employee_admin" model="res.groups">
|
||||||
<field name="name">Employee Admin</field>
|
<field name="name">Employee Admin</field>
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
|
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
|
||||||
access_employee_profile_user,employee.profile,model_employee_profile,employee_management.group_employee_user,1,0,0,0
|
access_employee_profile_user,employee.profile,model_employee_profile,employee_management.group_employee_user,1,1,1,1
|
||||||
access_employee_profile_admin,employee.profile,model_employee_profile,employee_management.group_employee_admin,1,1,1,1
|
access_employee_profile_admin,employee.profile,model_employee_profile,employee_management.group_employee_admin,1,1,1,1
|
||||||
access_add_employee_wizard_user,add.employee.wizard,model_add_employee_wizard,employee_management.group_employee_user,0,0,0,0
|
access_add_employee_wizard_user,add.employee.wizard,model_add_employee_wizard,employee_management.group_employee_user,1,1,1,1
|
||||||
access_add_employee_wizard_admin,add.employee.wizard,model_add_employee_wizard,employee_management.group_employee_admin,1,1,1,1
|
access_add_employee_wizard_admin,add.employee.wizard,model_add_employee_wizard,employee_management.group_employee_admin,1,1,1,1
|
||||||
|
|
5
loan_management/__init__.py
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
from . import controllers
|
||||||
|
from . import models
|
||||||
|
from . import wizards
|
46
loan_management/__manifest__.py
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
{
|
||||||
|
'name': "loan_management",
|
||||||
|
|
||||||
|
'summary': "Short (1 phrase/line) summary of the module's purpose",
|
||||||
|
|
||||||
|
'description': """
|
||||||
|
Long description of module's purpose
|
||||||
|
""",
|
||||||
|
|
||||||
|
'author': "My Company",
|
||||||
|
'website': "https://www.yourcompany.com",
|
||||||
|
|
||||||
|
# Categories can be used to filter modules in modules listing
|
||||||
|
# Check https://github.com/odoo/odoo/blob/15.0/odoo/addons/base/data/ir_module_category_data.xml
|
||||||
|
# for the full list
|
||||||
|
'category': 'Finance',
|
||||||
|
'version': '0.1',
|
||||||
|
|
||||||
|
# any module necessary for this one to work co rrectly
|
||||||
|
'depends': ['base','contacts','web'],
|
||||||
|
|
||||||
|
# always loaded
|
||||||
|
'data': [
|
||||||
|
"security/ir.model.access.csv",
|
||||||
|
'data/loan_sequence.xml',
|
||||||
|
'views/loan_type_views.xml',
|
||||||
|
'views/menu_items.xml',
|
||||||
|
'views/loan_borrower_view.xml',
|
||||||
|
'views/loan_interest_policy_views.xml',
|
||||||
|
'views/loan_request_view.xml',
|
||||||
|
],
|
||||||
|
"assets": {
|
||||||
|
"web.assets_backend": [
|
||||||
|
"loan_management/static/src/xml/res_config_edition.xml",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
|
||||||
|
# only loaded in demonstration mode
|
||||||
|
'demo': [
|
||||||
|
'demo/demo.xml',
|
||||||
|
],
|
||||||
|
"installable": True,
|
||||||
|
"application": True,
|
||||||
|
}
|
||||||
|
|
3
loan_management/controllers/__init__.py
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
from . import controllers
|
22
loan_management/controllers/controllers.py
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# from odoo import http
|
||||||
|
|
||||||
|
|
||||||
|
# class LoanManagement(http.Controller):
|
||||||
|
# @http.route('/loan_management/loan_management', auth='public')
|
||||||
|
# def index(self, **kw):
|
||||||
|
# return "Hello, world"
|
||||||
|
|
||||||
|
# @http.route('/loan_management/loan_management/objects', auth='public')
|
||||||
|
# def list(self, **kw):
|
||||||
|
# return http.request.render('loan_management.listing', {
|
||||||
|
# 'root': '/loan_management/loan_management',
|
||||||
|
# 'objects': http.request.env['loan_management.loan_management'].search([]),
|
||||||
|
# })
|
||||||
|
|
||||||
|
# @http.route('/loan_management/loan_management/objects/<model("loan_management.loan_management"):obj>', auth='public')
|
||||||
|
# def object(self, obj, **kw):
|
||||||
|
# return http.request.render('loan_management.object', {
|
||||||
|
# 'object': obj
|
||||||
|
# })
|
||||||
|
|
14
loan_management/data/loan_sequence.xml
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
<odoo>
|
||||||
|
<data noupdate="1">
|
||||||
|
|
||||||
|
<record id="seq_loan_contract" model="ir.sequence">
|
||||||
|
<field name="name">Loan Contract Sequence</field>
|
||||||
|
<field name="code">loan.contract</field>
|
||||||
|
<field name="prefix">HĐ%(year)s</field>
|
||||||
|
<field name="padding">4</field>
|
||||||
|
<field name="number_next">1</field>
|
||||||
|
<field name="number_increment">1</field>
|
||||||
|
</record>
|
||||||
|
|
||||||
|
</data>
|
||||||
|
</odoo>
|
30
loan_management/demo/demo.xml
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
<odoo>
|
||||||
|
<data>
|
||||||
|
<!--
|
||||||
|
<record id="object0" model="loan_management.loan_management">
|
||||||
|
<field name="name">Object 0</field>
|
||||||
|
<field name="value">0</field>
|
||||||
|
</record>
|
||||||
|
|
||||||
|
<record id="object1" model="loan_management.loan_management">
|
||||||
|
<field name="name">Object 1</field>
|
||||||
|
<field name="value">10</field>
|
||||||
|
</record>
|
||||||
|
|
||||||
|
<record id="object2" model="loan_management.loan_management">
|
||||||
|
<field name="name">Object 2</field>
|
||||||
|
<field name="value">20</field>
|
||||||
|
</record>
|
||||||
|
|
||||||
|
<record id="object3" model="loan_management.loan_management">
|
||||||
|
<field name="name">Object 3</field>
|
||||||
|
<field name="value">30</field>
|
||||||
|
</record>
|
||||||
|
|
||||||
|
<record id="object4" model="loan_management.loan_management">
|
||||||
|
<field name="name">Object 4</field>
|
||||||
|
<field name="value">40</field>
|
||||||
|
</record>
|
||||||
|
-->
|
||||||
|
</data>
|
||||||
|
</odoo>
|
0
loan_management/models/ repayment_schedule.py
Normal file
5
loan_management/models/__init__.py
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
from . import loan_type
|
||||||
|
from . import borrower
|
||||||
|
from . import loan_interest_policy
|
||||||
|
from . import loan_request
|
19
loan_management/models/borrower.py
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
from odoo import models, fields
|
||||||
|
|
||||||
|
class ResPartner(models.Model):
|
||||||
|
_inherit = 'res.partner'
|
||||||
|
is_borrower = fields.Boolean(string='Is Borrower',default=True)
|
||||||
|
gender = fields.Selection([
|
||||||
|
('male', 'Male'),
|
||||||
|
('female', 'Female'),
|
||||||
|
('other', 'Other')
|
||||||
|
], string='Gender')
|
||||||
|
date_of_birth = fields.Date(string='Date of Birth')
|
||||||
|
job = fields.Char(string='Occupation')
|
||||||
|
monthly_income = fields.Float(string='Monthly Income')
|
||||||
|
marital_status = fields.Selection([
|
||||||
|
('single', 'Single'),
|
||||||
|
('married', 'Married'),
|
||||||
|
('divorced', 'Divorced'),
|
||||||
|
('widowed', 'Widowed'),
|
||||||
|
], string='Marital Status')
|
176
loan_management/models/loan_contract.py
Normal file
@ -0,0 +1,176 @@
|
|||||||
|
from odoo import models, fields, api
|
||||||
|
from dateutil.relativedelta import relativedelta
|
||||||
|
class LoanContract(models.Model):
|
||||||
|
_name = 'loan.contract'
|
||||||
|
_description = 'Loan Contract'
|
||||||
|
|
||||||
|
code_contract = fields.Char(
|
||||||
|
string='Contract Code',
|
||||||
|
required=True,
|
||||||
|
copy=False,
|
||||||
|
readonly=True,
|
||||||
|
default=lambda self: self.env['ir.sequence'].next_by_code('loan.contract')
|
||||||
|
)
|
||||||
|
repayment_line_ids = fields.One2many('repayment.line', 'contract_id', string='Lịch trả nợ')
|
||||||
|
loan_request_id = fields.Many2one(
|
||||||
|
'loan.request',
|
||||||
|
string='Loan Request',
|
||||||
|
required=True,
|
||||||
|
ondelete='restrict'
|
||||||
|
)
|
||||||
|
|
||||||
|
borrower_id = fields.Many2one(
|
||||||
|
'loan.borrower',
|
||||||
|
string='Borrower',
|
||||||
|
required=True,
|
||||||
|
ondelete='restrict'
|
||||||
|
)
|
||||||
|
|
||||||
|
loan_type_id = fields.Many2one(
|
||||||
|
'loan.type1',
|
||||||
|
string='Loan Type',
|
||||||
|
readonly=True
|
||||||
|
)
|
||||||
|
|
||||||
|
amount = fields.Float(
|
||||||
|
string='Loan Amount',
|
||||||
|
required=True
|
||||||
|
)
|
||||||
|
|
||||||
|
term = fields.Integer(
|
||||||
|
string='Term (Months)',
|
||||||
|
required=True
|
||||||
|
)
|
||||||
|
payment_method = fields.Selection([
|
||||||
|
('cash', 'Cash'),
|
||||||
|
('bank_transfer', 'Bank Transfer'),
|
||||||
|
('check', 'Check')
|
||||||
|
], string='Payment Method', required=True, default='cash',readonly=True)
|
||||||
|
|
||||||
|
repayment_type = fields.Selection([
|
||||||
|
('fixed_principal', 'Trả gốc đều, lãi giảm dần'),
|
||||||
|
('annuity', 'Trả góp đều (gốc + lãi)'),
|
||||||
|
('interest_only', 'Chỉ trả lãi hàng kỳ, gốc trả cuối'),
|
||||||
|
('lump_sum', 'Trả 1 lần cuối kỳ'),
|
||||||
|
], string='Kiểu trả nợ', required=True, readonly=True)
|
||||||
|
|
||||||
|
interest_rate = fields.Float(
|
||||||
|
string='Interest Rate (%)',
|
||||||
|
required=True
|
||||||
|
)
|
||||||
|
|
||||||
|
processing_fee = fields.Float(
|
||||||
|
string='Processing Fee',
|
||||||
|
compute='_compute_processing_fee_amount_count',
|
||||||
|
store=True,
|
||||||
|
readonly=True
|
||||||
|
)
|
||||||
|
|
||||||
|
amount_count = fields.Float(
|
||||||
|
string='Amount Count',
|
||||||
|
compute='_compute_processing_fee_amount_count',
|
||||||
|
store=True,
|
||||||
|
readonly=True
|
||||||
|
)
|
||||||
|
|
||||||
|
start_date = fields.Date(
|
||||||
|
string='Start Date',
|
||||||
|
required=True,
|
||||||
|
default=fields.Date.context_today
|
||||||
|
)
|
||||||
|
|
||||||
|
end_date = fields.Date(
|
||||||
|
string='End Date',
|
||||||
|
compute='_compute_end_date',
|
||||||
|
store=True,
|
||||||
|
readonly=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
state = fields.Selection([
|
||||||
|
('draft', 'Draft'),
|
||||||
|
('active', 'Active'),
|
||||||
|
('done', 'Completed'),
|
||||||
|
('cancelled', 'Cancelled')
|
||||||
|
], string='Status', default='draft')
|
||||||
|
|
||||||
|
note = fields.Text(string='Notes')
|
||||||
|
|
||||||
|
@api.depends('start_date', 'term')
|
||||||
|
def _compute_end_date(self):
|
||||||
|
for rec in self:
|
||||||
|
if rec.start_date and rec.term:
|
||||||
|
rec.end_date = rec.start_date + relativedelta(months=rec.term)
|
||||||
|
else:
|
||||||
|
rec.end_date = False
|
||||||
|
|
||||||
|
@api.onchange('loan_request_id')
|
||||||
|
def _onchange_loan_request_id(self):
|
||||||
|
for rec in self:
|
||||||
|
if rec.loan_request_id:
|
||||||
|
rec.borrower_id = rec.loan_request_id.borrower_id
|
||||||
|
rec.loan_type_id = rec.loan_request_id.loan_type_id
|
||||||
|
rec.amount = rec.loan_request_id.amount
|
||||||
|
rec.interest_rate = rec.loan_request_id.interest_rate
|
||||||
|
rec.term = rec.loan_request_id.term
|
||||||
|
rec.repayment_type = rec.loan_request_id.repayment_type
|
||||||
|
|
||||||
|
@api.depends('loan_request_id')
|
||||||
|
def _compute_processing_fee_amount_count(self):
|
||||||
|
for rec in self:
|
||||||
|
if rec.loan_request_id:
|
||||||
|
rec.tinterest_rate = rec.loan_request_id.interest_rate or 0.0
|
||||||
|
rec.amount = rec.loan_request_id.amount or 0.0
|
||||||
|
rec.processing_fee = rec.amount - (rec.amount * rec.rate / 100)
|
||||||
|
rec.amount_count = rec.amount + rec.processing_fee
|
||||||
|
else:
|
||||||
|
rec.processing_fee = 0.0
|
||||||
|
rec.amount_count = 0.0
|
||||||
|
@api.model
|
||||||
|
def create(self, vals):
|
||||||
|
if vals.get('loan_request_id'):
|
||||||
|
request = self.env['loan.request'].browse(vals['loan_request_id'])
|
||||||
|
vals['repayment_type'] = request.repayment_type
|
||||||
|
vals['payment_method'] = request.payment_method
|
||||||
|
|
||||||
|
return super().create(vals)
|
||||||
|
@api.model
|
||||||
|
def write(self, vals):
|
||||||
|
res = super().write(vals)
|
||||||
|
for contract in self:
|
||||||
|
if vals.get('state') == 'active':
|
||||||
|
contract._generate_repayment_schedule()
|
||||||
|
return res
|
||||||
|
def _generate_repayment_schedule(self):
|
||||||
|
self.repayment_line_ids.unlink() # Xóa cũ nếu có
|
||||||
|
start_date = self.start_date
|
||||||
|
monthly_rate = self.interest_rate / 100 / 12
|
||||||
|
principal = self.amount
|
||||||
|
term = self.term
|
||||||
|
|
||||||
|
for i in range(1, term + 1):
|
||||||
|
due_date = start_date + relativedelta(months=i)
|
||||||
|
if self.repayment_type == 'fixed_principal':
|
||||||
|
principal_amount = principal / term
|
||||||
|
remaining = principal - principal_amount * (i - 1)
|
||||||
|
interest = remaining * monthly_rate
|
||||||
|
elif self.repayment_type == 'annuity':
|
||||||
|
annuity = principal * monthly_rate / (1 - (1 + monthly_rate) ** (-term))
|
||||||
|
interest = (principal - (i - 1) * (annuity - principal * monthly_rate)) * monthly_rate
|
||||||
|
principal_amount = annuity - interest
|
||||||
|
elif self.repayment_type == 'interest_only':
|
||||||
|
principal_amount = 0.0 if i < term else principal
|
||||||
|
interest = principal * monthly_rate
|
||||||
|
elif self.repayment_type == 'lump_sum':
|
||||||
|
principal_amount = principal if i == term else 0.0
|
||||||
|
interest = principal * monthly_rate if i == term else 0.0
|
||||||
|
else:
|
||||||
|
principal_amount = interest = 0.0
|
||||||
|
|
||||||
|
self.env['repayment.line'].create({
|
||||||
|
'contract_id': self.id,
|
||||||
|
'installment': i,
|
||||||
|
'due_date': due_date,
|
||||||
|
'principal': principal_amount,
|
||||||
|
'interest': interest,
|
||||||
|
'total': principal_amount + interest,
|
||||||
|
})
|
18
loan_management/models/loan_interest_policy.py
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
from odoo import models, fields
|
||||||
|
class LoanInterestPolicy(models.Model):
|
||||||
|
_name = 'loan.interest.policy'
|
||||||
|
_description = 'Loan Interest Policy'
|
||||||
|
|
||||||
|
loan_type_id = fields.Many2one('loan.type1', string='Loại khoản vay', required=True)
|
||||||
|
repayment_type = fields.Selection([
|
||||||
|
('fixed_principal', 'Gốc đều, lãi giảm dần'),
|
||||||
|
('annuity', 'Trả góp cố định'),
|
||||||
|
('interest_only', 'Chỉ trả lãi'),
|
||||||
|
('lump_sum', 'Trả 1 lần cuối kỳ'),
|
||||||
|
], string='Kiểu trả nợ', required=True)
|
||||||
|
|
||||||
|
interest_rate = fields.Float(string='Lãi suất (%)', required=True)
|
||||||
|
|
||||||
|
_sql_constraints = [
|
||||||
|
('unique_policy', 'unique(loan_type_id, repayment_type)', 'Chính sách lãi suất đã tồn tại cho loại vay và kiểu trả nợ này.')
|
||||||
|
]
|
39
loan_management/models/loan_request.py
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
from odoo import models, fields, api
|
||||||
|
class LoanRequest(models.Model):
|
||||||
|
_name = 'loan.request'
|
||||||
|
_description = 'Loan Request'
|
||||||
|
borrower_id = fields.Many2one('loan.borrower', string='Borrower', required=True, ondelete='restrict')
|
||||||
|
loan_type_id = fields.Many2one('loan.type1', string='Loan Type', required=True)
|
||||||
|
amount = fields.Float(string='Loan Amount', required=True)
|
||||||
|
term = fields.Integer(string='Term (months)', required=True,default=1)
|
||||||
|
repayment_type = fields.Selection([
|
||||||
|
('fixed_principal', 'Gốc đều, lãi giảm dần'),
|
||||||
|
('annuity', 'Trả góp cố định'),
|
||||||
|
('interest_only', 'Chỉ trả lãi'),
|
||||||
|
('lump_sum', 'Trả 1 lần cuối kỳ'),
|
||||||
|
], string='Kiểu trả nợ', required=True)
|
||||||
|
interest_rate = fields.Float(string='Interest Rate (%)', required=True)
|
||||||
|
expected_interest_rate = fields.Float(string='Lãi suất mong muốn', help="Khách hàng đề xuất một lãi suất thấp hơn nếu có")
|
||||||
|
payment_method = fields.Selection([
|
||||||
|
('cash', 'Cash'),
|
||||||
|
('bank_transfer', 'Bank Transfer'),
|
||||||
|
('check', 'Check')
|
||||||
|
], string='Payment Method', required=True, default='cash')
|
||||||
|
request_datetime = fields.Datetime(
|
||||||
|
string='Ngày giờ yêu cầu',
|
||||||
|
default=fields.Datetime.now)
|
||||||
|
state = fields.Selection([
|
||||||
|
('draft', 'Nháp'),
|
||||||
|
('processing', 'Đang xử lý'),
|
||||||
|
('approved', 'Đã duyệt'),
|
||||||
|
('rejected', 'Từ chối')
|
||||||
|
], string='Trạng thái', default='processing', required=True)
|
||||||
|
|
||||||
|
# def _onchange_interest_rate(self):
|
||||||
|
# if self.loan_type_id and self.repayment_type:
|
||||||
|
# policy = self.env['loan.interest.policy'].search([
|
||||||
|
# ('loan_type_id', '=', self.loan_type_id.id),
|
||||||
|
# ('repayment_type', '=', self.repayment_type)
|
||||||
|
# ], limit=1)
|
||||||
|
# self.interest_rate = policy.interest_rate if policy else 0.0
|
||||||
|
|
15
loan_management/models/loan_type.py
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
from odoo import api, models, fields
|
||||||
|
class LoanType(models.Model):
|
||||||
|
_name = 'loan.type1'
|
||||||
|
_description = 'Loan Type'
|
||||||
|
name = fields.Char(string='Loan Type', required=True,unique=True)
|
||||||
|
active = fields.Boolean(default=True)
|
||||||
|
interest_policy_ids = fields.One2many(
|
||||||
|
'loan.interest.policy',
|
||||||
|
'loan_type_id',
|
||||||
|
string='Chính sách lãi suất'
|
||||||
|
)
|
||||||
|
@api.onchange('name')
|
||||||
|
def _onchange_name_uppercase(self):
|
||||||
|
if self.name:
|
||||||
|
self.name = self.name.upper()
|
15
loan_management/models/repayment_line.py
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
from odoo import models, fields
|
||||||
|
class RepaymentLine(models.Model):
|
||||||
|
_name = 'repayment.line'
|
||||||
|
_description = 'Repayment Schedule Line'
|
||||||
|
|
||||||
|
contract_id = fields.Many2one('loan.contract', string='Contract', ondelete='cascade', required=True)
|
||||||
|
installment = fields.Integer(string='Kỳ thứ')
|
||||||
|
due_date = fields.Date(string='Ngày đến hạn')
|
||||||
|
principal = fields.Float(string='Tiền gốc')
|
||||||
|
interest = fields.Float(string='Tiền lãi')
|
||||||
|
total = fields.Float(string='Tổng phải trả')
|
||||||
|
state = fields.Selection([
|
||||||
|
('draft', 'Chưa trả'),
|
||||||
|
('paid', 'Đã trả'),
|
||||||
|
], default='draft')
|
4
loan_management/security/ir.model.access.csv
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
|
||||||
|
access_loan_type_user,access.loan.type.user,model_loan_type1,base.group_user,1,1,1,1
|
||||||
|
access_loan_interest_policy_user,access.loan.interest.policy.user,model_loan_interest_policy,base.group_user,1,1,1,1
|
||||||
|
access_loan_request_user,access.loan.request.user,model_loan_request,base.group_user,1,1,1,1
|
|
@ -0,0 +1,10 @@
|
|||||||
|
import { registry } from "@web/core/registry";
|
||||||
|
import { Component } from "@odoo/owl";
|
||||||
|
|
||||||
|
class HideResConfigEdition extends Component {
|
||||||
|
static template = "loan_management.hide_res_config_edition";
|
||||||
|
}
|
||||||
|
|
||||||
|
registry.category("view_widgets").add("res_config_edition", {
|
||||||
|
component: HideResConfigEdition,
|
||||||
|
});
|
16
loan_management/static/src/xml/res_config_edition.xml
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<templates xml:space="preserve">
|
||||||
|
<!-- Ẩn template res_config_edition -->
|
||||||
|
<t t-inherit="res_config_edition" t-inherit-mode="extension">
|
||||||
|
<xpath expr="//div[1]" position="replace">
|
||||||
|
<div t-if="False"/>
|
||||||
|
</xpath>
|
||||||
|
</t>
|
||||||
|
|
||||||
|
<!-- Ẩn template MobileAppsFunnel -->
|
||||||
|
<t t-inherit="web.MobileAppsFunnel" t-inherit-mode="extension">
|
||||||
|
<xpath expr="//div[1]" position="replace">
|
||||||
|
<div t-if="False"/>
|
||||||
|
</xpath>
|
||||||
|
</t>
|
||||||
|
</templates>
|
56
loan_management/views/loan_borrower_view.xml
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<odoo>
|
||||||
|
<!-- Tree View -->
|
||||||
|
<record id="view_partner_borrower_tree" model="ir.ui.view">
|
||||||
|
<field name="name">res.partner.borrower.tree</field>
|
||||||
|
<field name="model">res.partner</field>
|
||||||
|
<field name="inherit_id" ref="base.view_partner_tree"/>
|
||||||
|
<field name="arch" type="xml">
|
||||||
|
<xpath expr="//list" position="inside">
|
||||||
|
<field name="is_borrower"/>
|
||||||
|
<field name="name"/>
|
||||||
|
<field name="email"/>
|
||||||
|
<field name="phone"/>
|
||||||
|
<field name="monthly_income"/>
|
||||||
|
</xpath>
|
||||||
|
</field>
|
||||||
|
</record>
|
||||||
|
|
||||||
|
<!-- Form View -->
|
||||||
|
<record id="view_partner_borrower_form" model="ir.ui.view">
|
||||||
|
<field name="name">res.partner.borrower.form</field>
|
||||||
|
<field name="model">res.partner</field>
|
||||||
|
<field name="inherit_id" ref="base.view_partner_form"/>
|
||||||
|
<field name="arch" type="xml">
|
||||||
|
<xpath expr="//notebook" position="attributes">
|
||||||
|
<attribute name="invisible">1</attribute>
|
||||||
|
</xpath>
|
||||||
|
<xpath expr="//sheet/group[1]" position="attributes">
|
||||||
|
<attribute name="invisible">1</attribute>
|
||||||
|
</xpath>
|
||||||
|
<xpath expr="//sheet" position="inside">
|
||||||
|
<group string="Borrower Information">
|
||||||
|
<field name="is_borrower"/>
|
||||||
|
<field name="name"/>
|
||||||
|
<field name="email"/>
|
||||||
|
<field name="phone"/>
|
||||||
|
<field name="gender"/>
|
||||||
|
<field name="date_of_birth"/>
|
||||||
|
<field name="job"/>
|
||||||
|
<field name="monthly_income"/>
|
||||||
|
<field name="marital_status"/>
|
||||||
|
</group>
|
||||||
|
</xpath>
|
||||||
|
</field>
|
||||||
|
</record>
|
||||||
|
|
||||||
|
<!-- Action -->
|
||||||
|
<record id="action_borrower_res_partner" model="ir.actions.act_window">
|
||||||
|
<field name="name">Borrowers</field>
|
||||||
|
<field name="res_model">res.partner</field>
|
||||||
|
<field name="view_mode">list,form</field>
|
||||||
|
<field name="domain">[('is_borrower','=',True)]</field>
|
||||||
|
<field name="context">{'default_is_borrower': True}</field>
|
||||||
|
</record>
|
||||||
|
<menuitem id="menu_loan_borrower" name="Borrowers" parent="loan_management.menu_loan_root" action="action_borrower_res_partner" sequence="2"/>
|
||||||
|
</odoo>
|
44
loan_management/views/loan_interest_policy_views.xml
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<odoo>
|
||||||
|
<!-- Tree View -->
|
||||||
|
<record id="view_loan_interest_policy_tree" model="ir.ui.view">
|
||||||
|
<field name="name">loan.interest.policy.tree</field>
|
||||||
|
<field name="model">loan.interest.policy</field>
|
||||||
|
<field name="arch" type="xml">
|
||||||
|
<list string="Loan Interest Policies">
|
||||||
|
<field name="loan_type_id"/>
|
||||||
|
<field name="repayment_type"/>
|
||||||
|
<field name="interest_rate"/>
|
||||||
|
</list>
|
||||||
|
</field>
|
||||||
|
</record>
|
||||||
|
|
||||||
|
<!-- Form View -->
|
||||||
|
<record id="view_loan_interest_policy_form" model="ir.ui.view">
|
||||||
|
<field name="name">loan.interest.policy.form</field>
|
||||||
|
<field name="model">loan.interest.policy</field>
|
||||||
|
<field name="arch" type="xml">
|
||||||
|
<form string="Loan Interest Policy">
|
||||||
|
<sheet>
|
||||||
|
<group>
|
||||||
|
<field name="loan_type_id"/>
|
||||||
|
<field name="repayment_type"/>
|
||||||
|
<field name="interest_rate"/>
|
||||||
|
</group>
|
||||||
|
</sheet>
|
||||||
|
</form>
|
||||||
|
</field>
|
||||||
|
</record>
|
||||||
|
|
||||||
|
<!-- Action -->
|
||||||
|
<record id="action_loan_interest_policy" model="ir.actions.act_window">
|
||||||
|
<field name="name">Loan Interest Policies</field>
|
||||||
|
<field name="res_model">loan.interest.policy</field>
|
||||||
|
<field name="view_mode">list,form</field>
|
||||||
|
<field name="help" type="html">
|
||||||
|
<p class="o_view_nocontent_smiling_face">
|
||||||
|
Create and manage loan interest policies.
|
||||||
|
</p>
|
||||||
|
</field>
|
||||||
|
</record>
|
||||||
|
</odoo>
|
58
loan_management/views/loan_request_view.xml
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
<odoo>
|
||||||
|
<record id="view_loan_request_list" model="ir.ui.view">
|
||||||
|
<field name="name">loan.request.list</field>
|
||||||
|
<field name="model">loan.request</field>
|
||||||
|
<field name="arch" type="xml">
|
||||||
|
<list string="Danh sách yêu cầu vay vốn">
|
||||||
|
<field name="borrower_id"/>
|
||||||
|
<field name="loan_type_id"/>
|
||||||
|
<field name="amount"/>
|
||||||
|
<field name="term"/>
|
||||||
|
<field name="interest_rate"/>
|
||||||
|
<field name="payment_method"/>
|
||||||
|
<field name="state"/>
|
||||||
|
<field name="request_datetime"/>
|
||||||
|
</list>
|
||||||
|
</field>
|
||||||
|
</record>
|
||||||
|
|
||||||
|
<record id="view_loan_request_form" model="ir.ui.view">
|
||||||
|
<field name="name">loan.request.form</field>
|
||||||
|
<field name="model">loan.request</field>
|
||||||
|
<field name="arch" type="xml">
|
||||||
|
<form string="Gửi Yêu Cầu Vay Vốn">
|
||||||
|
<sheet>
|
||||||
|
<group>
|
||||||
|
<group>
|
||||||
|
<field name="borrower_id"/>
|
||||||
|
<field name="loan_type_id"/>
|
||||||
|
<field name="repayment_type"/>
|
||||||
|
<field name="amount"/>
|
||||||
|
<field name="term"/>
|
||||||
|
<field name="interest_rate"/>
|
||||||
|
<field name="expected_interest_rate"/>
|
||||||
|
</group>
|
||||||
|
<group>
|
||||||
|
<field name="payment_method"/>
|
||||||
|
<field name="request_datetime" readonly="1"/>
|
||||||
|
<field name="state" readonly="1"/>
|
||||||
|
</group>
|
||||||
|
</group>
|
||||||
|
</sheet>
|
||||||
|
</form>
|
||||||
|
</field>
|
||||||
|
</record>
|
||||||
|
|
||||||
|
<!-- Action để mở form -->
|
||||||
|
<record id="action_loan_request" model="ir.actions.act_window">
|
||||||
|
<field name="name">Yêu Cầu Vay Vốn</field>
|
||||||
|
<field name="res_model">loan.request</field>
|
||||||
|
<field name="view_mode">list,form</field>
|
||||||
|
<field name="help" type="html">
|
||||||
|
<p class="o_view_nocontent_smiling_face">
|
||||||
|
Tạo yêu cầu vay vốn đầu tiên
|
||||||
|
</p>
|
||||||
|
</field>
|
||||||
|
</record>
|
||||||
|
|
||||||
|
</odoo>
|
59
loan_management/views/loan_type_views.xml
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<odoo>
|
||||||
|
<record id="view_loan_type_form" model="ir.ui.view">
|
||||||
|
<field name="name">loan.type.form</field>
|
||||||
|
<field name="model">loan.type1</field>
|
||||||
|
<field name="arch" type="xml">
|
||||||
|
<form string="Loan Type1">
|
||||||
|
<group>
|
||||||
|
<group>
|
||||||
|
<strong>
|
||||||
|
<field name="name" readonly="true" class="o_text_bold o_text_large"/>
|
||||||
|
</strong>
|
||||||
|
</group>
|
||||||
|
<group>
|
||||||
|
<field name="active"/>
|
||||||
|
</group>
|
||||||
|
</group>
|
||||||
|
|
||||||
|
<!-- Notebook nằm dưới -->
|
||||||
|
<notebook>
|
||||||
|
<page string="Thông tin chính sách vay nợ">
|
||||||
|
<field name="interest_policy_ids">
|
||||||
|
<list editable="bottom">
|
||||||
|
<field name="repayment_type"/>
|
||||||
|
<field name="interest_rate"/>
|
||||||
|
</list>
|
||||||
|
</field>
|
||||||
|
|
||||||
|
</page>
|
||||||
|
<!-- Bạn có thể thêm nhiều page khác nếu cần -->
|
||||||
|
</notebook>
|
||||||
|
</form>
|
||||||
|
</field>
|
||||||
|
</record>
|
||||||
|
|
||||||
|
<record id="view_loan_type1_list" model="ir.ui.view">
|
||||||
|
<field name="name">loan.type1.list</field>
|
||||||
|
<field name="model">loan.type1</field>
|
||||||
|
<field name="arch" type="xml">
|
||||||
|
<list string="Loan Types">
|
||||||
|
<field name="name"/>
|
||||||
|
<field name="active"/>
|
||||||
|
<field name="interest_policy_ids"></field>
|
||||||
|
</list>
|
||||||
|
</field>
|
||||||
|
</record>
|
||||||
|
|
||||||
|
<record id="action_loan_type" model="ir.actions.act_window">
|
||||||
|
<field name="name">Loan Types</field>
|
||||||
|
<field name="res_model">loan.type1</field>
|
||||||
|
<field name="view_mode">list,form</field>
|
||||||
|
<field name="help" type="html">
|
||||||
|
<p class="o_view_nocontent_smiling_face">
|
||||||
|
Tạo các loại hình vay vốn tại đây.
|
||||||
|
</p>
|
||||||
|
</field>
|
||||||
|
</record>
|
||||||
|
|
||||||
|
</odoo>
|
14
loan_management/views/menu_items.xml
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<odoo>
|
||||||
|
|
||||||
|
<!-- Menu cha -->
|
||||||
|
<menuitem id="menu_loan_root" name="Loan Management" sequence="10"/>
|
||||||
|
|
||||||
|
<!-- Menu con liên kết tới action -->
|
||||||
|
<menuitem id="menu_loan_type_root" name="Loan Types" parent="menu_loan_root" sequence="1"/>
|
||||||
|
<menuitem id="menu_loan_tpe" name="kiểu vay vốn" parent="menu_loan_type_root" action="action_loan_type" sequence="1"/>
|
||||||
|
<menuitem id="menu_loan_interest_policy" name="chính sách vay vốn" parent="menu_loan_type_root" action="action_loan_interest_policy" sequence="2"/>
|
||||||
|
<menuitem id="menu_loan_borrower" name="Borrowers" parent="menu_loan_root" action="action_borrower_res_partner" sequence="2"/>
|
||||||
|
<menuitem id="menu_loan_request" name="Resquests" parent="menu_loan_root" action="action_loan_request" sequence="3"/>
|
||||||
|
|
||||||
|
</odoo>
|
13
loan_management/wizards/Loan_repayment_preview_line.py
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
from odoo import models, fields
|
||||||
|
|
||||||
|
|
||||||
|
class LoanRepaymentPreviewLine(models.TransientModel):
|
||||||
|
_name = 'loan.repayment.preview.line'
|
||||||
|
_description = 'Chi tiết dự kiến lịch trả nợ'
|
||||||
|
|
||||||
|
wizard_id = fields.Many2one('loan.repayment.preview.wizard', string='Wizard')
|
||||||
|
installment = fields.Integer(string='Kỳ số')
|
||||||
|
due_date = fields.Date(string='Ngày đến hạn')
|
||||||
|
principal = fields.Float(string='Gốc')
|
||||||
|
interest = fields.Float(string='Lãi')
|
||||||
|
total = fields.Float(string='Tổng')
|
1
loan_management/wizards/__init__.py
Normal file
@ -0,0 +1 @@
|
|||||||
|
from . import loan_repayment_preview_wizard,Loan_repayment_preview_line
|
59
loan_management/wizards/loan_repayment_preview_wizard.py
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
from odoo import models, fields
|
||||||
|
from dateutil.relativedelta import relativedelta
|
||||||
|
|
||||||
|
|
||||||
|
class LoanRepaymentPreviewWizard(models.TransientModel):
|
||||||
|
_name = 'loan.repayment.preview.wizard'
|
||||||
|
_description = 'Loan Repayment Preview Wizard'
|
||||||
|
|
||||||
|
loan_request_id = fields.Many2one('loan.request', string='Yêu cầu vay', required=True)
|
||||||
|
preview_line_ids = fields.One2many('loan.repayment.preview.line', 'wizard_id', string='Chi tiết lịch trả', readonly=True)
|
||||||
|
|
||||||
|
def action_generate_preview_schedule(self):
|
||||||
|
self.ensure_one()
|
||||||
|
request = self.loan_request_id
|
||||||
|
self.preview_line_ids.unlink() # Clear old preview lines
|
||||||
|
|
||||||
|
amount = request.amount
|
||||||
|
term = request.term
|
||||||
|
rate = request.interest_rate
|
||||||
|
repayment_type = request.repayment_type
|
||||||
|
start_date = request.request_datetime.date() or fields.Date.today()
|
||||||
|
|
||||||
|
for i in range(term):
|
||||||
|
due_date = start_date + relativedelta(months=i + 1)
|
||||||
|
|
||||||
|
if repayment_type == 'fixed_principal':
|
||||||
|
principal = amount / term
|
||||||
|
interest = (amount - principal * i) * rate / 100 / 12
|
||||||
|
total = principal + interest
|
||||||
|
|
||||||
|
elif repayment_type == 'annuity':
|
||||||
|
monthly_rate = rate / 100 / 12
|
||||||
|
if monthly_rate == 0:
|
||||||
|
annuity = amount / term
|
||||||
|
else:
|
||||||
|
annuity = (amount * monthly_rate) / (1 - (1 + monthly_rate) ** -term)
|
||||||
|
interest = (amount - i * (amount / term)) * monthly_rate
|
||||||
|
principal = annuity - interest
|
||||||
|
total = annuity
|
||||||
|
|
||||||
|
elif repayment_type == 'interest_only':
|
||||||
|
principal = amount if i == term - 1 else 0
|
||||||
|
interest = amount * rate / 100 / 12
|
||||||
|
total = principal + interest
|
||||||
|
|
||||||
|
elif repayment_type == 'lump_sum':
|
||||||
|
principal = amount if i == term - 1 else 0
|
||||||
|
interest = amount * rate / 100 / 12
|
||||||
|
total = principal + interest
|
||||||
|
|
||||||
|
self.env['loan.repayment.preview.line'].create({
|
||||||
|
'wizard_id': self.id,
|
||||||
|
'installment': i + 1,
|
||||||
|
'due_date': due_date,
|
||||||
|
'principal': round(principal, 2),
|
||||||
|
'interest': round(interest, 2),
|
||||||
|
'total': round(total, 2),
|
||||||
|
})
|
||||||
|
|
@ -0,0 +1,32 @@
|
|||||||
|
<odoo>
|
||||||
|
<record id="view_loan_repayment_preview_wizard_form" model="ir.ui.view">
|
||||||
|
<field name="name">loan.repayment.preview.wizard.form</field>
|
||||||
|
<field name="model">loan.repayment.preview.wizard</field>
|
||||||
|
<field name="arch" type="xml">
|
||||||
|
<form string="Xem trước lịch trả nợ" create="false" edit="false">
|
||||||
|
<group>
|
||||||
|
<field name="loan_request_id" readonly="1"/>
|
||||||
|
</group>
|
||||||
|
<field name="preview_line_ids">
|
||||||
|
<tree editable="false">
|
||||||
|
<field name="installment"/>
|
||||||
|
<field name="due_date"/>
|
||||||
|
<field name="principal"/>
|
||||||
|
<field name="interest"/>
|
||||||
|
<field name="total"/>
|
||||||
|
</tree>
|
||||||
|
</field>
|
||||||
|
<footer>
|
||||||
|
<button string="Đóng" special="cancel" class="btn-secondary"/>
|
||||||
|
</footer>
|
||||||
|
</form>
|
||||||
|
</field>
|
||||||
|
</record>
|
||||||
|
|
||||||
|
<record id="action_loan_repayment_preview_wizard" model="ir.actions.act_window">
|
||||||
|
<field name="name">Xem lịch trả nợ</field>
|
||||||
|
<field name="res_model">loan.repayment.preview.wizard</field>
|
||||||
|
<field name="view_mode">form</field>
|
||||||
|
<field name="target">new</field>
|
||||||
|
</record>
|
||||||
|
</odoo>
|
4
website_genhd_embeb/__init__.py
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
from . import controllers
|
||||||
|
from . import models
|
60
website_genhd_embeb/__manifest__.py
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
{
|
||||||
|
'name': "website_genhd_embeb",
|
||||||
|
|
||||||
|
'summary': "Short (1 phrase/line) summary of the module's purpose",
|
||||||
|
|
||||||
|
'description': """
|
||||||
|
Long description of module's purpose
|
||||||
|
""",
|
||||||
|
|
||||||
|
'author': "My Company",
|
||||||
|
'website': "https://www.yourcompany.com",
|
||||||
|
|
||||||
|
# Categories can be used to filter modules in modules listing
|
||||||
|
# Check https://github.com/odoo/odoo/blob/15.0/odoo/addons/base/data/ir_module_category_data.xml
|
||||||
|
# for the full list
|
||||||
|
'category': 'Uncategorized',
|
||||||
|
'version': '0.1',
|
||||||
|
|
||||||
|
# any module necessary for this one to work correctly
|
||||||
|
'depends': ['website'],
|
||||||
|
'assets': {
|
||||||
|
'web.assets_frontend': [
|
||||||
|
'website_genhd_embeb/static/css/bootstrap.min.css',
|
||||||
|
'website_genhd_embeb/static/css/bootstrap-icons.css',
|
||||||
|
'website_genhd_embeb/static/css/owl.carousel.min.css',
|
||||||
|
'website_genhd_embeb/static/css/tooplate-moso-interior.css',
|
||||||
|
'https://fonts.googleapis.com/css2?family=League+Spartan:wght@100;300;400;600;700&display=swap',
|
||||||
|
'website_genhd_embeb/static/js/bootstrap.min.js',
|
||||||
|
'website_genhd_embeb/static/js/click-scroll.js',
|
||||||
|
'website_genhd_embeb/static/js/jquery.backstretch.min.js',
|
||||||
|
'website_genhd_embeb/static/js/owl.carousel.min.js',
|
||||||
|
'website_genhd_embeb/static/js/custom.js',
|
||||||
|
"website_genhd_embeb/static/css/Backend_server.css"
|
||||||
|
|
||||||
|
],
|
||||||
|
},
|
||||||
|
# always loaded
|
||||||
|
'data': [
|
||||||
|
'security/ir.model.access.csv',
|
||||||
|
"views/custom_homepage.xml",
|
||||||
|
"views/frontend_views/website_moso_homePage.xml",
|
||||||
|
"views/frontend_views/nav_template.xml",
|
||||||
|
"views/frontend_views/footer_template.xml",
|
||||||
|
"views/frontend_views/website_moso_productList.xml",
|
||||||
|
"views/frontend_views/website_moso_detail.xml",
|
||||||
|
"views/frontend_views/webstie_moso_oder.xml",
|
||||||
|
"views/Backend_views/menu_items.xml",
|
||||||
|
"views/Backend_views/moso_category_view.xml",
|
||||||
|
"views/Backend_views/moso_condition_view.xml",
|
||||||
|
"views/Backend_views/moso_type_view.xml",
|
||||||
|
"views/Backend_views/moso_product_view.xml",
|
||||||
|
|
||||||
|
],
|
||||||
|
# only loaded in demonstration mode
|
||||||
|
'demo': [
|
||||||
|
'demo/demo.xml',
|
||||||
|
],
|
||||||
|
}
|
||||||
|
|
4
website_genhd_embeb/controllers/__init__.py
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
from . import controllers
|
||||||
|
from . import moso_api
|
24
website_genhd_embeb/controllers/controllers.py
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
# controllers/main.py
|
||||||
|
from odoo import http
|
||||||
|
from odoo.http import request
|
||||||
|
|
||||||
|
class WebsiteEmbed(http.Controller):
|
||||||
|
|
||||||
|
@http.route('/moso', type='http', auth='public', website=True)
|
||||||
|
def homepage(self, **kw):
|
||||||
|
return request.render('website_genhd_embeb.moso_homepage_template')
|
||||||
|
@http.route('/moso/productlist', type='http', auth='public', website=True)
|
||||||
|
def productpage(self, **kw):
|
||||||
|
conditions = request.env["moso.condition"].search([])
|
||||||
|
types = request.env["moso.type"].search([])
|
||||||
|
categorys = request.env["moso.category"].search([])
|
||||||
|
products = request.env["moso.product"].search([],limit=1)
|
||||||
|
product_count = request.env['product.template'].search_count([])
|
||||||
|
return request.render('website_genhd_embeb.moso_productlist_template',{"conditions":conditions,"types":types,"categorys":categorys,"products":products,"product_count":product_count})
|
||||||
|
@http.route('/moso/product/<category_name>/', type='http', auth='public', website=True)
|
||||||
|
def productdetail(self,category_name):
|
||||||
|
category = request.env['moso.category'].sudo().search([('name', '=', category_name)], limit=1)
|
||||||
|
return request.render("website_genhd_embeb.moso_deltailpage_template",{'category':category})
|
||||||
|
@http.route('/moso/oder', type='http', auth='public', website=True)
|
||||||
|
def orderpage(self):
|
||||||
|
return request.render("website_genhd_embeb.moso_order_template")
|
2
website_genhd_embeb/controllers/moso_api.py
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
from odoo import http
|
||||||
|
from odoo.http import request
|
30
website_genhd_embeb/demo/demo.xml
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
<odoo>
|
||||||
|
<data>
|
||||||
|
<!--
|
||||||
|
<record id="object0" model="website_genhd_embeb.website_genhd_embeb">
|
||||||
|
<field name="name">Object 0</field>
|
||||||
|
<field name="value">0</field>
|
||||||
|
</record>
|
||||||
|
|
||||||
|
<record id="object1" model="website_genhd_embeb.website_genhd_embeb">
|
||||||
|
<field name="name">Object 1</field>
|
||||||
|
<field name="value">10</field>
|
||||||
|
</record>
|
||||||
|
|
||||||
|
<record id="object2" model="website_genhd_embeb.website_genhd_embeb">
|
||||||
|
<field name="name">Object 2</field>
|
||||||
|
<field name="value">20</field>
|
||||||
|
</record>
|
||||||
|
|
||||||
|
<record id="object3" model="website_genhd_embeb.website_genhd_embeb">
|
||||||
|
<field name="name">Object 3</field>
|
||||||
|
<field name="value">30</field>
|
||||||
|
</record>
|
||||||
|
|
||||||
|
<record id="object4" model="website_genhd_embeb.website_genhd_embeb">
|
||||||
|
<field name="name">Object 4</field>
|
||||||
|
<field name="value">40</field>
|
||||||
|
</record>
|
||||||
|
-->
|
||||||
|
</data>
|
||||||
|
</odoo>
|
4
website_genhd_embeb/models/__init__.py
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
from . import models
|
||||||
|
from . import moso_category,moso_condition,moso_type,moso_product
|
19
website_genhd_embeb/models/models.py
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
# from odoo import models, fields, api
|
||||||
|
|
||||||
|
|
||||||
|
# class website_genhd_embeb(models.Model):
|
||||||
|
# _name = 'website_genhd_embeb.website_genhd_embeb'
|
||||||
|
# _description = 'website_genhd_embeb.website_genhd_embeb'
|
||||||
|
|
||||||
|
# name = fields.Char()
|
||||||
|
# value = fields.Integer()
|
||||||
|
# value2 = fields.Float(compute="_value_pc", store=True)
|
||||||
|
# description = fields.Text()
|
||||||
|
#
|
||||||
|
# @api.depends('value')
|
||||||
|
# def _value_pc(self):
|
||||||
|
# for record in self:
|
||||||
|
# record.value2 = float(record.value) / 100
|
||||||
|
|
14
website_genhd_embeb/models/moso_category.py
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
from odoo import models, fields
|
||||||
|
|
||||||
|
class MosoCategory(models.Model):
|
||||||
|
_name = 'moso.category'
|
||||||
|
_description = "Interior Category"
|
||||||
|
_sql_constraints = [
|
||||||
|
('unique_name', 'UNIQUE(name)', 'Tên danh mục phải là duy nhất.'),
|
||||||
|
]
|
||||||
|
|
||||||
|
product_id = fields.Many2one('moso.product',string = "mẫu thiết kế")
|
||||||
|
name = fields.Char(string="Tên danh mục", required=True, unique=True)
|
||||||
|
image = fields.Binary(string="Ảnh danh mục", attachment=True)
|
||||||
|
description = fields.Text(string="Mô tả danh mục")
|
||||||
|
price = fields.Integer(string="giá bán",default=0)
|
9
website_genhd_embeb/models/moso_condition.py
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
from odoo import models,fields
|
||||||
|
class MosoCondition(models.Model):
|
||||||
|
_name = "moso.condition"
|
||||||
|
_description = "condition interior"
|
||||||
|
_sql_constraints = [
|
||||||
|
('unique_name', 'UNIQUE(name)', 'Tên điều kiện phải là duy nhất.'),
|
||||||
|
]
|
||||||
|
|
||||||
|
name = fields.Char(string="tên điều kiện")
|
10
website_genhd_embeb/models/moso_product.py
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
from odoo import fields,models,api
|
||||||
|
class MosoProduct(models.Model):
|
||||||
|
_name = "moso.product"
|
||||||
|
_sql_constraints = [
|
||||||
|
('unique_name', 'UNIQUE(name)', 'Tên sản phẩm phải là duy nhất.'),
|
||||||
|
]
|
||||||
|
name = fields.Char(String = "Tên nội thât",unique=True,require = True)
|
||||||
|
condition_id = fields.Many2one('moso.condition',String ="Điều kiện")
|
||||||
|
type_id = fields.Many2one("moso.type",string="thể loại")
|
||||||
|
|
9
website_genhd_embeb/models/moso_type.py
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
from odoo import models,fields,api
|
||||||
|
class MosoType(models.Model):
|
||||||
|
_name = 'moso.type'
|
||||||
|
_description = "interiort type"
|
||||||
|
_sql_constraints = [
|
||||||
|
('unique_name', 'UNIQUE(name)', 'Tên thiết kế phải là duy nhất.'),
|
||||||
|
]
|
||||||
|
name = fields.Char(string="name",require=True,unique=True)
|
||||||
|
|
5
website_genhd_embeb/security/ir.model.access.csv
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
|
||||||
|
access_moso_category_user,access.moso.category,model_moso_category,base.group_user,1,1,1,1
|
||||||
|
access_moso_condition_user,access.moso.condition,model_moso_condition,base.group_user,1,1,1,1
|
||||||
|
access_moso_type_user,access.moso.type,model_moso_type,base.group_user,1,1,1,1
|
||||||
|
access_moso_product_user,access.moso.product,model_moso_product,base.group_user,1,1,1,1
|
|
8
website_genhd_embeb/static/css/Backend_server.css
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
.o_list_view .moso_image_small img,
|
||||||
|
.o_form_view .moso_image_small img,
|
||||||
|
.o_content .moso_image_small img {
|
||||||
|
width: 100px !important;
|
||||||
|
height: 100px !important;
|
||||||
|
object-fit: cover;
|
||||||
|
border-radius: 6px;
|
||||||
|
}
|
1556
website_genhd_embeb/static/css/bootstrap-icons.css
vendored
Normal file
7
website_genhd_embeb/static/css/bootstrap.min.css
vendored
Normal file
6
website_genhd_embeb/static/css/owl.carousel.min.css
vendored
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
/**
|
||||||
|
* Owl Carousel v2.3.4
|
||||||
|
* Copyright 2013-2018 David Deutsch
|
||||||
|
* Licensed under: SEE LICENSE IN https://github.com/OwlCarousel2/OwlCarousel2/blob/master/LICENSE
|
||||||
|
*/
|
||||||
|
.owl-carousel,.owl-carousel .owl-item{-webkit-tap-highlight-color:transparent;position:relative}.owl-carousel{display:none;width:100%;z-index:1}.owl-carousel .owl-stage{position:relative;-ms-touch-action:pan-Y;touch-action:manipulation;-moz-backface-visibility:hidden}.owl-carousel .owl-stage:after{content:".";display:block;clear:both;visibility:hidden;line-height:0;height:0}.owl-carousel .owl-stage-outer{position:relative;overflow:hidden;-webkit-transform:translate3d(0,0,0)}.owl-carousel .owl-item,.owl-carousel .owl-wrapper{-webkit-backface-visibility:hidden;-moz-backface-visibility:hidden;-ms-backface-visibility:hidden;-webkit-transform:translate3d(0,0,0);-moz-transform:translate3d(0,0,0);-ms-transform:translate3d(0,0,0)}.owl-carousel .owl-item{min-height:1px;float:left;-webkit-backface-visibility:hidden;-webkit-touch-callout:none}.owl-carousel .owl-item img{display:block;width:100%}.owl-carousel .owl-dots.disabled,.owl-carousel .owl-nav.disabled{display:none}.no-js .owl-carousel,.owl-carousel.owl-loaded{display:block}.owl-carousel .owl-dot,.owl-carousel .owl-nav .owl-next,.owl-carousel .owl-nav .owl-prev{cursor:pointer;-webkit-user-select:none;-khtml-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.owl-carousel .owl-nav button.owl-next,.owl-carousel .owl-nav button.owl-prev,.owl-carousel button.owl-dot{background:0 0;color:inherit;border:none;padding:0!important;font:inherit}.owl-carousel.owl-loading{opacity:0;display:block}.owl-carousel.owl-hidden{opacity:0}.owl-carousel.owl-refresh .owl-item{visibility:hidden}.owl-carousel.owl-drag .owl-item{-ms-touch-action:pan-y;touch-action:pan-y;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.owl-carousel.owl-grab{cursor:move;cursor:grab}.owl-carousel.owl-rtl{direction:rtl}.owl-carousel.owl-rtl .owl-item{float:right}.owl-carousel .animated{animation-duration:1s;animation-fill-mode:both}.owl-carousel .owl-animated-in{z-index:0}.owl-carousel .owl-animated-out{z-index:1}.owl-carousel .fadeOut{animation-name:fadeOut}@keyframes fadeOut{0%{opacity:1}100%{opacity:0}}.owl-height{transition:height .5s ease-in-out}.owl-carousel .owl-item .owl-lazy{opacity:0;transition:opacity .4s ease}.owl-carousel .owl-item .owl-lazy:not([src]),.owl-carousel .owl-item .owl-lazy[src^=""]{max-height:0}.owl-carousel .owl-item img.owl-lazy{transform-style:preserve-3d}.owl-carousel .owl-video-wrapper{position:relative;height:100%;background:#000}.owl-carousel .owl-video-play-icon{position:absolute;height:80px;width:80px;left:50%;top:50%;margin-left:-40px;margin-top:-40px;background:url(owl.video.play.png) no-repeat;cursor:pointer;z-index:1;-webkit-backface-visibility:hidden;transition:transform .1s ease}.owl-carousel .owl-video-play-icon:hover{-ms-transform:scale(1.3,1.3);transform:scale(1.3,1.3)}.owl-carousel .owl-video-playing .owl-video-play-icon,.owl-carousel .owl-video-playing .owl-video-tn{display:none}.owl-carousel .owl-video-tn{opacity:0;height:100%;background-position:center center;background-repeat:no-repeat;background-size:contain;transition:opacity .4s ease}.owl-carousel .owl-video-frame{position:relative;z-index:1;height:100%;width:100%}
|
1133
website_genhd_embeb/static/css/tooplate-moso-interior.css
Normal file
BIN
website_genhd_embeb/static/fonts/bootstrap-icons.woff
Normal file
BIN
website_genhd_embeb/static/fonts/bootstrap-icons.woff2
Normal file
After Width: | Height: | Size: 24 KiB |
After Width: | Height: | Size: 30 KiB |
After Width: | Height: | Size: 25 KiB |
After Width: | Height: | Size: 29 KiB |
After Width: | Height: | Size: 26 KiB |
After Width: | Height: | Size: 86 KiB |
BIN
website_genhd_embeb/static/image/kitchen.jpg
Normal file
After Width: | Height: | Size: 125 KiB |
After Width: | Height: | Size: 131 KiB |
After Width: | Height: | Size: 76 KiB |
After Width: | Height: | Size: 140 KiB |
After Width: | Height: | Size: 55 KiB |
After Width: | Height: | Size: 90 KiB |
After Width: | Height: | Size: 134 KiB |
After Width: | Height: | Size: 154 KiB |
After Width: | Height: | Size: 111 KiB |
After Width: | Height: | Size: 209 KiB |
7
website_genhd_embeb/static/js/bootstrap.min.js
vendored
Normal file
37
website_genhd_embeb/static/js/click-scroll.js
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
//jquery-click-scroll
|
||||||
|
//by syamsul'isul' Arifin
|
||||||
|
|
||||||
|
// var sectionArray = [1, 2, 3, 4, 5];
|
||||||
|
|
||||||
|
// $.each(sectionArray, function(index, value){
|
||||||
|
|
||||||
|
// $(document).scroll(function(){
|
||||||
|
// var offsetSection = $('#' + 'section_' + value).offset().top - 70;
|
||||||
|
// var docScroll = $(document).scrollTop();
|
||||||
|
// var docScroll1 = docScroll + 1;
|
||||||
|
|
||||||
|
|
||||||
|
// if ( docScroll1 >= offsetSection ){
|
||||||
|
// $('.navbar-nav .nav-item .nav-link').removeClass('active');
|
||||||
|
// $('.navbar-nav .nav-item .nav-link:link').addClass('inactive');
|
||||||
|
// $('.navbar-nav .nav-item .nav-link').eq(index).addClass('active');
|
||||||
|
// $('.navbar-nav .nav-item .nav-link').eq(index).removeClass('inactive');
|
||||||
|
// }
|
||||||
|
|
||||||
|
// });
|
||||||
|
|
||||||
|
// $('.click-scroll').eq(index).click(function(e){
|
||||||
|
// var offsetClick = $('#' + 'section_' + value).offset().top - 70;
|
||||||
|
// e.preventDefault();
|
||||||
|
// $('html, body').animate({
|
||||||
|
// 'scrollTop':offsetClick
|
||||||
|
// }, 300)
|
||||||
|
// });
|
||||||
|
|
||||||
|
// });
|
||||||
|
|
||||||
|
// $(document).ready(function(){
|
||||||
|
// $('.navbar-nav .nav-item .nav-link:link').addClass('inactive');
|
||||||
|
// $('.navbar-nav .nav-item .nav-link').eq(0).addClass('active');
|
||||||
|
// $('.navbar-nav .nav-item .nav-link:link').eq(0).removeClass('inactive');
|
||||||
|
// });
|
56
website_genhd_embeb/static/js/custom.js
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
|
||||||
|
(function ($) {
|
||||||
|
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
// HERO SLIDE
|
||||||
|
$('.hero-slide').backstretch([
|
||||||
|
"/website_genhd_embeb/static/image/slideshow/white-wall-living-room-have-sofa-decoration-3d-rendering.jpg",
|
||||||
|
"/website_genhd_embeb/static/image/slideshow/interior-wall-mockup-with-sofa-cabinet-living-room-with-empty-white-wall-background-3d-rendering.jpg",
|
||||||
|
"/website_genhd_embeb/static/image/slideshow/wood-sideboard-living-room-interior-with-copy-space.jpg"
|
||||||
|
], { duration: 2000, fade: 750 });
|
||||||
|
|
||||||
|
// REVIEWS CAROUSEL
|
||||||
|
$('.reviews-carousel').owlCarousel({
|
||||||
|
items: 3,
|
||||||
|
loop: true,
|
||||||
|
dots: false,
|
||||||
|
nav: true,
|
||||||
|
autoplay: true,
|
||||||
|
margin: 30,
|
||||||
|
responsive: {
|
||||||
|
0: {
|
||||||
|
items: 1
|
||||||
|
},
|
||||||
|
600: {
|
||||||
|
items: 2
|
||||||
|
},
|
||||||
|
1000: {
|
||||||
|
items: 3
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
// CUSTOM LINK
|
||||||
|
$('.smoothscroll').click(function () {
|
||||||
|
var el = $(this).attr('href');
|
||||||
|
var elWrapped = $(el);
|
||||||
|
var header_height = $('.navbar').height();
|
||||||
|
|
||||||
|
scrollToDiv(elWrapped, header_height);
|
||||||
|
return false;
|
||||||
|
|
||||||
|
function scrollToDiv(element, navheight) {
|
||||||
|
var offset = element.offset();
|
||||||
|
var offsetTop = offset.top;
|
||||||
|
var totalScroll = offsetTop - navheight;
|
||||||
|
|
||||||
|
$('body,html').animate({
|
||||||
|
scrollTop: totalScroll
|
||||||
|
}, 300);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
})(window.jQuery);
|
||||||
|
|
||||||
|
|
4
website_genhd_embeb/static/js/jquery.backstretch.min.js
vendored
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
/*! Backstretch - v2.0.4 - 2013-06-19
|
||||||
|
* http://srobbin.com/jquery-plugins/backstretch/
|
||||||
|
* Copyright (c) 2013 Scott Robbin; Licensed MIT */
|
||||||
|
(function(a,d,p){a.fn.backstretch=function(c,b){(c===p||0===c.length)&&a.error("No images were supplied for Backstretch");0===a(d).scrollTop()&&d.scrollTo(0,0);return this.each(function(){var d=a(this),g=d.data("backstretch");if(g){if("string"==typeof c&&"function"==typeof g[c]){g[c](b);return}b=a.extend(g.options,b);g.destroy(!0)}g=new q(this,c,b);d.data("backstretch",g)})};a.backstretch=function(c,b){return a("body").backstretch(c,b).data("backstretch")};a.expr[":"].backstretch=function(c){return a(c).data("backstretch")!==p};a.fn.backstretch.defaults={centeredX:!0,centeredY:!0,duration:5E3,fade:0};var r={left:0,top:0,overflow:"hidden",margin:0,padding:0,height:"400px",width:"100%",zIndex:-999999},s={position:"absolute",display:"none",margin:0,padding:0,border:"none",width:"auto",height:"400px",maxHeight:"none",maxWidth:"none",zIndex:-999999},q=function(c,b,e){this.options=a.extend({},a.fn.backstretch.defaults,e||{});this.images=a.isArray(b)?b:[b];a.each(this.images,function(){a("<img />")[0].src=this});this.isBody=c===document.body;this.$container=a(c);this.$root=this.isBody?l?a(d):a(document):this.$container;c=this.$container.children(".backstretch").first();this.$wrap=c.length?c:a('<div class="backstretch"></div>').css(r).appendTo(this.$container);this.isBody||(c=this.$container.css("position"),b=this.$container.css("zIndex"),this.$container.css({position:"static"===c?"relative":c,zIndex:"auto"===b?0:b,background:"none"}),this.$wrap.css({zIndex:-999998}));this.$wrap.css({position:this.isBody&&l?"fixed":"absolute"});this.index=0;this.show(this.index);a(d).on("resize.backstretch",a.proxy(this.resize,this)).on("orientationchange.backstretch",a.proxy(function(){this.isBody&&0===d.pageYOffset&&(d.scrollTo(0,1),this.resize())},this))};q.prototype={resize:function(){try{var a={left:0,top:0},b=this.isBody?this.$root.width():this.$root.innerWidth(),e=b,g=this.isBody?d.innerHeight?d.innerHeight:this.$root.height():this.$root.innerHeight(),j=e/this.$img.data("ratio"),f;j>=g?(f=(j-g)/2,this.options.centeredY&&(a.top="-"+f+"px")):(j=g,e=j*this.$img.data("ratio"),f=(e-b)/2,this.options.centeredX&&(a.left="-"+f+"px"));this.$wrap.css({width:b,height:g}).find("img:not(.deleteable)").css({width:e,height:j}).css(a)}catch(h){}return this},show:function(c){if(!(Math.abs(c)>this.images.length-1)){var b=this,e=b.$wrap.find("img").addClass("deleteable"),d={relatedTarget:b.$container[0]};b.$container.trigger(a.Event("backstretch.before",d),[b,c]);this.index=c;clearInterval(b.interval);b.$img=a("<img />").css(s).bind("load",function(f){var h=this.width||a(f.target).width();f=this.height||a(f.target).height();a(this).data("ratio",h/f);a(this).fadeIn(b.options.speed||b.options.fade,function(){e.remove();b.paused||b.cycle();a(["after","show"]).each(function(){b.$container.trigger(a.Event("backstretch."+this,d),[b,c])})});b.resize()}).appendTo(b.$wrap);b.$img.attr("src",b.images[c]);return b}},next:function(){return this.show(this.index<this.images.length-1?this.index+1:0)},prev:function(){return this.show(0===this.index?this.images.length-1:this.index-1)},pause:function(){this.paused=!0;return this},resume:function(){this.paused=!1;this.next();return this},cycle:function(){1<this.images.length&&(clearInterval(this.interval),this.interval=setInterval(a.proxy(function(){this.paused||this.next()},this),this.options.duration));return this},destroy:function(c){a(d).off("resize.backstretch orientationchange.backstretch");clearInterval(this.interval);c||this.$wrap.remove();this.$container.removeData("backstretch")}};var l,f=navigator.userAgent,m=navigator.platform,e=f.match(/AppleWebKit\/([0-9]+)/),e=!!e&&e[1],h=f.match(/Fennec\/([0-9]+)/),h=!!h&&h[1],n=f.match(/Opera Mobi\/([0-9]+)/),t=!!n&&n[1],k=f.match(/MSIE ([0-9]+)/),k=!!k&&k[1];l=!((-1<m.indexOf("iPhone")||-1<m.indexOf("iPad")||-1<m.indexOf("iPod"))&&e&&534>e||d.operamini&&"[object OperaMini]"==={}.toString.call(d.operamini)||n&&7458>t||-1<f.indexOf("Android")&&e&&533>e||h&&6>h||"palmGetResource"in d&&e&&534>e||-1<f.indexOf("MeeGo")&&-1<f.indexOf("NokiaBrowser/8.5.0")||k&&6>=k)})(jQuery,window);
|