yonbip-code-gen-mcp
Version:
YonBIP高级版代码生成MCP
879 lines (828 loc) • 42.4 kB
Markdown
# 采购订单生成付款计划时追加制单人信息
1. 业务处理要求
* 在`getPayPlanBillVOData`方法中将采购订单制单人(billmaker)设置给付款计划制单人上(billmaker)
2. 高级版2505版本源码如下
```java
package nc.pubitf.pu.m21p.util;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import nc.impl.scmpub.payterm.AbstractRecvPayPlan;
import nc.vo.bd.payment.IPaymentUtil;
import nc.vo.pu.m21.entity.OrderHeaderVO;
import nc.vo.pu.m21.entity.OrderItemVO;
import nc.vo.pu.m21.entity.OrderPaymentVO;
import nc.vo.pu.m21.entity.OrderVO;
import nc.vo.pu.m21.entity.PayPlanBillVO;
import nc.vo.pu.m21.entity.PayPlanItemVO;
import nc.vo.pu.m21.entity.PayPlanVO;
import nc.vo.pu.m21p.pub.RelationCalculateToolsFor21PUtils;
import nc.vo.pu.pub.constant.PUParaValue;
import nc.vo.pu.pub.util.PUSysParamUtil;
import nc.vo.pu.pub.util.PubSysParamUtil;
import nc.vo.pub.lang.UFBoolean;
import nc.vo.pub.lang.UFDate;
import nc.vo.pub.lang.UFDouble;
import nc.vo.pubapp.AppContext;
import nc.vo.pubapp.pattern.pub.MathTool;
import nc.vo.pubapp.scale.ScaleUtils;
import nc.vo.scmpub.payterm.pay.AbstractPayPlanVO;
import nc.vo.scmpub.res.billtype.POBillType;
import nc.vo.scmpub.res.para.NCPara;
import nc.vo.scmpub.util.BillBodySortUtils;
import nc.vo.scmpub.util.CollectionUtils;
import nc.vo.scmpub.util.StringUtil;
import nc.vo.scmpub.util.payterm.PayTermUtil;
import nccloud.commons.lang.ArrayUtils;
/**
* @description 采购订单审批生成采购订单付款计划工具类
* @author yinl
* @date 2022年8月25日 下午1:46:04
* @version ncc1.0
*/
public class PayPlanBillVODataUtil {
/**
* 金额字段数组(下标要和orderBidToSub中对应的金额字段下标一直)
* 0-税额-NTAX,1-本币金额-NMNY,2-无税金额-NORDERORIGMNY,
* 3-本币无税金额-NORDERMNY,4-价税合计-NORIGTAXMNY,
* 5-计税金额-NCALTAXMNY,6-计成本金额-NCALCOSTMNY,
* 7-不可抵扣税额-NNOSUBTAX,8-全局本币无税金额-NGLOBALMNY,
* 9-全局本币价税合计-NGLOBALTAXMNY,10-集团本币无税金额-NGROUPMNY,
* 11-集团本币价税合计-NGROUPTAXMNY
*/
private String[] mnyArrs = new String[] {
PayPlanItemVO.NTAX, PayPlanItemVO.NMNY, PayPlanItemVO.NORDERORIGMNY,
PayPlanItemVO.NORDERMNY, PayPlanItemVO.NORIGTAXMNY,
PayPlanItemVO.NCALTAXMNY, PayPlanItemVO.NCALCOSTMNY,
PayPlanItemVO.NNOSUBTAX, PayPlanItemVO.NGLOBALMNY,
PayPlanItemVO.NGLOBALTAXMNY, PayPlanItemVO.NGROUPMNY,
PayPlanItemVO.NGROUPTAXMNY
};
/**
* Map<付款计划金额字段,订单表体金额字段>
* 用于找到付款计划表体和订单表体金额对应的关系,获取订单上的金额字段,计算尾差使用
*/
private Map<String, String> planToOrderMnyKeys =
new HashMap<String, String>();
/**
* 单价字段
* 0-主本币无税单价,1-主无税单价,2- 主含税单价,3- 主本币含税单价
*
* 用于恢复付款计划单价使用,付款计划表体的单价金额算法,以原币金额驱动,由于数量是计算过的,单价可能会变动,
* 但是,生成付款计划的时候,单价是不变的才对,这里做个备份,计算完成之后,付款计划子表单价恢复成订单单价
*/
public String[] priceArrs = new String[] {
PayPlanItemVO.NORDERPRICE, PayPlanItemVO.NORDERORIGPRICE,
PayPlanItemVO.NORDERORIGTAXPRICE, PayPlanItemVO.NORDERTAXPRICE
};
/**
* Map<付款计划单价字段,订单单价字段>
* 用于恢复付款计划单价使用,付款计划表体的单价金额算法,以原币金额驱动,由于数量是计算过的,单价可能会变动,
* 但是,生成付款计划的时候,单价是不变的才对,这里做个备份,计算完成之后,付款计划子表单价恢复成订单单价
*/
private Map<String, String> planToOrderPriceKeys =
new HashMap<String, String>();
/** 原币金额字段集合,用于设置金额字段精度使用 */
private List<String> oriMnyKeyList = new ArrayList<String>();
/** 金额字段集合,用于设置金额字段精度使用 */
private List<String> mnyKeyList = new ArrayList<String>();
/** 金额字段集合,用于设置金额字段精度使用 */
private List<String> glogalAndGroupMnyKeyList = new ArrayList<String>();
public PayPlanBillVODataUtil() {
// 原币金额字段
oriMnyKeyList.add(PayPlanItemVO.NORDERORIGMNY);// 2-无税金额-NORDERORIGMNY
oriMnyKeyList.add(PayPlanItemVO.NORIGTAXMNY);// 4-价税合计-NORIGTAXMNY
// 本币金额字段
mnyKeyList.add(PayPlanItemVO.NTAX);// 0-税额-NTAX
mnyKeyList.add(PayPlanItemVO.NMNY);// 1-本币金额-NMNY
mnyKeyList.add(PayPlanItemVO.NORDERMNY);// 3-本币无税金额-NORDERMNY
mnyKeyList.add(PayPlanItemVO.NCALTAXMNY);// 5-计税金额-NCALTAXMNY
mnyKeyList.add(PayPlanItemVO.NCALCOSTMNY);// 6-计成本金额-NCALCOSTMNY
mnyKeyList.add(PayPlanItemVO.NNOSUBTAX);// 7-不可抵扣税额-NNOSUBTAX
mnyKeyList.add(PayPlanItemVO.NGLOBALMNY);// 8-全局本币无税金额-NGLOBALMNY
mnyKeyList.add(PayPlanItemVO.NGLOBALTAXMNY);// // 9-全局本币价税合计-NGLOBALTAXMNY
mnyKeyList.add(PayPlanItemVO.NGROUPMNY);// // 10-集团本币无税金额-NGROUPMNY
mnyKeyList.add(PayPlanItemVO.NGROUPTAXMNY);// 11-集团本币价税合计-NGROUPTAXMNY
// 全局、集团本币字段
glogalAndGroupMnyKeyList.add(PayPlanItemVO.NGLOBALMNY);// 8-全局本币无税金额-NGLOBALMNY
glogalAndGroupMnyKeyList.add(PayPlanItemVO.NGLOBALTAXMNY);// 9-全局本币价税合计-NGLOBALTAXMNY
glogalAndGroupMnyKeyList.add(PayPlanItemVO.NGROUPMNY);// 10-集团本币无税金额-NGROUPMNY
glogalAndGroupMnyKeyList.add(PayPlanItemVO.NGROUPTAXMNY);// 11-集团本币价税合计-NGROUPTAXMNY
// 设置集合Map<付款计划金额字段,订单表体金额字段>,用于计算尾差
planToOrderMnyKeys.put(PayPlanItemVO.NTAX, OrderItemVO.NTAX);// 0-本币税额
planToOrderMnyKeys.put(PayPlanItemVO.NMNY, OrderItemVO.NTAXMNY);// 1-本币金额
planToOrderMnyKeys.put(PayPlanItemVO.NORDERORIGMNY, OrderItemVO.NORIGMNY);// 2-无税金额
planToOrderMnyKeys.put(PayPlanItemVO.NORDERMNY, OrderItemVO.NMNY);// 3-无税金额
planToOrderMnyKeys.put(PayPlanItemVO.NORIGTAXMNY, OrderItemVO.NORIGTAXMNY);// 4-价税合计
planToOrderMnyKeys.put(PayPlanItemVO.NCALTAXMNY, OrderItemVO.NCALTAXMNY);// 5-计税金额
planToOrderMnyKeys.put(PayPlanItemVO.NCALCOSTMNY, OrderItemVO.NCALCOSTMNY);// 6-记成本金额
planToOrderMnyKeys.put(PayPlanItemVO.NNOSUBTAX, OrderItemVO.NNOSUBTAX);// 7-不可抵扣税额
planToOrderMnyKeys.put(PayPlanItemVO.NGLOBALMNY, OrderItemVO.NGLOBALMNY);// 8-全局本币无税金额
planToOrderMnyKeys.put(PayPlanItemVO.NGLOBALTAXMNY,
OrderItemVO.NGLOBALTAXMNY);// 9-全局本币价税合计
planToOrderMnyKeys.put(PayPlanItemVO.NGROUPMNY, OrderItemVO.NGROUPMNY);// 10-集团本币无税金额
planToOrderMnyKeys.put(PayPlanItemVO.NGROUPTAXMNY,
OrderItemVO.NGROUPTAXMNY);// 11-集团本币价税合计
// Map<付款计划单价字段,订单单价字段>
planToOrderPriceKeys.put(PayPlanItemVO.NORDERPRICE, OrderItemVO.NPRICE);// 0-主本币无税单价
planToOrderPriceKeys.put(PayPlanItemVO.NORDERORIGPRICE,
OrderItemVO.NORIGPRICE); // 1-主无税单价
planToOrderPriceKeys.put(PayPlanItemVO.NORDERORIGTAXPRICE,
OrderItemVO.NORIGTAXPRICE);// 2- 主含税单价
planToOrderPriceKeys.put(PayPlanItemVO.NORDERTAXPRICE,
OrderItemVO.NTAXPRICE);// 3- 主本币含税单价
}
/**
* 里程碑采购添加,获取聚合的采购订单付款计划vo
* @param vos 采购订单VO
* @return 采购订单付款计划聚合VO
*
*/
public PayPlanBillVO[] getPayPlanBillVOData(OrderVO[] vos) {
List<PayPlanBillVO> payPlanBillList = new ArrayList<PayPlanBillVO>();
for (OrderVO vo : vos) {
/** 1、获取订单的数据,用来组装采购订单付款计划 */
OrderHeaderVO orderHVO = vo.getHVO(); // 采购订单表头
OrderItemVO[] orderItemVOs = vo.getBVO(); // 采购订单表体
OrderPaymentVO[] orderPaymentVOs = vo.getPaymentVO(); // 采购订单付款协议
if (ArrayUtils.isEmpty(orderPaymentVOs)) {
orderPaymentVOs = new OrderPaymentVO[] {
new OrderPaymentVO()
};
// 结算方式
orderPaymentVOs[0].setPk_balatype(orderHVO.getPk_balatype());
// 设置默认账期号为1
orderPaymentVOs[0].setShoworder(Integer.valueOf(1));
}
/** 2、通过采购订单,生成采购订单付款计划 */
PayPlanBillVO[] payPlanBillVOs =
this.splitByPtch(orderHVO, orderItemVOs, orderPaymentVOs);
if (ArrayUtils.isEmpty(payPlanBillVOs)) {
continue;
}
else {
// 根据付款计划的付款方式(整单付款、明细付款)
// 采购订单付款计划付款
PUParaValue.po95 po95 = PUSysParamUtil.getPO95(orderHVO.getPk_org());
for (PayPlanBillVO payPlanBillVO : payPlanBillVOs) {
PayPlanVO hvo = payPlanBillVO.getHVO();
// 采购订单付款计划->付款单 付款方式是否为整单付款
if(po95.equals(PUParaValue.po95.BILLPAYMENT)){
hvo.setBbillpay(UFBoolean.TRUE);
}else if (po95.equals(PUParaValue.po95.DETAILPAYMENT)){
hvo.setBbillpay(UFBoolean.FALSE);
}
payPlanBillList.add(payPlanBillVO);
}
}
}
return payPlanBillList.toArray(new PayPlanBillVO[payPlanBillList.size()]);
}
/**
* 里程碑采购添加,获取聚合的采购订单付款计划vo
* 1、先按照采购订单明细行,拆分付款协议,每一个物料行都有一套付款协议
* 2、汇总采购订单付款计划子表信息,形成汇总数据
* 3、组装聚合vo,并设置到list集合中
* @param vos 采购订单VO
* @return 采购订单付款计划聚合VO
*
*/
private PayPlanBillVO[] splitByPtch(OrderHeaderVO orderHVO,
OrderItemVO[] orderItemVOs, OrderPaymentVO[] orderPaymentVOs) {
if (CollectionUtils.isNullForAllTElements(orderItemVOs)) {
return null;
}
/** 1、排序处理,以便后续计算尾差顺序是对的 */
BillBodySortUtils.sort(orderItemVOs);
BillBodySortUtils.sort(orderPaymentVOs, OrderPaymentVO.SHOWORDER);
/** 2、生成付款计划子表数据,先按照采购订单明细行,拆分付款协议,每一个物料行都有一套付款协议,用以组装采购订单付款计划子表信息 */
// 按照采购订单明细行拆分付款计划子表的集合,即每一个明细行都有一套付款计划
Map<String, List<PayPlanItemVO>> payPlanBVOMap =
new HashMap<String, List<PayPlanItemVO>>();
// 付款时点主键结合,用于整理汇总付款计划表头数据使用
List<String> pk_payments = new ArrayList<String>();
// Map<订单表体主键,订单表体vo> - 用于计算尾差使用
Map<String, OrderItemVO> orderBidToBvo = new HashMap<String, OrderItemVO>();
// 生成付款计划子表信息,并整理一些后续需要的集合
// payPlanBVOMap,付款计划子表信息
// pk_payments,付款时点主键集合
this.getPayPlanBVOs(orderHVO, orderItemVOs, orderPaymentVOs, payPlanBVOMap,
pk_payments, orderBidToBvo);
/** 3、获取付款计划组装好的主子表vo */
PayPlanBillVO[] bills =
this.getPayPlanVOs(orderHVO, payPlanBVOMap, pk_payments);
// 价格金额算法,计算全局、集团本位币金额等字段
/** 4、进行单价金额算法*/
for (PayPlanBillVO bill : bills) {
new RelationCalculateToolsFor21PUtils().calculate(bill,
PayPlanItemVO.NORIGMNY);
}
/** 5、计算尾差,单价金额算法结束后,处理税额、无税金额、价税合计的尾差,并汇总表头的本币金额*/
this.processLastDiff(bills, orderBidToBvo);
/** 6、汇总表头本币金额 */
this.sumHeadMny(bills);
return bills;
}
/**
* 获取账期到账日
* @param dbegindate 起算日期
* @param orderPaymentVO 付款协议
* @param paymentday 账期天数
* @return
*
*/
private UFDate getDenddate(UFDate dbegindate, OrderPaymentVO orderPaymentVO) {
// 固定结账日
Integer checkdata = orderPaymentVO.getCheckdata();
Integer accountDate = orderPaymentVO.getAccountday();
Integer effectmonth = orderPaymentVO.getEffectmonth();
Integer effectaddmonth = orderPaymentVO.getEffectaddmonth();
Integer iitermdays = orderPaymentVO.getPaymentday();
return PayTermUtil.getEndDate(dbegindate, iitermdays, checkdata, accountDate, effectmonth, effectaddmonth);
}
/**
* 生成付款计划子表信息
* @param orderHVO 订单表头vo
* @param orderItemVOs 订单明细表体vo
* @param orderPaymentVOs 订单付款协议表体vo
* @param payPlanBVOMap 生成的付款计划子表,Map<付款时点,List<付款计划子表>>
* @param pk_payments 付款时点主键(付款计划表头是按照付款时点主键汇总的)
* @param orderBidToSub Map<订单明细表体主键,[需要计算尾差的各字段数组]>
* 需要计算尾差的各字段数组的结构:
* [0-税额,1-本币金额,2-无税金额,3-本币无税金额,
* 4-价税合计,5-计税金额 ,6-计成本金额,7-不可抵扣税额,
* 8-全局本币无税金额,9-全局本币价税合计,10-集团本币无税金额,11-集团本币价税合计]
* @param orderBidToPrice Map<采购订单表体主键,[单价数组]>
* 单价数组结构:
* [0-订单行主本币无税单价,1-付款计划订单行主无税单价,
* 2-订单行主含税单价,3-订单行主本币含税单价]
*
*/
public void getPayPlanBVOs(OrderHeaderVO orderHVO, OrderItemVO[] orderItemVOs,
OrderPaymentVO[] orderPaymentVOs,
Map<String, List<PayPlanItemVO>> payPlanBVOMap, List<String> pk_payments,
Map<String, OrderItemVO> orderBidToBvo) {
for (OrderItemVO orderItem : orderItemVOs) {
// 获取订单表体主键
String pk_order_b = orderItem.getPk_order_b();
// NCC-365240 赠品行不生成付款计划子表 begin
UFBoolean largess = orderItem.getBlargess();
if(UFBoolean.TRUE.equals(largess)){
continue;
}
// NCC-365240 赠品行不生成付款计划子表 end
// 遍历采购订单付款协议,生成采购订单付款计划子表
UFDouble accNum = UFDouble.ZERO_DBL;// 数量,用于最后一行价税合计倒挤
UFDouble accOrimny = UFDouble.ZERO_DBL;// 金额和值,用于最后一行金额倒挤时使用
UFDouble accNoTaxmny = UFDouble.ZERO_DBL;// 无税金额和值,用于最后一行无税金额倒挤使用
// 设置需要计算尾差的map集合 begin
orderBidToBvo.put(pk_order_b, orderItem);
// 设置需要计算尾差的map集合 end
// 创建精度处理工具
String pk_group = AppContext.getInstance().getPkGroup();
ScaleUtils scale = new ScaleUtils(pk_group);
// 原币币种
String corigcurrencyid = orderHVO.getCorigcurrencyid();
for (int i = 0; i < orderPaymentVOs.length; i++) {
PayPlanItemVO payPlanItem = new PayPlanItemVO();
// 设置一些不需要计算的付款计划子表字段(非付款协议获取数据的字段)
payPlanItem =
PayPlanPubUtils.getPayPlanBVOs(orderHVO, orderItem, payPlanItem);
// 采购订单付款协议主键
String pk_payment = orderPaymentVOs[i].getPk_payment();
if (!pk_payments.contains(pk_payment)) {
pk_payments.add(pk_payment);
}
payPlanItem.setPk_paymentch(pk_payment);
// 备注
payPlanItem.setVmemo(orderItem.getVbmemo());
// 账期号
payPlanItem.setIaccounttermno(orderPaymentVOs[i].getShoworder());
// 起算依据
String effectdata = orderPaymentVOs[i].getPk_payperiod();
payPlanItem.setFeffdatetype(effectdata);
// 起算日期(原逻辑取采购订单的审批日期),需要根据起算日期延迟天数计算出真正的起算日期
UFDate dbegindate = null;
if (IPaymentUtil.PURCHASE_ORDER_APPROVE_DATE.equals(effectdata)) {
UFBoolean breturn = orderHVO.getBreturn();
if (UFBoolean.FALSE.equals(breturn)) {
// 退货不需要更新起算日期
dbegindate = orderHVO.getTaudittime();
}
}
// 起效日期延迟天数
Integer effectdateadddate = orderPaymentVOs[i].getEffectdateadddate();
payPlanItem.setEffectdateadddate(effectdateadddate);
// 根据起算日期延迟天数继续计算起算日期
dbegindate = PayTermUtil.getEffectDate(dbegindate, effectdateadddate);
payPlanItem.setDbegindate(dbegindate);
// 账期天数
Integer paymentday = orderPaymentVOs[i].getPaymentday();
payPlanItem.setIitermdays(paymentday);
// 账期到账日
payPlanItem.setDenddate(this.getDenddate(dbegindate, orderPaymentVOs[i]));
// 预付款
UFBoolean prepayment = orderPaymentVOs[i].getPrepayment();
if (prepayment == null) {
prepayment = UFBoolean.FALSE;
}
payPlanItem.setBpreflag(prepayment);
// 价税合计, 总价税合计(总付款金额)应该是表头的信息 (orderHVO.getNtotalorigmny());
UFDouble norigtaxmny = orderItem.getNorigtaxmny();
UFDouble norigmny = orderItem.getNorigmny();// 无税金额
// 比率
UFDouble rate = orderPaymentVOs[i].getAccrate();
if (rate == null) {
rate = new UFDouble(100);
}
payPlanItem.setNrate(rate);
// 订单的价税合计(付款计划的原币金额)
UFDouble mny = norigtaxmny.multiply(MathTool.nvl(rate)
.div(AbstractRecvPayPlan.UF100, UFDouble.DEFAULT_POWER));
mny = scale.adjustMnyScale(mny, corigcurrencyid);
// 无税金额
UFDouble noTaxMny = norigmny.multiply(MathTool.nvl(rate)
.div(AbstractRecvPayPlan.UF100, UFDouble.DEFAULT_POWER));
noTaxMny = scale.adjustMnyScale(noTaxMny, corigcurrencyid);
if (i < orderPaymentVOs.length - 1) {
// 计算金额
payPlanItem.setNorigmny(mny);
payPlanItem.setNorigtaxmny(mny);// 价税合计
accOrimny = MathTool.add(accOrimny, mny);
accNoTaxmny = MathTool.add(accNoTaxmny, noTaxMny);
}
else {
// 最后一行倒挤
payPlanItem.setNorigmny(MathTool.sub(norigtaxmny, accOrimny));
payPlanItem.setNorigtaxmny(MathTool.sub(norigtaxmny, accOrimny));// 价税合计
payPlanItem.setLastAccoutTerm(true);
payPlanItem.setNorderorigmny(MathTool.sub(norigmny, accNoTaxmny));// 无税金额
}
// 序号
payPlanItem.setCrowno(String.valueOf(10 * (i + 1)));
// 质保金
payPlanItem.setIsdeposit(orderPaymentVOs[i].getIsdeposit());
// 结算方式
payPlanItem.setPk_balatype(orderPaymentVOs[i].getPk_balatype());
// 订单行主数量
UFDouble orderItemNnum = orderItem.getNnum();
// NCC-171729 主数量(本次确认主数量) 这里处理进度,和采购发票保持一致 begin
UFDouble nnum = orderItemNnum.multiply(MathTool.nvl(rate)
.div(AbstractRecvPayPlan.UF100, UFDouble.DEFAULT_POWER));
UFDouble updateNum = UFDouble.ZERO_DBL;
String cunitid = orderItem.getCunitid();
if (i < orderPaymentVOs.length - 1) {
updateNum = scale.adjustNumScale(nnum, cunitid);
accNum = MathTool.add(accNum, updateNum);
}
else {
// 求尾差
updateNum = MathTool.sub(orderItemNnum, accNum);
}
payPlanItem.setNnum(updateNum);
// NCC-171729 主数量(本次确认主数量) 这里处理进度,和采购发票保持一致 end
// 价格金额算法
if (payPlanBVOMap.containsKey(pk_payment)) {
payPlanBVOMap.get(pk_payment).add(payPlanItem);
}
else {
// 采购订单付款计划子表List集合
List<PayPlanItemVO> payPlanBVOList = new ArrayList<PayPlanItemVO>();
payPlanBVOList.add(payPlanItem);
payPlanBVOMap.put(pk_payment, payPlanBVOList);
}
}
}
}
/**
* 获取付款计划主子表
* @param orderHVO 订单表头数据
* @param payPlanBVOMap 生成的付款计划子表,Map<付款时点,List<付款计划子表>>
* @param pk_payments 付款时点主键(付款计划表头是按照付款时点主键汇总的)
* @return
*/
public PayPlanBillVO[] getPayPlanVOs(OrderHeaderVO orderHVO,
Map<String, List<PayPlanItemVO>> payPlanBVOMap,
List<String> pk_payments) {
List<PayPlanBillVO> panPlanList = new ArrayList<PayPlanBillVO>();
int hvoCrowno = 0;// 采购订单付款计划表头的序号基数,后面会乘以10
for (int i = 0; i < pk_payments.size(); i++) {
String pk_paymentList = pk_payments.get(i);
PayPlanBillVO payPlan = new PayPlanBillVO();
// 设置采购订单付款计划子表信息
List<PayPlanItemVO> payPlanBVOs = payPlanBVOMap.get(pk_paymentList);
PayPlanItemVO[] payPlanItems =
payPlanBVOs.toArray(new PayPlanItemVO[payPlanBVOs.size()]);
payPlan.setBVO(payPlanItems);
// 设置采购订单付款计划表头信息(汇总信息)
PayPlanVO payPlanHVO = this.getPayPlanHVO(pk_paymentList, orderHVO,
payPlanItems, ++hvoCrowno);
payPlan.setHVO(payPlanHVO);
/** 4、组装聚合vo,并设置到list集合中,用以返回组装好的采购订单付款计划聚合vo数据 */
// 将设置好的聚合VO设置到返回的list中
panPlanList.add(payPlan);
}
PayPlanBillVO[] bills =
panPlanList.toArray(new PayPlanBillVO[panPlanList.size()]);
return bills;
}
/**
* 组装采购订单付款计划表头VO
* @param pk_payment 采购订单付款协议主键
* @param orderHVO 采购订单表头数据
* @param payPlanItems 采购订单付款计划表体数据
* @param hvoCrowno 采购订单付款计划表头序号基数,乘以10作为采购订单付款计划表头的序号使用
* @return
*
*/
public PayPlanVO getPayPlanHVO(String pk_payment, OrderHeaderVO orderHVO,
PayPlanItemVO[] payPlanItems, int hvoCrowno) {
BillBodySortUtils.sort(payPlanItems);// 排一下序
// 存放已经设置过数值的字段,例如表头的应付财务组织,设置过之后,如果发现表体的应付组织不完全相同,则需要清空,后续不再设置
Set<String> hadSetValue = new HashSet<String>();
PayPlanVO payPlanHVO = new PayPlanVO();
// 集团
payPlanHVO.setPk_group(orderHVO.getPk_group());
// 采购组织
payPlanHVO.setPk_org(orderHVO.getPk_org());
payPlanHVO.setPk_org_v(orderHVO.getPk_org_v());
// 采购订单主键
payPlanHVO.setPk_order(orderHVO.getPk_order());
// 采购订单编码(单据号)
payPlanHVO.setVordercode(orderHVO.getVbillcode());
// 采购订单单据日期
payPlanHVO.setVorderbilldate(orderHVO.getDbilldate());
// 采购订单单据类型、交易类型、交易类型编码
payPlanHVO.setVordertype(POBillType.Order.getCode());
payPlanHVO.setVordertrantype(orderHVO.getCtrantypeid());
payPlanHVO.setVordertrantypecode(orderHVO.getVtrantypecode());
// 供应商
payPlanHVO.setCvendorid(orderHVO.getPk_supplier());
payPlanHVO.setCvendorvid(orderHVO.getPk_supplier_v());
// 开票供应商
payPlanHVO.setPk_invcsupllier(orderHVO.getPk_invcsupllier());
payPlanHVO.setPk_invcsupllier_v(orderHVO.getPk_invcsupllier_v());
// 散户
payPlanHVO.setPk_freecust(orderHVO.getPk_freecust());
// 质保金
payPlanHVO.setIsdeposit(payPlanItems[0].getIsdeposit());
// 账期号(付款计划子表的账期号都一样,都取自付款协议)
payPlanHVO.setIaccounttermno(payPlanItems[0].getIaccounttermno());
// 起算依据(付款计划子表的起算依据都一样,都取自付款协议)
payPlanHVO.setFeffdatetype(payPlanItems[0].getFeffdatetype());
// 账期天数(付款计划子表的账期天数都一样,都取自付款协议)
payPlanHVO.setIitermdays(payPlanItems[0].getIitermdays());
// 起效日期延迟天数(付款计划子表起效日期延迟天数都一样,都取自付款协议)
payPlanHVO.setEffectdateadddate(payPlanItems[0].getEffectdateadddate());
// 付款协议主键
payPlanHVO.setPk_paytermch(pk_payment);
// 付款协议参照
String pk_payterm = orderHVO.getPk_payterm();
payPlanHVO.setPk_payterm(pk_payterm);
// 预付款(付款计划子表的预付款都一样,都取自付款协议)
payPlanHVO.setBpreflag(payPlanItems[0].getBpreflag());
// 比率(%)(付款计划子表的比率(%)都一样,都取自付款协议)
payPlanHVO.setNrate(payPlanItems[0].getNrate());
// 币种
payPlanHVO.setCorigcurrencyid(orderHVO.getCorigcurrencyid());
// 开户银行
payPlanHVO.setPk_bankdoc(orderHVO.getPk_bankdoc());
// 退货
payPlanHVO.setBreturn(orderHVO.getBreturn());
// 冻结
payPlanHVO.setBfrozen(orderHVO.getBfrozen());
// 业务流程
payPlanHVO.setPk_busitype(orderHVO.getPk_busitype());
// 整单扣税类别
payPlanHVO.setFhtaxtypeflag(orderHVO.getFhtaxtypeflag());
// 整单税率
payPlanHVO.setNhtaxrate(orderHVO.getNhtaxrate());
// 贸易术语
payPlanHVO.setCtradewordid(orderHVO.getCtradewordid());
// 结算方式 与05金盘一致,取表头
if (payPlanItems[0].getPk_balatype() != null) {
// 如果表体有,就取表体的,如果表体没有,就取表头的
payPlanHVO.setPk_balatype(payPlanItems[0].getPk_balatype());
}
else {
payPlanHVO.setPk_balatype(orderHVO.getPk_balatype());
}
// 总重量
payPlanHVO.setNtotalweight(orderHVO.getNtotalweight());
// 总体积
payPlanHVO.setNtotalvolume(orderHVO.getNtotalvolume());
// 总件数
payPlanHVO.setNtotalpiece(orderHVO.getNtotalpiece());
// 项目
payPlanHVO.setPk_project(orderHVO.getPk_project());
// 制单人
payPlanHVO.setBillmaker(orderHVO.getBillmaker());
// 制单日期
payPlanHVO.setDmakedate(orderHVO.getDmakedate());
// 采购员
payPlanHVO.setCemployeeid(orderHVO.getCemployeeid());
// 采购部门
payPlanHVO.setPk_dept(orderHVO.getPk_dept());
// 采购部门vid
payPlanHVO.setPk_dept_v(orderHVO.getPk_dept_v());
// 里程碑采购(付款计划子表的里程碑采购数都一样,都取自采购订单表头)
payPlanHVO.setBismilepost(payPlanItems[0].getBismilepost());
for (PayPlanItemVO payPlanItemVO : payPlanItems) {
// 应付财务组织(如果表体行的应付财务组织相同再给表头赋值,否则不赋值)
String pk_financeorg = payPlanHVO.getPk_financeorg();
String pk_financeorgItem = payPlanItemVO.getPk_financeorg();
String pk_financeorg_vItem = payPlanItemVO.getPk_financeorg_v();
String ccurrencyid = payPlanItemVO.getCcurrencyid();// 本币币种
if (pk_financeorg == null
&& !hadSetValue.contains(AbstractPayPlanVO.PK_FINANCEORG)) {
hadSetValue.add(AbstractPayPlanVO.PK_FINANCEORG);
payPlanHVO.setPk_financeorg(pk_financeorgItem);
payPlanHVO.setPk_financeorg_v(pk_financeorg_vItem);
payPlanHVO.setCcurrencyid(ccurrencyid);
}
else if (pk_financeorg != null
&& !pk_financeorg.equals(pk_financeorgItem)) {
payPlanHVO.setPk_financeorg(null);
payPlanHVO.setPk_financeorg_v(null);
payPlanHVO.setCcurrencyid(null);
}
// 序号
payPlanHVO.setCrowno(String.valueOf(10 * hvoCrowno));
// 起算日期(取表体最新的起算日期),账期到账日(取表体最新的账期到账日即可,表体在组装的时候已经计算过了)
UFDate dbegindate = payPlanHVO.getDbegindate();
UFDate dbegindateItem = payPlanItemVO.getDbegindate();
UFDate denddateItem = payPlanItemVO.getDenddate();
if (dbegindate == null) {
payPlanHVO.setDbegindate(dbegindateItem);
payPlanHVO.setDenddate(denddateItem);
}
else {
if (dbegindate.compareTo(dbegindateItem) < 0) {
payPlanHVO.setDbegindate(dbegindateItem);
payPlanHVO.setDenddate(denddateItem);
}
}
// 金额
UFDouble norigmny = payPlanHVO.getNorigmny();
UFDouble norigmnyItem = payPlanItemVO.getNorigmny();
payPlanHVO.setNorigmny(MathTool.add(norigmny, norigmnyItem));
// 本币金额
UFDouble nmny = payPlanHVO.getNmny();
UFDouble nmnyItem = payPlanItemVO.getNmny();
payPlanHVO.setNmny(MathTool.add(nmny, nmnyItem));
// 折本汇率(付款计划子表的折本汇率如果一致,则给表头赋值,否则不赋值)
this.setGatherPayPlanHVO(payPlanHVO, payPlanItemVO,
AbstractPayPlanVO.NEXCHANGERATE, hadSetValue);
// 组织汇率类型(付款计划子表的组织汇率类型如果一致,则给表头赋值,否则不赋值)
this.setGatherPayPlanHVO(payPlanHVO, payPlanItemVO,
AbstractPayPlanVO.CRATETYPE, hadSetValue);
// 组织汇率类别(付款计划子表的组织汇率类别如果一致,则给表头赋值,否则不赋值)
this.setGatherPayPlanHVO(payPlanHVO, payPlanItemVO,
AbstractPayPlanVO.FRATECATEGORY, hadSetValue);
// 组织汇率来源日期(付款计划子表的组织汇率来源日期如果一致,则给表头赋值,否则不赋值)
this.setGatherPayPlanHVO(payPlanHVO, payPlanItemVO,
AbstractPayPlanVO.DRATEDATE, hadSetValue);
// 合同号(付款计划子表的合同号如果一致,则给表头赋值,否则不赋值)
this.setGatherPayPlanHVO(payPlanHVO, payPlanItemVO,
OrderItemVO.CCONTRACTID, hadSetValue);
}
// 总数量
payPlanHVO.setNtotalastnum(orderHVO.getNtotalastnum());
// 总价税合计
payPlanHVO.setNtotalorigmny(orderHVO.getNtotalorigmny());
// 审批时间
payPlanHVO.setTaudittime(orderHVO.getTaudittime());
// 审批人
payPlanHVO.setApprover(orderHVO.getApprover());
// 备注
payPlanHVO.setVmemo(orderHVO.getVmemo());
if (StringUtil.isSEmptyOrNull(payPlanHVO.getCcurrencyid())) {
payPlanHVO.setNmny(null);
}
return payPlanHVO;
}
/**
* 处理尾差
* @param bills 付款计划主子表主键
* @param orderBidToBvo Map<采购订单表体主键,采购订单表体>
*
*/
public void processLastDiff(PayPlanBillVO[] bills,
Map<String, OrderItemVO> orderBidToBvo) {
// 将相同物料付款计划子表放在一起
Map<String, List<PayPlanItemVO>> mapItemVO =
new HashMap<String, List<PayPlanItemVO>>();
// Map<订单付款计划表头主键,订单付款计划表头vo>,用于设置付款计划表头的本币金额
Map<String, PayPlanVO> pkToHvo = new HashMap<String, PayPlanVO>();
// 将相同物料子表行放在一起
for (int i = 0; i < bills.length; i++) {
// 设置表头映射,用于设置表头的本币金额,本币金额单价金额算法只计算表体的,表头的金额是表体汇总的
PayPlanVO hvo = bills[i].getHVO();
String pk_order_payplan = hvo.getPk_order_payplan();
pkToHvo.put(pk_order_payplan, hvo);
// 设置表体的映射,计算表体尾差使用
PayPlanItemVO[] itemVOs = bills[i].getBVO();
for (int j = 0; j < itemVOs.length; j++) {
PayPlanItemVO item = itemVOs[j];
List<PayPlanItemVO> listItemVO = new ArrayList<PayPlanItemVO>();
if (mapItemVO.containsKey(itemVOs[j].getPk_order_b())) {
mapItemVO.get(itemVOs[j].getPk_order_b()).add(item);
}
else {
listItemVO.add(item);
mapItemVO.put(itemVOs[j].getPk_order_b(), listItemVO);
}
}
}
String[] pk_order_bs = mapItemVO.keySet().toArray(new String[0]);
// 创建精度处理工具
String pk_group = AppContext.getInstance().getPkGroup();
ScaleUtils scale = new ScaleUtils(pk_group);
// 处理尾差
for (int i = 0; i < pk_order_bs.length; i++) {
PayPlanItemVO[] itemvos =
mapItemVO.get(pk_order_bs[i]).toArray(new PayPlanItemVO[0]);
BillBodySortUtils.sort(itemvos);// 对付款计划进行排序
UFDouble[] accs = new UFDouble[12];
accs[0] = UFDouble.ZERO_DBL;// 0-税额
accs[1] = UFDouble.ZERO_DBL;// 1-本币金额
accs[2] = UFDouble.ZERO_DBL;// 2-无税金额
accs[3] = UFDouble.ZERO_DBL;// 3-本币无税金额
accs[4] = UFDouble.ZERO_DBL;// 4-价税合计
accs[5] = UFDouble.ZERO_DBL;// 5-计税金额
accs[6] = UFDouble.ZERO_DBL;// 6-计成本金额
accs[7] = UFDouble.ZERO_DBL;// 7-不可抵扣税额
accs[8] = UFDouble.ZERO_DBL;// 8-全局本币无税金额
accs[9] = UFDouble.ZERO_DBL;// 9-全局本币价税合计
accs[10] = UFDouble.ZERO_DBL;// 10-集团本币无税金额
accs[11] = UFDouble.ZERO_DBL;// 11-集团本币价税合计
for (int j = 0; j < itemvos.length; j++) {
// 这里把订单的单价设置回付款计划自表上,因为生成付款计划的时候,单价不变才是对的
String pk_order_b = itemvos[j].getPk_order_b();
OrderItemVO orderItemVO = orderBidToBvo.get(pk_order_b);
if (orderItemVO != null) {
// 恢复单价
// this.setPrice(itemvos[j], orderItemVO);
}
// 以下是求金额尾差逻辑,前面的行先求和,最后一行再求尾差
if (j < itemvos.length - 1) {
// 求和
accs[0] = MathTool.add(accs[0], itemvos[j].getNtax());// 0-税额
accs[1] = MathTool.add(accs[1], itemvos[j].getNmny());// 1-本币金额
accs[2] = MathTool.add(accs[2], itemvos[j].getNorderorigmny());// 2-无税金额
accs[3] = MathTool.add(accs[3], itemvos[j].getNordermny());// 3-无税本币金额
accs[4] = MathTool.add(accs[4], itemvos[j].getNorigtaxmny());// 4-价税合计
accs[5] = MathTool.add(accs[5], itemvos[j].getNcaltaxmny());// 5-计税金额
accs[6] = MathTool.add(accs[6], itemvos[j].getNcalcostmny());// 6-计成本金额
accs[7] = MathTool.add(accs[7], itemvos[j].getNnosubtax());// 7-不可抵扣税额
accs[8] = MathTool.add(accs[8], itemvos[j].getNglobalmny());// 8-全局本币无税金额
accs[9] = MathTool.add(accs[9], itemvos[j].getNglobaltaxmny());// 9-全局本币价税合计
accs[10] = MathTool.add(accs[10], itemvos[j].getNgroupmny());// 10-集团本币无税金额
accs[11] = MathTool.add(accs[11], itemvos[j].getNgrouptaxmny());// 11-集团本币价税合计
}
else {
// 倒挤
this.processLastDiffMnyAndScale(scale, orderBidToBvo, itemvos[j],
accs);
}
}
}
}
/**
* 设置表头的本币金额,重构前是先计算了本币金额,然后汇总到订单表头,重构后,单价金额算法统一计算
* 付款计划表头的本币金额是表体汇总的,因此这里重新汇总一下
* 新增的数据没有主键,没有办法做集合处理,因此,这里统一处理
* @param bills 单价金额算法之后的付款计划
*
*/
private void sumHeadMny(PayPlanBillVO[] bills) {
for (PayPlanBillVO bill : bills) {
UFDouble accHvoMny = UFDouble.ZERO_DBL;
// PayPlanVO hvo = bill.getHVO();
// UFDouble headMny = hvo.getNmny();
PayPlanItemVO[] bvos = bill.getBVO();
for (PayPlanItemVO bvo : bvos) {
UFDouble bodyMny = bvo.getNmny();
accHvoMny = MathTool.add(accHvoMny, bodyMny);
}
bill.getHVO().setNmny(accHvoMny);
}
}
/**
* 设置汇总信息,表体上的数据如果相同,则给表头设置,如果不同则不设置
* @param payPlanHVO 付款计划表头信息
* @param payPlanItem 付款计划表体信息
* @param key 字段
* @param hadSetValue 已经设置过的字段,如果这个集合里面有着字段,则这个字段的值为null时,不需要再设置
*
*/
public void setGatherPayPlanHVO(PayPlanVO payPlanHVO,
PayPlanItemVO payPlanItem, String key, Set<String> hadSetValue) {
Object headValue = payPlanHVO.getAttributeValue(key);
Object bodyValue = payPlanItem.getAttributeValue(key);
if (headValue == null && !hadSetValue.contains(key)) {
hadSetValue.add(key);
payPlanHVO.setAttributeValue(key, bodyValue);
}
else if (headValue != null && !headValue.equals(bodyValue)) {
payPlanHVO.setAttributeValue(key, null);
}
}
/**
* 获取非null的UFDouble类型
* @param number 数值
* @return
*
*/
public UFDouble getUFDouleNotNull(UFDouble number) {
return number == null ? UFDouble.ZERO_DBL : number;
}
/**
* 设置金额的精度,总数-和值=尾差。
* @param scale 精度工具类(调用处已创建对象)
* @param orderBidToBvo Map<采购订单表体主键,采购订单表体>
* @param item 付款计划表体
* @param accs 和值数组(数值的下标对应的业务含义与mnyArrs一致)
*
*/
public void processLastDiffMnyAndScale(ScaleUtils scale,
Map<String, OrderItemVO> orderBidToBvo, PayPlanItemVO item,
UFDouble[] accs) {
String corigcurrencyid = item.getCorigcurrencyid();// 原币币种
String ccurrencyid = item.getCcurrencyid();// 本币币种
String pk_order_b = item.getPk_order_b();
// 总数数组,顺序和mnyArrs一致
OrderItemVO orderItemVO = orderBidToBvo.get(pk_order_b);
if (orderItemVO == null) {
// 修订时删除了物料行,这个表体就找不到了
return;
}
for (int i = 0; i < mnyArrs.length; i++) {
String mnyArr = mnyArrs[i];// 对应的金额字段
// 判断全局NC002是否启用,不启用不处理尾差
if(PayPlanItemVO.NGLOBALMNY.equals(mnyArr) || PayPlanItemVO.NGLOBALTAXMNY.equals(mnyArr)){
String nc002 = PubSysParamUtil.getNC002();
if (NCPara.NC002_NOUSEGLOBALCURRTYPE.getName().equals(nc002)) {
continue;
}
}
// 判断集团NC001是否启用,不启用不处理尾差
if(PayPlanItemVO.NGROUPMNY.equals(mnyArr) || PayPlanItemVO.NGROUPTAXMNY.equals(mnyArr)){
String nc001 = PubSysParamUtil.getNC001(item.getPk_group());
if (NCPara.NC001_NOUSEGROUPCURRTYPE.getName().equals(nc001)) {
continue;
}
}
UFDouble acc = accs[i];// 和值,求尾差使用的
// 获取订单金额,mnyArr是付款计划子表的字段,需要找到对应订单的字段
Object mnyObj =
orderItemVO.getAttributeValue(planToOrderMnyKeys.get(mnyArr));
UFDouble mny = mnyObj == null ? null : (UFDouble) mnyObj;
// 尾差
UFDouble lastDiffNumber = MathTool.sub(mny, acc);
if (oriMnyKeyList.contains(mnyArr)) {
// 处理原币金额精度
item.setAttributeValue(mnyArr,
scale.adjustMnyScale(lastDiffNumber, corigcurrencyid));
}
else if (mnyKeyList.contains(mnyArr)) {
if (glogalAndGroupMnyKeyList.contains(mnyArr) && mny == null) {
// 如果是全局、集团本币金额,没有金额就不需要处理了
continue;
}
// 处理本币金额精度
item.setAttributeValue(mnyArr,
scale.adjustMnyScale(lastDiffNumber, ccurrencyid));
}
}
}
/**
* 设置付款计划子表行上的单价,在付款计划子表行单价金额算法之后,需要把单价恢复成订单的
*
* 设置过程:
* 1、获取付款计划单价字段
* 2、通过 planToOrderPriceKeys 集合,获取到订单上对应的单价字段
* 3、获取订单单价,设置到付款计划子表上
*
* @param item 单价金额算法之后的付款计划子表
* @param orderItemVO 订单表体行数据
*
*/
public void setPrice(PayPlanItemVO item, OrderItemVO orderItemVO) {
for (String priceKey : priceArrs) {
String orderPriceKey = planToOrderPriceKeys.get(priceKey);
Object price = orderItemVO.getAttributeValue(orderPriceKey);
item.setAttributeValue(priceKey, price);
}
}
}
```
3. 检查当前工程下有没有对应的源码类:`nc.pubitf.pu.m21p.util.PayPlanBillVODataUtil`
若存在源码,则在工程的源码中处理要求的业务
若不存在源码,则先按2生成源码,再按要求处理业务
4. 要求
* 不管工程中有没有源码,只需要在业务处理点处理业务,整体不做重构
* 源码的编码格式为GBK,不可修改源码的编码格式