Compare commits
10 Commits
97b8b1c3a6
...
d18b736e36
| Author | SHA1 | Date | |
|---|---|---|---|
| d18b736e36 | |||
| 4bb348cb7f | |||
|
|
5e2f7c04d9 | ||
|
|
cb2944a688 | ||
|
|
a614b5a7fc | ||
|
|
412b28eec3 | ||
|
|
b238bbe353 | ||
|
|
589b09279d | ||
|
|
9f6a277f31 | ||
|
|
f8963096ef |
3
.gitignore
vendored
3
.gitignore
vendored
@ -361,3 +361,6 @@ MigrationBackup/
|
|||||||
|
|
||||||
# Fody - auto-generated XML schema
|
# Fody - auto-generated XML schema
|
||||||
FodyWeavers.xsd
|
FodyWeavers.xsd
|
||||||
|
|
||||||
|
# History for Visual Studio
|
||||||
|
.history/
|
||||||
|
|||||||
1
Mappers/README.md
Normal file
1
Mappers/README.md
Normal file
@ -0,0 +1 @@
|
|||||||
|
// This folder will contain mapping logic between API/DB and domain models if needed
|
||||||
59
Models/Entities.cs
Normal file
59
Models/Entities.cs
Normal file
@ -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; }
|
||||||
|
}
|
||||||
|
}
|
||||||
1
Models/README.md
Normal file
1
Models/README.md
Normal file
@ -0,0 +1 @@
|
|||||||
|
// This folder will contain all data models (move from data.cs)
|
||||||
8
Pipefy.code-workspace
Normal file
8
Pipefy.code-workspace
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
{
|
||||||
|
"folders": [
|
||||||
|
{
|
||||||
|
"path": "."
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"settings": {}
|
||||||
|
}
|
||||||
@ -2,14 +2,31 @@
|
|||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<OutputType>Exe</OutputType>
|
<OutputType>Exe</OutputType>
|
||||||
<TargetFramework>net7.0-windows</TargetFramework>
|
<TargetFramework>net8.0-windows</TargetFramework>
|
||||||
<ImplicitUsings>enable</ImplicitUsings>
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
<Nullable>enable</Nullable>
|
<Nullable>enable</Nullable>
|
||||||
|
<UserSecretsId>1b2d76eb-7ab5-428f-9f67-13b6bf96375d</UserSecretsId>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<PackageReference Include="Dapper" Version="2.1.66" />
|
||||||
|
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="8.0.0" />
|
||||||
|
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="8.0.0">
|
||||||
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
|
<PrivateAssets>all</PrivateAssets>
|
||||||
|
</PackageReference>
|
||||||
|
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="8.0.0" />
|
||||||
|
<PackageReference Include="Microsoft.Extensions.Configuration" Version="8.0.0" />
|
||||||
|
<PackageReference Include="Microsoft.Extensions.Configuration.UserSecrets" Version="8.0.0" />
|
||||||
|
<PackageReference Include="Microsoft.Extensions.Hosting" Version="8.0.0" />
|
||||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
|
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
|
||||||
<PackageReference Include="System.Data.OleDb" Version="7.0.0" />
|
<PackageReference Include="System.Data.OleDb" Version="8.0.0" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<None Update="appsettings.json">
|
||||||
|
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||||
|
</None>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
|||||||
360
Program.cs
360
Program.cs
@ -1,301 +1,97 @@
|
|||||||
using System;
|
using System.Data.OleDb;
|
||||||
using System.Data.OleDb;
|
|
||||||
using System.Net.Http;
|
|
||||||
using System.Net.Http.Headers;
|
|
||||||
using System.Text.Json;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using Newtonsoft.Json;
|
|
||||||
using Newtonsoft.Json.Linq;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Reflection.Metadata;
|
|
||||||
using Pipefy;
|
using Pipefy;
|
||||||
|
using Pipefy.Models;
|
||||||
|
using Microsoft.Extensions.Configuration;
|
||||||
|
using Newtonsoft.Json.Linq;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
using System.Text;
|
||||||
|
using System.Timers;
|
||||||
|
using Pipefy.Services;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
|
||||||
class Program
|
class Program
|
||||||
{
|
{
|
||||||
|
static DateTime endTime;
|
||||||
|
static void SetEndTime(DateTime date)
|
||||||
|
{
|
||||||
|
endTime = date;
|
||||||
|
}
|
||||||
static async Task Main(string[] args)
|
static async Task Main(string[] args)
|
||||||
{
|
{
|
||||||
// URL da API que você deseja chamar
|
// Setup DI
|
||||||
string apiUrl = "https://api.pipefy.com/graphql";
|
var serviceCollection = new ServiceCollection();
|
||||||
string PipefyToken = "eyJhbGciOiJIUzUxMiJ9.eyJpc3MiOiJQaXBlZnkiLCJpYXQiOjE2OTg4NTYyMjcsImp0aSI6IjM2N2Y4M2NhLWZjODYtNGRhOC04ODEyLTkzODRkZGZkODc0MiIsInN1YiI6MzAyNTM0MzY2LCJ1c2VyIjp7ImlkIjozMDI1MzQzNjYsImVtYWlsIjoiYmFjazVAZW5lcmdpYXNtYXJ0LmNvbS5iciIsImFwcGxpY2F0aW9uIjozMDAyODkyNDgsInNjb3BlcyI6W119LCJpbnRlcmZhY2VfdXVpZCI6bnVsbH0.o13j9c_y3G3HX35qhX4PmkkibGsmlHsk5dL_Bxsr1CKV5Jlgj218kJdEmriS7aHiw0-P7sfs-bu4YcElfuyiqg";
|
serviceCollection.AddSingleton<IConfigurationService, ConfigurationService>();
|
||||||
string ConnSourcePath = @"C:\Users\contratos\Documents\Giuliano\Pipefy.accdb";
|
serviceCollection.AddSingleton<IPipefyApiService>(provider => {
|
||||||
string PipefyTokenTableID = "b9t-7uD5";
|
var config = provider.GetRequiredService<IConfigurationService>().GetAppSettings();
|
||||||
|
return new PipefyApiService(config.PIPEFY_API_URL, config.PIPEFY_API_TOKEN);
|
||||||
|
});
|
||||||
|
serviceCollection.AddSingleton<IDatabaseService, DatabaseService>();
|
||||||
|
serviceCollection.AddSingleton<IDataMapper, DataMapper>();
|
||||||
|
serviceCollection.AddSingleton<IBusinessLogicService, BusinessLogicService>();
|
||||||
|
var serviceProvider = serviceCollection.BuildServiceProvider();
|
||||||
|
|
||||||
string? cursor = "null";
|
var configService = serviceProvider.GetRequiredService<IConfigurationService>();
|
||||||
|
var AppSettings = configService.GetAppSettings();
|
||||||
|
if (AppSettings is null){ Environment.Exit(1); }
|
||||||
|
Console.Clear();
|
||||||
|
|
||||||
string 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}}}}}";
|
var pipefyApi = serviceProvider.GetRequiredService<IPipefyApiService>();
|
||||||
Console.WriteLine(query);
|
JArray allRecords = await pipefyApi.GetRecordsAsync(AppSettings.PIPEFY_TABLE_ID);
|
||||||
bool hasNextPage = true;
|
JArray allGestores = await pipefyApi.GetGestoresAsync(AppSettings.PIPEFY_TABLE_ID_GESTORES);
|
||||||
bool hasSucceeded = true;
|
Console.Clear();
|
||||||
JArray allRecords = new JArray();
|
|
||||||
|
|
||||||
while (hasNextPage)
|
if (allRecords is not null)
|
||||||
{
|
|
||||||
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);
|
|
||||||
|
|
||||||
var records = responseData["data"]["table_records"]["edges"];
|
|
||||||
foreach (var record in records)
|
|
||||||
{
|
|
||||||
allRecords.Add(record);
|
|
||||||
}
|
|
||||||
|
|
||||||
hasNextPage = responseData["data"]["table_records"]["pageInfo"]["hasNextPage"].Value<bool>();
|
|
||||||
cursor = responseData["data"]["table_records"]["pageInfo"]["endCursor"].Value<string>();
|
|
||||||
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}");
|
|
||||||
hasSucceeded = false;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (hasSucceeded)
|
|
||||||
{
|
{
|
||||||
|
string strGestores = JsonConvert.SerializeObject(allGestores);
|
||||||
|
var jsonGestores = JsonConvert.DeserializeObject<List<RootGestor>>(strGestores)!;
|
||||||
|
var mapper = serviceProvider.GetRequiredService<IDataMapper>();
|
||||||
|
List<ClasseGestores> jsonListGestores = mapper.ConvertGestoresJson(jsonGestores);
|
||||||
string strJson = JsonConvert.SerializeObject(allRecords);
|
string strJson = JsonConvert.SerializeObject(allRecords);
|
||||||
// Desserialize o JSON em objetos C#
|
var jsonData = JsonConvert.DeserializeObject<List<RootObject>>(strJson)!;
|
||||||
var jsonData = JsonConvert.DeserializeObject<Pipefy.RootObject>(strJson);
|
List<ClasseEmpresas> jsonList = mapper.ConvertEmpresasJson(jsonData);
|
||||||
|
var databaseService = serviceProvider.GetRequiredService<IDatabaseService>();
|
||||||
// Consulte os dados da tabela no banco de dados Access
|
List<ClasseEmpresas> databaseData = databaseService.GetDataFromDatabase(AppSettings.DB_PATH);
|
||||||
List<ClasseEmpresas> databaseData = GetDataFromDatabase(ConnSourcePath);
|
var businessLogic = serviceProvider.GetRequiredService<IBusinessLogicService>();
|
||||||
|
List<ClasseEmpresas> recordsMissingInJson = businessLogic.CompareData(databaseData, jsonList, jsonListGestores);
|
||||||
// Compare os dados e encontre os registros ausentes no JSON
|
recordsMissingInJson.AddRange(businessLogic.CompareData(jsonList, databaseData, jsonListGestores));
|
||||||
List<ClasseEmpresas> recordsMissingInJson = CompareData(databaseData, jsonData);
|
if (recordsMissingInJson.Count != 0 && recordsMissingInJson != null)
|
||||||
|
{
|
||||||
// Faça algo com os registros ausentes
|
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)
|
foreach (var record in recordsMissingInJson)
|
||||||
{
|
{
|
||||||
Console.WriteLine($"Registro ausente no JSON - ID: {record.c_odigo_smart}, Nome: {record.nome_da_empresa}");
|
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($"{recordsMissingInJson!.Count} registros encontrados.");
|
||||||
}
|
}
|
||||||
|
|
||||||
static List<ClasseEmpresas> GetDataFromDatabase(string ConnSourcePath)
|
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 void OnTimerElapsed(object sender, ElapsedEventArgs e)
|
||||||
{
|
{
|
||||||
string connectionString = @"Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" + ConnSourcePath;
|
Console.Write($"\rEncerrando em {endTime.Subtract(e.SignalTime).Seconds.ToString()}");
|
||||||
List<ClasseEmpresas> data = new List<ClasseEmpresas>();
|
|
||||||
|
|
||||||
using (OleDbConnection connection = new OleDbConnection(connectionString))
|
|
||||||
{
|
|
||||||
connection.Open();
|
|
||||||
|
|
||||||
// Execute uma consulta SQL para recuperar dados da tabela no banco de dados Access
|
|
||||||
string sqlQuery = "SELECT * FROM tblEmpresas";
|
|
||||||
using (OleDbCommand command = new OleDbCommand(sqlQuery, connection))
|
|
||||||
{
|
|
||||||
using (OleDbDataReader reader = command.ExecuteReader())
|
|
||||||
{
|
|
||||||
while (reader.Read())
|
|
||||||
{
|
|
||||||
ClasseEmpresas record = new ClasseEmpresas
|
|
||||||
{
|
|
||||||
c_odigo_smart = (int)reader["Código Smart"],
|
|
||||||
nome_da_empresa = (string)reader["Nome da empresa"],
|
|
||||||
modalidade = (string)reader["modalidade"],
|
|
||||||
gestores = (string)reader["gestores"],
|
|
||||||
|
|
||||||
// Adicione outras propriedades conforme necessário
|
|
||||||
};
|
|
||||||
data.Add(record);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return data;
|
|
||||||
}
|
|
||||||
|
|
||||||
static List<ClasseEmpresas> CompareData(List<ClasseEmpresas> databaseData, Pipefy.RootObject jsonData)
|
|
||||||
{
|
|
||||||
if (jsonData == null)
|
|
||||||
{
|
|
||||||
return databaseData;
|
|
||||||
}
|
|
||||||
|
|
||||||
List<ClasseEmpresas> recordsMissingInJson = new List<ClasseEmpresas>();
|
|
||||||
|
|
||||||
foreach (var record in databaseData)
|
|
||||||
{
|
|
||||||
//if (jsonData.node.Any(item => item.recordFields[0].value.ToString() == record.c_odigo_smart.ToString()))
|
|
||||||
//{
|
|
||||||
// continue;
|
|
||||||
//}
|
|
||||||
recordsMissingInJson.Add(record);
|
|
||||||
}
|
|
||||||
|
|
||||||
return recordsMissingInJson;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class ClasseEmpresas
|
|
||||||
{
|
|
||||||
public int c_odigo_smart { get; set; }
|
|
||||||
public string nome_da_empresa { get; set; }
|
|
||||||
public string modalidade { get; set; }
|
|
||||||
public string gestores { get; set; }
|
|
||||||
// Adicione outras propriedades conforme necessário
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//using System;
|
|
||||||
//using System.Data.OleDb;
|
|
||||||
//using System.Net.Http;
|
|
||||||
//using System.Net.Http.Headers;
|
|
||||||
//using System.Text.Json;
|
|
||||||
//using System.Threading.Tasks;
|
|
||||||
//using Newtonsoft.Json;
|
|
||||||
//using Newtonsoft.Json.Linq;
|
|
||||||
//using System.Collections.Generic;
|
|
||||||
|
|
||||||
//class Program
|
|
||||||
//{
|
|
||||||
// static async Task Main(string[] args)
|
|
||||||
// {
|
|
||||||
// // URL da API que você deseja chamar
|
|
||||||
// string apiUrl = "https://api.pipefy.com/graphql";
|
|
||||||
// string PipefyToken = "eyJhbGciOiJIUzUxMiJ9.eyJpc3MiOiJQaXBlZnkiLCJpYXQiOjE2OTg4NTYyMjcsImp0aSI6IjM2N2Y4M2NhLWZjODYtNGRhOC04ODEyLTkzODRkZGZkODc0MiIsInN1YiI6MzAyNTM0MzY2LCJ1c2VyIjp7ImlkIjozMDI1MzQzNjYsImVtYWlsIjoiYmFjazVAZW5lcmdpYXNtYXJ0LmNvbS5iciIsImFwcGxpY2F0aW9uIjozMDAyODkyNDgsInNjb3BlcyI6W119LCJpbnRlcmZhY2VfdXVpZCI6bnVsbH0.o13j9c_y3G3HX35qhX4PmkkibGsmlHsk5dL_Bxsr1CKV5Jlgj218kJdEmriS7aHiw0-P7sfs-bu4YcElfuyiqg";
|
|
||||||
// string ConnSourcePath = @"C:\Users\contratos\Documents\Giuliano\Pipefy.accdb";
|
|
||||||
// string PipefyTokenTableID = "b9t-7uD5";
|
|
||||||
|
|
||||||
|
|
||||||
// // Crie uma instância HttpClient
|
|
||||||
// using (HttpClient httpClient = new HttpClient())
|
|
||||||
// {
|
|
||||||
// // Defina os headers da requisição (opcional)
|
|
||||||
// httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
|
|
||||||
// httpClient.DefaultRequestHeaders.Add("Accept", "application/json");
|
|
||||||
// httpClient.DefaultRequestHeaders.Add("Authorization", "Bearer " + PipefyToken);
|
|
||||||
|
|
||||||
// // Crie a consulta GraphQL
|
|
||||||
// //string rawGraphQuery = @"{""query"":""query{\r\n table_records(table_id: \""" + PipefyTokenTableID + @"\"") {\r\n edges {\r\n node {\r\n id\r\n record_fields{\r\n field{\r\n id\r\n }\r\n value\r\n }\r\n }\r\n }\r\n }\r\n}"",""variables"":{}}";
|
|
||||||
// string rawGraphQuery = "{\"query\":\"query { table_records(table_id: \\\"" + PipefyTokenTableID + "\\\") { edges { node { id record_fields { field { id } value } } } } }\",\"variables\":{}}";
|
|
||||||
// string query = /*lang=json,strict*/ rawGraphQuery;
|
|
||||||
|
|
||||||
// // Defina o conteúdo do corpo da requisição
|
|
||||||
// var content = new StringContent(query, System.Text.Encoding.UTF8, "application/json");
|
|
||||||
|
|
||||||
// // Envie a requisição POST com a consulta GraphQL
|
|
||||||
// var response = await httpClient.PostAsync(apiUrl, content);
|
|
||||||
|
|
||||||
// if (response.IsSuccessStatusCode)
|
|
||||||
// {
|
|
||||||
// string responseBody = await response.Content.ReadAsStringAsync();
|
|
||||||
|
|
||||||
// Console.WriteLine("Resposta bem-sucedida:");
|
|
||||||
// Console.WriteLine(responseBody);
|
|
||||||
|
|
||||||
// // Desserialize o JSON em objetos C#
|
|
||||||
// var jsonData = JsonConvert.DeserializeObject<Root>(responseBody);
|
|
||||||
|
|
||||||
// // Consulte os dados da tabela no banco de dados Access
|
|
||||||
// List<ClasseEmpresas> databaseData = GetDataFromDatabase(ConnSourcePath);
|
|
||||||
|
|
||||||
// // Compare os dados e encontre os registros ausentes no JSON
|
|
||||||
// List<ClasseEmpresas> recordsMissingInJson = CompareData(databaseData, jsonData);
|
|
||||||
|
|
||||||
// // Faça algo com os registros ausentes
|
|
||||||
// foreach (var record in recordsMissingInJson)
|
|
||||||
// {
|
|
||||||
// Console.WriteLine($"Registro ausente no JSON - ID: {record.Id}, Nome: {record.Nome}");
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// else
|
|
||||||
// {
|
|
||||||
// Console.WriteLine($"Erro na requisição: {response.StatusCode}");
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// static List<ClasseEmpresas> GetDataFromDatabase(string ConnSourcePath)
|
|
||||||
// {
|
|
||||||
// string connectionString = @"Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" + ConnSourcePath;
|
|
||||||
// List<ClasseEmpresas> data = new List<ClasseEmpresas>();
|
|
||||||
|
|
||||||
// using (OleDbConnection connection = new OleDbConnection(connectionString))
|
|
||||||
// {
|
|
||||||
// connection.Open();
|
|
||||||
|
|
||||||
// // Execute uma consulta SQL para recuperar dados da tabela no banco de dados Access
|
|
||||||
// string sqlQuery = "SELECT * FROM tblEmpresas";
|
|
||||||
// using (OleDbCommand command = new OleDbCommand(sqlQuery, connection))
|
|
||||||
// {
|
|
||||||
// using (OleDbDataReader reader = command.ExecuteReader())
|
|
||||||
// {
|
|
||||||
// while (reader.Read())
|
|
||||||
// {
|
|
||||||
// ClasseEmpresas record = new ClasseEmpresas
|
|
||||||
// {
|
|
||||||
// Id = (int)reader["id"],
|
|
||||||
// Nome = (string)reader["nome"],
|
|
||||||
// // Adicione outras propriedades conforme necessário
|
|
||||||
// };
|
|
||||||
// data.Add(record);
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// return data;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// static List<ClasseEmpresas> CompareData(List<ClasseEmpresas> databaseData, Root? jsonData)
|
|
||||||
// {
|
|
||||||
// if(jsonData == null) { return databaseData; }
|
|
||||||
|
|
||||||
// List<ClasseEmpresas> recordsMissingInJson = new List<ClasseEmpresas>();
|
|
||||||
|
|
||||||
// foreach (var record in databaseData)
|
|
||||||
// {
|
|
||||||
// if (!jsonData.Any(item => item.id == record.id))
|
|
||||||
// {
|
|
||||||
// recordsMissingInJson.Add(record);
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// return recordsMissingInJson;
|
|
||||||
// }
|
|
||||||
//}
|
|
||||||
|
|
||||||
//class Root
|
|
||||||
//{
|
|
||||||
// public required List<ClasseEmpresas> jsonData { get; set; }
|
|
||||||
|
|
||||||
// internal bool Any(Func<object, bool> value)
|
|
||||||
// {
|
|
||||||
// throw new NotImplementedException();
|
|
||||||
// }
|
|
||||||
//}
|
|
||||||
//class ClasseEmpresas
|
|
||||||
//{
|
|
||||||
// public int Id { get; set; }
|
|
||||||
// public required string Nome { get; set; }
|
|
||||||
|
|
||||||
// internal bool Any(Func<object, bool> value)
|
|
||||||
// {
|
|
||||||
// throw new NotImplementedException();
|
|
||||||
// }
|
|
||||||
// // Adicione outras propriedades conforme necessário
|
|
||||||
//}
|
|
||||||
7
Properties/launchSettings.json
Normal file
7
Properties/launchSettings.json
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"profiles": {
|
||||||
|
"Pipefy": {
|
||||||
|
"commandName": "Project"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
71
SOLID-Refactoring-Plan.md
Normal file
71
SOLID-Refactoring-Plan.md
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
# 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)
|
||||||
|
- Note: Current structure is well-separated; ORM will further improve OCP and testability.
|
||||||
|
- [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.
|
||||||
|
- Note: All main responsibilities are separated. Consider splitting services further if logic grows (e.g., separate API read/write, config providers).
|
||||||
|
|
||||||
|
## 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).
|
||||||
|
- Note: Future data sources or logic can be added via new classes.
|
||||||
|
|
||||||
|
## 5. Liskov Substitution Principle (LSP)
|
||||||
|
- [ ] Ensure all service implementations can be replaced by their interfaces without breaking functionality.
|
||||||
|
- Note: Add/expand unit tests to verify all service implementations can be swapped without breaking consumers. Ensure interfaces do not expose implementation-specific details.
|
||||||
|
|
||||||
|
## 6. Interface Segregation Principle (ISP)
|
||||||
|
- [ ] Keep interfaces focused and small.
|
||||||
|
- [ ] Split large interfaces if needed.
|
||||||
|
- Note: Review interfaces for granularity. Split any that grow too large or have unrelated methods.
|
||||||
|
|
||||||
|
## 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.
|
||||||
|
- Note: Prioritize unit tests for business logic and service interfaces. Use mocks/fakes to test substitutability and isolation.
|
||||||
|
|
||||||
|
## 9. Documentation
|
||||||
|
- [ ] Update this plan as you progress.
|
||||||
|
- [ ] Document new structure and usage in a `README.md` or similar file.
|
||||||
|
- Note: Document service responsibilities and interface contracts. Add XML comments to public APIs.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**Progress Tracking:**
|
||||||
|
- Mark each step as complete (`[x]`) as you finish it.
|
||||||
|
- Add notes or decisions below each step if needed.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
_Last updated: May 19, 2025_
|
||||||
50
Services/BusinessLogicService.cs
Normal file
50
Services/BusinessLogicService.cs
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
using Pipefy.Models;
|
||||||
|
|
||||||
|
namespace Pipefy.Services
|
||||||
|
{
|
||||||
|
public class BusinessLogicService : IBusinessLogicService
|
||||||
|
{
|
||||||
|
public List<ClasseEmpresas> CompareData(List<ClasseEmpresas> databaseData, List<ClasseEmpresas> jsonList, List<ClasseGestores> jsonListGestores)
|
||||||
|
{
|
||||||
|
if (jsonList == null || jsonListGestores == null)
|
||||||
|
{
|
||||||
|
return databaseData;
|
||||||
|
}
|
||||||
|
List<ClasseEmpresas> recordsMissingInJson = new List<ClasseEmpresas>();
|
||||||
|
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<ClasseGestores> jsonListGestores)
|
||||||
|
{
|
||||||
|
for (var i = 0; i < jsonListGestores.Count; i++)
|
||||||
|
{
|
||||||
|
if (sCodigo == jsonListGestores[i].gestores!.ToString())
|
||||||
|
{
|
||||||
|
return jsonListGestores[i].id!;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return "0";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
21
Services/ConfigurationService.cs
Normal file
21
Services/ConfigurationService.cs
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
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<AppSettings>()!;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
57
Services/DataMapper.cs
Normal file
57
Services/DataMapper.cs
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
using Pipefy.Models;
|
||||||
|
|
||||||
|
namespace Pipefy.Services
|
||||||
|
{
|
||||||
|
public class DataMapper : IDataMapper
|
||||||
|
{
|
||||||
|
public List<ClasseEmpresas> ConvertEmpresasJson(List<RootObject> jsonData)
|
||||||
|
{
|
||||||
|
List<ClasseEmpresas> data = new List<ClasseEmpresas>();
|
||||||
|
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<ClasseGestores> ConvertGestoresJson(List<RootGestor> jsonData)
|
||||||
|
{
|
||||||
|
List<ClasseGestores> data = new List<ClasseGestores>();
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
33
Services/DatabaseService.cs
Normal file
33
Services/DatabaseService.cs
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Data.OleDb;
|
||||||
|
using Dapper;
|
||||||
|
using Pipefy.Models;
|
||||||
|
|
||||||
|
namespace Pipefy.Services
|
||||||
|
{
|
||||||
|
public class DatabaseService : IDatabaseService
|
||||||
|
{
|
||||||
|
public List<ClasseEmpresas> GetDataFromDatabase(string connSourcePath)
|
||||||
|
{
|
||||||
|
string connectionString = @"Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" + connSourcePath + ";Jet OLEDB:Database Password=gds21;";
|
||||||
|
using (OleDbConnection connection = new OleDbConnection(connectionString))
|
||||||
|
{
|
||||||
|
connection.Open();
|
||||||
|
string sqlQuery = @"SELECT cod_smart_cliente AS c_digo_smart,
|
||||||
|
cliente AS nome_da_empresa,
|
||||||
|
modalidade,
|
||||||
|
gestao AS gestores
|
||||||
|
FROM dados_cadastrais
|
||||||
|
WHERE cod_smart_unidade LIKE '%001'
|
||||||
|
AND unidade_gerenciada;";
|
||||||
|
var data = connection.Query<ClasseEmpresas>(sqlQuery).AsList();
|
||||||
|
// rec_id is not in the DB, set to empty string
|
||||||
|
foreach (var item in data)
|
||||||
|
{
|
||||||
|
item.rec_id = string.Empty;
|
||||||
|
}
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
11
Services/IBusinessLogicService.cs
Normal file
11
Services/IBusinessLogicService.cs
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
using Pipefy.Models;
|
||||||
|
|
||||||
|
namespace Pipefy.Services
|
||||||
|
{
|
||||||
|
public interface IBusinessLogicService
|
||||||
|
{
|
||||||
|
List<ClasseEmpresas> CompareData(List<ClasseEmpresas> databaseData, List<ClasseEmpresas> jsonList, List<ClasseGestores> jsonListGestores);
|
||||||
|
string FindGestores(string sCodigo, List<ClasseGestores> jsonListGestores);
|
||||||
|
}
|
||||||
|
}
|
||||||
9
Services/IConfigurationService.cs
Normal file
9
Services/IConfigurationService.cs
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
using Pipefy.Models;
|
||||||
|
|
||||||
|
namespace Pipefy.Services
|
||||||
|
{
|
||||||
|
public interface IConfigurationService
|
||||||
|
{
|
||||||
|
AppSettings GetAppSettings();
|
||||||
|
}
|
||||||
|
}
|
||||||
11
Services/IDataMapper.cs
Normal file
11
Services/IDataMapper.cs
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
using Pipefy.Models;
|
||||||
|
|
||||||
|
namespace Pipefy.Services
|
||||||
|
{
|
||||||
|
public interface IDataMapper
|
||||||
|
{
|
||||||
|
List<ClasseEmpresas> ConvertEmpresasJson(List<RootObject> jsonData);
|
||||||
|
List<ClasseGestores> ConvertGestoresJson(List<RootGestor> jsonData);
|
||||||
|
}
|
||||||
|
}
|
||||||
10
Services/IDatabaseService.cs
Normal file
10
Services/IDatabaseService.cs
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
using Pipefy.Models;
|
||||||
|
|
||||||
|
namespace Pipefy.Services
|
||||||
|
{
|
||||||
|
public interface IDatabaseService
|
||||||
|
{
|
||||||
|
List<ClasseEmpresas> GetDataFromDatabase(string connSourcePath);
|
||||||
|
}
|
||||||
|
}
|
||||||
14
Services/IPipefyApiService.cs
Normal file
14
Services/IPipefyApiService.cs
Normal file
@ -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<JArray> GetRecordsAsync(string tableId);
|
||||||
|
Task<JArray> GetGestoresAsync(string tableId);
|
||||||
|
Task<bool> CreateRecordsAsync(string tableId, List<ClasseEmpresas> records);
|
||||||
|
}
|
||||||
|
}
|
||||||
97
Services/PipefyApiService.cs
Normal file
97
Services/PipefyApiService.cs
Normal file
@ -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<JArray> 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<bool>();
|
||||||
|
cursor = responseData["data"]!["table_records"]!["pageInfo"]!["endCursor"]!.Value<string>()!;
|
||||||
|
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<JArray> GetGestoresAsync(string tableId)
|
||||||
|
{
|
||||||
|
// For now, this is the same as GetRecordsAsync, but can be customized if needed
|
||||||
|
return await GetRecordsAsync(tableId);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<bool> CreateRecordsAsync(string tableId, List<ClasseEmpresas> 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
1
Services/README.md
Normal file
1
Services/README.md
Normal file
@ -0,0 +1 @@
|
|||||||
|
// This folder will contain service interfaces and implementations (API, DB, config, business logic)
|
||||||
9
appsettings.json
Normal file
9
appsettings.json
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
{
|
||||||
|
"AppSettings": {
|
||||||
|
"DB_PATH": "X:\\Middle\\Informativo Setorial\\Modelo Word\\BD1_dados cadastrais e faturas.accdb",
|
||||||
|
"PIPEFY_API_TOKEN": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzUxMiJ9.eyJ1c2VyIjp7ImlkIjozMDIyODQxMDMsImVtYWlsIjoiYmFjazNAZW5lcmdpYXNtYXJ0LmNvbS5iciIsImFwcGxpY2F0aW9uIjozMDAyMzY4MDh9fQ.CXRzlEROM0fTCoOobH5FyHWnt6dcu0PvASi_gjpBqWSMynV7-6FsaC98JWLFpvW0p-jDgLzno7TDLuej2OD17A",
|
||||||
|
"PIPEFY_API_URL": "https://api.pipefy.com/graphql",
|
||||||
|
"PIPEFY_TABLE_ID": "b9t-7uD5",
|
||||||
|
"PIPEFY_TABLE_ID_GESTORES": "mGCNlqoB"
|
||||||
|
}
|
||||||
|
}
|
||||||
30
data.cs
30
data.cs
@ -3,33 +3,11 @@ using System.Collections.Generic;
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
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
|
namespace Pipefy
|
||||||
{
|
{
|
||||||
public class RootObject
|
|
||||||
{
|
|
||||||
public data[] Property1 { get; set; }
|
|
||||||
}
|
|
||||||
|
|
||||||
public class data
|
|
||||||
{
|
|
||||||
public Node node { get; set; }
|
|
||||||
}
|
|
||||||
|
|
||||||
public class Node
|
|
||||||
{
|
|
||||||
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; }
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user