diff --git a/yuthon_hr_employee/views/inherit_hr_job_views.xml b/yuthon_hr_employee/views/inherit_hr_job_views.xml index 845d9b0d1..312856978 100644 --- a/yuthon_hr_employee/views/inherit_hr_job_views.xml +++ b/yuthon_hr_employee/views/inherit_hr_job_views.xml @@ -82,7 +82,7 @@ 1 - + diff --git a/yuthon_report/models/ledger_report.py b/yuthon_report/models/ledger_report.py index e61bc790e..497005e9f 100644 --- a/yuthon_report/models/ledger_report.py +++ b/yuthon_report/models/ledger_report.py @@ -1,4 +1,5 @@ import datetime +import calendar from odoo import fields, models, api @@ -8,115 +9,101 @@ class YuthonProperty(models.Model): @api.model def get_complete_ledger_report(self, params): - domain = [('purpose_id.name', '=', '可租')] - # if params.get("date_start"): - # date_start = datetime.datetime.fromisoformat(params.get("date_start")).date() - # domain.append(("due_date", ">=", date_start)) - # if params.get("date_end"): - # date_end = datetime.datetime.fromisoformat(params.get("date_end")).date() - # domain.append(("due_date", "<=", date_end)) + """ + 物业台账报表(按查询月) + - 管理面积:manage_information_ids 中 end_date >= 查询月最后一天(或 end_date 为空)且 start_time <= 查询月最后一天 的最新行的 management_area + - 可租面积:同上,purpose_id.name == '可租' 的行的 rent_area + - 不可租面积:同上,purpose_id.name != '可租' 的行的 management_area + - 已租面积(物业):查询月内有执行中合同(actual_end_time >= 查询月底)的物业的可租面积 + - 空置面积:管理类型为可租,但查询月内无执行中合同的物业的可租面积 + """ + # 解析查询月 + date_start_str = params.get("date_start") + if date_start_str: + query_date = datetime.datetime.fromisoformat(date_start_str).date() + else: + query_date = datetime.date.today().replace(day=1) + # 查询月底最后一天 + last_day = calendar.monthrange(query_date.year, query_date.month)[1] + month_end = query_date.replace(day=last_day) + # 查询月第一天 + month_start = query_date.replace(day=1) + + # 基础过滤条件 condition = params.get('condition', False) partner_id = params.get('partner_id', False) company_id = params.get('company_id', False) - management_type_id = params.get('management_type_id', False) + domain = [] if condition: domain.append(('tenure_type', '=', condition)) - if partner_id: domain.append(('precinct_id', '=', partner_id)) if company_id: domain.append(('company_id', '=', company_id)) - if management_type_id: - domain.append(('management_type_id', '=', management_type_id)) + properties = self.search(domain, limit=500) + + # 查询月内有执行中合同的物业 id 集合 + # 合同 actual_end_time >= 查询月底 且 contact_state == 'ing' + active_contracts = self.env['property.lease.contract'].search([ + ('contact_state', '=', 'ing'), + ('actual_end_time', '>=', month_end), + ]) + rented_property_ids = set() + for contract in active_contracts: + for line in contract.lease_ids: + if line.address_id: + rented_property_ids.add(line.address_id.id) - properties = self.search(domain, limit=100) result = [] - - if partner_id: - admin_properties = self.env['yuthon.property'].search([ - ('precinct_id', '=', partner_id), - ]) - # 统计管理员下总面积 - total_rentable_area = sum( - prop.rent_area for prop in admin_properties - if prop.property_state == 'on_rent' and prop.rent_area - ) - # 统计管理员下所有空置面积 - total_vacant_area = sum( - prop.rent_area for prop in admin_properties - if prop.property_state == 'vacant' and prop.rent_area - ) - if total_rentable_area > 0: - rental_rate = round(((total_rentable_area - total_vacant_area) / total_rentable_area) * 100, 2) - - admin_contracts = self.env['property.lease.contract'].search([ - ('precinct_id', '=', partner_id), - ('contact_state', '=', 'ing') - ]) - - if admin_contracts: - receivable_domain = [ - ('contract_id', 'in', admin_contracts.ids), - ] - if params.get("date_end"): - date_end = datetime.datetime.fromisoformat(params.get("date_end")).date() - receivable_domain.append(('due_date', '<=', date_end)) - receivable_records = self.env['property.accounts.receivable'].search(receivable_domain) - if receivable_records: - total_delivered = sum(rec.delivered1 for rec in receivable_records) # 已交金额 - total_amount = sum(rec.original_amount for rec in receivable_records) # 当期金额 - if total_amount > 0: - collection_rate = round((total_delivered / total_amount) * 100, 2) - else: - collection_rate = 0.0 - else: - collection_rate = 0.0 - else: - collection_rate = 0.0 - else: - rental_rate = 0.0 - collection_rate = 0.0 - for p in properties: - if params.get("date_end"): - date_end = datetime.datetime.fromisoformat(params.get("date_end")).date() - valid_info = p.manage_information_ids.filtered( - lambda info: info.start_time <= date_end and - (not info.end_date or info.end_date >= date_end) - ) - else: - valid_info = p.manage_information_ids[-1] - management_area = valid_info.management_area if valid_info else 0 - rent_area = valid_info.rent_area if valid_info else 0 - lease_id = self.env['property.lease.contract.line'].search([ - ('address_id', '=', p.id), - ('lease_id.contact_state', '=', 'ing') - ], limit=1) - if lease_id: - contract_id = lease_id.lease_id - else: - contract_id = False + # 从 manage_information_ids 按查询月筛选有效行 + # 有效条件:start_time <= 月底 且 (end_date 为空 或 end_date >= 月底) + valid_lines = p.manage_information_ids.filtered( + lambda l: (not l.start_time or l.start_time <= month_end) and + (not l.end_date or l.end_date >= month_end) + ) - if p.property_state == 'on_rent': - leased_area = rent_area + if not valid_lines: + continue + + # 取最新一条(start_time 最大的) + current_line = sorted(valid_lines, key=lambda l: l.start_time or datetime.date.min, reverse=True)[0] + + purpose_name = current_line.purpose_id.name if current_line.purpose_id else '' + management_area = current_line.management_area or 0.0 + rent_area = current_line.rent_area or 0.0 if purpose_name == '可租' else 0.0 + non_rentable_area = management_area if purpose_name != '可租' else 0.0 + + is_rented = p.id in rented_property_ids + if purpose_name == '可租': + rented_area = rent_area if is_rented else 0.0 + vacant_area = rent_area if not is_rented else 0.0 else: - leased_area = 0.0 + rented_area = 0.0 + vacant_area = 0.0 + + # 查询月内的执行中合同 + contract_line = self.env['property.lease.contract.line'].search([ + ('address_id', '=', p.id), + ('lease_id.contact_state', '=', 'ing'), + ('lease_id.actual_end_time', '>=', month_end), + ], limit=1) + contract_id = contract_line.lease_id if contract_line else False result.append({ "物业名称": p.name or "", - "用途": p.asset_type_id.name, - "产权证号": p.title_deed, + "用途": purpose_name, + "产权证号": p.title_deed or "", "产权面积": p.equity_area or 0.0, - "管理面积": management_area or 0.0, - "可租面积": rent_area or 0.0, - "已租面积": leased_area or 0.0, - "出租率": rental_rate , - "收费率": collection_rate, - "所属公司": contract_id.lessor_id.referred if contract_id else "", - "租赁状态": "在租" if p.property_state == 'on_rent' else "空置" if p.property_state == 'vacant' else "", + "管理面积": round(management_area, 4), + "可租面积": round(rent_area, 4), + "不可租面积": round(non_rentable_area, 4), + "已租面积": round(rented_area, 4), + "空置面积": round(vacant_area, 4), + "租赁状态": "在租" if is_rented else ("空置" if purpose_name == '可租' else ""), "合同编号": { 'model': 'property.lease.contract', 'id': contract_id.id, @@ -129,7 +116,8 @@ class YuthonProperty(models.Model): } if contract_id and contract_id.lessee_id else "", "单价": contract_id.unit_price if contract_id else 0, "租金": contract_id.rent if contract_id else 0, - "管理员": p.admin_id.name, + "所属公司": current_line.company_id.name if current_line.company_id else "", + "管理员": current_line.admin_id.name if current_line.admin_id else "", }) - return result \ No newline at end of file + return result diff --git a/yuthon_report/views/ledger_report_views.xml b/yuthon_report/views/ledger_report_views.xml index 84a53c761..b42419d80 100644 --- a/yuthon_report/views/ledger_report_views.xml +++ b/yuthon_report/views/ledger_report_views.xml @@ -10,21 +10,22 @@ "report_config": { "model": "yuthon.property", "method": "get_complete_ledger_report", + "dateMode": "single", "columns": [ - {"headerName": "物业名称", "field": "物业名称", "flex": 1}, - {"headerName": "用途", "field": "用途", "flex": 1}, - {"headerName": "产权证号", "field": "产权证号", "flex": 1}, - {"headerName": "产权面积", "field": "产权面积", "flex": 1}, - {"headerName": "管理面积", "field": "管理面积", "flex": 1}, - {"headerName": "可租面积", "field": "可租面积", "flex": 1}, - {"headerName": "已租面积", "field": "已租面积", "flex": 1}, - {"headerName": "出租率", "field": "出租率", "flex": 1}, - {"headerName": "收费率", "field": "收费率", "flex": 1}, - {"headerName": "租赁状态", "field": "租赁状态", "flex": 1}, - {"headerName": "合同编号", "field": "合同编号", "flex": 1}, - {"headerName": "承租方", "field": "承租方", "flex": 1}, - {"headerName": "单价", "field": "单价", "flex": 1}, - {"headerName": "租金", "field": "租金", "flex": 1}, + {"headerName": "物业名称", "field": "物业名称", "flex": 2}, + {"headerName": "用途", "field": "用途", "flex": 0.8}, + {"headerName": "产权证号", "field": "产权证号", "flex": 1.2}, + {"headerName": "产权面积", "field": "产权面积", "flex": 1, "type": "number"}, + {"headerName": "管理面积", "field": "管理面积", "flex": 1, "type": "number"}, + {"headerName": "可租面积", "field": "可租面积", "flex": 1, "type": "number"}, + {"headerName": "不可租面积", "field": "不可租面积", "flex": 1, "type": "number"}, + {"headerName": "已租面积", "field": "已租面积", "flex": 1, "type": "number"}, + {"headerName": "空置面积", "field": "空置面积", "flex": 1, "type": "number"}, + {"headerName": "租赁状态", "field": "租赁状态", "flex": 0.8}, + {"headerName": "合同编号", "field": "合同编号", "flex": 1.2}, + {"headerName": "承租方", "field": "承租方", "flex": 1.2}, + {"headerName": "单价", "field": "单价", "flex": 0.8, "type": "number"}, + {"headerName": "租金", "field": "租金", "flex": 0.8, "type": "number"}, {"headerName": "所属公司", "field": "所属公司", "flex": 1}, {"headerName": "管理员", "field": "管理员", "flex": 1} ]