GoodsReserveTime.php 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391
  1. <?php
  2. namespace common\models\goods;
  3. use common\enums\StatusEnum;
  4. use common\helpers\ArrayHelper;
  5. use Exception;
  6. use Yii;
  7. /**
  8. * 预约商品SKU模型
  9. * This is the model class for table "{{%goods_reserve_time}}"
  10. * @property int $id
  11. * @property int $mall_id 商城id
  12. * @property int $mch_id 商家id
  13. * @property float $price 售价
  14. * @property float $original_price 原价(划线价仅展示)
  15. * @property float $cost_price 成本价
  16. * @property int $reserve_max_buy 每天最大预约数量
  17. * @property string $reserve_time 预约日期标题
  18. * @property string $reserve_range_time 时分秒时间范围
  19. * @property int $reserve_sku_id 预约商品SKU
  20. * @property int $stock 库存
  21. * @property int $sales 销量
  22. * @property int $time_span 时间间隔
  23. * @property int $created_at 创建时间
  24. * @property int $updated_at 修改时间
  25. * @property string $reserve_date 预约日期
  26. */
  27. class GoodsReserveTime extends \common\models\base\BaseActiveRecord
  28. {
  29. /**
  30. * {@inheritdoc}
  31. */
  32. public static function tableName()
  33. {
  34. return '{{%goods_reserve_time}}';
  35. }
  36. /**
  37. * {@inheritdoc}
  38. */
  39. public function rules()
  40. {
  41. return [
  42. [['mall_id', 'mch_id', 'reserve_max_buy', 'reserve_sku_id', 'stock', 'sales', 'time_span', 'created_at', 'updated_at'], 'integer'],
  43. [['price', 'original_price', 'cost_price'], 'number'],
  44. [['reserve_time', 'reserve_range_time','reserve_date'], 'string'],
  45. ];
  46. }
  47. /**
  48. * {@inheritdoc}
  49. */
  50. public function attributeLabels()
  51. {
  52. return [
  53. 'id' => '',
  54. 'mall_id' => '商城id',
  55. 'mch_id' => '商家id',
  56. 'price' => '售价',
  57. 'original_price' => '原价(划线价仅展示)',
  58. 'cost_price' => '成本价',
  59. 'reserve_max_buy' => '每天最大预约数量',
  60. 'reserve_time' => '预约日期标题',
  61. 'reserve_sku_id' => '预约商品SKU',
  62. 'stock' => '库存',
  63. 'sales' => '销量',
  64. 'reserve_range_time' => '时分秒时间范围',
  65. 'time_span' => '时间间隔(分钟)',
  66. 'created_at' => '创建时间',
  67. 'updated_at' => '修改时间',
  68. ];
  69. }
  70. public function getTimeSpec()
  71. {
  72. return $this->hasMany(GoodsReserveTimeSpec::class, ['reserve_time_id' => 'id']);
  73. }
  74. // 设置sku的可预约时间
  75. public static function setSkuTime($reserveGoodsSku)
  76. {
  77. try {
  78. $skuId = $reserveGoodsSku['id'];
  79. if($reserveGoodsSku['reserve_time_slot_price']){
  80. $reserveTimeSlotPrice = json_decode($reserveGoodsSku['reserve_time_slot_price'], true);
  81. }else{
  82. $reserveTimeSlotPrice = [];
  83. }
  84. //$reserveTimeSlotPrice = json_decode($reserveGoodsSku['reserve_time_slot_price'], true);
  85. //$reserveTimeSlotPrice = $reserveGoodsSku['reserve_time_slot_price'] ?? [];
  86. // \Yii::error(json_encode([$reserveGoodsSku, $reserveTimeSlotPrice], JSON_UNESCAPED_UNICODE));
  87. $totalStock = 0;
  88. // dd($reserveTimeSlotPrice);
  89. // 清除规格下的所有时间设置
  90. self::deleteAll(['reserve_sku_id' => $skuId]);
  91. GoodsReserveTimeSpec::deleteAll(['reserve_sku_id'=>$skuId]);
  92. if($reserveGoodsSku['reserve_time_range_type'] == 1){
  93. //按天预约
  94. $reserve_date = $reserveGoodsSku['reserve_date'] ? json_decode($reserveGoodsSku['reserve_date'],true) : [];
  95. foreach($reserve_date as $date){
  96. $model = new self();
  97. $model->loadDefaultValues();
  98. $attributes = [
  99. 'mall_id' => $reserveGoodsSku['mall_id'] ?? 0,
  100. 'mch_id' => $reserveGoodsSku['mch_id'] ?? 0,
  101. 'price' => $reserveGoodsSku['reserve_price_type'] == 2 ?
  102. ($reserveTimeSlotPrice[$date]['price'] ?? 0) : ($reserveGoodsSku['price'] ?? 0),
  103. 'original_price' => $reserveGoodsSku['reserve_price_type'] == 2 ?
  104. ($reserveTimeSlotPrice[$date]['original_price'] ?? 0) : ($reserveGoodsSku['original_price'] ?? 0),
  105. 'cost_price' => $reserveGoodsSku['reserve_price_type'] == 2 ?
  106. ($reserveTimeSlotPrice[$date]['cost_price'] ?? 0) : ($reserveGoodsSku['cost_price'] ?? 0),
  107. 'reserve_max_buy' => $reserveGoodsSku['reserve_price_type'] == 2 ?
  108. ($reserveTimeSlotPrice[$date]['reserve_max_buy'] ?? 0) : ($reserveGoodsSku['reserve_max_buy'] ?? 0),
  109. 'reserve_time' => $date,
  110. 'reserve_sku_id' => $reserveGoodsSku['id'] ?? 0,
  111. 'stock' => $reserveGoodsSku['reserve_price_type'] == 2 ?
  112. ($reserveTimeSlotPrice[$date]['reserve_max_buy'] ?? 0) : ($reserveGoodsSku['reserve_max_buy'] ?? 0),
  113. 'reserve_range_time' => $reserveGoodsSku['reserve_range_time'] ?? '',
  114. 'time_span' => $reserveGoodsSku['time_span'] ?? 0,
  115. 'reserve_date' => $date,
  116. ];
  117. Yii::error("{$reserveGoodsSku['reserve_time_range_type']} -> " . var_export($attributes, true));
  118. if (!$model->load($attributes, '') || !$model->save()) {
  119. throw new Exception($model->getErrorMessage());
  120. }
  121. $totalStock += $reserveGoodsSku['reserve_max_buy'];
  122. }
  123. }else{ // 按时间段
  124. array_map(function ($val) use (&$totalStock, &$reserveGoodsSku) {
  125. $model = new self();
  126. $model->loadDefaultValues();
  127. $attributes = [
  128. 'mall_id' => $reserveGoodsSku['mall_id'] ?? 0,
  129. 'mch_id' => $reserveGoodsSku['mch_id'] ?? 0,
  130. 'price' => $val['price'] ?? 0,
  131. 'original_price' => $val['original_price'] ?? 0,
  132. 'cost_price' => $val['cost_price'] ?? 0,
  133. 'reserve_max_buy' => $val['reserve_max_buy'] ?? 0,
  134. 'reserve_time' => $val['reserve_time'] ?? 0,
  135. 'reserve_sku_id' => $reserveGoodsSku['id'] ?? 0,
  136. 'stock' => $val['reserve_max_buy'] ?? 0,
  137. 'reserve_range_time' => $val['reserve_range_time'] ?? '',
  138. 'time_span' => $val['time_span'] ?? 0,
  139. 'reserve_date' => $val['reserve_time'] ?? date('Y-m-d'),
  140. ];
  141. Yii::error("{$reserveGoodsSku['reserve_time_range_type']} -> " . var_export($attributes, true));
  142. if (!$model->load($attributes, '') || !$model->save()) {
  143. throw new Exception($model->getErrorMessage());
  144. }
  145. // 有时间段设置
  146. if (!empty($val['time_spec'])) {
  147. $timeMdl = ArrayHelper::toArray($model);
  148. $res = GoodsReserveTimeSpec::setTimeSpec($timeMdl, $val['time_spec'], $totalStock);
  149. if($res === false) throw new Exception('处理预约商品预约时间规格异常,msg:'.GoodsReserveTimeSpec::getStaticError());
  150. } else {
  151. $totalStock += $val['reserve_max_buy'];
  152. }
  153. }, $reserveTimeSlotPrice);
  154. }
  155. if ($totalStock > 0) {
  156. $goods = Goods::findOne($reserveGoodsSku['goods_id']);
  157. $goods->stock = +$totalStock;
  158. if (!$goods->save()) throw new Exception($goods->getErrorMessage());
  159. }
  160. } catch (Exception $e) {
  161. if (isset($trans)) $trans->rollback();
  162. self::$static_error = $e->getMessage();
  163. return false;
  164. }
  165. }
  166. /**
  167. * 获取商品规格预约时间
  168. * @param $mall_id
  169. * @param array $sku
  170. * @param int $limit
  171. * @return array|\yii\db\ActiveRecord[]
  172. */
  173. public static function getSkuTime($mall_id,$sku,$limit = 20)
  174. {
  175. $reserve_date = $sku['reserve_date'];
  176. $reserve_date = $reserve_date ? json_decode($reserve_date,true) : [];
  177. $reserve = GoodsReserve::findOne(['goods_id' => $sku['goods_id']]);
  178. $reserve_days_range = $reserve['reserve_days_range'] ?: 30;
  179. $reserve_advance_hourse = $reserve['reserve_advance_hourse'] ?:0;
  180. $reserve_advance_hourse_time = $reserve_advance_hourse > 0 ? strtotime("+$reserve_advance_hourse hour") : 0;
  181. $max_reserve_time = strtotime(date('Y-m-d',strtotime("+$reserve_days_range days")));
  182. $reserve_date_arr = [];
  183. foreach($reserve_date as $date){
  184. $date_timestamp = strtotime($date);
  185. if($date_timestamp >= strtotime(date('Y-m-d')) && $date_timestamp <= $max_reserve_time){
  186. $reserve_date_arr[] = $date_timestamp;
  187. }
  188. }
  189. $max_reserve_date = $reserve_date_arr ? date('Y-m-d',max($reserve_date_arr)) : date('Y-m-d');
  190. $reserve_sku_id = $sku['id'];
  191. //reserve_time_range_type = 1 按天预约 timeSpec 为空
  192. $list = self::find()->where(['mall_id' => $mall_id,'reserve_sku_id' => $reserve_sku_id])
  193. ->with(['timeSpec' => function($query){ $query->select('id as time_spec_id, reserve_time_id,spec_time,price');}])
  194. ->andWhere(['>=','reserve_date',date('Y-m-d')])
  195. ->andWhere(['<=','reserve_date',$max_reserve_date])
  196. ->orderBy('reserve_date asc')
  197. ->limit($limit)
  198. ->select('id,price,original_price,cost_price,reserve_time,reserve_sku_id,reserve_max_buy,reserve_date')
  199. ->asArray()->all();
  200. //提前预约reserve_advance_hourse
  201. // dd($list);
  202. $next_arr = [];
  203. // $next_day = null;
  204. foreach ($list as $key => $val){
  205. $val['week_day'] = self::getWeekDay($val['reserve_time']);
  206. if($val['timeSpec']){
  207. foreach($val['timeSpec'] as $k => $v){
  208. $spec_time = explode('-',$v['spec_time']);
  209. $start_date_time = $val['reserve_time'].' '.$spec_time[0].':00';
  210. $end_date_time = $val['reserve_time'].' '.$spec_time[1].':00';
  211. $start_time = strtotime($start_date_time);
  212. if (strpos($end_date_time, '次日') !== false) {
  213. $end_date_time_arr = explode(" ", $end_date_time);
  214. $end_time = strtotime("$end_date_time_arr[0] 23:59:59");
  215. $list[$key]['timeSpec'][$k]['spec_time'] = "{$spec_time[0]}-23:59:59";
  216. $next = $key+1;
  217. // if (empty($list[$next])) {
  218. // $next_day = $val;
  219. // }
  220. $next_arr[$next] = $v;
  221. } else {
  222. $end_time = strtotime($end_date_time);
  223. }
  224. if(time() >= $end_time || $reserve_advance_hourse_time > $end_time){
  225. unset($val['timeSpec'][$k]);
  226. continue;
  227. }
  228. if(time() > $start_time && time() < $end_time){
  229. $v['spec_time'] = date("H:00").'-'.$spec_time[1];
  230. if($reserve_advance_hourse_time > $start_time){
  231. $v['spec_time'] = date("H:00",$reserve_advance_hourse_time).'-'.$spec_time[1];
  232. }
  233. if (strpos($v['spec_time'], "次日") !== false) {
  234. $v['spec_time'] = "$spec_time[0]-23:59";
  235. }
  236. $val['timeSpec'][$k] = $v;
  237. } else {
  238. if (strpos($v['spec_time'], "次日") !== false) {
  239. $v['spec_time'] = "$spec_time[0]-23:59";
  240. }
  241. $val['timeSpec'][$k] = $v;
  242. }
  243. }
  244. $val['timeSpec'] = array_values($val['timeSpec']);
  245. }
  246. $list[$key] = $val;
  247. }
  248. if (!empty($next_arr)) {
  249. foreach ($list as $key => &$item) {
  250. if (!empty($next_arr[$key])) {
  251. $tmp_v = $next_arr[$key];
  252. $time_arr = explode("次日", $tmp_v['spec_time']);
  253. $tmp_v['spec_time'] = "00:00-{$time_arr[1]}";
  254. $item['timeSpec'][] = $tmp_v;
  255. }
  256. }
  257. }
  258. //dd($list);
  259. return $list;
  260. }
  261. /**
  262. * 获取商品最近可预约时间
  263. * @param $mall_id
  264. * @param $goods_id
  265. * @param $reserve_sku_ids
  266. * @return array
  267. */
  268. public static function getSkuLatelyTime($mall_id,$goods_id,$reserve_sku_ids)
  269. {
  270. $where = ['mall_id' => $mall_id,'reserve_sku_id' => $reserve_sku_ids];
  271. $min_date = self::find()->where($where) ->andWhere(['>=','reserve_date',date('Y-m-d')])->groupBy('reserve_sku_id')
  272. ->select("min(reserve_date) as reserve_date")->asArray()->all();
  273. $min_date = array_column($min_date,'reserve_date');
  274. $min_date = array_unique($min_date);
  275. $time_arr = [];
  276. $res = self::find()->where(['mall_id' => $mall_id,'reserve_sku_id' => $reserve_sku_ids])
  277. ->with('timeSpec')
  278. ->andWhere(['>=','reserve_date',date('Y-m-d')])
  279. //->andWhere(['in','reserve_date',$min_date])
  280. ->orderBy('reserve_date asc')
  281. ->asArray()->all();
  282. $now = time();
  283. if($res){
  284. foreach($res as $val){
  285. $date = $val['reserve_date'];
  286. $date = self::getWeekDay($date);
  287. if($val['timeSpec']){
  288. foreach($val['timeSpec'] as $k => $v){
  289. $spec_time = explode('-',$v['spec_time']);
  290. $start_date_time = $val['reserve_time'].' '.$spec_time[0].':00';
  291. $end_date_time = $val['reserve_time'].' '.$spec_time[1].':00';
  292. $start_time = strtotime($start_date_time);
  293. $end_time = strtotime($end_date_time);
  294. if($now >= $end_time){
  295. continue;
  296. }else{
  297. if(!isset($time_arr[$val['reserve_sku_id']])){
  298. if ($now > $start_time && $val['reserve_time'] == date("Y-m-d")) {
  299. continue;
  300. }
  301. $time_arr[$val['reserve_sku_id']] = [
  302. 'time' => $date.' '.$v['spec_time'],
  303. 'time_spec_id' => $v['id'],
  304. 'time_id' => $v['reserve_time_id']
  305. ];
  306. }
  307. break;
  308. }
  309. }
  310. }else{
  311. if(!isset($time_arr[$val['reserve_sku_id']])){
  312. $time_arr[$val['reserve_sku_id']] = [
  313. 'time' => $date,
  314. 'time_spec_id' => 0,
  315. 'time_id' => $val['id']
  316. ];
  317. }
  318. }
  319. }
  320. }
  321. return $time_arr;
  322. }
  323. public static function getWeekDay($date)
  324. {
  325. $week_array = ["日", "一", "二", "三", "四", "五", "六"];
  326. $week = date("w", strtotime($date));
  327. $tomorrow = date('Y-m-d',strtotime('+1 day'));
  328. if($date == date('Y-m-d',time())){
  329. return '今天';
  330. }
  331. if($date == $tomorrow){
  332. return '明天';
  333. }
  334. return "周".$week_array[$week];
  335. }
  336. }