using Dlhis.Basic.Api; using Dlhis.Entity.Basic.Entity; using Dlhis.Entity.Basic.Enums; using Dlhis.Sys.Api; using Kurisu.SqlSugar.Services; using SqlSugar; using Dlhis.Sys.Api.Response; using Dlhis.ScheduledTask.Common.Dto; using Dlhis.ScheduledTask.Common.Comparers; using Kurisu.AspNetCore.Utils.Extensions; using Dlhis.Basic.Api.Dtos; using Microsoft.AspNetCore.Mvc.Formatters; namespace Dlhis.ScheduledTask.Common.Services.Implements; public class GainfoUpdateService : IGainfoUpdateService { private readonly IDbContext _dbContext; private readonly ILogger _logger; private readonly ITenantApi _tenantApi; private readonly IBusinessPlacePermissionsApi _businessPlacePermissionsApi; private readonly IDevicePermissionApi _devicePermissionApi; private readonly IJinkoSapService _jinkoSapService; private List _tenants; private List _departmentChanges; private List _jobChanges; public GainfoUpdateService(IDbContext dbContext, ILogger logger, ITenantApi tenantApi, IBusinessPlacePermissionsApi businessPlacePermissionsApi, IDevicePermissionApi devicePermissionApi, IJinkoSapService jinkoSapService) { _dbContext = dbContext; _dbContext.Client.QueryFilter.Clear(); _logger = logger; _tenantApi = tenantApi; _businessPlacePermissionsApi = businessPlacePermissionsApi; _devicePermissionApi = devicePermissionApi; _jinkoSapService = jinkoSapService; } public async Task TodoByWerkAsync(string werk) { var werkInfo = await _dbContext.Queryable().Where(x => x.Werk == werk).SingleAsync(); werkInfo.LastSyncStartTime = DateTime.Now; werkInfo.HandleMessage = "任务执行中"; await _dbContext.UpdateAsync(werkInfo); try { //var pJson = "{\"KOSTL\":\"156020336\",\"ZLZRQ\":\"2023-10-30T00:00:00\",\"ZZ_SFZH\":\"\\\"140105200112051318\n\",\"STELL\":null,\"STELL_NM\":null,\"ZZ_KLX\":\"3\",\"PERNR\":\"00281800\",\"ZWORKCODE\":\"098250\",\"MASSN\":\"ZD\",\"MNTXT\":\"离职\",\"MASSG\":\"41\",\"MGTXT\":\"自离【失效】\",\"ZSTATUS\":\"5\",\"STAT2\":\"0\",\"BEGDA\":\"2023-10-30\",\"ENDDA\":\"9999-12-31\",\"WERKS\":\"1560\",\"PERSG\":\"2\",\"PERSK\":\"30\",\"BTRTL\":\"1560\",\"ANSVH\":\"4\",\"MOABW\":\"29\",\"ORGEH\":\"00210591\",\"PLANS\":\"99999999\",\"ZZ_ZYSF\":\"2\",\"ZZ_AQJB\":\"10\",\"ZZ_ZD\":\"3\",\"ZZ_SJGH\":\"30042938\",\"ZZ_BGZT\":\"2000\",\"Z_ZJ\":\"T0\",\"ZZ_XSQY\":null,\"ZZ_LOC\":\"海宁尖山\",\"ZZ_COUN\":\"中国\",\"ZZ_CITY\":\"海宁\",\"NACHN\":\"岳\",\"VORNA\":\"文超\",\"NAME\":\"岳文超\",\"GESCH\":\"1\",\"GBDAT\":\"2001-12-05T00:00:00\",\"NATIO\":\"CN\",\"ZZ_QFRQ\":\"2019-04-11\",\"ZMOBILE\":\"13773151205\",\"ZEMAIL\":\"wenchao.yue@jinkosolar.com\",\"ZADZH\":null,\"ZRZRQ\":\"2023-05-05T00:00:00\",\"DAT01\":\"2023-05-05\",\"ZCJRQ\":\"2023-05-05\",\"ZZZRQ\":\"2023-08-04\",\"ZXUELI\":\"高中/中专【失效】\",\"ZZ_ZPQD\":\"8\",\"ZZ_COUNNM\":null,\"ZZ_GZDJDNM\":\"海宁基地\",\"ZZ_GZDCQNM\":\"海宁尖山\"}"; //var personResp = new SapPersonResponse //{ // Person = new SapPerson // { // Items = new List // { // pJson.ToObject() // } // }, // DepartmentInfo = new SapPerson() // { // Items = new List() // }, // JobStatusInfo = new SapPerson() // { // Items = new List() // } //}; var personResp = await _jinkoSapService.GetPersonsByWerkAsync(werk); var persons = personResp.Person.Items; _departmentChanges = personResp.DepartmentInfo.Items; _jobChanges = personResp.JobStatusInfo.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) { var d = modifiedPersons.First(); _logger.LogInformation("差异信息:{json}", d.ToJson()); _logger.LogInformation("差异信息:{json}", (await _dbContext.Queryable().Where(x => x.ename == d.ZWORKCODE).FirstAsync())?.ToJson()); await SavePersonAsync(modifiedPersons); } } werkInfo.HandleMessage = "同步结束"; werkInfo.LastSyncEndTime = DateTime.Now; werkInfo.BackgroundJobKey = string.Empty; await _dbContext.UpdateAsync(werkInfo); } catch (Exception ex) { 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); var personResp = await _jinkoSapService.GetPersonsByCodeAsync(code); var persons = personResp.Person.Items; _departmentChanges = personResp.DepartmentInfo.Items; _jobChanges = personResp.JobStatusInfo.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); } private async Task SavePersonAsync(List persons) { var tenantResult = await _tenantApi.GetTenantsInternalAsync(); _tenants = tenantResult.Data; 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() .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(); int i = 0; var updates = ToGainfoSap(originUpdates); _logger.LogWarning("SAP分批更新数:{count}", updates.Count); var inserts = ToGainfoSap(originInserts); _logger.LogWarning("SAP分批新增数:{count}", inserts.Count); foreach (var item in inserts) { i++; try { var no = await InsertPersonAsync(item); _logger.LogWarning("执行新增成功 工号:{code},姓名:{name}", item.ename, item.gname); var rResult = await _devicePermissionApi.RePermissionUsersInfoAsync(new PermissionUsersInfoDto { UserNos = new List { no }, PermissionInfos = new Dictionary> { [no] = new List() } }); var r = rResult.Data; } catch (Exception ex) { _logger.LogError(ex, "执行新增失败:{message}", ex.Message); } } foreach (var item in updates) { i++; try { var no = await _dbContext.Queryable().Where(x => x.Code == item.ename).Select(x => x.No).SingleAsync(); if (no.IsPresent()) { var dtoResult = await _devicePermissionApi.GetPermissionUsersInfoAsync(new List { no }); var dto = dtoResult.Data; await UpdatePersonAsync(item); _logger.LogWarning("执行更新成功 工号:{code},姓名:{name}", item.ename, item.gname); await _devicePermissionApi.RePermissionUsersInfoAsync(dto); } else { await UpdatePersonAsync(item); _logger.LogWarning("执行更新成功 工号:{code},姓名:{name}", item.ename, item.gname); } } catch (Exception ex) { _logger.LogError(ex, "执行更新失败:{message}", ex.Message); } } } } private async Task InsertPersonAsync(GainfoSapEntity item) { await _dbContext.InsertAsync(item); var info = GainfoSapToGainfo(item); if (item.isowner == "T") { await _dbContext.InsertAsync(info); return info.No; } else { await _dbContext.Client.Insertable(info).AS("GainfoLeave").ExecuteCommandAsync(); return null; } } private GainfoEntity GainfoSapToGainfo(GainfoSapEntity item) { var info = new GainfoEntity { No = Guid.NewGuid().ToString(), SapNo = item.PERNR, Type = item.@class, 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 = _tenants.FirstOrDefault(x => x.Name == item.ZZ_GZDJDNM)?.Code ?? item.ZZ_GZDJDNM, Factory = _tenants.FirstOrDefault(x => x.Name == item.ZZ_GZDCQNM)?.Code ?? item.ZZ_GZDCQNM, }; return info; } private async Task UpdatePersonAsync(GainfoSapEntity item) { var gainfoSap = await _dbContext.Queryable().Where(x => x.ename == item.ename).FirstAsync(); await _dbContext.Updateable().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, ZZ_KLX = item.ZZ_KLX, createdate = item.createdate, ZZ_GZDJDNM = item.ZZ_GZDJDNM, ZZ_GZDCQNM = item.ZZ_GZDCQNM, }) .Where(x => x.ename == item.ename) .ExecuteCommandAsync(); //获取当前在职人员 var gainfo = await _dbContext.Queryable().Where(x => x.Code == item.ename).FirstAsync(); if (item.isowner == "T") { if (gainfo != null) { var workplace = _tenants.FirstOrDefault(x => x.Name == item.ZZ_GZDJDNM)?.Code ?? item.ZZ_GZDJDNM; var factory = _tenants.FirstOrDefault(x => x.Name == item.ZZ_GZDCQNM)?.Code ?? item.ZZ_GZDCQNM; await _dbContext.Updateable().SetColumns(g => new GainfoEntity { SapNo = 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 }) .Where(x => x.Code == item.ename) .ExecuteCommandAsync(); } else { var info = GainfoSapToGainfo(item); await _dbContext.InsertAsync(info); } } else { //离职 if (gainfo != null) { try { await _businessPlacePermissionsApi.ResetAsync(new Basic.Api.Request.GainfoPermissionResetRequest { IsLeave = true, UserNo = gainfo.No }); } catch (Exception ex) { _logger.LogError(ex, "离职任务生成失败:{message}", ex.Message); } //先写入离职表 gainfo.IdentityUserId = (int)gainfo.Id; gainfo.Id = 0; gainfo.ResignationDate = item.ZLZRQ; await _dbContext.Client.Insertable(gainfo).AS("GainfoLeave").ExecuteCommandAsync(); await _dbContext.DeleteReallyAsync(gainfo); } } return gainfo?.No; } private async Task> GetModifiedPersonAsync(List sapList) { var last = await LoadDataAsync(); if (last.Count <= 0) { return sapList; } var now = DateTime.Now; foreach (var item in sapList) { var a = _jobChanges.OrderByDescending(x => x.BEGDA).FirstOrDefault(x => x.ZWORKCODE == item.ZWORKCODE); if (a != null) { if (a.BEGDA >= now && a.ENDDA <= now) { if (a.STAT2 == "0") { item.STAT2 = "0"; item.ZSTATUS = "5"; } } } var b = _departmentChanges.OrderByDescending(x => x.BEGDA).FirstOrDefault(x => x.ZWORKCODE == item.ZWORKCODE); if (b != null) { if (b.BEGDA >= now && b.ENDDA <= now) { item.ORGEH = b.ORGEH; item.WERKS = b.WERKS; } } } var needRemove = sapList.Intersect(last, new SapPersonComparer()).ToList(); return sapList.Except(needRemove, new SapPersonComparer()).ToList(); } private async Task> LoadDataAsync() { //var pJson = "{\"id\":0,\"ano\":null,\"class\":\"C\",\"passwd\":null,\"question\":null,\"answer\":null,\"gname\":\"岳文超\",\"ename\":\"098250\",\"country\":null,\"idcls\":\"ID\",\"idno\":\"\\\"140105200112051318\n\",\"native\":\"14010\",\"sex\":\"M\",\"birthday\":\"2001-12-05T00:00:00\",\"address\":\"\",\"postcode\":null,\"occupation\":\"99\",\"appellation\":\"00210591\",\"nation\":\"01\",\"phone\":\"13773151205\",\"fax\":null,\"mobile\":null,\"email\":\"高中/中专【失效】\",\"web\":\"\",\"vip\":null,\"sec\":null,\"cropsno\":null,\"cropname\":null,\"fancy\":null,\"remark\":\"入职时间:2023-05-05 离职时间:2023-10-30 变更原因:自离【失效】\",\"amount\":0,\"days\":0,\"consume01\":0.0000,\"consume02\":0.0000,\"consume03\":0.0000,\"consume04\":0.0000,\"log_id\":\"XX\",\"log_shift\":\"1\",\"log_date\":null,\"log_ip\":\"127.0.0.1\",\"times\":0,\"logmark\":0,\"rmcode\":null,\"mkt\":null,\"src\":null,\"isowner\":\"F\",\"createdate\":\"2023-05-05T00:00:00\",\"PERNR\":\"00281800\",\"WERKS\":\"1560\",\"ZSTATUS\":\"5\",\"KOSTL\":\"156020336\",\"ZZ_ZD\":\"3\",\"Z_ZJ\":\"T0\",\"STELL\":null,\"STELL_NM\":null,\"ZLZRQ\":\"2023-10-30T00:00:00\",\"MASSN\":\"ZD\",\"MNTXT\":\"离职\",\"MASSG\":null,\"MGTXT\":null,\"logdate\":\"2024-03-14T00:02:34\",\"updatelogdate\":null,\"guestno\":null,\"ZZ_KLX\":\"3\",\"DAT01\":null,\"ZZ_COUNNM\":null,\"ZZ_GZDJDNM\":\"海宁基地\",\"ZZ_GZDCQNM\":\"海宁尖山\"}"; //var gainfos = new List() { pJson.ToObject() }; var gainfos = await _dbContext.Queryable().ToListAsync(); return gainfos.Select(x => new SapPersonItem { NAME = x.gname, ZWORKCODE = x.ename, ZZ_SFZH = x.idno, GBDAT = x.birthday, ZZ_KLX = x.ZZ_KLX, 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_GZDJDNM = x.ZZ_GZDJDNM, ZZ_GZDCQNM = x.ZZ_GZDCQNM }) .ToList(); } private static List ToGainfoSap(List data) { return data.Select(person => { GainfoSapEntity o = null; try { //var position = _positions.FirstOrDefault(x => x.No == person.PLANS); var rzrq = person.ZRZRQ; var lzrq = person.ZLZRQ; var rmk = $"入职时间:{rzrq.ToString("yyyy-MM-dd", System.Globalization.CultureInfo.InvariantCulture)} "; if (lzrq != null && lzrq.Value.ToString("yyyy-MM-dd") != "1900-01-01") rmk += $"离职时间:{lzrq.Value.ToString("yyyy-MM-dd", System.Globalization.CultureInfo.InvariantCulture)} "; if (!string.IsNullOrWhiteSpace(person.MGTXT)) rmk += $"变更原因:{person.MGTXT}"; var native = GetNative(person.ZZ_SFZH); var sex = person.GESCH == "2" ? "F" : "M"; person.ZZ_SFZH = person.ZZ_SFZH?.TrimStart(); o = new GainfoSapEntity { gname = person.NAME, ename = person.ZWORKCODE, idno = person.ZZ_SFZH, birthday = person.GBDAT, ZZ_KLX = person.ZZ_KLX, 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 = sex, logdate = DateTime.Now, isowner = int.Parse(person.ZSTATUS) < 5 ? "T" : "F", @class = "C", country = person.ZZ_COUNNM, log_ip = "127.0.0.1", log_shift = "1", log_id = "XX", address = "", occupation = "99", nation = "01", idcls = "ID", ZZ_COUNNM = person.ZZ_COUNNM, ZZ_GZDJDNM = person.ZZ_GZDJDNM, ZZ_GZDCQNM = person.ZZ_GZDCQNM, }; return o; } catch (Exception) { throw; } }).ToList(); } private static string GetNative(string idno) { if (string.IsNullOrWhiteSpace(idno) || idno.Length < 6) return null; idno = idno.TrimStart(); return idno[..6]; } }