Shopify 接口调用

<?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])); 
    }
}
原文地址:https://www.cnblogs.com/lxdd/p/13937660.html