diff --git a/so/META-INF/saveCommit.rest b/so/META-INF/saveCommit.rest
new file mode 100644
index 0000000..10db0a0
--- /dev/null
+++ b/so/META-INF/saveCommit.rest
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/so/src/public/nccloud/api/so/saleinvoice/operator/OpenApiJsonConvertToExChangeXmlService.java b/so/src/public/nccloud/api/so/saleinvoice/operator/OpenApiJsonConvertToExChangeXmlService.java
new file mode 100644
index 0000000..cc981ef
--- /dev/null
+++ b/so/src/public/nccloud/api/so/saleinvoice/operator/OpenApiJsonConvertToExChangeXmlService.java
@@ -0,0 +1,28 @@
+package nccloud.api.so.saleinvoice.operator;
+
+import nc.bs.framework.core.util.ObjectCreator;
+import nccloud.api.baseapp.exchange.convert.IExchangeForService;
+import nccloud.api.baseapp.exchange.convert.IOpenApiJsonConvertToExChangeXmlService;
+import nccloud.api.baseapp.exchange.convert.OpenApiConvertDataObject;
+import nccloud.api.baseapp.exchange.convert.OpenApiConvertDataResult;
+
+
+/**
+ * 销售发票接口适配2005代码
+ * zhangxinah
+ */
+
+public class OpenApiJsonConvertToExChangeXmlService implements IOpenApiJsonConvertToExChangeXmlService {
+
+ @Override
+ public OpenApiConvertDataResult changeToExchangeData(OpenApiConvertDataObject openApiConvertDataObject)
+ throws Exception {
+ return getPFxxEJBService().changeToExchangeData(openApiConvertDataObject);
+ }
+
+ public static IExchangeForService getPFxxEJBService() {
+ IExchangeForService exchangeForService = (IExchangeForService) ObjectCreator.newInstance("ufesbexpress",
+ "nccloud.pubimpl.pfxx.convert.ExchangeForServiceImpl");
+ return exchangeForService;
+ }
+}
diff --git a/so/src/public/nccloud/api/so/saleinvoice/operator/saveCommitAction.java b/so/src/public/nccloud/api/so/saleinvoice/operator/saveCommitAction.java
new file mode 100644
index 0000000..bad744f
--- /dev/null
+++ b/so/src/public/nccloud/api/so/saleinvoice/operator/saveCommitAction.java
@@ -0,0 +1,377 @@
+package nccloud.api.so.saleinvoice.operator;
+
+import com.alibaba.fastjson.JSONArray;
+import com.alibaba.fastjson.JSONObject;
+import java.math.BigDecimal;
+import java.math.RoundingMode;
+import java.util.Map;
+import javax.ws.rs.Consumes;
+import javax.ws.rs.POST;
+import javax.ws.rs.Path;
+import javax.ws.rs.Produces;
+import nc.bs.framework.common.InvocationInfoProxy;
+import nc.bs.framework.common.NCLocator;
+import nc.bs.framework.core.util.ObjectCreator;
+import nc.itf.uap.IUAPQueryBS;
+import nc.jdbc.framework.processor.ColumnProcessor;
+import nc.jdbc.framework.processor.MapProcessor;
+import nc.pubitf.so.m32.api.ISaleinvoiceQueryAPI;
+import nc.vo.pub.BusinessException;
+import nc.vo.pubapp.pattern.model.entity.bill.AbstractBill;
+import nc.vo.pubapp.pflow.PfUserObject;
+import nc.vo.so.m32.entity.SaleInvoiceHVO;
+import nc.vo.so.m32.entity.SaleInvoiceVO;
+import nccloud.api.baseapp.exchange.convert.IExchangeForService;
+import nccloud.api.baseapp.exchange.convert.OpenApiConvertDataObject;
+import nccloud.api.baseapp.exchange.convert.OpenApiConvertDataResult;
+import nccloud.api.rest.utils.ResultMessageUtil;
+import nccloud.dto.scmpub.script.entity.SCMScriptResultDTO;
+import nccloud.pubitf.riart.pflow.CloudPFlowContext;
+import nccloud.pubitf.scmpub.commit.service.IBatchRunScriptService;
+import nccloud.pubitf.scmpub.ssc.service.ISSCService;
+import nccloud.pubitf.so.saleinvoice.service.ISaleInvoiceToTaxInvService;
+import nccloud.pubitf.ssctp.sscbd.lientage.ISSClientageMatchService.BusiUnitTypeEnum;
+import nccloud.ws.rest.resource.AbstractNCCRestResource;
+import org.json.JSONString;
+
+
+/**
+ * 销售发票接口适配2005代码
+ * zhangxinah
+ */
+@Path("so/saleinvoice/operator")
+public class saveCommitAction extends AbstractNCCRestResource {
+
+ public static String fplxStr = "";// 开票申请发票类型
+
+ public saveCommitAction() {
+
+ }
+
+ public OpenApiConvertDataResult changeToExchangeData(OpenApiConvertDataObject openApiConvertDataObject)
+ throws Exception {
+ return getPFxxEJBService().changeToExchangeData(openApiConvertDataObject);
+ }
+
+ public static IExchangeForService getPFxxEJBService() {
+ IExchangeForService exchangeForService = (IExchangeForService) ObjectCreator.newInstance("ufesbexpress",
+ "nccloud.pubimpl.pfxx.convert.ExchangeForServiceImpl");
+ return exchangeForService;
+ }
+
+ @Override
+ public String getModule() {
+ return "so";
+ }
+
+ @POST
+ @Path("/saveCommit")
+ @Consumes({ "application/json" })
+ @Produces({ "application/json" })
+ public JSONString saveCommit(JSONString json) throws Exception {
+ JSONObject jobject = JSONObject.parseObject(json.toJSONString());
+ if (jobject == null) {
+ return ResultMessageUtil.exceptionToJSON(new NullPointerException("JSONString:null"));
+ } else {
+ JSONObject bject = jobject.getJSONObject("billhead");
+ if (bject == null) {
+ return ResultMessageUtil.exceptionToJSON(new NullPointerException("billhead:null"));
+ } else {
+
+ JSONObject ufinterfaceObj = jsonObjectAss(jobject);
+ String tsType = ufinterfaceObj.getString("tsType");
+ if (tsType != null && tsType.equals("1")) {
+ Exception e = new NullPointerException("销售订单查询关联失败!");
+ return ResultMessageUtil.exceptionToJSON(e);
+ }
+ JSONObject bjects = ufinterfaceObj.getJSONObject("ufinterface");
+ String billtype = bjects.getString("billtype");
+ String account = bjects.getString("account");
+ String omscode = bjects.getString("orgcode");
+ String groupcode = bjects.getString("groupcode");
+
+ if (billtype != null && account != null && groupcode != null && "32".equals(billtype)) {
+ OpenApiConvertDataObject openApiconvertData0bject = new OpenApiConvertDataObject();
+ openApiconvertData0bject.setAccount(account);
+ openApiconvertData0bject.setBilltype(billtype);
+ openApiconvertData0bject.setGroupcode(groupcode);
+ openApiconvertData0bject.setOpenApiJsonData(ufinterfaceObj);
+ try {
+ OpenApiJsonConvertToExChangeXmlService oService = new OpenApiJsonConvertToExChangeXmlService();
+ OpenApiConvertDataResult r = oService.changeToExchangeData(openApiconvertData0bject);
+ JSONObject returnJson = r.getDesc();
+ String content = "";
+ // 逐层解析 JSON 数据
+ JSONObject ufinterface = returnJson.getJSONObject("ufinterface");
+ if (ufinterface != null) {
+ JSONArray sendResultArray = ufinterface.getJSONArray("sendresult");
+ if (sendResultArray != null && sendResultArray.size() > 0) {
+ // 提取 content 字段
+ content = sendResultArray.getJSONObject(0).getString("content");
+ }
+ }
+ if (content == null || content.equals("")) {
+ return r != null ? ResultMessageUtil.toJSON(r.getDesc(), "0")
+ : ResultMessageUtil.exceptionToJSON(new NullPointerException("未知异常"));
+ }
+ String[] ids = { content };
+ SaleInvoiceVO[] saleInvoiceVO = NCLocator.getInstance().lookup(ISaleinvoiceQueryAPI.class)
+ .queryVOByIDs(ids);
+ SaleInvoiceVO saleInvoiceVO22 = saleInvoiceVO[0];
+ SaleInvoiceHVO saleInvoiceHVO = saleInvoiceVO22.getParentVO();
+ // 销售发票审核开始
+ InvocationInfoProxy.getInstance().setUserId(saleInvoiceHVO.getApprover());
+ CloudPFlowContext context = new CloudPFlowContext();
+ context.setBillType("32");
+ context.setBillVos(new SaleInvoiceVO[] { saleInvoiceVO[0] });
+ ISSCService sscService = (ISSCService) NCLocator.getInstance().lookup(ISSCService.class);
+ String[] actionNames = sscService.isStartSSCWorkFlow(
+ (AbstractBill[]) ((AbstractBill[]) context.getBillVos()), BusiUnitTypeEnum.SO);
+ context.setActionName("APPROVE");
+ context.setTrantype("32-02");
+ context.setBatch(false);
+ context.setBatchUserObj(new PfUserObject[] { new PfUserObject() });
+ IBatchRunScriptService service = (IBatchRunScriptService) NCLocator.getInstance()
+ .lookup(IBatchRunScriptService.class);
+ SCMScriptResultDTO result = service.runBacth(context, SaleInvoiceVO.class);
+ // 销售发票审核结束
+ ISaleInvoiceToTaxInvService invoiceService = NCLocator.getInstance()
+ .lookup(ISaleInvoiceToTaxInvService.class);
+ invoiceService.issueTaxInvoice(saleInvoiceVO, "1");
+
+ return r != null ? ResultMessageUtil.toJSON(r.getDesc(), "0")
+ : ResultMessageUtil.exceptionToJSON(new NullPointerException("未知异常"));
+ } catch (Exception e) {
+ return ResultMessageUtil.exceptionToJSON(e);
+ }
+ } else {
+ Exception e = new NullPointerException(
+ "billtype:" + billtype + ",account:" + account + ",groupcode:" + groupcode);
+ return ResultMessageUtil.exceptionToJSON(e);
+ }
+
+ }
+ }
+ }
+
+ public static JSONObject jsonObjectAss(JSONObject originalJson) throws Exception {
+ try {
+ // 构建目标 JSON 格式
+ JSONObject resultJson = new JSONObject();
+ // 添加 ufinterface 字段
+ JSONObject ufinterface = new JSONObject();
+ ufinterface.put("billtype", "32");
+ ufinterface.put("sender", "BIP_NC");
+ ufinterface.put("level", "0");
+ ufinterface.put("replace", "Y");
+ ufinterface.put("roottag", "bill");
+ ufinterface.put("isexchange", "Y");
+ ufinterface.put("account", "01");
+ ufinterface.put("groupcode", "00");
+ // 处理 bill 数组
+ JSONArray billArray = new JSONArray();
+ JSONObject bill = new JSONObject();
+ // billhead 结构
+ JSONObject billhead = new JSONObject();
+ billhead = originalJson.getJSONObject("billhead");// 传入JSON对象
+ billhead.put("pk_org_v", originalJson.getJSONObject("billhead").getString("pk_org"));// 开票组织版本=开票组织
+ billhead.put("pk_group", "00");// 集团
+ fplxStr = originalJson.getJSONObject("billhead").getString("vdef22");
+ billhead.put("vtrantypecode", "32-02");// 发票类型编码
+ billhead.put("cbiztypeid", "SO01");// 业务流程
+ billhead.put("approver", "BIP");// 审批人
+ billhead.put("fstatusflag", 1);// 单据状态
+ billhead.put("billmaker", "BIP");// 制单人
+ billhead.put("csendcountryid", "CN");// 发货国家
+ billhead.put("crececountryid", "CN");// 收货国家
+ billhead.put("ctaxcountryid", "CN");// 报税国家
+ // 2025-2-8付业要求修改,根据发票类型Q(自定义档案)对照发票类型
+ String ctrantypeidStr = "32-02";// 默认普通发票
+ if (fplxStr != null && fplxStr.equals("31")) {
+ ctrantypeidStr = "32-01";
+ } else if (fplxStr != null && fplxStr.equals("32")) {
+ ctrantypeidStr = "32-02";
+ } else if (fplxStr != null && fplxStr.equals("36")) {
+ ctrantypeidStr = "32-Cxx-03";
+ }
+ billhead.put("ctrantypeid", ctrantypeidStr);// 发票类型
+ // billhead.put("ctrantypeid", "32-02");//发票类型
+ billhead.put("fbuysellflag", "1");// 购销类型
+ billhead.put("creator", "BIP");// 创建人
+ billhead.put("corigcurrencyid", "CNY");// 币种
+ billhead.put("ccurrencyid", "CNY");// 本位币
+ billhead.put("nexchangerate", 1);// 折本汇率
+ billhead.put("btriatradeflag", 0);// 三角贸易
+ JSONObject newItem = new JSONObject();
+ JSONArray csaleinvoicebid = new JSONArray();
+ // 遍历原始数据中的 csaleinvoicebid 数组
+ for (int i = 0; i < originalJson.getJSONObject("billhead").getJSONArray("csaleinvoicebid").size(); i++) {
+ JSONObject item = originalJson.getJSONObject("billhead").getJSONArray("csaleinvoicebid")
+ .getJSONObject(i);
+
+ JSONObject itemDetails = new JSONObject();
+ itemDetails = item;
+ itemDetails.put("carorgid", originalJson.getJSONObject("billhead").getString("pk_org"));// 应收组织
+ itemDetails.put("csendstockorgid", originalJson.getJSONObject("billhead").getString("pk_org"));// 库存组织原始版本
+ itemDetails.put("cmaterialid", item.getString("cmaterialvid"));// 物料编码
+ Map value2 = getSaleorderVo(item.getString("csrcbid"));
+ if (value2 == null) {
+ resultJson = new JSONObject();
+ resultJson.put("tsType", "1");
+ return resultJson;
+ }
+ itemDetails.put("vfirsttype", "30");// 源头单据类型
+ itemDetails.put("vfirstcode", value2.get("vbillcode"));// 源头单据号
+ itemDetails.put("blargessflag", value2.get("blargessflag"));// 赠品
+ itemDetails.put("vfirsttrantype", "30-01");// 源头交易类型
+ itemDetails.put("vfirstrowno", value2.get("crowno"));// 源头单据行号
+ itemDetails.put("cfirstid", item.getString("csrcid"));// 源头单据主表
+ itemDetails.put("cfirstbid", item.getString("csrcbid"));// 源头单据子表
+ itemDetails.put("vsrctype", "30");// 来源单据类型
+ itemDetails.put("vsrccode", value2.get("vbillcode"));// 来源单据号
+ itemDetails.put("vsrctrantype", "30-01");// 来源交易类型
+ itemDetails.put("vsrcrowno", value2.get("crowno"));// 来源单据行号
+ // 通过 ntaxrate 获取 taxcode
+ String taxcodeStr = getTaxcode(item.getString("ntaxrate"));
+ // 将 taxcodeStr 放入 bodyMap
+ itemDetails.put("ctaxcodeid", taxcodeStr);// 税码
+ itemDetails.put("nnum", item.getString("nastnum"));// 主数量
+ itemDetails.put("ftaxtypeflag", 1);// 扣税类别
+ itemDetails.put("pk_group", "00");// 集团
+ itemDetails.put("pk_org", originalJson.getJSONObject("billhead").getString("pk_org"));// 开票组织
+ itemDetails.put("cunitid", item.getString("castunitid"));// 主单位
+
+// double nastnum = Double.parseDouble(item.getString("nastnum"));//数量
+// double nqtorigtaxprice = Double.parseDouble(item.getString("nqtorigtaxprice"));//含税单价
+// double ntaxrate = Double.parseDouble(item.getString("ntaxrate"));//税率
+//
+// double nqtorigprice =
+// Math.round(nqtorigtaxprice / (1 + ntaxrate) * 100.0) / 100.0;//不含税单价、无税单价(含税单价/(1+税率))
+// double norigmny = Math.round(nqtorigprice * nastnum * 100.0) / 100.0;//无税金额(不含税单价*数量)
+// double norigtaxmny = Math.round(nastnum * nqtorigtaxprice * 100.0) / 100.0;//价税合计、含税金额(数量*含税单价)
+// double norigtaxprice = Math.round(nqtorigtaxprice * 100.0) / 100.0;//主含税单价(含税单价)
+// double norignetprice = nqtorigprice;//主无税净价(不含税单价)
+// double ntax = Math.round(norigtaxmny / (1 + ntaxrate) * ntaxrate * 100.0) / 100.0;//税额(含税金额/(1+税率)*税率)
+// double ncaltaxmny = norigmny;//计税金额(无税金额)
+// double norigtaxnetprice = norigtaxprice;//主含税净价(主含税单价)
+
+// BigDecimal nastnum = new BigDecimal(item.getString("nastnum"));//数量
+// BigDecimal nqtorigtaxprice = new BigDecimal(item.getString("nqtorigtaxprice"));//含税单价
+// BigDecimal ntaxrate = new BigDecimal(item.getString("ntaxrate"));//税率
+//
+// // 1. 计算不含税单价
+// BigDecimal nqtorigprice = nqtorigtaxprice.divide(BigDecimal.ONE.add(ntaxrate), 4, RoundingMode.HALF_UP);
+// // 2. 计算无税金额 = 不含税单价 * 数量
+// BigDecimal norigmny = nqtorigprice.multiply(nastnum).setScale(4, RoundingMode.HALF_UP);
+// // 3. 计算税额 = 无税金额 * 税率
+// BigDecimal ntax = norigmny.multiply(ntaxrate).setScale(4, RoundingMode.HALF_UP);
+// // 4. 计算含税金额 = 无税金额 + 税额
+// BigDecimal norigtaxmny = norigmny.add(ntax).setScale(4, RoundingMode.HALF_UP);
+// // 主含税单价(即含税单价)
+// BigDecimal norigtaxprice = nqtorigtaxprice.setScale(4, RoundingMode.HALF_UP);
+// // 主无税净价(即不含税单价)
+// BigDecimal norignetprice = nqtorigprice;
+// // 计税金额 = 无税金额
+// BigDecimal ncaltaxmny = norigmny;
+// // 主含税净价 = 含税单价(原始)
+// BigDecimal norigtaxnetprice = norigtaxprice;
+
+ // 输入参数:从你的 item 获取各个字段
+ BigDecimal nastnum = new BigDecimal(item.getString("nastnum")); // 数量
+ nastnum = nastnum.setScale(4, RoundingMode.HALF_UP);
+ BigDecimal nqtorigtaxprice = new BigDecimal(item.getString("nqtorigtaxprice")); // 含税单价
+ nqtorigtaxprice = nqtorigtaxprice.setScale(4, RoundingMode.HALF_UP);
+ BigDecimal ntaxrate = new BigDecimal(item.getString("ntaxrate")).divide(new BigDecimal("100")); // 税率
+ ntaxrate = ntaxrate.setScale(4, RoundingMode.HALF_UP);
+
+ // 含税净价
+ BigDecimal norigtaxnetprice = nqtorigtaxprice;
+ // 1. 计算价税合计(含税金额)
+ BigDecimal norigtaxmny = nastnum.multiply(norigtaxnetprice).setScale(2, RoundingMode.HALF_UP);
+ // 2. 计算折扣额
+ BigDecimal discountAmount = nastnum.multiply(nqtorigtaxprice).subtract(norigtaxmny).setScale(4,
+ RoundingMode.HALF_UP);
+ // 3. 计算税额(两种方法:应税外加税和应税内含税)
+ BigDecimal ntax = norigtaxmny.multiply(ntaxrate).divide(BigDecimal.ONE.add(ntaxrate), 2,
+ RoundingMode.HALF_UP); // 应税外加税
+ BigDecimal taxInclusiveInner = norigtaxmny.multiply(ntaxrate).setScale(4, RoundingMode.HALF_UP); // 应税内含税
+ // 4. 计算无税金额
+ BigDecimal norigmny = norigtaxmny.subtract(ntax).setScale(2, RoundingMode.HALF_UP);
+ // 4. 计算无税单价(nqtorigprice = 无税金额 / 数量)
+ BigDecimal nqtorigprice = norigmny.divide(nastnum, 4, RoundingMode.HALF_UP);
+ // 计税金额 = 无税金额
+ BigDecimal ncaltaxmny = norigmny;
+ // 主含税单价(即含税单价)
+ BigDecimal norigtaxprice = nqtorigtaxprice.setScale(4, RoundingMode.HALF_UP);
+ // 主无税净价(即不含税单价)
+ BigDecimal norignetprice = nqtorigprice;
+
+ itemDetails.put("nqtorigprice", nqtorigprice);// 无税单价
+ itemDetails.put("norigprice", nqtorigprice);// 主无税单价
+ itemDetails.put("norigmny", norigmny);// 无税金额
+ itemDetails.put("nmny", norigmny);// 本币无税金额
+ itemDetails.put("norigtaxmny", norigtaxmny);// 价税合计
+ itemDetails.put("norigtaxprice", norigtaxprice);// 主含税单价
+ itemDetails.put("norignetprice", norignetprice);// 主无税净价
+ itemDetails.put("nqtorigtaxprice", nqtorigtaxprice);// 含税单价
+ itemDetails.put("ntax", ntax);// 税额
+ itemDetails.put("ncaltaxmny", ncaltaxmny);// 计税金额
+ itemDetails.put("norigtaxnetprice", norigtaxnetprice);// 主含税净价
+ itemDetails.put("nnetprice", norignetprice);// 主本币无税净价
+ itemDetails.put("ntaxmny", norigtaxmny);// 本币价税合计
+ csaleinvoicebid.add(itemDetails);
+
+ }
+ newItem.put("item", csaleinvoicebid);
+ billhead.put("csaleinvoicebid", newItem);
+ bill.put("billhead", billhead);
+ bill.put("id", "");
+ // 将 bill 数组添加到 ufinterface 中
+ billArray.add(bill);
+ ufinterface.put("bill", billArray);
+ // 将 ufinterface 添加到最终的 resultJson 中
+ resultJson.put("ufinterface", ufinterface);
+ return resultJson;
+ } catch (Exception e) {
+ return (JSONObject) ResultMessageUtil.exceptionToJSON(e);
+ }
+ }
+
+ // 方法:检查必填项并返回转化后的Map
+ public static String checkRequiredFields(JSONObject data) throws Exception {
+ String returnStr = "";
+ // 2. 检查必填字段 pk_org
+ String pkOrg = (String) data.getOrDefault("pk_org", "");
+ if (pkOrg.isEmpty()) {
+ return "字段pk_org缺失或为空!";
+ }
+ // 2. 检查必填字段 pk_org
+ String vbillcode = (String) data.getOrDefault("vbillcode", "");
+ if (vbillcode.isEmpty()) {
+ return "字段vbillcode缺失或为空!";
+ }
+ return returnStr;
+ }
+
+ private static String getTaxcode(String taxrateStr) throws BusinessException {
+ IUAPQueryBS queryBS = NCLocator.getInstance().lookup(IUAPQueryBS.class);
+ String sql = " select code FROM bd_taxrate tt inner join bd_taxcode tc on tt.pk_taxcode=tc.pk_taxcode where taxrate='"
+ + taxrateStr + "' AND ROWNUM = 1 ";
+ String taxcodeStr = (String) queryBS.executeQuery(sql, new ColumnProcessor());
+ return taxcodeStr;
+ }
+
+ private static Map getSaleorderVo(String csourcebillbidStr) throws BusinessException {
+ IUAPQueryBS queryBS = NCLocator.getInstance().lookup(IUAPQueryBS.class);
+ String sql = " select s.vbillcode,s.csaleorderid,sb.csaleorderbid,sb.crowno,sb.blargessflag from so_saleorder_b sb\n"
+ + "inner join so_saleorder s on sb.csaleorderid=s.csaleorderid\n" + "where sb.csaleorderbid='"
+ + csourcebillbidStr + "' ";
+ Map value2 = (Map) queryBS.executeQuery(sql, new MapProcessor());
+ return value2;
+ }
+
+ public IUAPQueryBS getQueryService() {
+ return NCLocator.getInstance().lookup(IUAPQueryBS.class);
+ }
+
+}
\ No newline at end of file