package com.api.controller.v1; import com.alibaba.excel.EasyExcel; import com.alibaba.fastjson.JSONObject; import com.hfkj.common.exception.ErrorCode; import com.hfkj.common.exception.ErrorHelp; import com.hfkj.common.exception.SysCode; import com.hfkj.common.utils.*; import com.hfkj.config.CommonSysConst; import com.hfkj.entity.BsMer; import com.hfkj.entity.BsTradeOrder; import com.hfkj.entity.BsTradeOrderRefund; import com.hfkj.model.ResponseData; import com.hfkj.obs.HuaWeiYunObs; import com.hfkj.openapi.v1.model.*; import com.hfkj.openapi.v1.model.request.*; import com.hfkj.openapi.v1.model.response.ResponseQueryTradeModel; import com.hfkj.openapi.v1.model.response.ResponseRefundTradeModel; import com.hfkj.openapi.v1.service.OpenApiTradeOrderService; import com.hfkj.openapi.v1.utils.SignatureUtil; import com.hfkj.service.BsMerKeyService; import com.hfkj.service.BsMerService; import com.hfkj.sysenum.*; import com.obs.services.model.PutObjectResult; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; import org.apache.commons.lang3.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.stereotype.Controller; import org.springframework.util.ResourceUtils; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; import javax.annotation.Resource; import javax.servlet.http.HttpServletRequest; import javax.validation.constraints.NotBlank; import java.io.File; import java.math.BigDecimal; import java.util.*; @Controller @Api(value = "交易订单") @RequestMapping(value = "/v1/trade") public class TradeController { private static Logger log = LoggerFactory.getLogger(TradeController.class); @Resource private BsMerKeyService merKeyService; @Resource private OpenApiTradeOrderService openApiTradeOrderService; @Resource private BsMerService merService; @RequestMapping(value="/preorder",method = RequestMethod.POST) @ResponseBody @ApiOperation(value = "聚合主扫") public ResponseData preorder(@Validated @RequestBody RequestTradePreorderModel body, HttpServletRequest request) { log.info("========= Start 聚合主扫接口 Start ==========="); log.info("请求参数:" + JSONObject.toJSONString(body)); try { // 验证签名 if (!SignatureUtil.checkSign(body.getSign(), body, merKeyService.getKeyByMerNo(body.getMerchantNo()))) { throw ErrorHelp.genException(SysCode.OpenApi, ErrorCode.OPEN_API_SIGN_ERR, ""); } if (!body.getTransType().equals("JSAPI") && !body.getTransType().equals("NATIVE")) { throw ErrorHelp.genException(SysCode.OpenApi, ErrorCode.OPEN_API_COMMON, "接入方式错误"); } if (body.getTransType().equals("JSAPI") && StringUtils.isBlank(body.getUserId())) { throw ErrorHelp.genException(SysCode.OpenApi, ErrorCode.OPEN_API_COMMON, "用户标识必填项"); } // 查询支付方式 TradeOrderPayModeEnum payMode = TradeOrderPayModeEnum.getNameByCode(body.getPayMode()); if (payMode == null) { throw ErrorHelp.genException(SysCode.OpenApi, ErrorCode.OPEN_API_COMMON, "支付方式错误"); } // 查询商户 BsMer mer = merService.getMer(body.getMerchantNo()); if (mer == null) { throw ErrorHelp.genException(SysCode.OpenApi, ErrorCode.OPEN_API_COMMON, "未知的商户号"); } if (!mer.getMerStatus().equals(MerStatusEnum.status1.getNumber())) { throw ErrorHelp.genException(SysCode.OpenApi, ErrorCode.OPEN_API_COMMON, "商户状态异常"); } // 查询订单号是否存在 BsTradeOrder outTradeNo = openApiTradeOrderService.getOrderByOutTradeNo(body.getOutTradeNo()); if (outTradeNo != null) { throw ErrorHelp.genException(SysCode.OpenApi, ErrorCode.OPEN_API_COMMON, "商户交易流水重复"); } BsTradeOrder tradeOrder = new BsTradeOrder(); tradeOrder.setTransType(body.getTransType()); tradeOrder.setCompanyId(mer.getCompanyId()); tradeOrder.setAgentId(mer.getAgentId()); tradeOrder.setSalesmanId(mer.getSalesmanId()); tradeOrder.setSalesmanName(mer.getSalesmanName()); tradeOrder.setMerId(mer.getId()); tradeOrder.setMerName(mer.getMerName()); tradeOrder.setMerNo(mer.getMerNo()); tradeOrder.setMerAbbreviate(mer.getMerAbbreviate()); tradeOrder.setOutTradeNo(body.getOutTradeNo()); tradeOrder.setTradeAmount(new BigDecimal(body.getTotalAmount())); tradeOrder.setTradeActualAmount(tradeOrder.getTradeAmount()); tradeOrder.setPayMode(payMode.getCode()); tradeOrder.setStatus(TradeOrderStatusEnum.status1.getNumber()); tradeOrder.setProfitSharingStatus(body.getProfitSharing().equals("0")?false:true); tradeOrder.setCreateType(TradeOrderCreateTypeEnum.type3.getCode()); tradeOrder.setPayAppid(body.getSubAppid()); tradeOrder.setPayUserId(body.getUserId()); tradeOrder.setTimeoutExpress(body.getTimeoutExpress()); tradeOrder.setPayNotifyUrl(body.getNotifyUrl()); tradeOrder.setSubject(body.getSubject()); tradeOrder.setRefundPrice(new BigDecimal("0")); tradeOrder.setAttach(body.getAttach()); tradeOrder.setSpecialField(body.getSpecialField()); tradeOrder.setRequestIp(RequestUtils.getIpAddress(request)); tradeOrder.setRebateActivityPart(false); // 创建交易订单 Map returnParam = openApiTradeOrderService.createOrder(tradeOrder); log.info("返回参数:" + JSONObject.toJSONString(returnParam)); return ResponseMsgUtil.success(returnParam); } catch (Exception e) { log.info("出现异常:", e); return ResponseMsgUtil.exception(e); } finally { log.info("========= END 聚合主扫接口 END ==========="); } } @RequestMapping(value="/counter",method = RequestMethod.POST) @ResponseBody @ApiOperation(value = "收银台") public ResponseData counter(@Validated @RequestBody RequestTradeCounterModel body, HttpServletRequest request) { log.info("========= Start 收银台接口 Start ==========="); log.info("请求参数:" + JSONObject.toJSONString(body)); try { // 验证签名 if (!SignatureUtil.checkSign(body.getSign(), body, merKeyService.getKeyByMerNo(body.getMerchantNo()))) { throw ErrorHelp.genException(SysCode.OpenApi, ErrorCode.OPEN_API_SIGN_ERR, ""); } // 查询商户 BsMer mer = merService.getMer(body.getMerchantNo()); if (mer == null) { throw ErrorHelp.genException(SysCode.OpenApi, ErrorCode.OPEN_API_COMMON, "未知的商户号"); } if (!mer.getMerStatus().equals(MerStatusEnum.status1.getNumber())) { throw ErrorHelp.genException(SysCode.OpenApi, ErrorCode.OPEN_API_COMMON, "商户状态异常"); } // 查询订单号是否存在 BsTradeOrder outTradeNo = openApiTradeOrderService.getOrderByOutTradeNo(body.getOutTradeNo()); if (outTradeNo != null) { throw ErrorHelp.genException(SysCode.OpenApi, ErrorCode.OPEN_API_COMMON, "商户交易流水重复"); } BsTradeOrder tradeOrder = new BsTradeOrder(); tradeOrder.setTransType("COUNTER"); tradeOrder.setCompanyId(mer.getCompanyId()); tradeOrder.setAgentId(mer.getAgentId()); tradeOrder.setSalesmanId(mer.getSalesmanId()); tradeOrder.setSalesmanName(mer.getSalesmanName()); tradeOrder.setMerId(mer.getId()); tradeOrder.setMerName(mer.getMerName()); tradeOrder.setMerNo(mer.getMerNo()); tradeOrder.setMerAbbreviate(mer.getMerAbbreviate()); tradeOrder.setOutTradeNo(body.getOutTradeNo()); tradeOrder.setTradeAmount(new BigDecimal(body.getTotalAmount())); tradeOrder.setTradeActualAmount(tradeOrder.getTradeAmount()); tradeOrder.setStatus(TradeOrderStatusEnum.status1.getNumber()); tradeOrder.setProfitSharingStatus(false); tradeOrder.setPeriodStatus(false); tradeOrder.setCreateType(TradeOrderCreateTypeEnum.type3.getCode()); tradeOrder.setPayAppid(body.getSubAppid()); tradeOrder.setPayUserId(body.getUserId()); tradeOrder.setTimeoutExpress(body.getTimeoutExpress()); tradeOrder.setPayNotifyUrl(body.getNotifyUrl()); tradeOrder.setPayCallbackUrl(body.getCallbackUrl()); tradeOrder.setSubject(body.getSubject()); tradeOrder.setRefundPrice(new BigDecimal("0")); tradeOrder.setAttach(body.getAttach()); tradeOrder.setSpecialField(body.getSpecialField()); tradeOrder.setRequestIp(RequestUtils.getIpAddress(request)); tradeOrder.setRebateActivityPart(false); // 创建交易订单 Map returnParam = openApiTradeOrderService.counterCreateOrder(tradeOrder); log.info("返回参数:" + JSONObject.toJSONString(returnParam)); return ResponseMsgUtil.success(returnParam); } catch (Exception e) { log.info("出现异常:", e); return ResponseMsgUtil.exception(e); } finally { log.info("========= END 收银台接口 END ==========="); } } @RequestMapping(value="/queryTrade",method = RequestMethod.POST) @ResponseBody @ApiOperation(value = "查询交易") public ResponseData queryTrade(@RequestBody RequestQueryTradeModel body) { log.info("========= Start 查询交易 Start ==========="); log.info("请求参数:" + JSONObject.toJSONString(body)); try { // 验证签名 if (!SignatureUtil.checkSign(body.getSign(), body, merKeyService.getKeyByMerNo(body.getMerchantNo()))) { throw ErrorHelp.genException(SysCode.OpenApi, ErrorCode.OPEN_API_SIGN_ERR, ""); } // 查询交易订单号 BsTradeOrder tradeOrder = openApiTradeOrderService.getOrderByOutTradeNo(body.getOutTradeNo()); if (tradeOrder == null) { throw ErrorHelp.genException(SysCode.OpenApi, ErrorCode.OPEN_API_COMMON, "未知的交易订单号"); } ResponseQueryTradeModel responseQueryTradeModel = new ResponseQueryTradeModel(); responseQueryTradeModel.setMerchantNo(tradeOrder.getMerNo()); responseQueryTradeModel.setOutTradeNo(tradeOrder.getOutTradeNo()); responseQueryTradeModel.setAccTradeNo(tradeOrder.getAccTradeNo()); responseQueryTradeModel.setPlatformTradeNo(tradeOrder.getPlatformTradeNo()); responseQueryTradeModel.setUserId(tradeOrder.getPayUserId()); responseQueryTradeModel.setPayMode(tradeOrder.getPayMode()); responseQueryTradeModel.setTradeAmount(tradeOrder.getTradeAmount()); responseQueryTradeModel.setTradeActualAmount(tradeOrder.getTradeActualAmount()); responseQueryTradeModel.setStatus(tradeOrder.getStatus()); responseQueryTradeModel.setCreateTime(tradeOrder.getCreateTime()); responseQueryTradeModel.setPayTime(tradeOrder.getPayTime()); responseQueryTradeModel.setAttach(tradeOrder.getAttach()); responseQueryTradeModel.setSign(SignatureUtil.createSign(responseQueryTradeModel, merKeyService.getKeyByMerNo(body.getMerchantNo()))); log.info("返回参数:" + JSONObject.toJSONString(responseQueryTradeModel)); return ResponseMsgUtil.success(responseQueryTradeModel); } catch (Exception e) { log.info("出现异常:", e); return ResponseMsgUtil.exception(e); } finally { log.info("========= END 查询交易 END ==========="); } } @RequestMapping(value="/refund",method = RequestMethod.POST) @ResponseBody @ApiOperation(value = "退款交易") public ResponseData refund(@Validated @RequestBody RequestRefundTradeModel body) { log.info("========= Start 退款交易接口 Start ==========="); log.info("请求参数:" + JSONObject.toJSONString(body)); try { // 验证签名 if (!SignatureUtil.checkSign(body.getSign(), body, merKeyService.getKeyByMerNo(body.getMerchantNo()))) { throw ErrorHelp.genException(SysCode.OpenApi, ErrorCode.OPEN_API_SIGN_ERR, ""); } // 查询退款单号 BsTradeOrderRefund refund = openApiTradeOrderService.getRefundByNo(body.getRefundTradeNo()); if (refund != null) { throw ErrorHelp.genException(SysCode.OpenApi, ErrorCode.OPEN_API_COMMON, "退款流水重复"); } ResponseRefundTradeModel responseRefundTradeModel = openApiTradeOrderService.refund(body); log.info("返回参数:" + JSONObject.toJSONString(responseRefundTradeModel)); return ResponseMsgUtil.success(responseRefundTradeModel); } catch (Exception e) { log.info("出现异常:", e); return ResponseMsgUtil.exception(e); } finally { log.info("========= END 退款交易接口 END ==========="); } } @RequestMapping(value="/queryRefund",method = RequestMethod.POST) @ResponseBody @ApiOperation(value = "查询退款") public ResponseData queryRefund(@RequestBody RequestQueryRefundModel body) { log.info("========= Start 查询退款 Start ==========="); log.info("请求参数:" + JSONObject.toJSONString(body)); try { // 验证签名 if (!SignatureUtil.checkSign(body.getSign(), body, merKeyService.getKeyByMerNo(body.getMerchantNo()))) { throw ErrorHelp.genException(SysCode.OpenApi, ErrorCode.OPEN_API_SIGN_ERR, ""); } // 查询交易订单号 BsTradeOrderRefund refund = openApiTradeOrderService.getRefundByNo(body.getRefundTradeNo()); if (refund == null) { throw ErrorHelp.genException(SysCode.OpenApi, ErrorCode.OPEN_API_COMMON, "未知的退款单号"); } // 查询交易订单 BsTradeOrder tradeOrder = openApiTradeOrderService.getOrderByOutTradeNo(refund.getOutTradeNo()); if (tradeOrder == null) { throw ErrorHelp.genException(SysCode.OpenApi, ErrorCode.OPEN_API_COMMON, "未知的交易订单"); } ResponseRefundTradeModel refundTradeModel = new ResponseRefundTradeModel(); refundTradeModel.setMerchantNo(tradeOrder.getMerNo()); refundTradeModel.setOutTradeNo(tradeOrder.getOutTradeNo()); refundTradeModel.setPayMode(tradeOrder.getPayMode()); refundTradeModel.setRefundTradeNo(refund.getRefundNo()); refundTradeModel.setAccTradeNo(refund.getAccTradeNo()); refundTradeModel.setRefundAmount(refund.getRefundAmount().toString()); refundTradeModel.setRefundPayerAmount(refund.getPayerAmount().toString()); refundTradeModel.setRefundTime(refund.getRefundTime()); refundTradeModel.setSign(SignatureUtil.createSign(refundTradeModel, merKeyService.getKeyByMerNo(tradeOrder.getMerNo()))); log.info("返回参数:" + JSONObject.toJSONString(refundTradeModel)); return ResponseMsgUtil.success(refundTradeModel); } catch (Exception e) { log.info("出现异常:", e); return ResponseMsgUtil.exception(e); } finally { log.info("========= END 查询退款 END ==========="); } } @RequestMapping(value="/tradeBills",method = RequestMethod.POST) @ResponseBody @ApiOperation(value = "账单下载") public ResponseData tradeBills(@RequestBody RequestTradeBillsModel body) { log.info("========= Start 账单下载 Start ==========="); log.info("请求参数:" + JSONObject.toJSONString(body)); try { // 验证签名 if (!SignatureUtil.checkSign(body.getSign(), body, merKeyService.getKeyByMerNo(body.getMerchantNo()))) { throw ErrorHelp.genException(SysCode.OpenApi, ErrorCode.OPEN_API_SIGN_ERR, ""); } if (body.getBillDateS().compareTo(body.getBillDateE()) >= 0) { throw ErrorHelp.genException(SysCode.OpenApi, ErrorCode.OPEN_API_COMMON, "开始时间必须小于结束时间"); } // 最大周期范围3个月 90天 Long maxTime = 60*24*90L; if (maxTime.compareTo(DateUtil.getMinutesDiff(new Date(body.getBillDateS()), new Date(body.getBillDateE()))) < 0) { throw ErrorHelp.genException(SysCode.OpenApi, ErrorCode.OPEN_API_COMMON, "时间范围大于3个月"); } List tradeBills = openApiTradeOrderService.tradeBills(body.getMerchantNo(), body.getBillDateS(), body.getBillDateE()); String childPath = "temporary/"; String fileName = System.currentTimeMillis() + "" + Math.abs(new Random().nextInt() % 1000) + ".xlsx"; EasyExcel.write(CommonSysConst.getSysConfig().getFilesystem() + "/" + childPath + fileName, TradeBillsModel.class) .sheet(body.getMerchantNo()) .doWrite(tradeBills); // 上传华为云 OBS HuaWeiYunObs.obsUtilPutObject(CommonSysConst.getSysConfig().getFilesystem() + "/" + childPath + fileName, HuaWeiYunObs.bucketName, childPath + fileName); // 延迟1秒 OBS服务器内网上传,有时间差 Thread.sleep(1000); String fileUrl = CommonSysConst.getSysConfig().getObs_url() + "/"+ childPath + fileName; log.info("返回参数:" + fileUrl); return ResponseMsgUtil.success(fileUrl); } catch (Exception e) { log.info("出现异常:", e); return ResponseMsgUtil.exception(e); } finally { log.info("========= END 账单下载 END ==========="); } } @RequestMapping(value="/tradeRefundBills",method = RequestMethod.POST) @ResponseBody @ApiOperation(value = "账单退款下载") public ResponseData tradeRefundBills(@RequestBody RequestTradeRefundBillsModel body) { log.info("========= Start 账单退款下载 Start ==========="); log.info("请求参数:" + JSONObject.toJSONString(body)); try { // 验证签名 if (!SignatureUtil.checkSign(body.getSign(), body, merKeyService.getKeyByMerNo(body.getMerchantNo()))) { throw ErrorHelp.genException(SysCode.OpenApi, ErrorCode.OPEN_API_SIGN_ERR, ""); } if (body.getBillDateS().compareTo(body.getBillDateE()) >= 0) { throw ErrorHelp.genException(SysCode.OpenApi, ErrorCode.OPEN_API_COMMON, "开始时间必须小于结束时间"); } // 最大周期范围3个月 90天 Long maxTime = 60*24*90L; if (maxTime.compareTo(DateUtil.getMinutesDiff(new Date(body.getBillDateS()), new Date(body.getBillDateE()))) < 0) { throw ErrorHelp.genException(SysCode.OpenApi, ErrorCode.OPEN_API_COMMON, "时间范围大于3个月"); } List tradeBills = openApiTradeOrderService.tradeRefundBills(body.getMerchantNo(), body.getBillDateS(), body.getBillDateE()); String childPath = "temporary/"; String fileName = System.currentTimeMillis() + "" + Math.abs(new Random().nextInt() % 1000) + ".xlsx"; EasyExcel.write(CommonSysConst.getSysConfig().getFilesystem() + "/" + childPath + fileName, TradeRefundBillsModel.class) .sheet(body.getMerchantNo()) .doWrite(tradeBills); // 上传华为云 OBS HuaWeiYunObs.obsUtilPutObject(CommonSysConst.getSysConfig().getFilesystem() + "/" + childPath + fileName, HuaWeiYunObs.bucketName, childPath + fileName); // 延迟1秒 OBS服务器内网上传,有时间差 Thread.sleep(1000); String fileUrl = CommonSysConst.getSysConfig().getObs_url() + "/"+ childPath + fileName; log.info("返回参数:" + fileUrl); return ResponseMsgUtil.success(fileUrl); } catch (Exception e) { log.info("出现异常:", e); return ResponseMsgUtil.exception(e); } finally { log.info("========= END 账单退款下载 END ==========="); } } @RequestMapping(value="/tradeSettleBills",method = RequestMethod.POST) @ResponseBody @ApiOperation(value = "交易结算账单下载") public ResponseData tradeSettleBills(@RequestBody RequestTradeSettleBillsModel body) { log.info("========= Start 交易结算账单下载 Start ==========="); log.info("请求参数:" + JSONObject.toJSONString(body)); try { // 验证签名 if (!SignatureUtil.checkSign(body.getSign(), body, merKeyService.getKeyByMerNo(body.getMerchantNo()))) { throw ErrorHelp.genException(SysCode.OpenApi, ErrorCode.OPEN_API_SIGN_ERR, ""); } // 最大周期范围1个月 31天 Long maxTime = 60*24*31L; if (maxTime.compareTo(DateUtil.getMinutesDiff(new Date(body.getBillDateS()), new Date(body.getBillDateE()))) < 0) { throw ErrorHelp.genException(SysCode.OpenApi, ErrorCode.OPEN_API_COMMON, "时间范围大于1个月"); } Calendar billDateE = Calendar.getInstance(); billDateE.setTime(new Date(body.getBillDateE())); billDateE.set(Calendar.HOUR_OF_DAY, 00); billDateE.set(Calendar.MINUTE, 00); billDateE.set(Calendar.SECOND, 00); // 当前时间 Calendar currentDate = Calendar.getInstance(); currentDate.set(Calendar.HOUR_OF_DAY, 00); currentDate.set(Calendar.MINUTE, 00); currentDate.set(Calendar.SECOND, 00); if (DateUtil.getMinutesDiff(billDateE.getTime(),currentDate.getTime()) <= 0) { currentDate.add(Calendar.DAY_OF_MONTH, -1); body.setBillDateE(currentDate.getTimeInMillis()); } List tradeBills = openApiTradeOrderService.tradeSettleBills(body.getMerchantNo(), body.getBillDateS(), body.getBillDateE()); String childPath = "temporary/"; String fileName = System.currentTimeMillis() + "" + Math.abs(new Random().nextInt() % 1000) + ".xlsx"; EasyExcel.write(CommonSysConst.getSysConfig().getFilesystem() + "/" + childPath + fileName, TradeDetailBillsModel.class) .sheet(body.getMerchantNo()) .doWrite(tradeBills); // 上传华为云 OBS HuaWeiYunObs.obsUtilPutObject(CommonSysConst.getSysConfig().getFilesystem() + "/" + childPath + fileName, HuaWeiYunObs.bucketName, childPath + fileName); // 延迟1秒 OBS服务器内网上传,有时间差 Thread.sleep(1000); String fileUrl = CommonSysConst.getSysConfig().getObs_url() + "/"+ childPath + fileName; log.info("返回参数:" + fileUrl); return ResponseMsgUtil.success(fileUrl); } catch (Exception e) { log.info("出现异常:", e); return ResponseMsgUtil.exception(e); } finally { log.info("========= END 交易结算账单下载 END ==========="); } } }