Orders.php 57 KB

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