Files
jinko.yikatong/Src/Dlhis.Canteen/Voucher/Services/Implements/BirthdayVoucherService.cs

275 lines
11 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using System.Text;
using Dlhis.Basic.Api;
using Dlhis.Basic.Api.Requests;
using Dlhis.Canteen.Tickets.Services;
using Dlhis.Canteen.Tickets.Services.Implements;
using Dlhis.Canteen.Voucher.Requests;
using Dlhis.Canteen.Voucher.Response;
using Dlhis.Constants;
using Dlhis.Entity.Basic.Entity;
using Dlhis.Entity.Basic.Enums;
using Dlhis.Entity.Canteen.Entities;
using Dlhis.Entity.Canteen.Entities.Voucher;
using Dlhis.Entity.Canteen.Enums;
using Kurisu.AspNetCore.CustomClass;
using Kurisu.AspNetCore.DataAccess.Dto;
using Kurisu.AspNetCore.DataAccess.Entity;
using Kurisu.AspNetCore.DataAccess.SqlSugar.Extensions;
using Kurisu.AspNetCore.Utils.Extensions;
using SqlSugar;
namespace Dlhis.Canteen.Voucher.Services.Implements;
[Service("BirthdayVoucherService")]
public class BirthdayVoucherService : BaseVoucherService, IVoucherService
{
private readonly IFactorySettingApi _factorySettingApi;
private readonly IDingTalkApi _dingTalkApi;
private readonly ILogger<BirthdayVoucherService> _logger;
/// <inheritdoc />
public BirthdayVoucherService(IServiceProvider serviceProvider) : base(serviceProvider)
{
_factorySettingApi = serviceProvider.GetService<IFactorySettingApi>();
_dingTalkApi = serviceProvider.GetService<IDingTalkApi>();
_logger = serviceProvider.GetService<ILogger<BirthdayVoucherService>>();
}
/// <inheritdoc />
public override async Task CreateAsync(Dictionary<string, object> pairs)
{
var p = GetDateRange(pairs);
var remark = pairs != null && pairs.TryGetValue("remark", out var r) ? r?.ToString() : string.Empty;
var userCodes = pairs != null && pairs.TryGetValue("userCodes", out var c) ? c as List<string> : new List<string>();
//忽略tenant操作
await DbContext.IgnoreAsync<ITenantId>(async () =>
{
var gainfos = await GetGainfosAsync(userCodes, p.begin, p.end);
var departmentNos = gainfos.Select(g => g.DepartmentNo).Distinct().ToList();
var departmentInfos = await DbContext.Queryable<DepartmentEntity>()
.Where(x => departmentNos.Contains(x.No))
.ToListAsync();
foreach (var gainfo in gainfos.Where(x => x.Birthday.HasValue))
{
await DbContext.Client.Ado.BeginTranAsync();
try
{
var years = GetBirthdayYears(gainfo.Birthday.Value, p.begin, p.end);
foreach (var year in years)
{
await GenerateVoucherAsync(gainfo, departmentInfos, year, remark);
}
await DbContext.Client.Ado.CommitTranAsync();
}
catch (Exception)
{
await DbContext.Client.Ado.RollbackTranAsync();
}
}
});
}
private async Task GenerateVoucherAsync(GainfoEntity gainfo, List<DepartmentEntity> departments, int year, string remark)
{
//生日券金额固定100元
const decimal amount = 100;
var dayStr = year.ToString();//按年区分,避免生日日期变更重复发放
//由数据类型+工号+生日组成唯一标识
var no = GenerateUniqueCode(VoucherEnumType.Birthday.ToString() + gainfo.Code + dayStr);
if (!await DbContext.Queryable<VoucherEntity>()
.Where(x => x.No == no)
.Where(x => x.Type == VoucherEnumType.Birthday)
.AnyAsync())
{
await DbContext.InsertAsync(new VoucherEntity
{
No = no,
Type = VoucherEnumType.Birthday,
ClaimDateTime = new DateTime(year, gainfo.Birthday.Value.Month, gainfo.Birthday.Value.Day),
OriginalBalance = amount,
Balance = amount,
Description = dayStr + "生日券",
Remark = remark,
CreatedBy = 1,
CreateTime = DateTime.Now,
ModifiedBy = 1,
ModifiedTime = DateTime.Now,
Version = 0
});
var department = departments.FirstOrDefault(x => x.No == gainfo.DepartmentNo);
await DbContext.InsertAsync(new VoucherUserInfoEntity
{
VoucherNo = no,
UserCode = gainfo.Code,
CostId = gainfo.CostId,
Werks = gainfo.Werks,
Factory = gainfo.Factory,
DepartmentNo = gainfo.DepartmentNo,
DepartmentNoFirst = department?.DepartmentNoFirst,
DepartmentNoSecond = department?.DepartmentNoSecond,
CreatedBy = 1,
CreateTime = DateTime.Now,
ModifiedBy = 1,
ModifiedTime = DateTime.Now
});
try
{
await _dingTalkApi.SendMessageUrlAsync(new DingTalkMessageUrlRequest
{
MessageUrl = "dingtalk://dingtalkclient/page/link?url=https%3A%2F%2Fiam.jinkosolar.com%2Fsso%2Foidc1%2FdAuthorize%3Fclient_id%3DAPP104%26response_type%3Dcode%26redirect_uri%3Dhttps%3a%2f%2fface.jinkosolar.com%2fh5%2f%3fto%3dmyBirthdayCoupon",
PicUrl = "@lALOACZwe2Rk",
Title = "生日福利",
Text = gainfo.Name + "生日快乐!特意为你准备了一张生日消费券,点击下方链接去查看,快去超市选购心仪好物吧!",
UserCode = gainfo.Code
});
}
catch (Exception ex)
{
_logger.LogError(ex, "发送生日券消息失败,工号:{UserCode},错误原因:{Error}", gainfo.Code, ex.Message);
}
}
}
private (DateTime begin, DateTime end) GetDateRange(Dictionary<string, object> pairs)
{
var begin = DateTime.Today;
var end = begin;
if (pairs != null)
{
if (pairs.TryGetValue("begin", out var b))
{
if (b is DateTime bb)
{
begin = bb;
}
}
if (pairs.TryGetValue("end", out var e))
{
if (e is DateTime ee)
{
end = ee;
}
}
}
return (begin, end);
}
private async Task<List<GainfoEntity>> GetGainfosAsync(List<string> userCodes, DateTime begin, DateTime end)
{
var factries = await _factorySettingApi.GetEnableBirthdayVoucherFactoriesAsync();
var isToday = begin.Date == end.Date;
var beginMonth = begin.Month;
var endMonth = end.Month;
var overYear = endMonth < beginMonth;
//var limit = end.Date.AddHours(9);//9点入职
return await DbContext.Queryable<GainfoEntity>()
.WhereIF(userCodes.IsPresent(), x => userCodes.Contains(x.Code))
.Where(x => !SqlFunc.IsNullOrEmpty(x.DepartmentNo))
.Where(x => x.Type == GainfoUserTypeEnumType.Normal || x.Type == GainfoUserTypeEnumType.SecurityWhite)
.Where(x => x.Birthday.HasValue && !string.IsNullOrEmpty(x.CostId))
.WhereIF(isToday, x => SqlFunc.DateValue(x.Birthday.Value, DateType.Month) == begin.Month && SqlFunc.DateValue(x.Birthday.Value, DateType.Day) == begin.Day)
.WhereIF(!isToday && !overYear, x => SqlFunc.DateValue(x.Birthday.Value, DateType.Month) >= beginMonth && SqlFunc.DateValue(x.Birthday.Value, DateType.Month) <= endMonth)
.WhereIF(!isToday && overYear, x => SqlFunc.DateValue(x.Birthday.Value, DateType.Month) >= beginMonth || SqlFunc.DateValue(x.Birthday.Value, DateType.Month) <= endMonth)
.Where(x => factries.Contains(x.Factory))
.ToListAsync();
}
private static string GenerateUniqueCode(string data)
{
return QrCodeConstants.Birthday + data.ToArray().Select(x =>
{
var b = Encoding.ASCII.GetBytes(x.ToString());
int i = b[0];
return Convert.ToString(i);
}).Join(string.Empty);
}
/// <summary>
/// 计算给定生日在区间 [begin, end] 内出现的所有年份(可能为0、1或多个)。
/// - 对于每个候选年份构造安全的日期(处理 2/29 在非闰年的情况,退到当年最大天数)。
/// - 若区间内找不到匹配年份,则返回包含 begin.Year 的单元素列表作为兜底行为,保持向后兼容。
/// </summary>
private static List<int> GetBirthdayYears(DateTime birthday, DateTime begin, DateTime end)
{
var years = new List<int>();
// 扩展范围到 begin.Year-1 .. end.Year+1 以覆盖跨年边界的极端情况
var startYear = begin.Year - 1;
var endYear = end.Year + 1;
for (var y = startYear; y <= endYear; y++)
{
var candidate = SafeDate(y, birthday);
if (candidate >= begin && candidate <= end)
{
years.Add(candidate.Year);
}
}
// 去重并排序
years = years.Distinct().OrderBy(x => x).ToList();
return years;
static DateTime SafeDate(int year, DateTime bday)
{
var day = Math.Min(bday.Day, DateTime.DaysInMonth(year, bday.Month));
return new DateTime(year, bday.Month, day);
}
}
public override async Task<Pagination<VoucherBalancePageResponse>> GetVoucherBalancePageAsync(VoucherBalancePageRequest request)
{
return await DbContext.Queryable<BalanceRecordEntity>()
.LeftJoin<BusinessPlaceEntity>((x, bPlace) => x.BusinessPlaceCode == bPlace.Code)
.LeftJoin<DepartmentEntity>((x, bPlace, department) => x.DepartmentNo == department.No)
.WhereIF(request.Factories.IsPresent(), x => request.Factories.Contains(x.TenantId))
.WhereIF(request.UserCode.IsPresent(), x => x.UserCode == request.UserCode)
.WhereIF(request.DepartmentNo.IsPresent(), x => x.DepartmentNo == request.DepartmentNo)
.WhereIF(request.SearchDateTimePeriod.HasValue(), x => x.CostDate >= request.SearchDateTimePeriod.Start && x.CostDate <= request.SearchDateTimePeriod.End) //成本日期
.Where(x => x.Status == BalanceRecordStatusEnumType.Valid && x.Type == BalanceRecordTypeEnumType.Out) //有效,消费数据
.Where(x => x.Source == BalanceRecordSourceEnumType.Birthday)
.Select((x, bPlace, department) => new VoucherBalancePageResponse
{
No = x.No,
UserNo = x.UserNo,
Name = x.Name,
UserCode = x.UserCode,
DepartmentNo = x.DepartmentNo,
DepartmentName = department.Name,
CostDate = x.CostDate,
Remark = x.Remark,
Source = x.Source,
Type = x.Type,
Amount = SqlFunc.Abs(x.Amount),
BusinessPlaceName = bPlace.Name,
ShiftType = x.ShiftType,
DeviceInfo = x.DeviceUniqueNo,
CostId = x.CostId,
OriginTenantId = x.OriginTenantId,
Status = x.Status,
CostDateTime = x.CostDateTime,
Factory = x.TenantId,
Werks = x.Werks
})
.ToPageListAsync(request);
}
}