| 
					
				 | 
			
			
				@@ -1,420 +0,0 @@ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-<?php 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-namespace app\common\service; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-use Carbon\Carbon; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-use think\Validate; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-use think\facade\Db; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-use app\common\model\Io; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-use app\common\model\Good; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-use app\common\model\Repo; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-use app\common\model\Admin; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-use app\common\model\Stock; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-use app\common\model\IoDetail; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-use app\common\util\WhereBuilder; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-use app\common\util\PhpSpreadsheetExportV2; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-class IoService extends Service 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    /** 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-     * 处理分页请求 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-     *  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-     * @param array $params 请求参数数组 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-     * @return mixed 分页结果 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-     */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    public function page($params = []) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        // 自动处理请求参数 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        $this->autoParams($params); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        // 从请求参数中获取相关值 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        $type = $this->pg('type'); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        $change_type = $this->pg('change_type'); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        $keyword = $this->pg('keyword'); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        $repo_id = $this->pg('repo_id'); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        $begin_date = $this->pg('begin_date'); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        $end_date = $this->pg('end_date'); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        // 如果存在结束日期,则向后延长一天 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        if ($end_date) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            $end_date = Carbon::parse($end_date)->addDay()->toDateString(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        // 获取是否包含运输状态参数 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        $contain_transit = $this->pgd(false, 'contain_transit'); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        // 构建查询条件 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        $where = WhereBuilder::builder() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            ->like('io.sn|r.name|io.remark', $keyword) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            ->in('io.type', $type) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            ->in('io.change_type', $change_type) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            ->in('io.repo_id', $repo_id) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            ->between('io.date', $begin_date, $end_date) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            ->where('d.transit_status', 'in', [IoDetail::TRANSIT_STATUS_TRANSIT, IoDetail::TRANSIT_STATUS_TRANSIT], $contain_transit) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            ->build(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        // 构建查询对象 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        $query = (new Io) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            ->alias('io') 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            ->field('io.*, r.name as repo_name') 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            ->join('repo r', 'r.id = io.repo_id'); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        // 如果包含运输状态,则进行关联查询 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        if ($contain_transit) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            $query = $query->join('io_detail d', 'd.io_id = io.id'); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        // 执行分页查询 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        $page = $query->where($where) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            ->order('io.create_time desc') 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            ->paginate($this->tp6Page()); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        // 添加附加字段到分页结果集 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        $page->getCollection()->append(['change_type_text']); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        // 返回分页结果 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        return $page; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    /** 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-     * 获取Io信息 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-     *  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-     * @param array $params 请求参数数组 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-     * @return mixed Io对象 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-     */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    public function info($params = []) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        // 自动处理请求参数 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        $this->autoParams($params); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        // 查询单个Io对象 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        $io = $this->one(Io::class); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        // 添加附加字段到Io对象 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        $io->append(['change_type_text', 'details', 'repo', 'details.good']); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        // 返回Io对象 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        return $io; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    /** 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-     * 创建运输记录事务 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-     *  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-     * @param Admin $admin 管理员对象 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-     * @param array $params 请求参数数组 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-     * @return mixed 运输记录创建结果 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-     */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    public function createTrans(Admin $admin, $params = []) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        // 使用数据库事务执行创建操作 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        return Db::transaction(fn() => $this->create($admin, $params)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    /** 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-     * 创建运输记录 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-     *  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-     * @param Admin $admin 管理员对象 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-     * @param array $params 请求参数数组 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-     * @return mixed 创建的Io对象 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-     * @throws \Exception 创建失败时抛出异常 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-     */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    public function create(Admin $admin, $params = []) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        // 自动处理请求参数 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        $params = $this->autoParams($params); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        // 如果存在管理员对象,则将管理员ID赋值给参数数组 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        if ($admin) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            $params['admin_id'] = $admin->id; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        // 查询Repo对象 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        $repo = $this->one(Repo::class, 'repo_id'); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        // 获取出入库明细 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        $details = $this->pg('details'); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        // 过滤掉数量为0的明细 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        $details = array_filter($details, fn($detail) => $detail['num']); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        // 创建Io对象 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        $io = Io::create($params); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        // 赋值并检查明细 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        foreach ($details as &$detail) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            $detail['io_id'] = $io->id; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            $detail['date'] = isset($detail['date']) && $detail['date'] ? $detail['date'] : $io->date; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            $detail['type'] = isset($detail['type']) && $detail['type'] ? $detail['type'] : $io->type; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            $detail['repo_id'] = isset($detail['repo_id']) && $detail['repo_id'] ? $detail['repo_id'] : $io->repo_id; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            // 检查出入库数量 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            if ($detail['num'] == 0) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                $good = Good::find($detail['good_id']); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                throw $this->exception("物品--{$good?->name}的出入库数量不能为0"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            if ($detail['num'] > 0 && $detail['type'] == Io::TYPE_OUT) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                $good = Good::find($detail['good_id']); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                throw $this->exception("物品--{$good?->name}的出入库数量大于0但是类型为出库"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            if ($detail['num'] < 0 && $detail['type'] == Io::TYPE_IN) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                $good = Good::find($detail['good_id']); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                throw $this->exception("物品--{$good?->name}的出入库数量小于0但是类型为入库"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        // 保存出入库明细 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        $details = (new IoDetail)->saveAll($details); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        // 在oninsert事件中进行库存变更 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        $io->details = $details; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        // 返回创建的Io对象 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        return $io; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    /** 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-     * 导出运输记录 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-     *  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-     * @param array $params 请求参数数组 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-     * @return mixed 导出结果 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-     */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    public function export($params = []) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        // 自动处理请求参数 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        $this->autoParams($params); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        $type = $this->pg('type'); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        // 获取起始日期和结束日期 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        $begin_date = $this->pg('begin_date'); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        $end_date = $this->pg('end_date'); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        // 如果存在结束日期,则向后延长一天 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        if ($end_date) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            $end_date = Carbon::parse($end_date)->addDay()->toDateString(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        // 构建查询条件 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        $where = WhereBuilder::builder() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            ->in('io.type', $type) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            ->between('i.date', $begin_date, $end_date) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            ->build(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        // 导出表格的表头 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        $header = [ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            [ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                '编号', 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                '仓库名', 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                '出入库类型', 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                '变更原因', 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                '备注', 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                '来源', 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                '创建时间', 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                '日期', 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                '物品名', 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                '数量', 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                '明细备注', 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                '在途状态', 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                '归还数量', 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                '遗失数量' 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            ] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        ]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        // 构建查询字段中的change_type_export 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        $changeTypeField = <<<SQL 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            CASE i.change_type  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                WHEN 1 THEN "出入库"  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                WHEN 2 THEN "调拨"  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                WHEN 3 THEN "盘点"  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                ELSE "出入库"  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            END as change_type_export 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        SQL; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        // 构建查询字段中的transit_status_export 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        $transitStatusField = <<<SQL 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            CASE d.transit_status 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                WHEN "TRANSIT" THEN "在途" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                WHEN "COMPLETED" THEN "完成" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                ELSE "" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            END as transit_status_export 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        SQL; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        // 执行查询 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        $details = (new IoDetail)->alias('d') 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            ->field('i.sn, r.name as repo_name, if(i.type = 1, "入库", "出库")') 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            ->field($changeTypeField) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            ->field('i.remark, i.source, i.create_time, i.date') 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            ->field('g.name as good_name, d.num, d.remark as detail_remark') 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            ->field($transitStatusField) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            ->field('d.transit_received, d.transit_lost') 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            ->join('io i', 'i.id = d.io_id', 'LEFT') 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            ->join('repo r', 'r.id = i.repo_id', 'LEFT') 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            ->join('good g', 'g.id = d.good_id', 'LEFT') 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            ->where($where) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            ->select() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            ->toArray(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        // 导出表格文件 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        $res = PhpSpreadsheetExportV2::outputFile( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            $details, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            $header, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            'io' . date('Ymdis'), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            [] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        ); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        // 返回导出结果 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        return $res; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    public function completeTrans(Admin $admin, $params = []) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        return Db::transaction(fn() => $this->complete($admin, $params)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    public function complete(Admin $admin, $params = []) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        $params = $this->autoParams($params); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        $this->validate($params, new CompleteValidate); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        $transits = $this->pg('transits'); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        foreach ($transits as &$transit) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            /** 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-             * @var IoDetail 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-             */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            $detail = IoDetail::find($transit['id']); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            $stock = (new Stock) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                ->where('repo_id', '=', $detail->repo_id) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                ->where('good_id', '=', $detail->good_id) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                ->find(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            // 检查数量 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            $num = abs($detail->num); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            if ($transit['transit_received'] + $transit['transit_lost'] == $num) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                $transit['transit_status'] = IoDetail::TRANSIT_STATUS_COMPLETED; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            } elseif ($transit['transit_received'] + $transit['transit_lost'] > $num) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                throw $this->exception("到达/归还数量{$transit['transit_received']} 加 在途遗失数{$transit['transit_lost']} 大于该出入库明细的数量:{$num}"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            } elseif ($transit['transit_received'] < $detail->transit_received) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                throw $this->exception("到达/归还数量{$transit['transit_received']} 比原来还少了!(原数量:{$detail->transit_received}) 如发现归还数量错误,请使用盘点功能"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            } elseif ($transit['transit_lost'] < $detail->transit_lost) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                throw $this->exception("在途遗失数量{$transit['transit_lost']} 比原来还少了!(原数量:{$detail->transit_lost}) 如发现遗失后又归还,请使用盘点功能"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            } else { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                $transit['transit_status'] = isset($transit['transit_status']) ? $transit['transit_status'] : IoDetail::TRANSIT_STATUS_TRANSIT; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            $stock->num += self::getTypeMul($detail->type) * ($transit['transit_received'] - $detail->transit_received); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            $stock->save(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        (new IoDetail)->allowField(['transit_status', 'transit_received', 'transit_lost'])->saveAll($transits); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        return true; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    public function revertTrans(Admin $admin, $params = []) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        return Db::transaction(fn() => $this->revert($admin, $params)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    protected function revert(Admin $admin, $params = []) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        $this->autoParams($params); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        $io = $this->one(Io::class); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        if ($io->revert_id) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            return true; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        $revertData = [ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            'repo_id' => $io->repo_id, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            'date' => date('Ymd'), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            'type' => self::inverseIoType($io['type']), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            'sn' => 'REVERT_T' . hrtime(true) . '_SN' . rand(100000, 999999), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            'remark' => "回滚自$io->sn", 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            'admin_id' => $admin->id, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            'change_type' => $io->change_type, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            'source' => "$io->sn" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        ]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        $revert = Io::create($revertData); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        $revertDetails = []; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        foreach ($io->details as $detail) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            $revertDetail = [ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                'repo_id' => $detail->repo_id, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                'good_id' => $detail->good_id, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                'num' => -$detail['num'], 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                'date' => date('Ymd'), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                'type' => self::inverseIoType($detail['type']), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                'remark' => '回滚', 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                'io_id' => $revert->id, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            ]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            $revertDetails[] = $revertDetail; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        $details = (new IoDetail)->saveAll($revertDetails); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        $io->revert_id = $revert->id; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        $io->save(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        return $revert; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    /** 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-     * 翻转出入库类型 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-     * 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-     * @param int $type 出入库类型 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-     * @return int 翻转后的出入库类型 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-     */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    protected static function inverseIoType(int $type) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        return $type == Io::TYPE_IN ? Io::TYPE_OUT : Io::TYPE_IN; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    /** 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-     * 获取出入库类型的乘数 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-     * 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-     * @param int $type 出入库类型 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-     * @return int 出入库类型的乘数 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-     */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    protected static function getTypeMul(int $type) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        return $type == Io::TYPE_IN ? 1 : -1; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-class CreateIoValidate extends Validate 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    protected $rule = [ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        'repo_id|仓库' => 'require', 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        'valid|状态' => 'require', 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        'type|出入库类型' => 'require', 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        'change_type|变更类型' => 'require', 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        'details|出入库内容' => 'checkDetails', 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    ]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    protected function checkDetails($details) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        if (!is_array($details)) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            return 'details必须为数组'; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        if (!$details) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            return '出入库内容不能为空'; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        $setAndNotEmpty = fn($item, $index) => isset($item[$index]) && $item[$index]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        $requires = ['good_id', 'num', 'type', 'remark']; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        foreach ($details as $index => $detail) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            foreach ($requires as $require) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                if (!$setAndNotEmpty($detail, $require)) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    return "details[$index].$require 不能为空"; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            $good_id = $detail['good_id']; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            $good = Good::find($good_id); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            if (!$good) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                return "未找到物品对象, id={$good_id}"; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        return true; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-class CompleteValidate extends Validate 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    protected $rule = [ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        'transits' => 'array' 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    ]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-} 
			 |