diff --git a/.gitignore b/.gitignore
index 9491a2f..a724052 100644
--- a/.gitignore
+++ b/.gitignore
@@ -360,4 +360,7 @@ MigrationBackup/
.ionide/
# Fody - auto-generated XML schema
-FodyWeavers.xsd
\ No newline at end of file
+FodyWeavers.xsd
+
+# History for Visual Studio
+.history/
diff --git a/Mappers/README.md b/Mappers/README.md
new file mode 100644
index 0000000..c2ffa44
--- /dev/null
+++ b/Mappers/README.md
@@ -0,0 +1 @@
+// This folder will contain mapping logic between API/DB and domain models if needed
diff --git a/Models/Entities.cs b/Models/Entities.cs
new file mode 100644
index 0000000..a7f1b5b
--- /dev/null
+++ b/Models/Entities.cs
@@ -0,0 +1,59 @@
+using System;
+using System.Collections.Generic;
+
+namespace Pipefy.Models
+{
+ public class RootObject
+ {
+ public required Node node { get; set; }
+ }
+ public class RootGestor
+ {
+ public NodeGestor node { get; set; }
+ }
+ public class Data
+ {
+ public Node node { get; set; }
+ }
+ public class Node
+ {
+ public string id { get; set; }
+ public Record_Fields[] record_fields { get; set; }
+ }
+ public class NodeGestor
+ {
+ public string? id { get; set; }
+ public Record_Fields[] record_fields { get; set; }
+ }
+ public class Record_Fields
+ {
+ public Field field { get; set; }
+ public string? value { get; set; }
+ public string[] array_value { get; set; }
+ }
+ public class Field
+ {
+ public string? id { get; set; }
+ }
+ public class ClasseEmpresas
+ {
+ public string? c_digo_smart { get; set; }
+ public string? nome_da_empresa { get; set; }
+ public string? modalidade { get; set; }
+ public string? gestores { get; set; }
+ public string rec_id { get; set; }
+ }
+ public class ClasseGestores
+ {
+ public string? id { get; set; }
+ public string? gestores { get; set; }
+ }
+ public class AppSettings
+ {
+ public string DB_PATH { get; set; }
+ public string PIPEFY_API_TOKEN { get; set; }
+ public string PIPEFY_API_URL { get; set; }
+ public string PIPEFY_TABLE_ID { get; set; }
+ public string PIPEFY_TABLE_ID_GESTORES { get; set; }
+ }
+}
diff --git a/Models/README.md b/Models/README.md
new file mode 100644
index 0000000..c95a6fc
--- /dev/null
+++ b/Models/README.md
@@ -0,0 +1 @@
+// This folder will contain all data models (move from data.cs)
diff --git a/Pipefy.csproj b/Pipefy.csproj
index 127a3b7..9fe459a 100644
--- a/Pipefy.csproj
+++ b/Pipefy.csproj
@@ -2,13 +2,19 @@
Exe
- net7.0-windows
+ net8.0-windows
enable
enable
1b2d76eb-7ab5-428f-9f67-13b6bf96375d
+
+
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+ all
+
+
diff --git a/Program.cs b/Program.cs
index 9d39f56..60e148d 100644
--- a/Program.cs
+++ b/Program.cs
@@ -1,337 +1,96 @@
-using System;
-using System.Data.OleDb;
-using System.Net.Http;
-using System.Net.Http.Headers;
-using System.Text.Json;
-using System.Threading.Tasks;
-using System.Collections.Generic;
-using System.Reflection.Metadata;
+using System.Data.OleDb;
using Pipefy;
-using Microsoft.VisualBasic;
-using System.Net.Quic;
+using Pipefy.Models;
using Microsoft.Extensions.Configuration;
using Newtonsoft.Json.Linq;
using Newtonsoft.Json;
-using Microsoft.Extensions.Configuration.UserSecrets;
-using static System.Net.Mime.MediaTypeNames;
using System.Text;
+using System.Timers;
+using Pipefy.Services;
+using Microsoft.Extensions.DependencyInjection;
class Program
{
+ static DateTime endTime;
+ static void SetEndTime(DateTime date)
+ {
+ endTime = date;
+ }
static async Task Main(string[] args)
{
- var configurationBuilder = new ConfigurationBuilder().SetBasePath(Directory.GetCurrentDirectory()).AddJsonFile("appsettings.json", optional: false);
- IConfiguration configuration = configurationBuilder.Build();
- AppSettings AppSettings = configuration.GetSection("AppSettings").Get();
+ // Setup DI
+ var serviceCollection = new ServiceCollection();
+ serviceCollection.AddSingleton();
+ serviceCollection.AddSingleton(provider => {
+ var config = provider.GetRequiredService().LoadAppSettings();
+ return new PipefyApiService(config.PIPEFY_API_URL, config.PIPEFY_API_TOKEN);
+ });
+ serviceCollection.AddSingleton();
+ serviceCollection.AddSingleton();
+ serviceCollection.AddSingleton();
+ var serviceProvider = serviceCollection.BuildServiceProvider();
+ var configService = serviceProvider.GetRequiredService();
+ var AppSettings = configService.LoadAppSettings();
if (AppSettings is null){ Environment.Exit(1); }
-
Console.Clear();
- // URL da API que você deseja chamar
- string ConnSourcePath = AppSettings.DB_PATH;
- string apiUrl = AppSettings.PIPEFY_API_URL;
- string PipefyToken = AppSettings.PIPEFY_API_TOKEN;
- string PipefyTokenTableID = AppSettings.PIPEFY_TABLE_ID;
- string PipefyTokenTableIDGestores = AppSettings.PIPEFY_TABLE_ID_GESTORES;
-
- JArray allRecords = await GetPipefyDataAsync(apiUrl,PipefyToken,PipefyTokenTableID);
- JArray allGestores = await GetPipefyDataAsync(apiUrl, PipefyToken, PipefyTokenTableIDGestores);
-
+ var pipefyApi = serviceProvider.GetRequiredService();
+ JArray allRecords = await pipefyApi.GetRecordsAsync(AppSettings.PIPEFY_TABLE_ID);
+ JArray allGestores = await pipefyApi.GetGestoresAsync(AppSettings.PIPEFY_TABLE_ID_GESTORES);
Console.Clear();
if (allRecords is not null)
{
string strGestores = JsonConvert.SerializeObject(allGestores);
- // Desserialize o JSON em objetos C#
- var jsonGestores = JsonConvert.DeserializeObject>(strGestores);
-
- List jsonListGestores = convertGestoresJson(jsonGestores);
-
+ var jsonGestores = JsonConvert.DeserializeObject>(strGestores)!;
+ var mapper = serviceProvider.GetRequiredService();
+ List jsonListGestores = mapper.ConvertGestoresJson(jsonGestores);
string strJson = JsonConvert.SerializeObject(allRecords);
- // Desserialize o JSON em objetos C#
- var jsonData = JsonConvert.DeserializeObject>(strJson);
-
- List jsonList = convertEmpresasJson(jsonData);
-
- // Consulte os dados da tabela no banco de dados Access
- List databaseData = GetDataFromDatabase(ConnSourcePath);
-
- // Compare os dados e encontre os registros ausentes no JSON
- List recordsMissingInJson = CompareData(databaseData, jsonList, jsonListGestores);
-
- if (recordsMissingInJson.Count != 0)
+ var jsonData = JsonConvert.DeserializeObject>(strJson)!;
+ List jsonList = mapper.ConvertEmpresasJson(jsonData);
+ var databaseService = serviceProvider.GetRequiredService();
+ List databaseData = databaseService.GetDataFromDatabase(AppSettings.DB_PATH);
+ var businessLogic = serviceProvider.GetRequiredService();
+ List recordsMissingInJson = businessLogic.CompareData(databaseData, jsonList, jsonListGestores);
+ if (recordsMissingInJson.Count != 0 && recordsMissingInJson != null)
{
- string strQuery = "{\"query\":\"mutation {\\r\\n ";
- for (int i = 0; i < recordsMissingInJson.Count; i++)
- {
- if (i % 49 == 0) { strQuery = "{\"query\":\"mutation {\\r\\n "; }
-
- strQuery = strQuery + $"N{i}: createTableRecord(input: {{ table_id: \\\"{PipefyTokenTableID}\\\", fields_attributes: [ {{ field_id: \\\"nome_da_empresa\\\", field_value: \\\"{recordsMissingInJson[i].nome_da_empresa.ToString()}\\\" }} {{ field_id: \\\"c_digo_smart\\\", field_value: \\\"{recordsMissingInJson[i].c_digo_smart.ToString()}\\\" }} {{ field_id: \\\"modalidade\\\", field_value: \\\"{recordsMissingInJson[i].modalidade.ToString()}\\\" }} {{ field_id: \\\"gestores\\\", field_value: \\\"{recordsMissingInJson[i].gestores.ToString()}\\\" }}]}}) {{ table_record {{ id }}}}\\r\\n ";
-
- if (i % 48 == 0 && i != 0) {
-
- strQuery = strQuery + "}\",\"variables\":{}}";
-
- bool success = await CreatePipefyDataAsync(apiUrl, PipefyToken, PipefyTokenTableID, strQuery);
-
- //if (!success) {
- // int test2 = 10;
- //}
- }
- }
-
- strQuery = strQuery + "}\",\"variables\":{}}";
-
- bool success1 = await CreatePipefyDataAsync(apiUrl, PipefyToken, PipefyTokenTableID, strQuery);
-
- // Faça algo com os registros ausentes
- int maxCId = recordsMissingInJson.OrderByDescending(s => s.c_digo_smart.Length).First().c_digo_smart.Length;
- int maxCNome = recordsMissingInJson.OrderByDescending(s => s.nome_da_empresa.Length).First().nome_da_empresa.Length;
- int maxCMod = recordsMissingInJson.OrderByDescending(s => s.modalidade.Length).First().modalidade.Length;
- int maxCGestao = recordsMissingInJson.OrderByDescending(s => s.gestores.Length).First().gestores.Length;
-
+ await pipefyApi.CreateRecordsAsync(AppSettings.PIPEFY_TABLE_ID, recordsMissingInJson);
+ int maxCId = recordsMissingInJson.OrderByDescending(s => s.c_digo_smart!.Length).First().c_digo_smart!.Length;
+ int maxCNome = recordsMissingInJson.OrderByDescending(s => s.nome_da_empresa!.Length).First().nome_da_empresa!.Length;
+ int maxCMod = recordsMissingInJson.OrderByDescending(s => s.modalidade!.Length).First().modalidade!.Length;
+ int maxCGestao = recordsMissingInJson.OrderByDescending(s => s.gestores!.Length).First().gestores!.Length;
foreach (var record in recordsMissingInJson)
{
Console.WriteLine(String.Format($"| ID: {{0,{maxCId}}} | Nome: {{1,{maxCNome}}} | Modalidade: {{2,{maxCMod}}} | Gestão: {{3,{maxCGestao}}} |",record.c_digo_smart,record.nome_da_empresa,record.modalidade,record.gestores));
}
-
- Console.WriteLine($"");
-
+ Console.WriteLine("");
}
-
- Console.WriteLine($"{recordsMissingInJson.Count} registros encontrados.");
-
+ Console.WriteLine($"{recordsMissingInJson!.Count} registros encontrados.");
}
- System.Threading.Thread.Sleep(10000);
+
+ var timer = new System.Timers.Timer(100);
+ double remainingTime;
+ int interval = 60;
+ SetEndTime(System.DateTime.Now.AddSeconds(interval));
+ timer.Elapsed += OnTimerElapsed!;
+ timer.AutoReset = true;
+ timer.Enabled = true;
+
+ Console.WriteLine("");
+ Console.WriteLine("Pressione qualquer tecla para encerrar o programa...");
+ Console.WriteLine("");
+ Task.Factory.StartNew(
+ () => {
+ Console.ReadKey();
+ remainingTime = DateTime.Now.Subtract(endTime).TotalSeconds;
+ }
+ ).Wait(
+ TimeSpan.FromSeconds(interval)
+ );
}
- private static async Task CreatePipefyDataAsync(string apiUrl, string PipefyToken, string PipefyTokenTableID, string query)
+ private static void OnTimerElapsed(object sender, ElapsedEventArgs e)
{
-
- var httpClient = new HttpClient();
- // Defina os headers da requisição (opcional)
- httpClient.DefaultRequestHeaders.Add("Authorization", "Bearer " + PipefyToken);
-
- var request = new HttpRequestMessage(HttpMethod.Post, apiUrl);
- request.Headers.Add("Accept", "application/json");
-
- var content = new StringContent(query, null, "application/json");
- request.Content = content;
- var response = await httpClient.SendAsync(request);
- var body = JsonConvert.SerializeObject(response.Content);
- return response.IsSuccessStatusCode;
- }
- private static async Task GetPipefyDataAsync(string apiUrl, string PipefyToken, string PipefyTokenTableID)
- {
- JArray allRecords = new JArray();
-
- string cursor = "null";
-
- string query = $"{{\"query\":\"query GetRecords($cursor: String){{ table_records(table_id: \\\"{PipefyTokenTableID}\\\",first:50,after:$cursor){{ pageInfo{{ hasNextPage endCursor }} edges{{ node{{ id record_fields{{ field {{ id }} value array_value }} }} }} }}}}\",\"variables\":{{\"cursor\":{cursor}}}}}";
-
- bool hasNextPage = true;
-
- while (hasNextPage)
- {
- var httpClient = new HttpClient();
- // Defina os headers da requisição (opcional)
- httpClient.DefaultRequestHeaders.Add("Authorization", "Bearer " + PipefyToken);
-
- var request = new HttpRequestMessage(HttpMethod.Post, apiUrl);
- request.Headers.Add("Accept", "application/json");
-
- var content = new StringContent(query, null, "application/json");
- request.Content = content;
- var response = await httpClient.SendAsync(request);
-
- if (response.IsSuccessStatusCode)
- {
- var responseContent = await response.Content.ReadAsStringAsync();
- var responseData = JObject.Parse(responseContent);
-
- Console.Clear();
-
- var records = responseData["data"]["table_records"]["edges"];
- foreach (var record in records)
- {
- //Console.WriteLine(record);
- allRecords.Add(record);
- }
-
- hasNextPage = responseData["data"]["table_records"]["pageInfo"]["hasNextPage"].Value();
- cursor = responseData["data"]["table_records"]["pageInfo"]["endCursor"].Value();
- query = $"{{\"query\":\"query GetRecords($cursor: String){{ table_records(table_id: \\\"{PipefyTokenTableID}\\\",first:50,after:$cursor){{ pageInfo{{ hasNextPage endCursor }} edges{{ node{{ record_fields{{ field {{ id }} value array_value }} }} }} }}}}\",\"variables\":{{\"cursor\":\"{cursor}\"}}}}";
-
- }
- else
- {
- Console.WriteLine($"Erro na solicitação GraphQL: {response.StatusCode}");
- allRecords.Clear();
- return allRecords;
- }
- }
-
- return allRecords;
- }
-
- static List GetDataFromDatabase(string ConnSourcePath)
- {
- string connectionString = @"Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" + ConnSourcePath + ";Jet OLEDB:Database Password=gds21;";
- List data = new List();
-
- using (OleDbConnection connection = new OleDbConnection(connectionString))
- {
- connection.Open();
-
- // Execute uma consulta SQL para recuperar dados da tabela no banco de dados Access
- StringBuilder sqlQuery = new StringBuilder();
- sqlQuery.Append("SELECT cod_smart_cliente, \n");
- sqlQuery.Append(" cliente, \n");
- sqlQuery.Append(" modalidade, \n");
- sqlQuery.Append(" gestao \n");
- sqlQuery.Append("FROM dados_cadastrais \n");
- sqlQuery.Append("WHERE cod_smart_unidade LIKE \"%001\" \n");
- sqlQuery.Append(" AND unidade_gerenciada;");
-
- using (OleDbCommand command = new OleDbCommand(sqlQuery.ToString(), connection))
- {
- using (OleDbDataReader reader = command.ExecuteReader())
- {
- while (reader.Read())
- {
- Pipefy.ClasseEmpresas record = new Pipefy.ClasseEmpresas
- {
- c_digo_smart = (string)reader["Cod_Smart_cliente"].ToString(),
- nome_da_empresa = (string)reader["Cliente"],
- modalidade = (string)reader["Modalidade"],
- gestores = (string)reader["Gestao"],
- rec_id = ""
-
- // Adicione outras propriedades conforme necessário
- };
- data.Add(record);
- }
- }
- }
- }
-
- return data;
- }
- static List convertEmpresasJson(List jsonData)
- {
- List data = new List();
-
- for (int i = 0;i convertGestoresJson(List jsonData)
- {
- List data = new List();
-
- for (int i = 0; i < jsonData.Count; i++)
- {
-
- Pipefy.ClasseGestores record = new Pipefy.ClasseGestores();
- record.id = jsonData[i].node.id.ToString();
-
- for (int j = 0; j < jsonData[i].node.record_fields.Length; j++)
- {
- if (jsonData[i].node.record_fields[j].field.id == "gest_o")
- {
- record.gestores = jsonData[i].node.record_fields[j].value;
-
- }
- }
-
- // Adicione outras propriedades conforme necessário
- data.Add(record);
- }
-
- return data;
- }
-
- static List CompareData(List databaseData, List jsonList, List jsonListGestores)
- {
- if (jsonList == null | jsonListGestores == null)
- {
- return databaseData;
- }
-
- List recordsMissingInJson = new List();
- var exists = false;
-
- foreach (var record in databaseData)
- {
- exists = false;
-
- for (var j = 0; j < jsonList.Count; j++) {
-
- //Console.WriteLine(jsonList[j].c_digo_smart.ToString().Replace(".0", "") + " - " + record.c_digo_smart.ToString() + " - " + (jsonList[j].c_digo_smart.ToString().Replace(".0", "") == record.c_digo_smart.ToString()));
-
- if (jsonList[j].c_digo_smart.ToString().Replace(".0", "") == record.c_digo_smart.ToString())
- {
- exists = true;
- break;
- }
-
- }
-
- Console.Clear();
-
- if (exists == false) {
- record.gestores = findGestores(record.gestores,jsonListGestores);
-
- if (record.gestores != "0")
- {
- recordsMissingInJson.Add(record);
- }
- //else
- //{
- // int test = 10;
- //}
- }
- }
-
- return recordsMissingInJson;
- }
- static string findGestores(string sCodigo, List jsonListGestores)
- {
- for (var i = 0; i < jsonListGestores.Count; i++)
- {
- if (sCodigo == jsonListGestores[i].gestores.ToString())
- {
- return jsonListGestores[i].id;
- }
- }
- return "0";
+ Console.Write($"\rEncerrando em {endTime.Subtract(e.SignalTime).Seconds.ToString()}");
}
}
\ No newline at end of file
diff --git a/SOLID-Refactoring-Plan.md b/SOLID-Refactoring-Plan.md
new file mode 100644
index 0000000..f483285
--- /dev/null
+++ b/SOLID-Refactoring-Plan.md
@@ -0,0 +1,64 @@
+# SOLID Refactoring Plan for Pipefy Project
+
+This document outlines a step-by-step plan to refactor the Pipefy project to comply with SOLID principles. Check off each step as you complete it.
+
+---
+
+## 1. Preparation
+- [x] Review current codebase and identify major responsibilities in `Program.cs` and `data.cs`.
+ - **Program.cs**: Handles configuration loading, user interaction, API communication, JSON deserialization, database access, data comparison, record creation, console output, timer logic, and orchestration.
+ - **data.cs**: Contains data models for API responses, business entities, and configuration. No business logic.
+- [x] List all external dependencies (API, database, configuration).
+ - **Pipefy API**: Used for fetching and creating records (GraphQL over HTTP, requires API token and table IDs).
+ - **Access Database**: Used for reading local records (via OleDb, requires DB path and password).
+ - **Configuration**: Loaded from `appsettings.json` (contains DB path, API token, API URL, table IDs).
+ - **NuGet Packages**: Microsoft.Extensions.Configuration, Newtonsoft.Json, System.Data.OleDb, etc.
+
+## 2. Project Structure
+- [x] Create folders: `Services/`, `Models/`, `Mappers/` (if needed).
+ - `Services/`: For service and interface implementations (API, DB, config, business logic).
+ - `Models/`: For data models (move from `data.cs`).
+ - `Mappers/`: For mapping logic between API/DB and domain models (optional, if mapping grows).
+ - [ ] Integrate ORM (e.g., Entity Framework Core) to abstract DB access and ease future DB changes. (Next step)
+- [x] Move or create files as needed for separation of concerns.
+
+## 3. Single Responsibility Principle (SRP)
+- [x] Extract configuration loading into `IConfigurationService` and `ConfigurationService`.
+- [x] Extract Pipefy API logic into `IPipefyApiService` and `PipefyApiService`.
+- [x] Extract database logic into `IDatabaseService` and `DatabaseService`.
+- [x] Extract data mapping logic into `IDataMapper` and `DataMapper`.
+- [x] Extract business logic (comparison, orchestration) into `IBusinessLogicService` and `BusinessLogicService`.
+- [x] Remove static business/data methods from `Program.cs` and ensure all logic is in services.
+
+## 4. Open/Closed Principle (OCP)
+- [x] Define interfaces for each service (already done: IConfigurationService, IPipefyApiService, IDatabaseService, IDataMapper, IBusinessLogicService).
+- [x] Ensure new data sources or logic can be added by implementing new classes, not modifying existing ones (all main logic is now behind interfaces and DI).
+
+## 5. Liskov Substitution Principle (LSP)
+- [ ] Ensure all service implementations can be replaced by their interfaces without breaking functionality.
+
+## 6. Interface Segregation Principle (ISP)
+- [ ] Keep interfaces focused and small.
+- [ ] Split large interfaces if needed.
+
+## 7. Dependency Inversion Principle (DIP)
+- [x] Refactor `Program.cs` to depend on abstractions (interfaces), not concrete classes.
+- [x] Use dependency injection to provide services to the main program.
+
+## 8. Testing
+- [ ] Add or update unit tests for each service.
+- [ ] Ensure business logic is testable in isolation.
+
+## 9. Documentation
+- [ ] Update this plan as you progress.
+- [ ] Document new structure and usage in a `README.md` or similar file.
+
+---
+
+**Progress Tracking:**
+- Mark each step as complete (`[x]`) as you finish it.
+- Add notes or decisions below each step if needed.
+
+---
+
+_Last updated: May 16, 2025_
diff --git a/Services/BusinessLogicService.cs b/Services/BusinessLogicService.cs
new file mode 100644
index 0000000..2a8328f
--- /dev/null
+++ b/Services/BusinessLogicService.cs
@@ -0,0 +1,50 @@
+using System.Collections.Generic;
+using Pipefy.Models;
+
+namespace Pipefy.Services
+{
+ public class BusinessLogicService : IBusinessLogicService
+ {
+ public List CompareData(List databaseData, List jsonList, List jsonListGestores)
+ {
+ if (jsonList == null || jsonListGestores == null)
+ {
+ return databaseData;
+ }
+ List recordsMissingInJson = new List();
+ foreach (var record in databaseData)
+ {
+ bool exists = false;
+ for (var j = 0; j < jsonList.Count; j++)
+ {
+ if (jsonList[j].c_digo_smart!.ToString().Replace(".0", "") == record.c_digo_smart!.ToString())
+ {
+ exists = true;
+ break;
+ }
+ }
+ if (!exists)
+ {
+ record.gestores = FindGestores(record.gestores!, jsonListGestores);
+ if (record.gestores != "0")
+ {
+ recordsMissingInJson.Add(record);
+ }
+ }
+ }
+ return recordsMissingInJson;
+ }
+
+ public string FindGestores(string sCodigo, List jsonListGestores)
+ {
+ for (var i = 0; i < jsonListGestores.Count; i++)
+ {
+ if (sCodigo == jsonListGestores[i].gestores!.ToString())
+ {
+ return jsonListGestores[i].id!;
+ }
+ }
+ return "0";
+ }
+ }
+}
diff --git a/Services/ConfigurationService.cs b/Services/ConfigurationService.cs
new file mode 100644
index 0000000..120441c
--- /dev/null
+++ b/Services/ConfigurationService.cs
@@ -0,0 +1,30 @@
+using Microsoft.Extensions.Configuration;
+using Pipefy.Models;
+
+namespace Pipefy.Services
+{
+ public class ConfigurationService : IConfigurationService
+ {
+ private readonly IConfiguration _configuration;
+ public ConfigurationService()
+ {
+ _configuration = new ConfigurationBuilder()
+ .SetBasePath(Directory.GetCurrentDirectory())
+ .AddJsonFile("appsettings.json", optional: false)
+ .Build();
+ }
+ public AppSettings GetAppSettings()
+ {
+ return _configuration.GetSection("AppSettings").Get()!;
+ }
+
+ public AppSettings LoadAppSettings()
+ {
+ var configurationBuilder = new ConfigurationBuilder()
+ .SetBasePath(Directory.GetCurrentDirectory())
+ .AddJsonFile("appsettings.json", optional: false);
+ IConfiguration configuration = configurationBuilder.Build();
+ return configuration.GetSection("AppSettings").Get()!;
+ }
+ }
+}
diff --git a/Services/DataMapper.cs b/Services/DataMapper.cs
new file mode 100644
index 0000000..d599ae4
--- /dev/null
+++ b/Services/DataMapper.cs
@@ -0,0 +1,57 @@
+using System.Collections.Generic;
+using Pipefy.Models;
+
+namespace Pipefy.Services
+{
+ public class DataMapper : IDataMapper
+ {
+ public List ConvertEmpresasJson(List jsonData)
+ {
+ List data = new List();
+ for (int i = 0; i < jsonData.Count; i++)
+ {
+ ClasseEmpresas record = new ClasseEmpresas();
+ record.rec_id = jsonData[i].node.id;
+ for (int j = 0; j < jsonData[i].node.record_fields.Length; j++)
+ {
+ switch (jsonData[i].node.record_fields[j].field.id)
+ {
+ case "nome_da_empresa":
+ record.nome_da_empresa = jsonData[i].node.record_fields[j].value;
+ break;
+ case "c_digo_smart":
+ record.c_digo_smart = jsonData[i].node.record_fields[j].value!.Replace(".0", "");
+ break;
+ case "modalidade":
+ record.modalidade = jsonData[i].node.record_fields[j].value;
+ break;
+ case "gestores":
+ record.gestores = jsonData[i].node.record_fields[j].array_value.FirstOrDefault()!.ToString();
+ break;
+ }
+ }
+ data.Add(record);
+ }
+ return data;
+ }
+
+ public List ConvertGestoresJson(List jsonData)
+ {
+ List data = new List();
+ for (int i = 0; i < jsonData.Count; i++)
+ {
+ ClasseGestores record = new ClasseGestores();
+ record.id = jsonData[i].node.id!.ToString();
+ for (int j = 0; j < jsonData[i].node.record_fields.Length; j++)
+ {
+ if (jsonData[i].node.record_fields[j].field.id == "gest_o")
+ {
+ record.gestores = jsonData[i].node.record_fields[j].value;
+ }
+ }
+ data.Add(record);
+ }
+ return data;
+ }
+ }
+}
diff --git a/Services/DatabaseService.cs b/Services/DatabaseService.cs
new file mode 100644
index 0000000..3b76108
--- /dev/null
+++ b/Services/DatabaseService.cs
@@ -0,0 +1,47 @@
+using System.Collections.Generic;
+using System.Data.OleDb;
+using System.Text;
+using Pipefy.Models;
+
+namespace Pipefy.Services
+{
+ public class DatabaseService : IDatabaseService
+ {
+ public List GetDataFromDatabase(string connSourcePath)
+ {
+ string connectionString = @"Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" + connSourcePath + ";Jet OLEDB:Database Password=gds21;";
+ List data = new List();
+ using (OleDbConnection connection = new OleDbConnection(connectionString))
+ {
+ connection.Open();
+ StringBuilder sqlQuery = new StringBuilder();
+ sqlQuery.Append("SELECT cod_smart_cliente, \n");
+ sqlQuery.Append(" cliente, \n");
+ sqlQuery.Append(" modalidade, \n");
+ sqlQuery.Append(" gestao \n");
+ sqlQuery.Append("FROM dados_cadastrais \n");
+ sqlQuery.Append("WHERE cod_smart_unidade LIKE \"%001\" \n");
+ sqlQuery.Append(" AND unidade_gerenciada;");
+ using (OleDbCommand command = new OleDbCommand(sqlQuery.ToString(), connection))
+ {
+ using (OleDbDataReader reader = command.ExecuteReader())
+ {
+ while (reader.Read())
+ {
+ ClasseEmpresas record = new ClasseEmpresas
+ {
+ c_digo_smart = reader["Cod_Smart_cliente"].ToString(),
+ nome_da_empresa = reader["Cliente"].ToString(),
+ modalidade = reader["Modalidade"].ToString(),
+ gestores = reader["Gestao"].ToString(),
+ rec_id = ""
+ };
+ data.Add(record);
+ }
+ }
+ }
+ }
+ return data;
+ }
+ }
+}
diff --git a/Services/IBusinessLogicService.cs b/Services/IBusinessLogicService.cs
new file mode 100644
index 0000000..8dbf000
--- /dev/null
+++ b/Services/IBusinessLogicService.cs
@@ -0,0 +1,11 @@
+using System.Collections.Generic;
+using Pipefy.Models;
+
+namespace Pipefy.Services
+{
+ public interface IBusinessLogicService
+ {
+ List CompareData(List databaseData, List jsonList, List jsonListGestores);
+ string FindGestores(string sCodigo, List jsonListGestores);
+ }
+}
diff --git a/Services/IConfigurationService.cs b/Services/IConfigurationService.cs
new file mode 100644
index 0000000..1a832b2
--- /dev/null
+++ b/Services/IConfigurationService.cs
@@ -0,0 +1,10 @@
+using Pipefy.Models;
+
+namespace Pipefy.Services
+{
+ public interface IConfigurationService
+ {
+ AppSettings GetAppSettings();
+ AppSettings LoadAppSettings();
+ }
+}
diff --git a/Services/IDataMapper.cs b/Services/IDataMapper.cs
new file mode 100644
index 0000000..d0afd4e
--- /dev/null
+++ b/Services/IDataMapper.cs
@@ -0,0 +1,11 @@
+using System.Collections.Generic;
+using Pipefy.Models;
+
+namespace Pipefy.Services
+{
+ public interface IDataMapper
+ {
+ List ConvertEmpresasJson(List jsonData);
+ List ConvertGestoresJson(List jsonData);
+ }
+}
diff --git a/Services/IDatabaseService.cs b/Services/IDatabaseService.cs
new file mode 100644
index 0000000..e655af1
--- /dev/null
+++ b/Services/IDatabaseService.cs
@@ -0,0 +1,10 @@
+using System.Collections.Generic;
+using Pipefy.Models;
+
+namespace Pipefy.Services
+{
+ public interface IDatabaseService
+ {
+ List GetDataFromDatabase(string connSourcePath);
+ }
+}
diff --git a/Services/IPipefyApiService.cs b/Services/IPipefyApiService.cs
new file mode 100644
index 0000000..aec092d
--- /dev/null
+++ b/Services/IPipefyApiService.cs
@@ -0,0 +1,14 @@
+using Newtonsoft.Json.Linq;
+using System.Threading.Tasks;
+using System.Collections.Generic;
+using Pipefy.Models;
+
+namespace Pipefy.Services
+{
+ public interface IPipefyApiService
+ {
+ Task GetRecordsAsync(string tableId);
+ Task GetGestoresAsync(string tableId);
+ Task CreateRecordsAsync(string tableId, List records);
+ }
+}
diff --git a/Services/PipefyApiService.cs b/Services/PipefyApiService.cs
new file mode 100644
index 0000000..2d62b4e
--- /dev/null
+++ b/Services/PipefyApiService.cs
@@ -0,0 +1,97 @@
+using Newtonsoft.Json.Linq;
+using Newtonsoft.Json;
+using Pipefy.Models;
+using System.Net.Http;
+using System.Text;
+using System.Threading.Tasks;
+using System.Collections.Generic;
+
+namespace Pipefy.Services
+{
+ public class PipefyApiService : IPipefyApiService
+ {
+ private readonly string _apiUrl;
+ private readonly string _token;
+ public PipefyApiService(string apiUrl, string token)
+ {
+ _apiUrl = apiUrl;
+ _token = token;
+ }
+
+ public async Task GetRecordsAsync(string tableId)
+ {
+ JArray allRecords = new JArray();
+ string cursor = "null";
+ string query = $"{{\"query\":\"query GetRecords($cursor: String){{ table_records(table_id: \\\"{tableId}\\\",first:50,after:$cursor){{ pageInfo{{ hasNextPage endCursor }} edges{{ node{{ id record_fields{{ field {{ id }} value array_value }} }} }} }}}}\",\"variables\":{{\"cursor\":{cursor}}}}}";
+ bool hasNextPage = true;
+ while (hasNextPage)
+ {
+ var httpClient = new HttpClient();
+ httpClient.DefaultRequestHeaders.Add("Authorization", "Bearer " + _token);
+ var request = new HttpRequestMessage(HttpMethod.Post, _apiUrl);
+ request.Headers.Add("Accept", "application/json");
+ var content = new StringContent(query, null, "application/json");
+ request.Content = content;
+ var response = await httpClient.SendAsync(request);
+ if (response.IsSuccessStatusCode)
+ {
+ var responseContent = await response.Content.ReadAsStringAsync();
+ var responseData = JObject.Parse(responseContent);
+ var records = responseData["data"]!["table_records"]!["edges"];
+ foreach (var record in records!)
+ {
+ allRecords.Add(record);
+ }
+ hasNextPage = responseData["data"]!["table_records"]!["pageInfo"]!["hasNextPage"]!.Value();
+ cursor = responseData["data"]!["table_records"]!["pageInfo"]!["endCursor"]!.Value()!;
+ query = $"{{\"query\":\"query GetRecords($cursor: String){{ table_records(table_id: \\\"{tableId}\\\",first:50,after:$cursor){{ pageInfo{{ hasNextPage endCursor }} edges{{ node{{ record_fields{{ field {{ id }} value array_value }} }} }} }}}}\",\"variables\":{{\"cursor\":\"{cursor}\"}}}}";
+ }
+ else
+ {
+ allRecords.Clear();
+ return allRecords;
+ }
+ }
+ return allRecords;
+ }
+
+ public async Task GetGestoresAsync(string tableId)
+ {
+ // For now, this is the same as GetRecordsAsync, but can be customized if needed
+ return await GetRecordsAsync(tableId);
+ }
+
+ public async Task CreateRecordsAsync(string tableId, List records)
+ {
+ // This method should build the GraphQL mutation and send it in batches
+ // For brevity, this is a simplified version
+ if (records == null || records.Count == 0) return true;
+ string strQuery = "{\"query\":\"mutation {\\r\\n ";
+ for (int i = 0; i < records.Count; i++)
+ {
+ if (i % 49 == 0) { strQuery = "{\"query\":\"mutation {\\r\\n "; }
+ strQuery = strQuery + $"N{i}: createTableRecord(input: {{ table_id: \\\"{tableId}\\\", fields_attributes: [ {{ field_id: \\\"nome_da_empresa\\\", field_value: \\\"{records[i].nome_da_empresa}\\\" }} {{ field_id: \\\"c_digo_smart\\\", field_value: \\\"{records[i].c_digo_smart}\\\" }} {{ field_id: \\\"modalidade\\\", field_value: \\\"{records[i].modalidade}\\\" }} {{ field_id: \\\"gestores\\\", field_value: \\\"{records[i].gestores}\\\" }}]}}) {{ table_record {{ id }}}}\\r\\n ";
+ if (i % 48 == 0 && i != 0)
+ {
+ strQuery = strQuery + "}\",\"variables\":{}}";
+ var httpClient = new HttpClient();
+ httpClient.DefaultRequestHeaders.Add("Authorization", "Bearer " + _token);
+ var request = new HttpRequestMessage(HttpMethod.Post, _apiUrl);
+ request.Headers.Add("Accept", "application/json");
+ var content = new StringContent(strQuery, null, "application/json");
+ request.Content = content;
+ var response = await httpClient.SendAsync(request);
+ }
+ }
+ strQuery = strQuery + "}\",\"variables\":{}}";
+ var finalClient = new HttpClient();
+ finalClient.DefaultRequestHeaders.Add("Authorization", "Bearer " + _token);
+ var finalRequest = new HttpRequestMessage(HttpMethod.Post, _apiUrl);
+ finalRequest.Headers.Add("Accept", "application/json");
+ var finalContent = new StringContent(strQuery, null, "application/json");
+ finalRequest.Content = finalContent;
+ var finalResponse = await finalClient.SendAsync(finalRequest);
+ return finalResponse.IsSuccessStatusCode;
+ }
+ }
+}
diff --git a/Services/README.md b/Services/README.md
new file mode 100644
index 0000000..f5a672c
--- /dev/null
+++ b/Services/README.md
@@ -0,0 +1 @@
+// This folder will contain service interfaces and implementations (API, DB, config, business logic)
diff --git a/data.cs b/data.cs
index 8cb1427..e90ab63 100644
--- a/data.cs
+++ b/data.cs
@@ -5,67 +5,9 @@ using System.Text;
using System.Threading.Tasks;
using Microsoft.Extensions.Configuration;
+// All model classes have been moved to Models/Entities.cs under Pipefy.Models namespace.
+// This file should now only contain logic or be removed if not needed.
+
namespace Pipefy
{
- public class RootObject
- {
- public Node node { get; set; }
- }
- public class RootGestor
- {
- public NodeGestor node { get; set; }
- }
-
- public class Data
- {
- public Node node { get; set; }
- }
-
- public class Node
- {
- public string id { get; set; }
- public Record_Fields[] record_fields { get; set; }
- }
- public class NodeGestor
- {
- public string ?id { get; set; }
- public Record_Fields[] record_fields { get; set; }
- }
- public class Record_Fields
- {
- public Field field { get; set; }
- public string ?value { get; set; }
- public string[] array_value { get; set; }
- }
-
- public class Field
- {
- public string ?id { get; set; }
- }
-
- public class ClasseEmpresas
- {
- public string ?c_digo_smart { get; set; }
- public string ?nome_da_empresa { get; set; }
- public string ?modalidade { get; set; }
- public string ?gestores { get; set; }
- public string rec_id { get; set; }
-
- }
-
- public class ClasseGestores
- {
- public string ?id { get; set; }
- public string ?gestores { get; set; }
-
- }
-
- public class AppSettings
- {
- public string DB_PATH { get; set; }
- public string PIPEFY_API_TOKEN { get; set; }
- public string PIPEFY_API_URL { get; set; }
- public string PIPEFY_TABLE_ID { get; set; }
- public string PIPEFY_TABLE_ID_GESTORES { get; set; }
- }
}