抖音部署
This commit is contained in:
zhouwentao 2024-04-15 20:12:22 +08:00
parent 071254753b
commit 1380e03375
13 changed files with 336 additions and 11 deletions

View File

@ -0,0 +1,59 @@
package org.jeecg.modules.mini.controller;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.SecurityUtils;
import org.jeecg.common.api.vo.Result;
import org.jeecg.common.system.vo.LoginUser;
import org.jeecg.common.util.AssertUtils;
import org.jeecg.modules.yx.entity.YxOrder;
import org.jeecg.modules.yx.service.IYxOrderService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.List;
import java.util.stream.Collectors;
/**
* @Description
* @Author ZhouWenTao
* @Date 2024/4/15 18:37
*/
@Slf4j
@Api(tags = "小程序-订单相关接口")
@RestController
@RequestMapping("/mini/order")
public class MiniOrderController {
@Autowired
private IYxOrderService yxOrderService;
@GetMapping(value = "/orderList")
@ApiOperation(value = "获取订单列表")
public Result<?> orderList(){
LoginUser loginUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
AssertUtils.notNull(loginUser,"未获取到登录信息");
List<YxOrder> orderList = yxOrderService.findListByPaymentUserId(loginUser.getId());
orderList = orderList.stream().filter(o->!"1".equals(o.getOrderStatus())).collect(Collectors.toList());
for (YxOrder yxOrder : orderList) {
if (yxOrder.getTotalAmount()!=null) {
yxOrder.setTotalAmount(yxOrder.getTotalAmount().divide(new BigDecimal(100),2, RoundingMode.HALF_UP));
}
}
return Result.OK(orderList);
}
@GetMapping(value = "/orderDetail")
@ApiOperation(value = "获取订单详情")
public Result<?> buy(@RequestParam(value = "orderCode")String orderCode){
AssertUtils.notNull(orderCode,"订单编号为空!");
YxOrder yxOrder = yxOrderService.getByOrderCode(orderCode);
if (yxOrder.getTotalAmount()!=null) {
yxOrder.setTotalAmount(yxOrder.getTotalAmount().divide(new BigDecimal(100),2, RoundingMode.HALF_UP));
}
AssertUtils.notNull(yxOrder,"订单信息未找到!");
return Result.OK(yxOrder);
}
}

View File

@ -30,6 +30,8 @@ import org.jeecg.common.api.vo.Result;
import org.jeecg.common.exception.JeecgBootException;
import org.jeecg.common.system.vo.LoginUser;
import org.jeecg.common.util.AssertUtils;
import org.jeecg.modules.mini.douyin.model.DouYinOrderSyncModel;
import org.jeecg.modules.mini.douyin.model.ItemStruct;
import org.jeecg.modules.mini.douyin.util.DouWayPaymentMethod;
import org.jeecg.modules.mini.douyin.util.DouYinUtil;
import org.jeecg.modules.mini.douyin.util.Sign;
@ -38,6 +40,7 @@ import org.jeecg.modules.mini.douyin.model.DouYinOrderModel;
import org.jeecg.modules.mini.service.MiniUserService;
import org.jeecg.modules.system.entity.SysUser;
import org.jeecg.modules.system.service.ISysUserService;
import org.jeecg.modules.system.util.OrderNumberGenerator;
import org.jeecg.modules.yx.entity.YxOrder;
import org.jeecg.modules.yx.entity.YxVipSku;
import org.jeecg.modules.yx.service.IYxOrderService;
@ -151,7 +154,7 @@ public class MiniPayApiController {
}
YxOrder yxOrder = new YxOrder();
String orderCode = PayKit.generateStr();
String orderCode = OrderNumberGenerator.generateOrderNumber();
String openId = user.getWxOpenId();
BigDecimal skuPrice = yxVipSku.getSkuPrice();
BigDecimal totalAmount = skuPrice.multiply(new BigDecimal("100"));
@ -240,6 +243,8 @@ public class MiniPayApiController {
String result = HttpKit.readData(request);
try {
String timestamp = request.getHeader("Wechatpay-Timestamp");
YxOrder yxOrder = null;
SysUser sysUser = null;
if (StringUtils.isNotBlank(timestamp)) {
//微信平台
String nonce = request.getHeader("Wechatpay-Nonce");
@ -310,6 +315,26 @@ public class MiniPayApiController {
Date date = new Date();
date.setTime(paidAt*1000);
yxOrderService.paymentOrderOver(cpOrderno, DouWayPaymentMethod.getByWay(way), "2", date);
yxOrder = yxOrderService.getByOrderCode(cpOrderno);
sysUser = sysUserService.getById(yxOrder.getPaymentUserId());
long createTimeLong = yxOrder.getCreateTime().getTime() / 1000;
//同步抖音订单
DouYinOrderSyncModel douYinOrderSyncModel = new DouYinOrderSyncModel();
douYinOrderSyncModel.setOrder_id(cpOrderno);
douYinOrderSyncModel.setCreate_time(createTimeLong);
douYinOrderSyncModel.setStatus("已支付");
douYinOrderSyncModel.setAmount(1);
douYinOrderSyncModel.setTotal_price(yxOrder.getTotalAmount().longValue());
douYinOrderSyncModel.setDetail_url("pages/zyb/order/detail?orderCode="+cpOrderno);
List<ItemStruct> itemList=new ArrayList<>();
String img="https://mp-7a4eecb1-2a04-4d36-b050-1c4a78cc31a4.cdn.bspapp.com/images/vip.png";
if ("1001".equals(yxOrder.getSkuCode())) {
img="https://mp-7a4eecb1-2a04-4d36-b050-1c4a78cc31a4.cdn.bspapp.com/images/tiyanka.png";
}
itemList.add(new ItemStruct(yxOrder.getSkuCode(),img,"艺体志愿宝-"+yxOrder.getSkuName(),null,1,yxOrder.getTotalAmount().longValue()));
douYinOrderSyncModel.setItem_list(itemList);
DouYinUtil.orderSync(douYinOrderSyncModel,appid,secret,sysUser.getDyOpenId());
response.setStatus(200);
map.put("code", "SUCCESS");
map.put("message", "SUCCESS");

View File

@ -14,7 +14,6 @@ import cn.hutool.http.HttpStatus;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.ijpay.core.IJPayHttpResponse;
import com.ijpay.core.enums.RequestMethodEnum;
@ -42,6 +41,7 @@ import org.jeecg.modules.mini.dto.VipDTO;
import org.jeecg.modules.mini.service.MiniUserService;
import org.jeecg.modules.system.entity.SysUser;
import org.jeecg.modules.system.service.ISysUserService;
import org.jeecg.modules.system.util.OrderNumberGenerator;
import org.jeecg.modules.yx.entity.YxOrder;
import org.jeecg.modules.yx.entity.YxVipSku;
import org.jeecg.modules.yx.service.IYxOrderService;
@ -133,7 +133,7 @@ public class WxPayApiController {
}
YxOrder yxOrder = new YxOrder();
String orderCode = PayKit.generateStr();
String orderCode = OrderNumberGenerator.generateOrderNumber();
String openId = user.getWxOpenId();
BigDecimal skuPrice = yxVipSku.getSkuPrice();
BigDecimal totalAmount=skuPrice.multiply(new BigDecimal("100"));

View File

@ -0,0 +1,79 @@
package org.jeecg.modules.mini.douyin.model;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.io.Serializable;
import java.util.List;
/**
* @author ZhouWenTao
* @create 2024-04-15 11:43
* 官方文档 https://developer.open-douyin.com/docs/resource/zh-CN/mini-app/develop/server/ecpay/order/order-sync/#order_detail%20%E5%AD%97%E6%AE%B5%E8%AF%B4%E6%98%8E
*/
public class DouYinOrderSyncModel implements Serializable {
private String order_id; //*开发者侧业务单号用作幂等控制该订单号是和担保支付的支付单号绑定的也就是预下单时传入的 out_order_no 字段长度 <= 64byte
private long create_time;//*订单创建的时间13 位毫秒时间戳
private String status; //*订单状态建议采用以下枚举值,待支付,已支付,已取消,已超时,已核销,退款中,已退款,退款失败
private long amount; //*订单商品总数
private long total_price; //*订单总价单位为分
private String detail_url; //*小程序订单详情页 path长度<=1024 byte (备注该路径需要保证在小程序内配置过相对路径即可
private List<ItemStruct> item_list; //* 子订单商品列表不可为空
public String getOrder_id() {
return order_id;
}
public void setOrder_id(String order_id) {
this.order_id = order_id;
}
public long getCreate_time() {
return create_time;
}
public void setCreate_time(long create_time) {
this.create_time = create_time;
}
public String getStatus() {
return status;
}
public void setStatus(String status) {
this.status = status;
}
public long getAmount() {
return amount;
}
public void setAmount(long amount) {
this.amount = amount;
}
public long getTotal_price() {
return total_price;
}
public void setTotal_price(long total_price) {
this.total_price = total_price;
}
public String getDetail_url() {
return detail_url;
}
public void setDetail_url(String detail_url) {
this.detail_url = detail_url;
}
public List<ItemStruct> getItem_list() {
return item_list;
}
public void setItem_list(List<ItemStruct> item_list) {
this.item_list = item_list;
}
}

View File

@ -0,0 +1,31 @@
package org.jeecg.modules.mini.douyin.model;
import lombok.Data;
import java.io.Serializable;
/**
* @author ZhouWenTao
* @create 2024-04-15-15:54
*/
@Data
public class ItemStruct implements Serializable {
private String item_code;//*开发者侧商品 ID长度 <= 64 byte
private String img;//*子订单商品图片 URL
private String title;//*长度 <= 512 byte
private String sub_title;//子订单商品介绍标题长度 <= 256 byte
private long amount;//*子订单商品介绍副标题长度 <= 256 byte
private long price;//*单类商品的数目
public ItemStruct() {
}
public ItemStruct(String item_code, String img, String title, String sub_title, long amount, long price) {
this.item_code = item_code;
this.img = img;
this.title = title;
this.sub_title = sub_title;
this.amount = amount;
this.price = price;
}
}

View File

@ -2,10 +2,13 @@ package org.jeecg.modules.mini.douyin.util;
import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.jeecg.common.exception.JeecgBootException;
import org.jeecg.common.util.RestUtil;
import org.jeecg.modules.mini.douyin.model.DouYinOrderSyncModel;
import org.jeecg.modules.mini.douyin.model.ItemStruct;
import java.util.HashMap;
import java.util.Map;
import java.util.*;
/**
* @author ZhouWenTao
@ -13,6 +16,31 @@ import java.util.Map;
*/
@Slf4j
public class DouYinUtil {
//获取accessToken
private final static String getAccessTokenUrl="https://developer.toutiao.com/api/apps/v2/token";
private final static String orderSyncUrl="https://developer.toutiao.com/api/apps/order/v2/push";
/**
* 获取 accessToken
* @param appId
* @param appSecret
* 文档 https://developer.open-douyin.com/docs/resource/zh-CN/mini-app/develop/server/interface-request-credential/non-user-authorization/get-access-token
* @return
*/
public static String getAccessToken(String appId,String appSecret){
//
JSONObject jsonObject = JSONObject.parseObject("{\"appid\":\"" + appId + "\",\"grant_type\":\"client_credential\",\"secret\":\"" + appSecret + "\"}");
JSONObject post = RestUtil.post(getAccessTokenUrl, jsonObject);
if (post==null) {
return null;
}
String errTips = post.getString("err_tips");
if (!"success".equals(errTips)) {
return null;
}
return post.getJSONObject("data").getString("access_token");
}
public static String main(String appId,String token,String notifyUrl,String salt,String orderCode,
Integer totalAmount,String skuName,String description) {
Map<String, Object> testCase = new HashMap<String, Object>() {{
@ -43,4 +71,51 @@ public class DouYinUtil {
JSONObject msg = jsonObject.getJSONObject("msg");
System.out.println(JSONObject.parseObject(ss));*/
}
/**
* 订单同步
*/
public static void orderSync(DouYinOrderSyncModel douYinOrderSyncModel,String appId, String appSecret, String openId){
log.debug("抖音订单同步----订单号:"+douYinOrderSyncModel.getOrder_id());
//文档 https://developer.open-douyin.com/docs/resource/zh-CN/mini-app/develop/server/ecpay/order/order-sync/
String accessToken = getAccessToken(appId, appSecret);
if (StringUtils.isBlank(accessToken)) {
throw new JeecgBootException("获取accessToken失败");
}
JSONObject requestJson=new JSONObject();
requestJson.put("access_token",accessToken);
requestJson.put("app_name","douyin");
requestJson.put("open_id",openId);
requestJson.put("order_status",1);
requestJson.put("order_type",0);
requestJson.put("update_time",new Date().getTime()/1000);
//详情字段
requestJson.put("order_detail",JSONObject.toJSONString(douYinOrderSyncModel));
JSONObject post = RestUtil.post(orderSyncUrl,requestJson);
if (post!=null && "success".equals(post.getString("err_msg"))) {
//同步成功
log.debug("抖音订单同步成功----订单号:"+douYinOrderSyncModel.getOrder_id());
}else{
log.debug("抖音订单同步失败----订单号:"+douYinOrderSyncModel.getOrder_id()+",错误原因:"+post.toJSONString());
}
}
public static void main(String[] args) {
String openId="_000-8dokDbb5cDgK7gdSNOJrzIBFQZNqOrO";
String appId="tt59a72f1ac6964bfa01";
String appSecret="46882267247ca02561cf899d03adf562aa93ad3e";
//getAccessToken(appId,appSecret);
DouYinOrderSyncModel douYinOrderSyncModel=new DouYinOrderSyncModel();
String orderId="2bba71312366498c900b3575c7d9cad5";
douYinOrderSyncModel.setOrder_id(orderId);
douYinOrderSyncModel.setCreate_time(1713104670);
douYinOrderSyncModel.setStatus("已支付");
douYinOrderSyncModel.setAmount(1);
douYinOrderSyncModel.setTotal_price(1);
douYinOrderSyncModel.setDetail_url("pages/zyb/order/detail?orderCode="+orderId);
List<ItemStruct> itemList=new ArrayList<>();
itemList.add(new ItemStruct("1002","https://mp-7a4eecb1-2a04-4d36-b050-1c4a78cc31a4.cdn.bspapp.com/images/vip.png",null,"艺体志愿宝-数据体验卡",1,1));
douYinOrderSyncModel.setItem_list(itemList);
orderSync(douYinOrderSyncModel,appId,appSecret,openId);
}
}

View File

@ -0,0 +1,26 @@
package org.jeecg.modules.system.util;
/**
* @author ZhouWenTao
* @create 2024-04-15-18:04
*/
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Random;
public class OrderNumberGenerator {
public static String generateOrderNumber() {
SimpleDateFormat dateFormat = new SimpleDateFormat("yyMMddHHmmss");
String timestamp = dateFormat.format(new Date());
Random random = new Random();
int randomNumber = random.nextInt(1000); // 生成一个三位随机数
return "ORD" + timestamp + randomNumber;
}
public static void main(String[] args) {
String orderNumber = generateOrderNumber();
System.out.println("Generated Order Number: " + orderNumber);
}
}

View File

@ -4,10 +4,8 @@ import java.io.Serializable;
import java.io.UnsupportedEncodingException;
import java.util.Date;
import java.math.BigDecimal;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.baomidou.mybatisplus.annotation.TableLogic;
import com.baomidou.mybatisplus.annotation.*;
import lombok.Data;
import com.fasterxml.jackson.annotation.JsonFormat;
import org.springframework.format.annotation.DateTimeFormat;
@ -92,4 +90,21 @@ public class YxOrder implements Serializable {
/**订单签名*/
@ApiModelProperty(value = "订单签名")
private String orderSign;
/**退款金额*/
@Excel(name = "退款金额", width = 15)
@ApiModelProperty(value = "退款金额")
private java.math.BigDecimal refundAmount;
/**退款日期*/
@JsonFormat(timezone = "GMT+8",pattern = "yyyy-MM-dd HH:mm:ss")
@DateTimeFormat(pattern="yyyy-MM-dd HH:mm:ss")
@ApiModelProperty(value = "退款日期")
private java.util.Date refundTime;
//==================
@TableField(exist = false)
private String skuName;
@TableField(exist = false)
private String skuDetail;
}

View File

@ -15,4 +15,6 @@ import com.baomidou.mybatisplus.core.mapper.BaseMapper;
public interface YxOrderMapper extends BaseMapper<YxOrder> {
List<YxOrder> findListByPaymentUserId(String paymentUserId);
YxOrder selectByOrderCode(String orderCode);
}

View File

@ -3,9 +3,15 @@
<mapper namespace="org.jeecg.modules.yx.mapper.YxOrderMapper">
<select id="findListByPaymentUserId" resultType="org.jeecg.modules.yx.entity.YxOrder">
SELECT o.* FROM yx_order o
SELECT o.*,vsku.sku_name as skuName,vsku.sku_detail as skuDetail FROM yx_order o
LEFT JOIN yx_vip_sku vsku ON vsku.sku_code = o.sku_code
WHERE o.payment_user_id = #{paymentUserId}
WHERE o.payment_user_id = #{paymentUserId} AND o.order_code is not null
ORDER BY vsku.sku_code,o.payment_time DESC
</select>
<select id="selectByOrderCode" resultType="org.jeecg.modules.yx.entity.YxOrder">
SELECT o.*,vsku.sku_name as skuName,vsku.sku_detail as skuDetail FROM yx_order o
LEFT JOIN yx_vip_sku vsku ON vsku.sku_code = o.sku_code
WHERE o.order_code = #{orderCode}
ORDER BY vsku.sku_code,o.payment_time DESC
</select>
</mapper>

View File

@ -23,4 +23,6 @@ public interface IYxOrderService extends IService<YxOrder> {
* @param paymentTime 支付时间
*/
void paymentOrderOver(String orderCode,String paymentType, String orderStatus, Date paymentTime);
YxOrder getByOrderCode(String orderCode);
}

View File

@ -38,4 +38,9 @@ public class YxOrderServiceImpl extends ServiceImpl<YxOrderMapper, YxOrder> impl
lambdaUpdateWrapper.set(YxOrder::getOrderStatus, "2");
super.update(lambdaUpdateWrapper);
}
@Override
public YxOrder getByOrderCode(String orderCode) {
return baseMapper.selectByOrderCode(orderCode);
}
}