如何使用python 1秒钟做合同

  • 是否因为客户准备报价而占用大量时间
  • 是否总是在调Excel列宽行高搞得精疲力尽
  • 是否为产品在报价表上需要分类感到焦头烂额
  • 是否想有一个助手把这些机械的工作做得又快又好
下面这段python代码可以帮你解决以上所有问题,只用1秒钟。

先看下效果:
https://www.bilibili.com/video/BV1Be411x7j7/

  • 准备好基础数据表


    0.png
  • 客户信息照旧填写,把客户的需要的型号以及数量填好;
    0-2.png
  • 运行程序。

  • 完成!

0-3.png

接下来我们来看看如何实现。

需要准备的基础文件主要是产品信息统计表,python程序会根据客户的新需求在统计表中自动寻找匹配。此处我们将所有的信息都汇总在 ’DATA.xlsx‘ 下的'Pool 产品明细'中,并将客户需求填写在'AUTO PI DOCUMENT.xlsx'的'Sheet1'中,程序根据此表在 ’DATA.xlsx‘ 下的'Pool 产品明细'中做出匹配,然后生成新的'PI’ 作为发票草本。

  • 准备好基础文件后,我们正式进入编程

  • 我们会用到openpyxl库来处理Excel,及Font, Alignment,Border,Side方法来调整字体,格式,以及绘制表格。

  • 载入库函数

import openpyxl
from openpyxl.styles import Font, Alignment, Border, Side
  • 载入需要使用的文档,
# 打开要求文档
wbData = openpyxl.load_workbook('AUTO PI DOCUMENT.xlsx')
wsData = wbData['Sheet1']
wbSource = openpyxl.load_workbook('DATA.xlsx', data_only=True)
wsSource = wbSource['Pool 产品明细']
  • 这里注意在载入'Data.xlsx'的时候,因为表中存在大量公式进行计算,所以需要读取单元格内的值,而不要提取公式,所以后面加上了data_only=True

  • 新建一个工作簿,在新工作簿中创建名为‘PI’的工作表

# 新建文档
wb = openpyxl.Workbook()

# Sheet新建与命名
wsPI = wb.active
wsPI.title = 'PI'
  • 定义一下将会需要的字体与单元格边框格式
# 定义字体及边框格式
fontTitle = Font(name='Arial', bold=True, size=14)
fontObj1 = Font(name='Arial', size=9)
fontObj2 = Font(name='Arial', bold=True, size=8)
border_set = Border(left=Side(style='thin'),
                    right=Side(style='thin'),
                    top=Side(style='thin'),
                    bottom=Side(style='thin'))
  • 接下来需要制作几个内置函数来方便程序编写
    由于期望将客户需要的产品根据系列不同来分开,所以需要提取系列的编号,提取产品的型号,以及匹配信息并返回相应值的三个函数
  1. 提取系列的编号函数
  • 由于例子中的产品主要是开关插座产品,编号'C301', ' VP405',规则是第一位或前两位字母表示系列,后面3位表示型号,即便后面再加上颜色参数,总位数也不会超过8位。这里我首先需要判断产品型号是否小于8位,且第一位是字母,第三四位是数字。然后继续判断,如果第二位是数字,则系列编号只有1位,如果第二位也是字母,那么就返回前两位作为系列编号
# 判断是不是开关,并提取系列
def isswich (CODE):
    if len(CODE) < 8 and CODE[0].isalpha() and CODE[2:4].isdecimal():
        if CODE[1].isdecimal():
            return CODE[0]
        else:
            return CODE[0:2]
    else:
        return False

  1. 提取产品型号函数
  • 如果输入的产品是开关插座,那么将系列型号去除,接下来三位是编号,返回编号
# 提取产品型号
def code(CODE):
    if isswich(CODE):
        return CODE[len(isswich(CODE)): len(isswich(CODE))+3]

3.匹配产品信息函数

  • 需要根据产品的型号’item',匹配出需要的信息‘info'
# 匹配产品信息
def match(item,info):
    title_col = 0
    for title in range(1, wsSource.max_column+1):
        if wsSource.cell(row=1, column=title).value == info:
            title_col = title
    if isswich(item):
# 在database里寻找相应的系列
        for row in range(1, wsSource.max_row+1):
            if wsSource.cell(row=row, column=4).value == isswich(item) and \
                    wsSource.cell(row=row, column=5).value == int(code(item)):
                return wsSource.cell(row=row, column=title_col).value

  • 然后因为在PI中根据系列进行分类,那就先将所有系列抽取,放在一个list中
# 找出所有 range
AllRange = set()
for i in range(16, wsData.max_row+1):
    # 只有当item字符小于8个,首位是字母,第3,4位为数字,被认作是开关插座
    if isswich(wsData['C' + str(i)].value):
        rangeObj = str(wsData['C' + str(i)].value)[0:2]
        if rangeObj[1].isdecimal():
            rangeObj = rangeObj[0]

        AllRange.add(rangeObj)
AllRange = list(AllRange)
  • 接下来把所有产品分门别类的放在各个系列中,组成一个产品字典。
# 创建 产品字典
AllItem = {}
for Range in AllRange:
    for itemRow in range(16, wsData.max_row+1):
        if isswich(wsData['C'+str(itemRow)].value) == Range:
            ITEM = wsData.cell(row=itemRow, column=3).value
            qty = wsData.cell(row=itemRow, column=4).value
            AllItem.setdefault(Range, {})
            AllItem[Range].setdefault(ITEM, qty)
  • 准备工作都做好了,接下来开始正式编辑PI
  • 设置列宽
# 编辑文档
# 列宽设置
wsPI.column_dimensions['A'].width = 3
wsPI.column_dimensions['B'].width = 9
wsPI.column_dimensions['C'].width = 35
wsPI.column_dimensions['D'].width = 10
wsPI.column_dimensions['E'].width = 12
wsPI.column_dimensions['F'].width = 9.5
wsPI.column_dimensions['G'].width = 6.5
  • 填写公司名称等表头并调整字体格式
# 第一行 公司名称
wsPI['A1'].value = wsData['B3'].value
wsPI['A1'].font = fontTitle
wsPI.merge_cells('A1:G1')
wsPI['A1'].alignment = Alignment(horizontal='center')

# 第二行 地址
wsPI['A2'].value = wsData['B4'].value
wsPI['A2'].font = fontObj1
wsPI.merge_cells('A2:G2')
wsPI['A2'].alignment = Alignment(horizontal='center')
# 第三行 电话
wsPI['A3'].value = wsData['B5'].value
wsPI['A3'].font = fontObj1
wsPI.merge_cells('A3:G3')
wsPI['A3'].alignment = Alignment(horizontal='center')
# 第四行 表名
wsPI['A4'].value = wsData['B6'].value
wsPI['A4'].font = fontTitle
wsPI.merge_cells('A4:G4')
wsPI['A4'].alignment = Alignment(horizontal='center')
  • 第二部分填写订单相关信息并调整字体格式
  • 填写表头
# 第二部分,客户及合同信息
# 2.1 填写订单相关信息
wsPI['A5'].value = 'To: ' + str(wsData['B7'].value)
wsPI['A6'].value = 'SHIPMENT: ' + str(wsData['B8'].value)
wsPI['A7'].value = 'PAYMENT: ' + str(wsData['B9'].value)
wsPI['A8'].value = 'AMOUNT AND QUANTITY: ' + str(wsData['B10'].value)
wsPI['E5'].value = 'INVOICE NO.: ' + str(wsData['B1'].value)
wsPI['E6'].value = 'DATE: ' + str(wsData['B11'].value)
wsPI['E7'].value = 'PORT OF DESTINATION: ' + str(wsData['B12'].value)
wsPI['E8'].value = 'PORT OF LOADING: ' + str(wsData['B13'].value)
# 2.2 合并单元格
wsPI.merge_cells('A5:D5')
wsPI.merge_cells('A6:D6')
wsPI.merge_cells('A7:D7')
wsPI.merge_cells('A8:D8')
wsPI.merge_cells('E5:G5')
wsPI.merge_cells('E6:G6')
wsPI.merge_cells('E7:G7')
wsPI.merge_cells('E8:G8')

for i in range(5, 9):
    wsPI["A"+str(i)].font = fontObj1
    wsPI["E" + str(i)].font = fontObj1

  • 完成表格主体
# 填写产品相关信息
# 标题
TitleList = ['No.', 'ITEM', 'DESCRIPTION', 'QUANTITY', 'UNIT PRICE',
             'TOTAL', 'VOLUME', 'CTN', 'PCS/CTN', 'CBM/CTN']

for i in range(1, 11):
    wsPI.cell(row=9, column=i).value = str(TitleList[i - 1])
for i in range(1, 11):
    wsPI.cell(row=9, column=i).font = fontObj2
    wsPI.cell(row=9, column=i).alignment = Alignment(horizontal='center')

# 内容
Line = 10
for R in AllRange:
    wsPI.cell(row=Line, column=1).value = R+' Range'
    Line += 1
    ItemList = list(AllItem[R])
    for eachItem in ItemList:
        wsPI.cell(row=Line, column=2).value = eachItem
        wsPI.cell(row=Line, column=4).value = AllItem[R][eachItem]
        wsPI.cell(row=Line, column=3).value = match(wsPI.cell(row=Line, column=2).value, 'DESCRIPTION')
        wsPI.cell(row=Line, column=5).value = match(wsPI.cell(row=Line, column=2).value, 'PRICE')
        wsPI.cell(row=Line, column=9).value = match(wsPI.cell(row=Line, column=2).value, 'QTY/CTN')
        wsPI.cell(row=Line, column=10).value = match(wsPI.cell(row=Line, column=2).value, 'VOLUME')

        wsPI.cell(row=Line, column=6).value = '=round(D{}*E{},2)'.format(Line, Line)
        wsPI.cell(row=Line, column=8).value = '=D{}/I{}'.format(Line, Line)
        wsPI.cell(row=Line, column=7).value = '=round(H{}*J{},3)'.format(Line, Line)

        wsPI.cell(row=Line, column=4).number_format = '#,##0" PCS"'
        wsPI.cell(row=Line, column=5).number_format = '$#,##0.00'
        wsPI.cell(row=Line, column=6).number_format = '$#,##0.00'
        wsPI.cell(row=Line, column=7).number_format = '#,##0.000'
        wsPI.cell(row=Line, column=8).number_format = '#" CTN"'
        wsPI.cell(row=Line, column=9).number_format = '#" PCS"'
        wsPI.cell(row=Line, column=10).number_format = '#,##0.000'
        Line += 1
  • 完成表格汇总行
MaxRow = wsPI.max_row
wsPI.cell(row=MaxRow+1, column=3).value = 'TOTAL'
wsPI.cell(row=MaxRow+1, column=4).value = '=sum(D10:D{})'.format(MaxRow)
wsPI.cell(row=MaxRow+1, column=5).value = 'FOB WENZHOU'
wsPI.cell(row=MaxRow+1, column=6).value = '=sum(F10:F{})'.format(MaxRow)
wsPI.cell(row=MaxRow+1, column=7).value = '=sum(G10:G{})'.format(MaxRow)
wsPI.cell(row=MaxRow+1, column=8).value = '=sum(H10:H{})'.format(MaxRow)

wsPI.cell(row=wsPI.max_row, column=3).font = fontObj2
wsPI.cell(row=wsPI.max_row, column=3).alignment = Alignment(horizontal='center')
wsPI.cell(row=wsPI.max_row, column=4).number_format = '#,##0" PCS"'
wsPI.cell(row=wsPI.max_row, column=5).font = fontObj2
wsPI.cell(row=wsPI.max_row, column=5).alignment = Alignment(horizontal='center')
wsPI.cell(row=wsPI.max_row, column=6).number_format = '$#,##0.00'
wsPI.cell(row=wsPI.max_row, column=7).number_format = '#,##0.000'
wsPI.cell(row=wsPI.max_row, column=8).number_format = '#" CTN"'
  • 绘制表格,调整部分需要加粗字体
for row in range(10, wsPI.max_row+1):
    for column in range(1,8):
        wsPI.cell(row=row,column=column).border = border_set
        wsPI.cell(row=row, column=column).font = fontObj1
for row in range(9,wsPI.max_row+1):
    wsPI.cell(row=row, column=1).font = fontObj2
for column in range(1,8):
    wsPI.cell(row=9, column=column).border = border_set
  • 结尾 合同双方
# 结尾
lastRow = wsPI.max_row
wsPI.cell(row=lastRow+2, column=1).value = 'ACCEPTED:'
wsPI.cell(row=lastRow+3, column=1).value = wsData['B7'].value
wsPI.cell(row=lastRow+2, column=4).value = 'OFFERED:'
wsPI.cell(row=lastRow+3, column=4).value = wsData['B3'].value
for k in range(lastRow+2, lastRow+4):
    wsPI["A"+str(k)].font = fontObj2
    wsPI["D" + str(k)].font = fontObj2

  • 保存文件名(合同编号及卖方信息)
# 文件保存
wb.save("{}-{}.xlsx".format(wsData["B2"].value, wsData["B1"].value))
  • 以上便是合同编写简易的小程序
  • (代码中会有冗余,和不合理不严谨的逻辑,还望高手指正)
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 225,226评论 6 524
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 96,509评论 3 405
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 172,523评论 0 370
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 61,181评论 1 302
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 70,189评论 6 401
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 53,642评论 1 316
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 41,993评论 3 431
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 40,977评论 0 280
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 47,527评论 1 326
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 39,547评论 3 347
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 41,661评论 1 355
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 37,250评论 5 351
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 42,991评论 3 340
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 33,422评论 0 25
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 34,571评论 1 277
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 50,241评论 3 382
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 46,737评论 2 366

推荐阅读更多精彩内容