【准究极版】教你一分钟完成报表制作、报表发送、清单发送和微信通报

前言:标题有点噱头,其实实际做报表的时间远远不止1分钟,还有数据拉取。数据拉取因为数据库后台没有打通,必须前台网页拉取,而且有些报表等待时间较长,所以目前也没有好的解决办法。
在这里插入图片描述
11月17日更新:虽然不知道为什么,但终于找到了可以让189邮箱收到附件的方法了:用英文名字!
11月19日更新:
1)、在VBA中增加了自动把新门店、新套餐加入匹配表里的代码;
2)、增加了自动关闭VPN的代码,使得程序真正地内外网通用;
3)、受部分同学要求,把清单收件人也做了excel导入。
11月22日更新:
今天发生了因为excel崩溃导致在最后日报中数据不准确的情况,经过核验第一步数据刷新是成功的,问题出在第二步,所以加了一段代码,判断第二步日报成品中的移动数据和第一步的数据刷新结果是否一致,如果不一致就抛出异常并退出程序。
11月26日更新:
1)、在VBA代码中增加了自动增加“报表内缺的门店”到日报模板中,根据不同的渠道类型添加在不同的行
2)、在Python中增加了判断递归的次数,如果超过3次就抛出异常并退出

import smtplib #邮件
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from email.mime.base import MIMEBase #附件
from email import encoders #转码
from datetime import date
from datetime import timedelta
from datetime import datetime
from os import remove
from os import path
from os import system
from shutil import copyfile
from win32com.client import Dispatch
from itchat import auto_login
from itchat import get_chatrooms
from itchat import search_chatrooms
from itchat import send
from itchat import send_image
from time import sleep

#《《《《《《基础环境设置类》》》》》》
#获得昨天的日期,并把名字改成0901这样的格式
def getYesterday():
    today = date.today()
    oneday = timedelta(days = 1)
    yesterday = today - oneday
    date_yes = yesterday.strftime("%m%d")
    return date_yes

#启动excel和路径设置
def excel_pre():
    global path_this_file
    path_this_file = path.abspath('.')+"\\"
    global path_data
    path_data = path.abspath('..')+"\\数据\\"
    global xl
    xl = Dispatch("Excel.Application")
    xl.Visible = False #True是显示, False是隐藏
    xl.DisplayAlerts = 0

#运行宏
def useVBA(file_path, VBA):
    xlBook = xl.Workbooks.Open(file_path,False)
    xlBook.Application.Run(VBA)
    xlBook.Close(True)

#把报表中的需要通报的内容导出为图片
def excel_export(excel_range, name):
    rng=ws_pic.Range(excel_range)
    rng.CopyPicture()
    c=ws_pic.ChartObjects().Add(0,0,rng.Width,rng.Height).Chart
    c.Parent.Select()
    c.paste()
    c.Export(path_this_file + name + '.png', "png")
    c.Parent.Delete()

#《《《《《《报表制作类》》》》》》
#报表制作
def make_ribao():
    file_path1= path_this_file + "!源数据(每日刷新).xlsm"
    file_path2= path_this_file + "日报模板(会用宏的可以用用).xlsm"
    useVBA(file_path1, '数据添加刷新宏')
    sleep(5)
    print('>>>数据刷新完毕!')
    #判断是否报表内缺门店,如果缺的话提醒!
    # xlBook = xl.Workbooks.Open(file_path1,False)
    # agent_need_add = xlBook.Sheets('报表内缺门店').Range("A2").Value
    # if agent_need_add != None:
    #     print(">>>警告!!!有新的门店在日报中缺失,请手动添加!!!")
    # xlBook.Close(True)
    useVBA(file_path2, '日报宏')
    print('>>>日报制作完毕!')

#获得某个单元格的数据
def get_excel_value(excelbook,sheetname,cell):
    wb_path = path_this_file + excelbook
    wb = xl.Workbooks.Open(wb_path)
    ws = wb.Sheets(sheetname)
    ex_value = ws.Range(cell).Value
    wb.Close()
    return ex_value

#检查日报数据是否完整
def check_ribao(n):
    if n <= 3:
        n = n + 1
        ribao_value = get_excel_value(ribao_name,'渠道维度','AK34')
        cdma_value = get_excel_value('!源数据(每日刷新).xlsm','获得移动数据总量','B2')
        if -10 < (ribao_value - cdma_value) < 10:
            print(">>>移动数据准确!")
        else:
            print('>>>移动数据异常,准备关闭Excel程序并重试!')
            system('taskkill /F /IM Excel.exe')  # 关闭excel
            excel_pre()
            make_ribao()
            get_ribao()
            check_ribao(n)
    else:
        for i in range(5):
            print('>>>数据刷新异常,刷新次数超过3次,请检查!'.format(5 - i))
            sleep(1)
        exit(1)


#获得日报的标准名称
def get_ribao():
    global ribao_name
    ribao_name = '【基础经营-实体1】:“乘风破浪”百日冲刺报表'+getYesterday()+'.xlsx'
    global ribao_title
    ribao_title = '请收阅:'+'【基础经营-实体1】:“乘风破浪”百日冲刺报表'+getYesterday()
    global ribao_path
    ribao_path = path_this_file + ribao_name


#复制日报并改变名字成英文
def get_English_ribao():
    global English_ribao
    English_ribao = 'PD Daily Report_'+getYesterday()+'.xlsx'
    copyfile(ribao_name,English_ribao)

#《《《《《《获取内容类》》》》》》
#从日报中获取通报内容(可以用于微信通报和邮件正文)
def get_ribao_value():
    global wb_ribao
    wb_ribao = xl.Workbooks.Open(ribao_path)
    ws_body = wb_ribao.Sheets('门店通报')
    global everyday_report
    everyday_report = ws_body.Range('A2').Value
    print('>>>内容获取成功!')

#从日报中获取通报图片
def get_pic():
    global ws_pic
    ws_pic = wb_ribao.Sheets('群通报')
    excel_export('A1:R18', 'store')
    excel_export('A20:R34', 'agent')
    global store_pic
    store_pic = path_this_file + "store.png"  # 微信附件必须是英文
    global agent_pic
    agent_pic = path_this_file + "agent.png"
    print('>>>图片导出成功!')
    wb_ribao.Saved = True  # 不保存文件
    wb_ribao.Close()

#《《《《《《《邮件类》》》》》》》
#邮件基础设置
def mail_pre():
    global fromAddr
    fromAddr = '[email protected]'  # 发件人
    global myPass
    myPass = '******'  # 发件人密码

#读取收件人列表
def get_receiver(sheetname):
    receive_list = []
    file_email_list = path_this_file + '日报收件人.xlsx'
    receive_mail = xl.Workbooks.Open(file_email_list)
    sheet = receive_mail.Sheets(sheetname)
    max_row = sheet.UsedRange.Rows.Count + 1
    for rowNum in range(2, max_row):
        receive_list.append(sheet.Cells(rowNum, 2).Value)
    if len(receive_list) == 0:
        get_mail_receiver = ''
    else:
        get_mail_receiver = ','.join(receive_list)
    return get_mail_receiver

#邮件服务器基础设置
def server_pre(msg):
    server = smtplib.SMTP('mail.sh.ctc.com')
    server.starttls()
    server.login(fromAddr, myPass)
    server.send_message(msg)
    server.quit()

#邮件中添加附件(仅用于给清单)
def fujian(x):
    with open(path_data + x + '.xls','rb') as f:
        #这里附件的MIME和文件名,这里是xls类型
        mime = MIMEBase('xls','xls',filename=x+'.xls')
        #加上必要的头信息
        mime.add_header('Content-Disposition','attachment',filename=('gb2312', '', x + '.xls'))
        mime.add_header('Content-ID','<0>')
        mime.add_header('X-Attachment-Id','0')
        #把附件的内容读进来
        mime.set_payload(f.read())
        #用Base64编码
        encoders.encode_base64(mime)
        msg_list.attach(mime)

#添加日报附件了(仅限于针对英文日报)
def put_attachment(file_name):
    part = MIMEBase('attachment', 'octet-stream')  # 'octet-stream': binary data
    part.set_payload(open(file_name, 'rb').read())
    encoders.encode_base64(part)
    part.add_header('Content-Disposition', 'attachment', filename=file_name)
    msg_ribao.attach(part)

#《《《《《《执行类》》》》》》》
#发送清单
def send_listing():
    toAddr = get_receiver('清单收件人') #收件人
    global msg_list
    msg_list = MIMEMultipart()
    msg_list['From'] = fromAddr
    msg_list['To'] = toAddr
    msg_list['Subject'] = 'CDMA、宽带和单转融清单'
    body = 'CDMA、宽带和单转融清单'
    msg_list.attach(MIMEText(body))
    fujian('cdma')
    fujian('kd')
    fujian('单转融')
    fujian('88和wifi包')
    server_pre(msg_list)
    print(">>>清单发送成功!")

#发送日报
def send_ribao():
    toAddr = get_receiver('收件人')
    acc = get_receiver('抄送人')
    get_English_ribao()
    body = everyday_report
    global msg_ribao
    msg_ribao = MIMEMultipart()
    msg_ribao['From'] = fromAddr
    msg_ribao['To'] = toAddr
    msg_ribao['Subject'] = ribao_title
    msg_ribao['Cc'] = acc
    msg_ribao.attach(MIMEText(body))
    put_attachment(English_ribao)
    server_pre(msg_ribao)
    xl.quit()
    print(">>>日报发送完成!")

#发送微信通报
def wx_report():
    auto_login(hotReload=True)
    get_chatrooms() #如果是发到群里的消息或文件,必须保存群到通讯录才能用
    room_store = search_chatrooms(name = "自营厅店长群")[0]['UserName'] #不能发给自己
    room_agent = search_chatrooms(name = "浦东局专营渠道代理商群")[0]['UserName']
    room_qudao = search_chatrooms(name = "浦东实体渠道运营中心")[0]['UserName']
    # room_store = search_chatrooms(name = "周末报表群")[0]['UserName'] #不能发给自己
    # room_agent = search_chatrooms(name = "周末报表群")[0]['UserName']
    # room_qudao = search_chatrooms(name = "周末报表群")[0]['UserName']
    send_image(store_pic,toUserName=room_store)
    send_image(agent_pic,toUserName=room_agent)
    send(everyday_report, toUserName=room_qudao)
    print(">>>微信发送成功!")

# 主程序
if __name__ =="__main__":
    starttime = datetime.now()
    print('>>>程序正在运行中,请不要关闭窗口!')
    # 首先是基础环境配置
    excel_pre()
    # 然后是做报表,并获得通报内容和图片
    make_ribao()
    get_ribao()
    n = 1
    check_ribao(n)
    get_English_ribao()
    get_ribao_value()
    get_pic()
    # 然后是发送邮件
    mail_pre()
    send_listing()
    send_ribao()
    # 然后是微信通报
    system('taskkill /F /IM vpnagent.exe')  # 关闭VPN
    wx_report()
    # 收尾工作
    remove(store_pic)
    remove(agent_pic)
    remove(English_ribao)
    print(">>>文件删除成功!")
    xl.quit()
    endtime = datetime.now()
    total_time = (endtime - starttime).seconds
    print(">>>日报全部完成,总共耗时{}秒!".format(total_time))
    for i in range(3):
        print('>>>程序将在{}秒后关闭!'.format(3 - i))
        sleep(1)

Excel里几个VBA的代码如下:

Sub 数据添加刷新宏()

    '先刷新一次数据
    ActiveWorkbook.RefreshAll

    Path = Application.ThisWorkbook.Path
    '获得上级路径
    Path_up = Mid(Path, 1, InStrRev(Path, "\"))
    Path_pipei = Path_up & "数据\数据说明与匹配公式.xlsx"
    Path_ribao = Path & "\日报模板(会用宏的可以用用).xlsm"
    Workbooks.Open (Path_pipei)

    '新部门添加
    new_agent_maxrow = Application.Workbooks("!源数据(每日刷新).xlsm").Sheets("新增门店").UsedRange.Rows.Count
    old_agent_maxrow = Application.Workbooks("数据说明与匹配公式.xlsx").Sheets("部门匹配表").UsedRange.Rows.Count
    If Application.Workbooks("!源数据(每日刷新).xlsm").Sheets("新增门店").Range("A2").Value <> "" Then Workbooks("!源数据(每日刷新).xlsm").Sheets("新增门店").Range("A2:E" & new_agent_maxrow).Copy Workbooks("数据说明与匹配公式.xlsx").Sheets("部门匹配表").Range("A" & (old_agent_maxrow + 1))

    '新移动套餐添加
    new_cdma_maxrow = Application.Workbooks("!源数据(每日刷新).xlsm").Sheets("新增移动套餐").UsedRange.Rows.Count
    old_cdma_maxrow = Application.Workbooks("数据说明与匹配公式.xlsx").Sheets("套餐匹配表").Range("A65536").End(xlUp).Row
    If Application.Workbooks("!源数据(每日刷新).xlsm").Sheets("新增移动套餐").Range("A2").Value <> "" Then Workbooks("!源数据(每日刷新).xlsm").Sheets("新增移动套餐").Range("A2:A" & new_cdma_maxrow).Copy Workbooks("数据说明与匹配公式.xlsx").Sheets("套餐匹配表").Range("A" & (old_cdma_maxrow + 1))

    '新宽带套餐添加
    new_kd_maxrow = Application.Workbooks("!源数据(每日刷新).xlsm").Sheets("新增宽带套餐").UsedRange.Rows.Count
    old_kd_maxrow = Application.Workbooks("数据说明与匹配公式.xlsx").Sheets("套餐匹配表").Range("F65536").End(xlUp).Row
    If Application.Workbooks("!源数据(每日刷新).xlsm").Sheets("新增宽带套餐").Range("A2").Value <> "" Then Workbooks("!源数据(每日刷新).xlsm").Sheets("新增宽带套餐").Range("A2:A" & new_kd_maxrow).Copy Workbooks("数据说明与匹配公式.xlsx").Sheets("套餐匹配表").Range("F" & (old_kd_maxrow + 1))

    '关闭并保存“数据说明与匹配公式”
    Application.Workbooks("数据说明与匹配公式.xlsx").Close (True)
    
    '重新刷新一次
    If Application.Workbooks("!源数据(每日刷新).xlsm").Sheets("新增门店").Range("A2").Value <> "" Then ActiveWorkbook.RefreshAll
    
    '判断是否有报表内缺的门店,如果有的话就根据渠道在日报中增加
    que_agent_maxrow = Application.Workbooks("!源数据(每日刷新).xlsm").Sheets("报表内缺门店").UsedRange.Rows.Count
'    MsgBox (TypeName(que_agent_maxrow))
    If que_agent_maxrow = 2 And Application.Workbooks("!源数据(每日刷新).xlsm").Sheets("报表内缺门店").Range("A2").Value <> "" Then Call get_one_new_store
    If que_agent_maxrow > 2 Then Call get_more_new_store(que_agent_maxrow)
    
    '重新刷新一次
    If Application.Workbooks("!源数据(每日刷新).xlsm").Sheets("报表内缺门店").Range("A2").Value <> "" Then ActiveWorkbook.RefreshAll
    
End Sub

get_one_new_store() 和get_more_new_store(que_agent_maxrow)的代码如下:

Sub get_one_new_store()

    Dim store_name As String
    Dim qdname As String

    store_name = Application.Workbooks("!源数据(每日刷新).xlsm").Sheets("报表内缺门店").Range("B2").Value
    qdname = Application.Workbooks("!源数据(每日刷新).xlsm").Sheets("报表内缺门店").Range("A2").Value
    
    Path = Application.ThisWorkbook.Path
    Path_ribao = Path & "\日报模板(会用宏的可以用用).xlsm"
    Workbooks.Open (Path_ribao)
    
    Call get_new_qdstore(store_name, qdname)
    
    Application.Workbooks("日报模板(会用宏的可以用用).xlsm").Close (True)

End Sub
Sub get_more_new_store(que_agent_maxrow)
    
    maxrow = que_agent_maxrow
    Dim store_name As String
    Dim qdname As String
    Path = Application.ThisWorkbook.Path
    Path_ribao = Path & "\日报模板(会用宏的可以用用).xlsm"
    'MsgBox (maxrow)
    Workbooks.Open (Path_ribao)
    For i = 2 To maxrow
        store_name = Application.Workbooks("!源数据(每日刷新).xlsm").Sheets("报表内缺门店").Range("B" & i).Value
        'MsgBox (store_name)
        qdname = Application.Workbooks("!源数据(每日刷新).xlsm").Sheets("报表内缺门店").Range("A" & i).Value
        'MsgBox (qdname)
        Call get_new_qdstore(store_name, qdname)
    Next
    
    Application.Workbooks("日报模板(会用宏的可以用用).xlsm").Close (True)

End Sub

get_new_qdstore的代码:

Public Sub get_new_qdstore(store_name As String, qdname As String)
    '判断是哪个渠道的
    If qdname = "开放渠道" Then
    find_qd = "开放新增模板"
    ElseIf qdname = "中小渠道" Then
    find_qd = "中小新增模板"
    ElseIf qdname = "专营渠道" Then
    find_qd = "专营新增模板"
    End If
    
    '获得最大列
    Sheets("门店维度").Select
    Set last_column = Rows(3).Find("last", LookAt:=xlWhole)
    max_column_num = last_column.Column - 1
    get_max_column = Split(Range("A1")(1, max_column_num).Address, "$")(1)

    '根据该门店对应的渠道细分并插入
    Set Cell_qd = Columns("E").Find(find_qd, LookAt:=xlWhole)
    qd_row = Cell_qd.Row
    next_row = qd_row + 1
    Cell_qd.Select
    Selection.EntireRow.Insert , CopyOrigin:=xlFormatFromLeftOrAbove
    Range("C" & next_row & ":" & get_max_column & next_row).Select
    Selection.Copy
    Range("C" & qd_row).Select
    ActiveSheet.Paste
    Range("E" & qd_row).Value = store_name
    
End Sub

日报宏:

Sub 日报宏()
'获得昨天的标准日期(1018这种格式)
yesterday = DateAdd("d", -1, Now)
yesterday_format = Format(yesterday, "mmdd") & ".xlsx"
Path = Application.ThisWorkbook.Path
'增加一段代码,强制必须刷新
ActiveWorkbook.UpdateLink Name:= _
        Path & "\!源数据(每日刷新).xlsm", Type:=xlExcelLinks
Sheets("门店维度").Select
    Cells.Select
    Range("A2").Activate
    ActiveWorkbook.BreakLink Name:= _
        Path & "\!源数据(每日刷新).xlsm", Type:=xlExcelLinks
    Selection.Replace What:="#N/A", Replacement:="0", LookAt:=xlPart, _
        SearchOrder:=xlByRows, MatchCase:=False, SearchFormat:=False, _
        ReplaceFormat:=False
    Sheets("门店通报").Select
    Range("A1:K1").Select
    Selection.Copy
    Range("A2:K2").Select
    Selection.PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks _
        :=False, Transpose:=False
    Application.CutCopyMode = False
    ActiveWorkbook.SaveAs Filename:= _
        Path & "\【基础经营-实体1】:“乘风破浪”百日冲刺报表" & yesterday_format, _
        FileFormat:=xlOpenXMLWorkbook, CreateBackup:=False
End Sub

猜你喜欢

转载自blog.csdn.net/weixin_42029733/article/details/84099990