@@ -72,7 +72,6 @@
|
||||
<field name="print_date"/>
|
||||
<field name="discount_date"/>
|
||||
<field name="has_date"/>
|
||||
<button name="receivable_log_wizard" string="日志" type="object" class="oe_highlight"/>
|
||||
</tree>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
@@ -438,70 +438,70 @@ class PropertyBankStatements(models.Model):
|
||||
|
||||
current_sequence += 10
|
||||
|
||||
|
||||
all_vals = []
|
||||
service_vals, next_seq = create_reconciliation_vals(service_ids, 'service', 1)
|
||||
rent_vals, next_seq = create_reconciliation_vals(rent_ids, 'rent', 1)
|
||||
deposit_vals, next_seq = create_reconciliation_vals(deposit_ids, 'deposit', 100)
|
||||
management_vals, next_seq = create_reconciliation_vals(management_ids, 'management_fee', 200)
|
||||
rename_vals, next_seq = create_reconciliation_vals(rename_fee_ids, 'rename_fee', 210)
|
||||
lightbox_vals, next_seq = create_reconciliation_vals(lightbox_ids, 'lightbox', 220)
|
||||
guanzi_vals, next_seq = create_reconciliation_vals(guanzi_ids, 'guanzijian', 230)
|
||||
water_vals, next_seq = create_reconciliation_vals(water_ids, 'water_fee', 300)
|
||||
electricity_vals, next_seq = create_reconciliation_vals(electricity_ids, 'electricity_fee', 400)
|
||||
fee_vals, next_seq = create_reconciliation_vals(fee_ids, 'fee', 500)
|
||||
|
||||
all_vals.extend(rent_vals)
|
||||
all_vals.extend(deposit_vals)
|
||||
all_vals.extend(lightbox_vals)
|
||||
all_vals.extend(guanzi_vals)
|
||||
all_vals.extend(service_vals)
|
||||
all_vals.extend(management_vals)
|
||||
all_vals.extend(water_vals)
|
||||
all_vals.extend(electricity_vals)
|
||||
all_vals.extend(fee_vals)
|
||||
all_vals.extend(rename_vals)
|
||||
|
||||
return all_vals, total_rent_month,
|
||||
return [], 0
|
||||
|
||||
def _get_context_and_action(self, record, all_vals, total_rent_month):
|
||||
"""
|
||||
:param record: 银行收款记录
|
||||
:param all_vals: 应收费用列表
|
||||
:param total_rent_month: 应收总金额
|
||||
:return:
|
||||
"""
|
||||
start_time = self.start_time + relativedelta(hours=8)
|
||||
warning_msg = self._check_unreconciled_statements(start_time)
|
||||
context = {
|
||||
"default_actual_date": fields.Date.to_date(start_time),
|
||||
"default_bank_id": self.id,
|
||||
"default_bank_branch": self.bank_branch,
|
||||
"default_account": record.name,
|
||||
"default_contract_ids": [(6, 0, self.contract_ids.ids)],
|
||||
"default_actual_total": record.original_amount,
|
||||
"default_reconciliation_line_ids": all_vals, # 租金,应收日期排序、管理费、电、水、押金
|
||||
'default_amount_reconciled': self.no_amount,
|
||||
"default_receivable_total": total_rent_month,
|
||||
"default_warning_msg":warning_msg,
|
||||
"dialog_size": "extra-large",
|
||||
"default_order": "due_date desc",
|
||||
}
|
||||
return {
|
||||
"type": "ir.actions.act_window",
|
||||
"name": "对账弹窗",
|
||||
"res_model": "property.reconciliation.wizard",
|
||||
"view_mode": "form",
|
||||
"target": "new",
|
||||
"dialog_size": "extra-large",
|
||||
"context": context,
|
||||
}
|
||||
if vals_list and type_name:
|
||||
used_type_names.add(type_name)
|
||||
|
||||
return vals_list, current_sequence
|
||||
|
||||
all_vals = []
|
||||
service_vals, next_seq = create_reconciliation_vals(service_ids, 'service', 1)
|
||||
rent_vals, next_seq = create_reconciliation_vals(rent_ids, 'rent', 1)
|
||||
deposit_vals, next_seq = create_reconciliation_vals(deposit_ids, 'deposit', 100)
|
||||
management_vals, next_seq = create_reconciliation_vals(management_ids, 'management_fee', 200)
|
||||
rename_vals, next_seq = create_reconciliation_vals(rename_fee_ids, 'rename_fee', 210)
|
||||
lightbox_vals, next_seq = create_reconciliation_vals(lightbox_ids, 'lightbox', 220)
|
||||
guanzi_vals, next_seq = create_reconciliation_vals(guanzi_ids, 'guanzijian', 230)
|
||||
water_vals, next_seq = create_reconciliation_vals(water_ids, 'water_fee', 300)
|
||||
electricity_vals, next_seq = create_reconciliation_vals(electricity_ids, 'electricity_fee', 400)
|
||||
fee_vals, next_seq = create_reconciliation_vals(fee_ids, 'fee', 500)
|
||||
|
||||
all_vals.extend(rent_vals)
|
||||
all_vals.extend(deposit_vals)
|
||||
all_vals.extend(lightbox_vals)
|
||||
all_vals.extend(guanzi_vals)
|
||||
all_vals.extend(service_vals)
|
||||
all_vals.extend(management_vals)
|
||||
all_vals.extend(water_vals)
|
||||
all_vals.extend(electricity_vals)
|
||||
all_vals.extend(fee_vals)
|
||||
all_vals.extend(rename_vals)
|
||||
|
||||
return all_vals, total_rent_month,
|
||||
return [], 0
|
||||
|
||||
def _get_context_and_action(self, record, all_vals, total_rent_month):
|
||||
"""
|
||||
:param record: 银行收款记录
|
||||
:param all_vals: 应收费用列表
|
||||
:param total_rent_month: 应收总金额
|
||||
:return:
|
||||
"""
|
||||
start_time = self.start_time + relativedelta(hours=8)
|
||||
warning_msg = self._check_unreconciled_statements(start_time)
|
||||
context = {
|
||||
"default_actual_date": fields.Date.to_date(start_time),
|
||||
"default_bank_id": self.id,
|
||||
"default_bank_branch": self.bank_branch,
|
||||
"default_account": record.name,
|
||||
"default_contract_ids": [(6, 0, self.contract_ids.ids)],
|
||||
"default_actual_total": record.original_amount,
|
||||
"default_reconciliation_line_ids": all_vals, # 租金,应收日期排序、管理费、电、水、押金
|
||||
'default_amount_reconciled': self.no_amount,
|
||||
"default_receivable_total": total_rent_month,
|
||||
"default_warning_msg":warning_msg,
|
||||
"dialog_size": "extra-large",
|
||||
"default_order": "due_date desc",
|
||||
}
|
||||
return {
|
||||
"type": "ir.actions.act_window",
|
||||
"name": "对账弹窗",
|
||||
"res_model": "property.reconciliation.wizard",
|
||||
"view_mode": "form",
|
||||
"target": "new",
|
||||
"dialog_size": "extra-large",
|
||||
"context": context,
|
||||
}
|
||||
|
||||
def _check_unreconciled_statements(self, current_transaction_time):
|
||||
"""
|
||||
检查所有承租方对应的银行账号在property.bank.statements中是否有未对账流水
|
||||
@@ -617,173 +617,51 @@ class PropertyAccountsReceivable(models.Model):
|
||||
actual_coping = fields.Float(string="实际应付", compute='_compute_actual_coping', store=True)
|
||||
charging_range = fields.Text(string="收费区间")
|
||||
|
||||
|
||||
def _get_reconciliation_vals(self, record, contract_id):
|
||||
collection_type_map = {
|
||||
'rent': '租金',
|
||||
'deposit': '押金',
|
||||
'management_fee': '管理费',
|
||||
'lightbox': '灯箱',
|
||||
'guanzijian': '管子间',
|
||||
'water_fee': '水费',
|
||||
'electricity_fee': '电费',
|
||||
'rename_fee': '更名费',
|
||||
'service': '有偿服务收入',
|
||||
'fee': '人工费/日光灯款/代垫用料费',
|
||||
}
|
||||
used_type_names = set()
|
||||
total_rent_month = 0
|
||||
base_domain = [
|
||||
('contract_id', '=', contract_id.id),
|
||||
('is_invalid', '=', False),
|
||||
('is_reconciliation', '=', False),
|
||||
]
|
||||
|
||||
def _search_receivable(management_type_name):
|
||||
domain = base_domain + [('management_type_id.name', '=', management_type_name)]
|
||||
return self.env['property.accounts.receivable'].search(domain)
|
||||
|
||||
service_ids = _search_receivable('有偿服务收入')
|
||||
rent_ids = _search_receivable('租金')
|
||||
rename_fee_ids = _search_receivable('更名费')
|
||||
deposit_ids = _search_receivable('押金')
|
||||
management_ids = _search_receivable('管理费')
|
||||
lightbox_ids = _search_receivable('灯箱')
|
||||
guanzi_ids = _search_receivable('管子间')
|
||||
water_ids = _search_receivable('水费')
|
||||
electricity_ids = _search_receivable('电费')
|
||||
fee_ids = _search_receivable('人工费/日光灯款/代垫用料费')
|
||||
|
||||
def create_reconciliation_vals(ids, collection_type_val, sequence_val):
|
||||
"""
|
||||
:param ids:费用记录集
|
||||
:param collection_type_val: 费用类型(如 'rent', 'deposit')
|
||||
:return: 格式化后的费用行列表
|
||||
"""
|
||||
nonlocal total_rent_month
|
||||
vals_list = []
|
||||
current_sequence = sequence_val
|
||||
type_name = collection_type_map.get(collection_type_val, '')
|
||||
# 特殊处理:押金类型需要去重相同合同的记录
|
||||
if collection_type_val == 'deposit':
|
||||
# 使用字典来跟踪已处理的合同ID
|
||||
processed_contracts = set()
|
||||
for sub_record in ids:
|
||||
contract_id = sub_record.contract_id.id if sub_record.contract_id else False
|
||||
original_amount = sub_record.original_amount if sub_record.original_amount else 0
|
||||
submitted = sub_record.submitted if sub_record.submitted else 0
|
||||
# 跳过已处理的合同
|
||||
if contract_id and contract_id in processed_contracts:
|
||||
continue
|
||||
# 获取合同的实际结束日期作为到期日
|
||||
due_date = False
|
||||
if contract_id:
|
||||
due_date = sub_record.contract_id.actual_start_time
|
||||
# 构建对账行数据
|
||||
vals = {
|
||||
'contract_id': contract_id,
|
||||
'rent_month': original_amount,
|
||||
'rent': submitted,
|
||||
'collection_type': collection_type_val,
|
||||
'sequence': current_sequence,
|
||||
'due_date': due_date, # 押金类型使用合同实际开始日期
|
||||
}
|
||||
total_rent_month += original_amount # 累加总金额
|
||||
vals_list.append((0, 0, vals))
|
||||
# 标记此合同已处理
|
||||
if contract_id:
|
||||
processed_contracts.add(contract_id)
|
||||
|
||||
current_sequence += 10
|
||||
else:
|
||||
# 非押金类型:正常处理每条记录
|
||||
for sub_record in ids:
|
||||
contract_id = sub_record.contract_id.id if sub_record.contract_id else False
|
||||
original_amount = sub_record.original_amount if sub_record.original_amount else 0
|
||||
submitted = sub_record.submitted if sub_record.submitted else 0
|
||||
due_date = sub_record.due_date if sub_record.due_date else False
|
||||
vals = {
|
||||
'contract_id': contract_id,
|
||||
'rent_month': original_amount,
|
||||
'rent': submitted,
|
||||
'collection_type': collection_type_val,
|
||||
'sequence': current_sequence,
|
||||
'due_date': due_date,
|
||||
}
|
||||
total_rent_month += original_amount # 累加总金额
|
||||
vals_list.append((0, 0, vals))
|
||||
|
||||
current_sequence += 10
|
||||
|
||||
|
||||
all_vals = []
|
||||
service_vals, next_seq = create_reconciliation_vals(service_ids, 'service', 1)
|
||||
rent_vals, next_seq = create_reconciliation_vals(rent_ids, 'rent', 1)
|
||||
deposit_vals, next_seq = create_reconciliation_vals(deposit_ids, 'deposit', 100)
|
||||
management_vals, next_seq = create_reconciliation_vals(management_ids, 'management_fee', 200)
|
||||
rename_vals, next_seq = create_reconciliation_vals(rename_fee_ids, 'rename_fee', 210)
|
||||
lightbox_vals, next_seq = create_reconciliation_vals(lightbox_ids, 'lightbox', 220)
|
||||
guanzi_vals, next_seq = create_reconciliation_vals(guanzi_ids, 'guanzijian', 230)
|
||||
water_vals, next_seq = create_reconciliation_vals(water_ids, 'water_fee', 300)
|
||||
electricity_vals, next_seq = create_reconciliation_vals(electricity_ids, 'electricity_fee', 400)
|
||||
fee_vals, next_seq = create_reconciliation_vals(fee_ids, 'fee', 500)
|
||||
|
||||
all_vals.extend(rent_vals)
|
||||
all_vals.extend(deposit_vals)
|
||||
all_vals.extend(lightbox_vals)
|
||||
all_vals.extend(guanzi_vals)
|
||||
all_vals.extend(service_vals)
|
||||
all_vals.extend(management_vals)
|
||||
all_vals.extend(water_vals)
|
||||
all_vals.extend(electricity_vals)
|
||||
all_vals.extend(fee_vals)
|
||||
all_vals.extend(rename_vals)
|
||||
|
||||
return all_vals, total_rent_month,
|
||||
return [], 0
|
||||
|
||||
def _get_context_and_action(self, all_vals, total_rent_month):
|
||||
"""
|
||||
:param record: 银行收款记录
|
||||
:param all_vals: 应收费用列表
|
||||
:param total_rent_month: 应收总金额
|
||||
:return:
|
||||
"""
|
||||
start_time = self.start_time + relativedelta(hours=8)
|
||||
# context = {
|
||||
# "default_actual_date": fields.Date.to_date(start_time),
|
||||
# "default_contract_ids": [(6, 0, self.contract_id.id)],
|
||||
# "default_reconciliation_line_ids": all_vals, # 租金,应收日期排序、管理费、电、水、押金
|
||||
# "default_receivable_total": total_rent_month,
|
||||
# "dialog_size": "extra-large",
|
||||
# "default_order": "due_date desc",
|
||||
# }
|
||||
return {
|
||||
"type": "ir.actions.act_window",
|
||||
"name": "押金对账弹窗",
|
||||
"res_model": "property.deposit.wizard",
|
||||
"view_mode": "form",
|
||||
"target": "new",
|
||||
"dialog_size": "extra-large",
|
||||
# "context": context,
|
||||
}
|
||||
if vals_list and type_name:
|
||||
used_type_names.add(type_name)
|
||||
|
||||
return vals_list, current_sequence
|
||||
|
||||
def verification_wizard(self):
|
||||
for record in self:
|
||||
# all_vals, total_rent_month = self._get_reconciliation_vals(record, record.contract_id)
|
||||
return {
|
||||
"type": "ir.actions.act_window",
|
||||
"name": "押金对账弹窗",
|
||||
"res_model": "property.deposit.wizard",
|
||||
"view_mode": "form",
|
||||
"target": "new",
|
||||
"dialog_size": "extra-large",
|
||||
# "context": context,
|
||||
receivable_lines = self.env['property.accounts.receivable'].search([
|
||||
('contract_id', '=', self.contract_id.id),
|
||||
('is_reconciliation', '=', False),
|
||||
])
|
||||
receivable_line_vals = []
|
||||
for line in receivable_lines:
|
||||
receivable_line_vals.append((0, 0, {
|
||||
'due_date': line.due_date,
|
||||
'management_type_id': line.management_type_id.id,
|
||||
'amount': line.submitted,
|
||||
'payment_type': 'pay',
|
||||
'receivable_id': line.id,
|
||||
'remake': line.remark,
|
||||
}))
|
||||
|
||||
bills_lines = self.env['property.bills.list'].search([
|
||||
('contract_id', '=', self.contract_id.id),
|
||||
('actual_date', '!=', False),
|
||||
])
|
||||
bills_line_vals = []
|
||||
for line in bills_lines:
|
||||
bills_line_vals.append((0, 0, {
|
||||
'due_date': line.due_date,
|
||||
'management_type_id': line.management_type_id.id,
|
||||
'amount': line.amount,
|
||||
'bills_id': line.id,
|
||||
'payment_type': 'spending',
|
||||
'remake': line.remake
|
||||
}))
|
||||
all_line_vals = receivable_line_vals + bills_line_vals
|
||||
return {
|
||||
"type": "ir.actions.act_window",
|
||||
"name": "押金核销弹窗",
|
||||
"res_model": "property.deposit.wizard",
|
||||
"view_mode": "form",
|
||||
"target": "new",
|
||||
"context": {
|
||||
"default_contract_id": self.contract_id.id,
|
||||
"default_lessee_id": self.lessee_id.id,
|
||||
"default_actual_date": self.due_date,
|
||||
"default_deposit": self.original_amount,
|
||||
'default_reconciliation_line_ids': all_line_vals
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@api.depends('contract_id', 'due_date')
|
||||
|
||||
@@ -60,11 +60,22 @@ class PropertyLeaseRenewal(models.Model):
|
||||
deposit = fields.Float(string="原押金")
|
||||
is_full_refund = fields.Boolean(string="是否全额退押", default=True)
|
||||
refund_amount = fields.Float(string="退款金额")
|
||||
refund_remake = fields.Char(string="备注")
|
||||
total_receivables = fields.Float(string="应收金额", compute="_compute_total_receivables")
|
||||
total_remake = fields.Char(string="备注")
|
||||
balance = fields.Float(string="余额")
|
||||
remake = fields.Text(string="备注")
|
||||
balance_remake = fields.Char(string="备注")
|
||||
|
||||
receivables_ids = fields.One2many('early.receivables.line', 'renewal_id', string='应收明细')
|
||||
|
||||
@api.depends('receivables_ids', 'receivables_ids.original_amount', 'receivables_ids.reduction_amount',
|
||||
'receivables_ids.void')
|
||||
def _compute_total_receivables(self):
|
||||
for renewal in self:
|
||||
valid_receivable_lines = renewal.receivables_ids.filtered(lambda line: not line.void and line.is_reconciliation == False)
|
||||
total = sum(line.original_amount - line.reduction_amount for line in valid_receivable_lines)
|
||||
renewal.total_receivables = total
|
||||
|
||||
@api.onchange('refund_amount')
|
||||
def _onchange_refund_amount(self):
|
||||
for rec in self:
|
||||
@@ -177,19 +188,30 @@ class PropertyLeaseRenewal(models.Model):
|
||||
'contract_id': new_contract.id
|
||||
})
|
||||
else:
|
||||
receivable_ids = self.env['property.accounts.receivable'].search([
|
||||
('due_date', '<=', rec.early_quitting_date),
|
||||
('contract_id', '=', rec.contract_id.id),
|
||||
])
|
||||
# receivable_ids = self.env['property.accounts.receivable'].search([
|
||||
# ('due_date', '<=', rec.early_quitting_date),
|
||||
# ('contract_id', '=', rec.contract_id.id),
|
||||
# ])
|
||||
# if any(not receivable.is_reconciliation for receivable in receivable_ids):
|
||||
# raise UserError("该合同下存在未对账的应收单,无法提前退押金")
|
||||
|
||||
rec.contract_id.write({
|
||||
'actual_end_time': rec.early_quitting_date
|
||||
})
|
||||
rec.contract_id.get_property_contract_time()
|
||||
# rec.contract_id.get_property_contract_time()
|
||||
if rec.balance > rec.total_receivables:
|
||||
management_type_id = self.env['yuthon.management.type'].search([
|
||||
('name', '=', '违约金')
|
||||
])
|
||||
self.env['property.accounts.receivable'].create({
|
||||
'contract_id': rec.contract_id.id,
|
||||
'management_type_id': management_type_id.id,
|
||||
'due_date': rec.early_quitting_date,
|
||||
'original_amount': rec.balance - rec.total_receivables,
|
||||
'remark': rec.total_remake,
|
||||
})
|
||||
if rec.receivables_ids:
|
||||
refund_lines = rec.receivables_ids.filtered(lambda l: l.refund_amount > 0)
|
||||
refund_lines = rec.receivables_ids.filtered(lambda l: l.refund_amount > 0 and management_type_id.name != '押金')
|
||||
bills_line_list = []
|
||||
# 除押金的明细
|
||||
if refund_lines:
|
||||
@@ -199,7 +221,7 @@ class PropertyLeaseRenewal(models.Model):
|
||||
'management_type_id': refund_line.management_type_id.id,
|
||||
'amount': refund_line.refund_amount,
|
||||
'contract_id': rec.contract_id.id,
|
||||
'remake': rec.remake
|
||||
'remake': rec.refund_remake
|
||||
})
|
||||
# 押金
|
||||
deposit_management_type = self.env['yuthon.management.type'].search(
|
||||
@@ -213,7 +235,7 @@ class PropertyLeaseRenewal(models.Model):
|
||||
'management_type_id': deposit_management_type.id,
|
||||
'amount': deposit_amount,
|
||||
'contract_id': rec.contract_id.id,
|
||||
'remake': rec.remake
|
||||
'remake': rec.refund_remake
|
||||
})
|
||||
|
||||
if not rec.is_full_refund:
|
||||
@@ -222,7 +244,7 @@ class PropertyLeaseRenewal(models.Model):
|
||||
'start_time': start_time,
|
||||
'original_amount': rec.balance,
|
||||
'name_account': rec.lessee_id.name,
|
||||
'remake': rec.remake,
|
||||
'remake': rec.refund_remake,
|
||||
})
|
||||
|
||||
# 创建应付账单
|
||||
@@ -233,19 +255,16 @@ class PropertyLeaseRenewal(models.Model):
|
||||
for receivable_id in rec.receivables_ids:
|
||||
if receivable_id.void:
|
||||
receivable_id.receivable_id.write({
|
||||
'is_void': True,
|
||||
'is_invalid': True,
|
||||
'void_date': fields.Date.today()
|
||||
})
|
||||
if receivable_id.reduction_amount:
|
||||
receivable_id.receivable_id.reduction_amount = receivable_id.reduction_amount
|
||||
receivable_id.receivable_id.discount_amount = receivable_id.reduction_amount
|
||||
receivable_id.receivable_id.discount_date = fields.Date.today()
|
||||
|
||||
@api.onchange('early_quitting_date', 'contract_id')
|
||||
def _onchange_early_quitting_date(self):
|
||||
if not self.early_quitting_date :
|
||||
self.receivables_ids = [(5, 0, 0)]
|
||||
return
|
||||
|
||||
self.receivables_ids = [(5, 0, 0)]
|
||||
receivable_ids = self.env['property.accounts.receivable'].search([
|
||||
('due_date', '<=', self.early_quitting_date),
|
||||
('contract_id', '=', self.contract_id.id),
|
||||
|
||||
@@ -123,4 +123,5 @@ access_print_payment_wizard,print_payment_wizard,model_print_payment_wizard,base
|
||||
access_property_bills_list,property_bills_list,model_property_bills_list,base.group_user,1,1,1,1
|
||||
access_property_bills_wizard,property_bills_wizard,model_property_bills_wizard,base.group_user,1,1,1,1
|
||||
access_action_refuse_wizard,action_refuse_wizard,model_action_refuse_wizard,base.group_user,1,1,1,1
|
||||
access_property_deposit_wizard,property_deposit_wizard,model_property_deposit_wizard,base.group_user,1,1,1,1
|
||||
access_property_deposit_wizard,property_deposit_wizard,model_property_deposit_wizard,base.group_user,1,1,1,1
|
||||
access_deposit_reconciliation_line,deposit_reconciliation_line,model_deposit_reconciliation_line,base.group_user,1,1,1,1
|
||||
|
@@ -422,15 +422,7 @@
|
||||
<field name="model">property.accounts.receivable</field>
|
||||
<field name="inherit_id" ref="yuthon_property.view_property_accounts_receivable_tree1"/>
|
||||
<field name="arch" type="xml">
|
||||
<xpath expr="//tree" position="inside">
|
||||
<header>
|
||||
<button name="all_red" string="红冲" type="object" class="btn btn-primary"/>
|
||||
<button name="update_lessee_id" string="更新" type="object" class="btn btn-primary"/>
|
||||
</header>
|
||||
</xpath>
|
||||
<xpath expr="//button[@name='receivable_log_wizard']" position="before">
|
||||
<button name="penalty_wizard" string="收款明细" type="object" class="btn btn-primary" invisible="is_penalty"/>
|
||||
<button name="button_accounts_wizard" string="操作" type="object" class="btn btn-primary"/>
|
||||
<xpath expr="//field[@name='has_date']" position="before">
|
||||
<button name="verification_wizard" string="核销" type="object" class="btn btn-primary"/>
|
||||
</xpath>
|
||||
<xpath expr="//field[@name='remark']" position="after">
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
<form string="租赁变更审批" create="0">
|
||||
<sheet>
|
||||
<widget name="web_ribbon" title="普件" bg_color="text-bg-success"
|
||||
invisible="urgency_level != 'normal'"/>
|
||||
invisible="urgency_level != 'normal'"/>
|
||||
<widget name="web_ribbon" title="急件" bg_color="text-bg-warning"
|
||||
invisible="urgency_level != 'urgent'"/>
|
||||
<widget name="web_ribbon" title="特级" bg_color="text-bg-danger"
|
||||
@@ -41,7 +41,7 @@
|
||||
<group string="审批事项">
|
||||
<field name="is_back" invisible="1"/>
|
||||
<field name="name" required="1"/>
|
||||
<field name="renewal_type" widget="radio"/>
|
||||
<field name="renewal_type" widget="radio"/>
|
||||
<field name="company_id" invisible="1"/>
|
||||
<field name="department_id" invisible="1"/>
|
||||
<field name="work_end" invisible="1"/>
|
||||
@@ -83,34 +83,63 @@
|
||||
<field name="phone" invisible="renewal_type != 'lease'"/>
|
||||
</group>
|
||||
</group>
|
||||
<group>
|
||||
<field name="reason" invisible="renewal_type != 'lease'"/>
|
||||
<field name="effective_date" invisible="renewal_type != 'lease'"/>
|
||||
<field name="early_reason" invisible="renewal_type != 'early_checkout'"/>
|
||||
<field name="deposit" invisible="renewal_type != 'early_checkout'"/>
|
||||
<field name="is_full_refund" invisible="renewal_type != 'early_checkout'"/>
|
||||
</group>
|
||||
<group col="4">
|
||||
<group>
|
||||
<field name="reason" invisible="renewal_type != 'lease'"/>
|
||||
<field name="effective_date" invisible="renewal_type != 'lease'"/>
|
||||
<field name="early_reason" invisible="renewal_type != 'early_checkout'"/>
|
||||
<field name="deposit" invisible="renewal_type != 'early_checkout'"/>
|
||||
<field name="is_full_refund" invisible="renewal_type != 'early_checkout'"/>
|
||||
<field name="refund_amount" invisible="is_full_refund"/>
|
||||
<field name="balance" invisible="is_full_refund"/>
|
||||
<field name="remake" invisible="is_full_refund"/>
|
||||
<field name="early_explain" invisible="renewal_type != 'early_checkout'"/>
|
||||
<field name="document_ids" widget="preview_many2many"/>
|
||||
</group>
|
||||
<group>
|
||||
<field name="refund_remake" invisible="not refund_amount"/>
|
||||
</group>
|
||||
<group/>
|
||||
<group/>
|
||||
</group>
|
||||
<group col="4">
|
||||
<group>
|
||||
<field name="balance" invisible="is_full_refund"/>
|
||||
</group>
|
||||
<group>
|
||||
<field name="balance_remake" invisible="not balance"/>
|
||||
</group>
|
||||
<group/>
|
||||
<group/>
|
||||
</group>
|
||||
<group col="4">
|
||||
<group>
|
||||
<field name="total_receivables" invisible="is_full_refund"/>
|
||||
</group>
|
||||
<group>
|
||||
<field name="total_remake" invisible="not total_receivables"/>
|
||||
</group>
|
||||
<group/>
|
||||
<group/>
|
||||
</group>
|
||||
<group>
|
||||
<field name="early_explain" invisible="renewal_type != 'early_checkout'"/>
|
||||
<field name="document_ids" widget="preview_many2many"/>
|
||||
</group>
|
||||
<notebook>
|
||||
<page string="应收明细" invisible="renewal_type != 'early_checkout'">
|
||||
<field name="receivables_ids" string=" ">
|
||||
<tree editable="bottom">
|
||||
<field name="renewal_id" column_invisible="1"/>
|
||||
<field name="receivable_id" column_invisible="1"/>
|
||||
<field name="management_type_id"/>
|
||||
<field name="due_date"/>
|
||||
<field name="original_amount"/>
|
||||
<field name="reduction_amount"/>
|
||||
<field name="refund_amount"/>
|
||||
<field name="is_reconciliation"/>
|
||||
<field name="void"/>
|
||||
</tree>
|
||||
<field name="receivables_ids" string=" ">
|
||||
<tree editable="bottom">
|
||||
<field name="renewal_id" column_invisible="1"/>
|
||||
<field name="receivable_id" column_invisible="1"/>
|
||||
<field name="management_type_id"/>
|
||||
<field name="due_date"/>
|
||||
<field name="original_amount"/>
|
||||
<field name="reduction_amount"/>
|
||||
<field name="refund_amount"/>
|
||||
<field name="is_reconciliation"/>
|
||||
<field name="void"/>
|
||||
</tree>
|
||||
</field>
|
||||
</page>
|
||||
</page>
|
||||
</notebook>
|
||||
</sheet>
|
||||
</form>
|
||||
|
||||
@@ -9,580 +9,38 @@ _logger = logging.getLogger(__name__)
|
||||
|
||||
class PropertyDepositWizard(models.Model):
|
||||
_name = 'property.deposit.wizard'
|
||||
_description = '押金对账弹窗'
|
||||
_description = '押金核销'
|
||||
|
||||
receivable_total = fields.Float(string='应收金额', compute="_compute_receivable_total", store=True)
|
||||
bank_branch = fields.Char('银行名称')
|
||||
warning_msg = fields.Char(string='警告')
|
||||
bank_id = fields.Many2one('property.bank.statements', string='银行流水')
|
||||
lessee_ids = fields.Many2many('property.tenant.information', string='承租方')
|
||||
name_account = fields.Char( string='对方户名')
|
||||
account = fields.Char(string='账号')
|
||||
contract_ids = fields.Many2many('property.lease.contract', string='合同')
|
||||
amount_been_reconciled = fields.Float(string='已对金额', store=True)
|
||||
amount_water_been = fields.Float(string='已对流水金额', store=True)
|
||||
amount_water = fields.Float(string='未对流水金额', store=True)
|
||||
amount_reconciled = fields.Float(string='未核销', compute='_compute_receivable_total')
|
||||
actual_total = fields.Float(string='实收金额')
|
||||
actual_date = fields.Date(string='实收日期')
|
||||
initial_total = fields.Float(string='初始金额', default=0.0)
|
||||
rent = fields.Float(string='未收总租金', compute="_compute_rent_total")
|
||||
penalty = fields.Float(string='未收总违约金', compute="_compute_penalty_total")
|
||||
remake = fields.Text(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='物业信息')
|
||||
actual_date = fields.Date(string='核销日期')
|
||||
|
||||
deposit = fields.Float(string='押金')
|
||||
reconciliation_line_ids = fields.One2many('deposit.reconciliation.line', 'reconciliation_id', string='对账明细')
|
||||
|
||||
# @api.onchange('bank_id')
|
||||
# def _onchange_bank_id(self):
|
||||
# for rec in self:
|
||||
# rec.lessee_ids = rec.bank_id.lessee_ids.ids
|
||||
# rec.name_account = rec.bank_id.name_account
|
||||
# rec.remake = rec.bank_id.remake
|
||||
# rec.amount_water_been = rec.bank_id.yes_amount
|
||||
# rec.amount_water = rec.bank_id.no_amount
|
||||
#
|
||||
# @api.depends('reconciliation_line_ids')
|
||||
# def _compute_receivable_total(self):
|
||||
# for rec in self:
|
||||
# rec.receivable_total = sum(line.rent for line in rec.reconciliation_line_ids)
|
||||
# rec.amount_reconciled = max(0 , rec.bank_id.no_amount - sum(line.amount for line in self.reconciliation_line_ids))
|
||||
#
|
||||
# @api.depends('reconciliation_line_ids.collection_type', 'reconciliation_line_ids.rent')
|
||||
# def _compute_rent_total(self):
|
||||
# """计算所有类型为租金的明细行的未收总额"""
|
||||
# for wizard in self:
|
||||
# # 筛选出收款类型为租金的明细行,并累加其未收金额
|
||||
# rent_total = sum(
|
||||
# line.rent or 0.0
|
||||
# for line in wizard.reconciliation_line_ids
|
||||
# if line.collection_type == 'rent'
|
||||
# )
|
||||
# wizard.rent = rent_total
|
||||
#
|
||||
# @api.depends('reconciliation_line_ids.collection_type', 'reconciliation_line_ids.rent')
|
||||
# def _compute_penalty_total(self):
|
||||
# """计算所有类型为违约金的明细行的未收总额"""
|
||||
# for wizard in self:
|
||||
# penalty_total = sum(
|
||||
# line.rent or 0.0
|
||||
# for line in wizard.reconciliation_line_ids
|
||||
# if line.collection_type == 'penalty'
|
||||
# )
|
||||
# wizard.penalty = penalty_total
|
||||
#
|
||||
# @api.onchange('receivables_type_ids')
|
||||
# def onchange_receivables_type_ids(self):
|
||||
# for rec in self:
|
||||
# selected_type_names = rec.receivables_type_ids.mapped('name')
|
||||
# if not selected_type_names:
|
||||
# rec.reconciliation_line_ids = [(5, 0, 0)]
|
||||
# continue
|
||||
# # 收款类型与名称的映射(包含违约金,但后续会排除)
|
||||
# type_name_map = {
|
||||
# 'deposit': '押金',
|
||||
# 'rent': '租金',
|
||||
# 'water_fee': '水费',
|
||||
# 'lightbox': '灯箱',
|
||||
# 'guanzijian': '管子间',
|
||||
# 'electricity_fee': '电费',
|
||||
# 'penalty': '违约金',
|
||||
# 'management_fee': '管理费',
|
||||
# 'repair_fee': '维修费',
|
||||
# 'fee': '人工费/日光灯款/代垫用料费',
|
||||
# }
|
||||
# allowed_by_selection = [
|
||||
# coll_type for coll_type, name in type_name_map.items()
|
||||
# if name in selected_type_names
|
||||
# ]
|
||||
# to_delete = []
|
||||
# for line in rec.reconciliation_line_ids:
|
||||
# if line.collection_type not in allowed_by_selection:
|
||||
# to_delete.append((2, line.id, 0))
|
||||
#
|
||||
# if to_delete:
|
||||
# rec.reconciliation_line_ids = to_delete
|
||||
|
||||
# @api.onchange('actual_total')
|
||||
# def compute_reconciliation_line_ids(self):
|
||||
# type_name_map = {
|
||||
# 'deposit': '押金',
|
||||
# 'rent': '租金',
|
||||
# 'water_fee': '水费',
|
||||
# 'lightbox': '灯箱',
|
||||
# 'guanzijian': '管子间',
|
||||
# 'electricity_fee': '电费',
|
||||
# 'penalty': '违约金',
|
||||
# 'management_fee': '管理费',
|
||||
# 'repair_fee': '维修费',
|
||||
# 'fee': '人工费/日光灯款/代垫用料费',
|
||||
# }
|
||||
# new_lines = []
|
||||
# # 违约金生成
|
||||
# for contract_id in self.contract_ids:
|
||||
# contract_penalties = []
|
||||
# if not contract_id.lease_ids:
|
||||
# continue
|
||||
# receivable_penalties = self.env['property.accounts.receivable'].search([
|
||||
# ('contract_id', '=', contract_id.id.origin),
|
||||
# ('is_reconciliation', '=', False),
|
||||
# ('is_invalid', '=', False),
|
||||
# ('management_type_id.name', '=', '违约金')
|
||||
# ])
|
||||
# for penalty in receivable_penalties:
|
||||
# contract_penalties.append({
|
||||
# 'contract_id': penalty.contract_id.id,
|
||||
# 'rent_month': 0,
|
||||
# 'due_date': penalty.due_date,
|
||||
# 'rent': penalty.submitted,
|
||||
# 'amount': 0,
|
||||
# 'collection_type': 'penalty',
|
||||
# 'remake': penalty.remark,
|
||||
# })
|
||||
# contract_receivables_ids = self.env['property.accounts.receivable'].search([
|
||||
# ('contract_id', '=', contract_id.id.origin),
|
||||
# ('is_reconciliation', '=', False),
|
||||
# ('is_invalid', '=', False),
|
||||
# ('management_type_id.name', 'not in', ['违约金', '押金']),
|
||||
# ])
|
||||
# for contract_receivables in contract_receivables_ids:
|
||||
# if contract_receivables:
|
||||
# # 计算应收日期的下月1号
|
||||
# if not contract_receivables.due_date:
|
||||
# raise UserError(f'合同{contract_id.name}类型为{contract_receivables.management_type_id.name}的应收日期为空,请先填写应收日期')
|
||||
# next_month_first = (fields.Date.from_string(contract_receivables.due_date) +
|
||||
# relativedelta(months=1)).replace(day=1)
|
||||
# # 检查是否产生违约
|
||||
# if fields.Date.from_string(self.actual_date) >= next_month_first:
|
||||
# # 计算违约天数和违约金
|
||||
# late_days = (fields.Date.from_string(self.actual_date) - next_month_first).days + 1
|
||||
# # 找到符合月份的租金
|
||||
# penalty_amount = late_days * round(
|
||||
# contract_receivables.submitted * float(contract_id.percentage_liquidated_damages.name), 2
|
||||
# )
|
||||
# start_date_str = fields.Date.to_string(next_month_first)
|
||||
# end_date_str = self.actual_date
|
||||
# # 处理新产生的违约金
|
||||
# if penalty_amount > 0:
|
||||
# contract_penalties.append({
|
||||
# 'contract_id': contract_id.id,
|
||||
# 'rent_month': 0,
|
||||
# 'due_date': self.actual_date,
|
||||
# 'rent': penalty_amount,
|
||||
# 'amount': 0,
|
||||
# 'collection_type': 'penalty',
|
||||
# 'remake': f'违约金({start_date_str}至{end_date_str},共{late_days}天)',
|
||||
# })
|
||||
#
|
||||
# # 查找应收是否有未交全的租金
|
||||
# unpaid_rent_recs = self.env['property.accounts.receivable'].search([
|
||||
# ('management_type_id.name', 'not in', ['违约金', '押金']),
|
||||
# ('contract_id', '=', contract_id.id.origin),
|
||||
# ('is_invalid', '=', False),
|
||||
# ('submitted', '!=', 0),
|
||||
# ('payout_date', '!=', None),
|
||||
# ])
|
||||
# if unpaid_rent_recs:
|
||||
# for rent in unpaid_rent_recs:
|
||||
# if rent.payout_date <= rent.due_date: # 跳过预收的租金
|
||||
# continue
|
||||
# first_day = (rent.payout_date + timedelta(days=1))
|
||||
# last_month_rent = rent.submitted
|
||||
# penalty_days = self.actual_date - first_day
|
||||
# penalty_amount = (penalty_days.days + 1) * round(
|
||||
# last_month_rent * float(contract_id.percentage_liquidated_damages.name), 2
|
||||
# ) if contract_id else 0.0
|
||||
# if penalty_amount > 0:
|
||||
# new_lines.append((0, 0, {
|
||||
# 'contract_id': contract_id.id if contract_id else None,
|
||||
# 'rent_month': 0,
|
||||
# 'due_date': fields.Date.to_string(first_day),
|
||||
# 'rent': penalty_amount,
|
||||
# 'amount': 0,
|
||||
# 'collection_type': 'penalty',
|
||||
# 'remake': f'违约金({fields.Date.to_string(first_day)}至{fields.Date.to_string(self.actual_date)},共{penalty_days.days + 1}天)',
|
||||
# }))
|
||||
#
|
||||
# # 3. 添加到总列表
|
||||
# for vals in contract_penalties:
|
||||
# new_lines.append((0, 0, vals))
|
||||
#
|
||||
# if new_lines:
|
||||
# keep_lines = [
|
||||
# (4, line.id) for line in self.reconciliation_line_ids
|
||||
# if line.collection_type != 'penalty'
|
||||
# ]
|
||||
# self.reconciliation_line_ids = keep_lines + new_lines
|
||||
#
|
||||
# all_penalties = all(line.collection_type == 'penalty' for line in self.reconciliation_line_ids)
|
||||
# if all_penalties and self.reconciliation_line_ids:
|
||||
# total = sum(line.rent for line in self.reconciliation_line_ids)
|
||||
# self.receivable_total = total
|
||||
#
|
||||
# # all_due_dates = []
|
||||
# # for line in self.reconciliation_line_ids:
|
||||
# # if line.collection_type == 'rent' and line.due_date:
|
||||
# # all_due_dates.append(fields.Date.from_string(line.due_date))
|
||||
# # # 2. 找到最早的到期日期
|
||||
# # if all_due_dates:
|
||||
# # earliest_due_date = min(all_due_dates)
|
||||
# # # 获取实际日期(假设actual_date是日期对象,如果是字符串需要先转换)
|
||||
# # actual_date = fields.Date.from_string(self.actual_date) if isinstance(self.actual_date,
|
||||
# # str) else self.actual_date
|
||||
# #
|
||||
# # # 计算起始月份(最早到期日的月份)和结束月份(实际日期的月份)
|
||||
# # start_month = earliest_due_date + relativedelta(months=1)
|
||||
# # end_month = actual_date - relativedelta(months=1)
|
||||
# #
|
||||
# # temp_rent_set = set()
|
||||
# # target_rent_months = []
|
||||
# #
|
||||
# # # 遍历从起始月到结束月的所有月份
|
||||
# # current_month = start_month
|
||||
# # while current_month <= end_month:
|
||||
# # due_month = current_month.strftime('%Y-%m')
|
||||
# # # 为每个租金行添加当前月份的记录(去重)
|
||||
# # for line in self.reconciliation_line_ids:
|
||||
# # if line.collection_type == 'rent':
|
||||
# # unique_key = (
|
||||
# # line.contract_id.id if line.contract_id else None,
|
||||
# # due_month
|
||||
# # )
|
||||
# # if unique_key not in temp_rent_set:
|
||||
# # temp_rent_set.add(unique_key)
|
||||
# # target_rent_months.append({
|
||||
# # 'contract_id': line.contract_id,
|
||||
# # 'due_month': due_month
|
||||
# # })
|
||||
# # # 移动到下个月
|
||||
# # if current_month.month == 12:
|
||||
# # current_month = current_month.replace(year=current_month.year + 1, month=1, day=1)
|
||||
# # else:
|
||||
# # current_month = current_month.replace(month=current_month.month + 1, day=1)
|
||||
# # else:
|
||||
# # 没有符合条件的明细行时,返回空列表
|
||||
# target_rent_months = []
|
||||
#
|
||||
# # if target_rent_months:
|
||||
# # existing_penalty_months = set()
|
||||
# # for line in self.reconciliation_line_ids:
|
||||
# # if line.collection_type == 'penalty' and line.due_date:
|
||||
# # penalty_month = fields.Date.from_string(line.due_date).strftime('%Y-%m')
|
||||
# # penalty_key = (
|
||||
# # line.contract_id.id if line.contract_id else None,
|
||||
# # penalty_month
|
||||
# # )
|
||||
# # existing_penalty_months.add(penalty_key)
|
||||
# #
|
||||
# # # # 3. 补全缺失的跨月违约金(按合同+年月匹配,缺失则新增)
|
||||
# # # missing_penalty_lines = []
|
||||
# # # for rent_info in target_rent_months:
|
||||
# # # contract = rent_info['contract_id']
|
||||
# # # due_month = rent_info['due_month']
|
||||
# # #
|
||||
# # # # 构建待检查的违约金key(合同+年月)
|
||||
# # # check_key = (
|
||||
# # # contract.id if contract else None,
|
||||
# # # due_month
|
||||
# # # )
|
||||
# # #
|
||||
# # # if check_key not in existing_penalty_months:
|
||||
# # # year, month = map(int, due_month.split('-'))
|
||||
# # # first_day = datetime(year, month, 1).date()
|
||||
# # # penalty_days = (self.actual_date - first_day).days + 1
|
||||
# # #
|
||||
# # # # 计算补全违约金的日期范围:当月1号 ~ 当月最后1天
|
||||
# # # # 查找上个月的租金明细行
|
||||
# # # if month == 1:
|
||||
# # # last_month_year = year - 1
|
||||
# # # last_month = 12
|
||||
# # # else:
|
||||
# # # last_month_year = year
|
||||
# # # last_month = month - 1
|
||||
# # # last_month_str = f"{last_month_year}-{last_month:02d}"
|
||||
# # #
|
||||
# # # last_month_rent_line = next((
|
||||
# # # line for line in self.reconciliation_line_ids
|
||||
# # # if line.collection_type == 'rent'
|
||||
# # # and line.contract_id == contract
|
||||
# # # and line.due_date # 有到期日期
|
||||
# # # and fields.Date.from_string(line.due_date).strftime('%Y-%m') == last_month_str
|
||||
# # # ), None)
|
||||
# # # # 提取上个月租金的rent金额
|
||||
# # # last_month_rent = last_month_rent_line.rent if last_month_rent_line else 0.0
|
||||
# # # penalty_amount = penalty_days * round(
|
||||
# # # last_month_rent * float(contract.percentage_liquidated_damages.name), 2
|
||||
# # # ) if (contract and last_month_rent > 0) else 0.0
|
||||
# # #
|
||||
# # # if penalty_amount > 0:
|
||||
# # # missing_penalty_lines.append((0, 0, {
|
||||
# # # 'contract_id': contract.id if contract else None,
|
||||
# # # 'rent_month': 0,
|
||||
# # # 'due_date': fields.Date.to_string(first_day),
|
||||
# # # 'rent': penalty_amount,
|
||||
# # # 'amount': 0,
|
||||
# # # 'collection_type': 'penalty',
|
||||
# # # 'remake': f'违约金({fields.Date.to_string(first_day)}至{fields.Date.to_string(self.actual_date)},共{penalty_days}天',
|
||||
# # # }))
|
||||
# # #
|
||||
# # # # 添加缺失的违约金记录
|
||||
# # # if missing_penalty_lines:
|
||||
# # # self.write({'reconciliation_line_ids': missing_penalty_lines})
|
||||
#
|
||||
# self.create_reconciliation_vals()
|
||||
# line_types = []
|
||||
# for line in self.reconciliation_line_ids:
|
||||
# if line.collection_type not in line_types:
|
||||
# line_types.append(line.collection_type)
|
||||
# type_names = [type_name_map.get(t) for t in line_types if type_name_map.get(t)]
|
||||
# receivable_types = self.env['yuthon.management.type'].search([
|
||||
# ('name', 'in', type_names)
|
||||
# ])
|
||||
|
||||
def create_reconciliation_vals(self):
|
||||
"""
|
||||
按已生成的明细行 分配金额(优先处理押金)
|
||||
:return:
|
||||
"""
|
||||
remaining_amount = self.bank_id.no_amount
|
||||
penalty_lines = [line for line in self.reconciliation_line_ids if line.collection_type == "penalty"] # 违约金行
|
||||
rent_lines = [line for line in self.reconciliation_line_ids if line.contract_id.contract_code == "(租)(管)TX2023-072"] # 租金行
|
||||
|
||||
type_priority = {
|
||||
'deposit': 1, # 押金优先
|
||||
'rent': 2, # 其次租金
|
||||
'other': 3, # 其他类型
|
||||
'penalty': 4
|
||||
}
|
||||
all_lines = sorted(
|
||||
self.reconciliation_line_ids,
|
||||
key=lambda line: (
|
||||
line.due_date.strftime('%Y-%m') if line.due_date else '',
|
||||
type_priority.get(line.collection_type, 3)
|
||||
)
|
||||
)
|
||||
for line in all_lines:
|
||||
if remaining_amount <= 0:
|
||||
break
|
||||
if line.collection_type == "penalty":
|
||||
continue
|
||||
# 分配当前行金额
|
||||
line.amount = 0
|
||||
need_amount = round(line.rent or 0, 2)
|
||||
assign_amount = min(need_amount, remaining_amount)
|
||||
line.amount = assign_amount
|
||||
remaining_amount -= assign_amount
|
||||
if assign_amount > 0 and round(line.amount or 0, 2)>0:
|
||||
line.onchange_remake()
|
||||
|
||||
if remaining_amount > 0:
|
||||
penalty_lines = [line for line in all_lines if line.collection_type == "penalty"]
|
||||
for line in penalty_lines:
|
||||
if remaining_amount <= 0:
|
||||
break
|
||||
line.amount = 0
|
||||
need_amount = line.rent or 0
|
||||
assign_amount = min(need_amount, remaining_amount)
|
||||
line.amount = assign_amount
|
||||
remaining_amount -= assign_amount
|
||||
if assign_amount > 0 and round(line.amount or 0, 2) > 0:
|
||||
line.onchange_remake()
|
||||
|
||||
for line in penalty_lines:
|
||||
line.color = 'blue'
|
||||
|
||||
for line in rent_lines:
|
||||
line.color = 'success'
|
||||
|
||||
|
||||
def confirm(self):
|
||||
collection_type_mapping = {
|
||||
'deposit': '押金',
|
||||
'rent': '租金',
|
||||
'lightbox': '灯箱',
|
||||
'guanzijian': '管子间',
|
||||
'water_fee': '水费',
|
||||
'electricity_fee': '电费',
|
||||
'penalty': '违约金',
|
||||
'management_fee': '管理费',
|
||||
'repair_fee': '维修费',
|
||||
'other': '其他'
|
||||
}
|
||||
for rec in self:
|
||||
bank_lines = self.env['property.bank.line'].search([
|
||||
('bank', '=', rec.bank_id.name),
|
||||
('tenant_id.name', '!=', False)
|
||||
])
|
||||
if not bank_lines:
|
||||
information = self.env['property.tenant.information'].search(
|
||||
[('name', '=', rec.bank_id.name_account)],
|
||||
limit=1)
|
||||
if information:
|
||||
bank_lines = self.env['property.bank.line'].create({
|
||||
'tenant_id': information.id,
|
||||
'bank': rec.bank_id.name,
|
||||
'user': information.name,
|
||||
'name': rec.bank_id.bank_branch,
|
||||
})
|
||||
remaining_amount = 0
|
||||
for line in rec.reconciliation_line_ids:
|
||||
remaining_amount += line.amount
|
||||
for record in self:
|
||||
reconciliation_lines = record.reconciliation_line_ids
|
||||
total_amount = sum(line.amount for line in reconciliation_lines)
|
||||
total_write_amount = sum(line.write_amount for line in reconciliation_lines)
|
||||
|
||||
if round(rec.amount_water, 2) > round(remaining_amount, 2):
|
||||
rec.bank_id.registered = rec.amount_water - remaining_amount
|
||||
rec.bank_id.bank_state = 'registered'
|
||||
else:
|
||||
rec.bank_id.registered = 0
|
||||
rec.bank_id.bank_state = 'reconciled'
|
||||
rec.bank_id.reconciliation_time = fields.Datetime.now() - timedelta(hours=8)
|
||||
yes_amount = 0
|
||||
for line in rec.reconciliation_line_ids:
|
||||
# 跳过金额为0的行
|
||||
if (round(line.amount or 0, 2) == 0 and line.collection_type != 'penalty') or \
|
||||
(line.contract_id and line.contract_id.is_contract):
|
||||
continue
|
||||
first_day = line.due_date.replace(day=1)
|
||||
last_day = (first_day + relativedelta(months=1)) - relativedelta(days=1)
|
||||
if line.due_date >= self.actual_date and line.collection_type == 'deposit':
|
||||
domain = [
|
||||
('management_type_id.name', '=', collection_type_mapping.get(line.collection_type)),
|
||||
('is_reconciliation', '=', False),
|
||||
('is_suspend', '=', False),
|
||||
]
|
||||
else:
|
||||
domain = [
|
||||
('management_type_id.name', '=', collection_type_mapping.get(line.collection_type)),
|
||||
('is_reconciliation', '=', False),
|
||||
('is_suspend', '=', False),
|
||||
('due_date', '>=', first_day),
|
||||
('due_date', '<=', last_day)
|
||||
]
|
||||
if line.contract_id:
|
||||
domain.append(('contract_id', '=', line.contract_id.id))
|
||||
receivable_ids = self.env['property.accounts.receivable'].search(domain)
|
||||
for receivable in receivable_ids:
|
||||
if round(line.rent or 0, 2) == round(line.amount or 0, 2):
|
||||
is_reconciliation = True
|
||||
else:
|
||||
is_reconciliation = False
|
||||
if receivable and receivable.remark:
|
||||
final_remark = f"{receivable.remark}\n{line.remake}"
|
||||
else:
|
||||
final_remark = line.remake
|
||||
if line.collection_type != 'penalty':
|
||||
receivable.delivered1 = receivable.delivered1 + line.amount
|
||||
receivable.write({
|
||||
'is_reconciliation': is_reconciliation,
|
||||
'payout_date': rec.actual_date,
|
||||
'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}'
|
||||
})
|
||||
receivable.contract_id.update_contact_state()
|
||||
self.env['receivable.modify.line'].create({
|
||||
'bank_id': rec.bank_id.id,
|
||||
'not_collected': line.rent,
|
||||
'reconciliation_date': rec.actual_date if line.amount != 0 else None,
|
||||
'receivable_id': receivable.id,
|
||||
'is_write': True if line.amount != 0 else False,
|
||||
'is_penalty': False,
|
||||
'amount': line.amount,
|
||||
})
|
||||
|
||||
management_type_id = self.env['yuthon.management.type'].search([('name', '=', '违约金')])
|
||||
if line.collection_type == 'penalty':
|
||||
penalty_date = line.due_date
|
||||
first_day_of_last_month = penalty_date.replace(day=1) - relativedelta(months=2)
|
||||
# 上个月最后一天:当前月第一天减1天
|
||||
last_day_of_last_month = penalty_date.replace(day=1) - relativedelta(days=1)
|
||||
is_create = self.env['deposit.reconciliation.line'].search([
|
||||
('reconciliation_id', '=', self.id),
|
||||
('contract_id', '=', line.contract_id.id ),
|
||||
('due_date', '>=', first_day_of_last_month),
|
||||
('due_date', '<=', last_day_of_last_month),
|
||||
('collection_type', '!=', 'penalty'),
|
||||
('amount', '>', 0)
|
||||
])
|
||||
# 用备注的的开始日期和结束日期
|
||||
date_pattern = r'(\d{4}-\d{2}-\d{2})[至-](\d{4}-\d{2}-\d{2})'
|
||||
date_match = re.search(date_pattern, line.remake or '')
|
||||
extract_start_date = date_match.group(1) if date_match else line.due_date
|
||||
extract_end_date = date_match.group(2) if date_match else None
|
||||
check_domain = [
|
||||
('due_date', '=', line.due_date),
|
||||
('contract_id', '=', line.contract_id.id),
|
||||
('submitted', '=', line.rent),
|
||||
('is_invalid', '=', False),
|
||||
('management_type_id', '=', management_type_id.id),
|
||||
]
|
||||
# 检查是否已有相同记录
|
||||
existing_record = self.env['property.accounts.receivable'].search(check_domain)
|
||||
is_reconciliation = round(line.amount,2) == round(line.rent, 2)
|
||||
receivable_id = self.env['property.accounts.receivable']
|
||||
if not existing_record and is_create:
|
||||
domain2 = [
|
||||
('due_date', '=', line.due_date),
|
||||
('contract_id', '=', line.contract_id.id),
|
||||
('collection_type', '=', 'rent'),
|
||||
]
|
||||
extract_start_date = datetime.strptime(extract_start_date, "%Y-%m-%d").date()
|
||||
extract_end_date = datetime.strptime(extract_end_date, "%Y-%m-%d").date()
|
||||
reconciliation_id = self.env['deposit.reconciliation.line'].search(domain2, limit=1)
|
||||
receivable_id = self.env['property.accounts.receivable'].create({
|
||||
'is_reconciliation': is_reconciliation,
|
||||
'due_date': extract_end_date,
|
||||
'due_date_end': None,
|
||||
'penalty': reconciliation_id.rent,
|
||||
'management_type_id': management_type_id.id,
|
||||
'contract_id': line.contract_id.id,
|
||||
'delivered1': line.amount,
|
||||
'payout_date': rec.actual_date if (line.rent == line.amount and line.rent != 0) else None,
|
||||
'original_amount': line.rent,
|
||||
'remark': line.remake,
|
||||
'reconciliation_time': fields.Datetime.now(),
|
||||
'charging_range': f"{extract_start_date} 到 {extract_end_date}共{(extract_end_date - extract_start_date).days + 1}"
|
||||
})
|
||||
else:
|
||||
if line.amount:
|
||||
existing_record.write({
|
||||
'delivered1': existing_record.delivered1 + line.amount,
|
||||
'due_date': extract_end_date,
|
||||
'due_date_end': None,
|
||||
'is_reconciliation': is_reconciliation,
|
||||
'payout_date': rec.actual_date if (line.rent == line.amount and line.rent != 0) else None,
|
||||
'remark': line.remake,
|
||||
'bank_id': rec.bank_id.id if line.amount != 0 else None,
|
||||
'reconciliation_time': fields.Datetime.now(),
|
||||
})
|
||||
|
||||
if existing_record:
|
||||
receivable_id = existing_record
|
||||
|
||||
if receivable_id:
|
||||
self.env['receivable.modify.line'].create({
|
||||
'bank_id': rec.bank_id.id,
|
||||
'not_collected': line.rent,
|
||||
'is_write': True if line.amount != 0 else False,
|
||||
'is_penalty': True,
|
||||
'reconciliation_date': rec.actual_date if line.amount != 0 else None,
|
||||
'receivable_id': receivable_id.id,
|
||||
'amount': line.amount,
|
||||
})
|
||||
|
||||
rec.amount_been_reconciled += line.amount
|
||||
yes_amount += line.amount
|
||||
|
||||
rec.bank_id.yes_amount = rec.bank_id.yes_amount + yes_amount
|
||||
rec.bank_id.change_amount = sum(line.amount for line in rec.reconciliation_line_ids)
|
||||
|
||||
all_contracts = self.contract_ids
|
||||
remaining_contract_ids = []
|
||||
for contract in all_contracts:
|
||||
unreconciled_receivables = self.env["property.accounts.receivable"].search([
|
||||
('contract_id', '=', contract.id),
|
||||
('is_reconciliation', '=', False),
|
||||
('is_invalid', '=', False),
|
||||
], limit=1)
|
||||
if unreconciled_receivables:
|
||||
remaining_contract_ids.append(contract.id)
|
||||
amount_equal = abs(total_amount - total_write_amount) < 1e-6
|
||||
for line in reconciliation_lines:
|
||||
if line.write_amount:
|
||||
if line.receivable_id:
|
||||
if line.write_amount == line.amount:
|
||||
line.receivable_id.is_reconciliation = True
|
||||
else:
|
||||
line.receivable_id.yes_amount += line.write_amount
|
||||
if line.bills_id:
|
||||
line.bills_id.actual_date = record.actual_date
|
||||
line.bills_id.amount_actual = line.write_amount
|
||||
if amount_equal:
|
||||
if record.contract_id:
|
||||
record.contract_id.contact_state = 'settle'
|
||||
record.has_date = record.actual_date
|
||||
record.bills_list_id.contract_id.compute_is_has()
|
||||
|
||||
|
||||
class DepositReconciliationLine(models.Model):
|
||||
@@ -591,58 +49,20 @@ class DepositReconciliationLine(models.Model):
|
||||
_order = 'due_date desc'
|
||||
|
||||
reconciliation_id = fields.Many2one('property.deposit.wizard', string='关联押金对账单弹窗')
|
||||
sequence = fields.Integer(string='顺序')
|
||||
property_name = fields.Text(string='物业', compute="_compute_property_name")
|
||||
property_ids = fields.Many2many('yuthon.property', string='物业', compute="_compute_property_ids", store=True)
|
||||
contract_id = fields.Many2one('property.lease.contract', string='合同编号')
|
||||
rent_month = fields.Float(string='当期金额')
|
||||
receivable_id = fields.Many2one('property.accounts.receivable', string='关联应收账单')
|
||||
bill_id = fields.Many2one('property.bills.list', string='关联应付账单')
|
||||
|
||||
due_date = fields.Date(string='应收日期')
|
||||
rent = fields.Float(string='未收')
|
||||
management_type_id = fields.Many2one('yuthon.management.type', string='类型')
|
||||
payment_type = fields.Selection([('pay', '支付'), ('spending', '支出')], string='收付款类型')
|
||||
amount = fields.Float(string='金额', store=True)
|
||||
collection_type = fields.Selection([('deposit', '押金'), ('rent', '租金'), ('water_fee', '水费'), ('lightbox', '灯箱'), ('guanzijian', '管子间'),
|
||||
('electricity_fee', '电费'), ('penalty', '违约金'), ('management_fee', '管理费'), ('repair_fee', '维修费'), ('fee', '人工费/日光灯款/代垫用料费'), ('rename_fee', '更名费'), ('service', '有偿服务收入')], string='收款类型', store=True)
|
||||
write_amount = fields.Float(string='核销金额')
|
||||
remake = fields.Text(string='备注')
|
||||
color = fields.Selection([('success', '绿'), ('blue', '蓝')], string='颜色')
|
||||
|
||||
@api.depends('contract_id')
|
||||
def _compute_contract_name(self):
|
||||
for record in self:
|
||||
if record.contract_id and record.contract_id.version:
|
||||
record.contract_name = record.contract_id.contract_code + record.contract_id.version
|
||||
|
||||
@api.depends('contract_id')
|
||||
def _compute_property_name(self):
|
||||
for record in self:
|
||||
record.property_name = record.contract_id.property_name
|
||||
|
||||
@api.depends('contract_id', 'contract_id.lease_ids', 'contract_id.lease_ids.address_id')
|
||||
def _compute_property_ids(self):
|
||||
for record in self:
|
||||
property_ids = self.env['yuthon.property']
|
||||
if record.contract_id and record.contract_id.lease_ids:
|
||||
property_ids = record.contract_id.lease_ids.mapped('address_id')
|
||||
record.property_ids = property_ids
|
||||
|
||||
@api.onchange('amount', 'due_date', 'rent', 'collection_type', 'reconciliation_id.actual_date')
|
||||
@api.onchange('write_amount')
|
||||
def onchange_remake(self):
|
||||
for line in self:
|
||||
actual_date = fields.Date.to_date(line.reconciliation_id.bank_id.start_time + relativedelta(hours=8))
|
||||
if round(line.amount or 0, 2) == 0 and line.collection_type != 'penalty':
|
||||
line.remake = ""
|
||||
return
|
||||
if line.amount and line.collection_type != 'penalty':
|
||||
due_date = line.due_date
|
||||
actual_year, actual_month = actual_date.year, actual_date.month
|
||||
due_year, due_month = due_date.year, due_date.month
|
||||
due_date_str = due_date.strftime('%Y-%m')
|
||||
actual_date_str = actual_date.strftime('%Y-%m-%d')
|
||||
rent = round(line.rent or 0, 2)
|
||||
if (due_month > actual_month and due_year == actual_year) or (due_year > actual_year):
|
||||
if rent >= line.amount:
|
||||
line.remake = f'{actual_date_str}预{due_date_str},欠{round(rent - line.amount, 2)}'
|
||||
elif due_month == actual_month and due_year == actual_year:
|
||||
if rent >= line.amount:
|
||||
line.remake = f'交{due_date_str},欠{round(rent - line.amount, 2)}'
|
||||
elif (due_month < actual_month and due_year == actual_year) or (due_year < actual_year):
|
||||
if rent >= line.amount:
|
||||
line.remake = f'{actual_date_str}补{due_date_str},欠{round(rent - line.amount, 2)}'
|
||||
if line.write_amount and line.payment_type == 'pay' and line.management_type_id.name != '违约金':
|
||||
line.remake = '押金转'+ line.management_type_id.name
|
||||
elif line.write_amount and line.payment_type == 'spending':
|
||||
line.remake = '退' + line.management_type_id.name
|
||||
@@ -4,53 +4,38 @@
|
||||
<field name="name">property.deposit.wizard.form</field>
|
||||
<field name="model">property.deposit.wizard</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="对账弹窗">
|
||||
<form string="押金核销">
|
||||
<sheet>
|
||||
<!-- <div class="oe_title">-->
|
||||
<!-- <label for="actual_date"/>-->
|
||||
<!-- <h1>-->
|
||||
<!-- <field name="actual_date" style="font-weight: bold; color: #000000;" readonly="1" force_save="1"/>-->
|
||||
<!-- </h1>-->
|
||||
<!-- </div>-->
|
||||
<div class="oe_title">
|
||||
<label for="actual_date"/>
|
||||
<h1>
|
||||
<field name="actual_date" style="font-weight: bold; color: #000000;" force_save="1"/>
|
||||
</h1>
|
||||
</div>
|
||||
<group col="3">
|
||||
<group>
|
||||
<field name="lessee_ids" widget="many2many_tags" readonly="1"/>
|
||||
<field name="property_name" readonly="1"/>
|
||||
</group>
|
||||
<group>
|
||||
<field name="name_account" readonly="1"/>
|
||||
<field name="lessee_id" readonly="1"/>
|
||||
</group>
|
||||
<group>
|
||||
<field name="remake" readonly="1"/>
|
||||
<field name="contract_id" readonly="1"/>
|
||||
</group>
|
||||
</group>
|
||||
<group>
|
||||
<field name="bank_id" invisible="1"/>
|
||||
<field name="bank_branch" invisible="1"/>
|
||||
<field name="account" invisible="1"/>
|
||||
</group>
|
||||
<group>
|
||||
<field name="receivable_total" invisible="1"/>
|
||||
<field name="amount_been_reconciled" invisible="1"/>
|
||||
<field name="initial_total" invisible="1"/>
|
||||
<field name="rent" invisible="1"/>
|
||||
<field name="penalty" invisible="1"/>
|
||||
<field name="deposit"/>
|
||||
</group>
|
||||
<field name="reconciliation_line_ids">
|
||||
<tree editable="bottom" create="false" delete="false">
|
||||
<field name="sequence" column_invisible="1" />
|
||||
<field name="color" column_invisible="1" force_save="1"/>
|
||||
<tree editable="bottom">
|
||||
<field name="reconciliation_id" column_invisible="1"/>
|
||||
<field name="property_ids" column_invisible="1"/>
|
||||
<field name="contract_id" force_save="1"/>
|
||||
<field name="property_name"/>
|
||||
<field name="due_date" readonly="1" force_save="1"/>
|
||||
<field name="collection_type" readonly="1" force_save="1"
|
||||
decoration-success="color == 'success'"
|
||||
decoration-info="color == 'blue'"
|
||||
/>
|
||||
<field name="rent_month" sum = "Total" readonly="1" force_save="1"/>
|
||||
<field name="rent" sum = "Total" readonly="1" force_save="1"/>
|
||||
<field name="amount" sum = "Total" force_save="1" options='{"fg_color": "red: amount != false;" }'/>
|
||||
<field name="receivable_id" column_invisible="1"/>
|
||||
<field name="bill_id" column_invisible="1"/>
|
||||
<field name="management_type_id"/>
|
||||
<field name="due_date"/>
|
||||
<field name="payment_type"/>
|
||||
<field name="amount"/>
|
||||
<field name="write_amount"/>
|
||||
<field name="remake"/>
|
||||
</tree>
|
||||
</field>
|
||||
|
||||
Reference in New Issue
Block a user