Эх сурвалжийг харах

feat: 针对大量单据提交生成对账单优化处理

hejq 7 жил өмнө
parent
commit
08e7341b1a

+ 22 - 47
src/main/java/com/uas/platform/b2b/controller/SaleApCheckController.java

@@ -6,7 +6,6 @@ import com.uas.platform.b2b.model.ErpProdIODetail;
 import com.uas.platform.b2b.model.ErpProdIo;
 import com.uas.platform.b2b.model.OrderType;
 import com.uas.platform.b2b.model.PurchaseApCheck;
-import com.uas.platform.b2b.model.PurchaseApCheckItem;
 import com.uas.platform.b2b.model.Role;
 import com.uas.platform.b2b.model.SearchFilter;
 import com.uas.platform.b2b.model.Vendor;
@@ -20,7 +19,6 @@ import com.uas.platform.b2b.support.JxlsExcelView;
 import com.uas.platform.b2b.support.SPageUtils;
 import com.uas.platform.b2b.support.SystemSession;
 import com.uas.platform.b2b.support.UsageBufferedLogger;
-import com.uas.platform.core.exception.IllegalOperatorException;
 import com.uas.platform.core.logging.BufferedLoggerManager;
 import com.uas.platform.core.model.Constant;
 import com.uas.platform.core.model.PageInfo;
@@ -86,7 +84,7 @@ public class SaleApCheckController {
 	@Autowired
     private OrderRedDotService redDotService;
 
-	private final static UsageBufferedLogger logger = BufferedLoggerManager.getLogger(UsageBufferedLogger.class);
+	private final static UsageBufferedLogger LOGGER = BufferedLoggerManager.getLogger(UsageBufferedLogger.class);
 
 	/**
 	 * 打印权限判断
@@ -107,7 +105,7 @@ public class SaleApCheckController {
 	@RequestMapping(value = "/printCount/{id}", method = RequestMethod.POST)
 	public ResponseEntity<String> printCount(@PathVariable("id") Long id) {
 		purchaseApCheckService.print(id);
-		logger.log("应收对账单", "打印应付对账单", id.toString());
+		LOGGER.log("应收对账单", "打印应付对账单", id.toString());
 		return new ResponseEntity<>(HttpStatus.OK);
 	}
 
@@ -120,7 +118,7 @@ public class SaleApCheckController {
 	@RequestMapping("/operation/cancel")
 	public ModelMap cancelApCheck(Long id) {
 		boolean result = purchaseApCheckService.cancelApcheck(id);
-		logger.log("应收对账单", "作废应收对账单", result ? "成功" : "失败", "", id);
+		LOGGER.log("应收对账单", "作废应收对账单", result ? "成功" : "失败", "", id);
 		return new ModelMap("result", result);
 	}
 
@@ -172,7 +170,7 @@ public class SaleApCheckController {
 				}
 			}
 		}
-        logger.log("应收对账单", "获取客户信息", "获取所有符合条件的客户");
+        LOGGER.log("应收对账单", "获取客户信息", "获取所有符合条件的客户");
         return set;
 	}
 
@@ -210,7 +208,7 @@ public class SaleApCheckController {
      */
     @RequestMapping(value = "/customer", method = RequestMethod.GET)
     public SPage<Vendor> getCustomers(PageParams params, String keyword, String checkDate, String searchFilter) throws InterruptedException {
-        logger.log("应收对账单", "获取客户信息", "获取所有符合条件的客户");
+        LOGGER.log("应收对账单", "获取客户信息", "获取所有符合条件的客户");
         SearchFilter filter = JSONObject.parseObject(searchFilter, SearchFilter.class);
         return purchaseApCheckService.getCustomerInfo(params, keyword, checkDate, filter.getFromDate(), filter.getEndDate());
     }
@@ -223,34 +221,11 @@ public class SaleApCheckController {
 	 */
 	@RequestMapping(value = "/operation/save", method = RequestMethod.POST)
 	public ModelMap saveApCheck(@RequestBody String json) {
-		ModelMap map = new ModelMap();
-		Set<String> alters = new HashSet<>();
 		PurchaseApCheck apCheck = FlexJsonUtils.fromJson(json, PurchaseApCheck.class);
-		if (apCheck != null) {
-			for (PurchaseApCheckItem item : apCheck.getItems()) {
-				List<PurchaseApCheckItem> items = purchaseApCheckService
-						.findBySourceTableAndSourceId(item.getSourceTable(), item.getSourceId());
-				for (PurchaseApCheckItem newitem : items) {
-					if (newitem.getApCheck().getCheckStatus().equals("未对账")) {
-						alters.add(item.getInoutno());
-					}
-				}
-			}
-			if (alters.size() > 0) {
-				map.put("alters", alters);
-				throw new IllegalOperatorException("订单" + alters + "存在未对账的单据,请先进行对账!");
-			} else {
-				apCheck = purchaseApCheckService.save(apCheck);
-				logger.log("应收对账单", "多个单据生成同一张应收对账单", apCheck.getRemark(), null, apCheck.getId());
-				map.put("id", apCheck.getId());
-				return map;
-			}
-		} else {
-			throw new IllegalOperatorException("保存失败!");
-		}
+		return purchaseApCheckService.checkCount(apCheck);
 	}
 
-	/**
+    /**
 	 * 生成应收对账单的同时更新明细行来源表中,物料已转数
      *
 	 * @param json 对账数据
@@ -259,7 +234,7 @@ public class SaleApCheckController {
 	public void updateYCheckQty(@RequestBody String json) {
 		List<HashMap<String, Object>> list = FlexJsonUtils.fromJsonArray(json, HashMap.class);
 		purchaseApCheckService.updateYCheckQty(list);
-        logger.log("应收对账单", "生成应收对账单的同时更新明细行来源表中,物料已转数");
+        LOGGER.log("应收对账单", "生成应收对账单的同时更新明细行来源表中,物料已转数");
     }
 
 	/**
@@ -273,7 +248,7 @@ public class SaleApCheckController {
 	 */
 	@RequestMapping(value = "/{id}/info", method = RequestMethod.GET)
 	public PurchaseApCheck getCreatedPurchaseApCheckById(@PathVariable("id") Long id) {
-		logger.log("应收对账单", "查看单个应收对账单", null, null, id);
+		LOGGER.log("应收对账单", "查看单个应收对账单", null, null, id);
 		return purchaseApCheckService.findById(id);
 	}
 
@@ -284,7 +259,7 @@ public class SaleApCheckController {
 	@RequestMapping(value = "/operation/deleteApCheck", method = RequestMethod.POST)
 	public void deleteApCheck(Long id) {
 		purchaseApCheckService.deleteApCheck(id);
-        logger.log("应收对账单", "删除最新生成未提交的应收对账单", null, null, id);
+        LOGGER.log("应收对账单", "删除最新生成未提交的应收对账单", null, null, id);
     }
 
 	/**
@@ -296,7 +271,7 @@ public class SaleApCheckController {
 	public ModelMap updateApCheckStatus(Long id) {
 		ModelMap map = new ModelMap();
 		map.put("result", purchaseApCheckService.updateApCheckStatus(id));
-        logger.log("应收对账单", "提交生成的应收对账单", null, null, id);
+        LOGGER.log("应收对账单", "提交生成的应收对账单", null, null, id);
         return map;
 	}
 
@@ -309,7 +284,7 @@ public class SaleApCheckController {
 	 */
 	@RequestMapping(value = "/info/search", method = RequestMethod.GET)
 	public SPage<PurchaseApCheck> getPurchaseApChecks(PageParams params, String searchFilter) {
-		logger.log("应收对账单", "作为买家,获取全部应收对账单");
+		LOGGER.log("应收对账单", "作为买家,获取全部应收对账单");
 		SearchFilter filter = JSONObject.parseObject(searchFilter, SearchFilter.class);
 		if (StringUtils.isEmpty(filter.getKeyword())) {
             PageInfo pageInfo = new PageInfo(params);
@@ -336,7 +311,7 @@ public class SaleApCheckController {
 	 */
 	@RequestMapping(value = "/info/search", params = RequestState.TODO, method = RequestMethod.GET)
 	public SPage<PurchaseApCheck> getTodoApChecks(PageParams params, String searchFilter) {
-		logger.log("应收对账单", "获取未对账应收对账单");
+		LOGGER.log("应收对账单", "获取未对账应收对账单");
         SearchFilter filter = JSONObject.parseObject(searchFilter, SearchFilter.class);
         if (StringUtils.isEmpty(filter.getKeyword())) {
             PageInfo pageInfo = new PageInfo(params);
@@ -365,7 +340,7 @@ public class SaleApCheckController {
 	 */
 	@RequestMapping(value = "/info/search", params = RequestState.DONE, method = RequestMethod.GET)
 	public SPage<PurchaseApCheck> getDoneApChecks(PageParams params, String searchFilter) {
-		logger.log("应收对账单", "获取已对账应收对账单");
+		LOGGER.log("应收对账单", "获取已对账应收对账单");
         SearchFilter filter = JSONObject.parseObject(searchFilter, SearchFilter.class);
         if (StringUtils.isEmpty(filter.getKeyword())) {
             PageInfo pageInfo = new PageInfo(params);
@@ -401,7 +376,7 @@ public class SaleApCheckController {
 	 */
 	@RequestMapping(value = "/info/search", params = RequestState.END, method = RequestMethod.GET)
 	public SPage<PurchaseApCheck> getEndApChecks(PageParams params, String searchFilter) {
-		logger.log("应收对账单", "获取不同意,已作废应收对账单");
+		LOGGER.log("应收对账单", "获取不同意,已作废应收对账单");
         SearchFilter filter = JSONObject.parseObject(searchFilter, SearchFilter.class);
         if (StringUtils.isEmpty(filter.getKeyword())) {
             PageInfo pageInfo = new PageInfo(params);
@@ -478,7 +453,7 @@ public class SaleApCheckController {
 		modelAndView.addObject("state", "全部");
 		modelAndView.addObject("data", getPurchaseApChecks(params, searchFilter).getContent());
 		modelAndView.setView(new JxlsExcelView("classpath:jxls-tpl/fa/saleApCheck", "应收对账单列表_全部"));
-		logger.log("应收对账单", "导出Excel列表", "导出全部Excel列表");
+		LOGGER.log("应收对账单", "导出Excel列表", "导出全部Excel列表");
 		return modelAndView;
 	}
 
@@ -498,7 +473,7 @@ public class SaleApCheckController {
 		modelAndView.addObject("state", "已对账");
 		modelAndView.addObject("data", getDoneApChecks(params, searchFilter).getContent());
 		modelAndView.setView(new JxlsExcelView("classpath:jxls-tpl/fa/saleApCheck", "应收对账单列表_已对账"));
-		logger.log("应收对账单", "导出Excel列表", "导出已对账Excel列表");
+		LOGGER.log("应收对账单", "导出Excel列表", "导出已对账Excel列表");
 		return modelAndView;
 	}
 
@@ -518,7 +493,7 @@ public class SaleApCheckController {
 		modelAndView.addObject("state", "未对账");
 		modelAndView.addObject("data", getDoneApChecks(params, searchFilter).getContent());
 		modelAndView.setView(new JxlsExcelView("classpath:jxls-tpl/fa/saleApCheck", "应收对账单列表_未对账"));
-		logger.log("应收对账单", "导出Excel列表", "导出未对账Excel列表");
+		LOGGER.log("应收对账单", "导出Excel列表", "导出未对账Excel列表");
 		return modelAndView;
 	}
 
@@ -538,7 +513,7 @@ public class SaleApCheckController {
 		modelAndView.addObject("state", "已作废");
 		modelAndView.addObject("data", getEndApChecks(params, searchFilter).getContent());
 		modelAndView.setView(new JxlsExcelView("classpath:jxls-tpl/fa/saleApCheck", "应收对账单列表_已作废"));
-		logger.log("应收对账单", "导出Excel列表", "导出已做废Excel列表");
+		LOGGER.log("应收对账单", "导出Excel列表", "导出已做废Excel列表");
 		return modelAndView;
 	}
 
@@ -571,7 +546,7 @@ public class SaleApCheckController {
 		modelAndView.addObject("data", details);
         modelAndView.addObject("title", "客户应收对账单");
 		modelAndView.setView(new JxlsExcelView("classpath:jxls-tpl/fa/faApCheck", "客户应收对账单"));
-		logger.log("客户应收对账单", "导出Excel列表", "导出全部Excel列表");
+		LOGGER.log("客户应收对账单", "导出Excel列表", "导出全部Excel列表");
 		return modelAndView;
 	}
 
@@ -582,7 +557,7 @@ public class SaleApCheckController {
 	 */
 	@RequestMapping(value = "/setRead", method = RequestMethod.POST)
 	public void setReadByOrder(@RequestBody Long... sourceId) {
-        logger.log("消息红点", "设置单据已读", "设置对账单已读: " + sourceId);
+        LOGGER.log("消息红点", "设置单据已读", "设置对账单已读: " + sourceId);
         redDotService.setReadByIds(OrderType.apcheck.name(), sourceId);
 	}
 
@@ -636,7 +611,7 @@ public class SaleApCheckController {
      */
 	@RequestMapping(value = "/getBilled", method = RequestMethod.GET)
 	public Double getBilled(Long id) {
-        logger.log("应付发票", "通过id获取已开票数", "", "", id);
+        LOGGER.log("应付发票", "通过id获取已开票数", "", "", id);
         return purchaseApCheckService.getBilledByItemId(id);
 	}
 }

+ 10 - 0
src/main/java/com/uas/platform/b2b/dao/PurchaseApCheckItemDao.java

@@ -7,6 +7,7 @@ import org.springframework.data.jpa.repository.Query;
 import org.springframework.data.repository.query.Param;
 import org.springframework.stereotype.Repository;
 
+import java.util.Collection;
 import java.util.List;
 
 @Repository
@@ -22,6 +23,15 @@ public interface PurchaseApCheckItemDao
 	 */
 	List<PurchaseApCheckItem> findBySourceTableAndSourceId(String sourceTable, Long sourceId);
 
+    /**
+     * 通过sourceTable、sourceId判断是否已提交未对账
+     *
+     * @param sourceTable 来源表
+     * @param ids id集合
+     * @return 查询的数据
+     */
+	List<PurchaseApCheckItem> findBySourceTableAndSourceIdIn(String sourceTable, Collection<Long> ids);
+
 	/**
 	 * 通过id获取已开票数
 	 * @param id id

+ 2 - 1
src/main/java/com/uas/platform/b2b/model/PurchaseApCheck.java

@@ -14,6 +14,7 @@ import javax.persistence.Table;
 import javax.persistence.Transient;
 import java.io.*;
 import java.util.Date;
+import java.util.List;
 import java.util.Set;
 
 /**
@@ -198,7 +199,7 @@ public class PurchaseApCheck implements Serializable {
 	@OrderBy("number")
 	private Set<PurchaseApCheckItem> items;
 
-	public String getCustreply() {
+    public String getCustreply() {
 		return custreply;
 	}
 

+ 135 - 0
src/main/java/com/uas/platform/b2b/model/PurchaseApCheckItem.java

@@ -473,4 +473,139 @@ public class PurchaseApCheckItem implements Serializable {
 		return purchaseApChecks;
 	}
 
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) {
+            return true;
+        }
+        if (o == null || getClass() != o.getClass()) {
+            return false;
+        }
+
+        PurchaseApCheckItem checkItem = (PurchaseApCheckItem) o;
+
+        if (id != null ? !id.equals(checkItem.id) : checkItem.id != null) {
+            return false;
+        }
+        if (number != null ? !number.equals(checkItem.number) : checkItem.number != null) {
+            return false;
+        }
+        if (custUserUU != null ? !custUserUU.equals(checkItem.custUserUU) : checkItem.custUserUU != null) {
+            return false;
+        }
+        if (prid != null ? !prid.equals(checkItem.prid) : checkItem.prid != null) {
+            return false;
+        }
+        if (orderCode != null ? !orderCode.equals(checkItem.orderCode) : checkItem.orderCode != null) {
+            return false;
+        }
+        if (orderClass != null ? !orderClass.equals(checkItem.orderClass) : checkItem.orderClass != null) {
+            return false;
+        }
+        if (orderDetno != null ? !orderDetno.equals(checkItem.orderDetno) : checkItem.orderDetno != null) {
+            return false;
+        }
+        if (inoutno != null ? !inoutno.equals(checkItem.inoutno) : checkItem.inoutno != null) {
+            return false;
+        }
+        if (inoutnodetno != null ? !inoutnodetno.equals(checkItem.inoutnodetno) : checkItem.inoutnodetno != null) {
+            return false;
+        }
+        if (prodCode != null ? !prodCode.equals(checkItem.prodCode) : checkItem.prodCode != null) {
+            return false;
+        }
+        if (prodTitle != null ? !prodTitle.equals(checkItem.prodTitle) : checkItem.prodTitle != null) {
+            return false;
+        }
+        if (prodSpec != null ? !prodSpec.equals(checkItem.prodSpec) : checkItem.prodSpec != null) {
+            return false;
+        }
+        if (prodUnit != null ? !prodUnit.equals(checkItem.prodUnit) : checkItem.prodUnit != null) {
+            return false;
+        }
+        if (price != null ? !price.equals(checkItem.price) : checkItem.price != null) {
+            return false;
+        }
+        if (taxrate != null ? !taxrate.equals(checkItem.taxrate) : checkItem.taxrate != null) {
+            return false;
+        }
+        if (checkQty != null ? !checkQty.equals(checkItem.checkQty) : checkItem.checkQty != null) {
+            return false;
+        }
+        if (amount != null ? !amount.equals(checkItem.amount) : checkItem.amount != null) {
+            return false;
+        }
+        if (custCheckQty != null ? !custCheckQty.equals(checkItem.custCheckQty) : checkItem.custCheckQty != null) {
+            return false;
+        }
+        if (remark != null ? !remark.equals(checkItem.remark) : checkItem.remark != null) {
+            return false;
+        }
+        if (status != null ? !status.equals(checkItem.status) : checkItem.status != null) {
+            return false;
+        }
+        if (sourceTable != null ? !sourceTable.equals(checkItem.sourceTable) : checkItem.sourceTable != null) {
+            return false;
+        }
+        if (sourceId != null ? !sourceId.equals(checkItem.sourceId) : checkItem.sourceId != null) {
+            return false;
+        }
+        if (sourceDate != null ? !sourceDate.equals(checkItem.sourceDate) : checkItem.sourceDate != null) {
+            return false;
+        }
+        if (oldYCheckQty != null ? !oldYCheckQty.equals(checkItem.oldYCheckQty) : checkItem.oldYCheckQty != null) {
+            return false;
+        }
+        if (receiveCode != null ? !receiveCode.equals(checkItem.receiveCode) : checkItem.receiveCode != null) {
+            return false;
+        }
+        if (receiveName != null ? !receiveName.equals(checkItem.receiveName) : checkItem.receiveName != null) {
+            return false;
+        }
+        if (sendcode != null ? !sendcode.equals(checkItem.sendcode) : checkItem.sendcode != null) {
+            return false;
+        }
+        if (whname != null ? !whname.equals(checkItem.whname) : checkItem.whname != null) {
+            return false;
+        }
+        if (billed != null ? !billed.equals(checkItem.billed) : checkItem.billed != null) {
+            return false;
+        }
+        return apCheck != null ? apCheck.equals(checkItem.apCheck) : checkItem.apCheck == null;
+    }
+
+    @Override
+    public int hashCode() {
+        int result = id != null ? id.hashCode() : 0;
+        result = 31 * result + (number != null ? number.hashCode() : 0);
+        result = 31 * result + (custUserUU != null ? custUserUU.hashCode() : 0);
+        result = 31 * result + (prid != null ? prid.hashCode() : 0);
+        result = 31 * result + (orderCode != null ? orderCode.hashCode() : 0);
+        result = 31 * result + (orderClass != null ? orderClass.hashCode() : 0);
+        result = 31 * result + (orderDetno != null ? orderDetno.hashCode() : 0);
+        result = 31 * result + (inoutno != null ? inoutno.hashCode() : 0);
+        result = 31 * result + (inoutnodetno != null ? inoutnodetno.hashCode() : 0);
+        result = 31 * result + (prodCode != null ? prodCode.hashCode() : 0);
+        result = 31 * result + (prodTitle != null ? prodTitle.hashCode() : 0);
+        result = 31 * result + (prodSpec != null ? prodSpec.hashCode() : 0);
+        result = 31 * result + (prodUnit != null ? prodUnit.hashCode() : 0);
+        result = 31 * result + (price != null ? price.hashCode() : 0);
+        result = 31 * result + (taxrate != null ? taxrate.hashCode() : 0);
+        result = 31 * result + (checkQty != null ? checkQty.hashCode() : 0);
+        result = 31 * result + (amount != null ? amount.hashCode() : 0);
+        result = 31 * result + (custCheckQty != null ? custCheckQty.hashCode() : 0);
+        result = 31 * result + (remark != null ? remark.hashCode() : 0);
+        result = 31 * result + (status != null ? status.hashCode() : 0);
+        result = 31 * result + (sourceTable != null ? sourceTable.hashCode() : 0);
+        result = 31 * result + (sourceId != null ? sourceId.hashCode() : 0);
+        result = 31 * result + (sourceDate != null ? sourceDate.hashCode() : 0);
+        result = 31 * result + (oldYCheckQty != null ? oldYCheckQty.hashCode() : 0);
+        result = 31 * result + (receiveCode != null ? receiveCode.hashCode() : 0);
+        result = 31 * result + (receiveName != null ? receiveName.hashCode() : 0);
+        result = 31 * result + (sendcode != null ? sendcode.hashCode() : 0);
+        result = 31 * result + (whname != null ? whname.hashCode() : 0);
+        result = 31 * result + (billed != null ? billed.hashCode() : 0);
+        result = 31 * result + (apCheck != null ? apCheck.hashCode() : 0);
+        return result;
+    }
 }

+ 19 - 0
src/main/java/com/uas/platform/b2b/service/PurchaseApCheckService.java

@@ -12,7 +12,9 @@ import com.uas.platform.core.model.PageInfo;
 import com.uas.platform.core.model.PageParams;
 import com.uas.search.b2b.model.SPage;
 import org.springframework.data.domain.Page;
+import org.springframework.ui.ModelMap;
 
+import java.util.Collection;
 import java.util.HashMap;
 import java.util.List;
 import java.util.concurrent.CountDownLatch;
@@ -132,6 +134,15 @@ public interface PurchaseApCheckService {
 	 */
     List<PurchaseApCheckItem> findBySourceTableAndSourceId(String sourceTable, Long sourceId);
 
+    /**
+     * 通过sourceTable、sourceId判断是否已提交未对账
+     *
+     * @param sourceTable 来源表
+     * @param ids id集合
+     * @return 查询的数据
+     */
+    List<PurchaseApCheckItem> findBySourceTableAndSourceIdIn(String sourceTable, Collection<Long> ids);
+
 	/**
 	 * 获取明细表中已开票数
 	 * @param id 发票id
@@ -254,4 +265,12 @@ public interface PurchaseApCheckService {
      * @return sql
      */
     String updateApCheckCountSql(Long vendorUU, Long customerUU, Long vendorId);
+
+    /**
+     * 进行对账单对账操作
+     *
+     * @param apCheck 对账单数据
+     * @return 对账结果
+     */
+    ModelMap checkCount(PurchaseApCheck apCheck);
 }

+ 84 - 0
src/main/java/com/uas/platform/b2b/service/impl/PurchaseApCheckServiceImpl.java

@@ -4,6 +4,7 @@ import com.alibaba.fastjson.JSON;
 import com.uas.platform.b2b.constant.StringConstant;
 import com.uas.platform.b2b.core.util.BoundedExecutor;
 import com.uas.platform.b2b.core.util.ContextUtils;
+import com.uas.platform.b2b.core.util.StringUtil;
 import com.uas.platform.b2b.dao.CommonDao;
 import com.uas.platform.b2b.dao.CommunalLogDao;
 import com.uas.platform.b2b.dao.EnterpriseDao;
@@ -36,8 +37,10 @@ import com.uas.platform.b2b.service.UserService;
 import com.uas.platform.b2b.support.CollectionUtil;
 import com.uas.platform.b2b.support.DecimalUtils;
 import com.uas.platform.b2b.support.SystemSession;
+import com.uas.platform.b2b.support.UsageBufferedLogger;
 import com.uas.platform.b2b.task.ApCheckTask;
 import com.uas.platform.core.exception.IllegalOperatorException;
+import com.uas.platform.core.logging.BufferedLoggerManager;
 import com.uas.platform.core.model.Constant;
 import com.uas.platform.core.model.PageInfo;
 import com.uas.platform.core.model.PageParams;
@@ -50,6 +53,7 @@ import org.springframework.data.domain.Page;
 import org.springframework.data.jpa.domain.Specification;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
+import org.springframework.ui.ModelMap;
 import org.springframework.util.CollectionUtils;
 
 import javax.persistence.criteria.CriteriaBuilder;
@@ -59,6 +63,7 @@ import javax.persistence.criteria.Root;
 import java.sql.SQLException;
 import java.text.SimpleDateFormat;
 import java.util.ArrayList;
+import java.util.Collection;
 import java.util.Date;
 import java.util.HashMap;
 import java.util.HashSet;
@@ -89,6 +94,8 @@ public class PurchaseApCheckServiceImpl implements PurchaseApCheckService {
     @Autowired
     private ErpProdIODetailService erpProdIODetailService;
 
+    private final static UsageBufferedLogger LOGGER = BufferedLoggerManager.getLogger(UsageBufferedLogger.class);
+
     /**
      * RMB
      */
@@ -540,6 +547,18 @@ public class PurchaseApCheckServiceImpl implements PurchaseApCheckService {
 		return purchaseApCheckItemDao.findBySourceTableAndSourceId(sourceTable, sourceId);
 	}
 
+    /**
+     * 通过sourceTable、sourceId判断是否已提交未对账
+     *
+     * @param sourceTable 来源表
+     * @param ids         id集合
+     * @return 查询的数据
+     */
+    @Override
+    public List<PurchaseApCheckItem> findBySourceTableAndSourceIdIn(String sourceTable, Collection<Long> ids) {
+        return purchaseApCheckItemDao.findBySourceTableAndSourceIdIn(sourceTable, ids);
+    }
+
     @Override
     public Double getBilledByItemId(Long id) {
         return purchaseApCheckItemDao.getBilledById(id);
@@ -953,4 +972,69 @@ public class PurchaseApCheckServiceImpl implements PurchaseApCheckService {
         threadsSignal.await();
         return groupCountByCurrency(totalTrades);
     }
+
+    /**
+     * 进行对账单对账操作
+     *
+     * @param apCheck 对账单数据
+     * @return 对账结果
+     */
+    @Override
+    public ModelMap checkCount(PurchaseApCheck apCheck) {
+        if (apCheck != null) {
+            // 针对当前对账数据进行校验操作
+            enableCheck(apCheck.getItems());
+            apCheck = this.save(apCheck);
+            LOGGER.log("应收对账单", "多个单据生成同一张应收对账单", apCheck.getRemark(), null, apCheck.getId());
+            return new ModelMap("id", apCheck.getId());
+        }
+        LOGGER.log("应收对账单", "生成对账单失败,未选择对账数据");
+        throw new IllegalOperatorException("保存失败!");
+    }
+
+    /**
+     * 按表类型分别统计各个出入库单据的对账情况
+     *
+     * @param checkItemList 对账明细
+     */
+    private void enableCheck(Set<PurchaseApCheckItem> checkItemList) {
+        // 先取出表名
+        Set<String> tableNameSet = checkItemList.stream()
+            .filter(item -> !StringUtils.isEmpty(item.getSourceTable()))
+            .map(PurchaseApCheckItem::getSourceTable)
+            .collect(Collectors.toSet());
+        // 根据去重的表名分类统计各个来源id
+        if (!CollectionUtil.isEmpty(tableNameSet)) {
+            // 禁止提交生成对账单状态
+            String disableStatus = "未对账";
+            Set<String> alters = new HashSet<>();
+            // 分别统计各个单据是否存在未对账单据
+            tableNameSet.forEach(tableName -> {
+                Set<Long> sourceIdSet = getSourceIdSet(checkItemList, tableName);
+                List<PurchaseApCheckItem> itemList = this.findBySourceTableAndSourceIdIn(tableName, sourceIdSet);
+                itemList.forEach(item -> {
+                    if (disableStatus.equals(item.getApCheck().getCheckStatus())) {
+                        alters.add(item.getInoutno());
+                    }
+                });
+            });
+            if (!CollectionUtil.isEmpty(alters)) {
+                throw new IllegalOperatorException("订单" + new ModelMap("alters", alters) + "存在未对账的单据,请先进行对账!");
+            }
+        }
+    }
+
+    /**
+     * 按表名统计来源id
+     *
+     * @param checkItemList 对账明细集合
+     * @param tableName 表名
+     * @return id集合
+     */
+    private Set<Long> getSourceIdSet(Set<PurchaseApCheckItem> checkItemList, String tableName) {
+        return checkItemList.stream()
+            .filter(checkItem -> tableName.equals(checkItem.getSourceTable()))
+            .map(PurchaseApCheckItem::getSourceId)
+            .collect(Collectors.toSet());
+    }
 }