RefundCompensate.php 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592
  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\store\model\Setting as SettingModel;
  14. use app\store\service\User as UserService;
  15. use app\store\model\OrderGoods as OrderGoodsModel;
  16. use app\store\model\Order as OrderModel;
  17. // use app\common\model\order\RefundHis as RefundHisModel;
  18. // use app\common\model\order\RefundHis;
  19. use app\common\model\RefundCompensate as RefundCompensateModel;
  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\enum\order\refund\FinanceRefundStatus as FinanceRefundStatusEnum;
  24. use app\common\exception\BaseException;
  25. use app\common\service\Kuaidi as KuaidiService;
  26. // use app\store\model\OrderGoods;
  27. use app\common\service\Order as OrderService;
  28. use app\common\service\store\User as StoreUserService;
  29. use app\common\model\User as UserModel;
  30. use app\common\model\RefundCompensateHis as RefundCompensateHisModel;
  31. use app\api\model\card\UserRiceCard as UserRiceCardModel;
  32. use app\api\model\card\UserRiceCardConsume;
  33. use app\common\service\order\Refund as RefundService;
  34. /**
  35. * 售后补偿单模型
  36. * Class OrderRefund
  37. * @package app\api\model
  38. */
  39. class RefundCompensate extends RefundCompensateModel
  40. {
  41. /**
  42. * 隐藏字段
  43. * @var array
  44. */
  45. protected $hidden = [
  46. // 'store_id',
  47. // 'update_time'
  48. ];
  49. /**
  50. * 追加字段
  51. * @var array
  52. */
  53. protected $append = [
  54. 'state_text', // 售后补偿单状态
  55. // 'dfh_time', // 待用户发货倒计时
  56. ];
  57. /**
  58. * 添加补偿单
  59. * @param array $data
  60. * @return bool
  61. * @throws \think\db\exception\DataNotFoundException
  62. * @throws \think\db\exception\DbException
  63. * @throws \think\db\exception\ModelNotFoundException
  64. */
  65. public function edit(array $data)
  66. {
  67. $user = StoreUserService::getLoginInfo();
  68. $real_name = $user['user']['real_name']??'';
  69. // $data['refund_number'] = OrderService::createOrderNoPrefix('TKBC'); //
  70. // $data['order_id'] = $data['order_id']??0;
  71. // $data['submit_zy'] = $real_name;
  72. // // 事务处理
  73. $this->transaction(function () use ($data) {
  74. // 添加
  75. $this->save($data);
  76. });
  77. return true;
  78. }
  79. /**
  80. * 添加补偿单
  81. * @param array $data
  82. * @return bool
  83. * @throws \think\db\exception\DataNotFoundException
  84. * @throws \think\db\exception\DbException
  85. * @throws \think\db\exception\ModelNotFoundException
  86. */
  87. public function add(array $data){
  88. $user = StoreUserService::getLoginInfo();
  89. $real_name = $user['user']['real_name']??'';
  90. $data['refund_number'] = OrderService::createOrderNoPrefix('TKBC'); //
  91. $data['order_id'] = $data['order_id']??0;
  92. $data['submit_zy'] = $real_name;
  93. // // 事务处理
  94. $this->transaction(function () use ($data) {
  95. // 添加
  96. $this->save($data);
  97. });
  98. return true;
  99. }
  100. // /**
  101. // * 售后补偿单状态文字描述
  102. // * @param $value
  103. // * @param $data
  104. // * @return string
  105. // */
  106. public function getStateTextAttr($value, $data)
  107. {
  108. // 已完成
  109. if(!isset($data['status'])){
  110. return ['value'=>0,'name'=>'进行中'];
  111. }
  112. if ($data['status'] == 0&&$data['audit_status_zg']==0) {
  113. return ['value'=>1,'name'=>'待主管审核'];
  114. }
  115. // 已取消
  116. if ($data['finance_refund']==0&&$data['audit_status_zg']==10) {
  117. return ['value'=>2,'name'=>'待退款'];
  118. }
  119. // 待专员修改
  120. if ($data['status'] == 0&&$data['audit_status_zg']==20) {
  121. return ['value'=>3,'name'=>'待专员修改'];
  122. }
  123. // 已关闭
  124. if ($data['status'] == 40) {
  125. return ['value'=>4,'name'=>'已关闭'];
  126. }
  127. // 已退款
  128. if ($data['status'] == 20&&$data['finance_refund']==10) {
  129. return ['value'=>5,'name'=>'已退款'];
  130. }
  131. return ['value'=>0,'name'=>'进行中'];
  132. }
  133. /**
  134. * 获取售后补偿单列表 财务
  135. * @param
  136. * @return \think\Paginator
  137. * @throws \app\common\exception\BaseException
  138. * @throws \think\db\exception\DbException
  139. */
  140. public function getFinanceList(array $param=[])
  141. {
  142. // 检索查询条件
  143. $filter = [];
  144. $filter = $this->getFinanceFilter($param);
  145. // 售后补偿单状态
  146. // $state > -1 && $filter[] = ['status', '=', $state];
  147. // 当前用户ID
  148. // $userId = UserService::getCurrentLoginUserId();
  149. // 查询列表记录
  150. return $this->alias('refund')->field('refund.*, order.order_no,order.order_id,order.create_time as order_create_time,order.user_id,user.nick_name,user.mobile')->with(['orderData','orderGoods.image'])
  151. ->where($filter)->where('audit_status_zg',10) //主管同意
  152. ->leftJoin('orderGoods', 'orderGoods.order_goods_id = refund.order_goods_id')
  153. ->leftjoin('order', 'order.order_id = refund.order_id')
  154. ->join('user', 'user.user_id = order.user_id')
  155. ->leftJoin('provider', 'provider.provider_id = orderGoods.provider_id')
  156. // ->where('user_id', '=', $userId)
  157. ->order(['refund.create_time' => 'desc'])
  158. ->paginate(15)
  159. ->each(function($item) {
  160. $mobile = UserModel::where('user_id',$item['user_id'])->value("mobile");
  161. $item['orderData']['mobile'] = $mobile;
  162. $item['type'] = 'finance';
  163. $item['orderData']['pay_type_text'] = '微信';
  164. $pay_type_text ='微信';
  165. if($item['orderData']['pay_price']>0&& $item['orderData']['rice_card_id']>0){
  166. $pay_type_text = '微信+现金卡';
  167. }
  168. if($item['orderData']['pay_price']==0&&$item['orderData']['rice_card_id']>0){
  169. $pay_type_text = '现金卡';
  170. }
  171. $item['pay_type_text'] = $pay_type_text;
  172. });
  173. }
  174. /**
  175. * 补偿退款订单列表
  176. * @return array
  177. * @throws \think\db\exception\DataNotFoundException
  178. * @throws \think\db\exception\DbException
  179. * @throws \think\db\exception\ModelNotFoundException
  180. */
  181. public function refundsExport($param){
  182. $filter = $this->getFinanceFilter($param);
  183. // 获取列表数据
  184. $list = $this->alias('refund')->field('refund.*, order.order_no,order.order_id,order.create_time as order_create_time,order.user_id,user.nick_name,user.mobile')
  185. ->with(['orderData','orderGoods.image'])
  186. ->where($filter)->where('audit_status_zg',10) //主管同意
  187. ->leftJoin('orderGoods', 'orderGoods.order_goods_id = refund.order_goods_id')
  188. ->leftjoin('order', 'order.order_id = refund.order_id')
  189. ->join('user', 'user.user_id = order.user_id')
  190. ->leftJoin('provider', 'provider.provider_id = orderGoods.provider_id')
  191. ->order(['refund.create_time' => 'desc'])
  192. ->select();
  193. $data['header'] = ['序号', '退款单编号','订单编号','配送方式', '商品名称','规格','品牌','退款金额','申请时间','退款状态', '会员昵称','会员手机号','微信交易流水号'];
  194. $data['filename'] = '售后补偿退款单列表导出';
  195. $data['data'] = [];
  196. foreach ($list as $key=>$arr){
  197. $new_list['key'] = $key+1;
  198. $new_list['refund_number'] = $arr['refund_number'];
  199. $new_list['order_no'] = $arr['orderData']['order_no'];
  200. $new_list['delivery_type'] = $arr['orderData']['delivery_type']==10?'普通配送':'门店自提';
  201. $new_list['goods_name'] = $arr['orderGoods']['goods_name'];
  202. $new_list['goods_props'] = $arr['orderGoods']['goods_props'][0]['value']['name']??'-';
  203. $new_list['supplier'] = $arr['orderGoods']['supplier'] ?: '-';
  204. $new_list['refund_money'] = $arr['refund_money'];
  205. $new_list['create_time'] = $arr['create_time'];
  206. $new_list['finance_refund_text'] = $arr['state_text']['name'];
  207. $new_list['nick_name'] = $arr['nick_name'];
  208. $new_list['mobile'] = $arr['mobile'];
  209. $new_list['transaction_id'] = $arr['transaction_id'] ?: '-';
  210. $data['data'][] = $new_list;
  211. }
  212. return $data;
  213. }
  214. /**
  215. * 检索查询条件
  216. * @param array $param
  217. * @return array
  218. */
  219. private function getFinanceFilter(array $param = []): array
  220. {
  221. // 默认查询条件
  222. $params = $this->setQueryDefaultValue($param, [
  223. 'finance_refund' => -1, // 关键词类型 (10订单号 20会员昵称 30会员ID)
  224. // 'searchValue' => '', // 关键词内容
  225. // 'refundType' => -1, // 售后类型
  226. // 'refundStatus' => -1, // 售后单状态
  227. // 'betweenTime' => [], // 申请时间
  228. // 'delivery_type' =>-1 //配送方式(10快递配送 20门店自提)
  229. 'supplier' => '', // 供应商品牌
  230. 'type' => -1, // 退款类型 10-退货退款 30-仅退款
  231. 'transaction_id' => '',// 微信交易流水号
  232. ]);
  233. // 检查查询条件
  234. $filter = [];
  235. // //配送方式 (10快递配送 20门店自提)
  236. isset($params['delivery_type'])&&$params['delivery_type']>-1 && $filter[] = ['order.delivery_type', '=', (int)$params['delivery_type']];
  237. // 售后单编号
  238. !empty($params['refund_number']) && $filter[] = ['refund.refund_number', 'like', '%'.$params['refund_number'].'%'];
  239. // 退款状态
  240. $params['finance_refund']>-1 && $filter[] = ['refund.finance_refund', '=', $params['finance_refund']];
  241. // 订单编号
  242. !empty($params['order_no']) && $filter[] = ['order.order_no', 'like', '%'.$params['order_no'].'%'];
  243. // // 供应商名称
  244. !empty($params['provider_name']) && $filter[] = ['provider.provider_name', 'like', '%'.$params['provider_name'].'%'];
  245. //手机号码
  246. !empty($params['mobile']) && $filter[] = ['user.mobile', 'like', "%{$params['mobile']}%"];
  247. //退款人姓名:
  248. !empty($params['nick_name']) && $filter[] = ['user.nick_name', 'like', "%{$params['nick_name']}%"];
  249. // 申请时间
  250. if (!empty($params['betweenTime'])) {
  251. $times = between_time_format($params['betweenTime']);
  252. $filter[] = ['refund.create_time', '>=', $times['start_time']];
  253. $filter[] = ['refund.create_time', '<',$times['end_time']];
  254. }
  255. !empty($params['supplier']) && $filter[] = ['order_goods.supplier', 'like', "%{$params['supplier']}%"];
  256. !empty($params['transaction_id']) && $filter[] = ['refund.transaction_id', 'like', "%{$params['transaction_id']}%"];
  257. return $filter;
  258. }
  259. /**
  260. * 获取售后补偿单列表
  261. * @param
  262. * @return \think\Paginator
  263. * @throws \app\common\exception\BaseException
  264. * @throws \think\db\exception\DbException
  265. */
  266. public function getList(array $param=[])
  267. {
  268. // 检索查询条件
  269. $filter = [];
  270. $filter = $this->getFilter($param);
  271. // 售后补偿单状态
  272. // $state > -1 && $filter[] = ['status', '=', $state];
  273. // 当前用户ID
  274. // $userId = UserService::getCurrentLoginUserId();
  275. // 查询列表记录
  276. return $this->alias('refund')->field('refund.*, order.order_no,order.order_id,order.create_time as order_create_time,order.user_id')->with(['orderData','orderGoods.image'])
  277. ->where($filter)
  278. ->leftJoin('orderGoods', 'orderGoods.order_goods_id = refund.order_goods_id')
  279. ->leftjoin('order', 'order.order_id = refund.order_id')
  280. ->join('user', 'user.user_id = order.user_id')
  281. ->leftJoin('provider', 'provider.provider_id = orderGoods.provider_id')
  282. // ->where('user_id', '=', $userId)
  283. ->order(['refund.create_time' => 'desc'])
  284. ->paginate(15)
  285. ->each(function($item) {
  286. $mobile = UserModel::where('user_id',$item['user_id'])->value("mobile");
  287. $item['orderData']['mobile'] = $mobile;
  288. });
  289. }
  290. /**
  291. * 检索查询条件
  292. * @param array $param
  293. * @return array
  294. */
  295. private function getFilter(array $param = []): array
  296. {
  297. // 默认查询条件
  298. $params = $this->setQueryDefaultValue($param, [
  299. // 'searchType' => '', // 关键词类型 (10订单号 20会员昵称 30会员ID)
  300. // 'searchValue' => '', // 关键词内容
  301. // 'refundType' => -1, // 售后类型
  302. // 'refundStatus' => -1, // 售后单状态
  303. // 'betweenTime' => [], // 申请时间
  304. // 'delivery_type' =>-1 //配送方式(10快递配送 20门店自提)
  305. ]);
  306. // 检查查询条件
  307. $filter = [];
  308. // //配送方式 (10快递配送 20门店自提)
  309. isset($params['delivery_type'])&&$params['delivery_type']>-1 && $filter[] = ['order.delivery_type', '=', (int)$params['delivery_type']];
  310. // 售后单编号
  311. !empty($params['refund_number']) && $filter[] = ['refund.refund_number', 'like', '%'.$params['refund_number'].'%'];
  312. !empty($params['submit_zy']) && $filter[] = ['refund.submit_zy', 'like', '%'.$params['submit_zy'].'%'];
  313. // // 订单编号
  314. !empty($params['order_no']) && $filter[] = ['order.order_no', 'like', '%'.$params['order_no'].'%'];
  315. // // 供应商名称
  316. !empty($params['provider_name']) && $filter[] = ['provider.provider_name', 'like', '%'.$params['provider_name'].'%'];
  317. // //手机号码
  318. !empty($params['mobile']) && $filter[] = ['user.mobile', 'like', "%{$params['mobile']}%"];
  319. //售后状态
  320. if(isset($params['refund_status']) && $params['refund_status'] > 0){
  321. $this->statusValue($params['refund_status'],$filter);
  322. }
  323. // 订单时间
  324. if (!empty($params['betweenTime'])) {
  325. $times = between_time($params['betweenTime']);
  326. $filter[] = ['order.create_time', '>=', $times['start_time']];
  327. $filter[] = ['order.create_time', '<',$times['end_time'] + 86400];
  328. }
  329. return $filter;
  330. }
  331. private function statusValue($refundStatus,&$filter){
  332. switch ($refundStatus){
  333. case 1://待主管审核
  334. $filter[] = ['refund.status', '=',0]; //进行中
  335. $filter[] = ['refund.audit_status_zg', '=',0]; //等待专员审核
  336. break;
  337. case 2://待退款
  338. $filter[] = ['refund.finance_refund', '=', 0];
  339. $filter[] = ['refund.audit_status_zg', '=', 10];
  340. break;
  341. case 3://待专员修改
  342. $filter[] = ['refund.status', '=', 0];
  343. $filter[] = ['refund.audit_status_zg', '=', 20];
  344. break;
  345. case 4://关闭
  346. $filter[] = ['refund.status', '=', 40];
  347. break;
  348. case 5://已退款
  349. $filter[] = ['refund.status', '=', 20];
  350. $filter[] = ['refund.finance_refund', '=', 10];
  351. break;
  352. }
  353. return $filter;
  354. }
  355. /**
  356. * 获取当前用户的售后单详情
  357. * @param int $orderRefundId 售后单ID
  358. * @param bool $isWith 是否关联
  359. * @return static|null
  360. * @throws BaseException
  361. */
  362. public static function getDetail(int $id,$addWith=[])
  363. {
  364. // 关联查询
  365. $with = ['orderGoods' => ['image'],'his'];
  366. if($addWith){
  367. $with = array_merge($with,$addWith);
  368. }
  369. // 获取记录
  370. $detail = static::detail(['id' => $id], $with);
  371. if (empty($detail)) throwError('未找到该售后补偿单');
  372. return $detail;
  373. }
  374. /**
  375. * 主管审核
  376. * @param array $data
  377. * @return bool
  378. */
  379. public function auditzg(array $data): bool
  380. {
  381. if ($data['audit_status_zg'] ==20&& empty($data['refuse_desc_zg'])) {
  382. $this->error = '请输入拒绝原因';
  383. return false;
  384. }
  385. $this->transaction(function () use ($data) {
  386. $user = StoreUserService::getLoginInfo();
  387. $real_name = $user['user']['real_name']??'';
  388. $id = (int)$this['id'];
  389. if($data['audit_status_zg'] == 10) {
  390. (new RefundCompensateHisModel())->add($id,$real_name,'同意补偿','');
  391. }
  392. if($data['audit_status_zg'] == 20) {
  393. (new RefundCompensateHisModel())->add($id,$real_name,'拒绝',$data['refuse_desc_zg']);
  394. }
  395. $this->save($data);
  396. });
  397. return true;
  398. }
  399. //关闭售后单
  400. public function close(array $data=[]): bool
  401. {
  402. $user = StoreUserService::getLoginInfo();
  403. $real_name = $user['user']['real_name']??'';
  404. //售后单已关闭
  405. if($this['status']==20){
  406. $this->error = '售后补偿单已完成,不能关闭吧';
  407. return false;
  408. }
  409. //售后单已完成
  410. if($this['status']==40){
  411. $this->error = '售后补偿单已关闭,不要重复操作';
  412. return false;
  413. }
  414. $data['status'] = 40;
  415. $this->transaction(function () use ($data) {
  416. $this->save($data);
  417. // (new RefundCompensateHisModel())->add($id,$real_name,'关闭',$data['refuse_desc_zg']);
  418. });
  419. return true;
  420. }
  421. public function getError(){
  422. return $this->error;
  423. }
  424. /**
  425. * 财务退款
  426. * @return bool
  427. */
  428. public function refund(): bool
  429. {
  430. if ($this['refund_money'] <= 0) {
  431. $this->error = '退款金额不能小于0';
  432. return false;
  433. }
  434. // 事务处理
  435. $this->transaction(function () {
  436. $refund_money = floatval($this['refund_money']);
  437. $order_goods = OrderGoodsModel::where("order_goods_id",$this['order_goods_id'])->find();
  438. $wx_pay = floatval($order_goods['total_pay_price']);
  439. $rice_card_pay = floatval($order_goods['rice_card_money']);
  440. $ret_wx_pay = 0;
  441. $ret_rice_card_money = 0;
  442. if($rice_card_pay<=0&&$wx_pay>=$refund_money){
  443. $ret_wx_pay = $refund_money;
  444. $ret_rice_card_money = 0;
  445. }
  446. if($rice_card_pay>0){
  447. if($rice_card_pay>=$refund_money){
  448. $ret_rice_card_money = $refund_money;
  449. $ret_wx_pay = 0;
  450. }
  451. if($rice_card_pay<$refund_money){
  452. $ret_rice_card_money = $rice_card_pay;
  453. $ret_wx_pay = $refund_money- $ret_rice_card_money;
  454. }
  455. }
  456. //更新售后单状态
  457. // var_dump($ret_rice_card_money);
  458. // var_dump($ret_wx_pay);
  459. // die();
  460. $order = OrderModel::where("order_id",$this['order_id'])->find();
  461. $ret_wx_pay = round($ret_wx_pay,2);
  462. $this->save([
  463. 'status' => 20,
  464. 'finance_refund' => 10,
  465. 'finance_refund_time' => time(),
  466. 'out_refund_no' => time(),
  467. 'ret_wx_pay'=>$ret_wx_pay,
  468. 'ret_rice_card_money'=>$ret_rice_card_money
  469. ]);
  470. if ($ret_wx_pay > 0) {
  471. // 执行原路退款
  472. $refund_ret = (new RefundService)->execute($order, $this['refund_number'], $ret_wx_pay);
  473. if ($refund_ret['status'] == 200) {
  474. $this->save([
  475. 'transaction_id' => $refund_ret['data']['transaction_id'] // 微信退款交易号
  476. ]);
  477. }
  478. }
  479. if ($ret_rice_card_money>0) { // 订单商品有使用现金卡
  480. // 验证余额
  481. $riceCard = UserRiceCardModel::getValidRiceCardDetail($order_goods['rice_card_id']);
  482. if(empty($riceCard)){
  483. $this->error = '找不到米卡';
  484. return false;
  485. }
  486. if ($ret_rice_card_money + $riceCard['balance'] > $riceCard['face_value']) {
  487. $this->error = "现金卡退还金额异常";
  488. return false;
  489. }
  490. // 写入现金卡流水明细
  491. $order_amount = $order_goods['total_pay_price']+$order_goods['rice_card_money'];
  492. // 写入现金卡流水明细
  493. // var_dump($ret_rice_card_money);
  494. UserRiceCardConsume::addExtra($riceCard, $order['order_no'],$order_amount, $ret_rice_card_money,1, '售后退款');
  495. // 退还现金卡金额
  496. UserRiceCardModel::setIncByField($order_goods['rice_card_id'], 'balance', $ret_rice_card_money);
  497. $riceCard->effect_state = 1; // 改为 生效
  498. $riceCard->save();
  499. }
  500. });
  501. return true;
  502. }
  503. }