PurOrdNumberGenerator.cs 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687
  1. using System.Globalization;
  2. namespace Admin.NET.Plugin.AiDOP.Supply;
  3. /// <summary>
  4. /// 采购单号生成:类型前缀 + yyyyMMdd + 固定宽度流水(事务内 FOR UPDATE 取号)。
  5. /// </summary>
  6. public static class PurOrdNumberGenerator
  7. {
  8. public static async Task<string> NextAsync(ISqlSugarClient db, string typePrefix, DateTime sequenceDate, int serialWidth)
  9. {
  10. var batch = await NextBatchAsync(db, typePrefix, sequenceDate, serialWidth, 1);
  11. return batch[0];
  12. }
  13. public static async Task<IReadOnlyList<string>> NextBatchAsync(
  14. ISqlSugarClient db,
  15. string typePrefix,
  16. DateTime sequenceDate,
  17. int serialWidth,
  18. int count)
  19. {
  20. if (count <= 0) throw Oops.Oh("编号数量必须大于 0。");
  21. if (serialWidth <= 0 || serialWidth > 9) throw Oops.Oh("流水号宽度无效。");
  22. var prefix = typePrefix.Trim() + sequenceDate.ToString("yyyyMMdd", CultureInfo.InvariantCulture);
  23. var maxSeq = await db.Ado.GetIntAsync(
  24. """
  25. SELECT IFNULL(MAX(CAST(RIGHT(TRIM(PurOrd), @SerialWidth) AS UNSIGNED)), 0)
  26. FROM PurOrdMaster
  27. WHERE TRIM(PurOrd) LIKE CONCAT(@Prefix, '%')
  28. AND CHAR_LENGTH(TRIM(PurOrd)) = CHAR_LENGTH(@Prefix) + @SerialWidth
  29. FOR UPDATE
  30. """,
  31. new SugarParameter("@Prefix", prefix),
  32. new SugarParameter("@SerialWidth", serialWidth));
  33. var maxSerial = (int)Math.Pow(10, serialWidth) - 1;
  34. var result = new List<string>(count);
  35. for (var i = 1; i <= count; i++)
  36. {
  37. var next = maxSeq + i;
  38. if (next > maxSerial)
  39. throw Oops.Oh($"当日{typePrefix.Trim()}单号流水已超过 {maxSerial}(前缀 {prefix})");
  40. result.Add(prefix + next.ToString($"D{serialWidth}", CultureInfo.InvariantCulture));
  41. }
  42. return result;
  43. }
  44. /// <summary>
  45. /// PurOrdRctMaster.Receiver:类型前缀 + yyyyMMdd + 固定宽度流水(如 PT202605190001)。
  46. /// </summary>
  47. public static async Task<string> NextRctReceiverAsync(
  48. ISqlSugarClient db,
  49. string typePrefix,
  50. string rctType,
  51. DateTime sequenceDate,
  52. int serialWidth)
  53. {
  54. if (string.IsNullOrWhiteSpace(typePrefix)) throw Oops.Oh("单号前缀无效。");
  55. if (string.IsNullOrWhiteSpace(rctType)) throw Oops.Oh("收货类型无效。");
  56. if (serialWidth <= 0 || serialWidth > 9) throw Oops.Oh("流水号宽度无效。");
  57. var prefix = typePrefix.Trim() + sequenceDate.ToString("yyyyMMdd", CultureInfo.InvariantCulture);
  58. var maxSeq = await db.Ado.GetIntAsync(
  59. """
  60. SELECT IFNULL(MAX(CAST(RIGHT(TRIM(Receiver), @SerialWidth) AS UNSIGNED)), 0)
  61. FROM PurOrdRctMaster
  62. WHERE RctType = @RctType
  63. AND TRIM(Receiver) LIKE CONCAT(@Prefix, '%')
  64. AND CHAR_LENGTH(TRIM(Receiver)) = CHAR_LENGTH(@Prefix) + @SerialWidth
  65. FOR UPDATE
  66. """,
  67. new SugarParameter("@Prefix", prefix),
  68. new SugarParameter("@RctType", rctType.Trim()),
  69. new SugarParameter("@SerialWidth", serialWidth));
  70. var maxSerial = (int)Math.Pow(10, serialWidth) - 1;
  71. var next = maxSeq + 1;
  72. if (next > maxSerial)
  73. throw Oops.Oh($"当日{typePrefix.Trim()}单号流水已超过 {maxSerial}(前缀 {prefix})");
  74. return prefix + next.ToString($"D{serialWidth}", CultureInfo.InvariantCulture);
  75. }
  76. }