logic = (new InvItemLogic()); } /** * 获取验证器 */ public function getValidator() { return new $this->validator; } /** * 构造 CrudUtil 查询配置 */ protected function buildQueryConfig(Request $request, string $scene = 'default'): array { $p = $request->all(); $config = []; $config['model'] = $this->modelClass; switch ($scene) { case 'default': $config['where']['status'] = 1; $config['order']['sort'] = 'desc'; $config['order']['id'] = 'desc'; break; case 'index': $config['where']['status'] = 1; // 关键字 if (isset($p['keyword']) && $p['keyword']) { $k = '%' . $p['keyword'] . '%'; foreach (['item_name'] as $col) { $config['orWhere'][] = [$col, 'like', $k]; } } $config['order']['sort'] = 'desc'; $config['order']['id'] = 'desc'; break; case 'show': $config['where']['id'] = $p['id']; $config['where']['status'] = 1; break; case 'store': break; case 'update': $config['where']['id'] = $p['id']; break; case 'destroy': $config['where']['id'] = $p['id']; break; } return $config; } /** * 生成 8-12 位的物品编码(默认10位) * * @param int $length 编码长度,默认为10(范围 8-12) * @return string 返回大写的字母数字组合编码 */ private function generateItemCode($length = 10) { // 排除易混淆字符:0, O, o, 1, I, l $chars = '23456789ABCDEFGHJKLMNPQRSTUVWXYZ'; $code = ''; $maxIndex = strlen($chars) - 1; for ($i = 0; $i < $length; $i++) { $code .= $chars[mt_rand(0, $maxIndex)]; } return $code; } public function beforeServiceStore($data, Request $request): array { $data['item_code'] = $this->generateItemCode(); $data['category_id'] = 0; $data['spec_model'] = ''; $data['unit'] = '件'; $data['is_consumable'] = 0; $data['stock_qty'] = 1; $data['location'] = ''; return $data; } /** * 变动物品库存数量 * * @param int $itemId 物品ID * @param int $changeQty 变动数量:>0 入库,<0 出库 * @param bool $allowNegative 是否允许库存变成负数,默认不允许 * * @return InvItem 最新的物品记录 * @throws BusinessException */ public function changeStock(int $itemId, int $changeQty, bool $allowNegative = false): InvItem { if ($changeQty === 0) { throw new BusinessException('库存变动数量不能为 0'); } $now = time(); // 构建查询 $query = InvItem::query()->where('id', $itemId); // 如果不允许负数,并且是出库场景(变动为负) if (! $allowNegative && $changeQty < 0) { // 要保证:当前 stock_qty >= 出库数量 $query->where('stock_qty', '>=', -$changeQty); } // 使用 increment 实现:UPDATE inv_item SET stock_qty = stock_qty + ?, updated_at = ? WHERE ... $affected = $query->increment('stock_qty', $changeQty, [ 'updated_at' => $now, ]); if ($affected === 0) { // 更新不到行: // 1) 物品不存在 // 2) 或者库存不足(不允许负数时) $exists = InvItem::query()->where('id', $itemId)->exists(); if (! $exists) { throw new BusinessException('物品不存在'); } throw new BusinessException('库存不足,无法完成库存变动'); } // 再查一次最新数据返回(在外层事务中也会保持一致) /** @var InvItem $item */ $item = InvItem::query()->find($itemId); return $item; } /** * 出库(减库存,默认不允许负数) */ public function stockOut(int $itemId, int $qty, bool $allowNegative = false): InvItem { if ($qty <= 0) { throw new BusinessException('出库数量必须大于 0'); } return $this->changeStock($itemId, -$qty, $allowNegative); } /** * 入库(加库存) */ public function stockIn(int $itemId, int $qty): InvItem { if ($qty <= 0) { throw new BusinessException('入库数量必须大于 0'); } return $this->changeStock($itemId, $qty, true); } /** * 获取车型list */ public function getList() { return $this->logic->getList(); } }