GoodsForm.php 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698
  1. <?php
  2. /**
  3. * 重庆赤晓店信息科技有限公司
  4. * https://www.chixiaodian.com
  5. * Copyright (c) 2023 赤店商城 All rights reserved.
  6. */
  7. namespace app\modules\alliance\models;
  8. use app\constants\OptionSetting;
  9. use app\models\AboutArticle;
  10. use app\models\ActivityCutPriceGoods;
  11. use app\models\ActivityNewUser;
  12. use app\models\ActivityNewUserGoods;
  13. use app\models\Address;
  14. use app\models\Goods;
  15. use app\models\GoodsPic;
  16. use app\models\GoodsBook;
  17. use app\models\PtActivity;
  18. use app\models\PtActivityGoods;
  19. use app\models\PtActivityOrder;
  20. use app\models\PtActivityOrderDetail;
  21. use app\models\SaasUser;
  22. use app\models\SeckillActivity;
  23. use app\models\SeckillActivityGoods;
  24. use app\models\Store;
  25. use app\models\User;
  26. use app\models\WechatConfig;
  27. use app\models\PostageRules;
  28. use app\models\TerritorialLimitation;
  29. use app\utils\Tools;
  30. use yii\base\Model;
  31. use yii\helpers\Json;
  32. use app\models\Option;
  33. use app\models\GoodsFullMinus;
  34. use app\modules\client\models\v1\diy\GetInfo;
  35. use app\modules\client\models\v1\common\CommonGoods;
  36. class GoodsForm extends Model
  37. {
  38. public $id;
  39. public $user_id;
  40. public $store_id;
  41. public $mch_id;
  42. public $shop_id;
  43. public $address_id;
  44. public $verify_card_id;
  45. public $activity_new_user_id = 0;
  46. public $activity_cut_price_id = 0;
  47. public $is_pt;
  48. public $is_seckill;
  49. public function rules()
  50. {
  51. return [
  52. [['id'], 'required'],
  53. [['mch_id', 'shop_id', 'address_id'], 'integer'],
  54. [['user_id', 'activity_new_user_id', 'activity_cut_price_id', 'is_pt', 'is_seckill'], 'safe'],
  55. ];
  56. }
  57. /**
  58. * 排序类型$sort 1--综合排序 2--销量排序
  59. */
  60. public function search()
  61. {
  62. if (!$this->validate()) {
  63. return $this->getErrorSummary(false)[0];
  64. }
  65. $goods = Goods::findOne([
  66. 'id' => $this->id,
  67. 'is_delete' => 0,
  68. 'status' => 1
  69. ]);
  70. if (!empty($goods->verify_card_id)) {
  71. $ids = explode(',', $goods->verify_card_id);
  72. $verify_card = Tools::getVerifyList($ids);
  73. } else {
  74. $verify_card = [];
  75. }
  76. if (!$goods) {
  77. return [
  78. 'code' => 1,
  79. 'msg' => '商品已下架'
  80. ];
  81. }
  82. $mch = null;
  83. $pic_list = GoodsPic::find()->select('pic_url')->where(['goods_id' => $goods->id, 'is_delete' => 0])->asArray()->all();
  84. $is_favorite = 0;
  85. $service_list = explode(',', $goods->service);
  86. // 默认商品服务
  87. if (!$goods->service) {
  88. $option = Option::get('good_services', $goods->store_id, 'admin', []);
  89. foreach ($option as $item) {
  90. if (!empty($item['is_default'])) {
  91. $service_list = explode(',', $item['service']);
  92. break;
  93. }
  94. }
  95. }
  96. $new_service_list = [];
  97. if (is_array($service_list)) {
  98. foreach ($service_list as $item) {
  99. $item = trim($item);
  100. if ($item) {
  101. $new_service_list[] = $item;
  102. }
  103. }
  104. }
  105. //展示新人专享活动商品信息
  106. $this->activity_new_user($this->activity_new_user_id, $goods, $md_goods);
  107. //展示砍价活动商品信息
  108. $cutGoods = null;
  109. if($this->activity_cut_price_id){
  110. $cutGoods = ActivityCutPriceGoods::findOne(['activity_id' => $this->activity_cut_price_id, 'goods_id' => $goods->id, 'is_delete' => 0]);
  111. }
  112. $new_price = $goods->price;
  113. $price_attr = Json::decode($goods->attr);
  114. $price = [];
  115. if (is_array($price_attr)) {
  116. foreach ($price_attr as $v) {
  117. if (is_object($v) && $v->price > 0) {
  118. $price[] = $v->price;
  119. } else {
  120. $price[] = floatval($new_price);
  121. }
  122. }
  123. } else {
  124. $price = [$goods->price];
  125. }
  126. $res_url = GetInfo::getVideoInfo($goods->video_url);
  127. $goods->video_url = $res_url['url'];
  128. if ($goods->is_negotiable) {
  129. $min_price = Goods::GOODS_NEGOTIABLE;
  130. } else {
  131. $min_price = sprintf('%.2f', min($price));
  132. }
  133. $res = CommonGoods::getMMPrice([
  134. 'attr' => $goods->attr,
  135. 'attr_setting_type' => $goods->attr_setting_type,
  136. 'share_type' => $goods->share_type,
  137. 'share_commission_first' => $goods->share_commission_first,
  138. 'price' => $new_price,
  139. 'individual_share' => $goods->individual_share,
  140. 'mch_id' => $goods->mch_id,
  141. 'is_level' => $goods->is_level,
  142. 'use_attr' => $goods->use_attr,
  143. ]);
  144. $attr = $price_attr;
  145. $goodsPrice = $new_price;
  146. $isMemberPrice = false;
  147. if ($res['user_is_member'] === true && count($attr) === 1 && $attr[0]['attr_list'][0]['attr_name'] == '默认') {
  148. $goodsPrice = $res['min_member_price'] ? $res['min_member_price'] : $new_price;
  149. $isMemberPrice = true;
  150. }
  151. $GoodsFullMinus = GoodsFullMinus::find()
  152. ->select('*')
  153. ->where(['store_id' => $goods->store_id, 'goods_id' => $goods->id])
  154. ->orderBy('full_minus_num ASC')->asArray()->all();
  155. $seckill_activity_arr = null;
  156. $seckill_activity_goods = [];
  157. if ($this->is_seckill) {
  158. //秒杀活动
  159. $seckill_activity_goods = SeckillActivityGoods::find()->alias('sag')->where(['sag.goods_id' => $goods->id])
  160. ->leftJoin(['sa' => SeckillActivity::tableName()], 'sag.activity_id = sa.id')
  161. ->andWhere(['AND', ['sa.is_delete' => 0, 'sag.is_delete' => 0], ['>', 'sa.end_time', time()]])
  162. ->andWhere(['OR', ['sa.is_platform' => 1, 'sa.is_platform_audit' => 1, 'sa.status' => 1], ['sa.is_platform' => 0]])
  163. ->select('sa.id, sa.self_limit_num, sa.order_limit_num, sa.start_time, sa.end_time, sag.attr, sag.seckill_num, sag.seckill_price, sag.use_attr, sag.sale_num, sag.virtual_sales, sag.virtual_num')->asArray()->all();
  164. }
  165. if (!empty($seckill_activity_goods) && empty($this->activity_new_user_id) && empty($this->activity_cut_price_id) && empty($this->is_pt)) {
  166. $last_names = array_column($seckill_activity_goods,'start_time');
  167. array_multisort($last_names, SORT_ASC, $seckill_activity_goods);
  168. foreach ($seckill_activity_goods as $activity_good) {
  169. if (($activity_good['seckill_num'] + $activity_good['sale_num'] + $activity_good['virtual_sales']) > 0) {
  170. $activity_good['progress'] = sprintf('%.2f', (($activity_good['sale_num'] + $activity_good['virtual_sales']) / ($activity_good['seckill_num'] + $activity_good['sale_num'] + $activity_good['virtual_sales'])) * 100);
  171. } else {
  172. $activity_good['progress'] = 0;
  173. }
  174. $activity_good['seckill_num'] <= 0 && $activity_good['progress'] = 100;
  175. $activity_good['price'] = $new_price;
  176. $activity_good['seckill_price'] = sprintf('%.2f', $activity_good['seckill_price']);
  177. if ($activity_good['start_time'] < time()) { //活动进行中 前端展示距离结束
  178. $activity_good['status'] = 1;
  179. $seckill_activity_arr = $activity_good;
  180. goto seckill_activity_arr;
  181. }
  182. if ($activity_good['start_time'] >= time()) {//活动进行中 前端展示距离开始
  183. $activity_good['status'] = 2;
  184. $activity_good['progress'] = 0;
  185. $seckill_activity_arr = $activity_good;
  186. goto seckill_activity_arr;
  187. }
  188. }
  189. seckill_activity_arr:
  190. }
  191. if (!empty($seckill_activity_arr)) {
  192. $seckill_activity_arr['attr'] = json_decode($seckill_activity_arr['attr'], true);
  193. if (!empty($seckill_activity_arr['attr'])) {
  194. foreach ($seckill_activity_arr['attr'] as &$activity_attr) {
  195. $activity_attr['seckill_price'] = sprintf('%.2f', $activity_attr['seckill_price']);
  196. }
  197. }
  198. }
  199. //拼团活动信息
  200. $ptGoodsActivity = PtActivityGoods::find()->alias('pag')->where(['pag.is_delete' => 0, 'pa.is_delete' => 0, 'pa.store_id' => $goods->store_id])
  201. ->leftJoin(['pa' => PtActivity::tableName()], 'pag.activity_id = pa.id')
  202. ->andWhere(['OR', ['pag.goods_id' => $goods->id, 'pa.is_platform' => 1, 'pa.is_platform_audit' => 1, 'pa.status' => 1], ['pag.goods_id' => $goods->id, 'pa.is_platform' => 0]])
  203. ->select('pag.pt_price, pag.sale_num, pag.virtual_sales, pag.attr, pa.party_size, pa.party_type, pa.party_goods_count, pa.split_time, pa.head_integral, pa.id, pa.head_is_free')
  204. ->andWhere(['AND', ['<', 'pa.start_time', time()], ['>', 'pa.end_time', time()]])->asArray()->one();
  205. if ($ptGoodsActivity && !empty($this->is_pt)) {
  206. $split_time = $ptGoodsActivity['split_time'];
  207. $party_size = $ptGoodsActivity['party_size'];
  208. $party_type = $ptGoodsActivity['party_type'];
  209. $party_goods_count = $ptGoodsActivity['party_goods_count'];
  210. $party_id = $ptGoodsActivity['id'];
  211. //当前商品拼团数据
  212. $pt_arr = PtActivityOrderDetail::find()->alias('pod')
  213. ->where(['store_id' => $goods->store_id, 'pod.goods_id' => $goods->id])
  214. ->leftJoin(['po' => PtActivityOrder::tableName()], 'pod.order_id = po.id')
  215. ->andWhere(['po.pt_number' => 0, 'po.is_pay' => 1, 'po.is_pt_finish' => 0])
  216. ->select('po.id, po.pay_time')->orderBy('po.created_at desc')->asArray()->all();
  217. $arr = [];
  218. foreach ($pt_arr as $index => $item) {
  219. $arr[$index]['id'] = $item['id'];
  220. $end_time = ($item['pay_time'] + ($split_time * 60 * 60)) - time();
  221. $arr[$index]['end_time'] = $end_time > 0 ? $end_time : 0;
  222. $arr[$index]['user_list'] = PtActivityOrder::find()->alias('o')->where(['o.is_pay' => 1])
  223. ->leftJoin(['u' => User::tableName()], 'o.user_id = u.id')
  224. ->leftJoin(['su' => SaasUser::tableName()], 'u.binding = su.mobile')
  225. ->andWhere(['OR' , ['o.id' => $item['id']], ['o.pt_number' => $item['id']]])
  226. ->select('su.avatar, su.name')->limit(2)->asArray()->all();
  227. $arr[$index]['surplus_num'] = $party_size - count($arr[$index]['user_list']);
  228. $arr[$index]['party_type'] = $party_type;
  229. $arr[$index]['surplus_num_goods'] = 0;
  230. if($party_type == 1){
  231. $goodsCountQuery = PtActivityOrderDetail::find()->alias('pod')
  232. ->leftJoin(['po' => PtActivityOrder::tableName()], 'pod.order_id = po.id')
  233. ->where(['po.is_pay' => 1, 'pod.is_delete' => 0])
  234. ->andWhere(['OR' , ['po.id' => $item['id']], ['po.pt_number' => $item['id']]]);
  235. $goodsCount = $goodsCountQuery->sum('pod.num');
  236. $arr[$index]['surplus_num_goods'] = $party_goods_count - (int)$goodsCount;
  237. }
  238. }
  239. //拼团商品拼团数据
  240. $order_detail = PtActivityOrderDetail::find()->alias('pod')->where(['store_id' => $goods->store_id])
  241. ->leftJoin(['po' => PtActivityOrder::tableName()], 'pod.order_id = po.id')
  242. ->andWhere(['po.pt_number' => 0, 'po.is_pay' => 1, 'po.is_pt_finish' => 0])
  243. ->andWhere(['<>', 'pod.goods_id', $goods->id])
  244. ->select('pod.goods_id, pod.goods_name, pod.pic, pod.total_price pt_price, po.pay_time, pod.activity_id, po.user_id, po.id, po.store_id')
  245. ->orderBy('num desc')->asArray()->all();
  246. // $current_activity_num = count($order_detail);
  247. // $order_detail = $order_detail[0];
  248. $goods_activity = null;
  249. if ($order_detail) {
  250. foreach ($order_detail as $index => $value) {
  251. $activity = PtActivity::findOne($value['activity_id']);
  252. $goods_activity[$index]['name'] = $value['goods_name'];
  253. $goods_activity[$index]['cover_pic'] = $value['pic'];
  254. $saas_user = User::find()->alias('u')->leftJoin(['su' => SaasUser::tableName()], 'u.binding = su.mobile')
  255. ->select('su.name, su.avatar')->where(['u.id' => $value['user_id']])->asArray()->one();
  256. $goods_activity[$index]['avatar'] = $saas_user['avatar'];
  257. $goods_activity[$index]['end_time'] = 0;
  258. $goods_activity[$index]['pt_price'] = $value['pt_price'];
  259. if (($value['pay_time'] + ($activity->split_time * 60 * 60)) > time()) {
  260. $goods_activity[$index]['end_time'] = ($value['pay_time'] + ($activity->split_time * 60 * 60)) - time();
  261. }
  262. $goods_activity[$index]['goods_id'] = $value['goods_id'];
  263. $goods_activity[$index]['pt_number'] = $value['id'];
  264. $goods_activity[$index]['store_id'] = $value['store_id'];
  265. }
  266. }
  267. //获取活动规则
  268. $aboutArticle = AboutArticle::findOne(['store_id' => $goods->store_id, 'is_delete' => 0, 'type' => 1]);
  269. $pt_activity = [
  270. 'party_type' => (int)$party_type,
  271. 'is_join_pt' => (bool)$ptGoodsActivity,
  272. 'current_activity' => $arr,
  273. 'pt_price' => (string)$ptGoodsActivity['pt_price'],
  274. 'sale_num' => ((int)$ptGoodsActivity['sale_num'] + (int)$ptGoodsActivity['virtual_sales']),
  275. 'current_activity_num' => count($arr),
  276. 'goods_activity' => $goods_activity,
  277. 'rule' => $aboutArticle->desc ?? '',
  278. 'head_integral' => (int)$ptGoodsActivity['head_integral'],
  279. 'id' => $party_id,
  280. 'head_is_free' => (int)$ptGoodsActivity['head_is_free'],
  281. ];
  282. $goods->use_attr = 1;
  283. } else {
  284. $pt_activity = null;
  285. }
  286. $goods_attr = $goods->attr;
  287. if (!empty($ptGoodsActivity) && !empty($this->is_pt)) {
  288. $goods_attr = json_decode($goods_attr, true);
  289. $pt_attr = json_decode($ptGoodsActivity['attr'], true);
  290. if (!$goods->use_attr) {
  291. $goods_attr = [$goods_attr[0]];
  292. $pt_attr = [$pt_attr[0]];
  293. }
  294. foreach ($goods_attr as &$g_attr) {
  295. $g_attr_id = array_column($g_attr['attr_list'], 'attr_id');
  296. sort($g_attr_id);
  297. foreach ($pt_attr as $p_attr) {
  298. $p_attr_id = array_column($p_attr['attr_list'], 'attr_id');
  299. sort($p_attr_id);
  300. if (!array_diff($g_attr_id, $p_attr_id)) {
  301. $attr_name = $ptGoodsActivity['party_size'] . "人团";
  302. if($ptGoodsActivity['party_type'] == 1){
  303. $attr_name = $ptGoodsActivity['party_goods_count'] . "个商品成团";
  304. }
  305. $g_attr['attr_list'] = array_merge([
  306. [
  307. "attr_id" => -1,
  308. "attr_name" => $attr_name,
  309. ]
  310. ], $g_attr['attr_list']);
  311. $g_attr['price'] = $p_attr['pt_price'];
  312. }
  313. }
  314. }
  315. $last_names = array_column($pt_attr,'pt_price');
  316. array_multisort($last_names,SORT_DESC, $pt_attr);
  317. $pt_activity['pt_price'] = (string)($pt_attr[0]['pt_price']);
  318. $goods_attr = json_encode($goods_attr);
  319. }
  320. $storeInfo = Store::find()->where(['id'=> $goods->store_id,'is_delete'=>0])->select(['id', 'name', 'logo', 'coordinate', 'created_at', 'category_id', 'tags', 'sales', 'rank', 'per_spend','business_model','address','contact_tel'])->asArray()->one();
  321. if($goods->goods_send_profit > 0 || $goods->goods_take_price > 0){
  322. $is_league = 1;
  323. }else{
  324. $is_league = 0;
  325. }
  326. // $send_profit_model = Option::findOne(['name' => 'store_send_profit']);//平台让利比例
  327. // $this_store_send_profit_model= Option::findOne(['name' => 'store_this_profit','store_id' => $goods->store_id]);
  328. // if($this_store_send_profit_model->value > 0){
  329. // $basic_send_profit = (float)$this_store_send_profit_model->value;
  330. // }else{
  331. // $basic_send_profit = (float)$send_profit_model->value;
  332. // }
  333. $goods_send_profit = $goods->goods_send_profit * 0.01;
  334. $goods_take_profit = $goods->goods_take_price * 0.01;
  335. $data = [
  336. 'cutGoods' => $cutGoods,
  337. 'activityPrice' => sprintf('%.2f', $goods->activityPrice),
  338. 'id' => $goods->id,
  339. 'is_league' => $is_league,
  340. 'goods_send_profit' => $goods_send_profit,
  341. 'goods_take_profit' => $goods_take_profit,
  342. 'status' => $goods->status,
  343. 'pic_list' => $pic_list,
  344. 'attr' => $goods_attr,
  345. 'cover_pic' => $goods->cover_pic,
  346. 'is_negotiable' => $goods->is_negotiable,
  347. 'max_price' => sprintf('%.2f', max($price)),
  348. 'min_price' => $min_price,
  349. 'name' => $goods->name,
  350. 'cat_id' => $goods->cat_id,
  351. 'price' => sprintf('%.2f', $goodsPrice),
  352. 'detail' => $goods->detail,
  353. 'sales' => $goods->getSalesVolume() + $goods->virtual_sales,
  354. 'attr_group_list' => $goods->getAttrGroupList($this->is_pt, $goods->use_attr),
  355. 'num' => $goods->getNum(),
  356. 'is_favorite' => $is_favorite,
  357. 'service_list' => $new_service_list,
  358. 'original_price' => sprintf('%.2f', $goods->original_price),
  359. 'video_url' => $goods->video_url,
  360. 'unit' => $goods->unit,
  361. 'use_attr' => intval($goods->use_attr),
  362. 'mch' => $mch,
  363. 'max_share_price' => sprintf('%.2f', $res['max_share_price']),
  364. 'min_member_price' => sprintf('%.2f', $res['min_member_price']),
  365. 'is_share' => $res['is_share'],
  366. 'is_level' => $res['is_level'],
  367. 'is_member_price' => $isMemberPrice,
  368. 'full_minus' => $GoodsFullMinus,
  369. 'verify_card_id' => $verify_card,
  370. 'goods_share_title' => $goods->goods_share_title,
  371. 'goods_share_desc' => $goods->goods_share_desc,
  372. 'goods_share_logo' => $goods->goods_share_logo,
  373. 'product_type' => $goods->product_type,
  374. 'confine_count' => $goods->confine_count ?: 0,
  375. 'integral' => json_decode($goods->integral, true) ?: ['give' => 0, 'forehead' => 0, 'forehead_integral' => 0],
  376. 'store_info'=>$storeInfo,
  377. 'integral_price' => $goods->integral_price,
  378. 'seckill_activity_arr' => $seckill_activity_arr ?: null,
  379. 'pt_activity' => $pt_activity,
  380. ];
  381. $store_integral = Option::get(OptionSetting::STORE_INTEGRAL, $goods->store_id, 'gift', Option::get(OptionSetting::STORE_INTEGRAL, $goods->store_id, 'store')['value'])['value'];
  382. if ($goods->integral) {
  383. $goods_integral = Json::decode($goods->integral);
  384. if ($goods_integral['forehead'] > 0) {
  385. $data['integral'] = [
  386. 'give' => $goods_integral['give'],
  387. 'forehead' => $goods_integral['forehead'],
  388. 'forehead_integral' => round($store_integral * $goods_integral['forehead'])
  389. ];
  390. }
  391. }
  392. // 处理app上不显示没加协议的图片
  393. $data['detail'] = str_replace('src="//', 'src="https://', $data['detail']);
  394. $now_date = strtotime(date('Y-m-d'));
  395. $goods_book = GoodsBook::findOne(['goods_id' => $goods->id]);
  396. // 预约参数配置
  397. if ($data['product_type'] == Goods::GOODS_TYPE_DATE) {
  398. $data['num'] = Goods::getGoodsNum($goods)['data'];
  399. $data['date_book'] = [
  400. 'date_book' => $data['num'] ,
  401. 'date' => count($data['num'])
  402. ];
  403. if ($goods_book && !empty($goods_book->date_book)) {
  404. $date_book = Json::decode($goods_book->date_book);
  405. $count = 0;
  406. foreach ($date_book as $value) {
  407. if (strtotime($value['date']) >= $now_date) {
  408. $count++;
  409. }
  410. }
  411. // if ($count <= 0) {
  412. // return [
  413. // 'code' => 1,
  414. // 'msg' => '商品预约数据不存在'
  415. // ];
  416. // }
  417. $data['date_book'] = [
  418. 'date_book' => $date_book,
  419. 'date' => count($date_book)
  420. ];
  421. } else {
  422. // return [
  423. // 'code' => 1,
  424. // 'msg' => '该商品暂无可预约数据'
  425. // ];
  426. }
  427. }
  428. if ($data['product_type'] == Goods::GOODS_TYPE_TIME) {
  429. if ($goods_book && !empty($goods_book->service_book)) {
  430. $new_arr = $this->goodsBookingTime($goods['id'], 7);
  431. $data['service_book'] = $new_arr;
  432. } else {
  433. return [
  434. 'code' => 1,
  435. 'msg' => '商品服务预约配置有误'
  436. ];
  437. }
  438. }
  439. // if ($data['product_type'] == Goods::GOODS_TYPE_TIME) {
  440. // if ($goods_book && !empty($goods_book->service_book)) {
  441. // $service_book = Json::decode($goods_book->service_book);
  442. // $count = 0;
  443. // foreach ($service_book['data'] as &$value) {
  444. // if (strtotime($value['date']) >= $now_date) {
  445. // foreach ($value['time'] as &$m) {
  446. // foreach ($m['times'] as &$n) {
  447. // $times = explode('-', $n['time']);
  448. // if (strtotime(date('Y-m-d H:i:s')) <= strtotime($value['date'] . $times[1])) {
  449. // $count++;
  450. // }
  451. // }
  452. // }
  453. // }
  454. // }
  455. //
  456. // if ($count <= 0) {
  457. // return [
  458. // 'code' => 1,
  459. // 'msg' => '该商品暂无可预约数据'
  460. // ];
  461. // }
  462. // $data['service_book'] = $service_book;
  463. // } else {
  464. // return [
  465. // 'code' => 1,
  466. // 'msg' => '商品服务预约配置有误'
  467. // ];
  468. // }
  469. // }
  470. return [
  471. 'code' => 0,
  472. 'data' => $data
  473. ];
  474. }
  475. public function activity_new_user($activity_new_user_id, &$goods, &$md_goods = null) {
  476. // $activityAt = ActivityNewUser::activityAt($goods->store_id);
  477. // $activityAt && $this->activity_new_user_id = $activityAt->id;
  478. //展示活动商品信息
  479. $activityAt = ActivityNewUser::activityAt($goods->store_id);
  480. if ($activityAt) {
  481. $goods_ext = ActivityNewUserGoods::findOne(['activity_id' => $activityAt->id, 'goods_id' => $goods->id, 'is_delete' => 0]);
  482. //商品属于当前进行中活动
  483. if($goods_ext){
  484. if($goods_ext->price){
  485. $goods->price = $goods_ext->price;
  486. $md_goods && $md_goods->price = $goods_ext->price;
  487. }
  488. $ext_attrs = json_decode($goods_ext->attr, true);
  489. $attrs = json_decode($goods->attr, true);
  490. if($md_goods){
  491. $md_attrs = json_decode($md_goods->attr, true);
  492. }
  493. foreach($ext_attrs as $ext_attr){
  494. $ext_attr_list = json_encode($ext_attr['attr_list']);
  495. foreach($attrs as &$attr){
  496. $attr_list = json_encode($attr['attr_list']);
  497. if($attr_list == $ext_attr_list){
  498. $attr['price'] = $ext_attr['price'];
  499. }
  500. }
  501. if($md_goods){
  502. foreach($md_attrs as &$md_attr){
  503. $md_attr_list = json_encode($md_attr['attr_list']);
  504. if($md_attr_list == $ext_attr_list){
  505. $md_attr['price'] = $ext_attr['price'];
  506. }
  507. }
  508. }
  509. }
  510. $goods->attr = json_encode($attrs);
  511. $md_goods && $md_goods->attr = json_encode($md_attrs);
  512. }
  513. }
  514. }
  515. /**
  516. * @description: 获取商品收货地址
  517. * @param {*}
  518. * @return {*}
  519. */
  520. public function getAddress()
  521. {
  522. if ($this->address_id) {
  523. $query = Address::find()->where(['store_id' => get_store_id(), 'is_delete' => 0, 'id' => $this->address_id]);
  524. $address = $query->andWhere([
  525. 'user_id' => get_saas_user_id()
  526. ])->one();
  527. } else {
  528. $query = Address::find()->where(['store_id' => get_store_id(), 'is_delete' => 0]);
  529. $query->andWhere([
  530. 'user_id' => get_saas_user_id()
  531. ]);
  532. $address = $query->orderBy(['is_default' => SORT_DESC])->one();
  533. }
  534. $goods = Goods::findOne($this->id);
  535. // 计算运费
  536. $express_price = $this->getExpressPrice($address, $goods);
  537. // 计算区域限制购买
  538. $is_area = $this->getTerritorialLimitation($address, $goods);
  539. return [
  540. 'code' => 0,
  541. 'data' => [
  542. 'address' => $address,
  543. 'express_price' => $express_price,
  544. 'is_area' => $is_area
  545. ]
  546. ];
  547. }
  548. /**
  549. * 计算单个商品是否区域限制购买
  550. */
  551. protected function getTerritorialLimitation($address, $goods)
  552. {
  553. $isArea = 0;
  554. if ($address) {
  555. $area = TerritorialLimitation::findOne([
  556. 'store_id' => get_store_id(),
  557. 'is_delete' => 0,
  558. 'is_enable' => 1,
  559. ]);
  560. if ($area) {
  561. $city_id = []; //限制的地区ID
  562. $detail = json_decode($area->detail);
  563. if (!is_array($detail)) {
  564. $detail = [];
  565. }
  566. foreach ($detail as $key => $value) {
  567. foreach ($value->province_list as $key2 => $value2) {
  568. $city_id[] = $value2->id;
  569. }
  570. }
  571. $addressArr = [
  572. $address['province_id'],
  573. $address['city_id'],
  574. $address['district_id']
  575. ];
  576. $addressArray = array_intersect($addressArr, $city_id);
  577. if (empty($addressArray)) {
  578. $isArea = 1;
  579. }
  580. }
  581. }
  582. return $isArea;
  583. }
  584. /**
  585. * 计算单个商品的运费
  586. */
  587. protected function getExpressPrice($address, $goods)
  588. {
  589. $expressPrice = 0;
  590. if ($address) {
  591. //再通过运费规则计算运费
  592. $expressPrice = PostageRules::getExpressPrice($goods->store_id, $address->city_id, $goods, 1, $address->province_id);
  593. }
  594. return $expressPrice >= 0 ? $expressPrice : 0;
  595. }
  596. public function getDateByInterval(int $num) :array
  597. {
  598. //var_dump($st, $et);die;
  599. $returnData = [];
  600. $i = 0;
  601. do {
  602. $temp = date('Y-m-d', strtotime('+' . $i . ' day', strtotime(date('Y-m-d'))));
  603. $returnData[] = $temp;
  604. $i++;
  605. } while ($i < $num);
  606. return $returnData;
  607. }
  608. public function goodsBookingTime($goods_id, $dayCount = 7) {
  609. $now_date = strtotime(date('Y-m-d'));
  610. $goods_book = GoodsBook::findOne(['goods_id' => $goods_id]);
  611. $service_book = Json::decode($goods_book->service_book);
  612. $date_data = $this->getDateByInterval($dayCount);
  613. $new_arr = [
  614. 'data' => []
  615. ];
  616. $order = \app\models\Order::find()->alias('o')
  617. ->leftJoin(['od' => \app\models\OrderDetail::tableName()], 'o.id = od.order_id')
  618. ->where(['o.trade_status' => [0, 2, 3], 'o.is_delete' => 0, 'o.order_type' => 2, 'goods_id' => $goods_id])
  619. ->andWhere(['>', 'o.created_at', time() - 3600 - $dayCount * 86400])
  620. ->select('od.attr, od.num')->asArray()->all();
  621. foreach ($date_data as $index => $datum) {
  622. $new_arr['data'][$index]['date'] = $datum;
  623. $new_arr['data'][$index]['time'] = $service_book['data'][0]['time'];
  624. }
  625. foreach ($new_arr['data'] as &$value) {
  626. if (strtotime($value['date']) >= $now_date) {
  627. foreach ($value['time'] as &$m) {
  628. foreach ($m['times'] as &$n) {
  629. $times = explode('-', $n['time']);
  630. foreach ($order as $item) {
  631. if ($item['attr']) {
  632. $item['attr'] = json_decode($item['attr'], true);
  633. $order_time = explode('-', $item['attr']['time']);
  634. if (
  635. strtotime($item['attr']['date'] . ' ' . $times[0]) === strtotime($value['date'] . ' ' . $order_time[0]) &&
  636. strtotime($item['attr']['date'] . ' ' . $times[1]) === strtotime($value['date'] . ' ' . $order_time[1])
  637. ) {
  638. $n['num'] = $n['num'] - $item['num'];
  639. }
  640. }
  641. }
  642. }
  643. }
  644. }
  645. }
  646. return $new_arr;
  647. }
  648. }