OrderForm.php 69 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595
  1. <?php
  2. /**
  3. * 重庆赤晓店信息科技有限公司
  4. * https://www.chixiaodian.com
  5. * Copyright (c) 2023 赤店商城 All rights reserved.
  6. */
  7. namespace app\modules\client\models\v1\pt\order;
  8. use app\constants\OptionSetting;
  9. use app\models\Address;
  10. use app\models\Admin;
  11. use app\models\AgentGoodsBindGoods;
  12. use app\models\Attr;
  13. use app\models\AttrGroup;
  14. use app\models\Cat;
  15. use app\models\Coupon;
  16. use app\models\CouponAutoSend;
  17. use app\models\Form;
  18. use app\models\FreeDeliveryRules;
  19. use app\models\Goods;
  20. use app\models\GoodsBook;
  21. use app\models\GoodsCat;
  22. use app\models\IntegralAppreciationGoods;
  23. use app\models\IntegralAppreciationUser;
  24. use app\models\Level;
  25. use app\models\Mch;
  26. use app\models\MchGoodsCat;
  27. use app\models\MdGoods;
  28. use app\models\OfferPrice;
  29. use app\models\Option;
  30. use app\models\Order;
  31. use app\models\OrderDetail;
  32. use app\models\PostageRules;
  33. use app\models\PtActivity;
  34. use app\models\PtActivityGoods;
  35. use app\models\PtActivityOrder;
  36. use app\models\PtActivityOrderDetail;
  37. use app\models\SeckillActivity;
  38. use app\models\SeckillActivityGoods;
  39. use app\models\SeckillActivityOrderLog;
  40. use app\models\Shop;
  41. use app\models\Store;
  42. use app\models\TerritorialLimitation;
  43. use app\models\User;
  44. use app\models\UserCoupon;
  45. use app\utils\Delivery\Delivery;
  46. use app\utils\Delivery\Alipay\ADelivery;
  47. use Yii;
  48. use yii\base\Model;
  49. use yii\helpers\Json;
  50. class OrderForm extends Model
  51. {
  52. public $mch_list;
  53. public $address_id;
  54. public $_from;
  55. public $longitude;
  56. public $latitude;
  57. public $store_id;
  58. public $store;
  59. public $user_id;
  60. public $verify_card_id;
  61. /** @var User $user */
  62. protected $user;
  63. protected $address;
  64. protected $level;
  65. protected $integral;
  66. protected $keyword;
  67. public $order_type; //1认养商品
  68. public $goods_count_activity_new_user = [];
  69. public $pt_activity_id;
  70. public $pt_number;
  71. public $head_integral;
  72. public function rules()
  73. {
  74. $rules = [
  75. ['mch_list', 'required'],
  76. ['address_id', 'integer'],
  77. ['verify_card_id', 'integer'],
  78. ['order_type', 'integer'],
  79. [['order_type',], 'default', 'value' => 0],
  80. ['mch_list', function ($attr, $params) {
  81. $data = Json::decode($this->mch_list);
  82. if (!$data) {
  83. $this->addError($attr, "{$attr}数据格式错误。");
  84. }
  85. $this->mch_list = $data;
  86. }],
  87. ['mch_list', function ($attr, $params) {
  88. foreach ($this->mch_list as $i => &$mch) {
  89. if (!is_array($mch['goods_list'])) {
  90. $this->addError($attr, "{$attr}[{$i}]['goods_list']必须是一个数组。");
  91. return;
  92. }
  93. }
  94. }],
  95. [['longitude', 'latitude', '_from'], 'trim'],
  96. [['_from'], 'in', 'range' => ['app', 'mini', 'h5', 'official']],
  97. [['pt_activity_id', 'pt_number'], 'integer']
  98. ];
  99. return $rules;
  100. }
  101. public function afterValidate()
  102. {
  103. $this->user = User::findOne($this->user_id);
  104. $this->level = $this->getLevelData();
  105. $this->address = $this->getAddressData();
  106. $this->integral = [
  107. 'forehead' => 0,
  108. 'forehead_integral' => 0,
  109. 'integration' => Option::get(OptionSetting::STORE_INTEGRATION, get_store_id(), 'gift', Option::get(OptionSetting::STORE_INTEGRATION, get_store_id(), 'store')['value'])['value']
  110. ];
  111. parent::afterValidate();
  112. }
  113. /**
  114. * @throws \Exception
  115. */
  116. protected function getMchListData($submit = false)
  117. {
  118. foreach ($this->mch_list as $i => &$mch) {
  119. $mch['pt_number'] = $mch['pt_number'] ?? $this->pt_number;
  120. $mch['goods_list'] = $this->getGoodsList($mch['goods_list']);
  121. if (empty($mch['goods_list'])) {
  122. throw new \Exception($mch['goods_list']['msg'], 1);
  123. }
  124. if ($mch['goods_list']['code'] === 1) {
  125. throw new \Exception($mch['goods_list']['msg'], 1);
  126. }
  127. //拼团信息检测
  128. $pt_activity = PtActivity::findOne($this->pt_activity_id);
  129. if (!$pt_activity) {
  130. throw new \Exception("活动不存在或已结束");
  131. }
  132. $this->head_integral = 0;
  133. if (!empty($mch['pt_number'])) {
  134. $pt_order = PtActivityOrder::findOne($mch['pt_number']);
  135. if ($pt_order) {
  136. if ((int)$pt_order->is_pay === 0) {
  137. throw new \Exception("当前团暂未开放");
  138. }
  139. //error
  140. $check_pt_order = PtActivityOrder::find()->where(['trade_status' => 0, 'is_pay' => 1])
  141. ->andWhere(['OR', ['id' => $mch['pt_number']], ['pt_number' => $mch['pt_number']]])
  142. ->select('id, is_winner, user_id')->asArray()->all();
  143. //判断是否到解散时间
  144. $end_time = (($pt_activity->split_time * 60 * 60) + ($pt_order->pay_time));
  145. if ($end_time <= time()) {
  146. throw new \Exception("当前团已解散");
  147. }
  148. //判断是否开奖
  149. $open = false;
  150. foreach ($check_pt_order as $item) {
  151. if ((int)$item['is_winner'] > 0) {
  152. $open = true;
  153. }
  154. if($pt_activity->party_type == 0){
  155. if ((int)$item['user_id'] === get_user_id()) {
  156. throw new \Exception("已加入,不可重复操作");
  157. }
  158. }
  159. }
  160. if ($open) {
  161. throw new \Exception("当前团已开奖");
  162. }
  163. if($pt_activity->party_type == 0){
  164. if ($pt_activity->party_size <= (count($check_pt_order))) {
  165. throw new \Exception("当前团已达上限");
  166. }
  167. }
  168. if($pt_activity->party_type == 1){
  169. $goodsCountQuery = PtActivityOrderDetail::find()->alias('pod')
  170. ->leftJoin(['po' => PtActivityOrder::tableName()], 'pod.order_id = po.id')
  171. ->where(['po.is_pay' => 1, 'pod.is_delete' => 0])
  172. ->andWhere(['OR' , ['po.id' => $mch['pt_number']], ['po.pt_number' => $mch['pt_number']]]);
  173. $goodsCount = $goodsCountQuery->sum('pod.num');
  174. if ($pt_activity->party_goods_count <= (int)$goodsCount) {
  175. throw new \Exception("当前团商品数量已达上限");
  176. }
  177. $buyCount = 0;
  178. foreach ($mch['goods_list'] as $_goods) {
  179. $buyCount += (int)$_goods['num'];
  180. if ($pt_activity->party_goods_count < ((int)$goodsCount + $buyCount)) {
  181. throw new \Exception("当前购买商品数量已超活动限制");
  182. }
  183. }
  184. }
  185. } else {
  186. //判断团长是否积分充足
  187. $head_integral = $pt_activity->head_integral;
  188. if ($head_integral > 0) {
  189. if ($head_integral > get_user()->integral) {
  190. throw new \Exception("开团积分不足");
  191. }
  192. $this->head_integral = $head_integral;
  193. }
  194. }
  195. } else {
  196. //判断团长是否积分充足
  197. $head_integral = $pt_activity->head_integral;
  198. if ($head_integral > 0) {
  199. if ($head_integral > get_user()->integral) {
  200. throw new \Exception("开团积分不足");
  201. }
  202. $this->head_integral = $head_integral;
  203. }
  204. }
  205. if($pt_activity->party_type == 1){
  206. $buyCount = 0;
  207. foreach ($mch['goods_list'] as $_goods) {
  208. $buyCount += (int)$_goods['num'];
  209. if ($pt_activity->party_goods_count < $buyCount) {
  210. throw new \Exception("当前购买商品数量已超活动限制" . $pt_activity->party_goods_count);
  211. }
  212. }
  213. } else {
  214. $buyCount = 0;
  215. foreach ($mch['goods_list'] as $_goods) {
  216. $buyCount += (int)$_goods['num'];
  217. if ($pt_activity->order_goods_limit < $buyCount) {
  218. throw new \Exception("当前购买商品数量已超活动限制" . $pt_activity->order_goods_limit);
  219. }
  220. }
  221. }
  222. if ($mch['mch_id'] == 0) {
  223. $mch['name'] = '平台自营';
  224. // if ($submit == false) {
  225. // $mch['form'] = $this->getFormData();
  226. // } else {
  227. // $mch['form'] = $this->getForm($mch['form']);
  228. // }
  229. $send_type = Option::get(OptionSetting::STORE_SEND_TYPE, get_store_id(), 'store')['value'];
  230. $send_type = Option::get(OptionSetting::STORE_SEND_TYPE, get_store_id(), 'pay', $send_type);
  231. $send_type = !empty($send_type['value']) ? Json::decode($send_type['value']) : ["express" => ["text" => "快递", "value" => 1]];
  232. $send_type_arr = [];
  233. if (isset($send_type['express']['value']) && $send_type['express']['value']) {
  234. $send_type_arr[] = 'express';
  235. }
  236. if (isset($send_type['shop']['value']) && $send_type['shop']['value']) {
  237. $send_type_arr[] = 'shop';
  238. }
  239. // if ((isset($send_type['delivery']['value']) && $send_type['delivery']['value']) && $submit == false) {
  240. //
  241. // if(is_alipay_platform()){
  242. // $send_type_arr[] = 'delivery';
  243. // try{
  244. // $conf = ADelivery::getConf($this->store_id, get_mini_id(), 1);
  245. // $check = $conf['check'];
  246. // if($check['code'] == 0){
  247. // $send_type_arr[] = 'delivery';
  248. // }
  249. // } catch (\Exception $e) {
  250. // \Yii::error([__METHOD__, $this->store_id, get_mini_id(), $e]);
  251. // }
  252. // }else{
  253. // $res = Delivery::getBindAccount();
  254. // // 下单时判断是否可以同城配送
  255. // if (!empty($res['data']['shop_list'])) {
  256. // $store = Store::findOne($this->store_id);
  257. // if ($store->delivery_type > 0) {
  258. // $shop_list = $res['data']['shop_list'];
  259. // $delivery_arr = array_column($shop_list, 'delivery_id');
  260. // $delivery_arr[] = 'TEST';
  261. // $delivery_arr_id = array_column($shop_list, null, 'delivery_id');
  262. // if (in_array(Delivery::$deliveryIdArr[$store->delivery_type], $delivery_arr) && $delivery_arr_id[Delivery::$deliveryIdArr[$store->delivery_type]]['audit_result'] == 0) {
  263. // $send_type_arr[] = 'delivery';
  264. // }
  265. // }
  266. // }
  267. // }
  268. // }
  269. } else {
  270. $_mch = Mch::findOne([
  271. 'store_id' => $this->store_id,
  272. 'id' => $mch['mch_id'],
  273. ]);
  274. if (!$_mch) {
  275. unset($this->mch_list[$i]);
  276. continue;
  277. }
  278. $send_type_arr = [];
  279. if ($_mch['express_delivery']) {
  280. $send_type_arr[] = 'express';
  281. }
  282. if ($_mch['self_delivery']) {
  283. $send_type_arr[] = 'shop';
  284. }
  285. $mch['name'] = $_mch->name;
  286. $mch['form'] = null;
  287. // $mch['shop_list'] = [(object)[
  288. // 'address' => $_mch->address,
  289. // 'distance' => '',
  290. // 'id' => $_mch->id,
  291. // 'is_default' => 1,
  292. // 'latitude' => $_mch->latitude,
  293. // 'longitude' => $_mch->longitude,
  294. // 'mobile' => $_mch->tel,
  295. // 'name' => $_mch->name,
  296. // ]];
  297. }
  298. $mch['send_type'] = $send_type_arr;
  299. if (in_array('shop', $send_type_arr)) {
  300. $shopArr = $this->getShopList();
  301. $mch['is_shop'] = $shopArr['shop'];
  302. $mch['shop_list'] = $shopArr['list'];
  303. } else {
  304. $mch['shop_list'] = [];
  305. $mch['is_shop'] = '';
  306. }
  307. $total_price = 0;
  308. $level_price = 0;
  309. $next_level_price = 0;
  310. $integral = [
  311. 'forehead' => 0,
  312. 'forehead_integral' => 0
  313. ];
  314. $mch['plugin_type'] = isset($mch['plugin_type']) ? $mch['plugin_type'] : 0;
  315. $open = false;
  316. // foreach ($mch['goods_list'] as &$mch_goods) {
  317. // $seckill_activity_goods = SeckillActivityGoods::find()->alias('sag')->where(['sag.goods_id' => $mch_goods['goods_id']])
  318. // ->leftJoin(['sg' => SeckillActivity::tableName()], 'sg.id = sag.activity_id')
  319. // ->andWhere(['AND', ['>', 'sg.end_time', time()], ['<', 'sg.start_time', time()], ['sg.is_delete' => 0, 'sag.is_delete' => 0, 'sg.store_id' => get_store_id()]])
  320. // ->select('sg.is_use_coupon')->asArray()->one();
  321. // if ($seckill_activity_goods && (int)$seckill_activity_goods['is_use_coupon'] === 0) {
  322. // $open = true;
  323. // }
  324. // }
  325. foreach ($mch['goods_list'] as &$_goods) {
  326. // if (in_array($_goods['product_type'], [1, 2])) {
  327. // $mch['send_type'] = ['shop'];
  328. // }
  329. // if (in_array($_goods['product_type'], [1, 2]) && $submit == true) {
  330. // $res = $this->bookCheckGoodsNum($_goods, $_goods['product_type']);
  331. // if ($res['code'] != 0) {
  332. // throw new \Exception($res['msg'], 1);
  333. // }
  334. // }
  335. if ($submit == false) {
  336. $_goods = array_merge($_goods, [
  337. 'form' => []
  338. ]);
  339. $_goods['form'] = $this->getNewFormData($_goods);
  340. } else {
  341. $_goods['form'] = $this->getForm($_goods['form']);
  342. }
  343. $total_price += doubleval($_goods['price']);
  344. if ((int)$_goods['product_type'] === 2) {
  345. $_goods['level_price'] = sprintf('%.2f', $mch['list']['price']);
  346. $_goods['price'] = $mch['list']['price'];
  347. }
  348. $level_price += doubleval($_goods['level_price']) > 0 ? doubleval($_goods['level_price']) : doubleval($_goods['price']);
  349. $_goods['integral'] = [
  350. 'forehead' => 0,
  351. 'forehead_integral' => 0
  352. ];
  353. $integral['forehead'] = 0;
  354. $integral['forehead_integral'] = 0;
  355. unset($_goods['is_form']);
  356. unset($_goods['form_name']);
  357. }
  358. // $integral['forehead'] = round($integral['forehead'], 2);
  359. $mch['total_price'] = sprintf('%.2f', $total_price);
  360. $mch['level_price'] = sprintf('%.2f', $level_price);
  361. $mch['diy_send_type'] = [
  362. [
  363. 'key' => 'express',
  364. 'name' => Option::get(OptionSetting::DIY_EXPRESS_NAME, get_store_id(), 'pay', Option::get(OptionSetting::DIY_EXPRESS_NAME, get_store_id(), 'store', '快递配送')['value'] ?: '快递配送')['value']
  365. ],
  366. [
  367. 'key' => 'shop',
  368. 'name' => Option::get(OptionSetting::DIY_SHOP_NAME, get_store_id(), 'pay', Option::get(OptionSetting::DIY_SHOP_NAME, get_store_id(), 'store', '自提配送')['value'] ?: '自提配送')['value']
  369. ],
  370. [
  371. 'key' => 'delivery',
  372. 'name' => Option::get(OptionSetting::DIY_DELIVERY_NAME, get_store_id(), 'pay', Option::get(OptionSetting::DIY_DELIVERY_NAME, get_store_id(), 'store', '同城配送')['value'] ?: '同城配送')['value']
  373. ]
  374. ];
  375. $mch['integral'] = [
  376. "forehead" => 0,
  377. "forehead_integral" => 0
  378. ];
  379. $mch['coupon_list'] = [];
  380. $mch['express_price'] = $this->getExpressPrice($mch);
  381. $mch['offer_rule'] = null;
  382. // if(empty(input_params('flag_id'))){
  383. // //获取限制地区
  384. $mch['is_area'] = 0;
  385. // }
  386. // 如果是点餐的商品,结构需要变一下
  387. // if (get_md_id() && (!empty(input_params('flag_id')) || !empty(input_params('table_num'))) && !$submit) {
  388. // $user_list = [];
  389. // $user_ids = array_unique(array_column($mch['goods_list'], 'user_id'));
  390. // foreach ($user_ids as $user_id) {
  391. // $goods_list = [];
  392. // foreach ($mch['goods_list'] as $item) {
  393. // if ($item['user_id'] == $user_id) {
  394. // $goods_list[] = $item;
  395. // }
  396. // }
  397. // $saas_user = SaasUser::findOne(['mobile' => User::findOne($user_id)->binding]);
  398. // $user_list[] = [
  399. // 'name' => $saas_user->name,
  400. // 'avatar' => $saas_user->avatar,
  401. // 'user_id' => $user_id,
  402. // 'goods_list' => $goods_list
  403. // ];
  404. // }
  405. // $mch['goods_list'] = $user_list;
  406. // }
  407. }
  408. return $this->mch_list;
  409. }
  410. protected function getGoodsList($goods_list)
  411. {
  412. $goodsIds = [];
  413. // $cards = [];
  414. $goods_integral_amount = 0;
  415. foreach ($goods_list as $i => &$item) {
  416. $food_ext_goods = [];
  417. if ($item['goods_id']) {
  418. $attr_id_list = [];
  419. foreach ($item['attr'] as $_a) {
  420. array_push($attr_id_list, $_a['attr_id']);
  421. }
  422. $goods = Goods::findOne([
  423. 'store_id' => get_store_id(),
  424. 'id' => $item['goods_id'],
  425. ]);
  426. } else {
  427. unset($goods_list[$i]);
  428. continue;
  429. }
  430. if (!$goods) {
  431. unset($goods_list[$i]);
  432. continue;
  433. }
  434. // $delivery_rules = DeliveryRules::find()->where([
  435. // 'id' => $goods->delivery_rules_id,
  436. // 'is_delete' => 0,
  437. // 'status' => 1,
  438. // 'store_id' => get_store_id()
  439. // ])->select('type, times, days, name')->asArray()->one();
  440. //
  441. // if ($delivery_rules) {
  442. // $days = "下单" . $delivery_rules['days'] . "天后";
  443. // $delivery_rules['times'] =
  444. // (int)$delivery_rules['type'] === 1 ? $days : date("m月d日 H:i:s", $delivery_rules['times']);
  445. // $delivery_rules['type'] .= '';
  446. // }
  447. // $item['delivery_rules'] = $delivery_rules;
  448. // if (($goods->confine_count && $goods->confine_count > 0)) {
  449. // $goodsNum = Goods::getBuyNum($this->user, $goods->id);
  450. // if ($goodsNum) {
  451. //
  452. // } else {
  453. // $goodsNum = 0;
  454. // }
  455. // $goodsTotalNum = intval($goodsNum + $item['num']);
  456. // if ($goodsTotalNum > $goods->confine_count) {
  457. // throw new \Exception('商品:' . $goods->name . ' 只允许购买' . $goods->confine_count . $goods->unit, 1);
  458. // }
  459. // }
  460. //增值积分活动商品检测
  461. /* $integralAppreciationGoods = IntegralAppreciationGoods::findOne(['goods_id' => $goods->id, 'is_delete' => 0]);
  462. if ($integralAppreciationGoods && $integralAppreciationGoods->integral_amount > 0) {
  463. $integral_appreciation_setting = Option::get('integral_appreciation_setting', get_store_id(), 'integral_appreciation')['value'];
  464. $integral_appreciation_setting = json_decode($integral_appreciation_setting ?? '', true);
  465. $integral_custom_name = $integral_appreciation_setting['integral_custom_name'] ?: '增值积分';
  466. $integralAppreciationUser = IntegralAppreciationUser::findOne(['user_id' => $this->user_id]);
  467. if (!$integralAppreciationUser) {
  468. return [
  469. 'code' => 1,
  470. 'msg' => "用户{$integral_custom_name}数量不足"
  471. ];
  472. }
  473. $goods_integral_amount = bcadd(bcmul($integralAppreciationGoods->integral_amount, $item['num'], 2), $goods_integral_amount, 2);
  474. if ($goods_integral_amount > $integralAppreciationUser->integral) {
  475. return [
  476. 'code' => 1,
  477. 'msg' => "用户{$integral_custom_name}数量不足"
  478. ];
  479. }
  480. }*/
  481. $cat_id_arr = GoodsCat::find()->where(['goods_id' => $goods->id, 'is_delete' => 0])->select('cat_id')->column();
  482. $shop_count = Cat::find()->where(['id' => $cat_id_arr])->andWhere(['>', 'shop_count', 0])->select('shop_count')->min('shop_count') ?: 0;
  483. if ($shop_count > 0 && $shop_count > $item['num']) {
  484. return [
  485. 'code' => 1,
  486. 'msg' => $goods->name . "起购数量为" . $shop_count,
  487. ];
  488. }
  489. foreach ($attr_id_list as $index => $value) {
  490. if ($value < 0) {
  491. unset($attr_id_list[$index]);
  492. }
  493. }
  494. $attr = json_decode($goods->attr, true);
  495. $attr_info = $goods->getAttrInfo($attr_id_list);
  496. //获取拼团价格
  497. $pt_activity_goods = PtActivityGoods::find()->alias('pag')->where(['pag.goods_id' => $goods->id])
  498. ->leftJoin(['pa' => PtActivity::tableName()], 'pag.activity_id = pa.id')
  499. ->andWhere(['AND', ['pa.is_delete' => 0], ['>', 'pa.end_time', time()], ['<', 'start_time', time()], ['pag.is_delete' => 0]])
  500. ->select('pa.id, pa.party_size, pa.party_type, pa.party_goods_count, pa.join_num, pa.start_time, pa.end_time, pag.attr, pag.pt_price, pag.use_attr, pag.sale_num, pag.virtual_sales, pag.activity_id')->asArray()->one();
  501. if ($pt_activity_goods) {
  502. $pt_goods_attr = json_decode($pt_activity_goods['attr'], true);
  503. foreach ($pt_goods_attr as $pt_attr) {
  504. $pt_attr_id = array_column($pt_attr['attr_list'], 'attr_id');
  505. sort($pt_attr_id);
  506. sort($attr_id_list);
  507. if (empty(array_diff($pt_attr_id, $attr_id_list))) {
  508. $attr_info['price'] = $pt_attr['pt_price'];
  509. $goods->price = $pt_activity_goods['pt_price'] = $pt_attr['pt_price'];
  510. }
  511. foreach ($attr as &$g_attr) {
  512. $g_attr_id = array_column($g_attr['attr_list'], 'attr_id');
  513. sort($g_attr_id);
  514. if (empty(array_diff($pt_attr_id, $g_attr_id))) {
  515. $g_attr['price'] = $pt_attr['pt_price'];
  516. }
  517. }
  518. }
  519. $attr = json_encode($attr);
  520. $this->pt_activity_id = $pt_activity_goods['activity_id'];
  521. $join_num = $pt_activity_goods['join_num'];
  522. if($pt_activity_goods['party_type'] == 0){
  523. $s_today_time = strtotime(date('Y-m-d'));
  524. $e_today_time = (strtotime(date('Y-m-d')) + 3600 * 24);
  525. $join_count = PtActivityOrderDetail::find()->alias('od')
  526. ->leftJoin(['o' => PtActivityOrder::tableName()], 'od.order_id = o.id')
  527. ->where(['od.goods_id' => $goods->id, 'o.user_id' => get_user_id(), 'is_pay' => 1])
  528. ->andWhere(['AND', ['>', 'od.created_at', $s_today_time], ['<', 'od.created_at', $e_today_time]])->select('od.id')->count();
  529. if ($join_num > 0 && $join_count >= $join_num) {
  530. return [
  531. 'code' => 1,
  532. 'msg' => "今日参加此商品的拼团次数已达上限"
  533. ];
  534. }
  535. }
  536. } else {
  537. return [
  538. 'code' => 1,
  539. 'msg' => "拼团活动不存在"
  540. ];
  541. }
  542. $attr_list = Attr::find()->alias('a')
  543. ->select('ag.id AS attr_group_id,ag.attr_group_name,a.id AS attr_id,a.attr_name')
  544. ->leftJoin(['ag' => AttrGroup::tableName()], 'a.attr_group_id=ag.id')
  545. ->where(['a.id' => $attr_id_list, 'ag.store_id' => get_store_id(),])
  546. ->asArray()->all();
  547. $item['user_id'] = !empty($user_id) ? $user_id : 0;
  548. $item['attr_list'] = $attr_list;
  549. $item['goods_id'] = $goods->id;
  550. $item['mch_id'] = $goods->mch_id;
  551. $item['rate'] = $goods->rate;
  552. $item['rate_type'] = $goods->rate_type;
  553. $item['goods_name'] = $goods->name;
  554. $item['goods_pic'] = $attr_info['pic'] ? $attr_info['pic'] : $goods->cover_pic;
  555. //如果没有使用规格,则使用商品售价 否则使用规格售价
  556. $item['price'] = sprintf('%.2f', (($goods->use_attr ? $attr_info['price'] : $goods->price) * $item['num']));
  557. $item['single_price'] = sprintf('%.2f', $attr_info['price']);
  558. $item['weight'] = $goods->weight;
  559. $item['integral'] = 0;
  560. $item['integral'] = $goods->integral ? $goods->integral : 0;
  561. $item['freight'] = 0;
  562. $item['full_cut'] = $goods->full_cut;
  563. $item['goods_cat_id'] = $goods->cat_id;
  564. $item['id'] = $goods->id;
  565. $item['verify_card_id'] = 0;
  566. $item['type'] = $goods->type;
  567. $item['delivery_type'] = Json::decode($goods->delivery_type);
  568. if (in_array('delivery', $item['delivery_type'])) {
  569. foreach ($item['delivery_type'] as $delivery_index => $delivery_item) {
  570. if ($delivery_item == 'delivery') {
  571. unset($item['delivery_type'][$delivery_index]);
  572. }
  573. }
  574. }
  575. // 当前选择的规格
  576. $attrIdArr = [];
  577. foreach ($item['attr_list'] as $attrListItem) {
  578. $attrIdArr[] = $attrListItem['attr_id'];
  579. }
  580. // 门店逻辑
  581. $price = $goods->price;
  582. if ($pt_activity_goods) {
  583. $price = $pt_activity_goods['pt_price'];
  584. }
  585. $res = \app\modules\client\models\v1\common\CommonGoods::currentGoodsAttr([
  586. 'attr' => $attr,
  587. 'price' => $price,
  588. 'is_level' => 0,
  589. 'mch_id' => $goods->mch_id,
  590. 'unit' => $goods->unit,
  591. 'use_attr' => $goods->use_attr,
  592. 'food_ext_goods' => $food_ext_goods,
  593. ], $attrIdArr, [], $item['num']);
  594. $item['batch_price_tips'] = $res['batch_price_tips'];
  595. $item['current_batch_price_tips'] = $res['current_batch_price_tips'];
  596. $item['price'] = sprintf('%.2f', ($res['price'] * $item['num']));
  597. $item['level_price'] = sprintf('%.2f', ($res['level_price'] * $item['num']));
  598. $item['next_level_price'] = sprintf('%.2f', ($res['next_level_price'] * $item['num']));
  599. $item['is_level'] = $res['is_level'];
  600. $send_integral_profit = Option::get(OptionSetting::SEND_INTEGRAL_PROFIT, get_store_id(), 'gift', Option::get(OptionSetting::SEND_INTEGRAL_PROFIT, get_store_id(), 'store')['value'])['value'];
  601. $integralArr = $this->getIntegral((object)$item, Option::get(OptionSetting::STORE_INTEGRAL,get_store_id(), 'gift', Option::get(OptionSetting::STORE_INTEGRAL,get_store_id(), 'store')['value'])['value'], $goodsIds, $send_integral_profit);
  602. $item['give'] = $integralArr['give'];
  603. $item['resIntegral'] = $integralArr['resIntegral'];
  604. $goodsIds[] = $goods->id;
  605. $item['goods_card_list'] = null;
  606. $item['is_form'] = $goods->is_form;
  607. $item['form_name'] = $goods->form_name;
  608. $item['product_type'] = $goods->product_type;
  609. }
  610. // 和空数组合并重建索引,避免出现因索引key间断导致客户端显示问题
  611. return array_merge($goods_list, []);
  612. }
  613. //秒杀商品处理
  614. public function getSceKillGoodsPrice($goods, $attr, $submit, $num)
  615. {
  616. $t = \Yii::$app->db->beginTransaction();
  617. try {
  618. //秒杀订单
  619. $sql = SeckillActivityGoods::find()->alias('sag')->where(['sag.goods_id' => $goods->id])
  620. ->leftJoin(['sg' => SeckillActivity::tableName()], 'sg.id = sag.activity_id')
  621. ->andWhere(['AND', ['>', 'sg.end_time', time()], ['<', 'sg.start_time', time()], ['sg.is_delete' => 0, 'sag.is_delete' => 0, 'sg.store_id' => get_store_id()]])
  622. ->select('sag.id sag_id, sg.id, sg.end_time, sag.attr, sag.use_attr, sag.seckill_num, sag.seckill_price, sag.sale_num, sg.order_limit_num, sg.self_limit_num')->createCommand()->getRawSql();
  623. $sql = $sql . ' FOR UPDATE';
  624. $seckill_activity_goods = Yii::$app->db->createCommand($sql)->queryOne();
  625. $price = 0;
  626. $id = 0;
  627. if (!empty($seckill_activity_goods)) {
  628. $sum = SeckillActivityOrderLog::find()
  629. ->where(['activity_goods_id' => $seckill_activity_goods['sag_id'], 'store_id' => get_store_id(), 'user_id' => get_user_id(), 'is_delete' => 0])
  630. ->count('num');
  631. if ($seckill_activity_goods['self_limit_num'] > 0 && ($sum * 1 + $num) > $seckill_activity_goods['self_limit_num']) {
  632. throw new \Exception("购买数量超出限购数量");
  633. }
  634. if ($seckill_activity_goods['order_limit_num'] > 0 && $num > $seckill_activity_goods['order_limit_num']) {
  635. throw new \Exception("购买数量超出订单限购数量");
  636. }
  637. //如果商品使用规格 且 已经查找到活动
  638. // if ((int)$goods->use_attr === 1 && !empty($seckill_activity_goods['attr'])) {
  639. //解码
  640. $seckill_activity_goods['attr'] = $sag_attrs = json_decode($seckill_activity_goods['attr'], true);
  641. //获取设置的商品秒杀规格id数组与购物车添加的规格id数组比较
  642. // $sag_attrs = array_column($sag_attrs, 'attr_list');
  643. //假设没有对应的规格信息
  644. $open = false;
  645. foreach ($sag_attrs as $sag_attr) {
  646. $sag_attr_id = array_column($sag_attr['attr_list'], 'attr_id');
  647. // $sag_attr['seckill_num'] -= $num;
  648. //与购物车添加的规格id数组比较
  649. if (empty(array_diff($sag_attr_id, $attr))) {
  650. if ((int)$sag_attr['seckill_num'] >= $num) {
  651. $price = $sag_attr['seckill_price'];
  652. $id = $seckill_activity_goods['sag_id'];
  653. } else {
  654. throw new \Exception("当前秒杀商品库存不足");
  655. }
  656. }
  657. }
  658. // } else {
  659. // if ($seckill_activity_goods['seckill_num'] >= ($seckill_activity_goods['sale_num'] + $num)) {
  660. // $price = $seckill_activity_goods['seckill_price'];
  661. // $id = $seckill_activity_goods['sag_id'];
  662. // } else {
  663. // throw new \Exception("当前秒杀商品库存不足");
  664. // }
  665. // }
  666. if ($submit && $id > 0) {
  667. $activity_goods = SeckillActivityGoods::findOne($id);
  668. $activity_goods_attr = json_decode($activity_goods->attr, true);
  669. foreach ($activity_goods_attr as &$sag_attr) {
  670. $sag_attr_id = array_column($sag_attr['attr_list'], 'attr_id');
  671. // $sag_attr['seckill_num'] -= $num;
  672. //与购物车添加的规格id数组比较
  673. if (empty(array_diff($sag_attr_id, $attr))) {
  674. $sag_attr['seckill_num'] = $sag_attr['seckill_num'] - $num;
  675. }
  676. }
  677. $activity_goods->attr = json_encode($activity_goods_attr);
  678. $activity_goods->sale_num = ($activity_goods->sale_num * 1 + $num);
  679. $activity_goods->seckill_num = ($activity_goods->seckill_num - $num);
  680. if (!$activity_goods->save()) {
  681. throw new \Exception(json_encode($activity_goods->errors));
  682. }
  683. }
  684. }
  685. $t->commit();
  686. return [
  687. 'code' => 0,
  688. 'msg' => '获取成功',
  689. 'data' => $price,
  690. 'id' => $id
  691. ];
  692. } catch (\Exception $e) {
  693. $t->rollBack();
  694. return [
  695. 'code' => 1,
  696. 'msg' => $e->getMessage()
  697. ];
  698. }
  699. }
  700. //自定义表单
  701. protected function getFormData()
  702. {
  703. $new_list = [];
  704. $new_list['is_form'] = Option::get('is_form', $this->store_id, 'store', 0)['value'];
  705. $form_list = [];
  706. if ($new_list['is_form'] == 1) {
  707. $new_list['name'] = Option::get('form_name', $this->store_id, 'store', '表单信息')['value'];
  708. $form_list = Form::find()->where([
  709. 'store_id' => $this->store_id, 'is_delete' => 0,
  710. ])->orderBy(['sort' => SORT_ASC])->asArray()->all();
  711. foreach ($form_list as $index => $value) {
  712. if (in_array($value['type'], ['radio', 'checkbox'])) {
  713. $default = str_replace(",", ",", $value['default']);
  714. $list = explode(',', $default);
  715. $default_list = [];
  716. foreach ($list as $k => $v) {
  717. $default_list[$k]['name'] = $v;
  718. if ($k == 0) {
  719. if ($value['type'] == 'radio') {
  720. $form_list[$index]['default'] = $v;
  721. } else {
  722. $form_list[$index]['default'] = [$v];
  723. }
  724. $default_list[$k]['checked'] = true;
  725. } else {
  726. $default_list[$k]['checked'] = false;
  727. }
  728. }
  729. $form_list[$index]['default_list'] = $default_list;
  730. }
  731. }
  732. }
  733. $new_list['list'] = $form_list;
  734. return $new_list;
  735. }
  736. //自定义表单
  737. protected function getNewFormData($goods)
  738. {
  739. $new_list = [];
  740. $new_list['is_form'] = $goods['is_form'];
  741. $form_list = [];
  742. if ($new_list['is_form'] == 1) {
  743. $new_list['name'] = $goods['form_name'];
  744. $form_list = Form::find()->where([
  745. 'store_id' => $this->store_id, 'is_delete' => 0, 'goods_id' => $goods['id']
  746. ])->orderBy(['sort' => SORT_ASC])->asArray()->all();
  747. foreach ($form_list as $index => $value) {
  748. if (in_array($value['type'], ['radio', 'checkbox'])) {
  749. $default = str_replace(",", ",", $value['default']);
  750. $list = explode(',', $default);
  751. $default_list = [];
  752. foreach ($list as $k => $v) {
  753. $default_list[$k]['name'] = $v;
  754. if ($k == 0) {
  755. if ($value['type'] == 'radio') {
  756. $form_list[$index]['default'] = $v;
  757. } else {
  758. $form_list[$index]['default'] = [$v];
  759. }
  760. $default_list[$k]['checked'] = true;
  761. } else {
  762. $default_list[$k]['checked'] = false;
  763. }
  764. }
  765. $form_list[$index]['default_list'] = $default_list;
  766. }
  767. }
  768. }
  769. $new_list['list'] = $form_list;
  770. return $new_list;
  771. }
  772. protected function getAddress()
  773. {
  774. if (!$this->address) {
  775. if ($this->address_id) {
  776. $this->address = Address::findOne(['id' => $this->address_id, 'user_id' => get_saas_user_id(), 'is_delete' => 0]);
  777. } else {
  778. $this->address = Address::find()->where([
  779. 'user_id' => get_saas_user_id(),
  780. 'is_default' => 1,
  781. 'is_delete' => 0,
  782. ])->limit(1)->one();
  783. }
  784. }
  785. return (object)$this->address;
  786. }
  787. //获取收货地址,有address_id优先获取,没有则获取默认地址
  788. protected function getAddressData()
  789. {
  790. $address = $this->getAddress();
  791. if (isset($address->id)) {
  792. return [
  793. 'id' => $address->id,
  794. 'name' => $address->name,
  795. 'mobile' => $address->mobile,
  796. 'province_id' => $address->province_id,
  797. 'province' => $address->province,
  798. 'city_id' => $address->city_id,
  799. 'city' => $address->city,
  800. 'district_id' => $address->district_id,
  801. 'district' => $address->district,
  802. 'detail' => $address->detail,
  803. 'is_default' => $address->is_default,
  804. 'latitude' => $address->latitude,
  805. 'longitude' => $address->longitude,
  806. ];
  807. } else {
  808. return null;
  809. }
  810. }
  811. //获取支付方式
  812. public function getPayTypeList()
  813. {
  814. $pay_type_list_json = Option::get(OptionSetting::STORE_PAYMENT, get_store_id(), 'pay', Option::get(OptionSetting::STORE_PAYMENT, get_store_id(), 'store', '{"wechat":{"value":1}}')['value']);
  815. $pay_type_list = Json::decode($pay_type_list_json['value']);
  816. $user_pay_list_json = Option::get('payment_' . get_user_id(), get_store_id(), 'user')['value'];
  817. if ($user_pay_list_json) {
  818. $user_pay_list_arr = Json::decode($user_pay_list_json);
  819. foreach ($pay_type_list as $key => &$value) {
  820. if (isset($user_pay_list_arr[$key]) && $user_pay_list_arr[$key]['value'] == 0 && $value['value'] == 1) {
  821. $value['value'] = 0;
  822. }
  823. }
  824. }
  825. $new_list = [];
  826. foreach ($pay_type_list as $index => $pay_type_value) {
  827. if ((is_wechat_platform() || is_h5() || is_app_platform()) && $index == 'wechat' && $pay_type_value['value'] == 1) {
  828. $new_list[] = [
  829. 'name' => '微信支付',
  830. 'payment' => 1,
  831. 'icon' => \Yii::$app->request->hostInfo . \Yii::$app->request->baseUrl . '/web/v1/statics/images/recharge/icon-online.png'
  832. ];
  833. }
  834. if ((is_alipay_platform() || is_h5() || is_app_platform()) && $index == 'alipay' && $pay_type_value['value'] == 1) {
  835. $new_list[] = [
  836. 'name' => '支付宝支付',
  837. 'payment' => 4,
  838. 'icon' => \Yii::$app->request->hostInfo . \Yii::$app->request->baseUrl . '/web/v1/statics/images/recharge/icon-alipay.png'
  839. ];
  840. }
  841. //如果是微信且商城已配置通联支付进件数据
  842. if (is_wechat_platform() && $index == Order::PAY_TYPE_KEY_YUNST_WECHAT_PAY && $pay_type_value['value'] == 1) {
  843. $store = Store::findOne(get_store_id());
  844. if (!empty($store->cusid)) {
  845. $new_list[] = [
  846. 'name' => '通联支付',
  847. 'payment' => Order::PAY_TYPE_YUNST_WECHAT_PAY,
  848. 'icon' => \Yii::$app->request->hostInfo . \Yii::$app->request->baseUrl . '/web/v1/statics/images/recharge/icon-online.png'
  849. ];
  850. }
  851. }
  852. }
  853. return $new_list;
  854. }
  855. /**
  856. * 支付方式
  857. * @param array $is_payment //支付方式
  858. * @param array $ignore //忽略的支付方式
  859. * @return array
  860. */
  861. public static function getPayType($is_payment = array(), $ignore = array())
  862. {
  863. if (!$is_payment || empty($is_payment)) {
  864. $default = '{"wechat":{"value":1}}';
  865. if (is_alipay_platform()) {
  866. $default = '{"alipay":{"value":1}}';
  867. }
  868. if (is_toutiao_platform()) {
  869. $default = '{"toutiao":{"value":1}}';
  870. }
  871. $pay_str = Option::get(OptionSetting::STORE_PAYMENT, get_store_id(), 'pay', Option::get(OptionSetting::STORE_PAYMENT, get_store_id(), 'store', $default)['value']);
  872. $is_payment = Json::decode($pay_str['value']);
  873. }
  874. $pay_type_list = [];
  875. foreach ($is_payment as $index => $value) {
  876. if (in_array($index, $ignore)) {
  877. continue;
  878. }
  879. if ($index == 'wechat' && $value['value'] == 1 && is_wechat_platform()) {
  880. $pay_type_list[] = [
  881. 'name' => '微信支付',
  882. 'payment' => 1,
  883. 'icon' => \Yii::$app->request->hostInfo . \Yii::$app->request->baseUrl . '/v1/statics/wxapp/images/icon-payment-online.png'
  884. ];
  885. }
  886. if ($index == 'toutiao' && $value['value'] == 1 && is_toutiao_platform()) {
  887. $pay_type_list[] = [
  888. 'name' => '线上支付',
  889. 'payment' => 5,
  890. 'icon' => \Yii::$app->request->hostInfo . \Yii::$app->request->baseUrl . '/v1/statics/wxapp/images/icon-payment-online.png'
  891. ];
  892. }
  893. // if ($index == 'huodao' && $value['value'] == 1) {
  894. // $pay_type_list[] = [
  895. // 'name' => '货到付款',
  896. // 'payment' => 2,
  897. // 'icon' => \Yii::$app->request->hostInfo . \Yii::$app->request->baseUrl . '/v1/statics/wxapp/images/icon-payment-huodao.png'
  898. // ];
  899. // }
  900. if (get_params('_from') == OrderPayDataForm::PAY_FROM_APP || is_alipay_platform()) {
  901. if ($index == 'alipay' && $value['value'] == 1) {
  902. $pay_type_list[] = [
  903. 'name' => '支付宝支付',
  904. 'payment' => 4,
  905. 'icon' => \Yii::$app->request->hostInfo . \Yii::$app->request->baseUrl . '/statics/images/recharge/icon-alipay.png'
  906. ];
  907. }
  908. }
  909. if ($index == 'balance' && $value['value'] == 1) {
  910. $pay_type_list[] = [
  911. 'name' => '账户余额支付',
  912. 'payment' => 3,
  913. 'icon' => \Yii::$app->request->hostInfo . \Yii::$app->request->baseUrl . '/v1/statics/wxapp/images/icon-payment-balance.png'
  914. ];
  915. }
  916. }
  917. if (!$pay_type_list) {
  918. if (is_wechat_platform()) {
  919. $pay_type_list[] = [
  920. 'name' => '微信支付',
  921. 'payment' => 1,
  922. 'icon' => \Yii::$app->request->hostInfo . \Yii::$app->request->baseUrl . '/v1/statics/images/recharge/icon-online.png'
  923. ];
  924. }
  925. if (is_toutiao_platform()) {
  926. $pay_type_list[] = [
  927. 'name' => '线上支付',
  928. 'payment' => 5,
  929. 'icon' => \Yii::$app->request->hostInfo . \Yii::$app->request->baseUrl . '/v1/statics/images/recharge/icon-online.png'
  930. ];
  931. }
  932. }
  933. return $pay_type_list;
  934. }
  935. protected function getLevelData()
  936. {
  937. $level = Level::find()->select([
  938. 'name', 'level', 'discount',
  939. ])->where(['level' => $this->user->level, 'store_id' => $this->store_id, 'is_delete' => 0])
  940. ->asArray()->one();
  941. return $level;
  942. }
  943. //积分计算
  944. /**
  945. * @param $goods_item object 重新编写的goods_item
  946. * @param $store_integral int 商城设置的积分规则
  947. * @param $goods_id array 已设置积分的商品id数组
  948. * @return array
  949. */
  950. protected function getIntegral($goods_item, $store_integral, $goods_id = array(), $send_integral_profit = 0)
  951. {
  952. $integral = json_decode($goods_item->integral, true);
  953. $resIntegral = [
  954. 'forehead' => 0,
  955. 'forehead_integral' => 0,
  956. ];
  957. // 赠送积分计算
  958. if ($integral) {
  959. // // 赠送积分计算
  960. $give = (int)$integral['give'];
  961. if (strpos($give, '%') !== false) {
  962. // 百分比
  963. $give = trim($give, '%');
  964. $goods_item->give = (int)(intval($goods_item->price) * ($give / 100));
  965. } else {
  966. // 固定积分
  967. $goods_item->give = (intval($give) * intval($goods_item->num));
  968. }
  969. if ($give <= 0 && $send_integral_profit > 0) {
  970. $goods_item->give = (int)(intval($goods_item->price) * ($send_integral_profit / 100));
  971. }
  972. // 抵扣积分计算
  973. $forehead = $integral['forehead'];
  974. if ($forehead) {
  975. if (strpos($forehead, '%') !== false) {//百分比积分抵扣计算
  976. if ($forehead >= 100) {
  977. $forehead = 100;
  978. }
  979. if ($integral['more'] == '1') {//多件累计计算
  980. $resIntegral['forehead_integral'] = (int)(($forehead / 100) * $goods_item->price * $store_integral);
  981. } else {
  982. if (!in_array($goods_item->id, $goods_id)) { //不允许多件累计 同id商品值计算一次积分抵扣
  983. $resIntegral['forehead_integral'] = (int)(($forehead / 100) * $goods_item->single_price * $store_integral);
  984. }
  985. }
  986. } else {
  987. // 累计
  988. $resIntegral['forehead_integral'] = bcmul($store_integral, $goods_item->price);
  989. if ($goods_item->price > ($forehead * $goods_item->num)) {
  990. $resIntegral['forehead_integral'] = (int)($forehead * $goods_item->num * $store_integral);
  991. }
  992. }
  993. }
  994. $user_integral = $this->user->integral;
  995. $user_integral = floor_num($user_integral, 0);
  996. if ($this->integral['forehead_integral'] < $user_integral) {
  997. $resetIntegral = $user_integral - $this->integral['forehead_integral'];
  998. $resIntegral['forehead_integral'] = $resIntegral['forehead_integral'] >= $resetIntegral ? $resetIntegral : $resIntegral['forehead_integral'];
  999. $resIntegral['forehead'] = $store_integral ? sprintf("%.2f", ($resIntegral['forehead_integral'] / $store_integral)) : 0;
  1000. $this->integral['forehead_integral'] += $resIntegral['forehead_integral'];
  1001. $this->integral['forehead'] += $resIntegral['forehead'];
  1002. } else {
  1003. $resIntegral['forehead_integral'] = 0;
  1004. $resIntegral['forehead'] = 0;
  1005. }
  1006. }
  1007. return [
  1008. 'resIntegral' => $resIntegral,
  1009. 'give' => $goods_item->give ?? ''
  1010. ];
  1011. }
  1012. protected function getExpressPrice($mch)
  1013. {
  1014. $expressPrice = 0;
  1015. if ($this->address) {
  1016. $address = $this->address;
  1017. //先计算单品满件包邮和满额包邮
  1018. $resGoodsList = Goods::cutFull($mch['goods_list']);
  1019. //再通过运费规则计算运费
  1020. $expressPrice = PostageRules::getExpressPriceMore($this->store_id, $address['city_id'], $resGoodsList, $address['province_id']);
  1021. }
  1022. $expressPrice = $this->getFreeDeliveryRules($mch, $expressPrice);
  1023. return $expressPrice >= 0 ? $expressPrice : 0;
  1024. }
  1025. // 获取门店列表
  1026. protected function getShopList()
  1027. {
  1028. $start = 0;
  1029. $shop_table_name = Shop::tableName();
  1030. $latitude = 0;
  1031. $longitude = 0;
  1032. if ($this->address && isset($this->address['id'])) {
  1033. $address = Address::findOne($this->address['id']);
  1034. if ($address) {
  1035. $latitude = $address->latitude ? $address->latitude : 0;
  1036. $longitude = $address->longitude ? $address->longitude : 0;
  1037. }
  1038. }
  1039. $sql = "SELECT *, acos(cos({$latitude}*pi()/180 )*cos(latitude*pi()/180)*cos({$longitude}*pi()/180 -longitude*pi()/180)+sin({$latitude}*pi()/180 )*sin(latitude*pi()/180))*6370996.81 as
  1040. distance FROM {$shop_table_name} WHERE ((`store_id`={$this->store_id}) AND (`is_delete`=0)) ";
  1041. if ($this->keyword) {
  1042. $sql .= " AND (`name` like '%{$this->keyword}%') ";
  1043. }
  1044. $sql .= "ORDER BY `distance` LIMIT {$start},30";
  1045. $list = \Yii::$app->db->createCommand($sql)->queryAll();
  1046. $shop = null;
  1047. foreach ($list as $index => $item) {
  1048. if ($item['is_default'] == 1) {
  1049. $shop = $item;
  1050. }
  1051. $list[$index]['distance'] = round($item['distance']/1000, 2).'km';
  1052. }
  1053. return [
  1054. 'list' => $list,
  1055. 'shop' => $shop
  1056. ];
  1057. }
  1058. protected function getTerritorialLimitation($mch)
  1059. {
  1060. $isArea = 0;
  1061. if ($mch['mch_id'] > 0) {
  1062. return $isArea;
  1063. }
  1064. if ($this->address) {
  1065. $area = TerritorialLimitation::findOne([
  1066. 'store_id' => $this->store_id,
  1067. 'is_delete' => 0,
  1068. 'is_enable' => 1,
  1069. ]);
  1070. if ($area) {
  1071. $city_id = []; //限制的地区ID
  1072. $detail = json_decode($area->detail);
  1073. if (!is_array($detail)) {
  1074. $detail = [];
  1075. }
  1076. foreach ($detail as $key => $value) {
  1077. foreach ($value->province_list as $key2 => $value2) {
  1078. $city_id[] = $value2->id;
  1079. }
  1080. }
  1081. $addressArr = [
  1082. $this->address['province_id'],
  1083. $this->address['city_id'],
  1084. $this->address['district_id']
  1085. ];
  1086. $addressArray = array_intersect($addressArr, $city_id);
  1087. if (empty($addressArray)) {
  1088. $isArea = 1;
  1089. }
  1090. }
  1091. }
  1092. return $isArea;
  1093. }
  1094. // 包邮规则
  1095. protected function getFreeDeliveryRules($mch, $expressPrice)
  1096. {
  1097. if ($expressPrice == 0) {
  1098. return $expressPrice;
  1099. }
  1100. if ($mch['mch_id'] == 0) {
  1101. $free = FreeDeliveryRules::find()->where(['store_id' => $this->store_id, 'is_delete' => 0, 'mch_id' => 0])->asArray()->all();
  1102. foreach ($free as $k => $v) {
  1103. $city = json_decode($v['city'], true);
  1104. foreach ($city as $v1) {
  1105. if ($this->address['district_id'] == $v1['id'] && $mch['total_price'] >= $v['price']) {
  1106. $expressPrice = 0;
  1107. break;
  1108. }
  1109. }
  1110. }
  1111. } else {
  1112. $free = FreeDeliveryRules::find()->where(['store_id' => $this->store_id, 'mch_id' => $mch['mch_id'], 'is_delete' => 0])->asArray()->all();
  1113. foreach ($free as $k => $v) {
  1114. $city = json_decode($v['city'], true);
  1115. foreach ($city as $v1) {
  1116. if ($this->address['district_id'] == $v1['id'] && $mch['total_price'] >= $v['price']) {
  1117. $expressPrice = 0;
  1118. break;
  1119. }
  1120. }
  1121. }
  1122. }
  1123. return $expressPrice;
  1124. }
  1125. // 获取用户填写的自定义表单
  1126. protected function getForm(&$form)
  1127. {
  1128. if ($form['is_form'] == 1) {
  1129. $formList = &$form['list'];
  1130. foreach ($formList as $index => $value) {
  1131. if ($value['required'] == 1) {
  1132. if (in_array($value['type'], ['radio', 'checkbox'])) {
  1133. $is_true = false;
  1134. foreach ($value['default_list'] as $k => $v) {
  1135. if ($v['checked'] == true) {
  1136. $is_true = true;
  1137. }
  1138. }
  1139. if (!$is_true) {
  1140. return [
  1141. 'code' => 1,
  1142. 'msg' => '请填写' . $form['name'] . ',加“*”为必填项',
  1143. 'name' => $value['name']
  1144. ];
  1145. }
  1146. } else {
  1147. if (empty($value['default']) && strlen($value['default']) == 0) {
  1148. return [
  1149. 'code' => 1,
  1150. 'msg' => '请填写' . $form['name'] . ',加“*”为必填项',
  1151. 'name' => $value['name']
  1152. ];
  1153. }
  1154. }
  1155. }
  1156. if ($value['type'] == 'checkbox') {
  1157. $formList[$index]['default'] = is_array($value['default']) ? implode(',', $value['default']) : $value['default'];
  1158. }
  1159. }
  1160. }
  1161. return $form;
  1162. }
  1163. protected function goodsCardList()
  1164. {
  1165. $list = [];
  1166. foreach ($this->mch_list as $mch) {
  1167. if($mch['mch_id'] == 0) {
  1168. foreach ($mch['goods_list'] as $goods) {
  1169. if (!empty($goods['goods_list'])) {
  1170. foreach ($goods['goods_list'] as $val) {
  1171. if(!$val['goods_card_list']) {
  1172. $val['goods_card_list'] = [];
  1173. }
  1174. $list = array_merge($list, $val['goods_card_list']);
  1175. }
  1176. }
  1177. }
  1178. }
  1179. }
  1180. return $list;
  1181. }
  1182. /**
  1183. * @param $goods
  1184. * @param $type
  1185. */
  1186. public function bookCheckGoodsNum($goods, $type) {
  1187. // 酒店预约
  1188. if ($type == 1) {
  1189. // $date_book = GoodsBook::findOne(['goods_id' => $goods['id']])->date_book;
  1190. // $date_book = Json::decode($date_book);
  1191. // if (!$date_book) {
  1192. // return [
  1193. // 'code' => 1,
  1194. // 'msg' => '数据异常'
  1195. // ];
  1196. // }
  1197. // $data_config = array_combine(array_column($date_book, 'date'), array_column($date_book, 'num'));
  1198. //
  1199. // foreach ($goods['book'] as $value) {
  1200. // if ($data_config[$value['date']] < $goods['num']) {
  1201. // return [
  1202. // 'code' => 1,
  1203. // 'msg' => '选中日期' . $value['date'] . '内暂无房源'
  1204. // ];
  1205. // }
  1206. // }
  1207. }
  1208. // 服务预约
  1209. if ($type == 2) {
  1210. $service_book = GoodsBook::findOne(['goods_id' => $goods['id']])->service_book;
  1211. $service_book = Json::decode($service_book);
  1212. if (!$service_book) {
  1213. return [
  1214. 'code' => 1,
  1215. 'msg' => '数据异常'
  1216. ];
  1217. }
  1218. $date_data = $this->getDateByInterval(7);
  1219. $count = 0;
  1220. $new_arr = [
  1221. 'data' => []
  1222. ];
  1223. $order = Order::find()->alias('o')
  1224. ->leftJoin(['od' => OrderDetail::tableName()], 'o.id = od.order_id')
  1225. ->where(['o.trade_status' => [0, 2, 3], 'o.is_delete' => 0, 'o.order_type' => 2, 'goods_id' => $goods['id']])
  1226. ->andWhere(['>', 'o.created_at', strtotime(date("Y-m-d"))])
  1227. ->select('od.attr, od.num')->asArray()->all();
  1228. foreach ($date_data as $index => $datum) {
  1229. $new_arr['data'][$index]['date'] = $datum;
  1230. $new_arr['data'][$index]['time'] = $service_book['data'][0]['time'];
  1231. }
  1232. if (!$new_arr) {
  1233. return [
  1234. 'code' => 1,
  1235. 'msg' => '数据异常'
  1236. ];
  1237. }
  1238. $service_book = $new_arr['data'];
  1239. $service_book_date = array_column($service_book, NULL, 'date');
  1240. $service_book_time = $service_book_date[$goods['service']['date']]['time'];
  1241. $num = 0;
  1242. $price = 0;
  1243. foreach ($order as $item) {
  1244. $item['attr'] = json_decode($item['attr'], true);
  1245. if ($item['attr']['date'] === $goods['service']['date']) {
  1246. if ($goods['service']['time'] === $item['attr']['time']) {
  1247. $num += $item['num'];
  1248. }
  1249. }
  1250. }
  1251. foreach ($service_book_time as $m) {
  1252. foreach ($m['times'] as $n) {
  1253. if ($n['time'] == $goods['service']['time']) {
  1254. if (($goods['num'] + $num) > $n['num']) {
  1255. return [
  1256. 'code' => 1,
  1257. 'msg' => $n['time'] . '时间段内暂不可预约'
  1258. ];
  1259. }
  1260. }
  1261. }
  1262. }
  1263. }
  1264. return [
  1265. 'code' => 0,
  1266. 'msg' => 'success',
  1267. 'data' => [
  1268. 'price' => $price
  1269. ]
  1270. ];
  1271. }
  1272. /**
  1273. * 计算初始价格
  1274. * @param $order_id
  1275. * @return array
  1276. */
  1277. public static function findPrice($order_id) {
  1278. $order_detail = OrderDetail::findAll(['order_id' => $order_id]);
  1279. $original_price = 0;
  1280. $md_price = 0;
  1281. foreach ($order_detail as $detail) {
  1282. $goods = Goods::findOne($detail['goods_id']);
  1283. if ($goods->use_attr > 0) {
  1284. $attrs = Json::decode($goods->attr);
  1285. // 当前选择的规格
  1286. $attrIdArr = [];
  1287. foreach (Json::decode($detail['attr']) as $attrListItem) {
  1288. $attrIdArr[] = $attrListItem['attr_id'];
  1289. }
  1290. foreach ($attrs as $attr) {
  1291. $attrIds = [];
  1292. foreach ($attr['attr_list'] as $item) {
  1293. $attrIds[] = $item['attr_id'];
  1294. }
  1295. sort($attrIds);
  1296. sort($attrIdArr);
  1297. // 找出当前规格信息
  1298. if (implode($attrIds) === implode($attrIdArr)) {
  1299. $original_price += $attr['price'];
  1300. }
  1301. }
  1302. } else {
  1303. $original_price += $goods->price;
  1304. }
  1305. }
  1306. foreach ($order_detail as $detail) {
  1307. $md_goods = MdGoods::findOne(['goods_id' => $detail['goods_id'], 'md_id' => get_md_id()]);
  1308. $goods = Goods::findOne($detail['goods_id']);
  1309. $goods_attr = $goods->attr;
  1310. if ($md_goods) {
  1311. $goods_attr = $md_goods->attr;
  1312. }
  1313. if ($goods->use_attr == 1) {
  1314. $attrs = Json::decode($goods_attr);
  1315. // 当前选择的规格
  1316. $attrIdArr = [];
  1317. foreach (Json::decode($detail['attr']) as $attrListItem) {
  1318. $attrIdArr[] = $attrListItem['attr_id'];
  1319. }
  1320. foreach ($attrs as $attr) {
  1321. $attrIds = [];
  1322. foreach ($attr['attr_list'] as $item) {
  1323. $attrIds[] = $item['attr_id'];
  1324. }
  1325. sort($attrIds);
  1326. sort($attrIdArr);
  1327. // 找出当前规格信息
  1328. if (implode($attrIds) === implode($attrIdArr)) {
  1329. $md_price += $attr['price'];
  1330. }
  1331. }
  1332. } else {
  1333. if ($md_goods) {
  1334. $md_price += $md_goods->price;
  1335. } else {
  1336. $md_price += $goods->price;
  1337. }
  1338. }
  1339. }
  1340. return [
  1341. 'original_price' => $original_price > 0 ? $original_price : $md_price,
  1342. 'md_price' => $md_price
  1343. ];
  1344. }
  1345. public function getDateByInterval(int $num) :array
  1346. {
  1347. //var_dump($st, $et);die;
  1348. $returnData = [];
  1349. $i = 0;
  1350. do {
  1351. $temp = date('Y-m-d', strtotime('+' . $i . ' day', strtotime(date('Y-m-d'))));
  1352. $returnData[] = $temp;
  1353. $i++;
  1354. } while ($i < $num);
  1355. return $returnData;
  1356. }
  1357. //判断是否需为代理配送且要上门安装
  1358. public function goodsIsInstall($goods_id) {
  1359. try {
  1360. $goods = Goods::findOne($goods_id);
  1361. $goods_url = "/goods/getAttrParams";
  1362. $param = [
  1363. 'id' => $goods->cloud_goods_id
  1364. ];
  1365. //请求接口
  1366. $domain = (new OptionSetting)->getCloudDomainName();
  1367. $goodsInfo = cloud_post($domain . $goods_url, $param);
  1368. $goodsInfo = json_decode($goodsInfo, true);
  1369. if ((int)$goodsInfo['code'] === 0) {
  1370. $goodsInfo = $goodsInfo['data'];
  1371. //需要安装
  1372. if ((int)$goodsInfo['send_type'] === 3 && (int)$goodsInfo['is_need_install'] === 1) {
  1373. return 1;
  1374. }
  1375. //不需要安装
  1376. if ((int)$goodsInfo['send_type'] === 3) {
  1377. return 3;
  1378. }
  1379. }
  1380. return 2;
  1381. } catch (\Exception $e) {
  1382. return 2;
  1383. }
  1384. }
  1385. //判断是否存在代理
  1386. public function goodsIsGoodsAgent($address, $goods_id) {
  1387. try {
  1388. if (empty($address) || !is_array($address)) {
  1389. throw new \Exception('缺少地址信息');
  1390. }
  1391. $goods = Goods::findOne(['id' => $goods_id, 'is_delete' => 0]);
  1392. if ((!empty($goods) && empty($goods->cloud_goods_id) || empty($goods) )) {
  1393. return [
  1394. 'code' => 0,
  1395. 'msg' => '非云仓商品'
  1396. ];
  1397. }
  1398. $goods_agent_admin = AgentGoodsBindGoods::find()->where(['cloud_goods_id' => $goods->cloud_goods_id, 'status' => 1, 'is_delete' => 0])
  1399. ->select('goods_agent_admin_id')->column();
  1400. $where = [
  1401. 'province_id' => $address['province_id'],
  1402. 'type' => 'goods_agent',
  1403. 'is_delete' => 0,
  1404. 'id' => $goods_agent_admin
  1405. ];
  1406. $admin = Admin::findOne(array_merge(
  1407. [
  1408. 'area_level' => 1,
  1409. 'city_id' => $address['city_id'],
  1410. 'district_id' => $address['district_id'],
  1411. ], $where));
  1412. if (!empty($admin)) {
  1413. return [
  1414. 'code' => 0,
  1415. 'msg' => 'success',
  1416. 'data' => $admin
  1417. ];
  1418. }
  1419. $admin = Admin::findOne(array_merge(
  1420. [
  1421. 'area_level' => 2,
  1422. 'city_id' => $address['city_id'],
  1423. ], $where));
  1424. if (!empty($admin)) {
  1425. return [
  1426. 'code' => 0,
  1427. 'msg' => 'success',
  1428. 'data' => $admin
  1429. ];
  1430. }
  1431. $admin = Admin::findOne(array_merge(
  1432. [
  1433. 'area_level' => 3,
  1434. ], $where));
  1435. if (!empty($admin)) {
  1436. return [
  1437. 'code' => 0,
  1438. 'msg' => 'success',
  1439. 'data' => $admin
  1440. ];
  1441. }
  1442. return [
  1443. 'code' => 1,
  1444. 'msg' => '该区域未存在产品代理,无法下单'
  1445. ];
  1446. } catch (\Exception $e) {
  1447. return [
  1448. 'code' => 1,
  1449. 'msg' => $e->getMessage()
  1450. ];
  1451. }
  1452. }
  1453. // 检测拼团信息
  1454. public function checkPtActivity($pt_number)
  1455. {
  1456. $pt_order = PtActivityOrder::findOne(['id' => $pt_number]);
  1457. if ($pt_order) {
  1458. if ((int)$pt_order->is_pay === 0) {
  1459. return [
  1460. 'code' => 1,
  1461. 'msg' => "当前团暂未开放"
  1462. ];
  1463. }
  1464. //error
  1465. $check_pt_order = PtActivityOrder::find()->where(['trade_status' => 0, 'is_pay' => 1])
  1466. ->andWhere(['OR', ['id' => $pt_number], ['pt_number' => $pt_number]])
  1467. ->select('id')->column();
  1468. $pt_activity = PtActivity::findOne($this->pt_activity_id);
  1469. if (!$this->pt_activity_id) {
  1470. return [
  1471. 'code' => 1,
  1472. 'msg' => "活动信息不存在或已结束"
  1473. ];
  1474. }
  1475. if($pt_activity->party_type == 0){
  1476. if ($pt_activity->party_size <= (count($check_pt_order))) {
  1477. return [
  1478. 'code' => 1,
  1479. 'msg' => "当前团已达上限"
  1480. ];
  1481. }
  1482. }
  1483. if($pt_activity->party_type == 1){
  1484. $goodsCountQuery = PtActivityOrderDetail::find()->alias('pod')
  1485. ->leftJoin(['po' => PtActivityOrder::tableName()], 'pod.order_id = po.id')
  1486. ->where(['po.is_pay' => 1, 'pod.is_delete' => 0])
  1487. ->andWhere(['OR' , ['po.id' => $pt_number], ['po.pt_number' => $pt_number]]);
  1488. $goodsCount = $goodsCountQuery->sum('pod.num');
  1489. if($pt_activity->party_goods_count <= (int)$goodsCount){
  1490. return [
  1491. 'code' => 1,
  1492. 'msg' => "当前团商品数量已达上限"
  1493. ];
  1494. }
  1495. }
  1496. }
  1497. return ['code' => 0, 'msg' => ''];
  1498. }
  1499. }