diff --git a/yuthon_property/models/property_accounts_receivable.py b/yuthon_property/models/property_accounts_receivable.py
index fa978fb60..df45bc916 100644
--- a/yuthon_property/models/property_accounts_receivable.py
+++ b/yuthon_property/models/property_accounts_receivable.py
@@ -3,6 +3,8 @@ import xlwt
import base64
import io
from openpyxl import load_workbook
+from openpyxl.styles import Alignment
+from copy import copy
from odoo.modules import get_module_resource
from datetime import datetime, timedelta, date
@@ -286,3 +288,128 @@ class PropertyAccountsReceivable(models.Model):
'url': f'/web/content/{attachment.id}?download=true',
'target': 'self',
}
+
+ def export_kingdee_receivable(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', 'yingshoudanjindiedaoru.xlsx')
+ workbook = load_workbook(template_path)
+ sheet = workbook.active
+
+ # 从第3行开始写入数据(第1-2行是表头)
+ row = 3
+ # 序号起始值
+ sequence_number = 104101
+
+ # 获取模板样式行(使用第3行作为参考,但会被数据覆盖)
+ # 建议:确保模板第3行有完整的样式设置
+ template_row_idx = 3
+ if sheet.max_row >= template_row_idx:
+ # 先保存第3行的样式
+ template_styles = {}
+ for col in range(1, 37): # A到AJ列(36列)
+ 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 record in receivable_records:
+ # 先解除当前行的合并单元格(如果有)
+ 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)
+
+ # 先为所有列应用模板样式
+ for col in range(1, 37): # A到AJ列
+ 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 = copy(template_styles[col]['alignment'])
+
+ # A列:序号(从104101开始)
+ sheet.cell(row=row, column=1, value=sequence_number)
+
+ # B列:应收开始日期
+ if record.due_date:
+ sheet.cell(row=row, column=2, value=record.due_date.strftime('%Y-%m-%d'))
+
+ # C列:应收结束日期
+ if record.due_date_end:
+ sheet.cell(row=row, column=3, value=record.due_date_end.strftime('%Y-%m-%d'))
+
+ # E列:物业地址(设置自动换行)
+ e_cell = sheet.cell(row=row, column=5, value=record.property_name or '')
+ e_cell.alignment = Alignment(horizontal='center', vertical='center', wrap_text=True)
+
+ # M列:租赁单位(第13列)
+ rent_company = ''
+ if record.contract_id:
+ rent_company = record.contract_id.rent_company or ''
+ sheet.cell(row=row, column=13, value=rent_company)
+
+ # N列:备注(设置自动换行)
+ n_cell = sheet.cell(row=row, column=14, value=record.remark or '')
+ n_cell.alignment = Alignment(horizontal='left', vertical='center', wrap_text=True)
+
+ # 设置行高为自动(让Excel自动调整)
+ # 为确保自动换行生效,设置最小行高
+ if not sheet.row_dimensions[row].height or sheet.row_dimensions[row].height < 30:
+ sheet.row_dimensions[row].height = 30 # 设置最小行高30,确保能显示2-3行文本
+
+ # P列:承租方
+ sheet.cell(row=row, column=16, value=record.lessee_id.name if record.lessee_id else '')
+
+ # AF列:税率(第32列)
+ sheet.cell(row=row, column=32, value=record.tax or 0)
+
+ # AJ列:当期金额(第36列)
+ sheet.cell(row=row, column=36, value=record.original_amount or 0)
+
+ row += 1
+ sequence_number += 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',
+ }
diff --git a/yuthon_property/static/tmpl/yingshoudanjindiedaoru.xlsx b/yuthon_property/static/tmpl/yingshoudanjindiedaoru.xlsx
new file mode 100644
index 000000000..55fd2713b
Binary files /dev/null and b/yuthon_property/static/tmpl/yingshoudanjindiedaoru.xlsx differ
diff --git a/yuthon_property/views/property_accounts_receivable_views.xml b/yuthon_property/views/property_accounts_receivable_views.xml
index c0b48def5..2c05e23b6 100644
--- a/yuthon_property/views/property_accounts_receivable_views.xml
+++ b/yuthon_property/views/property_accounts_receivable_views.xml
@@ -162,4 +162,12 @@
code
action = model.export_batch_invoice()
+
+ 应收单金蝶导出
+
+
+ list
+ code
+ action = model.export_kingdee_receivable()
+
\ No newline at end of file
diff --git a/yuthon_salary/views/yuthon_salary_active_views.xml b/yuthon_salary/views/yuthon_salary_active_views.xml
index a38353af0..0b3ae8375 100644
--- a/yuthon_salary/views/yuthon_salary_active_views.xml
+++ b/yuthon_salary/views/yuthon_salary_active_views.xml
@@ -36,9 +36,6 @@
-
-
-
@@ -71,6 +68,9 @@
+
+
+