using System.Globalization;
namespace Admin.NET.Plugin.AiDOP.Supply;
///
/// 采购单号生成:类型前缀 + yyyyMMdd + 固定宽度流水(事务内 FOR UPDATE 取号)。
///
public static class PurOrdNumberGenerator
{
public static async Task NextAsync(ISqlSugarClient db, string typePrefix, DateTime sequenceDate, int serialWidth)
{
var batch = await NextBatchAsync(db, typePrefix, sequenceDate, serialWidth, 1);
return batch[0];
}
public static async Task> NextBatchAsync(
ISqlSugarClient db,
string typePrefix,
DateTime sequenceDate,
int serialWidth,
int count)
{
if (count <= 0) throw Oops.Oh("编号数量必须大于 0。");
if (serialWidth <= 0 || serialWidth > 9) throw Oops.Oh("流水号宽度无效。");
var prefix = typePrefix.Trim() + sequenceDate.ToString("yyyyMMdd", CultureInfo.InvariantCulture);
var maxSeq = await db.Ado.GetIntAsync(
"""
SELECT IFNULL(MAX(CAST(RIGHT(TRIM(PurOrd), @SerialWidth) AS UNSIGNED)), 0)
FROM PurOrdMaster
WHERE TRIM(PurOrd) LIKE CONCAT(@Prefix, '%')
AND CHAR_LENGTH(TRIM(PurOrd)) = CHAR_LENGTH(@Prefix) + @SerialWidth
FOR UPDATE
""",
new SugarParameter("@Prefix", prefix),
new SugarParameter("@SerialWidth", serialWidth));
var maxSerial = (int)Math.Pow(10, serialWidth) - 1;
var result = new List(count);
for (var i = 1; i <= count; i++)
{
var next = maxSeq + i;
if (next > maxSerial)
throw Oops.Oh($"当日{typePrefix.Trim()}单号流水已超过 {maxSerial}(前缀 {prefix})");
result.Add(prefix + next.ToString($"D{serialWidth}", CultureInfo.InvariantCulture));
}
return result;
}
///
/// PurOrdRctMaster.Receiver:类型前缀 + yyyyMMdd + 固定宽度流水(如 PT202605190001)。
///
public static async Task NextRctReceiverAsync(
ISqlSugarClient db,
string typePrefix,
string rctType,
DateTime sequenceDate,
int serialWidth)
{
if (string.IsNullOrWhiteSpace(typePrefix)) throw Oops.Oh("单号前缀无效。");
if (string.IsNullOrWhiteSpace(rctType)) throw Oops.Oh("收货类型无效。");
if (serialWidth <= 0 || serialWidth > 9) throw Oops.Oh("流水号宽度无效。");
var prefix = typePrefix.Trim() + sequenceDate.ToString("yyyyMMdd", CultureInfo.InvariantCulture);
var maxSeq = await db.Ado.GetIntAsync(
"""
SELECT IFNULL(MAX(CAST(RIGHT(TRIM(Receiver), @SerialWidth) AS UNSIGNED)), 0)
FROM PurOrdRctMaster
WHERE RctType = @RctType
AND TRIM(Receiver) LIKE CONCAT(@Prefix, '%')
AND CHAR_LENGTH(TRIM(Receiver)) = CHAR_LENGTH(@Prefix) + @SerialWidth
FOR UPDATE
""",
new SugarParameter("@Prefix", prefix),
new SugarParameter("@RctType", rctType.Trim()),
new SugarParameter("@SerialWidth", serialWidth));
var maxSerial = (int)Math.Pow(10, serialWidth) - 1;
var next = maxSeq + 1;
if (next > maxSerial)
throw Oops.Oh($"当日{typePrefix.Trim()}单号流水已超过 {maxSerial}(前缀 {prefix})");
return prefix + next.ToString($"D{serialWidth}", CultureInfo.InvariantCulture);
}
}