企业商户交易流水记录功能v1

wxpay
LI-CCONG\李聪聪 7 months ago
parent 2853583521
commit 25a68e6347

@ -1,12 +1,15 @@
package cc.yunxi.domain.po; package cc.yunxi.domain.po;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName; import com.baomidou.mybatisplus.annotation.TableName;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.Date; import java.util.Date;
import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty; import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.Getter; import lombok.Getter;
import lombok.Setter; import lombok.Setter;
@ -18,77 +21,53 @@ import lombok.Setter;
* @author ccongli * @author ccongli
* @since 2024-03-10 09:04:53 * @since 2024-03-10 09:04:53
*/ */
@Getter @Data
@Setter @TableName("base_organize")
@TableName("nx_enterprise")
@ApiModel(value = "Enterprise对象", description = "企业(商户)信息") @ApiModel(value = "Enterprise对象", description = "企业(商户)信息")
public class Enterprise { public class Enterprise {
@ApiModelProperty("自然主键") @ApiModelProperty("自然主键")
@TableId("id") @TableId(value = "f_id", type = IdType.ASSIGN_ID)
private String id; private String id;
@ApiModelProperty("商户代码") @ApiModelProperty("商户代码")
@TableField("enterprise_code") @TableField("f_en_code")
private String enterpriseCode; private String enterpriseCode;
@ApiModelProperty("商户名称") @ApiModelProperty("商户名称")
@TableField("enterprise_name") @TableField("f_full_name")
private String enterpriseName; private String enterpriseName;
@ApiModelProperty("商户简称") @ApiModelProperty("描述")
@TableField("enterprise_short_name") @TableField("f_description")
private String enterpriseShortName; private String description;
@ApiModelProperty("有效标志(0-禁用1-启用)")
@TableField("f_enabled_mark")
private Integer status;
@ApiModelProperty("商户余额")
@TableField("fund")
private BigDecimal fund;
@ApiModelProperty("商户logo") @ApiModelProperty("商户logo")
@TableField("enterprise_logo") @TableField("pictures")
private String enterpriseLogo; private String enterpriseLogo;
@ApiModelProperty("主体类型id国有企业私有企业集体") // @ApiModelProperty("注册人手持身份证照片")
@TableField("principal_type_id") // @TableField("registrant_pictures")
private String principalTypeId; // private String registrantPictures;
//
@ApiModelProperty("商户状态") // @ApiModelProperty("社会信用代码证照片")
@TableField("enterprise_status") // @TableField("society_pictures")
private Integer enterpriseStatus; // private String societyPictures;
@ApiModelProperty("合约状态")
@TableField("contract_status")
private Integer contractStatus;
@ApiModelProperty("所在城市")
@TableField("city")
private String city;
@ApiModelProperty("传真")
@TableField("fax")
private String fax;
@ApiModelProperty("联系电话")
@TableField("tele_phone")
private String telePhone;
@ApiModelProperty("详细地址")
@TableField("address")
private String address;
@ApiModelProperty("发票抬头")
@TableField("invoice_header")
private String invoiceHeader;
@ApiModelProperty("商户税号")
@TableField("tax_id")
private String taxId;
@ApiModelProperty("描述或说明")
@TableField("description")
private String description;
// @ApiModelProperty("拓展属性")
// @TableField("f_property_json")
// private String propertyJson;
@ApiModelProperty("创建时间") @ApiModelProperty("创建时间")
@TableField("f_creator_time") @TableField("f_creator_time")
private Date fCreatorTime; private LocalDateTime creatorTime;
@ApiModelProperty("修改时间") @ApiModelProperty("修改时间")
@TableField("f_last_modify_time") @TableField("f_last_modify_time")

@ -0,0 +1,75 @@
package cc.yunxi.domain.po;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.Date;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Getter;
import lombok.Setter;
/**
* <p>
*
* </p>
*
* @author ccongli
* @since 2024-03-14 06:39:30
*/
@Getter
@Setter
@TableName("nx_enterprise_account_bill")
@ApiModel(value = "EnterpriseAccountBill", description = "企业钱包流水")
public class EnterpriseAccountBill {
@ApiModelProperty("主键id")
@TableId(value = "id", type = IdType.ASSIGN_ID)
private String id;
@ApiModelProperty("企业id")
@TableField("enterprise_id")
private String enterpriseId;
@ApiModelProperty("流水编号")
@TableField("bill_number")
private String billNumber;
@ApiModelProperty("订单编号")
@TableField("order_number")
private String orderNumber;
// @ApiModelProperty("订单类型id")
// @TableField("order_type_id")
// private String orderTypeId;
// @ApiModelProperty("单据状态id")
// @TableField("bill_status_id")
// private String billStatusId;
// @ApiModelProperty("收入(元)")
// @TableField("income_amount")
// private BigDecimal incomeAmount;
@ApiModelProperty("交易额")
@TableField("payout_amount")
private BigDecimal payoutAmount;
@ApiModelProperty("账户余额(元)")
@TableField("account_balance")
private BigDecimal accountBalance;
@ApiModelProperty("创建时间")
@TableField("creator_time")
private LocalDateTime creatorTime;
@ApiModelProperty("备注")
@TableField("remark")
private String remark;
}

@ -122,9 +122,9 @@ public class RecycleStation {
@TableField("accept_range") @TableField("accept_range")
private Integer acceptRange; private Integer acceptRange;
@ApiModelProperty("服务范围内小区") // @ApiModelProperty("服务范围内小区")
@TableField("accept_housing_estate") // @TableField("accept_housing_estate")
private String acceptHousingEstate; // private String acceptHousingEstate;
@ApiModelProperty("创建时间") @ApiModelProperty("创建时间")
@TableField("creator_time") @TableField("creator_time")

@ -33,9 +33,9 @@ public class ClientAddressReqVO {
@NotBlank(message = "联系人手机号不能为空", groups = AddAddressGroup.class) @NotBlank(message = "联系人手机号不能为空", groups = AddAddressGroup.class)
private String receiveMobilePhone; private String receiveMobilePhone;
@ApiModelProperty(value = "城市",required = true) // @ApiModelProperty(value = "城市",required = true)
@NotBlank(message = "城市不能为空", groups = AddAddressGroup.class) // @NotBlank(message = "城市不能为空", groups = AddAddressGroup.class)
private String receiveCity; // private String receiveCity;
@ApiModelProperty(value = "地址",required = true) @ApiModelProperty(value = "地址",required = true)
@NotBlank(message = "地址不能为空", groups = AddAddressGroup.class) @NotBlank(message = "地址不能为空", groups = AddAddressGroup.class)

@ -12,7 +12,9 @@ import lombok.Getter;
@AllArgsConstructor @AllArgsConstructor
public enum BusinessCodeEnum implements BaseEnum { public enum BusinessCodeEnum implements BaseEnum {
ORDER("RO", "订单业务码"); ORDER("RO", "订单业务码"),
BILL("BL", "商户流水业务码");
private final String code; private final String code;

@ -0,0 +1,18 @@
package cc.yunxi.mapper;
import cc.yunxi.domain.po.EnterpriseAccountBill;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Mapper;
/**
* <p>
* Mapper
* </p>
*
* @author ccongli
* @since 2024-03-14 06:39:30
*/
@Mapper
public interface EnterpriseAccountBillMapper extends BaseMapper<EnterpriseAccountBill> {
}

@ -3,6 +3,7 @@ package cc.yunxi.mapper;
import cc.yunxi.domain.po.Enterprise; import cc.yunxi.domain.po.Enterprise;
import com.baomidou.mybatisplus.core.mapper.BaseMapper; import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
/** /**
* <p> * <p>
@ -15,4 +16,11 @@ import org.apache.ibatis.annotations.Mapper;
@Mapper @Mapper
public interface EnterpriseMapper extends BaseMapper<Enterprise> { public interface EnterpriseMapper extends BaseMapper<Enterprise> {
// /**
// * 站点id获取商户信息
// * @param stationId
// * @return Enterprise
// */
// Enterprise getEnterpriseByStationId(@Param("stationId") String stationId);
} }

@ -47,6 +47,13 @@ public interface IClientService extends IService<Client> {
*/ */
Client getClientByOpenid(String openid); Client getClientByOpenid(String openid);
/**
* keyId
* @param keyId
* @return Client
*/
Client getClientByKeyId(String keyId);
/** /**
* *
* @param phoneNumber * @param phoneNumber

@ -13,4 +13,17 @@ import com.baomidou.mybatisplus.extension.service.IService;
*/ */
public interface IEnterpriseService extends IService<Enterprise> { public interface IEnterpriseService extends IService<Enterprise> {
/**
* id
* @param stationId
* @return Enterprise
*/
Enterprise getEnterpriseByStationId(String stationId);
/**
* id
* @param enterpriseId
* @return Enterprise
*/
Enterprise getEnterpriseById(String enterpriseId);
} }

@ -4,21 +4,22 @@ import cc.yunxi.common.domain.LambdaQueryWrapperX;
import cc.yunxi.common.exception.BizIllegalException; import cc.yunxi.common.exception.BizIllegalException;
import cc.yunxi.common.exception.DbException; import cc.yunxi.common.exception.DbException;
import cc.yunxi.common.utils.BeanUtils; import cc.yunxi.common.utils.BeanUtils;
import cc.yunxi.common.utils.CommonUtil;
import cc.yunxi.config.props.WxPayV3Properties; import cc.yunxi.config.props.WxPayV3Properties;
import cc.yunxi.domain.dto.UserDTO; import cc.yunxi.domain.dto.UserDTO;
import cc.yunxi.domain.po.Client; import cc.yunxi.domain.po.*;
import cc.yunxi.domain.po.ClientAccountDetail;
import cc.yunxi.domain.po.RecycleOrder;
import cc.yunxi.domain.po.Recycler;
import cc.yunxi.domain.query.ClientAccountQuery; import cc.yunxi.domain.query.ClientAccountQuery;
import cc.yunxi.domain.query.ClientQuery; import cc.yunxi.domain.query.ClientQuery;
import cc.yunxi.domain.query.RecyclerQuery; import cc.yunxi.domain.query.RecyclerQuery;
import cc.yunxi.domain.vo.client.ClientUpdateVO; import cc.yunxi.domain.vo.client.ClientUpdateVO;
import cc.yunxi.enums.BalanceChangeTypeEnum; import cc.yunxi.enums.BalanceChangeTypeEnum;
import cc.yunxi.enums.BusinessCodeEnum;
import cc.yunxi.mapper.ClientAccountDetailMapper; import cc.yunxi.mapper.ClientAccountDetailMapper;
import cc.yunxi.mapper.ClientMapper; import cc.yunxi.mapper.ClientMapper;
import cc.yunxi.mapper.EnterpriseAccountBillMapper;
import cc.yunxi.mapper.RecyclerMapper; import cc.yunxi.mapper.RecyclerMapper;
import cc.yunxi.service.IClientService; import cc.yunxi.service.IClientService;
import cc.yunxi.service.IEnterpriseService;
import cc.yunxi.utils.UserContext; import cc.yunxi.utils.UserContext;
import cn.hutool.core.date.DatePattern; import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateUtil; import cn.hutool.core.date.DateUtil;
@ -66,6 +67,12 @@ public class ClientServiceImpl extends ServiceImpl<ClientMapper, Client> impleme
@Autowired @Autowired
private ClientAccountDetailMapper accountDetailMapper; private ClientAccountDetailMapper accountDetailMapper;
@Autowired
private EnterpriseAccountBillMapper accountBillMapper;
@Resource
private IEnterpriseService enterpriseService;
@Resource @Resource
private WxPayV3Properties wxPayV3Properties; private WxPayV3Properties wxPayV3Properties;
@ -98,6 +105,18 @@ public class ClientServiceImpl extends ServiceImpl<ClientMapper, Client> impleme
return lambdaQuery().eq(Client::getWxOpenid, openid).one(); return lambdaQuery().eq(Client::getWxOpenid, openid).one();
} }
@Override
public Client getClientByKeyId(String keyId) {
LambdaQueryWrapper<Client> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(Client::getId, keyId).or().eq(Client::getWxOpenid, keyId);
wrapper.last("for update");
Client client = this.getOne(wrapper);
if (client == null) {
throw new BizIllegalException("散户不存在");
}
return client;
}
@Override @Override
@Transactional @Transactional
@ -137,8 +156,8 @@ public class ClientServiceImpl extends ServiceImpl<ClientMapper, Client> impleme
@Override @Override
public void addBalance(String clientId, BigDecimal amount, String orderNo) { public void addBalance(String clientId, BigDecimal amount, String orderNo, String stationId) {
this.changeBalance(clientId, amount, orderNo, BalanceChangeTypeEnum.INCOME); this.changeBalance(clientId, amount, orderNo, stationId, BalanceChangeTypeEnum.INCOME);
} }
@ -146,7 +165,7 @@ public class ClientServiceImpl extends ServiceImpl<ClientMapper, Client> impleme
@Transactional(rollbackFor = Exception.class) @Transactional(rollbackFor = Exception.class)
public void cashBalance(String openId, Integer amount) throws Exception { public void cashBalance(String openId, Integer amount) throws Exception {
// 模拟提现成功 // 模拟提现成功
this.changeBalance(openId, new BigDecimal(amount), null, BalanceChangeTypeEnum.CASH_OUT); this.changeBalance(openId, new BigDecimal(amount), null, null, BalanceChangeTypeEnum.CASH_OUT);
/* BatchTransferModel batchTransferModel = new BatchTransferModel() /* BatchTransferModel batchTransferModel = new BatchTransferModel()
.setAppid(wxPayV3Properties.getAppId()) .setAppid(wxPayV3Properties.getAppId())
.setOut_batch_no(PayKit.generateStr()) .setOut_batch_no(PayKit.generateStr())
@ -222,30 +241,49 @@ public class ClientServiceImpl extends ServiceImpl<ClientMapper, Client> impleme
// 统一金额交易 // 统一金额交易
private void changeBalance(String keyId, BigDecimal amount, String orderNo, BalanceChangeTypeEnum changeTypeEnum) { private void changeBalance(String keyId, BigDecimal amount, String orderNo,
LambdaQueryWrapper<Client> wrapper = new LambdaQueryWrapper<>(); String stationId, BalanceChangeTypeEnum changeTypeEnum) {
wrapper.eq(Client::getId, keyId).or().eq(Client::getWxOpenid, keyId); Client client = this.getClientByKeyId(keyId);
wrapper.last("for update");
Client client = this.getOne(wrapper);
BigDecimal balance = client.getBanlance(); BigDecimal balance = client.getBanlance();
String remark; String remark;
LocalDateTime now = LocalDateTime.now(); LocalDateTime now = LocalDateTime.now();
if (changeTypeEnum.equals(BalanceChangeTypeEnum.INCOME)) { // 收入 if (changeTypeEnum.equals(BalanceChangeTypeEnum.INCOME)) { // 收入
balance = balance.add(amount); balance = balance.add(amount);
remark = "废品回收结算,收入" + amount + "元"; remark = "废品回收结算,收入" + amount + "元";
} else { // 支出/提现 } else { // 微信提现
if (balance.compareTo(amount) < 0) { if (balance.compareTo(amount) < 0) {
throw new BizIllegalException("余额不足"); throw new BizIllegalException("余额不足");
} }
balance = balance.subtract(amount); balance = balance.subtract(amount);
remark = "微信提现" + amount + "元"; remark = "微信提现" + amount + "元";
// 更新商户资金
Enterprise enterprise = enterpriseService.getEnterpriseByStationId(stationId);
BigDecimal fund = enterprise.getFund();
if (fund.compareTo(amount) < 0) {
throw new BizIllegalException("商户资金不足,请联系商户");
}
fund = fund.subtract(amount);
enterprise.setFund(fund);
enterpriseService.updateById(enterprise);
// 记录商户流水
EnterpriseAccountBill accountBill = new EnterpriseAccountBill();
accountBill.setEnterpriseId(enterprise.getId());
accountBill.setBillNumber(CommonUtil.getIdNumber(BusinessCodeEnum.BILL.getCode()));
accountBill.setAccountBalance(fund);
accountBill.setPayoutAmount(amount);
accountBill.setOrderNumber(orderNo);
accountBill.setRemark("支付给散户"+ amount + "元");
accountBill.setCreatorTime(now);
accountBillMapper.insert(accountBill);
} }
// 更新余额 // 更新散户余额
client.setBanlance(balance); client.setBanlance(balance);
client.setUpdateTime(now); client.setUpdateTime(now);
this.updateById(client); this.updateById(client);
// 添加流水记录 // 添加散户余额明细记录
ClientAccountDetail accountDetail = new ClientAccountDetail(); ClientAccountDetail accountDetail = new ClientAccountDetail();
accountDetail.setClientId(client.getId()); accountDetail.setClientId(client.getId());
accountDetail.setAmount(amount); accountDetail.setAmount(amount);

@ -1,11 +1,20 @@
package cc.yunxi.service.impl; package cc.yunxi.service.impl;
import cc.yunxi.common.exception.BizIllegalException;
import cc.yunxi.domain.po.Enterprise; import cc.yunxi.domain.po.Enterprise;
import cc.yunxi.domain.po.RecycleStation;
import cc.yunxi.enums.GlobalStatusEnum;
import cc.yunxi.mapper.EnterpriseMapper; import cc.yunxi.mapper.EnterpriseMapper;
import cc.yunxi.service.IEnterpriseService; import cc.yunxi.service.IEnterpriseService;
import cc.yunxi.service.IRecycleStationService;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import javax.annotation.Resource;
/** /**
* <p> * <p>
* () * ()
@ -17,4 +26,32 @@ import org.springframework.stereotype.Service;
@Service @Service
public class EnterpriseServiceImpl extends ServiceImpl<EnterpriseMapper, Enterprise> implements IEnterpriseService { public class EnterpriseServiceImpl extends ServiceImpl<EnterpriseMapper, Enterprise> implements IEnterpriseService {
@Resource
private IRecycleStationService recycleStationService;
public Enterprise getEnterpriseByStationId(String stationId) {
RecycleStation station = recycleStationService.getStationById(stationId);
String enterpriseId = station.getEnterpriseId();
if (StrUtil.isEmpty(enterpriseId)) {
throw new BizIllegalException("回收站点未绑定商户");
}
return this.getEnterpriseById(enterpriseId);
}
@Override
public Enterprise getEnterpriseById(String enterpriseId) {
if (StrUtil.isEmpty(enterpriseId)) {
throw new BizIllegalException("参数缺失");
}
LambdaQueryWrapper<Enterprise> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(Enterprise::getId, enterpriseId);
wrapper.eq(Enterprise::getStatus, GlobalStatusEnum.VALID.getCode());
wrapper.last("for update");
Enterprise enterprise = getOne(wrapper);
if (ObjectUtil.isEmpty(enterprise)) {
throw new BizIllegalException("商户不存在或已被禁用");
}
return enterprise;
}
} }

@ -235,8 +235,11 @@ public class RecycleOrderServiceImpl extends ServiceImpl<RecycleOrderMapper, Rec
List<RecycleOrderProduct> recycleOrderProducts = BeanUtils.copyList(recycleOrderProductVOList, RecycleOrderProduct.class); List<RecycleOrderProduct> recycleOrderProducts = BeanUtils.copyList(recycleOrderProductVOList, RecycleOrderProduct.class);
this.recycleOrderProductService.updateOrderProducts(recycleOrderProducts); this.recycleOrderProductService.updateOrderProducts(recycleOrderProducts);
// 记录关键信息
String clientId = recycleOrder.getClientId(); String clientId = recycleOrder.getClientId();
String orderNumber = recycleOrder.getOrderNumber(); String orderNumber = recycleOrder.getOrderNumber();
String recycleStationId = recycleOrder.getRecycleStationId();
recycleOrder = BeanUtils.copyBean(orderFinishVO, RecycleOrder.class); recycleOrder = BeanUtils.copyBean(orderFinishVO, RecycleOrder.class);
recycleOrder.setOrderStatus(OrderStatusEnum.FINISHED); recycleOrder.setOrderStatus(OrderStatusEnum.FINISHED);
recycleOrder.setCompleteTime(LocalDateTime.now()); recycleOrder.setCompleteTime(LocalDateTime.now());
@ -254,7 +257,7 @@ public class RecycleOrderServiceImpl extends ServiceImpl<RecycleOrderMapper, Rec
this.updateById(recycleOrder); this.updateById(recycleOrder);
// 增加收入余额 异步? todo // 增加收入余额 异步? todo
clientService.addBalance(clientId, totalAmount, orderNumber); clientService.addBalance(clientId, totalAmount, orderNumber, recycleStationId);
} }

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="cc.yunxi.mapper.EnterpriseAccountBillMapper">
</mapper>
Loading…
Cancel
Save