From 1fdedc13d358fc2208303ae562be36793d73e7cb 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: Sat, 20 Sep 2025 18:06:32 +0800 Subject: [PATCH] =?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/property_meter_archives.py | 39 +++- .../models/property_meter_water.py | 39 +++- .../views/hydropower_logs_views.xml | 2 +- .../views/property_meter_archives_views.xml | 24 +-- .../views/property_meter_water_views.xml | 24 +-- .../wizard/property_meter_wizard.py | 169 ++++++++++++------ .../wizard/property_water_wizard.py | 123 ++++++++----- .../property_accounting_approval_views.xml | 3 +- 8 files changed, 290 insertions(+), 133 deletions(-) diff --git a/yuthon_property/models/property_meter_archives.py b/yuthon_property/models/property_meter_archives.py index 9a7d77243..8746802ed 100644 --- a/yuthon_property/models/property_meter_archives.py +++ b/yuthon_property/models/property_meter_archives.py @@ -168,12 +168,12 @@ class MeterArchivesLine(models.Model): archives_id = fields.Many2one('property.meter.archives', string='电表库', required=True, ondelete='cascade') name = fields.Char(string='仪表编号') epitope_values = fields.Char(string='表位置') - lessee_id = fields.Many2one('property.tenant.information', string='承租方') + lessee_id = fields.Many2one('property.tenant.information', string='承租方', compute='_compute_lessee_id') yuthon_property_ids = fields.Many2many('yuthon.property', string='物业信息') last_meter = fields.Date(string='上次抄表日期') - last_dosage = fields.Float(string='上次用量') + last_dosage = fields.Float(string='上次用量', compute="_compute_last_dosage") last_read = fields.Float(string='上次读数', readonly=True) - current_meter = fields.Float(string='本次用量', readonly=True) + current_meter = fields.Float(string='本次用量', readonly=True, compute='_compute_current_meter') current_read = fields.Float(string='本次读数') unit_number = fields.Char(string='单元编号/用途') gauge_magnification = fields.Integer(string='仪表倍率', readonly=True, default=1) @@ -186,6 +186,39 @@ class MeterArchivesLine(models.Model): default='use') maximum_count = fields.Integer(string='最大位数') + @api.depends('current_read', 'last_read') + def _compute_current_meter(self): + for record in self: + record.current_meter = record.current_read - record.last_read + + @api.depends('yuthon_property_ids') + def _compute_lessee_id(self): + for record in self: + if record.yuthon_property_ids: + record.lessee_id = record.yuthon_property_ids[0].lessee_id + else: + record.lessee_id = False + + @api.depends('current_read', 'last_read') + def _compute_last_dosage(self): + """上次用量 = 上个月的本次读数 - 上个月的上次读数""" + for line in self: + # 获取同仪表的所有明细行并按抄表日期排序 + lines = self.search([ + ('archives_id', '=', line.archives_id.id), + ('last_meter', '!=', False) + ], order='last_meter asc') + + if line in lines: + idx = lines.ids.index(line.id) + if idx > 0: + prev_line = lines[idx - 1] + line.last_dosage = (prev_line.current_read or 0) - (prev_line.last_read or 0) + else: + line.last_dosage = 0.0 + else: + # 当前记录没有抄表日期,无法计算上次用量 + line.last_dosage = 0.0 class PropertyElectricReading(models.Model): _name = 'property.electric.reading' diff --git a/yuthon_property/models/property_meter_water.py b/yuthon_property/models/property_meter_water.py index 24786f223..f2ecf7bea 100644 --- a/yuthon_property/models/property_meter_water.py +++ b/yuthon_property/models/property_meter_water.py @@ -158,12 +158,12 @@ class MeterWaterLine(models.Model): water_id = fields.Many2one('property.meter.water', string='水表库', required=True, ondelete='cascade') name = fields.Char(string='仪表编号') epitope_values = fields.Char(string='表位置') - lessee_id = fields.Many2one('property.tenant.information', string='承租方') + lessee_id = fields.Many2one('property.tenant.information', string='承租方', compute='_compute_lessee_id') yuthon_property_ids = fields.Many2many('yuthon.property', string='物业信息') last_meter = fields.Date(string='上次抄表日期') - last_dosage = fields.Float(string='上次用量') + last_dosage = fields.Float(string='上次用量', compute="_compute_last_dosage") last_read = fields.Float(string='上次读数', readonly=True) - current_meter = fields.Float(string='本次用量', readonly=True) + current_meter = fields.Float(string='本次用量', readonly=True, compute='_compute_current_meter') current_read = fields.Float(string='本次读数') unit_number = fields.Char(string='单元编号/用途') gauge_magnification = fields.Integer(string='仪表倍率', readonly=True, default=1) @@ -176,6 +176,39 @@ class MeterWaterLine(models.Model): employee_ids = fields.Many2many('hr.employee', string='抄表人') maximum_count = fields.Integer(string='最大位数') + @api.depends('current_read', 'last_read') + def _compute_current_meter(self): + for record in self: + record.current_meter = record.current_read - record.last_read + + @api.depends('yuthon_property_ids') + def _compute_lessee_id(self): + for record in self: + if record.yuthon_property_ids: + record.lessee_id = record.yuthon_property_ids[0].lessee_id + else: + record.lessee_id = False + + @api.depends('current_read', 'last_read') + def _compute_last_dosage(self): + """上次用量 = 上个月的本次读数 - 上个月的上次读数""" + for line in self: + # 获取同仪表的所有明细行并按抄表日期排序 + lines = self.search([ + ('archives_id', '=', line.archives_id.id), + ('last_meter', '!=', False) + ], order='last_meter asc') + + if line in lines: + idx = lines.ids.index(line.id) + if idx > 0: + prev_line = lines[idx - 1] + line.last_dosage = (prev_line.current_read or 0) - (prev_line.last_read or 0) + else: + line.last_dosage = 0.0 + else: + # 当前记录没有抄表日期,无法计算上次用量 + line.last_dosage = 0.0 class PropertyWaterReading(models.Model): diff --git a/yuthon_property/views/hydropower_logs_views.xml b/yuthon_property/views/hydropower_logs_views.xml index 6b1cabdc8..36fe77491 100644 --- a/yuthon_property/views/hydropower_logs_views.xml +++ b/yuthon_property/views/hydropower_logs_views.xml @@ -13,7 +13,7 @@ - 水电单价” + 水电单价 hydropower.logs tree diff --git a/yuthon_property/views/property_meter_archives_views.xml b/yuthon_property/views/property_meter_archives_views.xml index 9ec6e2b23..5e79eed89 100644 --- a/yuthon_property/views/property_meter_archives_views.xml +++ b/yuthon_property/views/property_meter_archives_views.xml @@ -15,14 +15,14 @@ - - - - - + + + + + - + @@ -58,12 +58,12 @@ - - - - - - + + + + + + diff --git a/yuthon_property/views/property_meter_water_views.xml b/yuthon_property/views/property_meter_water_views.xml index 6c64d296c..72bd34cbb 100644 --- a/yuthon_property/views/property_meter_water_views.xml +++ b/yuthon_property/views/property_meter_water_views.xml @@ -16,14 +16,14 @@ - - - - - + + + + + - + @@ -61,12 +61,12 @@ - - - - - - + + + + + + diff --git a/yuthon_property/wizard/property_meter_wizard.py b/yuthon_property/wizard/property_meter_wizard.py index 094c6daa0..e4ac127fb 100644 --- a/yuthon_property/wizard/property_meter_wizard.py +++ b/yuthon_property/wizard/property_meter_wizard.py @@ -16,78 +16,139 @@ class PropertyMeterWizard(models.Model): def confirm(self): """ - 导入excel文件,按行读取数据并处理 + 导入excel文件,按行读取数据并处理,将1-9月数据写入明细行 """ if not self.excel_file: 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): + + # 解码并打开Excel文件 + try: + book = xlrd.open_workbook(file_contents=base64.decodebytes(self.excel_file)) + sh = book.sheet_by_index(0) + except Exception as e: + raise ValidationError(f'文件解析错误: {str(e)}') + + # 按行处理数据 + for rx in range(1, sh.nrows): # 跳过表头行 row = sh.row(rx) - last_read = 0 + last_read = 0.0 # 初始读数,第一个月的上次读数为0 + + # 处理1-9月份数据 for month in range(1, 10): last_read = self.property_meter_data(row, last_read, month) def property_meter_data(self, row, last_read, month): - epitope_values = row[0].value - name = row[3].value - type_dict = {'水表': 'water', '电表': 'electric', '电表(电子表)': 'smart', '': ''} - unit_number = row[1].value - installation_location = row[2].value - if row[5].value: - gauge_magnification = float(row[5].value) - else: - gauge_magnification = None - maximum_count = float(row[6].value) if row[6].value else None - type_dict = {'公共': 'public', '收费': 'fees', '': ''} - type = type_dict.get(row[7].value) - property_id = None - if row[2].value: - property_search = self.env['yuthon.property'].search([('name', '=', row[2].value)]) - if property_search: - property_id = property_search[0] + """ + 处理单月数据,查找主记录并创建/更新明细行 + """ + # 从Excel行获取基础数据 + epitope_values = row[0].value if len(row) > 0 else '' + unit_number = row[1].value if len(row) > 1 else '' + installation_location = row[2].value if len(row) > 2 else '' + name = row[3].value if len(row) > 3 else '' # 仪表编号(关键标识) + # 处理仪表倍率 + gauge_magnification = None + if len(row) > 5 and row[5].value: + try: + gauge_magnification = float(row[5].value) + except ValueError: + gauge_magnification = 1 # 默认为1 + + # 处理最大位数 + maximum_count = None + if len(row) > 6 and row[6].value: + try: + maximum_count = float(row[6].value) + except ValueError: + maximum_count = None + + # 处理类型转换 + type_dict = {'公共': 'public', '收费': 'fees', '': ''} + meter_type = type_dict.get(row[7].value if len(row) > 7 else '', '') + + # 处理物业信息 + property_id = None + if installation_location: # 使用安装位置匹配物业 + property_search = self.env['yuthon.property'].search( + [('name', '=', installation_location)], + limit=1 + ) + if property_search: + property_id = property_search + + # 确定当前读数列索引(1-8月正常,9月特殊处理) current_read_index = month + 9 if month < 9 else 9 - meter_date = None + + # 处理当月数据 + meter_date = datetime(2025, month, 15) if month < 9 else None current_read = None - # 1-8月份设置正常数据,9月份留空 - if month < 9: - meter_date = datetime(2025, month, 15) - current_read = row[current_read_index].value - is_push = month < 9 # 9月份依然保持is_push为False - additional_data = { + if month < 9 and len(row) > current_read_index and row[current_read_index].value: + try: + current_read = float(row[current_read_index].value) + except ValueError: + current_read = None + + # 查找或创建主表记录(按仪表编号) + archives = self.env['property.meter.archives'].search([('name', '=', name), + ('is_push', '=', False) + ], limit=1) + if not archives: + archives = self.env['property.meter.archives'].create({ + 'name': name, + 'epitope_values': epitope_values, + 'unit_number': unit_number, + 'installation_location': installation_location, + 'type': meter_type, + 'gauge_magnification': gauge_magnification, + 'maximum_count': maximum_count, + 'yuthon_property_ids': [(4, property_id.id)] if property_id else [], + }) + else: + # 更新已有记录的部分字段 + archives.write({ + 'epitope_values': epitope_values, + 'unit_number': unit_number, + 'installation_location': installation_location, + 'type': meter_type, + 'gauge_magnification': gauge_magnification, + 'maximum_count': maximum_count, + 'yuthon_property_ids': [(4, property_id.id)] if property_id else [], + }) + + # 准备明细行数据 + line_vals = { 'name': name, + 'archives_id': archives.id, 'epitope_values': epitope_values, - 'maximum_count': maximum_count, 'unit_number': unit_number, - 'installation_location': installation_location, - 'type':type, - 'gauge_magnification': gauge_magnification, - 'meter_date': meter_date, - 'current_read': current_read, + 'type': meter_type, + 'gauge_magnification': gauge_magnification or 1, + 'maximum_count': maximum_count, 'last_read': last_read, - 'is_push': is_push, + 'current_read': current_read, + 'last_meter': meter_date, + 'last_reading_time': meter_date, 'yuthon_property_ids': [(4, property_id.id)] if property_id else [], } + self.env['meter.archives.line'].sudo().create(line_vals) + # 返回当前读数作为下个月的上次读数 + return current_read if (month < 9 and current_read is not None) else last_read - # 处理数据逻辑... - combined_data = {**additional_data} - meter_id = self.env['property.meter.archives'].create(combined_data) + # if property_id: + # clear_entries = [(5,)] + # new_meter_entry = (0, 0, { + # 'property_meter_archives_id': meter_id.id, + # }) + # updated_meters = clear_entries + [new_meter_entry] + # property_id.write({ + # 'is_electricity_meter': True, + # 'energy_meter_ids': updated_meters + # }) - if property_id: - clear_entries = [(5,)] - new_meter_entry = (0, 0, { - 'property_meter_archives_id': meter_id.id, - }) - updated_meters = clear_entries + [new_meter_entry] - property_id.write({ - 'is_electricity_meter': True, - 'energy_meter_ids': updated_meters - }) - - if month < 9 and current_read is not None: - return current_read - else: - return last_read + # if month < 9 and current_read is not None: + # return current_read + # else: + # return last_read diff --git a/yuthon_property/wizard/property_water_wizard.py b/yuthon_property/wizard/property_water_wizard.py index 7dc981050..2ac40ac5d 100644 --- a/yuthon_property/wizard/property_water_wizard.py +++ b/yuthon_property/wizard/property_water_wizard.py @@ -16,79 +16,108 @@ class PropertyWaterWizard(models.Model): def confirm(self): """ - 导入excel文件,按行读取数据并处理 + 导入excel文件,按行读取数据并处理,将1-9月数据写入明细行 """ if not self.excel_file: raise ValidationError('请上传文件。') - book = xlrd.open_workbook(file_contents=base64.decodebytes(self.excel_file)) - sh = book.sheet_by_index(0) + + try: + book = xlrd.open_workbook(file_contents=base64.decodebytes(self.excel_file)) + sh = book.sheet_by_index(0) + except Exception as e: + raise ValidationError(f'文件解析错误: {str(e)}') for rx in range(1, sh.nrows): row = sh.row(rx) - last_read = 0 + last_read = 0.0 for month in range(1, 10): last_read = self.property_water_data(row, last_read, month) + return { + 'type': 'ir.actions.client', + 'tag': 'display_notification', + 'params': { + 'message': f'成功导入 {sh.nrows - 1} 条水表数据及明细', + 'type': 'success', + 'sticky': False, + } + } - def property_water_data(self,row, last_read, month): + def property_water_data(self, row, last_read, month): epitope_values = row[0].value - name = row[3].value - type_dict = {'水表': 'water', '电表': 'electric', '电表(电子表)': 'smart', '': ''} - meter_type = type_dict.get(row[4].value) + name = row[3].value # 仪表编号 unit_number = row[1].value installation_location = row[2].value - if row[5].value: - gauge_magnification = float(row[5].value) - else: - gauge_magnification = None + + # 仪表倍率 + gauge_magnification = float(row[5].value) if row[5].value else None + # 最大位数 maximum_count = float(row[6].value) if row[6].value else None + + # 类型转换 type_dict = {'公共': 'public', '收费': 'fees', '': ''} - type = type_dict.get(row[7].value) + meter_type = type_dict.get(row[7].value) + + # 物业信息 property_id = None if row[2].value: - property_search = self.env['yuthon.property'].search([('name', '=', row[2].value)]) + property_search = self.env['yuthon.property'].search([('name', '=', row[2].value)], limit=1) if property_search: property_id = property_search[0] + # 读数索引 current_read_index = month + 9 if month < 9 else 9 - meter_date = None - current_read = None - # 1-8月份设置正常数据,9月份留空 - if month < 9: - meter_date = datetime(2025, month, 15) - current_read = row[current_read_index].value - is_push = month < 9 # 9月份依然保持is_push为False - additional_data = { + + # 1-8月正常数据,9月留空 + meter_date = datetime(2025, month, 15) if month < 9 else None + current_read = row[current_read_index].value if (month < 9 and row[current_read_index].value) else None + # 查找或创建水表主记录 + water = self.env['property.meter.water'].search([('name', '=', name), + ('is_push', '=', False) + ], limit=1) + if not water: + water = self.env['property.meter.water'].create({ + 'name': name, + 'epitope_values': epitope_values, + 'unit_number': unit_number, + 'installation_location': installation_location, + 'type': meter_type, + 'gauge_magnification': gauge_magnification, + 'maximum_count': maximum_count, + 'yuthon_property_ids': [(4, property_id.id)] if property_id else [], + }) + else: + water.write({ + 'epitope_values': epitope_values, + 'unit_number': unit_number, + 'installation_location': installation_location, + 'type': meter_type, + 'gauge_magnification': gauge_magnification, + 'maximum_count': maximum_count, + 'yuthon_property_ids': [(4, property_id.id)] if property_id else [], + }) + + # 计算用量 + last_dosage = None + if last_read is not None and current_read is not None: + last_dosage = float(current_read) - float(last_read) + + # 准备明细行数据 + line_vals = { 'name': name, 'epitope_values': epitope_values, - 'maximum_count': maximum_count, 'unit_number': unit_number, - 'installation_location': installation_location, - 'type': type, + 'type': meter_type, 'gauge_magnification': gauge_magnification, - 'meter_date': meter_date, - 'current_read': current_read, + 'maximum_count': maximum_count, 'last_read': last_read, - 'is_push': is_push, + 'current_read': current_read, + 'last_dosage': last_dosage, + 'last_meter': meter_date, + 'last_reading_time': meter_date, 'yuthon_property_ids': [(4, property_id.id)] if property_id else [], } + water.write({'line_ids': [(0, 0, line_vals)]}) - # 处理数据逻辑... - combined_data = {**additional_data} - meter_id = self.env['property.meter.water'].create(combined_data) - - if property_id: - clear_entries = [(5,)] - new_meter_entry = (0, 0, { - 'property_meter_water_id': meter_id.id, - }) - updated_meters = clear_entries + [new_meter_entry] - property_id.write({ - 'is_meter': True, - 'water_meter_ids': updated_meters - }) - - if month < 9 and current_read is not None: - return current_read - else: - return last_read + # 返回当前读数作为下月上次读数 + return float(current_read) if (month < 9 and current_read is not None) else last_read diff --git a/yuthon_property_approval/views/property_accounting_approval_views.xml b/yuthon_property_approval/views/property_accounting_approval_views.xml index f62105b84..79f638557 100644 --- a/yuthon_property_approval/views/property_accounting_approval_views.xml +++ b/yuthon_property_approval/views/property_accounting_approval_views.xml @@ -66,6 +66,7 @@ force_save="1"/> + @@ -74,7 +75,7 @@ - +