first version
This commit is contained in:
@@ -0,0 +1,59 @@
|
||||
<?php
|
||||
|
||||
namespace App\Services;
|
||||
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use InvalidArgumentException;
|
||||
|
||||
/**
|
||||
* 单号生成服务
|
||||
*
|
||||
* 规则:前缀 + yyyyMMdd + 4 位序列,如 PO202607230001;
|
||||
* 按「前缀+当日」已生成的最大序列自增。
|
||||
*
|
||||
* 并发安全提示:本服务取当日最大单号 +1,依赖各单号字段的唯一索引兜底,
|
||||
* 高并发生成场景(如采购单汇总)须在事务内配合行锁调用(见 PurchaseGenerateService)。
|
||||
*/
|
||||
class BillNumberService
|
||||
{
|
||||
/**
|
||||
* 前缀 → [表名, 单号字段] 映射
|
||||
*
|
||||
* @var array<string, array{0: string, 1: string}>
|
||||
*/
|
||||
private const NUMBER_SOURCES = [
|
||||
'PO' => ['purchase_order', 'purchase_no'],
|
||||
'SO' => ['store_order', 'order_no'],
|
||||
'RC' => ['reconciliation', 'recon_no'],
|
||||
'ST' => ['statement', 'statement_no'],
|
||||
'JS' => ['settlement', 'settlement_no'],
|
||||
];
|
||||
|
||||
/**
|
||||
* 生成业务单号
|
||||
*
|
||||
* @param string $prefix 业务前缀:PO 采购单 / SO 订货单 / RC 对账 / ST 对账单 / JS 结算
|
||||
* @return string 如 PO202607230001
|
||||
*/
|
||||
public function make(string $prefix): string
|
||||
{
|
||||
$prefix = strtoupper($prefix);
|
||||
$source = self::NUMBER_SOURCES[$prefix]
|
||||
?? throw new InvalidArgumentException('不支持的单号前缀:' . $prefix);
|
||||
|
||||
[$table, $column] = $source;
|
||||
$datePrefix = $prefix . now()->format('Ymd');
|
||||
|
||||
$maxNo = DB::table($table)
|
||||
->where($column, 'like', $datePrefix . '%')
|
||||
->lockForUpdate()
|
||||
->max($column);
|
||||
|
||||
$sequence = 1;
|
||||
if (is_string($maxNo) && $maxNo !== '') {
|
||||
$sequence = ((int) substr($maxNo, strlen($datePrefix))) + 1;
|
||||
}
|
||||
|
||||
return $datePrefix . str_pad((string) $sequence, 4, '0', STR_PAD_LEFT);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user