OrderLogic.php 84 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189
  1. <?php
  2. namespace app\api\logic;
  3. use app\common\basics\Logic;
  4. use app\common\enum\ClientEnum;
  5. use app\common\enum\FootprintEnum;
  6. use app\common\enum\FreightEnum;
  7. use app\common\enum\GoodsEnum;
  8. use app\common\enum\OrderEnum;
  9. use app\common\enum\OrderGoodsEnum;
  10. use app\common\enum\OrderInvoiceEnum;
  11. use app\common\enum\OrderLogEnum;
  12. use app\common\enum\PayEnum;
  13. use app\common\enum\ShopEnum;
  14. use app\common\enum\TeamEnum;
  15. use app\common\logic\OrderLogLogic;
  16. use app\common\logic\OrderRefundLogic;
  17. use app\common\model\Cart;
  18. use app\common\model\dev\DevRegion;
  19. use app\common\model\Freight;
  20. use app\common\model\goods\Goods;
  21. use app\common\model\Delivery;
  22. use app\common\model\goods\GoodsItem;
  23. use app\common\model\integral\IntegralOrder;
  24. use app\common\model\order\Order;
  25. use app\common\model\order\OrderGoods;
  26. use app\common\model\order\OrderLog;
  27. use app\common\model\order\OrderRefund;
  28. use app\common\model\order\OrderTrade;
  29. use app\common\model\Pay;
  30. use app\common\model\RechargeOrder;
  31. use app\common\model\shop\Shop;
  32. use app\common\model\coupon\Coupon;
  33. use app\common\model\coupon\CouponList;
  34. use app\common\model\team\TeamFound;
  35. use app\common\model\team\TeamJoin;
  36. use app\common\model\user\User;
  37. use app\common\model\user\UserLevel;
  38. use app\common\server\UrlServer;
  39. use app\common\model\seckill\SeckillGoods;
  40. use app\common\model\bargain\BargainLaunch;
  41. use app\common\model\user\UserAddress;
  42. use app\common\server\AreaServer;
  43. use app\common\server\ConfigServer;
  44. use app\common\server\JsonServer;
  45. use expressage\Kd100;
  46. use expressage\Kdniao;
  47. use think\Exception;
  48. use think\facade\Db;
  49. use think\facade\Env;
  50. /**
  51. * Class OrderLogic
  52. * @package app\api\logic
  53. */
  54. class OrderLogic extends Logic
  55. {
  56. public static $order_type = OrderEnum::NORMAL_ORDER;
  57. /**
  58. * @notes 下单
  59. * @param $post
  60. * @return array|false
  61. * @throws Exception
  62. * @throws \think\db\exception\DataNotFoundException
  63. * @throws \think\db\exception\DbException
  64. * @throws \think\db\exception\ModelNotFoundException
  65. * @throws \think\exception\PDOException
  66. * @author suny
  67. * @date 2021/7/13 6:19 下午
  68. */
  69. public static function add($post)
  70. {
  71. // 商品类型 0普通 1虚拟
  72. $goods_type = input('goods_type/d', GoodsEnum::TYPE_ACTUAL);
  73. // 初始化支付方式
  74. $post['pay_way'] = 0;
  75. if (!empty($post['goods'])) {
  76. $goods = is_array($post['goods']) ? $post['goods'] : json_decode($post['goods'], true);
  77. } else {
  78. $where = [
  79. ['id', 'in', $post['cart_id']]
  80. ];
  81. $goods = Cart::where($where)
  82. ->field(['goods_id', 'item_id', 'shop_id', 'goods_num as num'])
  83. ->select()->toArray();
  84. }
  85. foreach ($goods as &$good) {
  86. $good['delivery_type'] = !isset($good['delivery_type']) ? GoodsEnum::DELIVERY_EXPRESS : $good['delivery_type'];
  87. }
  88. $post['goods'] = $goods;
  89. Db::startTrans();
  90. try {
  91. // 砍价订单验证
  92. if (isset($post['bargain_launch_id']) and $post['bargain_launch_id'] > 0) {
  93. self::$order_type = OrderEnum::BARGAIN_ORDER;
  94. $bargainLaunchModel = new BargainLaunch();
  95. $launch = $bargainLaunchModel->where(['id' => (int)$post['bargain_launch_id']])->find();
  96. if (!$launch) {
  97. throw new Exception('砍价异常');
  98. }
  99. if ($launch['status'] == 2) {
  100. throw new Exception('砍价失败,禁止下单');
  101. }
  102. if ($launch['payment_limit_time'] < time() and $launch['payment_limit_time'] > 0) {
  103. throw new Exception('下单失败,超出限制时间');
  104. }
  105. if ($launch['order_id'] > 0) {
  106. throw new Exception('您已下单了, 请勿重复操作');
  107. }
  108. }
  109. // 校验商品
  110. self::checkGoods($goods);
  111. $address = UserAddress::where('id', $post['address_id'] ?? 0)
  112. ->field('contact,telephone,province_id,city_id,district_id,address')
  113. ->find();
  114. if (empty($address) && $goods_type == GoodsEnum::TYPE_ACTUAL && $post['delivery_type'] == GoodsEnum::DELIVERY_EXPRESS) {
  115. throw new Exception('请选择地址');
  116. }
  117. // 校验发票信息 返回以店铺id为键,原发票参数为值的数组
  118. $invoice = OrderInvoiceLogic::checkOrderInvoice($post);
  119. if (false === $invoice) {
  120. throw new Exception(OrderInvoiceLogic::getError());
  121. }
  122. $order_trade_add = self::addOrderTrade($post, $address);
  123. $shop_goods = [];
  124. $order_goods_datas_insert = [];
  125. $order_log_datas_insert = [];
  126. foreach ($post['goods'] as $key => $value) { //按店铺区分商品
  127. $res = self::checkShop($value); //判断商家营业状态
  128. if ($res !== true) {
  129. throw new Exception($res);
  130. }
  131. $shop_goods[$value['shop_id']][] = $value;
  132. }
  133. foreach ($shop_goods as $key => $value) {
  134. foreach ($value as $val) {
  135. $seckill_goods_price = GoodsItem::isSeckill($val['item_id']);
  136. if ($seckill_goods_price != 0) {//是秒杀商品
  137. $sales_sum_res = self::setSeckillSaleSum($val['item_id'], $val['num']);
  138. if ($sales_sum_res !== true) {
  139. throw new Exception('秒杀商品销量设置失败');
  140. }
  141. }
  142. }
  143. $order_add = self::addOrder($order_trade_add, $value, $post, $key, $address);
  144. // 增加发票
  145. OrderInvoiceLogic::insertOrderInvoice($key, $post['user_id'], $order_add, $invoice);
  146. $order_log_add_data = self::getOrderLogData($key, $post['user_id'], $key);
  147. $order_log_datas_insert[] = $order_log_add_data;
  148. $order_goods_data = self::getOrderGoodsData($order_add, $value,$post['user_id']);
  149. $order_goods_datas_insert = array_merge($order_goods_datas_insert, $order_goods_data);
  150. }
  151. // 订单日志
  152. OrderLog::insertAll($order_log_datas_insert);
  153. // 订单商品
  154. OrderGoods::insertAll($order_goods_datas_insert);
  155. //商品库存减少
  156. self::subGoodsStock($post['goods']);
  157. //购物车删除
  158. if (isset($post['cart_id']) && $post['cart_id'] != 0) {
  159. self::delCart($post['cart_id']);
  160. }
  161. // 砍价订单处理
  162. if (isset($post['bargain_launch_id']) and $post['bargain_launch_id'] > 0) {
  163. $bargainLaunchModel = new BargainLaunch();
  164. $bargainLaunchModel->where(['id' => (int)$post['bargain_launch_id']])
  165. ->update(['order_id' => $order_add, 'status' => 1]);
  166. }
  167. // 检测包邮活动
  168. $orders = Db::name('order')->where('trade_id', $order_trade_add)->select()->toArray();
  169. foreach($orders as $item) {
  170. // 虚拟商品直接包邮
  171. $is_free = true;
  172. if ($goods_type == GoodsEnum::TYPE_ACTUAL) {
  173. $is_free = self::isFreeShipping($item['shop_id'], $item['goods_price'] - $item['discount_amount'], [
  174. 'province_id' => $item['province'],
  175. 'city_id' => $item['city'],
  176. 'district_id' => $item['district'],
  177. ]);
  178. }
  179. // 符合包邮条件,去邮费
  180. if($is_free) {
  181. Db::name('order')->where('id', $item['id'])->update([
  182. 'order_amount' => $item['order_amount'] - $item['shipping_price'],
  183. 'total_amount' => $item['total_amount'] - $item['shipping_price'],
  184. 'shipping_price' => 0,
  185. ]);
  186. }
  187. }
  188. // 更新主订单金额
  189. $newOrderAmount = Db::name('order')->where('trade_id', $order_trade_add)->sum('order_amount');
  190. $newTotalAmount = Db::name('order')->where('trade_id', $order_trade_add)->sum('total_amount');
  191. Db::name('order_trade')->where('id', $order_trade_add)->update([
  192. 'order_amount' => $newOrderAmount,
  193. 'total_amount' => $newTotalAmount,
  194. ]);
  195. Db::commit();
  196. return ['trade_id' => $order_trade_add, 'order_id' => $order_add, 'type' => 'trade'];
  197. } catch (Exception $e) {
  198. Db::rollback();
  199. self::$error = $e->getMessage();
  200. return false;
  201. }
  202. }
  203. /**
  204. * @notes 结算页数据
  205. * @param $post
  206. * @return array|false
  207. * @throws \think\db\exception\DataNotFoundException
  208. * @throws \think\db\exception\DbException
  209. * @throws \think\db\exception\ModelNotFoundException
  210. * @author suny
  211. * @date 2021/7/13 6:19 下午
  212. */
  213. public static function settlement($post)
  214. {
  215. // 商品类型 0普通 1虚拟
  216. $goods_type = input('goods_type/d', GoodsEnum::TYPE_ACTUAL);
  217. if (!empty($post['goods'])) {
  218. $goods = json_decode($post['goods'], true);
  219. $post['goods'] = $goods;
  220. } else {
  221. $where = [[
  222. 'id', 'in', $post['cart_id']]
  223. ];
  224. $post['goods'] = $goods = Cart::where($where)
  225. ->field(['goods_id', 'item_id', 'shop_id', 'goods_num as num'])
  226. ->select()->toArray();
  227. }
  228. // 检查店铺营业状态
  229. foreach($post['goods'] as $good) {
  230. $shop = Shop::field('name,expire_time,is_run,is_freeze')->where(['del' => 0, 'id' => $good['shop_id']])->findOrEmpty();
  231. if($shop->isEmpty()) {
  232. self::$error = '部分商品所属店铺不存在';
  233. return false;
  234. }
  235. // 获取原始数据(不经获取器)
  236. $shop = $shop->getData();
  237. if(!empty($shop['expire_time']) && ($shop['expire_time'] <= time())) {
  238. self::$error = '部分商品所属店铺已到期';
  239. return false;
  240. }
  241. if($shop['is_freeze']) {
  242. self::$error = '部分商品所属店铺已被冻结';
  243. return false;
  244. }
  245. if(!$shop['is_run']) {
  246. self::$error = '部分商品所属店铺暂停营业中';
  247. return false;
  248. }
  249. if ($good['num'] <= 0) {
  250. self::$error = '商品数量不能小于0';
  251. return false;
  252. }
  253. }
  254. $Goods = new Goods();
  255. $GoodsItem = new GoodsItem();
  256. $Shop = new Shop();
  257. if (isset($post['address_id']) && !empty($post['address_id'])) {
  258. $where = [
  259. 'id' => $post['address_id'],
  260. 'del' => 0,
  261. ];
  262. $address = UserAddress::where($where)
  263. ->field('id,contact,telephone,province_id,city_id,district_id,address')
  264. ->find()->toArray();
  265. } else {
  266. $address = UserAddress::where(['user_id' => $post['user_id'], 'is_default' => 1,'del' => 0])
  267. ->field('id,contact,telephone,province_id,city_id,district_id,address')
  268. ->find();
  269. }
  270. if (!empty($address) && $goods_type == GoodsEnum::TYPE_ACTUAL ) {
  271. $address['province'] = AreaServer::getAddress($address['province_id']);
  272. $address['city'] = AreaServer::getAddress($address['city_id']);
  273. $address['district'] = AreaServer::getAddress($address['district_id']);
  274. } else {
  275. $address = [];
  276. }
  277. // 校验发票信息 返回以店铺id为键,原发票参数为值的数组
  278. $invoice = OrderInvoiceLogic::checkOrderInvoice($post);
  279. if (false === $invoice) {
  280. self::$error = OrderInvoiceLogic::getError();
  281. return false;
  282. }
  283. $shop = [];
  284. foreach ($goods as &$good) {
  285. $goods_item = $GoodsItem->alias('gi')
  286. ->join('goods g', 'g.id = gi.goods_id')
  287. ->where(['gi.id' => $good['item_id'], 'gi.goods_id' => $good['goods_id']])
  288. ->field('gi.price,gi.spec_value_str,gi.image,g.image,g.name as goods_name, g.type as goods_type, g.delivery_type as delivery_types')
  289. ->find()
  290. ->toArray();
  291. $good['type'] = $goods_item['goods_type'];
  292. $good['name'] = $goods_item['goods_name'];
  293. $good['price'] = $goods_item['price'];
  294. $good['original_price'] = $goods_item['price'];
  295. $good['spec_value'] = $goods_item['spec_value_str'];
  296. $good['image'] = empty($goods_item['image']) ? $goods_item['image'] : $goods_item['image'];
  297. $good['image'] = UrlServer::getFileUrl($good['image']);
  298. $good['delivery_types'] = $goods_item['delivery_types'] ? explode(',', $goods_item['delivery_types']) : [];
  299. $good['delivery_type'] = $good['delivery_type'] ?? GoodsEnum::DELIVERY_EXPRESS;
  300. // 配送列表
  301. if ($good['type'] == GoodsEnum::TYPE_VIRTUAL) {
  302. // 虚拟商品, 配送方式为 虚拟发货
  303. $shop[$good['shop_id']]['delivery_types'][] = GoodsEnum::DELIVERY_VIRTUAL;
  304. } else {
  305. // 快递和自提
  306. foreach ($good['delivery_types'] as $ko => $vo) {
  307. $shop[$good['shop_id']]['delivery_types'][] = (int) $vo;
  308. }
  309. }
  310. unset($good['delivery_types']);
  311. }
  312. foreach ($shop as $shop_id => $shops_info) {
  313. $shop[$shop_id]['delivery_types_arr'] = GoodsEnum::getDeliveryLists($shops_info['delivery_types']);
  314. }
  315. foreach ($goods as $key => &$goods_info) {
  316. if (! in_array($goods_info['delivery_type'], $shop[$goods_info['shop_id']]['delivery_types'])) {
  317. $goods_info['delivery_type'] = $shop[$goods_info['shop_id']]['delivery_types_arr'][0]['delivery_type'];
  318. }
  319. $shop[$goods_info['shop_id']]['delivery_type'] = $goods_info['delivery_type'];
  320. $shop[$goods_info['shop_id']]['delivery_type_text'] = GoodsEnum::getDeliveryTypeDesc($goods_info['delivery_type']);
  321. }
  322. foreach ($goods as $key => $value) { //按店铺区分商品
  323. $shop_data = $Shop->where('id', $value['shop_id'])->find();
  324. $shop[$value['shop_id']]['shop_id'] = $value['shop_id'];
  325. $shop[$value['shop_id']]['shop_name'] = $shop_data['name'];
  326. $shop[$value['shop_id']]['open_invoice'] = $shop_data['open_invoice']; // 发票开关
  327. $shop[$value['shop_id']]['spec_invoice'] = $shop_data['spec_invoice']; // 是否支持专票
  328. // 经营信息
  329. $shop[$value['shop_id']]['run_start_time'] = $shop_data['run_start_time'] ? date('H:i:s', $shop_data['run_start_time']) : '';
  330. $shop[$value['shop_id']]['run_end_time'] = $shop_data['run_end_time'] ? date('H:i:s', $shop_data['run_end_time']) : '';
  331. $shop[$value['shop_id']]['weekdays'] = $shop_data['weekdays'];
  332. // 店铺地址
  333. $shop[$value['shop_id']]['province'] = DevRegion::getAreaName($shop_data['province_id']);
  334. $shop[$value['shop_id']]['city'] = DevRegion::getAreaName($shop_data['city_id']);
  335. $shop[$value['shop_id']]['district'] = DevRegion::getAreaName($shop_data['district_id']);
  336. $shop[$value['shop_id']]['address'] = $shop_data['address'];
  337. $array = $post;
  338. $array['shop_id'] = $value['shop_id'];
  339. $shop_coupon_list = CouponLogic::getShopCouponList($array);
  340. $shop[$value['shop_id']]['coupon_list'] = $shop_coupon_list['suit'];
  341. //是否为秒杀
  342. $value['is_seckill'] = 0;
  343. $seckill_goods_price = GoodsItem::isSeckill($value['item_id']);
  344. if ($seckill_goods_price != 0) {
  345. $value['price'] = $seckill_goods_price;
  346. $value['is_seckill'] = 1;
  347. self::$order_type = OrderEnum::SECKILL_ORDER; //秒杀订单
  348. }
  349. // 如果是砍价的商品,则替换信息
  350. if (isset($post['bargain_launch_id']) and $post['bargain_launch_id'] > 0) {
  351. $bargainLaunchModel = new BargainLaunch();
  352. $launch = $bargainLaunchModel->field(true)
  353. ->where(['id' => (int)$post['bargain_launch_id']])
  354. ->find();
  355. $bargainImage = $launch['goods_snap']['image'] == '' ? $launch['goods_snap']['goods_iamge'] : $launch['goods_snap']['image'];
  356. $value['goods_name'] = $launch['goods_snap']['name'];
  357. $value['image_str'] = UrlServer::getFileUrl($bargainImage);
  358. $value['price'] = $launch['current_price'];
  359. $value['spec_value_str'] = $launch['goods_snap']['spec_value_str'];
  360. self::$order_type = OrderEnum::BARGAIN_ORDER;//砍价订单
  361. }
  362. $shop[$value['shop_id']]['goods'][] = $value;
  363. $shop[$value['shop_id']]['shipping_price'] = 0;
  364. if ($shop[$value['shop_id']]['delivery_type'] == GoodsEnum::DELIVERY_EXPRESS) {
  365. $shop[$value['shop_id']]['shipping_price'] = self::calculateFreight($shop[$value['shop_id']]['goods'], $address);
  366. }
  367. $user = User::where('id', $post['user_id'])->find();
  368. $discount = UserLevel::where(['id' => $user['level'],'del' => 0])->value('discount');
  369. // 普通订单才参与会员价
  370. if (self::$order_type == OrderEnum::NORMAL_ORDER) {
  371. if($discount == 0){
  372. $discount = 10;
  373. }
  374. $shop[$value['shop_id']]['total_amount'] = round(self::calculateGoodsPrice($shop[$value['shop_id']]['goods'],$discount) + $shop[$value['shop_id']]['shipping_price'], 2);
  375. } else {
  376. $shop[$value['shop_id']]['total_amount'] = round(round($value['price'] * $value['num'], 2) + $shop[$value['shop_id']]['shipping_price'], 2);
  377. }
  378. //优惠券
  379. $discount_amount = 0;
  380. if (isset($post['coupon_id']) && !empty($post['coupon_id'])) {
  381. $result = self::checkCoupon($post['coupon_id'], $value['shop_id']);
  382. if ($result) {
  383. $discount_amount = self::getDiscountAmount($post['coupon_id'], $value['shop_id'])['money'] ?? 0;
  384. }
  385. }
  386. $shop[$value['shop_id']]['discount_amount'] = $discount_amount;
  387. if ($shop[$value['shop_id']]['total_amount'] > $discount_amount) {
  388. $shop[$value['shop_id']]['total_amount'] = round($shop[$value['shop_id']]['total_amount'] - $discount_amount, 2);
  389. } else { //优惠金额大于当前商品总价,总价为0
  390. $shop[$value['shop_id']]['discount_amount'] = $shop[$value['shop_id']]['total_amount'];
  391. $shop[$value['shop_id']]['total_amount'] = 0;
  392. }
  393. $num = 0;
  394. foreach ($shop[$value['shop_id']]['goods'] as &$item) {
  395. $is_member = Goods::where('id',$item['goods_id'])->value('is_member');
  396. $price_sum = round($item['price'] * $item['num'],2);
  397. // 商品参与会员价 并且订单是 普通订单
  398. if ($is_member && self::$order_type == OrderEnum::NORMAL_ORDER) {
  399. $item['is_member'] = 1;
  400. } else {
  401. $item['is_member'] = 0;
  402. }
  403. if($item['is_member']) {
  404. $member_amount = max(round($item['price']*$discount/10,2), 0.01);
  405. $item['member_amount'] = $member_amount;
  406. $price_sum = round($member_amount * $item['num'],2);
  407. }
  408. $item['sum_price'] = $price_sum;
  409. $num += $item['num'];
  410. }
  411. $shop[$value['shop_id']]['total_num'] = $num;
  412. }
  413. foreach ($shop as $ko => $shop_info) {
  414. unset($shop[$ko]['delivery_types']);
  415. $shop[$ko]['info'] = Shop::where('id', $shop_info['shop_id'])
  416. ->field([ 'name', 'province_id','city_id','district_id', 'address', 'longitude', 'latitude' ])
  417. ->append([ 'address_detail', 'province', 'city', 'district' ])
  418. ->findOrEmpty()->toArray();
  419. }
  420. $shop = array_values($shop);
  421. $total_amount = array_sum(array_column($shop, 'total_amount'));
  422. $orders['address'] = $address;
  423. $orders['shop'] = $shop;
  424. $orders['order_type'] = self::$order_type;
  425. $orders['total_amount'] = $total_amount;
  426. $orders['pay_way_text'] = "微信支付";
  427. $orders['pay_way'] = PayEnum::WECHAT_PAY;
  428. // 检验是否参与包邮活动,若参与去除邮费
  429. $orders = self::checkFreeShipping($orders);
  430. // 重新算总价
  431. $orders['total_amount'] = array_sum(array_column($orders['shop'], 'total_amount'));
  432. $orders['total_amount'] = round($orders['total_amount'], 2);
  433. $orders['invoice'] = array_values($invoice);
  434. return $orders;
  435. }
  436. /**
  437. * @notes 校验是否符合包邮条件
  438. * @param $orders
  439. * @author Tab
  440. * @date 2021/8/31 15:11
  441. */
  442. public static function checkFreeShipping($orders)
  443. {
  444. if (empty($orders['address'])) {
  445. return $orders;
  446. }
  447. $address = $orders['address'];
  448. foreach($orders['shop'] as &$item) {
  449. if (self::isFreeShipping($item['shop_id'], ($item['total_amount'] - $item['shipping_price']), $address)) {
  450. // 原总价格已算上邮费需减掉
  451. $item['total_amount'] = $item['total_amount'] - $item['shipping_price'];
  452. // 符合包邮条件,去邮费
  453. $item['shipping_price'] = 0;
  454. }
  455. }
  456. return $orders;
  457. }
  458. /**
  459. * @notes 是否满足包邮条件
  460. * @param $shopId
  461. * @param $orderAmount
  462. * @param $address
  463. * @return bool
  464. * @author Tab
  465. * @date 2021/8/31 15:42
  466. */
  467. public static function isFreeShipping($shopId, $orderAmount, $address)
  468. {
  469. $config = Db::name('free_shipping_config')->where([
  470. 'shop_id' => $shopId,
  471. 'del' => 0
  472. ])->findOrEmpty();
  473. if (empty($config) || $config['status'] == 0) {
  474. // 未设置 或 未开启包邮活动
  475. return false;
  476. }
  477. // 校验区级设置
  478. $district = Db::name('free_shipping_region')->where([
  479. 'shop_id' => $shopId,
  480. 'del' => 0
  481. ])->whereFindInSet('region', $address['district_id'])->findOrEmpty();
  482. if (!empty($district) && $orderAmount >= $district['order_amount']) {
  483. // 符合包邮条件
  484. return true;
  485. }
  486. if (!empty($district) && $orderAmount < $district['order_amount']) {
  487. // 不符合条件,不再校验市级
  488. return false;
  489. }
  490. // 校验市级设置
  491. $city = Db::name('free_shipping_region')->where([
  492. 'shop_id' => $shopId,
  493. 'del' => 0
  494. ])->whereFindInSet('region', $address['city_id'])->findOrEmpty();
  495. if (!empty($city) && $orderAmount >= $city['order_amount']) {
  496. // 符合包邮条件
  497. return true;
  498. }
  499. if (!empty($city) && $orderAmount < $city['order_amount']) {
  500. // 不符合条件,不再校验省级
  501. return false;
  502. }
  503. // 校验省级设置
  504. $province = Db::name('free_shipping_region')->where([
  505. 'shop_id' => $shopId,
  506. 'del' => 0
  507. ])->whereFindInSet('region', $address['province_id'])->findOrEmpty();
  508. if (!empty($province) && $orderAmount >= $province['order_amount']) {
  509. // 符合包邮条件
  510. return true;
  511. }
  512. if (!empty($province) && $orderAmount < $province['order_amount']) {
  513. // 不符合条件,不再校验全国设置
  514. return false;
  515. }
  516. // 校验全国设置
  517. $all = Db::name('free_shipping_region')->where([
  518. 'shop_id' => $shopId,
  519. 'del' => 0,
  520. 'region' => 'all'
  521. ])->findOrEmpty();
  522. if (!empty($all) && $orderAmount >= $all['order_amount']) {
  523. // 符合包邮条件
  524. return true;
  525. }
  526. return false;
  527. }
  528. /**
  529. * @notes 获取优惠金额
  530. * @param $coupon_id
  531. * @return int|mixed
  532. * @throws \think\db\exception\DataNotFoundException
  533. * @throws \think\db\exception\DbException
  534. * @throws \think\db\exception\ModelNotFoundException
  535. * @author suny
  536. * @date 2021/7/13 6:19 下午
  537. */
  538. public static function getDiscountAmount($coupon_id, $shopId = null)
  539. {
  540. $result = [
  541. 'money' => 0,
  542. 'shop_id' => $shopId,
  543. 'coupon_list_id' => 0,
  544. ];
  545. if (!isset($coupon_id) || empty($coupon_id)) {
  546. return $result;
  547. }
  548. //优惠金额
  549. foreach ($coupon_id as $item) {
  550. $Coupon_list = CouponList::where('id', $item)->find();
  551. if (is_null($shopId)) {
  552. $where = ['id' => $Coupon_list['coupon_id'], 'del' => 0];
  553. } else {
  554. $where = ['id' => $Coupon_list['coupon_id'], 'del' => 0, 'shop_id' => $shopId];
  555. }
  556. $coupon = Coupon::where($where)
  557. ->find();
  558. if (!empty($coupon)) {
  559. $result['money'] = $coupon['money'];
  560. $result['shop_id'] = $shopId;
  561. $result['coupon_list_id'] = $item;
  562. }
  563. }
  564. return $result;
  565. }
  566. /**
  567. * @notes shop优惠券
  568. * @param $coupon_ids
  569. * @param $shop_id
  570. * @return bool
  571. * @throws \think\db\exception\DataNotFoundException
  572. * @throws \think\db\exception\DbException
  573. * @throws \think\db\exception\ModelNotFoundException
  574. * @author suny
  575. * @date 2021/7/13 6:20 下午
  576. */
  577. public static function checkCoupon($coupon_ids, $shop_id)
  578. {
  579. $coupons = CouponList::where([['id', 'in', $coupon_ids]])->select()->toArray();
  580. if ($coupons) {
  581. foreach ($coupons as $item) {
  582. $coupon_id = $item['coupon_id'];
  583. $where = [
  584. 'id' => $coupon_id
  585. ];
  586. $result = Coupon::where($where)->value('shop_id');
  587. if ($shop_id == $result) {
  588. return true;
  589. }
  590. }
  591. } else {
  592. return false;
  593. }
  594. }
  595. /**
  596. * @notes 检查商品库存
  597. * @param $goods
  598. * @return bool
  599. * @throws \think\db\exception\DataNotFoundException
  600. * @throws \think\db\exception\DbException
  601. * @throws \think\db\exception\ModelNotFoundException
  602. * @author suny
  603. * @date 2021/7/13 6:20 下午
  604. */
  605. public static function checkGoods($goods)
  606. {
  607. if (!is_array($goods)) {
  608. throw new Exception('商品数据格式不正确');
  609. }
  610. // 商品信息
  611. $item_ids = array_column($goods, 'item_id');
  612. $field = 'i.id as item_id,g.id as goods_id,g.name,g.del,g.status,i.stock,
  613. g.delivery_type as goods_delivery,s.delivery_type as shop_delivery';
  614. $goodsData = (new Goods())->alias('g')
  615. ->join('goods_item i','i.goods_id = g.id')
  616. ->join('shop s','s.id = g.shop_id')
  617. ->field($field)
  618. ->whereIn('i.id', $item_ids)
  619. ->select()->toArray();
  620. $goodsData = array_column($goodsData, null, 'item_id');
  621. $shopData = Shop::whereIn('id', array_column($goods, 'shop_id'))->column('id,name', 'id');
  622. foreach ($goods as $key => $item) {
  623. if (!isset($goodsData[$item['item_id']])) {
  624. continue;
  625. }
  626. $goodsInfo = $goodsData[$item['item_id']];
  627. $goodsName = text_out_hidden($goodsInfo['name'], 8);
  628. $shopInfo = $shopData[$item['shop_id']] ?? [];
  629. $shopName = $shopInfo['name'] ?? '商家';
  630. if ($goodsInfo['del'] || !$goodsInfo['status']) {
  631. throw new Exception($goodsName . '商品不存在/未上架');
  632. }
  633. if ($item['num'] <= 0) {
  634. throw new Exception('请选择商品' . $goodsName . '数量');
  635. }
  636. if ($goodsInfo['stock'] < $item['num']) {
  637. throw new Exception($goodsName . '商品库存不足');
  638. }
  639. // 校验配送方式
  640. if ($item['delivery_type'] == GoodsEnum::DELIVERY_EXPRESS) {
  641. // 快递发货-商家设置
  642. if (!in_array(ShopEnum::DELIVERY_EXPRESS, explode(',', $goodsInfo['shop_delivery']))) {
  643. throw new Exception( '商家(' . $shopName . ')未开启快递配送');
  644. }
  645. // 商品设置
  646. if (!in_array(GoodsEnum::DELIVERY_EXPRESS, explode(',', $goodsInfo['goods_delivery']))) {
  647. throw new Exception('商品('. $goodsName . ')暂不支持快递配送');
  648. }
  649. }
  650. if ($item['delivery_type'] == GoodsEnum::DELIVERY_SELF) {
  651. // 线下自提-商家设置
  652. if (!in_array(ShopEnum::DELIVERY_SELF, explode(',', $goodsInfo['shop_delivery']))) {
  653. throw new Exception( '商家(' . $shopName . ')未开启线下自提');
  654. }
  655. // 商品设置
  656. if (!in_array(GoodsEnum::DELIVERY_SELF, explode(',', $goodsInfo['goods_delivery']))) {
  657. throw new Exception( '商品('. $goodsName .')暂不支持线下自提');
  658. }
  659. }
  660. }
  661. return true;
  662. }
  663. /**
  664. * @notes 计算商品总价格
  665. * @param $goods
  666. * @return false|float|int
  667. * @author suny
  668. * @date 2021/7/13 6:20 下午
  669. */
  670. public static function calculateGoodsPrice($goods,$discount)
  671. {
  672. if (!is_array($goods)) {
  673. return false;
  674. }
  675. $GoodsItem = new GoodsItem();
  676. $all_goods_price = 0;
  677. foreach ($goods as $key => $value) {
  678. $goods_price = $GoodsItem->sumGoodsPrice($value['goods_id'], $value['item_id'], $value['num'],$discount);
  679. $all_goods_price = round($goods_price + $all_goods_price, 2);
  680. }
  681. return $all_goods_price;
  682. }
  683. /**
  684. * @notes 计算会员折扣金额
  685. * @param $goods
  686. * @param $discount
  687. * @return false|float|int
  688. * @author suny
  689. * @date 2021/9/7 4:42 下午
  690. */
  691. public static function memberGoodsPrice($goods,$discount)
  692. {
  693. if (!is_array($goods)) {
  694. return false;
  695. }
  696. $GoodsItem = new GoodsItem();
  697. $all_goods_price = 0;
  698. foreach ($goods as $key => $value) {
  699. $goods_price = $GoodsItem->sumMemberPrice($value['goods_id'], $value['item_id'], $value['num'],$discount);
  700. $all_goods_price = round($goods_price + $all_goods_price, 2);
  701. }
  702. return $all_goods_price;
  703. }
  704. /**
  705. * @notes 根据goods计算商品总运费
  706. * @param $goodsList
  707. * @param $address
  708. * @return false|int|string
  709. * @throws \think\db\exception\DataNotFoundException
  710. * @throws \think\db\exception\DbException
  711. * @throws \think\db\exception\ModelNotFoundException
  712. * @author suny
  713. * @date 2021/7/13 6:20 下午
  714. */
  715. public static function calculateFreight($goodsList, $address)
  716. {
  717. if (!is_array($goodsList)) {
  718. return 0;
  719. }
  720. $templateList = [];
  721. $freight = 0;
  722. if (empty($address)) {
  723. return $freight;
  724. }
  725. foreach ($goodsList as $key => $goods) {
  726. // 不是快递配送时不计算
  727. if ($goods['delivery_type'] != GoodsEnum::DELIVERY_EXPRESS) {
  728. continue;
  729. }
  730. $express = (new Goods())->getExpressType($goods['goods_id']);
  731. switch ($express['express_type']) {
  732. // 统一运费
  733. case 2:
  734. $price = $express['express_money'] * $goods['num'];
  735. $freight = round(($freight + $price), 2);
  736. break;
  737. // 运费模板
  738. case 3:
  739. $templateList[$express['express_template_id']][] = $goods;
  740. break;
  741. default:
  742. break;
  743. }
  744. }
  745. foreach ($templateList as $templateId => $templateGoods) {
  746. $total_weight = 0;
  747. $total_volume = 0;
  748. $total_num = 0;
  749. foreach ($templateGoods as $goodsInfo) {
  750. $goods_item = (new GoodsItem())->where('id', $goodsInfo['item_id'])->field('stock,volume,weight')->find()->toArray();
  751. $total_weight = bcadd(($goods_item['weight'] ? : 0) * $goodsInfo['num'], $total_weight, 3);
  752. $total_volume = bcadd(($goods_item['volume'] ? : 0) * $goodsInfo['num'], $total_volume, 3);
  753. $total_num += $goodsInfo['num'];
  754. }
  755. $freightInfo = Freight::findOrEmpty($templateId);
  756. switch ($freightInfo['charge_way']) {
  757. // 重量
  758. case FreightEnum::CHARGE_WAY_WEIGHT:
  759. $nums = $total_weight;
  760. break;
  761. // 体积
  762. case FreightEnum::CHARGE_WAY_VOLUME:
  763. $nums = $total_volume;
  764. break;
  765. // 件数
  766. case FreightEnum::CHARGE_WAY_PIECE:
  767. $nums = $total_num;
  768. break;
  769. default:
  770. continue 2;
  771. }
  772. $price = (new Freight())->sumFreight($address, $templateId, $nums);
  773. $freight = round(($freight + $price), 2);
  774. }
  775. return $freight;
  776. }
  777. /**
  778. * @notes 添加父订单
  779. * @param $post
  780. * @param $address
  781. * @return false|mixed
  782. * @throws \think\db\exception\DataNotFoundException
  783. * @throws \think\db\exception\DbException
  784. * @throws \think\db\exception\ModelNotFoundException
  785. * @throws \think\exception\DbException
  786. * @author suny
  787. * @date 2021/7/13 6:20 下午
  788. */
  789. public static function addOrderTrade($post, $address)
  790. {
  791. $OrderTrade = new OrderTrade();
  792. $order_amount = 0;
  793. $total_amount = 0;
  794. //计算商品总价格
  795. $user = User::where('id', $post['user_id'])->find();
  796. $discount = UserLevel::where('id', $user['level'])->value('discount');
  797. if($discount == 0 || self::$order_type != OrderEnum::NORMAL_ORDER){
  798. $discount = 10;
  799. }
  800. $all_goods_price = self::calculateGoodsPrice($post['goods'],$discount);
  801. //计算商品运费
  802. $all_freight = self::calculateFreight($post['goods'], $address);
  803. $total_amount = $all_goods_price + $all_freight;
  804. //计算优惠券优惠的金额
  805. $discount_amount = 0;
  806. if (isset($post['coupon_id'])) {
  807. foreach ($post['goods'] as $value) {
  808. $discount_amount += self::getDiscountAmount($post['coupon_id'], $value['shop_id'])['money'] ?? 0;
  809. }
  810. }
  811. if ($total_amount > $discount_amount) {
  812. $total_amount = round(($total_amount - $discount_amount), 2);
  813. } else {
  814. //优惠金额大于当前商品总价,总价为0
  815. $discount_amount = $total_amount;
  816. $total_amount = 0;
  817. }
  818. // 砍价订单
  819. if (isset($post['bargain_launch_id']) and $post['bargain_launch_id'] > 0) {
  820. foreach ($post['goods'] as $goods) {
  821. $bargainLaunchModel = new BargainLaunch();
  822. $launch = $bargainLaunchModel->field(true)
  823. ->where(['id' => (int)$post['bargain_launch_id']])
  824. ->find();
  825. $total_amount = round($launch['current_price'] * $goods['num'], 2);
  826. }
  827. }
  828. // 记录访问足迹
  829. event('Footprint', [
  830. 'type' => FootprintEnum::PLACE_ORDER,
  831. 'user_id' => $post['user_id'],
  832. 'total_money' => $total_amount
  833. ]);
  834. $trade_order_data = [];
  835. $trade_order_data['t_sn'] = createSn('order_trade', 't_sn');
  836. // 拿shop_id,连接成字符串存入order_trade表shop_id中
  837. $shop_id = '';
  838. foreach ($post['goods'] as $key => $value) {
  839. $shop_id .= ',' . $value['shop_id'];
  840. }
  841. $shop_id = substr($shop_id, 1);
  842. $trade_order_data['shop_id'] = $shop_id;
  843. $trade_order_data['user_id'] = $post['user_id'];
  844. $trade_order_data['goods_price'] = $all_goods_price;
  845. $trade_order_data['order_amount'] = $total_amount;
  846. $trade_order_data['total_amount'] = $total_amount;
  847. $trade_order_data['discount_amount'] = $discount_amount;
  848. $trade_order_data['create_time'] = time();
  849. $order_trade_create = $OrderTrade->create($trade_order_data);
  850. if (false === $order_trade_create) {
  851. return false;
  852. }
  853. return $order_trade_create->id;
  854. }
  855. /**
  856. * @notes 添加子订单
  857. * @param $order_id
  858. * @param $goods
  859. * @param $post
  860. * @param $shop_id
  861. * @param $address
  862. * @return false|mixed
  863. * @throws \think\db\exception\DataNotFoundException
  864. * @throws \think\db\exception\DbException
  865. * @throws \think\db\exception\ModelNotFoundException
  866. * @throws \think\exception\DbException
  867. * @author suny
  868. * @date 2021/7/13 6:21 下午
  869. */
  870. public static function addOrder($order_id, $goods, $post, $shop_id, $address)
  871. {
  872. $Order = new Order();
  873. $remarks = isset($post['remark']) ? json_decode($post['remark'], true) : '';
  874. if ($remarks != '') {
  875. foreach ($remarks as $key => $value) {
  876. $user_remark[$value['shop_id']] = $value['remark'];
  877. }
  878. if (array_key_exists($shop_id, $user_remark)) {
  879. $remark = $user_remark[$shop_id];
  880. } else $remark = '';
  881. } else {
  882. $remark = $remarks;
  883. }
  884. $user = User::where('id', $post['user_id'])->find();
  885. $discount = UserLevel::where('id', $user['level'])->value('discount');
  886. if($discount == 0 || self::$order_type != OrderEnum::NORMAL_ORDER){
  887. $discount = 10;
  888. }
  889. $goods_price = self::calculateGoodsPrice($goods,$discount); //商品价格
  890. $member_amount = self::memberGoodsPrice($goods,$discount); //会员优惠价格
  891. $shipping_price = self::calculateFreight($goods, $address);
  892. //计算优惠券优惠的金额
  893. $coupon_list_id = 0;
  894. $discount_amount = 0;
  895. if (isset($post['coupon_id'])) {
  896. $discount = self::getDiscountAmount($post['coupon_id'], $shop_id);
  897. $discount_amount = $discount['money'];
  898. $coupon_list_id = $discount['coupon_list_id'];
  899. }
  900. $order_amount = $goods_price + $shipping_price;
  901. // 优惠金额大于实际支付的时候
  902. $discount_amount = min($order_amount, $discount_amount);
  903. $order_amount = $order_amount - $discount_amount;
  904. $total_amount = $order_amount;
  905. // 砍价订单
  906. if (isset($post['bargain_launch_id']) and $post['bargain_launch_id'] > 0) {
  907. foreach ($post['goods'] as $post_goods) {
  908. $bargainLaunchModel = new BargainLaunch();
  909. $launch = $bargainLaunchModel->field(true)
  910. ->where(['id' => (int)$post['bargain_launch_id']])
  911. ->find();
  912. $order_amount = $total_amount = round($launch['current_price'] * $post_goods['num'], 2);
  913. }
  914. }
  915. $order_data = [];
  916. $order_data['trade_id'] = $order_id;
  917. $order_data['shop_id'] = $shop_id;
  918. $order_data['user_id'] = $post['user_id'];
  919. $order_data['order_sn'] = createSn('order_trade', 't_sn');
  920. $order_data['order_type'] = self::$order_type;
  921. $order_data['order_source'] = $post['client'];
  922. $order_data['order_status'] = OrderEnum::ORDER_STATUS_NO_PAID;
  923. $order_data['pay_status'] = OrderEnum::PAY_STATUS_NO_PAID;
  924. $order_data['pay_way'] = $post['pay_way'];
  925. $order_data['delivery_type'] = OrderEnum::getChangeDeliveryTypeItem($goods[0]['delivery_type'] ?? 0);
  926. $order_data['aftersale_status'] = OrderEnum::AFTERSALE_STATUS_NO_SALE;
  927. $order_data['consignee'] = $address['contact'] ?? '';
  928. $order_data['province'] = $address['province_id'] ?? 0;
  929. $order_data['city'] = $address['city_id'] ?? 0;
  930. $order_data['district'] = $address['district_id'] ?? 0;
  931. $order_data['address'] = $address['address'] ?? '';
  932. $order_data['mobile'] = $address['telephone'] ?? '';
  933. $order_data['goods_price'] = $goods_price;
  934. $order_data['shipping_price'] = $shipping_price;
  935. $order_data['order_amount'] = $order_amount;
  936. $order_data['discount_amount'] = $discount_amount;
  937. $order_data['member_amount'] = $member_amount;
  938. $order_data['total_amount'] = $total_amount;
  939. $order_data['total_num'] = array_sum(array_column($goods, 'num'));
  940. $order_data['user_remark'] = $remark;
  941. $order_data['distribution_money'] = 0;
  942. $order_data['coupon_list_id'] = $coupon_list_id;
  943. $order_data['create_time'] = time();
  944. // 线下自提
  945. if ($goods[0]['delivery_type'] == GoodsEnum::DELIVERY_SELF) {
  946. $order_data['pickup_code'] = create_rand_number('order', 'pickup_code', 6);
  947. }
  948. $order_create = $Order->create($order_data);
  949. if (false === $order_create) {
  950. return false;
  951. }
  952. if (!empty($coupon_list_id)) {
  953. self::editCoupon($coupon_list_id, $order_create->id);
  954. }
  955. return $order_create->id;
  956. }
  957. /**
  958. * @notes 添加订单商品
  959. * @param $order_id
  960. * @param $goods
  961. * @return array
  962. * @throws \think\db\exception\DataNotFoundException
  963. * @throws \think\db\exception\DbException
  964. * @throws \think\db\exception\ModelNotFoundException
  965. * @author suny
  966. * @date 2021/7/13 6:21 下午
  967. */
  968. public static function getOrderGoodsData($order_id, $goods,$user_id)
  969. {
  970. $user = User::where('id', $user_id)->find();
  971. $discount = UserLevel::where('id', $user['level'])->value('discount');
  972. if($discount == 0 || self::$order_type != OrderEnum::NORMAL_ORDER){
  973. $discount = 10;
  974. }
  975. $goods_data = [];
  976. foreach ($goods as $key => $value) {
  977. $Goods = Goods::where('id', $value['goods_id'])->field('name,image,shop_id')->find();
  978. $GoodsItem = GoodsItem::where([
  979. ['id', '=', $value['item_id']],
  980. ['goods_id', '=', $value['goods_id']],
  981. ])->field('id,goods_id,price,image,spec_value_ids,spec_value_str,weight')
  982. ->find();
  983. $goodsItemPrice = GoodsItem::getGoodsItemPrice($GoodsItem);
  984. $goods_data[$key]['order_id'] = $order_id;
  985. $goods_data[$key]['shop_id'] = $Goods['shop_id'];
  986. $goods_data[$key]['goods_id'] = $value['goods_id'];
  987. $goods_data[$key]['item_id'] = $value['item_id'];
  988. $goods_data[$key]['goods_num'] = $value['num'];
  989. $goods_data[$key]['goods_name'] = $Goods['name'];
  990. $goods_data[$key]['goods_price'] = $goodsItemPrice;
  991. $goods_data[$key]['total_price'] = round($goodsItemPrice * $value['num'], 2);
  992. $goods_data[$key]['total_pay_price'] = self::calculateGoodsPrice([$value],$discount);
  993. $goods_data[$key]['spec_value'] = $GoodsItem['spec_value_str'];
  994. $goods_data[$key]['spec_value_ids'] = $GoodsItem['spec_value_ids'];
  995. $goods_data[$key]['image'] = !empty($Goods['image']) ? UrlServer::setFileUrl($Goods['image']) : '';
  996. $goods_data[$key]['weight'] = $GoodsItem['weight'];
  997. $goods_data[$key]['create_time'] = time();
  998. }
  999. $goods_data = self::shareDiscount($goods_data, $order_id);
  1000. return $goods_data;
  1001. }
  1002. public static function shareDiscount($goodsData, $orderId)
  1003. {
  1004. // 获取订单优惠价格
  1005. $orderDiscount = Order::where('id', $orderId)->value('discount_amount');
  1006. if ($orderDiscount <= 0) {
  1007. // 未使用优惠
  1008. foreach ($goodsData as $key => &$item) {
  1009. $item['discount_price'] = 0;
  1010. }
  1011. return $goodsData;
  1012. }
  1013. // 累计应付总金额
  1014. $sumPayPrice = array_sum(array_column($goodsData, 'total_pay_price')) ? : 0;
  1015. // 根据比例分摊优惠金额
  1016. $sumDiscount = 0;
  1017. foreach ($goodsData as $key => &$item) {
  1018. if ($key == (count($goodsData) - 1)) {
  1019. // 最后一条记录
  1020. $item['discount_price'] = $orderDiscount - $sumDiscount;
  1021. }
  1022. if ($sumPayPrice <= 0) {
  1023. continue;
  1024. }
  1025. $item['discount_price'] = round($item['total_pay_price'] / $sumPayPrice * $orderDiscount, 2);
  1026. // 优惠超过实付金额 使用实付
  1027. $item['discount_price'] = min($item['discount_price'], $item['total_pay_price']);
  1028. $item['total_pay_price'] -= $item['discount_price'];
  1029. }
  1030. return $goodsData;
  1031. }
  1032. /**
  1033. * @notes 扣除商品库存
  1034. * @param $goods
  1035. * @return bool
  1036. * @author suny
  1037. * @date 2021/7/13 6:21 下午
  1038. */
  1039. public static function subGoodsStock($goods)
  1040. {
  1041. $goods_ids = [];
  1042. foreach ($goods as $key => $value) {
  1043. $goods_item_stock_dec = GoodsItem::where([
  1044. ['id', '=', $value['item_id']],
  1045. ['goods_id', '=', $value['goods_id']],
  1046. ])->dec('stock', $value['num'])
  1047. ->update();
  1048. $goods_stock_dec = Goods::where('id', $value['goods_id'])
  1049. ->dec('stock', $value['num'])
  1050. ->update();
  1051. if (false === $goods_item_stock_dec) {
  1052. return false;
  1053. }
  1054. if (false === $goods_stock_dec) {
  1055. return false;
  1056. }
  1057. $goods_ids[] = $value['goods_id'];
  1058. }
  1059. // 下架总库存为0商品
  1060. //库存为0的商品暂不下架,显示为缺货
  1061. // self::outGoods($goods_ids);
  1062. return true;
  1063. }
  1064. /**
  1065. * @notes 下架总库存为0商品
  1066. * @param $goods_ids
  1067. * @return bool|void
  1068. * @author 段誉
  1069. * @date 2021/12/21 14:46
  1070. */
  1071. public static function outGoods($goods_ids)
  1072. {
  1073. try{
  1074. $goods = Goods::where('id', 'in', $goods_ids)
  1075. ->field('id, stock')
  1076. ->select();
  1077. if (empty($goods)) {
  1078. return true;
  1079. }
  1080. $need_handle_ids = [];
  1081. foreach ($goods as $good) {
  1082. if ($good['stock'] <= 0) {
  1083. $need_handle_ids[] = $good['id'];
  1084. }
  1085. }
  1086. if (empty($need_handle_ids)){
  1087. return true;
  1088. }
  1089. //下架订单商品中 商品总库存已为0的商品
  1090. Goods::where('id', 'in', $need_handle_ids)->update(['status' => 0]);
  1091. // 下架或删除商品更新收藏状态
  1092. event('UpdateCollect', ['goods_id' => $need_handle_ids]);
  1093. } catch (\Exception $e) {}
  1094. }
  1095. /**
  1096. * @notes 添加订单日志表
  1097. * @param $order_id
  1098. * @param $user_id
  1099. * @param $shop_id
  1100. * @return array
  1101. * @author suny
  1102. * @date 2021/7/13 6:21 下午
  1103. */
  1104. public static function getOrderLogData($order_id, $user_id, $shop_id)
  1105. {
  1106. $order_log_data = [];
  1107. $order_log_data['type'] = OrderLogEnum::TYPE_USER;
  1108. $order_log_data['channel'] = OrderLogEnum::USER_ADD_ORDER;
  1109. $order_log_data['order_id'] = $order_id;
  1110. $order_log_data['handle_id'] = $user_id;
  1111. $order_log_data['shop_id'] = $shop_id;
  1112. $order_log_data['content'] = OrderLogEnum::getLogDesc(OrderLogEnum::USER_ADD_ORDER);
  1113. $order_log_data['create_time'] = time();
  1114. return $order_log_data;
  1115. }
  1116. /**
  1117. * @notes 删除购物车
  1118. * @param $cart_id
  1119. * @return bool
  1120. * @author suny
  1121. * @date 2021/7/13 6:21 下午
  1122. */
  1123. public static function delCart($cart_id)
  1124. {
  1125. $delCart = Cart::where([
  1126. ['id', 'in', $cart_id],
  1127. ['selected', '=', 1]
  1128. ])
  1129. ->delete();
  1130. if (false === $delCart) {
  1131. return false;
  1132. }
  1133. return true;
  1134. }
  1135. /**
  1136. * @notes 订单列表
  1137. * @param $user_id
  1138. * @param $type
  1139. * @param $page
  1140. * @param $size
  1141. * @return array
  1142. * @throws \think\db\exception\DataNotFoundException
  1143. * @throws \think\db\exception\DbException
  1144. * @throws \think\db\exception\ModelNotFoundException
  1145. * @author suny
  1146. * @date 2021/7/13 6:21 下午
  1147. */
  1148. public static function getOrderList($user_id, $type, $page, $size)
  1149. {
  1150. $order = new Order();
  1151. $where[] = ['del', '=', 0];
  1152. $where[] = ['user_id', '=', $user_id];
  1153. switch ($type) {
  1154. case 'pay':
  1155. $where[] = ['order_status', '=', OrderEnum::ORDER_STATUS_NO_PAID];
  1156. break;
  1157. case 'delivery':
  1158. $where[] = ['order_status', 'in', [OrderEnum::ORDER_STATUS_DELIVERY, OrderEnum::ORDER_STATUS_GOODS]];
  1159. break;
  1160. case 'finish':
  1161. $where[] = ['order_status', '=', OrderEnum::ORDER_STATUS_COMPLETE];
  1162. break;
  1163. case 'close':
  1164. $where[] = ['order_status', '=', OrderEnum::ORDER_STATUS_DOWN];
  1165. break;
  1166. }
  1167. $count = $order->where(['del' => 0, 'user_id' => $user_id])
  1168. ->where($where)
  1169. ->count();
  1170. $lists = $order->where(['del' => 0, 'user_id' => $user_id])
  1171. ->where($where)
  1172. ->with(['order_goods', 'shop'])
  1173. ->field('id,order_sn,pay_way as pay_way_base,pay_way,order_status,pay_status,order_amount,order_status,order_type,shipping_status,create_time,shop_id,delivery_type')
  1174. ->page($page, $size)
  1175. ->order('id desc')
  1176. ->select();
  1177. $lists->append(['goods_count', 'pay_btn', 'cancel_btn', 'delivery_btn', 'take_btn', 'del_btn', 'comment_btn', 'content_btn','order_cancel_time','is_team_success']);
  1178. foreach ($lists as $list) {
  1179. if ($list['order_type'] == OrderEnum::SECKILL_ORDER) {//如果是秒杀
  1180. foreach ($list['order_goods'] as $item) {
  1181. $seckill_price = GoodsItem::isSeckill($item['item_id']);
  1182. if ($seckill_price != 0) {
  1183. $item['goods_price'] = $seckill_price;
  1184. }
  1185. }
  1186. }
  1187. // 查看提货码按钮
  1188. $list['pickup_btn'] = 0;
  1189. // 订单状态描述
  1190. $list['order_status_desc'] = OrderEnum::getOrderStatus($list['order_status']);
  1191. if ($list['order_status'] == OrderEnum::ORDER_STATUS_DELIVERY
  1192. && $list['delivery_type'] == OrderEnum::DELIVERY_TYPE_SELF
  1193. && $list['pay_status'] == PayEnum::ISPAID
  1194. ) {
  1195. $list['pickup_btn'] = 1;
  1196. $list['order_status_desc'] = '待取货';
  1197. }
  1198. if ($list['order_type'] == OrderEnum::TEAM_ORDER) {
  1199. $team = TeamJoin::field('id,status')
  1200. ->where(['order_id' => $list['id']])
  1201. ->findOrEmpty()->toArray();
  1202. if ($team['status'] != TeamEnum::TEAM_STATUS_SUCCESS) {
  1203. $list['pickup_btn'] = 0;
  1204. }
  1205. }
  1206. }
  1207. $data = [
  1208. 'list' => $lists,
  1209. 'page' => $page,
  1210. 'size' => $size,
  1211. 'count' => $count,
  1212. 'more' => is_more($count, $page, $size)
  1213. ];
  1214. return $data;
  1215. }
  1216. /**
  1217. * @notes 通过规格id查询秒杀价格
  1218. * @param $item_id
  1219. * @return int|mixed
  1220. * @throws \think\db\exception\DataNotFoundException
  1221. * @throws \think\db\exception\DbException
  1222. * @throws \think\db\exception\ModelNotFoundException
  1223. * @author suny
  1224. * @date 2021/7/13 6:21 下午
  1225. */
  1226. public static function getSekillPriceByItemId($item_id)
  1227. {
  1228. $where = [
  1229. 'item_id' => $item_id,
  1230. 'del' => 0,
  1231. 'review_status' => 1
  1232. ];
  1233. $seckill = SeckillGoods::where($where)->find();
  1234. return isset($seckill['price']) ? $seckill['price'] : 0;
  1235. }
  1236. /**
  1237. * @notes 订单详情
  1238. * @param $order_id
  1239. * @return array|\think\Model|null
  1240. * @throws \think\db\exception\DataNotFoundException
  1241. * @throws \think\db\exception\DbException
  1242. * @throws \think\db\exception\ModelNotFoundException
  1243. * @author suny
  1244. * @date 2021/7/13 6:22 下午
  1245. */
  1246. public static function getOrderDetail($order_id)
  1247. {
  1248. $order = Order::with(['order_goods', 'shop'])
  1249. ->field([ '*', 'pay_way as pay_way_base' ])
  1250. ->where(['del' => 0, 'id' => $order_id])
  1251. ->find();
  1252. if (isset($order['shop']['id'])) {
  1253. $order['shop']['run_start_time'] = $order['shop']['run_start_time'] ? date('H:i:s', $order['shop']['run_start_time']) : '';
  1254. $order['shop']['run_end_time'] = $order['shop']['run_end_time'] ? date('H:i:s', $order['shop']['run_end_time']) : '';
  1255. }
  1256. if ($order) {
  1257. $order->append(['delivery_address', 'pay_btn', 'cancel_btn', 'delivery_btn', 'take_btn', 'del_btn','view_invoice_btn','save_invoice_btn', 'order_cancel_time'])
  1258. ->hidden(['user_id', 'order_source',
  1259. 'city', 'district', 'address', 'shipping_status', 'shipping_code',
  1260. 'pay_status', 'transaction_id', 'del', 'province']);
  1261. // $refund_days = ConfigServer::get('after_sale', 'refund_days', 7 * 86400, 0) * 86400;
  1262. foreach ($order->order_goods as $order_good) {
  1263. if ($order['order_type'] == OrderEnum::SECKILL_ORDER) { // 是秒杀商品
  1264. $seckill_price = GoodsItem::isSeckill($order_good['item_id']);
  1265. if ($seckill_price != 0) {
  1266. $order_good['goods_price'] = $seckill_price;
  1267. }
  1268. }$order_good['sum_price'] = $order_good['goods_price'] * $order_good['goods_num'];
  1269. $order_good['comment_btn'] = 0;
  1270. if ($order['pay_status'] == PayEnum::ISPAID && $order['order_status'] == OrderEnum::ORDER_STATUS_COMPLETE && $order_good['is_comment'] == 0) {
  1271. $order_good['comment_btn'] = 1;
  1272. }
  1273. $order_good['refund_btn'] = 0;
  1274. // $confirm_take_time = strtotime($order['confirm_take_time']) ?: 0;
  1275. // $refund_time = $confirm_take_time + $refund_days;
  1276. if ($order['order_status'] == OrderEnum::ORDER_STATUS_COMPLETE && $order_good['refund_status'] == OrderGoodsEnum::REFUND_STATUS_NO) {
  1277. $order_good['refund_btn'] = 1;
  1278. }
  1279. $order_good['sum_price'] = $order_good['goods_price'] * $order_good['goods_num'];
  1280. }
  1281. //订单商品总价
  1282. $order->goods_price = $order->goods_price + $order->member_amount;
  1283. }
  1284. // 如果是拼团的订单
  1285. if ($order['order_type'] == OrderEnum::TEAM_ORDER) {
  1286. $teamJoin = (new TeamJoin())->where(['order_id' => $order['id']])->findOrEmpty()->toArray();
  1287. $teamJoin['team_snap'] = json_decode($teamJoin['team_snap'], true);
  1288. $order['team'] = [
  1289. 'team_activity_id' => $teamJoin['team_activity_id'],
  1290. 'team_id' => $teamJoin['team_id'],
  1291. 'identity' => $teamJoin['identity'] == 1 ? '团长' : '团员',
  1292. 'people_num' => $teamJoin['team_snap']['people_num'],
  1293. 'status' => $teamJoin['status'],
  1294. 'status_text' => TeamEnum::getStatusDesc($teamJoin['status'])
  1295. ];
  1296. }
  1297. $order['order_type'] = Order::getOrderType($order['order_type']);
  1298. $order['pay_way'] = PayEnum::getPayWay($order['pay_way']);
  1299. $order['create_time'] = $order['create_time'] == 0 ? '' : $order['create_time'];
  1300. $order['update_time'] = $order['update_time'] == 0 ? '' : $order['update_time'];
  1301. $order['confirm_take_time'] = $order['confirm_take_time'] == 0 ? '' : date('Y-m-d H:i:s', $order['confirm_take_time']);;
  1302. $order['shipping_time'] = $order['shipping_time'] == 0 ? '' : date('Y-m-d H:i:s', $order['shipping_time']);
  1303. $order['pay_time'] = $order['pay_time'] == 0 ? '' : date('Y-m-d H:i:s', $order['pay_time']);
  1304. $order['cancel_time'] = $order['cancel_time'] == 0 ? '' : date('Y-m-d H:i:s', $order['cancel_time']);
  1305. // 虚拟商品 发货内容
  1306. if ($order['delivery_type'] != OrderEnum::DELIVERY_TYPE_VIRTUAL || $order['shipping_status'] != OrderEnum::SHIPPING_FINISH) {
  1307. $order['delivery_content'] = '';
  1308. }
  1309. // 提货码
  1310. if ($order['pay_status'] == PayEnum::UNPAID){
  1311. $order['pickup_code'] = "";
  1312. }
  1313. // 订单状态描述
  1314. $order['order_status_desc'] = OrderEnum::getOrderStatus($order['order_status']);
  1315. if ($order['order_status'] == OrderEnum::ORDER_STATUS_DELIVERY && $order['delivery_type'] == OrderEnum::DELIVERY_TYPE_SELF) {
  1316. $order['order_status_desc'] = '待取货';
  1317. }
  1318. // 商家地址
  1319. $shop = Shop::where(['id' => $order['shop_id']])->findOrEmpty();
  1320. $region = Db::name('dev_region')
  1321. ->where('id', 'IN', [$shop['province_id'], $shop['city_id'], $shop['district_id']])
  1322. ->order('level asc')
  1323. ->column('name');
  1324. $order['shop_address'] = implode('', $region) . $shop['address'];
  1325. return $order->toArray();
  1326. }
  1327. static function wxReceiveDetail($id, $user_id)
  1328. {
  1329. $result = [
  1330. 'transaction_id' => '',
  1331. ];
  1332. $order = Order::where('id', $id)->where('user_id', $user_id)->findOrEmpty();
  1333. if ($order->isEmpty()) {
  1334. return $result;
  1335. }
  1336. $result['transaction_id'] = $order->transaction_id ? : OrderTrade::where('id', $order->trade_id)->value('transaction_id', '');
  1337. return $result;
  1338. }
  1339. /**
  1340. * @notes 取消订单
  1341. * @param $order_id
  1342. * @param $user_id
  1343. * @return \think\response\Json
  1344. * @throws \think\db\exception\DataNotFoundException
  1345. * @throws \think\db\exception\DbException
  1346. * @throws \think\db\exception\ModelNotFoundException
  1347. * @throws \think\exception\PDOException
  1348. * @author suny
  1349. * @date 2021/7/13 6:22 下午
  1350. */
  1351. public static function cancel($order_id, $user_id)
  1352. {
  1353. $time = time();
  1354. $order = Order::with(['orderGoods'])->where(['del' => 0, 'user_id' => $user_id, 'id' => $order_id])->find();
  1355. if (!$order || (int)$order['order_status'] > OrderEnum::ORDER_STATUS_DELIVERY) {
  1356. return JsonServer::error('很抱歉!订单无法取消');
  1357. }
  1358. $cancel_limit = ConfigServer::get('transaction', 'paid_order_cancel_time', 60);
  1359. $limit_time = $order->getOrigin('pay_time') + $cancel_limit * 60;
  1360. if ($limit_time < time() && $order['order_status'] != OrderEnum::ORDER_STATUS_NO_PAID) {
  1361. return JsonServer::error('很抱歉!订单已不可取消');
  1362. }
  1363. Db::startTrans();
  1364. try {
  1365. // 如果是拼团的订单
  1366. $team_join = (new TeamJoin())->where(['order_id' => $order['id'],'status'=>TeamEnum::TEAM_STATUS_CONDUCT])->findOrEmpty()->toArray();//拼团中
  1367. if ($order['order_type'] == OrderEnum::TEAM_ORDER && !empty($team_join)) {
  1368. $team_id = $team_join['team_id'];
  1369. $teamJoin = (new TeamJoin())->alias('TJ')
  1370. ->field(['TJ.*,O.order_sn,O.order_status,O.pay_status,O.refund_status,O.order_amount'])
  1371. ->where(['team_id' => $team_id])
  1372. ->join('order O', 'O.id=TJ.order_id')
  1373. ->select()->toArray();
  1374. TeamFound::update(['status' => TeamEnum::TEAM_STATUS_FAIL, 'team_end_time' => $time], ['id' => $team_id]);
  1375. foreach ($teamJoin as $item) {
  1376. TeamJoin::update(['status' => TeamEnum::TEAM_STATUS_FAIL, 'update_time' => $time], ['id' => $item['id']]);
  1377. OrderRefundLogic::cancelOrder($item['order_id'], OrderLogEnum::TYPE_USER, $user_id); //取消订单
  1378. if ($item['pay_status'] == PayEnum::ISPAID) {
  1379. $order = (new Order())->findOrEmpty($item['order_id'])->toArray();
  1380. OrderRefundLogic::cancelOrderRefundUpdate($order); //更新订单状态
  1381. OrderRefundLogic::refund($order, $order['order_amount'], $order['order_amount']); //订单退款
  1382. }
  1383. }
  1384. } else {
  1385. //取消订单
  1386. OrderRefundLogic::cancelOrder($order_id, OrderLogEnum::TYPE_USER, $user_id);
  1387. //已支付的订单,取消,退款
  1388. if ($order['pay_status'] == PayEnum::ISPAID) {
  1389. //更新订单状态
  1390. OrderRefundLogic::cancelOrderRefundUpdate($order);
  1391. //订单退款
  1392. OrderRefundLogic::refund($order, $order['order_amount'], $order['order_amount']);
  1393. }
  1394. }
  1395. Db::commit();
  1396. return JsonServer::success('取消成功');
  1397. } catch (Exception $e) {
  1398. Db::rollback();
  1399. self::addErrorRefund($order, $e->getMessage());
  1400. return JsonServer::error($e->getMessage());
  1401. }
  1402. }
  1403. /**
  1404. * @notes 回退商品库存
  1405. * @param $goods
  1406. * @author suny
  1407. * @date 2021/7/13 6:22 下午
  1408. */
  1409. public static function backStock($goods)
  1410. {
  1411. foreach ($goods as $good) {
  1412. //回退库存,回退规格库存,减少商品销量
  1413. Goods::where('id', $good['goods_id'])
  1414. ->update([
  1415. 'stock' => Db::raw('stock+' . $good['goods_num'])
  1416. ]);
  1417. //补充规格表库存
  1418. GoodsItem::where('id', $good['item_id'])
  1419. ->inc('stock', $good['goods_num'])
  1420. ->update();
  1421. }
  1422. }
  1423. /**
  1424. * @notes 增加退款失败记录
  1425. * @param $order
  1426. * @param $err_msg
  1427. * @return int|string
  1428. * @throws \think\db\exception\DataNotFoundException
  1429. * @throws \think\db\exception\DbException
  1430. * @throws \think\db\exception\ModelNotFoundException
  1431. * @throws \think\exception\DbException
  1432. * @author suny
  1433. * @date 2021/7/13 6:22 下午
  1434. */
  1435. public static function addErrorRefund($order, $err_msg)
  1436. {
  1437. $orderRefund = new OrderRefund();
  1438. $refund_data = [
  1439. 'order_id' => $order['id'],
  1440. 'user_id' => $order['user_id'],
  1441. 'refund_sn' => createSn('order_refund', 'refund_sn'),
  1442. 'order_amount' => $order['order_amount'],//订单应付金额
  1443. 'refund_amount' => $order['order_amount'],//订单退款金额
  1444. 'transaction_id' => $order['transaction_id'],
  1445. 'create_time' => time(),
  1446. 'refund_status' => 2,
  1447. 'refund_msg' => json_encode($err_msg, JSON_UNESCAPED_UNICODE),
  1448. ];
  1449. return $orderRefund->insertGetId($refund_data);
  1450. }
  1451. /**
  1452. * @notes 获取退款订单的应付金额
  1453. * @param $order
  1454. * @return mixed
  1455. * @throws \think\db\exception\DataNotFoundException
  1456. * @throws \think\db\exception\DbException
  1457. * @throws \think\db\exception\ModelNotFoundException
  1458. * @author suny
  1459. * @date 2021/7/13 6:22 下午
  1460. */
  1461. public static function getOrderTotalFee($order)
  1462. {
  1463. $OrderTrade = new OrderTrade();
  1464. $trade = $OrderTrade
  1465. ->where('transaction_id', $order['transaction_id'])
  1466. ->find();
  1467. $total_fee = $order['order_amount'];
  1468. if ($trade) {
  1469. $total_fee = $trade['order_amount'];
  1470. }
  1471. return $total_fee;
  1472. }
  1473. /**
  1474. * @notes 确认订单
  1475. * @param $order_id
  1476. * @param $user_id
  1477. * @return \think\response\Json
  1478. * @throws \think\db\exception\DataNotFoundException
  1479. * @throws \think\db\exception\DbException
  1480. * @throws \think\db\exception\ModelNotFoundException
  1481. * @author suny
  1482. * @date 2021/7/13 6:22 下午
  1483. */
  1484. public static function confirm($order_id, $user_id)
  1485. {
  1486. $order = Order::where(['del' => 0, 'id' => $order_id])->find();
  1487. if ($order['order_status'] == OrderEnum::ORDER_STATUS_COMPLETE) {
  1488. return JsonServer::error('订单已完成');
  1489. }
  1490. if ($order['shipping_status'] == 0) {
  1491. return JsonServer::error('订单未发货');
  1492. }
  1493. $order->order_status = OrderEnum::ORDER_STATUS_COMPLETE;
  1494. $order->update_time = time();
  1495. $order->confirm_take_time = time();
  1496. $order->save();
  1497. //订单日志
  1498. OrderLogLogic::record(
  1499. OrderLogEnum::TYPE_USER,
  1500. OrderLogEnum::USER_CONFIRM_ORDER,
  1501. $order_id,
  1502. $user_id,
  1503. OrderLogEnum::USER_CONFIRM_ORDER
  1504. );
  1505. return JsonServer::success('确认成功');
  1506. }
  1507. /**
  1508. * @notes 删除订单
  1509. * @param $order_id
  1510. * @param $user_id
  1511. * @return \think\response\Json
  1512. * @throws \think\db\exception\DataNotFoundException
  1513. * @throws \think\db\exception\DbException
  1514. * @throws \think\db\exception\ModelNotFoundException
  1515. * @author suny
  1516. * @date 2021/7/13 6:23 下午
  1517. */
  1518. public static function del($order_id, $user_id)
  1519. {
  1520. $where = [
  1521. 'order_status' => OrderEnum::ORDER_STATUS_DOWN,
  1522. 'user_id' => $user_id,
  1523. 'id' => $order_id,
  1524. 'del' => 0,
  1525. ];
  1526. $order = Order::where($where)->find();
  1527. if (!$order) {
  1528. return JsonServer::error('订单无法删除');
  1529. }
  1530. // $res = $order->save(['del' => 1, 'update_time' => time()]);
  1531. $data = ['del' => 1, 'update_time' => time(), 'pat_status' => OrderEnum::ORDER_STATUS_DOWN];
  1532. $res = Order::update($data, ['id' => $order['id']]);
  1533. OrderLogLogic::record(
  1534. OrderLogEnum::TYPE_USER,
  1535. OrderLogEnum::USER_DEL_ORDER,
  1536. $order_id,
  1537. $user_id,
  1538. OrderLogEnum::USER_DEL_ORDER
  1539. );
  1540. return JsonServer::success('删除成功', ['res' => $res]);
  1541. }
  1542. /**
  1543. * @notes 获取订单支付结果
  1544. * @param $trade_id
  1545. * @return array|false
  1546. * @author suny
  1547. * @date 2021/7/13 6:23 下午
  1548. */
  1549. public static function pay_result($id,$from)
  1550. {
  1551. switch ($from) {
  1552. case 'trade' : //如果是父订单类型下单,$id为父订单id
  1553. $result = OrderTrade::alias('ot')
  1554. ->where([ 'ot.id' => $id ])
  1555. ->join('order o','o.trade_id = ot.id')
  1556. ->field(['ot.id', 'ot.t_sn as order_sn', 'o.pay_time', 'o.pay_way', 'ot.total_amount' , 'o.pay_status' , 'ot.create_time'])
  1557. ->order('o.pay_status desc')
  1558. ->findOrEmpty()
  1559. ->toArray();
  1560. $result['total_amount'] = '¥' . $result['total_amount'];
  1561. break;
  1562. case 'order' : //如果是子订单类型下单,$id为子订单id
  1563. $result = Order::where(['id' => $id])
  1564. ->field(['id', 'order_sn', 'pay_time', 'pay_way', 'total_amount', 'pay_status' , 'create_time' ])
  1565. ->findOrEmpty()
  1566. ->toArray();
  1567. $result['total_amount'] = '¥' . $result['total_amount'];
  1568. break;
  1569. case 'integral':
  1570. $result = IntegralOrder::where(['id' => $id])
  1571. ->field(['id', 'order_sn', 'pay_time', 'pay_way', 'order_amount', 'order_integral', 'exchange_way', 'pay_status' , 'create_time' ])
  1572. ->findOrEmpty()->toArray();
  1573. $order_integral = $result['order_integral'] > 0 ? $result['order_integral'] . '积分' : '';
  1574. $order_amount = $result['order_amount'] > 0 ? '+ ¥' . $result['order_amount'] . '元' : '';
  1575. $result['total_amount'] = $order_integral . $order_amount;
  1576. break;
  1577. case 'recharge':
  1578. $result = RechargeOrder::where('id', $id)
  1579. ->field([ 'id', 'order_sn', 'pay_time', 'pay_way', 'pay_status as pay_status_origin', 'create_time', 'order_amount' ])
  1580. ->findOrEmpty()->toArray();
  1581. $result['total_amount'] = '¥' . $result['order_amount'];
  1582. $result['pay_status'] = $result['pay_status_origin'];
  1583. break;
  1584. default :
  1585. return false;
  1586. }
  1587. if ($result) {
  1588. $result['pay_time'] = empty($result['pay_time']) ? $result['create_time'] : date('Y-m-d H:i:s', $result['pay_time']);
  1589. $result['pay_way'] = PayEnum::getPayWay($result['pay_way']);
  1590. $result['pay_status'] = $result['pay_status'] ?? 0;
  1591. return $result;
  1592. }
  1593. return false;
  1594. }
  1595. /**
  1596. * @notes 获取支付方式
  1597. * @param $user_id
  1598. * @return array|array[]|\array[][]|\array[][][]
  1599. * @throws \think\db\exception\DataNotFoundException
  1600. * @throws \think\db\exception\DbException
  1601. * @throws \think\db\exception\ModelNotFoundException
  1602. * @author suny
  1603. * @date 2021/7/13 6:23 下午
  1604. */
  1605. public static function getPayWay($user_id, $client, $params)
  1606. {
  1607. $payModel = new Pay();
  1608. $payway = $payModel->where(['status' => 1])->order('sort')->hidden(['config'])->select()->toArray();
  1609. foreach ($payway as $k => &$item) {
  1610. if ($item['code'] == 'wechat') {
  1611. $item['extra'] = '微信快捷支付';
  1612. $item['pay_way'] = PayEnum::WECHAT_PAY;
  1613. }
  1614. if ($item['code'] == 'balance') {
  1615. $user_money = Db::name('user')->where(['id' => $user_id])->value('user_money');
  1616. $item['extra'] = '可用余额:' . $user_money;
  1617. $item['pay_way'] = PayEnum::BALANCE_PAY;
  1618. if($params['from'] == 'recharge') {
  1619. unset($payway[$k]);
  1620. }
  1621. }
  1622. if ($item['code'] == 'alipay') {
  1623. $item['extra'] = '';
  1624. $item['pay_way'] = PayEnum::ALI_PAY;
  1625. }
  1626. if ($item['code'] == 'hfdg_wechat') {
  1627. $item['extra'] = '';
  1628. $item['pay_way'] = PayEnum::HFDG_WECHAT;
  1629. if (! in_array($client, [ ClientEnum::mnp, ClientEnum::oa ])) {
  1630. unset($payway[$k]);
  1631. }
  1632. }
  1633. if ($item['code'] == 'hfdg_alipay') {
  1634. $item['extra'] = '';
  1635. $item['pay_way'] = PayEnum::HFDG_ALIPAY;
  1636. if (in_array($client, [ ClientEnum::mnp, ClientEnum::oa ])) {
  1637. unset($payway[$k]);
  1638. }
  1639. }
  1640. if ($item['code'] == 'offline') {
  1641. $item['extra'] = '';
  1642. $item['pay_way'] = PayEnum::OFFLINE_PAY;
  1643. if($params['from'] == 'recharge') {
  1644. unset($payway[$k]);
  1645. }
  1646. }
  1647. }
  1648. if($params['from'] == 'order') {
  1649. $order = Order::findOrEmpty($params['order_id']);
  1650. } else if($params['from'] == 'trade') {
  1651. $order = OrderTrade::findOrEmpty($params['order_id']);
  1652. } else if($params['from'] == 'integral') {
  1653. $order = IntegralOrder::findOrEmpty($params['order_id']);
  1654. } else {
  1655. $order = RechargeOrder::findOrEmpty($params['order_id']);
  1656. }
  1657. $cancelTime = ConfigServer::get('transaction', 'unpaid_order_cancel_time', 60);
  1658. if(empty($cancelTime) || $params['from'] == 'integral') {
  1659. $cancelTime = 0;
  1660. } else {
  1661. $cancelTime = strtotime($order['create_time']) + intval($cancelTime) * 60;
  1662. }
  1663. return [
  1664. 'pay_way' => array_values($payway),
  1665. 'order_amount' => $order['order_amount'],
  1666. 'cancel_time' => $cancelTime,
  1667. ];
  1668. }
  1669. /**
  1670. * @notes 查询物流
  1671. * @param $id
  1672. * @param $user_id
  1673. * @return array|false
  1674. * @throws \think\db\exception\DataNotFoundException
  1675. * @throws \think\db\exception\DbException
  1676. * @throws \think\db\exception\ModelNotFoundException
  1677. * @throws \think\exception\DbException
  1678. * @author suny
  1679. * @date 2021/7/13 6:23 下午
  1680. */
  1681. public static function orderTraces($id, $user_id)
  1682. {
  1683. $order = new Order();
  1684. $order = $order->alias('o')
  1685. ->join('order_goods og', 'o.id = og.order_id')
  1686. ->join('goods g', 'g.id = og.goods_id')
  1687. ->where(['o.id' => $id, 'o.user_id' => $user_id, 'pay_status' => OrderEnum::ORDER_STATUS_DELIVERY, 'o.del' => 0])
  1688. ->field('o.id,o.delivery_id,order_status,total_num,og.image,o.consignee,o.mobile,o.province,o.city,o.district,o.address,pay_time,confirm_take_time,o.shipping_status,shipping_time')
  1689. ->append(['delivery_address'])
  1690. ->find();
  1691. if (!self::checkDelivery($order['delivery_id'])) {
  1692. return false;
  1693. }
  1694. //初始化数据
  1695. $order_tips = '已下单';
  1696. $order_traces = [];
  1697. $traces = [];//物流轨迹
  1698. $shipment = [//发货
  1699. 'title' => '已发货',
  1700. 'tips' => '',
  1701. 'time' => '',
  1702. ];
  1703. $finish = [//交易完成
  1704. 'title' => '交易完成',
  1705. 'tips' => '',
  1706. 'time' => '',
  1707. ];
  1708. if ($order) {
  1709. $order_delivery = Delivery::where(['order_id' => $id])->field('invoice_no,shipping_name,shipping_id,mobile')->find();
  1710. $express = ConfigServer::get('express', 'way', '', '');
  1711. //已发货
  1712. if ($express && $order['shipping_status']) {
  1713. $key = ConfigServer::get($express, 'appkey');
  1714. $app = ConfigServer::get($express, 'appsecret');
  1715. //获取物流配置
  1716. if ($app && $key) {
  1717. //快递配置设置为快递鸟时
  1718. if ($express === 'kdniao') {
  1719. $expressage = (new Kdniao($app, $key, Env::get('app.app_debug', 'true')));
  1720. $shipping_field = 'codebird';
  1721. } else {
  1722. $expressage = (new Kd100($app, $key, Env::get('app.app_debug', 'true')));
  1723. $shipping_field = 'code100';
  1724. }
  1725. //快递编码
  1726. $shipping_code = Db::name('express')->where(['id' => $order_delivery['shipping_id']])->value($shipping_field);
  1727. //获取物流轨迹
  1728. if (in_array(strtolower($shipping_code ), [ 'sf', 'shunfeng' ])) {
  1729. if ($express === 'kdniao') {
  1730. $expressage->logistics($shipping_code, $order_delivery['invoice_no'], substr($order_delivery['mobile'],-4));
  1731. } else {
  1732. $expressage->logistics($shipping_code, $order_delivery['invoice_no'], $order_delivery['mobile']);
  1733. }
  1734. }else {
  1735. $expressage->logistics($shipping_code, $order_delivery['invoice_no']);
  1736. }
  1737. $traces = $expressage->logisticsFormat();
  1738. //获取不到物流轨迹时
  1739. if ($traces == false) {
  1740. $error = $expressage->getError();
  1741. $error = json_decode($error,true);
  1742. if ($express === 'kdniao') {
  1743. if($error['Success'] == false){
  1744. $traces[] = [$error['Reason']];
  1745. }
  1746. } else {
  1747. if($error['result'] == false){
  1748. $traces[] = [$error['message']];
  1749. }
  1750. }
  1751. } else {
  1752. foreach ($traces as &$item) {
  1753. $item = array_values(array_unique($item));
  1754. }
  1755. }
  1756. }
  1757. }
  1758. //待收货
  1759. if ($order['order_status'] == 2) {
  1760. $shipment['tips'] = '商品已出库';
  1761. $shipment['time'] = date('Y-m-d H:i:s', $order['shipping_time']);
  1762. }
  1763. //确认收货
  1764. if ($order['order_status'] == 3) {
  1765. $order_tips = '交易完成';
  1766. $finish['tips'] = '订单交易完成';
  1767. $finish['time'] = $order['confirm_take_time'] ? date('Y-m-d H:i:s', $order['confirm_take_time']) : $order['confirm_take_time'];
  1768. }
  1769. //数据合并
  1770. $order_traces = [
  1771. 'order' => [
  1772. 'tips' => $order_tips,
  1773. 'image' => UrlServer::getFileUrl($order['image']),
  1774. 'count' => $order['total_num'],
  1775. 'invoice_no' => $order_delivery['invoice_no'],
  1776. 'shipping_name' => empty($order_delivery['shipping_name']) ? '-' : $order_delivery['shipping_name'],
  1777. ],
  1778. 'take' => [
  1779. 'contacts' => $order['consignee'],
  1780. 'mobile' => $order['mobile'],
  1781. 'address' => $order['delivery_address'],
  1782. ],
  1783. 'finish' => $finish,
  1784. 'delivery' => [
  1785. 'title' => '运输中',
  1786. 'traces' => $traces
  1787. ],
  1788. 'shipment' => $shipment,
  1789. 'buy' => [
  1790. 'title' => '已下单',
  1791. 'tips' => '订单提交成功',
  1792. 'time' => date('Y-m-d H:i:s', $order['pay_time'])
  1793. ],
  1794. ];
  1795. return $order_traces;
  1796. }
  1797. return $order_traces;
  1798. }
  1799. /**
  1800. * @notes 配送方式无需快递的
  1801. * @param $delivery_id
  1802. * @return bool
  1803. * @throws \think\db\exception\DataNotFoundException
  1804. * @throws \think\db\exception\DbException
  1805. * @throws \think\db\exception\ModelNotFoundException
  1806. * @author suny
  1807. * @date 2021/7/13 6:23 下午
  1808. */
  1809. public static function checkDelivery($delivery_id)
  1810. {
  1811. $delivery = Delivery::where(['id' => $delivery_id])
  1812. ->find();
  1813. if ($delivery['send_type'] == 2) {
  1814. return false;
  1815. }
  1816. return true;
  1817. }
  1818. /**
  1819. * @notes 判断商家营业状态
  1820. * @param $value
  1821. * @return bool|string
  1822. * @author suny
  1823. * @date 2021/7/13 6:23 下午
  1824. */
  1825. public static function checkShop($value)
  1826. {
  1827. $shop = Shop::where('id', $value['shop_id'])->field('is_run, is_pay')->findOrEmpty();
  1828. if (!$shop['is_run']) {
  1829. return '该商家已暂停营业';
  1830. }
  1831. if (!$shop['is_pay']) {
  1832. return '该商家支付功能已关闭';
  1833. }
  1834. return true;
  1835. }
  1836. /**
  1837. * @notes 修改优惠券状态
  1838. * @param $coupon_id
  1839. * @param $order_id
  1840. * @return CouponList|false
  1841. * @throws \think\db\exception\DataNotFoundException
  1842. * @throws \think\db\exception\DbException
  1843. * @throws \think\db\exception\ModelNotFoundException
  1844. * @author suny
  1845. * @date 2021/7/13 6:23 下午
  1846. */
  1847. public static function editCoupon($coupon_id, $order_id)
  1848. {
  1849. $status = CouponList::where(['id' => $coupon_id, 'status' => 0])->find();
  1850. if (!$status) {
  1851. return false;
  1852. }
  1853. $time = time();
  1854. $data = [
  1855. 'status' => 1,
  1856. 'use_time' => $time,
  1857. 'update_time' => $time,
  1858. 'order_id' => $order_id
  1859. ];
  1860. $res = CouponList::where('id', $status->id)
  1861. ->update($data);
  1862. return $res;
  1863. }
  1864. /**
  1865. * @notes 设置秒杀商品销量
  1866. * @param $item_id
  1867. * @param $num
  1868. * @return bool
  1869. * @author suny
  1870. * @date 2021/7/13 6:23 下午
  1871. */
  1872. public static function setSeckillSaleSum($item_id, $num)
  1873. {
  1874. $result = SeckillGoods::where('item_id', $item_id)
  1875. ->inc('sales_sum', $num)
  1876. ->save();
  1877. if ($result) {
  1878. return true;
  1879. } else {
  1880. return false;
  1881. }
  1882. }
  1883. public static function getPayStatus($id,$from)
  1884. {
  1885. switch ($from){
  1886. case 'trade' : //如果是父订单类型下单,$id为父订单id
  1887. $order_trade = OrderTrade::alias('ot')
  1888. ->where(['ot.id' => $id])
  1889. ->join('order o','o.trade_id = ot.id')
  1890. ->field(['ot.id','o.id as order_id', 'ot.t_sn as order_sn', 'o.pay_time', 'o.pay_way', 'ot.total_amount','o.pay_status','o.order_status'])
  1891. ->select()
  1892. ->toArray();
  1893. foreach ($order_trade as $item) {
  1894. if($item['pay_time']){
  1895. $item['pay_time'] = date('Y-m-d H:i:s', $item['pay_time']);
  1896. }
  1897. $create_time = Db::name('order')->where(['id' => $item['order_id']])->value('create_time');
  1898. $unpaid_order_cancel_time = ConfigServer::get('transaction','unpaid_order_cancel_time',60);
  1899. $cancel_time = $create_time + $unpaid_order_cancel_time * 60;
  1900. $item['pay_status_text'] = PayEnum::getPayStatus($item['pay_status']);
  1901. $result = $item;
  1902. $goods_lists = Db::name('order_goods')
  1903. ->where(['order_id' => $item['order_id']])
  1904. ->field('id,goods_name')
  1905. ->order('shop_id desc')
  1906. ->select()
  1907. ->toArray();
  1908. foreach ($goods_lists as $goods_list) {
  1909. $order_goods[] = $goods_list;
  1910. }
  1911. $order = Order::where(['id' => $item['order_id']])
  1912. ->find()
  1913. ->append(['pc_address'])
  1914. ->toArray();
  1915. $contact = $order['consignee'];
  1916. $mobile = $order['mobile'];
  1917. $address = [
  1918. 'contact' => $contact,
  1919. 'mobile' => $mobile,
  1920. 'delivery_address' => $order['pc_address'],
  1921. ];
  1922. $pay_way_text = PayEnum::getPayWay($item['pay_way']);
  1923. $result['pay_way'] = $pay_way_text;
  1924. $result['cancel_time'] = $cancel_time;
  1925. }
  1926. $result['order_goods'] = $order_goods;
  1927. $result['address'] = $address;
  1928. break;
  1929. case 'order' : //如果是子订单类型下单,$id为子订单id
  1930. $result = Order::where(['id' => $id])
  1931. ->field(['id', 'order_sn', 'pay_time', 'pay_way', 'total_amount','consignee','mobile','province','city','district','address','pay_status','order_status'])
  1932. ->findOrEmpty()
  1933. ->append(['pc_address'])
  1934. ->toArray();
  1935. $create_time = Db::name('order')->where(['id' => $id])->value('create_time');
  1936. $unpaid_order_cancel_time = ConfigServer::get('transaction','unpaid_order_cancel_time',60);
  1937. $cancel_time = $create_time + $unpaid_order_cancel_time * 60;
  1938. $order_goods = Db::name('order_goods')
  1939. ->where(['order_id' => $result['id']])
  1940. ->field('id,goods_name')
  1941. ->order('shop_id desc')
  1942. ->select()
  1943. ->toArray();
  1944. $contact = $result['consignee'];
  1945. $mobile = $result['mobile'];
  1946. $address = [
  1947. 'contact' => $contact,
  1948. 'mobile' => $mobile,
  1949. 'delivery_address' => $result['pc_address'],
  1950. ];
  1951. $result['order_goods'] = $order_goods;
  1952. $result['address'] = $address;
  1953. $result['cancel_time'] = $cancel_time;
  1954. $result['pay_time'] = empty($result['pay_time']) ? '-' : date('Y-m-d H:i:s', $result['pay_time']);
  1955. break;
  1956. default :
  1957. return false;
  1958. }
  1959. return $result;
  1960. }
  1961. }