Files
SHERPA/SHERPA.AD/Data/MessageService.cs
2023-08-22 16:29:28 +02:00

724 lines
31 KiB
C#

using Blazored.LocalStorage;
using Blazored.SessionStorage;
using It.FattureInCloud.Sdk.Api;
using It.FattureInCloud.Sdk.Client;
using It.FattureInCloud.Sdk.Model;
using It.FattureInCloud.Sdk.OauthHelper;
using Newtonsoft.Json;
using NLog;
using SHERPA.Data.DbModels;
namespace SHERPA.AD.Data
{
public class MessageService
{
#region Public Constructors
public MessageService(ILocalStorageService genLocalStorage, ISessionStorageService sessStore)
{
localStorage = genLocalStorage;
sessionStore = sessStore;
}
#endregion Public Constructors
#region Public Events
public event Action? HeadChanged;
#endregion Public Events
#region Public Properties
/// <summary>
/// Token è verificato come presente...
/// </summary>
public bool hasToken { get; set; } = false;
#endregion Public Properties
#region Public Methods
/// <summary>
/// Crea un cliente in remoto dai datidel record sul DB
/// </summary>
/// <param name="currCust"></param>
/// <returns></returns>
public async Task<(CloudCallResult Result, ModelClient? CloudRecord)> cloudClientCreate(CustomerModel currCust)
{
CloudCallResult Result = new CloudCallResult();
ModelClient? CloudRecord = null;
string taxCode = currCust.CFisc ?? "";
string vatNum = currCust.PIva ?? "";
// test token locale
var tokenData = await getUserTokenAsync();
// se ho token provo a chiamare Fatture in Cloud...
if (tokenData != null)
{
Configuration config = new Configuration();
config.AccessToken = tokenData.AccessToken.Replace(@"\", "");
try
{
var userApiInstance = new UserApi(config);
// Retrieve User Companies
var userCompaniesResponse = userApiInstance.ListUserCompanies();
var firstCompanyId = userCompaniesResponse.Data.Companies[0].Id ?? 0;
// se ho company proseguo...
if (firstCompanyId > 0)
{
// per sicurezza cerco che NON esista già...
var clientsApiInstance = new ClientsApi(config);
CreateClientRequest addCliReq = new CreateClientRequest();
// converto formato dati cliente...
ModelClient? datiNewCliente = customerDbToCloud(currCust);
// salvo nella richiesta...
addCliReq.Data = datiNewCliente;
// effettuo la chiamata
var AddCustomerResp = await clientsApiInstance.CreateClientAsync(firstCompanyId, addCliReq);
// recupero e rendo!
CloudRecord = AddCustomerResp.Data;
// se ho fatto registro successo...
Result.success = true;
Result.message = $"Record Added! id: {CloudRecord.Id}";
}
}
catch (Exception exc)
{
Result.success = false;
Result.message = exc.Message;
Log.Error($"Eccezione in cloudClientCreate{Environment.NewLine}{exc}");
}
}
return (Result, CloudRecord);
}
/// <summary>
/// Cerca di recuperare record cliente dal record del DB utilizzando i dati fiscali (vatRate
/// / vatDesc)
/// </summary>
/// <param name="currCust"></param>
/// <returns></returns>
public async Task<(CloudCallResult Result, ModelClient? CloudRecord)> cloudClientSearch(CustomerModel currCust)
{
CloudCallResult Result = new CloudCallResult();
ModelClient? CloudRecord = null;
string taxCode = currCust.CFisc ?? "";
string vatNum = currCust.PIva ?? "";
// test token locale
var tokenData = await getUserTokenAsync();
// se ho token provo a chiamare Fatture in Cloud...
if (tokenData != null)
{
Configuration config = new Configuration();
config.AccessToken = tokenData.AccessToken.Replace(@"\", "");
try
{
var userApiInstance = new UserApi(config);
// Retrieve User Companies
var userCompaniesResponse = userApiInstance.ListUserCompanies();
var firstCompanyId = userCompaniesResponse.Data.Companies[0].Id ?? 0;
// se ho company proseguo...
if (firstCompanyId > 0)
{
var clientsApiInstance = new ClientsApi(config);
var fieldset = "detailed"; // string | Name of the fieldset. (optional)
var sort = "-id"; // string | List of comma-separated fields for result sorting (minus for desc sorting). (optional)
var page = 1; // int? | The page to retrieve. (optional) (default to 1)
var perPage = 10; // int? | The size of the page. (optional) (default to 5)
var query = $"tax_code='{taxCode}' OR vat_number='{vatNum}'";
var companyCustomers = clientsApiInstance.ListClients(firstCompanyId, null, fieldset, sort, page, perPage, query);
if (companyCustomers != null && companyCustomers.Data != null && companyCustomers.Data.Count > 0)
{
var custId = companyCustomers.Data[0].Id ?? 0;
CloudRecord = companyCustomers.Data[0];
Result.message = $"Record found! id: {CloudRecord.Id}";
}
// se ho fatto registro successo...
Result.success = true;
}
}
catch (Exception exc)
{
Result.success = false;
Result.message = exc.Message;
Log.Error($"Eccezione in cloudClientSearch{Environment.NewLine}{exc}");
}
}
return (Result, CloudRecord);
}
/// <summary>
/// Crea un documento in remoto dai dati del record sul DB
/// </summary>
/// <param name="currDoc"></param>
/// <param name="currCust"></param>
/// <param name="docRows"></param>
/// <returns></returns>
public async Task<(CloudCallResult Result, IssuedDocument? CloudRecord)> cloudDocCreate(vDocsExplModel currDoc, ModelClient currCust, List<RigheFattModel>? docRows)
{
CloudCallResult Result = new CloudCallResult();
IssuedDocument? CloudRecord = null;
string id_ext = currDoc.id_ext ?? "";
var doc_type = convTipoDoc(currDoc.tipo ?? "");
// test token locale
var tokenData = await getUserTokenAsync();
// se ho token provo a chiamare Fatture in Cloud...
if (tokenData != null)
{
Configuration config = new Configuration();
config.AccessToken = tokenData.AccessToken.Replace(@"\", "");
try
{
var userApiInstance = new UserApi(config);
// Retrieve User Companies
var userCompaniesResponse = userApiInstance.ListUserCompanies();
var firstCompanyId = userCompaniesResponse.Data.Companies[0].Id ?? 0;
// se ho company proseguo...
if (firstCompanyId > 0)
{
var issuedDocApiInstance = new IssuedDocumentsApi(config);
CreateIssuedDocumentRequest addIssuDocReq = new CreateIssuedDocumentRequest();
// converto formato dati cliente...
IssuedDocument? datiNewDoc = docDbToCloud(currDoc, currCust, docRows, false);
// salvo nella richiesta...
addIssuDocReq.Data = datiNewDoc;
// aggiunge fix pagamenti
addIssuDocReq.Options = new IssuedDocumentOptions(fixPayments: true);
// effettuo la chiamata
var AddIssuDocResp = await issuedDocApiInstance.CreateIssuedDocumentAsync(firstCompanyId, addIssuDocReq);
// recupero e rendo!
CloudRecord = AddIssuDocResp.Data;
// se ho fatto registro successo...
Result.success = true;
Result.message = $"Record Added! id: {CloudRecord.Id}";
}
}
catch (Exception exc)
{
Result.success = false;
Result.message = exc.Message;
Log.Error($"Eccezione in cloudDocCreate{Environment.NewLine}{exc}");
}
}
return (Result, CloudRecord);
}
/// <summary>
/// Cerca di recuperare record IssuedDocument dal record del DB
/// </summary>
/// <param name="localRecord"></param>
/// <returns></returns>
public async Task<(CloudCallResult Result, IssuedDocument? CloudRecord)> cloudDocSearch(vDocsExplModel localRecord)
{
CloudCallResult Result = new CloudCallResult();
IssuedDocument? CloudRecord = null;
string id_ext = localRecord.id_ext ?? "";
var doc_type = convTipoDoc(localRecord.tipo ?? "");
string codType = convToUnderscoreCase($"{doc_type}");
// test token locale
var tokenData = await getUserTokenAsync();
// se ho token provo a chiamare Fatture in Cloud...
if (tokenData != null)
{
Configuration config = new Configuration();
config.AccessToken = tokenData.AccessToken.Replace(@"\", "");
try
{
var userApiInstance = new UserApi(config);
// Retrieve User Companies
var userCompaniesResponse = userApiInstance.ListUserCompanies();
var firstCompanyId = userCompaniesResponse.Data.Companies[0].Id ?? 0;
// se ho company proseguo...
if (firstCompanyId > 0)
{
// cerco SOLOSE ho un id ext non nullo...
if (!string.IsNullOrEmpty(localRecord.id_ext))
{
var issuedDocApiInstance = new IssuedDocumentsApi(config);
var fields = "id,type,year,date,number,numeration,entity,currency,subject,visible_subject,notes,use_split_payment"; // string | List of comma-separated fields. (optional)
var fieldset = "detailed"; // string | Name of the fieldset. (optional)
var sort = "-id"; // string | List of comma-separated fields for result sorting (minus for desc sorting). (optional)
var page = 1; // int? | The page to retrieve. (optional) (default to 1)
var perPage = 10; // int? | The size of the page. (optional) (default to 5)
var query = $"id='{id_ext}' ";
//var query = $"id='{id_ext}' AND type ='{doc_type}'";
var searchDoc = issuedDocApiInstance.ListIssuedDocuments(firstCompanyId, codType, fields, fieldset, sort, page, perPage, query);
//var searchDoc = issuedDocApiInstance.ListIssuedDocuments(firstCompanyId, $"{doc_type}".ToLower(), fields, fieldset, sort, page, perPage, query);
if (searchDoc != null && searchDoc.Data != null && searchDoc.Data.Count > 0)
{
var docId = searchDoc.Data[0].Id ?? 0;
CloudRecord = searchDoc.Data[0];
Result.message = "Record found";
}
}
Result.success = true;
}
}
catch (Exception exc)
{
Result.success = false;
Result.message = exc.Message;
Log.Error($"Eccezione in cloudDocSearch{Environment.NewLine}{exc}");
}
}
return (Result, CloudRecord);
}
/// <summary>
/// Aggiorna un documento in remoto dai dati del record sul DB
/// </summary>
/// <param name="currDoc"></param>
/// <returns></returns>
public async Task<(CloudCallResult Result, IssuedDocument? CloudRecord)> cloudDocUpdate(vDocsExplModel currDoc, ModelClient currCust, List<RigheFattModel>? docRows, int currDocId)
{
CloudCallResult Result = new CloudCallResult();
IssuedDocument? CloudRecord = null;
string id_ext = currDoc.id_ext ?? "";
var doc_type = convTipoDoc(currDoc.tipo ?? "");
// test token locale
var tokenData = await getUserTokenAsync();
// se ho token provo a chiamare Fatture in Cloud...
if (tokenData != null)
{
Configuration config = new Configuration();
config.AccessToken = tokenData.AccessToken.Replace(@"\", "");
try
{
var userApiInstance = new UserApi(config);
// Retrieve User Companies
var userCompaniesResponse = userApiInstance.ListUserCompanies();
var firstCompanyId = userCompaniesResponse.Data.Companies[0].Id ?? 0;
// se ho company proseguo...
if (firstCompanyId > 0)
{
var issuedDocApiInstance = new IssuedDocumentsApi(config);
ModifyIssuedDocumentRequest modIssuDocReq = new ModifyIssuedDocumentRequest();
// converto formato dati cliente...
IssuedDocument? datiNewDoc = docDbToCloud(currDoc, currCust, docRows, true);
// salvo nella richiesta...
modIssuDocReq.Data = datiNewDoc;
// effettuo la chiamata
var ModIssuDocResp = await issuedDocApiInstance.ModifyIssuedDocumentAsync(firstCompanyId, currDocId, modIssuDocReq);
// recupero e rendo!
CloudRecord = ModIssuDocResp.Data;
// se ho fatto registro successo...
Result.success = true;
Result.message = $"Record Added! id: {CloudRecord.Id}";
}
}
catch (Exception exc)
{
Result.success = false;
Result.message = exc.Message;
Log.Error($"Eccezione in cloudDocUpdate{Environment.NewLine}{exc}");
}
}
return (Result, CloudRecord);
}
/// <summary>
/// Crea un record VAT in remoto dai dati del record sul DB
/// </summary>
/// <param name="localRecord"></param>
/// <returns></returns>
public async Task<(CloudCallResult Result, VatType? CloudRecord)> cloudVatCreate(VatModel localRecord)
{
CloudCallResult Result = new CloudCallResult();
VatType? CloudRecord = null;
// test token locale
var tokenData = await getUserTokenAsync();
// se ho token provo a chiamare Fatture in Cloud...
if (tokenData != null)
{
Configuration config = new Configuration();
config.AccessToken = tokenData.AccessToken.Replace(@"\", "");
try
{
var userApiInstance = new UserApi(config);
// Retrieve User Companies
var userCompaniesResponse = userApiInstance.ListUserCompanies();
var firstCompanyId = userCompaniesResponse.Data.Companies[0].Id ?? 0;
// se ho company proseguo...
if (firstCompanyId > 0)
{
// per sicurezza cerco che NON esista già...
var settApiInstance = new SettingsApi(config);
CreateVatTypeRequest addVatReq = new CreateVatTypeRequest();
// converto formato dati da inviare...
VatType? datiNewRecord = vatDbToCloud(localRecord);
// salvo nella richiesta...
addVatReq.Data = datiNewRecord;
// effettuo la chiamata
var AddVatResp = await settApiInstance.CreateVatTypeAsync(firstCompanyId, addVatReq);
// recupero e rendo!
CloudRecord = AddVatResp.Data;
// se ho fatto registro successo...
Result.success = true;
Result.message = $"Record Added! id: {CloudRecord.Id}";
}
}
catch (Exception exc)
{
Result.success = false;
Result.message = exc.Message;
Log.Error($"Eccezione in cloudVatCreate{Environment.NewLine}{exc}");
}
}
return (Result, CloudRecord);
}
/// <summary>
/// Cerca di recuperare record VAT dal record del DB
/// </summary>
/// <param name="localRecord"></param>
/// <returns></returns>
public async Task<(CloudCallResult Result, VatType? CloudRecord)> cloudVatSearch(VatModel localRecord)
{
CloudCallResult Result = new CloudCallResult();
VatType? CloudRecord = null;
// test token locale
var tokenData = await getUserTokenAsync();
// se ho token provo a chiamare Fatture in Cloud...
if (tokenData != null)
{
Configuration config = new Configuration();
config.AccessToken = tokenData.AccessToken.Replace(@"\", "");
try
{
var userApiInstance = new UserApi(config);
// Retrieve User Companies
var userCompaniesResponse = userApiInstance.ListUserCompanies();
var firstCompanyId = userCompaniesResponse.Data.Companies[0].Id ?? 0;
// se ho company proseguo...
if (firstCompanyId > 0)
{
var vatApiInstance = new InfoApi(config);
var companyVatRecords = vatApiInstance.ListVatTypes(firstCompanyId, null);
if (companyVatRecords != null && companyVatRecords.Data != null && companyVatRecords.Data.Count > 0)
{
decimal vatRate = (decimal)(localRecord.Iva * 100);
string vatDesc = localRecord.Descrizione ?? "";
// cerco nella risposta x descrizione e importo
CloudRecord = companyVatRecords.Data.Where(x => x.Description == vatDesc && x.Value == vatRate).FirstOrDefault();
Result.description = "Record found | S01";
// altrimenti solo descrizione
if (CloudRecord == null)
{
CloudRecord = companyVatRecords.Data.Where(x => x.Description == vatDesc).OrderBy(x => x.Id).FirstOrDefault();
Result.description = "Record found | S02";
}
// se ho trovato registro successo...
Result.success = true;
Result.message = "Record found";
}
}
}
catch (Exception exc)
{
Result.success = false;
Result.message = exc.Message;
Log.Error($"Eccezione in cloudVatSearch{Environment.NewLine}{exc}");
}
}
return (Result, CloudRecord);
}
/// <summary>
/// Restituisce il valore del token F.I.C. da localstorage
/// </summary>
/// <returns></returns>
public async Task<OAuth2AuthorizationCodeTokenResponse?> getUserTokenAsync()
{
OAuth2AuthorizationCodeTokenResponse? answ = null;
var result = await localStorage.GetItemAsync<string>(KeyTokenFIC);
if (result != null)
{
answ = JsonConvert.DeserializeObject<OAuth2AuthorizationCodeTokenResponse>(result);
}
return answ;
}
public void NotifyHeadChanged() => HeadChanged?.Invoke();
/// <summary>
/// Scrive il valore del token F.I.C. nel localstoragee
/// </summary>
/// <param name="newToken"></param>
/// <returns></returns>
public async Task<bool> setUserTokenAsync(OAuth2AuthorizationCodeTokenResponse? newToken)
{
bool answ = false;
// se nullo --> svuoto...
if (newToken == null)
{
await localStorage.RemoveItemAsync(KeyTokenFIC);
}
else
{
try
{
string rawData = newToken != null ? JsonConvert.SerializeObject(newToken) : "";
await localStorage.SetItemAsync(KeyTokenFIC, rawData);
answ = true;
}
catch (Exception ex)
{
Log.Error($"Eccezione in setUserTokenAsync{Environment.NewLine}{ex}");
}
}
return answ;
}
#endregion Public Methods
#region Protected Fields
protected const string KeyTokenFIC = "TokenFIC";
#endregion Protected Fields
#region Protected Properties
protected ILocalStorageService localStorage { get; set; } = null!;
protected ISessionStorageService sessionStore { get; set; } = null!;
#endregion Protected Properties
#region Protected Methods
protected string convToUnderscoreCase(string origName)
{
string result = string.Concat(origName.Select((x, i) => i > 0 && char.IsUpper(x) ? "_" + x.ToString() : x.ToString()));
return result.ToLower();
}
#endregion Protected Methods
#region Private Fields
private Logger Log = LogManager.GetCurrentClassLogger();
#endregion Private Fields
#region Private Methods
private IssuedDocumentType convTipoDoc(string tipoDoc)
{
IssuedDocumentType tipo = IssuedDocumentType.Proforma;
switch (tipoDoc.ToUpper())
{
case "FATTURE":
case "FATTURA":
tipo = IssuedDocumentType.Invoice;
break;
case "PREVENTIVO":
tipo = IssuedDocumentType.Quote;
break;
case "PROFORMA":
case "PRO-FORMA":
tipo = IssuedDocumentType.Proforma;
break;
case "RICEVUTA":
tipo = IssuedDocumentType.Receipt;
break;
case "DDT":
case "BOLLA":
case "BOLLA DI CONSEGNA":
case "DDT/BOLLA DI CONSEGNA":
tipo = IssuedDocumentType.DeliveryNote;
break;
case "NOTA DI CREDITO":
tipo = IssuedDocumentType.CreditNote;
break;
case "ORDINE":
tipo = IssuedDocumentType.Order;
break;
case "REPORT":
case "WORK_REPORT":
tipo = IssuedDocumentType.WorkReport;
break;
case "ORDINEFORNITORE":
case "ORDINE FORNITORE":
case "ORDINE_FORNITORE":
tipo = IssuedDocumentType.SupplierOrder;
break;
case "AUTOFATTURA":
case "SELF_OWN_INVOICE":
tipo = IssuedDocumentType.SelfOwnInvoice;
break;
case "AUTOFATTURA-FORNITORE":
case "SELF_SUPPLIER_INVOICE":
tipo = IssuedDocumentType.SelfSupplierInvoice;
break;
default:
tipo = IssuedDocumentType.Proforma;
break;
}
return tipo;
}
/// <summary>
/// Converte dati da DB model Customer EGW a modello Fatture In CLoud
/// </summary>
/// <param name="curRec"></param>
/// <returns></returns>
private ModelClient customerDbToCloud(CustomerModel curRec)
{
ModelClient result = new ModelClient()
{
Code = curRec.CodiceCliente,
TaxCode = curRec.CFisc,
VatNumber = curRec.CFisc,
Name = curRec.RagSoc,
AddressStreet = curRec.Via,
AddressPostalCode = curRec.Cap,
AddressCity = curRec.Localita,
AddressProvince = curRec.Provincia,
CertifiedEmail = curRec.Pec,
EiCode = curRec.CodUnivoco,
EInvoice = !string.IsNullOrEmpty(curRec.CodUnivoco)
};
return result;
}
/// <summary>
/// Converte dati da DB model Fatture EGW a modello Fatture In Cloud
/// </summary>
/// <param name="currDoc"></param>
/// <param name="currCust"></param>
/// <param name="DocRows"></param>
/// <param name="isUpdate"></param>
/// <returns></returns>
private IssuedDocument docDbToCloud(vDocsExplModel currDoc, ModelClient currCust, List<RigheFattModel>? DocRows, bool isUpdate)
{
// converto customer a entity
Entity newEntity = new Entity()
{
Id = currCust.Id,
Name = currCust.Name,
VatNumber = currCust.VatNumber,
TaxCode = currCust.TaxCode,
AddressStreet = currCust.AddressStreet,
AddressPostalCode = currCust.AddressPostalCode,
AddressCity = currCust.AddressCity,
AddressProvince = currCust.AddressProvince,
AddressExtra = currCust.AddressExtra,
CertifiedEmail = currCust.CertifiedEmail,
EiCode = currCust.EiCode,
Code = currCust.Code,
Notes = currCust.Notes,
};
List<IssuedDocumentItemsListItem> elItems = new List<IssuedDocumentItemsListItem>();
// recupero lista articoli...
if (DocRows != null && DocRows.Count > 0)
{
elItems = DocRows.OrderBy(x => x.numRiga).Select(x => new IssuedDocumentItemsListItem()
{
Measure = x.Um,
Qty = (decimal)x.Qta,
//Name = x.Descrizione,
Description = x.Descrizione,
NetPrice = x.Netto / (decimal)x.Qta,
GrossPrice = x.Importo / (decimal)x.Qta,
Vat = new VatType(x.IdxVatExt), // 0 = 22% standard, vedere note in DataStruct
//Vat = new VatType(x.CIva ?? 1, (x.VatNav != null ? (decimal)(x.VatNav.Iva ?? 0) * 100 : 22), (x.VatNav != null ? x.VatNav.Descrizione : "22%")), // 0 = 22% standard, vedere note in DataStruct
NotTaxable = false,
ApplyWithholdingTaxes = false,
Discount = (decimal)x.Sconto * 100, // sconto è in percentuale CON virgola
DiscountHighlight = true,
Stock = true
}).ToList();
}
// indico una modalità standar pagamento
IssuedDocumentPaymentsListItem pagam = new IssuedDocumentPaymentsListItem();
List<IssuedDocumentPaymentsListItem> listaPag = new List<IssuedDocumentPaymentsListItem>();
if (!isUpdate)
{
pagam = new IssuedDocumentPaymentsListItem()
{
DueDate = currDoc.emesso.AddMonths(1),
//Amount = currDoc.netto,
Amount = currDoc.importo,
Status = IssuedDocumentStatus.NotPaid
};
listaPag.Add(pagam);
}
else
{
// registro SOLO SE ho pagamenti e scadenze a zero...
if (currDoc.totPagato > 0 && currDoc.totScadenze == 0)
{
pagam = new IssuedDocumentPaymentsListItem()
{
PaidDate = currDoc.DataPagam,
Amount = currDoc.totScadenze,
Status = IssuedDocumentStatus.Paid
};
listaPag.Add(pagam);
}
}
//listaPag.Add(pagam);
IssuedDocument result = new IssuedDocument()
{
Entity = newEntity,
Type = convTipoDoc(currDoc.tipo),
Number = currDoc.num,
Date = currDoc.emesso,
Year = currDoc.anno,
UseGrossPrices = false,
Subject = currDoc.Descrizione,
VisibleSubject = currDoc.tipo.ToUpper(),
ShowPaymentMethod = true,
UseSplitPayment = false,
DeliveryNote = convTipoDoc(currDoc.tipo) == IssuedDocumentType.DeliveryNote
};
// verifico SE devo aggiungere pagamenti e fatture secondo stato modifica...
if (isUpdate || (currDoc.Changed & 2) != 0)
{
result.ItemsList = elItems;
}
if (!isUpdate || (currDoc.Changed & 4) != 0)
{
result.PaymentsList = listaPag;
}
return result;
}
/// <summary>
/// Converte dati da DB model VAT EGW a modello Fatture In CLoud
/// </summary>
/// <param name="curRec"></param>
/// <returns></returns>
private VatType vatDbToCloud(VatModel curRec)
{
VatType result = new VatType()
{
Value = (decimal)curRec.Iva * 100,
Description = curRec.Descrizione,
Notes = curRec.Descrizione,
IsDisabled = !curRec.Enabled,
EInvoice = true,
EiType = curRec.Iva > 0 ? "2" : "2.2",
EiDescription = curRec.Descrizione
};
return result;
}
#endregion Private Methods
}
}