ChatCausalGPT commited on
Commit
76b7572
·
0 Parent(s):

Initial commit: Quality Inspection Report Generator

Browse files
.gitignore ADDED
@@ -0,0 +1,38 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Python
2
+ __pycache__/
3
+ *.py[cod]
4
+ *$py.class
5
+ *.so
6
+ .Python
7
+ env/
8
+ build/
9
+ develop-eggs/
10
+ dist/
11
+ downloads/
12
+ eggs/
13
+ .eggs/
14
+ lib/
15
+ lib64/
16
+ parts/
17
+ sdist/
18
+ var/
19
+ wheels/
20
+ *.egg-info/
21
+ .installed.cfg
22
+ *.egg
23
+
24
+ # Excel files (since they contain data)
25
+ *.xls
26
+ *.xlsx
27
+ *.xlsm
28
+ *.xlsb
29
+
30
+ # IDE
31
+ .idea/
32
+ .vscode/
33
+ *.swp
34
+ *.swo
35
+
36
+ # OS
37
+ .DS_Store
38
+ Thumbs.db
LICENSE ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ MIT License
2
+
3
+ Copyright (c) 2024 Quality Inspection Report Generator
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
README.md ADDED
@@ -0,0 +1,80 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Quality Inspection Report Generator
2
+
3
+ 一个用于从 Excel 数据生成质量检验报告的 Python 工具。
4
+
5
+ ## 功能特点
6
+
7
+ - 从源数据 Excel 文件自动生成质量检验报告
8
+ - 支持多个客户的批量处理
9
+ - 保持模板格式和样式
10
+ - 自动计算日期和有效期
11
+ - 完整的化学元素和尺寸数据处理
12
+
13
+ ## 系统要求
14
+
15
+ - Python 3.6+
16
+ - pandas
17
+ - openpyxl
18
+
19
+ ## 安装
20
+
21
+ 1. 克隆仓库:
22
+ ```bash
23
+ git clone https://github.com/1587causalai/quality-inspection-report-generator.git
24
+ cd quality-inspection-report-generator
25
+ ```
26
+
27
+ 2. 安装依赖:
28
+ ```bash
29
+ pip install -r requirements.txt
30
+ ```
31
+
32
+ ## 使用方法
33
+
34
+ 1. 准备输入文件:
35
+ - `1.xls`:源数据文件,包含 HEADER、Dimension 和 Sand 工作表
36
+ - `2.xlsx`:模板文件,包含 WACKER 工作表
37
+
38
+ 2. 运行脚本:
39
+ ```bash
40
+ python generate_quality_inspection_reports.py
41
+ ```
42
+
43
+ 3. 检查输出:
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
+ ### 输出报告格式
60
+
61
+ - 基本信息(B3-D5):数量、批号、日期等
62
+ - 化学元素数据(D9-D19):11种元素的测试结果
63
+ - 尺寸数据(D20-D28):外径、高度、壁厚等
64
+ - 批准信息(D29):批准人姓名
65
+
66
+ ## 文档
67
+
68
+ 详细的代码文档请参考 `quality_inspection_documentation.py`。
69
+
70
+ ## 许可证
71
+
72
+ MIT License
73
+
74
+ ## 作者
75
+
76
+ [Your Name]
77
+
78
+ ## 贡献
79
+
80
+ 欢迎提交 Issue 和 Pull Request!
check_template.py ADDED
@@ -0,0 +1,34 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from openpyxl import load_workbook
2
+ import pandas as pd
3
+
4
+ def print_sheet_content(file_path, sheet_name):
5
+ wb = load_workbook(file_path)
6
+ sheet = wb[sheet_name]
7
+
8
+ print(f"\nContent of sheet '{sheet_name}':")
9
+ for i, row in enumerate(sheet.rows, 1):
10
+ values = [str(cell.value) if cell.value is not None else '' for cell in row]
11
+ print(f"Row {i}: {values}")
12
+
13
+ # 打印模板文件的内容
14
+ print_sheet_content('2.xlsx', 'WACKER')
15
+
16
+ # 读取第一个文件的Sand工作表
17
+ print("\n原始数据结构:")
18
+ file1 = '1.xls'
19
+ df = pd.read_excel(file1, sheet_name='Sand')
20
+ print("\n列名:")
21
+ print(df.columns.tolist())
22
+
23
+ # 打印前几行数据以查看结构
24
+ print("\n前几行数据:")
25
+ print(df.head())
26
+
27
+ # 读取跳过12行的数据
28
+ print("\n跳过12行的数据:")
29
+ sand_df_skipped = pd.read_excel(file1, sheet_name='Sand', skiprows=12)
30
+ print(sand_df_skipped.head())
31
+
32
+ # 打印所有列名
33
+ print("\n跳过12行后的列名:")
34
+ print(sand_df_skipped.columns.tolist())
generate_quality_inspection_reports.py ADDED
@@ -0,0 +1,113 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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')
quality_inspection_documentation.py ADDED
@@ -0,0 +1,109 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ 质量检验报告生成脚本说明文档
3
+ ============================
4
+
5
+ 本文档详细说明了 generate_quality_inspection_reports.py 的工作原理和数据处理流程。
6
+
7
+ 输入文件
8
+ --------
9
+ 1. 1.xls - 源数据文件,包含以下工作表:
10
+ - HEADER: 包含基本信息如数量和批准人
11
+ - Dimension: 包含尺寸数据和检验日期
12
+ - Sand: 包含化学元素测试数据
13
+
14
+ 2. 2.xlsx - 模板文件,包含:
15
+ - WACKER: 模板工作表,包含预设格式
16
+
17
+ 数据结构
18
+ --------
19
+ 1. Sand表结构(跳过前12行后):
20
+ - 第3列 (索引2): Crucible ID(客户ID)
21
+ - 第5-15列 (索引4-14): 化学元素测试数据
22
+ * Al: 第5列 (索引4)
23
+ * Ca: 第6列 (索引5)
24
+ * Cu: 第7列 (索引6)
25
+ * Fe: 第8列 (索引7)
26
+ * K: 第9列 (索引8)
27
+ * Li: 第10列 (索引9)
28
+ * Mg: 第11列 (索引10)
29
+ * Mn: 第12列 (索引11)
30
+ * Na: 第13列 (索引12)
31
+ * Ti: 第14列 (索引13)
32
+ * Zr: 第15列 (索引14)
33
+
34
+ 2. 输出报告结构:
35
+ - 基本信息(B3-D5):数量、批号、日期等
36
+ - 化学元素数据(D9-D19):对应11种元素的测试结果
37
+ - 尺寸数据(D20-D28):外径、高度、壁厚等
38
+ - 批准信息(D29):批准人姓名
39
+
40
+ 处理流程
41
+ --------
42
+ 1. 数据读取阶段:
43
+ - 读取HEADER表获取基本信息
44
+ - 读取Dimension表获取尺寸数据和日期信息
45
+ - 读取Sand表获取化学元素测试数据
46
+ - 读取模板文件作为基础格式
47
+
48
+ 2. 数据处理阶段:
49
+ - 遍历Dimension表中的每个Customer ID
50
+ - 为每个Customer ID创建新的工作表
51
+ - 复制模板内容保持格式一致
52
+ - 填充基本信息(数量、日期等)
53
+ - 从Sand表匹配并填充化学元素数据
54
+ - 填充尺寸数据
55
+ - 添加批准人信息
56
+
57
+ 3. 数据映射关系:
58
+ a. 元素行号映射 (element_row_mapping):
59
+ - Al -> 第9行
60
+ - Ca -> 第10行
61
+ - Cu -> 第11行
62
+ ...(依此类推)
63
+
64
+ b. 元素列索引映射 (element_col_mapping):
65
+ - Al -> 第5列(索引4)
66
+ - Ca -> 第6列(索引5)
67
+ - Cu -> 第7列(索引6)
68
+ ...(依此类推)
69
+
70
+ 注意事项
71
+ --------
72
+ 1. 日期处理:
73
+ - 检验日期格式化为 YYYY-MM-DD
74
+ - 失效日期自动计算为检验日期+730天(2年)
75
+
76
+ 2. 数据验证:
77
+ - 检查Customer ID是否存在于Sand表中
78
+ - 确保所有必要的数据都被正确填充
79
+
80
+ 3. 格式保持:
81
+ - 通过复制模板内容保持原有格式
82
+ - 保持"批准人:"文本的一致性
83
+
84
+ 使用方法
85
+ --------
86
+ 1. 确保输入文件 (1.xls 和 2.xlsx) 在正确的位置
87
+ 2. 运行脚本:python generate_quality_inspection_reports.py
88
+ 3. 输出文件将保存为 2_updated.xlsx
89
+
90
+ 输出文件
91
+ --------
92
+ 2_updated.xlsx:包含所有客户的质量检验报告,每个客户一个工作表,
93
+ 保持了原有的格式并填充了所有必要的数据。
94
+ """
95
+
96
+ # 示例:如何使用生成的报告
97
+ def usage_example():
98
+ print("使用示例:")
99
+ print("1. 准备输入文件:")
100
+ print(" - 确保有1.xls(源数据)")
101
+ print(" - 确保有2.xlsx(模板)")
102
+ print("\n2. 运行脚本:")
103
+ print(" python generate_quality_inspection_reports.py")
104
+ print("\n3. 检查输出:")
105
+ print(" - 查看2_updated.xlsx")
106
+ print(" - 验证每个客户的工作表是否正确生成")
107
+
108
+ if __name__ == "__main__":
109
+ usage_example()
quick.py ADDED
@@ -0,0 +1,61 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import pandas as pd
2
+
3
+ def extract_sand_data(input_file, output_file):
4
+ try:
5
+ # 读取Excel文件的Sand工作表
6
+ xls = pd.ExcelFile(input_file)
7
+ if 'Sand' not in xls.sheet_names:
8
+ raise ValueError("Excel文件中缺少'Sand'工作表")
9
+
10
+ # 读取Sand工作表
11
+ df = pd.read_excel(xls, sheet_name='Sand', header=None)
12
+
13
+ # 定义数据起始行和列索引
14
+ start_row = 13 # 数据从第11行开始(0-based索引)
15
+ crucible_id_col = 2 # Crucible ID在C列(0-based索引)
16
+ element_start_col = 4 # 元素数据从第5列开始(0-based索引)
17
+ element_end_col = 14 # 元素数据到第15列结束(0-based索引)
18
+
19
+ # 提取数据
20
+ results = []
21
+ for row_idx in range(start_row, len(df)):
22
+ row = df.iloc[row_idx]
23
+ if pd.isna(row[crucible_id_col]): # 跳过空行
24
+ continue
25
+
26
+ # 提取Crucible ID
27
+ crucible_id = str(row[crucible_id_col]).strip()
28
+
29
+ # 提取元素数据
30
+ elements = {
31
+ "Crucible ID": crucible_id,
32
+ "Al": row[element_start_col],
33
+ "Ca": row[element_start_col + 1],
34
+ "Cu": row[element_start_col + 2],
35
+ "Fe": row[element_start_col + 3],
36
+ "K": row[element_start_col + 4],
37
+ "Li": row[element_start_col + 5],
38
+ "Mg": row[element_start_col + 6],
39
+ "Mn": row[element_start_col + 7],
40
+ "Na": row[element_start_col + 8],
41
+ "Ti": row[element_start_col + 9],
42
+ "Zr": row[element_start_col + 10],
43
+ }
44
+ results.append(elements)
45
+
46
+ # 将结果转换为DataFrame
47
+ result_df = pd.DataFrame(results)
48
+
49
+ # 保存到新的Excel文件
50
+ result_df.to_excel(output_file, index=False)
51
+ return f"数据已成功保存到 {output_file}"
52
+
53
+ except Exception as e:
54
+ return f"处理错误: {str(e)}"
55
+
56
+ # 使用示例
57
+ if __name__ == "__main__":
58
+ input_file = "1.xls" # 输入文件路径
59
+ output_file = "output.xlsx" # 输出文件路径
60
+ result = extract_sand_data(input_file, output_file)
61
+ print(result)
requirements.txt ADDED
@@ -0,0 +1,2 @@
 
 
 
1
+ pandas>=1.3.0
2
+ openpyxl>=3.0.0
test_structure.py ADDED
@@ -0,0 +1,38 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import pandas as pd
2
+
3
+ def analyze_excel_structure(file_path):
4
+ """分析Excel文件的基本结构"""
5
+ print(f"\n开始分析文件: {file_path}")
6
+
7
+ # 读取Excel文件
8
+ xls = pd.ExcelFile(file_path)
9
+
10
+ # 打印所有sheet名称
11
+ print("\n所有Sheet页:")
12
+ for sheet_name in xls.sheet_names:
13
+ print(f"- {sheet_name}")
14
+
15
+ # 分析每个sheet的结构
16
+ for sheet_name in xls.sheet_names:
17
+ print(f"\n\n分析 Sheet [{sheet_name}]:")
18
+
19
+ # 尝试不同的skiprows值来找到正确的数据结构
20
+ for skip_rows in [0, 6, 12]:
21
+ print(f"\n跳过 {skip_rows} 行后的结构:")
22
+ try:
23
+ df = pd.read_excel(file_path, sheet_name=sheet_name, skiprows=skip_rows)
24
+ print("\n列名:")
25
+ print(df.columns.tolist())
26
+ print("\n前3行数据:")
27
+ print(df.head(3))
28
+
29
+ # 打印非空行数
30
+ non_empty_rows = len(df.dropna(how='all'))
31
+ print(f"\n非空行数: {non_empty_rows}")
32
+
33
+ except Exception as e:
34
+ print(f"读取出错: {str(e)}")
35
+
36
+ if __name__ == "__main__":
37
+ INPUT_FILE = "1.xls"
38
+ analyze_excel_structure(INPUT_FILE)