Commit c049f4c2 authored by wlx@33.cn's avatar wlx@33.cn

兼容使用权,退款,转赠,退货修正

parent 5d85b2b6
......@@ -9,16 +9,12 @@ import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.fzm.mall.server.admin.block_chain.util.ChainUtil;
import com.fzm.mall.server.admin.config.Redis;
import com.fzm.mall.server.admin.constant.MALLGlobalConfig;
import com.fzm.mall.server.admin.constant.MallResponseError;
import com.fzm.mall.server.admin.distribution.mapper.ParcelCenterMapper;
import com.fzm.mall.server.admin.distribution.service.IExpressService;
import com.fzm.mall.server.admin.exception.MyException;
import com.fzm.mall.server.admin.goods_center.entity.vo.GoodsSpuVO;
import com.fzm.mall.server.admin.goods_center.mapper.GoodsSkuUsufructMapper;
import com.fzm.mall.server.admin.goods_center.mapper.SpuMapper;
import com.fzm.mall.server.admin.goods_center.model.GoodsSkuUsufruct;
import com.fzm.mall.server.admin.goods_center.model.Spu;
import com.fzm.mall.server.admin.home_page.model.Merchant;
import com.fzm.mall.server.admin.home_page.service.IMerchantService;
import com.fzm.mall.server.admin.mq.MsgProducer;
......@@ -29,7 +25,6 @@ import com.fzm.mall.server.admin.order.mapper.DeliveryMapper;
import com.fzm.mall.server.admin.order.model.Config;
import com.fzm.mall.server.admin.order.model.Delivery;
import com.fzm.mall.server.admin.order.model.DeliveryLog;
import com.fzm.mall.server.admin.order.model.OrderDetail;
import com.fzm.mall.server.admin.order.service.IDeliveryLogService;
import com.fzm.mall.server.admin.order.service.IDeliveryRefundService;
import com.fzm.mall.server.admin.order.service.IDeliveryService;
......@@ -43,12 +38,9 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import java.math.BigDecimal;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
......@@ -218,88 +210,12 @@ public class DeliveryServiceImpl extends ServiceImpl<DeliveryMapper, Delivery> i
throw new MyException(MallResponseError.UPDATE_FAIL);
}
refundCoinOnChain(delivery);
}
/**
* 调用链上方法将币还给用户 , 成功后,将order_delivery_refund的state改为5退款成功
*
* @param delivery
*/
private void refundCoinOnChain(Delivery delivery) {
//判断商品是否为NFT
GoodsSpuVO goodsSpu = spuMapper.readByCoin(delivery.getCoin());
boolean isSalesNFTCopy = goodsSpu.getNftSalesType().equals(Spu.NFT_SALES_TYPE_COPY);
/**
* NFT商品为“使用权销售时”,根据订单购买的编号重置为未使用
* 1.调用链上方法将币还给用户 , 成功后,将order_delivery_refund的state改为5退款成功
* 2.nft不支持提货
*/
updateSkuSerialNo(null, delivery.getCoin(), isSalesNFTCopy);
//根据开关判断是否走链,默认不走链
if (payInChain) {
User user = userService.getOne(new QueryWrapper<User>().eq("uid", delivery.getUid()));
Merchant merchant = merchantService.getOne(new QueryWrapper<Merchant>().eq("merchant_id", delivery.getMerchantId()));
TranDto tranDto = new TranDto();
tranDto.setFromAddr(merchant.getTokenIssueAddr());
tranDto.setToAddr(user.getAddress());
tranDto.setCoin(delivery.getCoin());
//一个商品对应一个币,此处构造不存在精度丢失问题
tranDto.setAmount(new BigDecimal(delivery.getNumber()));
tranDto.setTableId(delivery.getOrderDeliveryId());
tranDto.setTableType(TranDto.TABLE_TYPE_DELIVERY);
goodsSpu.initTokenId();
String hash;
boolean doEvmTransfer = true;
/**
* 商品为外部导入或者NFT销售类型为“原商品销售”,用外部NFT转账合约
*/
if (goodsSpu.getCommodityPass().equals(Spu.COMMODITY_PASS_OUT) || goodsSpu.getNftSalesType().equals(Spu.NFT_SALES_TYPE_DEFAULT)) {
doEvmTransfer = false;
}
if (doEvmTransfer){
/**
* 内部nft操作
*/
hash = chainUtil.evmTransfer(tranDto.getToAddr(), tranDto.getFromAddr(), goodsSpu.getTokenId(), tranDto.getAmount().longValue());
tranDto.setCoinType(TranDto.COIN_TYPE_NFT_IN);
}else{
long[] tokenIds = new long[]{goodsSpu.getTokenId()};
long[] amounts = new long[]{tranDto.getAmount().longValue()};
hash = chainUtil.evmExec(tokenIds, amounts, tranDto.getFromAddr(), tranDto.getToAddr());
tranDto.setCoinType(TranDto.COIN_TYPE_NFT_OUT);
}
tranDto.setHash(hash);
producer.sendTTL(JSON.toJSONString(tranDto), QueueTTLTypeEnum.ORDER_REFUND_COINS_TTL, 5 * 1000);
}
}
/**
* 商品为“使用权”时,退款和退货,需要重置已使用的编号
* @param serialNo
* @param coin
* @param isSalesNFTCopy
*/
private void updateSkuSerialNo(String serialNo, String coin, boolean isSalesNFTCopy) {
if (!isSalesNFTCopy) {
return;
}
if (StringUtils.isEmpty(serialNo)) {
return;
}
List<Integer> serialNoList = JSON.parseArray(serialNo, int.class);
if (CollectionUtils.isEmpty(serialNoList)) {
return;
}
QueryWrapper<GoodsSkuUsufruct> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("prefix", coin);
GoodsSkuUsufruct skuUsufruct = goodsSkuUsufructMapper.selectOne(queryWrapper);
if (skuUsufruct == null) {
return;
}
List<Integer> dataSerialNoList = JSON.parseArray(skuUsufruct.getSerialNo(), int.class);
serialNoList.forEach(index -> {
dataSerialNoList.set(index, MALLGlobalConfig.SERIAL_NO_VALID);
});
User user = userService.getOne(new QueryWrapper<User>().eq("uid", delivery.getUid()));
Merchant merchant = merchantService.getOne(new QueryWrapper<Merchant>().eq("merchant_id", delivery.getMerchantId()));
assetService.refundCoinOnChain(TranDto.TABLE_TYPE_DELIVERY, delivery.getOrderDeliveryId(), delivery.getCoin(), delivery.getNumber(), null, merchant.getTokenIssueAddr(), user.getAddress());
}
}
......@@ -32,4 +32,6 @@ public interface IAssetService extends IService<Asset> {
* @param isApproved
*/
void integralDeduction(String oid, String uid, BigDecimal amount, String merchantId, List<OrderDetail> orderDetailList, Boolean isApproved);
void refundCoinOnChain(int tableType, String tableId, String coin, int number, String serialNo, String fromAddr, String toAddr);
}
......@@ -29,13 +29,11 @@ import com.fzm.mall.server.admin.user.service.IAssetService;
import com.fzm.mall.server.admin.user_center.model.User;
import com.fzm.mall.server.admin.user_center.service.IUserService;
import com.fzm.mall.server.admin.util.WxPayUtil;
import com.google.gson.JsonObject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import java.math.BigDecimal;
import java.util.List;
......@@ -106,6 +104,41 @@ public class AssetServiceImpl extends ServiceImpl<AssetMapper, Asset> implements
}
}
@Override
public void refundCoinOnChain(int tableType, String tableId, String coin, int number, String serialNo, String fromAddr, String toAddr) {
//判断商品是否为NFT
GoodsSpuVO goodsSpu = spuMapper.readByCoin(coin);
goodsSpu.initTokenId();
boolean isSalesNFTCopy = goodsSpu.getNftSalesType().equals(Spu.NFT_SALES_TYPE_COPY);
boolean commodityPassOut = goodsSpu.getCommodityPass().equals(Spu.COMMODITY_PASS_OUT);
/**
* 只有订单退款时,买家将商品币退还商家,商家刷一下退回的币的编号为可用
*/
boolean updateSkuSerialNo = TranDto.TABLE_TYPE_ORDER_INFO.equals(tableType);
/**
* NFT商品为“使用权销售时”,根据订单购买的编号重置为未使用
*/
List<Integer> serialNoList = JSON.parseArray(serialNo, int.class);
if (updateSkuSerialNo){
updateSkuSerialNo(serialNoList, coin, isSalesNFTCopy);
}
//根据开关判断是否走链,默认不走链
if (payInChain) {
/**
* NFT商品为“使用权销售”,tokenId+编号,循环转账操作
*/
if (isSalesNFTCopy){
serialNoList.forEach(index -> {
Long tokenId = Long.valueOf(goodsSpu.getTokenIdStr() + index);
payInChain(tableType, tableId, fromAddr, toAddr, coin, 1, tokenId, commodityPassOut, isSalesNFTCopy);
});
}else{
payInChain(tableType, tableId, fromAddr, toAddr, coin, number, goodsSpu.getTokenId(), commodityPassOut, isSalesNFTCopy);
}
}
}
/**
* 微信退款
*
......@@ -160,6 +193,8 @@ public class AssetServiceImpl extends ServiceImpl<AssetMapper, Asset> implements
*/
private void orderDetailCoinRefund(String uid, String merchantId, List<OrderDetail> orderDetailList, Boolean isApproved) {
if (isApproved) {
User user = userService.getOne(new QueryWrapper<User>().eq("uid", uid));
Merchant merchant = merchantService.getOne(new QueryWrapper<Merchant>().eq("merchant_id", merchantId));
orderDetailList.forEach(orderDetail -> {
QueryWrapper<Asset> queryWrapper = new QueryWrapper<Asset>().eq("uid", uid).eq("coin", orderDetail.getCoin());
Asset asset = assetMapper.selectOne(queryWrapper);
......@@ -173,8 +208,7 @@ public class AssetServiceImpl extends ServiceImpl<AssetMapper, Asset> implements
if (update == 0) {
throw new MyException(MallResponseError.UPDATE_FAIL);
}
refundOrderDetailCoin(uid, merchantId, orderDetail);
refundCoinOnChain(TranDto.TABLE_TYPE_ORDER_INFO, orderDetail.getOid(), orderDetail.getCoin(), orderDetail.getNumber(), orderDetail.getSerialNo(), user.getAddress(), merchant.getTokenIssueAddr());
});
} else {
orderDetailList.forEach(orderDetail -> {
......@@ -196,69 +230,49 @@ public class AssetServiceImpl extends ServiceImpl<AssetMapper, Asset> implements
}
}
private void refundOrderDetailCoin(String uid, String merchantId, OrderDetail orderDetail) {
//判断商品是否为NFT
GoodsSpuVO goodsSpu = spuMapper.readByCoin(orderDetail.getCoin());
boolean isSalesNFTCopy = goodsSpu.getNftSalesType().equals(Spu.NFT_SALES_TYPE_COPY);
private void payInChain(int tableType, String tableId, String fromAddr, String toAddr, String coin, int number,
Long tokenId, boolean commodityPassOut, boolean isSalesNFTCopy){
TranDto tranDto = new TranDto();
tranDto.setFromAddr(fromAddr);
tranDto.setToAddr(toAddr);
tranDto.setCoin(coin);
//一个商品对应一个币,此处构造不存在精度丢失问题
tranDto.setAmount(new BigDecimal(number));
tranDto.setTableId(tableId);
tranDto.setTableType(tableType);
String hash;
boolean doEvmTransfer = true;
/**
* NFT商品为“使用权销售时”,根据订单购买的编号重置为未使用
* 商品为外部导入或者NFT销售类型为“原商品销售”,用外部NFT转账合约
*/
updateSkuSerialNo(orderDetail.getSerialNo(), orderDetail.getCoin(), isSalesNFTCopy);
//根据开关判断是否走链,默认不走链
if (payInChain) {
User user = userService.getOne(new QueryWrapper<User>().eq("uid", uid));
Merchant merchant = merchantService.getOne(new QueryWrapper<Merchant>().eq("merchant_id", merchantId));
TranDto tranDto = new TranDto();
tranDto.setFromAddr(user.getAddress());
tranDto.setToAddr(merchant.getTokenIssueAddr());
tranDto.setCoin(orderDetail.getCoin());
//一个商品对应一个币,此处构造不存在精度丢失问题
tranDto.setAmount(new BigDecimal(orderDetail.getNumber()));
tranDto.setTableId(orderDetail.getOid());
tranDto.setTableType(TranDto.TABLE_TYPE_ORDER_INFO);
goodsSpu.initTokenId();
String hash;
boolean doEvmTransfer = true;
if (commodityPassOut || !isSalesNFTCopy) {
doEvmTransfer = false;
}
if (doEvmTransfer) {
/**
* 商品为外部导入或者NFT销售类型为“原商品销售”,用外部NFT转账合约
* 内部nft操作
*/
if (goodsSpu.getCommodityPass().equals(Spu.COMMODITY_PASS_OUT) || goodsSpu.getNftSalesType().equals(Spu.NFT_SALES_TYPE_DEFAULT)) {
doEvmTransfer = false;
}
if (doEvmTransfer) {
/**
* 内部nft操作
*/
hash = chainUtil.evmTransfer(tranDto.getToAddr(), tranDto.getFromAddr(), goodsSpu.getTokenId(), tranDto.getAmount().longValue());
tranDto.setCoinType(TranDto.COIN_TYPE_NFT_IN);
} else {
long[] tokenIds = new long[]{goodsSpu.getTokenId()};
long[] amounts = new long[]{tranDto.getAmount().longValue()};
hash = chainUtil.evmExec(tokenIds, amounts, tranDto.getFromAddr(), tranDto.getToAddr());
tranDto.setCoinType(TranDto.COIN_TYPE_NFT_OUT);
}
tranDto.setHash(hash);
producer.sendTTL(JSON.toJSONString(tranDto), QueueTTLTypeEnum.ORDER_REFUND_COINS_TTL, 5 * 1000);
hash = chainUtil.evmTransfer(tranDto.getToAddr(), tranDto.getFromAddr(), tokenId, tranDto.getAmount().longValue());
tranDto.setCoinType(TranDto.COIN_TYPE_NFT_IN);
} else {
long[] tokenIds = new long[]{tokenId};
long[] amounts = new long[]{tranDto.getAmount().longValue()};
hash = chainUtil.evmExec(tokenIds, amounts, tranDto.getFromAddr(), tranDto.getToAddr());
tranDto.setCoinType(TranDto.COIN_TYPE_NFT_OUT);
}
tranDto.setHash(hash);
producer.sendTTL(JSON.toJSONString(tranDto), QueueTTLTypeEnum.ORDER_REFUND_COINS_TTL, 5 * 1000);
}
/**
* 商品为“使用权”时,退款和退货,需要重置已使用的编号
* @param serialNo
*
* @param serialNoList
* @param coin
* @param isSalesNFTCopy
*/
private void updateSkuSerialNo(String serialNo, String coin, boolean isSalesNFTCopy) {
if (!isSalesNFTCopy) {
return;
}
if (StringUtils.isEmpty(serialNo)) {
return;
}
List<Integer> serialNoList = JSON.parseArray(serialNo, int.class);
if (CollectionUtils.isEmpty(serialNoList)) {
private void updateSkuSerialNo(List<Integer> serialNoList, String coin, boolean isSalesNFTCopy) {
if (!isSalesNFTCopy || CollectionUtils.isEmpty(serialNoList)) {
return;
}
QueryWrapper<GoodsSkuUsufruct> queryWrapper = new QueryWrapper<>();
......@@ -275,8 +289,12 @@ public class AssetServiceImpl extends ServiceImpl<AssetMapper, Asset> implements
skuUsufruct.setSerialNo(JSON.toJSONString(dataSerialNoList));
UpdateWrapper<GoodsSkuUsufruct> updateWrapper = new UpdateWrapper<>();
updateWrapper.eq("prefix", coin);
updateWrapper.eq("prefix", coin)
.eq("update_time", skuUsufruct.getUpdateTime());
goodsSkuUsufructMapper.update(skuUsufruct, updateWrapper);
int update = goodsSkuUsufructMapper.update(skuUsufruct, updateWrapper);
if (update == 0) {
throw new MyException(MallResponseError.UPDATE_FAIL);
}
}
}
......@@ -130,7 +130,7 @@
</select>
<select id="readByCoin" resultType="com.fzm.mall.server.admin.goods_center.entity.vo.GoodsSpuVO">
select sp.type, sp.commodity_pass, IFNULL(n.token_id, t.token_id) tokenIdStr, s.nft_sales_type
select sp.type, sp.commodity_pass, IFNULL(n.token_id, t.token_id) tokenIdStr, s.nft_sales_type as nftSalesType
from goods_sku s
left join goods_spu sp on s.goods_id = sp.goods_id
left join goods_nft n on sp.commodity_pass = 1 and sp.type = 6 and sp.goods_id = n.goods_id
......
......@@ -93,19 +93,25 @@ public class UserAssetTransferRecordServiceImpl extends ServiceImpl<UserAssetTra
if (userRecive == null || user.getAddress().equals(userRecive.getAddress())) {
throw new RuntimeException("addr_invalid");
}
boolean isSalesNFTCopy = goodSpu.getNftSalesType().equals(GoodSpu.NFT_SALES_TYPE_COPY);
boolean commodityPassOut = goodSpu.getCommodityPass().equals(GoodSpu.COMMODITY_PASS_OUT);
boolean doEvmTransfer = true;
/**
* 商品token如果是外部的,必然是上链查的nft;
* 如果是自动生成的,如果是NFT类,则用nft转让;其他为普通token
* 商品为外部导入或者NFT销售类型为“原商品销售”,用外部NFT转账合约
*/
if (commodityPassOut || !isSalesNFTCopy) {
doEvmTransfer = false;
}
String hash;
if (goodSpu.getCommodityPass().equals(Spu.COMMODITY_PASS_OUT)) {
if (doEvmTransfer) {
hash = chainUtil.evmTransfer(userRecive.getAddress(), user.getAddress(), goodSpu.getTokenId(), amount.longValue());
goodSpu.setCoinType(TranDto.COIN_TYPE_NFT_IN);
} else {
long[] tokenIds = new long[]{goodSpu.getTokenId()};
long[] amounts = new long[]{amount.longValue()};
hash = chainUtil.evmExec(tokenIds, amounts, user.getAddress(), userRecive.getAddress());
goodSpu.setCoinType(TranDto.COIN_TYPE_NFT_OUT);
} else {
hash = chainUtil.evmTransfer(userRecive.getAddress(), user.getAddress(), goodSpu.getTokenId(), amount.longValue());
goodSpu.setCoinType(TranDto.COIN_TYPE_NFT_IN);
}
return hash;
}
......
......@@ -39,6 +39,13 @@ public class GoodSpu implements Serializable {
public static final Integer COMMODITY_PASS_OUT = 2;
/**
* nft销售方式(1.原商品销售 2.拷贝销售)
*/
public static final Integer NFT_SALES_TYPE_DEFAULT = 1;
public static final Integer NFT_SALES_TYPE_COPY = 2;
@TableId(value = "id", type = IdType.AUTO)
private Long id;
......@@ -129,6 +136,12 @@ public class GoodSpu implements Serializable {
@TableField(exist = false)
private Integer coinType;
@ApiModelProperty(value = "nft销售方式(1.原商品销售 2.拷贝销售)")
@TableField(exist = false)
private Integer nftSalesType;
private String nftFile;
public void initTokenId() {
if (commodityPass.equals(COMMODITY_PASS_OUT)){
setTokenId(Long.valueOf(tokenIdStr));
......@@ -136,6 +149,4 @@ public class GoodSpu implements Serializable {
setTokenId(Long.valueOf(getTokenIdStr().replace( MALLGlobalConfig.GOODS_NFT_PREFIX,"")));
}
}
private String nftFile;
}
......@@ -3,7 +3,7 @@
<mapper namespace="com.fzm.mall.server.front.goods.mapper.GoodSpuMapper">
<select id="readByCoin" resultType="com.fzm.mall.server.front.goods.model.GoodSpu">
select sp.type, sp.commodity_pass, IFNULL(n.token_id, t.token_id) tokenIdStr
select sp.type, sp.commodity_pass, IFNULL(n.token_id, t.token_id) tokenIdStr, s.nft_sales_type as nftSalesType
from goods_sku s
left join goods_spu sp on s.goods_id = sp.goods_id
left join goods_nft n on sp.commodity_pass = 1 and sp.type = 6 and sp.goods_id = n.goods_id
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment