Merge remote-tracking branch 'origin/dev' into dev
This commit is contained in:
@@ -6,7 +6,7 @@
|
||||
|
||||
- 快捷筛选(quick_filter)
|
||||
- 自选时间筛选(select_date_filter)(待移植)
|
||||
- 字段搜索(field)(待移植)
|
||||
- 字段搜索(field)(已移植)
|
||||
|
||||
通过这些筛选标签,用户可以更灵活地对列表视图中的数据进行筛选。
|
||||
|
||||
@@ -20,9 +20,9 @@
|
||||
|
||||
#### 支持的属性:
|
||||
|
||||
| 属性名 | 类型 | 说明 | 是否可选 |
|
||||
| ------- | ------ | ---------- | ---- |
|
||||
| `class` | String | 自定义 CSS 类名 | ✅ |
|
||||
| 属性名 | 类型 | 说明 | 是否可选 |
|
||||
| ------- | ------ |-------------------------------------------------------------------| ---- |
|
||||
| `class` | String | 自定义 CSS 类名,<br/>可使用class="header-search-inline"使所有筛选在同一行并根据宽度自动换行 | ✅ |
|
||||
|
||||
#### 子标签支持:
|
||||
|
||||
@@ -56,7 +56,7 @@
|
||||
| ----------- | ------- | ----------- | ------------ |
|
||||
| `class` | String | 自定义 CSS 类名 | ✅ |
|
||||
| `string` | String | 显示的标头名称 | ✅ |
|
||||
| `invisible` | Boolean | 是否默认隐藏 | ✅ |
|
||||
| `invisible` | Boolean | 是否默认隐藏(废弃) | ✅ |
|
||||
| `options` | JSON | 扩展参数,支持以下参数: | ✅ |
|
||||
| | | `radio`: 是否单选 | |
|
||||
| | | `no_label`: 不显示标题 | |
|
||||
@@ -77,16 +77,16 @@
|
||||
|
||||
---
|
||||
|
||||
### 3. 自选时间筛选 (select_date_filter)
|
||||
### 3. 自选时间筛选 (select_date_filter)(废弃)
|
||||
|
||||
**标签名:** `select_date_filter`
|
||||
|
||||
#### 支持的属性:
|
||||
|
||||
| 属性名 | 类型 | 说明 | 是否可选 |
|
||||
| ------------------- | ------- | -------------- | ---- |
|
||||
| ------------------- | ------- |----------------| ---- |
|
||||
| `class` | String | 自定义 CSS 类名 | ✅ |
|
||||
| `invisible` | Boolean | 是否默认隐藏 | ✅ |
|
||||
| `invisible` | Boolean | 是否默认隐藏(废弃) | ✅ |
|
||||
| `allow_date_fields` | String | 允许筛选的时间字段,逗号分隔 | ✅ |
|
||||
|
||||
#### 示例:
|
||||
@@ -109,6 +109,9 @@
|
||||
| `string` | String | 显示的标头名称 | ✅ |
|
||||
| `class` | String | 自定义 CSS | ✅ |
|
||||
| `invisible` | Boolean | 是否默认隐藏 | ✅ |
|
||||
| `options` | JSON | 扩展参数,支持以下参数: | ✅ |
|
||||
| | | `radio`: 是否单选 | |
|
||||
| | | `no_label`: 不显示标题 | |
|
||||
|
||||
#### 示例:
|
||||
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
/** @odoo-module **/
|
||||
//
|
||||
// import {patch} from "@web/core/utils/patch";
|
||||
// import * as backend_utils from "@web/legacy/backend_utils";
|
||||
//
|
||||
// const originalSearchModelStateToLegacy = backend_utils.searchModelStateToLegacy;
|
||||
// const originalGetGlobalState = backend_utils.getGlobalState;
|
||||
//
|
||||
// patch(backend_utils, "header_search_panel.backend_utils", {
|
||||
// searchModelStateToLegacy(state) {
|
||||
// // 原始state
|
||||
// const originalState = JSON.parse(state);
|
||||
// // 获取原始state
|
||||
// let legacyState = JSON.parse(originalSearchModelStateToLegacy(state));
|
||||
// if (originalState.headerSearchInfo) {
|
||||
// legacyState.HeaderSearchInfo = originalState.headerSearchInfo;
|
||||
// }
|
||||
// return JSON.stringify(legacyState)
|
||||
// },
|
||||
//
|
||||
// getGlobalState(legacyControllerState) {
|
||||
// // 原始search model
|
||||
// const originalSearchModel = JSON.parse(legacyControllerState.searchModel)
|
||||
// let globalState = originalGetGlobalState(legacyControllerState);
|
||||
// let searchModel = JSON.parse(globalState?.searchModel || "{}");
|
||||
// if (originalSearchModel.HeaderSearchInfo) {
|
||||
// searchModel.headerSearchInfo = originalSearchModel.HeaderSearchInfo;
|
||||
// globalState.searchModel = JSON.stringify(searchModel)
|
||||
// }
|
||||
// console.log('headerSearchInfo: getGlobalState')
|
||||
// return globalState
|
||||
// },
|
||||
// })
|
||||
+54
@@ -0,0 +1,54 @@
|
||||
/** @odoo-module **/
|
||||
|
||||
import { Component } from "@odoo/owl";
|
||||
import { Domain } from "@web/core/domain";
|
||||
import { useService } from "@web/core/utils/hooks";
|
||||
import { Many2XAutocomplete } from "@web/views/fields/relational_utils";
|
||||
import { standardFieldFilterProps } from "../standard_field_filter_props.js"
|
||||
|
||||
|
||||
export class CharFilter extends Component {
|
||||
setup() {
|
||||
super.setup();
|
||||
this.rpc = useService("rpc");
|
||||
this.activeValues = this.env.searchModel.headerSearchInfo.FieldsFilter[this.props.id]?.activeValues || undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置筛选字段的值
|
||||
*/
|
||||
setActiveValues(ev) {
|
||||
this.activeValues = ev.target.value;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取筛选字段的domain
|
||||
*/
|
||||
get domain() {
|
||||
return this.activeValues ? [[this.props.name, "ilike", this.activeValues]]: [];
|
||||
}
|
||||
|
||||
/**
|
||||
* 点击清空筛选时触发
|
||||
*/
|
||||
resetFilter() {
|
||||
// 清空筛选字段的值
|
||||
this.activeValues = undefined;
|
||||
this.props.fieldOnchange({fieldDomainList: this.domain, activeValues: this.activeValues});
|
||||
}
|
||||
|
||||
getDomain() {
|
||||
return new Domain(this.props.domain).toList({});
|
||||
}
|
||||
|
||||
async onInputChange(ev) {
|
||||
this.setActiveValues(ev);
|
||||
this.props.fieldOnchange({fieldDomainList: this.domain, activeValues: this.activeValues});
|
||||
}
|
||||
}
|
||||
|
||||
CharFilter.template = "header_search_panel.CharFilter";
|
||||
CharFilter.components = {};
|
||||
CharFilter.props = {
|
||||
...standardFieldFilterProps,
|
||||
};
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<templates xml:space="preserve">
|
||||
|
||||
<t t-name="header_search_panel.CharFilter" owl="1">
|
||||
<div>
|
||||
<input class="o_input"
|
||||
t-att-id="props.id"
|
||||
type="text"
|
||||
t-ref="input"
|
||||
t-att-value="activeValues"
|
||||
t-on-input="onInputChange"/>
|
||||
</div>
|
||||
</t>
|
||||
|
||||
</templates>
|
||||
+27
-10
@@ -1,8 +1,9 @@
|
||||
/** @odoo-module **/
|
||||
|
||||
import {Component} from "@odoo/owl";
|
||||
import {Domain} from "@web/core/domain";
|
||||
import {standardFieldFilterProps} from "../standard_field_filter_props.js"
|
||||
import { Component } from "@odoo/owl";
|
||||
import { DateTimeInput } from "@web/core/datetime/datetime_input";
|
||||
import { deserializeDate } from "@web/core/l10n/dates";
|
||||
import { standardFieldFilterProps } from "../standard_field_filter_props.js"
|
||||
|
||||
export class DateFilter extends Component {
|
||||
setup() {
|
||||
@@ -13,13 +14,21 @@ export class DateFilter extends Component {
|
||||
this.endDate = this.env.searchModel.headerSearchInfo.FieldsFilter[this.props.id]?.endDate;
|
||||
}
|
||||
|
||||
get dateFrom() {
|
||||
return this.startDate ? deserializeDate(this.startDate): undefined;
|
||||
}
|
||||
|
||||
get dateTo() {
|
||||
return this.endDate ? deserializeDate(this.endDate): undefined;
|
||||
}
|
||||
|
||||
// 设置筛选字段的值
|
||||
setActiveValues(ev) {
|
||||
const value = ev.target.value;
|
||||
if (ev.target.id === this.props.id + "_start_date") {
|
||||
setActiveValues(dateValue, type) {
|
||||
const value = dateValue ? (this.props.type === "datetime" ? dateValue.toFormat("yyyy-MM-dd HH:mm:ss") : dateValue.toFormat("yyyy-MM-dd")) : undefined;
|
||||
if (type === "startDate") {
|
||||
this.startDate = value
|
||||
}
|
||||
if (ev.target.id === this.props.id + "_end_date") {
|
||||
if (type === "endDate") {
|
||||
this.endDate = value
|
||||
}
|
||||
}
|
||||
@@ -41,9 +50,14 @@ export class DateFilter extends Component {
|
||||
return domain
|
||||
}
|
||||
|
||||
// 点击日期选择器时触发
|
||||
dateOnchange(ev) {
|
||||
this.setActiveValues(ev);
|
||||
startDateOnchange (startDate) {
|
||||
this.setActiveValues(startDate, "startDate");
|
||||
this.props.fieldOnchange({fieldDomainList: this.domain, startDate: this.startDate, endDate: this.endDate});
|
||||
|
||||
}
|
||||
|
||||
endDateOnchange (endDate) {
|
||||
this.setActiveValues(endDate, "endDate");
|
||||
this.props.fieldOnchange({fieldDomainList: this.domain, startDate: this.startDate, endDate: this.endDate});
|
||||
}
|
||||
|
||||
@@ -67,6 +81,9 @@ export class DateFilter extends Component {
|
||||
}
|
||||
|
||||
DateFilter.template = "header_search_panel.DateFilter";
|
||||
DateFilter.components = {
|
||||
DateTimeInput,
|
||||
};
|
||||
DateFilter.props = {
|
||||
...standardFieldFilterProps,
|
||||
};
|
||||
|
||||
+26
-19
@@ -5,26 +5,33 @@
|
||||
<t t-name="header_search_panel.DateFilter" owl="1">
|
||||
<!-- 选择字段选择项 -->
|
||||
<div class="date-filter">
|
||||
<input
|
||||
type="date"
|
||||
t-attf-id="{{ props.id + '_start_date' }}"
|
||||
name="start_date"
|
||||
t-att-value="this.startDate"
|
||||
t-on-change="dateOnchange"/>
|
||||
<input
|
||||
type="date"
|
||||
t-attf-id="{{ props.id + '_end_date' }}"
|
||||
name="end_date"
|
||||
t-att-value="this.endDate"
|
||||
t-on-change="dateOnchange"/>
|
||||
<DateTimeInput value="dateFrom"
|
||||
type="props.type"
|
||||
onChange.bind="startDateOnchange"/>
|
||||
<i class="oi oi-arrow-right"/>
|
||||
<DateTimeInput value="dateTo"
|
||||
type="props.type"
|
||||
onChange.bind="endDateOnchange"/>
|
||||
<!-- <input -->
|
||||
<!-- t-att-type="props.type" -->
|
||||
<!-- t-attf-id="{{ props.id + '_start_date' }}" -->
|
||||
<!-- name="start_date" -->
|
||||
<!-- t-att-value="this.startDate" -->
|
||||
<!-- t-on-change="dateOnchange"/> -->
|
||||
<!-- <input -->
|
||||
<!-- t-att-type="props.type" -->
|
||||
<!-- t-attf-id="{{ props.id + '_end_date' }}" -->
|
||||
<!-- name="end_date" -->
|
||||
<!-- t-att-value="this.endDate" -->
|
||||
<!-- t-on-change="dateOnchange"/> -->
|
||||
</div>
|
||||
<div class="fast-date-filter">
|
||||
<a href="#" id="one-month" t-on-click="() => this.setDateRange(1)">近1个月</a>
|
||||
<a href="#" id="three-months" t-on-click="() => this.setDateRange(3)">近3个月</a>
|
||||
<a href="#" id="half-year" t-on-click="() => this.setDateRange(6)">近半年</a>
|
||||
<a href="#" id="one-year" t-on-click="() => this.setDateRange(12)">近1年</a>
|
||||
<a href="#" id="two-years" t-on-click="() => this.setDateRange(24)">近2年</a>
|
||||
</div>
|
||||
<!-- <div class="fast-date-filter"> -->
|
||||
<!-- <a href="#" id="one-month" t-on-click="() => this.setDateRange(1)">近1个月</a> -->
|
||||
<!-- <a href="#" id="three-months" t-on-click="() => this.setDateRange(3)">近3个月</a> -->
|
||||
<!-- <a href="#" id="half-year" t-on-click="() => this.setDateRange(6)">近半年</a> -->
|
||||
<!-- <a href="#" id="one-year" t-on-click="() => this.setDateRange(12)">近1年</a> -->
|
||||
<!-- <a href="#" id="two-years" t-on-click="() => this.setDateRange(24)">近2年</a> -->
|
||||
<!-- </div> -->
|
||||
</t>
|
||||
|
||||
</templates>
|
||||
|
||||
+15
@@ -8,6 +8,7 @@ import { BooleanFilter } from "./boolean_filter/boolean_filter";
|
||||
import { DateFilter } from "./date_filter/date_filter";
|
||||
import { Many2oneFilter } from "./many2one_filter/many2one_filter";
|
||||
import { X2ManyFilterFilter } from "./x2many_filter/x2many_filter";
|
||||
import { CharFilter } from "./char_filter/char_filter";
|
||||
|
||||
const fieldRegistry = registry.category("fields");
|
||||
|
||||
@@ -41,6 +42,9 @@ export class FieldsFilter extends Component {
|
||||
case "one2many":
|
||||
this.addX2ManyFieldDependencies(fieldInfo)
|
||||
break;
|
||||
case "char":
|
||||
this.addCharFieldDependencies(fieldInfo)
|
||||
break;
|
||||
}
|
||||
return fieldInfo;
|
||||
}
|
||||
@@ -65,6 +69,9 @@ export class FieldsFilter extends Component {
|
||||
case "many2many":
|
||||
case "one2many":
|
||||
return X2ManyFilterFilter;
|
||||
case "char":
|
||||
return CharFilter;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -128,6 +135,7 @@ export class FieldsFilter extends Component {
|
||||
domain: field.fieldDomain || "[]",
|
||||
fieldString: field.fieldString,
|
||||
searchLimit: field.fieldOptions?.search_limit || 10,
|
||||
placeholder: field.placeholder,
|
||||
}
|
||||
this._addFieldBaseProps(field.props, field);
|
||||
}
|
||||
@@ -144,6 +152,13 @@ export class FieldsFilter extends Component {
|
||||
this._addFieldBaseProps(field.props, field);
|
||||
}
|
||||
|
||||
addCharFieldDependencies(field) {
|
||||
field.Component = this._getComponent(field);
|
||||
// 组件props
|
||||
field.props = {};
|
||||
this._addFieldBaseProps(field.props, field);
|
||||
}
|
||||
|
||||
// 筛选字段的onChange事件,将筛选字段的id和domain传给searchModel
|
||||
fieldFilterOnchange(fieldsFilterId, fieldsFilterInfo) {
|
||||
if (fieldsFilterInfo?.fieldDomainList){
|
||||
|
||||
+1
@@ -104,6 +104,7 @@ export class Many2oneFilter extends Component {
|
||||
activeActions: {create: false, createEdit: false, write: false},
|
||||
fieldString: this.props.fieldString,
|
||||
searchLimit: this.props.searchLimit,
|
||||
placeholder: this.props.placeholder,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
+2
@@ -13,4 +13,6 @@ export const standardFieldFilterProps = {
|
||||
type: {type: String, required: true},
|
||||
// 字段变换监听函数
|
||||
fieldOnchange: { type: Function, required: true },
|
||||
// 提示
|
||||
placeholder: {type: String, optional: true},
|
||||
};
|
||||
|
||||
+2
-2
@@ -2,11 +2,11 @@
|
||||
<templates xml:space="preserve">
|
||||
<!-- 快速筛选组件 -->
|
||||
<t t-name="header_search_panel.QuickFilter" owl="1">
|
||||
<!-- <div t-if="props.showLabel" class="header-filter-label">
|
||||
<div t-if="props.showLabel" class="header-filter-label">
|
||||
<span>
|
||||
<t t-esc="props.string" />
|
||||
</span>
|
||||
</div> -->
|
||||
</div>
|
||||
<!-- quick filter 内的筛选循环 -->
|
||||
<div class="header-filter-value">
|
||||
<div class="selection-options">
|
||||
|
||||
@@ -74,10 +74,12 @@
|
||||
.fast-date-filter {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
input[type="date"],
|
||||
.o_datetime_input,
|
||||
.fast-date-filter a {
|
||||
width: auto;
|
||||
margin: 0.2rem;
|
||||
padding: 0.1rem 1rem;
|
||||
border: 0.1rem solid $o-community-color; /* 将边框颜色改为黑色 */
|
||||
@@ -149,6 +151,14 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.header-search-inline {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
align-items: start;
|
||||
gap: 5px;
|
||||
}
|
||||
|
||||
.header_search_toggle {
|
||||
width: 6rem;
|
||||
height: 2rem;
|
||||
@@ -161,4 +171,4 @@
|
||||
line-height: 2rem;
|
||||
margin-left: 0.5rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -165,6 +165,8 @@ patch(SearchArchParser.prototype, {
|
||||
const fieldString = node.getAttribute("string");
|
||||
// 自定义css类
|
||||
const cssClass = node.getAttribute("class");
|
||||
// placeholder
|
||||
const placeholder = node.getAttribute("placeholder");
|
||||
// 获取字段的options属性,该属性代表字段选项
|
||||
const fieldOptions = evaluateExpr(node.getAttribute("options") || "{}");
|
||||
// 获取widget
|
||||
@@ -173,7 +175,7 @@ patch(SearchArchParser.prototype, {
|
||||
if (fieldName) {
|
||||
const field = this.fields[fieldName];
|
||||
// 如果字段类型为selection或者bool,将字段名和选项添加到headerSearchInfo的fields中
|
||||
if (!["selection", "boolean", "date", "datetime", "many2one", "one2many", "many2many"].includes(field.type)) {
|
||||
if (!["selection", "boolean", "date", "datetime", "many2one", "one2many", "many2many", "char"].includes(field.type)) {
|
||||
return false;
|
||||
}
|
||||
const fieldInfo = {
|
||||
@@ -186,6 +188,7 @@ patch(SearchArchParser.prototype, {
|
||||
fieldOptions: fieldOptions,
|
||||
modifiers: JSON.parse(node.getAttribute("modifiers") || "{}"),
|
||||
class: cssClass,
|
||||
placeholder: placeholder || undefined,
|
||||
}
|
||||
if (["many2one", "many2many"].includes(field.type)) {
|
||||
fieldInfo.fieldDomain = node.getAttribute("domain");
|
||||
@@ -237,17 +240,16 @@ patch(SearchArchParser.prototype, {
|
||||
for (const node of headerSearchNode.children) {
|
||||
switch (node.tagName) {
|
||||
case "field":
|
||||
// // 字段筛选
|
||||
// this.visitHeaderField(node);
|
||||
// 字段筛选
|
||||
this.visitHeaderField(node);
|
||||
break;
|
||||
case "quick_filter":
|
||||
// 快捷筛选
|
||||
this.visitHeaderQuickFilter(node);
|
||||
break;
|
||||
case "select_date_filter":
|
||||
// // 自选日期筛选
|
||||
// this.visitHeaderSelectDateFilter(node);
|
||||
break;
|
||||
// 自选日期筛选
|
||||
this.visitHeaderSelectDateFilter(node);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
|
||||
@@ -244,7 +244,7 @@
|
||||
<field name="type">ir.actions.act_window</field>
|
||||
<field name="res_model">soong.workflow.record</field>
|
||||
<field name="view_mode">tree,form,search</field>
|
||||
<field name="context">{'search_default_group_by_group_soong_state': True,}</field>
|
||||
<field name="context">{'search_default_group_by_group_soong_state': True, 'search_default_group_by_workflow_id': True}</field>
|
||||
<field name="domain">[('reclaim_state', '=', False)]</field>
|
||||
<field name="search_view_id" ref="soong_workflow_record_search1"/>
|
||||
<field name="view_id" ref="soong_workflow_record_tree"/>
|
||||
|
||||
@@ -314,6 +314,8 @@ class HolidaysRequestBatch(models.Model):
|
||||
is_issues = fields.Boolean(string='是否上会')
|
||||
work_end = fields.Boolean(string="结束")
|
||||
issues_result = fields.Html(string="会议结果")
|
||||
entrusted_agent_id = fields.Many2one('res.users', string="委托代理人")
|
||||
is_entrusted = fields.Boolean(string="是否生成工作流委托")
|
||||
leave_by_hour = fields.Boolean(string='请假单位(小时)', default=False)
|
||||
leave_by_day = fields.Boolean(string='请假单位(天)', default=True)
|
||||
urgency_level = fields.Selection([('normal', '普件'), ('urgent', '急件'), ('emergency', '特急件')], string='紧急度',
|
||||
@@ -357,6 +359,22 @@ class HolidaysRequestBatch(models.Model):
|
||||
|
||||
# 提交
|
||||
def action_submit(self):
|
||||
if self.is_entrusted:
|
||||
leave_batch_model = self.env['ir.model'].search(
|
||||
[('model', '=', 'hr.leave.batch')],
|
||||
limit=1
|
||||
)
|
||||
entrust_vals = {
|
||||
'model_ids': [(6, 0, [leave_batch_model.id])],
|
||||
'entrust_user_id': self.users_id.id,
|
||||
'entrust_user_id2': self.entrusted_agent_id.id,
|
||||
'is_expiration_date': True,
|
||||
'start_date': fields.Date.today(),
|
||||
'end_date': False,
|
||||
'entrust_notice': True,
|
||||
}
|
||||
self.env['soong.workflow.entrust'].create(entrust_vals)
|
||||
|
||||
self.leave_ids.action_validate()
|
||||
self.hour_leave_ids.action_validate()
|
||||
"""提交请假申请,区分年假和其他假期处理"""
|
||||
|
||||
@@ -44,6 +44,9 @@
|
||||
<field name="is_back" invisible="1"/>
|
||||
<field name="name"/>
|
||||
<field name="users_id" options="{'no_create': True}"/>
|
||||
<field name="department_id" invisible="1"/>
|
||||
<field name="entrusted_agent_id" domain="[('employee_id.department_id', '=', department_id)]" />
|
||||
<field name="is_entrusted" invisible="not entrusted_agent_id"/>
|
||||
<field name="days" invisible="1"/>
|
||||
<field name="employee_id" invisible="1" force_save="1"/>
|
||||
<field name="text"/>
|
||||
@@ -239,7 +242,6 @@
|
||||
</form>
|
||||
</field>
|
||||
<group>
|
||||
<field name="department_id" invisible="1"/>
|
||||
<field name="user_role_id" invisible="1"/>
|
||||
<field name="is_issues" invisible="1"/>
|
||||
<field name="start_date" invisible="1"/>
|
||||
|
||||
@@ -814,16 +814,17 @@ class HrAttendance(models.Model):
|
||||
if is_executive:
|
||||
domain = [('current_data', '=', current_date)]
|
||||
attendances = self.env['hr.attendance'].search(domain)
|
||||
attended_employee_ids = attendances.mapped('employee_id')
|
||||
for employee in attended_employee_ids:
|
||||
if is_check_in:
|
||||
is_card = self.env['hr.attendance'].search([('employee_id', '=', employee.id), ('check_in', '!=', False), ('current_data', '=', current_date)], limit=1)
|
||||
if not is_card:
|
||||
self.card_in_comment(employee, '行政班次')
|
||||
else:
|
||||
is_card = self.env['hr.attendance'].search([('employee_id', '=', employee.id), ('check_out', '!=', False), ('current_data', '=', current_date)], limit=1)
|
||||
if not is_card:
|
||||
self.card_out_comment(employee, '行政班次')
|
||||
if self._process_shift_days(current_date): # 如果是工作日则提醒
|
||||
attended_employee_ids = attendances.mapped('employee_id')
|
||||
for employee in attended_employee_ids:
|
||||
if is_check_in:
|
||||
is_card = self.env['hr.attendance'].search([('employee_id', '=', employee.id), ('check_in', '!=', False), ('current_data', '=', current_date)], limit=1)
|
||||
if not is_card:
|
||||
self.card_in_comment(employee, '行政班次')
|
||||
else:
|
||||
is_card = self.env['hr.attendance'].search([('employee_id', '=', employee.id), ('check_out', '!=', False), ('current_data', '=', current_date)], limit=1)
|
||||
if not is_card:
|
||||
self.card_out_comment(employee, '行政班次')
|
||||
else:
|
||||
slot_start = datetime.combine(current_date, datetime.min.time())
|
||||
slot_end = datetime.combine(current_date + timedelta(days=1), datetime.min.time())
|
||||
|
||||
@@ -40,6 +40,7 @@
|
||||
</h1>
|
||||
</div>
|
||||
<group string="审批事项">
|
||||
<field name="is_back" invisible="1"/>
|
||||
<field name="name" required="1"/>
|
||||
<field name="company_id" invisible="1"/>
|
||||
<field name="issue_text"/>
|
||||
|
||||
@@ -70,13 +70,15 @@ class ProcessingOrderApproval(models.Model):
|
||||
|
||||
name_title = fields.Char(default=_get_default_name_title)
|
||||
|
||||
@api.depends("company_id")
|
||||
@api.depends("company_id", "repair_id", "device_id", "property_id")
|
||||
def _compute_name(self):
|
||||
self.name = False
|
||||
if self.repair_id:
|
||||
self.name = self.property_id.name + '-处理单'
|
||||
if self.device_id:
|
||||
self.name = self.device_id.name + '-处理单'
|
||||
for record in self:
|
||||
if record.repair_id and record.property_id:
|
||||
record.display_name = f"{record.property_id.name}-处理单"
|
||||
elif record.device_id:
|
||||
record.display_name = f"{record.device_id.name}-处理单"
|
||||
else:
|
||||
record.display_name = False
|
||||
|
||||
@api.depends('property_id')
|
||||
def _compute_contract_id(self):
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
<field name="software_processing_id"/>
|
||||
<field name="report_state"/>
|
||||
<field name="create_time"/>
|
||||
<button name="pull_order" string="提交" type="object" class="btn-primary"/>
|
||||
</tree>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
<field name="leader_id"/>
|
||||
<field name="report_state"/>
|
||||
<field name="create_time"/>
|
||||
<button name="pull_order" string="提交" type="object" class="btn-primary"/>
|
||||
</tree>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
@@ -262,6 +262,8 @@ class MeterArchivesLine(models.Model):
|
||||
type = fields.Selection([("public", "公共"), ("fees", "收费")], string="类型")
|
||||
employee_ids = fields.Many2many("hr.employee", string="抄表人")
|
||||
remarks = fields.Text(string="备注")
|
||||
is_fix_loss = fields.Selection([('yes', '有'), ('no', '无')], default="yes", string="有无线损")
|
||||
is_fix_price = fields.Selection([('yes', '是'), ('no', '否')], default="no", string="是否固定单价")
|
||||
archives_state = fields.Selection([("stop", "停用"), ("use", "正常"), ("rent", "出租")], string="状态", default="use",)
|
||||
state = fields.Selection([("reading", "已抄"), ("unreading", "未抄")], string="抄表状态", default="unreading",)
|
||||
maximum_count = fields.Integer(string="最大位数")
|
||||
|
||||
@@ -227,6 +227,8 @@ class MeterWaterLine(models.Model):
|
||||
remarks = fields.Text(string='备注')
|
||||
employee_ids = fields.Many2many('hr.employee', string='抄表人')
|
||||
maximum_count = fields.Integer(string='最大位数')
|
||||
is_fix_loss = fields.Selection([('yes', '有'), ('no', '无')], default="yes", string="有无线损")
|
||||
is_fix_price = fields.Selection([('yes', '是'), ('no', '否')], default="no", string="是否固定单价")
|
||||
is_push = fields.Boolean(string='推送', default=False)
|
||||
|
||||
@api.model_create_multi
|
||||
|
||||
@@ -37,6 +37,44 @@
|
||||
</tree>
|
||||
</field>
|
||||
</record>
|
||||
<!-- 押金对账列表-->
|
||||
<record id="view_property_accounts_receivable_tree1" model="ir.ui.view">
|
||||
<field name="name">property.accounts.receivable.tree</field>
|
||||
<field name="model">property.accounts.receivable</field>
|
||||
<field name="arch" type="xml">
|
||||
<tree editable="bottom" string="应收账单" decoration-success="is_reconciliation == True" limit="15" delete="false">
|
||||
<field name="acc_type" string=" "/>
|
||||
<field name="management_type_id" readonly="0"/>
|
||||
<field name="due_date" readonly="0" width="300px" required="1"/>
|
||||
<field name="due_date_end" readonly="0"/>
|
||||
<field name="payout_date" readonly="0"/>
|
||||
<field name="original_amount" readonly="0"/>
|
||||
<field name="discount_amount" readonly="0"/>
|
||||
<field name="delivered1" readonly="0"/>
|
||||
<field name="submitted" options='{"fg_color": "red: submitted != false;" }'/>
|
||||
<field name="number_of_payments"/>
|
||||
<field name="remark"/>
|
||||
<field name="multiplier" column_invisible="1"/>
|
||||
<field name="is_push" optional="hide" readonly="0"/>
|
||||
<field name="reconciliation_time" optional="hide" readonly="0"/>
|
||||
<field name="create_time" readonly="0"/>
|
||||
<field name="last_update_time" optional="hide" readonly="0"/>
|
||||
<field name="is_invalid" column_invisible="1"/>
|
||||
<field name="void_date" column_invisible="1"/>
|
||||
<field name="is_red" column_invisible="1"/>
|
||||
<field name="is_reconciliation" optional="hide"/>
|
||||
<field name="difference_amount" readonly="0"/>
|
||||
<field name="receivable_log" column_invisible="1"/>
|
||||
<field name="is_suspend" optional="hide"/>
|
||||
<field name="is_write" column_invisible="1"/>
|
||||
<field name="bank_id" column_invisible="1"/>
|
||||
<field name="print_number"/>
|
||||
<field name="print_date"/>
|
||||
<field name="discount_date"/>
|
||||
<field name="has_date"/>
|
||||
</tree>
|
||||
</field>
|
||||
</record>
|
||||
<record id="all_property_accounts_receivable_contract" model="ir.actions.server">
|
||||
<field name="name">导入应收初始化数据</field>
|
||||
<field name="model_id" ref="yuthon_property.model_property_accounts_receivable"/>
|
||||
|
||||
@@ -118,6 +118,8 @@
|
||||
<field name="last_meter" string="上次抄表日期"/>
|
||||
<field name="last_dosage" string="上次用量"/>
|
||||
<field name="is_push"/>
|
||||
<field name="is_fix_loss" column_invisible="1"/>
|
||||
<field name="is_fix_price" column_invisible="1"/>
|
||||
<field name="number" column_invisible="1"/>
|
||||
<field name="sequence" column_invisible="1"/>
|
||||
<field name="meter_date_month" column_invisible="1"/>
|
||||
|
||||
@@ -120,6 +120,8 @@
|
||||
<field name="last_meter" string="上次抄表日期"/>
|
||||
<field name="last_dosage" string="上次用量"/>
|
||||
<field name="is_push"/>
|
||||
<field name="is_fix_loss" column_invisible="1"/>
|
||||
<field name="is_fix_price" column_invisible="1"/>
|
||||
<field name="number" column_invisible="1"/>
|
||||
<field name="sequence" column_invisible="1"/>
|
||||
<field name="initial_value" column_invisible="1"/>
|
||||
|
||||
@@ -36,6 +36,17 @@ class ElectricWaterWizard(models.TransientModel):
|
||||
else:
|
||||
contract_line = False
|
||||
|
||||
electric_id = self.env['property.electric.fee.line'].search([
|
||||
('property_meter_archives_id', '=', meter.id),
|
||||
('contract_id', '!=', False),
|
||||
], limit=1)
|
||||
if electric_id:
|
||||
is_fix_loss = electric_id.is_fix_loss
|
||||
is_fix_price = electric_id.is_fix_price
|
||||
else:
|
||||
is_fix_loss = 'yes'
|
||||
is_fix_price = 'no'
|
||||
|
||||
# 查找上个月的记录
|
||||
# 查找上个月的记录,上次用量,上次读数,上次抄表日期
|
||||
last_month_line = meter.line_ids.search([('meter_date', '<', self.push_date)]).sorted('meter_date')[-1]
|
||||
@@ -46,6 +57,8 @@ class ElectricWaterWizard(models.TransientModel):
|
||||
meter.line_ids.create({
|
||||
'archives_id': meter.id,
|
||||
'is_acc': is_acc,
|
||||
'is_fix_loss':is_fix_loss,
|
||||
'is_fix_price':is_fix_price,
|
||||
'last_meter': last_month_line.last_meter,
|
||||
'last_read': last_month_line.last_read,
|
||||
'last_dosage': last_month_line.last_dosage,
|
||||
@@ -87,6 +100,16 @@ class ElectricWaterWizard(models.TransientModel):
|
||||
else:
|
||||
contract_line = False
|
||||
|
||||
water_id = self.env['property.water.fee.line'].search([('property_meter_water_id', '=', water.id),
|
||||
('contract_id', '!=', False),
|
||||
], limit=1)
|
||||
if water_id:
|
||||
is_fix_loss = water_id.is_fix_loss
|
||||
is_fix_price = water_id.is_fix_price
|
||||
else:
|
||||
is_fix_loss = 'yes'
|
||||
is_fix_price = 'no'
|
||||
|
||||
# 查找上个月的记录,上次用量,上次读数,上次抄表日期
|
||||
last_month_line = water.line_ids.search([('meter_date', '<', self.push_date)]).sorted('meter_date')[-1]
|
||||
# 如果当前数据不存在,则新建任务,按照天的纬度
|
||||
@@ -94,6 +117,8 @@ class ElectricWaterWizard(models.TransientModel):
|
||||
if not self_month_line:
|
||||
water.line_ids.create({
|
||||
'water_id': water.id,
|
||||
'is_fix_loss': is_fix_loss,
|
||||
'is_fix_price': is_fix_price,
|
||||
'last_meter': last_month_line.last_meter,
|
||||
'last_read': last_month_line.last_read,
|
||||
'last_dosage': last_month_line.last_dosage,
|
||||
|
||||
@@ -33,7 +33,6 @@ class MeterPriceWizard(models.TransientModel):
|
||||
('select_time', '=', str(last_month)),
|
||||
('meter_type', '=', 'electric')
|
||||
], limit=1)
|
||||
|
||||
# 3. 赋值价格
|
||||
self.price = logs_id.price if logs_id else 0.0
|
||||
self.line_loss = logs_id.line_loss if logs_id else 0.0
|
||||
@@ -74,7 +73,7 @@ class MeterPriceWizard(models.TransientModel):
|
||||
|
||||
valid.write({
|
||||
'unit': unit,
|
||||
'line_loss': self.line_loss
|
||||
'line_loss': self.line_loss if valid.is_fix_loss == 'yes' else 0
|
||||
})
|
||||
valid.onchange_receivables()
|
||||
|
||||
|
||||
@@ -75,7 +75,7 @@ class WaterPriceWizard(models.TransientModel):
|
||||
|
||||
valid.write({
|
||||
'unit': unit,
|
||||
'line_loss': self.line_loss,
|
||||
'line_loss': self.line_loss if valid.is_fix_loss == 'yes' else 0
|
||||
})
|
||||
valid.onchange_receivables()
|
||||
|
||||
|
||||
@@ -97,6 +97,7 @@
|
||||
'wizard/action_refuse_wizard_views.xml',
|
||||
'wizard/property_bills_wizard_views.xml',
|
||||
'wizard/property_meeting_wizard_views.xml',
|
||||
'wizard/property_deposit_wizard_views.xml',
|
||||
'views/property_menu_all.xml',
|
||||
],
|
||||
|
||||
|
||||
@@ -617,6 +617,53 @@ class PropertyAccountsReceivable(models.Model):
|
||||
actual_coping = fields.Float(string="实际应付", compute='_compute_actual_coping', store=True)
|
||||
charging_range = fields.Text(string="收费区间")
|
||||
|
||||
def verification_wizard(self):
|
||||
receivable_lines = self.env['property.accounts.receivable'].search([
|
||||
('contract_id', '=', self.contract_id.id),
|
||||
('is_reconciliation', '=', False),
|
||||
])
|
||||
receivable_line_vals = []
|
||||
for line in receivable_lines:
|
||||
receivable_line_vals.append((0, 0, {
|
||||
'due_date': line.due_date,
|
||||
'management_type_id': line.management_type_id.id,
|
||||
'amount': line.submitted,
|
||||
'payment_type': 'pay',
|
||||
'receivable_id': line.id,
|
||||
'remake': line.remark,
|
||||
}))
|
||||
|
||||
bills_lines = self.env['property.bills.list'].search([
|
||||
('contract_id', '=', self.contract_id.id),
|
||||
('actual_date', '!=', False),
|
||||
])
|
||||
bills_line_vals = []
|
||||
for line in bills_lines:
|
||||
bills_line_vals.append((0, 0, {
|
||||
'due_date': line.due_date,
|
||||
'management_type_id': line.management_type_id.id,
|
||||
'amount': line.amount,
|
||||
'bills_id': line.id,
|
||||
'payment_type': 'spending',
|
||||
'remake': line.remake
|
||||
}))
|
||||
all_line_vals = receivable_line_vals + bills_line_vals
|
||||
return {
|
||||
"type": "ir.actions.act_window",
|
||||
"name": "押金核销弹窗",
|
||||
"res_model": "property.deposit.wizard",
|
||||
"view_mode": "form",
|
||||
"target": "new",
|
||||
"context": {
|
||||
"default_contract_id": self.contract_id.id,
|
||||
"default_lessee_id": self.lessee_id.id,
|
||||
"default_actual_date": self.due_date,
|
||||
"default_deposit": self.original_amount,
|
||||
'default_reconciliation_line_ids': all_line_vals
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@api.depends('contract_id', 'due_date')
|
||||
def compute_tenure_type(self):
|
||||
for record in self:
|
||||
|
||||
@@ -614,7 +614,16 @@ class PropertyLeaseContract(models.Model):
|
||||
contract_ids = self.env["property.lease.contract"].browse(
|
||||
self._context.get('active_ids', self._context.get('active_id')))
|
||||
for rec in contract_ids:
|
||||
rec.onchange_lease_ids()
|
||||
if rec.electricity_fee_ids:
|
||||
for line in rec.electricity_fee_ids:
|
||||
line.is_fix_loss = 'yes'
|
||||
if line.unit_price > 0:
|
||||
line.is_fix_price = 'yes'
|
||||
if rec.water_fee_ids:
|
||||
for line in rec.water_fee_ids:
|
||||
line.is_fix_loss = 'yes'
|
||||
if line.unit_price > 0:
|
||||
line.is_fix_price = 'yes'
|
||||
|
||||
def update_admin_id(self):
|
||||
contract_ids = self.env["property.lease.contract"].browse(
|
||||
@@ -2421,15 +2430,14 @@ class PropertyWaterFeeLine(models.Model):
|
||||
start_date = fields.Date(related='contract_id.term_start_time', string="开始日期")
|
||||
end_date = fields.Date(related='contract_id.term_end_time', string="结束日期")
|
||||
unit_price = fields.Float(string='固定单价', digits=(16, 4))
|
||||
line_loss = fields.Float(string='线损')
|
||||
is_fix_loss = fields.Selection([('yes', '有'), ('no', '无')], default="yes", string="有无线损")
|
||||
is_fix_price = fields.Selection([('yes', '是'), ('no', '否')], default="no", string="是否固定单价")
|
||||
epitope_values_id = fields.Many2one(related='property_meter_water_id.epitope_values_id', string="表位置")
|
||||
|
||||
@api.constrains('line_loss')
|
||||
def _check_line_loss(self):
|
||||
for rec in self:
|
||||
if rec.property_meter_water_id.line_ids:
|
||||
for line in rec.property_meter_water_id.line_ids:
|
||||
line.line_loss = rec.line_loss
|
||||
@api.onchange('is_fix_price')
|
||||
def _onchange_is_fix_price(self):
|
||||
if self.is_fix_price == 'no':
|
||||
self.unit_price = 0
|
||||
|
||||
|
||||
class PropertyElectricFeeLine(models.Model):
|
||||
@@ -2443,16 +2451,14 @@ class PropertyElectricFeeLine(models.Model):
|
||||
start_date = fields.Date(related='contract_id.term_start_time', string="开始日期")
|
||||
end_date = fields.Date(related='contract_id.term_end_time', string="结束日期")
|
||||
unit_price = fields.Float(string='固定单价', digits=(16, 4))
|
||||
line_loss = fields.Float(string='线损')
|
||||
is_fix_loss = fields.Selection([('yes', '有'), ('no', '无')], default="no", string="有无线损")
|
||||
is_fix_price = fields.Selection([('yes', '是'),('no', '否')], default="no", string="是否固定单价")
|
||||
epitope_values_id = fields.Many2one(related='property_meter_archives_id.epitope_values_id', string="表位置")
|
||||
|
||||
@api.constrains('line_loss')
|
||||
def _check_line_loss(self):
|
||||
for rec in self:
|
||||
if rec.property_meter_archives_id.line_ids:
|
||||
for line in rec.property_meter_archives_id.line_ids:
|
||||
line.line_loss = rec.line_loss
|
||||
|
||||
@api.onchange('is_fix_price')
|
||||
def _onchange_is_fix_price(self):
|
||||
if self.is_fix_price == 'no':
|
||||
self.unit_price = 0
|
||||
|
||||
class PropertyOtherFeeLine(models.Model):
|
||||
_name = 'property.other.fee.line'
|
||||
|
||||
@@ -60,11 +60,22 @@ class PropertyLeaseRenewal(models.Model):
|
||||
deposit = fields.Float(string="原押金")
|
||||
is_full_refund = fields.Boolean(string="是否全额退押", default=True)
|
||||
refund_amount = fields.Float(string="退款金额")
|
||||
refund_remake = fields.Char(string="备注")
|
||||
total_receivables = fields.Float(string="应收金额", compute="_compute_total_receivables")
|
||||
total_remake = fields.Char(string="备注")
|
||||
balance = fields.Float(string="余额")
|
||||
remake = fields.Text(string="备注")
|
||||
balance_remake = fields.Char(string="备注")
|
||||
|
||||
receivables_ids = fields.One2many('early.receivables.line', 'renewal_id', string='应收明细')
|
||||
|
||||
@api.depends('receivables_ids', 'receivables_ids.original_amount', 'receivables_ids.reduction_amount',
|
||||
'receivables_ids.void')
|
||||
def _compute_total_receivables(self):
|
||||
for renewal in self:
|
||||
valid_receivable_lines = renewal.receivables_ids.filtered(lambda line: not line.void and line.is_reconciliation == False)
|
||||
total = sum(line.original_amount - line.reduction_amount for line in valid_receivable_lines)
|
||||
renewal.total_receivables = total
|
||||
|
||||
@api.onchange('refund_amount')
|
||||
def _onchange_refund_amount(self):
|
||||
for rec in self:
|
||||
@@ -177,19 +188,30 @@ class PropertyLeaseRenewal(models.Model):
|
||||
'contract_id': new_contract.id
|
||||
})
|
||||
else:
|
||||
receivable_ids = self.env['property.accounts.receivable'].search([
|
||||
('due_date', '<=', rec.early_quitting_date),
|
||||
('contract_id', '=', rec.contract_id.id),
|
||||
])
|
||||
# receivable_ids = self.env['property.accounts.receivable'].search([
|
||||
# ('due_date', '<=', rec.early_quitting_date),
|
||||
# ('contract_id', '=', rec.contract_id.id),
|
||||
# ])
|
||||
# if any(not receivable.is_reconciliation for receivable in receivable_ids):
|
||||
# raise UserError("该合同下存在未对账的应收单,无法提前退押金")
|
||||
|
||||
rec.contract_id.write({
|
||||
'actual_end_time': rec.early_quitting_date
|
||||
})
|
||||
rec.contract_id.get_property_contract_time()
|
||||
# rec.contract_id.get_property_contract_time()
|
||||
if rec.balance > rec.total_receivables:
|
||||
management_type_id = self.env['yuthon.management.type'].search([
|
||||
('name', '=', '违约金')
|
||||
])
|
||||
self.env['property.accounts.receivable'].create({
|
||||
'contract_id': rec.contract_id.id,
|
||||
'management_type_id': management_type_id.id,
|
||||
'due_date': rec.early_quitting_date,
|
||||
'original_amount': rec.balance - rec.total_receivables,
|
||||
'remark': rec.total_remake,
|
||||
})
|
||||
if rec.receivables_ids:
|
||||
refund_lines = rec.receivables_ids.filtered(lambda l: l.refund_amount > 0)
|
||||
refund_lines = rec.receivables_ids.filtered(lambda l: l.refund_amount > 0 and management_type_id.name != '押金')
|
||||
bills_line_list = []
|
||||
# 除押金的明细
|
||||
if refund_lines:
|
||||
@@ -199,7 +221,7 @@ class PropertyLeaseRenewal(models.Model):
|
||||
'management_type_id': refund_line.management_type_id.id,
|
||||
'amount': refund_line.refund_amount,
|
||||
'contract_id': rec.contract_id.id,
|
||||
'remake': rec.remake
|
||||
'remake': rec.refund_remake
|
||||
})
|
||||
# 押金
|
||||
deposit_management_type = self.env['yuthon.management.type'].search(
|
||||
@@ -213,7 +235,7 @@ class PropertyLeaseRenewal(models.Model):
|
||||
'management_type_id': deposit_management_type.id,
|
||||
'amount': deposit_amount,
|
||||
'contract_id': rec.contract_id.id,
|
||||
'remake': rec.remake
|
||||
'remake': rec.refund_remake
|
||||
})
|
||||
|
||||
if not rec.is_full_refund:
|
||||
@@ -222,7 +244,7 @@ class PropertyLeaseRenewal(models.Model):
|
||||
'start_time': start_time,
|
||||
'original_amount': rec.balance,
|
||||
'name_account': rec.lessee_id.name,
|
||||
'remake': rec.remake,
|
||||
'remake': rec.refund_remake,
|
||||
})
|
||||
|
||||
# 创建应付账单
|
||||
@@ -233,19 +255,16 @@ class PropertyLeaseRenewal(models.Model):
|
||||
for receivable_id in rec.receivables_ids:
|
||||
if receivable_id.void:
|
||||
receivable_id.receivable_id.write({
|
||||
'is_void': True,
|
||||
'is_invalid': True,
|
||||
'void_date': fields.Date.today()
|
||||
})
|
||||
if receivable_id.reduction_amount:
|
||||
receivable_id.receivable_id.reduction_amount = receivable_id.reduction_amount
|
||||
receivable_id.receivable_id.discount_amount = receivable_id.reduction_amount
|
||||
receivable_id.receivable_id.discount_date = fields.Date.today()
|
||||
|
||||
@api.onchange('early_quitting_date', 'contract_id')
|
||||
def _onchange_early_quitting_date(self):
|
||||
if not self.early_quitting_date :
|
||||
self.receivables_ids = [(5, 0, 0)]
|
||||
return
|
||||
|
||||
self.receivables_ids = [(5, 0, 0)]
|
||||
receivable_ids = self.env['property.accounts.receivable'].search([
|
||||
('due_date', '<=', self.early_quitting_date),
|
||||
('contract_id', '=', self.contract_id.id),
|
||||
|
||||
@@ -122,4 +122,6 @@ access_property_payment_notice,property_payment_notice,model_property_payment_no
|
||||
access_print_payment_wizard,print_payment_wizard,model_print_payment_wizard,base.group_user,1,1,1,1
|
||||
access_property_bills_list,property_bills_list,model_property_bills_list,base.group_user,1,1,1,1
|
||||
access_property_bills_wizard,property_bills_wizard,model_property_bills_wizard,base.group_user,1,1,1,1
|
||||
access_action_refuse_wizard,action_refuse_wizard,model_action_refuse_wizard,base.group_user,1,1,1,1
|
||||
access_action_refuse_wizard,action_refuse_wizard,model_action_refuse_wizard,base.group_user,1,1,1,1
|
||||
access_property_deposit_wizard,property_deposit_wizard,model_property_deposit_wizard,base.group_user,1,1,1,1
|
||||
access_deposit_reconciliation_line,deposit_reconciliation_line,model_deposit_reconciliation_line,base.group_user,1,1,1,1
|
||||
|
@@ -408,6 +408,35 @@
|
||||
<field name="this_month_table" column_invisible="1"/>
|
||||
<field name="ratio" column_invisible="1"/>
|
||||
<field name="billable_quantity" column_invisible="1"/>
|
||||
<!-- <field name="company_id1"/>-->
|
||||
<field name="contract_id" string="合同编号"/>
|
||||
</xpath>
|
||||
<xpath expr="//field[@name='receivable_log']" position="after">
|
||||
<field name="penalty"/>
|
||||
<field name="penalty_date"/>
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
<record id="inherit_property_accounts_receivable_form_tree" model="ir.ui.view">
|
||||
<field name="name">property.accounts.receivable.tree</field>
|
||||
<field name="model">property.accounts.receivable</field>
|
||||
<field name="inherit_id" ref="yuthon_property.view_property_accounts_receivable_tree1"/>
|
||||
<field name="arch" type="xml">
|
||||
<xpath expr="//field[@name='has_date']" position="before">
|
||||
<button name="verification_wizard" string="核销" type="object" class="btn btn-primary"/>
|
||||
</xpath>
|
||||
<xpath expr="//field[@name='remark']" position="after">
|
||||
<field name="charging_range"/>
|
||||
<field name="is_penalty" column_invisible="1"/>
|
||||
<field name="property_name" width="350px"/>
|
||||
<field name="property_ids" options="{'no_create': True}" widget="many2many_tags" column_invisible="1"/>
|
||||
<field name="lessee_id" options="{'no_create': True}" readonly="1"/>
|
||||
<field name="title_deed" readonly="1"/>
|
||||
<field name="company_id" column_invisible="1"/>
|
||||
<field name="last_month_table" column_invisible="1"/>
|
||||
<field name="this_month_table" column_invisible="1"/>
|
||||
<field name="ratio" column_invisible="1"/>
|
||||
<field name="billable_quantity" column_invisible="1"/>
|
||||
<!-- <field name="company_id1"/>-->
|
||||
<field name="contract_id" string="合同编号"/>
|
||||
</xpath>
|
||||
@@ -467,6 +496,15 @@
|
||||
<field name="search_view_id" ref="view_property_accounts_receivable_search"/>
|
||||
<field name="view_id" ref="yuthon_property.view_property_accounts_receivable_tree"/>
|
||||
</record>
|
||||
<record id="accounts_receivable_deposit_action" model="ir.actions.act_window">
|
||||
<field name="name">押金列表</field>
|
||||
<field name="res_model">property.accounts.receivable</field>
|
||||
<field name="view_mode">tree</field>
|
||||
<field name="context">{'search_default_group_by_contract_id': True}</field>
|
||||
<field name="domain">[('management_type_id.name','=', '押金')]</field>
|
||||
<field name="search_view_id" ref="view_property_accounts_receivable_search"/>
|
||||
<field name="view_id" ref="yuthon_property.view_property_accounts_receivable_tree1"/>
|
||||
</record>
|
||||
<!-- 合同应收报表 -->
|
||||
<record id="view_property_accounts_receivable_report_tree" model="ir.ui.view">
|
||||
<field name="name">property.accounts.receivable.tree.form</field>
|
||||
|
||||
@@ -279,8 +279,9 @@
|
||||
<field name="unit_number"/>
|
||||
<field name="property_meter_water_id" options="{'no_open': True}"/>
|
||||
<field name="rate"/>
|
||||
<field name="line_loss"/>
|
||||
<field name="unit_price"/>
|
||||
<field name="is_fix_loss"/>
|
||||
<field name="is_fix_price"/>
|
||||
<field name="unit_price" readonly="is_fix_price == 'no'"/>
|
||||
<field name="start_date"/>
|
||||
<field name="end_date"/>
|
||||
</tree>
|
||||
@@ -294,8 +295,9 @@
|
||||
<field name="unit_number"/>
|
||||
<field name="property_meter_archives_id" options="{'no_open': True}"/>
|
||||
<field name="rate"/>
|
||||
<field name="line_loss"/>
|
||||
<field name="unit_price"/>
|
||||
<field name="is_fix_loss"/>
|
||||
<field name="is_fix_price"/>
|
||||
<field name="unit_price" readonly="is_fix_price == 'no'"/>
|
||||
<field name="start_date"/>
|
||||
<field name="end_date"/>
|
||||
</tree>
|
||||
@@ -819,8 +821,9 @@
|
||||
<field name="unit_number"/>
|
||||
<field name="property_meter_water_id" options="{'no_open': True}"/>
|
||||
<field name="rate"/>
|
||||
<field name="line_loss"/>
|
||||
<field name="unit_price"/>
|
||||
<field name="is_fix_loss"/>
|
||||
<field name="is_fix_price"/>
|
||||
<field name="unit_price" readonly="is_fix_price == 'no'"/>
|
||||
<field name="start_date"/>
|
||||
<field name="end_date"/>
|
||||
</tree>
|
||||
@@ -833,9 +836,9 @@
|
||||
<field name="epitope_values_id"/>
|
||||
<field name="unit_number"/>
|
||||
<field name="property_meter_archives_id" options="{'no_open': True}"/>
|
||||
<field name="rate"/>
|
||||
<field name="line_loss"/>
|
||||
<field name="unit_price"/>
|
||||
<field name="is_fix_loss"/>
|
||||
<field name="is_fix_price"/>
|
||||
<field name="unit_price" readonly="is_fix_price == 'no'"/>
|
||||
<field name="start_date"/>
|
||||
<field name="end_date"/>
|
||||
</tree>
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
<form string="租赁变更审批" create="0">
|
||||
<sheet>
|
||||
<widget name="web_ribbon" title="普件" bg_color="text-bg-success"
|
||||
invisible="urgency_level != 'normal'"/>
|
||||
invisible="urgency_level != 'normal'"/>
|
||||
<widget name="web_ribbon" title="急件" bg_color="text-bg-warning"
|
||||
invisible="urgency_level != 'urgent'"/>
|
||||
<widget name="web_ribbon" title="特级" bg_color="text-bg-danger"
|
||||
@@ -41,7 +41,7 @@
|
||||
<group string="审批事项">
|
||||
<field name="is_back" invisible="1"/>
|
||||
<field name="name" required="1"/>
|
||||
<field name="renewal_type" widget="radio"/>
|
||||
<field name="renewal_type" widget="radio"/>
|
||||
<field name="company_id" invisible="1"/>
|
||||
<field name="department_id" invisible="1"/>
|
||||
<field name="work_end" invisible="1"/>
|
||||
@@ -83,34 +83,63 @@
|
||||
<field name="phone" invisible="renewal_type != 'lease'"/>
|
||||
</group>
|
||||
</group>
|
||||
<group>
|
||||
<field name="reason" invisible="renewal_type != 'lease'"/>
|
||||
<field name="effective_date" invisible="renewal_type != 'lease'"/>
|
||||
<field name="early_reason" invisible="renewal_type != 'early_checkout'"/>
|
||||
<field name="deposit" invisible="renewal_type != 'early_checkout'"/>
|
||||
<field name="is_full_refund" invisible="renewal_type != 'early_checkout'"/>
|
||||
</group>
|
||||
<group col="4">
|
||||
<group>
|
||||
<field name="reason" invisible="renewal_type != 'lease'"/>
|
||||
<field name="effective_date" invisible="renewal_type != 'lease'"/>
|
||||
<field name="early_reason" invisible="renewal_type != 'early_checkout'"/>
|
||||
<field name="deposit" invisible="renewal_type != 'early_checkout'"/>
|
||||
<field name="is_full_refund" invisible="renewal_type != 'early_checkout'"/>
|
||||
<field name="refund_amount" invisible="is_full_refund"/>
|
||||
<field name="balance" invisible="is_full_refund"/>
|
||||
<field name="remake" invisible="is_full_refund"/>
|
||||
<field name="early_explain" invisible="renewal_type != 'early_checkout'"/>
|
||||
<field name="document_ids" widget="preview_many2many"/>
|
||||
</group>
|
||||
<group>
|
||||
<field name="refund_remake" invisible="not refund_amount"/>
|
||||
</group>
|
||||
<group/>
|
||||
<group/>
|
||||
</group>
|
||||
<group col="4">
|
||||
<group>
|
||||
<field name="balance" invisible="is_full_refund"/>
|
||||
</group>
|
||||
<group>
|
||||
<field name="balance_remake" invisible="not balance"/>
|
||||
</group>
|
||||
<group/>
|
||||
<group/>
|
||||
</group>
|
||||
<group col="4">
|
||||
<group>
|
||||
<field name="total_receivables" invisible="is_full_refund"/>
|
||||
</group>
|
||||
<group>
|
||||
<field name="total_remake" invisible="not total_receivables"/>
|
||||
</group>
|
||||
<group/>
|
||||
<group/>
|
||||
</group>
|
||||
<group>
|
||||
<field name="early_explain" invisible="renewal_type != 'early_checkout'"/>
|
||||
<field name="document_ids" widget="preview_many2many"/>
|
||||
</group>
|
||||
<notebook>
|
||||
<page string="应收明细" invisible="renewal_type != 'early_checkout'">
|
||||
<field name="receivables_ids" string=" ">
|
||||
<tree editable="bottom">
|
||||
<field name="renewal_id" column_invisible="1"/>
|
||||
<field name="receivable_id" column_invisible="1"/>
|
||||
<field name="management_type_id"/>
|
||||
<field name="due_date"/>
|
||||
<field name="original_amount"/>
|
||||
<field name="reduction_amount"/>
|
||||
<field name="refund_amount"/>
|
||||
<field name="is_reconciliation"/>
|
||||
<field name="void"/>
|
||||
</tree>
|
||||
<field name="receivables_ids" string=" ">
|
||||
<tree editable="bottom">
|
||||
<field name="renewal_id" column_invisible="1"/>
|
||||
<field name="receivable_id" column_invisible="1"/>
|
||||
<field name="management_type_id"/>
|
||||
<field name="due_date"/>
|
||||
<field name="original_amount"/>
|
||||
<field name="reduction_amount"/>
|
||||
<field name="refund_amount"/>
|
||||
<field name="is_reconciliation"/>
|
||||
<field name="void"/>
|
||||
</tree>
|
||||
</field>
|
||||
</page>
|
||||
</page>
|
||||
</notebook>
|
||||
</sheet>
|
||||
</form>
|
||||
|
||||
@@ -14,4 +14,5 @@ from . import build_pop_wizard
|
||||
from . import penalty_line_wizard
|
||||
from . import print_payment_wizard
|
||||
from . import property_bills_wizard
|
||||
from . import action_refuse_wizard
|
||||
from . import action_refuse_wizard
|
||||
from . import property_deposit_wizard
|
||||
@@ -0,0 +1,68 @@
|
||||
from odoo import models, fields, api, _, SUPERUSER_ID
|
||||
from datetime import datetime, timedelta
|
||||
from dateutil.relativedelta import relativedelta
|
||||
from odoo.exceptions import UserError, ValidationError
|
||||
import re
|
||||
|
||||
import logging
|
||||
_logger = logging.getLogger(__name__)
|
||||
|
||||
class PropertyDepositWizard(models.Model):
|
||||
_name = 'property.deposit.wizard'
|
||||
_description = '押金核销'
|
||||
|
||||
lessee_id = fields.Many2one('property.tenant.information', string='承租方')
|
||||
contract_id = fields.Many2one('property.lease.contract', string='合同')
|
||||
property_name = fields.Char(related="contract_id.property_name", string='物业信息')
|
||||
actual_date = fields.Date(string='核销日期')
|
||||
|
||||
deposit = fields.Float(string='押金')
|
||||
reconciliation_line_ids = fields.One2many('deposit.reconciliation.line', 'reconciliation_id', string='对账明细')
|
||||
|
||||
def confirm(self):
|
||||
for record in self:
|
||||
reconciliation_lines = record.reconciliation_line_ids
|
||||
total_amount = sum(line.amount for line in reconciliation_lines)
|
||||
total_write_amount = sum(line.write_amount for line in reconciliation_lines)
|
||||
|
||||
amount_equal = abs(total_amount - total_write_amount) < 1e-6
|
||||
for line in reconciliation_lines:
|
||||
if line.write_amount:
|
||||
if line.receivable_id:
|
||||
if line.write_amount == line.amount:
|
||||
line.receivable_id.is_reconciliation = True
|
||||
else:
|
||||
line.receivable_id.yes_amount += line.write_amount
|
||||
if line.bills_id:
|
||||
line.bills_id.actual_date = record.actual_date
|
||||
line.bills_id.amount_actual = line.write_amount
|
||||
if amount_equal:
|
||||
if record.contract_id:
|
||||
record.contract_id.contact_state = 'settle'
|
||||
record.has_date = record.actual_date
|
||||
record.bills_list_id.contract_id.compute_is_has()
|
||||
|
||||
|
||||
class DepositReconciliationLine(models.Model):
|
||||
_name = 'deposit.reconciliation.line'
|
||||
_description = '押金对账明细'
|
||||
_order = 'due_date desc'
|
||||
|
||||
reconciliation_id = fields.Many2one('property.deposit.wizard', string='关联押金对账单弹窗')
|
||||
receivable_id = fields.Many2one('property.accounts.receivable', string='关联应收账单')
|
||||
bill_id = fields.Many2one('property.bills.list', string='关联应付账单')
|
||||
|
||||
due_date = fields.Date(string='应收日期')
|
||||
management_type_id = fields.Many2one('yuthon.management.type', string='类型')
|
||||
payment_type = fields.Selection([('pay', '支付'), ('spending', '支出')], string='收付款类型')
|
||||
amount = fields.Float(string='金额', store=True)
|
||||
write_amount = fields.Float(string='核销金额')
|
||||
remake = fields.Text(string='备注')
|
||||
|
||||
@api.onchange('write_amount')
|
||||
def onchange_remake(self):
|
||||
for line in self:
|
||||
if line.write_amount and line.payment_type == 'pay' and line.management_type_id.name != '违约金':
|
||||
line.remake = '押金转'+ line.management_type_id.name
|
||||
elif line.write_amount and line.payment_type == 'spending':
|
||||
line.remake = '退' + line.management_type_id.name
|
||||
@@ -0,0 +1,50 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<odoo>
|
||||
<record id="property_deposit_wizard_form" model="ir.ui.view">
|
||||
<field name="name">property.deposit.wizard.form</field>
|
||||
<field name="model">property.deposit.wizard</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="押金核销">
|
||||
<sheet>
|
||||
<div class="oe_title">
|
||||
<label for="actual_date"/>
|
||||
<h1>
|
||||
<field name="actual_date" style="font-weight: bold; color: #000000;" force_save="1"/>
|
||||
</h1>
|
||||
</div>
|
||||
<group col="3">
|
||||
<group>
|
||||
<field name="property_name" readonly="1"/>
|
||||
</group>
|
||||
<group>
|
||||
<field name="lessee_id" readonly="1"/>
|
||||
</group>
|
||||
<group>
|
||||
<field name="contract_id" readonly="1"/>
|
||||
</group>
|
||||
</group>
|
||||
<group>
|
||||
<field name="deposit"/>
|
||||
</group>
|
||||
<field name="reconciliation_line_ids">
|
||||
<tree editable="bottom">
|
||||
<field name="reconciliation_id" column_invisible="1"/>
|
||||
<field name="receivable_id" column_invisible="1"/>
|
||||
<field name="bill_id" column_invisible="1"/>
|
||||
<field name="management_type_id"/>
|
||||
<field name="due_date"/>
|
||||
<field name="payment_type"/>
|
||||
<field name="amount"/>
|
||||
<field name="write_amount"/>
|
||||
<field name="remake"/>
|
||||
</tree>
|
||||
</field>
|
||||
<footer>
|
||||
<button type="object" name="confirm" string="确认" class="oe_highlight"/>
|
||||
<button special="cancel" string="取消" class="btn-secondary"/>
|
||||
</footer>
|
||||
</sheet>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
</odoo>
|
||||
@@ -12,7 +12,7 @@
|
||||
<field name="actual_date" style="font-weight: bold; color: #000000;" readonly="1" force_save="1"/>
|
||||
</h1>
|
||||
</div>
|
||||
<group col="4">
|
||||
<group col="3">
|
||||
<group>
|
||||
<field name="lessee_ids" widget="many2many_tags" readonly="1"/>
|
||||
</group>
|
||||
@@ -22,7 +22,6 @@
|
||||
<group>
|
||||
<field name="remake" readonly="1"/>
|
||||
</group>
|
||||
<group/>
|
||||
</group>
|
||||
<group>
|
||||
<field name="bank_id" invisible="1"/>
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
from odoo import api, fields, models, _
|
||||
import re
|
||||
from pypinyin import pinyin, Style
|
||||
from datetime import date
|
||||
|
||||
from datetime import date, datetime
|
||||
|
||||
|
||||
class HrPayrollStructure(models.Model):
|
||||
@@ -18,7 +17,7 @@ class HrPayrollStructure(models.Model):
|
||||
sequence = fields.Char(string='级别序号', store=True)
|
||||
create_time = fields.Date(string="生效日期", default=fields.Date.today())
|
||||
end_time = fields.Date(string="失效日期")
|
||||
is_enable = fields.Boolean(string="启用", default=True)
|
||||
is_enable = fields.Boolean(string="启用", compute= "_compute_is_enable", store=True)
|
||||
currency_id = fields.Many2one("res.currency", string="货币", required=True, default=lambda self: self.env.company.currency_id)
|
||||
base_salary = fields.Monetary(string="基本工资", currency_field="currency_id")
|
||||
rank_salary = fields.Monetary(string="职级工资", currency_field="currency_id")
|
||||
@@ -29,6 +28,17 @@ class HrPayrollStructure(models.Model):
|
||||
advance_performance_bonuses = fields.Monetary(string="预发绩效奖金", currency_field="currency_id")
|
||||
renk_log_ids = fields.One2many("rank.log.line", "structure_id", string="职级日志明细行")
|
||||
|
||||
@api.depends('create_time', 'end_time')
|
||||
def _compute_is_enable(self):
|
||||
today = fields.Date.today()
|
||||
for record in self:
|
||||
if not record.create_time:
|
||||
record.is_enable = False
|
||||
elif not record.end_time:
|
||||
record.is_enable = record.create_time <= today
|
||||
else:
|
||||
record.is_enable = record.create_time <= today <= record.end_time
|
||||
|
||||
@api.model
|
||||
def read_group(self, domain, fields, groupby, offset=0, limit=None, orderby=False, lazy=True):
|
||||
res = super(HrPayrollStructure, self).read_group(domain, fields, groupby, offset=offset, limit=limit, orderby=orderby,
|
||||
@@ -196,6 +206,7 @@ class HrPayrollStructure(models.Model):
|
||||
for rule in payroll.rule_ids:
|
||||
rule.sudo().unlink()
|
||||
|
||||
|
||||
def update_payroll_items(self):
|
||||
payroll_ids = self.env["hr.payroll.structure"].browse(
|
||||
self._context.get('active_ids', self._context.get('active_id')))
|
||||
@@ -238,14 +249,12 @@ class HrPayrollStructure(models.Model):
|
||||
payroll.renk_log_ids.unlink()
|
||||
|
||||
def onetime(self):
|
||||
dec_2025_start = datetime(2025, 10, 31).date()
|
||||
payroll_ids = self.env["hr.payroll.structure"].browse(
|
||||
self._context.get('active_ids', self._context.get('active_id')))
|
||||
for payroll in payroll_ids:
|
||||
create_time = payroll.renk_log_ids[-1].effective_date
|
||||
payroll.write({
|
||||
'create_time': create_time,
|
||||
})
|
||||
|
||||
payroll.end_time = dec_2025_start
|
||||
payroll.is_enable = False
|
||||
|
||||
def rank_log_time(self):
|
||||
"""定时任务:根据日志记录的生效时间更新主模型字段值"""
|
||||
|
||||
@@ -1,5 +1,10 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<odoo>
|
||||
<record model="ir.rule" id="hr_payroll_structure_type_rule">
|
||||
<field name="name">职级类型多公司</field>
|
||||
<field name="model_id" ref="model_hr_payroll_structure_type"/>
|
||||
<field name="domain_force">[('company_id', 'in', company_ids)]</field>
|
||||
</record>
|
||||
<record model="ir.rule" id="salary_payroll_distribution_rule">
|
||||
<field name="name">薪资方法多公司</field>
|
||||
<field name="model_id" ref="model_salary_payroll_distribution"/>
|
||||
|
||||
@@ -100,6 +100,7 @@
|
||||
<field name="arch" type="xml">
|
||||
<search string="职级查询">
|
||||
<field name="name"/>
|
||||
<filter name="is_enable" string="启用" domain="[('is_enable', '=', True)]"/>
|
||||
<group expand="0">
|
||||
<filter name="group_date" string="查询年月" context="{'group_by': 'create_time'}"/>
|
||||
<filter name="group_lv_name" string="级别" context="{'group_by': 'lv_name'}"/>
|
||||
@@ -112,7 +113,7 @@
|
||||
<field name="name">职级</field>
|
||||
<field name="res_model">hr.payroll.structure</field>
|
||||
<field name="view_mode">tree,form,search</field>
|
||||
<!-- <field name="context">{'group_by_no_leaf':1,'group_by':[]}</field>-->
|
||||
<field name="context">{'search_default_is_enable':1}</field>
|
||||
</record>
|
||||
<record id="all_paroll_write_salary" model="ir.actions.server">
|
||||
<field name="name">批量更新职级类型</field>
|
||||
|
||||
@@ -24,19 +24,7 @@ class YuthonPayrollWizard(models.Model):
|
||||
sh = book.sheet_by_index(0)
|
||||
for rx in range(1, sh.nrows):
|
||||
row = sh.row(rx)
|
||||
self.yuthon_payroll_wg_data(row)
|
||||
# if sh.row(1)[6].value == 'thtz':
|
||||
# salary_rule_model = self.env['hr.salary.rule']
|
||||
# all_rules = salary_rule_model.search([])
|
||||
# all_rules.unlink()
|
||||
# for rx in range(1, sh.nrows):
|
||||
# row = sh.row(rx)
|
||||
# if row[6].value == 'thtz':
|
||||
# self.yuthon_payroll_tt_data(row)
|
||||
# elif row[6].value == 'thwg':
|
||||
# self.yuthon_payroll_wg_data(row)
|
||||
# elif row[6].value == 'thlc':
|
||||
# self.yuthon_payroll_lc_data(row)
|
||||
self.yuthon_payroll_lc_data(row)
|
||||
|
||||
def yuthon_payroll_tt_data(self, row):
|
||||
type_id = self.env['hr.payroll.structure.type'].search([('name', '=', row[0].value)], limit=1)
|
||||
@@ -72,17 +60,54 @@ class YuthonPayrollWizard(models.Model):
|
||||
})
|
||||
|
||||
def yuthon_payroll_lc_data(self, row):
|
||||
type_id = self.env['hr.payroll.structure.type'].search([('name', '=', row[0].value)], limit=1)
|
||||
base_salary = row[1].value
|
||||
position_subsidy = row[2].value
|
||||
position_salary = row[3].value
|
||||
advance_performance_bonuses = row[4].value
|
||||
payroll_id = self.env['hr.payroll.structure'].search(
|
||||
[('type_id', '=', type_id.id)])
|
||||
if payroll_id:
|
||||
payroll_id.write({
|
||||
'base_salary': base_salary,
|
||||
'position_salary': position_salary,
|
||||
'position_subsidy': position_subsidy,
|
||||
'advance_performance_bonuses': advance_performance_bonuses,
|
||||
})
|
||||
# 1. 获取传入的行数据
|
||||
type_name = row[0].value
|
||||
base_salary = float(row[1].value) if row[1].value else 0.0
|
||||
rank_salary = float(row[2].value) if row[2].value else 0.0
|
||||
advance_performance_bonuses = float(row[3].value) if row[3].value else 0.0
|
||||
|
||||
# 2. 查询薪资结构类型
|
||||
type_id = self.env['hr.payroll.structure.type'].search([('name', '=', type_name)], limit=1)
|
||||
if not type_id:
|
||||
# 可选:添加日志提示类型不存在
|
||||
self.env.user.notify_warning(message=f"未找到薪资结构类型:{type_name}")
|
||||
return
|
||||
|
||||
# 3. 查找“天河粮储”公司的任意hr.payroll.structure记录
|
||||
# 先找到公司(根据公司名称搜索,可替换为公司编码更精准)
|
||||
target_company = self.env['res.company'].search([('name', '=', '天河粮储')], limit=1)
|
||||
if not target_company:
|
||||
self.env.user.notify_warning(message="未找到名称为「天河粮储」的公司")
|
||||
return
|
||||
|
||||
source_structure = self.env['hr.payroll.structure'].search(
|
||||
[('company_id.name', '=', target_company.id)],
|
||||
limit=1 # 取任意一条
|
||||
)
|
||||
copied_salary_rules = []
|
||||
source_salary_rules = source_structure.rule_ids
|
||||
for rule in source_salary_rules:
|
||||
rule_vals = rule.copy_data()[0]
|
||||
for field in ['id', 'create_uid', 'create_date', 'write_uid', 'write_date']:
|
||||
rule_vals.pop(field, None)
|
||||
copied_salary_rules.append((0, 0, rule_vals))
|
||||
|
||||
new_structure = self.env['hr.payroll.structure'].create({
|
||||
'name': type_name,
|
||||
'type_id': type_id.id,
|
||||
'company_id': target_company.id,
|
||||
'rule_ids': copied_salary_rules,
|
||||
})
|
||||
salary_rule_mapping = {
|
||||
'基本工资': base_salary,
|
||||
'职级工资': rank_salary,
|
||||
'预发绩效奖金': advance_performance_bonuses
|
||||
}
|
||||
for rule_name, target_value in salary_rule_mapping.items():
|
||||
target_rule = new_structure.rule_ids.search(
|
||||
[('name', '=', rule_name), ('structure_id', '=', new_structure.id)],
|
||||
limit=1
|
||||
)
|
||||
if target_rule:
|
||||
target_rule.write({'amount_fix': target_value})
|
||||
|
||||
|
||||
@@ -874,7 +874,7 @@
|
||||
sequence="50"/>
|
||||
<menuitem id="yuthon_accounts_receivable_menu"
|
||||
sequence="1"
|
||||
name="应收账单(明细)"
|
||||
name="应收账单"
|
||||
parent="yuthon_financial_management_menu"
|
||||
action="yuthon_property_approval.property_accounts_receivable_action"/>
|
||||
<!-- <menuitem-->
|
||||
@@ -889,8 +889,14 @@
|
||||
name="应付账单"
|
||||
action="yuthon_property_approval.view_property_bills_list_action"
|
||||
sequence="4"/>
|
||||
<menuitem
|
||||
id="accounts_receivable_deposit_menu"
|
||||
parent="yuthon_financial_management_menu"
|
||||
name="押金列表"
|
||||
action="yuthon_property_approval.accounts_receivable_deposit_action"
|
||||
sequence="10"/>
|
||||
<menuitem id="yuthon_subject_form_menu"
|
||||
sequence="5"
|
||||
sequence="15"
|
||||
name="预算科目表"
|
||||
parent="yuthon_financial_management_menu"
|
||||
action="yuthon_property.view_property_subject_action"/>
|
||||
|
||||
Reference in New Issue
Block a user