'预定成功', self::RESPONSE_SOLDOUT => '满房', self::RESPONSE_CUSTORM => '自定义原因', self::RESPONSE_PRICEERROR => '价格校验失败', self::RESPONSE_SYSERROR => '系统异常', self::RESPONSE_REPEATBOOK => '重复预定', self::RESPONSE_NOT_HOTEL_ID => '酒店ID不存在', self::RESPONSE_NOT_ROOM_TYPE => '房型不存在', self::RESPONSE_NOT_RATE_PLAN => '价格政策不存在', self::RESPONSE_PARAM_ERROR => '参数错误', ]; public $room_type; //下单辅助参数 public $cus_list = ''; public $new_room_list = ''; public $zz_order_id; //蜘蛛订单号 public $apiParas = array(); /** * @inheritdoc */ public static function tableName() { return '{{%ali_order}}'; } /** * Author:Steven * Desc:设置场景 * @return array */ public function scenarios() { return [ //酒店试单 'ValidateRQ' => ['TaoBaoHotelId', 'HotelId', 'TaoBaoRoomTypeId', 'RoomTypeId', 'TaoBaoRatePlanId', 'RatePlanCode', 'TaoBaoGid', 'CheckIn', 'CheckOut', 'RoomNum', 'CustomerNumber', 'PaymentType', 'Extensions' ], //创建订单 'BookRQ' => ['TaoBaoOrderId', 'TaoBaoHotelId', 'HotelId', 'TaoBaoRoomTypeId', 'RoomTypeId', 'TaoBaoRatePlanId', 'RatePlanCode', 'Channel', 'TaoBaoGid', 'CheckIn', 'CheckOut', 'HourRent', 'EarliestArriveTime', 'LatestArriveTime', 'RoomNum', 'Occupancy', 'PriceType', 'IsMorningBuy', 'InventoryType', 'TotalPrice', 'OtherFee', 'PaidPrice', 'TotalSellerPromotion', 'Currency', 'PaymentType', 'ContactName', 'ContactTel', 'ContactEmail', 'DailyInfos', 'OriDailyInfos', 'DisDailyInfos', 'TravelInfo', 'OrderGuests', 'Comment', 'GuaranteeType', 'MemberInfo', 'AlipayTradeNo', 'VoucherInfos', 'CreditCardInfo', 'InvoiceInfo', 'PackageInfos', 'Extensions', 'zz_order_id' ], ]; } /** * @inheritdoc */ public function rules() { return [ //酒店试单 [['TaoBaoHotelId', 'HotelId', 'TaoBaoRoomTypeId', 'RoomTypeId', 'TaoBaoRatePlanId', 'RatePlanCode', 'TaoBaoGid', 'CheckIn', 'CheckOut', 'RoomNum', 'CustomerNumber', 'PaymentType'], 'required', 'on' => ['ValidateRQ']], [['HotelId', 'RoomTypeId', 'RatePlanCode', ''], 'string', 'max' => 64, 'on' => ['ValidateRQ']], [['RoomNum', 'CustomerNumber'], 'integer', 'min' => 1, 'max' => 9, 'message' => '入住人数或房间数量超限', 'on' => ['ValidateRQ']], // [['CustomerNumber'], 'match', 'pattern' => '/^[1-9]{1}$/', 'message' => '入住人数超限', 'on' => ['ValidateRQ']], [['CheckIn', 'CheckOut'], 'date', 'format' => 'yyyy-mm-dd', 'on' => ['ValidateRQ']], //创建订单 [['TaoBaoOrderId', 'TaoBaoHotelId', 'HotelId', 'TaoBaoRoomTypeId', 'RoomTypeId', 'TaoBaoRatePlanId', 'RatePlanCode', 'CheckIn', 'CheckOut', 'EarliestArriveTime', 'LatestArriveTime', 'RoomNum', 'Occupancy', 'TotalPrice', 'Currency', 'PaymentType', 'ContactName', 'ContactTel', 'DailyInfos', 'OrderGuests'], 'required', 'on' => ['BookRQ']], [['HotelId', 'RoomTypeId', 'RatePlanCode'], 'string', 'max' => 64, 'on' => ['BookRQ']], [['TaoBaoHotelId'], 'validateOrderExist', 'on' => ['BookRQ']], [['RatePlanCode'], 'validateDiret'], [['CreateTime', 'CheckIn', 'CheckOut', 'EarliestArriveTime', 'LatestArriveTime', 'OrderId', 'zz_order_id'], 'safe'], [['TaoBaoHotelId', 'HotelId', 'TaoBaoRoomTypeId', 'RoomTypeId', 'TaoBaoRatePlanId', 'RatePlanCode', 'TaoBaoGid', 'EarliestArriveTime', 'LatestArriveTime', 'Occupancy'], 'required'], // [['RoomNum', 'Occupancy', 'PriceType', 'IsMorningBuy', 'InventoryType', 'PaymentType', 'GuaranteeType'], 'integer'], ]; } /** * @inheritdoc */ public function attributeLabels() { return [ 'ID' => 'ID', 'CreateTime' => '创建时间', 'TaoBaoOrderId' => '淘宝订单id', 'TaoBaoHotelId' => '淘宝酒店id', 'OrderId' => '蜘蛛订单号', 'HotelId' => 'OTA酒店id,这里即我们系统中的酒店id', 'TaoBaoRoomTypeId' => '淘宝房型id', 'RoomTypeId' => 'OTA房型id,即我们系统中的房型id', 'TaoBaoRatePlanId' => '淘宝价格计划id', 'RatePlanCode' => 'OTA价格计划id,即opera_hotel_room中的id', 'Channel' => '酒店投放渠道 阿里协议价: 阿里员工 : A ;HRS商旅价: 阿里员工 + 阿里商旅用户 : A,O;公开价: 阿里员工 + 阿里商旅用户 + 飞猪用户:A,O,H', 'TaoBaoGid' => '淘宝酒店商品ID', 'CheckIn' => '入住时间', 'CheckOut' => '离店时间', 'HourRent' => '小时房(时间取Checkin/Checkout对应的具体时间)', 'EarliestArriveTime' => '最早到店时间', 'LatestArriveTime' => '最晚到店时间', 'RoomNum' => '房间数量(最大为9)', 'Occupancy' => '入住人数,目前支持一笔订单最多入住人数15。例如别墅订单存在多人的情况', 'PriceType' => '下单使用的价格类型:0默认值;1变价订单价格标记', 'IsMorningBuy' => '是否为凌晨房,0不是,1是,默认0', 'InventoryType' => '下单使用的库存类型:0.未知;1限售库存;2保留房库存;3物理库存;4超预定库存', 'TotalPrice' => '订单总价(分)', 'OtherFee' => '授权杂费金额(分)', 'PaidPrice' => '已付金额(预付和在线预约场景下启用)', 'TotalSellerPromotion' => '卖家优惠总金额', 'GTPrice' => '订单担保金额(担保订单场景下启用)', 'Currency' => '货币类型(现在只支持一种)', 'PaymentType' => '支付方式1预付、5面付、6后付(现在只有1、5、6)', 'ContactName' => '联系人姓名', 'ContactTel' => '联系人电话', 'ContactEmail' => '联系人邮箱', 'DailyInfos' => '每日价格', 'OriDailyInfos' => '每日原始价格 当存在卖家优惠的时候启用', 'DisDailyInfos' => '每日折扣价格 当存在卖家优惠的时候启动', 'TravelInfo' => 'Travel Info', 'OrderGuests' => '入住人信息', 'Comment' => '开票项目 一段文本(例如:代订房费、住宿费、会议费、旅游费等)', 'GuaranteeType' => '担保类型 0 无担保 1 峰时首晚担保 2峰时全额担保 3全天首晚担保 4全天全额担保', 'MemberInfo' => 'Member Info', 'AlipayTradeNo' => '支付宝交易号,只有预付的先付款后下单会有这个', 'VoucherInfos' => '订单优惠节点 当订单中含有优惠(房券/代金券/立减等)', 'CreditCardInfo' => 'Credit Card Info', 'InvoiceInfo' => 'Invoice Info', 'PackageInfos' => 'Package Infos', 'Extensions' => '扩展字段json,用于处理特殊OTA个性需求添加的扩展字段 {\"key\":\"value\"} 一些优惠信息等在扩展字段中传递', 'CustomerNumber' => 'Customer Number', ]; } /** * Author:Steven * Desc:自定义setAttributes * @param array $values * @param bool $safeOnly */ /*public function setAttributes($values, $safeOnly = true) { if (is_array($values)) { $attributes = array_flip($safeOnly ? $this->safeAttributes() : $this->attributes()); foreach ($values as $name => $value) { if (isset($attributes[$name])) { if (is_array($value) && !empty($value)) { $this->$name = json_encode($value); } else { $this->$name = $value; } } elseif ($safeOnly) { $this->onUnsafeAttribute($name, $value); } } } }*/ /** * Author:Steven * Desc:加载数据 主要用于阿里创建订单 * @param $data * @param null $formName * @return bool */ /*public function load($data, $formName = null) { $scope = $formName === null ? $this->formName() : $formName; if ($scope === '' && !empty($data)) { $this->setAttributes($data, false); //构造下单需要的参数 $this->cus_list = "{{$this->ContactName}{$this->ContactEmail}," . ($this->ContactTel) . "," . Yii::$app->params['ali']['base_user_id'] . "|" . time() . "|0|{$this->Comment}}"; $supplier = BaseSupplier::findOne(['ID' => Yii::$app->params['ali']['supplier_id']]); if ($supplier == null) { return false; } $commissionRule = $supplier->getCommissionRule(BaseSupplierSale::SALE_HOTEL); if ($commissionRule != null && $commissionRule->COMMISION_TYPE == BaseSupplierSale::TYPE_CHANNEL) { $base_com = $commissionRule->BACK_PERCENT; } else if ($commissionRule == null) { $this->addError('Channel', '没有对应渠道销售'); return false; } else { $base_com = 0; $this->Spider_sale_type = $commissionRule->SALE_TYPE; } if (isset($this->DailyInfos['DailyInfo'])) { foreach ($this->DailyInfos['DailyInfo'] as $DailyInfo) { $commission = ($base_com * $DailyInfo['Price']) / 100; $this->new_room_list .= "{''" . $DailyInfo['Day'] . "''," . $this->RoomNum . "," . $DailyInfo['Price'] . "," . $this->RoomNum * $commission . "}"; } } return true; } elseif (isset($data[$scope])) { $this->setAttributes($data[$scope]); return true; } else { return false; } }*/ /** * Author:Steven * Desc:加载数据 主要用于阿里创建订单 * @param $data * @param null $formName * @return bool */ public function loadBook($data, $formName = null) { $scope = $formName === null ? $this->formName() : $formName; if ($scope === '' && !empty($data)) { $this->setAttributes($data, false); //构造下单需要的参数 $this->cus_list = "{{$this->ContactName}{$this->ContactEmail}," . ($this->ContactTel) . "," . Yii::$app->params['ali']['base_user_id'] . "|" . time() . "|0|{$this->Comment}}"; $supplier = \common\models\BaseSupplier::findOne(['ID' => Yii::$app->params['ali']['supplier_id']]); if ($supplier == null) { return false; } $commissionRule = $supplier->getCommissionRule(BaseSupplierSale::SALE_HOTEL); if ($commissionRule != null && $commissionRule->COMMISION_TYPE == BaseSupplierSale::TYPE_CHANNEL) { $base_com = $commissionRule->BACK_PERCENT; } else if ($commissionRule == null) { $this->addError('Channel', '没有对应渠道销售'); return false; } else { $base_com = 0; $this->Spider_sale_type = $commissionRule->SALE_TYPE; } if (isset($this->DailyInfos['DailyInfo'])) { foreach ($this->DailyInfos['DailyInfo'] as $DailyInfo) { $commission = ($base_com * $DailyInfo['Price']) / 100; $this->new_room_list .= "{''" . $DailyInfo['Day'] . "''," . $this->RoomNum . "," . $DailyInfo['Price'] . "," . $this->RoomNum * $commission . "}"; } } return true; } elseif (isset($data[$scope])) { $this->setAttributes($data[$scope]); return true; } else { return false; } } /** * Author:Steven * Desc:验证订单是否存在,避免重复下单 * @param $attribute * @param $params */ public function validateOrderExist($attribute, $params) { $res = OrderMain::find()->where([ 'OUTSIDE_ORDER_NO' => "{$this->TaoBaoOrderId}", 'ORDER_PROD_TYPE' => OrderMain::ORDER_PROD_TYPE_MAIN, 'PARENT_ORDER_ID' => 0, 'CANCEL_FLAG' => 0 ])->limit(1)->asArray()->one(); if (!empty($res)) { $this->addError($attribute, self::RESPONSE_REPEATBOOK); } } /** * Author:Steven * Desc:判断是都符合直连需求 验证酒店、房型、RP等信息的有效性 * @return bool */ public function validateDiret($attribute, $params) { $model = OperaHotelRoom::find()->select(['a.ID', 'a.HOTEL_ID', 'a.PARENT_ROOM_TYPE', 'a.ROOM_TYPE', 'c.ChannelHotelId', 'b.ChannelRoomId', 'a.RP_ID']) ->leftJoin('channel_room_relation b', 'a.PARENT_ROOM_TYPE=RoomId and b.ChannelId=' . Yii::$app->params['ali']['relation_supplier_id']) ->leftJoin('channel_hotel_relation c', 'a.HOTEL_ID=c.HotelId and c.ChannelId=' . Yii::$app->params['ali']['relation_supplier_id']) ->from('opera_hotel_room a') ->where([ 'a.ID' => $this->RatePlanCode ])->asArray()->one(); if (empty($model) || $model['HOTEL_ID'] != $this->HotelId || $model['ChannelHotelId'] != $this->TaoBaoHotelId) { $this->addError($attribute, self::RESPONSE_NOT_HOTEL_ID); } elseif ($model['PARENT_ROOM_TYPE'] != $this->RoomTypeId || $model['ChannelRoomId'] != $this->TaoBaoRoomTypeId) { $this->addError($attribute, self::RESPONSE_NOT_ROOM_TYPE); } elseif ($model['RP_ID'] != $this->TaoBaoRatePlanId) { $this->addError($attribute, self::RESPONSE_NOT_RATE_PLAN); } $this->room_type = $model['ROOM_TYPE']; //在验证的时候顺便初始化子房型ID return true; } /** * Notes:阿里酒店下单接口 * User: Steven * Date: 2018/1/16 * Time: 11:43 * @return mixed * @throws \yii\db\Exception */ public function bookOrder() { $params = [ 'CreateUserID' => Yii::$app->params['ali']['base_user_id'], 'OrderID' => $this->TaoBaoOrderId, //渠道订单号 'HotelID' => $this->HotelId, //酒店ID 'RoomID' => $this->RatePlanCode, //房型ID 'DistribID' => Yii::$app->params['ali']['supplier_id'],//渠道ID 'RoomNum' => $this->RoomNum, //房间数量 'CheckIn' => $this->CheckIn, //入住日期 'CheckOut' => $this->CheckOut, //离店日期, 'TotalPrice' => $this->TotalPrice / 100,//订单总价 'Currency' => $this->Currency == 'CNY' ? 'RMB' : '', //币种 'ContactName' => $this->ContactName,//联系人姓名 'ContactTel' => $this->ContactTel, //联系人电话 'PayType' => CommonOrder::PAY_TYPE_CREDIT, // 638:支付宝支付; 221:现金支付 ;275:授信支付;278:微信支付 'PayTradeNo' => $this->AlipayTradeNo, //支付流水号 'OrderGuests' => $this->getGuestsName(), //入住人信息 'CommentType' => 2, //公共备注 'Comment' => empty($this->Comment) ? '' : $this->Comment, //客人备注 'NeedInvoice' => empty($this->InvoiceInfo['NeedInvoice']) ? 0 : $this->InvoiceInfo['NeedInvoice'], 'InvoiceInfos' => $this->InvoiceInfo, 'RoomPrices' => $this->getRoomPrices(), 'OrderTitleID' => 0 ]; $new_order = new CommonOrder(['scenario' => 'BookHotelOrder']); if ($new_order->load($params, '') && $new_order->validate()) { $res = $new_order->bookHotelOrder(); if ($res['code'] == CommonOrder::RETURN_CODE_SUCCESS) { $this->zz_order_id = $res['data']['order_id']; return self::RESPONSE_SUCCESS; } $return_code = self::RESPONSE_SYSERROR; if ($res['code'] == CommonOrder::RETURN_CODE_UNAUTHORIZED || $res['code'] == CommonOrder::RETURN_CODE_ROOM_CLOSED || $res['code'] == CommonOrder::RETURN_CODE_STOCK_FAIL) { $return_code = self::RESPONSE_SOLDOUT; } if ($res['code'] == CommonOrder::RETURN_CODE_PRICE_FAIL) { return self::RESPONSE_PRICEERROR; } if ($res['code'] == CommonOrder::RETURN_CODE_PROGRAM_FAIL) { return self::RESPONSE_SYSERROR; } return $return_code; } else { $error = array_values($new_order->getFirstErrors()); return self::RESPONSE_SYSERROR; } } /** * Author:Steven * Desc:验证产品是否可定 * @param $attribute * @param $params */ public function validateBook() { $end_date = date('Y-m-d', strtotime("-1 day", strtotime($this->CheckOut))); $data = RunHotelDistrib::getAvailProduct($this->RatePlanCode, $this->CheckIn, $end_date); $dailyInventory_flag = true; //房型是否可定标识 $precisDailyPrice_flag = true; //价格是否正确标识 foreach ($data as $item) { $dailyInventory[] = [ 'date' => $item['RUN_DATE'], 'inventory' => 0 ]; $precisDailyPrice[] = [ 'date' => $item['RUN_DATE'], 'price' => $item['PROD_PRICE'] * 100 ]; if ($item['RUN_STATUS'] == 329 || $item['AUTHORITY_STATUS'] == 0 || $item['ROOM_RUN_STATUS'] == 0 || $item['ROOM_IS_ONSALE'] == 0 || $item['IS_ONSALE'] == 0 || $this->RoomNum > $item['REMAINING_COUNT']) { //检查是否关 //表示满房 $dailyInventory_flag = false; $dailyInventory['reason'] = '满房'; } //需要校验价格是否正确 // $DailyInfos = json_decode($this->DailyInfos, true); $dailyInfo = isset($this->DailyInfos['DailyInfo'][0]) ? $this->DailyInfos['DailyInfo'] : $this->DailyInfos; foreach ($dailyInfo as $value) { if ($value['Day'] == $item['RUN_DATE']) { if ($item['PROD_PRICE'] * 100 != $value['Price']) { //价格(分) $precisDailyPrice_flag = false; $precisDailyPrice['reason'] = '价格校验失败'; } } } } if (!$dailyInventory_flag || empty($data)) { return ['ResultCode' => '-' . self::RESPONSE_SOLDOUT, 'Message' => json_encode($dailyInventory)]; } if (!$precisDailyPrice_flag) { return ['ResultCode' => '-' . self::RESPONSE_PRICEERROR, 'Message' => json_encode($precisDailyPrice)]; } return ['ResultCode' => self::RESPONSE_SUCCESS, 'Message' => '']; } /** * Notes:获取入住人的信息 * User: Steven * Date: 2018/1/25 * Time: 14:30 * @return array */ public function getGuestsName() { $Guest_arr = []; $OrderGuests = isset($this->OrderGuests['OrderGuest']['Name']) ? $this->OrderGuests : $this->OrderGuests['OrderGuest']; foreach ($OrderGuests as $OrderGuest) { $Guest_arr[] = [ 'Name' => $OrderGuest['Name'] ]; } if (empty($Guest_arr)) { $Guest_arr[0] = [ 'Name' => $this->ContactName ]; } return $Guest_arr; } /** * Notes: * User: Steven * Date: 2018/1/16 * Time: 15:52 */ public function getRoomPrices() { $room_prices = []; $DailyInfos = isset($this->DailyInfos['DailyInfo']['Day']) ? $this->DailyInfos : $this->DailyInfos['DailyInfo']; foreach ($DailyInfos as $item) { $room_prices[] = [ 'RunDate' => $item['Day'], 'Price' => $item['Price'] / 100 ]; } return $room_prices; } public function beforeSave($insert) { if ($this->isNewRecord) { $this->CreateTime = date('Y-m-d H:i:s', time()); $this->OrderGuests = is_array($this->OrderGuests) ? json_encode($this->OrderGuests) : $this->OrderGuests; $this->InvoiceInfo = is_array($this->InvoiceInfo) ? json_encode($this->InvoiceInfo) : $this->InvoiceInfo; $this->DailyInfos = is_array($this->DailyInfos) ? json_encode($this->DailyInfos) : $this->DailyInfos; } return parent::beforeSave($insert); } }