553 lines
22 KiB
C#
553 lines
22 KiB
C#
using Dlhis.Basic.Common.Message.Requests;
|
||
using Dlhis.Basic.Common.Message.Services;
|
||
using Dlhis.Basic.Organization.Comparers;
|
||
using Dlhis.Entity.Basic.Entity;
|
||
using Dlhis.Entity.Basic.Enums;
|
||
using Dlhis.Entity.Device.Enums;
|
||
using Dlhis.Entity.Sys.Entities;
|
||
using Dlhis.Entity.Sys.Enums;
|
||
using Dlhis.Jip.Api.Dto;
|
||
using Kurisu.AspNetCore.DataAccess.SqlSugar.Services;
|
||
using Kurisu.AspNetCore.Utils.Extensions;
|
||
|
||
namespace Dlhis.Basic.Organization.Services.Implements;
|
||
|
||
public class GainfoUpdateService : IGainfoUpdateService
|
||
{
|
||
private readonly IDbContext _dbContext;
|
||
private readonly ILogger<GainfoUpdateService> _logger;
|
||
private readonly IJinkoSapService _jinkoSapService;
|
||
private readonly IGainfoPermissionService _gainfoPermissionService;
|
||
private readonly IJinkoApiService _dingTalkApi;
|
||
private readonly IIdentityUserSyncService _identityUserSyncService;
|
||
|
||
public GainfoUpdateService(IDbContext dbContext,
|
||
ILogger<GainfoUpdateService> logger,
|
||
IJinkoSapService jinkoSapService,
|
||
IGainfoPermissionService gainfoPermissionService,
|
||
IJinkoApiService dingTalkApi,
|
||
IIdentityUserSyncService identityUserSyncService)
|
||
{
|
||
_dbContext = dbContext;
|
||
_logger = logger;
|
||
_jinkoSapService = jinkoSapService;
|
||
_gainfoPermissionService = gainfoPermissionService;
|
||
_dingTalkApi = dingTalkApi;
|
||
_identityUserSyncService = identityUserSyncService;
|
||
}
|
||
|
||
|
||
public async Task TodoByWerkAsync(string werk)
|
||
{
|
||
var werkInfo = await _dbContext.Queryable<WerkEntity>().Where(x => x.Werk == werk).SingleAsync();
|
||
werkInfo.LastSyncStartTime = DateTime.Now;
|
||
werkInfo.HandleMessage = "任务执行中";
|
||
await _dbContext.UpdateAsync(werkInfo);
|
||
|
||
try
|
||
{
|
||
var personResp = await _jinkoSapService.GetPersonsByWerkAsync(werk);
|
||
var persons = personResp.Person.Items;
|
||
|
||
werkInfo.HandleMessage = "SAP人员数量" + persons.Count;
|
||
werkInfo.Total = persons.Count;
|
||
await _dbContext.UpdateAsync(werkInfo);
|
||
|
||
if (persons.Count > 0)
|
||
{
|
||
var modifiedPersons = await GetModifiedPersonAsync(persons.OrderByDescending(x => x.ZSTATUS).ThenBy(x => x.ZRZRQ).ToList());
|
||
|
||
werkInfo.HandleMessage = "SAP人员差异数量" + modifiedPersons.Count;
|
||
werkInfo.DiffNumber = modifiedPersons.Count;
|
||
await _dbContext.UpdateAsync(werkInfo);
|
||
|
||
if (modifiedPersons.Count > 0)
|
||
{
|
||
await SavePersonAsync(modifiedPersons);
|
||
}
|
||
}
|
||
|
||
werkInfo.HandleMessage = "同步结束";
|
||
werkInfo.LastSyncEndTime = DateTime.Now;
|
||
werkInfo.BackgroundJobKey = string.Empty;
|
||
await _dbContext.UpdateAsync(werkInfo);
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
_logger.LogError(ex, "{werk}同步处理异常:{message}", werk, ex.Message);
|
||
werkInfo.HandleMessage = ex.Message;
|
||
werkInfo.LastSyncEndTime = DateTime.Now;
|
||
werkInfo.BackgroundJobKey = string.Empty;
|
||
await _dbContext.UpdateAsync(werkInfo);
|
||
}
|
||
}
|
||
|
||
public async Task TodoByCodeAsync(string code)
|
||
{
|
||
_logger.LogInformation("SAP根据学工号同步开始:{code}", code);
|
||
|
||
try
|
||
{
|
||
var personResp = await _jinkoSapService.GetPersonsByCodeAsync(code);
|
||
var persons = personResp.Person.Items;
|
||
|
||
_logger.LogInformation("获取SAP人员数量为:{count}", persons.Count);
|
||
if (persons.Count > 0)
|
||
{
|
||
var modifiedPersons = await GetModifiedPersonAsync(persons.OrderByDescending(x => x.ZSTATUS).ThenBy(x => x.ZRZRQ).ToList());
|
||
_logger.LogInformation("SAP人员差异数量为:{count}", modifiedPersons.Count);
|
||
if (modifiedPersons.Count > 0)
|
||
{
|
||
await SavePersonAsync(modifiedPersons);
|
||
}
|
||
}
|
||
|
||
_logger.LogInformation("SAP根据学工号同步结束:{code}", code);
|
||
}
|
||
catch (Exception e)
|
||
{
|
||
_logger.LogError(e, "同步人员异常:{msg}", e.Message);
|
||
}
|
||
}
|
||
|
||
|
||
private async Task SavePersonAsync(List<SapPersonItem> persons)
|
||
{
|
||
var workCodes = persons.Select(x => x.ZWORKCODE).ToList();
|
||
var chunks = workCodes.Chunk(4000).ToList();
|
||
|
||
foreach (var searchCodes in chunks)
|
||
{
|
||
_logger.LogWarning("SAP分批处理Chunk数量:{count}", searchCodes.Length);
|
||
var existsWorkCodes = await _dbContext.Queryable<GainfoSapEntity>()
|
||
.Where(x => searchCodes.Contains(x.ename))
|
||
.Select(x => x.ename)
|
||
.ToListAsync();
|
||
|
||
var originUpdates = persons.Where(x => existsWorkCodes.Contains(x.ZWORKCODE)).ToList();
|
||
var existsUpdateWorkCodes = originUpdates.Select(x => x.ZWORKCODE).ToList();
|
||
var originInserts = persons.Where(x => searchCodes.Contains(x.ZWORKCODE)).Where(x => !existsUpdateWorkCodes.Contains(x.ZWORKCODE)).ToList();
|
||
|
||
var updates = ToGainfoSap(originUpdates);
|
||
var inserts = ToGainfoSap(originInserts);
|
||
|
||
foreach (var item in inserts)
|
||
{
|
||
try
|
||
{
|
||
await InsertPersonAsync(item);
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
_logger.LogError(ex, "执行新增失败:{message}", ex.Message);
|
||
}
|
||
}
|
||
|
||
foreach (var item in updates)
|
||
{
|
||
try
|
||
{
|
||
var no = await _dbContext.Queryable<GainfoEntity>().Where(x => x.Code == item.ename).Select(x => x.No).SingleAsync();
|
||
if (no.IsEmpty())
|
||
{
|
||
await InsertPersonAsync(item);
|
||
}
|
||
else
|
||
{
|
||
await UpdatePersonAsync(item);
|
||
}
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
_logger.LogError(ex, "执行更新失败:{message}", ex.Message);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
private async Task InsertPersonAsync(GainfoSapEntity item)
|
||
{
|
||
var info = GainfoSapToGainfo(item);
|
||
//只有身份证号存在才进行新增
|
||
if (info.IdNo.IsPresent())
|
||
{
|
||
await _dbContext.UseTransactionAsync(async () =>
|
||
{
|
||
await _dbContext.InsertAsync(item);
|
||
|
||
if (item.isowner == "T")
|
||
{
|
||
await _dbContext.InsertAsync(info);
|
||
await _identityUserSyncService.SyncAccountAsync(info.Code, info.Name, info.IdNo, info.Factory);
|
||
}
|
||
else
|
||
{
|
||
if (!await _dbContext.Queryable<GainfoLeaveEntity>().AnyAsync(x => x.Code == item.ename))
|
||
{
|
||
await _dbContext.Client.Insertable(info).AS("GainfoLeave").ExecuteCommandAsync();
|
||
}
|
||
}
|
||
});
|
||
}
|
||
else
|
||
{
|
||
_logger.LogWarning("SAP新增人员失败,身份证号不存在:{userCode},{userName}", info.Code, info.Name);
|
||
}
|
||
}
|
||
|
||
private static GainfoEntity GainfoSapToGainfo(GainfoSapEntity item)
|
||
{
|
||
var info = new GainfoEntity
|
||
{
|
||
No = Guid.NewGuid().ToString(),
|
||
InternalNo = item.PERNR,
|
||
Type = GainfoUserTypeEnumType.Normal,
|
||
Name = item.gname,
|
||
Code = item.ename,
|
||
CountryNo = item.country,
|
||
IdClass = item.idcls,
|
||
IdNo = item.idno,
|
||
Native = item.native,
|
||
Gender = item.sex == "F" ? GenderEnumType.Female : GenderEnumType.Male,
|
||
Birthday = item.birthday,
|
||
Address = item.address,
|
||
DepartmentNo = item.appellation,
|
||
Nation = item.nation,
|
||
Phone = item.phone,
|
||
Degree = item.email,
|
||
Grade = item.ZZ_ZD,
|
||
Title = item.Z_ZJ,
|
||
PositionNo = item.STELL,
|
||
Remark = item.remark,
|
||
Werks = item.WERKS,
|
||
CostId = item.KOSTL,
|
||
EntryDate = item.createdate,
|
||
ResignationDate = item.ZLZRQ,
|
||
Workplace = item.ZZ_GZDJD,
|
||
Factory = item.ZZ_GZDCQ
|
||
};
|
||
|
||
return info;
|
||
}
|
||
|
||
private async Task UpdatePersonAsync(GainfoSapEntity item)
|
||
{
|
||
await _dbContext.Client.Ado.BeginTranAsync();
|
||
try
|
||
{
|
||
await _dbContext.Updateable<GainfoSapEntity>().SetColumns(g => new GainfoSapEntity
|
||
{
|
||
PERNR = item.PERNR,
|
||
gname = item.gname,
|
||
phone = item.phone,
|
||
appellation = item.appellation,
|
||
isowner = item.isowner,
|
||
remark = item.remark,
|
||
email = item.email,
|
||
WERKS = item.WERKS,
|
||
KOSTL = item.KOSTL,
|
||
STELL = item.STELL,
|
||
Z_ZJ = item.Z_ZJ,
|
||
ZZ_ZD = item.ZZ_ZD,
|
||
MNTXT = item.MNTXT,
|
||
MASSN = item.MASSN,
|
||
ZSTATUS = item.ZSTATUS,
|
||
ZLZRQ = item.ZLZRQ,
|
||
STELL_NM = item.STELL_NM,
|
||
createdate = item.createdate,
|
||
ZZ_GZDJD = item.ZZ_GZDJD,
|
||
ZZ_GZDCQ = item.ZZ_GZDCQ,
|
||
}).Where(x => x.ename == item.ename).ExecuteCommandAsync();
|
||
|
||
//获取当前在职人员
|
||
var gainfo = await _dbContext.Queryable<GainfoEntity>().Where(x => x.Code == item.ename).SingleAsync();
|
||
|
||
//默认人员存在
|
||
if (gainfo != null)
|
||
{
|
||
var workplace = item.ZZ_GZDJD;
|
||
var factory = item.ZZ_GZDCQ;
|
||
|
||
if (item.isowner == "T")
|
||
{
|
||
var change = string.Empty;
|
||
|
||
var hasFactoryChange = gainfo.Factory != factory || gainfo.Workplace != workplace;
|
||
var hasDepartmentChange = gainfo.DepartmentNo != item.appellation;
|
||
|
||
|
||
if (hasFactoryChange)
|
||
{
|
||
await _identityUserSyncService.SyncAccountAsync(gainfo.Code, gainfo.Name, gainfo.IdNo, factory);
|
||
change = $"{gainfo.Factory}->{factory}";
|
||
}
|
||
|
||
if (hasDepartmentChange)
|
||
{
|
||
change += $"{gainfo.DepartmentNo}->{item.appellation}";
|
||
}
|
||
|
||
if (change.IsPresent())
|
||
{
|
||
await _gainfoPermissionService.ResetPermissionsAsync(gainfo.No, DeviceTaskEnumType.Delete, null, $"异动生成({change})");
|
||
}
|
||
|
||
|
||
await _dbContext.Updateable<GainfoEntity>().SetColumns(g => new GainfoEntity
|
||
{
|
||
InternalNo = item.PERNR,
|
||
Name = item.gname,
|
||
PositionNo = item.STELL,
|
||
Grade = item.ZZ_ZD,
|
||
Title = item.Z_ZJ,
|
||
Phone = item.phone,
|
||
DepartmentNo = item.appellation,
|
||
Remark = item.remark,
|
||
Degree = item.email,
|
||
Werks = item.WERKS,
|
||
CostId = item.KOSTL,
|
||
EntryDate = item.createdate,
|
||
ResignationDate = item.ZLZRQ,
|
||
Workplace = workplace,
|
||
Factory = factory,
|
||
ModifiedTime = DateTime.Now
|
||
}).Where(x => x.Code == item.ename).ExecuteCommandAsync();
|
||
|
||
//有变更就重新下发
|
||
if (change.IsPresent())
|
||
{
|
||
await _gainfoPermissionService.ResetPermissionsAsync(gainfo.No, DeviceTaskEnumType.Add, null, $"异动生成({change})");
|
||
|
||
//只有厂区变更才需要处理工作网格
|
||
if (hasFactoryChange)
|
||
{
|
||
var workGridUser = await _dbContext.Queryable<WorkGridUserEntity>().Where(x => x.UserCode == gainfo.Code).SingleAsync();
|
||
if (workGridUser != null)
|
||
{
|
||
try
|
||
{
|
||
var resignationDate = DateOnly.FromDateTime(DateTime.Now);
|
||
|
||
var workGridSchedules = await _dbContext.Queryable<WorkGridScheduleEntity>()
|
||
.Where(x => x.UserCode == gainfo.Code)
|
||
.Where(x => x.Date >= resignationDate)
|
||
.ToListAsync();
|
||
|
||
if (workGridSchedules.Any())
|
||
{
|
||
var dates = workGridSchedules.Select(x => $"{x.Date.ToString("yyyy年-MM月-dd日")}的{x.PeriodType.GetDescription()}").Join(",");
|
||
var workGrid = await _dbContext.Queryable<WorkGridEntity>()
|
||
.Where(x => x.Code == workGridUser.WorkGridCode)
|
||
.Select(x => new
|
||
{
|
||
x.LeaderUserCode, x.Name
|
||
}).SingleAsync();
|
||
|
||
var content = $"{workGrid.Name}的网格长,你好,检测到你网格中 {gainfo.Name}({gainfo.Code}),因发生离职或者异动,现已经删除该员工{dates}的排班信息,请前往系统处理!";
|
||
|
||
await _dingTalkApi.SendWorkMessageAsync(new DingTalkWorkMessageRequest
|
||
{
|
||
Content = content,
|
||
WorkCodes = new List<string> { workGrid.LeaderUserCode }
|
||
});
|
||
}
|
||
|
||
await _dbContext.DeleteAsync(workGridUser);
|
||
await _dbContext.DeleteAsync(workGridSchedules);
|
||
}
|
||
catch (Exception e)
|
||
{
|
||
_logger.LogError(e, "网格异动处理异常:{error}", e.Message);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
else
|
||
{
|
||
await _gainfoPermissionService.ResetPermissionsAsync(gainfo.No, DeviceTaskEnumType.Delete, null, "人员离职生成");
|
||
|
||
//先写入离职表
|
||
gainfo.IdentityUserId = (int)gainfo.Id; //记录原始id
|
||
gainfo.Id = 0;
|
||
gainfo.ResignationDate = item.ZLZRQ;
|
||
|
||
if (!await _dbContext.Queryable<GainfoLeaveEntity>().AnyAsync(x => x.Code == item.ename))
|
||
{
|
||
await _dbContext.Client.Insertable(gainfo).AS("GainfoLeave").ExecuteCommandAsync();
|
||
}
|
||
|
||
await _dbContext.Deleteable<GainfoGroupRelationshipEntity>()
|
||
.Where(x => x.UserNo == gainfo.No)
|
||
.ExecuteCommandAsync();
|
||
await _dbContext.Deleteable<DevicePermissionEntity>()
|
||
.Where(x => x.AssignType == AssignTypeEnumType.User && x.AssignValue == gainfo.No)
|
||
.ExecuteCommandAsync();
|
||
|
||
var workGridUser = await _dbContext.Queryable<WorkGridUserEntity>()
|
||
.Where(x => x.UserCode == gainfo.Code)
|
||
.SingleAsync();
|
||
if (workGridUser != null)
|
||
{
|
||
try
|
||
{
|
||
var resignationDate = DateOnly.FromDateTime(gainfo.ResignationDate!.Value);
|
||
|
||
var workGridSchedules = await _dbContext.Queryable<WorkGridScheduleEntity>()
|
||
.Where(x => x.UserCode == gainfo.Code)
|
||
.Where(x => x.Date >= resignationDate)
|
||
.ToListAsync();
|
||
|
||
if (workGridSchedules.Any())
|
||
{
|
||
var dates = workGridSchedules.Select(x => $"{x.Date.ToString("yyyy年-MM月-dd日")}的{x.PeriodType.GetDescription()}").Join(",");
|
||
var workGrid = await _dbContext.Queryable<WorkGridEntity>()
|
||
.Where(x => x.Code == workGridUser.WorkGridCode)
|
||
.Select(x => new
|
||
{
|
||
x.LeaderUserCode, x.Name
|
||
}).SingleAsync();
|
||
var content = $"{workGrid.Name}的网格长,你好,检测到你网格中 {gainfo.Name}({gainfo.Code}),因发生离职或者异动,现已经删除该员工{dates}的排班信息,请前往系统处理!";
|
||
|
||
await _dingTalkApi.SendWorkMessageAsync(new DingTalkWorkMessageRequest
|
||
{
|
||
Content = content,
|
||
WorkCodes = new List<string> { workGrid.LeaderUserCode }
|
||
});
|
||
}
|
||
|
||
await _dbContext.DeleteAsync(workGridUser);
|
||
await _dbContext.DeleteAsync(workGridSchedules);
|
||
}
|
||
catch (Exception e)
|
||
{
|
||
_logger.LogError(e, "网格异动处理异常:{error}", e.Message);
|
||
}
|
||
}
|
||
|
||
gainfo.Id = gainfo.IdentityUserId;
|
||
await _dbContext.DeleteReallyAsync(gainfo);
|
||
await _identityUserSyncService.LockAccountAsync(gainfo.Code);
|
||
}
|
||
}
|
||
|
||
await _dbContext.Client.Ado.CommitTranAsync();
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
await _dbContext.Client.Ado.RollbackTranAsync();
|
||
_logger.LogError(ex, "更新人员失败:{message}", ex.Message);
|
||
}
|
||
}
|
||
|
||
private async Task<List<SapPersonItem>> GetModifiedPersonAsync(List<SapPersonItem> sapList)
|
||
{
|
||
var last = await LoadDataAsync();
|
||
if (last.Count <= 0)
|
||
{
|
||
return sapList;
|
||
}
|
||
|
||
var needRemove = sapList.Intersect(last, new SapPersonComparer());
|
||
return sapList.Except(needRemove, new SapPersonComparer()).ToList();
|
||
}
|
||
|
||
|
||
private async Task<List<SapPersonItem>> LoadDataAsync()
|
||
{
|
||
var gainfos = await _dbContext.Queryable<GainfoSapEntity>().ToListAsync();
|
||
|
||
return gainfos.Select(x => new SapPersonItem
|
||
{
|
||
NAME = x.gname,
|
||
ZWORKCODE = x.ename,
|
||
ZZ_SFZH = x.idno,
|
||
GBDAT = x.birthday,
|
||
ZXUELI = x.email,
|
||
ORGEH = x.appellation,
|
||
ZMOBILE = x.phone,
|
||
ZSTATUS = x.ZSTATUS,
|
||
ZRZRQ = x.createdate,
|
||
PERNR = x.PERNR,
|
||
WERKS = x.WERKS,
|
||
KOSTL = x.KOSTL,
|
||
ZZ_ZD = x.ZZ_ZD,
|
||
Z_ZJ = x.Z_ZJ,
|
||
STELL = x.STELL,
|
||
STELL_NM = x.STELL_NM,
|
||
ZLZRQ = x.ZLZRQ,
|
||
MASSN = x.MASSN,
|
||
MNTXT = x.MNTXT,
|
||
ZZ_COUNNM = x.ZZ_COUNNM,
|
||
ZZ_GZDJD = x.ZZ_GZDJD,
|
||
ZZ_GZDCQ = x.ZZ_GZDCQ
|
||
}).ToList();
|
||
}
|
||
|
||
|
||
private static List<GainfoSapEntity> ToGainfoSap(List<SapPersonItem> data)
|
||
{
|
||
return data.Select(person =>
|
||
{
|
||
var entryDate = person.ZRZRQ;
|
||
var resignDate = person.ZLZRQ;
|
||
|
||
var rmk = $"入职时间:{entryDate.ToString("yyyy-MM-dd", System.Globalization.CultureInfo.InvariantCulture)} ";
|
||
|
||
if (resignDate != null && resignDate.Value.ToString("yyyy-MM-dd") != "1900-01-01")
|
||
rmk += $"离职时间:{resignDate.Value.ToString("yyyy-MM-dd", System.Globalization.CultureInfo.InvariantCulture)} ";
|
||
|
||
if (!string.IsNullOrWhiteSpace(person.MGTXT))
|
||
rmk += $"变更原因:{person.MGTXT}";
|
||
|
||
var native = GetNative(person.ZZ_SFZH);
|
||
var gender = person.GESCH == "2" ? "F" : "M";
|
||
|
||
person.ZZ_SFZH = person.ZZ_SFZH.TrimStart();
|
||
GainfoSapEntity o = new()
|
||
{
|
||
gname = person.NAME,
|
||
ename = person.ZWORKCODE,
|
||
idno = person.ZZ_SFZH,
|
||
birthday = person.GBDAT,
|
||
email = person.ZXUELI,
|
||
appellation = person.ORGEH,
|
||
phone = person.ZMOBILE,
|
||
ZSTATUS = person.ZSTATUS,
|
||
createdate = person.ZRZRQ,
|
||
PERNR = person.PERNR,
|
||
WERKS = person.WERKS,
|
||
KOSTL = person.KOSTL,
|
||
ZZ_ZD = person.ZZ_ZD,
|
||
Z_ZJ = person.Z_ZJ,
|
||
STELL = person.STELL,
|
||
STELL_NM = person.STELL_NM,
|
||
ZLZRQ = person.ZLZRQ,
|
||
MASSN = person.MASSN,
|
||
MNTXT = person.MNTXT,
|
||
remark = rmk,
|
||
native = native,
|
||
sex = gender,
|
||
logdate = DateTime.Now,
|
||
isowner = int.Parse(person.ZSTATUS) < 5 ? "T" : "F",
|
||
country = person.ZZ_COUNNM,
|
||
address = "",
|
||
occupation = "99",
|
||
nation = "01",
|
||
idcls = "ID",
|
||
ZZ_COUNNM = person.ZZ_COUNNM,
|
||
ZZ_GZDJD = person.ZZ_GZDJD,
|
||
ZZ_GZDCQ = person.ZZ_GZDCQ
|
||
};
|
||
|
||
return o;
|
||
}).ToList();
|
||
}
|
||
|
||
private static string GetNative(string idNo)
|
||
{
|
||
if (string.IsNullOrWhiteSpace(idNo) || idNo.Length < 6) return null;
|
||
idNo = idNo.TrimStart();
|
||
return idNo[..6];
|
||
}
|
||
} |