Frappe/ERPNext框架 自定义报表学习(脚本自定义构建列)
ERPNext是一个开源的企业资源计划(ERP)系统,由Frappe Technologies Pvt. Ltd.开发,主要用于帮助中小企业进行全面的业务管理。
·
要实现的效果如下图

原始数据如下图,此项目要对(分摊明细)字符串进行控制(切片等),相对麻烦一些

实现方法如下
选择脚本报表类型,过滤条件在写完代码后添加,如下图

脚本代码如下
# === 过滤条件获取 ===
# 从报表界面获取三个关键过滤参数用于后续查询
# 上图过滤条件的前提代码,一一对应
expense_claim_type = filters.get('expense_claim_type')
year = filters.get('year')
month = filters.get('month')
# === 员工金额统计模块 ===
# 目标:获取指定条件下的员工报销分配明细
# as_dict=True将结果转为字典格式方便操作
sql_emp_amount = f"""
SELECT
tb2.empno,
tb2.employee_name,
tb2.total_hours,
tb2.amount
FROM `tabExpense Allocation Doc` tb1 join `tabAllocation Item` tb2 on tb1.name=tb2.parent
WHERE
tb1.expense_claim_type = '{expense_claim_type}' AND year = '{year}' AND month = '{month}' AND reverse=1
"""
emp_amount = frappe.db.sql(sql_emp_amount, as_dict=True)
# 系统标准方法,查询前的f,用于动态查询,如 '{expense_claim_type}'
# === 出勤天数计算 ===
# 构建单独列
# 逻辑:为每个员工补充计算当月出勤天数
for i in emp_amount:
i["qqq"]=0 # 初始化出勤天数字段
a=i.empno
sql_emp_amount1 = f"""
SELECT DISTINCT
tb2.from_time
FROM `tabTimesheet` tb1 join `tabTimesheet Detail` tb2 on tb1.name=tb2.parent
WHERE
month(tb2.from_time) = '{month}' AND tb1.employee = '{a}' AND year(tb2.from_time) = '{year}'
"""
emp_amount1 = frappe.db.sql(sql_emp_amount1, as_dict=True)
i["qqq"]=len(emp_amount1) # 存储考勤记录数
# === 动态列生成模块 ===
# 2.1 项目号统计
# 逻辑:从首个Expense Allocation Doc获取所有分配项目
# 注意:
doc_list = frappe.get_all('Expense Allocation Doc',filters={'expense_claim_type': expense_claim_type,'year': year,'month': month}) # 系统标准方法,用于筛选获取
# 字符串控制,提取所需
if len(doc_list) > 0:
doc = frappe.get_doc('Expense Allocation Doc',doc_list[0].name)
list_all = []
for row in doc.allocation_item:
# 解析分配明细字符串
for i in row.allocation_detail.split(','):
if len(i)>0:
list_all.append(i.split('/')[0]) # 提取项目号部分
list_result = set(list_all) # 去重获得唯一项目号集合
# 2.2 动态添加字段
# 初始化所有项目相关字段为0
# 注意:分两次添加项目工时列和项目金额列
for i in emp_amount:
for pro in list_result:
i[pro] = 0 # 添加项目工时字段
# 二次遍历添加金额字段
for i in emp_amount:
for pro in list_result:
pro = pro+'金额'
i[pro] = 0 # 添加项目金额字段
# === 数据填充模块 ===
# 3. 解析分配明细并填充数据
# 流程:
# 1. 提取原始分配数据 -> list0
# 2. 展开分配明细 -> list1
# 3. 分割明细项 -> list2(结构:[empno, 项目, 工时, 金额])
list0 = []
for row in doc.allocation_item:
l = []
l.append(row.empno)
l.append(row.allocation_detail)
list0.append(l)
list1 = []
for i in list0:
for item in i[1].split(','): # 拆分多个分配项
l = []
if len(item) > 0:
l.append(i[0]) # empno
l.append(item) # 分配项字符串
list1.append(l)
list2 = []
for i in list1:
l = []
l.append(i[0]) # empno
for item in i[1].split('/'): # 分割单个分配项
l.append(item)
list2.append(l) # 结构:[empno, 项目, 工时, 金额]
# 数据填充到emp_amount字典
for i in list2:
key_value = i[1]
key_value_a = i[1]+'金额'
for obj in emp_amount:
if obj.empno == i[0]: # 匹配员工
obj[key_value] = i[2] # 填充工时
obj[key_value_a] = i[3] # 填充金额
# === 报表列配置 ===
# 4. 动态构建报表列
# 结构:
# - 基础信息列
# - 动态项目工时列
# - 总金额列
# - 动态项目金额列
# 注意:
# - 列顺序影响前端显示
# - 金额列字段名需与数据字段名严格对应
columns = [
{
"label": _("EmpNo"),
"fieldtype": "Data",
"fieldname": "empno",
"width": 80
},
{
"label": _("姓名"),
"fieldtype": "Data",
"fieldname": "employee_name",
"width": 80
},
{
"label": "出勤天数",
"fieldtype": "Data",
"fieldname": "qqq",
"width": 88
},
{
"label": _("Total Hours"),
"fieldtype": "Currency",
"fieldname": "total_hours",
"width": 100
},
]
# 添加动态项目工时列
for pro in list_result:
element = {"label": pro,"fieldtype": "Currency","fieldname": pro,"width": 108,}
columns.append(element)
# 添加总金额列
amounts1 = {
"label": _("Amount"),
"fieldtype": "Currency",
"fieldname": "amount",
"width": 100}
columns.append(amounts1)
# 添加动态项目金额列
for pro in list_result:
plement = {"label": pro,"fieldtype": "Currency","fieldname": pro+'金额',"width": 108,}
columns.append(plement)
# === 最终输出 ===
# 系统标准输出格式
# 注意:columns需要与emp_amount中的字段完全匹配
data = columns, emp_amount
代码仅供参考,有许多可以优化的地方
更多推荐


所有评论(0)