From 4673b08e704474d4fa93c8f19eaa5a1df5726d22 Mon Sep 17 00:00:00 2001 From: liguoyang Date: Tue, 13 Aug 2024 10:32:27 +0800 Subject: [PATCH 01/25] =?UTF-8?q?feat=20=E9=A4=90=E6=AC=A1=E5=B0=B1?= =?UTF-8?q?=E9=A4=90=E5=88=86=E6=9E=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Controllers/BalanceSummaryController.cs | 9 ++++ .../Order/Dto/ShiftSummaryDto.cs | 9 ++++ .../BalanceRecordAnalysisByShiftRequest.cs | 29 +++++++++++++ .../BalanceRecordAnalysisShiftResponse.cs | 20 +++++++++ .../Order/Services/IBalanceSummaryService.cs | 5 ++- .../Implements/BalanceSummaryService.cs | 42 ++++++++++++++++++- .../Menu/Controllers/MenusController.cs | 1 + 7 files changed, 113 insertions(+), 2 deletions(-) create mode 100644 Src/Dlhis.Canteen/Order/Dto/ShiftSummaryDto.cs create mode 100644 Src/Dlhis.Canteen/Order/Request/BalanceRecordAnalysisByShiftRequest.cs create mode 100644 Src/Dlhis.Canteen/Order/Response/BalanceRecordAnalysisShiftResponse.cs diff --git a/Src/Dlhis.Canteen/Order/Controllers/BalanceSummaryController.cs b/Src/Dlhis.Canteen/Order/Controllers/BalanceSummaryController.cs index 96e3cc09..4326f250 100644 --- a/Src/Dlhis.Canteen/Order/Controllers/BalanceSummaryController.cs +++ b/Src/Dlhis.Canteen/Order/Controllers/BalanceSummaryController.cs @@ -41,4 +41,13 @@ public class BalanceSummaryController : ControllerBase { return await _balanceSummaryService.BalanceRecordAnalysisByCostIdAsync(); } + + /// + /// 用餐分析(餐次) + /// + [HttpGet("analysis/shift")] + public async Task BalanceRecordAnalysisByShiftAsync([FromQuery] BalanceRecordAnalysisByShiftRequest request) + { + return await _balanceSummaryService.BalanceRecordAnalysisByShiftAsync(request); + } } \ No newline at end of file diff --git a/Src/Dlhis.Canteen/Order/Dto/ShiftSummaryDto.cs b/Src/Dlhis.Canteen/Order/Dto/ShiftSummaryDto.cs new file mode 100644 index 00000000..5dfa4954 --- /dev/null +++ b/Src/Dlhis.Canteen/Order/Dto/ShiftSummaryDto.cs @@ -0,0 +1,9 @@ +using Dlhis.Entity.Canteen.Enums; + +namespace Dlhis.Canteen.Order.Dto; + +public class ShiftSummaryDto +{ + public ShiftEnumType? Shift { get; set; } + public T Value { get; set; } +} \ No newline at end of file diff --git a/Src/Dlhis.Canteen/Order/Request/BalanceRecordAnalysisByShiftRequest.cs b/Src/Dlhis.Canteen/Order/Request/BalanceRecordAnalysisByShiftRequest.cs new file mode 100644 index 00000000..65f99310 --- /dev/null +++ b/Src/Dlhis.Canteen/Order/Request/BalanceRecordAnalysisByShiftRequest.cs @@ -0,0 +1,29 @@ +using System.ComponentModel.DataAnnotations; +using Kurisu.AspNetCore.CustomClass; +using Kurisu.AspNetCore.DataAccess.Dto; + +namespace Dlhis.Canteen.Order.Request; + +public class BalanceRecordAnalysisByShiftRequest : PageDto, IValidatableObject +{ + /// + /// 营业点 + /// + public List BusinessPlaceCodes { get; set; } + + /// + /// + /// + public DateTimePeriod SearchDateTimePeriod { get; set; } + + /// + public IEnumerable Validate(ValidationContext validationContext) + { + if (SearchDateTimePeriod is { End: not null }) + { + SearchDateTimePeriod.End = SearchDateTimePeriod.End.Value.AddDays(1).AddSeconds(-1); + } + + yield break; + } +} \ No newline at end of file diff --git a/Src/Dlhis.Canteen/Order/Response/BalanceRecordAnalysisShiftResponse.cs b/Src/Dlhis.Canteen/Order/Response/BalanceRecordAnalysisShiftResponse.cs new file mode 100644 index 00000000..5598845f --- /dev/null +++ b/Src/Dlhis.Canteen/Order/Response/BalanceRecordAnalysisShiftResponse.cs @@ -0,0 +1,20 @@ +using Dlhis.Canteen.Order.Dto; +using Kurisu.AspNetCore.DataAccess.Dto; +using Kurisu.AspNetCore.Utils.Converters; +using Newtonsoft.Json; + +namespace Dlhis.Canteen.Order.Response; + +public class BalanceRecordAnalysisShiftResponse +{ + public decimal Amount { get; set; } + public Pagination Pagination { get; set; } +} + +public class BalanceRecordAnalysisShiftPageResponse +{ + [JsonConverter(typeof(ToDateJsonConverter))] + public DateTime Date { get; set; } + + public List> Shifts { get; set; } +} \ No newline at end of file diff --git a/Src/Dlhis.Canteen/Order/Services/IBalanceSummaryService.cs b/Src/Dlhis.Canteen/Order/Services/IBalanceSummaryService.cs index 113be8c6..79707980 100644 --- a/Src/Dlhis.Canteen/Order/Services/IBalanceSummaryService.cs +++ b/Src/Dlhis.Canteen/Order/Services/IBalanceSummaryService.cs @@ -9,4 +9,7 @@ public interface IBalanceSummaryService : IScopeDependency Task BalanceRecordAnalysisAsync(BalanceRecordAnalysisRequest request); Task> BalanceRecordAnalysisByCostIdAsync(); -} + + + Task BalanceRecordAnalysisByShiftAsync(BalanceRecordAnalysisByShiftRequest request); +} \ No newline at end of file diff --git a/Src/Dlhis.Canteen/Order/Services/Implements/BalanceSummaryService.cs b/Src/Dlhis.Canteen/Order/Services/Implements/BalanceSummaryService.cs index 8db7ff01..cb79225a 100644 --- a/Src/Dlhis.Canteen/Order/Services/Implements/BalanceSummaryService.cs +++ b/Src/Dlhis.Canteen/Order/Services/Implements/BalanceSummaryService.cs @@ -1,4 +1,6 @@ -using Dlhis.Canteen.Order.Request; +using System.Reflection; +using Dlhis.Canteen.Order.Dto; +using Dlhis.Canteen.Order.Request; using Dlhis.Canteen.Order.Response; using Dlhis.Entity.Canteen.Entities; using Dlhis.Entity.Canteen.Enums; @@ -6,6 +8,7 @@ using Kurisu.AspNetCore.CustomClass; using Kurisu.AspNetCore.DataAccess.Dto; using Kurisu.AspNetCore.DataAccess.Extensions; using Kurisu.AspNetCore.DataAccess.SqlSugar.Services; +using SqlSugar; namespace Dlhis.Canteen.Order.Services.Implements; @@ -85,4 +88,41 @@ public class BalanceSummaryService : IBalanceSummaryService return null; } + + + public async Task BalanceRecordAnalysisByShiftAsync(BalanceRecordAnalysisByShiftRequest request) + { + var queryable = _dbContext.Queryable() + .Where(x => x.Status == BalanceRecordStatusEnumType.Valid && x.Type == BalanceRecordTypeEnumType.Out) + .WhereIF(request.SearchDateTimePeriod.HasValue(), x => x.CostDate >= request.SearchDateTimePeriod.Start && x.CostDate <= request.SearchDateTimePeriod.End) + .WhereIF(request.BusinessPlaceCodes?.Any() == true, x => request.BusinessPlaceCodes.Contains(x.BusinessPlaceCode.Value)); + + var amount = await queryable.SumAsync(x => x.Amount); + + var count = typeof(ShiftEnumType).GetFields(BindingFlags.Public | BindingFlags.Static).Length; + + var result = await queryable.GroupBy(x => new { x.CostDate, x.ShiftType }) + .Select(x => new { x.CostDate, x.ShiftType, Amount = SqlFunc.AggregateSum(SqlFunc.Abs(x.Amount)) }) + .ToPageListAsync(request.PageIndex, count * request.PageSize); + + return new BalanceRecordAnalysisShiftResponse + { + Amount = amount, + Pagination = new Pagination + { + PageIndex = request.PageIndex, + PageSize = request.PageSize, + Total = result.Count, + Data = result.GroupBy(x => x.CostDate).Select(x => new BalanceRecordAnalysisShiftPageResponse + { + Date = x.Key, + Shifts = x.Select(item => new ShiftSummaryDto + { + Shift = item.ShiftType, + Value = item.Amount + }).ToList() + }).ToList() + } + }; + } } \ No newline at end of file diff --git a/Src/Dlhis.Sys/Menu/Controllers/MenusController.cs b/Src/Dlhis.Sys/Menu/Controllers/MenusController.cs index 63203c04..0f32e9ea 100644 --- a/Src/Dlhis.Sys/Menu/Controllers/MenusController.cs +++ b/Src/Dlhis.Sys/Menu/Controllers/MenusController.cs @@ -102,6 +102,7 @@ public class MenusController : ControllerBase /// [Authorize(Roles = "admin")] [HttpPost("reset")] + [Transactional] public async Task ResetAsync(List request) { await _menuService.ResetAsync(request); From 8f61ec207245ebc92e4054d39590d94dcdf790ac Mon Sep 17 00:00:00 2001 From: liguoyang Date: Tue, 13 Aug 2024 13:46:06 +0800 Subject: [PATCH 02/25] =?UTF-8?q?feat=20=E5=B0=B1=E9=A4=90=E5=88=86?= =?UTF-8?q?=E6=9E=90,=E9=A4=90=E6=AC=A1=E4=BD=BF=E7=94=A8=E9=87=91?= =?UTF-8?q?=E9=A2=9D=E5=92=8C=E4=BA=BA=E6=95=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Controllers/BalanceSummaryController.cs | 19 +++++++++--- ...cordAnalysisShiftAmountAndCountResponse.cs | 16 ++++++++++ .../BalanceRecordAnalysisShiftResponse.cs | 2 +- .../Order/Services/IBalanceSummaryService.cs | 4 ++- .../Services/Implements/BalanceService.cs | 13 +++++--- .../Implements/BalanceSummaryService.cs | 31 +++++++++++++++++-- 6 files changed, 72 insertions(+), 13 deletions(-) create mode 100644 Src/Dlhis.Canteen/Order/Response/BalanceRecordAnalysisShiftAmountAndCountResponse.cs diff --git a/Src/Dlhis.Canteen/Order/Controllers/BalanceSummaryController.cs b/Src/Dlhis.Canteen/Order/Controllers/BalanceSummaryController.cs index 4326f250..154eafb0 100644 --- a/Src/Dlhis.Canteen/Order/Controllers/BalanceSummaryController.cs +++ b/Src/Dlhis.Canteen/Order/Controllers/BalanceSummaryController.cs @@ -43,11 +43,22 @@ public class BalanceSummaryController : ControllerBase } /// - /// 用餐分析(餐次) + /// 餐次用餐分析,统计金额 /// - [HttpGet("analysis/shift")] - public async Task BalanceRecordAnalysisByShiftAsync([FromQuery] BalanceRecordAnalysisByShiftRequest request) + [HttpGet("shift/analysis/amount")] + public async Task BalanceRecordShiftAnalysisAmountAsync([FromQuery] BalanceRecordAnalysisByShiftRequest request) { - return await _balanceSummaryService.BalanceRecordAnalysisByShiftAsync(request); + return await _balanceSummaryService.BalanceRecordShiftAnalysisAmountAsync(request); + } + + /// + /// 餐次用餐分析,统计金额和人数 + /// + /// + /// + [HttpGet("shift/analysis/amountAndCount")] + public async Task BalanceRecordShiftAnalysisAmountAndCountAsync([FromQuery] BalanceRecordAnalysisByShiftRequest request) + { + return await _balanceSummaryService.BalanceRecordShiftAnalysisAmountAndCountAsync(request); } } \ No newline at end of file diff --git a/Src/Dlhis.Canteen/Order/Response/BalanceRecordAnalysisShiftAmountAndCountResponse.cs b/Src/Dlhis.Canteen/Order/Response/BalanceRecordAnalysisShiftAmountAndCountResponse.cs new file mode 100644 index 00000000..e20d86d3 --- /dev/null +++ b/Src/Dlhis.Canteen/Order/Response/BalanceRecordAnalysisShiftAmountAndCountResponse.cs @@ -0,0 +1,16 @@ +using Dlhis.Entity.Canteen.Enums; + +namespace Dlhis.Canteen.Order.Response; + +public class BalanceRecordAnalysisShiftAmountAndCountResponse +{ + public decimal Amount { get; set; } + public List Items { get; set; } +} + +public class BalanceRecordAnalysisShiftAmountAndCountItemResponse +{ + public ShiftEnumType? ShiftType { get; set; } + public decimal Amount { get; set; } + public int Count { get; set; } +} \ No newline at end of file diff --git a/Src/Dlhis.Canteen/Order/Response/BalanceRecordAnalysisShiftResponse.cs b/Src/Dlhis.Canteen/Order/Response/BalanceRecordAnalysisShiftResponse.cs index 5598845f..75b66dbe 100644 --- a/Src/Dlhis.Canteen/Order/Response/BalanceRecordAnalysisShiftResponse.cs +++ b/Src/Dlhis.Canteen/Order/Response/BalanceRecordAnalysisShiftResponse.cs @@ -5,7 +5,7 @@ using Newtonsoft.Json; namespace Dlhis.Canteen.Order.Response; -public class BalanceRecordAnalysisShiftResponse +public class BalanceRecordAnalysisShiftAmountResponse { public decimal Amount { get; set; } public Pagination Pagination { get; set; } diff --git a/Src/Dlhis.Canteen/Order/Services/IBalanceSummaryService.cs b/Src/Dlhis.Canteen/Order/Services/IBalanceSummaryService.cs index 79707980..b6a192d9 100644 --- a/Src/Dlhis.Canteen/Order/Services/IBalanceSummaryService.cs +++ b/Src/Dlhis.Canteen/Order/Services/IBalanceSummaryService.cs @@ -11,5 +11,7 @@ public interface IBalanceSummaryService : IScopeDependency Task> BalanceRecordAnalysisByCostIdAsync(); - Task BalanceRecordAnalysisByShiftAsync(BalanceRecordAnalysisByShiftRequest request); + Task BalanceRecordShiftAnalysisAmountAsync(BalanceRecordAnalysisByShiftRequest request); + + Task BalanceRecordShiftAnalysisAmountAndCountAsync(BalanceRecordAnalysisByShiftRequest request); } \ No newline at end of file diff --git a/Src/Dlhis.Canteen/Order/Services/Implements/BalanceService.cs b/Src/Dlhis.Canteen/Order/Services/Implements/BalanceService.cs index bb3483a3..cd1cc6a6 100644 --- a/Src/Dlhis.Canteen/Order/Services/Implements/BalanceService.cs +++ b/Src/Dlhis.Canteen/Order/Services/Implements/BalanceService.cs @@ -109,6 +109,10 @@ public class BalanceService : IBalanceService { var cache = App.GetServiceProvider().GetService(); var balanceRecord = await _dbContext.Queryable().Where(x => x.No == no).SingleAsync(); + balanceRecord.ThrowIfNull("数据不存在"); + + (balanceRecord.Status != BalanceRecordStatusEnumType.Valid).ThrowIfTrue("无法退款"); + await using var handler = await cache.LockAsync($"balance:refund:{no}", TimeSpan.FromSeconds(9)); if (handler.Acquired) { @@ -125,7 +129,7 @@ public class BalanceService : IBalanceService } } - var userNo = balanceRecord?.UserNo; + var userNo = balanceRecord.UserNo; //获取人员余额 return await _dbContext.Queryable() .LeftJoin((x, ga) => x.UserNo == ga.No) @@ -146,8 +150,8 @@ public class BalanceService : IBalanceService public async Task> GetPageByDeviceUniqueNoAsync(BalanceRecordPageByDeviceUniqueNoRequest request) { var device = await _dbContext.Queryable() - .Where(x => x.UniqueNo == request.DeviceUniqueNo || x.Code == Guid.Parse(request.DeviceUniqueNo)) - .FirstAsync(); + .Where(x => x.UniqueNo == request.DeviceUniqueNo) + .SingleAsync(); if (device == null) { @@ -182,7 +186,8 @@ public class BalanceService : IBalanceService .LeftJoin((record, ga, department, bPlace, imageRecord) => imageRecord.No == record.No) .Where(record => record.DeviceUniqueNo == device.UniqueNo) .Where(record => record.CostDate >= request.Start && record.CostDate <= request.End) - .Where(record => record.Type == BalanceRecordTypeEnumType.Out && record.Status == BalanceRecordStatusEnumType.Valid) + .Where(record => record.Type == BalanceRecordTypeEnumType.Out + && (record.Status == BalanceRecordStatusEnumType.Valid || (record.Status == BalanceRecordStatusEnumType.Obsolute && record.Remark == "退款"))) .WhereIF(request.UserCode.IsPresent(), record => record.UserCode == request.UserCode) .OrderBy(record => record.CostDateTime, OrderByType.Desc) .Select((record, ga, department, bPlace, imageRecord) => new BalanceRecordDeviceResponse diff --git a/Src/Dlhis.Canteen/Order/Services/Implements/BalanceSummaryService.cs b/Src/Dlhis.Canteen/Order/Services/Implements/BalanceSummaryService.cs index cb79225a..5a76b686 100644 --- a/Src/Dlhis.Canteen/Order/Services/Implements/BalanceSummaryService.cs +++ b/Src/Dlhis.Canteen/Order/Services/Implements/BalanceSummaryService.cs @@ -90,14 +90,14 @@ public class BalanceSummaryService : IBalanceSummaryService } - public async Task BalanceRecordAnalysisByShiftAsync(BalanceRecordAnalysisByShiftRequest request) + public async Task BalanceRecordShiftAnalysisAmountAsync(BalanceRecordAnalysisByShiftRequest request) { var queryable = _dbContext.Queryable() .Where(x => x.Status == BalanceRecordStatusEnumType.Valid && x.Type == BalanceRecordTypeEnumType.Out) .WhereIF(request.SearchDateTimePeriod.HasValue(), x => x.CostDate >= request.SearchDateTimePeriod.Start && x.CostDate <= request.SearchDateTimePeriod.End) .WhereIF(request.BusinessPlaceCodes?.Any() == true, x => request.BusinessPlaceCodes.Contains(x.BusinessPlaceCode.Value)); - var amount = await queryable.SumAsync(x => x.Amount); + var amount = await queryable.SumAsync(x => SqlFunc.Abs(x.Amount)); var count = typeof(ShiftEnumType).GetFields(BindingFlags.Public | BindingFlags.Static).Length; @@ -105,7 +105,7 @@ public class BalanceSummaryService : IBalanceSummaryService .Select(x => new { x.CostDate, x.ShiftType, Amount = SqlFunc.AggregateSum(SqlFunc.Abs(x.Amount)) }) .ToPageListAsync(request.PageIndex, count * request.PageSize); - return new BalanceRecordAnalysisShiftResponse + return new BalanceRecordAnalysisShiftAmountResponse { Amount = amount, Pagination = new Pagination @@ -125,4 +125,29 @@ public class BalanceSummaryService : IBalanceSummaryService } }; } + + public async Task BalanceRecordShiftAnalysisAmountAndCountAsync(BalanceRecordAnalysisByShiftRequest request) + { + var queryable = _dbContext.Queryable() + .Where(x => x.Status == BalanceRecordStatusEnumType.Valid && x.Type == BalanceRecordTypeEnumType.Out) + .WhereIF(request.SearchDateTimePeriod.HasValue(), x => x.CostDate >= request.SearchDateTimePeriod.Start && x.CostDate <= request.SearchDateTimePeriod.End) + .WhereIF(request.BusinessPlaceCodes?.Any() == true, x => request.BusinessPlaceCodes.Contains(x.BusinessPlaceCode.Value)); + + var amount = await queryable.SumAsync(x => SqlFunc.Abs(x.Amount)); + + var result = await queryable.GroupBy(x => new { x.ShiftType }) + .Select(x => new { x.ShiftType, Amount = SqlFunc.AggregateSum(SqlFunc.Abs(x.Amount)), Count = SqlFunc.AggregateDistinctCount(x.UserCode) }) + .ToListAsync(); + + return new BalanceRecordAnalysisShiftAmountAndCountResponse + { + Amount = amount, + Items = result.Select(x => new BalanceRecordAnalysisShiftAmountAndCountItemResponse + { + ShiftType = x.ShiftType, + Amount = x.Amount, + Count = x.Count + }).ToList() + }; + } } \ No newline at end of file From 827a1077ebeb90b99a7802a499fc4016b0fd1c8d Mon Sep 17 00:00:00 2001 From: liguoyang Date: Wed, 14 Aug 2024 15:07:08 +0800 Subject: [PATCH 03/25] =?UTF-8?q?feat=20=E7=94=B5=E5=AD=90=E9=A4=90?= =?UTF-8?q?=E5=88=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Implements/DeviceConnectService.cs | 4 +- .../Organization/Request/GainfoPageRequest.cs | 3 + .../Services/Implements/GainfoMealService.cs | 2 - .../Services/Implements/GainfoService.cs | 9 +- Src/Dlhis.Basic/Program.cs | 1 + Src/Dlhis.Canteen/Dlhis.Canteen.csproj | 6 - .../Controllers/EMealVoucherController.cs | 65 ++++ .../Request/EMealVoucherPageRequest.cs | 7 + .../Response/EMealVoucherDetailResponse.cs | 31 ++ .../Response/EMealVoucherPageResponse.cs | 12 + .../Services/IEMealVoucherService.cs | 18 ++ .../Implements/EMealVoucherService.cs | 106 +++++++ .../Implements/MealSupplementRecordService.cs | 1 - .../Order/Dto/OrderPreCheckDto.cs | 16 + .../Services/Implements/BalanceService.cs | 1 - .../Implements/BookingOrderService.cs | 1 - .../Implements/HainingBalanceService.cs | 1 - .../Order/Services/Implements/OrderService.cs | 300 ++++++++++++++---- .../Canteen/Entities/BalanceRecordEntity.cs | 6 - .../Entities/EMealVoucherDetailEntity.cs | 23 +- .../EMealVoucherDetailQrCodeEntity.cs | 29 ++ .../Enums/BalanceRecordSourceEnumType.cs | 2 +- .../Request/EMealVoucherReceiveRequest.cs | 5 + .../Implements/EMealVoucherService.cs | 2 +- .../Services/Implements/OrderService.cs | 1 - .../Jobs/MealSupplementHandlerJob.cs | 1 - Src/Gateway/Program.cs | 14 +- Src/Gateway/appsettings.json | 1 - Src/Gateway/ocelot.Development.json | 2 +- 29 files changed, 560 insertions(+), 110 deletions(-) create mode 100644 Src/Dlhis.Canteen/EMealVoucher/Request/EMealVoucherPageRequest.cs create mode 100644 Src/Dlhis.Canteen/EMealVoucher/Response/EMealVoucherDetailResponse.cs create mode 100644 Src/Dlhis.Canteen/EMealVoucher/Response/EMealVoucherPageResponse.cs create mode 100644 Src/Dlhis.Canteen/EMealVoucher/Services/IEMealVoucherService.cs create mode 100644 Src/Dlhis.Canteen/EMealVoucher/Services/Implements/EMealVoucherService.cs create mode 100644 Src/Dlhis.Canteen/Order/Dto/OrderPreCheckDto.cs create mode 100644 Src/Dlhis.Entity/Canteen/Entities/EMealVoucherDetailQrCodeEntity.cs diff --git a/Src/Dlhis.Basic/Device/Services/Implements/DeviceConnectService.cs b/Src/Dlhis.Basic/Device/Services/Implements/DeviceConnectService.cs index 4b767cc6..30671f82 100644 --- a/Src/Dlhis.Basic/Device/Services/Implements/DeviceConnectService.cs +++ b/Src/Dlhis.Basic/Device/Services/Implements/DeviceConnectService.cs @@ -17,10 +17,12 @@ namespace Dlhis.Basic.Device.Services.Implements; public class DeviceConnectService : IDeviceConnectService { private readonly IDbContext _dbContext; + private readonly IHttpContextAccessor _httpContextAccessor; - public DeviceConnectService(IDbContext dbContext) + public DeviceConnectService(IDbContext dbContext, IHttpContextAccessor httpContextAccessor) { _dbContext = dbContext; + _httpContextAccessor = httpContextAccessor; } diff --git a/Src/Dlhis.Basic/Organization/Request/GainfoPageRequest.cs b/Src/Dlhis.Basic/Organization/Request/GainfoPageRequest.cs index 899a8369..c0cf9d0e 100644 --- a/Src/Dlhis.Basic/Organization/Request/GainfoPageRequest.cs +++ b/Src/Dlhis.Basic/Organization/Request/GainfoPageRequest.cs @@ -24,6 +24,9 @@ public class GainfoPageRequest : PageDto, IValidatableObject [EnumDataType(typeof(GainfoSearchEnumType))] public GainfoSearchEnumType SearchType { get; set; } + + public bool IsSearchAll { get; set; } + public IEnumerable Validate(ValidationContext validationContext) { DepartmentSelections.ForEach(d => diff --git a/Src/Dlhis.Basic/Organization/Services/Implements/GainfoMealService.cs b/Src/Dlhis.Basic/Organization/Services/Implements/GainfoMealService.cs index 93249cff..587c3fb2 100644 --- a/Src/Dlhis.Basic/Organization/Services/Implements/GainfoMealService.cs +++ b/Src/Dlhis.Basic/Organization/Services/Implements/GainfoMealService.cs @@ -96,7 +96,6 @@ public class GainfoMealService : IGainfoMealService ShiftType = null, CostDate = now.Date, DeviceUniqueNo = null, - SubsidiesFromMonth = now.ToString("yyyyMM"), IP = null, CostId = gainfoLeave.CostId, OriginTenantId = gainfoLeave.Factory, @@ -141,7 +140,6 @@ public class GainfoMealService : IGainfoMealService ShiftType = null, CostDate = now.Date, DeviceUniqueNo = null, - SubsidiesFromMonth = now.ToString("yyyyMM"), IP = null, CostId = gainfo.CostId, OriginTenantId = gainfo.Factory, diff --git a/Src/Dlhis.Basic/Organization/Services/Implements/GainfoService.cs b/Src/Dlhis.Basic/Organization/Services/Implements/GainfoService.cs index 0b881111..6bdda56c 100644 --- a/Src/Dlhis.Basic/Organization/Services/Implements/GainfoService.cs +++ b/Src/Dlhis.Basic/Organization/Services/Implements/GainfoService.cs @@ -82,10 +82,11 @@ public class GainfoService : IGainfoService .WhereIF(request.SearchType != GainfoSearchEnumType.BusinessTrip && request.DepartmentSelections?.Any() == true, where) .LeftJoin((gainfo, department) => gainfo.DepartmentNo == department.No) .LeftJoin((gainfo, department, type) => type.Code == SqlFunc.ToString(gainfo.CardType) && type.Type == "timeperiod") - .WhereIF(request.SearchType != GainfoSearchEnumType.BusinessTrip && request.DepartmentSelections?.Any() == false, gainfo => factories.Contains(gainfo.Factory)) - .WhereIF(request.SearchType == GainfoSearchEnumType.Internal, gainfo => SqlFunc.Subqueryable().Where(p => p.Code == gainfo.Code).NotAny()) - .WhereIF(request.SearchType == GainfoSearchEnumType.Outsource, gainfo => SqlFunc.Subqueryable().Where(p => p.Code == gainfo.Code).Any()) - .WhereIF(request.SearchType == GainfoSearchEnumType.BusinessTrip, gainfo => + .WhereIF(request.IsSearchAll && request.DepartmentSelections?.Any() == false, gainfo => factories.Contains(gainfo.Factory)) + .WhereIF(!request.IsSearchAll && request.SearchType != GainfoSearchEnumType.BusinessTrip && request.DepartmentSelections?.Any() == false, gainfo => factories.Contains(gainfo.Factory)) + .WhereIF(!request.IsSearchAll && request.SearchType == GainfoSearchEnumType.Internal, gainfo => SqlFunc.Subqueryable().Where(p => p.Code == gainfo.Code).NotAny()) + .WhereIF(!request.IsSearchAll && request.SearchType == GainfoSearchEnumType.Outsource, gainfo => SqlFunc.Subqueryable().Where(p => p.Code == gainfo.Code).Any()) + .WhereIF(!request.IsSearchAll && request.SearchType == GainfoSearchEnumType.BusinessTrip, gainfo => SqlFunc.Subqueryable().Where(p => p.Code == gainfo.Code && factories.Contains(p.Destination) && SqlFunc.DateIsSame(p.BeginDate, today)).Any()) .WhereIF(request.Search.IsPresent(), gainfo => gainfo.Name.Contains(request.Search) diff --git a/Src/Dlhis.Basic/Program.cs b/Src/Dlhis.Basic/Program.cs index 882db25c..6bd00925 100644 --- a/Src/Dlhis.Basic/Program.cs +++ b/Src/Dlhis.Basic/Program.cs @@ -22,6 +22,7 @@ public class Startup : DefaultStartup public override void ConfigureServices(IServiceCollection services) { base.ConfigureServices(services); + services.AddHttpContextAccessor(); services.AddRedis(); } } \ No newline at end of file diff --git a/Src/Dlhis.Canteen/Dlhis.Canteen.csproj b/Src/Dlhis.Canteen/Dlhis.Canteen.csproj index fc8473bf..0c6bb0f3 100644 --- a/Src/Dlhis.Canteen/Dlhis.Canteen.csproj +++ b/Src/Dlhis.Canteen/Dlhis.Canteen.csproj @@ -28,10 +28,4 @@ - - - - - - diff --git a/Src/Dlhis.Canteen/EMealVoucher/Controllers/EMealVoucherController.cs b/Src/Dlhis.Canteen/EMealVoucher/Controllers/EMealVoucherController.cs index 98e2f3ed..40b9483d 100644 --- a/Src/Dlhis.Canteen/EMealVoucher/Controllers/EMealVoucherController.cs +++ b/Src/Dlhis.Canteen/EMealVoucher/Controllers/EMealVoucherController.cs @@ -1,3 +1,7 @@ +using Dlhis.Canteen.EMealVoucher.Request; +using Dlhis.Canteen.EMealVoucher.Response; +using Dlhis.Canteen.EMealVoucher.Services; +using Kurisu.AspNetCore.DataAccess.Dto; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; @@ -8,4 +12,65 @@ namespace Dlhis.Canteen.EMealVoucher.Controllers; [ApiController] public class EMealVoucherController : ControllerBase { + private readonly IEMealVoucherService _eMealVoucherService; + + public EMealVoucherController(IEMealVoucherService eMealVoucherService) + { + _eMealVoucherService = eMealVoucherService; + } + + /// + /// 获取我的电子餐券申请 + /// + /// + /// + [HttpGet("my")] + public async Task> GetMyEMealVoucherPageAsync([FromQuery] EMealVoucherPageRequest request) + { + return await _eMealVoucherService.GetMyEMealVoucherPageAsync(request); + } + + /// + /// 查看电子餐券 + /// + /// + /// + [HttpGet("no")] + public async Task> GetDetailsByNoAsync(string no) + { + return await _eMealVoucherService.GetDetailsByNoAsync(no); + } + + /// + /// 获取url签名 + /// + /// + /// + [HttpGet("signature")] + public async Task GetQrCodeSignatureAsync(long detailId) + { + return await _eMealVoucherService.GetQrCodeSignatureAsync(detailId); + } + + /// + /// 刷新url签名 + /// + /// + [HttpPost("signature/refresh")] + public async Task RefreshSignatureAsync(long detailId) + { + await _eMealVoucherService.RefreshSignatureAsync(detailId); + } + + /// + /// 获取二维码 + /// + /// + /// + [AllowAnonymous] + [HttpGet("qrcode")] + public async Task GetQrCodeAsync(string signature) + { + return await _eMealVoucherService.GetQrCodeAsync(signature); + } } \ No newline at end of file diff --git a/Src/Dlhis.Canteen/EMealVoucher/Request/EMealVoucherPageRequest.cs b/Src/Dlhis.Canteen/EMealVoucher/Request/EMealVoucherPageRequest.cs new file mode 100644 index 00000000..d23ddad0 --- /dev/null +++ b/Src/Dlhis.Canteen/EMealVoucher/Request/EMealVoucherPageRequest.cs @@ -0,0 +1,7 @@ +using Kurisu.AspNetCore.DataAccess.Dto; + +namespace Dlhis.Canteen.EMealVoucher.Request; + +public class EMealVoucherPageRequest : PageDto +{ +} \ No newline at end of file diff --git a/Src/Dlhis.Canteen/EMealVoucher/Response/EMealVoucherDetailResponse.cs b/Src/Dlhis.Canteen/EMealVoucher/Response/EMealVoucherDetailResponse.cs new file mode 100644 index 00000000..03656071 --- /dev/null +++ b/Src/Dlhis.Canteen/EMealVoucher/Response/EMealVoucherDetailResponse.cs @@ -0,0 +1,31 @@ +namespace Dlhis.Canteen.EMealVoucher.Response; + +public class EMealVoucherDetailResponse +{ + public long Id { get; set; } + + /// + /// 用餐人 + /// + public string Name { get; set; } + + /// + /// 手机号 + /// + public string Phone { get; set; } + + /// + /// 就餐开始 + /// + public DateTime Start { get; set; } + + /// + /// 就餐结束 + /// + public DateTime End { get; set; } + + /// + /// 金额 + /// + public decimal Balance { get; set; } +} \ No newline at end of file diff --git a/Src/Dlhis.Canteen/EMealVoucher/Response/EMealVoucherPageResponse.cs b/Src/Dlhis.Canteen/EMealVoucher/Response/EMealVoucherPageResponse.cs new file mode 100644 index 00000000..c35caac3 --- /dev/null +++ b/Src/Dlhis.Canteen/EMealVoucher/Response/EMealVoucherPageResponse.cs @@ -0,0 +1,12 @@ +namespace Dlhis.Canteen.EMealVoucher.Response; + +public class EMealVoucherPageResponse +{ + public long Id { get; set; } + + public string No { get; set; } + + public string Title { get; set; } + + public DateTime Date { get; set; } +} \ No newline at end of file diff --git a/Src/Dlhis.Canteen/EMealVoucher/Services/IEMealVoucherService.cs b/Src/Dlhis.Canteen/EMealVoucher/Services/IEMealVoucherService.cs new file mode 100644 index 00000000..ef41f70a --- /dev/null +++ b/Src/Dlhis.Canteen/EMealVoucher/Services/IEMealVoucherService.cs @@ -0,0 +1,18 @@ +using Dlhis.Canteen.EMealVoucher.Request; +using Dlhis.Canteen.EMealVoucher.Response; +using Kurisu.AspNetCore.DataAccess.Dto; + +namespace Dlhis.Canteen.EMealVoucher.Services; + +public interface IEMealVoucherService : IScopeDependency +{ + Task> GetMyEMealVoucherPageAsync(EMealVoucherPageRequest request); + + Task> GetDetailsByNoAsync(string no); + + Task GetQrCodeSignatureAsync(long detailId); + + Task RefreshSignatureAsync(long detailId); + + Task GetQrCodeAsync(string signature); +} \ No newline at end of file diff --git a/Src/Dlhis.Canteen/EMealVoucher/Services/Implements/EMealVoucherService.cs b/Src/Dlhis.Canteen/EMealVoucher/Services/Implements/EMealVoucherService.cs new file mode 100644 index 00000000..c00c2fa1 --- /dev/null +++ b/Src/Dlhis.Canteen/EMealVoucher/Services/Implements/EMealVoucherService.cs @@ -0,0 +1,106 @@ +using System.Text; +using Dlhis.Canteen.EMealVoucher.Request; +using Dlhis.Canteen.EMealVoucher.Response; +using Dlhis.Entity.Canteen.Entities; +using Kurisu.AspNetCore.Authentication.Abstractions; +using Kurisu.AspNetCore.DataAccess.Dto; +using Kurisu.AspNetCore.DataAccess.SqlSugar.Extensions; +using Kurisu.AspNetCore.DataAccess.SqlSugar.Services; +using Kurisu.AspNetCore.Utils.Extensions; +using SqlSugar; + +namespace Dlhis.Canteen.EMealVoucher.Services.Implements; + +public class EMealVoucherService : IEMealVoucherService +{ + private readonly IDbContext _dbContext; + private readonly ICurrentUser _currentUser; + + public EMealVoucherService(IDbContext dbContext, ICurrentUser currentUser) + { + _dbContext = dbContext; + _currentUser = currentUser; + } + + + public async Task> GetMyEMealVoucherPageAsync(EMealVoucherPageRequest request) + { + var code = _currentUser.GetUserClaim("jinko-code"); + code = "0123456"; + return await _dbContext.Queryable() + .Where(x => x.Code == code) + .OrderBy(x => x.Id, OrderByType.Desc) + .Select() + .ToPageListAsync(request); + } + + + public async Task> GetDetailsByNoAsync(string no) + { + return await _dbContext.Queryable() + .Where(x => x.No == no) + .Select() + .ToListAsync(); + } + + + public async Task GetQrCodeSignatureAsync(long detailId) + { + return await GenerateSignatureAsync(detailId, false); + } + + public async Task RefreshSignatureAsync(long detailId) + { + await GenerateSignatureAsync(detailId, true); + } + + private async Task GenerateSignatureAsync(long detailId, bool isRefresh) + { + var eMealVoucherDetail = await _dbContext.Queryable().Where(x => x.Id == detailId).SingleAsync(); + eMealVoucherDetail.ThrowIfNull("数据不存在"); + if (eMealVoucherDetail.Signature.IsPresent()) + { + if (isRefresh) + { + await _dbContext.Deleteable().Where(x => x.Signature == eMealVoucherDetail.Signature).ExecuteCommandAsync(); + } + else + { + return eMealVoucherDetail.Signature; + } + } + + eMealVoucherDetail.Signature = Guid.NewGuid().ToString().Replace("-", "") + DateTimeOffset.Now.ToUnixTimeMilliseconds(); + await _dbContext.UpdateAsync(eMealVoucherDetail); + + return eMealVoucherDetail.Signature; + } + + /// + public async Task GetQrCodeAsync(string signature) + { + var eMealVoucherDetail = await _dbContext.Queryable().Where(x => x.Signature == signature).SingleAsync(); + eMealVoucherDetail.ThrowIfNull("无效地址"); + var eMealVoucher = await _dbContext.Queryable().Where(x => x.No == eMealVoucherDetail.No).SingleAsync(); + + var ts = DateTimeOffset.Now.ToUnixTimeMilliseconds().ToString().Reverse().Join(string.Empty); + var originData = string.Concat(eMealVoucher.No, ":", ts, ":", eMealVoucher.Code, ":", eMealVoucherDetail.IdNo); + + var qrCode = "02" + originData.ToArray().Select(x => + { + var b = Encoding.ASCII.GetBytes(x.ToString()); + int i = b[0]; + return Convert.ToString(i); + }).Join(string.Empty); + + + await _dbContext.InsertAsync(new EMealVoucherDetailQrCodeEntity + { + Signature = signature, + OriginData = originData, + QrCode = qrCode + }); + + return qrCode; + } +} \ No newline at end of file diff --git a/Src/Dlhis.Canteen/MealSupplementRecord/Services/Implements/MealSupplementRecordService.cs b/Src/Dlhis.Canteen/MealSupplementRecord/Services/Implements/MealSupplementRecordService.cs index 70e94176..6bb57af2 100644 --- a/Src/Dlhis.Canteen/MealSupplementRecord/Services/Implements/MealSupplementRecordService.cs +++ b/Src/Dlhis.Canteen/MealSupplementRecord/Services/Implements/MealSupplementRecordService.cs @@ -174,7 +174,6 @@ public class MealSupplementRecordService : IMealSupplementRecordService Source = BalanceRecordSourceEnumType.LocalTenantSubsidies, Remark = "期初导入", CostId = gainfo.CostId, - SubsidiesFromMonth = today.ToString("yyyyMM"), OriginTenantId = gainfo.Factory, Werks = gainfo.Werks, Name = gainfo.Name, diff --git a/Src/Dlhis.Canteen/Order/Dto/OrderPreCheckDto.cs b/Src/Dlhis.Canteen/Order/Dto/OrderPreCheckDto.cs new file mode 100644 index 00000000..6667755e --- /dev/null +++ b/Src/Dlhis.Canteen/Order/Dto/OrderPreCheckDto.cs @@ -0,0 +1,16 @@ +using Dlhis.Entity.Basic.Entity; + +namespace Dlhis.Canteen.Order.Dto +{ + public class OrderPreCheckDto + { + public DateTime CostDate { get; set; } + public BusinessShiftMealRelationshipEntity Shift { get; set; } + + public string BusinessPlaceTenantId { get; set; } + + public Guid BusinessPlaceCode { get; set; } + + public Guid BusinessShiftCode { get; set; } + } +} \ No newline at end of file diff --git a/Src/Dlhis.Canteen/Order/Services/Implements/BalanceService.cs b/Src/Dlhis.Canteen/Order/Services/Implements/BalanceService.cs index cd1cc6a6..a83c3107 100644 --- a/Src/Dlhis.Canteen/Order/Services/Implements/BalanceService.cs +++ b/Src/Dlhis.Canteen/Order/Services/Implements/BalanceService.cs @@ -482,7 +482,6 @@ public class BalanceService : IBalanceService ShiftType = null, CostDate = DateTime.Now.Date, DeviceUniqueNo = null, - SubsidiesFromMonth = DateTime.Now.ToString("yyyyMM"), IP = null, CostId = gainfo.CostId, OriginTenantId = gainfo.Factory, diff --git a/Src/Dlhis.Canteen/Order/Services/Implements/BookingOrderService.cs b/Src/Dlhis.Canteen/Order/Services/Implements/BookingOrderService.cs index 17054b7b..afff04cd 100644 --- a/Src/Dlhis.Canteen/Order/Services/Implements/BookingOrderService.cs +++ b/Src/Dlhis.Canteen/Order/Services/Implements/BookingOrderService.cs @@ -71,7 +71,6 @@ public class BookingOrderService : BaseOrderService, IBookingOrderService DeliveryAddress = request.DeliveryAddress, No = SnowFlakeHelper.Instance.NextId().ToString(), - SubsidiesFromMonth = now.ToString("yyyyMM"), IsOffline = false, IsCostCrossTenant = await GetSettingAsync(gainfo.No, businessPlace.TenantId, CanteenSettingItemEnumType.AllowCrossTenant), diff --git a/Src/Dlhis.Canteen/Order/Services/Implements/HainingBalanceService.cs b/Src/Dlhis.Canteen/Order/Services/Implements/HainingBalanceService.cs index fd0e9fea..46ac4779 100644 --- a/Src/Dlhis.Canteen/Order/Services/Implements/HainingBalanceService.cs +++ b/Src/Dlhis.Canteen/Order/Services/Implements/HainingBalanceService.cs @@ -75,7 +75,6 @@ public class HainingBalanceService : IHainingBalanceService Source = request.Source, Remark = request.Remark, CostId = gainfo.CostId, - SubsidiesFromMonth = request.CostDate.ToString("yyyyMM"), TenantId = businessPlaceInfo?.TenantId ?? request.Factory, OriginTenantId = gainfo.Factory, Werks = gainfo.Werks, diff --git a/Src/Dlhis.Canteen/Order/Services/Implements/OrderService.cs b/Src/Dlhis.Canteen/Order/Services/Implements/OrderService.cs index 8edc15fa..e94823f6 100644 --- a/Src/Dlhis.Canteen/Order/Services/Implements/OrderService.cs +++ b/Src/Dlhis.Canteen/Order/Services/Implements/OrderService.cs @@ -1,4 +1,5 @@ using System.Diagnostics; +using Dlhis.Canteen.Order.Dto; using Dlhis.Canteen.Setting.Services; using Dlhis.Entity.Basic.Entity; using Dlhis.Entity.Canteen.Entities; @@ -161,7 +162,11 @@ public class OrderService : BaseOrderService, IOrderService } else if (request.UserUniqueNo.StartsWith("02")) { - request.Source = BalanceRecordSourceEnumType.EVoucher; + 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(); } } else @@ -180,8 +185,7 @@ public class OrderService : BaseOrderService, IOrderService { gainfo.ThrowIfNull("无法识别,无权消费"); } - - if (request.IsOffline) + else { //兼容hpt尚未删除人员后产生的消费数据 gainfo ??= await DbContext.Queryable().AS("GainfoLeave") @@ -305,7 +309,6 @@ public class OrderService : BaseOrderService, IOrderService _logs.Add("消费请求校验:" + _sw.ElapsedMilliseconds); _sw.Restart(); - await CommonHelper.RetryAsync(async () => { var gainfoMeal = await DbContext.Queryable().Where(x => x.UserNo == order.UserNo).SingleAsync(); @@ -329,42 +332,6 @@ public class OrderService : BaseOrderService, IOrderService _sw.Restart(); } - /// - /// 根据二维码获取消费用户 - /// - /// - /// - private async Task GetUserByQrCodeAsync(string qrCode) - { - var gainfoQrCode = await DbContext.Queryable().Where(x => x.QrCode == qrCode).SingleAsync(); - gainfoQrCode.ThrowIfNull("消费码已过期"); - (gainfoQrCode.ModifiedTime.AddMinutes(60) < DateTime.Now).ThrowIfTrue("消费码已过期"); - - return await DbContext.Queryable().Where(x => x.Code == gainfoQrCode.UserCode).SingleAsync(); - } - - - /// - /// 检查是否可以离线消费 - /// - /// - /// - private async Task ToCheckAbleOfflineConsumeAsync(string thirdNo) - { - var order = await DbContext.Queryable() - .Where(x => x.ThirdNo == thirdNo) - .OrderBy(x => x.CreateTime, OrderByType.Desc) - .FirstAsync(); - - if (order == null) - { - return true; - } - - //存在在线order数据,但是状态未成功 - return !order.IsOffline && order.OrderStatus != CanteenOrderStatusEnumType.Success; - } - /// /// 离线消费处理 /// @@ -418,7 +385,6 @@ public class OrderService : BaseOrderService, IOrderService DeviceUniqueNo = request.DeviceUniqueNo, No = SnowFlakeHelper.Instance.NextId().ToString(), - SubsidiesFromMonth = request.CostDateTime.ToString("yyyyMM"), IsOffline = request.IsOffline, IsCostCrossTenant = businessPlaceInfo!.TenantId != gainfo.Factory, @@ -492,8 +458,6 @@ public class OrderService : BaseOrderService, IOrderService device.ThrowIfNull("设备尚未登记"); device.Enable.ThrowIfFalse("设备已被停用"); - (request.Source == BalanceRecordSourceEnumType.QrCode && device.TenantId != gainfo.Factory).ThrowIfTrue("二维码在此设备禁止消费"); - var businessPlaceInfo = await DbContext.Queryable() .LeftJoin((x, sr) => x.Code == sr.PlaceCode) .Where(x => x.Code == registry.BusinessPlaceCode) @@ -523,6 +487,8 @@ public class OrderService : BaseOrderService, IOrderService var costDate = await GetCostDateAsync(shift, request.CostDateTime); + (request.Source == BalanceRecordSourceEnumType.QrCode && businessPlaceInfo.TenantId != gainfo.Factory).ThrowIfTrue("禁止跨厂区消费"); + var order = new CanteenOrderEntity { RequestJson = request.ToJson(), @@ -543,9 +509,8 @@ public class OrderService : BaseOrderService, IOrderService DeviceUniqueNo = request.DeviceUniqueNo, No = SnowFlakeHelper.Instance.NextId().ToString(), - SubsidiesFromMonth = request.CostDateTime.ToString("yyyyMM"), IsOffline = request.IsOffline, - IsCostCrossTenant = await GetSettingAsync(gainfo.No, businessPlaceInfo!.TenantId, CanteenSettingItemEnumType.AllowCrossTenant), + IsCostCrossTenant = gainfo.Factory != businessPlaceInfo!.TenantId, OriginTenantId = gainfo.Factory, Werks = gainfo.Werks, @@ -610,17 +575,29 @@ public class OrderService : BaseOrderService, IOrderService /// private async Task ToDoAsync(OrderAddRequest request, GainfoEntity gainfo) { - var message = ""; - if (request.IsOffline) - { - if (request.ThirdNo.IsPresent()) - { - var redisCache = _serviceProvider.GetService(); + var message = string.Empty; - await using var handler = await redisCache.LockAsync($"consume:device:{request.ThirdNo}"); - if (handler.Acquired) + if (request.Source == BalanceRecordSourceEnumType.EMealVoucher) + { + try + { + await EMealVoucherConsumeAsync(request.Adapt(), gainfo); + } + catch (Exception ex) + { + message = ex.Message; + } + } + else + { + if (request.IsOffline) + { + if (request.ThirdNo.IsPresent()) { - if (await ToCheckAbleOfflineConsumeAsync(request.ThirdNo)) + var redisCache = _serviceProvider.GetService(); + + await using var handler = await redisCache.LockAsync($"consume:device:{request.ThirdNo}"); + if (handler.Acquired && await ToCheckAbleOfflineConsumeAsync(request.ThirdNo)) { try { @@ -632,32 +609,219 @@ public class OrderService : BaseOrderService, IOrderService } } } + else + { + try + { + await HandleOfflineAsync(request.Adapt(), gainfo); + } + catch (Exception ex) + { + Logger.LogError(ex, "离线入库错误: 订单号:{no} .{message}", request.ThirdNo, ex.Message); + } + } } else { try { - await HandleOfflineAsync(request.Adapt(), gainfo); + (await DbContext.Queryable().Where(x => x.UserCode == gainfo.Code).AnyAsync()).ThrowIfFalse("就餐余额不足"); + await ConsumeAsync(request.Adapt(), gainfo); } catch (Exception ex) { - Logger.LogError(ex, "离线入库错误: 订单号:{no} .{message}", request.ThirdNo, ex.Message); + message = ex.Message; } } } - else - { - try - { - (await DbContext.Queryable().Where(x => x.UserCode == gainfo.Code).AnyAsync()).ThrowIfFalse("就餐余额不足"); - await ConsumeAsync(request.Adapt(), gainfo); - } - catch (Exception ex) - { - message = ex.Message; - } - } return message; + + async Task ToCheckAbleOfflineConsumeAsync(string thirdNo) + { + var order = await DbContext.Queryable() + .Where(x => x.ThirdNo == thirdNo) + .OrderBy(x => x.CreateTime, OrderByType.Desc) + .FirstAsync(); + + if (order == null) + { + return true; + } + + //存在在线order数据,但是状态未成功 + return !order.IsOffline && order.OrderStatus != CanteenOrderStatusEnumType.Success; + } + } + + /// + /// 根据二维码获取消费用户 + /// + /// + /// + private async Task GetUserByQrCodeAsync(string qrCode) + { + var gainfoQrCode = await DbContext.Queryable().Where(x => x.QrCode == qrCode).SingleAsync(); + gainfoQrCode.ThrowIfNull("消费码已过期"); + (gainfoQrCode.ModifiedTime.AddMinutes(60) < DateTime.Now).ThrowIfTrue("消费码已过期"); + + return await DbContext.Queryable().Where(x => x.Code == gainfoQrCode.UserCode).SingleAsync(); + } + + + private async Task EMealVoucherConsumeAsync(ConsumeRequest request, GainfoEntity gainfo) + { + var eMealVoucherQrCode = await DbContext.Queryable().Where(x => x.QrCode == request.UserUniqueNo).SingleAsync(); + var originData = eMealVoucherQrCode.OriginData.Split(':'); + + var no = originData[0]; + var idNo = originData[3]; + var nowDate = DateTime.Now.Date; + var current = await DbContext.Queryable() + .Where(x => x.No == no && x.IdNo == idNo).SingleAsync(); + (nowDate >= current.Start && nowDate <= current.End).ThrowIfFalse("餐券已过期"); + + var time = DateTimeOffset.FromUnixTimeMilliseconds(Convert.ToInt64(originData[1].Reverse().Join(string.Empty))).ToLocalTime().DateTime; + (time.AddMinutes(60) >= DateTime.Now).ThrowIfFalse("二维码已过期"); + + var eMealVoucher = await DbContext.Queryable().Where(x => x.No == no).SingleAsync(); + + var checkData = await PreCheckAsync(request.DeviceUniqueNo, request.CostDateTime); + eMealVoucher.Factories.Contains(checkData.BusinessPlaceTenantId).ThrowIfFalse("禁止在当前厂区消费"); + + _logs.Add("检验设备和营业点参数:" + _sw.ElapsedMilliseconds); + _sw.Restart(); + + var order = new CanteenOrderEntity + { + RequestJson = request.ToJson(), + ThirdNo = request.ThirdNo, + Type = BalanceRecordTypeEnumType.Out, + ApplicationType = CanteenApplicationTypeEnumType.Device, + Name = gainfo.Name, + Source = request.Source, + UserNo = eMealVoucherQrCode.OriginData, //记录为当前消费券 + UserCode = gainfo.Code, + Amount = request.Amount, + BusinessPlaceCode = checkData.BusinessPlaceCode, + BusinessShiftCode = checkData.BusinessShiftCode, + ShiftType = checkData.Shift.ShiftType, + CostDate = checkData.CostDate, + CostId = gainfo.CostId, + DepartmentNo = gainfo.DepartmentNo, + DeviceUniqueNo = request.DeviceUniqueNo, + + No = SnowFlakeHelper.Instance.NextId().ToString(), + IsOffline = false, + IsCostCrossTenant = gainfo.Factory != checkData.BusinessPlaceTenantId, + + OriginTenantId = gainfo.Factory, + Werks = gainfo.Werks, + Status = BalanceRecordStatusEnumType.Valid, + OrderStatus = CanteenOrderStatusEnumType.Wait, + CostDateTime = request.CostDateTime, + //标识当前消费的基地 + TenantId = checkData.BusinessPlaceTenantId, + }; + + var orderId = await DbContext.InsertReturnIdentityAsync(order); + _logs.Add("临时order写入:" + _sw.ElapsedMilliseconds); + _sw.Restart(); + + try + { + await CommonHelper.RetryAsync(async () => + { + var detail = await DbContext.Queryable().Where(x => x.No == no && x.IdNo == idNo).SingleAsync(); + //金额+- + detail.Balance += order.Amount; + (detail.Balance < 0).ThrowIfTrue("余额不足,无法消费"); + + await DbContext.Updateable() + .SetColumns(x => x.Balance == detail.Balance) + .SetColumns(x => x.Version == x.Version + 1) + .SetColumns(x => x.ModifiedTime == DateTime.Now) + .Where(x => x.No == no && x.IdNo == idNo && x.Version == detail.Version) //必须与查询时的version一致 + .ExecuteCommandThrowVersionAsync(); + + //写入记录 + var balanceRecord = order.Adapt(); + await DbContext.InsertAsync(balanceRecord); + }, 5); + + _logs.Add("消费写入:" + _sw.ElapsedMilliseconds); + _sw.Restart(); + + await DbContext.Updateable() + .SetColumns(x => x.OrderStatus == CanteenOrderStatusEnumType.Success) + .SetColumns(x => x.ModifiedTime == DateTime.Now) + .Where(x => x.Id == orderId) + .ExecuteCommandAsync(); + + _logs.Add("更新image和订单信息:" + _sw.ElapsedMilliseconds); + _sw.Restart(); + } + catch (Exception ex) + { + await DbContext.Updateable() + .SetColumns(x => x.OrderStatus == CanteenOrderStatusEnumType.Failure) + .SetColumns(x => x.Result == ex.Message) + .SetColumns(x => x.ModifiedTime == DateTime.Now) + .Where(x => x.Id == orderId) + .ExecuteCommandAsync(); + + throw; + } + } + + /// + /// 消费前预检 + /// + /// + /// + /// + private async Task PreCheckAsync(string deviceUniqueNo, DateTime costDateTime) + { + var registry = await DbContext.Queryable().Where(x => x.DeviceUniqueNo == deviceUniqueNo).SingleAsync(); + registry.ThrowIfNull("设备尚未登记"); + + var device = await DbContext.Queryable().Where(x => x.UniqueNo == deviceUniqueNo).SingleAsync(); + device.ThrowIfNull("设备尚未登记"); + device.Enable.ThrowIfFalse("设备已被停用"); + + var businessPlaceInfo = await DbContext.Queryable() + .LeftJoin((x, sr) => x.Code == sr.PlaceCode) + .Where(x => x.Code == registry.BusinessPlaceCode) + .Select((x, sr) => new + { + x.Code, + sr.ShiftCode, + x.TenantId + }) + .SingleAsync(); + + businessPlaceInfo.ThrowIfNull("设备尚未登记营业点"); + + //获取当前消费餐次 + var shifts = await DbContext.Queryable().Where(x => x.ShiftCode == businessPlaceInfo.ShiftCode).ToListAsync(); + shifts.ThrowIfEmpty("营业点餐次尚未设置"); + + var shift = shifts.FirstOrDefault(x => new TimePeriod + { + Start = x.Start, + End = x.End + }.IsPresent(costDateTime)); + shift.ThrowIfNull("非就餐时间,无法消费"); + + var costDate = await GetCostDateAsync(shift, costDateTime); + + return new OrderPreCheckDto + { + CostDate = costDate, + Shift = shift, + BusinessPlaceTenantId = businessPlaceInfo.TenantId, + BusinessPlaceCode = businessPlaceInfo.Code, + BusinessShiftCode = businessPlaceInfo.ShiftCode + }; } } \ No newline at end of file diff --git a/Src/Dlhis.Entity/Canteen/Entities/BalanceRecordEntity.cs b/Src/Dlhis.Entity/Canteen/Entities/BalanceRecordEntity.cs index b5874947..a3fdedda 100644 --- a/Src/Dlhis.Entity/Canteen/Entities/BalanceRecordEntity.cs +++ b/Src/Dlhis.Entity/Canteen/Entities/BalanceRecordEntity.cs @@ -91,12 +91,6 @@ public class BalanceRecordEntity : SugarBaseEntity, ISoftDeleted, ITenantId [SugarColumn(ColumnDescription = "消费机器唯一信息", IsNullable = true)] public string DeviceUniqueNo { get; set; } - /// - /// 餐补月份 - /// - [SugarColumn(ColumnDescription = "餐补月份")] - public string SubsidiesFromMonth { get; set; } - /// /// Ip /// diff --git a/Src/Dlhis.Entity/Canteen/Entities/EMealVoucherDetailEntity.cs b/Src/Dlhis.Entity/Canteen/Entities/EMealVoucherDetailEntity.cs index b41f0533..35a963b2 100644 --- a/Src/Dlhis.Entity/Canteen/Entities/EMealVoucherDetailEntity.cs +++ b/Src/Dlhis.Entity/Canteen/Entities/EMealVoucherDetailEntity.cs @@ -1,4 +1,5 @@ -using Kurisu.AspNetCore.DataAccess.SqlSugar; +using Kurisu.AspNetCore.DataAccess.Entity; +using Kurisu.AspNetCore.DataAccess.SqlSugar; using SqlSugar; namespace Dlhis.Entity.Canteen.Entities; @@ -7,7 +8,7 @@ namespace Dlhis.Entity.Canteen.Entities; /// 电子餐券明细 /// [SugarTable(TableName = "EMealVoucherDetail", TableDescription = "电子餐券明细")] -public class EMealVoucherDetailEntity : SugarBaseEntity +public class EMealVoucherDetailEntity : SugarBaseEntity, IVersion { /// /// 主表id @@ -18,7 +19,7 @@ public class EMealVoucherDetailEntity : SugarBaseEntity /// /// 流水号 /// - [SugarColumn(ColumnDescription = "流水号")] + [SugarColumn(ColumnDescription = "流水号", UniqueGroupNameList = new[] { "idx_EMealVoucherDetail_no_idno" })] public string No { get; set; } /// @@ -30,7 +31,7 @@ public class EMealVoucherDetailEntity : SugarBaseEntity /// /// 身份证 /// - [SugarColumn(ColumnDescription = "序号")] + [SugarColumn(ColumnDescription = "证件号", UniqueGroupNameList = new[] { "idx_EMealVoucherDetail_no_idno" })] public string IdNo { get; set; } /// @@ -60,6 +61,16 @@ public class EMealVoucherDetailEntity : SugarBaseEntity /// /// 金额 /// - [SugarColumn(ColumnDescription = "金额", ColumnDataType = "decimal(16,2)")] - public decimal Amount { get; set; } + [SugarColumn(ColumnDescription = "余额", ColumnDataType = "decimal(16,2)")] + public decimal Balance { get; set; } + + /// + /// 版本 + /// + [SugarColumn(ColumnDescription = "版本")] + public int Version { get; set; } + + + [SugarColumn(ColumnDataType = "varchar(255)")] + public string Signature { get; set; } } \ No newline at end of file diff --git a/Src/Dlhis.Entity/Canteen/Entities/EMealVoucherDetailQrCodeEntity.cs b/Src/Dlhis.Entity/Canteen/Entities/EMealVoucherDetailQrCodeEntity.cs new file mode 100644 index 00000000..b1a6b505 --- /dev/null +++ b/Src/Dlhis.Entity/Canteen/Entities/EMealVoucherDetailQrCodeEntity.cs @@ -0,0 +1,29 @@ +using Kurisu.AspNetCore.DataAccess.SqlSugar; +using SqlSugar; + +namespace Dlhis.Entity.Canteen.Entities; + +/// +/// 电子餐券明细QrCode +/// +[SugarTable(TableName = "EMealVoucherDetailQrCode", TableDescription = "电子餐券明细QrCode")] +public class EMealVoucherDetailQrCodeEntity : SugarBaseEntity +{ + /// + /// url签名 + /// + [SugarColumn(ColumnDataType = "varchar(255)", IndexGroupNameList = new[] { "idx_EMealVoucherDetailQrCode_signature" })] + public string Signature { get; set; } + + /// + /// 原始数据 + /// + [SugarColumn(ColumnDescription = "原始数据")] + public string OriginData { get; set; } + + /// + /// 二维码 + /// + [SugarColumn(ColumnDescription = "二维码", UniqueGroupNameList = new[] { "idx_EMealVoucherDetailQrCode_qrcode" })] + public string QrCode { get; set; } +} \ No newline at end of file diff --git a/Src/Dlhis.Entity/Canteen/Enums/BalanceRecordSourceEnumType.cs b/Src/Dlhis.Entity/Canteen/Enums/BalanceRecordSourceEnumType.cs index 587169b8..79d86f43 100644 --- a/Src/Dlhis.Entity/Canteen/Enums/BalanceRecordSourceEnumType.cs +++ b/Src/Dlhis.Entity/Canteen/Enums/BalanceRecordSourceEnumType.cs @@ -36,7 +36,7 @@ public enum BalanceRecordSourceEnumType /// 电子餐券 /// [Description("电子餐券")] - EVoucher, + EMealVoucher, //********************************************************************************************************* /// diff --git a/Src/Dlhis.External/EMealVoucher/Request/EMealVoucherReceiveRequest.cs b/Src/Dlhis.External/EMealVoucher/Request/EMealVoucherReceiveRequest.cs index 86f3aa3f..76597552 100644 --- a/Src/Dlhis.External/EMealVoucher/Request/EMealVoucherReceiveRequest.cs +++ b/Src/Dlhis.External/EMealVoucher/Request/EMealVoucherReceiveRequest.cs @@ -82,6 +82,11 @@ public class EMealVoucherReceiveRequest : IValidatableObject { yield return new ValidationResult("来宾数量不匹配", new[] { nameof(Number) }); } + + if (Details.DistinctBy(x => x.IdNo).Count() != Details.Count) + { + yield return new ValidationResult("证件信息重复", new[] { "IdNo" }); + } } } diff --git a/Src/Dlhis.External/EMealVoucher/Services/Implements/EMealVoucherService.cs b/Src/Dlhis.External/EMealVoucher/Services/Implements/EMealVoucherService.cs index 9e12372a..a956a612 100644 --- a/Src/Dlhis.External/EMealVoucher/Services/Implements/EMealVoucherService.cs +++ b/Src/Dlhis.External/EMealVoucher/Services/Implements/EMealVoucherService.cs @@ -43,7 +43,7 @@ public class EMealVoucherService : IEMealVoucherService Phone = x.Phone, Start = x.Start, End = x.End, - Amount = x.Amount + Balance = x.Amount }).ToList(); var id = await _dbContext.InsertReturnIdentityAsync(voucher); diff --git a/Src/Dlhis.Middle/Services/Implements/OrderService.cs b/Src/Dlhis.Middle/Services/Implements/OrderService.cs index 98126066..a632b1c5 100644 --- a/Src/Dlhis.Middle/Services/Implements/OrderService.cs +++ b/Src/Dlhis.Middle/Services/Implements/OrderService.cs @@ -171,7 +171,6 @@ public class OrderService : IOrderService DeviceUniqueNo = request.DeviceUniqueNo, No = _factory + "-" + SnowFlakeHelper.Instance.NextId(), - SubsidiesFromMonth = request.CostDateTime.ToString("yyyyMM"), // IsOffline = request.IsOffline, IsCostCrossTenant = await GetSettingAsync(businessPlaceInfo!.TenantId, CanteenSettingItemEnumType.AllowCrossTenant), diff --git a/Src/Dlhis.ScheduledTask/Jobs/MealSupplementHandlerJob.cs b/Src/Dlhis.ScheduledTask/Jobs/MealSupplementHandlerJob.cs index 0f288bd5..1a3698ca 100644 --- a/Src/Dlhis.ScheduledTask/Jobs/MealSupplementHandlerJob.cs +++ b/Src/Dlhis.ScheduledTask/Jobs/MealSupplementHandlerJob.cs @@ -156,7 +156,6 @@ public class MealSupplementHandlerJob : BaseJob Source = BalanceRecordSourceEnumType.LocalTenantSubsidies, Remark = mealSupplement.UniqueId + ":" + mealSupplement.Remark, CostId = gainfo.CostId, - SubsidiesFromMonth = mealSupplement.Date.ToString("yyyyMM"), OriginTenantId = gainfo.Factory, Werks = gainfo.Werks, Name = gainfo.Name, diff --git a/Src/Gateway/Program.cs b/Src/Gateway/Program.cs index e96a2582..c8fd2e8b 100644 --- a/Src/Gateway/Program.cs +++ b/Src/Gateway/Program.cs @@ -1,4 +1,3 @@ - using Gateway; public class Program @@ -8,13 +7,14 @@ public class Program Host.CreateDefaultBuilder(args) .ConfigureAppConfiguration((context, builder) => { - builder.AddJsonFile("ocelot.json", true, true); + if (context.HostingEnvironment.IsProduction()) + { + builder.AddJsonFile("ocelot.json", true, true); + } + builder.AddJsonFile($"ocelot.{context.HostingEnvironment.EnvironmentName}.json", true, true); }) - .ConfigureWebHostDefaults(webBuilder => - { - webBuilder.UseStartup(); - }) + .ConfigureWebHostDefaults(webBuilder => { webBuilder.UseStartup(); }) .Build().Run(); } -} +} \ No newline at end of file diff --git a/Src/Gateway/appsettings.json b/Src/Gateway/appsettings.json index 508d6f2a..d0e733e1 100644 --- a/Src/Gateway/appsettings.json +++ b/Src/Gateway/appsettings.json @@ -11,7 +11,6 @@ "Common", "Canteen", "Scheduled", - "User", "Sys", "Visitor", "Message" diff --git a/Src/Gateway/ocelot.Development.json b/Src/Gateway/ocelot.Development.json index e1aaacf0..45f461c0 100644 --- a/Src/Gateway/ocelot.Development.json +++ b/Src/Gateway/ocelot.Development.json @@ -72,7 +72,7 @@ "DownstreamScheme": "http", "DownstreamHostAndPorts": [ { - "Host": "localhost", + "Host": "192.168.199.115", "Port": 6000 } ] From e52cf0f37ad18f611c72061185632e4bb6519256 Mon Sep 17 00:00:00 2001 From: liguoyang Date: Wed, 14 Aug 2024 15:43:37 +0800 Subject: [PATCH 04/25] =?UTF-8?q?refactor=20=E4=BB=A3=E7=A0=81=E4=BC=98?= =?UTF-8?q?=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Order/Controllers/OrdersController.cs | 50 +------ .../Order/Services/Implements/OrderService.cs | 138 ++++++++---------- 2 files changed, 68 insertions(+), 120 deletions(-) diff --git a/Src/Dlhis.Canteen/Order/Controllers/OrdersController.cs b/Src/Dlhis.Canteen/Order/Controllers/OrdersController.cs index 51e0027c..59ab64b3 100644 --- a/Src/Dlhis.Canteen/Order/Controllers/OrdersController.cs +++ b/Src/Dlhis.Canteen/Order/Controllers/OrdersController.cs @@ -1,12 +1,10 @@ -using System.Diagnostics; -using Dlhis.Canteen.Dishes.Request; +using Dlhis.Canteen.Dishes.Request; using Dlhis.Canteen.Order.Request; using Dlhis.Canteen.Order.Response; using Dlhis.Canteen.Order.Services; using Kurisu.AspNetCore.DataAccess.Dto; using Kurisu.AspNetCore.DataAccess.SqlSugar.Aop; using Kurisu.AspNetCore.UnifyResultAndValidation; -using Kurisu.AspNetCore.Utils.Extensions; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; @@ -22,13 +20,11 @@ public class OrdersController : ControllerBase { private readonly IOrderService _orderService; private readonly IBookingOrderService _bookingOrderService; - private readonly ILogger _logger; - public OrdersController(IOrderService orderService, IBookingOrderService bookingOrderService, ILogger logger) + public OrdersController(IOrderService orderService, IBookingOrderService bookingOrderService) { _orderService = orderService; _bookingOrderService = bookingOrderService; - _logger = logger; } /// @@ -41,27 +37,8 @@ public class OrdersController : ControllerBase [IgnoreTenant] public async Task> AddAsync(OrderAddRequest request) { - var sw = Stopwatch.StartNew(); var result = await _orderService.AddAsync(request); - try - { - return result.Response; - } - finally - { - var ms = sw.ElapsedMilliseconds; - try - { - if (ms > 1000) - { - _logger.LogInformation("消费请求:{json}. 耗时记录:{log}", request.ToJson(), result.Logs.Join("\r\n")); - } - } - catch (Exception) - { - //ignore - } - } + return result.Response; } /// @@ -74,27 +51,8 @@ public class OrdersController : ControllerBase [IgnoreTenant] public async Task> DeviceConsume(OrderAddRequest request) { - var sw = Stopwatch.StartNew(); var result = await _orderService.AddAsync(request); - try - { - return result.Response; - } - finally - { - var ms = sw.ElapsedMilliseconds; - try - { - if (ms > 1000) - { - _logger.LogInformation("消费请求:{json}. 耗时记录:{log}", request.ToJson(), result.Logs.Join("\r\n")); - } - } - catch (Exception) - { - //ignore - } - } + return result.Response; } /// diff --git a/Src/Dlhis.Canteen/Order/Services/Implements/OrderService.cs b/Src/Dlhis.Canteen/Order/Services/Implements/OrderService.cs index e94823f6..d0c8b274 100644 --- a/Src/Dlhis.Canteen/Order/Services/Implements/OrderService.cs +++ b/Src/Dlhis.Canteen/Order/Services/Implements/OrderService.cs @@ -1,5 +1,4 @@ -using System.Diagnostics; -using Dlhis.Canteen.Order.Dto; +using Dlhis.Canteen.Order.Dto; using Dlhis.Canteen.Setting.Services; using Dlhis.Entity.Basic.Entity; using Dlhis.Entity.Canteen.Entities; @@ -24,8 +23,6 @@ namespace Dlhis.Canteen.Order.Services.Implements; public class OrderService : BaseOrderService, IOrderService { private readonly IServiceProvider _serviceProvider; - private Stopwatch _sw; - private readonly List _logs = new(); public OrderService(ICanteenSettingService canteenSettingService, IDbContext dbContext, @@ -54,44 +51,11 @@ public class OrderService : BaseOrderService, IOrderService /// public async Task AddAsync(OrderAddRequest request) { - _sw = new Stopwatch(); - var gainfo = await GetUserAsync(request); - _logs.Add("获取人员耗时:" + _sw.ElapsedMilliseconds); - _sw.Restart(); - - var message = await ToDoAsync(request, gainfo); - - //获取人员余额 - var data = await DbContext.Queryable() - .LeftJoin((x, ga) => x.UserNo == ga.No) - .LeftJoin((x, ga, department) => ga.DepartmentNo == department.No) - .Where(x => x.UserNo == gainfo.No) - .Select((x, ga, department) => new OrderResultResponse - { - UserCode = ga.Code, - UserName = ga.Name, - DepartmentNo = ga.DepartmentNo, - DepartmentName = department.Name, - CurrentBalance = x.Balance - }) - .SingleAsync(); - - var result = new DefaultApiResult - { - Code = message.IsPresent() ? ApiStateCode.Error : ApiStateCode.Success, - Data = data, - Msg = message - }; - - _logs.Add("获取余额:" + _sw.ElapsedMilliseconds); - _sw.Restart(); - return new OrderResultResponseWithLogs { - Response = result, - Logs = _logs + Response = await ToDoAsync(request, gainfo) }; } @@ -306,8 +270,6 @@ public class OrderService : BaseOrderService, IOrderService var order = await DbContext.Queryable().Where(x => x.Id == orderId).SingleAsync(); //校验 await Verify(order); - _logs.Add("消费请求校验:" + _sw.ElapsedMilliseconds); - _sw.Restart(); await CommonHelper.RetryAsync(async () => { @@ -327,9 +289,6 @@ public class OrderService : BaseOrderService, IOrderService var balanceRecord = order.Adapt(); await DbContext.InsertAsync(balanceRecord); }, 5); - - _logs.Add("消费写入:" + _sw.ElapsedMilliseconds); - _sw.Restart(); } /// @@ -482,9 +441,6 @@ public class OrderService : BaseOrderService, IOrderService }.IsPresent(request.CostDateTime)); shift.ThrowIfNull("非就餐时间,无法消费"); - _logs.Add("检验设备和营业点参数:" + _sw.ElapsedMilliseconds); - _sw.Restart(); - var costDate = await GetCostDateAsync(shift, request.CostDateTime); (request.Source == BalanceRecordSourceEnumType.QrCode && businessPlaceInfo.TenantId != gainfo.Factory).ThrowIfTrue("禁止跨厂区消费"); @@ -527,8 +483,6 @@ public class OrderService : BaseOrderService, IOrderService }; var orderId = await DbContext.InsertReturnIdentityAsync(order); - _logs.Add("临时order写入:" + _sw.ElapsedMilliseconds); - _sw.Restart(); try { @@ -549,9 +503,6 @@ public class OrderService : BaseOrderService, IOrderService .SetColumns(x => x.ModifiedTime == DateTime.Now) .Where(x => x.Id == orderId) .ExecuteCommandAsync(); - - _logs.Add("更新image和订单信息:" + _sw.ElapsedMilliseconds); - _sw.Restart(); } catch (Exception ex) { @@ -573,20 +524,55 @@ public class OrderService : BaseOrderService, IOrderService /// /// /// - private async Task ToDoAsync(OrderAddRequest request, GainfoEntity gainfo) + private async Task> ToDoAsync(OrderAddRequest request, GainfoEntity gainfo) { var message = string.Empty; if (request.Source == BalanceRecordSourceEnumType.EMealVoucher) { + var eMealVoucherQrCode = await DbContext.Queryable().Where(x => x.QrCode == request.UserUniqueNo).SingleAsync(); + if (eMealVoucherQrCode == null) + { + message = "无法识别"; + return new DefaultApiResult + { + Code = ApiStateCode.Error, + Data = null, + Msg = message + }; + } + + var originData = eMealVoucherQrCode.OriginData.Split(':'); + + var no = originData[0]; + var ts = originData[1]; + var idNo = originData[3]; + try { - await EMealVoucherConsumeAsync(request.Adapt(), gainfo); + await EMealVoucherConsumeAsync(request.Adapt(), gainfo, eMealVoucherQrCode.OriginData, no, ts, idNo); } catch (Exception ex) { message = ex.Message; } + + //获取餐券余额 + var data = await DbContext.Queryable() + .LeftJoin((x, d) => x.No == d.No) + .Where((x, d) => d.IdNo == idNo) + .Select((x, d) => new OrderResultResponse + { + CurrentBalance = d.Balance + }) + .SingleAsync(); + + return new DefaultApiResult + { + Code = message.IsPresent() ? ApiStateCode.Error : ApiStateCode.Success, + Data = data, + Msg = message + }; } else { @@ -633,9 +619,29 @@ public class OrderService : BaseOrderService, IOrderService message = ex.Message; } } - } - return message; + //获取人员余额 + var data = await DbContext.Queryable() + .LeftJoin((x, ga) => x.UserNo == ga.No) + .LeftJoin((x, ga, department) => ga.DepartmentNo == department.No) + .Where(x => x.UserNo == gainfo.No) + .Select((x, ga, department) => new OrderResultResponse + { + UserCode = ga.Code, + UserName = ga.Name, + DepartmentNo = ga.DepartmentNo, + DepartmentName = department.Name, + CurrentBalance = x.Balance + }) + .SingleAsync(); + + return new DefaultApiResult + { + Code = message.IsPresent() ? ApiStateCode.Error : ApiStateCode.Success, + Data = data, + Msg = message + }; + } async Task ToCheckAbleOfflineConsumeAsync(string thirdNo) { @@ -669,19 +675,14 @@ public class OrderService : BaseOrderService, IOrderService } - private async Task EMealVoucherConsumeAsync(ConsumeRequest request, GainfoEntity gainfo) + private async Task EMealVoucherConsumeAsync(ConsumeRequest request, GainfoEntity gainfo, string originData, string no, string ts, string idNo) { - var eMealVoucherQrCode = await DbContext.Queryable().Where(x => x.QrCode == request.UserUniqueNo).SingleAsync(); - var originData = eMealVoucherQrCode.OriginData.Split(':'); - - var no = originData[0]; - var idNo = originData[3]; var nowDate = DateTime.Now.Date; var current = await DbContext.Queryable() .Where(x => x.No == no && x.IdNo == idNo).SingleAsync(); (nowDate >= current.Start && nowDate <= current.End).ThrowIfFalse("餐券已过期"); - var time = DateTimeOffset.FromUnixTimeMilliseconds(Convert.ToInt64(originData[1].Reverse().Join(string.Empty))).ToLocalTime().DateTime; + var time = DateTimeOffset.FromUnixTimeMilliseconds(Convert.ToInt64(ts.Reverse().Join(string.Empty))).ToLocalTime().DateTime; (time.AddMinutes(60) >= DateTime.Now).ThrowIfFalse("二维码已过期"); var eMealVoucher = await DbContext.Queryable().Where(x => x.No == no).SingleAsync(); @@ -689,9 +690,6 @@ public class OrderService : BaseOrderService, IOrderService var checkData = await PreCheckAsync(request.DeviceUniqueNo, request.CostDateTime); eMealVoucher.Factories.Contains(checkData.BusinessPlaceTenantId).ThrowIfFalse("禁止在当前厂区消费"); - _logs.Add("检验设备和营业点参数:" + _sw.ElapsedMilliseconds); - _sw.Restart(); - var order = new CanteenOrderEntity { RequestJson = request.ToJson(), @@ -700,7 +698,7 @@ public class OrderService : BaseOrderService, IOrderService ApplicationType = CanteenApplicationTypeEnumType.Device, Name = gainfo.Name, Source = request.Source, - UserNo = eMealVoucherQrCode.OriginData, //记录为当前消费券 + UserNo = originData, //记录为当前消费券 UserCode = gainfo.Code, Amount = request.Amount, BusinessPlaceCode = checkData.BusinessPlaceCode, @@ -725,8 +723,6 @@ public class OrderService : BaseOrderService, IOrderService }; var orderId = await DbContext.InsertReturnIdentityAsync(order); - _logs.Add("临时order写入:" + _sw.ElapsedMilliseconds); - _sw.Restart(); try { @@ -749,17 +745,11 @@ public class OrderService : BaseOrderService, IOrderService await DbContext.InsertAsync(balanceRecord); }, 5); - _logs.Add("消费写入:" + _sw.ElapsedMilliseconds); - _sw.Restart(); - await DbContext.Updateable() .SetColumns(x => x.OrderStatus == CanteenOrderStatusEnumType.Success) .SetColumns(x => x.ModifiedTime == DateTime.Now) .Where(x => x.Id == orderId) .ExecuteCommandAsync(); - - _logs.Add("更新image和订单信息:" + _sw.ElapsedMilliseconds); - _sw.Restart(); } catch (Exception ex) { From 8803be54e9f7849b7424a00be481875eb3c77ae1 Mon Sep 17 00:00:00 2001 From: liguoyang Date: Tue, 13 Aug 2024 10:32:27 +0800 Subject: [PATCH 05/25] =?UTF-8?q?feat=20=E9=A4=90=E6=AC=A1=E5=B0=B1?= =?UTF-8?q?=E9=A4=90=E5=88=86=E6=9E=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Controllers/BalanceSummaryController.cs | 9 ++++ .../Order/Dto/ShiftSummaryDto.cs | 9 ++++ .../BalanceRecordAnalysisByShiftRequest.cs | 29 +++++++++++++ .../BalanceRecordAnalysisShiftResponse.cs | 20 +++++++++ .../Order/Services/IBalanceSummaryService.cs | 5 ++- .../Implements/BalanceSummaryService.cs | 42 ++++++++++++++++++- .../Menu/Controllers/MenusController.cs | 1 + 7 files changed, 113 insertions(+), 2 deletions(-) create mode 100644 Src/Dlhis.Canteen/Order/Dto/ShiftSummaryDto.cs create mode 100644 Src/Dlhis.Canteen/Order/Request/BalanceRecordAnalysisByShiftRequest.cs create mode 100644 Src/Dlhis.Canteen/Order/Response/BalanceRecordAnalysisShiftResponse.cs diff --git a/Src/Dlhis.Canteen/Order/Controllers/BalanceSummaryController.cs b/Src/Dlhis.Canteen/Order/Controllers/BalanceSummaryController.cs index 96e3cc09..4326f250 100644 --- a/Src/Dlhis.Canteen/Order/Controllers/BalanceSummaryController.cs +++ b/Src/Dlhis.Canteen/Order/Controllers/BalanceSummaryController.cs @@ -41,4 +41,13 @@ public class BalanceSummaryController : ControllerBase { return await _balanceSummaryService.BalanceRecordAnalysisByCostIdAsync(); } + + /// + /// 用餐分析(餐次) + /// + [HttpGet("analysis/shift")] + public async Task BalanceRecordAnalysisByShiftAsync([FromQuery] BalanceRecordAnalysisByShiftRequest request) + { + return await _balanceSummaryService.BalanceRecordAnalysisByShiftAsync(request); + } } \ No newline at end of file diff --git a/Src/Dlhis.Canteen/Order/Dto/ShiftSummaryDto.cs b/Src/Dlhis.Canteen/Order/Dto/ShiftSummaryDto.cs new file mode 100644 index 00000000..5dfa4954 --- /dev/null +++ b/Src/Dlhis.Canteen/Order/Dto/ShiftSummaryDto.cs @@ -0,0 +1,9 @@ +using Dlhis.Entity.Canteen.Enums; + +namespace Dlhis.Canteen.Order.Dto; + +public class ShiftSummaryDto +{ + public ShiftEnumType? Shift { get; set; } + public T Value { get; set; } +} \ No newline at end of file diff --git a/Src/Dlhis.Canteen/Order/Request/BalanceRecordAnalysisByShiftRequest.cs b/Src/Dlhis.Canteen/Order/Request/BalanceRecordAnalysisByShiftRequest.cs new file mode 100644 index 00000000..65f99310 --- /dev/null +++ b/Src/Dlhis.Canteen/Order/Request/BalanceRecordAnalysisByShiftRequest.cs @@ -0,0 +1,29 @@ +using System.ComponentModel.DataAnnotations; +using Kurisu.AspNetCore.CustomClass; +using Kurisu.AspNetCore.DataAccess.Dto; + +namespace Dlhis.Canteen.Order.Request; + +public class BalanceRecordAnalysisByShiftRequest : PageDto, IValidatableObject +{ + /// + /// 营业点 + /// + public List BusinessPlaceCodes { get; set; } + + /// + /// + /// + public DateTimePeriod SearchDateTimePeriod { get; set; } + + /// + public IEnumerable Validate(ValidationContext validationContext) + { + if (SearchDateTimePeriod is { End: not null }) + { + SearchDateTimePeriod.End = SearchDateTimePeriod.End.Value.AddDays(1).AddSeconds(-1); + } + + yield break; + } +} \ No newline at end of file diff --git a/Src/Dlhis.Canteen/Order/Response/BalanceRecordAnalysisShiftResponse.cs b/Src/Dlhis.Canteen/Order/Response/BalanceRecordAnalysisShiftResponse.cs new file mode 100644 index 00000000..5598845f --- /dev/null +++ b/Src/Dlhis.Canteen/Order/Response/BalanceRecordAnalysisShiftResponse.cs @@ -0,0 +1,20 @@ +using Dlhis.Canteen.Order.Dto; +using Kurisu.AspNetCore.DataAccess.Dto; +using Kurisu.AspNetCore.Utils.Converters; +using Newtonsoft.Json; + +namespace Dlhis.Canteen.Order.Response; + +public class BalanceRecordAnalysisShiftResponse +{ + public decimal Amount { get; set; } + public Pagination Pagination { get; set; } +} + +public class BalanceRecordAnalysisShiftPageResponse +{ + [JsonConverter(typeof(ToDateJsonConverter))] + public DateTime Date { get; set; } + + public List> Shifts { get; set; } +} \ No newline at end of file diff --git a/Src/Dlhis.Canteen/Order/Services/IBalanceSummaryService.cs b/Src/Dlhis.Canteen/Order/Services/IBalanceSummaryService.cs index 113be8c6..79707980 100644 --- a/Src/Dlhis.Canteen/Order/Services/IBalanceSummaryService.cs +++ b/Src/Dlhis.Canteen/Order/Services/IBalanceSummaryService.cs @@ -9,4 +9,7 @@ public interface IBalanceSummaryService : IScopeDependency Task BalanceRecordAnalysisAsync(BalanceRecordAnalysisRequest request); Task> BalanceRecordAnalysisByCostIdAsync(); -} + + + Task BalanceRecordAnalysisByShiftAsync(BalanceRecordAnalysisByShiftRequest request); +} \ No newline at end of file diff --git a/Src/Dlhis.Canteen/Order/Services/Implements/BalanceSummaryService.cs b/Src/Dlhis.Canteen/Order/Services/Implements/BalanceSummaryService.cs index 8db7ff01..cb79225a 100644 --- a/Src/Dlhis.Canteen/Order/Services/Implements/BalanceSummaryService.cs +++ b/Src/Dlhis.Canteen/Order/Services/Implements/BalanceSummaryService.cs @@ -1,4 +1,6 @@ -using Dlhis.Canteen.Order.Request; +using System.Reflection; +using Dlhis.Canteen.Order.Dto; +using Dlhis.Canteen.Order.Request; using Dlhis.Canteen.Order.Response; using Dlhis.Entity.Canteen.Entities; using Dlhis.Entity.Canteen.Enums; @@ -6,6 +8,7 @@ using Kurisu.AspNetCore.CustomClass; using Kurisu.AspNetCore.DataAccess.Dto; using Kurisu.AspNetCore.DataAccess.Extensions; using Kurisu.AspNetCore.DataAccess.SqlSugar.Services; +using SqlSugar; namespace Dlhis.Canteen.Order.Services.Implements; @@ -85,4 +88,41 @@ public class BalanceSummaryService : IBalanceSummaryService return null; } + + + public async Task BalanceRecordAnalysisByShiftAsync(BalanceRecordAnalysisByShiftRequest request) + { + var queryable = _dbContext.Queryable() + .Where(x => x.Status == BalanceRecordStatusEnumType.Valid && x.Type == BalanceRecordTypeEnumType.Out) + .WhereIF(request.SearchDateTimePeriod.HasValue(), x => x.CostDate >= request.SearchDateTimePeriod.Start && x.CostDate <= request.SearchDateTimePeriod.End) + .WhereIF(request.BusinessPlaceCodes?.Any() == true, x => request.BusinessPlaceCodes.Contains(x.BusinessPlaceCode.Value)); + + var amount = await queryable.SumAsync(x => x.Amount); + + var count = typeof(ShiftEnumType).GetFields(BindingFlags.Public | BindingFlags.Static).Length; + + var result = await queryable.GroupBy(x => new { x.CostDate, x.ShiftType }) + .Select(x => new { x.CostDate, x.ShiftType, Amount = SqlFunc.AggregateSum(SqlFunc.Abs(x.Amount)) }) + .ToPageListAsync(request.PageIndex, count * request.PageSize); + + return new BalanceRecordAnalysisShiftResponse + { + Amount = amount, + Pagination = new Pagination + { + PageIndex = request.PageIndex, + PageSize = request.PageSize, + Total = result.Count, + Data = result.GroupBy(x => x.CostDate).Select(x => new BalanceRecordAnalysisShiftPageResponse + { + Date = x.Key, + Shifts = x.Select(item => new ShiftSummaryDto + { + Shift = item.ShiftType, + Value = item.Amount + }).ToList() + }).ToList() + } + }; + } } \ No newline at end of file diff --git a/Src/Dlhis.Sys/Menu/Controllers/MenusController.cs b/Src/Dlhis.Sys/Menu/Controllers/MenusController.cs index 63203c04..0f32e9ea 100644 --- a/Src/Dlhis.Sys/Menu/Controllers/MenusController.cs +++ b/Src/Dlhis.Sys/Menu/Controllers/MenusController.cs @@ -102,6 +102,7 @@ public class MenusController : ControllerBase /// [Authorize(Roles = "admin")] [HttpPost("reset")] + [Transactional] public async Task ResetAsync(List request) { await _menuService.ResetAsync(request); From 23e4b4e6e7bf08124c928e0c013bc2d7df34fe35 Mon Sep 17 00:00:00 2001 From: liguoyang Date: Tue, 13 Aug 2024 13:46:06 +0800 Subject: [PATCH 06/25] =?UTF-8?q?feat=20=E5=B0=B1=E9=A4=90=E5=88=86?= =?UTF-8?q?=E6=9E=90,=E9=A4=90=E6=AC=A1=E4=BD=BF=E7=94=A8=E9=87=91?= =?UTF-8?q?=E9=A2=9D=E5=92=8C=E4=BA=BA=E6=95=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Controllers/BalanceSummaryController.cs | 19 +++++++++--- ...cordAnalysisShiftAmountAndCountResponse.cs | 16 ++++++++++ .../BalanceRecordAnalysisShiftResponse.cs | 2 +- .../Order/Services/IBalanceSummaryService.cs | 4 ++- .../Services/Implements/BalanceService.cs | 13 +++++--- .../Implements/BalanceSummaryService.cs | 31 +++++++++++++++++-- 6 files changed, 72 insertions(+), 13 deletions(-) create mode 100644 Src/Dlhis.Canteen/Order/Response/BalanceRecordAnalysisShiftAmountAndCountResponse.cs diff --git a/Src/Dlhis.Canteen/Order/Controllers/BalanceSummaryController.cs b/Src/Dlhis.Canteen/Order/Controllers/BalanceSummaryController.cs index 4326f250..154eafb0 100644 --- a/Src/Dlhis.Canteen/Order/Controllers/BalanceSummaryController.cs +++ b/Src/Dlhis.Canteen/Order/Controllers/BalanceSummaryController.cs @@ -43,11 +43,22 @@ public class BalanceSummaryController : ControllerBase } /// - /// 用餐分析(餐次) + /// 餐次用餐分析,统计金额 /// - [HttpGet("analysis/shift")] - public async Task BalanceRecordAnalysisByShiftAsync([FromQuery] BalanceRecordAnalysisByShiftRequest request) + [HttpGet("shift/analysis/amount")] + public async Task BalanceRecordShiftAnalysisAmountAsync([FromQuery] BalanceRecordAnalysisByShiftRequest request) { - return await _balanceSummaryService.BalanceRecordAnalysisByShiftAsync(request); + return await _balanceSummaryService.BalanceRecordShiftAnalysisAmountAsync(request); + } + + /// + /// 餐次用餐分析,统计金额和人数 + /// + /// + /// + [HttpGet("shift/analysis/amountAndCount")] + public async Task BalanceRecordShiftAnalysisAmountAndCountAsync([FromQuery] BalanceRecordAnalysisByShiftRequest request) + { + return await _balanceSummaryService.BalanceRecordShiftAnalysisAmountAndCountAsync(request); } } \ No newline at end of file diff --git a/Src/Dlhis.Canteen/Order/Response/BalanceRecordAnalysisShiftAmountAndCountResponse.cs b/Src/Dlhis.Canteen/Order/Response/BalanceRecordAnalysisShiftAmountAndCountResponse.cs new file mode 100644 index 00000000..e20d86d3 --- /dev/null +++ b/Src/Dlhis.Canteen/Order/Response/BalanceRecordAnalysisShiftAmountAndCountResponse.cs @@ -0,0 +1,16 @@ +using Dlhis.Entity.Canteen.Enums; + +namespace Dlhis.Canteen.Order.Response; + +public class BalanceRecordAnalysisShiftAmountAndCountResponse +{ + public decimal Amount { get; set; } + public List Items { get; set; } +} + +public class BalanceRecordAnalysisShiftAmountAndCountItemResponse +{ + public ShiftEnumType? ShiftType { get; set; } + public decimal Amount { get; set; } + public int Count { get; set; } +} \ No newline at end of file diff --git a/Src/Dlhis.Canteen/Order/Response/BalanceRecordAnalysisShiftResponse.cs b/Src/Dlhis.Canteen/Order/Response/BalanceRecordAnalysisShiftResponse.cs index 5598845f..75b66dbe 100644 --- a/Src/Dlhis.Canteen/Order/Response/BalanceRecordAnalysisShiftResponse.cs +++ b/Src/Dlhis.Canteen/Order/Response/BalanceRecordAnalysisShiftResponse.cs @@ -5,7 +5,7 @@ using Newtonsoft.Json; namespace Dlhis.Canteen.Order.Response; -public class BalanceRecordAnalysisShiftResponse +public class BalanceRecordAnalysisShiftAmountResponse { public decimal Amount { get; set; } public Pagination Pagination { get; set; } diff --git a/Src/Dlhis.Canteen/Order/Services/IBalanceSummaryService.cs b/Src/Dlhis.Canteen/Order/Services/IBalanceSummaryService.cs index 79707980..b6a192d9 100644 --- a/Src/Dlhis.Canteen/Order/Services/IBalanceSummaryService.cs +++ b/Src/Dlhis.Canteen/Order/Services/IBalanceSummaryService.cs @@ -11,5 +11,7 @@ public interface IBalanceSummaryService : IScopeDependency Task> BalanceRecordAnalysisByCostIdAsync(); - Task BalanceRecordAnalysisByShiftAsync(BalanceRecordAnalysisByShiftRequest request); + Task BalanceRecordShiftAnalysisAmountAsync(BalanceRecordAnalysisByShiftRequest request); + + Task BalanceRecordShiftAnalysisAmountAndCountAsync(BalanceRecordAnalysisByShiftRequest request); } \ No newline at end of file diff --git a/Src/Dlhis.Canteen/Order/Services/Implements/BalanceService.cs b/Src/Dlhis.Canteen/Order/Services/Implements/BalanceService.cs index bb3483a3..cd1cc6a6 100644 --- a/Src/Dlhis.Canteen/Order/Services/Implements/BalanceService.cs +++ b/Src/Dlhis.Canteen/Order/Services/Implements/BalanceService.cs @@ -109,6 +109,10 @@ public class BalanceService : IBalanceService { var cache = App.GetServiceProvider().GetService(); var balanceRecord = await _dbContext.Queryable().Where(x => x.No == no).SingleAsync(); + balanceRecord.ThrowIfNull("数据不存在"); + + (balanceRecord.Status != BalanceRecordStatusEnumType.Valid).ThrowIfTrue("无法退款"); + await using var handler = await cache.LockAsync($"balance:refund:{no}", TimeSpan.FromSeconds(9)); if (handler.Acquired) { @@ -125,7 +129,7 @@ public class BalanceService : IBalanceService } } - var userNo = balanceRecord?.UserNo; + var userNo = balanceRecord.UserNo; //获取人员余额 return await _dbContext.Queryable() .LeftJoin((x, ga) => x.UserNo == ga.No) @@ -146,8 +150,8 @@ public class BalanceService : IBalanceService public async Task> GetPageByDeviceUniqueNoAsync(BalanceRecordPageByDeviceUniqueNoRequest request) { var device = await _dbContext.Queryable() - .Where(x => x.UniqueNo == request.DeviceUniqueNo || x.Code == Guid.Parse(request.DeviceUniqueNo)) - .FirstAsync(); + .Where(x => x.UniqueNo == request.DeviceUniqueNo) + .SingleAsync(); if (device == null) { @@ -182,7 +186,8 @@ public class BalanceService : IBalanceService .LeftJoin((record, ga, department, bPlace, imageRecord) => imageRecord.No == record.No) .Where(record => record.DeviceUniqueNo == device.UniqueNo) .Where(record => record.CostDate >= request.Start && record.CostDate <= request.End) - .Where(record => record.Type == BalanceRecordTypeEnumType.Out && record.Status == BalanceRecordStatusEnumType.Valid) + .Where(record => record.Type == BalanceRecordTypeEnumType.Out + && (record.Status == BalanceRecordStatusEnumType.Valid || (record.Status == BalanceRecordStatusEnumType.Obsolute && record.Remark == "退款"))) .WhereIF(request.UserCode.IsPresent(), record => record.UserCode == request.UserCode) .OrderBy(record => record.CostDateTime, OrderByType.Desc) .Select((record, ga, department, bPlace, imageRecord) => new BalanceRecordDeviceResponse diff --git a/Src/Dlhis.Canteen/Order/Services/Implements/BalanceSummaryService.cs b/Src/Dlhis.Canteen/Order/Services/Implements/BalanceSummaryService.cs index cb79225a..5a76b686 100644 --- a/Src/Dlhis.Canteen/Order/Services/Implements/BalanceSummaryService.cs +++ b/Src/Dlhis.Canteen/Order/Services/Implements/BalanceSummaryService.cs @@ -90,14 +90,14 @@ public class BalanceSummaryService : IBalanceSummaryService } - public async Task BalanceRecordAnalysisByShiftAsync(BalanceRecordAnalysisByShiftRequest request) + public async Task BalanceRecordShiftAnalysisAmountAsync(BalanceRecordAnalysisByShiftRequest request) { var queryable = _dbContext.Queryable() .Where(x => x.Status == BalanceRecordStatusEnumType.Valid && x.Type == BalanceRecordTypeEnumType.Out) .WhereIF(request.SearchDateTimePeriod.HasValue(), x => x.CostDate >= request.SearchDateTimePeriod.Start && x.CostDate <= request.SearchDateTimePeriod.End) .WhereIF(request.BusinessPlaceCodes?.Any() == true, x => request.BusinessPlaceCodes.Contains(x.BusinessPlaceCode.Value)); - var amount = await queryable.SumAsync(x => x.Amount); + var amount = await queryable.SumAsync(x => SqlFunc.Abs(x.Amount)); var count = typeof(ShiftEnumType).GetFields(BindingFlags.Public | BindingFlags.Static).Length; @@ -105,7 +105,7 @@ public class BalanceSummaryService : IBalanceSummaryService .Select(x => new { x.CostDate, x.ShiftType, Amount = SqlFunc.AggregateSum(SqlFunc.Abs(x.Amount)) }) .ToPageListAsync(request.PageIndex, count * request.PageSize); - return new BalanceRecordAnalysisShiftResponse + return new BalanceRecordAnalysisShiftAmountResponse { Amount = amount, Pagination = new Pagination @@ -125,4 +125,29 @@ public class BalanceSummaryService : IBalanceSummaryService } }; } + + public async Task BalanceRecordShiftAnalysisAmountAndCountAsync(BalanceRecordAnalysisByShiftRequest request) + { + var queryable = _dbContext.Queryable() + .Where(x => x.Status == BalanceRecordStatusEnumType.Valid && x.Type == BalanceRecordTypeEnumType.Out) + .WhereIF(request.SearchDateTimePeriod.HasValue(), x => x.CostDate >= request.SearchDateTimePeriod.Start && x.CostDate <= request.SearchDateTimePeriod.End) + .WhereIF(request.BusinessPlaceCodes?.Any() == true, x => request.BusinessPlaceCodes.Contains(x.BusinessPlaceCode.Value)); + + var amount = await queryable.SumAsync(x => SqlFunc.Abs(x.Amount)); + + var result = await queryable.GroupBy(x => new { x.ShiftType }) + .Select(x => new { x.ShiftType, Amount = SqlFunc.AggregateSum(SqlFunc.Abs(x.Amount)), Count = SqlFunc.AggregateDistinctCount(x.UserCode) }) + .ToListAsync(); + + return new BalanceRecordAnalysisShiftAmountAndCountResponse + { + Amount = amount, + Items = result.Select(x => new BalanceRecordAnalysisShiftAmountAndCountItemResponse + { + ShiftType = x.ShiftType, + Amount = x.Amount, + Count = x.Count + }).ToList() + }; + } } \ No newline at end of file From ad0a97a16d196b9b9441c8a1419b63d86141d9db Mon Sep 17 00:00:00 2001 From: liguoyang Date: Wed, 14 Aug 2024 15:07:08 +0800 Subject: [PATCH 07/25] =?UTF-8?q?feat=20=E7=94=B5=E5=AD=90=E9=A4=90?= =?UTF-8?q?=E5=88=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Implements/DeviceConnectService.cs | 4 +- .../Services/Implements/GainfoMealService.cs | 2 - Src/Dlhis.Basic/Program.cs | 1 + Src/Dlhis.Canteen/Dlhis.Canteen.csproj | 6 - .../Controllers/EMealVoucherController.cs | 65 ++++ .../Request/EMealVoucherPageRequest.cs | 7 + .../Response/EMealVoucherDetailResponse.cs | 31 ++ .../Response/EMealVoucherPageResponse.cs | 12 + .../Services/IEMealVoucherService.cs | 18 ++ .../Implements/EMealVoucherService.cs | 106 +++++++ .../Implements/MealSupplementRecordService.cs | 1 - .../Order/Dto/OrderPreCheckDto.cs | 16 + .../Services/Implements/BalanceService.cs | 1 - .../Implements/BookingOrderService.cs | 1 - .../Implements/HainingBalanceService.cs | 1 - .../Order/Services/Implements/OrderService.cs | 300 ++++++++++++++---- .../Canteen/Entities/BalanceRecordEntity.cs | 6 - .../Entities/EMealVoucherDetailEntity.cs | 23 +- .../EMealVoucherDetailQrCodeEntity.cs | 29 ++ .../Enums/BalanceRecordSourceEnumType.cs | 2 +- .../Request/EMealVoucherReceiveRequest.cs | 5 + .../Implements/EMealVoucherService.cs | 2 +- .../Services/Implements/OrderService.cs | 1 - .../Jobs/MealSupplementHandlerJob.cs | 1 - Src/Gateway/Program.cs | 14 +- Src/Gateway/appsettings.json | 1 - Src/Gateway/ocelot.Development.json | 2 +- 27 files changed, 552 insertions(+), 106 deletions(-) create mode 100644 Src/Dlhis.Canteen/EMealVoucher/Request/EMealVoucherPageRequest.cs create mode 100644 Src/Dlhis.Canteen/EMealVoucher/Response/EMealVoucherDetailResponse.cs create mode 100644 Src/Dlhis.Canteen/EMealVoucher/Response/EMealVoucherPageResponse.cs create mode 100644 Src/Dlhis.Canteen/EMealVoucher/Services/IEMealVoucherService.cs create mode 100644 Src/Dlhis.Canteen/EMealVoucher/Services/Implements/EMealVoucherService.cs create mode 100644 Src/Dlhis.Canteen/Order/Dto/OrderPreCheckDto.cs create mode 100644 Src/Dlhis.Entity/Canteen/Entities/EMealVoucherDetailQrCodeEntity.cs diff --git a/Src/Dlhis.Basic/Device/Services/Implements/DeviceConnectService.cs b/Src/Dlhis.Basic/Device/Services/Implements/DeviceConnectService.cs index 4b767cc6..30671f82 100644 --- a/Src/Dlhis.Basic/Device/Services/Implements/DeviceConnectService.cs +++ b/Src/Dlhis.Basic/Device/Services/Implements/DeviceConnectService.cs @@ -17,10 +17,12 @@ namespace Dlhis.Basic.Device.Services.Implements; public class DeviceConnectService : IDeviceConnectService { private readonly IDbContext _dbContext; + private readonly IHttpContextAccessor _httpContextAccessor; - public DeviceConnectService(IDbContext dbContext) + public DeviceConnectService(IDbContext dbContext, IHttpContextAccessor httpContextAccessor) { _dbContext = dbContext; + _httpContextAccessor = httpContextAccessor; } diff --git a/Src/Dlhis.Basic/Organization/Services/Implements/GainfoMealService.cs b/Src/Dlhis.Basic/Organization/Services/Implements/GainfoMealService.cs index 93249cff..587c3fb2 100644 --- a/Src/Dlhis.Basic/Organization/Services/Implements/GainfoMealService.cs +++ b/Src/Dlhis.Basic/Organization/Services/Implements/GainfoMealService.cs @@ -96,7 +96,6 @@ public class GainfoMealService : IGainfoMealService ShiftType = null, CostDate = now.Date, DeviceUniqueNo = null, - SubsidiesFromMonth = now.ToString("yyyyMM"), IP = null, CostId = gainfoLeave.CostId, OriginTenantId = gainfoLeave.Factory, @@ -141,7 +140,6 @@ public class GainfoMealService : IGainfoMealService ShiftType = null, CostDate = now.Date, DeviceUniqueNo = null, - SubsidiesFromMonth = now.ToString("yyyyMM"), IP = null, CostId = gainfo.CostId, OriginTenantId = gainfo.Factory, diff --git a/Src/Dlhis.Basic/Program.cs b/Src/Dlhis.Basic/Program.cs index 882db25c..6bd00925 100644 --- a/Src/Dlhis.Basic/Program.cs +++ b/Src/Dlhis.Basic/Program.cs @@ -22,6 +22,7 @@ public class Startup : DefaultStartup public override void ConfigureServices(IServiceCollection services) { base.ConfigureServices(services); + services.AddHttpContextAccessor(); services.AddRedis(); } } \ No newline at end of file diff --git a/Src/Dlhis.Canteen/Dlhis.Canteen.csproj b/Src/Dlhis.Canteen/Dlhis.Canteen.csproj index fc8473bf..0c6bb0f3 100644 --- a/Src/Dlhis.Canteen/Dlhis.Canteen.csproj +++ b/Src/Dlhis.Canteen/Dlhis.Canteen.csproj @@ -28,10 +28,4 @@ - - - - - - diff --git a/Src/Dlhis.Canteen/EMealVoucher/Controllers/EMealVoucherController.cs b/Src/Dlhis.Canteen/EMealVoucher/Controllers/EMealVoucherController.cs index 98e2f3ed..40b9483d 100644 --- a/Src/Dlhis.Canteen/EMealVoucher/Controllers/EMealVoucherController.cs +++ b/Src/Dlhis.Canteen/EMealVoucher/Controllers/EMealVoucherController.cs @@ -1,3 +1,7 @@ +using Dlhis.Canteen.EMealVoucher.Request; +using Dlhis.Canteen.EMealVoucher.Response; +using Dlhis.Canteen.EMealVoucher.Services; +using Kurisu.AspNetCore.DataAccess.Dto; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; @@ -8,4 +12,65 @@ namespace Dlhis.Canteen.EMealVoucher.Controllers; [ApiController] public class EMealVoucherController : ControllerBase { + private readonly IEMealVoucherService _eMealVoucherService; + + public EMealVoucherController(IEMealVoucherService eMealVoucherService) + { + _eMealVoucherService = eMealVoucherService; + } + + /// + /// 获取我的电子餐券申请 + /// + /// + /// + [HttpGet("my")] + public async Task> GetMyEMealVoucherPageAsync([FromQuery] EMealVoucherPageRequest request) + { + return await _eMealVoucherService.GetMyEMealVoucherPageAsync(request); + } + + /// + /// 查看电子餐券 + /// + /// + /// + [HttpGet("no")] + public async Task> GetDetailsByNoAsync(string no) + { + return await _eMealVoucherService.GetDetailsByNoAsync(no); + } + + /// + /// 获取url签名 + /// + /// + /// + [HttpGet("signature")] + public async Task GetQrCodeSignatureAsync(long detailId) + { + return await _eMealVoucherService.GetQrCodeSignatureAsync(detailId); + } + + /// + /// 刷新url签名 + /// + /// + [HttpPost("signature/refresh")] + public async Task RefreshSignatureAsync(long detailId) + { + await _eMealVoucherService.RefreshSignatureAsync(detailId); + } + + /// + /// 获取二维码 + /// + /// + /// + [AllowAnonymous] + [HttpGet("qrcode")] + public async Task GetQrCodeAsync(string signature) + { + return await _eMealVoucherService.GetQrCodeAsync(signature); + } } \ No newline at end of file diff --git a/Src/Dlhis.Canteen/EMealVoucher/Request/EMealVoucherPageRequest.cs b/Src/Dlhis.Canteen/EMealVoucher/Request/EMealVoucherPageRequest.cs new file mode 100644 index 00000000..d23ddad0 --- /dev/null +++ b/Src/Dlhis.Canteen/EMealVoucher/Request/EMealVoucherPageRequest.cs @@ -0,0 +1,7 @@ +using Kurisu.AspNetCore.DataAccess.Dto; + +namespace Dlhis.Canteen.EMealVoucher.Request; + +public class EMealVoucherPageRequest : PageDto +{ +} \ No newline at end of file diff --git a/Src/Dlhis.Canteen/EMealVoucher/Response/EMealVoucherDetailResponse.cs b/Src/Dlhis.Canteen/EMealVoucher/Response/EMealVoucherDetailResponse.cs new file mode 100644 index 00000000..03656071 --- /dev/null +++ b/Src/Dlhis.Canteen/EMealVoucher/Response/EMealVoucherDetailResponse.cs @@ -0,0 +1,31 @@ +namespace Dlhis.Canteen.EMealVoucher.Response; + +public class EMealVoucherDetailResponse +{ + public long Id { get; set; } + + /// + /// 用餐人 + /// + public string Name { get; set; } + + /// + /// 手机号 + /// + public string Phone { get; set; } + + /// + /// 就餐开始 + /// + public DateTime Start { get; set; } + + /// + /// 就餐结束 + /// + public DateTime End { get; set; } + + /// + /// 金额 + /// + public decimal Balance { get; set; } +} \ No newline at end of file diff --git a/Src/Dlhis.Canteen/EMealVoucher/Response/EMealVoucherPageResponse.cs b/Src/Dlhis.Canteen/EMealVoucher/Response/EMealVoucherPageResponse.cs new file mode 100644 index 00000000..c35caac3 --- /dev/null +++ b/Src/Dlhis.Canteen/EMealVoucher/Response/EMealVoucherPageResponse.cs @@ -0,0 +1,12 @@ +namespace Dlhis.Canteen.EMealVoucher.Response; + +public class EMealVoucherPageResponse +{ + public long Id { get; set; } + + public string No { get; set; } + + public string Title { get; set; } + + public DateTime Date { get; set; } +} \ No newline at end of file diff --git a/Src/Dlhis.Canteen/EMealVoucher/Services/IEMealVoucherService.cs b/Src/Dlhis.Canteen/EMealVoucher/Services/IEMealVoucherService.cs new file mode 100644 index 00000000..ef41f70a --- /dev/null +++ b/Src/Dlhis.Canteen/EMealVoucher/Services/IEMealVoucherService.cs @@ -0,0 +1,18 @@ +using Dlhis.Canteen.EMealVoucher.Request; +using Dlhis.Canteen.EMealVoucher.Response; +using Kurisu.AspNetCore.DataAccess.Dto; + +namespace Dlhis.Canteen.EMealVoucher.Services; + +public interface IEMealVoucherService : IScopeDependency +{ + Task> GetMyEMealVoucherPageAsync(EMealVoucherPageRequest request); + + Task> GetDetailsByNoAsync(string no); + + Task GetQrCodeSignatureAsync(long detailId); + + Task RefreshSignatureAsync(long detailId); + + Task GetQrCodeAsync(string signature); +} \ No newline at end of file diff --git a/Src/Dlhis.Canteen/EMealVoucher/Services/Implements/EMealVoucherService.cs b/Src/Dlhis.Canteen/EMealVoucher/Services/Implements/EMealVoucherService.cs new file mode 100644 index 00000000..c00c2fa1 --- /dev/null +++ b/Src/Dlhis.Canteen/EMealVoucher/Services/Implements/EMealVoucherService.cs @@ -0,0 +1,106 @@ +using System.Text; +using Dlhis.Canteen.EMealVoucher.Request; +using Dlhis.Canteen.EMealVoucher.Response; +using Dlhis.Entity.Canteen.Entities; +using Kurisu.AspNetCore.Authentication.Abstractions; +using Kurisu.AspNetCore.DataAccess.Dto; +using Kurisu.AspNetCore.DataAccess.SqlSugar.Extensions; +using Kurisu.AspNetCore.DataAccess.SqlSugar.Services; +using Kurisu.AspNetCore.Utils.Extensions; +using SqlSugar; + +namespace Dlhis.Canteen.EMealVoucher.Services.Implements; + +public class EMealVoucherService : IEMealVoucherService +{ + private readonly IDbContext _dbContext; + private readonly ICurrentUser _currentUser; + + public EMealVoucherService(IDbContext dbContext, ICurrentUser currentUser) + { + _dbContext = dbContext; + _currentUser = currentUser; + } + + + public async Task> GetMyEMealVoucherPageAsync(EMealVoucherPageRequest request) + { + var code = _currentUser.GetUserClaim("jinko-code"); + code = "0123456"; + return await _dbContext.Queryable() + .Where(x => x.Code == code) + .OrderBy(x => x.Id, OrderByType.Desc) + .Select() + .ToPageListAsync(request); + } + + + public async Task> GetDetailsByNoAsync(string no) + { + return await _dbContext.Queryable() + .Where(x => x.No == no) + .Select() + .ToListAsync(); + } + + + public async Task GetQrCodeSignatureAsync(long detailId) + { + return await GenerateSignatureAsync(detailId, false); + } + + public async Task RefreshSignatureAsync(long detailId) + { + await GenerateSignatureAsync(detailId, true); + } + + private async Task GenerateSignatureAsync(long detailId, bool isRefresh) + { + var eMealVoucherDetail = await _dbContext.Queryable().Where(x => x.Id == detailId).SingleAsync(); + eMealVoucherDetail.ThrowIfNull("数据不存在"); + if (eMealVoucherDetail.Signature.IsPresent()) + { + if (isRefresh) + { + await _dbContext.Deleteable().Where(x => x.Signature == eMealVoucherDetail.Signature).ExecuteCommandAsync(); + } + else + { + return eMealVoucherDetail.Signature; + } + } + + eMealVoucherDetail.Signature = Guid.NewGuid().ToString().Replace("-", "") + DateTimeOffset.Now.ToUnixTimeMilliseconds(); + await _dbContext.UpdateAsync(eMealVoucherDetail); + + return eMealVoucherDetail.Signature; + } + + /// + public async Task GetQrCodeAsync(string signature) + { + var eMealVoucherDetail = await _dbContext.Queryable().Where(x => x.Signature == signature).SingleAsync(); + eMealVoucherDetail.ThrowIfNull("无效地址"); + var eMealVoucher = await _dbContext.Queryable().Where(x => x.No == eMealVoucherDetail.No).SingleAsync(); + + var ts = DateTimeOffset.Now.ToUnixTimeMilliseconds().ToString().Reverse().Join(string.Empty); + var originData = string.Concat(eMealVoucher.No, ":", ts, ":", eMealVoucher.Code, ":", eMealVoucherDetail.IdNo); + + var qrCode = "02" + originData.ToArray().Select(x => + { + var b = Encoding.ASCII.GetBytes(x.ToString()); + int i = b[0]; + return Convert.ToString(i); + }).Join(string.Empty); + + + await _dbContext.InsertAsync(new EMealVoucherDetailQrCodeEntity + { + Signature = signature, + OriginData = originData, + QrCode = qrCode + }); + + return qrCode; + } +} \ No newline at end of file diff --git a/Src/Dlhis.Canteen/MealSupplementRecord/Services/Implements/MealSupplementRecordService.cs b/Src/Dlhis.Canteen/MealSupplementRecord/Services/Implements/MealSupplementRecordService.cs index 70e94176..6bb57af2 100644 --- a/Src/Dlhis.Canteen/MealSupplementRecord/Services/Implements/MealSupplementRecordService.cs +++ b/Src/Dlhis.Canteen/MealSupplementRecord/Services/Implements/MealSupplementRecordService.cs @@ -174,7 +174,6 @@ public class MealSupplementRecordService : IMealSupplementRecordService Source = BalanceRecordSourceEnumType.LocalTenantSubsidies, Remark = "期初导入", CostId = gainfo.CostId, - SubsidiesFromMonth = today.ToString("yyyyMM"), OriginTenantId = gainfo.Factory, Werks = gainfo.Werks, Name = gainfo.Name, diff --git a/Src/Dlhis.Canteen/Order/Dto/OrderPreCheckDto.cs b/Src/Dlhis.Canteen/Order/Dto/OrderPreCheckDto.cs new file mode 100644 index 00000000..6667755e --- /dev/null +++ b/Src/Dlhis.Canteen/Order/Dto/OrderPreCheckDto.cs @@ -0,0 +1,16 @@ +using Dlhis.Entity.Basic.Entity; + +namespace Dlhis.Canteen.Order.Dto +{ + public class OrderPreCheckDto + { + public DateTime CostDate { get; set; } + public BusinessShiftMealRelationshipEntity Shift { get; set; } + + public string BusinessPlaceTenantId { get; set; } + + public Guid BusinessPlaceCode { get; set; } + + public Guid BusinessShiftCode { get; set; } + } +} \ No newline at end of file diff --git a/Src/Dlhis.Canteen/Order/Services/Implements/BalanceService.cs b/Src/Dlhis.Canteen/Order/Services/Implements/BalanceService.cs index cd1cc6a6..a83c3107 100644 --- a/Src/Dlhis.Canteen/Order/Services/Implements/BalanceService.cs +++ b/Src/Dlhis.Canteen/Order/Services/Implements/BalanceService.cs @@ -482,7 +482,6 @@ public class BalanceService : IBalanceService ShiftType = null, CostDate = DateTime.Now.Date, DeviceUniqueNo = null, - SubsidiesFromMonth = DateTime.Now.ToString("yyyyMM"), IP = null, CostId = gainfo.CostId, OriginTenantId = gainfo.Factory, diff --git a/Src/Dlhis.Canteen/Order/Services/Implements/BookingOrderService.cs b/Src/Dlhis.Canteen/Order/Services/Implements/BookingOrderService.cs index 17054b7b..afff04cd 100644 --- a/Src/Dlhis.Canteen/Order/Services/Implements/BookingOrderService.cs +++ b/Src/Dlhis.Canteen/Order/Services/Implements/BookingOrderService.cs @@ -71,7 +71,6 @@ public class BookingOrderService : BaseOrderService, IBookingOrderService DeliveryAddress = request.DeliveryAddress, No = SnowFlakeHelper.Instance.NextId().ToString(), - SubsidiesFromMonth = now.ToString("yyyyMM"), IsOffline = false, IsCostCrossTenant = await GetSettingAsync(gainfo.No, businessPlace.TenantId, CanteenSettingItemEnumType.AllowCrossTenant), diff --git a/Src/Dlhis.Canteen/Order/Services/Implements/HainingBalanceService.cs b/Src/Dlhis.Canteen/Order/Services/Implements/HainingBalanceService.cs index fd0e9fea..46ac4779 100644 --- a/Src/Dlhis.Canteen/Order/Services/Implements/HainingBalanceService.cs +++ b/Src/Dlhis.Canteen/Order/Services/Implements/HainingBalanceService.cs @@ -75,7 +75,6 @@ public class HainingBalanceService : IHainingBalanceService Source = request.Source, Remark = request.Remark, CostId = gainfo.CostId, - SubsidiesFromMonth = request.CostDate.ToString("yyyyMM"), TenantId = businessPlaceInfo?.TenantId ?? request.Factory, OriginTenantId = gainfo.Factory, Werks = gainfo.Werks, diff --git a/Src/Dlhis.Canteen/Order/Services/Implements/OrderService.cs b/Src/Dlhis.Canteen/Order/Services/Implements/OrderService.cs index 8edc15fa..e94823f6 100644 --- a/Src/Dlhis.Canteen/Order/Services/Implements/OrderService.cs +++ b/Src/Dlhis.Canteen/Order/Services/Implements/OrderService.cs @@ -1,4 +1,5 @@ using System.Diagnostics; +using Dlhis.Canteen.Order.Dto; using Dlhis.Canteen.Setting.Services; using Dlhis.Entity.Basic.Entity; using Dlhis.Entity.Canteen.Entities; @@ -161,7 +162,11 @@ public class OrderService : BaseOrderService, IOrderService } else if (request.UserUniqueNo.StartsWith("02")) { - request.Source = BalanceRecordSourceEnumType.EVoucher; + 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(); } } else @@ -180,8 +185,7 @@ public class OrderService : BaseOrderService, IOrderService { gainfo.ThrowIfNull("无法识别,无权消费"); } - - if (request.IsOffline) + else { //兼容hpt尚未删除人员后产生的消费数据 gainfo ??= await DbContext.Queryable().AS("GainfoLeave") @@ -305,7 +309,6 @@ public class OrderService : BaseOrderService, IOrderService _logs.Add("消费请求校验:" + _sw.ElapsedMilliseconds); _sw.Restart(); - await CommonHelper.RetryAsync(async () => { var gainfoMeal = await DbContext.Queryable().Where(x => x.UserNo == order.UserNo).SingleAsync(); @@ -329,42 +332,6 @@ public class OrderService : BaseOrderService, IOrderService _sw.Restart(); } - /// - /// 根据二维码获取消费用户 - /// - /// - /// - private async Task GetUserByQrCodeAsync(string qrCode) - { - var gainfoQrCode = await DbContext.Queryable().Where(x => x.QrCode == qrCode).SingleAsync(); - gainfoQrCode.ThrowIfNull("消费码已过期"); - (gainfoQrCode.ModifiedTime.AddMinutes(60) < DateTime.Now).ThrowIfTrue("消费码已过期"); - - return await DbContext.Queryable().Where(x => x.Code == gainfoQrCode.UserCode).SingleAsync(); - } - - - /// - /// 检查是否可以离线消费 - /// - /// - /// - private async Task ToCheckAbleOfflineConsumeAsync(string thirdNo) - { - var order = await DbContext.Queryable() - .Where(x => x.ThirdNo == thirdNo) - .OrderBy(x => x.CreateTime, OrderByType.Desc) - .FirstAsync(); - - if (order == null) - { - return true; - } - - //存在在线order数据,但是状态未成功 - return !order.IsOffline && order.OrderStatus != CanteenOrderStatusEnumType.Success; - } - /// /// 离线消费处理 /// @@ -418,7 +385,6 @@ public class OrderService : BaseOrderService, IOrderService DeviceUniqueNo = request.DeviceUniqueNo, No = SnowFlakeHelper.Instance.NextId().ToString(), - SubsidiesFromMonth = request.CostDateTime.ToString("yyyyMM"), IsOffline = request.IsOffline, IsCostCrossTenant = businessPlaceInfo!.TenantId != gainfo.Factory, @@ -492,8 +458,6 @@ public class OrderService : BaseOrderService, IOrderService device.ThrowIfNull("设备尚未登记"); device.Enable.ThrowIfFalse("设备已被停用"); - (request.Source == BalanceRecordSourceEnumType.QrCode && device.TenantId != gainfo.Factory).ThrowIfTrue("二维码在此设备禁止消费"); - var businessPlaceInfo = await DbContext.Queryable() .LeftJoin((x, sr) => x.Code == sr.PlaceCode) .Where(x => x.Code == registry.BusinessPlaceCode) @@ -523,6 +487,8 @@ public class OrderService : BaseOrderService, IOrderService var costDate = await GetCostDateAsync(shift, request.CostDateTime); + (request.Source == BalanceRecordSourceEnumType.QrCode && businessPlaceInfo.TenantId != gainfo.Factory).ThrowIfTrue("禁止跨厂区消费"); + var order = new CanteenOrderEntity { RequestJson = request.ToJson(), @@ -543,9 +509,8 @@ public class OrderService : BaseOrderService, IOrderService DeviceUniqueNo = request.DeviceUniqueNo, No = SnowFlakeHelper.Instance.NextId().ToString(), - SubsidiesFromMonth = request.CostDateTime.ToString("yyyyMM"), IsOffline = request.IsOffline, - IsCostCrossTenant = await GetSettingAsync(gainfo.No, businessPlaceInfo!.TenantId, CanteenSettingItemEnumType.AllowCrossTenant), + IsCostCrossTenant = gainfo.Factory != businessPlaceInfo!.TenantId, OriginTenantId = gainfo.Factory, Werks = gainfo.Werks, @@ -610,17 +575,29 @@ public class OrderService : BaseOrderService, IOrderService /// private async Task ToDoAsync(OrderAddRequest request, GainfoEntity gainfo) { - var message = ""; - if (request.IsOffline) - { - if (request.ThirdNo.IsPresent()) - { - var redisCache = _serviceProvider.GetService(); + var message = string.Empty; - await using var handler = await redisCache.LockAsync($"consume:device:{request.ThirdNo}"); - if (handler.Acquired) + if (request.Source == BalanceRecordSourceEnumType.EMealVoucher) + { + try + { + await EMealVoucherConsumeAsync(request.Adapt(), gainfo); + } + catch (Exception ex) + { + message = ex.Message; + } + } + else + { + if (request.IsOffline) + { + if (request.ThirdNo.IsPresent()) { - if (await ToCheckAbleOfflineConsumeAsync(request.ThirdNo)) + var redisCache = _serviceProvider.GetService(); + + await using var handler = await redisCache.LockAsync($"consume:device:{request.ThirdNo}"); + if (handler.Acquired && await ToCheckAbleOfflineConsumeAsync(request.ThirdNo)) { try { @@ -632,32 +609,219 @@ public class OrderService : BaseOrderService, IOrderService } } } + else + { + try + { + await HandleOfflineAsync(request.Adapt(), gainfo); + } + catch (Exception ex) + { + Logger.LogError(ex, "离线入库错误: 订单号:{no} .{message}", request.ThirdNo, ex.Message); + } + } } else { try { - await HandleOfflineAsync(request.Adapt(), gainfo); + (await DbContext.Queryable().Where(x => x.UserCode == gainfo.Code).AnyAsync()).ThrowIfFalse("就餐余额不足"); + await ConsumeAsync(request.Adapt(), gainfo); } catch (Exception ex) { - Logger.LogError(ex, "离线入库错误: 订单号:{no} .{message}", request.ThirdNo, ex.Message); + message = ex.Message; } } } - else - { - try - { - (await DbContext.Queryable().Where(x => x.UserCode == gainfo.Code).AnyAsync()).ThrowIfFalse("就餐余额不足"); - await ConsumeAsync(request.Adapt(), gainfo); - } - catch (Exception ex) - { - message = ex.Message; - } - } return message; + + async Task ToCheckAbleOfflineConsumeAsync(string thirdNo) + { + var order = await DbContext.Queryable() + .Where(x => x.ThirdNo == thirdNo) + .OrderBy(x => x.CreateTime, OrderByType.Desc) + .FirstAsync(); + + if (order == null) + { + return true; + } + + //存在在线order数据,但是状态未成功 + return !order.IsOffline && order.OrderStatus != CanteenOrderStatusEnumType.Success; + } + } + + /// + /// 根据二维码获取消费用户 + /// + /// + /// + private async Task GetUserByQrCodeAsync(string qrCode) + { + var gainfoQrCode = await DbContext.Queryable().Where(x => x.QrCode == qrCode).SingleAsync(); + gainfoQrCode.ThrowIfNull("消费码已过期"); + (gainfoQrCode.ModifiedTime.AddMinutes(60) < DateTime.Now).ThrowIfTrue("消费码已过期"); + + return await DbContext.Queryable().Where(x => x.Code == gainfoQrCode.UserCode).SingleAsync(); + } + + + private async Task EMealVoucherConsumeAsync(ConsumeRequest request, GainfoEntity gainfo) + { + var eMealVoucherQrCode = await DbContext.Queryable().Where(x => x.QrCode == request.UserUniqueNo).SingleAsync(); + var originData = eMealVoucherQrCode.OriginData.Split(':'); + + var no = originData[0]; + var idNo = originData[3]; + var nowDate = DateTime.Now.Date; + var current = await DbContext.Queryable() + .Where(x => x.No == no && x.IdNo == idNo).SingleAsync(); + (nowDate >= current.Start && nowDate <= current.End).ThrowIfFalse("餐券已过期"); + + var time = DateTimeOffset.FromUnixTimeMilliseconds(Convert.ToInt64(originData[1].Reverse().Join(string.Empty))).ToLocalTime().DateTime; + (time.AddMinutes(60) >= DateTime.Now).ThrowIfFalse("二维码已过期"); + + var eMealVoucher = await DbContext.Queryable().Where(x => x.No == no).SingleAsync(); + + var checkData = await PreCheckAsync(request.DeviceUniqueNo, request.CostDateTime); + eMealVoucher.Factories.Contains(checkData.BusinessPlaceTenantId).ThrowIfFalse("禁止在当前厂区消费"); + + _logs.Add("检验设备和营业点参数:" + _sw.ElapsedMilliseconds); + _sw.Restart(); + + var order = new CanteenOrderEntity + { + RequestJson = request.ToJson(), + ThirdNo = request.ThirdNo, + Type = BalanceRecordTypeEnumType.Out, + ApplicationType = CanteenApplicationTypeEnumType.Device, + Name = gainfo.Name, + Source = request.Source, + UserNo = eMealVoucherQrCode.OriginData, //记录为当前消费券 + UserCode = gainfo.Code, + Amount = request.Amount, + BusinessPlaceCode = checkData.BusinessPlaceCode, + BusinessShiftCode = checkData.BusinessShiftCode, + ShiftType = checkData.Shift.ShiftType, + CostDate = checkData.CostDate, + CostId = gainfo.CostId, + DepartmentNo = gainfo.DepartmentNo, + DeviceUniqueNo = request.DeviceUniqueNo, + + No = SnowFlakeHelper.Instance.NextId().ToString(), + IsOffline = false, + IsCostCrossTenant = gainfo.Factory != checkData.BusinessPlaceTenantId, + + OriginTenantId = gainfo.Factory, + Werks = gainfo.Werks, + Status = BalanceRecordStatusEnumType.Valid, + OrderStatus = CanteenOrderStatusEnumType.Wait, + CostDateTime = request.CostDateTime, + //标识当前消费的基地 + TenantId = checkData.BusinessPlaceTenantId, + }; + + var orderId = await DbContext.InsertReturnIdentityAsync(order); + _logs.Add("临时order写入:" + _sw.ElapsedMilliseconds); + _sw.Restart(); + + try + { + await CommonHelper.RetryAsync(async () => + { + var detail = await DbContext.Queryable().Where(x => x.No == no && x.IdNo == idNo).SingleAsync(); + //金额+- + detail.Balance += order.Amount; + (detail.Balance < 0).ThrowIfTrue("余额不足,无法消费"); + + await DbContext.Updateable() + .SetColumns(x => x.Balance == detail.Balance) + .SetColumns(x => x.Version == x.Version + 1) + .SetColumns(x => x.ModifiedTime == DateTime.Now) + .Where(x => x.No == no && x.IdNo == idNo && x.Version == detail.Version) //必须与查询时的version一致 + .ExecuteCommandThrowVersionAsync(); + + //写入记录 + var balanceRecord = order.Adapt(); + await DbContext.InsertAsync(balanceRecord); + }, 5); + + _logs.Add("消费写入:" + _sw.ElapsedMilliseconds); + _sw.Restart(); + + await DbContext.Updateable() + .SetColumns(x => x.OrderStatus == CanteenOrderStatusEnumType.Success) + .SetColumns(x => x.ModifiedTime == DateTime.Now) + .Where(x => x.Id == orderId) + .ExecuteCommandAsync(); + + _logs.Add("更新image和订单信息:" + _sw.ElapsedMilliseconds); + _sw.Restart(); + } + catch (Exception ex) + { + await DbContext.Updateable() + .SetColumns(x => x.OrderStatus == CanteenOrderStatusEnumType.Failure) + .SetColumns(x => x.Result == ex.Message) + .SetColumns(x => x.ModifiedTime == DateTime.Now) + .Where(x => x.Id == orderId) + .ExecuteCommandAsync(); + + throw; + } + } + + /// + /// 消费前预检 + /// + /// + /// + /// + private async Task PreCheckAsync(string deviceUniqueNo, DateTime costDateTime) + { + var registry = await DbContext.Queryable().Where(x => x.DeviceUniqueNo == deviceUniqueNo).SingleAsync(); + registry.ThrowIfNull("设备尚未登记"); + + var device = await DbContext.Queryable().Where(x => x.UniqueNo == deviceUniqueNo).SingleAsync(); + device.ThrowIfNull("设备尚未登记"); + device.Enable.ThrowIfFalse("设备已被停用"); + + var businessPlaceInfo = await DbContext.Queryable() + .LeftJoin((x, sr) => x.Code == sr.PlaceCode) + .Where(x => x.Code == registry.BusinessPlaceCode) + .Select((x, sr) => new + { + x.Code, + sr.ShiftCode, + x.TenantId + }) + .SingleAsync(); + + businessPlaceInfo.ThrowIfNull("设备尚未登记营业点"); + + //获取当前消费餐次 + var shifts = await DbContext.Queryable().Where(x => x.ShiftCode == businessPlaceInfo.ShiftCode).ToListAsync(); + shifts.ThrowIfEmpty("营业点餐次尚未设置"); + + var shift = shifts.FirstOrDefault(x => new TimePeriod + { + Start = x.Start, + End = x.End + }.IsPresent(costDateTime)); + shift.ThrowIfNull("非就餐时间,无法消费"); + + var costDate = await GetCostDateAsync(shift, costDateTime); + + return new OrderPreCheckDto + { + CostDate = costDate, + Shift = shift, + BusinessPlaceTenantId = businessPlaceInfo.TenantId, + BusinessPlaceCode = businessPlaceInfo.Code, + BusinessShiftCode = businessPlaceInfo.ShiftCode + }; } } \ No newline at end of file diff --git a/Src/Dlhis.Entity/Canteen/Entities/BalanceRecordEntity.cs b/Src/Dlhis.Entity/Canteen/Entities/BalanceRecordEntity.cs index b5874947..a3fdedda 100644 --- a/Src/Dlhis.Entity/Canteen/Entities/BalanceRecordEntity.cs +++ b/Src/Dlhis.Entity/Canteen/Entities/BalanceRecordEntity.cs @@ -91,12 +91,6 @@ public class BalanceRecordEntity : SugarBaseEntity, ISoftDeleted, ITenantId [SugarColumn(ColumnDescription = "消费机器唯一信息", IsNullable = true)] public string DeviceUniqueNo { get; set; } - /// - /// 餐补月份 - /// - [SugarColumn(ColumnDescription = "餐补月份")] - public string SubsidiesFromMonth { get; set; } - /// /// Ip /// diff --git a/Src/Dlhis.Entity/Canteen/Entities/EMealVoucherDetailEntity.cs b/Src/Dlhis.Entity/Canteen/Entities/EMealVoucherDetailEntity.cs index b41f0533..35a963b2 100644 --- a/Src/Dlhis.Entity/Canteen/Entities/EMealVoucherDetailEntity.cs +++ b/Src/Dlhis.Entity/Canteen/Entities/EMealVoucherDetailEntity.cs @@ -1,4 +1,5 @@ -using Kurisu.AspNetCore.DataAccess.SqlSugar; +using Kurisu.AspNetCore.DataAccess.Entity; +using Kurisu.AspNetCore.DataAccess.SqlSugar; using SqlSugar; namespace Dlhis.Entity.Canteen.Entities; @@ -7,7 +8,7 @@ namespace Dlhis.Entity.Canteen.Entities; /// 电子餐券明细 /// [SugarTable(TableName = "EMealVoucherDetail", TableDescription = "电子餐券明细")] -public class EMealVoucherDetailEntity : SugarBaseEntity +public class EMealVoucherDetailEntity : SugarBaseEntity, IVersion { /// /// 主表id @@ -18,7 +19,7 @@ public class EMealVoucherDetailEntity : SugarBaseEntity /// /// 流水号 /// - [SugarColumn(ColumnDescription = "流水号")] + [SugarColumn(ColumnDescription = "流水号", UniqueGroupNameList = new[] { "idx_EMealVoucherDetail_no_idno" })] public string No { get; set; } /// @@ -30,7 +31,7 @@ public class EMealVoucherDetailEntity : SugarBaseEntity /// /// 身份证 /// - [SugarColumn(ColumnDescription = "序号")] + [SugarColumn(ColumnDescription = "证件号", UniqueGroupNameList = new[] { "idx_EMealVoucherDetail_no_idno" })] public string IdNo { get; set; } /// @@ -60,6 +61,16 @@ public class EMealVoucherDetailEntity : SugarBaseEntity /// /// 金额 /// - [SugarColumn(ColumnDescription = "金额", ColumnDataType = "decimal(16,2)")] - public decimal Amount { get; set; } + [SugarColumn(ColumnDescription = "余额", ColumnDataType = "decimal(16,2)")] + public decimal Balance { get; set; } + + /// + /// 版本 + /// + [SugarColumn(ColumnDescription = "版本")] + public int Version { get; set; } + + + [SugarColumn(ColumnDataType = "varchar(255)")] + public string Signature { get; set; } } \ No newline at end of file diff --git a/Src/Dlhis.Entity/Canteen/Entities/EMealVoucherDetailQrCodeEntity.cs b/Src/Dlhis.Entity/Canteen/Entities/EMealVoucherDetailQrCodeEntity.cs new file mode 100644 index 00000000..b1a6b505 --- /dev/null +++ b/Src/Dlhis.Entity/Canteen/Entities/EMealVoucherDetailQrCodeEntity.cs @@ -0,0 +1,29 @@ +using Kurisu.AspNetCore.DataAccess.SqlSugar; +using SqlSugar; + +namespace Dlhis.Entity.Canteen.Entities; + +/// +/// 电子餐券明细QrCode +/// +[SugarTable(TableName = "EMealVoucherDetailQrCode", TableDescription = "电子餐券明细QrCode")] +public class EMealVoucherDetailQrCodeEntity : SugarBaseEntity +{ + /// + /// url签名 + /// + [SugarColumn(ColumnDataType = "varchar(255)", IndexGroupNameList = new[] { "idx_EMealVoucherDetailQrCode_signature" })] + public string Signature { get; set; } + + /// + /// 原始数据 + /// + [SugarColumn(ColumnDescription = "原始数据")] + public string OriginData { get; set; } + + /// + /// 二维码 + /// + [SugarColumn(ColumnDescription = "二维码", UniqueGroupNameList = new[] { "idx_EMealVoucherDetailQrCode_qrcode" })] + public string QrCode { get; set; } +} \ No newline at end of file diff --git a/Src/Dlhis.Entity/Canteen/Enums/BalanceRecordSourceEnumType.cs b/Src/Dlhis.Entity/Canteen/Enums/BalanceRecordSourceEnumType.cs index 587169b8..79d86f43 100644 --- a/Src/Dlhis.Entity/Canteen/Enums/BalanceRecordSourceEnumType.cs +++ b/Src/Dlhis.Entity/Canteen/Enums/BalanceRecordSourceEnumType.cs @@ -36,7 +36,7 @@ public enum BalanceRecordSourceEnumType /// 电子餐券 /// [Description("电子餐券")] - EVoucher, + EMealVoucher, //********************************************************************************************************* /// diff --git a/Src/Dlhis.External/EMealVoucher/Request/EMealVoucherReceiveRequest.cs b/Src/Dlhis.External/EMealVoucher/Request/EMealVoucherReceiveRequest.cs index 86f3aa3f..76597552 100644 --- a/Src/Dlhis.External/EMealVoucher/Request/EMealVoucherReceiveRequest.cs +++ b/Src/Dlhis.External/EMealVoucher/Request/EMealVoucherReceiveRequest.cs @@ -82,6 +82,11 @@ public class EMealVoucherReceiveRequest : IValidatableObject { yield return new ValidationResult("来宾数量不匹配", new[] { nameof(Number) }); } + + if (Details.DistinctBy(x => x.IdNo).Count() != Details.Count) + { + yield return new ValidationResult("证件信息重复", new[] { "IdNo" }); + } } } diff --git a/Src/Dlhis.External/EMealVoucher/Services/Implements/EMealVoucherService.cs b/Src/Dlhis.External/EMealVoucher/Services/Implements/EMealVoucherService.cs index 9e12372a..a956a612 100644 --- a/Src/Dlhis.External/EMealVoucher/Services/Implements/EMealVoucherService.cs +++ b/Src/Dlhis.External/EMealVoucher/Services/Implements/EMealVoucherService.cs @@ -43,7 +43,7 @@ public class EMealVoucherService : IEMealVoucherService Phone = x.Phone, Start = x.Start, End = x.End, - Amount = x.Amount + Balance = x.Amount }).ToList(); var id = await _dbContext.InsertReturnIdentityAsync(voucher); diff --git a/Src/Dlhis.Middle/Services/Implements/OrderService.cs b/Src/Dlhis.Middle/Services/Implements/OrderService.cs index 98126066..a632b1c5 100644 --- a/Src/Dlhis.Middle/Services/Implements/OrderService.cs +++ b/Src/Dlhis.Middle/Services/Implements/OrderService.cs @@ -171,7 +171,6 @@ public class OrderService : IOrderService DeviceUniqueNo = request.DeviceUniqueNo, No = _factory + "-" + SnowFlakeHelper.Instance.NextId(), - SubsidiesFromMonth = request.CostDateTime.ToString("yyyyMM"), // IsOffline = request.IsOffline, IsCostCrossTenant = await GetSettingAsync(businessPlaceInfo!.TenantId, CanteenSettingItemEnumType.AllowCrossTenant), diff --git a/Src/Dlhis.ScheduledTask/Jobs/MealSupplementHandlerJob.cs b/Src/Dlhis.ScheduledTask/Jobs/MealSupplementHandlerJob.cs index 0f288bd5..1a3698ca 100644 --- a/Src/Dlhis.ScheduledTask/Jobs/MealSupplementHandlerJob.cs +++ b/Src/Dlhis.ScheduledTask/Jobs/MealSupplementHandlerJob.cs @@ -156,7 +156,6 @@ public class MealSupplementHandlerJob : BaseJob Source = BalanceRecordSourceEnumType.LocalTenantSubsidies, Remark = mealSupplement.UniqueId + ":" + mealSupplement.Remark, CostId = gainfo.CostId, - SubsidiesFromMonth = mealSupplement.Date.ToString("yyyyMM"), OriginTenantId = gainfo.Factory, Werks = gainfo.Werks, Name = gainfo.Name, diff --git a/Src/Gateway/Program.cs b/Src/Gateway/Program.cs index e96a2582..c8fd2e8b 100644 --- a/Src/Gateway/Program.cs +++ b/Src/Gateway/Program.cs @@ -1,4 +1,3 @@ - using Gateway; public class Program @@ -8,13 +7,14 @@ public class Program Host.CreateDefaultBuilder(args) .ConfigureAppConfiguration((context, builder) => { - builder.AddJsonFile("ocelot.json", true, true); + if (context.HostingEnvironment.IsProduction()) + { + builder.AddJsonFile("ocelot.json", true, true); + } + builder.AddJsonFile($"ocelot.{context.HostingEnvironment.EnvironmentName}.json", true, true); }) - .ConfigureWebHostDefaults(webBuilder => - { - webBuilder.UseStartup(); - }) + .ConfigureWebHostDefaults(webBuilder => { webBuilder.UseStartup(); }) .Build().Run(); } -} +} \ No newline at end of file diff --git a/Src/Gateway/appsettings.json b/Src/Gateway/appsettings.json index 508d6f2a..d0e733e1 100644 --- a/Src/Gateway/appsettings.json +++ b/Src/Gateway/appsettings.json @@ -11,7 +11,6 @@ "Common", "Canteen", "Scheduled", - "User", "Sys", "Visitor", "Message" diff --git a/Src/Gateway/ocelot.Development.json b/Src/Gateway/ocelot.Development.json index e1aaacf0..45f461c0 100644 --- a/Src/Gateway/ocelot.Development.json +++ b/Src/Gateway/ocelot.Development.json @@ -72,7 +72,7 @@ "DownstreamScheme": "http", "DownstreamHostAndPorts": [ { - "Host": "localhost", + "Host": "192.168.199.115", "Port": 6000 } ] From fa3fc4e6b4b6b987c1a41adafe5f3671ca79af10 Mon Sep 17 00:00:00 2001 From: liguoyang Date: Wed, 14 Aug 2024 15:43:37 +0800 Subject: [PATCH 08/25] =?UTF-8?q?refactor=20=E4=BB=A3=E7=A0=81=E4=BC=98?= =?UTF-8?q?=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Order/Controllers/OrdersController.cs | 50 +------ .../Order/Services/Implements/OrderService.cs | 138 ++++++++---------- 2 files changed, 68 insertions(+), 120 deletions(-) diff --git a/Src/Dlhis.Canteen/Order/Controllers/OrdersController.cs b/Src/Dlhis.Canteen/Order/Controllers/OrdersController.cs index 51e0027c..59ab64b3 100644 --- a/Src/Dlhis.Canteen/Order/Controllers/OrdersController.cs +++ b/Src/Dlhis.Canteen/Order/Controllers/OrdersController.cs @@ -1,12 +1,10 @@ -using System.Diagnostics; -using Dlhis.Canteen.Dishes.Request; +using Dlhis.Canteen.Dishes.Request; using Dlhis.Canteen.Order.Request; using Dlhis.Canteen.Order.Response; using Dlhis.Canteen.Order.Services; using Kurisu.AspNetCore.DataAccess.Dto; using Kurisu.AspNetCore.DataAccess.SqlSugar.Aop; using Kurisu.AspNetCore.UnifyResultAndValidation; -using Kurisu.AspNetCore.Utils.Extensions; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; @@ -22,13 +20,11 @@ public class OrdersController : ControllerBase { private readonly IOrderService _orderService; private readonly IBookingOrderService _bookingOrderService; - private readonly ILogger _logger; - public OrdersController(IOrderService orderService, IBookingOrderService bookingOrderService, ILogger logger) + public OrdersController(IOrderService orderService, IBookingOrderService bookingOrderService) { _orderService = orderService; _bookingOrderService = bookingOrderService; - _logger = logger; } /// @@ -41,27 +37,8 @@ public class OrdersController : ControllerBase [IgnoreTenant] public async Task> AddAsync(OrderAddRequest request) { - var sw = Stopwatch.StartNew(); var result = await _orderService.AddAsync(request); - try - { - return result.Response; - } - finally - { - var ms = sw.ElapsedMilliseconds; - try - { - if (ms > 1000) - { - _logger.LogInformation("消费请求:{json}. 耗时记录:{log}", request.ToJson(), result.Logs.Join("\r\n")); - } - } - catch (Exception) - { - //ignore - } - } + return result.Response; } /// @@ -74,27 +51,8 @@ public class OrdersController : ControllerBase [IgnoreTenant] public async Task> DeviceConsume(OrderAddRequest request) { - var sw = Stopwatch.StartNew(); var result = await _orderService.AddAsync(request); - try - { - return result.Response; - } - finally - { - var ms = sw.ElapsedMilliseconds; - try - { - if (ms > 1000) - { - _logger.LogInformation("消费请求:{json}. 耗时记录:{log}", request.ToJson(), result.Logs.Join("\r\n")); - } - } - catch (Exception) - { - //ignore - } - } + return result.Response; } /// diff --git a/Src/Dlhis.Canteen/Order/Services/Implements/OrderService.cs b/Src/Dlhis.Canteen/Order/Services/Implements/OrderService.cs index e94823f6..d0c8b274 100644 --- a/Src/Dlhis.Canteen/Order/Services/Implements/OrderService.cs +++ b/Src/Dlhis.Canteen/Order/Services/Implements/OrderService.cs @@ -1,5 +1,4 @@ -using System.Diagnostics; -using Dlhis.Canteen.Order.Dto; +using Dlhis.Canteen.Order.Dto; using Dlhis.Canteen.Setting.Services; using Dlhis.Entity.Basic.Entity; using Dlhis.Entity.Canteen.Entities; @@ -24,8 +23,6 @@ namespace Dlhis.Canteen.Order.Services.Implements; public class OrderService : BaseOrderService, IOrderService { private readonly IServiceProvider _serviceProvider; - private Stopwatch _sw; - private readonly List _logs = new(); public OrderService(ICanteenSettingService canteenSettingService, IDbContext dbContext, @@ -54,44 +51,11 @@ public class OrderService : BaseOrderService, IOrderService /// public async Task AddAsync(OrderAddRequest request) { - _sw = new Stopwatch(); - var gainfo = await GetUserAsync(request); - _logs.Add("获取人员耗时:" + _sw.ElapsedMilliseconds); - _sw.Restart(); - - var message = await ToDoAsync(request, gainfo); - - //获取人员余额 - var data = await DbContext.Queryable() - .LeftJoin((x, ga) => x.UserNo == ga.No) - .LeftJoin((x, ga, department) => ga.DepartmentNo == department.No) - .Where(x => x.UserNo == gainfo.No) - .Select((x, ga, department) => new OrderResultResponse - { - UserCode = ga.Code, - UserName = ga.Name, - DepartmentNo = ga.DepartmentNo, - DepartmentName = department.Name, - CurrentBalance = x.Balance - }) - .SingleAsync(); - - var result = new DefaultApiResult - { - Code = message.IsPresent() ? ApiStateCode.Error : ApiStateCode.Success, - Data = data, - Msg = message - }; - - _logs.Add("获取余额:" + _sw.ElapsedMilliseconds); - _sw.Restart(); - return new OrderResultResponseWithLogs { - Response = result, - Logs = _logs + Response = await ToDoAsync(request, gainfo) }; } @@ -306,8 +270,6 @@ public class OrderService : BaseOrderService, IOrderService var order = await DbContext.Queryable().Where(x => x.Id == orderId).SingleAsync(); //校验 await Verify(order); - _logs.Add("消费请求校验:" + _sw.ElapsedMilliseconds); - _sw.Restart(); await CommonHelper.RetryAsync(async () => { @@ -327,9 +289,6 @@ public class OrderService : BaseOrderService, IOrderService var balanceRecord = order.Adapt(); await DbContext.InsertAsync(balanceRecord); }, 5); - - _logs.Add("消费写入:" + _sw.ElapsedMilliseconds); - _sw.Restart(); } /// @@ -482,9 +441,6 @@ public class OrderService : BaseOrderService, IOrderService }.IsPresent(request.CostDateTime)); shift.ThrowIfNull("非就餐时间,无法消费"); - _logs.Add("检验设备和营业点参数:" + _sw.ElapsedMilliseconds); - _sw.Restart(); - var costDate = await GetCostDateAsync(shift, request.CostDateTime); (request.Source == BalanceRecordSourceEnumType.QrCode && businessPlaceInfo.TenantId != gainfo.Factory).ThrowIfTrue("禁止跨厂区消费"); @@ -527,8 +483,6 @@ public class OrderService : BaseOrderService, IOrderService }; var orderId = await DbContext.InsertReturnIdentityAsync(order); - _logs.Add("临时order写入:" + _sw.ElapsedMilliseconds); - _sw.Restart(); try { @@ -549,9 +503,6 @@ public class OrderService : BaseOrderService, IOrderService .SetColumns(x => x.ModifiedTime == DateTime.Now) .Where(x => x.Id == orderId) .ExecuteCommandAsync(); - - _logs.Add("更新image和订单信息:" + _sw.ElapsedMilliseconds); - _sw.Restart(); } catch (Exception ex) { @@ -573,20 +524,55 @@ public class OrderService : BaseOrderService, IOrderService /// /// /// - private async Task ToDoAsync(OrderAddRequest request, GainfoEntity gainfo) + private async Task> ToDoAsync(OrderAddRequest request, GainfoEntity gainfo) { var message = string.Empty; if (request.Source == BalanceRecordSourceEnumType.EMealVoucher) { + var eMealVoucherQrCode = await DbContext.Queryable().Where(x => x.QrCode == request.UserUniqueNo).SingleAsync(); + if (eMealVoucherQrCode == null) + { + message = "无法识别"; + return new DefaultApiResult + { + Code = ApiStateCode.Error, + Data = null, + Msg = message + }; + } + + var originData = eMealVoucherQrCode.OriginData.Split(':'); + + var no = originData[0]; + var ts = originData[1]; + var idNo = originData[3]; + try { - await EMealVoucherConsumeAsync(request.Adapt(), gainfo); + await EMealVoucherConsumeAsync(request.Adapt(), gainfo, eMealVoucherQrCode.OriginData, no, ts, idNo); } catch (Exception ex) { message = ex.Message; } + + //获取餐券余额 + var data = await DbContext.Queryable() + .LeftJoin((x, d) => x.No == d.No) + .Where((x, d) => d.IdNo == idNo) + .Select((x, d) => new OrderResultResponse + { + CurrentBalance = d.Balance + }) + .SingleAsync(); + + return new DefaultApiResult + { + Code = message.IsPresent() ? ApiStateCode.Error : ApiStateCode.Success, + Data = data, + Msg = message + }; } else { @@ -633,9 +619,29 @@ public class OrderService : BaseOrderService, IOrderService message = ex.Message; } } - } - return message; + //获取人员余额 + var data = await DbContext.Queryable() + .LeftJoin((x, ga) => x.UserNo == ga.No) + .LeftJoin((x, ga, department) => ga.DepartmentNo == department.No) + .Where(x => x.UserNo == gainfo.No) + .Select((x, ga, department) => new OrderResultResponse + { + UserCode = ga.Code, + UserName = ga.Name, + DepartmentNo = ga.DepartmentNo, + DepartmentName = department.Name, + CurrentBalance = x.Balance + }) + .SingleAsync(); + + return new DefaultApiResult + { + Code = message.IsPresent() ? ApiStateCode.Error : ApiStateCode.Success, + Data = data, + Msg = message + }; + } async Task ToCheckAbleOfflineConsumeAsync(string thirdNo) { @@ -669,19 +675,14 @@ public class OrderService : BaseOrderService, IOrderService } - private async Task EMealVoucherConsumeAsync(ConsumeRequest request, GainfoEntity gainfo) + private async Task EMealVoucherConsumeAsync(ConsumeRequest request, GainfoEntity gainfo, string originData, string no, string ts, string idNo) { - var eMealVoucherQrCode = await DbContext.Queryable().Where(x => x.QrCode == request.UserUniqueNo).SingleAsync(); - var originData = eMealVoucherQrCode.OriginData.Split(':'); - - var no = originData[0]; - var idNo = originData[3]; var nowDate = DateTime.Now.Date; var current = await DbContext.Queryable() .Where(x => x.No == no && x.IdNo == idNo).SingleAsync(); (nowDate >= current.Start && nowDate <= current.End).ThrowIfFalse("餐券已过期"); - var time = DateTimeOffset.FromUnixTimeMilliseconds(Convert.ToInt64(originData[1].Reverse().Join(string.Empty))).ToLocalTime().DateTime; + var time = DateTimeOffset.FromUnixTimeMilliseconds(Convert.ToInt64(ts.Reverse().Join(string.Empty))).ToLocalTime().DateTime; (time.AddMinutes(60) >= DateTime.Now).ThrowIfFalse("二维码已过期"); var eMealVoucher = await DbContext.Queryable().Where(x => x.No == no).SingleAsync(); @@ -689,9 +690,6 @@ public class OrderService : BaseOrderService, IOrderService var checkData = await PreCheckAsync(request.DeviceUniqueNo, request.CostDateTime); eMealVoucher.Factories.Contains(checkData.BusinessPlaceTenantId).ThrowIfFalse("禁止在当前厂区消费"); - _logs.Add("检验设备和营业点参数:" + _sw.ElapsedMilliseconds); - _sw.Restart(); - var order = new CanteenOrderEntity { RequestJson = request.ToJson(), @@ -700,7 +698,7 @@ public class OrderService : BaseOrderService, IOrderService ApplicationType = CanteenApplicationTypeEnumType.Device, Name = gainfo.Name, Source = request.Source, - UserNo = eMealVoucherQrCode.OriginData, //记录为当前消费券 + UserNo = originData, //记录为当前消费券 UserCode = gainfo.Code, Amount = request.Amount, BusinessPlaceCode = checkData.BusinessPlaceCode, @@ -725,8 +723,6 @@ public class OrderService : BaseOrderService, IOrderService }; var orderId = await DbContext.InsertReturnIdentityAsync(order); - _logs.Add("临时order写入:" + _sw.ElapsedMilliseconds); - _sw.Restart(); try { @@ -749,17 +745,11 @@ public class OrderService : BaseOrderService, IOrderService await DbContext.InsertAsync(balanceRecord); }, 5); - _logs.Add("消费写入:" + _sw.ElapsedMilliseconds); - _sw.Restart(); - await DbContext.Updateable() .SetColumns(x => x.OrderStatus == CanteenOrderStatusEnumType.Success) .SetColumns(x => x.ModifiedTime == DateTime.Now) .Where(x => x.Id == orderId) .ExecuteCommandAsync(); - - _logs.Add("更新image和订单信息:" + _sw.ElapsedMilliseconds); - _sw.Restart(); } catch (Exception ex) { From dd4a94a7cdb0caee53e5ccb518417f8658653050 Mon Sep 17 00:00:00 2001 From: liguoyang Date: Wed, 14 Aug 2024 16:47:12 +0800 Subject: [PATCH 09/25] =?UTF-8?q?fix=20route=E5=90=8D=E7=A7=B0=E4=BF=AE?= =?UTF-8?q?=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Organization/Services/Implements/GainfoService.cs | 6 +++--- .../EMealVoucher/Controllers/EMealVoucherController.cs | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Src/Dlhis.Basic/Organization/Services/Implements/GainfoService.cs b/Src/Dlhis.Basic/Organization/Services/Implements/GainfoService.cs index a4690c83..fd693f37 100644 --- a/Src/Dlhis.Basic/Organization/Services/Implements/GainfoService.cs +++ b/Src/Dlhis.Basic/Organization/Services/Implements/GainfoService.cs @@ -463,14 +463,14 @@ public class GainfoService : IGainfoService return departmentNos.Distinct().ToList(); //local method - void RecursionGetNext(string currentNo, List departments, List result) + void RecursionGetNext(string currentNo, List internalDepartments, List result) { - var next = departments.Where(x => x.PNo == currentNo).ToList(); + var next = internalDepartments.Where(x => x.PNo == currentNo).ToList(); foreach (var item in next) { result.Add(item.No); - RecursionGetNext(item.No, departments, result); + RecursionGetNext(item.No, internalDepartments, result); } } } diff --git a/Src/Dlhis.Canteen/EMealVoucher/Controllers/EMealVoucherController.cs b/Src/Dlhis.Canteen/EMealVoucher/Controllers/EMealVoucherController.cs index 40b9483d..a4dd5f14 100644 --- a/Src/Dlhis.Canteen/EMealVoucher/Controllers/EMealVoucherController.cs +++ b/Src/Dlhis.Canteen/EMealVoucher/Controllers/EMealVoucherController.cs @@ -35,7 +35,7 @@ public class EMealVoucherController : ControllerBase /// /// /// - [HttpGet("no")] + [HttpGet("details")] public async Task> GetDetailsByNoAsync(string no) { return await _eMealVoucherService.GetDetailsByNoAsync(no); From 9e9368954ea8e67ee6cf987e391dafd9f1da9d4b Mon Sep 17 00:00:00 2001 From: liguoyang Date: Tue, 13 Aug 2024 10:32:27 +0800 Subject: [PATCH 10/25] =?UTF-8?q?feat=20=E9=A4=90=E6=AC=A1=E5=B0=B1?= =?UTF-8?q?=E9=A4=90=E5=88=86=E6=9E=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Controllers/BalanceSummaryController.cs | 9 ++++ .../Order/Dto/ShiftSummaryDto.cs | 9 ++++ .../BalanceRecordAnalysisByShiftRequest.cs | 29 +++++++++++++ .../BalanceRecordAnalysisShiftResponse.cs | 20 +++++++++ .../Order/Services/IBalanceSummaryService.cs | 5 ++- .../Implements/BalanceSummaryService.cs | 42 ++++++++++++++++++- .../Menu/Controllers/MenusController.cs | 1 + 7 files changed, 113 insertions(+), 2 deletions(-) create mode 100644 Src/Dlhis.Canteen/Order/Dto/ShiftSummaryDto.cs create mode 100644 Src/Dlhis.Canteen/Order/Request/BalanceRecordAnalysisByShiftRequest.cs create mode 100644 Src/Dlhis.Canteen/Order/Response/BalanceRecordAnalysisShiftResponse.cs diff --git a/Src/Dlhis.Canteen/Order/Controllers/BalanceSummaryController.cs b/Src/Dlhis.Canteen/Order/Controllers/BalanceSummaryController.cs index 96e3cc09..4326f250 100644 --- a/Src/Dlhis.Canteen/Order/Controllers/BalanceSummaryController.cs +++ b/Src/Dlhis.Canteen/Order/Controllers/BalanceSummaryController.cs @@ -41,4 +41,13 @@ public class BalanceSummaryController : ControllerBase { return await _balanceSummaryService.BalanceRecordAnalysisByCostIdAsync(); } + + /// + /// 用餐分析(餐次) + /// + [HttpGet("analysis/shift")] + public async Task BalanceRecordAnalysisByShiftAsync([FromQuery] BalanceRecordAnalysisByShiftRequest request) + { + return await _balanceSummaryService.BalanceRecordAnalysisByShiftAsync(request); + } } \ No newline at end of file diff --git a/Src/Dlhis.Canteen/Order/Dto/ShiftSummaryDto.cs b/Src/Dlhis.Canteen/Order/Dto/ShiftSummaryDto.cs new file mode 100644 index 00000000..5dfa4954 --- /dev/null +++ b/Src/Dlhis.Canteen/Order/Dto/ShiftSummaryDto.cs @@ -0,0 +1,9 @@ +using Dlhis.Entity.Canteen.Enums; + +namespace Dlhis.Canteen.Order.Dto; + +public class ShiftSummaryDto +{ + public ShiftEnumType? Shift { get; set; } + public T Value { get; set; } +} \ No newline at end of file diff --git a/Src/Dlhis.Canteen/Order/Request/BalanceRecordAnalysisByShiftRequest.cs b/Src/Dlhis.Canteen/Order/Request/BalanceRecordAnalysisByShiftRequest.cs new file mode 100644 index 00000000..65f99310 --- /dev/null +++ b/Src/Dlhis.Canteen/Order/Request/BalanceRecordAnalysisByShiftRequest.cs @@ -0,0 +1,29 @@ +using System.ComponentModel.DataAnnotations; +using Kurisu.AspNetCore.CustomClass; +using Kurisu.AspNetCore.DataAccess.Dto; + +namespace Dlhis.Canteen.Order.Request; + +public class BalanceRecordAnalysisByShiftRequest : PageDto, IValidatableObject +{ + /// + /// 营业点 + /// + public List BusinessPlaceCodes { get; set; } + + /// + /// + /// + public DateTimePeriod SearchDateTimePeriod { get; set; } + + /// + public IEnumerable Validate(ValidationContext validationContext) + { + if (SearchDateTimePeriod is { End: not null }) + { + SearchDateTimePeriod.End = SearchDateTimePeriod.End.Value.AddDays(1).AddSeconds(-1); + } + + yield break; + } +} \ No newline at end of file diff --git a/Src/Dlhis.Canteen/Order/Response/BalanceRecordAnalysisShiftResponse.cs b/Src/Dlhis.Canteen/Order/Response/BalanceRecordAnalysisShiftResponse.cs new file mode 100644 index 00000000..5598845f --- /dev/null +++ b/Src/Dlhis.Canteen/Order/Response/BalanceRecordAnalysisShiftResponse.cs @@ -0,0 +1,20 @@ +using Dlhis.Canteen.Order.Dto; +using Kurisu.AspNetCore.DataAccess.Dto; +using Kurisu.AspNetCore.Utils.Converters; +using Newtonsoft.Json; + +namespace Dlhis.Canteen.Order.Response; + +public class BalanceRecordAnalysisShiftResponse +{ + public decimal Amount { get; set; } + public Pagination Pagination { get; set; } +} + +public class BalanceRecordAnalysisShiftPageResponse +{ + [JsonConverter(typeof(ToDateJsonConverter))] + public DateTime Date { get; set; } + + public List> Shifts { get; set; } +} \ No newline at end of file diff --git a/Src/Dlhis.Canteen/Order/Services/IBalanceSummaryService.cs b/Src/Dlhis.Canteen/Order/Services/IBalanceSummaryService.cs index 113be8c6..79707980 100644 --- a/Src/Dlhis.Canteen/Order/Services/IBalanceSummaryService.cs +++ b/Src/Dlhis.Canteen/Order/Services/IBalanceSummaryService.cs @@ -9,4 +9,7 @@ public interface IBalanceSummaryService : IScopeDependency Task BalanceRecordAnalysisAsync(BalanceRecordAnalysisRequest request); Task> BalanceRecordAnalysisByCostIdAsync(); -} + + + Task BalanceRecordAnalysisByShiftAsync(BalanceRecordAnalysisByShiftRequest request); +} \ No newline at end of file diff --git a/Src/Dlhis.Canteen/Order/Services/Implements/BalanceSummaryService.cs b/Src/Dlhis.Canteen/Order/Services/Implements/BalanceSummaryService.cs index 8db7ff01..cb79225a 100644 --- a/Src/Dlhis.Canteen/Order/Services/Implements/BalanceSummaryService.cs +++ b/Src/Dlhis.Canteen/Order/Services/Implements/BalanceSummaryService.cs @@ -1,4 +1,6 @@ -using Dlhis.Canteen.Order.Request; +using System.Reflection; +using Dlhis.Canteen.Order.Dto; +using Dlhis.Canteen.Order.Request; using Dlhis.Canteen.Order.Response; using Dlhis.Entity.Canteen.Entities; using Dlhis.Entity.Canteen.Enums; @@ -6,6 +8,7 @@ using Kurisu.AspNetCore.CustomClass; using Kurisu.AspNetCore.DataAccess.Dto; using Kurisu.AspNetCore.DataAccess.Extensions; using Kurisu.AspNetCore.DataAccess.SqlSugar.Services; +using SqlSugar; namespace Dlhis.Canteen.Order.Services.Implements; @@ -85,4 +88,41 @@ public class BalanceSummaryService : IBalanceSummaryService return null; } + + + public async Task BalanceRecordAnalysisByShiftAsync(BalanceRecordAnalysisByShiftRequest request) + { + var queryable = _dbContext.Queryable() + .Where(x => x.Status == BalanceRecordStatusEnumType.Valid && x.Type == BalanceRecordTypeEnumType.Out) + .WhereIF(request.SearchDateTimePeriod.HasValue(), x => x.CostDate >= request.SearchDateTimePeriod.Start && x.CostDate <= request.SearchDateTimePeriod.End) + .WhereIF(request.BusinessPlaceCodes?.Any() == true, x => request.BusinessPlaceCodes.Contains(x.BusinessPlaceCode.Value)); + + var amount = await queryable.SumAsync(x => x.Amount); + + var count = typeof(ShiftEnumType).GetFields(BindingFlags.Public | BindingFlags.Static).Length; + + var result = await queryable.GroupBy(x => new { x.CostDate, x.ShiftType }) + .Select(x => new { x.CostDate, x.ShiftType, Amount = SqlFunc.AggregateSum(SqlFunc.Abs(x.Amount)) }) + .ToPageListAsync(request.PageIndex, count * request.PageSize); + + return new BalanceRecordAnalysisShiftResponse + { + Amount = amount, + Pagination = new Pagination + { + PageIndex = request.PageIndex, + PageSize = request.PageSize, + Total = result.Count, + Data = result.GroupBy(x => x.CostDate).Select(x => new BalanceRecordAnalysisShiftPageResponse + { + Date = x.Key, + Shifts = x.Select(item => new ShiftSummaryDto + { + Shift = item.ShiftType, + Value = item.Amount + }).ToList() + }).ToList() + } + }; + } } \ No newline at end of file diff --git a/Src/Dlhis.Sys/Menu/Controllers/MenusController.cs b/Src/Dlhis.Sys/Menu/Controllers/MenusController.cs index 63203c04..0f32e9ea 100644 --- a/Src/Dlhis.Sys/Menu/Controllers/MenusController.cs +++ b/Src/Dlhis.Sys/Menu/Controllers/MenusController.cs @@ -102,6 +102,7 @@ public class MenusController : ControllerBase /// [Authorize(Roles = "admin")] [HttpPost("reset")] + [Transactional] public async Task ResetAsync(List request) { await _menuService.ResetAsync(request); From de6640e89e584ad3420021a1f33c2b8b277606fc Mon Sep 17 00:00:00 2001 From: liguoyang Date: Tue, 13 Aug 2024 13:46:06 +0800 Subject: [PATCH 11/25] =?UTF-8?q?feat=20=E5=B0=B1=E9=A4=90=E5=88=86?= =?UTF-8?q?=E6=9E=90,=E9=A4=90=E6=AC=A1=E4=BD=BF=E7=94=A8=E9=87=91?= =?UTF-8?q?=E9=A2=9D=E5=92=8C=E4=BA=BA=E6=95=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Controllers/BalanceSummaryController.cs | 19 +++++++++--- ...cordAnalysisShiftAmountAndCountResponse.cs | 16 ++++++++++ .../BalanceRecordAnalysisShiftResponse.cs | 2 +- .../Order/Services/IBalanceSummaryService.cs | 4 ++- .../Services/Implements/BalanceService.cs | 13 +++++--- .../Implements/BalanceSummaryService.cs | 31 +++++++++++++++++-- 6 files changed, 72 insertions(+), 13 deletions(-) create mode 100644 Src/Dlhis.Canteen/Order/Response/BalanceRecordAnalysisShiftAmountAndCountResponse.cs diff --git a/Src/Dlhis.Canteen/Order/Controllers/BalanceSummaryController.cs b/Src/Dlhis.Canteen/Order/Controllers/BalanceSummaryController.cs index 4326f250..154eafb0 100644 --- a/Src/Dlhis.Canteen/Order/Controllers/BalanceSummaryController.cs +++ b/Src/Dlhis.Canteen/Order/Controllers/BalanceSummaryController.cs @@ -43,11 +43,22 @@ public class BalanceSummaryController : ControllerBase } /// - /// 用餐分析(餐次) + /// 餐次用餐分析,统计金额 /// - [HttpGet("analysis/shift")] - public async Task BalanceRecordAnalysisByShiftAsync([FromQuery] BalanceRecordAnalysisByShiftRequest request) + [HttpGet("shift/analysis/amount")] + public async Task BalanceRecordShiftAnalysisAmountAsync([FromQuery] BalanceRecordAnalysisByShiftRequest request) { - return await _balanceSummaryService.BalanceRecordAnalysisByShiftAsync(request); + return await _balanceSummaryService.BalanceRecordShiftAnalysisAmountAsync(request); + } + + /// + /// 餐次用餐分析,统计金额和人数 + /// + /// + /// + [HttpGet("shift/analysis/amountAndCount")] + public async Task BalanceRecordShiftAnalysisAmountAndCountAsync([FromQuery] BalanceRecordAnalysisByShiftRequest request) + { + return await _balanceSummaryService.BalanceRecordShiftAnalysisAmountAndCountAsync(request); } } \ No newline at end of file diff --git a/Src/Dlhis.Canteen/Order/Response/BalanceRecordAnalysisShiftAmountAndCountResponse.cs b/Src/Dlhis.Canteen/Order/Response/BalanceRecordAnalysisShiftAmountAndCountResponse.cs new file mode 100644 index 00000000..e20d86d3 --- /dev/null +++ b/Src/Dlhis.Canteen/Order/Response/BalanceRecordAnalysisShiftAmountAndCountResponse.cs @@ -0,0 +1,16 @@ +using Dlhis.Entity.Canteen.Enums; + +namespace Dlhis.Canteen.Order.Response; + +public class BalanceRecordAnalysisShiftAmountAndCountResponse +{ + public decimal Amount { get; set; } + public List Items { get; set; } +} + +public class BalanceRecordAnalysisShiftAmountAndCountItemResponse +{ + public ShiftEnumType? ShiftType { get; set; } + public decimal Amount { get; set; } + public int Count { get; set; } +} \ No newline at end of file diff --git a/Src/Dlhis.Canteen/Order/Response/BalanceRecordAnalysisShiftResponse.cs b/Src/Dlhis.Canteen/Order/Response/BalanceRecordAnalysisShiftResponse.cs index 5598845f..75b66dbe 100644 --- a/Src/Dlhis.Canteen/Order/Response/BalanceRecordAnalysisShiftResponse.cs +++ b/Src/Dlhis.Canteen/Order/Response/BalanceRecordAnalysisShiftResponse.cs @@ -5,7 +5,7 @@ using Newtonsoft.Json; namespace Dlhis.Canteen.Order.Response; -public class BalanceRecordAnalysisShiftResponse +public class BalanceRecordAnalysisShiftAmountResponse { public decimal Amount { get; set; } public Pagination Pagination { get; set; } diff --git a/Src/Dlhis.Canteen/Order/Services/IBalanceSummaryService.cs b/Src/Dlhis.Canteen/Order/Services/IBalanceSummaryService.cs index 79707980..b6a192d9 100644 --- a/Src/Dlhis.Canteen/Order/Services/IBalanceSummaryService.cs +++ b/Src/Dlhis.Canteen/Order/Services/IBalanceSummaryService.cs @@ -11,5 +11,7 @@ public interface IBalanceSummaryService : IScopeDependency Task> BalanceRecordAnalysisByCostIdAsync(); - Task BalanceRecordAnalysisByShiftAsync(BalanceRecordAnalysisByShiftRequest request); + Task BalanceRecordShiftAnalysisAmountAsync(BalanceRecordAnalysisByShiftRequest request); + + Task BalanceRecordShiftAnalysisAmountAndCountAsync(BalanceRecordAnalysisByShiftRequest request); } \ No newline at end of file diff --git a/Src/Dlhis.Canteen/Order/Services/Implements/BalanceService.cs b/Src/Dlhis.Canteen/Order/Services/Implements/BalanceService.cs index bb3483a3..cd1cc6a6 100644 --- a/Src/Dlhis.Canteen/Order/Services/Implements/BalanceService.cs +++ b/Src/Dlhis.Canteen/Order/Services/Implements/BalanceService.cs @@ -109,6 +109,10 @@ public class BalanceService : IBalanceService { var cache = App.GetServiceProvider().GetService(); var balanceRecord = await _dbContext.Queryable().Where(x => x.No == no).SingleAsync(); + balanceRecord.ThrowIfNull("数据不存在"); + + (balanceRecord.Status != BalanceRecordStatusEnumType.Valid).ThrowIfTrue("无法退款"); + await using var handler = await cache.LockAsync($"balance:refund:{no}", TimeSpan.FromSeconds(9)); if (handler.Acquired) { @@ -125,7 +129,7 @@ public class BalanceService : IBalanceService } } - var userNo = balanceRecord?.UserNo; + var userNo = balanceRecord.UserNo; //获取人员余额 return await _dbContext.Queryable() .LeftJoin((x, ga) => x.UserNo == ga.No) @@ -146,8 +150,8 @@ public class BalanceService : IBalanceService public async Task> GetPageByDeviceUniqueNoAsync(BalanceRecordPageByDeviceUniqueNoRequest request) { var device = await _dbContext.Queryable() - .Where(x => x.UniqueNo == request.DeviceUniqueNo || x.Code == Guid.Parse(request.DeviceUniqueNo)) - .FirstAsync(); + .Where(x => x.UniqueNo == request.DeviceUniqueNo) + .SingleAsync(); if (device == null) { @@ -182,7 +186,8 @@ public class BalanceService : IBalanceService .LeftJoin((record, ga, department, bPlace, imageRecord) => imageRecord.No == record.No) .Where(record => record.DeviceUniqueNo == device.UniqueNo) .Where(record => record.CostDate >= request.Start && record.CostDate <= request.End) - .Where(record => record.Type == BalanceRecordTypeEnumType.Out && record.Status == BalanceRecordStatusEnumType.Valid) + .Where(record => record.Type == BalanceRecordTypeEnumType.Out + && (record.Status == BalanceRecordStatusEnumType.Valid || (record.Status == BalanceRecordStatusEnumType.Obsolute && record.Remark == "退款"))) .WhereIF(request.UserCode.IsPresent(), record => record.UserCode == request.UserCode) .OrderBy(record => record.CostDateTime, OrderByType.Desc) .Select((record, ga, department, bPlace, imageRecord) => new BalanceRecordDeviceResponse diff --git a/Src/Dlhis.Canteen/Order/Services/Implements/BalanceSummaryService.cs b/Src/Dlhis.Canteen/Order/Services/Implements/BalanceSummaryService.cs index cb79225a..5a76b686 100644 --- a/Src/Dlhis.Canteen/Order/Services/Implements/BalanceSummaryService.cs +++ b/Src/Dlhis.Canteen/Order/Services/Implements/BalanceSummaryService.cs @@ -90,14 +90,14 @@ public class BalanceSummaryService : IBalanceSummaryService } - public async Task BalanceRecordAnalysisByShiftAsync(BalanceRecordAnalysisByShiftRequest request) + public async Task BalanceRecordShiftAnalysisAmountAsync(BalanceRecordAnalysisByShiftRequest request) { var queryable = _dbContext.Queryable() .Where(x => x.Status == BalanceRecordStatusEnumType.Valid && x.Type == BalanceRecordTypeEnumType.Out) .WhereIF(request.SearchDateTimePeriod.HasValue(), x => x.CostDate >= request.SearchDateTimePeriod.Start && x.CostDate <= request.SearchDateTimePeriod.End) .WhereIF(request.BusinessPlaceCodes?.Any() == true, x => request.BusinessPlaceCodes.Contains(x.BusinessPlaceCode.Value)); - var amount = await queryable.SumAsync(x => x.Amount); + var amount = await queryable.SumAsync(x => SqlFunc.Abs(x.Amount)); var count = typeof(ShiftEnumType).GetFields(BindingFlags.Public | BindingFlags.Static).Length; @@ -105,7 +105,7 @@ public class BalanceSummaryService : IBalanceSummaryService .Select(x => new { x.CostDate, x.ShiftType, Amount = SqlFunc.AggregateSum(SqlFunc.Abs(x.Amount)) }) .ToPageListAsync(request.PageIndex, count * request.PageSize); - return new BalanceRecordAnalysisShiftResponse + return new BalanceRecordAnalysisShiftAmountResponse { Amount = amount, Pagination = new Pagination @@ -125,4 +125,29 @@ public class BalanceSummaryService : IBalanceSummaryService } }; } + + public async Task BalanceRecordShiftAnalysisAmountAndCountAsync(BalanceRecordAnalysisByShiftRequest request) + { + var queryable = _dbContext.Queryable() + .Where(x => x.Status == BalanceRecordStatusEnumType.Valid && x.Type == BalanceRecordTypeEnumType.Out) + .WhereIF(request.SearchDateTimePeriod.HasValue(), x => x.CostDate >= request.SearchDateTimePeriod.Start && x.CostDate <= request.SearchDateTimePeriod.End) + .WhereIF(request.BusinessPlaceCodes?.Any() == true, x => request.BusinessPlaceCodes.Contains(x.BusinessPlaceCode.Value)); + + var amount = await queryable.SumAsync(x => SqlFunc.Abs(x.Amount)); + + var result = await queryable.GroupBy(x => new { x.ShiftType }) + .Select(x => new { x.ShiftType, Amount = SqlFunc.AggregateSum(SqlFunc.Abs(x.Amount)), Count = SqlFunc.AggregateDistinctCount(x.UserCode) }) + .ToListAsync(); + + return new BalanceRecordAnalysisShiftAmountAndCountResponse + { + Amount = amount, + Items = result.Select(x => new BalanceRecordAnalysisShiftAmountAndCountItemResponse + { + ShiftType = x.ShiftType, + Amount = x.Amount, + Count = x.Count + }).ToList() + }; + } } \ No newline at end of file From c83ad8bca4f75f3088d7a3b2876960bf89a09537 Mon Sep 17 00:00:00 2001 From: liguoyang Date: Wed, 14 Aug 2024 15:07:08 +0800 Subject: [PATCH 12/25] =?UTF-8?q?feat=20=E7=94=B5=E5=AD=90=E9=A4=90?= =?UTF-8?q?=E5=88=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Implements/DeviceConnectService.cs | 4 +- .../Services/Implements/GainfoMealService.cs | 2 - Src/Dlhis.Basic/Program.cs | 1 + Src/Dlhis.Canteen/Dlhis.Canteen.csproj | 6 - .../Controllers/EMealVoucherController.cs | 65 ++++ .../Request/EMealVoucherPageRequest.cs | 7 + .../Response/EMealVoucherDetailResponse.cs | 31 ++ .../Response/EMealVoucherPageResponse.cs | 12 + .../Services/IEMealVoucherService.cs | 18 ++ .../Implements/EMealVoucherService.cs | 106 +++++++ .../Implements/MealSupplementRecordService.cs | 1 - .../Order/Dto/OrderPreCheckDto.cs | 16 + .../Services/Implements/BalanceService.cs | 1 - .../Implements/BookingOrderService.cs | 1 - .../Implements/HainingBalanceService.cs | 1 - .../Order/Services/Implements/OrderService.cs | 300 ++++++++++++++---- .../Canteen/Entities/BalanceRecordEntity.cs | 6 - .../Entities/EMealVoucherDetailEntity.cs | 23 +- .../EMealVoucherDetailQrCodeEntity.cs | 29 ++ .../Enums/BalanceRecordSourceEnumType.cs | 2 +- .../Request/EMealVoucherReceiveRequest.cs | 5 + .../Implements/EMealVoucherService.cs | 2 +- .../Services/Implements/OrderService.cs | 1 - .../Jobs/MealSupplementHandlerJob.cs | 1 - Src/Gateway/Program.cs | 14 +- Src/Gateway/appsettings.json | 1 - Src/Gateway/ocelot.Development.json | 2 +- 27 files changed, 552 insertions(+), 106 deletions(-) create mode 100644 Src/Dlhis.Canteen/EMealVoucher/Request/EMealVoucherPageRequest.cs create mode 100644 Src/Dlhis.Canteen/EMealVoucher/Response/EMealVoucherDetailResponse.cs create mode 100644 Src/Dlhis.Canteen/EMealVoucher/Response/EMealVoucherPageResponse.cs create mode 100644 Src/Dlhis.Canteen/EMealVoucher/Services/IEMealVoucherService.cs create mode 100644 Src/Dlhis.Canteen/EMealVoucher/Services/Implements/EMealVoucherService.cs create mode 100644 Src/Dlhis.Canteen/Order/Dto/OrderPreCheckDto.cs create mode 100644 Src/Dlhis.Entity/Canteen/Entities/EMealVoucherDetailQrCodeEntity.cs diff --git a/Src/Dlhis.Basic/Device/Services/Implements/DeviceConnectService.cs b/Src/Dlhis.Basic/Device/Services/Implements/DeviceConnectService.cs index 4b767cc6..30671f82 100644 --- a/Src/Dlhis.Basic/Device/Services/Implements/DeviceConnectService.cs +++ b/Src/Dlhis.Basic/Device/Services/Implements/DeviceConnectService.cs @@ -17,10 +17,12 @@ namespace Dlhis.Basic.Device.Services.Implements; public class DeviceConnectService : IDeviceConnectService { private readonly IDbContext _dbContext; + private readonly IHttpContextAccessor _httpContextAccessor; - public DeviceConnectService(IDbContext dbContext) + public DeviceConnectService(IDbContext dbContext, IHttpContextAccessor httpContextAccessor) { _dbContext = dbContext; + _httpContextAccessor = httpContextAccessor; } diff --git a/Src/Dlhis.Basic/Organization/Services/Implements/GainfoMealService.cs b/Src/Dlhis.Basic/Organization/Services/Implements/GainfoMealService.cs index 93249cff..587c3fb2 100644 --- a/Src/Dlhis.Basic/Organization/Services/Implements/GainfoMealService.cs +++ b/Src/Dlhis.Basic/Organization/Services/Implements/GainfoMealService.cs @@ -96,7 +96,6 @@ public class GainfoMealService : IGainfoMealService ShiftType = null, CostDate = now.Date, DeviceUniqueNo = null, - SubsidiesFromMonth = now.ToString("yyyyMM"), IP = null, CostId = gainfoLeave.CostId, OriginTenantId = gainfoLeave.Factory, @@ -141,7 +140,6 @@ public class GainfoMealService : IGainfoMealService ShiftType = null, CostDate = now.Date, DeviceUniqueNo = null, - SubsidiesFromMonth = now.ToString("yyyyMM"), IP = null, CostId = gainfo.CostId, OriginTenantId = gainfo.Factory, diff --git a/Src/Dlhis.Basic/Program.cs b/Src/Dlhis.Basic/Program.cs index 882db25c..6bd00925 100644 --- a/Src/Dlhis.Basic/Program.cs +++ b/Src/Dlhis.Basic/Program.cs @@ -22,6 +22,7 @@ public class Startup : DefaultStartup public override void ConfigureServices(IServiceCollection services) { base.ConfigureServices(services); + services.AddHttpContextAccessor(); services.AddRedis(); } } \ No newline at end of file diff --git a/Src/Dlhis.Canteen/Dlhis.Canteen.csproj b/Src/Dlhis.Canteen/Dlhis.Canteen.csproj index fc8473bf..0c6bb0f3 100644 --- a/Src/Dlhis.Canteen/Dlhis.Canteen.csproj +++ b/Src/Dlhis.Canteen/Dlhis.Canteen.csproj @@ -28,10 +28,4 @@ - - - - - - diff --git a/Src/Dlhis.Canteen/EMealVoucher/Controllers/EMealVoucherController.cs b/Src/Dlhis.Canteen/EMealVoucher/Controllers/EMealVoucherController.cs index 98e2f3ed..40b9483d 100644 --- a/Src/Dlhis.Canteen/EMealVoucher/Controllers/EMealVoucherController.cs +++ b/Src/Dlhis.Canteen/EMealVoucher/Controllers/EMealVoucherController.cs @@ -1,3 +1,7 @@ +using Dlhis.Canteen.EMealVoucher.Request; +using Dlhis.Canteen.EMealVoucher.Response; +using Dlhis.Canteen.EMealVoucher.Services; +using Kurisu.AspNetCore.DataAccess.Dto; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; @@ -8,4 +12,65 @@ namespace Dlhis.Canteen.EMealVoucher.Controllers; [ApiController] public class EMealVoucherController : ControllerBase { + private readonly IEMealVoucherService _eMealVoucherService; + + public EMealVoucherController(IEMealVoucherService eMealVoucherService) + { + _eMealVoucherService = eMealVoucherService; + } + + /// + /// 获取我的电子餐券申请 + /// + /// + /// + [HttpGet("my")] + public async Task> GetMyEMealVoucherPageAsync([FromQuery] EMealVoucherPageRequest request) + { + return await _eMealVoucherService.GetMyEMealVoucherPageAsync(request); + } + + /// + /// 查看电子餐券 + /// + /// + /// + [HttpGet("no")] + public async Task> GetDetailsByNoAsync(string no) + { + return await _eMealVoucherService.GetDetailsByNoAsync(no); + } + + /// + /// 获取url签名 + /// + /// + /// + [HttpGet("signature")] + public async Task GetQrCodeSignatureAsync(long detailId) + { + return await _eMealVoucherService.GetQrCodeSignatureAsync(detailId); + } + + /// + /// 刷新url签名 + /// + /// + [HttpPost("signature/refresh")] + public async Task RefreshSignatureAsync(long detailId) + { + await _eMealVoucherService.RefreshSignatureAsync(detailId); + } + + /// + /// 获取二维码 + /// + /// + /// + [AllowAnonymous] + [HttpGet("qrcode")] + public async Task GetQrCodeAsync(string signature) + { + return await _eMealVoucherService.GetQrCodeAsync(signature); + } } \ No newline at end of file diff --git a/Src/Dlhis.Canteen/EMealVoucher/Request/EMealVoucherPageRequest.cs b/Src/Dlhis.Canteen/EMealVoucher/Request/EMealVoucherPageRequest.cs new file mode 100644 index 00000000..d23ddad0 --- /dev/null +++ b/Src/Dlhis.Canteen/EMealVoucher/Request/EMealVoucherPageRequest.cs @@ -0,0 +1,7 @@ +using Kurisu.AspNetCore.DataAccess.Dto; + +namespace Dlhis.Canteen.EMealVoucher.Request; + +public class EMealVoucherPageRequest : PageDto +{ +} \ No newline at end of file diff --git a/Src/Dlhis.Canteen/EMealVoucher/Response/EMealVoucherDetailResponse.cs b/Src/Dlhis.Canteen/EMealVoucher/Response/EMealVoucherDetailResponse.cs new file mode 100644 index 00000000..03656071 --- /dev/null +++ b/Src/Dlhis.Canteen/EMealVoucher/Response/EMealVoucherDetailResponse.cs @@ -0,0 +1,31 @@ +namespace Dlhis.Canteen.EMealVoucher.Response; + +public class EMealVoucherDetailResponse +{ + public long Id { get; set; } + + /// + /// 用餐人 + /// + public string Name { get; set; } + + /// + /// 手机号 + /// + public string Phone { get; set; } + + /// + /// 就餐开始 + /// + public DateTime Start { get; set; } + + /// + /// 就餐结束 + /// + public DateTime End { get; set; } + + /// + /// 金额 + /// + public decimal Balance { get; set; } +} \ No newline at end of file diff --git a/Src/Dlhis.Canteen/EMealVoucher/Response/EMealVoucherPageResponse.cs b/Src/Dlhis.Canteen/EMealVoucher/Response/EMealVoucherPageResponse.cs new file mode 100644 index 00000000..c35caac3 --- /dev/null +++ b/Src/Dlhis.Canteen/EMealVoucher/Response/EMealVoucherPageResponse.cs @@ -0,0 +1,12 @@ +namespace Dlhis.Canteen.EMealVoucher.Response; + +public class EMealVoucherPageResponse +{ + public long Id { get; set; } + + public string No { get; set; } + + public string Title { get; set; } + + public DateTime Date { get; set; } +} \ No newline at end of file diff --git a/Src/Dlhis.Canteen/EMealVoucher/Services/IEMealVoucherService.cs b/Src/Dlhis.Canteen/EMealVoucher/Services/IEMealVoucherService.cs new file mode 100644 index 00000000..ef41f70a --- /dev/null +++ b/Src/Dlhis.Canteen/EMealVoucher/Services/IEMealVoucherService.cs @@ -0,0 +1,18 @@ +using Dlhis.Canteen.EMealVoucher.Request; +using Dlhis.Canteen.EMealVoucher.Response; +using Kurisu.AspNetCore.DataAccess.Dto; + +namespace Dlhis.Canteen.EMealVoucher.Services; + +public interface IEMealVoucherService : IScopeDependency +{ + Task> GetMyEMealVoucherPageAsync(EMealVoucherPageRequest request); + + Task> GetDetailsByNoAsync(string no); + + Task GetQrCodeSignatureAsync(long detailId); + + Task RefreshSignatureAsync(long detailId); + + Task GetQrCodeAsync(string signature); +} \ No newline at end of file diff --git a/Src/Dlhis.Canteen/EMealVoucher/Services/Implements/EMealVoucherService.cs b/Src/Dlhis.Canteen/EMealVoucher/Services/Implements/EMealVoucherService.cs new file mode 100644 index 00000000..c00c2fa1 --- /dev/null +++ b/Src/Dlhis.Canteen/EMealVoucher/Services/Implements/EMealVoucherService.cs @@ -0,0 +1,106 @@ +using System.Text; +using Dlhis.Canteen.EMealVoucher.Request; +using Dlhis.Canteen.EMealVoucher.Response; +using Dlhis.Entity.Canteen.Entities; +using Kurisu.AspNetCore.Authentication.Abstractions; +using Kurisu.AspNetCore.DataAccess.Dto; +using Kurisu.AspNetCore.DataAccess.SqlSugar.Extensions; +using Kurisu.AspNetCore.DataAccess.SqlSugar.Services; +using Kurisu.AspNetCore.Utils.Extensions; +using SqlSugar; + +namespace Dlhis.Canteen.EMealVoucher.Services.Implements; + +public class EMealVoucherService : IEMealVoucherService +{ + private readonly IDbContext _dbContext; + private readonly ICurrentUser _currentUser; + + public EMealVoucherService(IDbContext dbContext, ICurrentUser currentUser) + { + _dbContext = dbContext; + _currentUser = currentUser; + } + + + public async Task> GetMyEMealVoucherPageAsync(EMealVoucherPageRequest request) + { + var code = _currentUser.GetUserClaim("jinko-code"); + code = "0123456"; + return await _dbContext.Queryable() + .Where(x => x.Code == code) + .OrderBy(x => x.Id, OrderByType.Desc) + .Select() + .ToPageListAsync(request); + } + + + public async Task> GetDetailsByNoAsync(string no) + { + return await _dbContext.Queryable() + .Where(x => x.No == no) + .Select() + .ToListAsync(); + } + + + public async Task GetQrCodeSignatureAsync(long detailId) + { + return await GenerateSignatureAsync(detailId, false); + } + + public async Task RefreshSignatureAsync(long detailId) + { + await GenerateSignatureAsync(detailId, true); + } + + private async Task GenerateSignatureAsync(long detailId, bool isRefresh) + { + var eMealVoucherDetail = await _dbContext.Queryable().Where(x => x.Id == detailId).SingleAsync(); + eMealVoucherDetail.ThrowIfNull("数据不存在"); + if (eMealVoucherDetail.Signature.IsPresent()) + { + if (isRefresh) + { + await _dbContext.Deleteable().Where(x => x.Signature == eMealVoucherDetail.Signature).ExecuteCommandAsync(); + } + else + { + return eMealVoucherDetail.Signature; + } + } + + eMealVoucherDetail.Signature = Guid.NewGuid().ToString().Replace("-", "") + DateTimeOffset.Now.ToUnixTimeMilliseconds(); + await _dbContext.UpdateAsync(eMealVoucherDetail); + + return eMealVoucherDetail.Signature; + } + + /// + public async Task GetQrCodeAsync(string signature) + { + var eMealVoucherDetail = await _dbContext.Queryable().Where(x => x.Signature == signature).SingleAsync(); + eMealVoucherDetail.ThrowIfNull("无效地址"); + var eMealVoucher = await _dbContext.Queryable().Where(x => x.No == eMealVoucherDetail.No).SingleAsync(); + + var ts = DateTimeOffset.Now.ToUnixTimeMilliseconds().ToString().Reverse().Join(string.Empty); + var originData = string.Concat(eMealVoucher.No, ":", ts, ":", eMealVoucher.Code, ":", eMealVoucherDetail.IdNo); + + var qrCode = "02" + originData.ToArray().Select(x => + { + var b = Encoding.ASCII.GetBytes(x.ToString()); + int i = b[0]; + return Convert.ToString(i); + }).Join(string.Empty); + + + await _dbContext.InsertAsync(new EMealVoucherDetailQrCodeEntity + { + Signature = signature, + OriginData = originData, + QrCode = qrCode + }); + + return qrCode; + } +} \ No newline at end of file diff --git a/Src/Dlhis.Canteen/MealSupplementRecord/Services/Implements/MealSupplementRecordService.cs b/Src/Dlhis.Canteen/MealSupplementRecord/Services/Implements/MealSupplementRecordService.cs index 70e94176..6bb57af2 100644 --- a/Src/Dlhis.Canteen/MealSupplementRecord/Services/Implements/MealSupplementRecordService.cs +++ b/Src/Dlhis.Canteen/MealSupplementRecord/Services/Implements/MealSupplementRecordService.cs @@ -174,7 +174,6 @@ public class MealSupplementRecordService : IMealSupplementRecordService Source = BalanceRecordSourceEnumType.LocalTenantSubsidies, Remark = "期初导入", CostId = gainfo.CostId, - SubsidiesFromMonth = today.ToString("yyyyMM"), OriginTenantId = gainfo.Factory, Werks = gainfo.Werks, Name = gainfo.Name, diff --git a/Src/Dlhis.Canteen/Order/Dto/OrderPreCheckDto.cs b/Src/Dlhis.Canteen/Order/Dto/OrderPreCheckDto.cs new file mode 100644 index 00000000..6667755e --- /dev/null +++ b/Src/Dlhis.Canteen/Order/Dto/OrderPreCheckDto.cs @@ -0,0 +1,16 @@ +using Dlhis.Entity.Basic.Entity; + +namespace Dlhis.Canteen.Order.Dto +{ + public class OrderPreCheckDto + { + public DateTime CostDate { get; set; } + public BusinessShiftMealRelationshipEntity Shift { get; set; } + + public string BusinessPlaceTenantId { get; set; } + + public Guid BusinessPlaceCode { get; set; } + + public Guid BusinessShiftCode { get; set; } + } +} \ No newline at end of file diff --git a/Src/Dlhis.Canteen/Order/Services/Implements/BalanceService.cs b/Src/Dlhis.Canteen/Order/Services/Implements/BalanceService.cs index cd1cc6a6..a83c3107 100644 --- a/Src/Dlhis.Canteen/Order/Services/Implements/BalanceService.cs +++ b/Src/Dlhis.Canteen/Order/Services/Implements/BalanceService.cs @@ -482,7 +482,6 @@ public class BalanceService : IBalanceService ShiftType = null, CostDate = DateTime.Now.Date, DeviceUniqueNo = null, - SubsidiesFromMonth = DateTime.Now.ToString("yyyyMM"), IP = null, CostId = gainfo.CostId, OriginTenantId = gainfo.Factory, diff --git a/Src/Dlhis.Canteen/Order/Services/Implements/BookingOrderService.cs b/Src/Dlhis.Canteen/Order/Services/Implements/BookingOrderService.cs index 17054b7b..afff04cd 100644 --- a/Src/Dlhis.Canteen/Order/Services/Implements/BookingOrderService.cs +++ b/Src/Dlhis.Canteen/Order/Services/Implements/BookingOrderService.cs @@ -71,7 +71,6 @@ public class BookingOrderService : BaseOrderService, IBookingOrderService DeliveryAddress = request.DeliveryAddress, No = SnowFlakeHelper.Instance.NextId().ToString(), - SubsidiesFromMonth = now.ToString("yyyyMM"), IsOffline = false, IsCostCrossTenant = await GetSettingAsync(gainfo.No, businessPlace.TenantId, CanteenSettingItemEnumType.AllowCrossTenant), diff --git a/Src/Dlhis.Canteen/Order/Services/Implements/HainingBalanceService.cs b/Src/Dlhis.Canteen/Order/Services/Implements/HainingBalanceService.cs index fd0e9fea..46ac4779 100644 --- a/Src/Dlhis.Canteen/Order/Services/Implements/HainingBalanceService.cs +++ b/Src/Dlhis.Canteen/Order/Services/Implements/HainingBalanceService.cs @@ -75,7 +75,6 @@ public class HainingBalanceService : IHainingBalanceService Source = request.Source, Remark = request.Remark, CostId = gainfo.CostId, - SubsidiesFromMonth = request.CostDate.ToString("yyyyMM"), TenantId = businessPlaceInfo?.TenantId ?? request.Factory, OriginTenantId = gainfo.Factory, Werks = gainfo.Werks, diff --git a/Src/Dlhis.Canteen/Order/Services/Implements/OrderService.cs b/Src/Dlhis.Canteen/Order/Services/Implements/OrderService.cs index 8edc15fa..e94823f6 100644 --- a/Src/Dlhis.Canteen/Order/Services/Implements/OrderService.cs +++ b/Src/Dlhis.Canteen/Order/Services/Implements/OrderService.cs @@ -1,4 +1,5 @@ using System.Diagnostics; +using Dlhis.Canteen.Order.Dto; using Dlhis.Canteen.Setting.Services; using Dlhis.Entity.Basic.Entity; using Dlhis.Entity.Canteen.Entities; @@ -161,7 +162,11 @@ public class OrderService : BaseOrderService, IOrderService } else if (request.UserUniqueNo.StartsWith("02")) { - request.Source = BalanceRecordSourceEnumType.EVoucher; + 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(); } } else @@ -180,8 +185,7 @@ public class OrderService : BaseOrderService, IOrderService { gainfo.ThrowIfNull("无法识别,无权消费"); } - - if (request.IsOffline) + else { //兼容hpt尚未删除人员后产生的消费数据 gainfo ??= await DbContext.Queryable().AS("GainfoLeave") @@ -305,7 +309,6 @@ public class OrderService : BaseOrderService, IOrderService _logs.Add("消费请求校验:" + _sw.ElapsedMilliseconds); _sw.Restart(); - await CommonHelper.RetryAsync(async () => { var gainfoMeal = await DbContext.Queryable().Where(x => x.UserNo == order.UserNo).SingleAsync(); @@ -329,42 +332,6 @@ public class OrderService : BaseOrderService, IOrderService _sw.Restart(); } - /// - /// 根据二维码获取消费用户 - /// - /// - /// - private async Task GetUserByQrCodeAsync(string qrCode) - { - var gainfoQrCode = await DbContext.Queryable().Where(x => x.QrCode == qrCode).SingleAsync(); - gainfoQrCode.ThrowIfNull("消费码已过期"); - (gainfoQrCode.ModifiedTime.AddMinutes(60) < DateTime.Now).ThrowIfTrue("消费码已过期"); - - return await DbContext.Queryable().Where(x => x.Code == gainfoQrCode.UserCode).SingleAsync(); - } - - - /// - /// 检查是否可以离线消费 - /// - /// - /// - private async Task ToCheckAbleOfflineConsumeAsync(string thirdNo) - { - var order = await DbContext.Queryable() - .Where(x => x.ThirdNo == thirdNo) - .OrderBy(x => x.CreateTime, OrderByType.Desc) - .FirstAsync(); - - if (order == null) - { - return true; - } - - //存在在线order数据,但是状态未成功 - return !order.IsOffline && order.OrderStatus != CanteenOrderStatusEnumType.Success; - } - /// /// 离线消费处理 /// @@ -418,7 +385,6 @@ public class OrderService : BaseOrderService, IOrderService DeviceUniqueNo = request.DeviceUniqueNo, No = SnowFlakeHelper.Instance.NextId().ToString(), - SubsidiesFromMonth = request.CostDateTime.ToString("yyyyMM"), IsOffline = request.IsOffline, IsCostCrossTenant = businessPlaceInfo!.TenantId != gainfo.Factory, @@ -492,8 +458,6 @@ public class OrderService : BaseOrderService, IOrderService device.ThrowIfNull("设备尚未登记"); device.Enable.ThrowIfFalse("设备已被停用"); - (request.Source == BalanceRecordSourceEnumType.QrCode && device.TenantId != gainfo.Factory).ThrowIfTrue("二维码在此设备禁止消费"); - var businessPlaceInfo = await DbContext.Queryable() .LeftJoin((x, sr) => x.Code == sr.PlaceCode) .Where(x => x.Code == registry.BusinessPlaceCode) @@ -523,6 +487,8 @@ public class OrderService : BaseOrderService, IOrderService var costDate = await GetCostDateAsync(shift, request.CostDateTime); + (request.Source == BalanceRecordSourceEnumType.QrCode && businessPlaceInfo.TenantId != gainfo.Factory).ThrowIfTrue("禁止跨厂区消费"); + var order = new CanteenOrderEntity { RequestJson = request.ToJson(), @@ -543,9 +509,8 @@ public class OrderService : BaseOrderService, IOrderService DeviceUniqueNo = request.DeviceUniqueNo, No = SnowFlakeHelper.Instance.NextId().ToString(), - SubsidiesFromMonth = request.CostDateTime.ToString("yyyyMM"), IsOffline = request.IsOffline, - IsCostCrossTenant = await GetSettingAsync(gainfo.No, businessPlaceInfo!.TenantId, CanteenSettingItemEnumType.AllowCrossTenant), + IsCostCrossTenant = gainfo.Factory != businessPlaceInfo!.TenantId, OriginTenantId = gainfo.Factory, Werks = gainfo.Werks, @@ -610,17 +575,29 @@ public class OrderService : BaseOrderService, IOrderService /// private async Task ToDoAsync(OrderAddRequest request, GainfoEntity gainfo) { - var message = ""; - if (request.IsOffline) - { - if (request.ThirdNo.IsPresent()) - { - var redisCache = _serviceProvider.GetService(); + var message = string.Empty; - await using var handler = await redisCache.LockAsync($"consume:device:{request.ThirdNo}"); - if (handler.Acquired) + if (request.Source == BalanceRecordSourceEnumType.EMealVoucher) + { + try + { + await EMealVoucherConsumeAsync(request.Adapt(), gainfo); + } + catch (Exception ex) + { + message = ex.Message; + } + } + else + { + if (request.IsOffline) + { + if (request.ThirdNo.IsPresent()) { - if (await ToCheckAbleOfflineConsumeAsync(request.ThirdNo)) + var redisCache = _serviceProvider.GetService(); + + await using var handler = await redisCache.LockAsync($"consume:device:{request.ThirdNo}"); + if (handler.Acquired && await ToCheckAbleOfflineConsumeAsync(request.ThirdNo)) { try { @@ -632,32 +609,219 @@ public class OrderService : BaseOrderService, IOrderService } } } + else + { + try + { + await HandleOfflineAsync(request.Adapt(), gainfo); + } + catch (Exception ex) + { + Logger.LogError(ex, "离线入库错误: 订单号:{no} .{message}", request.ThirdNo, ex.Message); + } + } } else { try { - await HandleOfflineAsync(request.Adapt(), gainfo); + (await DbContext.Queryable().Where(x => x.UserCode == gainfo.Code).AnyAsync()).ThrowIfFalse("就餐余额不足"); + await ConsumeAsync(request.Adapt(), gainfo); } catch (Exception ex) { - Logger.LogError(ex, "离线入库错误: 订单号:{no} .{message}", request.ThirdNo, ex.Message); + message = ex.Message; } } } - else - { - try - { - (await DbContext.Queryable().Where(x => x.UserCode == gainfo.Code).AnyAsync()).ThrowIfFalse("就餐余额不足"); - await ConsumeAsync(request.Adapt(), gainfo); - } - catch (Exception ex) - { - message = ex.Message; - } - } return message; + + async Task ToCheckAbleOfflineConsumeAsync(string thirdNo) + { + var order = await DbContext.Queryable() + .Where(x => x.ThirdNo == thirdNo) + .OrderBy(x => x.CreateTime, OrderByType.Desc) + .FirstAsync(); + + if (order == null) + { + return true; + } + + //存在在线order数据,但是状态未成功 + return !order.IsOffline && order.OrderStatus != CanteenOrderStatusEnumType.Success; + } + } + + /// + /// 根据二维码获取消费用户 + /// + /// + /// + private async Task GetUserByQrCodeAsync(string qrCode) + { + var gainfoQrCode = await DbContext.Queryable().Where(x => x.QrCode == qrCode).SingleAsync(); + gainfoQrCode.ThrowIfNull("消费码已过期"); + (gainfoQrCode.ModifiedTime.AddMinutes(60) < DateTime.Now).ThrowIfTrue("消费码已过期"); + + return await DbContext.Queryable().Where(x => x.Code == gainfoQrCode.UserCode).SingleAsync(); + } + + + private async Task EMealVoucherConsumeAsync(ConsumeRequest request, GainfoEntity gainfo) + { + var eMealVoucherQrCode = await DbContext.Queryable().Where(x => x.QrCode == request.UserUniqueNo).SingleAsync(); + var originData = eMealVoucherQrCode.OriginData.Split(':'); + + var no = originData[0]; + var idNo = originData[3]; + var nowDate = DateTime.Now.Date; + var current = await DbContext.Queryable() + .Where(x => x.No == no && x.IdNo == idNo).SingleAsync(); + (nowDate >= current.Start && nowDate <= current.End).ThrowIfFalse("餐券已过期"); + + var time = DateTimeOffset.FromUnixTimeMilliseconds(Convert.ToInt64(originData[1].Reverse().Join(string.Empty))).ToLocalTime().DateTime; + (time.AddMinutes(60) >= DateTime.Now).ThrowIfFalse("二维码已过期"); + + var eMealVoucher = await DbContext.Queryable().Where(x => x.No == no).SingleAsync(); + + var checkData = await PreCheckAsync(request.DeviceUniqueNo, request.CostDateTime); + eMealVoucher.Factories.Contains(checkData.BusinessPlaceTenantId).ThrowIfFalse("禁止在当前厂区消费"); + + _logs.Add("检验设备和营业点参数:" + _sw.ElapsedMilliseconds); + _sw.Restart(); + + var order = new CanteenOrderEntity + { + RequestJson = request.ToJson(), + ThirdNo = request.ThirdNo, + Type = BalanceRecordTypeEnumType.Out, + ApplicationType = CanteenApplicationTypeEnumType.Device, + Name = gainfo.Name, + Source = request.Source, + UserNo = eMealVoucherQrCode.OriginData, //记录为当前消费券 + UserCode = gainfo.Code, + Amount = request.Amount, + BusinessPlaceCode = checkData.BusinessPlaceCode, + BusinessShiftCode = checkData.BusinessShiftCode, + ShiftType = checkData.Shift.ShiftType, + CostDate = checkData.CostDate, + CostId = gainfo.CostId, + DepartmentNo = gainfo.DepartmentNo, + DeviceUniqueNo = request.DeviceUniqueNo, + + No = SnowFlakeHelper.Instance.NextId().ToString(), + IsOffline = false, + IsCostCrossTenant = gainfo.Factory != checkData.BusinessPlaceTenantId, + + OriginTenantId = gainfo.Factory, + Werks = gainfo.Werks, + Status = BalanceRecordStatusEnumType.Valid, + OrderStatus = CanteenOrderStatusEnumType.Wait, + CostDateTime = request.CostDateTime, + //标识当前消费的基地 + TenantId = checkData.BusinessPlaceTenantId, + }; + + var orderId = await DbContext.InsertReturnIdentityAsync(order); + _logs.Add("临时order写入:" + _sw.ElapsedMilliseconds); + _sw.Restart(); + + try + { + await CommonHelper.RetryAsync(async () => + { + var detail = await DbContext.Queryable().Where(x => x.No == no && x.IdNo == idNo).SingleAsync(); + //金额+- + detail.Balance += order.Amount; + (detail.Balance < 0).ThrowIfTrue("余额不足,无法消费"); + + await DbContext.Updateable() + .SetColumns(x => x.Balance == detail.Balance) + .SetColumns(x => x.Version == x.Version + 1) + .SetColumns(x => x.ModifiedTime == DateTime.Now) + .Where(x => x.No == no && x.IdNo == idNo && x.Version == detail.Version) //必须与查询时的version一致 + .ExecuteCommandThrowVersionAsync(); + + //写入记录 + var balanceRecord = order.Adapt(); + await DbContext.InsertAsync(balanceRecord); + }, 5); + + _logs.Add("消费写入:" + _sw.ElapsedMilliseconds); + _sw.Restart(); + + await DbContext.Updateable() + .SetColumns(x => x.OrderStatus == CanteenOrderStatusEnumType.Success) + .SetColumns(x => x.ModifiedTime == DateTime.Now) + .Where(x => x.Id == orderId) + .ExecuteCommandAsync(); + + _logs.Add("更新image和订单信息:" + _sw.ElapsedMilliseconds); + _sw.Restart(); + } + catch (Exception ex) + { + await DbContext.Updateable() + .SetColumns(x => x.OrderStatus == CanteenOrderStatusEnumType.Failure) + .SetColumns(x => x.Result == ex.Message) + .SetColumns(x => x.ModifiedTime == DateTime.Now) + .Where(x => x.Id == orderId) + .ExecuteCommandAsync(); + + throw; + } + } + + /// + /// 消费前预检 + /// + /// + /// + /// + private async Task PreCheckAsync(string deviceUniqueNo, DateTime costDateTime) + { + var registry = await DbContext.Queryable().Where(x => x.DeviceUniqueNo == deviceUniqueNo).SingleAsync(); + registry.ThrowIfNull("设备尚未登记"); + + var device = await DbContext.Queryable().Where(x => x.UniqueNo == deviceUniqueNo).SingleAsync(); + device.ThrowIfNull("设备尚未登记"); + device.Enable.ThrowIfFalse("设备已被停用"); + + var businessPlaceInfo = await DbContext.Queryable() + .LeftJoin((x, sr) => x.Code == sr.PlaceCode) + .Where(x => x.Code == registry.BusinessPlaceCode) + .Select((x, sr) => new + { + x.Code, + sr.ShiftCode, + x.TenantId + }) + .SingleAsync(); + + businessPlaceInfo.ThrowIfNull("设备尚未登记营业点"); + + //获取当前消费餐次 + var shifts = await DbContext.Queryable().Where(x => x.ShiftCode == businessPlaceInfo.ShiftCode).ToListAsync(); + shifts.ThrowIfEmpty("营业点餐次尚未设置"); + + var shift = shifts.FirstOrDefault(x => new TimePeriod + { + Start = x.Start, + End = x.End + }.IsPresent(costDateTime)); + shift.ThrowIfNull("非就餐时间,无法消费"); + + var costDate = await GetCostDateAsync(shift, costDateTime); + + return new OrderPreCheckDto + { + CostDate = costDate, + Shift = shift, + BusinessPlaceTenantId = businessPlaceInfo.TenantId, + BusinessPlaceCode = businessPlaceInfo.Code, + BusinessShiftCode = businessPlaceInfo.ShiftCode + }; } } \ No newline at end of file diff --git a/Src/Dlhis.Entity/Canteen/Entities/BalanceRecordEntity.cs b/Src/Dlhis.Entity/Canteen/Entities/BalanceRecordEntity.cs index b5874947..a3fdedda 100644 --- a/Src/Dlhis.Entity/Canteen/Entities/BalanceRecordEntity.cs +++ b/Src/Dlhis.Entity/Canteen/Entities/BalanceRecordEntity.cs @@ -91,12 +91,6 @@ public class BalanceRecordEntity : SugarBaseEntity, ISoftDeleted, ITenantId [SugarColumn(ColumnDescription = "消费机器唯一信息", IsNullable = true)] public string DeviceUniqueNo { get; set; } - /// - /// 餐补月份 - /// - [SugarColumn(ColumnDescription = "餐补月份")] - public string SubsidiesFromMonth { get; set; } - /// /// Ip /// diff --git a/Src/Dlhis.Entity/Canteen/Entities/EMealVoucherDetailEntity.cs b/Src/Dlhis.Entity/Canteen/Entities/EMealVoucherDetailEntity.cs index b41f0533..35a963b2 100644 --- a/Src/Dlhis.Entity/Canteen/Entities/EMealVoucherDetailEntity.cs +++ b/Src/Dlhis.Entity/Canteen/Entities/EMealVoucherDetailEntity.cs @@ -1,4 +1,5 @@ -using Kurisu.AspNetCore.DataAccess.SqlSugar; +using Kurisu.AspNetCore.DataAccess.Entity; +using Kurisu.AspNetCore.DataAccess.SqlSugar; using SqlSugar; namespace Dlhis.Entity.Canteen.Entities; @@ -7,7 +8,7 @@ namespace Dlhis.Entity.Canteen.Entities; /// 电子餐券明细 /// [SugarTable(TableName = "EMealVoucherDetail", TableDescription = "电子餐券明细")] -public class EMealVoucherDetailEntity : SugarBaseEntity +public class EMealVoucherDetailEntity : SugarBaseEntity, IVersion { /// /// 主表id @@ -18,7 +19,7 @@ public class EMealVoucherDetailEntity : SugarBaseEntity /// /// 流水号 /// - [SugarColumn(ColumnDescription = "流水号")] + [SugarColumn(ColumnDescription = "流水号", UniqueGroupNameList = new[] { "idx_EMealVoucherDetail_no_idno" })] public string No { get; set; } /// @@ -30,7 +31,7 @@ public class EMealVoucherDetailEntity : SugarBaseEntity /// /// 身份证 /// - [SugarColumn(ColumnDescription = "序号")] + [SugarColumn(ColumnDescription = "证件号", UniqueGroupNameList = new[] { "idx_EMealVoucherDetail_no_idno" })] public string IdNo { get; set; } /// @@ -60,6 +61,16 @@ public class EMealVoucherDetailEntity : SugarBaseEntity /// /// 金额 /// - [SugarColumn(ColumnDescription = "金额", ColumnDataType = "decimal(16,2)")] - public decimal Amount { get; set; } + [SugarColumn(ColumnDescription = "余额", ColumnDataType = "decimal(16,2)")] + public decimal Balance { get; set; } + + /// + /// 版本 + /// + [SugarColumn(ColumnDescription = "版本")] + public int Version { get; set; } + + + [SugarColumn(ColumnDataType = "varchar(255)")] + public string Signature { get; set; } } \ No newline at end of file diff --git a/Src/Dlhis.Entity/Canteen/Entities/EMealVoucherDetailQrCodeEntity.cs b/Src/Dlhis.Entity/Canteen/Entities/EMealVoucherDetailQrCodeEntity.cs new file mode 100644 index 00000000..b1a6b505 --- /dev/null +++ b/Src/Dlhis.Entity/Canteen/Entities/EMealVoucherDetailQrCodeEntity.cs @@ -0,0 +1,29 @@ +using Kurisu.AspNetCore.DataAccess.SqlSugar; +using SqlSugar; + +namespace Dlhis.Entity.Canteen.Entities; + +/// +/// 电子餐券明细QrCode +/// +[SugarTable(TableName = "EMealVoucherDetailQrCode", TableDescription = "电子餐券明细QrCode")] +public class EMealVoucherDetailQrCodeEntity : SugarBaseEntity +{ + /// + /// url签名 + /// + [SugarColumn(ColumnDataType = "varchar(255)", IndexGroupNameList = new[] { "idx_EMealVoucherDetailQrCode_signature" })] + public string Signature { get; set; } + + /// + /// 原始数据 + /// + [SugarColumn(ColumnDescription = "原始数据")] + public string OriginData { get; set; } + + /// + /// 二维码 + /// + [SugarColumn(ColumnDescription = "二维码", UniqueGroupNameList = new[] { "idx_EMealVoucherDetailQrCode_qrcode" })] + public string QrCode { get; set; } +} \ No newline at end of file diff --git a/Src/Dlhis.Entity/Canteen/Enums/BalanceRecordSourceEnumType.cs b/Src/Dlhis.Entity/Canteen/Enums/BalanceRecordSourceEnumType.cs index 587169b8..79d86f43 100644 --- a/Src/Dlhis.Entity/Canteen/Enums/BalanceRecordSourceEnumType.cs +++ b/Src/Dlhis.Entity/Canteen/Enums/BalanceRecordSourceEnumType.cs @@ -36,7 +36,7 @@ public enum BalanceRecordSourceEnumType /// 电子餐券 /// [Description("电子餐券")] - EVoucher, + EMealVoucher, //********************************************************************************************************* /// diff --git a/Src/Dlhis.External/EMealVoucher/Request/EMealVoucherReceiveRequest.cs b/Src/Dlhis.External/EMealVoucher/Request/EMealVoucherReceiveRequest.cs index 86f3aa3f..76597552 100644 --- a/Src/Dlhis.External/EMealVoucher/Request/EMealVoucherReceiveRequest.cs +++ b/Src/Dlhis.External/EMealVoucher/Request/EMealVoucherReceiveRequest.cs @@ -82,6 +82,11 @@ public class EMealVoucherReceiveRequest : IValidatableObject { yield return new ValidationResult("来宾数量不匹配", new[] { nameof(Number) }); } + + if (Details.DistinctBy(x => x.IdNo).Count() != Details.Count) + { + yield return new ValidationResult("证件信息重复", new[] { "IdNo" }); + } } } diff --git a/Src/Dlhis.External/EMealVoucher/Services/Implements/EMealVoucherService.cs b/Src/Dlhis.External/EMealVoucher/Services/Implements/EMealVoucherService.cs index 9e12372a..a956a612 100644 --- a/Src/Dlhis.External/EMealVoucher/Services/Implements/EMealVoucherService.cs +++ b/Src/Dlhis.External/EMealVoucher/Services/Implements/EMealVoucherService.cs @@ -43,7 +43,7 @@ public class EMealVoucherService : IEMealVoucherService Phone = x.Phone, Start = x.Start, End = x.End, - Amount = x.Amount + Balance = x.Amount }).ToList(); var id = await _dbContext.InsertReturnIdentityAsync(voucher); diff --git a/Src/Dlhis.Middle/Services/Implements/OrderService.cs b/Src/Dlhis.Middle/Services/Implements/OrderService.cs index 98126066..a632b1c5 100644 --- a/Src/Dlhis.Middle/Services/Implements/OrderService.cs +++ b/Src/Dlhis.Middle/Services/Implements/OrderService.cs @@ -171,7 +171,6 @@ public class OrderService : IOrderService DeviceUniqueNo = request.DeviceUniqueNo, No = _factory + "-" + SnowFlakeHelper.Instance.NextId(), - SubsidiesFromMonth = request.CostDateTime.ToString("yyyyMM"), // IsOffline = request.IsOffline, IsCostCrossTenant = await GetSettingAsync(businessPlaceInfo!.TenantId, CanteenSettingItemEnumType.AllowCrossTenant), diff --git a/Src/Dlhis.ScheduledTask/Jobs/MealSupplementHandlerJob.cs b/Src/Dlhis.ScheduledTask/Jobs/MealSupplementHandlerJob.cs index 0f288bd5..1a3698ca 100644 --- a/Src/Dlhis.ScheduledTask/Jobs/MealSupplementHandlerJob.cs +++ b/Src/Dlhis.ScheduledTask/Jobs/MealSupplementHandlerJob.cs @@ -156,7 +156,6 @@ public class MealSupplementHandlerJob : BaseJob Source = BalanceRecordSourceEnumType.LocalTenantSubsidies, Remark = mealSupplement.UniqueId + ":" + mealSupplement.Remark, CostId = gainfo.CostId, - SubsidiesFromMonth = mealSupplement.Date.ToString("yyyyMM"), OriginTenantId = gainfo.Factory, Werks = gainfo.Werks, Name = gainfo.Name, diff --git a/Src/Gateway/Program.cs b/Src/Gateway/Program.cs index e96a2582..c8fd2e8b 100644 --- a/Src/Gateway/Program.cs +++ b/Src/Gateway/Program.cs @@ -1,4 +1,3 @@ - using Gateway; public class Program @@ -8,13 +7,14 @@ public class Program Host.CreateDefaultBuilder(args) .ConfigureAppConfiguration((context, builder) => { - builder.AddJsonFile("ocelot.json", true, true); + if (context.HostingEnvironment.IsProduction()) + { + builder.AddJsonFile("ocelot.json", true, true); + } + builder.AddJsonFile($"ocelot.{context.HostingEnvironment.EnvironmentName}.json", true, true); }) - .ConfigureWebHostDefaults(webBuilder => - { - webBuilder.UseStartup(); - }) + .ConfigureWebHostDefaults(webBuilder => { webBuilder.UseStartup(); }) .Build().Run(); } -} +} \ No newline at end of file diff --git a/Src/Gateway/appsettings.json b/Src/Gateway/appsettings.json index 508d6f2a..d0e733e1 100644 --- a/Src/Gateway/appsettings.json +++ b/Src/Gateway/appsettings.json @@ -11,7 +11,6 @@ "Common", "Canteen", "Scheduled", - "User", "Sys", "Visitor", "Message" diff --git a/Src/Gateway/ocelot.Development.json b/Src/Gateway/ocelot.Development.json index e1aaacf0..45f461c0 100644 --- a/Src/Gateway/ocelot.Development.json +++ b/Src/Gateway/ocelot.Development.json @@ -72,7 +72,7 @@ "DownstreamScheme": "http", "DownstreamHostAndPorts": [ { - "Host": "localhost", + "Host": "192.168.199.115", "Port": 6000 } ] From 1c825491df0e57099d61502568374e742b6ba951 Mon Sep 17 00:00:00 2001 From: liguoyang Date: Wed, 14 Aug 2024 15:43:37 +0800 Subject: [PATCH 13/25] =?UTF-8?q?refactor=20=E4=BB=A3=E7=A0=81=E4=BC=98?= =?UTF-8?q?=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Order/Controllers/OrdersController.cs | 50 +------ .../Order/Services/Implements/OrderService.cs | 138 ++++++++---------- 2 files changed, 68 insertions(+), 120 deletions(-) diff --git a/Src/Dlhis.Canteen/Order/Controllers/OrdersController.cs b/Src/Dlhis.Canteen/Order/Controllers/OrdersController.cs index 51e0027c..59ab64b3 100644 --- a/Src/Dlhis.Canteen/Order/Controllers/OrdersController.cs +++ b/Src/Dlhis.Canteen/Order/Controllers/OrdersController.cs @@ -1,12 +1,10 @@ -using System.Diagnostics; -using Dlhis.Canteen.Dishes.Request; +using Dlhis.Canteen.Dishes.Request; using Dlhis.Canteen.Order.Request; using Dlhis.Canteen.Order.Response; using Dlhis.Canteen.Order.Services; using Kurisu.AspNetCore.DataAccess.Dto; using Kurisu.AspNetCore.DataAccess.SqlSugar.Aop; using Kurisu.AspNetCore.UnifyResultAndValidation; -using Kurisu.AspNetCore.Utils.Extensions; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; @@ -22,13 +20,11 @@ public class OrdersController : ControllerBase { private readonly IOrderService _orderService; private readonly IBookingOrderService _bookingOrderService; - private readonly ILogger _logger; - public OrdersController(IOrderService orderService, IBookingOrderService bookingOrderService, ILogger logger) + public OrdersController(IOrderService orderService, IBookingOrderService bookingOrderService) { _orderService = orderService; _bookingOrderService = bookingOrderService; - _logger = logger; } /// @@ -41,27 +37,8 @@ public class OrdersController : ControllerBase [IgnoreTenant] public async Task> AddAsync(OrderAddRequest request) { - var sw = Stopwatch.StartNew(); var result = await _orderService.AddAsync(request); - try - { - return result.Response; - } - finally - { - var ms = sw.ElapsedMilliseconds; - try - { - if (ms > 1000) - { - _logger.LogInformation("消费请求:{json}. 耗时记录:{log}", request.ToJson(), result.Logs.Join("\r\n")); - } - } - catch (Exception) - { - //ignore - } - } + return result.Response; } /// @@ -74,27 +51,8 @@ public class OrdersController : ControllerBase [IgnoreTenant] public async Task> DeviceConsume(OrderAddRequest request) { - var sw = Stopwatch.StartNew(); var result = await _orderService.AddAsync(request); - try - { - return result.Response; - } - finally - { - var ms = sw.ElapsedMilliseconds; - try - { - if (ms > 1000) - { - _logger.LogInformation("消费请求:{json}. 耗时记录:{log}", request.ToJson(), result.Logs.Join("\r\n")); - } - } - catch (Exception) - { - //ignore - } - } + return result.Response; } /// diff --git a/Src/Dlhis.Canteen/Order/Services/Implements/OrderService.cs b/Src/Dlhis.Canteen/Order/Services/Implements/OrderService.cs index e94823f6..d0c8b274 100644 --- a/Src/Dlhis.Canteen/Order/Services/Implements/OrderService.cs +++ b/Src/Dlhis.Canteen/Order/Services/Implements/OrderService.cs @@ -1,5 +1,4 @@ -using System.Diagnostics; -using Dlhis.Canteen.Order.Dto; +using Dlhis.Canteen.Order.Dto; using Dlhis.Canteen.Setting.Services; using Dlhis.Entity.Basic.Entity; using Dlhis.Entity.Canteen.Entities; @@ -24,8 +23,6 @@ namespace Dlhis.Canteen.Order.Services.Implements; public class OrderService : BaseOrderService, IOrderService { private readonly IServiceProvider _serviceProvider; - private Stopwatch _sw; - private readonly List _logs = new(); public OrderService(ICanteenSettingService canteenSettingService, IDbContext dbContext, @@ -54,44 +51,11 @@ public class OrderService : BaseOrderService, IOrderService /// public async Task AddAsync(OrderAddRequest request) { - _sw = new Stopwatch(); - var gainfo = await GetUserAsync(request); - _logs.Add("获取人员耗时:" + _sw.ElapsedMilliseconds); - _sw.Restart(); - - var message = await ToDoAsync(request, gainfo); - - //获取人员余额 - var data = await DbContext.Queryable() - .LeftJoin((x, ga) => x.UserNo == ga.No) - .LeftJoin((x, ga, department) => ga.DepartmentNo == department.No) - .Where(x => x.UserNo == gainfo.No) - .Select((x, ga, department) => new OrderResultResponse - { - UserCode = ga.Code, - UserName = ga.Name, - DepartmentNo = ga.DepartmentNo, - DepartmentName = department.Name, - CurrentBalance = x.Balance - }) - .SingleAsync(); - - var result = new DefaultApiResult - { - Code = message.IsPresent() ? ApiStateCode.Error : ApiStateCode.Success, - Data = data, - Msg = message - }; - - _logs.Add("获取余额:" + _sw.ElapsedMilliseconds); - _sw.Restart(); - return new OrderResultResponseWithLogs { - Response = result, - Logs = _logs + Response = await ToDoAsync(request, gainfo) }; } @@ -306,8 +270,6 @@ public class OrderService : BaseOrderService, IOrderService var order = await DbContext.Queryable().Where(x => x.Id == orderId).SingleAsync(); //校验 await Verify(order); - _logs.Add("消费请求校验:" + _sw.ElapsedMilliseconds); - _sw.Restart(); await CommonHelper.RetryAsync(async () => { @@ -327,9 +289,6 @@ public class OrderService : BaseOrderService, IOrderService var balanceRecord = order.Adapt(); await DbContext.InsertAsync(balanceRecord); }, 5); - - _logs.Add("消费写入:" + _sw.ElapsedMilliseconds); - _sw.Restart(); } /// @@ -482,9 +441,6 @@ public class OrderService : BaseOrderService, IOrderService }.IsPresent(request.CostDateTime)); shift.ThrowIfNull("非就餐时间,无法消费"); - _logs.Add("检验设备和营业点参数:" + _sw.ElapsedMilliseconds); - _sw.Restart(); - var costDate = await GetCostDateAsync(shift, request.CostDateTime); (request.Source == BalanceRecordSourceEnumType.QrCode && businessPlaceInfo.TenantId != gainfo.Factory).ThrowIfTrue("禁止跨厂区消费"); @@ -527,8 +483,6 @@ public class OrderService : BaseOrderService, IOrderService }; var orderId = await DbContext.InsertReturnIdentityAsync(order); - _logs.Add("临时order写入:" + _sw.ElapsedMilliseconds); - _sw.Restart(); try { @@ -549,9 +503,6 @@ public class OrderService : BaseOrderService, IOrderService .SetColumns(x => x.ModifiedTime == DateTime.Now) .Where(x => x.Id == orderId) .ExecuteCommandAsync(); - - _logs.Add("更新image和订单信息:" + _sw.ElapsedMilliseconds); - _sw.Restart(); } catch (Exception ex) { @@ -573,20 +524,55 @@ public class OrderService : BaseOrderService, IOrderService /// /// /// - private async Task ToDoAsync(OrderAddRequest request, GainfoEntity gainfo) + private async Task> ToDoAsync(OrderAddRequest request, GainfoEntity gainfo) { var message = string.Empty; if (request.Source == BalanceRecordSourceEnumType.EMealVoucher) { + var eMealVoucherQrCode = await DbContext.Queryable().Where(x => x.QrCode == request.UserUniqueNo).SingleAsync(); + if (eMealVoucherQrCode == null) + { + message = "无法识别"; + return new DefaultApiResult + { + Code = ApiStateCode.Error, + Data = null, + Msg = message + }; + } + + var originData = eMealVoucherQrCode.OriginData.Split(':'); + + var no = originData[0]; + var ts = originData[1]; + var idNo = originData[3]; + try { - await EMealVoucherConsumeAsync(request.Adapt(), gainfo); + await EMealVoucherConsumeAsync(request.Adapt(), gainfo, eMealVoucherQrCode.OriginData, no, ts, idNo); } catch (Exception ex) { message = ex.Message; } + + //获取餐券余额 + var data = await DbContext.Queryable() + .LeftJoin((x, d) => x.No == d.No) + .Where((x, d) => d.IdNo == idNo) + .Select((x, d) => new OrderResultResponse + { + CurrentBalance = d.Balance + }) + .SingleAsync(); + + return new DefaultApiResult + { + Code = message.IsPresent() ? ApiStateCode.Error : ApiStateCode.Success, + Data = data, + Msg = message + }; } else { @@ -633,9 +619,29 @@ public class OrderService : BaseOrderService, IOrderService message = ex.Message; } } - } - return message; + //获取人员余额 + var data = await DbContext.Queryable() + .LeftJoin((x, ga) => x.UserNo == ga.No) + .LeftJoin((x, ga, department) => ga.DepartmentNo == department.No) + .Where(x => x.UserNo == gainfo.No) + .Select((x, ga, department) => new OrderResultResponse + { + UserCode = ga.Code, + UserName = ga.Name, + DepartmentNo = ga.DepartmentNo, + DepartmentName = department.Name, + CurrentBalance = x.Balance + }) + .SingleAsync(); + + return new DefaultApiResult + { + Code = message.IsPresent() ? ApiStateCode.Error : ApiStateCode.Success, + Data = data, + Msg = message + }; + } async Task ToCheckAbleOfflineConsumeAsync(string thirdNo) { @@ -669,19 +675,14 @@ public class OrderService : BaseOrderService, IOrderService } - private async Task EMealVoucherConsumeAsync(ConsumeRequest request, GainfoEntity gainfo) + private async Task EMealVoucherConsumeAsync(ConsumeRequest request, GainfoEntity gainfo, string originData, string no, string ts, string idNo) { - var eMealVoucherQrCode = await DbContext.Queryable().Where(x => x.QrCode == request.UserUniqueNo).SingleAsync(); - var originData = eMealVoucherQrCode.OriginData.Split(':'); - - var no = originData[0]; - var idNo = originData[3]; var nowDate = DateTime.Now.Date; var current = await DbContext.Queryable() .Where(x => x.No == no && x.IdNo == idNo).SingleAsync(); (nowDate >= current.Start && nowDate <= current.End).ThrowIfFalse("餐券已过期"); - var time = DateTimeOffset.FromUnixTimeMilliseconds(Convert.ToInt64(originData[1].Reverse().Join(string.Empty))).ToLocalTime().DateTime; + var time = DateTimeOffset.FromUnixTimeMilliseconds(Convert.ToInt64(ts.Reverse().Join(string.Empty))).ToLocalTime().DateTime; (time.AddMinutes(60) >= DateTime.Now).ThrowIfFalse("二维码已过期"); var eMealVoucher = await DbContext.Queryable().Where(x => x.No == no).SingleAsync(); @@ -689,9 +690,6 @@ public class OrderService : BaseOrderService, IOrderService var checkData = await PreCheckAsync(request.DeviceUniqueNo, request.CostDateTime); eMealVoucher.Factories.Contains(checkData.BusinessPlaceTenantId).ThrowIfFalse("禁止在当前厂区消费"); - _logs.Add("检验设备和营业点参数:" + _sw.ElapsedMilliseconds); - _sw.Restart(); - var order = new CanteenOrderEntity { RequestJson = request.ToJson(), @@ -700,7 +698,7 @@ public class OrderService : BaseOrderService, IOrderService ApplicationType = CanteenApplicationTypeEnumType.Device, Name = gainfo.Name, Source = request.Source, - UserNo = eMealVoucherQrCode.OriginData, //记录为当前消费券 + UserNo = originData, //记录为当前消费券 UserCode = gainfo.Code, Amount = request.Amount, BusinessPlaceCode = checkData.BusinessPlaceCode, @@ -725,8 +723,6 @@ public class OrderService : BaseOrderService, IOrderService }; var orderId = await DbContext.InsertReturnIdentityAsync(order); - _logs.Add("临时order写入:" + _sw.ElapsedMilliseconds); - _sw.Restart(); try { @@ -749,17 +745,11 @@ public class OrderService : BaseOrderService, IOrderService await DbContext.InsertAsync(balanceRecord); }, 5); - _logs.Add("消费写入:" + _sw.ElapsedMilliseconds); - _sw.Restart(); - await DbContext.Updateable() .SetColumns(x => x.OrderStatus == CanteenOrderStatusEnumType.Success) .SetColumns(x => x.ModifiedTime == DateTime.Now) .Where(x => x.Id == orderId) .ExecuteCommandAsync(); - - _logs.Add("更新image和订单信息:" + _sw.ElapsedMilliseconds); - _sw.Restart(); } catch (Exception ex) { From 2394e8a4d2b379bb00995c4fa92fba99038ac28d Mon Sep 17 00:00:00 2001 From: liguoyang Date: Tue, 13 Aug 2024 10:32:27 +0800 Subject: [PATCH 14/25] =?UTF-8?q?feat=20=E9=A4=90=E6=AC=A1=E5=B0=B1?= =?UTF-8?q?=E9=A4=90=E5=88=86=E6=9E=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Order/Controllers/BalanceSummaryController.cs | 7 +++++++ Src/Dlhis.Canteen/Order/Services/IBalanceSummaryService.cs | 2 +- .../Order/Services/Implements/BalanceSummaryService.cs | 1 + 3 files changed, 9 insertions(+), 1 deletion(-) diff --git a/Src/Dlhis.Canteen/Order/Controllers/BalanceSummaryController.cs b/Src/Dlhis.Canteen/Order/Controllers/BalanceSummaryController.cs index 154eafb0..c508aaa9 100644 --- a/Src/Dlhis.Canteen/Order/Controllers/BalanceSummaryController.cs +++ b/Src/Dlhis.Canteen/Order/Controllers/BalanceSummaryController.cs @@ -60,5 +60,12 @@ public class BalanceSummaryController : ControllerBase public async Task BalanceRecordShiftAnalysisAmountAndCountAsync([FromQuery] BalanceRecordAnalysisByShiftRequest request) { return await _balanceSummaryService.BalanceRecordShiftAnalysisAmountAndCountAsync(request); +} + /// 用餐分析(餐次) + /// + [HttpGet("analysis/shift")] + public async Task BalanceRecordAnalysisByShiftAsync([FromQuery] BalanceRecordAnalysisByShiftRequest request) + { + return await _balanceSummaryService.BalanceRecordAnalysisByShiftAsync(request); } } \ No newline at end of file diff --git a/Src/Dlhis.Canteen/Order/Services/IBalanceSummaryService.cs b/Src/Dlhis.Canteen/Order/Services/IBalanceSummaryService.cs index b6a192d9..0fac698c 100644 --- a/Src/Dlhis.Canteen/Order/Services/IBalanceSummaryService.cs +++ b/Src/Dlhis.Canteen/Order/Services/IBalanceSummaryService.cs @@ -10,8 +10,8 @@ public interface IBalanceSummaryService : IScopeDependency Task> BalanceRecordAnalysisByCostIdAsync(); - Task BalanceRecordShiftAnalysisAmountAsync(BalanceRecordAnalysisByShiftRequest request); Task BalanceRecordShiftAnalysisAmountAndCountAsync(BalanceRecordAnalysisByShiftRequest request); + } \ No newline at end of file diff --git a/Src/Dlhis.Canteen/Order/Services/Implements/BalanceSummaryService.cs b/Src/Dlhis.Canteen/Order/Services/Implements/BalanceSummaryService.cs index 5a76b686..cad9e16d 100644 --- a/Src/Dlhis.Canteen/Order/Services/Implements/BalanceSummaryService.cs +++ b/Src/Dlhis.Canteen/Order/Services/Implements/BalanceSummaryService.cs @@ -99,6 +99,7 @@ public class BalanceSummaryService : IBalanceSummaryService var amount = await queryable.SumAsync(x => SqlFunc.Abs(x.Amount)); + var count = typeof(ShiftEnumType).GetFields(BindingFlags.Public | BindingFlags.Static).Length; var result = await queryable.GroupBy(x => new { x.CostDate, x.ShiftType }) From f76052427d9e4f505208310b2e189539bb26a92b Mon Sep 17 00:00:00 2001 From: liguoyang Date: Tue, 13 Aug 2024 13:46:06 +0800 Subject: [PATCH 15/25] =?UTF-8?q?feat=20=E5=B0=B1=E9=A4=90=E5=88=86?= =?UTF-8?q?=E6=9E=90,=E9=A4=90=E6=AC=A1=E4=BD=BF=E7=94=A8=E9=87=91?= =?UTF-8?q?=E9=A2=9D=E5=92=8C=E4=BA=BA=E6=95=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Order/Controllers/BalanceSummaryController.cs | 12 ++++++++---- .../Order/Services/IBalanceSummaryService.cs | 3 +++ .../Services/Implements/BalanceSummaryService.cs | 1 - 3 files changed, 11 insertions(+), 5 deletions(-) diff --git a/Src/Dlhis.Canteen/Order/Controllers/BalanceSummaryController.cs b/Src/Dlhis.Canteen/Order/Controllers/BalanceSummaryController.cs index c508aaa9..311a9479 100644 --- a/Src/Dlhis.Canteen/Order/Controllers/BalanceSummaryController.cs +++ b/Src/Dlhis.Canteen/Order/Controllers/BalanceSummaryController.cs @@ -61,11 +61,15 @@ public class BalanceSummaryController : ControllerBase { return await _balanceSummaryService.BalanceRecordShiftAnalysisAmountAndCountAsync(request); } - /// 用餐分析(餐次) + + /// + /// 餐次用餐分析,统计金额和人数 /// - [HttpGet("analysis/shift")] - public async Task BalanceRecordAnalysisByShiftAsync([FromQuery] BalanceRecordAnalysisByShiftRequest request) + /// + /// + [HttpGet("shift/analysis/amountAndCount")] + public async Task BalanceRecordShiftAnalysisAmountAndCountAsync([FromQuery] BalanceRecordAnalysisByShiftRequest request) { - return await _balanceSummaryService.BalanceRecordAnalysisByShiftAsync(request); + return await _balanceSummaryService.BalanceRecordShiftAnalysisAmountAndCountAsync(request); } } \ No newline at end of file diff --git a/Src/Dlhis.Canteen/Order/Services/IBalanceSummaryService.cs b/Src/Dlhis.Canteen/Order/Services/IBalanceSummaryService.cs index 0fac698c..455d7d59 100644 --- a/Src/Dlhis.Canteen/Order/Services/IBalanceSummaryService.cs +++ b/Src/Dlhis.Canteen/Order/Services/IBalanceSummaryService.cs @@ -14,4 +14,7 @@ public interface IBalanceSummaryService : IScopeDependency Task BalanceRecordShiftAnalysisAmountAndCountAsync(BalanceRecordAnalysisByShiftRequest request); + Task BalanceRecordShiftAnalysisAmountAsync(BalanceRecordAnalysisByShiftRequest request); + + Task BalanceRecordShiftAnalysisAmountAndCountAsync(BalanceRecordAnalysisByShiftRequest request); } \ No newline at end of file diff --git a/Src/Dlhis.Canteen/Order/Services/Implements/BalanceSummaryService.cs b/Src/Dlhis.Canteen/Order/Services/Implements/BalanceSummaryService.cs index cad9e16d..5a76b686 100644 --- a/Src/Dlhis.Canteen/Order/Services/Implements/BalanceSummaryService.cs +++ b/Src/Dlhis.Canteen/Order/Services/Implements/BalanceSummaryService.cs @@ -99,7 +99,6 @@ public class BalanceSummaryService : IBalanceSummaryService var amount = await queryable.SumAsync(x => SqlFunc.Abs(x.Amount)); - var count = typeof(ShiftEnumType).GetFields(BindingFlags.Public | BindingFlags.Static).Length; var result = await queryable.GroupBy(x => new { x.CostDate, x.ShiftType }) From 96b43876b84f13d0ac6be206ee8a6c94447b2872 Mon Sep 17 00:00:00 2001 From: liguoyang Date: Wed, 14 Aug 2024 15:07:08 +0800 Subject: [PATCH 16/25] =?UTF-8?q?feat=20=E7=94=B5=E5=AD=90=E9=A4=90?= =?UTF-8?q?=E5=88=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Order/Services/Implements/OrderService.cs | 22 +++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/Src/Dlhis.Canteen/Order/Services/Implements/OrderService.cs b/Src/Dlhis.Canteen/Order/Services/Implements/OrderService.cs index d0c8b274..bea63211 100644 --- a/Src/Dlhis.Canteen/Order/Services/Implements/OrderService.cs +++ b/Src/Dlhis.Canteen/Order/Services/Implements/OrderService.cs @@ -1,4 +1,4 @@ -using Dlhis.Canteen.Order.Dto; +using Dlhis.Canteen.Order.Dto; using Dlhis.Canteen.Setting.Services; using Dlhis.Entity.Basic.Entity; using Dlhis.Entity.Canteen.Entities; @@ -575,6 +575,22 @@ public class OrderService : BaseOrderService, IOrderService }; } else + { + if (request.IsOffline) + { + if (request.ThirdNo.IsPresent()) + { + + try + { + await EMealVoucherConsumeAsync(request.Adapt(), gainfo); + } + catch (Exception ex) + { + message = ex.Message; + } + } + else { if (request.IsOffline) { @@ -674,15 +690,16 @@ public class OrderService : BaseOrderService, IOrderService return await DbContext.Queryable().Where(x => x.Code == gainfoQrCode.UserCode).SingleAsync(); } - private async Task EMealVoucherConsumeAsync(ConsumeRequest request, GainfoEntity gainfo, string originData, string no, string ts, string idNo) { + var nowDate = DateTime.Now.Date; var current = await DbContext.Queryable() .Where(x => x.No == no && x.IdNo == idNo).SingleAsync(); (nowDate >= current.Start && nowDate <= current.End).ThrowIfFalse("餐券已过期"); var time = DateTimeOffset.FromUnixTimeMilliseconds(Convert.ToInt64(ts.Reverse().Join(string.Empty))).ToLocalTime().DateTime; + (time.AddMinutes(60) >= DateTime.Now).ThrowIfFalse("二维码已过期"); var eMealVoucher = await DbContext.Queryable().Where(x => x.No == no).SingleAsync(); @@ -750,6 +767,7 @@ public class OrderService : BaseOrderService, IOrderService .SetColumns(x => x.ModifiedTime == DateTime.Now) .Where(x => x.Id == orderId) .ExecuteCommandAsync(); + } catch (Exception ex) { From 23d3e1028b68ab26ff6f7b259af8bd305851e220 Mon Sep 17 00:00:00 2001 From: liguoyang Date: Wed, 14 Aug 2024 15:43:37 +0800 Subject: [PATCH 17/25] =?UTF-8?q?refactor=20=E4=BB=A3=E7=A0=81=E4=BC=98?= =?UTF-8?q?=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Order/Services/Implements/OrderService.cs | 21 ++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/Src/Dlhis.Canteen/Order/Services/Implements/OrderService.cs b/Src/Dlhis.Canteen/Order/Services/Implements/OrderService.cs index bea63211..2a508b8d 100644 --- a/Src/Dlhis.Canteen/Order/Services/Implements/OrderService.cs +++ b/Src/Dlhis.Canteen/Order/Services/Implements/OrderService.cs @@ -583,12 +583,29 @@ public class OrderService : BaseOrderService, IOrderService try { - await EMealVoucherConsumeAsync(request.Adapt(), gainfo); + await EMealVoucherConsumeAsync(request.Adapt(), gainfo, eMealVoucherQrCode.OriginData, no, ts, idNo); } catch (Exception ex) { message = ex.Message; } + + //获取餐券余额 + var data = await DbContext.Queryable() + .LeftJoin((x, d) => x.No == d.No) + .Where((x, d) => d.IdNo == idNo) + .Select((x, d) => new OrderResultResponse + { + CurrentBalance = d.Balance + }) + .SingleAsync(); + + return new DefaultApiResult + { + Code = message.IsPresent() ? ApiStateCode.Error : ApiStateCode.Success, + Data = data, + Msg = message + }; } else { @@ -692,7 +709,6 @@ public class OrderService : BaseOrderService, IOrderService private async Task EMealVoucherConsumeAsync(ConsumeRequest request, GainfoEntity gainfo, string originData, string no, string ts, string idNo) { - var nowDate = DateTime.Now.Date; var current = await DbContext.Queryable() .Where(x => x.No == no && x.IdNo == idNo).SingleAsync(); @@ -767,7 +783,6 @@ public class OrderService : BaseOrderService, IOrderService .SetColumns(x => x.ModifiedTime == DateTime.Now) .Where(x => x.Id == orderId) .ExecuteCommandAsync(); - } catch (Exception ex) { From fc597c6cb6a26c1183389b756e860a6fee9a80e4 Mon Sep 17 00:00:00 2001 From: liguoyang Date: Wed, 14 Aug 2024 16:47:12 +0800 Subject: [PATCH 18/25] =?UTF-8?q?fix=20route=E5=90=8D=E7=A7=B0=E4=BF=AE?= =?UTF-8?q?=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Organization/Services/Implements/GainfoService.cs | 6 +++--- .../EMealVoucher/Controllers/EMealVoucherController.cs | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Src/Dlhis.Basic/Organization/Services/Implements/GainfoService.cs b/Src/Dlhis.Basic/Organization/Services/Implements/GainfoService.cs index 4b04cfc7..8af911b0 100644 --- a/Src/Dlhis.Basic/Organization/Services/Implements/GainfoService.cs +++ b/Src/Dlhis.Basic/Organization/Services/Implements/GainfoService.cs @@ -463,14 +463,14 @@ public class GainfoService : IGainfoService return departmentNos.Distinct().ToList(); //local method - void RecursionGetNext(string currentNo, List departments, List result) + void RecursionGetNext(string currentNo, List internalDepartments, List result) { - var next = departments.Where(x => x.PNo == currentNo).ToList(); + var next = internalDepartments.Where(x => x.PNo == currentNo).ToList(); foreach (var item in next) { result.Add(item.No); - RecursionGetNext(item.No, departments, result); + RecursionGetNext(item.No, internalDepartments, result); } } } diff --git a/Src/Dlhis.Canteen/EMealVoucher/Controllers/EMealVoucherController.cs b/Src/Dlhis.Canteen/EMealVoucher/Controllers/EMealVoucherController.cs index 40b9483d..a4dd5f14 100644 --- a/Src/Dlhis.Canteen/EMealVoucher/Controllers/EMealVoucherController.cs +++ b/Src/Dlhis.Canteen/EMealVoucher/Controllers/EMealVoucherController.cs @@ -35,7 +35,7 @@ public class EMealVoucherController : ControllerBase /// /// /// - [HttpGet("no")] + [HttpGet("details")] public async Task> GetDetailsByNoAsync(string no) { return await _eMealVoucherService.GetDetailsByNoAsync(no); From 9685845a21eb84015c35dac8f8180b87e8fc01f2 Mon Sep 17 00:00:00 2001 From: liguoyang Date: Thu, 15 Aug 2024 16:49:50 +0800 Subject: [PATCH 19/25] =?UTF-8?q?fix=20=E7=BB=9F=E8=AE=A1,=E6=B6=88?= =?UTF-8?q?=E8=B4=B9=E6=98=8E=E7=BB=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Response/GainfoDetailResponse.cs | 3 +- .../GainfoOutSourceExternalInfoResponse.cs | 4 + .../Services/Implements/GainfoService.cs | 3 +- .../Controllers/EMealVoucherController.cs | 15 ++ .../Services/IEMealVoucherService.cs | 5 + .../Implements/EMealVoucherService.cs | 43 ++++++ .../Controllers/BalanceSummaryController.cs | 20 +-- .../Order/Controllers/BalancesController.cs | 1 + .../BalanceRecordAnalysisByShiftRequest.cs | 26 +--- .../Request/BalanceRecordAnalysisRequest.cs | 18 +-- .../BalanceRecordEMealVoucherPageRequest.cs | 9 ++ .../Order/Request/Common/SummaryCommonDto.cs | 28 ++++ .../BalanceRecordAnalysisByCostResponse.cs | 6 - ...BalanceRecordAnalysisDepartmentResponse.cs | 5 + .../BalanceRecordEMealVoucherResponse.cs | 129 ++++++++++++++++++ .../Order/Response/BalanceRecordResponse.cs | 3 + .../Order/Services/IBalanceSummaryService.cs | 3 +- .../Services/Implements/BalanceService.cs | 24 ++-- .../Implements/BalanceSummaryService.cs | 66 ++++----- .../Order/Services/Implements/OrderService.cs | 54 ++------ .../Basic/Entity/OutsourceEntity.cs | 51 ++++--- .../Canteen/Entities/EMealVoucherEntity.cs | 6 + .../Implements/EMealVoucherService.cs | 7 +- 23 files changed, 342 insertions(+), 187 deletions(-) create mode 100644 Src/Dlhis.Canteen/Order/Request/BalanceRecordEMealVoucherPageRequest.cs create mode 100644 Src/Dlhis.Canteen/Order/Request/Common/SummaryCommonDto.cs delete mode 100644 Src/Dlhis.Canteen/Order/Response/BalanceRecordAnalysisByCostResponse.cs create mode 100644 Src/Dlhis.Canteen/Order/Response/BalanceRecordAnalysisDepartmentResponse.cs create mode 100644 Src/Dlhis.Canteen/Order/Response/BalanceRecordEMealVoucherResponse.cs diff --git a/Src/Dlhis.Basic/Organization/Response/GainfoDetailResponse.cs b/Src/Dlhis.Basic/Organization/Response/GainfoDetailResponse.cs index c147c32d..17205533 100644 --- a/Src/Dlhis.Basic/Organization/Response/GainfoDetailResponse.cs +++ b/Src/Dlhis.Basic/Organization/Response/GainfoDetailResponse.cs @@ -56,7 +56,7 @@ public class GainfoDetailResponse /// /// 性别描述 /// - public string GenderCN => Gender.GetDescription(); + public string GenderDesc => Gender.GetDescription(); /// /// 身份证籍贯 @@ -138,6 +138,7 @@ public class GainfoDetailResponse /// /// 入职日期 /// + [JsonConverter(typeof(ToDateJsonConverter))] public DateTime? EntryDate { get; set; } /// diff --git a/Src/Dlhis.Basic/Organization/Response/GainfoOutSourceExternalInfoResponse.cs b/Src/Dlhis.Basic/Organization/Response/GainfoOutSourceExternalInfoResponse.cs index 820713f2..b6c7341f 100644 --- a/Src/Dlhis.Basic/Organization/Response/GainfoOutSourceExternalInfoResponse.cs +++ b/Src/Dlhis.Basic/Organization/Response/GainfoOutSourceExternalInfoResponse.cs @@ -1,4 +1,6 @@ using Dlhis.Basic.Organization.Dto; +using Kurisu.AspNetCore.Utils.Converters; +using Newtonsoft.Json; namespace Dlhis.Basic.Organization.Response; @@ -12,11 +14,13 @@ public class GainfoOutSourceExternalInfoResponse : GainfoOutSourceExternalInfoDt /// /// 入职日期 /// + [JsonConverter(typeof(ToDateJsonConverter))] public DateTime? EntryDate { get; set; } /// /// 离职日期 /// + [JsonConverter(typeof(ToDateJsonConverter))] public DateTime? ResignationDate { get; set; } /// diff --git a/Src/Dlhis.Basic/Organization/Services/Implements/GainfoService.cs b/Src/Dlhis.Basic/Organization/Services/Implements/GainfoService.cs index 8af911b0..80615642 100644 --- a/Src/Dlhis.Basic/Organization/Services/Implements/GainfoService.cs +++ b/Src/Dlhis.Basic/Organization/Services/Implements/GainfoService.cs @@ -100,13 +100,14 @@ public class GainfoService : IGainfoService .LeftJoin((gainfo, department, type) => type.Code == SqlFunc.ToString(gainfo.CardType) && type.Type == "timeperiod") .WhereIF(request.SearchType != GainfoSearchEnumType.BusinessTrip && request.DepartmentSelections?.Any() == false, gainfo => factories.Contains(gainfo.Factory)) .WhereIF(request.SearchType == GainfoSearchEnumType.Internal, gainfo => SqlFunc.Subqueryable().Where(p => p.Code == gainfo.Code).NotAny()) - .WhereIF(request.SearchType == GainfoSearchEnumType.Outsource, gainfo => SqlFunc.Subqueryable().Where(p => p.Code == gainfo.Code).Any())//&& today >= gainfo.EntryDate && today <= gainfo.ResignationDate + .WhereIF(request.SearchType == GainfoSearchEnumType.Outsource, gainfo => SqlFunc.Subqueryable().Where(p => p.Code == gainfo.Code).Any()) //&& today >= gainfo.EntryDate && today <= gainfo.ResignationDate .WhereIF(request.SearchType == GainfoSearchEnumType.BusinessTrip, gainfo => SqlFunc.Subqueryable().Where(p => p.Code == gainfo.Code && factories.Contains(p.Destination) && SqlFunc.DateIsSame(p.BeginDate, today)).Any()) .WhereIF(request.Search.IsPresent(), gainfo => gainfo.Name.Contains(request.Search) || gainfo.Code == request.Search || gainfo.IdNo == request.Search) + .OrderByIF(request.SearchType == GainfoSearchEnumType.Outsource, gainfo => gainfo.ResignationDate, OrderByType.Desc) //外包人员按离职日期倒排 .Select((gainfo, department, type) => new GainfoPageResponse { DepartmentName = department.Name, diff --git a/Src/Dlhis.Canteen/EMealVoucher/Controllers/EMealVoucherController.cs b/Src/Dlhis.Canteen/EMealVoucher/Controllers/EMealVoucherController.cs index a4dd5f14..ab0f2f76 100644 --- a/Src/Dlhis.Canteen/EMealVoucher/Controllers/EMealVoucherController.cs +++ b/Src/Dlhis.Canteen/EMealVoucher/Controllers/EMealVoucherController.cs @@ -1,7 +1,10 @@ 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 Kurisu.AspNetCore.DataAccess.Dto; +using Kurisu.AspNetCore.DataAccess.SqlSugar.Aop; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; @@ -73,4 +76,16 @@ public class EMealVoucherController : ControllerBase { return await _eMealVoucherService.GetQrCodeAsync(signature); } + + /// + /// 餐券消费分页 + /// + /// + /// + [HttpGet("balance/page")] + [IgnoreTenant] + public async Task> GetEMealVoucherPageAsync([FromQuery] BalanceRecordEMealVoucherPageRequest request) + { + return await _eMealVoucherService.GetEMealVoucherPageAsync(request); + } } \ No newline at end of file diff --git a/Src/Dlhis.Canteen/EMealVoucher/Services/IEMealVoucherService.cs b/Src/Dlhis.Canteen/EMealVoucher/Services/IEMealVoucherService.cs index ef41f70a..3ef1ae4f 100644 --- a/Src/Dlhis.Canteen/EMealVoucher/Services/IEMealVoucherService.cs +++ b/Src/Dlhis.Canteen/EMealVoucher/Services/IEMealVoucherService.cs @@ -1,6 +1,9 @@ using Dlhis.Canteen.EMealVoucher.Request; using Dlhis.Canteen.EMealVoucher.Response; +using Dlhis.Canteen.Order.Request; +using Dlhis.Canteen.Order.Response; using Kurisu.AspNetCore.DataAccess.Dto; +using Microsoft.AspNetCore.Mvc; namespace Dlhis.Canteen.EMealVoucher.Services; @@ -15,4 +18,6 @@ public interface IEMealVoucherService : IScopeDependency Task RefreshSignatureAsync(long detailId); Task GetQrCodeAsync(string signature); + + Task> GetEMealVoucherPageAsync([FromQuery] BalanceRecordEMealVoucherPageRequest request); } \ No newline at end of file diff --git a/Src/Dlhis.Canteen/EMealVoucher/Services/Implements/EMealVoucherService.cs b/Src/Dlhis.Canteen/EMealVoucher/Services/Implements/EMealVoucherService.cs index c00c2fa1..fb689658 100644 --- a/Src/Dlhis.Canteen/EMealVoucher/Services/Implements/EMealVoucherService.cs +++ b/Src/Dlhis.Canteen/EMealVoucher/Services/Implements/EMealVoucherService.cs @@ -1,8 +1,13 @@ 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.Entity.Basic.Entity; using Dlhis.Entity.Canteen.Entities; +using Dlhis.Entity.Canteen.Enums; using Kurisu.AspNetCore.Authentication.Abstractions; +using Kurisu.AspNetCore.CustomClass; using Kurisu.AspNetCore.DataAccess.Dto; using Kurisu.AspNetCore.DataAccess.SqlSugar.Extensions; using Kurisu.AspNetCore.DataAccess.SqlSugar.Services; @@ -103,4 +108,42 @@ public class EMealVoucherService : IEMealVoucherService return qrCode; } + + /// + public async Task> GetEMealVoucherPageAsync(BalanceRecordEMealVoucherPageRequest request) + { + var tenantId = _currentUser.GetStringTenantId(); + + return await _dbContext.Queryable() + .LeftJoin((x, bPlace) => x.BusinessPlaceCode == bPlace.Code) + .LeftJoin((x, bPlace, department) => x.DepartmentNo == department.No) + .Where(x => x.Status == BalanceRecordStatusEnumType.Valid && x.Type == BalanceRecordTypeEnumType.Out) //有效,消费数据 + .WhereIF(request.SearchDateTimePeriod.HasValue(), x => x.CostDate >= request.SearchDateTimePeriod.Start && x.CostDate <= request.SearchDateTimePeriod.End) //成本日期 + .Where(x => x.Source == BalanceRecordSourceEnumType.EMealVoucher) + .Where(x => SqlFunc.Subqueryable().Where(p => p.Factory == tenantId).Where(p => p.Code == x.UserCode).Any() || x.TenantId == tenantId) + .Select((x, bPlace, department) => new BalanceRecordEMealVoucherResponse + { + 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/Order/Controllers/BalanceSummaryController.cs b/Src/Dlhis.Canteen/Order/Controllers/BalanceSummaryController.cs index 4bf65777..2de326f2 100644 --- a/Src/Dlhis.Canteen/Order/Controllers/BalanceSummaryController.cs +++ b/Src/Dlhis.Canteen/Order/Controllers/BalanceSummaryController.cs @@ -1,4 +1,5 @@ using Dlhis.Canteen.Order.Request; +using Dlhis.Canteen.Order.Request.Common; using Dlhis.Canteen.Order.Response; using Dlhis.Canteen.Order.Services; using Kurisu.AspNetCore.DataAccess.Dto; @@ -34,12 +35,12 @@ public class BalanceSummaryController : ControllerBase } /// - /// 用餐分析(成本中心) + /// 餐次用餐分析,统计部门成本中心金额 /// - [HttpGet("analysis/cost")] - public async Task> BalanceRecordAnalysisByCostIdAsync() + [HttpGet("department/analysis/amount")] + public async Task> BalanceRecordAnalysisByCostIdAsync(SummaryCommonDto request) { - return await _balanceSummaryService.BalanceRecordAnalysisByCostIdAsync(); + return await _balanceSummaryService.BalanceRecordAnalysisByCostIdAsync(request); } /// @@ -61,15 +62,4 @@ public class BalanceSummaryController : ControllerBase { return await _balanceSummaryService.BalanceRecordShiftAnalysisAmountAndCountAsync(request); } - - /// - /// 餐次用餐分析,统计金额和人数 - /// - /// - /// - [HttpGet("shift/analysis/amountAndCount")] - public async Task BalanceRecordShiftAnalysisAmountAndCountAsync([FromQuery] BalanceRecordAnalysisByShiftRequest request) - { - return await _balanceSummaryService.BalanceRecordShiftAnalysisAmountAndCountAsync(request); - } } \ No newline at end of file diff --git a/Src/Dlhis.Canteen/Order/Controllers/BalancesController.cs b/Src/Dlhis.Canteen/Order/Controllers/BalancesController.cs index 32612c15..0e28e4db 100644 --- a/Src/Dlhis.Canteen/Order/Controllers/BalancesController.cs +++ b/Src/Dlhis.Canteen/Order/Controllers/BalancesController.cs @@ -1,5 +1,6 @@ using System.ComponentModel.DataAnnotations; using System.Data; +using Dlhis.Canteen.EMealVoucher.Services; using Dlhis.Canteen.Order.Request; using Dlhis.Canteen.Order.Response; using Dlhis.Canteen.Order.Services; diff --git a/Src/Dlhis.Canteen/Order/Request/BalanceRecordAnalysisByShiftRequest.cs b/Src/Dlhis.Canteen/Order/Request/BalanceRecordAnalysisByShiftRequest.cs index 65f99310..0933998f 100644 --- a/Src/Dlhis.Canteen/Order/Request/BalanceRecordAnalysisByShiftRequest.cs +++ b/Src/Dlhis.Canteen/Order/Request/BalanceRecordAnalysisByShiftRequest.cs @@ -1,29 +1,7 @@ -using System.ComponentModel.DataAnnotations; -using Kurisu.AspNetCore.CustomClass; -using Kurisu.AspNetCore.DataAccess.Dto; +using Dlhis.Canteen.Order.Request.Common; namespace Dlhis.Canteen.Order.Request; -public class BalanceRecordAnalysisByShiftRequest : PageDto, IValidatableObject +public class BalanceRecordAnalysisByShiftRequest : SummaryCommonDto { - /// - /// 营业点 - /// - public List BusinessPlaceCodes { get; set; } - - /// - /// - /// - public DateTimePeriod SearchDateTimePeriod { get; set; } - - /// - public IEnumerable Validate(ValidationContext validationContext) - { - if (SearchDateTimePeriod is { End: not null }) - { - SearchDateTimePeriod.End = SearchDateTimePeriod.End.Value.AddDays(1).AddSeconds(-1); - } - - yield break; - } } \ No newline at end of file diff --git a/Src/Dlhis.Canteen/Order/Request/BalanceRecordAnalysisRequest.cs b/Src/Dlhis.Canteen/Order/Request/BalanceRecordAnalysisRequest.cs index 6995147b..8b02b7a6 100644 --- a/Src/Dlhis.Canteen/Order/Request/BalanceRecordAnalysisRequest.cs +++ b/Src/Dlhis.Canteen/Order/Request/BalanceRecordAnalysisRequest.cs @@ -1,25 +1,11 @@ -using System.ComponentModel.DataAnnotations; -using Kurisu.AspNetCore.CustomClass; -using Kurisu.AspNetCore.DataAccess.Dto; +using Dlhis.Canteen.Order.Request.Common; namespace Dlhis.Canteen.Order.Request; -public class BalanceRecordAnalysisRequest : PageDto, IValidatableObject +public class BalanceRecordAnalysisRequest : SummaryCommonDto { - public DateTimePeriod SearchDateTimePeriod { get; set; } - /// /// 营业点 /// public Guid? BusinessPlaceCode { get; set; } - - public IEnumerable Validate(ValidationContext validationContext) - { - if (SearchDateTimePeriod is { End: not null }) - { - SearchDateTimePeriod.End = SearchDateTimePeriod.End.Value.AddDays(1).AddSeconds(-1); - } - - yield break; - } } \ No newline at end of file diff --git a/Src/Dlhis.Canteen/Order/Request/BalanceRecordEMealVoucherPageRequest.cs b/Src/Dlhis.Canteen/Order/Request/BalanceRecordEMealVoucherPageRequest.cs new file mode 100644 index 00000000..f4d717f6 --- /dev/null +++ b/Src/Dlhis.Canteen/Order/Request/BalanceRecordEMealVoucherPageRequest.cs @@ -0,0 +1,9 @@ +using Kurisu.AspNetCore.CustomClass; +using Kurisu.AspNetCore.DataAccess.Dto; + +namespace Dlhis.Canteen.Order.Request; + +public class BalanceRecordEMealVoucherPageRequest : PageDto +{ + public DateTimePeriod SearchDateTimePeriod { get; set; } +} \ No newline at end of file diff --git a/Src/Dlhis.Canteen/Order/Request/Common/SummaryCommonDto.cs b/Src/Dlhis.Canteen/Order/Request/Common/SummaryCommonDto.cs new file mode 100644 index 00000000..7b9b41f5 --- /dev/null +++ b/Src/Dlhis.Canteen/Order/Request/Common/SummaryCommonDto.cs @@ -0,0 +1,28 @@ +using System.ComponentModel.DataAnnotations; +using Kurisu.AspNetCore.CustomClass; +using Kurisu.AspNetCore.DataAccess.Dto; + +namespace Dlhis.Canteen.Order.Request.Common; + +public class SummaryCommonDto : PageDto, IValidatableObject +{ + /// + /// 营业点 + /// + public List BusinessPlaceCodes { get; set; } + + /// + /// 日期范围 + /// + public DateTimePeriod SearchDateTimePeriod { get; set; } + + public IEnumerable Validate(ValidationContext validationContext) + { + if (SearchDateTimePeriod is { End: not null }) + { + SearchDateTimePeriod.End = SearchDateTimePeriod.End.Value.AddDays(1).AddSeconds(-1); + } + + yield break; + } +} \ No newline at end of file diff --git a/Src/Dlhis.Canteen/Order/Response/BalanceRecordAnalysisByCostResponse.cs b/Src/Dlhis.Canteen/Order/Response/BalanceRecordAnalysisByCostResponse.cs deleted file mode 100644 index d9c97fa5..00000000 --- a/Src/Dlhis.Canteen/Order/Response/BalanceRecordAnalysisByCostResponse.cs +++ /dev/null @@ -1,6 +0,0 @@ -namespace Dlhis.Canteen.Order.Response; - -public class BalanceRecordAnalysisByCostResponse -{ - -} \ No newline at end of file diff --git a/Src/Dlhis.Canteen/Order/Response/BalanceRecordAnalysisDepartmentResponse.cs b/Src/Dlhis.Canteen/Order/Response/BalanceRecordAnalysisDepartmentResponse.cs new file mode 100644 index 00000000..7692aa61 --- /dev/null +++ b/Src/Dlhis.Canteen/Order/Response/BalanceRecordAnalysisDepartmentResponse.cs @@ -0,0 +1,5 @@ +namespace Dlhis.Canteen.Order.Response; + +public class BalanceRecordAnalysisDepartmentResponse +{ +} \ No newline at end of file diff --git a/Src/Dlhis.Canteen/Order/Response/BalanceRecordEMealVoucherResponse.cs b/Src/Dlhis.Canteen/Order/Response/BalanceRecordEMealVoucherResponse.cs new file mode 100644 index 00000000..6dc5dd5e --- /dev/null +++ b/Src/Dlhis.Canteen/Order/Response/BalanceRecordEMealVoucherResponse.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.Order.Response; + +public class BalanceRecordEMealVoucherResponse +{ + 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; } +} \ No newline at end of file diff --git a/Src/Dlhis.Canteen/Order/Response/BalanceRecordResponse.cs b/Src/Dlhis.Canteen/Order/Response/BalanceRecordResponse.cs index ac4c6183..ac19cb85 100644 --- a/Src/Dlhis.Canteen/Order/Response/BalanceRecordResponse.cs +++ b/Src/Dlhis.Canteen/Order/Response/BalanceRecordResponse.cs @@ -61,6 +61,9 @@ public class BalanceRecordResponse /// public BalanceRecordSourceEnumType Source { get; set; } + /// + /// 消费识别来源 + /// public string SourceDesc => Source.GetDescription(); /// diff --git a/Src/Dlhis.Canteen/Order/Services/IBalanceSummaryService.cs b/Src/Dlhis.Canteen/Order/Services/IBalanceSummaryService.cs index 0093f453..ae314b0b 100644 --- a/Src/Dlhis.Canteen/Order/Services/IBalanceSummaryService.cs +++ b/Src/Dlhis.Canteen/Order/Services/IBalanceSummaryService.cs @@ -1,4 +1,5 @@ using Dlhis.Canteen.Order.Request; +using Dlhis.Canteen.Order.Request.Common; using Dlhis.Canteen.Order.Response; using Kurisu.AspNetCore.DataAccess.Dto; @@ -8,7 +9,7 @@ public interface IBalanceSummaryService : IScopeDependency { Task BalanceRecordAnalysisAsync(BalanceRecordAnalysisRequest request); - Task> BalanceRecordAnalysisByCostIdAsync(); + Task> BalanceRecordAnalysisByCostIdAsync(SummaryCommonDto request); Task BalanceRecordShiftAnalysisAmountAsync(BalanceRecordAnalysisByShiftRequest request); diff --git a/Src/Dlhis.Canteen/Order/Services/Implements/BalanceService.cs b/Src/Dlhis.Canteen/Order/Services/Implements/BalanceService.cs index a83c3107..57b8d488 100644 --- a/Src/Dlhis.Canteen/Order/Services/Implements/BalanceService.cs +++ b/Src/Dlhis.Canteen/Order/Services/Implements/BalanceService.cs @@ -52,12 +52,11 @@ public class BalanceService : IBalanceService .LeftJoin((record, ga, department) => ga.DepartmentNo == department.No) .LeftJoin((record, ga, department, bPlace) => record.BusinessPlaceCode == bPlace.Code) .LeftJoin((record, ga, department, bPlace, order) => record.No == order.No) - .WhereIF(request.SearchDateTimePeriod?.Start.HasValue == true, record => record.CostDate >= request.SearchDateTimePeriod.Start) - .WhereIF(request.SearchDateTimePeriod?.End.HasValue == true, record => record.CostDate <= request.SearchDateTimePeriod.End) - .WhereIF(request.ShiftTypes.IsPresent(), record => request.ShiftTypes.Contains(record.ShiftType)) - .WhereIF(request.Type.HasValue, record => record.Type == request.Type) .WhereIF(request.Factory.IsPresent(), record => record.TenantId == request.Factory) - .WhereIF(request.Search.IsPresent(), (record, ga) => ga.Code == request.Search) + .WhereIF(request.Type.HasValue, record => record.Type == request.Type) + .WhereIF(request.SearchDateTimePeriod.HasValue(), record => record.CostDate >= request.SearchDateTimePeriod.Start && record.CostDate <= request.SearchDateTimePeriod.End) + .WhereIF(request.ShiftTypes.IsPresent(), record => request.ShiftTypes.Contains(record.ShiftType)) + .WhereIF(request.Search.IsPresent(), (record, ga) => ga.Code == request.Search || ga.Name == request.Search) .OrderBy(record => record.CreateTime, OrderByType.Desc) .Select((record, ga, department, bPlace, order) => new BalanceRecordResponse { @@ -82,7 +81,7 @@ public class BalanceService : IBalanceService Factory = record.TenantId, ShiftType = record.ShiftType, Remark = record.Remark, - Werks = ga.Werks + Werks = record.Werks }) .ToPageListAsync(request); @@ -346,12 +345,11 @@ public class BalanceService : IBalanceService .LeftJoin((record, ga) => record.UserNo == ga.No) .LeftJoin((record, ga, department) => ga.DepartmentNo == department.No) .LeftJoin((record, ga, department, bPlace) => record.BusinessPlaceCode == bPlace.Code) - .Where(record => record.Type == BalanceRecordTypeEnumType.Out) - .Where(record => record.Status == BalanceRecordStatusEnumType.Valid) - .WhereIF(request.SearchDateTimePeriod?.Start.HasValue == true, record => record.CostDate >= request.SearchDateTimePeriod.Start) - .WhereIF(request.SearchDateTimePeriod?.End.HasValue == true, record => record.CostDate <= request.SearchDateTimePeriod.End) + .Where((record, ga) => record.UserCode == jinkoCode) + .Where(record => record.Status == BalanceRecordStatusEnumType.Valid && record.Type == BalanceRecordTypeEnumType.Out) + .Where(record => record.Source != BalanceRecordSourceEnumType.EMealVoucher) //不展示电子餐券信息 + .WhereIF(request.SearchDateTimePeriod.HasValue(), record => record.CostDate >= request.SearchDateTimePeriod.Start && record.CostDate <= request.SearchDateTimePeriod.End) .WhereIF(request.ApplicationType.HasValue, record => record.ApplicationType == request.ApplicationType) - .Where((record, ga) => ga.Code == jinkoCode) .OrderBy(record => record.CostDateTime) .Select((record, ga, department, bPlace) => new BalanceRecordUserPageResponse { @@ -372,8 +370,8 @@ public class BalanceService : IBalanceService var monthSum = await _dbContext.Queryable() .Where(x => x.CostDateTime >= monthStart && x.CostDateTime <= monthEnd) - .Where(x => x.Type == BalanceRecordTypeEnumType.Out) - .Where(x => x.Status == BalanceRecordStatusEnumType.Valid) + .Where(x => x.Status == BalanceRecordStatusEnumType.Valid && x.Type == BalanceRecordTypeEnumType.Out) + .Where(x => x.Source != BalanceRecordSourceEnumType.EMealVoucher) .Where(x => x.UserCode == jinkoCode) .SumAsync(x => SqlFunc.Abs(x.Amount)); diff --git a/Src/Dlhis.Canteen/Order/Services/Implements/BalanceSummaryService.cs b/Src/Dlhis.Canteen/Order/Services/Implements/BalanceSummaryService.cs index 5a76b686..3f87efa6 100644 --- a/Src/Dlhis.Canteen/Order/Services/Implements/BalanceSummaryService.cs +++ b/Src/Dlhis.Canteen/Order/Services/Implements/BalanceSummaryService.cs @@ -1,6 +1,7 @@ using System.Reflection; using Dlhis.Canteen.Order.Dto; using Dlhis.Canteen.Order.Request; +using Dlhis.Canteen.Order.Request.Common; using Dlhis.Canteen.Order.Response; using Dlhis.Entity.Canteen.Entities; using Dlhis.Entity.Canteen.Enums; @@ -23,12 +24,13 @@ public class BalanceSummaryService : IBalanceSummaryService public async Task BalanceRecordAnalysisAsync(BalanceRecordAnalysisRequest request) { - var list = await _dbContext.Queryable() - .WhereIF(request.SearchDateTimePeriod.HasValue(), - record => record.CostDate >= request.SearchDateTimePeriod.Start && record.CostDate <= request.SearchDateTimePeriod.End) - .WhereIF(request.BusinessPlaceCode.HasValue, record => record.BusinessPlaceCode == request.BusinessPlaceCode) - .Where(record => record.Type == BalanceRecordTypeEnumType.Out && record.Status == BalanceRecordStatusEnumType.Valid) - .ToListAsync(); + if (request.BusinessPlaceCode.HasValue) + { + request.BusinessPlaceCodes = new List { request.BusinessPlaceCode.Value }; + } + + var queryable = GetQueryable(request); + var list =await queryable.ToListAsync(); var sum = list.Sum(x => Math.Abs(x.Amount)); @@ -59,32 +61,9 @@ public class BalanceSummaryService : IBalanceSummaryService } - public async Task> BalanceRecordAnalysisByCostIdAsync() + public async Task> BalanceRecordAnalysisByCostIdAsync(SummaryCommonDto request) { - var list = await _dbContext.Queryable() - // .WhereIF(request.SearchDateTimePeriod?.Start.HasValue == true && request.SearchDateTimePeriod?.End.HasValue == true, - // record => record.CostDate >= request.SearchDateTimePeriod.Start && record.CostDate <= request.SearchDateTimePeriod.End) - //.WhereIF(request.BusinessPlaceCode.HasValue, record => record.BusinessPlaceCode == request.BusinessPlaceCode) - .Where(record => record.Type == BalanceRecordTypeEnumType.Out && record.Status == BalanceRecordStatusEnumType.Valid) - .ToListAsync(); - - var shifts = Enum.GetValues().ToList(); - var page = list.GroupBy(record => record.CostDate.Date).Select(grp => - { - return new BalanceRecordAnalysisResponse - { - Date = DateOnly.FromDateTime(grp.Key), - Items = shifts.Select(shift => - { - return new KeyValueDto - { - Key = shift, - Value = grp.Where(x => x.ShiftType == shift).Select(x => x.UserNo).Distinct().Count() - }; - }).ToList(), - Total = grp.Where(x => x.CostDate == grp.Key).Select(x => x.UserNo).Distinct().Count() - }; - }).OrderByDescending(x => x.Date); + // var queryable = GetQueryable(request); return null; } @@ -92,10 +71,7 @@ public class BalanceSummaryService : IBalanceSummaryService public async Task BalanceRecordShiftAnalysisAmountAsync(BalanceRecordAnalysisByShiftRequest request) { - var queryable = _dbContext.Queryable() - .Where(x => x.Status == BalanceRecordStatusEnumType.Valid && x.Type == BalanceRecordTypeEnumType.Out) - .WhereIF(request.SearchDateTimePeriod.HasValue(), x => x.CostDate >= request.SearchDateTimePeriod.Start && x.CostDate <= request.SearchDateTimePeriod.End) - .WhereIF(request.BusinessPlaceCodes?.Any() == true, x => request.BusinessPlaceCodes.Contains(x.BusinessPlaceCode.Value)); + var queryable = GetQueryable(request); var amount = await queryable.SumAsync(x => SqlFunc.Abs(x.Amount)); @@ -128,10 +104,7 @@ public class BalanceSummaryService : IBalanceSummaryService public async Task BalanceRecordShiftAnalysisAmountAndCountAsync(BalanceRecordAnalysisByShiftRequest request) { - var queryable = _dbContext.Queryable() - .Where(x => x.Status == BalanceRecordStatusEnumType.Valid && x.Type == BalanceRecordTypeEnumType.Out) - .WhereIF(request.SearchDateTimePeriod.HasValue(), x => x.CostDate >= request.SearchDateTimePeriod.Start && x.CostDate <= request.SearchDateTimePeriod.End) - .WhereIF(request.BusinessPlaceCodes?.Any() == true, x => request.BusinessPlaceCodes.Contains(x.BusinessPlaceCode.Value)); + var queryable = GetQueryable(request); var amount = await queryable.SumAsync(x => SqlFunc.Abs(x.Amount)); @@ -150,4 +123,19 @@ public class BalanceSummaryService : IBalanceSummaryService }).ToList() }; } + + //**************************************************************help method*********************************************************************** + + /// + /// 获取默认查询queryable + /// + /// + /// + private ISugarQueryable GetQueryable(SummaryCommonDto request) + { + return _dbContext.Queryable() + .Where(x => x.Status == BalanceRecordStatusEnumType.Valid && x.Type == BalanceRecordTypeEnumType.Out) //有效,消费数据 + .WhereIF(request.SearchDateTimePeriod.HasValue(), x => x.CostDate >= request.SearchDateTimePeriod.Start && x.CostDate <= request.SearchDateTimePeriod.End) //成本日期 + .WhereIF(request.BusinessPlaceCodes?.Any() == true, x => request.BusinessPlaceCodes.Contains(x.BusinessPlaceCode.Value)); //营业点 + } } \ No newline at end of file diff --git a/Src/Dlhis.Canteen/Order/Services/Implements/OrderService.cs b/Src/Dlhis.Canteen/Order/Services/Implements/OrderService.cs index 4a2aede4..0fb1f2f9 100644 --- a/Src/Dlhis.Canteen/Order/Services/Implements/OrderService.cs +++ b/Src/Dlhis.Canteen/Order/Services/Implements/OrderService.cs @@ -410,40 +410,9 @@ public class OrderService : BaseOrderService, IOrderService /// private async Task ConsumeAsync(ConsumeRequest request, GainfoEntity gainfo) { - var registry = await DbContext.Queryable().Where(x => x.DeviceUniqueNo == request.DeviceUniqueNo).SingleAsync(); - registry.ThrowIfNull("设备尚未登记"); + var checkData = await PreCheckAsync(request.DeviceUniqueNo, request.CostDateTime); - var device = await DbContext.Queryable().Where(x => x.UniqueNo == request.DeviceUniqueNo).SingleAsync(); - device.ThrowIfNull("设备尚未登记"); - device.Enable.ThrowIfFalse("设备已被停用"); - - var businessPlaceInfo = await DbContext.Queryable() - .LeftJoin((x, sr) => x.Code == sr.PlaceCode) - .Where(x => x.Code == registry.BusinessPlaceCode) - .Select((x, sr) => new - { - x.Code, - sr.ShiftCode, - x.TenantId - }) - .SingleAsync(); - - businessPlaceInfo.ThrowIfNull("设备尚未登记营业点"); - - //获取当前消费餐次 - var shifts = await DbContext.Queryable().Where(x => x.ShiftCode == businessPlaceInfo.ShiftCode).ToListAsync(); - shifts.ThrowIfEmpty("营业点餐次尚未设置"); - - var shift = shifts.FirstOrDefault(x => new TimePeriod - { - Start = x.Start, - End = x.End - }.IsPresent(request.CostDateTime)); - shift.ThrowIfNull("非就餐时间,无法消费"); - - var costDate = await GetCostDateAsync(shift, request.CostDateTime); - - (request.Source == BalanceRecordSourceEnumType.QrCode && businessPlaceInfo.TenantId != gainfo.Factory).ThrowIfTrue("禁止跨厂区消费"); + (request.Source == BalanceRecordSourceEnumType.QrCode && checkData.BusinessPlaceTenantId != gainfo.Factory).ThrowIfTrue("禁止跨厂区消费"); var order = new CanteenOrderEntity { @@ -456,30 +425,28 @@ public class OrderService : BaseOrderService, IOrderService UserNo = gainfo.No, UserCode = gainfo.Code, Amount = request.Amount, - BusinessPlaceCode = businessPlaceInfo?.Code, - BusinessShiftCode = shift?.ShiftCode, - ShiftType = shift?.ShiftType, - CostDate = costDate.Date, + BusinessPlaceCode = checkData.BusinessPlaceCode, + BusinessShiftCode = checkData.BusinessShiftCode, + ShiftType = checkData.Shift.ShiftType, + CostDate = checkData.CostDate, CostId = gainfo.CostId, DepartmentNo = gainfo.DepartmentNo, DeviceUniqueNo = request.DeviceUniqueNo, No = SnowFlakeHelper.Instance.NextId().ToString(), IsOffline = request.IsOffline, - IsCostCrossTenant = gainfo.Factory != businessPlaceInfo!.TenantId, + IsCostCrossTenant = gainfo.Factory != checkData.BusinessPlaceTenantId, OriginTenantId = gainfo.Factory, Werks = gainfo.Werks, - - //餐别异常处理 - Status = shift == null ? BalanceRecordStatusEnumType.Doubtful : BalanceRecordStatusEnumType.Valid, + Status = BalanceRecordStatusEnumType.Valid, OrderStatus = CanteenOrderStatusEnumType.Wait, CostDateTime = request.CostDateTime, //标识当前消费的基地 - TenantId = businessPlaceInfo.TenantId, + TenantId = checkData.BusinessPlaceTenantId }; var orderId = await DbContext.InsertReturnIdentityAsync(order); @@ -576,7 +543,6 @@ public class OrderService : BaseOrderService, IOrderService } else { - if (request.IsOffline) { if (request.ThirdNo.IsPresent()) @@ -684,7 +650,7 @@ public class OrderService : BaseOrderService, IOrderService var time = DateTimeOffset.FromUnixTimeMilliseconds(Convert.ToInt64(ts.Reverse().Join(string.Empty))).ToLocalTime().DateTime; - (time.AddMinutes(60) >= DateTime.Now).ThrowIfFalse("二维码已过期"); + (time.AddMinutes(60) >= DateTime.Now).ThrowIfFalse("餐券二维码已过期"); var eMealVoucher = await DbContext.Queryable().Where(x => x.No == no).SingleAsync(); diff --git a/Src/Dlhis.Entity/Basic/Entity/OutsourceEntity.cs b/Src/Dlhis.Entity/Basic/Entity/OutsourceEntity.cs index 094240a7..6a32abc5 100644 --- a/Src/Dlhis.Entity/Basic/Entity/OutsourceEntity.cs +++ b/Src/Dlhis.Entity/Basic/Entity/OutsourceEntity.cs @@ -1,36 +1,35 @@ using Kurisu.AspNetCore.DataAccess.SqlSugar; using SqlSugar; -namespace Dlhis.Entity.Basic.Entity +namespace Dlhis.Entity.Basic.Entity; + +/// +/// 外包人员 +/// +[SugarTable(TableName = "Outsource", TableDescription = "外包人员")] +public class OutsourceEntity : SugarBaseEntity { /// - /// 外包人员 + /// 外包人员工号 LS开头 /// - [SugarTable(TableName = "Outsource", TableDescription = "外包人员")] - public class OutsourceEntity : SugarBaseEntity - { - /// - /// 外包人员工号 LS开头 - /// - [SugarColumn(IsNullable = false, ColumnDescription = "工号")] - public string Code { get; set; } + [SugarColumn(IsNullable = false, ColumnDescription = "工号")] + public string Code { get; set; } - /// - /// 供应商 - /// - [SugarColumn(IsNullable = false, ColumnDescription = "供应商")] - public string Supplier { get; set; } + /// + /// 供应商 + /// + [SugarColumn(IsNullable = false, ColumnDescription = "供应商")] + public string Supplier { get; set; } - /// - /// 对接人员工号 - /// - [SugarColumn(IsNullable = false, ColumnDescription = "对接人工号")] - public string SapCode { get; set; } + /// + /// 对接人员工号 + /// + [SugarColumn(IsNullable = false, ColumnDescription = "对接人工号")] + public string SapCode { get; set; } - /// - /// 对接人员手机号 - /// - [SugarColumn(IsNullable = false, ColumnDescription = "对接人手机号")] - public string SapPhone { get; set; } - } + /// + /// 对接人员手机号 + /// + [SugarColumn(IsNullable = false, ColumnDescription = "对接人手机号")] + public string SapPhone { get; set; } } \ No newline at end of file diff --git a/Src/Dlhis.Entity/Canteen/Entities/EMealVoucherEntity.cs b/Src/Dlhis.Entity/Canteen/Entities/EMealVoucherEntity.cs index 7ff544aa..c13e7ed1 100644 --- a/Src/Dlhis.Entity/Canteen/Entities/EMealVoucherEntity.cs +++ b/Src/Dlhis.Entity/Canteen/Entities/EMealVoucherEntity.cs @@ -75,4 +75,10 @@ public class EMealVoucherEntity : SugarBaseEntity /// [SugarColumn(ColumnDescription = "申请日期")] public DateTime Date { get; set; } + + /// + /// 厂区 + /// + [SugarColumn(ColumnDescription = "厂区")] + public string Factory { 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 a956a612..817fb5e3 100644 --- a/Src/Dlhis.External/EMealVoucher/Services/Implements/EMealVoucherService.cs +++ b/Src/Dlhis.External/EMealVoucher/Services/Implements/EMealVoucherService.cs @@ -1,3 +1,4 @@ +using Dlhis.Entity.Basic.Entity; using Dlhis.Entity.Canteen.Entities; using Dlhis.Entity.Canteen.Enums; using Dlhis.External.EMealVoucher.Request; @@ -19,6 +20,9 @@ public class EMealVoucherService : IEMealVoucherService { (await _dbContext.Queryable().Where(x => x.No == request.No).AnyAsync()).ThrowIfTrue($"{request.No}已存在"); + var gainfo = await _dbContext.Queryable().Where(x => x.Code == request.Code).SingleAsync(); + gainfo.ThrowIfNull("申请人不存在"); + var voucher = new EMealVoucherEntity { No = request.No, @@ -31,7 +35,8 @@ public class EMealVoucherService : IEMealVoucherService Reason = request.Reason, Shifts = request.Shifts.Select(x => (ShiftEnumType)x).ToList(), Date = request.Date, - Factories = request.Factories + Factories = request.Factories, + Factory = gainfo.Factory }; var details = request.Details.Select(x => new EMealVoucherDetailEntity From 2c216216cdadbc2acdd6124df4dbc91c7e7766d8 Mon Sep 17 00:00:00 2001 From: liguoyang Date: Thu, 15 Aug 2024 17:54:44 +0800 Subject: [PATCH 20/25] =?UTF-8?q?fix=20=E5=A4=84=E7=90=86=E5=B7=B2?= =?UTF-8?q?=E7=9F=A5=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Controllers/BalanceSummaryController.cs | 17 +++++++--- .../Request/BalanceRecordUserPageRequest.cs | 7 ++--- .../BalanceRecordAnalysisDResponse.cs | 9 ++++++ ...BalanceRecordAnalysisDepartmentResponse.cs | 5 --- .../Order/Services/IBalanceSummaryService.cs | 3 +- .../Implements/BalanceSummaryService.cs | 31 ++++++++++++++++--- .../Order/Services/Implements/OrderService.cs | 2 +- .../Identity/Controllers/UsersController.cs | 1 - 8 files changed, 54 insertions(+), 21 deletions(-) create mode 100644 Src/Dlhis.Canteen/Order/Response/BalanceRecordAnalysisDResponse.cs delete mode 100644 Src/Dlhis.Canteen/Order/Response/BalanceRecordAnalysisDepartmentResponse.cs diff --git a/Src/Dlhis.Canteen/Order/Controllers/BalanceSummaryController.cs b/Src/Dlhis.Canteen/Order/Controllers/BalanceSummaryController.cs index 2de326f2..898750ae 100644 --- a/Src/Dlhis.Canteen/Order/Controllers/BalanceSummaryController.cs +++ b/Src/Dlhis.Canteen/Order/Controllers/BalanceSummaryController.cs @@ -35,12 +35,21 @@ public class BalanceSummaryController : ControllerBase } /// - /// 餐次用餐分析,统计部门成本中心金额 + /// 餐次用餐分析,统计部门金额和消费人数 /// - [HttpGet("department/analysis/amount")] - public async Task> BalanceRecordAnalysisByCostIdAsync(SummaryCommonDto request) + [HttpGet("department/analysis/amountAndCount")] + public async Task> BalanceRecordAnalysisByDepartmentAsync([FromQuery] SummaryCommonDto request) { - return await _balanceSummaryService.BalanceRecordAnalysisByCostIdAsync(request); + return await _balanceSummaryService.BalanceRecordAnalysisByDepartmentAsync(request); + } + + /// + /// 餐次用餐分析,统计成本中心金额和消费人数 + /// + [HttpGet("costId/analysis/amountAndCount")] + public async Task> BalanceRecordAnalysisByCostAsync([FromQuery] SummaryCommonDto request) + { + return await _balanceSummaryService.BalanceRecordAnalysisByCostAsync(request); } /// diff --git a/Src/Dlhis.Canteen/Order/Request/BalanceRecordUserPageRequest.cs b/Src/Dlhis.Canteen/Order/Request/BalanceRecordUserPageRequest.cs index 80109baa..32f30543 100644 --- a/Src/Dlhis.Canteen/Order/Request/BalanceRecordUserPageRequest.cs +++ b/Src/Dlhis.Canteen/Order/Request/BalanceRecordUserPageRequest.cs @@ -20,12 +20,9 @@ public class BalanceRecordUserPageRequest : PageDto, IValidatableObject public IEnumerable Validate(ValidationContext validationContext) { - if (SearchDateTimePeriod != null) + if (SearchDateTimePeriod is { End: not null }) { - if (SearchDateTimePeriod.End != null) - { - SearchDateTimePeriod.End = SearchDateTimePeriod.End.Value.AddDays(1).AddSeconds(-1); - } + SearchDateTimePeriod.End = SearchDateTimePeriod.End.Value.AddDays(1).AddSeconds(-1); } yield break; diff --git a/Src/Dlhis.Canteen/Order/Response/BalanceRecordAnalysisDResponse.cs b/Src/Dlhis.Canteen/Order/Response/BalanceRecordAnalysisDResponse.cs new file mode 100644 index 00000000..11666871 --- /dev/null +++ b/Src/Dlhis.Canteen/Order/Response/BalanceRecordAnalysisDResponse.cs @@ -0,0 +1,9 @@ +namespace Dlhis.Canteen.Order.Response; + +public class BalanceRecordAnalysisDResponse +{ + public string No { get; set; } + public string Name { get; set; } + public decimal Amount { get; set; } + public int Count { get; set; } +} \ No newline at end of file diff --git a/Src/Dlhis.Canteen/Order/Response/BalanceRecordAnalysisDepartmentResponse.cs b/Src/Dlhis.Canteen/Order/Response/BalanceRecordAnalysisDepartmentResponse.cs deleted file mode 100644 index 7692aa61..00000000 --- a/Src/Dlhis.Canteen/Order/Response/BalanceRecordAnalysisDepartmentResponse.cs +++ /dev/null @@ -1,5 +0,0 @@ -namespace Dlhis.Canteen.Order.Response; - -public class BalanceRecordAnalysisDepartmentResponse -{ -} \ No newline at end of file diff --git a/Src/Dlhis.Canteen/Order/Services/IBalanceSummaryService.cs b/Src/Dlhis.Canteen/Order/Services/IBalanceSummaryService.cs index ae314b0b..fc35fd02 100644 --- a/Src/Dlhis.Canteen/Order/Services/IBalanceSummaryService.cs +++ b/Src/Dlhis.Canteen/Order/Services/IBalanceSummaryService.cs @@ -9,7 +9,8 @@ public interface IBalanceSummaryService : IScopeDependency { Task BalanceRecordAnalysisAsync(BalanceRecordAnalysisRequest request); - Task> BalanceRecordAnalysisByCostIdAsync(SummaryCommonDto request); + Task> BalanceRecordAnalysisByDepartmentAsync(SummaryCommonDto request); + Task> BalanceRecordAnalysisByCostAsync(SummaryCommonDto request); Task BalanceRecordShiftAnalysisAmountAsync(BalanceRecordAnalysisByShiftRequest request); diff --git a/Src/Dlhis.Canteen/Order/Services/Implements/BalanceSummaryService.cs b/Src/Dlhis.Canteen/Order/Services/Implements/BalanceSummaryService.cs index 3f87efa6..5cbea14f 100644 --- a/Src/Dlhis.Canteen/Order/Services/Implements/BalanceSummaryService.cs +++ b/Src/Dlhis.Canteen/Order/Services/Implements/BalanceSummaryService.cs @@ -3,11 +3,13 @@ using Dlhis.Canteen.Order.Dto; using Dlhis.Canteen.Order.Request; using Dlhis.Canteen.Order.Request.Common; using Dlhis.Canteen.Order.Response; +using Dlhis.Entity.Basic.Entity; using Dlhis.Entity.Canteen.Entities; using Dlhis.Entity.Canteen.Enums; using Kurisu.AspNetCore.CustomClass; using Kurisu.AspNetCore.DataAccess.Dto; using Kurisu.AspNetCore.DataAccess.Extensions; +using Kurisu.AspNetCore.DataAccess.SqlSugar.Extensions; using Kurisu.AspNetCore.DataAccess.SqlSugar.Services; using SqlSugar; @@ -30,7 +32,7 @@ public class BalanceSummaryService : IBalanceSummaryService } var queryable = GetQueryable(request); - var list =await queryable.ToListAsync(); + var list = await queryable.ToListAsync(); var sum = list.Sum(x => Math.Abs(x.Amount)); @@ -61,11 +63,32 @@ public class BalanceSummaryService : IBalanceSummaryService } - public async Task> BalanceRecordAnalysisByCostIdAsync(SummaryCommonDto request) + public async Task> BalanceRecordAnalysisByDepartmentAsync(SummaryCommonDto request) { - // var queryable = GetQueryable(request); + return await GetQueryable(request) + .LeftJoin((x, department) => x.DepartmentNo == department.No) + .GroupBy(x => x.DepartmentNo) + .Select((x, department) => new BalanceRecordAnalysisDResponse + { + No = x.DepartmentNo, + Name = department.Name, + Count = SqlFunc.AggregateDistinctCount(x.UserCode), + Amount = SqlFunc.AggregateSum(SqlFunc.Abs(x.Amount)) + }) + .ToPageListAsync(request); + } - return null; + public async Task> BalanceRecordAnalysisByCostAsync(SummaryCommonDto request) + { + return await GetQueryable(request) + .GroupBy(x => x.CostId) + .Select(x => new BalanceRecordAnalysisDResponse + { + No = x.CostId, + Count = SqlFunc.AggregateDistinctCount(x.UserCode), + Amount = SqlFunc.AggregateSum(SqlFunc.Abs(x.Amount)) + }) + .ToPageListAsync(request); } diff --git a/Src/Dlhis.Canteen/Order/Services/Implements/OrderService.cs b/Src/Dlhis.Canteen/Order/Services/Implements/OrderService.cs index 0fb1f2f9..99c414b1 100644 --- a/Src/Dlhis.Canteen/Order/Services/Implements/OrderService.cs +++ b/Src/Dlhis.Canteen/Order/Services/Implements/OrderService.cs @@ -147,7 +147,7 @@ public class OrderService : BaseOrderService, IOrderService //在线 if (!request.IsOffline) { - gainfo.ThrowIfNull("无法识别,无权消费"); + gainfo.ThrowIfNull("无法识别"); } else { diff --git a/Src/Dlhis.Sys/Identity/Controllers/UsersController.cs b/Src/Dlhis.Sys/Identity/Controllers/UsersController.cs index 119c0983..145236bc 100644 --- a/Src/Dlhis.Sys/Identity/Controllers/UsersController.cs +++ b/Src/Dlhis.Sys/Identity/Controllers/UsersController.cs @@ -68,7 +68,6 @@ public class UsersController : ControllerBase /// /// /// - [Authorize(Roles = "admin")] [HttpPost("create")] public async Task CreateUserAsync(UserCreateRequest request) { From 9b3a4fd0b5b05650ddf08669b0a39deef312dd50 Mon Sep 17 00:00:00 2001 From: liguoyang Date: Fri, 16 Aug 2024 14:45:50 +0800 Subject: [PATCH 21/25] =?UTF-8?q?refactor=20=E4=BC=98=E5=8C=96=E4=BB=A3?= =?UTF-8?q?=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Menu/Controllers/MenusController.cs | 6 +- .../Menu/Services/Implements/MenuService.cs | 58 +++++++++---------- 2 files changed, 29 insertions(+), 35 deletions(-) diff --git a/Src/Dlhis.Sys/Menu/Controllers/MenusController.cs b/Src/Dlhis.Sys/Menu/Controllers/MenusController.cs index 0f32e9ea..1d2dca16 100644 --- a/Src/Dlhis.Sys/Menu/Controllers/MenusController.cs +++ b/Src/Dlhis.Sys/Menu/Controllers/MenusController.cs @@ -30,9 +30,9 @@ public class MenusController : ControllerBase /// 菜单平台类型 PlatformEnumType /// [HttpGet("list")] - public async Task> GetListAsync([EnumDataType(typeof(PlatformEnumType))] PlatformEnumType? platform = PlatformEnumType.PCAdmin) + public async Task> GetListAsync([EnumDataType(typeof(PlatformEnumType))] PlatformEnumType platform = PlatformEnumType.PCAdmin) { - return await _menuService.GetListAsync(platform.Value); + return await _menuService.GetListAsync(platform); } /// @@ -53,7 +53,6 @@ public class MenusController : ControllerBase /// /// /// - [Authorize(Roles = "admin,tenant-admin")] [HttpPost("assign")] public async Task AssignmentAsync(MenuPermissionAssignmentRequest request) { @@ -66,7 +65,6 @@ public class MenusController : ControllerBase /// 权限分配类型 AssignTypeEnumType /// 类型对应的唯一值 /// - [Authorize(Roles = "admin,tenant-admin")] [HttpGet("assignments")] public async Task> GetAssignmentsAsync( [EnumDataType(typeof(AssignTypeEnumType))] AssignTypeEnumType uniqueType, diff --git a/Src/Dlhis.Sys/Menu/Services/Implements/MenuService.cs b/Src/Dlhis.Sys/Menu/Services/Implements/MenuService.cs index 877faa4f..011e3844 100644 --- a/Src/Dlhis.Sys/Menu/Services/Implements/MenuService.cs +++ b/Src/Dlhis.Sys/Menu/Services/Implements/MenuService.cs @@ -143,8 +143,7 @@ public class MenuService : IMenuService if (!allCodes.Any()) { //todo 管理员 - var userId = _currentUser.GetIntSubjectId(); - if (userId == 1) + if (_currentUser.GetName() == "admin") { return await GetListAsync(PlatformEnumType.PCAdmin); } @@ -215,6 +214,8 @@ public class MenuService : IMenuService } } + //****************************************************************** help methods ****************************************************************************** + private static void RecursionGetNext(MenuResponse current, List menus) { @@ -229,30 +230,30 @@ public class MenuService : IMenuService private async Task CheckAsync(SaveMenuRequest request) { //检查重复code - var exists = await _dbContext.Queryable() - .Where(x => x.Code == request.Code) - .WhereIF(request.Id.HasValue, x => x.Id != request.Id).AnyAsync(); - exists.ThrowIfTrue($"{request.Title}存在重复code"); + (await _dbContext.Queryable() + .Where(x => x.Code == request.Code) + .WhereIF(request.Id.HasValue, x => x.Id != request.Id).AnyAsync()) + .ThrowIfTrue($"{request.Title}存在重复code"); //检查name - exists = await _dbContext.Queryable() - .Where(x => x.Name == request.Name) - .WhereIF(request.Id.HasValue, x => x.Id != request.Id).AnyAsync(); - exists.ThrowIfTrue($"{request.Title}存在重复name"); + (await _dbContext.Queryable() + .Where(x => x.Name == request.Name) + .WhereIF(request.Id.HasValue, x => x.Id != request.Id).AnyAsync()) + .ThrowIfTrue($"{request.Title}存在重复name"); + //判断权限重复 if (request.Permission.IsPresent()) { - exists = await _dbContext.Queryable() - .Where(x => x.Permission == request.Permission && (request.MenuType == MenuEnumType.Menu || request.MenuType == MenuEnumType.Button)) - .WhereIF(request.Id.HasValue, x => x.Id != request.Id).AnyAsync(); - exists.ThrowIfTrue($"{request.Title}存在重复权限标识"); + (await _dbContext.Queryable() + .Where(x => x.Permission == request.Permission && (request.MenuType == MenuEnumType.Menu || request.MenuType == MenuEnumType.Button)) + .WhereIF(request.Id.HasValue, x => x.Id != request.Id) + .AnyAsync()) + .ThrowIfTrue($"{request.Title}存在重复权限标识"); } //request.PCode - var menu = await _dbContext.Queryable().Where(x => x.Code == request.PCode).FirstAsync(); - (menu == null && request.MenuType != MenuEnumType.Folder).ThrowIfTrue($"{request.Title}上级不存在"); - + var pMenu = await _dbContext.Queryable().Where(x => x.Code == request.PCode).SingleAsync(); if (request.MenuType == MenuEnumType.Folder) { //request.PCode = null; @@ -263,18 +264,13 @@ public class MenuService : IMenuService } else if (request.MenuType == MenuEnumType.Menu) { - if (menu.MenuType != MenuEnumType.Folder) - { - throw new Exception($"{request.Title}菜单上级需要为目录"); - } + pMenu.ThrowIfNull($"{request.Title}的上级菜单不存在"); + (pMenu.MenuType != MenuEnumType.Folder).ThrowIfTrue($"{request.Title}菜单上级需要为目录"); } - else + else if (request.MenuType == MenuEnumType.Button) { - //button - if (menu.MenuType != MenuEnumType.Menu) - { - throw new Exception($"{request.Title}按钮上级需要为菜单"); - } + pMenu.ThrowIfNull($"{request.Title}的上级菜单不存在"); + (pMenu.MenuType != MenuEnumType.Menu).ThrowIfTrue($"{request.Title}按钮上级需要为菜单"); } } @@ -292,17 +288,17 @@ public class MenuService : IMenuService } - private async Task ChangeIfCodeEditAsync(string beforeCode, string pcode) + private async Task ChangeIfCodeEditAsync(string beforeCode, string pCode) { - if (beforeCode != pcode) + if (beforeCode != pCode) { //修改下级的PCode为当前的code var menus = await _dbContext.Queryable().Where(x => x.PCode == beforeCode).ToListAsync(); - menus.ForEach(x => { x.PCode = pcode; }); + menus.ForEach(x => { x.PCode = pCode; }); //修改权限code为当前的code,避免权限丢失 var permissions = await _dbContext.Queryable().Where(x => x.Code == beforeCode).ToListAsync(); - permissions.ForEach(x => { x.Code = pcode; }); + permissions.ForEach(x => { x.Code = pCode; }); await _dbContext.UpdateAsync(menus); await _dbContext.UpdateAsync(permissions); From d72fc4a7b17426fcf860b046cf81a537824aa508 Mon Sep 17 00:00:00 2001 From: liguoyang Date: Fri, 16 Aug 2024 14:46:14 +0800 Subject: [PATCH 22/25] =?UTF-8?q?feat=20=E7=94=A8=E6=88=B7=E9=9B=86?= =?UTF-8?q?=E5=9B=A2=E6=B6=88=E8=B4=B9=E6=95=B0=E6=8D=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Order/Controllers/BalancesController.cs | 12 ++++++++ .../BalanceRecordUserGroupPageRequest.cs | 30 +++++++++++++++++++ .../Order/Services/IBalanceService.cs | 4 +++ .../Services/Implements/BalanceService.cs | 25 ++++++++++++++++ 4 files changed, 71 insertions(+) create mode 100644 Src/Dlhis.Canteen/Order/Request/BalanceRecordUserGroupPageRequest.cs diff --git a/Src/Dlhis.Canteen/Order/Controllers/BalancesController.cs b/Src/Dlhis.Canteen/Order/Controllers/BalancesController.cs index 0e28e4db..1f26795a 100644 --- a/Src/Dlhis.Canteen/Order/Controllers/BalancesController.cs +++ b/Src/Dlhis.Canteen/Order/Controllers/BalancesController.cs @@ -111,6 +111,18 @@ public class BalancesController : ControllerBase return await _balanceService.GetPageByUserAsync(request); } + /// + /// 用户集团消费记录 + /// + /// + /// + [HttpGet("user/group/page")] + [IgnoreTenant] + public async Task> GetUserBalanceGroupAsync(BalanceRecordUserGroupPageRequest request) + { + return await _balanceService.GetUserBalanceGroupAsync(request); + } + /// /// 获取消费机总数、离线设备数量、营业点数量、可消费人数、人均日消费额 /// diff --git a/Src/Dlhis.Canteen/Order/Request/BalanceRecordUserGroupPageRequest.cs b/Src/Dlhis.Canteen/Order/Request/BalanceRecordUserGroupPageRequest.cs new file mode 100644 index 00000000..30f332cb --- /dev/null +++ b/Src/Dlhis.Canteen/Order/Request/BalanceRecordUserGroupPageRequest.cs @@ -0,0 +1,30 @@ +using System.ComponentModel.DataAnnotations; +using Kurisu.AspNetCore.CustomClass; +using Kurisu.AspNetCore.DataAccess.Dto; + +namespace Dlhis.Canteen.Order.Request; + +public class BalanceRecordUserGroupPageRequest : PageDto, IValidatableObject +{ + /// + /// 日期范围查询 + /// + public DateTimePeriod SearchDateTimePeriod { get; set; } + + /// + /// 工号 + /// + [Required(ErrorMessage = "工号不可为空")] + public string UserCode { get; set; } + + + public IEnumerable Validate(ValidationContext validationContext) + { + if (SearchDateTimePeriod is { End: not null }) + { + SearchDateTimePeriod.End = SearchDateTimePeriod.End.Value.AddDays(1).AddSeconds(-1); + } + + yield break; + } +} \ No newline at end of file diff --git a/Src/Dlhis.Canteen/Order/Services/IBalanceService.cs b/Src/Dlhis.Canteen/Order/Services/IBalanceService.cs index 32dea145..b40fb39f 100644 --- a/Src/Dlhis.Canteen/Order/Services/IBalanceService.cs +++ b/Src/Dlhis.Canteen/Order/Services/IBalanceService.cs @@ -12,6 +12,10 @@ public interface IBalanceService : IScopeDependency Task GetPageByUserAsync(BalanceRecordUserPageRequest request); + + Task> GetUserBalanceGroupAsync(BalanceRecordUserGroupPageRequest request); + + Task SupplementBalanceAsync(BalanceSupplementRequest request); /// diff --git a/Src/Dlhis.Canteen/Order/Services/Implements/BalanceService.cs b/Src/Dlhis.Canteen/Order/Services/Implements/BalanceService.cs index 57b8d488..8c6fedcc 100644 --- a/Src/Dlhis.Canteen/Order/Services/Implements/BalanceService.cs +++ b/Src/Dlhis.Canteen/Order/Services/Implements/BalanceService.cs @@ -382,6 +382,31 @@ public class BalanceService : IBalanceService }; } + public async Task> GetUserBalanceGroupAsync(BalanceRecordUserGroupPageRequest request) + { + return await _dbContext.Queryable() + .LeftJoin((record, ga) => record.UserNo == ga.No) + .LeftJoin((record, ga, department) => ga.DepartmentNo == department.No) + .LeftJoin((record, ga, department, bPlace) => record.BusinessPlaceCode == bPlace.Code) + .Where((record, ga) => record.UserCode == request.UserCode) + .Where(record => record.Status == BalanceRecordStatusEnumType.Valid && record.Type == BalanceRecordTypeEnumType.Out) + .Where(record => record.Source != BalanceRecordSourceEnumType.EMealVoucher) //不展示电子餐券信息 + .WhereIF(request.SearchDateTimePeriod.HasValue(), record => record.CostDate >= request.SearchDateTimePeriod.Start && record.CostDate <= request.SearchDateTimePeriod.End) + .OrderBy(record => record.CostDateTime) + .Select((record, ga, department, bPlace) => new BalanceRecordUserPageResponse + { + Id = record.Id, + CurrentAmount = SqlFunc.Abs(record.Amount), + Source = record.Source, + No = record.No, + BusinessPlaceName = bPlace.Name, + ShiftType = record.ShiftType, + CostDateTime = record.CostDateTime, + ApplicationType = record.ApplicationType, + }) + .ToPageListAsync(request); + } + public async Task GetConsumeNumberAsync() { From 8fc4464a4103f1a51f7f8544890cec84fe4fa9a2 Mon Sep 17 00:00:00 2001 From: liguoyang Date: Fri, 16 Aug 2024 14:48:26 +0800 Subject: [PATCH 23/25] =?UTF-8?q?fix=20=E5=A4=84=E7=90=86=E8=AE=BE?= =?UTF-8?q?=E5=A4=87=E5=88=86=E7=BB=84=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../DataPermissions/GetDataPermissionService.cs | 17 +++++++++++------ .../Services/Implements/DeviceGroupService.cs | 6 +++--- .../DeviceCodeAttribute.cs | 2 +- .../DeviceGroupCodeAttribute.cs | 2 +- Src/Dlhis.Entity/Basic/Entity/DeviceEntity.cs | 2 +- 5 files changed, 17 insertions(+), 12 deletions(-) diff --git a/Src/Dlhis.Basic/DataPermissions/GetDataPermissionService.cs b/Src/Dlhis.Basic/DataPermissions/GetDataPermissionService.cs index a7895af3..10ee320c 100644 --- a/Src/Dlhis.Basic/DataPermissions/GetDataPermissionService.cs +++ b/Src/Dlhis.Basic/DataPermissions/GetDataPermissionService.cs @@ -1,3 +1,4 @@ +using Dlhis.DataPermission.Model; using Dlhis.Entity.Basic.Entity; using Dlhis.Entity.Device.Entities; using Dlhis.Entity.Sys.Entities; @@ -52,19 +53,23 @@ public class GetDataPermissionService : IGetDataPermissions, ISingletonDependenc //先计算分组权限下的设备 var deviceGroupCodes = userDataPermissions.Where(x => x.UniqueType == DeviceAssignmentTypeEnumType.Group).Select(x => x.UniqueValue).ToList(); - if (deviceGroupCodes.Any() && deviceCodeProperty != null) + if (deviceGroupCodes.Any()) { var data = db.Queryable().ToList(); //开始递归处理 var tops = data.Where(x => !x.PCode.HasValue).ToList(); tops.ForEach(x => { DeviceGroupRecursionGetNext(x, data, deviceGroupCodes, deviceGroupCodes.Contains(x.Code)); }); deviceGroupCodes = deviceGroupCodes.Distinct().ToList(); - deviceCodes = db.Queryable().Where(x => deviceGroupCodes.Contains(x.GroupCode)).Select(x => x.DeviceCode).ToList(); - } - if (deviceGroupCodeProperty != null && deviceGroupCodes.Any()) - { - dict.Add(deviceGroupCodeProperty.Name, deviceGroupCodes); + if (deviceCodeProperty != null) + { + deviceCodes = db.Queryable().Where(x => deviceGroupCodes.Contains(x.GroupCode)).Select(x => x.DeviceCode).ToList(); + } + + if (deviceGroupCodeProperty != null) + { + dict.Add(deviceGroupCodeProperty.Name, deviceGroupCodes); + } } if (deviceCodeProperty != null) diff --git a/Src/Dlhis.Basic/Device/Services/Implements/DeviceGroupService.cs b/Src/Dlhis.Basic/Device/Services/Implements/DeviceGroupService.cs index 813c5839..a18aa97e 100644 --- a/Src/Dlhis.Basic/Device/Services/Implements/DeviceGroupService.cs +++ b/Src/Dlhis.Basic/Device/Services/Implements/DeviceGroupService.cs @@ -43,11 +43,12 @@ public class DeviceGroupService : IDeviceGroupService .Select() .ToListAsync(); - var others = await _dbContext.Queryable() + var others = await _dbContext.Client.Queryable() .Where(x => x.Type == type) .Where(x => x.Name == "*共用区域" || x.Name == "*非共用区域" || x.Name == "*通用考勤设备组" || x.Name == "*专用考勤设备组") .Select() .ToListAsync(); + deviceGroups.AddRange(others); var tops = deviceGroups.Where(x => !x.PCode.HasValue).ToList(); @@ -167,7 +168,7 @@ public class DeviceGroupService : IDeviceGroupService /// /// /// - private async Task CheckPCodeAsync(DeviceGroupSaveRequest request) + private async Task CheckPCodeAsync(DeviceGroupSaveRequest request) { var pGrp = await _dbContext.Queryable().Where(x => x.Code == request.PCode).FirstAsync(); if (pGrp != null) @@ -178,7 +179,6 @@ public class DeviceGroupService : IDeviceGroupService } (pGrp != null && pGrp.Type != request.Type).ThrowIfTrue("分组类型必须与上级类型保持一致"); - return pGrp; } /// diff --git a/Src/Dlhis.DataPermission.Model/DeviceCodeAttribute.cs b/Src/Dlhis.DataPermission.Model/DeviceCodeAttribute.cs index 764d995b..a243b0b2 100644 --- a/Src/Dlhis.DataPermission.Model/DeviceCodeAttribute.cs +++ b/Src/Dlhis.DataPermission.Model/DeviceCodeAttribute.cs @@ -1,6 +1,6 @@ using Kurisu.AspNetCore.DataAccess.SqlSugar.Attributes; -namespace Dlhis.Basic.DataPermissions; +namespace Dlhis.DataPermission.Model; [AttributeUsage(AttributeTargets.Property)] public class DeviceCodeAttribute : BaseDataPermissionAttribute diff --git a/Src/Dlhis.DataPermission.Model/DeviceGroupCodeAttribute.cs b/Src/Dlhis.DataPermission.Model/DeviceGroupCodeAttribute.cs index 3f232bc4..90705a34 100644 --- a/Src/Dlhis.DataPermission.Model/DeviceGroupCodeAttribute.cs +++ b/Src/Dlhis.DataPermission.Model/DeviceGroupCodeAttribute.cs @@ -1,6 +1,6 @@ using Kurisu.AspNetCore.DataAccess.SqlSugar.Attributes; -namespace Dlhis.Basic.DataPermissions; +namespace Dlhis.DataPermission.Model; [AttributeUsage(AttributeTargets.Property)] public class DeviceGroupCodeAttribute : BaseDataPermissionAttribute diff --git a/Src/Dlhis.Entity/Basic/Entity/DeviceEntity.cs b/Src/Dlhis.Entity/Basic/Entity/DeviceEntity.cs index a1d431a3..44bde49a 100644 --- a/Src/Dlhis.Entity/Basic/Entity/DeviceEntity.cs +++ b/Src/Dlhis.Entity/Basic/Entity/DeviceEntity.cs @@ -1,4 +1,4 @@ -using Dlhis.Basic.DataPermissions; +using Dlhis.DataPermission.Model; using Dlhis.Entity.Device.Enums; using Kurisu.AspNetCore.DataAccess.Entity; using Kurisu.AspNetCore.DataAccess.SqlSugar; From ad47b675b1d63ccfa2d599e239c638c1cffed6f1 Mon Sep 17 00:00:00 2001 From: liguoyang Date: Fri, 16 Aug 2024 15:58:11 +0800 Subject: [PATCH 24/25] =?UTF-8?q?feat=20=E6=9F=A5=E8=AF=A2=E6=A1=A3?= =?UTF-8?q?=E6=A1=88=E4=BA=BA=E5=91=98=E6=89=80=E5=9C=A8=E7=9A=84=E4=BA=BA?= =?UTF-8?q?=E5=91=98=E5=88=86=E7=BB=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Controllers/GainfoGroupsController.cs | 13 ++++++++++- .../Services/IGainfoGroupService.cs | 2 ++ .../Services/Implements/GainfoGroupService.cs | 23 +++++++++++++++++++ 3 files changed, 37 insertions(+), 1 deletion(-) diff --git a/Src/Dlhis.Basic/Organization/Controllers/GainfoGroupsController.cs b/Src/Dlhis.Basic/Organization/Controllers/GainfoGroupsController.cs index ddcf6acc..1df53980 100644 --- a/Src/Dlhis.Basic/Organization/Controllers/GainfoGroupsController.cs +++ b/Src/Dlhis.Basic/Organization/Controllers/GainfoGroupsController.cs @@ -56,6 +56,17 @@ public class GainfoGroupsController : ControllerBase return await _gainfoGroupService.GetGainfosByGroupAsync(code); } + /// + /// 根据userCode获取分配的分组 + /// + /// + /// + [HttpGet("groups")] + public async Task> GetGainfoGroupsByUserCodeAsync(string userCode) + { + return await _gainfoGroupService.GetGainfoGroupsByUserCodeAsync(userCode); + } + /// /// 分配人员 /// @@ -69,4 +80,4 @@ public class GainfoGroupsController : ControllerBase { await _gainfoGroupService.AssignGainfosAsync(request); } -} +} \ No newline at end of file diff --git a/Src/Dlhis.Basic/Organization/Services/IGainfoGroupService.cs b/Src/Dlhis.Basic/Organization/Services/IGainfoGroupService.cs index d9b2801e..258089ec 100644 --- a/Src/Dlhis.Basic/Organization/Services/IGainfoGroupService.cs +++ b/Src/Dlhis.Basic/Organization/Services/IGainfoGroupService.cs @@ -12,4 +12,6 @@ public interface IGainfoGroupService : IScopeDependency Task> GetGainfosByGroupAsync(Guid code); Task AssignGainfosAsync(GainfoAssignRequest request); + + Task> GetGainfoGroupsByUserCodeAsync(string userCode); } diff --git a/Src/Dlhis.Basic/Organization/Services/Implements/GainfoGroupService.cs b/Src/Dlhis.Basic/Organization/Services/Implements/GainfoGroupService.cs index d6429595..f9f0e50b 100644 --- a/Src/Dlhis.Basic/Organization/Services/Implements/GainfoGroupService.cs +++ b/Src/Dlhis.Basic/Organization/Services/Implements/GainfoGroupService.cs @@ -101,6 +101,29 @@ public class GainfoGroupService : IGainfoGroupService }, null); } + + public async Task> GetGainfoGroupsByUserCodeAsync(string userCode) + { + var gainfo = await _dbContext.Queryable().Where(x => x.Code == userCode).SingleAsync(); + var userNo = gainfo?.No; + + return await _dbContext.Queryable() + .LeftJoin((x, r) => x.Code == r.GroupCode) + .Where((x, r) => r.UserNo == userNo) + .Select(x => new GainfoGroupTreeResponse + { + Id = x.Id, + PCode = x.PCode, + Code = x.Code, + Name = x.Name, + Remark = x.Remark, + Editable = x.Editable, + IsDefault = x.IsDefault, + TenantId = x.TenantId + }) + .ToListAsync(); + } + //******************************************************* help methods *********************************************************** /// From 81fede87643ae0f609bfeb00b2d38cd7593a0a9a Mon Sep 17 00:00:00 2001 From: liguoyang Date: Fri, 16 Aug 2024 15:58:25 +0800 Subject: [PATCH 25/25] =?UTF-8?q?fix=20=E6=9F=A5=E8=AF=A2=E4=BC=98?= =?UTF-8?q?=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Controllers/DeviceTaskAssignmentsController.cs | 2 +- .../Services/Implements/DeviceTaskAssignmentService.cs | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Src/Dlhis.ScheduledTask/TaskAssignment/Controllers/DeviceTaskAssignmentsController.cs b/Src/Dlhis.ScheduledTask/TaskAssignment/Controllers/DeviceTaskAssignmentsController.cs index 1a558741..bb56508b 100644 --- a/Src/Dlhis.ScheduledTask/TaskAssignment/Controllers/DeviceTaskAssignmentsController.cs +++ b/Src/Dlhis.ScheduledTask/TaskAssignment/Controllers/DeviceTaskAssignmentsController.cs @@ -29,7 +29,7 @@ public class DeviceTaskAssignmentsController : ControllerBase /// /// [HttpGet("page")] - [CrossTenant] + [IgnoreTenant] public async Task> GetPageAsync([FromQuery] DeviceTaskAssignmentRequest request) { return await _deviceTaskAssignmentService.GetPageAsync(request); diff --git a/Src/Dlhis.ScheduledTask/TaskAssignment/Services/Implements/DeviceTaskAssignmentService.cs b/Src/Dlhis.ScheduledTask/TaskAssignment/Services/Implements/DeviceTaskAssignmentService.cs index cf27a6c8..d410e4a1 100644 --- a/Src/Dlhis.ScheduledTask/TaskAssignment/Services/Implements/DeviceTaskAssignmentService.cs +++ b/Src/Dlhis.ScheduledTask/TaskAssignment/Services/Implements/DeviceTaskAssignmentService.cs @@ -4,6 +4,7 @@ using Dlhis.Entity.Device.Enums; using Dlhis.ScheduledTask.TaskAssignment.Request; using Dlhis.ScheduledTask.TaskAssignment.Response; using Dlhis.Sys.Api; +using Kurisu.AspNetCore.CustomClass; using Kurisu.AspNetCore.DataAccess.Dto; using Kurisu.AspNetCore.DataAccess.SqlSugar.Extensions; using Kurisu.AspNetCore.DataAccess.SqlSugar.Services; @@ -29,12 +30,11 @@ public class DeviceTaskAssignmentService : IDeviceTaskAssignmentService .LeftJoin((deviceTask, device) => deviceTask.DeviceUniqueNo == device.UniqueNo) .LeftJoin((deviceTask, device, ga) => deviceTask.UserNo == ga.No) .LeftJoin((deviceTask, device, ga, gaLeave) => deviceTask.UserNo == gaLeave.No) - .LeftJoin((deviceTask, device, ga, gaLeave, gaEx) => deviceTask.UserNo == gaEx.No) + .LeftJoin((deviceTask, device, ga, gaLeave, gaEx) => deviceTask.UserNo == gaEx.No) .LeftJoin((deviceTask, device, ga, gaLeave, gaEx, deviceRegistry) => deviceRegistry.DeviceUniqueNo == deviceTask.DeviceUniqueNo) .Where(deviceTask => deviceTask.TenantId == request.Factory) .WhereIF(request.Type.HasValue, deviceTask => deviceTask.DeviceType == request.Type) - .WhereIF(request.SearchDateTimePeriod?.Start.HasValue == true && request.SearchDateTimePeriod?.End.HasValue == true, - deviceTask => deviceTask.ModifiedTime >= request.SearchDateTimePeriod.Start && deviceTask.ModifiedTime <= request.SearchDateTimePeriod.End + .WhereIF(request.SearchDateTimePeriod.HasValue(), deviceTask => deviceTask.ModifiedTime >= request.SearchDateTimePeriod.Start && deviceTask.ModifiedTime <= request.SearchDateTimePeriod.End ) .WhereIF(request.TaskTypes.IsPresent(), deviceTask => request.TaskTypes.Contains(deviceTask.Type)) .WhereIF(request.Status.IsPresent(), deviceTask => request.Status.Contains(deviceTask.Status)) @@ -45,10 +45,10 @@ public class DeviceTaskAssignmentService : IDeviceTaskAssignmentService || deviceTask.DeviceUniqueNo == request.Search ) .WhereIF(request.IsOffline.HasValue && request.IsOffline.Value, (deviceTask, device, ga, gaLeave, gaEx, deviceRegistry) => - SqlFunc.DateAdd(deviceRegistry.LastHeartbeatTime, device.HeartbeatInterval, DateType.Second) < DateTime.Now) + device.HeartbeatInterval != 0 && SqlFunc.DateAdd(deviceRegistry.LastHeartbeatTime, device.HeartbeatInterval, DateType.Second) < DateTime.Now) .WhereIF(request.IsOffline.HasValue && !request.IsOffline.Value, (deviceTask, device, ga, gaLeave, gaEx, deviceRegistry) => device.HeartbeatInterval == 0 || SqlFunc.DateAdd(deviceRegistry.LastHeartbeatTime, device.HeartbeatInterval, DateType.Second) >= DateTime.Now) - .OrderBy(deviceTask => deviceTask.CreateTime, OrderByType.Desc) + .OrderBy(deviceTask => deviceTask.ModifiedTime, OrderByType.Desc) .Select((deviceTask, device, ga, gaLeave, gaEx, deviceRegistry) => new DeviceTaskAssignmentResponse { Id = deviceTask.Id,