Merge remote-tracking branch 'origin/dev' into dev
This commit is contained in:
@@ -7,6 +7,12 @@ class MenuInherit(models.Model):
|
||||
|
||||
is_phone = fields.Boolean("是否手机显示", default=True)
|
||||
|
||||
def update_is_phone(self):
|
||||
menu_ids = self.env["ir.ui.menu"].browse(
|
||||
self._context.get('active_ids', self._context.get('active_id')))
|
||||
for menu in menu_ids:
|
||||
menu.is_phone = False
|
||||
|
||||
def load_web_menus(self, debug):
|
||||
web_menus = {}
|
||||
menus = self.search_read([], fields=['id', 'is_phone'])
|
||||
|
||||
@@ -725,18 +725,18 @@ class SoongWorkflowMixin(models.AbstractModel):
|
||||
wkf_rec = wkf_obj.search([("model_id", "=", model), ('is_enable', '=', True)])
|
||||
for node in wkf_rec.node_ids:
|
||||
for button in node.button_ids:
|
||||
# if self.env.user.has_group("soong_workflow.group_soong_workflow_manager"):
|
||||
# btn_exec_action_el = etree.SubElement(header_el, "button")
|
||||
# btn_exec_action_el.set("name", "btn_exec_action")
|
||||
# btn_exec_action_el.set("string", button.name)
|
||||
# btn_exec_action_el.set("type", "object")
|
||||
# if button.is_highlight:
|
||||
# btn_exec_action_el.set("class", "oe_highlight")
|
||||
# if button.has_icon:
|
||||
# btn_exec_action_el.set("icon", button.icon)
|
||||
# btn_exec_action_el.set("invisible", "state != '%s'" % node.node_name)
|
||||
# btn_exec_action_el.set("context", "{'btn_key':'%s','active_model':'%s'}" % (button.btn_key, self._name),)
|
||||
# else:
|
||||
if self.env.user.has_group("soong_workflow.group_soong_workflow_manager"):
|
||||
btn_exec_action_el = etree.SubElement(header_el, "button")
|
||||
btn_exec_action_el.set("name", "btn_exec_action")
|
||||
btn_exec_action_el.set("string", button.name)
|
||||
btn_exec_action_el.set("type", "object")
|
||||
if button.is_highlight:
|
||||
btn_exec_action_el.set("class", "oe_highlight")
|
||||
if button.has_icon:
|
||||
btn_exec_action_el.set("icon", button.icon)
|
||||
btn_exec_action_el.set("invisible", "state != '%s'" % node.node_name)
|
||||
btn_exec_action_el.set("context", "{'btn_key':'%s','active_model':'%s'}" % (button.btn_key, self._name),)
|
||||
else:
|
||||
is_apostille = False
|
||||
if button.btn_hide:
|
||||
if button.review_type == "individual":
|
||||
|
||||
@@ -11,6 +11,16 @@
|
||||
parent="menu_soong_workflow_root"
|
||||
action="action_kklw_workflow_approval_request"
|
||||
sequence="1"/>
|
||||
<menuitem id="menu_soong_workflow_todo_record"
|
||||
name="待办"
|
||||
parent="menu_soong_workflow_root"
|
||||
action="soong_workflow_record_todo_action"
|
||||
sequence="2"/>
|
||||
<menuitem id="menu_soong_workflow_done_record"
|
||||
name="已办"
|
||||
parent="menu_soong_workflow_root"
|
||||
action="soong_workflow_record_done_action"
|
||||
sequence="3"/>
|
||||
<menuitem id="menu_soong_workflow_other_record"
|
||||
name="流程查询"
|
||||
parent="menu_soong_workflow_root"
|
||||
|
||||
@@ -199,6 +199,27 @@
|
||||
<field name="search_view_id" ref="soong_workflow_record_search"/>
|
||||
<field name="view_id" ref="soong_workflow_record_my_tree"/>
|
||||
</record>
|
||||
<record id="soong_workflow_record_todo_action" model="ir.actions.act_window">
|
||||
<field name="name">待办</field>
|
||||
<field name="type">ir.actions.act_window</field>
|
||||
<field name="res_model">soong.workflow.record</field>
|
||||
<field name="view_mode">tree,kanban,search</field>
|
||||
<!-- <field name="context">{'check_employee': 1, 'search_default_is_start':1, 'search_default_is_to_do':1}</field>-->
|
||||
<field name="context">{'header_search_default_approve_state': 1, 'header_search_default_to_do':1, 'check_employee': 1}</field>
|
||||
<field name="domain">[('users_ids', 'in', uid), ('reclaim_state', '=', False), ('soong_state', '=', 'to_do')]</field>
|
||||
<field name="search_view_id" ref="soong_workflow_record_search1"/>
|
||||
<field name="view_id" ref="soong_workflow_record_my_tree"/>
|
||||
</record>
|
||||
<record id="soong_workflow_record_done_action" model="ir.actions.act_window">
|
||||
<field name="name">已办</field>
|
||||
<field name="type">ir.actions.act_window</field>
|
||||
<field name="res_model">soong.workflow.record</field>
|
||||
<field name="view_mode">tree,kanban,search</field>
|
||||
<field name="context">{'header_search_default_approve_state': 1, 'header_search_default_to_do':1, 'check_employee': 1}</field>
|
||||
<field name="domain">[('users_ids', 'in', uid), ('reclaim_state', '=', False), ('soong_state', '=', 'done')]</field>
|
||||
<field name="search_view_id" ref="soong_workflow_record_search1"/>
|
||||
<field name="view_id" ref="soong_workflow_record_my_tree"/>
|
||||
</record>
|
||||
<record id="soong_workflow_hr_employee_action" model="ir.actions.act_window">
|
||||
<field name="name">人事相关流程</field>
|
||||
<field name="type">ir.actions.act_window</field>
|
||||
|
||||
@@ -8,7 +8,6 @@
|
||||
decoration-muted="task_state == 'cancel'"
|
||||
decoration-danger="priority == 'very_urgent'"
|
||||
decoration-info="priority == 'urgent'"
|
||||
decoration-primary="priority == 'general'"
|
||||
decoration-success="priority == 'important'">
|
||||
<field name="task_time" />
|
||||
<field name="start_date" string="任务日期" />
|
||||
@@ -62,8 +61,6 @@
|
||||
<field name="arch" type="xml">
|
||||
<form string="日程">
|
||||
<sheet>
|
||||
<widget name="web_ribbon" title="不紧急不重要" bg_color="text-bg-secondary"
|
||||
invisible="priority != 'general'" />
|
||||
<widget name="web_ribbon" title="重要不紧急" bg_color="text-bg-success"
|
||||
invisible="priority != 'important'" />
|
||||
<widget name="web_ribbon" title="紧急不重要" bg_color="text-bg-warning"
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
'security/ir.model.access.csv',
|
||||
'views/system_version_views.xml',
|
||||
'views/ir_cron_act_views.xml',
|
||||
'views/yuthon_timed_tasks_views.xml',
|
||||
'views/menu.xml',
|
||||
],
|
||||
'assets': {
|
||||
|
||||
@@ -3,4 +3,5 @@ from . import inherit_ir_attachment
|
||||
from . import system_version
|
||||
from . import fields_piyin
|
||||
from . import ir_cron_act
|
||||
from . import yuthon_timed_tasks
|
||||
# from . import res_partner
|
||||
@@ -0,0 +1,22 @@
|
||||
from odoo import models, fields, api
|
||||
|
||||
|
||||
class YuthonTimedTasks(models.Model):
|
||||
_name = 'yuthon.timed.tasks'
|
||||
_description = '定时任务'
|
||||
|
||||
|
||||
sequence = fields.Integer(string='序号')
|
||||
name = fields.Char(string='名称')
|
||||
notice_type = fields.Selection([('attendance', '出勤'), ('schedule', '日程'), ('announcement', '公告'),
|
||||
('attendance_confirmation', '考勤确认单'), ('salary_slip', '薪资条'),
|
||||
('process', '流程'), ('other', '其他')], string='类型')
|
||||
active = fields.Boolean(string='有效', default=True)
|
||||
runtime = fields.Datetime(string="运行时间")
|
||||
interval_number = fields.Integer(string='间隔')
|
||||
interval_type = fields.Selection([('minutes', '分钟'),
|
||||
('hours', '小时'),
|
||||
('days', '天'),
|
||||
('weeks', '周'),
|
||||
('months', '月')], string='运行周期', default='months')
|
||||
model_id = fields.Many2one("ir.model", string="模型")
|
||||
@@ -1,3 +1,4 @@
|
||||
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
|
||||
access_system_version,system_version,model_system_version,base.group_system,1,1,1,1
|
||||
access_ir_cron_type,ir.cron.type,model_ir_cron_type,base.group_system,1,1,1,1
|
||||
access_yuthon_timed_tasks,yuthon.timed.tasks,model_yuthon_timed_tasks,base.group_system,1,1,1,1
|
||||
|
||||
|
@@ -12,7 +12,7 @@
|
||||
<menuitem id="timed_tasks_menu_root"
|
||||
name="定时任务"
|
||||
parent="system_version_menu_root_board"
|
||||
action="base.ir_cron_act"
|
||||
action="yuthon_base.view_yuthon_timed_tasks_action"
|
||||
sequence="5"/>
|
||||
<menuitem id="cron_type_menu_root"
|
||||
name="配置"
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<odoo>
|
||||
<record id="view_yuthon_timed_tasks_tree" model="ir.ui.view">
|
||||
<field name="name">yuthon.timed.tasks.tree</field>
|
||||
<field name="model">yuthon.timed.tasks</field>
|
||||
<field name="arch" type="xml">
|
||||
<tree string="定时任务管理" editable="bottom">
|
||||
<field name="sequence" widget="handle"/>
|
||||
<field name="name"/>
|
||||
<field name="notice_type"/>
|
||||
<field name="model_id"/>
|
||||
<field name="runtime"/>
|
||||
<field name="interval_number"/>
|
||||
<field name="interval_type"/>
|
||||
<field name="active"/>
|
||||
</tree>
|
||||
</field>
|
||||
</record>
|
||||
<record id="view_yuthon_timed_tasks_action" model="ir.actions.act_window">
|
||||
<field name="name">定时任务管理</field>
|
||||
<field name="res_model">yuthon.timed.tasks</field>
|
||||
<field name="view_mode">tree</field>
|
||||
<field name="view_id" ref="view_yuthon_timed_tasks_tree"/>
|
||||
</record>
|
||||
</odoo>
|
||||
@@ -221,16 +221,14 @@ class HrLeave(models.Model):
|
||||
def _compute_duration(self):
|
||||
super()._compute_duration()
|
||||
for holiday in self:
|
||||
# 如果是自然日:
|
||||
# 如果是自然日:(按小时请假)
|
||||
if holiday.holiday_status_id.type_of_work == "1":
|
||||
if holiday.request_date_from and holiday.request_date_to:
|
||||
days = (holiday.request_date_to - holiday.request_date_from).days + 1
|
||||
hours = days * 8
|
||||
else:
|
||||
days = 0
|
||||
hours = 0.0
|
||||
holiday.number_of_hours = hours
|
||||
holiday.number_of_days = days
|
||||
if holiday.holiday_status_id.type_of_work == "0":
|
||||
if holiday.request_hour_from and holiday.request_hour_to:
|
||||
start_hour = float(holiday.request_hour_from)
|
||||
@@ -245,8 +243,10 @@ class HrLeave(models.Model):
|
||||
holiday.number_of_hours = hour
|
||||
else:
|
||||
holiday.number_of_hours = 0
|
||||
days = (holiday.request_date_to - holiday.request_date_from).days + 1
|
||||
holiday.number_of_days = days
|
||||
|
||||
# 按天请假
|
||||
days = holiday.batch_id._compute_duration_day(holiday.holiday_status_id, holiday.request_date_from , holiday.request_date_to)
|
||||
holiday.number_of_days = days
|
||||
|
||||
def _compute_request_unit_hours(self):
|
||||
if not self.env.context.get('no_change_request_unit_hours'):
|
||||
@@ -607,7 +607,7 @@ class HolidaysRequestBatch(models.Model):
|
||||
else:
|
||||
days = 0
|
||||
return days
|
||||
if holiday_status_id.type_of_work == 0:
|
||||
if holiday_status_id.type_of_work == "0":
|
||||
calendar_leaves = self.env['resource.calendar.leaves'].search([("calendar_id", "=", "行政考勤工作日")])
|
||||
holidays_list = []
|
||||
shift_days_list = []
|
||||
|
||||
@@ -326,6 +326,20 @@
|
||||
<field name="numbercall">-1</field>
|
||||
<field eval="False" name="doall"/>
|
||||
</record>
|
||||
|
||||
<record forcecreate="True" id="task_remind_out" model="ir.cron">
|
||||
<field name="name">定时任务:测试提醒</field>
|
||||
<field name="model_id" ref="model_hr_attendance"/>
|
||||
<field name="state">code</field>
|
||||
<field name="code">model.task_remind()</field>
|
||||
<field eval="True" name="active"/>
|
||||
<field name="user_id" ref="base.user_root"/>
|
||||
<field name="interval_number">1</field>
|
||||
<field name="interval_type">days</field>
|
||||
<field name="nextcall" eval="(DateTime.now() + timedelta(days=1)).strftime('%Y-%m-%d 17:00:00')"/>
|
||||
<field name="numbercall">-1</field>
|
||||
<field eval="False" name="doall"/>
|
||||
</record>
|
||||
</data>
|
||||
</odoo>
|
||||
|
||||
|
||||
@@ -63,6 +63,13 @@ class HrAttendance(models.Model):
|
||||
is_last_month = fields.Boolean(string="是否为上月数据", compute='_compute_month_status', store=True)
|
||||
correct_result = fields.Text(string="修正原因")
|
||||
|
||||
def task_remind(self):
|
||||
all_employees = self.env['hr.employee'].search([('name', 'in', ['Administrator', '叶华锋'])])
|
||||
for employee in all_employees:
|
||||
self.sudo().env["wecom.apps"].sync_send_message_textcard(
|
||||
category='att', user_id=employee.wecom_userid,
|
||||
description="记得打卡", title="测试提醒",btntxt="详细信息", )
|
||||
|
||||
def create_attendance_data_holiday(self):
|
||||
"""
|
||||
定时任务create_attendance_data_holiday
|
||||
|
||||
@@ -72,7 +72,11 @@
|
||||
</group>
|
||||
<group>
|
||||
<field name="name" required="1"/>
|
||||
<field name="notice_text" widget="tinymce"/>
|
||||
</group>
|
||||
<div>
|
||||
<field name="notice_text" widget="tinymce"/>
|
||||
</div>
|
||||
<group>
|
||||
<field name="documents_ids" widget="preview_many2many"/>
|
||||
</group>
|
||||
<group col="4" string="发布范围">
|
||||
|
||||
@@ -95,7 +95,7 @@
|
||||
<field name="model">meter.archives.line</field>
|
||||
<field name="arch" type="xml">
|
||||
<tree string="电表任务" create="1" editable="bottom" limit="15"
|
||||
js_class="custom_meter_button" decoration-success="not is_push" default_order="meter_date_month desc">
|
||||
js_class="custom_meter_button" decoration-success="is_push" default_order="meter_date_month desc">
|
||||
<header>
|
||||
<!-- <button name="delete_dec_2025_meter_data" type="object" string="删除" class="oe_highlight"/>-->
|
||||
<button name="push_task_push_wizard" type="object" string="推送" class="oe_highlight"/>
|
||||
|
||||
@@ -98,7 +98,7 @@
|
||||
<field name="name">meter.water.line.tree</field>
|
||||
<field name="model">meter.water.line</field>
|
||||
<field name="arch" type="xml">
|
||||
<tree string="水表任务" create="0" editable="bottom" js_class="custom_water_button" decoration-success="not is_push"
|
||||
<tree string="水表任务" create="0" editable="bottom" js_class="custom_water_button" decoration-success="is_push"
|
||||
default_order="meter_date_month desc" limit="15">
|
||||
<header>
|
||||
<button name="push_task_push_wizard" type="object" string="推送" class="oe_highlight"/>
|
||||
|
||||
@@ -86,7 +86,6 @@ class MeterPriceWizard(models.TransientModel):
|
||||
hydropower_log = self.env['hydropower.logs'].search(search_domain, limit=1)
|
||||
log_data = {
|
||||
'meter_type': 'electric',
|
||||
'logs_date': start_date,
|
||||
'select_time': self.select_time,
|
||||
'select_year': self.select_year,
|
||||
'line_loss': self.line_loss,
|
||||
|
||||
@@ -86,7 +86,6 @@ class WaterPriceWizard(models.TransientModel):
|
||||
hydropower_log = self.env['hydropower.logs'].search(search_domain, limit=1)
|
||||
log_data = {
|
||||
'meter_type': 'water',
|
||||
'logs_date': start_date,
|
||||
'select_time': self.select_time,
|
||||
'select_year': self.select_year,
|
||||
'line_loss': self.line_loss,
|
||||
|
||||
@@ -833,94 +833,6 @@ class PropertyAccountsReceivable(models.Model):
|
||||
for receivable in receivable_ids:
|
||||
receivable._compute_property_ids()
|
||||
|
||||
def de_duplicate(self):
|
||||
# 查询所有记录并按 id 升序排列
|
||||
records = self.search([], order='id ASC')
|
||||
# 用于存储已存在的组合
|
||||
unique_combinations = set()
|
||||
records_to_delete = self.browse() # 创建一个空记录集
|
||||
# 遍历所有记录,找出重复项
|
||||
for record in records:
|
||||
combination = (
|
||||
record.contract_id.id,
|
||||
record.property_id.id,
|
||||
record.lessee_id.id,
|
||||
record.due_date
|
||||
)
|
||||
|
||||
# 如果组合已存在,则添加到删除列表
|
||||
if combination in unique_combinations:
|
||||
records_to_delete += record
|
||||
else:
|
||||
# 否则添加到唯一组合集合
|
||||
unique_combinations.add(combination)
|
||||
# 删除重复记录
|
||||
if records_to_delete:
|
||||
records_to_delete.unlink()
|
||||
|
||||
def initialize_reconciliation(self):
|
||||
receivable_ids = self.env["property.accounts.receivable"].browse(
|
||||
self._context.get('active_ids', self._context.get('active_id')))
|
||||
for receivable in receivable_ids:
|
||||
receivable.delivered1 = receivable.submitted
|
||||
receivable.submitted = 0
|
||||
receivable.is_reconciliation = True
|
||||
|
||||
due_year = receivable.due_date.year
|
||||
due_month = receivable.due_date.month
|
||||
# 构建日期范围条件
|
||||
import calendar
|
||||
last_day = calendar.monthrange(due_year, due_month)[1]
|
||||
# 构建日期范围条件(使用正确的最后一天)
|
||||
start_date = f"{due_year}-{due_month:02d}-01"
|
||||
end_date = f"{due_year}-{due_month:02d}-{last_day}"
|
||||
# 搜索条件使用大于等于当月第一天,小于等于当月最后一天
|
||||
statements = self.env['property.bank.statements'].search([
|
||||
('name_account', '=', receivable.lessee_id.name),
|
||||
('bank_state', '=', 'reconciled'),
|
||||
('start_time', '>=', start_date),
|
||||
('start_time', '<=', end_date),
|
||||
])
|
||||
if statements:
|
||||
for statement in statements:
|
||||
receivable.payout_date = statement.start_time.date()
|
||||
else:
|
||||
receivable.payout_date = receivable.due_date
|
||||
|
||||
# @api.model_create_multi
|
||||
# def create(self, vals_list):
|
||||
# records = super().create(vals_list)
|
||||
# for record in records:
|
||||
# if record.lessee_id and record.contract_id:
|
||||
# lease_address_ids = record.contract_id.lease_ids.mapped('address_id.id')
|
||||
# property_ids_value = [(6, 0, lease_address_ids)] if lease_address_ids else [(6, 0, [])]
|
||||
# statements = self.env['property.bank.statements'].search([
|
||||
# ('name_account', '=', record.lessee_id.name),
|
||||
# ('bank_state', '=', 'not_reconciled'),
|
||||
# ])
|
||||
# contract_id_value = [(4, record.contract_id.id)] if record.contract_id else []
|
||||
# for statement in statements:
|
||||
# statement.write({
|
||||
# 'property_ids': property_ids_value,
|
||||
# 'contract_ids': contract_id_value,
|
||||
# })
|
||||
#
|
||||
# contract_account_map = {}
|
||||
# for vals in vals_list:
|
||||
# if 'contract_id' in vals and vals['contract_id']:
|
||||
# contract_id = vals['contract_id']
|
||||
# if contract_id not in contract_account_map:
|
||||
# contract_account = self.env['contract.accounts.receivable'].search([
|
||||
# ('contract_id', '=', contract_id)
|
||||
# ], limit=1)
|
||||
# if not contract_account:
|
||||
# contract_account = self.env['contract.accounts.receivable'].create({
|
||||
# 'contract_id': contract_id
|
||||
# })
|
||||
# contract_account.onchange_contract_id()
|
||||
#
|
||||
# return records
|
||||
|
||||
@api.onchange('penalty_date')
|
||||
def _onchange_penalty_date(self):
|
||||
for record in self:
|
||||
@@ -947,32 +859,7 @@ class PropertyAccountsReceivable(models.Model):
|
||||
penalty = days_difference * receivable.receivable_id.difference_amount
|
||||
receivable.receivable_id.write({'penalty': penalty})
|
||||
|
||||
# 批量撤销
|
||||
def batch_receivable_return(self):
|
||||
archives_ids = self.env["property.accounts.receivable"].browse(
|
||||
self._context.get('active_ids', self._context.get('active_id')))
|
||||
for rec in archives_ids:
|
||||
# 银行流水对应的已对账改为未对账
|
||||
due_year = rec.due_date.year
|
||||
due_month = rec.due_date.month
|
||||
import calendar
|
||||
last_day = calendar.monthrange(due_year, due_month)[1]
|
||||
|
||||
# 构建日期范围条件(使用正确的最后一天)
|
||||
start_date = f"{due_year}-{due_month:02d}-01"
|
||||
end_date = f"{due_year}-{due_month:02d}-{last_day}"
|
||||
# 搜索条件使用大于等于当月第一天,小于等于当月最后一天
|
||||
statements = self.env['property.bank.statements'].search([
|
||||
('name_account', '=', rec.lessee_id.name),
|
||||
('bank_state', '=', 'reconciled'),
|
||||
('start_time', '>=', start_date),
|
||||
('start_time', '<=', end_date),
|
||||
])
|
||||
rec.is_reconciliation = False
|
||||
for statement in statements:
|
||||
statement.write({'bank_state': 'not_reconciled'})
|
||||
|
||||
# 批量退回
|
||||
# 批量退回
|
||||
def action_refuse_all(self):
|
||||
model_type_data = {
|
||||
'水费': 'meter.water.line',
|
||||
@@ -983,25 +870,25 @@ class PropertyAccountsReceivable(models.Model):
|
||||
}
|
||||
archives_ids = self.env["property.accounts.receivable"].browse(
|
||||
self._context.get('active_ids', self._context.get('active_id')))
|
||||
valid_management_types = list(model_type_data.keys())
|
||||
valid_management_types = list(model_type_data.values())
|
||||
for rec in archives_ids:
|
||||
if rec.is_reconciliation == True:
|
||||
raise UserError("已对账的记录不能退回!请先银行流水撤销再退回")
|
||||
model_type = model_type_data.get(rec.management_type_id.name)
|
||||
if model_type not in valid_management_types:
|
||||
rec.unlink()
|
||||
continue
|
||||
if model_type in ('meter.archives.line', 'meter.water.line'):
|
||||
year = rec.due_date_end.year
|
||||
month = rec.due_date_end.month
|
||||
first_day = date(year, month, 1)
|
||||
if month == 12:
|
||||
next_month_first_day = date(year + 1, 1, 1)
|
||||
else:
|
||||
next_month_first_day = date(year, month + 1, 1)
|
||||
last_day = next_month_first_day - timedelta(days=1)
|
||||
if not rec.charging_range:
|
||||
raise UserError("请输入计费区间, 按照应为'YYYY-MM-DD 到 YYYY-MM-DD格式")
|
||||
charging_range = rec.charging_range.strip()
|
||||
start_str, end_str = [x.strip() for x in charging_range.split("到")]
|
||||
start_date = (datetime.strptime(end_str, "%Y-%m-%d").date()).replace(day=1)
|
||||
end_date = datetime.strptime(end_str, "%Y-%m-%d").date()
|
||||
model_id = self.env[model_type].search([
|
||||
('contract_id', '=', rec.contract_id.id),
|
||||
('meter_date', '>=', first_day),
|
||||
('meter_date', '<=', last_day)
|
||||
('meter_date', '>=', start_date),
|
||||
('meter_date', '<=', end_date)
|
||||
])
|
||||
else:
|
||||
last_day = rec.due_date + relativedelta(months=1) - timedelta(days=1)
|
||||
|
||||
@@ -452,26 +452,12 @@
|
||||
</search>
|
||||
</field>
|
||||
</record>
|
||||
<!-- <record id="initialize_reconciliation" model="ir.actions.server">-->
|
||||
<!-- <field name="name">初始化对账</field>-->
|
||||
<!-- <field name="model_id" ref="yuthon_property.model_property_accounts_receivable"/>-->
|
||||
<!-- <field name="binding_model_id" ref="yuthon_property.model_property_accounts_receivable"/>-->
|
||||
<!-- <field name="state">code</field>-->
|
||||
<!-- <field name="code">action = model.initialize_reconciliation()</field>-->
|
||||
<!-- </record>-->
|
||||
<!-- <record id="initialize_update_property" model="ir.actions.server">-->
|
||||
<!-- <field name="name">更新物业信息</field>-->
|
||||
<!-- <field name="model_id" ref="yuthon_property.model_property_accounts_receivable"/>-->
|
||||
<!-- <field name="binding_model_id" ref="yuthon_property.model_property_accounts_receivable"/>-->
|
||||
<!-- <field name="state">code</field>-->
|
||||
<!-- <field name="code">action = model.update_property_ids()</field>-->
|
||||
<!-- </record>-->
|
||||
<!-- <record id="de_duplicate_server" model="ir.actions.server">-->
|
||||
<!-- <field name="name">删除重复数据</field>-->
|
||||
<!-- <field name="model_id" ref="yuthon_property.model_property_accounts_receivable"/>-->
|
||||
<!-- <field name="binding_model_id" ref="yuthon_property.model_property_accounts_receivable"/>-->
|
||||
<!-- <field name="state">code</field>-->
|
||||
<!-- <field name="code">action = model.de_duplicate()</field>-->
|
||||
<!-- </record>-->
|
||||
<record id="property_accounts_receivable_action" model="ir.actions.act_window">
|
||||
<field name="name">应收账单</field>
|
||||
@@ -608,13 +594,6 @@
|
||||
<field name="state">code</field>
|
||||
<field name="code">action = model.all_penalty_date()</field>
|
||||
</record>
|
||||
<record id="all_button_return_property" model="ir.actions.server">
|
||||
<field name="name">批量撤销</field>
|
||||
<field name="model_id" ref="yuthon_property.model_property_accounts_receivable"/>
|
||||
<field name="binding_model_id" ref="yuthon_property.model_property_accounts_receivable"/>
|
||||
<field name="state">code</field>
|
||||
<field name="code">action = model.batch_receivable_return()</field>
|
||||
</record>
|
||||
<record id="all_action_refuse_all" model="ir.actions.server">
|
||||
<field name="name">批量退回</field>
|
||||
<field name="model_id" ref="yuthon_property.model_property_accounts_receivable"/>
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
'category': 'zhou',
|
||||
'version': '0.1',
|
||||
'license': 'LGPL-3',
|
||||
'depends': ['base', 'web', 'yuthon_property','yuthon_property_approval'],
|
||||
'depends': ['base', 'web', 'yuthon_property','yuthon_property_approval', 'hr_attendance'],
|
||||
'data': [
|
||||
'views/menu.xml',
|
||||
'views/ledger_report_views.xml',
|
||||
@@ -16,6 +16,7 @@
|
||||
'views/cumulative_income_report.xml',
|
||||
'views/overdue_amount_report.xml',
|
||||
'views/yuthon_report_res_partner.xml',
|
||||
'views/att_report_view.xml',
|
||||
],
|
||||
'installable': True,
|
||||
'application': True,
|
||||
@@ -38,6 +39,8 @@
|
||||
'yuthon_report/static/src/components/yuthon_report/yuthon_report.xml',
|
||||
'yuthon_report/static/src/components/yuthon_report/yuthon_contract_report.js',
|
||||
'yuthon_report/static/src/components/yuthon_report/yuthon_contract_report.xml',
|
||||
'yuthon_report/static/src/components/yuthon_report/att_report.js',
|
||||
'yuthon_report/static/src/components/yuthon_report/att_report.xml',
|
||||
'yuthon_report/static/src/components/yuthon_report/receivable_message_report.js',
|
||||
'yuthon_report/static/src/components/yuthon_report/receivable_message.xml',
|
||||
'yuthon_report/static/src/components/yuthon_report/yuthon_report.scss',
|
||||
|
||||
@@ -5,4 +5,5 @@ from . import receivable_report
|
||||
from . import receivables_message_report
|
||||
from . import yuthon_contract_report
|
||||
from . import cumulative_income_report
|
||||
from . import overdue_amount_report
|
||||
from . import overdue_amount_report
|
||||
from . import att_report
|
||||
@@ -0,0 +1,138 @@
|
||||
import datetime
|
||||
|
||||
from odoo import fields, models, api
|
||||
|
||||
|
||||
class AttendanceReport(models.Model):
|
||||
_inherit = 'hr.attendance'
|
||||
|
||||
def _get_common_domain_and_employees(self, params):
|
||||
vacation_domain = []
|
||||
if params.get("date_start"):
|
||||
date_start = datetime.datetime.fromisoformat(params.get("date_start")).date()
|
||||
vacation_domain.append(("vacation_date", ">=", date_start))
|
||||
if params.get("date_end"):
|
||||
date_end = datetime.datetime.fromisoformat(params.get("date_end")).date()
|
||||
vacation_domain.append(("vacation_date", "<=", date_end))
|
||||
salary_group_id = params.get('structure_id', False)
|
||||
department_id = params.get('department_id', False)
|
||||
company_id = params.get('company_id', False)
|
||||
|
||||
employee_domain = []
|
||||
if salary_group_id:
|
||||
employee_domain.append(('contract_id.salary_group_id', '=', salary_group_id))
|
||||
if department_id:
|
||||
employee_domain.append(('department_id', '=', department_id))
|
||||
if company_id:
|
||||
employee_domain.append(('company_id', '=', company_id))
|
||||
|
||||
employee_ids = []
|
||||
if employee_domain:
|
||||
employee_ids = self.env['hr.employee'].search(employee_domain).ids
|
||||
if employee_ids:
|
||||
vacation_domain.append(("employee_id", "in", employee_ids))
|
||||
|
||||
return vacation_domain, employee_ids
|
||||
|
||||
# ---------------------- 年假/其他假期报表 ----------------------
|
||||
@api.model
|
||||
def get_attendance_report(self, params):
|
||||
vacation_domain, employee_ids = self._get_common_domain_and_employees(params)
|
||||
if employee_ids and not employee_ids:
|
||||
return []
|
||||
vacation_reports = self.env['yuthon.vacation.reports'].search(vacation_domain, limit=1000)
|
||||
result_list = []
|
||||
for report in vacation_reports:
|
||||
employee_name = report.employee_id.name or ""
|
||||
company_name = report.company_id.name or ""
|
||||
for leave_line in report.leave_ids.filtered(lambda l: l.workflow_record_id):
|
||||
result_list.append({
|
||||
"员工": employee_name,
|
||||
"公司": company_name,
|
||||
"天数": leave_line.lines or 0.0,
|
||||
"类型": "年假",
|
||||
"流程": leave_line.workflow_record_id.name or ""
|
||||
})
|
||||
for fee_line in report.other_fee_ids.filtered(lambda l: l.workflow_record_id):
|
||||
result_list.append({
|
||||
"员工": employee_name,
|
||||
"公司": company_name,
|
||||
"天数": fee_line.lines or 0.0,
|
||||
"类型": fee_line.holiday_type.name or "其他假期",
|
||||
"流程": fee_line.workflow_record_id.name or ""
|
||||
})
|
||||
return result_list
|
||||
|
||||
# ---------------------- 误餐费报表(外出) ----------------------
|
||||
@api.model
|
||||
def get_meal_fee_report(self, params):
|
||||
vacation_domain, employee_ids = self._get_common_domain_and_employees(params)
|
||||
if employee_ids and not employee_ids:
|
||||
return []
|
||||
vacation_reports = self.env['yuthon.vacation.reports'].search(vacation_domain, limit=1000)
|
||||
result_list = []
|
||||
for report in vacation_reports:
|
||||
employee_name = report.employee_id.name or ""
|
||||
company_name = report.company_id.name or ""
|
||||
for meal_line in report.meal_fee_ids.filtered(lambda l: l.workflow_record_id):
|
||||
result_list.append({
|
||||
"员工": employee_name,
|
||||
"公司": company_name,
|
||||
"次数": meal_line.update_lines or 0,
|
||||
"类型": "外出",
|
||||
"流程": meal_line.workflow_record_id.name or ""
|
||||
})
|
||||
return result_list
|
||||
|
||||
# ---------------------- 加班费报表 ----------------------
|
||||
@api.model
|
||||
def get_overtime_report(self, params):
|
||||
vacation_domain, employee_ids = self._get_common_domain_and_employees(params)
|
||||
if employee_ids and not employee_ids:
|
||||
return []
|
||||
vacation_reports = self.env['yuthon.vacation.reports'].search(vacation_domain, limit=1000)
|
||||
result_list = []
|
||||
for report in vacation_reports:
|
||||
employee_name = report.employee_id.name or ""
|
||||
company_name = report.company_id.name or ""
|
||||
for overtime_line in report.overtime_ids.filtered(lambda l: l.workflow_record_id):
|
||||
overtime_detail = {}
|
||||
if overtime_line.workday > 0:
|
||||
overtime_detail["加班类型"] = "工作日"
|
||||
overtime_detail["时长(小时)"] = overtime_line.workday
|
||||
elif overtime_line.legal_day > 0:
|
||||
overtime_detail["加班类型"] = "法定节假日"
|
||||
overtime_detail["时长(小时)"] = overtime_line.legal_day
|
||||
elif overtime_line.public_holidays > 0:
|
||||
overtime_detail["加班类型"] = "公休日"
|
||||
overtime_detail["时长(小时)"] = overtime_line.public_holidays
|
||||
else:
|
||||
overtime_detail["加班类型"] = "无"
|
||||
overtime_detail["时长(小时)"] = 0.0
|
||||
|
||||
overtime_method_map = {
|
||||
'leave': '补休',
|
||||
'fee': '加班费结算'
|
||||
}
|
||||
compensation_method = overtime_method_map.get(overtime_line.overtime_methods, '补休')
|
||||
result_list.append({
|
||||
"员工": employee_name,
|
||||
"公司": company_name,
|
||||
"类型": "加班",
|
||||
"补偿方式": compensation_method,
|
||||
"加班类型": overtime_detail["加班类型"],
|
||||
"时长(小时)": overtime_detail["时长(小时)"],
|
||||
"流程": overtime_line.workflow_record_id.name or ""
|
||||
})
|
||||
return result_list
|
||||
|
||||
@api.model
|
||||
def get_domain(self, company_id=False):
|
||||
if not company_id:
|
||||
return [], []
|
||||
|
||||
department_records = self.env['hr.department'].search([('company_id', '=', company_id)])
|
||||
department_ids = [dept.id for dept in department_records]
|
||||
salary_group_records = self.env['yuthon.salary.group'].search([('company_id', '=', company_id)])
|
||||
salary_group_ids = [struct.id for struct in salary_group_records]
|
||||
return department_ids, salary_group_ids
|
||||
@@ -0,0 +1,179 @@
|
||||
/** @odoo-module1 **/
|
||||
|
||||
|
||||
import {registry} from "@web/core/registry";
|
||||
import {Component, onMounted, useRef, useState} from "@odoo/owl";
|
||||
import {useBus, useService} from "@web/core/utils/hooks";
|
||||
import {
|
||||
standardActionServiceProps
|
||||
} from "@web/webclient/actions/action_service";
|
||||
import {DateTimeInput} from "@web/core/datetime/datetime_input";
|
||||
import {CheckBox} from "@web/core/checkbox/checkbox";
|
||||
import {Many2XAutocomplete} from "@web/views/fields/relational_utils";
|
||||
import {formatDate} from "@web/core/l10n/dates"
|
||||
|
||||
const {DateTime} = luxon;
|
||||
|
||||
class ReceivableReport extends Component {
|
||||
setup() {
|
||||
this.gridRef = useRef("grid");
|
||||
console.log(this.props.action.context.report_config)
|
||||
|
||||
this.serviceOrm = useService("orm")
|
||||
|
||||
this.state = useState({
|
||||
startDate: DateTime.now().startOf("month"),
|
||||
endDate: DateTime.now().endOf("month"),
|
||||
keyword: "",
|
||||
booleanValue: true,
|
||||
selectDepartment: {},
|
||||
selectCompany: {},
|
||||
selectStructure: {},
|
||||
domainDepartment:[],
|
||||
domainStructure:[]
|
||||
});
|
||||
|
||||
this.config = this.props.action.context.report_config || {};
|
||||
|
||||
onMounted(async () => {
|
||||
// 加载 ag-grid
|
||||
//await loadJS("https://cdn.jsdelivr.net/npm/ag-grid-community/dist/ag-grid-community.min.js");
|
||||
this.gridOptions = {
|
||||
localeText: AG_GRID_LOCALE_CN,
|
||||
theme: agGrid.themeMaterial,
|
||||
columnDefs: this.config.columns || [],
|
||||
rowData: [],
|
||||
sideBar: true,
|
||||
enableCharts: true,
|
||||
cellSelection: true,
|
||||
defaultColDef: {
|
||||
sortable: true,
|
||||
filter: true,
|
||||
width: 200,
|
||||
minWidth: 150,
|
||||
flex: false,
|
||||
resizable: false
|
||||
},
|
||||
getContextMenuItems(params) {
|
||||
const items = params.defaultItems.slice();
|
||||
items.push("chartRange");
|
||||
return items;
|
||||
},
|
||||
|
||||
};
|
||||
this.grid = new agGrid.createGrid(this.gridRef.el, this.gridOptions);
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 改变布尔值
|
||||
* @param e
|
||||
*/
|
||||
|
||||
getDomainCompany() {
|
||||
return []
|
||||
}
|
||||
|
||||
getDomainStructure() {
|
||||
console.log(this.state)
|
||||
const isCompanyEmpty = Object.keys(this.state.selectCompany).length === 0;
|
||||
if (isCompanyEmpty) {
|
||||
return [];
|
||||
} else {
|
||||
return [['id','in', this.state.domainStructure]];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
getDomainDepartment() {
|
||||
console.log(this.state)
|
||||
const isCompanyEmpty = Object.keys(this.state.selectCompany).length === 0;
|
||||
if (isCompanyEmpty) {
|
||||
return [];
|
||||
} else {
|
||||
return [['id','in', this.state.domainDepartment]];
|
||||
}
|
||||
}
|
||||
|
||||
async searchDomain() {
|
||||
let results = await this.serviceOrm.call(
|
||||
'hr.attendance',
|
||||
'get_domain',
|
||||
[],
|
||||
{
|
||||
company_id: this.state.selectCompany?.id,
|
||||
}
|
||||
)
|
||||
console.log(results)
|
||||
this.state.domainDepartment = results[0]
|
||||
this.state.domainStructure = results[1]
|
||||
}
|
||||
|
||||
async onSearch() {
|
||||
console.log(this.state)
|
||||
let startDate = formatDate(this.state.startDate, {format: "yyyy-MM-dd"})
|
||||
let endDate = formatDate(this.state.endDate, {format: "yyyy-MM-dd"})
|
||||
|
||||
const params = {
|
||||
date_start: `${startDate} 00:00:00`,
|
||||
date_end: `${endDate} 23:59:59`,
|
||||
department_id: this.state.selectDepartment?.id,
|
||||
company_id: this.state.selectCompany?.id,
|
||||
structure_id: this.state.selectStructure?.id,
|
||||
};
|
||||
const result = await this.serviceOrm.call(
|
||||
this.config.model,
|
||||
this.config.method,
|
||||
[params]
|
||||
);
|
||||
console.log(result)
|
||||
this.grid.setGridOption('rowData', result);
|
||||
}
|
||||
|
||||
onExportExcel() {
|
||||
this.grid.exportDataAsExcel({
|
||||
fileName: 'my-data.xlsx',
|
||||
sheetName: 'Sheet1'
|
||||
});
|
||||
}
|
||||
|
||||
async onUpdateCompany(v) {
|
||||
this.state.selectCompany = v[0] || {}
|
||||
await this.searchDomain()
|
||||
}
|
||||
|
||||
async onUpdateStructure(v) {
|
||||
this.state.selectStructure = v[0] || {}
|
||||
}
|
||||
|
||||
async onUpdateDepartment(v) {
|
||||
this.state.selectDepartment = v[0]
|
||||
}
|
||||
|
||||
|
||||
async onChangeStartDate(date) {
|
||||
console.log(date)
|
||||
if (Array.isArray(date)) {
|
||||
this.state.startDate = date[0];
|
||||
this.state.endDate = date[1]
|
||||
}
|
||||
}
|
||||
|
||||
async onChangeEndDate(date) {
|
||||
if (Array.isArray(date)) {
|
||||
this.state.startDate = date[0];
|
||||
this.state.endDate = date[1]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ReceivableReport.props = {...standardActionServiceProps};
|
||||
ReceivableReport.template = "att_report.ReceivableReport";
|
||||
ReceivableReport.components = {
|
||||
DateTimeInput,
|
||||
CheckBox,
|
||||
Many2XAutocomplete,
|
||||
};
|
||||
|
||||
registry.category("actions").add("att_report_client", ReceivableReport);
|
||||
@@ -0,0 +1,87 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<templates id="template" xml:space="preserve">
|
||||
<t t-name="att_report.ReceivableReport">
|
||||
<div class="container-fluid d-flex flex-column h-100 mt-2 pb-3">
|
||||
<!-- 筛选卡片 -->
|
||||
<div class="card mb-2">
|
||||
<div class="card-body">
|
||||
<!-- 搜索区域 -->
|
||||
<div class="row mb-2" t-ref="search_area">
|
||||
|
||||
<!-- 应收日期范围 -->
|
||||
<div class="col-3">
|
||||
<label>日期范围</label>
|
||||
<div class="d-flex align-items-center gap-2">
|
||||
<DateTimeInput
|
||||
range="true"
|
||||
value="state.startDate"
|
||||
type="'date'"
|
||||
placeholder="fromPlaceholder"
|
||||
onChange="(date) => this.onChangeStartDate(date)"
|
||||
/>
|
||||
<i class="oi oi-arrow-right"></i>
|
||||
<DateTimeInput
|
||||
range="true"
|
||||
value="state.endDate"
|
||||
type="'date'"
|
||||
placeholder="toPlaceholder"
|
||||
onChange="(date) => this.onChangeEndDate(date)"
|
||||
/>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 所属公司 -->
|
||||
<div class="col-3">
|
||||
<label>所属公司</label>
|
||||
<Many2XAutocomplete
|
||||
value="state.selectCompany?.display_name"
|
||||
getDomain="getDomainCompany"
|
||||
resModel="'res.company'"
|
||||
fieldString="'所属公司'"
|
||||
activeActions="{}"
|
||||
update.bind="onUpdateCompany"
|
||||
/>
|
||||
</div>
|
||||
<div class="col-3">
|
||||
<label>部门</label>
|
||||
<Many2XAutocomplete
|
||||
value="state.selectDepartment?.display_name"
|
||||
getDomain.bind="getDomainDepartment"
|
||||
resModel="'hr.department'"
|
||||
fieldString="'部门'"
|
||||
activeActions="{}"
|
||||
update.bind="onUpdateDepartment"
|
||||
/>
|
||||
</div>
|
||||
<div class="col-3">
|
||||
<label>薪资分组</label>
|
||||
<Many2XAutocomplete
|
||||
value="state.selectStructure?.display_name"
|
||||
getDomain.bind="getDomainStructure"
|
||||
resModel="'yuthon.salary.group'"
|
||||
fieldString="'薪资分组'"
|
||||
activeActions="{}"
|
||||
update.bind="onUpdateStructure"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<!-- 操作按钮 -->
|
||||
<div class="col-12 mt-3 d-flex justify-content-end gap-2">
|
||||
<button class="btn btn-primary" t-on-click="onSearch">搜索</button>
|
||||
<button class="btn btn-success" t-on-click="onExportExcel">导出</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- ag-grid 表格区域 -->
|
||||
<div class="row flex-grow-1">
|
||||
<div class="col-12 h-100">
|
||||
<div class="ag-theme-alpine w-100 h-100" t-ref="grid"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</t>
|
||||
</templates>
|
||||
@@ -0,0 +1,88 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
<data>
|
||||
<record id="action_leave_deduction_report" model="ir.actions.client">
|
||||
<field name="name">请假扣款报表</field>
|
||||
<field name="tag">get_attendance_report</field>
|
||||
<field name="context">
|
||||
{
|
||||
"sideBar": true,
|
||||
"report_config": {
|
||||
"model": "hr.attendance",
|
||||
"method": "get_attendance_report",
|
||||
"columns": [
|
||||
{"headerName": "员工", "field": "员工", "flex": 1},
|
||||
{"headerName": "公司", "field": "公司", "flex": 1},
|
||||
{"headerName": "天数", "field": "天数", "flex": 1},
|
||||
{"headerName": "类型", "field": "类型", "flex": 1},
|
||||
{"headerName": "流程", "field": "流程", "flex": 1}
|
||||
]
|
||||
}
|
||||
}
|
||||
</field>
|
||||
</record>
|
||||
<record id="action_meal_fee_report" model="ir.actions.client">
|
||||
<field name="name">误餐费报表</field>
|
||||
<field name="tag">get_meal_fee_report</field>
|
||||
<field name="context">
|
||||
{
|
||||
"sideBar": true,
|
||||
"report_config": {
|
||||
"model": "hr.attendance",
|
||||
"method": "get_meal_fee_report",
|
||||
"columns": [
|
||||
{"headerName": "员工", "field": "员工", "flex": 1},
|
||||
{"headerName": "公司", "field": "公司", "flex": 1},
|
||||
{"headerName": "次数", "field": "次数", "flex": 1},
|
||||
{"headerName": "类型", "field": "类型", "flex": 1},
|
||||
{"headerName": "流程", "field": "流程", "flex": 1}
|
||||
]
|
||||
}
|
||||
}
|
||||
</field>
|
||||
</record>
|
||||
<record id="action_overtime_report" model="ir.actions.client">
|
||||
<field name="name">加班费报表</field>
|
||||
<field name="tag">get_overtime_report</field>
|
||||
<field name="context">
|
||||
{
|
||||
"sideBar": true,
|
||||
"report_config": {
|
||||
"model": "hr.attendance",
|
||||
"method": "get_overtime_report",
|
||||
"columns": [
|
||||
{"headerName": "员工", "field": "员工", "flex": 1},
|
||||
{"headerName": "公司", "field": "公司", "flex": 1},
|
||||
{"headerName": "类型", "field": "类型", "flex": 1},
|
||||
{"headerName": "补偿方式", "field": "补偿方式", "flex": 1},
|
||||
{"headerName": "加班类型", "field": "加班类型", "flex": 1},
|
||||
{"headerName": "时长(小时)", "field": "时长(小时)", "flex": 1},
|
||||
{"headerName": "流程", "field": "流程", "flex": 1}
|
||||
]
|
||||
}
|
||||
}
|
||||
</field>
|
||||
</record>
|
||||
<menuitem
|
||||
id="menu_leave_deduction_report"
|
||||
name="请假扣款报表"
|
||||
parent="yuthon_property_approval.property_approval_report_menu"
|
||||
action="action_leave_deduction_report"
|
||||
sequence="8"
|
||||
/>
|
||||
<menuitem
|
||||
id="menu_meal_fee_report"
|
||||
name="误餐费报表"
|
||||
parent="yuthon_property_approval.property_approval_report_menu"
|
||||
action="action_meal_fee_report"
|
||||
sequence="9"
|
||||
/>
|
||||
<menuitem
|
||||
id="menu_overtime_report"
|
||||
name="加班费报表"
|
||||
parent="yuthon_property_approval.property_approval_report_menu"
|
||||
action="action_overtime_report"
|
||||
sequence="10"
|
||||
/>
|
||||
</data>
|
||||
</odoo>
|
||||
@@ -65,8 +65,8 @@ class YuthonWillTask(models.Model):
|
||||
('22', '22:00'), ('22.25', '22:15'), ('22.5', '22:30'), ('22.75', '22:45'),
|
||||
('23', '23:00'), ('23.25', '23:15'), ('23.5', '23:30'), ('23.75', '23:45')], string='结束时间', default='18')
|
||||
|
||||
priority = fields.Selection([('general', '不紧急不重要'), ('important', '重要不紧急'),
|
||||
('urgent', '紧急不重要'), ('very_urgent', '重要且紧急')], string='优先级', default='general')
|
||||
priority = fields.Selection([('important', '重要不紧急'),
|
||||
('urgent', '紧急不重要'), ('very_urgent', '重要且紧急')], string='优先级')
|
||||
code = fields.Char(string="任务编号", default=lambda self: self.env['ir.sequence'].next_by_code('task_code'))
|
||||
user_id = fields.Many2one('res.users', string="创建人", default=lambda self: self.env.user)
|
||||
company_id = fields.Many2one('res.company', string="公司", default=lambda self: self.env.company)
|
||||
@@ -141,7 +141,7 @@ class YuthonWillTask(models.Model):
|
||||
from_time = hour_mapping.get(record.request_hour_from, "")
|
||||
to_time = hour_mapping.get(record.request_hour_to, "")
|
||||
if date_str and from_time and to_time:
|
||||
record.task_time = f"{date_str} ({from_time}--{to_time})"
|
||||
record.task_time = f"{date_str} {from_time}"
|
||||
else:
|
||||
record.task_time = ""
|
||||
|
||||
@@ -204,11 +204,12 @@ class YuthonWillTask(models.Model):
|
||||
|
||||
def add_comment(self):
|
||||
self.ensure_one()
|
||||
employee_list = [i.id for i in self.employee_ids] + [i.id for i in self.employee_ids2]
|
||||
admin = self.env['hr.employee'].search([('name', '=', 'Administrator')])
|
||||
employee_list = [i.id for i in self.employee_ids] + [i.id for i in self.employee_ids2] + admin.id
|
||||
for employee_id in self.env['hr.employee'].search([('id', 'in', employee_list)]):
|
||||
if not employee_id.wecom_userid:
|
||||
raise UserError("请同步{}的企业微信".format(employee_id.name))
|
||||
url = f'http:://oa.thtzjt.com/webh5#/journey?id={self.id}'
|
||||
url = f'https://oa.thtzjt.com/webh5#/journey?id={self.id}'
|
||||
data_name = "事项名称: " + self.name + '\n'
|
||||
data_user_ids = '参与人: ' + ', '.join(self.employee_ids.mapped('name')) + '\n'
|
||||
data_employee_id = ('司机:' + ', '.join(self.employee_ids2.mapped('name')) + '\n') if self.employee_ids2 else ''
|
||||
|
||||
@@ -8,7 +8,6 @@
|
||||
decoration-muted = "task_state == 'cancel'"
|
||||
decoration-danger="priority == 'very_urgent'"
|
||||
decoration-info="priority == 'urgent'"
|
||||
decoration-primary="priority == 'general'"
|
||||
decoration-success="priority == 'important'">
|
||||
<field name='start_date' column_invisible="1"/>
|
||||
<field name='task_time' />
|
||||
@@ -49,7 +48,6 @@
|
||||
<field name="arch" type="xml">
|
||||
<form string="日程">
|
||||
<sheet>
|
||||
<widget name="web_ribbon" title="不紧急不重要" bg_color="text-bg-secondary" invisible="priority != 'general'"/>
|
||||
<widget name="web_ribbon" title="重要不紧急" bg_color="text-bg-success" invisible="priority != 'important'"/>
|
||||
<widget name="web_ribbon" title="紧急不重要" bg_color="text-bg-warning" invisible="priority != 'urgent'"/>
|
||||
<widget name="web_ribbon" title="重要且紧急" bg_color="text-bg-danger" invisible="priority != 'very_urgent'"/>
|
||||
@@ -120,7 +118,6 @@
|
||||
decoration-muted = "task_state == 'cancel'"
|
||||
decoration-danger="priority == 'very_urgent'"
|
||||
decoration-info="priority == 'urgent'"
|
||||
decoration-primary="priority == 'general'"
|
||||
decoration-success="priority == 'important'" create="false" edit="false" js_class="custom_task_tree_button">
|
||||
<field name='start_date' column_invisible="1"/>
|
||||
<field name='task_time' />
|
||||
@@ -148,8 +145,6 @@
|
||||
<field name="arch" type="xml">
|
||||
<form string="日程" create="false">
|
||||
<sheet>
|
||||
<widget name="web_ribbon" title="不紧急不重要" bg_color="text-bg-secondary"
|
||||
invisible="priority != 'general'"/>
|
||||
<widget name="web_ribbon" title="重要不紧急" bg_color="text-bg-success"
|
||||
invisible="priority != 'important'"/>
|
||||
<widget name="web_ribbon" title="紧急不重要" bg_color="text-bg-warning"
|
||||
|
||||
Reference in New Issue
Block a user