diff --git a/Src/Dlhis.ScheduledTask/App.config b/Src/Dlhis.ScheduledTask/App.config
new file mode 100644
index 00000000..fb37bfe6
--- /dev/null
+++ b/Src/Dlhis.ScheduledTask/App.config
@@ -0,0 +1,75 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Src/Dlhis.ScheduledTask/Comparers/ZHRS_ORGComparer.cs b/Src/Dlhis.ScheduledTask/Comparers/ZHRS_ORGComparer.cs
new file mode 100644
index 00000000..a65d70a6
--- /dev/null
+++ b/Src/Dlhis.ScheduledTask/Comparers/ZHRS_ORGComparer.cs
@@ -0,0 +1,22 @@
+using Dlhis.ScheduledTask.Extensions;
+using Dlhis.ScheduledTask.WsProxy;
+
+namespace Dlhis.ScheduledTask.Comparers
+{
+ internal class ZHRS_ORGComparer : IEqualityComparer
+ {
+ public bool Equals(ZHRS_ORG x, ZHRS_ORG y)
+ {
+ if (ReferenceEquals(x, y)) return true;
+ if (ReferenceEquals(x, null)) return false;
+ if (ReferenceEquals(y, null)) return false;
+ if (x.GetType() != y.GetType()) return false;
+ return x.OBJID == y.OBJID && x.STEXT == y.STEXT && x.SOBID == y.SOBID;
+ }
+
+ public int GetHashCode(ZHRS_ORG obj)
+ {
+ return obj.OBJID.SafeGetHashCode() ^ obj.STEXT.SafeGetHashCode() ^ obj.SOBID.SafeGetHashCode();
+ }
+ }
+}
diff --git a/Src/Dlhis.ScheduledTask/Comparers/ZHRS_PERSONComparer.cs b/Src/Dlhis.ScheduledTask/Comparers/ZHRS_PERSONComparer.cs
new file mode 100644
index 00000000..7fe514fb
--- /dev/null
+++ b/Src/Dlhis.ScheduledTask/Comparers/ZHRS_PERSONComparer.cs
@@ -0,0 +1,92 @@
+using Dlhis.ScheduledTask.Dto;
+using Dlhis.ScheduledTask.Extensions;
+using System.Text;
+
+namespace Dlhis.ScheduledTask
+{
+ internal class ZHRS_PERSONComparer : IEqualityComparer
+ {
+ public bool Equals(PersonDetail x, PersonDetail y)
+ {
+ if (ReferenceEquals(x, y)) return true;
+ if (ReferenceEquals(x, null)) return false;
+ if (ReferenceEquals(y, null)) return false;
+
+ return x.PERNR == y.PERNR
+ && x.WERKS == y.WERKS
+ && SubString(x.ORGEH, 10) == SubString(y.ORGEH, 10)
+ && SubString(x.NAME, 50) == SubString(y.NAME, 50)
+ && SafeParseDate(x.GBDAT) == SafeParseDate(y.GBDAT)
+ && SubString(x.ZZ_SFZH, 18) == SubString(y.ZZ_SFZH, 18)
+ && SubString(x.ZWORKCODE, 50) == SubString(y.ZWORKCODE, 50)
+ && SubString(x.ZMOBILE, 20) == SubString(y.ZMOBILE, 20)
+ && x.ZSTATUS == y.ZSTATUS
+ && x.KOSTL == y.KOSTL
+ && x.ZZ_ZD == y.ZZ_ZD
+ && x.Z_ZJ == y.Z_ZJ
+ && x.ZRZRQ == y.ZRZRQ
+ && SafeParseDate(x.ZLZRQ) == SafeParseDate(y.ZLZRQ)
+ && x.STELL == y.STELL
+ && x.STELL_NM == y.STELL_NM
+ && 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);
+ }
+
+ public int GetHashCode(PersonDetail obj)
+ {
+ return obj.PERNR.SafeGetHashCode()
+ ^ obj.WERKS.SafeGetHashCode()
+ ^ SubString(obj.ORGEH, 10).SafeGetHashCode()
+ ^ SubString(obj.NAME, 50).SafeGetHashCode()
+ ^ SafeParseDate(obj.GBDAT).SafeGetHashCode()
+ ^ SubString(obj.ZZ_SFZH, 18).SafeGetHashCode()
+ ^ SubString(obj.ZWORKCODE, 50).SafeGetHashCode()
+ ^ SubString(obj.ZMOBILE, 20).SafeGetHashCode()
+ ^ obj.ZSTATUS.SafeGetHashCode()
+ ^ obj.KOSTL.SafeGetHashCode()
+ ^ obj.ZZ_ZD.SafeGetHashCode()
+ ^ obj.Z_ZJ.SafeGetHashCode()
+ ^ obj.ZRZRQ.SafeGetHashCode()
+ ^ SafeParseDate(obj.ZLZRQ).SafeGetHashCode()
+ ^ obj.STELL.SafeGetHashCode()
+ ^ obj.STELL_NM.SafeGetHashCode()
+ ^ obj.MASSN.SafeGetHashCode()
+ ^ obj.MNTXT.SafeGetHashCode()
+ ^ obj.ZXUELI.SafeGetHashCode()
+ ^ (obj.ZZ_KLX ?? "").SafeGetHashCode();
+ }
+
+
+ private string SubString(string s, int len)
+ {
+ if (string.IsNullOrWhiteSpace(s))
+ {
+ return s?.Trim() ?? "";
+ }
+ s = s.Trim();
+ var bs = Encoding.UTF8.GetBytes(s);
+ if (bs.Length <= len)
+ {
+ return s;
+ }
+ var bytes = new byte[len];
+ Buffer.BlockCopy(bs, 0, bytes, 0, len);
+ return Encoding.UTF8.GetString(bytes);
+ }
+
+
+ private DateTime? SafeParseDate(string str)
+ {
+ if (str == "0000-00-00" || str == "0001-01-01" || str == "1900-01-01")
+ return null;
+
+ if (DateTime.TryParse(str, out var d))
+ {
+ return d;
+ }
+ return null;
+ }
+ }
+}
diff --git a/Src/Dlhis.ScheduledTask/Comparers/ZHRS_POSTComparer.cs b/Src/Dlhis.ScheduledTask/Comparers/ZHRS_POSTComparer.cs
new file mode 100644
index 00000000..d74e200e
--- /dev/null
+++ b/Src/Dlhis.ScheduledTask/Comparers/ZHRS_POSTComparer.cs
@@ -0,0 +1,21 @@
+using Dlhis.ScheduledTask.WsProxy;
+
+namespace Dlhis.ScheduledTask.Comparers
+{
+ internal class ZHRS_POSTComparer : IEqualityComparer
+ {
+ public bool Equals(ZHRS_POST x, ZHRS_POST y)
+ {
+ if (ReferenceEquals(x, y)) return true;
+ if (ReferenceEquals(x, null)) return false;
+ if (ReferenceEquals(y, null)) return false;
+ if (x.GetType() != y.GetType()) return false;
+ return x.ZJOBID == y.ZJOBID && x.ZJOBNAME == y.ZJOBNAME && x.ZJOBACTID == y.ZJOBACTID && x.ZDEPID == y.ZDEPID;
+ }
+
+ public int GetHashCode(ZHRS_POST obj)
+ {
+ return obj.ZJOBID.SafeGetHashCode() ^ obj.ZJOBNAME.SafeGetHashCode() ^ obj.ZJOBACTID.SafeGetHashCode() ^ obj.ZDEPID.SafeGetHashCode();
+ }
+ }
+}
diff --git a/Src/Dlhis.ScheduledTask/Configurations/ServiceSettings.cs b/Src/Dlhis.ScheduledTask/Configurations/ServiceSettings.cs
new file mode 100644
index 00000000..a17dceea
--- /dev/null
+++ b/Src/Dlhis.ScheduledTask/Configurations/ServiceSettings.cs
@@ -0,0 +1,102 @@
+using System;
+using System.Configuration;
+using ConfigurationManager = System.Configuration.ConfigurationManager;
+
+
+namespace Dlhis.ScheduledTask.Configurations
+{
+ public class ServiceSettings
+ {
+ public string ServerUrl { get; private set; }
+
+ public string UserName { get; private set; }
+
+ public string Password { get; private set; }
+
+ public string SyncTime { get; private set; }
+ public int AttendanceUploadInterval { get; private set; }
+ public string AttendanceUploadUrl { get; private set; }
+ public string DlhisDatabase { get; private set; }
+
+ public string Werks { get; private set; }
+
+ public DateTime BeginSyncDate { get; private set; }
+ public int ApiPort { get; private set; }
+ public string EHRWebServiceUserName { get; set; }
+ public string EHRWebServicePassword { get; set; }
+ public string EHRInsertRecordApiUrl { get; set; }
+ public string EHRDeleteRecordApiUrl { get; set; }
+
+ public string EHRSavePhotoApiUrl { get; set; }
+
+
+ ///
+ /// 获取员工卡片信息RESUT地址
+ ///
+ public string EHR_GET_WORK_CARD_INFOApiUrl { get; set; }
+
+ ///
+ /// REST账号
+ ///
+ public string RestUserName { get; set; }
+
+ ///
+ /// REST密码
+ ///
+ public string RestPassword { get; set; }
+ public ServiceSettings()
+ {
+ ServerUrl = ConfigurationManager.AppSettings[nameof(ServerUrl)];
+ UserName = ConfigurationManager.AppSettings[nameof(UserName)];
+ Password = ConfigurationManager.AppSettings[nameof(Password)];
+ SyncTime = ConfigurationManager.AppSettings[nameof(SyncTime)];
+ DlhisDatabase = ConfigurationManager.AppSettings[nameof(DlhisDatabase)];
+ AttendanceUploadUrl = ConfigurationManager.AppSettings[nameof(AttendanceUploadUrl)];
+ AttendanceUploadInterval = SafeParseInt(ConfigurationManager.AppSettings[nameof(AttendanceUploadInterval)]);
+ Werks = ConfigurationManager.AppSettings[nameof(Werks)];
+ BeginSyncDate = SafeParseDate(ConfigurationManager.AppSettings[nameof(BeginSyncDate)], DateTime.Today);
+ ApiPort = SafeParseInt(ConfigurationManager.AppSettings[nameof(ApiPort)], 8099);
+ EHRWebServiceUserName = ConfigurationManager.AppSettings[nameof(EHRWebServiceUserName)];
+ EHRWebServicePassword = ConfigurationManager.AppSettings[nameof(EHRWebServicePassword)];
+ EHRInsertRecordApiUrl = ConfigurationManager.AppSettings[nameof(EHRInsertRecordApiUrl)];
+ EHRDeleteRecordApiUrl = ConfigurationManager.AppSettings[nameof(EHRDeleteRecordApiUrl)];
+ EHRSavePhotoApiUrl = ConfigurationManager.AppSettings[nameof(EHRSavePhotoApiUrl)];
+ EHR_GET_WORK_CARD_INFOApiUrl = ConfigurationManager.AppSettings[nameof(EHR_GET_WORK_CARD_INFOApiUrl)];
+ RestUserName = ConfigurationManager.AppSettings[nameof(RestUserName)];
+ RestPassword = ConfigurationManager.AppSettings[nameof(RestPassword)];
+ }
+
+ private static int SafeParseInt(string value, int defaultValue = 0)
+ {
+ if (int.TryParse(value, out int i))
+ {
+ return i;
+ }
+ return defaultValue;
+ }
+ private static bool SafeParseBoolean(string value, bool defaultValue = false)
+ {
+ if (bool.TryParse(value, out var b))
+ {
+ return b;
+ }
+ return defaultValue;
+ }
+ private static DateTime SafeParseDate(string value, DateTime defaultValue)
+ {
+ if (DateTime.TryParse(value, out var b))
+ {
+ return b;
+ }
+ return defaultValue;
+ }
+
+ public void SetBeginSyncDate(DateTime beginSyncDate)
+ {
+ BeginSyncDate = beginSyncDate;
+ Configuration config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
+ config.AppSettings.Settings[nameof(BeginSyncDate)].Value = beginSyncDate.ToString("yyyy-MM-dd");
+ config.Save(ConfigurationSaveMode.Modified);
+ }
+ }
+}
diff --git a/Src/Dlhis.ScheduledTask/Dlhis.ScheduledTask.csproj b/Src/Dlhis.ScheduledTask/Dlhis.ScheduledTask.csproj
index 6aa4680e..0e2c2f98 100644
--- a/Src/Dlhis.ScheduledTask/Dlhis.ScheduledTask.csproj
+++ b/Src/Dlhis.ScheduledTask/Dlhis.ScheduledTask.csproj
@@ -21,6 +21,7 @@
+
diff --git a/Src/Dlhis.ScheduledTask/Dto/Person.cs b/Src/Dlhis.ScheduledTask/Dto/Person.cs
new file mode 100644
index 00000000..8ee5479f
--- /dev/null
+++ b/Src/Dlhis.ScheduledTask/Dto/Person.cs
@@ -0,0 +1,203 @@
+namespace Dlhis.ScheduledTask.Dto
+{
+ public class PersonDetail
+ {
+ public string KOSTL { get; set; }
+
+ public string ZLZRQ { get; set; }
+ public string ZZ_SFZH { get; set; }
+
+ public string STELL { get; set; }
+
+ public string STELL_NM { get; set; }
+
+ public string ZZ_KLX { get; set; }
+
+ ///
+ ///
+ ///
+ public string PERNR { get; set; }
+ ///
+ ///
+ ///
+ public string ZWORKCODE { get; set; }
+ ///
+ ///
+ ///
+ public string MASSN { get; set; }
+ ///
+ /// 数据变更
+ ///
+ public string MNTXT { get; set; }
+ ///
+ ///
+ ///
+ public string MASSG { get; set; }
+ ///
+ /// 数据变更
+ ///
+ public string MGTXT { get; set; }
+ ///
+ ///
+ ///
+ public string ZSTATUS { get; set; }
+ ///
+ ///
+ ///
+ public string STAT2 { get; set; }
+ ///
+ ///
+ ///
+ public string BEGDA { get; set; }
+ ///
+ ///
+ ///
+ public string ENDDA { get; set; }
+ ///
+ ///
+ ///
+ public string WERKS { get; set; }
+ ///
+ ///
+ ///
+ public string PERSG { get; set; }
+ ///
+ ///
+ ///
+ public string PERSK { get; set; }
+ ///
+ ///
+ ///
+ public string BTRTL { get; set; }
+ ///
+ ///
+ ///
+ public string ANSVH { get; set; }
+ ///
+ ///
+ ///
+ public string MOABW { get; set; }
+ ///
+ ///
+ ///
+ public string ORGEH { get; set; }
+ ///
+ ///
+ ///
+ public string PLANS { get; set; }
+ ///
+ ///
+ ///
+ public string ZZ_ZYSF { get; set; }
+ ///
+ ///
+ ///
+ public string ZZ_AQJB { get; set; }
+ ///
+ ///
+ ///
+ public string ZZ_ZD { get; set; }
+ ///
+ ///
+ ///
+ public string ZZ_SJGH { get; set; }
+ ///
+ ///
+ ///
+ public string ZZ_BGZT { get; set; }
+ ///
+ ///
+ ///
+ public string Z_ZJ { get; set; }
+ ///
+ ///
+ ///
+ public string ZZ_XSQY { get; set; }
+ ///
+ /// 上海
+ ///
+ public string ZZ_LOC { get; set; }
+ ///
+ ///
+ ///
+ public string ZZ_COUN { get; set; }
+ ///
+ ///
+ ///
+ public string ZZ_CITY { get; set; }
+ ///
+ ///
+ ///
+ public string NACHN { get; set; }
+ ///
+ ///
+ ///
+ public string VORNA { get; set; }
+ ///
+ ///
+ ///
+ public string NAME { get; set; }
+ ///
+ ///
+ ///
+ public string GESCH { get; set; }
+ ///
+ ///
+ ///
+ public string GBDAT { get; set; }
+ ///
+ ///
+ ///
+ public string NATIO { get; set; }
+ ///
+ ///
+ ///
+ public string ZZ_QFRQ { get; set; }
+ ///
+ ///
+ ///
+ public string ZMOBILE { get; set; }
+ ///
+ ///
+ ///
+ public string ZEMAIL { get; set; }
+ ///
+ ///
+ ///
+ public string ZADZH { get; set; }
+ ///
+ ///
+ ///
+ public string ZRZRQ { get; set; }
+ ///
+ ///
+ ///
+ public string DAT01 { get; set; }
+ ///
+ ///
+ ///
+ public string ZCJRQ { get; set; }
+ ///
+ ///
+ ///
+ public string ZZZRQ { get; set; }
+ ///
+ /// 本科
+ ///
+ public string ZXUELI { get; set; }
+ ///
+ ///
+ ///
+ public string ZZ_ZPQD { get; set; }
+ }
+
+ public class T_PERSON
+ {
+ ///
+ ///
+ ///
+ public List item { get; set; }
+ }
+
+
+}
diff --git a/Src/Dlhis.ScheduledTask/Entities/GainfoSap.cs b/Src/Dlhis.ScheduledTask/Entities/GainfoSap.cs
new file mode 100644
index 00000000..a32ce79f
--- /dev/null
+++ b/Src/Dlhis.ScheduledTask/Entities/GainfoSap.cs
@@ -0,0 +1,115 @@
+namespace Dlhis.ScheduledTask.Entities
+{
+ public class GainfoSap
+ {
+ public GainfoSap()
+ {
+
+ }
+
+ [PkColumn]
+ public int id { get; set; }
+
+ public string ano { get; set; }
+ public string @class { get; set; }
+
+ public string passwd { get; set; }
+ public string question { get; set; }
+
+ public string answer { get; set; }
+ public string gname { get; set; }
+
+ [UpdateColumn]
+ public string ename { get; set; }
+
+ public string country { get; set; }
+ public string idcls { get; set; }
+ public string idno { get; set; }
+ public string native { get; set; }
+ public string sex { get; set; }
+ public DateTime? birthday { get; set; }
+ public string address { get; set; }
+ public string postcode { get; set; }
+ public string occupation { get; set; }
+ public string appellation { get; set; }
+ public string nation { get; set; }
+ public string phone { get; set; }
+ public string fax { get; set; }
+ public string mobile { get; set; }
+ public string email { get; set; }
+ public string web { get; set; }
+ public string vip { get; set; }
+ public string sec { get; set; }
+ public string cropsno { get; set; }
+ public string cropname { get; set; }
+ public string fancy { get; set; }
+ public string remark { get; set; }
+
+ public int amount { get; set; }
+ public int days { get; set; }
+ public decimal consume01 { get; set; }
+
+ public decimal consume02 { get; set; }
+
+ public decimal consume03 { get; set; }
+
+ public decimal consume04 { get; set; }
+ public string log_id { get; set; }
+ public string log_shift { get; set; }
+ public DateTime? log_date { get; set; }
+ public string log_ip { get; set; }
+ public int times { get; set; }
+ public int logmark { get; set; }
+ public string rmcode { get; set; }
+ public string mkt { get; set; }
+ public string src { get; set; }
+ public string isowner { get; set; }
+ public DateTime? createdate { get; set; }
+
+ public string PERNR { get; set; }
+
+ public string WERKS { get; set; }
+
+ public string ZSTATUS { get; set; }
+
+ public string KOSTL { get; set; }
+
+ public string ZZ_ZD { get; set; }
+
+ public string Z_ZJ { get; set; }
+
+ public string STELL { get; set; }
+
+ public string STELL_NM { get; set; }
+
+ public DateTime? ZLZRQ { get; set; }
+
+ public string MASSN { get; set; }
+
+ public string MNTXT { get; set; }
+ public string MASSG { get; set; }
+ public string MGTXT { get; set; }
+ public DateTime? logdate { get; set; }
+ public DateTime? updatelogdate { get; set; }
+ public string guestno { get; set; }
+ public string ZZ_KLX { get; set; }
+ public DateTime? DAT01 { get; set; }
+ }
+
+
+ public class UpdateColumnAttribute : Attribute
+ {
+
+ }
+
+ public class PkColumnAttribute : Attribute
+ {
+
+ }
+
+
+ public class IgnoreColumnAttribute : Attribute
+ {
+
+ }
+}
diff --git a/Src/Dlhis.ScheduledTask/Extensions/DbConnectionExtensions.cs b/Src/Dlhis.ScheduledTask/Extensions/DbConnectionExtensions.cs
new file mode 100644
index 00000000..30da5522
--- /dev/null
+++ b/Src/Dlhis.ScheduledTask/Extensions/DbConnectionExtensions.cs
@@ -0,0 +1,122 @@
+using log4net;
+using System.Data.SqlClient;
+using System.Data;
+using Dapper;
+using Dlhis.ScheduledTask.Job;
+
+namespace Dlhis.ScheduledTask.Extensions
+{
+ public static class DbConnectionExtensions
+ {
+ private static readonly ILog log = LogManager.GetLogger(typeof(JinkoHrJob));
+
+ public static void BulkcopyInsert(this IDbConnection conn, string tableName, List data)
+ {
+ using (var bulkcopy = new SqlBulkCopy(conn as SqlConnection))
+ {
+ bulkcopy.BatchSize = 10000;
+ bulkcopy.BulkCopyTimeout = 60;
+ bulkcopy.DestinationTableName = tableName;
+ var dt = ToDataTable(data);
+ foreach (DataColumn column in dt.Columns)
+ {
+ bulkcopy.ColumnMappings.Add(new SqlBulkCopyColumnMapping(column.ColumnName, column.ColumnName));
+ }
+
+ bulkcopy.WriteToServer(dt);
+ }
+ }
+
+
+ private static DataTable ToDataTable(List data)
+ {
+ var dt = new DataTable();
+ var properties = typeof(T).GetProperties();//.Where(x => x.IsDefined(typeof(CopyAttribute), false));
+
+ foreach (var property in properties)
+ {
+ dt.Columns.Add(property.Name, Nullable.GetUnderlyingType(property.PropertyType) ?? property.PropertyType);
+ }
+
+ foreach (var item in data)
+ {
+ var values = new object[properties.Length];
+ for (int i = 0; i < properties.Length; i++)
+ {
+ if (properties[i].PropertyType == typeof(DateTime?))
+ {
+ var o = (DateTime?)properties[i].GetValue(item);
+ if (!o.HasValue || o.Value == DateTime.MinValue)
+ {
+ o = new DateTime(1900, 1, 1);
+ }
+ values[i] = o;
+ }
+ else
+ {
+ var o = properties[i].GetValue(item);
+ values[i] = o;
+ }
+
+ }
+
+ dt.Rows.Add(values);
+ }
+
+ return dt;
+ }
+
+
+
+ public static void BulkcopyUpdate(this IDbConnection conn, string targetTableName, List data)
+ {
+ var tmpTable = "#tmp_" + targetTableName;
+ try
+ {
+ //go 语法错误 ???
+ conn.Execute($@"
+if object_id('tempdb..{tmpTable}') is not null
+drop table {tmpTable}");
+
+ conn.Execute($@"
+select *
+into {tmpTable}
+from {targetTableName} where 1=2 ;");
+
+ conn.BulkcopyInsert(tmpTable, data);
+
+ var properties = typeof(T).GetProperties();
+ var updates = properties.Where(x => !x.Name.Equals("ename"))
+ .Where(x => !x.Name.Equals("id"))
+ .Where(x => !x.Name.Equals("timeid"))
+ .Select(x =>
+ {
+ return $"T.{x.Name}=S.{x.Name}";
+ });
+
+ var updateScript = string.Join(",", updates);
+
+ var merge = $@"
+Merge into {targetTableName} AS T
+Using {tmpTable} AS S
+ON T.ename = S.ename
+WHEN MATCHED
+THEN UPDATE SET {updateScript} ;
+";
+
+ conn.Execute(merge);
+ }
+ catch (Exception ex)
+ {
+ log.Error($"批量更新失败:{ex.Message}", ex);
+ }
+ finally
+ {
+ conn.Execute($@"
+drop table {tmpTable}
+"
+);
+ }
+ }
+ }
+}
diff --git a/Src/Dlhis.ScheduledTask/Extensions/EnumerableExtensions.cs b/Src/Dlhis.ScheduledTask/Extensions/EnumerableExtensions.cs
new file mode 100644
index 00000000..caa57d0c
--- /dev/null
+++ b/Src/Dlhis.ScheduledTask/Extensions/EnumerableExtensions.cs
@@ -0,0 +1,13 @@
+namespace Dlhis.ScheduledTask.Extensions
+{
+ public static class EnumerableExtensions
+ {
+ public static IEnumerable> Chunk(this IEnumerable arr, int size)
+ {
+ for (var i = 0; i < arr.Count() / size + 1; i++)
+ {
+ yield return arr.Skip(i * size).Take(size);
+ }
+ }
+ }
+}
diff --git a/Src/Dlhis.ScheduledTask/Extensions/GetHashCodeExtensions.cs b/Src/Dlhis.ScheduledTask/Extensions/GetHashCodeExtensions.cs
new file mode 100644
index 00000000..d0db1f4c
--- /dev/null
+++ b/Src/Dlhis.ScheduledTask/Extensions/GetHashCodeExtensions.cs
@@ -0,0 +1,16 @@
+namespace Dlhis.ScheduledTask.Extensions
+{
+ internal static class GetHashCodeExtensions
+ {
+ public static int SafeGetHashCode(this object o)
+ {
+ if (o == null) return 0;
+ return o.GetHashCode();
+ }
+
+ public static int SafeGetHashCode(this int o)
+ {
+ return o.GetHashCode();
+ }
+ }
+}
diff --git a/Src/Dlhis.ScheduledTask/Job/JinkoHrJob.cs b/Src/Dlhis.ScheduledTask/Job/JinkoHrJob.cs
new file mode 100644
index 00000000..c4d1407c
--- /dev/null
+++ b/Src/Dlhis.ScheduledTask/Job/JinkoHrJob.cs
@@ -0,0 +1,476 @@
+using Dlhis.ScheduledTask.Configurations;
+using Dlhis.ScheduledTask.Dto;
+using Dlhis.ScheduledTask.Entities;
+using Dlhis.ScheduledTask.Response;
+using Hangfire.Logging;
+using Microsoft.AspNetCore.SignalR;
+using Microsoft.Extensions.DependencyModel;
+using Newtonsoft.Json;
+using Serilog;
+using System.Data.SqlClient;
+using System.Data;
+using System.Net;
+using System.Net.Http.Headers;
+using System.Text;
+using static Dapper.SqlMapper;
+using Dlhis.ScheduledTask.WsProxy;
+using log4net;
+
+namespace Dlhis.ScheduledTask.Job
+{
+ public class JinkoHrJob
+ {
+ private IDisposable webApp;
+ private static readonly log4net.ILog log = LogManager.GetLogger(typeof(JinkoHrJob));
+ const string ORG_CACHE_FILE = "org.json";
+ const string POSITION_CACHE_FILE = "position.json";
+ const string PERSON_CACHE_FILE = "person.json";
+
+ private List lastUpdatedPersonList = new List();
+ private List lastUpdatedOrgList = new List();
+ private List lastUpdatedPositionList = new List();
+ private readonly ZHRF_SYN_01 orgClient;
+ private readonly ZHRF_SYN_02 positionClient;
+ private readonly ZHRF_SYN_03N archivesClient;
+ private readonly ZHRF_SWIPE_DATA_SAVE_CLIENT dataSaveClient;
+ private readonly SI_DLDM2EHR_InsertRecord_OutServiceClient insertRecord_OutService;
+ private readonly SI_DLDM2EHR_DeleteRecord_OutServiceClient deleteRecord_OutService;
+
+ public ServiceSettings Settings { get; }
+ private readonly ZHRS_WERKS[] werks;
+ volatile bool started = false;
+ public JinkoHrJob(ServiceSettings settings)
+ {
+ Settings = settings;
+ var list = new List();
+ if (!string.IsNullOrWhiteSpace(Settings.Werks))
+ {
+ var ss = Settings.Werks.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
+ foreach (var w in ss)
+ {
+ list.Add(new ZHRS_WERKS() { WERKS = w });
+ }
+ werks = list.ToArray();
+ }
+ else
+ {
+ werks = Array.Empty();
+ }
+ orgClient = new ZHRF_SYN_01()
+ {
+ Url = Settings.ServerUrl + "/sap/bc/srt/rfc/sap/zhrf_syn_01/800/zhrf_syn_01/zhrf_syn_01",
+ Credentials = new NetworkCredential(Settings.UserName, Settings.Password),
+ Timeout = 10000000,
+ };
+ positionClient = new ZHRF_SYaN_02()
+ {
+ Url = Settings.ServerUrl + "/sap/bc/srt/rfc/sap/zhrf_syn_02/800/zhrf_syn_02/zhrf_syn_02",
+ Credentials = new NetworkCredential(Settings.UserName, Settings.Password),
+ Timeout = 10000000
+ };
+
+ archivesClient = new ZHRF_SYN_03N()
+ {
+ Url = Settings.ServerUrl + "/sap/bc/srt/rfc/sap/zhrf_syn_03n/800/zhrf_syn_03n/zhrf_syn_03n",
+ Credentials = new NetworkCredential(Settings.UserName, Settings.Password),
+ Timeout = 10000000
+ };
+
+ dataSaveClient = new ZHRF_SWIPE_DATA_SAVE_CLIENT()
+ {
+ Credentials = new NetworkCredential(Settings.UserName, Settings.Password),
+ Url = settings.AttendanceUploadUrl,
+ Timeout = 10000000
+ };
+ }
+
+ private PersonResult GetPersons()
+ {
+ HttpClient httpClient = new HttpClient();
+ httpClient.Timeout = TimeSpan.FromMinutes(10);
+ var credentials = string.Format("{0}:{1}", "EHS_USER", "y3R1hd2h*RICAC");
+ var headerValue = Convert.ToBase64String(Encoding.UTF8.GetBytes(credentials));
+ httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", headerValue);
+
+ List persons = new List();
+
+ foreach (var item in werks)
+ {
+ try
+ {
+ var body = new
+ {
+ T_WERKS = new
+ {
+ item = new List