61 lines
1.8 KiB
PHP
61 lines
1.8 KiB
PHP
<?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'],
|
||
'ZD' => ['bill', 'bill_no'],
|
||
];
|
||
|
||
/**
|
||
* 生成业务单号
|
||
*
|
||
* @param string $prefix 业务前缀:PO 采购单 / SO 订货单 / RC 对账 / ST 对账单 / JS 结算 / ZD 账单
|
||
* @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);
|
||
}
|
||
}
|