Merge branch 'master' into dev_zhou

# Conflicts:
#	attendance_iot/controllers/kaoqin_test.py
This commit is contained in:
李鹏宇
2026-05-11 18:07:27 +08:00
13 changed files with 114 additions and 84 deletions
@@ -40,6 +40,7 @@ class BusController(Controller):
)
if not exist:
employee.write({
'avatar_image': data.get('photo'),
'image_1920': data.get('photo'),
'attendance_iot_ids': [(0, 0, {
'employee_id': employee.id,
@@ -47,6 +48,7 @@ class BusController(Controller):
'attendance_address': ''
})]
})
_logger.info(f"-------------{employee.name}人脸更新触发------人脸数据{data.get('photo')}-------------")
_logger.info("-------------------------%s创建成功-------------------------------" % (employee.name))
return {"Result": 0, "Msg": "添加成功"}
+18 -16
View File
@@ -21,10 +21,10 @@
<field name="boss_char"/>
<field name="is_legal_trial"/>
<field name="co_organizer_dept" readonly="not is_admin and issue_state not in ['to_do', 'cancel','to_modify', 'draft']"/>
<field name="is_district_state"/>
<field name="is_district_government"/>
<field name="is_district_party"/>
<field name="is_external_person"/>
<field name="is_district_state" column_invisible="1"/>
<field name="is_district_government" column_invisible="1"/>
<field name="is_district_party" column_invisible="1"/>
<field name="is_external_person" column_invisible="1"/>
<field name="issue_state"/>
<field name="code" column_invisible="1"/>
<field name="company_id" column_invisible="1"/>
@@ -391,16 +391,17 @@
<button name="all_meeting_issue" type="object" string="会议安排" class="oe_highlight"/>
<button name="issue_party1_approval" type="object" string="批量审批" class="oe_highlight"/>
</header>
<field name="name"/>
<field name="name" column_invisible="1"/>
<field name="name_text" class="list_width"/>
<field name="department_id"/>
<field name="creart_datetime"/>
<field name="is_party" groups="yuthon_salary.group_jtbb_user" string="党总支"/>
<field name="is_party" groups="yuthon_salary.group_lc_user,yuthon_salary.group_wg_user"
string="党支部会"/>
<field name="party_char"/>
<field name="is_district_state"/>
<field name="is_district_government"/>
<field name="is_district_party"/>
<field name="is_district_state" column_invisible="1"/>
<field name="is_district_government" column_invisible="1"/>
<field name="is_district_party" column_invisible="1"/>
<field name="is_external_person"/>
<field name="issue_state" string="审批状态" />
<field name="issue_state_party"/>
@@ -435,16 +436,17 @@
<button name="all_meeting_issue" type="object" string="会议安排" class="oe_highlight"/>
<button name="issue_party_approval" type="object" string="批量审批" class="oe_highlight"/>
</header>
<field name="name"/>
<field name="name" column_invisible="1"/>
<field name="name_text" class="list_width"/>
<field name="department_id"/>
<field name="creart_datetime"/>
<field name="is_party" groups="yuthon_salary.group_jtbb_user" string="党总支"/>
<field name="is_party" groups="yuthon_salary.group_lc_user,yuthon_salary.group_wg_user"
string="党支部会"/>
<field name="party_char"/>
<field name="is_district_state"/>
<field name="is_district_government"/>
<field name="is_district_party"/>
<field name="is_district_state" column_invisible="1"/>
<field name="is_district_government" column_invisible="1"/>
<field name="is_district_party" column_invisible="1"/>
<field name="is_external_person"/>
<field name="issue_state" string="审批状态" />
<field name="issue_state_party"/>
@@ -586,7 +588,7 @@
['draft', 'to_draft'])]
</field>
<field name="search_view_id" ref="view_issue_library_filter"/>
<field name="context">{'from_action': 'issue_library_action3', 'search_default_to_approval': 1}</field>
<field name="context">{'from_action': 'issue_library_action3'}</field>
<field name="view_ids" eval="[(5, 0, 0),
(0, 0, {'view_mode': 'tree', 'view_id': ref('yuthon_issue.view_issue_library_tree2')}),
(0, 0, {'view_mode': 'form', 'view_id': ref('yuthon_issue.view_issue_library_form3')})]"/>
@@ -599,7 +601,7 @@
<field name="domain">[('is_push_party', '=', True),('issue_state', 'not in', ['draft', 'to_draft']),
('is_push_depart', '=', True), ('company_id.name', '!=', '集团本部')]
</field>
<field name="context">{'from_action': 'issue_library_action3', 'search_default_to_approval': 1}</field>
<field name="context">{'from_action': 'issue_library_action8'}</field>
<field name="search_view_id" ref="view_issue_library_filter"/>
<field name="view_ids" eval="[(5, 0, 0),
(0, 0, {'view_mode': 'tree', 'view_id': ref('yuthon_issue.view_issue_library_tree3')}),
@@ -767,7 +769,7 @@
('is_push_depart', '=', True)]
</field>
<field name="search_view_id" ref="view_issue_library_filter"/>
<field name="context">{'from_action': 'issue_library_action4', 'search_default_to_approval': 1}</field>
<field name="context">{'from_action': 'issue_library_action4'}</field>
<field name="view_ids" eval="[(5, 0, 0),
(0, 0, {'view_mode': 'tree', 'view_id': ref('yuthon_issue.view_issue_library_tree4')}),
(0, 0, {'view_mode': 'form', 'view_id': ref('yuthon_issue.view_issue_library_form4')})]"/>
@@ -933,7 +935,7 @@
('is_push_depart', '=', True)]
</field>
<field name="search_view_id" ref="view_issue_library_filter"/>
<field name="context">{'from_action': 'issue_library_action5', 'search_default_to_approval': 1}</field>
<field name="context">{'from_action': 'issue_library_action5'}</field>
<field name="view_ids" eval="[(5, 0, 0),
(0, 0, {'view_mode': 'tree', 'view_id': ref('yuthon_issue.view_issue_library_tree5')}),
(0, 0, {'view_mode': 'form', 'view_id': ref('yuthon_issue.view_issue_library_form5')})]"/>
@@ -28,6 +28,13 @@ class PropertyBillsPayable(models.Model):
document_ids = fields.Many2many('ir.attachment', string="附件")
active = fields.Boolean('Active', default=True, tracking=True)
work_end = fields.Boolean(string="结束")
payment_type = fields.Selection([
('deposit_refund', '退押'),
('lease_refund', '退租'),
('engineering', '工程款'),
('agency_fee', '中介费'),
('other', '其他')
], string='付款类型')
def _get_default_name_title(self):
return self._description if self._description else self._name
@@ -56,6 +56,7 @@
<field name="property_name"/>
<field name="lessee_id"/>
<field name="amount_payable"/>
<field name="payment_type"/>
<field name="deduction_amount"/>
<field name="remake" invisible="not deduction_amount"/>
<field name="actual_amount"/>
@@ -958,18 +958,20 @@
</group>
</group>
</page>
<page string="应收明细">
<page string="实收明细">
<field name="receivable_ids" string=" ">
<tree editable="bottom">
<field name="contract_id" column_invisible="1"/>
<field name="management_type_id"/>
<field name="last_month_table"/>
<field name="this_month_table"/>
<field name="ratio"/>
<field name="billable_quantity"/>
<field name="due_date"/>
<field name="due_date_end"/>
<field name="original_amount" string="应计金额"/>
<field name="last_month_table" column_invisible="1"/>
<field name="this_month_table" column_invisible="1"/>
<field name="ratio" column_invisible="1"/>
<field name="billable_quantity" column_invisible="1"/>
<field name="due_date" string="应收开始日期"/>
<field name="due_date_end" string="应收结束日期"/>
<field name="original_amount" string="收款金额"/>
<field name="payout_date" string="收款日期"/>
<field name="delivered1" string="应收金额"/>
<field name="pre_collection"/>
<field name="actual_coping"/>
<field name="remark"/>
@@ -37,7 +37,7 @@ class InheritPurchaseOrder(models.Model):
default=lambda self: [(6, 0, [self.env.user.id])])
pay_way = fields.Selection([('onetime', '一次性'), ('installment', '分期')], string="付款方式", default='onetime')
reason_text = fields.Text(string="申请事由")
purchase_type = fields.Selection([('fixed_asset', '固定资产采购'), ('sporadic', '零星采购'), ('comprehensive', '综合类')], string="采购类型", default='fixed_asset')
purchase_type = fields.Selection([('fixed_asset', '固定资产采购'), ('sporadic', '零星采购'), ('comprehensive', '综合类')], string="采购类型", default='comprehensive')
is_modify = fields.Boolean(string="可修改")
pay_line_ids = fields.One2many('purchase.order.pay.line', 'order_id', string="付款详情")
is_company = fields.Boolean(string="本公司", default=True, compute='_compute_is_company',search='_search_part_of_company')
@@ -41,7 +41,7 @@
</tr>
<tr>
<td class="label">采购标的类型</td>
<td colspan="5"><span t-esc="doc.category_id.name or ''"/></td>
<td colspan="5"><span t-esc="dict(doc._fields['purchase_type'].selection).get(doc.purchase_type, '')"/></td>
</tr>
<tr>
<td class="label">付款方式</td>
+55 -20
View File
@@ -9,24 +9,30 @@ class PreArrearsReport(models.Model):
@api.model
def get_pre_arrears_report(self, params):
"""
前期欠收报表(数据源:receivable.modify.line):
- 查询条件的日期对应应收账单的 due_date(应收日期在查询月内)
- 收款日期(reconciliation_date)晚于应收日期(due_date)的记录就是欠收
- 金额取收款记录的 not_collected(未收金额/欠收金额)
- 按应收账单聚合,每张账单只出一行(汇总该账单下所有欠收收款金额)
前期欠收报表(数据源:receivable.modify.line):
- 查询条件的日期对应应收账单的 due_date(应收日期在查询月及之前)
- 欠收条件:
- 收款日期在查询月之后(查询月时点还没收到钱)
- 或者 not_collected > 0 (部分收款,还没交完)
- 金额取值:
- 如果 not_collected > 0,取 not_collected (当前还欠的金额)
- 否则取 amount (已收金额)
- 按应收账单聚合,每张账单只出一行(汇总该账单下所有欠收收款金额)
"""
today = datetime.date.today()
this_month_first = today.replace(day=1)
date_start = params.get("date_start")
date_end = params.get("date_end")
# 应收日期在查询日期之前(不含查询月)
cutoff_date = datetime.datetime.fromisoformat(date_start).date() if date_start else this_month_first
# 应收日期在查询月及之前(包含查询月)
cutoff_date = datetime.datetime.fromisoformat(date_end).date() if date_end else this_month_first
# 查询月范围(用于判断收款是否在查询月内)
query_month_start = datetime.datetime.fromisoformat(date_start).date() if date_start else this_month_first
query_month_end = datetime.datetime.fromisoformat(date_end).date() if date_end else this_month_first
# 核心逻辑:due_date < cutoff_date,且收款日期 > 应收日期
# 核心逻辑:due_date <= cutoff_date(查询月及之前的应收)
domain = [
('reconciliation_date', '!=', False),
('receivable_id.due_date', '<', cutoff_date),
('receivable_id.due_date', '<=', cutoff_date),
('receivable_id.is_invalid', '=', False),
]
@@ -65,24 +71,43 @@ class PreArrearsReport(models.Model):
domain.append(('receivable_id.management_type_id.name', 'not in', ['押金', '违约金']))
lines = self.sudo().search(domain, order="receivable_id asc, reconciliation_date asc")
# 欠收条件:reconciliation_date > due_date 且不在同一个月(跨月才算欠收)
# 欠收条件(同时满足):
# 1. reconciliation_date >= query_month_start (收款日期不能小于查询月)
# 2. 满足以下任一:
# a. reconciliation_date > query_month_end (收款日期在查询月之后,查询月时点还没收到钱)
# b. not_collected > 0 (部分收款,还没交完)
lines = lines.filtered(
lambda l: l.reconciliation_date and l.receivable_id.due_date
and l.reconciliation_date > l.receivable_id.due_date
and not (
l.reconciliation_date.year == l.receivable_id.due_date.year
and l.reconciliation_date.month == l.receivable_id.due_date.month
)
lambda l: l.reconciliation_date and l.reconciliation_date >= query_month_start and (
(l.reconciliation_date > query_month_end) or
(l.not_collected and l.not_collected > 0)
)
)
# 调试日志
print(f"[前期欠收报表] 查询到的 lines 数量: {len(lines)}")
for line in lines:
print(f" - line.id={line.id}, receivable_id={line.receivable_id.id}, "
f"due_date={line.receivable_id.due_date}, "
f"reconciliation_date={line.reconciliation_date}, "
f"not_collected={line.not_collected}, amount={line.amount}")
# 按应收账单聚合
rec_map = {}
for line in lines:
rid = line.receivable_id.id
if rid not in rec_map:
rec_map[rid] = {'rec': line.receivable_id, 'amount': 0.0}
rec_map[rid]['amount'] += line.not_collected or 0.0
rec_map[rid] = {'rec': line.receivable_id, 'amount': 0.0, 'reconciliation_dates': []}
# 金额取值:有未收金额取not_collected,否则取amount
rec_map[rid]['amount'] += (line.not_collected if (line.not_collected and line.not_collected > 0) else line.amount) or 0.0
# 收集收款日期
if line.reconciliation_date:
rec_map[rid]['reconciliation_dates'].append(line.reconciliation_date)
# 调试日志
print(f"[前期欠收报表] 聚合后的 rec_map 数量: {len(rec_map)}")
for rid, data in rec_map.items():
print(f" - receivable_id={rid}, amount={data['amount']}")
rows = []
total_amount = 0.0
@@ -103,6 +128,13 @@ class PreArrearsReport(models.Model):
}
elif rec:
property_val = rec.property_name or ''
# 应收开始日期
due_date_str = rec.due_date.strftime('%Y-%m-%d') if rec.due_date else ''
# 收款日期(取所有收款日期,用逗号分隔)
reconciliation_dates = data.get('reconciliation_dates', [])
reconciliation_date_str = ', '.join([d.strftime('%Y-%m-%d') for d in sorted(set(reconciliation_dates))]) if reconciliation_dates else ''
rows.append({
"序号": idx,
@@ -110,6 +142,7 @@ class PreArrearsReport(models.Model):
'model': 'property.lease.contract',
'id': contract.id,
'display_name': contract.contract_code,
'view_id': self.env.ref('yuthon_property_approval.view_property_lease_contract_form1').id,
} if contract else "",
"物业名称": property_val,
"承租方名称": {
@@ -118,6 +151,8 @@ class PreArrearsReport(models.Model):
'display_name': rec.lessee_id.name,
} if rec.lessee_id else "",
"收款类型": rec.management_type_id.name if rec.management_type_id else "",
"应收开始日期": due_date_str,
"收款日期": reconciliation_date_str,
"金额": amount,
"所属公司": contract.lessor_id.name if contract and contract.lessor_id else "",
"管理员": {
@@ -8,48 +8,26 @@ class ReceivableModifyFilterDomains(models.Model):
@api.model
def get_receivable_filter_domains(self, params):
"""根据当前筛选条件,返回物业/承租方/合同的候选 ID 集合,用于三个下拉框互相过滤。"""
# 注意:这里不按日期限制,只根据当前组合条件(公司/权属/片区/收款类型/物业/承租方/合同)
# 来计算三类对象的全集,避免不同报表各自的日期口径导致候选集为空。
domain = [
('receivable_id.is_invalid', '=', False),
]
"""根据当前筛选条件,返回物业/承租方/合同的候选 ID 集合,用于三个下拉框互相过滤。
注意:
- 候选集不应受收款类型、是否无效等业务条件过滤
- 只根据用户已选择的物业/承租方/合同进行互相过滤
- 具体的业务过滤由报表查询方法自己处理
"""
domain = []
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')
# 只根据已选择的条件进行互相过滤,不应用业务过滤
property_id = params.get('property_id')
lessee_id = params.get('lessee_id')
contract_id = params.get('contract_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 property_id:
domain.append(('receivable_id.property_ids', 'in', [property_id]))
if lessee_id:
domain.append(('receivable_id.lessee_id', '=', lessee_id))
if contract_id:
domain.append(('receivable_id.contract_id', '=', contract_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.sudo().search(domain)
receivables = lines.mapped('receivable_id')
@@ -216,7 +216,7 @@ class ReceivableReport extends Component {
type: 'ir.actions.act_window',
res_model: model,
res_id: id,
views: [[false, 'form'], [false, 'search']],
views: [[view_id || false, 'form'], [false, 'search']],
target: 'new'
});
}
+3 -1
View File
@@ -13,11 +13,13 @@
"dateMode": "single",
"columns": [
{"headerName": "序号", "field": "序号", "width": 45, "flex": 0, "pinned": "left"},
{"headerName": "应收开始日期", "field": "应收开始日期", "flex": 1},
{"headerName": "收款日期", "field": "收款日期", "flex": 1},
{"headerName": "金额", "field": "金额", "flex": 1, "type": "number"},
{"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}
]
+1
View File
@@ -121,6 +121,7 @@ class YuthonWillTask(http.Controller):
'employee_num': ','.join(task.employee_ids.mapped('name')) if task.employee_ids else '',
'start_date': fields.Date.to_string(task.start_date),
'weekday': weekday_str,
'address': task.address or '',
'request_hour_from': '',
'request_hour_to': '',
'state': task.task_state,
+5 -5
View File
@@ -308,11 +308,11 @@
parent="attendance_resources_setting_root_board"
sequence="8"
action="yuthon_hr_attendance.view_overtime_page_action"/>
<menuitem id="menu_hr_resource_calendar_board"
name="法定节假日表"
parent="attendance_resources_setting_root_board"
sequence="10"
action="yuthon_hr_attendance.resource_calendar_leaves_action_from_calendar"/>
<!-- <menuitem id="menu_hr_resource_calendar_board"-->
<!-- name="法定节假日表"-->
<!-- parent="attendance_resources_setting_root_board"-->
<!-- sequence="10"-->
<!-- action="yuthon_hr_attendance.resource_calendar_leaves_action_from_calendar"/>-->
<menuitem id="holiday_set_type_board2"
name="休假类型"
parent="attendance_resources_setting_root_board"