引言
上次我们讲了 MWS 与订单相关的开发 ,这次我们就来讲如何通过 MWS 接口上传产品。
上传产品
上传产品有几种方式,此处我们采用的是提交类型为 _POST_FLAT_FILE_LISTINGS_DATA_
的 Feed 方式来上传产品。因为这种方式兼容性比较强。
思路
思路就是先生成一个包含产品信息的 csv 文件,再去请求 MWS 接口。
实现
《订单篇》 我有提到一个 MWS PHP 的库,但是再开发产品上传功能的时候,被这个库坑惨了,由于作者不维护了,即使提了 PR 也没人合并,所以我 Fork 了一份,自己直接改了代码,修复了 bug,欢迎你们使用我的这个库 forecho/amazon-mws 。
安装库
使用方式,先修改你项目的 composer.json
文件,添加如下代码
1
2
3
4
5
6
7
8
9
10
11
12
"require": {
// ...
"mcs/amazon-mws": "*",
// ...
},
"repositories": [
{
"name": "mcs/amazon-mws",
"type": "git",
"url": "git@github.com:forecho/amazon-mws.git"
}
]
然后再执行如下命令:
1
composer require mcs/amazon-mws
如果在执行命令行的时候提示需要输入 Token
的话,解决办法就是去 GitHub 的 Personal access tokens 页面,点击「Generate new token」新建一个 Token,选择 public_repo
,然后就会得到一个 Token,然后去终端输入这个值就可以继续了。
原来的库上传产品非常简单,更是没有提供 _POST_FLAT_FILE_LISTINGS_DATA_
的方式上传产品,我在这个 issue#30 - Add Product Error 的基础上加了此功能。
上传产品的伪代码
下面是我上传产品的伪代码,可以拿来参考:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
<? php
public function uploadAmazon (string $productType , Product $product , int $productNode , $otherAttributes = [])
{
$client = new MCS\MWSClient([
'Marketplace_Id' => '' ,
'Seller_Id' => '' ,
'Access_Key_ID' => '' ,
'Secret_Access_Key' => '' ,
'MWSAuthToken' => '' // Optional. Only use this key if you are a third party user/developer
]);
$amazonProducts = [];
$postItems = [];
$amazonProduct = new AmazonMarketPlaceProduct();
if ($product -> productSku ) {
$amazonProduct -> setSku ($product -> parent_sku )
-> setFeedProductType ($productType )
-> setBrand ($product -> brand )
-> setTitle ($product -> title )
-> setManufacturer ($product -> manufacturer )
-> setRecommendedBrowseNodes ($productNode )
-> setParentChild ('Parent' )
-> setOtherAttributes (\app\core\helpers\ArrayHelper:: clearValue ($otherAttributes ))
-> setVariationTheme ($product -> variation_theme );
array_push($amazonProducts , $amazonProduct );
array_push($postItems , $amazonProduct -> toArray (false ));
foreach ($product -> productSku as $productSku ) {
$retailPrice = $productSku -> retail_price ?: 0 ;
$salePrice = $productSku -> sale_price ?: 0 ;
$saleDate = $salePrice ? explode('~' , $productSku -> sale_date ) : [];
$_amazonProduct = clone $amazonProduct ;
$_amazonProduct -> setSku ($productSku -> product_sku )
-> setFeedProductType ($productType )
-> setBrand ($product -> brand )
-> setTitle ($product -> title )
-> setManufacturer ($product -> manufacturer )
-> setPrice ($retailPrice > 0 ? CurrencyConverter:: CNYConverter ($currency , $retailPrice ) : '' )
-> setSalePrice ($salePrice > 0 ? CurrencyConverter:: CNYConverter ($currency , $salePrice ) : '' )
-> setProductId ($amazonProductId )
-> setSizeName ($productSku -> size ?: '' )
-> setColorName ($productSku -> color ?: '' )
-> setProductIdType ('EAN' )
-> setCurrency ($currency )
-> setConditionType ('New' )
-> setWeight ($product -> weight )
-> setQuantity ($product -> quantity )
-> setParentChild ('Child' )
-> setParentSku ($parentSku )
-> setSaleFromDate (count($saleDate ) == 2 ? $saleDate [0 ] : '' )
-> setSaleEndDate (count($saleDate ) == 2 ? $saleDate [1 ] : '' )
-> setVariationTheme ($product -> variation_theme )
-> setKeywords ($product -> search_keyword )
-> setRecommendedBrowseNodes ($productNode )
-> setBulletPoint ($features )
-> setDescription ($product -> description )
-> setOtherAttributes ($otherAttributes )
-> setImage ($productSku -> images );
array_push($amazonProducts , $_amazonProduct );
array_push($postItems , $_amazonProduct -> toArray (false ));
}
} else {
$retailPrice = $product -> price ?: 0 ;
$salePrice = $product -> sale_price ?: 0 ;
$saleDate = $salePrice ? explode('~' , $product -> sale_date ) : [];
$amazonProduct -> setSku ($parentSku )
-> setFeedProductType ($productType )
-> setBrand ($product -> brand )
-> setTitle ($product -> {$titleAttribute })
-> setManufacturer ($product -> manufacturer )
-> setPrice ($retailPrice > 0 ? CurrencyConverter:: CNYConverter ($currency , $retailPrice ) : '' )
-> setSalePrice ($salePrice > 0 ? CurrencyConverter:: CNYConverter ($currency , $salePrice ) : '' )
-> setProductId ($amazonProductId )
-> setProductIdType ('EAN' )
-> setCurrency ($currency )
-> setConditionType ('New' )
-> setWeight ($product -> weight )
-> setQuantity ($product -> quantity )
-> setSaleFromDate (count($saleDate ) == 2 ? $saleDate [0 ] : '' )
-> setSaleEndDate (count($saleDate ) == 2 ? $saleDate [1 ] : '' )
-> setKeywords ($product -> search_keyword )
-> setRecommendedBrowseNodes ($productNode )
-> setBulletPoint ($features )
-> setDescription ($product -> description )
-> setOtherAttributes ($otherAttributes )
-> setImage ($product -> images );
array_push($amazonProducts , $amazonProduct );
array_push($postItems , $amazonProduct -> toArray (false ));
}
// You can also submit an array of MWSProduct objects
$feed = $client -> postProduct (
$amazonProducts ,
'fptcustomcustom' ,
'2019.0501' ,
'SE9NRV9MSUdIVElOR19BTkRfTEFNUFM='
);
Yii:: info ($postItems , $product -> id . '上传产品数据' );
return $feed ;
}
上传产品是一个异步接口,提交成功会返回如下数据:
1
2
3
4
5
6
[
'FeedSubmissionId' => 'xxxxxxx' , // 一串数字
'FeedType' => '_POST_FLAT_FILE_LISTINGS_DATA_' ,
'SubmittedDate' => '2019-08-08T10:15:29+00:00' ,
'FeedProcessingStatus' => '_SUBMITTED_' ,
]
要想获取结果,需要过两分钟之后再去请求另外一个接口,你可以用下面方法实现:
1
$client -> GetFeedSubmissionResult ($FeedSubmissionId );
如果成功返回的信息是了类似这样的:
1
2
3
4
5
Feed Processing Summary:
Number of records processed 2
Number of records successful 2
如果失败就类似这样的:
1
2
3
4
5
6
7
Feed Processing Summary:
Number of records processed 4
Number of records successful 3
original-record-number sku error-code error-type error-message
14 3uC000670-Random combination-Large*2+Sma 90118 Error The item_sku field contains an invalid value: 3uC000670-Random combination-Large*2+Small*2. The value exceeds the maximum number of bytes allowed: 40.
注意事项
编码问题
我最开始上传产品的时候,产品上传成功了,但是去亚马逊后台看,产品是乱码的,解决这个问题花了我几天时间。导致这个问题出现的原因就是编码问题。
meertensm/amazon-mws 提交接口的时候使用的是 iso-8859-1
编码,这意味着上传 CSV 文件的时候,要先把内容转成对应的格式。问题是并非所有的亚马逊站点都是用这个编码,日本就是用 UTF-8
编码的 ,所以之前上传产品到日本站点总算乱码。听说中国站点也是 UTF-8
编码,不过这已经不重要了,因为亚马逊这部分业务已经退出中国了。此问题我已经在 forecho/amazon-mws 解决 ,你可以不用关心此细节。
另外一个需要注意的编码问题就是,在使用 GetFeedSubmissionResult()
方法获取刊登结果时候,日本站返回的数据是 Shift-JIS
的,这个需要你手动转一下:
1
2
3
if ($isJp ) {
$string = mb_convert_encoding($string , 'UTF-8' , 'Shift-JIS' )
}
产品图片
上传产品的时候图片我们是给的图片地址链接,如果图片放在国内,很容易出现亚马逊下载产品图片超时导致的刊登失败。所以我们要想办法把我们的图片存到海外,比方说使用阿里的 OSS。
如果因为用了阿里 OSS 的海外 Bucket,导致我们在使用的时候上传图片很慢,可以了解一下这个《OSS 全球传输加速开启公测,助力企业业务全地域覆盖》 。
UPC/EAN
这个可以通过购买生成器生成 UPC 和 EAN,也可以购买合法 UPC/EAN。生成器生成的容易导致上传产品失败,换一个重新上传产品即可。有时候发现你上传的产品出现别人的图片,不要慌,这个就是因为 UPC/EAN 跟别人重复导致的,换一个重新上传产品即可。
关于产品描述
产品描述除了不能大于 2000 字符串之外,还不能使用除了 <br>
(换行)和 <b></b>
(加粗)之外的 HTML 标签。
SKU 异常
出现上传产品失败,错误信息 SKU 异常的,如 8008 错误,这种情况一般也是因为 UPC/EAN 有问题导致的,我们可以把异常的 SKU 的 UPC/EAN 在 美国统一代码委员会网站
查询,如果查询到有结果,说明你就不能使用此 UPC/EAN,换一个 UPC/EAN 重新上传即可。
总结
上传产品也是比较核心的功能,开发此功能比我开发同步订单花了更多时间,踩了不少坑,现在分享出来,让大家少走一点弯路。
相关文章
打赏
微信打赏
支付宝打赏