From 74d71adaa898501b7239e026a051375b705d6228 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=B9=8F=E5=AE=87?= Date: Mon, 2 Mar 2026 21:21:14 +0800 Subject: [PATCH 1/6] =?UTF-8?q?=E7=A8=8E=E7=8E=87?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- yuthon_report/models/current_receivable_property_fee_report.py | 2 +- yuthon_report/models/current_receivable_rent_report.py | 2 +- yuthon_report/models/receivable_report.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/yuthon_report/models/current_receivable_property_fee_report.py b/yuthon_report/models/current_receivable_property_fee_report.py index 6dbe31589..c34dbd582 100644 --- a/yuthon_report/models/current_receivable_property_fee_report.py +++ b/yuthon_report/models/current_receivable_property_fee_report.py @@ -79,7 +79,7 @@ class CurrentReceivablePropertyFeeReport(models.Model): for idx, rec in enumerate(receivables, start=1): amt = rec.original_amount or 0.0 # 从合同获取税率 - tax_rate = float(rec.contract_id.tax_rate.name) * 100 if rec.contract_id and rec.contract_id.tax_rate else 0.0 + tax_rate = float(rec.contract_id.tax_rate.name.replace('%', '')) if rec.contract_id and rec.contract_id.tax_rate else 0.0 amt_nt = amt / (1 + tax_rate / 100) if tax_rate else amt total_amount += amt total_amount_nt += amt_nt diff --git a/yuthon_report/models/current_receivable_rent_report.py b/yuthon_report/models/current_receivable_rent_report.py index 71b6d2ff0..85198c1e1 100644 --- a/yuthon_report/models/current_receivable_rent_report.py +++ b/yuthon_report/models/current_receivable_rent_report.py @@ -64,7 +64,7 @@ class CurrentReceivableRentReport(models.Model): # 实际应收 = 原始金额 - 减免金额 actual_amt = amt - discount # 从合同获取税率 - tax_rate = float(rec.contract_id.tax_rate.name) * 100 if rec.contract_id and rec.contract_id.tax_rate else 0.0 + tax_rate = float(rec.contract_id.tax_rate.name.replace('%', '')) if rec.contract_id and rec.contract_id.tax_rate else 0.0 actual_amt_nt = actual_amt / (1 + tax_rate / 100) if tax_rate else actual_amt # 统计每个管理类型的合计 diff --git a/yuthon_report/models/receivable_report.py b/yuthon_report/models/receivable_report.py index b8792c727..58f864eb9 100644 --- a/yuthon_report/models/receivable_report.py +++ b/yuthon_report/models/receivable_report.py @@ -78,7 +78,7 @@ class YuthonProperty(models.Model): 'display_name': rec.contract_id.contract_code, } if rec.contract_id else "", "发票类型": invoice_type_map.get(rec.invoice_type, ""), - "税率": f"{float(rec.contract_id.tax_rate.name) * 100:.1f}%" if rec.contract_id and rec.contract_id.tax_rate else "0.0%" + "税率": f"{float(rec.contract_id.tax_rate.name.replace('%', '')):.1f}%" if rec.contract_id and rec.contract_id.tax_rate else "0.0%" }) summary_stats = [] From 6148d9ee4ac77d3cb9d4ec95d3aa790ef50dbcb0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=B9=8F=E5=AE=87?= Date: Mon, 2 Mar 2026 21:33:31 +0800 Subject: [PATCH 2/6] =?UTF-8?q?=E7=A8=8E=E7=8E=87?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../models/current_receivable_property_fee_report.py | 6 +++++- yuthon_report/models/current_receivable_rent_report.py | 6 +++++- yuthon_report/models/receivable_report.py | 10 +++++++++- 3 files changed, 19 insertions(+), 3 deletions(-) diff --git a/yuthon_report/models/current_receivable_property_fee_report.py b/yuthon_report/models/current_receivable_property_fee_report.py index c34dbd582..adebda322 100644 --- a/yuthon_report/models/current_receivable_property_fee_report.py +++ b/yuthon_report/models/current_receivable_property_fee_report.py @@ -79,7 +79,11 @@ class CurrentReceivablePropertyFeeReport(models.Model): for idx, rec in enumerate(receivables, start=1): amt = rec.original_amount or 0.0 # 从合同获取税率 - tax_rate = float(rec.contract_id.tax_rate.name.replace('%', '')) if rec.contract_id and rec.contract_id.tax_rate else 0.0 + try: + tax_rate_str = str(rec.contract_id.tax_rate.name) if rec.contract_id and rec.contract_id.tax_rate else "0" + tax_rate = float(tax_rate_str.replace('%', '').strip()) if tax_rate_str else 0.0 + except (ValueError, TypeError): + tax_rate = 0.0 amt_nt = amt / (1 + tax_rate / 100) if tax_rate else amt total_amount += amt total_amount_nt += amt_nt diff --git a/yuthon_report/models/current_receivable_rent_report.py b/yuthon_report/models/current_receivable_rent_report.py index 85198c1e1..ea94a6661 100644 --- a/yuthon_report/models/current_receivable_rent_report.py +++ b/yuthon_report/models/current_receivable_rent_report.py @@ -64,7 +64,11 @@ class CurrentReceivableRentReport(models.Model): # 实际应收 = 原始金额 - 减免金额 actual_amt = amt - discount # 从合同获取税率 - tax_rate = float(rec.contract_id.tax_rate.name.replace('%', '')) if rec.contract_id and rec.contract_id.tax_rate else 0.0 + try: + tax_rate_str = str(rec.contract_id.tax_rate.name) if rec.contract_id and rec.contract_id.tax_rate else "0" + tax_rate = float(tax_rate_str.replace('%', '').strip()) if tax_rate_str else 0.0 + except (ValueError, TypeError): + tax_rate = 0.0 actual_amt_nt = actual_amt / (1 + tax_rate / 100) if tax_rate else actual_amt # 统计每个管理类型的合计 diff --git a/yuthon_report/models/receivable_report.py b/yuthon_report/models/receivable_report.py index 58f864eb9..cc3a63332 100644 --- a/yuthon_report/models/receivable_report.py +++ b/yuthon_report/models/receivable_report.py @@ -78,7 +78,15 @@ class YuthonProperty(models.Model): 'display_name': rec.contract_id.contract_code, } if rec.contract_id else "", "发票类型": invoice_type_map.get(rec.invoice_type, ""), - "税率": f"{float(rec.contract_id.tax_rate.name.replace('%', '')):.1f}%" if rec.contract_id and rec.contract_id.tax_rate else "0.0%" + "税率": ( + lambda tr: ( + lambda v: f"{v:.1f}%" if v is not None else "0.0%" + )( + float(str(tr).replace('%', '').strip()) + if tr and str(tr).replace('%', '').strip() + else None + ) + )(rec.contract_id.tax_rate.name if rec.contract_id and rec.contract_id.tax_rate else None) }) summary_stats = [] From 0b40b75a1b42fcfe31e6f1a1e065e5be8193da97 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=B9=8F=E5=AE=87?= Date: Mon, 2 Mar 2026 21:44:02 +0800 Subject: [PATCH 3/6] =?UTF-8?q?=E4=BD=8D=E7=BD=AE=E8=B0=83=E6=95=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- yuthon_report/models/receivable_report.py | 10 +++++----- yuthon_report/views/receivable_report_views.xml | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/yuthon_report/models/receivable_report.py b/yuthon_report/models/receivable_report.py index cc3a63332..bd2fe5729 100644 --- a/yuthon_report/models/receivable_report.py +++ b/yuthon_report/models/receivable_report.py @@ -65,6 +65,11 @@ class YuthonProperty(models.Model): "应收开始": rec.due_date.strftime("%Y-%m-%d") if rec.due_date else "", "应收结束": rec.due_date_end.strftime("%Y-%m-%d") if rec.due_date_end else "", "当期金额": round(amount, 2), + "合同编号": { + 'model': 'property.lease.contract', + 'id': rec.contract_id.id, + 'display_name': rec.contract_id.contract_code, + } if rec.contract_id else "", "承租方": { 'model': 'property.tenant.information', 'id': rec.lessee_id.id, @@ -72,11 +77,6 @@ class YuthonProperty(models.Model): } if rec.lessee_id else "", "物业名称": rec.property_name or "", "产权证号": rec.title_deed or "", - "合同编号": { - 'model': 'property.lease.contract', - 'id': rec.contract_id.id, - 'display_name': rec.contract_id.contract_code, - } if rec.contract_id else "", "发票类型": invoice_type_map.get(rec.invoice_type, ""), "税率": ( lambda tr: ( diff --git a/yuthon_report/views/receivable_report_views.xml b/yuthon_report/views/receivable_report_views.xml index 55f2fe90b..132782f32 100644 --- a/yuthon_report/views/receivable_report_views.xml +++ b/yuthon_report/views/receivable_report_views.xml @@ -15,10 +15,10 @@ {"headerName": "应收开始", "field": "应收开始", "flex": 1}, {"headerName": "应收结束", "field": "应收结束", "flex": 1}, {"headerName": "当期金额", "field": "当期金额", "flex": 1, "type": "number"}, + {"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} ] From 929641e6a1786c8abf1f100558493c175d8b90f8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=B9=8F=E5=AE=87?= Date: Mon, 2 Mar 2026 22:14:23 +0800 Subject: [PATCH 4/6] =?UTF-8?q?=E5=8F=91=E7=A5=A8=E7=B1=BB=E5=9E=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- yuthon_report/models/receivable_report.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/yuthon_report/models/receivable_report.py b/yuthon_report/models/receivable_report.py index bd2fe5729..c23970f27 100644 --- a/yuthon_report/models/receivable_report.py +++ b/yuthon_report/models/receivable_report.py @@ -77,7 +77,7 @@ class YuthonProperty(models.Model): } if rec.lessee_id else "", "物业名称": rec.property_name or "", "产权证号": rec.title_deed or "", - "发票类型": invoice_type_map.get(rec.invoice_type, ""), + "发票类型": rec.lessee_id.invoicing_ids[0].invoicing_type_id.name if rec.lessee_id and rec.lessee_id.invoicing_ids else "", "税率": ( lambda tr: ( lambda v: f"{v:.1f}%" if v is not None else "0.0%" From b1b00dd5ec80c439719e705cd3ac2a330c7e2f72 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: Mon, 2 Mar 2026 22:55:01 +0800 Subject: [PATCH 5/6] =?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 --- .../models/yuthon_vacation_reports.py | 2 +- .../wizard/yuthon_vacation_import_wizard.py | 108 +++++++++++++++--- .../yuthon_vacation_import_wizard_views.xml | 1 + 3 files changed, 95 insertions(+), 16 deletions(-) diff --git a/yuthon_hr_attendance/models/yuthon_vacation_reports.py b/yuthon_hr_attendance/models/yuthon_vacation_reports.py index 330628ccc..524f69bb3 100644 --- a/yuthon_hr_attendance/models/yuthon_vacation_reports.py +++ b/yuthon_hr_attendance/models/yuthon_vacation_reports.py @@ -202,7 +202,7 @@ class YuthonVacationReports(models.Model): rec.update_line() def update_line(self): - if self.vacation_date == fields.Date.from_string('2026-01-01'): + if self.vacation_date == fields.Date.from_string('2026-01-01') or (self.vacation_date == fields.Date.from_string('2026-03-01') and self.employee_id.name == '天河物管'): return self.manage_reject() # ========== 第一步:处理年假逻辑 ========== diff --git a/yuthon_hr_attendance/wizard/yuthon_vacation_import_wizard.py b/yuthon_hr_attendance/wizard/yuthon_vacation_import_wizard.py index 71aaaf89a..c871244fe 100644 --- a/yuthon_hr_attendance/wizard/yuthon_vacation_import_wizard.py +++ b/yuthon_hr_attendance/wizard/yuthon_vacation_import_wizard.py @@ -14,6 +14,7 @@ class YuthonVacationImportWizard(models.TransientModel): excel_file = fields.Binary(string="上传Excel表") excel_name = fields.Char(string="文件名") + company_id = fields.Many2one('res.company', string='公司') def confirm(self): """ @@ -24,14 +25,18 @@ class YuthonVacationImportWizard(models.TransientModel): raise ValidationError('请上传文件。') book = xlrd.open_workbook(file_contents=base64.decodebytes(self.excel_file)) sh = book.sheet_by_index(0) - for rx in range(1, sh.nrows): - row = sh.row(rx) - self.leave_import(row) + if self.company_id.name in ['集团本部', '天河粮储']: + for rx in range(1, sh.nrows): + row = sh.row(rx) + self.leave_import(row) + else: + for rx in range(1, sh.nrows): + row = sh.row(rx) + self.leave_import1(row) def leave_import(self, row): employee_id = self.env['hr.employee'].search([('name', '=', row[0].value)], limit=1) if not employee_id: - self.env.user.notify_warning(f"员工 {row[0].value} 不存在,跳过处理") return date = datetime(2026, 1, 1) @@ -39,24 +44,97 @@ class YuthonVacationImportWizard(models.TransientModel): [('employee_id', '=', employee_id.id), ('vacation_date', '=', date)], limit=1 ) + if vacation_id: - target_leaves = vacation_id.leave_ids.filtered(lambda l: l.text == '上月额度继承') - for leave in target_leaves: - update_value = int(row[1].value) * 8 - if update_value == 0: - leave.unlink() - else: - leave.write({'update_lines': update_value}) + if employee_id.company_id.name == '天河粮储': + target_leaves = vacation_id.leave_ids.filtered(lambda l: l.text == '年假分配') + for leave in target_leaves: + update_value = float(row[1].value) * 8 + if update_value == 0: + leave.unlink() + else: + leave.write({'update_lines': update_value}) + target_leaves1 = vacation_id.leave_ids.filtered(lambda l: l.text == '上月额度继承') + for leave in target_leaves1: + update_value = float(row[2].value) * 8 + if update_value == 0: + leave.unlink() + else: + leave.write({'update_lines': update_value}) + target_overtimes = vacation_id.overtime_ids.filtered(lambda o: o.text == '上月额度继承') for overtime in target_overtimes: - workday_value = int(row[2].value) * 8 - if workday_value == 0: + if employee_id.company_id.name == '集团本部': + workday_value = float(row[3].value) + public_holidays = float(row[4].value) + else: + workday_value = float(row[3].value) * 8 + public_holidays = float(row[4].value) * 8 + if workday_value == 0 and public_holidays == 0: overtime.unlink() else: - overtime.write({'workday': workday_value}) + overtime.write({'workday': workday_value, + 'public_holidays': public_holidays}) vacation_id.update_vacation1() + vacation_id._compute_leave() + vacation_id._compute_working_overtime() + def leave_import1(self, row): + employee_id = self.env['hr.employee'].search([('name', '=', row[0].value)], limit=1) + if not employee_id: + self.env.user.notify_warning(f"员工 {row[0].value} 不存在,跳过处理") + return + date = datetime(2026, 3, 1) + vacation_id = self.env['yuthon.vacation.reports'].search( + [('employee_id', '=', employee_id.id), ('vacation_date', '=', date)], + limit=1 + ) + if vacation_id: + target_leaves = vacation_id.leave_ids.filtered(lambda l: l.text == '上月额度继承') + update_value = float(row[1].value) * 8 + if target_leaves: + for leave in target_leaves: + if update_value == 0: + leave.unlink() + else: + leave.write({ + 'update_lines': update_value, + }) + vacation_id.dynamic_previous_year = update_value / 8 + else: + if update_value != 0: + self.env[vacation_id.leave_ids._name].create({ + 'text': '上月额度继承', + 'update_type': 'add', + 'update_date': date, + 'valid_date': datetime(2027, 2, 28), + 'update_lines': update_value, + 'vacation_id': vacation_id.id, + }) + vacation_id.dynamic_previous_year = update_value / 8 - + target_overtimes = vacation_id.overtime_ids.filtered(lambda o: o.text == '上月额度继承') + workday_value = float(row[2].value) * 8 + if target_overtimes: + for overtime in target_overtimes: + if workday_value == 0: + overtime.unlink() + else: + overtime.write({'workday': workday_value}) + vacation_id.dynamic_previous_year1 = workday_value / 8 + else: + if workday_value != 0: + self.env[vacation_id.overtime_ids._name].create({ + 'text': '上月额度继承', + 'update_type': 'add', + 'update_date': date, + 'overtime_methods': 'leave', + 'valid_date': datetime(2027, 2, 28), + 'workday': workday_value, + 'vacation_id': vacation_id.id, + }) + vacation_id.dynamic_previous_year1 = workday_value / 8 + vacation_id._compute_leave() + vacation_id._compute_working_overtime() diff --git a/yuthon_hr_attendance/wizard/yuthon_vacation_import_wizard_views.xml b/yuthon_hr_attendance/wizard/yuthon_vacation_import_wizard_views.xml index 9cfcd3eba..f4bd990c1 100644 --- a/yuthon_hr_attendance/wizard/yuthon_vacation_import_wizard_views.xml +++ b/yuthon_hr_attendance/wizard/yuthon_vacation_import_wizard_views.xml @@ -8,6 +8,7 @@ + From 6e2dfeed4b1532e593e6c635193b07ccf94a229e 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: Mon, 2 Mar 2026 23:01:26 +0800 Subject: [PATCH 6/6] =?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/wizard/yuthon_vacation_import_wizard.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/yuthon_hr_attendance/wizard/yuthon_vacation_import_wizard.py b/yuthon_hr_attendance/wizard/yuthon_vacation_import_wizard.py index c871244fe..fe0681f6e 100644 --- a/yuthon_hr_attendance/wizard/yuthon_vacation_import_wizard.py +++ b/yuthon_hr_attendance/wizard/yuthon_vacation_import_wizard.py @@ -70,7 +70,7 @@ class YuthonVacationImportWizard(models.TransientModel): public_holidays = float(row[4].value) else: workday_value = float(row[3].value) * 8 - public_holidays = float(row[4].value) * 8 + public_holidays = 0 if workday_value == 0 and public_holidays == 0: overtime.unlink() else: