feat(so): 同步 CLM 合同销售订单累计数量

- 新增销售订单累计出库数量回写功能
- 新增销售订单累计开票数量回写功能
- 新增销售订单累计退货数量回写功能
This commit is contained in:
mzr 2025-08-23 11:15:59 +08:00
parent 21cf13550b
commit 5600f4a391
6 changed files with 486 additions and 7 deletions

View File

@ -0,0 +1,190 @@
package nc.pubimpl.so.m30.ic.m4c;
import java.io.Serializable;
import java.util.HashMap;
import java.util.Map;
import com.yonyou.cloud.ncc.NCCSagas;
import nc.bs.so.m30.plugin.ServicePlugInPoint;
import nc.bs.so.m30.rule.credit.RenovateARByBidsBeginRule;
import nc.bs.so.m30.rule.credit.RenovateARByBidsEndRule;
import nc.impl.pubapp.env.BSContext;
import nc.impl.pubapp.pattern.data.view.ViewQuery;
import nc.impl.pubapp.pattern.data.view.ViewUpdate;
import nc.impl.pubapp.pattern.pub.LockOperator;
import nc.impl.pubapp.pattern.rule.processer.AroundProcesser;
import nc.itf.scmpub.reference.uap.group.SysInitGroupQuery;
import nc.itf.so.m30.compensate.ISaleOrderSagasCompensate;
import nc.pubimpl.so.m30.ic.m4c.rule.Rewrite35WhenOutNumChange;
import nc.pubimpl.so.m30.ic.m4c.rule.Rewrite38WhenOutNumChange;
import nc.pubimpl.so.m30.ic.m4c.rule.RewriteExchangeOutRule;
import nc.pubimpl.so.m30.ic.m4c.rule.RewriteOPCOutNumRule;
import nc.pubimpl.so.m30.ic.m4c.rule.RewriteOutNumRule;
import nc.pubimpl.so.m30.ic.m4c.rule.RewriteOutStateRule;
import nc.pubimpl.so.m30.ic.m4c.rule.RewritePriceNumRule;
import nc.pubimpl.so.m30.ic.m4c.rule.RewriteSetNumRule;
import nc.pubimpl.so.m30.ic.m4c.rule.RewriteToleranceCheck;
import nc.pubimpl.so.m30.ic.m4c.rule.RewriteZ3ByRowStateRule;
import nc.pubimpl.so.rule.SyncClmNumRule;
import nc.pubitf.so.m30.ic.m4c.IRewrite30For4C;
import nc.pubitf.so.m30.ic.m4c.Rewrite4CPara;
import nc.vo.credit.engrossmaintain.pub.action.M30EngrossAction;
import nc.vo.pub.BusinessException;
import nc.vo.pub.lang.UFBoolean;
import nc.vo.pubapp.pattern.exception.ExceptionUtils;
import nc.vo.pubapp.pattern.log.TimeLog;
import nc.vo.so.m30.entity.SaleOrderBVO;
import nc.vo.so.m30.entity.SaleOrderViewVO;
import nc.vo.so.pub.util.SOSagasConst;
/**
* 出库回写销售订单累计出库数量实现
* <p>
* <b>本类主要完成以下功能</b>
*
* <ul>
* <li>功能条目1
* <li>功能条目2
* <li>...
* </ul>
*
* @version 6.0
* @author 刘志伟
* @time 2010-7-12 下午04:50:48
*/
public class Rewrite30For4CImpl implements IRewrite30For4C {
@Override
public void rewrite30NumFor4C(Rewrite4CPara[] paras) throws BusinessException {
try {
//埋补偿
Map<String, Serializable> paraMap = new HashMap<String, Serializable>();
paraMap.put(SOSagasConst.OPERATER, SOSagasConst.REERITE30NUMFOR4CI);
paraMap.put(SOSagasConst.PARAS,paras);
NCCSagas.compensate(ISaleOrderSagasCompensate.class, paraMap);
this.rewrite(paras);
}
catch (RuntimeException ex) {
ExceptionUtils.marsh(ex);
}
}
private void addRule(AroundProcesser<SaleOrderViewVO> processer,
SaleOrderViewVO[] views) throws BusinessException {
// -------- 执行前规则 ----------------
// 先检查出库容差范围
new RewriteToleranceCheck().process(views);
processer.addBeforeRule(new RewriteOutNumRule());
processer.addBeforeRule(new RewriteExchangeOutRule());
// 执行前最后设置累计出库数量
processer.addBeforeRule(new RewriteSetNumRule());
processer.addBeforeRule(new Rewrite35WhenOutNumChange());
// 设置销售价格限量促销执行量 jilu for 恒安限量促销
processer.addBeforeRule(new RewritePriceNumRule());
// end
// 更新信用调用前(必须放在前后rule最内层防止和状态信用调用嵌套)
processer.addBeforeRule(new RenovateARByBidsBeginRule(
M30EngrossAction.M30OutReWrite));
// -------- 执行后规则 ----------------
// 更新信用调用后(必须放在前后rule最内层防止和状态信用调用嵌套)
processer.addAfterRule(new RenovateARByBidsEndRule(
M30EngrossAction.M30OutReWrite));
//回写预订单累计出库数量
processer.addAfterRule(new Rewrite38WhenOutNumChange());
// 为了通知StateCalculateUtil.isAutoTransitInvoiceOpen是自动回写调用的而非行手工打开
// 此处非常别扭作为临时处理以后版本对状态机的使用重新考虑
BSContext.getInstance().setSession(Rewrite30For4CImpl.class.getName(),
UFBoolean.TRUE);
// 回写电子销售:累计出库数量
if(SysInitGroupQuery.isOPCEnabled()){
processer.addAfterRule(new RewriteOPCOutNumRule());
}
processer.addAfterRule(new RewriteOutStateRule());
// 回写销售订单数量时如果订单行关闭还要回写上游合同
processer.addAfterRule(new RewriteZ3ByRowStateRule());
// 同步CLM合同销售订单-累计出库数量
processer.addAfterRule(new SyncClmNumRule("ntotaloutnum"));
}
private String[] lockBills(Map<String, Rewrite4CPara> index) {
int size = index.size();
String[] bids = new String[size];
bids = index.keySet().toArray(bids);
LockOperator locker = new LockOperator();
String message =
nc.vo.ml.NCLangRes4VoTransl.getNCLangRes().getStrByID("4006011_0",
"04006011-0180")/*@res "库存销售出库单回写销售订单累计出库数量,锁销售订单表体失败"*/;
locker.lock(bids, message);
return bids;
}
private Map<String, Rewrite4CPara> prepareParams(Rewrite4CPara[] paras) {
Map<String, Rewrite4CPara> index = new HashMap<String, Rewrite4CPara>();
for (Rewrite4CPara para : paras) {
index.put(para.getCsaleorderbid(), para);
}
return index;
}
private SaleOrderViewVO[] query(Map<String, Rewrite4CPara> index) {
String[] ids = this.lockBills(index);
ViewQuery<SaleOrderViewVO> bo =
new ViewQuery<SaleOrderViewVO>(SaleOrderViewVO.class);
bo.setSharedHead(true);
SaleOrderViewVO[] views = bo.query(ids);
if (views.length != index.size()) {
String message =
nc.vo.ml.NCLangRes4VoTransl.getNCLangRes().getStrByID("4006011_0",
"04006011-0171")/*@res "出现并发,请重新查询销售订单"*/;
ExceptionUtils.wrappBusinessException(message);
}
return views;
}
private void rewrite(Rewrite4CPara[] paras) throws BusinessException {
TimeLog.logStart();
Map<String, Rewrite4CPara> index = this.prepareParams(paras);
// 此处设置session变量以避免程序到处传递
BSContext.getInstance().setSession(Rewrite4CPara.class.getName(), index);
TimeLog.info("并处理参数"); /*-=notranslate=-*/
TimeLog.logStart();
SaleOrderViewVO[] views = this.query(index);
TimeLog.info("查询销售订单表体"); /*-=notranslate=-*/
AroundProcesser<SaleOrderViewVO> processer =
new AroundProcesser<SaleOrderViewVO>(
ServicePlugInPoint.rewrite30NumFor4C);
this.addRule(processer, views);
TimeLog.logStart();
processer.before(views);
TimeLog.info("写数据库前执行业务规则"); /*-=notranslate=-*/
TimeLog.logStart();
String[] names = new String[] {
SaleOrderBVO.NTOTALNOTOUTNUM, SaleOrderBVO.NTOTALOUTNUM
};
ViewUpdate<SaleOrderViewVO> bo = new ViewUpdate<SaleOrderViewVO>();
views = bo.update(views, SaleOrderBVO.class, names);
TimeLog.info("更新数据库"); /*-=notranslate=-*/
TimeLog.logStart();
processer.after(views);
TimeLog.info("写数据库后执行业务规则"); /*-=notranslate=-*/
// 此处释放session变量以免浪费内存
BSContext.getInstance().removeSession(Rewrite4CPara.class.getName());
BSContext.getInstance().removeSession(Rewrite30For4CImpl.class.getName());
}
}

View File

@ -0,0 +1,148 @@
package nc.pubimpl.so.m30.so.m32;
import java.util.HashMap;
import java.util.Map;
import nc.bs.so.m30.plugin.ServicePlugInPoint;
import nc.bs.so.m30.rule.credit.RenovateARByBidsBeginRule;
import nc.bs.so.m30.rule.credit.RenovateARByBidsEndRule;
import nc.impl.pubapp.env.BSContext;
import nc.impl.pubapp.pattern.data.view.ViewQuery;
import nc.impl.pubapp.pattern.data.view.ViewUpdate;
import nc.impl.pubapp.pattern.pub.LockOperator;
import nc.impl.pubapp.pattern.rule.processer.AroundProcesser;
import nc.pubimpl.so.m30.so.m32.rule.RewriteInvoiceStateRule;
import nc.pubimpl.so.m30.so.m32.rule.RewriteSetNumRule;
import nc.pubimpl.so.m30.so.m32.rule.RewriteToleranceCheck;
import nc.pubimpl.so.rule.SyncClmNumRule;
import nc.pubitf.so.m30.so.m32.IRewrite30For32;
import nc.pubitf.so.m30.so.m32.Rewrite32Para;
import nc.vo.credit.engrossmaintain.pub.action.M30EngrossAction;
import nc.vo.pub.BusinessException;
import nc.vo.pubapp.pattern.exception.ExceptionUtils;
import nc.vo.pubapp.pattern.log.TimeLog;
import nc.vo.so.m30.entity.SaleOrderBVO;
import nc.vo.so.m30.entity.SaleOrderViewVO;
/**
* 销售发票回写销售订单服务接口实现类
*
* @author 刘志伟
* @since 6.0
* @time 2010-01-28 下午13:49:07
*/
public class Rewrite30For32Impl implements IRewrite30For32 {
@Override
public void rewrite30NumFor32(Rewrite32Para[] paras) throws BusinessException {
try {
this.rewrite(paras);
}
catch (RuntimeException ex) {
ExceptionUtils.marsh(ex);
}
}
private void addRule(AroundProcesser<SaleOrderViewVO> processer,
SaleOrderViewVO[] views) throws BusinessException {
// -------- 执行前规则 ----------------
// 最先检查开票数量
new RewriteToleranceCheck().process(views);
// 执行前最后设置开票数量
processer.addBeforeRule(new RewriteSetNumRule());
// -------- 执行后规则 ----------------
// 执行后开票状态规则
processer.addAfterRule(new RewriteInvoiceStateRule());
// 同步CLM合同销售订单-累计开票数量
processer.addAfterRule(new SyncClmNumRule("ntotalinvoicenum"));
}
private String[] lockBills(Map<String, Rewrite32Para> index) {
int size = index.size();
String[] bids = new String[size];
bids = index.keySet().toArray(bids);
LockOperator locker = new LockOperator();
String message = nc.vo.ml.NCLangRes4VoTransl.getNCLangRes().getStrByID("4006011_0","04006011-0186")/*@res "销售发票回写销售订单累计开票数量,锁销售订单表体失败"*/;
locker.lock(bids, message);
return bids;
}
private Map<String, Rewrite32Para> prepareParams(Rewrite32Para[] paras) {
Map<String, Rewrite32Para> index = new HashMap<String, Rewrite32Para>();
for (Rewrite32Para para : paras) {
index.put(para.getCsaleorderbid(), para);
}
return index;
}
private SaleOrderViewVO[] query(Map<String, Rewrite32Para> index) {
String[] ids = this.lockBills(index);
ViewQuery<SaleOrderViewVO> bo =
new ViewQuery<SaleOrderViewVO>(SaleOrderViewVO.class);
bo.setSharedHead(true);
SaleOrderViewVO[] views = bo.query(ids);
if (views.length != index.size()) {
String message = nc.vo.ml.NCLangRes4VoTransl.getNCLangRes().getStrByID("4006011_0","04006011-0171")/*@res "出现并发,请重新查询销售订单"*/;
ExceptionUtils.wrappBusinessException(message);
}
return views;
}
private void rewrite(Rewrite32Para[] paras) throws BusinessException {
TimeLog.logStart();
Map<String, Rewrite32Para> index = this.prepareParams(paras);
// 此处设置session变量以避免程序到处传递
BSContext.getInstance().setSession(Rewrite32Para.class.getName(), index);
TimeLog.info("并处理参数"); /*-=notranslate=-*/
TimeLog.logStart();
SaleOrderViewVO[] views = this.query(index);
TimeLog.info("查询销售订单表体"); /*-=notranslate=-*/
AroundProcesser<SaleOrderViewVO> processer =
new AroundProcesser<SaleOrderViewVO>(
ServicePlugInPoint.rewrite30NumFor32);
this.addRule(processer, views);
TimeLog.logStart();
processer.before(views);
TimeLog.info("写数据库前执行业务规则"); /*-=notranslate=-*/
TimeLog.logStart();
String[] names = new String[] {
SaleOrderBVO.NTOTALINVOICENUM
};
ViewUpdate<SaleOrderViewVO> bo = new ViewUpdate<SaleOrderViewVO>();
views = bo.update(views, SaleOrderBVO.class, names);
TimeLog.info("更新数据库"); /*-=notranslate=-*/
TimeLog.logStart();
processer.after(views);
TimeLog.info("写数据库后执行业务规则"); /*-=notranslate=-*/
// 此处释放session变量以免浪费内存
BSContext.getInstance().removeSession(Rewrite32Para.class.getName());
}
@Override
public void rewirte30ForCredit(Rewrite32Para[] paras) throws BusinessException {
Map<String, Rewrite32Para> index = this.prepareParams(paras);
SaleOrderViewVO[] views = this.query(index);
AroundProcesser<SaleOrderViewVO> processer = new AroundProcesser<SaleOrderViewVO>(
ServicePlugInPoint.rewrite30NumFor32);
processer
.addBeforeRule(new RenovateARByBidsBeginRule(M30EngrossAction.M30InvoiceReWrite));
processer
.addAfterRule(new RenovateARByBidsEndRule(M30EngrossAction.M30InvoiceReWrite));
processer.before(views);
processer.after(views);
}
}

View File

@ -209,7 +209,7 @@ public class Rewrite30For33Impl implements IRewrite30For33 {
// --------------------------------------
// 更新信用调用后
processer.addAfterRule(new RenovateARByBidsEndRule(engrossAction));
// 谿꼍CLM북谿饋簡땐데
// 谿꼍CLM북谿饋簡땐데-작셕횅훰壇澗쏜띨
processer.addAfterRule(new SyncClmNumRule("ntotalarmny"));
}

View File

@ -0,0 +1,115 @@
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//
package nc.pubimpl.so.m30.so.withdraw;
import java.util.HashMap;
import java.util.Map;
import nc.bs.so.m30.plugin.ServicePlugInPoint;
import nc.bs.so.m30.rule.maintainprocess.NullRule;
import nc.bs.so.m30.rule.maintainprocess.RewriteReturnNumRule;
import nc.bs.so.m30.rule.rewrite.m30.CheckWithdrawNumRule;
import nc.impl.pubapp.env.BSContext;
import nc.impl.pubapp.pattern.data.view.ViewQuery;
import nc.impl.pubapp.pattern.data.view.ViewUpdate;
import nc.impl.pubapp.pattern.rule.IRule;
import nc.impl.pubapp.pattern.rule.processer.AroundProcesser;
import nc.pubimpl.so.rule.SyncClmNumRule;
import nc.pubitf.so.m30.so.withdraw.IRewriteSaleOrderByWithdraw;
import nc.pubitf.so.m30.so.withdraw.Rewrite30Para;
import nc.vo.ml.NCLangRes4VoTransl;
import nc.vo.pub.BusinessException;
import nc.vo.pub.lang.UFDouble;
import nc.vo.pubapp.pattern.exception.ExceptionUtils;
import nc.vo.pubapp.pattern.log.TimeLog;
import nc.vo.pubapp.pattern.pub.MathTool;
import nc.vo.so.m30.entity.SaleOrderBVO;
import nc.vo.so.m30.entity.SaleOrderViewVO;
public class RewriteSaleOrderByWitdrawImpl implements IRewriteSaleOrderByWithdraw {
public RewriteSaleOrderByWitdrawImpl() {
}
public void rewrite30NumForWithdraw(Rewrite30Para[] paras) throws BusinessException {
try {
this.rewrite(paras);
} catch (RuntimeException ex) {
ExceptionUtils.marsh(ex);
}
}
private void addAfterRule(AroundProcesser<SaleOrderViewVO> processer) {
processer.addAfterRule(new NullRule());
processer.addAfterRule(new RewriteReturnNumRule());
// 同步CLM合同销售订单-累计退货主数量
processer.addAfterRule(new SyncClmNumRule("ntotalreturnnum"));
}
private void addBeforeRule(AroundProcesser<SaleOrderViewVO> processer) {
IRule<SaleOrderViewVO> rule = new CheckWithdrawNumRule();
processer.addBeforeRule(rule);
}
private Map<String, Rewrite30Para> prepareParams(Rewrite30Para[] paras) {
Map<String, Rewrite30Para> index = new HashMap();
for(Rewrite30Para para : paras) {
index.put(para.getCsaleorderbid(), para);
}
return index;
}
private SaleOrderViewVO[] query(Map<String, Rewrite30Para> index) {
String[] ids = (String[])index.keySet().toArray(new String[0]);
ViewQuery<SaleOrderViewVO> bo = new ViewQuery(SaleOrderViewVO.class);
bo.setSharedHead(true);
SaleOrderViewVO[] views = (SaleOrderViewVO[])bo.query(ids);
if (views.length != index.size()) {
String message = NCLangRes4VoTransl.getNCLangRes().getStrByID("4006011_0", "04006011-0171");
ExceptionUtils.wrappBusinessException(message);
}
return views;
}
private void rewrite(Rewrite30Para[] paras) {
TimeLog.logStart();
Map<String, Rewrite30Para> index = this.prepareParams(paras);
TimeLog.logStart();
SaleOrderViewVO[] views = this.query(index);
TimeLog.info("查询销售订单表体");
BSContext.getInstance().setSession(Rewrite30Para.class.getName(), index);
AroundProcesser<SaleOrderViewVO> processer = new AroundProcesser(ServicePlugInPoint.rewrite30NumForWithdraw);
for(SaleOrderViewVO viewvo : views) {
this.setRewiteNum(viewvo, index);
}
TimeLog.logStart();
this.addBeforeRule(processer);
processer.before(views);
TimeLog.info("调用回写动作前插入点");
TimeLog.logStart();
String[] names = new String[]{"ntotalreturnnum"};
ViewUpdate<SaleOrderViewVO> bo = new ViewUpdate();
views = (SaleOrderViewVO[])bo.update(views, SaleOrderBVO.class, names);
TimeLog.info("更新数据库");
TimeLog.logStart();
this.addAfterRule(processer);
processer.after(views);
TimeLog.info("调用回写动作后插入点");
BSContext.getInstance().removeSession(Rewrite30Para.class.getName());
}
private void setRewiteNum(SaleOrderViewVO vo, Map<String, Rewrite30Para> index) {
SaleOrderBVO body = vo.getBody();
Rewrite30Para para = (Rewrite30Para)index.get(body.getCsaleorderbid());
UFDouble ntotalreturnnum = body.getNtotalreturnnum();
ntotalreturnnum = MathTool.sub(ntotalreturnnum, para.getNnum());
body.setNtotalreturnnum(ntotalreturnnum);
}
}

View File

@ -64,7 +64,7 @@ public class Rewrite30ArrangeImpl implements IRewrite30For20, IRewrite30For21,
processer.addBeforeRule(new RewriteCheckArrangeNumRule());
processer.addBeforeRule(new RewriteSetNumRule());
if (MMBillType.ProduceOrder.getCode().equals(srctype.getCode()) || MMBillType.LsProduceOrder.getCode().equals(srctype.getCode())) {
// 谿꼍CLM북谿饋簡땐데
// 同步CLM合同销售订单-累计安排生产订单主数量
processer.addAfterRule(new SyncClmNumRule("narrangemonum"));
}
}

View File

@ -38,9 +38,9 @@ public class SyncClmNumRule implements IRule<SaleOrderViewVO> {
if (StringUtils.isEmpty(vdef9) || StringUtils.isEmpty(vbdef11)) {
continue;
}
// 累计安排生产订单主数量
UFDouble narrangemonum = body.getNarrangemonum();
if ("narrangemonum".equals(flag) && narrangemonum == null) {
// 累计开票主数量
UFDouble ntotalinvoicenum = body.getNtotalinvoicenum();
if ("ntotalinvoicenum".equals(flag) && ntotalinvoicenum == null) {
continue;
}
// ÀÛ¼ÆÈ·ÈÏÓ¦ÊÕ½ðî
@ -48,17 +48,43 @@ public class SyncClmNumRule implements IRule<SaleOrderViewVO> {
if ("ntotalarmny".equals(flag) && ntotalarmny == null) {
continue;
}
// 累计出库数量
UFDouble ntotaloutnum = body.getNtotaloutnum();
if ("ntotaloutnum".equals(flag) && ntotaloutnum == null) {
continue;
}
// 累计安排生产订单主数量
UFDouble narrangemonum = body.getNarrangemonum();
if ("narrangemonum".equals(flag) && narrangemonum == null) {
continue;
}
// 累计退货主数量
UFDouble ntotalreturnnum = body.getNtotalreturnnum();
if ("ntotalreturnnum".equals(flag) && ntotalreturnnum == null) {
continue;
}
JSONObject oneJson = new JSONObject();
List<Map<String, Object>> bodyList = new ArrayList<>();
Map<String, Object> bodyMap = new HashMap<>();
bodyMap.put("id", vbdef11);
if (narrangemonum != null) {
bodyMap.put("narrangemonum", narrangemonum.toString());
if (ntotalinvoicenum != null) {
bodyMap.put("billQty", ntotalinvoicenum.toString());
}
if (ntotalarmny != null) {
bodyMap.put("totalAccrued", ntotalarmny.toString());
}
if (ntotaloutnum != null) {
bodyMap.put("totalOutQty", ntotaloutnum.toString());
}
if (narrangemonum != null) {
bodyMap.put("narrangemonum", narrangemonum.toString());
}
if (ntotalreturnnum != null) {
bodyMap.put("ntotalreturnnum", ntotalreturnnum.toString());
}
bodyList.add(bodyMap);