diff --git a/yuthon_property_approval/__manifest__.py b/yuthon_property_approval/__manifest__.py
index 289ef3247..638b6376d 100644
--- a/yuthon_property_approval/__manifest__.py
+++ b/yuthon_property_approval/__manifest__.py
@@ -120,6 +120,7 @@
'web.assets_backend': [
'yuthon_property_approval/static/src/scss/approval.scss',
'yuthon_property_approval/static/xml/misc.xml',
+ 'yuthon_property_approval/static/src/js/contract_m2m_tags.js',
],
},
'demo': [],
diff --git a/yuthon_property_approval/static/src/js/contract_m2m_tags.js b/yuthon_property_approval/static/src/js/contract_m2m_tags.js
new file mode 100644
index 000000000..bc54cf2c0
--- /dev/null
+++ b/yuthon_property_approval/static/src/js/contract_m2m_tags.js
@@ -0,0 +1,102 @@
+/** @odoo-module **/
+
+import { registry } from "@web/core/registry";
+import {
+ Many2ManyTagsField,
+ many2ManyTagsField,
+} from "@web/views/fields/many2many_tags/many2many_tags_field";
+import { Many2XAutocomplete } from "@web/views/fields/relational_utils";
+
+/**
+ * 自定义的 Many2X 自动完成组件:
+ * - 下拉候选使用 property.lease.contract 的 contract_code + lessor_id
+ */
+class ContractMany2XAutocomplete extends Many2XAutocomplete {
+ /**
+ * 重写搜索逻辑:不用 name_search,而是 search_read 读合同编号和出租方
+ */
+ search(name) {
+ const baseDomain = this.props.getDomain ? this.props.getDomain() : [];
+ const domain = [...(baseDomain || [])];
+ if (name) {
+ domain.push(["contract_code", "ilike", name]);
+ }
+ // 返回 ORM 的原始 Promise(带 abort 方法),以兼容父类 loadOptionsSource
+ return this.orm.searchRead(
+ "property.lease.contract",
+ domain,
+ ["contract_code", "lessor_id"],
+ { limit: this.props.searchLimit + 1 }
+ );
+ }
+
+
+ /**
+ * 把 search 返回的记录转换成下拉选项
+ */
+ mapRecordToOption(rec) {
+ const base = rec.contract_code || "";
+ const lessor = rec.lessor_id && rec.lessor_id[1] ? rec.lessor_id[1] : "";
+ const label = lessor ? `${base}(${lessor})` : base || "";
+ return {
+ value: rec.id,
+ label: label,
+ displayName: label,
+ };
+ }
+}
+
+/**
+ * 自定义 Many2ManyTags 字段:
+ * - 已选标签显示为 合同编号(出租方)
+ * - 下拉使用上面的 ContractMany2XAutocomplete
+ */
+export class ContractMany2ManyTags extends Many2ManyTagsField {
+ // 替换内部使用的自动完成组件
+ static components = {
+ ...Many2ManyTagsField.components,
+ Many2XAutocomplete: ContractMany2XAutocomplete,
+ };
+
+ /**
+ * 控制标签上的显示文本
+ */
+ getTagProps(record) {
+ const props = super.getTagProps(record);
+ const base = record.data.contract_code || record.data.display_name || "";
+ const lessor =
+ record.data.lessor_id && record.data.lessor_id[1]
+ ? record.data.lessor_id[1]
+ : "";
+ const label = lessor ? `${base}(${lessor})` : base;
+ return {
+ ...props,
+ text: label,
+ title: label,
+ };
+ }
+}
+
+/**
+ * 字段注册配置:
+ * - 复用原 many2many_tags 的配置
+ * - 额外声明需要加载 contract_code 和 lessor_id 这两个字段
+ */
+export const contractMany2ManyTagsField = {
+ ...many2ManyTagsField,
+ component: ContractMany2ManyTags,
+ relatedFields: (env) => {
+ const fields = many2ManyTagsField.relatedFields(env) || [];
+ const names = new Set(fields.map((f) => f.name));
+ if (!names.has("contract_code")) {
+ fields.push({ name: "contract_code", type: "char" });
+ }
+ if (!names.has("lessor_id")) {
+ fields.push({ name: "lessor_id", type: "many2one" });
+ }
+ return fields;
+ },
+};
+
+// 注册成一个新的字段类型:contract_m2m_tags
+registry.category("fields").add("contract_m2m_tags", contractMany2ManyTagsField);
diff --git a/yuthon_property_approval/wizard/binding_information_wizard_views.xml b/yuthon_property_approval/wizard/binding_information_wizard_views.xml
index 15af42517..accbeef44 100644
--- a/yuthon_property_approval/wizard/binding_information_wizard_views.xml
+++ b/yuthon_property_approval/wizard/binding_information_wizard_views.xml
@@ -12,7 +12,7 @@
-
+