86 lines
4.3 KiB
Python
86 lines
4.3 KiB
Python
# -*- coding: utf-8 -*-
|
|
from odoo import fields, models, tools
|
|
|
|
|
|
class PropertyAccountsReceivableSummary(models.Model):
|
|
"""应收账单未收汇总(按合同)—— 一行一个合同,聚合各应收类型未收金额。
|
|
|
|
采用 PostgreSQL 视图 + _auto=False 模型:视图实时按合同聚合,
|
|
无需定时任务同步,web 列表 / searchpanel / read_group 全部走标准 ORM。
|
|
"""
|
|
_name = 'property.accounts.receivable.summary'
|
|
_description = '应收账单未收汇总(按合同)'
|
|
_auto = False
|
|
_order = 'id desc'
|
|
|
|
contract_id = fields.Many2one('property.lease.contract', string='合同')
|
|
property_name = fields.Text(string='物业地址')
|
|
admin_id = fields.Many2one('res.users', string='片区管理员')
|
|
|
|
rent_unpaid = fields.Float(string='租金')
|
|
management_unpaid = fields.Float(string='管理费')
|
|
water_unpaid = fields.Float(string='水费')
|
|
electricity_unpaid = fields.Float(string='电费')
|
|
penalty_unpaid = fields.Float(string='违约金')
|
|
deposit_unpaid = fields.Float(string='押金')
|
|
lightbox_unpaid = fields.Float(string='灯箱')
|
|
other_unpaid = fields.Float(string='其他')
|
|
|
|
# 7 个单独展示的类型(灯箱单独一列);其余类型(广告灯箱费/有偿服务收入/停车费/管子间/
|
|
# 更名费/维修费/其他费用/评估费/保险费,以及以后新增的类型)全部归入「其他」
|
|
_SUMMARY_TYPES = ['租金', '管理费', '水费', '电费', '违约金', '押金', '灯箱']
|
|
|
|
def init(self):
|
|
tools.drop_view_if_exists(self.env.cr, self._table)
|
|
main_cols = ""
|
|
for fname, tname in [
|
|
('rent_unpaid', '租金'), ('management_unpaid', '管理费'), ('water_unpaid', '水费'),
|
|
('electricity_unpaid', '电费'), ('penalty_unpaid', '违约金'), ('deposit_unpaid', '押金'),
|
|
('lightbox_unpaid', '灯箱'),
|
|
]:
|
|
main_cols += "\n COALESCE(SUM(CASE WHEN t.name = '%s' THEN r.submitted ELSE 0.0 END), 0.0) AS %s," % (tname, fname)
|
|
excluded = ", ".join("'%s'" % t for t in self._SUMMARY_TYPES)
|
|
self.env.cr.execute("""
|
|
CREATE OR REPLACE VIEW %(table)s AS (
|
|
SELECT
|
|
r.contract_id AS id,
|
|
r.contract_id AS contract_id,
|
|
c.use_address AS property_name,
|
|
c.admin_id AS admin_id,%(main_cols)s
|
|
COALESCE(SUM(CASE WHEN t.name NOT IN (%(excluded)s) THEN r.submitted ELSE 0.0 END), 0.0) AS other_unpaid
|
|
FROM property_accounts_receivable r
|
|
LEFT JOIN property_lease_contract c ON c.id = r.contract_id
|
|
LEFT JOIN yuthon_management_type t ON t.id = r.management_type_id
|
|
WHERE r.contract_id IS NOT NULL
|
|
AND r.deposit_state IN ('unpaid', 'no_paid')
|
|
AND COALESCE(r.is_reconciliation, false) = false
|
|
GROUP BY r.contract_id, c.use_address, c.admin_id
|
|
HAVING COALESCE(SUM(r.submitted), 0) > 0
|
|
)
|
|
""" % {'table': self._table, 'main_cols': main_cols, 'excluded': excluded})
|
|
|
|
def action_open_unpaid_detail(self):
|
|
"""未收明细:打开该合同下 未收/收部分 且 未对账 的应收账单,
|
|
复用 view_property_accounts_receivable_tree,不做分组,按应收类型倒序"""
|
|
self.ensure_one()
|
|
tree_view = self.env.ref('yuthon_property.view_property_accounts_receivable_tree')
|
|
search_view = self.env.ref('yuthon_property_approval.view_property_accounts_receivable_search')
|
|
return {
|
|
'name': '未收明细 - %s' % (self.contract_id.display_name or ''),
|
|
'type': 'ir.actions.act_window',
|
|
'res_model': 'property.accounts.receivable',
|
|
'view_mode': 'tree',
|
|
'view_id': tree_view.id,
|
|
# 前端要求 search_view_id 为 [id, name] 列表格式,纯 int 会被忽略而回落到默认 search 视图
|
|
'search_view_id': [search_view.id, search_view.name],
|
|
'domain': [
|
|
('contract_id', '=', self.contract_id.id),
|
|
('deposit_state', 'in', ['unpaid', 'no_paid']),
|
|
('is_reconciliation', '=', False),
|
|
],
|
|
'context': {
|
|
'order': 'management_type_id desc',
|
|
},
|
|
'target': 'current',
|
|
}
|