Files
gzth/yuthon_property/models/property_meter_water.py
T
2026-03-23 17:26:38 +08:00

389 lines
17 KiB
Python

from odoo import models, fields, api
from odoo.exceptions import UserError, ValidationError
from datetime import datetime
from datetime import datetime, timedelta, date
class PropertyElectricReading(models.Model):
_name = "property.electric.reading"
class PropertyMeterWater(models.Model):
_name = "property.meter.water"
_description = "水表库"
_order = "number asc"
name = fields.Char(string="仪表编号")
number = fields.Integer(
related="epitope_values_id.sequence", string="序号", store=True
)
sequence1 = fields.Integer(string="序号")
unit_number = fields.Char(string="单元编号/用途")
installation_location = fields.Char(string="安装位置")
is_state = fields.Boolean(string="是否启用")
type = fields.Selection([("public", "公共"), ("fees", "收费")], string="类型")
gauge_magnification = fields.Integer(string="仪表倍率", default=1)
maximum_count = fields.Integer(string="最大位数")
lessee_id = fields.Many2one(
"property.tenant.information",
store=True,
compute="_compute_lessee_id",
string="承租方",
)
employee_ids = fields.Many2many("hr.employee", string="抄表人")
epitope_values = fields.Char(string="表位置")
epitope_values_id = fields.Many2one("yuthon.epitope.values", string="表位置")
other = fields.Char(string="其他")
unit = fields.Float(string="当月单价", digits=(16, 4))
start_time = fields.Date(string="安装日期")
end_time = fields.Date(string="拆除日期")
last_reading_time = fields.Date(string="最后读数时间")
water_state = fields.Selection(
[("stop", "停用"), ("use", "使用"), ("rent", "出租")],
string="状态",
store=True,
)
standards_id = fields.Many2one("yuthon.electricity.setting", string="标准")
yuthon_property_ids = fields.Many2many("yuthon.property", string="物业信息")
fixed_receivables = fields.Float(string="固定应收", digits=(16, 4))
line_ids = fields.One2many("meter.water.line", "water_id", string="水表明细行")
state = fields.Selection(
[("reading", "已抄"), ("unreading", "未抄")],
string="抄表状态",
default="unreading",
)
remarks = fields.Text(string="备注")
def update_water_state(self):
current_date = fields.Date.today() + timedelta(hours=8)
records = self.env["property.meter.water"].search([])
for record in records:
if record.end_time:
if current_date >= record.end_time:
record.water_state = "stop"
def water_task(self):
current_date = fields.Date.today()
current_date = current_date.replace(day=15)
month_start = current_date.replace(day=1)
if current_date.month == 12:
month_end = current_date.replace(year=current_date.year + 1, month=1, day=1) - timedelta(days=1)
else:
month_end = current_date.replace(month=current_date.month + 1, day=1) - timedelta(days=1)
water_archives = self.search([])
for water in water_archives:
existing_lines = self.env["meter.water.line"].search([
("water_id", "=", water.id),
("meter_date", ">=", month_start),
("meter_date", "<=", month_end),
], limit=1)
if not existing_lines:
self.env["meter.water.line"].create({
"water_id": water.id,
"epitope_values_id": water.epitope_values_id.id,
"meter_date": current_date,
"state": "unreading",
"water_state": "use",
"unit": water.unit or 0.0,
"gauge_magnification": water.gauge_magnification or 1,
"line_loss": 0.02,
"type": water.type,
"unit_number": water.unit_number or "",
"maximum_count": water.maximum_count or 0,
})
@api.model
def create(self, vals):
record = super().create(vals)
if "name" in vals and vals["name"]:
existing_records = self.search([
("name", "=", vals["name"]),
("id", "!=", record.id)
])
if existing_records:
raise ValidationError(
f"仪表编号 '{vals['name']}' 已存在,请使用其他编号!"
)
return record
def open_record(self):
return {
"type": "ir.actions.act_window",
"res_model": "property.meter.water",
"res_id": self.id,
"view_mode": "form",
}
@api.depends("yuthon_property_ids.lessee_id")
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
def button_water_state(self):
water_ids = self.env["property.meter.water"].browse(
self._context.get("active_ids", self._context.get("active_id"))
)
for record in water_ids:
record.water_state = "stop"
def action_property_water_wizard(self):
return {
"type": "ir.actions.act_window",
"name": "批量导入物业水表",
"res_model": "property.water.wizard",
"view_mode": "form",
"target": "new",
}
def batch_reading_water_push(self):
active_ids = self._context.get("active_ids", [])
return {
"name": "电水表推送",
"type": "ir.actions.act_window",
"res_model": "electric.water.wizard",
"view_mode": "form",
"view_type": "form",
"target": "new",
"context": {"default_water_ids": [(6, 0, active_ids)]},
}
@api.constrains("yuthon_property_ids", "epitope_values_id")
def _constrains_property_water(self):
for record in self:
selected_properties = record.yuthon_property_ids
# 当没有选中物业时,删除所有关联的水表示细行并更新物业标记
if not selected_properties:
meters_to_remove = self.env['yuthon.property.water'].search([
('property_meter_water_id', '=', record.id),
])
if meters_to_remove:
related_properties = meters_to_remove.mapped('yuthon_property_id')
meters_to_remove.unlink()
# 更新物业的水表标记(检查是否还有其他水表关联)
for prop in related_properties:
prop.is_meter = bool(prop.water_meter_ids)
# 删除不在选中列表中的物业对应的明细行
all_meters = self.env['yuthon.property.water'].search([
('property_meter_water_id', '=', record.id),
])
# 筛选出已移除的物业对应的明细行
meters_to_remove = all_meters.filtered(
lambda m: m.yuthon_property_id not in selected_properties
)
if meters_to_remove:
related_properties = meters_to_remove.mapped('yuthon_property_id')
meters_to_remove.unlink()
# 更新物业的水表标记
for prop in related_properties:
prop.is_meter = bool(prop.water_meter_ids)
for prop in selected_properties:
existing_meter = self.env['yuthon.property.water'].search([
('property_meter_water_id', '=', record.id),
('yuthon_property_id', '=', prop.id)
], limit=1)
if not existing_meter:
self.env['yuthon.property.water'].create({
'property_meter_water_id': record.id,
'yuthon_property_id': prop.id,
})
prop.is_meter = bool(prop.water_meter_ids)
# 4同步更新关联的line_ids记录
if record.line_ids:
write_vals = {
'epitope_values_id': record.epitope_values_id.id,
'yuthon_property_ids': [(6, 0, selected_properties.ids)]
if selected_properties else [(5,)]
}
record.line_ids.write(write_vals)
def update_property(self):
reading_ids = self.env["property.meter.water"].browse(
self._context.get("active_ids", self._context.get("active_id"))
)
for record in reading_ids:
record.onchange_property()
class MeterWaterLine(models.Model):
_name = "meter.water.line"
_description = "水表库明细行"
_order = "number asc, sequence asc, last_meter asc"
# name = fields.Char(string='仪表编号')
is_acc = fields.Boolean(string="新租", default=False)
water_id = fields.Many2one("property.meter.water", string="水表库", required=True, ondelete="cascade")
initial_value = fields.Float(string="初始值")
number = fields.Integer(related="epitope_values_id.sequence", string="序号", store=True)
sequence = fields.Integer(related="water_id.sequence1", string="表序号", store=True)
epitope_values_id = fields.Many2one("yuthon.epitope.values", string="表位置")
lessee_id = fields.Many2one("property.tenant.information", string="承租方")
yuthon_property_ids = fields.Many2many("yuthon.property", string="物业信息")
last_meter = fields.Date(string="上次抄表日期", compute="_compute_last", store=True)
last_dosage = fields.Float(string="上次用量", store=True, group_operator=None, compute="_compute_last")
last_read = fields.Float(string="上次读数", group_operator=None, compute="_compute_last")
meter_date = fields.Date(string="任务日期")
meter_date_month = fields.Char(string="任务日期月份", index=True, copy=False)
current_meter = fields.Float(string="本次用量", group_operator=None, compute="_compute_current_meter")
current_read = fields.Float(string='本次读数', group_operator=None)
unit_number = fields.Char(string='单元编号/用途')
unit = fields.Float(string='当月单价', group_operator=None, digits=(16, 4))
line_loss = fields.Float(string="线损", default=0.05)
receivables = fields.Float(string="应收", store=True, help="应收金额=本次用量*单价*(1+线损)")
gauge_magnification = fields.Integer(string='仪表倍率', default=1)
last_reading_time = fields.Date(string="最后读数时间")
type = fields.Selection([("public", "公共"), ("fees", "收费")], string="类型")
water_state = fields.Selection([('stop', '停用'), ('use', '使用'), ('rent', '出租')], string='状态')
state = fields.Selection([('reading', '已抄'), ('unreading', '未抄')], string='抄表状态', default='unreading')
remarks = fields.Text(string='备注')
employee_ids = fields.Many2many('hr.employee', string='抄表人')
maximum_count = fields.Integer(string='最大位数')
is_fix_loss = fields.Selection([('yes', '是'), ('no', '否')], default="no", string="是否固定线损")
is_fix_price = fields.Selection([('yes', '是'), ('no', '否')], default="no", string="是否固定单价")
is_push = fields.Boolean(string='推送', default=False)
@api.model_create_multi
def create(self, vals_list):
records = super().create(vals_list)
for rec in records:
if rec.meter_date:
rec.meter_date_month = rec.meter_date.strftime("%Y-%m")
else:
rec.meter_date_month = fields.Date.today().strftime("%Y-%m")
return records
@api.depends('last_read', 'current_read')
def _compute_current_meter(self):
for record in self:
if record.current_read >= record.last_read:
record.current_meter = record.current_read - record.last_read
else:
if record.current_read:
if record.maximum_count > 0:
max_value = 10 ** record.maximum_count - 1
record.current_meter = max_value - record.last_read + record.current_read
else:
record.current_meter = 0
else:
record.current_meter = 0
def _compute_meter_date_month(self):
for rec in self:
if rec.meter_date:
rec.meter_date_month = rec.meter_date.strftime("%Y-%m")
else:
rec.meter_date_month = False
@api.onchange('current_meter', 'unit', 'line_loss')
def onchange_receivables(self):
for record in self:
# 因为current_meter 取不到值所有复制一遍
if record.current_read >= record.last_read:
current_meter = record.current_read - record.last_read
else:
if record.current_read:
if record.maximum_count > 0:
max_value = 10 ** record.maximum_count - 1
current_meter = max_value - record.last_read + record.current_read
else:
current_meter = 0
else:
current_meter = 0
if current_meter and record.unit:
raw_value = current_meter * record.unit * (1 + record.line_loss) * record.gauge_magnification
record.receivables = round(raw_value, 1)
else:
record.receivables = 0.0
def update_meter(self):
current_year = datetime.now().year
target_date = datetime(current_year, 9, 1).date()
domain = [("meter_date", "<", target_date)] # 任务日期在9月之前
active_ids = self._context.get("active_ids", self._context.get("active_id"))
if active_ids:
domain.append(("id", "in", active_ids))
unread_meter_lines = self.env["meter.water.line"].search(domain)
if unread_meter_lines:
unread_meter_lines.write({"state": "reading"})
@api.depends('water_id', 'last_dosage', 'last_read', 'last_meter', 'current_meter', 'current_read',
'maximum_count')
def _compute_last(self):
"""
上次用量,读数,超标日期
:return:
"""
for i in self:
last_id = self.env['meter.water.line'].search(
[('meter_date', '<', i.meter_date), ('water_id', '=', i.water_id.id)]).sorted('meter_date')
if last_id:
i.last_dosage = last_id[-1].current_meter
i.last_read = last_id[-1].current_read
i.last_meter = last_id[-1].meter_date
if i.current_read >= i.last_read:
i.current_meter = i.current_read - i.last_read
else:
if i.current_read != 0:
if i.maximum_count > 0:
max_value = 10 ** i.maximum_count - 1
i.current_meter = max_value - i.last_read + i.current_read
else:
i.current_meter = 0
else:
i.current_meter = 0
else:
i.last_read = i.initial_value
i.last_dosage = 0
i.last_meter = i.meter_date
i.current_meter = 0
@api.onchange('current_read', 'last_read', 'maximum_count')
def onchange_current_meter(self):
for record in self:
if record.last_read is not None and record.current_read is not None and record.last_read > 0:
if record.current_read < record.last_read:
if record.current_meter>= 10000:
raise ValidationError(
f"输入错误:当前读数 {record.current_read} 必须大于上次读数 {record.last_read} "
)
@api.onchange("yuthon_property_ids")
def onchange_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
def update_date(self):
meter_ids = self.env["meter.water.line"].browse(
self._context.get("active_ids", self._context.get("active_id"))
)
for meter_id in meter_ids:
meter_id.is_acc = False
def push_task_push_wizard(self):
water_ids = self.env["meter.water.line"].browse(
self._context.get("active_ids", self._context.get("active_id"))
)
for water_id in water_ids:
if water_id.is_push == True:
raise UserError(f"水表名为{water_id.archives_id}任务已推送,请勿重复推送")
return {
"name": "电水表任务",
"type": "ir.actions.act_window",
"res_model": "task.push.wizard",
"view_mode": "form",
"target": "new",
"context": {
"default_water_ids": water_ids.ids,
}
}