@@ -6,7 +6,7 @@
|
||||
<field name="arch" type="xml">
|
||||
<page name="preferences" position="after">
|
||||
<page string="房地产信息" name="estate_property_info">
|
||||
<field name='property_ids' widget="one2many_list" />
|
||||
<field name='property_ids'/>
|
||||
</page>
|
||||
</page>
|
||||
</field>
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
__pycache__/
|
||||
*.py[cod]
|
||||
*.pyo
|
||||
*.pyd
|
||||
*.so
|
||||
@@ -1,27 +0,0 @@
|
||||
Odoo Proprietary License v1.0
|
||||
|
||||
This software and associated files (the "Software") may only be used (executed,
|
||||
modified, executed after modifications) if you have purchased a valid license
|
||||
from the authors, typically via Odoo Apps, or if you have received a written
|
||||
agreement from the authors of the Software (see the COPYRIGHT file).
|
||||
|
||||
You may develop Odoo modules that use the Software as a library (typically
|
||||
by depending on it, importing it and using its resources), but without copying
|
||||
any source code or material from the Software. You may distribute those
|
||||
modules under the license of your choice, provided that this license is
|
||||
compatible with the terms of the Odoo Proprietary License (For example:
|
||||
LGPL, MIT, or proprietary licenses similar to this one).
|
||||
|
||||
It is forbidden to publish, distribute, sublicense, or sell copies of the Software
|
||||
or modified copies of the Software.
|
||||
|
||||
The above copyright notice and this permission notice must be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
||||
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
DEALINGS IN THE SOFTWARE.
|
||||
@@ -51,15 +51,15 @@ In your Odoo view XML file, use the widget with options:
|
||||
|
||||
### Form View
|
||||
|
||||

|
||||

|
||||
|
||||
### List View
|
||||
|
||||

|
||||

|
||||
|
||||
### Kanban View
|
||||
|
||||

|
||||

|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -1,27 +0,0 @@
|
||||
Odoo Proprietary License v1.0
|
||||
|
||||
This software and associated files (the "Software") may only be used (executed,
|
||||
modified, executed after modifications) if you have purchased a valid license
|
||||
from the authors, typically via Odoo Apps, or if you have received a written
|
||||
agreement from the authors of the Software (see the COPYRIGHT file).
|
||||
|
||||
You may develop Odoo modules that use the Software as a library (typically
|
||||
by depending on it, importing it and using its resources), but without copying
|
||||
any source code or material from the Software. You may distribute those
|
||||
modules under the license of your choice, provided that this license is
|
||||
compatible with the terms of the Odoo Proprietary License (For example:
|
||||
LGPL, MIT, or proprietary licenses similar to this one).
|
||||
|
||||
It is forbidden to publish, distribute, sublicense, or sell copies of the Software
|
||||
or modified copies of the Software.
|
||||
|
||||
The above copyright notice and this permission notice must be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
||||
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
DEALINGS IN THE SOFTWARE.
|
||||
@@ -1,79 +0,0 @@
|
||||
# Many2Many Tags Preview
|
||||
|
||||
🚀 **Odoo Module** — 快速预览 Many2Many 字段的标签,提升导航效率。
|
||||
This module enhances the standard `many2many_tags` widget in Odoo, allowing instant preview and quick access to related records in **List, Form, and Kanban** views.
|
||||
|
||||
---
|
||||
|
||||
## ✨ Features
|
||||
|
||||
- 🔍 **Quick Preview**
|
||||
Preview related records directly from many2many tags.
|
||||
|
||||
- ⚙️ **Custom Form View**
|
||||
Support `context={'open_form_view': 'xml_id'}` to open a specific form view.
|
||||
|
||||
- 🔄 **Seamless Integration**
|
||||
Fully compatible with Odoo native `many2many_tags`.
|
||||
|
||||
- 📱 **Multi-View Support**
|
||||
Works in **List**, **Form**, and **Kanban** views.
|
||||
|
||||
---
|
||||
|
||||
## 📦 Installation
|
||||
|
||||
1. Clone this repository into your Odoo `addons` directory
|
||||
2. Restart Odoo server.
|
||||
3. Activate developer mode.
|
||||
4. Update Apps list and install **Many2Many Tags Preview** module.
|
||||
|
||||
---
|
||||
|
||||
## 🛠 Usage
|
||||
|
||||
In your Odoo view XML file, use the widget with options:
|
||||
|
||||
```xml
|
||||
<field name="tag_ids"
|
||||
widget="many2many_tags"
|
||||
options="{'color_field': 'color'}"
|
||||
context="{'open_form_view': 'estate.estate_property_tag_view_form02'}"/>
|
||||
```
|
||||
|
||||
- `widget="many2many_tags"` → Render tags.
|
||||
- `options="{'color_field': 'color'}"` → Use the `color` field for tag coloring.
|
||||
- `context="{'open_form_view': 'xml_id'}` → Specify a custom form view (if omitted, default form opens).
|
||||
|
||||
---
|
||||
|
||||
## 🖼 Screenshots
|
||||
|
||||
### Form View
|
||||
|
||||

|
||||
|
||||
### List View
|
||||
|
||||

|
||||
|
||||
### Kanban View
|
||||
|
||||

|
||||
|
||||
---
|
||||
|
||||
## 📌 Compatibility
|
||||
|
||||
- ✅ Odoo 17.0
|
||||
- ✅ Odoo 18.0
|
||||
- ✅ Odoo 19.0
|
||||
|
||||
Supports **Community** and **Enterprise** editions.
|
||||
|
||||
---
|
||||
|
||||
## 📧 Contact
|
||||
|
||||
Author: **LuckyJie12**
|
||||
Email: [2996985766@qq.com](mailto:2996985766@qq.com)
|
||||
|
Before Width: | Height: | Size: 1.4 MiB After Width: | Height: | Size: 1.4 MiB |
|
Before Width: | Height: | Size: 2.8 MiB After Width: | Height: | Size: 2.8 MiB |
|
Before Width: | Height: | Size: 681 KiB After Width: | Height: | Size: 681 KiB |
|
Before Width: | Height: | Size: 1.1 MiB After Width: | Height: | Size: 1.1 MiB |
|
Before Width: | Height: | Size: 6.5 KiB After Width: | Height: | Size: 6.5 KiB |
|
Before Width: | Height: | Size: 2.9 KiB After Width: | Height: | Size: 2.9 KiB |
@@ -6,9 +6,11 @@ from odoo.exceptions import UserError, ValidationError
|
||||
class PropertyMeterArchives(models.Model):
|
||||
_name = 'property.meter.archives'
|
||||
_description = '电表库'
|
||||
_order = 'number asc'
|
||||
|
||||
name = fields.Char(string='仪表编号')
|
||||
unit_number = fields.Char(string='单元编号/用途')
|
||||
number = fields.Char(string="序号")
|
||||
installation_location = fields.Char(string='安装位置')
|
||||
is_state = fields.Boolean(string='是否启用')
|
||||
type = fields.Selection([('public', '公共'), ('fees', '收费')], string='类型')
|
||||
|
||||
@@ -5,8 +5,10 @@ from odoo.exceptions import UserError, ValidationError
|
||||
class PropertyMeterWater(models.Model):
|
||||
_name = 'property.meter.water'
|
||||
_description = '水表库'
|
||||
_order = 'number asc'
|
||||
|
||||
name = fields.Char(string='仪表编号')
|
||||
number = fields.Char(string="序号")
|
||||
unit_number = fields.Char(string='单元编号/用途')
|
||||
installation_location = fields.Char(string='安装位置')
|
||||
is_state = fields.Boolean(string='是否启用')
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
<button class="oe_highlight" name="batch_reading_push" string="推送" type="object"/>
|
||||
<button class="oe_highlight" name="button_archives_state" string="停用" type="object"/>
|
||||
</header>
|
||||
<field name="number" widget="handle"/>
|
||||
<field name="name"/>
|
||||
<field name="epitope_values"/>
|
||||
<field name="lessee_id" options="{'no_create': True}"/>
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
<button class="oe_highlight" name="batch_reading_water_push" string="推送" type="object"/>
|
||||
<button class="oe_highlight" name="button_water_state" string="停用" type="object"/>
|
||||
</header>
|
||||
<field name="number" widget="handle"/>
|
||||
<field name="name"/>
|
||||
<field name="epitope_values"/>
|
||||
<field name="lessee_id" options="{'no_create': True}"/>
|
||||
|
||||
@@ -83,6 +83,7 @@
|
||||
'wizard/binding_information_wizard_views.xml',
|
||||
'wizard/property_rental_wizard_views.xml',
|
||||
'wizard/contract_signature_wizard_viwes.xml',
|
||||
'wizard/penalty_line_wizard_viwes.xml',
|
||||
'wizard/build_pop_wizard_viwes.xml',
|
||||
'wizard/property_meeting_wizard_views.xml',
|
||||
'views/property_menu_all.xml',
|
||||
|
||||
@@ -304,6 +304,7 @@ class PropertyBankStatements(models.Model):
|
||||
'default_amount_reconciled': self.no_amount,
|
||||
"default_receivable_total": total_rent_month,
|
||||
"dialog_size" : "extra-large",
|
||||
"default_order": "due_date desc",
|
||||
}
|
||||
|
||||
return {
|
||||
@@ -368,6 +369,7 @@ class PropertyAccountsReceivable(models.Model):
|
||||
|
||||
property_ids = fields.Many2many('yuthon.property', string='物业', compute='_compute_property_ids', store=True)
|
||||
property_name = fields.Text(string='物业', compute="_compute_property_name")
|
||||
is_rent = fields.Boolean(string='是否租金', default=True, compute = '_compute_is_rent', store=True)
|
||||
management_area = fields.Float(related='contract_id.total_area', string='面积')
|
||||
title_deed = fields.Char(string="产权证号", compute='_compute_title_deed')
|
||||
lessee_id = fields.Many2one(related='contract_id.lessee_id', string='承租方', stroe=True)
|
||||
@@ -382,6 +384,23 @@ class PropertyAccountsReceivable(models.Model):
|
||||
rent_owed = fields.Float(string="欠租金额")
|
||||
per_day = fields.Float(string="每天违约金(元/天)")
|
||||
|
||||
@api.depends('management_type_id')
|
||||
def _compute_is_rent(self):
|
||||
for rec in self:
|
||||
if rec.management_type_id.name == '租金':
|
||||
rec.is_rent = True
|
||||
else:
|
||||
rec.is_rent = False
|
||||
|
||||
def penalty_wizard(self):
|
||||
return {
|
||||
'name': '合同违约金明细',
|
||||
'type': 'ir.actions.act_window',
|
||||
'res_model': 'penalty.line.wizard',
|
||||
'view_mode': 'form',
|
||||
'target': 'new',
|
||||
}
|
||||
|
||||
@api.depends('contract_id')
|
||||
def _compute_property_name(self):
|
||||
for record in self:
|
||||
|
||||
@@ -105,3 +105,7 @@ access_contract_signature_wizard,contract_signature_wizard,model_contract_signat
|
||||
access_payment_process,payment_process,model_payment_process,base.group_user,1,1,1,1
|
||||
access_build_pop_wizard, build_pop_wizard,model_build_pop_wizard,base.group_user,1,1,1,1
|
||||
|
||||
|
||||
access_penalty_line_wizard, penalty_line_wizard,model_penalty_line_wizard,base.group_user,1,1,1,1
|
||||
access_penalty_compute_line_wizard, penalty_compute_line_wizard,model_penalty_compute_line_wizard,base.group_user,1,1,1,1
|
||||
access_penalty_pay_line, penalty_pay_line,model_penalty_pay_line,base.group_user,1,1,1,1
|
||||
|
||||
|
@@ -284,9 +284,11 @@
|
||||
</header>
|
||||
</xpath>
|
||||
<xpath expr="//field[@name='is_suspend']" position="before">
|
||||
<button name="penalty_wizard" string="违约金明细" type="object" class="btn btn-primary" invisible="not is_rent"/>
|
||||
<button name="button_accounts_wizard" string="操作" type="object" class="btn btn-primary"/>
|
||||
</xpath>
|
||||
<xpath expr="//field[@name='payout_date']" position="after">
|
||||
<field name="is_rent" column_invisible="1"/>
|
||||
<field name="lessee_id" options="{'no_create': True}" readonly="1"/>
|
||||
<field name="title_deed" readonly="1"/>
|
||||
<field name="property_ids" options="{'no_create': True}" widget="many2many_tags" column_invisible="1"/>
|
||||
|
||||
@@ -10,4 +10,5 @@ from . import click_reconciliation_wizard
|
||||
from . import accounts_wizard
|
||||
from . import binding_information_wizard
|
||||
from . import contract_signature_wizard
|
||||
from . import build_pop_wizard
|
||||
from . import build_pop_wizard
|
||||
from . import penalty_line_wizard
|
||||
@@ -0,0 +1,50 @@
|
||||
from email.policy import default
|
||||
|
||||
from odoo import models, fields, api, _, SUPERUSER_ID
|
||||
from odoo.exceptions import ValidationError, UserError
|
||||
import xlrd
|
||||
import base64
|
||||
import datetime
|
||||
from datetime import datetime
|
||||
import pandas as pd
|
||||
|
||||
|
||||
class PenaltyLineWizard(models.Model):
|
||||
_name = 'penalty.line.wizard'
|
||||
_description = '合同违约金明细'
|
||||
|
||||
rent_collected = fields.Float(string='未收租金')
|
||||
days_overdue = fields.Integer(string='逾期天数')
|
||||
total_penalty = fields.Float(string='违约金总额')
|
||||
collected_penalty = fields.Float(string='已收违约金')
|
||||
uncollected_penalty = fields.Float(string='未收违约金')
|
||||
pay_number = fields.Char(string='支付次数')
|
||||
remake = fields.Text(string='备注')
|
||||
|
||||
rule_description = fields.Text(string='计算规则说明:', default = '应收月的次月1号开始计算违约金\n。违约金按每日千分之 - (0.1 %)\n计算\n。租金部分支付后,剩余部分从前一次缴费日期次日开始里新计算')
|
||||
penalty_line_ids = fields.One2many('penalty.compute.line.wizard', 'penalty_id', string='违约金明细')
|
||||
pay_line_ids = fields.One2many('penalty.pay.line', 'penalty_id', string='违约金支付明细')
|
||||
|
||||
|
||||
class PenaltyComputeLineWizard(models.Model):
|
||||
_name = 'penalty.compute.line.wizard'
|
||||
_description = '违约金计算明细'
|
||||
_order = 'date desc'
|
||||
|
||||
penalty_id = fields.Many2one('penalty.line.wizard', string='关联违约金明细')
|
||||
date = fields.Date(string='日期')
|
||||
remake = fields.Text(string='说明')
|
||||
days_overdue = fields.Integer(string='逾期天数')
|
||||
remaining_principal = fields.Float(string='剩余本金')
|
||||
calculation_formula = fields.Text(string='计算公式')
|
||||
|
||||
|
||||
class PenaltyPayLine(models.Model):
|
||||
_name = 'penalty.pay.line'
|
||||
_description = '支付记录明细'
|
||||
|
||||
penalty_id = fields.Many2one('penalty.line.wizard', string='关联违约金明细')
|
||||
date = fields.Date(string='支付日期')
|
||||
amount = fields.Float(string='支付金额')
|
||||
management_type_id = fields.Many2one('yuthon.management.type', string='支付类型')
|
||||
remake = fields.Text(string='备注')
|
||||
@@ -0,0 +1,58 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<odoo>
|
||||
<record id="penalty_line_wizard_form_view" model="ir.ui.view">
|
||||
<field name="name">penalty.line.wizard.form</field>
|
||||
<field name="model">penalty.line.wizard</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="合同违约金详情">
|
||||
<sheet>
|
||||
<group col="2">
|
||||
<group>
|
||||
<field name="rent_collected"/>
|
||||
<field name="days_overdue"/>
|
||||
<field name="total_penalty"/>
|
||||
</group>
|
||||
<group>
|
||||
<field name="collected_penalty"/>
|
||||
<field name="uncollected_penalty"/>
|
||||
<field name="pay_number"/>
|
||||
</group>
|
||||
</group>
|
||||
<group>
|
||||
<field name="remake"/>
|
||||
</group>
|
||||
<notebook>
|
||||
<page string="违约金计算明细(按日千分之一计算)">
|
||||
<group>
|
||||
<field name="rule_description"/>
|
||||
</group>
|
||||
<field name="penalty_line_ids" string=" ">
|
||||
<tree editable="bottom">
|
||||
<field name="penalty_id" column_invisible="1"/>
|
||||
<field name="date"/>
|
||||
<field name="remake"/>
|
||||
<field name="days_overdue"/>
|
||||
<field name="remaining_principal"/>
|
||||
<field name="calculation_formula"/>
|
||||
</tree>
|
||||
</field>
|
||||
</page>
|
||||
</notebook>
|
||||
<notebook>
|
||||
<page string="支付详情">
|
||||
<field name="pay_line_ids" string=" ">
|
||||
<tree editable="bottom">
|
||||
<field name="penalty_id" column_invisible="1"/>
|
||||
<field name="date"/>
|
||||
<field name="amount"/>
|
||||
<field name="management_type_id"/>
|
||||
<field name="remake"/>
|
||||
</tree>
|
||||
</field>
|
||||
</page>
|
||||
</notebook>
|
||||
</sheet>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
</odoo>
|
||||
@@ -165,8 +165,6 @@ class PropertyReconciliationWizard(models.Model):
|
||||
if line.collection_type != 'penalty'
|
||||
]
|
||||
self.reconciliation_line_ids = keep_lines + new_lines
|
||||
if self.reconciliation_line_ids:
|
||||
self.reconciliation_line_ids.sorted(key=lambda r: r.sequence)
|
||||
|
||||
all_penalties = all(line.collection_type == 'penalty' for line in self.reconciliation_line_ids)
|
||||
if all_penalties and self.reconciliation_line_ids:
|
||||
@@ -492,7 +490,7 @@ class PropertyReconciliationWizard(models.Model):
|
||||
class PropertyReconciliationLine(models.Model):
|
||||
_name = 'property.reconciliation.line'
|
||||
_description = '对账明细'
|
||||
_order = 'sequence asc'
|
||||
_order = 'collection_type desc, due_date desc'
|
||||
|
||||
reconciliation_id = fields.Many2one('property.reconciliation.wizard', string='关联对账单弹窗')
|
||||
sequence = fields.Integer(string='顺序')
|
||||
|
||||
@@ -33,7 +33,7 @@
|
||||
<notebook>
|
||||
<page name="对账明细">
|
||||
<field name="reconciliation_line_ids">
|
||||
<tree editable="bottom" create="false" delete="false" default_order="sequence desc">
|
||||
<tree editable="bottom" create="false" delete="false">
|
||||
<field name="sequence" column_invisible="1" />
|
||||
<field name="reconciliation_id" column_invisible="1"/>
|
||||
<field name="property_ids" readonly="1" column_invisible="1"/>
|
||||
|
||||