ChatCausalGPT commited on
Commit
1f26669
·
1 Parent(s): 5639ab4

feat: add example files and update code structure

Browse files
Files changed (2) hide show
  1. README.md +22 -4
  2. generate_quality_inspection_reports.py +120 -100
README.md CHANGED
@@ -32,8 +32,12 @@ pip install -r requirements.txt
32
  ## 使用方法
33
 
34
  1. 准备输入文件:
35
- - `1.xls`:源数据文件,包含 HEADER、Dimension 和 Sand 工作表
36
- - `2.xlsx`:模板文件,包含 WACKER 工作表
 
 
 
 
37
 
38
  2. 运行脚本:
39
  ```bash
@@ -44,16 +48,30 @@ python generate_quality_inspection_reports.py
44
  - 生成的报告将保存为 `2_updated.xlsx`
45
  - 每个客户的数据将保存在单独的工作表中
46
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
47
  ## 数据格式要求
48
 
49
  ### 输入文件结构
50
 
51
- 1. `1.xls` 包含:
52
  - HEADER:基本信息(数量、批准人等)
53
  - Dimension:尺寸数据和检验日期
54
  - Sand:化学元素测试数据
55
 
56
- 2. `2.xlsx` 包含:
57
  - WACKER:报告模板格式
58
 
59
  ### 输出报告格式
 
32
  ## 使用方法
33
 
34
  1. 准备输入文件:
35
+ - 源数据文件(参考 `examples/example_source_data.xls`):
36
+ * HEADER 工作表:包含基本信息
37
+ * Dimension 工作表:包含尺寸数据
38
+ * Sand 工作表:包含化学元素测试数据
39
+ - 模板文件(参考 `examples/example_template.xlsx`):
40
+ * 包含预设的报告格式
41
 
42
  2. 运行脚本:
43
  ```bash
 
48
  - 生成的报告将保存为 `2_updated.xlsx`
49
  - 每个客户的数据将保存在单独的工作表中
50
 
51
+ ## 示例文件
52
+
53
+ 在 `examples` 目录中提供了示例文件:
54
+
55
+ 1. `example_source_data.xls`:源数据文件示例
56
+ - 展示了正确的数据格式和结构
57
+ - 包含了所有必需的工作表和字段
58
+
59
+ 2. `example_template.xlsx`:模板文件示例
60
+ - 展示了标准的报告格式
61
+ - 包含了所有必需的字段和公式
62
+
63
+ 您可以参考这些示例文件来准备您自己的输入文件。
64
+
65
  ## 数据格式要求
66
 
67
  ### 输入文件结构
68
 
69
+ 1. 源数据文件需要包含:
70
  - HEADER:基本信息(数量、批准人等)
71
  - Dimension:尺寸数据和检验日期
72
  - Sand:化学元素测试数据
73
 
74
+ 2. 模板文件需要包含:
75
  - WACKER:报告模板格式
76
 
77
  ### 输出报告格式
generate_quality_inspection_reports.py CHANGED
@@ -1,113 +1,133 @@
1
  import pandas as pd
2
  from openpyxl import load_workbook
3
  from datetime import datetime, timedelta
 
4
 
5
- # 读取第一个文件
6
- file1 = '1.xls'
7
- header_df = pd.read_excel(file1, sheet_name='HEADER')
 
 
8
 
9
- # 读取Dimension表,跳过前12行,然后使用第13行作为列名
10
- dimension_df = pd.read_excel(file1, sheet_name='Dimension', skiprows=12)
11
- # 使用第一行作为列名
12
- dimension_df.columns = dimension_df.iloc[0]
13
- # 删除第一行(现在已经作为列名)并重置索引
14
- dimension_df = dimension_df.iloc[1:].reset_index(drop=True)
 
 
 
 
15
 
16
- # 读取Sand表的数据
17
- sand_df = pd.read_excel(file1, sheet_name='Sand', header=None)
18
 
19
- # 读取第二个文件
20
- file2 = '2.xlsx'
21
- wb = load_workbook(file2)
22
- wacker_sheet = wb['WACKER']
 
 
23
 
24
- # 获取Sales Order Quantity和Quality Assured By
25
- sales_order_quantity = header_df.iloc[5, 2] # Sales Order Quantity位置
26
- quality_assured_by = header_df.iloc[3, 7] # Quality Assured By在第4行最后一列
27
 
28
- # 定义元素和行号的对应关系
29
- element_row_mapping = {
30
- 'Al': 9, # 硅柏_石英坩埚_QC530HS_201410_V3B-CN_Al
31
- 'Ca': 10, # 硅柏_石英坩埚_QC530HS_201410_V3B-CN_Ca
32
- 'Cu': 11, # 硅柏_石英坩埚_QC530HS_201410_V3B-CN_Cu
33
- 'Fe': 12, # 硅柏_石英坩埚_QC530HS_201410_V3B-CN_Fe
34
- 'K': 13, # 硅柏_石英坩埚_QC530HS_201410_V3B-CN_K
35
- 'Li': 14, # 硅柏_石英坩埚_QC530HS_201410_V3B-CN_Li
36
- 'Mg': 15, # 硅柏_石英坩埚_QC530HS_201410_V3B-CN_Mg
37
- 'Mn': 16, # 硅柏_石英坩埚_QC530HS_201410_V3B-CN_Mn
38
- 'Na': 17, # 硅柏_石英坩埚_QC530HS_201410_V3B-CN_Na
39
- 'Ti': 18, # 硅柏_石英坩埚_QC530HS_201410_V3B-CN_Ti
40
- 'Zr': 19 # 硅柏_石英坩埚_QC530HS_201410_V3B-CN_Zr
41
- }
42
 
43
- # 定义元素在Sand表中的列索引
44
- element_col_mapping = {
45
- 'Al': 4, # 第5列
46
- 'Ca': 5, # 第6列
47
- 'Cu': 6, # 第7列
48
- 'Fe': 7, # 第8列
49
- 'K': 8, # 第9列
50
- 'Li': 9, # 第10列
51
- 'Mg': 10, # 第11列
52
- 'Mn': 11, # 第12列
53
- 'Na': 12, # 第13列
54
- 'Ti': 13, # 第14列
55
- 'Zr': 14 # 第15列
56
- }
57
 
58
- # 遍历Dimension表格中的每个Customer ID
59
- for index, row in dimension_df.iterrows():
60
- customer_id = row['Customer ID'] # 现在这个列名应该是正确的了
61
- inspection_date = pd.to_datetime(row['Inspection Date']).strftime('%Y-%m-%d') # 格式化日期
62
-
63
- # 创建新的工作表
64
- new_sheet = wb.create_sheet(title=str(customer_id))
65
-
66
- # 复制WACKER表格的内容到新工作表(这样会保持原有的客户名称)
67
- for row_wacker in wacker_sheet.iter_rows(values_only=True):
68
- new_sheet.append(row_wacker)
69
-
70
- # 填充数据(不再覆盖客户名称)
71
- new_sheet['B3'] = str(sales_order_quantity) + ' PCS' # Number+Unit/数量+单位
72
- new_sheet['B4'] = customer_id # Batch reference/批号
73
- new_sheet['D4'] = inspection_date # Date of issue/报告日期
74
- new_sheet['B5'] = inspection_date # Production date/生产日期
75
- new_sheet['D5'] = (datetime.strptime(inspection_date, '%Y-%m-%d') + timedelta(days=730)).strftime('%Y-%m-%d') # Expiring date/失效日期
76
-
77
- # 从sand表中获取当前customer_id的数据
78
- sand_rows = sand_df[sand_df[2] == customer_id] # 使用第3列(索引2)作为Crucible ID
79
- if not sand_rows.empty:
80
- sand_row = sand_rows.iloc[0]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
81
 
82
- # 填充元素数据
83
- for element, target_row in element_row_mapping.items():
84
- source_col = element_col_mapping[element]
85
- new_sheet[f'D{target_row}'] = sand_row[source_col]
86
-
87
- # 填充Analysis result/分析结果
88
- # 保持原有的测试项目名称,只更新分析结果列
89
- for i in range(20, 29):
90
- if i == 20:
91
- new_sheet[f'D{i}'] = row['OD1'] # 外径1
92
- elif i == 21:
93
- new_sheet[f'D{i}'] = row['OD2'] # 外径2
94
- elif i == 22:
95
- new_sheet[f'D{i}'] = row['OD3'] # 外径3
96
- elif i == 23:
97
- new_sheet[f'D{i}'] = row['Height'] # 高度
98
- elif i == 24:
99
- new_sheet[f'D{i}'] = row['Wall11'] # 壁厚11
100
- elif i == 25:
101
- new_sheet[f'D{i}'] = row['Wall12'] # 壁厚12
102
- elif i == 26:
103
- new_sheet[f'D{i}'] = row['Wall13'] # 壁厚13
104
- elif i == 27:
105
- new_sheet[f'D{i}'] = row['Wall2'] # 壁厚2
106
- elif i == 28:
107
- new_sheet[f'D{i}'] = row['Wall3'] # 壁厚3
108
-
109
- # 保持"批准人:"文本,并在其后添加名字
110
- new_sheet['D29'] = f"批准人:{quality_assured_by}"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
111
 
112
- # 保存修改后的文件
113
- wb.save('2_updated.xlsx')
 
1
  import pandas as pd
2
  from openpyxl import load_workbook
3
  from datetime import datetime, timedelta
4
+ import os
5
 
6
+ def generate_reports(source_file='examples/example_source_data.xls',
7
+ template_file='examples/example_template.xlsx',
8
+ output_file='quality_inspection_report.xlsx'):
9
+ """
10
+ 生成质量检验报告。
11
 
12
+ 参数:
13
+ source_file (str): 源数据文件路径
14
+ template_file (str): 模板文件路径
15
+ output_file (str): 输出文件路径
16
+ """
17
+ # 检查文件是否存在
18
+ if not os.path.exists(source_file):
19
+ raise FileNotFoundError(f"源数据文件不存在: {source_file}")
20
+ if not os.path.exists(template_file):
21
+ raise FileNotFoundError(f"模板文件不存在: {template_file}")
22
 
23
+ # 读取第一个文件
24
+ header_df = pd.read_excel(source_file, sheet_name='HEADER')
25
 
26
+ # 读取Dimension表,跳过前12行,然后使用第13行作为列名
27
+ dimension_df = pd.read_excel(source_file, sheet_name='Dimension', skiprows=12)
28
+ # 使用第一行作为列名
29
+ dimension_df.columns = dimension_df.iloc[0]
30
+ # 删除第一行(现在已经作为列名)并重置索引
31
+ dimension_df = dimension_df.iloc[1:].reset_index(drop=True)
32
 
33
+ # 读取Sand表的数据
34
+ sand_df = pd.read_excel(source_file, sheet_name='Sand', header=None)
 
35
 
36
+ # 读取第二个文件
37
+ wb = load_workbook(template_file)
38
+ wacker_sheet = wb['WACKER']
 
 
 
 
 
 
 
 
 
 
 
39
 
40
+ # 获取Sales Order Quantity和Quality Assured By
41
+ sales_order_quantity = header_df.iloc[5, 2] # Sales Order Quantity位置
42
+ quality_assured_by = header_df.iloc[3, 7] # Quality Assured By在第4行最后一列
 
 
 
 
 
 
 
 
 
 
 
43
 
44
+ # 定义元素和行号的对应关系
45
+ element_row_mapping = {
46
+ 'Al': 9, # 硅柏_石英坩埚_QC530HS_201410_V3B-CN_Al
47
+ 'Ca': 10, # 硅柏_石英坩埚_QC530HS_201410_V3B-CN_Ca
48
+ 'Cu': 11, # 硅柏_石英坩埚_QC530HS_201410_V3B-CN_Cu
49
+ 'Fe': 12, # 硅柏_石英坩埚_QC530HS_201410_V3B-CN_Fe
50
+ 'K': 13, # 硅柏_石英坩埚_QC530HS_201410_V3B-CN_K
51
+ 'Li': 14, # 硅柏_石英坩埚_QC530HS_201410_V3B-CN_Li
52
+ 'Mg': 15, # 硅柏_石英坩埚_QC530HS_201410_V3B-CN_Mg
53
+ 'Mn': 16, # 硅柏_石英坩埚_QC530HS_201410_V3B-CN_Mn
54
+ 'Na': 17, # 硅柏_石英坩埚_QC530HS_201410_V3B-CN_Na
55
+ 'Ti': 18, # 硅柏_石英坩埚_QC530HS_201410_V3B-CN_Ti
56
+ 'Zr': 19 # 硅柏_石英坩埚_QC530HS_201410_V3B-CN_Zr
57
+ }
58
+
59
+ # 定义元素在Sand表中的列索引
60
+ element_col_mapping = {
61
+ 'Al': 4, # 第5列
62
+ 'Ca': 5, # 第6列
63
+ 'Cu': 6, # 第7列
64
+ 'Fe': 7, # 第8列
65
+ 'K': 8, # 第9列
66
+ 'Li': 9, # 第10列
67
+ 'Mg': 10, # 第11列
68
+ 'Mn': 11, # 第12列
69
+ 'Na': 12, # 第13列
70
+ 'Ti': 13, # 第14列
71
+ 'Zr': 14 # 第15列
72
+ }
73
+
74
+ # 遍历Dimension表格中的每个Customer ID
75
+ for index, row in dimension_df.iterrows():
76
+ customer_id = row['Customer ID'] # 现在这个列名应该是正确的了
77
+ inspection_date = pd.to_datetime(row['Inspection Date']).strftime('%Y-%m-%d') # 格式化日期
78
+
79
+ # 创建新的工作表
80
+ new_sheet = wb.create_sheet(title=str(customer_id))
81
+
82
+ # 复制WACKER表格的内容到新工作表(这样会保持原有的客户名称)
83
+ for row_wacker in wacker_sheet.iter_rows(values_only=True):
84
+ new_sheet.append(row_wacker)
85
 
86
+ # 填充数据(不再覆盖客户名称)
87
+ new_sheet['B3'] = str(sales_order_quantity) + ' PCS' # Number+Unit/数量+单位
88
+ new_sheet['B4'] = customer_id # Batch reference/批号
89
+ new_sheet['D4'] = inspection_date # Date of issue/报告日期
90
+ new_sheet['B5'] = inspection_date # Production date/生产日期
91
+ new_sheet['D5'] = (datetime.strptime(inspection_date, '%Y-%m-%d') + timedelta(days=730)).strftime('%Y-%m-%d') # Expiring date/失效日期
92
+
93
+ # 从sand表中获取当前customer_id的数据
94
+ sand_rows = sand_df[sand_df[2] == customer_id] # 使用第3列(索引2)作为Crucible ID
95
+ if not sand_rows.empty:
96
+ sand_row = sand_rows.iloc[0]
97
+
98
+ # 填充元素数据
99
+ for element, target_row in element_row_mapping.items():
100
+ source_col = element_col_mapping[element]
101
+ new_sheet[f'D{target_row}'] = sand_row[source_col]
102
+
103
+ # 填充Analysis result/分析结果
104
+ # 保持原有的测试项目名称,只更新分析结果列
105
+ for i in range(20, 29):
106
+ if i == 20:
107
+ new_sheet[f'D{i}'] = row['OD1'] # 外径1
108
+ elif i == 21:
109
+ new_sheet[f'D{i}'] = row['OD2'] # 外径2
110
+ elif i == 22:
111
+ new_sheet[f'D{i}'] = row['OD3'] # 外径3
112
+ elif i == 23:
113
+ new_sheet[f'D{i}'] = row['Height'] # 高度
114
+ elif i == 24:
115
+ new_sheet[f'D{i}'] = row['Wall11'] # 壁厚11
116
+ elif i == 25:
117
+ new_sheet[f'D{i}'] = row['Wall12'] # 壁厚12
118
+ elif i == 26:
119
+ new_sheet[f'D{i}'] = row['Wall13'] # 壁厚13
120
+ elif i == 27:
121
+ new_sheet[f'D{i}'] = row['Wall2'] # 壁厚2
122
+ elif i == 28:
123
+ new_sheet[f'D{i}'] = row['Wall3'] # 壁厚3
124
+
125
+ # 保持"批准人:"文本,并在其后添加名字
126
+ new_sheet['D29'] = f"批准人:{quality_assured_by}"
127
+
128
+ # 保存修改后的文件
129
+ wb.save(output_file)
130
+ print(f"报告已生成: {output_file}")
131
 
132
+ if __name__ == "__main__":
133
+ generate_reports()