This commit is contained in:
Duy Dat 2025-06-21 09:44:01 +07:00
parent 7819a1d6db
commit 446d1f7d9d
112 changed files with 4951 additions and 8 deletions

62
.gitignore vendored Normal file
View 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

View File

@ -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)

View File

@ -2,4 +2,5 @@
from . import controllers from . import controllers
from . import models from . import models
from . import wizard from . import security

View File

@ -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': [

View File

@ -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,

View File

@ -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>

View File

@ -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

1 id name model_id:id group_id:id perm_read perm_write perm_create perm_unlink
2 access_employee_profile_user employee.profile model_employee_profile employee_management.group_employee_user 1 0 1 0 1 0 1
3 access_employee_profile_admin employee.profile model_employee_profile employee_management.group_employee_admin 1 1 1 1
4 access_add_employee_wizard_user add.employee.wizard model_add_employee_wizard employee_management.group_employee_user 0 1 0 1 0 1 0 1
5 access_add_employee_wizard_admin add.employee.wizard model_add_employee_wizard employee_management.group_employee_admin 1 1 1 1

View File

@ -0,0 +1,5 @@
# -*- coding: utf-8 -*-
from . import controllers
from . import models
from . import wizards

View 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,
}

View File

@ -0,0 +1,3 @@
# -*- coding: utf-8 -*-
from . import controllers

View 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
# })

View 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>

View 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>

View File

@ -0,0 +1,5 @@
# -*- coding: utf-8 -*-
from . import loan_type
from . import borrower
from . import loan_interest_policy
from . import loan_request

View 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')

View 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,
})

View 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.')
]

View 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

View 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()

View 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')

View 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
1 id name model_id:id group_id:id perm_read perm_write perm_create perm_unlink
2 access_loan_type_user access.loan.type.user model_loan_type1 base.group_user 1 1 1 1
3 access_loan_interest_policy_user access.loan.interest.policy.user model_loan_interest_policy base.group_user 1 1 1 1
4 access_loan_request_user access.loan.request.user model_loan_request base.group_user 1 1 1 1

View File

@ -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,
});

View 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>

View 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>

View 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>

View 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>

View 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>

View 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>

View 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')

View File

@ -0,0 +1 @@
from . import loan_repayment_preview_wizard,Loan_repayment_preview_line

View 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),
})

View File

@ -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>

View File

@ -0,0 +1,4 @@
# -*- coding: utf-8 -*-
from . import controllers
from . import models

View 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',
],
}

View File

@ -0,0 +1,4 @@
# -*- coding: utf-8 -*-
from . import controllers
from . import moso_api

View 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")

View File

@ -0,0 +1,2 @@
from odoo import http
from odoo.http import request

View 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>

View File

@ -0,0 +1,4 @@
# -*- coding: utf-8 -*-
from . import models
from . import moso_category,moso_condition,moso_type,moso_product

View 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

View 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)

View 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")

View 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")

View 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)

View 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
1 id name model_id:id group_id:id perm_read perm_write perm_create perm_unlink
2 access_moso_category_user access.moso.category model_moso_category base.group_user 1 1 1 1
3 access_moso_condition_user access.moso.condition model_moso_condition base.group_user 1 1 1 1
4 access_moso_type_user access.moso.type model_moso_type base.group_user 1 1 1 1
5 access_moso_product_user access.moso.product model_moso_product base.group_user 1 1 1 1

View 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;
}

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

View 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%}

File diff suppressed because it is too large Load Diff

Binary file not shown.

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 125 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 131 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 76 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 140 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 55 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 90 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 134 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 111 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 209 KiB

File diff suppressed because one or more lines are too long

View 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');
// });

View 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);

View 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);

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,7 @@
<odoo>
<menuitem id="menu_moso_root" name="Moso Interior" sequence="10"/>
<menuitem id="menu_moso_category" name="Danh mục" parent="menu_moso_root" action="action_moso_category" sequence="40"/>
<menuitem id="menu_moso_condition" name="Điều kiện" parent="menu_moso_root" action="action_moso_condition" sequence="10"/>
<menuitem id="menu_moso_product" name="Sản phẩm" parent="menu_moso_root" action="action_moso_product" sequence="30"/>
<menuitem id="menu_moso_type" name="Thể loại" parent="menu_moso_root" action="action_moso_type" sequence="20"/>
</odoo>

Some files were not shown because too many files have changed in this diff Show More