OrderLogic.php 86 KB

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