diff --git a/so/src/public/nccloud/api/so/saleinvoice/operator/ApplicationRedInvoiceService.java b/so/src/public/nccloud/api/so/saleinvoice/operator/ApplicationRedInvoiceService.java new file mode 100644 index 0000000..5f214fc --- /dev/null +++ b/so/src/public/nccloud/api/so/saleinvoice/operator/ApplicationRedInvoiceService.java @@ -0,0 +1,190 @@ +package nccloud.api.so.saleinvoice.operator; + +import nc.vo.pub.BusinessException; +import nc.vo.pub.lang.UFDouble; +import nc.vo.pubapp.pattern.log.Log; +import nc.vo.pubapp.pattern.pub.MathTool; +import nc.vo.pubapp.scale.ScaleUtils; +import nc.vo.scmpub.util.ValueCheckUtil; +import nc.vo.so.m32.entity.SaleInvoiceBVO; +import nc.vo.so.m32.entity.SaleInvoiceVO; +import nc.vo.so.m32trantype.entity.M32TranTypeVO; +import nc.vo.so.m32trantype.enumeration.Finvoicetime; +import nc.vo.so.pub.enumeration.BillStatus; +import nc.vo.so.pub.util.AggVOUtil; +import nccloud.framework.core.exception.ExceptionUtils; +import nccloud.framework.service.ServiceLocator; +import nccloud.itf.sscivm.ivsale.service.ExchangeToIvAppService; +import nccloud.pubitf.so.saleinvoice.service.IM32TransTypeService; +import nccloud.web.scmpub.pub.action.group.SysInitGroupQueryNcc; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; + +public class ApplicationRedInvoiceService { + private static final String REDINVOICEMNYDEALFORSSC = "redinvoicemnydealforssc";// 红字发票传开票申请数据处理 + private static final String SL = "sl"; // 税率 + private static final String SESUM = "sesum"; // 税额合计 + private static final String JSHJSUM = "jshjsum"; // 价税合计 + private static final String JESUM = "jesum"; // 无税金额合计 + + /** + * 销售发票判断是否可以开红字发票 + * + * @param vos + * @return + */ + public List> getData(SaleInvoiceVO[] vos) { + Map>> dealMnyMap = new HashMap>>(); + try { + if (!SysInitGroupQueryNcc.isEndable("1058")) { + ExceptionUtils.wrapBusinessException( + nc.vo.ml.NCLangRes4VoTransl.getNCLangRes().getStrByID("4006013_0", "04006013-0038")/* @res "请启用发票管理模块!" */); + } + Map isCanGenerateMap = this.checkInvoiceStatus(AggVOUtil.getPrimaryKeys(vos)); + Map invoicetime = this.qryinvoicetime(vos); + + for (SaleInvoiceVO vo : vos) { + Boolean isCan = isCanGenerateMap.get(vo.getParentVO().getPrimaryKey()); + if (isCan == null || !isCan) { + ExceptionUtils.wrapBusinessException(nc.vo.ml.NCLangRes4VoTransl.getNCLangRes().getStrByID("4006013_0", + "04006013-0039", null, new String[]{vo.getParentVO().getVbillcode()})/* 发票{0}已经开票,不能再进行开票! */); + } + + Integer fstatusflag = vo.getParentVO().getFstatusflag(); + if (null != invoicetime && Finvoicetime.FINVOICETIEMAPPROVEAFTER + .equalsValue(invoicetime.get(vo.getParentVO().getCtrantypeid()).getFinvoicetime())) { + if (!BillStatus.AUDIT.getIntegerValue().equals(fstatusflag)) { + ExceptionUtils.wrapBusinessException(nc.vo.ml.NCLangRes4VoTransl + .getNCLangRes().getStrByID("4006013_0", "04006013-0141", null, new String[]{vo.getParentVO().getVbillcode()})/* @res "发票{0}的状态不是审批通过状态,不能进行红字发票处理!" */); + } + } else if (null != invoicetime && Finvoicetime.FINVOICETIEMAPPROVEBEFORE + .equalsValue(invoicetime.get(vo.getParentVO().getCtrantypeid()).getFinvoicetime())) { + if (BillStatus.AUDIT.getIntegerValue().equals(fstatusflag)) { + if (isCan == null || isCan) { + ExceptionUtils + .wrapBusinessException(nc.vo.ml.NCLangRes4VoTransl.getNCLangRes() + .getStrByID("4006013_0", "04006013-0146", null, new String[]{vo.getParentVO().getVbillcode()})/* @res "发票{0}的交易类型属性税务发票开票时机为先开票后审批通过,已审批通过不允许开票!" */); + } + } + } + } + // 根据税率分组,Map<税率,Map<价税合计,税额>> + dealMnyMap = this.dealMnyForSSC(vos); + } catch (Exception e) { + ExceptionUtils.wrapException(e); + } + return dealMnyMap.get(REDINVOICEMNYDEALFORSSC); + } + + /** + * 检查是否存在已生成、发票未作废的开票申请;能否继续操作 + * + * @param billIds + * @return (true / 未不包含有效下游单据 , 可继续开票 , 或业务单据逆向操作 ; false / 为包含下游单据 , 业务领域控制不允许继续开票 , 或业务单据逆向操作 ;) + * @throws BusinessException + */ + private Map checkInvoiceStatus(String[] billIds) throws BusinessException { + if (ValueCheckUtil.isNullORZeroLength(billIds)) { + return new HashMap(); + } + if (!SysInitGroupQueryNcc.isEndable("1058")) { + return new HashMap(); + } + return ServiceLocator.find(ExchangeToIvAppService.class).checkApplicationStatus(billIds); + } + + /** + * 查询交易类型开票时机 + * + * @param vos + * @throws BusinessException + */ + private Map qryinvoicetime(SaleInvoiceVO[] vos) throws BusinessException { + Map tranttypeMap = new HashMap(); + List trantypeids = new ArrayList(); + // 查询发票交易类型的税务发票开票时机 + for (SaleInvoiceVO vo : vos) { + trantypeids.add(vo.getParentVO().getCtrantypeid()); + } + // 默认先审批通过后开票 + if (null != trantypeids && !trantypeids.isEmpty()) { + try { + IM32TransTypeService service = ServiceLocator.find(IM32TransTypeService.class); + tranttypeMap = service.queryM32TranType(trantypeids.toArray(new String[0])); + } catch (Exception e) { + Log.info(e); + ExceptionUtils.wrapException(e); + } + } + if (null != tranttypeMap && !tranttypeMap.isEmpty()) { + return tranttypeMap; + } + return null; + } + + /** + * 处理表体发票数据,根据税率分组 + * + * @param vos + * @return Map>>:Map>> + * @throws BusinessException + */ + private Map>> dealMnyForSSC(SaleInvoiceVO[] vos) { + Map>> mnyDealForSSCMap = new HashMap>>(); + Map ntaxrateGroupMap = new HashMap(); + for (SaleInvoiceVO vo : vos) { + SaleInvoiceBVO[] bvos = vo.getChildrenVO(); + for (SaleInvoiceBVO bvo : bvos) { + // 税率 + UFDouble ntaxrate = bvo.getNtaxrate(); + // 税额 + UFDouble ntax = bvo.getNtax(); + // 价税合计 + UFDouble norigtaxmny = bvo.getNorigtaxmny(); + // 无税金额 + UFDouble norigmny = bvo.getNorigmny(); + if (ntaxrateGroupMap.containsKey(bvo.getNtaxrate())) { + String dealmny = ntaxrateGroupMap.get(ntaxrate); + String[] splitmny = dealmny.split(","); + UFDouble oldntax = new UFDouble(Double.valueOf(splitmny[0])); + UFDouble oldnorigtaxmny = new UFDouble(Double.valueOf(splitmny[1])); + UFDouble oldnorigmny = new UFDouble(Double.valueOf(splitmny[2])); + UFDouble ntaxsum = MathTool.add(ntax, oldntax); + UFDouble norigtaxmnysum = MathTool.add(norigtaxmny, oldnorigtaxmny); + UFDouble norigmnysum = MathTool.add(norigmny, oldnorigmny); + ntaxrateGroupMap.put(ntaxrate, ntaxsum + "," + norigtaxmnysum + "," + norigmnysum); + } else { + ntaxrateGroupMap.put(ntaxrate, ntax + "," + norigtaxmny + "," + norigmny); + } + } + + List> mnyDealForSSCList = new ArrayList>(); + for (Entry dealmny : ntaxrateGroupMap.entrySet()) { + Map mnyDealforSSCMap = new HashMap(); + UFDouble dealtaxrate = dealmny.getKey(); + String[] splitdealmny = dealmny.getValue().split(","); + UFDouble dealnatx = new UFDouble(Double.valueOf(splitdealmny[0])); + dealnatx = ScaleUtils.adjustScale(dealnatx, 2); + UFDouble dealnorigtaxmny = new UFDouble(Double.valueOf(splitdealmny[1])); + dealnorigtaxmny = ScaleUtils.adjustScale(dealnorigtaxmny, 2); + UFDouble dealnorigmny = new UFDouble(Double.valueOf(splitdealmny[2])); + dealnorigmny = ScaleUtils.adjustScale(dealnorigmny, 2); + // 税率 + mnyDealforSSCMap.put(SL, dealtaxrate.toString()); + // 税额合计 + mnyDealforSSCMap.put(SESUM, dealnatx.toString()); + // 价税合计 + mnyDealforSSCMap.put(JSHJSUM, dealnorigtaxmny.toString()); + // 无税金额合计 + mnyDealforSSCMap.put(JESUM, dealnorigmny.toString()); + mnyDealForSSCList.add(mnyDealforSSCMap); + } + mnyDealForSSCMap.put(REDINVOICEMNYDEALFORSSC, mnyDealForSSCList); + } + return mnyDealForSSCMap; + } +} diff --git a/so/src/public/nccloud/api/so/saleinvoice/operator/IAPISaleInvMaitainImpl.java b/so/src/public/nccloud/api/so/saleinvoice/operator/IAPISaleInvMaitainImpl.java index 4f1a363..b8ca3c2 100644 --- a/so/src/public/nccloud/api/so/saleinvoice/operator/IAPISaleInvMaitainImpl.java +++ b/so/src/public/nccloud/api/so/saleinvoice/operator/IAPISaleInvMaitainImpl.java @@ -5,7 +5,6 @@ import com.alibaba.fastjson.JSONObject; import nc.bs.framework.common.InvocationInfoProxy; import nc.bs.framework.common.NCLocator; import nc.bs.logging.Logger; -import nc.bs.trade.business.HYSuperDMO; import nc.itf.uap.IUAPQueryBS; import nc.jdbc.framework.processor.ColumnProcessor; import nc.jdbc.framework.processor.MapProcessor; @@ -30,7 +29,9 @@ import nccloud.api.baseapp.exchange.convert.OpenApiConvertDataResult; import nccloud.api.rest.utils.ResultMessageUtil; import nccloud.commons.lang.StringUtils; import nccloud.dto.scmpub.script.entity.SCMScriptResultDTO; -import nccloud.itf.sscivm.ivsale.impl.IVApplicationServiceImpl; +import nccloud.framework.core.exception.ExceptionUtils; +import nccloud.framework.service.ServiceLocator; +import nccloud.itf.sscivm.ivsale.service.IVApplicationInvoiceService; import nccloud.pubitf.riart.pflow.CloudPFlowContext; import nccloud.pubitf.riart.pflow.ICloudScriptPFlowService; import nccloud.pubitf.scmpub.commit.service.IBatchRunScriptService; @@ -40,7 +41,6 @@ import nccloud.pubitf.ssctp.sscbd.lientage.ISSClientageMatchService; import org.json.JSONString; import java.math.BigDecimal; -import java.math.RoundingMode; import java.util.List; import java.util.Map; @@ -210,22 +210,12 @@ public class IAPISaleInvMaitainImpl { /** * 开票申请红冲逻辑: - * 1.根据销售发票号查询下游开票申请 - * 2.根据原开票申请生成新红冲 + * 生成开票申请的旧逻辑,走不通已废弃 1.根据销售发票号查询下游开票申请 2.根据原开票申请生成新红冲 + * 新逻辑:根据税务云的发票号查询蓝字发票,根据蓝字和已生成的红字发票共同生成红字的开票申请 */ - String vBillcode = saleInvoiceVOs[0].getParentVO().getVbillcode(); - HYSuperDMO dmo = new HYSuperDMO(); - // 开票申请单主表 - IVApplicationHeadVO[] iVApplicationHeadVO = (IVApplicationHeadVO[]) dmo.queryByWhereClause(IVApplicationHeadVO.class, "src_billno='" + vBillcode + "' and dr=0 "); - String pk_ivapplication = iVApplicationHeadVO[0].getPk_ivapplication(); // 开票申请id - // 开票申请单子表 - IVApplicationBodyVO[] iVApplicationBodyVOs = (IVApplicationBodyVO[]) dmo.queryByWhereClause(IVApplicationBodyVO.class, "pk_ivapplication='" + pk_ivapplication + "' and dr=0 "); - // 调用函数封装开票申请红冲VO - IVApplicationAggVO iVApplicationAggVO = makeNewRedRushIVApplicationAggVO(iVApplicationHeadVO[0], iVApplicationBodyVOs, bject, redVos); - // 生成红冲的开票申请 - IVApplicationServiceImpl serviceImpl = new IVApplicationServiceImpl(); - IVApplicationAggVO returnSaveIVApplicationAggVO = serviceImpl.save(iVApplicationAggVO); + IVApplicationAggVO returnSaveIVApplicationAggVO = saveIVApplication(bject, redVos); if (returnSaveIVApplicationAggVO != null) { + Logger.error("inv-redApply = " + JSONArray.toJSONString(returnSaveIVApplicationAggVO)); // 查询红冲发票信息返回给调用方 return ResultMessageUtil.toJSON(redVos, "接口调用成功"); } else { @@ -661,7 +651,8 @@ public class IAPISaleInvMaitainImpl { newivApplicationHeadVO.setSrc_tradetype(rpSaleInvoiceHVO.getCtrantypeid()); // 来源交易类型 newivApplicationHeadVO.setSrc_pkbusibill(rpSaleInvoiceHVO.getCsaleinvoiceid()); // 来源单据id newivApplicationHeadVO.setSrc_billno(rpSaleInvoiceHVO.getVbillcode()); // 来源单据编号 - newivApplicationHeadVO.setHcyy("2"); // 红冲原因:2(开票有误) + // 红冲原因:1=销货退回; 2=开票有误; 3=服务中止; 4=销售折让; + newivApplicationHeadVO.setHcyy("1"); // 组装VO applicationAggVO.setParentVO(newivApplicationHeadVO); @@ -672,6 +663,36 @@ public class IAPISaleInvMaitainImpl { } } + public IVApplicationAggVO saveIVApplication(JSONObject bject, SaleInvoiceVO[] redVos) throws Exception { + // 获取 红字发票传开票申请的数据 + ApplicationRedInvoiceService applicationRedInvoiceService = new ApplicationRedInvoiceService(); + List> jeMap = applicationRedInvoiceService.getData(redVos); + + IVApplicationAggVO applyVo = null; + + String invId = bject.getOrDefault("vdef40", "") + ""; + + // 查询蓝字发票号对应的税务云开出的发票号 + String invCode = getSaleInvCode(invId); + if (StringUtils.isBlank(invCode) || "null".equals(invCode)) { + ExceptionUtils.wrapBusinessException("税务云的发票号不能为空"); + } + IVApplicationInvoiceService ivService = ServiceLocator.find(IVApplicationInvoiceService.class); + JSONObject jsonObject1 = new JSONObject(); + // 查询对应的蓝字发票 + IVApplicationAggVO[] blueVos = ivService.getRedInvoice("", invCode, jsonObject1); + Logger.error("saveIVApplication-jsonObject1 = " + jsonObject1); + JSONObject jsonObject = new JSONObject(); + // 红字发票生成开票申请动作 + IVApplicationAggVO[] ivApplicationVOs = ivService.makeRedInvoice(blueVos, jsonObject, jeMap); + if (ivApplicationVOs != null && ivApplicationVOs.length > 0) { + applyVo = ivApplicationVOs[0]; + } + Logger.error("saveIVApplication-msg = " + jsonObject); + return applyVo; + } + + private Map getSaleOrderInfo(String csaleorderbid) throws BusinessException { IUAPQueryBS queryBS = NCLocator.getInstance().lookup(IUAPQueryBS.class); String sql = " select s.vbillcode,s.csaleorderid, s.corigcurrencyid," + @@ -684,6 +705,22 @@ public class IAPISaleInvMaitainImpl { return (Map) queryBS.executeQuery(sql, new MapProcessor()); } + /** + * 根据税务云单号查询发票的单号 + * + * @param invId + * @return + * @throws BusinessException + */ + private String getSaleInvCode(String invId) throws BusinessException { + IUAPQueryBS queryBS = NCLocator.getInstance().lookup(IUAPQueryBS.class); + String sql = " select nvl(vdef13, '') vdef13" + + " from so_saleinvoice" + + " where nvl(dr,0) = 0 and csaleinvoiceid = '" + invId + "' "; + Map resMap = (Map) queryBS.executeQuery(sql, new MapProcessor()); + return resMap.getOrDefault("vbillcode", ""); + } + private String getString_TrimAsNull(Object value) { if ((value == null) || (value.toString().trim().isEmpty())) { return "";