OrderRefund.php 84 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935
  1. <?php
  2. /**
  3. * Niushop商城系统 - 团队十年电商经验汇集巨献!
  4. * =========================================================
  5. * Copy right 2019-2029 杭州牛之云科技有限公司, 保留所有权利。
  6. * ----------------------------------------------
  7. * 官方网址: https://www.niushop.com
  8. * =========================================================
  9. */
  10. namespace app\model\order;
  11. use addon\cardservice\model\MemberCard;
  12. use addon\presale\model\PresaleOrder;
  13. use app\model\goods\GoodsStock;
  14. use app\model\member\Member;
  15. use app\model\member\MemberAccount;
  16. use app\model\shop\Shop;
  17. use app\model\shop\SiteAddress;
  18. use app\model\system\Pay;
  19. use app\model\BaseModel;
  20. use app\model\message\Message;
  21. use addon\coupon\model\Coupon;
  22. use app\model\order\Order as OrderModel;
  23. use app\model\system\Stat;
  24. use app\model\verify\Verify as VerifyModel;
  25. use addon\shopcomponent\model\Weapp;
  26. /**
  27. * 订单退款
  28. *
  29. * @author Administrator
  30. *
  31. */
  32. class OrderRefund extends BaseModel
  33. {
  34. /*********************************************************************************订单退款状态*****************************************************/
  35. //未申请退款
  36. const REFUND_NOT_APPLY = 0;
  37. //已申请退款
  38. const REFUND_APPLY = 1;
  39. // 已确认
  40. const REFUND_CONFIRM = 2;
  41. //已完成
  42. const REFUND_COMPLETE = 3;
  43. //等待买家发货
  44. const REFUND_WAIT_DELIVERY = 4;
  45. //等待卖家收货
  46. const REFUND_WAIT_TAKEDELIVERY = 5;
  47. //卖家确认收货
  48. const REFUND_TAKEDELIVERY = 6;
  49. // 卖家拒绝退款
  50. const REFUND_DIEAGREE = -1;
  51. // 卖家关闭退款
  52. const REFUND_CLOSE = -2;
  53. //退款方式
  54. const ONLY_REFUNDS = 1;//仅退款
  55. const A_REFUND_RETURN = 2;//退款退货
  56. const SHOP_ACTIVE_REFUND = 3;//店铺主动退款
  57. /**
  58. * 订单退款状态
  59. * @var unknown
  60. */
  61. public $order_refund_status = [
  62. 0 => [
  63. 'status' => 0,
  64. 'name' => '',
  65. 'action' => [
  66. ],
  67. 'member_action' => [
  68. [
  69. 'event' => 'orderRefundApply',
  70. 'title' => '申请维权',
  71. 'color' => ''
  72. ],
  73. ]
  74. ],
  75. self::REFUND_APPLY => [
  76. 'status' => self::REFUND_APPLY,
  77. 'name' => '申请维权',
  78. 'action' => [
  79. [
  80. 'event' => 'orderRefundAgree',
  81. 'title' => '同意',
  82. 'color' => ''
  83. ],
  84. [
  85. 'event' => 'orderRefundRefuse',
  86. 'title' => '拒绝',
  87. 'color' => ''
  88. ],
  89. [
  90. 'event' => 'orderRefundClose',
  91. 'title' => '关闭维权',
  92. 'color' => ''
  93. ]
  94. ],
  95. 'member_action' => [
  96. [
  97. 'event' => 'orderRefundCancel',
  98. 'title' => '撤销维权',
  99. 'color' => ''
  100. ],
  101. ]
  102. ],
  103. self::REFUND_CONFIRM => [
  104. 'status' => self::REFUND_CONFIRM,
  105. 'name' => '待转账',
  106. 'action' => [
  107. [
  108. 'event' => 'orderRefundTransfer',
  109. 'title' => '转账',
  110. 'color' => ''
  111. ],
  112. [
  113. 'event' => 'orderRefundClose',
  114. 'title' => '关闭维权',
  115. 'color' => ''
  116. ]
  117. ],
  118. 'member_action' => [
  119. ]
  120. ],
  121. self::REFUND_COMPLETE => [
  122. 'status' => self::REFUND_COMPLETE,
  123. 'name' => '维权结束',
  124. 'action' => [
  125. ],
  126. 'member_action' => [
  127. ]
  128. ],
  129. self::REFUND_WAIT_DELIVERY => [
  130. 'status' => self::REFUND_WAIT_DELIVERY,
  131. 'name' => '买家待退货',
  132. 'action' => [
  133. [
  134. 'event' => 'orderRefundClose',
  135. 'title' => '关闭维权',
  136. 'color' => ''
  137. ]
  138. ],
  139. 'member_action' => [
  140. [
  141. 'event' => 'orderRefundDelivery',
  142. 'title' => '填写发货物流',
  143. 'color' => ''
  144. ],
  145. ]
  146. ],
  147. self::REFUND_WAIT_TAKEDELIVERY => [
  148. 'status' => self::REFUND_WAIT_TAKEDELIVERY,
  149. 'name' => '卖家待收货',
  150. 'action' => [
  151. [
  152. 'event' => 'orderRefundTakeDelivery',
  153. 'title' => '收货',
  154. 'color' => ''
  155. ],
  156. [
  157. 'event' => 'orderRefundRefuse',
  158. 'title' => '拒绝',
  159. 'color' => ''
  160. ],
  161. [
  162. 'event' => 'orderRefundClose',
  163. 'title' => '关闭维权',
  164. 'color' => ''
  165. ]
  166. ],
  167. 'member_action' => [
  168. ]
  169. ],
  170. self::REFUND_TAKEDELIVERY => [
  171. 'status' => self::REFUND_TAKEDELIVERY,
  172. 'name' => '卖家已收货',
  173. 'action' => [
  174. [
  175. 'event' => 'orderRefundTransfer',
  176. 'title' => '转账',
  177. 'color' => ''
  178. ],
  179. [
  180. 'event' => 'orderRefundClose',
  181. 'title' => '关闭维权',
  182. 'color' => ''
  183. ]
  184. ],
  185. 'member_action' => [
  186. ]
  187. ],
  188. self::REFUND_DIEAGREE => [
  189. 'status' => self::REFUND_DIEAGREE,
  190. 'name' => '卖家拒绝',
  191. 'action' => [
  192. [
  193. 'event' => 'orderRefundClose',
  194. 'title' => '关闭维权',
  195. 'color' => ''
  196. ]
  197. ],
  198. 'member_action' => [
  199. [
  200. 'event' => 'orderRefundCancel',
  201. 'title' => '撤销维权',
  202. 'color' => ''
  203. ],
  204. [
  205. 'event' => 'orderRefundAsk',
  206. 'title' => '修改申请',
  207. 'color' => ''
  208. ],
  209. ]
  210. ]
  211. ];
  212. /**
  213. * 退款方式
  214. * @var unknown
  215. */
  216. public $refund_type = [
  217. self::ONLY_REFUNDS => '仅退款',
  218. self::A_REFUND_RETURN => '退货退款',
  219. ];
  220. /**
  221. * 退款方式
  222. * @var unknown
  223. */
  224. public $refund_reason_type = [
  225. '未按约定时间发货',
  226. '拍错/多拍/不喜欢',
  227. '协商一致退款',
  228. '其他',
  229. ];
  230. /****************************************************************************订单退款相关操作(开始)**********************************/
  231. /**
  232. * 获取退款金额
  233. * @param string $order_goods_ids
  234. */
  235. public function getOrderRefundMoney($order_goods_ids)
  236. {
  237. //订单商品项
  238. $order_goods_ids = (string) $order_goods_ids;
  239. $order_goods_lists = model('order_goods')->getList([ [
  240. 'order_goods_id', 'in', is_array($order_goods_ids) ? $order_goods_ids : (string) $order_goods_ids
  241. ] ]);
  242. if (empty($order_goods_lists)) return $this->error(null, '未查询到订单商品');
  243. $order_id = $order_goods_lists[ 0 ][ 'order_id' ];
  244. //退款状态检测 只有未申请的可以发起退款
  245. foreach ($order_goods_lists as $val) {
  246. if (!in_array($val[ 'refund_status' ], [ 0, self::REFUND_NOT_APPLY, self::REFUND_DIEAGREE ])) {
  247. return $this->error(null, '订单商品退款状态有误');
  248. }
  249. }
  250. //剩余未申请退款的订单商品统计
  251. $not_apply_count = model('order_goods')->getCount([
  252. [ 'order_id', '=', $order_id ],
  253. [ 'order_goods_id', 'not in', $order_goods_ids ],
  254. [ 'refund_status', 'in', [ 0, self::REFUND_NOT_APPLY, self::REFUND_DIEAGREE ] ],
  255. ], 'order_goods_id');
  256. //有退过运费的订单商品统计
  257. $refund_delivery_count = model('order_goods')->getCount([
  258. [ 'order_id', '=', $order_id ],
  259. [ 'order_goods_id', 'not in', $order_goods_ids ],
  260. [ 'refund_delivery_money', '>', 0 ],
  261. ], 'order_goods_id');
  262. //如果还有未申请退款的商品就不退运费 发票 和发票运费
  263. if ($not_apply_count > 0) {
  264. $delivery_money = 0;
  265. $invoice_delivery_money = 0;
  266. $invoice_money = 0;
  267. } else {
  268. $order_info = model('order')->getInfo([
  269. [ 'order_id', '=', $order_id ],
  270. ], 'delivery_money, invoice_delivery_money, invoice_money');
  271. if ($refund_delivery_count == 0) {
  272. $delivery_money = $order_info[ 'delivery_money' ];
  273. } else {
  274. $delivery_money = 0;
  275. }
  276. $invoice_delivery_money = $order_info[ 'invoice_delivery_money' ];
  277. $invoice_money = $order_info[ 'invoice_money' ];
  278. }
  279. //计算实际退款金额
  280. $refund_money = 0;
  281. foreach ($order_goods_lists as $item) {
  282. $refund_money += $item[ 'real_goods_money' ];
  283. }
  284. $refund_money += $delivery_money + $invoice_delivery_money + $invoice_money;
  285. $data = array (
  286. 'refund_money' => round($refund_money, 2),
  287. 'refund_delivery_money' => round($delivery_money, 2)
  288. );
  289. return $data;
  290. }
  291. /**
  292. * 订单退回余额
  293. * @param int $order_goods_id
  294. */
  295. public function getOrderRefundBalance($order_goods_id)
  296. {
  297. //订单商品项
  298. $order_goods_info = model('order_goods')->getInfo([
  299. 'order_goods_id' => $order_goods_id
  300. ], 'order_id, goods_money');
  301. //订单整体项
  302. $order_info = model('order')->getInfo([
  303. 'order_id' => $order_goods_info[ 'order_id' ]
  304. ], 'goods_money, balance_money');
  305. if ($order_info[ 'balance_money' ] != 0) {
  306. if ($order_info[ 'goods_money' ] != 0) {
  307. return $this->success($order_info[ 'balance_money' ] * $order_goods_info[ 'goods_money' ] / $order_info[ 'goods_money' ]);
  308. } else {
  309. return $this->success(0);
  310. }
  311. }
  312. return $this->success(0);
  313. }
  314. /**
  315. * 添加退款操作日志
  316. * @param int $order_goods_id
  317. * @param int $refund_status
  318. * @param string $action
  319. * @param int $action_way
  320. * @param int $action_userid
  321. * @param string $action_username
  322. */
  323. public function addOrderRefundLog($order_goods_id, $refund_status, $action, $action_way, $action_userid, $action_username, $desc = '')
  324. {
  325. $data = [
  326. 'order_goods_id' => $order_goods_id,
  327. 'refund_status' => $refund_status,
  328. 'action' => $action,
  329. 'action_way' => $action_way,
  330. 'action_userid' => $action_userid,
  331. 'username' => $action_username,
  332. 'action_time' => time(),
  333. 'desc' => $desc
  334. ];
  335. $res = model('order_refund_log')->add($data);
  336. // 维权状态变更
  337. event('RefundStatusChange', $data);
  338. return $res;
  339. }
  340. /**
  341. * 会员申请退款
  342. * @param array $data
  343. * @param array $member_info
  344. * @return multitype:string mixed
  345. */
  346. public function orderRefundApply($data, $member_info, $log_data = [])
  347. {
  348. $order_goods_info = model('order_goods')->getInfo([ 'order_goods_id' => $data[ 'order_goods_id' ] ], 'order_id,refund_status,delivery_status,is_virtual,site_id,order_no,order_goods_id');
  349. if (empty($order_goods_info))
  350. return $this->error();
  351. if ($order_goods_info[ 'refund_status' ] != 0 && $order_goods_info[ 'refund_status' ] != -1)
  352. return $this->error();
  353. $refund_type_list = $this->getRefundType($order_goods_info);
  354. //防止退款方式越权
  355. if (!in_array($data[ 'refund_type' ], $refund_type_list))
  356. return $this->error();
  357. $order_info = model('order')->getInfo([ 'order_id' => $order_goods_info[ 'order_id' ] ]);
  358. //判断是否允许申请退款
  359. if ($order_info[ 'is_enable_refund' ] == 0) {
  360. if ($order_info[ 'promotion_type' ] == 'pinfan') {
  361. return $this->error('', '拼团活动正在进行中,待拼成功后可发起退款');
  362. }
  363. return $this->error();
  364. }
  365. model('order_goods')->startTrans();
  366. try {
  367. $data[ 'refund_status' ] = self::REFUND_APPLY;
  368. $data[ 'refund_status_name' ] = $this->order_refund_status[ self::REFUND_APPLY ][ 'name' ];
  369. $data[ 'refund_status_action' ] = json_encode($this->order_refund_status[ self::REFUND_APPLY ], JSON_UNESCAPED_UNICODE);
  370. $data[ 'refund_mode' ] = $order_info[ 'order_status' ] == Order::ORDER_COMPLETE ? 2 : 1;
  371. $pay_model = new Pay();
  372. $data[ 'refund_no' ] = $pay_model->createRefundNo();
  373. $data[ 'refund_action_time' ] = time();
  374. $refund_apply_money_array = $this->getOrderRefundMoney($data[ 'order_goods_id' ]);//可退款金额 通过计算获得
  375. $refund_apply_money = $refund_apply_money_array[ 'refund_money' ];
  376. $refund_delivery_money = $refund_apply_money_array[ 'refund_delivery_money' ];
  377. $data[ 'refund_apply_money' ] = $refund_apply_money;//申请的总退款
  378. $data[ 'refund_delivery_money' ] = $refund_delivery_money;//退的运费
  379. //生成视频号订单ID
  380. $data[ 'out_aftersale_id' ] = $order_goods_info[ 'order_no' ] . time() . $order_goods_info[ 'order_goods_id' ];
  381. $res = model('order_goods')->update($data, [ 'order_goods_id' => $data[ 'order_goods_id' ] ]);
  382. //验证订单锁定状态
  383. $local_result = $this->verifyOrderLock($order_goods_info[ 'order_id' ]);
  384. $this->addOrderRefundLog($data[ 'order_goods_id' ], self::REFUND_APPLY, '买家申请退款', 1, $member_info[ 'member_id' ], $member_info[ 'nickname' ]);
  385. event('orderRefundApply', $data);//传入订单类型以及订单项id
  386. model('order_goods')->commit();
  387. //订单会员申请退款消息
  388. $message_model = new Message();
  389. $message_model->sendMessage([ 'keywords' => 'BUYER_REFUND', 'order_goods_id' => $data[ 'order_goods_id' ], 'site_id' => $order_goods_info[ 'site_id' ] ]);
  390. // 发起维权 关闭订单评价
  391. model('order')->update([ 'is_evaluate' => 0 ], [ 'order_id' => $order_goods_info[ 'order_id' ] ]);
  392. //记录订单日志 start
  393. if ($log_data) {
  394. $order_common_model = new OrderCommon();
  395. $log_data = array_merge($log_data, [
  396. 'order_id' => $order_goods_info[ 'order_id' ],
  397. 'order_status' => $order_info[ 'order_status' ],
  398. 'order_status_name' => $order_info[ 'order_status_name' ]
  399. ]);
  400. $order_common_model->addOrderLog($log_data);
  401. }
  402. //记录订单日志 end
  403. return $this->success($res);
  404. } catch (\Exception $e) {
  405. model('order_goods')->rollback();
  406. return $this->error('', $e->getMessage());
  407. }
  408. }
  409. /**
  410. * 用户撤销退款申请
  411. * @param array $data
  412. * @param array $member_info
  413. * @return string[]|mixed[]
  414. */
  415. public function memberCancelRefund($data, $member_info, $log_data = [])
  416. {
  417. $order_goods_info = model('order_goods')->getInfo([ 'order_goods_id' => $data[ 'order_goods_id' ] ]);
  418. if (empty($order_goods_info)) {
  419. return $this->error();
  420. }
  421. model('order_goods')->startTrans();
  422. try {
  423. //
  424. $data[ 'refund_status' ] = 0;
  425. $data[ 'refund_status_name' ] = $this->order_refund_status[ 0 ][ 'name' ];
  426. $data[ 'refund_status_action' ] = json_encode($this->order_refund_status[ 0 ], JSON_UNESCAPED_UNICODE);
  427. $data[ 'refund_type' ] = 0;
  428. //重置部分字段
  429. $data[ 'refund_address' ] = '';
  430. $data[ 'refund_delivery_remark' ] = '';
  431. $data[ 'refund_remark' ] = '';
  432. $data[ 'refund_delivery_name' ] = '';
  433. $data[ 'refund_delivery_no' ] = '';
  434. $data[ 'refund_reason' ] = '';
  435. $res = model('order_goods')->update($data, [ 'order_goods_id' => $data[ 'order_goods_id' ] ]);
  436. //验证订单锁定状态
  437. $lock_result = $this->verifyOrderLock($order_goods_info[ 'order_id' ]);
  438. // 维权拒绝 评价锁定放开
  439. $order_info = model('order')->getInfo([ 'order_id' => $order_goods_info[ 'order_id' ] ]);
  440. if ($order_info[ 'evaluate_status' ] != 2) {
  441. model('order')->update([ 'is_evaluate' => 1 ], [ [ 'order_id', '=', $order_goods_info[ 'order_id' ] ], [ 'order_status', 'in', [ OrderModel::ORDER_TAKE_DELIVERY, OrderModel::ORDER_COMPLETE ] ] ]);
  442. }
  443. //记录订单日志 start
  444. if ($log_data) {
  445. $order_common_model = new OrderCommon();
  446. $order_info = model('order')->getInfo([ 'order_id' => $order_goods_info[ 'order_id' ] ], 'order_status,order_status_name,member_id,site_id,is_video_number');
  447. $log_data = array_merge($log_data, [
  448. 'order_id' => $order_goods_info[ 'order_id' ],
  449. 'order_status' => $order_info[ 'order_status' ],
  450. 'order_status_name' => $order_info[ 'order_status_name' ]
  451. ]);
  452. $order_common_model->addOrderLog($log_data);
  453. if ($order_info[ 'is_video_number' ] == 1) {
  454. $weapp_model = new Weapp($order_info[ 'site_id' ]);
  455. $member = model('member')->getInfo([ [ 'member_id', '=', $order_info[ 'member_id' ] ] ]);
  456. $res = $weapp_model->cancel([
  457. 'out_aftersale_id' => $order_goods_info[ 'out_aftersale_id' ],
  458. 'openid' => $member[ 'weapp_openid' ]
  459. ]);
  460. if ($res[ 'code' ] < 0) {
  461. model('order_goods')->rollback();
  462. return $this->error('', $res[ 'message' ]);
  463. }
  464. }
  465. }
  466. //记录订单日志 end
  467. $this->addOrderRefundLog($data[ 'order_goods_id' ], 0, '买家撤销退款申请', 1, $member_info[ 'member_id' ], $member_info[ 'nickname' ]);
  468. event('memberCancelRefund', $data);//传入订单类型以及订单项id
  469. model('order_goods')->commit();
  470. return $this->success();
  471. } catch (\Exception $e) {
  472. model('order_goods')->rollback();
  473. return $this->error('', $e->getMessage());
  474. }
  475. }
  476. /**
  477. * 卖家确认退款
  478. * @param array $data
  479. * @param array $user_info
  480. */
  481. public function orderRefundConfirm($data, $user_info)
  482. {
  483. $order_goods_info = model('order_goods')->getInfo([ 'order_goods_id' => $data[ 'order_goods_id' ] ]);
  484. if (empty($order_goods_info)) {
  485. return $this->error();
  486. }
  487. if ($order_goods_info[ 'refund_status' ] != self::REFUND_APPLY) {
  488. return $this->error();
  489. }
  490. model('order_goods')->startTrans();
  491. try {
  492. if ($order_goods_info[ 'refund_type' ] == 1) {
  493. $data[ 'refund_status' ] = self::REFUND_CONFIRM; //确认等待转账
  494. } else {
  495. $data[ 'refund_status' ] = self::REFUND_WAIT_DELIVERY; //确认等待买家发货
  496. }
  497. $data[ 'refund_status_name' ] = $this->order_refund_status[ $data[ 'refund_status' ] ][ 'name' ];
  498. $data[ 'refund_status_action' ] = json_encode($this->order_refund_status[ $data[ 'refund_status' ] ], JSON_UNESCAPED_UNICODE);
  499. $res = model('order_goods')->update($data, [ 'order_goods_id' => $data[ 'order_goods_id' ] ]);
  500. //记录订单日志 start
  501. $order_common_model = new OrderCommon();
  502. $order_info = model('order')->getInfo([ 'order_id' => $order_goods_info[ 'order_id' ] ], 'order_status,order_status_name,is_video_number,site_id');
  503. $log_data = [
  504. 'uid' => $user_info[ 'uid' ],
  505. 'nick_name' => $user_info[ 'username' ],
  506. 'action' => '商家同意了退款申请,等待转账',
  507. 'action_way' => 2,
  508. 'order_id' => $order_goods_info[ 'order_id' ],
  509. 'order_status' => $order_info[ 'order_status' ],
  510. 'order_status_name' => $order_info[ 'order_status_name' ]
  511. ];
  512. $order_common_model->addOrderLog($log_data);
  513. //记录订单日志 end
  514. if ($order_goods_info[ 'refund_type' ] != 1) {
  515. if ($order_info[ 'is_video_number' ] == 1) {
  516. // $shop_info = model('shop')->getInfo([['site_id', '=',$order_info['site_id'] ]]);
  517. $refund_address = $this->getRefundAddress($order_goods_info[ 'site_id' ]);
  518. $weapp_model = new Weapp($order_info[ 'site_id' ]);
  519. $res = $weapp_model->aceptreturn([
  520. 'out_aftersale_id' => $order_goods_info[ 'out_aftersale_id' ],
  521. 'address_info' => [
  522. 'receiver_name' => $refund_address[ 'shop_contacts' ],
  523. 'detailed_address' => $refund_address[ 'shop_address' ],
  524. 'tel_number' => $refund_address[ 'shop_mobile' ],
  525. 'country' => '',
  526. 'province' => $refund_address[ 'province_name' ] ?? '无',
  527. 'city' => $refund_address[ 'city_name' ] ?? '无',
  528. 'town' => $refund_address[ 'district_name' ] ?? '无',
  529. ]
  530. ]);
  531. if ($res[ 'code' ] < 0) {
  532. model('order_goods')->rollback();
  533. return $this->error('', $res[ 'message' ]);
  534. }
  535. }
  536. }
  537. $this->addOrderRefundLog($data[ 'order_goods_id' ], $data[ 'refund_status' ], '卖家确认退款', 2, $user_info[ 'uid' ], $user_info[ 'username' ]);
  538. model('order_goods')->commit();
  539. //订单退款同意消息
  540. $message_model = new Message();
  541. $message_model->sendMessage([ 'keywords' => 'ORDER_REFUND_AGREE', 'order_id' => $order_goods_info[ 'order_id' ], 'order_goods_id' => $data[ 'order_goods_id' ], 'site_id' => $order_goods_info[ 'site_id' ] ]);
  542. return $this->success($res);
  543. } catch (\Exception $e) {
  544. model('order_goods')->rollback();
  545. return $this->error('', $e->getMessage());
  546. }
  547. }
  548. /**
  549. * 卖家拒绝退款
  550. * @param array $data
  551. * @param array $user_info
  552. */
  553. public function orderRefundRefuse($data, $user_info, $refund_refuse_reason, $log_data = [])
  554. {
  555. $order_goods_info = model('order_goods')->getInfo([ 'order_goods_id' => $data[ 'order_goods_id' ] ]);
  556. if (empty($order_goods_info)) {
  557. return $this->error();
  558. }
  559. if ($order_goods_info[ 'refund_status' ] != self::REFUND_APPLY && $order_goods_info[ 'refund_status' ] != self::REFUND_WAIT_TAKEDELIVERY) {
  560. return $this->error();
  561. }
  562. model('order_goods')->startTrans();
  563. try {
  564. $data[ 'refund_status' ] = self::REFUND_DIEAGREE;
  565. $data[ 'refund_status_name' ] = $this->order_refund_status[ self::REFUND_DIEAGREE ][ 'name' ];
  566. $data[ 'refund_status_action' ] = json_encode($this->order_refund_status[ self::REFUND_DIEAGREE ], JSON_UNESCAPED_UNICODE);
  567. $data[ 'refund_refuse_reason' ] = $refund_refuse_reason;
  568. $data[ 'refund_action_time' ] = time();
  569. $res = model('order_goods')->update($data, [ 'order_goods_id' => $data[ 'order_goods_id' ] ]);
  570. //验证订单锁定状态
  571. $lock_result = $this->verifyOrderLock($order_goods_info[ 'order_id' ]);
  572. $log_desc = empty($refund_refuse_reason) ? '' : '拒绝原因:' . $refund_refuse_reason;
  573. $this->addOrderRefundLog($data[ 'order_goods_id' ], $data[ 'refund_status' ], '卖家拒绝退款', 2, $user_info[ 'uid' ], $user_info[ 'username' ], $log_desc);
  574. event('OrderRefundRefuse', $data);
  575. //记录订单日志 start
  576. $order_info = model('order')->getInfo([ 'order_id' => $order_goods_info[ 'order_id' ] ], 'order_status,order_status_name,is_video_number,site_id');
  577. if ($log_data) {
  578. $order_common_model = new OrderCommon();
  579. $log_data = array_merge($log_data, [
  580. 'order_id' => $order_goods_info[ 'order_id' ],
  581. 'order_status' => $order_info[ 'order_status' ],
  582. 'order_status_name' => $order_info[ 'order_status_name' ]
  583. ]);
  584. $order_common_model->addOrderLog($log_data);
  585. }
  586. if ($order_info[ 'is_video_number' ] == 1) {
  587. $weapp_model = new Weapp($order_info[ 'site_id' ]);
  588. $res = $weapp_model->orderNoRefund([ 'out_aftersale_id' => $order_goods_info[ 'out_aftersale_id' ] ]);
  589. if ($res[ 'code' ] < 0) {
  590. model('order_goods')->rollback();
  591. return $this->error('', $res[ 'message' ]);
  592. }
  593. }
  594. //记录订单日志 end
  595. // 维权拒绝 评价锁定放开
  596. model('order')->update([ 'is_evaluate' => 1 ], [ [ 'order_id', '=', $order_goods_info[ 'order_id' ] ], [ 'order_status', 'in', [ OrderModel::ORDER_TAKE_DELIVERY, OrderModel::ORDER_COMPLETE ] ] ]);
  597. //订单退款拒绝消息
  598. $message_model = new Message();
  599. $message_model->sendMessage([ 'keywords' => 'ORDER_REFUND_REFUSE', 'order_id' => $order_goods_info[ 'order_id' ], 'order_goods_id' => $data[ 'order_goods_id' ], 'site_id' => $order_goods_info[ 'site_id' ] ]);
  600. model('order_goods')->commit();
  601. return $this->success();
  602. } catch (\Exception $e) {
  603. model('order_goods')->rollback();
  604. return $this->error('', $e->getMessage());
  605. }
  606. }
  607. /**
  608. * 买家退货
  609. * @param array $data 退货信息
  610. * @param array $member_info 会员信息
  611. */
  612. public function orderRefundDelivery($data, $member_info)
  613. {
  614. $order_goods_info = model('order_goods')->getInfo([ 'order_goods_id' => $data[ 'order_goods_id' ] ]);
  615. if (empty($order_goods_info)) {
  616. return $this->error();
  617. }
  618. if ($order_goods_info[ 'refund_status' ] != self::REFUND_WAIT_DELIVERY) {
  619. return $this->error();
  620. }
  621. model('order_goods')->startTrans();
  622. try {
  623. $data[ 'refund_status' ] = self::REFUND_WAIT_TAKEDELIVERY;
  624. $data[ 'refund_status_name' ] = $this->order_refund_status[ self::REFUND_WAIT_TAKEDELIVERY ][ 'name' ];
  625. $data[ 'refund_status_action' ] = json_encode($this->order_refund_status[ self::REFUND_WAIT_TAKEDELIVERY ], JSON_UNESCAPED_UNICODE);
  626. // $shop_model = new Shop();
  627. // $shop_info_result = $shop_model->getShopInfo([ [ 'site_id', '=', $order_goods_info[ 'site_id' ] ] ], 'full_address');
  628. // $shop_info = $shop_info_result[ 'data' ];
  629. $refund_address = $this->getRefundAddress($order_goods_info[ 'site_id' ]);
  630. $data[ 'refund_address' ] = $refund_address[ 'shop_address' ];
  631. $res = model('order_goods')->update($data, [ 'order_goods_id' => $data[ 'order_goods_id' ] ]);
  632. $this->addOrderRefundLog($data[ 'order_goods_id' ], $data[ 'refund_status' ], $data[ 'refund_delivery_name' ] . ':' . $data[ 'refund_delivery_no' ], 1, $member_info[ 'member_id' ], $member_info[ 'nickname' ]);
  633. $order_info = model('order')->getInfo([ 'order_id' => $order_goods_info[ 'order_id' ] ], 'order_status,order_status_name,is_video_number,site_id,member_id');
  634. if ($order_info[ 'is_video_number' ] == 1) {
  635. $member_info = model('member')->getInfo([ [ 'member_id', '=', $order_info[ 'member_id' ] ] ]);
  636. $weapp_model = new Weapp($order_info[ 'site_id' ]);
  637. $res = $weapp_model->uploadreturninfo([
  638. 'out_aftersale_id' => $order_goods_info[ 'out_aftersale_id' ],
  639. 'openid' => $member_info[ 'weapp_openid' ],
  640. 'delivery_id' => '',
  641. 'waybill_id' => $order_goods_info[ 'refund_delivery_no' ],
  642. 'delivery_name' => $order_goods_info[ 'refund_delivery_name' ]
  643. ]);
  644. if ($res[ 'code' ] < 0) {
  645. model('order_goods')->rollback();
  646. return $this->error('', $res[ 'message' ]);
  647. }
  648. }
  649. model('order_goods')->commit();
  650. //买家已退货提醒
  651. $message_model = new Message();
  652. $message_model->sendMessage([ 'keywords' => 'BUYER_DELIVERY_REFUND', 'order_goods_info' => $order_goods_info, 'site_id' => $order_goods_info[ 'site_id' ] ]);
  653. return $this->success();
  654. } catch (\Exception $e) {
  655. model('order_goods')->rollback();
  656. return $this->error('', $e->getMessage());
  657. }
  658. }
  659. /**
  660. * 卖家确认收到退货
  661. * @param array $data 退货信息
  662. * @param array $member_info 会员信息
  663. */
  664. public function orderRefundTakeDelivery($data, $user_info)
  665. {
  666. $order_goods_info = model('order_goods')->getInfo([ 'order_goods_id' => $data[ 'order_goods_id' ] ]);
  667. if (empty($order_goods_info)) {
  668. return $this->error();
  669. }
  670. if ($order_goods_info[ 'refund_status' ] != self::REFUND_WAIT_TAKEDELIVERY) {
  671. return $this->error();
  672. }
  673. model('order_goods')->startTrans();
  674. try {
  675. $data[ 'refund_status' ] = self::REFUND_TAKEDELIVERY;
  676. $data[ 'refund_status_name' ] = $this->order_refund_status[ self::REFUND_TAKEDELIVERY ][ 'name' ];
  677. $data[ 'refund_status_action' ] = json_encode($this->order_refund_status[ self::REFUND_TAKEDELIVERY ], JSON_UNESCAPED_UNICODE);
  678. $res = model('order_goods')->update($data, [ 'order_goods_id' => $data[ 'order_goods_id' ] ]);
  679. $this->addOrderRefundLog($data[ 'order_goods_id' ], $data[ 'refund_status' ], '卖家确认收到退货', 2, $user_info[ 'uid' ], $user_info[ 'username' ]);
  680. model('order_goods')->commit();
  681. return $this->success();
  682. } catch (\Exception $e) {
  683. model('order_goods')->rollback();
  684. return $this->error('', $e->getMessage());
  685. }
  686. }
  687. /**
  688. * 退货完成
  689. * @param array $data
  690. * @param array $user_info
  691. * @return multitype:string mixed
  692. */
  693. public function orderRefundFinish($data, $user_info, $log_data = [])
  694. {
  695. $order_goods_info = model('order_goods')->getInfo([ 'order_goods_id' => $data[ 'order_goods_id' ] ]);
  696. if (empty($order_goods_info))
  697. return $this->error([], '不存在的退款项');
  698. $order_id = $order_goods_info[ 'order_id' ];
  699. $order_info = model('order')->getInfo([ [ 'order_id', '=', $order_id ] ]);
  700. if (empty($order_info))
  701. return $this->error([], '不存在的退款项');
  702. $refund_apply_money = $order_goods_info[ 'refund_apply_money' ];
  703. $shop_active_refund = $data[ 'shop_active_refund' ] ?? 0;
  704. $update_data = array (
  705. 'refund_time' => time(),
  706. 'shop_active_refund' => $shop_active_refund,
  707. );
  708. if ($shop_active_refund == 1) {//商家主动退款
  709. //查询发货状态(已发货的不能主动退款)
  710. if ($order_info[ 'order_scene' ] == 'online') {//todo 只有非收银订单受限
  711. if ($order_goods_info[ 'delivery_status' ] != OrderModel::DELIVERY_WAIT) {
  712. return $this->error([], '已发货的订单不能发起主动退款');
  713. }
  714. }
  715. //获取可退金额
  716. $do_refund_money = $data[ 'do_refund_money' ] ?? 0;
  717. $refund_apply_money_arr = $this->getOrderRefundMoney($data[ 'order_goods_id' ]);
  718. // $refund_apply_money = $refund_apply_money_arr['refund_money'];
  719. $refund_apply_money = $do_refund_money;
  720. $refund_delivery_money = $refund_apply_money_arr[ 'refund_delivery_money' ];
  721. $data[ 'refund_real_money' ] = $refund_apply_money;
  722. $data[ 'refund_delivery_money' ] = $refund_delivery_money;
  723. $update_data[ 'refund_no' ] = ( new Pay() )->createRefundNo();
  724. $update_data[ 'refund_action_time' ] = time();
  725. } else {
  726. if ($order_goods_info[ 'refund_status' ] != self::REFUND_TAKEDELIVERY && $order_goods_info[ 'refund_status' ] != self::REFUND_CONFIRM) {
  727. return $this->error();
  728. }
  729. }
  730. if ($data[ 'refund_real_money' ] > $refund_apply_money) return $this->error('', '退款金额超出最大可退金额');
  731. model('order_goods')->startTrans();
  732. try {
  733. $update_data[ 'refund_apply_money' ] = $refund_apply_money;
  734. $update_data[ 'refund_money_type' ] = $data[ 'refund_money_type' ];
  735. $update_data[ 'refund_real_money' ] = $data[ 'refund_real_money' ];
  736. $update_data[ 'shop_refund_remark' ] = $data[ 'shop_refund_remark' ];
  737. $update_data[ 'refund_delivery_money' ] = $data[ 'refund_delivery_money' ] ?? 0.00;
  738. $update_data[ 'refund_status' ] = self::REFUND_COMPLETE;
  739. $update_data[ 'refund_status_name' ] = $this->order_refund_status[ self::REFUND_COMPLETE ][ 'name' ];
  740. $update_data[ 'refund_status_action' ] = json_encode($this->order_refund_status[ self::REFUND_COMPLETE ], JSON_UNESCAPED_UNICODE);
  741. if (!empty($data[ 'out_aftersale_id' ])) {
  742. $update_data[ 'out_aftersale_id' ] = $data[ 'out_aftersale_id' ];
  743. }
  744. $res = model('order_goods')->update($update_data, [ [ 'order_goods_id', '=', $data[ 'order_goods_id' ] ] ]);
  745. $result = $this->finishAction($data[ 'order_goods_id' ], $log_data, $data[ 'is_deposit_back' ] ?? 0);
  746. if ($result[ 'code' ] < 0) {
  747. model('order_goods')->rollback();
  748. return $result;
  749. }
  750. //退货日志
  751. $this->addOrderRefundLog($data[ 'order_goods_id' ], self::REFUND_COMPLETE, '维权完成', 2, $user_info[ 'uid' ], $user_info[ 'username' ], '维权完成,退款金额:¥' . $data[ 'refund_real_money' ] ?? 0);
  752. $order_goods_info = model('order_goods')->getInfo([ [ 'order_goods_id', '=', $data[ 'order_goods_id' ] ] ]);
  753. $this->orderGoodsRefund($order_goods_info);
  754. //库存返还 lic
  755. $this->refundGoodsStock($order_goods_info,$user_info);
  756. //同时修改用户的order_money
  757. model('member')->setDec([ [ 'member_id', '=', $order_goods_info[ 'member_id' ] ] ], 'order_money', $order_goods_info[ 'refund_real_money' ]);
  758. // event('OrderRefundFinish', $order_goods_info);//传入订单类型以及订单项id
  759. model('order_goods')->commit();
  760. return $this->success();
  761. } catch (\Exception $e) {
  762. model('order_goods')->rollback();
  763. return $this->error('', $e->getMessage() . $e->getFile() . $e->getLine());
  764. }
  765. }
  766. /**
  767. * 库存返还
  768. * */
  769. public function refundGoodsStock($order_goods_info,$user_info){
  770. $gswhere=[];
  771. $gswhere[]=['goods_id','=',$order_goods_info['goods_id']];
  772. $gswhere[]=['sku_id','=',$order_goods_info['sku_id']];
  773. $goods_sku_info = model('goods_sku')->getInfo($gswhere);
  774. $update_sku_data['stock'] = $goods_sku_info['stock'] + $order_goods_info['num'];
  775. $update_sku_data['real_stock'] = $goods_sku_info['real_stock'] + $order_goods_info['num'];
  776. $res = model('goods_sku')->update($update_sku_data,$gswhere);
  777. $sgswhere = [];
  778. $sgswhere[]=['goods_id','=',$order_goods_info['goods_id']];
  779. $sgswhere[]=['sku_id','=',$order_goods_info['sku_id']];
  780. $sgswhere[]=['store_id','=',$order_goods_info['store_id']];
  781. $store_goods_sku_info = model('store_goods_sku')->getInfo($sgswhere);
  782. $update_store_sku_data['stock'] = $store_goods_sku_info['stock'] + $order_goods_info['num'];
  783. $update_store_sku_data['real_stock'] = $store_goods_sku_info['real_stock'] + $order_goods_info['num'];
  784. $res = model('store_goods_sku')->update($update_store_sku_data,$sgswhere);
  785. $sgwhere = [];
  786. $sgwhere[]=['goods_id','=',$order_goods_info['goods_id']];
  787. $sgwhere[]=['store_id','=',$order_goods_info['store_id']];
  788. $store_goods_info = model('store_goods')->getInfo($sgwhere);
  789. $update_store_goods_data['stock'] = $store_goods_info['stock'] + $order_goods_info['num'];
  790. $update_store_goods_data['real_stock'] = $store_goods_info['real_stock'] + $order_goods_info['num'];
  791. $res = model('store_goods')->update($update_store_goods_data,$sgwhere);
  792. $store_info = model('store')->getInfo(['store_id'=>$order_goods_info['store_id']]);
  793. // $goods_sku_info = model('goods_sku')->getInfo(['goods_id'=>$order_goods_info['goods_id'],'sku_id'=>$order_goods_info['sku_id']]);
  794. $document_type_info = [
  795. 'name' => '退货入库单',
  796. 'type' => 'input',
  797. 'prefix' => 'THRK',
  798. 'key' => 'REFUND',
  799. ];
  800. outFileLog($document_type_info,'refund','$document_type_info');
  801. $prefix = $document_type_info[ 'prefix' ];//单据前缀
  802. $type = $document_type_info[ 'type' ];//出入库类型
  803. $document_no = $this->createDocumentNo($prefix);
  804. outFileLog($document_no,'refund','$document_no');
  805. // $user_info = $this->user_info;
  806. outFileLog($user_info,'refund','$user_info');
  807. $params['site_id']=$order_goods_info['site_id'];
  808. $params['document_no']=$document_no;
  809. $params['key']=$document_type_info['key'];
  810. $params['type']=$type;
  811. $params['goods_money']=$order_goods_info['goods_money'];
  812. $params['document_money']=$order_goods_info['goods_money'];
  813. $params['status']=2;
  814. $params['create_time']=time();
  815. $params['store_id']=$order_goods_info['store_id'];
  816. $params['store_name']=$store_info['store_name'];
  817. $params['operater']=$user_info['uid'];
  818. $params['operater_name']=$user_info['username'];
  819. $params['time']=time();
  820. $document_id = model('stock_document')->add($params);
  821. $dgData['document_id']=$document_id;
  822. $dgData['goods_id']=$order_goods_info['goods_id'];
  823. $dgData['goods_sku_id']=$order_goods_info['sku_id'];
  824. $dgData['goods_sku_no']=$order_goods_info['sku_no'];
  825. $dgData['goods_sku_img']=$order_goods_info['sku_image'];
  826. $dgData['goods_sku_name']=$order_goods_info['sku_name'];
  827. $dgData['goods_num']=$order_goods_info['num'];
  828. $dgData['goods_price']=$order_goods_info['price'];
  829. $dgData['create_time']=time();
  830. $dgData['site_id']=$order_goods_info['site_id'];
  831. $dgData['before_stock']=$goods_sku_info['stock'];
  832. $dgData['after_stock']=$goods_sku_info['stock'] + $order_goods_info['num'];
  833. $dgData['before_goods_price']=$goods_sku_info['cost_price'];
  834. $dgData['after_goods_price']=$goods_sku_info['cost_price'];
  835. $dgData['store_id']=$order_goods_info['store_id'];
  836. $dgData['operater']=$user_info['uid'];
  837. $dgData['operater_name']=$user_info['username'];
  838. $dgData['before_store_stock']=$goods_sku_info['stock'];
  839. $dgData['before_store_goods_price']=$goods_sku_info['cost_price'];
  840. $dgData['after_store_stock']=$goods_sku_info['stock']+ $order_goods_info['num'];
  841. $dgData['after_store_goods_price']=$goods_sku_info['cost_price'];
  842. $dgData['total_goods_money']=$order_goods_info['goods_money'];
  843. $document_id = model('stock_document_goods')->add($dgData);
  844. return true;
  845. }
  846. /**
  847. * 退款完成操作
  848. * @param $order_goods_id
  849. * @param $refund_money_type
  850. * @return array
  851. */
  852. public function finishAction($order_goods_id, $log_data = [], $is_deposit_back = 1, $is_active_refund = false)
  853. {
  854. $order_goods_info = model('order_goods')->getInfo([ 'order_goods_id' => $order_goods_id ]);
  855. $order_id = $order_goods_info[ 'order_id' ];
  856. $site_id = $order_goods_info[ 'site_id' ];
  857. model('order_goods')->startTrans();
  858. try {
  859. $order_info = model('order')->getInfo([ 'order_id' => $order_id ]);
  860. //验证订单是否全部退款完毕
  861. $order_goods_count = model('order_goods')->getCount([ [ 'order_id', '=', $order_id ] ], 'order_goods_id');
  862. $refund_count = model('order_goods')->getCount([ [ 'order_id', '=', $order_id ], [ 'refund_status', '=', self::REFUND_COMPLETE ] ], 'order_goods_id');
  863. $refund_total_real_money = model('order_goods')->getSum([ [ 'order_id', '=', $order_id ], [ 'refund_status', '=', self::REFUND_COMPLETE ] ], 'refund_real_money');
  864. if ($refund_total_real_money > $order_info[ 'order_money' ]) {
  865. model('order_goods')->rollback();
  866. return $this->error([], '退款金额不能大于订单总金额');
  867. }
  868. //todo 退还创建订单时使用的次卡
  869. //实际执行转账 (存在余额支付的话 退款一部分余额 退还一部分实际金额) //订单退款退回余额积分等操作
  870. if ($order_info[ 'balance_money' ] > 0 && $order_goods_info[ 'refund_real_money' ] > 0) {
  871. $balance_rate = $order_info[ 'balance_money' ] / $order_info[ 'order_money' ];
  872. $refund_balance_money = $order_goods_info[ 'refund_real_money' ] * $balance_rate;
  873. $refund_pay_money = $order_goods_info[ 'refund_real_money' ] - $refund_balance_money;
  874. } else {
  875. $refund_balance_money = 0;
  876. $refund_pay_money = $order_goods_info[ 'refund_real_money' ];
  877. }
  878. model('order_goods')->update([ 'refund_pay_money' => $refund_pay_money ], [ 'order_goods_id' => $order_goods_id ]);
  879. $addon_result = event('AddonOrderRefund', [ 'order_no' => $order_info[ 'order_no' ], 'promotion_type' => $order_info[ 'promotion_type' ], 'is_deposit_back' => $is_deposit_back, 'refund_money_type' => $order_goods_info[ 'refund_money_type' ] ], true);
  880. if (empty($addon_result)) {
  881. //原路退回的时候退还余额 + 支付金额
  882. if ($order_goods_info[ 'refund_money_type' ] == 1) {
  883. //退还直接支付的金额
  884. if ($refund_pay_money > 0) {
  885. $pay_model = new Pay();
  886. if ($order_goods_info[ 'refund_no' ] == '') {
  887. $refund_no = $pay_model->createRefundNo();
  888. } else {
  889. $refund_no = $order_goods_info[ 'refund_no' ];
  890. }
  891. $refund_result = $pay_model->refund($refund_no, $refund_pay_money, $order_info[ 'out_trade_no' ], '', $order_info[ 'pay_money' ], $order_info[ 'site_id' ], 1, $order_goods_id, $order_info[ 'is_video_number' ]);
  892. if ($refund_result[ 'code' ] < 0) {
  893. model('order_goods')->rollback();
  894. return $refund_result;
  895. }
  896. //支付时超卖,主动退款的话,不计入统计数据
  897. if (!$is_active_refund) {
  898. $stat_model = new Stat();
  899. $stat_model->switchStat([ 'type' => 'order_refund', 'data' => [ 'order_goods_id' => $order_goods_id, 'refund_pay_money' => $refund_pay_money, 'site_id' => $site_id ] ]);
  900. }
  901. }
  902. //退款余额
  903. if ($refund_balance_money > 0) {
  904. $member_account_model = new MemberAccount();
  905. // 查询该订单使用的现金余额
  906. $order_use_balance_money = abs($member_account_model->getMemberAccountSum([ [ 'account_type', '=', 'balance_money' ], [ 'type_tag', '=', $order_id ], [ 'from_type', '=', 'order' ] ], 'account_data')[ 'data' ]);
  907. // 查询该订单已退回的现金余额
  908. $refunded_balance_money = $member_account_model->getMemberAccountSum([ [ 'account_type', '=', 'balance_money' ], [ 'type_tag', '=', $order_id ], [ 'from_type', '=', 'refund' ] ], 'account_data')[ 'data' ];
  909. if ($order_use_balance_money > $refunded_balance_money) {
  910. $refundable_balance_money = $order_use_balance_money - $refunded_balance_money;
  911. $refundable_balance_money = $refundable_balance_money > $refund_balance_money ? $refund_balance_money : $refundable_balance_money;
  912. $refund_balance_money -= $refundable_balance_money;
  913. $balance_result = $member_account_model->addMemberAccount($order_info[ 'site_id' ], $order_info[ 'member_id' ], 'balance_money', $refundable_balance_money, 'refund', $order_id, '订单退款返还');
  914. if ($balance_result[ 'code' ] < 0) {
  915. model('order_goods')->rollback();
  916. return $balance_result;
  917. }
  918. }
  919. if ($refund_balance_money > 0) {
  920. $balance_result = $member_account_model->addMemberAccount($order_info[ 'site_id' ], $order_info[ 'member_id' ], 'balance', $refund_balance_money, 'refund', $order_id, '订单退款返还');
  921. if ($balance_result[ 'code' ] < 0) {
  922. model('order_goods')->rollback();
  923. return $balance_result;
  924. }
  925. }
  926. }
  927. } else if ($order_goods_info[ 'refund_money_type' ] == 3) { //退款到余额
  928. $member_account_model = new MemberAccount();
  929. $refund_result = $member_account_model->addMemberAccount($order_info[ 'site_id' ], $order_info[ 'member_id' ], 'balance', $refund_total_real_money, 'refund', $order_id, '订单退款返还');
  930. if ($refund_result[ 'code' ] < 0) {
  931. model('order_goods')->rollback();
  932. return $refund_result;
  933. }
  934. } else if ($order_goods_info[ 'refund_money_type' ] == 2) {//线下退款
  935. //支付时超卖,主动退款的话,不计入统计数据
  936. if (!$is_active_refund) {
  937. $stat_model = new Stat();
  938. $stat_model->switchStat([ 'type' => 'order_refund', 'data' => [ 'order_goods_id' => $order_goods_id, 'refund_pay_money' => $refund_pay_money, 'site_id' => $site_id ] ]);
  939. }
  940. }
  941. } else {
  942. if ($addon_result[ 'code' ] < 0) {
  943. model('order_goods')->rollback();
  944. return $addon_result;
  945. }
  946. }
  947. //虚拟商品 退款 修改核销码状态
  948. if ($order_goods_info[ 'refund_mode' ] == 1 && $order_goods_info[ 'goods_class' ] == 2) {
  949. $verify_goods_condition = [
  950. [ 'order_no', '=', $order_info[ 'order_no' ] ],
  951. [ 'site_id', '=', $order_info[ 'site_id' ] ]
  952. ];
  953. $virtual_goods_res = model('goods_virtual')->update([ 'is_veirfy' => 2 ], $verify_goods_condition);
  954. $verify_model = new VerifyModel();
  955. $verify_condition = [
  956. [ 'verify_code', '=', $order_info[ 'virtual_code' ] ],
  957. [ 'site_id', '=', $order_info[ 'site_id' ] ]
  958. ];
  959. $verify_res = $verify_model->editVerify([ 'is_verify' => 2 ], $verify_condition);
  960. }
  961. // 退还积分 只有退款时返还 售后不返还
  962. if ($order_goods_info[ 'refund_mode' ] == 1 && $order_goods_info[ 'use_point' ] > 0) {
  963. $member_account_model = new MemberAccount();
  964. $point_result = $member_account_model->addMemberAccount($order_info[ 'site_id' ], $order_info[ 'member_id' ], 'point', $order_goods_info[ 'use_point' ], 'refund', $order_id, '订单退款返还');
  965. if ($point_result[ 'code' ] < 0) {
  966. model('order_goods')->rollback();
  967. return $point_result;
  968. }
  969. }
  970. // 退还次卡
  971. if (!empty($order_goods_info[ 'card_item_id' ]) && addon_is_exit('cardservice', $order_goods_info[ 'site_id' ])) {
  972. ( new MemberCard() )->refund([ [ 'type' => 'order', 'relation_id' => $order_goods_info[ 'order_goods_id' ] ] ]);
  973. }
  974. //验证订单锁定状态
  975. $lock_result = $this->verifyOrderLock($order_id);
  976. //验证订单是否全部退款完毕 订单如果全部退款完毕,订单关闭
  977. if ($order_goods_count == $refund_count) {
  978. //将订单设置为不可退款
  979. $order_common_model = new OrderCommon();
  980. $order_common_model->orderUpdate([ 'is_enable_refund' => 0 ], [ [ 'order_id', '=', $order_id ] ]);
  981. if ($order_info[ 'order_status' ] != Order::ORDER_COMPLETE) {
  982. $order_common_model = new OrderCommon();
  983. //记录订单日志 start
  984. if (!empty($log_data)) {
  985. $log_data = array_merge($log_data, [
  986. 'order_id' => $order_id,
  987. 'order_status' => -1,
  988. 'order_status_name' => '已关闭'
  989. ]);
  990. $order_common_model->addOrderLog($log_data);
  991. }
  992. $close_result = $order_common_model->orderClose($order_id, [], '退款完成,订单关闭');
  993. if ($close_result[ 'code' ] < 0) {
  994. model('order_goods')->rollback();
  995. return $close_result;
  996. }
  997. } else {
  998. if (!empty($log_data)) {
  999. $order_common_model = new OrderCommon();
  1000. $log_data = array_merge($log_data, [
  1001. 'order_id' => $order_id,
  1002. 'order_status' => $order_info[ 'order_status' ],
  1003. 'order_status_name' => $order_info[ 'order_status_name' ]
  1004. ]);
  1005. $order_common_model->addOrderLog($log_data);
  1006. }
  1007. }
  1008. } else {
  1009. //记录订单日志 start
  1010. if (!empty($log_data)) {
  1011. $order_common_model = new OrderCommon();
  1012. $log_data = array_merge($log_data, [
  1013. 'order_id' => $order_id,
  1014. 'order_status' => $order_info[ 'order_status' ],
  1015. 'order_status_name' => $order_info[ 'order_status_name' ]
  1016. ]);
  1017. $order_common_model->addOrderLog($log_data);
  1018. }
  1019. //记录订单日志 end
  1020. }
  1021. // 如果售后完成关闭订单评价
  1022. if ($order_goods_count == $refund_count && $order_info[ 'order_status' ] == Order::ORDER_COMPLETE) {
  1023. $order_common_model = new OrderCommon();
  1024. $order_common_model->orderUpdate([ 'is_evaluate' => 0 ], [ [ 'order_id', '=', $order_id ] ]);
  1025. } else if ($order_info[ 'order_status' ] == Order::ORDER_COMPLETE || $order_info[ 'order_status' ] == Order::ORDER_TAKE_DELIVERY) {
  1026. $order_common_model = new OrderCommon();
  1027. if ($order_info[ 'evaluate_status' ] != 2) {
  1028. $order_common_model->orderUpdate([ 'is_evaluate' => 1 ], [ [ 'order_id', '=', $order_id ] ]);
  1029. }
  1030. }
  1031. //订单累加 退款
  1032. model('order')->update([ 'refund_money' => $refund_total_real_money ], [ [ 'order_id', '=', $order_id ] ]);
  1033. event('OrderRefundFinish', $order_goods_info);//传入订单类型以及订单项id
  1034. model('order_goods')->commit();
  1035. return $this->success();
  1036. } catch (\Exception $e) {
  1037. model('order_goods')->rollback();
  1038. return $this->error('', $e->getMessage() . $e->getFile() . $e->getLine());
  1039. }
  1040. }
  1041. /**
  1042. * 创建出入库单号
  1043. * @param $prefix
  1044. * @return string
  1045. */
  1046. public function createDocumentNo($prefix)
  1047. {
  1048. $document_no = $prefix . date('ymdhis', time()) . rand(1111, 9999);
  1049. return $document_no;
  1050. }
  1051. /**
  1052. * 获取订单售后操作列表
  1053. * @param array $condition
  1054. * @param string $field
  1055. * @return array
  1056. */
  1057. public function getOrderRefundLogList($condition = [], $field = '*', $order = '', $limit = null)
  1058. {
  1059. $list = model('order_refund_log')->getList($condition, $field, $order, '', '', '', $limit);
  1060. return $this->success($list);
  1061. }
  1062. /**
  1063. * 获取退款维权订单列表
  1064. * @param array $condition
  1065. * @param number $page
  1066. * @param string $page_size
  1067. * @param string $order
  1068. * @param string $field
  1069. */
  1070. public function getRefundOrderGoodsPageList($condition = [], $page = 1, $page_size = PAGE_LIST_ROWS, $order = '', $field = 'nop.*,no.order_no,no.site_id,no.site_name,no.name,m.nickname')
  1071. {
  1072. $join = [
  1073. [
  1074. 'order no',
  1075. 'nop.order_id = no.order_id',
  1076. 'left'
  1077. ],
  1078. [
  1079. 'member m',
  1080. 'm.member_id = no.member_id',
  1081. 'left'
  1082. ],
  1083. ];
  1084. $list = model('order_goods')->pageList($condition, $field, $order, $page, $page_size, 'nop', $join);
  1085. if (!empty($list[ 'list' ])) {
  1086. foreach ($list[ 'list' ] as $k => $v) {
  1087. $refund_action = empty($v[ 'refund_status_action' ]) ? [] : json_decode($v[ 'refund_status_action' ], true);
  1088. $refund_member_action = $refund_action[ 'member_action' ] ?? [];
  1089. $list[ 'list' ][ $k ][ 'refund_action' ] = $refund_member_action;
  1090. if (isset($v[ 'goods_num' ])) {
  1091. $list[ 'list' ][ $k ][ 'goods_num' ] = numberFormat($list[ 'list' ][ $k ][ 'goods_num' ]);
  1092. }
  1093. if (isset($v[ 'num' ])) {
  1094. $list[ 'list' ][ $k ][ 'num' ] = numberFormat($list[ 'list' ][ $k ][ 'num' ]);
  1095. }
  1096. }
  1097. }
  1098. return $this->success($list);
  1099. }
  1100. /**
  1101. * 获取退款维权订单数量
  1102. * @param array $condition
  1103. */
  1104. public function getRefundOrderGoodsCount($condition = [])
  1105. {
  1106. $count = model('order_goods')->getCount($condition);
  1107. return $this->success($count);
  1108. }
  1109. /**
  1110. * 初始化订单项退款操作
  1111. * @param $order_id
  1112. */
  1113. public function initOrderGoodsRefundAction($condition)
  1114. {
  1115. //订单项增加可退款操作
  1116. $data = array (
  1117. 'refund_status_action' => json_encode($this->order_refund_status[ 0 ], JSON_UNESCAPED_UNICODE)
  1118. );
  1119. $result = model('order_goods')->update($data, $condition);
  1120. return $this->success($result);
  1121. }
  1122. /**
  1123. * 移除订单项退款操作
  1124. * @param $order_id
  1125. */
  1126. public function removeOrderGoodsRefundAction($condition)
  1127. {
  1128. //订单项增加可退款操作
  1129. $data = array (
  1130. 'refund_status_action' => ''
  1131. );
  1132. $result = model('order_goods')->update($data, $condition);
  1133. return $this->success($result);
  1134. }
  1135. /**
  1136. * 会员维权详情
  1137. * @param $order_goods_id
  1138. */
  1139. public function getMemberRefundDetail($order_goods_id, $member_id)
  1140. {
  1141. $condition = array (
  1142. [ 'order_goods_id', '=', $order_goods_id ]
  1143. );
  1144. $condition[] = [ 'member_id', '=', $member_id ];
  1145. $info = model('order_goods')->getInfo($condition);
  1146. $refund_action = empty($info[ 'refund_status_action' ]) ? [] : json_decode($info[ 'refund_status_action' ], true);
  1147. $refund_member_action = $refund_action[ 'member_action' ] ?? [];
  1148. $info[ 'refund_action' ] = $refund_member_action;
  1149. $info[ 'num' ] = numberFormat($info[ 'num' ]);
  1150. //将售后日志引入
  1151. $refund_log_list = model('order_refund_log')->getList([ [ 'order_goods_id', '=', $order_goods_id ] ], '*', 'action_time desc');
  1152. $info[ 'refund_log_list' ] = $refund_log_list;
  1153. return $this->success($info);
  1154. }
  1155. /**
  1156. * 会员维权详情
  1157. * @param $order_goods_id
  1158. */
  1159. public function getRefundDetail($order_goods_id, $site_id = 0, $store_id = 0)
  1160. {
  1161. $condition = array (
  1162. [ 'order_goods_id', '=', $order_goods_id ]
  1163. );
  1164. if ($site_id > 0) {
  1165. $condition[] = [ 'site_id', '=', $site_id ];
  1166. }
  1167. if ($store_id > 0) {
  1168. $condition[] = [ 'store_id', '=', $store_id ];
  1169. }
  1170. $info = model('order_goods')->getInfo($condition);
  1171. if (empty($info)) return $this->error('', '');
  1172. $order_common_model = new OrderCommon();
  1173. $order_info = $order_common_model->getOrderDetail($info[ "order_id" ])[ 'data' ];
  1174. $info[ 'pay_type' ] = $order_info[ 'pay_type' ];
  1175. $coupon_info = [];
  1176. if ($order_info[ 'coupon_id' ] > 0) {
  1177. $order_goods_count = model('order_goods')->getCount([ [ 'order_id', '=', $info[ 'order_id' ] ] ], 'order_goods_id');
  1178. $refund_count = model('order_goods')->getCount([ [ 'order_id', '=', $info[ 'order_id' ] ], [ 'refund_status', '=', self::REFUND_COMPLETE ] ], 'order_goods_id');
  1179. if (( $order_goods_count - $refund_count ) == 1) {
  1180. //查询优惠劵信息
  1181. $coupon_model = new Coupon();
  1182. $coupon_info = $coupon_model->getCouponInfo([ [ 'coupon_id', '=', $order_info[ 'coupon_id' ] ] ], 'coupon_id,coupon_name,type,at_least,money,discount,discount_limit');
  1183. $coupon_info = $coupon_info[ 'data' ];
  1184. }
  1185. }
  1186. $info[ 'coupon_info' ] = $coupon_info;
  1187. //添加会员昵称
  1188. $member = new Member();
  1189. $member_info = $member->getMemberInfo([ [ "member_id", '=', $info[ 'member_id' ] ] ], 'nickname')[ 'data' ] ?? [];
  1190. $info[ 'nickname' ] = $member_info[ 'nickname' ] ?? '';
  1191. if ($info[ 'refund_status' ] == 0) {
  1192. $refund_apply_arr = $this->getOrderRefundMoney($order_goods_id);
  1193. $info[ 'refund_apply_money' ] = round($refund_apply_arr[ 'refund_money' ], 2);
  1194. $info[ 'refund_delivery_money' ] = $refund_apply_arr[ 'refund_delivery_money' ];
  1195. }
  1196. $refund_action = empty($info[ 'refund_status_action' ]) ? [] : json_decode($info[ 'refund_status_action' ], true);
  1197. $refund_action = $refund_action[ 'action' ] ?? [];
  1198. $info[ 'refund_action' ] = $refund_action;
  1199. //将售后日志引入
  1200. $refund_log_list = model('order_refund_log')->getList([ [ 'order_goods_id', '=', $order_goods_id ] ], '*', 'action_time desc');
  1201. $info[ 'refund_log_list' ] = $refund_log_list;
  1202. $info[ 'num' ] = numberFormat($info[ 'num' ]);
  1203. return $this->success($info);
  1204. }
  1205. /**
  1206. * 根据配送状态获取退款方式
  1207. * @param $refund_status
  1208. */
  1209. public function getRefundType($order_goods_info)
  1210. {
  1211. if ($order_goods_info[ 'is_virtual' ] == 1) {
  1212. return [ self::ONLY_REFUNDS ];
  1213. } else {
  1214. if ($order_goods_info[ 'delivery_status' ] == 0) {
  1215. return [ self::ONLY_REFUNDS ];
  1216. } else {
  1217. return [ self::ONLY_REFUNDS, self::A_REFUND_RETURN ];
  1218. }
  1219. }
  1220. }
  1221. /**
  1222. * 根据配送状态获取退款方式
  1223. */
  1224. public function getRefundOrderType($order_id)
  1225. {
  1226. $status = model('order')->getInfo([ [ 'order_id', '=', $order_id ] ], 'delivery_status');
  1227. if ($status[ 'delivery_status' ] == 0) {
  1228. return [ self::ONLY_REFUNDS ];
  1229. } else {
  1230. return [ self::ONLY_REFUNDS, self::A_REFUND_RETURN ];
  1231. }
  1232. }
  1233. /****************************************************************************订单退款相关操作(结束)**********************************/
  1234. /********************************************************************** 主动退款 ********************************************************************/
  1235. /**
  1236. * 主动完成退款流程
  1237. * @param $order_id
  1238. */
  1239. public function activeRefund($order_id, $remark, $refund_reason)
  1240. {
  1241. $order_info = model('order')->getInfo([ [ 'order_id', '=', $order_id ] ], 'order_money, out_trade_no, site_id, delivery_money');
  1242. if ($order_info[ 'order_money' ] > 0) {
  1243. $pay_model = new Pay();
  1244. //遍历订单项
  1245. $order_goods_list = model('order_goods')->getList([ [ 'order_id', '=', $order_id ] ]);
  1246. if (!empty($order_goods_list)) {
  1247. $count = count($order_goods_list);
  1248. foreach ($order_goods_list as $k => $v) {
  1249. $item_refund_money = $v[ 'real_goods_money' ];
  1250. if ($count == ( $k + 1 )) {
  1251. $item_refund_money += $order_info[ 'delivery_money' ];
  1252. }
  1253. $item_result = $this->activeOrderGoodsRefund($v[ 'order_goods_id' ], $item_refund_money, $remark, $refund_reason);
  1254. if ($item_result[ 'code' ] < 0) {
  1255. return $item_result;
  1256. }
  1257. }
  1258. }
  1259. //订单整体退款
  1260. // $refund_result = $pay_model->refund($refund_no, $order_info['pay_money'], $order_info['out_trade_no'], '', $order_info['pay_money'], $order_info['site_id'], 1);
  1261. return $this->success();
  1262. } else {
  1263. return $this->success();
  1264. }
  1265. }
  1266. /**
  1267. * 订单项主动退款
  1268. * @param $order_goods_id
  1269. * @param $refund_money
  1270. * @return array|mixed|void
  1271. */
  1272. public function activeOrderGoodsRefund($order_goods_id, $refund_money, $remark = '', $refund_reason = '')
  1273. {
  1274. model('order_goods')->startTrans();
  1275. try {
  1276. //判断是否退款完毕
  1277. $order_goods_info = model('order_goods')->getInfo([ [ 'order_goods_id', '=', $order_goods_id ] ]);
  1278. if ($order_goods_info[ 'refund_status' ] == self::REFUND_COMPLETE) {
  1279. model('order_goods')->rollback();
  1280. return $this->error('', '订单不能重复维权');
  1281. }
  1282. $pay_model = new Pay();
  1283. $refund_no = $pay_model->createRefundNo();
  1284. $update_data = array (
  1285. 'refund_no' => $refund_no,
  1286. 'refund_time' => time(),
  1287. 'refund_reason' => $refund_reason,
  1288. 'refund_apply_money' => $refund_money,
  1289. 'refund_real_money' => $refund_money,
  1290. 'refund_action_time' => time()
  1291. );
  1292. $update_data[ 'refund_status' ] = self::REFUND_COMPLETE;
  1293. $update_data[ 'refund_status_name' ] = $this->order_refund_status[ self::REFUND_COMPLETE ][ 'name' ];
  1294. $update_data[ 'refund_status_action' ] = json_encode($this->order_refund_status[ self::REFUND_COMPLETE ], JSON_UNESCAPED_UNICODE);
  1295. $res = model('order_goods')->update($update_data, [ [ 'order_goods_id', '=', $order_goods_id ] ]);
  1296. if ($res === false) {
  1297. model('order_goods')->rollback();
  1298. return $this->error();
  1299. }
  1300. $refund_result = $this->finishAction($order_goods_id, [], 1, true);
  1301. if ($refund_result[ 'code' ] < 0) {
  1302. model('order_goods')->rollback();
  1303. return $refund_result;
  1304. }
  1305. //退货日志
  1306. $this->addOrderRefundLog($order_goods_id, self::REFUND_COMPLETE, $remark . ',维权完成', 3, 0, '平台');
  1307. model('order_goods')->commit();
  1308. return $this->success();
  1309. } catch (\Exception $e) {
  1310. model('order_goods')->rollback();
  1311. return $this->error('', $e->getMessage());
  1312. }
  1313. }
  1314. /********************************************************************** 主动退款 ********************************************************************/
  1315. /**
  1316. * 判断订单的锁定状态
  1317. * @param $order_goods_id
  1318. */
  1319. public function verifyOrderLock($order_id)
  1320. {
  1321. $condition = array (
  1322. [ 'order_id', '=', $order_id ],
  1323. [ 'refund_status', 'not in', [ 0, 3 ] ],
  1324. );
  1325. $count = model('order_goods')->getCount($condition, 'order_goods_id');
  1326. $order_common_model = new OrderCommon();
  1327. if ($count > 0) {
  1328. $res = $order_common_model->orderLock($order_id);
  1329. } else {
  1330. $res = $order_common_model->orderUnlock($order_id);
  1331. }
  1332. return $res;
  1333. }
  1334. /**
  1335. * 关闭退款
  1336. * @param $order_goods_id
  1337. * @param $site_id
  1338. */
  1339. public function orderRefundClose($order_goods_id, $site_id, $user_info)
  1340. {
  1341. $order_goods_info = model('order_goods')->getInfo([ 'order_goods_id' => $order_goods_id, 'site_id' => $site_id ]);
  1342. if (empty($order_goods_info)) {
  1343. return $this->error();
  1344. }
  1345. model('order_goods')->startTrans();
  1346. try {
  1347. $data = [
  1348. 'order_goods_id' => $order_goods_id,
  1349. 'refund_status' => 0,
  1350. 'refund_status_name' => $this->order_refund_status[ 0 ][ 'name' ],
  1351. 'refund_status_action' => json_encode($this->order_refund_status[ 0 ], JSON_UNESCAPED_UNICODE),
  1352. 'refund_type' => 0,
  1353. 'refund_address' => '',
  1354. 'refund_delivery_remark' => '',
  1355. 'refund_remark' => '',
  1356. 'refund_delivery_name' => '',
  1357. 'refund_delivery_no' => '',
  1358. 'refund_reason' => ''
  1359. ];
  1360. $res = model('order_goods')->update($data, [ 'order_goods_id' => $order_goods_id ]);
  1361. //验证订单锁定状态
  1362. $lock_result = $this->verifyOrderLock($order_goods_info[ 'order_id' ]);
  1363. //记录订单日志 start
  1364. $order_common_model = new OrderCommon();
  1365. $order_info = model('order')->getInfo([ 'order_id' => $order_goods_info[ 'order_id' ] ], 'order_status,order_status_name,is_video_number,site_id,member_id');
  1366. $log_data = [
  1367. 'uid' => $user_info[ 'uid' ],
  1368. 'nick_name' => $user_info[ 'username' ],
  1369. 'action' => '商家关闭了维权',
  1370. 'action_way' => 2,
  1371. 'order_id' => $order_goods_info[ 'order_id' ],
  1372. 'order_status' => $order_info[ 'order_status' ],
  1373. 'order_status_name' => $order_info[ 'order_status_name' ]
  1374. ];
  1375. $order_common_model->addOrderLog($log_data);
  1376. //记录订单日志 end
  1377. if ($order_info[ 'is_video_number' ] == 1) {
  1378. $weapp_model = new Weapp($order_info[ 'site_id' ]);
  1379. $member = model('member')->getInfo([ [ 'member_id', '=', $order_info[ 'member_id' ] ] ]);
  1380. $res = $weapp_model->orderNoRefund([
  1381. 'out_aftersale_id' => $order_goods_info[ 'out_aftersale_id' ]
  1382. ]);
  1383. if ($res[ 'code' ] < 0) {
  1384. model('order_goods')->rollback();
  1385. return $this->error('', $res[ 'message' ]);
  1386. }
  1387. }
  1388. $this->addOrderRefundLog($data[ 'order_goods_id' ], 0, '卖家关闭本次维权', 2, $user_info[ 'uid' ], $user_info[ 'username' ]);
  1389. event('memberCancelRefund', $data);//传入订单类型以及订单项id
  1390. model('order_goods')->commit();
  1391. return $this->success();
  1392. } catch (\Exception $e) {
  1393. model('order_goods')->rollback();
  1394. return $this->error('', $e->getMessage());
  1395. }
  1396. }
  1397. /**
  1398. * 获取订单项退款信息
  1399. * @param $order_goods_id
  1400. * @param $site_id
  1401. * @return array
  1402. */
  1403. public function getOrderGoodsRefundInfo($order_goods_id, $site_id = 0, $store_id = 0)
  1404. {
  1405. $order_goods_condition = array (
  1406. [ 'order_goods_id', '=', $order_goods_id ]
  1407. );
  1408. if ($site_id > 0) {
  1409. $order_goods_condition[] = [ 'site_id', '=', $site_id ];
  1410. }
  1411. if ($store_id > 0) {
  1412. $order_goods_condition[] = [ 'store_id', '=', $store_id ];
  1413. }
  1414. $order_goods_info = model('order_goods')->getInfo($order_goods_condition);
  1415. if (empty($order_goods_info)) {
  1416. return $this->error('', '该订单项不存在');
  1417. }
  1418. if ($order_goods_info[ 'refund_status' ] == self::REFUND_COMPLETE) {
  1419. return $this->error('该订单项已维权结束');
  1420. }
  1421. $order_goods_info[ 'num' ] = numberFormat($order_goods_info[ 'num' ]);
  1422. if ($order_goods_info[ 'refund_status' ] == 0) {
  1423. $refund_apply_arr = $this->getOrderRefundMoney($order_goods_id);
  1424. $order_goods_info[ 'refund_apply_money' ] = round($refund_apply_arr[ 'refund_money' ], 2);
  1425. $order_goods_info[ 'refund_delivery_money' ] = $refund_apply_arr[ 'refund_delivery_money' ];
  1426. }
  1427. //获取订单信息
  1428. $order_info = model('order')->getInfo([ [ 'order_id', '=', $order_goods_info[ 'order_id' ] ] ]);
  1429. $coupon_info = [];
  1430. if ($order_info[ 'coupon_id' ] > 0) {
  1431. $order_goods_count = model('order_goods')->getCount([ [ 'order_id', '=', $order_goods_info[ 'order_id' ] ] ], 'order_goods_id');
  1432. $refund_count = model('order_goods')->getCount([ [ 'order_id', '=', $order_goods_info[ 'order_id' ] ], [ 'refund_status', '=', self::REFUND_COMPLETE ] ], 'order_goods_id');
  1433. if (( $order_goods_count - $refund_count ) == 1) {
  1434. //查询优惠劵信息
  1435. $coupon_model = new Coupon();
  1436. $coupon_info = $coupon_model->getCouponInfo([ [ 'coupon_id', '=', $order_info[ 'coupon_id' ] ] ], 'coupon_id,coupon_name,type,at_least,money,discount,discount_limit');
  1437. $coupon_info = $coupon_info[ 'data' ];
  1438. }
  1439. }
  1440. $data = [
  1441. 'order_goods_info' => $order_goods_info,
  1442. 'order_info' => $order_info,
  1443. 'coupon_info' => $coupon_info
  1444. ];
  1445. //预售订单
  1446. if ($order_info[ 'promotion_type' ] == 'presale') {
  1447. $presale_order_model = new PresaleOrder();
  1448. $presale_order_info = $presale_order_model->getPresaleOrderInfo([ [ 'order_no', '=', $order_info[ 'order_no' ] ] ], 'presale_deposit_money,final_money');
  1449. $data[ 'presale_order_info' ] = $presale_order_info[ 'data' ];
  1450. }
  1451. return $this->success($data);
  1452. }
  1453. public function addshopcomponent($data)
  1454. {
  1455. $order_goods_info = model('order_goods')->getInfo([ 'order_goods_id' => $data[ 'order_goods_id' ] ]);
  1456. if (empty($order_goods_info)) {
  1457. return $this->error();
  1458. }
  1459. $refund_apply_money = $order_goods_info[ 'refund_apply_money' ];
  1460. $shop_active_refund = $data[ 'shop_active_refund' ] ?? 0;
  1461. if ($shop_active_refund == 1) {//商家主动退款
  1462. //查询发货状态(已发货的不能主动退款)
  1463. if ($order_goods_info[ 'delivery_status' ] != OrderModel::DELIVERY_WAIT) {
  1464. return $this->error();
  1465. }
  1466. //获取可退金额
  1467. $refund_apply_money_arr = $this->getOrderRefundMoney($data[ 'order_goods_id' ]);
  1468. $refund_apply_money = $refund_apply_money_arr[ 'refund_money' ];
  1469. $refund_delivery_money = $refund_apply_money_arr[ 'refund_delivery_money' ];
  1470. $data[ 'refund_real_money' ] = $refund_apply_money;
  1471. $data[ 'refund_delivery_money' ] = $refund_delivery_money;
  1472. } else {
  1473. if ($order_goods_info[ 'refund_status' ] != self::REFUND_TAKEDELIVERY && $order_goods_info[ 'refund_status' ] != self::REFUND_CONFIRM) {
  1474. return $this->error();
  1475. }
  1476. }
  1477. if ($data[ 'refund_real_money' ] > $refund_apply_money) return $this->error('', '退款金额超出最大可退金额');
  1478. //视频号订单创建订单
  1479. $order_info = model('order')->getInfo([ [ 'order_id', '=', $order_goods_info[ 'order_id' ] ] ]);
  1480. if ($order_info[ 'is_video_number' ] == 1) {
  1481. $member = model('member')->getInfo([ [ 'member_id', '=', $order_info[ 'member_id' ] ] ]);
  1482. $data = [
  1483. 'out_order_id' => (string) $order_info[ 'order_id' ],
  1484. 'out_aftersale_id' => $data[ 'out_aftersale_id' ],
  1485. 'openid' => $member[ 'weapp_openid' ],
  1486. 'type' => 1,
  1487. 'product_info' => [
  1488. 'out_product_id' => (string) $order_goods_info[ 'goods_id' ],
  1489. 'out_sku_id' => (string) $order_goods_info[ 'sku_id' ],
  1490. 'product_cnt' => (int) $order_goods_info[ 'num' ],//注意:这儿不支持称重商品
  1491. ],
  1492. 'refund_reason' => '无',
  1493. 'refund_reason_type' => 12,
  1494. 'orderamt' => round($refund_apply_money * 100)
  1495. ];
  1496. $weapp = new Weapp($order_info[ 'site_id' ]);
  1497. $res = $weapp->addAftersale($data);
  1498. if ($res[ 'code' ] < 0) {
  1499. return $this->error('', $res[ 'message' ]);
  1500. }
  1501. }
  1502. }
  1503. /******************************************************************************** 主动退款(商家) **********************************************/
  1504. /**
  1505. * 商家主动退款
  1506. * @param $params
  1507. */
  1508. public function doOrderOrderRefund($params)
  1509. {
  1510. $site_id = $params[ 'site_id' ] ?? 0;
  1511. $app_module = $params[ 'app_module' ];
  1512. $refund_money_type = $params[ 'refund_money_type' ];
  1513. $shop_refund_remark = $params[ 'shop_refund_remark' ];
  1514. $do_refund_money = $params[ 'do_refund_money' ] ?? 0;
  1515. $user_info = $params[ 'user_info' ];
  1516. $order_goods_id = $params[ 'order_goods_id' ];
  1517. $config_model = new Config();
  1518. $config_info = $config_model->getOrderEventTimeConfig($site_id, $app_module)[ 'data' ][ 'value' ] ?? [];
  1519. $do_refund = $config_info[ 'do_refund' ] ?? 1;
  1520. $order_commnn_model = new OrderCommon();
  1521. $order_goods_info = $order_commnn_model->getOrderGoodsInfo([ [ 'order_goods_id', '=', $order_goods_id ] ]);
  1522. $out_aftersale_id = $order_goods_info[ 'data' ][ 'order_no' ] . time() . $order_goods_id;
  1523. $data = array (
  1524. 'order_goods_id' => $order_goods_id,
  1525. 'refund_money_type' => $refund_money_type,
  1526. 'shop_refund_remark' => $shop_refund_remark,
  1527. 'shop_active_refund' => 1,
  1528. 'out_aftersale_id' => $out_aftersale_id,
  1529. 'do_refund_money' => $do_refund_money
  1530. );
  1531. $log_data = [
  1532. 'uid' => $user_info[ 'uid' ],
  1533. 'nick_name' => $user_info[ 'username' ],
  1534. 'action' => '商家对订单进行了主动退款',
  1535. 'action_way' => 2
  1536. ];
  1537. if ($do_refund == 1) {//直接完成退款
  1538. //创建视频号售后订单
  1539. $res = $this->addshopcomponent($data);
  1540. if ($res) {
  1541. return $res;
  1542. }
  1543. $result = $this->orderRefundFinish($data, $user_info, $log_data);
  1544. } else {
  1545. //发起申请,需要审核通过转账(仅退款)
  1546. //主动模拟退款申请和退款通过
  1547. $apply_data = array (
  1548. 'order_goods_id' => $order_goods_id,
  1549. 'refund_type' => self::ONLY_REFUNDS,
  1550. 'refund_reason' => '商家对订单进行了主动退款',
  1551. 'refund_remark' => '商家对订单进行了主动退款',
  1552. );
  1553. $refund_data = array (
  1554. 'data' => $apply_data,
  1555. 'user_info' => $user_info,
  1556. 'log_data' => $log_data,
  1557. 'do_refund_money' => $do_refund_money
  1558. );
  1559. $result = $this->doOrderOrderRefundApply($refund_data);
  1560. }
  1561. return $result;
  1562. }
  1563. /**
  1564. * 店家主动申请退款
  1565. * @param $params
  1566. * @return array
  1567. */
  1568. public function doOrderOrderRefundApply($params)
  1569. {
  1570. $data = $params[ 'data' ];
  1571. $user_info = $params[ 'user_info' ];
  1572. $log_data = $params[ 'log_data' ] ?? [];
  1573. $do_refund_money = $params[ 'do_refund_money' ];
  1574. $order_goods_info = model('order_goods')->getInfo([ 'order_goods_id' => $data[ 'order_goods_id' ] ], 'order_id,refund_status,delivery_status,is_virtual,site_id,order_no,order_goods_id');
  1575. if (empty($order_goods_info))
  1576. return $this->error();
  1577. if ($order_goods_info[ 'refund_status' ] != 0 && $order_goods_info[ 'refund_status' ] != -1)
  1578. return $this->error([], '存在进行中的退款');
  1579. // $refund_type_list = $this->getRefundType($order_goods_info);
  1580. // //防止退款方式越权
  1581. // if (!in_array($data[ 'refund_type' ], $refund_type_list))
  1582. // return $this->error();
  1583. $order_info = model('order')->getInfo([ 'order_id' => $order_goods_info[ 'order_id' ] ]);
  1584. //判断是否允许申请退款
  1585. if ($order_info[ 'is_enable_refund' ] == 0) {
  1586. if ($order_info[ 'promotion_type' ] == 'pinfan') {
  1587. return $this->error('', '拼团活动正在进行中,待拼成功后可发起退款');
  1588. }
  1589. return $this->error();
  1590. }
  1591. model('order_goods')->startTrans();
  1592. try {
  1593. $data[ 'refund_status' ] = self::REFUND_APPLY;
  1594. $data[ 'refund_status_name' ] = $this->order_refund_status[ self::REFUND_APPLY ][ 'name' ];
  1595. $data[ 'refund_status_action' ] = json_encode($this->order_refund_status[ self::REFUND_APPLY ], JSON_UNESCAPED_UNICODE);
  1596. $data[ 'refund_mode' ] = $order_info[ 'order_status' ] == Order::ORDER_COMPLETE ? 2 : 1;
  1597. $pay_model = new Pay();
  1598. $data[ 'refund_no' ] = $pay_model->createRefundNo();
  1599. $data[ 'refund_action_time' ] = time();
  1600. $refund_apply_money_array = $this->getOrderRefundMoney($data[ 'order_goods_id' ]);//可退款金额 通过计算获得
  1601. $refund_apply_money = $refund_apply_money_array[ 'refund_money' ];
  1602. if ($do_refund_money > $refund_apply_money) {
  1603. model('order_goods')->rollback();
  1604. return $this->error('', '主动退款金额不能大于可退款总额');
  1605. }
  1606. $refund_apply_money = $do_refund_money;
  1607. $refund_delivery_money = $refund_apply_money_array[ 'refund_delivery_money' ];
  1608. $data[ 'refund_apply_money' ] = $refund_apply_money;//申请的总退款
  1609. $data[ 'refund_delivery_money' ] = $refund_delivery_money;//退的运费
  1610. //生成视频号订单ID
  1611. $data[ 'out_aftersale_id' ] = $order_goods_info[ 'order_no' ] . time() . $order_goods_info[ 'order_goods_id' ];
  1612. $res = model('order_goods')->update($data, [ 'order_goods_id' => $data[ 'order_goods_id' ] ]);
  1613. //验证订单锁定状态
  1614. $local_result = $this->verifyOrderLock($order_goods_info[ 'order_id' ]);
  1615. $this->addOrderRefundLog($data[ 'order_goods_id' ], self::REFUND_APPLY, '商家主动退款', 2, $user_info[ 'uid' ], $user_info[ 'username' ]);
  1616. event('orderRefundApply', $data);//传入订单类型以及订单项id
  1617. model('order_goods')->commit();
  1618. //订单会员申请退款消息
  1619. // $message_model = new Message();
  1620. // $message_model->sendMessage([ 'keywords' => 'BUYER_REFUND', 'order_goods_id' => $data[ 'order_goods_id' ], 'site_id' => $order_goods_info[ 'site_id' ] ]);
  1621. // 发起维权 关闭订单评价
  1622. model('order')->update([ 'is_evaluate' => 0 ], [ 'order_id' => $order_goods_info[ 'order_id' ] ]);
  1623. //记录订单日志 start
  1624. if ($log_data) {
  1625. $order_common_model = new OrderCommon();
  1626. $log_data = array_merge($log_data, [
  1627. 'order_id' => $order_goods_info[ 'order_id' ],
  1628. 'order_status' => $order_info[ 'order_status' ],
  1629. 'order_status_name' => $order_info[ 'order_status_name' ]
  1630. ]);
  1631. $order_common_model->addOrderLog($log_data);
  1632. }
  1633. //记录订单日志 end
  1634. return $this->success($res);
  1635. } catch (\Exception $e) {
  1636. model('order_goods')->rollback();
  1637. return $this->error('', $e->getMessage());
  1638. }
  1639. }
  1640. /**
  1641. * 查询退货地址
  1642. * @param $site_id
  1643. * @return array
  1644. */
  1645. public function getRefundAddress($site_id, $refund_address_id = 0)
  1646. {
  1647. $address = [];
  1648. $site_address_model = new SiteAddress();
  1649. $site_address_condition = array (
  1650. [ 'site_id', '=', $site_id ],
  1651. [ 'is_return', '=', 1 ],
  1652. );
  1653. if ($refund_address_id > 0) {
  1654. $site_address_condition[] = [ 'id', '=', $refund_address_id ];
  1655. } else {
  1656. $site_address_condition[] = [ 'is_return_default', '=', 1 ];
  1657. }
  1658. $site_address_info = $site_address_model->getAddressInfo($site_address_condition)[ 'data' ] ?? [];
  1659. if (empty($site_address_info)) {
  1660. unset($site_address_condition[ 2 ]);
  1661. $site_address_info = $site_address_model->getAddressInfo($site_address_condition)[ 'data' ] ?? [];
  1662. }
  1663. if (empty($site_address_info)) {
  1664. $shop_model = new Shop();
  1665. $shop_info_result = $shop_model->getShopInfo([ [ 'site_id', '=', $site_id ] ], 'full_address,address,name,mobile');
  1666. $shop_info = $shop_info_result[ 'data' ];
  1667. $address[ 'shop_contacts' ] = $shop_info[ 'name' ];
  1668. $address[ 'shop_mobile' ] = $shop_info[ 'mobile' ];
  1669. $address[ 'shop_address' ] = $shop_info[ 'full_address' ] . $shop_info[ 'address' ];
  1670. }
  1671. if (!empty($site_address_info)) {
  1672. $address[ 'shop_contacts' ] = $site_address_info[ 'contact_name' ];
  1673. $address[ 'shop_mobile' ] = $site_address_info[ 'mobile' ];
  1674. $address[ 'shop_address' ] = $site_address_info[ 'full_address' ];
  1675. }
  1676. return $address;
  1677. }
  1678. /**
  1679. * 求和
  1680. * @param array $where
  1681. * @param string $field
  1682. * @param string $alias
  1683. * @param null $join
  1684. * @return array
  1685. */
  1686. public function getRefundSum($where = [], $field = '', $alias = 'a', $join = null)
  1687. {
  1688. $data = model('order_goods')->getSum($where, $field, $alias, $join);
  1689. return $this->success($data);
  1690. }
  1691. /**
  1692. * 订单项退款
  1693. * @param $order_goods_info
  1694. * @return mixed|void
  1695. */
  1696. public function orderGoodsRefund($order_goods_info)
  1697. {
  1698. $order_info = model('order')->getInfo([ 'order_id' => $order_goods_info[ 'order_id' ] ]);
  1699. if (!empty($order_info)) {
  1700. $order_info[ 'goods_num' ] = numberFormat($order_info[ 'goods_num' ]);
  1701. }
  1702. $order_goods_info[ 'order_info' ] = $order_info;
  1703. $result = event('OrderGoodsRefund', $order_goods_info, true);
  1704. if (empty($result)) {
  1705. $order_common_model = new OrderCommon();
  1706. $order_model = $order_common_model->getOrderModel($order_info);
  1707. $result = $order_model->refund($order_goods_info);
  1708. }
  1709. return $result;
  1710. }
  1711. }