物品扫码领用与库存

This commit is contained in:
2026-02-24 11:28:12 +08:00
parent 7098f30af2
commit cd692594e4
18 changed files with 1192 additions and 51 deletions
+84 -10
View File
@@ -124,16 +124,28 @@ class InvItemService
* @param int $itemId 物品ID
* @param int $changeQty 变动数量:>0 入库,<0 出库
* @param bool $allowNegative 是否允许库存变成负数,默认不允许
*
* @param array $options 额外选项(用于记录日志)
* - biz_type: 业务类型
* - biz_no: 单据号
* - operator_id: 操作人ID
* - operator_name: 操作人姓名
* - remark: 备注
* @return InvItem 最新的物品记录
* @throws BusinessException
*/
public function changeStock(int $itemId, int $changeQty, bool $allowNegative = false): InvItem
public function changeStock(int $itemId, int $changeQty, bool $allowNegative = false, array $options = []): InvItem
{
if ($changeQty === 0) {
throw new BusinessException('库存变动数量不能为 0');
}
// 获取变动前的库存(用于日志)
$itemBefore = InvItem::query()->find($itemId);
if (!$itemBefore) {
throw new BusinessException('物品不存在');
}
$beforeQty = $itemBefore->stock_qty;
$now = time();
// 构建查询
@@ -154,39 +166,101 @@ class InvItemService
// 更新不到行:
// 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);
// 记录库存变化日志
$this->recordStockLog([
'item_id' => $itemId,
'item_name_snap' => $item->item_name,
'change_qty' => $changeQty,
'before_qty' => $beforeQty,
'after_qty' => $item->stock_qty,
'biz_type' => $options['biz_type'] ?? null,
'biz_no' => $options['biz_no'] ?? null,
'operator_id' => $options['operator_id'] ?? null,
'operator_name' => $options['operator_name'] ?? null,
'remark' => $options['remark'] ?? null,
], $changeQty);
return $item;
}
/**
* 出库(减库存,默认不允许负数)
*
* @param int $itemId 物品ID
* @param int $qty 出库数量
* @param bool $allowNegative 是否允许负数
* @param array $options 日志选项(同 changeStock)
* @return InvItem
* @throws BusinessException
*/
public function stockOut(int $itemId, int $qty, bool $allowNegative = false): InvItem
public function stockOut(int $itemId, int $qty, bool $allowNegative = false, array $options = []): InvItem
{
if ($qty <= 0) {
throw new BusinessException('出库数量必须大于 0');
}
return $this->changeStock($itemId, -$qty, $allowNegative);
// 确定变动类型:2-出库(领用)或 3-出库(损耗)
$changeType = $options['change_type'] ?? \app\common\model\InvStockLog::CHANGE_TYPE_OUT_CLAIM;
return $this->changeStock($itemId, -$qty, $allowNegative, array_merge($options, [
'change_type' => $changeType,
'remark' => $options['remark'] ?? '领用出库',
]));
}
/**
* 入库(加库存)
*
* @param int $itemId 物品ID
* @param int $qty 入库数量
* @param array $options 日志选项(同 changeStock)
* @return InvItem
* @throws BusinessException
*/
public function stockIn(int $itemId, int $qty): InvItem
public function stockIn(int $itemId, int $qty, array $options = []): InvItem
{
if ($qty <= 0) {
throw new BusinessException('入库数量必须大于 0');
}
return $this->changeStock($itemId, $qty, true);
// 确定变动类型:1-入库 或 4-入库(归还)
$changeType = $options['change_type'] ?? \app\common\model\InvStockLog::CHANGE_TYPE_IN;
return $this->changeStock($itemId, $qty, true, array_merge($options, [
'change_type' => $changeType,
'remark' => $options['remark'] ?? '入库',
]));
}
/**
* 记录库存变化日志
*
* @param array $logData
* @param int $changeQty 变动数量
* @return void
*/
private function recordStockLog(array $logData, int $changeQty): void
{
try {
// 根据变动数量确定变动类型(如果未指定)
if (!isset($logData['change_type'])) {
if ($changeQty > 0) {
$logData['change_type'] = \app\common\model\InvStockLog::CHANGE_TYPE_IN;
} else {
$logData['change_type'] = \app\common\model\InvStockLog::CHANGE_TYPE_OUT_CLAIM;
}
}
(new InvStockLogService())->record($logData);
} catch (\Throwable $e) {
// 日志记录失败不影响主业务,仅记录错误
error_log('库存日志记录失败: ' . $e->getMessage());
}
}
/**