Merge branch 'master' of https://gitee.com/jinan-pengyusen-data/gzth
This commit is contained in:
@@ -23,32 +23,32 @@ patch(UserMenu.prototype, {
|
||||
this.app_lang_list = session.app_lang_list;
|
||||
//todo: 演习 shortCutsItem 中的用法,当前是直接 xml 写了展现
|
||||
|
||||
//修正 bug,在移动端不会关闭本身
|
||||
//o_burger_menu position-fixed top-0 bottom-0 start-100 d-flex flex-column flex-nowrap burgerslide burgerslide-enter-active
|
||||
function preferencesItem(env) {
|
||||
return {
|
||||
type: "item",
|
||||
id: "settings",
|
||||
description: _t("Preferences"),
|
||||
callback: async function () {
|
||||
const actionDescription = await env.services.orm.call("res.users", "action_get");
|
||||
actionDescription.res_id = env.services.user.userId;
|
||||
try {
|
||||
let m = document.getElementsByClassName("o_burger_menu_close");
|
||||
if (m) {
|
||||
m[0].click();
|
||||
}
|
||||
} catch (e) {
|
||||
;
|
||||
}
|
||||
env.services.action.doAction(actionDescription);
|
||||
//修正 bug,在移动端不会关闭本身
|
||||
},
|
||||
sequence: 50,
|
||||
};
|
||||
}
|
||||
userMenuRegistry.add("profile", preferencesItem, {'force': true, 'menu': this});
|
||||
userMenuRegistry.add("refresh_current", refresh_current, {'force': true});
|
||||
// 修正 bug,在移动端不会关闭本身
|
||||
// o_burger_menu position-fixed top-0 bottom-0 start-100 d-flex flex-column flex-nowrap burgerslide burgerslide-enter-active
|
||||
// function preferencesItem(env) {
|
||||
// return {
|
||||
// type: "item",
|
||||
// id: "settings",
|
||||
// description: _t("Preferences"),
|
||||
// callback: async function () {
|
||||
// const actionDescription = await env.services.orm.call("res.users", "action_get");
|
||||
// actionDescription.res_id = env.services.user.userId;
|
||||
// try {
|
||||
// let m = document.getElementsByClassName("o_burger_menu_close");
|
||||
// if (m) {
|
||||
// m[0].click();
|
||||
// }
|
||||
// } catch (e) {
|
||||
// ;
|
||||
// }
|
||||
// env.services.action.doAction(actionDescription);
|
||||
// //修正 bug,在移动端不会关闭本身
|
||||
// },
|
||||
// sequence: 50,
|
||||
// };
|
||||
// }
|
||||
// userMenuRegistry.add("profile", preferencesItem, {'force': true, 'menu': this});
|
||||
// userMenuRegistry.add("refresh_current", refresh_current, {'force': true});
|
||||
|
||||
if (session.app_show_lang) {
|
||||
userMenuRegistry.add("separator1", separator1, {'force': true})
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
'views/attendance_iot_user_views.xml',
|
||||
'views/attendance_iot_manager_views.xml',
|
||||
'views/attendance_iot_views.xml',
|
||||
'views/attendance_iot_log_views.xml',
|
||||
# 'views/inherit_hr_employee_views.xml',
|
||||
'wizard/attendance_iot_manager_wizard_views.xml',
|
||||
'views/iot_message.xml'
|
||||
|
||||
@@ -56,7 +56,7 @@ class BusController(Controller):
|
||||
except Exception as e:
|
||||
_logger.info(f'抛出异常,异常原因:{e}')
|
||||
return e
|
||||
_logger.info(f'考勤机发送过来的数据集合{data}-------我把photo去掉因为太长可')
|
||||
# _logger.info(f'考勤机发送过来的数据集合{data}-------我把photo去掉因为太长可')
|
||||
user_id = data.get('logs')[0].get('user_id')
|
||||
recog_time = data.get('logs')[0].get('recog_time')
|
||||
if recog_time:
|
||||
|
||||
@@ -4,3 +4,4 @@ from . import attendance_iot
|
||||
from . import attendance_iot_datas
|
||||
from . import attendance_iot_manager
|
||||
from . import iot_message
|
||||
from . import attendance_iot_log
|
||||
|
||||
@@ -20,6 +20,7 @@ class AttendanceIot(models.Model):
|
||||
company_id = fields.Many2one('res.company', string="公司")
|
||||
remake = fields.Text(string='备注')
|
||||
employee_ids = fields.Many2many('hr.employee', string="员工")
|
||||
is_connected = fields.Boolean(string="连接状态", default=False)
|
||||
|
||||
def action_init_device(self):
|
||||
'''
|
||||
@@ -102,3 +103,17 @@ class AttendanceIot(models.Model):
|
||||
'value': 'off'
|
||||
}, ensure_ascii=False)
|
||||
}])
|
||||
|
||||
def action_view_logs(self):
|
||||
"""查看该设备的日志"""
|
||||
self.ensure_one()
|
||||
return {
|
||||
'name': '考勤机日志',
|
||||
'type': 'ir.actions.act_window',
|
||||
'res_model': 'attendance.iot.log',
|
||||
'view_mode': 'tree,form',
|
||||
'domain': [('attendance_iot_id', '=', self.id)],
|
||||
'context': {'default_attendance_iot_id': self.id},
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
from odoo import api, fields, models
|
||||
|
||||
|
||||
class AttendanceIotLog(models.Model):
|
||||
_name = 'attendance.iot.log'
|
||||
_description = '考勤机日志'
|
||||
_order = 'create_date desc'
|
||||
|
||||
attendance_iot_id = fields.Many2one('attendance.iot', string="考勤机设备", required=True, ondelete='cascade')
|
||||
content = fields.Text(string="内容")
|
||||
@@ -5,4 +5,5 @@ access_attendance_iot_manager_wizard,attendance.iot.manager.wizard,model_attenda
|
||||
access_attendance_iot_datas,attendance.iot.datas,model_attendance_iot_datas,base.group_user,1,1,1,1
|
||||
access_attendance_iot_user,attendance.iot.user,model_attendance_iot_user,base.group_user,1,1,1,1
|
||||
access_iot_message,iot.message.user,model_iot_message,base.group_user,1,1,1,1
|
||||
access_attendance_iot_import_user_wizard,access.attendance.iot.import.user.wizard,model_attendance_iot_import_user_wizard,base.group_user,1,1,1,1
|
||||
access_attendance_iot_import_user_wizard,access.attendance.iot.import.user.wizard,model_attendance_iot_import_user_wizard,base.group_user,1,1,1,1
|
||||
access_attendance_iot_log,attendance.iot.log,model_attendance_iot_log,base.group_user,1,1,1,1
|
||||
|
@@ -0,0 +1,39 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<odoo>
|
||||
<!-- 考勤机日志 tree 视图 -->
|
||||
<record id="attendance_iot_log_tree" model="ir.ui.view">
|
||||
<field name="name">attendance.iot.log.tree</field>
|
||||
<field name="model">attendance.iot.log</field>
|
||||
<field name="arch" type="xml">
|
||||
<tree>
|
||||
<field name="attendance_iot_id"/>
|
||||
<field name="create_date" string="创建日期"/>
|
||||
<field name="content"/>
|
||||
</tree>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<!-- 考勤机日志 form 视图 -->
|
||||
<record id="attendance_iot_log_form" model="ir.ui.view">
|
||||
<field name="name">attendance.iot.log.form</field>
|
||||
<field name="model">attendance.iot.log</field>
|
||||
<field name="arch" type="xml">
|
||||
<form>
|
||||
<sheet>
|
||||
<group>
|
||||
<field name="attendance_iot_id"/>
|
||||
<field name="create_date" string="创建日期"/>
|
||||
<field name="content"/>
|
||||
</group>
|
||||
</sheet>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<!-- 考勤机日志 action -->
|
||||
<record id="attendance_iot_log_action" model="ir.actions.act_window">
|
||||
<field name="name">考勤机日志</field>
|
||||
<field name="res_model">attendance.iot.log</field>
|
||||
<field name="view_mode">tree,form</field>
|
||||
</record>
|
||||
</odoo>
|
||||
@@ -16,7 +16,9 @@
|
||||
<field name="company_id"/>
|
||||
<field name="number"/>
|
||||
<field name="remake"/>
|
||||
<field name="is_connected"/>
|
||||
<button name="open_record" type="object" string="详情" class="btn btn-blue"/>
|
||||
<button name="action_view_logs" type="object" string="日志" class="btn btn-blue"/>
|
||||
<button name="action_send_sync_sigle" type="object" string="同步数据" class="btn btn-blue"/>
|
||||
<button name="action_send_open_door_sigle" type="object" string="开门" class="btn btn-blue"/>
|
||||
<button name="action_send_close_door_sigle" type="object" string="关门" class="btn btn-blue"/>
|
||||
|
||||
@@ -37,13 +37,8 @@ class SoongWorkflowMixin(models.AbstractModel):
|
||||
# setattr(record, field, value)
|
||||
# return res
|
||||
|
||||
def write(self, vals):
|
||||
if self._context.get('_correction_skip'):
|
||||
return super(SoongWorkflowMixin, self).write(vals)
|
||||
for record in self:
|
||||
if record.is_modify:
|
||||
record._write({'is_modify': False})
|
||||
return super(SoongWorkflowMixin, self).write(vals)
|
||||
def action_is_modify(self):
|
||||
self.is_modify = False
|
||||
|
||||
@api.model
|
||||
def _compute_default_state(self):
|
||||
@@ -1318,6 +1313,13 @@ class SoongWorkflowMixin(models.AbstractModel):
|
||||
done_el.set("invisible", "1")
|
||||
header_el.append(done_el)
|
||||
|
||||
modify_btn_el = etree.SubElement(header_el, "button")
|
||||
modify_btn_el.set("name", "action_is_modify")
|
||||
modify_btn_el.set("string", "已修正")
|
||||
modify_btn_el.set("type", "object")
|
||||
modify_btn_el.set("invisible", "not is_modify")
|
||||
modify_btn_el.set("class", "btn btn-primary")
|
||||
|
||||
modify_el = etree.Element("field")
|
||||
modify_el.set("name", "is_modify")
|
||||
modify_el.set("invisible", "1")
|
||||
@@ -1460,7 +1462,7 @@ class SoongWorkflowMixin(models.AbstractModel):
|
||||
arr = []
|
||||
ext_ids = group._get_external_ids()
|
||||
for ext_id in ext_ids:
|
||||
arr.append(ext_ids[ext_id][0])
|
||||
arr.append(ext_ids[ext_id])
|
||||
return arr
|
||||
|
||||
if view_type == "form":
|
||||
|
||||
@@ -124,7 +124,6 @@ class SoongWorkflowRecord(models.Model):
|
||||
description=f"您有一条流水号为【{rec.code}】标题为【{rec.name}】流程待修正,请尽快修正",
|
||||
url=url, btntxt="详细信息")
|
||||
record = self.env[rec.res_model].sudo().browse(rec.res_id).exists()
|
||||
record = record.with_context(_correction_skip=True)
|
||||
record.is_modify = True
|
||||
|
||||
@api.returns('self', lambda value: value.id)
|
||||
|
||||
@@ -72,7 +72,8 @@
|
||||
<field name="is_log2" stirng="抄送"/>
|
||||
<field name="name"/>
|
||||
<field name="code"/>
|
||||
<field name="employee_ids" string="当前经办人" widget="many2one"/>
|
||||
<field name="documents_ids" string="附件"/>
|
||||
<field name="employee_ids" string="当前经办人"/>
|
||||
<field name="create_uid" string="创建人"/>
|
||||
</header_search>
|
||||
<searchpanel>
|
||||
|
||||
@@ -585,6 +585,60 @@ class SoongWorkflowCommentWizard(models.TransientModel):
|
||||
current_user = self.env.user
|
||||
current_datetime = fields.Datetime.now()
|
||||
is_admin = current_user.has_group('base.group_system')
|
||||
# 归档判断
|
||||
last_log = record_id.log_ids[-1] if record_id.log_ids else None
|
||||
if last_log:
|
||||
same_name_logs = record_id.log_ids.filtered(
|
||||
lambda log: log.name == last_log.name and log.node_btn_name == '4' and log.id != last_log.id
|
||||
)
|
||||
all_approved = all(log.approval_state in ['2', '3'] for log in same_name_logs) or not same_name_logs
|
||||
if all_approved:
|
||||
workflow_record = self.env['soong.workflow.record'].search([('code', '=', record_id.code)],
|
||||
limit=1)
|
||||
has_archive_btn = any(btn_name.name == '归档' for btn_name in self.node_btn_id.node_id.button_ids)
|
||||
if has_archive_btn:
|
||||
log_id = record_id.log_ids.filtered(lambda l: l.name == '归档')
|
||||
employee_id = self.env['hr.employee'].sudo().search(
|
||||
[('user_id', '=', record_id.log_ids[0].done_by.id)], limit=1)
|
||||
if workflow_record:
|
||||
workflow_record.write({
|
||||
'approve_state': 'end',
|
||||
'employee_ids': [(6, 0, [employee_id.id])],
|
||||
'soong_state': 'to_active',
|
||||
'node_id': False,
|
||||
})
|
||||
if not log_id:
|
||||
self.env["soong.workflow.log"].create({
|
||||
'name': '归档',
|
||||
"code": self.code,
|
||||
"model": self.res_model,
|
||||
"res_id": self.res_id,
|
||||
"workflow_id": self.node_btn_id.workflow_id.id,
|
||||
"done_by": record_id.log_ids[0].done_by.id,
|
||||
"approval_state": "0",
|
||||
"node_btn_id": self.node_btn_id.id,
|
||||
})
|
||||
is_work_remind = True
|
||||
else:
|
||||
log_id.write({
|
||||
'document_ids': [(6, 0, self.document_ids.ids)],
|
||||
"approval_state": "2",
|
||||
'lase_click_date': fields.Datetime.now(),
|
||||
})
|
||||
workflow_record.write({
|
||||
'soong_state': 'active',
|
||||
'employee_ids': False,
|
||||
})
|
||||
else:
|
||||
if workflow_record:
|
||||
workflow_record.sudo().write({
|
||||
'approve_state': 'end',
|
||||
'employee_ids': False,
|
||||
'node_id': False,
|
||||
'soong_state': 'done',
|
||||
})
|
||||
record_id.work_end = True
|
||||
|
||||
if is_admin:
|
||||
user_log = record_id.log_ids.filtered(
|
||||
lambda log: log.done_by == current_user and log.node_btn_name != '1' and log.approval_state == '0'
|
||||
@@ -679,58 +733,7 @@ class SoongWorkflowCommentWizard(models.TransientModel):
|
||||
title=record_id._description + "传阅/抄送",
|
||||
description=description, url=url,
|
||||
btntxt="查看详情")
|
||||
# if not record_id.log_ids2.search([('approval_state', '=', '0')]) or record_id.log_ids2:
|
||||
last_log = record_id.log_ids[-1] if record_id.log_ids else None
|
||||
if last_log:
|
||||
same_name_logs = record_id.log_ids.filtered(
|
||||
lambda log: log.name == last_log.name and log.node_btn_name == '4' and log.id != last_log.id
|
||||
)
|
||||
all_approved = all(log.approval_state in ['2', '3'] for log in same_name_logs) or not same_name_logs
|
||||
if all_approved:
|
||||
workflow_record = self.env['soong.workflow.record'].search([('code', '=', record_id.code)],
|
||||
limit=1)
|
||||
has_archive_btn = any(btn_name.name == '归档' for btn_name in self.node_btn_id.node_id.button_ids)
|
||||
if has_archive_btn:
|
||||
log_id = record_id.log_ids.filtered(lambda l: l.name == '归档')
|
||||
employee_id = self.env['hr.employee'].sudo().search([('user_id', '=', record_id.log_ids[0].done_by.id)], limit=1)
|
||||
if workflow_record:
|
||||
workflow_record.write({
|
||||
'approve_state': 'end',
|
||||
'employee_ids': [(6, 0, [employee_id.id])],
|
||||
'soong_state': 'to_active',
|
||||
'node_id': False,
|
||||
})
|
||||
if not log_id:
|
||||
self.env["soong.workflow.log"].create({
|
||||
'name': '归档',
|
||||
"code": self.code,
|
||||
"model": self.res_model,
|
||||
"res_id": self.res_id,
|
||||
"workflow_id": self.node_btn_id.workflow_id.id,
|
||||
"done_by": record_id.log_ids[0].done_by.id,
|
||||
"approval_state": "0",
|
||||
"node_btn_id": self.node_btn_id.id,
|
||||
})
|
||||
is_work_remind = True
|
||||
else:
|
||||
log_id.write({
|
||||
'document_ids': [(6, 0, self.document_ids.ids)],
|
||||
"approval_state": "2",
|
||||
'lase_click_date': fields.Datetime.now(),
|
||||
})
|
||||
workflow_record.write({
|
||||
'soong_state': 'active',
|
||||
'employee_ids': False,
|
||||
})
|
||||
else:
|
||||
if workflow_record:
|
||||
workflow_record.sudo().write({
|
||||
'approve_state': 'end',
|
||||
'employee_ids': False,
|
||||
'node_id': False,
|
||||
'soong_state': 'done',
|
||||
})
|
||||
record_id.work_end = True
|
||||
|
||||
# 给申请人发消息
|
||||
if is_work_remind:
|
||||
biz_record = self.env[self.res_model].browse(self.res_id)
|
||||
|
||||
@@ -5,7 +5,7 @@ import { patch } from "@web/core/utils/patch";
|
||||
import { deepCopy } from "@web/core/utils/objects";
|
||||
import { useService } from "@web/core/utils/hooks";
|
||||
import { url } from "@web/core/utils/urls";
|
||||
import { clickRefreshButton} from "../actions/client_actions";
|
||||
import { clickRefreshButton } from "../actions/client_actions";
|
||||
|
||||
const WKF_NOTIFY_TYPE = 'wkf_notify'
|
||||
|
||||
@@ -17,10 +17,11 @@ patch(NavBar.prototype, {
|
||||
this.audio.src = this.audio.canPlayType("audio/ogg; codecs=vorbis")
|
||||
? url("/mail/static/src/audio/ting.ogg")
|
||||
: url("/mail/static/src/audio/ting.mp3");
|
||||
|
||||
const clearCache = () => this.env.bus.trigger("CLEAR-CACHES");
|
||||
const play = () => {
|
||||
return this.audio.play()
|
||||
.then(() => {
|
||||
clearCache()
|
||||
clickRefreshButton()
|
||||
})
|
||||
.catch((e) => {
|
||||
@@ -28,13 +29,13 @@ patch(NavBar.prototype, {
|
||||
});
|
||||
}
|
||||
/**
|
||||
* 监听后端发送的信号,重新加载菜单数据
|
||||
* 监听后端发送的信号,重新加载菜单数据,清除viewSevice的缓存
|
||||
* 1. 通知类型为WKF_NOTIFY_TYPE时,直接刷新菜单播放音频
|
||||
* 2. 其余则通过菜单badge_count对比
|
||||
*/
|
||||
this.busService.subscribe("sun_badge_menu.reload_menu_data", (detail) => {
|
||||
console.log('[sun_badge_menu.reload_menu_data]重新加载数据...')
|
||||
debugger
|
||||
// debugger
|
||||
for (const d of detail) {
|
||||
if (d?.type === WKF_NOTIFY_TYPE) {
|
||||
this.menuService.reload();
|
||||
@@ -48,7 +49,7 @@ patch(NavBar.prototype, {
|
||||
return value ? value.reduce((count, app) => count + (app?.badge_count || 0), 0) : 0;
|
||||
}
|
||||
browser.setTimeout(() => {
|
||||
debugger
|
||||
// debugger
|
||||
const oldCount = getReduceCount(oldMenuApps)
|
||||
const newMenuApps = this.menuService.getApps()
|
||||
const newCount = getReduceCount(newMenuApps)
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
/** @odoo-module **/
|
||||
|
||||
import { registry } from "@web/core/registry";
|
||||
|
||||
registry.category("user_menuitems").remove("documentation");
|
||||
registry.category("user_menuitems").remove("profile");
|
||||
@@ -12,10 +12,10 @@
|
||||
<menuitem id="yuthon_catering_conf_root_menu" name="配置" sequence="99"/>
|
||||
</menuitem>
|
||||
<!-- 餐费报表(员工)一级菜单 -->
|
||||
<menuitem id="yuthon_salary_meal_views_menu_employee"
|
||||
name="餐费报表(员工)"
|
||||
action="yuthon_salary.view_yuthon_meal_expenses_action_readonly"
|
||||
sequence="2"
|
||||
web_icon="yuthon_catering,static/description/catering.png"/>
|
||||
<!-- <menuitem id="yuthon_salary_meal_views_menu_employee"-->
|
||||
<!-- name="餐费报表(员工)"-->
|
||||
<!-- action="yuthon_salary.view_yuthon_meal_expenses_action_readonly"-->
|
||||
<!-- sequence="2"-->
|
||||
<!-- web_icon="yuthon_catering,static/description/catering.png"/>-->
|
||||
</data>
|
||||
</odoo>
|
||||
@@ -214,71 +214,36 @@ class HrLeaveAllocation(models.Model):
|
||||
return super(HrLeaveAllocation, self).unlink()
|
||||
|
||||
|
||||
def update_vacation(self):
|
||||
leave_ids = self.env["hr.leave.allocation"].browse(
|
||||
self._context.get('active_ids', self._context.get('active_id')))
|
||||
for leave in leave_ids:
|
||||
leave_list = []
|
||||
compensatory_list = []
|
||||
def action_validate(self):
|
||||
result = super(HrLeaveAllocation, self).action_validate()
|
||||
|
||||
for leave in self:
|
||||
if leave.holiday_status_id.name != '年假':
|
||||
continue
|
||||
|
||||
vacation_date = leave.date_from.replace(day=1) if leave.date_from else fields.Date.today().replace(day=1)
|
||||
|
||||
reports_id = self.env['yuthon.vacation.reports'].search([
|
||||
('employee_id', '=', leave.employee_id.id),
|
||||
('vacation_date', '=', leave.date_from)
|
||||
('vacation_date', '=', vacation_date)
|
||||
], limit=1)
|
||||
other_list = []
|
||||
|
||||
if leave.holiday_status_id.name == '年假':
|
||||
current_leave_hours = leave.number_of_days * 8
|
||||
existing_leave_line = False
|
||||
if reports_id and reports_id.leave_ids:
|
||||
existing_leave_line = reports_id.leave_ids.filtered(
|
||||
lambda l: l.text == '上月额度继承'
|
||||
)[:1]
|
||||
if existing_leave_line:
|
||||
update_leave_vals = {
|
||||
'valid_date': leave.date_to,
|
||||
}
|
||||
existing_leave_line.write(update_leave_vals)
|
||||
|
||||
leave_list.append([0, 0, {
|
||||
'vacation_id': reports_id.id,
|
||||
'update_type': 'add',
|
||||
'update_date': fields.Datetime.now(),
|
||||
'valid_date': leave.date_from,
|
||||
'update_lines': current_leave_hours,
|
||||
'text': '年假分配'
|
||||
}])
|
||||
|
||||
elif leave.holiday_status_id.name == '补休':
|
||||
compensatory_list.append([0, 0, {
|
||||
'vacation_id': reports_id.id,
|
||||
'employee_id': reports_id.employee_id.id,
|
||||
'update_type': 'add',
|
||||
'valid_date': leave.date_from,
|
||||
'workday': leave.number_of_hours_display,
|
||||
'legal_day': 0,
|
||||
'public_holidays': 0,
|
||||
'meal_number': 0,
|
||||
'text': f"上月额度继承"
|
||||
}])
|
||||
else:
|
||||
other_list.append([0, 0, {
|
||||
'vacation_id': reports_id.id,
|
||||
'holiday_type': leave.holiday_status_id.id,
|
||||
'employee_id': leave.employee_id.id,
|
||||
'update_date': fields.Date.today(),
|
||||
'update_type': 'add',
|
||||
'lines': leave.number_of_hours_display / 8,
|
||||
'text': leave.name
|
||||
}])
|
||||
|
||||
|
||||
if reports_id:
|
||||
leave_hours = leave.number_of_days_display * 8
|
||||
reports_id.write({
|
||||
'leave_ids': leave_list,
|
||||
'year_distribution': leave.number_of_days,
|
||||
'valid_date': leave.date_to,
|
||||
'overtime_ids': compensatory_list,
|
||||
'other_fee_ids': other_list
|
||||
'leave_ids': [(0, 0, {
|
||||
'vacation_id': reports_id.id,
|
||||
'update_type': 'add',
|
||||
'update_date': fields.Datetime.now(),
|
||||
'valid_date': leave.date_from,
|
||||
'update_lines': leave_hours,
|
||||
'text': '年假分配'
|
||||
})]
|
||||
})
|
||||
reports_id.update_line()
|
||||
|
||||
return result
|
||||
|
||||
def update_employee(self):
|
||||
leave_ids = self.env["hr.leave.allocation"].browse(
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
<field name="name">yuthon.holiday.allocation.form</field>
|
||||
<field name="model">hr.leave.allocation</field>
|
||||
<field name="inherit_id" ref="hr_holidays.hr_leave_allocation_view_form_manager"/>
|
||||
<field name="priority" eval="100"/>
|
||||
<field name="arch" type="xml">
|
||||
<xpath expr="//form" position="attributes">
|
||||
<attribute name="create">0</attribute>
|
||||
@@ -37,6 +38,7 @@
|
||||
<field name="name">yuthon.holiday.allocation.form2</field>
|
||||
<field name="model">hr.leave.allocation</field>
|
||||
<field name="inherit_id" ref="hr_holidays.hr_leave_allocation_view_form"/>
|
||||
<field name="priority" eval="100"/>
|
||||
<field name="arch" type="xml">
|
||||
<xpath expr="//form" position="attributes">
|
||||
<attribute name="create">0</attribute>
|
||||
@@ -69,13 +71,6 @@
|
||||
<field name="state">code</field>
|
||||
<field name="code">action = model.action_uninstall_wizard()</field>
|
||||
</record>
|
||||
<record id="all_holiday_update_vacation" model="ir.actions.server">
|
||||
<field name="name">更新报表</field>
|
||||
<field name="model_id" ref="hr_holidays.model_hr_leave_allocation"/>
|
||||
<field name="binding_model_id" ref="hr_holidays.model_hr_leave_allocation"/>
|
||||
<field name="state">code</field>
|
||||
<field name="code">action = model.update_vacation()</field>
|
||||
</record>
|
||||
<record id="all_one_time" model="ir.actions.server">
|
||||
<field name="name">更新结束时间</field>
|
||||
<field name="model_id" ref="hr_holidays.model_hr_leave_allocation"/>
|
||||
|
||||
@@ -79,6 +79,8 @@ class CustomerPortal(portal.CustomerPortal):
|
||||
num = float(value or 0) * multiply
|
||||
if num == 0:
|
||||
return "0"
|
||||
if unit == "小时":
|
||||
return f"{round(num, 1)}{unit}"
|
||||
return f"{num}{unit}"
|
||||
|
||||
data = {
|
||||
|
||||
@@ -27,19 +27,19 @@
|
||||
<field name="numbercall">-1</field>
|
||||
<field eval="False" name="doall"/>
|
||||
</record>
|
||||
<record forcecreate="True" id="attendance_missing_card_judgment" model="ir.cron">
|
||||
<field name="name">定时任务:考勤缺卡判断</field>
|
||||
<field name="model_id" ref="model_hr_attendance"/>
|
||||
<field name="state">code</field>
|
||||
<field name="code">model.missing_card_judgment()</field>
|
||||
<field eval="True" name="active"/>
|
||||
<field name="user_id" ref="base.user_root"/>
|
||||
<field name="interval_type">days</field>
|
||||
<field name="interval_number">1</field>
|
||||
<field name="nextcall" eval="(DateTime.now()).strftime('%Y-%m-%d 23:00:00')"/>
|
||||
<field name="numbercall">-1</field>
|
||||
<field eval="False" name="doall"/>
|
||||
</record>
|
||||
<!-- <record forcecreate="True" id="attendance_missing_card_judgment" model="ir.cron">-->
|
||||
<!-- <field name="name">定时任务:考勤缺卡判断</field>-->
|
||||
<!-- <field name="model_id" ref="model_hr_attendance"/>-->
|
||||
<!-- <field name="state">code</field>-->
|
||||
<!-- <field name="code">model.missing_card_judgment()</field>-->
|
||||
<!-- <field eval="True" name="active"/>-->
|
||||
<!-- <field name="user_id" ref="base.user_root"/>-->
|
||||
<!-- <field name="interval_type">days</field>-->
|
||||
<!-- <field name="interval_number">1</field>-->
|
||||
<!-- <field name="nextcall" eval="(DateTime.now()).strftime('%Y-%m-%d 23:00:00')"/>-->
|
||||
<!-- <field name="numbercall">-1</field>-->
|
||||
<!-- <field eval="False" name="doall"/>-->
|
||||
<!-- </record>-->
|
||||
|
||||
<!-- 粮库相关提醒 -->
|
||||
<record forcecreate="True" id="card_lc_remind_time_in" model="ir.cron">
|
||||
|
||||
@@ -1315,6 +1315,8 @@ class HrAttendance(models.Model):
|
||||
'absenteeism_card': False
|
||||
})
|
||||
return
|
||||
if self.workflow_id.res_model == 'overtime.approval':
|
||||
return
|
||||
current_date_start = datetime.combine(current_date, datetime.min.time()) # 当天 00:00:00 datetime类型
|
||||
current_date_end = datetime.combine(current_date, datetime.max.time()) # 当天 23:59:59 datetime类型
|
||||
|
||||
|
||||
@@ -208,16 +208,16 @@ class HrAttendanceDetail(models.Model):
|
||||
|
||||
if checkin_datetime > sch_check_out_time:
|
||||
message = f"打卡成功!今日下班时间:{record.checkin_time + timedelta(hours=8)}: {employee_id.name},祝您归途平安!"
|
||||
# if record.employee_id.name not in ['蒋彬', '麦丽娜']:
|
||||
self.sudo().env["wecom.apps"].sync_send_message(
|
||||
category='att', user_id=employee_id.wecom_userid,
|
||||
message=message,
|
||||
)
|
||||
# if record.employee_id.name in ['蒋彬', '麦丽娜']:
|
||||
# self.sudo().env["wecom.apps"].sync_send_message(
|
||||
# category='att', user_id='18562027762',
|
||||
# message=message + f'管理员测试管理员测试{vals}',
|
||||
# )
|
||||
if record.employee_id.name not in ['林伟东']:
|
||||
self.sudo().env["wecom.apps"].sync_send_message(
|
||||
category='att', user_id=employee_id.wecom_userid,
|
||||
message=message,
|
||||
)
|
||||
else:
|
||||
self.sudo().env["wecom.apps"].sync_send_message(
|
||||
category='att', user_id='18562027762',
|
||||
message=message + f'管理员测试管理员测试{vals}',
|
||||
)
|
||||
self.write({'remark': message})
|
||||
_logger.info(message)
|
||||
|
||||
|
||||
@@ -527,6 +527,7 @@ class OvertimeApprovals(models.Model):
|
||||
def _compute_overtime_type(self):
|
||||
for record in self:
|
||||
current_date = datetime.today()
|
||||
record.type_overtime = 'work'
|
||||
if record.start_time and record.end_time:
|
||||
if record.start_time > record.end_time:
|
||||
raise UserError("开始时间不能晚于结束时间")
|
||||
@@ -554,10 +555,16 @@ class OvertimeApprovals(models.Model):
|
||||
date_str = start_date.strftime('%m月%d日')
|
||||
date_str = self.remove_leading_zero(date_str)
|
||||
is_weekend = start_date.weekday() in [5, 6]
|
||||
if date_str in statutory_set:
|
||||
# 调班补班日
|
||||
if date_str in shift_days_set:
|
||||
record.type_overtime = 'work'
|
||||
# 法定节假日
|
||||
elif date_str in statutory_set:
|
||||
record.type_overtime = 'holiday'
|
||||
# 周末 或 调休日
|
||||
elif date_str in holidays_set or is_weekend:
|
||||
record.type_overtime = 'weekend'
|
||||
# 普通工作日
|
||||
else:
|
||||
record.type_overtime = 'work'
|
||||
|
||||
|
||||
@@ -76,7 +76,7 @@ class YuthonVacationReports(models.Model):
|
||||
show_date = fields.Date(string='日期', compute='_compute_display_date', store=True)
|
||||
display_date = fields.Char(string='日期', compute='_compute_display_date')
|
||||
done_leave = fields.Float(string='年假', compute='_compute_leave', store=True, digits=(16, 3), group_operator=None)
|
||||
done_working_overtime = fields.Float(string='加班时', compute='_compute_working_overtime', digits=(16, 3),
|
||||
done_working_overtime = fields.Float(string='加班时', compute='_compute_working_overtime', digits=(16, 1),
|
||||
store=True, group_operator=None)
|
||||
leave = fields.Float(string='剩余年假d', compute='_compute_leave', store=True, digits=(16, 3), group_operator=None)
|
||||
working_overtime = fields.Float(string='剩余补休d', compute='_compute_working_overtime', store=True,
|
||||
@@ -400,13 +400,14 @@ class YuthonVacationReports(models.Model):
|
||||
|
||||
# 2. 剩余部分扣减本年补休剩余(this_year1)
|
||||
if remaining_overtime_deduct > 0 and rec.this_year1 > 0:
|
||||
deduct_from_current1 = min(rec.this_year1, remaining_overtime_deduct)
|
||||
deduct_from_current1 = remaining_overtime_deduct
|
||||
rec.this_year1 -= deduct_from_current1
|
||||
rec.used_this_year1 += deduct_from_current1 # 累加到本年已休
|
||||
remaining_overtime_deduct -= deduct_from_current1
|
||||
|
||||
rec._compute_leave()
|
||||
rec._compute_meal_fee()
|
||||
rec._compute_parental_leave()
|
||||
rec._compute_working_overtime()
|
||||
|
||||
def update_vacation(self):
|
||||
@@ -823,13 +824,23 @@ class YuthonVacationReports(models.Model):
|
||||
is_late = is_early = is_no = is_work = is_abnormal = 0
|
||||
probation_days = regular_days = expatriation_days = 0
|
||||
actual_attendance = leave_total_days = 0
|
||||
is_retired = rec.employee_id.user_state in ('leave', 'withdraw')
|
||||
is_retired = False
|
||||
employee = rec.employee_id
|
||||
vacation_date = rec.vacation_date # 每月1号
|
||||
if employee and vacation_date:
|
||||
if employee.user_state in ('leave', 'withdraw'):
|
||||
contract = employee.contract_id
|
||||
leave_date = False
|
||||
# 优先取合同中止日期
|
||||
if contract and contract.end_date:
|
||||
leave_date = contract.end_date
|
||||
if leave_date and leave_date >= vacation_date:
|
||||
is_retired = False
|
||||
else:
|
||||
is_retired = True
|
||||
|
||||
# 核心:外出天数统计(按workflow_id去重)
|
||||
go_out_days = 0.0 # 外出总天数
|
||||
processed_workflow_ids = set() # 已处理的workflow_id(去重)
|
||||
|
||||
# 外派相关变量
|
||||
go_out_days = 0.0
|
||||
processed_workflow_ids = set()
|
||||
is_outside = exp_has_return = False
|
||||
exp_start_date = exp_end_return = exp_end_date = None
|
||||
|
||||
@@ -1535,10 +1546,10 @@ class YuthonVacationReports(models.Model):
|
||||
|
||||
if rec.remain_missed_meals:
|
||||
self._update_meal_lines(rec, [rec], rec.remain_missed_meals)
|
||||
if rec.leave:
|
||||
if rec.leave != 0:
|
||||
leave_hours = rec.leave * 8
|
||||
self._update_leave_lines(rec, [rec], leave_hours)
|
||||
if rec.working_overtime:
|
||||
if rec.working_overtime != 0:
|
||||
overtime_hours = rec.working_overtime * 8
|
||||
self._update_over_lines(rec, [rec], overtime_hours)
|
||||
if rec.employee_id.id not in target_employee_ids:
|
||||
@@ -1705,8 +1716,8 @@ class YuthonVacationReports(models.Model):
|
||||
if other_line.holiday_type and other_line.holiday_type.name == '调休':
|
||||
adjust_holiday_days += other_line.lines or 0
|
||||
|
||||
record.working_overtime = max(total_add / 8, 0) + adjust_holiday_days
|
||||
record.done_working_overtime = total_add1 / 8
|
||||
record.working_overtime = (total_add / 8) + adjust_holiday_days
|
||||
record.done_working_overtime = total_add1
|
||||
record.statutory_leave = legal_total/8
|
||||
record.cop_leave = total_add2 / 8
|
||||
|
||||
@@ -1980,15 +1991,18 @@ class YuthonVacationReports(models.Model):
|
||||
('text', '=', '上月额度继承'),
|
||||
], limit=1)
|
||||
if existing_line:
|
||||
continue
|
||||
self.env['vacation.parenting.line'].sudo().create({
|
||||
'vacation_id': report.id,
|
||||
'employee_id': report.employee_id.id,
|
||||
'update_date': update_date,
|
||||
'end_date': end_date,
|
||||
'lines': number_of_hours_display,
|
||||
'text': f"上月额度继承",
|
||||
})
|
||||
existing_line.write({
|
||||
'lines': number_of_hours_display,
|
||||
})
|
||||
else:
|
||||
self.env['vacation.parenting.line'].sudo().create({
|
||||
'vacation_id': report.id,
|
||||
'employee_id': report.employee_id.id,
|
||||
'update_date': update_date,
|
||||
'end_date': end_date,
|
||||
'lines': number_of_hours_display,
|
||||
'text': f"上月额度继承",
|
||||
})
|
||||
|
||||
def _update_meal_lines(self, report, allocations, number_of_hours_display):
|
||||
for alloc in allocations:
|
||||
|
||||
@@ -95,19 +95,19 @@
|
||||
<field name="hospital_sick_leave" options='{ "fg_color": "white: hospital_sick_leave == False"}'/>
|
||||
<field name="recovery_sick_leave" options='{ "fg_color": "white: recovery_sick_leave == False"}'/>
|
||||
<field name="exam_leave" options='{ "fg_color": "white: exam_leave == False"}'/>
|
||||
<field name="previous_year"/>
|
||||
<field name="valid_date"/>
|
||||
<field name="year_distribution"/>
|
||||
<field name="used_this_year"/>
|
||||
<field name="remainder_year"/>
|
||||
<field name="last_holiday"/>
|
||||
<field name="last_workday"/>
|
||||
<field name="valid_date1"/>
|
||||
<field name="year_holiday"/>
|
||||
<field name="year_workday"/>
|
||||
<field name="year_sum"/>
|
||||
<field name="used_this_year1"/>
|
||||
<field name="working_overtime"/>
|
||||
<field name="previous_year" column_invisible="1"/>
|
||||
<field name="valid_date" column_invisible="1"/>
|
||||
<field name="year_distribution" column_invisible="1"/>
|
||||
<field name="used_this_year" column_invisible="1"/>
|
||||
<field name="remainder_year" column_invisible="1"/>
|
||||
<field name="last_holiday" column_invisible="1"/>
|
||||
<field name="last_workday" column_invisible="1"/>
|
||||
<field name="valid_date1" column_invisible="1"/>
|
||||
<field name="year_holiday" column_invisible="1"/>
|
||||
<field name="year_workday" column_invisible="1"/>
|
||||
<field name="year_sum" column_invisible="1"/>
|
||||
<field name="used_this_year1" column_invisible="1"/>
|
||||
<field name="working_overtime" column_invisible="1"/>
|
||||
<button name="log" type="object" string="详情" class="oe_highlight"/>
|
||||
<button name="button_put" string="发送" invisible="vacation_state == 'confirmed'" type="object"
|
||||
class="oe_highlight"/>
|
||||
@@ -849,13 +849,13 @@
|
||||
(0, 0, {'view_mode': 'tree', 'view_id': ref('yuthon_hr_attendance.view_yuthon_vacation_my_reports_tree')}),
|
||||
(0, 0, {'view_mode': 'form', 'view_id': ref('yuthon_hr_attendance.view_yuthon_vacation_reports_form1')})]"/>
|
||||
</record>
|
||||
<record id="all_vacation_delete" model="ir.actions.server">
|
||||
<field name="name">初始化日志</field>
|
||||
<field name="model_id" ref="yuthon_hr_attendance.model_yuthon_vacation_reports"/>
|
||||
<field name="binding_model_id" ref="yuthon_hr_attendance.model_yuthon_vacation_reports"/>
|
||||
<field name="state">code</field>
|
||||
<field name="code">action = model.vacation_delete()</field>
|
||||
</record>
|
||||
<!-- <record id="all_vacation_delete" model="ir.actions.server">-->
|
||||
<!-- <field name="name">初始化日志</field>-->
|
||||
<!-- <field name="model_id" ref="yuthon_hr_attendance.model_yuthon_vacation_reports"/>-->
|
||||
<!-- <field name="binding_model_id" ref="yuthon_hr_attendance.model_yuthon_vacation_reports"/>-->
|
||||
<!-- <field name="state">code</field>-->
|
||||
<!-- <field name="code">action = model.vacation_delete()</field>-->
|
||||
<!-- </record>-->
|
||||
<record id="all_put" model="ir.actions.server">
|
||||
<field name="name">发送确认提醒</field>
|
||||
<field name="model_id" ref="yuthon_hr_attendance.model_yuthon_vacation_reports"/>
|
||||
@@ -863,13 +863,14 @@
|
||||
<field name="state">code</field>
|
||||
<field name="code">action = model.all_put()</field>
|
||||
</record>
|
||||
<record id="all_confirm" model="ir.actions.server">
|
||||
<field name="name">批量确认</field>
|
||||
<field name="model_id" ref="yuthon_hr_attendance.model_yuthon_vacation_reports"/>
|
||||
<field name="binding_model_id" ref="yuthon_hr_attendance.model_yuthon_vacation_reports"/>
|
||||
<field name="state">code</field>
|
||||
<field name="code">action = model.all_confirm()</field>
|
||||
</record>
|
||||
<!-- <record id="all_confirm" model="ir.actions.server">-->
|
||||
<!-- <field name="name">批量确认</field>-->
|
||||
<!-- <field name="model_id" ref="yuthon_hr_attendance.model_yuthon_vacation_reports"/>-->
|
||||
<!-- <field name="binding_model_id" ref="yuthon_hr_attendance.model_yuthon_vacation_reports"/>-->
|
||||
<!-- <field name="state">code</field>-->
|
||||
<!-- <field name="code">action = model.all_confirm()</field>-->
|
||||
<!-- <field name="groups_id" eval="[(4, ref('hr_payroll.group_hr_payroll_manager'))]"/>-->
|
||||
<!-- </record>-->
|
||||
<record id="all_carryover" model="ir.actions.server">
|
||||
<field name="name">加班费结转</field>
|
||||
<field name="model_id" ref="yuthon_hr_attendance.model_yuthon_vacation_reports"/>
|
||||
@@ -883,22 +884,22 @@
|
||||
<field name="binding_model_id" ref="yuthon_hr_attendance.model_yuthon_vacation_reports"/>
|
||||
<field name="state">code</field>
|
||||
<field name="code">action = model.manage_confirmation()</field>
|
||||
<field name="groups_id" eval="[(4, ref('base.group_system'))]"/>
|
||||
</record>
|
||||
<record id="all_update_vacation" model="ir.actions.server">
|
||||
<field name="name">更新初始(1月)数据</field>
|
||||
<field name="model_id" ref="yuthon_hr_attendance.model_yuthon_vacation_reports"/>
|
||||
<field name="binding_model_id" ref="yuthon_hr_attendance.model_yuthon_vacation_reports"/>
|
||||
<field name="state">code</field>
|
||||
<field name="code">action = model.update_vacation()</field>
|
||||
</record>
|
||||
<record id="import_initial_data" model="ir.actions.server">
|
||||
<field name="name">导入初始数据</field>
|
||||
<field name="model_id" ref="yuthon_hr_attendance.model_yuthon_vacation_reports"/>
|
||||
<field name="binding_model_id" ref="yuthon_hr_attendance.model_yuthon_vacation_reports"/>
|
||||
<field name="state">code</field>
|
||||
<field name="code">action = model.import_initial_data()</field>
|
||||
<field name="groups_id" eval="[(4, ref('hr_payroll.group_hr_payroll_manager'))]"/>
|
||||
</record>
|
||||
<!-- <record id="all_update_vacation" model="ir.actions.server">-->
|
||||
<!-- <field name="name">更新初始(1月)数据</field>-->
|
||||
<!-- <field name="model_id" ref="yuthon_hr_attendance.model_yuthon_vacation_reports"/>-->
|
||||
<!-- <field name="binding_model_id" ref="yuthon_hr_attendance.model_yuthon_vacation_reports"/>-->
|
||||
<!-- <field name="state">code</field>-->
|
||||
<!-- <field name="code">action = model.update_vacation()</field>-->
|
||||
<!-- </record>-->
|
||||
<!-- <record id="import_initial_data" model="ir.actions.server">-->
|
||||
<!-- <field name="name">导入初始数据</field>-->
|
||||
<!-- <field name="model_id" ref="yuthon_hr_attendance.model_yuthon_vacation_reports"/>-->
|
||||
<!-- <field name="binding_model_id" ref="yuthon_hr_attendance.model_yuthon_vacation_reports"/>-->
|
||||
<!-- <field name="state">code</field>-->
|
||||
<!-- <field name="code">action = model.import_initial_data()</field>-->
|
||||
<!-- </record>-->
|
||||
<record id="all_update_line" model="ir.actions.server">
|
||||
<field name="name">批量重新计算</field>
|
||||
<field name="model_id" ref="yuthon_hr_attendance.model_yuthon_vacation_reports"/>
|
||||
@@ -906,27 +907,27 @@
|
||||
<field name="state">code</field>
|
||||
<field name="code">action = model.all_update_line()</field>
|
||||
</record>
|
||||
<record id="all_update_working_overtime" model="ir.actions.server">
|
||||
<field name="name">一次性</field>
|
||||
<field name="model_id" ref="yuthon_hr_attendance.model_yuthon_vacation_reports"/>
|
||||
<field name="binding_model_id" ref="yuthon_hr_attendance.model_yuthon_vacation_reports"/>
|
||||
<field name="state">code</field>
|
||||
<field name="code">action = model.update_is_visible()</field>
|
||||
</record>
|
||||
<record id="all_update_data" model="ir.actions.server">
|
||||
<field name="name">更新报表</field>
|
||||
<field name="model_id" ref="yuthon_hr_attendance.model_yuthon_vacation_reports"/>
|
||||
<field name="binding_model_id" ref="yuthon_hr_attendance.model_yuthon_vacation_reports"/>
|
||||
<field name="state">code</field>
|
||||
<field name="code">action = model.update_data()</field>
|
||||
</record>
|
||||
<record id="all_update_holiday" model="ir.actions.server">
|
||||
<field name="name">更新休假</field>
|
||||
<field name="model_id" ref="yuthon_hr_attendance.model_yuthon_vacation_reports"/>
|
||||
<field name="binding_model_id" ref="yuthon_hr_attendance.model_yuthon_vacation_reports"/>
|
||||
<field name="state">code</field>
|
||||
<field name="code">action = model.update_holiday()</field>
|
||||
</record>
|
||||
<!-- <record id="all_update_working_overtime" model="ir.actions.server">-->
|
||||
<!-- <field name="name">一次性</field>-->
|
||||
<!-- <field name="model_id" ref="yuthon_hr_attendance.model_yuthon_vacation_reports"/>-->
|
||||
<!-- <field name="binding_model_id" ref="yuthon_hr_attendance.model_yuthon_vacation_reports"/>-->
|
||||
<!-- <field name="state">code</field>-->
|
||||
<!-- <field name="code">action = model.update_is_visible()</field>-->
|
||||
<!-- </record>-->
|
||||
<!-- <record id="all_update_data" model="ir.actions.server">-->
|
||||
<!-- <field name="name">更新报表</field>-->
|
||||
<!-- <field name="model_id" ref="yuthon_hr_attendance.model_yuthon_vacation_reports"/>-->
|
||||
<!-- <field name="binding_model_id" ref="yuthon_hr_attendance.model_yuthon_vacation_reports"/>-->
|
||||
<!-- <field name="state">code</field>-->
|
||||
<!-- <field name="code">action = model.update_data()</field>-->
|
||||
<!-- </record>-->
|
||||
<!-- <record id="all_update_holiday" model="ir.actions.server">-->
|
||||
<!-- <field name="name">更新休假</field>-->
|
||||
<!-- <field name="model_id" ref="yuthon_hr_attendance.model_yuthon_vacation_reports"/>-->
|
||||
<!-- <field name="binding_model_id" ref="yuthon_hr_attendance.model_yuthon_vacation_reports"/>-->
|
||||
<!-- <field name="state">code</field>-->
|
||||
<!-- <field name="code">action = model.update_holiday()</field>-->
|
||||
<!-- </record>-->
|
||||
<record id="details_tree_view" model="ir.ui.view">
|
||||
<field name="name">details.tree.tree</field>
|
||||
<field name="model">details.tree</field>
|
||||
|
||||
@@ -140,7 +140,7 @@ class YuthonMedicalManage(models.Model):
|
||||
('user_state', '=', 'in'),
|
||||
('company_id.name', '=', '集团本部'),
|
||||
('contract_id.party_id', 'in', party_setting_records),
|
||||
('contract_id.is_probation', '=', False)
|
||||
('contract_type_id.name', '!=', '实习协议')
|
||||
])
|
||||
for employee in open_employees:
|
||||
medical_manage_rec = self.env['yuthon.medical.manage'].search([
|
||||
|
||||
@@ -750,4 +750,5 @@
|
||||
<!-- </xpath>-->
|
||||
<!-- </field>-->
|
||||
<!-- </record>-->
|
||||
<menuitem id="menu_personal_information" name="个人信息" parent="yuthon_work_brand.holiday_manage_menu_root_board" action="action_server_my_employee" sequence="45"/>
|
||||
</odoo>
|
||||
|
||||
@@ -246,12 +246,13 @@ class YuthonOnboardApproval(models.Model):
|
||||
})
|
||||
else:
|
||||
contract_type_id = self.env['hr.contract.type'].search([('name', '=', '正式合同(一签)')], limit=1)
|
||||
self.env['hr.contract'].create({
|
||||
new_contract = self.env['hr.contract'].create({
|
||||
'wage': salary,
|
||||
'job_id': self.job_id.id,
|
||||
'party_id': self.party_id.id,
|
||||
'salary_group_id': self.salary_group_id.id,
|
||||
'department_id': self.department_id1.id,
|
||||
'state': 'open',
|
||||
'employee_id': employee_id.id,
|
||||
'date_start': self.duration_employment,
|
||||
'contract_type_id': contract_type_id.id,
|
||||
@@ -263,7 +264,12 @@ class YuthonOnboardApproval(models.Model):
|
||||
'resource_calendar_id': resource_calendar_id.id,
|
||||
'is_probation': True,
|
||||
})
|
||||
|
||||
if new_contract.contract_type_id and new_contract.contract_type_id.name != '实习协议':
|
||||
cron_job = self.env['ir.cron'].sudo().search([
|
||||
('name', '=', '定时任务:体检费分配')
|
||||
], limit=1)
|
||||
if cron_job:
|
||||
cron_job.sudo().method_direct_trigger()
|
||||
vacation_date = self.duration_employment.replace(day=1)
|
||||
report_id = self.env['yuthon.vacation.reports'].search([('employee_id', '=', employee_id.id), ('vacation_date', '=', vacation_date)])
|
||||
if not report_id:
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
from odoo import models, fields, api
|
||||
from odoo.exceptions import UserError
|
||||
from dateutil.relativedelta import relativedelta
|
||||
import re
|
||||
|
||||
|
||||
class YuthonRegularizationPrepareApproval(models.Model):
|
||||
@@ -10,16 +11,20 @@ class YuthonRegularizationPrepareApproval(models.Model):
|
||||
|
||||
name = fields.Char(string="名称")
|
||||
department_id = fields.Many2one(related='users_id.employee_id.department_id', string="部门")
|
||||
users_id = fields.Many2one('res.users', string="申请人", default=lambda self: self.env.user.id)
|
||||
users_id = fields.Many2one('res.users', string="转正人", default=lambda self: self.env.user.id)
|
||||
confirmation_user_id = fields.Many2one('res.users', string="申请人")
|
||||
code = fields.Char(string="编号",
|
||||
default=lambda self: self.env['ir.sequence'].next_by_code('yuthon_regularization_approval_code'))
|
||||
structure_type_id = fields.Many2one('hr.payroll.structure.type', string="转正前职级")
|
||||
end_date = fields.Date(string="转正日期", compute="_compute_end_date")
|
||||
end_date = fields.Date(string="转正日期")
|
||||
|
||||
documents_id = fields.Many2one('ir.attachment', string="转正申请书")
|
||||
documents_id1 = fields.Many2one('ir.attachment', string="转正考核表")
|
||||
assessment_rating = fields.Char(string="考核评级")
|
||||
structure_type_id1 = fields.Many2one('hr.payroll.structure.type', string="转正后职级")
|
||||
is_leave_year = fields.Selection([('yes', '是'), ('no', '否')], string="是否分配年假")
|
||||
amount_days = fields.Float(string="年假天数")
|
||||
leave_allocate_attachment = fields.Many2one('ir.attachment', string="证明材料")
|
||||
is_adjust = fields.Boolean(string='是否调整')
|
||||
adjust_reason = fields.Text(string="调整原因")
|
||||
remake = fields.Text(string="备注")
|
||||
@@ -45,32 +50,110 @@ class YuthonRegularizationPrepareApproval(models.Model):
|
||||
else:
|
||||
self.is_adjust = False
|
||||
|
||||
@api.depends('users_id')
|
||||
def _compute_end_date(self):
|
||||
@api.onchange('users_id')
|
||||
def _onchange_users_id(self):
|
||||
for rec in self:
|
||||
rec.end_date = False
|
||||
if rec.users_id:
|
||||
rec.end_date = rec.users_id.employee_ids.contract_id.end_date + relativedelta(days=1)
|
||||
employee = rec.users_id.employee_ids[:1]
|
||||
if employee and employee.contract_id and employee.contract_id.end_date:
|
||||
rec.end_date = employee.contract_id.end_date + relativedelta(days=1)
|
||||
|
||||
def end_approval(self):
|
||||
for rec in self:
|
||||
version_str = rec.users_id.employee_ids.contract_id.version.lstrip('V')
|
||||
main_version = version_str.split('.')[0]
|
||||
contract_type_id = self.env['hr.contract.type'].search([('name', '=', '正式合同(一签)')], limit=1)
|
||||
new_main_version = int(main_version) + 1
|
||||
new_version = f"V{new_main_version}.0"
|
||||
original_contract = rec.users_id.employee_ids.contract_id
|
||||
original_contract.write({
|
||||
'state': 'cancel',
|
||||
})
|
||||
original_contract.write({'state': 'cancel'})
|
||||
|
||||
new_contract_vals = {
|
||||
'structure_type_id': rec.structure_type_id1.id,
|
||||
'version': new_version,
|
||||
'is_probation': False,
|
||||
'contract_type_id': contract_type_id.id,
|
||||
'state': 'open',
|
||||
}
|
||||
new_contract = original_contract.with_context(skip_contract_code_check=True).copy(new_contract_vals)
|
||||
rec.users_id.employee_ids.write({
|
||||
'contract_id': new_contract.id,
|
||||
})
|
||||
rec.users_id.employee_ids.write({'contract_id': new_contract.id})
|
||||
employee = rec.users_id.employee_ids
|
||||
cron_job = self.env['ir.cron'].sudo().search([
|
||||
('name', '=', '定时任务:体检费分配')
|
||||
], limit=1)
|
||||
if cron_job:
|
||||
cron_job.sudo().method_direct_trigger()
|
||||
if rec.is_leave_year == 'yes':
|
||||
end_date = rec.end_date
|
||||
amount_days = rec.amount_days
|
||||
amount_hours = amount_days * 8
|
||||
# ---------------------- 4. 固定有效期:9月1日 → 次年8月31日 (粮储)----------------------
|
||||
current_year = end_date.year
|
||||
# 开始日期:当年 9月1日
|
||||
date_from = f"{current_year}-09-01"
|
||||
|
||||
# 结束日期:次年 8月31日
|
||||
date_to = f"{current_year + 1}-08-31"
|
||||
first_day = end_date.replace(day=1)
|
||||
vacation_report = self.env['yuthon.vacation.reports'].search([
|
||||
('employee_id', '=', employee.id),
|
||||
('vacation_date', '=', first_day)
|
||||
], limit=1)
|
||||
# if not vacation_report:
|
||||
# continue
|
||||
holiday_status = self.env['hr.leave.type'].search([
|
||||
('name', 'ilike', '年假'),
|
||||
('company_id.name', '=', '天河粮储')
|
||||
], limit=1)
|
||||
alloc = self.sudo().env['hr.leave.allocation'].create({
|
||||
'name': f'年假发放',
|
||||
'employee_id': employee.id,
|
||||
'holiday_status_id': holiday_status.id,
|
||||
'number_of_days': amount_days,
|
||||
'date_from': date_from,
|
||||
'date_to': date_to,
|
||||
'allocation_type': 'regular',
|
||||
})
|
||||
alloc.action_validate()
|
||||
self.env['vacation.leave.line'].create({
|
||||
'vacation_id': vacation_report.id,
|
||||
'employee_id': employee.id,
|
||||
'update_type': 'add',
|
||||
'update_date': fields.Datetime.now(),
|
||||
'update_lines': round(amount_hours, 1),
|
||||
'allocation_type': 'allocation',
|
||||
'text': f'年假分配',
|
||||
})
|
||||
vacation_report.write({'valid_date': date_to})
|
||||
vacation_report.update_line()
|
||||
|
||||
@api.onchange('is_leave_year')
|
||||
def _onchange_is_leave_year(self):
|
||||
for rec in self:
|
||||
if rec.is_leave_year == 'yes':
|
||||
rec.amount_days = 0
|
||||
end_date = rec.end_date
|
||||
employee = rec.users_id.employee_ids
|
||||
# ---------------------- 1. 正则提取工龄 ----------------------
|
||||
work_year_str = employee.social_insurance_time or ''
|
||||
year_match = re.search(r'(\d+)年', work_year_str)
|
||||
work_years = int(year_match.group(1)) if year_match else 0
|
||||
# ---------------------- 2. 工龄对应年假天数 ----------------------
|
||||
if 1 <= work_years < 10:
|
||||
annual_days = 5
|
||||
elif 10 <= work_years < 20:
|
||||
annual_days = 10
|
||||
elif work_years >= 20:
|
||||
annual_days = 15
|
||||
else:
|
||||
annual_days = 0
|
||||
|
||||
if annual_days == 0:
|
||||
continue
|
||||
# ---------------------- 3. 计算额度:(12 - 转正月) / 12 ----------------------
|
||||
join_month = end_date.month
|
||||
rec.amount_days = round((12 - join_month) / 12 * annual_days, 1)
|
||||
|
||||
@api.onchange('is_issues')
|
||||
def _onchange_is_issues(self):
|
||||
|
||||
@@ -47,7 +47,7 @@ class YuthonRetiredApproval(models.Model):
|
||||
def end_approval(self):
|
||||
current_date = fields.Date.today()
|
||||
self.employee_id.contract_id.termination_date = self.expected_departure_date
|
||||
if current_date >= self.expected_departure_date:
|
||||
if not self.expected_departure_date or current_date >= self.expected_departure_date:
|
||||
self.employee_id.user_state = 'withdraw'
|
||||
if self.employee_id.contract_id:
|
||||
self.employee_id.contract_id.state = 'cancel'
|
||||
|
||||
@@ -50,12 +50,17 @@
|
||||
</group>
|
||||
<group col="2" string="审批详情">
|
||||
<group colspan="2">
|
||||
<field name="state" invisible="1"/>
|
||||
<field name="name" string="标题"/>
|
||||
<field name="is_back" invisible="1"/>
|
||||
<field name="confirmation_user_id" options="{'no_create': True}"/>
|
||||
<field name="users_id" options="{'no_create': True}"/>
|
||||
<field name="department_id" invisible="1"/>
|
||||
<field name="end_date"/>
|
||||
<field name="work_end" invisible="1"/>
|
||||
<field name="is_leave_year" invisible="state != '人事专员'" required="state == '人事专员'"/>
|
||||
<field name="amount_days" invisible="is_leave_year != 'yes'"/>
|
||||
<field name="leave_allocate_attachment" widget="preview_many2one" required="is_leave_year == 'yes'" invisible="is_leave_year != 'yes'"/>
|
||||
<field name="documents_id" widget="preview_many2one"/>
|
||||
</group>
|
||||
<!-- <field name="is_back" invisible="1"/>-->
|
||||
|
||||
@@ -74,7 +74,7 @@ class RoomBooking(models.Model):
|
||||
if '班子' in meeting_type_name:
|
||||
if meet.issue_library_id.is_class and (meet.issue_library_id.is_class_passed == 'reject' or not meet.issue_library_id.is_class_passed):
|
||||
meet.issue_library_id.class_char = str(
|
||||
record.start_datetime.date()) + f'第{record.number_of_meetings}' + record.meeting_type_id.name
|
||||
record.start_datetime.date()) + f'第{record.number_of_meetings}次' + record.meeting_type_id.name
|
||||
meet.issue_library_id.issue_state_class = 'meeting'
|
||||
meet.issue_library_id.issue_state = False
|
||||
|
||||
@@ -94,7 +94,7 @@ class RoomBooking(models.Model):
|
||||
meet.issue_library_id.issue_state = False
|
||||
elif meet.issue_library_id.is_class and (meet.issue_library_id.is_class_passed == 'r eject' or not meet.issue_library_id.is_class_passed):
|
||||
meet.issue_library_id.class_char = str(
|
||||
record.start_datetime.date()) + f'第{record.number_of_meetings}' + record.meeting_type_id.name
|
||||
record.start_datetime.date()) + f'第{record.number_of_meetings}次' + record.meeting_type_id.name
|
||||
meet.issue_library_id.issue_state_class = 'meeting'
|
||||
meet.issue_library_id.issue_state = False
|
||||
|
||||
|
||||
@@ -151,14 +151,10 @@ class IssueLibrary(models.Model):
|
||||
'target': 'current',
|
||||
}
|
||||
|
||||
def write(self, vals):
|
||||
if self._context.get('_correction_skip'):
|
||||
return super(IssueLibrary, self).write(vals)
|
||||
def action_is_modify(self):
|
||||
for rec in self:
|
||||
if rec.issue_state == 'to_modify':
|
||||
vals['issue_state'] = rec.original_issue_state
|
||||
vals['original_issue_state'] = False
|
||||
return super(IssueLibrary, self).write(vals)
|
||||
rec.issue_state = rec.original_issue_state
|
||||
rec.original_issue_state = False
|
||||
|
||||
def issue_party_approval(self):
|
||||
issue_active_ids = self.env["issue.library"].browse(
|
||||
@@ -326,7 +322,7 @@ class IssueLibrary(models.Model):
|
||||
title="议题修正",
|
||||
description="您有待修正的议题,请尽快修正",
|
||||
url=url, btntxt="详细信息")
|
||||
rec.with_context(_correction_skip=True).write({
|
||||
rec.write({
|
||||
'original_issue_state': rec.issue_state,
|
||||
'issue_state': 'to_modify',
|
||||
'is_confirm': True,
|
||||
|
||||
@@ -21,10 +21,10 @@
|
||||
<field name="boss_char"/>
|
||||
<field name="is_legal_trial"/>
|
||||
<field name="co_organizer_dept" readonly="not is_admin and issue_state not in ['to_do', 'cancel','to_modify', 'draft']"/>
|
||||
<field name="is_district_state"/>
|
||||
<field name="is_district_government"/>
|
||||
<field name="is_district_party"/>
|
||||
<field name="is_external_person"/>
|
||||
<field name="is_district_state" column_invisible="1"/>
|
||||
<field name="is_district_government" column_invisible="1"/>
|
||||
<field name="is_district_party" column_invisible="1"/>
|
||||
<field name="is_external_person" column_invisible="1"/>
|
||||
<field name="issue_state"/>
|
||||
<field name="code" column_invisible="1"/>
|
||||
<field name="company_id" column_invisible="1"/>
|
||||
@@ -150,6 +150,10 @@
|
||||
<field name="arch" type="xml">
|
||||
<form string="议题总库" create="0">
|
||||
<sheet>
|
||||
<header>
|
||||
<button name="action_is_modify" class="btn btn-primary" type="object"
|
||||
string="已修改" invisible="issue_state != 'to_modify'"/>
|
||||
</header>
|
||||
<widget name="web_ribbon" title="普件" bg_color="text-bg-success"
|
||||
invisible="urgency_level != 'normal'"/>
|
||||
<widget name="web_ribbon" title="急件" bg_color="text-bg-warning"
|
||||
@@ -387,16 +391,17 @@
|
||||
<button name="all_meeting_issue" type="object" string="会议安排" class="oe_highlight"/>
|
||||
<button name="issue_party1_approval" type="object" string="批量审批" class="oe_highlight"/>
|
||||
</header>
|
||||
<field name="name"/>
|
||||
<field name="name" column_invisible="1"/>
|
||||
<field name="name_text" class="list_width"/>
|
||||
<field name="department_id"/>
|
||||
<field name="creart_datetime"/>
|
||||
<field name="is_party" groups="yuthon_salary.group_jtbb_user" string="党总支"/>
|
||||
<field name="is_party" groups="yuthon_salary.group_lc_user,yuthon_salary.group_wg_user"
|
||||
string="党支部会"/>
|
||||
<field name="party_char"/>
|
||||
<field name="is_district_state"/>
|
||||
<field name="is_district_government"/>
|
||||
<field name="is_district_party"/>
|
||||
<field name="is_district_state" column_invisible="1"/>
|
||||
<field name="is_district_government" column_invisible="1"/>
|
||||
<field name="is_district_party" column_invisible="1"/>
|
||||
<field name="is_external_person"/>
|
||||
<field name="issue_state" string="审批状态" />
|
||||
<field name="issue_state_party"/>
|
||||
@@ -431,16 +436,17 @@
|
||||
<button name="all_meeting_issue" type="object" string="会议安排" class="oe_highlight"/>
|
||||
<button name="issue_party_approval" type="object" string="批量审批" class="oe_highlight"/>
|
||||
</header>
|
||||
<field name="name"/>
|
||||
<field name="name" column_invisible="1"/>
|
||||
<field name="name_text" class="list_width"/>
|
||||
<field name="department_id"/>
|
||||
<field name="creart_datetime"/>
|
||||
<field name="is_party" groups="yuthon_salary.group_jtbb_user" string="党总支"/>
|
||||
<field name="is_party" groups="yuthon_salary.group_lc_user,yuthon_salary.group_wg_user"
|
||||
string="党支部会"/>
|
||||
<field name="party_char"/>
|
||||
<field name="is_district_state"/>
|
||||
<field name="is_district_government"/>
|
||||
<field name="is_district_party"/>
|
||||
<field name="is_district_state" column_invisible="1"/>
|
||||
<field name="is_district_government" column_invisible="1"/>
|
||||
<field name="is_district_party" column_invisible="1"/>
|
||||
<field name="is_external_person"/>
|
||||
<field name="issue_state" string="审批状态" />
|
||||
<field name="issue_state_party"/>
|
||||
@@ -582,7 +588,7 @@
|
||||
['draft', 'to_draft'])]
|
||||
</field>
|
||||
<field name="search_view_id" ref="view_issue_library_filter"/>
|
||||
<field name="context">{'from_action': 'issue_library_action3', 'search_default_to_approval': 1}</field>
|
||||
<field name="context">{'from_action': 'issue_library_action3'}</field>
|
||||
<field name="view_ids" eval="[(5, 0, 0),
|
||||
(0, 0, {'view_mode': 'tree', 'view_id': ref('yuthon_issue.view_issue_library_tree2')}),
|
||||
(0, 0, {'view_mode': 'form', 'view_id': ref('yuthon_issue.view_issue_library_form3')})]"/>
|
||||
@@ -595,7 +601,7 @@
|
||||
<field name="domain">[('is_push_party', '=', True),('issue_state', 'not in', ['draft', 'to_draft']),
|
||||
('is_push_depart', '=', True), ('company_id.name', '!=', '集团本部')]
|
||||
</field>
|
||||
<field name="context">{'from_action': 'issue_library_action3', 'search_default_to_approval': 1}</field>
|
||||
<field name="context">{'from_action': 'issue_library_action8'}</field>
|
||||
<field name="search_view_id" ref="view_issue_library_filter"/>
|
||||
<field name="view_ids" eval="[(5, 0, 0),
|
||||
(0, 0, {'view_mode': 'tree', 'view_id': ref('yuthon_issue.view_issue_library_tree3')}),
|
||||
@@ -763,7 +769,7 @@
|
||||
('is_push_depart', '=', True)]
|
||||
</field>
|
||||
<field name="search_view_id" ref="view_issue_library_filter"/>
|
||||
<field name="context">{'from_action': 'issue_library_action4', 'search_default_to_approval': 1}</field>
|
||||
<field name="context">{'from_action': 'issue_library_action4'}</field>
|
||||
<field name="view_ids" eval="[(5, 0, 0),
|
||||
(0, 0, {'view_mode': 'tree', 'view_id': ref('yuthon_issue.view_issue_library_tree4')}),
|
||||
(0, 0, {'view_mode': 'form', 'view_id': ref('yuthon_issue.view_issue_library_form4')})]"/>
|
||||
@@ -929,7 +935,7 @@
|
||||
('is_push_depart', '=', True)]
|
||||
</field>
|
||||
<field name="search_view_id" ref="view_issue_library_filter"/>
|
||||
<field name="context">{'from_action': 'issue_library_action5', 'search_default_to_approval': 1}</field>
|
||||
<field name="context">{'from_action': 'issue_library_action5'}</field>
|
||||
<field name="view_ids" eval="[(5, 0, 0),
|
||||
(0, 0, {'view_mode': 'tree', 'view_id': ref('yuthon_issue.view_issue_library_tree5')}),
|
||||
(0, 0, {'view_mode': 'form', 'view_id': ref('yuthon_issue.view_issue_library_form5')})]"/>
|
||||
|
||||
@@ -226,6 +226,7 @@ class ReceivableModifyLine(models.Model):
|
||||
no_amount = fields.Float(related='bank_id.no_amount', string='未对', store=False)
|
||||
bank_state = fields.Selection(related='bank_id.bank_state', string='状态', store=False)
|
||||
receivable_id = fields.Many2one('property.accounts.receivable', string='合同编号')
|
||||
contract_id = fields.Many2one('property.lease.contract', string='关联租赁合同', compute='_compute_contract_id')
|
||||
management_type_id = fields.Many2one('yuthon.management.type', related='receivable_id.management_type_id', string='应收类型', store=True)
|
||||
due_date = fields.Date(related='receivable_id.due_date', string='应收开始', store=False)
|
||||
due_date_end = fields.Date(related='receivable_id.due_date_end', string='应收结束', store=False)
|
||||
@@ -240,6 +241,13 @@ class ReceivableModifyLine(models.Model):
|
||||
# search='_search_lessee_id',
|
||||
# )
|
||||
|
||||
@api.depends('receivable_id')
|
||||
def _compute_contract_id(self):
|
||||
for rec in self:
|
||||
rec.contract_id = False
|
||||
if rec.receivable_id:
|
||||
rec.contract_id = rec.receivable_id.contract_id
|
||||
|
||||
@api.depends('receivable_id')
|
||||
def _compute_lessee_id_company(self):
|
||||
for rec in self:
|
||||
|
||||
@@ -13,7 +13,7 @@ class PropertyBillsList(models.Model):
|
||||
amount_actual = fields.Float(string='实付')
|
||||
receivables_id = fields.Many2one('property.accounts.receivable', string='应收账单')
|
||||
contract_id = fields.Many2one('property.lease.contract', string="合同编号")
|
||||
lessor_id = fields.Many2one('yuthon.property.company', string="支付公司")
|
||||
lessor_id = fields.Many2one(related='contract_id.lessor_id', string="支付公司")
|
||||
lessee_id = fields.Many2one(related="contract_id.lessee_id", string="承租方", store=True)
|
||||
property_name = fields.Char(related='contract_id.property_name', string="物业信息")
|
||||
workflow_record_id = fields.Many2one('soong.workflow.record', string="流程")
|
||||
|
||||
@@ -28,6 +28,13 @@ class PropertyBillsPayable(models.Model):
|
||||
document_ids = fields.Many2many('ir.attachment', string="附件")
|
||||
active = fields.Boolean('Active', default=True, tracking=True)
|
||||
work_end = fields.Boolean(string="结束")
|
||||
payment_type = fields.Selection([
|
||||
('deposit_refund', '退押'),
|
||||
('lease_refund', '退租'),
|
||||
('engineering', '工程款'),
|
||||
('agency_fee', '中介费'),
|
||||
('other', '其他')
|
||||
], string='付款类型')
|
||||
|
||||
def _get_default_name_title(self):
|
||||
return self._description if self._description else self._name
|
||||
|
||||
@@ -240,7 +240,7 @@ class PropertyLeaseContract(models.Model):
|
||||
electricity_fee_ids = fields.One2many('property.electric.fee.line', 'contract_id', string="物业电表明细行")
|
||||
other_ids = fields.One2many('property.other.fee.line', 'other_id', string="其他费用明细行")
|
||||
lease_bank_ids = fields.One2many('property.bank.line', 'contract_id', string="承租方账户明细行")
|
||||
bank_statements_ids = fields.One2many('property.bank.statements', 'contract_id', string="银行流水明细行")
|
||||
bank_statements_ids = fields.One2many('receivable.modify.line', 'contract_id', string="银行流水明细行")
|
||||
contact_state = fields.Selection([('to', '待执行' ), ('ing', '执行中'), ('terminate', '中止'), ('complete', '完成'), ('early_termination', '提前终止'), ('settle', '结清')], string='合同管理状态', default='to')
|
||||
# 附件
|
||||
license_ids = fields.Many2many('ir.attachment',
|
||||
@@ -711,9 +711,8 @@ class PropertyLeaseContract(models.Model):
|
||||
|
||||
def _compute_reconciliation_count(self):
|
||||
for record in self:
|
||||
record.reconciliation_count = self.env['property.bank.statements'].search_count([('contract_id', '=', record.id),
|
||||
('name_account', '=', record.lessee_id.name)
|
||||
])
|
||||
record.reconciliation_count = self.env['receivable.modify.line'].search_count([('receivable_id.contract_id', '=', self.id)])
|
||||
|
||||
def _compute_process_count(self):
|
||||
for record in self:
|
||||
record.process_count = self.env['soong.workflow.record'].search_count([('code', '=', record.code)])
|
||||
@@ -732,9 +731,8 @@ class PropertyLeaseContract(models.Model):
|
||||
|
||||
def action_open_reconciliation(self):
|
||||
self.ensure_one()
|
||||
action = self.env["ir.actions.actions"]._for_xml_id("yuthon_property.view_property_bank_statements_action1")
|
||||
action.update({'domain': [('contract_id', '=', self.id),
|
||||
('name_account', '=', self.lessee_id.name)
|
||||
action = self.env["ir.actions.actions"]._for_xml_id("yuthon_work_brand.action_receivable_modify_line_wbrand")
|
||||
action.update({'domain': [('receivable_id.contract_id', '=', self.id),
|
||||
]
|
||||
})
|
||||
return action
|
||||
|
||||
@@ -42,6 +42,7 @@
|
||||
<group>
|
||||
<field name="is_back" invisible="1"/>
|
||||
<field name="name"/>
|
||||
<field name="payment_type"/>
|
||||
<field name="users_id"/>
|
||||
<field name="work_end" invisible="1"/>
|
||||
<field name="company_id" invisible="1"/>
|
||||
@@ -54,7 +55,7 @@
|
||||
<group>
|
||||
<field name="lease_contract_id"/>
|
||||
<field name="property_name"/>
|
||||
<field name="lessee_id"/>
|
||||
<field name="lessee_id" string="收款方"/>
|
||||
<field name="amount_payable"/>
|
||||
<field name="deduction_amount"/>
|
||||
<field name="remake" invisible="not deduction_amount"/>
|
||||
|
||||
@@ -336,19 +336,21 @@
|
||||
</tree>
|
||||
</field>
|
||||
</page>
|
||||
<page string="银行流水" invisible="(state in ['分管领导', '总经理']) and (not work_end)">
|
||||
<page string="银行流水">
|
||||
<field name="bank_statements_ids" string=" ">
|
||||
<tree editable="bottom">
|
||||
<field name="start_time"/>
|
||||
<field name="company_id" required="1"/>
|
||||
<field name="name"/>
|
||||
<field name="name_account"/>
|
||||
<field name="contract_account"/>
|
||||
<field name="remake"/>
|
||||
<field name="property_ids" widget="many2many_tags" options="{'no_create': True}"/>
|
||||
<field name="contract_penalty"/>
|
||||
<field name="contract_id" column_invisible="1"/>
|
||||
<field name="management_type_id"/>
|
||||
<field name="due_date"/>
|
||||
<field name="due_date_end"/>
|
||||
<field name="reconciliation_date"/>
|
||||
<field name="has_date"/>
|
||||
<field name="delivered1"/>
|
||||
<field name="amount"/>
|
||||
<field name="original_amount"/>
|
||||
<field name="voucher_type"/>
|
||||
<field name="no_amount"/>
|
||||
<field name="not_collected"/>
|
||||
<field name="bank_state"/>
|
||||
</tree>
|
||||
</field>
|
||||
</page>
|
||||
@@ -846,17 +848,19 @@
|
||||
</page>
|
||||
<page string="银行流水">
|
||||
<field name="bank_statements_ids" string=" ">
|
||||
<tree editable="bottom" delete="false">
|
||||
<field name="start_time"/>
|
||||
<field name="company_id" options="{'no_open': True}"/>
|
||||
<field name="name"/>
|
||||
<field name="name_account"/>
|
||||
<field name="contract_account"/>
|
||||
<field name="remake"/>
|
||||
<field name="property_ids" widget="many2many_tags" options="{'no_create': True}"/>
|
||||
<field name="contract_penalty"/>
|
||||
<tree editable="bottom">
|
||||
<field name="contract_id" column_invisible="1"/>
|
||||
<field name="management_type_id"/>
|
||||
<field name="due_date"/>
|
||||
<field name="due_date_end"/>
|
||||
<field name="reconciliation_date"/>
|
||||
<field name="has_date"/>
|
||||
<field name="delivered1"/>
|
||||
<field name="amount"/>
|
||||
<field name="original_amount"/>
|
||||
<field name="voucher_type"/>
|
||||
<field name="no_amount"/>
|
||||
<field name="not_collected"/>
|
||||
<field name="bank_state"/>
|
||||
</tree>
|
||||
</field>
|
||||
</page>
|
||||
@@ -954,18 +958,20 @@
|
||||
</group>
|
||||
</group>
|
||||
</page>
|
||||
<page string="应收明细">
|
||||
<page string="实收明细">
|
||||
<field name="receivable_ids" string=" ">
|
||||
<tree editable="bottom">
|
||||
<field name="contract_id" column_invisible="1"/>
|
||||
<field name="management_type_id"/>
|
||||
<field name="last_month_table"/>
|
||||
<field name="this_month_table"/>
|
||||
<field name="ratio"/>
|
||||
<field name="billable_quantity"/>
|
||||
<field name="due_date"/>
|
||||
<field name="due_date_end"/>
|
||||
<field name="original_amount" string="应计金额"/>
|
||||
<field name="last_month_table" column_invisible="1"/>
|
||||
<field name="this_month_table" column_invisible="1"/>
|
||||
<field name="ratio" column_invisible="1"/>
|
||||
<field name="billable_quantity" column_invisible="1"/>
|
||||
<field name="due_date" string="应收开始日期"/>
|
||||
<field name="due_date_end" string="应收结束日期"/>
|
||||
<field name="original_amount" string="收款金额"/>
|
||||
<field name="payout_date" string="收款日期"/>
|
||||
<field name="delivered1" string="应收金额"/>
|
||||
<field name="pre_collection"/>
|
||||
<field name="actual_coping"/>
|
||||
<field name="remark"/>
|
||||
@@ -1112,7 +1118,6 @@
|
||||
<field name="res_model">property.lease.contract</field>
|
||||
<field name="view_mode">tree,form</field>
|
||||
<field name="context">{'search_default_group_by_admin_id': True,'header_search_default_ing': 1}</field>
|
||||
<field name="domain">[('is_contract', '=', False)]</field>
|
||||
<field name="view_ids" eval="[(5, 0, 0),
|
||||
(0, 0, {'view_mode': 'tree', 'view_id': ref('yuthon_property_approval.view_property_lease_contract_tree1')}),
|
||||
(0, 0, {'view_mode': 'form', 'view_id': ref('yuthon_property_approval.view_property_lease_contract_form1')})]"/>
|
||||
|
||||
@@ -25,7 +25,7 @@ class PropertyBillsWizard(models.TransientModel):
|
||||
self.bills_list_id.actual_date = self.actual_date
|
||||
self.bills_list_id.pay_state = 'paid'
|
||||
receivable = self.env['property.accounts.receivable'].search([('contract_id', '=', self.bills_list_id.contract_id.id),
|
||||
('management_type_id', '=', self.bills_list_i.management_type_id.id)
|
||||
('management_type_id', '=', self.bills_list_id.management_type_id.id)
|
||||
])
|
||||
if receivable:
|
||||
receivable.write({'has_date': self.actual_date,
|
||||
|
||||
@@ -237,7 +237,7 @@ class PropertyRentalWizard(models.Model):
|
||||
|
||||
# 当期应收日期
|
||||
if new_version:
|
||||
if start_year_month <= date_field_year_month <= end_year_month:
|
||||
if start_year_month < date_field_year_month <= end_year_month:
|
||||
if rent_id.period_rent != 0 and record.contract_sort not in ['guanggao', 'guanzi', 'room']:
|
||||
self.create_rent_list(record, rent_id, rent_amount, start_date, multiplier)
|
||||
self.create_management_list(record, start_date, manage_amount)
|
||||
|
||||
@@ -37,6 +37,7 @@ class InheritPurchaseOrder(models.Model):
|
||||
default=lambda self: [(6, 0, [self.env.user.id])])
|
||||
pay_way = fields.Selection([('onetime', '一次性'), ('installment', '分期')], string="付款方式", default='onetime')
|
||||
reason_text = fields.Text(string="申请事由")
|
||||
purchase_type = fields.Selection([('fixed_asset', '固定资产采购'), ('sporadic', '零星采购'), ('comprehensive', '综合类')], string="采购类型", default='comprehensive')
|
||||
is_modify = fields.Boolean(string="可修改")
|
||||
pay_line_ids = fields.One2many('purchase.order.pay.line', 'order_id', string="付款详情")
|
||||
is_company = fields.Boolean(string="本公司", default=True, compute='_compute_is_company',search='_search_part_of_company')
|
||||
@@ -246,6 +247,7 @@ class InheritPurchaseOrderLine(models.Model):
|
||||
category_id = fields.Many2one('product.category', string="产品分类")
|
||||
brand_spec = fields.Char(string="品牌/规格")
|
||||
category_ids = fields.Many2many('product.category', string="产品分类", compute='_compute_category_id')
|
||||
purchase_type = fields.Selection(related='order_id.purchase_type', string="采购类型")
|
||||
|
||||
@api.depends('category_id')
|
||||
def _compute_category_id(self):
|
||||
@@ -261,3 +263,37 @@ class InheritPurchaseOrderLine(models.Model):
|
||||
])
|
||||
record.category_ids = [(6, 0, matching_categories.ids)] if matching_categories else [(5,)]
|
||||
|
||||
@api.onchange('product_id')
|
||||
def _onchange_product_id_check_tag(self):
|
||||
"""检查产品标签是否符合采购类型要求"""
|
||||
if self.product_id and self.order_id.purchase_type:
|
||||
tag_names = self.product_id.product_tag_ids.mapped('name')
|
||||
if self.order_id.purchase_type == 'fixed_asset':
|
||||
# 固定资产采购:只能选择有固定资产标签的产品
|
||||
if '固定资产' not in tag_names:
|
||||
warning = {
|
||||
'title': '产品不符合要求',
|
||||
'message': '固定资产采购只能选择产品标签为“固定资产”的产品!'
|
||||
}
|
||||
return {'warning': warning, 'value': {'product_id': False}}
|
||||
elif self.order_id.purchase_type == 'sporadic':
|
||||
# 零星采购:只能选择没有固定资产标签的产品
|
||||
if '固定资产' in tag_names:
|
||||
warning = {
|
||||
'title': '产品不符合要求',
|
||||
'message': '零星采购不能选择产品标签为“固定资产”的产品!'
|
||||
}
|
||||
return {'warning': warning, 'value': {'product_id': False}}
|
||||
|
||||
@api.onchange('order_id')
|
||||
def _onchange_order_id_set_product_domain(self):
|
||||
"""根据采购类型设置产品domain"""
|
||||
if self.order_id:
|
||||
if self.order_id.purchase_type == 'fixed_asset':
|
||||
# 固定资产采购:只能选择有固定资产标签的产品
|
||||
return {'domain': {'product_id': [('product_tag_ids.name', 'in', ['固定资产'])]}}
|
||||
elif self.order_id.purchase_type == 'sporadic':
|
||||
# 零星采购:只能选择没有固定资产标签的产品
|
||||
return {'domain': {'product_id': [('product_tag_ids.name', 'not in', ['固定资产'])]}}
|
||||
# 综合类:不设置domain,显示所有产品
|
||||
|
||||
|
||||
@@ -41,7 +41,7 @@
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="label">采购标的类型</td>
|
||||
<td colspan="5"><span t-esc="doc.category_id.name or ''"/></td>
|
||||
<td colspan="5"><span t-esc="dict(doc._fields['purchase_type'].selection).get(doc.purchase_type, '')"/></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="label">付款方式</td>
|
||||
|
||||
@@ -161,6 +161,7 @@
|
||||
</xpath>
|
||||
<xpath expr="//field[@name='date_order']" position="before">
|
||||
<field name="pay_way"/>
|
||||
<field name="purchase_type" widget="radio"/>
|
||||
</xpath>
|
||||
<xpath expr="//div[@name='date_approve']" position="attributes">
|
||||
<attribute name="invisible">1</attribute>
|
||||
@@ -180,6 +181,12 @@
|
||||
<field name="category_id" column_invisible="1"/>
|
||||
<field name="category_ids" widget="many2many_tags" column_invisible="1"/>
|
||||
</xpath>
|
||||
<xpath expr="//field[@name='order_line']//tree" position="inside">
|
||||
<field name="purchase_type" column_invisible="1"/>
|
||||
</xpath>
|
||||
<xpath expr="//field[@name='order_line']//tree//field[@name='product_id']" position="attributes">
|
||||
<attribute name="domain">purchase_type == 'fixed_asset' and [('product_tag_ids.name', 'in', ['固定资产'])] or purchase_type == 'sporadic' and [('product_tag_ids.name', 'not in', ['固定资产'])] or []</attribute>
|
||||
</xpath>
|
||||
<xpath expr="//field[@name='order_line']//tree//field[@name='product_id']" position="after">
|
||||
<field name="brand_spec" string="品牌/规格" optional="show"/>
|
||||
</xpath>
|
||||
@@ -192,9 +199,9 @@
|
||||
<field name="product_packaging_qty" invisible="not product_id or not product_packaging_id" groups="product.group_stock_packaging" optional="show"/>
|
||||
<field name="product_packaging_id" invisible="not product_id" context="{'default_product_id': product_id, 'tree_view_ref':'product.product_packaging_tree_view', 'form_view_ref':'product.product_packaging_form_view'}" groups="product.group_stock_packaging" optional="show"/>
|
||||
</xpath>
|
||||
<!-- <xpath expr="//field[@name='order_line']" position="attributes">-->
|
||||
<!-- <attribute name="context">{'default_category_id': category_id}</attribute>-->
|
||||
<!-- </xpath>-->
|
||||
<xpath expr="//field[@name='order_line']" position="attributes">
|
||||
<attribute name="context">{'default_order_id': id, 'purchase_type': purchase_type}</attribute>
|
||||
</xpath>
|
||||
<xpath expr="//page[@name='products']" position="after">
|
||||
<page string="付款详情" invisible="pay_way == 'onetime'">
|
||||
<field name="pay_line_ids">
|
||||
|
||||
@@ -11,8 +11,8 @@ class CumArrearsReport(models.Model):
|
||||
def get_cum_arrears_report(self, params):
|
||||
"""
|
||||
累计欠收报表(数据源:receivable.modify.line):
|
||||
- 状态为挂账(bank_state = 'registered')
|
||||
- 应收开始日期(receivable_id.due_date)小于等于查询月月末
|
||||
- 未收金额大于0(not_collected > 0)
|
||||
- 排除押金和违约金类型
|
||||
- 金额取 not_collected(未收)
|
||||
"""
|
||||
@@ -29,24 +29,30 @@ class CumArrearsReport(models.Model):
|
||||
month_end = query_date.replace(day=last_day)
|
||||
|
||||
domain = [
|
||||
('bank_state', '=', 'registered'),
|
||||
('receivable_id.due_date', '<=', month_end),
|
||||
('receivable_id.is_invalid', '=', False),
|
||||
]
|
||||
|
||||
keyword = params.get("keyword")
|
||||
if keyword:
|
||||
print(f"[累计欠收报表] keyword = {keyword}")
|
||||
# 处理 False, None, '' 等falsy值,只对非空字符串进行搜索
|
||||
# 前端可能传递 False 表示无搜索,所以需要特殊处理
|
||||
if keyword is not False and keyword is not None and isinstance(keyword, str) and keyword.strip():
|
||||
print(f"[累计欠收报表] 添加搜索条件: {keyword}")
|
||||
domain += [
|
||||
'|', '|',
|
||||
('receivable_id.contract_id.contract_code', 'ilike', keyword),
|
||||
('receivable_id.property_name', 'ilike', keyword),
|
||||
('receivable_id.lessee_id.name', 'ilike', keyword),
|
||||
('receivable_id.contract_id.contract_code', 'ilike', keyword.strip()),
|
||||
('receivable_id.property_name', 'ilike', keyword.strip()),
|
||||
('receivable_id.lessee_id.name', 'ilike', keyword.strip()),
|
||||
]
|
||||
|
||||
condition = params.get('condition')
|
||||
partner_id = params.get('partner_id')
|
||||
company_id = params.get('company_id')
|
||||
management_type_id = params.get('management_type_id')
|
||||
property_id = params.get('property_id')
|
||||
lessee_id = params.get('lessee_id')
|
||||
contract_id = params.get('contract_id')
|
||||
|
||||
if condition:
|
||||
domain.append(('receivable_id.tenure_type', '=', condition))
|
||||
@@ -57,9 +63,22 @@ class CumArrearsReport(models.Model):
|
||||
if management_type_id:
|
||||
domain.append(('receivable_id.management_type_id', '=', management_type_id))
|
||||
else:
|
||||
# 排除押金和违约金类型
|
||||
domain.append(('receivable_id.management_type_id.name', 'not in', ['押金', '违约金']))
|
||||
if property_id:
|
||||
domain.append(('receivable_id.property_ids', 'in', [property_id]))
|
||||
if lessee_id:
|
||||
domain.append(('receivable_id.lessee_id', '=', lessee_id))
|
||||
if contract_id:
|
||||
domain.append(('receivable_id.contract_id', '=', contract_id))
|
||||
|
||||
lines = self.search(domain, order="receivable_id asc")
|
||||
print(f"[累计欠收报表] domain = {domain}")
|
||||
lines = self.sudo().search(domain, order="receivable_id asc")
|
||||
print(f"[累计欠收报表] 搜索到的记录数 = {len(lines)}")
|
||||
|
||||
# 欠收条件: not_collected > 0
|
||||
lines = lines.filtered(lambda l: l.not_collected and l.not_collected > 0)
|
||||
print(f"[累计欠收报表] 过滤后记录数 = {len(lines)}")
|
||||
|
||||
rows = []
|
||||
total_amount = 0.0
|
||||
|
||||
@@ -9,24 +9,30 @@ class PreArrearsReport(models.Model):
|
||||
@api.model
|
||||
def get_pre_arrears_report(self, params):
|
||||
"""
|
||||
前期欠收报表(数据源:receivable.modify.line):
|
||||
- 查询条件的日期对应应收账单的 due_date(应收日期在查询月内)
|
||||
- 收款日期(reconciliation_date)晚于应收日期(due_date)的记录就是欠收
|
||||
- 金额取收款记录的 amount
|
||||
- 按应收账单聚合,每张账单只出一行(汇总该账单下所有欠收收款金额)
|
||||
前期欠收报表(数据源:receivable.modify.line):
|
||||
- 查询条件的日期对应应收账单的 due_date(应收日期在查询月及之前)
|
||||
- 欠收条件:
|
||||
- 收款日期在查询月之后(查询月时点还没收到钱)
|
||||
- 或者 not_collected > 0 (部分收款,还没交完)
|
||||
- 金额取值:
|
||||
- 如果 not_collected > 0,取 not_collected (当前还欠的金额)
|
||||
- 否则取 amount (已收金额)
|
||||
- 按应收账单聚合,每张账单只出一行(汇总该账单下所有欠收收款金额)
|
||||
"""
|
||||
today = datetime.date.today()
|
||||
this_month_first = today.replace(day=1)
|
||||
|
||||
date_start = params.get("date_start")
|
||||
date_end = params.get("date_end")
|
||||
# 应收日期在查询日期之前(不含查询月)
|
||||
cutoff_date = datetime.datetime.fromisoformat(date_start).date() if date_start else this_month_first
|
||||
# 应收日期在查询月及之前(包含查询月)
|
||||
cutoff_date = datetime.datetime.fromisoformat(date_end).date() if date_end else this_month_first
|
||||
# 查询月范围(用于判断收款是否在查询月内)
|
||||
query_month_start = datetime.datetime.fromisoformat(date_start).date() if date_start else this_month_first
|
||||
query_month_end = datetime.datetime.fromisoformat(date_end).date() if date_end else this_month_first
|
||||
|
||||
# 核心逻辑:due_date < cutoff_date,且收款日期 > 应收日期
|
||||
# 核心逻辑:due_date <= cutoff_date(查询月及之前的应收)
|
||||
domain = [
|
||||
('reconciliation_date', '!=', False),
|
||||
('receivable_id.due_date', '<', cutoff_date),
|
||||
('receivable_id.due_date', '<=', cutoff_date),
|
||||
('receivable_id.is_invalid', '=', False),
|
||||
]
|
||||
|
||||
@@ -65,24 +71,43 @@ class PreArrearsReport(models.Model):
|
||||
domain.append(('receivable_id.management_type_id.name', 'not in', ['押金', '违约金']))
|
||||
|
||||
lines = self.sudo().search(domain, order="receivable_id asc, reconciliation_date asc")
|
||||
|
||||
# 欠收条件:reconciliation_date > due_date 且不在同一个月(跨月才算欠收)
|
||||
|
||||
# 欠收条件(同时满足):
|
||||
# 1. reconciliation_date >= query_month_start (收款日期不能小于查询月)
|
||||
# 2. 满足以下任一:
|
||||
# a. reconciliation_date > query_month_end (收款日期在查询月之后,查询月时点还没收到钱)
|
||||
# b. not_collected > 0 (部分收款,还没交完)
|
||||
lines = lines.filtered(
|
||||
lambda l: l.reconciliation_date and l.receivable_id.due_date
|
||||
and l.reconciliation_date > l.receivable_id.due_date
|
||||
and not (
|
||||
l.reconciliation_date.year == l.receivable_id.due_date.year
|
||||
and l.reconciliation_date.month == l.receivable_id.due_date.month
|
||||
)
|
||||
lambda l: l.reconciliation_date and l.reconciliation_date >= query_month_start and (
|
||||
(l.reconciliation_date > query_month_end) or
|
||||
(l.not_collected and l.not_collected > 0)
|
||||
)
|
||||
)
|
||||
|
||||
# 调试日志
|
||||
print(f"[前期欠收报表] 查询到的 lines 数量: {len(lines)}")
|
||||
for line in lines:
|
||||
print(f" - line.id={line.id}, receivable_id={line.receivable_id.id}, "
|
||||
f"due_date={line.receivable_id.due_date}, "
|
||||
f"reconciliation_date={line.reconciliation_date}, "
|
||||
f"not_collected={line.not_collected}, amount={line.amount}")
|
||||
|
||||
# 按应收账单聚合
|
||||
rec_map = {}
|
||||
for line in lines:
|
||||
rid = line.receivable_id.id
|
||||
if rid not in rec_map:
|
||||
rec_map[rid] = {'rec': line.receivable_id, 'amount': 0.0}
|
||||
rec_map[rid]['amount'] += line.amount or 0.0
|
||||
rec_map[rid] = {'rec': line.receivable_id, 'amount': 0.0, 'reconciliation_dates': []}
|
||||
# 金额取值:有未收金额取not_collected,否则取amount
|
||||
rec_map[rid]['amount'] += (line.not_collected if (line.not_collected and line.not_collected > 0) else line.amount) or 0.0
|
||||
# 收集收款日期
|
||||
if line.reconciliation_date:
|
||||
rec_map[rid]['reconciliation_dates'].append(line.reconciliation_date)
|
||||
|
||||
# 调试日志
|
||||
print(f"[前期欠收报表] 聚合后的 rec_map 数量: {len(rec_map)}")
|
||||
for rid, data in rec_map.items():
|
||||
print(f" - receivable_id={rid}, amount={data['amount']}")
|
||||
|
||||
rows = []
|
||||
total_amount = 0.0
|
||||
@@ -103,6 +128,13 @@ class PreArrearsReport(models.Model):
|
||||
}
|
||||
elif rec:
|
||||
property_val = rec.property_name or ''
|
||||
|
||||
# 应收开始日期
|
||||
due_date_str = rec.due_date.strftime('%Y-%m-%d') if rec.due_date else ''
|
||||
|
||||
# 收款日期(取所有收款日期,用逗号分隔)
|
||||
reconciliation_dates = data.get('reconciliation_dates', [])
|
||||
reconciliation_date_str = ', '.join([d.strftime('%Y-%m-%d') for d in sorted(set(reconciliation_dates))]) if reconciliation_dates else ''
|
||||
|
||||
rows.append({
|
||||
"序号": idx,
|
||||
@@ -110,6 +142,7 @@ class PreArrearsReport(models.Model):
|
||||
'model': 'property.lease.contract',
|
||||
'id': contract.id,
|
||||
'display_name': contract.contract_code,
|
||||
'view_id': self.env.ref('yuthon_property_approval.view_property_lease_contract_form1').id,
|
||||
} if contract else "",
|
||||
"物业名称": property_val,
|
||||
"承租方名称": {
|
||||
@@ -118,6 +151,8 @@ class PreArrearsReport(models.Model):
|
||||
'display_name': rec.lessee_id.name,
|
||||
} if rec.lessee_id else "",
|
||||
"收款类型": rec.management_type_id.name if rec.management_type_id else "",
|
||||
"应收开始日期": due_date_str,
|
||||
"收款日期": reconciliation_date_str,
|
||||
"金额": amount,
|
||||
"所属公司": contract.lessor_id.name if contract and contract.lessor_id else "",
|
||||
"管理员": {
|
||||
|
||||
@@ -8,48 +8,26 @@ class ReceivableModifyFilterDomains(models.Model):
|
||||
|
||||
@api.model
|
||||
def get_receivable_filter_domains(self, params):
|
||||
"""根据当前筛选条件,返回物业/承租方/合同的候选 ID 集合,用于三个下拉框互相过滤。"""
|
||||
# 注意:这里不按日期限制,只根据当前组合条件(公司/权属/片区/收款类型/物业/承租方/合同)
|
||||
# 来计算三类对象的全集,避免不同报表各自的日期口径导致候选集为空。
|
||||
domain = [
|
||||
('receivable_id.is_invalid', '=', False),
|
||||
]
|
||||
"""根据当前筛选条件,返回物业/承租方/合同的候选 ID 集合,用于三个下拉框互相过滤。
|
||||
|
||||
注意:
|
||||
- 候选集不应受收款类型、是否无效等业务条件过滤
|
||||
- 只根据用户已选择的物业/承租方/合同进行互相过滤
|
||||
- 具体的业务过滤由报表查询方法自己处理
|
||||
"""
|
||||
domain = []
|
||||
|
||||
keyword = params.get("keyword")
|
||||
|
||||
if keyword:
|
||||
domain += [
|
||||
'|', '|',
|
||||
('receivable_id.contract_id.contract_code', 'ilike', keyword),
|
||||
('receivable_id.property_name', 'ilike', keyword),
|
||||
('receivable_id.lessee_id.name', 'ilike', keyword),
|
||||
]
|
||||
|
||||
condition = params.get('condition')
|
||||
partner_id = params.get('partner_id')
|
||||
company_id = params.get('company_id')
|
||||
management_type_id = params.get('management_type_id')
|
||||
# 只根据已选择的条件进行互相过滤,不应用业务过滤
|
||||
property_id = params.get('property_id')
|
||||
lessee_id = params.get('lessee_id')
|
||||
contract_id = params.get('contract_id')
|
||||
|
||||
if condition:
|
||||
domain.append(('receivable_id.tenure_type', '=', condition))
|
||||
if partner_id:
|
||||
domain.append(('receivable_id.precinct_id', '=', partner_id))
|
||||
if company_id:
|
||||
domain.append(('receivable_id.company_id', '=', company_id))
|
||||
if property_id:
|
||||
domain.append(('receivable_id.property_ids', 'in', [property_id]))
|
||||
if lessee_id:
|
||||
domain.append(('receivable_id.lessee_id', '=', lessee_id))
|
||||
if contract_id:
|
||||
domain.append(('receivable_id.contract_id', '=', contract_id))
|
||||
if management_type_id:
|
||||
domain.append(('receivable_id.management_type_id', '=', management_type_id))
|
||||
else:
|
||||
# 与各报表保持一致:默认剔除押金、违约金类型
|
||||
domain.append(('receivable_id.management_type_id.name', 'not in', ['押金', '违约金']))
|
||||
|
||||
lines = self.sudo().search(domain)
|
||||
receivables = lines.mapped('receivable_id')
|
||||
|
||||
@@ -0,0 +1,287 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
import datetime
|
||||
import calendar
|
||||
|
||||
from odoo import api, models
|
||||
|
||||
|
||||
class TextSummaryReport(models.Model):
|
||||
_name = 'text.summary.report'
|
||||
_description = '文字汇总报表'
|
||||
|
||||
@api.model
|
||||
def get_text_summary_report(self, params):
|
||||
"""
|
||||
生成文字汇总报表(类似图中的格式)
|
||||
:param params: 筛选参数(date_start/company_id/partner_id等)
|
||||
:return: 分组汇总数据
|
||||
"""
|
||||
today = datetime.date.today()
|
||||
|
||||
# 处理日期参数
|
||||
date_str = params.get("date_start")
|
||||
if date_str:
|
||||
# 支持 YYYY-MM 和 YYYY-MM-DD 两种格式
|
||||
if len(date_str) == 7: # YYYY-MM 格式
|
||||
year, month = map(int, date_str.split('-'))
|
||||
query_date = datetime.date(year, month, 1)
|
||||
else: # YYYY-MM-DD 格式
|
||||
query_date = datetime.datetime.fromisoformat(date_str).date()
|
||||
else:
|
||||
query_date = today
|
||||
|
||||
# 获取筛选条件
|
||||
company_id = params.get('company_id')
|
||||
precinct_id = params.get('partner_id')
|
||||
|
||||
# 构建报表数据结构
|
||||
report_data = {
|
||||
'summary_info': {
|
||||
'统计时间': f"{query_date.year}-{query_date.month:02d}",
|
||||
'统计片区': '全部' if not precinct_id else self._get_precinct_name(precinct_id),
|
||||
'所属公司': '全部' if not company_id else self._get_company_name(company_id),
|
||||
'创建时间': datetime.date.today().strftime("%Y-%m-%d"),
|
||||
},
|
||||
'groups': [
|
||||
{
|
||||
'title': '租金累计欠收',
|
||||
'items': self._get_rent_arrears_data(query_date, company_id, precinct_id)
|
||||
},
|
||||
{
|
||||
'title': '违约金累计欠收',
|
||||
'items': self._get_penalty_arrears_data(query_date, company_id, precinct_id)
|
||||
},
|
||||
{
|
||||
'title': '本月预收',
|
||||
'items': self._get_month_precollection_data(query_date, company_id, precinct_id)
|
||||
},
|
||||
{
|
||||
'title': '其他收入',
|
||||
'items': self._get_other_income_data(query_date, company_id, precinct_id)
|
||||
},
|
||||
{
|
||||
'title': '管理费支出',
|
||||
'items': self._get_management_fee_data(query_date, company_id, precinct_id)
|
||||
},
|
||||
]
|
||||
}
|
||||
|
||||
return report_data
|
||||
|
||||
def _get_precinct_name(self, precinct_id):
|
||||
"""获取片区名称"""
|
||||
try:
|
||||
precinct = self.env['res.users'].browse(precinct_id)
|
||||
return precinct.name if precinct else '未知'
|
||||
except:
|
||||
return '未知'
|
||||
|
||||
def _get_company_name(self, company_id):
|
||||
"""获取公司名称"""
|
||||
try:
|
||||
company = self.env['yuthon.property.company'].browse(company_id)
|
||||
return company.name if company else '未知'
|
||||
except:
|
||||
return '未知'
|
||||
|
||||
def _get_rent_arrears_data(self, query_date, company_id, precinct_id):
|
||||
"""获取租金累计欠收数据 - 从累计欠收报表获取"""
|
||||
params = {
|
||||
'date_start': query_date.strftime("%Y-%m-%d"),
|
||||
'company_id': company_id,
|
||||
'partner_id': precinct_id,
|
||||
}
|
||||
|
||||
# 调用累计欠收报表
|
||||
result = self.env['receivable.modify.line'].get_cum_arrears_report(params)
|
||||
rows = result.get('rows', [])
|
||||
|
||||
items = []
|
||||
# 按片区分组
|
||||
area_map = {}
|
||||
for row in rows:
|
||||
area = row.get('管理员', {}).get('display_name', '未分配') if isinstance(row.get('管理员'), dict) else row.get('管理员', '未分配')
|
||||
if area not in area_map:
|
||||
area_map[area] = []
|
||||
|
||||
property_name = row.get('物业名称', {})
|
||||
if isinstance(property_name, dict):
|
||||
property_name = property_name.get('display_name', '未命名物业')
|
||||
|
||||
amount = row.get('未收金额', 0.0)
|
||||
area_map[area].append(f"{property_name} 欠收:{amount:.2f}元")
|
||||
|
||||
for area, texts in area_map.items():
|
||||
items.append({
|
||||
'area': area,
|
||||
'content': '。'.join(texts[:10]) + '。' # 每个片区最多显示10条
|
||||
})
|
||||
|
||||
return items if items else [{'area': '暂无数据', 'content': '暂无租金累计欠收数据。'}]
|
||||
|
||||
def _get_penalty_arrears_data(self, query_date, company_id, precinct_id):
|
||||
"""获取违约金累计欠收数据 - 从违约金欠收报表获取"""
|
||||
params = {
|
||||
'date_start': query_date.strftime("%Y-%m-%d"),
|
||||
'company_id': company_id,
|
||||
'partner_id': precinct_id,
|
||||
}
|
||||
|
||||
# 调用违约金欠收报表
|
||||
result = self.env['property.accounts.receivable'].get_penalty_arrears_report(params)
|
||||
rows = result.get('rows', [])
|
||||
|
||||
items = []
|
||||
# 按片区分组
|
||||
area_map = {}
|
||||
for row in rows:
|
||||
area = row.get('管理员', {}).get('display_name', '未分配') if isinstance(row.get('管理员'), dict) else row.get('管理员', '未分配')
|
||||
if area not in area_map:
|
||||
area_map[area] = []
|
||||
|
||||
property_name = row.get('物业名称', {})
|
||||
if isinstance(property_name, dict):
|
||||
property_name = property_name.get('display_name', '未命名物业')
|
||||
|
||||
amount = row.get('总未收', 0.0)
|
||||
area_map[area].append(f"{property_name} 违约金欠收:{amount:.2f}元")
|
||||
|
||||
for area, texts in area_map.items():
|
||||
items.append({
|
||||
'area': area,
|
||||
'content': '。'.join(texts[:10]) + '。'
|
||||
})
|
||||
|
||||
return items if items else [{'area': '暂无数据', 'content': '暂无违约金累计欠收数据。'}]
|
||||
|
||||
def _get_month_precollection_data(self, query_date, company_id, precinct_id):
|
||||
"""获取本月预收数据 - 从本月预收报表获取"""
|
||||
params = {
|
||||
'date_start': query_date.strftime("%Y-%m-%d"),
|
||||
'company_id': company_id,
|
||||
'partner_id': precinct_id,
|
||||
}
|
||||
|
||||
# 调用本月预收报表
|
||||
result = self.env['receivable.modify.line'].get_monthly_precollection_report(params)
|
||||
rows = result.get('rows', [])
|
||||
|
||||
items = []
|
||||
# 按片区分组
|
||||
area_map = {}
|
||||
for row in rows:
|
||||
area = row.get('管理员', {}).get('display_name', '未分配') if isinstance(row.get('管理员'), dict) else row.get('管理员', '未分配')
|
||||
if area not in area_map:
|
||||
area_map[area] = []
|
||||
|
||||
property_name = row.get('物业名称', {})
|
||||
if isinstance(property_name, dict):
|
||||
property_name = property_name.get('display_name', '未命名物业')
|
||||
|
||||
amount = row.get('金额', 0.0)
|
||||
area_map[area].append(f"{property_name}本月预收:{amount:.2f}元")
|
||||
|
||||
for area, texts in area_map.items():
|
||||
items.append({
|
||||
'area': area,
|
||||
'content': '。'.join(texts[:10]) + '。'
|
||||
})
|
||||
|
||||
return items if items else [{'area': '暂无数据', 'content': '暂无本月预收数据。'}]
|
||||
|
||||
def _get_other_income_data(self, query_date, company_id, precinct_id):
|
||||
"""获取其他收入数据 - 从停车费报表获取"""
|
||||
params = {
|
||||
'date_start': query_date.strftime("%Y-%m-%d"),
|
||||
'company_id': company_id,
|
||||
'partner_id': precinct_id,
|
||||
}
|
||||
|
||||
# 调用停车费本月实收报表
|
||||
result = self.env['property.accounts.receivable'].get_parking_fee_current_month_report(params)
|
||||
rows = result.get('rows', [])
|
||||
|
||||
items = []
|
||||
# 按片区分组
|
||||
area_map = {}
|
||||
total_parking = 0.0
|
||||
|
||||
for row in rows:
|
||||
area = row.get('管理员', {}).get('display_name', '未分配') if isinstance(row.get('管理员'), dict) else row.get('管理员', '未分配')
|
||||
if area not in area_map:
|
||||
area_map[area] = []
|
||||
|
||||
property_name = row.get('物业名称', {})
|
||||
if isinstance(property_name, dict):
|
||||
property_name = property_name.get('display_name', '未命名物业')
|
||||
|
||||
amount = row.get('金额', 0.0)
|
||||
total_parking += amount
|
||||
area_map[area].append(f"{property_name}停车费:{amount:.2f}元")
|
||||
|
||||
for area, texts in area_map.items():
|
||||
items.append({
|
||||
'area': area,
|
||||
'content': '。'.join(texts[:10]) + '。'
|
||||
})
|
||||
|
||||
# 如果停车费有数据,添加汇总信息
|
||||
if total_parking > 0:
|
||||
items.append({
|
||||
'area': '合计',
|
||||
'content': f"停车费总收入:{total_parking:.2f}元。"
|
||||
})
|
||||
|
||||
return items if items else [{'area': '暂无数据', 'content': '暂无其他收入数据。'}]
|
||||
|
||||
def _get_management_fee_data(self, query_date, company_id, precinct_id):
|
||||
"""获取管理费支出数据 - 从管理费相关报表获取"""
|
||||
# 管理费支出需要根据实际业务逻辑查询
|
||||
# 这里查询管理费类型的应收记录作为支出参考
|
||||
|
||||
# 查询管理费类型
|
||||
management_types = self.env['yuthon.management.type'].search([('name', 'ilike', '管理')])
|
||||
|
||||
params = {
|
||||
'date_start': query_date.strftime("%Y-%m-%d"),
|
||||
'company_id': company_id,
|
||||
'partner_id': precinct_id,
|
||||
'management_type_id': management_types[0].id if management_types else None,
|
||||
}
|
||||
|
||||
# 调用归属本月报表获取管理费数据
|
||||
result = self.env['receivable.modify.line'].get_current_month_received_report(params)
|
||||
rows = result.get('rows', [])
|
||||
|
||||
items = []
|
||||
# 按片区分组
|
||||
area_map = {}
|
||||
total_fee = 0.0
|
||||
|
||||
for row in rows:
|
||||
area = row.get('管理员', {}).get('display_name', '未分配') if isinstance(row.get('管理员'), dict) else row.get('管理员', '未分配')
|
||||
if area not in area_map:
|
||||
area_map[area] = []
|
||||
|
||||
property_name = row.get('物业名称', {})
|
||||
if isinstance(property_name, dict):
|
||||
property_name = property_name.get('display_name', '未命名物业')
|
||||
|
||||
amount = row.get('金额', 0.0)
|
||||
total_fee += amount
|
||||
area_map[area].append(f"{property_name}管理费 支出:{amount:.2f}元")
|
||||
|
||||
for area, texts in area_map.items():
|
||||
items.append({
|
||||
'area': area,
|
||||
'content': '。'.join(texts[:10]) + '。'
|
||||
})
|
||||
|
||||
# 如果管理费有数据,添加汇总信息
|
||||
if total_fee > 0:
|
||||
items.append({
|
||||
'area': '合计',
|
||||
'content': f"管理费总支出:{total_fee:.2f}元。"
|
||||
})
|
||||
|
||||
return items if items else [{'area': '暂无数据', 'content': '暂无管理费支出数据。'}]
|
||||
@@ -5,8 +5,6 @@ from odoo import fields, models, api
|
||||
|
||||
class YuthonContractReport(models.Model):
|
||||
_inherit = 'property.lease.contract'
|
||||
_description = '合同信息报表'
|
||||
|
||||
|
||||
@api.model
|
||||
def get_contract_info_report(self, params):
|
||||
|
||||
@@ -216,7 +216,7 @@ class ReceivableReport extends Component {
|
||||
type: 'ir.actions.act_window',
|
||||
res_model: model,
|
||||
res_id: id,
|
||||
views: [[false, 'form'], [false, 'search']],
|
||||
views: [[view_id || false, 'form'], [false, 'search']],
|
||||
target: 'new'
|
||||
});
|
||||
}
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
/** @odoo-module **/
|
||||
|
||||
import { registry } from "@web/core/registry";
|
||||
import { Component, onMounted, useState } from "@odoo/owl";
|
||||
import { useService } from "@web/core/utils/hooks";
|
||||
import { standardActionServiceProps } from "@web/webclient/actions/action_service";
|
||||
|
||||
class TextSummaryReport extends Component {
|
||||
setup() {
|
||||
this.serviceOrm = useService("orm");
|
||||
|
||||
this.state = useState({
|
||||
reportData: null,
|
||||
dateStart: "",
|
||||
loading: false,
|
||||
});
|
||||
|
||||
this.config = this.props.action.context.report_config || {};
|
||||
|
||||
onMounted(() => {
|
||||
// 页面加载时自动执行搜索
|
||||
this.onSearch();
|
||||
});
|
||||
}
|
||||
|
||||
async onSearch() {
|
||||
this.state.loading = true;
|
||||
|
||||
const params = {
|
||||
date_start: this.state.dateStart,
|
||||
};
|
||||
|
||||
try {
|
||||
const result = await this.serviceOrm.call(
|
||||
this.config.model || 'text.summary.report',
|
||||
this.config.method || 'get_text_summary_report',
|
||||
[params]
|
||||
);
|
||||
this.state.reportData = result;
|
||||
} catch (error) {
|
||||
console.error('报表查询失败:', error);
|
||||
this.state.reportData = null;
|
||||
} finally {
|
||||
this.state.loading = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TextSummaryReport.props = { ...standardActionServiceProps };
|
||||
TextSummaryReport.template = "text_summary_report.TextSummaryReport";
|
||||
|
||||
registry.category("actions").add("text_summary_report_client", TextSummaryReport);
|
||||
@@ -0,0 +1,90 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<templates id="template" xml:space="preserve">
|
||||
<t t-name="text_summary_report.TextSummaryReport">
|
||||
<div class="container-fluid" style="height: calc(100vh - 80px); display: flex; flex-direction: column;">
|
||||
<!-- 搜索区域 -->
|
||||
<div class="card mb-3 flex-shrink-0">
|
||||
<div class="card-body">
|
||||
<div class="row">
|
||||
<div class="col-md-2">
|
||||
<label class="form-label">年月:</label>
|
||||
<input
|
||||
type="month"
|
||||
class="form-control"
|
||||
t-model="state.dateStart"
|
||||
/>
|
||||
</div>
|
||||
<div class="col-md-10 d-flex align-items-end justify-end">
|
||||
<button class="btn btn-primary" t-on-click="onSearch">
|
||||
<span t-if="state.loading" class="fa fa-spinner fa-spin"></span>
|
||||
查询
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 报表信息栏 -->
|
||||
<div t-if="state.reportData" class="card mb-3 flex-shrink-0">
|
||||
<div class="card-body">
|
||||
<div class="row">
|
||||
<div class="col-md-3">
|
||||
<span class="text-muted">统计时间:</span>
|
||||
<span t-esc="state.reportData.summary_info['统计时间']"></span>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<span class="text-muted">统计片区:</span>
|
||||
<span t-esc="state.reportData.summary_info['统计片区']"></span>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<span class="text-muted">所属公司:</span>
|
||||
<span t-esc="state.reportData.summary_info['所属公司']"></span>
|
||||
</div>
|
||||
<div class="col-md-3 text-right">
|
||||
<span class="text-muted">创建时间:</span>
|
||||
<span t-esc="state.reportData.summary_info['创建时间']"></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 报表内容区域 - 可滚动 -->
|
||||
<div t-if="state.reportData" class="card flex-grow-1 overflow-auto" style="min-height: 0;">
|
||||
<div class="card-body">
|
||||
<t t-foreach="state.reportData.groups" t-as="group" t-key="group_index">
|
||||
<div class="mb-4">
|
||||
<div class="bg-danger text-white p-2 mb-2">
|
||||
<strong t-esc="group.title"></strong>
|
||||
</div>
|
||||
<div class="border-left-4 border-danger pl-3">
|
||||
<t t-foreach="group.items" t-as="item" t-key="item_index">
|
||||
<div class="mb-2">
|
||||
<div class="font-weight-bold text-primary" t-esc="item.area"></div>
|
||||
<div class="text-sm text-gray-700" t-esc="item.content"></div>
|
||||
</div>
|
||||
</t>
|
||||
</div>
|
||||
</div>
|
||||
</t>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 加载提示 -->
|
||||
<div t-if="state.loading" class="flex-grow-1 flex items-center justify-center">
|
||||
<div class="text-center">
|
||||
<i class="fa fa-spinner fa-spin fa-3x"></i>
|
||||
<p>加载中...</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 空状态提示 -->
|
||||
<div t-if="!state.loading && !state.reportData" class="flex-grow-1 flex items-center justify-center">
|
||||
<div class="text-center text-muted">
|
||||
<i class="fa fa-file-text-o fa-3x mb-2"></i>
|
||||
<p>请点击查询按钮获取报表数据</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</t>
|
||||
</templates>
|
||||
@@ -13,11 +13,13 @@
|
||||
"dateMode": "single",
|
||||
"columns": [
|
||||
{"headerName": "序号", "field": "序号", "width": 45, "flex": 0, "pinned": "left"},
|
||||
{"headerName": "应收开始日期", "field": "应收开始日期", "flex": 1},
|
||||
{"headerName": "收款日期", "field": "收款日期", "flex": 1},
|
||||
{"headerName": "金额", "field": "金额", "flex": 1, "type": "number"},
|
||||
{"headerName": "合同编号", "field": "合同编号", "flex": 1.2},
|
||||
{"headerName": "物业名称", "field": "物业名称", "flex": 2.5},
|
||||
{"headerName": "承租方名称", "field": "承租方名称", "flex": 1.4},
|
||||
{"headerName": "收款类型", "field": "收款类型", "flex": 1},
|
||||
{"headerName": "金额", "field": "金额", "flex": 1, "type": "number"},
|
||||
{"headerName": "所属公司", "field": "所属公司", "flex": 1},
|
||||
{"headerName": "管理员", "field": "管理员", "flex": 1}
|
||||
]
|
||||
|
||||
@@ -4,7 +4,7 @@ from odoo import models, fields, api, exceptions, _
|
||||
|
||||
class ParkingFeeApproval(models.Model):
|
||||
_name = 'parking.fee.approval'
|
||||
_description = '停车费发放'
|
||||
_description = '停车票发放'
|
||||
_inherit = ['soong.workflow.mixin', 'mail.thread.main.attachment', 'mail.activity.mixin']
|
||||
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@ from odoo.osv import expression
|
||||
from urllib.parse import quote
|
||||
import logging
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
_logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def get_is_leader_domain(is_leader: bool):
|
||||
@@ -86,12 +86,8 @@ class YuthonWillTask(http.Controller):
|
||||
users_id = int(kwargs.get('users_id'))
|
||||
_filter = kwargs.get('filter')
|
||||
state = kwargs.get('state')
|
||||
order = 'task_datetime desc' if state == 'done' else 'task_datetime desc'
|
||||
|
||||
order = 'task_datetime desc' if state == 'done' else 'task_datetime asc'
|
||||
domain = [('users_ids', 'in', [users_id])]
|
||||
logger.info(f"{kwargs}")
|
||||
logger.info(f"{kwargs}")
|
||||
logger.info(f"{kwargs}")
|
||||
if _filter == 'leader':
|
||||
domain = [('user_role_ids.name', 'in', ['董事长', '分管领导', '总经理', '部门副经理', '副总经理', '司机'])]
|
||||
# expression.AND([domain, get_is_leader_domain(True)])
|
||||
@@ -111,26 +107,31 @@ class YuthonWillTask(http.Controller):
|
||||
state_dict = dict(WillTask.fields_get(allfields=['task_state'])['task_state']['selection'])
|
||||
result_list = []
|
||||
task_ids = request.env['yuthon.will.task'].sudo().search(domain, offset=start, limit=20, order=order)
|
||||
user_id = request.env['res.users'].sudo().search([('id', '=', users_id)])
|
||||
company_id = user_id.company_id
|
||||
for task in task_ids:
|
||||
weekday_str = ["周一", "周二", "周三", "周四", "周五", "周六", "周日"][task.start_date.weekday()]
|
||||
result = {
|
||||
'id': task.id,
|
||||
'name': task.name,
|
||||
'employee_id': task.employee_id.name or '',
|
||||
'employee_ids': ', '.join(task.employee_ids.mapped('name')) if task.employee_ids else '',
|
||||
'employee_num': len(task.employee_ids),
|
||||
'start_date': fields.Date.to_string(task.start_date),
|
||||
'weekday': weekday_str,
|
||||
'request_hour_from': '',
|
||||
'request_hour_to': '',
|
||||
'state': task.task_state,
|
||||
'display_state': state_dict.get(task.task_state),
|
||||
'task_type': task.task_type
|
||||
}
|
||||
hour_dict = dict(request_hour_selection)
|
||||
result['request_hour_from'] = hour_dict.get(task.request_hour_from)
|
||||
result['request_hour_to'] = hour_dict.get(task.request_hour_to)
|
||||
result_list.append(result)
|
||||
# _logger.info(f"当前用户{user_id.name}--对应公司{company_id.name}--任务公司{task.company_id.name}")
|
||||
if company_id.id == task.company_id.id:
|
||||
weekday_str = ["周一", "周二", "周三", "周四", "周五", "周六", "周日"][task.start_date.weekday()]
|
||||
result = {
|
||||
'id': task.id,
|
||||
'name': task.name,
|
||||
'employee_id': task.employee_id.name or '',
|
||||
'employee_ids': ', '.join(task.employee_ids.mapped('name')) if task.employee_ids else '',
|
||||
'employee_num': ','.join(task.employee_ids.mapped('name')) if task.employee_ids else '',
|
||||
'start_date': fields.Date.to_string(task.start_date),
|
||||
'weekday': weekday_str,
|
||||
'address': task.address or '',
|
||||
'request_hour_from': '',
|
||||
'request_hour_to': '',
|
||||
'state': task.task_state,
|
||||
'display_state': state_dict.get(task.task_state),
|
||||
'task_type': task.task_type
|
||||
}
|
||||
hour_dict = dict(request_hour_selection)
|
||||
result['request_hour_from'] = hour_dict.get(task.request_hour_from)
|
||||
result['request_hour_to'] = hour_dict.get(task.request_hour_to)
|
||||
result_list.append(result)
|
||||
return json.dumps({
|
||||
'data': result_list,
|
||||
'code': 200,
|
||||
|
||||
@@ -309,8 +309,8 @@
|
||||
<t t-if="record.task_week.raw_value">
|
||||
<t t-esc="record.task_week.raw_value"/>
|
||||
</t>
|
||||
<t t-if="record.request_hour_from.raw_value">
|
||||
<t t-esc="record.request_hour_from.raw_value"/> - <t t-esc="record.request_hour_to.raw_value"/>
|
||||
<t t-if="record.request_hour_from.value and record.request_hour_to.value">
|
||||
<t t-esc="record.request_hour_from.value"/> - <t t-esc="record.request_hour_to.value"/>
|
||||
</t>
|
||||
</div>
|
||||
<!-- 参与人 -->
|
||||
|
||||
@@ -228,6 +228,12 @@
|
||||
action="attendance_iot.attendance_iot_action"
|
||||
sequence="80"/>
|
||||
|
||||
<menuitem id="menu_attendance_iot_log_board"
|
||||
name="考勤机日志"
|
||||
parent="hr_attendance_root_board_menu"
|
||||
action="attendance_iot.attendance_iot_log_action"
|
||||
sequence="81"/>
|
||||
|
||||
<!-- <menuitem-->
|
||||
<!-- id="menu_att_report"-->
|
||||
<!-- name="报表"-->
|
||||
@@ -302,11 +308,11 @@
|
||||
parent="attendance_resources_setting_root_board"
|
||||
sequence="8"
|
||||
action="yuthon_hr_attendance.view_overtime_page_action"/>
|
||||
<menuitem id="menu_hr_resource_calendar_board"
|
||||
name="法定节假日表"
|
||||
parent="attendance_resources_setting_root_board"
|
||||
sequence="10"
|
||||
action="yuthon_hr_attendance.resource_calendar_leaves_action_from_calendar"/>
|
||||
<!-- <menuitem id="menu_hr_resource_calendar_board"-->
|
||||
<!-- name="法定节假日表"-->
|
||||
<!-- parent="attendance_resources_setting_root_board"-->
|
||||
<!-- sequence="10"-->
|
||||
<!-- action="yuthon_hr_attendance.resource_calendar_leaves_action_from_calendar"/>-->
|
||||
<menuitem id="holiday_set_type_board2"
|
||||
name="休假类型"
|
||||
parent="attendance_resources_setting_root_board"
|
||||
@@ -779,6 +785,7 @@
|
||||
<menuitem id="holiday_manage_menu_root_board" name="我的" web_icon="yuthon_work_brand,static/description/holiday.png" sequence="3">
|
||||
<menuitem id="menu_workflow_approval_request_new" name="新建流程" action="soong_workflow.action_kklw_workflow_approval_request" sequence="5" groups="base.group_user"/>
|
||||
<menuitem id="menu_soong_workflow_todo_record" name="待办流程" action="soong_workflow.soong_workflow_record_todo_action" sequence="10" groups="base.group_user"/>
|
||||
<menuitem id="yuthon_salary_meal_views_menu_employee" name="我的餐费" action="yuthon_salary.view_yuthon_meal_expenses_action_readonly" sequence="11" groups="base.group_user"/>
|
||||
<menuitem id="menu_soong_workflow_done_record" name="已办流程" action="soong_workflow.soong_workflow_record_done_action" sequence="15" groups="base.group_user"/>
|
||||
<menuitem id="menu_soong_workflow_department_record" name="流程查询" action="soong_workflow.soong_workflow_department_record_action" sequence="20" groups="base.group_user"/>
|
||||
<menuitem id="menu_workflow_approval_request_admin" name="流程监控" action="soong_workflow.soong_workflow_record_action_admin" sequence="25"/>
|
||||
|
||||
@@ -61,6 +61,7 @@
|
||||
<menuitem id="inventory_asset_fixed_root" name="固定资产" action="maintenance.hr_equipment_action" sequence="20"/>
|
||||
</menuitem>
|
||||
<menuitem id="inventory_setting_product_tag_root" name="产品模版" action="product.product_tag_action" sequence="80"/>
|
||||
<menuitem id="inventory_setting_putaway_root" name="上架规则" action="stock.action_putaway_tree" sequence="90"/>
|
||||
</menuitem>
|
||||
</menuitem>
|
||||
</odoo>
|
||||
Reference in New Issue
Block a user