php 批量发货功能修改记录

269 阅读2分钟

公司运营的商城系统是基于萤火商城二开的。其中批量发货功能由之前的程序员开发发,在发送数量,和性能都存在很大的问题。抽出时间来对该功能进行梳理。首先展示下发货的模板,

image.png

image.png 基本思路整理:上传csv文件 ->获取csv文件内容 -> 获取订单号验证是否存在 -> 更新订单商品表发货状态 -> 更新订单表发货状态(这里注意一个订单对应多个商品时的发货状态处理)

第一步:获取.csv文件方法:

private function getCsvData()
{
    // 获取表单上传文件 例如上传了001.jpg
    if (!$file = \request()->file('iFile')) {
        $this->error = '请上传发货模板';
        return false;
    }
    // 设置区域信息
    setlocale(LC_ALL, 'zh_CN');
    // 打开上传的文件
    $csvFile = fopen($file->getInfo()['tmp_name'], 'r');
    // 忽略第一行(csv标题)
    fgetcsv($csvFile);
    // 遍历并记录订单信息
    $orderList = [];
    $msg = '模板文件数据不合法';
    while ($item = fgetcsv($csvFile)) {
        if (isset($item[0]) && !empty($item[0]) && isset($item[1]) && !empty($item[1])) {
            unset($msg);
        }
        if(isset($msg)){
            fclose($csvFile);
            $this->error = $msg;
            return false;
        }
        $orderList[] = $item;
    }
    if (empty($orderList)) {
        fclose($csvFile);
        $this->error = '模板文件中没有订单数据';
        return false;
    }
    fclose($csvFile);
    return $orderList;
}

第二步到第四步:订单号处理:

 public function batchDelivery($data)
    {
        // 获取csv文件中的数据  if ( (!$csvData = $this->getCsvData() ) || (!$excelData = $this->getExcelData() ) ) {
        $csvData = $this->getCsvData() ;
        //  $csvData 数据过滤   这一步也可以省略
        if($csvData && !empty($csvData)){
            foreach ($csvData as $k => $value){
                if (isset($value[0])){
                    $csvData[$k][0] =trim(strip_tags(substr($value[0],0)));//注意获取订单号 要去除空格
                }
            }
        } else{
           return false;
        }
        //第三步:获取订单号验证是否存在
        
        // 整理订单要发货的订单order_no集
        $orderNos = helper::getArrayColumn($csvData, 0);    //整理所有订单号 成为数组
        // 获取订单列表数据
        $orderList = helper::arrayColumn2Key(($this->getListByOrderNos($orderNos)),'order_no');

        // 验证订单是否存在
        $tempArr = array_values(array_diff($orderNos, array_keys($orderList)));
        if (!empty($tempArr)) {
            $this->error = "订单号[{$tempArr[0]}] 不存在!";
            return false;
        }
        
          // 验证订单是否满足发货条件
         if (!$this->verifyDelivery($orderList)) {
           return false;
         }
         
        //  第四步: 更新订单商品表发货状态(方法在下面)
        //根据提供信息更新订单商品表
        $this->updateOrderGoods($csvData,$orderList);

        //第五步:  更新订单表发货状态
        //检查此订单下商品是否有未发货的,如果都已发货更新整个订单的状态
        $orderGoods=new OrderGoodsModel();      //实例化订单商品表模型
        $orderModel=new OrderModel();           //实例化订单表

        $orderGoodsdeliverylist= [];
        $updateOrderList=array();

        foreach ($csvData as $item) {
            $order_id=$orderList[$item[0]]['order_id'];
            //更新一个订单多个商品 订单的物流信息
            //查询查询订单商品表 该订单下的商品是否全部发货。是更新订单表该订单状态为已发货  否则只更新订单商品表发货状态    //该查询语句还可以优化
            $orderGoods20=$orderGoods->where('order_id','=',$order_id)->where('delivery_status','=',20)->field('order_goods_id')->find();

//            if ($orderList[$item[0]]['delivery_status']['value'] == 20){
            if ($orderGoods20){     //更新订单表订单状态
                $orderGoodsdeliverylist[] =array(
                    'express_id' => $item[3],
                    'express_no'=>$item[1],
                    'express_company'=>eval('return '.iconv('gbk','utf-8',var_export($item[4],true)).';'),
                    'delivery_time'=>time(),
                    'delivery_status'=>20,
                    'order_id'=>$order_id
                );
            }else{      // 多个商品未发货订单只更新订单表物流单号
                $updateOrderList[]=array(
                    'order_id'=>$order_id,
                    'express_id'=>$item[3],
                    'express_no'=>$item[1],
                    'express_company'=>eval('return '.iconv('gbk','utf-8',var_export($item[4],true)).';')
                );

            }
        }
        // 更新订单发货状态(批量)    updateToDelivery 方法在下面
        if ($status = $this->updateToDelivery($updateOrderList)){
            //更新更新一个订单多个商品 类订单 已发过货的订单状态
            $deliverystatus= $orderModel->isUpdate(false)->saveAll($orderGoodsdeliverylist);

            // 获取已发货的订单
            $completed = $this->getListByOrderNos($orderNos, ['user', 'address', 'goods', 'express']);
            // 发送消息通知
            $this->sendDeliveryMessage($completed);
            //  同步好物圈订单
            (new WowService(self::$wxapp_id))->update($completed);
        }
        return $status;
    }
    
//  第四步:
 /**
* 更新订单商品的发货数据信息,一个订单存在多个商品
* @param $data array
* @return bool
*/

public function updateOrderGoods($data=array(),$orderList=array()){
        if(!isset($data)){return false;}
        $goodsOrder=array();
        $orderGoods=new OrderGoodsModel();
        //更新订单商品表
        foreach($data as $k => $v){
            if (!empty($v[0])){
                $goodsOrder[$k]['order_goods_id']=trim($v[2]);
                $goodsOrder[$k]['delivery_status']=20;
                $goodsOrder[$k]['delivery_no']=$v[1];
                $goodsOrder[$k]['delivery_id']=$v[3];
                $goodsOrder[$k]['delivery_time']=time();
                $goodsOrder[$k]['delivery_name']=eval('return '.iconv('gbk','utf-8',var_export($v[4],true)).';');
            }
        }
        $orderGoods->saveAll($goodsOrder);
    }
    

/**
 * 更新订单发货状态(批量)
 * @param $orderList
 * @return array|false
 * @throws \Exception
 */
private function updateToDelivery($orderList)
{   
    if(!isset($orderList)){return false;}
    $data = [];
    foreach ($orderList as $item) {
        $data[] = [
            'order_id' => $item['order_id'],
            'express_no' => $item['express_no'],
            'express_id' => $item['express_id'],
            'delivery_status' => 20,
            'delivery_time' => time(),
        ];
    }
    return $this->isUpdate()->saveAll($data);
}

以上就是订单批量发货的全部方法。该方法是在tp5 框架中使用的。主要方法都贴出来了,有些调用模型查数据的方法都是常用的,没有贴出。之所以记录,是因为之前的技术在这个方法中饶了很多弯,在每一次更新数据前都调用数据库查询方法链接数据库,导致批量发货的数量和稳定性都很差。我花了好几天的功夫才把他写的代码吃透,把这个方法优化处理了下。 特在此简单记录,以备以后用到。 供网友们借鉴。