Orders.php 54 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058
  1. <?php namespace App\Http\Controllers\Api;
  2. use App\Http\Controllers\Api\Api;
  3. use App\Models\Orders as Model;
  4. use App\Models\Product;
  5. use App\Models\Product\Skus as ProductSkus;
  6. use App\Http\Requests\Api\Orders as Request;
  7. use App\Models\Business;
  8. use App\Models\City;
  9. use App\Models\Custom;
  10. use App\Models\CustomAddr;
  11. use App\Models\CustomCoupon;
  12. use App\Models\CustomScore;
  13. use App\Models\OrdersAddr;
  14. use App\Models\OrdersProduct;
  15. use App\Models\Regiment;
  16. use App\Models\RegimentActive;
  17. use App\Models\RegimentRecord;
  18. use App\Models\ShopCart;
  19. use Illuminate\Support\Facades\DB;
  20. use App\Models\WeiBan\Tags as WeiBanTags;
  21. use App\Models\PromoProduct as PromoProduct;
  22. /**
  23. * 订单接口
  24. *
  25. * @author 刘相欣
  26. *
  27. * */
  28. class Orders extends Api{
  29. /**
  30. * 创建订单 /api/orders/create
  31. *
  32. * */
  33. public function create(Request $request,Custom $Custom,City $City,Model $Model,WeiBanTags $WeiBanTags,OrdersAddr $OrdersAddr,OrdersProduct $OrdersProduct,Product $Product,ProductSkus $ProductSkus,CustomCoupon $CustomCoupon,ShopCart $ShopCart,CustomAddr $CustomAddr,CustomScore $CustomScore,PromoProduct $PromoProduct){
  34. // 接口验签
  35. // $this->verify_sign();
  36. // 验证参数
  37. $request->scene('create')->validate();
  38. // 检查登录
  39. $uid = $this->checkLogin();
  40. // 接收参数
  41. $isCart = request('is_cart',0);
  42. $productList = request('product_list','[]');
  43. $customCouponId = request('custom_coupon_id',0);
  44. $addrId = request('addr_id',0);
  45. // 如果不存在数据
  46. if( !$addrId ) return json_send(['code'=>'error','msg'=>'请选择收货地址','data'=>['error'=>'请选择收货地址']]);
  47. // 解码购买信息
  48. $buyList = json_decode($productList,true);
  49. // 如果不存在数据
  50. if( empty($buyList) ) return json_send(['code'=>'error','msg'=>'没有需下单的产品','data'=>['error'=>'产品列表为空']]);
  51. // 选择地址
  52. $addr = $CustomAddr->getOne($addrId);
  53. // 如果不存在数据
  54. if( !$addr ) return json_send(['code'=>'error','msg'=>'地址有误,请核对','data'=>['error'=>'没有找到对应的地址']]);
  55. // 如果不存在的话
  56. if( !$addr['contact_shop'] ) return json_send(['code'=>'error','msg'=>'请在店铺名称处填写具体药店名称','data'=>['error'=>'所用地址请补充店铺名称']]);
  57. // 重组数据
  58. $addr = ['contact_name'=>$addr['contact_name'],'contact_shop'=>$addr['contact_shop'],'shop_type'=>$addr['shop_type'],'contact_phone'=>$addr['contact_phone'],'contact_province'=>$addr['contact_province'],'contact_city'=>$addr['contact_city'],'contact_area'=>$addr['contact_area'],'contact_addr'=>$addr['contact_addr']];
  59. // 获取客户城市ID
  60. $custom = $Custom->getOne($uid);
  61. // 如果不存在的话
  62. if( !$custom ) return json_send(['code'=>'no_login','msg'=>'用户不存在,请重新登录','data'=>['error'=>'用户不存在,请重新登录']]);
  63. // 如果不存在的话
  64. if( !$custom['city_id'] ) return json_send(['code'=>'error','msg'=>'请选择所在城市后下单','data'=>['error'=>'请选择所在城市后下单']]);
  65. // 获取城市ID
  66. $cityId = $custom['city_id'];
  67. $cityName = $City->getOne($cityId,'name');
  68. $pid = $City->getOne($cityId,'pid');
  69. // 如果上级不是省份
  70. if( strlen($cityId) > 4 ) $pid = (int) $City->getOne($pid,'pid');
  71. $province = $City->getOne($pid,'name');
  72. // 如果不是海南,
  73. if( $province != '海南省' ) {
  74. // 判断选择的城市名称是不是一致
  75. if( trim($cityName) != trim($addr['contact_city']) ) return json_send(['code'=>'error','msg'=>'收货地址请选择'.($province=='直辖县级'?$cityName:$province).'/'.$cityName,'data'=>['error'=>'收货地址需与您所选城市一致']]);
  76. }else{
  77. if( trim($addr['contact_province']) != trim($province) ) return json_send(['code'=>'error','msg'=>'收货地址请选择海南范围','data'=>['error'=>'收货地址需与您所选城市一致']]);
  78. }
  79. // 商品购买数量
  80. $buyNum = [];
  81. // 循环购买信息
  82. foreach ($buyList as $key => $value) {
  83. // 获取每个商品的总量
  84. $buyNum[$value['product_id']] = isset($buyNum[$value['product_id']]) ? ($buyNum[$value['product_id']] + $value['buy_num']) : $value['buy_num'];
  85. }
  86. // 查询用户标签
  87. $tags = $WeiBanTags->getListByWeibanExtid($custom['weiban_extid']);
  88. // 查询产品信息
  89. $productList = $Product->getListByIds(array_column($buyList,'product_id'),[1,$cityId]);
  90. $skusList = $ProductSkus->getListByIds(array_column($buyList,'product_skuid'));
  91. // 当前时间
  92. $time = time();
  93. // 产品以店铺分组,方便写入订单
  94. $orderProduct = [];
  95. // 产品价格同级,用于优惠券计算
  96. $productPrice = [];
  97. // 循环处理购买信息
  98. foreach ($buyList as $buyInfo) {
  99. // 如果产品不存在
  100. if( empty($productList[$buyInfo['product_id']]) ) return json_send(['code'=>'error','msg'=>'产品不存在或已下架','data'=>['error'=>'产品不存在或已下架=>'.$buyInfo['product_id']]]);
  101. // 获取产信息
  102. $productInfo = $productList[$buyInfo['product_id']];
  103. // 判断是不是可以参与
  104. if( $productInfo['tag_scope'] ) {
  105. // 解析数组
  106. $productInfo['tag_scope'] = explode(',',$productInfo['tag_scope']);
  107. // 标签范围限定时,默认不能参与
  108. $allowJoin = 0;
  109. // 判断标签是不是存在
  110. foreach ($tags as $value) {
  111. // 标签范围内,允许参加
  112. if( in_array($value['name'],$productInfo['tag_scope']) ) $allowJoin = 1;
  113. }
  114. // 如果不能参与
  115. if( !$allowJoin ) return json_send(['code'=>'error','msg'=>'不在 '.$productInfo['product_name'].' 参与范围','data'=>['error'=>'不在标签范围内']]);
  116. }
  117. // 判断是不是可以参与
  118. if( $productInfo['tag_exclude'] ) {
  119. // 解析数组
  120. $productInfo['tag_exclude'] = explode(',',$productInfo['tag_exclude']);
  121. // 判断标签是不是存在
  122. foreach ($tags as $value) {
  123. // 标签排除范围内,不允许参加
  124. if( in_array($value['name'],$productInfo['tag_exclude']) ) return json_send(['code'=>'error','msg'=>'不在 '.$productInfo['product_name'].' 可参与范围','data'=>['error'=>'用户在标签排除范围']]);
  125. }
  126. }
  127. // 如果产品限购
  128. if( $productInfo['quota'] ) {
  129. // 是否在限购时间,当前时间大于开始时间,并且小于结束时间
  130. if( $productInfo['quota_start'] <= $time && $time <= $productInfo['quota_end'] ){
  131. // 通过时间查询商品的购买总数
  132. $total = $OrdersProduct->query()->whereIn('status',[0,1,2,3,8,9])->where([['custom_uid','=',$uid],['is_rebate','=',0],['product_id','=',$productInfo['id']],['insert_time','>=',$productInfo['quota_start']],['insert_time','<=',$productInfo['quota_end']]])->sum('buy_num');
  133. // 判断限购数量
  134. $total = $buyNum[$buyInfo['product_id']] + $total;
  135. // 如果超过数量
  136. if( $total > $productInfo['quota'] ) return json_send(['code'=>'error','msg'=>'限购'.$productInfo['quota'].'单-'.$productInfo['product_name'],'data'=>['error'=>'已超限=>'.($total - $productInfo['quota'])]]);
  137. }
  138. }
  139. // 如果有限制产品的SKU起购规则是与
  140. if( $productInfo['sku_min_quota_and'] ){
  141. // 查询该产品的所有SKU
  142. $skuMin = $ProductSkus->getListByProductId($productInfo['id']);
  143. // 循环产品的SKU
  144. foreach ($skuMin as $key => $value) {
  145. // 如果SKU不限制起购数量,跳过
  146. if( !$value['min_quota'] ) continue;
  147. // 如果限购的SKU不在购买列表中
  148. if( !in_array($value['id'],array_column($buyList,'product_skuid')) ) return json_send(['code'=>'error','msg'=>'请搭配'.$productInfo['product_name'].'【'.$value['attr_names'].'】下单','data'=>['error'=>'最少购买'.$value['min_quota'].'单-'.$productInfo['product_name']]]);;
  149. // 如果购买数量小于最低起购数量
  150. foreach ($buyList as $item) {
  151. // 如果SKU不匹配,跳过
  152. if( $item['product_skuid'] != $value['id'] ) continue;
  153. // 如果购买数量小于最低起购数量
  154. if( $item['buy_num'] < $value['min_quota'] ) return json_send(['code'=>'error','msg'=>'最少购买'.$value['min_quota'].'单-'.$productInfo['product_name'].'【'.$value['attr_names'].'】','data'=>['error'=>'最少购买'.$value['min_quota'].'单-'.$productInfo['product_name']]]);
  155. }
  156. }
  157. }
  158. // 如果存在SKU
  159. if( $buyInfo['product_skuid'] ) {
  160. // 判断SKU信息存不存在
  161. if( empty($skusList[$buyInfo['product_skuid']]) ) return json_send(['code'=>'error','msg'=>'该产品规格不存在或已下架','data'=>['error'=>'SKU不存在或已下架=>'.$buyInfo['product_skuid']]]);
  162. // 产品ID不匹配的话
  163. if( $skusList[$buyInfo['product_skuid']]['product_id'] != $buyInfo['product_id'] ) return json_send(['code'=>'error','msg'=>'该产品规格不存在或已下架','data'=>['error'=>'SKU不匹配=>'.$buyInfo['product_skuid']]]);
  164. // SKU信息
  165. $skuInfo = $skusList[$buyInfo['product_skuid']];
  166. // 如果产品有最低起购
  167. if( $skuInfo['min_quota'] ) {
  168. // 如果购买数量小于最低起购数量
  169. if( $buyInfo['buy_num'] < $skuInfo['min_quota'] ){
  170. // 如果超过数量
  171. return json_send(['code'=>'error','msg'=>'最少购买'.$skuInfo['min_quota'].'单-'.$productInfo['product_name'].'【'.$skuInfo['sku_attr_names'].'】','data'=>['error'=>'最少购买'.$skuInfo['min_quota'].'单-'.$productInfo['product_name']]]);
  172. }
  173. }
  174. // 如果SKU限购
  175. if( $skuInfo['quota'] ) {
  176. // 是否在限购时间,当前时间大于开始时间,并且小于结束时间
  177. if( $productInfo['quota_start'] <= $time && $time <= $productInfo['quota_end'] ){
  178. // 通过时间查询商品的购买总数
  179. $total = $OrdersProduct->query()->whereIn('status',[0,1,2,3,8,9])->where([['custom_uid','=',$uid],['is_rebate','=',0],['product_id','=',$productInfo['id']],['sku_attr_names','=',$skuInfo['sku_attr_names']],['insert_time','>=',$productInfo['quota_start']],['insert_time','<=',$productInfo['quota_end']]])->sum('buy_num');
  180. // 判断限购数量
  181. $total = $buyInfo['buy_num'] + $total;
  182. // 如果超过数量
  183. if( $total > $skuInfo['quota'] ) return json_send(['code'=>'error','msg'=>'限购'.$skuInfo['quota'].'单-'.$productInfo['product_name'].'【'.$skuInfo['sku_attr_names'].'】','data'=>['error'=>'已超限=>'.($total - $skuInfo['quota'])]]);
  184. }
  185. }
  186. // 删除起购字段,避免影响后续产品最低起购的判定
  187. unset($skuInfo['min_quota']);
  188. // 如果SKU存在,合并产品信息
  189. $productInfo = array_merge($productInfo,$skuInfo);
  190. // 需要扣除的库存
  191. $skusList[$buyInfo['product_skuid']]['decr'] = empty($skusList[$buyInfo['product_skuid']]['decr']) ? $buyInfo['buy_num'] : $skusList[$buyInfo['product_skuid']]['decr'] + $buyInfo['buy_num'];
  192. }
  193. // 如果产品有最低起购
  194. if( $productInfo['min_quota'] ) {
  195. // 如果购买数量小于最低起购数量
  196. if( $buyNum[$buyInfo['product_id']] < $productInfo['min_quota'] ){
  197. // 如果超过数量
  198. return json_send(['code'=>'error','msg'=>'最少购买'.$productInfo['min_quota'].'单-'.$productInfo['product_name'],'data'=>['error'=>'最少购买'.$productInfo['min_quota'].'单-'.$productInfo['product_name']]]);
  199. }
  200. }
  201. // 需要扣除的库存
  202. $productList[$buyInfo['product_id']]['decr'] = empty($productList[$buyInfo['product_id']]['decr']) ? $buyInfo['buy_num'] : $productList[$buyInfo['product_id']]['decr'] + $buyInfo['buy_num'];
  203. // 判断库存
  204. if( $productInfo['stock'] < $productList[$buyInfo['product_id']]['decr'] ) return json_send(['code'=>'error','msg'=>$productInfo['product_name'].'-库存不足','data'=>['error'=>'产品库存不足=>'.$buyInfo['product_id']]]);
  205. // 计算价值
  206. $priceTotal = $buyInfo['buy_num'] * $productInfo['price'];
  207. // 购买信息
  208. $buyInfo = ['is_rebate'=>0,'custom_uid'=>$uid,'business_id'=>$productInfo['business_id'],'product_id'=>$buyInfo['product_id'],'buy_num'=>$buyInfo['buy_num'],'price_total'=>$priceTotal,'pay_total'=>$priceTotal,'coupon_total'=>0,'product_name'=>$productInfo['product_name'],'sku_attr_names'=>$productInfo['sku_attr_names'],'product_thumb'=>$productInfo['product_thumb']];
  209. // 获取信息
  210. if( !isset($orderProduct[$buyInfo['business_id']]) ) $orderProduct[$buyInfo['business_id']] = ['business_id'=>$buyInfo['business_id'],'custom_uid'=>$buyInfo['custom_uid'],'price_total'=>0,'pay_total'=>0,'coupon_total'=>0,'product_list'=>[]];
  211. // 订单产品
  212. $orderProduct[$buyInfo['business_id']]['price_total'] += $buyInfo['price_total'];
  213. $orderProduct[$buyInfo['business_id']]['pay_total'] += $buyInfo['price_total'];
  214. $orderProduct[$buyInfo['business_id']]['product_list'][] = $buyInfo;
  215. // 商品优惠信息不存在,创建
  216. if( !isset($productPrice[$buyInfo['product_id']]) ) $productPrice[$buyInfo['product_id']] = ['price_total'=>0,'rebate_price'=>0];
  217. // 计算总价
  218. $productPrice[$buyInfo['product_id']]['price_total'] = $productPrice[$buyInfo['product_id']]['price_total'] + $priceTotal;
  219. }
  220. // 优惠券数据
  221. $couponRebate = $CustomCoupon->getRebatePrice($customCouponId,$uid,$productPrice);
  222. // 判断是否使用了优惠券
  223. $usedCoupon = $couponRebate['is_used'];
  224. // 获取优惠券扣减金额
  225. $productPrice = $couponRebate['product_price'];
  226. // 获取优惠券赠品信息
  227. $rebateProduct = $couponRebate['rebate_product'];
  228. /*活动优惠数据*/
  229. $promoList = $PromoProduct->getRebatePrice(array_column($buyList,'product_id'),$uid,$productPrice,$cityId,$tags);
  230. $promoProductPrice = $promoList['product_price'];
  231. $promoRebateProduct = $promoList['rebate_product'];
  232. // 组合订单数据
  233. foreach ($orderProduct as $key => $order) {
  234. // 判断哪一家的赠品
  235. if( isset($rebateProduct[$order['business_id']]) ){
  236. // 循环赠品
  237. foreach ( $rebateProduct[$order['business_id']] as $value) {
  238. // 没有对应的产品
  239. if( !isset($productList[$value['product_id']]) ) $productList[$value['product_id']] = ['id'=>$value['id'],'stock'=>$value['stock']];
  240. // 判断库存,如果库存不足,只赠送最后的库存
  241. if( $productList[$value['product_id']]['stock'] <= $value['buy_num'] ) $value['buy_num'] = $productList[$value['product_id']]['stock'];
  242. // 库存扣减
  243. $productList[$value['product_id']]['decr'] = empty($productList[$value['product_id']]['decr']) ? $value['buy_num'] : $productList[$value['product_id']]['decr'] + $value['buy_num'];
  244. // 追加到订单表
  245. $order['product_list'][] = ['is_rebate'=>1,'custom_uid'=>$uid,'business_id'=>$value['business_id'],'product_id'=>$value['product_id'],'buy_num'=>$value['buy_num'],'price_total'=>$value['price_total'],'pay_total'=>$value['pay_total'],'coupon_total'=>$value['coupon_total'],'product_name'=>$value['product_name'],'sku_attr_names'=>$value['sku_attr_names'],'product_thumb'=>$value['product_thumb']];
  246. }
  247. }
  248. // 促销活动判断哪一家的赠品
  249. if( isset($promoRebateProduct[$order['business_id']]) ){
  250. // 循环赠品
  251. foreach ( $promoRebateProduct[$order['business_id']] as $value) {
  252. // 没有对应的产品
  253. if( !isset($productList[$value['product_id']]) ) $productList[$value['product_id']] = ['id'=>$value['product_id'],'stock'=>$value['stock']];
  254. // 判断库存,如果库存不足,只赠送最后的库存
  255. if( $productList[$value['product_id']]['stock'] <= $value['buy_num'] ) $value['buy_num'] = $productList[$value['product_id']]['stock'];
  256. // 库存扣减
  257. $productList[$value['product_id']]['decr'] = empty($productList[$value['product_id']]['decr']) ? $value['buy_num'] : $productList[$value['product_id']]['decr'] + $value['buy_num'];
  258. // 追加到订单表
  259. $order['product_list'][] = ['is_rebate'=>1,'custom_uid'=>$uid,'business_id'=>$value['business_id'],'product_id'=>$value['product_id'],'buy_num'=>$value['buy_num'],'price_total'=>$value['price_total'],'pay_total'=>$value['pay_total'],'coupon_total'=>$value['coupon_total'],'sku_attr_names'=>$value['sku_attr_names'],'product_name'=>$value['name'],'product_thumb'=>$value['thumb']];
  260. }
  261. }
  262. // 计算总价格
  263. foreach ($order['product_list'] as $k=>$product) {
  264. //促销活动扣减
  265. if (isset($promoProductPrice[$product['product_id']]['promo_rebate_price']) && $promoProductPrice[$product['product_id']]['promo_rebate_price']> 0){
  266. // 当前商品的优惠折扣计算
  267. $product['coupon_total'] = number_format( $promoProductPrice[$product['product_id']]['rebate_price'] * ($product['price_total'] / $promoProductPrice[$product['product_id']]['price_total']) , 2 , '.' ,'');
  268. // 总优惠增加
  269. $order['coupon_total'] = $order['coupon_total'] + $product['coupon_total'];
  270. // 成交小计
  271. $product['pay_total'] = $product['pay_total'] - $product['coupon_total'];
  272. }
  273. // 商品不存在,不进行扣减
  274. if( empty($productPrice[$product['product_id']]['rebate_price']) ) {
  275. // 重组
  276. $order['product_list'][$k] = $product;
  277. continue;
  278. }
  279. // 当前商品的优惠折扣计算
  280. $product['coupon_total'] = number_format( $productPrice[$product['product_id']]['rebate_price'] * ($product['price_total'] / $productPrice[$product['product_id']]['price_total']) , 2 , '.' ,'');
  281. // 总优惠增加
  282. $order['coupon_total'] = $order['coupon_total'] + $product['coupon_total'];
  283. // 成交小计
  284. $product['pay_total'] = $product['pay_total'] - $product['coupon_total'];
  285. // 重组
  286. $order['product_list'][$k] = $product;
  287. }
  288. // 成交总价
  289. $order['pay_total'] = $order['pay_total'] - $order['coupon_total'];
  290. // 赠送积分
  291. $order['order_score'] = (config('order_score_send',0) && floor( $order['pay_total'] * 1 ) > 0 ) ? floor( $order['pay_total'] * 1 ) : 0;
  292. // 成交总价
  293. $order['custom_uid'] = $uid;
  294. // 重组
  295. $orderProduct[$key] = $order;
  296. }
  297. // 组合数据,写入订单表,子表
  298. DB::beginTransaction();
  299. // 写入数据
  300. try {
  301. // 扣减商品库存
  302. foreach ($productList as $key => $value) {
  303. // 扣减库存
  304. $result = $Product->edit($value['id'],['stock'=>DB::raw('stock+-'.$value['decr'])]);
  305. // 判断结果
  306. if( !$result ) {
  307. // 回退数据
  308. DB::rollBack();
  309. // 错误提示
  310. return json_send(['code'=>'error','msg'=>'库存扣减失败','data'=>['error'=>'库存扣减失败']]);
  311. }
  312. }
  313. // 扣减商品库存
  314. foreach ($skusList as $key => $value) {
  315. // 扣减库存
  316. $result = $ProductSkus->edit($value['sku_id'],['stock'=>DB::raw('stock+-'.$value['decr'])]);
  317. // 判断结果
  318. if( !$result ) {
  319. // 回退数据
  320. DB::rollBack();
  321. // 错误提示
  322. return json_send(['code'=>'error','msg'=>'库存扣减失败','data'=>['error'=>'库存扣减失败']]);
  323. }
  324. }
  325. // 循环订单数据
  326. foreach ($orderProduct as $order) {
  327. // 先获取产品列表,并去除key
  328. $productItem = array_values($order['product_list']);
  329. // 删除非必要数据
  330. unset($order['product_list']);
  331. // 创建总订单
  332. $orderId = $Model->add($order);
  333. // 如果订单写入失败
  334. if( !$orderId ) {
  335. // 回退数据
  336. DB::rollBack();
  337. // 错误提示
  338. return json_send(['code'=>'error','msg'=>'下单失败','data'=>['error'=>'订单创建失败']]);
  339. }
  340. // 创建子订单
  341. foreach ($productItem as $key=>$value) {
  342. // 增加订单ID
  343. $value['order_id'] = $orderId;
  344. // 增加订单ID
  345. $value['insert_time']= $time;
  346. $value['update_time']= $time;
  347. // 结果
  348. $productItem[$key] = $value;
  349. }
  350. // 写入子表
  351. $result = $OrdersProduct->query()->insert($productItem);
  352. // 如果扣减失败
  353. if( !$result ) {
  354. // 回退数据
  355. DB::rollBack();
  356. // 提示信息
  357. return json_send(['code'=>'error','msg'=>'子订单创建失败','data'=>['error'=>'子订单创建失败']]);
  358. }
  359. // 写入订单地址表
  360. $addr['order_id'] = $orderId;
  361. // 写入订单地址表
  362. $result = $OrdersAddr->add($addr);
  363. // 地址写入失败
  364. if( !$result ) {
  365. // 回退数据
  366. DB::rollBack();
  367. // 提示信息
  368. return json_send(['code'=>'error','msg'=>'地址写入失败','data'=>['error'=>'地址写入失败']]);
  369. }
  370. // 赠送积分
  371. if( $order['order_score'] > 0 ) $CustomScore->trade($order['custom_uid'],$orderId,$order['order_score'],5,1);
  372. // 如果使用了优惠券
  373. if( $usedCoupon ) $CustomCoupon->edit($usedCoupon,['status'=>1,'order_id'=>$orderId]);
  374. // 购物车
  375. if( $isCart ) $ShopCart->query()->where([['custom_uid','=',$uid]])->whereIn('skuid',array_column($buyList,'product_skuid'))->delete();
  376. }
  377. // 自动发放优惠券
  378. $this->autoCoupon($uid);
  379. // 提交数据
  380. DB::commit();
  381. // 返回结果
  382. return json_send(['code'=>'success','msg'=>'下单成功','data'=>['id'=>null]]);
  383. // 返回结果
  384. } catch (\Throwable $th) {
  385. // 回退数据
  386. DB::rollBack();
  387. // 判断结果,如果库存扣减失败的话
  388. if( stripos($th->getMessage(),'UNSIGNED') ) return json_send(['code'=>'error','msg'=>'库存不足','data'=>['error'=>'产品库存扣减失败']]);
  389. // 下单失败提示
  390. return json_send(['code'=>'error','msg'=>'系统异常,请稍后再试','data'=>['error'=>$th->getMessage().$th->getLine()]]);
  391. }
  392. }
  393. /**
  394. * 获取列表 /api/orders/get_list
  395. *
  396. * @param string $name 产品名称
  397. * @param int $page 页码,默认1
  398. * @param int $limit 每页条数,默认10条
  399. *
  400. * */
  401. public function get_list(Request $request, Model $Model, OrdersProduct $OrdersProduct, Business $Business){
  402. // 接口验签
  403. // $this->verify_sign();
  404. // 验证参数
  405. $request->scene('get_list')->validate();
  406. // 检查登录
  407. $uid = $this->checkLogin();
  408. // 接收参数
  409. $status = request('status',0);
  410. $limit = request('limit',10);
  411. // 显示
  412. $map = [['custom_uid','=',$uid]];
  413. // 查询状态
  414. if( $status ) $map[] = ['status','=',$status];
  415. // 查询
  416. $Paginator = $Model->query()->where($map)->orderByDesc('id')->paginate($limit,['id','pay_total','status','price_total','coupon_total','business_id','pay_total','weizan_orderid','insert_time']);
  417. // 订单产品
  418. $productList = $OrdersProduct->query()->whereIn('order_id', array_column($Paginator->items(),'id'))->select(['id as item_id','order_id','product_id','buy_num','is_rebate','sku_attr_names as product_spec','product_name','product_thumb'])->get()->toArray();
  419. // 循环处理
  420. foreach ($Paginator as $key => $order) {
  421. // 商品列表
  422. $itemList = [];
  423. // 返回结果
  424. foreach ($productList as $item) {
  425. // 产品图路径
  426. $item['product_thumb'] = path_compat($item['product_thumb']);
  427. // 如果是订单的
  428. if( $item['order_id'] == $order['id'] ) $itemList[] = $item;
  429. }
  430. // 获取子列表
  431. $order['state'] = (string) $Model->getState($order['status'],'state');
  432. // 获取子列表
  433. $order['business_name'] = (string) ($order['business_id'] ? $Business->getOne($order['business_id'],'name') : ($order['weizan_orderid'] ? '微赞订单' : ''));
  434. // 获取子列表
  435. $order['contents_class']= 0;
  436. // 获取子列表
  437. $order['product_list'] = $itemList;
  438. // 重组
  439. $Paginator[$key] = $order;
  440. }
  441. // 获取数据
  442. $data['total'] = $Paginator->total();
  443. $data['current_page'] = $Paginator->currentPage();
  444. $data['per_page'] = $Paginator->perPage();
  445. $data['last_page'] = $Paginator->lastPage();
  446. $data['data'] = $Paginator->items();
  447. // 返回结果
  448. return json_send(['code'=>'success','msg'=>'获取成功','data'=>$data]);
  449. }
  450. /**
  451. * 自动发放优惠券
  452. *
  453. */
  454. private function autoCoupon($uid){
  455. // 模型实例
  456. $Rule = new \App\Models\CouponRewardRule();
  457. // 获取配置列表
  458. $ruleList = $Rule->getList();
  459. // 如果没有信息的话
  460. if( !$ruleList ) return ['success'=>'暂无活动'];
  461. // 其他实例
  462. $RuleProduct = new \App\Models\CouponRewardProduct();
  463. $OrdersProduct = new \App\Models\OrdersProduct();
  464. $Custom = new \App\Models\Custom();
  465. $Coupon = new \App\Models\Coupon();
  466. $CustomCoupon = new \App\Models\CustomCoupon();
  467. // 获取客户城市ID
  468. $customCityId = (int) $Custom->getValue($uid,'city_id');
  469. // 循环配置列表
  470. foreach ( $ruleList as $value ) {
  471. // 如果存在城市范围,并且不在城市范围,不参与这个活动
  472. if( $value['city_ids'] && !in_array($customCityId,explode(',',$value['city_ids'])) ) continue;
  473. // 未到开始时间
  474. if( $value['start_time'] > time() ) continue;
  475. // 通过配置ID获取对应的商品范围
  476. $productList = $RuleProduct->getListByRule($value['id']);
  477. // 如果不存在产品范围,跳过
  478. if( !$productList ) continue;
  479. // 获取客户 规定时段内订单的商品ID以及购买数量
  480. $orderList = $OrdersProduct->query()->where([['custom_uid','=',$uid],['status','=',1],['insert_time','>=',$value['start_time']],['insert_time','<=',$value['end_time']]])->get(['product_id','buy_num'])->toArray();
  481. // 如果没有订单总数
  482. if( !$orderList ) continue;
  483. // 计算商品总量
  484. $total = 0;
  485. // 循环商品范围
  486. foreach ($productList as $scope) {
  487. // 循环订单产品
  488. foreach ($orderList as $order) {
  489. // 如果产品不相等
  490. if( $scope['product_id'] != $order['product_id'] ) continue;
  491. // 相等的计算总量
  492. $total += $scope['product_units'] * $order['buy_num'];
  493. }
  494. }
  495. // 判断总数是不是达标
  496. if( $total < $value['std_num'] ) continue;
  497. if ($value['coupon_id']){
  498. $couponIdArray = explode(',',$value['coupon_id']);
  499. foreach ($couponIdArray as $couponId) {
  500. // 达标的是否已经发送过优惠券
  501. $havaCoupon = $CustomCoupon->query()->where([['custom_uid','=',$uid],['coupon_id','=',$couponId]])->first(['status']);
  502. // 已经发过优惠券的,不发
  503. if( $havaCoupon ) continue;
  504. // 获取优惠券的可用时间
  505. $expTime = $Coupon->query()->where([['id','=',$couponId]])->value('exp_time');
  506. // 时间转时间
  507. $expTime = $Coupon->getExpTime($expTime);
  508. // 发送优惠券
  509. $CustomCoupon->add(['coupon_id'=>$couponId,'custom_uid'=>$uid,'exp_time'=>$expTime]);
  510. }
  511. }
  512. }
  513. // 返回成功
  514. return ['success'=>'操作成功'];
  515. }
  516. /**
  517. * 取消 /api/orders/cancel
  518. *
  519. * */
  520. public function cancel( Request $request, Model $Model,OrdersProduct $OrdersProduct,CustomScore $CustomScore){
  521. // 验证参数
  522. $request->scene('cancel')->validate();
  523. // 检查登录
  524. $uid = $this->checkLogin();
  525. // 接收参数
  526. $id = request('id',0);
  527. $status = 4;
  528. // 获取产品和数量
  529. $oldData = $Model->query()->where([['id','=',$id],['custom_uid','=',$uid]])->first(['id','order_score','status','custom_uid','insert_time']);
  530. // 如果用户不存在
  531. if( !$oldData ) return json_send(['code'=>'error','msg'=>'订单不存在']);
  532. // 如果已经取消
  533. if( $oldData['status'] == 4 ) return json_send(['code'=>'error','msg'=>'订单已取消']);
  534. // 组合数据,写入订单表,子表
  535. DB::beginTransaction();
  536. try{
  537. // 查询数据
  538. $result = $Model->setOrderStatus($id,$status,$OrdersProduct);
  539. // 提示新增失败
  540. if( isset($result['error']) ) {
  541. // 回退数据
  542. DB::rollBack();
  543. // 提示信息
  544. return json_send(['code'=>'error','msg'=>$result['error'],'data'=>['error'=>$result['error']]]);
  545. }
  546. if( $status == 4 ){
  547. // 取消积分
  548. if( $oldData['order_score'] > 0 ) {
  549. // 如果扣减失败
  550. $result = $CustomScore->trade($oldData['custom_uid'],$oldData['id'],($oldData['order_score']*-1),6,1);
  551. // 提示新增失败
  552. if( isset($result['error']) ) {
  553. // 回退数据
  554. DB::rollBack();
  555. // 提示信息
  556. return json_send(['code'=>'error','msg'=>'取消赠送积分失败','data'=>['error'=>$result['error']]]);
  557. }
  558. }
  559. // 取消关联订单
  560. $result = $Model->cancelRelate($oldData['insert_time'],$oldData['custom_uid'],$OrdersProduct,$CustomScore);
  561. // 提示新增失败
  562. if( isset($result['error']) ) {
  563. // 回退数据
  564. DB::rollBack();
  565. // 提示信息
  566. return json_send(['code'=>'error','msg'=>'取消关联订单失败','data'=>['error'=>$result['error']]]);
  567. }
  568. }
  569. // 提交数据
  570. DB::commit();
  571. // 告知结果
  572. return json_send(['code'=>'success','msg'=>'取消成功']);
  573. // 返回结果
  574. } catch (\Throwable $th) {
  575. // 回退数据
  576. DB::rollBack();
  577. // 下单失败提示
  578. return json_send(['code'=>'error','msg'=>'取消失败','data'=>['error'=>$th->getMessage().$th->getLine()]]);
  579. }
  580. }
  581. /**
  582. * 获取订单子数据 /api/orders/get_item
  583. *
  584. * @param string $name 产品名称
  585. * @param int $page 页码,默认1
  586. * @param int $limit 每页条数,默认10条
  587. *
  588. * */
  589. public function get_item(Request $request, Model $Model, OrdersProduct $OrdersProduct, Business $Business){
  590. // 接口验签
  591. // $this->verify_sign();
  592. // 验证参数
  593. $request->scene('get_item')->validate();
  594. // 检查登录
  595. $uid = $this->checkLogin();
  596. // 接收参数
  597. $id = request('id',0);
  598. // 查询
  599. $orderInfo = $Model->query()->where([['id','=',$id],['custom_uid','=',$uid]])->first(['id','pay_total','status','price_total','coupon_total','business_id','pay_total','weizan_orderid','insert_time']);
  600. // 如果用户不存在
  601. if( !$orderInfo ) return json_send(['code'=>'error','msg'=>'订单不存在']);
  602. // 转数组
  603. $orderInfo = $orderInfo->toArray();
  604. // 订单产品
  605. $orderInfo['product_list'] = $OrdersProduct->query()->where([['order_id','=',$id]])->select(['id as item_id','order_id','product_id','buy_num','is_rebate','sku_attr_names as product_spec','product_name','product_thumb'])->get()->toArray();
  606. // 循环处理
  607. foreach ($orderInfo['product_list'] as $key => $item) {
  608. // 产品图路径
  609. $item['product_thumb'] = path_compat($item['product_thumb']);
  610. // 重组
  611. $orderInfo['product_list'][$key] = $item;
  612. }
  613. // 获取子列表
  614. $orderInfo['state'] = (string) $Model->getState($orderInfo['status'],'state');
  615. // 获取子列表
  616. $orderInfo['business_name'] = (string) ($orderInfo['business_id'] ? $Business->getOne($orderInfo['business_id'],'name') : ($orderInfo['weizan_orderid'] ? '微赞订单' : ''));
  617. // 返回结果
  618. return json_send(['code'=>'success','msg'=>'获取成功','data'=>$orderInfo]);
  619. }
  620. /**
  621. * 创建拼团订单 /api/orders/create_regiment
  622. *
  623. * */
  624. public function create_regiment(Request $request,Custom $Custom,City $City,Model $Model,WeiBanTags $WeiBanTags,OrdersAddr $OrdersAddr,OrdersProduct $OrdersProduct,Product $Product,CustomAddr $CustomAddr,CustomScore $CustomScore){
  625. // 接口验签
  626. // $this->verify_sign();
  627. // 验证参数
  628. $request->scene('create')->validate();
  629. // 检查登录
  630. $uid = $this->checkLogin();
  631. // 接收参数
  632. $isCart = request('is_cart',0);
  633. $productList = request('product_list','[]');
  634. $customCouponId = request('custom_coupon_id',0);
  635. $addrId = request('addr_id',0);
  636. $regimentId = request('regiment_id',0);
  637. $regimentActiveId = request('regiment_active_id',0);
  638. $btnType = request('btn_type',0);
  639. // 如果不存在数据
  640. if( !$addrId ) return json_send(['code'=>'error','msg'=>'请选择收货地址','data'=>['error'=>'请选择收货地址']]);
  641. // 解码购买信息
  642. $buyList = json_decode($productList,true);
  643. // 如果不存在数据
  644. if( empty($buyList) ) return json_send(['code'=>'error','msg'=>'没有需下单的产品','data'=>['error'=>'产品列表为空']]);
  645. $time = time();
  646. // 选择地址
  647. $addr = $CustomAddr->getOne($addrId);
  648. // 如果不存在数据
  649. if( !$addr ) return json_send(['code'=>'error','msg'=>'地址有误,请核对','data'=>['error'=>'没有找到对应的地址']]);
  650. // 重组数据
  651. $addr = ['contact_name'=>$addr['contact_name'],'contact_shop'=>$addr['contact_shop'],'contact_phone'=>$addr['contact_phone'],'contact_province'=>$addr['contact_province'],'contact_city'=>$addr['contact_city'],'contact_area'=>$addr['contact_area'],'contact_addr'=>$addr['contact_addr']];
  652. // 获取客户城市ID
  653. $custom = $Custom->getOne($uid);
  654. // 如果不存在的话
  655. if( !$custom ) return json_send(['code'=>'no_login','msg'=>'用户不存在,请重新登录','data'=>['error'=>'用户不存在,请重新登录']]);
  656. // 如果不存在的话
  657. if( !$custom['city_id'] ) return json_send(['code'=>'error','msg'=>'请选择所在城市后下单','data'=>['error'=>'请选择所在城市后下单']]);
  658. // 获取城市ID
  659. $cityId = $custom['city_id'];
  660. $cityName = $City->getOne($cityId,'name');
  661. $pid = $City->getOne($cityId,'pid');
  662. // 如果上级不是省份
  663. if( strlen($cityId) > 4 ) $pid = (int) $City->getOne($pid,'pid');
  664. $province = $City->getOne($pid,'name');
  665. // 如果不是海南,
  666. if( $province != '海南省' ) {
  667. // 判断选择的城市名称是不是一致
  668. if( $cityName != $addr['contact_city'] ) return json_send(['code'=>'error','msg'=>'收货地址请选择'.$province.'/'.$cityName,'data'=>['error'=>'收货地址需与您所选城市一致']]);
  669. }else{
  670. if( trim($addr['contact_province']) != trim($province) ) return json_send(['code'=>'error','msg'=>'收货地址请选择海南范围','data'=>['error'=>'收货地址需与您所选城市一致']]);
  671. }
  672. //获取团活动信息
  673. $regimentActiveInfo = RegimentActive::query()
  674. ->where([['id','=',$regimentActiveId],['status','=',1],['start_time','<=',$time],['end_time','>=',$time]])
  675. ->first();
  676. if (!$regimentActiveInfo) return json_send(['code'=>'error','msg'=>'拼团活动不存在','data'=>['error'=>'拼团活动不存在']]);
  677. //是否符合开团条件
  678. if($btnType == 3){
  679. if ($regimentActiveInfo['open_people'] == 1){
  680. if ($custom['insert_time'] > $regimentActiveInfo['start_time']) return json_send(['code'=>'error','msg'=>'此活动只允许老用户开团','data'=>['error'=>'此活动只允许老用户开团']]);
  681. }
  682. if ($regimentActiveInfo['open_people'] == 2){
  683. if ($custom['insert_time'] < $regimentActiveInfo['start_time']) return json_send(['code'=>'error','msg'=>'此活动只允许新用户开团','data'=>['error'=>'此活动只允许新用户开团']]);
  684. }
  685. }
  686. //是否符合参团条件
  687. if($btnType == 4){
  688. if ($regimentActiveInfo['partake_people'] == 1){
  689. if ($custom['insert_time'] > $regimentActiveInfo['start_time']) return json_send(['code'=>'error','msg'=>'此活动只允许老用户参与','data'=>['error'=>'此活动只允许老用户开团']]);
  690. }
  691. if ($regimentActiveInfo['partake_people'] == 2){
  692. if ($custom['insert_time'] < $regimentActiveInfo['start_time']) return json_send(['code'=>'error','msg'=>'此活动只允许新用户参与','data'=>['error'=>'此活动只允许新用户开团']]);
  693. }
  694. //查询团信息
  695. $regimentInfo = Regiment::query()
  696. ->where([['id','=',$regimentId],['status','=',0],['start_time','<=',$time],['end_time','>=',$time]])
  697. ->first();
  698. if (!$regimentInfo) return json_send(['code'=>'error','msg'=>'拼团活动不存在','data'=>['error'=>'拼团活动不存在']]);
  699. $regimentRecordres = RegimentRecord::query()
  700. ->where([['custom_uid','=',$uid],['regiment_id','=',$regimentId]])
  701. ->first();
  702. if ($regimentRecordres) return json_send(['code'=>'error','msg'=>'您已参与此拼团','data'=>['error'=>'您已参与此拼团']]);
  703. }
  704. //查询用户参团记录
  705. $regimentRecordCount = RegimentRecord::query()
  706. ->where([['custom_uid','=',$uid],['active_id','=',$regimentActiveInfo['id']]])
  707. ->count('id');
  708. if ($regimentRecordCount >= $regimentActiveInfo['participation_number']) return json_send(['code'=>'error','msg'=>'该活动每人仅限参与'.$regimentActiveInfo['participation_number'].'次','data'=>['error'=>'该活动每人仅限参与'.$regimentActiveInfo['participation_number'].'次']]);
  709. $tags = $WeiBanTags->getListByWeibanExtid($custom['weiban_extid']);
  710. // 查询产品信息
  711. $productList = $Product->getListByIds(array_column($buyList,'product_id'));
  712. // 当前时间
  713. $time = time();
  714. // 产品以店铺分组,方便写入订单
  715. $orderProduct = [];
  716. // 产品价格同级,用于优惠券计算
  717. $productPrice = [];
  718. $priceTotal = 0;
  719. $payTotal = 0;
  720. $buyInfo = $buyList[0];
  721. if ($buyInfo){
  722. if( empty($productList[$buyInfo['product_id']]) ) return json_send(['code'=>'error','msg'=>'产品不存在或已下架','data'=>['error'=>'产品不存在或已下架=>'.$buyInfo['product_id']]]);
  723. // 获取产信息
  724. $productInfo = $productList[$buyInfo['product_id']];
  725. // 判断是不是可以参与
  726. if( $productInfo['tag_scope'] ) {
  727. // 解析数组
  728. $productInfo['tag_scope'] = explode(',',$productInfo['tag_scope']);
  729. // 标签范围限定时,默认不能参与
  730. $allowJoin = 0;
  731. // 判断标签是不是存在
  732. foreach ($tags as $value) {
  733. // 标签范围内,允许参加
  734. if( in_array($value['name'],$productInfo['tag_scope']) ) $allowJoin = 1;
  735. }
  736. // 如果不能参与
  737. if( !$allowJoin ) return json_send(['code'=>'error','msg'=>'不在 '.$productInfo['product_name'].' 参与范围','data'=>['error'=>'不在标签范围内']]);
  738. }
  739. // 判断是不是可以参与
  740. if( $productInfo['tag_exclude'] ) {
  741. // 解析数组
  742. $productInfo['tag_exclude'] = explode(',',$productInfo['tag_exclude']);
  743. // 判断标签是不是存在
  744. foreach ($tags as $value) {
  745. // 标签排除范围内,不允许参加
  746. if( in_array($value['name'],$productInfo['tag_exclude']) ) return json_send(['code'=>'error','msg'=>'不在 '.$productInfo['product_name'].' 可参与范围','data'=>['error'=>'用户在标签排除范围']]);
  747. }
  748. }
  749. //拼团活动限购
  750. if ($regimentActiveInfo['quota']){
  751. if ($buyInfo['buy_num'] > $regimentActiveInfo['quota']) return json_send(['code'=>'error','msg'=>'超过拼团限购','data'=>['error'=>'拼团限购=>'.$buyInfo['product_id']]]);
  752. }
  753. // 如果产品限购
  754. if( $productInfo['quota'] ) {
  755. // 是否在限购时间,当前时间大于开始时间,并且小于结束时间
  756. if( $productInfo['quota_start'] <= $time && $time <= $productInfo['quota_end'] ){
  757. // 通过时间查询商品的购买总数
  758. $total = $OrdersProduct->query()->where([['custom_uid','=',$uid],['product_id','=',$productInfo['id']],['insert_time','>=',$productInfo['quota_start']],['insert_time','<=',$productInfo['quota_end']]])->sum('buy_num');
  759. // 判断限购数量
  760. $total = $buyInfo['buy_num'] + $total;
  761. // 如果超过数量
  762. if( $total > $productInfo['quota'] ) return json_send(['code'=>'error','msg'=>'限购'.$productInfo['quota'].'单-'.$productInfo['product_name'],'data'=>['error'=>'已超限=>'.($total - $productInfo['quota'])]]);
  763. }
  764. }
  765. // 需要扣除的库存
  766. $productList[$buyInfo['product_id']]['decr'] = $buyInfo['buy_num'];
  767. // 判断库存
  768. if( $productInfo['stock'] < $productList[$buyInfo['product_id']]['decr'] ) return json_send(['code'=>'error','msg'=>$productInfo['product_name'].'-库存不足','data'=>['error'=>'产品库存不足=>'.$buyInfo['product_id']]]);
  769. // 计算价值
  770. $priceTotal = $buyInfo['buy_num'] * $productInfo['price'];
  771. $payTotal = $buyInfo['buy_num'] * $regimentActiveInfo['regiment_price'];
  772. }
  773. $orderInfo = [
  774. 'custom_uid' => $uid,
  775. 'status' => 10,
  776. 'insert_time' => $time,
  777. 'update_time' => $time,
  778. 'pay_total' => $payTotal,
  779. 'price_total' => $priceTotal,
  780. 'business_id' => $productList[$buyInfo['product_id']]['business_id'],
  781. ];
  782. // 赠送积分
  783. $orderInfo['order_score'] = (config('order_score_send',0) && floor( $orderInfo['pay_total'] * 1 ) > 0 ) ? floor( $orderInfo['pay_total'] * 1 ) : 0;
  784. $orderProductInfo = [
  785. 'product_name' => $productList[$buyInfo['product_id']]['product_name'],
  786. 'sku_attr_names' => $productList[$buyInfo['product_id']]['sku_attr_names'],
  787. 'product_thumb' => $productList[$buyInfo['product_id']]['product_thumb'],
  788. 'buy_num' => $buyInfo['buy_num'],
  789. 'price_total' => $priceTotal,
  790. 'pay_total' => $buyInfo['buy_num'] * $productList[$buyInfo['product_id']]['price'],
  791. 'product_id' => $buyInfo['product_id'],
  792. 'custom_uid' => $uid,
  793. 'business_id' => $productList[$buyInfo['product_id']]['business_id'],
  794. 'insert_time' => $time,
  795. 'update_time' => $time,
  796. 'status' => 10,
  797. ];
  798. // 组合数据,写入订单表,子表
  799. DB::beginTransaction();
  800. // 写入数据
  801. try {
  802. // 扣减商品库存
  803. foreach ($productList as $key => $value) {
  804. // 扣减库存
  805. $result = $Product->edit($value['id'],['stock'=>DB::raw('stock+-'.$value['decr'])]);
  806. // 判断结果
  807. if( !$result ) {
  808. // 回退数据
  809. DB::rollBack();
  810. // 错误提示
  811. return json_send(['code'=>'error','msg'=>'库存扣减失败','data'=>['error'=>'库存扣减失败']]);
  812. }
  813. }
  814. //创建拼团
  815. if($btnType == 3){
  816. $regimentInfo = [
  817. 'custom_uid' => $uid,
  818. 'active_id' => $regimentActiveInfo['id'],
  819. 'product_id' => $buyInfo['product_id'],
  820. 'people_number' => 1,
  821. 'status' => 0,
  822. 'start_time' => $time,
  823. 'end_time' => $time + $regimentActiveInfo['expiration']*3600,
  824. 'update_time' => $time,
  825. 'insert_time' => $time,
  826. ];
  827. $regimentId = Regiment::query()->insertGetId($regimentInfo);
  828. if( !$regimentId ) {
  829. // 回退数据
  830. DB::rollBack();
  831. // 提示信息
  832. return json_send(['code'=>'error','msg'=>'创建拼团失败','data'=>['error'=>'创建拼团失败']]);
  833. }
  834. }
  835. $orderInfo['regiment_id'] = $regimentId;
  836. // 创建总订单
  837. $orderId = $Model->add($orderInfo);
  838. // 如果订单写入失败
  839. if( !$orderId ) {
  840. // 回退数据
  841. DB::rollBack();
  842. // 错误提示
  843. return json_send(['code'=>'error','msg'=>'下单失败','data'=>['error'=>'订单创建失败']]);
  844. }
  845. $orderProductInfo['order_id'] = $orderId;
  846. // 写入子表
  847. $result = $OrdersProduct->query()->insert($orderProductInfo);
  848. // 如果扣减失败
  849. if( !$result ) {
  850. // 回退数据
  851. DB::rollBack();
  852. // 提示信息
  853. return json_send(['code'=>'error','msg'=>'子订单创建失败','data'=>['error'=>'子订单创建失败']]);
  854. }
  855. // 写入订单地址表
  856. $addr['order_id'] = $orderId;
  857. // 写入订单地址表
  858. $result = $OrdersAddr->add($addr);
  859. // 地址写入失败
  860. if( !$result ) {
  861. // 回退数据
  862. DB::rollBack();
  863. // 提示信息
  864. return json_send(['code'=>'error','msg'=>'地址写入失败','data'=>['error'=>'地址写入失败']]);
  865. }
  866. if($btnType == 4){
  867. // 拼团人数加1
  868. $inc = Regiment::query()->where('id','=',$regimentId)->increment('people_number',1);
  869. if( !$inc ) {
  870. // 回退数据
  871. DB::rollBack();
  872. // 提示信息
  873. return json_send(['code'=>'error','msg'=>'创建拼团失败','data'=>['error'=>'创建拼团失败']]);
  874. }
  875. //团满
  876. if ((($regimentInfo['people_number'] + 1) == $regimentActiveInfo['number']) && $regimentActiveInfo['exceed_people'] == 1) {
  877. $res = regiment::query()->where('id','=',$regimentId)->update(['status'=>3]);
  878. if( !$res ) {
  879. // 回退数据
  880. DB::rollBack();
  881. // 提示信息
  882. return json_send(['code'=>'error','msg'=>'创建拼团失败','data'=>['error'=>'创建拼团失败']]);
  883. }
  884. //修改订单
  885. $orderRes = $Model::query()->where('regiment_id','=',$regimentId)->update(['status'=>'1']);
  886. if( !$orderRes ) {
  887. // 回退数据
  888. DB::rollBack();
  889. // 提示信息
  890. return json_send(['code'=>'error','msg'=>'创建拼团失败','data'=>['error'=>'创建拼团失败']]);
  891. }
  892. //赠送积分
  893. $orderList = $Model::query()->where('regiment_id','=',$regimentId)->get();
  894. foreach ($orderList as $key => $value) {
  895. if( $value['order_score'] > 0 ) $CustomScore->trade($orderInfo['custom_uid'],$value['id'],$value['order_score'],5,1);
  896. }
  897. }
  898. }
  899. //拼团记录
  900. $regimentRecordInfo = [
  901. 'custom_uid' => $uid,
  902. 'regiment_id' => $regimentId,
  903. 'active_id' => $regimentActiveInfo['id'],
  904. 'product_id' => $buyInfo['product_id'],
  905. 'order_id' => $orderId,
  906. 'update_time' => $time,
  907. 'insert_time' => $time,
  908. ];
  909. $result = RegimentRecord::query()->insert($regimentRecordInfo);
  910. if( !$result ) {
  911. // 回退数据
  912. DB::rollBack();
  913. // 提示信息
  914. return json_send(['code'=>'error','msg'=>'创建拼团记录失败','data'=>['error'=>'创建拼团记录失败']]);
  915. }
  916. // 提交数据
  917. DB::commit();
  918. // 返回结果
  919. return json_send(['code'=>'success','msg'=>'下单成功','data'=>['id'=>null]]);
  920. // 返回结果
  921. } catch (\Throwable $th) {
  922. // 回退数据
  923. DB::rollBack();
  924. // 判断结果,如果库存扣减失败的话
  925. if( stripos($th->getMessage(),'UNSIGNED') ) return json_send(['code'=>'error','msg'=>'库存不足','data'=>['error'=>'产品库存扣减失败']]);
  926. // 下单失败提示
  927. return json_send(['code'=>'error','msg'=>'系统异常,请稍后再试','data'=>['error'=>$th->getMessage().$th->getLine()]]);
  928. }
  929. }
  930. /**
  931. * 取消拼团 /api/orders/cancel_regiment
  932. *
  933. * */
  934. public function cancel_regiment( Request $request, Model $Model,OrdersProduct $OrdersProduct){
  935. // 验证参数
  936. $request->scene('cancel')->validate();
  937. // 检查登录
  938. $uid = $this->checkLogin();
  939. // 接收参数
  940. $id = request('id',0);
  941. $status = 12;
  942. // 获取产品和数量
  943. $oldData = $Model->query()->where([['id','=',$id],['custom_uid','=',$uid]])->first(['id','order_score','status','custom_uid','insert_time','regiment_id']);
  944. // 如果用户不存在
  945. if( !$oldData ) return json_send(['code'=>'error','msg'=>'订单不存在']);
  946. // 如果已经取消
  947. if( $oldData['status'] == 12 ) return json_send(['code'=>'error','msg'=>'订单已取消']);
  948. // 如果团不存在
  949. if( !$oldData['regiment_id'] ) return json_send(['code'=>'error','msg'=>'拼团不存在']);
  950. //查询团信息
  951. $regimentInfo = Regiment::query()->find($oldData['regiment_id']);
  952. if( !$regimentInfo ) return json_send(['code'=>'error','msg'=>'拼团不存在']);
  953. // 组合数据,写入订单表,子表
  954. DB::beginTransaction();
  955. try{
  956. // 查询数据
  957. $result = $Model->setOrderStatus($id,$status,$OrdersProduct);
  958. // 提示新增失败
  959. if( isset($result['error']) ) {
  960. // 回退数据
  961. DB::rollBack();
  962. // 提示信息
  963. return json_send(['code'=>'error','msg'=>$result['error'],'data'=>['error'=>$result['error']]]);
  964. }
  965. //开团用户取消团订单
  966. if ($regimentInfo['people_number'] > 1 && $regimentInfo['custom_uid'] == $uid){
  967. //查询团记录
  968. $regimentRecordInfo = RegimentRecord::query()->where([['order_id','<>',$oldData['id']],['regiment_id','=',$regimentInfo['id']],['status','=',0]])->first();
  969. if ($regimentRecordInfo){
  970. //将参团成员中的第一个用户变成开团人
  971. $result = Regiment::query()->where('id','=',$regimentRecordInfo['regiment_id'])->update(['custom_uid'=>$regimentRecordInfo['custom_uid']]);
  972. if (!$result) {
  973. DB::rollBack();
  974. return json_send(['code'=>'error','msg'=>'取消拼团,改变开团人失败']);
  975. }
  976. }
  977. //扣减加入团人数
  978. $regimentRes = Regiment::query()->where('id','=',$oldData['regiment_id'])->decrement('people_number',1);
  979. if( !$regimentRes ) {
  980. // 回退数据
  981. DB::rollBack();
  982. // 提示信息
  983. return json_send(['code'=>'error','msg'=>'取消拼团失败']);
  984. }
  985. }else{
  986. $regimentRes = Regiment::query()->where('id','=',$oldData['regiment_id'])->update(['status'=>1]);
  987. if (!$regimentRes){
  988. DB::rollBack();
  989. return json_send(['code'=>'error','msg'=>'取消拼团失败']);
  990. }
  991. }
  992. //修改拼团记录
  993. $regimentRes = RegimentRecord::query()->where([['order_id','=',$oldData['id'],]])->update(['status'=>'1']);
  994. if( !$regimentRes ) {
  995. // 回退数据
  996. DB::rollBack();
  997. // 提示信息
  998. return json_send(['code'=>'error','msg'=>'取消拼团失败']);
  999. }
  1000. // 提交数据
  1001. DB::commit();
  1002. // 告知结果
  1003. return json_send(['code'=>'success','msg'=>'取消成功']);
  1004. // 返回结果
  1005. } catch (\Throwable $th) {
  1006. // 回退数据
  1007. DB::rollBack();
  1008. // 下单失败提示
  1009. return json_send(['code'=>'error','msg'=>'取消失败','data'=>['error'=>$th->getMessage().$th->getLine()]]);
  1010. }
  1011. }
  1012. /**
  1013. * 订单详情
  1014. *
  1015. * @pamam int $id 订单ID
  1016. *
  1017. * */
  1018. public function get_detail( Request $request, Model $Model,OrdersProduct $OrdersProduct,Business $Business,OrdersAddr $OrdersAddr){
  1019. // 验证参数
  1020. $request->scene('get_detail')->validate();
  1021. // 接受参数
  1022. $id = request('id',0);
  1023. // 查询数据
  1024. $order = $Model->query()->find($id,['id','pay_total','status','price_total','coupon_total','business_id','pay_total','weizan_orderid','insert_time']);
  1025. // 查询不到订单
  1026. if( !$order ) return json_send(['code'=>'error','msg'=>'订单不存在']);
  1027. // 数据转换
  1028. $order = $order->toArray();
  1029. // id转编号
  1030. $order['insert_time'] = date('Y-m-d H:i:s',$order['insert_time']);
  1031. $order['business_name'] = (string) $Business->getOne($order['business_id'],'name');
  1032. $order['order_code'] = $Model->idToCode($order['id']);
  1033. $order['state'] = $Model->getState($order['status'],'state');
  1034. // 查询子订单数据
  1035. $order['order_items'] = $OrdersProduct->query()->where([['order_id','=',$id]])->select(['id as item_id','order_id','product_id','buy_num','pay_total','is_rebate','sku_attr_names as product_spec','product_name','product_thumb'])->get()->toArray();
  1036. // 处理缩略图
  1037. foreach ($order['order_items'] as $key => $value) {
  1038. $order['order_items'][$key]['product_thumb'] = $value['product_thumb'] ? path_compat($value['product_thumb']) : '';
  1039. }
  1040. // 地址
  1041. $order['order_addr'] = $OrdersAddr->query()->where([['order_id','=',$id]])->first(['contact_name','contact_phone','contact_province','contact_city','contact_area','contact_addr','contact_shop']);
  1042. // 加载模板
  1043. return json_send(['code'=>'success','msg'=>'获取成功','data'=>$order]);
  1044. }
  1045. }