feat 生日券功能,自动上传消费数据,提醒访客到期
This commit is contained in:
@@ -4,13 +4,13 @@ namespace Dlhis.Canteen.Api;
|
|||||||
|
|
||||||
[RequestResultHandler]
|
[RequestResultHandler]
|
||||||
[EnableRemoteClient(Name = "canteen-service", BaseUrl = "${InternalRequest:CanteenRequestUrl}")]
|
[EnableRemoteClient(Name = "canteen-service", BaseUrl = "${InternalRequest:CanteenRequestUrl}")]
|
||||||
public interface ITicketApi
|
public interface IVoucherApi
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 创建券
|
/// 创建券
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="type"></param>
|
/// <param name="type"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>s
|
||||||
[Post("/api/tickets/{type}/create")]
|
[Post("/api/vouchers/birthday/create")]
|
||||||
Task CreateAsync(string type);
|
Task CreateAsync(VoucherByBirthdayRequest request);
|
||||||
}
|
}
|
||||||
8
Src/Dlhis.Canteen.Api/VoucherByBirthdayRequest.cs
Normal file
8
Src/Dlhis.Canteen.Api/VoucherByBirthdayRequest.cs
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
namespace Dlhis.Canteen.Api;
|
||||||
|
|
||||||
|
public class VoucherByBirthdayRequest
|
||||||
|
{
|
||||||
|
public DateTime Begin { get; set; }
|
||||||
|
public DateTime End { get; set; }
|
||||||
|
public string Remark { get; set; }
|
||||||
|
}
|
||||||
@@ -1,8 +1,10 @@
|
|||||||
|
using Dlhis.Basic.Api;
|
||||||
using Dlhis.Canteen.Order.Repository;
|
using Dlhis.Canteen.Order.Repository;
|
||||||
using Dlhis.Canteen.Order.Request;
|
using Dlhis.Canteen.Order.Request;
|
||||||
using Dlhis.Canteen.Order.Response;
|
using Dlhis.Canteen.Order.Response;
|
||||||
using Dlhis.Entity.Basic.Entity;
|
using Dlhis.Entity.Basic.Entity;
|
||||||
using Dlhis.Entity.Canteen.Entities;
|
using Dlhis.Entity.Canteen.Entities;
|
||||||
|
using Dlhis.Entity.Canteen.Entities.Voucher;
|
||||||
using Dlhis.Entity.Canteen.Enums;
|
using Dlhis.Entity.Canteen.Enums;
|
||||||
using Kurisu.AspNetCore.DataAccess.SqlSugar.Extensions;
|
using Kurisu.AspNetCore.DataAccess.SqlSugar.Extensions;
|
||||||
using Kurisu.AspNetCore.DataAccess.SqlSugar.Services;
|
using Kurisu.AspNetCore.DataAccess.SqlSugar.Services;
|
||||||
@@ -22,64 +24,78 @@ public class BirthdayConsumeHandler : IConsumeHandler
|
|||||||
private readonly IDbContext _dbContext;
|
private readonly IDbContext _dbContext;
|
||||||
private readonly IOrderCommonHandler _orderCommonHandler;
|
private readonly IOrderCommonHandler _orderCommonHandler;
|
||||||
private readonly IOrderRepository _orderRepository;
|
private readonly IOrderRepository _orderRepository;
|
||||||
|
private readonly IFactorySettingApi _factorySettingApi;
|
||||||
|
|
||||||
public BirthdayConsumeHandler(IDbContext dbContext,
|
public BirthdayConsumeHandler(IDbContext dbContext,
|
||||||
IOrderCommonHandler orderCommonHandler,
|
IOrderCommonHandler orderCommonHandler,
|
||||||
IOrderRepository orderRepository)
|
IOrderRepository orderRepository,
|
||||||
|
IFactorySettingApi factorySettingApi)
|
||||||
{
|
{
|
||||||
_dbContext = dbContext;
|
_dbContext = dbContext;
|
||||||
_orderCommonHandler = orderCommonHandler;
|
_orderCommonHandler = orderCommonHandler;
|
||||||
_orderRepository = orderRepository;
|
_orderRepository = orderRepository;
|
||||||
|
_factorySettingApi = factorySettingApi;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<DefaultApiResult<OrderResultResponse>> ConsumeAsync(OrderAddRequest request, GainfoEntity gainfo)
|
public async Task<DefaultApiResult<OrderResultResponse>> ConsumeAsync(OrderAddRequest request, GainfoEntity gainfo)
|
||||||
{
|
{
|
||||||
var msg = string.Empty;
|
var msg = string.Empty;
|
||||||
var ticketNo = request.UserUniqueNo;
|
var qrCode = request.UserUniqueNo;
|
||||||
|
|
||||||
var exists = await _dbContext.Queryable<TicketEntity>()
|
var voucherQrCode = await _dbContext.Queryable<VoucherQrCodeEntity>()
|
||||||
.Where(x => x.Type == TicketEnumType.Birthday)
|
.LeftJoin<VoucherUserInfoEntity>((x, u) => x.VoucherNo == u.VoucherNo)
|
||||||
.Where(x => x.QrCode == ticketNo)
|
.Where(x => x.QrCode == qrCode)
|
||||||
.AnyAsync();
|
.Select((x, u) => new
|
||||||
|
{
|
||||||
exists.ThrowIfFalse("生日券无效");
|
x.VoucherNo,
|
||||||
|
u.UserCode,
|
||||||
|
u.Factory
|
||||||
|
})
|
||||||
|
.SingleAsync();
|
||||||
|
voucherQrCode.ThrowIfNull("生日券无效");
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var checkData = await _orderCommonHandler.PreCheckAsync(request.DeviceUniqueNo, request.CostDateTime!.Value);
|
var checkData = await _orderCommonHandler.PreCheckAsync(request.DeviceUniqueNo, request.CostDateTime!.Value);
|
||||||
var isSupermarket = await _dbContext.Queryable<BusinessPlaceEntity>()
|
var businessPlace = await _dbContext.Queryable<BusinessPlaceEntity>()
|
||||||
.Where(x => x.Code == checkData.BusinessPlaceCode)
|
.Where(x => x.Code == checkData.BusinessPlaceCode)
|
||||||
.Select(x => x.Catalog == CanteenBusinessPlaceCatalogEnumType.Supermarket)
|
//.Select(x => x.Catalog == CanteenBusinessPlaceCatalogEnumType.Supermarket)
|
||||||
.SingleAsync();
|
.SingleAsync();
|
||||||
|
|
||||||
|
businessPlace.ThrowIfNull("营业点不存在");
|
||||||
|
var isSupermarket = businessPlace.Catalog == CanteenBusinessPlaceCatalogEnumType.Supermarket;
|
||||||
isSupermarket.ThrowIfFalse("请在超市消费");
|
isSupermarket.ThrowIfFalse("请在超市消费");
|
||||||
|
|
||||||
|
var allowFactories = await _factorySettingApi.GetEnableUseBirthdayVoucherFactoriesAsync(voucherQrCode.Factory);
|
||||||
|
allowFactories.Contains(businessPlace.TenantId).ThrowIfFalse($"该厂区({businessPlace.TenantId})不可使用此生日券");
|
||||||
|
|
||||||
var order = await _orderRepository.CreateDeviceConsumeOrderAsync(checkData, request.Adapt<ConsumeRequest>(), gainfo);
|
var order = await _orderRepository.CreateDeviceConsumeOrderAsync(checkData, request.Adapt<ConsumeRequest>(), gainfo);
|
||||||
|
|
||||||
await _orderCommonHandler.TryConsumeAsync(order.Id, async () =>
|
await _orderCommonHandler.TryConsumeAsync(order.Id, async () =>
|
||||||
{
|
{
|
||||||
await CommonHelper.RetryAsync(async () =>
|
await CommonHelper.RetryAsync(async () =>
|
||||||
{
|
{
|
||||||
var ticket = await _dbContext.Queryable<TicketEntity>()
|
var voucher = await _dbContext.Queryable<VoucherEntity>()
|
||||||
.Where(x => x.Type == TicketEnumType.Birthday)
|
.Where(x => x.Type == VoucherEnumType.Birthday)
|
||||||
.Where(x => x.QrCode == ticketNo)
|
.Where(x => x.No == voucherQrCode.VoucherNo)
|
||||||
.SingleAsync();
|
.SingleAsync();
|
||||||
|
|
||||||
//金额+-
|
//金额+-
|
||||||
ticket.Balance += order.Amount;
|
voucher.Balance += order.Amount;
|
||||||
(ticket.Balance < 0).ThrowIfTrue("余额不足,无法消费");
|
(voucher.Balance < 0).ThrowIfTrue("余额不足,无法消费");
|
||||||
|
|
||||||
await _dbContext.Updateable<TicketEntity>()
|
await _dbContext.Updateable<VoucherEntity>()
|
||||||
.SetColumns(x => x.Balance == ticket.Balance)
|
.SetColumns(x => x.Balance == voucher.Balance)
|
||||||
.SetColumns(x => x.Version == x.Version + 1)
|
.SetColumns(x => x.Version == x.Version + 1)
|
||||||
.SetColumns(x => x.ModifiedTime == DateTime.Now)
|
.SetColumns(x => x.ModifiedTime == DateTime.Now)
|
||||||
.Where(x => x.QrCode == ticketNo && x.Version == ticket.Version) //必须与查询时的version一致
|
.Where(x => x.No == voucher.No && x.Version == voucher.Version) //必须与查询时的version一致
|
||||||
.ExecuteCommandThrowVersionAsync();
|
.ExecuteCommandThrowVersionAsync();
|
||||||
|
|
||||||
//写入记录
|
//写入记录
|
||||||
var balanceRecord = order.Adapt<BalanceRecordEntity>();
|
var balanceRecord = order.Adapt<BalanceRecordEntity>();
|
||||||
balanceRecord.Remark = $"{ticket.QrCode}(生日券消费)";
|
balanceRecord.Remark = $"{voucher.No}(生日券消费)";
|
||||||
await _dbContext.InsertAsync(balanceRecord);
|
await _dbContext.InsertAsync(balanceRecord);
|
||||||
|
|
||||||
}, 5);
|
}, 5);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -89,12 +105,13 @@ public class BirthdayConsumeHandler : IConsumeHandler
|
|||||||
}
|
}
|
||||||
|
|
||||||
//获取餐券余额
|
//获取餐券余额
|
||||||
var data = await _dbContext.Queryable<TicketEntity>()
|
var data = await _dbContext.Queryable<VoucherEntity>()
|
||||||
.LeftJoin<GainfoEntity>((x, ga) => x.UserCode == ga.Code)
|
.LeftJoin<VoucherUserInfoEntity>((x, u) => x.No == u.VoucherNo)
|
||||||
.Where(x => x.Type == TicketEnumType.Birthday && x.QrCode == ticketNo)
|
.LeftJoin<GainfoEntity>((x, u, ga) => u.UserCode == ga.Code)
|
||||||
.Select((x, ga) => new OrderResultResponse
|
.Where(x => x.Type == VoucherEnumType.Birthday && x.No == voucherQrCode.VoucherNo)
|
||||||
|
.Select((x, u, ga) => new OrderResultResponse
|
||||||
{
|
{
|
||||||
UserCode = x.UserCode,
|
UserCode = u.UserCode,
|
||||||
UserName = ga.Name,
|
UserName = ga.Name,
|
||||||
CurrentBalance = x.Balance
|
CurrentBalance = x.Balance
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ using Dlhis.Canteen.Order.Request;
|
|||||||
using Dlhis.Canteen.Order.Response;
|
using Dlhis.Canteen.Order.Response;
|
||||||
using Dlhis.Entity.Basic.Entity;
|
using Dlhis.Entity.Basic.Entity;
|
||||||
using Dlhis.Entity.Canteen.Entities;
|
using Dlhis.Entity.Canteen.Entities;
|
||||||
|
using Dlhis.Entity.Canteen.Entities.EMealVoucher;
|
||||||
using Dlhis.Entity.Canteen.Enums;
|
using Dlhis.Entity.Canteen.Enums;
|
||||||
using Kurisu.AspNetCore.DataAccess.SqlSugar.Extensions;
|
using Kurisu.AspNetCore.DataAccess.SqlSugar.Extensions;
|
||||||
using Kurisu.AspNetCore.DataAccess.SqlSugar.Services;
|
using Kurisu.AspNetCore.DataAccess.SqlSugar.Services;
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ using Dlhis.Entity.Device.Enums;
|
|||||||
using Kurisu.AspNetCore.CustomClass;
|
using Kurisu.AspNetCore.CustomClass;
|
||||||
using Kurisu.AspNetCore.DataAccess.SqlSugar.Services;
|
using Kurisu.AspNetCore.DataAccess.SqlSugar.Services;
|
||||||
using Kurisu.AspNetCore.Utils.Extensions;
|
using Kurisu.AspNetCore.Utils.Extensions;
|
||||||
|
using Microsoft.Extensions.Primitives;
|
||||||
|
|
||||||
namespace Dlhis.Canteen.Order.Services.ConsumeHandlers;
|
namespace Dlhis.Canteen.Order.Services.ConsumeHandlers;
|
||||||
|
|
||||||
@@ -40,7 +41,8 @@ public class OrderCommonHandler : IOrderCommonHandler
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (_httpContextAccessor.HttpContext!.Request.Headers.TryGetValue("X-Requested-DeviceIp", out var ip))
|
StringValues ip = "";
|
||||||
|
if (_httpContextAccessor.HttpContext?.Request.Headers.TryGetValue("X-Requested-DeviceIp", out ip) == true)
|
||||||
{
|
{
|
||||||
var device = await _dbContext.Queryable<DeviceEntity>().Where(x => x.UniqueNo == deviceNo).SingleAsync();
|
var device = await _dbContext.Queryable<DeviceEntity>().Where(x => x.UniqueNo == deviceNo).SingleAsync();
|
||||||
device.ConnectionInfo = new
|
device.ConnectionInfo = new
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ using Dlhis.Canteen.Setting.Services;
|
|||||||
using Dlhis.Constants;
|
using Dlhis.Constants;
|
||||||
using Dlhis.Entity.Basic.Entity;
|
using Dlhis.Entity.Basic.Entity;
|
||||||
using Dlhis.Entity.Canteen.Entities;
|
using Dlhis.Entity.Canteen.Entities;
|
||||||
|
using Dlhis.Entity.Canteen.Entities.EMealVoucher;
|
||||||
using Dlhis.Entity.Canteen.Enums;
|
using Dlhis.Entity.Canteen.Enums;
|
||||||
using Dlhis.Entity.Device;
|
using Dlhis.Entity.Device;
|
||||||
using Dlhis.Entity.Device.Entities;
|
using Dlhis.Entity.Device.Entities;
|
||||||
|
|||||||
@@ -6,6 +6,8 @@ using Dlhis.Canteen.Setting.Services;
|
|||||||
using Dlhis.Constants;
|
using Dlhis.Constants;
|
||||||
using Dlhis.Entity.Basic.Entity;
|
using Dlhis.Entity.Basic.Entity;
|
||||||
using Dlhis.Entity.Canteen.Entities;
|
using Dlhis.Entity.Canteen.Entities;
|
||||||
|
using Dlhis.Entity.Canteen.Entities.EMealVoucher;
|
||||||
|
using Dlhis.Entity.Canteen.Entities.Voucher;
|
||||||
using Dlhis.Entity.Canteen.Enums;
|
using Dlhis.Entity.Canteen.Enums;
|
||||||
using Dlhis.Entity.Device;
|
using Dlhis.Entity.Device;
|
||||||
using Dlhis.Entity.Device.Entities;
|
using Dlhis.Entity.Device.Entities;
|
||||||
@@ -160,27 +162,35 @@ public class OrderService : IOrderService
|
|||||||
switch (flag)
|
switch (flag)
|
||||||
{
|
{
|
||||||
case QrCodeConstants.User:
|
case QrCodeConstants.User:
|
||||||
{
|
{
|
||||||
gainfo = await GetUserByQrCodeAsync(request.UserUniqueNo);
|
gainfo = await GetUserByQrCodeAsync(request.UserUniqueNo);
|
||||||
await CheckPermissionAsync(gainfo.Code, request.DeviceUniqueNo);
|
await CheckPermissionAsync(gainfo.Code, request.DeviceUniqueNo);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case QrCodeConstants.EMealVoucher:
|
case QrCodeConstants.EMealVoucher:
|
||||||
{
|
{
|
||||||
request.Source = BalanceRecordSourceEnumType.EMealVoucher;
|
request.Source = BalanceRecordSourceEnumType.EMealVoucher;
|
||||||
var eMealVoucherQrCode = await _dbContext.Queryable<EMealVoucherDetailQrCodeEntity>().Where(x => x.QrCode == request.UserUniqueNo).SingleAsync();
|
var eMealVoucherQrCode = await _dbContext.Queryable<EMealVoucherDetailQrCodeEntity>().Where(x => x.QrCode == request.UserUniqueNo).SingleAsync();
|
||||||
eMealVoucherQrCode.ThrowIfNull("无法识别");
|
eMealVoucherQrCode.ThrowIfNull("无法识别");
|
||||||
var code = eMealVoucherQrCode.OriginData.Split(':')[2];
|
var code = eMealVoucherQrCode.OriginData.Split(':')[2];
|
||||||
gainfo = await _dbContext.Queryable<GainfoEntity>().Where(x => x.Code == code).SingleAsync();
|
gainfo = await _dbContext.Queryable<GainfoEntity>().Where(x => x.Code == code).SingleAsync();
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case QrCodeConstants.Birthday:
|
case QrCodeConstants.Birthday:
|
||||||
{
|
{
|
||||||
request.Source = BalanceRecordSourceEnumType.Birthday;
|
request.Source = BalanceRecordSourceEnumType.Birthday;
|
||||||
var ticket = await _dbContext.Queryable<TicketEntity>().Where(x => x.Type == TicketEnumType.Birthday).Where(x => x.QrCode == request.UserUniqueNo).SingleAsync();
|
var qrcode = await _dbContext.Queryable<VoucherQrCodeEntity>()
|
||||||
ticket.ThrowIfNull("无法识别");
|
.Where(x => x.QrCode == request.UserUniqueNo)
|
||||||
gainfo = await _dbContext.Queryable<GainfoEntity>().Where(x => x.Code == ticket.UserCode).SingleAsync();
|
.SingleAsync();
|
||||||
}
|
|
||||||
|
qrcode.ThrowIfNull("券码无法识别");
|
||||||
|
|
||||||
|
var vourcher = await _dbContext.Queryable<VoucherUserInfoEntity>()
|
||||||
|
.Where(x => x.VoucherNo == qrcode.VoucherNo)
|
||||||
|
.SingleAsync();
|
||||||
|
|
||||||
|
gainfo = await _dbContext.Queryable<GainfoEntity>().Where(x => x.Code == vourcher.UserCode).SingleAsync();
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default: throw new UserFriendlyException($"无法识别{request.UserUniqueNo}");
|
default: throw new UserFriendlyException($"无法识别{request.UserUniqueNo}");
|
||||||
@@ -201,7 +211,7 @@ public class OrderService : IOrderService
|
|||||||
//在线
|
//在线
|
||||||
if (!request.IsOffline)
|
if (!request.IsOffline)
|
||||||
{
|
{
|
||||||
gainfo.ThrowIfNull("无法识别");
|
gainfo.ThrowIfNull("无法识别人员信息");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -213,6 +223,7 @@ public class OrderService : IOrderService
|
|||||||
.FirstAsync();
|
.FirstAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
gainfo.ThrowIfNull("无法识别人员信息");
|
||||||
return gainfo;
|
return gainfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -292,7 +303,9 @@ public class OrderService : IOrderService
|
|||||||
.Where(x => x.DeviceUniqueNo == request.DeviceUniqueNo && x.BusinessPlaceCode.HasValue)
|
.Where(x => x.DeviceUniqueNo == request.DeviceUniqueNo && x.BusinessPlaceCode.HasValue)
|
||||||
.Select((x, b, bs) => new
|
.Select((x, b, bs) => new
|
||||||
{
|
{
|
||||||
b.Code, bs.ShiftCode, Factory = b.TenantId
|
b.Code,
|
||||||
|
bs.ShiftCode,
|
||||||
|
Factory = b.TenantId
|
||||||
})
|
})
|
||||||
.SingleAsync();
|
.SingleAsync();
|
||||||
|
|
||||||
|
|||||||
@@ -1,50 +0,0 @@
|
|||||||
using Dlhis.Canteen.Tickets.Request;
|
|
||||||
using Dlhis.Canteen.Tickets.Response;
|
|
||||||
using Dlhis.Canteen.Tickets.Services;
|
|
||||||
using Kurisu.AspNetCore.DataAccess.Dto;
|
|
||||||
using Kurisu.AspNetCore.Utils.Extensions;
|
|
||||||
using Microsoft.AspNetCore.Authorization;
|
|
||||||
using Microsoft.AspNetCore.Mvc;
|
|
||||||
|
|
||||||
namespace Dlhis.Canteen.Tickets.Controllers;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 券
|
|
||||||
/// </summary>
|
|
||||||
[Authorize]
|
|
||||||
[Route("api/[controller]")]
|
|
||||||
[ApiController]
|
|
||||||
public class TicketsController : ControllerBase
|
|
||||||
{
|
|
||||||
private readonly INamedResolver _namedResolver;
|
|
||||||
|
|
||||||
public TicketsController(INamedResolver namedResolver)
|
|
||||||
{
|
|
||||||
_namedResolver = namedResolver;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 获取分页数据(按券类型)
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="request"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
[HttpGet("page")]
|
|
||||||
public async Task<Pagination<TicketPageResponse>> GetPageAsync(TicketPageRequest request)
|
|
||||||
{
|
|
||||||
return await _namedResolver.GetService<ITicketService>(request.Type.ToString()).GetPageAsync(request);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 创建券
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="type">券类型,需要后端支持</param>
|
|
||||||
[AllowAnonymous]
|
|
||||||
[HttpPost("{type:required}/create")]
|
|
||||||
public async Task CreateAsync(string type)
|
|
||||||
{
|
|
||||||
var srv = _namedResolver.GetService<ITicketService>(type);
|
|
||||||
srv.ThrowIfNull("不支持的券类型");
|
|
||||||
|
|
||||||
await srv.CreateAsync();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,19 +0,0 @@
|
|||||||
using System.ComponentModel.DataAnnotations;
|
|
||||||
using Dlhis.Entity.Canteen.Enums;
|
|
||||||
using Kurisu.AspNetCore.DataAccess.Dto;
|
|
||||||
|
|
||||||
namespace Dlhis.Canteen.Tickets.Request;
|
|
||||||
|
|
||||||
public class TicketPageRequest : PageDto
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// 类型
|
|
||||||
/// </summary>
|
|
||||||
[EnumDataType(typeof(TicketEnumType))]
|
|
||||||
public TicketEnumType Type { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 工号
|
|
||||||
/// </summary>
|
|
||||||
public string UserCode { get; set; }
|
|
||||||
}
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
namespace Dlhis.Canteen.Tickets.Services;
|
|
||||||
|
|
||||||
public interface IBirthdayTicketService : ITicketService
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,24 +0,0 @@
|
|||||||
using Dlhis.Canteen.Tickets.Request;
|
|
||||||
using Dlhis.Canteen.Tickets.Response;
|
|
||||||
using Kurisu.AspNetCore.DataAccess.Dto;
|
|
||||||
|
|
||||||
namespace Dlhis.Canteen.Tickets.Services;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 券
|
|
||||||
/// </summary>
|
|
||||||
public interface ITicketService : IScopeDependency
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// 分页数据
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="request"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
Task<Pagination<TicketPageResponse>> GetPageAsync(TicketPageRequest request);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 创建
|
|
||||||
/// </summary>
|
|
||||||
/// <returns></returns>
|
|
||||||
Task CreateAsync();
|
|
||||||
}
|
|
||||||
@@ -1,65 +0,0 @@
|
|||||||
using System.Text;
|
|
||||||
using Dlhis.Constants;
|
|
||||||
using Dlhis.Entity.Basic.Entity;
|
|
||||||
using Dlhis.Entity.Canteen.Entities;
|
|
||||||
using Dlhis.Entity.Canteen.Enums;
|
|
||||||
using Kurisu.AspNetCore.DataAccess.Entity;
|
|
||||||
using Kurisu.AspNetCore.DataAccess.SqlSugar.Services;
|
|
||||||
using Kurisu.AspNetCore.Utils.Extensions;
|
|
||||||
using SqlSugar;
|
|
||||||
|
|
||||||
namespace Dlhis.Canteen.Tickets.Services.Implements;
|
|
||||||
|
|
||||||
[Service(nameof(TicketEnumType.Birthday))]
|
|
||||||
public class BirthdayTicketService : BaseTicketService, IBirthdayTicketService
|
|
||||||
{
|
|
||||||
/// <inheritdoc />
|
|
||||||
public BirthdayTicketService(IDbContext dbContext) : base(dbContext)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
public override async Task CreateAsync()
|
|
||||||
{
|
|
||||||
await DbContext.IgnoreAsync<ITenantId>(async () =>
|
|
||||||
{
|
|
||||||
var today = DateTime.Today;
|
|
||||||
var userCodes = await DbContext.Queryable<GainfoEntity>()
|
|
||||||
.Where(x => SqlFunc.DateIsSame(SqlFunc.ToDate(x.Birthday), today, DateType.Day))
|
|
||||||
.Select(x => new { x.Code, x.Factory })
|
|
||||||
.ToListAsync();
|
|
||||||
|
|
||||||
const decimal amount = 30;
|
|
||||||
var todayStr = today.ToString("yyyy-MM-dd");
|
|
||||||
foreach (var item in userCodes)
|
|
||||||
{
|
|
||||||
var qrCode = GetQrCode(item.Code + todayStr);
|
|
||||||
if (!await DbContext.Queryable<TicketEntity>().Where(x => x.Type == TicketEnumType.Birthday && x.UserCode == item.Code && x.QrCode == qrCode).AnyAsync())
|
|
||||||
{
|
|
||||||
await DbContext.InsertAsync(new TicketEntity
|
|
||||||
{
|
|
||||||
Type = TicketEnumType.Birthday,
|
|
||||||
UserCode = item.Code,
|
|
||||||
OriginalBalance = amount,
|
|
||||||
Balance = amount,
|
|
||||||
QrCode = qrCode,
|
|
||||||
Remark = todayStr + "生日券",
|
|
||||||
TenantId = item.Factory
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private static string GetQrCode(string data)
|
|
||||||
{
|
|
||||||
var qrCode = QrCodeConstants.Birthday + data.ToArray().Select(x =>
|
|
||||||
{
|
|
||||||
var b = Encoding.ASCII.GetBytes(x.ToString());
|
|
||||||
int i = b[0];
|
|
||||||
return Convert.ToString(i);
|
|
||||||
}).Join(string.Empty);
|
|
||||||
|
|
||||||
return qrCode;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,32 +0,0 @@
|
|||||||
using Dlhis.Canteen.Tickets.Request;
|
|
||||||
using Dlhis.Canteen.Tickets.Response;
|
|
||||||
using Dlhis.Entity.Basic.Entity;
|
|
||||||
using Dlhis.Entity.Canteen.Entities;
|
|
||||||
using Kurisu.AspNetCore.DataAccess.Dto;
|
|
||||||
using Kurisu.AspNetCore.DataAccess.SqlSugar.Extensions;
|
|
||||||
using Kurisu.AspNetCore.DataAccess.SqlSugar.Services;
|
|
||||||
using Kurisu.AspNetCore.Utils.Extensions;
|
|
||||||
|
|
||||||
namespace Dlhis.Canteen.Tickets.Services.Implements;
|
|
||||||
|
|
||||||
public abstract class BaseTicketService : ITicketService
|
|
||||||
{
|
|
||||||
protected IDbContext DbContext { get; set; }
|
|
||||||
|
|
||||||
protected BaseTicketService(IDbContext dbContext)
|
|
||||||
{
|
|
||||||
DbContext = dbContext;
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<Pagination<TicketPageResponse>> GetPageAsync(TicketPageRequest request)
|
|
||||||
{
|
|
||||||
return await DbContext.Queryable<TicketEntity>()
|
|
||||||
.LeftJoin<GainfoEntity>((x, ga) => x.UserCode == ga.Code)
|
|
||||||
.Where(x => x.Type == request.Type)
|
|
||||||
.WhereIF(request.UserCode.IsPresent(), x => x.UserCode == request.UserCode)
|
|
||||||
.Select((x, ga) => new TicketPageResponse { UserName = ga.Name }, true)
|
|
||||||
.ToPageListAsync(request);
|
|
||||||
}
|
|
||||||
|
|
||||||
public abstract Task CreateAsync();
|
|
||||||
}
|
|
||||||
@@ -1,14 +1,14 @@
|
|||||||
using Dlhis.Canteen.EMealVoucher.Request;
|
|
||||||
using Dlhis.Canteen.EMealVoucher.Response;
|
|
||||||
using Dlhis.Canteen.EMealVoucher.Services;
|
|
||||||
using Dlhis.Canteen.Order.Request;
|
using Dlhis.Canteen.Order.Request;
|
||||||
using Dlhis.Canteen.Order.Response;
|
using Dlhis.Canteen.Order.Response;
|
||||||
|
using Dlhis.Canteen.Voucher.Requests;
|
||||||
|
using Dlhis.Canteen.Voucher.Response;
|
||||||
|
using Dlhis.Canteen.Voucher.Services;
|
||||||
using Kurisu.AspNetCore.DataAccess.Dto;
|
using Kurisu.AspNetCore.DataAccess.Dto;
|
||||||
using Kurisu.AspNetCore.DataAccess.SqlSugar.Aop;
|
using Kurisu.AspNetCore.DataAccess.SqlSugar.Aop;
|
||||||
using Microsoft.AspNetCore.Authorization;
|
using Microsoft.AspNetCore.Authorization;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
|
||||||
namespace Dlhis.Canteen.EMealVoucher.Controllers;
|
namespace Dlhis.Canteen.Voucher.Controllers;
|
||||||
|
|
||||||
[Authorize]
|
[Authorize]
|
||||||
[Route("api/[controller]")]
|
[Route("api/[controller]")]
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
using Dlhis.Canteen.Voucher.Services;
|
||||||
|
using Microsoft.AspNetCore.Authorization;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
|
||||||
|
namespace Dlhis.Canteen.Voucher.Controllers;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 券二维码服务
|
||||||
|
/// </summary>
|
||||||
|
[Authorize]
|
||||||
|
[ApiController]
|
||||||
|
[Route("api/[controller]")]
|
||||||
|
public class VoucherQrCodesController : ControllerBase
|
||||||
|
{
|
||||||
|
private readonly IVoucherQrCodeService _voucherQrCodeService;
|
||||||
|
|
||||||
|
public VoucherQrCodesController(IVoucherQrCodeService voucherQrCodeService)
|
||||||
|
{
|
||||||
|
_voucherQrCodeService = voucherQrCodeService;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 获取二维码
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="voucherNo">券码</param>
|
||||||
|
/// <param name="isNeedRefresh">true:请求刷新</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
[HttpGet]
|
||||||
|
public async Task<string> GetQrCodeAsync(string voucherNo, bool isNeedRefresh = false)
|
||||||
|
{
|
||||||
|
return await _voucherQrCodeService.GetQrCodeAsync(voucherNo, isNeedRefresh);
|
||||||
|
}
|
||||||
|
}
|
||||||
107
Src/Dlhis.Canteen/Voucher/Controllers/VouchersController.cs
Normal file
107
Src/Dlhis.Canteen/Voucher/Controllers/VouchersController.cs
Normal file
@@ -0,0 +1,107 @@
|
|||||||
|
using Dlhis.Basic.Vouchers.Request;
|
||||||
|
using Dlhis.Canteen.Order.Request;
|
||||||
|
using Dlhis.Canteen.Order.Response;
|
||||||
|
using Dlhis.Canteen.Tickets.Request;
|
||||||
|
using Dlhis.Canteen.Tickets.Services;
|
||||||
|
using Dlhis.Canteen.Voucher.Requests;
|
||||||
|
using Dlhis.Canteen.Voucher.Response;
|
||||||
|
using Dlhis.Constants;
|
||||||
|
using Dlhis.Entity.Canteen.Enums;
|
||||||
|
using Kurisu.AspNetCore.Authentication.Abstractions;
|
||||||
|
using Kurisu.AspNetCore.DataAccess.Dto;
|
||||||
|
using Kurisu.AspNetCore.DataAccess.SqlSugar.Aop;
|
||||||
|
using Kurisu.AspNetCore.Utils.Extensions;
|
||||||
|
using Microsoft.AspNetCore.Authorization;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
|
||||||
|
namespace Dlhis.Canteen.Voucher.Controllers;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 券
|
||||||
|
/// </summary>
|
||||||
|
[Authorize]
|
||||||
|
[Route("api/[controller]")]
|
||||||
|
[ApiController]
|
||||||
|
public class VouchersController : ControllerBase
|
||||||
|
{
|
||||||
|
private readonly INamedResolver _namedResolver;
|
||||||
|
private readonly ICurrentUser _currentUser;
|
||||||
|
|
||||||
|
public VouchersController(INamedResolver namedResolver, ICurrentUser currentUser)
|
||||||
|
{
|
||||||
|
_namedResolver = namedResolver;
|
||||||
|
_currentUser = currentUser;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 获取分页数据(按券类型)
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="request"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
[HttpGet("page")]
|
||||||
|
public async Task<Pagination<VoucherPageResponse>> GetPageAsync([FromQuery] VoucherPageRequest request)
|
||||||
|
{
|
||||||
|
return await _namedResolver.GetService<IVoucherService>(request.Type.ToString() + "VoucherService").GetPageAsync(request);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 获取我的分页数据(按券类型)(H5)
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="request"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
[HttpGet("my")]
|
||||||
|
public async Task<Pagination<VoucherPageResponse>> GetMyPageAsync([FromQuery] VoucherPageRequest request)
|
||||||
|
{
|
||||||
|
var userCode = _currentUser.GetUserClaim(UserClaimConstants.JinkoCode);
|
||||||
|
request.UserCode = userCode;
|
||||||
|
return await _namedResolver.GetService<IVoucherService>(request.Type.ToString()).GetPageAsync(request);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 创建生日券
|
||||||
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
|
[AllowAnonymous]
|
||||||
|
[HttpPost("birthday/create")]
|
||||||
|
public async Task CreateBirthdayVoucherAsync(VoucherByBirthdayRequest request)
|
||||||
|
{
|
||||||
|
var srv = _namedResolver.GetService<IVoucherService>(VoucherEnumType.Birthday.ToString() + "VoucherService");
|
||||||
|
srv.ThrowIfNull("不支持的券类型");
|
||||||
|
await srv.CreateAsync(new Dictionary<string, object>
|
||||||
|
{
|
||||||
|
["userCodes"] = request.UserCodes,
|
||||||
|
["begin"] = request.Begin,
|
||||||
|
["end"] = request.End,
|
||||||
|
["remark"] = request.Remark
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 餐券消费分页
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="request"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
[HttpGet("balance/page")]
|
||||||
|
[IgnoreTenant]
|
||||||
|
public async Task<Pagination<VoucherBalancePageResponse>> GetVoucherBalancePageAsync([FromQuery] VoucherBalancePageRequest request)
|
||||||
|
{
|
||||||
|
var srv = _namedResolver.GetService<IVoucherService>(request.Type.ToString() + "VoucherService");
|
||||||
|
|
||||||
|
return await srv.GetVoucherBalancePageAsync(request);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 我的餐券消费分页(H5)
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="request"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
[HttpGet("balance/my/page")]
|
||||||
|
[IgnoreTenant]
|
||||||
|
public async Task<Pagination<VoucherBalancePageResponse>> GetMyVoucherBalancePageAsync([FromQuery] VoucherBalancePageRequest request)
|
||||||
|
{
|
||||||
|
var srv = _namedResolver.GetService<IVoucherService>(request.Type.ToString());
|
||||||
|
return await srv.GetVoucherBalancePageAsync(request);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -2,7 +2,7 @@ using System.ComponentModel.DataAnnotations;
|
|||||||
using Kurisu.AspNetCore.CustomClass;
|
using Kurisu.AspNetCore.CustomClass;
|
||||||
using Kurisu.AspNetCore.DataAccess.Dto;
|
using Kurisu.AspNetCore.DataAccess.Dto;
|
||||||
|
|
||||||
namespace Dlhis.Canteen.EMealVoucher.Request;
|
namespace Dlhis.Canteen.Voucher.Requests;
|
||||||
|
|
||||||
public class EMealVoucherPageRequest : PageDto, IValidatableObject
|
public class EMealVoucherPageRequest : PageDto, IValidatableObject
|
||||||
{
|
{
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
using System.ComponentModel.DataAnnotations;
|
||||||
|
using Dlhis.Entity.Canteen.Enums;
|
||||||
|
using Kurisu.AspNetCore.CustomClass;
|
||||||
|
using Kurisu.AspNetCore.DataAccess.Dto;
|
||||||
|
|
||||||
|
namespace Dlhis.Canteen.Voucher.Requests;
|
||||||
|
|
||||||
|
public class VoucherBalancePageRequest : PageDto
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 券类型 VoucherEnumType
|
||||||
|
/// </summary>
|
||||||
|
[EnumDataType(typeof(VoucherEnumType))]
|
||||||
|
public VoucherEnumType Type { get; set; }
|
||||||
|
|
||||||
|
public string UserCode { get; set; }
|
||||||
|
|
||||||
|
public DateTimePeriod SearchDateTimePeriod { get; set; }
|
||||||
|
}
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
|
||||||
|
using System.ComponentModel.DataAnnotations;
|
||||||
|
|
||||||
|
namespace Dlhis.Basic.Vouchers.Request;
|
||||||
|
|
||||||
|
public class VoucherByBirthdayRequest
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 支持指定工号
|
||||||
|
/// </summary>
|
||||||
|
public List<string> UserCodes { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 开始范围
|
||||||
|
/// </summary>
|
||||||
|
public DateTime Begin { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 结束范围
|
||||||
|
/// </summary>
|
||||||
|
public DateTime End { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 备注
|
||||||
|
/// </summary>
|
||||||
|
[Required(ErrorMessage = "请填写备注")]
|
||||||
|
public string Remark { get; set; }
|
||||||
|
}
|
||||||
35
Src/Dlhis.Canteen/Voucher/Requests/VoucherPageRequest.cs
Normal file
35
Src/Dlhis.Canteen/Voucher/Requests/VoucherPageRequest.cs
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
using System.ComponentModel.DataAnnotations;
|
||||||
|
using Dlhis.Entity.Canteen.Enums;
|
||||||
|
using Kurisu.AspNetCore.CustomClass;
|
||||||
|
using Kurisu.AspNetCore.DataAccess.Dto;
|
||||||
|
|
||||||
|
namespace Dlhis.Canteen.Tickets.Request;
|
||||||
|
|
||||||
|
public class VoucherPageRequest : PageDto
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 类型 VoucherEnumType
|
||||||
|
/// </summary>
|
||||||
|
[EnumDataType(typeof(VoucherEnumType))]
|
||||||
|
public VoucherEnumType Type { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 工号
|
||||||
|
/// </summary>
|
||||||
|
public string UserCode { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 查询日期区间
|
||||||
|
/// </summary>
|
||||||
|
public DateTimePeriod SearchDateTimePeriod { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 一级部门
|
||||||
|
/// </summary>
|
||||||
|
public string DepartmentNoFirst { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 二级部门
|
||||||
|
/// </summary>
|
||||||
|
public string DepartmentNoSecond { get; set; }
|
||||||
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
namespace Dlhis.Canteen.EMealVoucher.Response;
|
namespace Dlhis.Canteen.Voucher.Response;
|
||||||
|
|
||||||
public class EMealVoucherDetailResponse
|
public class EMealVoucherDetailResponse
|
||||||
{
|
{
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
namespace Dlhis.Canteen.EMealVoucher.Response;
|
namespace Dlhis.Canteen.Voucher.Response;
|
||||||
|
|
||||||
public class EMealVoucherMyPageResponse
|
public class EMealVoucherMyPageResponse
|
||||||
{
|
{
|
||||||
@@ -3,7 +3,7 @@ using Kurisu.AspNetCore.Utils.Extensions;
|
|||||||
using Mapster.Utils;
|
using Mapster.Utils;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
namespace Dlhis.Canteen.EMealVoucher.Response;
|
namespace Dlhis.Canteen.Voucher.Response;
|
||||||
|
|
||||||
public class EMealVoucherPageResponse
|
public class EMealVoucherPageResponse
|
||||||
{
|
{
|
||||||
@@ -65,7 +65,7 @@ public class EMealVoucherPageResponse
|
|||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
var a = CurrentShifts.ToObject<List<int>>().Select(x => ((ShiftEnumType)(x * 10))).ToList();
|
var a = CurrentShifts.ToObject<List<int>>().Select(x => (ShiftEnumType)(x * 10)).ToList();
|
||||||
return a.Select(x=>x.GetDescription()).ToList();
|
return a.Select(x=>x.GetDescription()).ToList();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
129
Src/Dlhis.Canteen/Voucher/Response/VoucherBalancePageResponse.cs
Normal file
129
Src/Dlhis.Canteen/Voucher/Response/VoucherBalancePageResponse.cs
Normal file
@@ -0,0 +1,129 @@
|
|||||||
|
using Dlhis.Entity.Canteen.Enums;
|
||||||
|
using Kurisu.AspNetCore.Utils.Converters;
|
||||||
|
using Kurisu.AspNetCore.Utils.Extensions;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
|
namespace Dlhis.Canteen.Voucher.Response;
|
||||||
|
|
||||||
|
public class VoucherBalancePageResponse
|
||||||
|
{
|
||||||
|
public long Id { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 流水号
|
||||||
|
/// </summary>
|
||||||
|
public string No { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 档案号/QRCode
|
||||||
|
/// </summary>
|
||||||
|
public string UserNo { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 姓名
|
||||||
|
/// </summary>
|
||||||
|
public string Name { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 学工号
|
||||||
|
/// </summary>
|
||||||
|
public string UserCode { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 部门号
|
||||||
|
/// </summary>
|
||||||
|
public string DepartmentNo { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 部门
|
||||||
|
/// </summary>
|
||||||
|
public string DepartmentName { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 所属成本日期
|
||||||
|
/// </summary>
|
||||||
|
[JsonConverter(typeof(ToDateJsonConverter))]
|
||||||
|
public DateTime CostDate { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 备注
|
||||||
|
/// </summary>
|
||||||
|
public string Remark { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 来源
|
||||||
|
/// </summary>
|
||||||
|
public BalanceRecordSourceEnumType Source { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 消费识别来源
|
||||||
|
/// </summary>
|
||||||
|
public string SourceDesc => Source.GetDescription();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 收入/支出
|
||||||
|
/// </summary>
|
||||||
|
public BalanceRecordTypeEnumType Type { get; set; }
|
||||||
|
|
||||||
|
public string TypeDesc => Type.GetDescription();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 金额
|
||||||
|
/// </summary>
|
||||||
|
public decimal Amount { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 营业点
|
||||||
|
/// </summary>
|
||||||
|
public string BusinessPlaceName { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 餐次
|
||||||
|
/// </summary>
|
||||||
|
public ShiftEnumType? ShiftType { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 餐次
|
||||||
|
/// </summary>
|
||||||
|
public string ShiftTypeDesc => ShiftType?.GetDescription();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 消费机器唯一信息
|
||||||
|
/// </summary>
|
||||||
|
public string DeviceInfo { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 成本中心
|
||||||
|
/// </summary>
|
||||||
|
public string CostId { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 消费者所在基地
|
||||||
|
/// </summary>
|
||||||
|
public string OriginTenantId { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 数据状态
|
||||||
|
/// </summary>
|
||||||
|
public BalanceRecordStatusEnumType Status { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 数据状态描述
|
||||||
|
/// </summary>
|
||||||
|
public string StatusDesc => Status.GetDescription();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 记录产生时间
|
||||||
|
/// </summary>
|
||||||
|
public DateTime CostDateTime { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 厂区
|
||||||
|
/// </summary>
|
||||||
|
public string Factory { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 人事范围
|
||||||
|
/// </summary>
|
||||||
|
public string Werks { get; set; }
|
||||||
|
}
|
||||||
@@ -1,13 +1,13 @@
|
|||||||
using Dlhis.Entity.Canteen.Enums;
|
using Dlhis.Entity.Canteen.Enums;
|
||||||
|
|
||||||
namespace Dlhis.Canteen.Tickets.Response;
|
namespace Dlhis.Canteen.Voucher.Response;
|
||||||
|
|
||||||
public class TicketPageResponse
|
public class VoucherPageResponse
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 券类型
|
/// 券类型
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public TicketEnumType Type { get; set; }
|
public VoucherEnumType Type { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 工号
|
/// 工号
|
||||||
@@ -30,12 +30,27 @@ public class TicketPageResponse
|
|||||||
public decimal Amount { get; set; }
|
public decimal Amount { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 消费码
|
/// 描述
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string QrCode { get; set; }
|
public string Description { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 备注
|
/// 备注
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string Remark { get; set; }
|
public string Remark { get; set; }
|
||||||
|
|
||||||
|
public string CostId { get; set; }
|
||||||
|
|
||||||
|
|
||||||
|
public string DepartmentNo { get; set; }
|
||||||
|
public string DepartmentName { get; set; }
|
||||||
|
|
||||||
|
public string DepartmentNoFirst { get; set; }
|
||||||
|
public string DepartmentNameFirst { get; set; }
|
||||||
|
public string DepartmentNoSecond { get; set; }
|
||||||
|
public string DepartmentNameSecond { get; set; }
|
||||||
|
|
||||||
|
|
||||||
|
public string Werks { get; set; }
|
||||||
|
public string Factory { get; set; }
|
||||||
}
|
}
|
||||||
@@ -1,11 +1,11 @@
|
|||||||
using Dlhis.Canteen.EMealVoucher.Request;
|
|
||||||
using Dlhis.Canteen.EMealVoucher.Response;
|
|
||||||
using Dlhis.Canteen.Order.Request;
|
using Dlhis.Canteen.Order.Request;
|
||||||
using Dlhis.Canteen.Order.Response;
|
using Dlhis.Canteen.Order.Response;
|
||||||
|
using Dlhis.Canteen.Voucher.Requests;
|
||||||
|
using Dlhis.Canteen.Voucher.Response;
|
||||||
using Kurisu.AspNetCore.DataAccess.Dto;
|
using Kurisu.AspNetCore.DataAccess.Dto;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
|
||||||
namespace Dlhis.Canteen.EMealVoucher.Services;
|
namespace Dlhis.Canteen.Voucher.Services;
|
||||||
|
|
||||||
public interface IEMealVoucherService : IScopeDependency
|
public interface IEMealVoucherService : IScopeDependency
|
||||||
{
|
{
|
||||||
13
Src/Dlhis.Canteen/Voucher/Services/IVoucherQrCodeService.cs
Normal file
13
Src/Dlhis.Canteen/Voucher/Services/IVoucherQrCodeService.cs
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
namespace Dlhis.Canteen.Voucher.Services;
|
||||||
|
|
||||||
|
public interface IVoucherQrCodeService
|
||||||
|
{
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 获取二维码
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="voucherNo"></param>
|
||||||
|
/// <param name="isNeedRefresh"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
Task<string> GetQrCodeAsync(string voucherNo, bool isNeedRefresh = false);
|
||||||
|
}
|
||||||
28
Src/Dlhis.Canteen/Voucher/Services/IVoucherService.cs
Normal file
28
Src/Dlhis.Canteen/Voucher/Services/IVoucherService.cs
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
using Dlhis.Canteen.Tickets.Request;
|
||||||
|
using Dlhis.Canteen.Voucher.Requests;
|
||||||
|
using Dlhis.Canteen.Voucher.Response;
|
||||||
|
using Kurisu.AspNetCore.DataAccess.Dto;
|
||||||
|
|
||||||
|
namespace Dlhis.Canteen.Tickets.Services;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 券
|
||||||
|
/// </summary>
|
||||||
|
public interface IVoucherService : IScopeDependency
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 分页数据
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="request"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
Task<Pagination<VoucherPageResponse>> GetPageAsync(VoucherPageRequest request);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 创建
|
||||||
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
|
Task CreateAsync(Dictionary<string, object> pairs);
|
||||||
|
|
||||||
|
|
||||||
|
Task<Pagination<VoucherBalancePageResponse>> GetVoucherBalancePageAsync(VoucherBalancePageRequest request);
|
||||||
|
}
|
||||||
@@ -0,0 +1,83 @@
|
|||||||
|
using Dlhis.Canteen.Tickets.Request;
|
||||||
|
using Dlhis.Canteen.Voucher.Requests;
|
||||||
|
using Dlhis.Canteen.Voucher.Response;
|
||||||
|
using Dlhis.Entity.Basic.Entity;
|
||||||
|
using Dlhis.Entity.Canteen.Entities.Voucher;
|
||||||
|
using Kurisu.AspNetCore.CustomClass;
|
||||||
|
using Kurisu.AspNetCore.DataAccess.Dto;
|
||||||
|
using Kurisu.AspNetCore.DataAccess.SqlSugar.Extensions;
|
||||||
|
using Kurisu.AspNetCore.DataAccess.SqlSugar.Services;
|
||||||
|
using Kurisu.AspNetCore.Utils.Extensions;
|
||||||
|
|
||||||
|
namespace Dlhis.Canteen.Tickets.Services.Implements;
|
||||||
|
|
||||||
|
public abstract class BaseVoucherService : IVoucherService
|
||||||
|
{
|
||||||
|
protected IDbContext DbContext { get; set; }
|
||||||
|
|
||||||
|
protected BaseVoucherService(IDbContext dbContext)
|
||||||
|
{
|
||||||
|
DbContext = dbContext;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<Pagination<VoucherPageResponse>> GetPageAsync(VoucherPageRequest request)
|
||||||
|
{
|
||||||
|
var pagination = await DbContext.Queryable<VoucherEntity>()
|
||||||
|
.LeftJoin<VoucherUserInfoEntity>((x, u) => x.No == u.VoucherNo)
|
||||||
|
.LeftJoin<GainfoEntity>((x, u, ga) => u.UserCode == ga.Code)
|
||||||
|
.Where(x => x.Type == request.Type)
|
||||||
|
.WhereIF(request.UserCode.IsPresent(), (x, u, ga) => u.UserCode == request.UserCode)
|
||||||
|
.WhereIF(request.SearchDateTimePeriod.HasValue(),
|
||||||
|
(x, u, ga) => x.CreateTime >= request.SearchDateTimePeriod.Start &&
|
||||||
|
x.CreateTime <= request.SearchDateTimePeriod.End)
|
||||||
|
.WhereIF(request.DepartmentNoFirst.IsPresent(),
|
||||||
|
(x, u, ga) => u.DepartmentNoFirst == request.DepartmentNoFirst)
|
||||||
|
.WhereIF(request.DepartmentNoSecond.IsPresent(),
|
||||||
|
(x, u, ga) => u.DepartmentNoSecond == request.DepartmentNoSecond)
|
||||||
|
.OrderByDescending(x => x.ClaimDateTime)
|
||||||
|
.Select((x, u, ga) => new VoucherPageResponse
|
||||||
|
{
|
||||||
|
Type = x.Type,
|
||||||
|
UserCode = u.UserCode,
|
||||||
|
UserName = ga.Name,
|
||||||
|
OriginalAmount = x.OriginalBalance,
|
||||||
|
Amount = x.Balance,
|
||||||
|
Remark = x.Remark,
|
||||||
|
Description = x.Description,
|
||||||
|
|
||||||
|
CostId = u.CostId,
|
||||||
|
|
||||||
|
DepartmentNo = u.DepartmentNo,
|
||||||
|
DepartmentNoFirst = u.DepartmentNoFirst,
|
||||||
|
DepartmentNoSecond = u.DepartmentNoSecond,
|
||||||
|
|
||||||
|
Werks = u.Werks,
|
||||||
|
Factory = u.Factory
|
||||||
|
})
|
||||||
|
.ToPageListAsync(request);
|
||||||
|
|
||||||
|
var searchNos = pagination.Data.SelectMany(x =>
|
||||||
|
{
|
||||||
|
return new List<string>
|
||||||
|
{
|
||||||
|
x.DepartmentNo,
|
||||||
|
x.DepartmentNoFirst,
|
||||||
|
x.DepartmentNoSecond
|
||||||
|
};
|
||||||
|
}).Distinct().ToList();
|
||||||
|
|
||||||
|
var departments = await DbContext.Queryable<DepartmentEntity>().Where(x => searchNos.Contains(x.No)).ToListAsync();
|
||||||
|
|
||||||
|
pagination.Data.ForEach(x =>
|
||||||
|
{
|
||||||
|
x.DepartmentName = departments.FirstOrDefault(d => d.No == x.DepartmentNo)?.Name;
|
||||||
|
x.DepartmentNameFirst = departments.FirstOrDefault(d => d.No == x.DepartmentNoFirst)?.Name;
|
||||||
|
x.DepartmentNameSecond = departments.FirstOrDefault(d => d.No == x.DepartmentNoSecond)?.Name;
|
||||||
|
});
|
||||||
|
|
||||||
|
return pagination;
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract Task CreateAsync(Dictionary<string, object> pairs);
|
||||||
|
public abstract Task<Pagination<VoucherBalancePageResponse>> GetVoucherBalancePageAsync(VoucherBalancePageRequest request);
|
||||||
|
}
|
||||||
@@ -0,0 +1,254 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Text;
|
||||||
|
using Dlhis.Basic.Api;
|
||||||
|
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.DataAccess.SqlSugar.Services;
|
||||||
|
using Kurisu.AspNetCore.Utils.Extensions;
|
||||||
|
using SqlSugar;
|
||||||
|
|
||||||
|
namespace Dlhis.Canteen.Voucher.Services.Implements;
|
||||||
|
|
||||||
|
[Service("BirthdayVoucherService")]
|
||||||
|
public class BirthdayVoucherService : BaseVoucherService, IVoucherService
|
||||||
|
{
|
||||||
|
private readonly IFactorySettingApi _factorySettingApi;
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public BirthdayVoucherService(IDbContext dbContext, IFactorySettingApi factorySettingApi) : base(dbContext)
|
||||||
|
{
|
||||||
|
_factorySettingApi = factorySettingApi;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <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 + "-" + gainfo.Birthday.Value.ToString("MM-dd");
|
||||||
|
//由数据类型+工号+生日组成唯一标识
|
||||||
|
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
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
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 => 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)
|
||||||
|
.Where(x => x.UserCode == request.UserCode)
|
||||||
|
.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);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,11 +1,12 @@
|
|||||||
using System.Text;
|
using System.Text;
|
||||||
using Dlhis.Canteen.EMealVoucher.Request;
|
|
||||||
using Dlhis.Canteen.EMealVoucher.Response;
|
|
||||||
using Dlhis.Canteen.Order.Request;
|
using Dlhis.Canteen.Order.Request;
|
||||||
using Dlhis.Canteen.Order.Response;
|
using Dlhis.Canteen.Order.Response;
|
||||||
|
using Dlhis.Canteen.Voucher.Requests;
|
||||||
|
using Dlhis.Canteen.Voucher.Response;
|
||||||
using Dlhis.Constants;
|
using Dlhis.Constants;
|
||||||
using Dlhis.Entity.Basic.Entity;
|
using Dlhis.Entity.Basic.Entity;
|
||||||
using Dlhis.Entity.Canteen.Entities;
|
using Dlhis.Entity.Canteen.Entities;
|
||||||
|
using Dlhis.Entity.Canteen.Entities.EMealVoucher;
|
||||||
using Dlhis.Entity.Canteen.Enums;
|
using Dlhis.Entity.Canteen.Enums;
|
||||||
using Kurisu.AspNetCore.Authentication.Abstractions;
|
using Kurisu.AspNetCore.Authentication.Abstractions;
|
||||||
using Kurisu.AspNetCore.CustomClass;
|
using Kurisu.AspNetCore.CustomClass;
|
||||||
@@ -15,7 +16,7 @@ using Kurisu.AspNetCore.DataAccess.SqlSugar.Services;
|
|||||||
using Kurisu.AspNetCore.Utils.Extensions;
|
using Kurisu.AspNetCore.Utils.Extensions;
|
||||||
using SqlSugar;
|
using SqlSugar;
|
||||||
|
|
||||||
namespace Dlhis.Canteen.EMealVoucher.Services.Implements;
|
namespace Dlhis.Canteen.Voucher.Services.Implements;
|
||||||
|
|
||||||
public class EMealVoucherService : IEMealVoucherService
|
public class EMealVoucherService : IEMealVoucherService
|
||||||
{
|
{
|
||||||
@@ -0,0 +1,75 @@
|
|||||||
|
|
||||||
|
using System.Text;
|
||||||
|
using Dlhis.Constants;
|
||||||
|
using Dlhis.Entity.Canteen.Entities.Voucher;
|
||||||
|
using Kurisu.AspNetCore.Authentication.Abstractions;
|
||||||
|
using Kurisu.AspNetCore.DataAccess.SqlSugar.Services;
|
||||||
|
using Kurisu.AspNetCore.Utils.Extensions;
|
||||||
|
|
||||||
|
namespace Dlhis.Canteen.Voucher.Services.Implements;
|
||||||
|
|
||||||
|
public class VoucherQrCodeService : IVoucherQrCodeService
|
||||||
|
{
|
||||||
|
private readonly IDbContext _dbContext;
|
||||||
|
private readonly ICurrentUser _currentUser;
|
||||||
|
|
||||||
|
public VoucherQrCodeService(IDbContext dbContext, ICurrentUser currentUser)
|
||||||
|
{
|
||||||
|
_dbContext = dbContext;
|
||||||
|
_currentUser = currentUser;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public async Task<string> GetQrCodeAsync(string voucherNo, bool isNeedRefresh = false)
|
||||||
|
{
|
||||||
|
var userCode = _currentUser.GetUserClaim(UserClaimConstants.JinkoCode);
|
||||||
|
if (!await _dbContext.Queryable<VoucherUserInfoEntity>().Where(x => x.VoucherNo == voucherNo && x.UserCode == userCode).AnyAsync())
|
||||||
|
{
|
||||||
|
true.ThrowIfTrue("非法的消费券");
|
||||||
|
}
|
||||||
|
|
||||||
|
var qrcodeInfo = await _dbContext.Queryable<VoucherQrCodeEntity>().SingleAsync(x => x.VoucherNo == voucherNo);
|
||||||
|
|
||||||
|
if (qrcodeInfo == null)
|
||||||
|
{
|
||||||
|
qrcodeInfo = new VoucherQrCodeEntity
|
||||||
|
{
|
||||||
|
VoucherNo = voucherNo,
|
||||||
|
QrCode = GenerateQrCode(voucherNo)
|
||||||
|
};
|
||||||
|
|
||||||
|
await _dbContext.InsertAsync(qrcodeInfo);
|
||||||
|
return qrcodeInfo.QrCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
var now = DateTime.Now;
|
||||||
|
if (qrcodeInfo.ModifiedTime.AddMinutes(1) >= now && !isNeedRefresh)
|
||||||
|
{
|
||||||
|
return qrcodeInfo.QrCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
qrcodeInfo.QrCode = GenerateQrCode(voucherNo);
|
||||||
|
await _dbContext.UpdateAsync(qrcodeInfo);
|
||||||
|
|
||||||
|
return qrcodeInfo.QrCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// qrCode生成
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="voucherNo"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
private static string GenerateQrCode(string voucherNo)
|
||||||
|
{
|
||||||
|
var ts = DateTimeOffset.Now.ToUnixTimeMilliseconds();
|
||||||
|
|
||||||
|
return QrCodeConstants.Birthday + voucherNo.ToArray().Select(x =>
|
||||||
|
{
|
||||||
|
var b = Encoding.ASCII.GetBytes(x.ToString());
|
||||||
|
int i = b[0];
|
||||||
|
return Convert.ToString(i);
|
||||||
|
|
||||||
|
}).Join(string.Empty) + ts;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -26,5 +26,17 @@ namespace Dlhis.Entity.Basic.Entity
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
[SugarColumn(IsNullable = false, ColumnDescription = "部门名称")]
|
[SugarColumn(IsNullable = false, ColumnDescription = "部门名称")]
|
||||||
public string Name { get; set; }
|
public string Name { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 部门编码
|
||||||
|
/// </summary>
|
||||||
|
[SugarColumn(IsNullable = true, ColumnDescription = "一级部门编码")]
|
||||||
|
public string DepartmentNoFirst { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 部门编码
|
||||||
|
/// </summary>
|
||||||
|
[SugarColumn(IsNullable = true, ColumnDescription = "二级部门编码")]
|
||||||
|
public string DepartmentNoSecond { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
13
Src/Dlhis.Entity/Basic/Entity/OutsourceWhiteListEntity.cs
Normal file
13
Src/Dlhis.Entity/Basic/Entity/OutsourceWhiteListEntity.cs
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
using Kurisu.AspNetCore.DataAccess.Entity;
|
||||||
|
using Kurisu.AspNetCore.DataAccess.SqlSugar;
|
||||||
|
using SqlSugar;
|
||||||
|
|
||||||
|
namespace Dlhis.Entity.Basic.Entity;
|
||||||
|
|
||||||
|
|
||||||
|
[SugarTable(TableName = "OutsourceWhiteList", TableDescription = "外包人员白名单")]
|
||||||
|
public class OutsourceWhiteListEntity : SugarBaseEntity, ISoftDeleted
|
||||||
|
{
|
||||||
|
public string UserCode { get; set; }
|
||||||
|
public bool IsDeleted { get; set; }
|
||||||
|
}
|
||||||
@@ -2,7 +2,7 @@
|
|||||||
using Kurisu.AspNetCore.DataAccess.SqlSugar;
|
using Kurisu.AspNetCore.DataAccess.SqlSugar;
|
||||||
using SqlSugar;
|
using SqlSugar;
|
||||||
|
|
||||||
namespace Dlhis.Entity.Canteen.Entities;
|
namespace Dlhis.Entity.Canteen.Entities.EMealVoucher;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 电子餐券明细
|
/// 电子餐券明细
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
using Kurisu.AspNetCore.DataAccess.SqlSugar;
|
using Kurisu.AspNetCore.DataAccess.SqlSugar;
|
||||||
using SqlSugar;
|
using SqlSugar;
|
||||||
|
|
||||||
namespace Dlhis.Entity.Canteen.Entities;
|
namespace Dlhis.Entity.Canteen.Entities.EMealVoucher;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 电子餐券明细QrCode
|
/// 电子餐券明细QrCode
|
||||||
@@ -2,7 +2,7 @@
|
|||||||
using Kurisu.AspNetCore.DataAccess.SqlSugar;
|
using Kurisu.AspNetCore.DataAccess.SqlSugar;
|
||||||
using SqlSugar;
|
using SqlSugar;
|
||||||
|
|
||||||
namespace Dlhis.Entity.Canteen.Entities;
|
namespace Dlhis.Entity.Canteen.Entities.EMealVoucher;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 餐券
|
/// 餐券
|
||||||
@@ -1,28 +0,0 @@
|
|||||||
using Kurisu.AspNetCore.DataAccess.Entity;
|
|
||||||
using Kurisu.AspNetCore.DataAccess.SqlSugar;
|
|
||||||
using SqlSugar;
|
|
||||||
|
|
||||||
namespace Dlhis.Entity.Canteen.Entities;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 用户余额表
|
|
||||||
/// </summary>
|
|
||||||
[SugarTable(TableName = "UserBalanceTmp", TableDescription = "用户余额表")]
|
|
||||||
public class UserBalanceTmpEntity : SugarBaseEntity, IVersion
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// 学工号
|
|
||||||
/// </summary>
|
|
||||||
[SugarColumn(IsNullable = false, ColumnDescription = "学工号", UniqueGroupNameList = new[] { "idx_UserBalances_useCode" })]
|
|
||||||
public string UserCode { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 余额
|
|
||||||
/// </summary>
|
|
||||||
[SugarColumn(IsNullable = false, ColumnDescription = "余额")]
|
|
||||||
public decimal Balance { get; set; }
|
|
||||||
|
|
||||||
|
|
||||||
[SugarColumn(IsNullable = false)]
|
|
||||||
public int Version { get; set; }
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
using Kurisu.AspNetCore.DataAccess.SqlSugar;
|
||||||
|
using SqlSugar;
|
||||||
|
|
||||||
|
namespace Dlhis.Entity.Canteen.Entities;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 用户消费上传记录表
|
||||||
|
/// </summary>
|
||||||
|
[SugarTable(TableName = "UserBalanceUploadRecords", TableDescription = "用户消费上传记录表")]
|
||||||
|
public class UserBalanceUploadRecordEntity : SugarBaseEntity
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 年份
|
||||||
|
/// </summary>
|
||||||
|
[SugarColumn(IsNullable = false, ColumnDescription = "年份")]
|
||||||
|
public int Year { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 月份
|
||||||
|
/// </summary>
|
||||||
|
[SugarColumn(IsNullable = false, ColumnDescription = "月份")]
|
||||||
|
public int Month { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 学工号
|
||||||
|
/// </summary>
|
||||||
|
[SugarColumn(IsNullable = false, ColumnDescription = "学工号", UniqueGroupNameList = new[] { "idx_UserBalances_useCode" })]
|
||||||
|
public string UserCode { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 消费
|
||||||
|
/// </summary>
|
||||||
|
[SugarColumn(IsNullable = false, ColumnDescription = "余额")]
|
||||||
|
public decimal Cost { get; set; }
|
||||||
|
}
|
||||||
@@ -4,25 +4,30 @@ using Kurisu.AspNetCore.DataAccess.SqlSugar;
|
|||||||
using SqlSugar;
|
using SqlSugar;
|
||||||
using SqlSugar.DbConvert;
|
using SqlSugar.DbConvert;
|
||||||
|
|
||||||
namespace Dlhis.Entity.Canteen.Entities;
|
namespace Dlhis.Entity.Canteen.Entities.Voucher;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 券
|
/// 券
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[SugarTable("Tickets", TableDescription = "券")]
|
[SugarTable("Vouchers", TableDescription = "券")]
|
||||||
public class TicketEntity : SugarBaseEntity, ITenantId, IVersion
|
public class VoucherEntity : SugarBaseEntity, IVersion
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 券唯一标识
|
||||||
|
/// </summary>
|
||||||
|
[SugarColumn(IsNullable = false, ColumnDescription = "券唯一标识")]
|
||||||
|
public string No { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 获取日期时间
|
||||||
|
/// </summary>
|
||||||
|
public DateTime ClaimDateTime { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 类型
|
/// 类型
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[SugarColumn(IsNullable = false, ColumnDataType = "varchar(50)", ColumnDescription = "券类型", SqlParameterDbType = typeof(EnumToStringConvert))]
|
[SugarColumn(IsNullable = false, ColumnDataType = "varchar(50)", ColumnDescription = "券类型", SqlParameterDbType = typeof(EnumToStringConvert))]
|
||||||
public TicketEnumType Type { get; set; }
|
public VoucherEnumType Type { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 工号
|
|
||||||
/// </summary>
|
|
||||||
[SugarColumn(IsNullable = false, ColumnDescription = "工号")]
|
|
||||||
public string UserCode { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 初始余额
|
/// 初始余额
|
||||||
@@ -37,10 +42,10 @@ public class TicketEntity : SugarBaseEntity, ITenantId, IVersion
|
|||||||
public decimal Balance { get; set; }
|
public decimal Balance { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 消费码
|
/// 描述
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[SugarColumn(IsNullable = false, ColumnDescription = "消费码")]
|
[SugarColumn(IsNullable = true, ColumnDescription = "描述")]
|
||||||
public string QrCode { get; set; }
|
public string Description { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 备注
|
/// 备注
|
||||||
@@ -48,8 +53,5 @@ public class TicketEntity : SugarBaseEntity, ITenantId, IVersion
|
|||||||
[SugarColumn(IsNullable = true, ColumnDescription = "备注")]
|
[SugarColumn(IsNullable = true, ColumnDescription = "备注")]
|
||||||
public string Remark { get; set; }
|
public string Remark { get; set; }
|
||||||
|
|
||||||
public string TenantId { get; set; }
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
public int Version { get; set; }
|
public int Version { get; set; }
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
using Kurisu.AspNetCore.DataAccess.SqlSugar;
|
||||||
|
using SqlSugar;
|
||||||
|
|
||||||
|
namespace Dlhis.Entity.Canteen.Entities.Voucher;
|
||||||
|
|
||||||
|
[SugarTable(TableName = "VoucherQrCodes")]
|
||||||
|
public class VoucherQrCodeEntity : SugarBaseEntity
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 券No
|
||||||
|
/// </summary>
|
||||||
|
[SugarColumn(ColumnDescription = "券No")]
|
||||||
|
public string VoucherNo { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 二维码
|
||||||
|
/// </summary>
|
||||||
|
[SugarColumn(ColumnDescription = "二维码", UniqueGroupNameList = new[] { "idx_EMealVoucherDetailQrCode_qrcode" })]
|
||||||
|
public string QrCode { get; set; }
|
||||||
|
}
|
||||||
@@ -0,0 +1,63 @@
|
|||||||
|
using Kurisu.AspNetCore.DataAccess.SqlSugar;
|
||||||
|
using SqlSugar;
|
||||||
|
|
||||||
|
namespace Dlhis.Entity.Canteen.Entities.Voucher;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 券发放时候关联的用户信息
|
||||||
|
/// </summary>
|
||||||
|
[SugarTable(TableName = "VoucherUserInfos")]
|
||||||
|
public class VoucherUserInfoEntity : SugarBaseEntity
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 券码
|
||||||
|
/// </summary>
|
||||||
|
[SugarColumn(IsNullable = false)]
|
||||||
|
public string VoucherNo { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 工号
|
||||||
|
/// </summary>
|
||||||
|
[SugarColumn(IsNullable = false, ColumnDescription = "工号")]
|
||||||
|
public string UserCode { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 成本中心
|
||||||
|
/// </summary>
|
||||||
|
[SugarColumn(IsNullable = false)]
|
||||||
|
public string CostId { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 人事范围
|
||||||
|
/// </summary>
|
||||||
|
[SugarColumn(IsNullable = false)]
|
||||||
|
public string Werks { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 厂区
|
||||||
|
/// </summary>
|
||||||
|
[SugarColumn(IsNullable = false)]
|
||||||
|
public string Factory { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 当前部门
|
||||||
|
/// </summary>
|
||||||
|
[SugarColumn(IsNullable = false)]
|
||||||
|
public string DepartmentNo { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 一级部门
|
||||||
|
/// </summary>
|
||||||
|
[SugarColumn(IsNullable = false)]
|
||||||
|
public string DepartmentNoFirst { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 二级部门
|
||||||
|
/// </summary>
|
||||||
|
[SugarColumn(IsNullable = true)]
|
||||||
|
public string DepartmentNoSecond { get; set; }
|
||||||
|
|
||||||
|
|
||||||
|
[SugarColumn(IsNullable = true, ColumnDataType = "varchar(255)")]
|
||||||
|
public string Signature { get; set; }
|
||||||
|
}
|
||||||
@@ -6,7 +6,7 @@ namespace Dlhis.Entity.Canteen.Enums;
|
|||||||
/// 券类型
|
/// 券类型
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[Description("券类型")]
|
[Description("券类型")]
|
||||||
public enum TicketEnumType
|
public enum VoucherEnumType
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 生日券
|
/// 生日券
|
||||||
@@ -9,7 +9,7 @@ namespace Dlhis.Entity.Device.Entities;
|
|||||||
/// 设备权限(手动)
|
/// 设备权限(手动)
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[SugarTable(TableName = "DevicePermissionManually")]
|
[SugarTable(TableName = "DevicePermissionManually")]
|
||||||
public class DevicePermissionManuallyEntity : SugarBaseEntity, ISoftDeleted , ITenantId
|
public class DevicePermissionManuallyEntity : SugarBaseEntity, ISoftDeleted, ITenantId
|
||||||
{
|
{
|
||||||
[DeviceCode]
|
[DeviceCode]
|
||||||
[SugarColumn(IsNullable = false)]
|
[SugarColumn(IsNullable = false)]
|
||||||
@@ -19,9 +19,13 @@ public class DevicePermissionManuallyEntity : SugarBaseEntity, ISoftDeleted , IT
|
|||||||
[SugarColumn(IsNullable = false)]
|
[SugarColumn(IsNullable = false)]
|
||||||
public string UserNo { get; set; }
|
public string UserNo { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 有效时间
|
||||||
|
/// </summary>
|
||||||
|
[SugarColumn(IsNullable = true)]
|
||||||
|
public DateTime? ValidDateTime { get; set; }
|
||||||
|
|
||||||
public bool IsDeleted { get; set; }
|
public bool IsDeleted { get; set; }
|
||||||
|
|
||||||
|
|
||||||
public string TenantId { get; set; }
|
public string TenantId { get; set; }
|
||||||
}
|
}
|
||||||
@@ -49,5 +49,17 @@ public class FactorySettingEntity : SugarBaseEntity, ITenantId
|
|||||||
[SugarColumn(IsNullable = true, ColumnDataType = "time", ColumnDescription = "工作网格编辑限制时间")]
|
[SugarColumn(IsNullable = true, ColumnDataType = "time", ColumnDescription = "工作网格编辑限制时间")]
|
||||||
public TimeOnly? WorkGridSetLimit { get; set; }
|
public TimeOnly? WorkGridSetLimit { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 是否启用生日电子餐券
|
||||||
|
/// </summary>
|
||||||
|
[SugarColumn(ColumnDataType = "bit", ColumnDescription = "是否启用生日电子餐券", DefaultValue = "0")]
|
||||||
|
public bool EnableBirthdayVoucher { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 允许消费的厂区
|
||||||
|
/// </summary>
|
||||||
|
[SugarColumn(ColumnDescription = "允许消费的厂区")]
|
||||||
|
public string EnableUseBirthdayVoucherFactories { get; set; }
|
||||||
|
|
||||||
public string TenantId { get; set; }
|
public string TenantId { get; set; }
|
||||||
}
|
}
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
using Dlhis.Entity.Basic.Entity;
|
using Dlhis.Entity.Basic.Entity;
|
||||||
using Dlhis.Entity.Canteen.Entities;
|
using Dlhis.Entity.Canteen.Entities.EMealVoucher;
|
||||||
using Dlhis.Entity.Canteen.Enums;
|
using Dlhis.Entity.Canteen.Enums;
|
||||||
using Dlhis.External.EMealVoucher.Request;
|
using Dlhis.External.EMealVoucher.Request;
|
||||||
using Kurisu.AspNetCore.DataAccess.SqlSugar.Services;
|
using Kurisu.AspNetCore.DataAccess.SqlSugar.Services;
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
using Dlhis.Entity.Basic.Entity;
|
using Dlhis.Entity.Basic.Entity;
|
||||||
using Dlhis.Entity.Canteen.Entities;
|
using Dlhis.Entity.Canteen.Entities;
|
||||||
|
using Dlhis.Entity.Canteen.Entities.EMealVoucher;
|
||||||
using Dlhis.Entity.Canteen.Enums;
|
using Dlhis.Entity.Canteen.Enums;
|
||||||
using Dlhis.External.OpenApi.Response;
|
using Dlhis.External.OpenApi.Response;
|
||||||
using Kurisu.AspNetCore.CustomClass;
|
using Kurisu.AspNetCore.CustomClass;
|
||||||
|
|||||||
@@ -41,6 +41,37 @@ public class SapOrganizationItem
|
|||||||
/// 事业部
|
/// 事业部
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string ORGID02 { get; set; }
|
public string ORGID02 { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 一级部分
|
||||||
|
/// </summary>
|
||||||
|
public string ORGID03 { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 二级部门
|
||||||
|
/// </summary>
|
||||||
|
public string ORGID04 { get; set; }
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 三级部门
|
||||||
|
/// </summary>
|
||||||
|
public string ORGID05 { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 四级部门
|
||||||
|
/// </summary>
|
||||||
|
public string ORGID06 { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 五级部门
|
||||||
|
/// </summary>
|
||||||
|
public string ORGID07 { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 六级部门
|
||||||
|
/// </summary>
|
||||||
|
public string ORGID08 { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -86,4 +86,14 @@ public interface IJinkoJipApi
|
|||||||
[RequestLog]
|
[RequestLog]
|
||||||
[Post("/JIP/HCM/HCM_I_SHIFTREP")]
|
[Post("/JIP/HCM/HCM_I_SHIFTREP")]
|
||||||
Task<SyncWorkShiftResponse> SyncWorkShiftAsync(SyncWorkShiftRequest request);
|
Task<SyncWorkShiftResponse> SyncWorkShiftAsync(SyncWorkShiftRequest request);
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 费用上传
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="request"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
[RequestLog]
|
||||||
|
[Post("/JIP/HCM/HCM_0015_INSERT")]
|
||||||
|
Task<UploadCostResponse> UploadCostAsync(UploadCostRequest request);
|
||||||
}
|
}
|
||||||
39
Src/Dlhis.Jip.Api/Requests/UploadCostRequest.cs
Normal file
39
Src/Dlhis.Jip.Api/Requests/UploadCostRequest.cs
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
|
||||||
|
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
|
namespace Dlhis.Jip.Api.Requests;
|
||||||
|
|
||||||
|
public class UploadCostRequest
|
||||||
|
{
|
||||||
|
[JsonProperty("T_DATA")]
|
||||||
|
public List<UploadCostItemRequest> Data { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public class UploadCostItemRequest
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 工号 可选,为空则删除日期下的所有记录
|
||||||
|
/// </summary>
|
||||||
|
[JsonProperty("ZWORKCODE")]
|
||||||
|
public string WorkCode { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 子信息类型 9020 水费扣减(上饶),9021 冷水扣减(上饶),9022 热水扣减(上饶), 2086餐卡消费金额 , 2088生日券发放金额、2089生日券消费金额
|
||||||
|
/// </summary>
|
||||||
|
[JsonProperty("SUBTY")]
|
||||||
|
public string Code { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 开始日期
|
||||||
|
/// </summary>
|
||||||
|
[JsonProperty("BEGDA")]
|
||||||
|
public string BeginDate { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 工资项金额
|
||||||
|
/// </summary>
|
||||||
|
[JsonProperty("BETRG")]
|
||||||
|
public decimal Charge { get; set; }
|
||||||
|
}
|
||||||
47
Src/Dlhis.Jip.Api/Responses/UploadCostResponse.cs
Normal file
47
Src/Dlhis.Jip.Api/Responses/UploadCostResponse.cs
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
|
namespace Dlhis.Jip.Api.Responses;
|
||||||
|
|
||||||
|
public class UploadCostResponse
|
||||||
|
{
|
||||||
|
[JsonProperty("T_DATA")]
|
||||||
|
public List<UploadCostItemResponse> Data { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class UploadCostItemResponse
|
||||||
|
{
|
||||||
|
[JsonProperty("ZWORKCODE")]
|
||||||
|
public string WorkCode { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 子信息类型 9020 水费扣减(上饶),9021 冷水扣减(上饶),9022 热水扣减(上饶)
|
||||||
|
/// </summary>
|
||||||
|
[JsonProperty("SUBTY")]
|
||||||
|
public string Code { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 开始日期
|
||||||
|
/// </summary>
|
||||||
|
[JsonProperty("BEGDA")]
|
||||||
|
public string BeginDate { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 工资项金额
|
||||||
|
/// </summary>
|
||||||
|
[JsonProperty("BETRG")]
|
||||||
|
public decimal Price { get; set; }
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// S 成功
|
||||||
|
/// </summary>
|
||||||
|
[JsonProperty("MSGTY")]
|
||||||
|
public string Success { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 响应消息
|
||||||
|
/// </summary>
|
||||||
|
[JsonProperty("MSGTX")]
|
||||||
|
public string Message { get; set; }
|
||||||
|
}
|
||||||
@@ -11,12 +11,10 @@ public class RecurringJobAttribute : Attribute
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="uniqueJobKey">任务的唯一标识符。</param>
|
/// <param name="uniqueJobKey">任务的唯一标识符。</param>
|
||||||
/// <param name="cron">Cron 表达式,定义任务的执行计划。</param>
|
/// <param name="cron">Cron 表达式,定义任务的执行计划。</param>
|
||||||
/// <param name="runOnDevelopment">是否在开发环境中运行。</param>
|
public RecurringJobAttribute(string uniqueJobKey, string cron)
|
||||||
public RecurringJobAttribute(string uniqueJobKey, string cron, bool runOnDevelopment = false)
|
|
||||||
{
|
{
|
||||||
UniqueJobKey = uniqueJobKey;
|
UniqueJobKey = uniqueJobKey;
|
||||||
Cron = cron;
|
Cron = cron;
|
||||||
RunOnDevelopment = runOnDevelopment;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -37,7 +35,7 @@ public class RecurringJobAttribute : Attribute
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 是否在开发环境中运行。
|
/// 是否在开发环境中运行。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool RunOnDevelopment { get; }
|
public bool RunOnDevelopment { get; set; } = false;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 任务所属队列,默认为 "default"。
|
/// 任务所属队列,默认为 "default"。
|
||||||
|
|||||||
@@ -36,6 +36,11 @@ public class DeviceUploadLogsController : ControllerBase
|
|||||||
return await _deviceUploadLogService.GetPageAsync(request);
|
return await _deviceUploadLogService.GetPageAsync(request);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 查询用户的上传记录分页
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="request"></param>
|
||||||
|
/// <returns></returns>
|
||||||
[HttpGet("userpage")]
|
[HttpGet("userpage")]
|
||||||
public async Task<Pagination<DeviceUploadLogUserResponse>> GetUserPageAsync([FromQuery] DeviceUploadLogUserPageRequest request)
|
public async Task<Pagination<DeviceUploadLogUserResponse>> GetUserPageAsync([FromQuery] DeviceUploadLogUserPageRequest request)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -238,13 +238,13 @@ public class DeviceUploadLogService : IDeviceUploadLogService
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
await _dingTalkApi.SendWorkMessageAsync(new JinkoSendWorkMessageRequest
|
await _dingTalkApi.SendWorkMessageByWorkGridAsync(new JinkoSendWorkMessageRequest
|
||||||
{
|
{
|
||||||
Content = $"{workGridInfo.WorkGrid.WorkGridName}的网格长,你好,检测到你网格中 {currentGainfo.Name}({currentGainfo.Code}){request.RaiseDateTime.ToString("yyyy年MM月dd日")}未排班,但是有考勤记录,请前往系统处理!",
|
Content = $"{workGridInfo.WorkGrid.WorkGridName}的网格长,你好,检测到你网格中 {currentGainfo.Name}({currentGainfo.Code}){request.RaiseDateTime.ToString("yyyy年MM月dd日")}未排班,但是有考勤记录,请前往系统处理!",
|
||||||
WorkCodes = new List<string> { workGridInfo.WorkGrid.LeaderUserCode }
|
WorkCodes = new List<string> { workGridInfo.WorkGrid.LeaderUserCode }
|
||||||
});
|
});
|
||||||
|
|
||||||
await _dingTalkApi.SendWorkMessageAsync(new JinkoSendWorkMessageRequest
|
await _dingTalkApi.SendWorkMessageByWorkGridAsync(new JinkoSendWorkMessageRequest
|
||||||
{
|
{
|
||||||
Content = $"{currentGainfo.Name}({currentGainfo.Code},检测到你在{workGridInfo.WorkGrid.WorkGridName}网格中,当日未排班,考勤记录不生效,请立即联系网格长",
|
Content = $"{currentGainfo.Name}({currentGainfo.Code},检测到你在{workGridInfo.WorkGrid.WorkGridName}网格中,当日未排班,考勤记录不生效,请立即联系网格长",
|
||||||
WorkCodes = new List<string> { currentGainfo.Code }
|
WorkCodes = new List<string> { currentGainfo.Code }
|
||||||
|
|||||||
84
Src/Dlhis.ScheduledTask/Jobs/CostUploadJob.cs
Normal file
84
Src/Dlhis.ScheduledTask/Jobs/CostUploadJob.cs
Normal file
@@ -0,0 +1,84 @@
|
|||||||
|
using Dlhis.Entity.Canteen.Entities;
|
||||||
|
using Dlhis.Entity.Canteen.Enums;
|
||||||
|
using Dlhis.Jip.Api;
|
||||||
|
using Dlhis.Jip.Api.Requests;
|
||||||
|
using Dlhis.ScheduledTask.Attributes;
|
||||||
|
using SqlSugar;
|
||||||
|
|
||||||
|
namespace Dlhis.ScheduledTask.Jobs;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 每月8号上传消费数据
|
||||||
|
/// </summary>
|
||||||
|
[RecurringJob(nameof(CostUploadJob), "0 0 0 8 * ? ", Name = "每月8号上传消费数据")]
|
||||||
|
public class CostUploadJob : BaseJob
|
||||||
|
{
|
||||||
|
|
||||||
|
public CostUploadJob(IServiceProvider serviceProvider) : base(serviceProvider)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override async Task RunAsync(IServiceProvider serviceProvider)
|
||||||
|
{
|
||||||
|
var jipApi = serviceProvider.GetService<IJinkoJipApi>();
|
||||||
|
|
||||||
|
var now = DateTime.Now;
|
||||||
|
var month = now.Month == 1 ? 12 : now.Month - 1;
|
||||||
|
var s = new DateTime(2025, month, 1);
|
||||||
|
var e = new DateTime(2025, month + 1, 1);
|
||||||
|
var endDayOfMonth = e.AddDays(-1);
|
||||||
|
|
||||||
|
//从余额找人
|
||||||
|
var userCodes = await DbContext.Queryable<UserBalanceEntity>()
|
||||||
|
.Where(x => SqlFunc.Subqueryable<UserBalanceUploadRecordEntity>()
|
||||||
|
.Where(p => p.UserCode == x.UserCode)
|
||||||
|
.Where(p => p.Year == s.Year && p.Month == s.Month)
|
||||||
|
.NotAny()
|
||||||
|
)
|
||||||
|
.Select(x => x.UserCode)
|
||||||
|
.Distinct()
|
||||||
|
.ToListAsync();
|
||||||
|
|
||||||
|
foreach (var userCode in userCodes)
|
||||||
|
{
|
||||||
|
var balance = await DbContext.Queryable<BalanceRecordEntity>()
|
||||||
|
.Where(x => x.UserCode == userCode)
|
||||||
|
.Where(x => x.Status == BalanceRecordStatusEnumType.Valid)
|
||||||
|
.Where(x => x.Type == BalanceRecordTypeEnumType.Out)
|
||||||
|
.Where(x => x.CostDate >= s && x.CostDate < e)
|
||||||
|
.Where(x => !BalanceRecordSourceConstants.IgnoreSources.Contains(x.Source))
|
||||||
|
.SumAsync(x => x.Amount);
|
||||||
|
|
||||||
|
var response = await jipApi.UploadCostAsync(new UploadCostRequest
|
||||||
|
{
|
||||||
|
Data = new List<UploadCostItemRequest>
|
||||||
|
{
|
||||||
|
new UploadCostItemRequest
|
||||||
|
{
|
||||||
|
WorkCode = userCode,
|
||||||
|
BeginDate = endDayOfMonth.ToString("yyyy-MM-dd"),
|
||||||
|
Charge = balance,
|
||||||
|
Code= "2086"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (response.Data.FirstOrDefault(x => x.WorkCode == userCode)?.Success == "S")
|
||||||
|
{
|
||||||
|
if (!await DbContext.Queryable<UserBalanceUploadRecordEntity>()
|
||||||
|
.Where(x => x.UserCode == userCode)
|
||||||
|
.Where(x => x.Year == s.Year && x.Month == s.Month)
|
||||||
|
.AnyAsync())
|
||||||
|
{
|
||||||
|
await DbContext.InsertAsync(new UserBalanceUploadRecordEntity
|
||||||
|
{
|
||||||
|
Year = s.Year,
|
||||||
|
Month = s.Month,
|
||||||
|
UserCode = userCode,
|
||||||
|
Cost = balance,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
28
Src/Dlhis.ScheduledTask/Jobs/GenerateBirthdayVoucherJob.cs
Normal file
28
Src/Dlhis.ScheduledTask/Jobs/GenerateBirthdayVoucherJob.cs
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
using Dlhis.Canteen.Api;
|
||||||
|
using Dlhis.ScheduledTask.Attributes;
|
||||||
|
|
||||||
|
namespace Dlhis.ScheduledTask.Jobs;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 生日券生成
|
||||||
|
/// </summary>
|
||||||
|
[RecurringJob(nameof(GenerateBirthdayVoucherJob), "0 0 1,12 * * ?", Name = "生日券生成")]
|
||||||
|
public class GenerateBirthdayVoucherJob : BaseJob
|
||||||
|
{
|
||||||
|
public GenerateBirthdayVoucherJob(IServiceProvider serviceProvider) : base(serviceProvider)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override async Task RunAsync(IServiceProvider serviceProvider)
|
||||||
|
{
|
||||||
|
var now = DateTime.Today.Date;
|
||||||
|
|
||||||
|
var voucherApi = serviceProvider.GetService<IVoucherApi>();
|
||||||
|
await voucherApi.CreateAsync(new VoucherByBirthdayRequest
|
||||||
|
{
|
||||||
|
Begin = now,
|
||||||
|
End = now,
|
||||||
|
Remark = "定时执行生成"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -31,7 +31,7 @@ public class SendMsgToWorkGridLeaderJob : BaseJob
|
|||||||
|
|
||||||
foreach (var items in infos.Chunk(5))
|
foreach (var items in infos.Chunk(5))
|
||||||
{
|
{
|
||||||
await dingtalkApi.SendWorkMessageAsync(new JinkoSendWorkMessageRequest
|
await dingtalkApi.SendWorkMessageByWorkGridAsync(new JinkoSendWorkMessageRequest
|
||||||
{
|
{
|
||||||
Content = "你好,网格长,请看到消息后,前往人脸应用平台,执行明天的排班,已排班的请忽略!",
|
Content = "你好,网格长,请看到消息后,前往人脸应用平台,执行明天的排班,已排班的请忽略!",
|
||||||
WorkCodes = items.Select(x => x.LeaderUserCode).ToList()
|
WorkCodes = items.Select(x => x.LeaderUserCode).ToList()
|
||||||
|
|||||||
@@ -40,6 +40,8 @@ public class SyncOrganizationJob : BaseJob
|
|||||||
No = item.OBJID,
|
No = item.OBJID,
|
||||||
Name = item.STEXT,
|
Name = item.STEXT,
|
||||||
PNo = item.SOBID,
|
PNo = item.SOBID,
|
||||||
|
DepartmentNoFirst = item.ORGID03,
|
||||||
|
DepartmentNoSecond = item.ORGID04
|
||||||
};
|
};
|
||||||
|
|
||||||
await DbContext.InsertAsync(department);
|
await DbContext.InsertAsync(department);
|
||||||
@@ -48,6 +50,8 @@ public class SyncOrganizationJob : BaseJob
|
|||||||
{
|
{
|
||||||
department.PNo = item.SOBID;
|
department.PNo = item.SOBID;
|
||||||
department.Name = item.STEXT;
|
department.Name = item.STEXT;
|
||||||
|
department.DepartmentNoFirst = item.ORGID03;
|
||||||
|
department.DepartmentNoSecond = item.ORGID04;
|
||||||
|
|
||||||
await DbContext.UpdateAsync(department);
|
await DbContext.UpdateAsync(department);
|
||||||
}
|
}
|
||||||
|
|||||||
77
Src/Dlhis.ScheduledTask/Jobs/TipAppointmentExpireJob.cs
Normal file
77
Src/Dlhis.ScheduledTask/Jobs/TipAppointmentExpireJob.cs
Normal file
@@ -0,0 +1,77 @@
|
|||||||
|
using Dlhis.Basic.Api;
|
||||||
|
using Dlhis.Basic.Api.Requests;
|
||||||
|
using Dlhis.Entity.Visitor.Entity;
|
||||||
|
using Dlhis.Entity.Visitor.Enums;
|
||||||
|
using Dlhis.ScheduledTask.Attributes;
|
||||||
|
|
||||||
|
namespace Dlhis.ScheduledTask.Jobs;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 每天10点提醒访客预约到期
|
||||||
|
/// </summary>
|
||||||
|
[RecurringJob(nameof(TipAppointmentExpireJob), "0 0 10 * * ?", Name = "提醒到访人访客将要到期")]
|
||||||
|
public class TipAppointmentExpireJob : BaseJob
|
||||||
|
{
|
||||||
|
private readonly IDingTalkApi _dingTalkApi;
|
||||||
|
|
||||||
|
public TipAppointmentExpireJob(IServiceProvider serviceProvider, IDingTalkApi dingTalkApi) : base(serviceProvider)
|
||||||
|
{
|
||||||
|
_dingTalkApi = dingTalkApi;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override async Task RunAsync(IServiceProvider serviceProvider)
|
||||||
|
{
|
||||||
|
var details = await DbContext.Queryable<VisitorAppointmentDetailEntity>()
|
||||||
|
.Where(x => (x.IsEnterDoorArea && x.DoorStatus == VisitorAppointmentDetailStatusEnumType.Arrived) ||
|
||||||
|
(x.IsEnterWorkplace && x.WorkplaceStatus == VisitorAppointmentDetailStatusEnumType.Arrived))
|
||||||
|
.ToListAsync();
|
||||||
|
|
||||||
|
var warningDetails = new List<VisitorAppointmentDetailEntity>();
|
||||||
|
foreach (var detail in details)
|
||||||
|
{
|
||||||
|
if (IsWarningData(detail))
|
||||||
|
{
|
||||||
|
warningDetails.Add(detail);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (warningDetails.Any())
|
||||||
|
{
|
||||||
|
foreach (var item in warningDetails.GroupBy(x => x.No))
|
||||||
|
{
|
||||||
|
var appointment = await DbContext.Queryable<VisitorAppointmentEntity>()
|
||||||
|
.Where(x => x.No == item.Key)
|
||||||
|
.SingleAsync();
|
||||||
|
|
||||||
|
await _dingTalkApi.SendWorkMessageAsync(new JinkoSendWorkMessageRequest
|
||||||
|
{
|
||||||
|
WorkCodes = new List<string> { appointment.Code },
|
||||||
|
Content = $"您的访客预约 {appointment.No}《{appointment.Title}》中有访客即将到达访问结束时间,请及时处理。"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static bool IsWarningData(VisitorAppointmentDetailEntity detail)
|
||||||
|
{
|
||||||
|
var now = DateTime.Now.Date.AddDays(-3);
|
||||||
|
if (detail.IsEnterDoorArea
|
||||||
|
&& detail.DoorStatus == VisitorAppointmentDetailStatusEnumType.Arrived
|
||||||
|
&& detail.DoorEnd.Value.Date == now)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (detail.IsEnterWorkplace
|
||||||
|
&& detail.WorkplaceStatus == VisitorAppointmentDetailStatusEnumType.Arrived
|
||||||
|
&& detail.WorkplaceEnd.Value.Date <= now)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -76,87 +76,6 @@ public class AssignmentsController : ControllerBase
|
|||||||
await _assignmentService.UpdateDeviceTaskStatusAsync(requests);
|
await _assignmentService.UpdateDeviceTaskStatusAsync(requests);
|
||||||
}
|
}
|
||||||
|
|
||||||
[AllowAnonymous]
|
|
||||||
[HttpPost("balance/calc/{month:int}")]
|
|
||||||
[IgnoreTenant]
|
|
||||||
public async Task Calc([FromRoute] int month)
|
|
||||||
{
|
|
||||||
if (month is < 1 or > 12)
|
|
||||||
{
|
|
||||||
throw new UserFriendlyException("月份错误");
|
|
||||||
}
|
|
||||||
|
|
||||||
var s = new DateTime(2025, month, 1);
|
|
||||||
var e = new DateTime(2025, month + 1, 1);
|
|
||||||
|
|
||||||
var userCodes = await _dbContext.Queryable<UserBalanceEntity>()
|
|
||||||
.Where(x => SqlFunc.Subqueryable<UserBalanceTmpEntity>().Where(p => p.UserCode == x.UserCode).NotAny())
|
|
||||||
.Select(x => x.UserCode)
|
|
||||||
.Distinct()
|
|
||||||
.ToListAsync();
|
|
||||||
|
|
||||||
foreach (var userCode in userCodes)
|
|
||||||
{
|
|
||||||
if (!await _dbContext.Queryable<UserBalanceTmpEntity>().Where(x => x.UserCode == userCode).AnyAsync())
|
|
||||||
{
|
|
||||||
await _dbContext.InsertAsync(new UserBalanceTmpEntity
|
|
||||||
{
|
|
||||||
UserCode = userCode,
|
|
||||||
Balance = 0,
|
|
||||||
Version = 0
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
var balance = await _dbContext.Queryable<BalanceRecordEntity>()
|
|
||||||
.Where(x => x.UserCode == userCode)
|
|
||||||
.Where(x => x.Status == BalanceRecordStatusEnumType.Valid)
|
|
||||||
.Where(x => x.Type == BalanceRecordTypeEnumType.Out)
|
|
||||||
.Where(x => x.CostDate >= s && x.CostDate < e)
|
|
||||||
.Where(x => !BalanceRecordSourceConstants.IgnoreSources.Contains(x.Source))
|
|
||||||
.SumAsync(x => x.Amount);
|
|
||||||
|
|
||||||
await _dbContext.Updateable<UserBalanceTmpEntity>()
|
|
||||||
.SetColumns(x => x.Balance == balance)
|
|
||||||
.SetColumns(x => x.ModifiedTime == DateTime.Now)
|
|
||||||
.Where(x => x.UserCode == userCode)
|
|
||||||
.ExecuteCommandAsync();
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
// var userCodes = await _dbContext.Queryable<GainfoLeaveEntity>().Where(x => x.ResignationDate.HasValue && x.ResignationDate >= s && x.ResignationDate <= e)
|
|
||||||
// .Where(x => x.Type != GainfoUserTypeEnumType.External && x.Type != GainfoUserTypeEnumType.Outsource)
|
|
||||||
// .Select(x => x.Code)
|
|
||||||
// .Distinct()
|
|
||||||
// .ToListAsync();
|
|
||||||
//
|
|
||||||
// foreach (var userCode in userCodes)
|
|
||||||
// {
|
|
||||||
// if (!await _dbContext.Queryable<UserBalanceTmpEntity>().Where(x => x.UserCode == userCode).AnyAsync())
|
|
||||||
// {
|
|
||||||
// await _dbContext.InsertAsync(new UserBalanceTmpEntity
|
|
||||||
// {
|
|
||||||
// UserCode = userCode,
|
|
||||||
// Balance = 0,
|
|
||||||
// Version = 0
|
|
||||||
// });
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// var balance = await _dbContext.Queryable<BalanceRecordEntity>()
|
|
||||||
// .Where(x => x.UserCode == userCode)
|
|
||||||
// .Where(x => x.Status == BalanceRecordStatusEnumType.Valid)
|
|
||||||
// .Where(x => !BalanceRecordSourceConstants.IgnoreSources.Contains(x.Source))
|
|
||||||
// .Where(x => x.CostDate >= s && x.CostDate <= e)
|
|
||||||
// .Where(x => x.Type == BalanceRecordTypeEnumType.In)
|
|
||||||
// .SumAsync(x => x.Amount);
|
|
||||||
//
|
|
||||||
// await _dbContext.Updateable<UserBalanceTmpEntity>()
|
|
||||||
// .SetColumns(x => x.Balance == balance)
|
|
||||||
// .SetColumns(x => x.ModifiedTime == DateTime.Now)
|
|
||||||
// .Where(x => x.UserCode == userCode)
|
|
||||||
// .ExecuteCommandAsync();
|
|
||||||
// }
|
|
||||||
}
|
|
||||||
|
|
||||||
[Obsolete]
|
[Obsolete]
|
||||||
[AllowAnonymous]
|
[AllowAnonymous]
|
||||||
[IgnoreTenant]
|
[IgnoreTenant]
|
||||||
|
|||||||
Reference in New Issue
Block a user