@@ -3,7 +3,8 @@
|
||||
|
||||
import re
|
||||
|
||||
from odoo import models, fields
|
||||
from odoo import models, fields, api, tools
|
||||
from odoo.osv import expression
|
||||
|
||||
|
||||
def compute_badge_count_recursive(web_menus, menu_id):
|
||||
@@ -31,6 +32,93 @@ class IrUiMenu(models.Model):
|
||||
_inherit = "ir.ui.menu"
|
||||
|
||||
show_badge_count = fields.Boolean(string="显示菜单角标",default=True)
|
||||
is_phone = fields.Boolean(string="手机菜单",default=False)
|
||||
is_pc = fields.Boolean(string="PC菜单",default=True)
|
||||
|
||||
@api.model
|
||||
@tools.ormcache_context('self._uid', 'debug', keys=('lang',))
|
||||
def load_menus(self, debug):
|
||||
""" Loads all menu items (all applications and their sub-menus).
|
||||
|
||||
:return: the menu root
|
||||
:rtype: dict('children': menu_nodes)
|
||||
"""
|
||||
fields = ['name', 'sequence', 'parent_id', 'action', 'web_icon','show_badge_count']
|
||||
menu_roots = self.get_user_roots()
|
||||
menu_roots_data = menu_roots.read(fields) if menu_roots else []
|
||||
menu_root = {
|
||||
'id': False,
|
||||
'name': 'root',
|
||||
'parent_id': [-1, ''],
|
||||
'children': [menu['id'] for menu in menu_roots_data],
|
||||
}
|
||||
|
||||
all_menus = {'root': menu_root}
|
||||
|
||||
if not menu_roots_data:
|
||||
return all_menus
|
||||
|
||||
# menus are loaded fully unlike a regular tree view, cause there are a
|
||||
# limited number of items (752 when all 6.1 addons are installed)
|
||||
menus_domain = [('id', 'child_of', menu_roots.ids)]
|
||||
blacklisted_menu_ids = self._load_menus_blacklist()
|
||||
if blacklisted_menu_ids:
|
||||
menus_domain = expression.AND([menus_domain, [('id', 'not in', blacklisted_menu_ids)]])
|
||||
menus = self.search(menus_domain)
|
||||
menu_items = menus.read(fields)
|
||||
xmlids = (menu_roots + menus)._get_menuitems_xmlids()
|
||||
|
||||
# add roots at the end of the sequence, so that they will overwrite
|
||||
# equivalent menu items from full menu read when put into id:item
|
||||
# mapping, resulting in children being correctly set on the roots.
|
||||
menu_items.extend(menu_roots_data)
|
||||
|
||||
mi_attachments = self.env['ir.attachment'].sudo().search_read(
|
||||
domain=[('res_model', '=', 'ir.ui.menu'),
|
||||
('res_id', 'in', [menu_item['id'] for menu_item in menu_items if menu_item['id']]),
|
||||
('res_field', '=', 'web_icon_data')],
|
||||
fields=['res_id', 'datas', 'mimetype'])
|
||||
|
||||
mi_attachment_by_res_id = {attachment['res_id']: attachment for attachment in mi_attachments}
|
||||
|
||||
# set children ids and xmlids
|
||||
menu_items_map = {menu_item["id"]: menu_item for menu_item in menu_items}
|
||||
for menu_item in menu_items:
|
||||
menu_item.setdefault('children', [])
|
||||
parent = menu_item['parent_id'] and menu_item['parent_id'][0]
|
||||
menu_item['xmlid'] = xmlids.get(menu_item['id'], "")
|
||||
if parent in menu_items_map:
|
||||
menu_items_map[parent].setdefault(
|
||||
'children', []).append(menu_item['id'])
|
||||
attachment = mi_attachment_by_res_id.get(menu_item['id'])
|
||||
if attachment:
|
||||
menu_item['web_icon_data'] = attachment['datas']
|
||||
menu_item['web_icon_data_mimetype'] = attachment['mimetype']
|
||||
else:
|
||||
menu_item['web_icon_data'] = False
|
||||
menu_item['web_icon_data_mimetype'] = False
|
||||
all_menus.update(menu_items_map)
|
||||
|
||||
# sort by sequence
|
||||
for menu_id in all_menus:
|
||||
all_menus[menu_id]['children'].sort(key=lambda id: all_menus[id]['sequence'])
|
||||
|
||||
# recursively set app ids to related children
|
||||
def _set_app_id(app_id, menu):
|
||||
menu['app_id'] = app_id
|
||||
for child_id in menu['children']:
|
||||
_set_app_id(app_id, all_menus[child_id])
|
||||
|
||||
for app in menu_roots_data:
|
||||
app_id = app['id']
|
||||
_set_app_id(app_id, all_menus[app_id])
|
||||
|
||||
# filter out menus not related to an app (+ keep root menu)
|
||||
all_menus = {menu['id']: menu for menu in all_menus.values() if menu.get('app_id')}
|
||||
all_menus['root'] = menu_root
|
||||
|
||||
return all_menus
|
||||
|
||||
|
||||
def load_web_menus(self, debug):
|
||||
""" Loads all menu items (all applications and their sub-menus) and
|
||||
@@ -75,7 +163,8 @@ class IrUiMenu(models.Model):
|
||||
action_id = int(action_id) if action_id else False
|
||||
badge_count = 0
|
||||
res_model = False
|
||||
if action_model and action_id:
|
||||
# 增加 show_badge_count 限制是否显示"角标".
|
||||
if action_model and action_id and menu['show_badge_count']:
|
||||
action_record = self.env[action_model].browse(action_id).sudo()
|
||||
|
||||
if action_model == 'ir.actions.act_window' and action_record.view_mode != 'form':
|
||||
|
||||
@@ -27,4 +27,5 @@ from . import yuthon_department_change
|
||||
from . import yuthon_renewal_approval
|
||||
from . import contract_review_approval
|
||||
from . import yuthon_employee_add
|
||||
from . import yuthon_pre_examination
|
||||
from . import yuthon_pre_examination
|
||||
from . import yuthon_employee_setting
|
||||
@@ -0,0 +1,9 @@
|
||||
from odoo import models, fields, api
|
||||
from dateutil.relativedelta import relativedelta
|
||||
|
||||
|
||||
class YuthonServiceType(models.Model):
|
||||
_name = 'yuthon.service.type'
|
||||
_description = '服务类型'
|
||||
|
||||
name = fields.Char(string="名称")
|
||||
@@ -10,20 +10,22 @@ class YuthonServiceApproval(models.Model):
|
||||
name = fields.Char(string='标题')
|
||||
code = fields.Char(string="编号",
|
||||
default=lambda self: self.env['ir.sequence'].next_by_code('yuthon_service_approval_code'))
|
||||
service_type = fields.Selection([('done', '在职证明'), ('leaving', '离职证明'), ('income', '收入证明')], string="服务类型")
|
||||
service_type_id = fields.Many2one('yuthon.service.type', string="服务类型")
|
||||
users_id = fields.Many2one('res.users', string="申请人", default=lambda self: self.env.user.id)
|
||||
documents_ids = fields.Many2many('ir.attachment', string="附件")
|
||||
department_id = fields.Many2one(related='users_id.employee_id.department_id', string="部门", store=True)
|
||||
employee_id = fields.Many2one('hr.employee', string="员工姓名")
|
||||
employee_id = fields.Many2one('hr.employee', string="员工姓名", default=lambda self: self.env.user.employee_id.id)
|
||||
company_id = fields.Many2one(related="users_id.employee_id.company_id", string="公司", store=True)
|
||||
tenant_user_card = fields.Many2one('ir.attachment', string="身份证")
|
||||
|
||||
onboarding_time = fields.Date(related='employee_id.open_start_time', string="入职时间")
|
||||
onboarding_time = fields.Date(related='employee_id.open_start_time', string="入职日期")
|
||||
job_id = fields.Many2one(related='employee_id.job_id', string="岗位")
|
||||
is_turnover = fields.Boolean()
|
||||
reason_issuance = fields.Char(string="开证原因")
|
||||
is_issues = fields.Boolean(string='是否上会')
|
||||
issues_result = fields.Html(string="会议结果")
|
||||
related_issues_id = fields.Many2one('issue.library', string="关联议题")
|
||||
separation_date = fields.Date(string="离职日期")
|
||||
urgency_level = fields.Selection([('normal', '普件'), ('urgent', '急件'), ('emergency', '特急件')], string='紧急度',
|
||||
default='normal')
|
||||
active = fields.Boolean('Active', default=True, tracking=True)
|
||||
@@ -50,14 +52,13 @@ class YuthonServiceApproval(models.Model):
|
||||
'approval_date': fields.Datetime.now(),
|
||||
})
|
||||
|
||||
@api.onchange('service_type')
|
||||
@api.onchange('service_type_id')
|
||||
def _onchange_service_type(self):
|
||||
if self.service_type and self.users_id.name:
|
||||
# 创建一个映射表,将技术值映射到显示文本
|
||||
service_type_map = {
|
||||
'done': '在职证明',
|
||||
'leaving': '离职证明',
|
||||
'income': '收入证明'
|
||||
}
|
||||
service_display = service_type_map.get(self.service_type, self.service_type)
|
||||
self.name = f"{self.users_id.name}的{service_display}"
|
||||
if self.service_type_id and self.users_id.name:
|
||||
self.name = f"{self.users_id.name}的{self.service_type_id.name}"
|
||||
|
||||
if self.service_type_id.name == '离职证明':
|
||||
self.is_turnover = True
|
||||
else:
|
||||
self.is_turnover = False
|
||||
|
||||
|
||||
@@ -56,3 +56,4 @@ access_contract_review_approval,contract_review_approval,model_contract_review_a
|
||||
access_awards_line, awards_line,model_awards_line,base.group_user,1,1,1,1
|
||||
access_yuthon_employee_add,yuthon_employee_add,model_yuthon_employee_add,base.group_user,1,1,1,1
|
||||
access_yuthon_pre_examination,yuthon_pre_examination,model_yuthon_pre_examination,base.group_user,1,1,1,1
|
||||
access_yuthon_service_type,yuthon_service_type,model_yuthon_service_type,base.group_user,1,1,1,1
|
||||
|
||||
|
@@ -52,11 +52,13 @@
|
||||
<field name="reason_issuance"/>
|
||||
<field name="company_id" invisible="1"/>
|
||||
<field name="issues_result" invisible="is_issues == False"/>
|
||||
<field name="service_type"/>
|
||||
<field name="employee_id" widget="ztree_select"/>
|
||||
<field name="service_type_id"/>
|
||||
<field name="is_turnover" invisible="1"/>
|
||||
<field name="employee_id" domain="[('user_state', '=', 'leave')] if is_turnover else [('user_state', '=', 'in')]"/>
|
||||
<field name="job_id"/>
|
||||
<field name="department_id" invisible="1"/>
|
||||
<field name="department_id"/>
|
||||
<field name="onboarding_time"/>
|
||||
<field name="separation_date" invisible="not is_turnover"/>
|
||||
<field name="documents_ids" widget="preview_many2many"/>
|
||||
</group>
|
||||
</sheet>
|
||||
|
||||
@@ -33,11 +33,11 @@ class ReceivableReport extends Component {
|
||||
selectManagementType: {},
|
||||
condition: false,
|
||||
conditions: [
|
||||
{ 'name': '', 'value': '' },
|
||||
{ 'name': '自有', 'value': 'self' },
|
||||
{ 'name': '代管', 'value': 'agency' }
|
||||
{'name': '', 'value': ''},
|
||||
{'name': '自有', 'value': 'self'},
|
||||
{'name': '代管', 'value': 'agency'}
|
||||
],
|
||||
domainUsers:[]
|
||||
domainUsers: []
|
||||
});
|
||||
|
||||
this.config = this.props.action.context.report_config || {};
|
||||
@@ -90,14 +90,14 @@ class ReceivableReport extends Component {
|
||||
}
|
||||
|
||||
getDomain() {
|
||||
console.log(this.state)
|
||||
const isCompanyEmpty = Object.keys(this.state.selectCompany).length === 0;
|
||||
if (isCompanyEmpty) {
|
||||
return [];
|
||||
} else {
|
||||
return [['id','in', this.state.domainUsers]];
|
||||
console.log(this.state)
|
||||
const isCompanyEmpty = Object.keys(this.state.selectCompany).length === 0;
|
||||
if (isCompanyEmpty) {
|
||||
return [];
|
||||
} else {
|
||||
return [['id', 'in', this.state.domainUsers]];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async onUpdatePartner(v) {
|
||||
console.log(v)
|
||||
@@ -105,7 +105,7 @@ class ReceivableReport extends Component {
|
||||
}
|
||||
|
||||
async searchUserDomain() {
|
||||
this.state.selectPartner = {}
|
||||
this.state.selectPartner = {}
|
||||
let startDate = formatDate(this.state.startDate, {format: "yyyy-MM-dd"})
|
||||
let endDate = formatDate(this.state.endDate, {format: "yyyy-MM-dd"})
|
||||
|
||||
@@ -123,13 +123,35 @@ class ReceivableReport extends Component {
|
||||
this.state.domainUsers = results
|
||||
}
|
||||
|
||||
|
||||
async onUpdateCompany(v) {
|
||||
this.state.selectCompany = v[0] || {}
|
||||
console.log(v)
|
||||
// 执行一次 查询
|
||||
// 通过 read 重新查询一次, 更多只返回了 id
|
||||
let values = await this.serviceOrm.call(
|
||||
'yuthon.property.company',
|
||||
'read',
|
||||
[[v[0].id]],
|
||||
{
|
||||
fields: ['display_name'],
|
||||
}
|
||||
)
|
||||
console.log(values)
|
||||
this.state.selectCompany = values[0] || {}
|
||||
// 查询这个过程中的 user_id 组合成列表.返回.
|
||||
// 重置 partner 筛选结果
|
||||
// 修改过滤条件
|
||||
await this.searchUserDomain()
|
||||
}
|
||||
onClickPreMonth(){
|
||||
// 开始的月份的前一个月
|
||||
this.state.startDate = this.state.startDate.minus({months: 1});
|
||||
this.state.endDate = this.state.startDate.endOf("month");
|
||||
}
|
||||
onClickNextMonth() {
|
||||
this.state.startDate = this.state.startDate.plus({months: 1});
|
||||
this.state.endDate = this.state.startDate.endOf("month");
|
||||
}
|
||||
|
||||
async onSearch() {
|
||||
console.log(this.state)
|
||||
@@ -170,7 +192,7 @@ class ReceivableReport extends Component {
|
||||
}
|
||||
}
|
||||
|
||||
async onUpdateManagementType(v) {
|
||||
async onUpdateManagementType(v) {
|
||||
this.state.selectManagementType = v[0] || {};
|
||||
}
|
||||
|
||||
|
||||
@@ -10,9 +10,13 @@
|
||||
<div class="row mb-2" t-ref="search_area">
|
||||
|
||||
<!-- 应收日期范围 -->
|
||||
<div class="col-3">
|
||||
<div class="col-6">
|
||||
<label>日期范围</label>
|
||||
<div class="d-flex align-items-center gap-2">
|
||||
<!-- 上一个月 按钮-->
|
||||
<button class="btn btn-info" style="margin-bottom: 5px" t-on-click="onClickPreMonth">
|
||||
<i class="oi oi-chevron-left"></i>
|
||||
</button>
|
||||
<DateTimeInput
|
||||
range="true"
|
||||
value="state.startDate"
|
||||
@@ -29,6 +33,10 @@
|
||||
onChange="(date) => this.onChangeEndDate(date)"
|
||||
/>
|
||||
|
||||
<!-- 下一个月-->
|
||||
<button class="btn btn-sm btn-outline-secondary" style="margin-bottom: 5px" t-on-click="onClickNextMonth">
|
||||
<i class="oi oi-chevron-right"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user