代码改变世界

Amazon SP API拉取listing 和 批量调价

2022-08-18 11:47  天心PHP  阅读(1708)  评论(0编辑  收藏  举报

文档地址:https://developer-docs.amazon.com/sp-api/docs

class AmazonList{

    /**拉取amazonlisting  文档:https://developer-docs.amazon.com/sp-api/docs/reports-api-v2021-06-30-use-case-guide
     * 1.申请报告
     * 2.拉取报告状态
     * 3.得到下载报告的URL
     * 4.下载报告,解析报告
    */
    public function getAmazonListing(){
        $account_id = 106;
        $requestReport = new AmazonAllListingNew();//创建实例
        $account = YbModel::model('AmazonAccount')->findByPk($account_id);//根据账户ID获取账户信息
        //申请报告返回一个 ['reportId'=>607810323249222]
        $result = $requestReport->applicationreport($account->merchant_id,strtolower($account->site),'/reports/2021-06-30/reports',"",["reportType"=>'GET_MERCHANT_LISTINGS_ALL_DATA',"marketplaceIds"=>[$account->market_place_id]]);
        //获取报告结果 reports后面的数字是上一步返回的结果reportId
        $result = $requestReport->getreportstatus($account->merchant_id,strtolower($account->site),'/reports/2021-06-30/reports/607810323249222',"","","GET");
        //得到结果
        /*
        Array
        (
            [reportType] => GET_MERCHANT_LISTINGS_ALL_DATA
            [processingEndTime] => 2022-08-18T07:40:12+00:00
            [processingStatus] => DONE
            [marketplaceIds] => Array
                (
                    [0] => A1PA6795UKUSNDMFR9
                )

            [reportDocumentId] => amzn1.spdoc.1.3.35adbdc99-fse83-4c07-a097-9059sd6a3aa6b8.T399XP0BSE3YDD4II.47700
            [reportId] => 601310019222
            [dataEndTime] => 2022-08-18T07:39:56+00:00
            [createdTime] => 2022-08-18T07:39:56+00:00
            [processingStartTime] => 2022-08-18T07:40:00+00:00
            [dataStartTime] => 2022-08-18T07:39:56+00:00
        )
         */
         //获取报告下载链接  documents后面的参数就是上一步返回的 reportDocumentId
        $res = $requestReport->getreportsurl($account->merchant_id,strtolower($account->site),'/reports/2021-06-30/documents/amzn1.spdoc.1.3.35adbdc99-fse83-4c07-a097-9059sd6a3aa6b8.T399XP0BSE3YDD4II.47700',"","","GET");//获取报告下载链接
        //得到结果
        /*
        Array
        (
            [reportDocumentId] => amzn1.spdoc.1.3.35adbc99-fe83-4c07-a097-90596a3aa6b8.T399XP0B3YD4II.47700
            [compressionAlgorithm] => GZIP
            [url] => https://tortuga-prod-eu.s3-eu-west-1.amazonaws.com/%2FNinstetyDays/amzn1.tortuga.3.bf2b549f-14bc-48484-a4da8-51es52f9e0462.T2TYSPCHTORURJ?X-Amz-Algosrithm=AWS4-HMAC-SHA256&X-Amz-Date=202203818T08043556Z&X-Amz-SignedHeaders=host&X-Amz-Expires=300&X-Amz-Credential=AKIAX2ZVOZFBIW3AHAR5%2F20220818%2Feu-west-1%2Fs3%2Faws4_request&X-Amz-Signature=6dbe4f1764c511b7c5a5d5db3ba0c87a1b37eb007d2763803e2b26c44cf7e0d5
        )
        */
        //下载文件
        $tmp_name = md5(uniqid(md5(microtime(true)),true));//重命名
        if(isset($res['url'])){
            $url = Yii::getPathOfAlias('webroot') . '/upload/amazoncsv/';//保存下载文件的路径
            $filename = $tmp_name.'.gz';//gz压缩包
            //下载文件
            $requestReport->getFile($res['url'],$url,$filename);//下载文件
            $content = $requestReport->read_gz($url.$filename);//读取压缩包里面的内容
            if($content){
                @unlink($url . $filename);//读取内容了 删除下载的包
                //解析内容 不同的站点解析规则不同
                if(strtolower($account->site)=='jp'){
                    handleListItemJP($content, $account);
                }elseif (strtolower($account->site)=='fr'){
                    handleListItemFr($content, $account);
                }else{
                    handleListItem($content, $account);
                }
            }
        }
    }

    /**amazon调价 文档:https://developer-docs.amazon.com/sp-api/docs/feeds-api-v2021-06-30-use-case-guide
     * 1.调用createFeedDocument操作,为您提交的提要指定内容类型。返回一个feedDocumentId值和一个用于上传 feed 内容的 URL。(步骤 1. 创建提要文件)
     * 2.组建xml格式(步骤 2. 构建提要)
     * 3.将您的提要文档内容上传到上一步中的 URL。(步骤 3. 上传 Feed 数据)
     * 4.调用createFeed操作。使用inputFeedDocumentId参数传入步骤 1 中的feedDocumentId值。指定您希望应用该提要的市场以及任何相关的提要选项。亚马逊返回一个feedId值(第 4 步:创建提要)
     * 5.获取 /feeds/2021-06-30/feeds/{feedId}结果状态(Step 5. 确认饲料加工)
     * 6.Feed 处理报告指出您提交的 Feed 中哪些记录成功,哪些记录产生了错误。在此步骤中,您将获得一个用于下载 Feed 处理报告的预签名 URL。(步骤 6. 获取信息以检索 Feed 处理报告)
     * 7.下载处理的结果 (步骤 7. 下载 Feed 处理报告)
     */
    public function putAmazonPrice(){
        $account_id = 106;
        $requestReport = new AmazonAllListingNew();
        $account = YbModel::model('AmazonAccount')->findByPk($account_id);//根据账户ID获取账户信息
        $payload =["contentType"=>"text/xml; charset=UTF-8"];
        //第一步 获取上传的url
        $res = $requestReport->applicationreport($account->merchant_id,strtolower($account->site),'/feeds/2021-06-30/documents','',$payload,'POST');
        //得到结果
        /*Array
        (
            [feedDocumentId] => amzn1.tortuga.3.c1862c93-d899-4529-866a-035c3ed971d4.T2OJ5JLG154REG
            [url] => https://tortuga-prod-eu.s3-eu-west-1.amazonaws.com/%2FNinetyDays/amzn1.tortuga.3.c18s62c93-d899-4529-866a-035c3ed971d4.T2OJ5JLG154REG?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Date=20220818T092528Z&X-Amz-SignedHeaders=content-type%3Bhost&X-Amz-Expires=300&X-Amz-Credential=AKIAX2ZVOZFBIW3AHAR5%2F20220818%2Feu-west-1%2Fs3%2Faws4_request&X-Amz-Signature=7a0a7b8fc15f0ed3ff0372eead322d4617eaf07f03c39330ad0da46acef14756
        )*/
        //第二步 组织xml格式
        $feeddata = [
            [
                'sku'=>'FBA -  RC-Winschset',
                'stdprice'=>30.19,
                'BusinessPrice'=>29.59,
                'currency'=>'EUR'
            ],
            [
                'sku'=>'FBA - 1000pcs Screws',
                'stdprice'=>10.49,
                'BusinessPrice'=>10.29,
                'currency'=>'EUR'
            ]
        ];
        $xml = $requestReport->getxml($account->merchant_id,$feeddata);
        //得到结果
        /*
         * <?xml version="1.0"?>
        <amazonenvelope xsi:nonamespaceschemalocation="amzn-envelope.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
            <header>
                <documentversion>1.01</documentversion>
                <merchantidentifier>A68YOTXQQLJUV</merchantidentifier>
            </header>
            <messagetype>Price</messagetype>
            <message>
                <messageid>1</messageid>
                <price>
                    <sku>FBA - RC-Winschset</sku>
                    <standardprice currency="EUR">30.19</standardprice>
                    <businessprice>29.59</businessprice>
                </price>
            </message>
            <message>
                <messageid>2</messageid>
                <price>
                    <sku>FBA - 1000pcs Screws</sku>
                    <standardprice currency="EUR">10.49</standardprice>
                    <businessprice>10.29</businessprice>
                </price>
            </message>
        </amazonenvelope>
         */
        //第三步 上传xml
        $res1 = $requestReport->cur_request($res['url'],'PUT',$xml,["Content-Type:text/xml; charset=UTF-8"]);
        //结果  $res1[0]==200 上传成功
        //第四步 createFeed操作  inputFeedDocumentId 为第一步得到的 feedDocumentId
        $payload2 = ["feedType"=>"POST_PRODUCT_PRICING_DATA","marketplaceIds"=>[$account->market_place_id],"inputFeedDocumentId"=>$res['feedDocumentId']];
        $res2 = $requestReport->applicationreport($account->merchant_id,strtolower($account->site),'/feeds/2021-06-30/feeds','',$payload2,'POST');
        //得到结果 ["feedId"=>542852019132]
        //第五步 获取结果状态 feeds后面的数组 是第四步获取得到
        $feedsinfo = $requestReport->applicationreport($account->merchant_id,strtolower($account->site),'/feeds/2021-06-30/feeds/542852019132','','','GET');
        //得到结果
        /*
         Array
        (
            [processingEndTime] => 2022-08-18T02:13:15+00:00
            [processingStatus] => DONE //代表成功
            [marketplaceIds] => Array
                (
                    [0] => A1PA6795UKMFR9
                )

            [feedId] => 601176019222
            [feedType] => POST_PRODUCT_PRICING_DATA
            [createdTime] => 2022-08-18T02:08:40+00:00
            [processingStartTime] => 2022-08-18T02:08:48+00:00
            [resultFeedDocumentId] => amzn1.tortuga.3.b0b72a07-653f-43cc-81c4-f6dcdde3494e.T3EM20FN5I647Q
        )
         */
        //第六步  获取信息以检索 Feed 处理报告  documents后面的数组 为 第五步得到的 resultFeedDocumentId
        if(isset($feedsinfo['processingStatus'])&&$feedsinfo['processingStatus']=='DONE'){
            $xmlurl = $requestReport->applicationreport($account->merchant_id,$account->site,'/feeds/2021-06-30/documents/'.$feedsinfo['resultFeedDocumentId'],'','','GET');
            if(isset($xmlurl['url'])){
                //第七步得到 xml内容查看结果
                $xml = file_get_contents($xmlurl['url']);
                //结果
                /*
                 <AmazonEnvelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="amzn-envelope.xsd">
                <Header>
                <DocumentVersion>1.02</DocumentVersion>
                <MerchantIdentifier>A68YOTXQQLJUV</MerchantIdentifier>
                </Header>
                <MessageType>ProcessingReport</MessageType>
                <Message>
                <MessageID>1</MessageID>
                <ProcessingReport>
                <DocumentTransactionID>601176019222</DocumentTransactionID>
                <StatusCode>Complete</StatusCode>
                <ProcessingSummary>
                <MessagesProcessed>489</MessagesProcessed>
                <MessagesSuccessful>489</MessagesSuccessful> //成功的数量
                <MessagesWithError>0</MessagesWithError>
                <MessagesWithWarning>0</MessagesWithWarning>
                </ProcessingSummary>
                </ProcessingReport>
                </Message>
                </AmazonEnvelope>
                */
            }
        }

    }

    public static function handleListItemJp($filename, $accountInfo)
    {
        $tmp_name = md5(uniqid(md5(microtime(true)),true));
        file_put_contents($tmp_name,$filename);
        $status = array('Active'=>1, 'Inactive'=>2, 'Incomplete'=>9);
        $model = YbModel::model('AmazonLog');
        $i = 0;
        $c = [];
        $file = fopen($tmp_name,"rb");
        while(!feof($file)) {
            $data = null;
            $items = null;
            $str = null;
            $title_items = null;
            $str = fgets($file);
            $items = explode("\t",$str);
            if (++$i == 1) {
                $column_len = count($items);
                foreach ($items as $k => $v) {
                    $str = iconv('Shift-JIS','utf-8', trim($v));
                    $title_items[] = $str;
                }
                $c = array_reverse($title_items);
                $c = array_flip($c);
                continue;
            }
            $data = array_reverse($items);

            if (count($data) < $column_len) {
                self::mylog($model, $accountInfo->account_name, 'err_col > '.addslashes($str), '异常数据',1);
                continue;
            }
            if (trim($data[$c['ステータス']]) == 'Incomplete') continue;
            $line_data = null;
            //获取表格内指定行数据
            $line_data = json_encode([
                'account_id' => $accountInfo->id,
                'item_name' => CHelper::TrimStr(trim($data[$column_len - 1])),
                'listing_id' => CHelper::TrimStr($data[$c['出品ID']]),
                'seller_sku' => CHelper::TrimStr($data[$c['出品者SKU']]),
                'price' => is_numeric(CHelper::TrimStr($data[$c['価格']])) ? CHelper::TrimStr($data[$c['価格']]) : "NULL",
                'quantity' => is_numeric(CHelper::TrimStr($data[$c['数量']])) ? CHelper::TrimStr($data[$c['数量']]) : "NULL",
                'open_date' => CHelper::TrimStr($data[$c['出品日']]),
                'image_url' => '',
                'item_is_marketplace' => '',
                'item_condition' => is_numeric(CHelper::TrimStr($data[$c['コンディション']])) ? CHelper::TrimStr($data[$c['コンディション']]) : "NULL",
                'asin1' => '',
                'product_id' => CHelper::TrimStr($data[$c['商品ID']]),
                'product_id_type' => CHelper::TrimStr($data[$c['商品IDタイプ']]),
                'add_delete' => '',
                'pending_quantity' => is_numeric(CHelper::TrimStr($data[$c['在庫数']])) ?  CHelper::TrimStr($data[$c['在庫数']]) : "NULL",
                'fulfillment_channel' => CHelper::TrimStr($data[$c['フルフィルメント・チャンネル']])=='DEFAULT' ? 'DEF': 'AMA',
                'status' => $status[CHelper::TrimStr(trim($data[$c['ステータス']]))]
            ],JSON_UNESCAPED_UNICODE);
            if (empty($line_data)) {
                self::mylog($model, $accountInfo->account_name, 'err_col > '.addslashes($str), '空数据',1);
                continue;
            }
            $insert_data[] = [
                'report_type' => self::LISTING,
                'account_id' => $accountInfo->id,
                'report_data' => addslashes($line_data),
                'site' => $accountInfo->site
            ];
            //如果待写入数据到了500则开始写入数据
            if (count($insert_data) >= 500) {
                self::_insertData($model,$insert_data,$accountInfo->account_name);
                unset($insert_data);
            }
        }
        fclose($file);
        if (is_file($tmp_name)) {
            unlink($tmp_name);
            self::saveTmpFile($tmp_name, $accountInfo->id, $accountInfo->site);
        }

        if (!empty($insert_data)) {
            self::_insertData($model,$insert_data,$accountInfo->account_name);
        }
        return $i;
    }

    public static function handleListItemFr($filename, $accountInfo)
    {
        $tmp_name = md5(uniqid(md5(microtime(true)),true));
        file_put_contents($tmp_name,$filename);
        $status = array('Active'=>1, 'Inactive'=>2, 'Incomplete'=>9);
        $model = YbModel::model('AmazonLog');
        $i = 0;
        $c = [];
        $col_len = 0;
        $file = fopen($tmp_name,"rb");
        while(!feof($file))
        {
            $data = null;
            $items = null;
            $str = null;
            $title_items = null;
            $str = fgets($file);
            $items = explode("\t",$str);
            if (++$i == 1) {
                $column_len = count($items);
                foreach ($items as $k => $v) {
                    $title_items[] = trim($v);
                }
                $c = array_reverse($title_items);
                $c = array_flip($c);
                continue;
            }
            $data = array_reverse($items);
            if (count($data) < $column_len) {
                self::mylog($model, $accountInfo->account_name, 'err_col > '.addslashes($str), '异常数据',1);
                continue;
            }
            if (trim($data[$c['status']]) == 'Incomplete') continue;
            $line_data = null;
            //获取表格内指定行数据
            if(isset($c['fulfilment-channel'])){
                $fulfillment_channel = $data[$c['fulfilment-channel']] == 'DEFAULT' ? 'DEF' : 'AMA';
            }else if(isset($c['fulfillment-channel'])){
                $fulfillment_channel = $data[$c['fulfillment-channel']] == 'DEFAULT' ? 'DEF' : 'AMA';
            }else{
                $fulfillment_channel = 'DEF';
            }
            $line_data = json_encode([
                'account_id' => $accountInfo->id,
                'item_name' => utf8_encode(trim($data[$column_len-1])),
                'listing_id' => $data[$c['listing-id']],
                'seller_sku' => $data[$c['seller-sku']],
                'price' => is_numeric($data[$c['price']]) ? $data[$c['price']] : "NULL",
                'quantity' => is_numeric($data[$c['quantity']]) ? $data[$c['quantity']] : "NULL",
                'open_date' => $data[$c['open-date']],
                'image_url' => '',
                'item_is_marketplace' => '',
                'item_condition' => is_numeric($data[$c['item-condition']]) ? $data[$c['item-condition']] : "NULL",
                'asin1' => '',
                'product_id' => $data[$c['product-id']],
                'product_id_type' => $data[$c['product-id-type']],
                'add_delete' => '',
                'pending_quantity' => is_numeric($data[$c['pending-quantity']]) ? $data[$c['pending-quantity']] : "NULL",
                'fulfillment_channel' => $fulfillment_channel,
                'status' => $status[trim($data[$c['status']])]
            ], JSON_UNESCAPED_UNICODE);
            if (empty($line_data)) {
                self::mylog($model, $accountInfo->account_name, 'err_col > '.addslashes($str), '空数据',1);
                continue;
            }
            $insert_data[] = [
                'report_type' => self::LISTING,
                'account_id' => $accountInfo->id,
                'report_data' => addslashes($line_data),
                'site' => $accountInfo->site
            ];
            //如果待写入数据到了500则开始写入数据
            if (count($insert_data) >= 500) {
                self::_insertData($model,$insert_data,$accountInfo->account_name);
                unset($insert_data);
            }
        }
        fclose($file);
        if (is_file($tmp_name)) {
            unlink($tmp_name);
            self::saveTmpFile($tmp_name, $accountInfo->id, $accountInfo->site);
        }
        if (!empty($insert_data)) {
            self::_insertData($model,$insert_data,$accountInfo->account_name);
        }
        return $i;
    }

    public static function handleListItem($filename, $accountInfo)
    {
        $tmp_name = md5(uniqid(md5(microtime(true)),true));
        file_put_contents($tmp_name,$filename);
        $model = YbModel::model('AmazonLog');
        $status = array(
            'Active' => 1,
            'Inactive' => 2,
            'Incomplete' => 9
        );
        $index = $accountInfo->site == 'ae' ? 27 : 28;
        $i = 0;
        $column_len = 0;
        $file = fopen($tmp_name,"rb");
        while(!feof($file)) {
            $data = null;
            $items = null;
            $str = null;
            $title_items = null;
            $str = fgets($file);
            $items = explode("\t",$str);
            if (++$i == 1) {
                $column_len = count($items);
                $sp_bm = [];
                foreach ($items as $k => $v) {
                    if (trim($v) == '商品编码') {
                        if (in_array($v,$sp_bm)) {
                            $v = '商品编码2';
                        } else {
                            $sp_bm[] = $v;
                        }
                    }
                    $title_items[] = trim($v);
                }
                $c = array_reverse($title_items);
                $c = array_flip($c);
                continue;
            }
            $data = array_reverse($items);
            if (count($data) < $column_len) {
                self::mylog($model, $accountInfo->account_name, 'err_col > '.addslashes($str), '异常数据',1);
                continue;
            }
            $line_data = null;
            //获取表格内指定行数据
            $listing_id = '';
            $seller_sku = '';
            $price = '';
            $quantity = '';
            $open_date = '';
            $item_is_marketplace = '';
            $item_condition = '';
            $asin1 = '';
            $product_id = '';
            $product_id_type = '';
            $pending_quantity = '';
            $fulfillment_channel = '';
            $status_report = '';
            if (isset($c['status'])) {
                $listing_id = $data[$c['listing-id']];
                $seller_sku = $data[$c['seller-sku']];
                $price = is_numeric($data[$c['price']]) ? $data[$c['price']] : "NULL";
                $quantity = is_numeric($data[$c['quantity']]) ? $data[$c['quantity']] : "NULL";
                $open_date = $data[$c['open-date']];
                $item_is_marketplace = $data[$c['item-is-marketplace']];
                $item_condition = is_numeric($data[$c['item-condition']]) ? $data[$c['item-condition']] : "NULL";
                $asin1 = $data[$c['asin1']];
                $product_id = $data[$c['product-id']];
                $product_id_type = $data[$c['product-id-type']];
                $pending_quantity = is_numeric($data[$c['pending-quantity']]) ? $data[$c['pending-quantity']] : "NULL";
                if(isset($c['fulfilment-channel'])){
                    $fulfillment_channel = $data[$c['fulfilment-channel']] == 'DEFAULT' ? 'DEF' : 'AMA';
                }else if(isset($c['fulfillment-channel'])){
                    $fulfillment_channel = $data[$c['fulfillment-channel']] == 'DEFAULT' ? 'DEF' : 'AMA';
                }else{
                    $fulfillment_channel = 'DEF';
                }
                $status_report = $status[trim($data[$c['status']])];
                $items_status = trim($data[$c['status']]);
            } elseif (isset($c['状态'])) {
                $listing_id = $data[$c['商品编码']];
                $seller_sku = $data[$c['卖家 SKU']];
                $price = is_numeric($data[$c['价格']]) ? $data[$c['价格']] : "NULL";
                $quantity = is_numeric($data[$c['数量']]) ? $data[$c['数量']] : "NULL";
                $open_date = $data[$c['开售日期']];
                $item_is_marketplace = $data[$c['是否为商城中的商品']];
                $item_condition = is_numeric($data[$c['商品状况']]) ? $data[$c['商品状况']] : "NULL";
                $asin1 = $data[$c['ASIN1']];
                $product_id = $data[$c['商品编码2']];
                $product_id_type = $data[$c['商品编码类型']];
                $pending_quantity = is_numeric($data[$c['等待购买数量']]) ? $data[$c['等待购买数量']] : "NULL";
                $fulfillment_channel = $data[$c['配送渠道']] == 'DEFAULT' ? 'DEF' : 'AMA';
                $status_report = $status[trim($data[$c['状态']])];
                $items_status = trim($data[$c['状态']]);
            } else {
                self::mylog($model, $accountInfo->account_name, 'err_col > '.addslashes($str), '未匹配到数据',1);
                continue;
            }
            //未完成状态不下载
            if ($items_status == 'Incomplete') continue;
            if (empty($open_date) || empty($asin1)) {
                self::mylog($model, $accountInfo->account_name, 'err_col > '.addslashes($str), '字段数据缺失',1);
                continue;
            }
            $line_data = json_encode([
                'account_id' => $accountInfo->id,
                'item_name' => utf8_encode(trim($data[$column_len-1])),
                'listing_id' => $listing_id,
                'seller_sku' => $seller_sku,
                'price' => $price,
                'quantity' => $quantity,
                'open_date' => $open_date,
                'image_url' => '',
                'item_is_marketplace' => $item_is_marketplace,
                'item_condition' => $item_condition,
                'asin1' => $asin1,
                'product_id' => $product_id,
                'product_id_type' => $product_id_type,
                'add_delete' => '',
                'pending_quantity' => $pending_quantity,
                'fulfillment_channel' => $fulfillment_channel,
                'status' => $status_report
            ], JSON_UNESCAPED_UNICODE);
            if (empty($line_data)) {
                self::mylog($model, $accountInfo->account_name, 'err_col > '.addslashes($str), '空数据',1);
                continue;
            }
            $insert_data[] = [
                'report_type' => self::LISTING,
                'account_id' => $accountInfo->id,
                'report_data' => addslashes($line_data),
                'site' => $accountInfo->site
            ];
            //如果待写入数据到了500则开始写入数据
            file_put_contents("dump_0813.txt",date("Y-m-d H:i:s")."--001"."\n".var_export($insert_data,true).PHP_EOL, FILE_APPEND);
            if (count($insert_data) >= 500) {
                self::_insertData($model,$insert_data,$accountInfo->account_name);
                unset($insert_data);
            }
        }
        fclose($file);
        if (is_file($tmp_name)) {
            unlink($tmp_name);
            self::saveTmpFile($tmp_name, $accountInfo->id, $accountInfo->site);
        }
        if (!empty($insert_data)) {
            self::_insertData($model,$insert_data,$accountInfo->account_name);
        }
        return $i;
    }

    /**
     * 通过标识符(ASIN)检索Amazon目录中单个商品的详细信息
     * @throws Exception
     * /services/amazon/amazonfbainventoryplanning/getbrand
     */
    public function actionGetBrand(){
        $requestReport = new AmazonAllListingNew();
        $account = YbModel::model('AmazonAccount')->findByPk(7);
        $result = $requestReport->applicationreport($account->merchant_id,strtolower($account->site),'/catalog/2022-04-01/items/B0B936PZDF',['marketplaceIds'=>$account->market_place_id],"",'GET');
        print_r('<pre>');
        print_r($result);
        print_r('</pre>');
        exit();
    }

    /**
     * 按ASIN或产品标识符搜索一个或多个项目
     * @throws Exception
     * /services/amazon/amazonfbainventoryplanning/getbrandlist
     */
    public function actionGetBrandList(){
        $requestReport = new AmazonAllListingNew();
        $account = YbModel::model('AmazonAccount')->findByPk(7);
        $result = $requestReport->applicationreport($account->merchant_id,strtolower($account->site),'/catalog/2022-04-01/items',['marketplaceIds'=>$account->market_place_id,'identifiersType'=>'ASIN','identifiers'=>'B0B93M87Z8,B0B936PZDF'],"",'GET');
        print_r('<pre>');
        print_r($result);
        print_r('</pre>');
        exit();
    }
}

 

基础类:

class AmazonAllListingNew
{
    private $url = "http://s1.xxxxxx.com/amz_sp_sign_v1.php"; //授权获取token是另一个系统做的
    private $amzurl = "https://sellingpartnerapi-na.amazon.com";
    private $amzurl1 = "https://sellingpartnerapi-eu.amazon.com";
    private $amzurl2 = "https://sellingpartnerapi-fe.amazon.com";
    private $sitelist = [
        'us' => 1,
        'uk' => 2,
        'de' => 3,
        'fr' => 4,
        'it' => 5,
        'jp' => 6,
        'ca' => 8,
        'es' => 9,
        'sp' => 9,
        'mx' => 11,
        'br' => 14,
        'tr' => 15,
        'nl' => 17,
        'se' => 19,
        'pl' => 20
    ];
    private $token, $SellerId, $SiteID;

    public function __construct()
    {
        $this->token = AmazonModelHelper::getecpptoken();//调用另一个系统的token
    }

    //不同的站点域名不同
    public function geturl($site)
    {
        if (in_array($site, ['us', 'br', 'ca', 'mx'])) {
            $url = $this->amzurl;
        } elseif (in_array($site, ['jp', 'sg', 'au'])) {
            $url = $this->amzurl2;
        } else {
            $url = $this->amzurl1;
        }
        return $url;
    }

    //得到调价的xml
    public function getxml($merchant_id, $feeddata)
    {
        $xml = '<?xml version="1.0" encoding="UTF-8"?><AmazonEnvelope xsi:noNamespaceSchemaLocation="amzn-envelope.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"><Header><DocumentVersion>1.01</DocumentVersion><MerchantIdentifier>' . $merchant_id . '</MerchantIdentifier></Header><MessageType>Price</MessageType>';
        foreach ($feeddata as $key => $val) {
            $xml .= '<Message><MessageID>' . ($key + 1) . '</MessageID><Price><SKU>' . $val['sku'] . '</SKU>';
            if (isset($val['saleprice'])) {
                $xml .= '<Sale><StartDate>' . $val['stime'] . '</StartDate><EndDate>' . $val['etime'] . '</EndDate><SalePrice currency="' . $val['currency'] . '">' . $val['saleprice'] . '</SalePrice></Sale>';
            }
            $xml .= '<StandardPrice currency="' . $val['currency'] . '">' . $val['stdprice'] . '</StandardPrice><BusinessPrice>' . $val['BusinessPrice'] . '</BusinessPrice></Price></Message>';
        }
        $xml .= '</AmazonEnvelope>';
        return $xml;
    }

    //得到调库存的xml
    public function getstockxml($merchant_id, $feeddata)
    {
        $xml = '<?xml version="1.0" encoding="utf-8"?><AmazonEnvelope xsi:noNamespaceSchemaLocation="amzn-envelope.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"><Header><DocumentVersion>1.01</DocumentVersion><MerchantIdentifier>' . $merchant_id . '</MerchantIdentifier></Header><MessageType>Inventory</MessageType>';
        foreach ($feeddata as $key => $val) {
            $xml .= '<Message><MessageID>' . ($key + 1) . '</MessageID><OperationType>Update</OperationType><Inventory><SKU>' . $val['sku'] . '</SKU><Quantity>' . $val['qty'] . '</Quantity><FulfillmentLatency>' . $val['latency'] . '</FulfillmentLatency></Inventory></Message>';
        }
        $xml .= '</AmazonEnvelope>';
        return $xml;
    }

    /** 获取报告下载链接
     * @param $SellerId
     * @param $Path
     * @param string $QueryParams
     * @param string $Payload
     * @param string $type
     * @return array|mixed
     */
    public function getreportsurl($SellerId, $site, $Path, $QueryParams = '', $Payload = '', $type = 'GET')
    {
        $headers = $this->getheaders($SellerId, $site, $Path, $QueryParams, $Payload, $type);
        $url = $this->geturl($site) . $Path;
        $data2 = $type == 'GET' ? $QueryParams : $Payload;
        $res2 = $this->cur_request($url, $type, "", $headers);
        $list = [];
        if ($res2[0] == 200) {
            $list = $res2[1];
        }
        return $list;
    }

    /** 获取报告状态
     * @param $SellerId
     * @param $Path
     * @param string $QueryParams
     * @param string $Payload
     * @param string $type
     * @return
     * [0]=>200
     * [1]=>[
     *   [reportType] => GET_MERCHANT_LISTINGS_ALL_DATA
     * [processingEndTime] => 2022-08-18T07:40:12+00:00
     * [processingStatus] => DONE
     * [marketplaceIds] => Array
     * (
     * [0] => A1PA6795UKMFR9
     * )
     * [reportDocumentId] => amzn1.spdoc.1.3.35adbc99-fe83-4c07-a097-90596a3sdfasdsdfsdaa6b8.T399XP0B3YD4II.47700
     * [reportId] => 6013100123239222
     * [dataEndTime] => 2022-08-18T07:39:56+00:00
     * [createdTime] => 2022-08-18T07:39:56+00:00
     * [processingStartTime] => 2022-08-18T07:40:00+00:00
     * [dataStartTime] => 2022-08-18T07:39:56+00:00
     * ]
     */
    public function getreportstatus($SellerId, $site, $Path, $QueryParams = '', $Payload = '', $type = 'GET')
    {
        $headers = $this->getheaders($SellerId, $site, $Path, $QueryParams, $Payload, $type);
        $url = $this->geturl($site) . $Path;
        $data2 = $type == 'GET' ? $QueryParams : $Payload;
        $res2 = $this->cur_request($url, $type, "", $headers);
        $list = [];
        if ($res2[0] == 200) {
            $list = $res2[1];
        }
        return $list;
    }

    /** 申请报告
     * @param $SellerId
     * @param $Path
     * @param string $QueryParams
     * @param string $Payload
     * @param string $type
     * @return
     * [0]=>202
     * [1]=>['reportId'=>607810349222]
     */
    public function applicationreport($SellerId, $site, $Path, $QueryParams = '', $Payload = '', $type = 'POST')
    {
        $headers = $this->getheaders($SellerId, $site, $Path, $QueryParams, $Payload, $type);
        $url = $this->geturl($site) . $Path;//不同的站点对应的url不同
        if($type=='GET' && $QueryParams){
            $url = $url.'?';
            foreach ($QueryParams as $key=>$val){
                $url.=$key.'='.$val.'&';
            }
        }
        $url = rtrim($url,"&");
        $data2 = $type == 'GET' ? $QueryParams : $Payload;//内容
        $res2 = $this->cur_request($url, $type, is_array($data2)?json_encode($data2):$data2, $headers);
        $list = [];
        $list = $res2[1];
        return $list;
    }

    /** 获取订单
     * @param $SellerId
     * @param $Path
     * @param string $QueryParams
     * @param string $Payload
     * @param string $type
     * @return array|mixed
     */
    public function getorders($SellerId, $Path, $QueryParams = '', $Payload = '', $type = 'GET')
    {
        $headers = $this->getheaders($SellerId, $Path, $QueryParams, $Payload, $type);
        $url = $this->amzurl . $Path;
        if ($type == 'GET' && $QueryParams) {
            $url = $url . '?';
            foreach ($QueryParams as $key => $val) {
                $url .= $key . '=' . $val . '&';
            }
        }
        $url = rtrim($url, "&");
        $data = $type == 'GET' ? $QueryParams : $Payload;
        $res = $this->cur_request($url, $type, $data, $headers);
        if ($res[0] == 200) {
            return $res[1]['payload'];
        }
        return [];
    }

    /** 获取签名加密的头部信息
     * @param $SellerId APPID
     * @param $Path 路径
     * @param string $QueryParams URL参数
     * @param string $Payload Http Body参数
     * @return
     * data =>[
     *   'content-type'=>'application/json',
     *   'host'=>'sellingpartnerapi-eu.amazon.com',
     *   'x-amz-access-token'=>'Atza|IwEBIFeKuf0TMLRiErT21YMvY7zuvL2s7VU5-_Mo9hP3yMWPgY5_ojxZ0FfTceO8ml8670zIXMbFAg1aH7aTYnCyzYV1kqkOvzzS7__9zUmP8u0SU2f72hqxQ2xJ_0jfDauI547puR5fdOfESpAK3RlnngOr22RMzs1...',
     *   'x-amz-date'=>'20220818T073502Z',
     *   'Authorization'=>'AWS4-HMAC-SHA256 Credential=AKIAVXZJUCM74Z3OQDQ5/20220818/eu-west-1/execute-api/aws4_request, SignedHeaders=host;x-amz-access-token;x-amz-date, Signature=50f9c73125dc65c7e57a8beeca3af999fece248f0b96084abf9fdddec2ccba3e'
     * ]
     */
    public function getheaders($SellerId, $site, $Path, $QueryParams = '', $Payload = '', $type = 'GET')
    {
        if (!$SellerId || !$Path) {
            return '参数错误';
            exit();
        }
        $tdata = date('YmdHi', (time() - 8 * 3600));
        $tdata = substr_replace($tdata, 'T', 8, 0);
        $access_token = $this->gettoken($SellerId);
        $data = [
            "token" => $this->token,
            "action" => "Signature",
            "SellerId" => $SellerId,
            "config" => ["SiteID" => $this->sitelist[strtolower($site)], "Path" => $Path],
            "parameters" => [
                "AccessToken" => $access_token,
                "HttpMethod" => $type,
                "QueryParams" => $QueryParams,
                "Payload" => $Payload,
                "Timestamp" => $tdata . "02Z",
                "headers" => ["content-type" => "application/json"]
            ]
        ];
        $headers = [];
        $res = $this->cur_request($this->url, 'POST', json_encode($data), '');
        if ($res[0] == 200 && $res[1]['success'] == 1) {
            foreach ($res[1]['data']['headers'] as $key => $val) {
                $headers[] = $key . ":" . $val;
            }
        }
        return $headers;
    }

    /**获取access_token (因为是从ecpp获取的token,刷新token)
     * @param $SellerId
     * @return
     * data = [
     *    'access_token'=>'Atza|IwEBIDAOKLIaQGdlwms0KXma2ezFoJkfC6VkbuvWXGPhP8Yfpmyufcx-trU7Q4d5WbqS9pqTfh-Lqkg1LB81BOdiuCY....',
     *    'refresh_token'=>'Atzr|IwEBIAeGmiOy6aCYcAWzF2f6mxkfYJui7q5HFaVu94VdTS7yrTvqJWDVm2peQCMtvx0AhC6...',
     *    'token_type'=>'bearer',
     *    'expires_in'=>3600
     * ]
     */
    public function gettoken($SellerId)
    {
        $data = [
            "token" => $this->token,//ecpp的token
            "SellerId" => $SellerId,//appid也就是merchant_id
            "action" => "RefreshToken",
            "parameters" => [
                "RefreshToken" => $this->getecppinfo()[$SellerId]
            ]
        ];
        $res = $this->cur_request($this->url, 'POST', json_encode($data), '');
        $access_token = '';
        if ($res[0] == 200 && $res[1]['success'] == 1) {
            $access_token = $res[1]['data']['access_token'];
        }
        return $access_token;
    }

    public function getecppinfo()
    {//ecpp的token
        $url = "http://publish.xxxxx.com/services/yunyi/amazonapi/getecppinfo";
        $data = $this->cur_request($url, 'GET', "", "");
        return $data[1];
    }

    //请求函数
    public function cur_request($URL, $type, $params, $headers, $types = 0)
    {
        $ch = curl_init();
        curl_setopt($ch, CURLOPT_URL, $URL);
        if ($headers != "") {
            curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
        } else {
            curl_setopt($ch, CURLOPT_HTTPHEADER, array('Content-type: application/json'));
        }
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);
        curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
        curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 30);
        switch ($type) {
            case "GET" :
                curl_setopt($ch, CURLOPT_HTTPGET, true);
                break;
            case "POST":
                curl_setopt($ch, CURLOPT_POST, true);
                curl_setopt($ch, CURLOPT_POSTFIELDS, $params);
                break;
            case "PUT" :
                curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "PUT");
                curl_setopt($ch, CURLOPT_POSTFIELDS, $params);
                break;
            case "PATCH":
                curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'PATCH');
                curl_setopt($ch, CURLOPT_POSTFIELDS, $params);
                break;
            case "DELETE":
                curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "DELETE");
                curl_setopt($ch, CURLOPT_POSTFIELDS, $params);
                break;
        }
        $file_contents = curl_exec($ch);//获得返回值
        if ($types) {
            print_r('<pre>');
            print_r($file_contents);
            print_r('</pre>');
        }
        $responseCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
        if ($types) {
            print_r('<pre>');
            print_r($responseCode);
            print_r('</pre>');
        }
        curl_close($ch);
        return [$responseCode, json_decode($file_contents, true)];
    }

    /**
     * description: 文件下载
     * @throws CException
     */
    public function getFile($url, $save_dir = '', $filename = '', $type = 0)
    {
        if (trim($url) == '') {
            return false;
        }
        if (trim($save_dir) == '') {
            $save_dir = './';
        }
        if (0 !== strrpos($save_dir, '/')) {
            $save_dir .= '/';
        }
        //创建保存目录
        if (!file_exists($save_dir) && !mkdir($save_dir, 0777, true)) {
            return false;
        }
        //获取远程文件所采用的方法
        if ($type) {
            $ch = curl_init();
            $timeout = 5;
            curl_setopt($ch, CURLOPT_URL, $url);
            curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
            curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $timeout);
            $content = curl_exec($ch);
            curl_close($ch);
        } else {
            ob_start();
            readfile($url);
            $content = ob_get_contents();
            ob_end_clean();
        }
        //echo $content;
        $size = strlen($content);
        //文件大小
        $fp2 = @fopen($save_dir . $filename, 'a');
        @fwrite($fp2, $content);
        @fclose($fp2);
        unset($content, $url);
        return array(
            'status' => 1,
            'file_name' => $filename,
            'save_path' => $save_dir . $filename,
            'file_size' => $size
        );
    }

    //得到.gz压缩包的内容
    public function read_gz($gz_file)
    {
        $buffer_size = 4096; // read 4kb at a time
        $file = gzopen($gz_file, 'rb');
        $str = '';
        while (!gzeof($file)) {
            $str .= gzread($file, $buffer_size);
        }
        gzclose($file);
        return $str;
    }

    //用yield读取大文件
    public function read_yield_gz($gz_file)
    {
        $buffer_size = 4096; // read 4kb at a time
        $file = gzopen($gz_file, 'rb');
        while (!gzeof($file)) {
            yield gzread($file, $buffer_size);
        }
        gzclose($file);
    }

    /**
     * description: 读取CSV
     * @throws CException
     *  使用 $csvlist = $this->modelapi->readCSV($url.'kaufland_'.$val['id_report'].'.csv');
     *  foreach ($csvlist as $key=>$vd){}
     */
    public function readCSV($filename)
    {
        $fp = fopen($filename, 'rb');
        while (!feof($fp)) {
            yield fgetcsv($fp);
        }
        fclose($fp);
    }

    //过滤表情信息
    private function filter_emoji($str = '')
    {
        preg_match_all('/[\x{4e00}-\x{9fff}\d\w\s[:punct:]]+/u', $str, $result);
        return join('', $result[0]);
    }

    //对文本文件结果进行解析
    public function turnTxt2Array($txt, $account_id)
    {
        $array = array();
        $txt = explode("\n", $txt);
        $keys = array_map('trim', explode("\t", str_replace('-', '_', array_shift($txt))));
        array_push($keys, 'account_id', 'update_time');//添加自己的 账户ID和时间
        foreach ($txt as $unit) {
            $unit = str_replace('--', 0, $unit);
            $unit = array_map('trim', explode("\t", $unit));
            $unit[3] = base64_encode($unit[3]);
            array_push($unit, $account_id, time());//对应的账户和时间内容
            if (count($keys) != count($unit)) {
                continue;
            }
            $array[] = array_combine($keys, $unit);
        }
        return $array;
    }

}

 

拉取listing           GET_MERCHANT_LISTINGS_ALL_DATA
拉取库龄报告          GET_FBA_INVENTORY_AGED_DATA
FBA管理库存健康报告   GET_FBA_INVENTORY_PLANNING_DATA
fba退货报告           GET_FBA_FULFILLMENT_CUSTOMER_RETURNS_DATA
fba移除报告           GET_FBA_FULFILLMENT_REMOVAL_ORDER_DETAIL_DATA
抓取fba配送费         GET_PAN_EU_OFFER_STATUS
fba配送费报告         GET_FBA_ESTIMATED_FBA_FEES_TXT_DATA
亚马逊预留库存        GET_RESERVED_INVENTORY_DATA
自发货退货报告(每次只能拉取60天的数据) GET_XML_RETURNS_DATA_BY_RETURN_DATE
日期范围报告(无法申请报告的爬虫模拟后台登陆点击申请报告再接口拉取) GET_DATE_RANGE_FINANCIAL_TRANSACTION_DATA

 

#自发货退货报告
$time = date("Y-m-d H:i:s");
$start_date = str_replace(' ','T',$start_date1);
$end_date = str_replace(' ','T',$end_date1);
$result = $requestReport->applicationreport($account->merchant_id,strtolower($account->site),'/reports/2021-06-30/reports',"",["reportType"=>self::REPORT_TYPE,'dataStartTime'=>$start_date,'dataEndTime'=>$end_date,"marketplaceIds"=>[$account->market_place_id]]);

 日期范围报告   GET_DATE_RANGE_FINANCIAL_TRANSACTION_DATA

#获取报告结果
$result = $requestReport->applicationreport($account->merchant_id,strtolower($account->site),'/reports/2021-06-30/reports?reportTypes='.self::REPORT_TYPE.'&marketplaceIds='.$account->market_place_id,'','','GET');

#得到下载连接
$result = $requestReport->getreportsurl($account->merchant_id,$account->site,'/reports/2021-06-30/documents/'.$val['reportdocumentid'],"","","GET");//获取报告下载链接