<?php /** * Created by PhpStorm. * User: lxd * Date: 2019/12/30 * Time: 11:22 * Comm: */ namespace ApiController; use CommonLibTsTsPackage; use CommonLogicCountryLogic; use CommonLogicDeviceLogic; use CommonLogicGoodsLogic; use CommonLogicIslandLogic; use CommonLogicPartnerGoodsOrderLogic; use CommonLogicPartnerGoodsSonorderLogic; use CommonLogicPartnerLogic; use CommonLogicSimcardLogic; use CommonModelDataPackageModel; use CommonModelGoodsModel; use CommonModelPartnerModel; use PartnerLogicLeaseLogic; use ThinkController; use ThinkException; use ThinkLog; use ThinkModel; class ShopifyNoticeController extends Controller { private $_param; private $_paramArr; private $_header = [ 'HTTP_X_SHOPIFY_TEST' => 'false', 'HTTP_X_SHOPIFY_HMAC_SHA256' => '', ]; private $_logque; private $_sign = '33ee5426dad7acd783862018ec04af35069f2ed0f913b2ff486f95432b2e02f7'; private $_self_partner = 1; //shopify的合作商id,订单归属合作商 private $_partner; private $_api = [ 'key' => '951d7d219e283094adf901a6640a8a42', 'pwd' => '207fe05963cc8c4a8559c65ecec3e417', 'url' => 'test-uro.myshopify.com/admin/api/', 'version' => '2020-01', 'authorization' => '' ]; private $_curl; private $_cityToCollectionRedisKey = "ShopifyNotice:cityToCollection"; // private $_productToCoolectRedisKey = "ShopifyNotice:productToCoolect"; private $_productStatus = "ShopifyNotice:productStatus"; private $_productToArea = "ShopifyNotice:productToArea"; //最后一个逗号值是商品类型 private $_shopifyCurlQueue = "ShopifyNotice:curlQueue"; //curl放队列里面 单个执行 private $_curlLastErr = ''; private $_skipCheckHeaderAction = ['getcustomcollections']; const DEVICEFLOW = 'DEVICE_FLOW'; //设备流量 const SIMFLOW = 'SIM_FLOW'; //sim流量 const SIMOTAFLOW = 'SIM_FLOW_AND_OTA_CARD'; //sim流量 + ota卡 const SIMONCEFLOW = 'SIM_FLOW_AND_ONCE_CARD'; //sim流量 + 非ota卡 CONST ESIM = 'ESIM'; //esim 类型 const TAGOTA = 'plus ota card'; const TAGONCE = 'plus once card'; const HANDLESIM = 2; CONST HANDLEDEVICE = 3; CONST HANDLEOTA = 4; CONST HANDLEONCE = 5; CONST HANDLE_ESIM = 6; public function __construct( $skipPartner = false ) { parent::__construct(); $this->_param = file_get_contents( 'php://input' ); $this->_paramArr = json_decode( $this->_param, true ); $this->_header = $_SERVER; if( $this->_param ) $this->_setLog( "receive param == {$this->_param}, header == " . json_encode( $this->_header ) ); if( !APP_DEBUG ) { $this->_sign = '//online data'; $this->_api = [ //online shopify api data ]; } $this->_curl = new Curl(); $this->_api['authorization'] = base64_encode( "{$this->_api['key']}:{$this->_api['pwd']}" ); if( !in_array( strtolower( ACTION_NAME ), $this->_skipCheckHeaderAction ) ) $this->_checkParam(); } public function getCurlQueueName() { return $this->_shopifyCurlQueue; } public function getCustomCollections( $param ) { if( !isset( $param['ids'] ) ) { return []; } $proIds = explode( ',', $param['ids'] ); array_filter( $proIds ); if( empty( $proIds ) ) return []; //读取商品对应的city ids $redis = getRedis(); $reret = $redis->hMGet( $this->_productToArea, $proIds ); if( empty( $reret ) ) return []; $cityToCollection = []; $tempCityToCollection = $redis->hGetAll( $this->_cityToCollectionRedisKey ); foreach( $tempCityToCollection as $cid => $collInfo ) { $tempCollInfo = json_decode( $collInfo,true ); if( empty( $tempCollInfo ) ) continue; $cityToCollection[$cid] = $tempCollInfo['id']; } $return = []; foreach( $reret as $pid => $areas ) { $tempArea = explode(',', $areas ); array_pop( $tempArea ); //弹出商品类型 if( count( $tempArea ) < 1 ) //出错了,忽略掉 continue; $tempAreaCollIds = []; foreach( $tempArea as $_cid ) { if( isset( $cityToCollection[$_cid] ) ) { $tempAreaCollIds[] = $cityToCollection[$_cid]; } } $return[$pid] = $tempAreaCollIds; } return $return; } /** * 订单支付成功后的通知 * author liuxiaodong * date 2020/1/2 16:53 */ public function payed() { try { ignore_user_abort( true ); if( !APP_DEBUG && $this->_header['HTTP_X_SHOPIFY_TEST'] === 'true' ) { $this->_setLog( '正式服务器上收到了测试的shopify信息,程序停止!请检查! HTTP_X_SHOPIFY_TEST = ' . $this->_header['HTTP_X_SHOPIFY_TEST'], Log::ERR ); } if( $this->_paramArr['financial_status'] != 'paid' ) { $this->_setLog( '订单状态异常,非paid !!' . $this->_paramArr['financial_status'] ); //流量商品需配置该信息,其他的商品,mos忽略 exit; } $imeis = $cards = $all = []; // if( empty( $this->_paramArr['note_attributes'] ) ){ // $this->_setLog( '未收到 note_attributes 信息,没有需要同步的信息' . json_encode( $this->_paramArr['note_attributes'] ) ); // //流量商品需配置该信息,其他的商品,mos忽略 // exit; // } $productsDeivce = []; foreach ( $this->_paramArr['line_items'] as $line_item) { if( isset( $line_item['properties'] ) ) { foreach( $line_item['properties'] as $prod ) { $prod['type'] = $prod['name']; $prod['name'] = "imei{$line_item['product_id']}"; $productsDeivce[] = $prod; } } } if( empty( $productsDeivce ) ){ $this->_setLog( '未收到 productsDeivce 信息,没有需要同步的信息' . json_encode( $productsDeivce ) ); //流量商品需配置该信息,其他的商品,mos忽略 exit; } $this->_setLog( ' productsDeivce === ' . json_encode( $productsDeivce ) ); if( $this->_paramArr['fulfillment_status'] == 'fulfilled' ) { $this->_setLog( '该商品已发货' . json_encode( $this->_paramArr['fulfillment_status'] ) ); //流量商品需配置该信息,其他的商品,mos忽略 exit; } $redis = getRedis(); $rekey = "ShopifyNotice:payed" . $this->_paramArr['token']; $ret = $redis->setnx( $rekey, 1 ); if( !$ret ) { $this->_setLog( '该token已被处理,忽略' . json_encode( $this->_paramArr['token'] ) ); //token校验 exit; } $redis->expire( $rekey, 30 * 86400 ); $skus = []; $is_esim = 0; $_esim_num = ''; foreach ( $productsDeivce as $item ) { $productId = trim( $item['name'], 'imei' ); $valInfo = []; foreach( $this->_paramArr['line_items'] as $prod ) { if( $prod['product_id'] == $productId ) { $valInfo = [ 'name' => $prod['name'], 'sku' => $prod['sku'], 'quantity' => $prod['quantity'], 'id' => $prod['id'] ]; $skus[] = $prod['sku']; break; } } if( $item['type'] == 'esim' ) { $is_esim = 1; for( $_i = 0; $_i < $valInfo['quantity']; $_i++ ) { if( !isset( $all[$_esim_num] ) ) $all[$_esim_num] = [$valInfo]; else $all[$_esim_num][] = $valInfo; } }else { //simcard ,macaroon 使用 imei if( strlen( $item['value'] ) == 20 ) $cards[] = $item['value']; else $imeis[] = $item['value']; if( !isset( $all[$item['value']] ) ) $all[$item['value']] = [$valInfo]; else $all[$item['value']][] = $valInfo; } } $this->_setLog( "设备商品信息:imeis== " . json_encode( $imeis ) . " ;; cards == " . json_encode( $cards ) . " ;; is_esim == " . $is_esim ); if( $is_esim ) { $this->_setLog( 'esmi 类型;开始处理,无需检查设备信息 。。 valInfo == ' . json_encode($valInfo) ); }else { if( empty( $imeis ) && empty( $cards ) ) { $ret = $this->_addNoteToOrder( $this->_paramArr['id'], 'MOS ERROR: 无设备,无卡,失败' ); if( $ret ) $this->_setLog( '发送shopify请求成功,ret' . $ret ); $this->_setLog( '无设备,无卡,请检查', Log::ERR ); } } //验证设备信息 if( $imeis ) { if( !$this->_checkImeis( $imeis ) ) { $ret = $this->_addNoteToOrder( $this->_paramArr['id'], 'MOS ERROR: 未找到有关的设备信息,失败' ); if( $ret ) $this->_setLog( '发送shopify请求成功,ret' . var_export($ret, true ) ); $this->_setLog( '服务器检查imei失败,请查看并更新错误!', Log::ERR ); } } if( $cards ) { if( !$this->_checkCards( $cards ) ) { $ret = $this->_addNoteToOrder( $this->_paramArr['id'], 'MOS ERROR: 未找到有关的卡信息,失败' ); if( $ret ) $this->_setLog( '发送shopify请求成功,ret' . var_export($ret, true ) ); $this->_setLog( '服务器检查imei失败,请查看并更新错误!', Log::ERR ); } } $this->_setLog( '验证设备信息成功,开始验证商品...' ); //获取商品信息 $newSkuInfo = []; if( $skus ) { $skuInfo = $this->_checkSkus( $skus ); if( !$skuInfo ) { $ret = $this->_addNoteToOrder($this->_paramArr['id'], 'MOS ERROR: 未找到有关的商品信息,失败'); if ($ret) $this->_setLog('发送shopify请求成功,ret' . var_export($ret, true )); $this->_setLog( '服务器检查套餐失败,请查看并更新错误!skus = ' . var_export($skus, true ), Log::ERR ); } foreach( $skuInfo as $item ) { if( !isset( $item['validay'] ) ){ $item['validay'] = $item['validity']; } $newSkuInfo[$item['sku']] = $item; } unset( $skuInfo ); }else { $ret = $this->_addNoteToOrder( $this->_paramArr['id'], 'MOS ERROR: 商品没有配置SKU,失败' ); if( $ret ) $this->_setLog( '发送shopify请求成功,ret' . var_export($ret, true ) ); $this->_setLog( '商品没有配置SKU信息,请检查', Log::ERR ); } $this->_setLog( '验证商品信息成功,开始同步...' ); $startTime = new DateTime(); $leaseLogic = new LeaseLogic(); //开始同步 if( $all ) { $oid = createOrderNumber('SY'); $orderData = $sonOrderData = []; foreach( $all as $imei => $item ) { foreach( $item as $ik => $iv ) { $ginfo = $newSkuInfo[$iv['sku']]; $orderData['gnames'][] = $iv['name']; $orderData['gshows'][$iv['id']] = [ //data ]; $endTmfd = clone $startTime; $addDays = $iv['quantity'] * $ginfo['validity']; $endTmfd->add( new DateInterval( "P{$addDays}D" ) ); $sonOrderData[] = [//data] } } $gtid = !empty( $imeis) ? GoodsModel::GTFLOW : GoodsModel::GTSIMFLOW; if( $is_esim ) { $gtid = GoodsModel::GTESIMFLOW; } $addData = [ //data ]; $orderModel = new PartnerGoodsOrderLogic(); $sonOrderModel = new PartnerGoodsSonorderLogic(); $orderModel->startTrans(); if( !$orderModel->add( $addData ) ) { $orderModel->rollback(); $this->_setLog( '服务器新增主订单失败' . json_encode( $addData ), Log::ERR ); } if( !$sonOrderModel->addAll( $sonOrderData ) ) { $orderModel->rollback(); $this->_setLog( '服务器新增子订单失败' . json_encode( $orderData ), Log::ERR ); } $orderModel->commit(); $this->_setLog( '商品入库成功...' ); $ret = $leaseLogic->_syncTsNew( $oid, [], 0, DataPackageModel::SOURCESHOPIFY ); $str = $ret ? '成功' : '失败'; $node = "MOS已同步[$oid]。结果: {$str}"; if( !$ret ) { $this->_addNoteToOrder( $this->_paramArr['id'], $node ); $this->_setLog( 'MOS 同步失败,不发货...' ); $this->_setLog( '执行完毕...' ); return true; } $this->_setLog( '开始发货...' ); $esimList = []; if( $is_esim ) { //esim 卡需要获取卡的二维码信息 $esimList = (new PartnerGoodsSonorderLogic())->getEsimCardQcode( $oid ); if( !$esimList ) { $this->_setLog( '开始发货...,esim 类型,获取二维码失败,发货失败' ); $this->_addNoteToOrder( $this->_paramArr['id'], $node . ' ;; 二维码读取失败,发货失败' ); return false; } } $flag = true; foreach( $this->_paramArr['line_items'] as $item ) { if( !$this->_fulfillment( $this->_paramArr['id'], $item['id'], $item['variant_id'], $node, $item['sku'], $esimList ) ) $flag = false; } if( $flag ) $this->_setLog( '发货成功...' ); else $this->_setLog( '发货失败...' ); $this->_setLog( '开始写note...' ); $this->_addNoteToOrder( $this->_paramArr['id'], $node ); $this->_setLog( '执行完毕...' ); } }catch ( Exception $e ) { $this->_setLog( '执行过程出异常了...' . $e, Log::ERR ); } } private function _esimJob( $valInfo, $skus ) { $this->_setLog( '开始esmi发货处理....' . json_encode( ['valInfo' => $valInfo, 'skus' => $skus ] ) ); } //商品创建 public function prodUpdate() { if( !isset( $this->_paramArr['variants'] ) ) { $this->_setLog( '商品没有variants信息,忽略', Log::ERR ); } $skus = []; foreach( $this->_paramArr['variants'] as $item ) { $skus[] = $item['sku']; } $md5Sku = md5( json_encode( $skus ) . $this->_param['tags'] ); $redis = getRedis(); $proSt = $redis->hGet( $this->_productStatus, $this->_paramArr['id'] ); if( $this->_paramArr['published_at'] ) { if( $proSt == $md5Sku ) { $this->_setLog( '商品sku未更新,商品状态未更新,忽略', Log::WARN ); return; }else { $this->_setLog( '开始下架原商品。。。' ); $this->prodDeletion( $this->_paramArr['id'] ); $this->_setLog( '下架完成。。。' ); } }else { //下架 $this->_setLog( '开始下架商品。。。' ); $this->prodDeletion( $this->_paramArr['id'] ); return; } //获取商品信息 $model = new GoodsLogic(); $glist = $model->getListSku( $skus, $this->_getPartners() ); if( !$glist ) { $this->_setLog( '未获取到sku对应的信息,忽略该商品', Log::ERR ); } $this->_setLog( "读取sku成功。" ); $customCollect = $this->_getCustomCollections(); $collect = $customCollectMof = []; $productArea = []; foreach( $glist as $ginfo ) { if( empty( $ginfo['_area'] ) ) { $this->_setLog( "改sku{$ginfo['sku']}没有对应的区域信息,忽略。" ); continue; } foreach( $ginfo['_area'] as $cityId ) { $sim = $dev = $simOta = $simOnce = $esim = 0; $_self_gtype = null; if( $ginfo['gtid'] == GoodsModel::GTFLOW ) { $dev = 1; $_self_gtype = self::HANDLEDEVICE; }else if( $ginfo['gtid'] == GoodsModel::GTSIMFLOW ) { if( strpos( $this->_paramArr['tags'], self::TAGOTA ) !== false ) { $simOta = 1; $_self_gtype = self::HANDLEOTA; }else if( strpos( $this->_paramArr['tags'], self::TAGONCE ) !== false ) { $simOnce = 1; $_self_gtype = self::HANDLEONCE; }else { $sim = 1; $_self_gtype = self::HANDLESIM; } }else if( $ginfo['gtid'] == GoodsModel::GTESIMFLOW ) { $esim = 1; $_self_gtype = self::HANDLE_ESIM; } $this->_setLog( "处理城市id== {$cityId}; sim = {$sim}; dev = {$dev}; simota = {$simOta}; simonce = {$simOnce}; esim = {$esim}; _self_gtype == {$_self_gtype}" ); if( isset( $customCollect[$cityId] ) ) { $_customCollectArr = json_decode( $customCollect[$cityId], true ); $_customCollectId = $_customCollectArr['id']; $_customCollectHandle = explode('_', $_customCollectArr['handle'] ); $_customCollectHandle[self::HANDLESIM] = ( (int)$_customCollectHandle[self::HANDLESIM] ) + $sim; $_customCollectHandle[self::HANDLEDEVICE] = ( (int)$_customCollectHandle[self::HANDLEDEVICE] ) + $dev; $_customCollectHandle[self::HANDLEOTA] = ( (int)$_customCollectHandle[self::HANDLEOTA] ) + $simOta; $_customCollectHandle[self::HANDLEONCE] = ( (int)$_customCollectHandle[self::HANDLEONCE] ) + $simOnce; $_customCollectHandle[self::HANDLE_ESIM] = isset( $_customCollectHandle[self::HANDLE_ESIM] ) ? ( (int)$_customCollectHandle[self::HANDLE_ESIM] ) + $esim : $esim; $collect[] = [ 'collect' => [ 'product_id' => $this->_paramArr['id'], 'collection_id' => $_customCollectId ] ]; $customCollectMof[$_customCollectId] = [ 'custom_collection' => [ 'id' => $_customCollectId, 'handle' => implode( '_', $_customCollectHandle ) ] ]; $productArea[] = $cityId; // $customCollectRedis[$cityId] = json_encode( [ 'id' => $_customCollectId, 'handle' => implode( '_', $_customCollectHandle ) ] ); }else { $collection = $this->_createCollection( $cityId, $sim, $dev ); if( isset( $collection['id'] ) ){ $collect[] = [ 'collect' => [ 'product_id' => $this->_paramArr['id'], 'collection_id' => $collection['id'] ] ]; $productArea[] = $cityId; }else { $this->_setLog( "城市{$cityId}请求createCollection 失败,建立商品关系失败", Log::WARN ); continue; } // $customCollectRedis[$cityId] = json_encode( [ 'id' => $collection['id'], 'handle' => $collection['handle'] ] ); } } } if( $collect ) { $this->_setLog( "开始请求 collect 信息" ); $this->_createCollect( $collect ); } if( $customCollectMof ) { $this->_setLog( "有需要更新的custom collection信息。" ); $this->_mofCollection( $customCollectMof ); } if( $productArea ) { $this->_setLog( "设定商品对应的国家id关系。" . json_encode( $productArea ) ); $productArea = array_unique( $productArea ); $redis->hSet( $this->_productToArea, $this->_paramArr['id'], implode( ',', $productArea ) . ',' . $_self_gtype ); } $productType = ''; switch ( $_self_gtype ) { case self::HANDLESIM: $productType = self::SIMFLOW; break; case self::HANDLEONCE: $productType = self::SIMONCEFLOW; break; case self::HANDLEOTA: $productType = self::SIMOTAFLOW; break; case self::HANDLEDEVICE: $productType = self::DEVICEFLOW; break; case self::HANDLE_ESIM: $productType = self::ESIM; break; } $redis->rPush( $this->_shopifyCurlQueue, json_encode( [ 'className' => self::class, 'method' => 'mofProductJob', 'param' => [ 'product' => [ 'id' => $this->_paramArr['id'], 'product_type' => $productType ] ], 'doTimes' => 0 ] ) ); $redis->hSet( $this->_productStatus, $this->_paramArr['id'], $md5Sku ); $this->_setLog( "执行完毕。ok" ); } public function prodDeletion( $id = null ) { if( !$id ) $id = $this->_paramArr['id']; if( !$id ) { $this->_setLog( "id 「{$id}」 为空。忽略。。" ); return; } $redis = getRedis(); //清理管连关系 $area = $redis->hGet( $this->_productToArea, $id ); if( !$area ) { $this->_setLog( "未找到商品的关联区域信息。忽略。。" ); return; } $redis->hDel( $this->_productToArea, $id ); $areaArr = explode( ',', $area ); $gtype = array_pop( $areaArr ); $this->_setLog( "处理区域与custom collection关系" ); $customCollectMof = []; foreach( $areaArr as $cityId ) { $customCollect = $redis->hget( $this->_cityToCollectionRedisKey, $cityId ); if( $customCollect ) { $_tmp = json_decode( $customCollect, true ); $_handle = explode( '_', $_tmp['handle'] ); switch ( $gtype ) { case self::HANDLESIM: $_handle[self::HANDLESIM] = ( (int)$_handle[self::HANDLESIM] ) - 1; break; case self::HANDLEONCE: $_handle[self::HANDLEONCE] = ( (int)$_handle[self::HANDLEONCE] ) - 1; break; case self::HANDLEOTA: $_handle[self::HANDLEOTA] = ( (int)$_handle[self::HANDLEOTA] ) - 1; break; case self::HANDLEDEVICE: $_handle[self::HANDLEDEVICE] = ( (int)$_handle[self::HANDLEDEVICE] ) - 1; break; case self::HANDLE_ESIM: $_handle[self::HANDLE_ESIM] = ( (int)$_handle[self::HANDLE_ESIM] ) - 1; break; } $_tmp['handle'] = implode( '_', $_handle ); $customCollectMof[] = [ 'custom_collection' => [ 'id' => $_tmp['id'], 'handle' => $_tmp['handle'] ] ]; $_tmp = null; } } if( $customCollectMof ) $this->_mofCollection( $customCollectMof ); $redis->hSet( $this->_productStatus, $id, '' ); } private function sendRequest( $method, $urlExtend, $data = '', $header = [], $needResHeader = false ) { static $tryTimes = 1; $tmpHeader = ['Content-Type:application/json','Cache-Controller: max-age=0', 'Authorization: Basic ' . $this->_api['authorization']]; if( is_array( $data ) && !empty( $data ) ) { $data = json_encode( $data ); $tmpHeader[] = 'Content-Length: ' . strlen( $data ); }else { $data = (string)$data; } if( !empty( $header ) ) { $tmpHeader = array_merge( $tmpHeader, $header ); } $redis = getRedis(); $url = "https://{$this->_api['key']}:{$this->_api['pwd']}@{$this->_api['url']}{$this->_api['version']}/{$urlExtend}"; $this->_setLog( '开始curl '. $method .' ,url == ' . $url . ',, param == ' . $data ); $ret = $this->_curl->execute( $method, $url, $data, '', $tmpHeader, '', '', $needResHeader ); if( is_array( $ret ) || $ret === false ) { $tryTimes++; if( $tryTimes >= 1 ) { $this->_curlLastErr = "send curl error .."; if( isset( $ret[1] ) ) $this->_curlLastErr .= "{$ret[1]}"; $this->_setLog( 'curl 请求shopify失败,请检查! ' . json_encode( $ret ), Log::WARN ); //添加到重试队列 $redis->rPush( $this->_shopifyCurlQueue, json_encode( [ 'className' => self::class, 'method' => 'curlRedoJob', 'param' => [ 'method' => $method, 'url' => $urlExtend, 'data' => $data, 'header' => $header, 'needResHeader' => $needResHeader ], 'doTimes' => 0 ] ) ); return false; }else { return $this->sendRequest( $method, $urlExtend, $data, $header, $needResHeader ); } } $deRet = json_decode( $ret, true ); if( $needResHeader ) { if( isset( $deRet['ret']['errors'] ) ) { $this->_curlLastErr = $ret; $this->_setLog( '请求成功,但是返回了失败,.' . $ret, Log::WARN ); return false; } }else { if( isset( $deRet['errors'] ) || isset( $deRet['error'] ) ) { $this->_curlLastErr = $ret; $this->_setLog( '请求成功,但是返回了失败,.' . $ret, Log::WARN ); return false; } } $this->_setLog( '请求成功了,' . $ret ); return $deRet; } public function curlRedoJob( $data ) { $ret = $this->sendRequest( $data['method'], $data['url'], $data['data'], $data['header'], $data['needResHeader'] ); if( !$ret ) { return false; } return true; } //给订单添加note private function _addNoteToOrder( $oid, $note ) { $param = ['order' => [ 'id' => $oid, 'note' => $note ]]; $ret = $this->sendRequest( 'PUT', "orders/{$oid}.json", $param ); if( !$ret ) { $this->_setLog( '请求_addNoteToOrder失败了' . var_export( $ret, true ), Log::ERR ); } return $ret; } private function _getCustomCollections( $force = false ) { $ret = []; $redis = getRedis(); $ret = $redis->hGetAll( $this->_cityToCollectionRedisKey ); if( $ret && !$force ) return $ret; $url = 'custom_collections.json?limit=250'; while( true ) { $list = $this->sendRequest( 'GET', $url, '', [] ,true ); $retArr = json_decode( $list['ret'], true ); if( empty( $retArr['custom_collections'] ) ) { $this->_setLog( '获取CustomCollections失败,请检查.' . var_export( $list, true ), Log::WARN ); return []; } foreach( $retArr['custom_collections'] as $item ) { // $tmpPatten = "/<inputstype="hidden"svalue='(.*?)'>/"; // $match = []; // if( !preg_match( $tmpPatten, $item['body_html'], $match ) ) { // continue; // } // $storeInfo = json_decode( $match[1], true ); // $id = $storeInfo['id']; // if( !$id ) // continue; $_tmp = explode( '_', $item['handle'] ); if( !isset( $_tmp[1] ) ) continue; $id = $_tmp[1]; $ret[$id] = json_encode( [ 'id' => $item['id'], 'handle' => $item['handle'] ] ); } $linkPattern = "/link:s<(.*)>/U"; $match = []; if( preg_match( $linkPattern, $list['header'],$match ) ) { $url = "custom_collections.json?" . parse_url( $match[1] )['query']; }else { break; } } $redis->hMset( $this->_cityToCollectionRedisKey, $ret ); return $ret; } public function initCreateCollection() { $this->_createCollection( 'init' ); } private function _createCollection( $ids = '', $sim = 0, $dev = 0, $ota = 0, $noOta = 0 ) { $isLand = [ 1 => 'America', 2 => 'Oceania', 4 => 'Africa', 5 => 'Europe', 6 => 'Asia' ]; if( !$ids ) return false; $where = []; if( $ids ) { if( $ids === 'init' ) { $where = []; }else $where['ids'] = $ids; } $country = new CountryLogic(); $list = $country->getCountryList( $where ); foreach( $list as $item ) { if( empty( $item['english_language'] ) ) { $this->_setLog( '城市' . $item['id'] . '没有英文名称!!!', Log::WARN ); continue; } $continentName = isset( $isLand[$item['continent_id']] ) ? $isLand[$item['continent_id']] : 'other'; if( $continentName == 'other' ) { echo $item['name'] . "<br />"; } // $json = json_encode( [ // 'id' => $item['id'], // 'sim' => $sim, // 'dev' => $dev, // 'cn' => $item['name'], // 'jp' => $item['ja_name'] // ], JSON_UNESCAPED_UNICODE ); $handle = strtolower( $continentName ) . "_{$item['id']}_{$sim}_{$dev}_{$ota}_{$noOta}"; $param = [ 'custom_collection' => [ 'title' => strtolower( $item['english_language'] ), 'handle' => $handle, ] ]; $ret = $this->sendRequest( 'POST', 'custom_collections.json', $param ); if( !$ret ) { $this->_setLog( '城市' . $item['id'] . '建立custom_collections失败!!!', Log::WARN ); return false; } $redis = getRedis(); $redis->hSet( $this->_cityToCollectionRedisKey, $item['id'], json_encode( [ 'id' => $ret['custom_collection']['id'], 'handle' => $handle ] ) ); if( $ids === 'init' ) continue; else return $ret['custom_collection']; } return false; } private function _mofCollection( $data ) { $redis = getRedis(); foreach( $data as $item ) { // $ret = $this->sendRequest( 'PUT', 'custom_collections/' . $item['custom_collection']['id'] . '.json', $item ); // if( !$ret ) { // $this->_setLog( "更新custom collection 失败" . var_export( $item, true ) ); // continue; // } $redis->rPush( $this->_shopifyCurlQueue, json_encode( [ 'className' => self::class, 'method' => 'mofCollectionJob', 'param' => $item, 'doTimes' => 0 ] ) ); $handleArr = explode( '_', $item['custom_collection']['handle'] ); $redis->hSet( $this->_cityToCollectionRedisKey, $handleArr[1], json_encode( ['id' => $item['custom_collection']['id'] , 'handle' => $item['custom_collection']['handle'] ] ) ); } } public function mofCollectionJob( $data ) { $ret = $this->sendRequest( 'PUT', 'custom_collections/' . $data['custom_collection']['id'] . '.json', $data ); if( !$ret ) { return false; } return true; } public function mofProductJob( $data ) { $ret = $this->sendRequest( 'PUT', "products/{$data['product']['id']}.json", $data ); if( !$ret ) { return false; } return true; } private function _createCollect( $data ) { $redis = getRedis(); foreach( $data as $item ) { $redis->rPush( $this->_shopifyCurlQueue, json_encode( [ 'className' => self::class, 'method' => 'createCollectJob', 'param' => $item, 'doTimes' => 0 ] ) ); // $ret = $this->sendRequest( 'POST', 'collects.json', $item ); // if( !$ret ) { // $this->_setLog( "设定商品,collect 关联关系失败" . var_export( $ret, true ) ); // continue; // } // $reval = $redis->hGet( $this->_productToCoolectRedisKey, $item['collect']['product_id'] ); // $setVal = "{$ret['collect']['id']}"; // if( $reval ) // $setVal .= ",{$reval}"; // $redis->hSet( $this->_productToCoolectRedisKey, $item['collect']['product_id'], $setVal ); } } public function createCollectJob( $data ) { $ret = $this->sendRequest( 'POST', 'collects.json', $data ); if( !$ret ) { if( strpos( $this->_curlLastErr, 'already exists' ) ) { return true; } return false; } return true; } /** private function _delCollect( $productId ) { $redis = getRedis(); $ret = $redis->hGet( $this->_productToCoolectRedisKey, $productId ); if( !$ret ) { $this->_setLog( "该商品无collect信息" ); return; } $data = explode( ',', $ret ); foreach( $data as $item ) { $ret = $this->sendRequest( 'DELETE', "collects/{$item}.json" ); if( $ret === false ) { $this->_setLog( "设定商品,collect 清理关联关系失败" . var_export( $ret, true ) ); continue; } } $redis->hDel( $this->_productToCoolectRedisKey, $productId ); } */ //获取商品 private function _fulfillment( $oid, $lineItemId, $variantRestId, &$note, $sku, $esimList = [] ) { $ret = $this->sendRequest( 'GET', "variants/{$variantRestId}.json" ); if( !$ret ) { $note .= " 获取商品信息异常(variants),发货失败"; $this->_setLog( "variants/{$variantRestId}.json 请求失败。" . var_export( $ret, true ) ); return false; } $ret = $this->sendRequest( 'GET', "inventory_levels.json?inventory_item_ids={$ret['variant']['inventory_item_id']}" ); if( !$ret ) { $note .= " 获取商品信息异常(inventory_levels),发货失败"; $this->_setLog( "inventory_levels.json?inventory_item_ids={$ret['variant']['inventory_item_id']} 请求失败。" . var_export( $ret, true ) ); return false; } $param = [ 'fulfillment' => [ 'location_id' => $ret['inventory_levels'][0]['location_id'], 'tracking_number' => null, 'line_items' => [['id' => $lineItemId]] ] ]; if( isset( $esimList[$sku] ) ) { $tracking_urls = $esimList[$sku]; $param['fulfillment']['tracking_numbers'] = $tracking_urls; foreach( $tracking_urls as &$_item ) { $_item = $this->createEsimQrImg( $_item ); } unset( $_item ); $param['fulfillment']['tracking_urls'] = $tracking_urls; $param['fulfillment']['tracking_company'] = 'self'; } $ret = $this->sendRequest( 'POST', "orders/{$oid}/fulfillments.json", $param ); if( !$ret ) { $note .= " 请求发货接口失败,发货失败"; $this->_setLog( "orders/{$oid}/fulfillments.json 请求失败。" . var_export( $ret, true ) ); return false; } return true; } public function createEsimQrImg( $str ) { $path = './' . C("UPLOADPATH") . 'qrcode/'; //上传主目录 $file_name = $path . md5( $str ) . '.png'; if (!file_exists($file_name)) { $QR = new CommonLibQrcode(); $logo = "./public/images/esim_qr_logo.png"; if (!file_exists($path)) { mkdir($path, 755, true); } $bgImg = "./public/images/esim_qr_bg.png"; $QR->create_with_background($str, $file_name, 'M', 10, $logo, $bgImg); } if (file_exists($file_name)) { $img = $file_name ? 'http://' . $_SERVER['SERVER_NAME'] . '/' . $file_name : ''; } return $img; } public function __call($name, $arguments) { // TODO: Implement __call() method. $data = [ 'name' => $name, 'arg' => $arguments ]; $this->_setLog( json_encode( $data ) ); return true; } private function _checkImeis( $imeis ) { $model = new DeviceLogic(); $count = $model->getCountInImei( $this->_partner, $imeis ); if( $count != count( array_unique( $imeis ) ) ) return false; return true; } private function _checkCards( $cards ) { $model = new SimcardLogic(); $count = $model->getCountInImei( $this->_partner, $cards ); if( $count != count( array_unique( $cards ) ) ) return false; return true; } private function _checkSkus( $skus ) { $model = new GoodsLogic(); $count = $model->getListSku( $skus, $this->_partner ); if( count( $count ) != count( array_unique( $skus ) ) ) return false; return $count; } private function _getPartners() { $partner = new PartnerLogic(); $list = $partner->getSonList( PartnerModel::UROAMING_PARTNER_ID ); return array_keys( $list ); } //验证来源 private function _checkParam() { if( IS_CLI ) { return true; } $hashStr = base64_encode( hash_hmac( 'sha256', $this->_param, $this->_sign, true ) ); if( $this->_header['HTTP_X_SHOPIFY_HMAC_SHA256'] !== $hashStr ) { $this->_setLog( '服务器校验来源异常,程序停止!请检查!', Log::ERR ); return false; } $this->_setLog( '检查参数合法性成功' ); return true; } private function _setLog( $msg, $level = Log::NOTICE ) { if( !$this->_logque instanceof SplQueue ) $this->_logque = new SplQueue(); $this->_logque->enqueue( $msg . PHP_EOL ); if( $level == Log::ERR ) { //send mail exit; } } public function __destruct() { if( $this->_logque instanceof SplQueue ) { $msg = ''; while( !$this->_logque->isEmpty() ) { $msg .= $this->_logque->dequeue(); } Log::write( $msg, Log::NOTICE, '', durableLog( 'api-shopify' ) ); } } public function test() { $model = new SimcardLogic(); var_dump( $model->getEsimEmpty( 2, [1])); } }