fix 并发执行问题,保密人员余额迁移

This commit is contained in:
2024-06-04 21:38:12 +08:00
parent 9af6472be6
commit 582393e45d
31 changed files with 400 additions and 274 deletions

View File

@@ -30,7 +30,10 @@
</ItemGroup>
<ItemGroup>
<Folder Include="MealUser\Controllers\" />
<Folder Include="MealUser\Request\" />
<Folder Include="MealUser\Response\" />
<Folder Include="MealUser\Services\Implements\" />
<Folder Include="Summary\Request\" />
</ItemGroup>

View File

@@ -1,5 +1,5 @@
using Dlhis.Basic.MealUser.Response;
using Dlhis.Basic.MealUser.Services;
using Dlhis.Basic.Organization.Response;
using Dlhis.Basic.Organization.Services;
using Kurisu.AspNetCore.DataAccess.Dto;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;

View File

@@ -1,9 +0,0 @@
using Dlhis.Basic.MealUser.Response;
using Kurisu.AspNetCore.DataAccess.Dto;
namespace Dlhis.Basic.MealUser.Services;
public interface IMealUserService : IScopeDependency
{
Task<Pagination<MealUserResponse>> GetPageAsync(PageDto request);
}

View File

@@ -1,45 +0,0 @@
using Dlhis.Basic.MealUser.Response;
using Dlhis.Entity.Basic.Entity;
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;
namespace Dlhis.Basic.MealUser.Services.Implements;
public class MealUserService : IMealUserService
{
private readonly IDbContext _dbContext;
private readonly ICurrentUser _currentUser;
public MealUserService(IDbContext dbContext, ICurrentUser currentUser)
{
_dbContext = dbContext;
_currentUser = currentUser;
}
public async Task<Pagination<MealUserResponse>> GetPageAsync(PageDto request)
{
var tenantId = _currentUser.GetStringTenantId();
var page = await _dbContext.Queryable<GainfoEntity>()
.LeftJoin<GainfoMealEntity>((x, meal) => x.Code == meal.UserCode)
.LeftJoin<DepartmentEntity>((x, meal, dept) => dept.No == x.DepartmentNo)
.WhereIF(request.Search.IsPresent(), (x, meal) => x.Code == request.Search || x.Name == request.Search)
.Where(x => x.Factory == tenantId)
.Select((x, meal, dept) => new MealUserResponse
{
Balance = meal.Balance,
BalanceOfRecharge = meal.BalanceOfRecharge,
BalanceOfSubsidies = meal.BalanceOfSubsidies,
UserCode = x.Code,
UserName = x.Name,
UserNo = x.No,
DepartmentName = dept.Name,
})
.ToPageListAsync(request);
return page;
}
}

View File

@@ -0,0 +1,45 @@
using Dlhis.Basic.Organization.Request;
using Dlhis.Basic.Organization.Response;
using Dlhis.Basic.Organization.Services;
using Kurisu.AspNetCore.DataAccess.Dto;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
namespace Dlhis.Basic.Organization.Controllers;
/// <summary>
/// 就餐人员
/// </summary>
[Authorize]
[Route("api/[controller]")]
[ApiController]
public class GainfoMealController : ControllerBase
{
private readonly IMealUserService _mealUserService;
public GainfoMealController(IMealUserService mealUserService)
{
_mealUserService = mealUserService;
}
/// <summary>
/// 就餐人员分页
/// </summary>
/// <param name="request"></param>
/// <returns></returns>
[HttpGet("page")]
public async Task<Pagination<MealUserResponse>> GetPageAsync([FromQuery] PageDto request)
{
return await _mealUserService.GetPageAsync(request);
}
/// <summary>
/// 迁移
/// </summary>
/// <param name="request"></param>
[HttpPost("migration")]
public async Task MigrationAsync(GainfoBalanceMigrationRequest request)
{
await _mealUserService.MigrationAsync(request);
}
}

View File

@@ -0,0 +1,12 @@
using System.ComponentModel.DataAnnotations;
namespace Dlhis.Basic.Organization.Request;
public class GainfoBalanceMigrationRequest
{
[Required]
public string BeforeCode { get; set; }
[Required]
public string NowCode { get; set; }
}

View File

@@ -1,4 +1,4 @@
namespace Dlhis.Basic.MealUser.Response;
namespace Dlhis.Basic.Organization.Response;
public class MealUserResponse
{

View File

@@ -0,0 +1,12 @@
using Dlhis.Basic.Organization.Request;
using Dlhis.Basic.Organization.Response;
using Kurisu.AspNetCore.DataAccess.Dto;
namespace Dlhis.Basic.Organization.Services;
public interface IMealUserService : IScopeDependency
{
Task<Pagination<MealUserResponse>> GetPageAsync(PageDto request);
Task MigrationAsync(GainfoBalanceMigrationRequest request);
}

View File

@@ -0,0 +1,113 @@
using Dlhis.Basic.Organization.Request;
using Dlhis.Basic.Organization.Response;
using Dlhis.Entity.Basic.Entity;
using Dlhis.Entity.Canteen.Entities;
using Dlhis.Entity.Canteen.Enums;
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;
using Kurisu.AspNetCore.Utils.Extensions;
namespace Dlhis.Basic.Organization.Services.Implements;
public class MealUserService : IMealUserService
{
private readonly IDbContext _dbContext;
private readonly ICurrentUser _currentUser;
public MealUserService(IDbContext dbContext, ICurrentUser currentUser)
{
_dbContext = dbContext;
_currentUser = currentUser;
}
public async Task<Pagination<MealUserResponse>> GetPageAsync(PageDto request)
{
var tenantId = _currentUser.GetStringTenantId();
var page = await _dbContext.Queryable<GainfoEntity>()
.LeftJoin<GainfoMealEntity>((x, meal) => x.Code == meal.UserCode)
.LeftJoin<DepartmentEntity>((x, meal, dept) => dept.No == x.DepartmentNo)
.WhereIF(request.Search.IsPresent(), (x, meal) => x.Code == request.Search || x.Name == request.Search)
.Where(x => x.Factory == tenantId)
.Select((x, meal, dept) => new MealUserResponse
{
Balance = meal.Balance,
BalanceOfRecharge = meal.BalanceOfRecharge,
BalanceOfSubsidies = meal.BalanceOfSubsidies,
UserCode = x.Code,
UserName = x.Name,
UserNo = x.No,
DepartmentName = dept.Name,
})
.ToPageListAsync(request);
return page;
}
/// <inheritdoc />
public async Task MigrationAsync(GainfoBalanceMigrationRequest request)
{
var gainfoLeave = await _dbContext.Queryable<GainfoLeaveEntity>().Where(x => x.Code == request.BeforeCode).SingleAsync();
gainfoLeave.ThrowIfNull("需要对已离职人员迁移");
var beforeBalance = await _dbContext.Queryable<GainfoMealEntity>().Where(x => x.UserCode == request.BeforeCode).Select(x => x.Balance).SingleAsync();
if (beforeBalance == 0)
{
return;
}
var gainfo = await _dbContext.Queryable<GainfoEntity>().Where(x => x.Code == request.NowCode).SingleAsync();
gainfo.ThrowIfNull("目标人员不存在");
//清空余额
await _dbContext.Updateable<GainfoMealEntity>()
.SetColumns(x => x.Balance == 0)
.SetColumns(x => x.ModifiedTime == DateTime.Now)
.SetColumns(x => x.Version == x.Version + 1)
.Where(x => x.UserCode == request.BeforeCode) //不需要判断version
.ExecuteCommandAsync();
var now = DateTime.Now;
await _dbContext.InsertAsync(new BalanceRecordEntity
{
No = SnowFlakeHelper.Instance.NextId().ToString(),
UserNo = gainfo.No,
Name = gainfo.Name,
UserCode = gainfo.Code,
DepartmentNo = gainfo.DepartmentNo,
Source = BalanceRecordSourceEnumType.BalanceMigration,
Type = BalanceRecordTypeEnumType.In,
Amount = beforeBalance,
BusinessPlaceCode = null,
BusinessShiftCode = null,
ShiftType = null,
CostDate = now.Date,
DeviceUniqueNo = null,
SubsidiesFromMonth = now.ToString("yyyyMM"),
IP = null,
CostId = gainfo.CostId,
OriginTenantId = gainfo.Factory,
IsCostCrossTenant = false,
Status = BalanceRecordStatusEnumType.Valid,
CostDateTime = DateTime.Now,
Remark = $"{gainfoLeave.Code}:余额转入",
ApplicationType = CanteenApplicaitonTypeEnumType.MealSupplement,
TenantId = gainfo.Factory,
Werks = gainfo.Werks,
IsDeleted = false,
});
var nowGainfoMeal = await _dbContext.Queryable<GainfoMealEntity>().Where(x => x.UserCode == request.NowCode).SingleAsync();
var nowBalance = nowGainfoMeal.Balance + beforeBalance;
await _dbContext.Updateable<GainfoMealEntity>()
.SetColumns(x => x.Balance == nowBalance)
.SetColumns(x => x.ModifiedTime == DateTime.Now)
.SetColumns(x => x.Version == x.Version + 1)
.Where(x => x.UserCode == request.NowCode && x.Version == nowGainfoMeal.Version)
.ExecuteCommandThrowVersionAsync("转入失败");
}
}

View File

@@ -1,5 +1,4 @@
using Dlhis.Canteen.Dishes.Request;
using Dlhis.Canteen.Order.Request;
using Dlhis.Canteen.Order.Request;
using Dlhis.Canteen.Order.Response;
using Dlhis.Canteen.Order.Services;
using Kurisu.AspNetCore.DataAccess.Dto;

View File

@@ -50,16 +50,11 @@ public class OrderAddRequest : IValidatableObject
//处理金额
Amount = -Math.Abs(Amount);
if (!CostDateTime.HasValue)
{
CostDateTime = DateTime.Now;
}
CostDateTime ??= DateTime.Now;
if (DeviceUniqueNo.IsEmpty())
{
yield return new ValidationResult("设备号不能为空", new[] { nameof(DeviceUniqueNo) });
}
yield break;
}
}

View File

@@ -43,46 +43,46 @@ public class BalanceService : IBalanceService
public async Task<Pagination<BalanceRecordResponse>> GetPageAsync(BalanceRecordPageRequest request)
{
var page = await _dbContext.Queryable<BalanceRecordEntity>()
.LeftJoin<GainfoEntity>((record, ga) => record.UserNo == ga.No)
.LeftJoin<DepartmentEntity>((record, ga, department) => ga.DepartmentNo == department.No)
.LeftJoin<BusinessPlaceEntity>((record, ga, department, bplace) => record.BusinessPlaceCode == bplace.Code)
.LeftJoin<CanteenOrderEntity>((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.Name == request.Search
.LeftJoin<GainfoEntity>((record, ga) => record.UserNo == ga.No)
.LeftJoin<DepartmentEntity>((record, ga, department) => ga.DepartmentNo == department.No)
.LeftJoin<BusinessPlaceEntity>((record, ga, department, bplace) => record.BusinessPlaceCode == bplace.Code)
.LeftJoin<CanteenOrderEntity>((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.Name == request.Search
|| ga.Code == request.Search
)
.OrderBy(record => record.CreateTime, OrderByType.Desc)
.Select((record, ga, department, bplace, order) => new BalanceRecordResponse
{
Id = record.Id,
No = record.No,
IsOffline = order.IsOffline,
Amount = SqlFunc.Abs(record.Amount),
CostDate = record.CostDate,
CostId = record.CostId,
DepartmentNo = record.DepartmentNo,
DeviceInfo = record.DeviceUniqueNo,
UserNo = record.UserNo,
UserCode = record.UserCode,
Type = record.Type,
Status = record.Status,
Source = record.Source,
OriginTenantId = record.OriginTenantId,
Name = record.Name,
DepartmentName = department.Name,
BusinessPlaceName = bplace.Name,
CostDateTime = record.CostDateTime,
Factory = record.TenantId,
ShiftType = record.ShiftType,
Remark = record.Remark,
Werks = ga.Werks
})
.ToPageListAsync(request);
)
.OrderBy(record => record.CreateTime, OrderByType.Desc)
.Select((record, ga, department, bplace, order) => new BalanceRecordResponse
{
Id = record.Id,
No = record.No,
IsOffline = order.IsOffline,
Amount = SqlFunc.Abs(record.Amount),
CostDate = record.CostDate,
CostId = record.CostId,
DepartmentNo = record.DepartmentNo,
DeviceInfo = record.DeviceUniqueNo,
UserNo = record.UserNo,
UserCode = record.UserCode,
Type = record.Type,
Status = record.Status,
Source = record.Source,
OriginTenantId = record.OriginTenantId,
Name = record.Name,
DepartmentName = department.Name,
BusinessPlaceName = bplace.Name,
CostDateTime = record.CostDateTime,
Factory = record.TenantId,
ShiftType = record.ShiftType,
Remark = record.Remark,
Werks = ga.Werks
})
.ToPageListAsync(request);
try
{
@@ -94,7 +94,6 @@ public class BalanceService : IBalanceService
item.OriginTenantId = tenants.FirstOrDefault(x => x.Code == item.OriginTenantId)?.Name;
item.Factory = tenants.FirstOrDefault(x => x.Code == item.Factory)?.Name;
});
}
catch (Exception)
{
@@ -129,40 +128,40 @@ public class BalanceService : IBalanceService
}
var page = await _dbContext.Queryable<BalanceRecordEntity>()
.LeftJoin<GainfoEntity>((record, ga) => record.UserNo == ga.No)
.LeftJoin<DepartmentEntity>((record, ga, department) => ga.DepartmentNo == department.No)
.LeftJoin<BusinessPlaceEntity>((record, ga, department, bplace) => record.BusinessPlaceCode == bplace.Code)
.Where(record => SqlFunc.DateIsSame(record.CostDate, date, DateType.Day))
.Where(record => record.DeviceUniqueNo == device.UniqueNo || record.DeviceUniqueNo == device.Code.ToString())
.Where(record => record.Type == BalanceRecordTypeEnumType.Out && record.Status == BalanceRecordStatusEnumType.Valid)
.OrderBy(record => record.CreateTime, OrderByType.Desc)
.Select((record, ga, department, bplace) => new BalanceRecordDeviceResponse
{
Id = record.Id,
Amount = SqlFunc.Abs(record.Amount),
CostDate = record.CostDate,
DepartmentNo = record.DepartmentNo,
UserNo = record.UserNo,
UserCode = record.UserCode,
Type = record.Type,
Status = record.Status,
Source = record.Source,
No = record.No,
Name = record.Name,
DepartmentName = department.Name,
BusinessPlaceName = bplace.Name,
ShiftType = record.ShiftType,
CostDateTime = record.CostDateTime,
TenantId = record.TenantId,
})
.ToPageListAsync(request);
.LeftJoin<GainfoEntity>((record, ga) => record.UserNo == ga.No)
.LeftJoin<DepartmentEntity>((record, ga, department) => ga.DepartmentNo == department.No)
.LeftJoin<BusinessPlaceEntity>((record, ga, department, bplace) => record.BusinessPlaceCode == bplace.Code)
.Where(record => SqlFunc.DateIsSame(record.CostDate, date, DateType.Day))
.Where(record => record.DeviceUniqueNo == device.UniqueNo || record.DeviceUniqueNo == device.Code.ToString())
.Where(record => record.Type == BalanceRecordTypeEnumType.Out && record.Status == BalanceRecordStatusEnumType.Valid)
.OrderBy(record => record.CreateTime, OrderByType.Desc)
.Select((record, ga, department, bplace) => new BalanceRecordDeviceResponse
{
Id = record.Id,
Amount = SqlFunc.Abs(record.Amount),
CostDate = record.CostDate,
DepartmentNo = record.DepartmentNo,
UserNo = record.UserNo,
UserCode = record.UserCode,
Type = record.Type,
Status = record.Status,
Source = record.Source,
No = record.No,
Name = record.Name,
DepartmentName = department.Name,
BusinessPlaceName = bplace.Name,
ShiftType = record.ShiftType,
CostDateTime = record.CostDateTime,
TenantId = record.TenantId,
})
.ToPageListAsync(request);
//消费总金额
var sum = await _dbContext.Queryable<BalanceRecordEntity>()
.Where(record => SqlFunc.DateIsSame(record.CostDate, date, DateType.Day))
.Where(record => record.DeviceUniqueNo == device.UniqueNo || record.DeviceUniqueNo == device.Code.ToString())
.Where(record => record.Type == BalanceRecordTypeEnumType.Out && record.Status == BalanceRecordStatusEnumType.Valid)
.SumAsync(record => SqlFunc.Abs(SqlFunc.IsNull(record.Amount, 0)));
.Where(record => SqlFunc.DateIsSame(record.CostDate, date, DateType.Day))
.Where(record => record.DeviceUniqueNo == device.UniqueNo || record.DeviceUniqueNo == device.Code.ToString())
.Where(record => record.Type == BalanceRecordTypeEnumType.Out && record.Status == BalanceRecordStatusEnumType.Valid)
.SumAsync(record => SqlFunc.Abs(SqlFunc.IsNull(record.Amount, 0)));
page.Data.ForEach(x => x.Sum = sum);
@@ -216,10 +215,7 @@ public class BalanceService : IBalanceService
var tenantResult = await _tenantApi.GetTenantsInternalAsync();
var tenants = tenantResult.Data;
page.Data.ForEach(item =>
{
item.Factory = tenants.FirstOrDefault(x => x.Code == item.Factory)?.Name;
});
page.Data.ForEach(item => { item.Factory = tenants.FirstOrDefault(x => x.Code == item.Factory)?.Name; });
}
catch (Exception)
{
@@ -242,7 +238,7 @@ public class BalanceService : IBalanceService
{
var balanceInfo = await _dbContext.Queryable<BalanceRecordEntity>().Where(x => x.No == request.No).SingleAsync();
balanceInfo.ThrowIfNull("明细数据不存在");
(balanceInfo.Status != BalanceRecordStatusEnumType.Valid && balanceInfo.Type != BalanceRecordTypeEnumType.Out).ThrowIfTrue("消费明细状态有误");
(balanceInfo.Status != BalanceRecordStatusEnumType.Valid || balanceInfo.Type != BalanceRecordTypeEnumType.Out).ThrowIfTrue("消费明细状态有误");
balanceInfo.Status = BalanceRecordStatusEnumType.Obsolute;
balanceInfo.Remark += request.Reason;
@@ -278,11 +274,11 @@ public class BalanceService : IBalanceService
var balance = gainfoMeal.Balance + Math.Abs(balanceInfo.Amount) + request.Amount;
await _dbContext.Updateable<GainfoMealEntity>()
.SetColumns(x => x.Balance == balance)
.SetColumns(x => x.Version == x.Version + 1)
.SetColumns(x => x.ModifiedTime == DateTime.Now)
.Where(x => x.UserCode == balanceInfo.UserCode && x.Version == gainfoMeal.Version)
.ExecuteCommandThrowVersionAsync();
.SetColumns(x => x.Balance == balance)
.SetColumns(x => x.Version == x.Version + 1)
.SetColumns(x => x.ModifiedTime == DateTime.Now)
.Where(x => x.UserCode == balanceInfo.UserCode && x.Version == gainfoMeal.Version)
.ExecuteCommandThrowVersionAsync();
}, 10);
}
@@ -291,28 +287,28 @@ public class BalanceService : IBalanceService
var jinkoCode = _currentUser.GetUserClaim("jinko-code") ?? string.Empty;
var page = await _dbContext.Queryable<BalanceRecordEntity>()
.LeftJoin<GainfoEntity>((record, ga) => record.UserNo == ga.No)
.LeftJoin<DepartmentEntity>((record, ga, department) => ga.DepartmentNo == department.No)
.LeftJoin<BusinessPlaceEntity>((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)
.WhereIF(request.ApplicationType.HasValue, record => record.ApplicationType == request.ApplicationType)
.Where((record, ga) => ga.Code == jinkoCode)
.OrderBy(record => record.CreateTime, OrderByType.Desc)
.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);
.LeftJoin<GainfoEntity>((record, ga) => record.UserNo == ga.No)
.LeftJoin<DepartmentEntity>((record, ga, department) => ga.DepartmentNo == department.No)
.LeftJoin<BusinessPlaceEntity>((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)
.WhereIF(request.ApplicationType.HasValue, record => record.ApplicationType == request.ApplicationType)
.Where((record, ga) => ga.Code == jinkoCode)
.OrderBy(record => record.CreateTime, OrderByType.Desc)
.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);
var now = DateTime.Now;
var monthStart = new DateTime(now.Year, now.Month, 1);
@@ -371,7 +367,6 @@ public class BalanceService : IBalanceService
Months = months
};
return res;
}
/// <summary>
@@ -466,8 +461,8 @@ public class BalanceService : IBalanceService
{
//消费机离线设备
var devices = await _dbContext.Queryable<DeviceEntity>()
.Where(x => x.Type == DeviceTypeEnumType.Meal)
.ToListAsync();
.Where(x => x.Type == DeviceTypeEnumType.Meal)
.ToListAsync();
var offs = await GetOfflineDevicesCount(devices);
var offUniqueNos = offs.Select(x => x.UniqueNo).ToList();
@@ -480,23 +475,22 @@ public class BalanceService : IBalanceService
FuncsStr = d.Funcs.ToString(),
Brand = dt.Brand,
Type = d.Type,
}, true)
.ToPageListAsync(request);
return offpage;
}
//消费机总数
var page = await _dbContext.Queryable<DeviceEntity>()
.LeftJoin<DeviceTemplateEntity>((d, dt) => d.TemplateCode == dt.Code)
.Where(d => d.Type == DeviceTypeEnumType.Meal)
.Select((d, dt) => new DevicePageResponse
{
FuncsStr = d.Funcs.ToString(),
Brand = dt.Brand,
Type = d.Type,
}, true)
.ToPageListAsync(request);
.LeftJoin<DeviceTemplateEntity>((d, dt) => d.TemplateCode == dt.Code)
.Where(d => d.Type == DeviceTypeEnumType.Meal)
.Select((d, dt) => new DevicePageResponse
{
FuncsStr = d.Funcs.ToString(),
Brand = dt.Brand,
Type = d.Type,
}, true)
.ToPageListAsync(request);
return page;
}
@@ -524,21 +518,20 @@ public class BalanceService : IBalanceService
.ToListAsync();
var OnlineDevices = deviceRegistries
.Where(x =>
.Where(x =>
{
if (x.HeartbeatInterval <= 0)
{
if (x.HeartbeatInterval <= 0)
{
return true;
}
return true;
}
return x.LastHeartbeatTime.AddSeconds(x.HeartbeatInterval * 3) >= now;
})
.Select(x => new
{
x.UniqueNo,
})
.ToList();
return x.LastHeartbeatTime.AddSeconds(x.HeartbeatInterval * 3) >= now;
})
.Select(x => new
{
x.UniqueNo,
})
.ToList();
var onlineUniqueNos = new List<string>();
OnlineDevices.ForEach(x => onlineUniqueNos.Add(x.UniqueNo));
@@ -583,7 +576,7 @@ public class BalanceService : IBalanceService
foreach (var day in days)
{
var currentAmount = Math.Round(Math.Abs(bs.Where(x => x.CostDateTime.ToString("yyyy-MM-dd") == day)
.Sum(x => x.Amount)), 2);
.Sum(x => x.Amount)), 2);
var res = new ConsumptionTrendResponse
{
@@ -594,6 +587,7 @@ public class BalanceService : IBalanceService
list.Add(res);
}
}
return list;
}
@@ -612,6 +606,7 @@ public class BalanceService : IBalanceService
var monthDate = new DateTime(year, month, 1);
months.Add(monthDate.ToString("yyyy-MM"));
}
return months;
}
@@ -639,4 +634,4 @@ public class BalanceService : IBalanceService
return days;
}
}
}

View File

@@ -88,7 +88,7 @@ public class OrderService : BaseOrderService, IOrderService
}
else
{
gainfo.ThrowIfNull($"无消费权限");
gainfo.ThrowIfNull("无消费权限");
await CheckPermissionAsync(gainfo.No, request.DeviceUniqueNo);
try

View File

@@ -15,7 +15,7 @@ public class BalanceRecordEntity : SugarBaseEntity, ISoftDeleted, ITenantId
/// <summary>
/// 流水号
/// </summary>
[SugarColumn(ColumnDescription = "流水号")]
[SugarColumn(ColumnDescription = "流水号", UniqueGroupNameList = new[] { "Unique_BalanceRecord_No" })]
public string No { get; set; }
/// <summary>

View File

@@ -65,4 +65,10 @@ public enum BalanceRecordSourceEnumType
/// </summary>
[Description("其他基地餐补")]
OtherTenantSubsidies,
/// <summary>
/// 余额写入
/// </summary>
[Description("余额写入")]
BalanceMigration,
}

View File

@@ -27,5 +27,9 @@ public enum CanteenApplicaitonTypeEnumType
/// 餐补发放
/// </summary>
[Description("餐补发放")]
MealSupplement = 400
MealSupplement = 400,
[Description("余额转入")]
BalanceMigration
}

View File

@@ -1,4 +1,4 @@
namespace Kurisu.Scheduled.Attributes;
namespace Dlhis.ScheduledTask.Attributes;
[AttributeUsage(AttributeTargets.Class)]
public class RecurringJobAttribute : Attribute

View File

@@ -1,8 +1,9 @@
using System.Reflection;
using Dlhis.ScheduledTask.Attributes;
using Kurisu.AspNetCore.DataAccess.Entity;
using Kurisu.AspNetCore.DataAccess.SqlSugar.Services;
using Kurisu.AspNetCore.Utils;
using Kurisu.Scheduled.Abstractions;
using Kurisu.Scheduled.Attributes;
namespace Dlhis.ScheduledTask;
@@ -23,18 +24,27 @@ public abstract class BaseJob : IJob
using (var scope = _serviceProvider.CreateScope())
{
Logger = scope.ServiceProvider.GetService<ILogger<BaseJob>>();
var recurringJob = this.GetType().GetCustomAttribute<RecurringJobAttribute>()!;
var key = recurringJob.UniqueJobKey;
var name = recurringJob!.Name;
var redisCache = scope.ServiceProvider.GetService<RedisCache>();
await using var handler = await redisCache.LockAsync($"scheduled:{key}");
DbContext = scope.ServiceProvider.GetService<IDbContext>();
var sqlSugarOptionsService = scope.ServiceProvider.GetService<ISqlSugarOptionsService>();
DbContext.Client.QueryFilter.ClearAndBackup<ITenantId>();
var sqlSugarOptionsService = scope.ServiceProvider.GetService<ISqlSugarOptionsService>();
sqlSugarOptionsService.IgnoreTenant = true;
var name = this.GetType().GetCustomAttribute<RecurringJobAttribute>()!.Name;
Logger.LogDebug("[{name}]开始执行...", name);
try
{
await RunAsync(scope.ServiceProvider);
if (handler.Acquired)
{
Logger.LogInformation("[{name}]开始执行...", name);
await RunAsync(scope.ServiceProvider);
}
}
catch (Exception ex)
{
@@ -49,5 +59,5 @@ public abstract class BaseJob : IJob
}
}
public abstract Task RunAsync(IServiceProvider serviceProvider);
}
protected abstract Task RunAsync(IServiceProvider serviceProvider);
}

View File

@@ -1,10 +1,10 @@
using Dlhis.Entity.Basic.Entity;
using Dlhis.Entity.Device.Entities;
using Dlhis.Entity.Device.Enums;
using Dlhis.ScheduledTask.Attributes;
using Dlhis.Sys.Api;
using Dlhis.Sys.Api.Response;
using Kurisu.AspNetCore.Utils.Extensions;
using Kurisu.Scheduled.Attributes;
using Newtonsoft.Json;
namespace Dlhis.ScheduledTask.Jobs;
@@ -26,7 +26,7 @@ public class CreateDefinitelyGroupJob : BaseJob
private static readonly string _remark = "系统自动生成";
public override async Task RunAsync(IServiceProvider serviceProvider)
protected override async Task RunAsync(IServiceProvider serviceProvider)
{
//获取所有基地信息
var tenantResult = await _tenantApi.GetTenantsInternalAsync();

View File

@@ -1,8 +1,7 @@
using Dlhis.Entity.Basic.Entity;
using Dlhis.Entity.Device.Entities;
using Dlhis.Entity.Device.Enums;
using Kurisu.Scheduled;
using Kurisu.Scheduled.Attributes;
using Dlhis.ScheduledTask.Attributes;
namespace Dlhis.ScheduledTask.Jobs;
@@ -17,7 +16,7 @@ public class CreateGetUploadRecordJob : BaseJob
{
}
public override async Task RunAsync(IServiceProvider serviceProvider)
protected override async Task RunAsync(IServiceProvider serviceProvider)
{
var devices = await DbContext.Queryable<DeviceEntity>()
.Where(x => x.Enable)

View File

@@ -1,8 +1,7 @@
using Dlhis.Entity.Basic.Entity;
using Dlhis.Entity.Device.Entities;
using Dlhis.Entity.Device.Enums;
using Kurisu.Scheduled;
using Kurisu.Scheduled.Attributes;
using Dlhis.ScheduledTask.Attributes;
namespace Dlhis.ScheduledTask.Jobs;
@@ -17,7 +16,7 @@ public class CreateSyncServerDateTimeJob : BaseJob
{
}
public override async Task RunAsync(IServiceProvider serviceProvider)
protected override async Task RunAsync(IServiceProvider serviceProvider)
{
var deviceUniqueNos = await DbContext.Queryable<DeviceTaskEntity>()
.Where(x => x.Status == DeviceTaskStatusEnumType.Wait || x.Status == DeviceTaskStatusEnumType.Process)

View File

@@ -1,6 +1,5 @@
using Dlhis.Entity.Common;
using Kurisu.Scheduled;
using Kurisu.Scheduled.Attributes;
using Dlhis.ScheduledTask.Attributes;
namespace Dlhis.ScheduledTask.Jobs;
@@ -15,7 +14,7 @@ public class DeleteApiLogTaskJob : BaseJob
{
}
public override async Task RunAsync(IServiceProvider serviceProvider)
protected override async Task RunAsync(IServiceProvider serviceProvider)
{
var before = DateTime.Now.Date.AddDays(-7);
await DbContext.ChangeDb("log").Client.Deleteable<ApiLogEntity>().Where(x => x._ts <= before).ExecuteCommandAsync();

View File

@@ -2,9 +2,9 @@
using System.Net.Sockets;
using Dlhis.Entity.Basic.Entity;
using Dlhis.Entity.Device.Entities;
using Dlhis.ScheduledTask.Attributes;
using Kurisu.AspNetCore.CustomClass;
using Kurisu.AspNetCore.Utils;
using Kurisu.Scheduled.Attributes;
using Newtonsoft.Json;
namespace Dlhis.ScheduledTask.Jobs;
@@ -22,7 +22,7 @@ public class HeartbeatJob : BaseJob
_redisCache = redisCache;
}
public override async Task RunAsync(IServiceProvider serviceProvider)
protected override async Task RunAsync(IServiceProvider serviceProvider)
{
const string key = "heartbeat-devices";
await _redisCache.KeyDeleteAsync(key);

View File

@@ -4,13 +4,13 @@ using Dlhis.Entity.Basic.Entity;
using Dlhis.Entity.Basic.Enums;
using Dlhis.Entity.Canteen.Entities;
using Dlhis.Entity.Canteen.Enums;
using Dlhis.ScheduledTask.Attributes;
using Dlhis.ScheduledTask.Common.Request;
using Dlhis.ScheduledTask.Common.Services;
using Hangfire;
using Kurisu.AspNetCore.DataAccess.SqlSugar.Extensions;
using Kurisu.AspNetCore.Utils;
using Kurisu.AspNetCore.Utils.Extensions;
using Kurisu.Scheduled.Attributes;
namespace Dlhis.ScheduledTask.Jobs;
@@ -31,7 +31,7 @@ public class MealSupplementHandlerJob : BaseJob
_jinkoJIPService = jinkoJIPService;
}
public override async Task RunAsync(IServiceProvider serviceProvider)
protected override async Task RunAsync(IServiceProvider serviceProvider)
{
//查询待处理餐补
var mealSupplements = await DbContext.Queryable<MealSupplementRecordEntity>()
@@ -49,11 +49,11 @@ public class MealSupplementHandlerJob : BaseJob
if (gainfo == null)
{
await DbContext.Updateable<MealSupplementRecordEntity>()
.SetColumns(x => x.Status == MealSupplementStatusEnumtype.Error)
.SetColumns(x => x.Result == "人员档案不存在")
.SetColumns(x => x.ModifiedTime == DateTime.Now)
.Where(x => x.UniqueId == item.UniqueId)
.ExecuteCommandAsync();
.SetColumns(x => x.Status == MealSupplementStatusEnumtype.Error)
.SetColumns(x => x.Result == "人员档案不存在")
.SetColumns(x => x.ModifiedTime == DateTime.Now)
.Where(x => x.UniqueId == item.UniqueId)
.ExecuteCommandAsync();
//后台任务获取人员
BackgroundJob.Enqueue<IGainfoUpdateService>(x => x.TodoByCodeAsync(item.Code));
@@ -65,14 +65,14 @@ public class MealSupplementHandlerJob : BaseJob
try
{
var r = await _jinkoJIPService.SyncMealSupplementRecordsAsync(new List<SyncMealSupplementRecordRequest>
{
new()
{
new()
{
UniqueId = item.UniqueId,
Status = "FAIL",
Msg = "人员离职"
}
});
UniqueId = item.UniqueId,
Status = "FAIL",
Msg = "人员离职"
}
});
await DbContext.Updateable<MealSupplementRecordEntity>()
.SetColumns(x => x.Result == r)
@@ -81,11 +81,9 @@ public class MealSupplementHandlerJob : BaseJob
.SetColumns(x => x.ModifiedTime == DateTime.Now)
.Where(x => x.UniqueId == item.UniqueId)
.ExecuteCommandAsync();
}
catch
{
}
continue;
@@ -132,21 +130,20 @@ public class MealSupplementHandlerJob : BaseJob
var b = mealUser.Balance += mealSupplement.Amount;
await DbContext.Updateable<GainfoMealEntity>()
.SetColumns(x => x.Version == x.Version + 1)
.SetColumns(x => x.Balance == b)
.SetColumns(x => x.ModifiedTime == DateTime.Now)
.Where(x => x.UserCode == mealUser.UserCode && x.Version == mealUser.Version)
.ExecuteCommandThrowVersionAsync();
.SetColumns(x => x.Version == x.Version + 1)
.SetColumns(x => x.Balance == b)
.SetColumns(x => x.ModifiedTime == DateTime.Now)
.Where(x => x.UserCode == mealUser.UserCode && x.Version == mealUser.Version)
.ExecuteCommandThrowVersionAsync();
}, 5);
var r = await _jinkoJIPService.SyncMealSupplementRecordsAsync(new List<SyncMealSupplementRecordRequest>
{
new()
{
UniqueId = mealSupplement.UniqueId,
Status = "SUCCESS",
Msg = "操作成功"
UniqueId = mealSupplement.UniqueId,
Status = "SUCCESS",
Msg = "操作成功"
}
});
@@ -170,7 +167,7 @@ public class MealSupplementHandlerJob : BaseJob
CostDate = mealSupplement.Date,
CostDateTime = DateTime.Now,
UserNo = gainfo.No,
No = SnowFlakeHelper.Instance.NextId().ToString(),
No = mealSupplement.UniqueId, //使用DHR流水号
UserCode = gainfo.Code,
TenantId = mealSupplement.Factory,
Status = BalanceRecordStatusEnumType.Valid,
@@ -228,9 +225,9 @@ public class MealSupplementHandlerJob : BaseJob
{
new()
{
UniqueId = mealSupplement.UniqueId,
Status = "SUCCESS",
Msg = "操作成功"
UniqueId = mealSupplement.UniqueId,
Status = "SUCCESS",
Msg = "操作成功"
}
});
@@ -257,4 +254,4 @@ public class MealSupplementHandlerJob : BaseJob
.ExecuteCommandAsync();
}
}
}
}

View File

@@ -1,9 +1,7 @@
using Dlhis.Entity.Basic.Entity;
using Dlhis.ScheduledTask.Attributes;
using Dlhis.ScheduledTask.Common.Dto;
using Dlhis.ScheduledTask.Common.Services;
using Hangfire;
using Kurisu.Scheduled;
using Kurisu.Scheduled.Attributes;
namespace Dlhis.ScheduledTask.Jobs;
@@ -20,7 +18,7 @@ public class SyncOrganizationJob : BaseJob
_jinkoSapService = jinkoSapService;
}
public override async Task RunAsync(IServiceProvider serviceProvider)
protected override async Task RunAsync(IServiceProvider serviceProvider)
{
var orgResult = await _jinkoSapService.GetSapOrganizationsAsync();

View File

@@ -1,12 +1,9 @@
using Dlhis.Entity.Basic.Entity;
using Dlhis.Entity.Device.Entities;
using Dlhis.Entity.Device.Enums;
using Dlhis.ScheduledTask.Attributes;
using Dlhis.ScheduledTask.Common.Request;
using Dlhis.ScheduledTask.Common.Services;
using Kurisu.AspNetCore.Utils.Extensions;
using Kurisu.Scheduled;
using Kurisu.Scheduled.Attributes;
using Microsoft.Extensions.Logging;
using SqlSugar;
namespace Dlhis.ScheduledTask.Jobs;
@@ -24,7 +21,7 @@ public class SyncOriginCardInfoJob : BaseJob
_jinkoJIPService = jinkoJIPService;
}
public override async Task RunAsync(IServiceProvider serviceProvider)
protected override async Task RunAsync(IServiceProvider serviceProvider)
{
//考勤设备(不需要Enable参数)
var devices = await DbContext.Queryable<DeviceEntity>()

View File

@@ -1,9 +1,8 @@
using Dlhis.Entity.Basic.Entity;
using Dlhis.ScheduledTask.Attributes;
using Dlhis.ScheduledTask.Common.Services;
using Hangfire;
using Kurisu.AspNetCore.Utils.Extensions;
using Kurisu.Scheduled;
using Kurisu.Scheduled.Attributes;
namespace Dlhis.ScheduledTask.Jobs;
@@ -17,7 +16,7 @@ public class SyncPersonJob : BaseJob
{
}
public override async Task RunAsync(IServiceProvider serviceProvider)
protected override async Task RunAsync(IServiceProvider serviceProvider)
{
var werks = await DbContext.Queryable<WerkEntity>()
.Where(x => x.Enable)

View File

@@ -1,8 +1,7 @@
using Dlhis.Entity.Basic.Entity;
using Dlhis.ScheduledTask.Attributes;
using Dlhis.ScheduledTask.Common.Dto;
using Dlhis.ScheduledTask.Common.Services;
using Kurisu.Scheduled;
using Kurisu.Scheduled.Attributes;
namespace Dlhis.ScheduledTask.Jobs;
@@ -19,7 +18,7 @@ public class SyncPositionJob : BaseJob
_jinkoSapService = jinkoSapService;
}
public override async Task RunAsync(IServiceProvider serviceProvider)
protected override async Task RunAsync(IServiceProvider serviceProvider)
{
var positionResult = await _jinkoSapService.GetPositionsAsync();

View File

@@ -1,9 +1,8 @@
using Dlhis.Entity.Basic.Entity;
using Dlhis.Entity.Basic.Enums;
using Dlhis.ScheduledTask.Attributes;
using Dlhis.ScheduledTask.Common.Dto;
using Kurisu.AspNetCore.Utils;
using Kurisu.Scheduled;
using Kurisu.Scheduled.Attributes;
namespace Dlhis.ScheduledTask.Jobs;
@@ -20,7 +19,7 @@ public class SyncShanxiGainfoJob : BaseJob
_redisCache = redisCache;
}
public override async Task RunAsync(IServiceProvider serviceProvider)
protected override async Task RunAsync(IServiceProvider serviceProvider)
{
var key = "gainfo:shanxi";
await _redisCache.KeyDeleteAsync(key);

View File

@@ -1,8 +1,8 @@
using Dlhis.Entity.Basic.Entity;
using Dlhis.Entity.Sys.Entities;
using Dlhis.ScheduledTask.Attributes;
using Kurisu.AspNetCore.DataAccess.SqlSugar.Services;
using Kurisu.AspNetCore.Utils.Extensions;
using Kurisu.Scheduled.Attributes;
using Microsoft.AspNetCore.Identity;
namespace Dlhis.ScheduledTask.Jobs;
@@ -17,7 +17,7 @@ public class UpdateUserPasswordJob : BaseJob
{
}
public override async Task RunAsync(IServiceProvider serviceProvider)
protected override async Task RunAsync(IServiceProvider serviceProvider)
{
var identityDbContext = DbContext.ChangeDb("identity");

View File

@@ -1,10 +1,10 @@
using System.Linq.Expressions;
using System.Reflection;
using Dlhis.ScheduledTask.Attributes;
using Hangfire;
using Hangfire.Common;
using Kurisu.AspNetCore.Startup;
using Kurisu.AspNetCore.Utils.Extensions;
using Kurisu.Scheduled.Attributes;
namespace Dlhis.ScheduledTask.Packs;