CheckoutGroupbuy.php 36 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961
  1. <?php
  2. // +----------------------------------------------------------------------
  3. // | 萤火商城系统 [ 致力于通过产品和服务,帮助商家高效化开拓市场 ]
  4. // +----------------------------------------------------------------------
  5. // | Copyright (c) 2017~2021 https://www.yiovo.com All rights reserved.
  6. // +----------------------------------------------------------------------
  7. // | Licensed 这不是一个自由软件,不允许对程序代码以任何形式任何目的的再发行
  8. // +----------------------------------------------------------------------
  9. // | Author: 萤火科技 <admin@yiovo.com>
  10. // +----------------------------------------------------------------------
  11. declare (strict_types=1);
  12. namespace app\api\service\order;
  13. use app\api\model\card\UserRiceCard as UserRiceCardModel;
  14. use app\api\model\card\UserRiceCardConsume as UserRiceCardConsumeModel;
  15. use app\api\model\fullsend\FullSendActivity;
  16. use app\api\model\GoodsCategoryRel as GoodsCategoryRelModel;
  17. use app\api\model\GoodsPackage as GoodsPackageModel;
  18. use app\api\model\kj\KjActivityJoin;
  19. use app\api\model\member\DeductionLimit as DeductionLimitModel;
  20. use app\api\model\member\GoldRice as GoldRiceModel;
  21. use app\api\model\OrderGoodsTaocan as OrderGoodsTaocanModel;
  22. use app\api\model\Order as OrderModel;
  23. use app\api\model\PromotionMonitor;
  24. use app\api\model\User as UserModel;
  25. use app\api\model\Goods as GoodsModel;
  26. use app\api\model\Setting as SettingModel;
  27. use app\api\model\shop\Shops;
  28. use app\api\model\UserAddress;
  29. use app\api\model\UserCoupon as UserCouponModel;
  30. use app\api\service\User as UserService;
  31. use app\api\service\Payment as PaymentService;
  32. use app\api\service\coupon\GoodsDeduct as GoodsDeductService;
  33. use app\api\service\ricecard\GoodsDeduct as RiceDeductService;
  34. use app\api\service\points\GoodsDeduct as PointsDeductService;
  35. use app\api\service\order\source\checkout\Factory as CheckoutFactory;
  36. use app\common\enum\Setting as SettingEnum;
  37. use app\common\enum\order\PayType as OrderPayTypeEnum;
  38. use app\common\enum\order\OrderStatus as OrderStatusEnum;
  39. use app\common\enum\order\OrderSource as OrderSourceEnum;
  40. use app\common\enum\order\DeliveryType as DeliveryTypeEnum;
  41. use app\common\service\BaseService;
  42. use app\common\service\card\UserRiceCard as UserRiceCardService;
  43. use app\common\service\commission\RecordWaitCommission;
  44. use app\common\service\delivery\Express as ExpressService;
  45. use app\common\service\goods\source\Factory as StockFactory;
  46. use app\common\library\helper;
  47. use app\common\exception\BaseException;
  48. use app\common\enum\order\PayStatus as PayStatusEnum;
  49. use app\common\model\ShopGoodsSku;
  50. use app\common\model\User;
  51. use http\Header\Parser;
  52. use app\api\model\groupbuy\GroupBuyHelp;
  53. use app\api\model\groupbuy\GroupBuyJoin;
  54. use app\api\model\groupbuy\GroupBuyActivity;
  55. use app\api\model\order\GroupBuyPay;
  56. use think\facade\Log;
  57. /**
  58. * 订单结算台服务类
  59. * Class Checkout
  60. * @package app\api\service\order
  61. */
  62. class CheckoutGroupbuy extends BaseService
  63. {
  64. /* $model OrderModel 订单模型 */
  65. public $model;
  66. public $buyhelpModel;//参团模型
  67. public $buyjoinModel;//发起团模型
  68. /* @var UserModel $user 当前用户信息 */
  69. private $user;
  70. // 订单结算商品列表
  71. private $goodsList = [];
  72. // 错误信息
  73. protected $error;
  74. // 错误信息状态
  75. protected $errorStatus;
  76. /**
  77. * 订单结算api参数
  78. * @var array
  79. */
  80. private $param = [
  81. 'delivery' => null, // 配送方式 默认:快递配送
  82. 'couponId' => 0, // 优惠券id
  83. 'riceCardId' => 0, // 现金米卡id
  84. 'isUsePoints' => 0, // 是否使用积分抵扣
  85. 'isUseGoldRice' => 1, // 默认使用金米粒
  86. 'remark' => '', // 买家留言
  87. 'payType' => OrderPayTypeEnum::WECHAT, // 支付方式
  88. 'addressId' => 0, //地址ID
  89. 'staffUserId' => 0, //分享链接用户ID
  90. ];
  91. /**
  92. * 订单结算的规则
  93. * @var array
  94. */
  95. private $checkoutRule = [
  96. 'isUserGrade' => false, // 会员等级折扣
  97. 'isCoupon' => true, // 优惠券抵扣
  98. 'isRiceCard' => true, // 现金米卡抵扣
  99. 'isUsePoints' => false, // 是否使用积分抵扣
  100. ];
  101. /**
  102. * 订单来源
  103. * @var array
  104. */
  105. private $orderSource = [
  106. 'source' => OrderSourceEnum::GROUPBUY,
  107. 'source_id' => 0,
  108. ];
  109. /**
  110. * 订单结算数据
  111. * @var array
  112. */
  113. private $orderData = [];
  114. /**
  115. * 构造函数
  116. * Checkout constructor.
  117. * @throws BaseException
  118. */
  119. public function __construct()
  120. {
  121. parent::__construct();
  122. $this->user = UserService::getCurrentLoginUser(true);
  123. $this->model = new OrderModel;
  124. $this->buyhelpModel = new GroupBuyHelp;
  125. $this->buyjoinModel = new GroupBuyJoin;
  126. $this->storeId = $this->getStoreId();
  127. }
  128. /**
  129. * 设置结算台请求的参数
  130. * @param $param
  131. * @return array
  132. */
  133. public function setParam($param)
  134. {
  135. $this->param = array_merge($this->param, $param);
  136. return $this->getParam();
  137. }
  138. /**
  139. * 获取结算台请求的参数
  140. * @return array
  141. */
  142. public function getParam()
  143. {
  144. return $this->param;
  145. }
  146. /**
  147. * 订单结算的规则
  148. * @param $data
  149. * @return $this
  150. */
  151. public function setCheckoutRule($data)
  152. {
  153. $this->checkoutRule = array_merge($this->checkoutRule, $data);
  154. return $this;
  155. }
  156. /**
  157. * 设置订单来源(普通订单)
  158. * @param $data
  159. * @return $this
  160. */
  161. public function setOrderSource($data)
  162. {
  163. $this->orderSource = array_merge($this->orderSource, $data);
  164. return $this;
  165. }
  166. /**
  167. * 订单确认-结算台
  168. * @param $goodsList
  169. * @return array
  170. * @throws BaseException
  171. * @throws \think\db\exception\DataNotFoundException
  172. * @throws \think\db\exception\DbException
  173. * @throws \think\db\exception\ModelNotFoundException
  174. */
  175. public function onCheckout($goodsList)
  176. {
  177. // 订单确认-立即购买
  178. $this->goodsList = $goodsList;
  179. return $this->checkout();
  180. }
  181. /**
  182. * 订单结算台
  183. * @return array
  184. * @throws BaseException
  185. * @throws \think\db\exception\DataNotFoundException
  186. * @throws \think\db\exception\DbException
  187. * @throws \think\db\exception\ModelNotFoundException
  188. */
  189. private function checkout()
  190. {
  191. // 整理订单数据
  192. $this->orderData = $this->getOrderData();
  193. // 验证商品状态, 是否允许购买
  194. $this->validateGoodsList();
  195. // 设置订单商品总金额()
  196. $this->setOrderTotalPrice();
  197. //订单总运费金额
  198. $this->setOrderExpress();
  199. //金米粒抵扣-V1.4.0版本添加2022年6月6日
  200. $this->setOrderGolRiceAmount();
  201. //获取当前可用的现金卡列表
  202. $userRiceCardList = $this->getUserRiceCardList();
  203. //计算使用米卡现金券抵扣后的金额
  204. $this->setOrderRiceCardMoney($userRiceCardList,(int)$this->param['riceCardId']);
  205. // 计算订单商品的实际付款金额
  206. $this->setOrderGoodsPayPrice();
  207. // 计算订单最终金额+运费
  208. $this->setOrderPayPrice();
  209. //订单商品的所有店铺集合2021年9月28日 10:56:45
  210. $this->setOrderProviderIds();
  211. // 订单商品总数量
  212. $orderTotalNum = helper::getArrayColumnSum($this->goodsList, 'total_num');
  213. // 返回订单数据
  214. return array_merge([
  215. 'goodsList' => $this->goodsList, // 商品信息
  216. 'orderTotalNum' => $orderTotalNum, // 商品总数量
  217. // 'couponList' => array_values($couponList), // 优惠券列表
  218. 'hasError' => $this->hasError(),
  219. 'errorMsg' => $this->getError(),
  220. 'errorStatus' => $this->getErrorStatus(),
  221. ], $this->orderData);
  222. }
  223. /**
  224. * 设置订单使用金米粒抵扣信息
  225. * @return bool
  226. * @throws BaseException
  227. */
  228. private function setOrderGolRiceAmount()
  229. {
  230. // 设置默认数据:订单信息
  231. helper::setDataAttribute($this->orderData, [
  232. 'goldRiceAmount' => 0, // 金米粒抵扣总数量 1金米粒=0.01元
  233. 'goldRiceMoney' => 0.00, // 金米粒抵扣总金额
  234. ], false);
  235. // 设置默认数据:订单商品列表
  236. helper::setDataAttribute($this->goodsList, [
  237. 'gold_rice_amount' => 0, // 金米粒抵扣数量
  238. 'gold_rice_money' => 0, // 金米粒抵扣金额
  239. ], true);
  240. $this->orderData['isUseGoldRice'] = 0;//
  241. if($this->orderData['isUseGoldRice']<1){//没有使用金米粒
  242. return false;
  243. }
  244. $orderTotalGroupPrice = $this->orderData['orderTotalGroupPrice']; //实际支付金额
  245. // 如果没有可用的金米粒,直接返回
  246. $DeductionLimit = DeductionLimitModel::where('id','>',0)->find();
  247. $score = floor($DeductionLimit['discount']*$orderTotalGroupPrice);
  248. //不够起用数量
  249. if($score<$DeductionLimit['score']){
  250. $this->orderData['isUseGoldRice'] = -1;
  251. return false;
  252. }
  253. //用户可用金米粒数量不够起用数量
  254. if($this->user['gold_rice']<$DeductionLimit['score']){
  255. $this->orderData['isUseGoldRice'] = -1;
  256. return false;
  257. }
  258. if($score>$this->user['gold_rice']){
  259. $score = $this->user['gold_rice'];
  260. }
  261. // 获取优惠券信息
  262. $goodsListTemp = [];
  263. foreach ($this->goodsList as $key=> $good){
  264. $goodsListTemp[$key]['total_price'] = helper::bcsub($good['group_price']*$good['total_num'],0);
  265. }
  266. $RiceMoney = new RiceDeductService;
  267. $gold_rice_money = helper::bcdiv($score,100);
  268. $completed = $RiceMoney->setGoodsCouponMoney($goodsListTemp, $gold_rice_money);
  269. // 分配订单商品抵扣的金米粒数量
  270. foreach ($this->goodsList as $key => &$goods) {
  271. $goods['gold_rice_amount'] = isset($completed[$key]['rice_card_money']) ? $completed[$key]['rice_card_money'] : 0;
  272. $goods['gold_rice_money'] = helper::bcdiv($goods['gold_rice_amount'],100);
  273. }
  274. // 记录订单抵扣的金米粒数量
  275. $this->orderData['goldRiceAmount'] = $score;
  276. $this->orderData['goldRiceMoney'] = $gold_rice_money;
  277. return true;
  278. }
  279. //我的可用现金卡
  280. public function getUserRiceCardList(){
  281. $user = UserService::getCurrentLoginUser(true);
  282. $list = UserRiceCardModel::getUserRiceCardList($user['user_id'])->toArray();
  283. $data = [];
  284. foreach ($list as $key=>&$item){
  285. $i = 0;
  286. $exceptGoodsId = helper::getArrayColumn($item['riceCardGoodsExcept'],'goods_id');
  287. foreach ($this->goodsList as $good) {
  288. if(!empty($item['dk_cat_ids']) && strpos((string)$item['dk_cat_ids'],(string)$good['category']['category_id']) === false){
  289. unset($list[$key]);
  290. $i = 1;
  291. }
  292. if(!empty($exceptGoodsId) && in_array($good['goods_id'],$exceptGoodsId)){
  293. unset($list[$key]);
  294. $i = 1;
  295. }
  296. }
  297. if(!$i){
  298. unset($item['riceCardGoodsExcept']);
  299. $data[$item['id']] = $item;
  300. }
  301. }
  302. if($this->param['riceCardId']==0){ //-1表示不使用米卡
  303. $this->param['riceCardId'] = key($data)??0;//若果没有选择米卡,默认使用第一张
  304. }
  305. return $data;
  306. }
  307. /**
  308. * 整理订单数据(结算台初始化)
  309. * @return array
  310. * @throws \think\db\exception\DataNotFoundException
  311. * @throws \think\db\exception\DbException
  312. * @throws \think\db\exception\ModelNotFoundException
  313. */
  314. private function getOrderData()
  315. {
  316. // 系统支持的配送方式 (后台设置)
  317. $deliveryType = SettingModel::getItem(SettingEnum::DELIVERY)['delivery_type'];
  318. return [
  319. // 当前配送类型
  320. 'delivery' => $this->param['delivery'] > 0 ? $this->param['delivery'] : $deliveryType[0],
  321. // 默认地址
  322. 'address' => '',
  323. // 是否存在收货地址
  324. 'existAddress' => $this->user['address_id'] > 0,
  325. // 配送费用
  326. 'expressPrice' => 0.00,
  327. //是否使用了金米粒
  328. 'isUseGoldRice' => $this->param['isUseGoldRice'],
  329. //金米粒数量
  330. 'userGoldRiceNum' => $this->user['gold_rice']??0,
  331. // 当前用户收货城市是否存在配送规则中
  332. 'isIntraRegion' => true,
  333. // 是否允许使用积分抵扣
  334. 'isAllowPoints' => false,
  335. // 是否使用积分抵扣
  336. 'isUsePoints' => $this->param['isUsePoints'],
  337. // 积分抵扣金额
  338. 'pointsMoney' => 0.00,
  339. // 赠送的积分数量
  340. 'pointsBonus' => 0,
  341. // 支付方式
  342. 'payType' => $this->param['payType'],
  343. // 系统设置
  344. 'setting' => $this->getSetting(),
  345. // 推广监控ID
  346. "promotionMonitorId" => $this->param['promotionMonitorId'] ?? 0
  347. ];
  348. }
  349. /**
  350. * 获取订单页面中使用到的系统设置
  351. * @return array
  352. * @throws \think\db\exception\DataNotFoundException
  353. * @throws \think\db\exception\DbException
  354. * @throws \think\db\exception\ModelNotFoundException
  355. */
  356. private function getSetting()
  357. {
  358. // 系统支持的配送方式 (后台设置)
  359. $deliveryType = SettingModel::getItem(SettingEnum::DELIVERY)['delivery_type'];
  360. // 积分设置
  361. $pointsSetting = SettingModel::getItem(SettingEnum::POINTS);
  362. return [
  363. 'deliveryType' => $deliveryType, // 支持的配送方式
  364. 'points_name' => $pointsSetting['points_name'], // 积分名称
  365. 'points_describe' => $pointsSetting['describe'], // 积分说明
  366. ];
  367. }
  368. /**
  369. * 验证订单商品的状态
  370. * @return bool
  371. */
  372. private function validateGoodsList()
  373. {
  374. $Checkout = CheckoutFactory::getFactory(
  375. $this->user,
  376. $this->goodsList,
  377. $this->orderData['delivery'],
  378. $this->shopInfo['shop_id'] ?? 0,
  379. $this->orderSource['source']
  380. );
  381. $status = $Checkout->validateGoodsList();
  382. if(!$status){
  383. $this->setError($Checkout->getError());
  384. $this->setErrorStatus(422);
  385. }
  386. return $status;
  387. }
  388. /**
  389. * 设置订单的商品总金额(不含优惠折扣)
  390. */
  391. private function setOrderTotalPrice()
  392. {
  393. // 订单商品的总金额
  394. $this->orderData['orderTotalPrice'] = helper::number2(helper::getArrayColumnSum($this->goodsList, 'total_price'));
  395. //拼团总金额
  396. $this->orderData['orderTotalGroupPrice'] = helper::number2(helper::getArrayColumnSum($this->goodsList, 'group_price')*helper::getArrayColumnSum($this->goodsList, 'total_num'));
  397. }
  398. /**
  399. * 订单商品的所有店铺集合
  400. */
  401. private function setOrderProviderIds()
  402. {
  403. // 订单商品的所有店铺集合
  404. $this->orderData['orderProviderIds'] = implode(',',array_values(array_unique(helper::getArrayColumn($this->goodsList, 'provider_id'))));
  405. }
  406. /**
  407. * 设置订单的实际支付金额(含配送费)
  408. */
  409. private function setOrderPayPrice()
  410. {
  411. // 订单金额(含优惠折扣)
  412. //(商品总价 - N件X折 - 优惠券 - 分销员)+ 运费 = 微信支付+米卡抵扣+米卡抵扣运费
  413. //(total_price-coupon_money-distrbutor_total_money)+express_price = pay_price+rice_card_money+rice_card_express_money
  414. $this->orderData['orderPrice'] = helper::number2(helper::getArrayColumnSum($this->goodsList, 'total_pay_price'));
  415. // 订单实付款金额(订单金额 + 运费 - 现金卡运费抵扣金额)
  416. $this->orderData['orderPayPrice'] = helper::number2(helper::bcadd($this->orderData['orderPrice'], $this->orderData['expressPrice']-$this->orderData['riceCardExpressMoney']));
  417. }
  418. /**
  419. * 计算订单商品的实际付款金额
  420. * @return bool
  421. */
  422. private function setOrderGoodsPayPrice()
  423. {
  424. // 商品总价 - 优惠抵扣
  425. foreach ($this->goodsList as &$goods) {
  426. //减去现金米卡抵扣的金额
  427. $value = helper::bcsub($goods['group_price']*$goods['total_num'], $goods['rice_card_money']+$goods['gold_rice_money']);
  428. $goods['total_pay_price'] = helper::number2($value);
  429. }
  430. return true;
  431. }
  432. /**
  433. * 设置订单现金米卡抵扣信息
  434. * @param int $riceCardId 可使用米卡列表
  435. * @param int $riceCardId 当前选择的现金米卡id
  436. * @return bool
  437. * @throws BaseException
  438. */
  439. private function setOrderRiceCardMoney($userRiceCardList,int $riceCardId)
  440. {
  441. // 设置默认数据:订单信息
  442. helper::setDataAttribute($this->orderData, [
  443. 'riceCardId' => $riceCardId, // 用户现金米卡id
  444. 'riceCardMoney' => 0, // 现金米卡抵扣总金额
  445. 'riceCardExpressMoney' => 0, // 现金米卡抵扣运费
  446. 'userRiceCardList' => [], // 米卡列表
  447. 'userRiceCard' => [], // 已选择的米卡
  448. ], false);
  449. // 设置默认数据:订单商品列表
  450. helper::setDataAttribute($this->goodsList, [
  451. 'rice_card_id' => 0, // 用户现金米卡id
  452. 'rice_card_money' => 0, // 金米卡抵扣金额
  453. ], true);
  454. if($riceCardId<0){//如果米卡ID小于0表示不使用,但是也要返回可使用列表
  455. $this->orderData['userRiceCardList'] = array_values($userRiceCardList);
  456. return true;
  457. }
  458. // 验证选择的优惠券ID是否合法
  459. if (!$this->verifyUserRiceCard($riceCardId, $userRiceCardList)) {
  460. return false;
  461. }
  462. // 获取优惠券信息
  463. $riceCard = $this->getRiceCardInfo($riceCardId, $userRiceCardList);
  464. $goodsListTemp = [];
  465. foreach ($this->goodsList as $key=> $good){
  466. $goodsListTemp[$key]['total_price'] = helper::bcsub($good['group_price']*$good['total_num'],$good['gold_rice_money']);
  467. }
  468. $RiceMoney = new RiceDeductService;
  469. $completed = $RiceMoney->setGoodsCouponMoney($goodsListTemp, $riceCard['balance']);
  470. // 分配订单商品优惠券抵扣金额
  471. $rice_card_money = 0;
  472. foreach ($this->goodsList as $key => &$goods) {
  473. $goods['rice_card_money'] = isset($completed[$key]['rice_card_money']) ? $completed[$key]['rice_card_money'] / 100 : 0;
  474. $goods['rice_card_id'] = $riceCardId;
  475. $rice_card_money += $goods['rice_card_money'];
  476. }
  477. $orderTotalGroupPrice = $this->orderData['orderTotalGroupPrice']-$this->orderData['goldRiceMoney']; //实际支付金额-金米粒抵扣的金额
  478. //有运费,并且现金米卡可用的金额大于商品总价
  479. $rice_card_express_money = 0;
  480. if($riceCard['balance']>$orderTotalGroupPrice && $this->orderData['expressPrice']>0){
  481. $residueMoney = $riceCard['balance']-$orderTotalGroupPrice;
  482. if($residueMoney-$this->orderData['expressPrice']>0){
  483. $rice_card_express_money += $this->orderData['expressPrice'];
  484. }else{
  485. $rice_card_express_money += $residueMoney;
  486. }
  487. }
  488. // 记录订单现金米卡信息
  489. $this->orderData['userRiceCard'] = $userRiceCardList[$riceCardId];
  490. $this->orderData['riceCardId'] = $riceCardId;
  491. $this->orderData['riceCardMoney'] = helper::bcmul($rice_card_money+$rice_card_express_money,1);
  492. $this->orderData['riceCardExpressMoney'] = helper::bcmul($rice_card_express_money,1);
  493. $this->orderData['userRiceCardList'] = array_values($userRiceCardList);
  494. return true;
  495. }
  496. /**
  497. * 验证用户选择的现金米卡
  498. * @param $riceCard
  499. * @return bool
  500. * @throws BaseException
  501. */
  502. private function verifyUserRiceCard($riceCardId,$userRiceCardList)
  503. {
  504. // 是否开启现金米卡抵扣
  505. if (!$this->checkoutRule['isRiceCard']) {
  506. return false;
  507. }
  508. // 如果没有可用的现金米卡,直接返回
  509. if ($riceCardId <= 0) {
  510. return false;
  511. }
  512. // 判断优惠券是否存在
  513. $riceCard = $this->getRiceCardInfo($riceCardId, $userRiceCardList);
  514. // 如果没有现金米卡,直接返回
  515. if (empty($riceCard)) {
  516. throwError('未找到米卡信息');
  517. }
  518. return true;
  519. }
  520. /**
  521. * 查找指定的优惠券信息
  522. * @param int $couponId 优惠券ID
  523. * @param array $couponList 优惠券列表
  524. * @return false|mixed
  525. */
  526. private function getRiceCardInfo(int $riceCardId, array $userRiceCardList)
  527. {
  528. return helper::getArrayItemByColumn($userRiceCardList, 'id', $riceCardId);
  529. }
  530. /**
  531. * 订单配送-快递配送
  532. * @return bool
  533. * @throws \think\db\exception\DataNotFoundException
  534. * @throws \think\db\exception\DbException
  535. * @throws \think\db\exception\ModelNotFoundException
  536. */
  537. private function setOrderExpress()
  538. {
  539. // 设置默认数据:配送费用
  540. helper::setDataAttribute($this->goodsList, [
  541. 'expressPrice' => 0,
  542. ], true);
  543. // 当前用户收货城市id
  544. if($this->param['addressId']){ //有传参
  545. $addredd = UserAddress::get(['user_id' => $this->user['user_id'], 'address_id' => $this->param['addressId']]);
  546. $cityId = $addredd ? (int)$addredd['city_id'] : 0;
  547. $this->orderData['address'] = $addredd;
  548. }else{ //没有传参读默认地址
  549. $cityId = $this->user['address_default'] ? (int)$this->user['address_default']['city_id'] : 0;
  550. $this->orderData['address'] = $this->user['address_default'];
  551. }
  552. if ($this->param['delivery'] == DeliveryTypeEnum::EXPRESS) { // 普通快递
  553. // 初始化配送服务类
  554. $ExpressService = new ExpressService($cityId, $this->goodsList);
  555. // 验证商品是否在限购配送范围
  556. $isDeliveryLimit = $ExpressService->isDeliveryLimit();
  557. if($cityId > 0){
  558. if ($isDeliveryLimit == false) {
  559. $this->setError("很抱歉,您的收货地址在限购地区的配送范围内");
  560. $this->setErrorStatus(423);
  561. $this->orderData['isIntraRegion'] = $isDeliveryLimit;
  562. }else{
  563. // 验证商品是否在配送范围
  564. $isIntraRegion = $ExpressService->isIntraRegion();
  565. if ($isIntraRegion == false) {
  566. $notInRuleGoodsName = $ExpressService->getNotInRuleGoodsName();
  567. $this->setError("很抱歉,您的收货地址不在商品 [".limit_str((string)$notInRuleGoodsName)."] 的配送范围内");
  568. $this->setErrorStatus(423);
  569. }
  570. $this->orderData['isIntraRegion'] = $isIntraRegion;
  571. }
  572. }
  573. // 订单总运费金额
  574. $this->orderData['expressPrice'] = $ExpressService->getDeliveryFee();
  575. } else { // 门店自提
  576. $this->orderData['expressPrice'] = "0.00";
  577. }
  578. return true;
  579. }
  580. /**
  581. * 创建新订单
  582. * @param array $order 订单信息
  583. * @return bool
  584. */
  585. public function createOrder(array $order)
  586. {
  587. // 表单验证
  588. if (!$this->validateOrderForm($order)) {
  589. return false;
  590. }
  591. // 创建新的订单
  592. $status = $this->buyhelpModel->transaction(function () use ($order) {
  593. // dd($order);
  594. // 创建订单事件
  595. return $this->createOrderEvent($order);
  596. });
  597. // 余额支付标记订单已支付
  598. return $status;
  599. }
  600. /**
  601. * 创建订单事件
  602. * @param $order
  603. * @return bool
  604. * @throws BaseException
  605. * @throws \Exception
  606. */
  607. private function createOrderEvent($order)
  608. {
  609. // 新增订单记录
  610. $status = $this->add($order, $this->param['remark']);
  611. //金米粒处理逻辑
  612. if($order['orderPayPrice']>0){
  613. //冻结金米粒数量
  614. if($order['goldRiceAmount']>0) UserModel::setIncDecByField($this->user['user_id'],['gold_rice_frozen'=>(float)$order['goldRiceAmount']],['gold_rice'=>(float)$order['goldRiceAmount']]);
  615. }else{
  616. if($order['goldRiceAmount']>0){
  617. //写金米粒出账记录
  618. GoldRiceModel::add($this->user['user_id'],$this->orderData['order_no'],'下单抵扣',$order['goldRiceAmount'],0);
  619. //用户直接扣除金米粒
  620. UserModel::setDecByField($this->user['user_id'],'gold_rice',(float)$order['goldRiceAmount']);
  621. }
  622. }
  623. if($order['riceCardId']>0 && $order['riceCardMoney']>0){
  624. //根据支付的金额来判断逻辑
  625. if($order['orderPayPrice']>0){
  626. //冻结现金卡金额
  627. UserRiceCardModel::setIncDecByField($order['riceCardId'],['frozen_amount'=>(float)$order['riceCardMoney']],['balance'=>(float)$order['riceCardMoney']]);
  628. }else{//不需要结算金额
  629. //写现金卡出账记录
  630. UserRiceCardConsumeModel::add($order['userRiceCard'],$this->orderData['order_no'],$order['orderPayPrice'],$order['riceCardMoney']);
  631. //如果可用余额等于要抵扣的金额
  632. if($order['riceCardMoney']==$order['userRiceCard']['balance']){
  633. //现金卡直接减可用余额,并且状态改为已失效
  634. UserRiceCardModel::setIncDecByField($order['riceCardId'],[],['balance'=>(float)$order['riceCardMoney']],['effect_state'=>2]);
  635. }else{
  636. //现金卡直接减可用余额
  637. UserRiceCardModel::setDecByField($order['riceCardId'],'balance',(float)$order['riceCardMoney']);
  638. }
  639. // 更新商品销量(付款后减库存、加销量)
  640. $order['goods'] = $order['goodsList'];
  641. $order['delivery_type'] = $order['delivery'];
  642. StockFactory::getFactory(OrderSourceEnum::GROUPBUY)->updateStockSales($order);
  643. }
  644. }
  645. return $status;
  646. }
  647. /**
  648. * 构建支付请求的参数
  649. * @return array
  650. * @throws BaseException
  651. * @throws \think\db\exception\DataNotFoundException
  652. * @throws \think\db\exception\DbException
  653. * @throws \think\db\exception\ModelNotFoundException
  654. */
  655. public function onOrderPayment()
  656. {
  657. return PaymentService::orderPayment($this->model, $this->param['payType']);
  658. }
  659. /**
  660. * 表单验证 (订单提交)
  661. * @param array $order 订单信息
  662. * @return bool
  663. */
  664. private function validateOrderForm(array $order)
  665. {
  666. if ($order['delivery'] == DeliveryTypeEnum::EXPRESS) {
  667. if (empty($order['address'])) {
  668. $this->error = '您还没有选择配送地址';
  669. return false;
  670. }
  671. }
  672. // 余额支付时判断用户余额是否足够
  673. if ($order['payType'] == OrderPayTypeEnum::BALANCE) {
  674. if ($this->user['balance'] < $order['orderPayPrice']) {
  675. $this->error = '您的余额不足,无法使用余额支付';
  676. return false;
  677. }
  678. }
  679. return true;
  680. }
  681. /**
  682. * 当前订单是否存在和使用积分抵扣
  683. * @param $order
  684. * @return bool
  685. */
  686. private function isExistPointsDeduction($order)
  687. {
  688. return $order['isAllowPoints'] && $order['isUsePoints'];
  689. }
  690. /**
  691. * 新增订单记录
  692. * @param $order
  693. * @param string $remark
  694. * @return false|int
  695. */
  696. private function add($order, $remark = ''){
  697. $user = UserModel::where('user_id',$this->user['user_id'])->with(['avatar'])->find();
  698. //发起拼团
  699. $help = [];
  700. // 根据推广监控ID判断活动效果归属
  701. $promotionMonitorId = PromotionMonitor::checkActEffectOwner(4, $order['promotionMonitorId'] ?? 0, $order['group_buy_activity_id']);
  702. if($order['join_id']==0){
  703. $activity = GroupBuyActivity::where("id",$order['group_buy_activity_id'])->find();
  704. $join = [
  705. 'group_buy_activity_id' => $order['group_buy_activity_id'],
  706. 'people_count'=> $activity['people_count'],
  707. 'end_time' => Date("Y-m-d H:i:s",time() + $activity['during_time']*60*60),
  708. 'share_title'=>$activity['share_title'],
  709. 'create_time'=>time(),
  710. 'update_time'=>time(),
  711. 'user_id'=>$this->user['user_id']
  712. ];
  713. $this->buyjoinModel->save($join);
  714. $help = [
  715. 'user_id' => $this->user['user_id'],
  716. 'order_no' => $this->model->orderNo('PT'),
  717. 'group_buy_activity_id' => $order['group_buy_activity_id'],
  718. 'join_id'=>$this->buyjoinModel['id'],
  719. 'goods_num' =>$order['orderTotalNum'],
  720. 'head_picture'=>$user->avatar['preview_url']??'',
  721. 'gold_rice_amount' => $order['goldRiceAmount']??0,
  722. 'gold_rice_money' => $order['goldRiceMoney']??0,
  723. 'rice_card_id'=>$order['riceCardId']<=0?0:$order['riceCardId'],
  724. 'rice_card_money'=>$order['riceCardMoney'],
  725. 'rice_card_express_money'=>$order['riceCardExpressMoney'],
  726. 'pay_money'=> $order['orderPayPrice'],
  727. 'express_money'=> $order['expressPrice'],
  728. 'order_money'=> helper::bcadd($order['expressPrice'],$order['orderTotalGroupPrice']),
  729. 'provider_ids'=>$order['orderProviderIds'],
  730. 'good_rice_card_money'=>$order['goodsList'][0]['rice_card_money']??0,
  731. 'promotion_monitor_id' => $promotionMonitorId,
  732. 'staff_user_id' => $order['goodsList'][0]['staffUserId'] ?? 0,
  733. 'staff_shop_id' => $order['goodsList'][0]['shopId'] ?? 0
  734. ];
  735. }
  736. //参与拼团
  737. if($order['join_id']>0){
  738. $help = [
  739. 'user_id' => $this->user['user_id'],
  740. 'order_no' => $this->model->orderNo('PT'),
  741. 'group_buy_activity_id' => $order['group_buy_activity_id'],
  742. 'join_id'=>$order['join_id'],
  743. 'goods_num' =>$order['orderTotalNum'],
  744. 'head_picture'=>$user->avatar['preview_url']??'',
  745. 'gold_rice_amount' => $order['goldRiceAmount']??0,
  746. 'gold_rice_money' => $order['goldRiceMoney']??0,
  747. 'rice_card_id'=>$order['riceCardId']<=0?0:$order['riceCardId'],
  748. 'rice_card_money'=>$order['riceCardMoney'],
  749. 'rice_card_express_money'=>$order['riceCardExpressMoney'],
  750. 'pay_money'=> $order['orderPayPrice'],
  751. 'express_money'=> $order['expressPrice'],
  752. 'rice_card_express_money'=>$order['riceCardExpressMoney'],
  753. 'order_money'=> helper::bcadd($order['expressPrice'],$order['orderTotalGroupPrice']),
  754. 'provider_ids'=>$order['orderProviderIds'],
  755. 'good_rice_card_money'=>$order['goodsList'][0]['rice_card_money']??0,
  756. 'promotion_monitor_id' => $promotionMonitorId,
  757. 'staff_user_id' => $order['goodsList'][0]['staffUserId'] ?? 0,
  758. 'staff_shop_id' => $order['goodsList'][0]['shopId'] ?? 0
  759. ];
  760. }
  761. $address['user_name'] = $order['address']['name']??'';
  762. $address['phone'] = $order['address']['phone']??'';
  763. $address['province_id'] = $order['address']['province_id']??0;
  764. $address['city_id'] = $order['address']['city_id']??0;
  765. $address['region_id'] = $order['address']['region_id']??0;
  766. $address['detail'] = $order['address']['detail']??'';
  767. $help = array_merge($help,$address);
  768. $help['pay_type'] = $order['payType']??OrderPayTypeEnum::WECHAT;
  769. $isPay = false;
  770. //米卡兑换直接成功
  771. if($order['orderPayPrice']<=0 || $order['payType']==OrderPayTypeEnum::MICAH_EXCHANGE){
  772. $help['pay_state'] = 1;
  773. $help['pay_time'] = time();
  774. $partJoin = GroupBuyJoin::where('id','=',$help['join_id'])->find();
  775. $partJoin->help_count = $partJoin->help_count + 1;
  776. $partJoin->save();
  777. $isPay = true;
  778. }
  779. $this->orderData['order_no'] = $help['order_no'];
  780. // 保存参团记录
  781. $this->buyhelpModel->save($help);
  782. //米卡支付完成并且属于参团的,要看是不是成团了,成团要写订单
  783. if($isPay&&$order['join_id']>0){
  784. if($partJoin->help_count==$partJoin->people_count){
  785. $pay = new GroupBuyPay;
  786. $pay->ptSuccessNotify($help['join_id']);
  787. }
  788. }
  789. StockFactory::getFactory(OrderSourceEnum::GROUPBUY)->updateGoodsStock($order);
  790. //更新拼团活动库存的数量
  791. StockFactory::getFactory(OrderSourceEnum::GROUPBUY)->updateActivityStock($order);
  792. return true;
  793. }
  794. /**
  795. * 更新商品库存 (针对下单减库存的商品)
  796. * 普通快递、门店自提 分开扣库存
  797. * @param $order
  798. * @return mixed
  799. */
  800. private function updateGoodsStockNum($order)
  801. {
  802. return StockFactory::getFactory($this->model['order_source'])->updateGoodsStock($order);
  803. }
  804. /**
  805. * 保存砍价信息
  806. * @param $order
  807. * @return int
  808. */
  809. private function saveKjActivityJoin($order)
  810. {
  811. // 订单商品列表
  812. foreach ($order['goodsList'] as $key=> $goods) {
  813. $data[] = [
  814. 'where' => ['id' => $goods['bargain_id']],
  815. 'data' => [
  816. 'order_id' => $this->model['order_id'],//订单ID
  817. 'order_price' => helper::bcadd($goods['bargain_price'],$this->orderData['expressPrice']),//订单金额+运费
  818. 'is_submit_order'=>1 //是否提交订单 1是
  819. ]
  820. ];
  821. }
  822. return (new KjActivityJoin())->updateAll($data) !== false;
  823. }
  824. /**
  825. * 记录收货地址
  826. * @param $address
  827. * @return false|\think\Model
  828. */
  829. private function saveOrderAddress($address)
  830. {
  831. return $this->model->address()->save([
  832. 'user_id' => $this->user['user_id'],
  833. 'store_id' => $this->storeId,
  834. 'name' => $address['name'],
  835. 'phone' => $address['phone'],
  836. 'province_id' => $address['province_id'],
  837. 'city_id' => $address['city_id'],
  838. 'region_id' => $address['region_id'],
  839. 'detail' => $address['detail'],
  840. ]);
  841. }
  842. /**
  843. * 设置错误信息
  844. * @param $error
  845. */
  846. protected function setError($error)
  847. {
  848. empty($this->error) && $this->error = $error;
  849. }
  850. /**
  851. * 获取错误信息
  852. * @return mixed
  853. */
  854. public function getError()
  855. {
  856. return $this->error ?: '';
  857. }
  858. /**
  859. * 设置错误状态
  860. * @param $errorStatus
  861. */
  862. protected function setErrorStatus($errorStatus)
  863. {
  864. empty($this->errorStatus) && $this->errorStatus = $errorStatus;
  865. }
  866. /**
  867. * 获取错误信息
  868. * @return mixed
  869. */
  870. public function getErrorStatus()
  871. {
  872. return $this->errorStatus ?: 0;
  873. }
  874. /**
  875. * 是否存在错误
  876. * @return bool
  877. */
  878. public function hasError()
  879. {
  880. return !empty($this->error);
  881. }
  882. }