diff --git a/Src/Dlhis.Canteen.Api/ITicketApi.cs b/Src/Dlhis.Canteen.Api/IVoucherApi.cs similarity index 64% rename from Src/Dlhis.Canteen.Api/ITicketApi.cs rename to Src/Dlhis.Canteen.Api/IVoucherApi.cs index 149b9826..3aabef3b 100644 --- a/Src/Dlhis.Canteen.Api/ITicketApi.cs +++ b/Src/Dlhis.Canteen.Api/IVoucherApi.cs @@ -4,13 +4,13 @@ namespace Dlhis.Canteen.Api; [RequestResultHandler] [EnableRemoteClient(Name = "canteen-service", BaseUrl = "${InternalRequest:CanteenRequestUrl}")] -public interface ITicketApi +public interface IVoucherApi { /// /// 创建券 /// /// - /// - [Post("/api/tickets/{type}/create")] - Task CreateAsync(string type); + /// s + [Post("/api/vouchers/birthday/create")] + Task CreateAsync(VoucherByBirthdayRequest request); } \ No newline at end of file diff --git a/Src/Dlhis.Canteen.Api/VoucherByBirthdayRequest.cs b/Src/Dlhis.Canteen.Api/VoucherByBirthdayRequest.cs new file mode 100644 index 00000000..e05df6d5 --- /dev/null +++ b/Src/Dlhis.Canteen.Api/VoucherByBirthdayRequest.cs @@ -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; } +} diff --git a/Src/Dlhis.Canteen/Order/Services/ConsumeHandlers/BirthdayConsumeHandler.cs b/Src/Dlhis.Canteen/Order/Services/ConsumeHandlers/BirthdayConsumeHandler.cs index dafafc7d..c00fd862 100644 --- a/Src/Dlhis.Canteen/Order/Services/ConsumeHandlers/BirthdayConsumeHandler.cs +++ b/Src/Dlhis.Canteen/Order/Services/ConsumeHandlers/BirthdayConsumeHandler.cs @@ -1,8 +1,10 @@ +using Dlhis.Basic.Api; using Dlhis.Canteen.Order.Repository; using Dlhis.Canteen.Order.Request; using Dlhis.Canteen.Order.Response; using Dlhis.Entity.Basic.Entity; using Dlhis.Entity.Canteen.Entities; +using Dlhis.Entity.Canteen.Entities.Voucher; using Dlhis.Entity.Canteen.Enums; using Kurisu.AspNetCore.DataAccess.SqlSugar.Extensions; using Kurisu.AspNetCore.DataAccess.SqlSugar.Services; @@ -22,64 +24,78 @@ public class BirthdayConsumeHandler : IConsumeHandler private readonly IDbContext _dbContext; private readonly IOrderCommonHandler _orderCommonHandler; private readonly IOrderRepository _orderRepository; + private readonly IFactorySettingApi _factorySettingApi; public BirthdayConsumeHandler(IDbContext dbContext, IOrderCommonHandler orderCommonHandler, - IOrderRepository orderRepository) + IOrderRepository orderRepository, + IFactorySettingApi factorySettingApi) { _dbContext = dbContext; _orderCommonHandler = orderCommonHandler; _orderRepository = orderRepository; + _factorySettingApi = factorySettingApi; } public async Task> ConsumeAsync(OrderAddRequest request, GainfoEntity gainfo) { var msg = string.Empty; - var ticketNo = request.UserUniqueNo; + var qrCode = request.UserUniqueNo; - var exists = await _dbContext.Queryable() - .Where(x => x.Type == TicketEnumType.Birthday) - .Where(x => x.QrCode == ticketNo) - .AnyAsync(); - - exists.ThrowIfFalse("生日券无效"); + var voucherQrCode = await _dbContext.Queryable() + .LeftJoin((x, u) => x.VoucherNo == u.VoucherNo) + .Where(x => x.QrCode == qrCode) + .Select((x, u) => new + { + x.VoucherNo, + u.UserCode, + u.Factory + }) + .SingleAsync(); + voucherQrCode.ThrowIfNull("生日券无效"); try { var checkData = await _orderCommonHandler.PreCheckAsync(request.DeviceUniqueNo, request.CostDateTime!.Value); - var isSupermarket = await _dbContext.Queryable() + var businessPlace = await _dbContext.Queryable() .Where(x => x.Code == checkData.BusinessPlaceCode) - .Select(x => x.Catalog == CanteenBusinessPlaceCatalogEnumType.Supermarket) + //.Select(x => x.Catalog == CanteenBusinessPlaceCatalogEnumType.Supermarket) .SingleAsync(); + businessPlace.ThrowIfNull("营业点不存在"); + var isSupermarket = businessPlace.Catalog == CanteenBusinessPlaceCatalogEnumType.Supermarket; isSupermarket.ThrowIfFalse("请在超市消费"); + var allowFactories = await _factorySettingApi.GetEnableUseBirthdayVoucherFactoriesAsync(voucherQrCode.Factory); + allowFactories.Contains(businessPlace.TenantId).ThrowIfFalse($"该厂区({businessPlace.TenantId})不可使用此生日券"); + var order = await _orderRepository.CreateDeviceConsumeOrderAsync(checkData, request.Adapt(), gainfo); await _orderCommonHandler.TryConsumeAsync(order.Id, async () => { await CommonHelper.RetryAsync(async () => { - var ticket = await _dbContext.Queryable() - .Where(x => x.Type == TicketEnumType.Birthday) - .Where(x => x.QrCode == ticketNo) + var voucher = await _dbContext.Queryable() + .Where(x => x.Type == VoucherEnumType.Birthday) + .Where(x => x.No == voucherQrCode.VoucherNo) .SingleAsync(); //金额+- - ticket.Balance += order.Amount; - (ticket.Balance < 0).ThrowIfTrue("余额不足,无法消费"); + voucher.Balance += order.Amount; + (voucher.Balance < 0).ThrowIfTrue("余额不足,无法消费"); - await _dbContext.Updateable() - .SetColumns(x => x.Balance == ticket.Balance) + await _dbContext.Updateable() + .SetColumns(x => x.Balance == voucher.Balance) .SetColumns(x => x.Version == x.Version + 1) .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(); //写入记录 var balanceRecord = order.Adapt(); - balanceRecord.Remark = $"{ticket.QrCode}(生日券消费)"; + balanceRecord.Remark = $"{voucher.No}(生日券消费)"; await _dbContext.InsertAsync(balanceRecord); + }, 5); }); } @@ -87,14 +103,15 @@ public class BirthdayConsumeHandler : IConsumeHandler { msg = ex.Message; } - + //获取餐券余额 - var data = await _dbContext.Queryable() - .LeftJoin((x, ga) => x.UserCode == ga.Code) - .Where(x => x.Type == TicketEnumType.Birthday && x.QrCode == ticketNo) - .Select((x, ga) => new OrderResultResponse + var data = await _dbContext.Queryable() + .LeftJoin((x, u) => x.No == u.VoucherNo) + .LeftJoin((x, u, ga) => u.UserCode == ga.Code) + .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, CurrentBalance = x.Balance }) diff --git a/Src/Dlhis.Canteen/Order/Services/ConsumeHandlers/EMealVoucherHandler.cs b/Src/Dlhis.Canteen/Order/Services/ConsumeHandlers/EMealVoucherHandler.cs index 86140edf..fecf22f4 100644 --- a/Src/Dlhis.Canteen/Order/Services/ConsumeHandlers/EMealVoucherHandler.cs +++ b/Src/Dlhis.Canteen/Order/Services/ConsumeHandlers/EMealVoucherHandler.cs @@ -3,6 +3,7 @@ using Dlhis.Canteen.Order.Request; using Dlhis.Canteen.Order.Response; using Dlhis.Entity.Basic.Entity; using Dlhis.Entity.Canteen.Entities; +using Dlhis.Entity.Canteen.Entities.EMealVoucher; using Dlhis.Entity.Canteen.Enums; using Kurisu.AspNetCore.DataAccess.SqlSugar.Extensions; using Kurisu.AspNetCore.DataAccess.SqlSugar.Services; diff --git a/Src/Dlhis.Canteen/Order/Services/ConsumeHandlers/OrderCommonHandler.cs b/Src/Dlhis.Canteen/Order/Services/ConsumeHandlers/OrderCommonHandler.cs index 08d5164e..9d300e37 100644 --- a/Src/Dlhis.Canteen/Order/Services/ConsumeHandlers/OrderCommonHandler.cs +++ b/Src/Dlhis.Canteen/Order/Services/ConsumeHandlers/OrderCommonHandler.cs @@ -8,6 +8,7 @@ using Dlhis.Entity.Device.Enums; using Kurisu.AspNetCore.CustomClass; using Kurisu.AspNetCore.DataAccess.SqlSugar.Services; using Kurisu.AspNetCore.Utils.Extensions; +using Microsoft.Extensions.Primitives; namespace Dlhis.Canteen.Order.Services.ConsumeHandlers; @@ -40,7 +41,8 @@ public class OrderCommonHandler : IOrderCommonHandler { 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().Where(x => x.UniqueNo == deviceNo).SingleAsync(); device.ConnectionInfo = new diff --git a/Src/Dlhis.Canteen/Order/Services/Implements/BalanceService.cs b/Src/Dlhis.Canteen/Order/Services/Implements/BalanceService.cs index d63c8e65..87bceaac 100644 --- a/Src/Dlhis.Canteen/Order/Services/Implements/BalanceService.cs +++ b/Src/Dlhis.Canteen/Order/Services/Implements/BalanceService.cs @@ -6,6 +6,7 @@ using Dlhis.Canteen.Setting.Services; using Dlhis.Constants; using Dlhis.Entity.Basic.Entity; using Dlhis.Entity.Canteen.Entities; +using Dlhis.Entity.Canteen.Entities.EMealVoucher; using Dlhis.Entity.Canteen.Enums; using Dlhis.Entity.Device; using Dlhis.Entity.Device.Entities; diff --git a/Src/Dlhis.Canteen/Order/Services/Implements/OrderService.cs b/Src/Dlhis.Canteen/Order/Services/Implements/OrderService.cs index 8d92bffa..2faf441f 100644 --- a/Src/Dlhis.Canteen/Order/Services/Implements/OrderService.cs +++ b/Src/Dlhis.Canteen/Order/Services/Implements/OrderService.cs @@ -6,6 +6,8 @@ using Dlhis.Canteen.Setting.Services; using Dlhis.Constants; using Dlhis.Entity.Basic.Entity; 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.Device; using Dlhis.Entity.Device.Entities; @@ -160,27 +162,35 @@ public class OrderService : IOrderService switch (flag) { case QrCodeConstants.User: - { - gainfo = await GetUserByQrCodeAsync(request.UserUniqueNo); - await CheckPermissionAsync(gainfo.Code, request.DeviceUniqueNo); - } + { + gainfo = await GetUserByQrCodeAsync(request.UserUniqueNo); + await CheckPermissionAsync(gainfo.Code, request.DeviceUniqueNo); + } break; case QrCodeConstants.EMealVoucher: - { - request.Source = BalanceRecordSourceEnumType.EMealVoucher; - var eMealVoucherQrCode = await _dbContext.Queryable().Where(x => x.QrCode == request.UserUniqueNo).SingleAsync(); - eMealVoucherQrCode.ThrowIfNull("无法识别"); - var code = eMealVoucherQrCode.OriginData.Split(':')[2]; - gainfo = await _dbContext.Queryable().Where(x => x.Code == code).SingleAsync(); - } + { + request.Source = BalanceRecordSourceEnumType.EMealVoucher; + var eMealVoucherQrCode = await _dbContext.Queryable().Where(x => x.QrCode == request.UserUniqueNo).SingleAsync(); + eMealVoucherQrCode.ThrowIfNull("无法识别"); + var code = eMealVoucherQrCode.OriginData.Split(':')[2]; + gainfo = await _dbContext.Queryable().Where(x => x.Code == code).SingleAsync(); + } break; case QrCodeConstants.Birthday: - { - request.Source = BalanceRecordSourceEnumType.Birthday; - var ticket = await _dbContext.Queryable().Where(x => x.Type == TicketEnumType.Birthday).Where(x => x.QrCode == request.UserUniqueNo).SingleAsync(); - ticket.ThrowIfNull("无法识别"); - gainfo = await _dbContext.Queryable().Where(x => x.Code == ticket.UserCode).SingleAsync(); - } + { + request.Source = BalanceRecordSourceEnumType.Birthday; + var qrcode = await _dbContext.Queryable() + .Where(x => x.QrCode == request.UserUniqueNo) + .SingleAsync(); + + qrcode.ThrowIfNull("券码无法识别"); + + var vourcher = await _dbContext.Queryable() + .Where(x => x.VoucherNo == qrcode.VoucherNo) + .SingleAsync(); + + gainfo = await _dbContext.Queryable().Where(x => x.Code == vourcher.UserCode).SingleAsync(); + } break; default: throw new UserFriendlyException($"无法识别{request.UserUniqueNo}"); @@ -201,7 +211,7 @@ public class OrderService : IOrderService //在线 if (!request.IsOffline) { - gainfo.ThrowIfNull("无法识别"); + gainfo.ThrowIfNull("无法识别人员信息"); } else { @@ -213,6 +223,7 @@ public class OrderService : IOrderService .FirstAsync(); } + gainfo.ThrowIfNull("无法识别人员信息"); return gainfo; } @@ -292,7 +303,9 @@ public class OrderService : IOrderService .Where(x => x.DeviceUniqueNo == request.DeviceUniqueNo && x.BusinessPlaceCode.HasValue) .Select((x, b, bs) => new { - b.Code, bs.ShiftCode, Factory = b.TenantId + b.Code, + bs.ShiftCode, + Factory = b.TenantId }) .SingleAsync(); @@ -485,7 +498,7 @@ public class OrderService : IOrderService return await _dbContext.Queryable().Where(x => x.Code == gainfoQrCode.UserCode).SingleAsync(); } - + /// /// 检查是否能够进行离线消费,处理hpt重复提交 /// diff --git a/Src/Dlhis.Canteen/Tickets/Controllers/TicketsController.cs b/Src/Dlhis.Canteen/Tickets/Controllers/TicketsController.cs deleted file mode 100644 index 9dfb8ae1..00000000 --- a/Src/Dlhis.Canteen/Tickets/Controllers/TicketsController.cs +++ /dev/null @@ -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; - -/// -/// 券 -/// -[Authorize] -[Route("api/[controller]")] -[ApiController] -public class TicketsController : ControllerBase -{ - private readonly INamedResolver _namedResolver; - - public TicketsController(INamedResolver namedResolver) - { - _namedResolver = namedResolver; - } - - /// - /// 获取分页数据(按券类型) - /// - /// - /// - [HttpGet("page")] - public async Task> GetPageAsync(TicketPageRequest request) - { - return await _namedResolver.GetService(request.Type.ToString()).GetPageAsync(request); - } - - /// - /// 创建券 - /// - /// 券类型,需要后端支持 - [AllowAnonymous] - [HttpPost("{type:required}/create")] - public async Task CreateAsync(string type) - { - var srv = _namedResolver.GetService(type); - srv.ThrowIfNull("不支持的券类型"); - - await srv.CreateAsync(); - } -} \ No newline at end of file diff --git a/Src/Dlhis.Canteen/Tickets/Request/TicketPageRequest.cs b/Src/Dlhis.Canteen/Tickets/Request/TicketPageRequest.cs deleted file mode 100644 index 02620a43..00000000 --- a/Src/Dlhis.Canteen/Tickets/Request/TicketPageRequest.cs +++ /dev/null @@ -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 -{ - /// - /// 类型 - /// - [EnumDataType(typeof(TicketEnumType))] - public TicketEnumType Type { get; set; } - - /// - /// 工号 - /// - public string UserCode { get; set; } -} \ No newline at end of file diff --git a/Src/Dlhis.Canteen/Tickets/Services/IBirthdayTicketService.cs b/Src/Dlhis.Canteen/Tickets/Services/IBirthdayTicketService.cs deleted file mode 100644 index 1b67cc3a..00000000 --- a/Src/Dlhis.Canteen/Tickets/Services/IBirthdayTicketService.cs +++ /dev/null @@ -1,6 +0,0 @@ -namespace Dlhis.Canteen.Tickets.Services; - -public interface IBirthdayTicketService : ITicketService -{ - -} \ No newline at end of file diff --git a/Src/Dlhis.Canteen/Tickets/Services/ITicketService.cs b/Src/Dlhis.Canteen/Tickets/Services/ITicketService.cs deleted file mode 100644 index bc8731f2..00000000 --- a/Src/Dlhis.Canteen/Tickets/Services/ITicketService.cs +++ /dev/null @@ -1,24 +0,0 @@ -using Dlhis.Canteen.Tickets.Request; -using Dlhis.Canteen.Tickets.Response; -using Kurisu.AspNetCore.DataAccess.Dto; - -namespace Dlhis.Canteen.Tickets.Services; - -/// -/// 券 -/// -public interface ITicketService : IScopeDependency -{ - /// - /// 分页数据 - /// - /// - /// - Task> GetPageAsync(TicketPageRequest request); - - /// - /// 创建 - /// - /// - Task CreateAsync(); -} \ No newline at end of file diff --git a/Src/Dlhis.Canteen/Tickets/Services/Implements/BirthdayTicketService.cs b/Src/Dlhis.Canteen/Tickets/Services/Implements/BirthdayTicketService.cs deleted file mode 100644 index 78bc5e07..00000000 --- a/Src/Dlhis.Canteen/Tickets/Services/Implements/BirthdayTicketService.cs +++ /dev/null @@ -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 -{ - /// - public BirthdayTicketService(IDbContext dbContext) : base(dbContext) - { - } - - /// - public override async Task CreateAsync() - { - await DbContext.IgnoreAsync(async () => - { - var today = DateTime.Today; - var userCodes = await DbContext.Queryable() - .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().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; - } -} \ No newline at end of file diff --git a/Src/Dlhis.Canteen/Tickets/Services/Implements/TicketService.cs b/Src/Dlhis.Canteen/Tickets/Services/Implements/TicketService.cs deleted file mode 100644 index 8af5da71..00000000 --- a/Src/Dlhis.Canteen/Tickets/Services/Implements/TicketService.cs +++ /dev/null @@ -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> GetPageAsync(TicketPageRequest request) - { - return await DbContext.Queryable() - .LeftJoin((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(); -} \ No newline at end of file diff --git a/Src/Dlhis.Canteen/EMealVoucher/Controllers/EMealVoucherController.cs b/Src/Dlhis.Canteen/Voucher/Controllers/EMealVoucherController.cs similarity index 94% rename from Src/Dlhis.Canteen/EMealVoucher/Controllers/EMealVoucherController.cs rename to Src/Dlhis.Canteen/Voucher/Controllers/EMealVoucherController.cs index 6a961cbb..1e8a8d04 100644 --- a/Src/Dlhis.Canteen/EMealVoucher/Controllers/EMealVoucherController.cs +++ b/Src/Dlhis.Canteen/Voucher/Controllers/EMealVoucherController.cs @@ -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.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.SqlSugar.Aop; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; -namespace Dlhis.Canteen.EMealVoucher.Controllers; +namespace Dlhis.Canteen.Voucher.Controllers; [Authorize] [Route("api/[controller]")] diff --git a/Src/Dlhis.Canteen/Voucher/Controllers/VoucherQrCodesController.cs b/Src/Dlhis.Canteen/Voucher/Controllers/VoucherQrCodesController.cs new file mode 100644 index 00000000..a608870a --- /dev/null +++ b/Src/Dlhis.Canteen/Voucher/Controllers/VoucherQrCodesController.cs @@ -0,0 +1,33 @@ +using Dlhis.Canteen.Voucher.Services; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; + +namespace Dlhis.Canteen.Voucher.Controllers; + +/// +/// 券二维码服务 +/// +[Authorize] +[ApiController] +[Route("api/[controller]")] +public class VoucherQrCodesController : ControllerBase +{ + private readonly IVoucherQrCodeService _voucherQrCodeService; + + public VoucherQrCodesController(IVoucherQrCodeService voucherQrCodeService) + { + _voucherQrCodeService = voucherQrCodeService; + } + + /// + /// 获取二维码 + /// + /// 券码 + /// true:请求刷新 + /// + [HttpGet] + public async Task GetQrCodeAsync(string voucherNo, bool isNeedRefresh = false) + { + return await _voucherQrCodeService.GetQrCodeAsync(voucherNo, isNeedRefresh); + } +} diff --git a/Src/Dlhis.Canteen/Voucher/Controllers/VouchersController.cs b/Src/Dlhis.Canteen/Voucher/Controllers/VouchersController.cs new file mode 100644 index 00000000..6b905a26 --- /dev/null +++ b/Src/Dlhis.Canteen/Voucher/Controllers/VouchersController.cs @@ -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; + +/// +/// 券 +/// +[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; + } + + /// + /// 获取分页数据(按券类型) + /// + /// + /// + [HttpGet("page")] + public async Task> GetPageAsync([FromQuery] VoucherPageRequest request) + { + return await _namedResolver.GetService(request.Type.ToString() + "VoucherService").GetPageAsync(request); + } + + + /// + /// 获取我的分页数据(按券类型)(H5) + /// + /// + /// + [HttpGet("my")] + public async Task> GetMyPageAsync([FromQuery] VoucherPageRequest request) + { + var userCode = _currentUser.GetUserClaim(UserClaimConstants.JinkoCode); + request.UserCode = userCode; + return await _namedResolver.GetService(request.Type.ToString()).GetPageAsync(request); + } + + + /// + /// 创建生日券 + /// + /// + [AllowAnonymous] + [HttpPost("birthday/create")] + public async Task CreateBirthdayVoucherAsync(VoucherByBirthdayRequest request) + { + var srv = _namedResolver.GetService(VoucherEnumType.Birthday.ToString() + "VoucherService"); + srv.ThrowIfNull("不支持的券类型"); + await srv.CreateAsync(new Dictionary + { + ["userCodes"] = request.UserCodes, + ["begin"] = request.Begin, + ["end"] = request.End, + ["remark"] = request.Remark + }); + } + + /// + /// 餐券消费分页 + /// + /// + /// + [HttpGet("balance/page")] + [IgnoreTenant] + public async Task> GetVoucherBalancePageAsync([FromQuery] VoucherBalancePageRequest request) + { + var srv = _namedResolver.GetService(request.Type.ToString() + "VoucherService"); + + return await srv.GetVoucherBalancePageAsync(request); + } + + /// + /// 我的餐券消费分页(H5) + /// + /// + /// + [HttpGet("balance/my/page")] + [IgnoreTenant] + public async Task> GetMyVoucherBalancePageAsync([FromQuery] VoucherBalancePageRequest request) + { + var srv = _namedResolver.GetService(request.Type.ToString()); + return await srv.GetVoucherBalancePageAsync(request); + } +} \ No newline at end of file diff --git a/Src/Dlhis.Canteen/EMealVoucher/Request/EMealVoucherPageRequest.cs b/Src/Dlhis.Canteen/Voucher/Requests/EMealVoucherPageRequest.cs similarity index 92% rename from Src/Dlhis.Canteen/EMealVoucher/Request/EMealVoucherPageRequest.cs rename to Src/Dlhis.Canteen/Voucher/Requests/EMealVoucherPageRequest.cs index 6dbcde84..4fe64f7a 100644 --- a/Src/Dlhis.Canteen/EMealVoucher/Request/EMealVoucherPageRequest.cs +++ b/Src/Dlhis.Canteen/Voucher/Requests/EMealVoucherPageRequest.cs @@ -2,7 +2,7 @@ using System.ComponentModel.DataAnnotations; using Kurisu.AspNetCore.CustomClass; using Kurisu.AspNetCore.DataAccess.Dto; -namespace Dlhis.Canteen.EMealVoucher.Request; +namespace Dlhis.Canteen.Voucher.Requests; public class EMealVoucherPageRequest : PageDto, IValidatableObject { diff --git a/Src/Dlhis.Canteen/Voucher/Requests/VoucherBalancePageRequest.cs b/Src/Dlhis.Canteen/Voucher/Requests/VoucherBalancePageRequest.cs new file mode 100644 index 00000000..ec84c447 --- /dev/null +++ b/Src/Dlhis.Canteen/Voucher/Requests/VoucherBalancePageRequest.cs @@ -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 +{ + /// + /// 券类型 VoucherEnumType + /// + [EnumDataType(typeof(VoucherEnumType))] + public VoucherEnumType Type { get; set; } + + public string UserCode { get; set; } + + public DateTimePeriod SearchDateTimePeriod { get; set; } +} diff --git a/Src/Dlhis.Canteen/Voucher/Requests/VoucherByBirthdayRequest.cs b/Src/Dlhis.Canteen/Voucher/Requests/VoucherByBirthdayRequest.cs new file mode 100644 index 00000000..3543653b --- /dev/null +++ b/Src/Dlhis.Canteen/Voucher/Requests/VoucherByBirthdayRequest.cs @@ -0,0 +1,28 @@ + +using System.ComponentModel.DataAnnotations; + +namespace Dlhis.Basic.Vouchers.Request; + +public class VoucherByBirthdayRequest +{ + /// + /// 支持指定工号 + /// + public List UserCodes { get; set; } + + /// + /// 开始范围 + /// + public DateTime Begin { get; set; } + + /// + /// 结束范围 + /// + public DateTime End { get; set; } + + /// + /// 备注 + /// + [Required(ErrorMessage = "请填写备注")] + public string Remark { get; set; } +} diff --git a/Src/Dlhis.Canteen/Voucher/Requests/VoucherPageRequest.cs b/Src/Dlhis.Canteen/Voucher/Requests/VoucherPageRequest.cs new file mode 100644 index 00000000..ff0dab33 --- /dev/null +++ b/Src/Dlhis.Canteen/Voucher/Requests/VoucherPageRequest.cs @@ -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 +{ + /// + /// 类型 VoucherEnumType + /// + [EnumDataType(typeof(VoucherEnumType))] + public VoucherEnumType Type { get; set; } + + /// + /// 工号 + /// + public string UserCode { get; set; } + + /// + /// 查询日期区间 + /// + public DateTimePeriod SearchDateTimePeriod { get; set; } + + /// + /// 一级部门 + /// + public string DepartmentNoFirst { get; set; } + + /// + /// 二级部门 + /// + public string DepartmentNoSecond { get; set; } +} \ No newline at end of file diff --git a/Src/Dlhis.Canteen/EMealVoucher/Response/EMealVoucherDetailResponse.cs b/Src/Dlhis.Canteen/Voucher/Response/EMealVoucherDetailResponse.cs similarity index 93% rename from Src/Dlhis.Canteen/EMealVoucher/Response/EMealVoucherDetailResponse.cs rename to Src/Dlhis.Canteen/Voucher/Response/EMealVoucherDetailResponse.cs index c185c7b2..b35b5cb8 100644 --- a/Src/Dlhis.Canteen/EMealVoucher/Response/EMealVoucherDetailResponse.cs +++ b/Src/Dlhis.Canteen/Voucher/Response/EMealVoucherDetailResponse.cs @@ -1,4 +1,4 @@ -namespace Dlhis.Canteen.EMealVoucher.Response; +namespace Dlhis.Canteen.Voucher.Response; public class EMealVoucherDetailResponse { diff --git a/Src/Dlhis.Canteen/EMealVoucher/Response/EMealVoucherMyPageResponse.cs b/Src/Dlhis.Canteen/Voucher/Response/EMealVoucherMyPageResponse.cs similarity index 81% rename from Src/Dlhis.Canteen/EMealVoucher/Response/EMealVoucherMyPageResponse.cs rename to Src/Dlhis.Canteen/Voucher/Response/EMealVoucherMyPageResponse.cs index 5769bbc0..0d222479 100644 --- a/Src/Dlhis.Canteen/EMealVoucher/Response/EMealVoucherMyPageResponse.cs +++ b/Src/Dlhis.Canteen/Voucher/Response/EMealVoucherMyPageResponse.cs @@ -1,4 +1,4 @@ -namespace Dlhis.Canteen.EMealVoucher.Response; +namespace Dlhis.Canteen.Voucher.Response; public class EMealVoucherMyPageResponse { diff --git a/Src/Dlhis.Canteen/EMealVoucher/Response/EMealVoucherPageResponse.cs b/Src/Dlhis.Canteen/Voucher/Response/EMealVoucherPageResponse.cs similarity index 94% rename from Src/Dlhis.Canteen/EMealVoucher/Response/EMealVoucherPageResponse.cs rename to Src/Dlhis.Canteen/Voucher/Response/EMealVoucherPageResponse.cs index 0cd8428d..b7085c88 100644 --- a/Src/Dlhis.Canteen/EMealVoucher/Response/EMealVoucherPageResponse.cs +++ b/Src/Dlhis.Canteen/Voucher/Response/EMealVoucherPageResponse.cs @@ -3,7 +3,7 @@ using Kurisu.AspNetCore.Utils.Extensions; using Mapster.Utils; using Newtonsoft.Json; -namespace Dlhis.Canteen.EMealVoucher.Response; +namespace Dlhis.Canteen.Voucher.Response; public class EMealVoucherPageResponse { @@ -65,7 +65,7 @@ public class EMealVoucherPageResponse { get { - var a = CurrentShifts.ToObject>().Select(x => ((ShiftEnumType)(x * 10))).ToList(); + var a = CurrentShifts.ToObject>().Select(x => (ShiftEnumType)(x * 10)).ToList(); return a.Select(x=>x.GetDescription()).ToList(); } } diff --git a/Src/Dlhis.Canteen/Voucher/Response/VoucherBalancePageResponse.cs b/Src/Dlhis.Canteen/Voucher/Response/VoucherBalancePageResponse.cs new file mode 100644 index 00000000..bf975702 --- /dev/null +++ b/Src/Dlhis.Canteen/Voucher/Response/VoucherBalancePageResponse.cs @@ -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; } + + /// + /// 流水号 + /// + public string No { get; set; } + + /// + /// 档案号/QRCode + /// + public string UserNo { get; set; } + + /// + /// 姓名 + /// + public string Name { get; set; } + + /// + /// 学工号 + /// + public string UserCode { get; set; } + + /// + /// 部门号 + /// + public string DepartmentNo { get; set; } + + /// + /// 部门 + /// + public string DepartmentName { get; set; } + + /// + /// 所属成本日期 + /// + [JsonConverter(typeof(ToDateJsonConverter))] + public DateTime CostDate { get; set; } + + /// + /// 备注 + /// + public string Remark { get; set; } + + /// + /// 来源 + /// + public BalanceRecordSourceEnumType Source { get; set; } + + /// + /// 消费识别来源 + /// + public string SourceDesc => Source.GetDescription(); + + /// + /// 收入/支出 + /// + public BalanceRecordTypeEnumType Type { get; set; } + + public string TypeDesc => Type.GetDescription(); + + /// + /// 金额 + /// + public decimal Amount { get; set; } + + /// + /// 营业点 + /// + public string BusinessPlaceName { get; set; } + + /// + /// 餐次 + /// + public ShiftEnumType? ShiftType { get; set; } + + /// + /// 餐次 + /// + public string ShiftTypeDesc => ShiftType?.GetDescription(); + + /// + /// 消费机器唯一信息 + /// + public string DeviceInfo { get; set; } + + /// + /// 成本中心 + /// + public string CostId { get; set; } + + /// + /// 消费者所在基地 + /// + public string OriginTenantId { get; set; } + + /// + /// 数据状态 + /// + public BalanceRecordStatusEnumType Status { get; set; } + + /// + /// 数据状态描述 + /// + public string StatusDesc => Status.GetDescription(); + + /// + /// 记录产生时间 + /// + public DateTime CostDateTime { get; set; } + + /// + /// 厂区 + /// + public string Factory { get; set; } + + /// + /// 人事范围 + /// + public string Werks { get; set; } +} diff --git a/Src/Dlhis.Canteen/Tickets/Response/TicketPageResponse.cs b/Src/Dlhis.Canteen/Voucher/Response/VoucherPageResponse.cs similarity index 50% rename from Src/Dlhis.Canteen/Tickets/Response/TicketPageResponse.cs rename to Src/Dlhis.Canteen/Voucher/Response/VoucherPageResponse.cs index b7be7bc6..a623c07e 100644 --- a/Src/Dlhis.Canteen/Tickets/Response/TicketPageResponse.cs +++ b/Src/Dlhis.Canteen/Voucher/Response/VoucherPageResponse.cs @@ -1,13 +1,13 @@ using Dlhis.Entity.Canteen.Enums; -namespace Dlhis.Canteen.Tickets.Response; +namespace Dlhis.Canteen.Voucher.Response; -public class TicketPageResponse +public class VoucherPageResponse { /// /// 券类型 /// - public TicketEnumType Type { get; set; } + public VoucherEnumType Type { get; set; } /// /// 工号 @@ -30,12 +30,27 @@ public class TicketPageResponse public decimal Amount { get; set; } /// - /// 消费码 + /// 描述 /// - public string QrCode { get; set; } + public string Description { 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; } } \ No newline at end of file diff --git a/Src/Dlhis.Canteen/EMealVoucher/Services/IEMealVoucherService.cs b/Src/Dlhis.Canteen/Voucher/Services/IEMealVoucherService.cs similarity index 85% rename from Src/Dlhis.Canteen/EMealVoucher/Services/IEMealVoucherService.cs rename to Src/Dlhis.Canteen/Voucher/Services/IEMealVoucherService.cs index 3c4fc174..7982fec0 100644 --- a/Src/Dlhis.Canteen/EMealVoucher/Services/IEMealVoucherService.cs +++ b/Src/Dlhis.Canteen/Voucher/Services/IEMealVoucherService.cs @@ -1,11 +1,11 @@ -using Dlhis.Canteen.EMealVoucher.Request; -using Dlhis.Canteen.EMealVoucher.Response; using Dlhis.Canteen.Order.Request; using Dlhis.Canteen.Order.Response; +using Dlhis.Canteen.Voucher.Requests; +using Dlhis.Canteen.Voucher.Response; using Kurisu.AspNetCore.DataAccess.Dto; using Microsoft.AspNetCore.Mvc; -namespace Dlhis.Canteen.EMealVoucher.Services; +namespace Dlhis.Canteen.Voucher.Services; public interface IEMealVoucherService : IScopeDependency { diff --git a/Src/Dlhis.Canteen/Voucher/Services/IVoucherQrCodeService.cs b/Src/Dlhis.Canteen/Voucher/Services/IVoucherQrCodeService.cs new file mode 100644 index 00000000..edbe47d4 --- /dev/null +++ b/Src/Dlhis.Canteen/Voucher/Services/IVoucherQrCodeService.cs @@ -0,0 +1,13 @@ +namespace Dlhis.Canteen.Voucher.Services; + +public interface IVoucherQrCodeService +{ + + /// + /// 获取二维码 + /// + /// + /// + /// + Task GetQrCodeAsync(string voucherNo, bool isNeedRefresh = false); +} diff --git a/Src/Dlhis.Canteen/Voucher/Services/IVoucherService.cs b/Src/Dlhis.Canteen/Voucher/Services/IVoucherService.cs new file mode 100644 index 00000000..1ad09b15 --- /dev/null +++ b/Src/Dlhis.Canteen/Voucher/Services/IVoucherService.cs @@ -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; + +/// +/// 券 +/// +public interface IVoucherService : IScopeDependency +{ + /// + /// 分页数据 + /// + /// + /// + Task> GetPageAsync(VoucherPageRequest request); + + /// + /// 创建 + /// + /// + Task CreateAsync(Dictionary pairs); + + + Task> GetVoucherBalancePageAsync(VoucherBalancePageRequest request); +} \ No newline at end of file diff --git a/Src/Dlhis.Canteen/Voucher/Services/Implements/BaseVoucherService.cs b/Src/Dlhis.Canteen/Voucher/Services/Implements/BaseVoucherService.cs new file mode 100644 index 00000000..e0222840 --- /dev/null +++ b/Src/Dlhis.Canteen/Voucher/Services/Implements/BaseVoucherService.cs @@ -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> GetPageAsync(VoucherPageRequest request) + { + var pagination = await DbContext.Queryable() + .LeftJoin((x, u) => x.No == u.VoucherNo) + .LeftJoin((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 + { + x.DepartmentNo, + x.DepartmentNoFirst, + x.DepartmentNoSecond + }; + }).Distinct().ToList(); + + var departments = await DbContext.Queryable().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 pairs); + public abstract Task> GetVoucherBalancePageAsync(VoucherBalancePageRequest request); +} \ No newline at end of file diff --git a/Src/Dlhis.Canteen/Voucher/Services/Implements/BirthdayVoucherService.cs b/Src/Dlhis.Canteen/Voucher/Services/Implements/BirthdayVoucherService.cs new file mode 100644 index 00000000..e878e34e --- /dev/null +++ b/Src/Dlhis.Canteen/Voucher/Services/Implements/BirthdayVoucherService.cs @@ -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; + + /// + public BirthdayVoucherService(IDbContext dbContext, IFactorySettingApi factorySettingApi) : base(dbContext) + { + _factorySettingApi = factorySettingApi; + } + + /// + public override async Task CreateAsync(Dictionary 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 : new List(); + + //忽略tenant操作 + await DbContext.IgnoreAsync(async () => + { + var gainfos = await GetGainfosAsync(userCodes, p.begin, p.end); + var departmentNos = gainfos.Select(g => g.DepartmentNo).Distinct().ToList(); + var departmentInfos = await DbContext.Queryable() + .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 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() + .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 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> GetGainfosAsync(List 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() + .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); + } + + /// + /// 计算给定生日在区间 [begin, end] 内出现的所有年份(可能为0、1或多个)。 + /// - 对于每个候选年份构造安全的日期(处理 2/29 在非闰年的情况,退到当年最大天数)。 + /// - 若区间内找不到匹配年份,则返回包含 begin.Year 的单元素列表作为兜底行为,保持向后兼容。 + /// + private static List GetBirthdayYears(DateTime birthday, DateTime begin, DateTime end) + { + var years = new List(); + + // 扩展范围到 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> GetVoucherBalancePageAsync(VoucherBalancePageRequest request) + { + return await DbContext.Queryable() + .LeftJoin((x, bPlace) => x.BusinessPlaceCode == bPlace.Code) + .LeftJoin((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); + } +} \ No newline at end of file diff --git a/Src/Dlhis.Canteen/EMealVoucher/Services/Implements/EMealVoucherService.cs b/Src/Dlhis.Canteen/Voucher/Services/Implements/EMealVoucherService.cs similarity index 97% rename from Src/Dlhis.Canteen/EMealVoucher/Services/Implements/EMealVoucherService.cs rename to Src/Dlhis.Canteen/Voucher/Services/Implements/EMealVoucherService.cs index 9bb4b838..7c3cf576 100644 --- a/Src/Dlhis.Canteen/EMealVoucher/Services/Implements/EMealVoucherService.cs +++ b/Src/Dlhis.Canteen/Voucher/Services/Implements/EMealVoucherService.cs @@ -1,11 +1,12 @@ using System.Text; -using Dlhis.Canteen.EMealVoucher.Request; -using Dlhis.Canteen.EMealVoucher.Response; using Dlhis.Canteen.Order.Request; using Dlhis.Canteen.Order.Response; +using Dlhis.Canteen.Voucher.Requests; +using Dlhis.Canteen.Voucher.Response; using Dlhis.Constants; using Dlhis.Entity.Basic.Entity; using Dlhis.Entity.Canteen.Entities; +using Dlhis.Entity.Canteen.Entities.EMealVoucher; using Dlhis.Entity.Canteen.Enums; using Kurisu.AspNetCore.Authentication.Abstractions; using Kurisu.AspNetCore.CustomClass; @@ -15,7 +16,7 @@ using Kurisu.AspNetCore.DataAccess.SqlSugar.Services; using Kurisu.AspNetCore.Utils.Extensions; using SqlSugar; -namespace Dlhis.Canteen.EMealVoucher.Services.Implements; +namespace Dlhis.Canteen.Voucher.Services.Implements; public class EMealVoucherService : IEMealVoucherService { diff --git a/Src/Dlhis.Canteen/Voucher/Services/Implements/VoucherQrCodeService.cs b/Src/Dlhis.Canteen/Voucher/Services/Implements/VoucherQrCodeService.cs new file mode 100644 index 00000000..7b2fb713 --- /dev/null +++ b/Src/Dlhis.Canteen/Voucher/Services/Implements/VoucherQrCodeService.cs @@ -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 GetQrCodeAsync(string voucherNo, bool isNeedRefresh = false) + { + var userCode = _currentUser.GetUserClaim(UserClaimConstants.JinkoCode); + if (!await _dbContext.Queryable().Where(x => x.VoucherNo == voucherNo && x.UserCode == userCode).AnyAsync()) + { + true.ThrowIfTrue("非法的消费券"); + } + + var qrcodeInfo = await _dbContext.Queryable().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; + } + + + /// + /// qrCode生成 + /// + /// + /// + 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; + } +} diff --git a/Src/Dlhis.Entity/Basic/Entity/DepartmentEntity.cs b/Src/Dlhis.Entity/Basic/Entity/DepartmentEntity.cs index 270793d5..a177074c 100644 --- a/Src/Dlhis.Entity/Basic/Entity/DepartmentEntity.cs +++ b/Src/Dlhis.Entity/Basic/Entity/DepartmentEntity.cs @@ -26,5 +26,17 @@ namespace Dlhis.Entity.Basic.Entity /// [SugarColumn(IsNullable = false, ColumnDescription = "部门名称")] public string Name { get; set; } + + /// + /// 部门编码 + /// + [SugarColumn(IsNullable = true, ColumnDescription = "一级部门编码")] + public string DepartmentNoFirst { get; set; } + + /// + /// 部门编码 + /// + [SugarColumn(IsNullable = true, ColumnDescription = "二级部门编码")] + public string DepartmentNoSecond { get; set; } } } \ No newline at end of file diff --git a/Src/Dlhis.Entity/Basic/Entity/OutsourceWhiteListEntity.cs b/Src/Dlhis.Entity/Basic/Entity/OutsourceWhiteListEntity.cs new file mode 100644 index 00000000..4c6cd27a --- /dev/null +++ b/Src/Dlhis.Entity/Basic/Entity/OutsourceWhiteListEntity.cs @@ -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; } +} diff --git a/Src/Dlhis.Entity/Canteen/Entities/EMealVoucherDetailEntity.cs b/Src/Dlhis.Entity/Canteen/Entities/EMealVoucher/EMealVoucherDetailEntity.cs similarity index 97% rename from Src/Dlhis.Entity/Canteen/Entities/EMealVoucherDetailEntity.cs rename to Src/Dlhis.Entity/Canteen/Entities/EMealVoucher/EMealVoucherDetailEntity.cs index 52816945..2a9b8d2d 100644 --- a/Src/Dlhis.Entity/Canteen/Entities/EMealVoucherDetailEntity.cs +++ b/Src/Dlhis.Entity/Canteen/Entities/EMealVoucher/EMealVoucherDetailEntity.cs @@ -2,7 +2,7 @@ using Kurisu.AspNetCore.DataAccess.SqlSugar; using SqlSugar; -namespace Dlhis.Entity.Canteen.Entities; +namespace Dlhis.Entity.Canteen.Entities.EMealVoucher; /// /// 电子餐券明细 diff --git a/Src/Dlhis.Entity/Canteen/Entities/EMealVoucherDetailQrCodeEntity.cs b/Src/Dlhis.Entity/Canteen/Entities/EMealVoucher/EMealVoucherDetailQrCodeEntity.cs similarity index 94% rename from Src/Dlhis.Entity/Canteen/Entities/EMealVoucherDetailQrCodeEntity.cs rename to Src/Dlhis.Entity/Canteen/Entities/EMealVoucher/EMealVoucherDetailQrCodeEntity.cs index b1a6b505..1f0216a8 100644 --- a/Src/Dlhis.Entity/Canteen/Entities/EMealVoucherDetailQrCodeEntity.cs +++ b/Src/Dlhis.Entity/Canteen/Entities/EMealVoucher/EMealVoucherDetailQrCodeEntity.cs @@ -1,7 +1,7 @@ using Kurisu.AspNetCore.DataAccess.SqlSugar; using SqlSugar; -namespace Dlhis.Entity.Canteen.Entities; +namespace Dlhis.Entity.Canteen.Entities.EMealVoucher; /// /// 电子餐券明细QrCode diff --git a/Src/Dlhis.Entity/Canteen/Entities/EMealVoucherEntity.cs b/Src/Dlhis.Entity/Canteen/Entities/EMealVoucher/EMealVoucherEntity.cs similarity index 97% rename from Src/Dlhis.Entity/Canteen/Entities/EMealVoucherEntity.cs rename to Src/Dlhis.Entity/Canteen/Entities/EMealVoucher/EMealVoucherEntity.cs index e015507c..c7d3b875 100644 --- a/Src/Dlhis.Entity/Canteen/Entities/EMealVoucherEntity.cs +++ b/Src/Dlhis.Entity/Canteen/Entities/EMealVoucher/EMealVoucherEntity.cs @@ -2,7 +2,7 @@ using Kurisu.AspNetCore.DataAccess.SqlSugar; using SqlSugar; -namespace Dlhis.Entity.Canteen.Entities; +namespace Dlhis.Entity.Canteen.Entities.EMealVoucher; /// /// 餐券 diff --git a/Src/Dlhis.Entity/Canteen/Entities/UserBalanceTmpEntity.cs b/Src/Dlhis.Entity/Canteen/Entities/UserBalanceTmpEntity.cs deleted file mode 100644 index 1fb925ec..00000000 --- a/Src/Dlhis.Entity/Canteen/Entities/UserBalanceTmpEntity.cs +++ /dev/null @@ -1,28 +0,0 @@ -using Kurisu.AspNetCore.DataAccess.Entity; -using Kurisu.AspNetCore.DataAccess.SqlSugar; -using SqlSugar; - -namespace Dlhis.Entity.Canteen.Entities; - -/// -/// 用户余额表 -/// -[SugarTable(TableName = "UserBalanceTmp", TableDescription = "用户余额表")] -public class UserBalanceTmpEntity : SugarBaseEntity, IVersion -{ - /// - /// 学工号 - /// - [SugarColumn(IsNullable = false, ColumnDescription = "学工号", UniqueGroupNameList = new[] { "idx_UserBalances_useCode" })] - public string UserCode { get; set; } - - /// - /// 余额 - /// - [SugarColumn(IsNullable = false, ColumnDescription = "余额")] - public decimal Balance { get; set; } - - - [SugarColumn(IsNullable = false)] - public int Version { get; set; } -} \ No newline at end of file diff --git a/Src/Dlhis.Entity/Canteen/Entities/UserBalanceUploadRecordEntity.cs b/Src/Dlhis.Entity/Canteen/Entities/UserBalanceUploadRecordEntity.cs new file mode 100644 index 00000000..7d81c52e --- /dev/null +++ b/Src/Dlhis.Entity/Canteen/Entities/UserBalanceUploadRecordEntity.cs @@ -0,0 +1,35 @@ +using Kurisu.AspNetCore.DataAccess.SqlSugar; +using SqlSugar; + +namespace Dlhis.Entity.Canteen.Entities; + +/// +/// 用户消费上传记录表 +/// +[SugarTable(TableName = "UserBalanceUploadRecords", TableDescription = "用户消费上传记录表")] +public class UserBalanceUploadRecordEntity : SugarBaseEntity +{ + /// + /// 年份 + /// + [SugarColumn(IsNullable = false, ColumnDescription = "年份")] + public int Year { get; set; } + + /// + /// 月份 + /// + [SugarColumn(IsNullable = false, ColumnDescription = "月份")] + public int Month { get; set; } + + /// + /// 学工号 + /// + [SugarColumn(IsNullable = false, ColumnDescription = "学工号", UniqueGroupNameList = new[] { "idx_UserBalances_useCode" })] + public string UserCode { get; set; } + + /// + /// 消费 + /// + [SugarColumn(IsNullable = false, ColumnDescription = "余额")] + public decimal Cost { get; set; } +} \ No newline at end of file diff --git a/Src/Dlhis.Entity/Canteen/Entities/TicketEntity.cs b/Src/Dlhis.Entity/Canteen/Entities/Voucher/VoucherEntity.cs similarity index 64% rename from Src/Dlhis.Entity/Canteen/Entities/TicketEntity.cs rename to Src/Dlhis.Entity/Canteen/Entities/Voucher/VoucherEntity.cs index 451b7ba4..1ae1af6b 100644 --- a/Src/Dlhis.Entity/Canteen/Entities/TicketEntity.cs +++ b/Src/Dlhis.Entity/Canteen/Entities/Voucher/VoucherEntity.cs @@ -4,25 +4,30 @@ using Kurisu.AspNetCore.DataAccess.SqlSugar; using SqlSugar; using SqlSugar.DbConvert; -namespace Dlhis.Entity.Canteen.Entities; +namespace Dlhis.Entity.Canteen.Entities.Voucher; /// /// 券 /// -[SugarTable("Tickets", TableDescription = "券")] -public class TicketEntity : SugarBaseEntity, ITenantId, IVersion +[SugarTable("Vouchers", TableDescription = "券")] +public class VoucherEntity : SugarBaseEntity, IVersion { + /// + /// 券唯一标识 + /// + [SugarColumn(IsNullable = false, ColumnDescription = "券唯一标识")] + public string No { get; set; } + + /// + /// 获取日期时间 + /// + public DateTime ClaimDateTime { get; set; } + /// /// 类型 /// [SugarColumn(IsNullable = false, ColumnDataType = "varchar(50)", ColumnDescription = "券类型", SqlParameterDbType = typeof(EnumToStringConvert))] - public TicketEnumType Type { get; set; } - - /// - /// 工号 - /// - [SugarColumn(IsNullable = false, ColumnDescription = "工号")] - public string UserCode { get; set; } + public VoucherEnumType Type { get; set; } /// /// 初始余额 @@ -37,10 +42,10 @@ public class TicketEntity : SugarBaseEntity, ITenantId, IVersion public decimal Balance { get; set; } /// - /// 消费码 + /// 描述 /// - [SugarColumn(IsNullable = false, ColumnDescription = "消费码")] - public string QrCode { get; set; } + [SugarColumn(IsNullable = true, ColumnDescription = "描述")] + public string Description { get; set; } /// /// 备注 @@ -48,8 +53,5 @@ public class TicketEntity : SugarBaseEntity, ITenantId, IVersion [SugarColumn(IsNullable = true, ColumnDescription = "备注")] public string Remark { get; set; } - public string TenantId { get; set; } - - /// public int Version { get; set; } } \ No newline at end of file diff --git a/Src/Dlhis.Entity/Canteen/Entities/Voucher/VoucherQrCodeEntity.cs b/Src/Dlhis.Entity/Canteen/Entities/Voucher/VoucherQrCodeEntity.cs new file mode 100644 index 00000000..12fa83c8 --- /dev/null +++ b/Src/Dlhis.Entity/Canteen/Entities/Voucher/VoucherQrCodeEntity.cs @@ -0,0 +1,20 @@ +using Kurisu.AspNetCore.DataAccess.SqlSugar; +using SqlSugar; + +namespace Dlhis.Entity.Canteen.Entities.Voucher; + +[SugarTable(TableName = "VoucherQrCodes")] +public class VoucherQrCodeEntity : SugarBaseEntity +{ + /// + /// 券No + /// + [SugarColumn(ColumnDescription = "券No")] + public string VoucherNo { get; set; } + + /// + /// 二维码 + /// + [SugarColumn(ColumnDescription = "二维码", UniqueGroupNameList = new[] { "idx_EMealVoucherDetailQrCode_qrcode" })] + public string QrCode { get; set; } +} diff --git a/Src/Dlhis.Entity/Canteen/Entities/Voucher/VoucherUserInfoEntity.cs b/Src/Dlhis.Entity/Canteen/Entities/Voucher/VoucherUserInfoEntity.cs new file mode 100644 index 00000000..54874fc7 --- /dev/null +++ b/Src/Dlhis.Entity/Canteen/Entities/Voucher/VoucherUserInfoEntity.cs @@ -0,0 +1,63 @@ +using Kurisu.AspNetCore.DataAccess.SqlSugar; +using SqlSugar; + +namespace Dlhis.Entity.Canteen.Entities.Voucher; + +/// +/// 券发放时候关联的用户信息 +/// +[SugarTable(TableName = "VoucherUserInfos")] +public class VoucherUserInfoEntity : SugarBaseEntity +{ + /// + /// 券码 + /// + [SugarColumn(IsNullable = false)] + public string VoucherNo { get; set; } + + /// + /// 工号 + /// + [SugarColumn(IsNullable = false, ColumnDescription = "工号")] + public string UserCode { get; set; } + + /// + /// 成本中心 + /// + [SugarColumn(IsNullable = false)] + public string CostId { get; set; } + + /// + /// 人事范围 + /// + [SugarColumn(IsNullable = false)] + public string Werks { get; set; } + + /// + /// 厂区 + /// + [SugarColumn(IsNullable = false)] + public string Factory { get; set; } + + /// + /// 当前部门 + /// + [SugarColumn(IsNullable = false)] + public string DepartmentNo { get; set; } + + /// + /// 一级部门 + /// + [SugarColumn(IsNullable = false)] + public string DepartmentNoFirst { get; set; } + + /// + /// 二级部门 + /// + [SugarColumn(IsNullable = true)] + public string DepartmentNoSecond { get; set; } + + + [SugarColumn(IsNullable = true, ColumnDataType = "varchar(255)")] + public string Signature { get; set; } +} diff --git a/Src/Dlhis.Entity/Canteen/Enums/TicketEnumType.cs b/Src/Dlhis.Entity/Canteen/Enums/VoucherEnumType.cs similarity index 89% rename from Src/Dlhis.Entity/Canteen/Enums/TicketEnumType.cs rename to Src/Dlhis.Entity/Canteen/Enums/VoucherEnumType.cs index 3df284e2..36e69470 100644 --- a/Src/Dlhis.Entity/Canteen/Enums/TicketEnumType.cs +++ b/Src/Dlhis.Entity/Canteen/Enums/VoucherEnumType.cs @@ -6,7 +6,7 @@ namespace Dlhis.Entity.Canteen.Enums; /// 券类型 /// [Description("券类型")] -public enum TicketEnumType +public enum VoucherEnumType { /// /// 生日券 diff --git a/Src/Dlhis.Entity/Device/Entities/DevicePermissionManuallyEntity.cs b/Src/Dlhis.Entity/Device/Entities/DevicePermissionManuallyEntity.cs index 5a27d65d..df67a7b6 100644 --- a/Src/Dlhis.Entity/Device/Entities/DevicePermissionManuallyEntity.cs +++ b/Src/Dlhis.Entity/Device/Entities/DevicePermissionManuallyEntity.cs @@ -9,19 +9,23 @@ namespace Dlhis.Entity.Device.Entities; /// 设备权限(手动) /// [SugarTable(TableName = "DevicePermissionManually")] -public class DevicePermissionManuallyEntity : SugarBaseEntity, ISoftDeleted , ITenantId +public class DevicePermissionManuallyEntity : SugarBaseEntity, ISoftDeleted, ITenantId { [DeviceCode] [SugarColumn(IsNullable = false)] public Guid DeviceCode { get; set; } - + [SugarColumn(IsNullable = false)] public string UserNo { get; set; } - - + + /// + /// 有效时间 + /// + [SugarColumn(IsNullable = true)] + public DateTime? ValidDateTime { get; set; } + public bool IsDeleted { get; set; } - - + public string TenantId { get; set; } } \ No newline at end of file diff --git a/Src/Dlhis.Entity/Sys/Entities/FactorySettingEntity.cs b/Src/Dlhis.Entity/Sys/Entities/FactorySettingEntity.cs index b30049fc..0e1b02cf 100644 --- a/Src/Dlhis.Entity/Sys/Entities/FactorySettingEntity.cs +++ b/Src/Dlhis.Entity/Sys/Entities/FactorySettingEntity.cs @@ -49,5 +49,17 @@ public class FactorySettingEntity : SugarBaseEntity, ITenantId [SugarColumn(IsNullable = true, ColumnDataType = "time", ColumnDescription = "工作网格编辑限制时间")] public TimeOnly? WorkGridSetLimit { get; set; } + /// + /// 是否启用生日电子餐券 + /// + [SugarColumn(ColumnDataType = "bit", ColumnDescription = "是否启用生日电子餐券", DefaultValue = "0")] + public bool EnableBirthdayVoucher { get; set; } + + /// + /// 允许消费的厂区 + /// + [SugarColumn(ColumnDescription = "允许消费的厂区")] + public string EnableUseBirthdayVoucherFactories { get; set; } + public string TenantId { get; set; } } \ No newline at end of file diff --git a/Src/Dlhis.External/EMealVoucher/Services/Implements/EMealVoucherService.cs b/Src/Dlhis.External/EMealVoucher/Services/Implements/EMealVoucherService.cs index 27c4a930..a5f8d488 100644 --- a/Src/Dlhis.External/EMealVoucher/Services/Implements/EMealVoucherService.cs +++ b/Src/Dlhis.External/EMealVoucher/Services/Implements/EMealVoucherService.cs @@ -1,5 +1,5 @@ using Dlhis.Entity.Basic.Entity; -using Dlhis.Entity.Canteen.Entities; +using Dlhis.Entity.Canteen.Entities.EMealVoucher; using Dlhis.Entity.Canteen.Enums; using Dlhis.External.EMealVoucher.Request; using Kurisu.AspNetCore.DataAccess.SqlSugar.Services; diff --git a/Src/Dlhis.External/OpenApi/Controllers/CanteenController.cs b/Src/Dlhis.External/OpenApi/Controllers/CanteenController.cs index 4d4ff92f..1f79d274 100644 --- a/Src/Dlhis.External/OpenApi/Controllers/CanteenController.cs +++ b/Src/Dlhis.External/OpenApi/Controllers/CanteenController.cs @@ -1,5 +1,6 @@ using Dlhis.Entity.Basic.Entity; using Dlhis.Entity.Canteen.Entities; +using Dlhis.Entity.Canteen.Entities.EMealVoucher; using Dlhis.Entity.Canteen.Enums; using Dlhis.External.OpenApi.Response; using Kurisu.AspNetCore.CustomClass; diff --git a/Src/Dlhis.Jip.Api/Dto/SapOrganizationItem.cs b/Src/Dlhis.Jip.Api/Dto/SapOrganizationItem.cs index 1f8d6ce3..f3535a3b 100644 --- a/Src/Dlhis.Jip.Api/Dto/SapOrganizationItem.cs +++ b/Src/Dlhis.Jip.Api/Dto/SapOrganizationItem.cs @@ -41,6 +41,37 @@ public class SapOrganizationItem /// 事业部 /// public string ORGID02 { get; set; } + + /// + /// 一级部分 + /// + public string ORGID03 { get; set; } + + /// + /// 二级部门 + /// + public string ORGID04 { get; set; } + + + /// + /// 三级部门 + /// + public string ORGID05 { get; set; } + + /// + /// 四级部门 + /// + public string ORGID06 { get; set; } + + /// + /// 五级部门 + /// + public string ORGID07 { get; set; } + + /// + /// 六级部门 + /// + public string ORGID08 { get; set; } } diff --git a/Src/Dlhis.Jip.Api/IJinkoJipApi.cs b/Src/Dlhis.Jip.Api/IJinkoJipApi.cs index 23214f21..b0311737 100644 --- a/Src/Dlhis.Jip.Api/IJinkoJipApi.cs +++ b/Src/Dlhis.Jip.Api/IJinkoJipApi.cs @@ -86,4 +86,14 @@ public interface IJinkoJipApi [RequestLog] [Post("/JIP/HCM/HCM_I_SHIFTREP")] Task SyncWorkShiftAsync(SyncWorkShiftRequest request); + + + /// + /// 费用上传 + /// + /// + /// + [RequestLog] + [Post("/JIP/HCM/HCM_0015_INSERT")] + Task UploadCostAsync(UploadCostRequest request); } \ No newline at end of file diff --git a/Src/Dlhis.Jip.Api/Requests/UploadCostRequest.cs b/Src/Dlhis.Jip.Api/Requests/UploadCostRequest.cs new file mode 100644 index 00000000..5ea54df2 --- /dev/null +++ b/Src/Dlhis.Jip.Api/Requests/UploadCostRequest.cs @@ -0,0 +1,39 @@ + + +using Newtonsoft.Json; + +namespace Dlhis.Jip.Api.Requests; + +public class UploadCostRequest +{ + [JsonProperty("T_DATA")] + public List Data { get; set; } +} + + +public class UploadCostItemRequest +{ + /// + /// 工号 可选,为空则删除日期下的所有记录 + /// + [JsonProperty("ZWORKCODE")] + public string WorkCode { get; set; } + + /// + /// 子信息类型 9020 水费扣减(上饶),9021 冷水扣减(上饶),9022 热水扣减(上饶), 2086餐卡消费金额 , 2088生日券发放金额、2089生日券消费金额 + /// + [JsonProperty("SUBTY")] + public string Code { get; set; } + + /// + /// 开始日期 + /// + [JsonProperty("BEGDA")] + public string BeginDate { get; set; } + + /// + /// 工资项金额 + /// + [JsonProperty("BETRG")] + public decimal Charge { get; set; } +} \ No newline at end of file diff --git a/Src/Dlhis.Jip.Api/Responses/UploadCostResponse.cs b/Src/Dlhis.Jip.Api/Responses/UploadCostResponse.cs new file mode 100644 index 00000000..49c3c42b --- /dev/null +++ b/Src/Dlhis.Jip.Api/Responses/UploadCostResponse.cs @@ -0,0 +1,47 @@ + +using Newtonsoft.Json; + +namespace Dlhis.Jip.Api.Responses; + +public class UploadCostResponse +{ + [JsonProperty("T_DATA")] + public List Data { get; set; } +} + +public class UploadCostItemResponse +{ + [JsonProperty("ZWORKCODE")] + public string WorkCode { get; set; } + + /// + /// 子信息类型 9020 水费扣减(上饶),9021 冷水扣减(上饶),9022 热水扣减(上饶) + /// + [JsonProperty("SUBTY")] + public string Code { get; set; } + + /// + /// 开始日期 + /// + [JsonProperty("BEGDA")] + public string BeginDate { get; set; } + + /// + /// 工资项金额 + /// + [JsonProperty("BETRG")] + public decimal Price { get; set; } + + + /// + /// S 成功 + /// + [JsonProperty("MSGTY")] + public string Success { get; set; } + + /// + /// 响应消息 + /// + [JsonProperty("MSGTX")] + public string Message { get; set; } +} \ No newline at end of file diff --git a/Src/Dlhis.ScheduledTask/Attributes/RecurringJobAttribute.cs b/Src/Dlhis.ScheduledTask/Attributes/RecurringJobAttribute.cs index 9db34804..9d8a9c46 100644 --- a/Src/Dlhis.ScheduledTask/Attributes/RecurringJobAttribute.cs +++ b/Src/Dlhis.ScheduledTask/Attributes/RecurringJobAttribute.cs @@ -11,12 +11,10 @@ public class RecurringJobAttribute : Attribute /// /// 任务的唯一标识符。 /// Cron 表达式,定义任务的执行计划。 - /// 是否在开发环境中运行。 - public RecurringJobAttribute(string uniqueJobKey, string cron, bool runOnDevelopment = false) + public RecurringJobAttribute(string uniqueJobKey, string cron) { UniqueJobKey = uniqueJobKey; Cron = cron; - RunOnDevelopment = runOnDevelopment; } /// @@ -37,7 +35,7 @@ public class RecurringJobAttribute : Attribute /// /// 是否在开发环境中运行。 /// - public bool RunOnDevelopment { get; } + public bool RunOnDevelopment { get; set; } = false; /// /// 任务所属队列,默认为 "default"。 diff --git a/Src/Dlhis.ScheduledTask/DeviceUploadLog/Controllers/DeviceUploadLogsController.cs b/Src/Dlhis.ScheduledTask/DeviceUploadLog/Controllers/DeviceUploadLogsController.cs index 91df64bb..82e1b273 100644 --- a/Src/Dlhis.ScheduledTask/DeviceUploadLog/Controllers/DeviceUploadLogsController.cs +++ b/Src/Dlhis.ScheduledTask/DeviceUploadLog/Controllers/DeviceUploadLogsController.cs @@ -36,6 +36,11 @@ public class DeviceUploadLogsController : ControllerBase return await _deviceUploadLogService.GetPageAsync(request); } + /// + /// 查询用户的上传记录分页 + /// + /// + /// [HttpGet("userpage")] public async Task> GetUserPageAsync([FromQuery] DeviceUploadLogUserPageRequest request) { diff --git a/Src/Dlhis.ScheduledTask/DeviceUploadLog/Services/Implements/DeviceUploadLogService.cs b/Src/Dlhis.ScheduledTask/DeviceUploadLog/Services/Implements/DeviceUploadLogService.cs index d43f0938..936559ec 100644 --- a/Src/Dlhis.ScheduledTask/DeviceUploadLog/Services/Implements/DeviceUploadLogService.cs +++ b/Src/Dlhis.ScheduledTask/DeviceUploadLog/Services/Implements/DeviceUploadLogService.cs @@ -238,13 +238,13 @@ public class DeviceUploadLogService : IDeviceUploadLogService { 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日")}未排班,但是有考勤记录,请前往系统处理!", WorkCodes = new List { workGridInfo.WorkGrid.LeaderUserCode } }); - await _dingTalkApi.SendWorkMessageAsync(new JinkoSendWorkMessageRequest + await _dingTalkApi.SendWorkMessageByWorkGridAsync(new JinkoSendWorkMessageRequest { Content = $"{currentGainfo.Name}({currentGainfo.Code},检测到你在{workGridInfo.WorkGrid.WorkGridName}网格中,当日未排班,考勤记录不生效,请立即联系网格长", WorkCodes = new List { currentGainfo.Code } diff --git a/Src/Dlhis.ScheduledTask/Jobs/CostUploadJob.cs b/Src/Dlhis.ScheduledTask/Jobs/CostUploadJob.cs new file mode 100644 index 00000000..6695974e --- /dev/null +++ b/Src/Dlhis.ScheduledTask/Jobs/CostUploadJob.cs @@ -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; + +/// +/// 每月8号上传消费数据 +/// +[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(); + + 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() + .Where(x => SqlFunc.Subqueryable() + .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() + .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 + { + 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() + .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, + }); + } + } + } + } +} diff --git a/Src/Dlhis.ScheduledTask/Jobs/GenerateBirthdayVoucherJob.cs b/Src/Dlhis.ScheduledTask/Jobs/GenerateBirthdayVoucherJob.cs new file mode 100644 index 00000000..afff58db --- /dev/null +++ b/Src/Dlhis.ScheduledTask/Jobs/GenerateBirthdayVoucherJob.cs @@ -0,0 +1,28 @@ +using Dlhis.Canteen.Api; +using Dlhis.ScheduledTask.Attributes; + +namespace Dlhis.ScheduledTask.Jobs; + +/// +/// 生日券生成 +/// +[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(); + await voucherApi.CreateAsync(new VoucherByBirthdayRequest + { + Begin = now, + End = now, + Remark = "定时执行生成" + }); + } +} diff --git a/Src/Dlhis.ScheduledTask/Jobs/SendMsgToWorkGridLeaderJob.cs b/Src/Dlhis.ScheduledTask/Jobs/SendMsgToWorkGridLeaderJob.cs index 448d1f5b..e44df8b2 100644 --- a/Src/Dlhis.ScheduledTask/Jobs/SendMsgToWorkGridLeaderJob.cs +++ b/Src/Dlhis.ScheduledTask/Jobs/SendMsgToWorkGridLeaderJob.cs @@ -31,7 +31,7 @@ public class SendMsgToWorkGridLeaderJob : BaseJob foreach (var items in infos.Chunk(5)) { - await dingtalkApi.SendWorkMessageAsync(new JinkoSendWorkMessageRequest + await dingtalkApi.SendWorkMessageByWorkGridAsync(new JinkoSendWorkMessageRequest { Content = "你好,网格长,请看到消息后,前往人脸应用平台,执行明天的排班,已排班的请忽略!", WorkCodes = items.Select(x => x.LeaderUserCode).ToList() diff --git a/Src/Dlhis.ScheduledTask/Jobs/SyncOrganizationJob.cs b/Src/Dlhis.ScheduledTask/Jobs/SyncOrganizationJob.cs index 3896edd1..43b00d1e 100644 --- a/Src/Dlhis.ScheduledTask/Jobs/SyncOrganizationJob.cs +++ b/Src/Dlhis.ScheduledTask/Jobs/SyncOrganizationJob.cs @@ -40,6 +40,8 @@ public class SyncOrganizationJob : BaseJob No = item.OBJID, Name = item.STEXT, PNo = item.SOBID, + DepartmentNoFirst = item.ORGID03, + DepartmentNoSecond = item.ORGID04 }; await DbContext.InsertAsync(department); @@ -48,6 +50,8 @@ public class SyncOrganizationJob : BaseJob { department.PNo = item.SOBID; department.Name = item.STEXT; + department.DepartmentNoFirst = item.ORGID03; + department.DepartmentNoSecond = item.ORGID04; await DbContext.UpdateAsync(department); } diff --git a/Src/Dlhis.ScheduledTask/Jobs/TipAppointmentExpireJob.cs b/Src/Dlhis.ScheduledTask/Jobs/TipAppointmentExpireJob.cs new file mode 100644 index 00000000..83b20067 --- /dev/null +++ b/Src/Dlhis.ScheduledTask/Jobs/TipAppointmentExpireJob.cs @@ -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; + +/// +/// 每天10点提醒访客预约到期 +/// +[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() + .Where(x => (x.IsEnterDoorArea && x.DoorStatus == VisitorAppointmentDetailStatusEnumType.Arrived) || + (x.IsEnterWorkplace && x.WorkplaceStatus == VisitorAppointmentDetailStatusEnumType.Arrived)) + .ToListAsync(); + + var warningDetails = new List(); + 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() + .Where(x => x.No == item.Key) + .SingleAsync(); + + await _dingTalkApi.SendWorkMessageAsync(new JinkoSendWorkMessageRequest + { + WorkCodes = new List { 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; + } +} + + + diff --git a/Src/Dlhis.ScheduledTask/TaskAssignment/Controllers/AssignmentsController.cs b/Src/Dlhis.ScheduledTask/TaskAssignment/Controllers/AssignmentsController.cs index 3a8a1f49..2cf21b14 100644 --- a/Src/Dlhis.ScheduledTask/TaskAssignment/Controllers/AssignmentsController.cs +++ b/Src/Dlhis.ScheduledTask/TaskAssignment/Controllers/AssignmentsController.cs @@ -76,87 +76,6 @@ public class AssignmentsController : ControllerBase 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() - .Where(x => SqlFunc.Subqueryable().Where(p => p.UserCode == x.UserCode).NotAny()) - .Select(x => x.UserCode) - .Distinct() - .ToListAsync(); - - foreach (var userCode in userCodes) - { - if (!await _dbContext.Queryable().Where(x => x.UserCode == userCode).AnyAsync()) - { - await _dbContext.InsertAsync(new UserBalanceTmpEntity - { - UserCode = userCode, - Balance = 0, - Version = 0 - }); - } - - var balance = await _dbContext.Queryable() - .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() - .SetColumns(x => x.Balance == balance) - .SetColumns(x => x.ModifiedTime == DateTime.Now) - .Where(x => x.UserCode == userCode) - .ExecuteCommandAsync(); - } - - // - // var userCodes = await _dbContext.Queryable().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().Where(x => x.UserCode == userCode).AnyAsync()) - // { - // await _dbContext.InsertAsync(new UserBalanceTmpEntity - // { - // UserCode = userCode, - // Balance = 0, - // Version = 0 - // }); - // } - // - // var balance = await _dbContext.Queryable() - // .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() - // .SetColumns(x => x.Balance == balance) - // .SetColumns(x => x.ModifiedTime == DateTime.Now) - // .Where(x => x.UserCode == userCode) - // .ExecuteCommandAsync(); - // } - } - [Obsolete] [AllowAnonymous] [IgnoreTenant]