From e2ef33b58f838997073249c69f70cf11a43ccd07 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=B9=8F=E5=AE=87?= Date: Fri, 18 Sep 2026 19:05:55 +0800 Subject: [PATCH] =?UTF-8?q?=E9=80=80=E7=A7=9F=E8=A1=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- yuthon_property_approval/models/__init__.py | 2 + .../models/property_tenant_checkout.py | 111 ++++++++---- .../models/property_tenant_checkout_fee.py | 18 ++ .../property_tenant_checkout_inspection.py | 18 ++ .../property_tenant_checkout_template.xml | 158 +++++++++++------- .../security/ir.model.access.csv | 4 +- .../views/property_lease_contract.xml | 2 + .../views/property_tenant_checkout_views.xml | 148 ++++++++++------ 8 files changed, 318 insertions(+), 143 deletions(-) create mode 100644 yuthon_property_approval/models/property_tenant_checkout_fee.py create mode 100644 yuthon_property_approval/models/property_tenant_checkout_inspection.py diff --git a/yuthon_property_approval/models/__init__.py b/yuthon_property_approval/models/__init__.py index 7e1238066..53b3834c6 100644 --- a/yuthon_property_approval/models/__init__.py +++ b/yuthon_property_approval/models/__init__.py @@ -66,3 +66,5 @@ from . import property_fee_form from . import receivable_modify_line from . import yuthon_property_task from . import property_tenant_checkout +from . import property_tenant_checkout_inspection +from . import property_tenant_checkout_fee diff --git a/yuthon_property_approval/models/property_tenant_checkout.py b/yuthon_property_approval/models/property_tenant_checkout.py index 81c0bc4c2..c1da1b939 100644 --- a/yuthon_property_approval/models/property_tenant_checkout.py +++ b/yuthon_property_approval/models/property_tenant_checkout.py @@ -1,12 +1,14 @@ # -*- coding: utf-8 -*- # Part of Odoo. See LICENSE file for full copyright and licensing details. -from odoo import models, fields, api, exceptions, _ +from odoo import models, fields, api from odoo.exceptions import UserError class PropertyTenantCheckout(models.Model): - """租户退租表:物业客户服务中心与财务部联合验收结算的审批单(纯自由录入,不关联合同/承租方)""" + """租户退租表:物业客户服务中心检查、租户签字、财务结算的多节点审批单。 + 各节点可见内容由工作流 state 字段驱动(form 视图按 state 显隐分组), + 节点与按钮在工作流里配置,本模型只管字段与数据。""" _name = 'property.tenant.checkout' _description = '租户退租表' _inherit = ['mail.thread.main.attachment', 'mail.activity.mixin', 'soong.workflow.mixin'] @@ -27,44 +29,63 @@ class PropertyTenantCheckout(models.Model): active = fields.Boolean('Active', default=True, tracking=True) # 归档标记 work_end = fields.Boolean(string="结束") # 流程是否结束 - document_ids = fields.Many2many('ir.attachment', string="附件") # 附件 + document_ids = fields.Many2many('ir.attachment', 'property_tenant_checkout_document_rel', + 'checkout_id', 'attachment_id', string="附件") # 附件 - # ===== 表头信息(纯自由录入)===== - tenant_unit = fields.Char(string='租户单元') # 如:4F东边01单元 - company_name = fields.Char(string='公司名称') # 承租方公司名称 + # ===== 关联租赁合同 ===== + contract_id = fields.Many2one('property.lease.contract', string='关联租赁合同') # 从合同列表「退租」按钮发起时自动带入 + + # ===== 合同信息(关联后自动带出,只读参考)===== + tenant_unit = fields.Char(string='租户单元') # 如:4F东边01单元(关联合同后自动带出,可改) + lessee_id = fields.Many2one(related='contract_id.lessee_id', string='承租方', readonly=True) # 承租方(关联合同自动带出) + contract_code = fields.Char(related='contract_id.contract_code', string='合同编号', readonly=True) # 合同编号 + lessor_id = fields.Many2one(related='contract_id.lessor_id', string='出租方公司', readonly=True) # 出租方 + contract_term_start = fields.Date(related='contract_id.term_start_time', string='合同开始', readonly=True) # 合同期限起 + contract_term_end = fields.Date(related='contract_id.term_end_time', string='合同结束', readonly=True) # 合同期限止 + deposit_amount = fields.Float(related='contract_id.deposit', string='合同保证金', readonly=True) # 合同保证金 + rent_address = fields.Char(string='租赁地址') # 租赁地址(关联合同后自动带出,可改) + + # ===== 节点一:发起申请 ===== checkout_deadline = fields.Date(string='退租截止日期') # 退租截止日期 - handler = fields.Char(string='经办人') # 经办人 + contract_handle_type = fields.Selection([ + ('checkout', '退租'), ('renew', '续租'), ('transfer', '转租'), ('other', '其他') + ], string='合同办理方式', default='checkout') # 合同办理方式 + checkout_reason = fields.Text(string='退租原因') # 退租原因 + other_note = fields.Text(string='其它(补充说明)') # 其它补充说明 - # ===== 客户服务中心 ===== - contract_handling = fields.Char(string='合同办理') # 合同办理说明 - contract_expiry = fields.Date(string='合同到期') # 合同到期日 - other_note = fields.Text(string='其它说明') # 其它说明(如保证金退回说明) - air_conditioner = fields.Char(string='空调机') # 空调机验收备注 - light_tube = fields.Char(string='光管') # 光管验收备注 - interior_decor = fields.Char(string='室内装修') # 室内装修验收备注 - other_equipment = fields.Char(string='其它设备') # 其它设备验收备注 - retrieve_keys = fields.Char(string='收回钥匙') # 收回钥匙验收备注 - electric_meter = fields.Char(string='电表') # 电表验收备注 - engineering_group = fields.Char(string='工程组') # 工程组 - center_person_in_charge = fields.Char(string='负责人') # 客户服务中心负责人 - inspection_date = fields.Date(string='验收日期') # 客户服务中心验收日期 + # ===== 节点二:工程组检查与确认 ===== + inspection_ids = fields.One2many('property.tenant.checkout.inspection', 'checkout_id', string='物业检查项') # 物业检查项明细 + site_photo = fields.Many2many('ir.attachment', 'property_tenant_checkout_site_photo_rel', + 'checkout_id', 'attachment_id', string='现场照片') # 现场照片 + engineering_sign = fields.Binary(string='工程组检查确认签字') # 工程组检查确认签字(PNG) + handler = fields.Char(string='经办人') # 经办人(工程组) - # ===== 租户签字 ===== - tenant_sign_date = fields.Date(string='租户签字日期') # 租户签字确认日期 - tenant_signature = fields.Binary(string='租户电子签名') # 租户电子签名(PNG 图片,存手绘/打字/上传的签名) + # ===== 节点三:租户签字确认 ===== + result_summary = fields.Text(string='结果摘要') # 退租结果摘要 + tenant_signature = fields.Binary(string='租户电子签名') # 租户电子签名(PNG:手绘/打字/上传) + signer_name = fields.Char(string='签字人姓名') # 签字人姓名 + tenant_sign_date = fields.Date(string='签字确认日期') # 签字确认日期 - # ===== 财务部 ===== - rent_fee = fields.Char(string='房租') # 房租 - management_fee = fields.Char(string='管理费') # 管理费 - phone_fee = fields.Char(string='电话费') # 电话费 - utility_fee = fields.Char(string='水、电费') # 水、电费 - other_fee = fields.Char(string='其它费用') # 其它费用 - settlement = fields.Char(string='结算') # 结算 + # ===== 节点四:费用结算与复核 ===== + fee_ids = fields.One2many('property.tenant.checkout.fee', 'checkout_id', string='应收费用明细') # 应收费用明细 + total_fee = fields.Float(string='应收合计', compute='_compute_total_fee', store=True) # 应收费用合计(自动求和) + deposit_treatment = fields.Selection([ + ('full', '退还全额'), ('part', '部分退还'), ('none', '不退还') + ], string='保证金处理方式') # 保证金处理方式 + settlement_sign = fields.Binary(string='结算复核签字') # 结算复核签字(PNG) + + # ===== 节点五:财务处理 ===== finance_handler = fields.Char(string='财务部经办人') # 财务部经办人 finance_reviewer = fields.Char(string='复核人') # 复核人 finance_person_in_charge = fields.Char(string='财务部负责人') # 财务部负责人 finance_date = fields.Date(string='财务日期') # 财务部日期 + @api.depends('fee_ids', 'fee_ids.amount') + def _compute_total_fee(self): + """应收合计 = 所有费用明细金额之和""" + for rec in self: + rec.total_fee = sum(line.amount for line in rec.fee_ids) + @api.onchange('tenant_signature') def _onchange_tenant_signature(self): """签名后自动填写签字日期;清除签名则清空日期(仅记录、不强制)""" @@ -73,9 +94,37 @@ class PropertyTenantCheckout(models.Model): else: self.tenant_sign_date = False # 无签名则清空日期 + @api.onchange('contract_id') + def _onchange_contract_id(self): + """关联合同后自动带出公司名称/物业信息/租赁地址(可再手工修改);其余信息以 related 只读展示""" + if self.contract_id: + self.tenant_unit = self.contract_id.property_name # 租户单元=合同物业信息 + # 租赁地址=合同物业明细首行对应的物业地址名称(无物业明细则为空) + self.rent_address = self.contract_id.lease_ids[:1].address_id.name + def action_print_tenant_checkout(self): """打印租户退租表""" self.ensure_one() - # 调用报表动作生成 PDF report = self.env.ref('yuthon_property_approval.action_property_tenant_checkout_report') return report.report_action(self) + + +class PropertyLeaseContract(models.Model): + """在租赁合同上增加「退租」入口:从合同列表直接发起租户退租表""" + _inherit = 'property.lease.contract' + + def action_tenant_checkout(self): + """合同列表「退租」按钮:打开租户退租表并自动关联当前合同""" + self.ensure_one() + return { + 'name': '租户退租表', + 'type': 'ir.actions.act_window', + 'res_model': 'property.tenant.checkout', + 'view_mode': 'form', + 'target': 'current', + 'context': { + 'default_contract_id': self.id, # 关联当前合同 + 'default_tenant_unit': self.property_name, # 带出租户单元(物业信息) + 'default_rent_address': self.lease_ids[:1].address_id.name, # 带出租赁地址(物业地址名称) + }, + } diff --git a/yuthon_property_approval/models/property_tenant_checkout_fee.py b/yuthon_property_approval/models/property_tenant_checkout_fee.py new file mode 100644 index 000000000..17f6c6e10 --- /dev/null +++ b/yuthon_property_approval/models/property_tenant_checkout_fee.py @@ -0,0 +1,18 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. + +from odoo import models, fields + + +class PropertyTenantCheckoutFee(models.Model): + """租户退租表-应收费用明细(费用结算阶段的可增删明细行)""" + _name = 'property.tenant.checkout.fee' + _description = '租户退租表-应收费用明细' + _order = 'sequence, id' + + checkout_id = fields.Many2one('property.tenant.checkout', string='退租表', ondelete='cascade') # 关联退租表 + sequence = fields.Integer(string='序号', default=10) # 排序 + item = fields.Char(string='费用项') # 费用项名称(租金/管理费/电费/电话费/水费/其它) + amount = fields.Float(string='金额') # 金额 + period = fields.Char(string='所属周期') # 费用所属周期 + remark = fields.Text(string='说明') # 说明 diff --git a/yuthon_property_approval/models/property_tenant_checkout_inspection.py b/yuthon_property_approval/models/property_tenant_checkout_inspection.py new file mode 100644 index 000000000..e036ee2da --- /dev/null +++ b/yuthon_property_approval/models/property_tenant_checkout_inspection.py @@ -0,0 +1,18 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. + +from odoo import models, fields + + +class PropertyTenantCheckoutInspection(models.Model): + """租户退租表-物业检查项(工程组检查阶段的可增删明细行)""" + _name = 'property.tenant.checkout.inspection' + _description = '租户退租表-物业检查项' + _order = 'sequence, id' + + checkout_id = fields.Many2one('property.tenant.checkout', string='退租表', ondelete='cascade') # 关联退租表 + sequence = fields.Integer(string='序号', default=10) # 排序 + item = fields.Char(string='检查项') # 检查项名称 + status = fields.Selection([('normal', '正常'), ('abnormal', '异常')], string='状态', default='normal') # 正常/异常 + note = fields.Text(string='批注') # 批注说明 + repair_fee = fields.Float(string='维修费') # 维修费金额 diff --git a/yuthon_property_approval/report/property_tenant_checkout_template.xml b/yuthon_property_approval/report/property_tenant_checkout_template.xml index b6a84ae59..389055df9 100644 --- a/yuthon_property_approval/report/property_tenant_checkout_template.xml +++ b/yuthon_property_approval/report/property_tenant_checkout_template.xml @@ -44,57 +44,70 @@ 租户单元 - 公司名称 - + 承租方 + + + + 合同编号 + + 出租方 + + + + 合同期限 + + + ~ + + 合同保证金 + + + + 租赁地址 + 退租截止日期 - 经办人 - - - - - - 客户服务中心 + 合同办理方式 + - 合同办理 - - 合同到期 - + 退租原因 + - 其它说明 + 其它(补充说明) + + - 空调机 - - 光管 - + 工程组检查与确认 + + + 检查项 + 状态 + 批注 + 维修费 + + + + + + + + + + - 室内装修 - - 其它设备 - - - - 收回钥匙 - - 电表 - - - - 工程组 - - 负责人 - - - - 验收日期 - + 经办人 + + 工程组确认签字 + + + @@ -102,49 +115,68 @@ 租户签字确认 - 租户签字日期 - + 结果摘要 + 租户电子签名 - - + + 签字人/日期 + + + + - + - 财务部 + 费用结算与复核 + + + + 费用项 + 金额 + 所属周期 + 说明 + + + + + + + + + + + + 应收合计 + + 保证金处理 + - 房租 - - 管理费 - + 结算复核签字 + + + + + + + + 财务处理 - 电话费 - - 水、电费 - - - - 其它费用 - - 结算 - - - - 经办人 + 财务部经办人 复核人 - 负责人 + 财务部负责人 - 日期 + 财务日期 diff --git a/yuthon_property_approval/security/ir.model.access.csv b/yuthon_property_approval/security/ir.model.access.csv index 21c08b4bf..e45756e5d 100644 --- a/yuthon_property_approval/security/ir.model.access.csv +++ b/yuthon_property_approval/security/ir.model.access.csv @@ -146,4 +146,6 @@ access_property_payment_type,property_payment_type,model_property_payment_type,b access_property_contract_rental_wizard,property_contract_rental_wizard,model_property_contract_rental_wizard,base.group_user,1,1,1,1 access_yuthon_property_task,yuthon_property_task,model_yuthon_property_task,base.group_user,1,1,1,1 access_yuthon_property_task_confirm,yuthon_property_task_confirm,model_yuthon_property_task_confirm,base.group_user,1,1,1,1 -access_property_tenant_checkout,property_tenant_checkout,model_property_tenant_checkout,base.group_user,1,1,1,1 \ No newline at end of file +access_property_tenant_checkout,property_tenant_checkout,model_property_tenant_checkout,base.group_user,1,1,1,1 +access_property_tenant_checkout_inspection,property_tenant_checkout_inspection,model_property_tenant_checkout_inspection,base.group_user,1,1,1,1 +access_property_tenant_checkout_fee,property_tenant_checkout_fee,model_property_tenant_checkout_fee,base.group_user,1,1,1,1 \ No newline at end of file diff --git a/yuthon_property_approval/views/property_lease_contract.xml b/yuthon_property_approval/views/property_lease_contract.xml index 4165f5be1..77023c263 100644 --- a/yuthon_property_approval/views/property_lease_contract.xml +++ b/yuthon_property_approval/views/property_lease_contract.xml @@ -482,6 +482,8 @@