package com.java110.fee.cmd.fee; import com.alibaba.fastjson.JSONArray; import com.alibaba.fastjson.JSONObject; import com.java110.core.annotation.Java110Cmd; import com.java110.core.annotation.Java110Transactional; import com.java110.core.context.CmdContextUtils; import com.java110.core.context.ICmdDataFlowContext; import com.java110.core.event.cmd.Cmd; import com.java110.core.event.cmd.CmdEvent; import com.java110.core.factory.GenerateCodeFactory; import com.java110.core.factory.Java110TransactionalFactory; import com.java110.core.log.LoggerFactory; import com.java110.core.smo.IComputeFeeSMO; import com.java110.dto.account.AccountDto; import com.java110.dto.app.AppDto; import com.java110.dto.fee.FeeAttrDto; import com.java110.dto.fee.FeeConfigDto; import com.java110.dto.fee.FeeDetailDto; import com.java110.dto.fee.FeeDto; import com.java110.dto.fee.FeeReceiptDetailDto; import com.java110.dto.owner.OwnerCarDto; import com.java110.dto.owner.OwnerDto; import com.java110.dto.parking.ParkingSpaceDto; import com.java110.dto.repair.RepairDto; import com.java110.dto.repair.RepairUserDto; import com.java110.dto.user.UserDto; import com.java110.fee.bmo.fee.IFinishFeeNotify; import com.java110.fee.smo.impl.FeeReceiptInnerServiceSMOImpl; import com.java110.intf.acct.IAccountInnerServiceSMO; import com.java110.intf.community.*; import com.java110.intf.fee.*; import com.java110.intf.user.IOwnerCarInnerServiceSMO; import com.java110.intf.user.IUserV1InnerServiceSMO; import com.java110.po.account.AccountDetailPo; import com.java110.po.car.OwnerCarPo; import com.java110.po.fee.PayFeeDetailPo; import com.java110.po.fee.PayFeePo; import com.java110.po.fee.FeeReceiptPo; import com.java110.po.fee.FeeReceiptDetailPo; import com.java110.po.owner.RepairPoolPo; import com.java110.po.owner.RepairUserPo; import com.java110.utils.cache.CommonCache; import com.java110.utils.constant.ResponseConstant; import com.java110.utils.exception.CmdException; import com.java110.utils.exception.ListenerExecuteException; import com.java110.utils.util.Assert; import com.java110.utils.util.BeanConvertUtil; import com.java110.utils.util.DateUtil; import com.java110.utils.util.StringUtil; import com.java110.vo.ResultVo; import org.slf4j.Logger; import org.springframework.beans.factory.annotation.Autowired; import java.math.BigDecimal; import java.text.ParseException; import java.util.*; @Java110Cmd(serviceCode = "fee.payOweFee") public class PayOweFeeCmd extends Cmd { private static Logger logger = LoggerFactory.getLogger(PayOweFeeCmd.class); @Autowired private IParkingSpaceInnerServiceSMO parkingSpaceInnerServiceSMOImpl; @Autowired private IFeeInnerServiceSMO feeInnerServiceSMOImpl; @Autowired private IFeeAttrInnerServiceSMO feeAttrInnerServiceSMOImpl; @Autowired private IRoomInnerServiceSMO roomInnerServiceSMOImpl; @Autowired private IFeeConfigInnerServiceSMO feeConfigInnerServiceSMOImpl; @Autowired private IFeeReceiptInnerServiceSMO feeReceiptInnerServiceSMOImpl; @Autowired private IFeeReceiptDetailInnerServiceSMO feeReceiptDetailInnerServiceSMOImpl; @Autowired private IPayFeeV1InnerServiceSMO payFeeV1InnerServiceSMOImpl; @Autowired private IPayFeeDetailV1InnerServiceSMO payFeeDetailV1InnerServiceSMOImpl; @Autowired private IComputeFeeSMO computeFeeSMOImpl; @Autowired private IUserV1InnerServiceSMO userV1InnerServiceSMOImpl; @Autowired private IFinishFeeNotify finishFeeNotifyImpl; @Autowired private IAccountInnerServiceSMO accountInnerServiceSMOImpl; @Override public void validate(CmdEvent event, ICmdDataFlowContext context, JSONObject reqJson) throws CmdException { Assert.hasKey(reqJson, "fees", "请求报文中未包含费用信息"); JSONArray fees = reqJson.getJSONArray("fees"); JSONObject feeObject = null; for (int feeIndex = 0; feeIndex < fees.size(); feeIndex++) { feeObject = fees.getJSONObject(feeIndex); Assert.hasKeyAndValue(feeObject, "feeId", "未包含费用信息"); Assert.hasKeyAndValue(feeObject, "startTime", "未包含开始时间"); Assert.hasKeyAndValue(feeObject, "endTime", "未包含结束时间"); Assert.hasKeyAndValue(feeObject, "receivedAmount", "未包含实收金额"); //计算 应收金额 FeeDto feeDto = new FeeDto(); feeDto.setFeeId(feeObject.getString("feeId")); feeDto.setCommunityId(feeObject.getString("communityId")); Date pageEndTime = null; List feeDtos = feeInnerServiceSMOImpl.queryFees(feeDto); if (feeDtos == null || feeDtos.size() != 1) { throw new ListenerExecuteException(ResponseConstant.RESULT_CODE_ERROR, "查询费用信息失败,未查到数据或查到多条数据"); } feeDto = feeDtos.get(0); feeObject.put("feeDto", feeDto); if (!FeeDto.FEE_FLAG_CYCLE.equals(feeDto.getFeeFlag())) { continue; } pageEndTime = DateUtil.getDateFromStringB(feeObject.getString("endTime")); if (pageEndTime.getTime() <= feeDto.getEndTime().getTime()) { throw new IllegalArgumentException("可能存在重复缴费,请刷新页面重新缴费"); } } //todo 从账户中扣款 ifHasAccount(reqJson, fees); } @Override @Java110Transactional public void doCmd(CmdEvent event, ICmdDataFlowContext dataFlowContext, JSONObject paramObj) throws CmdException, ParseException { logger.info("======欠费缴费返回======:" + JSONArray.toJSONString(paramObj)); String userId = CmdContextUtils.getUserId(dataFlowContext); UserDto userDto = new UserDto(); userDto.setUserId(userId); List userDtos = userV1InnerServiceSMOImpl.queryUsers(userDto); Assert.listOnlyOne(userDtos, "用户未登录"); String payOrderId = paramObj.getString("payOrderId"); JSONArray fees = paramObj.getJSONArray("fees"); JSONObject feeObj = null; String appId = dataFlowContext.getReqHeaders().get("app-id"); //todo 生成收据编号 String receiptCode = feeReceiptInnerServiceSMOImpl.generatorReceiptCode(paramObj.getString("communityId")); //todo 根据明细ID 查询收据信息 JSONArray details = new JSONArray(); for (int feeIndex = 0; feeIndex < fees.size(); feeIndex++) { feeObj = fees.getJSONObject(feeIndex); feeObj.put("communityId", paramObj.getString("communityId")); if (paramObj.containsKey("oId")) { feeObj.put("oId", paramObj.getString("oId")); } String remark = paramObj.getString("remark"); feeObj.put("remark", remark); if (!feeObj.containsKey("primeRate") && AppDto.OWNER_WECHAT_PAY.equals(appId)) { //微信公众号支付 feeObj.put("primeRate", "5"); feeObj.put("remark", "线上公众号支付"); } if (!feeObj.containsKey("primeRate")) { feeObj.put("primeRate", "6"); } logger.info("======支付方式======:" + appId + "+======+" + feeObj.containsKey("primeRate") + "======:" + JSONArray.toJSONString(dataFlowContext)); if (AppDto.OWNER_WECHAT_PAY.equals(appId) && FeeDetailDto.PRIME_REATE_WECHAT.equals(feeObj.getString("primeRate"))) { //微信支付(欠费缴费无法区分小程序还是微信公众号) feeObj.put("remark", "线上公众号支付"); } else if (AppDto.OWNER_WECHAT_PAY.equals(appId) && FeeDetailDto.PRIME_REATE_WECHAT_APP.equals(feeObj.getString("primeRate"))) { feeObj.put("remark", "线上小程序支付"); } feeObj.put("state", "1400"); // todo 添加交费明细 addOweFeeDetail(feeObj, details, userDto, receiptCode, payOrderId); modifyOweFee(feeObj, dataFlowContext); //todo 账户扣款 finishFeeNotifyImpl.withholdAccount(feeObj, feeObj.getString("feeId"), feeObj.getString("communityId")); //todo 修改车辆 finishFeeNotifyImpl.updateCarEndTime(feeObj.getString("feeId"), feeObj.getString("communityId")); //todo 修改报修单 finishFeeNotifyImpl.updateRepair(feeObj.getString("feeId"), feeObj.getString("communityId"), feeObj.getString("receivedAmount")); } JSONObject data = new JSONObject(); data.put("details", details); dataFlowContext.setResponseEntity(ResultVo.createResponseEntity(data)); } /** * 修改费用信息 * * @param paramInJson 接口调用放传入入参 * @param dataFlowContext 数据上下文 * @return 订单服务能够接受的报文 */ public void modifyOweFee(JSONObject paramInJson, ICmdDataFlowContext dataFlowContext) { JSONObject businessFee = new JSONObject(); FeeDto feeInfo = (FeeDto) paramInJson.get("feeInfo"); Map feeMap = BeanConvertUtil.beanCovertMap(feeInfo); feeMap.put("startTime", DateUtil.getFormatTimeString(feeInfo.getStartTime(), DateUtil.DATE_FORMATE_STRING_A)); feeMap.put("endTime", DateUtil.getNextSecTime(paramInJson.getString("endTime"))); feeMap.put("cycles", paramInJson.getString("cycles")); feeMap.put("configEndTime", feeInfo.getConfigEndTime()); if (FeeDto.FEE_FLAG_ONCE.equals(feeInfo.getFeeFlag())) { //缴费结束 feeMap.put("state", FeeDto.STATE_FINISH); } Date maxEndTime = feeInfo.getMaxEndTime(); if (maxEndTime == null) { maxEndTime = feeInfo.getConfigEndTime(); } if (maxEndTime != null) { //这里数据问题的情况下 Date endTime = DateUtil.getDateFromStringA(paramInJson.getString("endTime")); if (endTime.getTime() >= maxEndTime.getTime()) { feeMap.put("state", FeeDto.STATE_FINISH); } } businessFee.putAll(feeMap); PayFeePo payFeePo = BeanConvertUtil.covertBean(businessFee, PayFeePo.class); int flag = payFeeV1InnerServiceSMOImpl.updatePayFee(payFeePo); if (flag < 1) { throw new CmdException("修改失败"); } } public void addOweFeeDetail(JSONObject paramInJson, JSONArray detailIds, UserDto userDto, String receiptCode, String payOrderId) { JSONObject businessFeeDetail = new JSONObject(); businessFeeDetail.putAll(paramInJson); businessFeeDetail.put("detailId", GenerateCodeFactory.getGeneratorId(GenerateCodeFactory.CODE_PREFIX_detailId)); businessFeeDetail.put("primeRate", paramInJson.getString("primeRate")); FeeDto feeDto = (FeeDto) paramInJson.get("feeDto"); businessFeeDetail.put("startTime", paramInJson.getString("startTime")); BigDecimal cycles = null; Map feePriceAll = computeFeeSMOImpl.getFeePrice(feeDto); BigDecimal feePrice = new BigDecimal(feePriceAll.get("feePrice").toString()); Date endTime = feeDto.getEndTime(); Calendar endCalender = Calendar.getInstance(); endCalender.setTime(endTime); BigDecimal receivedAmount = new BigDecimal(Double.parseDouble(paramInJson.getString("receivedAmount"))); cycles = receivedAmount.divide(feePrice, 4, BigDecimal.ROUND_HALF_EVEN); businessFeeDetail.put("cycles", receivedAmount.divide(feePrice, 2, BigDecimal.ROUND_HALF_UP).doubleValue()); if (!paramInJson.containsKey("receivableAmount") || StringUtil.isEmpty(paramInJson.getString("receivableAmount"))) { paramInJson.put("receivableAmount", paramInJson.getString("receivedAmount")); } businessFeeDetail.put("receivableAmount", paramInJson.getString("receivableAmount")); businessFeeDetail.put("receivedAmount", paramInJson.getString("receivedAmount")); businessFeeDetail.put("payableAmount", paramInJson.getString("receivedAmount")); businessFeeDetail.put("endTime", paramInJson.getString("endTime")); paramInJson.put("feeInfo", feeDto); paramInJson.put("cycles", cycles.doubleValue()); PayFeeDetailPo payFeeDetailPo = BeanConvertUtil.covertBean(businessFeeDetail, PayFeeDetailPo.class); if (paramInJson.containsKey("oId")) { payFeeDetailPo.setPayOrderId(paramInJson.getString("oId")); } else { String oId = Java110TransactionalFactory.getOId(); if (StringUtil.isEmpty(oId)) { oId = payFeeDetailPo.getDetailId(); } payFeeDetailPo.setPayOrderId(oId); } // todo 如果 扫码枪支付 输入支付订单ID if (!StringUtil.isEmpty(payOrderId)) { payFeeDetailPo.setPayOrderId(payOrderId); } if (paramInJson.containsKey("accountAmount")) { payFeeDetailPo.setAcctAmount(paramInJson.getString("accountAmount")); } payFeeDetailPo.setCashierId(userDto.getUserId()); payFeeDetailPo.setCashierName(userDto.getName()); payFeeDetailPo.setOpenInvoice("N"); //todo 缓存收据编号 CommonCache.setValue(payFeeDetailPo.getDetailId() + CommonCache.RECEIPT_CODE, receiptCode, CommonCache.DEFAULT_EXPIRETIME_TWO_MIN); int flag = payFeeDetailV1InnerServiceSMOImpl.savePayFeeDetailNew(payFeeDetailPo); if (flag < 1) { throw new CmdException("保存明细失败"); } paramInJson.put("detailId", businessFeeDetail.getString("detailId")); detailIds.add(businessFeeDetail.getString("detailId")); } private void ifHasAccount(JSONObject reqJson, JSONArray fees) { if (!reqJson.containsKey("accountAmount")) { return; } double accountAmount = reqJson.getDouble("accountAmount"); if (accountAmount <= 0) { return; } Assert.hasKeyAndValue(reqJson, "acctId", "未包含账户ID"); String acctId = reqJson.getString("acctId"); //todo 校验账户金额是否充足 AccountDto accountDto = new AccountDto(); accountDto.setAcctId(acctId); List accountDtos = accountInnerServiceSMOImpl.queryAccounts(accountDto); Assert.listOnlyOne(accountDtos, "账户不存在"); if (Double.parseDouble(accountDtos.get(0).getAmount()) < accountAmount) { throw new CmdException("账户余额不足"); } BigDecimal accountAmountDec = null; // todo 从费用实际缴费中扣款 JSONObject feeObject = null; double receivedAmount = 0.0; BigDecimal receivedAmountDec = null; for (int feeIndex = 0; feeIndex < fees.size(); feeIndex++) { if (accountAmount == 0) { continue; } accountAmountDec = new BigDecimal(accountAmount); feeObject = fees.getJSONObject(feeIndex); receivedAmount = feeObject.getDouble("receivedAmount"); receivedAmountDec = new BigDecimal(receivedAmount); if (receivedAmount >= accountAmount) { receivedAmountDec = receivedAmountDec.subtract(accountAmountDec).setScale(2, BigDecimal.ROUND_HALF_UP); feeObject.put("receivedAmount", receivedAmountDec.doubleValue()); feeObject.put("accountAmount", accountAmount); feeObject.put("acctId", acctId); accountAmount = 0.00; continue; } feeObject.put("receivedAmount", "0"); feeObject.put("accountAmount", receivedAmount); feeObject.put("acctId", acctId); accountAmountDec = accountAmountDec.subtract(receivedAmountDec).setScale(2, BigDecimal.ROUND_HALF_UP); accountAmount = accountAmountDec.doubleValue(); } } }