Commit 511353b3 authored by 万继龙's avatar 万继龙

Merge branch 'refund_wanjl_0818' into 'master'

Refund wanjl 0818

See merge request bp/pay!67
parents d03c6b68 c7abd980
...@@ -26,5 +26,8 @@ class RefundException extends BaseException ...@@ -26,5 +26,8 @@ class RefundException extends BaseException
11 => 'pingxx退单缺少matadata!', 11 => 'pingxx退单缺少matadata!',
12 => 'pingxx未支付订单不允许退款。', 12 => 'pingxx未支付订单不允许退款。',
13 => 'pingxx订单可能存在多次成功支付,需人工确认处理。', 13 => 'pingxx订单可能存在多次成功支付,需人工确认处理。',
14 => '不存在满足条件的退款订单。',
15 => '订单未支付或不存在,请核对。',
16 => '订单退款回调处理失败,请核对。',
]; ];
} }
...@@ -21,11 +21,12 @@ class PayOrderClearingItem extends MysqlBase ...@@ -21,11 +21,12 @@ class PayOrderClearingItem extends MysqlBase
return $ret; return $ret;
} }
/* /**/
$sql = "select sum(poci.`pay_amount`) as 'pay_amount', notify_account_status from pay_order_clearing_item poci $sql = "select sum(poci.`pay_amount`) as 'pay_amount', notify_account_status from pay_order_clearing_item poci
join pay_order_item poi on poi.`order_item_id` = poci.`order_item_id` join pay_order_item poi on poi.`order_item_id` = poci.`order_item_id`
where poci.pay_sub_type = 105 and poci.account_id = ? and poi.refund_order_status = 0 group by notify_account_status "; where poci.pay_sub_type = 105 and poci.account_id = ? and poi.refund_order_status = 0 group by notify_account_status ";
*/
/*
$sql = "select sum(poci.`pay_amount`) as 'pay_amount', $sql = "select sum(poci.`pay_amount`) as 'pay_amount',
notify_account_status from pay_order_clearing_item poci notify_account_status from pay_order_clearing_item poci
join pay_order_item poi on poi.`order_item_id` = poci.`order_item_id` join pay_order_item poi on poi.`order_item_id` = poci.`order_item_id`
...@@ -33,6 +34,7 @@ where ...@@ -33,6 +34,7 @@ where
not exists (select 1 from refund_order ro where ro.`order_item_id` = poci.`order_item_id`) and not exists (select 1 from refund_order ro where ro.`order_item_id` = poci.`order_item_id`) and
poci.pay_sub_type = 105 and poci.account_id = ? poci.pay_sub_type = 105 and poci.account_id = ?
group by notify_account_status "; group by notify_account_status ";
*/
/* /*
type=1: 该团长历史累计分销佣金收入总和 type=1: 该团长历史累计分销佣金收入总和
......
...@@ -2,6 +2,7 @@ ...@@ -2,6 +2,7 @@
use App\Base\Base; use App\Base\Base;
use App\Exception\custom\PayException;
use App\Services\pay\PayService; use App\Services\pay\PayService;
use App\Services\refund\RefundService; use App\Services\refund\RefundService;
use Api\PhpUtils\Log\FileLog; use Api\PhpUtils\Log\FileLog;
...@@ -39,15 +40,25 @@ class OrderController extends Base ...@@ -39,15 +40,25 @@ class OrderController extends Base
public function refundAction() { public function refundAction() {
$params = $this->params; $params = $this->getRequest()->getPost();
$user_id = $params['user_id'];
$order_item_id = $params['order_item_id']; if(!empty($params['order_item_id'])) {
if(!is_array($params['order_item_id'])) {
$params['order_item_id'] = explode(',', $params['order_item_id']);
}
} else {
$params['order_item_id'] = [];
}
if(empty($params['order_id'])) {
throw new PayException(['cus' => 1]);
}
$refundSrv = new RefundService(); $refundSrv = new RefundService();
$ret = $refundSrv->do_refund($order_item_id, $user_id); $ret = $refundSrv->do_refund($params['order_id'], $params['order_item_id']);
$this->success(['result'=>$ret]); $this->success(['result'=>$ret]);
} }
public function write_offAction() { public function write_offAction() {
......
...@@ -46,7 +46,7 @@ class Hook extends \Yaf\Plugin_Abstract { ...@@ -46,7 +46,7 @@ class Hook extends \Yaf\Plugin_Abstract {
} }
public function preDispatch(\Yaf\Request_Abstract $request, \Yaf\Response_Abstract $response) { public function preDispatch(\Yaf\Request_Abstract $request, \Yaf\Response_Abstract $response) {
// application/json形式,仅处理$_POST, 不整合$_GET, $_REQUEST // application/json形式,仅处理$_POST, 不整合$_GET
if($request->isPost() if($request->isPost()
&& $request->getServer('CONTENT_TYPE') == 'application/json') { && $request->getServer('CONTENT_TYPE') == 'application/json') {
...@@ -57,10 +57,13 @@ class Hook extends \Yaf\Plugin_Abstract { ...@@ -57,10 +57,13 @@ class Hook extends \Yaf\Plugin_Abstract {
} }
$_POST = json_decode($jsonPost, true); $_POST = json_decode($jsonPost, true);
if(!is_array($_POST)) { if(!is_array($_POST)) {
$_POST = []; $_POST = [];
FileLog::error('bp-gateway', 'json decode error raw:' . $jsonPost); FileLog::error('bp-gateway', 'json decode error raw:' . $jsonPost);
} }
$_REQUEST = array_merge($_REQUEST, $_POST);
} }
} }
......
...@@ -265,20 +265,24 @@ class PayService ...@@ -265,20 +265,24 @@ class PayService
$title = ''; $title = '';
} }
try{ try{
//通知消息 //通知消息
$app_id = 'wx65e9ba99c333444f'; $app_id = 'wx65e9ba99c333444f';
$template_id = 'EzOH2ZpfW-eUdFf9gzjZTAv-Z9PFmKHNsQ0VOGvvN7c'; $template_id = 'EzOH2ZpfW-eUdFf9gzjZTAv-Z9PFmKHNsQ0VOGvvN7c';
$page_url = 'https://testwx.appgc.cn/%23/bpmp/ticket/my'; $page_url = \Yaf\Application::app()->getConfig()->get('wxApp.jw.order');
$type = 1; $type = 1;
$param = [ $query = [
$title, $title,
$pay_order['order_id'], $pay_order['order_id'],
round($pay_order['pay_amount'] / 100, 2), round($pay_order['pay_amount'] / 100, 2),
date('Y-m-d'), date('Y-m-d'),
]; ];
Msg::send($pay_order['user_id'], $app_id, $template_id, $page_url, $type, $param); if(isset($ret['result']['order_info']['business_from']) && $ret['result']['order_info']['business_from'] != 2) {
//接龙业务不发送消息
Msg::send($pay_order['user_id'], $app_id, $template_id, $page_url, $type, $query);
}
}catch (\Throwable $e) { }catch (\Throwable $e) {
; ;
...@@ -295,30 +299,32 @@ class PayService ...@@ -295,30 +299,32 @@ class PayService
*/ */
public function write_off($order_item_id, $life_account_id) public function write_off($order_item_id, $life_account_id)
{ {
$cnt = 0;
//锁定状态 //锁定状态
try{ try{
PayOrderItem::beginTransaction(); PayOrderItem::beginTransaction();
$cnt = PayOrderItem::update([
'notify_account_status' => 0,
'can_notify_account' => 1,
'can_notify_account_time' => date('Y-m-d H:i:s'),
], ['order_item_id' => $order_item_id, 'can_notify_account'=>0]);
$refund = RefundOrder::getMaster('*', ['order_item_id'=>$order_item_id]);
if(!empty($refund)) {
throw new PayException(['cus'=>9]);
}
$item = PayOrderItem::getMaster('*', ['order_item_id' => $order_item_id]); $item = PayOrderItem::getMaster('*', ['order_item_id' => $order_item_id]);
if(empty($item)) { if(empty($item)) {
throw new PayException(['cus'=>10]); throw new PayException(['cus'=>10]);
} }
if($item['refund_order_status'] != 0) {
throw new PayException(['cus'=>9]);
}
$pay_order = PayOrder::getMaster('*', ['pay_order_id'=>$item['pay_order_id']]); $pay_order = PayOrder::getMaster('*', ['pay_order_id'=>$item['pay_order_id']]);
if(empty($pay_order) || $pay_order['life_account_id'] != $life_account_id) { if(empty($pay_order) || $pay_order['life_account_id'] != $life_account_id) {
throw new PayException(['cus'=>11]); throw new PayException(['cus'=>11]);
} }
$cnt = PayOrderItem::update([
'notify_account_status' => 0,
'can_notify_account' => 1,
'can_notify_account_time' => date('Y-m-d H:i:s'),
], ['order_item_id' => $order_item_id, 'can_notify_account'=>0, 'refund_order_status'=>0]);
PayOrderItem::commit(); PayOrderItem::commit();
}catch (\Exception $e) { }catch (\Exception $e) {
PayOrderItem::rollback(); PayOrderItem::rollback();
...@@ -421,6 +427,7 @@ class PayService ...@@ -421,6 +427,7 @@ class PayService
'pay_order_id' => $this->pay_order['pay_order_id'], 'pay_order_id' => $this->pay_order['pay_order_id'],
'order_id' => $this->pay_order['order_id'], 'order_id' => $this->pay_order['order_id'],
'order_item_id' => $r['order_item_id'], 'order_item_id' => $r['order_item_id'],
'payment' => $r['payment'],
'user_id' => $this->pay_order['user_id'], 'user_id' => $this->pay_order['user_id'],
]; ];
} }
......
...@@ -29,31 +29,13 @@ class RefundService ...@@ -29,31 +29,13 @@ class RefundService
* @throws RefundException * @throws RefundException
* 发起退款请求 * 发起退款请求
*/ */
public function do_refund($order_item_id, $user_id) { public function do_refund($order_id, $order_item_ids = []) {
if(empty($order_item_id)) { if(empty($order_id)) {
throw new RefundException(['cus' => 1]); throw new RefundException(['cus' => 1]);
} }
// 获取子单信息
$ret = OrderService::getOrderItemData($order_item_id);
if(empty($ret['result'])) {
throw new RefundException(['cus' => 2]);
}
if(empty($ret['result']['user_id']) || $ret['result']['user_id'] != $user_id) {
throw new RefundException(['cus' => 3]);
}
$order_item = $ret['result']; $data = $this->can_refund($order_id, $order_item_ids);
$where = [
'order_item_id'=>$order_item_id,
'user_id'=>$user_id,
'order_id'=>$order_item['order_id'],
'refund_amount'=>$order_item['payment'],
'refund_order_id'=>$this->gen_refund_order_id($user_id),
];
$data = $this->can_refund($where, $order_item);
/* /*
https://www.pingxx.com/api/%E8%AE%A2%E5%8D%95%20Refunds%20%E9%80%80%E6%AC%BE%E6%A6%82%E8%BF%B0.html https://www.pingxx.com/api/%E8%AE%A2%E5%8D%95%20Refunds%20%E9%80%80%E6%AC%BE%E6%A6%82%E8%BF%B0.html
...@@ -84,9 +66,8 @@ class RefundService ...@@ -84,9 +66,8 @@ class RefundService
'app_id'=>'merchant-c', 'app_id'=>'merchant-c',
'environ'=>Application::app()->environ(), 'environ'=>Application::app()->environ(),
'refund_order_id'=>$data['refund_order']['refund_order_id'], 'refund_order_id'=>$data['refund_order']['refund_order_id'],
'order_id'=>$order_item['order_id'], 'order_item_id'=>$data['order_item_id'],
'order_item_id'=>$data['refund_order']['order_item_id'], 'order_id'=>$order_id,
'goods_sku_id'=>$order_item['goods_sku_id'] ?? '',
], ],
]; ];
...@@ -99,11 +80,16 @@ class RefundService ...@@ -99,11 +80,16 @@ class RefundService
throw new BaseException(['msg'=>$ret['error']['message'], 'code'=>'2011']); throw new BaseException(['msg'=>$ret['error']['message'], 'code'=>'2011']);
} }
return ['order_item_id'=>$order_item_id]; return [
'order_item_id'=>$data['order_item_id'],
'refund_order_id'=>$data['refund_order']['refund_order_id'],
];
}catch (\Exception $e) { }catch (\Exception $e) {
$edit = ['refund_order_status'=>0]; $edit = ['refund_order_status'=>0];
RefundOrder::update($edit, ['refund_order_id'=>$data['refund_order']['refund_order_id']]); RefundOrder::update($edit, ['refund_order_id'=>$data['refund_order']['refund_order_id']]);
PayOrderItem::update(['refund_order_status'=>0], ['order_item_id'=>$data['order_item_id']]);
throw $e; throw $e;
} }
} }
...@@ -146,18 +132,35 @@ class RefundService ...@@ -146,18 +132,35 @@ class RefundService
return ['error'=>'退款订单缺少matadata,不做处理。']; return ['error'=>'退款订单缺少matadata,不做处理。'];
} }
if(empty($object['metadata']['order_item_id'])) {
return ['error'=>'退款订单缺少order_item_id,不做处理。'];
}
// 修改状态,锁定业务 // 修改状态,锁定业务
RefundOrder::beginTransaction();
$refund_order_id = $object['metadata']['refund_order_id']; $refund_order_id = $object['metadata']['refund_order_id'];
$edit = [ $edit = [
'refund_order_status'=>2, //pingxx回调成功, 'refund_order_status'=>2, //pingxx回调成功,
'pingxx_callback_success_time'=>date('Y-m-d H:i:s'), //回调成功时间 'pingxx_callback_success_time'=>date('Y-m-d H:i:s'), //回调成功时间
'notify_account_status'=>1, //不需要通知钱包
]; ];
$cnt = RefundOrder::update($edit, ['refund_order_id'=>$refund_order_id, 'refund_order_status'=>1]); $cnt_r = RefundOrder::update($edit, ['refund_order_id'=>$refund_order_id, 'refund_order_status'=>1]);
//保持幂等操作
if($cnt == 0) { $cnt_i = PayOrderItem::update(['refund_order_status'=>2], [
return ['refund_order_id'=>$refund_order_id]; 'order_item_id'=>$object['metadata']['order_item_id']
]);
if($cnt_r && $cnt_i) {
RefundOrder::commit();
} else {
RefundOrder::rollback();
}
$refund = RefundOrder::getMaster('*', ['refund_order_id'=>$refund_order_id]);
if($refund['refund_order_status'] != 2) {
throw new RefundException(['cus' => 16]);
} }
return ['refund_order_id'=>$refund_order_id]; return ['refund_order_id'=>$refund_order_id];
...@@ -171,57 +174,52 @@ class RefundService ...@@ -171,57 +174,52 @@ class RefundService
* @throws RefundException * @throws RefundException
* 判断订单是否可退,判断是否存在退款申请 * 判断订单是否可退,判断是否存在退款申请
*/ */
private function can_refund($where, $order_item) { private function can_refund($order_id, $order_item_ids) {
/** /**
* 业务方自行解决,订单关闭、订单超过时长不允许退款等逻辑 * 业务方自行解决,订单关闭、订单超过时长不允许退款等逻辑
* 支付中心退款判断仅做主单是否支付,主单是否支持退款的判断 * 支付中心退款判断仅做主单是否支付,主单是否支持退款的判断
*/ */
$refund_payment = 0;
try{ try{
RefundOrder::beginTransaction(); RefundOrder::beginTransaction();
$pay_order_item = PayOrderItem::getMaster('*', ['order_item_id'=>$where['order_item_id']]); $pay_order = PayOrder::getMaster('*', ['order_id'=>$order_id]);
if(empty($pay_order_item)) { if(empty($pay_order)) {
throw new RefundException(['cus' => 15]);
}
$pay_order_items = PayOrderItem::selectMaster('*', ['order_id'=>$order_id]);
if(empty($pay_order_items)) {
throw new RefundException(['cus' => 4]); throw new RefundException(['cus' => 4]);
} }
if($pay_order_item['can_notify_account'] == 1) {
throw new RefundException(['cus' => 5]); foreach ($pay_order_items as $item) {
if($item['can_notify_account'] == 1) {
continue; //已结算不允许退款
} }
$refund_order = RefundOrder::getMaster('*', ['order_item_id'=>$where['order_item_id']]); if(in_array($item['refund_order_status'], [1, 2])) {
if(!empty($refund_order)) { continue; //退款中、已退款不允许再次申请
if($refund_order['refund_order_status'] == Dictionary::REFUND_ORDER_STATUS_OK) {
throw new RefundException(['cus' => 6]);
} }
if($refund_order['refund_order_status'] == Dictionary::REFUND_ORDER_STATUS_SEND) { if(!empty($order_item_ids) && !in_array($item['order_item_id'], $order_item_ids)) {
throw new RefundException(['cus' => 7]); continue; //部分退款,且不再退款子单列表,不处理
} }
} else { $items[] = $item;
$refund_order = $where;
$refund_order['refund_order_status'] = Dictionary::REFUND_ORDER_STATUS_UNDO; $refund_payment += $item['payment'];
//$refund_order['refund_amount'] = 0;
$cnt = RefundOrder::insert($refund_order, ['rowCount'=>true]);
if($cnt == 0) {
throw new RefundException(['cus' => 0]);
} }
if(empty($items)) {
throw new RefundException(['cus' => 14]); //
} }
//重新计算微信手续费 //重新计算微信手续费
$cleared_amount = $cleared_tip = 0; $cleared_amount = $cleared_tip = 0;
$pay_order = PayOrder::getMaster('*', ['order_id'=>$where['order_id']]); // 计算已退金额、已退手续费 sum(refund_wx_tip), sum(refund_amount)
// 总共手续费 $list = RefundOrder::selectMaster('*', ['order_id'=>$pay_order['order_id']]);
$wx_clear = PayOrderClearing::getMaster('*', [
'order_id'=>$where['order_id'],
'pay_order_id'=>$pay_order['pay_order_id'],
'pay_sub_type'=>406 //三方渠道手续费
]
);
// 计算已退金额、已退手续费
$list = RefundOrder::selectMaster('*', ['order_id'=>$where['order_id']]);
foreach ($list as $r) { foreach ($list as $r) {
if($r['refund_order_status'] == Dictionary::REFUND_ORDER_STATUS_UNDO) { if($r['refund_order_status'] == Dictionary::REFUND_ORDER_STATUS_UNDO) {
continue; continue;
...@@ -231,27 +229,43 @@ class RefundService ...@@ -231,27 +229,43 @@ class RefundService
$cleared_tip += $r['refund_wx_tip']; $cleared_tip += $r['refund_wx_tip'];
} }
// 总共手续费
$wx_clear = PayOrderClearing::getMaster('*', [
'order_id'=>$pay_order['order_id'],
'pay_order_id'=>$pay_order['pay_order_id'],
'pay_sub_type'=>406 //三方渠道手续费
]
);
$wx_total_tip = 0; $wx_total_tip = 0;
if($wx_clear) { if($wx_clear) {
$wx_total_tip = $wx_clear['pay_amount']; $wx_total_tip = $wx_clear['pay_amount'];
} }
$wx_tip = Strategy::getWxTip($order_item['payment'], $pay_order['pay_amount'], $cleared_amount, $wx_total_tip, $cleared_tip); $wx_tip = Strategy::getWxTip($refund_payment, $pay_order['pay_amount'], $cleared_amount, $wx_total_tip, $cleared_tip);
$edit = [ $refund = [
'refund_order_status'=>Dictionary::REFUND_ORDER_STATUS_SEND, 'refund_order_id'=>$this->gen_refund_order_id($pay_order['user_id']),
'refund_amount'=>$order_item['payment'], 'user_id'=>$pay_order['user_id'],
'order_id'=>$pay_order['order_id'],
'refund_order_status'=>1,
'refund_amount'=>$refund_payment,
'refund_wx_tip'=>$wx_tip, 'refund_wx_tip'=>$wx_tip,
'source_name'=>$pay_order['source_name'],
'extra'=> json_encode(['order_item_id'=>array_column($items, 'order_item_id')]),
]; ];
$ret = RefundOrder::update($edit, ['refund_order_id'=>$refund_order['refund_order_id']]);
if(!$ret) { $cnt = RefundOrder::insert($refund, ['rowCount'=>true]);
if($cnt == 0) {
throw new RefundException(['cus' => 0]); throw new RefundException(['cus' => 0]);
} }
//重新获取
$refund_order = RefundOrder::getMaster('*', ['refund_order_id'=>$refund_order['refund_order_id']]); //批量更新子单状态 "user_id" => [2, 123, 234, 54],
PayOrderItem::update(['refund_order_status'=>1], ['order_item_id'=>array_column($items, 'order_item_id')]);
$data = [ $data = [
'refund_order'=>$refund_order, 'refund_order'=>$refund,
'pay_order'=>$pay_order, 'pay_order'=>$pay_order,
'order_item_id'=>array_column($items, 'order_item_id'),
]; ];
RefundOrder::commit(); RefundOrder::commit();
......
...@@ -39,12 +39,14 @@ dingTalk.keys[]="SEC0298ad3f80e16df12cd4d6f6c39e961b500e2ff486f4c4377c0e2af8f453 ...@@ -39,12 +39,14 @@ dingTalk.keys[]="SEC0298ad3f80e16df12cd4d6f6c39e961b500e2ff486f4c4377c0e2af8f453
[prod : common : exception : dingTalk] [prod : common : exception : dingTalk]
pingxx.appid = "app_9m1ubDG4e1mPXLCG" pingxx.appid = "app_9m1ubDG4e1mPXLCG"
wxApp.jw.order = "https://wx.appgc.cn/%23/bpmp/ticket/my"
[pref : common : exception : dingTalk] [pref : common : exception : dingTalk]
pingxx.appid = "app_9m1ubDG4e1mPXLCG" pingxx.appid = "app_9m1ubDG4e1mPXLCG"
[test : common : exception : dingTalk] [test : common : exception : dingTalk]
pingxx.appid = "app_W10Oe5XrvbzHfP4W" pingxx.appid = "app_W10Oe5XrvbzHfP4W"
wxApp.jw.order = "https://testwx.appgc.cn/%23/bpmp/ticket/my"
[dev : common : exception] [dev : common : exception]
pingxx.appid = "app_W10Oe5XrvbzHfP4W" pingxx.appid = "app_W10Oe5XrvbzHfP4W"
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment