diff --git a/Src/Dlhis.Entity/Basic/Entity/GainfoSap.cs b/Src/Dlhis.Entity/Basic/Entity/GainfoSap.cs index b9081d8e..8af49906 100644 --- a/Src/Dlhis.Entity/Basic/Entity/GainfoSap.cs +++ b/Src/Dlhis.Entity/Basic/Entity/GainfoSap.cs @@ -93,6 +93,11 @@ public class GainfoSapEntity public string guestno { get; set; } public string ZZ_KLX { get; set; } public DateTime? DAT01 { get; set; } + + public string ZZ_COUNNM { get; set; } + public string ZZ_GZDJDNM { get; set; } + public string ZZ_GZDCQNM { get; set; } + } diff --git a/Src/Dlhis.Entity/Basic/Entity/WerkEntity.cs b/Src/Dlhis.Entity/Basic/Entity/WerkEntity.cs new file mode 100644 index 00000000..6b6a7b76 --- /dev/null +++ b/Src/Dlhis.Entity/Basic/Entity/WerkEntity.cs @@ -0,0 +1,18 @@ +using Kurisu.SqlSugar; +using SqlSugar; + +namespace Dlhis.Entity.Basic.Entity; + +[SugarTable(TableName = "Werk", TableDescription = "人事范围")] +public class WerkEntity : SugarBaseEntity +{ + /// + /// 人事范围 + /// + public string Werk { get; set; } + + /// + /// 名称 + /// + public string Name { get; set; } +} diff --git a/Src/Dlhis.ScheduledTask/SyncSapInfo/Comparers/SapPersonComparer.cs b/Src/Dlhis.ScheduledTask/SyncSapInfo/Comparers/SapPersonComparer.cs index f0caf571..fdea7c12 100644 --- a/Src/Dlhis.ScheduledTask/SyncSapInfo/Comparers/SapPersonComparer.cs +++ b/Src/Dlhis.ScheduledTask/SyncSapInfo/Comparers/SapPersonComparer.cs @@ -33,7 +33,11 @@ public class SapPersonComparer : IEqualityComparer && x.MASSN == y.MASSN && x.MNTXT == y.MNTXT && (x.ZXUELI ?? string.Empty).Trim() == (y.ZXUELI ?? string.Empty).Trim() - && (x.ZZ_KLX ?? string.Empty) == (y.ZZ_KLX ?? string.Empty); + && (x.ZZ_KLX ?? string.Empty) == (y.ZZ_KLX ?? string.Empty) + && x.ZZ_COUNNM == y.ZZ_COUNNM + && x.ZZ_GZDJDNM == y.ZZ_GZDJDNM + && x.ZZ_GZDCQNM == y.ZZ_GZDCQNM + ; } public int GetHashCode(SapPersonItem obj) @@ -57,7 +61,11 @@ public class SapPersonComparer : IEqualityComparer ^ obj.MASSN.SafeGetHashCode() ^ obj.MNTXT.SafeGetHashCode() ^ obj.ZXUELI.SafeGetHashCode() - ^ (obj.ZZ_KLX ?? "").SafeGetHashCode(); + ^ (obj.ZZ_KLX ?? "").SafeGetHashCode() + ^ obj.ZZ_COUNNM.SafeGetHashCode() + ^ obj.ZZ_GZDJDNM.SafeGetHashCode() + ^ obj.ZZ_GZDCQNM.SafeGetHashCode() + ; } diff --git a/Src/Dlhis.ScheduledTask/SyncSapInfo/Dto/SapPerson.cs b/Src/Dlhis.ScheduledTask/SyncSapInfo/Dto/SapPerson.cs index a4a7db3c..a018be58 100644 --- a/Src/Dlhis.ScheduledTask/SyncSapInfo/Dto/SapPerson.cs +++ b/Src/Dlhis.ScheduledTask/SyncSapInfo/Dto/SapPerson.cs @@ -2,11 +2,8 @@ namespace Dlhis.ScheduledTask.SyncSapInfo.Dto; -public class SapPerson +public class SapPerson { - /// - /// - /// [JsonProperty("item")] - public List Items { get; set; } + public List Items { get; set; } } diff --git a/Src/Dlhis.ScheduledTask/SyncSapInfo/Dto/SapPersonDepartmentStatus.cs b/Src/Dlhis.ScheduledTask/SyncSapInfo/Dto/SapPersonDepartmentStatus.cs new file mode 100644 index 00000000..7711c882 --- /dev/null +++ b/Src/Dlhis.ScheduledTask/SyncSapInfo/Dto/SapPersonDepartmentStatus.cs @@ -0,0 +1,19 @@ +namespace Dlhis.ScheduledTask.SyncSapInfo.Dto +{ + public class SapPersonDepartmentStatus + { + public string ZWORKCODE { get; set; } + + public DateTime BEGDA { get; set; } + + public DateTime ENDDA { get; set; } + + public string WERKS { get; set; } + + /// + /// 部门号 + /// + public string ORGEH { get; set; } + + } +} diff --git a/Src/Dlhis.ScheduledTask/SyncSapInfo/Dto/SapPersonItem.cs b/Src/Dlhis.ScheduledTask/SyncSapInfo/Dto/SapPersonItem.cs index 42561eb9..998370f8 100644 --- a/Src/Dlhis.ScheduledTask/SyncSapInfo/Dto/SapPersonItem.cs +++ b/Src/Dlhis.ScheduledTask/SyncSapInfo/Dto/SapPersonItem.cs @@ -5,6 +5,7 @@ public class SapPersonItem public string KOSTL { get; set; } public string ZLZRQ { get; set; } + public string ZZ_SFZH { get; set; } public string STELL { get; set; } @@ -189,4 +190,19 @@ public class SapPersonItem /// /// public string ZZ_ZPQD { get; set; } + + /// + /// 国家 + /// + public string ZZ_COUNNM { get; set; } + + /// + /// 基地 + /// + public string ZZ_GZDJDNM { get; set; } + + /// + /// 厂区 + /// + public string ZZ_GZDCQNM { get; set; } } diff --git a/Src/Dlhis.ScheduledTask/SyncSapInfo/Dto/SapPersonJobStatus.cs b/Src/Dlhis.ScheduledTask/SyncSapInfo/Dto/SapPersonJobStatus.cs new file mode 100644 index 00000000..70e9b247 --- /dev/null +++ b/Src/Dlhis.ScheduledTask/SyncSapInfo/Dto/SapPersonJobStatus.cs @@ -0,0 +1,16 @@ +namespace Dlhis.ScheduledTask.SyncSapInfo.Dto +{ + public class SapPersonJobStatus + { + public string ZWORKCODE { get; set; } + + public DateTime BEGDA { get; set; } + + public DateTime ENDDA { get; set; } + + /// + /// 0离职 + /// + public int STAT2 { get; set; } + } +} diff --git a/Src/Dlhis.ScheduledTask/SyncSapInfo/Job/SyncOriginCardInfoJob.cs b/Src/Dlhis.ScheduledTask/SyncSapInfo/Job/SyncOriginCardInfoJob.cs new file mode 100644 index 00000000..b7161013 --- /dev/null +++ b/Src/Dlhis.ScheduledTask/SyncSapInfo/Job/SyncOriginCardInfoJob.cs @@ -0,0 +1,26 @@ +using Dlhis.ScheduledTask.SyncSapInfo.Services; + +namespace Dlhis.ScheduledTask.SyncSapInfo.Job; + +public class SyncOriginCardInfoJob +{ + private readonly IJinkoJIPService _jinkoJIPService; + + public SyncOriginCardInfoJob(IJinkoJIPService jinkoJIPService) + { + _jinkoJIPService = jinkoJIPService; + } + + public async Task RunAsync() + { + await _jinkoJIPService.UploadAttendancesAsync(new List() + { + new UploadAttendanceRequest() + { + RaiseTime = DateTime.Now, + ZWORKCODE = "000001", + ZNOTE = "正门1" + } + }); + } +} diff --git a/Src/Dlhis.ScheduledTask/SyncSapInfo/Job/SyncPersonJob.cs b/Src/Dlhis.ScheduledTask/SyncSapInfo/Job/SyncPersonJob.cs index 0502a332..3a135938 100644 --- a/Src/Dlhis.ScheduledTask/SyncSapInfo/Job/SyncPersonJob.cs +++ b/Src/Dlhis.ScheduledTask/SyncSapInfo/Job/SyncPersonJob.cs @@ -7,6 +7,9 @@ using Dlhis.ScheduledTask.SyncSapInfo.Comparers; using Dlhis.ScheduledTask.SyncSapInfo.Services; using Kurisu.AspNetCore.Scope; using Dlhis.Entity.Basic.Enums; +using Dlhis.Sys.Api; +using Dlhis.Sys.Api.Response; +using SqlSugar; namespace Dlhis.ScheduledTask.SyncSapInfo.Job; @@ -14,12 +17,15 @@ public class SyncPersonJob { private readonly ILogger _logger; private readonly IJinkoSapService _jinkoSapService; + private readonly ITenantApi _tenantApi; private List _positions; + private List _tenants; - public SyncPersonJob(ILogger logger, IJinkoSapService jinkoSapService) + public SyncPersonJob(ILogger logger, IJinkoSapService jinkoSapService, ITenantApi tenantApi) { _logger = logger; _jinkoSapService = jinkoSapService; + _tenantApi = tenantApi; } public async Task RunAsync() @@ -44,8 +50,11 @@ public class SyncPersonJob } } - private int SavePerson(List persons) + private async Task SavePerson(List persons) { + var tenantResult = await _tenantApi.GetTenantsInternalAsync(); + _tenants = tenantResult.Data; + var failure = 0; var workCodes = persons.Select(x => x.ZWORKCODE).ToList(); var chunks = workCodes.Chunk(4000).ToList(); @@ -67,7 +76,6 @@ public class SyncPersonJob 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 currentTotal = originUpdates.Count + originInserts.Count; @@ -137,6 +145,8 @@ public class SyncPersonJob Position = item.web, Remark = item.remark, Werks = item.WERKS, + Workplace = _tenants.FirstOrDefault(x => x.Name == item.ZZ_GZDJDNM)?.Code, + Factory = _tenants.FirstOrDefault(x => x.Name == item.ZZ_GZDCQNM)?.Code, }; if (item.isowner == "T") @@ -149,7 +159,7 @@ public class SyncPersonJob } } - + private void UpdatePerson(IDbContext db, GainfoSapEntity item) { var gainfoSap = db.Queryable().Where(x => x.ename == item.ename).First(); @@ -163,7 +173,9 @@ public class SyncPersonJob isowner = item.isowner, remark = item.remark, email = item.email, - WERKS = item.WERKS + WERKS = item.WERKS, + ZZ_GZDJDNM = item.ZZ_GZDJDNM, + ZZ_GZDCQNM = item.ZZ_GZDCQNM, }) .Where(x => x.ename == item.ename) .ExecuteCommand(); @@ -180,7 +192,9 @@ public class SyncPersonJob DepartmentNo = item.appellation, Remark = item.remark, Degree = item.email, - Werks = item.WERKS + Werks = item.WERKS, + Workplace = item.ZZ_GZDJDNM, + Factory = item.ZZ_GZDCQNM }) .Where(x => x.Code == item.ename) .ExecuteCommand(); @@ -288,15 +302,18 @@ public class SyncPersonJob sex = sex, web = SubString(position?.Name ?? "", 30), logdate = DateTime.Now, - isowner = int.Parse(person.ZSTATUS) < 4 ? "T" : "F", + isowner = int.Parse(person.ZSTATUS) < 5 ? "T" : "F", @class = "C", - country = "CN", + country = person.ZZ_COUNNM, log_ip = "127.0.0.1", log_shift = "1", log_id = "XX", address = "", occupation = "99", - nation = "01" + nation = "01", + ZZ_COUNNM = person.ZZ_COUNNM, + ZZ_GZDJDNM = person.ZZ_GZDJDNM, + ZZ_GZDCQNM = person.ZZ_GZDCQNM, }; return o; diff --git a/Src/Dlhis.ScheduledTask/SyncSapInfo/Response/SapPersonResponse.cs b/Src/Dlhis.ScheduledTask/SyncSapInfo/Response/SapPersonResponse.cs index cc9cbb75..956edf4e 100644 --- a/Src/Dlhis.ScheduledTask/SyncSapInfo/Response/SapPersonResponse.cs +++ b/Src/Dlhis.ScheduledTask/SyncSapInfo/Response/SapPersonResponse.cs @@ -9,5 +9,18 @@ public class SapPersonResponse /// /// [JsonProperty("T_PERSON")] - public SapPerson Person { get; set; } + public SapPerson Person { get; set; } + + /// + /// 离职状态 + /// + [JsonProperty("T_0000")] + public SapPerson JobStatusInfo { get; set; } + + /// + /// 部门变更信息 + /// + [JsonProperty("T_0001")] + public SapPerson DepartmentInfo { get; set; } + } diff --git a/Src/Dlhis.ScheduledTask/SyncSapInfo/Response/UploadAttendanceResponse.cs b/Src/Dlhis.ScheduledTask/SyncSapInfo/Response/UploadAttendanceResponse.cs new file mode 100644 index 00000000..4115ca77 --- /dev/null +++ b/Src/Dlhis.ScheduledTask/SyncSapInfo/Response/UploadAttendanceResponse.cs @@ -0,0 +1,12 @@ +namespace Dlhis.ScheduledTask.SyncSapInfo.Response +{ + public class UploadAttendanceResponse + { + /// + /// 0 成功 + /// + public string OLX { get; set; } + + public string OMS { get; set; } + } +} diff --git a/Src/Dlhis.ScheduledTask/SyncSapInfo/Services/IJinkoJIPService.cs b/Src/Dlhis.ScheduledTask/SyncSapInfo/Services/IJinkoJIPService.cs new file mode 100644 index 00000000..847e2635 --- /dev/null +++ b/Src/Dlhis.ScheduledTask/SyncSapInfo/Services/IJinkoJIPService.cs @@ -0,0 +1,9 @@ +using Dlhis.ScheduledTask.SyncSapInfo.Response; + +namespace Dlhis.ScheduledTask.SyncSapInfo.Services +{ + public interface IJinkoJIPService : ISingletonDependency + { + Task UploadAttendancesAsync(List requests); + } +} diff --git a/Src/Dlhis.ScheduledTask/SyncSapInfo/Services/Implements/JinkoJIPService.cs b/Src/Dlhis.ScheduledTask/SyncSapInfo/Services/Implements/JinkoJIPService.cs new file mode 100644 index 00000000..ed00b0eb --- /dev/null +++ b/Src/Dlhis.ScheduledTask/SyncSapInfo/Services/Implements/JinkoJIPService.cs @@ -0,0 +1,84 @@ +using System.IdentityModel.Tokens.Jwt; +using System.Net.Http.Headers; +using System.Security.Claims; +using System.Text; +using Dlhis.ScheduledTask.SyncSapInfo.Response; +using Kurisu.AspNetCore.Utils.Extensions; +using Microsoft.IdentityModel.Tokens; + +namespace Dlhis.ScheduledTask.SyncSapInfo.Services.Implements; + +public class JinkoJIPService : IJinkoJIPService +{ + private readonly IHttpClientFactory _httpClientFactory; + private readonly ILogger _logger; + + public JinkoJIPService(IHttpClientFactory httpClientFactory, ILogger logger) + { + _httpClientFactory = httpClientFactory; + _logger = logger; + } + + + private HttpClient GetHttpClient() + { + var httpClient = _httpClientFactory.CreateClient(); + //httpClient.BaseAddress = new Uri(""); + //httpClient.Timeout = TimeSpan.FromMinutes(10); + var key = "FACE-7409WIBX"; + var secret = "be0a4b88-cd80-4509-b9b9-865205d0d3d8"; + httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", IssueJwt(key, secret, 5)); + + return httpClient; + } + + + private static string IssueJwt(string jwtKey, string jwtSecret, int mins) + { + var now = DateTime.Now.AddMinutes(-mins); + var expires = DateTime.Now.AddMinutes(mins); + + var claims = new List + { + new Claim(JwtRegisteredClaimNames.Nbf,$"{new DateTimeOffset(now).ToUnixTimeSeconds()}"), + new Claim(JwtRegisteredClaimNames.Exp,$"{new DateTimeOffset(expires).ToUnixTimeSeconds()}"), + new Claim(JwtRegisteredClaimNames.Iss,jwtKey), + }; + + var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(jwtSecret)); + var descriptor = new SecurityTokenDescriptor + { + Subject = new ClaimsIdentity(claims), + Issuer = jwtKey, + IssuedAt = now, + NotBefore = now, + Expires = expires, + SigningCredentials = new SigningCredentials(key, SecurityAlgorithms.HmacSha256) + }; + + var jwtHandler = new JwtSecurityTokenHandler(); + var securityToken = jwtHandler.CreateToken(descriptor); + return jwtHandler.WriteToken(securityToken); + } + + public async Task UploadAttendancesAsync(List requests) + { + var body = new + { + T_DATA = requests, + }; + + var json = body.ToJson(); + + _logger.LogInformation("上传考勤记录请求:{json}", json); + + var content = new StringContent(json, Encoding.UTF8, "application/json"); + var response = await GetHttpClient().PostAsync("http://172.16.202.34:8000/JIP/HCM/HCM_SWIPE_DATA_SAVE", content); + var responseJson = await response.Content.ReadAsStringAsync(); + + _logger.LogInformation("上传考勤记录响应:{json}", responseJson); + + var r = responseJson.ToObject(); + return r; + } +} diff --git a/Src/Dlhis.ScheduledTask/SyncSapInfo/Services/Implements/JinkoSapService.cs b/Src/Dlhis.ScheduledTask/SyncSapInfo/Services/Implements/JinkoSapService.cs index 292b8f8e..05ceed7c 100644 --- a/Src/Dlhis.ScheduledTask/SyncSapInfo/Services/Implements/JinkoSapService.cs +++ b/Src/Dlhis.ScheduledTask/SyncSapInfo/Services/Implements/JinkoSapService.cs @@ -1,8 +1,9 @@ using System.Net.Http.Headers; using System.Text; +using Dlhis.Entity.Basic.Entity; using Dlhis.ScheduledTask.SyncSapInfo.Dto; using Dlhis.ScheduledTask.SyncSapInfo.Response; -using Dlhis.Sys.Api; +using Kurisu.SqlSugar.Services; using Newtonsoft.Json; namespace Dlhis.ScheduledTask.SyncSapInfo.Services.Implements; @@ -10,14 +11,14 @@ namespace Dlhis.ScheduledTask.SyncSapInfo.Services.Implements; public class JinkoSapService : IJinkoSapService { private readonly ILogger _logger; + private readonly IDbContext _dbContext; private readonly IHttpClientFactory _httpClientFactory; - private readonly ITenantApi _tenantApi; - public JinkoSapService(IHttpClientFactory httpClientFactory, ILogger logger, ITenantApi tenantApi) + public JinkoSapService(IHttpClientFactory httpClientFactory, ILogger logger, IDbContext dbContext) { _logger = logger; + _dbContext = dbContext; _httpClientFactory = httpClientFactory; - _tenantApi = tenantApi; } private HttpClient GetHttpClient() @@ -64,11 +65,13 @@ public class JinkoSapService : IJinkoSapService { var apiUrl = "/RESTAdapter/Rest/EHR_PERSONNEL/"; - var tenantResult = await _tenantApi.GetTenantsInternalAsync(); - var tenants = tenantResult.Data; + var werks = await _dbContext.Queryable().ToListAsync(); List persons = new(); - foreach (var item in tenants) + List jobInfos = new(); + List departmentInfos = new(); + + foreach (var item in werks) { try { @@ -80,7 +83,7 @@ public class JinkoSapService : IJinkoSapService { new { - WERKS = item.Code + WERKS = item.Werk } } }, @@ -99,6 +102,16 @@ public class JinkoSapService : IJinkoSapService { persons.AddRange(personResp.Person.Items); } + + if (personResp?.JobStatusInfo?.Items?.Any() == true) + { + jobInfos.AddRange(personResp.JobStatusInfo.Items); + } + + if (personResp?.DepartmentInfo?.Items?.Any() == true) + { + departmentInfos.AddRange(personResp.DepartmentInfo.Items); + } } catch (Exception ex) { @@ -108,10 +121,18 @@ public class JinkoSapService : IJinkoSapService return new SapPersonResponse() { - Person = new SapPerson + Person = new SapPerson { Items = persons }, + JobStatusInfo = new SapPerson + { + Items = jobInfos, + }, + DepartmentInfo = new SapPerson + { + Items = departmentInfos + } }; } } diff --git a/Src/Dlhis.ScheduledTask/SyncSapInfo/UploadAttendanceRequest.cs b/Src/Dlhis.ScheduledTask/SyncSapInfo/UploadAttendanceRequest.cs new file mode 100644 index 00000000..ac552237 --- /dev/null +++ b/Src/Dlhis.ScheduledTask/SyncSapInfo/UploadAttendanceRequest.cs @@ -0,0 +1,27 @@ +namespace Dlhis.ScheduledTask.SyncSapInfo +{ + public class UploadAttendanceRequest + { + /// + /// item.CardNo.TrimEnd('\0') + /// + public string ZWORKCODE { get; set; } + + public DateTime RaiseTime { get; set; } + + /// + /// yyyy-MM-dd + /// + public string ZDATE => RaiseTime.ToString("yyyy-MM-dd"); + + /// + /// HH:mm:ss + /// + public string ZTIME => RaiseTime.ToString("HH:mm:ss"); + + /// + /// 设备位置 + /// + public string ZNOTE { get; set; } + } +} diff --git a/Src/Gateway/ocelot.json b/Src/Gateway/ocelot.json index 903c8b82..46e3b225 100644 --- a/Src/Gateway/ocelot.json +++ b/Src/Gateway/ocelot.json @@ -1,18 +1,90 @@ { "Routes": [ { - "UpstreamPathTemplate": "/api/basic/{url}", - "UpstreamHttpMethod": [ "Get", "Post" ], + "UpstreamPathTemplate": "/api/oauth2/{url}", "DownstreamPathTemplate": "/api/{url}", "DownstreamScheme": "http", "DownstreamHostAndPorts": [ { - "Host": "localhost", - "Port": 5002 + "Host": "192.168.199.30", + "Port": 31001 + } + ] + }, + { + "UpstreamPathTemplate": "/api/common/{url}", + "DownstreamPathTemplate": "/api/{url}", + "DownstreamScheme": "http", + "DownstreamHostAndPorts": [ + { + "Host": "192.168.199.30", + "Port": 31002 + } + ] + }, + { + "UpstreamPathTemplate": "/api/sys/{url}", + "DownstreamPathTemplate": "/api/{url}", + "DownstreamScheme": "http", + "DownstreamHostAndPorts": [ + { + "Host": "192.168.199.30", + "Port": 31003 + } + ] + }, + { + "UpstreamPathTemplate": "/api/user/{url}", + "UpstreamHttpMethod": [ + "Get", + "Post" + ], + "DownstreamPathTemplate": "/api/{url}", + "DownstreamScheme": "http", + "DownstreamHostAndPorts": [ + { + "Host": "192.168.199.30", + "Port": 31004 + } + ] + }, + { + "UpstreamPathTemplate": "/api/basic/{url}", + "UpstreamHttpMethod": [ + "Get", + "Post" + ], + "DownstreamPathTemplate": "/api/{url}", + "DownstreamScheme": "http", + "DownstreamHostAndPorts": [ + { + "Host": "192.168.199.30", + "Port": 31005 + } + ] + }, + { + "UpstreamPathTemplate": "/api/scheduled/{url}", + "DownstreamPathTemplate": "/api/{url}", + "DownstreamScheme": "http", + "DownstreamHostAndPorts": [ + { + "Host": "192.168.199.30", + "Port": 31006 + } + ] + }, + { + "UpstreamPathTemplate": "/api/canteen/{url}", + "DownstreamPathTemplate": "/api/{url}", + "DownstreamScheme": "http", + "DownstreamHostAndPorts": [ + { + "Host": "192.168.199.30", + "Port": 31007 } ] } ], - "GlobalConfiguration": { - } + "GlobalConfiguration": {} } \ No newline at end of file