PtStoreActivityForm.php 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563
  1. <?php
  2. namespace app\modules\alliance\models\storeActivity;
  3. use app\constants\OptionSetting;
  4. use app\models\ActivityCutPriceGoods;
  5. use app\models\ActivityCutPriceOrder;
  6. use app\models\ActivityNewUserGoods;
  7. use app\models\Coupon;
  8. use app\models\CouponAutoSend;
  9. use app\models\District;
  10. use app\models\Option;
  11. use app\models\Order;
  12. use app\models\OrderDetail;
  13. use app\models\PtActivity;
  14. use app\models\PtActivityGoods;
  15. use app\models\SaasUser;
  16. use app\models\SeckillActivityGoods;
  17. use app\models\Store;
  18. use app\models\User;
  19. use app\models\UserCoupon;
  20. use app\models\WechatConfig;
  21. use yii\base\Model;
  22. class PtStoreActivityForm extends Model
  23. {
  24. public $table_model;
  25. public $goods_model;
  26. public $price_type;
  27. public $store_name;
  28. public $distance;
  29. public $district_id;
  30. public $min_price;
  31. public $max_price;
  32. public $min_sale_num;
  33. public $max_sale_num;
  34. public $sort;
  35. public $latitude;
  36. public $longitude;
  37. public $model_type;
  38. public $saas_user_id;
  39. public $page;
  40. public $pageSize;
  41. public $store_id;
  42. public function rules()
  43. {
  44. return [
  45. [['distance', 'store_name'], 'string'],
  46. [['district_id', 'sort', 'model_type', 'saas_user_id', 'store_id'], 'integer'],
  47. [['min_sale_num', 'max_sale_num', 'min_price', 'max_price', 'latitude', 'longitude', 'page', 'pageSize'], 'number'],
  48. ];
  49. }
  50. public function activityGoodsList() {
  51. try {
  52. $price_type = $this->price_type;
  53. $model_type = $this->model_type;
  54. $distance_ = 0;
  55. $distance = $this->distance;
  56. $district_id = $this->district_id;
  57. //查询有活动的店铺
  58. $latitude = $this->latitude;
  59. $longitude = $this->longitude;
  60. $min_price = $this->min_price;
  61. $max_price = $this->max_price;
  62. $min_sale_num = $this->min_sale_num;
  63. $max_sale_num = $this->max_sale_num;
  64. $sort = (int)$this->sort;
  65. $store_name = $this->store_name;
  66. $page = $this->page ?: 1;
  67. $pageSize = $this->pageSize ?: 10;
  68. //判断附近
  69. if (strpos($distance, 'km') !== false) {
  70. //1-5km
  71. $km = strpos($distance, 'km');
  72. $distance_ = substr($distance, 0, $km);
  73. $distance_ = $distance_ * 1000;
  74. } else {
  75. if (strpos($distance, 'm') !== false) {
  76. //500m
  77. $km = strpos($distance, 'm');
  78. $distance_ = substr($distance, 0, $km);
  79. }
  80. }
  81. $sql = $this->getSql($latitude, $longitude);
  82. //判断距离
  83. if ($distance_ > 0) {
  84. $sql .= " AND s_.distance < {$distance_}";
  85. } else {
  86. if ($district_id) {
  87. $sql .= " AND s.district_id = {$district_id}";
  88. }
  89. }
  90. //只有平台运营的商城或者单店铺的无独立小程序才展示商盟的营销活动
  91. if (\Yii::$app->prod_is_dandianpu()) {
  92. $store_id = Option::find()->where(['group' => 'store', 'name' => 'self_mini'])->select('store_id')->column();
  93. $store_id = implode(',', $store_id);
  94. $sql .= " AND s.id NOT IN ({$store_id})";
  95. } else {
  96. $sql .= " AND s.business_model = 2";
  97. }
  98. if ($store_name) {
  99. $sql .= " AND s.name LIKE '%{$store_name}%' ";
  100. }
  101. // $sql .= " GROUP BY s.id " ;
  102. $total_count = \Yii::$app->db->createCommand($sql . " GROUP BY s.id ")->query()->count();
  103. if (in_array($sort, [0, 1])) {
  104. $sql .= " ORDER BY s_.distance ASC";
  105. }
  106. $array = \Yii::$app->db->createCommand($sql)->queryAll();
  107. // $sql .= " LIMIT " . $pageSize . " OFFSET " . ($page - 1) * $pageSize ;
  108. $store_id = array_column($array, 'store_id');
  109. array_push($store_id, 0);
  110. $store_id = array_unique($store_id);
  111. $activity_goods_id = array_column($array, 'id');
  112. $field_ = "";
  113. switch (intval($model_type)) {
  114. case 1:
  115. $field_ = ", ag.sale_num";
  116. break;
  117. case 2:
  118. $field_ = ", a.coupon_ids, g.goods_num, a.buy_limit";
  119. break;
  120. case 3:
  121. $field_ = ", ag.seckill_num, ag.virtual_sales, ag.sale_num";
  122. break;
  123. default:
  124. $field_ = ", a.party_size, ag.sale_num, ag.virtual_sales";
  125. break;
  126. }
  127. $field = 'g.id, a.id activity_id, ag.id activity_goods_id, a.start_time, a.end_time, ag.attr, g.name, g.cover_pic, s.id store_id, s.name store_name, s.logo, s.province_id, s.city_id, s.district_id, s.address, s.business_model, s_.distance' . $field_;
  128. $sql = $this->getSql($latitude, $longitude, $field);
  129. //筛选价格销量
  130. $a_goods_id = [];
  131. $this->getGoodsId($min_price, $max_price, $min_sale_num, $max_sale_num, $activity_goods_id, $model_type, $price_type,$a_goods_id);
  132. //价格 销量筛选
  133. if ($a_goods_id) {
  134. $a_goods_id = implode(',', $a_goods_id);
  135. $sql .= " AND ag.id in ({$a_goods_id})";
  136. }
  137. //距离筛选
  138. $store_id = implode(',', $store_id);
  139. $sql .= " AND s.id in ({$store_id})";
  140. // $sql .= " GROUP BY ag.id";
  141. //距离排序
  142. switch ($sort) {
  143. case 1://距离优先
  144. $sql .= " ORDER BY s_.distance ASC";
  145. break;
  146. case 2://好评优先
  147. $sql .= " ORDER BY s.rank DESC";
  148. break;
  149. case 3://销量优先
  150. if (intval($model_type) !== 2) {
  151. $sql .= " ORDER BY ag.sale_num DESC";
  152. }
  153. break;
  154. default:
  155. $sql .= " ORDER BY s_.distance ASC";
  156. break;
  157. }
  158. $list = \Yii::$app->db->createCommand($sql)->queryAll();
  159. foreach ($list as &$item) {
  160. $item['distance'] = $this->distance($item['distance']);
  161. //获取最低活动价格的规格,填充单价和单卖价格
  162. $attr = json_decode($item['attr'], true);
  163. $max_price_arr = array_column($attr, $price_type);
  164. $current_attr = [
  165. $price_type => max($max_price_arr)
  166. ];
  167. foreach ($attr as $attr_item) {
  168. if ($attr_item[$price_type] <= $current_attr[$price_type]) {
  169. $current_attr = $attr_item;
  170. }
  171. }
  172. $item['activity_price'] = $current_attr[$price_type];
  173. if (in_array($model_type, [1, 2])) {
  174. //砍价 新人原价处理
  175. $item['price'] = $current_attr['oldPrice'];
  176. } else {
  177. $item['price'] = $current_attr['price'];
  178. }
  179. //拼接商城地址信息
  180. $province = '';
  181. if ($item['province_id']) {
  182. $province = District::findOne($item['province_id'])->name ?: '';
  183. }
  184. $city = '';
  185. if ($item['city_id']) {
  186. $city = District::findOne($item['city_id'])->name ?: '';
  187. }
  188. $district = '';
  189. if ($item['district_id']) {
  190. $district = District::findOne($item['district_id'])->name ?: '';
  191. }
  192. $item['address'] = $province . $city . $district . $item['address'];
  193. //获取商城logo
  194. $item['logo'] = $item['logo'] ?: Option::get(OptionSetting::STORE_LOGO, $item['store_id'], 'store', '')['value'];
  195. if (empty($item['logo'])) {
  196. $item['logo'] = Option::get('web_log', $item['store_id'], 'web', '')['value'];
  197. }
  198. //获取秒杀信息(进度条)
  199. if (isset($item['seckill_num']) && isset($item['virtual_sales'])&& isset($item['sale_num'])) {
  200. if (((int)$item['seckill_num'] + $item['virtual_sales']) === 0 || ((int)$item['sale_num'] + $item['virtual_sales']) === 0) {
  201. $item['progress'] = 0;
  202. } else {
  203. $item['progress'] = sprintf('%.2f', (($item['sale_num'] * 1) / ($item['seckill_num'] + $item['sale_num'])) * 100);
  204. $item['seckill_num'] <= 0 && $item['progress'] = 100;
  205. if ($item['start_time'] > time()) {
  206. $item['progress'] = 0;
  207. $item['virtual_sales'] = 0;
  208. }
  209. }
  210. }
  211. //砍价信息获取
  212. if (intval($model_type) === 1) {
  213. //参与人数
  214. $userCount = ActivityCutPriceOrder::find()->where(
  215. [
  216. "AND",
  217. [
  218. 'activity_id' => $item['activity_id'],
  219. 'is_delete' => 0,
  220. 'activity_goods_id' => $item['activity_goods_id']
  221. ], ['AND',
  222. [
  223. 'used_order_id' => 0
  224. ],[
  225. '>', 'end_time', time()
  226. ]
  227. ]
  228. ]
  229. )->groupBy(['saas_id'])->count();
  230. $item['sale_num'] = $userCount;
  231. //是否正在参与
  232. $user_join_activity = ActivityCutPriceOrder::find()->where(['AND',
  233. [
  234. 'activity_id' => $item['activity_id'],
  235. 'activity_goods_id' => $item['activity_goods_id'],
  236. 'is_delete' => 0,
  237. 'saas_id' => $this->saas_user_id
  238. ], [
  239. 'AND',
  240. [
  241. 'used_order_id' => 0
  242. ],[
  243. '>', 'end_time', time()
  244. ]
  245. ]
  246. ])->asArray()->one();//支付时间 < 活动截止时间
  247. $item['user_join'] = 0;
  248. if ($user_join_activity) {
  249. $item['user_join'] = 1;
  250. //如果正在参与将price改为已砍价格
  251. $item['price'] = $user_join_activity['pay_price'];
  252. }
  253. }
  254. //新人专享
  255. if (intval($model_type) === 2) {
  256. $item['sale_num'] = OrderDetail::find()->alias('od')->leftJoin(['o' => Order::tableName()], 'o.id = od.order_id')
  257. ->where(['od.goods_id' => $item['id'], 'o.is_pay' => 1])->select('od.num')->sum('od.num') ?: 0;
  258. }
  259. //新人专享
  260. if (intval($model_type) === 0) {
  261. $item['sale_num'] += $item['virtual_sales'];
  262. }
  263. unset($item['attr'], $item['virtual_sales']);
  264. }
  265. $list = array_values($list);
  266. $store_id_arr = array_column($list, 'store_id');
  267. $store_id_arr = array_unique($store_id_arr);
  268. $list = $this->handleData($store_id_arr, $list);
  269. return [
  270. 'code' => 0,
  271. 'msg' => '获取成功',
  272. 'data' => [
  273. 'list' => $list,
  274. 'page' => $page,
  275. 'totalCount' => $total_count
  276. ]
  277. ];
  278. } catch (\Exception $e) {
  279. return [
  280. 'code' => 0,
  281. 'msg' => $e->getMessage()
  282. ];
  283. }
  284. }
  285. public function handleData($store_id_arr, $list) {
  286. $data = [];
  287. foreach ($store_id_arr as $store_item) {
  288. foreach ($list as $item_) {
  289. if ($store_item === $item_['store_id']) {
  290. $data[$store_item]['coupon_ids'] = '0,';
  291. if (!empty($item_['coupon_ids'])) {
  292. $data[$store_item]['coupon_ids'] .= $item_['coupon_ids'] . ',';
  293. }
  294. if (!$data[$store_item]['store']) {
  295. $data[$store_item]['store'] = [
  296. 'store_name' => $item_['store_name'],
  297. 'logo' => $item_['logo'],
  298. 'address' => $item_['address'],
  299. 'distance' => $item_['distance'],
  300. 'business_model' => (int)$item_['business_model'],
  301. 'id' => $item_['store_id'],
  302. 'wechat_app_id' => '',
  303. 'gh_wechat_app_id' => '',
  304. 'alipay_app_id' => ''
  305. ];
  306. $wechatInfo = WechatConfig::find()->where(['store_id' => $item_['store_id'], 'is_delete'=>0, 'type'=>1])->asArray()->one();
  307. if($wechatInfo){
  308. $data[$store_item]['store']['wechat_app_id'] = $wechatInfo['app_id'];
  309. $data[$store_item]['store']['gh_wechat_app_id'] = $wechatInfo['gh_wechat_app_id'];
  310. }
  311. $alipayInfo = Option::get('alipay_config', $item_['store_id'], 'alipay');
  312. if($alipayInfo && $alipayInfo['value']){
  313. $alipayInfo = json_decode($alipayInfo['value'], true);
  314. $data[$store_item]['store']['alipay_app_id'] = $alipayInfo['app_id'];
  315. }
  316. }
  317. $data[$store_item]['goods_list'][] = $item_;
  318. }
  319. }
  320. //新人专享优惠券
  321. if (intval($this->model_type) === 2) {
  322. // $coupon_ids = explode(',', $coupon_ids);
  323. // $coupon_ids = array_unique($coupon_ids);
  324. // $coupon = Coupon::find()->alias('c')->leftJoin([
  325. // 'cu' => UserCoupon::tableName()
  326. // ], 'c.id = cu.coupon_id')
  327. // ->where(['c.id' => $coupon_ids, 'c.is_delete' => 0])
  328. // ->andWhere(['OR', ['cu.is_use' => 0], ['IS', 'cu.id', NULL]])
  329. // ->select('c.id, c.name, c.discount_type, c.min_price, c.sub_price, c.discount, c.total_count')->asArray()->all();
  330. // foreach ($coupon as $coupon_index => &$coupon_item) {
  331. // $coupon_item['discount_type'] = intval($coupon_item['discount_type']);
  332. // $coupon_item['is_use'] = 0;
  333. // $saas_user = SaasUser::findOne($this->saas_user_id);
  334. // if ($saas_user) {
  335. // $user = User::findOne(['binding' => $saas_user->mobile, 'store_id' => $store_item]);
  336. // if ($user) {
  337. // $user_coupon = UserCoupon::findOne(['coupon_id' => $coupon_item['id'], 'user_id' => $user->id, 'is_delete' => 0]);
  338. // if ($user_coupon) {
  339. // $coupon_item['is_use'] = 1;
  340. // }
  341. // }
  342. // }
  343. //
  344. //
  345. // $coupon_count = UserCoupon::find()->where(['store_id' => $store_item, 'is_delete' => 0,
  346. // 'coupon_id' => $coupon_item['id']])->andWhere(['!=', 'type', 3])->count();
  347. // if ($coupon_item['total_count'] != -1 && $coupon_item['total_count'] <= $coupon_count) {
  348. // unset($coupon[$coupon_index]);
  349. // }
  350. // }
  351. // $coupon = array_values($coupon);
  352. // $data[$store_item]['coupon'] = $coupon;
  353. $data[$store_item]['coupon'] = [];
  354. $coupons = explode(',', $data[$store_item]['coupon_ids']);
  355. if($coupons){
  356. $coupon_list = Coupon::find()->where(['in', 'id', $coupons])->andWhere(['is_delete' => 0])->asArray()->all();
  357. $auto_sends = CouponAutoSend::find()->where(['store_id' => $store_item, 'is_delete' => 0, 'status' => 1])->asArray()->all();
  358. if($auto_sends){
  359. foreach($coupon_list as $index => &$item){
  360. $item['auto_send'] = [];
  361. foreach ($auto_sends as $k){
  362. $cids = json_decode($k['coupon_id'], true);
  363. if(in_array($item['id'], $cids)){
  364. unset($coupon_list[$index]);
  365. }
  366. }
  367. }
  368. $coupon_list = array_values($coupon_list);
  369. }
  370. $saas_user = SaasUser::findOne($this->saas_user_id);
  371. if ($saas_user) {
  372. $user = User::findOne(['binding' => $saas_user->mobile, 'store_id' => $store_item, 'is_delete' => 0]);
  373. if($user){
  374. $user_coupons = UserCoupon::find()->where(['store_id' => $store_item, 'user_id' => $user->id])->asArray()->all();
  375. foreach($coupon_list as $coupon_index => &$item){
  376. foreach ($user_coupons as $k) {
  377. if($item['id'] == $k['coupon_id']){
  378. unset($coupon_list[$coupon_index]);
  379. }
  380. }
  381. }
  382. $coupon_list = array_values($coupon_list);
  383. }
  384. }
  385. $data[$store_item]['coupon'] = $coupon_list;
  386. }
  387. }
  388. unset($data[$store_item]['coupon_ids']);
  389. }
  390. return array_values($data);
  391. }
  392. public function getGoodsId($min_price, $max_price, $min_sale_num, $max_sale_num, $activity_goods_id, $model_type, $price_type, &$a_goods_id = []) {
  393. switch (intval($model_type)) {
  394. case 1:
  395. $ptActivityGoods = ActivityCutPriceGoods::find()->where(['id' => $activity_goods_id])->asArray()->all();
  396. break;
  397. case 2:
  398. $ptActivityGoods = ActivityNewUserGoods::find()->where(['id' => $activity_goods_id])->asArray()->all();
  399. break;
  400. case 3:
  401. $ptActivityGoods = SeckillActivityGoods::find()->where(['id' => $activity_goods_id])->asArray()->all();
  402. break;
  403. default:
  404. $ptActivityGoods = PtActivityGoods::find()->where(['id' => $activity_goods_id])->asArray()->all();
  405. break;
  406. }
  407. foreach ($ptActivityGoods as &$goods_item) {
  408. $open = false;
  409. $attr = json_decode($goods_item['attr'], true);
  410. foreach ($attr as $attr_item) {
  411. if ($min_price && $max_price) {
  412. array_push($a_goods_id, 0);
  413. if ($attr_item[$price_type] >= $min_price && $attr_item[$price_type] <= $max_price) {
  414. $open = true;
  415. }
  416. }
  417. }
  418. $num_open = false;
  419. if ($min_sale_num && $max_sale_num) {
  420. array_push($a_goods_id, 0);
  421. //单独处理新人专享
  422. if (intval($model_type) === 2) {
  423. $goods_item['sale_num'] = OrderDetail::find()->alias('od')->leftJoin(['o' => Order::tableName()], 'o.id = od.order_id')
  424. ->where(['od.goods_id' => $goods_item['goods_id'], 'o.is_pay' => 1])->select('od.num')->sum('od.num') ?: 0;
  425. }
  426. if ($goods_item['sale_num'] >= $min_sale_num && $goods_item['sale_num'] <= $max_sale_num) {
  427. $num_open = true;
  428. }
  429. }
  430. if ($min_price && $max_price && $min_sale_num && $max_sale_num) {
  431. if ($num_open && $open) {
  432. array_push($a_goods_id, $goods_item['id']);
  433. }
  434. } else {
  435. if ($num_open || $open) {
  436. array_push($a_goods_id, $goods_item['id']);
  437. }
  438. }
  439. }
  440. }
  441. public function getSql($latitude, $longitude, $field = 's.id store_id, ag.id') {
  442. $table_model = $this->table_model;
  443. $goods_model = $this->goods_model;
  444. $store_id = $this->store_id;
  445. $latitude = $latitude ?: 1;
  446. $longitude = $longitude ?: 1;
  447. $time = time();
  448. $sql = "SELECT
  449. {$field}
  450. FROM
  451. {$goods_model} `ag`
  452. LEFT JOIN {$table_model} `a` ON a.id = ag.activity_id
  453. LEFT JOIN `cyy_goods` `g` ON g.id = ag.goods_id
  454. LEFT JOIN `cyy_store` `s` ON s.id = a.store_id
  455. LEFT JOIN (select id, 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
  456. distance from cyy_store) as s_ ON s_.id = s.id
  457. WHERE
  458. ( `a`.`is_delete` = 0 )
  459. AND ( `ag`.`is_delete` = 0 )
  460. AND ( `g`.`is_delete` = 0 )
  461. AND ( `s`.`is_delete` = 0 )
  462. AND (`a`.`start_time` <= {$time} AND `a`.`end_time` > {$time})";//
  463. if ($store_id > 0) {
  464. $sql .= " AND ( `a`.`is_platform` = 0 AND `a`.`store_id` = {$store_id})";
  465. } else {
  466. $sql .= " AND ( `a`.`status` = 1 )
  467. AND ( `g`.`status` = 1 )
  468. AND ( `a`.`is_platform` = 1 )
  469. AND (`a`.`is_platform_audit` = 1) ";
  470. }
  471. return $sql;
  472. }
  473. public function distance($distance)
  474. {
  475. if ($distance == -1) {
  476. return -1;
  477. }
  478. if ($distance > 1000) {
  479. $distance = round($distance / 1000, 2) . 'km';
  480. } else {
  481. $distance = round($distance, 2);
  482. $distance .= 'm';
  483. }
  484. return $distance;
  485. }
  486. }