This commit is contained in:
夜未央
2025-09-12 00:14:48 +08:00
55 changed files with 1090 additions and 351 deletions
+109 -1
View File
@@ -4,6 +4,7 @@ from odoo import models, fields, api, _
from odoo.exceptions import ValidationError, UserError
import logging
from datetime import datetime, date, time, timedelta
import re
_logger = logging.getLogger(__name__)
@@ -52,7 +53,114 @@ class SoongWorkflowRecord(models.Model):
member_of_department = fields.Boolean("是否是本部门数据", compute='_compute_part_of_department', search='_search_part_of_department')
def admin_end(self):
pass
workflow_ids = self.env["soong.workflow.record"].browse(
self._context.get('active_ids', self._context.get('active_id', []))
)
current_datetime = fields.Datetime.now()
for workflow in workflow_ids:
record_id = self.env[workflow.res_model].search([('id', '=', workflow.res_id)])
if hasattr(record_id, 'user_id') and record_id.user_id:
user_id = record_id.user_id
elif hasattr(record_id, 'users_id') and record_id.users_id:
user_id = record_id.users_id
if not record_id:
continue
# 触发模型对应的结束方法
end_node = self.env["soong.workflow.node"].search(
[('workflow_id', '=', workflow.workflow_id.id), ('is_end', '=', True)],
limit=1
)
end_btn = self.env["soong.workflow.node.button"].search(
[('node_id', '=', end_node.id),
('name', '=', '结束')],
limit=1
)
if end_btn:
self.execute_button_code(end_btn.id, workflow.res_model, workflow.res_id)
node_id = self.env["soong.workflow.node"].search(
[('workflow_id', '=', workflow.workflow_id.id),
('name', '=', record_id.state)],
limit=1
)
# 修改日志
log_records = None
if record_id.log_ids2:
log_records = record_id.log_ids2
elif record_id.log_ids:
log_records = record_id.log_ids
log_model = "soong.workflow.log"
if record_id.log_ids2:
log_model = "soong.workflow.log2"
elif record_id.log_ids:
log_model = "soong.workflow.log"
if log_records:
log_records[-1].write({
'approval_state': '3',
'lase_click_date': current_datetime,
})
else:
self.env[log_model].create({
'done_by': user_id.id,
'node_id': node_id.id if node_id else False,
'workflow_id': workflow.workflow_id.id,
'model': workflow.res_model,
'res_id': workflow.res_id,
'approval_state': '3',
'lase_click_date': current_datetime,
'sequence': 99,
})
workflow.approve_state = 'end'
def execute_button_code(self, button_id, res_model, res_id):
"""
执行按钮code字段中的代码,动态解析并验证方法是否存在
:param button_id: soong.workflow.node.button的记录ID
:param res_model: 模型名称
"""
button = self.env["soong.workflow.node.button"].browse(button_id)
if not button or not button.code:
return
workflow = button.node_id.workflow_id if button.node_id else None
obj = self.env[res_model].browse(res_id)
if not obj:
raise UserError(f"找不到{res_model}模型中ID为{res_id}的记录")
# 从code中提取obj调用的方法名(匹配obj.xxx()格式)
method_match = re.search(r'obj\.(\w+)\(\)', button.code)
if not method_match:
raise UserError("该按钮没有配置结束的方法,请先配置!")
# 准备代码执行的上下文环境
local_context = {
'time': time,
'date': date,
'datetime': datetime,
'timedelta': timedelta,
'env': self.env,
'model': self.env[res_model],
'obj': obj,
'user': self.env.user,
'workflow': workflow,
'syslog': self._log_debug,
'warning': self._get_warning_exception,
'action': None
}
exec(button.code, globals(), local_context)
# 如果有返回的action,处理它
if local_context.get('action'):
return local_context['action']
def _log_debug(self, message):
"""用于syslog的实现"""
self.env.logger.debug(message)
def _get_warning_exception(self, message):
"""用于warning的实现"""
return Warning(message)
def update_self_users_ids(self):
record_ids = self.env["soong.workflow.record"].browse(
@@ -64,7 +64,7 @@
decoration-danger="approve_state == 'end'" delete="false"
create="false" default_order="write_date2 desc, id desc" expand="1">
<header>
<button name="admin_end" type="object" string="管理员强制结束" class="oe_highlight"/>
<button name="admin_end" type="object" string="管理员强制结束" class="oe_highlight" groups="soong_workflow.group_soong_workflow_manager"/>
<button name="delete_record" type="object" string="删除" class="oe_highlight" groups="soong_workflow.group_soong_workflow_manager"/>
</header>
<field name="code"/>
@@ -172,7 +172,7 @@
<field name="type">ir.actions.act_window</field>
<field name="res_model">soong.workflow.record</field>
<field name="view_mode">tree,kanban,search</field>
<field name="domain">[('reclaim_state', '=', False), '|', ('approvals_group_id.name', '=', '人力资源'), ('approvals_group_id.name', '=', '考勤')]</field>
<field name="domain">[('reclaim_state', '=', False), '|', ('approvals_group_id.name', '=', '人力资源'), ('approvals_group_id.name', '=', '考勤'), ('approve_state', '!=', 'start')]</field>
<field name="search_view_id" ref="soong_workflow_record_search"/>
</record>
<record id="soong_workflow_other_record_action" model="ir.actions.act_window">
@@ -24,7 +24,7 @@ class SoongWorkflowCommentWizard(models.TransientModel):
node_link_len = fields.Char(string="转交2")
is_supervising = fields.Boolean(string="是否督办")
comment_note_id = fields.Many2one('soong.note', string="常用意见", default='妥否,呈领导审批')
comment_note = fields.Char(string="意见")
comment_note = fields.Char(string="意见", default='同意')
comment = fields.Char(compute='_compute_comment', store=True)
state_list = fields.Char(string="状态列表")
record_id = fields.Integer()
@@ -492,13 +492,54 @@ class SoongWorkflowCommentWizard(models.TransientModel):
related_record.self_users_ids = [(6, 0, user_ids)] if user_ids else [(5,)]
return self.node_btn_id.with_context(cx).run()
if self.node_btn_name == '结束':
record_id.log_ids[-1].comment = self.comment
record_id.log_ids[-1].approval_state = "3"
record_id.log_ids[-1].lase_click_date = fields.Datetime.now()
record_id.work_end = True
self.env['soong.workflow.record'].search([('code', '=', record_id.code)]).write({'approve_state': 'end',
"employee_ids": False,
"node_id": False,})
current_user = self.env.user
current_datetime = fields.Datetime.now()
log_records = record_id.log_ids
if record_id.log_ids2:
log_records = record_id.log_ids2
elif record_id.log_ids:
log_records = record_id.log_ids
if log_records:
# 查找当前用户的日志记录并更新
user_log = log_records.filtered(lambda log: log.done_by == current_user)
if user_log:
user_log.write({
'comment': self.comment,
'approval_state': "3",
'lase_click_date': current_datetime
})
last_log = log_records[-1] if log_records else None
if last_log:
same_name_logs = log_records.filtered(
lambda log: log.name == last_log.name
and log.node_btn_name == '4'
and log.id != last_log.id
)
# 判断是否需要更新工作流状态
if same_name_logs:
all_approved = all(log.approval_state == '3' for log in same_name_logs)
all_approved = all_approved and (last_log.approval_state == '3')
if all_approved:
# 所有符合条件的记录都已批准,更新工作流状态
self.env['soong.workflow.record'].search([
('code', '=', record_id.code)
]).write({
'approve_state': 'end',
'employee_ids': False,
'node_id': False,
})
record_id.work_end = True
else:
self.env['soong.workflow.record'].search([
('code', '=', record_id.code)
]).write({
'approve_state': 'end',
'employee_ids': False,
'node_id': False,
})
record_id.work_end = True
# 给申请人发消息
biz_record = self.env[self.res_model].browse(self.res_id)
@@ -17,33 +17,55 @@ class SoongWorkflowRecordDeleteWizard(models.TransientModel):
def add_comment(self):
for record in self.record_ids:
if self.name == "确认删除":
if record.reclaim_state is False:
self.env["soong.workflow.record"].sudo().search([("id", "=", record.id)]).write({
"reclaim_state": True
})
# 首先检查工作流记录是否存在
workflow_record = self.env["soong.workflow.record"].sudo().search([("id", "=", record.id)], limit=1)
if not workflow_record:
continue
# 删除假期额度里面的对应的流程记录
related_detail_models = [
'vacation.leave.line',
'vacation.over.line',
'vacation.meal.line',
'vacation.medical.line'
]
for model_name in related_detail_models:
detail_model = self.env[model_name].sudo()
related_detail_records = detail_model.search([
('workflow_record_id', '=', workflow_record.id)
])
if related_detail_records:
related_detail_records.unlink()
if not record.reclaim_state:
workflow_record.write({"reclaim_state": True})
# 处理工作流日志
log_ids = self.env["soong.workflow.log"].sudo().search([("code", "=", record.code)])
for log_id in log_ids:
log_id.sudo().write({
"active": False
})
target_model = self.env[record.res_model]
target_record = target_model.sudo().browse(record.res_id)
if target_model._name in ["hr.leave.batch"]:
if target_record.leave_ids:
for leave in target_record.leave_ids:
leave.sudo().with_context(from_cancel_wizard=True).write({
"state": "confirm",
"active": False
})
if target_record.hour_leave_ids:
for hour_leave in target_record.hour_leave_ids:
hour_leave.sudo().with_context(from_cancel_wizard=True).write({
"state": "confirm",
"active": False
})
target_record.write({'active': False})
log_id.sudo().write({"active": False})
if record.res_model and record.res_id:
target_model = self.env[record.res_model]
target_record = target_model.sudo().browse(record.res_id).exists()
if target_record:
if target_model._name in ["hr.leave.batch"]:
if target_record.leave_ids:
for leave in target_record.leave_ids:
leave.sudo().with_context(from_cancel_wizard=True).write({
"state": "confirm",
"active": False
})
if target_record.hour_leave_ids:
for hour_leave in target_record.hour_leave_ids:
hour_leave.sudo().with_context(from_cancel_wizard=True).write({
"state": "confirm",
"active": False
})
# 确保在写入前记录仍然存在
if target_record.exists():
target_record.write({'active': False})
else:
self.env["soong.workflow.record"].sudo().search(
[("id", "=", record.id), ('reclaim_state', "=", True)]).write({
"active": False
})
workflow_record = self.env["soong.workflow.record"].sudo().search(
[("id", "=", record.id), ('reclaim_state', "=", True)], limit=1)
if workflow_record:
workflow_record.write({"active": False})
File diff suppressed because one or more lines are too long
@@ -0,0 +1 @@
import{_ as e}from"./index-CimcMLIq.js";const r={};function c(n,t){return null}const o=e(r,[["render",c]]);export{o as default};
@@ -0,0 +1 @@
import{B as _,E as i,C as d,D as v}from"./requests-DdoUQiv8.js";import{_ as p,r as h,o as m,u as y,h as f,i as l,g as a,t,k,l as g}from"./index-CimcMLIq.js";const w=r=>_("/yuthon/yuthon/will/task",{id:r}),x={class:"container"},B={class:"meeting-header"},C={class:"title"},q={class:"time"},D={class:"location"},E={__name:"Journey",setup(r){const u=y(),e=h({});return m(async()=>{try{const s=parseInt(u.query.id),n=await w(s);e.value=n.data}catch(s){i("获取任务详情失败"),console.error(s)}}),(s,n)=>{const o=v,c=d;return g(),f("div",x,[l("div",B,[l("div",C,t(e.value.name),1),l("div",q,t(e.value.start_date)+" "+t(e.value.start_date_week)+" "+t(e.value.request_hour_from)+" - "+t(e.value.request_hour_to),1),l("div",D,"地址: "+t(e.value.address),1)]),a(c,null,{default:k(()=>[a(o,{title:"组织人",value:e.value.user_id},null,8,["value"]),a(o,{title:"参与人",value:"共"+(e.value.employee_ids?.length||0)+"人"},null,8,["value"]),a(o,{title:"描述",value:e.value.remarks},null,8,["value"]),a(o,{title:"任务编号",value:e.value.code},null,8,["value"])]),_:1})])}}},N=p(E,[["__scopeId","data-v-0aa7162a"]]);export{N as default};
File diff suppressed because one or more lines are too long
@@ -0,0 +1 @@
import{v as B,t as A,c as p,H as E,I as V,j as w,n as b,F as y,B as q,E as H,C as O,D as j}from"./requests-DdoUQiv8.js";import{d as x,g as a,T as G,F as I,s as K,_ as M,r as R,o as J,u as Q,h as S,i as f,t as k,k as P,l as C,p as U,q as W}from"./index-CimcMLIq.js";import{I as X}from"./index-BJ3ARmPk.js";const[Y,T]=p("tag"),Z={size:String,mark:Boolean,show:A,type:B("default"),color:String,plain:Boolean,round:Boolean,textColor:String,closeable:Boolean};var ee=x({name:Y,props:Z,emits:["close"],setup(t,{slots:e,emit:u}){const l=o=>{o.stopPropagation(),u("close",o)},r=()=>t.plain?{color:t.textColor||t.color,borderColor:t.color}:{color:t.textColor,background:t.color},d=()=>{var o;const{type:m,mark:i,plain:c,round:v,size:s,closeable:_}=t,g={mark:i,plain:c,round:v};s&&(g[s]=s);const h=_&&a(V,{name:"cross",class:[T("close"),E],onClick:l},null);return a("span",{style:r(),class:T([g,m])},[(o=e.default)==null?void 0:o.call(e),h])};return()=>a(G,{name:t.closeable?"van-fade":void 0},{default:()=>[t.show?d():null]})}});const te=w(ee),[ae,n]=p("card"),ne={tag:String,num:b,desc:String,thumb:String,title:String,price:b,centered:Boolean,lazyLoad:Boolean,currency:B("¥"),thumbLink:String,originPrice:b};var re=x({name:ae,props:ne,emits:["clickThumb"],setup(t,{slots:e,emit:u}){const l=()=>{if(e.title)return e.title();if(t.title)return a("div",{class:[n("title"),"van-multi-ellipsis--l2"]},[t.title])},r=()=>{if(e.tag||t.tag)return a("div",{class:n("tag")},[e.tag?e.tag():a(te,{mark:!0,type:"primary"},{default:()=>[t.tag]})])},d=()=>e.thumb?e.thumb():a(X,{src:t.thumb,fit:"cover",width:"100%",height:"100%",lazyLoad:t.lazyLoad},null),o=()=>{if(e.thumb||t.thumb)return a("a",{href:t.thumbLink,class:n("thumb"),onClick:c=>u("clickThumb",c)},[d(),r()])},m=()=>{if(e.desc)return e.desc();if(t.desc)return a("div",{class:[n("desc"),"van-ellipsis"]},[t.desc])},i=()=>{const c=t.price.toString().split(".");return a("div",null,[a("span",{class:n("price-currency")},[t.currency]),a("span",{class:n("price-integer")},[c[0]]),c.length>1&&a(I,null,[K("."),a("span",{class:n("price-decimal")},[c[1]])])])};return()=>{var c,v,s;const _=e.num||y(t.num),g=e.price||y(t.price),h=e["origin-price"]||y(t.originPrice),D=_||g||h||e.bottom,F=g&&a("div",{class:n("price")},[e.price?e.price():i()]),L=h&&a("div",{class:n("origin-price")},[e["origin-price"]?e["origin-price"]():`${t.currency} ${t.originPrice}`]),N=_&&a("div",{class:n("num")},[e.num?e.num():`x${t.num}`]),$=e.footer&&a("div",{class:n("footer")},[e.footer()]),z=D&&a("div",{class:n("bottom")},[(c=e["price-top"])==null?void 0:c.call(e),F,L,N,(v=e.bottom)==null?void 0:v.call(e)]);return a("div",{class:n()},[a("div",{class:n("header")},[o(),a("div",{class:n("content",{centered:t.centered})},[a("div",null,[l(),m(),(s=e.tags)==null?void 0:s.call(e)]),z])]),$])}}});const ce=w(re),oe=t=>q("/yuthon/yuthon/salary",{id:t}),ie={class:"container"},le={class:"header"},se={class:"salary-amount"},ue={class:"detail-section"},de={__name:"Salary",setup(t){const e=R({}),u=Q();return J(async()=>{const l=parseInt(u.query.id);try{const r=await oe(l);console.log(r),e.value=r.data}catch(r){H("获取工资条失败"),console.error(r)}}),(l,r)=>{const d=ce,o=j,m=O;return C(),S("div",ie,[f("div",le,k(e.value.date_from)+" - "+k(e.value.date_to)+" 工资条 ",1),a(d,{class:"salary-card",title:"实发工资",bordered:""},{desc:P(()=>[f("div",se,k(e.value.amount_total),1)]),_:1}),f("div",ue,[r[0]||(r[0]=f("div",{class:"section-title"},"明细",-1)),a(m,null,{default:P(()=>[(C(!0),S(I,null,U(e.value.lines_ids,i=>(C(),W(o,{key:i.name,title:i.name,value:i.total},null,8,["title","value"]))),128))]),_:1})])])}}},_e=M(de,[["__scopeId","data-v-4564b9eb"]]);export{_e as default};
@@ -0,0 +1 @@
import{v as P,t as S,n as d,c as B,G as u,F as $,J as j,I as D,j as _}from"./requests-DdoUQiv8.js";import{d as C,r as f,v as F,c as N,w as R,f as U,o as G,n as z,g as n,x as J,y as M,m as b}from"./index-CimcMLIq.js";const[O,i]=B("image"),T={src:String,alt:String,fit:String,position:String,round:Boolean,block:Boolean,width:d,height:d,radius:d,lazyLoad:Boolean,iconSize:d,showError:S,errorIcon:P("photo-fail"),iconPrefix:String,showLoading:S,loadingIcon:P("photo"),crossorigin:String,referrerpolicy:String,decoding:String};var V=C({name:O,props:T,emits:["load","error"],setup(r,{emit:g,slots:c}){const t=f(!1),a=f(!0),o=f(),{$Lazyload:l}=F().proxy,x=N(()=>{const e={width:u(r.width),height:u(r.height)};return $(r.radius)&&(e.overflow="hidden",e.borderRadius=u(r.radius)),e});R(()=>r.src,()=>{t.value=!1,a.value=!0});const v=e=>{a.value&&(a.value=!1,g("load",e))},m=()=>{const e=new Event("load");Object.defineProperty(e,"target",{value:o.value,enumerable:!0}),v(e)},h=e=>{t.value=!0,a.value=!1,g("error",e)},y=(e,s,I)=>I?I():n(D,{name:e,size:r.iconSize,class:s,classPrefix:r.iconPrefix},null),E=()=>{if(a.value&&r.showLoading)return n("div",{class:i("loading")},[y(r.loadingIcon,i("loading-icon"),c.loading)]);if(t.value&&r.showError)return n("div",{class:i("error")},[y(r.errorIcon,i("error-icon"),c.error)])},k=()=>{if(t.value||!r.src)return;const e={alt:r.alt,class:i("img"),decoding:r.decoding,style:{objectFit:r.fit,objectPosition:r.position},crossorigin:r.crossorigin,referrerpolicy:r.referrerpolicy};return r.lazyLoad?J(n("img",b({ref:o},e),null),[[M("lazy"),r.src]]):n("img",b({ref:o,src:r.src,onLoad:v,onError:h},e),null)},w=({el:e})=>{const s=()=>{e===o.value&&a.value&&m()};o.value?s():z(s)},L=({el:e})=>{e===o.value&&!t.value&&h()};return l&&j&&(l.$on("loaded",w),l.$on("error",L),U(()=>{l.$off("loaded",w),l.$off("error",L)})),G(()=>{z(()=>{var e;(e=o.value)!=null&&e.complete&&!r.lazyLoad&&m()})}),()=>{var e;return n("div",{class:i({round:r.round,block:r.block}),style:x.value},[k(),E(),(e=c.default)==null?void 0:e.call(c)])}}});const H=_(V);export{H as I};
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -35,29 +35,28 @@ class LeaveAllocationWizard(models.Model):
holiday_status_id = self.env['hr.leave.type'].search([('name', '=', '年假'), ('company_id', '=', '天河物管')], limit=1)
holiday_status_id1 = self.env['hr.leave.type'].search([('name', '=', '补休')], limit=1)
accrual_plan_id = self.env['hr.leave.accrual.plan'].search([('name', '=', '年假(天河物管)')], limit=1)
if row[1].value:
number_of_days_display = int(row[1].value)/8
else:
number_of_days_display = 0
self.env['hr.leave.allocation'].create({
'employee_id': employee_id.id,
'name': '年假公司分配',
'number_of_days': number_of_days_display,
'employee_ids': [(6, 0, [employee_id.id])],
'holiday_status_id': holiday_status_id.id,
'accrual_plan_id': accrual_plan_id.id,
'allocation_type': 'accrual',
"number_of_days_display":number_of_days_display,
'notes':'年假公司分配'
})
self.env['hr.leave.allocation'].create({
'employee_id': employee_id.id,
'name': '补休',
'employee_ids': [(6, 0, [employee_id.id])],
'holiday_status_id' : holiday_status_id1.id,
'number_of_hours_display':row[2].value,
})
if row[1].value and int(row[1].value) != 0:
number_of_days_display = int(row[1].value) / 8
self.env['hr.leave.allocation'].create({
'employee_id': employee_id.id,
'name': '年假公司分配',
'number_of_days': number_of_days_display,
'employee_ids': [(6, 0, [employee_id.id])],
'holiday_status_id': holiday_status_id.id,
'accrual_plan_id': accrual_plan_id.id,
'allocation_type': 'accrual',
"number_of_days_display": number_of_days_display,
'notes': '年假公司分配'
})
if row[2].value and int(row[2].value) != 0:
self.env['hr.leave.allocation'].create({
'holiday_status_id': holiday_status_id1.id,
'employee_id': employee_id.id,
'name': '补休',
'employee_ids': [(6, 0, [employee_id.id])],
'number_of_hours_display': int(row[2].value)
})
+87 -12
View File
@@ -82,15 +82,45 @@ class GoApprovals(models.Model):
'approval_date': fields.Datetime.now(),
})
@api.depends('users_id', 'days', 'hours')
@api.depends('employee_ids', 'days', 'hours', 'statr_date', 'end_date', 'date_start', 'date_end', 'is_day', 'is_half',
'is_hour')
def _compute_name(self):
for rec in self:
if rec.is_hour == True:
rec.name = f"{rec.users_id.name}外出{rec.hours}小时"
elif rec.is_day == True:
rec.name = f"{rec.users_id.name}外出{rec.days}天"
employee_list = [employee.name for employee in rec.employee_ids]
# 将员工列表转换为逗号分隔的字符串
employees_str = ", ".join(employee_list)
base_name = f"{employees_str}外出"
date_info = ""
if rec.is_hour:
# 按小时
if rec.date_start and rec.date_end:
start_date = fields.Date.from_string(rec.date_start)
end_date = fields.Date.from_string(rec.date_end)
start_str = start_date.strftime('%Y-%m-%d')
end_str = end_date.strftime('%Y-%m-%d')
if start_date == end_date:
date_info = f"{start_str}共:{rec.hours}小时"
else:
date_info = f"{start_str}至{end_str}共:{rec.hours}小时"
elif rec.is_day or rec.is_half:
# 按天或半天
if rec.statr_date and rec.end_date:
start_str = rec.statr_date.strftime('%Y-%m-%d')
end_str = rec.end_date.strftime('%Y-%m-%d')
if rec.statr_date == rec.end_date:
date_part = start_str
else:
date_part = f"{start_str}至{end_str}"
if rec.is_day:
date_info = f"{date_part}共:{rec.days}天"
else:
date_info = f"{date_part}共:{rec.days}天"
if date_info:
rec.name = f"{base_name}{date_info}"
else:
rec.name = f"{rec.users_id.name}外出"
rec.name = base_name
@api.onchange('statr_date', 'end_date')
def _onchange_days(self):
@@ -138,23 +168,68 @@ class GoApprovals(models.Model):
def end_approval(self):
if self.meal:
# 创建日志
go_approval_list = []
first_day = self.statr_date.replace(day=1)
reports_id = self.env['yuthon.vacation.reports'].search([
('employee_id', '=', self.users_id.employee_id.id),
('vacation_date', '=', first_day)
])
workflow_record_id = self.env['soong.workflow.record'].search([
('code', '=', self.code)
])
go_approval_list.append((0, 0, {
meal_fee_value = (0, 0, {
'vacation_id': reports_id.id,
'update_type': 'add',
'workflow_record_id': workflow_record_id.id,
'update_date': fields.Datetime.now(),
'update_lines': 1 ,
'update_lines': 1,
'text': '审批'
}))
reports_id.write({'meal_fee_ids': [(0, 0, go_approval_list)]})
})
reports_id.write({'meal_fee_ids': [meal_fee_value]})
for employee in self.employee_ids:
if self.is_day or self.is_half:
start = self.statr_date
end = self.end_date
date_field = 'current_data'
elif self.is_hour:
start = self.date_start.date() if self.date_start else None
end = self.date_end.date() if self.date_end else None
date_field = 'current_data'
else:
return True
if not (start and end):
return True
attendance_records = self.env['hr.attendance'].search([
('employee_id', '=', employee.id),
(date_field, '>=', start),
(date_field, '<=', end)
])
if attendance_records:
attendance_records.write({
'is_clock_card': True,
'is_no_card': False,
'is_early_card': False,
'is_late_card': False,
'is_abnormal': False,
'absenteeism_card': False
})
else:
current_date = start
while current_date <= end:
self.env['hr.attendance'].create({
'employee_id': employee.id,
date_field: current_date,
'is_clock_card': True,
'check_in': False,
'check_out': False,
'is_no_card': False,
'is_early_card': False,
'is_late_card': False,
'is_abnormal': False,
'absenteeism_card': False
})
# 日期递增
current_date += timedelta(days=1)
+9 -2
View File
@@ -219,7 +219,7 @@ class HrAttendance(models.Model):
if record.absenteeism_card:
absenteeism_card += 1
if has_abnormal:
url = f"http://oa.thtzjt.com/#/clock_in_staticstis?user_id={employee.user_id.id}"
url = f"https://oa.thtzjt.com/webh5#/clock_in_staticstis?user_id={employee.user_id.id}"
self.sudo().env["wecom.apps"].sync_send_message_textcard(category='att', user_id=employee.wecom_userid, title="打卡异常提醒",
description="本月迟到: {}\n本月缺卡: {}\n本月早退: {}\n本月异常:{}\n 本月旷工: {}\n"
.format(is_late_card, is_no_card, is_early_card, is_abnormal, absenteeism_card),
@@ -264,7 +264,7 @@ class HrAttendance(models.Model):
# 工作日打卡情况判断
if is_workday:
if employee_record:
is_no_card = not employee_record.check_in or not employee_record.check_out
is_no_card = (not employee_record.check_in or not employee_record.check_out) and not employee_record.is_clock_card
else:
is_no_card = True
else:
@@ -1044,6 +1044,13 @@ class HrAttendance(models.Model):
self._update_vacation_report(record)
return result
def unlink(self):
for record in self:
self._update_vacation_report(record)
result = super(HrAttendance, self).unlink()
return result
def _update_vacation_report(self, record):
"""更新相关的假期报表日志"""
if record.current_data and record.employee_id:
@@ -110,7 +110,9 @@ class HrAttendanceDetail(models.Model):
for resource_id in role.resource_ids:
employee_list.append(resource_id.employee_id.id)
if not record.employee_id.id in employee_list:
days = self.env['yuthon.vacation.reports']._create_leave_record(slot_start_dt, slot_end_dt)
start_dt = slot_start_dt.date()
end_dt = slot_end_dt.date()
days = self.env['yuthon.vacation.reports']._create_leave_record(record.employee_id, start_dt, end_dt)
else:
monthly_slots = self.env['planning.slot'].search([
('employee_id', '=', record.employee_id.id),
@@ -509,6 +511,7 @@ class HrAttendanceDetail(models.Model):
result = response.json()
if result.get('errcode') != 0:
# 301021至少有一个不存在通讯录
# 301024获取打卡间隔受限
_logger.error('获取外出打卡数据失败\n异常:{0}\n数量:{1}\n用户列表:{2}'.format(str(result.get('errmsg')), len(userid_limit), str(userid_limit)))
return []
checkin_data = result.get('checkindata', [])
@@ -621,11 +624,14 @@ class HrAttendanceDetail(models.Model):
"""
# 从用户列表里获取企业微信的用户
user_list = self._get_wx_attendance_user_list()
now_time = datetime.now() + timedelta(hours=8)
start_time = now_time - timedelta(days=30)
now_time = datetime(2025, 9, 1) # 替换为你需要的年份
start_time = datetime(2025, 8, 15) # 替换为你需要的年份
# now_time = datetime.now() + timedelta(hours=8)
# start_time = now_time - timedelta(days=3)
# 企业微信获取打卡数据,要求用户分组100,分批获取打卡记录
# for userid_limit in self.utils_list_page(user_list, 1):
for userid_limit in user_list:
# 获取企业微信的打卡信息
try:
@@ -180,6 +180,7 @@ class OvertimeApprovals(models.Model):
if self.meal == 'yes':
meal_number += 1
employee_id.write({'meal_number': meal_number})
holiday_status_id = self.env['hr.leave.type'].search([('name', '=', '补休')])
allocation = self.env['hr.leave.allocation'].create({
'employee_id': employee_id.id,
@@ -224,6 +225,17 @@ class OvertimeApprovals(models.Model):
'update_date': fields.Datetime.now(),
'text': '审批'
}
if self.meal == 'yes':
meal_fee_value = (0, 0, {
'vacation_id': reports_id.id,
'update_type': 'add',
'workflow_record_id': workflow_record_id.id,
'update_date': fields.Datetime.now(),
'update_lines': 1,
'text': '审批'
})
reports_id.write({'meal_fee_ids': [meal_fee_value]})
reports_id.write({'overtime_ids': [(0, 0, overtime_data)]})
@api.depends('users_id', 'duration')
@@ -13,6 +13,7 @@ class WifiMessage(models.Model):
mac = fields.Char(string='MAC地址')
name = fields.Char(string='详细地址')
bssid = fields.Char(string='BSSID')
create_time = fields.Date(string='创建日期', default=lambda self: fields.Date.today())
company_id = fields.Many2one("res.company", string="公司", default=lambda self: self.env.company)
@@ -22,13 +22,13 @@ class YuthonVacationReports(models.Model):
meal_fee_ids = fields.One2many('vacation.meal.line', 'vacation_id', string='误餐明细')
medical_fee_ids = fields.One2many('vacation.medical.line', 'vacation_id', string='体检费明细')
other_fee_ids = fields.One2many('vacation.other.line', 'vacation_id', string='其他明细')
vacation_date = fields.Date(string='日期', default=lambda self: fields.Date.today())
vacation_date = fields.Date(string='日期', default=lambda self: fields.Date.today().replace(day=1))
display_date = fields.Char(string='日期', compute='_compute_display_date')
done_leave = fields.Float(string='年假', compute='_compute_leave', store=True, digits=(16, 3), group_operator=None)
done_working_overtime = fields.Float(string='加班时', compute='_compute_working_overtime', digits=(16, 3),
store=True, group_operator=None)
leave = fields.Float(string='剩余年假', compute='_compute_leave', store=True, digits=(16, 3), group_operator=None)
working_overtime = fields.Float(string='剩余加班时', compute='_compute_working_overtime', store=True,
working_overtime = fields.Float(string='剩余补休', compute='_compute_working_overtime', store=True,
digits=(16, 3), group_operator=None)
meal_fee = fields.Integer(string="误餐次数", compute='_compute_meal_fee', store=True, group_operator=None)
medical_fee = fields.Float(string="体检费", compute='_compute_medical_fee', store=True, group_operator=None)
@@ -36,7 +36,7 @@ class YuthonVacationReports(models.Model):
leave_of_absence = fields.Float(string="事假", digits=(16, 3), compute='_compute_other_leave', store=True,
group_operator=None)
statutory_leave = fields.Integer(string="加班时(法定)", compute='_compute_other_leave', store=True, group_operator=None)
cop_leave = fields.Float(string='补休', digits=(16, 3), compute='_compute_other_leave', store=True,
cop_leave = fields.Float(string='补休', digits=(16, 3), store=True, compute='_compute_working_overtime',
group_operator=None)
duty_off_leave = fields.Integer(string='值班调休', compute='_compute_other_leave', store=True, group_operator=None)
marriage_leave = fields.Integer(string='婚假', compute='_compute_other_leave', store=True, group_operator=None)
@@ -73,6 +73,21 @@ class YuthonVacationReports(models.Model):
tracking=3,
default='unconfirmed')
@api.constrains('employee_id', 'vacation_date')
def _check_duplicate_monthly_record(self):
"""检查是否存在同一员工当月的重复记录"""
for record in self:
duplicate_records = self.search([
('employee_id', '=', record.employee_id.id),
('vacation_date', '=', record.vacation_date),
('id', '!=', record.id)
])
if duplicate_records:
raise ValidationError(
f"员工 {record.employee_id.name} 在 {record.vacation_date.strftime('%Y年%m月')} "
f"已存在假期额度记录,不能重复创建!"
)
def confirm_state(self):
for rec in self:
rec.vacation_state = 'confirmed'
@@ -131,8 +146,16 @@ class YuthonVacationReports(models.Model):
days_in_month = calendar.monthrange(year, month)[1]
month_start = date(year, month, 1)
month_end = date(year, month, days_in_month)
leave_days = rec._create_leave_record(month_start, month_end)
for day in range(1, days_in_month + 1):
leave_days = rec._create_leave_record(rec.employee_id, month_start, month_end)
entry_date = rec.employee_id.entry_date
if month_start > entry_date:
start_day = 1
else:
days_in_month = (date(year, month + 1, 1) - timedelta(days=1)).day
start_day = min(entry_date.day, days_in_month)
days_in_month = (date(year, month + 1, 1) - timedelta(days=1)).day
actual_days_range = range(start_day, days_in_month + 1)
for day in actual_days_range:
current_date = date(year, month, day)
attendances = self.env["hr.attendance"].sudo().search([
('employee_id', '=', rec.employee_id.id),
@@ -172,8 +195,8 @@ class YuthonVacationReports(models.Model):
rec._compute_attendance_fields1()
def update_data(self):
august_start = fields.Date.from_string('2025-08-01')
august_end = fields.Date.from_string('2025-08-31')
august_start = fields.Date.from_string('2025-09-01')
august_end = fields.Date.from_string('2025-9-30')
august_records = self.env["yuthon.vacation.reports"].search([
('vacation_date', '>=', august_start),
('vacation_date', '<=', august_end)
@@ -228,7 +251,10 @@ class YuthonVacationReports(models.Model):
for field in int_fields:
setattr(rec, field, getattr(rec, field) or 0)
def _create_leave_record(self, start_date, end_date):
def _create_leave_record(self, employee_id, start_date, end_date):
entry_date = employee_id.entry_date
# 调整日期范围:如果开始日期早于入职日期,则从入职日期开始计算
actual_start_date = max(start_date, entry_date) if entry_date else start_date
calendar_leaves = self.env['resource.calendar.leaves'].search([("calendar_id", "=", "行政考勤工作日")])
holidays_list = []
shift_days_list = []
@@ -243,7 +269,7 @@ class YuthonVacationReports(models.Model):
holidays_list = [self.remove_leading_zero(date) for date in holidays_list]
shift_days_list = [self.remove_leading_zero(date) for date in shift_days_list]
days = 0 # 初始化工作日计数
current_date = start_date
current_date = actual_start_date
while current_date <= end_date:
current_date_str = current_date.strftime('%m月%d日')
@@ -476,25 +502,33 @@ class YuthonVacationReports(models.Model):
'overtime_ids.legal_day',
'overtime_ids.public_holidays',
'overtime_ids.update_type',
'overtime_ids.is_void'
'overtime_ids.is_void',
'overtime_ids.workflow_record_id'
)
def _compute_working_overtime(self):
for record in self:
total_add1 = 0.0
total_add2 = 0.0
total_add = 0.0
total_reduce = 0.0
done_working_overtime = 0.0
for line in record.overtime_ids:
if not line.is_void:
line_total = (line.workday or 0) + (line.legal_day or 0) + (line.public_holidays or 0)
if line.update_type == 'add':
total_add += line_total
elif line.update_type == 'reduce':
total_reduce += line_total
total_add -= line_total
done_working_overtime += line_total
if line.is_void:
continue
line_total = (line.workday or 0) + (line.legal_day or 0) + (line.public_holidays or 0)
if line.update_type == 'add':
total_add += line_total
elif line.update_type == 'reduce':
total_add -= line_total
if line.workflow_record_id and line.update_type == 'add':
total_add1 += line_total
if line.workflow_record_id and line.update_type == 'reduce':
total_add2 += line_total
record.working_overtime = max(total_add / 8, 0)
record.done_working_overtime = done_working_overtime / 8
record.cop_leave = total_reduce / 8
record.done_working_overtime = total_add1 / 8
record.cop_leave = total_add2 / 8
@api.depends('meal_fee_ids.update_lines', 'meal_fee_ids.update_type', 'meal_fee_ids.is_void')
def _compute_meal_fee(self):
@@ -738,9 +772,9 @@ class VacationMealLine(models.Model):
delta = int(record.update_lines) * sign
if record.update_type == 'add':
employee.write({'meal_count': employee.meal_count + delta})
employee.write({'meal_number': employee.meal_number + delta})
elif record.update_type == 'reduce':
employee.write({'meal_count': employee.meal_count - delta})
employee.write({'meal_number': employee.meal_number - delta})
def unlink(self):
self._sync_to_employee(reverse=True)
@@ -12,7 +12,7 @@
<field name="domain_force">[('company_id', 'in', company_ids)]</field>
</record>
<record id="module_he_attendance_sign" model="ir.module.category">
<field name="name">考勤记录详情组</field>
<field name="name">考勤记录详情/修正组</field>
</record>
<record id="group_he_attendance_sign_manager" model="res.groups">
<field name="name">管理员</field>
@@ -9,10 +9,16 @@
decoration-danger="is_workflow or is_approval"
editable="bottom">
<header>
<button name="compute_company_id" string="公司更新" type="object" class="btn btn-primary"/>
<!-- <button name="compute_company_id" string="公司更新" type="object" class="btn btn-primary"/>-->
<!-- <button name="button_all" string="班次更新" type="object" class="btn btn-primary"/>-->
<button name="compute_attendance_ids" string="重新计算" type="object" class="btn btn-primary"/>
<button name="state_fix" string="状态修正" type="object" class="btn btn-primary" groups="yuthon_hr_attendance.group_he_attendance_sign_manager"/>
<button name="unlink"
string="删除"
type="object"
icon="fa-trash"
groups="yuthon_hr_attendance.group_he_attendance_sign_manager"
confirm="确定要删除选中的记录吗?"/>
</header>
<field name="employee_id" class="list_current_data" options="{'no_create': True}"/>
<field name="current_data" optional="show" class="list_current_data"/>
@@ -39,8 +45,8 @@
<field name="is_workflow" optional="hidden"/>
<field name="workflow_id" optional="hidden"/>
<button name="button_controls_wizard" type="object" string="操作" class="oe_highlight" invisible="not (is_abnormal or is_early_card or is_late_card or absenteeism_card or is_no_card)"/>
<button name="button_correct_wizard" type="object" string="修正" class="btn btn-primary" invisible="not (is_abnormal or is_early_card or is_late_card or absenteeism_card or is_no_card)" groups="base.group_system"/>
<button name="revoke" type="object" string="撤销" class="btn btn-primary" invisible="not (is_check_out_red or is_check_in_red)" groups="base.group_system"/>
<button name="button_correct_wizard" type="object" string="修正" class="btn btn-primary" invisible="not (is_abnormal or is_early_card or is_late_card or absenteeism_card or is_no_card)" groups="yuthon_hr_attendance.group_he_attendance_sign_manager"/>
<button name="revoke" type="object" string="撤销" class="btn btn-primary" invisible="not (is_check_out_red or is_check_in_red)" groups="yuthon_hr_attendance.group_he_attendance_sign_manager"/>
<button name="button_workflow" type="object" string="流程" class="oe_highlight" invisible="not is_workflow"/>
<button name="button_source" type="object" string="详情" class="oe_highlight" groups="yuthon_hr_attendance.group_he_attendance_sign_manager"/>
</tree>
@@ -80,8 +86,8 @@
<field name="is_check_in_red" column_invisible="1"/>
<field name="is_check_out_red" column_invisible="1"/>
<button name="button_controls_wizard" type="object" string="操作" class="oe_highlight" invisible="not (is_abnormal or is_early_card or is_late_card or absenteeism_card or is_no_card)"/>
<button name="button_correct_wizard" type="object" string="修正" class="btn btn-primary" invisible="not (is_abnormal or is_early_card or is_late_card or absenteeism_card or is_no_card)" groups="base.group_system"/>
<button name="revoke" type="object" string="撤销" class="btn btn-primary" invisible="not (is_check_out_red or is_check_in_red)" groups="base.group_system"/>
<button name="button_correct_wizard" type="object" string="修正" class="btn btn-primary" invisible="not (is_abnormal or is_early_card or is_late_card or absenteeism_card or is_no_card)" groups="yuthon_hr_attendance.group_he_attendance_sign_manager"/>
<button name="revoke" type="object" string="撤销" class="btn btn-primary" invisible="not (is_check_out_red or is_check_in_red)" groups="yuthon_hr_attendance.group_he_attendance_sign_manager"/>
<button name="button_source" type="object" string="详情" class="oe_highlight" groups="yuthon_hr_attendance.group_he_attendance_sign_manager"/>
</tree>
</field>
@@ -157,14 +163,14 @@
<field name="binding_model_id" ref="yuthon_hr_attendance.model_hr_attendance"/>
<field name="state">code</field>
<field name="code">action = model.button_batch_correct()</field>
<field name="groups_id" eval="[(4, ref('base.group_system'))]"/>
<field name="groups_id" eval="[(4, ref('yuthon_hr_attendance.group_he_attendance_sign_manager'))]"/>
</record>
<record id="action_update_shift" model="ir.actions.server">
<field name="name">批量更新班次</field>
<field name="model_id" ref="yuthon_hr_attendance.model_hr_attendance"/>
<field name="binding_model_id" ref="yuthon_hr_attendance.model_hr_attendance"/>
<field name="state">code</field>
<field name="groups_id" eval="[(4, ref('base.group_system'))]"/>
<field name="groups_id" eval="[(4, ref('yuthon_hr_attendance.group_he_attendance_sign_manager'))]"/>
</record>
<record id="action_update_abnormal_shift" model="ir.actions.server">
<field name="name">批量更新异常</field>
@@ -172,6 +178,6 @@
<field name="binding_model_id" ref="yuthon_hr_attendance.model_hr_attendance"/>
<field name="state">code</field>
<field name="code">action = model.update_abnormal()</field>
<field name="groups_id" eval="[(4, ref('base.group_system'))]"/>
<field name="groups_id" eval="[(4, ref('yuthon_hr_attendance.group_he_attendance_sign_manager'))]"/>
</record>
</odoo>
@@ -10,6 +10,7 @@
<field name="name"/>
<field name="bssid" />
<field name="company_id"/>
<field name="create_time"/>
</tree>
</field>
</record>
@@ -99,7 +99,11 @@
<field name="arch" type="xml">
<form string="假期额度日志">
<sheet>
<field name="employee_id" invisible="1"/>
<div>
</div>
<field name="employee_id"/>
<field name="vacation_date"/>
<div class="col-12 text-center">
<h1>
<field name="display_date"/>
@@ -194,7 +198,7 @@
</tree>
</field>
</page>
<page string="其他">
<page string="请假情况">
<field name="other_fee_ids" context="{'default_employee_id': employee_id}">
<tree editable="bottom" delete="false" decoration-muted="is_void">
<field name="employee_id" column_invisible="1"/>
@@ -130,6 +130,11 @@ class YuthonMessageLogin(models.Model):
degree_id_ids = fields.One2many('education.details.line2', 'degree_id', string="学位证")
certificate_ids = fields.One2many('certificates.detail.line', 'certificate_id', string="专业证书")
@api.onchange('staff_name')
def _onchange_staff_name(self):
if self.staff_name:
self.name = '人员信息登记表'+ '-' + self.staff_name
@api.onchange('is_issues')
def _onchange_is_issues(self):
if self.is_issues:
@@ -12,6 +12,11 @@
parent="hr_process_work_job"
action="yuthon_recruitment_approval_action"
sequence="1"/>
<menuitem id="hr_menu_message_login"
name="个人信息登记表"
parent="hr_process_work_job"
action="yuthon_message_login_action"
sequence="2"/>
<menuitem id="hr_menu_interview_approval"
name="面试信息表"
parent="hr_process_work_job"
@@ -22,11 +27,6 @@
parent="hr_process_work_job"
action="yuthon_onboard_approval_action"
sequence="5"/>
<menuitem id="hr_menu_message_login"
name="个人信息登记表"
parent="hr_process_work_job"
action="yuthon_message_login_action"
sequence="7"/>
<menuitem id="hr_menu_prepare_approval"
name="编制调整申请表"
parent="hr_process_work_job"
@@ -51,6 +51,7 @@ class YuthonProperty(models.Model):
image_1920 = fields.Image(string="图片")
description = fields.Html(string="描述")
is_message_fee = fields.Boolean(string="管理费")
financial_address = fields.Char(string="财务地址")
message_standard_id = fields.Many2one('property.message.fee', string="管理费标准")
rental_unit_price = fields.Float(string="评估单价")
title_number = fields.Char(string="产权编号")
Binary file not shown.
@@ -71,6 +71,7 @@
<field name="units"/>
<field name="property_orientation"/>
<field name="street"/>
<field name="financial_address"/>
<field name="effective_date"/>
</group>
<group>
@@ -3,7 +3,7 @@
<record id="initialize_template_downloads_action" model="ir.actions.act_url">
<field name="name">初始化模板下载</field>
<field name="target">self</field>
<field name="url">.</field>
<field name="url">/yuthon_property/static/others/rent_temp.xlsx</field>
</record>
<record id="initialize_wizard_form" model="ir.ui.view">
<field name="name">审批意见弹窗</field>
+2
View File
@@ -55,6 +55,7 @@
'views/property_accounting_approval_views.xml',
'views/property_record_views.xml',
'views/property_equity_views.xml',
'views/payment_process_viwes.xml',
'views/property_handover_views.xml',
'views/property_merge_approval_views.xml',
'views/property_current_approval_views.xml',
@@ -80,6 +81,7 @@
'wizard/binding_information_wizard_views.xml',
'wizard/property_rental_wizard_views.xml',
'wizard/contract_signature_wizard_viwes.xml',
'wizard/build_pop_wizard_viwes.xml',
'wizard/property_meeting_wizard_views.xml',
'views/property_menu_all.xml',
],
@@ -7,7 +7,13 @@
<field name="padding">3</field>
<field name="company_id" eval="False"/>
</record>
<record id="payment_process_code_sequence" model="ir.sequence">
<field name="name">支付流程编号</field>
<field name="code">payment_process_code</field>
<field name="prefix">ZF%(y)s%(month)s%(day)s</field>
<field name="padding">3</field>
<field name="company_id" eval="False"/>
</record>
<record id="property_business_confirm_code_sequence" model="ir.sequence">
<field name="name">经营报表确认单编号</field>
<field name="code">property_business_confirm_code</field>
+2 -1
View File
@@ -55,4 +55,5 @@ from . import property_accounts_approval
from . import inherit_property_tenant_information
from . import property_meeting_approval
from . import property_lessee_analysis
from . import yuthon_property_ledger
from . import yuthon_property_ledger
from . import payment_process
@@ -0,0 +1,32 @@
from odoo import models, fields, api
class PaymentProcess(models.Model):
_name = 'payment.process'
_description = '支付流程'
_inherit = ['soong.workflow.mixin', 'mail.thread.main.attachment', 'mail.activity.mixin']
code = fields.Char(string="编号", readonly=True,default=lambda self: self.env['ir.sequence'].next_by_code('payment_process_code'))
users_id = fields.Many2one('res.users', string="申请人", default=lambda self: self.env.user.id)
department_id = fields.Many2one(related='users_id.employee_id.department_id', string="部门")
company_id = fields.Many2one(related='users_id.employee_id.company_id', string="公司")
supervising_id = fields.Many2one('property.supervising.approval', string='合同编号')
reason = fields.Text(related='supervising_id.reason', string='事项')
payment_instructions = fields.Text(string='支付说明')
payment_nodes = fields.Selection([('first', '一期'), ('second', '二期'), ('third', '三期'), ('fourth', '四期')],
string="支付节点")
amount = fields.Float(string="金额")
documents_id = fields.Many2one('ir.attachment', string="附件")
urgency_level = fields.Selection([('normal', '普件'), ('urgent', '急件'), ('emergency', '特急件')], string='紧急度',
default='normal')
active = fields.Boolean('Active', default=True, tracking=True)
work_end = fields.Boolean(string="结束")
def _get_default_name_title(self):
return self._description if self._description else self._name
name_title = fields.Char(default=_get_default_name_title)
self_users_ids = fields.Many2many('res.users', string="当前经办人",
default=lambda self: [(6, 0, [self.env.user.id])])
@@ -7,28 +7,29 @@ from odoo.exceptions import UserError, ValidationError
class PropertyAccountingApproval(models.Model):
_name = 'property.accounting.approval'
_description = '建设工程委托核算合同审批'
_description = '建设工程委托监理合同审批 '
_inherit = ['soong.workflow.mixin', 'mail.thread.main.attachment', 'mail.activity.mixin']
name = fields.Char(string='标题')
name = fields.Char(string='合同编号')
code = fields.Char(string="编号", default=lambda self: self.env['ir.sequence'].next_by_code('property_accounting_approval_code'))
users_id = fields.Many2one('res.users', string="申请人", default=lambda self: self.env.user.id)
department_id = fields.Many2one(related='users_id.employee_id.department_id', string="部门")
company_id = fields.Many2one('yuthon.property.company', string="甲方")
project_content = fields.Char(string="工程内容")
company_b_id = fields.Many2one('property.construction.unit', string="乙方")
property_id = fields.Many2one('yuthon.property', string='物业')
company_id = fields.Many2one(related='users_id.employee_id.company_id', string="公司")
company_a_id = fields.Many2one('yuthon.property.company', string="甲方")
reason = fields.Text(string="正文")
three_point_offer = fields.Text(string="三方报价")
documents_ids = fields.Many2many('ir.attachment', string="附件")
contract_id = fields.Many2one('ir.attachment', string="合同")
budget_list_id = fields.Many2one('ir.attachment', string="预算清单")
project_content = fields.Char(string="工程内容")
image = fields.Binary(string="维修前图片")
company_b_id = fields.Many2one('property.construction.unit', string="乙方")
property_address = fields.Char(string='物业地址')
contract_amount = fields.Float(string="合同金额")
start_date = fields.Date(string="开始日期")
end_date = fields.Date(string="结束日期")
amount = fields.Float(string="总金额")
is_tex = fields.Boolean(string="是否含税")
lack = fields.Float(string="差额")
percentage = fields.Float(string="差额百分比")
business_type = fields.Char(string="业务类型")
payment_methods = fields.Selection([('onetime', '一次性'), ('installment', '分期')], string="付款方式")
contract_id = fields.Many2one('ir.attachment', string="合同")
accounting_way_ids = fields.One2many('accounting.way.line', 'accounting_id', string="关联支付方式明细行")
lease_ids = fields.One2many('property.lease.contract.line', 'accounting_id', string="物业信息明细")
urgency_level = fields.Selection([('normal', '普件'), ('urgent', '急件'), ('emergency', '特急件')], string='紧急度',
default='normal')
active = fields.Boolean('Active', default=True, tracking=True)
@@ -40,12 +41,26 @@ class PropertyAccountingApproval(models.Model):
name_title = fields.Char(default=_get_default_name_title)
self_users_ids = fields.Many2many('res.users', string="当前经办人", default=lambda self: [(6, 0, [self.env.user.id])])
def build_pop(self):
return {
'name': '添加物业',
'type': 'ir.actions.act_window',
'res_model': 'build.pop.wizard',
'view_mode': 'form',
'target': 'new',
'context': {
'default_accounting_id': self.id,
}
}
class AccountingWayLine(models.Model):
_name = 'accounting.way.line'
pay_way = fields.Selection([('cumulative', '累计项'), ('stage', '单项'), ('other', '其他')], string="付款方式",)
interval = fields.Char(string="区间")
service_charge = fields.Float(string="服务费")
payment_nodes = fields.Selection([('first', '一期'), ('second', '二期'), ('third', '三期'), ('fourth', '四期')],
string="支付节点")
payout_ratio = fields.Float(string="支付比例")
amount = fields.Float(string="金额")
remake = fields.Char(string="备注")
payment_instructions = fields.Text(string="支付说明")
accounting_id = fields.Many2one('property.accounting.approval', string="关联核算方式")
@@ -7,27 +7,29 @@ from odoo.exceptions import UserError, ValidationError
class PropertyConstructionApproval(models.Model):
_name = 'property.construction.approval'
_description = '建设工程施工合同审批'
_description = '建设工程造价咨询合同审批'
_inherit = ['soong.workflow.mixin', 'mail.thread.main.attachment', 'mail.activity.mixin']
name = fields.Char(string='标题')
code = fields.Char(string="编号",
default=lambda self: self.env['ir.sequence'].next_by_code('property_construction_approval_code'))
users_id = fields.Many2one('res.users', string="申请人", default=lambda self: self.env.user.id)
department_id = fields.Many2one(related='users_id.employee_id.department_id', string="部门")
company_id = fields.Many2one('yuthon.property.company', string="甲方")
user_id = fields.Many2one('res.users', string="申请人", default=lambda self: self.env.user.id)
department_id = fields.Many2one(related='user_id.employee_id.department_id', string="部门")
company_id = fields.Many2one(related='user_id.employee_id.company_id', string="公司")
company_a_id = fields.Many2one('yuthon.property.company', string="甲方")
project_content = fields.Char(string="工程内容")
company_b_id = fields.Many2one('property.construction.unit', string="乙方")
property_id = fields.Many2one('yuthon.property', string='物业')
property_address = fields.Char(string='物业地址')
reason = fields.Text(string="正文")
image = fields.Binary(string="开工前图片")
contract_id = fields.Many2one('ir.attachment', string="合同")
start_date = fields.Date(string="开始日期")
end_date = fields.Date(string="结束日期")
review_price = fields.Float(string="审核价")
budget_list_id = fields.Many2one('ir.attachment', string="预算清单")
start_date = fields.Date(string="代理开始日期")
end_date = fields.Date(string="代理结束日期")
business_type = fields.Char(string="业务类型")
contract_amount = fields.Float(string="合同金额")
payment_methods = fields.Char(string="付款方式")
contract_id = fields.Many2one('ir.attachment', string="合同")
payment_methods = fields.Selection([('onetime', '一次性'), ('installment', '分期')], string="付款方式")
lease_ids = fields.One2many('property.lease.contract.line', 'construction_id', string="物业信息明细")
construction_way_ids = fields.One2many('construction.way.line', 'construction_id', string="关联支付方式")
urgency_level = fields.Selection([('normal', '普件'), ('urgent', '急件'), ('emergency', '特急件')], string='紧急度',
default='normal')
@@ -40,15 +42,28 @@ class PropertyConstructionApproval(models.Model):
name_title = fields.Char(default=_get_default_name_title)
self_users_ids = fields.Many2many('res.users', string="当前经办人", default=lambda self: [(6, 0, [self.env.user.id])])
def build_pop(self):
return {
'name': '添加物业',
'type': 'ir.actions.act_window',
'res_model': 'build.pop.wizard',
'view_mode': 'form',
'target': 'new',
'context': {
'default_construction_id': self.id,
}
}
class ConstructionWayLine(models.Model):
_name = 'construction.way.line'
_description = '施工支付方式'
_description = '价咨询合同审批支付方式'
name = fields.Char(string="支付节点")
pay_ratio = fields.Float(string="支付比例%")
payment_nodes = fields.Selection([('first', '一期'), ('second', '二期'), ('third', '三期'), ('fourth', '四期')],
string="支付节点")
payout_ratio = fields.Float(string="支付比例")
coping_date = fields.Date(string="应付日期")
amount = fields.Float(string="金额")
paid_time = fields.Text(string="付费时间")
remake = fields.Char(string="备注")
construction_id = fields.Many2one('property.construction.approval', string="关联施工合同")
payment_instructions = fields.Text(string="支付说明")
construction_id = fields.Many2one('property.construction.approval', string="关联价咨询合同审批")
@@ -6,19 +6,27 @@ from odoo import models, fields, api, exceptions, _
class PropertyDelegatedAgent(models.Model):
_name = 'property.delegated.agent'
_description = '零星工程'
_description = '零星工程年度委托合同审批'
_inherit = ['soong.workflow.mixin', 'mail.thread.main.attachment', 'mail.activity.mixin']
name = fields.Char(string="名称")
users_id = fields.Many2one('res.users', string="申请人", default=lambda self: self.env.user.id)
department_id = fields.Many2one(related='users_id.employee_id.department_id', string="部门")
name = fields.Char(string="合同编号")
department_id = fields.Many2one(related='user_id.employee_id.department_id', string="部门")
code = fields.Char(string="编号", default=lambda self: self.env['ir.sequence'].next_by_code('property_delegated_agent_code'))
annual = fields.Char(string="年度")
contract_date = fields.Date(string="合同有效期")
signing_date = fields.Date(string="签订日期")
payment_date = fields.Date(string="付款日期")
consult_fee = fields.Float(string="咨询费")
quotations_list_id = fields.Many2one('ir.attachment', string="报价清单")
user_id = fields.Many2one('res.users', string="申请人", default=lambda self: self.env.user.id)
company_id = fields.Many2one(related='user_id.employee_id.company_id', string="公司")
company_a_id = fields.Many2one('yuthon.property.company', string="甲方")
company_b_id = fields.Many2one('property.construction.unit', string="乙方")
matters = fields.Text(string="事项")
text = fields.Text(string="正文")
license_id = fields.Many2one('ir.attachment', string='营业执照')
aptitude_id = fields.Many2one('ir.attachment', string='资质')
contract_id = fields.Many2one('ir.attachment', string='合同')
legal_person_id_card = fields.Many2one('ir.attachment', string='法人身份证')
bid_winning = fields.Many2one('ir.attachment', string='中标确认书')
service_start_date = fields.Date(string="服务开始时间")
service_end_date = fields.Date(string="服务结束时间")
settlement_method = fields.Selection([('cash', '预算审核'), ('bank', '结算审核')], string='结算方式', default='cash')
floating = fields.Float(string="下浮%")
urgency_level = fields.Selection([('normal', '普件'), ('urgent', '急件'), ('emergency', '特急件')], string='紧急度',
default='normal')
active = fields.Boolean('Active', default=True, tracking=True)
@@ -4,27 +4,29 @@ from odoo.exceptions import UserError, ValidationError
class PropertyDesignApproval(models.Model):
_name = 'property.design.approval'
_description = '工程设计合同审批'
_description = '建设工程设计合同审批'
_inherit = ['soong.workflow.mixin', 'mail.thread.main.attachment', 'mail.activity.mixin']
name = fields.Char(string='标题')
name = fields.Char(string='合同编号')
code = fields.Char(string="编号",
default=lambda self: self.env['ir.sequence'].next_by_code('property_design_approval_code'))
users_id = fields.Many2one('res.users', string="申请人", default=lambda self: self.env.user.id)
department_id = fields.Many2one(related='users_id.employee_id.department_id', string="部门")
company_id = fields.Many2one('yuthon.property.company', string="甲方")
company_id = fields.Many2one(related='users_id.employee_id.company_id', string="公司")
project_content = fields.Char(string="工程内容")
company_a_id = fields.Many2one('yuthon.property.company', string="甲方")
company_b_id = fields.Many2one('property.construction.unit', string="乙方")
property_id = fields.Many2one('yuthon.property', string='物业')
budget_list_id = fields.Many2one('ir.attachment', string="预算清单")
property_address = fields.Char(string='物业地址')
reason = fields.Text(string="正文")
three_point_offer = fields.Text(string="三方报价")
image = fields.Binary(string="开工前图片")
contract_id = fields.Many2one('ir.attachment', string="合同")
start_date = fields.Date(string="开始日期")
end_date = fields.Date(string="结束日期")
review_price = fields.Float(string="审核价")
business_type = fields.Char(string="业务类型")
contract_amount = fields.Float(string="合同金额")
payment_methods = fields.Char(string="付款方式")
payment_methods = fields.Selection([('onetime', '一次性'), ('installment', '分期')], string="付款方式")
lease_ids = fields.One2many('property.lease.contract.line', 'design_id', string="关联租赁信息")
business_type = fields.Char(string="业务类型")
design_way_ids = fields.One2many('design.way.line', 'design_id', string="关联支付方式")
urgency_level = fields.Selection([('normal', '普件'), ('urgent', '急件'), ('emergency', '特急件')], string='紧急度',
default='normal')
@@ -37,14 +39,27 @@ class PropertyDesignApproval(models.Model):
name_title = fields.Char(default=_get_default_name_title)
self_users_ids = fields.Many2many('res.users', string="当前经办人", default=lambda self: [(6, 0, [self.env.user.id])])
def build_pop(self):
return {
'name': '添加物业',
'type': 'ir.actions.act_window',
'res_model': 'build.pop.wizard',
'view_mode': 'form',
'target': 'new',
'context': {
'default_design_id': self.id,
}
}
class DesignWayLine(models.Model):
_name = 'design.way.line'
_description = '施工支付方式'
name = fields.Char(string="支付节点")
pay_ratio = fields.Float(string="支付比例%")
payment_nodes = fields.Selection([('first', '一期'), ('second', '二期'), ('third', '三期'), ('fourth', '四期')],
string="支付节点")
payout_ratio = fields.Float(string="支付比例")
amount = fields.Float(string="金额")
paid_time = fields.Text(string="付费时间")
remake = fields.Char(string="备注")
payment_instructions = fields.Text(string="支付说明")
design_id = fields.Many2one('property.design.approval', string="关联施工合同")
@@ -216,11 +216,24 @@ class PropertyLeaseContract(models.Model):
responsibility_book_name = fields.Char(string="安全生产责任书(住宅)名称", compute='_compute_attachment_names',
store=True)
self_users_ids = fields.Many2many('res.users', string="当前经办人", default=lambda self: [(6, 0, [self.env.user.id])])
title_information = fields.Text(string="产权证信息")
title_information = fields.Text(string="产权证信息", compute='_compute_title_information')
contract_count = fields.Integer(string="联系人数量", compute='_compute_contract_count')
reconciliation_count = fields.Integer(string="对账数量", compute='_compute_reconciliation_count')
process_count = fields.Integer(string="流程数量", compute='_compute_process_count')
@api.depends('lease_ids.address_id.title_deed')
def _compute_title_information(self):
for record in self:
seen_titles = set()
unique_titles = []
for lease in record.lease_ids:
if lease.address_id and lease.address_id.title_deed:
title = lease.address_id.title_deed.strip()
if title and title not in seen_titles:
seen_titles.add(title)
unique_titles.append(title)
record.title_information = ', '.join(unique_titles)
def contract_signature(self):
return {
'type': 'ir.actions.act_window',
@@ -1645,6 +1658,11 @@ class PropertyLeaseContractLine(models.Model):
_description = '物业列表明细行'
lease_id = fields.Many2one('property.lease.contract', string="关联凭租合同审批")
construction_id = fields.Many2one('property.construction.approval', string="关联建设工程造价咨询合同审批")
project_id = fields.Many2one('property.project.approval', string="关联工程立项")
design_id = fields.Many2one('property.design.approval', string="关联建设工程设计合同审批")
accounting_id = fields.Many2one('property.accounting.approval', string="关联建设工程委托监理合同审批")
supervising_id = fields.Many2one('property.supervising.approval', string="关联建设工程施工合同审批")
address_id = fields.Many2one('yuthon.property', string="物业地址")
admin_line_id = fields.Many2one(related='address_id.admin_id', string="管理员")
property_area = fields.Float(related='address_id.management_area', string="面积")
@@ -12,12 +12,13 @@ class PropertyProjectApproval(models.Model):
default=lambda self: self.env['ir.sequence'].next_by_code('property_project_approval_code'))
users_id = fields.Many2one('res.users', string="申请人", default=lambda self: self.env.user.id)
department_id = fields.Many2one(related='users_id.employee_id.department_id', string="部门")
property_id = fields.Many2one('yuthon.property', string='物业')
property_address = fields.Char(string='物业地址')
background_note = fields.Html(string="背景说明")
documents_id = fields.Many2one('ir.attachment', string="建议书/可研报告")
amount = fields.Float(string="预算金额")
start_date = fields.Date(string="开始日期")
end_date = fields.Date(string="结束日期")
lease_ids = fields.One2many('property.lease.contract.line', 'project_id', string="物业信息")
urgency_level = fields.Selection([('normal', '普件'), ('urgent', '急件'), ('emergency', '特急件')], string='紧急度',
default='normal')
active = fields.Boolean('Active', default=True, tracking=True)
@@ -27,4 +28,16 @@ class PropertyProjectApproval(models.Model):
return self._description if self._description else self._name
name_title = fields.Char(default=_get_default_name_title)
self_users_ids = fields.Many2many('res.users', string="当前经办人", default=lambda self: [(6, 0, [self.env.user.id])])
self_users_ids = fields.Many2many('res.users', string="当前经办人", default=lambda self: [(6, 0, [self.env.user.id])])
def build_pop(self):
return {
'name': '添加物业',
'type': 'ir.actions.act_window',
'res_model': 'build.pop.wizard',
'view_mode': 'form',
'target': 'new',
'context': {
'default_project_id': self.id,
}
}
@@ -4,19 +4,25 @@ from odoo.exceptions import UserError
class PropertySporadicWorks(models.Model):
_name = 'property.sporadic.works'
_description = '委托招标代理'
_description = '项目委托招标代理合同'
_inherit = ['soong.workflow.mixin', 'mail.thread.main.attachment', 'mail.activity.mixin']
name = fields.Char(string="工程名称", required=True)
code = fields.Char(string="编号", default=lambda self: self.env['ir.sequence'].next_by_code('property_sporadic_works_code'))
name = fields.Char(string="合同编号", required=True)
code = fields.Char(string="流水号", default=lambda self: self.env['ir.sequence'].next_by_code('property_sporadic_works_code'))
users_id = fields.Many2one('res.users', string="申请人", default=lambda self: self.env.user.id)
company_a_id = fields.Many2one('yuthon.property.company', string="甲方")
company_b_id = fields.Many2one('property.construction.unit', string="乙方")
department_id = fields.Many2one(related='users_id.employee_id.department_id', string="部门")
signing_date = fields.Date(string="签订日期")
acceptance_date = fields.Date(string="验收日期")
total = fields.Float(string="总金额")
coping = fields.Float(string="应付")
paid = fields.Float(string="已付")
not_paid = fields.Float(string="未付")
company_id = fields.Many2one(related='users_id.employee_id.company_id', string="公司")
text = fields.Text(string="正文")
three_quotation_id = fields.Many2one('ir.attachment', string="三方报价")
service_contract = fields.Many2one('ir.attachment', string="服务合同")
service_start_date = fields.Date(string="服务开始时间")
service_end_date = fields.Date(string="服务结束时间")
standard_amount = fields.Float(string="标准金额")
service_fee = fields.Float(string="服务费")
settlement_party = fields.Selection([('self' , '我方'), ('other', '中标方')], string="结算方")
payment_methods = fields.Selection([('onetime', '一次性'), ('installment', '分期')], string="付款方式")
payment_methods_line_ids = fields.One2many('payment.methods.line', 'payment_methods_id', string="付款方式明细行")
urgency_level = fields.Selection([('normal', '普件'), ('urgent', '急件'), ('emergency', '特急件')], string='紧急度',
default='normal')
@@ -34,10 +40,10 @@ class PaymentMethodsLine(models.Model):
_name = 'payment.methods.line'
_description = '付款方式明细行'
name = fields.Char(string="合同阶段")
payment_nodes = fields.Selection([('first', '一期' ), ('second', '二期'), ('third', '三期'), ('fourth', '四期')], string="支付节点")
payout_ratio = fields.Float(string="支付比例")
coping_date = fields.Date(string="应付日期")
amount = fields.Float(string="金额")
remake = fields.Char(string="备注")
quotations_list_id = fields.Many2one('ir.attachment', string="报价清单")
accounting_list_id = fields.Many2one('ir.attachment', string="核算清单")
payment_instructions = fields.Text(string="支付说明")
payment_methods_id = fields.Many2one('property.sporadic.works', string="关联付款方式")
@@ -4,30 +4,35 @@ from odoo.exceptions import UserError, ValidationError
class PropertySupervisingApproval(models.Model):
_name = 'property.supervising.approval'
_description = '工程设计合同审批'
_description = '建设工程施工合同审批 '
_inherit = ['soong.workflow.mixin', 'mail.thread.main.attachment', 'mail.activity.mixin']
name = fields.Char(string='标题')
code = fields.Char(string="编号",
default=lambda self: self.env['ir.sequence'].next_by_code('property_supervising_code'))
users_id = fields.Many2one('res.users', string="申请人", default=lambda self: self.env.user.id)
department_id = fields.Many2one(related='users_id.employee_id.department_id', string="部门")
company_id = fields.Many2one('yuthon.property.company', string="甲方")
project_content = fields.Char(string="工程内容")
company_b_id = fields.Many2one('property.construction.unit', string="乙方")
property_id = fields.Many2one('yuthon.property', string='物业')
reason = fields.Text(string="正文")
documents_ids = fields.Many2many('ir.attachment', string="附件")
contract_id = fields.Many2one('ir.attachment', string="合同")
start_date = fields.Date(string="开始日期")
end_date = fields.Date(string="结束日期")
review_price = fields.Float(string="审核价")
business_type = fields.Char(string="业务类型")
contract_amount = fields.Float(string="合同金额")
payment_methods = fields.Char(string="付款方式")
supervising_way_ids = fields.One2many('supervising.way.line', 'supervising_id', string="关联支付方式")
urgency_level = fields.Selection([('normal', '普件'), ('urgent', '急件'), ('emergency', '特急件')], string='紧急度',
default='normal')
users_id = fields.Many2one('res.users', string="申请人", default=lambda self: self.env.user.id)
department_id = fields.Many2one(related='users_id.employee_id.department_id', string="部门")
company_id = fields.Many2one(related='users_id.employee_id.company_id', string="公司")
company_a_id = fields.Many2one('yuthon.property.company', string="甲方")
company_b_id = fields.Many2one('property.construction.unit', string="乙方")
budget_list_id = fields.Many2one('ir.attachment', string="预算清单")
property_address = fields.Char(string='物业地址')
reason = fields.Text(string="正文")
image = fields.Binary(string="开工前图片")
contract_id = fields.Many2one('ir.attachment', string="合同")
start_date = fields.Date(string="开始日期")
project_content = fields.Char(string="工程内容")
end_date = fields.Date(string="结束日期")
review_price = fields.Float(string="审核价")
floating = fields.Float(string="浮动")
contract_amount = fields.Float(string="合同金额")
payment_methods = fields.Selection([('onetime', '一次性'), ('installment', '分期')], string="付款方式")
lease_ids = fields.One2many('property.lease.contract.line', 'supervising_id', string="物业信息明细")
business_type = fields.Char(string="业务类型")
active = fields.Boolean('Active', default=True, tracking=True)
work_end = fields.Boolean(string="结束")
@@ -37,11 +42,24 @@ class PropertySupervisingApproval(models.Model):
name_title = fields.Char(default=_get_default_name_title)
self_users_ids = fields.Many2many('res.users', string="当前经办人", default=lambda self: [(6, 0, [self.env.user.id])])
def build_pop(self):
return {
'name': '添加物业',
'type': 'ir.actions.act_window',
'res_model': 'build.pop.wizard',
'view_mode': 'form',
'target': 'new',
'context': {
'default_supervising_id': self.id,
}
}
class SupervisingWayLine(models.Model):
_name = 'supervising.way.line'
_description = '施工支付方式'
name = fields.Char(string="支付节点")
payment_nodes = fields.Selection([('first', '一期'), ('second', '二期'), ('third', '三期'), ('fourth', '四期')],
string="支付节点")
pay_ratio = fields.Float(string="支付比例%")
amount = fields.Float(string="金额")
remake = fields.Char(string="备注")
@@ -102,5 +102,6 @@ access_binding_information_wizard,binding_information_wizard,model_binding_infor
access_yuthon_property_ledger, yuthon_property_ledger,model_yuthon_property_ledger,base.group_user,1,1,1,1
access_property_lessee_analysis,property_lessee_analysis,model_property_lessee_analysis,base.group_user,1,1,1,1
access_contract_signature_wizard,contract_signature_wizard,model_contract_signature_wizard,base.group_user,1,1,1,1
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
1 id name model_id:id group_id:id perm_read perm_write perm_create perm_unlink
102 access_property_lessee_analysis property_lessee_analysis model_property_lessee_analysis base.group_user 1 1 1 1
103 access_contract_signature_wizard contract_signature_wizard model_contract_signature_wizard base.group_user 1 1 1 1
104 access_payment_process payment_process model_payment_process base.group_user 1 1 1 1
105 access_build_pop_wizard build_pop_wizard model_build_pop_wizard base.group_user 1 1 1 1
106
107
@@ -0,0 +1,56 @@
<?xml version="1.0" encoding="UTF-8" ?>
<odoo>
<record id="view_payment_process_tree" model="ir.ui.view">
<field name="name">payment.process.tree</field>
<field name="model">payment.process</field>
<field name="arch" type="xml">
<tree string="支付流程">
<field name="supervising_id"/>
<field name="reason"/>
<field name="payment_instructions"/>
</tree>
</field>
</record>
<record id="view_payment_process_form" model="ir.ui.view">
<field name="name">payment.process.form</field>
<field name="model">payment.process</field>
<field name="arch" type="xml">
<form string="支付流程">
<sheet>
<widget name="web_ribbon" title="普件" bg_color="text-bg-success"
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"
invisible="urgency_level != 'emergency'"/>
<group col="3">
<group>
<field name="code" string="流水号" readonly="1"/>
</group>
<group>
<field name="urgency_level" readonly="1"/>
</group>
<group/>
</group>
<div class="col-12 text-center">
<h1>
<field name="name_title" readonly="1"/>
</h1>
</div>
<group string="审批事项">
<field name="work_end" invisible="1"/>
<field name="users_id"/>
<field name="supervising_id"/>
<field name="reason"/>
<field name="payment_instructions"/>
<field name="payment_nodes"/>
<field name="amount"/>
<field name="documents_id" widget="preview_many2one"/>
<field name="department_id" invisible="1"/>
<field name="company_id" invisible="1"/>
</group>
</sheet>
</form>
</field>
</record>
</odoo>
@@ -4,7 +4,7 @@
<field name="name">property.accounting.approval.tree</field>
<field name="model">property.accounting.approval</field>
<field name="arch" type="xml">
<tree string="建设工程委托核算合同审批">
<tree string="建设工程委托监理合同审批">
<field name="name"/>
<field name="company_id" required="1"/>
<field name="company_b_id"/>
@@ -17,7 +17,7 @@
<field name="name">property.accounting.approval.form</field>
<field name="model">property.accounting.approval</field>
<field name="arch" type="xml">
<form string="建设工程委托核算合同审批" create="0">
<form string="建设工程委托监理合同审批" create="0">
<sheet>
<widget name="web_ribbon" title="普件" bg_color="text-bg-success"
invisible="urgency_level != 'normal'"/>
@@ -42,49 +42,58 @@
<group>
<field name="name" required="1" string="合同编号:"/>
</group>
<group col="2">
<group col="2">
<group>
<field name="company_id" required="1"/>
<field name="project_content"/>
<field name="users_id" invisible="1"/>
<field name="department_id" invisible="1"/>
<field name="company_a_id"/>
</group>
<group>
<field name="company_b_id" options="{'no_create': True}"/>
<field name="property_id" options="{'no_create': True}"/>
<field name="company_b_id"/>
</group>
</group>
<group>
<field name="work_end" invisible="1"/>
<field name="users_id"/>
<field name="work_end" invisible="1"/>
<field name="property_address"/>
<field name="reason"/>
<field name="three_point_offer"/>
<field name="documents_ids" widget="preview_many2many"/>
<field name="image"/>
<field name="budget_list_id" widget="preview_many2one"/>
<field name="contract_id" widget="preview_many2one"/>
</group>
<group col="2">
<group>
<field name="start_date"/>
<field name="amount"/>
</group>
<group>
<field name="end_date"/>
<field name="is_tex"/>
</group>
</group>
<label for="lack"/>
<label for="start_date"/>
<div class="d-inline-flex w-100">
<field name="lack" class="me-2" style="max-width: 11rem !important;" string=" "/>不足
<field name="percentage" class="me-2" style="max-width: 11rem !important;"/>元收百分比
<field name="start_date" class="me-2" style="max-width: 7rem;"
string="代理期限"/>至
<field name="end_date" class="me-2" style="max-width: 7rem;"
force_save="1"/>
</div>
<field name="contract_amount"/>
<field name="business_type"/>
<field name="payment_methods"/>
<field name="work_end" invisible="1"/>
<field name="company_id" invisible="1"/>
<field name="project_content"/>
<field name="department_id" invisible="1"/>
</group>
<notebook>
<page string="物业信息">
<button name="build_pop" string="添加物业" type="object"
class="btn-primary"/>
<field name="lease_ids">
<tree editable="bottom" create="false">
<field name="accounting_id" column_invisible="1"/>
<field name="address_id"/>
<field name="admin_line_id"/>
<field name="property_area"/>
<field name="evaluate_unit_price"/>
</tree>
</field>
</page>
<page string="支付方式">
<field name="accounting_way_ids">
<tree editable="bottom">
<field name="accounting_id" column_invisible="1"/>
<field name="pay_way"/>
<field name="interval"/>
<field name="service_charge"/>
<field name="remake"/>
<field name="accounting_id" column_invisible="1"/>
<field name="payment_nodes"/>
<field name="amount"/>
<field name="remake"/>
</tree>
</field>
</page>
@@ -94,7 +103,7 @@
</field>
</record>
<record id="view_property_accounting_approval_action" model="ir.actions.act_window">
<field name="name">核算审批</field>
<field name="name">建设工程委托监理合同审批</field>
<field name="res_model">property.accounting.approval</field>
<field name="view_mode">tree,form</field>
</record>
@@ -27,7 +27,7 @@
invisible="urgency_level != 'emergency'"/>
<group col="3">
<group>
<field name="code" string="流水号" readonly="1"/>
<field name="code" string="合同编号" readonly="1"/>
</group>
<group>
<field name="urgency_level" readonly="1"/>
@@ -40,49 +40,60 @@
</h1>
</div>
<group>
<field name="name" required="1" string="合同编号:"/>
<field name="name" readonly="1"/>
</group>
<group col="2">
<group>
<field name="work_end" invisible="1"/>
<field name="company_id" required="1"/>
<field name="project_content"/>
<field name="users_id" invisible="1"/>
<field name="department_id" invisible="1"/>
<field name="company_a_id"/>
</group>
<group>
<field name="company_b_id" options="{'no_create': True}"/>
<field name="property_id" options="{'no_create': True}"/>
<field name="company_b_id"/>
</group>
</group>
<group>
<field name="user_id"/>
<field name="work_end" invisible="1"/>
<field name="property_address"/>
<field name="department_id" invisible="1"/>
<field name="company_id" invisible="1"/>
<field name="reason"/>
<field name="image"/>
<field name="budget_list_id" widget="preview_many2one"/>
<field name="contract_id" widget="preview_many2one"/>
</group>
<group col="2">
<group>
<field name="contract_amount"/>
<field name="start_date"/>
<field name="review_price"/>
</group>
<group>
<field name="payment_methods"/>
<field name="end_date"/>
<field name="business_type"/>
</group>
<label for="start_date"/>
<div class="d-inline-flex w-100">
<field name="start_date" class="me-2" style="max-width: 7rem;"
string="代理期限"/>至
<field name="end_date" class="me-2" style="max-width: 7rem;"
force_save="1"/>
</div>
<field name="contract_amount"/>
<field name="business_type"/>
<field name="payment_methods"/>
</group>
<notebook>
<page string="物业信息">
<button name="build_pop" string="添加物业" type="object"
class="btn-primary"/>
<field name="lease_ids">
<tree editable="bottom" create="false">
<field name="construction_id" column_invisible="1"/>
<field name="address_id"/>
<field name="admin_line_id"/>
<field name="property_area"/>
<field name="evaluate_unit_price"/>
</tree>
</field>
</page>
<page string="支付方式">
<field name="construction_way_ids">
<tree editable="bottom">
<field name="construction_id" column_invisible="1"/>
<field name="name"/>
<field name="pay_ratio"/>
<tree editable="bottom">
<field name="construction_id" column_invisible="1"/>
<field name="payment_nodes"/>
<field name="coping_date"/>
<field name="amount"/>
<field name="paid_time"/>
<field name="remake"/>
</tree>
</tree>
</field>
</page>
</notebook>
@@ -6,10 +6,8 @@
<field name="arch" type="xml">
<tree string="零星工程">
<field name="name"/>
<field name="annual"/>
<field name="contract_date"/>
<field name="payment_date"/>
<field name="consult_fee"/>
<field name="service_start_date"/>
<field name="service_end_date"/>
</tree>
</field>
</record>
@@ -45,14 +43,43 @@
<field name="name" required="1"/>
</h1>
</div>
<group col="2">
<group>
<field name="company_a_id"/>
</group>
<group>
<field name="company_b_id"/>
</group>
</group>
<group>
<field name="user_id"/>
<field name="department_id" invisible="1"/>
<field name="company_id" invisible="1"/>
<field name="work_end" invisible="1"/>
<field name="annual"/>
<field name="contract_date"/>
<field name="signing_date"/>
<field name="payment_date"/>
<field name="consult_fee"/>
<field name="quotations_list_id" widget="preview_many2one"/>
<field name="matters"/>
<field name="text"/>
</group>
<group col="2">
<group>
<field name="license_id" widget="preview_many2one"/>
<field name="aptitude_id" widget="preview_many2one"/>
<field name="contract_id" widget="preview_many2one"/>
</group>
<group>
<field name="legal_person_id_card" widget="preview_many2one"/>
<field name="bid_winning" widget="preview_many2one"/>
</group>
</group>
<group>
<label for="service_start_date"/>
<div class="d-inline-flex w-100">
<field name="service_start_date" class="me-2" style="max-width: 7rem;"
string="服务期限"/>至
<field name="service_end_date" class="me-2" style="max-width: 7rem;"
force_save="1"/>
</div>
<field name="settlement_method"/>
<field name="floating"/>
</group>
</sheet>
</form>
@@ -44,43 +44,55 @@
</group>
<group col="2">
<group>
<field name="work_end" invisible="1"/>
<field name="company_id" required="1"/>
<field name="project_content"/>
<field name="users_id" invisible="1"/>
<field name="department_id" invisible="1"/>
<field name="company_a_id"/>
</group>
<group>
<field name="company_b_id" options="{'no_create': True}"/>
<field name="property_id" options="{'no_create': True}"/>
<field name="company_b_id"/>
</group>
</group>
<group>
<field name="work_end" invisible="1"/>
<field name="users_id"/>
<field name="property_address"/>
<field name="reason"/>
<field name="three_point_offer"/>
<field name="image"/>
<field name="budget_list_id" widget="preview_many2one"/>
<field name="contract_id" widget="preview_many2one"/>
</group>
<group col="2">
<group>
<field name="contract_amount"/>
<field name="start_date"/>
<field name="review_price"/>
</group>
<group>
<field name="payment_methods"/>
<field name="end_date"/>
<field name="business_type"/>
</group>
<label for="start_date"/>
<div class="d-inline-flex w-100">
<field name="start_date" class="me-2" style="max-width: 7rem;"
string="合同期限"/>至
<field name="end_date" class="me-2" style="max-width: 7rem;"
force_save="1"/>
</div>
<field name="contract_amount"/>
<field name="business_type"/>
<field name="payment_methods"/>
<field name="work_end" invisible="1"/>
<field name="company_id" invisible="1"/>
<field name="project_content"/>
<field name="department_id" invisible="1"/>
</group>
<notebook>
<page string="物业信息">
<button name="build_pop" string="添加物业" type="object"
class="btn-primary"/>
<field name="lease_ids">
<tree editable="bottom" create="false">
<field name="design_id" column_invisible="1"/>
<field name="address_id"/>
<field name="admin_line_id"/>
<field name="property_area"/>
<field name="evaluate_unit_price"/>
</tree>
</field>
</page>
<page string="支付方式">
<field name="design_way_ids">
<tree editable="bottom">
<field name="design_id" column_invisible="1"/>
<field name="name"/>
<field name="pay_ratio"/>
<field name="payment_nodes"/>
<field name="amount"/>
<field name="paid_time"/>
<field name="remake"/>
</tree>
</field>
@@ -92,7 +104,7 @@
</record>
<record id="view_property_design_approval_action" model="ir.actions.act_window">
<field name="name">建设工程设计合同审批</field>
<field name="res_model">property.construction.approval</field>
<field name="res_model">property.design.approval</field>
<field name="view_mode">tree,form</field>
</record>
</odoo>
@@ -6,7 +6,7 @@
<field name="arch" type="xml">
<tree string="项目立项审批">
<field name="name"/>
<field name="property_id"/>
<field name="property_address"/>
<field name="amount"/>
<field name="start_date"/>
<field name="end_date"/>
@@ -42,15 +42,30 @@
<group>
<field name="work_end" invisible="1"/>
<field name="name" required="1" string="项目名称:"/>
<field name="property_address"/>
<field name="users_id" invisible="1"/>
<field name="department_id" invisible="1"/>
<field name="property_id" options="{'no_create': True}"/>
<field name="background_note"/>
<field name="amount"/>
<field name="documents_id" widget="preview_many2one"/>
<field name="start_date"/>
<field name="end_date"/>
</group>
<notebook>
<page string="物业信息">
<button name="build_pop" string="添加物业" type="object"
class="btn-primary"/>
<field name="lease_ids">
<tree editable="bottom" create="false">
<field name="project_id" column_invisible="1"/>
<field name="address_id"/>
<field name="admin_line_id"/>
<field name="property_area"/>
<field name="evaluate_unit_price"/>
</tree>
</field>
</page>
</notebook>
</sheet>
</form>
</field>
@@ -4,11 +4,8 @@
<field name="name">property.sporadic.works.tree</field>
<field name="model">property.sporadic.works</field>
<field name="arch" type="xml">
<tree string="委托招标代理">
<tree string="项目委托招标代理合同">
<field name="name"/>
<field name="signing_date"/>
<field name="acceptance_date"/>
<field name="total"/>
</tree>
</field>
</record>
@@ -16,7 +13,7 @@
<field name="name">property.sporadic.works.form</field>
<field name="model">property.sporadic.works</field>
<field name="arch" type="xml">
<form string="委托招标代理" create="0">
<form string="项目委托招标代理合同" create="0">
<sheet>
<widget name="web_ribbon" title="普件" bg_color="text-bg-success"
invisible="urgency_level != 'normal'"/>
@@ -44,27 +41,47 @@
<field name="name" required="1"/>
</h1>
</div>
<group col="2">
<group>
<field name="company_a_id"/>
</group>
<group>
<field name="company_b_id"/>
</group>
</group>
<group>
<field name="signing_date"/>
<field name="acceptance_date"/>
<field name="total"/>
<field name="work_end" invisible="1"/>
<field name="coping"/>
<field name="paid"/>
<field name="not_paid"/>
<field name="users_id" invisible="1"/>
<field name="work_end" invisible="1"/>
<field name="department_id" invisible="1"/>
<field name="company_id" invisible="1"/>
<field name="text"/>
<field name="three_quotation_id" widget="preview_many2one"/>
<field name="service_contract" widget="preview_many2one"/>
<label for="service_start_date"/>
<div class="d-inline-flex w-100">
<field name="service_start_date" class="me-2" style="max-width: 7rem;"
string="服务期限"/>至
<field name="service_end_date" class="me-2" style="max-width: 7rem;"
force_save="1"/>
</div>
</group>
<group col="2">
<group>
<field name="standard_amount"/>
<field name="service_fee"/>
</group>
<group>
<field name="settlement_party"/>
<field name="payment_methods"/>
</group>
</group>
<notebook>
<page string="付款方式">
<field name="payment_methods_line_ids">
<tree editable="bottom">
<field name="name"/>
<field name="payment_nodes"/>
<field name="coping_date"/>
<field name="amount"/>
<field name="remake"/>
<field name="quotations_list_id" widget="preview_many2one"/>
<field name="accounting_list_id" widget="preview_many2one"/>
</tree>
</field>
</page>
@@ -42,43 +42,58 @@
<group>
<field name="name" required="1" string="合同编号:"/>
</group>
<group col="2">
<group col="2">
<group>
<field name="work_end" invisible="1"/>
<field name="company_id" required="1"/>
<field name="project_content"/>
<field name="users_id" invisible="1"/>
<field name="department_id" invisible="1"/>
<field name="company_a_id"/>
</group>
<group>
<field name="company_b_id"/>
<field name="property_id"/>
</group>
</group>
<group>
<field name="work_end" invisible="1"/>
<field name="users_id"/>
<field name="property_address"/>
<field name="reason"/>
<field name="documents_ids" widget="preview_many2many"/>
<field name="image"/>
<field name="budget_list_id" widget="preview_many2one"/>
<field name="contract_id" widget="preview_many2one"/>
</group>
<group col="2">
<group>
<field name="contract_amount"/>
<field name="start_date"/>
<field name="review_price"/>
</group>
<group>
<field name="payment_methods"/>
<field name="end_date"/>
<field name="business_type"/>
</group>
<label for="start_date"/>
<div class="d-inline-flex w-100">
<field name="start_date" class="me-2" style="max-width: 7rem;"
string="代理期限"/>至
<field name="end_date" class="me-2" style="max-width: 7rem;"
force_save="1"/>
</div>
<field name="review_price"/>
<field name="floating"/>
<field name="contract_amount"/>
<field name="business_type"/>
<field name="payment_methods"/>
<field name="work_end" invisible="1"/>
<field name="company_id" invisible="1"/>
<field name="project_content"/>
<field name="department_id" invisible="1"/>
</group>
<notebook>
<page string="物业信息">
<button name="build_pop" string="添加物业" type="object"
class="btn-primary"/>
<field name="lease_ids">
<tree editable="bottom" create="false">
<field name="supervising_id" column_invisible="1"/>
<field name="address_id"/>
<field name="admin_line_id"/>
<field name="property_area"/>
<field name="evaluate_unit_price"/>
</tree>
</field>
</page>
<page string="支付方式">
<field name="supervising_way_ids">
<tree editable="bottom">
<field name="supervising_id" column_invisible="1"/>
<field name="name"/>
<field name="pay_ratio"/>
<field name="payment_nodes"/>
<field name="amount"/>
<field name="remake"/>
</tree>
@@ -91,7 +106,7 @@
</record>
<record id="view_property_supervising_approval_action" model="ir.actions.act_window">
<field name="name">建设工程委托监理合同审批</field>
<field name="res_model">property.construction.approval</field>
<field name="res_model">property.supervising.approval</field>
<field name="view_mode">tree,form</field>
</record>
</odoo>
+2 -1
View File
@@ -9,4 +9,5 @@ from . import property_management_wizard
from . import click_reconciliation_wizard
from . import accounts_wizard
from . import binding_information_wizard
from . import contract_signature_wizard
from . import contract_signature_wizard
from . import build_pop_wizard
@@ -0,0 +1,48 @@
from odoo import models, fields, api, _, SUPERUSER_ID
from odoo.exceptions import UserError, ValidationError
class BuildPopWizard(models.TransientModel):
_name = 'build.pop.wizard'
_description = '添加物业弹窗'
property_ids = fields.Many2many('yuthon.property', string='物业')
construction_id = fields.Many2one('property.construction.approval', string="关联建设工程造价咨询合同审批")
project_id = fields.Many2one('property.project.approval', string="关联工程立项")
design_id = fields.Many2one('property.design.approval', string="关联建设工程设计合同审批")
accounting_id = fields.Many2one('property.accounting.approval', string="关联建设工程委托监理合同审批")
supervising_id = fields.Many2one('property.supervising.approval', string="关联建设工程施工合同审批")
def confirm(self):
# 收集所有选中物业的地址
property_addresses = [
prop.name
for prop in self.property_ids
if prop.name
]
concatenated_address = ', '.join(property_addresses)
related_fields = [
('construction_id', 'construction_id'),
('project_id', 'project_id'),
('design_id', 'design_id'),
('accounting_id', 'accounting_id'),
('supervising_id', 'supervising_id')
]
for field, line_field in related_fields:
record = getattr(self, field)
if record:
if hasattr(record, 'property_address'):
record.write({'property_address': concatenated_address})
existing_lines = self.env['property.lease.contract.line'].search([
(line_field, '=', record.id)
])
if existing_lines:
existing_lines.unlink()
for prop in self.property_ids:
self.env['property.lease.contract.line'].create({
line_field: record.id,
'address_id': prop.id,
})
@@ -0,0 +1,25 @@
<?xml version="1.0" encoding="UTF-8" ?>
<odoo>
<record id="build_pop_wizard_form" model="ir.ui.view">
<field name="name">build.pop.wizard.form</field>
<field name="model">build.pop.wizard</field>
<field name="arch" type="xml">
<form>
<sheet>
<group>
<field name="property_ids" widget="many2many_tags"/>
<field name="construction_id" invisible="1"/>
<field name="project_id" invisible="1"/>
<field name="design_id" invisible="1"/>
<field name="accounting_id" invisible="1"/>
<field name="supervising_id" invisible="1"/>
</group>
</sheet>
<footer>
<button name="confirm" string="确认" type="object" class="oe_highlight"/>
<button string="返回" class="btn-secondary" special="cancel"/>
</footer>
</form>
</field>
</record>
</odoo>
@@ -66,12 +66,6 @@ class ChoosePropertyWizard(models.Model):
name_val = lease.address_id.name
existing_names.append(name_val if name_val is not None else "无")
information_names = []
for lease in self.lease_contract_id.lease_ids:
if lease.address_id and lease.address_id.title_deed != '无产权':
deed_val = lease.address_id.title_deed
information_names.append(str(deed_val) if deed_val is not None else "无")
title_name = []
for lease in self.lease_contract_id.lease_ids:
if lease.address_id:
@@ -80,7 +74,6 @@ class ChoosePropertyWizard(models.Model):
# 过滤空字符串,避免拼接时出现空内容
all_names = [name for name in list(set(existing_names + lease_name)) if name]
title_information = [info for info in list(set(information_names + title_deed))]
title_address_combined = [addr for addr in list(set(title_address + title_name)) if addr]
existing_lease_ids = [(4, lease.id) for lease in self.lease_contract_id.lease_ids]
@@ -94,7 +87,6 @@ class ChoosePropertyWizard(models.Model):
if self.lease_contract_id.lease_ids else False,
'use_address': ','.join(all_names),
'address_for_delivery': ','.join(all_names),
'title_information': ','.join(title_information),
'total_area': sum([lease.property_area for lease in rec.lease_ids])
})
@@ -178,8 +178,8 @@ class PropertyRentalWizard(models.Model):
start_year_month = start_date_adj.strftime('%Y-%m')
end_year_month = rent_id.end_data.strftime('%Y-%m')
start_day = start_date_adj.day
# 通过period_month 来判断是否有免租期,则使用 period_rent,否则使用 monthly_amount
rent_amount = rent_id.period_rent if period_month else rent_id.monthly_amount
# 通过period_month 来判断是否有免租期,则使用 ,否则月租金使用 期间租金
rent_amount = rent_id.monthly_amount if period_month else rent_id.period_rent
if is_year:
if rent_id.month_number >12:
multiplier = rent_id.month_number - 12