Skip to content
项目
群组
代码片段
帮助
当前项目
正在载入...
登录 / 注册
切换导航面板
Y
yudao-cloud
项目
项目
详情
活动
周期分析
仓库
仓库
文件
提交
分支
标签
贡献者
图表
比较
统计图
议题
0
议题
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
CI / CD
CI / CD
流水线
作业
日程
统计图
Wiki
Wiki
代码片段
代码片段
成员
成员
折叠边栏
关闭边栏
活动
图像
聊天
创建新问题
作业
提交
问题看板
Open sidebar
hblj
yudao-cloud
Commits
207fdc1d
提交
207fdc1d
authored
4月 26, 2019
作者:
YunaiV
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
后端:完成退款逻辑
上级
1be40cb1
隐藏空白字符变更
内嵌
并排
正在显示
27 个修改的文件
包含
446 行增加
和
335 行删除
+446
-335
OrderReturnService.java
...in/java/cn/iocoder/mall/order/api/OrderReturnService.java
+12
-1
OrderReturnServiceImpl.java
...ocoder/mall/order/biz/service/OrderReturnServiceImpl.java
+5
-0
OrderServiceImpl.java
...a/cn/iocoder/mall/order/biz/service/OrderServiceImpl.java
+5
-3
AbstractPayNotifySuccessMessage.java
...mall/pay/api/message/AbstractPayNotifySuccessMessage.java
+26
-0
PayRefundSuccessMessage.java
...iocoder/mall/pay/api/message/PayRefundSuccessMessage.java
+6
-71
PayTransactionSuccessMessage.java
...er/mall/pay/api/message/PayTransactionSuccessMessage.java
+6
-71
PingxxPaySDK.java
...ain/java/cn/iocoder/mall/pay/biz/client/PingxxPaySDK.java
+15
-3
DubboReferencePool.java
...cn/iocoder/mall/pay/biz/component/DubboReferencePool.java
+66
-0
PayNotifyConvert.java
...ava/cn/iocoder/mall/pay/biz/convert/PayNotifyConvert.java
+29
-0
PayRefundConvert.java
...ava/cn/iocoder/mall/pay/biz/convert/PayRefundConvert.java
+17
-0
PayTransactionConvert.java
...n/iocoder/mall/pay/biz/convert/PayTransactionConvert.java
+0
-22
PayNotifyLogMapper.java
.../java/cn/iocoder/mall/pay/biz/dao/PayNotifyLogMapper.java
+1
-1
PayNotifyTaskMapper.java
...java/cn/iocoder/mall/pay/biz/dao/PayNotifyTaskMapper.java
+1
-1
PayNotifyJob.java
...c/main/java/cn/iocoder/mall/pay/biz/job/PayNotifyJob.java
+12
-11
AbstractPayNotifySuccessConsumer.java
...der/mall/pay/biz/mq/AbstractPayNotifySuccessConsumer.java
+82
-0
PayRefundSuccessConsumer.java
.../cn/iocoder/mall/pay/biz/mq/PayRefundSuccessConsumer.java
+45
-0
PayTransactionSuccessConsumer.java
...ocoder/mall/pay/biz/mq/PayTransactionSuccessConsumer.java
+13
-120
PayNotifyServiceImpl.java
...cn/iocoder/mall/pay/biz/service/PayNotifyServiceImpl.java
+18
-7
PayRefundServiceImpl.java
...cn/iocoder/mall/pay/biz/service/PayRefundServiceImpl.java
+9
-6
PayTransactionServiceImpl.java
...coder/mall/pay/biz/service/PayTransactionServiceImpl.java
+2
-2
PayNotifyLogMapper.xml
...ice-impl/src/main/resources/mapper/PayNotifyLogMapper.xml
+2
-2
PayNotifyTaskMapper.xml
...ce-impl/src/main/resources/mapper/PayNotifyTaskMapper.xml
+22
-10
PayRefundMapper.xml
...ervice-impl/src/main/resources/mapper/PayRefundMapper.xml
+1
-1
PayTransactionMapper.xml
...e-impl/src/main/resources/mapper/PayTransactionMapper.xml
+2
-2
PayRefundServiceImplTest.java
...ocoder/mall/pay/biz/service/PayRefundServiceImplTest.java
+29
-0
PayTransactionServiceImplTest.java
...r/mall/pay/biz/service/PayTransactionServiceImplTest.java
+17
-0
CouponService.java
...ain/java/cn/iocoder/mall/promotion/api/CouponService.java
+3
-1
没有找到文件。
order/order-service-api/src/main/java/cn/iocoder/mall/order/api/OrderReturnService.java
浏览文件 @
207fdc1d
...
...
@@ -2,7 +2,6 @@ package cn.iocoder.mall.order.api;
import
cn.iocoder.common.framework.vo.CommonResult
;
import
cn.iocoder.mall.order.api.dto.OrderReturnApplyDTO
;
import
cn.iocoder.mall.order.api.dto.OrderReturnCreateDTO
;
/**
* 订单退货
...
...
@@ -21,4 +20,16 @@ public interface OrderReturnService {
*/
CommonResult
orderReturnApply
(
OrderReturnApplyDTO
orderReturnApplyDTO
);
/**
* 更新退款成功
*
* 如果成功,则返回 success
* 如果失败,则返回具体原因
*
* @param orderId 订单编号
* @param refundPrice 退款金额
* @return 支付结果
*/
String
updateRefundSuccess
(
String
orderId
,
Integer
refundPrice
);
}
order/order-service-impl/src/main/java/cn/iocoder/mall/order/biz/service/OrderReturnServiceImpl.java
浏览文件 @
207fdc1d
...
...
@@ -52,4 +52,9 @@ public class OrderReturnServiceImpl implements OrderReturnService {
orderReturnMapper
.
insert
(
orderReturnDO
);
return
CommonResult
.
success
(
null
);
}
@Override
public
String
updateRefundSuccess
(
String
orderId
,
Integer
refundPrice
)
{
return
"success"
;
}
}
order/order-service-impl/src/main/java/cn/iocoder/mall/order/biz/service/OrderServiceImpl.java
浏览文件 @
207fdc1d
...
...
@@ -258,9 +258,11 @@ public class OrderServiceImpl implements OrderService {
}
// 标记优惠劵已使用
CommonResult
<
Boolean
>
useCouponCardResult
=
couponService
.
useCouponCard
(
userId
,
orderCreateDTO
.
getCouponCardId
());
if
(
useCouponCardResult
.
isError
())
{
return
CommonResult
.
error
(
useCouponCardResult
);
if
(
orderCreateDTO
.
getCouponCardId
()
!=
null
)
{
CommonResult
<
Boolean
>
useCouponCardResult
=
couponService
.
useCouponCard
(
userId
,
orderCreateDTO
.
getCouponCardId
());
if
(
useCouponCardResult
.
isError
())
{
return
CommonResult
.
error
(
useCouponCardResult
);
}
}
// TODO 芋艿,扣除库存
...
...
pay/pay-service-api/src/main/java/cn/iocoder/mall/pay/api/message/AbstractPayNotifySuccessMessage.java
0 → 100644
浏览文件 @
207fdc1d
package
cn
.
iocoder
.
mall
.
pay
.
api
.
message
;
import
lombok.Data
;
import
lombok.experimental.Accessors
;
@Data
@Accessors
(
chain
=
true
)
public
class
AbstractPayNotifySuccessMessage
{
/**
* 任务编号
*/
private
Integer
id
;
/**
* 应用编号
*/
private
String
appId
;
/**
* 当前通知次数
*/
private
Integer
notifyTimes
;
/**
* 通知地址
*/
private
String
notifyUrl
;
}
pay/pay-service-api/src/main/java/cn/iocoder/mall/pay/api/message/PayRefundSuccessMessage.java
浏览文件 @
207fdc1d
package
cn
.
iocoder
.
mall
.
pay
.
api
.
message
;
import
lombok.Data
;
import
lombok.experimental.Accessors
;
/**
* 支付退款成功的消息对象
*/
public
class
PayRefundSuccessMessage
{
@Data
@Accessors
(
chain
=
true
)
public
class
PayRefundSuccessMessage
extends
AbstractPayNotifySuccessMessage
{
public
static
final
String
TOPIC
=
"PAY_REFUND_SUCCESS"
;
/**
* 任务编号
*/
private
Integer
id
;
/**
* 退款单编号
*/
...
...
@@ -19,75 +20,9 @@ public class PayRefundSuccessMessage {
* 交易编号
*/
private
Integer
transactionId
;
/**
* 应用编号
*/
private
String
appId
;
/**
* 应用订单编号
*/
private
String
orderId
;
/**
* 当前通知次数
*/
private
Integer
notifyTimes
;
/**
* 通知地址
*/
private
String
notifyUrl
;
public
Integer
getId
()
{
return
id
;
}
public
PayRefundSuccessMessage
setId
(
Integer
id
)
{
this
.
id
=
id
;
return
this
;
}
public
String
getAppId
()
{
return
appId
;
}
public
PayRefundSuccessMessage
setAppId
(
String
appId
)
{
this
.
appId
=
appId
;
return
this
;
}
public
String
getOrderId
()
{
return
orderId
;
}
public
PayRefundSuccessMessage
setOrderId
(
String
orderId
)
{
this
.
orderId
=
orderId
;
return
this
;
}
public
Integer
getNotifyTimes
()
{
return
notifyTimes
;
}
public
PayRefundSuccessMessage
setNotifyTimes
(
Integer
notifyTimes
)
{
this
.
notifyTimes
=
notifyTimes
;
return
this
;
}
public
String
getNotifyUrl
()
{
return
notifyUrl
;
}
public
PayRefundSuccessMessage
setNotifyUrl
(
String
notifyUrl
)
{
this
.
notifyUrl
=
notifyUrl
;
return
this
;
}
public
Integer
getTransactionId
()
{
return
transactionId
;
}
public
PayRefundSuccessMessage
setTransactionId
(
Integer
transactionId
)
{
this
.
transactionId
=
transactionId
;
return
this
;
}
}
pay/pay-service-api/src/main/java/cn/iocoder/mall/pay/api/message/PayTransactionSuccessMessage.java
浏览文件 @
207fdc1d
package
cn
.
iocoder
.
mall
.
pay
.
api
.
message
;
import
lombok.Data
;
import
lombok.experimental.Accessors
;
/**
* 支付交易单支付成功的消息对象
*/
public
class
PayTransactionSuccessMessage
{
@Data
@Accessors
(
chain
=
true
)
public
class
PayTransactionSuccessMessage
extends
AbstractPayNotifySuccessMessage
{
public
static
final
String
TOPIC
=
"PAY_TRANSACTION_SUCCESS"
;
/**
* 任务编号
*/
private
Integer
id
;
/**
* 交易编号
*/
private
Integer
transactionId
;
/**
* 应用编号
*/
private
String
appId
;
/**
* 应用订单编号
*/
private
String
orderId
;
/**
* 当前通知次数
*/
private
Integer
notifyTimes
;
/**
* 通知地址
*/
private
String
notifyUrl
;
public
Integer
getId
()
{
return
id
;
}
public
PayTransactionSuccessMessage
setId
(
Integer
id
)
{
this
.
id
=
id
;
return
this
;
}
public
String
getAppId
()
{
return
appId
;
}
public
PayTransactionSuccessMessage
setAppId
(
String
appId
)
{
this
.
appId
=
appId
;
return
this
;
}
public
String
getOrderId
()
{
return
orderId
;
}
public
PayTransactionSuccessMessage
setOrderId
(
String
orderId
)
{
this
.
orderId
=
orderId
;
return
this
;
}
public
Integer
getNotifyTimes
()
{
return
notifyTimes
;
}
public
PayTransactionSuccessMessage
setNotifyTimes
(
Integer
notifyTimes
)
{
this
.
notifyTimes
=
notifyTimes
;
return
this
;
}
public
String
getNotifyUrl
()
{
return
notifyUrl
;
}
public
PayTransactionSuccessMessage
setNotifyUrl
(
String
notifyUrl
)
{
this
.
notifyUrl
=
notifyUrl
;
return
this
;
}
public
Integer
getTransactionId
()
{
return
transactionId
;
}
public
PayTransactionSuccessMessage
setTransactionId
(
Integer
transactionId
)
{
this
.
transactionId
=
transactionId
;
return
this
;
}
}
pay/pay-service-impl/src/main/java/cn/iocoder/mall/pay/biz/client/PingxxPaySDK.java
浏览文件 @
207fdc1d
...
...
@@ -84,7 +84,7 @@ public class PingxxPaySDK extends AbstractPaySDK {
JSONObject
chargeObj
=
paramsObj
.
getJSONObject
(
"data"
).
getJSONObject
(
"object"
);
String
chargeId
=
chargeObj
.
getString
(
"id"
);
// 请求ping++
Map
<
String
,
Object
>
reqObj
=
createRefundRequest
(
chargeId
,
refund
.
getOrderDescription
(),
refund
.
getPrice
());
Map
<
String
,
Object
>
reqObj
=
createRefundRequest
(
refund
,
chargeId
,
refund
.
getOrderDescription
(),
refund
.
getPrice
());
try
{
Refund
pingxxRefund
=
Refund
.
create
(
chargeId
,
reqObj
);
System
.
out
.
println
(
pingxxRefund
.
toString
());
...
...
@@ -97,16 +97,28 @@ public class PingxxPaySDK extends AbstractPaySDK {
}
}
// {"id":"evt_400190427005305341228202","created":1556297585,"livemode":false,"type":"refund.succeeded","data":{"object":{"id":"re_HO0m9GOGOi50KCmX104ufHe1","object":"refund","order_no":"HO0m9GOGOi50KCmX104ufHe1","amount":1,"created":1556297585,"succeed":true,"status":"succeeded","time_succeed":1556297585,"description":"测试下退款","failure_code":null,"failure_msg":null,"metadata":{},"charge":"ch_y1iXjLnDS4G4OO4uT4a5C4W1","charge_order_no":"20190427004410165545","transaction_no":"201904270053053608824","extra":{}}},"object":"event","request":"iar_Oa188KCiHC40iLibbHX5WrHC","pending_webhooks":0}
@Override
public
CommonResult
<
RefundSuccessBO
>
parseRefundSuccessParams
(
String
params
)
{
return
null
;
JSONObject
paramsObj
=
JSON
.
parseObject
(
params
);
JSONObject
chargeObj
=
paramsObj
.
getJSONObject
(
"data"
).
getJSONObject
(
"object"
);
RefundSuccessBO
refundSuccessBO
=
new
RefundSuccessBO
()
.
setRefundCode
(
chargeObj
.
getJSONObject
(
"metadata"
).
getString
(
"refundCode"
))
.
setRefundTime
(
new
Date
(
chargeObj
.
getLong
(
"time_succeed"
)
*
1000
))
.
setTradeNo
(
chargeObj
.
getString
(
"transaction_no"
))
// TODO 芋艿,需要测试下,退款失败
.
setSuccess
(
chargeObj
.
containsValue
(
"failure_code"
)
||
chargeObj
.
containsValue
(
"failure_msg"
));
return
CommonResult
.
success
(
refundSuccessBO
);
}
private
Map
<
String
,
Object
>
createRefundRequest
(
String
chargeId
,
String
orderDescription
,
Integer
price
)
{
private
Map
<
String
,
Object
>
createRefundRequest
(
PayRefundDO
refund
,
String
chargeId
,
String
orderDescription
,
Integer
price
)
{
Map
<
String
,
Object
>
reqObj
=
new
HashMap
<>();
// reqObj.put("CHARGE_ID", chargeId);
reqObj
.
put
(
"description"
,
orderDescription
);
reqObj
.
put
(
"amount"
,
price
);
Map
<
String
,
Object
>
metadata
=
new
HashMap
<>();
metadata
.
put
(
"refundCode"
,
refund
.
getRefundCode
());
reqObj
.
put
(
"metadata"
,
metadata
);
return
reqObj
;
}
...
...
pay/pay-service-impl/src/main/java/cn/iocoder/mall/pay/biz/component/DubboReferencePool.java
浏览文件 @
207fdc1d
package
cn
.
iocoder
.
mall
.
pay
.
biz
.
component
;
import
com.alibaba.dubbo.config.ApplicationConfig
;
import
com.alibaba.dubbo.config.ReferenceConfig
;
import
com.alibaba.dubbo.config.RegistryConfig
;
import
com.alibaba.dubbo.rpc.service.GenericService
;
import
com.google.common.cache.CacheBuilder
;
import
com.google.common.cache.CacheLoader
;
import
com.google.common.cache.LoadingCache
;
import
lombok.Data
;
import
org.springframework.beans.factory.annotation.Value
;
import
org.springframework.stereotype.Component
;
import
org.springframework.util.Assert
;
@Component
public
class
DubboReferencePool
{
@Data
public
class
ReferenceMeta
{
private
final
ReferenceConfig
config
;
// TODO 芋艿,后续需要做销毁
private
final
GenericService
service
;
private
final
String
methodName
;
private
ReferenceMeta
(
ReferenceConfig
config
,
GenericService
service
,
String
methodName
)
{
this
.
config
=
config
;
this
.
service
=
service
;
this
.
methodName
=
methodName
;
}
}
private
LoadingCache
<
String
,
ReferenceMeta
>
referenceMetaCache
=
CacheBuilder
.
newBuilder
()
.
build
(
new
CacheLoader
<
String
,
ReferenceMeta
>()
{
@Override
public
ReferenceMeta
load
(
String
notifyUrl
)
{
return
createGenericService
(
notifyUrl
);
}
});
@Value
(
"${dubbo.registry.address}"
)
private
String
dubboRegistryAddress
;
@Value
(
"${dubbo.application.name}"
)
private
String
dubboApplicationName
;
private
ReferenceMeta
createGenericService
(
String
notifyUrl
)
{
String
[]
notifyUrlParts
=
notifyUrl
.
split
(
"#"
);
// 创建 ApplicationConfig 对象
ApplicationConfig
application
=
new
ApplicationConfig
();
application
.
setName
(
dubboApplicationName
);
// 创建 RegistryConfig 对象
RegistryConfig
registry
=
new
RegistryConfig
();
// registry.setAddress("zookeeper://127.0.0.1:2181");
registry
.
setAddress
(
dubboRegistryAddress
);
application
.
setRegistry
(
registry
);
// 创建 ReferenceConfig 对象
ReferenceConfig
<
GenericService
>
reference
=
new
ReferenceConfig
<>();
reference
.
setInterface
(
notifyUrlParts
[
0
]);
// 弱类型接口名
reference
.
setGeneric
(
true
);
// 声明为泛化接口
reference
.
setApplication
(
application
);
// 获得 GenericService 对象
GenericService
genericService
=
reference
.
get
();
// 构建最终的 ReferenceMeta 对象
return
new
ReferenceMeta
(
reference
,
genericService
,
notifyUrlParts
[
1
]);
}
public
ReferenceMeta
getReferenceMeta
(
String
notifyUrl
)
{
DubboReferencePool
.
ReferenceMeta
referenceMeta
=
referenceMetaCache
.
getUnchecked
(
notifyUrl
);
Assert
.
notNull
(
referenceMeta
,
String
.
format
(
"notifyUrl(%s) 不存在对应的 ReferenceMeta 对象"
,
notifyUrl
));
return
referenceMeta
;
}
}
pay/pay-service-impl/src/main/java/cn/iocoder/mall/pay/biz/convert/PayNotifyConvert.java
0 → 100644
浏览文件 @
207fdc1d
package
cn
.
iocoder
.
mall
.
pay
.
biz
.
convert
;
import
cn.iocoder.mall.pay.api.message.PayRefundSuccessMessage
;
import
cn.iocoder.mall.pay.api.message.PayTransactionSuccessMessage
;
import
cn.iocoder.mall.pay.biz.dataobject.PayNotifyTaskDO
;
import
org.mapstruct.Mapper
;
import
org.mapstruct.Mapping
;
import
org.mapstruct.Mappings
;
import
org.mapstruct.factory.Mappers
;
@Mapper
public
interface
PayNotifyConvert
{
PayNotifyConvert
INSTANCE
=
Mappers
.
getMapper
(
PayNotifyConvert
.
class
);
@Mappings
({
@Mapping
(
source
=
"transaction.transactionId"
,
target
=
"transactionId"
),
@Mapping
(
source
=
"transaction.orderId"
,
target
=
"orderId"
),
})
PayTransactionSuccessMessage
convertTransaction
(
PayNotifyTaskDO
payTransactionNotifyTaskDO
);
@Mappings
({
@Mapping
(
source
=
"refund.transactionId"
,
target
=
"transactionId"
),
@Mapping
(
source
=
"refund.orderId"
,
target
=
"orderId"
),
@Mapping
(
source
=
"refund.refundId"
,
target
=
"refundId"
),
})
PayRefundSuccessMessage
convertRefund
(
PayNotifyTaskDO
payTransactionNotifyTaskDO
);
}
pay/pay-service-impl/src/main/java/cn/iocoder/mall/pay/biz/convert/PayRefundConvert.java
0 → 100644
浏览文件 @
207fdc1d
package
cn
.
iocoder
.
mall
.
pay
.
biz
.
convert
;
import
cn.iocoder.mall.pay.api.dto.PayRefundSubmitDTO
;
import
cn.iocoder.mall.pay.biz.dataobject.PayRefundDO
;
import
org.mapstruct.Mapper
;
import
org.mapstruct.Mappings
;
import
org.mapstruct.factory.Mappers
;
@Mapper
public
interface
PayRefundConvert
{
PayRefundConvert
INSTANCE
=
Mappers
.
getMapper
(
PayRefundConvert
.
class
);
@Mappings
({})
PayRefundDO
convert
(
PayRefundSubmitDTO
payRefundSubmitDTO
);
}
pay/pay-service-impl/src/main/java/cn/iocoder/mall/pay/biz/convert/PayTransactionConvert.java
浏览文件 @
207fdc1d
package
cn
.
iocoder
.
mall
.
pay
.
biz
.
convert
;
import
cn.iocoder.mall.pay.api.bo.PayTransactionBO
;
import
cn.iocoder.mall.pay.api.dto.PayRefundSubmitDTO
;
import
cn.iocoder.mall.pay.api.dto.PayTransactionCreateDTO
;
import
cn.iocoder.mall.pay.api.dto.PayTransactionSubmitDTO
;
import
cn.iocoder.mall.pay.api.message.PayRefundSuccessMessage
;
import
cn.iocoder.mall.pay.api.message.PayTransactionSuccessMessage
;
import
cn.iocoder.mall.pay.biz.dataobject.PayRefundDO
;
import
cn.iocoder.mall.pay.biz.dataobject.PayTransactionDO
;
import
cn.iocoder.mall.pay.biz.dataobject.PayTransactionExtensionDO
;
import
cn.iocoder.mall.pay.biz.dataobject.PayNotifyTaskDO
;
import
org.mapstruct.Mapper
;
import
org.mapstruct.Mapping
;
import
org.mapstruct.Mappings
;
import
org.mapstruct.factory.Mappers
;
...
...
@@ -29,20 +23,4 @@ public interface PayTransactionConvert {
@Mappings
({})
PayTransactionExtensionDO
convert
(
PayTransactionSubmitDTO
payTransactionSubmitDTO
);
@Mappings
({
@Mapping
(
source
=
"transaction.transactionId"
,
target
=
"transactionId"
),
@Mapping
(
source
=
"transaction.orderId"
,
target
=
"orderId"
),
})
PayTransactionSuccessMessage
convert
(
PayNotifyTaskDO
payTransactionNotifyTaskDO
);
@Mappings
({
@Mapping
(
source
=
"refund.transactionId"
,
target
=
"transactionId"
),
@Mapping
(
source
=
"refund.orderId"
,
target
=
"orderId"
),
@Mapping
(
source
=
"refund.refundId"
,
target
=
"refundId"
),
})
PayRefundSuccessMessage
convert2
(
PayNotifyTaskDO
payTransactionNotifyTaskDO
);
@Mappings
({})
PayRefundDO
convert
(
PayRefundSubmitDTO
payRefundSubmitDTO
);
}
pay/pay-service-impl/src/main/java/cn/iocoder/mall/pay/biz/dao/Pay
Transaction
NotifyLogMapper.java
→
pay/pay-service-impl/src/main/java/cn/iocoder/mall/pay/biz/dao/PayNotifyLogMapper.java
浏览文件 @
207fdc1d
...
...
@@ -4,7 +4,7 @@ import cn.iocoder.mall.pay.biz.dataobject.PayNotifyLogDO;
import
org.springframework.stereotype.Repository
;
@Repository
public
interface
Pay
Transaction
NotifyLogMapper
{
public
interface
PayNotifyLogMapper
{
void
insert
(
PayNotifyLogDO
entity
);
...
...
pay/pay-service-impl/src/main/java/cn/iocoder/mall/pay/biz/dao/Pay
Transaction
NotifyTaskMapper.java
→
pay/pay-service-impl/src/main/java/cn/iocoder/mall/pay/biz/dao/PayNotifyTaskMapper.java
浏览文件 @
207fdc1d
...
...
@@ -6,7 +6,7 @@ import org.springframework.stereotype.Repository;
import
java.util.List
;
@Repository
public
interface
Pay
Transaction
NotifyTaskMapper
{
public
interface
PayNotifyTaskMapper
{
void
insert
(
PayNotifyTaskDO
entity
);
...
...
pay/pay-service-impl/src/main/java/cn/iocoder/mall/pay/biz/
scheduler/PayTransaction
NotifyJob.java
→
pay/pay-service-impl/src/main/java/cn/iocoder/mall/pay/biz/
job/Pay
NotifyJob.java
浏览文件 @
207fdc1d
package
cn
.
iocoder
.
mall
.
pay
.
biz
.
scheduler
;
package
cn
.
iocoder
.
mall
.
pay
.
biz
.
job
;
import
cn.iocoder.mall.pay.api.message.PayTransactionSuccessMessage
;
import
cn.iocoder.mall.pay.biz.convert.PayTransactionConvert
;
import
cn.iocoder.mall.pay.biz.dao.PayTransactionNotifyTaskMapper
;
import
cn.iocoder.mall.pay.biz.dao.PayNotifyTaskMapper
;
import
cn.iocoder.mall.pay.biz.dataobject.PayNotifyTaskDO
;
import
cn.iocoder.mall.pay.biz.service.PayNotifyServiceImpl
;
import
com.xxl.job.core.biz.model.ReturnT
;
import
com.xxl.job.core.handler.IJobHandler
;
import
com.xxl.job.core.handler.annotation.JobHandler
;
...
...
@@ -16,14 +15,17 @@ import java.util.Date;
import
java.util.List
;
/**
* 支付
交易成功通知
Job
* 支付
通知重试
Job
*/
@Component
@JobHandler
(
value
=
"payTransactionNotifyJob"
)
public
class
Pay
Transaction
NotifyJob
extends
IJobHandler
{
public
class
PayNotifyJob
extends
IJobHandler
{
@Autowired
private
PayTransactionNotifyTaskMapper
payTransactionNotifyTaskMapper
;
private
PayNotifyTaskMapper
payTransactionNotifyTaskMapper
;
@Autowired
private
PayNotifyServiceImpl
payNotifyService
;
@Resource
private
RocketMQTemplate
rocketMQTemplate
;
...
...
@@ -33,16 +35,15 @@ public class PayTransactionNotifyJob extends IJobHandler {
// 获得需要通知的任务
List
<
PayNotifyTaskDO
>
notifyTasks
=
payTransactionNotifyTaskMapper
.
selectByNotify
();
// 循环任务,发送通知
for
(
PayNotifyTaskDO
payTransactionN
otifyTask
:
notifyTasks
)
{
for
(
PayNotifyTaskDO
n
otifyTask
:
notifyTasks
)
{
// 发送 MQ
rocketMQTemplate
.
convertAndSend
(
PayTransactionSuccessMessage
.
TOPIC
,
PayTransactionConvert
.
INSTANCE
.
convert
(
payTransactionNotifyTask
));
payNotifyService
.
sendNotifyMessage
(
notifyTask
);
// 更新最后通知时间
// 1. 这样操作,虽然可能会出现 MQ 消费快于下面 PayTransactionNotifyTaskDO 的更新语句。但是,因为更新字段不同,所以不会有问题。
// 2. 换个视角,如果先更新 PayTransactionNotifyTaskDO ,再发送 MQ 消息。如果 MQ 消息发送失败,则 PayTransactionNotifyTaskDO 再也不会被轮询到了。
// 3. 当然,最最最完美的话,就是做事务消息,不过这样又过于复杂~
PayNotifyTaskDO
updateNotifyTask
=
new
PayNotifyTaskDO
()
.
setId
(
payTransactionN
otifyTask
.
getId
()).
setLastExecuteTime
(
new
Date
());
.
setId
(
n
otifyTask
.
getId
()).
setLastExecuteTime
(
new
Date
());
payTransactionNotifyTaskMapper
.
update
(
updateNotifyTask
);
}
return
new
ReturnT
<>(
"执行通知数:"
+
notifyTasks
.
size
());
...
...
pay/pay-service-impl/src/main/java/cn/iocoder/mall/pay/biz/mq/AbstractPayNotifySuccessConsumer.java
0 → 100644
浏览文件 @
207fdc1d
package
cn
.
iocoder
.
mall
.
pay
.
biz
.
mq
;
import
cn.iocoder.common.framework.util.DateUtil
;
import
cn.iocoder.common.framework.util.ExceptionUtil
;
import
cn.iocoder.mall.pay.api.constant.PayTransactionNotifyStatusEnum
;
import
cn.iocoder.mall.pay.api.message.AbstractPayNotifySuccessMessage
;
import
cn.iocoder.mall.pay.biz.component.DubboReferencePool
;
import
cn.iocoder.mall.pay.biz.dao.PayNotifyLogMapper
;
import
cn.iocoder.mall.pay.biz.dao.PayNotifyTaskMapper
;
import
cn.iocoder.mall.pay.biz.dataobject.PayNotifyLogDO
;
import
cn.iocoder.mall.pay.biz.dataobject.PayNotifyTaskDO
;
import
com.alibaba.fastjson.JSON
;
import
org.apache.rocketmq.spring.core.RocketMQListener
;
import
org.springframework.beans.factory.annotation.Autowired
;
import
org.springframework.transaction.annotation.Transactional
;
import
java.util.Calendar
;
import
java.util.Date
;
public
abstract
class
AbstractPayNotifySuccessConsumer
<
T
extends
AbstractPayNotifySuccessMessage
>
implements
RocketMQListener
<
T
>
{
@Autowired
private
DubboReferencePool
dubboReferencePool
;
@Autowired
private
PayNotifyTaskMapper
payTransactionNotifyTaskMapper
;
@Autowired
private
PayNotifyLogMapper
payTransactionNotifyLogMapper
;
@Override
@Transactional
public
void
onMessage
(
T
message
)
{
// 获得 ReferenceMeta 对象
DubboReferencePool
.
ReferenceMeta
referenceMeta
=
dubboReferencePool
.
getReferenceMeta
(
message
.
getNotifyUrl
());
// 发起调用
String
response
=
null
;
// RPC / HTTP 调用的响应
PayNotifyTaskDO
updateTask
=
new
PayNotifyTaskDO
()
// 更新 PayTransactionNotifyTaskDO 对象
.
setId
(
message
.
getId
())
.
setLastExecuteTime
(
new
Date
())
.
setNotifyTimes
(
message
.
getNotifyTimes
()
+
1
);
try
{
response
=
invoke
(
message
,
referenceMeta
);
if
(
"success"
.
equals
(
response
))
{
// 情况一,请求成功且返回成功
// 更新通知成功
updateTask
.
setStatus
(
PayTransactionNotifyStatusEnum
.
SUCCESS
.
getValue
());
payTransactionNotifyTaskMapper
.
update
(
updateTask
);
// 需要更新支付交易单通知应用成功
afterInvokeSuccess
(
message
);
}
else
{
// 情况二,请求成功且返回失败
// 更新通知请求成功,但是结果失败
handleFailure
(
updateTask
,
PayTransactionNotifyStatusEnum
.
REQUEST_SUCCESS
.
getValue
());
payTransactionNotifyTaskMapper
.
update
(
updateTask
);
}
}
catch
(
Throwable
e
)
{
// 请求失败
// 更新通知请求失败
response
=
ExceptionUtil
.
getRootCauseMessage
(
e
);
handleFailure
(
updateTask
,
PayTransactionNotifyStatusEnum
.
REQUEST_FAILURE
.
getValue
());
payTransactionNotifyTaskMapper
.
update
(
updateTask
);
// 抛出异常,回滚事务
throw
e
;
// TODO 芋艿,此处不能抛出异常。因为,会导致 MQ + 定时任务多重试。此处的目标是,事务回滚 + 吃掉事务。另外,最后的 finally 的日志,要插入成功。
}
finally
{
// 插入 PayTransactionNotifyLogDO 日志
PayNotifyLogDO
notifyLog
=
new
PayNotifyLogDO
().
setNotifyId
(
message
.
getId
())
.
setRequest
(
JSON
.
toJSONString
(
message
)).
setResponse
(
response
).
setStatus
(
updateTask
.
getStatus
());
payTransactionNotifyLogMapper
.
insert
(
notifyLog
);
}
}
private
void
handleFailure
(
PayNotifyTaskDO
updateTask
,
Integer
defaultStatus
)
{
if
(
updateTask
.
getNotifyTimes
()
>=
PayNotifyTaskDO
.
NOTIFY_FREQUENCY
.
length
)
{
updateTask
.
setStatus
(
PayTransactionNotifyStatusEnum
.
FAILURE
.
getValue
());
}
else
{
updateTask
.
setNextNotifyTime
(
DateUtil
.
addDate
(
Calendar
.
SECOND
,
PayNotifyTaskDO
.
NOTIFY_FREQUENCY
[
updateTask
.
getNotifyTimes
()]));
updateTask
.
setStatus
(
defaultStatus
);
}
}
protected
abstract
String
invoke
(
T
message
,
DubboReferencePool
.
ReferenceMeta
referenceMeta
);
protected
abstract
void
afterInvokeSuccess
(
T
message
);
}
pay/pay-service-impl/src/main/java/cn/iocoder/mall/pay/biz/mq/PayRefundSuccessConsumer.java
0 → 100644
浏览文件 @
207fdc1d
package
cn
.
iocoder
.
mall
.
pay
.
biz
.
mq
;
import
cn.iocoder.mall.pay.api.message.PayRefundSuccessMessage
;
import
cn.iocoder.mall.pay.biz.component.DubboReferencePool
;
import
cn.iocoder.mall.pay.biz.dao.PayRefundMapper
;
import
cn.iocoder.mall.pay.biz.dataobject.PayRefundDO
;
import
com.alibaba.dubbo.rpc.service.GenericService
;
import
org.apache.rocketmq.spring.annotation.RocketMQMessageListener
;
import
org.apache.rocketmq.spring.core.RocketMQListener
;
import
org.springframework.beans.factory.annotation.Autowired
;
import
org.springframework.stereotype.Service
;
import
org.springframework.util.Assert
;
import
java.util.Date
;
@Service
@RocketMQMessageListener
(
topic
=
PayRefundSuccessMessage
.
TOPIC
,
consumerGroup
=
"pay-consumer-group-"
+
PayRefundSuccessMessage
.
TOPIC
)
public
class
PayRefundSuccessConsumer
extends
AbstractPayNotifySuccessConsumer
<
PayRefundSuccessMessage
>
implements
RocketMQListener
<
PayRefundSuccessMessage
>
{
@Autowired
private
PayRefundMapper
payRefundMapper
;
@Override
protected
String
invoke
(
PayRefundSuccessMessage
message
,
DubboReferencePool
.
ReferenceMeta
referenceMeta
)
{
// 查询支付交易
PayRefundDO
refund
=
payRefundMapper
.
selectById
(
message
.
getRefundId
());
Assert
.
notNull
(
refund
,
String
.
format
(
"回调消息(%s) 退款单不能为空"
,
message
.
toString
()));
// 执行调用
GenericService
genericService
=
referenceMeta
.
getService
();
String
methodName
=
referenceMeta
.
getMethodName
();
return
(
String
)
genericService
.
$invoke
(
methodName
,
new
String
[]{
String
.
class
.
getName
(),
Integer
.
class
.
getName
()},
new
Object
[]{
message
.
getOrderId
(),
refund
.
getPrice
()});
}
@Override
protected
void
afterInvokeSuccess
(
PayRefundSuccessMessage
message
)
{
PayRefundDO
updateRefund
=
new
PayRefundDO
().
setId
(
message
.
getRefundId
()).
setFinishTime
(
new
Date
());
payRefundMapper
.
update
(
updateRefund
,
null
);
}
}
pay/pay-service-impl/src/main/java/cn/iocoder/mall/pay/biz/mq/PayTransactionSuccessConsumer.java
浏览文件 @
207fdc1d
package
cn
.
iocoder
.
mall
.
pay
.
biz
.
mq
;
import
cn.iocoder.common.framework.util.DateUtil
;
import
cn.iocoder.common.framework.util.ExceptionUtil
;
import
cn.iocoder.mall.pay.api.constant.PayTransactionNotifyStatusEnum
;
import
cn.iocoder.mall.pay.api.message.PayTransactionSuccessMessage
;
import
cn.iocoder.mall.pay.biz.component.DubboReferencePool
;
import
cn.iocoder.mall.pay.biz.dao.PayTransactionMapper
;
import
cn.iocoder.mall.pay.biz.dao.PayTransactionNotifyLogMapper
;
import
cn.iocoder.mall.pay.biz.dao.PayTransactionNotifyTaskMapper
;
import
cn.iocoder.mall.pay.biz.dataobject.PayNotifyTaskDO
;
import
cn.iocoder.mall.pay.biz.dataobject.PayTransactionDO
;
import
cn.iocoder.mall.pay.biz.dataobject.PayNotifyLogDO
;
import
com.alibaba.dubbo.config.ApplicationConfig
;
import
com.alibaba.dubbo.config.ReferenceConfig
;
import
com.alibaba.dubbo.config.RegistryConfig
;
import
com.alibaba.dubbo.rpc.service.GenericService
;
import
com.google.common.cache.CacheBuilder
;
import
com.google.common.cache.CacheLoader
;
import
com.google.common.cache.LoadingCache
;
import
lombok.Data
;
import
org.apache.rocketmq.spring.annotation.RocketMQMessageListener
;
import
org.apache.rocketmq.spring.core.RocketMQListener
;
import
org.springframework.beans.factory.annotation.Autowired
;
import
org.springframework.beans.factory.annotation.Value
;
import
org.springframework.stereotype.Service
;
import
org.springframework.transaction.annotation.Transactional
;
import
org.springframework.util.Assert
;
import
java.util.Calendar
;
import
java.util.Date
;
@Service
...
...
@@ -34,119 +18,28 @@ import java.util.Date;
topic
=
PayTransactionSuccessMessage
.
TOPIC
,
consumerGroup
=
"pay-consumer-group-"
+
PayTransactionSuccessMessage
.
TOPIC
)
public
class
PayTransactionSuccessConsumer
implements
RocketMQListener
<
PayTransactionSuccessMessage
>
{
public
class
PayTransactionSuccessConsumer
extends
AbstractPayNotifySuccessConsumer
<
PayTransactionSuccessMessage
>
implements
RocketMQListener
<
PayTransactionSuccessMessage
>
{
@Data
private
class
ReferenceMeta
{
private
final
ReferenceConfig
config
;
// TODO 芋艿,后续需要做销毁
private
final
GenericService
service
;
private
final
String
methodName
;
private
ReferenceMeta
(
ReferenceConfig
config
,
GenericService
service
,
String
methodName
)
{
this
.
config
=
config
;
this
.
service
=
service
;
this
.
methodName
=
methodName
;
}
}
@Value
(
"${dubbo.registry.address}"
)
private
String
dubboRegistryAddress
;
@Value
(
"${dubbo.application.name}"
)
private
String
dubboApplicationName
;
@Autowired
private
PayTransactionNotifyTaskMapper
payTransactionNotifyTaskMapper
;
@Autowired
private
PayTransactionNotifyLogMapper
payTransactionNotifyLogMapper
;
@Autowired
private
PayTransactionMapper
payTransactionMapper
;
private
LoadingCache
<
String
,
ReferenceMeta
>
referenceMetaCache
=
CacheBuilder
.
newBuilder
()
.
build
(
new
CacheLoader
<
String
,
ReferenceMeta
>()
{
@Override
public
ReferenceMeta
load
(
String
notifyUrl
)
{
return
createGenericService
(
notifyUrl
);
}
});
private
ReferenceMeta
createGenericService
(
String
notifyUrl
)
{
String
[]
notifyUrlParts
=
notifyUrl
.
split
(
"#"
);
// 创建 ApplicationConfig 对象
ApplicationConfig
application
=
new
ApplicationConfig
();
application
.
setName
(
dubboApplicationName
);
// 创建 RegistryConfig 对象
RegistryConfig
registry
=
new
RegistryConfig
();
// registry.setAddress("zookeeper://127.0.0.1:2181");
registry
.
setAddress
(
dubboRegistryAddress
);
application
.
setRegistry
(
registry
);
// 创建 ReferenceConfig 对象
ReferenceConfig
<
GenericService
>
reference
=
new
ReferenceConfig
<>();
reference
.
setInterface
(
notifyUrlParts
[
0
]);
// 弱类型接口名
reference
.
setGeneric
(
true
);
// 声明为泛化接口
reference
.
setApplication
(
application
);
// 获得 GenericService 对象
GenericService
genericService
=
reference
.
get
();
// 构建最终的 ReferenceMeta 对象
return
new
ReferenceMeta
(
reference
,
genericService
,
notifyUrlParts
[
1
]);
}
@Override
@Transactional
public
void
onMessage
(
PayTransactionSuccessMessage
message
)
{
// 获得 ReferenceMeta 对象
ReferenceMeta
referenceMeta
=
referenceMetaCache
.
getUnchecked
(
message
.
getNotifyUrl
());
Assert
.
notNull
(
referenceMeta
,
String
.
format
(
"notifyUrl(%s) 不存在对应的 ReferenceMeta 对象"
,
message
.
getNotifyUrl
()));
GenericService
genericService
=
referenceMeta
.
getService
();
String
methodName
=
referenceMeta
.
getMethodName
();
protected
String
invoke
(
PayTransactionSuccessMessage
message
,
DubboReferencePool
.
ReferenceMeta
referenceMeta
)
{
// 查询支付交易
PayTransactionDO
transaction
=
payTransactionMapper
.
selectById
(
message
.
getTransactionId
());
Assert
.
notNull
(
transaction
,
String
.
format
(
"回调消息(%s) 订单交易不能为空"
,
message
.
toString
()));
// 发起调用
String
response
=
null
;
// RPC / HTTP 调用的响应
PayNotifyTaskDO
updateTask
=
new
PayNotifyTaskDO
()
// 更新 PayTransactionNotifyTaskDO 对象
.
setId
(
message
.
getId
())
.
setLastExecuteTime
(
new
Date
())
.
setNotifyTimes
(
message
.
getNotifyTimes
()
+
1
);
try
{
response
=
(
String
)
genericService
.
$invoke
(
methodName
,
new
String
[]{
String
.
class
.
getName
(),
Integer
.
class
.
getName
()},
new
Object
[]{
message
.
getOrderId
(),
transaction
.
getPrice
()});
if
(
"success"
.
equals
(
response
))
{
// 情况一,请求成功且返回成功
// 更新通知成功
updateTask
.
setStatus
(
PayTransactionNotifyStatusEnum
.
SUCCESS
.
getValue
());
payTransactionNotifyTaskMapper
.
update
(
updateTask
);
// 需要更新支付交易单通知应用成功
PayTransactionDO
updateTransaction
=
new
PayTransactionDO
().
setId
(
message
.
getTransactionId
())
.
setFinishTime
(
new
Date
());
payTransactionMapper
.
update
(
updateTransaction
,
null
);
}
else
{
// 情况二,请求成功且返回失败
// 更新通知请求成功,但是结果失败
handleFailure
(
updateTask
,
PayTransactionNotifyStatusEnum
.
REQUEST_SUCCESS
.
getValue
());
payTransactionNotifyTaskMapper
.
update
(
updateTask
);
}
}
catch
(
Throwable
e
)
{
// 请求失败
// 更新通知请求失败
response
=
ExceptionUtil
.
getRootCauseMessage
(
e
);
handleFailure
(
updateTask
,
PayTransactionNotifyStatusEnum
.
REQUEST_FAILURE
.
getValue
());
payTransactionNotifyTaskMapper
.
update
(
updateTask
);
// 抛出异常,回滚事务
throw
e
;
// TODO 芋艿,此处不能抛出异常。因为,会导致 MQ + 定时任务多重试。此处的目标是,事务回滚 + 吃掉事务。另外,最后的 finally 的日志,要插入成功。
}
finally
{
// 插入 PayTransactionNotifyLogDO 日志
PayNotifyLogDO
notifyLog
=
new
PayNotifyLogDO
().
setNotifyId
(
message
.
getId
())
.
setRequest
(
message
.
getOrderId
()).
setResponse
(
response
).
setStatus
(
updateTask
.
getStatus
());
payTransactionNotifyLogMapper
.
insert
(
notifyLog
);
}
// 执行调用
GenericService
genericService
=
referenceMeta
.
getService
();
String
methodName
=
referenceMeta
.
getMethodName
();
return
(
String
)
genericService
.
$invoke
(
methodName
,
new
String
[]{
String
.
class
.
getName
(),
Integer
.
class
.
getName
()},
new
Object
[]{
message
.
getOrderId
(),
transaction
.
getPrice
()});
}
private
void
handleFailure
(
PayNotifyTaskDO
updateTask
,
Integer
defaultStatus
)
{
if
(
updateTask
.
getNotifyTimes
()
>=
PayNotifyTaskDO
.
NOTIFY_FREQUENCY
.
length
)
{
updateTask
.
setStatus
(
PayTransactionNotifyStatusEnum
.
FAILURE
.
getValue
());
}
else
{
updateTask
.
setNextNotifyTime
(
DateUtil
.
addDate
(
Calendar
.
SECOND
,
PayNotifyTaskDO
.
NOTIFY_FREQUENCY
[
updateTask
.
getNotifyTimes
()]));
updateTask
.
setStatus
(
defaultStatus
);
}
@Override
protected
void
afterInvokeSuccess
(
PayTransactionSuccessMessage
message
)
{
PayTransactionDO
updateTransaction
=
new
PayTransactionDO
().
setId
(
message
.
getTransactionId
()).
setFinishTime
(
new
Date
());
payTransactionMapper
.
update
(
updateTransaction
,
null
);
}
}
pay/pay-service-impl/src/main/java/cn/iocoder/mall/pay/biz/service/PayNotifyServiceImpl.java
浏览文件 @
207fdc1d
...
...
@@ -3,9 +3,10 @@ package cn.iocoder.mall.pay.biz.service;
import
cn.iocoder.common.framework.util.DateUtil
;
import
cn.iocoder.mall.pay.api.constant.PayNotifyType
;
import
cn.iocoder.mall.pay.api.constant.PayTransactionNotifyStatusEnum
;
import
cn.iocoder.mall.pay.api.message.PayRefundSuccessMessage
;
import
cn.iocoder.mall.pay.api.message.PayTransactionSuccessMessage
;
import
cn.iocoder.mall.pay.biz.convert.Pay
Transaction
Convert
;
import
cn.iocoder.mall.pay.biz.dao.Pay
Transaction
NotifyTaskMapper
;
import
cn.iocoder.mall.pay.biz.convert.Pay
Notify
Convert
;
import
cn.iocoder.mall.pay.biz.dao.PayNotifyTaskMapper
;
import
cn.iocoder.mall.pay.biz.dataobject.PayNotifyTaskDO
;
import
cn.iocoder.mall.pay.biz.dataobject.PayRefundDO
;
import
cn.iocoder.mall.pay.biz.dataobject.PayTransactionDO
;
...
...
@@ -21,7 +22,7 @@ import java.util.Calendar;
public
class
PayNotifyServiceImpl
{
@Autowired
private
Pay
Transaction
NotifyTaskMapper
payTransactionNotifyTaskMapper
;
private
PayNotifyTaskMapper
payTransactionNotifyTaskMapper
;
@Resource
private
RocketMQTemplate
rocketMQTemplate
;
...
...
@@ -35,8 +36,7 @@ public class PayNotifyServiceImpl {
// 保存到数据库
payTransactionNotifyTaskMapper
.
insert
(
payTransactionNotifyTask
);
// 发送 MQ 消息
rocketMQTemplate
.
convertAndSend
(
PayTransactionSuccessMessage
.
TOPIC
,
PayTransactionConvert
.
INSTANCE
.
convert
(
payTransactionNotifyTask
));
sendNotifyMessage
(
payTransactionNotifyTask
);
}
public
void
addTransactionNotifyTask
(
PayTransactionDO
transaction
,
PayTransactionExtensionDO
extension
)
{
...
...
@@ -47,8 +47,7 @@ public class PayNotifyServiceImpl {
.
setTransactionId
(
extension
.
getTransactionId
()).
setTransactionExtensionId
(
extension
.
getId
()));
payTransactionNotifyTaskMapper
.
insert
(
payTransactionNotifyTask
);
// 3.2 发送 MQ
rocketMQTemplate
.
convertAndSend
(
PayTransactionSuccessMessage
.
TOPIC
,
PayTransactionConvert
.
INSTANCE
.
convert
(
payTransactionNotifyTask
));
sendNotifyMessage
(
payTransactionNotifyTask
);
}
private
PayNotifyTaskDO
createBasePayNotifyTaskDO
(
String
appId
,
String
notifyUrl
)
{
...
...
@@ -60,4 +59,16 @@ public class PayNotifyServiceImpl {
.
setNotifyUrl
(
notifyUrl
);
}
public
void
sendNotifyMessage
(
PayNotifyTaskDO
notifyTask
)
{
if
(
PayNotifyType
.
TRANSACTION
.
getValue
().
equals
(
notifyTask
.
getType
()))
{
rocketMQTemplate
.
convertAndSend
(
PayTransactionSuccessMessage
.
TOPIC
,
PayNotifyConvert
.
INSTANCE
.
convertTransaction
(
notifyTask
));
}
else
if
(
PayNotifyType
.
REFUND
.
getValue
().
equals
(
notifyTask
.
getType
()))
{
rocketMQTemplate
.
convertAndSend
(
PayRefundSuccessMessage
.
TOPIC
,
PayNotifyConvert
.
INSTANCE
.
convertRefund
(
notifyTask
));
}
else
{
throw
new
IllegalArgumentException
(
String
.
format
(
"通知任务(%s) 无法发送通知消息"
,
notifyTask
.
toString
()));
}
}
}
pay/pay-service-impl/src/main/java/cn/iocoder/mall/pay/biz/service/PayRefundServiceImpl.java
浏览文件 @
207fdc1d
...
...
@@ -6,14 +6,19 @@ import cn.iocoder.common.framework.util.ServiceExceptionUtil;
import
cn.iocoder.common.framework.vo.CommonResult
;
import
cn.iocoder.mall.pay.api.PayRefundService
;
import
cn.iocoder.mall.pay.api.bo.PayRefundSubmitBO
;
import
cn.iocoder.mall.pay.api.constant.*
;
import
cn.iocoder.mall.pay.api.constant.PayErrorCodeEnum
;
import
cn.iocoder.mall.pay.api.constant.PayRefundStatus
;
import
cn.iocoder.mall.pay.api.constant.PayTransactionStatusEnum
;
import
cn.iocoder.mall.pay.api.dto.PayRefundSubmitDTO
;
import
cn.iocoder.mall.pay.biz.client.AbstractPaySDK
;
import
cn.iocoder.mall.pay.biz.client.PaySDKFactory
;
import
cn.iocoder.mall.pay.biz.client.RefundSuccessBO
;
import
cn.iocoder.mall.pay.biz.convert.Pay
Transaction
Convert
;
import
cn.iocoder.mall.pay.biz.convert.Pay
Refund
Convert
;
import
cn.iocoder.mall.pay.biz.dao.PayRefundMapper
;
import
cn.iocoder.mall.pay.biz.dataobject.*
;
import
cn.iocoder.mall.pay.biz.dataobject.PayAppDO
;
import
cn.iocoder.mall.pay.biz.dataobject.PayRefundDO
;
import
cn.iocoder.mall.pay.biz.dataobject.PayTransactionDO
;
import
cn.iocoder.mall.pay.biz.dataobject.PayTransactionExtensionDO
;
import
org.apache.rocketmq.spring.core.RocketMQTemplate
;
import
org.slf4j.Logger
;
import
org.slf4j.LoggerFactory
;
...
...
@@ -71,7 +76,7 @@ public class PayRefundServiceImpl implements PayRefundService {
return
ServiceExceptionUtil
.
error
(
PayErrorCodeEnum
.
PAY_TRANSACTION_EXTENSION_STATUS_IS_NOT_SUCCESS
.
getCode
());
}
// 插入 PayTransactionExtensionDO
PayRefundDO
payRefundDO
=
Pay
Transaction
Convert
.
INSTANCE
.
convert
(
payRefundSubmitDTO
)
PayRefundDO
payRefundDO
=
Pay
Refund
Convert
.
INSTANCE
.
convert
(
payRefundSubmitDTO
)
.
setTransactionId
(
payTransaction
.
getId
())
.
setRefundCode
(
generateTransactionCode
())
// TODO 芋艿,后续调整
.
setStatus
(
PayRefundStatus
.
WAITING
.
getValue
())
...
...
@@ -120,7 +125,6 @@ public class PayRefundServiceImpl implements PayRefundService {
if
(
updateCounts
==
0
)
{
// 校验状态,必须是待支付
throw
ServiceExceptionUtil
.
exception
(
PayErrorCodeEnum
.
PAY_REFUND_STATUS_NOT_WAITING
.
getCode
());
}
logger
.
info
(
"[updateRefundSuccess][PayRefundDO({}) 更新为({})]"
,
payRefund
.
getId
(),
status
);
// 2.1 判断 PayTransactionDO ,增加已退款金额
PayTransactionDO
payTransaction
=
payTransactionService
.
getTransaction
(
payRefund
.
getTransactionId
());
if
(
payTransaction
==
null
)
{
...
...
@@ -137,7 +141,6 @@ public class PayRefundServiceImpl implements PayRefundService {
if
(
updateCounts
==
0
)
{
// 保证不超退 TODO 这种类型,需要思考下。需要返回错误,但是又要保证事务回滚
throw
ServiceExceptionUtil
.
exception
(
PayErrorCodeEnum
.
PAY_REFUND_PRICE_EXCEED
.
getCode
());
}
logger
.
info
(
"[updateRefundSuccess][PayTransactionDO({}) 更新为已支付]"
,
payTransaction
.
getId
());
// 3 新增 PayNotifyTaskDO
payNotifyService
.
addRefundNotifyTask
(
payRefund
);
// 返回结果
...
...
pay/pay-service-impl/src/main/java/cn/iocoder/mall/pay/biz/service/PayTransactionServiceImpl.java
浏览文件 @
207fdc1d
...
...
@@ -17,7 +17,7 @@ import cn.iocoder.mall.pay.biz.client.TransactionSuccessBO;
import
cn.iocoder.mall.pay.biz.convert.PayTransactionConvert
;
import
cn.iocoder.mall.pay.biz.dao.PayTransactionExtensionMapper
;
import
cn.iocoder.mall.pay.biz.dao.PayTransactionMapper
;
import
cn.iocoder.mall.pay.biz.dao.Pay
Transaction
NotifyTaskMapper
;
import
cn.iocoder.mall.pay.biz.dao.PayNotifyTaskMapper
;
import
cn.iocoder.mall.pay.biz.dataobject.PayAppDO
;
import
cn.iocoder.mall.pay.biz.dataobject.PayTransactionDO
;
import
cn.iocoder.mall.pay.biz.dataobject.PayTransactionExtensionDO
;
...
...
@@ -40,7 +40,7 @@ public class PayTransactionServiceImpl implements PayTransactionService {
@Autowired
private
PayTransactionExtensionMapper
payTransactionExtensionMapper
;
@Autowired
private
Pay
Transaction
NotifyTaskMapper
payTransactionNotifyTaskMapper
;
private
PayNotifyTaskMapper
payTransactionNotifyTaskMapper
;
@Autowired
private
PayAppServiceImpl
payAppService
;
...
...
pay/pay-service-impl/src/main/resources/mapper/Pay
Transaction
NotifyLogMapper.xml
→
pay/pay-service-impl/src/main/resources/mapper/PayNotifyLogMapper.xml
浏览文件 @
207fdc1d
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper
namespace=
"cn.iocoder.mall.pay.biz.dao.Pay
Transaction
NotifyLogMapper"
>
<mapper
namespace=
"cn.iocoder.mall.pay.biz.dao.PayNotifyLogMapper"
>
<!--<sql id="FIELDS">-->
<!--id, transaction_id, transaction_extension_id, app_id, order_id,-->
...
...
@@ -9,7 +9,7 @@
<!--</sql>-->
<insert
id=
"insert"
parameterType=
"PayNotifyLogDO"
useGeneratedKeys=
"true"
keyColumn=
"id"
keyProperty=
"id"
>
INSERT INTO
transaction_
notify_log (
INSERT INTO notify_log (
notify_id, request, response, status
) VALUES (
#{notifyId}, #{request}, #{response}, #{status}
...
...
pay/pay-service-impl/src/main/resources/mapper/Pay
Transaction
NotifyTaskMapper.xml
→
pay/pay-service-impl/src/main/resources/mapper/PayNotifyTaskMapper.xml
浏览文件 @
207fdc1d
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper
namespace=
"cn.iocoder.mall.pay.biz.dao.Pay
Transaction
NotifyTaskMapper"
>
<mapper
namespace=
"cn.iocoder.mall.pay.biz.dao.PayNotifyTaskMapper"
>
<sql
id=
"FIELDS"
>
id,
transaction_id, transaction_extension_id, app_id, order_id
,
id,
app_id, type
,
status, next_notify_time, last_execute_time, notify_times, max_notify_times,
create_time
</sql>
<resultMap
id=
"PayNotifyTaskResultMap"
type=
"PayNotifyTaskDO"
>
<result
property=
"transaction"
column=
"transaction"
javaType=
"cn.iocoder.mall.pay.biz.dataobject.PayNotifyTaskDO$Transaction"
typeHandler=
"cn.iocoder.common.framework.mybatis.JSONTypeHandler"
/>
<result
property=
"refund"
column=
"refund"
javaType=
"cn.iocoder.mall.pay.biz.dataobject.PayNotifyTaskDO$Refund"
typeHandler=
"cn.iocoder.common.framework.mybatis.JSONTypeHandler"
/>
</resultMap>
<insert
id=
"insert"
parameterType=
"PayNotifyTaskDO"
useGeneratedKeys=
"true"
keyColumn=
"id"
keyProperty=
"id"
>
INSERT INTO transaction_notify_task (
transaction_id, transaction_extension_id, app_id, order_id,
status, next_notify_time, notify_times, max_notify_times
INSERT INTO notify_task (
app_id, type,
status, next_notify_time, notify_times, max_notify_times,
`transaction`, refund
) VALUES (
#{transactionId}, #{transactionExtensionId}, #{appId}, #{orderId},
#{status}, #{nextNotifyTime}, #{notifyTimes}, #{maxNotifyTimes}
#{appId}, #{type},
#{status}, #{nextNotifyTime}, #{notifyTimes}, #{maxNotifyTimes},
#{transaction, typeHandler=cn.iocoder.common.framework.mybatis.JSONTypeHandler},
#{refund, typeHandler=cn.iocoder.common.framework.mybatis.JSONTypeHandler}
)
</insert>
<update
id=
"update"
parameterType=
"PayNotifyTaskDO"
>
UPDATE
transaction_
notify_task
UPDATE notify_task
<set>
<if
test=
"status != null"
>
, status = #{status}
...
...
@@ -37,10 +49,10 @@
WHERE id = #{id}
</update>
<select
id=
"selectByNotify"
result
Type=
"PayNotifyTaskDO
"
>
<select
id=
"selectByNotify"
result
Map=
"PayNotifyTaskResultMap
"
>
SELECT
<include
refid=
"FIELDS"
/>
FROM
transaction_
notify_task
FROM notify_task
WHERE status IN (1, 4, 5)
AND next_notify_time
<![CDATA[ <= ]]>
NOW()
AND last_execute_time > next_notify_time
...
...
pay/pay-service-impl/src/main/resources/mapper/PayRefundMapper.xml
浏览文件 @
207fdc1d
...
...
@@ -3,7 +3,7 @@
<mapper
namespace=
"cn.iocoder.mall.pay.biz.dao.PayRefundMapper"
>
<sql
id=
"FIELDS"
>
id, transaction_id, refund_cod, app_id, create_ip, order_id,
id, transaction_id, refund_cod
e
, app_id, create_ip, order_id,
order_description, price, status,
finish_time, notify_url, extension_data, refund_channel, refund_time, notify_time,
trade_no, create_time
...
...
pay/pay-service-impl/src/main/resources/mapper/PayTransactionMapper.xml
浏览文件 @
207fdc1d
...
...
@@ -56,8 +56,8 @@
<update
id=
"updateForRefundTotal"
>
UPDATE `transaction`
SET refund
Total = refundT
otal + ${refundTotalIncr}
WHERE price >= refund
T
otal + ${refundTotalIncr}
SET refund
_total = refund_t
otal + ${refundTotalIncr}
WHERE price >= refund
_t
otal + ${refundTotalIncr}
</update>
<select
id=
"selectByAppIdAndOrderId"
resultType=
"PayTransactionDO"
>
...
...
pay/pay-service-impl/src/test/java/cn/iocoder/mall/pay/biz/service/PayRefundServiceImplTest.java
0 → 100644
浏览文件 @
207fdc1d
package
cn
.
iocoder
.
mall
.
pay
.
biz
.
service
;
import
cn.iocoder.mall.pay.api.PayRefundService
;
import
cn.iocoder.mall.pay.api.dto.PayRefundSubmitDTO
;
import
org.junit.Test
;
import
org.junit.runner.RunWith
;
import
org.springframework.beans.factory.annotation.Autowired
;
import
org.springframework.boot.test.context.SpringBootTest
;
import
org.springframework.test.context.junit4.SpringJUnit4ClassRunner
;
@RunWith
(
SpringJUnit4ClassRunner
.
class
)
@SpringBootTest
(
webEnvironment
=
SpringBootTest
.
WebEnvironment
.
NONE
)
public
class
PayRefundServiceImplTest
{
@Autowired
private
PayRefundService
payRefundService
;
@Test
public
void
testSubmitRefund
()
{
PayRefundSubmitDTO
payRefundSubmitDTO
=
new
PayRefundSubmitDTO
()
.
setAppId
(
"POd4RC6a"
)
.
setCreateIp
(
"127.0.0.1"
)
.
setOrderId
(
"135"
)
.
setOrderDescription
(
"测试下退款"
)
.
setPrice
(
1
);
payRefundService
.
submitRefund
(
payRefundSubmitDTO
);
}
}
pay/pay-service-impl/src/test/java/cn/iocoder/mall/pay/biz/service/PayTransactionServiceImplTest.java
0 → 100644
浏览文件 @
207fdc1d
package
cn
.
iocoder
.
mall
.
pay
.
biz
.
service
;
import
cn.iocoder.mall.pay.api.dto.PayRefundSubmitDTO
;
import
org.junit.Ignore
;
import
org.junit.Test
;
import
org.junit.runner.RunWith
;
import
org.springframework.beans.factory.annotation.Autowired
;
import
org.springframework.boot.test.context.SpringBootTest
;
import
org.springframework.test.context.junit4.SpringJUnit4ClassRunner
;
@RunWith
(
SpringJUnit4ClassRunner
.
class
)
@SpringBootTest
(
webEnvironment
=
SpringBootTest
.
WebEnvironment
.
NONE
)
public
class
PayTransactionServiceImplTest
{
}
promotion/promotion-service-api/src/main/java/cn/iocoder/mall/promotion/api/CouponService.java
浏览文件 @
207fdc1d
...
...
@@ -6,6 +6,7 @@ import cn.iocoder.mall.promotion.api.bo.*;
import
cn.iocoder.mall.promotion.api.constant.CouponTemplateStatusEnum
;
import
cn.iocoder.mall.promotion.api.dto.*
;
import
javax.validation.constraints.NotNull
;
import
java.util.List
;
public
interface
CouponService
{
...
...
@@ -79,7 +80,8 @@ public interface CouponService {
* @param couponCardId 优惠劵编号
* @return 是否成功
*/
CommonResult
<
Boolean
>
useCouponCard
(
Integer
userId
,
Integer
couponCardId
);
CommonResult
<
Boolean
>
useCouponCard
(
Integer
userId
,
@NotNull
(
message
=
"优惠劵编号不能为空"
)
Integer
couponCardId
);
/**
* 取消优惠劵的使用
...
...
编写
预览
Markdown
格式
0%
重试
或
添加新文件
添加附件
取消
您添加了
0
人
到此讨论。请谨慎行事。
请先完成此评论的编辑!
取消
请
注册
或者
登录
后发表评论