using EgtBEAMWALL.DataLayer.DatabaseModels; using EgwProxy.MagMan; using EgwProxy.MagMan.DTO; using Newtonsoft.Json; using NLog; using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; namespace EgtBEAMWALL.DataLayer.Controllers { /// /// Gestione Sync MagMan (DB locale/online) /// public class MagmanController : IDisposable { #region Public Constructors /// /// Init controller gestione MagmanSync /// /// URL del server /// Token di autorizzazione public MagmanController(string ServerAddress, string AuthToken) { commLib = new DataSyncro(ServerAddress, AuthToken); bool servOk = commLib.CheckRemote(); Log.Info($"Avviato MagmanController | server: {ServerAddress} | timeout: standard (500ms)| CheckRemote OK: {servOk}"); } /// /// Init controller gestione MagmanSync /// /// URL del server /// Token di autorizzazione /// Timeout chiamate in ms public MagmanController(string ServerAddress, string AuthToken, int timeout) { commLib = new DataSyncro(ServerAddress, AuthToken, timeout); bool servOk = commLib.CheckRemote(); Log.Info($"Avviato MagmanController | server: {ServerAddress} | timeout: {timeout}ms | CheckRemote OK: {servOk}"); } #endregion Public Constructors #region Public Enums /// /// Enum del risultato della sincronizzazione /// 0: ALL_OK /// public enum SyncResult { ALL_OK = 0, ERR_ND, ERR_ServerKo, ERR_CloudMatNotSent, ERR_CloudResNotSent, ERR_SrcMatNotFound, ERR_MergeMatEmpty, ERR_CloudMatEmpty, ERR_Res2SendEmpty, ERR_InvSendError, ERR_AliasMatEmpty, ERR_CloudAliasNotSent, ERR_ProjIdNotFound, ERR_ProjNotSync, RES_CheckChanged, RES_CheckEqual, RES_CheckND } #endregion Public Enums #region Public Methods /// /// Esegue sync Alias: /// - download + sync (locale) /// - upload + sync (cloud) /// /// Risultato sincronizzazione public SyncResult AliasSyncro() { SyncResult answ = SyncResult.ERR_ND; // verifico server ok bool servOk = commLib.CheckRemote(); if (!servOk) { answ = SyncResult.ERR_ServerKo; } else { using (AliasController dbContr = new AliasController()) { try { List list2merge = commLib.AliasGet(); // 2024.04.04 effettuo conversione DTO --> model + merge x attivi List list2MergeDb = list2merge.Where(x => x.IsActive).Select(x => AliasController.ConvToModel(x, "MatCode")).ToList(); // 2024.04.04 prendo quelli con cancellazione logica che devo poi eliminare in locale... List list2DeleteDb = list2merge.Where(x => x.IsActive == false).Select(x => AliasController.ConvToModel(x, "MatCode")).ToList(); // ciclo... if (list2MergeDb == null) { answ = SyncResult.ERR_AliasMatEmpty; } else { // inizio con eventuale eliminazione... var deleteOk = dbContr.DeleteList(list2DeleteDb); // ora merge var updateOk = dbContr.UpsertList(list2MergeDb); if (updateOk || deleteOk) { // in primis leggo l'elenco materiali dal DB locale List listDb = dbContr.GetFilt("MatCode"); List list2send = listDb.Select(x => AliasController.ConvToDto(x)).ToList(); // preparo pacchetto invio... bool okMat = commLib.AliasSend(list2send); // se inviato, scarico x merge locale if (!okMat) { answ = SyncResult.ERR_CloudAliasNotSent; } else { answ = SyncResult.ALL_OK; } } } } catch { answ = SyncResult.ERR_ServerKo; } } } return answ; } /// /// Esegue sync Alias in modalità asincrona: /// - download + sync (locale) /// - upload + sync (cloud) /// /// Se "" esegue per tutti, altrimenti limitatamente al MatCode cercato /// Risultato sincronizzazione public async Task AliasSyncroAsync() { SyncResult answ = SyncResult.ERR_ND; // verifico server ok bool servOk = commLib.CheckRemote(); if (!servOk) { answ = SyncResult.ERR_ServerKo; } else { using (AliasController dbContr = new AliasController()) { try { List list2merge = await commLib.AliasGetAsync(); // 2024.04.04 effettuo conversione DTO --> model + merge x attivi List list2MergeDb = list2merge.Where(x => x.IsActive).Select(x => AliasController.ConvToModel(x, "MatCode")).ToList(); // 2024.04.04 prendo quelli con cancellazione logica che devo poi eliminare in locale... List list2DeleteDb = list2merge.Where(x => x.IsActive == false).Select(x => AliasController.ConvToModel(x, "MatCode")).ToList(); // ciclo... if (list2merge == null) { answ = SyncResult.ERR_AliasMatEmpty; } else { // inizio con eventuale eliminazione... var deleteOk = dbContr.DeleteList(list2DeleteDb); // ora merge var updateOk = dbContr.UpsertList(list2MergeDb); if (updateOk || deleteOk) { // in primis leggo l'elenco materiali dal DB locale List listDb = dbContr.GetFilt("MatCode"); List list2send = listDb.Select(x => AliasController.ConvToDto(x)).ToList(); // preparo pacchetto invio... bool okMat = await commLib.AliasSendAsync(list2send); // se inviato, scarico x merge locale if (!okMat) { answ = SyncResult.ERR_CloudAliasNotSent; } else { answ = SyncResult.ALL_OK; } } } } catch { answ = SyncResult.ERR_ServerKo; } } } return answ; } /// /// Esegue sync dei CloudId x Materiali e RawItems: /// - upload + sync (cloud) /// - download + sync (locale) /// /// /// true = Indica di forzare il sync di tutto, false = SOLAMENTE per i nuovi materiali (MatCloudId==0) /// /// True: sincronizza quantità, False = NON sincronizza quantità /// /// True: effettua 1 sola chiamata upload e 1 sola download per il sync /// /// public SyncResult CloudSyncro(bool ForceAll, bool SyncQty, bool BlockSend) { SyncResult answ = SyncResult.ERR_ND; List MatIdList = new List(); // verifico server ok bool servOk = commLib.CheckRemote(); if (!servOk) { answ = SyncResult.ERR_ServerKo; } else { using (MaterialsController matDbContr = new MaterialsController()) { // elenco materiali (completo) var matListDb = matDbContr.GetFiltModel(""); if (matListDb == null) { answ = SyncResult.ERR_SrcMatNotFound; } else { try { // se non è forzato a tutti --> filtro solo quelli nuovi if (!ForceAll) { matListDb = matListDb.Where(x => x.MatCloudId == 0).ToList(); } // eseguo il sync! List list2send = matListDb.Select(x => MaterialsController.ConvToDto(x)).ToList(); // preparo pacchetto invio... bool okMat = commLib.MaterialsSend(list2send); // se inviato, scarico x merge locale if (!okMat) { answ = SyncResult.ERR_CloudMatNotSent; } else { // recupero elenco materiali (ALL) List list2merge = commLib.MaterialsGet(); // effettuo conversione DTO --> model + merge List list2MergeDb = list2merge.Select(x => MaterialsController.ConvToModel(x)).ToList(); // ciclo... if (list2MergeDb == null) { answ = SyncResult.ERR_MergeMatEmpty; } else { int numOk = 0; int num2Write = list2MergeDb.Count(); foreach (var item in list2MergeDb) { var newId = matDbContr.Upsert(item); if (newId > 0) { numOk++; // aggiungo ID x successivo sync dei RawItems del materiale... MatIdList.Add(newId); } } // se non fosse tutto ok --> loggo if (num2Write != numOk) { Log.Error($"Errore sync Materiali | num2Write: {num2Write} | numOk: {numOk}"); } else { answ = SyncResult.ALL_OK; } // eseguo sync dell'elenco RawItems answ = ResourcesSync(MatIdList, SyncQty, BlockSend); } } } catch { answ = SyncResult.ERR_ServerKo; } } } } return answ; } public void Dispose() { commLib = null; } /// /// Forza sincronizzazione invii non completati... /// /// Restituisce esito resync, ALL OK solo se ha fatto tutti gli invii necessari public SyncResult ForceSyncroSend() { SyncResult answ = SyncResult.ERR_ND; ProjResState projType = ProjResState.Consumed; // recupero da DB eventuale elenco dati da sincronizzare using (MagmanSyncController msContr = new MagmanSyncController()) { var list2resend = msContr.GetUnsentFilt("", DateTime.Now.AddDays(1), 1000); if (list2resend == null || list2resend.Count == 0) { answ = SyncResult.ALL_OK; } else { // verifico server ok bool servOk = commLib.CheckRemote(); if (!servOk) { answ = SyncResult.ERR_ServerKo; } else { try { // eseguo re-invio 1:1... List list2send = new List(); foreach (var record in list2resend) { list2send = JsonConvert.DeserializeObject>(record.Payload); if (Enum.TryParse(record.SyncType, out projType)) { // effettuo invio... bool resOk = commLib.ResourceSend(record.CloudId, projType, record.DtReq, list2send); if (!resOk) { answ = SyncResult.ERR_CloudResNotSent; } else { answ = SyncResult.ALL_OK; // registro su DB dataora conclusione invio msContr.SetCompleted(record.SyncId, DateTime.Now); } } } } catch { answ = SyncResult.ERR_ServerKo; } } } } return answ; } /// /// Esegue sync Materiale: /// - upload + sync (cloud) /// - download + sync (locale) /// /// Id LOCALE del materiale da sincronizzare /// public SyncResult MaterialsSyncro(int MatId) { SyncResult answ = SyncResult.ERR_ND; // verifico server ok bool servOk = commLib.CheckRemote(); if (!servOk) { answ = SyncResult.ERR_ServerKo; } else { using (MaterialsController matDbContr = new MaterialsController()) { // elenco materiali (completo) var matRecord = matDbContr.FindByDbIdModel(MatId); if (matRecord == null) { answ = SyncResult.ERR_SrcMatNotFound; } else { try { // eseguo il sync! List list2send = new List() { MaterialsController.ConvToDto(matRecord) }; // preparo pacchetto invio... bool okMat = commLib.MaterialsSend(list2send); // se inviato, scarico x merge locale if (!okMat) { answ = SyncResult.ERR_CloudMatNotSent; } else { // recupero elenco materiali (ALL) List list2merge = commLib.MaterialsGet(); // effettuo conversione DTO --> model + merge List list2MergeDb = list2merge.Select(x => MaterialsController.ConvToModel(x)).ToList(); // ciclo... if (list2MergeDb == null) { answ = SyncResult.ERR_MergeMatEmpty; } else { int numOk = 0; int num2Write = list2MergeDb.Count(); foreach (var item in list2MergeDb) { var newId = matDbContr.Upsert(item); if (newId > 0) { numOk++; } } // solo se tutto andato bene esito ALL_OK if (num2Write == numOk) { answ = SyncResult.ALL_OK; } } } } catch { answ = SyncResult.ERR_ServerKo; } } } } return answ; } /// /// Esegue sync Materiali: /// - upload + sync (cloud) /// - download + sync (locale) /// /// Indica di forzare il sync SOLAMENTE per i nuovi materiali (MatCloudId==0) /// [Obsolete("MaterialsSyncro is deprecated, please use CloudSyncro", true)] public SyncResult MaterialsSyncro(bool onlyNew) { SyncResult answ = SyncResult.ERR_ND; // verifico server ok bool servOk = commLib.CheckRemote(); if (!servOk) { answ = SyncResult.ERR_ServerKo; } else { using (MaterialsController matDbContr = new MaterialsController()) { // elenco materiali (completo) var matListDb = matDbContr.GetFiltModel(""); if (matListDb == null) { answ = SyncResult.ERR_SrcMatNotFound; } else { try { // se non è forzato a tutti --> filtro solo quelli nuovi if (onlyNew) { matListDb = matListDb.Where(x => x.MatCloudId == 0).ToList(); } // eseguo il sync! List list2send = matListDb.Select(x => MaterialsController.ConvToDto(x)).ToList(); // preparo pacchetto invio... bool okMat = commLib.MaterialsSend(list2send); // se inviato, scarico x merge locale if (!okMat) { answ = SyncResult.ERR_CloudMatNotSent; } else { // recupero elenco materiali (ALL) List list2merge = commLib.MaterialsGet(); // effettuo conversione DTO --> model + merge List list2MergeDb = list2merge.Select(x => MaterialsController.ConvToModel(x)).ToList(); // ciclo... if (list2MergeDb == null) { answ = SyncResult.ERR_MergeMatEmpty; } else { int numOk = 0; int num2Write = list2MergeDb.Count(); foreach (var item in list2MergeDb) { var newId = matDbContr.Upsert(item); if (newId > 0) { numOk++; } } // solo se tutto andato bene esito ALL_OK if (num2Write == numOk) { answ = SyncResult.ALL_OK; } } } } catch { answ = SyncResult.ERR_ServerKo; } } } } return answ; } /// /// Esegue sync materiali: /// - upload + sync (cloud) /// - download + sync (locale) /// /// Se "" esegue per tutti, altrimenti limitatamente al MatCode cercato /// Risultato sincronizzazione [Obsolete("MaterialsSyncro is deprecated, please use CloudSyncro", true)] public SyncResult MaterialsSyncro(string MatCode = "") { SyncResult answ = SyncResult.ERR_ND; // verifico server ok bool servOk = commLib.CheckRemote(); if (!servOk) { answ = SyncResult.ERR_ServerKo; } else { using (MaterialsController dbContr = new MaterialsController()) { // in primis leggo l'elenco materiali dal DB locale List matListDb = dbContr.GetFiltModel(MatCode); if (matListDb == null) { answ = SyncResult.ERR_SrcMatNotFound; } else { try { List list2send = matListDb.Select(x => MaterialsController.ConvToDto(x)).ToList(); // preparo pacchetto invio... bool okMat = commLib.MaterialsSend(list2send); // se inviato, scarico x merge locale if (!okMat) { answ = SyncResult.ERR_CloudMatNotSent; } else { List list2merge = commLib.MaterialsGet(); // se filtro x materiale processo solo quello... if (!string.IsNullOrEmpty(MatCode)) { list2merge = list2merge.Where(x => x.MatCode == MatCode).ToList(); } // effettuo conversione DTO --> model + merge List list2MergeDb = list2merge.Select(x => MaterialsController.ConvToModel(x)).ToList(); // ciclo... if (list2MergeDb == null) { answ = SyncResult.ERR_MergeMatEmpty; } else { int numOk = 0; int num2Write = list2MergeDb.Count(); foreach (var item in list2MergeDb) { var newId = dbContr.Upsert(item); if (newId > 0) { numOk++; } } // solo se tutto andato bene esito ALL_OK if (num2Write == numOk) { answ = SyncResult.ALL_OK; } } } } catch { answ = SyncResult.ERR_ServerKo; } } } } return answ; } /// /// Esegue sync materiali in modalità asincrona: /// - upload + sync (cloud) /// - download + sync (locale) /// /// Se "" esegue per tutti, altrimenti limitatamente al MatCode cercato /// Risultato sincronizzazione [Obsolete("MaterialsSyncro is deprecated, please use CloudSyncro", true)] public async Task MaterialsSyncroAsync(string MatCode = "") { SyncResult answ = SyncResult.ERR_ND; // verifico server ok bool servOk = commLib.CheckRemote(); if (!servOk) { answ = SyncResult.ERR_ServerKo; } else { using (MaterialsController dbContr = new MaterialsController()) { // in primis leggo l'elenco materiali dal DB locale List matListDb = dbContr.GetFiltModel(MatCode); if (matListDb == null) { answ = SyncResult.ERR_SrcMatNotFound; } else { try { List list2send = matListDb.Select(x => MaterialsController.ConvToDto(x)).ToList(); // preparo pacchetto invio... bool okMat = await commLib.MaterialsSendAsync(list2send); // se inviato, scarico x merge locale if (!okMat) { answ = SyncResult.ERR_CloudMatNotSent; } else { List list2merge = await commLib.MaterialsGetAsync(); // se filtro x materiale processo solo quello... if (!string.IsNullOrEmpty(MatCode)) { list2merge = list2merge.Where(x => x.MatCode == MatCode).ToList(); } // effettuo conversione DTO --> model + merge List list2MergeDb = list2merge.Select(x => MaterialsController.ConvToModel(x)).ToList(); // ciclo... if (list2MergeDb == null) { answ = SyncResult.ERR_MergeMatEmpty; } else { int numOk = 0; int num2Write = list2MergeDb.Count(); foreach (var item in list2MergeDb) { var newId = dbContr.Upsert(item); if (newId > 0) { numOk++; } } // solo se tutto andato bene esito ALL_OK if (num2Write == numOk) { answ = SyncResult.ALL_OK; } } } } catch { answ = SyncResult.ERR_ServerKo; } } } } return answ; } /// /// Esegue sync di un SINGOLO PROD (cloud proj): /// - legge il progetto locale + upload x sync (verso cloud) /// - riceve ID cloud e aggiorna in locale... /// /// Id del Prod da sincronizzare (invio dati con eventuale fix ProjCloudId) /// Risultato sincronizzazione public SyncResult ProjSyncro(int ProdId) { int cloudId = 0; SyncResult answ = ProjSyncro(ProdId, ref cloudId); return answ; } /// /// Esegue sync di un SINGOLO PROD (cloud proj): /// - legge il progetto locale + upload x sync (verso cloud) /// - riceve ID cloud e aggiorna in locale... /// /// Id del Prod da sincronizzare (invio dati con eventuale fix ProjCloudId) /// /// Id del Prod in rete (eventualmente creato) che verrà RESTITUITO x reference /// /// Risultato sincronizzazione public SyncResult ProjSyncro(int ProdId, ref int ProjCloudId) { SyncResult answ = SyncResult.ERR_ND; // verifico server ok bool servOk = commLib.CheckRemote(); if (!servOk) { answ = SyncResult.ERR_ServerKo; } else { using (ProdController dbContr = new ProdController()) { // in primis recupero item var currRec = dbContr.FindByProdId(ProdId); if (currRec == null) { answ = SyncResult.ERR_ProjIdNotFound; } else { try { // preparo obj da inviare... var projDto = ProdController.ConvToDto(currRec); // invio e recupero ID... ProjCloudId = commLib.ProjectSend(projDto); // se inviato, faccio upgrade locale... if (ProjCloudId == 0) { answ = SyncResult.ERR_ProjNotSync; } else { // verifico SE SIA da scrivere cloud ID... if (ProjCloudId != currRec.ProjCloudId) { dbContr.UpdateCloudId(ProdId, ProjCloudId); } answ = SyncResult.ALL_OK; } } catch { answ = SyncResult.ERR_ServerKo; } } } } return answ; } /// /// Esegue registrazione Risorse (RawItems) come CONSUMI effettivi: /// /// DB Id del progetto x cui si inviano i dati /// /// Elenco RawPart come dizionario quantità consumate [nId, qty]. nID = id del db LOCALE /// /// public SyncResult ResourceSendCons(int ProjCloudId, Dictionary rec2send) { SyncResult answ = ResourceSendTrack(ProjCloudId, rec2send, ProjResState.Consumed, -1); return answ; } /// /// Esegue registrazione Risorse (RawItems) come CONSUMI effettivi, versione ASYNC: /// /// DB Id del progetto x cui si inviano i dati /// /// Elenco RawPart come dizionario quantità consumate [nId, qty]. nID = id del db LOCALE /// /// public async Task ResourceSendConsAsync(int ProjCloudId, Dictionary rec2send) { SyncResult answ = await ResourceSendTrackAsync(ProjCloudId, rec2send, ProjResState.Consumed, -1); return answ; } /// /// Esegue registrazione Risorse (RawItems) come stima: /// /// DB Id del progetto x cui si inviano i dati /// /// Elenco RawPart come dizionario quantità consumate [nId, qty]. nID = id del db LOCALE /// /// public SyncResult ResourceSendEstimate(int ProjCloudId, Dictionary rec2send) { SyncResult answ = ResourceSendTrack(ProjCloudId, rec2send, ProjResState.Estimated, 1); return answ; } /// /// Esegue registrazione Risorse (RawItems) come stima, versione ASYNC: /// /// DB Id del progetto x cui si inviano i dati /// /// Elenco RawPart come dizionario quantità consumate [nId, qty]. nID = id del db LOCALE /// /// public async Task ResourceSendEstimateAsync(int ProjCloudId, Dictionary rec2send) { SyncResult answ = await ResourceSendTrackAsync(ProjCloudId, rec2send, ProjResState.Estimated, 1); return answ; } /// /// Esegue sync forzato risorse (Materiali + RawItem): /// - download + sync (locale) /// /// public SyncResult ResourcesForceSyncAll() { SyncResult answ = SyncResult.ERR_ND; // verifico server ok bool servOk = commLib.CheckRemote(); if (!servOk) { answ = SyncResult.ERR_ServerKo; } else { using (MaterialsController matDbContr = new MaterialsController()) { using (RawItemsController rawItemDbContr = new RawItemsController()) { // elenco di tutti i materiali var matListAll = commLib.MaterialsGet(); if (matListAll == null || matListAll.Count == 0) { answ = SyncResult.ERR_CloudMatEmpty; } else { try { int numMatOk = 0; int numMat2Write = 0; // ciclo 1:1 materiali + inventario foreach (var mat in matListAll) { List list2merge = commLib.InventoryGet(mat.MatCloudId); // ciclo sui materiali... if (list2merge != null) { numMat2Write += list2merge.Count(); foreach (var item in list2merge) { var newId = matDbContr.Insert(MaterialsController.ConvToModel(item)); if (newId > 0) { numMatOk++; // ora processo 1:1 gli items... foreach (var rawItem in item.ItemList) { rawItemDbContr.Upsert(RawItemsController.ConvToModel(rawItem, true), false, true); } } } } } // solo se tutto andato bene esito ALL_OK if (numMat2Write == numMatOk) { answ = SyncResult.ALL_OK; } } catch { answ = SyncResult.ERR_ServerKo; } } } } } return answ; } /// /// Esegue sync risorse RawItem dato elenco MatId: /// - upload + sync (cloud) /// - download + sync (locale) /// /// /// Elenco Id dei materiali (DB LOCALE): saranno inviati x sync (con quantità sovrascritta) /// SOLO SE RawItemCloudId == 0 /// /// True: sincronizza quantità, False = NON sincronizza quantità /// /// True: effettua 1 sola chiamata upload e 1 sola download per il sync /// /// public SyncResult ResourcesSync(List MatIdList, bool SyncQty, bool BlockSend) { SyncResult answ = SyncResult.ERR_ND; // verifico server ok bool servOk = commLib.CheckRemote(); if (!servOk) { answ = SyncResult.ERR_ServerKo; } else { using (RawItemsController rawItemDbContr = new RawItemsController()) { List rawItemList = new List(); // ciclo per ogni materiale indicato foreach (var item in MatIdList) { // recupero elenco rawItem List currList = rawItemDbContr.GetFiltModel(item); if (currList == null || currList.Count == 0) { answ = SyncResult.ERR_Res2SendEmpty; } else { // verifico se e cosa aggiungere... foreach (var rawItem in currList) { if (!rawItemList.Contains(rawItem)) { rawItemList.Add(rawItem); } } } } // effettuo sync alla fine... answ = ResourcesSync(rawItemList, SyncQty, BlockSend); } } return answ; } /// /// Esegue sync risorse (Materiali + RawItem): /// - upload + sync (cloud) /// - download + sync (locale) /// /// /// Elenco item, saranno inviati x sync (con quantità sovrascritta) SOLO SE RawItemCloudId==0 /// /// True: sincronizza quantità, False = NON sincronizza quantità /// /// True: effettua 1 sola chiamata upload e 1 sola download per il sync /// /// public SyncResult ResourcesSync(List itemList, bool SyncQty, bool BlockSend) { SyncResult answ = SyncResult.ERR_ND; // verifico server ok bool servOk = commLib.CheckRemote(); if (!servOk) { answ = SyncResult.ERR_ServerKo; } else { using (MaterialsController matDbContr = new MaterialsController()) { using (RawItemsController rawItemDbContr = new RawItemsController()) { // per prima cosa invio dati Dictionary dictMat = new Dictionary(); // 2024.02.17 --> invio tutti! foreach (var item in itemList) { // verifico se mancasse il materiale nel caso lo aggiungo... if (!dictMat.ContainsKey(item.MatId)) { var rigaMat = matDbContr.FindByDbIdModel(item.MatId); if (rigaMat != null) { var rigaMatDto = MaterialsController.ConvToDto(rigaMat); dictMat.Add(item.MatId, rigaMatDto); } } // a questo punto aggiungo item nel DTO del dictionary dictMat[item.MatId].ItemList.Add(RawItemsController.ConvToItemDto(item)); } // per ogni materiale faccio invio + rilettura/sync... if (dictMat != null && dictMat.Count > 0) { try { int numMatOk = 0; int numMat2Write = 0; // 2024.03.12 verifico se fare chiamata in blocco x sync prima UP // verso cloud poi DOWN verso DB if (BlockSend) { List list2send = new List(); // preparo tutti gli items x un unico invio foreach (var matKVP in dictMat) { list2send.AddRange(matKVP.Value.ItemList); } // faccio 1 sola chiamata UPLOAD per TUTTI gli items... bool invOk = commLib.InventorySend(list2send); // ora rileggo dati... if (!invOk) { answ = SyncResult.ERR_InvSendError; } else { // faccio 1 sola chiamata DOWNLOAD per TUTTI i materiali... List listAll = commLib.InventoryGet(0); // ciclo sui materiali... if (listAll != null) { numMat2Write += listAll.Count(); foreach (var item in listAll) { var matLocalId = matDbContr.Insert(MaterialsController.ConvToModel(item)); if (matLocalId > 0) { // inserisco il materiale locale negli items... item.MatLocalId = matLocalId; numMatOk++; // ora processo 1:1 gli items... foreach (var rawItem in item.ItemList) { // sovrascrivo materaile anche x ogni RawItem rawItem.MatLocalId = matLocalId; rawItemDbContr.Upsert(RawItemsController.ConvToModel(rawItem, true), false, SyncQty); } } } } } } else { foreach (var matKVP in dictMat) { // invio! bool invOk = commLib.InventorySend(matKVP.Value.ItemList); // ora rileggo dati... if (!invOk) { answ = SyncResult.ERR_InvSendError; break; } else { List list2merge = commLib.InventoryGet(matKVP.Value.MatCloudId); // ciclo sui materiali... if (list2merge != null) { numMat2Write += list2merge.Count(); foreach (var item in list2merge) { var matLocalId = matDbContr.Insert(MaterialsController.ConvToModel(item)); if (matLocalId > 0) { // inserisco il materiale locale negli items... item.MatLocalId = matLocalId; numMatOk++; // ora processo 1:1 gli items... foreach (var rawItem in item.ItemList) { // sovrascrivo materaile anche x ogni RawItem rawItem.MatLocalId = matLocalId; rawItemDbContr.Upsert(RawItemsController.ConvToModel(rawItem, true), false, SyncQty); } } } } } } } // solo se tutto andato bene esito ALL_OK if (numMat2Write == numMatOk) { answ = SyncResult.ALL_OK; } } catch { answ = SyncResult.ERR_ServerKo; } } else { // nessun materiale da sincronizzare --> ok! answ = SyncResult.ALL_OK; } } } } return answ; } /// /// Esegue sync risorse (Materiali + RawItem) dato elenco MatId, versione ASYNC: /// - upload + sync (cloud) /// - download + sync (locale) /// /// /// Elenco Id dei materiali (DB LOCALE): saranno inviati x sync (con quantità sovrascritta) /// SOLO SE RawItemCloudId == 0 /// /// public async Task ResourcesSyncAsync(List MatIdList) { SyncResult answ = SyncResult.ERR_ND; // verifico server ok bool servOk = commLib.CheckRemote(); if (!servOk) { answ = SyncResult.ERR_ServerKo; } else { using (RawItemsController rawItemDbContr = new RawItemsController()) { // ciclo per ogni materiale indicato foreach (var item in MatIdList) { // recupero elenco rawItem var currList = rawItemDbContr.GetFiltModel(item); if (currList == null || currList.Count == 0) { answ = SyncResult.ERR_Res2SendEmpty; break; } else { // effettuo sync... answ = await ResourcesSyncAsync(currList); } } } } return answ; } /// /// Esegue sync risorse (Materiali + RawItem): /// - upload + sync (cloud) /// - download + sync (locale) /// /// /// Elenco item dal DB locale saranno inviati x sync (con quantità sovrascritta) SOLO SE /// RawItemCloudId == 0 /// /// public async Task ResourcesSyncAsync(List itemList) { SyncResult answ = SyncResult.ERR_ND; // verifico server ok bool servOk = commLib.CheckRemote(); if (!servOk) { answ = SyncResult.ERR_ServerKo; } else { using (MaterialsController matDbContr = new MaterialsController()) { using (RawItemsController rawItemDbContr = new RawItemsController()) { // per prima cosa invio dati Dictionary dictMat = new Dictionary(); // costruisco elenco materiali da inviare in magazzino (se RawItemCloudId== // 0) ... var rec2sync = itemList.Where(x => x.RawItemCloudId == 0).ToList(); foreach (var item in rec2sync) { // verifico se mancasse il materiale nel caso lo aggiungo... if (!dictMat.ContainsKey(item.MatId)) { var rigaMat = matDbContr.FindByDbIdModel(item.MatId); if (rigaMat != null) { var rigaMatDto = MaterialsController.ConvToDto(rigaMat); dictMat.Add(item.MatId, rigaMatDto); } } // a questo punto aggiungo item nel DTO del dictionary dictMat[item.MatId].ItemList.Add(RawItemsController.ConvToItemDto(item)); } // per ogni materiale faccio invio + rilettura/sync... if (dictMat != null && dictMat.Count > 0) { try { int numMatOk = 0; int numMat2Write = 0; foreach (var matKVP in dictMat) { // invio! bool invOk = await commLib.InventorySendAsync(matKVP.Value.ItemList); // ora rileggo dati... if (!invOk) { answ = SyncResult.ERR_InvSendError; break; } else { List list2merge = await commLib.InventoryGetAsync(matKVP.Key); // ciclo sui materiali... if (list2merge != null) { numMat2Write += list2merge.Count(); foreach (var item in list2merge) { var newId = matDbContr.Insert(MaterialsController.ConvToModel(item)); if (newId > 0) { numMatOk++; // ora processo 1:1 gli items... foreach (var rawItem in item.ItemList) { rawItemDbContr.Upsert(RawItemsController.ConvToModel(rawItem, true), false, true); } } } } } } // solo se tutto andato bene esito ALL_OK if (numMat2Write == numMatOk) { answ = SyncResult.ALL_OK; } } catch { answ = SyncResult.ERR_ServerKo; } } } } } return answ; } #endregion Public Methods #region Private Fields private DataSyncro commLib = null; /// /// Istanza logger /// private NLog.Logger Log = LogManager.GetCurrentClassLogger(); #endregion Private Fields #region Private Methods /// /// Effettua invio track risorse /// /// DB Id del progetto x cui si inviano i dati /// Elenco RawPart come dizionario quantità consumate [nId, qty] /// tipologia dato inviato /// segno da applicare alle quantità dsa inviare /// private SyncResult ResourceSendTrack(int ProjCloudId, Dictionary rec2send, ProjResState trackType, int sign) { SyncResult answ = SyncResult.ERR_ND; using (RawItemsController dbContr = new RawItemsController()) { List list2send = new List(); // recupero elenco risorse da lista int delle chiavi... var allResources = dbContr.GetFiltModel(0); // ciclo tra risorse richieste... foreach (var item in rec2send) { var currRes = allResources.Find(x => x.RawItemId == item.Key); list2send.Add(new ResourceDTO() { RawItemLocalId = item.Key, RawItemCloudId = currRes.RawItemCloudId, Qty = sign * Math.Abs(item.Value) }); } //if (list2send == null || list2send.Count == 0) if (list2send == null) { answ = SyncResult.ERR_Res2SendEmpty; } else { int syncId = 0; string payload = JsonConvert.SerializeObject(list2send); DateTime adesso = DateTime.Now; // registro su DB invio.. MagmanSyncModel newRec = new MagmanSyncModel() { CloudId = ProjCloudId, SyncType = $"{trackType}", DtReq = adesso, Payload = payload }; // salvo sul DB using (MagmanSyncController msContr = new MagmanSyncController()) { syncId = msContr.Insert(newRec); // se si tratta di STIMA cancello EVENTUALI record precedenti non inviati if (trackType == ProjResState.Estimated) { // elimino eventuali eventi rimasti fino a 1 sec precedente msContr.DeleteUnsentFilt(ProjCloudId, $"{trackType}", adesso.AddSeconds(-1)); } // verifico server ok bool servOk = commLib.CheckRemote(); if (!servOk) { answ = SyncResult.ERR_ServerKo; } else { try { // effettuo invio... bool resOk = commLib.ResourceSend(ProjCloudId, trackType, adesso, list2send); if (!resOk) { answ = SyncResult.ERR_CloudResNotSent; } else { answ = SyncResult.ALL_OK; // registro su DB dataora conclusione invio msContr.SetCompleted(syncId, DateTime.Now); } } catch { answ = SyncResult.ERR_ServerKo; } } } } } return answ; } /// /// Effettua verifica risorse /// /// DB Id del progetto x cui si inviano i dati /// Elenco RawPart come dizionario quantità consumate [nId, qty] /// tipologia dato inviato /// segno da applicare alle quantità dsa inviare /// Restitusice errore comunicazione oppure se le risorse siano uguali o cambiate private SyncResult ResourceCheckChanged(int ProjCloudId, Dictionary rec2send, ProjResState trackType, int sign) { SyncResult answ = SyncResult.ERR_ND; using (RawItemsController dbContr = new RawItemsController()) { List list2send = new List(); // recupero elenco risorse da lista int delle chiavi... var allResources = dbContr.GetFiltModel(0); // ciclo tra risorse richieste... foreach (var item in rec2send) { var currRes = allResources.Find(x => x.RawItemId == item.Key); list2send.Add(new ResourceDTO() { RawItemLocalId = item.Key, RawItemCloudId = currRes.RawItemCloudId, Qty = sign * Math.Abs(item.Value) }); } //if (list2send == null || list2send.Count == 0) if (list2send == null) { answ = SyncResult.ERR_Res2SendEmpty; } else { string payload = JsonConvert.SerializeObject(list2send); DateTime adesso = DateTime.Now; // registro su DB invio.. MagmanSyncModel newRec = new MagmanSyncModel() { CloudId = ProjCloudId, SyncType = $"{trackType}", DtReq = adesso, Payload = payload }; // verifico server ok bool servOk = commLib.CheckRemote(); if (!servOk) { answ = SyncResult.ERR_ServerKo; } else { try { // effettuo invio... int resChk = commLib.ResourceCheck(ProjCloudId, trackType, adesso, list2send); switch (resChk) { case 1: answ = SyncResult.RES_CheckEqual; break; case 2: answ = SyncResult.RES_CheckChanged; break; case 0: default: answ = SyncResult.RES_CheckND; break; } } catch { answ = SyncResult.ERR_ServerKo; } } } } return answ; } /// /// Effettua invio track risorse /// /// DB Id del progetto x cui si inviano i dati /// Elenco RawPart come dizionario quantità consumate [nId, qty] /// tipologia dato inviato /// segno da applicare alle quantità dsa inviare /// private async Task ResourceSendTrackAsync(int ProjCloudId, Dictionary rec2send, ProjResState trackType, int sign) { SyncResult answ = SyncResult.ERR_ND; // verifico server ok using (RawItemsController dbContr = new RawItemsController()) { List list2send = new List(); // recupero elenco risorse da lista int delle chiavi... var allResources = dbContr.GetFiltModel(0); // ciclo tra risorse richieste... foreach (var item in rec2send) { var currRes = allResources.Find(x => x.RawItemId == item.Key); list2send.Add(new ResourceDTO() { RawItemLocalId = item.Key, RawItemCloudId = currRes.RawItemCloudId, Qty = sign * Math.Abs(item.Value) }); } if (list2send == null || list2send.Count == 0) { answ = SyncResult.ERR_Res2SendEmpty; } else { int syncId = 0; string payload = JsonConvert.SerializeObject(list2send); // registro su DB invio.. MagmanSyncModel newRec = new MagmanSyncModel() { CloudId = ProjCloudId, SyncType = $"{trackType}", DtReq = DateTime.Now, Payload = payload }; // salvo sul DB using (MagmanSyncController msContr = new MagmanSyncController()) { syncId = msContr.Insert(newRec); bool servOk = commLib.CheckRemote(); if (!servOk) { answ = SyncResult.ERR_ServerKo; } else { try { // effettuo invio... bool resOk = await commLib.ResourceSendAsync(ProjCloudId, trackType, list2send); if (!resOk) { answ = SyncResult.ERR_CloudResNotSent; } else { answ = SyncResult.ALL_OK; } } catch { answ = SyncResult.ERR_ServerKo; } } } } } return answ; } #endregion Private Methods } }