公司最近在推进铺货工具的开发和优化,所谓铺货,指的是是说服零售商经销本企业产品的一系列过程,是企业与经销商(或上线经销商与下线经销商)之间合作在短期内开拓市场的一种活动,简而言之就是把上游供应商的商品放到自己的零售店铺里来销售,公司的铺货工具根植于1688大市场,拥有庞大的货源和供应商,具有天然优势,而且大多供应商都支持一件代发,零售商无后顾之忧。
作为铺货工具自然会涉及到最近火热的新电商平台——拼多多,但不同平台之间的商品的属性,规格,详情等各种信息格式并不相同,导致铺货的成功率堪忧,为优化成功率,我们进行了大量的探索和优化。
根据拼多多的成功率分析,我们发现有一些商品是因为规格值过于庞大,超多了拼多多的限制。拼多多的规则是规格值的和要小于30,笛卡尔积要小于484,针对这一点,我们准备开发一套针对过多的规格之进行拆分的算法规则。
根据用户的使用习惯和接受度,我们计划最多将同一个商品拆分为3个商品铺货,更多的话将由用户主动选择铺货的规格,不进行自动拆分。根据此原则,我先标记出了边界值,如下:
当单规格时,规格数>90则不计算,
当双规格值时,两个规格值同时大于22则不计算,
当三规格时,三个规格值同时大于11则不计算,
其他更多规格不考虑。
然后根据多种规格指情况来逐条分析:
单规格商品,当拆分时,判断是否大于60,大于则将之除以3取整x,取余y(可为0),如果余数为2,则分为x,x+1,x+1三个规格,如果不为2则为x,x,x+y。若不大于60,则判断是否大于30,大于则将之除以2取证n,取余m,分为,n和n+m。
是双规格值,当拆分时,先判断是否两个规格相加小于等于30若是则不拆分,若不是,则判断两个规格中更小的一个和30的差值*3是否大于等于较大的哪一个,若大于,则可以分,否则不行。拆分时,先判断两个规格中更小的一个和30的差值*2是否大于等于较大的一个,若大于,则将之除以2取证n,取余m,分为,n和n+m。否则,将较大的一个除以3取整x,取余y(可为0),如果余数为2,则分为x,x+1,x+1三个规格,如果不为2则为x,x,x+y。
当是三规格时,先判断三个规格相加是否小于等于30并且相乘小于等于484,若是则不拆分,若不是,则找到三个数中最大的一个,判断30-另外两个数的和之后的值乘上3,是否大于等于最大数,若大于,则可分,否则不行。拆分时,先判断30-另外两个数的和之后的值乘上2,是否大于等于最大数,若大于,则将之除以2取证n,取余m,分为,n和n+m。否则,将最大的一个除以3取整x,取余y(可为0),如果余数为2,则分为x,x+1,x+1三个规格,如果不为2则为x,x,x+y。
根据此原则可以将一个多规格的商品规格拆分成多个符合拼多多要求的商品进行铺货,同时拆分的规格值尽量平均。
以上是在开始写代码之前的逻辑分析,下面是具体的代码:
//循环获取sku的规格属性组合值,data为商品的规格数据,即每个规格的组合后的值组成的数组,也就是用户实际看到的组合后的sku值
function revolveskuinfos($data){
$specone = array();
$spectwo = array();
$specthree = array();
//判断规格值种类是否大于3规格
$specount = count($data[0]->attributes);
if($specount<=3){
foreach ($data as $dataone) {
for($i=0;$i<count($dataone->attributes);$i++){
//双层循环找到最里层的数据
$dataonearr = json_encode($dataone->attributes);
$newdataonearr = json_decode($dataonearr,true);
//找到属性1,2,3的独立不重复的值,组合进三个数组
switch ($i){
case 0:{
if (in_array($newdataonearr[$i],$specone)) {
}else{
$specone[] = $newdataonearr[$i];
}
}
break;
case 1:{
if (in_array($newdataonearr[$i],$spectwo)) {
}else{
$spectwo[] = $newdataonearr[$i];
}
}
break;
case 2:{
if (in_array($newdataonearr[$i],$specthree)) {
}else{
$specthree[] = $newdataonearr[$i];
}
}
break;
default:
}
}
}
//返回三个数组的个数和他们的规格之名字
$this->splitskuinfo(count($specone),count($spectwo),count($specthree),$specount,$specone[0]['attributeDisplayName'],$spectwo[0]['attributeDisplayName'],$specthree[0]['attributeDisplayName']);
}else{
//大于3规格直接略过
return $this->setJsonResponse(array('value'=>'out','code'=>404));
}
}
//拆分规格的函数
function splitskuinfo($specountone,$specounttwo,$specountthree,$specount,$spenameone,$spenametwo,$spenamethree){
$resspecone = $specountone;
$resspectwo = $specounttwo;
$resspecthree = $specountthree;
$splitgoodsnumber = 1;
//区分是单规格还是双规格还是三规格
switch ($specount){
case 1:{
if($specountone>90){
//单规格,规格值大于90,略过
return $this->setJsonResponse(array('value'=>'out','code'=>404));
}else{
if($specountone>60){
//单规格,规格值小于90大于60,拆分3份
$resspecone = $this->splitthree($specountone);
$splitgoodsnumber = 3;
}else{
//单规格,规格值小于60大于30,拆分2份
if($specountone>30){
$resspecone = $this->splittwo($specountone);
$splitgoodsnumber = 2;
}else{
//其他情况不拆分
$resspecone = 'nouse';
}
}
}
}
break;
case 2:{
if($specountone>22&&$specounttwo>22){
//双规格,两个规格都大于22,略过
return $this->setJsonResponse(array('value'=>'out','code'=>404));
}else{
if($specountone+$specounttwo<=30){
//双规格,两个规格和小于30,不拆分
$resspecone = 'nouse';
$resspectwo = 'nouse';
}else{
if($specountone>$specounttwo){
//双规格,找到规格值中较大的一个
if((30-$specounttwo)*3>=$specountone){
//当较小的一个和30的差值的3倍大于较大的一个时
if((30-$specounttwo)*2>=$specountone){
//判断较小的一个和30的差值的2倍大于较大的一个时,拆分2分
$resspecone = $this->splittwo($specountone);
$splitgoodsnumber = 2;
}else{
//判断较小的一个和30的差值的2倍不大于较大的一个但3倍大于时,拆分3分
$resspecone = $this->splitthree($specountone);
$splitgoodsnumber = 3;
}
}else{
return $this->setJsonResponse(array('value'=>'out','code'=>404));
}
}else{
//同理处理当第二个规格值较大时
if((30-$specountone)*3>=$specounttwo){
if((30-$specountone)*2>=$specounttwo){
$resspectwo = $this->splittwo($specounttwo);
$splitgoodsnumber = 2;
}else{
$resspectwo = $this->splitthree($specounttwo);
$splitgoodsnumber = 3;
}
}else{
return $this->setJsonResponse(array('value'=>'out','code'=>404));
}
}
}
}
}
break;
case 3:{
if($specountone>11&&$specounttwo>11&&$specountthree>11){
//三规格,当三个规格都小于11时,略过
return $this->setJsonResponse(array('value'=>'out','code'=>404));
}else{
if(($specountone+$specounttwo+$specountthree)<=30&&($specountone*$specounttwo*$specountthree)<=484){
//三规格,当三个规格的和小于30,笛卡尔积小于484时,不用拆分
$resspecone = 'nouse';
$resspectwo = 'nouse';
$resspecthree = 'nouse';
}else{
//找到最大的一个数
$biggest = max($specountone,$specounttwo,$specountthree);
switch($biggest){
//当最大的数分别是三个的三种处理情况
case $specountone:{
if((30-$specounttwo-$specountthree)*3>=$specountone){
if((30-$specounttwo-$specountthree)*2>=$specountone){
$resspecone = $this->splittwo($specountone);
$splitgoodsnumber = 2;
}else{
$resspecone = $this->splitthree($specountone);
$splitgoodsnumber = 3;
}
}else{
return $this->setJsonResponse(array('value'=>'out','code'=>404));
}
}break;
case $specounttwo:{
if((30-$specountone-$specountthree)*3>=$specounttwo){
if((30-$specountone-$specountthree)*2>=$specounttwo){
$resspectwo = $this->splittwo($specounttwo);
$splitgoodsnumber = 2;
}else{
$resspectwo = $this->splitthree($specounttwo);
$splitgoodsnumber = 3;
}
}else{
return $this->setJsonResponse(array('value'=>'out','code'=>404));
}
}break;
case $specountthree:{
if((30-$specountone-$specounttwo)*3>=$specountthree){
if((30-$specountone-$specounttwo)*2>=$specountthree){
$resspecthree = $this->splittwo($specountthree);
$splitgoodsnumber = 2;
}else{
$resspecthree = $this->splitthree($specountthree);
$splitgoodsnumber = 3;
}
}else{
return $this->setJsonResponse(array('value'=>'out','code'=>404));
}
}break;
default:
}
}
}
}
break;
default:
}
return $this->setJsonResponse(array('value'=>'split',$spenameone=>$resspecone,$spenametwo=>$resspectwo,$spenamethree=>$resspecthree,'splitgoodsnumber'=>$splitgoodsnumber,'code'=>200));
}
//封装拆分两份的方法,返回拆分后应分割成的两个数
function splittwo($data){
$n = intval(floor($data/2));
$m = $data%2;
return array($n,$n+$m);
}
//封装拆分三份的方法,返回拆分后应分割成的三个数
function splitthree($data){
$x = intval(floor($data/3));
$y = $data%3;
$res = array();
if($y==2){
$res = array($x,$x+1,$x+1);
}else{
$res = array($x,$x,$x+$y);
}
return $res;
}
网友评论