389 lines
17 KiB
Python
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,
|
|
}
|
|
}
|
|
|
|
|