From b42f8be26563216799aa21f1dbb45a19d8c49df9 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E6=9D=8E=E9=B9=8F=E5=AE=87?=
<9664676+pengyuthon@user.noreply.gitee.com>
Date: Tue, 16 Dec 2025 14:17:19 +0800
Subject: [PATCH 01/14] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E5=8A=9F=E8=83=BD?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
yuthon_property/wizard/meter_price_wizard.py | 1 -
yuthon_property/wizard/water_price_wizard.py | 1 -
2 files changed, 2 deletions(-)
diff --git a/yuthon_property/wizard/meter_price_wizard.py b/yuthon_property/wizard/meter_price_wizard.py
index c5ffe0c4c..72ea6e9a0 100644
--- a/yuthon_property/wizard/meter_price_wizard.py
+++ b/yuthon_property/wizard/meter_price_wizard.py
@@ -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,
diff --git a/yuthon_property/wizard/water_price_wizard.py b/yuthon_property/wizard/water_price_wizard.py
index 330d998bd..641685c4b 100644
--- a/yuthon_property/wizard/water_price_wizard.py
+++ b/yuthon_property/wizard/water_price_wizard.py
@@ -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,
From 81c2ad21d9d9ef58c2e2d59e87b734878906b4ef Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E6=9D=8E=E9=B9=8F=E5=AE=87?=
<9664676+pengyuthon@user.noreply.gitee.com>
Date: Tue, 16 Dec 2025 14:59:23 +0800
Subject: [PATCH 02/14] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E5=8A=9F=E8=83=BD?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../views/property_meter_archives_views.xml | 2 +-
.../views/property_meter_water_views.xml | 2 +-
.../models/inherit_yuthon_property.py | 137 ++----------------
.../views/inherit_yuthon_property_views.xml | 21 ---
4 files changed, 14 insertions(+), 148 deletions(-)
diff --git a/yuthon_property/views/property_meter_archives_views.xml b/yuthon_property/views/property_meter_archives_views.xml
index bc8d3b4ef..0b1fb307d 100644
--- a/yuthon_property/views/property_meter_archives_views.xml
+++ b/yuthon_property/views/property_meter_archives_views.xml
@@ -95,7 +95,7 @@
meter.archives.line
+ js_class="custom_meter_button" decoration-success="is_push" default_order="meter_date_month desc">
diff --git a/yuthon_property/views/property_meter_water_views.xml b/yuthon_property/views/property_meter_water_views.xml
index e39046a47..83ec9add6 100644
--- a/yuthon_property/views/property_meter_water_views.xml
+++ b/yuthon_property/views/property_meter_water_views.xml
@@ -98,7 +98,7 @@
meter.water.line.tree
meter.water.line
-
diff --git a/yuthon_property_approval/models/inherit_yuthon_property.py b/yuthon_property_approval/models/inherit_yuthon_property.py
index d6690f950..36cfbbd7e 100644
--- a/yuthon_property_approval/models/inherit_yuthon_property.py
+++ b/yuthon_property_approval/models/inherit_yuthon_property.py
@@ -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)
diff --git a/yuthon_property_approval/views/inherit_yuthon_property_views.xml b/yuthon_property_approval/views/inherit_yuthon_property_views.xml
index e119c8238..60af20fb6 100644
--- a/yuthon_property_approval/views/inherit_yuthon_property_views.xml
+++ b/yuthon_property_approval/views/inherit_yuthon_property_views.xml
@@ -452,26 +452,12 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
应收账单
@@ -608,13 +594,6 @@
code
action = model.all_penalty_date()
-
- 批量撤销
-
-
- code
- action = model.batch_receivable_return()
-
批量退回
From 38f560b3e7529e967c546c2416c67bcb1130b277 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E6=9D=8E=E9=B9=8F=E5=AE=87?=
<9664676+pengyuthon@user.noreply.gitee.com>
Date: Tue, 16 Dec 2025 15:42:34 +0800
Subject: [PATCH 03/14] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E5=8A=9F=E8=83=BD?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
yuthon_base/__manifest__.py | 1 +
yuthon_base/models/__init__.py | 1 +
yuthon_base/models/yuthon_timed_tasks.py | 22 ++++++++++++++++
yuthon_base/security/ir.model.access.csv | 1 +
yuthon_base/views/menu.xml | 2 +-
.../views/yuthon_timed_tasks_views.xml | 25 +++++++++++++++++++
yuthon_notice/models/yuthon_notice.py | 2 +-
7 files changed, 52 insertions(+), 2 deletions(-)
create mode 100644 yuthon_base/models/yuthon_timed_tasks.py
create mode 100644 yuthon_base/views/yuthon_timed_tasks_views.xml
diff --git a/yuthon_base/__manifest__.py b/yuthon_base/__manifest__.py
index 3a8ecbd2b..bc4e3f528 100644
--- a/yuthon_base/__manifest__.py
+++ b/yuthon_base/__manifest__.py
@@ -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': {
diff --git a/yuthon_base/models/__init__.py b/yuthon_base/models/__init__.py
index 024efa1ca..38ec55d94 100644
--- a/yuthon_base/models/__init__.py
+++ b/yuthon_base/models/__init__.py
@@ -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
\ No newline at end of file
diff --git a/yuthon_base/models/yuthon_timed_tasks.py b/yuthon_base/models/yuthon_timed_tasks.py
new file mode 100644
index 000000000..cca454b40
--- /dev/null
+++ b/yuthon_base/models/yuthon_timed_tasks.py
@@ -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="模型")
\ No newline at end of file
diff --git a/yuthon_base/security/ir.model.access.csv b/yuthon_base/security/ir.model.access.csv
index 318f27c43..abc9f248e 100644
--- a/yuthon_base/security/ir.model.access.csv
+++ b/yuthon_base/security/ir.model.access.csv
@@ -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
diff --git a/yuthon_base/views/menu.xml b/yuthon_base/views/menu.xml
index 319fe26c6..318b263f8 100644
--- a/yuthon_base/views/menu.xml
+++ b/yuthon_base/views/menu.xml
@@ -12,7 +12,7 @@
+
+ 待办
+ ir.actions.act_window
+ soong.workflow.record
+ tree,kanban,search
+
+ {'header_search_default_approve_state': 1, 'header_search_default_to_do':1, 'check_employee': 1}
+ [('users_ids', 'in', uid), ('reclaim_state', '=', False), ('soong_state', '=', 'to_do')]
+
+
+
+
+ 已办
+ ir.actions.act_window
+ soong.workflow.record
+ tree,kanban,search
+ {'header_search_default_approve_state': 1, 'header_search_default_to_do':1, 'check_employee': 1}
+ [('users_ids', 'in', uid), ('reclaim_state', '=', False), ('soong_state', '=', 'done')]
+
+
+
人事相关流程
ir.actions.act_window
From eb9a4332b7f296b6d0664a015f4b54083e99c771 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E6=9D=8E=E9=B9=8F=E5=AE=87?=
<9664676+pengyuthon@user.noreply.gitee.com>
Date: Tue, 16 Dec 2025 18:34:22 +0800
Subject: [PATCH 08/14] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E5=8A=9F=E8=83=BD?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
yuthon_hr_attendance/data/attendance_time_data.xml | 14 ++++++++++++++
yuthon_hr_attendance/models/hr_attendance.py | 5 +++++
2 files changed, 19 insertions(+)
diff --git a/yuthon_hr_attendance/data/attendance_time_data.xml b/yuthon_hr_attendance/data/attendance_time_data.xml
index fff00f95d..2ed26133a 100644
--- a/yuthon_hr_attendance/data/attendance_time_data.xml
+++ b/yuthon_hr_attendance/data/attendance_time_data.xml
@@ -326,6 +326,20 @@
-1
+
+
+ 定时任务:测试提醒
+
+ code
+ model.task_remind()
+
+
+ 1
+ days
+
+ -1
+
+
diff --git a/yuthon_hr_attendance/models/hr_attendance.py b/yuthon_hr_attendance/models/hr_attendance.py
index bf7f1689b..95fd1a862 100644
--- a/yuthon_hr_attendance/models/hr_attendance.py
+++ b/yuthon_hr_attendance/models/hr_attendance.py
@@ -63,6 +63,11 @@ 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):
+ self.sudo().env["wecom.apps"].sync_send_message_textcard(
+ category='att', user_id=18562027762,
+ description="记得打卡", title="打卡提醒",btntxt="详细信息", )
+
def create_attendance_data_holiday(self):
"""
定时任务create_attendance_data_holiday
From 537ad98ae42b9dca73ca97bca44c2713980131ed Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E6=9D=8E=E9=B9=8F=E5=AE=87?=
<9664676+pengyuthon@user.noreply.gitee.com>
Date: Tue, 16 Dec 2025 21:01:39 +0800
Subject: [PATCH 09/14] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E5=8A=9F=E8=83=BD?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
yuthon_report/__manifest__.py | 5 +-
yuthon_report/models/__init__.py | 3 +-
yuthon_report/models/att_report.py | 73 +++++++
.../components/yuthon_report/att_report.js | 179 ++++++++++++++++++
.../components/yuthon_report/att_report.xml | 87 +++++++++
yuthon_report/views/att_report_view.xml | 32 ++++
6 files changed, 377 insertions(+), 2 deletions(-)
create mode 100644 yuthon_report/models/att_report.py
create mode 100644 yuthon_report/static/src/components/yuthon_report/att_report.js
create mode 100644 yuthon_report/static/src/components/yuthon_report/att_report.xml
create mode 100644 yuthon_report/views/att_report_view.xml
diff --git a/yuthon_report/__manifest__.py b/yuthon_report/__manifest__.py
index d800b8327..d6f9ccade 100644
--- a/yuthon_report/__manifest__.py
+++ b/yuthon_report/__manifest__.py
@@ -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',
diff --git a/yuthon_report/models/__init__.py b/yuthon_report/models/__init__.py
index 22476b2ab..431e39e45 100644
--- a/yuthon_report/models/__init__.py
+++ b/yuthon_report/models/__init__.py
@@ -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
\ No newline at end of file
+from . import overdue_amount_report
+from . import att_report
\ No newline at end of file
diff --git a/yuthon_report/models/att_report.py b/yuthon_report/models/att_report.py
new file mode 100644
index 000000000..9593c98d3
--- /dev/null
+++ b/yuthon_report/models/att_report.py
@@ -0,0 +1,73 @@
+import datetime
+
+from odoo import fields, models, api
+
+
+class AttendanceReport(models.Model):
+ _inherit = 'hr.attendance'
+
+ @api.model
+ def get_attendance_report(self, params):
+ domain = []
+ if params.get("date_start"):
+ date_start = datetime.datetime.fromisoformat(params.get("date_start")).date()
+ domain.append(("vacation_date", ">=", date_start))
+ if params.get("date_end"):
+ date_end = datetime.datetime.fromisoformat(params.get("date_end")).date()
+ 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))
+
+ if employee_domain:
+ employee_ids = self.env['hr.employee'].search(employee_domain).ids
+ if employee_ids:
+ domain.append(("employee_id", "in", employee_ids))
+ else:
+ return []
+
+ vacation_reports = self.env['yuthon.vacation.reports'].search(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_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
\ No newline at end of file
diff --git a/yuthon_report/static/src/components/yuthon_report/att_report.js b/yuthon_report/static/src/components/yuthon_report/att_report.js
new file mode 100644
index 000000000..8ecb33e5c
--- /dev/null
+++ b/yuthon_report/static/src/components/yuthon_report/att_report.js
@@ -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);
diff --git a/yuthon_report/static/src/components/yuthon_report/att_report.xml b/yuthon_report/static/src/components/yuthon_report/att_report.xml
new file mode 100644
index 000000000..dd94d93f1
--- /dev/null
+++ b/yuthon_report/static/src/components/yuthon_report/att_report.xml
@@ -0,0 +1,87 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/yuthon_report/views/att_report_view.xml b/yuthon_report/views/att_report_view.xml
new file mode 100644
index 000000000..1d6865c7c
--- /dev/null
+++ b/yuthon_report/views/att_report_view.xml
@@ -0,0 +1,32 @@
+
+
+
+
+ 请假扣款报表
+ att_report_client
+
+ {
+ "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},
+ ]
+ }
+ }
+
+
+
+
+
From 807626b728b3b2a07e3c60a9f2a68b93a1f24f42 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E6=9D=8E=E9=B9=8F=E5=AE=87?=
<9664676+pengyuthon@user.noreply.gitee.com>
Date: Wed, 17 Dec 2025 09:32:02 +0800
Subject: [PATCH 10/14] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E5=8A=9F=E8=83=BD?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
yuthon_will_task/models/yuthon_will_task.py | 6 +++---
yuthon_will_task/views/yuthon_will_task_views.xml | 5 -----
2 files changed, 3 insertions(+), 8 deletions(-)
diff --git a/yuthon_will_task/models/yuthon_will_task.py b/yuthon_will_task/models/yuthon_will_task.py
index 981ecb238..2d52a9b68 100644
--- a/yuthon_will_task/models/yuthon_will_task.py
+++ b/yuthon_will_task/models/yuthon_will_task.py
@@ -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 = ""
diff --git a/yuthon_will_task/views/yuthon_will_task_views.xml b/yuthon_will_task/views/yuthon_will_task_views.xml
index 1b11a4d06..047654fd8 100644
--- a/yuthon_will_task/views/yuthon_will_task_views.xml
+++ b/yuthon_will_task/views/yuthon_will_task_views.xml
@@ -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'">
@@ -49,7 +48,6 @@