StoreOrder.php 41 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944
  1. <?php
  2. /**
  3. *
  4. * @author: xaboy<365615158@qq.com>
  5. * @day: 2017/12/20
  6. */
  7. namespace app\ebapi\model\store;
  8. use app\core\model\routine\RoutineTemplate;
  9. use app\ebapi\model\user\User;
  10. use app\ebapi\model\user\UserAddress;
  11. use app\core\model\user\UserBill;
  12. use app\ebapi\model\user\WechatUser;
  13. use basic\ModelBasic;
  14. use app\core\behavior\OrderBehavior;
  15. use app\core\behavior\GoodsBehavior;
  16. use app\core\behavior\UserBehavior;
  17. use app\core\behavior\PaymentBehavior;
  18. use service\HookService;
  19. use app\core\util\MiniProgramService;
  20. use app\core\util\SystemConfigService;
  21. use think\Cache;
  22. use traits\ModelTrait;
  23. class StoreOrder extends ModelBasic
  24. {
  25. use ModelTrait;
  26. protected $insert = ['add_time'];
  27. protected static $payType = ['weixin'=>'微信支付','yue'=>'余额支付','offline'=>'线下支付'];
  28. protected static $deliveryType = ['send'=>'商家配送','express'=>'快递配送'];
  29. protected function setAddTimeAttr()
  30. {
  31. return time();
  32. }
  33. protected function setCartIdAttr($value)
  34. {
  35. return is_array($value) ? json_encode($value) : $value;
  36. }
  37. protected function getCartIdAttr($value)
  38. {
  39. return json_decode($value,true);
  40. }
  41. /**获取订单组信息
  42. * @param $cartInfo
  43. * @return array
  44. */
  45. public static function getOrderPriceGroup($cartInfo)
  46. {
  47. $storePostage = floatval(SystemConfigService::get('store_postage'))?:0;//邮费基础价
  48. $storeFreePostage = floatval(SystemConfigService::get('store_free_postage'))?:0;//满额包邮
  49. $totalPrice = self::getOrderSumPrice($cartInfo,'truePrice');//获取订单总金额
  50. $costPrice = self::getOrderSumPrice($cartInfo,'costPrice');//获取订单成本价
  51. $vipPrice = self::getOrderSumPrice($cartInfo,'vip_truePrice');//获取订单会员优惠金额
  52. //如果满额包邮等于0
  53. if(!$storeFreePostage) {
  54. $storePostage = 0;
  55. }else{
  56. foreach ($cartInfo as $cart){
  57. if(!$cart['productInfo']['is_postage'])//若果产品不包邮
  58. $storePostage = bcadd($storePostage,$cart['productInfo']['postage'],2);
  59. }
  60. if($storeFreePostage <= $totalPrice) $storePostage = 0;//如果总价大于等于满额包邮 邮费等于0
  61. }
  62. // $totalPrice = bcadd($totalPrice,$storePostage,2);
  63. return compact('storePostage','storeFreePostage','totalPrice','costPrice','vipPrice');
  64. }
  65. /**获取某个字段总金额
  66. * @param $cartInfo
  67. * @param $key 键名
  68. * @return int|string
  69. */
  70. public static function getOrderSumPrice($cartInfo,$key='truePrice')
  71. {
  72. $SumPrice = 0;
  73. foreach ($cartInfo as $cart){
  74. $SumPrice = bcadd($SumPrice,bcmul($cart['cart_num'],$cart[$key],2),2);
  75. }
  76. return $SumPrice;
  77. }
  78. /**
  79. * 拼团
  80. * @param $cartInfo
  81. * @return array
  82. */
  83. public static function getCombinationOrderPriceGroup($cartInfo)
  84. {
  85. $storePostage = floatval(SystemConfigService::get('store_postage'))?:0;
  86. $storeFreePostage = floatval(SystemConfigService::get('store_free_postage'))?:0;
  87. $totalPrice = self::getCombinationOrderTotalPrice($cartInfo);
  88. $costPrice = self::getCombinationOrderTotalPrice($cartInfo);
  89. if(!$storeFreePostage) {
  90. $storePostage = 0;
  91. }else{
  92. foreach ($cartInfo as $cart){
  93. if(!StoreCombination::where('id',$cart['combination_id'])->value('is_postage'))
  94. $storePostage = bcadd($storePostage,StoreCombination::where('id',$cart['combination_id'])->value('postage'),2);
  95. }
  96. if($storeFreePostage <= $totalPrice) $storePostage = 0;
  97. }
  98. return compact('storePostage','storeFreePostage','totalPrice','costPrice');
  99. }
  100. /**
  101. * 拼团价格
  102. * @param $cartInfo
  103. * @return float
  104. */
  105. public static function getCombinationOrderTotalPrice($cartInfo)
  106. {
  107. $totalPrice = 0;
  108. foreach ($cartInfo as $cart){
  109. if($cart['combination_id']){
  110. $totalPrice = bcadd($totalPrice,bcmul($cart['cart_num'],StoreCombination::where('id',$cart['combination_id'])->value('price'),2),2);
  111. }
  112. }
  113. return (float)$totalPrice;
  114. }
  115. public static function cacheOrderInfo($uid,$cartInfo,$priceGroup,$other = [],$cacheTime = 600)
  116. {
  117. $key = md5(time());
  118. Cache::set('user_order_'.$uid.$key,compact('cartInfo','priceGroup','other'),$cacheTime);
  119. return $key;
  120. }
  121. public static function getCacheOrderInfo($uid,$key)
  122. {
  123. $cacheName = 'user_order_'.$uid.$key;
  124. if(!Cache::has($cacheName)) return null;
  125. return Cache::get($cacheName);
  126. }
  127. public static function clearCacheOrderInfo($uid,$key)
  128. {
  129. Cache::clear('user_order_'.$uid.$key);
  130. }
  131. /**生成订单
  132. * @param $uid
  133. * @param $key
  134. * @param $addressId
  135. * @param $payType
  136. * @param bool $useIntegral
  137. * @param int $couponId
  138. * @param string $mark
  139. * @param int $combinationId
  140. * @param int $pinkId
  141. * @param int $seckill_id
  142. * @param int $bargain_id
  143. * @return bool|object
  144. */
  145. public static function cacheKeyCreateOrder($uid,$key,$addressId,$payType,$useIntegral = false,$couponId = 0,$mark = '',$combinationId = 0,$pinkId = 0,$seckill_id=0,$bargain_id=0)
  146. {
  147. if(!array_key_exists($payType,self::$payType)) return self::setErrorInfo('选择支付方式有误!');
  148. if(self::be(['unique'=>$key,'uid'=>$uid])) return self::setErrorInfo('请勿重复提交订单');
  149. $userInfo = User::getUserInfo($uid);
  150. if(!$userInfo) return self::setErrorInfo('用户不存在!');
  151. $cartGroup = self::getCacheOrderInfo($uid,$key);
  152. if(!$cartGroup) return self::setErrorInfo('订单已过期,请刷新当前页面!');
  153. $cartInfo = $cartGroup['cartInfo'];
  154. $priceGroup = $cartGroup['priceGroup'];
  155. $other = $cartGroup['other'];
  156. $payPrice = (float)$priceGroup['totalPrice'];
  157. $payPostage = $priceGroup['storePostage'];
  158. if(!$addressId) return self::setErrorInfo('请选择收货地址!');
  159. if(!UserAddress::be(['uid'=>$uid,'id'=>$addressId,'is_del'=>0]) || !($addressInfo = UserAddress::find($addressId)))
  160. return self::setErrorInfo('地址选择有误!');
  161. //使用优惠劵
  162. $res1 = true;
  163. if($couponId){
  164. $couponInfo = StoreCouponUser::validAddressWhere()->where('id',$couponId)->where('uid',$uid)->find();
  165. if(!$couponInfo) return self::setErrorInfo('选择的优惠劵无效!');
  166. if($couponInfo['use_min_price'] > $payPrice)
  167. return self::setErrorInfo('不满足优惠劵的使用条件!');
  168. $payPrice = (float)bcsub($payPrice,$couponInfo['coupon_price'],2);
  169. $res1 = StoreCouponUser::useCoupon($couponId);
  170. $couponPrice = $couponInfo['coupon_price'];
  171. }else{
  172. $couponId = 0;
  173. $couponPrice = 0;
  174. }
  175. if(!$res1) return self::setErrorInfo('使用优惠劵失败!');
  176. //是否包邮
  177. if((isset($other['offlinePostage']) && $other['offlinePostage'] && $payType == 'offline')) $payPostage = 0;
  178. $payPrice = (float)bcadd($payPrice,$payPostage,2);
  179. //积分抵扣
  180. $res2 = true;
  181. if($useIntegral && $userInfo['integral'] > 0){
  182. $deductionPrice = (float)bcmul($userInfo['integral'],$other['integralRatio'],2);
  183. if($deductionPrice < $payPrice){
  184. $payPrice = bcsub($payPrice,$deductionPrice,2);
  185. $usedIntegral = $userInfo['integral'];
  186. $res2 = false !== User::edit(['integral'=>0],$userInfo['uid'],'uid');
  187. }else{
  188. $deductionPrice = $payPrice;
  189. $usedIntegral = (float)bcdiv($payPrice,$other['integralRatio'],2);
  190. $res2 = false !== User::bcDec($userInfo['uid'],'integral',$usedIntegral,'uid');
  191. $payPrice = 0;
  192. }
  193. $res2 = $res2 && false != UserBill::expend('积分抵扣',$uid,'integral','deduction',$usedIntegral,$key,$userInfo['integral'],'购买商品使用'.floatval($usedIntegral).'积分抵扣'.floatval($deductionPrice).'元');
  194. }else{
  195. $deductionPrice = 0;
  196. $usedIntegral = 0;
  197. }
  198. if(!$res2) return self::setErrorInfo('使用积分抵扣失败!');
  199. $cartIds = [];
  200. $totalNum = 0;
  201. $gainIntegral = 0;
  202. foreach ($cartInfo as $cart){
  203. $cartIds[] = $cart['id'];
  204. $totalNum += $cart['cart_num'];
  205. $gainIntegral = bcadd($gainIntegral,isset($cart['productInfo']['give_integral']) ? $cart['productInfo']['give_integral'] : 0,2);
  206. }
  207. $orderInfo = [
  208. 'uid'=>$uid,
  209. 'order_id'=>self::getNewOrderId(),
  210. 'real_name'=>$addressInfo['real_name'],
  211. 'user_phone'=>$addressInfo['phone'],
  212. 'user_address'=>$addressInfo['province'].' '.$addressInfo['city'].' '.$addressInfo['district'].' '.$addressInfo['detail'],
  213. 'cart_id'=>$cartIds,
  214. 'total_num'=>$totalNum,
  215. 'total_price'=>$priceGroup['totalPrice'],
  216. 'total_postage'=>$priceGroup['storePostage'],
  217. 'coupon_id'=>$couponId,
  218. 'coupon_price'=>$couponPrice,
  219. 'pay_price'=>$payPrice,
  220. 'pay_postage'=>$payPostage,
  221. 'deduction_price'=>$deductionPrice,
  222. 'paid'=>0,
  223. 'pay_type'=>$payType,
  224. 'use_integral'=>$usedIntegral,
  225. 'gain_integral'=>$gainIntegral,
  226. 'mark'=>htmlspecialchars($mark),
  227. 'combination_id'=>$combinationId,
  228. 'pink_id'=>$pinkId,
  229. 'seckill_id'=>$seckill_id,
  230. 'bargain_id'=>$bargain_id,
  231. 'cost'=>$priceGroup['costPrice'],
  232. 'is_channel'=>1,
  233. 'unique'=>$key
  234. ];
  235. $order = self::set($orderInfo);
  236. if(!$order)return self::setErrorInfo('订单生成失败!');
  237. $res5 = true;
  238. //保存购物车商品信息
  239. $res4 = false !== StoreOrderCartInfo::setCartInfo($order['id'],$cartInfo);
  240. //购物车状态修改
  241. $res6 = false !== StoreCart::where('id','IN',$cartIds)->update(['is_pay'=>1]);
  242. if(!$res4 || !$res5 || !$res6) return self::setErrorInfo('订单生成失败!');
  243. try{
  244. HookService::listen('store_product_order_create',$order,compact('cartInfo','addressId'),false,GoodsBehavior::class);
  245. }catch (\Exception $e){
  246. return self::setErrorInfo($e->getMessage());
  247. }
  248. self::clearCacheOrderInfo($uid,$key);
  249. self::commitTrans();
  250. StoreOrderStatus::status($order['id'],'cache_key_create_order','订单生成');
  251. return $order;
  252. }
  253. /*
  254. * 回退积分
  255. * @param array $order 订单信息
  256. * @return boolean
  257. * */
  258. public static function RegressionIntegral($order)
  259. {
  260. if($order['paid'] || $order['status']==-2 || $order['is_del']) return false;
  261. if($order['use_integral'] < 0) return true;
  262. if((int)$order['status']!=-2 && (int)$order['refund_status']!=2 && $order['back_integral'] >= $order['use_integral'])
  263. return self::setErrorInfo('已退积分或该状态无法回退积分');
  264. $res=User::bcInc($order['uid'],'integral',$order['use_integral']);
  265. if(!$res) return self::setErrorInfo('回退积分增加失败');
  266. UserBill::income('积分回退',$order['uid'],'integral','deduction',$order['use_integral'],$order['unique'],User::where('uid',$order['uid'])->value('integral'),'购买商品失败,回退积分'.floatval($order['use_integral']));
  267. return self::where('order_id',$order['order_id'])->update(['back_integral'=>$order['use_integral']]);
  268. }
  269. /*
  270. * 回退库存和销量
  271. * @param array $order 订单信息
  272. * @return boolean
  273. * */
  274. public static function RegressionStock($order)
  275. {
  276. if($order['paid'] || $order['status']==-2 || $order['is_del']) return false;
  277. $combinationId=$order['combination_id'];
  278. $seckill_id=$order['seckill_id'];
  279. $bargain_id=$order['bargain_id'];
  280. $res5=true;
  281. $cartInfo=StoreOrderCartInfo::where('cart_id','in',$order['cart_id'])->select();
  282. foreach ($cartInfo as $cart)
  283. {
  284. //增库存减销量
  285. if($combinationId) $res5 = $res5 && StoreCombination::incCombinationStock($cart['cart_info']['cart_num'],$combinationId);
  286. else if($seckill_id) $res5 = $res5 && StoreSeckill::incSeckillStock($cart['cart_info']['cart_num'],$seckill_id);
  287. else if($bargain_id) $res5 = $res5 && StoreBargain::incBargainStock($cart['cart_info']['cart_num'],$bargain_id);
  288. else $res5 = $res5 && StoreProduct::incProductStock($cart['cart_info']['cart_num'],$cart['cart_info']['productInfo']['id'],isset($cart['cart_info']['productInfo']['attrInfo']) ? $cart['cart_info']['productInfo']['attrInfo']['unique']:'');
  289. }
  290. return $res5;
  291. }
  292. /*
  293. * 回退优惠卷
  294. * @param array $order 订单信息
  295. * @return boolean
  296. * */
  297. public static function RegressionCoupon($order)
  298. {
  299. if($order['paid'] || $order['status']==-2 || $order['is_del']) return false;
  300. $res=true;
  301. if($order['coupon_id'] && StoreCouponUser::be(['id'=>$order['coupon_id'],'uid'=>$order['uid'],'status'=>1])){
  302. $res= $res && StoreCouponUser::where(['id'=>$order['coupon_id'],'uid'=>$order['uid']])->update(['status'=>0,'use_time'=>0]);
  303. }
  304. return $res;
  305. }
  306. /*
  307. * 取消订单
  308. * @param string order_id 订单id
  309. * */
  310. public static function cancelOrder($order_id)
  311. {
  312. $order=self::where('order_id',$order_id)->find();
  313. if(!$order) return self::setErrorInfo('没有查到此订单');
  314. self::beginTrans();
  315. try{
  316. $res=self::RegressionIntegral($order) && self::RegressionCoupon($order);
  317. if($res){
  318. $order->is_del=1;
  319. self::commitTrans();
  320. return $order->save();
  321. }
  322. }catch (\Exception $e){
  323. self::rollbackTrans();
  324. return self::setErrorInfo(['line'=>$e->getLine(),'message'=>$e->getMessage()]);
  325. }
  326. }
  327. public static function getNewOrderId()
  328. {
  329. $count = (int) self::where('add_time',['>=',strtotime(date("Y-m-d"))],['<',strtotime(date("Y-m-d",strtotime('+1 day')))])->count();
  330. return 'wx'.date('YmdHis',time()).(10000+$count+1);
  331. }
  332. public static function changeOrderId($orderId)
  333. {
  334. $ymd = substr($orderId,2,8);
  335. $key = substr($orderId,16);
  336. return 'wx'.$ymd.date('His').$key;
  337. }
  338. //TODO JS支付
  339. public static function jsPay($orderId,$field = 'order_id')
  340. {
  341. if(is_string($orderId))
  342. $orderInfo = self::where($field,$orderId)->find();
  343. else
  344. $orderInfo = $orderId;
  345. if(!$orderInfo || !isset($orderInfo['paid'])) exception('支付订单不存在!');
  346. if($orderInfo['paid']) exception('支付已支付!');
  347. if($orderInfo['pay_price'] <= 0) exception('该支付无需支付!');
  348. $openid = WechatUser::getOpenId($orderInfo['uid']);
  349. return MiniProgramService::jsPay($openid,$orderInfo['order_id'],$orderInfo['pay_price'],'productr',SystemConfigService::get('site_name'));
  350. }
  351. //TODO 余额支付
  352. public static function yuePay($order_id,$uid,$formId = '')
  353. {
  354. $orderInfo = self::where('uid',$uid)->where('order_id',$order_id)->where('is_del',0)->find();
  355. if(!$orderInfo) return self::setErrorInfo('订单不存在!');
  356. if($orderInfo['paid']) return self::setErrorInfo('该订单已支付!');
  357. // if($orderInfo['pay_type'] != 'yue') return self::setErrorInfo('该订单不能使用余额支付!');
  358. $userInfo = User::getUserInfo($uid);
  359. if($userInfo['now_money'] < $orderInfo['pay_price'])
  360. return self::setErrorInfo(['status'=>'pay_deficiency','msg'=>'余额不足'.floatval($orderInfo['pay_price'])]);
  361. self::beginTrans();
  362. $res1 = false !== User::bcDec($uid,'now_money',$orderInfo['pay_price'],'uid');
  363. $res2 = UserBill::expend('购买商品',$uid,'now_money','pay_product',$orderInfo['pay_price'],$orderInfo['id'],$userInfo['now_money'],'余额支付'.floatval($orderInfo['pay_price']).'元购买商品');
  364. $res3 = self::paySuccess($order_id,'yue',$formId);//余额支付成功
  365. try{
  366. HookService::listen('yue_pay_product',$userInfo,$orderInfo,false,PaymentBehavior::class);
  367. }catch (\Exception $e){
  368. self::rollbackTrans();
  369. return self::setErrorInfo($e->getMessage());
  370. }
  371. $res = $res1 && $res2 && $res3;
  372. self::checkTrans($res);
  373. return $res;
  374. }
  375. /**
  376. * 微信支付 为 0元时
  377. * @param $order_id
  378. * @param $uid
  379. * @return bool
  380. */
  381. public static function jsPayPrice($order_id,$uid,$formId = ''){
  382. $orderInfo = self::where('uid',$uid)->where('order_id',$order_id)->where('is_del',0)->find();
  383. if(!$orderInfo) return self::setErrorInfo('订单不存在!');
  384. if($orderInfo['paid']) return self::setErrorInfo('该订单已支付!');
  385. $userInfo = User::getUserInfo($uid);
  386. self::beginTrans();
  387. $res1 = UserBill::expend('购买商品',$uid,'now_money','pay_product',$orderInfo['pay_price'],$orderInfo['id'],$userInfo['now_money'],'微信支付'.floatval($orderInfo['pay_price']).'元购买商品');
  388. $res2 = self::paySuccess($order_id,'weixin',$formId);//微信支付为0时
  389. $res = $res1 && $res2;
  390. self::checkTrans($res);
  391. return $res;
  392. }
  393. /**
  394. * 用户申请退款
  395. * @param $uni
  396. * @param $uid
  397. * @param string $refundReasonWap
  398. * @return bool
  399. */
  400. public static function orderApplyRefund($uni, $uid,$refundReasonWap = '',$refundReasonWapExplain = '',$refundReasonWapImg = array())
  401. {
  402. $order = self::getUserOrderDetail($uid,$uni);
  403. if(!$order) return self::setErrorInfo('支付订单不存在!');
  404. if($order['refund_status'] == 2) return self::setErrorInfo('订单已退款!');
  405. if($order['refund_status'] == 1) return self::setErrorInfo('正在申请退款中!');
  406. if($order['status'] == 1) return self::setErrorInfo('订单当前无法退款!');
  407. self::beginTrans();
  408. $res1 = false !== StoreOrderStatus::status($order['id'],'apply_refund','用户申请退款,原因:'.$refundReasonWap);
  409. $res2 = false !== self::edit(['refund_status'=>1,'refund_reason_time'=>time(),'refund_reason_wap'=>$refundReasonWap,'refund_reason_wap_explain'=>$refundReasonWapExplain,'refund_reason_wap_img'=>json_encode($refundReasonWapImg)],$order['id'],'id');
  410. $res = $res1 && $res2;
  411. self::checkTrans($res);
  412. if(!$res)
  413. return self::setErrorInfo('申请退款失败!');
  414. else{
  415. $adminIds = SystemConfigService::get('site_store_admin_uids');
  416. if(!empty($adminIds)){
  417. try{
  418. if(!($adminList = array_unique(array_filter(explode(',',trim($adminIds)))))){
  419. self::setErrorInfo('申请退款成功,');
  420. return false;
  421. }
  422. RoutineTemplate::sendOrderRefundStatus($order,$refundReasonWap,$adminList);//小程序 发送模板消息
  423. }catch (\Exception $e){}
  424. }
  425. return true;
  426. }
  427. }
  428. /**
  429. * //TODO 支付成功后
  430. * @param $orderId
  431. * @param $paytype
  432. * @param $notify
  433. * @return bool
  434. */
  435. public static function paySuccess($orderId,$paytype='weixin',$formId = '')
  436. {
  437. $order = self::where('order_id',$orderId)->find();
  438. $resPink = true;
  439. $res1 = self::where('order_id',$orderId)->update(['paid'=>1,'pay_type'=>$paytype,'pay_time'=>time()]);//订单改为支付
  440. $cartInfo = self::getDb('StoreOrderCartInfo')->where('oid', $order['id'])->column('cart_info', 'unique') ?: [];
  441. foreach ($cartInfo as $k => &$cart) $cart = json_decode($cart, true);
  442. $res2 = true;
  443. foreach ($cartInfo as $k => &$cart) { //减库存加销量
  444. if ($cart['combination_id']) $res2 = $res2 && StoreCombination::decCombinationStock($cart['cart_num'], $cart['combination_id']);
  445. else if ($cart['seckill_id']) $res2 = $res2 && StoreSeckill::decSeckillStock($cart['cart_num'], $cart['seckill_id']);
  446. else if ($cart['bargain_id']) $res2 = $res2 && StoreBargain::decBargainStock($cart['cart_num'], $cart['bargain_id']);
  447. else $res2 = $res2 && StoreProduct::decProductStock($cart['cart_num'], $cart['productInfo']['id'], isset($cart['productInfo']['attrInfo']) ? $cart['productInfo']['attrInfo']['unique'] : '');
  448. }
  449. User::bcInc($order['uid'],'pay_count',1,'uid');
  450. if($order->combination_id && $res1 && !$order->refund_status) $resPink = StorePink::createPink($order);//创建拼团
  451. $oid = self::where('order_id',$orderId)->value('id');
  452. StoreOrderStatus::status($oid,'pay_success','用户付款成功');
  453. RoutineTemplate::sendOrderSuccess($formId,$orderId);
  454. HookService::afterListen('user_level',User::where('uid',$order['uid'])->find(),false,UserBehavior::class);
  455. $res = $res1 && $resPink;
  456. return false !== $res;
  457. }
  458. /*
  459. * 线下支付消息通知
  460. * 待完善
  461. *
  462. * */
  463. public static function createOrderTemplate($order)
  464. {
  465. //$goodsName = StoreOrderCartInfo::getProductNameList($order['id']);
  466. // RoutineTemplateService::sendTemplate(WechatUser::getOpenId($order['uid']),RoutineTemplateService::ORDER_CREATE, [
  467. // 'first'=>'亲,您购买的商品已支付成功',
  468. // 'keyword1'=>date('Y/m/d H:i',$order['add_time']),
  469. // 'keyword2'=>implode(',',$goodsName),
  470. // 'keyword3'=>$order['order_id'],
  471. // 'remark'=>'点击查看订单详情'
  472. // ],Url::build('/wap/My/order',['uni'=>$order['order_id']],true,true));
  473. // RoutineTemplateService::sendAdminNoticeTemplate([
  474. // 'first'=>"亲,您有一个新订单 \n订单号:{$order['order_id']}",
  475. // 'keyword1'=>'新订单',
  476. // 'keyword2'=>'线下支付',
  477. // 'keyword3'=>date('Y/m/d H:i',time()),
  478. // 'remark'=>'请及时处理'
  479. // ]);
  480. }
  481. public static function getUserOrderDetail($uid,$key)
  482. {
  483. return self::where('order_id|unique',$key)->where('uid',$uid)->where('is_del',0)->find();
  484. }
  485. /**
  486. * TODO 订单发货
  487. * @param array $postageData 发货信息
  488. * @param string $oid orderID
  489. */
  490. public static function orderPostageAfter($postageData, $oid)
  491. {
  492. $order = self::where('id',$oid)->find();
  493. $url ='/pages/order_details/index?order_id='.$order['order_id'];
  494. $group = [
  495. 'first'=>'亲,您的订单已发货,请注意查收',
  496. 'remark'=>'点击查看订单详情'
  497. ];
  498. if($postageData['delivery_type'] == 'send'){//送货
  499. $goodsName = StoreOrderCartInfo::getProductNameList($order['id']);
  500. $group = array_merge($group,[
  501. 'keyword1'=>$goodsName,
  502. 'keyword2'=>$order['pay_type'] == 'offline' ? '线下支付' : date('Y/m/d H:i',$order['pay_time']),
  503. 'keyword3'=>$order['user_address'],
  504. 'keyword4'=>$postageData['delivery_name'],
  505. 'keyword5'=>$postageData['delivery_id']
  506. ]);
  507. RoutineTemplate::sendOut('ORDER_DELIVER_SUCCESS',$order['uid'],$group,$url);
  508. }else if($postageData['delivery_type'] == 'express'){//发货
  509. $group = array_merge($group,[
  510. 'keyword1'=>$order['order_id'],
  511. 'keyword2'=>$postageData['delivery_name'],
  512. 'keyword3'=>$postageData['delivery_id']
  513. ]);
  514. RoutineTemplate::sendOut('ORDER_POSTAGE_SUCCESS',$order['uid'],$group,$url);
  515. }
  516. }
  517. public static function orderTakeAfter($order)
  518. {
  519. // $openid = WechatUser::getOpenId($order['uid']);
  520. // RoutineTemplateService::sendTemplate($openid,RoutineTemplateService::ORDER_TAKE_SUCCESS,[
  521. // 'first'=>'亲,您的订单已成功签收,快去评价一下吧',
  522. // 'keyword1'=>$order['order_id'],
  523. // 'keyword2'=>'已收货',
  524. // 'keyword3'=>date('Y/m/d H:i',time()),
  525. // 'keyword4'=>implode(',',StoreOrderCartInfo::getProductNameList($order['id'])),
  526. // 'remark'=>'点击查看订单详情'
  527. // ],Url::build('My/order',['uni'=>$order['order_id']],true,true));
  528. }
  529. /**
  530. * 删除订单
  531. * @param $uni
  532. * @param $uid
  533. * @return bool
  534. */
  535. public static function removeOrder($uni, $uid)
  536. {
  537. $order = self::getUserOrderDetail($uid,$uni);
  538. if(!$order) return self::setErrorInfo('订单不存在!');
  539. $order = self::tidyOrder($order);
  540. if($order['_status']['_type'] != 0 && $order['_status']['_type']!= -2 && $order['_status']['_type'] != 4)
  541. return self::setErrorInfo('该订单无法删除!');
  542. if(false !== self::edit(['is_del'=>1],$order['id'],'id') && false !==StoreOrderStatus::status($order['id'],'remove_order','删除订单')) {
  543. //未支付和已退款的状态下才可以退积分退库存退优惠券
  544. if($order['_status']['_type']== 0 || $order['_status']['_type']== -2) {
  545. HookService::afterListen('store_order_regression_all',$order,null,false,OrderBehavior::class);
  546. }
  547. return true;
  548. }else
  549. return self::setErrorInfo('订单删除失败!');
  550. }
  551. /**
  552. * //TODO 用户确认收货
  553. * @param $uni
  554. * @param $uid
  555. */
  556. public static function takeOrder($uni, $uid)
  557. {
  558. $order = self::getUserOrderDetail($uid,$uni);
  559. if(!$order) return self::setErrorInfo('订单不存在!');
  560. $order = self::tidyOrder($order);
  561. if($order['_status']['_type'] != 2) return self::setErrorInfo('订单状态错误!');
  562. self::beginTrans();
  563. if(false !== self::edit(['status'=>2],$order['id'],'id') &&
  564. false !== StoreOrderStatus::status($order['id'],'user_take_delivery','用户已收货')){
  565. try{
  566. HookService::listen('store_product_order_user_take_delivery',$order,$uid,false,GoodsBehavior::class);
  567. }catch (\Exception $e){
  568. return self::setErrorInfo($e->getMessage());
  569. }
  570. self::commitTrans();
  571. return true;
  572. }else{
  573. self::rollbackTrans();
  574. return false;
  575. }
  576. }
  577. public static function tidyOrder($order,$detail = false,$isPic=false)
  578. {
  579. if($detail == true && isset($order['id'])){
  580. $cartInfo = self::getDb('StoreOrderCartInfo')->where('oid',$order['id'])->column('cart_info','unique')?:[];
  581. $info=[];
  582. foreach ($cartInfo as $k=>$cart){
  583. $cart=json_decode($cart, true);
  584. $cart['unique']=$k;
  585. //新增是否评价字段
  586. $cart['is_reply'] = self::getDb('store_product_reply')->where('unique',$k)->count();
  587. array_push($info,$cart);
  588. unset($cart);
  589. }
  590. $order['cartInfo'] = $info;
  591. }
  592. $status = [];
  593. if(!$order['paid'] && $order['pay_type'] == 'offline' && !$order['status'] >= 2){
  594. $status['_type'] = 9;
  595. $status['_title'] = '线下付款';
  596. $status['_msg'] = '等待商家处理,请耐心等待';
  597. $status['_class'] = 'nobuy';
  598. }else if(!$order['paid']){
  599. $status['_type'] = 0;
  600. $status['_title'] = '未支付';
  601. $status['_msg'] = '立即支付订单吧';
  602. $status['_class'] = 'nobuy';
  603. }else if($order['refund_status'] == 1){
  604. $status['_type'] = -1;
  605. $status['_title'] = '申请退款中';
  606. $status['_msg'] = '商家审核中,请耐心等待';
  607. $status['_class'] = 'state-sqtk';
  608. }else if($order['refund_status'] == 2){
  609. $status['_type'] = -2;
  610. $status['_title'] = '已退款';
  611. $status['_msg'] = '已为您退款,感谢您的支持';
  612. $status['_class'] = 'state-sqtk';
  613. }else if(!$order['status']){
  614. if($order['pink_id']){
  615. if(StorePink::where('id',$order['pink_id'])->where('status',1)->count()){
  616. $status['_type'] = 1;
  617. $status['_title'] = '拼团中';
  618. $status['_msg'] = '等待其他人参加拼团';
  619. $status['_class'] = 'state-nfh';
  620. }else{
  621. $status['_type'] = 1;
  622. $status['_title'] = '未发货';
  623. $status['_msg'] = '商家未发货,请耐心等待';
  624. $status['_class'] = 'state-nfh';
  625. }
  626. }else{
  627. $status['_type'] = 1;
  628. $status['_title'] = '未发货';
  629. $status['_msg'] = '商家未发货,请耐心等待';
  630. $status['_class'] = 'state-nfh';
  631. }
  632. }else if($order['status'] == 1){
  633. $status['_type'] = 2;
  634. $status['_title'] = '待收货';
  635. $status['_msg'] = date('m月d日H时i分',StoreOrderStatus::getTime($order['id'],'delivery_goods')).'服务商已发货';
  636. $status['_class'] = 'state-ysh';
  637. }else if($order['status'] == 2){
  638. $status['_type'] = 3;
  639. $status['_title'] = '待评价';
  640. $status['_msg'] = '已收货,快去评价一下吧';
  641. $status['_class'] = 'state-ypj';
  642. }else if($order['status'] == 3){
  643. $status['_type'] = 4;
  644. $status['_title'] = '交易完成';
  645. $status['_msg'] = '交易完成,感谢您的支持';
  646. $status['_class'] = 'state-ytk';
  647. }
  648. if(isset($order['pay_type']))
  649. $status['_payType'] = isset(self::$payType[$order['pay_type']]) ? self::$payType[$order['pay_type']] : '其他方式';
  650. if(isset($order['delivery_type']))
  651. $status['_deliveryType'] = isset(self::$deliveryType[$order['delivery_type']]) ? self::$deliveryType[$order['delivery_type']] : '其他方式';
  652. $order['_status'] = $status;
  653. $order['_pay_time']=isset($order['pay_time']) && $order['pay_time'] != null ? date('Y-m-d H:i:s',$order['pay_time']) : date('Y-m-d H:i:s',$order['add_time']);
  654. $order['_add_time']=isset($order['add_time']) ? (strstr($order['add_time'],'-')===false ? date('Y-m-d H:i:s',$order['add_time']) : $order['add_time'] ): '';
  655. $order['status_pic']='';
  656. //获取产品状态图片
  657. if($isPic){
  658. $order_details_images=\app\core\util\GroupDataService::getData('order_details_images') ? : [];
  659. foreach ($order_details_images as $image){
  660. if(isset($image['order_status']) && $image['order_status']==$order['_status']['_type']){
  661. $order['status_pic']=$image['pic'];
  662. break;
  663. }
  664. }
  665. }
  666. return $order;
  667. }
  668. public static function statusByWhere($status,$uid=0,$model = null)
  669. {
  670. // $orderId = StorePink::where('uid',$uid)->where('status',1)->column('order_id','id');//获取正在拼团的订单编号
  671. if($model == null) $model = new self;
  672. if('' === $status)
  673. return $model;
  674. else if($status == 0)
  675. return $model->where('paid',0)->where('status',0)->where('refund_status',0);
  676. else if($status == 1)//待发货
  677. return $model->where('paid',1)->where('status',0)->where('refund_status',0);
  678. else if($status == 2)
  679. return $model->where('paid',1)->where('status',1)->where('refund_status',0);
  680. else if($status == 3)
  681. return $model->where('paid',1)->where('status',2)->where('refund_status',0);
  682. else if($status == 4)
  683. return $model->where('paid',1)->where('status',3)->where('refund_status',0);
  684. else if($status == -1)
  685. return $model->where('paid',1)->where('refund_status',1);
  686. else if($status == -2)
  687. return $model->where('paid',1)->where('refund_status',2);
  688. else if($status == -3)
  689. return $model->where('paid',1)->where('refund_status','IN','1,2');
  690. // else if($status == 11){
  691. // return $model->where('order_id','IN',implode(',',$orderId));
  692. // }
  693. else
  694. return $model;
  695. }
  696. public static function getUserOrderList($uid,$status = '',$page = 0,$limit = 8)
  697. {
  698. $list = self::statusByWhere($status,$uid)->where('is_del',0)->where('uid',$uid)
  699. ->field('add_time,seckill_id,bargain_id,combination_id,id,order_id,pay_price,total_num,total_price,pay_postage,total_postage,paid,status,refund_status,pay_type,coupon_price,deduction_price,pink_id,delivery_type')
  700. ->order('add_time DESC')->page((int)$page,(int)$limit)->select()->toArray();
  701. foreach ($list as $k=>$order){
  702. $list[$k] = self::tidyOrder($order,true);
  703. }
  704. return $list;
  705. }
  706. /**
  707. * 获取推广人地下用户的订单金额
  708. * @param string $uid
  709. * @param string $status
  710. * @return array
  711. */
  712. public static function getUserOrderCount($uid = '',$status = ''){
  713. $res = self::statusByWhere($status,$uid)->where('uid','IN',$uid)->column('pay_price');
  714. return $res;
  715. }
  716. public static function searchUserOrder($uid,$order_id)
  717. {
  718. $order = self::where('uid',$uid)->where('order_id',$order_id)->where('is_del',0)->field('seckill_id,bargain_id,combination_id,id,order_id,pay_price,total_num,total_price,pay_postage,total_postage,paid,status,refund_status,pay_type,coupon_price,deduction_price,delivery_type')
  719. ->order('add_time DESC')->find();
  720. if(!$order)
  721. return false;
  722. else
  723. return self::tidyOrder($order->toArray(),true);
  724. }
  725. public static function orderOver($oid)
  726. {
  727. $res = self::edit(['status'=>'3'],$oid,'id');
  728. if(!$res) exception('评价后置操作失败!');
  729. StoreOrderStatus::status($oid,'check_order_over','用户评价');
  730. }
  731. public static function checkOrderOver($oid)
  732. {
  733. $uniqueList = StoreOrderCartInfo::where('oid',$oid)->column('unique');
  734. if(StoreProductReply::where('unique','IN',$uniqueList)->where('oid',$oid)->count() == count($uniqueList)){
  735. HookService::listen('store_product_order_over',$oid,null,false,GoodsBehavior::class);
  736. self::orderOver($oid);
  737. }
  738. }
  739. public static function getOrderStatusNum($uid)
  740. {
  741. $noBuy = self::where('uid',$uid)->where('paid',0)->where('is_del',0)->where('pay_type','<>','offline')->count();
  742. $noPostageNoPink = self::where('o.uid',$uid)->alias('o')->where('o.paid',1)->where('o.pink_id',0)->where('o.is_del',0)->where('o.status',0)->where('o.pay_type','<>','offline')->count();
  743. $noPostageYesPink = self::where('o.uid',$uid)->alias('o')->join('StorePink p','o.pink_id = p.id')->where('p.status',2)->where('o.paid',1)->where('o.is_del',0)->where('o.status',0)->where('o.pay_type','<>','offline')->count();
  744. $noPostage = bcadd($noPostageNoPink,$noPostageYesPink);
  745. $noTake = self::where('uid',$uid)->where('paid',1)->where('is_del',0)->where('status',1)->where('pay_type','<>','offline')->count();
  746. $noReply = self::where('uid',$uid)->where('paid',1)->where('is_del',0)->where('status',2)->count();
  747. $noPink = self::where('o.uid',$uid)->alias('o')->join('StorePink p','o.pink_id = p.id')->where('p.status',1)->where('o.paid',1)->where('o.is_del',0)->where('o.status',0)->where('o.pay_type','<>','offline')->count();
  748. $noRefund = self::where('uid',$uid)->where('paid',1)->where('is_del',0)->where('refund_status','IN','1,2')->count();
  749. return compact('noBuy','noPostage','noTake','noReply','noPink','noRefund');
  750. }
  751. public static function gainUserIntegral($order)
  752. {
  753. if($order['gain_integral'] > 0){
  754. $userInfo = User::getUserInfo($order['uid']);
  755. ModelBasic::beginTrans();
  756. $res1 = false != User::where('uid',$userInfo['uid'])->update(['integral'=>bcadd($userInfo['integral'],$order['gain_integral'],2)]);
  757. $res2 = false != UserBill::income('购买商品赠送积分',$order['uid'],'integral','gain',$order['gain_integral'],$order['id'],$userInfo['integral'],'购买商品赠送'.floatval($order['gain_integral']).'积分');
  758. $res = $res1 && $res2;
  759. ModelBasic::checkTrans($res);
  760. return $res;
  761. }
  762. return true;
  763. }
  764. /**
  765. * 获取当前订单中有没有拼团存在
  766. * @param $pid
  767. * @return int|string
  768. */
  769. public static function getIsOrderPink($pid = 0 ,$uid = 0){
  770. return self::where('uid',$uid)->where('pink_id',$pid)->where('refund_status',0)->where('is_del',0)->count();
  771. }
  772. /**
  773. * 获取order_id
  774. * @param $pid
  775. * @return mixed
  776. */
  777. public static function getStoreIdPink($pid = 0 ,$uid = 0){
  778. return self::where('uid',$uid)->where('pink_id',$pid)->where('is_del',0)->value('order_id');
  779. }
  780. /**
  781. * 删除当前用户拼团未支付的订单
  782. */
  783. public static function delCombination(){
  784. self::where('combination','GT',0)->where('paid',0)->where('uid',User::getActiveUid())->delete();
  785. }
  786. public static function getUserPrice($uid =0){
  787. if(!$uid) return 0;
  788. $price = self::where('paid',1)->where('uid',$uid)->where('status',2)->where('refund_status',0)->column('pay_price','id');
  789. $count = 0;
  790. if($price){
  791. foreach ($price as $v){
  792. $count = bcadd($count,$v,2);
  793. }
  794. }
  795. return $count;
  796. }
  797. /*
  798. * 个人中心获取个人订单列表和订单搜索
  799. * @param int $uid 用户uid
  800. * @param int | string 查找订单类型
  801. * @param int $first 分页
  802. * @param int 每页显示多少条
  803. * @param string $search 订单号
  804. * @return array
  805. * */
  806. public static function getUserOrderSearchList($uid,$type,$page,$limit,$search)
  807. {
  808. if($search){
  809. $order = self::searchUserOrder($uid,$search)?:[];
  810. $list = $order == false ? [] : [$order];
  811. }else{
  812. $list = self::getUserOrderList($uid,$type,$page,$limit);
  813. }
  814. foreach ($list as $k=>$order){
  815. $list[$k] = self::tidyOrder($order,true);
  816. if($list[$k]['_status']['_type'] == 3){
  817. foreach ($order['cartInfo']?:[] as $key=>$product){
  818. $list[$k]['cartInfo'][$key]['is_reply'] = StoreProductReply::isReply($product['unique'],'product');
  819. $list[$k]['cartInfo'][$key]['add_time'] = date('Y-m-d H:i',$product['add_time']);
  820. }
  821. }
  822. }
  823. return $list;
  824. }
  825. /*
  826. * 获取用户下级的订单
  827. * @param int $xuid 下级用户用户uid
  828. * @param int $uid 用户uid
  829. * @param int $type 订单类型
  830. * @param int $first 截取行数
  831. * @param int $limit 展示条数
  832. * @return array
  833. * */
  834. public static function getSubordinateOrderlist($xUid,$uid,$type,$first,$limit)
  835. {
  836. $list = [];
  837. if(!$xUid){
  838. $arr = User::getOneSpreadUid($uid);
  839. foreach($arr as $v) $list = StoreOrder::getUserOrderList($v,$type,$first,$limit);
  840. }else $list = self::getUserOrderList($xUid,$type,$first,$limit);
  841. foreach ($list as $k=>$order){
  842. $list[$k] = self::tidyOrder($order,true);
  843. if($list[$k]['_status']['_type'] == 3){
  844. foreach ($order['cartInfo']?:[] as $key=>$product){
  845. $list[$k]['cartInfo'][$key]['is_reply'] = StoreProductReply::isReply($product['unique'],'product');
  846. }
  847. }
  848. }
  849. return $list;
  850. }
  851. /*
  852. * 获取某个用户的订单统计数据
  853. * @param int $uid 用户uid
  854. * */
  855. public static function getOrderData($uid)
  856. {
  857. $data['order_count']=self::where(['is_del'=>0,'paid'=>1,'uid'=>$uid,'refund_status'=>0])->count();
  858. $data['sum_price']=self::where(['is_del'=>0,'paid'=>1,'uid'=>$uid,'refund_status'=>0])->sum('pay_price');
  859. $data['unpaid_count']=self::statusByWhere(0,$uid)->where('is_del',0)->where('uid',$uid)->count();
  860. $data['unshipped_count']=self::statusByWhere(1,$uid)->where('is_del',0)->where('uid',$uid)->count();
  861. $data['received_count']=self::statusByWhere(2,$uid)->where('is_del',0)->where('uid',$uid)->count();
  862. $data['evaluated_count']=self::statusByWhere(3,$uid)->where('is_del',0)->where('uid',$uid)->count();
  863. $data['complete_count']=self::statusByWhere(4,$uid)->where('is_del',0)->where('uid',$uid)->count();
  864. return $data;
  865. }
  866. /*
  867. * 累计消费
  868. * **/
  869. public static function getOrderStatusSum($uid)
  870. {
  871. return self::where(['uid'=>$uid,'is_del'=>0,'paid'=>1])->sum('pay_price');
  872. }
  873. public static function getPinkOrderId($id){
  874. return self::where('id',$id)->value('order_id');
  875. }
  876. }