CheckoutExchange.php 80 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887
  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\member\DeductionLimit as DeductionLimitModel;
  19. use app\api\model\member\MemberGoods;
  20. use app\api\model\mj\MjSendActivity;
  21. use app\api\model\OrderGoodsTaocan as OrderGoodsTaocanModel;
  22. use app\api\model\Order as OrderModel;
  23. use app\api\model\qc\QcMjSendActivity;
  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\model\member\GoldRice as GoldRiceModel;
  31. use app\api\service\User as UserService;
  32. use app\api\service\Payment as PaymentService;
  33. use app\api\service\coupon\GoodsDeduct as GoodsDeductService;
  34. use app\api\service\ricecard\GoodsDeduct as RiceDeductService;
  35. use app\api\service\points\GoodsDeduct as PointsDeductService;
  36. use app\api\service\order\source\checkout\Factory as CheckoutFactory;
  37. use app\common\enum\Setting as SettingEnum;
  38. use app\common\enum\order\PayType as OrderPayTypeEnum;
  39. use app\common\enum\order\OrderStatus as OrderStatusEnum;
  40. use app\common\enum\order\OrderSource as OrderSourceEnum;
  41. use app\common\enum\order\DeliveryType as DeliveryTypeEnum;
  42. use app\common\service\BaseService;
  43. use app\common\service\card\UserRiceCard as UserRiceCardService;
  44. use app\common\service\commission\RecordWaitCommission;
  45. use app\common\service\delivery\Express as ExpressService;
  46. use app\common\service\goods\source\Factory as StockFactory;
  47. use app\common\library\helper;
  48. use app\common\exception\BaseException;
  49. use app\common\enum\order\PayStatus as PayStatusEnum;
  50. use app\common\model\ShopGoodsSku;
  51. use app\common\model\User;
  52. /**
  53. * 订单结算台服务类
  54. * Class Checkout
  55. * @package app\api\service\order
  56. */
  57. class CheckoutExchange extends BaseService
  58. {
  59. /* $model OrderModel 订单模型 */
  60. public $model;
  61. /* @var UserModel $user 当前用户信息 */
  62. private $user;
  63. // 订单结算商品列表
  64. private $goodsList = [];
  65. private $invalidGoodsList = [];
  66. private $shopInfo = [];
  67. // 错误信息
  68. protected $error;
  69. // 错误信息状态
  70. protected $errorStatus;
  71. /**
  72. * 订单结算api参数
  73. * @var array
  74. */
  75. private $param = [
  76. 'delivery' => DeliveryTypeEnum::EXPRESS, // 配送方式 默认:快递配送
  77. 'couponId' => 0, // 优惠券id
  78. 'riceCardId' => 0, // 现金米卡id
  79. 'isUsePoints' => 0, // 是否使用积分抵扣
  80. 'isUseGoldRice' => 0, // 默认使用金米粒
  81. 'remark' => '', // 买家留言
  82. 'payType' => OrderPayTypeEnum::EXCHANGE, // 支付方式
  83. 'addressId' => 0, //地址ID
  84. 'staffUserId' => 0, //分享链接用户ID
  85. ];
  86. /**
  87. * 订单结算的规则
  88. * @var array
  89. */
  90. private $checkoutRule = [
  91. 'isUserGrade' => false, // 会员等级折扣
  92. 'isCoupon' => false, // 优惠券抵扣
  93. 'isRiceCard' => false, // 现金米卡抵扣
  94. 'isUsePoints' => false, // 是否使用积分抵扣
  95. ];
  96. /**
  97. * 订单来源
  98. * @var array
  99. */
  100. private $orderSource = [
  101. 'source' => OrderSourceEnum::MASTER,
  102. 'source_id' => 0,
  103. ];
  104. /**
  105. * 订单结算数据
  106. * @var array
  107. */
  108. private $orderData = [];
  109. /**
  110. * 构造函数
  111. * Checkout constructor.
  112. * @throws BaseException
  113. */
  114. public function __construct()
  115. {
  116. parent::__construct();
  117. $this->user = UserService::getCurrentLoginUser(true);
  118. $this->model = new OrderModel;
  119. $this->storeId = $this->getStoreId();
  120. }
  121. /**
  122. * 设置结算台请求的参数
  123. * @param $param
  124. * @return array
  125. */
  126. public function setParam($param)
  127. {
  128. $this->param = array_merge($this->param, $param);
  129. return $this->getParam();
  130. }
  131. /**
  132. * 获取结算台请求的参数
  133. * @return array
  134. */
  135. public function getParam()
  136. {
  137. return $this->param;
  138. }
  139. /**
  140. * 订单结算的规则
  141. * @param $data
  142. * @return $this
  143. */
  144. public function setCheckoutRule($data)
  145. {
  146. $this->checkoutRule = array_merge($this->checkoutRule, $data);
  147. return $this;
  148. }
  149. /**
  150. * 设置订单来源(普通订单)
  151. * @param $data
  152. * @return $this
  153. */
  154. public function setOrderSource($data)
  155. {
  156. $this->orderSource = array_merge($this->orderSource, $data);
  157. return $this;
  158. }
  159. /**
  160. * 订单确认-结算台
  161. * @param $goodsList
  162. * @return array
  163. * @throws BaseException
  164. * @throws \think\db\exception\DataNotFoundException
  165. * @throws \think\db\exception\DbException
  166. * @throws \think\db\exception\ModelNotFoundException
  167. */
  168. public function onCheckout($goodsList)
  169. {
  170. // 订单确认-立即购买
  171. $this->goodsList = $goodsList;
  172. return $this->checkout();
  173. }
  174. //积分兑换商品
  175. public function onCheckoutExchange($goodsList)
  176. {
  177. $this->goodsList = $goodsList;
  178. $this->orderData = $this->getOrderData();
  179. $this->validateGoodsList();
  180. $this->orderData['distributorTotalMoney'] = 0;
  181. $this->orderData['activityDiscountTotalPrice'] = 0;
  182. $this->orderData['memberTotalMoney'] = 0;
  183. // 设置订单商品总金额(不含优惠折扣,不含会员折扣,不含金米粒抵扣,不含专属优惠)
  184. $this->setOrderTotalPrice();
  185. // 计算优惠券抵扣
  186. $this->setOrderCouponMoney([], (int)$this->param['couponId']);
  187. //订单总运费金额
  188. $this->setOrderExpress();
  189. //金米粒抵扣-V1.4.0版本添加2022年6月1日,运费不能抵扣金米粒
  190. $this->setOrderGolRiceAmount();
  191. //金米粒获取-V1.4.0版本添加2022年6月7日,运费不获取金米粒
  192. $this->setOrderInputGolRiceAmount();
  193. $this->setOrderRiceCardMoney([],-1);
  194. // 计算订单最终金额+运费
  195. $this->setOrderPayPrice();
  196. //设置满件送活动是否有赠送商品--一定要放在满就送后面来处理,不然会报错
  197. $this->setMjGoodsList();
  198. // 订单商品总数量
  199. $orderTotalNum = helper::getArrayColumnSum($this->goodsList, 'total_num') + helper::getArrayColumnSum($this->invalidGoodsList, 'total_num');
  200. return array_merge([
  201. 'goodsList' => $this->goodsList, // 商品信息
  202. 'invalidGoodsList' => $this->invalidGoodsList, // 无效商品信息(门店无库存)
  203. 'shopInfo' => $this->shopInfo, // 门店信息
  204. 'isPickup' => false, // 是否支持门店自提 true-支持 false-不支持
  205. 'orderTotalNum' => $orderTotalNum, // 商品总数量
  206. // 'couponList' => array_values($couponList), // 优惠券列表
  207. 'hasError' => $this->hasError(),
  208. 'errorMsg' => $this->getError(),
  209. 'errorStatus' => $this->getErrorStatus(),
  210. ], $this->orderData);
  211. }
  212. /**
  213. * 订单结算台
  214. * @return array
  215. * @throws BaseException
  216. * @throws \think\db\exception\DataNotFoundException
  217. * @throws \think\db\exception\DbException
  218. * @throws \think\db\exception\ModelNotFoundException
  219. */
  220. private function checkout()
  221. {
  222. // 整理订单数据
  223. $this->orderData = $this->getOrderData();
  224. // 门店自提处理
  225. $this->setShopPickupData();
  226. // 验证商品状态, 是否允许购买
  227. $this->validateGoodsList();
  228. // 设置订单商品会员折扣价
  229. $this->setOrderGoodsGradeMoney();
  230. //活动使用排序:N件X折活动 > 会员折扣 > 优惠券 > 推荐官专属折扣 > 金米粒抵扣 > 满就赠 > 全场满件送 > 满件送
  231. //设置N件X折活动优惠-v1.3.6版本添加2022年3月11日
  232. $this->setActivityDiscountMoney();
  233. // 设置订单商品总金额(不含优惠折扣,不含会员折扣,不含金米粒抵扣,不含专属优惠)
  234. $this->setOrderTotalPrice();
  235. //会员折扣-V1.4.0版本添加2022年6月1日
  236. $this->setOrderGoodsMemberMoney();
  237. // 当前用户可用的优惠券列表
  238. // $couponList = $this->getUserCouponList((float)$this->orderData['orderTotalPrice']);
  239. $couponList = $this->getUserCouponList();
  240. // 计算优惠券抵扣
  241. $this->setOrderCouponMoney($couponList, (int)$this->param['couponId']);
  242. //设置分销员购物或分享后用户购买的折扣价-V1.2.2.2版本添加2021年11月18日
  243. $this->setOrderGoodsDistributorMoney();
  244. // 计算可用积分抵扣
  245. $this->setOrderPoints();
  246. //订单总运费金额
  247. $this->setOrderExpress();
  248. //金米粒抵扣-V1.4.0版本添加2022年6月1日,运费不能抵扣金米粒
  249. $this->setOrderGolRiceAmount();
  250. //金米粒获取-V1.4.0版本添加2022年6月7日,运费不获取金米粒
  251. $this->setOrderInputGolRiceAmount();
  252. //获取当前可用的现金卡列表
  253. $userRiceCardList = $this->getUserRiceCardList();
  254. //计算使用米卡现金券抵扣后的金额-start
  255. $this->setOrderRiceCardMoney($userRiceCardList,(int)$this->param['riceCardId']);
  256. //计算使用米卡现金券抵扣后的金额-end
  257. // 计算订单商品的实际付款金额
  258. $this->setOrderGoodsPayPrice();
  259. // 计算订单最终金额+运费
  260. $this->setOrderPayPrice();
  261. // 计算订单积分赠送数量
  262. $this->setOrderPointsBonus();
  263. //订单商品的所有店铺集合2021年9月28日 10:56:45
  264. $this->setOrderProviderIds();
  265. // 无效商品信息处理
  266. $this->setInvalidGoods();
  267. // 订单商品总数量
  268. $orderTotalNum = helper::getArrayColumnSum($this->goodsList, 'total_num') + helper::getArrayColumnSum($this->invalidGoodsList, 'total_num');
  269. //设置满就送活动是否有赠送商品--一定要放在所有优惠后面最后面来处理,不然会报错
  270. $this->setFullGoodsList();
  271. //设置全场满件送活动是否有赠送商品--一定要放在满就送后面来处理,不然会报错
  272. $this->setQcMjGoodsList();
  273. //设置满件送活动是否有赠送商品--一定要放在满就送后面来处理,不然会报错
  274. $this->setMjGoodsList();
  275. // 验证商品状态, 是否允许购买
  276. // $this->validateGoodsList();
  277. // 返回订单数据
  278. return array_merge([
  279. 'goodsList' => $this->goodsList, // 商品信息
  280. 'invalidGoodsList' => $this->invalidGoodsList, // 无效商品信息(门店无库存)
  281. 'shopInfo' => $this->shopInfo, // 门店信息
  282. 'isPickup' => $this->isPickup, // 是否支持门店自提 true-支持 false-不支持
  283. 'orderTotalNum' => $orderTotalNum, // 商品总数量
  284. // 'couponList' => array_values($couponList), // 优惠券列表
  285. 'hasError' => $this->hasError(),
  286. 'errorMsg' => $this->getError(),
  287. 'errorStatus' => $this->getErrorStatus(),
  288. ], $this->orderData);
  289. }
  290. /**
  291. * 设置N件X折活动优惠设置
  292. * @throws \think\db\exception\DataNotFoundException
  293. * @throws \think\db\exception\DbException
  294. * @throws \think\db\exception\ModelNotFoundException
  295. * @author: zjwhust
  296. * @Time: 2022/3/11 11:28
  297. */
  298. public function setActivityDiscountMoney(){
  299. // 设置默认数据:订单信息
  300. helper::setDataAttribute($this->orderData, [
  301. 'activityDiscountList' => [], // N件X折优惠列表
  302. 'activityDiscountTotalPrice' => 0.00, // N件X折优惠总金额
  303. ], false);
  304. // 设置默认数据
  305. helper::setDataAttribute($this->goodsList, [
  306. // 是否参与N件X折活动 0否 1是
  307. 'is_activity_discount' => 0,
  308. // N件X折活动ID
  309. 'activity_discount_id' => 0,
  310. // N件X折活动折扣金额
  311. 'activity_discount_total_price' => 0.00,//N件活动折扣金额
  312. // N件X折活动描述
  313. 'activity_discount_desc' => '',
  314. // N件X折活动叠加优惠 1-优惠券 2-满就送 3-满件送 多个以逗号分隔
  315. 'activity_discount_overlay' => '',
  316. 'activity_discount_count' => '',//数量
  317. ], true);
  318. $i = 0;
  319. foreach ($this->goodsList as $item){
  320. (new GoodsModel)->getActivityDiscountDetail($item,2);
  321. if($item['is_activity_discount']){
  322. $this->orderData['activityDiscountList'][$i]['goods_id'] = $item['goods_id'];
  323. $this->orderData['activityDiscountList'][$i]['goods_image'] = $item['goods_image'];
  324. $this->orderData['activityDiscountList'][$i]['activity_discount_total_price'] = $item['activity_discount_total_price'];
  325. $this->orderData['activityDiscountList'][$i]['activity_discount_desc'] = $item['activity_discount_desc'];
  326. $this->orderData['activityDiscountList'][$i]['total_price'] = $item['total_price'];
  327. $i++;
  328. $this->orderData['activityDiscountTotalPrice'] += $item['activity_discount_total_price'];
  329. }
  330. }
  331. $this->orderData['activityDiscountTotalPrice'] = helper::number2($this->orderData['activityDiscountTotalPrice']);//设置订单优惠合计
  332. }
  333. /**
  334. * 判断满就送商品是否需要添加
  335. */
  336. public function setFullGoodsList()
  337. {
  338. $isFull = FullSendActivity::validActivityList($this->goodsList,$this->orderData);
  339. }
  340. /**
  341. * 判断全场满件送商品是否需要添加
  342. */
  343. public function setQcMjGoodsList()
  344. {
  345. $isMj = QcMjSendActivity::validActivityList($this->goodsList,$this->orderData);
  346. if($isMj){
  347. foreach ($this->goodsList as $good){
  348. foreach ($isMj as $key=>$num){
  349. if($num>0 && $good['goods_id']==$key && ($good['total_num']+$num)>$good['skuInfo']['stock_num']){
  350. // dd($good['total_num']+$num-$good['skuInfo']['stock_num']);
  351. $this->setError("很抱歉,赠品 [".limit_str((string)$good['goods_name'])."] 库存不足");
  352. $this->setErrorStatus(424);
  353. }
  354. }
  355. }
  356. }
  357. }
  358. /**
  359. * 判断满件送商品是否需要添加
  360. */
  361. public function setMjGoodsList()
  362. {
  363. $isMj = MjSendActivity::validActivityList($this->goodsList,$this->orderData);
  364. // dd($isMj);
  365. if($isMj){
  366. foreach ($this->goodsList as $good){
  367. foreach ($isMj as $key=>$num){
  368. if($num>0 && $good['goods_id']==$key && ($good['total_num']+$num)>$good['skuInfo']['stock_num']){
  369. // dd($good['total_num']+$num-$good['skuInfo']['stock_num']);
  370. $this->setError("很抱歉,赠品 [".limit_str((string)$good['goods_name'])."] 库存不足");
  371. $this->setErrorStatus(424);
  372. }
  373. }
  374. }
  375. }
  376. // return $status;
  377. }
  378. /**
  379. * 门店自提处理
  380. */
  381. public function setShopPickupData() {
  382. $deliveryType = $this->param['delivery'];
  383. // 返回商品处理
  384. $normalGoodsList = []; // 正常状态商品
  385. $invalidGoodsList = []; // 无货状态商品
  386. // 门店信息
  387. $userStaff = User::detail($this->param['staffUserId']);
  388. $shopInfo = [];
  389. $isPickup = false;
  390. if (!empty($userStaff) && $userStaff['role'] == User::SHOP_SELLER) {
  391. $shopInfo = Shops::find($userStaff['shop_id']);
  392. if ($shopInfo['is_pickup']) {
  393. $isPickup = true;
  394. }
  395. }
  396. if ($deliveryType == DeliveryTypeEnum::SHOPS_DELIVERY) {
  397. if (empty($shopInfo)) {
  398. // 门店自提方式 且门店不存在
  399. throwError("不支持门店自提方式");
  400. }
  401. if (!$shopInfo['is_pickup']) {
  402. // 门店自提开关
  403. throwError("不支持门店自提方式");
  404. }
  405. }
  406. // 门店库存总和
  407. $shopStockTotal = 0;
  408. foreach($this->goodsList as &$item) {
  409. // 获取商品门店库存
  410. if ($shopInfo) {
  411. $shopGoodsSku = ShopGoodsSku::with('shopGoods')->where(['shop_id' => $shopInfo['shop_id'], 'goods_id' => $item['goods_id'], 'goods_sku_id' => $item['goods_sku_id']])->find();
  412. if (!empty($shopGoodsSku) && $shopGoodsSku['stock_num'] > 0) {
  413. $shopStockTotal += $shopGoodsSku['stock_num'];
  414. }
  415. }
  416. // 判断配送方式
  417. if ($deliveryType == DeliveryTypeEnum::EXPRESS) { // 快递配送
  418. $normalGoodsList[] = $item;
  419. // 判断库存 todo 购买数量大于实际库存 取实际库存
  420. // 有库存
  421. if ($item['skuInfo']['stock_num'] >= $item['total_num']) {
  422. $item['stock_enough'] = true;
  423. } else {
  424. $item['stock_enough'] = false;
  425. $item['total_num'] = $item['skuInfo']['stock_num']; // 库存不够时,取最大库存
  426. $item['total_price'] = helper::bcmul($item['goods_price'], $item['total_num']);
  427. }
  428. $item['is_pickup_invalid'] = false;
  429. } elseif ($deliveryType == DeliveryTypeEnum::SHOPS_DELIVERY) { // 门店自提
  430. // 判断有无库存
  431. if (!empty($shopGoodsSku)) {
  432. $item['stock_total'] = $shopGoodsSku['shopGoods']['stock_total'];
  433. $item['alarm_stock_total'] = $shopGoodsSku['shopGoods']['alarm_stock_total'];
  434. $item['skuInfo']['stock_num'] = $shopGoodsSku['stock_num'];
  435. $item['skuInfo']['alarm_stock_num'] = $shopGoodsSku['alarm_stock_num'];
  436. if ($shopGoodsSku['stock_num'] > 0) {
  437. // 有库存
  438. if ($shopGoodsSku['stock_num'] >= $item['total_num']) {
  439. $item['stock_enough'] = true;
  440. } else {
  441. $item['stock_enough'] = false;
  442. $item['total_num'] = $shopGoodsSku['stock_num']; // 库存不够时,取最大库存
  443. $item['total_price'] = helper::bcmul($item['goods_price'], $item['total_num']);
  444. }
  445. $normalGoodsList[] = $item;
  446. } else {
  447. // 没有库存
  448. $item['stock_enough'] = false;
  449. $item['is_pickup_invalid'] = true;
  450. $invalidGoodsList[] = $item;
  451. }
  452. } else {
  453. // 无库存
  454. // $item['stock_total'] = 0;
  455. // $item['alarm_stock_total'] = 0;
  456. // $item['skuInfo']['stock_num'] = 0;
  457. // $item['skuInfo']['alarm_stock_num'] = 0;
  458. $item['stock_enough'] = false;
  459. // $item['total_num'] = 0; // 无门店库存
  460. // $item['total_price'] = 0;
  461. $item['is_pickup_invalid'] = true;
  462. $invalidGoodsList[] = $item;
  463. }
  464. }
  465. }
  466. if ($shopStockTotal <= 0) { // 门店总库存不大于0
  467. $isPickup = false;
  468. }
  469. $this->shopInfo = $shopInfo; // 门店信息
  470. $this->isPickup = $isPickup; // 是否支持门店自提
  471. $this->orderData['shopInfo'] = $shopInfo;
  472. // $this->goodsList = $normalGoodsList;
  473. // $this->invalidGoodsList = $invalidGoodsList;
  474. }
  475. /**
  476. * 无效商品信息处理
  477. */
  478. public function setInvalidGoods() {
  479. $normalGoodsList = []; // 正常状态商品
  480. $invalidGoodsList = []; // 无货状态商品
  481. foreach($this->goodsList as $item) {
  482. if (!$item['is_pickup_invalid']) { // 快递配送
  483. $normalGoodsList[] = $item;
  484. } else {
  485. $invalidGoodsList[] = $item;
  486. }
  487. }
  488. $this->goodsList = $normalGoodsList;
  489. $this->invalidGoodsList = $invalidGoodsList;
  490. }
  491. //我的可用现金卡
  492. public function getUserRiceCardList(){
  493. $user = UserService::getCurrentLoginUser(true);
  494. $list = UserRiceCardModel::getUserRiceCardList($user['user_id'])->toArray();
  495. $data = [];
  496. foreach ($list as $key=>&$item){
  497. $i = 0;
  498. $exceptGoodsId = helper::getArrayColumn($item['riceCardGoodsExcept'],'goods_id');
  499. foreach ($this->goodsList as $good) {
  500. if(!empty($item['dk_cat_ids']) && strpos((string)$item['dk_cat_ids'],(string)$good['category']['category_id']) === false){
  501. unset($list[$key]);
  502. $i = 1;
  503. }
  504. if(!empty($exceptGoodsId) && in_array($good['goods_id'],$exceptGoodsId)){
  505. unset($list[$key]);
  506. $i = 1;
  507. }
  508. }
  509. if(!$i){
  510. unset($item['riceCardGoodsExcept']);
  511. $data[$item['id']] = $item;
  512. }
  513. }
  514. if($this->param['riceCardId']==0){ //-1表示不使用米卡
  515. $this->param['riceCardId'] = key($data)??0;//若果没有选择米卡,默认使用第一张
  516. }
  517. return $data;
  518. }
  519. /**
  520. * 计算订单可用积分抵扣
  521. * @return bool
  522. * @throws \think\db\exception\DataNotFoundException
  523. * @throws \think\db\exception\DbException
  524. * @throws \think\db\exception\ModelNotFoundException
  525. */
  526. private function setOrderPoints()
  527. {
  528. // 设置默认的商品积分抵扣信息
  529. $this->setDefaultGoodsPoints();
  530. // 积分设置
  531. $setting = SettingModel::getItem('points');
  532. // 条件:后台开启下单使用积分抵扣
  533. if (!$setting['is_shopping_discount'] || !$this->checkoutRule['isUsePoints']) {
  534. return false;
  535. }
  536. // 条件:订单金额满足[?]元
  537. if (helper::bccomp($setting['discount']['full_order_price'], $this->orderData['orderTotalPrice']) === 1) {
  538. return false;
  539. }
  540. // 计算订单商品最多可抵扣的积分数量
  541. $this->setOrderGoodsMaxPointsNum();
  542. // 订单最多可抵扣的积分总数量
  543. $maxPointsNumCount = helper::getArrayColumnSum($this->goodsList, 'max_points_num');
  544. // 实际可抵扣的积分数量
  545. $actualPointsNum = min($maxPointsNumCount, $this->user['points']);
  546. if ($actualPointsNum < 1) {
  547. return false;
  548. }
  549. // 计算订单商品实际抵扣的积分数量和金额
  550. $GoodsDeduct = new PointsDeductService($this->goodsList);
  551. $GoodsDeduct->setGoodsPoints($maxPointsNumCount, $actualPointsNum);
  552. // 积分抵扣总金额
  553. $orderPointsMoney = helper::getArrayColumnSum($this->goodsList, 'points_money');
  554. $this->orderData['pointsMoney'] = helper::number2($orderPointsMoney);
  555. // 积分抵扣总数量
  556. $this->orderData['pointsNum'] = $actualPointsNum;
  557. // 允许积分抵扣
  558. $this->orderData['isAllowPoints'] = true;
  559. return true;
  560. }
  561. /**
  562. * 计算订单商品最多可抵扣的积分数量
  563. * @return bool
  564. * @throws \think\db\exception\DataNotFoundException
  565. * @throws \think\db\exception\DbException
  566. * @throws \think\db\exception\ModelNotFoundException
  567. */
  568. private function setOrderGoodsMaxPointsNum()
  569. {
  570. // 积分设置
  571. $setting = SettingModel::getItem('points');
  572. foreach ($this->goodsList as &$goods) {
  573. // 商品不允许积分抵扣
  574. if (!$goods['is_points_discount']) continue;
  575. // 积分抵扣比例
  576. $deductionRatio = helper::bcdiv($setting['discount']['max_money_ratio'], 100);
  577. // 最多可抵扣的金额
  578. $totalPayPrice = helper::bcsub($goods['total_price'], $goods['coupon_money']);
  579. $maxPointsMoney = helper::bcmul($totalPayPrice, $deductionRatio);
  580. // 最多可抵扣的积分数量
  581. $goods['max_points_num'] = helper::bcdiv($maxPointsMoney, $setting['discount']['discount_ratio'], 0);
  582. }
  583. return true;
  584. }
  585. /**
  586. * 设置默认的商品积分抵扣信息
  587. * @return bool
  588. */
  589. private function setDefaultGoodsPoints()
  590. {
  591. foreach ($this->goodsList as &$goods) {
  592. // 最多可抵扣的积分数量
  593. $goods['max_points_num'] = 0;
  594. // 实际抵扣的积分数量
  595. $goods['pointsNum'] = 0;
  596. // 实际抵扣的金额
  597. $goods['points_money'] = 0.00;
  598. }
  599. return true;
  600. }
  601. /**
  602. * 整理订单数据(结算台初始化)
  603. * @return array
  604. * @throws \think\db\exception\DataNotFoundException
  605. * @throws \think\db\exception\DbException
  606. * @throws \think\db\exception\ModelNotFoundException
  607. */
  608. private function getOrderData()
  609. {
  610. // 系统支持的配送方式 (后台设置)
  611. $deliveryType = SettingModel::getItem(SettingEnum::DELIVERY)['delivery_type'];
  612. return [
  613. // 当前配送类型
  614. 'delivery' => $this->param['delivery'] > 0 ? $this->param['delivery'] : $deliveryType[0],
  615. // 默认地址
  616. 'address' => '',
  617. // 是否存在收货地址
  618. 'existAddress' => $this->user['address_id'] > 0,
  619. // 配送费用
  620. 'expressPrice' => 0.00,
  621. //是否使用了金米粒
  622. 'isUseGoldRice' => $this->param['isUseGoldRice'],
  623. //金米粒数量
  624. 'userGoldRiceNum' => $this->user['gold_rice']??0,
  625. // 当前用户收货城市是否存在配送规则中
  626. 'isIntraRegion' => true,
  627. // 是否允许使用积分抵扣
  628. 'isAllowPoints' => false,
  629. // 是否使用积分抵扣
  630. 'isUsePoints' => $this->param['isUsePoints'],
  631. // 积分抵扣金额
  632. 'pointsMoney' => 0.00,
  633. // 赠送的积分数量
  634. 'pointsBonus' => 0,
  635. // 支付方式
  636. 'payType' => $this->param['payType'],
  637. // 系统设置
  638. 'setting' => $this->getSetting(),
  639. // 推广监控ID
  640. "promotionMonitorId" => $this->param['promotionMonitorId'] ?? 0
  641. ];
  642. }
  643. /**
  644. * 获取订单页面中使用到的系统设置
  645. * @return array
  646. * @throws \think\db\exception\DataNotFoundException
  647. * @throws \think\db\exception\DbException
  648. * @throws \think\db\exception\ModelNotFoundException
  649. */
  650. private function getSetting()
  651. {
  652. // 系统支持的配送方式 (后台设置)
  653. $deliveryType = SettingModel::getItem(SettingEnum::DELIVERY)['delivery_type'];
  654. // 积分设置
  655. $pointsSetting = SettingModel::getItem(SettingEnum::POINTS);
  656. return [
  657. 'deliveryType' => $deliveryType, // 支持的配送方式
  658. 'points_name' => $pointsSetting['points_name'], // 积分名称
  659. 'points_describe' => $pointsSetting['describe'], // 积分说明
  660. ];
  661. }
  662. /**
  663. * 当前用户可用的优惠券列表
  664. * @param $goodsList 确认订单商品列表
  665. * @return array|mixed
  666. * @throws \think\db\exception\DbException
  667. */
  668. private function getUserCouponList()
  669. {
  670. // 是否开启优惠券折扣
  671. if (!$this->checkoutRule['isCoupon']) {
  672. return [];
  673. }
  674. // 整理当前订单所有商品ID集
  675. $orderGoodsIds = helper::getArrayColumn($this->goodsList, 'goods_id');
  676. // 当前用户可用的优惠券列表(筛选了除外商品)
  677. // if($orderTotalPrice<=0){
  678. // $couponList = [];
  679. // }else{
  680. $couponList = UserCouponModel::getUserCouponList($this->user['user_id'], $this->goodsList, $orderGoodsIds);
  681. // }
  682. // // 判断当前优惠券是否满足订单使用条件 (优惠券适用范围)
  683. // $couponList = UserCouponModel::couponListApplyRange($couponList, $orderGoodsIds);
  684. if($this->param['couponId']==0){//-1不使用优惠券
  685. $this->param['couponId'] = key($couponList)??0;//若果没有选择优惠券,默认使用第一张优惠券
  686. }
  687. return $couponList;
  688. }
  689. /**
  690. * 验证订单商品的状态
  691. * @return bool
  692. */
  693. private function validateGoodsList()
  694. {
  695. $Checkout = CheckoutFactory::getFactory(
  696. $this->user,
  697. $this->goodsList,
  698. $this->orderData['delivery'],
  699. $this->shopInfo['shop_id'] ?? 0,
  700. $this->orderSource['source']
  701. );
  702. $status = $Checkout->validateGoodsList();
  703. if(!$status){
  704. $this->setError($Checkout->getError());
  705. $this->setErrorStatus(422);
  706. }
  707. return $status;
  708. }
  709. /**
  710. * 设置订单的商品总金额(不含优惠折扣)
  711. */
  712. private function setOrderTotalPrice()
  713. {
  714. // 订单商品的总金额(不含优惠券折扣,不含N件X折优惠券)
  715. $this->orderData['orderTotalPrice'] = helper::number2(helper::getArrayColumnSum($this->goodsList, 'total_price'));
  716. }
  717. /**
  718. * 订单商品的所有店铺集合
  719. */
  720. private function setOrderProviderIds()
  721. {
  722. // 订单商品的所有店铺集合
  723. $this->orderData['orderProviderIds'] = implode(',',array_values(array_unique(helper::getArrayColumn($this->goodsList, 'provider_id'))));
  724. }
  725. /**
  726. * 设置订单的实际支付金额(含配送费)
  727. */
  728. private function setOrderPayPrice()
  729. {
  730. // 订单金额(含优惠折扣)
  731. //(商品总价 - N件X折 - 优惠券 - 分销员)+ 运费 = 微信支付+米卡抵扣+米卡抵扣运费
  732. //(total_price-coupon_money-distrbutor_total_money)+express_price = pay_price+rice_card_money+rice_card_express_money
  733. $this->orderData['orderPrice'] = helper::number2(helper::getArrayColumnSum($this->goodsList, 'total_pay_price'));
  734. // 订单实付款金额(订单金额 + 运费 - 现金卡运费抵扣金额)
  735. $this->orderData['orderPayPrice'] = helper::number2(helper::bcadd($this->orderData['orderPrice'], $this->orderData['expressPrice']-$this->orderData['riceCardExpressMoney']));
  736. }
  737. /**
  738. * 计算订单积分赠送数量
  739. * @return bool
  740. * @throws \think\db\exception\DataNotFoundException
  741. * @throws \think\db\exception\DbException
  742. * @throws \think\db\exception\ModelNotFoundException
  743. */
  744. private function setOrderPointsBonus()
  745. {
  746. // 初始化商品积分赠送数量
  747. foreach ($this->goodsList as &$goods) {
  748. $goods['points_bonus'] = 0;
  749. }
  750. // 积分设置
  751. $setting = SettingModel::getItem('points');
  752. // 条件:后台开启开启购物送积分
  753. if (!$setting['is_shopping_gift']) {
  754. return false;
  755. }
  756. // 设置商品积分赠送数量
  757. foreach ($this->goodsList as &$goods) {
  758. // 积分赠送比例
  759. $ratio = $setting['gift_ratio'] / 100;
  760. // 计算抵扣积分数量
  761. $goods['points_bonus'] = !$goods['is_points_gift'] ? 0 : helper::bcmul($goods['total_pay_price'], $ratio, 0);
  762. }
  763. // 订单积分赠送数量
  764. $this->orderData['pointsBonus'] = helper::getArrayColumnSum($this->goodsList, 'points_bonus');
  765. return true;
  766. }
  767. /**
  768. * 设置金稻会员折扣价
  769. * @return bool
  770. */
  771. private function setOrderGoodsMemberMoney()
  772. {
  773. // 设置默认数据
  774. helper::setDataAttribute($this->goodsList, [
  775. // 标记金稻会员是否参与购物折扣
  776. 'is_user_member' => false,
  777. // 金稻会员购物抵扣的比例
  778. 'member_radio' => 0,
  779. // 金稻会员购物减去的折扣优惠总额差
  780. 'member_total_money' => 0.00,
  781. ], true);
  782. // 设置默认数据:订单信息
  783. helper::setDataAttribute($this->orderData, [
  784. 'memberTotalMoney' => 0, // 抵扣金额
  785. 'isUserMember' => false, // 是否有商品使用了会员折扣
  786. ], false);
  787. //如果不是会员,或者会员已过期
  788. if($this->user['member_expire_time']<time()){
  789. return false;
  790. }
  791. $member_total_money = 0;
  792. // 计算抵扣金额
  793. foreach ($this->goodsList as &$goods) {
  794. //判断当前商品是否能使用会员折扣
  795. $memberGoods = MemberGoods::where('goods_id',$goods['goods_id'])->where('status',0)->find();
  796. if ($memberGoods && $memberGoods['discount']<100) {
  797. $memberRatio = helper::bcdiv(100-$memberGoods['discount'], 100);//换算成百分比
  798. helper::setDataAttribute($goods, [
  799. 'is_user_member' => true,
  800. 'member_radio' => $memberRatio,
  801. 'member_total_money' => helper::number2(helper::bcmul(($goods['total_price']-$goods['activity_discount_total_price']), $memberRatio)),
  802. // 'total_price' => $gradeTotalPrice,
  803. ], false);
  804. $this->orderData['isUserMember'] = true;
  805. }
  806. $member_total_money += $goods['member_total_money'];
  807. }
  808. $this->orderData['memberTotalMoney'] = helper::number2($member_total_money);//设置订单优惠合计
  809. return true;
  810. }
  811. /**
  812. * 计算订单商品的实际付款金额
  813. * @return bool
  814. */
  815. private function setOrderGoodsPayPrice()
  816. {
  817. // 商品总价 - 优惠抵扣
  818. foreach ($this->goodsList as &$goods) {
  819. //减去金稻会员抵扣的金额
  820. $value = helper::bcsub($goods['total_price'], $goods['member_total_money']);
  821. // 减去N件X折抵扣金额
  822. $value = helper::bcsub($value, $goods['activity_discount_total_price']);
  823. //减去分销员购物的优惠金额
  824. $value = helper::bcsub($value, $goods['distributor_total_money']);
  825. // 减去优惠券抵扣金额
  826. $value = helper::bcsub($value, $goods['coupon_money']);
  827. // 减去积分抵扣金额
  828. if ($this->orderData['isAllowPoints'] && $this->orderData['isUsePoints']) {
  829. $value = helper::bcsub($value, $goods['points_money']);
  830. }
  831. //减去金米粒抵扣的金额
  832. $value = helper::bcsub($value, $goods['gold_rice_money']);
  833. $goods['totalPayPrice'] = helper::number2($value);
  834. //减去现金米卡抵扣的金额
  835. $value = helper::bcsub($value, $goods['rice_card_money']);
  836. $goods['total_pay_price'] = helper::number2($value);
  837. }
  838. return true;
  839. }
  840. /**
  841. * 设置订单商品会员折扣价
  842. * @return bool
  843. */
  844. private function setOrderGoodsGradeMoney()
  845. {
  846. // 设置默认数据
  847. helper::setDataAttribute($this->goodsList, [
  848. // 标记参与会员折扣
  849. 'is_user_grade' => false,
  850. // 会员等级抵扣的金额
  851. 'grade_ratio' => 0,
  852. // 会员折扣的商品单价
  853. 'grade_goods_price' => 0.00,
  854. // 会员折扣的总额差
  855. 'grade_total_money' => 0.00,
  856. ], true);
  857. // 是否开启会员等级折扣
  858. if (!$this->checkoutRule['isUserGrade']) {
  859. return false;
  860. }
  861. // 会员等级状态
  862. if (!(
  863. $this->user['grade_id'] > 0 && !empty($this->user['grade'])
  864. && !$this->user['grade']['is_delete'] && $this->user['grade']['status']
  865. )) {
  866. return false;
  867. }
  868. // 计算抵扣金额
  869. foreach ($this->goodsList as &$goods) {
  870. // 判断商品是否参与会员折扣
  871. if (!$goods['is_enable_grade']) {
  872. continue;
  873. }
  874. // 商品单独设置了会员折扣
  875. if ($goods['is_alone_grade'] && isset($goods['alone_grade_equity'][$this->user['grade_id']])) {
  876. // 折扣比例
  877. $discountRatio = helper::bcdiv($goods['alone_grade_equity'][$this->user['grade_id']], 10);
  878. } else {
  879. // 折扣比例
  880. $discountRatio = helper::bcdiv($this->user['grade']['equity']['discount'], 10);
  881. }
  882. if ($discountRatio > 0) {
  883. // 会员折扣后的商品总金额
  884. $gradeTotalPrice = max(0.01, helper::bcmul($goods['total_price'], $discountRatio));
  885. helper::setDataAttribute($goods, [
  886. 'is_user_grade' => true,
  887. 'grade_ratio' => $discountRatio,
  888. 'grade_goods_price' => helper::number2(helper::bcmul($goods['goods_price'], $discountRatio), true),
  889. 'grade_total_money' => helper::number2(helper::bcsub($goods['total_price'], $gradeTotalPrice)),
  890. 'total_price' => $gradeTotalPrice,
  891. ], false);
  892. }
  893. }
  894. return true;
  895. }
  896. /**
  897. * 设置分销员购物折扣价
  898. * @return bool
  899. */
  900. private function setOrderGoodsDistributorMoney()
  901. {
  902. // 设置默认数据
  903. helper::setDataAttribute($this->goodsList, [
  904. // 标记参与顾客购物折扣
  905. 'is_user_distributor' => false,
  906. // 顾客购物抵扣的比例
  907. 'distributor_radio' => 0,
  908. // 顾客购物减去的折扣优惠价格
  909. 'distributor_goods_price' => 0.00,
  910. // 顾客购物减去的折扣优惠总额差
  911. 'distributor_total_money' => 0.00,
  912. ], true);
  913. // 设置默认数据:订单信息
  914. helper::setDataAttribute($this->orderData, [
  915. 'distributorTotalMoney' => 0, // 优惠券抵扣金额
  916. 'isUserDistributor' => false, // 是否有商品使用了推荐官专属折扣
  917. ], false);
  918. //使用了优惠券并且优惠券没有勾选使用分销员优惠
  919. if($this->orderData['couponId']>0 && stripos($this->orderData['couponOverlayDiscount'],'1') === false){
  920. return true;
  921. }
  922. $distributor_total_money = 0;
  923. // 计算抵扣金额
  924. foreach ($this->goodsList as &$goods) {
  925. $discountRatio = helper::bcdiv($goods['distributorRadio'], 100);//换算成百分比
  926. if ($discountRatio > 0) {
  927. // 顾客购物折扣的优惠价格
  928. // $gradeTotalPrice = max(0.01, helper::bcmul($goods['total_price'], (1-$discountRatio)));
  929. helper::setDataAttribute($goods, [
  930. 'is_user_distributor' => true,
  931. 'distributor_radio' => $discountRatio,
  932. 'distributor_goods_price' => $goods['total_num']>0 ? helper::number2(helper::bcmul($goods['goods_price']-($goods['coupon_money']+$goods['activity_discount_total_price']+$goods['member_total_money'])/$goods['total_num'], $discountRatio), true):0,
  933. 'distributor_total_money' => helper::number2(helper::bcmul(($goods['total_price']-$goods['coupon_money']-$goods['activity_discount_total_price']-$goods['member_total_money']), $discountRatio)),
  934. // 'total_price' => $gradeTotalPrice,
  935. ], false);
  936. $this->orderData['isUserDistributor'] = true;
  937. }
  938. $distributor_total_money += $goods['distributor_total_money'];
  939. }
  940. $this->orderData['distributorTotalMoney'] = helper::number2($distributor_total_money);//设置订单优惠合计
  941. return true;
  942. }
  943. /**
  944. * 设置订单优惠券抵扣信息
  945. * @param array $couponList 当前用户可用的优惠券列表
  946. * @param int $couponId 当前选择的优惠券id
  947. * @return bool
  948. * @throws BaseException
  949. */
  950. private function setOrderCouponMoney(array $couponList, int $couponId)
  951. {
  952. // 设置默认数据:订单信息
  953. helper::setDataAttribute($this->orderData, [
  954. 'couponId' => $couponId, // 用户优惠券id
  955. 'couponMoney' => 0, // 优惠券抵扣金额
  956. 'couponName' => '', // 优惠券抵扣名称
  957. 'couponOverlayDiscount' => '', // 叠加字段
  958. 'couponList' => [],
  959. ], false);
  960. // 设置默认数据:订单商品列表
  961. helper::setDataAttribute($this->goodsList, [
  962. 'coupon_money' => 0, // 优惠券抵扣金额
  963. 'coupon_id' => 0, // 优惠券ID
  964. ], true);
  965. if($couponId<0){//如果米卡ID小于0表示不使用,但是也要返回可使用列表
  966. $this->orderData['couponList'] = array_values($couponList);
  967. return true;
  968. }
  969. // 验证选择的优惠券ID是否合法
  970. if (!$this->verifyOrderCouponId($couponId, $couponList)) {
  971. return false;
  972. }
  973. // 获取优惠券信息
  974. $couponInfo = $this->getCouponInfo($couponId, $couponList);
  975. // 整理当前订单所有商品ID集
  976. // $orderGoodsIds = helper::getArrayColumn($this->goodsList, 'goods_id');
  977. // 获取当前参与商品分佣的ID集
  978. // $diffGoodsIds = array_diff($orderGoodsIds,$couponInfo['except_goods_id']);
  979. $diffGoodsIds = $couponInfo['new_good_ids'];//在获取可用优惠券列表时就已经计算出哪些商品可以使用优惠券了
  980. $goodsListTemp = [];
  981. foreach ($this->goodsList as $key=> $good){
  982. $goodsListTemp[$key]['total_price'] = helper::bcsub($good['total_price'],$good['activity_discount_total_price']+$good['member_total_money']);
  983. if(!in_array($good['goods_id'],$diffGoodsIds)){
  984. $goodsListTemp[$key]['total_price'] = 0;
  985. }
  986. }
  987. $CouponMoney = new GoodsDeductService;
  988. $completed = $CouponMoney->setGoodsCouponMoney($goodsListTemp, $couponInfo['reduced_price']);
  989. // 分配订单商品优惠券抵扣金额
  990. foreach ($this->goodsList as $key => &$goods) {
  991. $goods['coupon_money'] = isset($completed[$key]['coupon_money']) ? $completed[$key]['coupon_money'] / 100 : 0;
  992. $goods['coupon_id'] = $couponId;
  993. if(!in_array($goods['goods_id'],$diffGoodsIds)){
  994. $goods['coupon_id'] = 0;
  995. }
  996. }
  997. // 记录订单优惠券信息
  998. $this->orderData['couponId'] = $couponId;
  999. $this->orderData['couponOverlayDiscount'] = $couponInfo['overlay_discount'];
  1000. $this->orderData['couponMoney'] = helper::number2($CouponMoney->getActualReducedMoney() / 100);
  1001. $this->orderData['couponName'] = $couponInfo['name'];
  1002. $this->orderData['couponList'] = array_values($couponList);
  1003. return true;
  1004. }
  1005. /**
  1006. * 设置订单使用金米粒抵扣信息
  1007. * @return bool
  1008. * @throws BaseException
  1009. */
  1010. private function setOrderGolRiceAmount()
  1011. {
  1012. // 设置默认数据:订单信息
  1013. helper::setDataAttribute($this->orderData, [
  1014. 'goldRiceAmount' => 0, // 金米粒抵扣总数量 1金米粒=0.01元
  1015. 'goldRiceMoney' => 0.00, // 金米粒抵扣总金额
  1016. ], false);
  1017. // 设置默认数据:订单商品列表
  1018. helper::setDataAttribute($this->goodsList, [
  1019. 'gold_rice_amount' => 0, // 金米粒抵扣数量
  1020. 'gold_rice_money' => 0, // 金米粒抵扣金额
  1021. ], true);
  1022. if($this->orderData['isUseGoldRice']<1){//没有使用金米粒
  1023. return false;
  1024. }
  1025. $orderTotalPrice = $this->orderData['orderTotalPrice']-$this->orderData['distributorTotalMoney']-$this->orderData['couponMoney']-$this->orderData['activityDiscountTotalPrice']-$this->orderData['memberTotalMoney']; //实际支付金额-N件X折活动优惠-分销员优惠-优惠券优惠-金稻会员优惠
  1026. // 如果没有可用的现金米卡,直接返回
  1027. $DeductionLimit = DeductionLimitModel::where('id','>',0)->find();
  1028. $score = helper::bcmul($orderTotalPrice,$DeductionLimit['discount'],0);
  1029. //不够起用数量
  1030. if($score<$DeductionLimit['score']){
  1031. $this->orderData['isUseGoldRice'] = -1;
  1032. return false;
  1033. }
  1034. //用户可用金米粒数量不够起用数量
  1035. if($this->user['gold_rice']<$DeductionLimit['score']){
  1036. $this->orderData['isUseGoldRice'] = -1;
  1037. return false;
  1038. }
  1039. if($score>$this->user['gold_rice']){
  1040. $score = $this->user['gold_rice'];
  1041. }
  1042. // 获取优惠券信息
  1043. $goodsListTemp = [];
  1044. foreach ($this->goodsList as $key=> $good){
  1045. $goodsListTemp[$key]['total_price'] = helper::bcsub($good['total_price'],$good['distributor_total_money']+$good['coupon_money']+$good['activity_discount_total_price']+$good['member_total_money']);
  1046. }
  1047. $RiceMoney = new RiceDeductService;
  1048. $gold_rice_money = helper::bcdiv($score,100);
  1049. $completed = $RiceMoney->setGoodsCouponMoney($goodsListTemp, $gold_rice_money);
  1050. // 分配订单商品抵扣的金米粒数量
  1051. foreach ($this->goodsList as $key => &$goods) {
  1052. $goods['gold_rice_amount'] = isset($completed[$key]['rice_card_money']) ? $completed[$key]['rice_card_money'] : 0;
  1053. $goods['gold_rice_money'] = helper::bcdiv($goods['gold_rice_amount'],100);
  1054. }
  1055. // 记录订单抵扣的金米粒数量
  1056. $this->orderData['goldRiceAmount'] = $score;
  1057. $this->orderData['goldRiceMoney'] = $gold_rice_money;
  1058. return true;
  1059. }
  1060. /**
  1061. * 设置订单使用金米粒获取信息
  1062. * @return bool
  1063. * @throws BaseException
  1064. */
  1065. private function setOrderInputGolRiceAmount()
  1066. {
  1067. // 设置默认数据:订单信息
  1068. helper::setDataAttribute($this->orderData, [
  1069. 'goldRiceAmountInput' => 0, // 金米粒获取总数量 累加商品金额
  1070. ], false);
  1071. // 设置默认数据:订单商品列表
  1072. helper::setDataAttribute($this->goodsList, [
  1073. 'gold_rice_amount_input' => 0, // 金米粒获取数量,1元可以获取1金米粒,只舍不入
  1074. ], true);
  1075. //如果不是会员,或者会员已过期
  1076. if($this->user['member_expire_time']<time()){
  1077. return false;
  1078. }
  1079. $score = 0;
  1080. // 分配订单商品获取的金米粒数量
  1081. foreach ($this->goodsList as $key => &$goods) {
  1082. //获取商品需要实付的金额
  1083. $good_total_price = helper::bcsub($goods['total_price'],$goods['distributor_total_money']+$goods['coupon_money']+$goods['activity_discount_total_price']+$goods['member_total_money']+$goods['gold_rice_money']);
  1084. $goods['gold_rice_amount_input'] = floor($good_total_price);//金米粒获取数量,1元可以获取1金米粒,只舍不入
  1085. $score += $goods['gold_rice_amount_input'];
  1086. }
  1087. // 记录订单获得的金米粒数量
  1088. $this->orderData['goldRiceAmountInput'] = $score;
  1089. return true;
  1090. }
  1091. /**
  1092. * 设置订单现金米卡抵扣信息
  1093. * @param int $riceCardId 可使用米卡列表
  1094. * @param int $riceCardId 当前选择的现金米卡id
  1095. * @return bool
  1096. * @throws BaseException
  1097. */
  1098. private function setOrderRiceCardMoney($userRiceCardList,int $riceCardId)
  1099. {
  1100. // 设置默认数据:订单信息
  1101. helper::setDataAttribute($this->orderData, [
  1102. 'riceCardId' => $riceCardId, // 用户现金米卡id
  1103. 'riceCardMoney' => 0, // 现金米卡抵扣总金额
  1104. 'riceCardExpressMoney' => 0, // 现金米卡抵扣运费
  1105. 'userRiceCardList' => [], // 米卡列表
  1106. 'userRiceCard' => [], // 已选择的米卡
  1107. ], false);
  1108. // 设置默认数据:订单商品列表
  1109. helper::setDataAttribute($this->goodsList, [
  1110. 'rice_card_id' => 0, // 用户现金米卡id
  1111. 'rice_card_money' => 0, // 金米卡抵扣金额
  1112. ], true);
  1113. if($riceCardId<0){//如果米卡ID小于0表示不使用,但是也要返回可使用列表
  1114. $this->orderData['userRiceCardList'] = array_values($userRiceCardList);
  1115. return true;
  1116. }
  1117. // 验证选择的优惠券ID是否合法
  1118. if (!$this->verifyUserRiceCard($riceCardId, $userRiceCardList)) {
  1119. return false;
  1120. }
  1121. // 获取优惠券信息
  1122. $riceCard = $this->getRiceCardInfo($riceCardId, $userRiceCardList);
  1123. $goodsListTemp = [];
  1124. foreach ($this->goodsList as $key=> $good){
  1125. $goodsListTemp[$key]['total_price'] = helper::bcsub($good['total_price'],$good['distributor_total_money']+$good['coupon_money']+$good['activity_discount_total_price']+$good['gold_rice_money']+$good['member_total_money']);
  1126. }
  1127. $RiceMoney = new RiceDeductService;
  1128. $completed = $RiceMoney->setGoodsCouponMoney($goodsListTemp, $riceCard['balance']);
  1129. // 分配订单商品优惠券抵扣金额
  1130. $rice_card_money = 0;
  1131. foreach ($this->goodsList as $key => &$goods) {
  1132. $goods['rice_card_money'] = isset($completed[$key]['rice_card_money']) ? $completed[$key]['rice_card_money'] / 100 : 0;
  1133. $goods['rice_card_id'] = $riceCardId;
  1134. $rice_card_money += $goods['rice_card_money'];
  1135. }
  1136. $orderTotalPrice = $this->orderData['orderTotalPrice']-$this->orderData['distributorTotalMoney']-$this->orderData['couponMoney']-$this->orderData['activityDiscountTotalPrice']-$this->orderData['goldRiceMoney']-$this->orderData['memberTotalMoney']; //实际支付金额-N件X折活动优惠-分销员优惠-优惠券优惠-金米粒抵扣金额
  1137. //有运费,并且现金米卡可用的金额大于商品总价
  1138. $rice_card_express_money = 0;
  1139. if($riceCard['balance']>$orderTotalPrice && $this->orderData['expressPrice']>0){
  1140. $residueMoney = $riceCard['balance']-$orderTotalPrice;
  1141. if($residueMoney-$this->orderData['expressPrice']>0){
  1142. $rice_card_express_money += $this->orderData['expressPrice'];
  1143. }else{
  1144. $rice_card_express_money += $residueMoney;
  1145. }
  1146. }
  1147. // 记录订单现金米卡信息
  1148. $this->orderData['userRiceCard'] = $userRiceCardList[$riceCardId];
  1149. $this->orderData['riceCardId'] = $riceCardId;
  1150. $this->orderData['riceCardMoney'] = helper::bcmul($rice_card_money+$rice_card_express_money,1);
  1151. $this->orderData['riceCardExpressMoney'] = helper::bcmul($rice_card_express_money,1);
  1152. $this->orderData['userRiceCardList'] = array_values($userRiceCardList);
  1153. return true;
  1154. }
  1155. /**
  1156. * 验证用户选择的现金米卡
  1157. * @param $riceCard
  1158. * @return bool
  1159. * @throws BaseException
  1160. */
  1161. private function verifyUserRiceCard($riceCardId,$userRiceCardList)
  1162. {
  1163. // 是否开启现金米卡抵扣
  1164. if (!$this->checkoutRule['isRiceCard']) {
  1165. return false;
  1166. }
  1167. // 如果没有可用的现金米卡,直接返回
  1168. if ($riceCardId <= 0) {
  1169. return false;
  1170. }
  1171. // 判断优惠券是否存在
  1172. $riceCard = $this->getRiceCardInfo($riceCardId, $userRiceCardList);
  1173. // 如果没有现金米卡,直接返回
  1174. if (empty($riceCard)) {
  1175. throwError('未找到米卡信息');
  1176. }
  1177. // $UserRiceCardService = new UserRiceCardService($this->goodsList);
  1178. // $isExceptGoods = $UserRiceCardService->isIncludeGoods($riceCard);
  1179. // if ($isExceptGoods == false) {
  1180. // $notExceptGoodsName = $UserRiceCardService->getExceptGoodsName();
  1181. // $this->setError("很抱歉,商品 [".limit_str((string)$notExceptGoodsName)."] 不可使用该米卡");
  1182. // $this->setErrorStatus(422);
  1183. // }else{
  1184. // $isExceptGoods = $UserRiceCardService->isExceptGoods($riceCard);
  1185. // if ($isExceptGoods == false) {
  1186. // $notExceptGoodsName = $UserRiceCardService->getExceptGoodsName();
  1187. // $this->setError("很抱歉,商品 [".limit_str((string)$notExceptGoodsName)."] 不可使用该米卡");
  1188. // $this->setErrorStatus(422);
  1189. // }
  1190. // }
  1191. return true;
  1192. }
  1193. /**
  1194. * 验证用户选择的优惠券ID是否合法
  1195. * @param $couponId
  1196. * @param $couponList
  1197. * @return bool
  1198. * @throws BaseException
  1199. */
  1200. private function verifyOrderCouponId($couponId, $couponList)
  1201. {
  1202. // 是否开启优惠券折扣
  1203. if (!$this->checkoutRule['isCoupon']) {
  1204. return false;
  1205. }
  1206. // 如果没有可用的优惠券,直接返回
  1207. if ($couponId <= 0 || empty($couponList)) {
  1208. return false;
  1209. }
  1210. // 判断优惠券是否存在
  1211. $couponInfo = $this->getCouponInfo($couponId, $couponList);
  1212. if (!$couponInfo) {
  1213. // throwError('未找到优惠券信息');
  1214. $this->param['couponId'] = key($couponList)??0;//若果没有选择优惠券,默认使用第一张优惠券
  1215. $this->orderData['couponList'] = array_values($couponList);
  1216. return false;
  1217. }
  1218. // 判断优惠券适用范围是否合法
  1219. // if (!$couponInfo['is_apply']) {
  1220. // throwError($couponInfo['not_apply_info']);
  1221. // }
  1222. return true;
  1223. }
  1224. /**
  1225. * 查找指定的优惠券信息
  1226. * @param int $couponId 优惠券ID
  1227. * @param array $couponList 优惠券列表
  1228. * @return false|mixed
  1229. */
  1230. private function getCouponInfo(int $couponId, array $couponList)
  1231. {
  1232. return helper::getArrayItemByColumn($couponList, 'user_coupon_id', $couponId);
  1233. }
  1234. /**
  1235. * 查找指定的优惠券信息
  1236. * @param int $couponId 优惠券ID
  1237. * @param array $couponList 优惠券列表
  1238. * @return false|mixed
  1239. */
  1240. private function getRiceCardInfo(int $riceCardId, array $userRiceCardList)
  1241. {
  1242. return helper::getArrayItemByColumn($userRiceCardList, 'id', $riceCardId);
  1243. }
  1244. /**
  1245. * 订单配送-快递配送
  1246. * @return bool
  1247. * @throws \think\db\exception\DataNotFoundException
  1248. * @throws \think\db\exception\DbException
  1249. * @throws \think\db\exception\ModelNotFoundException
  1250. */
  1251. private function setOrderExpress()
  1252. {
  1253. // 设置默认数据:配送费用
  1254. helper::setDataAttribute($this->goodsList, [
  1255. 'expressPrice' => 0,
  1256. ], true);
  1257. // 当前用户收货城市id
  1258. if($this->param['addressId']){ //有传参
  1259. $addredd = UserAddress::get(['user_id' => $this->user['user_id'], 'address_id' => $this->param['addressId']]);
  1260. $cityId = $addredd ? (int)$addredd['city_id'] : 0;
  1261. $this->orderData['address'] = $addredd;
  1262. }else{ //没有传参读默认地址
  1263. $cityId = $this->user['address_default'] ? (int)$this->user['address_default']['city_id'] : 0;
  1264. $this->orderData['address'] = $this->user['address_default'];
  1265. }
  1266. if ($this->param['delivery'] == DeliveryTypeEnum::EXPRESS) { // 普通快递
  1267. // 初始化配送服务类
  1268. $ExpressService = new ExpressService($cityId, $this->goodsList);
  1269. // 验证商品是否在限购配送范围
  1270. $isDeliveryLimit = $ExpressService->isDeliveryLimit();
  1271. if($cityId > 0){
  1272. if ($isDeliveryLimit == false) {
  1273. $this->setError("很抱歉,您的收货地址在限购地区的配送范围内");
  1274. $this->setErrorStatus(423);
  1275. $this->orderData['isIntraRegion'] = $isDeliveryLimit;
  1276. }else{
  1277. // 验证商品是否在配送范围
  1278. $isIntraRegion = $ExpressService->isIntraRegion();
  1279. if ($isIntraRegion == false) {
  1280. $notInRuleGoodsName = $ExpressService->getNotInRuleGoodsName();
  1281. $this->setError("很抱歉,您的收货地址不在商品 [".limit_str((string)$notInRuleGoodsName)."] 的配送范围内");
  1282. $this->setErrorStatus(423);
  1283. }
  1284. $this->orderData['isIntraRegion'] = $isIntraRegion;
  1285. }
  1286. }
  1287. // 订单总运费金额
  1288. $this->orderData['expressPrice'] = $ExpressService->getDeliveryFee();
  1289. } else { // 门店自提
  1290. $this->orderData['expressPrice'] = "0.00";
  1291. }
  1292. return true;
  1293. }
  1294. /**
  1295. * 创建新订单
  1296. * @param array $order 订单信息
  1297. * @return bool
  1298. */
  1299. public function createOrder(array $order)
  1300. {
  1301. // 表单验证
  1302. if (!$this->validateOrderForm($order)) {
  1303. return false;
  1304. }
  1305. // 创建新的订单
  1306. $status = $this->model->transaction(function () use ($order) {
  1307. // 创建订单事件
  1308. return $this->createOrderEvent($order);
  1309. });
  1310. if ($status && $order['payType'] == OrderPayTypeEnum::EXCHANGE) {
  1311. return $this->model->onPaymentByAccumulatePoints($this->model['order_no']);
  1312. }
  1313. return $status;
  1314. }
  1315. /**
  1316. * 创建订单事件
  1317. * @param $order
  1318. * @return bool
  1319. * @throws BaseException
  1320. * @throws \Exception
  1321. */
  1322. private function createOrderEvent($order)
  1323. {
  1324. // 门店自提
  1325. if ($order['delivery'] == DeliveryTypeEnum::SHOPS_DELIVERY) {
  1326. $order['hx_code'] = $this->model->hxCode();
  1327. $order['pickup_deadline'] = time() + OrderModel::getPickupDeadline() * 60; // 提货截止时间:提交订单2天内
  1328. $order['shop_id'] = $order['shopInfo']['shop_id']; // 订单自提门店id
  1329. }
  1330. // 新增订单记录
  1331. $status = $this->add($order, $this->param['remark']);
  1332. if ($order['delivery'] == DeliveryTypeEnum::EXPRESS) {
  1333. // 记录收货地址
  1334. $this->saveOrderAddress($order['address']);
  1335. }
  1336. // 保存订单商品信息
  1337. $this->saveOrderGoods($order);
  1338. //保存满件送商品信息
  1339. $this->saveOrderGoodsMj($order);
  1340. // 保存订单套餐商品信息
  1341. $this->saveOrderGoodsTaocan($order);
  1342. // 更新商品库存 (针对下单减库存的商品)
  1343. $this->updateGoodsStockNum($order);
  1344. // 更新多个活动的活动库存
  1345. $this->updateActivityStock($order);
  1346. // 设置优惠券使用状态
  1347. $order['couponId'] > 0 && UserCouponModel::setIsUse((int)$order['couponId']);
  1348. //设置福利状态zq
  1349. if ($order['couponId'] > 0)UserCouponModel::setWelfareStatus((int)$order['couponId'],1);
  1350. // 获取订单详情
  1351. // $detail = OrderModel::getUserOrderDetail((int)$this->model['order_id']);
  1352. return $status;
  1353. }
  1354. /**
  1355. * 构建支付请求的参数
  1356. * @return array
  1357. * @throws BaseException
  1358. * @throws \think\db\exception\DataNotFoundException
  1359. * @throws \think\db\exception\DbException
  1360. * @throws \think\db\exception\ModelNotFoundException
  1361. */
  1362. public function onOrderPayment()
  1363. {
  1364. return PaymentService::orderPayment($this->model, $this->param['payType']);
  1365. }
  1366. /**
  1367. * 表单验证 (订单提交)
  1368. * @param array $order 订单信息
  1369. * @return bool
  1370. */
  1371. private function validateOrderForm(array $order)
  1372. {
  1373. if ($order['delivery'] == DeliveryTypeEnum::EXPRESS) {
  1374. if (empty($order['address'])) {
  1375. $this->error = '您还没有选择配送地址';
  1376. return false;
  1377. }
  1378. }
  1379. // 余额支付时判断用户余额是否足够
  1380. if ($order['payType'] == OrderPayTypeEnum::BALANCE) {
  1381. if ($this->user['balance'] < $order['orderPayPrice']) {
  1382. $this->error = '您的余额不足,无法使用余额支付';
  1383. return false;
  1384. }
  1385. }
  1386. return true;
  1387. }
  1388. /**
  1389. * 当前订单是否存在和使用积分抵扣
  1390. * @param $order
  1391. * @return bool
  1392. */
  1393. private function isExistPointsDeduction($order)
  1394. {
  1395. return $order['isAllowPoints'] && $order['isUsePoints'];
  1396. }
  1397. /**
  1398. * 新增订单记录
  1399. * @param $order
  1400. * @param string $remark
  1401. * @return false|int
  1402. */
  1403. private function add($order, $remark = '')
  1404. {
  1405. // 当前订单是否存在和使用积分抵扣
  1406. $isExistPointsDeduction = $this->isExistPointsDeduction($order);
  1407. // 订单数据
  1408. $data = [
  1409. 'user_id' => $this->user['user_id'],
  1410. 'order_no' => $this->model->orderNo(),
  1411. 'total_price' => $order['orderTotalPrice'],
  1412. 'order_price' => $order['orderPrice'],
  1413. 'coupon_id' => $order['couponId']>0?$order['couponId']:0,
  1414. 'coupon_money' => $order['couponMoney'],
  1415. 'points_money' => $isExistPointsDeduction ? $order['pointsMoney'] : 0.00,
  1416. 'points_num' => $isExistPointsDeduction ? $order['pointsNum'] : 0,
  1417. 'pay_price' => $order['orderPayPrice'],
  1418. 'delivery_type' => $order['delivery'],
  1419. 'pay_type' => $order['orderPayPrice'] > 0 ? $order['payType'] : OrderPayTypeEnum::MICAH_EXCHANGE,
  1420. 'buyer_remark' => trim($remark),
  1421. 'order_source' => $this->orderSource['source'],
  1422. 'order_source_id' => $this->orderSource['source_id'],
  1423. 'points_bonus' => $order['pointsBonus'],
  1424. 'order_status' => OrderStatusEnum::NORMAL,
  1425. 'store_id' => $this->storeId,
  1426. 'provider_ids' => $order['orderProviderIds']??0,
  1427. 'distributor_total_money' => $order['distributorTotalMoney']??0,
  1428. 'member_total_money' => $order['memberTotalMoney']??0,
  1429. 'gold_rice_amount' => $order['goldRiceAmount']??0,
  1430. 'gold_rice_money' => $order['goldRiceMoney']??0,
  1431. 'gold_rice_amount_input' => $order['goldRiceAmountInput']??0,
  1432. 'rice_card_id' => $order['riceCardId']>0?$order['riceCardId']:0,
  1433. 'rice_card_money' => $order['riceCardMoney']??0,
  1434. 'rice_card_express_money' => $order['riceCardExpressMoney']??0,
  1435. 'hx_code' => $order['hx_code'] ?? '',
  1436. 'pickup_deadline' => $order['pickup_deadline'] ?? 0,
  1437. 'shop_id' => $order['shop_id'] ?? 0,
  1438. 'invoice_deadline' => $order['invoice_deadline'] ?? 0,
  1439. 'is_full_send' => $order['is_full_send'] ?? 0,
  1440. 'full_send_activity_id' => $order['full_send_activity_id'] ?? 0,
  1441. 'is_qc_send_send' => $order['is_qc_send_send'] ?? 0,//是否参与全场满件送活动
  1442. 'qc_send_activity_id' => $order['qc_send_activity_id'] ?? 0,//全场满件送活动ID
  1443. 'activity_discount_total_price' => $order['activityDiscountTotalPrice'] ?? 0,
  1444. 'staff_user_id' => $order['goodsList'][0]['staffUserId'] ?? 0,
  1445. 'staff_shop_id' => $order['goodsList'][0]['shopId'] ?? 0,
  1446. 'promotion_monitor_id' => $order['promotionMonitorId'] ?? 0,
  1447. ];
  1448. //米卡兑换直接成功
  1449. if ($order['orderPayPrice']<=0 && $order['payType']==OrderPayTypeEnum::EXCHANGE){
  1450. $data['pay_status'] = PayStatusEnum::PENDING;
  1451. }else{
  1452. //米卡兑换直接成功
  1453. if($order['orderPayPrice']<=0 || $order['payType']==OrderPayTypeEnum::MICAH_EXCHANGE){
  1454. $data['pay_status'] = PayStatusEnum::SUCCESS;
  1455. $data['pay_time'] = time();
  1456. $data['invoice_deadline'] = time() + OrderModel::getInvoiceDeadline() * 60; // 申请开票截止时间:订单付款后的40天内可以申请开票
  1457. }
  1458. }
  1459. if ($order['delivery'] == DeliveryTypeEnum::EXPRESS) {
  1460. $data['express_price'] = $order['expressPrice'];
  1461. }
  1462. // 保存订单记录
  1463. return $this->model->save($data);
  1464. }
  1465. /**
  1466. * 保存订单商品信息
  1467. * @param $order
  1468. * @return int
  1469. */
  1470. private function saveOrderGoods($order)
  1471. {
  1472. // 当前订单是否存在和使用积分抵扣
  1473. $isExistPointsDeduction = $this->isExistPointsDeduction($order);
  1474. // 订单商品列表
  1475. $goodsList = [];
  1476. foreach ($order['goodsList'] as $key=> $goods) {
  1477. // dd($goods['total_pay_price']);
  1478. /* @var GoodsModel $goods */
  1479. $item = [
  1480. 'user_id' => $this->user['user_id'],
  1481. 'store_id' => $this->storeId,
  1482. 'goods_id' => $goods['goods_id'],
  1483. 'goods_name' => $goods['goods_name'],
  1484. 'goods_no' => $goods['goods_no'] ?: '',
  1485. 'image_id' => (int)current($goods['goods_images'])['file_id'],
  1486. 'deduct_stock_type' => $goods['deduct_stock_type'],
  1487. 'spec_type' => $goods['spec_type'],
  1488. 'goods_sku_id' => $goods['skuInfo']['goods_sku_id'],
  1489. 'goods_props' => $goods['skuInfo']['goods_props'] ?: '',
  1490. 'content' => $goods['content'] ?? '',
  1491. 'goods_sku_no' => $goods['skuInfo']['goods_sku_no'] ?: '',
  1492. 'goods_price' => $goods['skuInfo']['goods_price'],
  1493. 'specs' => $goods['skuInfo']['specs'],
  1494. 'supplier' => $goods['supplier'],
  1495. 'line_price' => $goods['skuInfo']['line_price'],
  1496. 'goods_weight' => $goods['skuInfo']['goods_weight'],
  1497. 'is_user_grade' => (int)$goods['is_user_grade'],
  1498. 'grade_ratio' => $goods['grade_ratio']??0,
  1499. 'grade_goods_price' => $goods['grade_goods_price']??0,
  1500. 'grade_total_money' => $goods['grade_total_money']??0,
  1501. 'coupon_id' => $goods['coupon_id']??0,
  1502. 'coupon_money' => $goods['coupon_money']??0,
  1503. 'points_money' => $isExistPointsDeduction ? $goods['points_money'] : 0.00,
  1504. 'points_num' => $isExistPointsDeduction ? $goods['points_num'] : 0,
  1505. 'points_bonus' => $goods['points_bonus']??0,
  1506. 'total_num' => $goods['total_num'],
  1507. 'total_price' => $goods['total_price'],
  1508. 'total_pay_price' => $goods['total_pay_price']??0,
  1509. 'provider_id' => $goods['provider_id'],
  1510. 'brand' => $goods['brand'],
  1511. 'province_id' => $goods['province_id'],
  1512. 'city_id' => $goods['city_id'],
  1513. 'storage' => $goods['storage'],
  1514. 'unit' => $goods['unit'],
  1515. 'clearing_price' => $goods['skuInfo']['clearing_price']??'0.00',
  1516. 'platform_rate' => $goods['skuInfo']['platform_rate']??'0.00',
  1517. 'staff_user_id' => $goods['staffUserId'],
  1518. 'shop_id' => $goods['shopId'],
  1519. 'distributor_radio' => $goods['distributor_radio']??0,
  1520. 'distributor_goods_price' => $goods['distributor_goods_price']??0,
  1521. 'distributor_total_money' => $goods['distributor_total_money']??0,
  1522. 'member_radio' => $goods['member_radio']??0,
  1523. 'member_total_money' => $goods['member_total_money']??0,
  1524. 'gold_rice_amount' => $goods['gold_rice_amount']??0,
  1525. 'gold_rice_money' => $goods['gold_rice_money']??0,
  1526. 'gold_rice_amount_input' => $goods['gold_rice_amount_input']??0,
  1527. 'rice_card_id' => $goods['rice_card_id']??0,
  1528. 'rice_card_money' => $goods['rice_card_money']??0,
  1529. 'goods_type' => $goods['goods_type']??10,
  1530. // 'has_refund_full' => $goods['goods_type']==20? 1 : 0,//赠品直接默认为全额退款状态
  1531. 'is_full_send' => $goods['is_full_send'] ?? 0,
  1532. 'full_send_activity_id' => $goods['full_send_activity_id'] ?? 0,
  1533. 'full_send_count' => $goods['full_send_count'] ?? 0,//满就送活动实际参与活动数量
  1534. 'is_qc_send_send' => $goods['is_qc_send_send'] ?? 0,//是否参与全场满件送活动
  1535. 'qc_send_activity_id' => $goods['qc_send_activity_id'] ?? 0,//全场满件送活动ID
  1536. 'qc_send_count' => $goods['qc_send_count'] ?? 0,//全场满件送活动赠品的数量
  1537. 'qc_send_use_count' => $goods['qc_send_use_count'] ?? 0,//全场满件送活动实际参与活动数量
  1538. 'is_activity_discount' => $goods['is_activity_discount'] ?? 0,//是否参与了N件X折活动 0否 1是
  1539. 'activity_discount_id' => $goods['activity_discount_id'] ?? 0,//N件X折活动ID
  1540. 'activity_discount_total_price' => $goods['activity_discount_total_price'] ?? 0,//N件X折活动折扣金额
  1541. 'activity_discount_desc' => $goods['activity_discount_desc'] ?? 0,//N件X折活动描述
  1542. 'activity_discount_count' => $goods['activity_discount_count'] ?? 0,//N件X折活动实际参与活动数量
  1543. 'is_mj_send' => $goods['is_mj_send'] ?? 0,
  1544. 'mj_send_activity_id' => $goods['mj_send_activity_id'] ?? 0,
  1545. 'mj_send_num' => $goods['mj_send_num'] ?? 0,
  1546. 'mj_send_count' => $goods['mj_send_count'] ?? 0,//满件送活动赠品的数量
  1547. 'mj_send_use_count' => $goods['mj_send_use_count'] ?? 0,//满件送活动实际参与活动数量
  1548. // 'promotion_monitor_id' => $goods['promotion_monitor_id'] ?? 0, // 推广监控ID
  1549. ];
  1550. // 记录订单商品来源id
  1551. $item['goods_source_id'] = isset($goods['goods_source_id']) ? $goods['goods_source_id'] : 0;
  1552. $goodsList[] = $item;
  1553. }
  1554. return $this->model->goods()->saveAll($goodsList) !== false;
  1555. }
  1556. /**
  1557. * 保存订单套餐商品信息
  1558. * @param $order
  1559. * @return int
  1560. */
  1561. private function saveOrderGoodsMj($order)
  1562. {
  1563. // 订单商品列表
  1564. $goodsList = [];
  1565. foreach ($order['goodsList'] as $key=> $goods) {
  1566. //如果存在满减商品也保存起来
  1567. foreach ($goods['mj_send_goods_list'] as $mj_send_goods){
  1568. $mj_item = [
  1569. 'user_id' => $this->user['user_id'],
  1570. 'store_id' => $this->storeId,
  1571. 'goods_id' => $mj_send_goods['goods_id'],
  1572. 'goods_name' => $mj_send_goods['goods_name'],
  1573. 'goods_no' => $mj_send_goods['goods_no'] ?: '',
  1574. 'image_id' => (int)current($mj_send_goods['goods_images'])['file_id'],
  1575. 'deduct_stock_type' => $mj_send_goods['deduct_stock_type'],
  1576. 'spec_type' => $mj_send_goods['spec_type'],
  1577. 'goods_sku_id' => $mj_send_goods['skuInfo']['goods_sku_id'],
  1578. 'goods_props' => $mj_send_goods['skuInfo']['goods_props'] ?: '',
  1579. 'content' => $mj_send_goods['content'] ?? '',
  1580. 'goods_sku_no' => $mj_send_goods['skuInfo']['goods_sku_no'] ?: '',
  1581. 'goods_price' => $mj_send_goods['skuInfo']['goods_price'],
  1582. 'line_price' => $mj_send_goods['skuInfo']['line_price'],
  1583. 'goods_weight' => $mj_send_goods['skuInfo']['goods_weight'],
  1584. 'is_user_grade' => (int)$mj_send_goods['is_user_grade'],
  1585. 'grade_ratio' => $mj_send_goods['grade_ratio']??0,
  1586. 'grade_goods_price' => $mj_send_goods['grade_goods_price']??0,
  1587. 'grade_total_money' => $mj_send_goods['grade_total_money']??0,
  1588. 'coupon_id' => $mj_send_goods['coupon_id']??0,
  1589. 'coupon_money' => $mj_send_goods['coupon_money']??0,
  1590. 'points_bonus' => $mj_send_goods['points_bonus']??0,
  1591. 'total_num' => $mj_send_goods['total_num'],
  1592. 'total_price' => $mj_send_goods['total_price'],
  1593. 'total_pay_price' => $mj_send_goods['total_pay_price']??0,
  1594. 'provider_id' => $mj_send_goods['provider_id'],
  1595. 'brand' => $mj_send_goods['brand'],
  1596. 'province_id' => $mj_send_goods['province_id'],
  1597. 'city_id' => $mj_send_goods['city_id'],
  1598. 'storage' => $mj_send_goods['storage'],
  1599. 'unit' => $mj_send_goods['unit'],
  1600. 'clearing_price' => $mj_send_goods['skuInfo']['clearing_price']??'0.00',
  1601. 'platform_rate' => $mj_send_goods['skuInfo']['platform_rate']??'0.00',
  1602. 'staff_user_id' => $mj_send_goods['staffUserId'],
  1603. 'shop_id' => $mj_send_goods['shopId'],
  1604. 'rice_card_id' => $mj_send_goods['rice_card_id']??0,
  1605. 'rice_card_money' => $mj_send_goods['rice_card_money']??0,
  1606. 'goods_type' => $mj_send_goods['goods_type']??20, //默认赠品
  1607. 'is_mj_send' => $goods['is_mj_send'] ?? 0,
  1608. 'mj_send_activity_id' => $goods['mj_send_activity_id'] ?? 0,
  1609. 'master_order_goods_id' => $this->model->goods[$key]['order_goods_id'],
  1610. ];
  1611. // 记录订单商品来源id
  1612. $mj_item['goods_source_id'] = isset($goods['goods_source_id']) ? $goods['goods_source_id'] : 0;
  1613. $goodsList[] = $mj_item;
  1614. }
  1615. }
  1616. return $this->model->goods()->saveAll($goodsList) !== false;
  1617. }
  1618. /**
  1619. * 保存订单套餐商品信息
  1620. * @param $order
  1621. * @return int
  1622. */
  1623. private function saveOrderGoodsTaocan($order)
  1624. {
  1625. // 当前订单是否存在和使用积分抵扣
  1626. $isExistPointsDeduction = $this->isExistPointsDeduction($order);
  1627. // 订单商品列表
  1628. $goodsList = [];
  1629. foreach ($order['goodsList'] as $key=> $goods) {
  1630. if($goods['goods_type']!=30){//是套餐商品
  1631. continue;
  1632. }
  1633. $relGoodList = GoodsPackageModel::with(['relGood'=>['images','skuList']])->where('goods_id',$goods['goods_id'])->select();
  1634. // dd( $relGoodList->toArray());
  1635. foreach ($relGoodList as $relGood){
  1636. $relGood['skuList'] = [];
  1637. foreach ($relGood['relGood']['skuList'] as $sku){
  1638. if($sku['goods_sku_id']==$relGood['rel_goods_sku_id']){
  1639. $relGood['skuList'] = $sku;
  1640. }
  1641. }
  1642. $item = [
  1643. 'user_id' => $this->user['user_id'],
  1644. 'order_id' => $this->model['order_id'],
  1645. 'order_goods_id' => $this->model->goods[$key]['order_goods_id'],
  1646. 'store_id' => $this->storeId,
  1647. 'goods_id' => $relGood['relGood']['goods_id'],
  1648. 'goods_name' => $relGood['relGood']['goods_name'],
  1649. 'goods_no' => $relGood['relGood']['goods_no'] ?: '',
  1650. 'image_id' => (int)$relGood['relGood']['images'][0]['image_id']??0,
  1651. 'deduct_stock_type' => $relGood['relGood']['deduct_stock_type'],
  1652. 'spec_type' => $relGood['relGood']['spec_type'],
  1653. 'goods_sku_id' => $relGood['skuList']['goods_sku_id']??0,
  1654. 'goods_props' => $relGood['skuList']['goods_props'] ?? '',
  1655. 'content' => $relGood['relGood']['content'] ?? '',
  1656. 'goods_sku_no' => $relGood['skuList']['goods_sku_no'] ?? '',
  1657. 'goods_price' => $relGood['skuList']['goods_price']??'0.00',
  1658. 'line_price' => $relGood['skuList']['line_price']??'0.00',
  1659. 'goods_weight' => $relGood['skuList']['goods_weight']??'0.00',
  1660. 'is_user_grade' => (int)$relGood['relGood']['is_user_grade'],
  1661. 'grade_ratio' => $relGood['relGood']['grade_ratio']??0,
  1662. 'grade_goods_price' => $relGood['relGood']['grade_goods_price']??0,
  1663. 'grade_total_money' => $relGood['relGood']['grade_total_money']??0,
  1664. 'coupon_id' => $relGood['relGood']['coupon_id']??0,
  1665. 'coupon_money' => $relGood['relGood']['coupon_money']??0,
  1666. 'points_money' => $isExistPointsDeduction ? $relGood['relGood']['points_money'] : 0.00,
  1667. 'points_num' => $isExistPointsDeduction ? $relGood['relGood']['points_num'] : 0,
  1668. 'points_bonus' => $relGood['relGood']['points_bonus']??0,
  1669. 'total_num' => 1,
  1670. 'total_price' => $relGood['relGood']['total_price']??0,
  1671. 'total_pay_price' => $relGood['relGood']['total_pay_price']??0,
  1672. 'provider_id' => $relGood['relGood']['provider_id'],
  1673. 'brand' => $relGood['relGood']['brand'],
  1674. 'province_id' => $goods['province_id'],
  1675. 'city_id' => $relGood['relGood']['city_id'],
  1676. 'storage' => $relGood['relGood']['storage'],
  1677. 'unit' => $relGood['relGood']['unit'],
  1678. 'clearing_price' => $relGood['skuList']['clearing_price']??'0.00',
  1679. 'platform_rate' => $relGood['skuList']['platform_rate']??'0.00',
  1680. 'goods_type' => 30,
  1681. ];
  1682. // 记录订单商品来源id
  1683. $item['goods_source_id'] = isset($relGood['goods_source_id']) ? $relGood['goods_source_id'] : 0;
  1684. $goodsList[] = $item;
  1685. }
  1686. }
  1687. return (new OrderGoodsTaocanModel())->saveAll($goodsList) !== false;
  1688. }
  1689. /**
  1690. * 更新商品库存 (针对下单减库存的商品)
  1691. * 普通快递、门店自提 分开扣库存
  1692. * @param $order
  1693. * @return mixed
  1694. */
  1695. private function updateGoodsStockNum($order)
  1696. {
  1697. return StockFactory::getFactory($this->model['order_source'])->updateGoodsStock($order);
  1698. }
  1699. /**
  1700. * 更新商品库存 (针对下单减库存的商品)
  1701. * 普通快递、门店自提 分开扣库存
  1702. * @param $order
  1703. * @return mixed
  1704. */
  1705. private function updateActivityStock($order)
  1706. {
  1707. return StockFactory::getFactory($this->model['order_source'])->updateActivityStock($order);
  1708. }
  1709. /**
  1710. * 记录收货地址
  1711. * @param $address
  1712. * @return false|\think\Model
  1713. */
  1714. private function saveOrderAddress($address)
  1715. {
  1716. return $this->model->address()->save([
  1717. 'user_id' => $this->user['user_id'],
  1718. 'store_id' => $this->storeId,
  1719. 'name' => $address['name'],
  1720. 'phone' => $address['phone'],
  1721. 'province_id' => $address['province_id'],
  1722. 'city_id' => $address['city_id'],
  1723. 'region_id' => $address['region_id'],
  1724. 'detail' => $address['detail'],
  1725. ]);
  1726. }
  1727. /**
  1728. * 设置错误信息
  1729. * @param $error
  1730. */
  1731. protected function setError($error)
  1732. {
  1733. empty($this->error) && $this->error = $error;
  1734. }
  1735. /**
  1736. * 获取错误信息
  1737. * @return mixed
  1738. */
  1739. public function getError()
  1740. {
  1741. return $this->error ?: '';
  1742. }
  1743. /**
  1744. * 设置错误状态
  1745. * @param $errorStatus
  1746. */
  1747. protected function setErrorStatus($errorStatus)
  1748. {
  1749. empty($this->errorStatus) && $this->errorStatus = $errorStatus;
  1750. }
  1751. /**
  1752. * 获取错误信息
  1753. * @return mixed
  1754. */
  1755. public function getErrorStatus()
  1756. {
  1757. return $this->errorStatus ?: 0;
  1758. }
  1759. /**
  1760. * 是否存在错误
  1761. * @return bool
  1762. */
  1763. public function hasError()
  1764. {
  1765. return !empty($this->error);
  1766. }
  1767. }