首先发一下牢骚,公司效益不好,我们被老美抛弃, 成为了内地一家企业的被收购方,按理被收购方是应该被集团替换掉系统才对的.但由于收购方的系统完善程度还远不如我们. 这不,没办法,收购方的其中一个工厂(目标工厂)做的产品与我们类似.需要用我们的系统管理.唉.. 这样一来, 就有我们忙的了, 可是现在的我们就相当于是二娘养的,做好了是应该的,做不好挨骂的份就落到身上了... 进入正文
系统自己写的,我们对基础资料的导入和环境的部署自然不是问题了,但目标工厂提出了一个较为紧急的问题就是客户的对帐单,由于系统目前的应收款单不符合要求,需要额外的写一个,由于财务与信贷的报表一向由我负责. 老大自然把这任务安排到我的头上. 于是不得不梳理一下财务数据取数. 我觉得挺有代表性的.于是决定写下来. 包括帖出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