diff --git a/yuthon_holiday/__manifest__.py b/yuthon_holiday/__manifest__.py
index f1968c02a..5f3092d54 100644
--- a/yuthon_holiday/__manifest__.py
+++ b/yuthon_holiday/__manifest__.py
@@ -14,6 +14,7 @@
'report/hr_leave_batch_report_action.xml',
'views/inherit_hr_type_views.xml',
'views/inherit_hr_leave_allocation_views.xml',
+ 'views/extended_vacation_approval_views.xml',
'views/inherit_hr_leave_accrual_plan_views.xml',
'views/hr_leave_accrual_views.xml',
'views/yuthon_fixes_approval_views.xml',
diff --git a/yuthon_holiday/data/yuthon_holiday_data.xml b/yuthon_holiday/data/yuthon_holiday_data.xml
index e40998543..7b607a966 100644
--- a/yuthon_holiday/data/yuthon_holiday_data.xml
+++ b/yuthon_holiday/data/yuthon_holiday_data.xml
@@ -14,6 +14,13 @@
4
+
+ 修正编号
+ yuthon_extended_code
+ JQYC
+ 4
+
+
哺乳编号
yuthon_breastfeed_leave_code
diff --git a/yuthon_holiday/models/__init__.py b/yuthon_holiday/models/__init__.py
index 1bd3fb868..5bd4cf43d 100644
--- a/yuthon_holiday/models/__init__.py
+++ b/yuthon_holiday/models/__init__.py
@@ -4,4 +4,5 @@ from . import inherit_hr_leave
from . import inherit_hr_leave_accrual_plan
from . import yuthon_fixes_approval
from . import yuthon_holiday_setting
-from . import yuthon_breastfeed_leave
\ No newline at end of file
+from . import yuthon_breastfeed_leave
+from . import extended_vacation_approval
\ No newline at end of file
diff --git a/yuthon_holiday/models/extended_vacation_approval.py b/yuthon_holiday/models/extended_vacation_approval.py
new file mode 100644
index 000000000..09952f3de
--- /dev/null
+++ b/yuthon_holiday/models/extended_vacation_approval.py
@@ -0,0 +1,90 @@
+# -*- coding: utf-8 -*-
+from email.policy import default
+
+from odoo import models, fields, api
+
+
+class ExtendedVacationApproval(models.Model):
+ _name = 'extended.vacation.approval'
+ _description = '假期延长申请'
+ _inherit = ['soong.workflow.mixin', 'mail.thread.main.attachment', 'mail.activity.mixin']
+
+ name = fields.Char(string="标题")
+ code = fields.Char(string="编号", default=lambda self: self.env['ir.sequence'].next_by_code('yuthon_extended_code'))
+ users_id = fields.Many2one('res.users', string="申请人", default=lambda self: self.env.user.id)
+ department_id = fields.Many2one(related='users_id.employee_id.department_id', string="部门")
+ employee_ids = fields.Many2many('hr.employee', string="假期顺延人员")
+ type_vacations_ids = fields.Many2many('hr.leave.type', string="假期类型")
+ is_issues = fields.Boolean(string='是否上会')
+ issues_result = fields.Html(string="会议结果")
+ related_issues_id = fields.Many2one('issue.library', string="关联议题")
+ reason_application = fields.Text(string="申请事由")
+ documents_ids = fields.Many2many('ir.attachment', string="附件")
+ date_postponed = fields.Date(string="延期至")
+ active = fields.Boolean('Active', default=True, tracking=True)
+ remarks = fields.Text(string="备注")
+ work_end = fields.Boolean(string="结束")
+ urgency_level = fields.Selection([('normal', '普件'), ('urgent', '急件'), ('emergency', '特急件')], string='紧急度',
+ default='normal')
+ line_ids = fields.One2many('extended.vacation.line', 'vacation_id', string="延期假期")
+
+ def _get_default_name_title(self):
+ return self._description if self._description else self._name
+ name_title = fields.Char(default=_get_default_name_title)
+ self_users_ids = fields.Many2many('res.users', string="当前经办人", default=lambda self: [(6, 0, [self.env.user.id])])
+
+ @api.onchange('employee_ids')
+ def _onchange_employee_ids(self):
+ if not self.employee_ids:
+ self.line_ids = [(5, 0, 0)]
+ return
+ current_date = fields.Date.today()
+ target_date = fields.Date.to_date(f"{current_date.year}-{current_date.month}-01")
+ self.line_ids = [(5, 0, 0)]
+ line_values = []
+ for employee in self.employee_ids:
+ report_record = self.env['yuthon.vacation.reports'].search([
+ ('employee_id', '=', employee.id.origin),
+ ('vacation_date', '=', target_date)
+ ], limit=1)
+ line_data = {
+ 'employee_id': employee.id,
+ 'dynamic_previous_year': report_record.dynamic_previous_year if report_record else 0.0,
+ 'dynamic_previous_year1': report_record.dynamic_previous_year1 if report_record else 0.0,
+ }
+ line_values.append((0, 0, line_data))
+ self.line_ids = line_values
+
+ def end_approval(self):
+ current_date = fields.Date.today()
+ start_date = fields.Date.to_date(f"{current_date.year}-01-01")
+ end_date = fields.Date.to_date(f"{current_date.year}-{current_date.month}-01")
+ if self.employee_ids:
+ has_annual_leave = self.type_vacations_ids.filtered(lambda r: r.name == '年假')
+ has_overtime_leave = self.type_vacations_ids.filtered(lambda r: r.name == '补休')
+ for employee in self.employee_ids:
+ report_records = self.env['yuthon.vacation.reports'].search([
+ ('employee_id', '=', employee.id),
+ ('vacation_date', '>=', start_date),
+ ('vacation_date', '<=', end_date)
+ ])
+ if report_records:
+ write_vals = {}
+ if has_annual_leave:
+ write_vals['valid_date'] = self.date_postponed
+ if has_overtime_leave:
+ write_vals['valid_date1'] = self.date_postponed
+
+ if write_vals:
+ report_records.write(write_vals)
+ for record in report_records:
+ record.update_line()
+
+class ExtendedVacationLine(models.Model):
+ _name = 'extended.vacation.line'
+ _description = "假期延长明细"
+
+ vacation_id = fields.Many2one('extended.vacation.approval', string="假期延长")
+ employee_id = fields.Many2one('hr.employee', string="姓名")
+ dynamic_previous_year = fields.Float(string="上年年假剩余d", digits=(16, 3))
+ dynamic_previous_year1 = fields.Float(string="上年补休剩余d", digits=(16, 3))
\ No newline at end of file
diff --git a/yuthon_holiday/security/ir.model.access.csv b/yuthon_holiday/security/ir.model.access.csv
index 29aef657e..70ee2a65b 100644
--- a/yuthon_holiday/security/ir.model.access.csv
+++ b/yuthon_holiday/security/ir.model.access.csv
@@ -6,4 +6,6 @@ access_yuthon_fixes_wizard,yuthon_fixes_wizard,model_yuthon_fixes_wizard,base.gr
access_yuthon_holiday_setting,yuthon_holiday_setting,model_yuthon_holiday_setting,base.group_user,1,1,1,1
access_leave_allocation_wizard,leave_allocation_wizard,model_leave_allocation_wizard,base.group_user,1,1,1,1
access_yuthon_leave_wizard,yuthon_leave_wizard,model_yuthon_leave_wizard,base.group_user,1,1,1,1
-access_yuthon_breastfeed_leave,yuthon_breastfeed_leave,model_yuthon_breastfeed_leave,base.group_user,1,1,1,1
\ No newline at end of file
+access_yuthon_breastfeed_leave,yuthon_breastfeed_leave,model_yuthon_breastfeed_leave,base.group_user,1,1,1,1
+access_extended_vacation_approval,extended_vacation_approval,model_extended_vacation_approval,base.group_user,1,1,1,1
+access_extended_vacation_line,extended_vacation_line,model_extended_vacation_line,base.group_user,1,1,1,1
\ No newline at end of file
diff --git a/yuthon_holiday/views/extended_vacation_approval_views.xml b/yuthon_holiday/views/extended_vacation_approval_views.xml
new file mode 100644
index 000000000..7e01fc5e8
--- /dev/null
+++ b/yuthon_holiday/views/extended_vacation_approval_views.xml
@@ -0,0 +1,77 @@
+
+
+
+ extended.vacation.approval.tree
+ extended.vacation.approval
+
+
+
+
+
+
+
+
+ extended.vacation.approval.form
+ extended.vacation.approval
+
+
+
+
+
+
+
+
+
+
diff --git a/yuthon_hr_attendance/models/yuthon_vacation_reports.py b/yuthon_hr_attendance/models/yuthon_vacation_reports.py
index 8ad5bb1b8..2a041e9d9 100644
--- a/yuthon_hr_attendance/models/yuthon_vacation_reports.py
+++ b/yuthon_hr_attendance/models/yuthon_vacation_reports.py
@@ -377,17 +377,33 @@ class YuthonVacationReports(models.Model):
rec.year_workday += workday_overtime_add
rec.year_holiday += holidays_overtime_add
- if rec.working_overtime > 0:
+ current_month_first = rec.vacation_date.replace(day=1)
+ last_month_last = current_month_first - timedelta(days=1)
+ last_month_first = last_month_last.replace(day=1)
+ last_month_record = self.env['yuthon.vacation.reports'].search([
+ ('employee_id', '=', rec.employee_id.id),
+ ('vacation_date', '=', last_month_first),
+ ], limit=1)
+ if last_month_record:
+ total_overtime = last_month_record.dynamic_previous_year1 + last_month_record.this_year1
+ else:
+ total_overtime = 0.0
+
+ if total_overtime > 0:
working_overtime_lines = rec.overtime_ids.filtered(
lambda o: not o.workflow_record_id and o.text == '上月额度继承'
)
- working_overtime_lines.workday = rec.working_overtime * 8
+ working_overtime_lines.workday = total_overtime * 8
+ if last_month_record:
+ total_leave = last_month_record.dynamic_previous_year + last_month_record.dynamic_remainder_year
+ else:
+ total_leave = 0.0
- if rec.leave > 0:
+ if total_leave > 0:
leave_lines = rec.leave_ids.filtered(
lambda o: not o.workflow_record_id and o.text == '上月额度继承'
)
- leave_lines.update_lines = rec.leave * 8
+ leave_lines.update_lines = total_leave * 8
rec._compute_leave()
rec._compute_working_overtime()
@@ -1365,12 +1381,21 @@ class YuthonVacationReports(models.Model):
}
rec.write(inherit_vals)
+ current_date = fields.Date.today()
if last_month_record:
+ if last_month_record.valid_date and last_month_record.valid_date < current_date:
+ dynamic_previous_year_val = 0.0
+ else:
+ dynamic_previous_year_val = last_month_record.dynamic_previous_year
+ if last_month_record.valid_date1 and last_month_record.valid_date1 < current_date:
+ dynamic_previous_year1_val = 0.0
+ else:
+ dynamic_previous_year1_val = last_month_record.dynamic_previous_year1
inherit_vals = {
'leave': last_month_record.leave,
- 'dynamic_previous_year': last_month_record.dynamic_previous_year,
+ 'dynamic_previous_year': dynamic_previous_year_val,
'dynamic_remainder_year': last_month_record.dynamic_remainder_year,
- 'dynamic_previous_year1': last_month_record.dynamic_previous_year1,
+ 'dynamic_previous_year1': dynamic_previous_year1_val,
'this_year1': last_month_record.this_year1,
'working_overtime': last_month_record.working_overtime,
'medical_fee': last_month_record.medical_fee,
diff --git a/yuthon_property/models/property_bank_statements.py b/yuthon_property/models/property_bank_statements.py
index 4412ab636..e4c5c2a1e 100644
--- a/yuthon_property/models/property_bank_statements.py
+++ b/yuthon_property/models/property_bank_statements.py
@@ -195,11 +195,14 @@ class ReceivableModifyLine(models.Model):
bank_id = fields.Many2one('property.bank.statements', string='关联银行对账单')
original_amount = fields.Float(related='bank_id.original_amount', string='交易金额', store=False)
+ 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='应收账单')
management_type_id = fields.Many2one('yuthon.management.type', related='receivable_id.management_type_id', string='应收类型', store=False)
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)
property_name = fields.Text(string='物业', compute='_compute_property_name', store=False, search='_search_property_name')
+ delivered1 = fields.Float(related='receivable_id.delivered1', string='已收金额', store=False)
is_write = fields.Boolean()
@api.depends('receivable_id')
@@ -225,6 +228,32 @@ class ReceivableModifyLine(models.Model):
not_collected = fields.Float(string='未收')
amount = fields.Float(string='已对金额')
+ def open_receivable(self):
+ """打开应收账单"""
+ self.ensure_one()
+ if self.receivable_id:
+ return {
+ 'type': 'ir.actions.act_window',
+ 'name': '应收账单',
+ 'res_model': 'property.accounts.receivable',
+ 'res_id': self.receivable_id.id,
+ 'view_mode': 'form',
+ 'target': 'current',
+ }
+
+ def open_bank_statement(self):
+ """打开银行流水"""
+ self.ensure_one()
+ if self.bank_id:
+ return {
+ 'type': 'ir.actions.act_window',
+ 'name': '银行流水',
+ 'res_model': 'property.bank.statements',
+ 'res_id': self.bank_id.id,
+ 'view_mode': 'form',
+ 'target': 'current',
+ }
+
diff --git a/yuthon_property/views/property_bank_statements_views.xml b/yuthon_property/views/property_bank_statements_views.xml
index 0aefe7b6c..70848a5e4 100644
--- a/yuthon_property/views/property_bank_statements_views.xml
+++ b/yuthon_property/views/property_bank_statements_views.xml
@@ -116,16 +116,21 @@
+
+
+
+
+
diff --git a/yuthon_property/views/property_meter_archives_views.xml b/yuthon_property/views/property_meter_archives_views.xml
index 8ee5e10fc..439d1c13b 100644
--- a/yuthon_property/views/property_meter_archives_views.xml
+++ b/yuthon_property/views/property_meter_archives_views.xml
@@ -66,7 +66,7 @@
-
+
@@ -110,7 +110,7 @@
-
+
diff --git a/yuthon_property/views/property_meter_water_views.xml b/yuthon_property/views/property_meter_water_views.xml
index c440d48e2..0df132a2d 100644
--- a/yuthon_property/views/property_meter_water_views.xml
+++ b/yuthon_property/views/property_meter_water_views.xml
@@ -66,7 +66,7 @@
domain="[('type', '=', 'watermeter')]" options="{'no_create': True, 'no_open': True}"/>
-
+
@@ -112,7 +112,7 @@
-
+
diff --git a/yuthon_property/wizard/property_statements_wizard.py b/yuthon_property/wizard/property_statements_wizard.py
index 7c369f47b..41f69f7d2 100644
--- a/yuthon_property/wizard/property_statements_wizard.py
+++ b/yuthon_property/wizard/property_statements_wizard.py
@@ -11,7 +11,7 @@ class PropertyStatementsWizard(models.Model):
_name = 'property.statements.wizard'
_description = '银行流水向导弹窗'
- selection_bank = fields.Selection([('js', '建设银行'), ('gs', '工商银行'),('sh', '农商')], string="选择银行")
+ selection_bank = fields.Selection([('js', '建设银行'), ('gs', '工商银行'),('sh', '农商'), ('ms', '民生'), ('zc', '中城'), ('dj', '东进')], string="选择银行")
excel_file = fields.Binary(string="上传Excel表")
excel_name = fields.Char(string="文件名")
@@ -31,6 +31,12 @@ class PropertyStatementsWizard(models.Model):
self.property_bank_statements_gc_data(row)
elif self.selection_bank == 'sh':
self.property_bank_statements_sh_data(row)
+ elif self.selection_bank == 'ms':
+ self.property_bank_statements_ms_data(row)
+ elif self.selection_bank == 'zc':
+ self.property_bank_statements_zc_data(row)
+ elif self.selection_bank == 'dj':
+ self.property_bank_statements_dj_data(row)
def property_bank_statements_gc_data(self, row):
if row[0].value:
@@ -171,6 +177,31 @@ class PropertyStatementsWizard(models.Model):
elif original_amount:
self.env['property.bank.statements'].create(bank_data)
+ def property_bank_statements_ms_data(self, row):
+ if row[2].value:
+ start_time = datetime.strptime(row[2].value, '%Y-%m-%d %H:%M:%S')
+ else:
+ start_time = None
+ name = row[1].value
+ number = row[0].value
+ if row[3].value == "贷":
+ lending_direction = "loan"
+ elif row[3].value == "借":
+ lending_direction = "borrow"
+ name_account = row[4].value
+ bank_number = row[5].value
+ purpose = row[6].value
+ extract = row[7].value
+ remake = row[8].value
+ company_id = self.env['res.company'].search([('name', '=', '天河物管')], limit=1)
+ pass
+
+ def property_bank_statements_zc_data(self, row):
+ pass
+
+ def property_bank_statements_dj_data(self, row):
+ pass
+
def classify_by_last_four(self, input_str):
if not isinstance(input_str, str) or len(input_str) < 4:
diff --git a/yuthon_property_approval/models/inherit_yuthon_property.py b/yuthon_property_approval/models/inherit_yuthon_property.py
index e2f2d09af..df83f5686 100644
--- a/yuthon_property_approval/models/inherit_yuthon_property.py
+++ b/yuthon_property_approval/models/inherit_yuthon_property.py
@@ -201,6 +201,7 @@ class PropertyBankStatements(models.Model):
@api.depends('name')
def _compute_property_employee_id(self):
for record in self:
+ # 1. 原有逻辑:根据银行名称匹配承租方
if record.name:
bank_account = self.env['property.bank.line'].search([
('bank', '=', record.name)
@@ -209,20 +210,38 @@ class PropertyBankStatements(models.Model):
record.lessee_ids = [(6, 0, bank_list)] if bank_list else [(6, 0, [])]
else:
record.lessee_ids = [(6, 0, [])]
+
+ # 2. 重构核心逻辑:按日期筛选出租方变更行,匹配所属单元
if record.lessee_ids:
contract_set = self.env['property.lease.contract']
+ # 获取当前记录的日期(用于判断出租方变更行的生效期)
+ target_date = record.start_time.date() if record.start_time else fields.Date.today()
+
for lessee in record.lessee_ids:
- # 从承租方的 property_contract_ids(租户行)提取合同
+ # 从承租方的租户行提取合同
tenant_lines = lessee.property_contract_ids.filtered(
- lambda line:
- line.lease_contract_id and
- line.lease_contract_id.lessor_id and
- line.lease_contract_id.lessor_id.referred == record.your_own_unit
+ lambda line: line.lease_contract_id is not False
)
- contract_ids = tenant_lines.mapped('lease_contract_id.id')
- contracts = self.env['property.lease.contract'].browse(contract_ids)
- contracts = contracts.filtered(lambda c: c.contact_state != 'settle')
- contract_set |= contracts
+
+ for tenant_line in tenant_lines:
+ contract = tenant_line.lease_contract_id
+ if not contract:
+ continue
+ # 1. 筛选合同的出租方变更行:生效日期≤目标日期,失效日期≥目标日期/未设置
+ valid_lessor_lines = contract.lessor_line.filtered(
+ lambda l:
+ l.start_date <= target_date and
+ (not l.end_date or l.end_date >= target_date)
+ )
+ # 2. 确定最终的出租方referred值
+ if valid_lessor_lines:
+ actual_lessor_referred = valid_lessor_lines[0].lessor_id.referred
+ else:
+ actual_lessor_referred = contract.lessor_id.referred if contract.lessor_id else False
+ if actual_lessor_referred == record.your_own_unit:
+ if contract.contact_state != 'settle':
+ contract_set |= contract
+
record.contract_ids = contract_set
record.admin_id = record.contract_ids[0].admin_id if record.contract_ids else False
else:
diff --git a/yuthon_report/__manifest__.py b/yuthon_report/__manifest__.py
index 0dd3c1ccd..a211ecdce 100644
--- a/yuthon_report/__manifest__.py
+++ b/yuthon_report/__manifest__.py
@@ -16,6 +16,8 @@
'views/penalty_month_received_report.xml',
'views/penalty_year_cum_report.xml',
'views/deposit_reports.xml',
+ 'views/cum_income_report.xml',
+ 'views/cum_arrears_report.xml',
'views/menu.xml',
'views/ledger_report_views.xml',
'views/receivable_report_views.xml',
@@ -32,6 +34,7 @@
'views/yuthon_report_res_partner.xml',
'views/att_report_view.xml',
'views/staff_position_report.xml',
+ 'views/hydropower_report_views.xml',
],
'installable': True,
'application': True,
diff --git a/yuthon_report/models/__init__.py b/yuthon_report/models/__init__.py
index d2816f2c3..eaec86839 100644
--- a/yuthon_report/models/__init__.py
+++ b/yuthon_report/models/__init__.py
@@ -18,6 +18,8 @@ from . import pre_arrears_report
from . import pre_advance_report
from . import month_receivable_report
from . import total_received_report
+from . import cum_income_report
+from . import cum_arrears_report
from . import penalty_arrears_report
from . import penalty_month_received_report
from . import penalty_year_cum_report
@@ -25,4 +27,5 @@ from . import deposit_month_receivable_report
from . import deposit_pre_received_report
from . import deposit_month_received_report
from . import deposit_cum_arrears_report
-from . import deposit_month_refund_report
\ No newline at end of file
+from . import deposit_month_refund_report
+from . import hydropower_report
\ No newline at end of file
diff --git a/yuthon_report/models/cum_arrears_report.py b/yuthon_report/models/cum_arrears_report.py
new file mode 100644
index 000000000..dc7fee57f
--- /dev/null
+++ b/yuthon_report/models/cum_arrears_report.py
@@ -0,0 +1,112 @@
+import datetime
+import calendar
+
+from odoo import api, models
+
+
+class CumArrearsReport(models.Model):
+ _inherit = 'receivable.modify.line'
+
+ @api.model
+ def get_cum_arrears_report(self, params):
+ """
+ 累计欠收报表(数据源:receivable.modify.line):
+ - 状态为挂账(bank_state = 'registered')
+ - 应收开始日期(receivable_id.due_date)小于等于查询月月末
+ - 排除押金和违约金类型
+ - 金额取 not_collected(未收)
+ """
+ today = datetime.date.today()
+
+ date_start = params.get("date_start")
+ if date_start:
+ query_date = datetime.datetime.fromisoformat(date_start).date()
+ else:
+ query_date = today
+
+ # 查询月月末
+ last_day = calendar.monthrange(query_date.year, query_date.month)[1]
+ 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:
+ 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')
+
+ 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 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.search(domain, order="receivable_id asc")
+
+ rows = []
+ total_amount = 0.0
+ for idx, line in enumerate(lines, start=1):
+ rec = line.receivable_id
+ contract = rec.contract_id if rec else None
+ amount = round(line.not_collected or 0.0, 2)
+ total_amount += amount
+
+ # 物业穿透
+ property_val = ''
+ if contract and contract.lease_ids and contract.lease_ids[0].address_id:
+ prop = contract.lease_ids[0].address_id
+ property_val = {
+ 'model': 'yuthon.property',
+ 'id': prop.id,
+ 'display_name': rec.property_name or prop.name,
+ }
+ elif rec:
+ property_val = rec.property_name or ''
+
+ rows.append({
+ "序号": idx,
+ "合同编号": {
+ 'model': 'property.lease.contract',
+ 'id': contract.id,
+ 'display_name': contract.contract_code,
+ } if contract else "",
+ "物业名称": property_val,
+ "承租方名称": {
+ 'model': 'property.tenant.information',
+ 'id': rec.lessee_id.id,
+ 'display_name': rec.lessee_id.name,
+ } if rec and rec.lessee_id else "",
+ "收款类型": rec.management_type_id.name if rec and rec.management_type_id else "",
+ "未收金额": amount,
+ "所属公司": contract.lessor_id.name if contract and contract.lessor_id else "",
+ "管理员": {
+ 'model': 'res.users',
+ 'id': rec.admin_id.id,
+ 'display_name': rec.admin_id.name,
+ } if rec and rec.admin_id else "",
+ })
+
+ stats = [
+ {'name': '记录总数', 'amount': len(rows)},
+ {'name': '累计欠收', 'amount': round(total_amount, 2)},
+ ]
+
+ return {"rows": rows, "stats": stats}
diff --git a/yuthon_report/models/cum_income_report.py b/yuthon_report/models/cum_income_report.py
new file mode 100644
index 000000000..5deb3078e
--- /dev/null
+++ b/yuthon_report/models/cum_income_report.py
@@ -0,0 +1,105 @@
+import datetime
+
+from odoo import api, models
+
+
+class CumIncomeReport(models.Model):
+ _inherit = 'receivable.modify.line'
+
+ @api.model
+ def get_cum_income_report(self, params):
+ """
+ 累计收入报表(数据源:receivable.modify.line):
+ - 按年查询
+ - 取交易金额(original_amount)
+ - 排除押金和违约金类型
+ """
+ today = datetime.date.today()
+ current_year = today.year
+
+ date_start = params.get("date_start")
+ # 按年查询:如果有传值则使用该年份,否则使用当前年份
+ if date_start:
+ year = datetime.datetime.fromisoformat(date_start).year
+ else:
+ year = current_year
+
+ # 构建年份的开始和结束日期
+ year_start = datetime.date(year, 1, 1)
+ year_end = datetime.date(year, 12, 31)
+
+ domain = [
+ ('receivable_id.due_date', '>=', year_start),
+ ('receivable_id.due_date', '<=', year_end),
+ ('receivable_id.is_invalid', '=', False),
+ ]
+
+ 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')
+
+ 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 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.search(domain, order="receivable_id asc")
+
+ rows = []
+ total_amount = 0.0
+ for idx, line in enumerate(lines, start=1):
+ rec = line.receivable_id
+ contract = rec.contract_id if rec else None
+ amount = round(line.original_amount or 0.0, 2)
+ total_amount += amount
+
+ # 物业穿透
+ property_val = ''
+ if contract and contract.lease_ids and contract.lease_ids[0].address_id:
+ prop = contract.lease_ids[0].address_id
+ property_val = {
+ 'model': 'yuthon.property',
+ 'id': prop.id,
+ 'display_name': rec.property_name or prop.name,
+ }
+ elif rec:
+ property_val = rec.property_name or ''
+
+ rows.append({
+ "序号": idx,
+ "合同编号": {
+ 'model': 'property.lease.contract',
+ 'id': contract.id,
+ 'display_name': contract.contract_code,
+ } if contract else "",
+ "承租方名称": {
+ 'model': 'property.tenant.information',
+ 'id': rec.lessee_id.id,
+ 'display_name': rec.lessee_id.name,
+ } if rec and rec.lessee_id else "",
+ "物业名称": property_val,
+ "金额": amount,
+ })
+
+ stats = [
+ {'name': '记录总数', 'amount': len(rows)},
+ {'name': '累计收入', 'amount': round(total_amount, 2)},
+ ]
+
+ return {"rows": rows, "stats": stats}
diff --git a/yuthon_report/models/current_month_received_report.py b/yuthon_report/models/current_month_received_report.py
index 34eef1b36..ba53891f5 100644
--- a/yuthon_report/models/current_month_received_report.py
+++ b/yuthon_report/models/current_month_received_report.py
@@ -4,7 +4,7 @@ from odoo import api, models
class CurrentMonthReceivedReport(models.Model):
- _inherit = 'property.accounts.receivable'
+ _inherit = 'receivable.modify.line'
@api.model
def get_current_month_received_report(self, params):
@@ -15,9 +15,9 @@ class CurrentMonthReceivedReport(models.Model):
if keyword:
domain += [
'|', '|',
- ('contract_id.contract_code', 'ilike', keyword),
- ('property_name', 'ilike', keyword),
- ('lessee_id.name', 'ilike', keyword),
+ ('receivable_id.contract_id.contract_code', 'ilike', keyword),
+ ('receivable_id.property_name', 'ilike', keyword),
+ ('receivable_id.lessee_id.name', 'ilike', keyword),
]
date_start = params.get("date_start")
@@ -28,20 +28,20 @@ class CurrentMonthReceivedReport(models.Model):
# 优先按收款日期过滤;若收款日期为空,则按应收日期兜底
domain += [
'|',
- '&', ('payout_date', '>=', start_dt), ('payout_date', '<=', end_dt),
- '&', ('payout_date', '=', False), '&', ('due_date', '>=', start_dt), ('due_date', '<=', end_dt)
+ '&', ('receivable_id.payout_date', '>=', start_dt), ('receivable_id.payout_date', '<=', end_dt),
+ '&', ('receivable_id.payout_date', '=', False), '&', ('receivable_id.due_date', '>=', start_dt), ('receivable_id.due_date', '<=', end_dt)
]
elif start_dt:
domain += [
'|',
- ('payout_date', '>=', start_dt),
- '&', ('payout_date', '=', False), ('due_date', '>=', start_dt)
+ ('receivable_id.payout_date', '>=', start_dt),
+ '&', ('receivable_id.payout_date', '=', False), ('receivable_id.due_date', '>=', start_dt)
]
elif end_dt:
domain += [
'|',
- ('payout_date', '<=', end_dt),
- '&', ('payout_date', '=', False), ('due_date', '<=', end_dt)
+ ('receivable_id.payout_date', '<=', end_dt),
+ '&', ('receivable_id.payout_date', '=', False), ('receivable_id.due_date', '<=', end_dt)
]
condition = params.get('condition')
@@ -50,21 +50,22 @@ class CurrentMonthReceivedReport(models.Model):
management_type_id = params.get('management_type_id')
if condition:
- domain.append(('tenure_type', '=', condition))
+ domain.append(('receivable_id.tenure_type', '=', condition))
if partner_id:
- domain.append(('precinct_id', '=', partner_id))
+ domain.append(('receivable_id.precinct_id', '=', partner_id))
if company_id:
- domain.append(('company_id', '=', company_id))
+ domain.append(('receivable_id.company_id', '=', company_id))
if management_type_id:
- domain.append(('management_type_id', '=', management_type_id))
+ domain.append(('receivable_id.management_type_id', '=', management_type_id))
- receivables = self.search(domain, order="payout_date asc, due_date asc")
+ lines = self.search(domain, order="receivable_id asc")
rows = []
total_amount = 0.0
- for idx, rec in enumerate(receivables, start=1):
- amount = rec.delivered1 or 0.0 # 已收金额
+ for idx, line in enumerate(lines, start=1):
+ rec = line.receivable_id
+ amount = line.amount or 0.0 # 已对金额
total_amount += amount
rows.append({
@@ -73,24 +74,24 @@ class CurrentMonthReceivedReport(models.Model):
'model': 'property.lease.contract',
'id': rec.contract_id.id,
'display_name': rec.contract_id.contract_code,
- } if rec.contract_id else "",
+ } if rec and rec.contract_id else "",
"物业名称": {
'model': 'yuthon.property',
'id': rec.contract_id.lease_ids[0].address_id.id,
'display_name': rec.property_name,
- } if rec.contract_id and rec.contract_id.lease_ids and rec.contract_id.lease_ids[0].address_id else rec.property_name or "",
+ } if rec and rec.contract_id and rec.contract_id.lease_ids and rec.contract_id.lease_ids[0].address_id else rec.property_name or "",
"承租方名称": {
'model': 'property.tenant.information',
'id': rec.lessee_id.id,
'display_name': rec.lessee_id.name,
- } if rec.lessee_id else "",
+ } if rec and rec.lessee_id else "",
"金额": round(amount, 2),
- "所属公司": rec.company_id.referred if rec.company_id and hasattr(rec.company_id, 'referred') else rec.company_id.name if rec.company_id else "",
+ "所属公司": rec.company_id.referred if rec and rec.company_id and hasattr(rec.company_id, 'referred') else rec.company_id.name if rec and rec.company_id else "",
"管理员": {
'model': 'res.users',
'id': rec.admin_id.id,
'display_name': rec.admin_id.name,
- } if rec.admin_id else "",
+ } if rec and rec.admin_id else "",
})
return {
diff --git a/yuthon_report/models/hydropower_report.py b/yuthon_report/models/hydropower_report.py
new file mode 100644
index 000000000..40d5e0112
--- /dev/null
+++ b/yuthon_report/models/hydropower_report.py
@@ -0,0 +1,93 @@
+from odoo import models, fields, api
+from datetime import datetime, date
+
+
+class HydropowerReport(models.Model):
+ _name = 'hydropower.report'
+ _description = '水电表应收明细表'
+ _auto = False
+
+ property_name = fields.Char(string='房屋名称')
+ lessee_name = fields.Char(string='业户名称')
+ water_fee = fields.Float(string='水费')
+ water_period = fields.Char(string='水费期间')
+ electric_fee = fields.Float(string='电费')
+ electric_period = fields.Char(string='电费期间')
+ total = fields.Float(string='小计')
+
+ @api.model
+ def get_hydropower_data(self, params):
+ """获取水电表数据,接收 params 字典"""
+ date_start = params.get('date_start')
+ date_end = params.get('date_end')
+
+ start_date = datetime.fromisoformat(date_start).date() if date_start else date.today().replace(day=1)
+ end_date = datetime.fromisoformat(date_end).date() if date_end else date.today()
+
+ # 获取水表数据
+ water_data = self.env['meter.water.line'].search([
+ ('meter_date', '>=', start_date),
+ ('meter_date', '<=', end_date),
+ ('state', '=', 'reading')
+ ])
+
+ # 获取电表数据
+ electric_data = self.env['meter.archives.line'].search([
+ ('meter_date', '>=', start_date),
+ ('meter_date', '<=', end_date),
+ ('state', '=', 'reading')
+ ])
+
+ # 整合数据
+ property_dict = {}
+
+ for water in water_data:
+ for property_id in water.yuthon_property_ids:
+ key = property_id.name
+ if key not in property_dict:
+ property_dict[key] = {
+ '房屋名称': property_id.name,
+ '业户名称': property_id.lessee_id.name if property_id.lessee_id else '',
+ '水费': 0.0,
+ '水费期间': '',
+ '电费': 0.0,
+ '电费期间': '',
+ '小计': 0.0
+ }
+ property_dict[key]['水费'] += water.receivables
+ property_dict[key]['水费期间'] = f"{start_date}到{end_date}"
+
+ for electric in electric_data:
+ for property_id in electric.yuthon_property_ids:
+ key = property_id.name
+ if key not in property_dict:
+ property_dict[key] = {
+ '房屋名称': property_id.name,
+ '业户名称': property_id.lessee_id.name if property_id.lessee_id else '',
+ '水费': 0.0,
+ '水费期间': '',
+ '电费': 0.0,
+ '电费期间': '',
+ '小计': 0.0
+ }
+ property_dict[key]['电费'] += electric.receivables
+ property_dict[key]['电费期间'] = f"{start_date}到{end_date}"
+
+ rows = []
+ total_water = 0.0
+ total_electric = 0.0
+ for idx, (key, value) in enumerate(property_dict.items(), start=1):
+ value['小计'] = round(value['水费'] + value['电费'], 2)
+ value['水费'] = round(value['水费'], 2)
+ value['电费'] = round(value['电费'], 2)
+ total_water += value['水费']
+ total_electric += value['电费']
+ rows.append(value)
+
+ stats = [
+ {'name': '记录数', 'amount': len(rows)},
+ {'name': '水费合计', 'amount': round(total_water, 2)},
+ {'name': '电费合计', 'amount': round(total_electric, 2)},
+ {'name': '合计', 'amount': round(total_water + total_electric, 2)},
+ ]
+ return {'rows': rows, 'stats': stats}
diff --git a/yuthon_report/models/monthly_precollection_report.py b/yuthon_report/models/monthly_precollection_report.py
index 1f78e0334..7af723cd2 100644
--- a/yuthon_report/models/monthly_precollection_report.py
+++ b/yuthon_report/models/monthly_precollection_report.py
@@ -1,90 +1,121 @@
import datetime
+import calendar
from odoo import api, models
class MonthlyPrecollectionReport(models.Model):
- _inherit = 'property.accounts.receivable'
+ _inherit = 'receivable.modify.line'
@api.model
def get_monthly_precollection_report(self, params):
- """汇总当前筛选条件下的应收数据(本月预收视图)。"""
- domain = []
+ """
+ 本月预收报表(数据源:receivable.modify.line):
+ - 应收开始日期(receivable_id.due_date)在查询月当月(月初 ~ 月末)
+ - delivered1 > original_amount(已交超过当期金额,即有预收)
+ - 应收账单非作废:receivable_id.is_invalid = False
+ - 排除押金和违约金类型
+ - 金额取 delivered1 - original_amount(预收金额)
+ """
+ today = datetime.date.today()
+
+ date_start = params.get("date_start")
+ if date_start:
+ query_date = datetime.datetime.fromisoformat(date_start).date()
+ else:
+ query_date = today
+
+ # 查询月月初和月末
+ month_start = query_date.replace(day=1)
+ last_day = calendar.monthrange(query_date.year, query_date.month)[1]
+ month_end = query_date.replace(day=last_day)
+
+ domain = [
+ ('receivable_id.due_date', '>=', month_start),
+ ('receivable_id.due_date', '<=', month_end),
+ ('receivable_id.delivered1', '>', 0),
+ ('receivable_id.is_invalid', '=', False),
+ ]
keyword = params.get("keyword")
if keyword:
domain += [
'|', '|',
- ('lessee_id.name', 'ilike', keyword),
- ('property_name', 'ilike', keyword),
- ('title_deed', 'ilike', keyword),
+ ('receivable_id.contract_id.contract_code', 'ilike', keyword),
+ ('receivable_id.property_name', 'ilike', keyword),
+ ('receivable_id.lessee_id.name', 'ilike', keyword),
]
- date_start = params.get("date_start")
- date_end = params.get("date_end")
- if date_start:
- start_dt = datetime.datetime.fromisoformat(date_start).date()
- domain.append(("due_date", ">=", start_dt))
- if date_end:
- end_dt = datetime.datetime.fromisoformat(date_end).date()
- domain.append(("due_date", "<=", end_dt))
-
condition = params.get('condition')
partner_id = params.get('partner_id')
company_id = params.get('company_id')
management_type_id = params.get('management_type_id')
if condition:
- domain.append(('tenure_type', '=', condition))
+ domain.append(('receivable_id.tenure_type', '=', condition))
if partner_id:
- domain.append(('precinct_id', '=', partner_id))
+ domain.append(('receivable_id.precinct_id', '=', partner_id))
if company_id:
- domain.append(('company_id', '=', company_id))
+ domain.append(('receivable_id.company_id', '=', company_id))
if management_type_id:
- domain.append(('management_type_id', '=', management_type_id))
+ domain.append(('receivable_id.management_type_id', '=', management_type_id))
+ else:
+ domain.append(('receivable_id.management_type_id.name', 'not in', ['押金', '违约金']))
- receivables = self.search(domain, limit=1000, order="due_date asc")
+ lines = self.search(domain, order="receivable_id asc")
- result = []
+ rows = []
total_amount = 0.0
- for index, rec in enumerate(receivables, start=1):
- amount = rec.original_amount or 0.0
+ idx = 1
+ for line in lines:
+ rec = line.receivable_id
+ contract = rec.contract_id if rec else None
+ # 预收金额 = 已交 - 当期金额,必须 > 0 才是真正预收
+ amount = round((rec.delivered1 or 0.0) - (rec.original_amount or 0.0), 2)
+ if amount <= 0:
+ continue
total_amount += amount
- result.append({
- "序号": index,
+
+ # 物业穿透
+ property_val = ''
+ if contract and contract.lease_ids and contract.lease_ids[0].address_id:
+ prop = contract.lease_ids[0].address_id
+ property_val = {
+ 'model': 'yuthon.property',
+ 'id': prop.id,
+ 'display_name': rec.property_name or prop.name,
+ }
+ elif rec:
+ property_val = rec.property_name or ''
+
+ rows.append({
+ "序号": idx,
"合同编号": {
'model': 'property.lease.contract',
- 'id': rec.contract_id.id,
- 'display_name': rec.contract_id.contract_code,
- } if rec.contract_id else "",
- "物业名称": {
- 'model': 'yuthon.property',
- 'id': rec.contract_id.lease_ids[0].address_id.id,
- 'display_name': rec.property_name,
- } if rec.contract_id and rec.contract_id.lease_ids and rec.contract_id.lease_ids[0].address_id else rec.property_name or "",
+ 'id': contract.id,
+ 'display_name': contract.contract_code,
+ } if contract else "",
+ "物业名称": property_val,
"承租方名称": {
'model': 'property.tenant.information',
'id': rec.lessee_id.id,
'display_name': rec.lessee_id.name,
- } if rec.lessee_id else "",
- "金额": round(amount, 2),
- "所属公司": (
- rec.contract_id.lessor_id.referred
- or rec.contract_id.lessor_id.name
- if rec.contract_id and rec.contract_id.lessor_id
- else ""
- ),
+ } if rec and rec.lessee_id else "",
+ "收款类型": rec.management_type_id.name if rec and rec.management_type_id else "",
+ "金额": amount,
+ "所属公司": contract.lessor_id.name if contract and contract.lessor_id else "",
"管理员": {
'model': 'res.users',
- 'id': rec.contract_id.admin_id.id,
- 'display_name': rec.contract_id.admin_id.name,
- } if rec.contract_id and rec.contract_id.admin_id else "",
+ 'id': rec.admin_id.id,
+ 'display_name': rec.admin_id.name,
+ } if rec and rec.admin_id else "",
})
+ idx += 1
- return {
- "rows": result,
- "stats": [
- {"name": "应收总额", "amount": round(total_amount, 2)},
- ],
- }
+ stats = [
+ {'name': '合同总数', 'amount': len(rows)},
+ {'name': '预收总额', 'amount': round(total_amount, 2)},
+ ]
+
+ return {"rows": rows, "stats": stats}
diff --git a/yuthon_report/models/pre_advance_report.py b/yuthon_report/models/pre_advance_report.py
index b9c3c9aaf..51c740a31 100644
--- a/yuthon_report/models/pre_advance_report.py
+++ b/yuthon_report/models/pre_advance_report.py
@@ -11,11 +11,10 @@ class PreAdvanceReport(models.Model):
"""
前期预收报表(数据源:receivable.modify.line):
- 应收开始日期(receivable_id.due_date)在查询月最后一天之后(未来应收)
- - 应收账单未收金额(receivable_id.submitted)= 0(已全额收款)
- - original_amount > 0(有交易金额)
+ - delivered1 > original_amount(已交超过当期金额,即有预收)
- 应收账单非作废:receivable_id.is_invalid = False
- 排除押金和违约金类型
- - 金额取 original_amount(交易金额)
+ - 金额取 delivered1 - original_amount(预收金额)
"""
today = datetime.date.today()
if today.month == 12:
@@ -30,8 +29,7 @@ class PreAdvanceReport(models.Model):
domain = [
('receivable_id.due_date', '>', cutoff_date),
- ('receivable_id.submitted', '=', 0),
- ('original_amount', '>', 0),
+ ('receivable_id.delivered1', '>', 0),
('receivable_id.is_invalid', '=', False),
]
@@ -64,10 +62,14 @@ class PreAdvanceReport(models.Model):
rows = []
total_amount = 0.0
- for idx, line in enumerate(lines, start=1):
+ idx = 1
+ for line in lines:
rec = line.receivable_id
contract = rec.contract_id if rec else None
- amount = round(line.original_amount or 0.0, 2)
+ # 预收金额 = 已交 - 当期金额,必须 > 0 才是真正预收
+ amount = round((rec.delivered1 or 0.0) - (rec.original_amount or 0.0), 2)
+ if amount <= 0:
+ continue
total_amount += amount
# 物业穿透
@@ -103,6 +105,7 @@ class PreAdvanceReport(models.Model):
'display_name': rec.admin_id.name,
} if rec and rec.admin_id else "",
})
+ idx += 1
stats = [
{'name': '合同总数', 'amount': len(rows)},
diff --git a/yuthon_report/models/pre_arrears_report.py b/yuthon_report/models/pre_arrears_report.py
index 3ee8f0914..83244793c 100644
--- a/yuthon_report/models/pre_arrears_report.py
+++ b/yuthon_report/models/pre_arrears_report.py
@@ -61,7 +61,7 @@ class PreArrearsReport(models.Model):
for idx, line in enumerate(lines, start=1):
rec = line.receivable_id
contract = rec.contract_id if rec else None
- amount = round(line.original_amount or 0.0, 2)
+ amount = round(rec.submitted or 0.0, 2)
total_amount += amount
# 物业穿透
diff --git a/yuthon_report/views/cum_arrears_report.xml b/yuthon_report/views/cum_arrears_report.xml
new file mode 100644
index 000000000..21bce27e6
--- /dev/null
+++ b/yuthon_report/views/cum_arrears_report.xml
@@ -0,0 +1,29 @@
+
+
+
+
+ 累计欠收
+ receivable_report_client
+
+ {
+ "sideBar": true,
+ "report_config": {
+ "model": "receivable.modify.line",
+ "method": "get_cum_arrears_report",
+ "dateMode": "single",
+ "columns": [
+ {"headerName": "序号", "field": "序号", "width": 45, "flex": 0, "pinned": "left"},
+ {"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}
+ ]
+ }
+ }
+
+
+
+
diff --git a/yuthon_report/views/cum_income_report.xml b/yuthon_report/views/cum_income_report.xml
new file mode 100644
index 000000000..a2916dbf3
--- /dev/null
+++ b/yuthon_report/views/cum_income_report.xml
@@ -0,0 +1,8 @@
+
+
+
+ 累计收入
+ receivable_report_client
+ {"report_config": {"model": "receivable.modify.line", "method": "get_cum_income_report", "columns": [{"headerName": "序号", "field": "序号", "width": 80, "flex": 0}, {"headerName": "合同编号", "field": "合同编号", "flex": 1}, {"headerName": "承租方名称", "field": "承租方名称", "flex": 1}, {"headerName": "物业名称", "field": "物业名称", "flex": 1}, {"headerName": "金额", "field": "金额", "flex": 1}]}}
+
+
diff --git a/yuthon_report/views/current_month_received_report.xml b/yuthon_report/views/current_month_received_report.xml
index 8dab2328b..1a9e3c230 100644
--- a/yuthon_report/views/current_month_received_report.xml
+++ b/yuthon_report/views/current_month_received_report.xml
@@ -8,7 +8,7 @@
{
"sideBar": true,
"report_config": {
- "model": "property.accounts.receivable",
+ "model": "receivable.modify.line",
"method": "get_current_month_received_report",
"columns": [
{"headerName": "序号", "field": "序号", "width": 45, "flex": 0, "pinned": "left"},
diff --git a/yuthon_report/views/hydropower_report_views.xml b/yuthon_report/views/hydropower_report_views.xml
new file mode 100644
index 000000000..c0800554f
--- /dev/null
+++ b/yuthon_report/views/hydropower_report_views.xml
@@ -0,0 +1,18 @@
+
+
+
+
+
+ 水电表应收明细表
+ receivable_report_client
+ {"sideBar": true, "report_config": {"model": "hydropower.report", "method": "get_hydropower_data", "dateMode": "range", "columns": [{"headerName": "房屋名称", "field": "房屋名称", "flex": 2}, {"headerName": "业户名称", "field": "业户名称", "flex": 1.5}, {"headerName": "水费", "field": "水费", "flex": 1, "type": "number"}, {"headerName": "水费期间", "field": "水费期间", "flex": 2}, {"headerName": "电费", "field": "电费", "flex": 1, "type": "number"}, {"headerName": "电费期间", "field": "电费期间", "flex": 2}, {"headerName": "小计", "field": "小计", "flex": 1, "type": "number"}]}}
+
+
+
+
+
+
diff --git a/yuthon_report/views/menu.xml b/yuthon_report/views/menu.xml
index 0a2159aa3..3e08126a8 100644
--- a/yuthon_report/views/menu.xml
+++ b/yuthon_report/views/menu.xml
@@ -48,30 +48,26 @@
name="本月实收总额"
parent="yuthon_property_income_menu"
action="action_total_received_report"/>
-
+ action="action_cum_arrears_report"/>
+ action="action_cum_income_report"/>