Merge pull request !8877 from 李鹏宇/dev
This commit is contained in:
@@ -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>
|
||||
Reference in New Issue
Block a user