Merge remote-tracking branch 'origin/dev' into dev
This commit is contained in:
@@ -14,6 +14,7 @@
|
||||
'report/hr_leave_batch_report_action.xml',
|
||||
'views/inherit_hr_type_views.xml',
|
||||
'views/inherit_hr_leave_allocation_views.xml',
|
||||
'views/extended_vacation_approval_views.xml',
|
||||
'views/inherit_hr_leave_accrual_plan_views.xml',
|
||||
'views/hr_leave_accrual_views.xml',
|
||||
'views/yuthon_fixes_approval_views.xml',
|
||||
|
||||
@@ -14,6 +14,13 @@
|
||||
<field name="padding">4</field>
|
||||
<field name="company_id" eval="False"/>
|
||||
</record>
|
||||
<record id="yuthon_extended_sequence" model="ir.sequence">
|
||||
<field name="name">修正编号</field>
|
||||
<field name="code">yuthon_extended_code</field>
|
||||
<field name="prefix">JQYC</field>
|
||||
<field name="padding">4</field>
|
||||
<field name="company_id" eval="False"/>
|
||||
</record>
|
||||
<record id="yuthon_breastfeed_leave_sequence" model="ir.sequence">
|
||||
<field name="name">哺乳编号</field>
|
||||
<field name="code">yuthon_breastfeed_leave_code</field>
|
||||
|
||||
@@ -4,4 +4,5 @@ from . import inherit_hr_leave
|
||||
from . import inherit_hr_leave_accrual_plan
|
||||
from . import yuthon_fixes_approval
|
||||
from . import yuthon_holiday_setting
|
||||
from . import yuthon_breastfeed_leave
|
||||
from . import yuthon_breastfeed_leave
|
||||
from . import extended_vacation_approval
|
||||
@@ -0,0 +1,90 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from email.policy import default
|
||||
|
||||
from odoo import models, fields, api
|
||||
|
||||
|
||||
class ExtendedVacationApproval(models.Model):
|
||||
_name = 'extended.vacation.approval'
|
||||
_description = '假期延长申请'
|
||||
_inherit = ['soong.workflow.mixin', 'mail.thread.main.attachment', 'mail.activity.mixin']
|
||||
|
||||
name = fields.Char(string="标题")
|
||||
code = fields.Char(string="编号", default=lambda self: self.env['ir.sequence'].next_by_code('yuthon_extended_code'))
|
||||
users_id = fields.Many2one('res.users', string="申请人", default=lambda self: self.env.user.id)
|
||||
department_id = fields.Many2one(related='users_id.employee_id.department_id', string="部门")
|
||||
employee_ids = fields.Many2many('hr.employee', string="假期顺延人员")
|
||||
type_vacations_ids = fields.Many2many('hr.leave.type', string="假期类型")
|
||||
is_issues = fields.Boolean(string='是否上会')
|
||||
issues_result = fields.Html(string="会议结果")
|
||||
related_issues_id = fields.Many2one('issue.library', string="关联议题")
|
||||
reason_application = fields.Text(string="申请事由")
|
||||
documents_ids = fields.Many2many('ir.attachment', string="附件")
|
||||
date_postponed = fields.Date(string="延期至")
|
||||
active = fields.Boolean('Active', default=True, tracking=True)
|
||||
remarks = fields.Text(string="备注")
|
||||
work_end = fields.Boolean(string="结束")
|
||||
urgency_level = fields.Selection([('normal', '普件'), ('urgent', '急件'), ('emergency', '特急件')], string='紧急度',
|
||||
default='normal')
|
||||
line_ids = fields.One2many('extended.vacation.line', 'vacation_id', string="延期假期")
|
||||
|
||||
def _get_default_name_title(self):
|
||||
return self._description if self._description else self._name
|
||||
name_title = fields.Char(default=_get_default_name_title)
|
||||
self_users_ids = fields.Many2many('res.users', string="当前经办人", default=lambda self: [(6, 0, [self.env.user.id])])
|
||||
|
||||
@api.onchange('employee_ids')
|
||||
def _onchange_employee_ids(self):
|
||||
if not self.employee_ids:
|
||||
self.line_ids = [(5, 0, 0)]
|
||||
return
|
||||
current_date = fields.Date.today()
|
||||
target_date = fields.Date.to_date(f"{current_date.year}-{current_date.month}-01")
|
||||
self.line_ids = [(5, 0, 0)]
|
||||
line_values = []
|
||||
for employee in self.employee_ids:
|
||||
report_record = self.env['yuthon.vacation.reports'].search([
|
||||
('employee_id', '=', employee.id.origin),
|
||||
('vacation_date', '=', target_date)
|
||||
], limit=1)
|
||||
line_data = {
|
||||
'employee_id': employee.id,
|
||||
'dynamic_previous_year': report_record.dynamic_previous_year if report_record else 0.0,
|
||||
'dynamic_previous_year1': report_record.dynamic_previous_year1 if report_record else 0.0,
|
||||
}
|
||||
line_values.append((0, 0, line_data))
|
||||
self.line_ids = line_values
|
||||
|
||||
def end_approval(self):
|
||||
current_date = fields.Date.today()
|
||||
start_date = fields.Date.to_date(f"{current_date.year}-01-01")
|
||||
end_date = fields.Date.to_date(f"{current_date.year}-{current_date.month}-01")
|
||||
if self.employee_ids:
|
||||
has_annual_leave = self.type_vacations_ids.filtered(lambda r: r.name == '年假')
|
||||
has_overtime_leave = self.type_vacations_ids.filtered(lambda r: r.name == '补休')
|
||||
for employee in self.employee_ids:
|
||||
report_records = self.env['yuthon.vacation.reports'].search([
|
||||
('employee_id', '=', employee.id),
|
||||
('vacation_date', '>=', start_date),
|
||||
('vacation_date', '<=', end_date)
|
||||
])
|
||||
if report_records:
|
||||
write_vals = {}
|
||||
if has_annual_leave:
|
||||
write_vals['valid_date'] = self.date_postponed
|
||||
if has_overtime_leave:
|
||||
write_vals['valid_date1'] = self.date_postponed
|
||||
|
||||
if write_vals:
|
||||
report_records.write(write_vals)
|
||||
for record in report_records:
|
||||
record.update_line()
|
||||
|
||||
class ExtendedVacationLine(models.Model):
|
||||
_name = 'extended.vacation.line'
|
||||
_description = "假期延长明细"
|
||||
|
||||
vacation_id = fields.Many2one('extended.vacation.approval', string="假期延长")
|
||||
employee_id = fields.Many2one('hr.employee', string="姓名")
|
||||
dynamic_previous_year = fields.Float(string="上年年假剩余d", digits=(16, 3))
|
||||
dynamic_previous_year1 = fields.Float(string="上年补休剩余d", digits=(16, 3))
|
||||
@@ -6,4 +6,6 @@ access_yuthon_fixes_wizard,yuthon_fixes_wizard,model_yuthon_fixes_wizard,base.gr
|
||||
access_yuthon_holiday_setting,yuthon_holiday_setting,model_yuthon_holiday_setting,base.group_user,1,1,1,1
|
||||
access_leave_allocation_wizard,leave_allocation_wizard,model_leave_allocation_wizard,base.group_user,1,1,1,1
|
||||
access_yuthon_leave_wizard,yuthon_leave_wizard,model_yuthon_leave_wizard,base.group_user,1,1,1,1
|
||||
access_yuthon_breastfeed_leave,yuthon_breastfeed_leave,model_yuthon_breastfeed_leave,base.group_user,1,1,1,1
|
||||
access_yuthon_breastfeed_leave,yuthon_breastfeed_leave,model_yuthon_breastfeed_leave,base.group_user,1,1,1,1
|
||||
access_extended_vacation_approval,extended_vacation_approval,model_extended_vacation_approval,base.group_user,1,1,1,1
|
||||
access_extended_vacation_line,extended_vacation_line,model_extended_vacation_line,base.group_user,1,1,1,1
|
||||
|
@@ -0,0 +1,77 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<odoo>
|
||||
<record id="view_extended_vacation_approval_tree" model="ir.ui.view">
|
||||
<field name="name">extended.vacation.approval.tree</field>
|
||||
<field name="model">extended.vacation.approval</field>
|
||||
<field name="arch" type="xml">
|
||||
<tree string="假期延长申请">
|
||||
<field name="users_id"/>
|
||||
<field name="department_id"/>
|
||||
</tree>
|
||||
</field>
|
||||
</record>
|
||||
<record id="view_extended_vacation_approval_form" model="ir.ui.view">
|
||||
<field name="name">extended.vacation.approval.form</field>
|
||||
<field name="model">extended.vacation.approval</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string='假期延长审批' create="1">
|
||||
<sheet>
|
||||
<widget name="web_ribbon" title="普件" bg_color="text-bg-success"
|
||||
invisible="urgency_level != 'normal'"/>
|
||||
<widget name="web_ribbon" title="急件" bg_color="text-bg-warning"
|
||||
invisible="urgency_level != 'urgent'"/>
|
||||
<widget name="web_ribbon" title="特急" bg_color="text-bg-danger"
|
||||
invisible="urgency_level != 'emergency'"/>
|
||||
<group col="4">
|
||||
<group>
|
||||
<field name="code" string="流水号" readonly="1"/>
|
||||
</group>
|
||||
<group>
|
||||
<field name="urgency_level" readonly="1"/>
|
||||
</group>
|
||||
<group>
|
||||
<field name="is_issues"/>
|
||||
</group>
|
||||
<group>
|
||||
<field name="related_issues_id" invisible="is_issues == False"/>
|
||||
</group>
|
||||
</group>
|
||||
<div class="col-12 text-center">
|
||||
<h1>
|
||||
<field name="name_title" readonly="1"/>
|
||||
</h1>
|
||||
</div>
|
||||
<group string="审批事项">
|
||||
<group>
|
||||
<field name="users_id"/>
|
||||
<field name="type_vacations_ids" widget="many2many_tags"/>
|
||||
<field name="department_id" invisible="1"/>
|
||||
<field name="date_postponed"/>
|
||||
<field name="employee_ids" widget="many2many_tags"/>
|
||||
</group>
|
||||
</group>
|
||||
<group string="延长明细">
|
||||
<field name="line_ids" string=" ">
|
||||
<tree editable="bottom">
|
||||
<field name="vacation_id" column_invisible="1"/>
|
||||
<field name="employee_id"/>
|
||||
<field name="dynamic_previous_year"/>
|
||||
<field name="dynamic_previous_year1"/>
|
||||
</tree>
|
||||
</field>
|
||||
</group>
|
||||
<group>
|
||||
<field name="reason_application"/>
|
||||
<field name="work_end" invisible="1"/>
|
||||
<field name="documents_ids" widget="preview_many2many"/>
|
||||
</group>
|
||||
</sheet>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
</odoo>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -377,17 +377,33 @@ class YuthonVacationReports(models.Model):
|
||||
rec.year_workday += workday_overtime_add
|
||||
rec.year_holiday += holidays_overtime_add
|
||||
|
||||
if rec.working_overtime > 0:
|
||||
current_month_first = rec.vacation_date.replace(day=1)
|
||||
last_month_last = current_month_first - timedelta(days=1)
|
||||
last_month_first = last_month_last.replace(day=1)
|
||||
last_month_record = self.env['yuthon.vacation.reports'].search([
|
||||
('employee_id', '=', rec.employee_id.id),
|
||||
('vacation_date', '=', last_month_first),
|
||||
], limit=1)
|
||||
if last_month_record:
|
||||
total_overtime = last_month_record.dynamic_previous_year1 + last_month_record.this_year1
|
||||
else:
|
||||
total_overtime = 0.0
|
||||
|
||||
if total_overtime > 0:
|
||||
working_overtime_lines = rec.overtime_ids.filtered(
|
||||
lambda o: not o.workflow_record_id and o.text == '上月额度继承'
|
||||
)
|
||||
working_overtime_lines.workday = rec.working_overtime * 8
|
||||
working_overtime_lines.workday = total_overtime * 8
|
||||
if last_month_record:
|
||||
total_leave = last_month_record.dynamic_previous_year + last_month_record.dynamic_remainder_year
|
||||
else:
|
||||
total_leave = 0.0
|
||||
|
||||
if rec.leave > 0:
|
||||
if total_leave > 0:
|
||||
leave_lines = rec.leave_ids.filtered(
|
||||
lambda o: not o.workflow_record_id and o.text == '上月额度继承'
|
||||
)
|
||||
leave_lines.update_lines = rec.leave * 8
|
||||
leave_lines.update_lines = total_leave * 8
|
||||
|
||||
rec._compute_leave()
|
||||
rec._compute_working_overtime()
|
||||
@@ -1365,12 +1381,21 @@ class YuthonVacationReports(models.Model):
|
||||
}
|
||||
rec.write(inherit_vals)
|
||||
|
||||
current_date = fields.Date.today()
|
||||
if last_month_record:
|
||||
if last_month_record.valid_date and last_month_record.valid_date < current_date:
|
||||
dynamic_previous_year_val = 0.0
|
||||
else:
|
||||
dynamic_previous_year_val = last_month_record.dynamic_previous_year
|
||||
if last_month_record.valid_date1 and last_month_record.valid_date1 < current_date:
|
||||
dynamic_previous_year1_val = 0.0
|
||||
else:
|
||||
dynamic_previous_year1_val = last_month_record.dynamic_previous_year1
|
||||
inherit_vals = {
|
||||
'leave': last_month_record.leave,
|
||||
'dynamic_previous_year': last_month_record.dynamic_previous_year,
|
||||
'dynamic_previous_year': dynamic_previous_year_val,
|
||||
'dynamic_remainder_year': last_month_record.dynamic_remainder_year,
|
||||
'dynamic_previous_year1': last_month_record.dynamic_previous_year1,
|
||||
'dynamic_previous_year1': dynamic_previous_year1_val,
|
||||
'this_year1': last_month_record.this_year1,
|
||||
'working_overtime': last_month_record.working_overtime,
|
||||
'medical_fee': last_month_record.medical_fee,
|
||||
|
||||
@@ -195,11 +195,14 @@ class ReceivableModifyLine(models.Model):
|
||||
|
||||
bank_id = fields.Many2one('property.bank.statements', string='关联银行对账单')
|
||||
original_amount = fields.Float(related='bank_id.original_amount', string='交易金额', store=False)
|
||||
no_amount = fields.Float(related='bank_id.no_amount', string='未对', store=False)
|
||||
bank_state = fields.Selection(related='bank_id.bank_state', string='状态', store=False)
|
||||
receivable_id = fields.Many2one('property.accounts.receivable', string='应收账单')
|
||||
management_type_id = fields.Many2one('yuthon.management.type', related='receivable_id.management_type_id', string='应收类型', store=False)
|
||||
due_date = fields.Date(related='receivable_id.due_date', string='应收开始', store=False)
|
||||
due_date_end = fields.Date(related='receivable_id.due_date_end', string='应收结束', store=False)
|
||||
property_name = fields.Text(string='物业', compute='_compute_property_name', store=False, search='_search_property_name')
|
||||
delivered1 = fields.Float(related='receivable_id.delivered1', string='已收金额', store=False)
|
||||
is_write = fields.Boolean()
|
||||
|
||||
@api.depends('receivable_id')
|
||||
@@ -225,6 +228,32 @@ class ReceivableModifyLine(models.Model):
|
||||
not_collected = fields.Float(string='未收')
|
||||
amount = fields.Float(string='已对金额')
|
||||
|
||||
def open_receivable(self):
|
||||
"""打开应收账单"""
|
||||
self.ensure_one()
|
||||
if self.receivable_id:
|
||||
return {
|
||||
'type': 'ir.actions.act_window',
|
||||
'name': '应收账单',
|
||||
'res_model': 'property.accounts.receivable',
|
||||
'res_id': self.receivable_id.id,
|
||||
'view_mode': 'form',
|
||||
'target': 'current',
|
||||
}
|
||||
|
||||
def open_bank_statement(self):
|
||||
"""打开银行流水"""
|
||||
self.ensure_one()
|
||||
if self.bank_id:
|
||||
return {
|
||||
'type': 'ir.actions.act_window',
|
||||
'name': '银行流水',
|
||||
'res_model': 'property.bank.statements',
|
||||
'res_id': self.bank_id.id,
|
||||
'view_mode': 'form',
|
||||
'target': 'current',
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -116,16 +116,21 @@
|
||||
<field name="arch" type="xml">
|
||||
<tree string="应收流水中间表" editable="top">
|
||||
<field name="bank_id"/>
|
||||
<field name="no_amount"/>
|
||||
<field name="bank_state"/>
|
||||
<field name="reconciliation_date"/>
|
||||
<field name="not_collected"/>
|
||||
<field name="amount"/>
|
||||
<field name="original_amount"/>
|
||||
<field name="delivered1"/>
|
||||
<field name="receivable_id"/>
|
||||
<field name="property_name"/>
|
||||
<field name="due_date"/>
|
||||
<field name="due_date_end"/>
|
||||
<field name="management_type_id"/>
|
||||
<field name="is_penalty"/>
|
||||
<button name="open_receivable" string="应收账单" type="object" class="btn btn-blue"/>
|
||||
<button name="open_bank_statement" string="银行流水" type="object" class="btn btn-blue"/>
|
||||
</tree>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
@@ -66,7 +66,7 @@
|
||||
<field name="epitope_values_id" domain="[('type', '=', 'ammeter')]" options="{'no_open': True}" column_invisible="1"/>
|
||||
<field name="meter_date"/>
|
||||
<field name="last_read" readonly="1" />
|
||||
<field name="current_read" />
|
||||
<field name="current_read" decoration-warning="1"/>
|
||||
<field name="last_dosage" />
|
||||
<field name="current_meter" readonly="1" />
|
||||
<field name="unit" />
|
||||
@@ -110,7 +110,7 @@
|
||||
<field name="gauge_magnification" string="倍率"/>
|
||||
<field name="current_meter" string="用量"/>
|
||||
<field name="initial_value"/>
|
||||
<field name="current_read" string="本次读数"/>
|
||||
<field name="current_read" string="本次读数" decoration-warning="1"/>
|
||||
<field name="last_read" string="上次读数"/>
|
||||
<field name="lessee_id" string="承租方"/>
|
||||
<field name="yuthon_property_ids" string="地址" widget="many2many_tags"/>
|
||||
|
||||
@@ -66,7 +66,7 @@
|
||||
domain="[('type', '=', 'watermeter')]" options="{'no_create': True, 'no_open': True}"/>
|
||||
<field name="meter_date"/>
|
||||
<field name="last_read" readonly="1" />
|
||||
<field name="current_read" />
|
||||
<field name="current_read" decoration-warning="1"/>
|
||||
<field name="last_dosage" />
|
||||
<field name="current_meter" readonly="1" />
|
||||
<field name="unit" />
|
||||
@@ -112,7 +112,7 @@
|
||||
<field name="line_loss" string="线损"/>
|
||||
<field name="gauge_magnification" string="倍率"/>
|
||||
<field name="current_meter" string="用量"/>
|
||||
<field name="current_read" string="本次读数"/>
|
||||
<field name="current_read" string="本次读数" decoration-warning="1"/>
|
||||
<field name="last_read" string="上次读数"/>
|
||||
<field name="lessee_id" string="承租方"/>
|
||||
<field name="yuthon_property_ids" string="地址" widget="many2many_tags"/>
|
||||
|
||||
@@ -11,7 +11,7 @@ class PropertyStatementsWizard(models.Model):
|
||||
_name = 'property.statements.wizard'
|
||||
_description = '银行流水向导弹窗'
|
||||
|
||||
selection_bank = fields.Selection([('js', '建设银行'), ('gs', '工商银行'),('sh', '农商')], string="选择银行")
|
||||
selection_bank = fields.Selection([('js', '建设银行'), ('gs', '工商银行'),('sh', '农商'), ('ms', '民生'), ('zc', '中城'), ('dj', '东进')], string="选择银行")
|
||||
excel_file = fields.Binary(string="上传Excel表")
|
||||
excel_name = fields.Char(string="文件名")
|
||||
|
||||
@@ -31,6 +31,12 @@ class PropertyStatementsWizard(models.Model):
|
||||
self.property_bank_statements_gc_data(row)
|
||||
elif self.selection_bank == 'sh':
|
||||
self.property_bank_statements_sh_data(row)
|
||||
elif self.selection_bank == 'ms':
|
||||
self.property_bank_statements_ms_data(row)
|
||||
elif self.selection_bank == 'zc':
|
||||
self.property_bank_statements_zc_data(row)
|
||||
elif self.selection_bank == 'dj':
|
||||
self.property_bank_statements_dj_data(row)
|
||||
|
||||
def property_bank_statements_gc_data(self, row):
|
||||
if row[0].value:
|
||||
@@ -171,6 +177,31 @@ class PropertyStatementsWizard(models.Model):
|
||||
elif original_amount:
|
||||
self.env['property.bank.statements'].create(bank_data)
|
||||
|
||||
def property_bank_statements_ms_data(self, row):
|
||||
if row[2].value:
|
||||
start_time = datetime.strptime(row[2].value, '%Y-%m-%d %H:%M:%S')
|
||||
else:
|
||||
start_time = None
|
||||
name = row[1].value
|
||||
number = row[0].value
|
||||
if row[3].value == "贷":
|
||||
lending_direction = "loan"
|
||||
elif row[3].value == "借":
|
||||
lending_direction = "borrow"
|
||||
name_account = row[4].value
|
||||
bank_number = row[5].value
|
||||
purpose = row[6].value
|
||||
extract = row[7].value
|
||||
remake = row[8].value
|
||||
company_id = self.env['res.company'].search([('name', '=', '天河物管')], limit=1)
|
||||
pass
|
||||
|
||||
def property_bank_statements_zc_data(self, row):
|
||||
pass
|
||||
|
||||
def property_bank_statements_dj_data(self, row):
|
||||
pass
|
||||
|
||||
|
||||
def classify_by_last_four(self, input_str):
|
||||
if not isinstance(input_str, str) or len(input_str) < 4:
|
||||
|
||||
@@ -201,6 +201,7 @@ class PropertyBankStatements(models.Model):
|
||||
@api.depends('name')
|
||||
def _compute_property_employee_id(self):
|
||||
for record in self:
|
||||
# 1. 原有逻辑:根据银行名称匹配承租方
|
||||
if record.name:
|
||||
bank_account = self.env['property.bank.line'].search([
|
||||
('bank', '=', record.name)
|
||||
@@ -209,20 +210,38 @@ class PropertyBankStatements(models.Model):
|
||||
record.lessee_ids = [(6, 0, bank_list)] if bank_list else [(6, 0, [])]
|
||||
else:
|
||||
record.lessee_ids = [(6, 0, [])]
|
||||
|
||||
# 2. 重构核心逻辑:按日期筛选出租方变更行,匹配所属单元
|
||||
if record.lessee_ids:
|
||||
contract_set = self.env['property.lease.contract']
|
||||
# 获取当前记录的日期(用于判断出租方变更行的生效期)
|
||||
target_date = record.start_time.date() if record.start_time else fields.Date.today()
|
||||
|
||||
for lessee in record.lessee_ids:
|
||||
# 从承租方的 property_contract_ids(租户行)提取合同
|
||||
# 从承租方的租户行提取合同
|
||||
tenant_lines = lessee.property_contract_ids.filtered(
|
||||
lambda line:
|
||||
line.lease_contract_id and
|
||||
line.lease_contract_id.lessor_id and
|
||||
line.lease_contract_id.lessor_id.referred == record.your_own_unit
|
||||
lambda line: line.lease_contract_id is not False
|
||||
)
|
||||
contract_ids = tenant_lines.mapped('lease_contract_id.id')
|
||||
contracts = self.env['property.lease.contract'].browse(contract_ids)
|
||||
contracts = contracts.filtered(lambda c: c.contact_state != 'settle')
|
||||
contract_set |= contracts
|
||||
|
||||
for tenant_line in tenant_lines:
|
||||
contract = tenant_line.lease_contract_id
|
||||
if not contract:
|
||||
continue
|
||||
# 1. 筛选合同的出租方变更行:生效日期≤目标日期,失效日期≥目标日期/未设置
|
||||
valid_lessor_lines = contract.lessor_line.filtered(
|
||||
lambda l:
|
||||
l.start_date <= target_date and
|
||||
(not l.end_date or l.end_date >= target_date)
|
||||
)
|
||||
# 2. 确定最终的出租方referred值
|
||||
if valid_lessor_lines:
|
||||
actual_lessor_referred = valid_lessor_lines[0].lessor_id.referred
|
||||
else:
|
||||
actual_lessor_referred = contract.lessor_id.referred if contract.lessor_id else False
|
||||
if actual_lessor_referred == record.your_own_unit:
|
||||
if contract.contact_state != 'settle':
|
||||
contract_set |= contract
|
||||
|
||||
record.contract_ids = contract_set
|
||||
record.admin_id = record.contract_ids[0].admin_id if record.contract_ids else False
|
||||
else:
|
||||
|
||||
@@ -16,6 +16,8 @@
|
||||
'views/penalty_month_received_report.xml',
|
||||
'views/penalty_year_cum_report.xml',
|
||||
'views/deposit_reports.xml',
|
||||
'views/cum_income_report.xml',
|
||||
'views/cum_arrears_report.xml',
|
||||
'views/menu.xml',
|
||||
'views/ledger_report_views.xml',
|
||||
'views/receivable_report_views.xml',
|
||||
@@ -32,6 +34,7 @@
|
||||
'views/yuthon_report_res_partner.xml',
|
||||
'views/att_report_view.xml',
|
||||
'views/staff_position_report.xml',
|
||||
'views/hydropower_report_views.xml',
|
||||
],
|
||||
'installable': True,
|
||||
'application': True,
|
||||
|
||||
@@ -18,6 +18,8 @@ from . import pre_arrears_report
|
||||
from . import pre_advance_report
|
||||
from . import month_receivable_report
|
||||
from . import total_received_report
|
||||
from . import cum_income_report
|
||||
from . import cum_arrears_report
|
||||
from . import penalty_arrears_report
|
||||
from . import penalty_month_received_report
|
||||
from . import penalty_year_cum_report
|
||||
@@ -25,4 +27,5 @@ from . import deposit_month_receivable_report
|
||||
from . import deposit_pre_received_report
|
||||
from . import deposit_month_received_report
|
||||
from . import deposit_cum_arrears_report
|
||||
from . import deposit_month_refund_report
|
||||
from . import deposit_month_refund_report
|
||||
from . import hydropower_report
|
||||
@@ -0,0 +1,112 @@
|
||||
import datetime
|
||||
import calendar
|
||||
|
||||
from odoo import api, models
|
||||
|
||||
|
||||
class CumArrearsReport(models.Model):
|
||||
_inherit = 'receivable.modify.line'
|
||||
|
||||
@api.model
|
||||
def get_cum_arrears_report(self, params):
|
||||
"""
|
||||
累计欠收报表(数据源:receivable.modify.line):
|
||||
- 状态为挂账(bank_state = 'registered')
|
||||
- 应收开始日期(receivable_id.due_date)小于等于查询月月末
|
||||
- 排除押金和违约金类型
|
||||
- 金额取 not_collected(未收)
|
||||
"""
|
||||
today = datetime.date.today()
|
||||
|
||||
date_start = params.get("date_start")
|
||||
if date_start:
|
||||
query_date = datetime.datetime.fromisoformat(date_start).date()
|
||||
else:
|
||||
query_date = today
|
||||
|
||||
# 查询月月末
|
||||
last_day = calendar.monthrange(query_date.year, query_date.month)[1]
|
||||
month_end = query_date.replace(day=last_day)
|
||||
|
||||
domain = [
|
||||
('bank_state', '=', 'registered'),
|
||||
('receivable_id.due_date', '<=', month_end),
|
||||
('receivable_id.is_invalid', '=', False),
|
||||
]
|
||||
|
||||
keyword = params.get("keyword")
|
||||
if keyword:
|
||||
domain += [
|
||||
'|', '|',
|
||||
('receivable_id.contract_id.contract_code', 'ilike', keyword),
|
||||
('receivable_id.property_name', 'ilike', keyword),
|
||||
('receivable_id.lessee_id.name', 'ilike', keyword),
|
||||
]
|
||||
|
||||
condition = params.get('condition')
|
||||
partner_id = params.get('partner_id')
|
||||
company_id = params.get('company_id')
|
||||
management_type_id = params.get('management_type_id')
|
||||
|
||||
if condition:
|
||||
domain.append(('receivable_id.tenure_type', '=', condition))
|
||||
if partner_id:
|
||||
domain.append(('receivable_id.precinct_id', '=', partner_id))
|
||||
if company_id:
|
||||
domain.append(('receivable_id.company_id', '=', company_id))
|
||||
if management_type_id:
|
||||
domain.append(('receivable_id.management_type_id', '=', management_type_id))
|
||||
else:
|
||||
domain.append(('receivable_id.management_type_id.name', 'not in', ['押金', '违约金']))
|
||||
|
||||
lines = self.search(domain, order="receivable_id asc")
|
||||
|
||||
rows = []
|
||||
total_amount = 0.0
|
||||
for idx, line in enumerate(lines, start=1):
|
||||
rec = line.receivable_id
|
||||
contract = rec.contract_id if rec else None
|
||||
amount = round(line.not_collected or 0.0, 2)
|
||||
total_amount += amount
|
||||
|
||||
# 物业穿透
|
||||
property_val = ''
|
||||
if contract and contract.lease_ids and contract.lease_ids[0].address_id:
|
||||
prop = contract.lease_ids[0].address_id
|
||||
property_val = {
|
||||
'model': 'yuthon.property',
|
||||
'id': prop.id,
|
||||
'display_name': rec.property_name or prop.name,
|
||||
}
|
||||
elif rec:
|
||||
property_val = rec.property_name or ''
|
||||
|
||||
rows.append({
|
||||
"序号": idx,
|
||||
"合同编号": {
|
||||
'model': 'property.lease.contract',
|
||||
'id': contract.id,
|
||||
'display_name': contract.contract_code,
|
||||
} if contract else "",
|
||||
"物业名称": property_val,
|
||||
"承租方名称": {
|
||||
'model': 'property.tenant.information',
|
||||
'id': rec.lessee_id.id,
|
||||
'display_name': rec.lessee_id.name,
|
||||
} if rec and rec.lessee_id else "",
|
||||
"收款类型": rec.management_type_id.name if rec and rec.management_type_id else "",
|
||||
"未收金额": amount,
|
||||
"所属公司": contract.lessor_id.name if contract and contract.lessor_id else "",
|
||||
"管理员": {
|
||||
'model': 'res.users',
|
||||
'id': rec.admin_id.id,
|
||||
'display_name': rec.admin_id.name,
|
||||
} if rec and rec.admin_id else "",
|
||||
})
|
||||
|
||||
stats = [
|
||||
{'name': '记录总数', 'amount': len(rows)},
|
||||
{'name': '累计欠收', 'amount': round(total_amount, 2)},
|
||||
]
|
||||
|
||||
return {"rows": rows, "stats": stats}
|
||||
@@ -0,0 +1,105 @@
|
||||
import datetime
|
||||
|
||||
from odoo import api, models
|
||||
|
||||
|
||||
class CumIncomeReport(models.Model):
|
||||
_inherit = 'receivable.modify.line'
|
||||
|
||||
@api.model
|
||||
def get_cum_income_report(self, params):
|
||||
"""
|
||||
累计收入报表(数据源:receivable.modify.line):
|
||||
- 按年查询
|
||||
- 取交易金额(original_amount)
|
||||
- 排除押金和违约金类型
|
||||
"""
|
||||
today = datetime.date.today()
|
||||
current_year = today.year
|
||||
|
||||
date_start = params.get("date_start")
|
||||
# 按年查询:如果有传值则使用该年份,否则使用当前年份
|
||||
if date_start:
|
||||
year = datetime.datetime.fromisoformat(date_start).year
|
||||
else:
|
||||
year = current_year
|
||||
|
||||
# 构建年份的开始和结束日期
|
||||
year_start = datetime.date(year, 1, 1)
|
||||
year_end = datetime.date(year, 12, 31)
|
||||
|
||||
domain = [
|
||||
('receivable_id.due_date', '>=', year_start),
|
||||
('receivable_id.due_date', '<=', year_end),
|
||||
('receivable_id.is_invalid', '=', False),
|
||||
]
|
||||
|
||||
keyword = params.get("keyword")
|
||||
if keyword:
|
||||
domain += [
|
||||
'|', '|',
|
||||
('receivable_id.contract_id.contract_code', 'ilike', keyword),
|
||||
('receivable_id.property_name', 'ilike', keyword),
|
||||
('receivable_id.lessee_id.name', 'ilike', keyword),
|
||||
]
|
||||
|
||||
condition = params.get('condition')
|
||||
partner_id = params.get('partner_id')
|
||||
company_id = params.get('company_id')
|
||||
management_type_id = params.get('management_type_id')
|
||||
|
||||
if condition:
|
||||
domain.append(('receivable_id.tenure_type', '=', condition))
|
||||
if partner_id:
|
||||
domain.append(('receivable_id.precinct_id', '=', partner_id))
|
||||
if company_id:
|
||||
domain.append(('receivable_id.company_id', '=', company_id))
|
||||
if management_type_id:
|
||||
domain.append(('receivable_id.management_type_id', '=', management_type_id))
|
||||
else:
|
||||
domain.append(('receivable_id.management_type_id.name', 'not in', ['押金', '违约金']))
|
||||
|
||||
lines = self.search(domain, order="receivable_id asc")
|
||||
|
||||
rows = []
|
||||
total_amount = 0.0
|
||||
for idx, line in enumerate(lines, start=1):
|
||||
rec = line.receivable_id
|
||||
contract = rec.contract_id if rec else None
|
||||
amount = round(line.original_amount or 0.0, 2)
|
||||
total_amount += amount
|
||||
|
||||
# 物业穿透
|
||||
property_val = ''
|
||||
if contract and contract.lease_ids and contract.lease_ids[0].address_id:
|
||||
prop = contract.lease_ids[0].address_id
|
||||
property_val = {
|
||||
'model': 'yuthon.property',
|
||||
'id': prop.id,
|
||||
'display_name': rec.property_name or prop.name,
|
||||
}
|
||||
elif rec:
|
||||
property_val = rec.property_name or ''
|
||||
|
||||
rows.append({
|
||||
"序号": idx,
|
||||
"合同编号": {
|
||||
'model': 'property.lease.contract',
|
||||
'id': contract.id,
|
||||
'display_name': contract.contract_code,
|
||||
} if contract else "",
|
||||
"承租方名称": {
|
||||
'model': 'property.tenant.information',
|
||||
'id': rec.lessee_id.id,
|
||||
'display_name': rec.lessee_id.name,
|
||||
} if rec and rec.lessee_id else "",
|
||||
"物业名称": property_val,
|
||||
"金额": amount,
|
||||
})
|
||||
|
||||
stats = [
|
||||
{'name': '记录总数', 'amount': len(rows)},
|
||||
{'name': '累计收入', 'amount': round(total_amount, 2)},
|
||||
]
|
||||
|
||||
return {"rows": rows, "stats": stats}
|
||||
@@ -4,7 +4,7 @@ from odoo import api, models
|
||||
|
||||
|
||||
class CurrentMonthReceivedReport(models.Model):
|
||||
_inherit = 'property.accounts.receivable'
|
||||
_inherit = 'receivable.modify.line'
|
||||
|
||||
@api.model
|
||||
def get_current_month_received_report(self, params):
|
||||
@@ -15,9 +15,9 @@ class CurrentMonthReceivedReport(models.Model):
|
||||
if keyword:
|
||||
domain += [
|
||||
'|', '|',
|
||||
('contract_id.contract_code', 'ilike', keyword),
|
||||
('property_name', 'ilike', keyword),
|
||||
('lessee_id.name', 'ilike', keyword),
|
||||
('receivable_id.contract_id.contract_code', 'ilike', keyword),
|
||||
('receivable_id.property_name', 'ilike', keyword),
|
||||
('receivable_id.lessee_id.name', 'ilike', keyword),
|
||||
]
|
||||
|
||||
date_start = params.get("date_start")
|
||||
@@ -28,20 +28,20 @@ class CurrentMonthReceivedReport(models.Model):
|
||||
# 优先按收款日期过滤;若收款日期为空,则按应收日期兜底
|
||||
domain += [
|
||||
'|',
|
||||
'&', ('payout_date', '>=', start_dt), ('payout_date', '<=', end_dt),
|
||||
'&', ('payout_date', '=', False), '&', ('due_date', '>=', start_dt), ('due_date', '<=', end_dt)
|
||||
'&', ('receivable_id.payout_date', '>=', start_dt), ('receivable_id.payout_date', '<=', end_dt),
|
||||
'&', ('receivable_id.payout_date', '=', False), '&', ('receivable_id.due_date', '>=', start_dt), ('receivable_id.due_date', '<=', end_dt)
|
||||
]
|
||||
elif start_dt:
|
||||
domain += [
|
||||
'|',
|
||||
('payout_date', '>=', start_dt),
|
||||
'&', ('payout_date', '=', False), ('due_date', '>=', start_dt)
|
||||
('receivable_id.payout_date', '>=', start_dt),
|
||||
'&', ('receivable_id.payout_date', '=', False), ('receivable_id.due_date', '>=', start_dt)
|
||||
]
|
||||
elif end_dt:
|
||||
domain += [
|
||||
'|',
|
||||
('payout_date', '<=', end_dt),
|
||||
'&', ('payout_date', '=', False), ('due_date', '<=', end_dt)
|
||||
('receivable_id.payout_date', '<=', end_dt),
|
||||
'&', ('receivable_id.payout_date', '=', False), ('receivable_id.due_date', '<=', end_dt)
|
||||
]
|
||||
|
||||
condition = params.get('condition')
|
||||
@@ -50,21 +50,22 @@ class CurrentMonthReceivedReport(models.Model):
|
||||
management_type_id = params.get('management_type_id')
|
||||
|
||||
if condition:
|
||||
domain.append(('tenure_type', '=', condition))
|
||||
domain.append(('receivable_id.tenure_type', '=', condition))
|
||||
if partner_id:
|
||||
domain.append(('precinct_id', '=', partner_id))
|
||||
domain.append(('receivable_id.precinct_id', '=', partner_id))
|
||||
if company_id:
|
||||
domain.append(('company_id', '=', company_id))
|
||||
domain.append(('receivable_id.company_id', '=', company_id))
|
||||
if management_type_id:
|
||||
domain.append(('management_type_id', '=', management_type_id))
|
||||
domain.append(('receivable_id.management_type_id', '=', management_type_id))
|
||||
|
||||
receivables = self.search(domain, order="payout_date asc, due_date asc")
|
||||
lines = self.search(domain, order="receivable_id asc")
|
||||
|
||||
rows = []
|
||||
total_amount = 0.0
|
||||
|
||||
for idx, rec in enumerate(receivables, start=1):
|
||||
amount = rec.delivered1 or 0.0 # 已收金额
|
||||
for idx, line in enumerate(lines, start=1):
|
||||
rec = line.receivable_id
|
||||
amount = line.amount or 0.0 # 已对金额
|
||||
total_amount += amount
|
||||
|
||||
rows.append({
|
||||
@@ -73,24 +74,24 @@ class CurrentMonthReceivedReport(models.Model):
|
||||
'model': 'property.lease.contract',
|
||||
'id': rec.contract_id.id,
|
||||
'display_name': rec.contract_id.contract_code,
|
||||
} if rec.contract_id else "",
|
||||
} if rec and rec.contract_id else "",
|
||||
"物业名称": {
|
||||
'model': 'yuthon.property',
|
||||
'id': rec.contract_id.lease_ids[0].address_id.id,
|
||||
'display_name': rec.property_name,
|
||||
} if rec.contract_id and rec.contract_id.lease_ids and rec.contract_id.lease_ids[0].address_id else rec.property_name or "",
|
||||
} if rec and rec.contract_id and rec.contract_id.lease_ids and rec.contract_id.lease_ids[0].address_id else rec.property_name or "",
|
||||
"承租方名称": {
|
||||
'model': 'property.tenant.information',
|
||||
'id': rec.lessee_id.id,
|
||||
'display_name': rec.lessee_id.name,
|
||||
} if rec.lessee_id else "",
|
||||
} if rec and rec.lessee_id else "",
|
||||
"金额": round(amount, 2),
|
||||
"所属公司": rec.company_id.referred if rec.company_id and hasattr(rec.company_id, 'referred') else rec.company_id.name if rec.company_id else "",
|
||||
"所属公司": rec.company_id.referred if rec and rec.company_id and hasattr(rec.company_id, 'referred') else rec.company_id.name if rec and rec.company_id else "",
|
||||
"管理员": {
|
||||
'model': 'res.users',
|
||||
'id': rec.admin_id.id,
|
||||
'display_name': rec.admin_id.name,
|
||||
} if rec.admin_id else "",
|
||||
} if rec and rec.admin_id else "",
|
||||
})
|
||||
|
||||
return {
|
||||
|
||||
@@ -0,0 +1,93 @@
|
||||
from odoo import models, fields, api
|
||||
from datetime import datetime, date
|
||||
|
||||
|
||||
class HydropowerReport(models.Model):
|
||||
_name = 'hydropower.report'
|
||||
_description = '水电表应收明细表'
|
||||
_auto = False
|
||||
|
||||
property_name = fields.Char(string='房屋名称')
|
||||
lessee_name = fields.Char(string='业户名称')
|
||||
water_fee = fields.Float(string='水费')
|
||||
water_period = fields.Char(string='水费期间')
|
||||
electric_fee = fields.Float(string='电费')
|
||||
electric_period = fields.Char(string='电费期间')
|
||||
total = fields.Float(string='小计')
|
||||
|
||||
@api.model
|
||||
def get_hydropower_data(self, params):
|
||||
"""获取水电表数据,接收 params 字典"""
|
||||
date_start = params.get('date_start')
|
||||
date_end = params.get('date_end')
|
||||
|
||||
start_date = datetime.fromisoformat(date_start).date() if date_start else date.today().replace(day=1)
|
||||
end_date = datetime.fromisoformat(date_end).date() if date_end else date.today()
|
||||
|
||||
# 获取水表数据
|
||||
water_data = self.env['meter.water.line'].search([
|
||||
('meter_date', '>=', start_date),
|
||||
('meter_date', '<=', end_date),
|
||||
('state', '=', 'reading')
|
||||
])
|
||||
|
||||
# 获取电表数据
|
||||
electric_data = self.env['meter.archives.line'].search([
|
||||
('meter_date', '>=', start_date),
|
||||
('meter_date', '<=', end_date),
|
||||
('state', '=', 'reading')
|
||||
])
|
||||
|
||||
# 整合数据
|
||||
property_dict = {}
|
||||
|
||||
for water in water_data:
|
||||
for property_id in water.yuthon_property_ids:
|
||||
key = property_id.name
|
||||
if key not in property_dict:
|
||||
property_dict[key] = {
|
||||
'房屋名称': property_id.name,
|
||||
'业户名称': property_id.lessee_id.name if property_id.lessee_id else '',
|
||||
'水费': 0.0,
|
||||
'水费期间': '',
|
||||
'电费': 0.0,
|
||||
'电费期间': '',
|
||||
'小计': 0.0
|
||||
}
|
||||
property_dict[key]['水费'] += water.receivables
|
||||
property_dict[key]['水费期间'] = f"{start_date}到{end_date}"
|
||||
|
||||
for electric in electric_data:
|
||||
for property_id in electric.yuthon_property_ids:
|
||||
key = property_id.name
|
||||
if key not in property_dict:
|
||||
property_dict[key] = {
|
||||
'房屋名称': property_id.name,
|
||||
'业户名称': property_id.lessee_id.name if property_id.lessee_id else '',
|
||||
'水费': 0.0,
|
||||
'水费期间': '',
|
||||
'电费': 0.0,
|
||||
'电费期间': '',
|
||||
'小计': 0.0
|
||||
}
|
||||
property_dict[key]['电费'] += electric.receivables
|
||||
property_dict[key]['电费期间'] = f"{start_date}到{end_date}"
|
||||
|
||||
rows = []
|
||||
total_water = 0.0
|
||||
total_electric = 0.0
|
||||
for idx, (key, value) in enumerate(property_dict.items(), start=1):
|
||||
value['小计'] = round(value['水费'] + value['电费'], 2)
|
||||
value['水费'] = round(value['水费'], 2)
|
||||
value['电费'] = round(value['电费'], 2)
|
||||
total_water += value['水费']
|
||||
total_electric += value['电费']
|
||||
rows.append(value)
|
||||
|
||||
stats = [
|
||||
{'name': '记录数', 'amount': len(rows)},
|
||||
{'name': '水费合计', 'amount': round(total_water, 2)},
|
||||
{'name': '电费合计', 'amount': round(total_electric, 2)},
|
||||
{'name': '合计', 'amount': round(total_water + total_electric, 2)},
|
||||
]
|
||||
return {'rows': rows, 'stats': stats}
|
||||
@@ -1,90 +1,121 @@
|
||||
import datetime
|
||||
import calendar
|
||||
|
||||
from odoo import api, models
|
||||
|
||||
|
||||
class MonthlyPrecollectionReport(models.Model):
|
||||
_inherit = 'property.accounts.receivable'
|
||||
_inherit = 'receivable.modify.line'
|
||||
|
||||
@api.model
|
||||
def get_monthly_precollection_report(self, params):
|
||||
"""汇总当前筛选条件下的应收数据(本月预收视图)。"""
|
||||
domain = []
|
||||
"""
|
||||
本月预收报表(数据源:receivable.modify.line):
|
||||
- 应收开始日期(receivable_id.due_date)在查询月当月(月初 ~ 月末)
|
||||
- delivered1 > original_amount(已交超过当期金额,即有预收)
|
||||
- 应收账单非作废:receivable_id.is_invalid = False
|
||||
- 排除押金和违约金类型
|
||||
- 金额取 delivered1 - original_amount(预收金额)
|
||||
"""
|
||||
today = datetime.date.today()
|
||||
|
||||
date_start = params.get("date_start")
|
||||
if date_start:
|
||||
query_date = datetime.datetime.fromisoformat(date_start).date()
|
||||
else:
|
||||
query_date = today
|
||||
|
||||
# 查询月月初和月末
|
||||
month_start = query_date.replace(day=1)
|
||||
last_day = calendar.monthrange(query_date.year, query_date.month)[1]
|
||||
month_end = query_date.replace(day=last_day)
|
||||
|
||||
domain = [
|
||||
('receivable_id.due_date', '>=', month_start),
|
||||
('receivable_id.due_date', '<=', month_end),
|
||||
('receivable_id.delivered1', '>', 0),
|
||||
('receivable_id.is_invalid', '=', False),
|
||||
]
|
||||
|
||||
keyword = params.get("keyword")
|
||||
if keyword:
|
||||
domain += [
|
||||
'|', '|',
|
||||
('lessee_id.name', 'ilike', keyword),
|
||||
('property_name', 'ilike', keyword),
|
||||
('title_deed', 'ilike', keyword),
|
||||
('receivable_id.contract_id.contract_code', 'ilike', keyword),
|
||||
('receivable_id.property_name', 'ilike', keyword),
|
||||
('receivable_id.lessee_id.name', 'ilike', keyword),
|
||||
]
|
||||
|
||||
date_start = params.get("date_start")
|
||||
date_end = params.get("date_end")
|
||||
if date_start:
|
||||
start_dt = datetime.datetime.fromisoformat(date_start).date()
|
||||
domain.append(("due_date", ">=", start_dt))
|
||||
if date_end:
|
||||
end_dt = datetime.datetime.fromisoformat(date_end).date()
|
||||
domain.append(("due_date", "<=", end_dt))
|
||||
|
||||
condition = params.get('condition')
|
||||
partner_id = params.get('partner_id')
|
||||
company_id = params.get('company_id')
|
||||
management_type_id = params.get('management_type_id')
|
||||
|
||||
if condition:
|
||||
domain.append(('tenure_type', '=', condition))
|
||||
domain.append(('receivable_id.tenure_type', '=', condition))
|
||||
if partner_id:
|
||||
domain.append(('precinct_id', '=', partner_id))
|
||||
domain.append(('receivable_id.precinct_id', '=', partner_id))
|
||||
if company_id:
|
||||
domain.append(('company_id', '=', company_id))
|
||||
domain.append(('receivable_id.company_id', '=', company_id))
|
||||
if management_type_id:
|
||||
domain.append(('management_type_id', '=', management_type_id))
|
||||
domain.append(('receivable_id.management_type_id', '=', management_type_id))
|
||||
else:
|
||||
domain.append(('receivable_id.management_type_id.name', 'not in', ['押金', '违约金']))
|
||||
|
||||
receivables = self.search(domain, limit=1000, order="due_date asc")
|
||||
lines = self.search(domain, order="receivable_id asc")
|
||||
|
||||
result = []
|
||||
rows = []
|
||||
total_amount = 0.0
|
||||
for index, rec in enumerate(receivables, start=1):
|
||||
amount = rec.original_amount or 0.0
|
||||
idx = 1
|
||||
for line in lines:
|
||||
rec = line.receivable_id
|
||||
contract = rec.contract_id if rec else None
|
||||
# 预收金额 = 已交 - 当期金额,必须 > 0 才是真正预收
|
||||
amount = round((rec.delivered1 or 0.0) - (rec.original_amount or 0.0), 2)
|
||||
if amount <= 0:
|
||||
continue
|
||||
total_amount += amount
|
||||
result.append({
|
||||
"序号": index,
|
||||
|
||||
# 物业穿透
|
||||
property_val = ''
|
||||
if contract and contract.lease_ids and contract.lease_ids[0].address_id:
|
||||
prop = contract.lease_ids[0].address_id
|
||||
property_val = {
|
||||
'model': 'yuthon.property',
|
||||
'id': prop.id,
|
||||
'display_name': rec.property_name or prop.name,
|
||||
}
|
||||
elif rec:
|
||||
property_val = rec.property_name or ''
|
||||
|
||||
rows.append({
|
||||
"序号": idx,
|
||||
"合同编号": {
|
||||
'model': 'property.lease.contract',
|
||||
'id': rec.contract_id.id,
|
||||
'display_name': rec.contract_id.contract_code,
|
||||
} if rec.contract_id else "",
|
||||
"物业名称": {
|
||||
'model': 'yuthon.property',
|
||||
'id': rec.contract_id.lease_ids[0].address_id.id,
|
||||
'display_name': rec.property_name,
|
||||
} if rec.contract_id and rec.contract_id.lease_ids and rec.contract_id.lease_ids[0].address_id else rec.property_name or "",
|
||||
'id': contract.id,
|
||||
'display_name': contract.contract_code,
|
||||
} if contract else "",
|
||||
"物业名称": property_val,
|
||||
"承租方名称": {
|
||||
'model': 'property.tenant.information',
|
||||
'id': rec.lessee_id.id,
|
||||
'display_name': rec.lessee_id.name,
|
||||
} if rec.lessee_id else "",
|
||||
"金额": round(amount, 2),
|
||||
"所属公司": (
|
||||
rec.contract_id.lessor_id.referred
|
||||
or rec.contract_id.lessor_id.name
|
||||
if rec.contract_id and rec.contract_id.lessor_id
|
||||
else ""
|
||||
),
|
||||
} if rec and rec.lessee_id else "",
|
||||
"收款类型": rec.management_type_id.name if rec and rec.management_type_id else "",
|
||||
"金额": amount,
|
||||
"所属公司": contract.lessor_id.name if contract and contract.lessor_id else "",
|
||||
"管理员": {
|
||||
'model': 'res.users',
|
||||
'id': rec.contract_id.admin_id.id,
|
||||
'display_name': rec.contract_id.admin_id.name,
|
||||
} if rec.contract_id and rec.contract_id.admin_id else "",
|
||||
'id': rec.admin_id.id,
|
||||
'display_name': rec.admin_id.name,
|
||||
} if rec and rec.admin_id else "",
|
||||
})
|
||||
idx += 1
|
||||
|
||||
return {
|
||||
"rows": result,
|
||||
"stats": [
|
||||
{"name": "应收总额", "amount": round(total_amount, 2)},
|
||||
],
|
||||
}
|
||||
stats = [
|
||||
{'name': '合同总数', 'amount': len(rows)},
|
||||
{'name': '预收总额', 'amount': round(total_amount, 2)},
|
||||
]
|
||||
|
||||
return {"rows": rows, "stats": stats}
|
||||
|
||||
|
||||
@@ -11,11 +11,10 @@ class PreAdvanceReport(models.Model):
|
||||
"""
|
||||
前期预收报表(数据源:receivable.modify.line):
|
||||
- 应收开始日期(receivable_id.due_date)在查询月最后一天之后(未来应收)
|
||||
- 应收账单未收金额(receivable_id.submitted)= 0(已全额收款)
|
||||
- original_amount > 0(有交易金额)
|
||||
- delivered1 > original_amount(已交超过当期金额,即有预收)
|
||||
- 应收账单非作废:receivable_id.is_invalid = False
|
||||
- 排除押金和违约金类型
|
||||
- 金额取 original_amount(交易金额)
|
||||
- 金额取 delivered1 - original_amount(预收金额)
|
||||
"""
|
||||
today = datetime.date.today()
|
||||
if today.month == 12:
|
||||
@@ -30,8 +29,7 @@ class PreAdvanceReport(models.Model):
|
||||
|
||||
domain = [
|
||||
('receivable_id.due_date', '>', cutoff_date),
|
||||
('receivable_id.submitted', '=', 0),
|
||||
('original_amount', '>', 0),
|
||||
('receivable_id.delivered1', '>', 0),
|
||||
('receivable_id.is_invalid', '=', False),
|
||||
]
|
||||
|
||||
@@ -64,10 +62,14 @@ class PreAdvanceReport(models.Model):
|
||||
|
||||
rows = []
|
||||
total_amount = 0.0
|
||||
for idx, line in enumerate(lines, start=1):
|
||||
idx = 1
|
||||
for line in lines:
|
||||
rec = line.receivable_id
|
||||
contract = rec.contract_id if rec else None
|
||||
amount = round(line.original_amount or 0.0, 2)
|
||||
# 预收金额 = 已交 - 当期金额,必须 > 0 才是真正预收
|
||||
amount = round((rec.delivered1 or 0.0) - (rec.original_amount or 0.0), 2)
|
||||
if amount <= 0:
|
||||
continue
|
||||
total_amount += amount
|
||||
|
||||
# 物业穿透
|
||||
@@ -103,6 +105,7 @@ class PreAdvanceReport(models.Model):
|
||||
'display_name': rec.admin_id.name,
|
||||
} if rec and rec.admin_id else "",
|
||||
})
|
||||
idx += 1
|
||||
|
||||
stats = [
|
||||
{'name': '合同总数', 'amount': len(rows)},
|
||||
|
||||
@@ -61,7 +61,7 @@ class PreArrearsReport(models.Model):
|
||||
for idx, line in enumerate(lines, start=1):
|
||||
rec = line.receivable_id
|
||||
contract = rec.contract_id if rec else None
|
||||
amount = round(line.original_amount or 0.0, 2)
|
||||
amount = round(rec.submitted or 0.0, 2)
|
||||
total_amount += amount
|
||||
|
||||
# 物业穿透
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
<data>
|
||||
<record id="action_cum_arrears_report" model="ir.actions.client">
|
||||
<field name="name">累计欠收</field>
|
||||
<field name="tag">receivable_report_client</field>
|
||||
<field name="context">
|
||||
{
|
||||
"sideBar": true,
|
||||
"report_config": {
|
||||
"model": "receivable.modify.line",
|
||||
"method": "get_cum_arrears_report",
|
||||
"dateMode": "single",
|
||||
"columns": [
|
||||
{"headerName": "序号", "field": "序号", "width": 45, "flex": 0, "pinned": "left"},
|
||||
{"headerName": "合同编号", "field": "合同编号", "flex": 1.2},
|
||||
{"headerName": "物业名称", "field": "物业名称", "flex": 2.5},
|
||||
{"headerName": "承租方名称", "field": "承租方名称", "flex": 1.4},
|
||||
{"headerName": "收款类型", "field": "收款类型", "flex": 1},
|
||||
{"headerName": "未收金额", "field": "未收金额", "flex": 1, "type": "number"},
|
||||
{"headerName": "所属公司", "field": "所属公司", "flex": 1},
|
||||
{"headerName": "管理员", "field": "管理员", "flex": 1}
|
||||
]
|
||||
}
|
||||
}
|
||||
</field>
|
||||
</record>
|
||||
</data>
|
||||
</odoo>
|
||||
@@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<odoo>
|
||||
<record id="action_cum_income_report" model="ir.actions.client">
|
||||
<field name="name">累计收入</field>
|
||||
<field name="tag">receivable_report_client</field>
|
||||
<field name="context">{"report_config": {"model": "receivable.modify.line", "method": "get_cum_income_report", "columns": [{"headerName": "序号", "field": "序号", "width": 80, "flex": 0}, {"headerName": "合同编号", "field": "合同编号", "flex": 1}, {"headerName": "承租方名称", "field": "承租方名称", "flex": 1}, {"headerName": "物业名称", "field": "物业名称", "flex": 1}, {"headerName": "金额", "field": "金额", "flex": 1}]}}</field>
|
||||
</record>
|
||||
</odoo>
|
||||
@@ -8,7 +8,7 @@
|
||||
{
|
||||
"sideBar": true,
|
||||
"report_config": {
|
||||
"model": "property.accounts.receivable",
|
||||
"model": "receivable.modify.line",
|
||||
"method": "get_current_month_received_report",
|
||||
"columns": [
|
||||
{"headerName": "序号", "field": "序号", "width": 45, "flex": 0, "pinned": "left"},
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
<data noupdate="0">
|
||||
<!-- 水电表应收明细表动作 -->
|
||||
<record id="action_hydropower_report" model="ir.actions.client">
|
||||
<field name="name">水电表应收明细表</field>
|
||||
<field name="tag">receivable_report_client</field>
|
||||
<field name="context">{"sideBar": true, "report_config": {"model": "hydropower.report", "method": "get_hydropower_data", "dateMode": "range", "columns": [{"headerName": "房屋名称", "field": "房屋名称", "flex": 2}, {"headerName": "业户名称", "field": "业户名称", "flex": 1.5}, {"headerName": "水费", "field": "水费", "flex": 1, "type": "number"}, {"headerName": "水费期间", "field": "水费期间", "flex": 2}, {"headerName": "电费", "field": "电费", "flex": 1, "type": "number"}, {"headerName": "电费期间", "field": "电费期间", "flex": 2}, {"headerName": "小计", "field": "小计", "flex": 1, "type": "number"}]}}</field>
|
||||
</record>
|
||||
|
||||
<!-- 水电表应收明细表菜单 -->
|
||||
<menuitem id="yuthon_property_hydropower_menu"
|
||||
sequence="5"
|
||||
name="水电表应收明细"
|
||||
parent="yuthon_property_approval.property_approval_report_menu"
|
||||
action="action_hydropower_report"/>
|
||||
</data>
|
||||
</odoo>
|
||||
@@ -48,30 +48,26 @@
|
||||
name="本月实收总额"
|
||||
parent="yuthon_property_income_menu"
|
||||
action="action_total_received_report"/>
|
||||
<menuitem id="yuthon_property_income_month_received_menu"
|
||||
sequence="6"
|
||||
name="本月实收"
|
||||
parent="yuthon_property_income_menu"/>
|
||||
<menuitem id="yuthon_property_income_month_received_belong_menu"
|
||||
sequence="1"
|
||||
sequence="6"
|
||||
name="归属本月"
|
||||
parent="yuthon_property_income_month_received_menu"
|
||||
parent="yuthon_property_income_menu"
|
||||
action="action_current_month_received_report"/>
|
||||
<menuitem id="yuthon_property_income_month_received_advance_menu"
|
||||
sequence="2"
|
||||
sequence="7"
|
||||
name="本月预收"
|
||||
parent="yuthon_property_income_month_received_menu"
|
||||
parent="yuthon_property_income_menu"
|
||||
action="action_monthly_precollection_report"/>
|
||||
<menuitem id="yuthon_property_income_cum_arrears_menu"
|
||||
sequence="7"
|
||||
sequence="8"
|
||||
name="累计欠收"
|
||||
parent="yuthon_property_income_menu"
|
||||
action="action_report_placeholder"/>
|
||||
action="action_cum_arrears_report"/>
|
||||
<menuitem id="yuthon_property_income_cum_income_menu"
|
||||
sequence="8"
|
||||
sequence="9"
|
||||
name="累计收入"
|
||||
parent="yuthon_property_income_menu"
|
||||
action="action_report_placeholder"/>
|
||||
action="action_cum_income_report"/>
|
||||
|
||||
<!-- 其他收入 -->
|
||||
<menuitem id="yuthon_property_other_income_menu"
|
||||
|
||||
@@ -8,13 +8,15 @@
|
||||
{
|
||||
"sideBar": true,
|
||||
"report_config": {
|
||||
"model": "property.accounts.receivable",
|
||||
"model": "receivable.modify.line",
|
||||
"method": "get_monthly_precollection_report",
|
||||
"dateMode": "single",
|
||||
"columns": [
|
||||
{"headerName": "序号", "field": "序号", "width": 45, "flex": 0, "pinned": "left"},
|
||||
{"headerName": "合同编号", "field": "合同编号", "flex": 1},
|
||||
{"headerName": "物业名称", "field": "物业名称", "flex": 2},
|
||||
{"headerName": "承租方名称", "field": "承租方名称", "flex": 1.2},
|
||||
{"headerName": "合同编号", "field": "合同编号", "flex": 1.2},
|
||||
{"headerName": "物业名称", "field": "物业名称", "flex": 2.5},
|
||||
{"headerName": "承租方名称", "field": "承租方名称", "flex": 1.4},
|
||||
{"headerName": "收款类型", "field": "收款类型", "flex": 1},
|
||||
{"headerName": "金额", "field": "金额", "flex": 1, "type": "number"},
|
||||
{"headerName": "所属公司", "field": "所属公司", "flex": 1},
|
||||
{"headerName": "管理员", "field": "管理员", "flex": 1}
|
||||
|
||||
@@ -9,8 +9,8 @@ class YuthonMealExpenses(models.Model):
|
||||
|
||||
employee_id = fields.Many2one('hr.employee', string='姓名')
|
||||
card = fields.Char(string='身份证')
|
||||
number_breakfasts = fields.Integer(string='早餐次数')
|
||||
number_lunches = fields.Integer(string='午餐次数')
|
||||
number_breakfasts = fields.Integer(string='早餐次数', compute='_compute_catering_counts', store=True)
|
||||
number_lunches = fields.Integer(string='午餐次数', compute='_compute_catering_counts', store=True)
|
||||
total_payment = fields.Float(string='合计缴费', compute='_compute_total_payment', store=True)
|
||||
company_id = fields.Many2one(related='employee_id.company_id', string="公司")
|
||||
select_time = fields.Selection([('1', '一月'), ('2', '二月'), ('3', '三月'), ('4', '四月'),
|
||||
@@ -24,6 +24,30 @@ class YuthonMealExpenses(models.Model):
|
||||
toll_state = fields.Selection([('to_do', '待缴'), ('done', '已缴')], string='缴费状态', default='to_do')
|
||||
|
||||
|
||||
def _get_date_range(self):
|
||||
year = int(self.select_year)
|
||||
month = int(self.select_time)
|
||||
last_day = calendar.monthrange(year, month)[1]
|
||||
date_start = '%04d-%02d-01' % (year, month)
|
||||
date_end = '%04d-%02d-%02d' % (year, month, last_day)
|
||||
return date_start, date_end
|
||||
|
||||
@api.depends('employee_id', 'select_year', 'select_time')
|
||||
def _compute_catering_counts(self):
|
||||
for record in self:
|
||||
if not record.employee_id or not record.select_year or not record.select_time:
|
||||
record.number_breakfasts = 0
|
||||
record.number_lunches = 0
|
||||
continue
|
||||
date_start, date_end = record._get_date_range()
|
||||
caterings = self.env['yuthon.catering'].search([
|
||||
('employee_id', '=', record.employee_id.id),
|
||||
('date', '>=', date_start),
|
||||
('date', '<=', date_end),
|
||||
])
|
||||
record.number_breakfasts = len(caterings.filtered(lambda c: c.breakfast))
|
||||
record.number_lunches = len(caterings.filtered(lambda c: c.lunch))
|
||||
|
||||
@api.depends('number_breakfasts', 'number_lunches')
|
||||
def _compute_total_payment(self):
|
||||
for record in self:
|
||||
@@ -54,3 +78,53 @@ class YuthonMealExpenses(models.Model):
|
||||
'skip_party_month_onchange': True
|
||||
},
|
||||
}
|
||||
|
||||
def action_generate_missing_feb(self):
|
||||
target_year = '2026'
|
||||
target_month = '2'
|
||||
# 取全部参餐员工
|
||||
all_confs = self.env['yuthon.catering.conf'].search([])
|
||||
all_employees = all_confs.mapped('employee_ids')
|
||||
# 已有记录的员工
|
||||
existing = self.search([
|
||||
('select_year', '=', target_year),
|
||||
('select_time', '=', target_month),
|
||||
])
|
||||
existing_emp_ids = existing.mapped('employee_id').ids
|
||||
# 批量创建缺失记录
|
||||
created = 0
|
||||
for emp in all_employees:
|
||||
if emp.id not in existing_emp_ids:
|
||||
self.create({
|
||||
'employee_id': emp.id,
|
||||
'card': emp.identification_id or '',
|
||||
'select_year': target_year,
|
||||
'select_time': target_month,
|
||||
})
|
||||
created += 1
|
||||
return {
|
||||
'type': 'ir.actions.client',
|
||||
'tag': 'display_notification',
|
||||
'params': {
|
||||
'title': '生成完成',
|
||||
'message': '共生成2026年2月缺失数据 %d 条' % created,
|
||||
'type': 'success',
|
||||
'sticky': False,
|
||||
}
|
||||
}
|
||||
|
||||
def action_view_detail(self):
|
||||
self.ensure_one()
|
||||
date_start, date_end = self._get_date_range()
|
||||
catering_tree_view = self.env.ref('yuthon_catering.yuthon_catering_tree_view')
|
||||
return {
|
||||
'type': 'ir.actions.act_window',
|
||||
'name': '%s年%s月 %s 餐饮明细' % (self.select_year, self.select_time, self.employee_id.name),
|
||||
'res_model': 'yuthon.catering',
|
||||
'view_mode': 'tree',
|
||||
'views': [(catering_tree_view.id, 'tree')],
|
||||
'target': 'new',
|
||||
'domain': [('employee_id', '=', self.employee_id.id),
|
||||
('date', '>=', date_start),
|
||||
('date', '<=', date_end)],
|
||||
}
|
||||
|
||||
@@ -24,6 +24,9 @@
|
||||
<field name="model">yuthon.meal.expenses</field>
|
||||
<field name="arch" type="xml">
|
||||
<tree string="餐费" editable="bottom" js_class="custom_meal_button">
|
||||
<header>
|
||||
<button name="action_generate_missing_feb" string="批量生成2026年2月缺失数据" type="object" class="btn btn-blue"/>
|
||||
</header>
|
||||
<field name="select_year"/>
|
||||
<field name="select_time"/>
|
||||
<field name="employee_id"/>
|
||||
@@ -34,6 +37,7 @@
|
||||
<field name="company_id"/>
|
||||
<field name="toll_state"/>
|
||||
<field name="meal_state"/>
|
||||
<button name="action_view_detail" string="明细" type="object" class="btn btn-blue"/>
|
||||
<button name="send_meal" string="发送" type="object" class="btn btn-blue"/>
|
||||
</tree>
|
||||
</field>
|
||||
|
||||
Reference in New Issue
Block a user