大家好,我是刀哥。

如果你是一家集团公司的财务人员,合并报表由你来做,或者你是这家集团公司外聘的独立审计师,需要你定期编制合并底稿、出具审计报告,而集团公司有多家分子公司,可能十几家,甚至几十家上百家。

在做合并报表时,需要将每家分子公司原始财务报表(或称未审报表)数据过入到合并底稿表格中,然后再编制调整分录,此时如果手工一家一家数据搬运,无数次Ctrl c和Ctrl v,会觉得特别无聊,也非常累人,估计连续搬运还不到5家,手就开始抽筋了。

加上如果每月都要做的话,那光就重复搬运未审数这一项任务,就足够费时够折磨人的,所以这次刀哥就拿自己工作中的实例,用代码来解决这个问题。

1.

目标任务

刀哥要将2020年8月16家分子公司的财务报表(资产负债表和利润表)数据,过入到2020年8月的合并底稿表格中。

合并报表的10个步骤(将16家公司财务报表数据过入合并底稿表格)(1)

合并报表的10个步骤(将16家公司财务报表数据过入合并底稿表格)(2)

▲ 各家原始财务报表及待填入的合并底稿表格,已作脱敏处理

2.

解决过程

①获取每家公司原始财务报表的文件路径并保存

如上图,刀哥已将这16家分子公司的财务报表都放在了同一文件夹下,文件夹名称为“8月报表”。如果还有更多的分子公司,请全部放在同一文件夹下,尽管放!使劲放!

获取每家财务报表文件路径的代码如下。

1#把所有原始财务报表放在同一文件夹下,将其文件路径提取出来并保存 2defget_file(folder_path):#获取同一文件夹下所有财务报表各自的文件路径 3dir_file=os.listdir(folder_path) 4print(type(dir_file)) 5forpathindir_file: 6ifpath[-4:]=='xlsx'orpath[-3:]=='xls': 7whole_path=r'd:\F:学习\python\读写财务报表\8月报表\{}'.format(path) 8dir_xls.append(whole_path) 9returndir_xls 10 11dir_xls=[] 12folder_path=r'd:\F:学习\python\读写财务报表\8月报表'#此为文件夹路径 13dir_xls=get_file(folder_path) 14print(dir_xls)

②打开已加密的合并底稿表格。

1#打开要写入的合并底稿表格,因为是加密文档,用密码打开 2xlApp=win32.Dispatch('Excel.Application') 3write_filepath=r'd:\F:学习\python\读写财务报表\某超NB集团公司 Consolidation-2020-IFRS.xlsx'#要写入的合并底稿表格的文件路径 4password='Hope for a peace world'#打开密码 5xlApp.Visible=True 6xlwb=xlApp.Workbooks.Open(write_filepath,False,True,None,Password=password)

③读取单家财务报表数并写入合并底稿

我用单元格内容定位进行读取,用单元格地址定位进行写入。

比如,读取资产负债表时,取“项目”列中“货币资金”对应的“期末余额”数,取到之后写入合并底稿对应表格的“E14”单元格中,其他各报表项目均以此类推,代码如下。

1defread_and_write_datas(read_file_path,target_sheet):#读取财务报表数据,并写入合并底稿表格 2data=xlrd.open_workbook(read_file_path) 3names=data.sheet_names() 4#print(names) 5foriinnames: 6if'资产负债表'ini: 7sheetName1=i 8elif'利润表'ini: 9sheetName2=i 10else: 11continue 12data1=pd.read_excel(read_file_path,sheet_name=sheetName1,header=3) 13assets=data1.iloc[:,:4] 14liabilities_and_equity=data1.iloc[:,4:8] 15data2=pd.read_excel(read_file_path,sheet_name=sheetName2,header=3) 16 17#--------------------------- 18#资产类项目 19Cash_and_cash_equivalents=assets['期末余额'][assets['项目']==' 货币资金']#货币资金 20Fair_value_financial_assets_through_PL=assets['期末余额'][assets['项目']==' 交易性金融资产']#交易性金融资产 21Bills_receivable=assets['期末余额'][assets['项目']==' 应收票据']#应收票据 22Trade_receviables_others=assets['期末余额'][assets['项目']==' 应收账款']#应收账款 23Prepayment_to_suppliers=assets['期末余额'][assets['项目']==' 预付款项']#预付款项 24Other_receivables=assets['期末余额'][assets['项目']==' 其他应收款']#其他应收款 25Inventory=assets['期末余额'][assets['项目']==' 存货']#存货 26Deferred_expenses=assets['期末余额'][assets['项目']==' 长期待摊费用']#待摊费用 27Property_and_equipment=assets['期末余额'][assets['项目']==' 固定资产净额']#固定资产 28Construction_in_progress=assets['期末余额'][assets['项目']==' 在建工程']#在建工程 29Intangible_assets=assets['期末余额'][assets['项目']==' 无形资产']#无形资产 30 31#--------------------------- 32#负债类和所有者权益类项目,都要加负号 33Bank_loan=-liabilities_and_equity['期末余额.1'][liabilities_and_equity['项目.1']==' 短期借款']#短期借款 34Notes_payable=-liabilities_and_equity['期末余额.1'][liabilities_and_equity['项目.1']==' 应付票据']#应付票据 35Accounts_payable=-liabilities_and_equity['期末余额.1'][liabilities_and_equity['项目.1']==' 应付账款']#应付账款 36Advance_from_customers=-liabilities_and_equity['期末余额.1'][liabilities_and_equity['项目.1']==' 预收款项']#预收款项 37Salaries_and_welfare=-liabilities_and_equity['期末余额.1'][liabilities_and_equity['项目.1']==' 应付职工薪酬']#应付职工薪酬 38Income_tax=-liabilities_and_equity['期末余额.1'][liabilities_and_equity['项目.1']==' 应交税费']#应交税费 39Interest_payable_current=-liabilities_and_equity['期末余额.1'][liabilities_and_equity['项目.1']==' 应付利息']#应付利息 40Other_payables=-liabilities_and_equity['期末余额.1'][liabilities_and_equity['项目.1']==' 其他应付款']#其他应付款 41Long_term_loan=-liabilities_and_equity['期末余额.1'][liabilities_and_equity['项目.1']==' 长期借款']#长期借款 42Long_term_payables=-liabilities_and_equity['期末余额.1'][liabilities_and_equity['项目.1']==' 长期应付款']#长期应付款 43Reserves=-liabilities_and_equity['期末余额.1'][liabilities_and_equity['项目.1']==' 专项储备']#专项储备 44 45#--------------------------- 46#损益类项目,收入类加负号,成本费用类不加负号 47turnover=-data2['本年累计'][data2['项目']=='其中:主营业务收入']#主营业务收入 48Cost_of_Sales=data2['本年累计'][data2['项目']=='其中:主营业务成本']#主营业务成本 49business_tax_and_surcharges=data2['本年累计'][data2['项目']=='营业税金及附加']#营业税金及附加 50Selling_Expenses=data2['本年累计'][data2['项目']=='销售费用']#销售费用 51G_A=data2['本年累计'][data2['项目']=='管理费用']#管理费用 52Finance_Cost=data2['本年累计'][data2['项目']=='财务费用']#财务费用 53Interest_Income=data2['本年累计'][data2['项目']=='利息收入']#利息收入 54Other_expense=data2['本年累计'][data2['项目']=='减:营业外支出']#营业外支出 55Other_Income=-data2['本年累计'][data2['项目']=='加:营业外收入']#营业外收入 56Realized_Gain_or_Loss_from_Financial_Assets=-data2['本年累计'][data2['项目']=='投资收益(损失以“-”号填列)']#投资收益 57Income_Taxes=data2['本年累计'][data2['项目']=='减:所得税费用']#所得税费用 58 59#---------------- 60#写入已打开的合并底稿表格 61ws=xlwb.Worksheets(target_sheet) #实现表格一一对应关系 62ws.Range('E14').value=float(Cash_and_cash_equivalents) 63ws.Range('E16').value=float(Fair_value_financial_assets_through_PL) 64ws.Range('E17').value=float(Trade_receviables_others) 65ws.Range('E19').value=float(Bills_receivable) 66ws.Range('E20').value=float(Other_receivables) 67ws.Range('E22').value=float(Inventory) 68ws.Range('E23').value=float(Prepayment_to_suppliers) 69ws.Range('E24').value=float(Deferred_expenses) 70ws.Range('E40').value=float(Property_and_equipment) 71ws.Range('E44').value=float(Construction_in_progress) 72ws.Range('E52').value=float(Intangible_assets) 73ws.Range('E67').value=float(Bank_loan) 74ws.Range('E68').value=float(Notes_payable) 75ws.Range('E69').value=float(Accounts_payable) 76ws.Range('E70').value=float(Advance_from_customers) 77ws.Range('E71').value=float(Salaries_and_welfare) 78ws.Range('E73').value=float(Income_tax) 79ws.Range('E77').value=float(Interest_payable_current) 80ws.Range('E74').value=float(Other_payables) 81ws.Range('E90').value=float(Long_term_loan) 82ws.Range('E92').value=float(Long_term_payables) 83ws.Range('E101').value=float(Reserves) 84ws.Range('E131').value=float(turnover) 85ws.Range('E133').value=float(Cost_of_Sales) float(business_tax_and_surcharges) 86ws.Range('E139').value=float(Selling_Expenses) 87ws.Range('E141').value=float(G_A) 88ws.Range('E143').value=float(Finance_Cost)-float(Interest_Income) 89ws.Range('E145').value=float(Interest_Income) 90ws.Range('E147').value=float(Other_expense) float(Other_Income) 91ws.Range('E157').value=float(Realized_Gain_or_Loss_from_Financial_Assets) 92ws.Range('E164').value=float(Income_Taxes)

④建立合并底稿与各单家的一一对应关系,实现多报表批量读写

因为要将各单家公司原始财务报表数据过入到合并底稿中对应公司名的表格中去,故需建立一一对应关系,防止数据跑错表格。

且与①中保持一致,有多少家就放多少家,尽管放!使劲放!代码如下。

1#建立匹配对应关系,即每一张未审报表数据读取出来后,要写入到合并底稿中的哪个表格中去,指明去处,别跑错地方了 2match_dict={ 3'P公司':'CX', 4'A公司':'BF', 5'B公司':'FY', 6'C公司':'DY', 7'D公司':'BP', 8'E公司':'DT', 9'F公司':'JL', 10'G公司':'LJ', 11'H公司':'PX', 12'I公司':'PXF', 13'J公司':'MA', 14'K公司':'XS', 15'L公司':'XP', 16'M公司':'XY', 17'N公司':'GC', 18'O公司':'YF' 19} 20 21#读写过程 22start_time=time.time() 23print('刀哥,程序开始读写工作!') 24foriinrange(len(dir_xls)): 25print('正在读写第{}张表:{}'.format(i 1,dir_xls[i])) 26read_file_path=dir_xls[i] 27forkey,valueinmatch_dict.items(): 28ifkeyinread_file_path: 29target_sheet=value 30read_and_write_datas(read_file_path,target_sheet) 31print('第{}张表读写完毕!'.format(i 1)) 32end_time=time.time() 33total_time=end_time-start_time 34print('所有财务报表全部读写完毕!共用时{:.1f}秒'.format(total_time))

3.

目标实现

经过上述一番折腾,运行代码终端输出如下结果。

1刀哥,程序开始读写工作! 2正在读写第1张表:d:\F:学习\python\读写财务报表\8月报表\财务报表(2020-08)-P公司.xlsx 3第1张表读写完毕! 4正在读写第2张表:d:\F:学习\python\读写财务报表\8月报表\财务报表(2020-08)-A公司.xlsx 5第2张表读写完毕! 6...... 7正在读写第15张表:d:\F:学习\python\读写财务报表\8月报表\财务报表(2020年-08)-N公司.xlsx 8第15张表读写完毕! 9正在读写第16张表:d:\F:学习\python\读写财务报表\8月报表\财务报表(2020年-08)-O公司.xlsx 10第16张表读写完毕! 11所有财务报表全部读写完毕!共用时78.4秒

于是,经过1分多钟的等待,16张报表数据全部过入到对应的合并底稿表格中,并已保存好乖乖躺在了我的电脑里,至此,打完收工!

最后还要说一点的是,通过代码实现对表格格式的统一性要求比较高,需要各公司使用统一格式的报表模板,合并底稿中对应各家的表格也要统一,这样才能准确的读取数据,并准确的写入到指定的地方去。否则,程序容易报错,读写结果也容易出现错位串行。

每家公司报表难免会有自己的特殊性,难免用代码写入后还有报表不平的情况,遇到这样的情况,手动打开表格检查一下修改一下就好,这也比完全靠人工搬运,效率也要高出几十、几百倍,并且单家报表数量越多,则越能体现出它的优势。

刀哥介绍:一个会写代码的注册会计师,看用代码能把财会玩出什么新花样!

,