using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using System.Threading.Tasks;
using VOL.Core.Configuration;
using VOL.Core.DBManager;
using VOL.Core.Enums;
namespace VOL.Core.Extensions
{
public static class IdentityCode
{
///
/// 创建自增单据号
///
///
/// 实体对象
/// 要设置单据号的字段
/// 单据号前缀,如:{TC}{2023}{0001}
/// 日期字段,用于按周期筛选数据
/// 单据号周期类型,默认每日
/// 流水号位数,默认4位
/// 生成的单据号
///
/// 单条生成(默认每日4位流水号):
///
/// Sys_Order order = new Sys_Order();
/// // 结果:SO202606080001
/// order.Create(x => x.OrderNo, "SO", x => x.CreateDate);
///
/// 每月重置流水号:
///
/// // 结果:SO2026060001
/// order.Create(x => x.OrderNo, "SO", x => x.CreateDate, IdentityCodeCycleType.Month);
///
/// 每年重置流水号:
///
/// // 结果:SO20260001
/// order.Create(x => x.OrderNo, "SO", x => x.CreateDate, IdentityCodeCycleType.Year);
///
/// 自定义流水号位数:
///
/// // 结果:SO20260608000001
/// order.Create(x => x.OrderNo, "SO", x => x.CreateDate, IdentityCodeCycleType.Day, 6);
///
///
public static string Create(this T entity,
Expression> codeField,
string preCode = "Code",
Expression> dateFieldExpression = null,
IdentityCodeCycleType cycleType = IdentityCodeCycleType.Day,
int serialLength = 4
) where T : class
{
return new[] { entity }.CreateList(codeField, preCode, dateFieldExpression, cycleType, serialLength).FirstOrDefault();
}
///
/// 批量创建自增单据号(只查询一次数据库,依次递增)
///
///
/// 实体集合
/// 要设置单据号的字段
/// 单据号前缀,如:{TC}{2023}{0001}
/// 日期字段,用于按周期筛选数据
/// 单据号周期类型,默认每日
/// 流水号位数,默认4位
/// 生成的单据号列表
///
/// 批量生成(默认每日4位流水号):
///
/// List orders = new List { order1, order2, order3 };
/// // 结果:SO202606080001、SO202606080002、SO202606080003
/// orders.CreateList(x => x.OrderNo, "SO", x => x.CreateDate);
///
/// 每月重置流水号:
///
/// // 结果:SO2026060001、SO2026060002
/// orders.CreateList(x => x.OrderNo, "SO", x => x.CreateDate, IdentityCodeCycleType.Month);
///
/// 每年重置流水号:
///
/// // 结果:SO20260001、SO20260002
/// orders.CreateList(x => x.OrderNo, "SO", x => x.CreateDate, IdentityCodeCycleType.Year);
///
/// 自定义流水号位数:
///
/// // 结果:SO20260608000001、SO20260608000002
/// orders.CreateList(x => x.OrderNo, "SO", x => x.CreateDate, IdentityCodeCycleType.Day, 6);
///
///
public static List CreateList(this IEnumerable entities,
Expression> codeField,
string preCode = "Code",
Expression> dateFieldExpression = null,
IdentityCodeCycleType cycleType = IdentityCodeCycleType.Day,
int serialLength = 4
) where T : class
{
var entityList = entities?.ToList() ?? new List();
if (entityList.Count == 0)
{
return new List();
}
string dateField;
if (dateFieldExpression == null)
{
dateField = AppSetting.CreateMember.DateField;
}
else
{
dateField = dateFieldExpression.GetExpressionPropertyFirst();
}
var codeFieldName = codeField.GetExpressionPropertyFirst();
DateTime cycleStartDate = GetCycleStartDate(cycleType);
var dateCondition = dateField.CreateExpression(cycleStartDate, LinqExpressionType.ThanOrEqual);
var codeCondition = codeFieldName.CreateExpression(preCode, LinqExpressionType.LikeStart);
var condition = dateCondition.And(codeCondition);
string orderNo = DBServerProvider.DbContext.Set().Where(condition)
.OrderByDescending(codeField)
.Select(codeField)
.FirstOrDefault()
?.ToString();
if (serialLength < 1)
{
serialLength = 4;
}
int startNo = string.IsNullOrEmpty(orderNo) ? 1 : orderNo.Substring(orderNo.Length - serialLength).GetInt() + 1;
string prefix = $"{preCode}{GetDatePart(cycleType)}";
string serialFormat = $"D{serialLength}";
var property = typeof(T).GetProperty(codeFieldName);
var rules = new List(entityList.Count);
for (int i = 0; i < entityList.Count; i++)
{
string rule = prefix + (startNo + i).ToString(serialFormat);
property.SetValue(entityList[i], rule);
rules.Add(rule);
}
return rules;
}
private static DateTime GetCycleStartDate(IdentityCodeCycleType cycleType)
{
DateTime now = DateTime.Now;
switch (cycleType)
{
case IdentityCodeCycleType.Year:
return new DateTime(now.Year, 1, 1);
case IdentityCodeCycleType.Month:
return new DateTime(now.Year, now.Month, 1);
default:
return (DateTime)now.ToString("yyyy-MM-dd").GetDateTime();
}
}
private static string GetDatePart(IdentityCodeCycleType cycleType)
{
switch (cycleType)
{
case IdentityCodeCycleType.Year:
return DateTime.Now.ToString("yyyy");
case IdentityCodeCycleType.Month:
return DateTime.Now.ToString("yyyyMM");
default:
return DateTime.Now.ToString("yyyyMMdd");
}
}
}
}