@@ -7,8 +7,8 @@
|
||||
<tree string="财务数据表项目配置" editable="bottom">
|
||||
<field name="sequence"/>
|
||||
<field name="name"/>
|
||||
<field name="employee_ids" widget="many2many_tags"/>
|
||||
<field name="user_role_ids" widget="many2many_tags"/>
|
||||
<field name="employee_ids" widget="many2many_tags" options="{'no_create': True}"/>
|
||||
<field name="user_role_ids" widget="many2many_tags" options="{'no_create': True}"/>
|
||||
<field name="start_date"/>
|
||||
<field name="end_date"/>
|
||||
<field name="is_enable"/>
|
||||
@@ -27,8 +27,8 @@
|
||||
<tree string="信息汇总表项目配置" editable="bottom">
|
||||
<field name="sequence"/>
|
||||
<field name="name"/>
|
||||
<field name="employee_ids" widget="many2many_tags"/>
|
||||
<field name="user_role_ids" widget="many2many_tags"/>
|
||||
<field name="employee_ids" widget="many2many_tags" options="{'no_create': True}"/>
|
||||
<field name="user_role_ids" widget="many2many_tags" options="{'no_create': True}"/>
|
||||
<field name="start_date"/>
|
||||
<field name="end_date"/>
|
||||
<field name="is_enable"/>
|
||||
|
||||
@@ -47,6 +47,17 @@ class PropertyBankStatements(models.Model):
|
||||
change_amount = fields.Float(string='修改金额')
|
||||
receivable_modify_ids = fields.One2many('receivable.modify.line', 'bank_id', string='修改应收单')
|
||||
|
||||
@api.onchange('extract')
|
||||
def _onchange_extract_set_bank_state(self):
|
||||
for rec in self:
|
||||
if rec.extract and '结息' in rec.extract:
|
||||
rec.bank_state = 'other'
|
||||
|
||||
@api.onchange('remake')
|
||||
def _onchange_remake_set_bank_state(self):
|
||||
for rec in self:
|
||||
if rec.remake and '党费' in rec.remake:
|
||||
rec.bank_state = 'other'
|
||||
|
||||
@api.depends('yes_amount', 'original_amount')
|
||||
def _compute_no_amount(self):
|
||||
|
||||
@@ -209,6 +209,7 @@ class PropertyLeaseContract(models.Model):
|
||||
number = fields.Integer(string="次数", default=0)
|
||||
total_area = fields.Float(string="总面积", digits=(16, 4))
|
||||
not_received = fields.Float(string="未收", compute="_compute_contract_count")
|
||||
month_received = fields.Float(string="本月已收")
|
||||
actual_receivable = fields.Float(string="实际应收")
|
||||
now_receivable = fields.Float(string="当期应收")
|
||||
total_receivable = fields.Float(string="总已收")
|
||||
|
||||
@@ -584,7 +584,7 @@ class PropertyReconciliationWizard(models.Model):
|
||||
})
|
||||
|
||||
if existing_record:
|
||||
receivable_id = existing_record.id
|
||||
receivable_id = existing_record
|
||||
self.env['receivable.modify.line'].create({
|
||||
'bank_id': rec.bank_id.id,
|
||||
'not_collected': line.rent,
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
'views/ledger_report_views.xml',
|
||||
'views/receivable_report_views.xml',
|
||||
'views/receivables_message_report_views.xml',
|
||||
'views/yuthon_contract_report_views.xml',
|
||||
'views/yuthon_report_res_partner.xml',
|
||||
],
|
||||
'installable': True,
|
||||
@@ -33,6 +34,8 @@
|
||||
|
||||
'yuthon_report/static/src/components/yuthon_report/yuthon_report.js',
|
||||
'yuthon_report/static/src/components/yuthon_report/yuthon_report.xml',
|
||||
'yuthon_report/static/src/components/yuthon_report/yuthon_contract_report.js',
|
||||
'yuthon_report/static/src/components/yuthon_report/yuthon_contract_report.xml',
|
||||
'yuthon_report/static/src/components/yuthon_report/receivable_message_report.js',
|
||||
'yuthon_report/static/src/components/yuthon_report/receivable_message.xml',
|
||||
'yuthon_report/static/src/components/yuthon_report/yuthon_report.scss',
|
||||
|
||||
@@ -2,4 +2,5 @@
|
||||
from . import res_partner
|
||||
from . import ledger_report
|
||||
from . import receivable_report
|
||||
from . import receivables_message_report
|
||||
from . import receivables_message_report
|
||||
from . import yuthon_contract_report
|
||||
@@ -0,0 +1,81 @@
|
||||
import datetime
|
||||
|
||||
from odoo import fields, models, api
|
||||
|
||||
|
||||
class YuthonContractReport(models.Model):
|
||||
_inherit = 'property.lease.contract'
|
||||
_description = '合同信息报表'
|
||||
|
||||
|
||||
@api.model
|
||||
def get_contract_info_report(self, params):
|
||||
"""
|
||||
生成合同信息报表
|
||||
:param params: 筛选参数(keyword/date_start/date_end/company_id/manager_id等)
|
||||
:return: 合同信息列表
|
||||
"""
|
||||
domain = []
|
||||
if params.get("date_start"):
|
||||
date_start = datetime.datetime.fromisoformat(params.get("date_start")).date()
|
||||
domain.append(("actual_start_time", ">=", date_start))
|
||||
if params.get("date_end"):
|
||||
date_end = datetime.datetime.fromisoformat(params.get("date_end")).date()
|
||||
domain.append(("actual_end_time", "<=", date_end))
|
||||
|
||||
if params.get('lessor_id'):
|
||||
domain.append(('lessor_id', '=', params['lessor_id']))
|
||||
if params.get("precinct_id"):
|
||||
domain.append(("precinct_id", "=", params.get("precinct_id")))
|
||||
|
||||
contracts = self.search(domain, limit=1000)
|
||||
report_data = []
|
||||
for rec in contracts:
|
||||
rent_free_month = rec.rent_free_period_month or 0
|
||||
rent_free_days = rec.rent_free_period_days or 0
|
||||
if rent_free_month > 0 and rent_free_days > 0:
|
||||
rent_free_text = f"{rent_free_month}月{rent_free_days}天"
|
||||
elif rent_free_month > 0:
|
||||
rent_free_text = f"{rent_free_month}月"
|
||||
elif rent_free_days > 0:
|
||||
rent_free_text = f"{rent_free_days}天"
|
||||
else:
|
||||
rent_free_text = "0个月"
|
||||
|
||||
if rec.term_start_time and rec.term_end_time:
|
||||
contract_tenure = f"{rec.term_start_time.strftime('%Y-%m-%d')} 至 {rec.term_end_time.strftime('%Y-%m-%d')}"
|
||||
elif rec.term_start_time:
|
||||
contract_tenure = f"{rec.term_start_time.strftime('%Y-%m-%d')} 至 未设置结束时间"
|
||||
elif rec.term_end_time:
|
||||
contract_tenure = f"未设置开始时间 至 {rec.term_end_time.strftime('%Y-%m-%d')}"
|
||||
else:
|
||||
contract_tenure = "未设置租期"
|
||||
|
||||
if rec.actual_start_time and rec.actual_end_time:
|
||||
actual_tenure = f"{rec.actual_start_time.strftime('%Y-%m-%d')} 至 {rec.actual_end_time.strftime('%Y-%m-%d')}"
|
||||
elif rec.actual_start_time:
|
||||
actual_tenure = f"{rec.actual_start_time.strftime('%Y-%m-%d')} 至 未结束"
|
||||
elif rec.actual_end_time:
|
||||
actual_tenure = f"未设置实际开始时间 至 {rec.actual_end_time.strftime('%Y-%m-%d')}"
|
||||
else:
|
||||
actual_tenure = "未设置实际租期"
|
||||
|
||||
report_data.append({
|
||||
"物业名称": rec.property_name or "",
|
||||
"承租方": rec.lessee_id.name or "" if rec.lessee_id else "",
|
||||
"递增规律": rec.increment_percentage or "",
|
||||
"免租期": rent_free_text,
|
||||
"面积": f"{rec.total_area} ㎡" if rec.total_area else "0 ㎡",
|
||||
"押金": rec.deposit or 0.0,
|
||||
"租金": rec.rent or 0.0,
|
||||
"未收": round(rec.not_received, 2),
|
||||
"本月已收": rec.month_received,
|
||||
"违约金": rec.percentage_damages or 0.0,
|
||||
"实际租期": actual_tenure,
|
||||
"合同租期": contract_tenure,
|
||||
"所属公司": rec.lessor_id.name or "" if rec.lessor_id else "",
|
||||
"负责人": rec.admin_id.name if rec.admin_id else " ",
|
||||
"合同编号": rec.contract_code or ""
|
||||
})
|
||||
|
||||
return report_data
|
||||
@@ -0,0 +1,137 @@
|
||||
/** @odoo-module */
|
||||
|
||||
import {registry} from "@web/core/registry";
|
||||
import {Component, onMounted, useRef, useState} from "@odoo/owl";
|
||||
import {useService} from "@web/core/utils/hooks";
|
||||
import {standardActionServiceProps} from "@web/webclient/actions/action_service";
|
||||
import {DateTimeInput} from "@web/core/datetime/datetime_input";
|
||||
import {Many2XAutocomplete} from "@web/views/fields/relational_utils";
|
||||
import {formatDate} from "@web/core/l10n/dates";
|
||||
|
||||
const {DateTime} = luxon;
|
||||
class ContractInfoReport extends Component {
|
||||
setup() {
|
||||
this.gridRef = useRef("grid");
|
||||
console.log("合同信息报表配置:", this.props.action.context.report_config);
|
||||
this.serviceOrm = useService("orm");
|
||||
this.notification = useService("notification");
|
||||
|
||||
this.state = useState({
|
||||
startDate: DateTime.now().startOf("month"),
|
||||
endDate: DateTime.now().endOf("month"),
|
||||
selectLessor: {},
|
||||
selectPrecinct: {},
|
||||
});
|
||||
|
||||
this.config = this.props.action.context.report_config || {};
|
||||
|
||||
onMounted(async () => {
|
||||
this.gridOptions = {
|
||||
localeText: AG_GRID_LOCALE_CN,
|
||||
theme: agGrid?.themeMaterial || "ag-theme-alpine",
|
||||
columnDefs: this.config.columns || [],
|
||||
rowData: [],
|
||||
sideBar: this.config.sideBar !== false,
|
||||
enableCharts: true, // 启用图表功能
|
||||
cellSelection: true, // 支持单元格选择
|
||||
defaultColDef: {
|
||||
sortable: true, // 支持排序
|
||||
filter: true, // 支持筛选
|
||||
width: 200,
|
||||
minWidth: 150,
|
||||
flex: false,
|
||||
resizable: false
|
||||
},
|
||||
|
||||
getContextMenuItems: (params) => {
|
||||
const items = params.defaultItems.slice();
|
||||
items.push("chartRange");
|
||||
return items;
|
||||
},
|
||||
};
|
||||
|
||||
if (this.gridRef.el) {
|
||||
this.grid = agGrid.createGrid(this.gridRef.el, this.gridOptions);
|
||||
await this.onSearch();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// -------------------------- 筛选器配置 --------------------------
|
||||
getDomainLessor() {
|
||||
return [];
|
||||
}
|
||||
|
||||
// 所属片区筛选域
|
||||
getDomainPrecinct() {
|
||||
return [];
|
||||
}
|
||||
|
||||
|
||||
// -------------------------- 筛选事件处理 --------------------------
|
||||
async onUpdateLessor(v) {
|
||||
console.log("选择所属公司:", v);
|
||||
this.state.selectLessor = v[0] || {};
|
||||
}
|
||||
|
||||
async onUpdatePrecinct(v) {
|
||||
console.log("选择所属片区:", v);
|
||||
this.state.selectPrecinct = v[0] || {};
|
||||
}
|
||||
|
||||
async onChangeStartDate(date) {
|
||||
console.log("实际开始日期变更:", date);
|
||||
this.state.startDate = date || false;
|
||||
}
|
||||
|
||||
async onChangeEndDate(date) {
|
||||
console.log("实际结束日期变更:", date);
|
||||
this.state.endDate = date || false;
|
||||
}
|
||||
|
||||
// -------------------------- 核心业务逻辑 --------------------------
|
||||
async onSearch() {
|
||||
console.log("筛选参数:", this.state);
|
||||
const startDate = this.state.startDate
|
||||
? formatDate(this.state.startDate, {format: "yyyy-MM-dd"})
|
||||
: false;
|
||||
const endDate = this.state.endDate
|
||||
? formatDate(this.state.endDate, {format: "yyyy-MM-dd"})
|
||||
: false;
|
||||
|
||||
const params = {
|
||||
date_start: startDate,
|
||||
date_end: endDate,
|
||||
lessor_id: this.state.selectLessor?.id || false,
|
||||
precinct_id: this.state.selectPrecinct?.id || false,
|
||||
};
|
||||
|
||||
try {
|
||||
const result = await this.serviceOrm.call(
|
||||
this.config.model,
|
||||
this.config.method,
|
||||
[params]
|
||||
);
|
||||
this.grid.setGridOption('rowData', result);
|
||||
} catch (e) {
|
||||
console.error("获取收款信息表数据失败:", e);
|
||||
}
|
||||
}
|
||||
|
||||
onExportExcel() {
|
||||
this.grid.exportDataAsExcel({
|
||||
fileName: "合同信息报表.xlsx",
|
||||
sheetName: "合同台账"
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// -------------------------- 组件配置 --------------------------
|
||||
ContractInfoReport.props = {...standardActionServiceProps};
|
||||
ContractInfoReport.template = "yuthon_report.ContractInfoReport"; // 模板名需与XML模板ID一致
|
||||
ContractInfoReport.components = {
|
||||
DateTimeInput,
|
||||
Many2XAutocomplete
|
||||
};
|
||||
|
||||
registry.category("actions").add("contract_info_report_client", ContractInfoReport);
|
||||
@@ -0,0 +1,73 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<templates id="template" xml:space="preserve">
|
||||
<t t-name="yuthon_report.ContractInfoReport">
|
||||
<div class="container-fluid d-flex flex-column h-100 mt-2 pb-3">
|
||||
<div class="card mb-2">
|
||||
<div class="card-body">
|
||||
<div class="row mb-2" t-ref="search_area">
|
||||
|
||||
<!--日期 -->
|
||||
<div class="col-3">
|
||||
<label>日期范围</label>
|
||||
<div class="d-flex align-items-center gap-2">
|
||||
<DateTimeInput
|
||||
range="true"
|
||||
value="state.startDate"
|
||||
type="'date'"
|
||||
placeholder="fromPlaceholder"
|
||||
onChange="(date) => this.onChangeStartDate(date)"
|
||||
/>
|
||||
<i class="oi oi-arrow-right"></i>
|
||||
<DateTimeInput
|
||||
range="true"
|
||||
value="state.endDate"
|
||||
type="'date'"
|
||||
placeholder="toPlaceholder"
|
||||
onChange="(date) => this.onChangeEndDate(date)"
|
||||
/>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<!-- 所属公司 -->
|
||||
<div class="col-3">
|
||||
<label>所属公司</label>
|
||||
<Many2XAutocomplete
|
||||
value="state.selectLessor?.display_name"
|
||||
getDomain="getDomainLessor"
|
||||
resModel="'yuthon.property.company'"
|
||||
fieldString="'所属公司'"
|
||||
activeActions="{}"
|
||||
update.bind="onUpdateLessor"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="col-3">
|
||||
<label>负责人</label>
|
||||
<Many2XAutocomplete
|
||||
value="state.selectPrecinct?.display_name"
|
||||
getDomain="getDomainPrecinct"
|
||||
resModel="'yuthon.precinct.message'"
|
||||
fieldString="'负责人'"
|
||||
activeActions="{}"
|
||||
update.bind="onUpdatePrecinct"
|
||||
/>
|
||||
</div>
|
||||
<div class="col-12 mt-3 d-flex justify-content-end gap-2">
|
||||
<button class="btn btn-primary" t-on-click="onSearch">搜索</button>
|
||||
<button class="btn btn-success" t-on-click="onExportExcel">导出</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="row flex-grow-1">
|
||||
<div class="col-12 h-100">
|
||||
<div class="ag-theme-alpine w-100 h-100" t-ref="grid"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</t>
|
||||
</templates>
|
||||
@@ -0,0 +1,48 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
<data>
|
||||
<record id="action_yuthon_contract_report_report" model="ir.actions.client">
|
||||
<field name="name">合同信息报表</field>
|
||||
<field name="tag">contract_info_report_client</field>
|
||||
<field name="context">
|
||||
{
|
||||
"sideBar": true,
|
||||
"report_config": {
|
||||
"model": "property.lease.contract",
|
||||
"method": "get_contract_info_report",
|
||||
"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, "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.5},
|
||||
{"headerName": "合同租期", "field": "合同租期", "flex": 1.5},
|
||||
{"headerName": "所属公司", "field": "所属公司", "flex": 1},
|
||||
{"headerName": "负责人", "field": "负责人", "flex": 1},
|
||||
{"headerName": "合同编号", "field": "合同编号", "flex": 1}
|
||||
],
|
||||
"filters": [
|
||||
{"name": "date_start", "label": "合同开始日期", "type": "date"},
|
||||
{"name": "date_end", "label": "合同结束日期", "type": "date"},
|
||||
{"name": "lessor_id", "label": "所属公司", "type": "many2one", "model": "yuthon.property.company"},
|
||||
{"name": "admin_id", "label": "负责人", "type": "many2one", "model": "res.users"}
|
||||
]
|
||||
}
|
||||
}
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<menuitem
|
||||
id="menu_yuthon_contract_report"
|
||||
name="合同信息报表"
|
||||
parent="yuthon_property_approval.property_approval_report_menu"
|
||||
action="action_yuthon_contract_report_report"
|
||||
sequence="10"/>
|
||||
</data>
|
||||
</odoo>
|
||||
Reference in New Issue
Block a user