You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

853 lines
40 KiB

  1. <?php
  2. /**
  3. * Created by PhpStorm.
  4. * User: wangxj
  5. * Date: 2017/4/12
  6. * Time: 13:54
  7. * $OrderID, $InterFaceSendID, $Hotel, $HotelName, $Arrival, $Departure,
  8. * $EarlyArrivalTime, $LastArrivalTime, $Person, $Notice, $IsHoldRoom,
  9. * $IsFlashLive, $Guests, $MobilePhone, $Currency, $Amount, $CNYAmount, $GuaranteeType, $BalanceType,
  10. * $Room, $RoomPerson, $RoomName, $Quantity, $CostAmount, $CNYCostAmount,
  11. * $RoomPrices, $AddOptionals, $InterFaceConfirmNo, $HotelConfirmNo, $InterFaceAmount, $ReturnCode, $ReturnDescript,
  12. * $OrderStatus, $FGToPP, $DepositAmount, $IsFreeSale
  13. */
  14. namespace backend\modules\hotel\models;
  15. use backend\common\Utils;
  16. use Yii;
  17. use common\models\BaseSupplierSale;
  18. use yii\base\Model;
  19. use yii\db\Exception;
  20. use backend\modules\api\logic\BaseBalance;
  21. /**
  22. * Class CtripOrder
  23. * @package backend\modules\hotel\models
  24. *
  25. * @property string $OrderID
  26. * @property string $OldOrderID
  27. * @property string $Ori_OrderID
  28. * @property string $InterFaceConfirmNO
  29. * @property string $ClientName
  30. * @property string $InterFaceSendID
  31. * @property string $Hotel
  32. * @property string $HotelName
  33. * @property string $Arrival
  34. * @property string $Departure,
  35. * @property string $EarlyArrivalTime
  36. * @property string $LastArrivalTime
  37. * @property string $Person
  38. * @property string $Notice
  39. * @property string $IF_LAST_PROD
  40. * @property string $IsHoldRoom,
  41. * @property string $IsFlashLive
  42. * @property array $Guests
  43. * @property string $MobilePhone
  44. * @property string $Currency
  45. * @property string $Amount
  46. * @property string $CNYAmount
  47. * @property string $GuaranteeType
  48. * @property string $BalanceType,
  49. * @property string $Room
  50. * @property string $RoomPerson
  51. * @property string $RoomName
  52. * @property string $Quantity
  53. * @property string $CostAmount
  54. * @property string $CNYCostAmount,
  55. * @property array $RoomPrices
  56. * @property string $AddOptionals
  57. * @property string $InterFaceConfirmNo
  58. * @property string $HotelConfirmNo
  59. * @property string $InterFaceAmount
  60. * @property string $ReturnCode
  61. * @property string $ReturnDescript,
  62. * @property string $OrderStatus
  63. * @property string $FGToPP
  64. * @property string $DepositAmount
  65. * @property string $IsFreeSale
  66. * @property string $Spider_order_id
  67. *
  68. */
  69. class CtripOrder extends Model
  70. {
  71. const ORDER_DOCKING_TYPE = 556; // 对接进来的订单
  72. const ORDER_STATUS_WAITING = 550; //待处理
  73. const ORDER_STATUS_ACCEPT = 551; //已接单
  74. const ORDER_STATUS_REJECT = 552; //已拒绝
  75. const ORDER_STATUS_CANCEL_APPLY = 553; //申请取消
  76. const ORDER_STATUS_CANCEL_REJECT = 554; //取消被拒
  77. const ORDER_STATUS_CANCEL_ACCEPT = 563; //已取消
  78. public $relation_supplier_id;
  79. public $OrderID;
  80. public $OldOrderID;
  81. public $Ori_OrderID;
  82. public $InterFaceConfirmNO;
  83. public $ClientName;
  84. public $InterFaceSendID;
  85. public $Hotel;
  86. public $Spider_hotel; //蜘蛛的酒店id,opera_hotel HOTEL_ID
  87. public $HotelName;
  88. public $Arrival;
  89. public $Departure;
  90. public $EarlyArrivalTime;
  91. public $LastArrivalTime;
  92. public $Person;
  93. public $Notice;
  94. public $IF_LAST_PROD = 1; //礼盒为2
  95. public $IsHoldRoom;
  96. public $IsFlashLive;
  97. public $Guests;
  98. public $MobilePhone;
  99. public $Currency;
  100. public $Amount;
  101. public $CNYAmount;
  102. public $GuaranteeType = 9999; //担保类型 无限制
  103. public $BalanceType = 'PP'; //支付方式 预付
  104. public $Room;
  105. public $Spider_room; //蜘蛛的房型id,opera_hotel_room ID
  106. public $Spider_parent_room_type; //蜘蛛的房型id,opera_hotel_room PARENT_ROOM_TYPE
  107. public $Spider_room_type; //蜘蛛的房型id,opera_hotel_room ROOM_TYPE
  108. public $Spider_sale_type; //渠道的销售方式
  109. public $Spider_order_id; //渠道的销售方式
  110. public $RoomPerson;
  111. public $RoomName;
  112. public $Quantity;
  113. public $CostAmount;
  114. public $CNYCostAmount;
  115. public $RoomPrices;
  116. public $CNYPrice;
  117. public $CNYCost;
  118. public $AddOptionals;
  119. public $InterFaceConfirmNo;
  120. public $HotelConfirmNo;
  121. public $InterFaceAmount;
  122. public $ReturnCode;
  123. public $ReturnDescript;
  124. public $OrderStatus;
  125. public $FGToPP;
  126. public $DepositAmount;
  127. public $IsFreeSale;
  128. public $RoomNumber;
  129. public $cus_list = '';
  130. public $room_list = '';
  131. public $new_room_list = '';
  132. public $white_list_flag = null;
  133. //返回值 该返回值为标准返回码,对渠道而言,需要根据渠道需要的
  134. const RETURN_CODE_SUCCESS = 0; //操作成功
  135. const RETURN_CODE_CANCEL_FAIL = 100; //取消失败/异常
  136. const RETURN_CODE_STOCK_FAIL = 101; //酒店满房/房量不足
  137. const RETURN_CODE_NOTICE_FAIL = 102; //备注不接受
  138. const RETURN_CODE_PRICE_FAIL = 103; //价格错误
  139. const RETURN_CODE_DATE_FAIL = 104; //日期错误/日期超过最大入住天数
  140. const RETURN_CODE_CHECKOUT = 105; //已入住不允许取消或修改
  141. const RETURN_CODE_EXPIRED = 106; //已过最晚取消修改时间
  142. const RETURN_CODE_NOT_EXIST = 107; //修改/取消原订单不存在
  143. const RETURN_CODE_PROGRAM_FAIL = 108; //程序错误
  144. const RETURN_CODE_NETWORK_FAIL = 109; //网络问题(程序错误)
  145. const RETURN_CODE_GUARANTEE_FAIL = 110; //担保错误
  146. const RETURN_CODE_HOTEL_CLOSED = 111; //酒店已停止合作
  147. const RETURN_CODE_MAPPING_FAIL = 112; //直连匹配错误(程序错误)
  148. const RETURN_CODE_REPEAT = 113; //重复预订
  149. const RETURN_CODE_NEED_TOTAL_GUARANTEE = 114; // 需要全额担保
  150. const RETURN_CODE_OVER_NUM = 115; //人数超限
  151. const RETURN_CODE_OVER_STOCK = 116; //客人当天累计已超间,请提供担保 重新预订
  152. const RETURN_CODE_SYSTEM_FAIL = 117; //服务器运行错误(程序错误)
  153. const RETURN_CODE_AUTH_FAIL = 118; //用户认证或授权错误(程序错误)
  154. const RETURN_CODE_PARAMS_FAIL = 119; //参数错误(程序错误)
  155. const RETURN_CODE_INFO_FAIL = 120; //预订信息不正确
  156. const RETURN_CODE_NOT_ALLOW_UPDATE = 121; //订单不允许修改
  157. const RETURN_CODE_NOT_ALLOW_CANCEL = 122; //订单不允许取消
  158. const RETURN_CODE_NEED_ALL_GUARANTEE = 123; //需要一律担保
  159. const RETURN_CODE_BREAKFAST_FAIL = 124; //早餐不一致
  160. const RETURN_CODE_CURRENCY_FAIL = 125; //币种错误
  161. const RETURN_CODE_UNAUTHORIZED = 126; //渠道未授权
  162. const RETURN_CODE_ROOM_CLOSED = 127; //房型已下线
  163. const RETURN_CODE_OTHER = 9999; //其他
  164. //携程可订检查返回code
  165. const RETURN_CODE_CHCEK_STOCK_FAIL = 1000;
  166. const RETURN_CODE_CHCEK_STOCK_LESS = 1001;
  167. const RETURN_CODE_CHCEK_NO_ROOM_STATUS = 1002;
  168. const RETURN_CODE_CHCEK_PRICE_FAIL = 1003;
  169. const RETURN_CODE_CHCEK_API_TIMEOUT = 1004;
  170. const RETURN_CODE_CHCEK_CANNOT_ANALYZE = 1005;
  171. const RETURN_CODE_CHCEK_RMB_FAIL = 1006;
  172. const RETURN_CODE_CHCEK_DATE_FAIL = 1007;
  173. const RETURN_CODE_CHCEK_UNKNOWN = 1008;
  174. //返回给渠道的订单状态
  175. const ORDER_STATUS_COMFIRMING = 1; //待确认 已发送到合作方,确认中
  176. const ORDER_STATUS_FAIL = 2; //失败 订单未发送到合作方或返回代码 为失败
  177. const ORDER_STATUS_COMFIRMED = 3; // 确认订单
  178. const ORDER_STATUS_REFUSED = 4; //拒绝订单
  179. CONST RETURN_MSG = [
  180. self::RETURN_CODE_SUCCESS => '操作成功',
  181. self::RETURN_CODE_CANCEL_FAIL => '取消失败/异常',
  182. self::RETURN_CODE_STOCK_FAIL => '酒店满房/房量不足',
  183. self::RETURN_CODE_NOTICE_FAIL => '备注不接受',
  184. self::RETURN_CODE_PRICE_FAIL => '价格错误',
  185. self::RETURN_CODE_DATE_FAIL => '日期错误/日期超过最大入住天数',
  186. self::RETURN_CODE_CHECKOUT => '已入住不允许取消或修改',
  187. self::RETURN_CODE_EXPIRED => '已过最晚取消修改时间',
  188. self::RETURN_CODE_NOT_EXIST => '修改/取消原订单不存在',
  189. self::RETURN_CODE_PROGRAM_FAIL => '程序错误',
  190. self::RETURN_CODE_NETWORK_FAIL => '网络问题(程序错误)',
  191. self::RETURN_CODE_GUARANTEE_FAIL => '担保错误',
  192. self::RETURN_CODE_HOTEL_CLOSED => '酒店已停止合作/酒店已停售/下架',
  193. self::RETURN_CODE_MAPPING_FAIL => '直连匹配错误(程序错误)',
  194. self::RETURN_CODE_REPEAT => '重复预定',
  195. self::RETURN_CODE_NEED_TOTAL_GUARANTEE => '需要全额担保',
  196. self::RETURN_CODE_OVER_NUM => '人数超限',
  197. self::RETURN_CODE_OVER_STOCK => '客人当天累计已超间,请提供担保 重新预订',
  198. self::RETURN_CODE_SYSTEM_FAIL => '服务器运行错误(程序错误)',
  199. self::RETURN_CODE_AUTH_FAIL => '用户认证或授权错误(程序错误)',
  200. self::RETURN_CODE_PARAMS_FAIL => '参数错误(程序错误)',
  201. self::RETURN_CODE_INFO_FAIL => '预订信息不正确',
  202. self::RETURN_CODE_NOT_ALLOW_UPDATE => '订单不允许修改',
  203. self::RETURN_CODE_NOT_ALLOW_CANCEL => '订单不允许取消',
  204. self::RETURN_CODE_NEED_ALL_GUARANTEE => '需要一律担保',
  205. self::RETURN_CODE_BREAKFAST_FAIL => '早餐不一致',
  206. self::RETURN_CODE_CURRENCY_FAIL => '币种错误',
  207. self::RETURN_CODE_UNAUTHORIZED => '该渠道未授权',
  208. self::RETURN_CODE_CURRENCY_FAIL => '币种错误',
  209. self::RETURN_CODE_ROOM_CLOSED => '房型已下线',
  210. self:: RETURN_CODE_OTHER => '其他'
  211. ];
  212. public function __construct(array $config = [])
  213. {
  214. $this->relation_supplier_id = Yii::$app->params['ctrip']['relation_supplier_id'];
  215. parent::__construct($config);
  216. }
  217. public function rules()
  218. {
  219. return [
  220. [['OrderID', 'InterFaceSendID', 'Hotel', 'HotelName', 'Arrival', 'Departure',
  221. 'EarlyArrivalTime', 'LastArrivalTime', 'Person',
  222. 'Amount', 'CNYAmount', 'Room', 'RoomPerson', 'RoomName',
  223. 'Quantity', 'CostAmount', 'CNYCostAmount', 'RoomPrices',], 'required', 'on' => ['new-order']],
  224. [['Spider_hotel', 'Spider_room'], 'required', 'on' => ['new-order']],
  225. ['Currency', 'validateCurrency', 'params' => ['message' => '币种验证失败。'], 'on' => ['new-order']],
  226. ['CNYCostAmount', 'validateCNYCostAmount', 'params' => ['message' => '价格错误'], 'on' => ['new-order']],
  227. ['IsHoldRoom', 'validateHoldRoom', 'params' => ['message' => '无保留房'], 'on' => ['new-order']],
  228. ['spider_hotel', 'validateSpider', 'params' => ['message' => 'mapping失败'], 'on' => ['new-order']],
  229. [['Hotel', 'Arrival', 'Departure', 'Room', 'RoomNumber', 'Currency', 'Person', 'BalanceType', 'IsHoldRoom'], 'required', 'on' => ['check-room-avail']],
  230. ];
  231. }
  232. /**
  233. * @inheritdoc
  234. */
  235. public function scenarios()
  236. {
  237. $scenarios['new-order'] = ['OrderID', 'InterFaceSendID', 'Hotel', 'HotelName', 'Arrival', 'Departure',
  238. 'EarlyArrivalTime', 'LastArrivalTime', 'Person', 'Notice', 'IsHoldRoom', 'MobilePhone', 'Currency',
  239. 'Amount', 'CNYAmount', 'GuaranteeType', 'BalanceType', 'Room', 'RoomPerson', 'RoomName', 'Spider_hotel', 'Spider_room',
  240. 'Quantity', 'CostAmount', 'CNYCostAmount',];
  241. $scenarios['check-room-avail'] = ['Hotel', 'Arrival', 'Departure', 'Room', 'Currency', 'RoomNumber', 'Person', 'BlanceType', 'IsHoldRoom', 'RoomPrices', 'EffectDate', 'CNYCost', 'BreakFast'];
  242. $scenarios['cancel-order'] = ['OrderID', 'InterFaceSendID', 'Hotel', 'HotelName', 'Arrival', 'Departure',
  243. 'EarlyArrivalTime', 'LastArrivalTime', 'Person', 'Notice', 'IsHoldRoom', 'MobilePhone', 'Currency',
  244. 'Amount', 'CNYAmount', 'GuaranteeType', 'BalanceType', 'Room', 'RoomPerson', 'RoomName', 'Spider_hotel', 'Spider_room',
  245. 'Quantity', 'CostAmount', 'CNYCostAmount',];
  246. $scenarios['order-status'] = ['OrderID', 'InterFaceSendID'];
  247. return $scenarios;
  248. }
  249. /**
  250. * User: wangxj
  251. *
  252. * 加载数据
  253. *
  254. * @param array $data
  255. * @param null $formName
  256. * @return bool
  257. */
  258. public function load($data, $formName = null)
  259. {
  260. $scope = $formName === null ? $this->formName() : $formName;
  261. if ($scope === '' && !empty($data)) {
  262. $this->setAttributes($data, false);
  263. $this->Arrival = substr($this->Arrival, 0, 10);
  264. $this->Departure = substr($this->Departure, 0, 10);
  265. //mapping酒店 id和房型id
  266. $this->Spider_hotel = HotelRelation::getSpiderId($this->Hotel, $this->relation_supplier_id);
  267. $this->Spider_room = RoomRelation::getSpiderId($this->Room, $this->relation_supplier_id);
  268. $room = OperaHotelRoom::findOne($this->Spider_room);
  269. if ($room != null) {
  270. $this->Spider_room_type = $room->ROOM_TYPE;
  271. $this->Spider_parent_room_type = $room->PARENT_ROOM_TYPE;
  272. }
  273. $supplier = \common\models\BaseSupplier::findOne(['ID' => \Yii::$app->params['ctrip']['supplier_id']]);
  274. if ($supplier == null) {
  275. return false;
  276. }
  277. $commissionRule = $supplier->getCommissionRule(BaseSupplierSale::SALE_HOTEL);
  278. if ($commissionRule != null && $commissionRule->COMMISION_TYPE == BaseSupplierSale::TYPE_CHANNEL) {
  279. $base_com = $commissionRule->BACK_PERCENT;
  280. $this->Spider_sale_type = $commissionRule->SALE_TYPE;
  281. } else if ($commissionRule == null) {
  282. $this->addError('Spider_sale_type', '没有对应渠道销售');
  283. return false;
  284. } else {
  285. $base_com = 0;
  286. $this->Spider_sale_type = $commissionRule->SALE_TYPE;
  287. }
  288. /*$customer_name = CtripOrder::getGuestsName($this->Guests);
  289. // $guests = isset($this->Guests['GuestEntity'][0]) ? $this->Guests['GuestEntity'] : $this->Guests;
  290. // if (is_array($guests)) {
  291. // foreach ($guests as $GuestEntity) {
  292. // $FirstName = empty($GuestEntity['FirstName']) ? '' : $GuestEntity['FirstName'];
  293. // $LastName = empty($GuestEntity['LastName']) ? '' : $GuestEntity['LastName'];
  294. // if ($customer_name == '' || (strstr($GuestEntity['ChinesName'], trim($customer_name)) == false && strstr(($FirstName . ' ' . $LastName), trim($customer_name)) == false)) {
  295. // $customer_name .= empty($GuestEntity['ChinesName']) ? ($FirstName . ' ' . $LastName) : $GuestEntity['ChinesName'] . ' ';
  296. // }
  297. // }
  298. // }
  299. //对接的电话号码都是假的,不存
  300. $this->MobilePhone = '';
  301. $customer_name = trim($customer_name); //630 临时携程账号
  302. $customer_name = str_replace(',', ',', $customer_name);*/
  303. //xml simplexml_load_string json_decode会把空字符串转换为空数组,而不是空字符串
  304. /* if (empty($this->Notice) || (is_array($this->Notice) && trim($this->Notice[0]) == '')) {
  305. /* $this->Notice = '';
  306. $this->cus_list = "{{$customer_name}," . ($this->MobilePhone) . ",}";
  307. } else {
  308. $this->Notice = str_replace(',', ',', $this->Notice);
  309. $this->Notice = str_replace('|', ',', $this->Notice);
  310. $this->Notice = trim(str_replace(';', ';', $this->Notice));
  311. if (strpos($this->Notice, '礼盒') >= 0) {
  312. $this->IF_LAST_PROD = 2;
  313. }
  314. // $this->cus_list = "{{$customer_name}," . ($this->MobilePhone) . "," . Yii::$app->params['ctrip']['base_user_id'] . "|" . time() . "|0|{$this->Notice}}";
  315. }
  316. $supplier = BaseSupplier::findOne(['ID' => \Yii::$app->params['ctrip']['supplier_id']]);
  317. if ($supplier == null) {
  318. return false;
  319. }
  320. $commissionRule = $supplier->getCommissionRule(BaseSupplierSale::SALE_HOTEL);
  321. if ($commissionRule != null && $commissionRule->COMMISION_TYPE == BaseSupplierSale::TYPE_CHANNEL) {
  322. $base_com = $commissionRule->BACK_PERCENT;
  323. $this->Spider_sale_type = $commissionRule->SALE_TYPE;
  324. } else if ($commissionRule == null) {
  325. $this->addError('Spider_sale_type', '没有对应渠道销售');
  326. return false;
  327. } else {
  328. $base_com = 0;
  329. $this->Spider_sale_type = $commissionRule->SALE_TYPE;
  330. }
  331. $roomPrices = isset($this->RoomPrices['RoomPrice'][0]) ? $this->RoomPrices['RoomPrice'] : $this->RoomPrices;
  332. if (!empty($roomPrices)) {
  333. $date = array_column($roomPrices, 'EffectDate');
  334. array_multisort($date, SORT_ASC, $roomPrices);
  335. if (is_array($roomPrices)) {
  336. foreach ($roomPrices as $RoomPrice) { //每个RoomPrice对应一天价格
  337. $EffectDate = substr($RoomPrice['EffectDate'], 0, 10);
  338. // $Price = $RoomPrice['Price']; //订单卖价金额(原币种),预付一般不传或者传0
  339. // $CNYPrice = $RoomPrice['CNYPrice']; //订单卖价金额(人民币),预付一般不传或者传0
  340. // $Cost = $RoomPrice['Cost']; //订单底价金额(原币种),现付一般不传或者传0
  341. $CNYCost = $RoomPrice['Cost']; //-订单底价金额(人民币),现付一般不传或者传0
  342. // $BreakFast = $RoomPrice['BreakFast']; //早餐数量
  343. $commission = $base_com * $CNYCost / 100;
  344. $this->new_room_list .= "{''" . $EffectDate . "''," . $this->Quantity . "," . $CNYCost . "," . $this->Quantity * $commission . "}";
  345. }
  346. }
  347. }*/
  348. $spider_order = OrderMain::findOne(['CANCEL_FLAG' => 0, 'OUTSIDE_ORDER_NO' => $this->OrderID, 'PARENT_PROD_ID' => $this->Spider_hotel]);
  349. if ($spider_order != null) {
  350. $this->Spider_order_id = $spider_order->ORDER_ID;
  351. }
  352. return true;
  353. } elseif (isset($data[$scope])) {
  354. $this->setAttributes($data[$scope]);
  355. return true;
  356. } else {
  357. return false;
  358. }
  359. }
  360. /**
  361. * User:Steven
  362. * Desc:加载可定检查的相关数据
  363. * @param $data
  364. * @param null $formName
  365. * @return bool
  366. */
  367. public function load_valid($data, $formName = null)
  368. {
  369. $scope = $formName === null ? $this->formName() : $formName;
  370. if ($scope === '' && !empty($data)) {
  371. $this->setAttributes($data, false);
  372. //mapping酒店 id和房型id
  373. $this->Spider_hotel = HotelRelation::getSpiderId($this->Hotel, $this->relation_supplier_id);
  374. $this->Spider_room = RoomRelation::getSpiderId($this->Room, $this->relation_supplier_id);
  375. $this->Spider_room_type = OperaHotelRoom::getSpiderRoomType($this->Room);
  376. return true;
  377. } elseif (isset($data[$scope])) {
  378. $this->setAttributes($data[$scope]);
  379. return true;
  380. } else {
  381. return false;
  382. }
  383. }
  384. /**
  385. * User:Steven
  386. * Desc:可定检查
  387. * param $roomInfo
  388. * @return array|\yii\db\ActiveRecord[]
  389. */
  390. public function CheckRoomAvail()
  391. {
  392. $model = new RunHotelDistrib();
  393. $roomInfo['hotel_id'] = $this->Spider_hotel;
  394. $roomInfo['room_id'] = $this->Spider_room;
  395. $roomInfo['room_prices'] = $this->RoomPrices;
  396. $roomInfo['Arrival'] = $this->Arrival;
  397. $roomInfo['Departure'] = $this->Departure;
  398. $res = $model->CheckRoomAvail($roomInfo);
  399. return $res;
  400. }
  401. /**
  402. * Notes:生成携程订单
  403. * User: Steven
  404. * Date: 2018/1/10
  405. * Time: 18:00
  406. * @throws Exception
  407. */
  408. public function makeOrder()
  409. {
  410. $params = [
  411. 'CreateUserID' => Yii::$app->params['ctrip']['base_user_id'],
  412. 'OrderID' => $this->OrderID, //渠道订单号
  413. 'HotelID' => $this->Spider_hotel, //酒店ID
  414. 'RoomID' => $this->Spider_room, //房型ID
  415. 'DistribID' => Yii::$app->params['ctrip']['supplier_id'],//渠道ID
  416. 'RoomNum' => $this->Quantity, //房间数量
  417. 'CheckIn' => $this->Arrival, //入住日期
  418. 'CheckOut' => $this->Departure, //离店日期,
  419. 'TotalPrice' => $this->CostAmount,//订单总价
  420. 'Currency' => $this->Currency, //币种
  421. 'ContactName' => '',//联系人姓名
  422. 'ContactTel' => '', //联系人电话
  423. 'PayType' => CommonOrder::PAY_TYPE_CREDIT, // 638:支付宝支付; 221:现金支付 ;275:授信支付;278:微信支付
  424. 'PayTradeNo' => '', //支付流水号
  425. 'OrderGuests' => CtripOrder::getGuestsName($this->Guests), //入住人信息
  426. 'Comment' => $this->Notice, //客人备注
  427. 'NeedInvoice' => 0,
  428. 'InvoiceInfos' => [ //发票信息
  429. ],
  430. 'RoomPrices' => CtripOrder::getRoomPrices($this->RoomPrices),
  431. 'OrderTitleID' => 0
  432. ];
  433. $new_order = new CommonOrder(['scenario' => 'BookHotelOrder']);
  434. if ($new_order->load($params, '') && $new_order->validate()) {
  435. $res = $new_order->bookHotelOrder();
  436. if ($res['code'] == CommonOrder::RETURN_CODE_SUCCESS) {
  437. $this->Spider_order_id = $res['data']['order_id'];
  438. return self::RETURN_CODE_SUCCESS;
  439. }
  440. $return_code = self::RETURN_CODE_PROGRAM_FAIL; //程序错误
  441. if ($res['code'] == CommonOrder::RETURN_CODE_UNAUTHORIZED || $res['code'] == CommonOrder::RETURN_CODE_ROOM_CLOSED ||
  442. $res['code'] == CommonOrder::RETURN_CODE_STOCK_FAIL) {
  443. $return_code = self::RETURN_CODE_STOCK_FAIL; //酒店满房/房量不足
  444. }
  445. if ($res['code'] == CommonOrder::RETURN_CODE_PRICE_FAIL) {
  446. return self::RETURN_CODE_PRICE_FAIL; //价格错误
  447. }
  448. if ($res['code'] == CommonOrder::RETURN_CODE_PROGRAM_FAIL) {
  449. return self::RETURN_CODE_PROGRAM_FAIL; //程序错误
  450. }
  451. return $return_code;
  452. } else {
  453. $error = array_values($new_order->getFirstErrors());
  454. //TODO:通知
  455. return self::RETURN_CODE_PROGRAM_FAIL;
  456. }
  457. }
  458. /**
  459. * User: wangxj
  460. *
  461. * 取消订单
  462. *
  463. * @return array|false
  464. */
  465. /*public function cancelOrder()
  466. {
  467. $user_id = Yii::$app->params['ctrip']['base_user_id'];
  468. //最后一个参数是cancel_flag,旧的下单逻辑,如果是修改导致的取消,cancel_flag置为4
  469. $sql = "CALL ht_cancel_order(" . $user_id . "," . $this->Spider_order_id . ",1)";
  470. $db = Yii::$app->db;
  471. $result = $db->createCommand($sql)->queryOne();
  472. //供应商余额
  473. $model = new BaseBalance($this->Spider_order_id, 2, '取消还款');
  474. $sup_data = $model->cancelBalanceMain();
  475. $model->addLog($sup_data);
  476. return $result;
  477. }*/
  478. /**
  479. * Notes:携程取消订单
  480. * User: Steven
  481. * Date: 2018/1/12
  482. * Time: 17:50
  483. * @return array|int
  484. * @throws Exception
  485. * @throws \Exception
  486. */
  487. public function applyCancel()
  488. {
  489. $order = OrderMain::findOne([
  490. 'cancel_flag' => 0,
  491. 'PARENT_PROD_ID' => $this->Spider_hotel,
  492. 'OUTSIDE_ORDER_NO' => $this->OrderID,
  493. 'DOCKING_TYPE' => OrderMain::ORDER_TYPE_CHANNEL,
  494. 'PARENT_ORDER_ID' => 0
  495. ]);
  496. if (empty($order)) { //订单不存在
  497. return self::RETURN_CODE_NOT_EXIST;
  498. }
  499. if ($order->CHANNEL_ORDER_STATUS == OrderMain::ORDER_CHANNEL_STATUS_APPLY_CANCEL_CONFIRMED) { //渠道接单状态是已取消 ,依然返回同意取消
  500. $this->saveLog(2, '渠道状态已经变更为已取消,二次取消,同意取消' . "[{$order->CHANNEL_ORDER_STATUS}]/[{$order->ORDER_STATUS}]");
  501. return self::RETURN_CODE_SUCCESS;
  502. }
  503. $white_list = OrderHtExceptionList::find()->where(['order_id' => $order->ORDER_ID])->one();
  504. if ($white_list != null) { //加入白名单的直接同意取消即可
  505. if ($white_list->status == OrderHtExceptionList::AGREE_CANCEL) { //同意取消
  506. $channel_status = OrderMain::ORDER_CHANNEL_STATUS_APPLY_CANCEL_CONFIRMED;
  507. } else { //拒绝取消
  508. $channel_status = OrderMain::ORDER_CHANNEL_STATUS_APPLY_CANCEL_REJECT;
  509. }
  510. //变更渠道的订单状态为已取消,但是不取消订单,即不回退库存,发人工退改申请
  511. $count = OrderMain::updateAll(['CHANNEL_ORDER_STATUS' => $channel_status, 'UPDATE_TIME' => date('Y-m-d H:i:s', time())],
  512. ['ORDER_PROD_TYPE' => [25, 26], 'CANCEL_FLAG' => 0, 'OUTSIDE_ORDER_NO' => $this->OrderID, 'DOCKING_TYPE' => OrderMain::ORDER_TYPE_CHANNEL]);
  513. if ($count == 0) {
  514. throw new \Exception();
  515. }
  516. if ($channel_status == OrderMain::ORDER_CHANNEL_STATUS_APPLY_CANCEL_CONFIRMED) {
  517. $this->saveLog(2, '该订单已加入白名单,白名单类型:同意取消,同意渠道取消。' . "[{$order->CHANNEL_ORDER_STATUS}]/[{$order->ORDER_STATUS}]");
  518. return self::RETURN_CODE_SUCCESS;
  519. } else {
  520. $this->saveLog(2, '该订单已加入白名单,白名单类型:拒绝取消,拒绝渠道取消。' . "[{$order->CHANNEL_ORDER_STATUS}]/[{$order->ORDER_STATUS}]");
  521. return self::RETURN_CODE_NOT_ALLOW_CANCEL;
  522. }
  523. }
  524. //白名单的订单不需要在这里直接取消订单,先同意渠道取消订单,然后人工发退改申请
  525. $rs = $this->validateCancel($order);
  526. if (!$rs || $order->CHANNEL_ORDER_STATUS != OrderMain::ORDER_CHANNEL_STATUS_WAITING ||
  527. !in_array($order->ORDER_STATUS, [OrderMain::ORDER_STATUS_NO_PAID, OrderMain::ORDER_STATUS_WAITING_SEND, OrderMain::ORDER_STATUS_WAITING_CONFIRM])) { //该情况不能退单
  528. $this->saveLog(2, '拒绝渠道取消。' . "[{$order->CHANNEL_ORDER_STATUS}]/[{$order->ORDER_STATUS}]");
  529. return self::RETURN_CODE_NOT_ALLOW_CANCEL;
  530. }
  531. $transaction = Yii::$app->db->beginTransaction();
  532. try {
  533. //日志
  534. $this->saveLog(2, '同意渠道取消。' . "[{$order->CHANNEL_ORDER_STATUS}]/[{$order->ORDER_STATUS}]");
  535. //我们没有发单给酒店,订单状态直接变为已取消,根据订单库存类型,
  536. //1、订单状态改为已取消
  537. //2、回退库存
  538. //对于已发单待安排的订单(这种情况如果直接取消的话,需要客服告知酒店需要取消,避免不必要的沟通麻烦),不需要直接取消订单,由客服操作取消,并且这个状态下酒店是不能确认订单的
  539. if ($order->ORDER_STATUS == OrderMain::ORDER_STATUS_WAITING_SEND) { //待发单 (携程无待支付状态,所以不需要要判断) 需要直接取消订单
  540. $order->ORDER_STATUS = OrderMain::ORDER_STATUS_CANCEL;
  541. $order->ORDER_VALID_STATUS = 0;
  542. $cancel = $order->rollbackStocks();
  543. if (!$cancel) {
  544. throw new \Exception();
  545. }
  546. //供应商余额
  547. /* $model = new BaseBalance($order->ORDER_ID, 2, '取消还款');
  548. $sup_data = $model->cancelBalanceMain();
  549. $model->addLog($sup_data);*/
  550. }
  551. $count = OrderMain::updateAll(['CHANNEL_ORDER_STATUS' => OrderMain::ORDER_CHANNEL_STATUS_APPLY_CANCEL_CONFIRMED, 'ORDER_VALID_STATUS' => $order->ORDER_VALID_STATUS,
  552. 'ORDER_STATUS' => $order->ORDER_STATUS, 'UPDATE_TIME' => date('Y-m-d H:i:s', time())],
  553. ['ORDER_PROD_TYPE' => [25, 26], 'CANCEL_FLAG' => 0, 'OUTSIDE_ORDER_NO' => $this->OrderID, 'DOCKING_TYPE' => OrderMain::ORDER_TYPE_CHANNEL]);
  554. if ($count == 0) {
  555. throw new \Exception();
  556. }
  557. $orderComment = new OrderComment();
  558. $orderComment->ORDER_ID = $order->ORDER_ID;
  559. $orderComment->COMMENT_TYPE = OrderComment::TYPE_CANCEL_NOTE;
  560. $orderComment->COMMENT_TXT = $this->Notice;
  561. $orderComment->CREATE_USER_ID = Yii::$app->params['ctrip']['base_user_id'];
  562. $orderComment->UPDATE_USER_ID = Yii::$app->params['ctrip']['base_user_id'];
  563. $orderComment->save();
  564. $transaction->commit();
  565. return self::RETURN_CODE_SUCCESS;
  566. } catch (Exception $exception) {
  567. $transaction->rollBack();
  568. return self::RETURN_CODE_CANCEL_FAIL;
  569. }
  570. //
  571. /*if ($order != null && $rs || ($this->white_list_flag != null && $this->white_list_flag == 1)) {
  572. // $timeMinutes = (time() - strtotime($order->CREATE_TIME)) / 60;
  573. if ($order->CHANNEL_ORDER_STATUS == OrderMain::ORDER_CHANNEL_STATUS_APPLY_CANCEL_CONFIRMED) { //渠道接单状态是已取消 ,依然返回同意取消
  574. $this->saveLog(2, '渠道状态已经变更为已取消,二次取消,同意取消');
  575. return ['code' => 1, 'data' => $order];
  576. }
  577. if (
  578. (
  579. //15分钟内,渠道状态未接单 直接取消
  580. ($order->CHANNEL_ORDER_STATUS != OrderMain::ORDER_CHANNEL_STATUS_WAITING) //非待接单状态 不能取消
  581. && //待支付、待确认、
  582. (in_array($order->ORDER_STATUS, [OrderMain::ORDER_STATUS_CONFIRMED, OrderMain::ORDER_STATUS_FINISH, OrderMain::ORDER_STATUS_CANCEL]) //已确认、已完成、已取消
  583. || $order->CHANNEL_ORDER_STATUS == OrderMain::ORDER_CHANNEL_STATUS_APPLY_CANCEL_REJECT //取消被拒 已经拒绝的也不允许取消
  584. || ($this->white_list_flag != null && $this->white_list_flag == 2)
  585. || ($order->CHANNEL_ORDER_STATUS != OrderMain::ORDER_CHANNEL_STATUS_WAITING) //如果渠道接单状态为待处理,可以直接取消
  586. )) && //白名单
  587. ($this->white_list_flag == null || ($this->white_list_flag != null && $this->white_list_flag == 2)) //白名单为拒绝取消也不能取消 2:拒绝取消
  588. ) {
  589. return ['code' => 2, 'msg' => '不符合取消规则,拒绝取消'];
  590. } else {
  591. }
  592. } else {
  593. $this->saveLog(2, '拒绝渠道取消' . ',validateCancel:' . !empty($rs) . 'order对象:' . !empty($order));
  594. return ['code' => 2, 'msg' => '不符合取消规则,拒绝取消'];
  595. }*/
  596. }
  597. /**
  598. * User:Steven
  599. * Desc:获取订单状态
  600. */
  601. public function getOrderStatus()
  602. {
  603. $query = OrderMain::find()->select(['CHANNEL_ORDER_STATUS', 'ORDER_STATUS', 'ORDER_ID'])->where(['OUTSIDE_ORDER_NO' => $this->OrderID, 'PARENT_ORDER_ID' => 0])->asArray()->one();
  604. return $query;
  605. }
  606. /**
  607. * User: wangxj
  608. *
  609. * 验证币种是否正确
  610. *
  611. * @param $attribute string
  612. * @param $params array
  613. *
  614. */
  615. public function validateCurrency($attribute, $params)
  616. {
  617. if ($this->$attribute != null && $this->$attribute != Yii::$app->params['ctrip']['currency_type']) {
  618. $this->addError('Currency', self::RETURN_CODE_CURRENCY_FAIL);
  619. }
  620. }
  621. /**
  622. * User: wangxj
  623. *
  624. * 验证是否可以取消
  625. * 根据时间判断是否可以取消
  626. * 未接单的订单全部返回取消成功;已接单15分钟内,返回取消成功;已接单超过15分钟,且在最晚取消时间内,返回成功;
  627. * 已接单超过15分钟,超过最晚取消时间,返回失败
  628. *
  629. * @param OrderMain $order
  630. *
  631. * @return bool
  632. *
  633. */
  634. public function validateCancel($order)
  635. {
  636. //这里现在不需要进行酒店和房型的验证,由于携程修改订单(取消+新订)的时候,取消的时候传入的修改后订单的room_id等信息
  637. //Ctrip-姜欢(1902623359) 2017/12/25 10:40:00 :这个取消传的是修改后订单的roomid,取消单不用判roomid的
  638. //订单的酒店是否匹配,房型是否匹配
  639. /*if ($this->Spider_hotel != $order->PARENT_PROD_ID || $this->Spider_room_type != $order->PROD_ID) {
  640. return false;
  641. }*/
  642. //根据时间判断是否可以取消
  643. //$timeMin = (time() - strtotime($order->CREATE_TIME)) / 60;
  644. //禅道需求:http://192.168.6.248/zentao/task-view-567.html
  645. //1.对于携程15分钟之内已接单的订单,携程接口申请取消时,根据订单状态接口返回是否同意取消;
  646. //2.对于待发单状态的订单,接口返回同意取消,渠道接单状态变更为“已取消”,订单状态变更为已取消,记录3条订单日志;
  647. //3.对于已取消状态的订单,接口返回同意取消,渠道接单状态变更为“已取消”,记录2条订单日志;
  648. //4.对于待安排、已安排、已入住状态的订单,接口返回拒绝取消,渠道接单状态变更为“取消被拒”,记录3条订单日志;
  649. //5.对于退改中、待退单确认状态的订单,不会出现这样的情况。
  650. //根据这里的描述,好像没有15分钟的强制条件了
  651. // if ($timeMin <= 15 || $order->CHANNEL_ORDER_STATUS == OrderMain::ORDER_CHANNEL_STATUS_WAITING) {
  652. if ($order->CHANNEL_ORDER_STATUS == OrderMain::ORDER_CHANNEL_STATUS_WAITING) {
  653. return true;
  654. } else {
  655. $room = OperaHotelRoom::findOne(['HOTEL_ID' => $order->PARENT_PROD_ID, 'ROOM_TYPE' => $order->PROD_ID]);
  656. if ($room == null) {
  657. return false;
  658. }
  659. //在最晚取消时间内
  660. if (time() < $room->getLatestCancel($order->PROD_START_STATION_DATE)) {
  661. return true;
  662. }
  663. //超过最晚取消时间
  664. return false;
  665. }
  666. }
  667. /**
  668. * User: wangxj
  669. *
  670. * 验证金额是否一致,如果传过来的金额和我们设置的金额不一致,下单失败
  671. * 103 价格错误
  672. * @param $attribute string
  673. * @param $params array
  674. *
  675. */
  676. public function validateCNYCostAmount($attribute, $params)
  677. {
  678. $hotel = $this->Spider_hotel;
  679. $room_type = $this->Spider_room_type;
  680. $sale_type = $this->Spider_sale_type;
  681. $ctripInfo = Yii::$app->params['ctrip'];
  682. $roomPrices = isset($this->RoomPrices['RoomPrice'][0]) ? $this->RoomPrices['RoomPrice'] : $this->RoomPrices;
  683. foreach ($roomPrices as $roomPrice) {
  684. $EffectDate = substr($roomPrice['EffectDate'], 0, 10);
  685. $CNYCost = $roomPrice['Cost']; //-订单底价金额(人民币),现付一般不传或者传0
  686. $filed = BaseSupplierSale::getSaleField($sale_type);
  687. $room = RunHotelDistrib::findOne(['HOTEL_ID' => $hotel, 'ROOM_TYPE' => $room_type, 'RUN_DATE' => $EffectDate, 'DISTRIB_ID' => $ctripInfo['supplier_id']]);
  688. if ($room != null) {
  689. $cost = $room->$filed;
  690. if ((int)($cost * 100) != (int)($CNYCost * 100)) {
  691. $this->clearErrors($attribute);
  692. $this->addError($attribute, self::RETURN_CODE_PRICE_FAIL);
  693. }
  694. } else {
  695. $this->clearErrors($attribute);
  696. $this->addError($attribute, self::RETURN_CODE_ROOM_CLOSED);
  697. }
  698. }
  699. }
  700. /**
  701. * User: wangxj
  702. *
  703. * 检查保留房是否有房
  704. *
  705. * @param $attribute
  706. * @param $params
  707. */
  708. public function validateHoldRoom($attribute, $params)
  709. {
  710. if ($this->$attribute == 'R') {
  711. $roomPrices = isset($this->RoomPrices['RoomPrice'][0]) ? $this->RoomPrices['RoomPrice'] : $this->RoomPrices;
  712. foreach ($roomPrices as $roomPrice) {
  713. $EffectDate = substr($roomPrice['EffectDate'], 0, 10);
  714. $room_stock = RunHotelDistrib::find()->where(['RUN_DATE' => $EffectDate,
  715. 'ROOM_TYPE' => $this->Spider_room_type, 'RUN_STATUS' => RunHotelDistrib::ROOM_STATUS_SALE,
  716. 'HOTEL_ID' => $this->Spider_hotel])->andFilterWhere(['>=', 'REMAINING_COUNT', $this->Quantity])->one();;
  717. if ($room_stock == null) {
  718. $this->addError($attribute, self::RETURN_CODE_STOCK_FAIL);
  719. }
  720. }
  721. }
  722. }
  723. /**
  724. * User: wangxj
  725. *
  726. * 检查mapping的酒店和房型是否正常
  727. *
  728. * @param $attribute
  729. * @param $params
  730. */
  731. public function validateSpider($attribute, $params)
  732. {
  733. if ($this->Spider_hotel == 0 || $this->Spider_room == 0) {
  734. $this->addError($attribute, self::RETURN_CODE_MAPPING_FAIL);
  735. }
  736. }
  737. /**
  738. * User: wangxj
  739. *
  740. * 根据订单当前状态,写入不同日志,条数和内容可能都不相同
  741. *
  742. * @param $user_id integer
  743. * @param $msg string
  744. *
  745. */
  746. public function saveLog($user_id, $msg)
  747. {
  748. $orderLog = new OperaHotelLog();
  749. $orderLog->CREATE_USER_ID = $user_id;
  750. $orderLog->HOTEL_ID = $this->Spider_hotel;
  751. $orderLog->LOG_TYPE = OperaHotelLog::LOG_TYPE_ORDER;
  752. $orderLog->ROOM_TYPE = $this->Spider_room_type;
  753. $orderLog->PARENT_ROOM_TYPE = $this->Spider_parent_room_type;
  754. $orderLog->LOG_DESC = $msg;
  755. $orderLog->ORDER_ID = $this->Spider_order_id;
  756. $orderLog->save();
  757. }
  758. public static function getGuestsName($array)
  759. {
  760. $customer_name = '';
  761. $guests = isset($array['GuestEntity'][0]) ? $array['GuestEntity'] : $array;
  762. if (is_array($guests)) {
  763. $customer_name = [];
  764. foreach ($guests as $GuestEntity) {
  765. if (!empty($GuestEntity['ChinesName'])) {
  766. $customer_name[]['Name'] = $GuestEntity['ChinesName'];
  767. } else {
  768. $customer_name[]['Name'] = $GuestEntity['LastName'] . '/' . $GuestEntity['FirstName'];
  769. }
  770. /*$FirstName = empty($GuestEntity['FirstName']) ? '' : $GuestEntity['FirstName'];
  771. $LastName = empty($GuestEntity['LastName']) ? '' : $GuestEntity['LastName'];
  772. if ($customer_name == '' || (strstr($GuestEntity['ChinesName'], trim($customer_name)) == false && strstr(($FirstName . ' ' . $LastName), trim($customer_name)) == false)) {
  773. $customer_name .= ',' . (empty($GuestEntity['ChinesName']) ? ($FirstName . ' ' . $LastName) : $GuestEntity['ChinesName'] . ' ');
  774. }*/
  775. }
  776. }
  777. return $customer_name;
  778. }
  779. /**
  780. * Notes:
  781. * User: Steven
  782. * Date: 2018/1/11
  783. * Time: 11:48
  784. * @param $RoomPrices
  785. * @return array
  786. */
  787. public static function getRoomPrices($RoomPrices)
  788. {
  789. $roomPrices = isset($RoomPrices['RoomPrice'][0]) ? $RoomPrices['RoomPrice'] : $RoomPrices;
  790. $date = array_column($roomPrices, 'EffectDate');
  791. array_multisort($date, SORT_ASC, $roomPrices);
  792. if (!empty($roomPrices)) {
  793. $RoomPricesArr = [];
  794. foreach ($roomPrices as $RoomPrice) { //每个RoomPrice对应一天价格
  795. $EffectDate = substr($RoomPrice['EffectDate'], 0, 10);
  796. $RoomPricesArr[] = [
  797. 'RunDate' => $EffectDate,
  798. 'Price' => $RoomPrice['Cost']
  799. ];
  800. }
  801. }
  802. return $RoomPricesArr;
  803. }
  804. }