# -*- coding: utf-8 -*-
import os
import cx_Oracle as cx
import pandas as pd
import datetime as dt
import warnings
import time
from threading import Thread
import schedule
from openpyxl import load_workbook
from openpyxl.utils.dataframe import dataframe_to_rows
import requests
import base64
import hashlib
from PIL import ImageGrab
import win32com.client as win32
import pythoncom
warnings.filterwarnings('ignore')
class Wechat:
def __init__(self, secret):
self.secret = secret
def access_token(self):
"""获取企业微信access_token"""
url = f'https://qyapi.weixin.qq.com/cgi-bin/gettoken?corpid=wwed5e7f3fd1a3a553&corpsecret={self.secret}'
response = requests.get(url).json()
return response['access_token']
def oracle_connect(sql):
"""Oracle数据库连接查询"""
con = cx.connect("admin/xxb20140415@192.168.3.16:1521/zzjdata")
cursor = con.cursor()
cursor.execute(sql)
column_s = [col[0] for col in cursor.description]
data = cursor.fetchall()
cursor.close()
con.close()
return data, column_s
def generate_g3_monthly_sql():
"""生成月度G3阶段销售数据查询SQL"""
sql = """
------阶段销售查询表(按门店)(月度)
with hzxs as (select a.subbh,a.hedgehh,a.sl,a.lsh,a.jshj,a.ml,a.hh,a.ph1_xq,a.posguid,a.xsr from subfhd a left join gl_custom b on a.subbh=b.tjbh where a.kdrq between TRUNC(SYSDATE-1,'MONTH') and TRUNC(SYSDATE-1) and nvl(a.bz,' ')<>'会员礼品成本调整单' and nvl(a.bz,' ')<>'¥' and nvl(a.bm,' ')<>'积分兑换' and b.tj_tag<>'40'),
abc as (select b.tjbh,f.hh,a.PRODUCTTYPE,a.PRODUCTSUBTYPE,a.FEETYPE1,a.productid,sum(a.amount) jshj from abc_feedetail a
left join gl_custom b on a.CLINICID=b.C_ABCID left join yw_kck f on a.productid=f.c_abcgoodsid
where to_date(substr(a.created,1,10),'yyyy-mm-dd') between TRUNC(SYSDATE-1,'MONTH') and TRUNC(SYSDATE-1) group by b.tjbh,f.hh,a.PRODUCTTYPE,a.PRODUCTSUBTYPE,a.FEETYPE1,a.productid),
xs as (select subbh,sum(jshj) jshj,sum(ml) ml,count(distinct lsh) kds from hzxs group by subbh
union
select a.tjbh,nvl(a.jshj,0)-nvl(d.jshj,0) jshj,nvl(c.ml,0)+nvl(b.ml,0) ml,a.kds
from (select b.tjbh,sum(a.amount) jshj,count(distinct TRANSACTIONID) kds from abc_feebill a
left join gl_custom b on a.CLINICID=b.C_ABCID where to_date(substr(a.created,1,10),'yyyy-mm-dd') between TRUNC(SYSDATE-1,'MONTH') and TRUNC(SYSDATE-1) group by b.tjbh) a
left join (select c.tjbh,sum(case when a.action='退药' then -a.saleprice else a.saleprice end)+sum(a.costprice) ml from ABC_INOUTSTOCK a
left join gl_custom c on a.clinicid=c.c_abcid where a.action in ('发药','退药') and to_date(substr(a.fdate,1,10),'yyyy-mm-dd') between TRUNC(SYSDATE-1,'MONTH') and TRUNC(SYSDATE-1) group by c.tjbh) c on a.tjbh=c.tjbh
left join (select tjbh,sum(jshj) ml from abc where producttype not in ('1','2','7') and productid not in ('00000000000000000000000000000007','00000000000000000000000000000003','00000000000000000000000000000004','00000000000000000000000000000008',
'00000000000000000000000000000010') group by tjbh) b on a.tjbh=b.tjbh
left join (select tjbh,sum(jshj) jshj from abc where FEETYPE1 like '%充值%' group by tjbh) d on a.tjbh=d.tjbh ),
zyy as (select a.subbh,sum(a.jshj) jshj from hzxs a inner join yw_kck b on a.hedgehh=b.hh left join gl_ryk c on a.xsr=c.dh where b.fzflsx1='08'group by a.subbh
union
select tjbh,sum(jshj) jshj from abc where FEETYPE1<>'西药' and FEETYPE1<>'中成药'and FEETYPE1<>'卡项充值本金' and FEETYPE1<>'会员充值本金' group by tjbh ),
--zyml as (select subbh,abs(sum(ml)) ml from hzxs where ml<0 and sl>0 and hedgehh in (select hh from c_zkmdbmlpzmx) group by subbh),
rw as (select a.subbh,round(nvl(a.yxse*(b.xsxs/100),0),0) xsrw,round(a.ymle*(d.xsxs/100),0) mlrw,round(nvl(a.ybbxse*(c.xsxs/100),0),0) tyrw
from (select subbh,yxse,ybbxse,ymle from c_mdjyys where nd='0' and yf='0') a
left join (select a.rwlb,sum(b.xsxs) xsxs from C_ZKMTXSSCB a left join C_ZKMTXSSCBDETAIL b on a.guid=b.mainguid
where a.rwlb='绩效销售额任务' and trunc(b.ksrq) between TRUNC(SYSDATE-1,'MONTH') and TRUNC(SYSDATE-1) group by a.rwlb) b on 1=1
left join (select a.rwlb,sum(b.xsxs) xsxs from C_ZKMTXSSCB a left join C_ZKMTXSSCBDETAIL b on a.guid=b.mainguid
where a.rwlb='月毛利额任务' and trunc(b.ksrq) between TRUNC(SYSDATE-1,'MONTH') and TRUNC(SYSDATE-1) group by a.rwlb) d on 1=1
left join (select a.rwlb,sum(b.xsxs) xsxs from C_ZKMTXSSCB a left join C_ZKMTXSSCBDETAIL b on a.guid=b.mainguid
where a.rwlb='特药任务' and trunc(b.ksrq) between TRUNC(SYSDATE-1,'MONTH') and TRUNC(SYSDATE-1) group by a.rwlb) c on 1=1),
zyrw as (select a.subbh,a.pzlb,a.rwje*(b.xsxs/100) rwje
from (select * from c_zbjlrwzk where nd='0' and yf='0' and pzlb='中药任务') a left join (select sum(b.xsxs) xsxs from C_ZKMTXSSCB a left join C_ZKMTXSSCBDETAIL b on a.guid=b.mainguid where a.rwlb='中药任务' and trunc(b.ksrq) between TRUNC(SYSDATE-1,'MONTH') and TRUNC(SYSDATE-1)) b on 1=1),
nfrw as (select a.subbh,a.pzlb,a.rwje*(b.xsxs/100) rwje
from (select * from c_zbjlrwzk where nd='0' and yf='0' and pzlb='膏方任务') a left join (select sum(b.xsxs) xsxs from C_ZKMTXSSCB a left join C_ZKMTXSSCBDETAIL b on a.guid=b.mainguid where a.rwlb='膏方任务' and trunc(b.ksrq) between TRUNC(SYSDATE-1,'MONTH') and TRUNC(SYSDATE-1)) b on 1=1),
gfrw as (select a.subbh,a.pzlb,a.rwje*(b.xsxs/100) rwje
from (select * from c_zbjlrwzk where nd='0' and yf='0' and pzlb='内方基础任务') a left join (select sum(b.xsxs) xsxs from C_ZKMTXSSCB a left join C_ZKMTXSSCBDETAIL b on a.guid=b.mainguid where a.rwlb='内方任务' and trunc(b.ksrq) between TRUNC(SYSDATE-1,'MONTH') and TRUNC(SYSDATE-1)) b on 1=1),
zdpzrw as (select a.subbh,a.pzlb,a.rwje*(b.xsxs/100) rwje
from (select * from c_zbjlrwzk where nd='0' and yf='0' and pzlb='重点品种任务') a left join (select sum(b.xsxs) xsxs from C_ZKMTXSSCB a left join C_ZKMTXSSCBDETAIL b on a.guid=b.mainguid where a.rwlb='重点品种任务' and trunc(b.ksrq) between TRUNC(SYSDATE-1,'MONTH') and TRUNC(SYSDATE-1)) b on 1=1),
zdpz as (select b.subbh,sum(b.jshj) jshj from (select a.code,b.hh,b.sx from organization a left join spjxlbz b on a.SPJXFLZ=b.lbz where b.sx='A+' OR b.sx='B' OR b.sx='A'OR b.sx='D+') a
inner join (select subbh,hedgehh,jshj,lsh from hzxs union all select tjbh,hh,jshj,' ' from abc ) b on a.code=b.subbh and a.hh=b.hedgehh group by b.subbh),
gfxs as (select a.subbh,sum(a.jshj) jshj from hzxs a left join yw_kck b on a.hedgehh=b.hh where nvl(a.posguid,' ')='10001' or b.fzflsx2='08042' group by a.subbh),
xsfl as (select a.*,c.sx from (select subbh,hedgehh,jshj,ml,lsh from hzxs union all select tjbh,hh,jshj,0,' ' from abc ) a left join(select * from spjxlbz where lbz='1') c on a.hedgehh=c.hh)
select a.c_mdfq 大区,a.c_mdfq1 地区,a.tjbh 门店编号,a.mc 门店名称,nvl(b.xsrw,0)+nvl(b.tyrw,0) 总销售任务,c.jshj 总销售额,b.mlrw 毛利任务,nvl(c.ml,0)-nvl(y6.ml,0) 毛利额,k.rwje 重点品种任务,nvl(e.jshj,0)+nvl(i.jshj,0) 重点品种销售,
j.jshj 中医药销售,to_char(a.c_kykdrq,'yyyy-mm-dd') 开业日期,case when t1.SPJXFLZ='1' then '郑州市' when t1.SPJXFLZ='2' then '外地市' when t1.SPJXFLZ='3' then '县乡镇' else ' ' end 地域类型,round((nvl(f.rwje,0)+nvl(g.rwje,0)+nvl(h.rwje,0)),2) 中医药任务,
case when nvl(b.mlrw,0)<>0 then round( (nvl(c.ml,0)-nvl(y6.ml,0))*100/b.mlrw,2) else 0 end 毛利进度,nvl(x.jshj,0) 线下销售额,nvl(x.kds,0) 线下客单,nvl(c.kds,0) 总客流,
case when nvl(k.rwje,0)<>0 then round((nvl(e.jshj,0)+nvl(i.jshj,0))*100/k.rwje,2) else 0 end 重点品种进度,case when nvl(b.tyrw,0)=0 then 0 else nvl(y6.jshj,0) end 特药销售,b.tyrw 特药任务,
case when nvl(b.tyrw,0)<>0 then round((case when nvl(b.tyrw,0)=0 then 0 else nvl(y6.jshj,0) end)*100/b.tyrw,2) else 0 end 特药完成进度,
nvl(b.xsrw,0) 非特药任务, case when nvl(b.tyrw,0)=0 then nvl(c.jshj,0) else nvl(c.jshj,0)-nvl(y6.jshj,0) end 非特药销售,case when nvl(b.xsrw,0)<>0 then round((case when nvl(b.tyrw,0)=0 then nvl(c.jshj,0) else nvl(c.jshj,0)-nvl(y6.jshj,0) end)*100/nvl(b.xsrw,0),2) else 0 end 非特药完成进度
from gl_custom a
left join rw b on a.tjbh=b.subbh
left join xs c on a.tjbh=c.subbh
left join zyrw f on a.tjbh=f.subbh
left join nfrw g on a.tjbh=g.subbh
left join gfrw h on a.tjbh=h.subbh
left join zyy j on a.tjbh=j.subbh
left join zdpz e on a.tjbh=e.subbh
left join gfxs i on a.tjbh=i.subbh
left join zdpzrw k on a.tjbh=k.subbh
left join organization t1 on a.tjbh=t1.code
left join (select subbh,sum(jshj) jshj,sum(ml) ml,count(distinct lsh) kds from hzxs where nvl(posguid,' ')<>'10000' group by subbh) x on a.tjbh=x.subbh
left join (select subbh,sum(jshj) jshj from xsfl where sx = 'A+' group by subbh) y1 on a.tjbh=y1.subbh
left join (select subbh,sum(jshj) jshj from xsfl where sx = 'C+' group by subbh) y2 on a.tjbh=y2.subbh
left join (select subbh,sum(jshj) jshj from xsfl where sx = 'A' group by subbh) y3 on a.tjbh=y3.subbh
left join (select subbh,sum(jshj) jshj from xsfl where sx = 'B' group by subbh) y4 on a.tjbh=y4.subbh
left join (select subbh,sum(jshj) jshj from xsfl where sx = 'C' OR sx = 'C ' group by subbh) y5 on a.tjbh=y5.subbh
left join (select subbh,sum(jshj) jshj,sum(ml) ml from xsfl where sx = 'D' group by subbh) y6 on a.tjbh=y6.subbh
left join (select subbh,sum(jshj) jshj from xsfl where sx = 'E' group by subbh) y7 on a.tjbh=y7.subbh
left join (select subbh,sum(jshj) jshj from xsfl where sx = 'F' OR sx = 'f' group by subbh) y8 on a.tjbh=y8.subbh
where a.c_mdfq is not null and (a.tj_tag='14' or a.tj_tag='40') --and a.mc like '%仲景生活%'
and nvl(a.C_STORETYPE, '0') = '1'
"""
return sql
def generate_g3_weekly_sql():
"""生成月度G3周度销售数据查询SQL"""
sql = """
---------仲景生活周度数据通报(月度)
select b.TJBH as 门店编号,b.mc as 门店名称,TRUNC(a.kdrq) as 日期,d.name as 零售小类,a.hh as 货号,c.pm as 品名,sum(a.SL) as 数量 ,sum(a.jshj) as 销售额,case when nvl(sum(SL),0)<>0 then round(sum(cbe) / sum(SL), 2) else 0 end as 成本价, sum(a.ML) as 毛利,
case when nvl(sum(a.JSHJ),0)<>0 then round(sum(ml) / sum(JSHJ), 2) else 0 end as 毛利率,c.hyj as 会员价,c.lsj as 零售价
from subfhd a
left join gl_custom b on a.subbh=b.tjbh
left join yw_kck c on a.hh = c.HH
left join dataitem d on c.FZFLSX3 = d.CODE
where a.kdrq between TRUNC(SYSDATE-1,'MONTH') and TRUNC(SYSDATE-1) and nvl(a.bz,' ')<>'会员礼品成本调整单' and nvl(a.bz,' ')<>'¥' and nvl(a.bm,' ')<>'积分兑换' and b.tj_tag<>'40' and nvl(b.C_STORETYPE, '0') = '1'
group by b.TJBH, b.mc, TRUNC(a.kdrq), d.name, a.hh, c.pm, c.lsj, c.hyj order by b.tjbh, TRUNC(a.kdrq)
"""
return sql
def generate_g3_daily_monthly_sql():
"""生成月度G3每日销售数据查询SQL"""
sql = """
------门店每日总销售额(月度)
select a.kdrq 日期,a.subbh 门店编码,a.mc 门店名称,a.jshj 价税合计,nvl(a.jshj-dx.dxje,a.jshj) 总销售额,round((nvl(a.jshj,0)-nvl(c.fkje,0)-nvl(d.fkje,0)-nvl(f.fkje,0)-nvl(g.fkje,0)-nvl(xs.fkje,0))/j.xxkl,2) 线下客单价,nvl(a.jshj,0)-nvl(c.fkje,0)-nvl(d.fkje,0)-nvl(f.fkje,0)-nvl(g.fkje,0)-nvl(xs.fkje,0) 线下价税合计,
(case when nvl(a.jshj,0)=0 then 0 else round(a.hsmle/a.jshj,4) end) 毛利率,sum(a.khs) 客户数,sum(a.hykds) 会员客单数,sum((case when nvl(a.khs,0)=0 then 0 else round(nvl(a.jshj,0)/a.khs,4) end)) 客单价,round((nvl(c.fkje,0)+nvl(d.fkje,0)+nvl(f.fkje,0)+nvl(g.fkje,0)+nvl(xs.fkje,0))/NULLIF(nvl(a.jshj, 0), 0)*100,2) 线上销售额占比,
a.hsmle 毛利额,a.hyxse 会员销售额,dx.dxje 积分抵现金额,round((nvl(c.fkje,0)+nvl(d.fkje,0)+nvl(f.fkje,0)+nvl(g.fkje,0)+nvl(xs.fkje,0))/i.xskl,2) 线上客单价,nvl(c.fkje,0)+nvl(d.fkje,0)+nvl(f.fkje,0)+nvl(g.fkje,0)+nvl(xs.fkje,0) 线上价税合计,
(case when nvl(a.jshj,0)=0 then 0 else 100*round(nvl(a.hyxse,0)/a.jshj,4) end) 会员销售占比,b.hyqb 会员钱包销售额,xs.fkje 惜食小程序,d.fkje 饿了么,c.fkje 美团外卖,f.fkje 美团点评,round((nvl(a.jshj,0)-nvl(c.fkje,0)-nvl(d.fkje,0)-nvl(f.fkje,0)-nvl(g.fkje,0)-nvl(xs.fkje,0))/NULLIF(nvl(a.jshj, 0), 0)*100,2) 线下销售额占比,
h.fkje 收钱吧,g.fkje 抖音团购,i.xskl 线上客单数,j.xxkl 线下客单数
from (
select a.kdrq kdrq,b.mc mc,a.subbh subbh,ROUND(sum(a.jshj),2) jshj,sum(c.sj1) sj1,
count(distinct a.lsh) as khs,count(distinct case when nvl(a.YHKH,' ')<>' ' then a.lsh else ' ' end) hykds,
sum(case when nvl(a.yhkh,' ')<>' ' then a.jshj else 0 end) hyxse,
sum(a.ml) hsmle,sum(a.ml) ml
from subfhd a
right join (select * from gl_custom where nvl(c_storetype,0)=1) b on a.subbh=b.tjbh
right join (select * from yw_kck ) c on a.hh=c.hh
where a.Kdrq between TRUNC(SYSDATE-1,'MONTH') and TRUNC(SYSDATE-1) and nvl(a.bz,' ')<>'会员礼品成本调整单' and nvl(a.bz,' ')<>'¥' group by a.subbh,a.kdrq,b.mc
) a
left join (select kdrq,subbh,sum(jshj) dxje from subfhd where kdrq between TRUNC(SYSDATE-1,'MONTH') and TRUNC(SYSDATE-1) and hh='JFDX' group by subbh, kdrq ) dx on (a.subbh=dx.subbh and a.kdrq=dx.kdrq)
left join (
select a.KDRQ,a.subbh,sum(a.fkje) hyqb from subdfkfs a
inner join (select tjbh from gl_custom where nvl(c_storetype,0)=1) b on a.subbh=b.tjbh
where a.fkfsid='hyqb' and KDRQ between TRUNC(SYSDATE-1,'MONTH') and TRUNC(SYSDATE-1)
group by a.subbh,a.KDRQ
) b on (a.subbh=b.subbh and a.kdrq=b.kdrq)
left join (select SUBBH, KDRQ,sum(fkje) fkje from subdfkfs where kDRQ between TRUNC(SYSDATE-1,'MONTH') and TRUNC(SYSDATE-1) and fkfsid in ('SY-MTWM')
group by SUBBH, KDRQ) c on a.subbh=c.subbh and a.kdrq=c.kdrq
left join (select SUBBH, KDRQ,sum(fkje) fkje from subdfkfs where kDRQ between TRUNC(SYSDATE-1,'MONTH') and TRUNC(SYSDATE-1) and fkfsid in ('SYELM')
group by SUBBH, KDRQ) d on a.subbh=d.subbh and a.kdrq=d.kdrq
left join (select SUBBH, KDRQ,sum(fkje) fkje from subdfkfs where kDRQ between TRUNC(SYSDATE-1,'MONTH') and TRUNC(SYSDATE-1) and fkfsid in ('197')
group by SUBBH, KDRQ) f on a.subbh=f.subbh and a.kdrq=f.kdrq
left join (select SUBBH, KDRQ,sum(fkje) fkje from subdfkfs where kDRQ between TRUNC(SYSDATE-1,'MONTH') and TRUNC(SYSDATE-1) and fkfsid in ('801')
group by SUBBH, KDRQ) g on a.subbh=g.subbh and a.kdrq=g.kdrq
left join (select SUBBH, KDRQ,sum(fkje) fkje from subdfkfs where kDRQ between TRUNC(SYSDATE-1,'MONTH') and TRUNC(SYSDATE-1) and fkfsid in ('806')
group by SUBBH, KDRQ) h on a.subbh=h.subbh and a.kdrq=h.kdrq
left join (select SUBBH, KDRQ,sum(fkje) fkje from subdfkfs where kDRQ between TRUNC(SYSDATE-1,'MONTH') and TRUNC(SYSDATE-1) and fkfsid in ('215')
group by SUBBH, KDRQ) xs on a.subbh=xs.subbh and a.kdrq=xs.kdrq
left join (select SUBBH, KDRQ,count(distinct xhlsh) xskl from subdfkfs where kDRQ between TRUNC(SYSDATE-1,'MONTH') and TRUNC(SYSDATE-1) and fkfsid in ('SY-MTWM','SYELM','197','801','808','215')
group by SUBBH, KDRQ) i on a.subbh=i.subbh and a.kdrq=i.kdrq
left join (select SUBBH, KDRQ,count(distinct xhlsh) xxkl from subdfkfs where kDRQ between TRUNC(SYSDATE-1,'MONTH') and TRUNC(SYSDATE-1) and fkfsid not in ('SY-MTWM','SYELM','197','801','808','215')
group by SUBBH, KDRQ) j on a.subbh=j.subbh and a.kdrq=j.kdrq
group by a.subbh, a.mc, a.kdrq, a.jshj, a.hsmle,a.ml,b.hyqb,a.hyxse, (case when nvl(a.jshj,0)=0 then 0 else round(a.hsmle/a.jshj,4) end), dx.dxje, nvl(a.jshj-dx.dxje,a.jshj), (case when nvl(a.jshj,0)=0 then 0 else 100*round(nvl(a.hyxse,0)/a.jshj,4) end),c.fkje,d.fkje,f.fkje,g.fkje,h.fkje,xs.fkje,nvl(a.jshj,0)-nvl(c.fkje,0)-nvl(d.fkje,0)-nvl(f.fkje,0)-nvl(g.fkje,0)-nvl(xs.fkje,0)
,nvl(c.fkje,0)+nvl(d.fkje,0)+nvl(f.fkje,0)+nvl(g.fkje,0)+nvl(xs.fkje,0) ,round((nvl(c.fkje,0)+nvl(d.fkje,0)+nvl(f.fkje,0)+nvl(g.fkje,0)+nvl(xs.fkje,0))/NULLIF(nvl(a.jshj, 0), 0)*100,2)
,round((nvl(a.jshj,0)-nvl(c.fkje,0)-nvl(d.fkje,0)-nvl(f.fkje,0)-nvl(g.fkje,0)-nvl(xs.fkje,0))/NULLIF(nvl(a.jshj, 0), 0)*100,2)
,round((nvl(c.fkje,0)+nvl(d.fkje,0)+nvl(f.fkje,0)+nvl(g.fkje,0)+nvl(xs.fkje,0))/i.xskl,2) ,round((nvl(a.jshj,0)-nvl(c.fkje,0)-nvl(d.fkje,0)-nvl(f.fkje,0)-nvl(g.fkje,0)-nvl(xs.fkje,0))/j.xxkl,2),i.xskl,j.xxkl
order by a.subbh
"""
return sql
def generate_g3_daily_yesterday_sql():
"""生成昨日G3每日销售数据查询SQL"""
sql = """
------门店每日总销售额(昨日)
select a.kdrq 日期,a.subbh 门店编码,a.mc 门店名称,a.jshj 价税合计,nvl(a.jshj-dx.dxje,a.jshj) 总销售额,round((nvl(a.jshj,0)-nvl(c.fkje,0)-nvl(d.fkje,0)-nvl(f.fkje,0)-nvl(g.fkje,0)-nvl(xs.fkje,0))/j.xxkl,2) 线下客单价,nvl(a.jshj,0)-nvl(c.fkje,0)-nvl(d.fkje,0)-nvl(f.fkje,0)-nvl(g.fkje,0)-nvl(xs.fkje,0) 线下价税合计,
(case when nvl(a.jshj,0)=0 then 0 else round(a.hsmle/a.jshj,4) end) 毛利率,sum(a.khs) 客户数,sum(a.hykds) 会员客单数,sum((case when nvl(a.khs,0)=0 then 0 else round(nvl(a.jshj,0)/a.khs,4) end)) 客单价,round((nvl(c.fkje,0)+nvl(d.fkje,0)+nvl(f.fkje,0)+nvl(g.fkje,0)+nvl(xs.fkje,0))/NULLIF(nvl(a.jshj, 0), 0)*100,2) 线上销售额占比,
a.hsmle 毛利额,a.hyxse 会员销售额,dx.dxje 积分抵现金额,round((nvl(c.fkje,0)+nvl(d.fkje,0)+nvl(f.fkje,0)+nvl(g.fkje,0)+nvl(xs.fkje,0))/i.xskl,2) 线上客单价,nvl(c.fkje,0)+nvl(d.fkje,0)+nvl(f.fkje,0)+nvl(g.fkje,0)+nvl(xs.fkje,0) 线上价税合计,
(case when nvl(a.jshj,0)=0 then 0 else 100*round(nvl(a.hyxse,0)/a.jshj,4) end) 会员销售占比,b.hyqb 会员钱包销售额,xs.fkje 惜食小程序,d.fkje 饿了么,c.fkje 美团外卖,f.fkje 美团点评,round((nvl(a.jshj,0)-nvl(c.fkje,0)-nvl(d.fkje,0)-nvl(f.fkje,0)-nvl(g.fkje,0)-nvl(xs.fkje,0))/NULLIF(nvl(a.jshj, 0), 0)*100,2) 线下销售额占比,
h.fkje 收钱吧,g.fkje 抖音团购,i.xskl 线上客单数,j.xxkl 线下客单数
from (
select a.kdrq kdrq,b.mc mc,a.subbh subbh,ROUND(sum(a.jshj),2) jshj,sum(c.sj1) sj1,
count(distinct a.lsh) as khs,count(distinct case when nvl(a.YHKH,' ')<>' ' then a.lsh else ' ' end) hykds,
sum(case when nvl(a.yhkh,' ')<>' ' then a.jshj else 0 end) hyxse,
sum(a.ml) hsmle,sum(a.ml) ml
from subfhd a
right join (select * from gl_custom where nvl(c_storetype,0)=1) b on a.subbh=b.tjbh
right join (select * from yw_kck ) c on a.hh=c.hh
where a.Kdrq = TRUNC(SYSDATE-1) and nvl(a.bz,' ')<>'会员礼品成本调整单' and nvl(a.bz,' ')<>'¥' group by a.subbh,a.kdrq,b.mc
) a
left join (select kdrq,subbh,sum(jshj) dxje from subfhd where kdrq = TRUNC(SYSDATE-1) and hh='JFDX' group by subbh, kdrq ) dx on (a.subbh=dx.subbh and a.kdrq=dx.kdrq)
left join (
select a.KDRQ,a.subbh,sum(a.fkje) hyqb from subdfkfs a
inner join (select tjbh from gl_custom where nvl(c_storetype,0)=1) b on a.subbh=b.tjbh
where a.fkfsid='hyqb' and KDRQ = TRUNC(SYSDATE-1)
group by a.subbh,a.KDRQ
) b on (a.subbh=b.subbh and a.kdrq=b.kdrq)
left join (select SUBBH, KDRQ,sum(fkje) fkje from subdfkfs where kDRQ = TRUNC(SYSDATE-1) and fkfsid in ('SY-MTWM')
group by SUBBH, KDRQ) c on a.subbh=c.subbh and a.kdrq=c.kdrq
left join (select SUBBH, KDRQ,sum(fkje) fkje from subdfkfs where kDRQ = TRUNC(SYSDATE-1) and fkfsid in ('SYELM')
group by SUBBH, KDRQ) d on a.subbh=d.subbh and a.kdrq=d.kdrq
left join (select SUBBH, KDRQ,sum(fkje) fkje from subdfkfs where kDRQ = TRUNC(SYSDATE-1) and fkfsid in ('197')
group by SUBBH, KDRQ) f on a.subbh=f.subbh and a.kdrq=f.kdrq
left join (select SUBBH, KDRQ,sum(fkje) fkje from subdfkfs where kDRQ = TRUNC(SYSDATE-1) and fkfsid in ('801')
group by SUBBH, KDRQ) g on a.subbh=g.subbh and a.kdrq=g.kdrq
left join (select SUBBH, KDRQ,sum(fkje) fkje from subdfkfs where kDRQ = TRUNC(SYSDATE-1) and fkfsid in ('806')
group by SUBBH, KDRQ) h on a.subbh=h.subbh and a.kdrq=h.kdrq
left join (select SUBBH, KDRQ,sum(fkje) fkje from subdfkfs where kDRQ = TRUNC(SYSDATE-1) and fkfsid in ('215')
group by SUBBH, KDRQ) xs on a.subbh=xs.subbh and a.kdrq=xs.kdrq
left join (select SUBBH, KDRQ,count(distinct xhlsh) xskl from subdfkfs where kDRQ = TRUNC(SYSDATE-1) and fkfsid in ('SY-MTWM','SYELM','197','801','808','215')
group by SUBBH, KDRQ) i on a.subbh=i.subbh and a.kdrq=i.kdrq
left join (select SUBBH, KDRQ,count(distinct xhlsh) xxkl from subdfkfs where kDRQ = TRUNC(SYSDATE-1) and fkfsid not in ('SY-MTWM','SYELM','197','801','808','215')
group by SUBBH, KDRQ) j on a.subbh=j.subbh and a.kdrq=j.kdrq
group by a.subbh, a.mc, a.kdrq, a.jshj, a.hsmle,a.ml,b.hyqb,a.hyxse, (case when nvl(a.jshj,0)=0 then 0 else round(a.hsmle/a.jshj,4) end), dx.dxje, nvl(a.jshj-dx.dxje,a.jshj), (case when nvl(a.jshj,0)=0 then 0 else 100*round(nvl(a.hyxse,0)/a.jshj,4) end),c.fkje,d.fkje,f.fkje,g.fkje,h.fkje,xs.fkje,nvl(a.jshj,0)-nvl(c.fkje,0)-nvl(d.fkje,0)-nvl(f.fkje,0)-nvl(g.fkje,0)-nvl(xs.fkje,0)
,nvl(c.fkje,0)+nvl(d.fkje,0)+nvl(f.fkje,0)+nvl(g.fkje,0)+nvl(xs.fkje,0) ,round((nvl(c.fkje,0)+nvl(d.fkje,0)+nvl(f.fkje,0)+nvl(g.fkje,0)+nvl(xs.fkje,0))/NULLIF(nvl(a.jshj, 0), 0)*100,2)
,round((nvl(a.jshj,0)-nvl(c.fkje,0)-nvl(d.fkje,0)-nvl(f.fkje,0)-nvl(g.fkje,0)-nvl(xs.fkje,0))/NULLIF(nvl(a.jshj, 0), 0)*100,2)
,round((nvl(c.fkje,0)+nvl(d.fkje,0)+nvl(f.fkje,0)+nvl(g.fkje,0)+nvl(xs.fkje,0))/i.xskl,2) ,round((nvl(a.jshj,0)-nvl(c.fkje,0)-nvl(d.fkje,0)-nvl(f.fkje,0)-nvl(g.fkje,0)-nvl(xs.fkje,0))/j.xxkl,2),i.xskl,j.xxkl
order by a.subbh
"""
return sql
def update_excel_sheet(excel_path, sheet_name, data, columns):
"""更新Excel指定sheet的数据 - 清空整个sheet后放入数据(包括标题行)"""
try:
# 加载工作簿
wb = load_workbook(excel_path)
# 选择指定sheet
if sheet_name in wb.sheetnames:
ws = wb[sheet_name]
else:
ws = wb.create_sheet(sheet_name)
# 清空整个工作表的所有数据
ws.delete_rows(1, ws.max_row)
# 创建DataFrame(包含标题行)
df = pd.DataFrame(data, columns=columns)
# 将数据写入sheet(包括标题行)
for r_idx, row in enumerate(dataframe_to_rows(df, index=False, header=True), 1):
for c_idx, value in enumerate(row, 1):
ws.cell(row=r_idx, column=c_idx, value=value)
# 保存工作簿
wb.save(excel_path)
print(f"成功更新 {sheet_name} 工作表,共 {len(data)} 行数据")
return True
except Exception as e:
print(f"更新Excel失败: {str(e)}")
return False
def update_excel_data(excel_path):
"""更新Excel文件中的所有G3销售数据"""
try:
print("开始更新Excel数据...")
# 更新月度G3阶段数据
print("正在查询月度G3阶段数据...")
sql1 = generate_g3_monthly_sql()
data1, columns1 = oracle_connect(sql1)
if data1:
print(f"查询到月度G3阶段数据 {len(data1)} 行")
update_excel_sheet(excel_path, "月度G3阶段", data1, columns1)
else:
print("未查询到月度G3阶段数据")
# 更新月度G3周度销售数据
print("正在查询月度G3周度销售数据...")
sql2 = generate_g3_weekly_sql()
data2, columns2 = oracle_connect(sql2)
if data2:
print(f"查询到月度G3周度销售数据 {len(data2)} 行")
update_excel_sheet(excel_path, "月度G3周度销售", data2, columns2)
else:
print("未查询到月度G3周度销售数据")
# 更新月度G3每日销售数据
print("正在查询月度G3每日销售数据...")
sql3 = generate_g3_daily_monthly_sql()
data3, columns3 = oracle_connect(sql3)
if data3:
print(f"查询到月度G3每日销售数据 {len(data3)} 行")
update_excel_sheet(excel_path, "月度G3每日销售", data3, columns3)
else:
print("未查询到月度G3每日销售数据")
# 更新昨日G3每日销售数据
print("正在查询昨日G3每日销售数据...")
sql4 = generate_g3_daily_yesterday_sql()
data4, columns4 = oracle_connect(sql4)
if data4:
print(f"查询到昨日G3每日销售数据 {len(data4)} 行")
update_excel_sheet(excel_path, "昨日G3每日销售", data4, columns4)
else:
print("未查询到昨日G3每日销售数据")
print("Excel数据更新完成")
return True
except Exception as e:
print(f"更新Excel数据失败: {str(e)}")
return False
class ExcelScreenshot:
"""Excel截图类,处理COM初始化问题"""
def __init__(self):
self.excel_app = None
self.workbook = None
def initialize_com(self):
"""初始化COM对象"""
try:
pythoncom.CoInitialize()
self.excel_app = win32.gencache.EnsureDispatch('Excel.Application')
self.excel_app.Visible = True
self.excel_app.DisplayAlerts = False
return True
except Exception as e:
print(f"COM初始化失败: {str(e)}")
return False
def open_workbook(self, excel_path):
"""打开工作簿"""
try:
if not self.excel_app:
if not self.initialize_com():
return False
self.workbook = self.excel_app.Workbooks.Open(excel_path)
return True
except Exception as e:
print(f"打开工作簿失败: {str(e)}")
return False
def capture_sheet(self, sheet_name, screenshot_path):
"""截图指定工作表"""
try:
if not self.workbook:
return False
# 选择工作表
worksheet = self.workbook.Sheets(sheet_name)
self.workbook.Windows(1).Activate()
worksheet.Activate()
# 获取有数据的区域
used_range = worksheet.UsedRange
if used_range is None:
print(f"{sheet_name} 工作表没有数据")
return False
used_range.Select()
# 等待Excel刷新
time.sleep(2)
# 复制选中的区域
worksheet.Range(used_range.Address).CopyPicture(Appearance=1, Format=2)
# 从剪贴板获取图片并保存
time.sleep(1)
image = ImageGrab.grabclipboard()
if image:
image.save(screenshot_path)
return True
else:
return False
except Exception as e:
print(f"截图 {sheet_name} 失败: {str(e)}")
return False
def close(self):
"""关闭Excel应用"""
try:
if self.workbook:
self.workbook.Close(SaveChanges=False)
if self.excel_app:
self.excel_app.Quit()
pythoncom.CoUninitialize()
except Exception as e:
print(f"关闭Excel失败: {str(e)}")
def capture_excel_screenshots(excel_path):
"""截图Excel的四个sheet表有数据的区域"""
screenshot = ExcelScreenshot()
screenshot_paths = []
try:
print("开始截图Excel工作表...")
# 初始化并打开工作簿
if not screenshot.open_workbook(excel_path):
raise Exception("无法打开Excel文件")
sheet_names = ["销售", "品类", "主推品", "昨日销售"]
for sheet_name in sheet_names:
try:
print(f"正在截图 {sheet_name} 工作表...")
screenshot_path = f"D:\\仲景生活\\{sheet_name}_截图_{dt.datetime.now().strftime('%Y%m%d%H%M%S')}.png"
if screenshot.capture_sheet(sheet_name, screenshot_path):
screenshot_paths.append(screenshot_path)
print(f"成功截图 {sheet_name} 工作表,保存为: {screenshot_path}")
else:
print(f"截图失败 {sheet_name} 工作表")
except Exception as e:
print(f"截图 {sheet_name} 失败: {str(e)}")
continue
print(f"截图完成,共生成 {len(screenshot_paths)} 张截图")
return screenshot_paths
except Exception as e:
print(f"截图Excel失败: {str(e)}")
return []
finally:
screenshot.close()
def application_push_image(access_token, image_path, user_id="037565", agent_id="1000077"):
"""推送图片到企业微信应用"""
try:
# 上传图片获取media_id
with open(image_path, 'rb') as f:
files = {'media': f}
upload_url = f'https://qyapi.weixin.qq.com/cgi-bin/media/upload?access_token={access_token}&type=image'
upload_response = requests.post(upload_url, files=files).json()
if 'media_id' not in upload_response:
print(f"图片上传失败: {upload_response}")
return None
media_id = upload_response['media_id']
# 发送图片消息
send_url = f'https://qyapi.weixin.qq.com/cgi-bin/message/send?access_token={access_token}'
payload = {
"touser": user_id,
"msgtype": "image",
"agentid": agent_id,
"image": {"media_id": media_id},
"safe": 0
}
response = requests.post(send_url, json=payload).json()
return response
except Exception as e:
print(f"图片发送失败: {str(e)}")
return None
def webhook_push_image(image_path, webhook_url):
"""通过webhook推送图片到企业微信群"""
try:
# 读取图片并转换为base64
with open(image_path, 'rb') as f:
image_data = f.read()
# 上传到临时位置或直接使用base64
image_base64 = base64.b64encode(image_data).decode('utf-8')
# 构建消息内容
payload = {
"msgtype": "image",
"image": {
"base64": image_base64,
"md5": hashlib.md5(image_data).hexdigest()
}
}
response = requests.post(webhook_url, json=payload)
return response.json()
except Exception as e:
print(f"Webhook图片发送失败: {str(e)}")
return None
def send_excel_report():
"""发送Excel报表截图"""
try:
print(f"{dt.datetime.now()} - 开始执行Excel报表推送任务")
# 初始化微信
wechat = Wechat('tXNMrgcTgeV3IAqJhWB7mOe_bcKe9EtdCDze_75mGeY')
access_token = wechat.access_token()
# 群webhook地址
webhook_url = "https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=3cb06b7e-3658-4fbd-9676-54fc25fea470"
excel_path = r"D:\仲景生活\月度销售汇总.xlsx"
# 检查文件是否存在
if not os.path.exists(excel_path):
print(f"Excel文件不存在: {excel_path}")
# 创建空的Excel文件
wb = load_workbook()
wb.save(excel_path)
print("已创建新的Excel文件")
# 更新Excel数据
if not update_excel_data(excel_path):
raise Exception("Excel数据更新失败")
# 截图四个sheet表
screenshot_paths = capture_excel_screenshots(excel_path)
if not screenshot_paths:
print("Excel截图失败,尝试使用备用截图方法...")
# 备用方案:使用pyautogui截图
screenshot_paths = capture_with_pyautogui(excel_path)
if not screenshot_paths:
raise Exception("所有截图方法都失败了")
# 推送所有截图到个人
success_count_personal = 0
for image_path in screenshot_paths:
if os.path.exists(image_path):
print(f"正在推送图片到个人: {os.path.basename(image_path)}")
result = application_push_image(access_token, image_path, "037565")
if result and result.get('errcode') == 0:
success_count_personal += 1
print(f"成功发送到个人: {os.path.basename(image_path)}")
else:
print(f"发送到个人失败: {os.path.basename(image_path)} - {result}")
# 推送所有截图到群
success_count_group = 0
for image_path in screenshot_paths:
if os.path.exists(image_path):
print(f"正在推送图片到群: {os.path.basename(image_path)}")
result = webhook_push_image(image_path, webhook_url)
if result and result.get('errcode') == 0:
success_count_group += 1
print(f"成功发送到群: {os.path.basename(image_path)}")
else:
print(f"发送到群失败: {os.path.basename(image_path)} - {result}")
# 删除已发送的截图
for image_path in screenshot_paths:
if os.path.exists(image_path):
os.remove(image_path)
print(f"已删除截图文件: {os.path.basename(image_path)}")
print(f"{dt.datetime.now()} - Excel报表推送完成")
print(f"个人成功发送: {success_count_personal}/{len(screenshot_paths)}")
print(f"群成功发送: {success_count_group}/{len(screenshot_paths)}")
return success_count_personal > 0 or success_count_group > 0
except Exception as e:
print(f"{dt.datetime.now()} - Excel报表推送失败: {str(e)}")
import traceback
traceback.print_exc()
return False
def capture_with_pyautogui(excel_path):
"""备用截图方法:使用pyautogui"""
try:
import pyautogui
import subprocess
import time
# 使用Excel打开文件
subprocess.Popen([excel_path], shell=True)
time.sleep(5)
screenshot_paths = []
sheet_names = ["销售", "品类", "主推品", "昨日销售"]
for sheet_name in sheet_names:
try:
# 这里需要根据实际情况调整截图区域
screenshot_path = f"D:\\仲景生活\\{sheet_name}_截图_{dt.datetime.now().strftime('%Y%m%d%H%M%S')}.png"
# 全屏截图(需要手动调整)
screenshot = pyautogui.screenshot()
screenshot.save(screenshot_path)
screenshot_paths.append(screenshot_path)
print(f"使用pyautogui截图: {screenshot_path}")
except Exception as e:
print(f"pyautogui截图失败: {str(e)}")
continue
return screenshot_paths
except Exception as e:
print(f"备用截图方法失败: {str(e)}")
return []
def run_scheduler():
"""运行定时任务"""
# 每天早上8:30执行
schedule.every().day.at("08:30").do(send_excel_report)
# 立即测试一次
print(f"{dt.datetime.now()} - 正在执行首次测试...")
send_excel_report()
while True:
schedule.run_pending()
time.sleep(60)
if __name__ == '__main__':
print(f'程序启动时间: {dt.datetime.now()}')
# 确保目录存在
output_dir = r'D:\仲景生活'
if not os.path.exists(output_dir):
os.makedirs(output_dir)
print(f"已创建目录: {output_dir}")
# 启动定时任务线程
scheduler_thread = Thread(target=run_scheduler)
scheduler_thread.daemon = True
scheduler_thread.start()
try:
while True:
time.sleep(60)
except KeyboardInterrupt:
print("程序已停止")
推送的截图中销售的图右侧有过多无数据区域,品类下侧有部分无数据区域,昨日销售右侧有部分无数据区域,修正代码,自动精确截图区域
只写出需要修改部分代码