Você não pode selecionar mais de 25 tópicos Os tópicos devem começar com uma letra ou um número, podem incluir traços ('-') e podem ter até 35 caracteres.
 
 
 
 
 
 

441 linhas
17 KiB

  1. <?php
  2. namespace backend\modules\hotel\models;
  3. use common\models\BaseUserAuth;
  4. use Yii;
  5. use yii\data\ActiveDataProvider;
  6. use yii\data\SqlDataProvider;
  7. use backend\modules\hotel\controllers\ComparePriceController;
  8. /**
  9. * This is the model class for table "price_compared_hotel".
  10. *
  11. * @property integer $id
  12. * @property integer $cancel_flag
  13. * @property string $ChannelHotelId
  14. * @property integer $HotelId
  15. * @property integer $ChannelId
  16. */
  17. class PriceComparedHotel extends \yii\db\ActiveRecord
  18. {
  19. public $inferiority;
  20. public $no_show;
  21. public $competitive;
  22. public $lose;
  23. /**
  24. * @inheritdoc
  25. */
  26. public static function tableName()
  27. {
  28. return 'price_compared_hotel';
  29. }
  30. /**
  31. * @inheritdoc ChannelHotelId
  32. */
  33. public function rules()
  34. {
  35. return [
  36. [['cancel_flag', 'HotelId', 'ChannelId'], 'integer'],
  37. [['ChannelHotelId', 'HotelId', 'ChannelId'], 'required'],
  38. [['ChannelHotelId'], 'string', 'max' => 20],
  39. [['ChannelHotelId'], 'unique'],
  40. [['HotelId', 'ChannelId'], 'unique', 'targetAttribute' => ['HotelId', 'ChannelId'], 'message' => 'The combination of 本地酒店ID and 渠道ID 1:携程 has already been taken.'],
  41. [['ChannelHotelId', 'ChannelId'], 'unique', 'targetAttribute' => ['ChannelHotelId', 'ChannelId'], 'message' => 'The combination of 渠道酒店ID and 渠道ID 1:携程 has already been taken.'],
  42. ];
  43. }
  44. /**
  45. * @inheritdoc
  46. */
  47. public function attributeLabels()
  48. {
  49. return [
  50. 'id' => 'ID',
  51. 'cancel_flag' => 'Cancel Flag',
  52. 'ChannelHotelId' => '渠道酒店ID',
  53. 'HotelId' => '本地酒店ID',
  54. 'ChannelId' => '渠道',
  55. ];
  56. }
  57. public function getOperaHotel()
  58. {
  59. return $this->hasOne(OperaHotel::className(), ['HOTEL_ID' => 'HotelId']);
  60. }
  61. public function getHotelPriceConversion()
  62. {
  63. return $this->hasOne(HotelPriceConversion::className(), ['hotel_id' => 'HotelId']);
  64. }
  65. public function getOperaHotelRoom()
  66. {
  67. return $this->hasOne(OperaHotelRoom::className(), ['HOTEL_ID' => 'HotelId']);
  68. }
  69. public function index($filter)
  70. {
  71. $query = PriceComparedHotel::find()
  72. ->joinWith('operaHotel as b')
  73. ->joinWith('hotelPriceConversion c')
  74. ->leftJoin('price_compared_room as e', 'a.HotelId =e.hotel_id')
  75. ->leftJoin('opera_hotel_room as d', 'e.room_id = d.ID')
  76. ->from('price_compared_hotel as a')
  77. ->select(['a.id', 'a.ChannelHotelId', 'a.HotelId', 'a.ChannelId', 'b.HOTEL_NAME',
  78. 'a.cancel_flag', 'c.remain_room_conversion', 'c.breakfast_conversion', 'c.cancel_rules_conversion', 'c.pay_type_conversion', 'IF(e.hotel_id, count(a.HotelId), 0) as room_num', 'a.SendMsg'])
  79. ->where(['b.cancel_flag' => 0])
  80. ->groupBy(['a.HotelId']);
  81. if ($filter['channel_id'] != null) {
  82. $query->andFilterWhere(['=', 'a.ChannelHotelId', $filter['channel_id']]);
  83. }
  84. if ($filter['cancel_flag'] != null && $filter['cancel_flag'] != -1) {
  85. $query->andFilterWhere(['=', 'a.cancel_flag', $filter['cancel_flag']]);
  86. }
  87. if ($filter['hotel_name'] != null) {
  88. $query->andFilterWhere(['like', 'b.HOTEL_NAME', $filter['hotel_name']]);
  89. }
  90. if ($filter['channel'] != null && $filter['channel'] != -1) {
  91. $query->andFilterWhere(['=', 'a.ChannelId', $filter['channel']]);
  92. }
  93. // 采购负责人、客服、客服管理员不能查看比较数据
  94. if(Yii::$app->user->identity['USER_ROLE'] == BaseUserAuth::HOTEL_PURCHASE || Yii::$app->user->identity['USER_ROLE'] == BaseUserAuth::HOTEL_CUSTOMER
  95. || Yii::$app->user->identity['USER_ROLE'] == BaseUserAuth::HOTEL_CUS_ADMIN){
  96. $query->andFilterWhere(['a.id' => -1]);
  97. }
  98. $dataProvider = new ActiveDataProvider([
  99. 'query' => $query->asArray(),
  100. 'pagination' => [
  101. 'pageSize' => 15,
  102. ],
  103. ]);
  104. return $dataProvider;
  105. }
  106. /**
  107. * 修改酒店比价状态
  108. */
  109. public function setCancelFlag($id, $cancel_flag)
  110. {
  111. $hotel = PriceComparedHotel::findOne($id);
  112. $hotel->cancel_flag = $cancel_flag;
  113. $hotel->save();
  114. if ($hotel->update()) {
  115. return true;
  116. } else {
  117. return false;
  118. }
  119. }
  120. public function getHotelList()
  121. {
  122. $sql = 'SELECT HOTEL_ID, HOTEL_NAME FROM opera_hotel WHERE HOTEL_ID not in (SELECT HotelId FROM price_compared_hotel) AND CANCEL_FLAG = 0';
  123. $hotel_list = Yii::$app->db->createCommand($sql)->queryAll();
  124. return $hotel_list;
  125. }
  126. /**
  127. * Author:Steven
  128. * Desc:获取酒店价格总览列表
  129. * @param $channel_id
  130. * @return SqlDataProvider
  131. */
  132. public function getHotelOverview($channel_id, $hotel_name, $hotel_pricipal)
  133. {
  134. $end_date = date('Y-m-d');
  135. $start_date = date('Y-m-d', strtotime('-30 days'));
  136. $str = $hotel_pricipal == -1 ? 'and (1 = 1)' : 'and e.PRINCIPAL=' . $hotel_pricipal;
  137. // 采购负责人、客服、客服管理员不能查看比较数据
  138. if(Yii::$app->user->identity['USER_ROLE'] ==BaseUserAuth::HOTEL_PURCHASE || Yii::$app->user->identity['USER_ROLE'] ==BaseUserAuth::HOTEL_CUSTOMER
  139. || Yii::$app->user->identity['USER_ROLE'] ==BaseUserAuth::HOTEL_CUS_ADMIN){
  140. $str = ' and c.id=-1';
  141. }
  142. $sql = "select c.*,count(d.room_id) as room_count,e.hotel_name from (select a.*,sum(b.SALED_COUNT) as saled_count from price_compared_hotel a
  143. LEFT JOIN run_hotel b on a.HotelId=b.HOTEL_ID and b.RUN_DATE BETWEEN :start_date and :end_date where a.ChannelId=:channel_id
  144. GROUP BY a.HotelId,a.ChannelId) c
  145. LEFT JOIN price_compared_room d on c.HotelId=d.hotel_id and d.cancel_flag=0 and d.channel_id=:channel_id
  146. LEFT JOIN opera_hotel e on c.HotelId=e.HOTEL_ID and e.CANCEL_FLAG=0
  147. WHERE e.HOTEL_NAME LIKE :hotel_name $str GROUP BY c.HotelId,c.ChannelId ORDER BY c.saled_count DESC";
  148. $count = Yii::$app->db->createCommand("select count(1) from " . "(" . $sql . ")" . "as count ", [':start_date' => $start_date, ':end_date' => $end_date, ':channel_id' => $channel_id, ':hotel_name' => "%$hotel_name%"])->queryScalar();
  149. $dataProvider = new SqlDataProvider([
  150. 'sql' => $sql,
  151. 'params' => [':start_date' => $start_date, ':end_date' => $end_date, ':channel_id' => (int)$channel_id, ':hotel_name' => "%$hotel_name%"],
  152. 'totalCount' => $count,
  153. 'sort' => false,
  154. 'pagination' => [
  155. 'pagesize' => 20
  156. ]
  157. ]);
  158. return $dataProvider;
  159. }
  160. /**
  161. * User:Steven
  162. * Desc:获取比价总览页面的数据
  163. * @param $hotel_id
  164. * @param $price
  165. * @param $start_date
  166. * @param $end_date
  167. * @return bool
  168. */
  169. public static function GetOverviewData($hotel_id, &$price, $start_date, $end_date)
  170. {
  171. $ctripHotelPrice = new CtripHotelPrice();
  172. $data = $ctripHotelPrice->getCtripData($hotel_id, $start_date, $end_date);
  173. if (empty($data)) {
  174. return false;
  175. }
  176. // $disadvantage = $price->ctripDataService($data, $hotel_id, false); //未进行价差折算 价格劣势
  177. $competitiveness = $price->ctripDataService($data, $hotel_id); //进行价差折算 竞争力不足
  178. $inferiority = 0;
  179. $no_show = 0;
  180. $competitive = 0;
  181. if (!empty($data)) {
  182. /*foreach ($disadvantage as $key => $value) {
  183. foreach ($value as $item) {
  184. if (empty($item)) {
  185. continue;
  186. }
  187. foreach ($item as $k => $v) {
  188. if (!is_null($v['a_price']) && !is_null($v['b_price'])) { //劣势
  189. $inferiority++;
  190. } elseif (!is_null($v['a_price']) && is_null($v['b_price'])) {
  191. $no_show++;
  192. }
  193. }
  194. }
  195. }*/
  196. foreach ($competitiveness as $key => $value) {
  197. foreach ($value as $item) {
  198. if (empty($item)) {
  199. continue;
  200. }
  201. foreach ($item as $k => $v) {
  202. if (!is_null($v['a_price']) && !is_null($v['b_price']) && $v['inferiority'] == 2) { //劣势
  203. $inferiority++;
  204. }
  205. if (!is_null($v['a_price']) && is_null($v['b_price'])) {
  206. $no_show++;
  207. }
  208. if ($v['inferiority'] == 3) { //劣势
  209. $competitive++;
  210. }
  211. }
  212. }
  213. }
  214. }
  215. $lose = $inferiority + $no_show + $competitive;
  216. $price->inferiority = $inferiority;
  217. $price->no_show = $no_show;
  218. $price->competitive = $competitive;
  219. $price->lose = $lose;
  220. // return ['inferiority' => $inferiority, 'no_show' => $no_show, 'competitive' => $competitive, 'lose' => $lose];
  221. }
  222. /**
  223. * Author:Steven
  224. * Desc:比价数据处理
  225. * @param $ctrip_data
  226. * @param $price_conversion
  227. * @param $flag
  228. * @return array
  229. */
  230. public function ctripDataService($ctrip_data, $HOTEL_ID, $flag = true)
  231. {
  232. //查询当前有直连关系的房型ID
  233. $ctripHotelPrice = new CtripHotelPrice();
  234. $room_arr = $ctripHotelPrice->getRelationRoom($ctrip_data[0]['spider_hotel_id']);
  235. $room_list = [];
  236. foreach ($room_arr as $room) {
  237. $room_list[] = $room['channel_room_id'];
  238. }
  239. //a_表示携程 b_表示蜘蛛
  240. $arr = array();
  241. if ($flag) {
  242. $ctripHotelPrice = new CtripHotelPrice();
  243. $price_conversion = $ctripHotelPrice->getHotelConversion($HOTEL_ID);
  244. $price_conversion = $price_conversion[0];
  245. }
  246. foreach ($ctrip_data as $item) {
  247. $spider_price = $item['b_price'];
  248. $ctrip_price = $item['a_price'];
  249. $origin_spider_price = $item['b_price']; //用于记录没有折算价差的时候的价格
  250. $origin_ctrip_price = $item['a_price'];
  251. if ($flag) {//携程价格折算
  252. $remain_room_conversion = isset($price_conversion['remain_room_conversion']) ? $price_conversion['remain_room_conversion'] : 0;
  253. $breakfast_conversion = isset($price_conversion['breakfast_conversion']) ? $price_conversion['breakfast_conversion'] : 0;
  254. $cancel_rules_conversion = isset($price_conversion['cancel_rules_conversion']) ? $price_conversion['cancel_rules_conversion'] : 0;
  255. $pay_type_conversion = isset($price_conversion['pay_type_conversion']) ? $price_conversion['pay_type_conversion'] : 0;
  256. //早餐(非早餐类型的早餐折算) 以我们的价格为基数,加上或者减去早餐数之差*价差
  257. $ctrip_breakfast = $this->calBreakfastLevel($item['a_breakfast']);
  258. $spider_breakfast = $this->calBreakfastLevel($item['b_breakfast']);
  259. $spider_price = $spider_price - ($spider_breakfast - $ctrip_breakfast) * $breakfast_conversion;
  260. //别墅类型的早餐折算
  261. $ctrip_breakfast1 = $this->calbreakfast1($item['a_breakfast']);
  262. $spider_breakfast2 = $this->calbreakfast1($item['b_breakfast']);
  263. $ctrip_person = $this->number($item['a_room_person']);
  264. $spider_person = $this->number($item['b_room_person']);
  265. $spider_price = $spider_price + ($spider_breakfast2 * $spider_person - $ctrip_breakfast1 * $ctrip_person) * $breakfast_conversion;
  266. //现预付 蜘蛛是预付
  267. if ($item['a_payment_txt'] == '到店付' || $item['a_payment_txt'] == '担保') {//现付
  268. $ctrip_price = $ctrip_price - $pay_type_conversion;
  269. }
  270. //保留房
  271. $item['a_confirm_info'] == '立即确认' ? '' : $ctrip_price = $ctrip_price + $remain_room_conversion;
  272. $item['b_confirm_info'] == '立即确认' ? '' : $spider_price = $spider_price + $remain_room_conversion;
  273. //取消规则
  274. $item['a_room_policy'] == '免费取消' ? '' : $ctrip_price = $ctrip_price + $cancel_rules_conversion;
  275. $item['b_room_policy'] == '免费取消' ? '' : $spider_price = $spider_price + $cancel_rules_conversion;
  276. }
  277. if ($spider_price > $ctrip_price || is_null($item['b_price'])) { //蜘蛛价格为null时,即价格未在携程前台显示
  278. $room_type = preg_replace('/^([^\d]+).*/', '$1', str_replace(array("\r\n", "\r", " ", "\n"), "", $item['room_type']));
  279. $arr[$item['spider_hotel_id']][$room_type][$item['start_date']] = array(
  280. 'a_bed_type' => $item['a_bed_type'],
  281. 'b_bed_type' => $item['b_bed_type'],
  282. 'a_breakfast' => $item['a_breakfast'],
  283. 'b_breakfast' => $item['b_breakfast'],
  284. 'a_room_policy' => $item['a_room_policy'],
  285. 'b_room_policy' => $item['b_room_policy'],
  286. 'a_confirm_info' => $item['a_confirm_info'],
  287. 'b_confirm_info' => $item['b_confirm_info'],
  288. 'a_supply_id' => $item['a_supply_id'],
  289. 'a_showdow_id' => $item['a_showdow_id'],
  290. 'a_payment_txt' => $item['a_payment_txt'],
  291. 'b_payment_txt' => $item['b_payment_txt'],
  292. 'a_room_person' => $item['a_room_person'],
  293. 'b_room_person' => $item['b_room_person'],
  294. 'a_price' => $item['a_price'],
  295. 'b_price' => $item['b_price'],
  296. 'b_son_room_id' => $item['son_room_id'],
  297. 'inferiority' => 2,
  298. );
  299. if (($origin_spider_price < $origin_ctrip_price) && !is_null($item['b_price'])) { //这种属于竞争力不足
  300. $arr[$item['spider_hotel_id']][$room_type][$item['start_date']]['inferiority'] = 3;
  301. }
  302. //判断当前房型是不是直连的房型
  303. if (!in_array($item['son_room_id'], $room_list)) {
  304. unset($arr[$item['spider_hotel_id']][$room_type][$item['start_date']]);
  305. }
  306. }
  307. }
  308. //当某个房型下所有的日期,蜘蛛的数据都是空的,表明我们没有合作此房型
  309. foreach ($arr as $itmem_k => $item) {
  310. foreach ($item as $key => $value) {
  311. $i = 0;
  312. foreach ($value as $k => $v) {
  313. if (is_null($v['b_price'])) {
  314. $i++;
  315. if ($i == count($value)) {
  316. unset($arr[$itmem_k][$key]);
  317. }
  318. }
  319. }
  320. }
  321. }
  322. return $arr;
  323. }
  324. /**
  325. * User:Steven
  326. * Desc:计算早餐级别
  327. * @param $breakfast
  328. * @return int
  329. */
  330. public function calBreakfastLevel($breakfast)
  331. {
  332. switch ($breakfast) {
  333. case '无早':
  334. $breakfast_level = 0;
  335. break;
  336. case '每天单早':
  337. $breakfast_level = 1;
  338. break;
  339. case '每天双早':
  340. $breakfast_level = 2;
  341. break;
  342. case '每天三早':
  343. $breakfast_level = 3;
  344. break;
  345. case '每天四早':
  346. $breakfast_level = 4;
  347. break;
  348. case '每天五早':
  349. $breakfast_level = 5;
  350. break;
  351. case '每天六早':
  352. $breakfast_level = 6;
  353. break;
  354. case '每天七早':
  355. $breakfast_level = 7;
  356. break;
  357. case '每天八早':
  358. $breakfast_level = 8;
  359. break;
  360. case '每天九早':
  361. $breakfast_level = 9;
  362. break;
  363. case '每天十早':
  364. $breakfast_level = 10;
  365. break;
  366. default:
  367. $breakfast_level = 0;
  368. break;
  369. }
  370. return $breakfast_level;
  371. }
  372. /**
  373. * User:Steven
  374. * Desc:对于别墅类型的房,计算早餐个数的时候需要考虑到入住人数
  375. * @param $breakfast
  376. * @return int|string
  377. */
  378. public function calbreakfast1($breakfast)
  379. {
  380. $arr = array(1 => '一', 2 => '二', 3 => '三', 4 => '四', 5 => '五', 6 => '六', 7 => '七', 8 => '八', 9 => '九', 10 => '十', 11 => '十一', 12 => '十二');
  381. foreach ($arr as $k => $v) {
  382. if ($breakfast == '每天每人' . $v . '份早') {
  383. return $k;
  384. } else {
  385. return 0;
  386. }
  387. }
  388. }
  389. /**
  390. * User:Steven
  391. * Desc:获取字符串中的数字部分
  392. * @param $str
  393. * @return mixed
  394. */
  395. public function number($str)
  396. {
  397. return preg_replace('/\D/s', '', $str);
  398. }
  399. public function beforeSave($insert)
  400. {
  401. if ($this->isNewRecord) {
  402. $this->cancel_flag = 0;
  403. }
  404. return parent::beforeSave($insert);
  405. }
  406. }