diff --git a/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/date/DateUtils.java b/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/date/DateUtils.java index 1162d7e27..e7878f8b2 100644 --- a/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/date/DateUtils.java +++ b/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/date/DateUtils.java @@ -188,6 +188,36 @@ public class DateUtils { SimpleDateFormat dft = new SimpleDateFormat(DATE_FORMAT); return dft.format(new Date()); } + + /** + * 获取当前日期,指定格式 + * 描述:<描述函数实现的功能>. + * + * @return + */ + public static Date nowDateTime() { + return strToDate(nowDateTimeStr(), Constants.DATE_FORMAT); + } + /** + * 获取当前日期,指定格式 + * 描述:<描述函数实现的功能>. + * + * @return + */ + public static String nowDateTimeStr() { + return nowDate(Constants.DATE_FORMAT); + } + /** + * 获取当前日期,指定格式 + * 描述:<描述函数实现的功能>. + * + * @return + */ + public static String nowDate(String DATE_FORMAT) { + SimpleDateFormat dft = new SimpleDateFormat(DATE_FORMAT); + return dft.format(new Date()); + } + /** * 指定日期加上天数后的日期 * @@ -208,6 +238,21 @@ public class DateUtils { } } + /** + * 指定日期加上天数后的日期 + * + * @param num 为增加的天数 + * @param newDate 创建时间 + * @return + */ + public static final String addDay(Date newDate, int num, String pattern) { + SimpleDateFormat format = new SimpleDateFormat(pattern); + Calendar ca = Calendar.getInstance(); + ca.setTime(newDate); + ca.add(Calendar.DATE, num); + return format.format(ca.getTime()); + } + /** 获得本周第一天:yyyy-MM-dd HH:mm:ss */ public static String getWeekStartDay() { Calendar c = Calendar.getInstance(); @@ -303,6 +348,31 @@ public class DateUtils { return null; } } + + /** + * 两个日期之前的相差天数 + * @param starDate 开始日期 + * @param endDate 结束日期 + * @return 相差天数 + */ + public static int daysBetween(Date starDate,Date endDate){ + + Calendar cal = Calendar.getInstance(); + + cal.setTime(starDate); + + long time1 = cal.getTimeInMillis(); + + cal.setTime(endDate); + + long time2 = cal.getTimeInMillis(); + + long between_days=(time2-time1)/(1000*3600*24); + + return Integer.parseInt(String.valueOf(between_days)); + + } + /** * 获取指定日期指定格式字符串 * diff --git a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/express/ShippingTemplatesFreeServiceImpl.java b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/express/impl/ShippingTemplatesFreeServiceImpl.java similarity index 97% rename from yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/express/ShippingTemplatesFreeServiceImpl.java rename to yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/express/impl/ShippingTemplatesFreeServiceImpl.java index a7e6a8274..8ab6a086c 100644 --- a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/express/ShippingTemplatesFreeServiceImpl.java +++ b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/express/impl/ShippingTemplatesFreeServiceImpl.java @@ -1,9 +1,10 @@ -package cn.iocoder.yudao.module.product.service.express; +package cn.iocoder.yudao.module.product.service.express.impl; import cn.iocoder.yudao.framework.common.util.string.StrUtils; import cn.iocoder.yudao.module.product.controller.admin.express.vo.ShippingTemplatesFreeRespVO; import cn.iocoder.yudao.module.product.dal.dataobject.express.ShippingTemplatesFreeDO; import cn.iocoder.yudao.module.product.dal.mysql.express.ShippingTemplatesFreeMapper; +import cn.iocoder.yudao.module.product.service.express.ShippingTemplatesFreeService; import cn.iocoder.yudao.module.system.controller.admin.ip.vo.AreaNodeRespVO; import cn.iocoder.yudao.module.system.service.ip.AreaService; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; diff --git a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/express/ShippingTemplatesNoDeliveryServiceImpl.java b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/express/impl/ShippingTemplatesNoDeliveryServiceImpl.java similarity index 96% rename from yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/express/ShippingTemplatesNoDeliveryServiceImpl.java rename to yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/express/impl/ShippingTemplatesNoDeliveryServiceImpl.java index c9d887826..32f976942 100644 --- a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/express/ShippingTemplatesNoDeliveryServiceImpl.java +++ b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/express/impl/ShippingTemplatesNoDeliveryServiceImpl.java @@ -1,9 +1,10 @@ -package cn.iocoder.yudao.module.product.service.express; +package cn.iocoder.yudao.module.product.service.express.impl; import cn.iocoder.yudao.framework.common.util.string.StrUtils; import cn.iocoder.yudao.module.product.controller.admin.express.vo.ShippingTemplatesNoDeliveryRespVO; import cn.iocoder.yudao.module.product.dal.dataobject.express.ShippingTemplatesNoDeliveryDO; import cn.iocoder.yudao.module.product.dal.mysql.express.ShippingTemplatesNoDeliveryMapper; +import cn.iocoder.yudao.module.product.service.express.ShippingTemplatesNoDeliveryService; import cn.iocoder.yudao.module.system.controller.admin.ip.vo.AreaNodeRespVO; import cn.iocoder.yudao.module.system.service.ip.AreaService; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; diff --git a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/express/ShippingTemplatesRegionServiceImpl.java b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/express/impl/ShippingTemplatesRegionServiceImpl.java similarity index 98% rename from yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/express/ShippingTemplatesRegionServiceImpl.java rename to yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/express/impl/ShippingTemplatesRegionServiceImpl.java index dadcca922..87e457c2a 100644 --- a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/express/ShippingTemplatesRegionServiceImpl.java +++ b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/express/impl/ShippingTemplatesRegionServiceImpl.java @@ -1,9 +1,10 @@ -package cn.iocoder.yudao.module.product.service.express; +package cn.iocoder.yudao.module.product.service.express.impl; import cn.iocoder.yudao.framework.common.util.string.StrUtils; import cn.iocoder.yudao.module.product.controller.admin.express.vo.ShippingTemplatesRegionRespVO; import cn.iocoder.yudao.module.product.dal.dataobject.express.ShippingTemplatesRegionDO; import cn.iocoder.yudao.module.product.dal.mysql.express.ShippingTemplatesRegionMapper; +import cn.iocoder.yudao.module.product.service.express.ShippingTemplatesRegionService; import cn.iocoder.yudao.module.system.controller.admin.ip.vo.AreaNodeRespVO; import cn.iocoder.yudao.module.system.service.ip.AreaService; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; diff --git a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/express/ShippingTemplatesServiceImpl.java b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/express/impl/ShippingTemplatesServiceImpl.java similarity index 95% rename from yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/express/ShippingTemplatesServiceImpl.java rename to yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/express/impl/ShippingTemplatesServiceImpl.java index dfe4d7eb2..6cdcd3311 100644 --- a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/express/ShippingTemplatesServiceImpl.java +++ b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/express/impl/ShippingTemplatesServiceImpl.java @@ -1,4 +1,4 @@ -package cn.iocoder.yudao.module.product.service.express; +package cn.iocoder.yudao.module.product.service.express.impl; import cn.hutool.core.collection.CollUtil; import cn.hutool.core.util.ObjectUtil; @@ -7,6 +7,10 @@ import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.module.product.controller.admin.express.vo.*; import cn.iocoder.yudao.module.product.dal.dataobject.express.ShippingTemplatesDO; import cn.iocoder.yudao.module.product.dal.mysql.express.ShippingTemplatesMapper; +import cn.iocoder.yudao.module.product.service.express.ShippingTemplatesFreeService; +import cn.iocoder.yudao.module.product.service.express.ShippingTemplatesNoDeliveryService; +import cn.iocoder.yudao.module.product.service.express.ShippingTemplatesRegionService; +import cn.iocoder.yudao.module.product.service.express.ShippingTemplatesService; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import org.apache.commons.lang3.StringUtils; diff --git a/yudao-module-mall/yudao-module-shop-api/src/main/java/cn/iocoder/yudao/module/shop/response/order/StoreOrderCountItemResponse.java b/yudao-module-mall/yudao-module-shop-api/src/main/java/cn/iocoder/yudao/module/shop/response/order/StoreOrderCountItemResponse.java index 38b9091b8..5b42b10e1 100644 --- a/yudao-module-mall/yudao-module-shop-api/src/main/java/cn/iocoder/yudao/module/shop/response/order/StoreOrderCountItemResponse.java +++ b/yudao-module-mall/yudao-module-shop-api/src/main/java/cn/iocoder/yudao/module/shop/response/order/StoreOrderCountItemResponse.java @@ -29,35 +29,35 @@ public class StoreOrderCountItemResponse implements Serializable { private static final long serialVersionUID = -8605913636959651047L; @Schema(description = "总数") - private Integer all; + private Long all; @Schema(description = "未支付") - private Integer unPaid; + private Long unPaid; @Schema(description = "未发货") - private Integer notShipped; + private Long notShipped; @Schema(description = "待收货") - private Integer spike; + private Long spike; @Schema(description = "待评价") - private Integer bargain; + private Long bargain; @Schema(description = "交易完成") - private Integer complete; + private Long complete; @Schema(description = "待核销") - private Integer toBeWrittenOff; + private Long toBeWrittenOff; @Schema(description = "退款中") - private Integer refunding; + private Long refunding; @Schema(description = "已退款") - private Integer refunded; + private Long refunded; @Schema(description = "0 未退款 1 申请中 2 已退款") - private Integer refundStatus; + private Long refundStatus; @Schema(description = "已删除") - private Integer deleted; + private Long deleted; } diff --git a/yudao-module-mall/yudao-module-shop-api/src/main/java/cn/iocoder/yudao/module/shop/response/order/StoreOrderTopItemResponse.java b/yudao-module-mall/yudao-module-shop-api/src/main/java/cn/iocoder/yudao/module/shop/response/order/StoreOrderTopItemResponse.java index df0548f46..c5d74f920 100644 --- a/yudao-module-mall/yudao-module-shop-api/src/main/java/cn/iocoder/yudao/module/shop/response/order/StoreOrderTopItemResponse.java +++ b/yudao-module-mall/yudao-module-shop-api/src/main/java/cn/iocoder/yudao/module/shop/response/order/StoreOrderTopItemResponse.java @@ -29,7 +29,7 @@ public class StoreOrderTopItemResponse implements Serializable { private static final long serialVersionUID = -7583407020447771557L; @Schema(description = "订单数量") - private Integer count; + private Long count; @Schema(description = "订单金额") private BigDecimal amount; diff --git a/yudao-module-mall/yudao-module-shop-biz/pom.xml b/yudao-module-mall/yudao-module-shop-biz/pom.xml index 93831ac83..9ed68ff68 100644 --- a/yudao-module-mall/yudao-module-shop-biz/pom.xml +++ b/yudao-module-mall/yudao-module-shop-biz/pom.xml @@ -75,5 +75,17 @@ com.github.pagehelper pagehelper-spring-boot-starter + + cn.iocoder.boot + yudao-module-member-biz + 1.7.2-snapshot + compile + + + cn.iocoder.boot + yudao-module-system-biz + 1.7.2-snapshot + compile + \ No newline at end of file diff --git a/yudao-module-mall/yudao-module-shop-biz/src/main/java/cn/iocoder/yudao/module/shop/constants/PayConstants.java b/yudao-module-mall/yudao-module-shop-biz/src/main/java/cn/iocoder/yudao/module/shop/constants/PayConstants.java new file mode 100644 index 000000000..9b83d231e --- /dev/null +++ b/yudao-module-mall/yudao-module-shop-biz/src/main/java/cn/iocoder/yudao/module/shop/constants/PayConstants.java @@ -0,0 +1,56 @@ +package cn.iocoder.yudao.module.shop.constants; + +/** + * 支付相关常量类 + * +---------------------------------------------------------------------- + * | CRMEB [ CRMEB赋能开发者,助力企业发展 ] + * +---------------------------------------------------------------------- + * | Copyright (c) 2016~2022 https://www.crmeb.com All rights reserved. + * +---------------------------------------------------------------------- + * | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权 + * +---------------------------------------------------------------------- + * | Author: CRMEB Team + * +---------------------------------------------------------------------- + */ +public class PayConstants { + + //支付方式 + public static final String PAY_TYPE_WE_CHAT = "weixin"; //微信支付 + public static final String PAY_TYPE_YUE = "yue"; //余额支付 + public static final String PAY_TYPE_OFFLINE = "offline"; //线下支付 + public static final String PAY_TYPE_ALI_PAY = "alipay"; //支付宝 + public static final String PAY_TYPE_ZERO_PAY = "zeroPay"; // 零元付 + + //支付渠道 + public static final String PAY_CHANNEL_WE_CHAT_H5 = "weixinh5"; //H5唤起微信支付 + public static final String PAY_CHANNEL_WE_CHAT_PUBLIC = "public"; //公众号 + public static final String PAY_CHANNEL_WE_CHAT_PROGRAM = "routine"; //小程序 + public static final String PAY_CHANNEL_WE_CHAT_APP_IOS = "weixinAppIos"; //微信App支付ios + public static final String PAY_CHANNEL_WE_CHAT_APP_ANDROID = "weixinAppAndroid"; //微信App支付android + + public static final String PAY_CHANNEL_ALI_PAY = "alipay"; //支付宝支付 + public static final String PAY_CHANNEL_ALI_APP_PAY = "appAliPay"; //支付宝App支付 + + public static final String WX_PAY_TRADE_TYPE_JS = "JSAPI"; + public static final String WX_PAY_TRADE_TYPE_H5 = "MWEB"; + + //微信支付接口请求地址 + public static final String WX_PAY_API_URL = "https://api.mch.weixin.qq.com/"; + // 微信统一预下单 + public static final String WX_PAY_API_URI = "pay/unifiedorder"; + // 微信查询订单 + public static final String WX_PAY_ORDER_QUERY_API_URI = "pay/orderquery"; + // 微信支付回调地址 + public static final String WX_PAY_NOTIFY_API_URI = "/api/admin/payment/callback/wechat"; + // 微信退款回调地址 + public static final String WX_PAY_REFUND_NOTIFY_API_URI = "/api/admin/payment/callback/wechat/refund"; + + public static final String WX_PAY_SIGN_TYPE_MD5 = "MD5"; + public static final String WX_PAY_SIGN_TYPE_SHA256 = "HMAC-SHA256"; + + public static final String PAY_BODY = "Crmeb支付中心-订单支付"; + public static final String FIELD_SIGN = "sign"; + + // 公共号退款 + public static final String WX_PAY_REFUND_API_URI= "secapi/pay/refund"; +} diff --git a/yudao-module-mall/yudao-module-shop-biz/src/main/java/cn/iocoder/yudao/module/shop/constants/WeChatConstants.java b/yudao-module-mall/yudao-module-shop-biz/src/main/java/cn/iocoder/yudao/module/shop/constants/WeChatConstants.java new file mode 100644 index 000000000..9ed8ee677 --- /dev/null +++ b/yudao-module-mall/yudao-module-shop-biz/src/main/java/cn/iocoder/yudao/module/shop/constants/WeChatConstants.java @@ -0,0 +1,387 @@ +package cn.iocoder.yudao.module.shop.constants; + +/** 微信配置 + * +---------------------------------------------------------------------- + * | CRMEB [ CRMEB赋能开发者,助力企业发展 ] + * +---------------------------------------------------------------------- + * | Copyright (c) 2016~2022 https://www.crmeb.com All rights reserved. + * +---------------------------------------------------------------------- + * | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权 + * +---------------------------------------------------------------------- + * | Author: CRMEB Team + * +---------------------------------------------------------------------- + */ +public class WeChatConstants { + + //-------------------------------------------微信系统配置------------------------------------------------------------ + /** 公众号appId key */ + public static final String WECHAT_PUBLIC_APPID = "wechat_appid"; + /** 公众号appSecret key */ + public static final String WECHAT_PUBLIC_APPSECRET = "wechat_appsecret"; + /** 小程序appId key */ + public static final String WECHAT_MINI_APPID = "routine_appid"; + // 小程序 名称 + public static final String WECHAT_MINI_NAME = "routine_name"; + /** 小程序appSecret key */ + public static final String WECHAT_MINI_APPSECRET = "routine_appsecret"; + + + + + + //------------------------------------------------微信公众号------------------------------------------------ + //微信接口请求地址 + public static final String API_URL = "https://api.weixin.qq.com/"; + //获取token + public static final String API_TOKEN_URI = "cgi-bin/token?grant_type=client_credential"; + // 微信token 过期时间,娶了一个中间值 4000 官方的7200不靠谱 + public static final Long API_TOKEN_EXPIRES = 3000L; + //微信公众号菜单创建 + public static final String PUBLIC_API_MENU_CREATE_URI = "cgi-bin/menu/create"; + //微信公众号菜单获取 + public static final String PUBLIC_API_MENU_GET_URI = "cgi-bin/menu/get"; + //微信公众号菜单删除 + public static final String PUBLIC_API_MENU_DELETE_URI = "cgi-bin/menu/delete"; + //微信公众号,获取自定义菜单配置接口 + public static final String PUBLIC_API_MENU_SELF_SET_URI = "cgi-bin/get_current_selfmenu_info"; + //微信公众号,创建个性化菜单 + public static final String PUBLIC_API_MENU_ADD_CONDITIONAL_URI = "cgi-bin/menu/addconditional"; + //微信公众号,删除个性化菜单 + public static final String PUBLIC_API_MENU_DEL_CONDITIONAL_URI = "cgi-bin/menu/delconditional"; + //微信公众号,测试个性化菜单匹配结果 + public static final String PUBLIC_API_USER_INFO_URI = "cgi-bin/menu/trymatch"; + //获取公众号已创建的标签 + public static final String PUBLIC_API_TAG_LIST_URI = "cgi-bin/tags/get"; + //创建标签 + public static final String PUBLIC_API_TAG_CREATE_URI = "cgi-bin/tags/create"; + //编辑标签 + public static final String PUBLIC_API_TAG_UPDATE_URI = "cgi-bin/tags/update"; + //删除标签 + public static final String PUBLIC_API_TAG_DELETE_URI = "cgi-bin/tags/delete"; + //获取标签下粉丝列表 + public static final String PUBLIC_API_TAG_USER_GET_URI = "cgi-bin/user/tag/get"; + //批量为用户打标签 + public static final String PUBLIC_API_TAG_MEMBER_BATCH_URI = "cgi-bin/tags/members/batchtagging"; + //批量为用户取消标签 + public static final String PUBLIC_API_TAG_MEMBER_BATCH_UN_URI = "cgi-bin/tags/members/batchuntagging"; + //获取用户身上的标签列表 + public static final String PUBLIC_API_TAG_GET_ID_LIST_URI = "cgi-bin/tags/getidlist"; + //获取 JsApiTicket + public static final String PUBLIC_API_JS_API_TICKET = "cgi-bin/ticket/getticket"; + //发送公众号模板消息 + public static final String PUBLIC_API_PUBLIC_TEMPLATE_MESSAGE_SEND = "cgi-bin/message/template/send"; + //获取设置的行业信息 + public static final String PUBLIC_API_TEMPLATE_MESSAGE_INDUSTRY = "cgi-bin/template/get_industry"; + //新增其他类型永久素材 + public static final String PUBLIC_API_MEDIA_UPLOAD = "cgi-bin/material/add_material"; + //获取永久素材 + public static final String PUBLIC_API_MEDIA_GET = "cgi-bin/material/get_material"; + //获取微信素材总数 + public static final String PUBLIC_API_MEDIA_COUNT = "cgi-bin/material/get_materialcount"; + //发送客服消息 + public static final String PUBLIC_API_KF_MESSAGE_SEND = "cgi-bin/message/custom/send"; + + + //------------------------------------------------微信小程序------------------------------------------------ + //小程序行业消息 + public static final String PUBLIC_API_PROGRAM_CATEGORY = "wxaapi/newtmpl/getcategory"; + //小程序公共模板库 + public static final String PUBLIC_API_PROGRAM_PUBLIC_TEMP = "wxaapi/newtmpl/getpubtemplatetitles"; + //小程序模板关键词列表 + public static final String PUBLIC_API_PROGRAM_PUBLIC_TEMP_KEYWORDS = "wxaapi/newtmpl/getpubtemplatekeywords"; + //添加小程序订阅消息 + public static final String PUBLIC_API_ADD_PROGRAM_TEMPLATE = "wxaapi/newtmpl/addtemplate"; + //删除小程序订阅消息 + public static final String PUBLIC_API_DELETE_PROGRAM_TEMPLATE = "wxaapi/newtmpl/deltemplate"; + //发送小程序模板消息 + public static final String PUBLIC_API_PROGRAM_TEMPLATE_MESSAGE_SEND = "cgi-bin/message/subscribe/send"; + + //授权登录 + + //获取临时code跳转地址 + public static final String WE_CHAT_AUTHORIZE_REDIRECT_URI_URL = "/api/front/wechat/authorize/login"; + + //获取openId + public static final String WE_CHAT_AUTHORIZE_GET_OPEN_ID = "sns/oauth2/access_token"; + + //获取小程序openId + public static final String WE_CHAT_AUTHORIZE_PROGRAM_GET_OPEN_ID = "sns/jscode2session"; + + //获取用户信息 + public static final String WE_CHAT_AUTHORIZE_GET_USER_INFO = "sns/userinfo"; + + //生成二维码 + public static final String WE_CHAT_CREATE_QRCODE = "wxa/getwxacodeunlimit"; + + //微信消息存储队列 + public static final String WE_CHAT_MESSAGE_SEND_KEY = "we_chat_message_send_list"; + + //大家注意这里消息类型的定义,以 RESP 开头的表示返回的消息类型,以 REQ 表示微信服务器发来的消息类型 + /** + * 返回消息类型:文本 + */ + public static final String WE_CHAT_MESSAGE_RESP_MESSAGE_TYPE_TEXT = "text"; + /** + * 返回消息类型:音乐 + */ + public static final String WE_CHAT_MESSAGE_RESP_MESSAGE_TYPE_MUSIC = "music"; + /** + * 返回消息类型:图文 + */ + public static final String WE_CHAT_MESSAGE_RESP_MESSAGE_TYPE_NEWS = "news"; + /** + * 返回消息类型:图片 + */ + public static final String WE_CHAT_MESSAGE_RESP_MESSAGE_TYPE_IMAGE = "image"; + /** + * 返回消息类型:语音 + */ + public static final String WE_CHAT_MESSAGE_RESP_MESSAGE_TYPE_VOICE = "voice"; + /** + * 返回消息类型:视频 + */ + public static final String WE_CHAT_MESSAGE_RESP_MESSAGE_TYPE_VIDEO = "video"; + /** + * 请求消息类型:文本 + */ + public static final String WE_CHAT_MESSAGE_REQ_MESSAGE_TYPE_TEXT = "text"; + /** + * 请求消息类型:图片 + */ + public static final String WE_CHAT_MESSAGE_REQ_MESSAGE_TYPE_IMAGE = "image"; + /** + * 请求消息类型:链接 + */ + public static final String WE_CHAT_MESSAGE_REQ_MESSAGE_TYPE_LINK = "link"; + /** + * 请求消息类型:地理位置 + */ + public static final String WE_CHAT_MESSAGE_REQ_MESSAGE_TYPE_LOCATION = "location"; + /** + * 请求消息类型:音频 + */ + public static final String WE_CHAT_MESSAGE_REQ_MESSAGE_TYPE_VOICE = "voice"; + /** + * 请求消息类型:视频 + */ + public static final String WE_CHAT_MESSAGE_REQ_MESSAGE_TYPE_VIDEO = "video"; + /** + * 请求消息类型:推送 + */ + public static final String WE_CHAT_MESSAGE_REQ_MESSAGE_TYPE_EVENT = "event"; + /** + * 事件类型:subscribe(订阅) + */ + public static final String WE_CHAT_MESSAGE_EVENT_TYPE_SUBSCRIBE = "subscribe"; + /** + * 事件类型:unsubscribe(取消订阅) + */ + public static final String WE_CHAT_MESSAGE_EVENT_TYPE_UNSUBSCRIBE = "unsubscribe"; + /** + * 事件类型:CLICK(自定义菜单点击事件) + */ + public static final String WE_CHAT_MESSAGE_EVENT_TYPE_CLICK = "click"; + /** + * 事件类型:VIEW(自定义菜单 URl 视图) + */ + public static final String WE_CHAT_MESSAGE_EVENT_TYPE_VIEW = "view"; + /** + * 事件类型:LOCATION(上报地理位置事件) + */ + public static final String WE_CHAT_MESSAGE_EVENT_TYPE_LOCATION = "LOCATION"; + /** + * 事件类型:LOCATION(上报地理位置事件) + */ + public static final String WE_CHAT_MESSAGE_EVENT_TYPE_SCAN = "SCAN"; + + //无效关键字key + public static final String WE_CHAT_MESSAGE_DEFAULT_CONTENT_KEY = "default"; + //Js sdk api 列表 + public static final String PUBLIC_API_JS_API_SDK_LIST = "openAddress,updateTimelineShareData,updateAppMessageShareData,onMenuShareTimeline,onMenuShareAppMessage,onMenuShareQQ,onMenuShareWeibo,onMenuShareQZone,startRecord,stopRecord,onVoiceRecordEnd,playVoice,pauseVoice,stopVoice,onVoicePlayEnd,uploadVoice,downloadVoice,chooseImage,previewImage,uploadImage,downloadImage,translateVoice,getNetworkType,openLocation,getLocation,hideOptionMenu,showOptionMenu,hideMenuItems,showMenuItems,hideAllNonBaseMenuItem,showAllNonBaseMenuItem,closeWindow,scanQRCode,chooseWXPay,openProductSpecificView,addCard,chooseCard,openCard"; + + + //token + public static final String REDIS_TOKEN_KEY = "wechat_token"; + public static final String REDIS_PROGRAM_TOKEN_KEY = "wechat_program_token"; + //tag + public static final String REDIS_TAGS_LIST_KEY = "wechat_tags_list"; + //user tag + public static final String REDIS_TAGS_LIST_USER_KEY = "wechat_tags_user_list"; + //微信菜单 + public static final String REDIS_PUBLIC_MENU_KEY = "wechat_public_menu_key"; + //微信自定义菜单 + public static final String REDIS_PUBLIC_MENU_SELF_KEY = "wechat_public_menu_self_key"; + + + + //授权请求地址 + public static final String WE_CHAT_AUTHORIZE_URL = "https://open.weixin.qq.com/connect/oauth2/authorize?appid={$appId}&redirect_uri={$redirectUri}&response_type=code&scope=snsapi_base&state=#wechat_redirect"; + + + //-------------------------------------------微信支付------------------------------------------------------------ + //微信支付接口请求地址 + public static final String PAY_API_URL = "https://api.mch.weixin.qq.com/"; + public static final String PAY_API_URI = "pay/unifiedorder"; + public static final String PAY_NOTIFY_API_URI_WECHAT = "/api/admin/payment/callback/wechat"; + // 公共号退款 + public static final String PAY_REFUND_API_URI_WECHAT = "secapi/pay/refund"; + + public static final String PAY_TYPE_JS = "JSAPI"; + public static final String PAY_TYPE_H5 = "MWEB"; + + // -------------------------------------------------------------------------------------------------------- + // 微信部分 + // -------------------------------------------------------------------------------------------------------- + + /** 获取accessToken的url */ + public static final String WECHAT_ACCESS_TOKEN_URL = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid={}&secret={}"; + /** 开放平台获取accessToken的url */ + public static final String WECHAT_OAUTH2_ACCESS_TOKEN_URL = "https://api.weixin.qq.com/sns/oauth2/access_token?appid={}&secret={}&code={}&grant_type=authorization_code"; + /** 开放平台获取用户的url */ + public static final String WECHAT_SNS_USERINFO_URL = "https://api.weixin.qq.com/sns/userinfo?access_token={}&openid={}&lang={}"; + + /** 公众号js-sdk获取ticket的url */ + public static final String WECHAT_PUBLIC_JS_TICKET_URL = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token={}&type=jsapi"; + /** 公众号发送模板消息的url */ + public static final String WECHAT_PUBLIC_SEND_TEMPLATE_URL = "https://api.weixin.qq.com/cgi-bin/message/template/send?access_token={}"; + /** 公众号获取自定义菜单配置的url */ + public static final String WECHAT_PUBLIC_MENU_GET_URL = "https://api.weixin.qq.com/cgi-bin/menu/get?access_token={}"; + /** 公众号创建自定义菜单的url */ + public static final String WECHAT_PUBLIC_MENU_CREATE_URL = "https://api.weixin.qq.com/cgi-bin/menu/create?access_token={}"; + /** 公众号删除自定义菜单的url */ + public static final String WECHAT_PUBLIC_MENU_DELETE_URL = "https://api.weixin.qq.com/cgi-bin/menu/delete?access_token={}"; + /** 企业号上传其他类型永久素材的url */ + public static final String WECHAT_PUBLIC_QYAPI_ADD_MATERIAL_URL = "https://qyapi.weixin.qq.com/cgi-bin/material/add_material?type={}&access_token={}"; + /** 公众号获取模板列表(自己的) */ + public static final String WECHAT_PUBLIC_GET_ALL_PRIVATE_TEMPLATE_URL = "https://api.weixin.qq.com/cgi-bin/template/get_all_private_template?access_token={}"; + /** 公众号删除模板(自己的) */ + public static final String WECHAT_PUBLIC_DEL_PRIVATE_TEMPLATE_URL = "https://api.weixin.qq.com/cgi-bin/template/del_private_template?access_token={}"; + /** 公众号添加模板(自己的) */ + public static final String WECHAT_PUBLIC_API_ADD_TEMPLATE_URL = "https://api.weixin.qq.com/cgi-bin/template/api_add_template?access_token={}"; + + + /** 小程序登录凭证校验的url */ + public static final String WECHAT_MINI_SNS_AUTH_CODE2SESSION_URL = "https://api.weixin.qq.com/sns/jscode2session?appid={}&secret={}&js_code={}&grant_type=authorization_code"; + /** 小程序生成小程序码的url */ + public static final String WECHAT_MINI_QRCODE_UNLIMITED_URL = "https://api.weixin.qq.com/wxa/getwxacodeunlimit?access_token={}"; + /** 小程序发送订阅消息的url */ + public static final String WECHAT_MINI_SEND_SUBSCRIBE_URL = "https://api.weixin.qq.com/cgi-bin/message/subscribe/send?access_token={}"; + /** 小程序获取订阅列表(自己的) */ + public static final String WECHAT_MINI_GET_ALL_PRIVATE_TEMPLATE_URL = "https://api.weixin.qq.com/wxaapi/newtmpl/gettemplate?access_token={}"; + /** 小程序删除模板(自己的) */ + public static final String WECHAT_MINI_DEL_PRIVATE_TEMPLATE_URL = "https://api.weixin.qq.com/wxaapi/newtmpl/deltemplate?access_token={}"; + /** 小程序获取订阅模板(小程序的) */ + public static final String WECHAT_MINI_GET_TEMPLATE_URL = "https://api.weixin.qq.com/wxaapi/newtmpl/getpubtemplatekeywords?access_token={}&tid={}"; + /** 公众号添加模板(自己的) */ + public static final String WECHAT_MINI_API_ADD_TEMPLATE_URL = "https://api.weixin.qq.com/wxaapi/newtmpl/addtemplate?access_token={}"; + + /** 小程序accessToken redis key */ + public static final String REDIS_WECAHT_MINI_ACCESS_TOKEN_KEY = "wechat_mini_accessToken"; + /** 公众号accessToken redis key */ + public static final String REDIS_WECAHT_PUBLIC_ACCESS_TOKEN_KEY = "wechat_public_accessToken"; + /** 公众号JsApiTicket redis key */ + public static final String REDIS_PUBLIC_JS_API_TICKET = "wechat_js_api_ticket"; + public static final Long REDIS_PUBLIC_JS_API_TICKET_EXPRESS = 7100L; + + /** + * -------------------------------------------------------------------------------------------------------- + * 以下为视频号相关部分 + * -------------------------------------------------------------------------------------------------------- + */ + + /*------------------------------------------ 申请接入接口 START ---------------------------------------*/ + + /* 申请接入申请 */ + public static final String WECHAT_SHOP_REGISTER_APPLY = "https://api.weixin.qq.com/shop/register/apply?access_token={}"; + /* 获取接入状态 */ + public static final String WECHAT_SHOP_REGISTER_CHECK = "https://api.weixin.qq.com/shop/register/check?access_token={}"; + + /*------------------------------------------ 申请接入接口 END ---------------------------------------*/ + + + /*------------------------------------------ 接入商品前必须接口 START ---------------------------------------*/ + /** 获取商品类目(自定义交易组件) */ + public static final String WECHAT_SHOP_CAT_GET_URL = "https://api.weixin.qq.com/shop/cat/get?access_token={}"; + /** 上传图片 **/ + public static final String WECHAT_SHOP_IMG_UPLOAD = "https://api.weixin.qq.com/shop/img/upload?&access_token={}"; + /** 上传品牌信息 */ + public static final String WECHAT_SHOP_AUDIT_AUDIT_BRAND = "https://api.weixin.qq.com/shop/audit/audit_brand?&access_token={}"; + /** 上传类目资质 */ + public static final String WECHAT_SHOP_AUDIT_AUDIT_CATEGORY = "https://api.weixin.qq.com/shop/audit/audit_category?&access_token={}"; + /** 查询类目审核结果 */ + public static final String WECHAT_SHOP_AUDIT_RESULT= "https://api.weixin.qq.com/shop/audit/result?access_token={}"; + /** 获取小程序提交过的入驻资质信息 */ + public static final String WECHAT_SHOP_AUDIT_GET_MINIAPP_CERTIFICATE= "https://api.weixin.qq.com/shop/audit/get_miniapp_certificate?access_token={}"; + /*------------------------------------------ 接入商品前必须接口 END ---------------------------------------*/ + + + /*------------------------------------------ 商家入驻接口 START ---------------------------------------*/ + /** 获取类目列表 */ + public static final String WECHAT_SHOP_ACCOUNT_GET_CATEGORY_LIST = "https://api.weixin.qq.com/shop/account/get_category_list?access_token={}"; + /** 获取品牌列表 */ + public static final String WECHAT_SHOP_ACCOUNT_GET_BRAND_LIST = "https://api.weixin.qq.com/shop/account/get_brand_list?access_token={}"; + /** 更新商家信息 */ + public static final String WECHAT_SHOP_ACCOUNT_UPDATE_INFO = "https://api.weixin.qq.com/shop/account/update_info?access_token={}"; + /** 获取商家信息 */ + public static final String WECHAT_SHOP_ACCOUNT_GET_INFO = "https://api.weixin.qq.com/shop/account/get_info?access_token={}"; + /*------------------------------------------ 商家入驻接口 END ---------------------------------------*/ + + /*------------------------------------------ SPU 接口 START ---------------------------------------*/ +// /** 获取品牌列表(自定义交易组件) */ +// public static final String WECHAT_SHOP_BRAND_GET_URL = "https://api.weixin.qq.com/shop/account/get_brand_list?access_token={}"; + /** 添加商品(自定义交易组件) */ + public static final String WECHAT_SHOP_SPU_ADD_URL = "https://api.weixin.qq.com/shop/spu/add?access_token={}"; + /** 删除商品(自定义交易组件) */ + public static final String WECHAT_SHOP_SPU_DEL_URL = "https://api.weixin.qq.com/shop/spu/del?access_token={}"; + /** 撤回商品审核(自定义交易组件) */ + public static final String WECHAT_SHOP_SPU_DEL_AUDIT_URL = "https://api.weixin.qq.com/shop/spu/del_audit?access_token={}"; + /** 获取商品(自定义交易组件) */ + public static final String WECHAT_SHOP_SPU_GET_URL = "https://api.weixin.qq.com/shop/spu/get?access_token={}"; + /** 获取商品列表(自定义交易组件) */ + public static final String WECHAT_SHOP_SPU_GET_LIST_URL = "https://api.weixin.qq.com/shop/spu/get_list?access_token={}"; + /** 更新商品(自定义交易组件) */ + public static final String WECHAT_SHOP_SPU_UPDATE_URL = "https://api.weixin.qq.com/shop/spu/update?access_token={}"; + /** 上架商品(自定义交易组件) */ + public static final String WECHAT_SHOP_SPU_LISTING_URL = "https://api.weixin.qq.com/shop/spu/listing?access_token={}"; + /** 下架商品(自定义交易组件) */ + public static final String WECHAT_SHOP_SPU_DELISTING_URL = "https://api.weixin.qq.com/shop/spu/delisting?access_token={}"; + /** 检查场景值是否在支付校验范围内(自定义交易组件) */ + public static final String WECHAT_SHOP_SCENE_CHECK_URL = "https://api.weixin.qq.com/shop/scene/check?access_token={}"; + /*------------------------------------------ SPU 接口 END ---------------------------------------*/ + + /*------------------------------------------ 订单 接口 START ---------------------------------------*/ + /** 生成订单并获取ticket(自定义交易组件) */ + public static final String WECHAT_SHOP_ORDER_ADD_URL = "https://api.weixin.qq.com/shop/order/add?access_token={}"; + /** 同步订单支付结果(自定义交易组件) */ + public static final String WECHAT_SHOP_ORDER_PAY_URL = "https://api.weixin.qq.com/shop/order/pay?access_token={}"; + /** 获取订单(自定义交易组件) */ + public static final String WECHAT_SHOP_ORDER_GET_URL = "https://api.weixin.qq.com/shop/order/get?access_token={}"; + /*------------------------------------------ 订单 接口 END ---------------------------------------*/ + + /*------------------------------------------ 物流 接口 START ---------------------------------------*/ + /** 获取快递公司列表(自定义交易组件) */ + public static final String WECHAT_SHOP_DELIVERY_GET_COMPANY_LIST_URL = "https://api.weixin.qq.com/shop/delivery/get_company_list?access_token={}"; + /** 订单发货(自定义交易组件) */ + public static final String WECHAT_SHOP_DELIVERY_SEND_URL = "https://api.weixin.qq.com/shop/delivery/send?access_token={}"; + /** 订单确认收货(自定义交易组件) */ + public static final String WECHAT_SHOP_DELIVERY_RECIEVE_URL = "https://api.weixin.qq.com/shop/delivery/recieve?access_token={}"; + /*------------------------------------------ 物流 接口 END ---------------------------------------*/ + + /*------------------------------------------ 售后 接口 START ---------------------------------------*/ + /** 创建售后(自定义交易组件) */ + public static final String WECHAT_SHOP_AFTERSALE_ADD_URL = "https://api.weixin.qq.com/shop/aftersale/add?access_token={}"; + /** 获取售后(自定义交易组件) */ + public static final String WECHAT_SHOP_AFTERSALE_GET_URL = "https://api.weixin.qq.com/shop/aftersale/get?access_token={}"; + /** 更新售后(自定义交易组件) */ + public static final String WECHAT_SHOP_AFTERSALE_UPDATE_URL = "https://api.weixin.qq.com/shop/aftersale/update?access_token={}"; + /*------------------------------------------ 售后 接口 END ---------------------------------------*/ + + + /** 自定义组件,商品类型 redis key */ + public static final String REDIS_WECHAT_SHOP_CAT_KEY = "wechat_shop_cat"; + + /** 微信小程序回调,商品审核回调事件 */ + public static final String WECAHT_CALLBACK_EVENT_SPU_AUDIT = "open_product_spu_audit"; + /** 微信小程序回调,品牌审核回调事件 */ + public static final String WECAHT_CALLBACK_EVENT_BRAND_AUDIT = "open_product_brand_audit"; +} diff --git a/yudao-module-mall/yudao-module-shop-biz/src/main/java/cn/iocoder/yudao/module/shop/controller/admin/order/vo/WxRefundResponseVo.java b/yudao-module-mall/yudao-module-shop-biz/src/main/java/cn/iocoder/yudao/module/shop/controller/admin/order/vo/WxRefundResponseVo.java new file mode 100644 index 000000000..4a9855def --- /dev/null +++ b/yudao-module-mall/yudao-module-shop-biz/src/main/java/cn/iocoder/yudao/module/shop/controller/admin/order/vo/WxRefundResponseVo.java @@ -0,0 +1,109 @@ +package cn.iocoder.yudao.module.shop.controller.admin.order.vo; + +import com.fasterxml.jackson.annotation.JsonProperty; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.experimental.Accessors; + +/** + * 微信退款返回对象 + * +---------------------------------------------------------------------- + * | CRMEB [ CRMEB赋能开发者,助力企业发展 ] + * +---------------------------------------------------------------------- + * | Copyright (c) 2016~2022 https://www.crmeb.com All rights reserved. + * +---------------------------------------------------------------------- + * | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权 + * +---------------------------------------------------------------------- + * | Author: CRMEB Team + * +---------------------------------------------------------------------- + */ +@Data +@EqualsAndHashCode(callSuper = false) +@Accessors(chain = true) +@Schema(description="微信退款返回对象") +public class WxRefundResponseVo { + @Schema(description = "SUCCESS/FAIL此字段是通信标识,非交易标识,交易是否成功需要查看trade_state来判断") + @JsonProperty(value = "return_code") + private String returnCode; + + @Schema(description = "当return_code为FAIL时返回信息为错误原因 ,例如 签名失败 参数格式校验错误") + @JsonProperty(value = "return_msg") + private String returnMsg; + + @Schema(description = "SUCCESS/FAIL 业务结果") + @JsonProperty(value = "result_code") + private String resultCode; + + @Schema(description = "详细参见错误列表") + @JsonProperty(value = "err_code") + private String errCode; + + @Schema(description = "错误返回的信息描述") + @JsonProperty(value = "err_code_des") + private String errCodeDes; + + @Schema(description = "调用接口提交的公众账号ID") + @JsonProperty(value = "appid") + private String appId; + + @Schema(description = "调用接口提交的商户号") + @JsonProperty(value = "mch_id") + private String mchId; + + @Schema(description = "微信返回的随机字符串") + @JsonProperty(value = "nonce_str") + private String nonceStr; + + @Schema(description = "微信返回的签名") + private String sign; + + @Schema(description = "微信支付订单号") + @JsonProperty(value = "transaction_id") + private String transactionId; + + @Schema(description = "商户系统内部的订单号,32个字符内、可包含字母, 其他说明见商户订单号", required = true) + @JsonProperty(value = "out_trade_no") + private String outTradeNo; + + @Schema(description = "商户退款单号,同一退款单号多次请求只退一笔。") + @JsonProperty(value = "out_refund_no") + private String outRefundNo; + + @Schema(description = "微信退款单号") + @JsonProperty(value = "refund_id") + private String refundId; + + @Schema(description = "退款总金额,单位为分,可以做部分退款") + @JsonProperty(value = "refund_fee") + private Integer refundFee; + + @Schema(description = "应结退款金额") + @JsonProperty(value = "settlement_refund_fee") + private Integer settlementRefundFee; + + @Schema(description = "标价金额") + @JsonProperty(value = "total_fee") + private Integer totalFee; + + @Schema(description = "应结订单金额") + @JsonProperty(value = "settlement_total_fee") + private Integer settlementTotalFee; + + @Schema(description = "标价币种,订单金额货币类型,符合ISO 4217标准的三位字母代码,默认人民币:CNY,其他值列表详见货币类型") + @JsonProperty(value = "fee_type") + private String feeType; + + @Schema(description = "现金支付金额") + @JsonProperty(value = "cash_fee") + private Integer cashFee; + + @Schema(description = "现金支付币种,订单金额货币类型,符合ISO 4217标准的三位字母代码,默认人民币:CNY,其他值列表详见货币类型") + @JsonProperty(value = "cash_fee_type") + private String cashFeeType; + + @Schema(description = "现金退款金额") + @JsonProperty(value = "cash_refund_fee") + private Integer cashRefundFee; + +} diff --git a/yudao-module-mall/yudao-module-shop-biz/src/main/java/cn/iocoder/yudao/module/shop/controller/admin/order/vo/WxRefundVo.java b/yudao-module-mall/yudao-module-shop-biz/src/main/java/cn/iocoder/yudao/module/shop/controller/admin/order/vo/WxRefundVo.java new file mode 100644 index 000000000..0eb2d2d8a --- /dev/null +++ b/yudao-module-mall/yudao-module-shop-biz/src/main/java/cn/iocoder/yudao/module/shop/controller/admin/order/vo/WxRefundVo.java @@ -0,0 +1,64 @@ + +package cn.iocoder.yudao.module.shop.controller.admin.order.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.experimental.Accessors; + +/** + * 调用微信退款所需要的参数 + * +---------------------------------------------------------------------- + * | CRMEB [ CRMEB赋能开发者,助力企业发展 ] + * +---------------------------------------------------------------------- + * | Copyright (c) 2016~2022 https://www.crmeb.com All rights reserved. + * +---------------------------------------------------------------------- + * | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权 + * +---------------------------------------------------------------------- + * | Author: CRMEB Team + * +---------------------------------------------------------------------- + */ +@Data +@EqualsAndHashCode(callSuper = false) +@Accessors(chain = true) +@Schema(description="调用微信退款所需要的参数") +public class WxRefundVo { + + @Schema(description = "appId,公众号名称,由商户传入", required = true) + private String appid; + + @Schema(description = "直连商户的商户号,由微信支付生成并下发", required = true) + private String mch_id; + + @Schema(description = "随机字符串,不长于32位", required = true) + private String nonce_str; + + @Schema(description = "签名", required = true) + private String sign; + + @Schema(description = "签名类型,目前支持HMAC-SHA256和MD5,默认为MD5") + private String sign_type = "MD5"; + + @Schema(description = "微信支付订单号:微信生成的订单号,在支付通知中有返回") + private String transaction_id; + + @Schema(description = "商户系统内部的订单号,32个字符内、可包含字母, 其他说明见商户订单号", required = true) + private String out_trade_no; + + @Schema(description = "商户退款单号,同一退款单号多次请求只退一笔。") + private String out_refund_no; + + @Schema(description = "订单总金额,单位为分", required = true) + private int total_fee; + + @Schema(description = "退款金额,单位为分", required = true) + private int refund_fee; + + @Schema(description = "退款货币种类:符合ISO 4217标准的三位字母代码,默认人民币:CNY,其他值列表详见货币类型") + private String refund_fee_type = "CNY"; + + @Schema(description = "退款结果通知url") + private String notify_url; + +} + diff --git a/yudao-module-mall/yudao-module-shop-biz/src/main/java/cn/iocoder/yudao/module/shop/service/order/StoreOrderService.java b/yudao-module-mall/yudao-module-shop-biz/src/main/java/cn/iocoder/yudao/module/shop/service/order/StoreOrderService.java index afe7665a4..ce078009b 100644 --- a/yudao-module-mall/yudao-module-shop-biz/src/main/java/cn/iocoder/yudao/module/shop/service/order/StoreOrderService.java +++ b/yudao-module-mall/yudao-module-shop-biz/src/main/java/cn/iocoder/yudao/module/shop/service/order/StoreOrderService.java @@ -75,7 +75,7 @@ public interface StoreOrderService extends IService { * @param status 状态参数 * @return 查询到的订单结果 */ - Integer getTopDataUtil(Integer status, Integer userId); + Long getTopDataUtil(Integer status, Integer userId); List getOrderGroupByDate(String dateLimit, int lefTime); @@ -195,7 +195,7 @@ public interface StoreOrderService extends IService { * @param uid 用户uid * @return Integer */ - Integer getOrderCountByUid(Integer uid); + Long getOrderCountByUid(Integer uid); /** * 获取用户总消费金额 @@ -209,7 +209,7 @@ public interface StoreOrderService extends IService { * @param uid 用户uid * @return Integer */ - Integer getOrderCountByUidAndDate(Integer uid, String date); + Long getOrderCountByUidAndDate(Integer uid, String date); /** * 获取用户消费金额(时间) @@ -267,14 +267,14 @@ public interface StoreOrderService extends IService { * @param date 日期,yyyy-MM-dd格式 * @return Integer */ - Integer getOrderNumByDate(String date); + Long getOrderNumByDate(String date); /** * 通过日期获取支付订单数量 * @param date 日期,yyyy-MM-dd格式 * @return Integer */ - Integer getPayOrderNumByDate(String date); + Long getPayOrderNumByDate(String date); /** * 通过日期获取支付订单金额 @@ -352,17 +352,17 @@ public interface StoreOrderService extends IService { * 获取待发货订单数量 * @return Integer */ - Integer getNotShippingNum(); + Long getNotShippingNum(); /** * 获取退款中订单数量 */ - Integer getRefundingNum(); + Long getRefundingNum(); /** * 获取待核销订单数量 */ - Integer getNotWriteOffNum(); + Long getNotWriteOffNum(); /** * 获取佣金相关数据 diff --git a/yudao-module-mall/yudao-module-shop-biz/src/main/java/cn/iocoder/yudao/module/shop/service/order/StoreOrderStatusService.java b/yudao-module-mall/yudao-module-shop-biz/src/main/java/cn/iocoder/yudao/module/shop/service/order/StoreOrderStatusService.java index 1d7fbbddd..17ea221bc 100644 --- a/yudao-module-mall/yudao-module-shop-biz/src/main/java/cn/iocoder/yudao/module/shop/service/order/StoreOrderStatusService.java +++ b/yudao-module-mall/yudao-module-shop-biz/src/main/java/cn/iocoder/yudao/module/shop/service/order/StoreOrderStatusService.java @@ -68,7 +68,7 @@ public interface StoreOrderStatusService extends IService { * @param date 日期,yyyy-MM-dd格式 * @return Integer */ - Integer getRefundOrderNumByDate(String date); + Long getRefundOrderNumByDate(String date); /** * 通过日期获取订单退款金额 diff --git a/yudao-module-mall/yudao-module-shop-biz/src/main/java/cn/iocoder/yudao/module/shop/service/order/impl/StoreOrderInfoServiceImpl.java b/yudao-module-mall/yudao-module-shop-biz/src/main/java/cn/iocoder/yudao/module/shop/service/order/impl/StoreOrderInfoServiceImpl.java index 06432d655..eca336b87 100644 --- a/yudao-module-mall/yudao-module-shop-biz/src/main/java/cn/iocoder/yudao/module/shop/service/order/impl/StoreOrderInfoServiceImpl.java +++ b/yudao-module-mall/yudao-module-shop-biz/src/main/java/cn/iocoder/yudao/module/shop/service/order/impl/StoreOrderInfoServiceImpl.java @@ -3,12 +3,21 @@ package cn.iocoder.yudao.module.shop.service.order.impl; import cn.iocoder.yudao.module.shop.dal.dataobject.order.StoreOrderInfo; import cn.iocoder.yudao.module.shop.dal.mysql.order.StoreOrderInfoMapper; import cn.iocoder.yudao.module.shop.service.order.StoreOrderInfoService; +import cn.iocoder.yudao.module.shop.service.product.StoreProductReplyService; +import cn.iocoder.yudao.module.shop.vo.order.OrderInfoDetailVo; import cn.iocoder.yudao.module.shop.vo.order.StoreOrderInfoOldVo; import cn.iocoder.yudao.module.shop.vo.order.StoreOrderInfoVo; +import com.alibaba.fastjson.JSON; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import org.springframework.beans.BeanUtils; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; +import javax.annotation.Resource; import java.math.BigDecimal; +import java.util.ArrayList; import java.util.HashMap; import java.util.List; @@ -27,15 +36,61 @@ import java.util.List; @Service public class StoreOrderInfoServiceImpl extends ServiceImpl implements StoreOrderInfoService { + @Resource + private StoreOrderInfoMapper mapper; + + @Autowired + private StoreProductReplyService storeProductReplyService; @Override public HashMap> getMapInId(List orderIdList) { - return null; + HashMap> map = new HashMap<>(); + if(orderIdList.size() < 1){ + return map; + } + LambdaQueryWrapper lambdaQueryWrapper = Wrappers.lambdaQuery(); + lambdaQueryWrapper.in(StoreOrderInfo::getOrderId, orderIdList); + List systemStoreStaffList = mapper.selectList(lambdaQueryWrapper); + if(systemStoreStaffList.size() < 1){ + return map; + } + for (StoreOrderInfo storeOrderInfo : systemStoreStaffList) { + //解析商品详情JSON + StoreOrderInfoOldVo StoreOrderInfoVo = new StoreOrderInfoOldVo(); + BeanUtils.copyProperties(storeOrderInfo, StoreOrderInfoVo, "info"); + StoreOrderInfoVo.setInfo(JSON.parseObject(storeOrderInfo.getInfo(), OrderInfoDetailVo.class)); + if(map.containsKey(storeOrderInfo.getOrderId())){ + map.get(storeOrderInfo.getOrderId()).add(StoreOrderInfoVo); + }else{ + List storeOrderInfoVoList = new ArrayList<>(); + storeOrderInfoVoList.add(StoreOrderInfoVo); + map.put(storeOrderInfo.getOrderId(), storeOrderInfoVoList); + } + } + return map; } @Override public List getOrderListByOrderId(Integer orderId) { - return null; + LambdaQueryWrapper lambdaQueryWrapper = new LambdaQueryWrapper<>(); + lambdaQueryWrapper.eq(StoreOrderInfo::getOrderId, orderId); + List systemStoreStaffList = mapper.selectList(lambdaQueryWrapper); + if(systemStoreStaffList.size() < 1){ + return null; + } + + List storeOrderInfoVoList = new ArrayList<>(); + for (StoreOrderInfo storeOrderInfo : systemStoreStaffList) { + //解析商品详情JSON + StoreOrderInfoOldVo storeOrderInfoVo = new StoreOrderInfoOldVo(); + BeanUtils.copyProperties(storeOrderInfo, storeOrderInfoVo, "info"); + storeOrderInfoVo.setInfo(JSON.parseObject(storeOrderInfo.getInfo(), OrderInfoDetailVo.class)); + storeOrderInfoVo.getInfo().setIsReply( + storeProductReplyService.isReply(storeOrderInfoVo.getUnique(), storeOrderInfoVo.getOrderId()) ? 1 : 0 + ); + storeOrderInfoVoList.add(storeOrderInfoVo); + } + return storeOrderInfoVoList; } /** @@ -46,7 +101,7 @@ public class StoreOrderInfoServiceImpl extends ServiceImpl storeOrderInfos) { - return false; + return saveBatch(storeOrderInfos); } /** @@ -58,7 +113,11 @@ public class StoreOrderInfoServiceImpl extends ServiceImpl lambdaQueryWrapper = new LambdaQueryWrapper<>(); + lambdaQueryWrapper.eq(StoreOrderInfo::getOrderId, orderId); + lambdaQueryWrapper.eq(StoreOrderInfo::getUnique, uni); + return mapper.selectOne(lambdaQueryWrapper); } /** @@ -69,7 +128,22 @@ public class StoreOrderInfoServiceImpl extends ServiceImpl getVoListByOrderId(Integer orderId) { - return null; + LambdaQueryWrapper lambdaQueryWrapper = new LambdaQueryWrapper<>(); + lambdaQueryWrapper.eq(StoreOrderInfo::getOrderId, orderId); + List systemStoreStaffList = mapper.selectList(lambdaQueryWrapper); + if(systemStoreStaffList.size() < 1){ + return null; + } + + List storeOrderInfoVoList = new ArrayList<>(); + for (StoreOrderInfo storeOrderInfo : systemStoreStaffList) { + //解析商品详情JSON + StoreOrderInfoVo storeOrderInfoVo = new StoreOrderInfoVo(); + BeanUtils.copyProperties(storeOrderInfo, storeOrderInfoVo, "info"); + storeOrderInfoVo.setInfo(JSON.parseObject(storeOrderInfo.getInfo(), OrderInfoDetailVo.class)); + storeOrderInfoVoList.add(storeOrderInfoVo); + } + return storeOrderInfoVoList; } /** @@ -80,7 +154,9 @@ public class StoreOrderInfoServiceImpl extends ServiceImpl getListByOrderNo(String orderNo) { - return null; + LambdaQueryWrapper lqw = Wrappers.lambdaQuery(); + lqw.eq(StoreOrderInfo::getOrderNo, orderNo); + return mapper.selectList(lqw); } /** @@ -92,7 +168,7 @@ public class StoreOrderInfoServiceImpl extends ServiceImpl implements StoreOrderRefundService { + @Autowired + private ApiConfigApi apiConfigApi; + + @Autowired + private WechatNewService wechatNewService; @Override public void refund(StoreOrderRefundRequest request, StoreOrder storeOrder) { - + refundWx(request, storeOrder); } + + /** + * 公共号退款 + * @param request + * @param storeOrder + */ + private void refundWx(StoreOrderRefundRequest request, StoreOrder storeOrder) { + // 获取appid、mch_id + // 微信签名key + String appId = ""; + String mchId = ""; + String signKey = ""; + String path = ""; + if (storeOrder.getIsChannel() == 0) {// 公众号 + appId = apiConfigApi.getConfigKey(Constants.CONFIG_KEY_PAY_WE_CHAT_APP_ID).toString(); + mchId = apiConfigApi.getConfigKey(Constants.CONFIG_KEY_PAY_WE_CHAT_MCH_ID).toString(); + signKey = apiConfigApi.getConfigKey(Constants.CONFIG_KEY_PAY_WE_CHAT_APP_KEY).toString(); +// path = systemConfigService.getValueByKeyException("pay_routine_client_p12"); + path = apiConfigApi.getConfigKey("pay_weixin_certificate_path").toString(); + } + if (storeOrder.getIsChannel() == 1) {// 小程序 + appId = apiConfigApi.getConfigKey(Constants.CONFIG_KEY_PAY_ROUTINE_APP_ID).toString(); + mchId = apiConfigApi.getConfigKey(Constants.CONFIG_KEY_PAY_ROUTINE_MCH_ID).toString(); + signKey = apiConfigApi.getConfigKey(Constants.CONFIG_KEY_PAY_ROUTINE_APP_KEY).toString(); +// path = systemConfigService.getValueByKeyException("pay_mini_client_p12"); + path = apiConfigApi.getConfigKey("pay_routine_certificate_path").toString(); + } + if (storeOrder.getIsChannel() == 2) {// H5, 使用公众号的 + appId = apiConfigApi.getConfigKey(Constants.CONFIG_KEY_PAY_WE_CHAT_APP_ID).toString(); + mchId = apiConfigApi.getConfigKey(Constants.CONFIG_KEY_PAY_WE_CHAT_MCH_ID).toString(); + signKey = apiConfigApi.getConfigKey(Constants.CONFIG_KEY_PAY_WE_CHAT_APP_KEY).toString(); +// path = systemConfigService.getValueByKeyException("pay_mini_client_p12"); + path = apiConfigApi.getConfigKey("pay_weixin_certificate_path").toString(); + } + + String apiDomain = apiConfigApi.getConfigKey(Constants.CONFIG_KEY_API_URL).toString(); + + //统一下单数据 + WxRefundVo wxRefundVo = new WxRefundVo(); + wxRefundVo.setAppid(appId); + wxRefundVo.setMch_id(mchId); + wxRefundVo.setNonce_str(WxPayUtil.getNonceStr()); + wxRefundVo.setOut_trade_no(storeOrder.getOutTradeNo()); + wxRefundVo.setOut_refund_no(storeOrder.getOrderId()); + wxRefundVo.setTotal_fee(storeOrder.getPayPrice().multiply(BigDecimal.TEN).multiply(BigDecimal.TEN).intValue()); + wxRefundVo.setRefund_fee(request.getAmount().multiply(BigDecimal.TEN).multiply(BigDecimal.TEN).intValue()); + wxRefundVo.setNotify_url(apiDomain + PayConstants.WX_PAY_REFUND_NOTIFY_API_URI); + String sign = WxPayUtil.getSign(wxRefundVo, signKey); + wxRefundVo.setSign(sign); + + wechatNewService.payRefund(wxRefundVo, path); + } + + + } diff --git a/yudao-module-mall/yudao-module-shop-biz/src/main/java/cn/iocoder/yudao/module/shop/service/order/impl/StoreOrderServiceImpl.java b/yudao-module-mall/yudao-module-shop-biz/src/main/java/cn/iocoder/yudao/module/shop/service/order/impl/StoreOrderServiceImpl.java index 9a5c18b5e..3954999a3 100644 --- a/yudao-module-mall/yudao-module-shop-biz/src/main/java/cn/iocoder/yudao/module/shop/service/order/impl/StoreOrderServiceImpl.java +++ b/yudao-module-mall/yudao-module-shop-biz/src/main/java/cn/iocoder/yudao/module/shop/service/order/impl/StoreOrderServiceImpl.java @@ -1,21 +1,55 @@ package cn.iocoder.yudao.module.shop.service.order.impl; +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.ObjectUtil; +import cn.hutool.core.util.PhoneUtil; +import cn.hutool.core.util.StrUtil; +import cn.iocoder.yudao.framework.common.enums.Constants; +import cn.iocoder.yudao.framework.common.exception.ServiceException; +import cn.iocoder.yudao.framework.common.pojo.DateLimitUtilVo; import cn.iocoder.yudao.framework.common.pojo.PageParam; +import cn.iocoder.yudao.framework.common.util.date.DateUtils; +import cn.iocoder.yudao.module.member.dal.dataobject.user.MemberUserDO; +import cn.iocoder.yudao.module.member.service.user.MemberUserService; import cn.iocoder.yudao.module.shop.dal.dataobject.order.StoreOrder; import cn.iocoder.yudao.module.shop.dal.mysql.order.StoreOrderMapper; import cn.iocoder.yudao.module.shop.request.order.StoreOrderRefundRequest; import cn.iocoder.yudao.module.shop.request.order.StoreOrderSearchRequest; import cn.iocoder.yudao.module.shop.request.order.StoreOrderSendRequest; import cn.iocoder.yudao.module.shop.request.order.StoreOrderUpdatePriceRequest; -import cn.iocoder.yudao.module.shop.service.order.StoreOrderService; import cn.iocoder.yudao.module.shop.response.order.*; +import cn.iocoder.yudao.module.shop.service.order.StoreOrderInfoService; +import cn.iocoder.yudao.module.shop.service.order.StoreOrderRefundService; +import cn.iocoder.yudao.module.shop.service.order.StoreOrderService; +import cn.iocoder.yudao.module.shop.service.order.StoreOrderStatusService; +import cn.iocoder.yudao.module.shop.utils.CommonPage; +import cn.iocoder.yudao.module.shop.utils.OrderUtils; +import cn.iocoder.yudao.module.shop.utils.RedisUtil; import cn.iocoder.yudao.module.shop.vo.order.LogisticsResultVo; +import cn.iocoder.yudao.module.shop.vo.order.StoreDateRangeSqlPram; +import cn.iocoder.yudao.module.shop.vo.order.StoreOrderInfoOldVo; +import cn.iocoder.yudao.module.system.service.sms.SmsTemplateService; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.github.pagehelper.Page; +import com.github.pagehelper.PageHelper; import com.github.pagehelper.PageInfo; +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.BeanUtils; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; +import org.springframework.transaction.support.TransactionTemplate; +import javax.annotation.Resource; import java.math.BigDecimal; -import java.util.*; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; /** * StoreOrderServiceImpl 接口实现 @@ -32,6 +66,35 @@ import java.util.*; @Service public class StoreOrderServiceImpl extends ServiceImpl implements StoreOrderService { + @Resource + private StoreOrderMapper mapper; + + @Autowired + private StoreOrderInfoService StoreOrderInfoService; + + @Autowired + private MemberUserService userService; + + @Autowired + private StoreOrderStatusService storeOrderStatusService; + + @Autowired + private StoreOrderRefundService storeOrderRefundService; + + @Autowired + private OrderUtils orderUtils; + + @Autowired + private RedisUtil redisUtil; + + @Autowired + private TransactionTemplate transactionTemplate; + + @Autowired + private StoreOrderInfoService storeOrderInfoService; + + @Autowired + private SmsTemplateService smsTemplateService; /** * 列表(PC) @@ -42,7 +105,26 @@ public class StoreOrderServiceImpl extends ServiceImpl getAdminList(StoreOrderSearchRequest request, PageParam pageParamRequest) { - return null; + Page startPage = PageHelper.startPage(pageParamRequest.getPageNo(), pageParamRequest.getPageSize()); + QueryWrapper queryWrapper = new QueryWrapper<>(); + queryWrapper.select("id", "order_id", "uid", "real_name", "pay_price", "pay_type", "create_time", "status", "refund_status" + , "refund_reason_wap_img", "refund_reason_wap_explain", "refund_reason_wap", "refund_reason", "refund_reason_time" + , "is_del", "combination_id", "pink_id", "seckill_id", "bargain_id", "verify_code", "remark", "paid", "is_system_del", "shipping_type", "type", "is_alter_price"); + if (StrUtil.isNotBlank(request.getOrderNo())) { + queryWrapper.eq("order_id", request.getOrderNo()); + } + getRequestTimeWhere(queryWrapper, request); + getStatusWhere(queryWrapper, request.getStatus()); + if (!request.getType().equals(2)) { + queryWrapper.eq("type", request.getType()); + } + queryWrapper.orderByDesc("id"); + List orderList = mapper.selectList(queryWrapper); + List detailResponseList = new ArrayList<>(); + if (CollUtil.isNotEmpty(orderList)) { + detailResponseList = formatOrder1(orderList); + } + return CommonPage.copyPageInfo(startPage, detailResponseList); } /** @@ -56,7 +138,22 @@ public class StoreOrderServiceImpl extends ServiceImpl queryWrapper = new QueryWrapper<>(); + queryWrapper.select("sum(pay_price) as pay_price"). + eq("paid", 1). + eq("is_del", 0); + if (null != userId) { + queryWrapper.eq("uid", userId); + } + if (null != date) { + DateLimitUtilVo dateLimit = DateUtils.getDateLimit(date); + queryWrapper.between("create_time", dateLimit.getStartTime(), dateLimit.getEndTime()); + } + StoreOrder storeOrder = mapper.selectOne(queryWrapper); + if (null == storeOrder || null == storeOrder.getPayPrice()) { + return BigDecimal.ZERO; + } + return storeOrder.getPayPrice(); } /** @@ -69,7 +166,12 @@ public class StoreOrderServiceImpl extends ServiceImpl getUserOrderList(Integer uid, Integer status, PageParam pageParamRequest) { - return null; + PageHelper.startPage(pageParamRequest.getPageNo(), pageParamRequest.getPageSize()); + LambdaQueryWrapper lqw = new LambdaQueryWrapper<>(); + orderUtils.statusApiByWhere(lqw, status); + lqw.eq(StoreOrder::getUid, uid); + lqw.orderByDesc(StoreOrder::getId); + return mapper.selectList(lqw); } /** @@ -80,7 +182,7 @@ public class StoreOrderServiceImpl extends ServiceImpl 0; } /** @@ -91,7 +193,9 @@ public class StoreOrderServiceImpl extends ServiceImpl lqw = new LambdaQueryWrapper<>(); + lqw.setEntity(storeOrder); + return mapper.selectOne(lqw); } /** @@ -102,18 +206,76 @@ public class StoreOrderServiceImpl extends ServiceImpl lqw = new LambdaQueryWrapper<>(); + orderUtils.statusApiByWhere(lqw, status); + lqw.eq(StoreOrder::getUid,userId); + return mapper.selectCount(lqw); } @Override public List getOrderGroupByDate(String dateLimit, int lefTime) { - return null; + QueryWrapper queryWrapper = new QueryWrapper<>(); + queryWrapper.select("sum(pay_price) as pay_price", "left(create_time, "+lefTime+") as orderId", "count(id) as id"); + if (StringUtils.isNotBlank(dateLimit)) { + DateLimitUtilVo dateLimitVo = DateUtils.getDateLimit(dateLimit); + queryWrapper.between("create_time", dateLimitVo.getStartTime(), dateLimitVo.getEndTime()); + } + queryWrapper.groupBy("orderId").orderByAsc("orderId"); + return mapper.selectList(queryWrapper); } @Override public boolean refund(StoreOrderRefundRequest request) { - return false; + StoreOrder storeOrder = getInfoException(request.getOrderNo()); + if (!storeOrder.getPaid()) { + throw new ServiceException("未支付无法退款"); + } + if (storeOrder.getRefundPrice().add(request.getAmount()).compareTo(storeOrder.getPayPrice()) > 0) { + throw new ServiceException("退款金额大于支付金额,请修改退款金额"); + } + if (request.getAmount().compareTo(BigDecimal.ZERO) <= 0) { + if (storeOrder.getPayPrice().compareTo(BigDecimal.ZERO) != 0) { + throw new ServiceException("退款金额不能为0,请修改退款金额"); + } + } + request.setOrderId(storeOrder.getId()); + //用户 + MemberUserDO user = userService.getUser(storeOrder.getUid()); + + //退款 + if (storeOrder.getPayType().equals(Constants.PAY_TYPE_WE_CHAT) && request.getAmount().compareTo(BigDecimal.ZERO) > 0) { + try { + storeOrderRefundService.refund(request, storeOrder); + } catch (Exception e) { + e.printStackTrace(); + throw new ServiceException("微信申请退款失败!"); + } + } + + //修改订单退款状态 + storeOrder.setRefundStatus(3); + storeOrder.setRefundPrice(request.getAmount()); + + Boolean execute = transactionTemplate.execute(e -> { + updateById(storeOrder); + if (storeOrder.getPayType().equals(Constants.PAY_TYPE_YUE)) { + // 退款task + redisUtil.lPush(Constants.ORDER_TASK_REDIS_KEY_AFTER_REFUND_BY_USER, storeOrder.getId()); + } + if (storeOrder.getPayType().equals(Constants.PAY_TYPE_WE_CHAT) && request.getAmount().compareTo(BigDecimal.ZERO) == 0) { + // 退款task + redisUtil.lPush(Constants.ORDER_TASK_REDIS_KEY_AFTER_REFUND_BY_USER, storeOrder.getId()); + } + return Boolean.TRUE; + }); + if (!execute) { + storeOrderStatusService.saveRefund(storeOrder.getId(), request.getAmount(), "失败"); + throw new ServiceException("订单更新失败"); + } + + // 发送消息通知 + return execute; } /** @@ -124,12 +286,59 @@ public class StoreOrderServiceImpl extends ServiceImpl orderInfos = StoreOrderInfoService.getOrderListByOrderId(storeOrder.getId()); + storeOrderInfoResponse.setOrderInfo(orderInfos); + storeOrderInfoResponse.setPayTypeStr(getPayType(storeOrder.getPayType())); + storeOrderInfoResponse.setStatusStr(getStatus(storeOrder)); +// if (ObjectUtil.isNotNull(storeOrder.getStoreId()) && storeOrder.getStoreId() > 0) { +// SystemStore systemStorePram = new SystemStore(); +// systemStorePram.setId(storeOrder.getStoreId()); +// storeOrderInfoResponse.setSystemStore(systemStoreService.getByCondition(systemStorePram)); +// } + + //用户信息 + MemberUserDO user = userService.getUser(storeOrder.getUid()); + storeOrderInfoResponse.setNikeName(user.getNickname()); + storeOrderInfoResponse.setPhone(user.getMobile()); + + //佣金 +// UserBrokerageRecord brokerageRecord = userBrokerageRecordService.getByLinkIdAndLinkType(orderNo, "order"); +// if (ObjectUtil.isNotNull(brokerageRecord)) { +// MemberUserDO spread = userService.getUser(brokerageRecord.getUid()); +// storeOrderInfoResponse.setSpreadName(spread.getNickname()); +// } + + storeOrderInfoResponse.setProTotalPrice(storeOrder.getTotalPrice().subtract(storeOrder.getTotalPostage())); + return storeOrderInfoResponse; } @Override public Boolean send(StoreOrderSendRequest request) { - return null; + //订单信息 + StoreOrder storeOrder = getInfoException(request.getOrderNo()); + if (storeOrder.getIsDel()) throw new ServiceException("订单已删除,不能发货!"); + if (storeOrder.getStatus() > 0) throw new ServiceException("订单已发货请勿重复操作!"); + request.setId(storeOrder.getId()); + switch (request.getType()) { + case "1":// 发货 + express(request, storeOrder); + break; + case "2":// 送货 + delivery(request, storeOrder); + break; + case "3":// 虚拟 + virtual(request, storeOrder); + break; + default: + throw new ServiceException("类型错误"); + } + return true; } /** @@ -141,7 +350,9 @@ public class StoreOrderServiceImpl extends ServiceImpl { + updateById(storeOrder); + storeOrderStatusService.createLog(storeOrder.getId(), Constants.ORDER_LOG_REFUND_REFUSE, Constants.ORDER_LOG_MESSAGE_REFUND_REFUSE.replace("{reason}", reason)); + return Boolean.TRUE; + }); + return execute; } @Override public StoreOrder getInfoByEntity(StoreOrder storeOrder) { - return null; + LambdaQueryWrapper lambdaQueryWrapper = new LambdaQueryWrapper<>(); + lambdaQueryWrapper.setEntity(storeOrder); + return mapper.selectOne(lambdaQueryWrapper); } /** @@ -169,6 +396,17 @@ public class StoreOrderServiceImpl extends ServiceImpl orderPerList = getOrderPayedByDateLimit(perDateStart,dateStart); + + // 当前时间段 + List orderCurrentList = getOrderPayedByDateLimit(dateStart, dateEnd); + double increasePrice = 0; + if (type == 1) { + double perSumPrice = orderPerList.stream().mapToDouble(e -> e.getPayPrice().doubleValue()).sum(); + double currentSumPrice = orderCurrentList.stream().mapToDouble(e -> e.getPayPrice().doubleValue()).sum(); + + response.setChart(mapper.getOrderStatisticsPriceDetail(new StoreDateRangeSqlPram(dateStart,dateEnd))); + response.setTime(BigDecimal.valueOf(currentSumPrice).setScale(2,BigDecimal.ROUND_HALF_UP)); + // 当前营业额和上一个同比营业额增长区间 + increasePrice = currentSumPrice - perSumPrice; + if (increasePrice <= 0) response.setGrowthRate(0); + else if (perSumPrice == 0) response.setGrowthRate((int) increasePrice * 100); + else response.setGrowthRate((int)((increasePrice * perSumPrice) * 100)); + }else if (type ==2) { + response.setChart(mapper.getOrderStatisticsOrderCountDetail(new StoreDateRangeSqlPram(dateStart,dateEnd))); + response.setTime(BigDecimal.valueOf(orderCurrentList.size())); + increasePrice = orderCurrentList.size() - orderPerList.size(); + if (increasePrice <= 0) response.setGrowthRate(0); + else if (orderPerList.size() == 0) response.setGrowthRate((int) increasePrice); + else response.setGrowthRate((int)((increasePrice / orderPerList.size()) * 100)); + } + response.setIncreaseTime(increasePrice+""); + response.setIncreaseTimeStatus(increasePrice >= 0 ? 1:2); + return response; } /** @@ -193,7 +476,14 @@ public class StoreOrderServiceImpl extends ServiceImpl getUserCurrentDaySecKillOrders(Integer uid, Integer seckillId) { - return null; + String dayStart = DateUtils.nowDateTime(Constants.DATE_FORMAT_START); + String dayEnd = DateUtils.nowDateTime(Constants.DATE_FORMAT_END); + LambdaQueryWrapper lqw = Wrappers.lambdaQuery(); + lqw.eq(StoreOrder::getUid, uid); + lqw.eq(StoreOrder::getSeckillId, seckillId); + lqw.between(StoreOrder::getCreateTime, dayStart, dayEnd); + lqw.eq(StoreOrder::getIsDel, false); + return mapper.selectList(lqw); } /** @@ -205,7 +495,11 @@ public class StoreOrderServiceImpl extends ServiceImpl getUserCurrentBargainOrders(Integer uid, Integer bargainId) { - return null; + LambdaQueryWrapper lqw = Wrappers.lambdaQuery(); + lqw.eq(StoreOrder::getUid, uid); + lqw.eq(StoreOrder::getBargainId, bargainId); + lqw.eq(StoreOrder::getIsDel, false); + return mapper.selectList(lqw); } /** @@ -217,12 +511,18 @@ public class StoreOrderServiceImpl extends ServiceImpl getUserCurrentCombinationOrders(Integer uid, Integer combinationId) { - return null; + LambdaQueryWrapper lqw = Wrappers.lambdaQuery(); + lqw.eq(StoreOrder::getUid, uid); + lqw.eq(StoreOrder::getCombinationId, combinationId); + lqw.eq(StoreOrder::getIsDel, false); + return mapper.selectList(lqw); } @Override public StoreOrder getByOderId(String orderId) { - return null; + LambdaQueryWrapper lqw = Wrappers.lambdaQuery(); + lqw.eq(StoreOrder::getOrderId, orderId); + return mapper.selectOne(lqw); } /** @@ -232,7 +532,12 @@ public class StoreOrderServiceImpl extends ServiceImpl lqw = new LambdaUpdateWrapper<>(); + lqw.set(StoreOrder::getPaid, true); + lqw.set(StoreOrder::getPayTime, DateUtils.nowDateTime()); + lqw.eq(StoreOrder::getOrderId, orderNo); + lqw.eq(StoreOrder::getPaid,false); + return update(lqw); } /** @@ -243,7 +548,14 @@ public class StoreOrderServiceImpl extends ServiceImpl getMapInOrderNo(List orderNoList) { - return null; + Map map = new HashMap<>(); + LambdaUpdateWrapper lqw = new LambdaUpdateWrapper<>(); + lqw.in(StoreOrder::getOrderId, orderNoList); + List orderList = mapper.selectList(lqw); + orderList.forEach(order -> { + map.put(order.getOrderId(), order); + }); + return map; } /** @@ -254,7 +566,11 @@ public class StoreOrderServiceImpl extends ServiceImpl orderNoList) { - return null; + LambdaQueryWrapper lqw = new LambdaQueryWrapper<>(); + lqw.select(StoreOrder::getPayPrice); + lqw.in(StoreOrder::getOrderId, orderNoList); + List orderList = mapper.selectList(lqw); + return orderList.stream().map(StoreOrder::getPayPrice).reduce(BigDecimal.ZERO, BigDecimal::add); } /** @@ -264,7 +580,16 @@ public class StoreOrderServiceImpl extends ServiceImpl findIdAndUidListByReceipt() { - return null; + LambdaQueryWrapper lqw = new LambdaQueryWrapper<>(); + lqw.select(StoreOrder::getId, StoreOrder::getUid); + lqw.eq(StoreOrder::getStatus, 2); + lqw.eq(StoreOrder::getRefundStatus, 0); + lqw.eq(StoreOrder::getIsDel, false); + List orderList = mapper.selectList(lqw); + if (CollUtil.isEmpty(orderList)) { + return CollUtil.newArrayList(); + } + return orderList; } /** @@ -276,7 +601,14 @@ public class StoreOrderServiceImpl extends ServiceImpl findPaidListByUid(Integer userId, PageParam pageParamRequest) { - return null; + PageHelper.startPage(pageParamRequest.getPageNo(), pageParamRequest.getPageSize()); + LambdaQueryWrapper lqw = new LambdaQueryWrapper<>(); + lqw.eq(StoreOrder::getUid, userId); + lqw.eq(StoreOrder::getPaid, true); + lqw.eq(StoreOrder::getIsDel, false); + lqw.lt(StoreOrder::getRefundStatus, 2); + lqw.orderByDesc(StoreOrder::getId); + return mapper.selectList(lqw); } /** @@ -287,7 +619,36 @@ public class StoreOrderServiceImpl extends ServiceImpl { + // 修改订单价格 + orderEditPrice(existOrder.getOrderId(), request.getPayPrice(), existOrder.getPayPrice()); + // 订单修改状态操作 + storeOrderStatusService.createLog(existOrder.getId(), Constants.ORDER_LOG_EDIT, + Constants.RESULT_ORDER_EDIT_PRICE_LOGS.replace("${orderPrice}", oldPrice) + .replace("${price}", request.getPayPrice() + "")); + return Boolean.TRUE; + }); + if (!execute) { + throw new ServiceException(Constants.RESULT_ORDER_EDIT_PRICE_SUCCESS + .replace("${orderNo}", existOrder.getOrderId()).replace("${price}", request.getPayPrice()+"")); + } + // TODO 发送改价短信提醒 + + return execute; } /** @@ -297,8 +658,13 @@ public class StoreOrderServiceImpl extends ServiceImpl lqw = Wrappers.lambdaQuery(); + lqw.eq(StoreOrder::getPaid, true); + lqw.eq(StoreOrder::getIsDel, false); + lqw.eq(StoreOrder::getUid, uid); + lqw.lt(StoreOrder::getRefundStatus, 2); + return mapper.selectCount(lqw); } /** @@ -309,7 +675,14 @@ public class StoreOrderServiceImpl extends ServiceImpl lqw = Wrappers.lambdaQuery(); + lqw.select(StoreOrder::getPayPrice); + lqw.eq(StoreOrder::getPaid, true); + lqw.eq(StoreOrder::getIsDel, false); + lqw.eq(StoreOrder::getUid, userId); + lqw.lt(StoreOrder::getRefundStatus, 2); + List orderList = mapper.selectList(lqw); + return orderList.stream().map(StoreOrder::getPayPrice).reduce(BigDecimal.ZERO, BigDecimal::add); } /** @@ -320,8 +693,17 @@ public class StoreOrderServiceImpl extends ServiceImpl lqw = Wrappers.lambdaQuery(); + lqw.eq(StoreOrder::getPaid, true); + lqw.eq(StoreOrder::getIsDel, false); + lqw.eq(StoreOrder::getUid, uid); + lqw.lt(StoreOrder::getRefundStatus, 2); + if (StrUtil.isNotBlank(date)) { + DateLimitUtilVo dateLimit = DateUtils.getDateLimit(date); + lqw.between(StoreOrder::getCreateTime, dateLimit.getStartTime(), dateLimit.getEndTime()); + } + return mapper.selectCount(lqw); } /** @@ -333,7 +715,18 @@ public class StoreOrderServiceImpl extends ServiceImpl lqw = Wrappers.lambdaQuery(); + lqw.select(StoreOrder::getPayPrice); + lqw.eq(StoreOrder::getPaid, true); + lqw.eq(StoreOrder::getIsDel, false); + lqw.eq(StoreOrder::getUid, userId); + lqw.lt(StoreOrder::getRefundStatus, 2); + if (StrUtil.isNotBlank(date)) { + DateLimitUtilVo dateLimit = DateUtils.getDateLimit(date); + lqw.between(StoreOrder::getCreateTime, dateLimit.getStartTime(), dateLimit.getEndTime()); + } + List orderList = mapper.selectList(lqw); + return orderList.stream().map(StoreOrder::getPayPrice).reduce(BigDecimal.ZERO, BigDecimal::add); } /** @@ -345,7 +738,12 @@ public class StoreOrderServiceImpl extends ServiceImpl lqw = Wrappers.lambdaQuery(); + lqw.eq(StoreOrder::getBargainId, bargainId); + lqw.eq(StoreOrder::getBargainUserId, bargainUserId); + lqw.orderByDesc(StoreOrder::getId); + lqw.last(" limit 1"); + return mapper.selectOne(lqw); } /** @@ -357,7 +755,31 @@ public class StoreOrderServiceImpl extends ServiceImpl wrapper = new QueryWrapper<>(); + wrapper.select("IFNULL(sum(total_num), 0) as total_num"); + wrapper.apply("date_format(create_time, '%Y-%m-%d') = {0}", date); + StoreOrder storeOrder = mapper.selectOne(wrapper); + return storeOrder.getTotalNum(); } /** @@ -401,7 +844,12 @@ public class StoreOrderServiceImpl extends ServiceImpl wrapper = new QueryWrapper<>(); + wrapper.select("IFNULL(sum(total_num), 0) as total_num"); + wrapper.eq("paid", 1); + wrapper.apply("date_format(create_time, '%Y-%m-%d') = {0}", date); + StoreOrder storeOrder = mapper.selectOne(wrapper); + return storeOrder.getTotalNum(); } /** @@ -411,8 +859,12 @@ public class StoreOrderServiceImpl extends ServiceImpl wrapper = new QueryWrapper<>(); + wrapper.select("id"); + wrapper.eq("paid", 1); + wrapper.apply("date_format(create_time, '%Y-%m-%d') = {0}", date); + return mapper.selectCount(wrapper); } /** @@ -422,8 +874,12 @@ public class StoreOrderServiceImpl extends ServiceImpl wrapper = new QueryWrapper<>(); + wrapper.select("id"); + wrapper.eq("paid", 1); + wrapper.apply("date_format(create_time, '%Y-%m-%d') = {0}", date); + return mapper.selectCount(wrapper); } /** @@ -434,7 +890,12 @@ public class StoreOrderServiceImpl extends ServiceImpl wrapper = new QueryWrapper<>(); + wrapper.select("IFNULL(sum(pay_price), 0) as pay_price"); + wrapper.eq("paid", 1); + wrapper.apply("date_format(create_time, '%Y-%m-%d') = {0}", date); + StoreOrder storeOrder = mapper.selectOne(wrapper); + return storeOrder.getPayPrice(); } /** @@ -446,7 +907,12 @@ public class StoreOrderServiceImpl extends ServiceImpl wrapper = new QueryWrapper<>(); + wrapper.select("IFNULL(sum(pay_price), 0) as pay_price"); + wrapper.eq("paid", 1); + wrapper.apply("date_format(create_time, '%Y-%m-%d') between {0} and {1}", startDate, endDate); + StoreOrder storeOrder = mapper.selectOne(wrapper); + return storeOrder.getPayPrice(); } /** @@ -457,7 +923,13 @@ public class StoreOrderServiceImpl extends ServiceImpl wrapper = new QueryWrapper<>(); + wrapper.select("IFNULL(sum(pay_price), 0) as pay_price"); + wrapper.eq("paid", 1); + wrapper.eq("pay_type", "yue"); + wrapper.apply("date_format(create_time, '%Y-%m-%d') = {0}", date); + StoreOrder storeOrder = mapper.selectOne(wrapper); + return storeOrder.getPayPrice(); } /** @@ -467,7 +939,11 @@ public class StoreOrderServiceImpl extends ServiceImpl wrapper = new QueryWrapper<>(); + wrapper.select("IFNULL(sum(pay_price), 0) as pay_price"); + wrapper.eq("paid", 1); + StoreOrder storeOrder = mapper.selectOne(wrapper); + return storeOrder.getPayPrice(); } /** @@ -478,7 +954,15 @@ public class StoreOrderServiceImpl extends ServiceImpl wrapper = new QueryWrapper<>(); + wrapper.select("id"); + wrapper.apply("date_format(create_time, '%Y-%m-%d') = {0}", date); + wrapper.groupBy("uid"); + List orderList = mapper.selectList(wrapper); + if (CollUtil.isEmpty(orderList)) { + return 0; + } + return orderList.size(); } /** @@ -490,7 +974,15 @@ public class StoreOrderServiceImpl extends ServiceImpl wrapper = new QueryWrapper<>(); + wrapper.select("id"); + wrapper.apply("date_format(create_time, '%Y-%m-%d') between {0} and {1}", startDate, endDate); + wrapper.groupBy("uid"); + List orderList = mapper.selectList(wrapper); + if (CollUtil.isEmpty(orderList)) { + return 0; + } + return orderList.size(); } /** @@ -501,7 +993,16 @@ public class StoreOrderServiceImpl extends ServiceImpl wrapper = new QueryWrapper<>(); + wrapper.select("id"); + wrapper.eq("paid", 1); + wrapper.apply("date_format(create_time, '%Y-%m-%d') = {0}", date); + wrapper.groupBy("uid"); + List orderList = mapper.selectList(wrapper); + if (CollUtil.isEmpty(orderList)) { + return 0; + } + return orderList.size(); } /** @@ -513,7 +1014,16 @@ public class StoreOrderServiceImpl extends ServiceImpl wrapper = new QueryWrapper<>(); + wrapper.select("id"); + wrapper.eq("paid", 1); + wrapper.apply("date_format(create_time, '%Y-%m-%d') between {0} and {1}", startDate, endDate); + wrapper.groupBy("uid"); + List orderList = mapper.selectList(wrapper); + if (CollUtil.isEmpty(orderList)) { + return 0; + } + return orderList.size(); } /** @@ -524,7 +1034,16 @@ public class StoreOrderServiceImpl extends ServiceImpl uidList) { - return null; + QueryWrapper wrapper = new QueryWrapper<>(); + wrapper.select("id"); + wrapper.eq("paid", 1); + wrapper.in("uid", uidList); + wrapper.groupBy("uid"); + List orderList = mapper.selectList(wrapper); + if (CollUtil.isEmpty(orderList)) { + return 0; + } + return orderList.size(); } /** @@ -535,7 +1054,16 @@ public class StoreOrderServiceImpl extends ServiceImpl uidList) { - return null; + QueryWrapper wrapper = new QueryWrapper<>(); + wrapper.select("IFNULL(sum(pay_price), 0.00) as pay_price"); +// wrapper.select("ifnull(if(sum(pay_price) = 0.00, 0, sum(pay_price)), 0) as pay_price"); + wrapper.eq("paid", 1); + wrapper.in("uid", uidList); + List orderList = mapper.selectList(wrapper); + if (CollUtil.isEmpty(orderList)) { + return BigDecimal.ZERO; + } + return orderList.stream().map(StoreOrder::getPayPrice).reduce(BigDecimal.ZERO, BigDecimal::add); } /** @@ -544,24 +1072,24 @@ public class StoreOrderServiceImpl extends ServiceImpl lqw = Wrappers.lambdaQuery(); + lqw.eq(StoreOrder::getOrderId, orderNo); + StoreOrder storeOrder = mapper.selectOne(lqw); + if (ObjectUtil.isNull(storeOrder)) { + throw new ServiceException("没有找到订单信息"); + } + return storeOrder; + } + + /** + * 获取订单金额 + * @param dateLimit 时间端 + * @param type 支付类型 + * @return Integer + */ + private BigDecimal getAmount(String dateLimit, String type) { + QueryWrapper queryWrapper = new QueryWrapper<>(); + queryWrapper.select("sum(pay_price) as pay_price"); + if (StringUtils.isNotBlank(type)) { + queryWrapper.eq("pay_type", type); + } + queryWrapper.isNotNull("pay_time"); + queryWrapper.eq("paid", 1); + if (StringUtils.isNotBlank(dateLimit)) { + DateLimitUtilVo dateLimitUtilVo = DateUtils.getDateLimit(dateLimit); + queryWrapper.between("create_time", dateLimitUtilVo.getStartTime(), dateLimitUtilVo.getEndTime()); + } + StoreOrder storeOrder = mapper.selectOne(queryWrapper); + if (ObjectUtil.isNull(storeOrder)) { + return BigDecimal.ZERO; + } + return storeOrder.getPayPrice(); + } + + /** + * 获取订单总数 + * @param dateLimit 时间端 + * @param status String 状态 + * @return Integer + */ + private Long getCount(String dateLimit, String status) { + //总数只计算时间 + QueryWrapper queryWrapper = new QueryWrapper<>(); + if (StrUtil.isNotBlank(dateLimit)) { + DateLimitUtilVo dateLimitUtilVo = DateUtils.getDateLimit(dateLimit); + queryWrapper.between("create_time", dateLimitUtilVo.getStartTime(), dateLimitUtilVo.getEndTime()); + } + getStatusWhereNew(queryWrapper, status); + return mapper.selectCount(queryWrapper); + } + + /** + * 获取订单总数 + * @param dateLimit 时间端 + * @param status String 状态 + * @return Integer + */ + private Long getCount(String dateLimit, String status, Integer type) { + //总数只计算时间 + QueryWrapper queryWrapper = new QueryWrapper<>(); + if (StrUtil.isNotBlank(dateLimit)) { + DateLimitUtilVo dateLimitUtilVo = DateUtils.getDateLimit(dateLimit); + queryWrapper.between("create_time", dateLimitUtilVo.getStartTime(), dateLimitUtilVo.getEndTime()); + } + getStatusWhereNew(queryWrapper, status); + if (ObjectUtil.isNotNull(type)) { + queryWrapper.eq("type", type); + } + return mapper.selectCount(queryWrapper); + } + + /** + * 改价 + * @param orderNo 订单编号 + * @param price 修改后的价格 + * @param oldPrice 原支付金额 + */ + private Boolean orderEditPrice(String orderNo, BigDecimal price, BigDecimal oldPrice) { + LambdaUpdateWrapper luw = new LambdaUpdateWrapper<>(); + luw.set(StoreOrder::getPayPrice, price); + luw.set(StoreOrder::getBeforePayPrice, oldPrice); + luw.set(StoreOrder::getIsAlterPrice, 1); + luw.eq(StoreOrder::getOrderId, orderNo); + luw.eq(StoreOrder::getPaid, false); + return update(luw); + } + + /** + * 根据时间参数获取有效订单 + * @return 有效订单列表 + */ + private List getOrderPayedByDateLimit(String startTime, String endTime) { + LambdaQueryWrapper lqw = Wrappers.lambdaQuery(); + lqw.eq(StoreOrder::getIsDel, false).eq(StoreOrder::getPaid, true).eq(StoreOrder::getRefundStatus,0) + .between(StoreOrder::getCreateTime, startTime, endTime); + return mapper.selectList(lqw); + } + + /** 快递 + * @param request StoreOrderSendRequest 发货参数 + * @param storeOrder StoreOrder 订单信息 + */ + private void express(StoreOrderSendRequest request, StoreOrder storeOrder) { + // 校验快递发货参数 + validateExpressSend(request); + // TODO 快递公司信息 +// Express express = expressService.getByCode(request.getExpressCode()); +// if (request.getExpressRecordType().equals("1")) { // 正常发货 +// deliverGoods(request, storeOrder); +// } +// if (request.getExpressRecordType().equals("2")) { // 电子面单 +// request.setExpressName(express.getName()); +// expressDump(request, storeOrder, express); +// } +// +// storeOrder.setDeliveryCode(express.getCode()); +// storeOrder.setDeliveryName(express.getName()); +// storeOrder.setStatus(1); +// storeOrder.setDeliveryType("express"); + + String message = Constants.ORDER_LOG_MESSAGE_EXPRESS.replace("{deliveryName}", request.getExpressName()).replace("{deliveryCode}", storeOrder.getDeliveryId()); + + Boolean execute = transactionTemplate.execute(i -> { + updateById(storeOrder); + //订单记录增加 + storeOrderStatusService.createLog(request.getId(), Constants.ORDER_LOG_EXPRESS, message); + return Boolean.TRUE; + }); + + if (!execute) throw new ServiceException("快递发货失败!"); + + sendGoodsNotify(storeOrder); + } + + /** + * 校验快递发货参数 + */ + private void validateExpressSend(StoreOrderSendRequest request) { + if (request.getExpressRecordType().equals("1")) { + if (StrUtil.isBlank(request.getExpressNumber())) throw new ServiceException("请填写快递单号"); + return; + } + if (StrUtil.isBlank(request.getExpressCode())) throw new ServiceException("请选择快递公司"); + if (StrUtil.isBlank(request.getExpressRecordType())) throw new ServiceException("请选择发货记录类型"); + if (StrUtil.isBlank(request.getExpressTempId())) throw new ServiceException("请选择电子面单"); + if (StrUtil.isBlank(request.getToName())) throw new ServiceException("请填写寄件人姓名"); + if (StrUtil.isBlank(request.getToTel())) throw new ServiceException("请填写寄件人电话"); + if (StrUtil.isBlank(request.getToAddr())) throw new ServiceException("请填写寄件人地址"); + } + + /** + * 正常发货 + */ + private void deliverGoods(StoreOrderSendRequest request, StoreOrder storeOrder) { + storeOrder.setDeliveryId(request.getExpressNumber()); + } + + /** + * 发货通知 + * @param storeOrder 订单 + */ + private void sendGoodsNotify(StoreOrder storeOrder) { + MemberUserDO user = userService.getUser(storeOrder.getUid()); + //TODO 发送发货短信提醒 + + // 发送消息通知 +// pushMessageOrder(storeOrder, user, notification); + } + + + /** 送货上门 + * @param request StoreOrderSendRequest 发货参数 + * @param storeOrder StoreOrder 订单信息 + * @author Mr.Zhang + * @since 2020-06-10 + */ + private void delivery(StoreOrderSendRequest request, StoreOrder storeOrder) { + if (StrUtil.isBlank(request.getDeliveryName())) throw new ServiceException("请输入送货人姓名"); + if (StrUtil.isBlank(request.getDeliveryTel())) throw new ServiceException("请输入送货人电话号码"); + PhoneUtil.isPhone(request.getDeliveryTel()); + + //送货信息 + storeOrder.setDeliveryName(request.getDeliveryName()); + storeOrder.setDeliveryId(request.getDeliveryTel()); + storeOrder.setStatus(1); + storeOrder.setDeliveryType("send"); + + //获取购买商品名称 + List orderIdList = new ArrayList<>(); + orderIdList.add(storeOrder.getId()); + HashMap> orderInfoMap = StoreOrderInfoService.getMapInId(orderIdList); + if (orderInfoMap.isEmpty() || !orderInfoMap.containsKey(storeOrder.getId())) { + throw new ServiceException("没有找到购买的商品信息"); + } + List productNameList = new ArrayList<>(); + for (StoreOrderInfoOldVo storeOrderInfoVo : orderInfoMap.get(storeOrder.getId())) { + productNameList.add(storeOrderInfoVo.getInfo().getProductName()); + } + + String message = Constants.ORDER_LOG_MESSAGE_DELIVERY.replace("{deliveryName}", request.getDeliveryName()).replace("{deliveryCode}", request.getDeliveryTel()); + + Boolean execute = transactionTemplate.execute(i -> { + // 更新订单 + updateById(storeOrder); + // 订单记录增加 + storeOrderStatusService.createLog(request.getId(), Constants.ORDER_LOG_DELIVERY, message); + return Boolean.TRUE; + }); + if (!execute) throw new ServiceException("订单更新送货失败"); + + MemberUserDO user = userService.getUser(storeOrder.getUid()); + // TODO 发送消息通知 +// pushMessageDeliveryOrder(storeOrder, user, request, productNameList); + } + + /** 虚拟 + * @param request StoreOrderSendRequest 发货参数 + * @param storeOrder StoreOrder 订单信息 + * @author Mr.Zhang + * @since 2020-06-10 + */ + private void virtual(StoreOrderSendRequest request, StoreOrder storeOrder) { + //快递信息 + storeOrder.setDeliveryType("fictitious"); + storeOrder.setStatus(1); + + Boolean execute = transactionTemplate.execute(i -> { + updateById(storeOrder); + //订单记录增加 + storeOrderStatusService.createLog(request.getId(), Constants.ORDER_LOG_DELIVERY_VI, "虚拟物品发货"); + return Boolean.TRUE; + }); + if (!execute) throw new ServiceException("虚拟物品发货失败"); + } + + /** + * 格式化订单信息,对外输出一致 + * @param orderList List 订单列表 + * @return List + */ + private List formatOrder1(List orderList) { + List detailResponseList = new ArrayList<>(); + if (CollUtil.isEmpty(orderList)) { + return detailResponseList; + } + + //订单id集合 + List orderIdList = orderList.stream().map(StoreOrder::getId).distinct().collect(Collectors.toList()); + + //获取订单详情map + HashMap> orderInfoList = StoreOrderInfoService.getMapInId(orderIdList); +// +// //根据用户获取信息 +// List userIdList = orderList.stream().map(StoreOrder::getUid).distinct().collect(Collectors.toList()); +// //订单用户信息 +// HashMap userList = userService.getMapListInUid(userIdList); + + for (StoreOrder storeOrder : orderList) { + StoreOrderDetailResponse storeOrderItemResponse = new StoreOrderDetailResponse(); + BeanUtils.copyProperties(storeOrder, storeOrderItemResponse); + + storeOrderItemResponse.setProductList(orderInfoList.get(storeOrder.getId())); + + //订单状态 + storeOrderItemResponse.setStatusStr(getStatus(storeOrder)); + storeOrderItemResponse.setStatus(storeOrder.getStatus()); + //支付方式 + storeOrderItemResponse.setPayTypeStr(getPayType(storeOrder.getPayType())); + + // 添加订单类型信息 + storeOrderItemResponse.setOrderType(getOrderTypeStr(storeOrder)); + detailResponseList.add(storeOrderItemResponse); + } + return detailResponseList; + } + + /** + * 获取request的where条件 + * @param queryWrapper QueryWrapper 表达式 + * @param request StoreOrderSearchRequest 请求参数 + */ + private void getRequestTimeWhere(QueryWrapper queryWrapper, StoreOrderSearchRequest request) { + if (StringUtils.isNotBlank(request.getDateLimit())) { + DateLimitUtilVo dateLimitUtilVo = DateUtils.getDateLimit(request.getDateLimit()); + queryWrapper.between("create_time", dateLimitUtilVo.getStartTime(), dateLimitUtilVo.getEndTime()); + } + } + + /** + * 获取订单状态 + * @param storeOrder StoreOrder 订单信息 + * @author Mr.Zhang + * @since 2020-06-12 + */ + private Map getStatus(StoreOrder storeOrder) { + Map map = new HashMap<>(); + map.put("key", ""); + map.put("value", ""); + if (null == storeOrder) { + return map; + } + // 未支付 + if (!storeOrder.getPaid() + && storeOrder.getStatus() == 0 + && storeOrder.getRefundStatus() == 0 + && !storeOrder.getIsDel() + && !storeOrder.getIsSystemDel()) { + map.put("key", Constants.ORDER_STATUS_UNPAID); + map.put("value", Constants.ORDER_STATUS_STR_UNPAID); + return map; + } + // 未发货 + if (storeOrder.getPaid() + && storeOrder.getStatus() == 0 + && storeOrder.getRefundStatus() == 0 + && storeOrder.getShippingType() == 1 + && !storeOrder.getIsDel() + && !storeOrder.getIsSystemDel()) { + map.put("key", Constants.ORDER_STATUS_NOT_SHIPPED); + map.put("value", Constants.ORDER_STATUS_STR_NOT_SHIPPED); + return map; + } + // 待收货 + if (storeOrder.getPaid() + && storeOrder.getStatus() == 1 + && storeOrder.getRefundStatus() == 0 + && storeOrder.getShippingType() == 1 + && !storeOrder.getIsDel() + && !storeOrder.getIsSystemDel()) { + map.put("key", Constants.ORDER_STATUS_SPIKE); + map.put("value", Constants.ORDER_STATUS_STR_SPIKE); + return map; + } + // 待评价 + if (storeOrder.getPaid() + && storeOrder.getStatus() == 2 + && storeOrder.getRefundStatus() == 0 + && !storeOrder.getIsDel() + && !storeOrder.getIsSystemDel()) { + map.put("key", Constants.ORDER_STATUS_BARGAIN); + map.put("value", Constants.ORDER_STATUS_STR_BARGAIN); + return map; + } + // 交易完成 + if (storeOrder.getPaid() + && storeOrder.getStatus() == 3 + && storeOrder.getRefundStatus() == 0 + && !storeOrder.getIsDel() + && !storeOrder.getIsSystemDel()) { + map.put("key", Constants.ORDER_STATUS_COMPLETE); + map.put("value", Constants.ORDER_STATUS_STR_COMPLETE); + return map; + } + // 待核销 + if (storeOrder.getPaid() + && storeOrder.getStatus() == 0 + && storeOrder.getRefundStatus() == 0 + && storeOrder.getShippingType() == 2 + && !storeOrder.getIsDel() + && !storeOrder.getIsSystemDel()) { + map.put("key", Constants.ORDER_STATUS_TOBE_WRITTEN_OFF); + map.put("value", Constants.ORDER_STATUS_STR_TOBE_WRITTEN_OFF); + return map; + } + + //申请退款 + if (storeOrder.getPaid() + && storeOrder.getRefundStatus() == 1 + && !storeOrder.getIsDel() + && !storeOrder.getIsSystemDel()) { + map.put("key", Constants.ORDER_STATUS_APPLY_REFUNDING); + map.put("value", Constants.ORDER_STATUS_STR_APPLY_REFUNDING); + return map; + } + + //退款中 + if (storeOrder.getPaid() + && storeOrder.getRefundStatus() == 3 + && !storeOrder.getIsDel() + && !storeOrder.getIsSystemDel()) { + map.put("key", Constants.ORDER_STATUS_REFUNDING); + map.put("value", Constants.ORDER_STATUS_STR_REFUNDING); + return map; + } + + //已退款 + if (storeOrder.getPaid() + && storeOrder.getRefundStatus() == 2 + && !storeOrder.getIsDel() + && !storeOrder.getIsSystemDel()) { + map.put("key", Constants.ORDER_STATUS_REFUNDED); + map.put("value", Constants.ORDER_STATUS_STR_REFUNDED); + } + + //已删除 + if (storeOrder.getIsDel() || storeOrder.getIsSystemDel()) { + map.put("key", Constants.ORDER_STATUS_DELETED); + map.put("value", Constants.ORDER_STATUS_STR_DELETED); + } + + return map; + } + + /** + * 根据订单状态获取where条件 + * @param queryWrapper QueryWrapper 表达式 + * @param status String 类型 + */ + private void getStatusWhereNew(QueryWrapper queryWrapper, String status) { + if (StrUtil.isBlank(status)) { + return; + } + switch (status) { + case Constants.ORDER_STATUS_ALL: //全部 + break; + case Constants.ORDER_STATUS_UNPAID: //未支付 + queryWrapper.eq("paid", 0);//支付状态 + queryWrapper.eq("status", 0); //订单状态 + queryWrapper.eq("is_del", 0);//删除状态 + break; + case Constants.ORDER_STATUS_NOT_SHIPPED: //未发货 + queryWrapper.eq("paid", 1); + queryWrapper.eq("status", 0); + queryWrapper.eq("refund_status", 0); + queryWrapper.eq("shipping_type", 1);//配送方式 + queryWrapper.eq("is_del", 0); + break; + case Constants.ORDER_STATUS_SPIKE: //待收货 + queryWrapper.eq("paid", 1); + queryWrapper.eq("status", 1); + queryWrapper.eq("refund_status", 0); + queryWrapper.eq("is_del", 0); + break; + case Constants.ORDER_STATUS_BARGAIN: //待评价 + queryWrapper.eq("paid", 1); + queryWrapper.eq("status", 2); + queryWrapper.eq("refund_status", 0); + queryWrapper.eq("is_del", 0); + break; + case Constants.ORDER_STATUS_COMPLETE: //交易完成 + queryWrapper.eq("paid", 1); + queryWrapper.eq("status", 3); + queryWrapper.eq("refund_status", 0); + queryWrapper.eq("is_del", 0); + break; + case Constants.ORDER_STATUS_TOBE_WRITTEN_OFF: //待核销 + queryWrapper.eq("paid", 1); + queryWrapper.eq("status", 0); + queryWrapper.eq("refund_status", 0); + queryWrapper.eq("shipping_type", 2);//配送方式 + queryWrapper.eq("is_del", 0); + break; + case Constants.ORDER_STATUS_REFUNDING: //退款中 + queryWrapper.eq("paid", 1); + queryWrapper.in("refund_status", 1,3); + queryWrapper.eq("is_del", 0); + break; + case Constants.ORDER_STATUS_REFUNDED: //已退款 + queryWrapper.eq("paid", 1); + queryWrapper.eq("refund_status", 2); + queryWrapper.eq("is_del", 0); + break; + case Constants.ORDER_STATUS_DELETED: //已删除 + queryWrapper.eq("is_del", 1); + break; + default: + queryWrapper.eq("paid", 1); + queryWrapper.ne("refund_status", 2); + break; + } + queryWrapper.eq("is_system_del", 0); + } + + /** + * 获取支付文字 + * @param payType String 支付方式 + */ + private String getPayType(String payType) { + switch (payType) { + case Constants.PAY_TYPE_WE_CHAT: + return Constants.PAY_TYPE_STR_WE_CHAT; + case Constants.PAY_TYPE_YUE: + return Constants.PAY_TYPE_STR_YUE; + case Constants.PAY_TYPE_ALI_PAY: + return Constants.PAY_TYPE_STR_ALI_PAY; + default: + return Constants.PAY_TYPE_STR_OTHER; + } + } + + /** + * 获取订单类型(前端展示) + * @param storeOrder 订单 + * @return String + */ + private String getOrderTypeStr(StoreOrder storeOrder) { + String orderTypeFormat = "[{}订单]{}"; + String orderType = StrUtil.format(orderTypeFormat, "普通", ""); + // 核销 + if (StrUtil.isNotBlank(storeOrder.getVerifyCode())) { + orderType = StrUtil.format(orderTypeFormat, "核销", ""); + } + if (storeOrder.getType().equals(1)) {// 视频订单 + orderType = StrUtil.format(orderTypeFormat, "视频号", ""); + } + return orderType; + } + + /** + * 根据订单状态获取where条件 + * @param queryWrapper QueryWrapper 表达式 + * @param status String 类型 + */ + private void getStatusWhere(QueryWrapper queryWrapper, String status) { + if (StrUtil.isBlank(status)) { + return; + } + switch (status) { + case Constants.ORDER_STATUS_UNPAID: //未支付 + queryWrapper.eq("paid", 0);//支付状态 + queryWrapper.eq("status", 0); //订单状态 + queryWrapper.eq("is_del", 0);//删除状态 + break; + case Constants.ORDER_STATUS_NOT_SHIPPED: //未发货 + queryWrapper.eq("paid", 1); + queryWrapper.eq("status", 0); + queryWrapper.eq("refund_status", 0); + queryWrapper.eq("shipping_type", 1);//配送方式 + queryWrapper.eq("is_del", 0); + break; + case Constants.ORDER_STATUS_SPIKE: //待收货 + queryWrapper.eq("paid", 1); + queryWrapper.eq("status", 1); + queryWrapper.eq("refund_status", 0); + queryWrapper.eq("is_del", 0); + break; + case Constants.ORDER_STATUS_BARGAIN: //待评价 + queryWrapper.eq("paid", 1); + queryWrapper.eq("status", 2); + queryWrapper.eq("refund_status", 0); + queryWrapper.eq("is_del", 0); + break; + case Constants.ORDER_STATUS_COMPLETE: //交易完成 + queryWrapper.eq("paid", 1); + queryWrapper.eq("status", 3); + queryWrapper.eq("refund_status", 0); + queryWrapper.eq("is_del", 0); + break; + case Constants.ORDER_STATUS_TOBE_WRITTEN_OFF: //待核销 + queryWrapper.eq("paid", 1); + queryWrapper.eq("status", 0); + queryWrapper.eq("refund_status", 0); + queryWrapper.eq("shipping_type", 2);//配送方式 + queryWrapper.eq("is_del", 0); + break; + case Constants.ORDER_STATUS_REFUNDING: //退款中 + queryWrapper.eq("paid", 1); + queryWrapper.in("refund_status", 1,3); + queryWrapper.eq("is_del", 0); + break; + case Constants.ORDER_STATUS_REFUNDED: //已退款 + queryWrapper.eq("paid", 1); + queryWrapper.eq("refund_status", 2); + queryWrapper.eq("is_del", 0); + break; + case Constants.ORDER_STATUS_DELETED: //已删除 + queryWrapper.eq("is_del", 1); + break; + default: + queryWrapper.eq("paid", 1); + queryWrapper.ne("refund_status", 2); + break; + } + queryWrapper.eq("is_system_del", 0); + } + + + } diff --git a/yudao-module-mall/yudao-module-shop-biz/src/main/java/cn/iocoder/yudao/module/shop/service/order/impl/StoreOrderStatusServiceImpl.java b/yudao-module-mall/yudao-module-shop-biz/src/main/java/cn/iocoder/yudao/module/shop/service/order/impl/StoreOrderStatusServiceImpl.java index bc188197c..d783c52e4 100644 --- a/yudao-module-mall/yudao-module-shop-biz/src/main/java/cn/iocoder/yudao/module/shop/service/order/impl/StoreOrderStatusServiceImpl.java +++ b/yudao-module-mall/yudao-module-shop-biz/src/main/java/cn/iocoder/yudao/module/shop/service/order/impl/StoreOrderStatusServiceImpl.java @@ -1,14 +1,26 @@ package cn.iocoder.yudao.module.shop.service.order.impl; +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.ObjectUtil; +import cn.iocoder.yudao.framework.common.enums.Constants; import cn.iocoder.yudao.framework.common.pojo.PageParam; +import cn.iocoder.yudao.framework.common.util.date.DateUtils; +import cn.iocoder.yudao.module.shop.dal.dataobject.order.StoreOrder; import cn.iocoder.yudao.module.shop.dal.dataobject.order.StoreOrderStatus; import cn.iocoder.yudao.module.shop.dal.mysql.order.StoreOrderStatusMapper; import cn.iocoder.yudao.module.shop.request.order.StoreOrderStatusSearchRequest; +import cn.iocoder.yudao.module.shop.service.order.StoreOrderService; import cn.iocoder.yudao.module.shop.service.order.StoreOrderStatusService; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.github.pagehelper.PageHelper; import com.github.pagehelper.PageInfo; +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; +import javax.annotation.Resource; import java.math.BigDecimal; import java.util.List; @@ -26,6 +38,13 @@ import java.util.List; */ @Service public class StoreOrderStatusServiceImpl extends ServiceImpl implements StoreOrderStatusService { + + @Resource + private StoreOrderStatusMapper mapper; + + @Autowired + private StoreOrderService storeOrderService; + /** * 订单操作记录列表 * @@ -35,7 +54,15 @@ public class StoreOrderStatusServiceImpl extends ServiceImpl getList(StoreOrderStatusSearchRequest request, PageParam pageParamRequest) { - return null; + StoreOrder storeOrder = storeOrderService.getByOderId(request.getOrderNo()); + if (ObjectUtil.isNull(storeOrder)) { + return new PageInfo<>(CollUtil.newArrayList()); + } + PageHelper.startPage(pageParamRequest.getPageNo(), pageParamRequest.getPageSize()); + LambdaQueryWrapper lqw = new LambdaQueryWrapper<>(); + lqw.eq(StoreOrderStatus::getOid, storeOrder.getId()); + lqw.orderByDesc(StoreOrderStatus::getCreateTime); + return new PageInfo<>(mapper.selectList(lqw)); } /** @@ -48,7 +75,16 @@ public class StoreOrderStatusServiceImpl extends ServiceImpl getByEntity(StoreOrderStatus storeOrderStatus) { - return null; + LambdaQueryWrapper lambdaQueryWrapper = new LambdaQueryWrapper<>(); + lambdaQueryWrapper.setEntity(storeOrderStatus); + return mapper.selectList(lambdaQueryWrapper); } /** @@ -83,7 +126,11 @@ public class StoreOrderStatusServiceImpl extends ServiceImpl queryWrapper = new QueryWrapper<>(); + queryWrapper.eq("oid", orderId); + queryWrapper.orderByDesc("create_time"); + queryWrapper.last(" limit 1"); + return mapper.selectOne(queryWrapper); } /** @@ -93,8 +140,12 @@ public class StoreOrderStatusServiceImpl extends ServiceImpl wrapper = new QueryWrapper<>(); + wrapper.select("oid"); + wrapper.eq("change_type", "refund_price"); + wrapper.apply("date_format(create_time, '%Y-%m-%d') = {0}", date); + return mapper.selectCount(wrapper); } /** @@ -105,7 +156,7 @@ public class StoreOrderStatusServiceImpl extends ServiceImpl orderInfoList = storeOrderInfoService.getListByOrderNo(storeOrder.getOrderId()); + if(null == orderInfoList || orderInfoList.size() < 1){ + return true; + } + + // 正常商品回滚销量库存 + for (StoreOrderInfo orderInfoVo : orderInfoList) { + storeProductService.operationStock(orderInfoVo.getProductId(), orderInfoVo.getPayNum(), "add"); + attrValueService.operationStock(orderInfoVo.getAttrValueId(), orderInfoVo.getPayNum(), "add", Constants.PRODUCT_TYPE_NORMAL); + } + }catch (Exception e){ +// throw new CrmebException(e.getMessage()); + logger.error("回滚库存失败,error = " + e.getMessage()); + return true; + } + return true; } @Override + @Transactional(rollbackFor = {RuntimeException.class, Error.class, ServerException.class}) public Boolean complete(StoreOrder storeOrder) { - return null; + /* + * 1、修改订单状态 (用户操作的时候已处理) + * 2、写订单日志 + * */ + try{ + storeOrderStatusService.createLog(storeOrder.getId(), "check_order_over", "用户评价"); + return true; + }catch (Exception e){ + return false; + } } @Override public Boolean refundOrder(StoreOrder storeOrder) { - return null; + /** + * 1、写订单日志 + * 2、回滚库存 + * 3、发送通知 + * 实际上2-5就是user数据的处理+userBill的记录 + */ + // 获取用户对象 + MemberUserDO user = memberUserMapper.selectById(storeOrder.getUid()); + if (ObjectUtil.isNull(user)) { + logger.error("订单退款处理,对应的用户不存在,storeOrder===>" + storeOrder); + return Boolean.FALSE; + } + + StoreOrder tempOrder = new StoreOrder(); + tempOrder.setId(storeOrder.getId()); + tempOrder.setRefundStatus(2); + + Boolean execute = transactionTemplate.execute(e -> { + //写订单日志 + storeOrderStatusService.saveRefund(storeOrder.getId(), storeOrder.getRefundPrice(), "成功"); + + // 更新用户数据 + memberUserMapper.updateById(user); + + // 回滚库存 + rollbackStock(storeOrder); + + storeOrderService.updateById(tempOrder); + + return Boolean.TRUE; + }); + return execute; } @Override public Boolean autoCancel(StoreOrder storeOrder) { - return null; + // 判断订单是否支付 + if (storeOrder.getPaid()) { + return Boolean.TRUE; + } + if (storeOrder.getIsDel() || storeOrder.getIsSystemDel()) { + return Boolean.TRUE; + } + // 获取过期时间 + String cancelStr; + DateTime cancelTime; + if (storeOrder.getType().equals(1)) { + cancelStr = "3"; + cancelTime = cn.hutool.core.date.DateUtil.offset(storeOrder.getCreateTime(), DateField.MINUTE, Integer.parseInt(cancelStr)); + } else { + if (storeOrder.getBargainId() > 0 || storeOrder.getSeckillId() > 0 || storeOrder.getCombinationId() > 0) { + cancelStr = apiConfigApi.getConfigKey("order_activity_time").toString(); + } else { + cancelStr = apiConfigApi.getConfigKey("order_cancel_time").toString(); + } + if (StrUtil.isBlank(cancelStr)) { + cancelStr = "1"; + } + cancelTime = cn.hutool.core.date.DateUtil.offset(storeOrder.getCreateTime(), DateField.HOUR_OF_DAY, Integer.parseInt(cancelStr)); + } + long between = cn.hutool.core.date.DateUtil.between(cancelTime, cn.hutool.core.date.DateUtil.date(), DateUnit.SECOND, false); + if (between < 0) {// 未到过期时间继续循环 + return Boolean.FALSE; + } + storeOrder.setIsDel(true).setIsSystemDel(true); + Boolean execute = transactionTemplate.execute(e -> { + storeOrderService.updateById(storeOrder); + //写订单日志 + storeOrderStatusService.createLog(storeOrder.getId(), "cancel", "到期未支付系统自动取消"); + return Boolean.TRUE; + }); + if (execute) { + // 回滚库存 + rollbackStock(storeOrder); + } + return execute; } @Override public Boolean orderReceiving(Integer orderId) { - return null; + StoreOrder storeOrder = storeOrderService.getById(orderId); + if (ObjectUtil.isNull(storeOrder)) { + throw new ServiceException(StrUtil.format("订单收货task处理,未找到订单,id={}", orderId)); + } + + Boolean execute = transactionTemplate.execute(e -> { + // 日志 + storeOrderStatusService.createLog(storeOrder.getId(), "user_take_delivery", Constants.ORDER_STATUS_STR_TAKE); + return Boolean.TRUE; + }); + //TODO 发送用户确认收货管理员提醒短信 + + return execute; } + + /** + * 发送消息通知 + * 根据用户类型发送 + * 公众号模板消息 + * 小程序订阅消息 + */ +// private void pushMessageOrder(StoreOrder storeOrder, MemberUserDO user) { +// SystemNotification notification = systemNotificationService.getByMark(NotifyConstants.RECEIPT_GOODS_MARK); +// if (storeOrder.getIsChannel().equals(2)) { +// return; +// } +// if (!storeOrder.getPayType().equals(Constants.PAY_TYPE_WE_CHAT)) { +// return; +// } +// UserToken userToken; +// HashMap temMap = new HashMap<>(); +// // 公众号 +// if (storeOrder.getIsChannel().equals(Constants.ORDER_PAY_CHANNEL_PUBLIC) && notification.getIsWechat().equals(1)) { +// userToken = userTokenService.getTokenByUserId(user.getUid(), UserConstants.USER_TOKEN_TYPE_WECHAT); +// if (ObjectUtil.isNull(userToken)) { +// return ; +// } +// // 发送微信模板消息 +// temMap.put(Constants.WE_CHAT_TEMP_KEY_FIRST, "您购买的商品已确认收货!"); +// temMap.put("keyword1", storeOrder.getOrderId()); +// temMap.put("keyword2", "已收货"); +// temMap.put("keyword3", DateUtils.nowDateTimeStr()); +// temMap.put("keyword4", "详情请进入订单查看"); +// temMap.put(Constants.WE_CHAT_TEMP_KEY_END, "感谢你的使用。"); +// templateMessageService.pushTemplateMessage(notification.getWechatId(), temMap, userToken.getToken()); +// } else if (notification.getIsRoutine().equals(1)) { +// // 小程序发送订阅消息 +// userToken = userTokenService.getTokenByUserId(user.getUid(), UserConstants.USER_TOKEN_TYPE_ROUTINE); +// if (ObjectUtil.isNull(userToken)) { +// return ; +// } +// // 组装数据 +// // 获取商品名称 +// String storeNameAndCarNumString = orderUtils.getStoreNameAndCarNumString(storeOrder.getId()); +// if (StrUtil.isBlank(storeNameAndCarNumString)) { +// return ; +// } +// if (storeNameAndCarNumString.length() > 20) { +// storeNameAndCarNumString = storeNameAndCarNumString.substring(0, 15) + "***"; +// } +//// temMap.put("character_string6", storeOrder.getOrderId()); +//// temMap.put("phrase4", "已收货"); +//// temMap.put("time7", DateUtil.nowDateTimeStr()); +//// temMap.put("thing1", storeNameAndCarNumString); +//// temMap.put("thing5", "您购买的商品已确认收货!"); +// temMap.put("character_string6", storeOrder.getOrderId()); +// temMap.put("date5", DateUtils.nowDateTimeStr()); +// temMap.put("thing2", storeNameAndCarNumString); +// templateMessageService.pushMiniTemplateMessage(notification.getRoutineId(), temMap, userToken.getToken()); +// } +// } } diff --git a/yudao-module-mall/yudao-module-shop-biz/src/main/java/cn/iocoder/yudao/module/shop/service/wechat/WechatNewService.java b/yudao-module-mall/yudao-module-shop-biz/src/main/java/cn/iocoder/yudao/module/shop/service/wechat/WechatNewService.java new file mode 100644 index 000000000..a0c4975c1 --- /dev/null +++ b/yudao-module-mall/yudao-module-shop-biz/src/main/java/cn/iocoder/yudao/module/shop/service/wechat/WechatNewService.java @@ -0,0 +1,28 @@ +package cn.iocoder.yudao.module.shop.service.wechat; + +import cn.iocoder.yudao.module.shop.controller.admin.order.vo.WxRefundResponseVo; +import cn.iocoder.yudao.module.shop.controller.admin.order.vo.WxRefundVo; + +/** + * 微信公用服务 + * +---------------------------------------------------------------------- + * | CRMEB [ CRMEB赋能开发者,助力企业发展 ] + * +---------------------------------------------------------------------- + * | Copyright (c) 2016~2022 https://www.crmeb.com All rights reserved. + * +---------------------------------------------------------------------- + * | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权 + * +---------------------------------------------------------------------- + * | Author: CRMEB Team + * +---------------------------------------------------------------------- + */ +public interface WechatNewService { + + /** + * 微信申请退款 + * @param wxRefundVo 微信申请退款对象 + * @param path 商户p12证书绝对路径 + * @return 申请退款结果对象 + */ + WxRefundResponseVo payRefund(WxRefundVo wxRefundVo, String path); + +} diff --git a/yudao-module-mall/yudao-module-shop-biz/src/main/java/cn/iocoder/yudao/module/shop/service/wechat/impl/WechatNewServiceImpl.java b/yudao-module-mall/yudao-module-shop-biz/src/main/java/cn/iocoder/yudao/module/shop/service/wechat/impl/WechatNewServiceImpl.java new file mode 100644 index 000000000..aa21dfb0d --- /dev/null +++ b/yudao-module-mall/yudao-module-shop-biz/src/main/java/cn/iocoder/yudao/module/shop/service/wechat/impl/WechatNewServiceImpl.java @@ -0,0 +1,102 @@ +package cn.iocoder.yudao.module.shop.service.wechat.impl; + +import cn.iocoder.yudao.framework.common.exception.ServiceException; +import cn.iocoder.yudao.module.shop.constants.WeChatConstants; +import cn.iocoder.yudao.module.shop.controller.admin.order.vo.WxRefundResponseVo; +import cn.iocoder.yudao.module.shop.controller.admin.order.vo.WxRefundVo; +import cn.iocoder.yudao.module.shop.service.wechat.WechatNewService; +import cn.iocoder.yudao.module.shop.utils.CrmebUtil; +import cn.iocoder.yudao.module.shop.utils.RedisUtil; +import cn.iocoder.yudao.module.shop.utils.RestTemplateUtil; +import cn.iocoder.yudao.module.shop.utils.XmlUtil; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.HashMap; + +/** + * 微信公用服务实现类 + * +---------------------------------------------------------------------- + * | CRMEB [ CRMEB赋能开发者,助力企业发展 ] + * +---------------------------------------------------------------------- + * | Copyright (c) 2016~2022 https://www.crmeb.com All rights reserved. + * +---------------------------------------------------------------------- + * | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权 + * +---------------------------------------------------------------------- + * | Author: CRMEB Team + * +---------------------------------------------------------------------- + */ +@Service +public class WechatNewServiceImpl implements WechatNewService { + private static final Logger logger = LoggerFactory.getLogger(WechatNewServiceImpl.class); + + @Autowired + private RedisUtil redisUtil; + + @Autowired + private RestTemplateUtil restTemplateUtil; + + + /** + * 微信申请退款 + * @param wxRefundVo 微信申请退款对象 + * @param path 商户p12证书绝对路径 + * @return 申请退款结果对象 + */ + @Override + public WxRefundResponseVo payRefund(WxRefundVo wxRefundVo, String path) { + String xmlStr = XmlUtil.objectToXml(wxRefundVo); + String url = WeChatConstants.PAY_API_URL + WeChatConstants.PAY_REFUND_API_URI_WECHAT; + HashMap map = new HashMap<>(); + String xml = ""; + try { + xml = restTemplateUtil.postWXRefundXml(url, xmlStr, wxRefundVo.getMch_id(), path); + map = XmlUtil.xmlToMap(xml); + } catch (Exception e) { + e.printStackTrace(); + throw new ServiceException("xmlToMap错误,xml = " + xml); + } + if (null == map) { + throw new ServiceException("微信无信息返回,微信申请退款失败!"); + } + + WxRefundResponseVo responseVo = CrmebUtil.mapToObj(map, WxRefundResponseVo.class); + if (responseVo.getReturnCode().toUpperCase().equals("FAIL")) { +// wxPayExceptionDispose(map, "微信申请退款异常1"); + throw new ServiceException("微信申请退款失败1!" + responseVo.getReturnMsg()); + } + + if (responseVo.getResultCode().toUpperCase().equals("FAIL")) { +// wxPayExceptionDispose(map, "微信申请退款业务异常"); + throw new ServiceException("微信申请退款失败2!" + responseVo.getErrCodeDes()); + } + System.out.println("================微信申请退款结束========================="); + return responseVo; + } + + /** + * 微信支付异常处理 + * @param map 微信返回数据 + * @param remark 备注 + */ +// private void wxPayExceptionDispose(HashMap map, String remark) { +// WechatExceptions wechatExceptions = new WechatExceptions(); +// String returnCode = (String) map.get("return_code"); +// if (returnCode.toUpperCase().equals("FAIL")) { +// wechatExceptions.setErrcode("-100"); +// wechatExceptions.setErrmsg(map.get("return_msg").toString()); +// } else { +// wechatExceptions.setErrcode(map.get("err_code").toString()); +// wechatExceptions.setErrmsg(map.get("err_code_des").toString()); +// } +// wechatExceptions.setData(JSONObject.toJSONString(map)); +// wechatExceptions.setRemark(remark); +// wechatExceptions.setCreateTime(DateUtil.date()); +// wechatExceptions.setUpdateTime(DateUtil.date()); +// wechatExceptionsService.save(wechatExceptions); +// } + +} + diff --git a/yudao-module-mall/yudao-module-shop-biz/src/main/java/cn/iocoder/yudao/module/shop/utils/CrmebUtil.java b/yudao-module-mall/yudao-module-shop-biz/src/main/java/cn/iocoder/yudao/module/shop/utils/CrmebUtil.java index cc5866f49..2715d1b30 100644 --- a/yudao-module-mall/yudao-module-shop-biz/src/main/java/cn/iocoder/yudao/module/shop/utils/CrmebUtil.java +++ b/yudao-module-mall/yudao-module-shop-biz/src/main/java/cn/iocoder/yudao/module/shop/utils/CrmebUtil.java @@ -3,6 +3,7 @@ package cn.iocoder.yudao.module.shop.utils; import cn.hutool.core.util.StrUtil; import cn.hutool.crypto.SecureUtil; import cn.iocoder.yudao.framework.common.enums.Constants; +import com.alibaba.fastjson.JSONObject; import org.apache.commons.lang3.StringUtils; import javax.crypto.Cipher; @@ -51,6 +52,19 @@ public class CrmebUtil { return new String(result, StandardCharsets.UTF_8); } + /** + * map转对象 + * @param map map + * @param clz 对象 + * @author Mr.Zhang + * @since 2020-04-14 + * @return Map + */ + public static T mapToObj(HashMap map, Class clz){ + if (map == null) return null; + return JSONObject.parseObject(JSONObject.toJSONString(map), clz); + } + /** * 获得DES加密秘钥 * @param key diff --git a/yudao-module-mall/yudao-module-shop-biz/src/main/java/cn/iocoder/yudao/module/shop/utils/RestTemplateUtil.java b/yudao-module-mall/yudao-module-shop-biz/src/main/java/cn/iocoder/yudao/module/shop/utils/RestTemplateUtil.java new file mode 100644 index 000000000..9cf42f6b1 --- /dev/null +++ b/yudao-module-mall/yudao-module-shop-biz/src/main/java/cn/iocoder/yudao/module/shop/utils/RestTemplateUtil.java @@ -0,0 +1,111 @@ +package cn.iocoder.yudao.module.shop.utils; + +import org.apache.http.HttpResponse; +import org.apache.http.client.HttpClient; +import org.apache.http.client.config.RequestConfig; +import org.apache.http.client.methods.HttpPost; +import org.apache.http.config.RegistryBuilder; +import org.apache.http.conn.socket.ConnectionSocketFactory; +import org.apache.http.conn.socket.PlainConnectionSocketFactory; +import org.apache.http.conn.ssl.DefaultHostnameVerifier; +import org.apache.http.conn.ssl.SSLConnectionSocketFactory; +import org.apache.http.entity.StringEntity; +import org.apache.http.impl.client.HttpClientBuilder; +import org.apache.http.impl.conn.BasicHttpClientConnectionManager; +import org.apache.http.util.EntityUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; +import org.springframework.web.client.RestTemplate; + +import javax.net.ssl.KeyManagerFactory; +import javax.net.ssl.SSLContext; +import java.io.FileInputStream; +import java.security.KeyStore; +import java.security.SecureRandom; + + +/** + * +---------------------------------------------------------------------- + * | CRMEB [ CRMEB赋能开发者,助力企业发展 ] + * +---------------------------------------------------------------------- + * | Copyright (c) 2016~2022 https://www.crmeb.com All rights reserved. + * +---------------------------------------------------------------------- + * | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权 + * +---------------------------------------------------------------------- + * | Author: CRMEB Team + * +---------------------------------------------------------------------- + * httpClient 工具类 + */ + +@Component +public class RestTemplateUtil { + + @Autowired + private RestTemplate restTemplate; + + public static final String WXPAYSDK_VERSION = "WXPaySDK/3.0.9"; + public static final String USER_AGENT = WXPAYSDK_VERSION + + " (" + System.getProperty("os.arch") + " " + System.getProperty("os.name") + " " + System.getProperty("os.version") + + ") Java/" + System.getProperty("java.version") + " HttpClient/" + HttpClient.class.getPackage().getImplementationVersion(); + /** + * 发送POST-JSON请求(微信退款专用) + * + * @param url + * @return + */ + + public String postWXRefundXml(String url, String xml, String mchId, String path) throws Exception { + KeyStore clientStore = KeyStore.getInstance("PKCS12"); + // 读取本机存放的PKCS12证书文件 + FileInputStream instream = new FileInputStream(path); + try { + // 指定PKCS12的密码(商户ID) + clientStore.load(instream, mchId.toCharArray()); + } finally { + instream.close(); + } + + // 实例化密钥库 & 初始化密钥工厂 + KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm()); + kmf.init(clientStore, mchId.toCharArray()); + + // 创建 SSLContext + SSLContext sslContext = SSLContext.getInstance("TLS"); + sslContext.init(kmf.getKeyManagers(), null, new SecureRandom()); + + SSLConnectionSocketFactory sslConnectionSocketFactory = new SSLConnectionSocketFactory( + sslContext, +// new String[]{"TLSv1"}, +// null, + new DefaultHostnameVerifier()); + + BasicHttpClientConnectionManager connManager = new BasicHttpClientConnectionManager( + RegistryBuilder.create() + .register("http", PlainConnectionSocketFactory.getSocketFactory()) + .register("https", sslConnectionSocketFactory) + .build(), + null, + null, + null + ); + + HttpClient httpClient = HttpClientBuilder.create() + .setConnectionManager(connManager) + .build(); + + HttpPost httpPost = new HttpPost(url); + + RequestConfig requestConfig = RequestConfig.custom().setSocketTimeout(8*1000).setConnectTimeout(6*1000).build(); + httpPost.setConfig(requestConfig); + + StringEntity postEntity = new StringEntity(xml, "UTF-8"); + httpPost.addHeader("Content-Type", "text/xml"); + httpPost.addHeader("User-Agent", USER_AGENT + " " + mchId); + httpPost.setEntity(postEntity); + + HttpResponse httpResponse = httpClient.execute(httpPost); + org.apache.http.HttpEntity httpEntity = httpResponse.getEntity(); + return EntityUtils.toString(httpEntity, "UTF-8"); + } + +} diff --git a/yudao-module-mall/yudao-module-shop-biz/src/main/java/cn/iocoder/yudao/module/shop/utils/WxPayUtil.java b/yudao-module-mall/yudao-module-shop-biz/src/main/java/cn/iocoder/yudao/module/shop/utils/WxPayUtil.java new file mode 100644 index 000000000..4c8e1bd2a --- /dev/null +++ b/yudao-module-mall/yudao-module-shop-biz/src/main/java/cn/iocoder/yudao/module/shop/utils/WxPayUtil.java @@ -0,0 +1,88 @@ +package cn.iocoder.yudao.module.shop.utils; + +import cn.hutool.core.util.ObjectUtil; +import cn.hutool.core.util.StrUtil; +import cn.hutool.crypto.SecureUtil; +import cn.iocoder.yudao.module.shop.constants.PayConstants; +import cn.iocoder.yudao.module.shop.controller.admin.order.vo.WxRefundVo; +import com.alibaba.fastjson.JSONObject; +import org.apache.commons.codec.digest.DigestUtils; + +import java.util.Arrays; +import java.util.Map; +import java.util.Set; + +/** + * 微信支付工具类 + * +---------------------------------------------------------------------- + * | CRMEB [ CRMEB赋能开发者,助力企业发展 ] + * +---------------------------------------------------------------------- + * | Copyright (c) 2016~2022 https://www.crmeb.com All rights reserved. + * +---------------------------------------------------------------------- + * | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权 + * +---------------------------------------------------------------------- + * | Author: CRMEB Team + * +---------------------------------------------------------------------- + */ +public class WxPayUtil { + + /** + * 获取sign + * @param wxRefundVo 微信退款对象 + * @param signKey 微信签名key + * @return String + */ + public static String getSign(WxRefundVo wxRefundVo, String signKey) { + // 对象转map + Map map = JSONObject.parseObject(JSONObject.toJSONString(wxRefundVo), Map.class); + // map排序 + Set keySet = map.keySet(); + String[] keyArray = keySet.toArray(new String[keySet.size()]); + Arrays.sort(keyArray); + StringBuilder sb = new StringBuilder(); + for (String k : keyArray) { + if (k.equals(PayConstants.FIELD_SIGN)) { + continue; + } + if (ObjectUtil.isNotNull(map.get(k))) // 参数值为空,则不参与签名 + sb.append(k).append("=").append(map.get(k)).append("&"); + } + sb.append("key=").append(signKey); + String sign = SecureUtil.md5(sb.toString()).toUpperCase(); + System.out.println("sign ========== " + sign); + return sign; + } + + /** + * 获取sign + * @param map 待签名数据 + * @param signKey 微信签名key + * @return String + */ + public static String getSign(Map map, String signKey) { + // map排序 + Set keySet = map.keySet(); + String[] keyArray = keySet.toArray(new String[keySet.size()]); + Arrays.sort(keyArray); + StringBuilder sb = new StringBuilder(); + for (String k : keyArray) { + if (k.equals(PayConstants.FIELD_SIGN)) { + continue; + } + if (StrUtil.isNotBlank(map.get(k)) && map.get(k).trim().length() > 0) // 参数值为空,则不参与签名 + sb.append(k).append("=").append(map.get(k).trim()).append("&"); + } + sb.append("key=").append(signKey); + String sign = SecureUtil.md5(sb.toString()).toUpperCase(); + System.out.println("sign ========== " + sign); + return sign; + } + + /** + * 获取随机字符串,长度要求在32位以内。 + */ + public static String getNonceStr() { + return DigestUtils.md5Hex(CrmebUtil.getUuid() + CrmebUtil.randomCount(111111, 666666)); + } + +} diff --git a/yudao-module-mall/yudao-module-shop-biz/src/main/java/cn/iocoder/yudao/module/shop/utils/XmlUtil.java b/yudao-module-mall/yudao-module-shop-biz/src/main/java/cn/iocoder/yudao/module/shop/utils/XmlUtil.java new file mode 100644 index 000000000..6427c5d3a --- /dev/null +++ b/yudao-module-mall/yudao-module-shop-biz/src/main/java/cn/iocoder/yudao/module/shop/utils/XmlUtil.java @@ -0,0 +1,95 @@ +package cn.iocoder.yudao.module.shop.utils; + +import com.thoughtworks.xstream.XStream; +import com.thoughtworks.xstream.io.naming.NoNameCoder; +import com.thoughtworks.xstream.io.xml.Xpp3Driver; +import org.apache.commons.lang3.StringUtils; +import org.dom4j.Document; +import org.dom4j.DocumentException; +import org.dom4j.Element; +import org.dom4j.io.SAXReader; + +import javax.servlet.http.HttpServletRequest; +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.nio.charset.StandardCharsets; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * XML 工具类 + * +---------------------------------------------------------------------- + * | CRMEB [ CRMEB赋能开发者,助力企业发展 ] + * +---------------------------------------------------------------------- + * | Copyright (c) 2016~2022 https://www.crmeb.com All rights reserved. + * +---------------------------------------------------------------------- + * | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权 + * +---------------------------------------------------------------------- + * | Author: CRMEB Team + * +---------------------------------------------------------------------- + */ +public class XmlUtil { + public static Map xmlToMap(HttpServletRequest request) { + Map map = new HashMap<>(); + SAXReader reader = new SAXReader(); + + InputStream in = null; + try { + in = request.getInputStream(); + Document doc = reader.read(in); + Element root = doc.getRootElement(); + List list = root.elements(); + for (Element element : list) { + map.put(element.getName(), element.getText()); + } + } catch (IOException | DocumentException e) { + e.printStackTrace(); + } finally { + try { + assert in != null; + in.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + return map; + } + + /** + * 将发送消息封装成对应的xml格式 + */ + public static HashMap xmlToMap(String strxml) throws Exception { + strxml = strxml.replaceFirst("encoding=\".*\"", "encoding=\"UTF-8\""); + + HashMap map = new HashMap<>(); + SAXReader reader = new SAXReader(); + InputStream inputStream = new ByteArrayInputStream(strxml.getBytes(StandardCharsets.UTF_8)); + + if (StringUtils.isBlank(strxml)) { + return null; + } + + Document document = reader.read(inputStream); + Element root = document.getRootElement(); + List list = root.elements(); + + for (Element e : list) { + map.put(e.getName(), e.getText()); + } + inputStream.close(); + + return map; + } + + /** + * 将发送消息封装成对应的xml格式 + */ + public static String objectToXml(Object object) { + XStream xstream = new XStream(new Xpp3Driver(new NoNameCoder())); //不需要转义 + xstream.alias("xml", object.getClass()); + return xstream.toXML(object); + } + +}