|
- <?php
- /**
- * Created by PhpStorm.
- * User: Steven
- * Date: 2018/4/28
- * Time: 11:01
- */
-
- namespace backend\modules\hotel\models;
-
- use backend\common\Utils;
- use Yii;
- use yii\base\Model;
-
-
- use backend\modules\hotel\models\ChannelHotelMapping;
- use backend\modules\hotel\models\OperaRoomDistrib;
- use yii\filters\AccessControl;
- use yii\filters\ContentNegotiator;
- use yii\web\Response;
- use yii\helpers\Html;
- use yii\base\Module;
- use yii\httpclient\Client;
- use backend\modules\hotel\models\CtripCountryList;
- use backend\modules\hotel\models\CtripCityList;
- use backend\modules\hotel\models\CtripHotelList;
- use backend\modules\hotel\models\ChannelBaseRoomMapping;
- use backend\modules\hotel\models\OperaHotel;
- use yii\db\Exception;
- use yii\db\Expression;
- use yii\data\ActiveDataProvider;
-
- class CtripSwitch extends Model
- {
- public $masterHotelID; //母酒店ID
- public $hotelId; //子酒店ID
- public $masterBasicRoomTypeId; //母物理房型ID
- public $basicRoomTypeId; //子物理房型
- public $roomTypeId; //售卖房型,即子房型
- public $supplierID; //供应商ID 即代理通分配给我们的ID
- public $channel; //代理通 渠道
- public $roomStatus; //售卖房型上下线状态
-
- public $zz_room_id; //蜘蛛子房型ID
- public $zz_channel_id; //蜘蛛渠道ID
- public $zz_hotel_id; //蜘蛛酒店ID
- public $zz_base_room_id; //蜘蛛基础房型ID
-
- public $roomDataEntitys; // 房态推送数据实体
- public $start_date; // 房态房价日期范围开始日期
- public $end_date; // 房态房价日期范围结束日期
-
-
- public $ctripConf; //基础配置参数
-
- const SUCCESS_CODE = 0;
- const SYS_ERR0R = 100; //系统错误
- const CTRIP_HOTEL_CODE = 101; //携程创建子酒店失败
- const MASTER_HOTEL_EMPTY = 102; //母酒店ID不能为空
- const REPEAT_CREATE = 103; //该酒店已添加
- const MAPPING_HOTEL_ERROR = 104; //酒店关联失败
- const UNMAPPING_CODE = 105; //酒店未关联
- const PARAM_ERR0R = 106; //请求参数缺失
- const ADD_HOTEL_ERR = 107; //添加酒店信息失败
- const GET_MASTER_HOTEL_ERR = 108; //添加酒店信息失败
-
-
- const RETURN_MSG = [
- self::SUCCESS_CODE => 'success',
- self::CTRIP_HOTEL_CODE => '携程创建子酒店失败',
- self::SYS_ERR0R => '系统错误',
- self::MASTER_HOTEL_EMPTY => '母酒店ID不能为空',
- self::REPEAT_CREATE => '携程子酒店已创建,但cs系统不存在子酒店id',
- self::MAPPING_HOTEL_ERROR => '酒店关联失败',
- self::UNMAPPING_CODE => '请检查 Mapping 关系!',
- self::PARAM_ERR0R => '请求参数缺失',
- self::ADD_HOTEL_ERR => '添加酒店信息失败',
- self::GET_MASTER_HOTEL_ERR => '获取代理通酒店信息失败',
- ];
-
-
- const CTRIP_ID = 669; //携程
- const QUNAR_ID = 1667; //去哪
- const ELONG_ID = 1668; //艺龙
- const CHANNELA_ID = 1669; //分销A
- const B2B_ID = 1670; //b2b
-
- public function __construct(array $config = [])
- {
- $this->supplierID = Yii::$app->params['ctrip_switch']['switch_supplier_id'];
- $this->ctripConf = Yii::$app->params['ctrip_switch'];
- parent::__construct($config);
- }
-
- /**
- * Created by PhpStorm.
- * NOTES:设置场景
- * User: Steven
- * Date: 2018/4/28
- * Time: 11:11
- * Class scenarios
- * @return array
- */
- public function scenarios()
- {
- $scenarios = parent::scenarios();
- $scenarios['updateRoomSaleName'] = ['zz_room_id', 'zz_channel_id', 'zz_hotel_id'];
- $scenarios['setRoomOnlineOffline'] = ['zz_room_id', 'zz_channel_id', 'roomStatus'];
- $scenarios['CheckMapping'] = ['zz_hotel_id', 'zz_channel_id', 'zz_room_id']; // 验证的zz_room_id 实为room_type
- $scenarios['PushRoomData'] = ['zz_hotel_id', 'zz_room_id', 'zz_channel_id', 'roomDataEntitys'];
-
- return $scenarios;
- }
-
- /**
- * Created by PhpStorm.
- * NOTES:
- * User: Steven
- * Date: 2018/4/28
- * Time: 11:11
- * Class rules
- * @return array
- */
- public function rules()
- {
- return [
- //酒店试单
- [['zz_room_id', 'zz_channel_id', 'zz_hotel_id'], 'required', 'on' => ['updateRoomSaleName']],
- [['zz_room_id', 'zz_channel_id', 'roomStatus'], 'required', 'on' => ['setRoomOnlineOffline']],
- [['zz_hotel_id', 'zz_channel_id', 'zz_room_id'], 'required', 'on' => ['CheckMapping']],
- [['zz_hotel_id', 'zz_channel_id', 'zz_room_id', 'roomDataEntitys'], 'required', 'on' => ['CheckMapping']],
- ];
- }
-
- public function loadPushData($data, $formName = null)
- {
- $scope = $formName === null ? $this->formName() : $formName;
- if ($scope === '' && !empty($data)) {
- $this->setAttributes($data, false);
- if (!$this->getProductInfo()) {
- return false;
- }
-
- return true;
- } elseif (isset($data[$scope])) {
- $this->setAttributes($data[$scope]);
-
- return true;
- } else {
- return false;
- }
- }
-
-
- /**
- * Notes:request请求
- * User: Steven
- * Date: 2018/4/16
- * Time: 15:28
- * @param $target_url
- * @param $data
- * @return mixed
- */
- public function request($target_url, $data)
- {
- $data['requestor'] = $this->getCommonParams();
- $timestamp = $this->getTimestamp();
- $signature = $this->setSignature($this->ctripConf['switch_supplier_id'], $timestamp, $this->ctripConf['interfacekey']);
- $client = new Client(['baseUrl' => $this->ctripConf['base_url']]);
- $request = $client->createRequest()
- ->setHeaders(['content-type' => 'application/json;charset=UTF-8'])
- ->addHeaders(["timestamp" => $timestamp])
- ->addHeaders(['signature' => $signature])
- ->setFormat(Client::FORMAT_JSON)
- ->setMethod('post')
- ->setUrl($target_url)
- ->setData($data);
- $t1 = microtime(true);
- self::writeLog($target_url . '-' . $timestamp, json_encode($request->getData()));
- $response = $request->send();
- $t2 = microtime(true);
- self::writeLog($target_url . '-' . $timestamp . ' 耗时:' . round($t2 - $t1, 3) . 's', json_encode($response->getData()) . PHP_EOL);
- return json_decode($response->content);
- }
-
- /**
- * Notes:生成公共节点
- * User: Steven
- * Date: 2018/4/19
- * Time: 14:38
- * @return array
- */
- private function getCommonParams()
- {
- return [
- 'invoker' => $this->ctripConf['requestor']['invoker'],
- 'operatorName' => $this->ctripConf['requestor']['operatorName'],
- 'opClientIP' => $this->ctripConf['requestor']['opClientIP'],
- 'userId' => $this->ctripConf['requestor']['userId'],
- 'languageType' => $this->ctripConf['requestor']['languageType'],
- ];
- }
-
-
- /**
- * Notes:加密验证逻辑
- * User: Steven
- * Date: 2018/4/16
- * Time: 15:42
- * @param $supplierID //供应商ID,int类型
- * @param $timestamp
- * @param $interfacekey //密钥Key
- * @param $signature
- * @return bool
- */
- private function getSignature($supplierID, $timestamp, $interfacekey, $signature)
- {
- //加密算法是md5(base64)
- $signature_str = strtoupper(base64_encode(md5($supplierID . $timestamp . $interfacekey, true)));
-
- return $signature == $signature_str;
- }
-
- /**
- * Notes:生成加密串
- * User: Steven
- * Date: 2018/4/16
- * Time: 17:58
- * @param $supplierID
- * @param $timestamp
- * @param $interfacekey
- * @return string
- */
- private function setSignature($supplierID, $timestamp, $interfacekey)
- {
- //加密算法是md5(base64)
- $signature = strtoupper(base64_encode(md5($supplierID . $timestamp . $interfacekey, true)));
-
- return $signature;
- }
-
- /**
- * Notes:获取当前时间的毫秒数
- * User: Steven
- * Date: 2018/4/16
- * Time: 18:01
- * @return float
- */
- public function getTimestamp()
- {
- list($msec, $sec) = explode(' ', microtime());
- $msectime = (float)sprintf('%.0f', (floatval($msec) + floatval($sec)) * 1000);
-
- return $msectime;
- }
-
- /**
- * Created by PhpStorm.
- * NOTES:获取接口所需要的渠道ID
- * User: Steven
- * Date: 2018/4/27
- * Time: 16:25
- * Class getChannelID
- * @param $channel_str
- * @return string
- */
- public function getChannelID($channel_str)
- {
- $channel_arr = explode(',', $channel_str);
- $channel_id_str = '';
- foreach ($channel_arr as $value) {
- $channel_id_str .= $channel_id_str == '' ? '' : ',';
- switch ($value) {
- case self::CTRIP_ID:
- $channel_id_str .= 'Ctrip';
- break;
- case self::QUNAR_ID:
- $channel_id_str .= 'Qunar';
- break;
- case self::ELONG_ID:
- $channel_id_str .= 'Elong';
- break;
- case self::CHANNELA_ID:
- $channel_id_str .= 'ChannelA';
- break;
- case self::B2B_ID:
- $channel_id_str .= 'B2B';
- break;
- default:
- break;
- }
- }
-
- return $channel_id_str;
- }
-
- /**
- * Notes:根据代理通渠道标识获取CS蜘蛛渠道ID
- * User: Steven
- * Date: 2018/5/11
- * Time: 11:37
- * @param $dltOrderId
- * @return int
- */
- public static function SupplierDict($supplier_str)
- {
- //supplier:手工单,这种订单是人工在代理通录入的
- switch ($supplier_str) {
- case 'EBK':
- case 'Email':
- case 'SMS':
- case 'FAX':
- case 'DirectConn':
- case 'NotCtripOrder':
- return 669;
- break;
- case 'Elong':
- return 1668;
- break;
- case 'Qunar':
- return 1667;
- break;
- case 'B2B':
- case 'B2BOffLine':
- return 1670;
- break;
- case 'TC':
- return 1669;
- break;
- default:
- return 0;
- }
- }
-
- /**
- * Created by PhpStorm.
- * NOTES:批量插入数据
- * User: Steven
- * Date: 2018/4/20
- * Time: 11:37
- * Class batchInsert
- * @param $model 表名称
- * @param $table_key 表字段
- * @param $table_value 表字段的值
- * @return int 受影响行数
- * @throws yii\db\Exception
- */
- public function batchInsert($model, $table_key, $table_value)
- {
- $res = Yii::$app->db->createCommand()
- ->batchInsert($model, $table_key, $table_value)
- ->execute();
- $query = CtripCountryList::find()
- ->from('user')
- ->indexBy('username');
- $query->each();
-
- return $res;
- }
-
- /**
- * Notes:携程代理通直连请求日志
- * User: Steven
- * Date: 2018/5/22
- * Time: 16:00
- * @param $Invoketype
- * @param $string
- */
- public static function writeLog($Invoketype, $string)
- {
- $dir = "/../../../runtime/logs/ctripSwitchLog";
- $string = date('Y-m-d H:i:s') . " $Invoketype " . PHP_EOL . $string . PHP_EOL;
- if (!file_exists(__DIR__ . $dir)) {
- mkdir(__DIR__ . $dir, 0777, true);
- }
- file_put_contents(__DIR__ . $dir . '/' . date('Y-m-d') . '.log', $string, FILE_APPEND);
- }
-
- /**
- * @Author: wanglg
- * @DESC: 获取房型在某渠道的信息
- * @param $params // hotel_id,parent_room_type, room_type,channel_id, start_date, end_date
- * @return $this
- */
- public function getProductInfo()
- {
- // 查询某房型在一定日期段内的房态房价信息
- $products = OperaHotelRoom::find()
- ->leftJoin('opera_room_distrib b', 'a.ID=b.ROOM_ID and b.cancel_flag=0 and b.distrib_id=' . $this->zz_channel_id)
- ->leftJoin('run_hotel_distrib c', 'a.hotel_id=c.hotel_id and a.parent_room_type=c.base_room_type and a.room_type=c.room_type and c.distrib_id=b.distrib_id')
- ->leftJoin('run_hotel_sub_room d', 'a.hotel_id=d.hotel_id and a.parent_room_type=d.base_room_type and a.room_type=d.room_type and c.run_date=d.run_date')
- ->leftJoin('run_hotel e', 'a.hotel_id=e.hotel_id and a.parent_room_type=e.base_room_type and c.run_date=e.run_date')
- ->leftJoin('opera_hotel_gift f', 'c.gift_id=f.id and a.hotel_id=f.hotel_id and f.cancel_flag=0')
- ->from('opera_hotel_room a')
- ->where(['a.hotel_id' => $this->zz_hotel_id, 'a.parent_room_type' => $this->zz_base_room_id, 'a.room_type' => $this->zz_room_id, 'a.cancel_flag' => 0,]);
- $products->andWhere(['between', 'c.run_date', $this->start_date, $this->end_date]);
- $products->addSelect(['if(c.prod_price = 0, c.cus_price, c.prod_price) as room_price', 'a.breakfast_include', 'c.distrib_id', 'c.run_date', 'c.run_status', 'b.channel_mapping_id',
- 'c.oversell_flag', 'c.remaining_count', 'c.saled_count', 'b.latest_comfirm_time', 'b.distrib_room_name', 'b.authority_status', 'a.lastest_book_time',
- 'd.is_onsale as base_is_onsale', 'd.run_status as base_run_status', 'c.gift_id', 'f.gift_name', 'f.gift_content', 'e.is_onsale base_room_onsale',
- 'SUM(case e.stock_type when 228 then e.remaining_count else 0 end) as buyout',
- 'SUM(case e.stock_type when 229 then e.remaining_count else 0 end) as inquiry',
- 'SUM(case e.stock_type when 230 then e.remaining_count else 0 end) as retain',]);
- $products->groupBy('c.run_date');
- $res = $products->asArray()->all();
-
- foreach ($res as $key => $value) {
- // 获取渠道信息, 处理渠道名称,如果是推送房价、房态、动态规则,渠道名称首字母大写, Ctrip,Qunar, QunarB,QunarD,QunarY,QunarT ,Elong,B2B ,ChannelA,B2BOffline ,Share
- // 如果是房量,渠道名称全部为小写 ctrip,qunar,elong,manual
- $channel_price = $value['distrib_id'] == Yii::$app->params['ctrip']['supplier_id'] ? 'Ctrip' :
- ($value['distrib_id'] == Yii::$app->params['qunar']['supplier_id'] ? 'Qunar' :
- ($value['distrib_id'] == Yii::$app->params['elong']['supplier_id'] ? 'Elong' :
- ($value['distrib_id'] == Yii::$app->params['channela']['supplier_id'] ? 'ChannelA' :
- ($value['distrib_id'] == Yii::$app->params['channela']['supplier_id'] ? 'B2B' : ''))));
-
- $channel_quanity = $value['distrib_id'] == Yii::$app->params['ctrip']['supplier_id'] ? 'ctrip' :
- ($value['distrib_id'] == Yii::$app->params['qunar']['supplier_id'] ? 'qunar' :
- ($value['distrib_id'] == Yii::$app->params['elong']['supplier_id'] ? 'elong' :
- ($value['distrib_id'] == Yii::$app->params['channela']['supplier_id'] ? 'channela' :
- ($value['distrib_id'] == Yii::$app->params['channela']['supplier_id'] ? 'b2b' : ''))));
-
- if (!$channel_quanity || !$channel_price) {
- return false;
- }
- if ($value['base_run_status'] == 0 || $value['base_is_onsale'] == 0 || $value['run_status'] == 329 || $value['authority_status'] == 0) {
- $sale_status = 0;
- } else {
- if ($value['oversell_flag'] == 0) {
- $sale_status = $value['remaining_count'] <= 0 ? 0 : 2;
- } else {
- $sale_status = 1;
- }
- }
-
- $pre_quantity = $value['remaining_count'] <= 0 ? 0 : $value['remaining_count'];
- $data = [
- 'roomId' => (int)$value['channel_mapping_id'],
- 'startDate' => $value['run_date'],
- 'endDate' => $value['run_date'],
- 'weekDayIndex' => '1111111', //依次周一值周日,为1设置生效为0不生效
- 'roomPriceModel' => [ //房价信息
- 'roomPrice' => (float)$value['room_price'],
- 'tax' => (float)0,
- 'currency' => 'CNY',
- 'breakfast' => (int)$value['breakfast_include'],
- 'channel' => $channel_price,
- ],
- 'roomStatusModel' => [ // 房态信息
- 'saleStatus' => (int)$sale_status, // 0. 满房 1. 销售 2. 限量
- 'channel' => $channel_price,
- ],
- 'roomInventoryModel' => [ // 房量信息
- 'preservedQuantity' => (int)$pre_quantity, // 保留房数量
- 'unPreservedQuantity' => (int)($value['buyout'] + $value['inquiry'] + $value['retain'] - $pre_quantity), //非保留房数量
- 'autoCloseRoom' => 0, // 自动关房
- 'channel' => $channel_quanity, // 渠道
- ],
- 'saleRuleModel' => [
- 'channel' => $channel_price,
- ],
- ];
-
- // 如果当前渠道是b2b 或 channelA ,动态售卖规则中的 礼盒信息和最晚立即确认时间不能同时为空
- if (empty($value['gift_id']) && $value['latest_comfirm_time'] == -1 && (strtolower($channel_price) == 'b2b' || strtolower($channel_quanity) == 'channela')) {
- return false;
- }
- if (!empty($value['gift_id'])) {
- $data['saleRuleModel']['roomGiftRule'] = [ // 礼盒规则
- 'giftId' => $value['gift_id'], // 礼盒ID
- 'takeEffectType' => 1, //1:入住生效 2:离店生效 3:在店生效
- 'giftDesc' => $value['distrib_id'] == Yii::$app->params['ctrip']['supplier_id'] ? $value['gift_content'] : '', // 礼盒信息
- ];
- }
-
- // 如果有设置渠道最晚预订时间推送相关信息
- if ($value['latest_comfirm_time'] != -1) {
- $last_confirm = explode(',', $value['latest_comfirm_time']);
- if ($value['distrib_id'] != Yii::$app->params['ctrip']['supplier_id']) {
- $last_book_time = explode(',', $value['lastest_book_time']);
- $data['saleRuleModel']['ctripSellRule'] = [
- 'latestconfirmTimeOfDays' => $last_confirm[0],
- 'latestconfirmTimeOfHours' => Utils::timeHour($last_confirm[1]),
- 'latestBookingTimeOfDays' => $last_book_time[0],
- 'latestBookingTimeOfHours' => Utils::timeHour($last_book_time[1]),
- 'cancelType' => 1,
- ];
- } else {
- $data['saleRuleModel']['sellingRule'] = [
- 'latestconfirmTimeOfDays' => (int)$last_confirm[0],
- 'latestconfirmTimeOfHours' => Utils::timeHour($last_confirm[1]),
- ];
- }
- }
-
- $this->roomDataEntitys[] = $data;
- }
-
- return $this;
- }
-
- /**
- * @Author: wanglg
- * @DESC:判断酒店、房型、基础房型是否直连
- * @param :hotel_id 酒店ID
- * @param :room_type 子房型type
- * @param :channel_id 关联渠道ID:可不传,默认为携程
- * @return array
- */
- public function isMapping($hotel_id, $room_type = 0, $channel_id = 669)
- {
- // 判断渠道
- $request = ['zz_channel_id' => $channel_id, 'zz_hotel_id' => $hotel_id, 'zz_room_id' => $room_type];
- $request['zz_channel_id'] = empty($request['zz_channel_id']) ? Yii::$app->params['ctrip']['supplier_id'] : $request['zz_channel_id'];
- $model = new CtripSwitch(['scenario' => 'CheckMapping']);
- if (!$model->load($request, '') || !$model->validate()) {
- return ['code' => CtripSwitch::PARAM_ERR0R, 'msg' => CtripSwitch::RETURN_MSG[CtripSwitch::PARAM_ERR0R]];
- }
- $query = ChannelHotelMapping::find()
- ->select(['a.sub_hotel_id'])
- ->from('channel_hotel_mapping a')->where(['a.hotel_id' => $model->zz_hotel_id, 'a.channel_id' => $model->zz_channel_id, 'a.cancel_flag' => 0]);
-
- // 子房型type不为空,关联查询子房型是否直连
- if (!empty($model->zz_room_id)) {
- $query->addSelect(['b.sub_base_room_id', 'd.channel_mapping_id']);
- $query->leftJoin('opera_hotel_room c', 'a.hotel_id=c.hotel_id and c.room_type=' . $model->zz_room_id)
- ->leftJoin('channel_base_room_mapping b', 'b.base_room_id=c.parent_room_type and b.cancel_flag=0 and a.sub_hotel_id=b.sub_hotel_id and a.channel_id=b.channel_id and a.hotel_id=b.hotel_id and a.master_hotel_id = b.master_hotel_id')
- ->leftJoin('opera_room_distrib d', 'd.room_id=c.id and d.distrib_id=a.channel_id');
- }
-
- $mapping_res = $query->asArray()->one();
-
- // 代理通酒店id未查到说明酒店未直连
- if (empty($mapping_res['sub_hotel_id'])) {
- return ['code' => CtripSwitch::UNMAPPING_CODE, 'msg' => CtripSwitch::RETURN_MSG[CtripSwitch::UNMAPPING_CODE]];
- }
-
- // 存在子房型但是结果集中没有查到代理通售卖房型id,说明子房型未直连
- if (!empty($model->zz_room_id) && (empty($mapping_res['channel_mapping_id']) || empty($mapping_res['sub_base_room_id']))) {
- return ['code' => CtripSwitch::UNMAPPING_CODE, 'msg' => CtripSwitch::RETURN_MSG[CtripSwitch::UNMAPPING_CODE]];
- }
-
- // 成功,返回直连id
- return ['code' => CtripSwitch::SUCCESS_CODE, 'msg' => CtripSwitch::RETURN_MSG[CtripSwitch::SUCCESS_CODE], 'data' => $mapping_res];
- }
-
-
- /**
- * Notes:根据携程酒店ID ,房型ID 查找mapping 的蜘蛛Id
- * User: Steven
- * Date: 2018/5/11
- * Time: 19:38
- */
- public static function getZzIDByCtripID($distrib_id, $room_id)
- {
- $res = OperaRoomDistrib::find()->select(['b.HOTEL_ID', 'b.ID as ROOM_ID'])
- ->leftJoin('opera_hotel_room b', 'a.ROOM_ID=b.ID')
- ->from('opera_room_distrib a')
- ->where(['a.CHANNEL_MAPPING_ID' => 37138191, 'a.DISTRIB_ID' => 669, 'a.CANCEL_FLAG' => 0, 'b.CANCEL_FLAG' => 0])
- ->asArray()->one();
- return $res;
- }
-
-
- /**
- * @Author: wanglg
- * @DESC:通过传入需要处理的周天数据,例如 周二周三[2, 3]
- * @param $week_arr
- * @return array
- */
- public function weekDays($week_arr)
- {
- $init_arr = array(0, 0, 0, 0, 0, 0, 0);
- foreach ($week_arr as $value) {
- $init_arr[$value - 1] = 1;
- }
- return $init_arr;
- }
-
- }
|