合并报表/财务报表模块,常见业务规则处理场景合集

合并报表实施和运维过程中,经常需要通过业务规则处理一些特殊场景,因此我们搜集并整理了一些常见场景的规则处理案例,供实施人员参考和使用:
1 注意事项
调试时,执行的是调试版的业务规则;如果打开报表检查数据执行业务规则或者智能合并,执行的是运行版的业务规则。
业务规则不能照搬,维度限定、执行条件等需要根据现场实际使用情况做个性化的修改。如果对业务规则的修改或者调试有疑问,可以提单咨询。
2 常见场景
2.1 公共库
/**************************************常量声明与赋值*****************************************/
const INI_FY_CODE = "FY2021"; // 初始化财年编码
const INI_FY_P_CODE = "202101"; // 初始化财年期间编码
/**************************************全局变量声明与赋值**************************************/
let CTX_S_CODE = ctx.S.number; // 当前情景编码
let CTX_FY_CODE = ctx.FY.number; // 当前财年编码
let CTX_P_CODE = ctx.P.number; // 当前期间编码
let CTX_E_CODE = ctx.E.number; // 当前组织编码
let CTX_C_CODE = ctx.C.number; // 当前币别编码
let CTX_BP_CODE = ctx.BP.number; // 当前过程编码
let CTX_EC_CODE = ctx.E.EC; // 当前组织本位币
let CTX_PC_CODE = ctx.E.PC; // 当前组织母公司币别
let CTX_PE_CODE = ctx.E.parent(); //获取当前组织的父级
let CTX_E_ISBASE = ctx.E.isBase(); // 当前组织是否单体公司
// 当前财年期间编码,形如"202001"
let CTX_FY_P_CODE = CTX_FY_CODE.substr(-4) + CTX_P_CODE.substr(-2);
// 当前财年的上一年,初始化财年期间之后有效,否则返回空字符串
let CTX_FY_LAST = (CTX_FY_CODE > INI_FY_CODE) ? ctx.FY.lastYear() : "";
// 当前期间的上期间,需要注意的是如果使用了13期,那么13期的上期是11期,1期的上期还是1期
if (CTX_P_CODE == "M_M01") {
CTX_P_LAST = "M_M01";};
if (CTX_P_CODE == "M_M13") {
CTX_P_LAST = "M_M11";};
// 跨年的上期:获取上期的财年期间维度组合字符串,常用于需要在runs函数中获取上月数的情况,初始财年的第1期的上期返回为空,非初始财年的第1期的上期是上年的12期,其他期的上期逻辑为CTX_P_LAST的逻辑
let CTX_LAST_FYP = "";
if (CTX_FY_LAST == "") {
CTX_LAST_FYP = (CTX_P_CODE == "M_M01") ? "" : ",P@" + CTX_P_LAST;
}
else {
CTX_LAST_FYP = (CTX_P_CODE == "M_M01") ? ",FY@" + CTX_FY_LAST + ",P@M_M12" : ",P@" + CTX_P_LAST;
}
//股权相关全局变量声明
//是否参与合并状态
let CTX_CON_STATUS = getConAttr("AS");
//合并方法字段值
let CTX_CON_METHOD = getConAttr("CM");
//合并架构信息设置自定义项1
let CTX_CON_UD1 = getConAttr("UD1");
/**
* @function ctxIsNewConsol()
* @returns {boolean} true/false
* @description 判断当期组织在当前期间是否新设合并
* @example
* let isNewConsol = ctxIsNewConsol();
*/
function ctxIsNewConsol() {
let res = false;
if (CTX_CON_UD1 == "ud1") {
if (CTX_P_CODE == "M_M01") {
res = true;
}
else {
let lastConUD1 = getConAttr("UD1","P@" + CTX_P_LAST);
if (lastConUD1 != "ud1") {
res = true;
}
}
}
return res;
}
2.2 录入本年累计计算本期
//1月的本期=1月的本年累计;其他月份的本期=本期的本年累计-上期的本年累计;13期的本期=本期的本年累计-11期的本年累计,包含了12期本期数和13期调整数
//此业务规则需.要分配给EJE等过程成员,这样抵销数等才会参与该计算
let sc = scope(A["R2001"].base(),其他维度).except(A.in("1001"));
let vExp = "v('CT@CurrentPeriod') = v('CT@YTD') - v('CT@YTD,P@" + CTX_P_LAST + "')";
if(CTX_P_CODE == "M_M01"){
vExp = "v('CT@CurrentPeriod') = v('CT@YTD')";
};
runs(sc,vExp);
2.3 录入本期计算本年累计
//方式一:本期累计=本期+上期本年累计,依赖上期的本年累计数,即必须逐期依次执行
//此业务规则需要分配给EJE等过程成员,这样抵销数等才会参与该计算
let sc = scope(A["R2001"].base(),其他维度);
let vExp = "v('CT@YTD') = v('CT@CurrentPeriod') + v('CT@YTD,P@" + CTX_P_LAST + "')";
if(CTX_P_CODE == "M_M01"){
vExp = "v('CT@YTD') = v('CT@CurrentPeriod') "
};
runs(sc,vExp);
//方式二:本期累计=1期本期+2期本期....+当期本期,不依赖先计算出上期累计,但此方式可能会影响性能
//此业务规则需要分配给EJE等过程成员,这样抵销数等才会参与该计算
let sc = scope(A["R6001"].base(),其他维度);
let vExp = "v('CT@YTD') = v('CT@CurrentPeriod')";
let pNum = Number(CTX_P_CODE.substr(-2));
for (let i = 1; i < pNum; i++) {
let pCode = "00" + i;
pCode = "M_M" + pCode.substr(-2);
vExp = vExp + " + v('CT@CurrentPeriod,P@" + pCode + "')";
};
runs(sc,vExp);
2.4 获取上年同期累计数
//获取上年同期累计数写到当年的当期的LYYTD上。
//LYYTD是指新的上年同期累计数变动类型成员,其他维度字样那补充其他维度成员scope信息,R2001是指科目成员编码
runs(
scope(A["R2001"].base(),其他维度),
"v('CT@LYYTD') = v('CT@YTD,FY@" + ctx.FY.lastYear() + "')"
);
2.5 跨年获取上期数,判断12期和13期是否有数
function getLastPeriod() {
let sc = scope(A["RPTItem"].base(),FY.in(CTX_FY_LAST),P.in("M_M13"));
let cs = getCellSet(sc);
if (cs == null || cs.length == 0) {
return "M_M12";
}
return "M_M13";
}
2.6 变动类型成员BFLY按组织层级往上聚合
//entList获取传入组织的所有直接下级。
//Exp将其通过for拼成一个语句:BFLY,当前传入组织=BFLY,第1个下级组织+BFLY,第2个下级组织+。。。
//validChildren是指参与合并的直接下级组织,如同一父级下有相同编码的下级,那么,只会获取生效的直接下级。
let entList = ctx.E.validChildren();
//let entList = ctx.E.children();
let Exp = "v('CT@BFLY') = ";
let i = 0;
if(entList.length>0) {
Exp = Exp + "v('CT@BFLY,E@" + entList[i] + "')";
}
for (i = 1; i < entList.length; i++) {
Exp = Exp + " + v('CT@BFLY,E@" + entList[i] + "')";
}
log(Exp);
if(entList.length>0){
runs(
//scope中确定执行语句的范围,目前限定了RPTItem下的科目成员才会执行,可根据需求自行修改
scope(
AT.in("EntityInput"),
A["RPTItem"].base(),
IC.in("ICNone"),
C1.in("C1None")
),
Exp
);
}
2.7 将上年的本期或本年数写到本年的对应变动类型成员中
//本期CurrentPeriod 财年为:上年LastYear 的数据写入到变动类型为上年同期数 014 财年为:本年CurrentYear
//将 变动类型为:本年累计YTD 财年为:上年LastYear 的数据写入到变动类型为上年同期累计数 015 财年为:本年CurrentYear
//scope中没有写A科目维度成员,就代表所有科目成员;BUD["Budget"].base()代表BUD自定义维度的Budget成员的所有明细成员;IC.in("ICNone")表示仅在IC维度的ICNone这个成员上的数据执行
//所有年度上年数据借用组织合并得到合并节点数据,因此CTX_E_ISBASE仅在明细组织成员上执行;
if (CTX_E_ISBASE) {
runs(
scope(IC.in("ICNone"),
AT.in("EntityInput"),
C1.in("C1None")
),
"v('CT@014')=v('FY@" + CTX_FY_LAST + ",CT@CurrentPeriod')",
"v('CT@015')=v('FY@" + CTX_FY_LAST + ",CT@YTD')"
);
}
2.8 小规模纳税报表
//先将核算数据写到组织(公司)+门店维度(小规模)上(该步骤通过acct取数公式实现),再通过下述业务规则将数据从“组织(公司)+门店维度(小规模)”写到“组织(小规模)+门店指定成员MDGL004”上。其中MDGL00302是CU门店维度成员“门店(仅小规模)合计”的编码。
let isBaseCU = CU.isBase(CTX_E_CODE,"MDGL00302");
if (isBaseCU) {
let gongsi = CTX_E_CODE.substr(0,4);
runs(
scope(
AT.in("EntityInput"),
A["RPTItem"].base(),
Mon.in("MonNone"),
IC.in("ICNone")
),
"v('CU@MDGL004') = v('E@" + gongsi + ",CU@" + CTX_E_CODE + "')"
);
}
2.9 只看当月及之前的数据
//月份自定义维度的业务,实现上述逻辑
//报表:房租费用明细表 、五险费用明细表、工资费用明细表、装修费用明细表、汇总销售累计报表、汇总盈亏报表、毛利率汇总表、汇总累计费用报表
//需求:当月只看以前月份及当期的数据
const MONTH_LIST =["M_M01","M_M02","M_M03","M_M04","M_M05","M_M06","M_M07","M_M08","M_M09","M_M10","M_M11","M_M12","M_M13"];
let vExp = new Array();
let idx = MONTH_LIST.indexOf(CTX_P_CODE);
//throw(idx);
for (let i = 0; i <= idx; i++) {
let monCode = MONTH_LIST[i].substr(-3);
vExp.push("v('Mon@" + monCode + "') = v('Mon@MonNone,P@" + MONTH_LIST[i] + "')");
}
//throw(vExp);
runs(
scope(CT.in("YTD"),
IC.in("ICNone"),
AT.in("EntityInput"),
CU["MDGL001"].hierarchy(),
A.in("A10012701")
// A["CustomItems"].hierarchy()
),
vExp
);
2.10 计算到月份的天数,如每天营业额
//A1008月增加及减少=本月营业额-上月营业额
//A1010天增加及减少=本月每天营业额-上月每天营业额
//A1011环比增长率=(本月营业额-上月营业额)/上月营业额
//A1009本月每天营业额=本月营业额/天数
let CTX_P_LAST = ctx.P.lastPeriod();
let CTX_FY_CODE = ctx.FY.number;
let CTX_P_CODE = ctx.P.number;
let dDate = new Date(CTX_FY_CODE.substr(-4),CTX_P_CODE.substr(-2),0);
let days = dDate.getDate();
runs(
scope(CT.in("CurrentPeriod"),
IC.in("ICNone"),
AT.in("EntityInput"),
Mon.in("MonNone"),
CU["MDHJ001"].hierarchy()
),
"v('A@A1008')=v('A@A1002020101')-v('P@" + CTX_P_LAST + ",A@A1002020101')",
"v('A@A1010')=v('A@A1009')-v('P@" + CTX_P_LAST + ",A@A1009')",
"v('A@A1011')=(v('A@A1002020101')-v('P@" + CTX_P_LAST + ",A@A1002020101'))/v('P@" + CTX_P_LAST + ",A@A1002020101')",
"v('A@A1009')=round(v('A@A1002020101')/" + days + ",2)"
);
2.11 计算月平均毛利率
//民勤等累计毛利率统计表直接计算得到,集团汇总累计毛利率统计表需要智能合并
//具体毛利率A1003写在各个月份自定义维度Mon成员(如M01等)上,
//需要将月毛利率的合计(月份汇总Mon.YFHJ,A1003中不排除Mon的动态计算)除以有毛利率的期间成员个数,
//得到月平均毛利率A1013,excel公式可以写为:=IFERROR(SUM(C4:N4)/COUNT(C4:N4),"")。
let expArr = new Array();
let baseSC = scope(
A.in("A1003"),CT.in("CurrentPeriod"),AT.in("EntityInput"),IC.in("ICNone")
);
let sc = scope(
baseSC,Mon.in("YFHJ"),CU["Customize"].hierarchy()
);
let cs = getCellSet(sc);
//debug(cs.length);
cs.forEach(
function (dc) {
let dData = dc.value;
let cuCode = dc.Customize;
if (dData != 0) {
let cuSC = scope(baseSC,CU.in(cuCode),Mon["YFHJ"].base());
let cuCS = getCellSet(cuSC);
let count = cuCS.length;
//debug(count);
if (count != 0) {
expArr.push("v('CU@" + cuCode + "') = " + dData / count);
}}});
if (expArr.length > 0) {
// expArr.forEach(function(exp){debug(exp);});
runs(
scope(
A.in("A1013"),
AT.in("EntityInput"),
Mon.in("MonNone"),
IC.in("ICNone"),
CT.in("CurrentPeriod")
),
expArr
);
}
2.12 自定义特殊折算规则
// 如果科目借贷算法=借加贷减,YJF=BBOY折算前数*(期末汇率-年初汇率)+YJF折算前数*期末汇率,YDF=YDF折算前数*期末汇率
// 如果科目借贷算法=借减贷加,YJF=YJF折算前数*期末汇率,YDF=BBOY折算前数*(期末汇率-年初汇率)+YDF原币*期末汇率)
let excpAccs = ["1511","4001"];
let rateEnt = ["ZIHL","ZRAML","WPGL","ZIWML","ZIWML-ZH8","ZRPHZQ","ZRPHCW","ZRPHJR","ZRPHMY","ZRGJZB","ZIB2021L","ZIB2019L","ZKBL","ZRTGIHL","ZRTGIMIL"]; //汇率方案组织编码
ctxTranslate(A["GL01"].base(),rateEnt,excpAccs);
ctxTranslate(A["GL02"].base(),rateEnt,excpAccs);
ctxTranslate(A["GL03"].base(),rateEnt,excpAccs);
ctxTranslate(A["GL04"].base(),rateEnt,excpAccs);
function ctxTranslate(accList,rateEnt,excpAccs) {
if (rateEnt.includes(CTX_E_CODE) && CTX_BP_CODE == "IRpt" && CTX_EC_CODE != CTX_C_CODE) {
let cl = getRate(CTX_EC_CODE, CTX_C_CODE, "ClosingRate", "RatePreset")
let bo = getRate(CTX_EC_CODE, CTX_C_CODE, "BOYRate", "RatePreset");
if (cl != null && cl > 0 && bo != null && bo > 0) {
let drAccList = accList.filter(function (acc) { return acc.dcDirect == "1" && (excpAccs == null || !(excpAccs.includes(acc.number))); });
let crAccList = accList.filter(function (acc) { return acc.dcDirect == "2" && (excpAccs == null || !(excpAccs.includes(acc.number))); });
if (drAccList.length > 0) {
runs(
scope(drAccList),
"v('CT@YJF') = v('C@" + CTX_EC_CODE + ",BP@ERpt,CT@BBOY') * (" + cl + " - " + bo + " ) + v('C@" + CTX_EC_CODE + ",BP@ERpt,CT@YJF') * " + cl ,
"v('CT@YDF') = v('C@" + CTX_EC_CODE + ",BP@ERpt,CT@YDF') * " + cl
);
}
if (crAccList.length > 0) {
runs(
scope(crAccList),
"v('CT@YJF') = v('C@" + CTX_EC_CODE + ",BP@ERpt,CT@YJF') * " + cl ,
"v('CT@YDF') = v('C@" + CTX_EC_CODE + ",BP@ERpt,CT@BBOY') * (" + cl + " - " + bo + ") + v('C@" + CTX_EC_CODE + ",BP@ERpt,CT@YDF') * " + cl
);
}
}
}
}
2.13 科目指定范围汇总求和函数
/**
* @f
合并报表/财务报表模块,常见业务规则处理场景合集
声明:除非特别标注,否则均为本站原创文章,转载时请以链接形式注明文章出处。如若本站内容侵犯了原著者的合法权益,可联系本站删除。



