Checkout.php 81 KB

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