复盘下上周:通过excel表格批量导入商品库存及成本。
通过表格中的商品货号找到该商品,再通过匹配表格中的规格名称导入对应数据。
正式导入前,会先将匹配不到的数据返回至前台进行展示。
问题在于,平台伙伴也许对规格名称有其他的叫法,所以还需要在导入的基础上增加一个信息配置——将伙伴的属性名称对应平台的系统属性名称上。(当然,平台的一个系统属性有可能对应多个伙伴属性名称)
表格导入写过不下5次了,这次却翻车翻得最惨——再次感慨自己的基础知识薄弱。
确定表头
最开始想好的表头顺序为:商品货号、规格1……规格n、库存、成本。(示例:maatwebsite)
出于用户需求,表头必须是中文。所以读取数据就只能通过下标数值进行读取。
\Excel::load($file_path, function ($reader) use ($data){ //通过表头判断表格是否合法 $temp = clone $reader; $header_now = array_filter($temp->takeRows(3)->toArray()[0]??[]); $header = ['商品货号','库存','成本']; foreach($header as $k=>$v){ if(!isset($header_now[$k])||!$header_now[$k]==$v){ throw new GoodsException('表格不合法'); } } $data = $reader->all()->toArray(); }
首先判断表头是否合法,咱不能啥表都往这儿送。之所以clone $reader是因为$reader只能读取一次,类似读一次指针就停在了最终位置,无法反复使用。判断了表头还得用它获取所有的数据。
接着,就要判断表格内容是否合法了。
$item_sheet = array_filter($item_sheet); if(empty($item_sheet)){ continue; } if(!isset($item_sheet[0])){ continue; }
如果出现某行无数据,就直接跳过。这也是上方第一行代码为什么要array_filter的意义。但问题就来了——如果某行表格数据也不合法,库存与成本都没有数据,在不确定规格属性到底有几个的情况下,无法通过数值下标去获取到。
所以这样的表格格式无法使用。
调整后的表头:商品货号、库存、成本、规格1……规格n
将无法确定的规格放在表头最后,这样能够通过下方对库存与成本进行获取。
isset($item_sheet[1]) ? $item_sheet[1] : 0 isset($item_sheet[2]) ? $item_sheet[2] : ''
通过规格名称组合成唯一的sku
通过获取货号,可以拿到对应商品下的所有规格。
判断表格里的名称是否存在,如果不存在,再去信息配置中寻找是否有伙伴配置的不一样的属性名称。最终拿到所有属性id。
还没完,拿到所有对应的属性后,还要通过算法找出不同顺序组合下的组合再进行最后的匹配。
祭出烧掉好几十万脑细胞的笛卡尔乘积算法:
protected function cartesian($array,$arr = array()){ //去除第一个元素 $first = array_shift($array); //判断是否是第一次进行拼接 if(count($arr) > 0) { foreach ($arr as $k => $val) { foreach ($first as $key => $value) { $arr2[] = $val.','.$value; } } }else{ foreach ($first as $key => $value) { $arr2[] = $value; } } //递归进行拼接 if(count($array) > 0){ $arr2 = $this->cartesian($array,$arr2); } $tmp = []; foreach ($arr2 as $v){ $tmp_arr = explode(',',$v); sort($tmp_arr); $tmp[] = implode('__',$tmp_arr); } //返回最终笛卡尔积 return $tmp; }
最后,匹配商品对应的唯一的sku。
我的问题
1、最开始想的只用名称去找就好了,但是如果有信息配置里的名称与系统名称重合时,我的名称组合就无法找准是哪一个了。这个最开始就该想到。
2、表格式的问题也是如此。
3、数据结构不清晰。
综上,丧了我一上午,还是要谢谢我的锅巴。
本文作者为MingJun,转载请注明。