Merge remote-tracking branch 'origin/dev' into dev
This commit is contained in:
Binary file not shown.
|
Before Width: | Height: | Size: 4.0 KiB After Width: | Height: | Size: 3.2 KiB |
@@ -1084,7 +1084,7 @@ class SoongWorkflowMixin(models.AbstractModel):
|
||||
btn_exec_action_el.set("icon", button.icon)
|
||||
# 接下来是隐藏的配置
|
||||
invisible = "state != '{0}' ".format(str(node.node_name))
|
||||
if button.review_type == 'user_role':
|
||||
if button.review_type == 'user_role' and model != 'yuthon.seals.approval':
|
||||
# 构建角色条件
|
||||
role_domain = []
|
||||
if button.users_role_id:
|
||||
@@ -1548,7 +1548,7 @@ class SoongWorkflowLine(models.Model):
|
||||
|
||||
model = fields.Char(string="Related Document Model", index=True)
|
||||
res_id = fields.Integer(string="Related Document ID", index=True)
|
||||
workflow_record_id = fields.Many2one("soong.workflow.record", string="标题")
|
||||
workflow_record_id = fields.Many2one("soong.workflow.record", string="标题", required=True)
|
||||
code = fields.Char(related="workflow_record_id.code", string="流水号")
|
||||
workflow_id = fields.Many2one(related="workflow_record_id.workflow_id", string="审批类型")
|
||||
company_id = fields.Many2one(related="workflow_record_id.company_id", string="公司")
|
||||
|
||||
@@ -562,13 +562,7 @@ class SoongWorkflowRecord(models.Model):
|
||||
department_ids = self.env['hr.department'].search([
|
||||
('id', 'child_of', active_department.id)
|
||||
]).ids
|
||||
valid_employee_ids = self.env['hr.employee'].search([
|
||||
('department_id', 'in', department_ids)
|
||||
]).ids
|
||||
valid_user_ids = self.env['res.users'].search([
|
||||
('employee_id', 'in', valid_employee_ids)
|
||||
]).ids
|
||||
domain = [('users_ids', 'in', valid_user_ids)]
|
||||
domain = [('department_id', 'in', department_ids)]
|
||||
if (operator == '=' and not value) or (operator == '!=' and value):
|
||||
domain = ['!'] + domain
|
||||
return domain
|
||||
|
||||
@@ -34,8 +34,8 @@
|
||||
<field name="soong_record_ids" style="width:100%; margin-top: 10px;">
|
||||
<tree create="1" edit="1" delete="1" editable="bottom" type="object">
|
||||
<button name="open_record" type="object" string="详情" class="btn-primary"/>
|
||||
<field name="workflow_record_id" domain="[('users_ids', 'in', uid)]"
|
||||
options="{'no_open': True}" context="{'tree_view_ref': 'soong_workflow.soong_workflow_record_no_action_tree'}"/>
|
||||
<field name="workflow_record_id" domain="[('member_of_department', '=', True), ('approvals_group_id.name', 'not in', ['考勤', '人事'])]"
|
||||
required="1" options="{'no_open': True}" context="{'tree_view_ref': 'soong_workflow.soong_workflow_record_no_action_tree'}"/>
|
||||
<field name="code" column_invisible="1"/>
|
||||
<field name="workflow_id"/>
|
||||
<field name="create_uid"/>
|
||||
@@ -92,8 +92,8 @@
|
||||
<field name="soong_record_ids" style="width:100%%; margin-top: 10px;">
|
||||
<tree editable="bottom" delete="False">
|
||||
<button name="open_record" type="object" string="详情" class="btn-primary"/>
|
||||
<field name="workflow_record_id" domain="[('users_ids', 'in', uid)]"
|
||||
options="{'no_open': True}" context="{'tree_view_ref': 'soong_workflow.soong_workflow_record_no_action_tree'}"/>
|
||||
<field name="workflow_record_id" domain="[('member_of_department', '=', True), ('approvals_group_id.name', 'not in', ['考勤', '人事'])]"
|
||||
required="1" options="{'no_open': True}" context="{'tree_view_ref': 'soong_workflow.soong_workflow_record_no_action_tree'}"/>
|
||||
<field name="code" column_invisible="1"/>
|
||||
<field name="workflow_id"/>
|
||||
<field name="create_uid"/>
|
||||
|
||||
@@ -891,7 +891,7 @@ class YuthonVacationReports(models.Model):
|
||||
if attendances:
|
||||
# 过滤有效考勤记录
|
||||
valid_attendances = [att for att in attendances if (
|
||||
att.check_in or att.check_out) and att.shift_name != '休息' and not att.is_abnormal]
|
||||
att.check_in or att.check_out or att.workflow_id.workflow_id.name == '外出') and att.shift_name != '休息' and not att.is_abnormal]
|
||||
leave_days = 0
|
||||
processed_leave_codes = set()
|
||||
|
||||
|
||||
@@ -53,6 +53,7 @@ class YuthonRenewalApproval(models.Model):
|
||||
def end_approval(self):
|
||||
self.ensure_one()
|
||||
original_contract = self.employee_id.contract_id
|
||||
resource_calendar_id = self.env['resource.calendar'].search([('company_id', '=', self.company_id.id)], limit=1)
|
||||
version_num = float(self.employee_id.contract_id.version.lstrip('Vv'))
|
||||
new_version_num = version_num + 1.0
|
||||
new_version = f"V{new_version_num:.1f}"
|
||||
@@ -73,7 +74,9 @@ class YuthonRenewalApproval(models.Model):
|
||||
'date_start': self.renewal_date,
|
||||
'state': 'open',
|
||||
'job_id': self.job_id.id,
|
||||
'resource_calendar_id': resource_calendar_id.id,
|
||||
'version': new_version,
|
||||
'is_probation': False,
|
||||
'contract_type_id': new_contract_type_id,
|
||||
'structure_type_id': self.payroll_structure_id.type_id.id,
|
||||
'department_id': self.department1_id.id
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 5.8 KiB After Width: | Height: | Size: 3.4 KiB |
@@ -1,6 +1,19 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<odoo>
|
||||
<data noupdate="1">
|
||||
<record forcecreate="True" id="property_update_deposit_state_task" model="ir.cron">
|
||||
<field name="name">定时任务:应收账单状态</field>
|
||||
<field name="model_id" ref="model_property_accounts_receivable"/>
|
||||
<field name="state">code</field>
|
||||
<field name="code">model.update_deposit_state_task()</field>
|
||||
<field eval="True" name="active"/>
|
||||
<field name="user_id" ref="base.user_root"/>
|
||||
<field name="interval_number">1</field>
|
||||
<field name="interval_type">days</field>
|
||||
<field name="nextcall" eval="(DateTime.now()).strftime('%Y-%m-%d 01:00:00')"/>
|
||||
<field name="numbercall">-1</field>
|
||||
<field eval="False" name="doall"/>
|
||||
</record>
|
||||
<record forcecreate="True" id="property_update_manage_new" model="ir.cron">
|
||||
<field name="name">定时任务:更新物业管理信息</field>
|
||||
<field name="model_id" ref="model_yuthon_property"/>
|
||||
|
||||
@@ -14,6 +14,7 @@ class PropertyAccountsReceivable(models.Model):
|
||||
_description = '应收账单'
|
||||
|
||||
payout_date = fields.Date(string='收款日期')
|
||||
deposit_state = fields.Selection([('unpaid', '未收'), ('no_paid', '收部分'), ('paid', '已收'), ('no', '待退'), ('yes', '已退')], string='状态', default='unpaid')
|
||||
is_liquidated_damages = fields.Boolean(string='生成违约金', default=True)
|
||||
rent_month = fields.Float(string='当月租金')
|
||||
tax = fields.Float(string='税率')
|
||||
@@ -53,14 +54,82 @@ class PropertyAccountsReceivable(models.Model):
|
||||
|
||||
acc_type = fields.Selection([('new', '新租'), ('done', '到期')], string='类型')
|
||||
bank_id = fields.Many2one('property.bank.statements', string='流水记录')
|
||||
workflow_record_id = fields.Many2one('soong.workflow.record', string="流程")
|
||||
receivable_log = fields.Text(string='应收日志')
|
||||
|
||||
def open_record(self):
|
||||
return {
|
||||
"type": "ir.actions.act_window",
|
||||
"res_model": self.workflow_record_id.res_model,
|
||||
"res_id": self.workflow_record_id.res_id,
|
||||
"name": self.workflow_record_id.name,
|
||||
"view_mode": "form",
|
||||
}
|
||||
|
||||
def update_is_liquidated_damages(self):
|
||||
rent_ids = self.env["property.accounts.receivable"].browse(
|
||||
self._context.get('active_ids', self._context.get('active_id')))
|
||||
for rent in rent_ids:
|
||||
rent.is_liquidated_damages = False
|
||||
|
||||
def update_deposit_state_task(self):
|
||||
receivable_ids = self.env["property.accounts.receivable"].search(
|
||||
[('management_type_id.name', '=', '押金'), ('deposit_state', '=', 'paid')])
|
||||
today = fields.Date.today()
|
||||
for receivable in receivable_ids:
|
||||
if receivable.contract_id.actual_end_time:
|
||||
if receivable.contract_id.actual_end_time < today:
|
||||
receivable.deposit_state = 'no'
|
||||
|
||||
def update_damages(self):
|
||||
# 获取当前选中的应收记录
|
||||
rent_ids = self.env["property.accounts.receivable"].browse(
|
||||
self._context.get('active_ids', self._context.get('active_id'))
|
||||
)
|
||||
today = fields.Date.context_today(self)
|
||||
for record in rent_ids:
|
||||
contract = record.contract_id
|
||||
is_ended = False
|
||||
if round(record.delivered1, 2) :
|
||||
if record.original_amount == round(record.delivered1, 2) + round(record.discount_amount, 2):
|
||||
record.deposit_state = 'paid'
|
||||
elif record.original_amount < round(record.delivered1, 2) + round(record.discount_amount, 2):
|
||||
record.deposit_state = 'paid'
|
||||
else:
|
||||
record.deposit_state = 'no_paid'
|
||||
else:
|
||||
record.deposit_state = 'unpaid'
|
||||
|
||||
if record.management_type_id and record.management_type_id.name == '押金':
|
||||
if contract and contract.actual_end_time:
|
||||
if contract.actual_end_time < today:
|
||||
is_ended = True
|
||||
is_forfeited_deposit = False
|
||||
if contract:
|
||||
renewal = self.env['property.lease.renewal'].search([
|
||||
('contract_id', '=', contract.id),
|
||||
('renewal_type', '=', 'early_checkout'),
|
||||
('work_end', '=', True),
|
||||
], limit=1)
|
||||
if renewal:
|
||||
is_forfeited_deposit = True
|
||||
workflow_record_id = self.env['soong.workflow.record'].sudo().search([
|
||||
('res_id', '=', renewal.id),
|
||||
('res_model', '=', renewal._name)
|
||||
], limit=1)
|
||||
record.workflow_record_id = workflow_record_id.id
|
||||
record.is_reconciliation = True
|
||||
record.delivered1 = record.submitted
|
||||
|
||||
if is_forfeited_deposit:
|
||||
record.deposit_state = 'yes' # 已退
|
||||
if record.contract_id:
|
||||
record.contract_id.contact_state = 'settle'
|
||||
record.has_date = renewal.early_quitting_date
|
||||
record.contract_id.compute_is_has()
|
||||
elif is_ended:
|
||||
record.deposit_state = 'no'
|
||||
|
||||
@api.onchange('contract_id')
|
||||
def _onchange_contract_id(self):
|
||||
"""选择合同时自动填充税率"""
|
||||
@@ -132,43 +201,60 @@ class PropertyAccountsReceivable(models.Model):
|
||||
|
||||
def compute_number_of_payments(self):
|
||||
for record in self:
|
||||
if record.due_date:
|
||||
due_year = record.due_date.year
|
||||
due_month = record.due_date.month
|
||||
# 次月1号(违约金开始计算的日期)
|
||||
next_month = due_month + 1 if due_month < 12 else 1
|
||||
next_year = due_year if due_month < 12 else due_year + 1
|
||||
penalty_start_date = date(next_year, next_month, 1)
|
||||
# 默认为0
|
||||
record.number_of_payments = 0
|
||||
|
||||
# 获取关联的支付明细
|
||||
modify_lines = self.env['receivable.modify.line'].search([
|
||||
('receivable_id', '=', record.id),
|
||||
('reconciliation_date', '!=', False)
|
||||
if not record.due_date:
|
||||
continue
|
||||
|
||||
due_year = record.due_date.year
|
||||
due_month = record.due_date.month
|
||||
next_month = due_month + 1 if due_month < 12 else 1
|
||||
next_year = due_year if due_month < 12 else due_year + 1
|
||||
penalty_start_date = date(next_year, next_month, 1)
|
||||
|
||||
# 1. 获取正常支付明细
|
||||
modify_lines = self.env['receivable.modify.line'].search([
|
||||
('receivable_id', '=', record.id),
|
||||
('reconciliation_date', '!=', False)
|
||||
], order='reconciliation_date asc')
|
||||
|
||||
# 2. 获取违约金支付明细
|
||||
penalty_receivable_id = self.env['property.accounts.receivable'].search([
|
||||
('contract_id', '=', record.contract_id.id),
|
||||
('due_date', '=', penalty_start_date),
|
||||
('management_type_id.name', '=', '违约金'),
|
||||
], limit=1)
|
||||
penalty_lines = self.env['receivable.modify.line']
|
||||
if penalty_receivable_id:
|
||||
penalty_lines = self.env['receivable.modify.line'].search([
|
||||
('receivable_id', '=', penalty_receivable_id.id),
|
||||
('reconciliation_date', '!=', False),
|
||||
('is_penalty', '=', True)
|
||||
], order='reconciliation_date asc')
|
||||
|
||||
penalty_receivable_id = self.env['property.accounts.receivable'].search([
|
||||
('contract_id', '=', record.contract_id.id),
|
||||
('due_date', '=', penalty_start_date),
|
||||
('management_type_id.name', '=', '违约金'),
|
||||
# 3. 基础次数
|
||||
rent_pay_count = len(modify_lines.filtered(lambda l: not l.is_penalty))
|
||||
penalty_pay_count = len(penalty_lines.filtered(lambda l: l.is_penalty))
|
||||
|
||||
deposit_penalty_count = 0
|
||||
contract = record.contract_id
|
||||
if contract:
|
||||
renewal = self.env['property.lease.renewal'].search([
|
||||
('contract_id', '=', contract.id),
|
||||
('renewal_type', '=', 'early_checkout'),
|
||||
('work_end', '=', True),
|
||||
], limit=1)
|
||||
if penalty_receivable_id:
|
||||
penalty_lines = self.env['receivable.modify.line'].search([
|
||||
('receivable_id', '=', penalty_receivable_id.id),
|
||||
('reconciliation_date', '!=', False),
|
||||
('is_penalty', '=', True)
|
||||
], order='reconciliation_date asc')
|
||||
else:
|
||||
penalty_lines = self.env['receivable.modify.line']
|
||||
if renewal:
|
||||
if not renewal.is_full_refund:
|
||||
penalty_amount = renewal.deposit - renewal.refund_amount - renewal.total_receivables
|
||||
if penalty_amount > 0:
|
||||
deposit_penalty_count = 1
|
||||
|
||||
rent_pay_count = len(modify_lines.filtered(lambda l: not l.is_penalty)) # 租金支付次数
|
||||
penalty_pay_count = len(penalty_lines.filtered(lambda l: l.is_penalty)) # 违约金支付次数
|
||||
if record.management_type_id.name == '押金':
|
||||
record.number_of_payments = rent_pay_count
|
||||
else:
|
||||
record.number_of_payments = rent_pay_count + penalty_pay_count
|
||||
if record.management_type_id.name == '押金':
|
||||
record.number_of_payments = rent_pay_count + deposit_penalty_count
|
||||
else:
|
||||
record.number_of_payments = 0
|
||||
|
||||
record.number_of_payments = rent_pay_count + penalty_pay_count
|
||||
|
||||
@api.depends('original_amount', 'delivered1', 'discount_amount')
|
||||
def compute_submitted(self):
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
<tree editable="bottom" string="应收账单" decoration-success="is_reconciliation == True" default_order="due_date desc" limit="15" delete="false"
|
||||
decoration-muted="is_invalid">
|
||||
<field name="acc_type" string=" "/>
|
||||
<field name="deposit_state"/>
|
||||
<field name="management_type_id" readonly="0"/>
|
||||
<field name="due_date" readonly="0" width="300px" required="1"/>
|
||||
<field name="due_date_end" readonly="0"/>
|
||||
@@ -46,6 +47,7 @@
|
||||
<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="deposit_state"/>
|
||||
<field name="management_type_id" readonly="0"/>
|
||||
<field name="due_date" readonly="0" width="300px" required="1"/>
|
||||
<field name="due_date_end" readonly="0"/>
|
||||
@@ -70,6 +72,7 @@
|
||||
<field name="is_suspend" optional="hide"/>
|
||||
<field name="is_write" column_invisible="1"/>
|
||||
<field name="bank_id" column_invisible="1"/>
|
||||
<field name="workflow_record_id" column_invisible="1"/>
|
||||
<field name="print_number"/>
|
||||
<field name="print_date"/>
|
||||
<field name="discount_date"/>
|
||||
|
||||
@@ -701,6 +701,7 @@ class PropertyAccountsReceivable(models.Model):
|
||||
"view_mode": "form",
|
||||
"target": "new",
|
||||
"context": {
|
||||
"default_receivable_id": self.id,
|
||||
"default_contract_id": self.contract_id.id,
|
||||
"default_lessee_id": self.lessee_id.id,
|
||||
"default_actual_date": self.due_date,
|
||||
|
||||
@@ -11,6 +11,7 @@ class PropertyBillsList(models.Model):
|
||||
actual_date = fields.Date(string='实付日期')
|
||||
amount = fields.Float(string='应付')
|
||||
amount_actual = fields.Float(string='实付')
|
||||
receivables_id = fields.Many2one('property.accounts.receivable', string='应收账单')
|
||||
contract_id = fields.Many2one('property.lease.contract', string="合同编号")
|
||||
lessee_id = fields.Many2one(related="contract_id.lessee_id", string="承租方", store=True)
|
||||
property_name = fields.Char(related='contract_id.property_name', string="物业信息")
|
||||
@@ -43,6 +44,7 @@ class PropertyBillsList(models.Model):
|
||||
'res_model': 'property.bills.wizard',
|
||||
'target': 'new',
|
||||
'context': {
|
||||
'default_receivables_id': self.receivables_id.id,
|
||||
'default_bills_list_id': self.id,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -115,15 +115,9 @@ class PropertyLeaseRenewal(models.Model):
|
||||
rec.phone = False
|
||||
rec.card = False
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@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)
|
||||
@@ -208,6 +202,8 @@ class PropertyLeaseRenewal(models.Model):
|
||||
'due_date': rec.effective_date,
|
||||
})
|
||||
elif rec.renewal_type == 'early_checkout':
|
||||
workflow_record_id = self.env["soong.workflow.record"].search(
|
||||
[("res_model", "=", self._name), ("res_id", "=", self.id)])
|
||||
lessor_id = rec.contract_id.lessor_id
|
||||
company_id = self.env['res.company'].search([('name', '=', '集团本部')], limit=1)
|
||||
if lessor_id.referred in ['天河投资', '天投城建']:
|
||||
@@ -224,25 +220,35 @@ class PropertyLeaseRenewal(models.Model):
|
||||
rec.contract_id.write({
|
||||
'actual_end_time': rec.early_quitting_date
|
||||
})
|
||||
penalty_amount = rec.balance - rec.total_receivables
|
||||
if rec.balance > rec.total_receivables and penalty_amount > 0:
|
||||
management_type_id = self.env['yuthon.management.type'].search([
|
||||
('name', '=', '违约金')
|
||||
], limit=1)
|
||||
exist_receivable = self.env['property.accounts.receivable'].search([
|
||||
('contract_id', '=', rec.contract_id.id),
|
||||
('management_type_id', '=', management_type_id.id),
|
||||
('due_date', '=', rec.early_quitting_date),
|
||||
('original_amount', '=', penalty_amount),
|
||||
], limit=1)
|
||||
if not exist_receivable:
|
||||
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': penalty_amount,
|
||||
'remark': rec.total_remake,
|
||||
})
|
||||
if not rec.is_full_refund:
|
||||
penalty_amount = rec.deposit - rec.refund_amount - rec.total_receivables
|
||||
if penalty_amount > 0:
|
||||
management_type_id = self.env['yuthon.management.type'].search([
|
||||
('name', '=', '违约金')
|
||||
], limit=1)
|
||||
exist_receivable = self.env['property.accounts.receivable'].search([
|
||||
('contract_id', '=', rec.contract_id.id),
|
||||
('management_type_id', '=', management_type_id.id),
|
||||
('due_date', '=', rec.early_quitting_date),
|
||||
('original_amount', '=', penalty_amount),
|
||||
], limit=1)
|
||||
if not exist_receivable:
|
||||
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': penalty_amount,
|
||||
'remark': rec.total_remake,
|
||||
})
|
||||
deposit_id = self.env['property.accounts.receivable'].search([
|
||||
('contract_id', '=', rec.contract_id.id),
|
||||
('management_type_id.name', '=', '押金'),
|
||||
], limit=1)
|
||||
if deposit_id:
|
||||
deposit_id.write({
|
||||
'workflow_record_id': workflow_record_id.id
|
||||
})
|
||||
|
||||
if rec.receivables_ids:
|
||||
refund_lines = rec.receivables_ids.filtered(lambda l: l.refund_amount > 0 and l.management_type_id.name != '押金')
|
||||
bills_line_list = []
|
||||
@@ -254,6 +260,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,
|
||||
'receivables_id': refund_line.id,
|
||||
'remake': rec.refund_remake
|
||||
})
|
||||
# 押金
|
||||
@@ -261,8 +268,6 @@ class PropertyLeaseRenewal(models.Model):
|
||||
[('name', '=', '押金')],
|
||||
limit=1
|
||||
)
|
||||
workflow_record_id = self.env["soong.workflow.record"].search(
|
||||
[("res_model", "=", self._name), ("res_id", "=", self.id)])
|
||||
deposit_amount = rec.deposit if rec.is_full_refund else rec.refund_amount
|
||||
if deposit_amount > 0:
|
||||
bills_line_list.append({
|
||||
@@ -275,10 +280,11 @@ class PropertyLeaseRenewal(models.Model):
|
||||
})
|
||||
|
||||
if not rec.is_full_refund:
|
||||
balance = rec.deposit - rec.refund_amount
|
||||
start_time = datetime.combine(rec.early_quitting_date, datetime.min.time().replace(hour=8, minute=00))
|
||||
existing_bank_statement = self.env['property.bank.statements'].sudo().search([
|
||||
('start_time', '=', start_time),
|
||||
('original_amount', '=', rec.balance),
|
||||
('original_amount', '=', balance),
|
||||
('name_account', '=', rec.lessee_id.name),
|
||||
('remake', '=', '押转租/没收押金'),
|
||||
('workflow_record_id', '=', workflow_record_id.id),
|
||||
@@ -287,7 +293,7 @@ class PropertyLeaseRenewal(models.Model):
|
||||
bank_id = self.env['property.bank.statements'].sudo().create({
|
||||
'start_time': start_time,
|
||||
'name': bank_accounts,
|
||||
'original_amount': rec.balance,
|
||||
'original_amount': balance,
|
||||
'name_account': rec.lessee_id.name,
|
||||
'remake': '押转租/没收押金',
|
||||
'lending_direction': 'loan',
|
||||
@@ -335,6 +341,7 @@ class PropertyLeaseRenewal(models.Model):
|
||||
for rec in normal_receivables:
|
||||
receivable_list.append([0, 0, {
|
||||
'receivable_id': rec.id,
|
||||
'is_reconciliation': rec.is_reconciliation,
|
||||
}])
|
||||
self.receivables_ids = receivable_list
|
||||
|
||||
@@ -360,7 +367,7 @@ class EarlyReceivablesLine(models.Model):
|
||||
renewal_id = fields.Many2one('property.lease.renewal', string='关联续租审批')
|
||||
receivable_id = fields.Many2one('property.accounts.receivable', string='应收账单')
|
||||
management_type_id = fields.Many2one(related='receivable_id.management_type_id', string='类型')
|
||||
is_reconciliation = fields.Boolean(related='receivable_id.is_reconciliation', string='对账')
|
||||
is_reconciliation = fields.Boolean(string='对账')
|
||||
due_date = fields.Date(related='receivable_id.due_date', string='应收日期')
|
||||
original_amount = fields.Float(string='金额', compute='_compute_original_amount')
|
||||
reduction_amount = fields.Float(string='减免金额')
|
||||
|
||||
@@ -423,7 +423,7 @@
|
||||
<field name="inherit_id" ref="yuthon_property.view_property_accounts_receivable_tree1"/>
|
||||
<field name="arch" type="xml">
|
||||
<xpath expr="//field[@name='has_date']" position="after">
|
||||
<button name="verification_wizard" string="核销" type="object" class="btn btn-primary"/>
|
||||
<button name="open_record" string="流程" type="object" class="btn btn-primary" />
|
||||
</xpath>
|
||||
<xpath expr="//field[@name='remark']" position="after">
|
||||
<field name="charging_range"/>
|
||||
@@ -459,6 +459,7 @@
|
||||
<field name="contract_id" string="合同"/>
|
||||
<field name="company_id"/>
|
||||
<field name="original_amount"/>
|
||||
<field name="deposit_state"/>
|
||||
<group expand="0" string="group_by">
|
||||
<filter name="group_company_id" string="公司" context="{'group_by':'company_id'}"/>
|
||||
<filter name="group_is_reconciliation" string="对账" context="{'group_by':'is_reconciliation'}"/>
|
||||
@@ -652,6 +653,13 @@
|
||||
<field name="binding_model_id" ref="yuthon_property.model_property_accounts_receivable"/>
|
||||
<field name="state">code</field>
|
||||
<field name="code">action = model.update_is_liquidated_damages()</field>
|
||||
</record>
|
||||
<record id="all_update_is_liquidated_damages" model="ir.actions.server">
|
||||
<field name="name">一次性更新</field>
|
||||
<field name="model_id" ref="yuthon_property.model_property_accounts_receivable"/>
|
||||
<field name="binding_model_id" ref="yuthon_property.model_property_accounts_receivable"/>
|
||||
<field name="state">code</field>
|
||||
<field name="code">action = model.update_damages()</field>
|
||||
</record>
|
||||
<record id="update_compute_lessee_id" model="ir.actions.server">
|
||||
<field name="name">同步出租方和承租方</field>
|
||||
|
||||
@@ -63,13 +63,11 @@ class PenaltyLineWizard(models.Model):
|
||||
if not due_date:
|
||||
return
|
||||
|
||||
pay_index = 0 # 是否是第一笔支付
|
||||
current_idx = 0 # 支付次数
|
||||
pay_index = 0
|
||||
current_idx = 0
|
||||
|
||||
# 2. 计算关键日期:、次月1号(违约金起算日)
|
||||
due_year = due_date.year
|
||||
due_month = due_date.month
|
||||
# # 次月1号(违约金开始计算的日期)
|
||||
next_month = due_month + 1 if due_month < 12 else 1
|
||||
next_year = due_year if due_month < 12 else due_year + 1
|
||||
start_date = date(next_year, next_month, 1)
|
||||
@@ -92,7 +90,7 @@ class PenaltyLineWizard(models.Model):
|
||||
('receivable_id', '=', penalty_receivable_id.id),
|
||||
('reconciliation_date', '!=', False),
|
||||
('is_penalty', '=', True)
|
||||
], order='reconciliation_date asc')
|
||||
], order='reconciliation_date asc')
|
||||
else:
|
||||
penalty_lines = self.env['receivable.modify.line']
|
||||
|
||||
@@ -100,14 +98,18 @@ class PenaltyLineWizard(models.Model):
|
||||
new_pay_lines = []
|
||||
rent_type = self.receivable_id.management_type_id
|
||||
penalty_type = self.env['yuthon.management.type'].search([('name', '=', '违约金')], limit=1)
|
||||
# 【新增】押金类型
|
||||
deposit_type = self.env['yuthon.management.type'].search([('name', '=', '押金')], limit=1)
|
||||
|
||||
all_lines = (modify_lines + penalty_lines).sorted(key=lambda l: l.reconciliation_date)
|
||||
|
||||
for pay_line in all_lines:
|
||||
pay_index += 1
|
||||
current_idx += 1
|
||||
pay_amount = pay_line.amount # 付款金额
|
||||
pay_date = pay_line.reconciliation_date # 付款日期
|
||||
is_penalty = pay_line.is_penalty # 是否是违约金
|
||||
pay_amount = pay_line.amount
|
||||
pay_date = pay_line.reconciliation_date
|
||||
is_penalty = pay_line.is_penalty
|
||||
|
||||
if is_penalty:
|
||||
days_overdue = (pay_date - penalty_start_date).days + 1
|
||||
if pay_line.not_collected > pay_line.amount:
|
||||
@@ -127,16 +129,17 @@ class PenaltyLineWizard(models.Model):
|
||||
days_overdue = 0
|
||||
current_penalty = 0
|
||||
|
||||
# 计算剩余本金
|
||||
remaining_principal = max(0, pay_line.not_collected - pay_amount)
|
||||
penalty_start_date = pay_date
|
||||
|
||||
if is_penalty:
|
||||
remake = f'支付违约金¥{pay_line.amount}'
|
||||
else:
|
||||
remake = f'支付金额¥{pay_line.amount}'
|
||||
|
||||
new_penalty_lines.append((0, 0, {
|
||||
'date': pay_date,
|
||||
'remake':remake,
|
||||
'remake': remake,
|
||||
'days_overdue': days_overdue,
|
||||
'remaining_principal': remaining_principal,
|
||||
'penalty': round(current_penalty, 2),
|
||||
@@ -151,7 +154,6 @@ class PenaltyLineWizard(models.Model):
|
||||
'remake': pay_remake,
|
||||
}))
|
||||
|
||||
# 未支付的违约金(静态)
|
||||
if not penalty_receivable_id.payout_date and penalty_receivable_id:
|
||||
new_penalty_lines.append((0, 0, {
|
||||
'date': start_date,
|
||||
@@ -161,8 +163,30 @@ class PenaltyLineWizard(models.Model):
|
||||
'penalty': penalty_receivable_id.submitted,
|
||||
}))
|
||||
|
||||
contract = receivable.contract_id
|
||||
if contract and receivable.management_type_id.name == '押金':
|
||||
# 1. 查找 合同对应的 提前退租 续约单
|
||||
renewal = self.env['property.lease.renewal'].search([
|
||||
('contract_id', '=', contract.id),
|
||||
('renewal_type', '=', 'early_checkout'),
|
||||
('work_end', '=', True),
|
||||
], limit=1)
|
||||
if renewal:
|
||||
# 2. 判断条件:未全额退款
|
||||
if not renewal.is_full_refund:
|
||||
# 3. 计算没收押金金额
|
||||
penalty_amount = renewal.deposit - renewal.refund_amount - renewal.total_receivables
|
||||
if penalty_amount > 0:
|
||||
# 4. 日期 = 提前退租日期
|
||||
penalty_date = renewal.early_quitting_date
|
||||
new_pay_lines.append((0, 0, {
|
||||
'date': penalty_date,
|
||||
'amount': -self.receivable_id.delivered1,
|
||||
'management_type_id': deposit_type.id if deposit_type else False,
|
||||
'remake': '没收押金',
|
||||
}))
|
||||
# 关联应付账单
|
||||
bills_id = self.env['property.bills.list'].search([('contract_id', '=', receivable.contract_id.id)])
|
||||
bills_id = self.env['property.bills.list'].search([('contract_id', '=', contract.id)])
|
||||
for bill in bills_id:
|
||||
if bill.actual_date:
|
||||
new_pay_lines.append((0, 0, {
|
||||
@@ -233,4 +257,4 @@ class PenaltyPayLine(models.Model):
|
||||
date = fields.Date(string='支付日期')
|
||||
amount = fields.Float(string='支付金额')
|
||||
management_type_id = fields.Many2one('yuthon.management.type', string='支付类型')
|
||||
remake = fields.Text(string='备注')
|
||||
remake = fields.Text(string='备注')
|
||||
|
||||
@@ -48,10 +48,10 @@
|
||||
<field name="pay_line_ids" string=" ">
|
||||
<tree editable="bottom">
|
||||
<field name="penalty_id" column_invisible="1"/>
|
||||
<field name="date" string="收款日期"/>
|
||||
<field name="date" string="收付款日期"/>
|
||||
<field name="amount" string="收款金额"/>
|
||||
<field name="management_type_id" string="收款类型"/>
|
||||
<field name="remake"/>
|
||||
<field name="remake"/>>
|
||||
</tree>
|
||||
</field>
|
||||
</page>
|
||||
|
||||
@@ -8,6 +8,7 @@ class PropertyBillsWizard(models.TransientModel):
|
||||
|
||||
bills_list_id = fields.Many2one('property.bills.list', string="账单")
|
||||
actual_date = fields.Date(string='实付日期', default=fields.Date.today)
|
||||
receivables_id = fields.Many2one('property.accounts.receivable', string="应收账单")
|
||||
|
||||
def confirm(self):
|
||||
receivable_ids = self.env['property.accounts.receivable'].search([
|
||||
@@ -17,13 +18,19 @@ class PropertyBillsWizard(models.TransientModel):
|
||||
if any(not receivable.is_reconciliation for receivable in receivable_ids):
|
||||
raise UserError("该合同下存在未对账的应收单,无法退金额")
|
||||
|
||||
if self.receivables_id:
|
||||
self.receivables_id.deposit_state = 'yes'
|
||||
|
||||
if self.actual_date:
|
||||
self.bills_list_id.actual_date = self.actual_date
|
||||
receivable = self.env['property.accounts.receivable'].search([('contract_id', '=', self.bills_list_id.contract_id.id),
|
||||
('management_type_id', '=', self.bills_list_i.management_type_id.id)
|
||||
])
|
||||
if receivable:
|
||||
receivable.write({'has_date': self.actual_date})
|
||||
receivable.write({'has_date': self.actual_date,
|
||||
'deposit_state': 'yes'
|
||||
})
|
||||
|
||||
self.bills_list_id.contract_id.contact_state = 'settle'
|
||||
self.bills_list_id.contract_id.compute_is_has()
|
||||
|
||||
|
||||
@@ -11,6 +11,7 @@ class PropertyDepositWizard(models.Model):
|
||||
_name = 'property.deposit.wizard'
|
||||
_description = '押金核销'
|
||||
|
||||
receivable_id = fields.Many2one('property.accounts.receivable', string='应收账款')
|
||||
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='物业信息')
|
||||
@@ -41,6 +42,7 @@ class PropertyDepositWizard(models.Model):
|
||||
record.contract_id.contact_state = 'settle'
|
||||
record.has_date = record.actual_date
|
||||
record.bills_list_id.contract_id.compute_is_has()
|
||||
record.receivable_id.deposit_state = 'yes'
|
||||
|
||||
|
||||
class DepositReconciliationLine(models.Model):
|
||||
|
||||
@@ -394,9 +394,14 @@ class PropertyReconciliationWizard(models.Model):
|
||||
final_remark = line.remake
|
||||
if line.collection_type != 'penalty':
|
||||
receivable.delivered1 = receivable.delivered1 + line.amount
|
||||
if receivable.original_amount == round(receivable.delivered1, 2) + line.amount + round(receivable.discount_amount, 2) :
|
||||
deposit_state = 'paid'
|
||||
else:
|
||||
deposit_state = 'no_paid'
|
||||
receivable.write({
|
||||
'is_reconciliation': is_reconciliation,
|
||||
'payout_date': rec.actual_date,
|
||||
'deposit_state': deposit_state,
|
||||
'remark': final_remark,
|
||||
'reconciliation_time': fields.Datetime.now(),
|
||||
'receivable_log': f'当前登录人{rec.env.user.name}于{fields.Datetime.now()}对户名为{rec.bank_id.name_account}进行对账操作,对账应收金额为{rec.receivable_total},实际金额为{rec.amount_water}'
|
||||
@@ -473,9 +478,27 @@ class PropertyReconciliationWizard(models.Model):
|
||||
if receivable_id and source_receivable and not receivable_id.source_receivable_id:
|
||||
receivable_id.write({'source_receivable_id': source_receivable.id})
|
||||
if receivable_id and line.amount:
|
||||
if receivable_id.original_amount == round(receivable_id.delivered1, 2) + line.amount + round(receivable_id.discount_amount, 2):
|
||||
deposit_state = 'paid'
|
||||
else:
|
||||
deposit_state = 'no_paid'
|
||||
|
||||
deposit_id = self.env['property.accounts.receivable'].search(
|
||||
[('contract_id', '=', receivable_id.contract_id.id),
|
||||
('workflow_record_id', '!=', False),
|
||||
('management_type_id.name', '=', '押金'),
|
||||
]
|
||||
)
|
||||
if deposit_id:
|
||||
deposit_id.deposit_state = 'yes'
|
||||
deposit_id.contract_id.contact_state = 'settle'
|
||||
deposit_id.has_date = fields.Datetime.now()
|
||||
deposit_id.contract_id.compute_is_has()
|
||||
|
||||
receivable_id.write({
|
||||
'delivered1': receivable_id.delivered1 + line.amount,
|
||||
'due_date': extract_end_date or line.due_date,
|
||||
'deposit_state' : deposit_state,
|
||||
'due_date_end': None,
|
||||
'is_reconciliation': is_reconciliation,
|
||||
'payout_date': rec.actual_date if (line.rent == line.amount and line.rent != 0) else None,
|
||||
|
||||
@@ -93,9 +93,9 @@
|
||||
<group>
|
||||
<label for="request_hour_to" string="结束日期"/>
|
||||
<div class="d-inline-flex w-100">
|
||||
<field name="start_date" string="结束日期" class="me-2" readonly="1"
|
||||
<field name="start_date" string="结束日期" class="me-2"
|
||||
style="max-width: 6rem !important;"/>
|
||||
<field name="task_week" string="" class="me-2" readonly="1" style="max-width: 4rem !important;"/>
|
||||
<field name="task_week" string="" class="me-2" style="max-width: 4rem !important;"/>
|
||||
<field name="request_hour_to" string=" " class="ms-2"
|
||||
style="max-width: 5rem !important;"/>
|
||||
</div>
|
||||
@@ -246,6 +246,49 @@
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
<record id="view_yuthon_will_task_kanban" model="ir.ui.view">
|
||||
<field name="name">yuthon.will.task.kanban</field>
|
||||
<field name="model">yuthon.will.task</field>
|
||||
<field name="arch" type="xml">
|
||||
<kanban>
|
||||
<field name="name"/>
|
||||
<field name="task_state"/>
|
||||
<field name="task_time"/>
|
||||
<field name="employee_id"/>
|
||||
<field name="employee_ids"/>
|
||||
<templates>
|
||||
<t t-name="kanban-box">
|
||||
<div class="oe_kanban_global_click" style="border-radius: 8px; padding: 12px; margin-bottom: 8px;">
|
||||
<!-- 标题行:任务名称 + 状态标签 -->
|
||||
<div style="display: flex; justify-content: space-between; align-items: flex-start; margin-bottom: 6px;">
|
||||
<div style="font-weight: bold; font-size: 14px; line-height: 1.5; flex: 1; margin-right: 8px;">
|
||||
<field name="name"/>
|
||||
</div>
|
||||
<div>
|
||||
<field name="task_state" widget="badge"
|
||||
decoration-success="task_state == 'done'"
|
||||
decoration-info="task_state == 'will'"
|
||||
decoration-muted="task_state == 'cancel'"/>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 时间行 -->
|
||||
<div style="color: #555; font-size: 13px; margin-bottom: 4px;">
|
||||
<field name="task_time"/>
|
||||
</div>
|
||||
<!-- 经办人 + 共N人 -->
|
||||
<div style="color: #555; font-size: 13px;">
|
||||
经办人:<field name="employee_id"/>
|
||||
<t t-if="record.employee_ids.raw_value">
|
||||
| 共<t t-esc="record.employee_ids.raw_value.length"/>人
|
||||
</t>
|
||||
</div>
|
||||
</div>
|
||||
</t>
|
||||
</templates>
|
||||
</kanban>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="view_calendar_event_calendar" model="ir.ui.view">
|
||||
<field name="name">yuthon.will.task.calendar</field>
|
||||
<field name="model">yuthon.will.task</field>
|
||||
@@ -265,19 +308,23 @@
|
||||
<record id='view_yuthon_will_task_action' model='ir.actions.act_window'>
|
||||
<field name='name'>我的日程</field>
|
||||
<field name='res_model'>yuthon.will.task</field>
|
||||
<field name='view_mode'>tree,calendar,form</field>
|
||||
<field name='view_mode'>tree,kanban,calendar,form</field>
|
||||
<field name='domain'>[('users_ids', 'in', [uid]), ('task_state', '!=', 'cancel')]</field>
|
||||
<field name="context">{'search_default_next_seven_days': 1}</field>
|
||||
<field name="view_ids" eval="[(5, 0, 0),
|
||||
(0, 0, {'view_mode': 'tree', 'view_id': ref('yuthon_will_task.view_yuthon_will_task_tree2')}),
|
||||
(0, 0, {'view_mode': 'form', 'view_id': ref('yuthon_will_task.view_yuthon_will_task_form2')})]"/>
|
||||
(0, 0, {'view_mode': 'kanban', 'view_id': ref('yuthon_will_task.view_yuthon_will_task_kanban')}),
|
||||
(0, 0, {'view_mode': 'form', 'view_id': ref('yuthon_will_task.view_yuthon_will_task_form2')})]" />
|
||||
</record>
|
||||
<record id='view_yuthon_will_task_action2' model='ir.actions.act_window'>
|
||||
<field name='name'>日程管理</field>
|
||||
<field name='res_model'>yuthon.will.task</field>
|
||||
<field name='view_mode'>tree,calendar,form</field>
|
||||
<field name='view_mode'>tree,kanban,calendar,form</field>
|
||||
<field name='domain'>[('task_state', '!=', 'cancel')]</field>
|
||||
<field name="context">{'search_default_next_seven_days': 1}</field>
|
||||
<field name="view_ids" eval="[(5, 0, 0),
|
||||
(0, 0, {'view_mode': 'tree', 'view_id': ref('yuthon_will_task.view_yuthon_will_task_tree2')}),
|
||||
(0, 0, {'view_mode': 'kanban', 'view_id': ref('yuthon_will_task.view_yuthon_will_task_kanban')})]" />
|
||||
</record>
|
||||
<record id='view_yuthon_will_task_action21' model='ir.actions.act_window'>
|
||||
<field name='name'>领导日程</field>
|
||||
@@ -289,11 +336,14 @@
|
||||
<record id='view_yuthon_will_task_action4' model='ir.actions.act_window'>
|
||||
<field name='name'>领导日程</field>
|
||||
<field name='res_model'>yuthon.will.task</field>
|
||||
<field name='view_mode'>tree,calendar,form</field>
|
||||
<field name='view_mode'>tree,kanban,calendar,form</field>
|
||||
<field name='domain'>[('user_role_ids.name', 'in', ['董事长', '分管领导', '总经理', '部门副经理', '副总经理',
|
||||
'司机']), ('task_state', '!=', 'cancel')]
|
||||
</field>
|
||||
<field name="context">{'search_default_next_seven_days': 1}</field>
|
||||
<field name="view_ids" eval="[(5, 0, 0),
|
||||
(0, 0, {'view_mode': 'tree', 'view_id': ref('yuthon_will_task.view_yuthon_will_task_tree2')}),
|
||||
(0, 0, {'view_mode': 'kanban', 'view_id': ref('yuthon_will_task.view_yuthon_will_task_kanban')})]" />
|
||||
</record>
|
||||
<record id="all_yuthon_will_task" model="ir.actions.server">
|
||||
<field name="name">更新</field>
|
||||
|
||||
Reference in New Issue
Block a user