python 钉钉导出Excel考勤统计

本文介绍了一种使用Python处理钉钉导出的考勤表的方法,通过pandas和xlwings实现自动化统计加班时长及补贴,包括生成个人统计表和汇总表。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

  • 解决钉钉导出考勤表统计(加班时长、补贴)
  • 支持自定义格式输出,生成每个人的考勤统计
  • 基于pandas和xlwings对表格进行读写
import pandas as pd
import sys
import os
import numpy as np
import xlwings as xw
import time
import datetime
import glob
sys.path.append(os.path.dirname(os.path.abspath(__file__)))

class CheckIn:
    def __init__(self):
        pass

    def check_table(self, url):
        df = pd.read_excel(url, header=None, index_col=None)
        df = df[2:]
        df = df[[0, 1, 5, 6, 7, 8, 9]]
        df = df.drop(3, axis=0)
        df.columns = df.iloc[0].values
        df = df.drop(2, axis=0)
        # 只处理含‘正常’班和休息的班次
        df = df[df['上班1打卡结果'].isin(['正常']) | df['班次'].isin(['休息'])]
        # 必须包含上下班打卡
        df = df[~df['上班1打卡时间'].isin([np.NaN]) & ~df['下班1打卡时间'].isin([np.NaN])]
        df['累计加班'] = 0
        df['加班次数'] = 0
        df['餐补标准'] = 25
        df['报销金额'] = 0
        for _, row in df.iterrows():
            # 计算上下班时间
            row['上班1打卡时间'] = str(row['上班1打卡时间'])[0: 5]
            row['下班1打卡时间'] = str(row['下班1打卡时间'])[0: 5]
            start_time = row['上班1打卡时间']
            over_time = row['下班1打卡时间']
            add_min = 0
            if '次日' in row['下班1打卡时间']:  # 最晚有效下班时间为24:00
                over_time = '23:59'
                add_min = 60
            # print('start_time', str(start_time))
            start_time = datetime.datetime.strptime(start_time, "%H:%M")
            over_time = datetime.datetime.strptime(over_time, "%H:%M")
            work_time = max(round(((over_time - start_time).seconds + 1 + add_min) / 3600), 0)
            #  餐补统计
            if ('正常' in row['上班1打卡结果']) and (row['下班1打卡时间'] >= '19:00'):
                df.loc[row.name, '加班次数'] = 1
            elif '休息' in row['班次']:
                if work_time >= 4:
                    df.loc[row.name, '加班次数'] = 1
                if work_time >= 7:
                    df.loc[row.name, '加班次数'] = 2
            df.loc[row.name, '报销金额'] = df.loc[row.name, '加班次数'] * df.loc[row.name, '餐补标准']
            #  加班统计
            work_plus_time = 0
            if '正常' in row['上班1打卡结果']:
                if start_time.hour >= 7:  # 有效打卡早7点以后
                    if start_time.hour <= 9:  # 九点后累计上班时长
                        start_time = datetime.datetime.strptime('09:00', "%H:%M")
                    work_plus_time = max(round(((over_time - start_time).seconds + 1 + add_min) / 3600 - 9.5),
                                         0)  # 超过9.5计算加班时长,半小时一个粒度
            elif '休息' in row['班次']:
                if work_time >= 4:
                    work_plus_time = work_time
            df.loc[row.name, '累计加班'] = work_plus_time

        word_plus = url.replace('base', 'new').replace('考勤表', '加班餐补-加班时长明细表')
        df.to_excel(word_plus, index=False)
        df['加班日期'] = df['日期'].map(lambda x: x.split(" ")[0] + ' ') + df['下班1打卡时间'].map(str)
        df.loc[df['班次'] == '休息', '加班日期'] = df['日期'].map(str) + df['上班1打卡时间'].map(str)
        df_output = df[['姓名', '加班日期', '加班次数', '餐补标准', '报销金额', '上班1打卡结果', '班次', '累计加班']]
        return df_output[['姓名', '加班日期', '加班次数', '餐补标准', '报销金额', '累计加班', '班次']]

    def money_table(self, url, data, output_url):
        data = data[data['加班次数'] > 0 | data['班次'].isin(['休息'])]
        data = data.drop(['班次'], axis=1)
        name_list = data['姓名'].unique()
        wb = xw.Book(url)
        sht_sheet1 = wb.sheets['Sheet1']  # 要复制的sheets
        for i, v in enumerate(name_list):
            sht_sheet1.api.Copy(Before=sht_sheet1.api)
            sht = wb.sheets['Sheet1 (2)']
            sht.api.Name = v
            struct_time = time.localtime(time.time())  # 得到结构化时间格式
            now_time = time.strftime("%Y/%m/%d", struct_time)
            sht.range('H4').value = now_time
            sht.range('B4').value = output_url.split('/')[-1].split('\\')[-1].split('20')[0]
            item = data[data['姓名'] == v]
            new_data_rows = item.values.shape[0]
            item.insert(0, '序号', [i+1 for i in range(new_data_rows)])
            start_row = 7
            # last_row = sht.range('A7').expand().last_cell.row
            last_row = 38
            work_rows = last_row - start_row
            sub_rows = abs(new_data_rows - work_rows)
            # print(f'last{last_row},word{work_rows}')
            if new_data_rows > work_rows:
                for _ in range(sub_rows):
                    sht.api.rows(start_row + 1).insert
            elif new_data_rows < work_rows:
                for _ in range(sub_rows):
                    sht.api.rows(start_row + 1).delete
            # print(f'last{sht.range("A7").expand().last_cell.row},new{new_data_rows},word{work_rows}')
            sht.range('A7').value = item.values
        wb.save(output_url)
        wb.close()

    def total(self, df, output_url):
        total_df = df.groupby(by='姓名').sum()[['加班次数', '报销金额', '累计加班']]
        total_df = total_df.sort_values(by='加班次数', ascending=False)
        total_df['备注'] = ''
        total_df = total_df.reset_index()
        total_df = total_df.append([{
            '姓名': '合计', '加班次数': total_df['加班次数'].sum(), '报销金额': total_df['报销金额'].sum(),
            '累计加班': total_df['累计加班'].sum(), '备注':''
        }], ignore_index=True)
        total_df.to_excel(output_url, index=None)


if __name__ == '__main__':
    t = time.time()
    year = '2019'
    month = '5'
    root = '../../data/check'
    standard_url = f'{root}/研发加班餐补201908_standard.xlsx'
    for _, m in enumerate(range(10, 11, 1)):
        month = m
        print(f'生成月份:{month}')
        for check_url in glob.glob(f"{root}/{year}-{month}/base/*.xlsx"):
            if '$' in check_url:
                continue
            check_in = CheckIn()
            check_df = check_in.check_table(url=check_url)
            new_url = check_url.replace('base', 'new')
            total_output_url = new_url.replace('考勤表', '总计表')
            money_output_url = new_url.replace('考勤表', '加班餐补表')
            check_in.total(df=check_df, output_url=total_output_url)
            check_df = check_df.drop('累计加班', axis=1)
            check_in.money_table(url=standard_url, data=check_df, output_url=money_output_url)
    print(time.time()-t)

# print(df_output)
# df_output.to_excel(url.replace('.xlsx', '_清洗.xlsx'), index=None)

文件目录

在这里插入图片描述

钉钉导出表

在这里插入图片描述

生成个人统计表

在这里插入图片描述

依照标准格式表生成每人一张表

在这里插入图片描述

生成汇总统计表

在这里插入图片描述

### 钉钉OA系统自动化实现方法 #### 使用ETLCloud进行数据同步 为了简化并加速钉钉OA系统中的数据处理过程,可以采用ETLCloud这一工具来构建自动化流程。这不仅能够使数据从钉钉OA系统向数据仓库的转移变得更为高效,而且整个操作过程也变得更加简便,几乎无需人工干预即可完成复杂的数据迁移任务[^1]。 对于那些希望不依赖于专门的ETL软件而自行搭建解决方案的企业来说,则可以通过编程接口的方式直接对接钉钉API服务端口,从而达到相同的效果——即自动化的将特定时间段内产生的考勤记录等信息导出至外部存储介质如Excel文件或是进一步导入到企业的数据中心里去分析使用[^2]。 #### 利用钉钉开放平台的能力 借助于钉钉所提供的强大开放功能模块,尤其是其连接器特性,允许第三方开发者轻易地建立起与其他内部管理系统之间的桥梁;这意味着只要遵循官方文档指导下的标准协议编写相应程序逻辑就能轻松达成诸如定时抓取员工打卡情况之类的日常运维需求,并且这一切都可以被集成在一个统一的应用框架之下运行,极大地促进了工作效率的同时还保障了信息安全性和稳定性[^3]。 #### 创建与管理自定义审批流 针对更复杂的业务场景比如请假申请审核之类的情况,还可以考虑基于钉钉的小程序生态环境来自行设计个性化的在线表单模板供相关人员填写提交给上级领导审阅批准。一旦所有必要的输入项都被正确设置完毕之后,只需几行Python脚本就可以触发后台服务器发起请求创建新的待办事项条目,在此期间所获得的关键标识符(例如`instanceId`)同样应当妥善保管以便后续查询跟踪进展状况直至最终关闭结案为止[^4]。 ```python import requests def create_approval_instance(params, access_token): url = f"https://oapi.dingtalk.com/topapi/processinstance/create?access_token={access_token}" response = requests.post(url=url, json=params) result = response.json() if 'errcode' not in result or result['errcode'] != 0: raise Exception(f"Failed to create approval instance: {result}") return result.get('processInstanceId') ``` 上述代码展示了如何通过调用DingTalk API创建一个新的审批实例,并返回该实例的唯一标识符用于后续的状态监控和管理[^5]。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值