首先发一下牢骚,公司效益不好,我们被老美抛弃, 成为了内地一家企业的被收购方,按理被收购方是应该被集团替换掉系统才对的.但由于收购方的系统完善程度还远不如我们. 这不,没办法,收购方的其中一个工厂(目标工厂)做的产品与我们类似.需要用我们的系统管理.唉.. 这样一来, 就有我们忙的了, 可是现在的我们就相当于是二娘养的,做好了是应该的,做不好挨骂的份就落到身上了... 进入正文
系统自己写的,我们对基础资料的导入和环境的部署自然不是问题了,但目标工厂提出了一个较为紧急的问题就是客户的对帐单,由于系统目前的应收款单不符合要求,需要额外的写一个,由于财务与信贷的报表一向由我负责. 老大自然把这任务安排到我的头上. 于是不得不梳理一下财务数据取数. 我觉得挺有代表性的.于是决定写下来. 包括帖出SQL的代码. 我相信大部分ERP系统都不外乎这几种情况. 顶多是数据源的TABLE不一样罢了. 先上效果图.
这里有几个需要注意的地方,水晶报表按组分页和统计. 还有页码重置等..
效果很简单.这里主要的是计算期初的数值和本期的回款.
以下是SQL代码,留意一下参数.
/* developed history created by geton jew on 2014-6-19 popurse: for credit report rpt_woer_statement this sp invoked another store_procedure CAL_WOER_STATEMENT to calculate the opening data modified by geton on 2014-6-25 decription: due to users want to show the open bal enevn no data during these period use left join instead of inner join, modified by geton on 2014-6-27 decription: added @soffice parameter as a filter RPT_WOER_STATEMENT '0840','0840','2014/7/3','2014/7/23','ALL' modified by geton on 2014-07-01 decription: added CN/DN journal to this period */ CREATE PROCEDURE [dbo].[RPT_WOER_STATEMENT] @cus1 char(4)='Z21N', @cus2 char(4)='Z23N', @begdate char(10)='2014/04/2', @enddate char(10)='2014/06/26', @soffice varchar(10) = 'ALL' AS -- CREATE TABLE #RESULT ( CUS CHAR(4), TYPE VARCHAR(15), BEGDATE CHAR(10), ENDDATE CHAR(10), AMT FLOAT, OSAMT FLOAT, ORIAMT FLOAT, ORIOSAMT FLOAT ) declare @where varchar(10) if @soffice='ALL' set @where = '%' else set @where = @soffice --select @where -- @BEGDATE 传进去要少一天 DECLARE @cutday VARCHAR(10) SELECT @cutday=CONVERT(VARCHAR(10),DATEADD(DAY,-1,CONVERT(SMALLDATETIME,@begdate)),121) INSERT INTO #RESULT EXEC CAL_WOER_STATEMENT @cus1,@cus2,@cutday,@enddate,@where SELECT A.*,B.TYPE AS RECTYPE,B.BEGDATE AS RECBEGDATE,B.ENDDATE AS RECENDDATE, -isnull(B.AMT,0) AS RECAMT, -isnull(B.OSAMT,0) AS RECOSAMT, -isnull(B.ORIAMT,0) AS RECORIAMT, -isnull(B.ORIOSAMT,0) AS RECORIOSAMT, CUSNAME=SPACE(400), CUSFAX=SPACE(20), CUSTEL=SPACE(20), CONTACT=SPACE(40) INTO #FINANAL FROM #RESULT A left JOIN #RESULT B ON A.CUS=B.CUS AND B.TYPE='*Received*' WHERE A.TYPE='*Openning*' CREATE TABLE #TMP ( SINV CHAR(10), INVNO CHAR(20), PONO CHAR(40), SONUM CHAR(16), MODEL CHAR(40), CUSMODEL CHAR(240), OURPRO CHAR(40), PRODESC CHAR(250), QTY float, PRICE float, SUMQTY float, TAXQTY float, SIDATE smalldatetime, CUSNUM CHAR(4), TAX float, COMPANY CHAR(40), COMPANY1 CHAR(40), TEL CHAR(25), FAX CHAR(25), ADDR1 CHAR(500), CURR CHAR(5), SUMALL FLOAT, FUOM CHAR(5), F2 BIT, INVDATE smalldatetime, COMMENT CHAR(200) ) PRINT 'K' INSERT INTO #TMP(SINV,INVNO,PONO,SONUM,MODEL,CUSMODEL,OURPRO,QTY,PRICE,SUMQTY,TAXQTY,SIDATE,CUSNUM,TAX,CURR,FUOM,F2,INVDATE,COMMENT) SELECT SINV.SINV, CASE WHEN ISNULL(SINV.INVNUM,'A')='A' THEN SINV.DN ELSE SINV.INVNUM END, SO.YOURREF, SO.SONUM, SODTL.PRONUM, SODTL2.COMMENT, SINVDTL.MODEL, SINVDTL.QTY, PRICE, PRICE*SINVDTL.QTY, (SINVDTL.QTY*CASE WHEN SO.TAXINC='TRUE' THEN SODTL.UPRICE/(1+SO.TAX) END)*0.17, SINV.IDATE, SINV.CUS, SINV.TAX, SO.CURRENCY, SINVDTL.SUOM, SO.F2, CASE WHEN ISNULL(SINV.INVDATE,'1900/01/01')='1900/01/01'THEN SINV.IDATE ELSE SINV.INVDATE END, SODTL2.COMMENT FROM SINV WITH (NOLOCK),SINVDTL WITH (NOLOCK),SODTL WITH (NOLOCK),SO WITH (NOLOCK),SODTL2 WITH (NOLOCK),CUS WITH(NOLOCK) WHERE SINV.SINV=SINVDTL.SINV AND SINVDTL.SO=SODTL.SONUM AND SINVDTL.MODEL=SODTL.OURPRO AND SODTL.SONUM=SO.SONUM AND SINV.CUS = CUS.CUS AND CUS.OFFNUM LIKE @where and CUS.CUS BETWEEN @cus1 AND @cus2 AND SINV.IDATE BETWEEN @begdate AND @enddate AND SODTL2.SONUM=SODTL.SONUM AND SODTL2.PRONUM=SODTL.PRONUM AND SODTL2.LOT=SINVDTL.LOT -- CN/DN单据 INSERT #TMP (SINV,SIDATE,CUSNUM,SONUM,SUMQTY,COMMENT) SELECT SINV,IDATE,SINV.CUS,'DN',AMT,INVCOMMENT FROM SINV with (nolock), CUS with (nolock) WHERE SITYPE='a' and SINV.CUS = CUS.CUS AND CUS.OFFNUM LIKE @where and CUS.CUS BETWEEN @cus1 AND @cus2 AND SINV.IDATE BETWEEN @begdate AND @enddate UNION SELECT SRNUM,SR.DATE,CUSNUM,'CN',-AMT,COMMENT FROM SR, CUS WHERE SRTYPE='a' and SR.CUSNUM = CUS.CUS AND CUS.OFFNUM LIKE @where and CUS.CUS BETWEEN @cus1 AND @cus2 AND SR.DATE BETWEEN @begdate AND @enddate UPDATE #TMP SET PRODESC=P.PRODESC FROM PRODUCT P WITH (NOLOCK) WHERE P.PRONUM=#TMP.OURPRO UPDATE #TMP SET COMPANY=COMPANYINFO.CONAME,ADDR1=COMPANYINFO.ADDR1,COMPANY1=COMPANYINFO.CONAME2,TEL=COMPANYINFO.TEL1,FAX=COMPANYINFO.FAX FROM COMPANYINFO WITH (NOLOCK) UPDATE #TMP SET INVNO=JOU.XREF FROM JOU,#TMP WHERE #TMP.SINV=JOU.JOU AND #TMP.INVNO='' -- 采用全连接,不然表中始终会有记录不显示 SELECT * into #fdata FROM #FINANAL FULL join #TMP on #FINANAL.CUS=#TMP.CUSNUM ORDER BY SIDATE ASC --按客户代码更新相应的客户信息. UPDATE #fdata SET CUS=isnull(#fdata.CUS,#fdata.CUSNUM),ORIOSAMT=ISNULL(ORIOSAMT,0),RECORIOSAMT=ISNULL(RECORIOSAMT,0), CUSNAME=CUS.NAME,CUSFAX=CUS.FAX,CUSTEL=CUS.TEL1,CONTACT=CUS.CONTACT FROM CUS WITH (NOLOCK) WHERE isnull(#fdata.CUS,#fdata.CUSNUM)=CUS.CUS update #fdata set PRODESC=MODEL select * from #fdata DROP TABLE #TMP, #RESULT,#FINANAL,#fdata
剩下的另一个SP的代码.主要的计算逻辑都在这里.里面包含了描述.(20141027编辑此文章,脚本有所修改.)
/* Developed History Created by Geton Jew on 2014-6-19 Popurse: For Credit Report RPT_WOER_STATEMENT this was invoked by another store_procedure: RPT_WOER_STATEMENT to show the final data -- RPT_WOER_STATEMENT '0820','0820','2014/7/4','2014/7/25','%' modified by geton on 2014-7-22,2014-7-28 2014-10-24 Content: Change the Received money calculate method. */ -- select * from SINV WHERE CUS= '0820' alter procedure [dbo].[CAL_WOER_STATEMENT] @cus1 char(4)='Z21N', @cus2 char(4)='Z21N', @begdate char(10)='2014/06/25', @enddate char(10)='2014/06/26', @where varchar(10) = '%' as -- --grant execute on CAL_WOER_STATEMENT to public CREATE TABLE #result ( CUS char(4), TYPE varchar(15), BEGDATE char(10), ENDDATE char(10), AMT FLOAT, OSAMT FLOAT, ORIAMT FLOAT, ORIOSAMT FLOAT ) declare @delclose int set @delclose=1 -- 送货单 select SI.CUS, J.JOUTYPE, J.JOU, J.IDATE, AMT=JD.DR, REF=convert(varchar(30),J.JOU), OSAMT=JD.DR, ORIAMT=JD.ORIAMT, ORIOSAMT=JD.ORIAMT, CURR=SI.CURR into #T1 from SINV SI with (nolock),JOU J with (nolock), JOUDTL JD with (nolock), CUS with (nolock) where SI.JOUTYPE=J.JOUTYPE and SI.SINV=J.JOU and J.JOUTYPE=JD.JOUTYPE and J.JOU=JD.JOU and JD.ACC=SI.RECACC and SI.CUS between @cus1 and @cus2 and SI.CUS = CUS.CUS and CUS.OFFNUM LIKE @where and SI.IDATE <= @enddate and (JD.R = 'false' or JD.RR=0) and isnull(SI.DN,'')<>'NIL' -- 收款 截止为参数2日期 -- select * from CUS WHERE CUS='Z21N' insert #T1 select AR.CUS, 'RV', AR.JOU, AR.IDATE, AMT=-AR.AMT, -- AMT为收款金额,这里为负数 AR.CHK, OSAMT=0, -- OSAMT栏位为0 ORIAMT=-ORIAMT, -- 收的是原幣金額 OSORIAMT=0, CURR=AR.CURR from AREC AR with (nolock), CUS with (nolock) where AR.CUS = CUS.CUS and --CUS.OFFNUM LIKE @where and AR.CUS between @cus1 and @cus2 and CUS.OFFNUM LIKE @where and AR.IDATE <= @enddate -- [CAL_WOER_STATEMENT_zz] '0708','0708','2014/7/1','2014/7/28','%' select R2.JOU,R.CUS,MISCHRG=sum(R2.DR+R2.CR) -- 手续费等 into #ta1 from ARECDTL2 R2 with (nolock), AREC R with (nolock),CUS with (nolock) where R.CUS=CUS.CUS and R.JOU=R2.JOU and R2.ACC<>R.AR and -- 科目不等于该客户应收科目 R.CUS between @cus1 and @cus2 and CUS.OFFNUM LIKE @where and R.IDATE <= @begdate group by R2.JOU,R.CUS select R2.JOU, R.CUS,DEPOSIT=sum(R2.DR-R2.CR),ODEPOSIT=sum(R2.ORIAMT) into #tb1 from ARECDTL2 R2 with (nolock),AREC R with (nolock),CUS with (nolock) where R.CUS = CUS.CUS and R.JOU=R2.JOU and R2.ACC=R.AR and -- 科目等于该客户应收科目,即应收减少,相当于有余钱在我们公司 R.CUS between @cus1 and @cus2 and CUS.OFFNUM LIKE @where and R.IDATE <= @begdate group by R2.JOU,R.CUS update #T1 set AMT=#T1.AMT-#ta1.MISCHRG -- AMT收款增加,即等于对冲票据总额 from #ta1 where #T1.JOUTYPE='RV' and #T1.JOU=#ta1.JOU AND #ta1.CUS = #T1.CUS update #T1 set OSAMT=#tb1.DEPOSIT, ORIOSAMT=#tb1.ODEPOSIT -- 这里更新为客户新的应收,分别为本位币和原币 from #tb1 where #T1.JOUTYPE='RV' and #T1.JOU=#tb1.JOU AND #tb1.CUS = #T1.CUS /*** 退货 ***/ --print 88 insert #T1 select SR.CUSNUM, JD.JOUTYPE, SR.SRNUM, SR.DATE, AMT=-JD.CR, -- 负数,退钱 isnull(SR.XREF,''), OSAMT=-JD.CR, -- 负数,退钱 ORIAMT=JD.ORIAMT, -- 同样,这里会负数 ORIOSAMT=JD.ORIAMT, -- 同样,这里会负数 CURR=SR.CURR from SR,JOUDTL JD,CUS where SR.RECACC=JD.ACC and SR.JOUTYPE=JD.JOUTYPE and SR.SRNUM=JD.JOU and SR.CUSNUM between @cus1 and @cus2 and CUS.OFFNUM LIKE @where and SR.DATE <= @enddate and (JD.R = 'false' or JD.RR=0) and isnull(SR.XREF,'')<>'NIL' and SR.CUSNUM=CUS.CUS /*** update OSAMT ***/ select SINV,#T1.CUS, AMTPAID=sum(AMTPAID),ORIAMTPAID=sum(ARECDTL.ORIAMT) -- AMTPAID 應收金額,ORIAMT原幣金額 into #T3 from AREC, ARECDTL, #T1 where ARECDTL.SINV=#T1.JOU and AREC.JOU=ARECDTL.JOU and #T1.CUS=AREC.CUS and AREC.IDATE <= @begdate -- 这里的CUTDATE被我换了@begdate group by SINV,#T1.CUS update #T1 set OSAMT=OSAMT-AMTPAID, ORIOSAMT=ORIOSAMT-ORIAMTPAID from #T3 where #T3.SINV=#T1.JOU AND #T3.CUS=#T1.CUS -- select * from #T1 WHERE JOU='NSB4001333' -- 这段时间收款分开计算 select R2.JOU,R.CUS,MISCHRG=sum(R2.DR+R2.CR) -- 手续费等 into #ta2 from ARECDTL2 R2 with (nolock), AREC R with (nolock),CUS with (nolock) where R.CUS=CUS.CUS and R.JOU=R2.JOU and R2.ACC<>R.AR and -- 科目不等于该客户 应收科目 R.CUS between @cus1 and @cus2 and CUS.OFFNUM LIKE @where and R.IDATE >@begdate and R.IDATE <= @enddate group by R2.JOU,R.CUS select R2.JOU, R.CUS,DEPOSIT=sum(R2.DR-R2.CR),ODEPOSIT=sum(R2.ORIAMT) into #tb2 from ARECDTL2 R2 with (nolock),AREC R with (nolock),CUS with (nolock) where R.CUS = CUS.CUS and R.JOU=R2.JOU and R2.ACC=R.AR and -- 科目等于该客户应收科目,即冲掉一笔应收,又开一笔应收,相当于调到期的应收 R.CUS between @cus1 and @cus2 and CUS.OFFNUM LIKE @where and R.IDATE >@begdate and R.IDATE <= @enddate group by R2.JOU,R.CUS update #T1 set AMT=#T1.AMT-#ta2.MISCHRG -- AMT收款增加,即等于对冲票据总额 from #ta2 where #T1.JOUTYPE='RV' and #T1.JOU=#ta2.JOU AND #ta2.CUS = #T1.CUS update #T1 set OSAMT=#tb2.DEPOSIT, ORIOSAMT=#tb2.ODEPOSIT -- 这里更新为客户余的钱在我们公司,分别为本位币和原币 from #tb2 where #T1.JOUTYPE='RV' and #T1.JOU=#tb2.JOU AND #tb2.CUS = #T1.CUS -- modified flag 20141024 -- select SINV,#T1.CUS, -- AMTPAID=sum(isnull(AMTPAID,AREC.AMT)), -- 假如没有冲帐,即有预收款等,就直接取一层的金额了。 -- ORIAMTPAID=sum(isnull(ARECDTL.ORIAMT,AREC.ORIAMT)) --into #T4 --from #T1 --left join AREC with (nolock) on #T1.JOU=AREC.JOU and #T1.CUS=AREC.CUS and AREC.CHKACC IN('36000','AAAA') --如果算收款的是特定科目,则这里应该加设科目,否则一些调帐的收票或其它收票将会做会收款。 --left join ARECDTL on AREC.JOU=ARECDTL.JOU --where AREC.IDATE>@begdate and AREC.IDATE <= @enddate --group by SINV ,#T1.CUS -- modified flag: 由20141024的假如没有冲帐,即有预收款等,就直接取一层的金额了。 -- 直接换取收票金额,而不管它有没有冲销, 同时加上手续费(科目是6601) select #T1.JOU,#T1.CUS, AMTPAID=sum(isnull(AREC.AMT,0)+ isnull(ARECDTL2.ORIAMT*ARECDTL2.RATE,0)), ORIAMTPAID=sum(isnull(AREC.ORIAMT,0) + isnull(ARECDTL2.ORIAMT,0)) into #T4 from #T1 left join AREC with (nolock) on #T1.JOU=AREC.JOU and #T1.CUS=AREC.CUS and AREC.CHKACC IN('36000','AAAA') --如果算收款的是特定科目,则这里应该加设科目,否则一些调帐的收票或其它收票将会做会收款。 left join ARECDTL2 on AREC.JOU=ARECDTL2.JOU AND ARECDTL2.ACC='6601' where AREC.IDATE>@begdate and AREC.IDATE <= @enddate group by #T1.JOU ,#T1.CUS -- [CAL_WOER_STATEMENT_zz] '0708','0708','2014/7/1','2014/7/28','%' select CUS, AMTPAID=sum(AMTPAID),ORIAMTPAID=sum(#T4.ORIAMTPAID) into #T5 FROM #T4 GROUP BY CUS /*** group all entry before sid1 to form one entries and delete the individual ones ***/ if @delclose=1 delete #T1 where OSAMT=0 --select * from #T1 where IDATE < @begdate order by IDATE ASC select CUS, AMT=sum(AMT), OSAMT=sum(OSAMT), ORIAMT=sum(ORIAMT), ORIOSAMT=sum(ORIOSAMT) into #T2 from #T1 where IDATE <= @begdate group by CUS --delete #T1 where IDATE < @begdate insert #result select CUS, '*Openning*', convert(varchar(10),convert(smalldatetime,'1900/01/01'),121), convert(varchar(10),convert(smalldatetime,@begdate),121), AMT, OSAMT, ORIAMT, ORIOSAMT from #T2 --WHERE ORIOSAMT>0 /*** 以上算完了期初,所以收票还要加上这个期间的数 ***/ insert #result select CUS, '*Received*', convert(varchar(10),dateadd(day,1,convert(smalldatetime,@begdate)),121), convert(varchar(10),convert(smalldatetime,@enddate),121), -AMTPAID, -ORIAMTPAID, -AMTPAID, -ORIAMTPAID from #T5 -- 如果只有期初,没有回款,那么添加回款为0. insert #result select CUS, '*Received*', convert(varchar(10),dateadd(day,1,convert(smalldatetime,@begdate)),121), convert(varchar(10),convert(smalldatetime,@enddate),121),0,0,0,0 FROM CUS with (nolock) WHERE CUS between @cus1 and @cus2 and CUS.OFFNUM LIKE @where and CUS NOT IN (select CUS FROM #result WHERE TYPE='*Received*') --select * from #result -- 如果只有本期回款却没有期初的话,要插入期初为0,以便后续报表显示 -- [CAL_WOER_STATEMENT] '0716','0716','2014/7/1','2014/7/28','%' insert #result --(CUS,TYPE,BEGDATE,ENDDATE) SELECT CUS,'*Openning*',convert(varchar(10),convert(smalldatetime,'1900/01/01'),121), convert(varchar(10),convert(smalldatetime,@begdate),121),0,0,0,0 FROM #result a WHERE TYPE='*Received*' AND NOT EXISTS ( SELECT * FROM #result b where a.CUS = b.CUS and b.TYPE='*Openning*') select * from #result order by CUS ASC,BEGDATE ASC drop table #ta1,#tb1, #ta2,#tb2,#T1,#T2,#T3,#T4,#T5,#result