OrderRefund.php 47 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014
  1. <?php
  2. // +----------------------------------------------------------------------
  3. // | 萤火商城系统 [ 致力于通过产品和服务,帮助商家高效化开拓市场 ]
  4. // +----------------------------------------------------------------------
  5. // | Copyright (c) 2017~2021 https://www.yiovo.com All rights reserved.
  6. // +----------------------------------------------------------------------
  7. // | Licensed 这不是一个自由软件,不允许对程序代码以任何形式任何目的的再发行
  8. // +----------------------------------------------------------------------
  9. // | Author: 萤火科技 <admin@yiovo.com>
  10. // +----------------------------------------------------------------------
  11. declare (strict_types = 1);
  12. namespace app\store\model;
  13. use app\common\enum\goods\GoodsType;
  14. use app\common\enum\order\refund\RefundType;
  15. use app\common\model\user\CommissionsDetail;
  16. use app\common\service\Order as OrderService;
  17. use app\store\model\member\GoldRice;
  18. use app\store\model\User as UserModel;
  19. use app\common\model\OrderRefund as OrderRefundModel;
  20. use app\common\enum\order\refund\RefundType as RefundTypeEnum;
  21. use app\common\enum\order\refund\AuditStatus as AuditStatusEnum;
  22. use app\common\enum\order\refund\RefundStatus as RefundStatusEnum;
  23. use app\common\service\Message as MessageService;
  24. use app\common\service\order\Refund as RefundService;
  25. use app\common\enum\order\refund\FinanceRefundStatus as FinanceRefundStatusEnum;
  26. use app\common\model\OrderGoods as OrderGoodsModel;
  27. use app\common\model\Provider as ProviderModel;
  28. use app\store\model\OrderRefundAddress;
  29. use app\common\model\order\RefundHis;
  30. // use app\common\service\order\Refund as RefundService;
  31. use app\common\service\store\User as StoreUserService;
  32. use app\api\model\card\UserRiceCard as UserRiceCardModel;
  33. use app\api\model\card\UserRiceCardConsume;
  34. use app\api\model\card\UserRiceCard;
  35. use app\common\service\goods\source\Factory as FactoryStock;
  36. /**
  37. * 售后单模型
  38. * Class OrderRefund
  39. * @package app\api\model
  40. */
  41. class OrderRefund extends OrderRefundModel
  42. {
  43. // /**
  44. // * 售后单状态文字描述
  45. // * @param $value
  46. // * @param $data
  47. // * @return string
  48. // */
  49. public function getStateTextAttr($value,$data){
  50. if(!isset($data['delivery_type'])){
  51. return '';
  52. }
  53. if($data['delivery_type']==10){
  54. if($data['type']== RefundTypeEnum::COMPLETE){
  55. if($data['status']==RefundStatusEnum::COMPLETED){
  56. return '已退款';
  57. }
  58. // 已取消
  59. if ($data['status'] == RefundStatusEnum::CANCELLED) {
  60. return '用户撤销';
  61. }
  62. if($data['status']==RefundStatusEnum::CLOSE){
  63. return '已关闭售后单';
  64. }
  65. if (isset($data['audit_status'])&&$data['audit_status'] == AuditStatusEnum::WAIT) {
  66. return '待专员审核';
  67. }
  68. if(isset($data['audit_status'])&&$data['audit_status'] == AuditStatusEnum::REJECTED) {
  69. return '不同意';
  70. }
  71. }
  72. //退货退款
  73. if($data['type'] == RefundTypeEnum::RETURN){
  74. if($data['status']==RefundStatusEnum::CANCELLED){
  75. return '用户撤销';
  76. }
  77. if($data['status']==RefundStatusEnum::CLOSE){
  78. if($data['close_username']!=''){
  79. return '已关闭售后单';
  80. }else{
  81. return '用户超时未退货,系统自动关闭售后单';
  82. }
  83. }
  84. if($data['status']==RefundStatusEnum::COMPLETED){
  85. return '已退款';
  86. }
  87. if($data['status']==RefundStatusEnum::REJECTED){
  88. return '不同意';
  89. }
  90. if(isset($data['audit_status'])&&$data['audit_status'] == AuditStatusEnum::WAIT) {
  91. return '待专员审核';
  92. }
  93. if(isset($data['audit_status'])&&$data['audit_status']==AuditStatusEnum::REVIEWED&&$data['audit_status_zg']==AuditStatusEnum::WAIT){
  94. return '待主管审核';
  95. }
  96. if(isset($data['audit_status_zg'])&&$data['audit_status_zg']==AuditStatusEnum::REVIEWED&&$data['is_user_send']==0){
  97. return '待买家退货';
  98. }
  99. if(isset($data['is_user_send'])&&$data['is_user_send']==1&&isset($data['is_receipt'])&&$data['is_receipt']==0){
  100. return '待仓库收货';
  101. }
  102. if(isset($data['is_receipt'])&&$data['is_receipt']==1&&isset($data['finance_refund'])&&$data['finance_refund']==0){
  103. return '待退款';
  104. }
  105. }
  106. }
  107. //自提售后单
  108. if($data['delivery_type']==20){
  109. if($data['hx_status']==10){
  110. if($data['audit_status']==AuditStatusEnum::REVIEWED&&$data['finance_refund']==10){
  111. return '已退款';
  112. }
  113. }
  114. if($data['hx_status']==20){
  115. // if($data['status']==RefundStatusEnum::CANCELLED){
  116. // return '用户撤销';
  117. // }
  118. if($data['status']==RefundStatusEnum::CLOSE&&$data['audit_status']==AuditStatusEnum::WAIT){
  119. return '用户撤销';
  120. }
  121. if($data['audit_status']==AuditStatusEnum::REJECTED&&$data['status']==RefundStatusEnum::CLOSE){
  122. return '已关闭';
  123. }
  124. if($data['audit_status']==AuditStatusEnum::WAIT){
  125. return '待门店审核';
  126. }
  127. if($data['audit_status']==AuditStatusEnum::REVIEWED&&$data['finance_refund']==0){
  128. return '待退款';
  129. }
  130. }
  131. if($data['status']==RefundStatusEnum::COMPLETED){
  132. if($data['finance_refund']==10){
  133. return '已退款';
  134. }
  135. }
  136. }
  137. return '-';
  138. }
  139. /**
  140. * 获取售后单列表
  141. * @param array $param
  142. * @return mixed
  143. */
  144. public function getList(array $param = [])
  145. {
  146. // 检索查询条件
  147. $filter = $this->getFilter($param);
  148. // 获取列表数据
  149. return $this->alias('refund')
  150. ->field('refund.*, order.order_no')
  151. ->with(['orderGoods.image', 'orderGoodsAll.image', 'orderData', 'user'])
  152. ->join('order', 'order.order_id = refund.order_id')
  153. ->join('user', 'user.user_id = order.user_id')
  154. ->leftJoin('orderGoods', 'orderGoods.order_goods_id = refund.order_goods_id')
  155. ->leftJoin('provider', 'provider.provider_id = orderGoods.provider_id')
  156. ->where($filter)
  157. ->order(['refund.create_time' => 'desc', 'refund.' . $this->getPk()])
  158. ->paginate(15)->each(function($e){
  159. $e['audit_text'] = $this->getAuditText($e);
  160. if (!$e['order_goods_id']) {
  161. // 整单退款
  162. $orderGoods = $e['orderGoodsAll'];
  163. } else {
  164. $e['orderGoods']['total_num'] = $e['goods_num'];
  165. $orderGoods = [$e['orderGoods']];
  166. }
  167. unset($e['orderGoods'], $e['orderGoodsAll']);
  168. $e['orderGoods'] = $orderGoods;
  169. });
  170. }
  171. //审核状态
  172. public function getAuditText($e){
  173. $audit_text = '--';
  174. if($e['delivery_type']==10){
  175. if($e['audit_status'] == AuditStatusEnum::WAIT){ //待专员审核
  176. $audit_text = '待专员审核';
  177. }
  178. elseif($e['audit_status'] == AuditStatusEnum::REJECTED){ //专员已拒绝
  179. $audit_text = '专员已拒绝';
  180. }
  181. else{//专员已同意
  182. if($e['audit_status_zg'] == AuditStatusEnum::WAIT){ // 待主管员审核
  183. $audit_text = '专员已同意';
  184. }
  185. elseif($e['audit_status_zg'] == AuditStatusEnum::REJECTED){ // 主管已拒绝
  186. $audit_text = '主管已拒绝';
  187. }else{//主管已同意
  188. if($e['is_receipt'] == 1) { //待主管员审核
  189. $audit_text = '确认仓库收货';
  190. }else{
  191. $audit_text = '主管已同意';
  192. }
  193. }
  194. }
  195. if($e['status']==RefundStatusEnum::COMPLETED){
  196. if($e['finance_refund']==10&&$e['type']==RefundTypeEnum::COMPLETE){
  197. $audit_text = '已同意';
  198. }else{
  199. $audit_text = '财务已退款';
  200. }
  201. }
  202. }
  203. //门店自提
  204. if($e['delivery_type']==20){
  205. if($e['hx_status']==10){
  206. if($e['audit_status']==AuditStatusEnum::REVIEWED){
  207. $audit_text = '门店已同意';
  208. }
  209. }
  210. if($e['hx_status']==20){
  211. // if($e['status']==RefundStatusEnum::CANCELLED){
  212. // $audit_text = '用户撤销';
  213. // }
  214. if($e['status']==RefundStatusEnum::CLOSE&&$e['audit_status']==AuditStatusEnum::WAIT){
  215. return '用户撤销';
  216. }
  217. if($e['audit_status']==AuditStatusEnum::WAIT){
  218. $audit_text = '待门店审核';
  219. }
  220. if($e['audit_status']==AuditStatusEnum::REVIEWED){
  221. $audit_text = '门店已同意';
  222. }
  223. if($e['audit_status']==AuditStatusEnum::REJECTED){
  224. $audit_text = '门店已拒绝';
  225. }
  226. }
  227. if($e['status']==RefundStatusEnum::COMPLETED){
  228. if($e['finance_refund']==10){
  229. $audit_text = '财务已退款';
  230. }
  231. }
  232. }
  233. return $audit_text;
  234. }
  235. /**
  236. * 获取售后单详情
  237. * @param int $orderRefundId
  238. * @return OrderRefund|false|null
  239. */
  240. public function getDetail(int $orderRefundId)
  241. {
  242. $detail = static::detail($orderRefundId, [
  243. 'orderData', 'orderGoods.image', 'orderGoodsAll.image', 'express', 'address', 'user'
  244. ]);
  245. if (empty($detail)) return false;
  246. $orderGoodsIds = $zengpinOrderGoods = [];
  247. $count = 0;
  248. $count2 = 0;
  249. if (!$detail['order_goods_id']) {
  250. // 整单退款
  251. $orderGoods = $detail['orderGoodsAll'];
  252. foreach($orderGoods as &$goods){
  253. $goods['refund_total_num'] = $goods['total_num'];
  254. }
  255. if($detail['type']!=RefundType::COMPLETE) {
  256. //获取整单退款的所以赠品
  257. $orderGoodsIds = OrderGoodsModel::with(['image'])
  258. ->where('order_id', $detail['order_id'])
  259. ->where('goods_type', GoodsType::GIFT)
  260. ->column('order_goods_id');
  261. }
  262. } else {
  263. $detail['orderGoods']['refund_total_num'] = $detail['goods_num'];
  264. $orderGoods = [$detail['orderGoods']];
  265. if($detail['type']!=RefundType::COMPLETE) {
  266. if($detail['orderGoods']['full_send_activity_id']>0){//如果参与了满就送活动
  267. $checkRefund = RefundService::checkRefund($detail['order_id'],$detail['order_goods_id'],$detail['refund_money']);
  268. if($checkRefund){//获取满就送的所有赠品
  269. $ids = OrderGoodsModel::with(['image'])
  270. ->where('goods_type',GoodsType::GIFT)
  271. ->where('order_id',$detail['order_id'])
  272. ->where('master_order_goods_id',0)
  273. ->column('order_goods_id');
  274. $orderGoodsIds = array_merge($orderGoodsIds,$ids);
  275. }
  276. }
  277. if($detail['orderGoods']['mj_send_activity_id']>0){//如果参与了满件送活动
  278. $checkRefund = RefundService::checkMjRefund($detail['order_id'],$detail['order_goods_id'],$detail['goods_num']);
  279. if($checkRefund){//获取满件送的赠品
  280. $count = $checkRefund;
  281. $ids = OrderGoodsModel::with(['image'])
  282. ->where('goods_type',GoodsType::GIFT)
  283. ->where('order_id',$detail['order_id'])
  284. ->where('master_order_goods_id',$detail['order_goods_id'])
  285. ->column('order_goods_id');
  286. $orderGoodsIds = array_merge($orderGoodsIds,$ids);
  287. }
  288. }
  289. if($detail['orderGoods']['qc_send_activity_id']>0){//如果参与了全场满件送活动
  290. $checkRefund = RefundService::checkQcMjRefund($detail['order_id'],$detail['order_goods_id'],$detail['goods_num']);
  291. if($checkRefund){//获取全场满件送的赠品
  292. $count2 = $checkRefund;
  293. $ids = OrderGoodsModel::with(['image'])
  294. ->where('goods_type',GoodsType::GIFT)
  295. ->where('order_id',$detail['order_id'])
  296. ->where('master_order_goods_id',0)
  297. ->column('order_goods_id');
  298. $orderGoodsIds = array_merge($orderGoodsIds,$ids);
  299. }
  300. }
  301. }
  302. }
  303. unset($detail['orderGoods'], $detail['orderGoodsAll']);
  304. $detail['orderGoods'] = $orderGoods;
  305. if($detail['type']!=RefundType::COMPLETE) {
  306. // $orderGoodsIds = array_column(gettype($orderGoods)=='object'?$orderGoods->toArray():$orderGoods, 'order_goods_id');
  307. $zengpinOrderGoods = OrderGoodsModel::with(['image'])->where('order_goods_id', 'in', $orderGoodsIds)->select()->each(function ($item) use ($count,$count2) {
  308. $item['full_send_activity'] = null;
  309. //添加满就送活动信息
  310. if ($item->is_full_send == 1) {
  311. $item['full_send_activity'] = \app\store\model\fullsend\FullSendActivity::where('id', $item->full_send_activity_id)
  312. ->field('name,code,start_time,end_time,status,"满就送" as type')->find();
  313. }
  314. //添加满件送活动信息
  315. $item['mj_send_activities'] = null;
  316. if ($item->is_mj_send == 1) {
  317. $item['total_num'] = $count;
  318. $item['mj_send_activities'] = \app\store\model\mj\MjSendActivity::where('id', $item->mj_send_activity_id)
  319. ->field('name,code,start_time,end_time,status,"满件送" as type')->find();
  320. }
  321. //添加全场满件送活动信息
  322. $item['qc_send_activities'] = null;
  323. if ($item->is_qc_send_send == 1) {
  324. $item['total_num'] = $count2;
  325. $item['qc_send_activities'] = \app\store\model\qc\QcMjSendActivity::where('id', $item->qc_send_activity_id)
  326. ->field('name,code,start_time,end_time,status,"全场满件送" as type')->find();
  327. }
  328. });
  329. }
  330. $detail['zengpinOrderGoods'] = $zengpinOrderGoods;
  331. return $detail;
  332. }
  333. /**
  334. * 检索查询条件
  335. * @param array $param
  336. * @return array
  337. */
  338. private function getFilter(array $param = []): array
  339. {
  340. // 默认查询条件
  341. $params = $this->setQueryDefaultValue($param, [
  342. 'searchType' => '', // 关键词类型 (10订单号 20会员昵称 30会员ID)
  343. 'searchValue' => '', // 关键词内容
  344. 'refundType' => -1, // 售后类型
  345. 'refundStatus' => -1, // 售后单状态
  346. 'betweenTime' => [], // 申请时间
  347. 'delivery_type' =>-1 //配送方式(10快递配送 20门店自提)
  348. ]);
  349. // 检查查询条件
  350. $filter = [];
  351. //配送方式 (10快递配送 20门店自提)
  352. isset($params['delivery_type'])&&$params['delivery_type']>-1 && $filter[] = ['refund.delivery_type', '=', (int)$params['delivery_type']];
  353. // 售后单编号
  354. !empty($params['refund_number']) && $filter[] = ['refund.refund_number', 'like', '%'.$params['refund_number'].'%'];
  355. // 订单编号
  356. !empty($params['order_no']) && $filter[] = ['order.order_no', 'like', '%'.$params['order_no'].'%'];
  357. // 供应商名称
  358. !empty($params['provider_name']) && $filter[] = ['provider.provider_name', 'like', '%'.$params['provider_name'].'%'];
  359. // 申请人昵称
  360. !empty($params['nick_name']) && $filter[] = ['user.nick_name', 'like', '%'.$params['nick_name'].'%'];
  361. // 用户ID
  362. !empty($params['user_id']) && $filter[] = ['refund.user_id', '=', (int)$params['user_id']];
  363. //手机号码
  364. !empty($params['mobile']) && $filter[] = ['user.mobile', 'like', "%{$params['mobile']}%"];
  365. // 订单时间
  366. if (!empty($params['betweenTime'])) {
  367. $times = between_time($params['betweenTime']);
  368. $filter[] = ['refund.create_time', '>=', $times['start_time']];
  369. $filter[] = ['refund.create_time', '<', $times['end_time'] + 86400];
  370. }
  371. // 售后类型
  372. isset($params['type']) && $params['type'] > -1 && $filter[] = ['refund.type', '=', (int)$params['type']];
  373. // 售后状态
  374. if(isset($params['refund_status']) && $params['refund_status'] > -1){
  375. $this->statusValue($params['refund_status'],$filter);
  376. }
  377. // $params['refundStatus'] > -1 && $filter[] = ['refund.status', '=', (int)$params['refundStatus']];
  378. return $filter;
  379. }
  380. private function statusValue($refundStatus,&$filter){
  381. switch ($refundStatus){
  382. case 0://待专员审核
  383. $filter[] = ['refund.status', '=', RefundStatusEnum::NORMAL]; //进行中
  384. $filter[] = ['refund.audit_status', '=', AuditStatusEnum::WAIT]; //等待专员审核
  385. break;
  386. case 1://已退款
  387. $filter[] = ['refund.status', '=', RefundStatusEnum::COMPLETED]; //已完成
  388. break;
  389. case 2://用户撤销,用户超时未退货,系统自动关闭售后单
  390. $filter[] = ['refund.status', 'in', [RefundStatusEnum::CANCELLED,RefundStatusEnum::CLOSE]]; //已取消
  391. $filter[] = ['refund.close_username', '=', ''];
  392. break;
  393. // case 3://用户超时未退货,系统自动关闭售后单
  394. // $filter[] = ['refund.status', '=', RefundStatusEnum::CLOSE]; //已关闭
  395. // $filter[] = ['refund.close_username', '=', '']; //已关闭
  396. // break;
  397. case 9://后台人员已关闭售后单
  398. $filter[] = ['refund.status', '=', RefundStatusEnum::CLOSE]; //已关闭
  399. $filter[] = ['refund.close_username', '<>', '']; //已关闭
  400. break;
  401. case 4://不同意
  402. $filter[] = ['refund.status', '=', RefundStatusEnum::REJECTED]; //已拒绝
  403. break;
  404. case 5://待主管审核
  405. $filter[] = ['refund.status', '=', RefundStatusEnum::NORMAL]; //进行中
  406. $filter[] = ['refund.audit_status', '=', AuditStatusEnum::REVIEWED]; //专员已审核通过
  407. $filter[] = ['refund.audit_status_zg', '=', AuditStatusEnum::WAIT]; //主管待审核
  408. break;
  409. case 6://待买家退货
  410. $filter[] = ['refund.status', '=', RefundStatusEnum::NORMAL]; //进行中
  411. $filter[] = ['refund.audit_status', '=', AuditStatusEnum::REVIEWED]; //专员已审核通过
  412. $filter[] = ['refund.audit_status_zg', '=', AuditStatusEnum::REVIEWED]; //主管已审核通过
  413. $filter[] = ['refund.is_user_send', '=', 0]; //用户未发货
  414. break;
  415. case 7://待仓库收货
  416. $filter[] = ['refund.status', '=', RefundStatusEnum::NORMAL]; //进行中
  417. $filter[] = ['refund.audit_status', '=', AuditStatusEnum::REVIEWED]; //专员已审核通过
  418. $filter[] = ['refund.audit_status_zg', '=', AuditStatusEnum::REVIEWED]; //主管已审核通过
  419. $filter[] = ['refund.is_user_send', '=', 1]; //用户已发货
  420. $filter[] = ['refund.is_receipt', '=', 0]; //仓库未收货
  421. break;
  422. case 8://待退款
  423. $filter[] = ['refund.status', '=', RefundStatusEnum::NORMAL]; //进行中
  424. $filter[] = ['refund.audit_status', '=', AuditStatusEnum::REVIEWED]; //专员已审核通过
  425. $filter[] = ['refund.audit_status_zg', '=', AuditStatusEnum::REVIEWED]; //主管已审核通过
  426. $filter[] = ['refund.is_user_send', '=', 1]; //用户已发货
  427. $filter[] = ['refund.is_receipt', '=', 1]; //仓库已收货
  428. $filter[] = ['refund.finance_refund', '=', 0]; //财务未退款
  429. break;
  430. }
  431. return $filter;
  432. }
  433. /**
  434. * 专员审核
  435. * @param array $data
  436. * @return bool
  437. */
  438. public function audit(array $data): bool
  439. {
  440. if ($data['audit_status'] == AuditStatusEnum::REJECTED && empty($data['refuse_desc'])) {
  441. // $this->error = '请输入拒绝原因';
  442. // return false;
  443. }
  444. if ($data['audit_status'] == AuditStatusEnum::REJECTED){
  445. $data['status'] = RefundStatusEnum::REJECTED;
  446. }
  447. // if ($data['audit_status'] == AuditStatusEnum::REVIEWED && empty($data['address_id'])) {
  448. // $this->error = '请选择退货地址';
  449. // return false;
  450. // }
  451. $this->transaction(function () use ($data) {
  452. $user = StoreUserService::getLoginInfo();
  453. $real_name = $user['user']['real_name']??'';
  454. $order_refund_id = (int)$this['order_refund_id'];
  455. //退货退款
  456. if($this['type'] == RefundTypeEnum::RETURN){
  457. if ($data['audit_status'] == AuditStatusEnum::REVIEWED) {
  458. $data['status'] = 0;
  459. $address = OrderRefundAddress::where("order_refund_id",$order_refund_id)->find();
  460. if(empty($address)){
  461. $orderGoods = OrderGoodsModel::where('order_goods_id',$this['order_goods_id'])->find();
  462. $provider_id = (int)$orderGoods['provider_id'];
  463. (new OrderRefundAddress())->addProviderAddress($order_refund_id, $provider_id);
  464. }
  465. }
  466. //专员拒绝 写一个协商记录
  467. if($data['audit_status'] == AuditStatusEnum::REJECTED){
  468. $json_str = json_encode(["平台已拒绝","退款类型:退货退款","申请原因:".$this['apply_desc'],"退款说明:".$this['apply_detail_desc']]);
  469. $his_type = 3;
  470. $name = '公明腊肠官方体验商城';
  471. (new RefundHis())->add($this['order_refund_id'],$name,$his_type,$json_str,$this['images'],$real_name,'专员拒绝');
  472. }else{
  473. $json_str = json_encode([""]);
  474. $his_type = 0;//这个类型不在前台显示
  475. $name = '';
  476. (new RefundHis())->add($this['order_refund_id'],$name,$his_type,$json_str,$this['images'],$real_name,'专员同意');
  477. }
  478. }
  479. //未发货直接退款
  480. if($this['type'] == RefundTypeEnum::COMPLETE){
  481. //看是不是专员同意了,
  482. if($data['audit_status'] == AuditStatusEnum::REVIEWED){
  483. $orderGoods = OrderGoodsModel::where('order_goods_id',$this['order_goods_id'])->find();
  484. $express_no = $orderGoods['express_no']??'';
  485. //看是不是未发货,没发货的话
  486. if(empty($express_no)){
  487. //看退款了没,没的话给退款
  488. if($this['finance_refund']==0){
  489. $data['out_refund_time'] = time(); //退款时间
  490. $data['refund_succ_time'] = time(); //退款成功时间
  491. $data['finance_refund'] = 10;
  492. $data['is_sys_refund'] = 1;
  493. $data['status'] =20;
  494. // $param['handle_agree'] = 1; //平台同意退款
  495. // $param['handle_time'] = time(); //平台同意退款时间
  496. $refund_res = OrderRefundModel::where('order_refund_id',$this['order_refund_id'])->update($data);
  497. $order = Order::where("order_id",$this['order_id'])->find();
  498. //直接退款逻辑处理 不直接退款
  499. $RefundService = new RefundService();
  500. $refund_ret = $RefundService->execute($order,$this['refund_number'],$this['refund_money']);
  501. if ($refund_ret['status'] == 200) {
  502. $data['transaction_id'] = $refund_ret['data']['transaction_id']; // 微信退款交易号
  503. }
  504. $json_str = json_encode(["退款成功"]);
  505. $his_type = 2;
  506. $name = '公明腊肠官方体验商城';
  507. (new RefundHis())->add($this['order_refund_id'],$name,$his_type,$json_str,$this['images'],$real_name,'专员同意');
  508. //订单商品修改成全额退款状态-2021年11月6日 15:24:19
  509. OrderGoodsModel::updateBase(['has_refund_full' => 1,'frozen_status'=>0], ['order_goods_id'=>$this['order_goods_id']]);
  510. //关闭订单状态
  511. $RefundService = new OrderService();
  512. $RefundService->closeOrder($this['order_id']);
  513. //写入金米粒记录
  514. GoldRice::refundGoldRiceRoad($order,$this);
  515. //售后单完成之后,把库存退回
  516. if($orderGoods['total_num']==$this['goods_num']){
  517. FactoryStock::getFactory($order['order_source'])->backGoodsSkuStock($order,$orderGoods['goods_id'],$orderGoods['goods_sku_id'],$this['goods_num']);
  518. //售后单成功退了某商品的全部数量,把库存退回给活动库存
  519. FactoryStock::getFactory($order['order_source'])->backActivityGoodsStock($orderGoods,$this['goods_num']);
  520. }
  521. }
  522. }
  523. }else{
  524. $json_str = json_encode(["平台已拒绝","退款类型:仅退款","申请原因:".$this['apply_desc']]);
  525. $his_type = 3;
  526. $name = '公明腊肠官方体验商城';
  527. (new RefundHis())->add($this['order_refund_id'],$name,$his_type,$json_str,$this['images'],$real_name,'专员拒绝');
  528. }
  529. }
  530. $this->save($data);
  531. });
  532. return true;
  533. }
  534. //关闭售后单
  535. public function close(array $data=[]): bool
  536. {
  537. $user = StoreUserService::getLoginInfo();
  538. $real_name = $user['user']['real_name']??'';
  539. //未发货退款
  540. if ($this['type'] == RefundTypeEnum::COMPLETE) {
  541. if($this['audit_status']!=AuditStatusEnum::REJECTED||$this['status']==RefundStatusEnum::CANCELLED){
  542. $this->error = '未发货退款售后单需要专员拒绝或用户取消';
  543. return false;
  544. }
  545. }
  546. //发货退款
  547. if ($this['type'] == RefundTypeEnum::RETURN) {
  548. if(($this['audit_status']!=AuditStatusEnum::REJECTED&&$this['audit_status_zg']!=AuditStatusEnum::REJECTED&&$this['is_receipt']!=2)||$this['status']==RefundStatusEnum::CANCELLED){
  549. $this->error = '退货退款售后单需要专员和主管都拒绝或用户取消';
  550. return false;
  551. }
  552. }
  553. //售后单已关闭
  554. if($this['status']==RefundStatusEnum::COMPLETED){
  555. $this->error = '售后单已完成,不能关闭吧';
  556. return false;
  557. }
  558. //售后单已完成
  559. if($this['status']==RefundStatusEnum::CLOSE){
  560. $this->error = '售后单已关闭,不要重复操作';
  561. return false;
  562. }
  563. $param['status'] = RefundStatusEnum::CLOSE;
  564. $param['close_username'] = $real_name;
  565. $this->save($param);
  566. $this->transaction(function () use ($data) {
  567. });
  568. return true;
  569. }
  570. /**
  571. * 主管审核
  572. * @param array $data
  573. * @return bool
  574. */
  575. public function auditzg(array $data): bool
  576. {
  577. if ($data['audit_status_zg'] == AuditStatusEnum::REJECTED && empty($data['refuse_desc'])) {
  578. // $this->error = '请输入拒绝原因';
  579. // return false;
  580. }
  581. if ($data['audit_status_zg'] == AuditStatusEnum::REJECTED){
  582. $data['status'] = RefundStatusEnum::REJECTED;
  583. if($this['audit_status']!=AuditStatusEnum::REVIEWED){
  584. $this->error = '专员同意后 主管才能拒绝';
  585. return false;
  586. }
  587. }
  588. $this->transaction(function () use ($data) {
  589. $user = StoreUserService::getLoginInfo();
  590. $real_name = $user['user']['real_name']??'';
  591. $order_refund_id = (int)$this['order_refund_id'];
  592. //退货退款
  593. if($this['type'] == RefundTypeEnum::RETURN){
  594. $data['status'] = 0;
  595. if($data['audit_status_zg'] == AuditStatusEnum::REVIEWED) {
  596. $json_str = json_encode(["处理结果:同意","平台同意了本次售后服务申请"]);
  597. $his_type = 6;
  598. $name = '公明腊肠官方体验商城';
  599. (new RefundHis())->add($this['order_refund_id'],$name,$his_type,$json_str,$this['images'], $real_name,'主管同意');
  600. $data['approved_time'] = time();
  601. }
  602. if ($data['audit_status_zg'] == AuditStatusEnum::REJECTED) {
  603. $data['status'] = 10;
  604. $json_str = json_encode(["平台已拒绝","退款类型:退货退款","申请原因:".$this['apply_desc'],"退款说明:".$this['apply_detail_desc']]);
  605. $his_type = 5;
  606. $name = '公明腊肠官方体验商城';
  607. (new RefundHis())->add($this['order_refund_id'],$name,$his_type,$json_str,$this['images'],$real_name,'主管已拒绝');
  608. }
  609. }
  610. $this->save($data);
  611. });
  612. return true;
  613. }
  614. /**
  615. * 确认收货
  616. * @return bool
  617. */
  618. public function receipt($data): bool
  619. {
  620. //原来的确认收货
  621. if($data['is_receipt']==1){
  622. // 事务处理
  623. $this->transaction(function () use ($data){
  624. $user = StoreUserService::getLoginInfo();
  625. $real_name = $user['user']['real_name']??'';
  626. $data['is_receipt'] = 1;
  627. $this->save($data);
  628. $json_str = json_encode(["仓库已确认收货"]);
  629. $his_type = 8;
  630. $name = '公明腊肠官方体验商城';
  631. (new RefundHis())->add($this['order_refund_id'],$name,$his_type,$json_str,'',$real_name,'专员点击确认仓库收货');
  632. //标记是否退货zq 2021/11/5
  633. OrderGoods::where('order_goods_id', $this['order_goods_id'])->update(['has_refund_act' => 1]);
  634. });
  635. }
  636. //仓库不同意收货,改专员和主管审核状态为拒绝
  637. if($data['is_receipt']==2){
  638. $this->transaction(function () use ($data){
  639. $user = StoreUserService::getLoginInfo();
  640. $real_name = $user['user']['real_name']??'';
  641. $data['is_receipt'] = 2;
  642. //专员拒绝 主管拒绝
  643. // $data['audit_status'] = 20;
  644. // $data['audit_status_zg'] = 20;
  645. $refuse_desc = $data['refuse_desc']??'';
  646. $this->save($data);
  647. $json_str = json_encode(["退货检测不合格,拒绝退货","退款说明:".$refuse_desc]);
  648. $his_type = 14;
  649. $name = '公明腊肠官方体验商城';
  650. (new RefundHis())->add($this['order_refund_id'],$name,$his_type,$json_str,'',$real_name,'退货检测不合格,拒绝退货');
  651. });
  652. }
  653. return true;
  654. }
  655. /**
  656. * 财务退款
  657. * @return bool
  658. */
  659. public function refund(): bool
  660. {
  661. if ($this['refund_money'] <= 0) {
  662. $this->error = '退款金额不能小于0';
  663. return false;
  664. }
  665. // 订单详情
  666. $order = Order::detail($this['order_id']);
  667. $thatMoney = min(($order['pay_price']+$order['rice_card_money']), ($this['orderGoods']['total_pay_price']+$this['orderGoods']['rice_card_money']));
  668. if(floatval($this['refund_money'])*100>$thatMoney*100){
  669. $this->error = '退款金额不能大于商品实付款金额';
  670. return false;
  671. }
  672. // if ($this['refund_money'] > min(($order['pay_price']+$order['rice_card_money']), ($this['orderGoods']['total_pay_price']+$this['orderGoods']['rice_card_money']))) {
  673. // $this->error = '退款金额不能大于商品实付款金额';
  674. // return false;
  675. // }
  676. // 事务处理
  677. $this->transaction(function () use ($order) {
  678. $user = StoreUserService::getLoginInfo();
  679. $real_name = $user['user']['real_name']??'';
  680. // 更新售后单状态
  681. $this->save([
  682. 'status' => RefundStatusEnum::COMPLETED,
  683. 'finance_refund' => 10,
  684. 'finance_refund_time' => time(),
  685. 'out_refund_time' => time(),
  686. 'refund_succ_time' => time(),
  687. 'refund_close_time' => time(),
  688. ]);
  689. $json_str = json_encode(["财务已退款"]);
  690. $his_type = 9;
  691. $name = '公明腊肠官方体验商城';
  692. (new RefundHis())->add($this['order_refund_id'],$name,$his_type,$json_str,'',$real_name,'财务退款');
  693. $orderGoods = OrderGoods::where('order_goods_id', $this['order_goods_id'])->find();
  694. $orderGoods->frozen_status = 0;// 解冻订单商品
  695. // 消减用户的实际消费金额
  696. // 条件:判断订单是否已结算
  697. // if ($order['is_settled'] == true) {
  698. // (new UserModel)->setDecUserExpend($order['user_id'], $this['refund_money']);
  699. // }
  700. if ($this['pay_money'] > 0) {
  701. // 执行原路退款
  702. $refund_ret = (new RefundService)->execute($order, $this['refund_number'], $this['pay_money']);
  703. if ($refund_ret['status'] == 200) {
  704. $this->save([
  705. 'transaction_id' => $refund_ret['data']['transaction_id'] // 微信退款交易号
  706. ]);
  707. }
  708. }
  709. //如果退货的商品和购买的商品相等
  710. if($this['goods_num']==$orderGoods['total_num']){
  711. $orderGoods->has_refund_full = 1;
  712. }
  713. $orderGoods->save();//更新
  714. //原路退回商品库存 退货的商品和购买的商品相等
  715. if($this['goods_num']==$orderGoods['total_num']){
  716. FactoryStock::getFactory($order['order_source'])->backGoodsSkuStock($order,$orderGoods['goods_id'],$orderGoods['goods_sku_id'],$this['goods_num']);
  717. }
  718. //售后单成功退了某商品的全部数量,把库存退回给活动库存
  719. FactoryStock::getFactory($order['order_source'])->backActivityGoodsStock($orderGoods,$this['goods_num']);
  720. // 解冻订单商品
  721. //订单商品修改成全额退款状态-2021年11月6日 15:24:19
  722. // OrderGoodsModel::updateBase(['has_refund_full' => 1], ['order_goods_id'=>$this['order_goods_id']]);
  723. //关闭订单状态
  724. $RefundService = new OrderService();
  725. $RefundService->closeOrder($this['order_id']);
  726. //写入金米粒记录
  727. GoldRice::refundGoldRiceRoad($order,$this);
  728. $riceCard = UserRiceCardModel::getValidRiceCardDetail($this['rice_card_id']);
  729. if ($this['rice_card_id']) { // 订单商品有使用现金卡
  730. // 验证余额
  731. if ($this['rice_card_money'] + $riceCard['balance'] > $riceCard['face_value']) {
  732. $this->error = "现金卡退还金额异常";
  733. return false;
  734. }
  735. // 写入现金卡流水明细
  736. UserRiceCardConsume::add($riceCard, $order['order_no'], $this['pay_money'], $this['rice_card_money'], 1, '商品退款');
  737. // 退还现金卡金额
  738. UserRiceCard::setIncByField($this['rice_card_id'], 'balance', (float)$this['rice_card_money']);
  739. $riceCard->effect_state = 1; // 改为 生效
  740. $riceCard->save();
  741. }
  742. // 发送消息通知
  743. // MessageService::send('order.refund', [
  744. // 'refund' => $this, // 退款单信息
  745. // 'order_no' => $order['order_no'], // 订单信息
  746. // ], $this['store_id']);
  747. });
  748. return true;
  749. }
  750. /**
  751. * 获取待处理售后单数量
  752. * @return int
  753. */
  754. public function getRefundTotal()
  755. {
  756. return $this->where('status', '=', RefundStatusEnum::NORMAL)->count();
  757. }
  758. /**
  759. * 获取退款单列表
  760. * @param array $param
  761. * @return mixed
  762. */
  763. public function getFinanceList(array $param = [])
  764. {
  765. // 检索查询条件
  766. $filter = $this->getFinanceFilter($param);
  767. // 获取列表数据
  768. return $this->alias('refund')
  769. ->field('refund.*, order.order_no')
  770. ->with(['orderGoods.image', 'orderGoodsAll.image', 'orderData', 'user.avatar'])
  771. ->join('order', 'order.order_id = refund.order_id')
  772. ->join('user', 'user.user_id = order.user_id')
  773. ->leftJoin('orderGoods', 'orderGoods.order_goods_id=refund.order_goods_id')
  774. ->leftJoin('provider', 'provider.provider_id = orderGoods.provider_id')
  775. ->where($filter)
  776. ->where(function ($query) {
  777. $query->whereOr(function ($query) {
  778. $query->where('type', '=', 10)
  779. ->where('is_user_send','=',1)
  780. ->where('is_receipt','=',1);
  781. })->whereOr(function ($query) {
  782. $query->where('type', '=', 30);
  783. });
  784. })
  785. ->order(['refund.create_time' => 'desc', 'refund.' . $this->getPk()])
  786. ->paginate(15)
  787. ->each(function($item) {
  788. $item->can_refund = false;
  789. if ($item->type == 10 && $item->finance_refund == 0 && $item->is_user_send == 1 && $item->status == 0 && $item->is_receipt == 1) {
  790. // 退款类型为退货退款、财务退款状态为未退款、用户已发货 售后状态为进行中 商家已收货
  791. $item->can_refund = true;
  792. }
  793. $pay_type_text ='微信';
  794. if($item->pay_money>0&&$item->rice_card_id>0){
  795. $pay_type_text = '微信+现金卡';
  796. }
  797. if($item->pay_money==0&&$item->rice_card_id>0){
  798. $pay_type_text = '现金卡';
  799. }
  800. $item->pay_type_text = $pay_type_text;
  801. if (!$item['order_goods_id']) {
  802. // 整单退款
  803. $orderGoods = $item['orderGoodsAll'];
  804. } else {
  805. $item['orderGoods']['total_num'] = $item['goods_num'];
  806. $orderGoods = [$item['orderGoods']];
  807. }
  808. unset($item['orderGoods'], $item['orderGoodsAll']);
  809. $item['orderGoods'] = $orderGoods[0];
  810. });
  811. }
  812. /**
  813. * 检索查询条件
  814. * @param array $param
  815. * @return array
  816. */
  817. private function getFinanceFilter(array $param = []): array
  818. {
  819. // 默认查询条件
  820. $params = $this->setQueryDefaultValue($param, [
  821. 'refund_number' => '', // 退款单编号
  822. 'order_no' => '', // 订单编号
  823. 'provider_name' => '', // 供应商名称
  824. 'nick_name' => '', // 退款人姓名
  825. 'mobile' => '', // 退款人手机号
  826. 'betweenTime' => [], // 申请时间
  827. 'finance_refund' => -1, // 财务退款状态
  828. 'delivery_type' =>-1, //10 快递 20 自提
  829. 'supplier' => '', // 供应商品牌
  830. 'type' => -1, // 退款类型 10-退货退款 30-仅退款
  831. 'transaction_id' => '',// 微信交易流水号
  832. ]);
  833. // 检查查询条件
  834. $filter = [];
  835. // $filter[] = ['type', '=', 10];
  836. // $filter[] = ['is_user_send', '=', 1];
  837. // $filter[] = ['is_receipt', '=', 1];
  838. $filter[] = ['status', 'in', [0, 20]];
  839. isset($params['delivery_type'])&&$params['delivery_type']>-1 && $filter[] = ['refund.delivery_type', '=', (int)$params['delivery_type']];
  840. !empty($params['refund_number']) && $filter[] = ['refund.refund_number', 'like', "%{$params['refund_number']}%"];
  841. !empty($params['order_no']) && $filter[] = ['order.order_no', 'like', "%{$params['order_no']}%"];
  842. !empty($params['provider_name']) && $filter[] = ['provider.provider_name', 'like', "%{$params['provider_name']}%"];
  843. !empty($params['nick_name']) && $filter[] = ['user.nick_name', 'like', "%{$params['nick_name']}%"];
  844. !empty($params['mobile']) && $filter[] = ['user.mobile', 'like', "%{$params['mobile']}%"];
  845. // 起止时间
  846. if (!empty($params['betweenTime'])) {
  847. $times = between_time_format($params['betweenTime']);
  848. $filter[] = ['refund.create_time', '>=', $times['start_time']];
  849. $filter[] = ['refund.create_time', '<', $times['end_time']];
  850. }
  851. // 财务退款状态
  852. $params['finance_refund'] > -1 && $filter[] = ['refund.finance_refund', '=', (int)$params['finance_refund']];
  853. !empty($params['supplier']) && $filter[] = ['order_goods.supplier', 'like', "%{$params['supplier']}%"];
  854. isset($params['type'])&&$params['type']>-1 && $filter[] = ['refund.type', '=', (int)$params['type']];
  855. !empty($params['transaction_id']) && $filter[] = ['refund.transaction_id', 'like', "%{$params['transaction_id']}%"];
  856. return $filter;
  857. }
  858. /**
  859. * 获取累计退款金额
  860. */
  861. public function getRefundMoneyTotal()
  862. {
  863. return $this->where('status', '=', RefundStatusEnum::CANCELLED)->where('finance_refund', 10)->sum('refund_money');
  864. }
  865. /**
  866. * 普通退款订单列表
  867. * @return array
  868. * @throws \think\db\exception\DataNotFoundException
  869. * @throws \think\db\exception\DbException
  870. * @throws \think\db\exception\ModelNotFoundException
  871. */
  872. public function refundsExport($param){
  873. $filter = $this->getFinanceFilter($param);
  874. // 获取列表数据
  875. $list = $this->alias('refund')
  876. ->field('refund.*, order.order_no')
  877. ->with(['orderGoods.image', 'orderGoodsAll.image', 'orderData', 'user.avatar'])
  878. ->join('order', 'order.order_id = refund.order_id')
  879. ->join('user', 'user.user_id = order.user_id')
  880. ->leftJoin('orderGoods', 'orderGoods.order_goods_id=refund.order_goods_id')
  881. ->leftJoin('provider', 'provider.provider_id = orderGoods.provider_id')
  882. ->where($filter)
  883. ->where(function ($query) {
  884. $query->whereOr(function ($query) {
  885. $query->where('type', '=', 10)
  886. ->where('is_user_send','=',1)
  887. ->where('is_receipt','=',1);
  888. })->whereOr(function ($query) {
  889. $query->where('type', '=', 30);
  890. });
  891. })
  892. ->order(['refund.create_time' => 'desc', 'refund.' . $this->getPk()])
  893. ->select()
  894. ->each(function($item) {
  895. $item->can_refund = false;
  896. if ($item->type == 10 && $item->finance_refund == 0 && $item->is_user_send == 1 && $item->status == 0 && $item->is_receipt == 1) {
  897. // 退款类型为退货退款、财务退款状态为未退款、用户已发货 售后状态为进行中 商家已收货
  898. $item->can_refund = true;
  899. }
  900. $pay_type_text ='微信';
  901. if($item->pay_money>0&&$item->rice_card_id>0){
  902. $pay_type_text = '微信+现金卡';
  903. }
  904. if($item->pay_money==0&&$item->rice_card_id>0){
  905. $pay_type_text = '现金卡';
  906. }
  907. $item->pay_type_text = $pay_type_text;
  908. if (!$item['order_goods_id']) {
  909. // 整单退款
  910. $orderGoods = $item['orderGoodsAll'];
  911. } else {
  912. $item['orderGoods']['total_num'] = $item['goods_num'];
  913. $orderGoods = [$item['orderGoods']];
  914. }
  915. unset($item['orderGoods'], $item['orderGoodsAll']);
  916. $item['orderGoods'] = $orderGoods[0];
  917. });
  918. $data['header'] = ['序号', '退款单编号','订单编号','配送方式', '商品名称','规格','品牌','退款金额','申请时间', '退款类型','退款状态', '会员昵称','会员手机号','微信交易流水号'];
  919. $data['filename'] = '普通退款单列表导出';
  920. $data['data'] = [];
  921. foreach ($list as $key=>$arr){
  922. $new_list['key'] = $key+1;
  923. $new_list['refund_number'] = $arr['refund_number'];
  924. $new_list['order_no'] = $arr['orderData']['order_no'];
  925. $new_list['delivery_type'] = $arr['delivery_type']==10?'普通配送':'门店自提';
  926. $new_list['goods_name'] = $arr['orderGoods']['goods_name'];
  927. $new_list['goods_props'] = $arr['orderGoods']['goods_props'][0]['value']['name']??'-';
  928. $new_list['supplier'] = $arr['orderGoods']['supplier'] ?: '-';
  929. $new_list['refund_money'] = $arr['refund_money'];
  930. $new_list['create_time'] = $arr['create_time'];
  931. $new_list['type'] = str_replace([10, 20, 30], ['退货退款','不退货退款', '仅退款'], $arr['type']);
  932. $new_list['finance_refund_text'] = $arr['finance_refund_text'];
  933. $new_list['nick_name'] = $arr['user']['nick_name'];
  934. $new_list['mobile'] = $arr['user']['mobile'];
  935. $new_list['transaction_id'] = $arr['transaction_id'] ?: '-';
  936. $data['data'][] = $new_list;
  937. }
  938. return $data;
  939. }
  940. }