package abacus.springboot.example.api;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import com.abacus.pms.wsi.ProductServiceIF;
import com.abacus.xpos.foundation.dao.Employee;
import com.abacus.xpos.foundation.pubs.DaoIdGenerator;
import com.abacus.xpos.foundation.wsi.EmployeeServiceIF;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;

import abacus.commons.component.http.AbacusRestTemplate;
import abacus.commons.exception.BusinessException;
import abacus.commons.standard.util.FileUtil;
import abacus.config.dao.AbacusConfigItem;
import abacus.springboot.example.api.view.ApiBillHg;
import abacus.springboot.example.api.view.ApiBillHgId;
import abacus.springboot.example.api.view.ApiBillHgItem;
import abacus.springboot.example.api.view.ApiBillHgPayment;
import abacus.springboot.example.api.view.ApiJcBill;
import abacus.springboot.example.api.view.ApiJcBillCollect;
import abacus.springboot.example.api.view.ApiJcBillGoodsPhoto;
import abacus.springboot.example.api.view.ApiJcBillHgSearch;
import abacus.springboot.example.api.view.ApiJcBillHgSearchItem;
import abacus.springboot.example.api.view.ApiJcBillItem;
import abacus.springboot.example.api.view.ApiJcBillSearch;
import abacus.springboot.example.api.view.ApiReqJcBill;
import abacus.springboot.example.api.view.ApiReqJcBillGoodsPhoto;
import abacus.springboot.example.api.view.ApiReqJcBillHg;
import abacus.springboot.example.api.view.ApiReqJcBillItem;
import abacus.springboot.example.api.view.ApiReqJcBillPayment;
import abacus.springboot.example.api.view.ApiReqJcBillPhoto;
import abacus.springboot.example.api.view.ApiReqJcBillPhotoItem;
import abacus.springboot.example.api.view.ApiRespBillHgPay;
import abacus.springboot.example.api.view.ApiRespJcPorduct;
import abacus.springboot.example.api.view.ApiRespJcPorductAcount;
import abacus.springboot.example.api.view.ApiRespJcPorductItem;
import abacus.springboot.example.api.view.ApiRespJcPorductProduct;
import abacus.springboot.example.api.view.ApiRespReceiveGoods;
import abacus.springboot.example.api.view.ApiRespWarehouse;
import abacus.springboot.example.api.view.EdgBcsCode;
import abacus.springboot.example.api.view.JcBillCount;
import abacus.springboot.example.api.view.JcCodeFlow;
import abacus.springboot.example.api.view.JcProduct;
import abacus.springboot.example.api.view.JcProductBillSouce;
import abacus.springboot.example.config.JcConfigKey;
import abacus.springboot.example.controller.BaseServlet;
import abacus.springboot.example.dao.JcBill;
import abacus.springboot.example.dao.JcBillHg;
import abacus.springboot.example.dao.JcBillHgPay;
import abacus.springboot.example.dao.JcBillPhoto;
import abacus.springboot.example.dao.JcBillSourceItem;
import abacus.springboot.example.dao.JcSourceItem;
import abacus.springboot.example.pi.AutoCompleteAccessIF;
import abacus.springboot.example.util.DateUtil;
import abacus.springboot.example.esb.JcBillBizService;
import abacus.springboot.example.wsi.ApiJcBillServiceIF;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.Parameters;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.tags.Tag;

/**
 * <p>Title:JcBillController</p>
   <p>Description: 对外接口</p>
   @author chuanZeng 
   @date 2026年8月18日
 */
@RestController
@RequestMapping(value = "/3.0/jc")
@Tag(name="稽查接口服务", description="稽查接口服务说明")
public class JcBillController extends BaseServlet{

	private static final Logger LOG = LoggerFactory.getLogger(JcBillController.class);
	
	@Autowired
	private ApiJcBillServiceIF apiJcBillService;
	
	@Autowired
	private DaoIdGenerator jcBillIdGenerator;
	
	@Autowired
	private ProductServiceIF productService;
	
	@Autowired
	private EmployeeServiceIF employeeService;
	
	@Autowired
	private AutoCompleteAccessIF autoCompleteAccess;
	
	@Autowired
	private JcBillBizService jcBillBizService;
	
	// TODO 百度通用文字识别和二维码识别
	@RequestMapping(value="recogInterface", method = RequestMethod.POST)
	@Operation(summary="百度通用文字识别和二维码识别")
	@Parameters({
		@Parameter(name="imageUrl", 	required = false, description="HTTP URL地址", schema = @Schema(pattern = "", defaultValue=""), example="HTTP:IP/1.PNG"),
	})
	public JSONObject recogInterface(@RequestParam String imageUrl)
			throws Exception {
		try {
			String bdurl = this.getConfigValue("si.baidu.url");
//			String appid = this.getConfigValue("si.baidu.appid");
//			String apikey = this.getConfigValue("si.baidu.apikey");
//			String secretkey = this.getConfigValue("si.baidu.secretkey");
			
			String token = apiJcBillService.getBaiduToken();
			
			if(StringUtils.isBlank(token)) throw new BusinessException("百度token没有获取！");
			
			AbacusRestTemplate art = new AbacusRestTemplate();
			
			HttpHeaders headers = new HttpHeaders();
	        headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
	        
	        // 创建MultiValueMap对象并添加表单数据
	        MultiValueMap<String, String> params = new LinkedMultiValueMap<>();
	        params.add("url", imageUrl);
			
	        // 创建HttpEntity对象
	        HttpEntity<MultiValueMap<String, String>> requestEntity = new HttpEntity<>(params, headers);

			// 同用文字识别
			ResponseEntity<String> resultOcr = art.restTemplate().postForEntity(bdurl + "/rest/2.0/ocr/v1/accurate_basic?access_token=" + token, requestEntity, String.class);
			
			ResponseEntity<String> resultQrcode = art.restTemplate().postForEntity(bdurl + "/rest/2.0/ocr/v1/qrcode?access_token=" + token, requestEntity, String.class);

			JSONObject obj = new JSONObject();
			obj.put("OCR", JSONObject.parse(resultOcr.getBody()));
			obj.put("qrcode", JSONObject.parse(resultQrcode.getBody()));
			return obj;
		} catch (Exception e) {
			LOG.error(e.getMessage(), e);
			e.printStackTrace();
			throw e;
		}
	}
	
	// TODO 稽查收货查询
	@RequestMapping(value="getJcBillSearch", method = RequestMethod.GET)
	@Operation(summary="稽查收货查询")
	@Parameters({
		@Parameter(name="keyword", 	required = false, description="搜索内容（稽查单号货收货产品、货品编号模糊搜索）", schema = @Schema(pattern = "", defaultValue=""), example="JC202411180001"),
		@Parameter(name="employee", required = false, description="员工编码", schema = @Schema(pattern = "", defaultValue=""), example="0"),
		@Parameter(name="status", 	required = false, description="状态", schema = @Schema(pattern = "溯源驳回：-2，待提交：0，待溯源：2，待入库：3，已入库：5 ，回购通知：6，出库：8", defaultValue=""),			example="1"),
		@Parameter(name="page", 	required = false, description="页数", schema = @Schema(pattern = "", defaultValue="1"), example="1"),
		@Parameter(name="size", 	required = false, description="每页显示的条数", 	schema = @Schema(pattern = "", defaultValue="10"), example="10")
	})
	public ApiJcBillCollect getJcBillSearch(
			@RequestParam(required = false) String keyword,
			@RequestParam(required = false) String employee,
			@RequestParam(required = false) String status,
			@RequestParam(required = false) String page,
			@RequestParam(required = false) String size
	) throws Exception{
		try {
			LOG.info("稽查收货查询>>>keyword>>>{}, employee>>>{}, status>>>{}, page>>>{}, size>>>{}, 处理开始", keyword, employee, status, page, size);
			long time0 = System.currentTimeMillis();
			
			// 页数默认为：1
			Integer pageNumber = 1;
			if(StringUtils.isNotBlank(page)) {
				pageNumber = Integer.parseInt(page);
			}
			
			// 每页显示的条数默认为：10
			Integer pageSize = 10;
			if(StringUtils.isNotBlank(size)) {
				pageSize = Integer.parseInt(size);
			}
			
			// 当前页
			Pageable pageable = PageRequest.of(pageNumber - 1, pageSize);
			long time1 = System.currentTimeMillis();
			Page<ApiJcBillSearch> pageLists = apiJcBillService.queryApiJcBillSearch(keyword, employee, status, pageable);
			long time2 = System.currentTimeMillis();
			LOG.info("稽查收货查询>>>queryApiJcBillSearch查询耗时>>>{}", (time2 - time1));
			
			for(ApiJcBillSearch jcBill : pageLists.getContent()) {
				if (jcBill.getHgstatus() == 1)	jcBill.setStatus(JcBill.STATUS_SIX);
				else if (jcBill.getHgstatus() == 2)	jcBill.setStatus(JcBill.STATUS_SEVEN);
			}
			
			if("8".equals(status)) {// 出库状态
				
				// 获取稽查单号集合
		        List<String> billIds = pageLists.getContent().stream()
	                    .map(ApiJcBillSearch::getBillid) 
	                    .collect(Collectors.toList());
		        
		        List<JcBillHg> hgs = apiJcBillService.qeryJcBillHgs(billIds);
				
		        Map<String, List<JcBillHg>> mapHgs = hgs.stream()
						.collect(Collectors.groupingBy(e -> {
							return e.getBillid();
						}, 
						Collectors.collectingAndThen(Collectors.toList(), value -> value)
					));
		        
		        Map<String, Integer> mapBillStatus = new HashMap<String, Integer>();
		        for(String key : mapHgs.keySet()) {
		        	List<JcBillHg> billHgs = mapHgs.get(key);
		        	
		        	// 是否全部出库
		        	boolean hgFale = true;
		        	for(JcBillHg billHg : billHgs) {
		        		if(billHg.getStatus() == 5 || billHg.getStatus() == 4 || billHg.getStatus() == 3
		        				|| billHg.getStatus() == 2 || billHg.getStatus() == 1) {
		        			hgFale = false;
		        			continue;
		        		}
		        	}
		        	
		        	if(hgFale) mapBillStatus.put(key, 9);
		        	else mapBillStatus.put(key, 8);
		        }
		        
		        for(ApiJcBillSearch jcBill : pageLists.getContent()) {
		        	
		        	if(mapBillStatus.containsKey(jcBill.getBillid())) {
		        		Integer ckStatus = mapBillStatus.get(jcBill.getBillid());
		        		if (jcBill.getStatus() == JcBill.STATUS_SIX) {
		        			jcBill.setStatus(8);
			        	} else if (jcBill.getStatus() == JcBill.STATUS_SEVEN) {
			        		jcBill.setStatus(ckStatus);
			        	}
		        	}
				}
			}
				
			
			
			ApiJcBillCollect abc = new ApiJcBillCollect();
			abc.setTotal(pageLists.getTotalElements());
			abc.setTotalPages(pageLists.getTotalPages());
			abc.setBills(pageLists.getContent());
			
			long time3 = System.currentTimeMillis();
			LOG.info("稽查收货查询>>>总耗时>>>{}", (time3 - time0));
			
			return abc;
		} catch(Throwable e){
			LOG.error(e.getMessage(), e);
			e.printStackTrace();
			throw e;
		}
	}
	
	// TODO 稽查收货订单详情查询
	@RequestMapping(value="getJcBillDetails", method = RequestMethod.GET)
	@Operation(summary="稽查收货订单详情查询")
	@Parameters({
		@Parameter(name="billId", 	required = true, description="稽查单号", schema = @Schema(pattern = "", defaultValue=""), example="JC202411180001")
	})
	public ApiJcBill getJcBillDetails(
			@RequestParam(required = false) String billId
	) throws Exception{
		try {
			if(StringUtils.isBlank(billId)) throw new BusinessException("稽查单号不能为空！");
			
			LOG.info("稽查收货订单详情查询>>>billId>>>{}, 处理开始", billId);
			long time0 = System.currentTimeMillis();
			
			ApiJcBill bill = apiJcBillService.queryApiJcBillById(billId);
			long time1 = System.currentTimeMillis();
			LOG.info("稽查收货订单详情查询>>>queryApiJcBillById查询耗时>>>{}", (time1 - time0));
			
			List<JcBillSourceItem> sourceItems = apiJcBillService.queryJcBillSourceItemByBillId(billId);
			long time2 = System.currentTimeMillis();
			LOG.info("稽查收货订单详情查询>>>queryJcBillSourceItemByBillId查询耗时>>>{}", (time2 - time1));
			
			if(sourceItems != null) {
				Map<String, List<JcBillPhoto>> mapPhoto = apiJcBillService.queryJcBillPhoto(billId);
				long time3 = System.currentTimeMillis();
				LOG.info("稽查收货订单详情查询>>>queryJcBillPhoto查询耗时>>>{}", (time3 - time2));
				
				Map<String, List<JcBillSourceItem>> map = sourceItems.stream()
						.collect(Collectors.groupingBy(e -> {
							return String.valueOf(e.getIndexno());
						}, 
						Collectors.collectingAndThen(Collectors.toList(), value -> value)
					));
				
				List<ApiJcBillItem> billItems = new ArrayList<ApiJcBillItem>();
				ApiJcBillItem billItem = null;
				boolean flagStaus = true;
				List<ApiJcBillGoodsPhoto> goodsPhotos = null;
				// 解析图片+明细
				for(String key : map.keySet()) {
					billItem = new ApiJcBillItem();
					List<JcBillSourceItem> temps = map.get(key);
					JcBillSourceItem temp = null;
					
					// 汇总数量
					BigDecimal quantityBig = new BigDecimal("0");
					// 汇总件数
					BigDecimal numbersBig = new BigDecimal("0");
					// 汇总金额
//					BigDecimal subtotalBig = new BigDecimal("0");
					
					goodsPhotos = new ArrayList<ApiJcBillGoodsPhoto>();
					ApiJcBillGoodsPhoto goodsPhoto = null;
					for(JcBillSourceItem item : temps) {
						temp = item;
						
						// 货品图
						List<JcBillPhoto> hpts = mapPhoto.get(JcBillPhoto.JC_HP + "#" + String.valueOf(item.getIndexno()) + "#" + String.valueOf(item.getGoodsid()));
						List<String> hptList = new ArrayList<String>();
						if(hpts != null && hpts.size() >= 1) {
							for(JcBillPhoto hpt : hpts) {
								hptList.add(hpt.getUrlphoto());
							}
						}
						
						// 汇总
						quantityBig = quantityBig.add(new BigDecimal(String.valueOf(item.getQuantity())));
						numbersBig = numbersBig.add(new BigDecimal(String.valueOf(item.getNumbers())));
//						subtotalBig = subtotalBig.add(new BigDecimal(String.valueOf(item.getSubtotal())));
						
						// 图片
						goodsPhoto = new ApiJcBillGoodsPhoto();
						goodsPhoto.setId(item.getId());
						goodsPhoto.setStatus(item.getStatus());
						goodsPhoto.setGoodsid(item.getGoodsid());
						goodsPhoto.setLogisticsid(item.getLogisticsid());
						goodsPhoto.setGoodsPhotos(hptList);
						goodsPhoto.setReason(item.getReason());
						
						if(item.getStatus() == 0) {
							flagStaus = false;
						}
						
						goodsPhotos.add(goodsPhoto);
					}
					
					// 稽查付款截图
					List<JcBillPhoto> fkts = mapPhoto.get(JcBillPhoto.JC_FK + "#" + String.valueOf(temp.getIndexno()));
					if(fkts != null && fkts.size() >= 1) {
						List<String> fkList = new ArrayList<String>();
						
						for(JcBillPhoto fkt : fkts) {
							fkList.add(fkt.getUrlphoto());
						}
						
						billItem.setPaymentPhoto(fkList);
					}
					
					
					billItem.setId(temp.getId());
					billItem.setIndexno(temp.getIndexno());
					billItem.setRecsource(temp.getRecsource());
					billItem.setChannel(temp.getChannel());
					billItem.setRecplatform(temp.getRecplatform());
					billItem.setPrice(temp.getPrice());
					billItem.setQuantity(quantityBig.doubleValue());
					billItem.setNumbers(numbersBig.doubleValue());
					billItem.setSubtotal(temp.getSubtotal());
					billItem.setGoodsPhotos(goodsPhotos);
					
					billItems.add(billItem);
				}
				
				if(bill.getStatus() <= 1) {
					if(bill.getStatus() == -2) {
						bill.setStatus(JcBill.STATUS_MINUS_TWO);
					} else {
						if(flagStaus) {
							bill.setStatus(JcBill.STATUS_ONE);
						}
					}
				}
				
				bill.setItems(billItems);
			}
			
			long time4 = System.currentTimeMillis();
			LOG.info("稽查收货订单详情查询>>>总耗时>>>{}>>>{}", (time4 - time0), JSON.toJSONString(bill));
			
			return bill;
		} catch(Throwable e){
			LOG.error(e.getMessage(), e);
			e.printStackTrace();
			throw e;
		}
	}
	
	
	// TODO 稽查收货-删除订单详情
	@RequestMapping(value="deleteJcBillDetails", method = RequestMethod.GET)
	@Operation(summary="稽查收货删除订单详情")
	@Parameters({
		@Parameter(name="billId", 	required = true, description="稽查单号", schema = @Schema(pattern = "", defaultValue=""), example="JC202411180001"),
		@Parameter(name="itemid", 	required = true, description="稽查明细单号", schema = @Schema(pattern = "", defaultValue=""), example="1")
	})
	public void deleteJcBillDetails(
			@RequestParam(required = false) String billId,
			@RequestParam(required = false) String itemid
	) throws Exception{
		try {
			if(StringUtils.isBlank(billId)) throw new BusinessException("参数[billId]为空！");
			if(StringUtils.isBlank(itemid)) throw new BusinessException("参数[itemid]为空！");
			
			LOG.info("稽查收货删除订单详情>>>billInfo:{},itemid:{},处理开始", billId, itemid);
			long time0 = System.currentTimeMillis();
			
			apiJcBillService.deleteJcSourceItem(billId, itemid);
			
			long time4 = System.currentTimeMillis();
			LOG.info("稽查收货删除订单详情>>>总耗时>>>{}", (time4 - time0));
			
		} catch(Throwable e){
			LOG.error(e.getMessage(), e);
			e.printStackTrace();
			throw e;
		}
	}
	
	
	// TODO 稽查收货订单保存
	@RequestMapping(value="createJcBill", method = RequestMethod.POST)
	@Operation(summary="稽查收货订单保存")
	@Parameters({
		@Parameter(name="billInfo", required = true, description="稽查收货JSONObject", schema = @Schema(implementation = ApiReqJcBill.class))
	})
	public ApiReqJcBill createJcBill(
			@RequestParam(required = false) String billInfo
	) throws Exception{
		try {
			if(StringUtils.isBlank(billInfo)) throw new BusinessException("参数[billInfo]为空！");
			
			LOG.info("稽查收货订单保存>>>billInfo:{},处理开始", billInfo);
			long time0 = System.currentTimeMillis();
			
			ApiReqJcBill reqJcBill = JSON.parseObject(billInfo, ApiReqJcBill.class);
			
			if(StringUtils.isBlank(reqJcBill.getApplicant()) || StringUtils.isBlank(reqJcBill.getApplicantname()))
				throw new BusinessException("参数[applicant]或[applicantname]为空！");
			
			
			if(StringUtils.isBlank(reqJcBill.getId())) jcBillBizService.saveJcBill(reqJcBill);
			else jcBillBizService.updateJcbill(reqJcBill);
			
			long time1 = System.currentTimeMillis();
			LOG.info("稽查收货订单保存>>>总耗时>>>{}", (time1 - time0));
			
			return reqJcBill;
		} catch(Throwable e){
			LOG.error(e.getMessage(), e);
			e.printStackTrace();
			throw e;
		}
	}
	
	// TODO 验证溯源
	@RequestMapping(value="checkSource", method = RequestMethod.POST)
	@Operation(summary="验证溯源")
	@Parameters({
		@Parameter(name="billId", 	required = true, description="稽查单号", schema = @Schema(pattern = "", defaultValue=""), example="JC202411180001")
	})
	public List<JcBillSourceItem> checkSource(
			@RequestParam(required = false) String billId
	) throws Exception{
		try {
			if(StringUtils.isBlank(billId)) throw new BusinessException("稽查单号不能为空！");
			
			LOG.info("验证溯源>>>billId>>>{}, 处理开始", billId);
			long time0 = System.currentTimeMillis();
			
			JcBill jcBill = apiJcBillService.queryJcBillById(billId);
			long time01 = System.currentTimeMillis();
			LOG.info("验证溯源>>>queryJcBillById耗时>>>{}", (time01 - time0));
			
			if(jcBill == null) throw new BusinessException("无收记录信息！");
			
			List<JcBillSourceItem> items = apiJcBillService.queryJcBillSourceItemByBillId(billId);
			long time1 = System.currentTimeMillis();
			LOG.info("验证溯源>>>queryJcBillSourceItemByBillId耗时>>>{}", (time1 - time01));
			
			if(items == null) throw new BusinessException("无收货信息！");
			
			// 获取物流码集合
	        List<String> codes = new ArrayList<>();
	        for(JcBillSourceItem item : items) {
	        	if(StringUtils.isNotBlank(item.getLogisticsid())) {
	        		codes.add(item.getLogisticsid());
	        	}
	        }
			
	        List<JcSourceItem> sourceItems = new ArrayList<JcSourceItem>();
	        if(codes != null && codes.size() >= 1) {
	        	long time2 = System.currentTimeMillis();
	        	List<JcCodeFlow> jcCodeFlows = apiJcBillService.queryJcCodeFlow(codes);
		        long time3 = System.currentTimeMillis();
				LOG.info("验证溯源>>>queryJcCodeFlow耗时>>>{}", (time3 - time2));
				
				List<EdgBcsCode> edgBcsCodes = edgopenapiBcscode(codes);
				long time4 = System.currentTimeMillis();
				LOG.info("验证溯源>>>物流码溯源查询耗时>>>{}", (time4 - time3));
				
				
				JcSourceItem sourceItem = null;
				JcSourceItem sourceItem2 = null;
				
				for(JcBillSourceItem item : items) {
					String key_code = item.getLogisticsid();
					
					// 是否只有一个出库单号
					boolean billFlage = true;
					// 是否溯源成功
					boolean flage = false;
					
					
					String billouts = null, billout = null, billoutdt = null, billoutwh = null, billoutwhname = null, 
							product = null, productname = null, account = null, accountname = null, 
							operator = null, operatorname = null, groupid = null, groupname = null,
							salearea = null, saleareaname = null, source = null;
					// 二维码来源
					if(edgBcsCodes != null && edgBcsCodes.size() >= 1) {
						for(EdgBcsCode bcsCode : edgBcsCodes) {
							if(key_code.equals(bcsCode.getCode())) {
								flage = true;
								
								if(StringUtils.isBlank(billouts)) {
									billouts = bcsCode.getCk_id();
								} else {
									billouts += "," + bcsCode.getCk_id();
								}
								
								billout = bcsCode.getCk_id();
								billoutdt = bcsCode.getCdt();
								billoutwh = bcsCode.getDccw_id();
								billoutwhname = bcsCode.getDccw_name(); 
								product = bcsCode.getProductid();
								productname = bcsCode.getProductname();
								account = bcsCode.getCustomerid();
								accountname = bcsCode.getCustomername(); 
								operator = bcsCode.getEmployeeid();
								operatorname = bcsCode.getEmployeename();
								groupid = bcsCode.getGroup_id();
								groupname = bcsCode.getGroup_name();
								salearea = bcsCode.getDepartmentid(); 
								saleareaname = bcsCode.getDepartmentname();
								source = JcBillSourceItem.SOURCE_EWM;
								
								sourceItem = new JcSourceItem();
								sourceItem.setStatus(JcSourceItem.STATUS_ZERO);
								sourceItem.setBillid(billId);
								sourceItem.setSrcitemid(String.valueOf(item.getId()));
								sourceItem.setGoodsid(item.getGoodsid());
								sourceItem.setLogisticsid(item.getLogisticsid());
								sourceItem.setBillout(billout);
								sourceItem.setBilloutdt(DateUtil.toDateTime(billoutdt));
								sourceItem.setBilloutwh(billoutwh);
								sourceItem.setBilloutwhname(billoutwhname);
								sourceItem.setProduct(product);
								sourceItem.setProductname(productname);
								sourceItem.setAccount(account);
								sourceItem.setAccountname(accountname);
								sourceItem.setOperator(operator);
								sourceItem.setOperatorname(operatorname);
								sourceItem.setGroupid(groupid);
								sourceItem.setGroupname(groupname);
								sourceItem.setSalearea(salearea);
								sourceItem.setSaleareaname(saleareaname);
								sourceItem.setSource(source);
								sourceItem.setDt(new Date());
								
								sourceItems.add(sourceItem);
							}
						}
					}
					
					// 业务中台
					if(jcCodeFlows != null && jcCodeFlows.size() >= 1) {
						for(JcCodeFlow codeFlow : jcCodeFlows) {
							
							if(key_code.equals(codeFlow.getCode())) {
								flage = true;
								
								if(StringUtils.isBlank(billouts)) {
									billouts = codeFlow.getId();
								} else {
									billouts += "," + codeFlow.getId();
								}
								
								billout = codeFlow.getId();
								billoutdt = codeFlow.getTdate();
								billoutwh = codeFlow.getDeposit();
								billoutwhname = codeFlow.getDepositname();
								product = codeFlow.getProductid();
								productname = codeFlow.getProductname();
								account = codeFlow.getCustomerid();
								accountname = codeFlow.getCustomername();
								operator = codeFlow.getAprssalemanid();
								operatorname = codeFlow.getAprssalemanname();
								groupid = codeFlow.getBizgroupid();
								groupname = codeFlow.getBizgroupname();
								salearea = codeFlow.getWsareaid();
								saleareaname = codeFlow.getWsareaname();
								source = JcBillSourceItem.SOURCE_ERP;
								
								sourceItem2 = new JcSourceItem();
								sourceItem2.setStatus(JcSourceItem.STATUS_ZERO);
								sourceItem2.setBillid(billId);
								sourceItem2.setSrcitemid(String.valueOf(item.getId()));
								sourceItem2.setGoodsid(item.getGoodsid());
								sourceItem2.setLogisticsid(item.getLogisticsid());
								sourceItem2.setBillout(billout);
								sourceItem2.setBilloutdt(DateUtil.toDateTime(billoutdt));
								sourceItem2.setBilloutwh(billoutwh);
								sourceItem2.setBilloutwhname(billoutwhname);
								sourceItem2.setProduct(product);
								sourceItem2.setProductname(productname);
								sourceItem2.setAccount(account);
								sourceItem2.setAccountname(accountname);
								sourceItem2.setOperator(operator);
								sourceItem2.setOperatorname(operatorname);
								sourceItem2.setGroupid(groupid);
								sourceItem2.setGroupname(groupname);
								sourceItem2.setSalearea(salearea);
								sourceItem2.setSaleareaname(saleareaname);
								sourceItem2.setSource(source);
								sourceItem2.setDt(new Date());
								
								sourceItems.add(sourceItem2);
							}
						}
					}
					
					if(flage) {
						item.setStatus(JcBillSourceItem.STATUS_ONE);
					} else {
						item.setStatus(JcBillSourceItem.STATUS_MINUS_ONE);
					}
					
					if(StringUtils.isNotBlank(billouts)) item.setBillout(billouts);
					if(StringUtils.isNotBlank(billoutdt)) item.setBilloutdt(DateUtil.toDateTime(billoutdt));
					if(StringUtils.isNotBlank(billoutwh)) item.setBilloutwh(billoutwh);
					if(StringUtils.isNotBlank(billoutwhname)) item.setBilloutwhname(billoutwhname);
					if(StringUtils.isNotBlank(product)) item.setProduct(product);
					if(StringUtils.isNotBlank(productname)) item.setProductname(productname);
					if(StringUtils.isNotBlank(account)) item.setAccount(account);
					if(StringUtils.isNotBlank(accountname)) item.setAccountname(accountname);
					if(StringUtils.isNotBlank(operator)) item.setOperator(operator);
					if(StringUtils.isNotBlank(operatorname)) item.setOperatorname(operatorname);
					if(StringUtils.isNotBlank(groupid)) item.setGroupid(groupid);
					if(StringUtils.isNotBlank(groupname)) item.setGroupname(groupname);
					if(StringUtils.isNotBlank(salearea)) item.setSalearea(salearea);
					if(StringUtils.isNotBlank(saleareaname)) item.setSaleareaname(saleareaname);
					if(StringUtils.isNotBlank(source)) item.setSource(source);
					
				}
	        } else {
	        	for(JcBillSourceItem item : items) {
	        		item.setStatus(JcBillSourceItem.STATUS_MINUS_ONE);
	        	}
	        }
			
			long time5 = System.currentTimeMillis();
			apiJcBillService.saveJcSourceItem(items, sourceItems, jcBill);
			long time00 = System.currentTimeMillis();
			LOG.info("验证溯源>>>saveJcSourceItem耗时>>>{}", (time00 - time5));
			
			LOG.info("验证溯源>>>总耗时>>>{}", (time00 - time0));
			
			return items;
		} catch(Throwable e){
			LOG.error(e.getMessage(), e);
			e.printStackTrace();
			throw e;
		}
	}
	
	/**
	 * 	调第三方接口查询，物流码溯源查询
	 * @param codes
	 * @return
	 * @throws Exception
	 */
	public List<EdgBcsCode> edgopenapiBcscode(List<String> logisticss) throws Exception{
		try {
			long time0 = System.currentTimeMillis();
			List<String> codes = new ArrayList<String>();
			// 取对应连接后32位，生成溯源码
			for(String logistics : logisticss) {
				String[] codeArray = logistics.split("/");
				
				String code = codeArray[codeArray.length - 1];
				
				if(StringUtils.isNotBlank(code)) codes.add(code);
			}
			
			String rzUrl = getConfigValue("pms.rzUrl");
			String param_appkey = getConfigValue("pms.edg_appkey");
			String param_appsecret = getConfigValue("pms.edg_appsecret");
			String bcscodeUrl = rzUrl + "/edgopenapi/services/bcscode";
			String getTokenUrl = rzUrl + getConfigValue("pms.rztokenUrl") + "?EDG-APPKEY=" + param_appkey + "&EDG-APPSECRET=" + param_appsecret;
			
			long time1 = System.currentTimeMillis();
			LOG.info("验证溯源>>>edgopenapiBcscode>>>接口配置参数耗时>>>{}", (time1 - time0));
			
			String result = null, token=null;
			
			AbacusRestTemplate art = new AbacusRestTemplate();
			
			// 获取token
			result = art.restTemplate().getForObject(getTokenUrl, String.class);
			
			if(result != null && !result.equals("")){
				JSONObject json = JSONObject.parseObject(result);
				token = json.getJSONObject("data").getString("token");
			}
			long time2 = System.currentTimeMillis();
			LOG.info("验证溯源>>>edgopenapiBcscode>>>接口token获取耗时>>>{}", (time2 - time1));
			
			if (token != null) {
				// 请求头
				String header_token = "EDAPI-TOKEN";
		        HttpHeaders headers = new HttpHeaders();
		        headers.setContentType(MediaType.APPLICATION_JSON);
		        headers.set(header_token, token);
				
				JSONObject requestJsonObj = new JSONObject();
				JSONObject bodyJsonObj = new JSONObject();
				bodyJsonObj.put("code", codes);
				bodyJsonObj.put("$query-page-size","100");
				bodyJsonObj.put("$query-page-index",1);
				requestJsonObj.put("request", bodyJsonObj);
				
				// 设置body，headers
				HttpEntity<String> requestEntity = new HttpEntity<String>(requestJsonObj.toString(), headers);
				
				// 物流码溯源查询
				result = art.restTemplate().postForObject(bcscodeUrl, requestEntity, String.class);
				long time3 = System.currentTimeMillis();
				LOG.info("验证溯源>>>edgopenapiBcscode>>>物流码溯源查询耗时>>>{}", (time3 - time2));
				
				JSONObject rq = JSONObject.parseObject(result);
				
				if(rq.getString("retcode").equals("EDAC-200")) {
					
					JSONArray jsonArrays = rq.getJSONObject("response").getJSONArray("$data-detail");
					
					if(!jsonArrays.isEmpty()){
						
						List<EdgBcsCode> edgBcsCodes = JSONArray.parseArray(jsonArrays.toJSONString(), EdgBcsCode.class);
						
//						Map<String, EdgBcsCode> map = edgBcsCodes.stream()
//								.collect(Collectors.groupingBy(e -> {
//									return e.getCode();
//								}, 
//								Collectors.collectingAndThen(Collectors.toList(), value -> value.get(0))
//							));
						
						return edgBcsCodes;
					} else {
						return null;
					}
				} else {
					throw new BusinessException("睿治物流码溯源查询接口(" + bcscodeUrl + "),返回异常：" + rq.getString("msg"));
				}
			} else {
				throw new BusinessException("睿治token未获取到,无法调用物流码溯源查询接口！");
			}
		} catch(Throwable e){
			LOG.error(e.getMessage(), e);
			e.printStackTrace();
			throw e;
		}
	}
	
	
	// TODO 提交溯源
	@RequestMapping(value="submitSource", method = RequestMethod.POST)
	@Operation(summary="提交溯源")
	@Parameters({
		@Parameter(name="billId", required = true, description="稽查单号", schema = @Schema(pattern = "", defaultValue=""), example="JC202411180001")
	})
	public void submitSource(
			@RequestParam(required = false) String billId
	) throws Exception{
		try {
			if(StringUtils.isBlank(billId)) throw new BusinessException("参数[billId]为空！");
			
			LOG.info("提交溯源>>>billId:{},处理开始", billId);
			long time0 = System.currentTimeMillis();
			
			JcBill bill = apiJcBillService.queryJcBillById(billId);
			long time1 = System.currentTimeMillis();
			LOG.info("提交溯源>>>queryJcBillById耗时>>>{}", (time1 - time0));
			
			if(bill == null) throw new BusinessException("稽查单号：" + billId + "，未查询到稽查单");
			
			// 状态
			int oldStatus = bill.getStatus();
			
			List<JcBillSourceItem> sourceItems = apiJcBillService.queryJcBillSourceItemByBillId(billId);
			long time2 = System.currentTimeMillis();
			LOG.info("提交溯源>>>queryJcBillSourceItemByBillId耗时>>>{}", (time2 - time1));
			
			if(sourceItems == null) throw new BusinessException("稽查单号：" + billId + "，未查询到稽查收货信息");
			
			Map<String, List<JcBillPhoto>> mapPhto = apiJcBillService.queryJcBillPhoto(billId);
			long time3 = System.currentTimeMillis();
			LOG.info("提交溯源>>>queryJcBillPhoto耗时>>>{}", (time3 - time2));
			
			if(mapPhto == null) throw new BusinessException("稽查单号：" + billId + "，未查询到稽查收货货品图货收款图信息");
			
			if(StringUtils.isBlank(bill.getGoods())) throw new BusinessException("收货产品，不能为空！");
			if(StringUtils.isBlank(bill.getReceivedt())) throw new BusinessException("收货日期，不能为空！");
			if(StringUtils.isBlank(bill.getWarehouse())) throw new BusinessException("收货仓库，不能为空！");
				
			for(JcBillSourceItem item : sourceItems) {
				if(StringUtils.isBlank(item.getRecsource())) throw new BusinessException("收货来源，不能为空！");
//				if(StringUtils.isBlank(item.getRecplatform())) throw new BusinessException("收货平台，不能为空！");
				if(StringUtils.isBlank(item.getChannel())) throw new BusinessException("收货渠道，不能为空！");
				if(item.getPrice() <= 0) throw new BusinessException("收货单价，不能小于等于0！");
				
				if(item.getQuantity() <= 0) throw new BusinessException("收货数量，不能小于等于0！");
				if(item.getNumbers() <= 0) throw new BusinessException("收货件数，不能小于等于0！");
				if(item.getSubtotal() <= 0) throw new BusinessException("收货金额，不能小于等于0！");
				
				if(StringUtils.isBlank(item.getGoodsid())) throw new BusinessException("货品编号，不能为空！");
//				if(StringUtils.isBlank(item.getLogisticsid())) throw new BusinessException("物流码，不能为空！");
				
				if(item.getStatus() == JcBillSourceItem.STATUS_ZERO) throw new BusinessException("货品编号：" + item.getGoodsid() + "，系统溯源未验证！");
				
				String fkt = JcBillPhoto.JC_FK + "#" + item.getIndexno();
				if(!mapPhto.containsKey(fkt)) throw new BusinessException("付款图未上传！");
				
				String hpt = JcBillPhoto.JC_HP + "#" + item.getIndexno() + "#" + item.getGoodsid();
				if(!mapPhto.containsKey(hpt)) throw new BusinessException("货品图未上传！");
			}
			
			bill.setStatus(JcBill.STATUS_TWO);
			
			long time4 = System.currentTimeMillis();
			apiJcBillService.updateStatusJcBill(bill, oldStatus);
			long time5 = System.currentTimeMillis();
			LOG.info("提交溯源>>>updateStatusJcBill耗时>>>{}", (time5 - time4));
			
			LOG.info("提交溯源>>>总耗时>>>{}", (time5 - time0));
			
		} catch(Throwable e){
			LOG.error(e.getMessage(), e);
			e.printStackTrace();
			throw e;
		}
	}
	
	// TODO 回购列表查询
	@RequestMapping(value="getJcBillHgSearch", method = RequestMethod.GET)
	@Operation(summary="回购列表查询")
	@Parameters({
		@Parameter(name="keyword", 	required = false, description="搜索内容（回购/稽查单号/客户名称/编码/收货人手机号/商品名称）", schema = @Schema(pattern = "", defaultValue=""), example="JC202411180001"),
		@Parameter(name="employee", required = false, description="员工编码", schema = @Schema(pattern = "", defaultValue=""), example="0"),
		@Parameter(name="status", 	required = false, description="状态", schema = @Schema(pattern = "待提交：1，待付款：2，待分仓：3，待出库：5，已出库：6 ", defaultValue=""),			example="1"),
		@Parameter(name="page", 	required = false, description="页数", schema = @Schema(pattern = "", defaultValue="1"), example="1"),
		@Parameter(name="size", 	required = false, description="每页显示的条数", 	schema = @Schema(pattern = "", defaultValue="10"), example="10")
	})
	public ApiJcBillHgSearch getJcBillHgSearch(
			@RequestParam(required = false) String keyword,
			@RequestParam(required = false) String employee,
			@RequestParam(required = false) String status,
			@RequestParam(required = false) String page,
			@RequestParam(required = false) String size
	) throws Exception{
		try {
			LOG.info("回购列表查询>>>keyword>>>{}, employee>>>{}, status>>>{}, page>>>{}, size>>>{}, 处理开始", keyword, employee, status, page, size);
			long time0 = System.currentTimeMillis();
			
			// 页数默认为：1
			Integer pageNumber = 1;
			if(StringUtils.isNotBlank(page)) {
				pageNumber = Integer.parseInt(page);
			}
			
			// 每页显示的条数默认为：10
			Integer pageSize = 10;
			if(StringUtils.isNotBlank(size)) {
				pageSize = Integer.parseInt(size);
			}
			
			// 当前页
			Pageable pageable = PageRequest.of(pageNumber - 1, pageSize);
			
			long time1 = System.currentTimeMillis();
			Page<ApiJcBillHgSearchItem> pageLists = apiJcBillService.queryApiJcBillHgSearchItem(keyword, employee, status, pageable);
			long time2 = System.currentTimeMillis();
			LOG.info("回购列表查询>>>queryApiJcBillHgSearchItem查询耗时>>>{}", (time2 - time1));
			
			// 获取回购订单的集合
	        List<String> ids = new ArrayList<String>();
	        for(ApiJcBillHgSearchItem item : pageLists) {
	        	if(StringUtils.isNotBlank(item.getBillHg())) {
	        		ids.add(item.getBillHg());
	        	}
	        }
			
	        long time3 = System.currentTimeMillis();
	        Map<String, JcBillCount> mapCounts = apiJcBillService.queryJcBillCount(ids);
	        long time4 = System.currentTimeMillis();
			LOG.info("回购列表查询>>>queryJcBillCount查询耗时>>>{}", (time4 - time3));
			
			// 回购相关图片
			Map<String, List<JcBillPhoto>> mapPhoto = apiJcBillService.queryJcBillPhotoIn(ids);
			long time5 = System.currentTimeMillis();
			LOG.info("回购订单详情查询>>>queryJcBillPhotoIn查询耗时>>>{}", (time5 - time4));
			
//			String erpUrl = getConfigValue(JcConfigKey.KEY_JC_ERP_URL);
			long time6 = System.currentTimeMillis();
//			LOG.info("回购订单详情查询>>>getConfigValue查询耗时>>>{}", (time6 - time5));
			
			List<ApiBillHgPayment> payments = apiJcBillService.queryApiBillHgPaymentByHgId(ids);
			long time7 = System.currentTimeMillis();
			LOG.info("回购订单详情查询>>>queryApiBillHgPaymentByHgId查询耗时>>>{}", (time7 - time6));
			
			Map<String, List<ApiBillHgPayment>> paymentsMap = new HashMap<String, List<ApiBillHgPayment>>();
			if(payments != null && payments.size() >= 1) {
				paymentsMap = payments.stream()
						.collect(Collectors.groupingBy(e -> {
							return e.getBillhg();
						}, 
						Collectors.collectingAndThen(Collectors.toList(), value -> value)
					));
			}
			
			
			for(ApiJcBillHgSearchItem item : pageLists.getContent()) {
				String billHg = item.getBillHg();
				
				JcBillCount count = mapCounts.get(billHg);
				if(count != null) {
					item.setBreednum(count.getBreednum());
					item.setNumbers(count.getNumbers());
				}
				
				// 回购通知函
				String tzh_key = JcBillPhoto.HG_TZH + "#" + billHg;
				List<JcBillPhoto> tzh = mapPhoto.get(tzh_key);
				
				// 回购违规通知函
				String wgtzh_key = JcBillPhoto.HG_WGTZH + "#" + billHg;
				List<JcBillPhoto> wgtzh = mapPhoto.get(wgtzh_key);
				
				// 回购支付凭证
				String zfpz_key = JcBillPhoto.HG_ZFPZ + "#" + billHg;
				List<JcBillPhoto> zfpz = mapPhoto.get(zfpz_key);
				
				item.setTzhUrl((tzh != null && tzh.size() >= 1) ? "/" +  FileUtil.getFileAccessPath(tzh.get(0).getUrlphoto()) : "");
				item.setWgtzhUrl((wgtzh != null && wgtzh.size() >= 1) ? wgtzh : null);
				item.setZfpzUrl((zfpz != null && zfpz.size() >= 1) ? zfpz : null);
				
				item.setPayments(paymentsMap.get(billHg));
			}
			
			ApiJcBillHgSearch abc = new ApiJcBillHgSearch();
			abc.setTotal(pageLists.getTotalElements());
			abc.setTotalPages(pageLists.getTotalPages());
			abc.setItems(pageLists.getContent());
			
			long time00 = System.currentTimeMillis();
			LOG.info("回购列表查询>>>总耗时>>>{}", (time00 - time0));
			
			return abc;
		} catch(Throwable e){
			LOG.error(e.getMessage(), e);
			e.printStackTrace();
			throw e;
		}
	}
	
	// TODO 回购订单详情查询
	@RequestMapping(value="getJcBillHgDetails", method = RequestMethod.GET)
	@Operation(summary="回购订单详情查询")
	@Parameters({
		@Parameter(name="billHg", 	required = true, description="回购单号", schema = @Schema(pattern = "", defaultValue=""), example="HG202411180001")
	})
	public ApiBillHg getJcBillHgDetails(
			@RequestParam(required = false) String billHg
	) throws Exception{
		try {
			if(StringUtils.isBlank(billHg)) throw new BusinessException("回购单号不能为空！");
			
			LOG.info("回购订单详情查询>>>billHg>>>{}, 处理开始", billHg);
			long time0 = System.currentTimeMillis();
			
			ApiBillHg bill = apiJcBillService.queryApiBillHgById(billHg);
			long time1 = System.currentTimeMillis();
			LOG.info("回购订单详情查询>>>queryApiBillHgById查询耗时>>>{}", (time1 - time0));
			
			if(bill == null) throw new BusinessException("回购单号：" + billHg + "，未查询到回购单！");
			
			List<ApiBillHgItem> billItems = apiJcBillService.queryApiBillHgItemByHgId(billHg);
			long time2 = System.currentTimeMillis();
			LOG.info("回购订单详情查询>>>queryApiBillHgItemByHgId查询耗时>>>{}", (time2 - time1));
			
			List<ApiBillHgPayment> payments = apiJcBillService.queryApiBillHgPaymentByHgId(billHg);
			long time3 = System.currentTimeMillis();
			LOG.info("回购订单详情查询>>>queryApiBillHgPaymentByHgId查询耗时>>>{}", (time3 - time2));
			
			// 获取商品编码集合
	        List<String> productids = billItems.stream()
                    .map(ApiBillHgItem::getProduct) 
                    .collect(Collectors.toList());
			
//			Map<String, JSONObject> mapProductPhoto = productService.getProductsPhoto(productids);
	        Map<String, JSONObject> mapProductPhoto = new HashMap<String, JSONObject>();
			long time4 = System.currentTimeMillis();
			LOG.info("回购订单详情查询>>>getProductsPhoto查询耗时>>>{}", (time4 - time3));
			
			// 设置商品图片
			for(ApiBillHgItem item : billItems) {
				JSONObject obj = mapProductPhoto.get(item.getProduct());
				if(obj != null) item.setProductphoto(obj);
			}
			
			// 回购相关图片
			long time5 = System.currentTimeMillis();
			Map<String, List<JcBillPhoto>> mapPhoto = apiJcBillService.queryJcBillPhoto(billHg);
			long time6 = System.currentTimeMillis();
			LOG.info("回购订单详情查询>>>queryJcBillPhoto查询耗时>>>{}", (time6 - time5));
			
			// 回购通知函
			String tzh_key = JcBillPhoto.HG_TZH + "#" + billHg;
			List<JcBillPhoto> tzh = mapPhoto.get(tzh_key);
			
			// 回购违规通知函
			String wgtzh_key = JcBillPhoto.HG_WGTZH + "#" + billHg;
			List<JcBillPhoto> wgtzh = mapPhoto.get(wgtzh_key);
			
			// 回购支付凭证
			String zfpz_key = JcBillPhoto.HG_ZFPZ + "#" + billHg;
			List<JcBillPhoto> zfpz = mapPhoto.get(zfpz_key);
//			List<String> zfpzs = new ArrayList<String>();
//			if(zfpz != null) {
//				for(JcBillPhoto photo : zfpz) {
//					zfpzs.add(photo.getUrlphoto());
//				}
//			}
			
//			bill.setTzhUrl((tzh != null && tzh.size() >= 1) ? tzh.get(0).getUrlphoto() : "");
//			bill.setWgtzhUrl((wgtzh != null && wgtzh.size() >= 1) ? wgtzh.get(0).getUrlphoto() : "");
//			bill.setZfpzUrl(zfpzs);
			bill.setTzhUrl(tzh);
			bill.setTzhUrls((tzh != null && tzh.size() >= 1) ? "/" +  FileUtil.getFileAccessPath(tzh.get(0).getUrlphoto()) : "");
			bill.setWgtzhUrl(wgtzh);
			bill.setZfpzUrl(zfpz);
			bill.setItems(billItems);
			bill.setPayments(payments);
			
			long time00 = System.currentTimeMillis();
			LOG.info("回购订单详情查询>>>总耗时>>>{}", (time00 - time0));
			
			return bill;
		} catch(Throwable e){
			LOG.error(e.getMessage(), e);
			e.printStackTrace();
			throw e;
		}
	}
	
	// TODO 提交回购订单
	@RequestMapping(value="submitBillHg", method = RequestMethod.POST)
	@Operation(summary="提交回购订单")
	@Parameters({
		@Parameter(name="billInfo", required = true, description="回购订单JSONObject", schema = @Schema(implementation = ApiReqJcBillHg.class))
	})
	public ApiBillHgId submitBillHg(
			@RequestParam(required = false) String billInfo
	) throws Exception{
		try {
			if(StringUtils.isBlank(billInfo)) throw new BusinessException("参数[billInfo]为空！");
			
			LOG.info("提交回购订单>>>billInfo>>>{}, 处理开始", billInfo);
			long time0 = System.currentTimeMillis();
			
			ApiReqJcBillHg reqJcBill = JSON.parseObject(billInfo, ApiReqJcBillHg.class);
			
			if(StringUtils.isBlank(reqJcBill.getId()))
				throw new BusinessException("参数[id]为空！");
			if(reqJcBill.getSubtotal() == null)
				throw new BusinessException("参数[subtotal]为空！");
			if(reqJcBill.getFreight() == null)
				throw new BusinessException("参数[freight]为空！");
			if(StringUtils.isBlank(reqJcBill.getConsignee()))
				throw new BusinessException("参数[consignee]为空！");
			if(StringUtils.isBlank(reqJcBill.getConsigneephone()))
				throw new BusinessException("参数[consigneephone]为空！");
			if(StringUtils.isBlank(reqJcBill.getProvincename()))
				throw new BusinessException("参数[provincename]为空！");
			if(StringUtils.isBlank(reqJcBill.getCityname()))
				throw new BusinessException("参数[cityname]为空！");
			if(StringUtils.isBlank(reqJcBill.getAreaname()))
				throw new BusinessException("参数[areaname]为空！");
			if(StringUtils.isBlank(reqJcBill.getAddress()))
				throw new BusinessException("参数[address]为空！");
			if(StringUtils.isBlank(reqJcBill.getSubmit()))
				throw new BusinessException("参数[submit]为空！");
			if(StringUtils.isBlank(reqJcBill.getSubmitname()))
				throw new BusinessException("参数[submitname]为空！");
			
			long time1 = System.currentTimeMillis();
			JcBillHg billHg = apiJcBillService.queryJcBillHg(reqJcBill.getId());
			long time2 = System.currentTimeMillis();
			LOG.info("提交回购订单>>>queryJcBillHg查询耗时>>>{}", (time2 - time1));
			
			if(billHg == null) throw new BusinessException("回购单号：" + reqJcBill.getId() + "，未查询到回购单！");
			
			// 计算支付众金额
//			BigDecimal paymentAmount = new BigDecimal(String.valueOf(reqJcBill.getSubtotal())).add(new BigDecimal(String.valueOf(reqJcBill.getFreight())));
			
			// 支付
			List<JcBillHgPay> pays = new ArrayList<JcBillHgPay>();
			JcBillHgPay pay = null;
			List<ApiReqJcBillPayment> payments = reqJcBill.getPayments();
			for(ApiReqJcBillPayment payment : payments) {
				if(payment.getAmount() == null)
					throw new BusinessException("参数[amount]为空！");
				if(StringUtils.isBlank(payment.getPayment()))
					throw new BusinessException("参数[payment]为空！");
				if(StringUtils.isBlank(payment.getZhmc()))
					throw new BusinessException("参数[zhmc]为空！");
				if(StringUtils.isBlank(payment.getKhyh()))
					throw new BusinessException("参数[khyh]为空！");
				if(StringUtils.isBlank(payment.getYhzh()))
					throw new BusinessException("参数[yhzh]为空！");
				
				pay = new JcBillHgPay();
				pay.setBillid(billHg.getBillid());
				pay.setBillhg(billHg.getId());
				pay.setPayment(payment.getPayment());
				pay.setAmount(payment.getAmount());
				pay.setZhmc(payment.getZhmc());
				pay.setKhyh(payment.getKhyh());
				pay.setYhzh(payment.getYhzh());
				pay.setDt(new Date());
				
				pays.add(pay);
			}
			
			billHg.setStatus(JcBillHg.STATUS_TWO);
			billHg.setSubtotal(reqJcBill.getSubtotal());
			billHg.setFreight(reqJcBill.getFreight());
			billHg.setConsignee(reqJcBill.getConsignee());
			billHg.setConsigneephone(reqJcBill.getConsigneephone());
			billHg.setProvince(reqJcBill.getProvince());
			billHg.setProvincename(reqJcBill.getProvincename());
			billHg.setCity(reqJcBill.getCity());
			billHg.setCityname(reqJcBill.getCityname());
			billHg.setArea(reqJcBill.getArea());
			billHg.setAreaname(reqJcBill.getAreaname());
			billHg.setAddress(reqJcBill.getAddress());
			billHg.setRemark(reqJcBill.getRemark());
			billHg.setRemark1(reqJcBill.getRemark1());
			billHg.setSubmit(reqJcBill.getSubmit());
			billHg.setSubmitname(reqJcBill.getSubmitname());
			billHg.setSubmitdt(new Date());
			
			long time3 = System.currentTimeMillis();
			LOG.info("提交回购订单>>>逻辑处理耗时>>>{}", (time3 - time2));
			
			apiJcBillService.updateJcBillHg(billHg, pays);
			long time4 = System.currentTimeMillis();
			LOG.info("提交回购订单>>>updateJcBillHg耗时>>>{}", (time4 - time3));
			
			String lastHgId = apiJcBillService.lastBillHgId();
			long time5 = System.currentTimeMillis();
			LOG.info("提交回购订单>>>lastBillHgId耗时>>>{}", (time5 - time4));
			
			LOG.info("提交回购订单>>>总耗时>>>{}", (time5 - time0));
			
			return new ApiBillHgId(lastHgId);
		} catch(Throwable e){
			LOG.error(e.getMessage(), e);
			e.printStackTrace();
			throw e;
		}
	}

	// TODO 查询支付方式
	@RequestMapping(value="queryPayments", method = RequestMethod.GET)
	@Operation(summary="查询支付方式")
	@Parameters({
	})
	public List<ApiRespBillHgPay> queryPayments(
	) throws Exception {
		try {
			LOG.info("查询支付方式>>>处理开始");
			long time0 = System.currentTimeMillis();
			
			Map<String, String> offlineMaps = getConfigSet(JcConfigKey.KEY_GROUP, JcConfigKey.KEY_JC_PAYMENT_OFFLINE);
			long time1 = System.currentTimeMillis();
			LOG.info("查询支付方式>>>getConfigSet耗时>>>{}", (time1 - time0));
			
			List<ApiRespBillHgPay> pays = new ArrayList<ApiRespBillHgPay>();
			ApiRespBillHgPay pay = new ApiRespBillHgPay();
			pay.setPayment("线下支付");
			pay.setKhyh(offlineMaps.get("khyh"));
			pay.setYhzh(offlineMaps.get("yhzh"));
			pay.setZhmc(offlineMaps.get("zhmc"));
			pays.add(pay);
			
			long time00 = System.currentTimeMillis();
			LOG.info("查询支付方式>>>总耗时>>>{}", (time00 - time0));
			
			return pays;
		} catch (Exception e) {
			LOG.error(e.getMessage(), e);
			e.printStackTrace();
			throw e;
		}
	}
	
	// TODO 上传图片
	@RequestMapping(value="uploadingBillPhoto", method = RequestMethod.POST)
	@Operation(summary="上传图片")
	@Parameters({
		@Parameter(name="billInfo", required = true, description="图片JSONObject", schema = @Schema(implementation = ApiReqJcBillPhoto.class)),
		@Parameter(name="type", 	required = true, description="类型", schema = @Schema(pattern = "溯源入库：1，回购发货：2", defaultValue=""), example="HG202411180001"),
		@Parameter(name="accountName", 	required = false, description="账号名称", schema = @Schema(pattern = "当type=2时，必填", defaultValue=""), example="HG202411180001")
	})
	public void uploadingBillPhoto(
			@RequestParam(required = false) String billInfo,
			@RequestParam(required = false) String type,
			@RequestParam(required = false) String accountName
	) throws Exception{
		try {
			if(StringUtils.isBlank(billInfo)) throw new BusinessException("参数[billInfo]为空！");
			if(StringUtils.isBlank(type)) throw new BusinessException("参数[type]为空！");
			
			LOG.info("上传图片>>>type>>>{}, billInfo>>>{}，处理开始", type, billInfo);
			long time0 = System.currentTimeMillis();
			
			ApiReqJcBillPhoto reqBillPhoto = JSON.parseObject(billInfo, ApiReqJcBillPhoto.class);
			
			if("1".equals(type)) {
				if(StringUtils.isBlank(reqBillPhoto.getId()))
					throw new BusinessException("参数[id]为空！");
				JcBill bill = apiJcBillService.queryJcBillById(reqBillPhoto.getId());
				long time_2 = System.currentTimeMillis();
				LOG.info("上传图片>>>queryJcBillById查询耗时>>>{}", (time_2 - time0));
				
				if(bill == null)throw new BusinessException("溯源入库单不存在！");
				
				List<ApiReqJcBillPhotoItem> items = reqBillPhoto.getItems();
				JcBillPhoto billPhoto = null;
				List<JcBillPhoto> billPhotos = new ArrayList<JcBillPhoto>();
				for(ApiReqJcBillPhotoItem item : items) {
					billPhoto = new JcBillPhoto();
							
					billPhoto.setSrcid(reqBillPhoto.getId());
					billPhoto.setSrcitemid(reqBillPhoto.getId());
					billPhoto.setTypephoto(item.getTypePhoto());
					billPhoto.setUrlphoto(item.getUrlPhoto());
					billPhotos.add(billPhoto);
				}
				
				long time1 = System.currentTimeMillis();
				apiJcBillService.saveAndDeletePhoto(billPhotos, reqBillPhoto.getId());
				long time2 = System.currentTimeMillis();
				LOG.info("上传图片>>>saveAndDeletePhoto耗时>>>{}", (time2 - time1));
			} else {
				if(StringUtils.isBlank(reqBillPhoto.getId()))
					throw new BusinessException("参数[id]为空！");
				
				JcBillHg billHg = apiJcBillService.queryJcBillHg(reqBillPhoto.getId());
				long time_2 = System.currentTimeMillis();
				LOG.info("上传图片>>>queryJcBillHg查询耗时>>>{}", (time_2 - time0));
				
				if(billHg == null)throw new BusinessException("回购单不存在！");
				
				List<ApiReqJcBillPhotoItem> items = reqBillPhoto.getItems();
				
				JcBillPhoto billPhoto = null;
				List<JcBillPhoto> billPhotos = new ArrayList<JcBillPhoto>();
				for(ApiReqJcBillPhotoItem item : items) {
					billPhoto = new JcBillPhoto();
							
					billPhoto.setSrcid(reqBillPhoto.getId());
					billPhoto.setSrcitemid(reqBillPhoto.getId());
					billPhoto.setTypephoto(item.getTypePhoto());
					billPhoto.setUrlphoto(item.getUrlPhoto());
					billPhotos.add(billPhoto);
					
					if(JcBillPhoto.HG_ZFPZ.equals(item.getTypePhoto())) {
						if(StringUtils.isBlank(accountName)) throw new BusinessException("参数[accountName]为空！");
						billHg.setStatus(JcBillHg.STATUS_THREE);
						billHg.setProofaccountname(accountName);
						billHg.setProofdt(new Date());
					}
				}
				
				long time1 = System.currentTimeMillis();
				apiJcBillService.saveAndDeletePhoto(billPhotos, billHg);
				long time2 = System.currentTimeMillis();
				LOG.info("上传图片>>>saveAndDeletePhoto耗时>>>{}", (time2 - time1));
			}
			long time3 = System.currentTimeMillis();
			LOG.info("上传图片>>>总耗时>>>{}", (time3 - time0));
			
		} catch(Throwable e){
			LOG.error(e.getMessage(), e);
			e.printStackTrace();
			throw e;
		}
	}

	// TODO 删除图片
	@RequestMapping(value="deleteBillPhoto", method = RequestMethod.POST)
	@Operation(summary="删除图片")
	@Parameters({
		@Parameter(name="id", 	required = true, description="图片序号", schema = @Schema(pattern = "", defaultValue=""), example="1")
	})
	public void deleteBillPhoto(
			@RequestParam(required = false) String id
	) throws Exception{
		try {
			
			if(StringUtils.isBlank(id)) throw new BusinessException("参数[id]为空！");
			
			LOG.info("删除图片>>>id>>>{}，处理开始", id);
			long time0 = System.currentTimeMillis();
			
			JcBillPhoto billPhoto = apiJcBillService.queryJcBillPhotoById(id);
			long time2 = System.currentTimeMillis();
			LOG.info("删除图片>>>queryJcBillPhotoById查询耗时>>>{}", (time2 - time0));
			
			if(billPhoto == null) return;
			
			apiJcBillService.deleteJcBillPhotoById(billPhoto);
			long time3 = System.currentTimeMillis();
			LOG.info("删除图片>>>deleteJcBillPhotoById耗时>>>{}", (time3 - time2));
			
			LOG.info("删除图片>>>总耗时>>>{}", (time3 - time0));
		} catch (Exception e) {
			LOG.error(e.getMessage(), e);
			e.printStackTrace();
			throw e;
		}
	}

	// TODO 查询收货仓库
	@RequestMapping(value="queryWarehouse", method = RequestMethod.GET)
	@Operation(summary="查询收货仓库")
	@Parameters({
		@Parameter(name="keyCode", 	required = true, description="编码或者名称", schema = @Schema(pattern = "", defaultValue=""), example="1")
	})
	public List<ApiRespWarehouse> queryWarehouse(
			@RequestParam(required = false) String keyCode
	) throws Exception {
		try {
			LOG.info("查询收货仓库>>>处理开始");
			long time0 = System.currentTimeMillis();
			
			List<AbacusConfigItem> objs = this.autoCompleteAccess.abacusConfigItemGroupAutoComplete(keyCode, JcConfigKey.KEY_GROUP, JcConfigKey.KEY_JC_WAREHOUSE);
			long time1 = System.currentTimeMillis();
			LOG.info("查询收货仓库>>>getConfigSet耗时>>>{}", (time1 - time0));
			
			List<ApiRespWarehouse> warehouses = new ArrayList<ApiRespWarehouse>();
			ApiRespWarehouse warehouse = null;
			for(AbacusConfigItem obj : objs) {
				warehouse = new ApiRespWarehouse();
				warehouse.setCode(obj.getCode());
				warehouse.setName(obj.getName());
				
				warehouses.add(warehouse);
			}
			
			long time00 = System.currentTimeMillis();
			LOG.info("查询收货仓库>>>总耗时>>>{}", (time00 - time0));
			
			return warehouses;
		} catch (Exception e) {
			LOG.error(e.getMessage(), e);
			e.printStackTrace();
			throw e;
		}
	}
	
	
	// TODO 稽查货品查询---华致第三方用的
	@RequestMapping(value="queryJcProduct", method = RequestMethod.GET)
	@Operation(summary="稽查货品查询")
	@Parameters({
		@Parameter(name="product", 		required = false, description="货品编码", schema = @Schema(pattern = "", defaultValue=""), example="1010400021"),
		@Parameter(name="stockInId", 	required = false, description="入库单号", schema = @Schema(pattern = "", defaultValue=""), example="WDT2292992992"),
		@Parameter(name="hgId", 		required = false, description="回购单号", schema = @Schema(pattern = "", defaultValue=""), example="HG202501090002")
	})
	public List<ApiRespJcPorduct> queryJcProduct(
			@RequestParam(required = false) String product,
			@RequestParam(required = false) String stockInId,
			@RequestParam(required = false) String hgId
	) throws Exception {
		try {
			LOG.info("稽查货品查询>>>处理开始");
			long time0 = System.currentTimeMillis();
			
			if(StringUtils.isBlank(product) && StringUtils.isBlank(stockInId) && StringUtils.isBlank(hgId))
				 throw new BusinessException("参数不能同时为空！");
			
			List<ApiRespJcPorduct> respJcProducts = new ArrayList<ApiRespJcPorduct>();
			respJcProducts.addAll(jcBillBizService.hgAnalyze(product, stockInId, hgId));
			
			LOG.info("稽查货品查询>>>总耗时>>>{}", (System.currentTimeMillis() - time0));
	        
			return respJcProducts;
		} catch (Exception e) {
			LOG.error(e.getMessage(), e);
			e.printStackTrace();
			throw e;
		}
	}
	
	// TODO 修改稽查单状态
	@RequestMapping(value="updateStatus", method = RequestMethod.POST)
	@Operation(summary="修改稽查单状态")
	@Parameters({
		@Parameter(name="billId", required = true, description="稽查单号", schema = @Schema(pattern = "", defaultValue=""), example="JC202411180001"),
		@Parameter(name="status", required = true, description="状态", schema = @Schema(pattern = "-3：取消，0：待提交", defaultValue=""), example="-3")
	})
	public void updateStatus(
			@RequestParam(required = false) String billId,
			@RequestParam(required = false) String status
	) throws Exception {
		try {
			LOG.info("修改稽查单状态>>>处理开始");
			long time0 = System.currentTimeMillis();
			
			if(StringUtils.isBlank(billId)) throw new BusinessException("参数[billId]为空！");
			if(StringUtils.isBlank(status)) throw new BusinessException("参数[status]为空！");
			
			JcBill bill = apiJcBillService.queryJcBillById(billId);
			long time1 = System.currentTimeMillis();
			LOG.info("修改稽查单状态>>>queryJcBillById耗时>>>{}", (time1 - time0));
			
			if(status.equals("0") || status.equals("-3")) {
				apiJcBillService.updateStatusByJcBill(bill, Integer.parseInt(status));
				LOG.info("修改稽查单状态>>>updateStatusByJcBill耗时>>>{}", (System.currentTimeMillis() - time1));
			} else {
				throw new BusinessException("该状态不支持修改！");
			}
			
			LOG.info("修改稽查单状态>>>总耗时>>>{}", (System.currentTimeMillis() - time0));
			
		} catch (Exception e) {
			LOG.error(e.getMessage(), e);
			e.printStackTrace();
			throw e;
		}
	}
	
	
	
	// TODO 溯源结果
	@RequestMapping(value="billSourceItem", method = RequestMethod.POST)
	@Operation(summary="溯源结果")
	@Parameters({
		@Parameter(name="itemId", required = true, description="明细序号", schema = @Schema(pattern = "", defaultValue=""), example="11"),
	})
	public JcBillSourceItem billSourceItem(
			@RequestParam(required = false) String itemId
	) throws Exception {
		try {
			LOG.info("溯源结果>>>处理开始");
			long time0 = System.currentTimeMillis();
			
			if(StringUtils.isBlank(itemId)) throw new BusinessException("参数[itemId]为空！");
			
			JcBillSourceItem sourceItem = apiJcBillService.queryJcBillSourceItembyId(Long.parseLong(itemId));
			LOG.info("溯源结果>>>queryJcBillSourceItembyId查询耗时>>>{}", (System.currentTimeMillis() - time0));
			
			LOG.info("溯源结果>>>总耗时>>>{}", (System.currentTimeMillis() - time0));
			
			return sourceItem;
		} catch (Exception e) {
			LOG.error(e.getMessage(), e);
			e.printStackTrace();
			throw e;
		}
	}
	
	
	// TODO 根据回购明细id，查询物流码和对应的出库单号
	@RequestMapping(value="receiveGoods", method = RequestMethod.POST)
	@Operation(summary="查看收货信息")
	@Parameters({
		@Parameter(name="billHg", required = true, description="回购单号", schema = @Schema(pattern = "", defaultValue=""), example="HG202501020001"),
	})
	public List<ApiRespReceiveGoods> receiveGoods(
			@RequestParam(required = false) String billHg
	) throws Exception {
		try {
			LOG.info("查看收货信息>>>处理开始");
			long time0 = System.currentTimeMillis();
			
			if(StringUtils.isBlank(billHg)) throw new BusinessException("参数[billHg]为空！");
			
			ApiBillHg bill = apiJcBillService.queryApiBillHgById(billHg);
			long time1 = System.currentTimeMillis();
			LOG.info("查看收货信息>>>queryApiBillHgById查询耗时>>>{}", (time1 - time0));
			
			if(bill == null) throw new BusinessException("回购单号：" + billHg + "，未查询到回购单！");
			
			List<ApiBillHgItem> billItems = apiJcBillService.queryApiBillHgItemByHgId(billHg);
			long time2 = System.currentTimeMillis();
			LOG.info("查看收货信息>>>queryApiBillHgItemByHgId查询耗时>>>{}", (time2 - time1));
			
			List<JcBillSourceItem> sources = apiJcBillService.queryJcBillSourceItemByBillId(bill.getBillid());
			LOG.info("查看收货信息>>>queryJcBillSourceItemByBillId查询耗时>>>{}", (System.currentTimeMillis() - time0));
			
			Map<String, List<JcBillSourceItem>> sourceMaps = sources.stream()
					.collect(Collectors.groupingBy(e -> {
						return e.getAccount() + e.getProduct();
					}, 
					Collectors.collectingAndThen(Collectors.toList(), value -> value)
				));
			
			List<ApiRespReceiveGoods> apiLists = new ArrayList<ApiRespReceiveGoods>();
			ApiRespReceiveGoods arg = null;
			for(ApiBillHgItem hgItem : billItems) {
				List<JcBillSourceItem> tempLists = sourceMaps.get(bill.getAccount() + hgItem.getProduct());
				
				for(JcBillSourceItem item : tempLists) {
					arg = new ApiRespReceiveGoods();
					arg.setBillid(bill.getBillid());
					arg.setLogisticsid(item.getLogisticsid());
					arg.setBillout(item.getBillout());
					
					apiLists.add(arg);
				}
			}
			
			LOG.info("查看收货信息>>>总耗时>>>{}", (System.currentTimeMillis() - time0));
			
			return apiLists;
		} catch (Exception e) {
			LOG.error(e.getMessage(), e);
			e.printStackTrace();
			throw e;
		}
	}
}



















































