!9157 Merge branch 'dev' of <a href="https://gitee.com/jinan-pengyusen-data/gzth">https://gitee.com/jinan-pengyusen-data/gzth</a> into dev_wang
Merge pull request !9157 from 李鹏宇/dev_wang
This commit is contained in:
@@ -188,42 +188,47 @@ class PropertyAccountsReceivable(models.Model):
|
||||
}
|
||||
|
||||
def export_batch_invoice(self):
|
||||
"""导出批量开票数据到Excel模板"""
|
||||
# 获取勾选的应收账单记录
|
||||
"""导出批量开票数据到新Excel模板"""
|
||||
receivable_ids = self._context.get('active_ids', [])
|
||||
if not receivable_ids:
|
||||
return {
|
||||
'type': 'ir.actions.client',
|
||||
'tag': 'display_notification',
|
||||
'params': {
|
||||
'message': '请先勾选需要导出的应收账单记录',
|
||||
'title': '警告',
|
||||
'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
|
||||
receivable_records = self.env['property.accounts.receivable'].browse(receivable_ids)
|
||||
|
||||
# 加载新模板文件
|
||||
template_path = get_module_resource('yuthon_property', 'static', 'tmpl', 'piliangkaipiao (2).xlsx')
|
||||
workbook = load_workbook(template_path)
|
||||
|
||||
# 指定写入"原始数据"sheet
|
||||
sheet = workbook['原始数据']
|
||||
|
||||
row = start_row
|
||||
# 从第3行开始写入数据(第1-2行是表头)
|
||||
row = 3
|
||||
|
||||
# 获取模板样式行(使用第3行作为参考)
|
||||
template_row_idx = 3
|
||||
if sheet.max_row >= template_row_idx:
|
||||
template_styles = {}
|
||||
for col in range(1, 11): # A到J列(10列)
|
||||
cell = sheet.cell(row=template_row_idx, column=col)
|
||||
template_styles[col] = {
|
||||
'font': copy(cell.font),
|
||||
'fill': copy(cell.fill),
|
||||
'border': copy(cell.border),
|
||||
'alignment': copy(cell.alignment),
|
||||
}
|
||||
else:
|
||||
template_styles = {}
|
||||
|
||||
for index, record in enumerate(receivable_records, start=1):
|
||||
# 先解除当前行的合并单元格(如果有)
|
||||
merged_cells_to_unmerge = []
|
||||
@@ -233,69 +238,97 @@ class PropertyAccountsReceivable(models.Model):
|
||||
for merged_range_str in merged_cells_to_unmerge:
|
||||
sheet.unmerge_cells(merged_range_str)
|
||||
|
||||
# A列:序号
|
||||
# 先为所有列应用模板样式并统一居中对齐
|
||||
for col in range(1, 11): # A到J列
|
||||
cell = sheet.cell(row=row, column=col)
|
||||
if col in template_styles:
|
||||
cell.font = copy(template_styles[col]['font'])
|
||||
cell.fill = copy(template_styles[col]['fill'])
|
||||
cell.border = copy(template_styles[col]['border'])
|
||||
# 统一设置居中对齐
|
||||
cell.alignment = Alignment(horizontal='center', vertical='center')
|
||||
|
||||
# A列:序号(从1开始)
|
||||
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)
|
||||
# B列:应收租期(due_date ~ due_date_end)
|
||||
date_range = ''
|
||||
if record.due_date and record.due_date_end:
|
||||
date_range = f"{record.due_date.strftime('%Y-%m-%d')} ~ {record.due_date_end.strftime('%Y-%m-%d')}"
|
||||
elif record.due_date:
|
||||
date_range = record.due_date.strftime('%Y-%m-%d')
|
||||
sheet.cell(row=row, column=2, value=date_range)
|
||||
|
||||
# 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)
|
||||
# C列:承租方名称(lessee_id)
|
||||
sheet.cell(row=row, column=3, value=record.lessee_id.name if record.lessee_id else '')
|
||||
|
||||
# D列:承租方
|
||||
sheet.cell(row=row, column=4, value=record.lessee_id.name if record.lessee_id else '')
|
||||
# D列:统一社会信用代码/纳税人识别号(从invoicing.information.line获取)
|
||||
tax_number = ''
|
||||
if record.lessee_id and record.lessee_id.invoicing_ids:
|
||||
# 取第一条有效记录的税号
|
||||
for inv_line in record.lessee_id.invoicing_ids:
|
||||
if inv_line.tax_number:
|
||||
tax_number = inv_line.tax_number
|
||||
break
|
||||
sheet.cell(row=row, column=4, value=tax_number)
|
||||
|
||||
# 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)
|
||||
# E列:金额(original_amount)
|
||||
sheet.cell(row=row, column=5, value=record.original_amount or 0)
|
||||
|
||||
# F列:当期金额
|
||||
sheet.cell(row=row, column=6, value=record.original_amount or 0)
|
||||
# F列:物业名称(property_name)
|
||||
sheet.cell(row=row, column=6, value=record.property_name or '')
|
||||
|
||||
# G列:物业地址
|
||||
sheet.cell(row=row, column=7, value=record.property_name or '')
|
||||
# G列:产权证(title_information,从合同获取)
|
||||
title_info = ''
|
||||
if record.contract_id:
|
||||
title_info = record.contract_id.title_information or ''
|
||||
sheet.cell(row=row, column=7, value=title_info)
|
||||
|
||||
# H列:产权证信息
|
||||
title_info = record.contract_id.title_information if record.contract_id else ''
|
||||
sheet.cell(row=row, column=8, value=title_info or '')
|
||||
# H列:发票类型(从invoicing.information.line的invoicing_type_id获取)
|
||||
invoicing_type = ''
|
||||
if record.lessee_id and record.lessee_id.invoicing_ids:
|
||||
# 取第一条有效记录的发票类型
|
||||
for inv_line in record.lessee_id.invoicing_ids:
|
||||
if inv_line.invoicing_type_id:
|
||||
invoicing_type = inv_line.invoicing_type_id.name or ''
|
||||
break
|
||||
sheet.cell(row=row, column=8, value=invoicing_type)
|
||||
|
||||
# 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)
|
||||
# I列:税率(从合同的tax_rate获取)
|
||||
tax_rate_name = ''
|
||||
if record.contract_id and record.contract_id.tax_rate:
|
||||
tax_rate_name = record.contract_id.tax_rate.name or ''
|
||||
sheet.cell(row=row, column=9, value=tax_rate_name)
|
||||
|
||||
# J列:税率
|
||||
sheet.cell(row=row, column=10, value=record.tax or 0)
|
||||
# J列:合同编号(contract_code,从合同获取)
|
||||
contract_code = ''
|
||||
if record.contract_id:
|
||||
contract_code = record.contract_id.contract_code or ''
|
||||
sheet.cell(row=row, column=10, value=contract_code)
|
||||
|
||||
# 设置最小行高
|
||||
if not sheet.row_dimensions[row].height or sheet.row_dimensions[row].height < 30:
|
||||
sheet.row_dimensions[row].height = 30
|
||||
|
||||
row += 1
|
||||
|
||||
|
||||
# 保存到内存
|
||||
output = io.BytesIO()
|
||||
workbook.save(output)
|
||||
output.seek(0)
|
||||
excel_data = base64.b64encode(output.read())
|
||||
output.close()
|
||||
|
||||
# 创建附件并返回下载
|
||||
|
||||
# 创建附件
|
||||
filename = f'批量开票_{datetime.now().strftime("%Y%m%d")}.xlsx'
|
||||
attachment = self.env['ir.attachment'].create({
|
||||
'name': '批量开票数据.xlsx',
|
||||
'name': filename,
|
||||
'type': 'binary',
|
||||
'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',
|
||||
|
||||
BIN
Binary file not shown.
@@ -1,5 +1,24 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<odoo>
|
||||
<record id="view_yuthon_meal_expenses_search" model="ir.ui.view">
|
||||
<field name="name">yuthon.meal.expenses.search</field>
|
||||
<field name="model">yuthon.meal.expenses</field>
|
||||
<field name="arch" type="xml">
|
||||
<search>
|
||||
<field name="employee_id"/>
|
||||
<field name="card"/>
|
||||
<field name="select_year"/>
|
||||
<field name="select_time"/>
|
||||
<field name="company_id"/>
|
||||
<field name="meal_state"/>
|
||||
<group expand="0" string="分组">
|
||||
<filter string="年份" name="group_by_year" context="{'group_by':'select_year'}"/>
|
||||
<filter string="月份" name="group_by_month" context="{'group_by':'select_time'}"/>
|
||||
<filter string="状态" name="group_by_state" context="{'group_by':'meal_state'}"/>
|
||||
</group>
|
||||
</search>
|
||||
</field>
|
||||
</record>
|
||||
<record id="view_yuthon_meal_expenses_tree" model="ir.ui.view">
|
||||
<field name="name">yuthon.meal.expenses.tree</field>
|
||||
<field name="model">yuthon.meal.expenses</field>
|
||||
|
||||
Reference in New Issue
Block a user