Files
jinko.yikatong/Src/Dlhis.Basic/Organization/Services/Implements/GainfoUpdateService.cs

620 lines
24 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using Dlhis.Basic.Common.Message.Requests;
using Dlhis.Basic.Common.Message.Services;
using Dlhis.Basic.Organization.Comparers;
using Dlhis.Basic.Organization.Repositories;
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;
private readonly IGainfoSapRepository _gainfoSapRepository;
public GainfoUpdateService(IDbContext dbContext,
ILogger<GainfoUpdateService> logger,
IJinkoSapService jinkoSapService,
IGainfoPermissionService gainfoPermissionService,
IJinkoApiService dingTalkApi,
IIdentityUserSyncService identityUserSyncService,
IGainfoSapRepository gainfoSapRepository)
{
_dbContext = dbContext;
_logger = logger;
_jinkoSapService = jinkoSapService;
_gainfoPermissionService = gainfoPermissionService;
_dingTalkApi = dingTalkApi;
_identityUserSyncService = identityUserSyncService;
_gainfoSapRepository = gainfoSapRepository;
}
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.Persons;
werkInfo.HandleMessage = "SAP人员数量" + persons.Count;
werkInfo.DiffNumber = 0;
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.Persons;
_logger.LogInformation("获取SAP人员数量为:{count}", persons.Count);
if (persons.Count > 0)
{
var deleteCount = await _gainfoSapRepository.DeleteByWorkCodeAsync(code);
_logger.LogInformation("删除工号:{code}的GainfoSap历史数量:{count}", code, deleteCount);
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 thirdPartPersons = persons.Where(x => !string.IsNullOrWhiteSpace(x.ZWORKCODE)).ToList();
if (thirdPartPersons.Count <= 0)
{
return;
}
var workCodes = thirdPartPersons.Select(x => x.ZWORKCODE).Distinct().ToList();
var chunks = workCodes.Chunk(4000).ToList();
var comparer = new SapPersonComparer();
foreach (var searchCodes in chunks)
{
_logger.LogWarning("SAP分批处理Chunk数量:{count}", searchCodes.Length);
var chunkThirdPartPersons = thirdPartPersons.Where(x => searchCodes.Contains(x.ZWORKCODE)).ToList();
var latestHistoryPersons = (await _gainfoSapRepository.GetLatestPersonsAsync(searchCodes.ToList()))
.ToDictionary(x => x.ZWORKCODE, x => x);
foreach (var person in chunkThirdPartPersons)
{
try
{
await _dbContext.UseTransactionAsync(async () =>
{
var item = ToGainfoSap(person);
if (!latestHistoryPersons.TryGetValue(person.ZWORKCODE, out var latestHistory)
|| !comparer.Equals(person, latestHistory))
{
await _dbContext.InsertAsync(item);
}
var no = await _dbContext.Queryable<GainfoEntity>()
.Where(x => x.Code == item.ename)
.Select(x => x.No)
.SingleAsync();
if (no.IsEmpty())
{
await InsertCurrentPersonCoreAsync(item);
}
else
{
await UpdatePersonAsync(item, false);
}
});
}
catch (Exception ex)
{
_logger.LogError(ex, "执行人员同步失败,工号:{workCode},错误:{message}", person.ZWORKCODE, ex.Message);
}
}
}
}
private async Task InsertCurrentPersonCoreAsync(GainfoSapEntity item)
{
var info = GainfoSapToGainfo(item);
//只有身份证号存在才进行新增
if (info.IdNo.IsPresent())
{
if (item.isowner == "T")
{
if (!await _dbContext.Queryable<GainfoEntity>().AnyAsync(x => x.Code == item.ename))
{
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,
NameEn = item.gname2,
Code = item.ename,
CountryNo = item.country,
IdClass = item.idcls,
IdNo = item.idno.ToUpperInvariant(),
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;
}
public async Task UpdatePersonAsync(GainfoSapEntity item, bool useTransaction = true)
{
if (useTransaction)
{
await _dbContext.Client.Ado.BeginTranAsync();
}
try
{
//获取当前在职人员
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, null, $"异动生成({change})");
}
await _dbContext.Updateable<GainfoEntity>().SetColumns(g => new GainfoEntity
{
InternalNo = item.PERNR,
Name = item.gname,
NameEn = item.gname2,
IdNo = item.idno.ToUpperInvariant(),
Birthday = item.birthday,
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, null, $"异动生成({change})");
//只有厂区变更才需要处理工作网格
if (hasFactoryChange)
{
await HandleWorkGridChangeAsync(gainfo, DateOnly.FromDateTime(DateTime.Now));
}
}
}
else
{
await _gainfoPermissionService.ResetPermissionsAsync(gainfo.No, DeviceTaskEnumType.Delete, null, 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();
await HandleWorkGridChangeAsync(gainfo, DateOnly.FromDateTime(gainfo.ResignationDate!.Value));
gainfo.Id = gainfo.IdentityUserId;
await _dbContext.DeleteReallyAsync(gainfo);
await _identityUserSyncService.LockAccountAsync(gainfo.Code);
}
}
if (useTransaction)
{
await _dbContext.Client.Ado.CommitTranAsync();
}
}
catch (Exception ex)
{
if (useTransaction)
{
await _dbContext.Client.Ado.RollbackTranAsync();
}
_logger.LogError(ex, "更新人员失败:{message}", ex.Message);
throw;
}
}
private async Task HandleWorkGridChangeAsync(GainfoEntity gainfo, DateOnly effectiveDate)
{
try
{
var workGridUser = await _dbContext.Queryable<WorkGridUserEntity>()
.Where(x => x.UserCode == gainfo.Code)
.SingleAsync();
if (workGridUser == null)
{
return;
}
var workGridSchedules = await _dbContext.Queryable<WorkGridScheduleEntity>()
.Where(x => x.UserCode == gainfo.Code)
.Where(x => x.Date >= effectiveDate)
.ToListAsync();
if (workGridSchedules.Any())
{
try
{
var workGrid = await _dbContext.Queryable<WorkGridEntity>()
.Where(x => x.Code == workGridUser.WorkGridCode)
.Select(x => new
{
x.LeaderUserCode,
x.Name
})
.SingleAsync();
if (workGrid != null)
{
var dates = workGridSchedules
.Select(x => $"{x.Date:yyyy年-MM月-dd日}的{x.PeriodType.GetDescription()}")
.Join(",");
var content =
$"{workGrid.Name}的网格长,你好,检测到你网格中 {gainfo.Name}({gainfo.Code}),因发生离职或者异动,现已经删除该员工{dates}的排班信息,请前往系统处理!";
await _dingTalkApi.SendWorkMessageByWorkGridAsync(new DingTalkWorkMessageRequest
{
Content = content,
WorkCodes = new List<string> { workGrid.LeaderUserCode }
});
}
}
catch (Exception ex)
{
_logger.LogError(ex, "工作网格消息通知失败,工号:{workCode},错误:{error}", gainfo.Code, ex.Message);
}
}
await _dbContext.DeleteAsync(workGridUser);
await _dbContext.DeleteAsync(workGridSchedules);
}
catch (Exception ex)
{
_logger.LogError(ex, "网格异动处理异常,工号:{workCode},错误:{error}", gainfo.Code, ex.Message);
}
}
private async Task<List<SapPersonItem>> GetModifiedPersonAsync(List<SapPersonItem> sapList)
{
if (sapList.Count <= 0)
{
return new List<SapPersonItem>();
}
var comparer = new SapPersonComparer();
var workCodes = sapList
.Select(x => x.ZWORKCODE)
.Where(x => !string.IsNullOrWhiteSpace(x))
.Distinct()
.ToList();
if (workCodes.Count <= 0)
{
return sapList;
}
var last = await _gainfoSapRepository.GetLatestPersonsAsync(workCodes);
if (last.Count <= 0)
{
return sapList;
}
var lastMap = last
.Where(x => !string.IsNullOrWhiteSpace(x.ZWORKCODE))
.GroupBy(x => x.ZWORKCODE)
.ToDictionary(x => x.Key, x => x.First());
var existingCodes = await _dbContext.Queryable<GainfoEntity>()
.Where(x => workCodes.Contains(x.Code))
.Select(x => x.Code)
.ToListAsync();
var modifiedPersons = new List<SapPersonItem>();
foreach (var person in sapList)
{
if (string.IsNullOrWhiteSpace(person.ZWORKCODE))
{
modifiedPersons.Add(person);
continue;
}
var existsInGainfo = existingCodes.Contains(person.ZWORKCODE);
var isOwner = int.Parse(person.ZSTATUS) < 5;
if ((isOwner && !existsInGainfo) || (!isOwner && existsInGainfo))
{
modifiedPersons.Add(person);
continue;
}
if (!lastMap.TryGetValue(person.ZWORKCODE, out var latestHistory))
{
modifiedPersons.Add(person);
continue;
}
if (comparer.Equals(person, latestHistory))
{
continue;
}
modifiedPersons.Add(person);
}
if (modifiedPersons.Count > 0)
{
var first = modifiedPersons[0];
var historyCandidates = !string.IsNullOrWhiteSpace(first.ZWORKCODE)
&& lastMap.TryGetValue(first.ZWORKCODE, out var currentHistoryPerson)
? currentHistoryPerson
: null;
var hasHistory = historyCandidates != null;
var diffType = hasHistory ? "Update" : "Insert";
var diffMessage = hasHistory
? string.Join("; ", GetFirstDiffFields(first, historyCandidates))
: "历史记录不存在";
_logger.LogWarning("SAP首条差异 DiffType:{diffType}, ZWORKCODE:{workCode}, HasHistory:{hasHistory}, Diffs:{diffs}",
diffType, first.ZWORKCODE, hasHistory, diffMessage);
}
return modifiedPersons;
}
private static GainfoSapEntity ToGainfoSap(SapPersonItem 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();
return new GainfoSapEntity
{
gname = person.NAME,
gname2 = person.NAME2,
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_XJ,
ZZ_ZD = person.ZZ_ZD,
Z_ZJ = person.Z_ZJ,
STELL = person.PLANS, //person.STELL, 20251129变更
STELL_NM = person.STELL_NM ?? string.Empty,
ZLZRQ = person.ZLZRQ,
MASSN = person.MASSN ?? string.Empty,
MNTXT = person.MNTXT ?? string.Empty,
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
};
}
private static string GetNative(string idNo)
{
if (string.IsNullOrWhiteSpace(idNo) || idNo.Length < 6) return null;
idNo = idNo.TrimStart();
return idNo[..6];
}
private static List<string> GetFirstDiffFields(SapPersonItem current, SapPersonItem history)
{
var diffs = new List<string>();
AddDiff(diffs, "PERNR", current.PERNR, history.PERNR);
AddDiff(diffs, "WERKS", current.WERKS, history.WERKS);
AddDiff(diffs, "ORGEH", current.ORGEH, history.ORGEH);
AddDiff(diffs, "NAME", current.NAME, history.NAME);
AddDiff(diffs, "GBDAT", FormatDate(current.GBDAT), FormatDate(history.GBDAT));
AddDiff(diffs, "ZZ_SFZH", NormalizeIdNo(current.ZZ_SFZH), NormalizeIdNo(history.ZZ_SFZH));
AddDiff(diffs, "ZWORKCODE", current.ZWORKCODE, history.ZWORKCODE);
AddDiff(diffs, "ZMOBILE", Normalize(current.ZMOBILE), Normalize(history.ZMOBILE));
AddDiff(diffs, "ZSTATUS", Normalize(current.ZSTATUS), Normalize(history.ZSTATUS));
AddDiff(diffs, "KOSTL_XJ", Normalize(current.KOSTL_XJ), Normalize(history.KOSTL_XJ));
AddDiff(diffs, "NAME2", Normalize(current.NAME2), Normalize(history.NAME2));
AddDiff(diffs, "ZZ_ZD", Normalize(current.ZZ_ZD), Normalize(history.ZZ_ZD));
AddDiff(diffs, "Z_ZJ", Normalize(current.Z_ZJ), Normalize(history.Z_ZJ));
AddDiff(diffs, "ZRZRQ", FormatDate(current.ZRZRQ), FormatDate(history.ZRZRQ));
AddDiff(diffs, "ZLZRQ", FormatDate(current.ZLZRQ), FormatDate(history.ZLZRQ));
AddDiff(diffs, "PLANS", Normalize(current.PLANS), Normalize(history.PLANS));
AddDiff(diffs, "STELL_NM", Normalize(current.STELL_NM), Normalize(history.STELL_NM));
AddDiff(diffs, "MASSN", Normalize(current.MASSN), Normalize(history.MASSN));
AddDiff(diffs, "MNTXT", Normalize(current.MNTXT), Normalize(history.MNTXT));
AddDiff(diffs, "ZZ_GZDJD", Normalize(current.ZZ_GZDJD), Normalize(history.ZZ_GZDJD));
AddDiff(diffs, "ZZ_GZDCQ", Normalize(current.ZZ_GZDCQ), Normalize(history.ZZ_GZDCQ));
return diffs;
}
private static void AddDiff(List<string> diffs, string field, string current, string history)
{
if (!string.Equals(current ?? string.Empty, history ?? string.Empty, StringComparison.Ordinal))
{
diffs.Add($"{field}: [{history}] -> [{current}]");
}
}
private static string Normalize(string value) => value?.Trim() ?? string.Empty;
private static string NormalizeIdNo(string value) => value?.TrimStart() ?? string.Empty;
private static string FormatDate(DateTime? value) => value?.ToString("yyyy-MM-dd HH:mm:ss") ?? string.Empty;
private static string FormatDate(DateTime value) => value.ToString("yyyy-MM-dd HH:mm:ss");
}