!8877 !8876 Merge branch 'dev' of <a href="https://gitee.com/jinan-pengyusen…

Merge pull request !8877 from 李鹏宇/dev
This commit is contained in:
李鹏宇
2026-02-11 13:08:58 +00:00
committed by Gitee
3 changed files with 126 additions and 0 deletions
@@ -1,5 +1,8 @@
from odoo import models, fields, api
import xlwt
import base64
import io
from openpyxl import load_workbook
from odoo.modules import get_module_resource
from datetime import datetime, timedelta, date
@@ -168,3 +171,118 @@ class PropertyAccountsReceivable(models.Model):
'default_name' : self.receivable_log
}
}
def export_batch_invoice(self):
"""导出批量开票数据到Excel模板"""
# 获取勾选的应收账单记录
receivable_ids = self._context.get('active_ids', [])
if not receivable_ids:
return {
'type': 'ir.actions.client',
'tag': 'display_notification',
'params': {
'message': '请先勾选需要导出的应收账单记录',
'type': 'warning',
'sticky': False,
}
}
receivable_records = self.env['property.accounts.receivable'].browse(receivable_ids)
# 加载模板文件
template_path = get_module_resource('yuthon_property', 'static', 'tmpl', 'piliangkaipiao.xlsx')
workbook = load_workbook(template_path)
sheet = workbook.active
# 找到第一个数据行(跳过表头)
# 从第1行开始检查,找到第一个完全空的行作为数据起始行
start_row = 1
for row_idx in range(1, 100): # 最多检查100行
# 检查该行的前10列是否都为空
is_empty_row = all(sheet.cell(row=row_idx, column=col).value is None for col in range(1, 11))
if is_empty_row:
start_row = row_idx
break
# 如果没找到空行,默认从第2行开始(假设第1行是表头)
if start_row == 1:
start_row = 2
row = start_row
for index, record in enumerate(receivable_records, start=1):
# 先解除当前行的合并单元格(如果有)
merged_cells_to_unmerge = []
for merged_range in sheet.merged_cells.ranges:
if merged_range.min_row <= row <= merged_range.max_row:
merged_cells_to_unmerge.append(str(merged_range))
for merged_range_str in merged_cells_to_unmerge:
sheet.unmerge_cells(merged_range_str)
# A列:序号
sheet.cell(row=row, column=1, value=index)
# B列:类型
acc_type_display = dict(record._fields['acc_type'].selection).get(record.acc_type, '') if record.acc_type else ''
sheet.cell(row=row, column=2, value=acc_type_display)
# C列:应收时间段(due_date ~ due_date_end)
due_date_str = record.due_date.strftime('%Y-%m-%d') if record.due_date else ''
due_date_end_str = record.due_date_end.strftime('%Y-%m-%d') if record.due_date_end else ''
date_range = f"{due_date_str} ~ {due_date_end_str}" if due_date_str and due_date_end_str else due_date_str
sheet.cell(row=row, column=3, value=date_range)
# D列:承租方
sheet.cell(row=row, column=4, value=record.lessee_id.name if record.lessee_id else '')
# E列:统一社会信用代码(从台账获取)
credit_code = ''
if record.contract_id and record.contract_id.lessee_id:
ledger = self.env['yuthon.property.ledger'].search([
('lessee_id', '=', record.contract_id.lessee_id.id)
], limit=1)
if ledger:
credit_code = ledger.credit_code or ''
sheet.cell(row=row, column=5, value=credit_code)
# F列:当期金额
sheet.cell(row=row, column=6, value=record.original_amount or 0)
# G列:物业地址
sheet.cell(row=row, column=7, value=record.property_name or '')
# H列:产权证信息
title_info = record.contract_id.title_information if record.contract_id else ''
sheet.cell(row=row, column=8, value=title_info or '')
# I列:开票类型
invoicing_type_display = ''
if record.lessee_id and record.lessee_id.invoicing_type:
invoicing_type_display = dict(record.lessee_id._fields['invoicing_type'].selection).get(
record.lessee_id.invoicing_type, '')
sheet.cell(row=row, column=9, value=invoicing_type_display)
# J列:税率
sheet.cell(row=row, column=10, value=record.tax or 0)
row += 1
# 保存到内存
output = io.BytesIO()
workbook.save(output)
output.seek(0)
excel_data = base64.b64encode(output.read())
output.close()
# 创建附件并返回下载
attachment = self.env['ir.attachment'].create({
'name': '批量开票数据.xlsx',
'datas': excel_data,
'mimetype': 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
'type': 'binary',
})
return {
'type': 'ir.actions.act_url',
'url': f'/web/content/{attachment.id}?download=true',
'target': 'self',
}
Binary file not shown.
@@ -154,4 +154,12 @@
]]>
</field>
</record>
<record id="export_batch_invoice_action" model="ir.actions.server">
<field name="name">批量开票导出</field>
<field name="model_id" ref="yuthon_property.model_property_accounts_receivable"/>
<field name="binding_model_id" ref="yuthon_property.model_property_accounts_receivable"/>
<field name="binding_view_types">list</field>
<field name="state">code</field>
<field name="code">action = model.export_batch_invoice()</field>
</record>
</odoo>