// +---------------------------------------------------------------------- declare (strict_types=1); namespace app\store\model\goods; use think\Paginator; use think\db\exception\DbException; use PhpOffice\PhpSpreadsheet\Exception; use app\job\controller\goods\AdminImport as GoodsAdminImportJob; use app\job\controller\goods\GoodsStoreImport as GoodsStoreImportJob; use app\job\controller\goods\GoodsUpdateImport as GoodsUpdateImportJob; use app\common\enum\goods\ImportStatus as GoodsImportStatusEnum; use app\common\library\FileLocal; use app\common\library\helper; use app\common\library\phpoffice\ReadExecl; use app\common\model\goods\Import as ImportModel; use cores\exception\BaseException; use app\common\model\Goods as GoodsModel; use app\common\model\GoodsSku as GoodsSkuModel; use app\store\model\GoodsCategoryRel as GoodsCategoryRelModel; /** * 商品批量导入记录模型 * Class Import * @package app\store\model\goods */ class Import extends ImportModel { /** * 获取导出记录 * @param array $param * @return Paginator * @throws DbException */ public function getList(array $param = []): \think\Paginator { $where = $this->getFilter($param); if (isset($param['channels']) && $param['channels']) { $where[] = ['channel', 'in', $param['channels']]; } return $this->where($where) ->where('is_delete', '=', 0) ->order(['create_time' => 'desc', $this->getPk()]) ->paginate(); } /** * 获取查询条件 * @param array $param * @return array */ private function getFilter(array $param = []): array { // 默认查询参数 $params = $this->setQueryDefaultValue($param, ['goods_type' => -1, 'status' => -1]); // 检索查询条件 $filter = []; $params['status'] > -1 && $filter[] = ['status', '=', (int)$params['status']]; isset($params['store_id']) && $params['store_id'] > -1 && $filter[] = ['store_id', '=', (int)$params['store_id']]; isset($params['merchant_id']) && $params['merchant_id'] > -1 && $filter[] = ['merchant_id', '=', (int)$params['merchant_id']]; return $filter; } /** * 执行批量导入 * @param array $form * @return bool * @throws BaseException * @throws Exception * @throws \PhpOffice\PhpSpreadsheet\Reader\Exception */ public function adminBatch(array $form): bool { // 读取excel文件内容 $execlData = $this->readExecl(); // echo "
";
        // print_r($execlData);
        // exit();
        // 验证导入的商品数量是否合法
        $this->checkLimit($execlData);
        self::$merchantId = $form['merchant_id'] ?? 0;
        self::$storeId = $form['store_id'] ?? 0;
        foreach ($execlData as &$value) {
            $value['A0'] = $form['channel']??'zy';
        }
        // $obj = new \app\job\service\goods\AdminImport();
        // $service = new \app\job\service\goods\Collector();
        // foreach ($execlData as $item) {
        //     $info = \app\common\model\Goods::where('goods_no', $item['C'])->where('store_id', self::$storeId)->where('channel', $item['B'])->where('is_delete',0)->find();
        //     // var_dump($item['C']);
        //     // var_dump($info);
        //     if ($info) {
        //         var_dump($info->goods_id);
        //         $this->successCount++;
        //         continue;
        //     }
        //     //var_dump($info->goods_id);
        //     //exit();
        //     $data = $obj->createData($item, self::$storeId);
        //     $service->single($item['D'], $data, self::$storeId);
        //     // // 记录导入成功
        //     // $this->successCount++;
        // }
        // var_dump(\count($execlData));
        // exit();
        // 新增商品导入记录
        $recordId = $this->addRecord(\count($execlData), $form['channel'] ?? 'zy');

        
        // 调度计划任务
        $this->adminDispatchJob($execlData, $recordId);
        return true;
    }
    /**
     * 执行批量导入
     * @param array $form
     * @return bool
     * @throws BaseException
     * @throws Exception
     * @throws \PhpOffice\PhpSpreadsheet\Reader\Exception
     */
    public function storeBatch(array $form): bool
    {
        // 读取excel文件内容
        $execlData = $this->readExecl();
        // echo "
";
        // print_r($execlData);
        // exit();
        // 验证导入的商品数量是否合法
        $this->checkLimit($execlData);
        
        self::$storeId = $form['store_id'] ?? 0;
        self::$merchantId = $form['merchant_id'] ?? 0;
        
        foreach ($execlData as &$value) {
            $value['channel'] = $form['channel']??'zy';
        }


        $obj = new \app\job\service\goods\GoodsStoreImport();
        $service = new \app\job\service\goods\Collector();
        foreach ($execlData as $item) {
            $info = \app\common\model\Goods::where('goods_no', $item['C'])->where('store_id', self::$storeId)->where('merchant_id', self::$merchantId)->where('channel', $item['channel'])->where('is_delete',0)->find();
            // var_dump($item['C']);
            // var_dump($info);
            if ($info) {
                var_dump($info->goods_id);
                $this->successCount++;
                continue;
            }
            //var_dump($info->goods_id);
            //exit();
            $data = $obj->createData($item, self::$storeId, self::$merchantId);
            $service->single($item['D'], $data, self::$storeId);
            exit();
            // // 记录导入成功
            // $this->successCount++;
        }
        var_dump(\count($execlData));
        exit();
        


        // 新增商品导入记录
        $recordId = $this->addRecord(\count($execlData), $form['channel'] ?? 'zy');

        
        // 调度计划任务
        $this->storeDispatchJob($execlData, $recordId);
        return true;
    }
    /**
     * 执行批量更新
     * @param array $form
     * @return bool
     * @throws BaseException
     * @throws Exception
     * @throws \PhpOffice\PhpSpreadsheet\Reader\Exception
     */
    public function goodsUpdateBatch (array $form): bool
    {
        // 读取excel文件内容
        $execlData = $this->readExecl();
        
        // echo "
";
        // print_r($execlData);
        // exit();
        // 验证导入的商品数量是否合法
        $this->checkLimit($execlData);
        
        self::$storeId = $form['store_id'] ?? 0;
        self::$merchantId = $form['merchant_id'] ?? 0;
        // $obj = new \app\job\service\goods\GoodsUpdateImport();
        // $service = new \app\job\service\goods\Collector();
        // foreach ($execlData as $item) {

        //     $data = $obj->createData($item, self::$storeId);
        //     // echo "
";
        //     // print_r($data);
        //     // exit();
        //     $service->updateGoods($item['G'], $data, self::$storeId);
        //     exit();
        //     // // 记录导入成功
        //     // $this->successCount++;
        // }

        // 新增商品导入记录
        $recordId = $this->addRecord(\count($execlData), $form['channel'] ?? 'zy');

        
        // 调度计划任务
        $this->goodsUpdateJob($execlData, $recordId);
        return true;
    }
    /**
     * 执行批量更新
     * @param array $form
     * @return bool
     * @throws BaseException
     * @throws Exception
     * @throws \PhpOffice\PhpSpreadsheet\Reader\Exception
     */
    public function storeGoodsUpdateBatch(array $form): bool
    {
        // 读取excel文件内容
        $execlData = $this->readExecl();
        
        // echo "
";
        // print_r($execlData);
        // exit();
        // 验证导入的商品数量是否合法
        $this->checkLimit($execlData);
        
        self::$storeId = $form['store_id'] ?? 0;
        foreach ($execlData as $key => $value) {

            $upData = [
                'goods_name'=> $value['B'],
                'cmmdty_model'=> $value['C'],
                'goods_source'=> $value['D'],
                //'goods_no'=> $value['E'],
                'delivery_time'=> $value['G'],
                'is_check'=> $value['H'],
                'delivery_id'=> $value['I'],
                'status'=> $value['J'],
                // 'cost_price_min'=> $value['K'],
                // 'goods_price_min'=> $value['L'],
                // 'goods_price_max'=> $value['L'],
                // 'line_price_min'=> $value['L'],
                // 'line_price_max'=> $value['L'],
                'stock_total'=> $value['M'],
                'remark'=> $value['N'],
                'is_use_jd_stock'=> $value['O'],
            ];
            $goods = GoodsModel::where('goods_id', $value['A'])->find();
            if (!$goods) {
                continue;
            }
            //自营数据才能更新价格
            if (in_array($goods['channel'], ['zy'])) {
                $upData['goods_no'] = $value['E'];
                $upData['cost_price_min'] = $value['K'];
                $upData['goods_price_min' ]= $value['L'];
                $upData['goods_price_max'] = $value['L'];
                $upData['line_price_min'] = $value['L'];
                $upData['line_price_max'] = $value['L'];
                $profit = (float)$upData['goods_price_min'] - (float)$upData['cost_price_min'];
                $profit_rate = (float)$upData['goods_price_min'] > 0 ? bcmul(bcdiv((string)$profit, (string)$upData['goods_price_min'], 2), (string)100, 2) : 0.00;
                $upData['profit'] = $profit;
                $upData['profit_rate'] = $profit_rate;
                GoodsSkuModel::where('goods_id', $value['A'])->update(['cost_price' => $value['K'], 'goods_price' => $value['L']]);
            }

            // echo "
";
            // print_r(explode(",", $value['F']));
            // exit();
            GoodsModel::where('goods_id', $value['A'])->update($upData);
            
            GoodsCategoryRelModel::updates((int)$value['A'], explode(",", $value['F']));
        }
        return true;
    }
    /**
     * 执行批量导入
     * @param array $form
     * @return bool
     * @throws BaseException
     * @throws Exception
     * @throws \PhpOffice\PhpSpreadsheet\Reader\Exception
     */
    public function goodsUpdateBatch1(array $form): bool
    {
        // 读取excel文件内容
        //$execlData = $this->readExecl();
         // 接收用户上传的模板文件
        $file = request()->file('file');
        empty($file) && throwError('很抱歉,您没有上传模板文件');
        // 写入到本地临时目录
        $path = FileLocal::writeFile($file, 'batch-goods', self::$storeId);
        $file = fopen($path, "r");
        $data = array();
        $i = 0;
        while (($line = fgetcsv($file)) !== false) {
            // foreach ($line as $key => &$value) {
            //     $value = mb_convert_encoding($value, 'UTF-8', "GBK");
            // }
            


            // echo "
";
            // print_r($line);
            // exit();
            if ($i == 0) {
                $i++;
                continue;
            }
            // $line是当前行的所有数据,可以根据实际需求进行处理
            $execlData[] = $line; // 将每一行数据保存到$data数组中
            $i++;
        }
         
        fclose($file);
        // echo "
";
        // print_r($execlData);
        // exit();
        // 验证导入的商品数量是否合法
        $this->checkLimit($execlData);
        
        self::$storeId = $form['store_id'] ?? 0;
        // $obj = new \app\job\service\goods\GoodsUpdateImport();
        // $service = new \app\job\service\goods\Collector();
        // foreach ($execlData as $item) {

        //     $data = $obj->createData($item, self::$storeId);
        //     // echo "
";
        //     // print_r($data);
        //     // exit();
        //     $service->updateGoods($item[6], $data, self::$storeId);
        //     exit();
        //     // // 记录导入成功
        //     // $this->successCount++;
        // }

        // 新增商品导入记录
        $recordId = $this->addRecord(\count($execlData));

        
        // 调度计划任务
        $this->goodsUpdateJob($execlData, $recordId);
        return true;
    }
    /**
     * 调度队列服务执行商品导入
     * @param array $goodsList 商品列表
     * @param int $recordId 商品导入记录ID
     * @return void
     */
    private function goodsUpdateJob(array $goodsList, int $recordId)
    {
        // 分批每次导入20条
        $limit = 20;
        // 根据商品总数量计算需要的队列任务数量
        $jobCount = \count($goodsList) / $limit;
        // 逐次发布队列任务
        for ($i = 0; $i < $jobCount; $i++) {
            $data = array_slice($goodsList, $i * $limit, $limit);
            GoodsUpdateImportJob::dispatch([
                'list' => $data,
                'recordId' => $recordId,
                'storeId' => self::$storeId,
            ]);
        }
    }
    /**
     * 调度队列服务执行商品导入
     * @param array $goodsList 商品列表
     * @param int $recordId 商品导入记录ID
     * @return void
     */
    private function adminDispatchJob(array $goodsList, int $recordId)
    {
        // 分批每次导入20条
        $limit = 20;
        // 根据商品总数量计算需要的队列任务数量
        $jobCount = \count($goodsList) / $limit;
        // 逐次发布队列任务
        for ($i = 0; $i < $jobCount; $i++) {
            $data = array_slice($goodsList, $i * $limit, $limit);
            GoodsAdminImportJob::dispatch([
                'list' => $data,
                'recordId' => $recordId,
                'storeId' => self::$storeId,
            ]);
        }
    }
    /**
     * 调度队列服务执行商品导入
     * @param array $goodsList 商品列表
     * @param int $recordId 商品导入记录ID
     * @return void
     */
    private function storeDispatchJob(array $goodsList, int $recordId)
    {
        // 分批每次导入20条
        $limit = 20;
        // 根据商品总数量计算需要的队列任务数量
        $jobCount = \count($goodsList) / $limit;
        // 逐次发布队列任务
        for ($i = 0; $i < $jobCount; $i++) {
            $data = array_slice($goodsList, $i * $limit, $limit);
            GoodsStoreImportJob::dispatch([
                'list' => $data,
                'recordId' => $recordId,
                'storeId' => self::$storeId,
                'merchantId' => self::$merchantId,
            ]);
        }
    }
    
    /**
     * 执行批量导入
     * @param array $form
     * @return bool
     * @throws BaseException
     * @throws Exception
     * @throws \PhpOffice\PhpSpreadsheet\Reader\Exception
     */
    public function batch(array $form): bool
    {
        // 读取excel文件内容
        $execlData = $this->readExecl();
        // 验证导入的商品数量是否合法
        $this->checkLimit($execlData);
        // 格式化导入的商品列表数据
        $goodsList = $this->formatGoodsList($execlData);
        // 新增商品导入记录
        $recordId = $this->addRecord(\count($goodsList));
        // 调度计划任务
        $this->dispatchJob($goodsList, $recordId);
        return true;
    }

    /**
     * 调度队列服务执行商品导入
     * @param array $goodsList 商品列表
     * @param int $recordId 商品导入记录ID
     * @return void
     */
    private function dispatchJob(array $goodsList, int $recordId)
    {
        // 分批每次导入20条
        $limit = 20;
        // 根据商品总数量计算需要的队列任务数量
        $jobCount = \count($goodsList) / $limit;
        // 逐次发布队列任务
        for ($i = 0; $i < $jobCount; $i++) {
            $data = array_slice($goodsList, $i * $limit, $limit);
            GoodsImportJob::dispatch([
                'list' => $data,
                'recordId' => $recordId,
                'storeId' => self::$storeId,
            ]);
        }
    }

    /**
     * 新增商品导入记录
     * @param int $totalCount 商品总数量
     * @return int
     */
    private function addRecord(int $totalCount, string $channel = 'zy'): int
    {
        $this->save([
            'total_count' => $totalCount,
            'start_time' => \time(),
            'fail_log' => [],
            'status' => GoodsImportStatusEnum::NORMAL,
            'store_id' => self::$storeId,
            'merchant_id' => self::$merchantId,
            'channel' => $channel,
        ]);
        return (int)$this['id'];
    }
    
    /**
     * 格式化导入的商品列表数据
     * @param array $execlData
     * @return array
     */
    private function formatGoodsList(array $execlData): array
    {
        $goodsList = [];
        foreach ($execlData as $row) {
            // 不存在商品序号的记录视为空行跳过
            if (!is_numeric($row['A'])) {
                continue;
            }
            // SKU信息
            $skuInfo = helper::pick($row, ['G', 'H', 'I', 'J', 'K', 'L', 'M', 'N']);
            // 商品数据里不存在相同序号, 代表是第一次记录
            if (!isset($goodsList[$row['A']])) {
                $goodsList[$row['A']] = $row;
                // 存在规格值组合则商品是多规格
                if (!empty($row['H'])) {
                    $goodsList[$row['A']]['skuList'] = [$skuInfo];
                }
            } elseif (isset($goodsList[$row['A']]['skuList'])) {
                // 否则代表是多规格商品的SKU
                $goodsList[$row['A']]['skuList'][] = $skuInfo;
            }
        }
        return array_values($goodsList);
    }

    /**
     * 验证导入的商品数量是否合法
     * @param array $execlData
     * @return void
     * @throws BaseException
     */
    private function checkLimit(array $execlData): void
    {
        // 判断商品数据是否为空
        if (empty($execlData)) {
            throwError('很抱歉,模板文件中商品数量为空');
        }
        // 过滤重复的商品序号
        $originalUnique = helper::arrayUnique($execlData, 'A');
        // 判断商品数量是否超出500条
        if (\count($originalUnique) > 500) {
            throwError('很抱歉,模板文件中最多不能超过500个商品');
        }
    }

    /**
     * 读取excel文件内容
     * @return array
     * @throws BaseException
     * @throws \PhpOffice\PhpSpreadsheet\Exception
     * @throws \PhpOffice\PhpSpreadsheet\Reader\Exception
     */
    private function readExecl(): array
    {
        // 接收用户上传的模板文件
        $file = request()->file('file');
        empty($file) && throwError('很抱歉,您没有上传模板文件');
        // 写入到本地临时目录
        $path = FileLocal::writeFile($file, 'batch-goods', self::$storeId);
        // 读取excel数据
        $original = ReadExecl::load($path, 0, 21);
        // 去除标题数据
        unset($original[1]);
        // 过滤空行和无效的内容
        // foreach ($original as $key => $row) {
        //     if (!is_numeric($row['A']) || empty($row['A'])) {
        //         unset($original[$key]);
        //     }
        // }
        return $original;
    }

    /**
     * 删除记录
     * @return bool
     */
    public function setDelete(): bool
    {
        if ($this['status'] == GoodsImportStatusEnum::NORMAL) {
            $this->error = '很抱歉,当前任务没有结束不能删除';
            return false;
        }
        return $this->save(['is_delete' => 1]);
    }
}