超存货可销成本

准备好这两张表

1.商品的效期库存表:

直接拉生产及结束日期的商品库存,留下几列空白字段,后续update处理

image.png
2.商品的预算表:把预算表加工处理
image.png

业务逻辑:

  • 最短的效期:

    • 若效期时长能销售的预算 <= 库途,即到效期结束,仍还有库途没销万,即 产生折损(折损 = 库途 - 效期时长的预算) ,且实际销售天数为效期时长

    • 若效期时长能销售的预算 > 库途,即效期还没结束,库途就已经被销完了,不产生折损,但 实际销售天数为本次库途的可销天 ,而非效期时长

  • 其他效期:

    • (若效期时长能销售的预算 - 本效期之前的累计销售预算) <= 库途,即到效期结束,仍还有库途没销万,即 产生折损(折损 = 库途 - 效期时长的预算 - 本效期之前的累计销售预算),且 实际销售天数为效期时长 - 本效期之前的累计销售天数

    • (若效期时长能销售的预算 - 本效期之前的累计销售预算) > 库途,即效期还没结束,库途就已经被销完了,不产生折损,但 实际销售天数为本次(库途 + 本效期之前的累计销售预算)算出的可销天 再 - 本效期之前的累计销售天数,而非效期时长

  • 深红色文字:超过两年的效期或者库途的处理的业务逻辑

    • 当效期的时长是超过两年,即超过的那部分的预算 = (效期 - 总累计销售天数)* 24个月的预算日均
    • 当库途超过两年后的预算,即超过的那部分的可销天 = (库途 - 两年的累计预算)/ 24个月的预算日均

python 实现过程

# -*- coding: utf-8 -*-
"""
Created on Thu Nov 21 10:55:23 2019

@author: liand
"""
# mysql连接包
from pymysql import connect
# import pandas as pd
# 不发出警告
# import warnings
# warnings.filterwarnings("ignore")


# 连接数据库
conn = connect(host='localhost', user='root', password='123', db='test', port=3306)  
# 获取操作游标
cursor = conn.cursor()

# 获取需要计算到超存货可销天的商品
sql = "SELECT DISTINCT 商品 FROM xiaoqi;"
# 执行查询语句
cursor.execute(sql)
skus = list(cursor.fetchall())


for i in skus:
    the_sku = i[0]
    # print(the_sku)
    ################################## 开始计算某个商品(sku)各个效期的存货超可销成本################################
    
    # 执行查询语句
    sql = "SELECT * FROM xiaoqi WHERE 商品 = {1}{0}{1} ORDER BY 效期 ;".format(the_sku,"'")
    cursor.execute(sql) 
    # 获取查询结果(元组形式转列表)
    data = list(cursor.fetchall())
    # 获取第一条,为效期最短的
    a = data[0]
    # print(a)
    # 设置序列号,方便检查结果,后续校验好了可去掉
    num = 0
    for i in data:         
        num = num + 1
        sku = i[0] # 商品
        xiaoqi = i[1] # 效期(天数)
        kucun = i[2] # 库存(这批效期的库存)
        # 当次条记录等于第一条的时候,则行以下结果
        if i == a:
            # sql比较长,且部分语句是重复使用,先拆分,再合并
            # 定位要分析效期的商品
            sub_sql1 = """SELECT * FROM test_one WHERE 商品 = {1}{0}{1}""".format(the_sku,"'")
            # 效期不大于两年:月初预算 +(效期-月初累计天数)*日均   效期大于两年:月尾预算+(效期-月尾天数)*(月尾预算/730-当月过去天数)
            sub_sql2 = """IF(a.月份 = REPLACE(LEFT(date_add(CURDATE(),interval 24 month),7),'-',''), 
                             a.月尾累计预算 + ({0} - a.月尾累计天数)*(a.月尾累计预算/(730 - DAYOFMONTH( CURDATE() ) )),
                             a.月初累计预算+({0}-a.月初累计天数)*a.日均)""".format(xiaoqi)

            # 定位效期的位置
            sub_sql3 = """SELECT ss.商品, max(ss.月份) AS 月份 FROM ({0}) ss  WHERE {1}>= ss.月初累计天数 GROUP BY ss.商品""".format(sub_sql1,xiaoqi)
            # 定位库途能卖多少天
            sub_sql4 = """SELECT s.商品,max(s.月份) as 月份 FROM ({0}) s WHERE {1}>= s.月初累计预算 GROUP BY s.商品""".format(sub_sql1,kucun)
            # 库途不大于两年后累计:月初天数+(库途-月初预算)*日均  库途大于两年:月尾天数+(库途-月尾预算)/(月尾预算/730-当月过去天数)
            sub_sql5 = """IF(a.月份 = REPLACE(LEFT(date_add(CURDATE(),interval 24 month),7),'-',''), -- 当定位到的月份在2年后时
                             a.月尾累计天数 + ({0} - a.月尾累计预算)/(a.月尾累计预算/(730 - DAYOFMONTH( CURDATE() ) )),
                             a.月初累计天数+({0} -a.月初累计预算)/a.日均)""".format(kucun)
            
            
            
            
            # 拼接sql语句,业务逻辑:
            # 以次批次的效期定位到要计算的记录行上,通过结构计算出折损与实际销售天数
            # 若效期时长能销售的预算 <= 库途,即到效期结束,仍还有库途没销万,即产生折损,且实际销售天数为效期时长
            # 若效期时长能销售的预算  > 库途,即效期还没结束,库途就已经被销完了,不产生折损,但实际销售天数为本次库途的可销天,而非效期时长
            sql ="""SELECT if(({3})<={0},{0}-(({3})),0) 折损,
                           if(({3})<={0},{1},
                               (SELECT ({6}) FROM ({2}) a INNER JOIN ({5}) b ON a.商品 = b.商品 AND a.月份 = b.月份)
                                ) 实际用了多少天销售
                    FROM ({2}) a INNER JOIN ({4}) b on a.月份 = b.月份;""".format(kucun,xiaoqi,sub_sql1,sub_sql2,sub_sql3,sub_sql4,sub_sql5)
            # print(sql)
            # 执行sql语句       
            cursor.execute(sql)
            # 返回结果
            data2 = list(cursor.fetchall())
            # print(num,data2)
            # 折损
            zesun = data2[0][0]
            # 实际销售天数(简称可销天)
            kexiaotian = data2[0][1]
            # 实际销售库途 = 库途 - 能销售的预算
            xiaohao = float(kucun) - zesun
            # print(kexiaotian,zesun,xiaohao)
            # print(zesun,kexiaotian,xiaohao)
            print(num,"商品:",the_sku,">>","销售天数:",kexiaotian,"折损:",zesun,"实际卖出:",xiaohao,"\n")
            # 更新表数据
            sql = """
            UPDATE xiaoqi SET 
            销售天数 = {6}{0}{6},
            折损 = {6}{1}{6}, 
            实际卖出 = {6}{2}{6}
            WHERE 商品 = {6}{3}{6} AND 效期 = {6}{4}{6} AND 库存 = {6}{5}{6};""".format(kexiaotian,zesun,xiaohao,sku,xiaoqi,kucun,"'")
            cursor.execute(sql)
            # 提交更新操作,完成事务
            conn.commit()
            
            # 由于第一条为最低的效期,所以并没有截止到目前(即汇总前面效期的累计预算)的累计预算及累计天数,
            # 相当于初始化,所以直接设置为零,也可以不更新,让它为空也行。
            # sql = """UPDATE xiaoqi SET 截止目前累计销售 = '0',截止目前累计销售天数 = '0' 
            # WHERE 商品 = {3}{0}{3} AND 效期 = {3}{1}{3}  AND 库存 = {3}{2}{3};""".format(sku,xiaoqi,kucun,"'")
            # cursor.execute(sql)
            # conn.commit()
            
            # 查看目前最后的计算结果,方便检查,后续检查完毕可去掉
            sql = """
            SELECT * FROM xiaoqi WHERE 
            商品 = {3}{0}{3} AND 效期 = {3}{1}{3} AND 库存 = {3}{2}{3};""".format(sku,xiaoqi,kucun,"'")
            cursor.execute(sql)
            data = list(cursor.fetchall())
            # print(num, data)
        #  获取非第一条,为效期不是最短的其他数据   
        else:
            # 更新在本效期之前的所有效期的累计销售预算及累计销售天数
            data = list(cursor.fetchall())     
            sql = """UPDATE xiaoqi b INNER JOIN (SELECT (SELECT SUM(b.实际卖出) FROM xiaoqi AS b WHERE b.效期 < a.效期 AND b.商品 = a.商品) 累计,
                     (SELECT SUM(b.销售天数) FROM xiaoqi AS b WHERE b.效期 < a.效期 AND b.商品 = a.商品) 累计天数,
                    商品,效期,库存
                    FROM xiaoqi a) a ON b.商品=a.商品 AND a.效期=b.效期 AND a.库存 = a.库存 SET b.截止目前累计销售=a.累计,b.截止目前累计销售天数 = a.累计天数;"""
            cursor.execute(sql)
            conn.commit()
            
            # 拿到累计销售及累计天数 
            sql = """SELECT * FROM xiaoqi WHERE 商品 = {0}{1}{0} AND 效期 = {0}{2}{0} AND 库存 = {0}{3}{0};""".format("'",the_sku,xiaoqi,kucun)
            cursor.execute(sql)
            data = list(cursor.fetchall())
            leijixiaoshou = data[0][6] # 累计销售 (截止到这批之前商品已累计销售了多少库存)
            leijitianshu = data[0][7] # 累计天数 (截止到这批之前商品已累计销售了多少天数)            
            
            # sql比较长,且部分语句是重复使用,先拆分,再合并
            # 月初预算 +(效期-月初累计天数)*日均 - 累计预算
            sub_sql1 = """IF(a.月份 = REPLACE(LEFT(date_add(CURDATE(),interval 24 month),7),'-',''), 
                             a.月尾累计预算 + ({0} - a.月尾累计天数)*(a.月尾累计预算/(730 - DAYOFMONTH( CURDATE() ) )),
                             a.月初累计预算+({0}-a.月初累计天数)*a.日均) - {1}""".format(xiaoqi,leijixiaoshou)
            # 定位到分析效期的商品 
            sub_sql2 = """SELECT * FROM test_one WHERE 商品 = {1}{0}{1}""".format(the_sku,"'")
            # 定位库途能销售到哪,用于算可销天
            sub_sql3 = """SELECT s.商品,max(s.月份) as 月份 FROM 
                         (SELECT * FROM test_one WHERE 商品 = {1}{0}{1}) s WHERE ({2}+{3})>= s.月初累计预算 GROUP BY s.商品""".format(the_sku,"'",kucun,leijixiaoshou)
            # 效期定位到要计算的记录行 
            sub_sql4 = """SELECT ss.商品, max(ss.月份) AS 月份 
                            FROM (SELECT * FROM test_one WHERE 商品 = {1}{0}{1}) ss
                            WHERE {2}>= ss.月初累计天数 GROUP BY ss.商品""".format(the_sku,"'",xiaoqi)
            # 库途+之前批次累计预算不大于两年后累计:月初天数+(库途+之前批次累计预算-月初预算)*日均
            # 库途+之前批次累计预算大于两年后累计:月尾天数+(库途+之前批次累计预算-月尾预算)/(月尾预算/730-当月过去天数)
            sub_sql5 = """IF(a.月份 = REPLACE(LEFT(date_add(CURDATE(),interval 24 month),7),'-',''),
                             a.月尾累计天数 + ({0}+{1} - a.月尾累计预算)/(a.月尾累计预算/(730 - DAYOFMONTH( CURDATE() ) )),
                             a.月初累计天数+({0}+{1} -a.月初累计预算)/a.日均)""".format(kucun,leijixiaoshou)
                                
                        
            # 拼接sql语句,业务逻辑: 
            # 以次批次的效期定位到要计算的记录行上,通过结构计算出折损与实际销售天数
            # (若效期时长能销售的预算 - 本效期之前的累计销售预算) <= 库途,即到效期结束,仍还有库途没销万,即产生折损(折损 = 库途 - 效期时长的预算 - 本效期之前的累计销售预算),且实际销售天数为效期时长 - 本效期之前的累计销售天数
            # (若效期时长能销售的预算 - 本效期之前的累计销售预算)  > 库途,即效期还没结束,库途就已经被销完了,不产生折损,但实际销售天数为本次(库途 + 本效期之前的累计销售预算)算出的可销天 再 - 本效期之前的累计销售天数,而非效期时长
            sql = """SELECT if(({4})<={0},{0}-({4}),0) 折损,
                            if(({4})<={0},{1}-{2},((SELECT ({8}) FROM ({5}) a 
                            INNER JOIN ({6}) b ON a.商品 = b.商品 AND a.月份 = b.月份)-{2})) 实际用了多少天销售       
                     FROM ({5}) a INNER JOIN ({7}) b on a.月份 = b.月份;""".format(kucun,xiaoqi,leijitianshu,leijixiaoshou,sub_sql1,sub_sql2,sub_sql3,sub_sql4,sub_sql5)
            # 执行sql语句 
            cursor.execute(sql)          
            data2 = list(cursor.fetchall())            
            zesun = data2[0][0] # 折损           
            kexiaotian = data2[0][1] # 实际销售天数       
            xiaohao = float(kucun) - zesun # 实际销售预算
            
            print(num,"商品:",the_sku,">>","销售天数:",kexiaotian,"折损:",zesun,"实际卖出:",xiaohao,"\n")
            
            # 更新表数据 
            sql = """
            UPDATE xiaoqi SET 
            销售天数 = {6}{0}{6},
            折损 = {6}{1}{6}, 
            实际卖出 = {6}{2}{6}
            WHERE 商品 = {6}{3}{6} AND 效期 = {6}{4}{6} AND 库存 = {6}{5}{6};""".format(kexiaotian,zesun,xiaohao,sku,xiaoqi,kucun,"'")
            cursor.execute(sql)
            # 提交更新操作,完成事务
            conn.commit()
                       
            # 查看目前最后的计算结果,方便检查,后续检查完毕可去掉
            sql = """
            SELECT * FROM xiaoqi WHERE 
            商品 = {3}{0}{3} AND 效期 = {3}{1}{3} AND 库存 = {3}{2}{3};""".format(sku,xiaoqi,kucun,"'")
            cursor.execute(sql)
            data = list(cursor.fetchall())
            # print(num,"商品:",the_sku,">>",data,"\n")
        
# 关闭游标
cursor.close()
# 关闭数据库连接
conn.close()  

最后的表,呈现商品每个效期的折损成本

image.png
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,588评论 6 496
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,456评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,146评论 0 350
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,387评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,481评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,510评论 1 293
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,522评论 3 414
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,296评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,745评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,039评论 2 330
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,202评论 1 343
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,901评论 5 338
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,538评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,165评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,415评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,081评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,085评论 2 352

推荐阅读更多精彩内容

  • Tomlinson(1995)认为有效的差异教学有四大特征。 1.第一大特征是所有学生都应有机会探究和应用所学...
    sunflower80阅读 493评论 0 0
  • 老婆会带你去我去过的地方,感受美好的风景和美好的食物~从一个人的回忆变成我们的回忆!我还要带你去我们都没去过的地方...
    万四爷阅读 187评论 0 1
  • 2017-9-12 姓名:李义 公司:慈溪创鑫车辆零部件有限公司 组别:259期利他二组 【知~学习】 背诵 六项...
    六度轮回阅读 99评论 0 0
  • 前天又收到一条道路违章信息提醒,懊恼,心疼之余,在心里慰藉自己“开车不违章的司机,不是好司机”!这回已经不知道是今...
    张花阅读 1,350评论 0 0
  • 前不久,吴彦祖的一条微博火了。 许久没有露面的吴彦祖终于露面了,八妹兴奋的点开图片...... ???等等,哪个是...
    Kmoving2019阅读 876评论 0 3