private async Task fireAndForgetAsync(PayrollStampingParams payrollStampingParams,
                                              Overdraft overdraftToStamp,
                                              List <PayrollCompanyConfiguration> payrollConfigurations,
                                              BlobStorageUtil blobStorageUtil,
                                              ISendMailProvider sendMailProvider,
                                              Guid UUID, string XML)
        {
            try
            {
                //7. Save XML to BlobStorage
                await blobStorageUtil.UploadDocumentAsync($"{UUID}.xml", XML);

                ////8. Transforma el XML a HTML y PDF
                var resultTransformation = await xmlTransformationAsync(payrollStampingParams, overdraftToStamp,
                                                                        XML);

                ////Save PDF to BlobStorage
                await blobStorageUtil.UploadDocumentAsync($"{UUID}.pdf",
                                                          resultTransformation.PreviewTransformResultDetails.FirstOrDefault().TransformPDFResult);

                ////9. Send email with the payroll to Employee
                await sendMailAsync(overdraftToStamp, UUID, XML,
                                    resultTransformation.PreviewTransformResultDetails.FirstOrDefault().TransformPDFResult, sendMailProvider,
                                    payrollConfigurations);
            }
            catch (Exception ex)
            {
                Trace.TraceError($"No fue posible transformar / enviar el comprobante al colaborador. {ex.Message}");
            }
        }
示例#2
0
        public async Task <JsonResult> Stamping(List <Guid> overdrafstList, Guid periodDetailID)
        {
            try
            {
                Trace.WriteLine("Llega al controller");
                if (!overdrafstList.Any())
                {
                    throw new CotorraException(102, "102", "No existe ninguna nómina a timbrar.", null);
                }

                var detailsList = new List <PayrollStampingDetail>();
                for (int i = 0; i < overdrafstList.Count(); i++)
                {
                    var odID = overdrafstList[i];
                    detailsList.Add(new PayrollStampingDetail()
                    {
                        Folio             = String.Empty,
                        Series            = String.Empty,
                        PaymentDate       = DateTime.Now,
                        RFCOriginEmployer = String.Empty,
                        OverdraftID       = odID,
                    });
                }

                var stampingParams = new PayrollStampingParams
                {
                    Detail   = detailsList,
                    Currency = Currency.MXN,
                    FiscalStampingVersion = FiscalStampingVersion.CFDI33_Nom12,
                    PeriodDetailID        = periodDetailID,
                    IdentityWorkID        = SessionModel.CompanyID,
                    InstanceID            = SessionModel.InstanceID,
                };
                Trace.WriteLine("Invoka al cliente");
                var stampProcess = await stampingClient.PayrollStampingAsync(stampingParams);

                var result = from psr in stampProcess.PayrollStampingResultDetails
                             select new
                {
                    psr.HistoricEmployeeID,
                    psr.OverdraftID,
                    psr.PeriodDetailID,
                    psr.UUID,
                    psr.PayrollStampingResultStatus,
                    psr.Message
                };

                return(Json(result));
            }
            catch (Exception ex)
            {
                Trace.WriteLine(ex.ToString());
                throw;
            }
        }
        private (byte[], byte[], string) Crypto(PayrollStampingParams payrollStampingParams, string certificateCER,
                                                string certificateKey, string certPassword)
        {
            var clsCryptoToCreate = new ClsCrypto(
                payrollStampingParams.IdentityWorkID.ToString().ToLower().Replace("-", ""),
                payrollStampingParams.InstanceID.ToString().ToLower().Replace("-", ""),
                payrollStampingParams.InstanceID.ToString().ToLower().Replace("-", "").Substring(0, 19));
            var certificatebytesCER  = Convert.FromBase64String(clsCryptoToCreate.Decrypt(certificateCER));
            var certificatebytesKEY  = Convert.FromBase64String(clsCryptoToCreate.Decrypt(certificateKey));
            var certPasswordToResult = StringCipher.Decrypt(certPassword);

            return(certificatebytesCER, certificatebytesKEY, certPasswordToResult);
        }
        private async Task <PreviewTransformResult> xmlTransformationAsync(PayrollStampingParams payrollStampingParams, Overdraft overdraftToStamp, string XML)
        {
            var fiscalPreviewManager   = new FiscalPreviewerManager();
            var previewTransformParams = new PreviewTransformParams();

            previewTransformParams.FiscalStampingVersion = payrollStampingParams.FiscalStampingVersion;
            previewTransformParams.InstanceID            = payrollStampingParams.InstanceID;
            previewTransformParams.IdentityWorkID        = payrollStampingParams.IdentityWorkID;

            previewTransformParams.PreviewTransformParamsDetails.Add(new PreviewTransformParamsDetail()
            {
                OverdraftID = overdraftToStamp.ID,
                Overdraft   = overdraftToStamp,
                XML         = XML
            });

            var resultTransformation = await fiscalPreviewManager.TransformAsync(previewTransformParams);

            return(resultTransformation);
        }
        public async Task <PayrollStampingResult> PayrollStampingAsync(PayrollStampingParams payrollStampingParams)
        {
            var manager = new PayrollStampingManager();

            return(await manager.PayrollStampingAsync(payrollStampingParams));
        }
示例#6
0
        public async Task Should_Stamp_Payroll_CFDI_Valid()
        {
            var xmlCancelacion = "<?xml version=\"1.0\" encoding=\"utf-8\"?><Acuse xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" Fecha=\"2020-07-02T16:02:07.2838838\" RfcEmisor=\"KAHO641101B39\">  <Folios xmlns=\"http://cancelacfd.sat.gob.mx\">    <UUID>3377E0AA-C54B-4E9E-BFF2-1D8BA96D5DD4</UUID>    <EstatusUUID>201</EstatusUUID>  </Folios>  <Signature Id=\"SelloSAT\" xmlns=\"http://www.w3.org/2000/09/xmldsig#\">    <SignedInfo>      <CanonicalizationMethod Algorithm=\"http://www.w3.org/TR/2001/REC-xml-c14n-20010315\" />      <SignatureMethod Algorithm=\"http://www.w3.org/2001/04/xmldsig-more#hmac-sha512\" />      <Reference URI=\"\">        <Transforms>          <Transform Algorithm=\"http://www.w3.org/TR/1999/REC-xpath-19991116\">            <XPath>not(ancestor-or-self::*[local-name()='Signature'])</XPath>          </Transform>        </Transforms>        <DigestMethod Algorithm=\"http://www.w3.org/2001/04/xmlenc#sha512\" />        <DigestValue>BThmOyTf26Ax25v8Li0oqcP3wyrhW3kjjxOcO1zamRYasNIPcHSnBiRyxmJ449a3gdgAWaz/UKVil3pqcper+g==</DigestValue>      </Reference>    </SignedInfo>    <SignatureValue>6qDGoWoHW5tK2MGNiXU7fI6hfpkbrYTMHafVvIsGRkl9xq2H2YQRvId4CO7B9GGJFbuVMku2IBkpKU/Tscqo9Q==</SignatureValue>    <KeyInfo>      <KeyName>BF66E582888CC845</KeyName>      <KeyValue>        <RSAKeyValue>          <Modulus>n5YsGT0w5Z70ONPbqszhExfJU+KY3Bscftc2jxUn4wxpSjEUhnCuTd88OK5QbDW3Mupoc61jr83lRhUCjchFAmCigpC10rEntTfEU+7qtX8ud/jJJDB1a9lTIB6bhBN//X8IQDjhmHrfKvfen3p7RxLrFoxzWgpwKriuGI5wUlU=</Modulus>          <Exponent>AQAB</Exponent>        </RSAKeyValue>      </KeyValue>    </KeyInfo>  </Signature></Acuse>";
            var acuse          = SerializerXml.DeserializeObject <Schema.CFDI33Nom12.Acuse>(xmlCancelacion);

            using var scope = new TransactionScope(TransactionScopeAsyncFlowOption.Enabled);

            try
            {
                var identityWorkId = Guid.NewGuid();
                var instanceID     = Guid.NewGuid();

                var overdraft      = await new PayrollStampingManagerUT().CreateRealOverdraftAsync(identityWorkId, instanceID);
                var periodDetailID = overdraft.PeriodDetailID;

                //Recalculate
                var calculateParams = new CalculateOverdraftParams()
                {
                    DeleteAccumulates = true,
                    IdentityWorkID    = identityWorkId,
                    InstanceID        = instanceID,
                    OverdraftID       = overdraft.ID,
                    ResetCalculation  = true,
                    SaveOverdraft     = true,
                    UserID            = Guid.Empty
                };

                var calculationResult = await new OverdraftCalculationManager().CalculateAsync(calculateParams);
                overdraft = (calculationResult as CalculateOverdraftResult).OverdraftResult;
                Assert.True(overdraft.OverdraftDetails.Sum(p => p.Amount) > 0);

                //Autorización de la nómina
                var authorizationManager = new AuthorizationManager();
                var authorizationParams  = new AuthorizationParams()
                {
                    IdentityWorkID            = identityWorkId,
                    InstanceID                = instanceID,
                    PeriodDetailIDToAuthorize = periodDetailID,
                    ResourceID                = Guid.Empty,
                    user = Guid.Empty
                };

                //autorizacion de la nómina
                var historicOverdrafts = await authorizationManager.AuthorizationAsync(authorizationParams);

                //Timbrado

                var overdraftManager   = new MiddlewareManager <Overdraft>(new BaseRecordManager <Overdraft>(), new OverdraftValidator());
                var overdraftsPrevious = await overdraftManager.FindByExpressionAsync(p => p.PeriodDetailID == periodDetailID, identityWorkId);

                var manager       = new PayrollStampingManager();
                var dateTime      = DateTime.Now;
                var stampingParms = new PayrollStampingParams()
                {
                    FiscalStampingVersion = FiscalStampingVersion.CFDI33_Nom12,
                    IdentityWorkID        = identityWorkId,
                    InstanceID            = instanceID,
                    PeriodDetailID        = periodDetailID,
                    Detail = new List <PayrollStampingDetail>()
                    {
                        new PayrollStampingDetail()
                        {
                            Folio             = "2020",
                            Series            = "S1",
                            PaymentDate       = dateTime.AddDays(-2),
                            RFCOriginEmployer = null,
                            SNCFEntity        = null,
                            OverdraftID       = overdraftsPrevious.FirstOrDefault().ID,
                        }
                    },

                    Currency = Currency.MXN
                };

                var payrollStampingResult = await manager.PayrollStampingAsync(stampingParms);

                Assert.Contains(payrollStampingResult.PayrollStampingResultDetails, p => p.PayrollStampingResultStatus == PayrollStampingResultStatus.Success);

                //cancel payroll
                var cancelStampingManager = new CancelStampingManager();
                var cancelParams          = new CancelPayrollStampingParams()
                {
                    FiscalStampingVersion = FiscalStampingVersion.CFDI33_Nom12,
                    IdentityWorkID        = identityWorkId,
                    InstanceID            = instanceID,
                    OverdraftIDs          = overdraftsPrevious.Select(p => p.ID).ToList(),
                    user = Guid.Empty
                };

                await Task.Delay(10000);

                var cancelationResult = await cancelStampingManager.CancelPayrollStampingAsync(cancelParams);

                Assert.False(cancelationResult.WithErrors);

                var cancelManager = new MiddlewareManager <CancelationFiscalDocument>(new BaseRecordManager <CancelationFiscalDocument>(),
                                                                                      new CancelationFiscalDocumentValidator());
                var cancelations = await cancelManager.FindByExpressionAsync(p => p.InstanceID == instanceID, identityWorkId,
                                                                             new string[] { "CancelationFiscalDocumentDetails" });

                Assert.True(cancelations.Any());

                var overIds         = overdraftsPrevious.Select(p => p.ID).ToList();
                var olderOverdrafts = await overdraftManager.FindByExpressionAsync(p => overIds.Contains(p.ID), identityWorkId);

                Assert.False(olderOverdrafts.Any(p => p.OverdraftStatus != OverdraftStatus.Canceled));

                var newOverdrafts = await overdraftManager.FindByExpressionAsync(p => overIds.Contains(p.OverdraftPreviousCancelRelationshipID.Value), identityWorkId);

                Assert.False(newOverdrafts.Any(p => p.OverdraftPreviousCancelRelationshipID == null));
            }
            catch (Exception ex)
            {
                var t = ex.ToString();
                Assert.True(false, ex.ToString());
            }
        }
示例#7
0
 public async Task <PayrollStampingResult> PayrollStampingAsync(PayrollStampingParams payrollStampingParams)
 {
     return(await _client.PayrollStampingAsync(payrollStampingParams));
 }
 public async Task <PayrollStampingResult> PayrollStampingAsync(PayrollStampingParams payrollStampingParams)
 {
     throw new NotImplementedException();
 }
示例#9
0
        public async Task Should_Stamp_Payroll_CFDI_Valid()
        {
            using var scope = new TransactionScope(TransactionScopeAsyncFlowOption.Enabled);

            try
            {
                var identityWorkId = Guid.NewGuid();
                var instanceID     = Guid.NewGuid();

                var overdraft = await CreateRealOverdraftAsync(identityWorkId, instanceID);

                var periodDetailID = overdraft.PeriodDetailID;

                //Recalculate
                var calculateParams = new CalculateOverdraftParams()
                {
                    DeleteAccumulates = true,
                    IdentityWorkID    = identityWorkId,
                    InstanceID        = instanceID,
                    OverdraftID       = overdraft.ID,
                    ResetCalculation  = true,
                    SaveOverdraft     = true,
                    UserID            = Guid.Empty
                };

                var calculationResult = await new OverdraftCalculationManager().CalculateAsync(calculateParams);
                overdraft = (calculationResult as CalculateOverdraftResult).OverdraftResult;
                Assert.True(overdraft.OverdraftDetails.Sum(p => p.Amount) > 0);

                //Autorización de la nómina
                var authorizationManager = new AuthorizationManager();
                var authorizationParams  = new AuthorizationParams()
                {
                    IdentityWorkID            = identityWorkId,
                    InstanceID                = instanceID,
                    PeriodDetailIDToAuthorize = periodDetailID,
                    ResourceID                = Guid.Empty,
                    user = Guid.Empty
                };

                //autorizacion de la nómina
                var historicOverdrafts = await authorizationManager.AuthorizationAsync(authorizationParams);

                //Timbrado

                var overdraftManager   = new MiddlewareManager <Overdraft>(new BaseRecordManager <Overdraft>(), new OverdraftValidator());
                var overdraftsPrevious = await overdraftManager.FindByExpressionAsync(p => p.PeriodDetailID == periodDetailID, identityWorkId);

                var manager       = new PayrollStampingManager();
                var dateTime      = DateTime.Now;
                var stampingParms = new PayrollStampingParams()
                {
                    FiscalStampingVersion = FiscalStampingVersion.CFDI33_Nom12,
                    IdentityWorkID        = identityWorkId,
                    InstanceID            = instanceID,
                    PeriodDetailID        = periodDetailID,
                    Detail = new List <PayrollStampingDetail>()
                    {
                        new PayrollStampingDetail()
                        {
                            Folio             = "2020",
                            Series            = "S1",
                            PaymentDate       = dateTime.AddDays(-2),
                            RFCOriginEmployer = null,
                            SNCFEntity        = null,
                            OverdraftID       = overdraftsPrevious.FirstOrDefault().ID,
                        }
                    },

                    Currency = Currency.MXN
                };

                var payrollStampingResult = await manager.PayrollStampingAsync(stampingParms);

                Assert.Contains(payrollStampingResult.PayrollStampingResultDetails, p => p.PayrollStampingResultStatus == PayrollStampingResultStatus.Success);

                var uuid          = payrollStampingResult.PayrollStampingResultDetails.FirstOrDefault().Overdraft.UUID;
                var fiscalManager = FiscalPreviewFactory.CreateInstance(FiscalStampingVersion.CFDI33_Nom12);
                var resultUrls    = await fiscalManager.GetPreviewUrlByUUIDAsync(instanceID, uuid);

                HttpClient client   = new HttpClient();
                var        pdfBytes = await client.GetByteArrayAsync(resultUrls.PDFUri);

                //Save XML to FileSystem
                var xmlFilePath = Path.Combine(DirectoryUtil.AssemblyDirectory, "example.xml");
                await File.WriteAllTextAsync(xmlFilePath, payrollStampingResult.PayrollStampingResultDetails.FirstOrDefault().XML);

                Assert.True(File.Exists(xmlFilePath));

                //Save PDF to FileSystem
                var outPDFFilePath = Path.Combine(DirectoryUtil.AssemblyDirectory, "example.pdf");
                await File.WriteAllBytesAsync(outPDFFilePath, pdfBytes);

                Assert.True(File.Exists(outPDFFilePath));
            }
            catch (Exception ex)
            {
                var t = ex.ToString();
                Assert.True(false, ex.ToString());
            }
        }
        private async Task saveOverdraftStampedAsync(PayrollStampingParams payrollStampingParams,
                                                     PayrollStampingResult payrollStampingResult)
        {
            var details = payrollStampingResult.PayrollStampingResultDetails
                          .Where(p => p.PayrollStampingResultStatus == PayrollStampingResultStatus.Success);

            using (var connection = new SqlConnection(ConnectionManager.ConfigConnectionString))
            {
                if (connection.State != ConnectionState.Open)
                {
                    await connection.OpenAsync();
                }

                using (var command = connection.CreateCommand())
                {
                    command.CommandType = CommandType.StoredProcedure;
                    command.CommandText = STORED_PROCEDURE_SAVEOVERDRAFT;

                    //PeriodDetails Parameter
                    var periodDetailIds = details
                                          .Select(p => p.PeriodDetailID).ToList();
                    if (periodDetailIds.Any())
                    {
                        DataTable dtGuidList = new DataTable();
                        dtGuidList.Columns.Add("ID", typeof(string));
                        periodDetailIds.ForEach(p =>
                        {
                            dtGuidList.Rows.Add(p);
                        });
                        SqlParameter param = new SqlParameter("@PeriodDetailIds", SqlDbType.Structured)
                        {
                            TypeName = "dbo.guidlisttabletype",
                            Value    = dtGuidList
                        };
                        command.Parameters.Add(param);

                        //OverdraftIds Parameter
                        var overdraftIds = details
                                           .Select(p => new { p.OverdraftID, p.UUID }).ToList();
                        DataTable dtOverdraftGuidList = new DataTable();
                        dtOverdraftGuidList.Columns.Add("ID", typeof(string));
                        dtOverdraftGuidList.Columns.Add("UUID", typeof(string));
                        overdraftIds.ForEach(p =>
                        {
                            dtOverdraftGuidList.Rows.Add(p.OverdraftID, p.UUID);
                        });
                        SqlParameter paramOverdraftIdsTable = new SqlParameter("@OverdraftIds", SqlDbType.Structured)
                        {
                            TypeName = "dbo.stampoverdrafttabletype",
                            Value    = dtOverdraftGuidList
                        };
                        command.Parameters.Add(paramOverdraftIdsTable);

                        command.Parameters.AddWithValue("@InstanceId", payrollStampingParams.InstanceID);
                        command.Parameters.AddWithValue("@company", payrollStampingParams.IdentityWorkID);
                        command.Parameters.AddWithValue("@user", payrollStampingParams.user);

                        //Execute SP de autorización
                        await command.ExecuteNonQueryAsync();
                    }
                }
            }
        }
        public async Task <PayrollStampingResult> PayrollStampingAsync(PayrollStampingParams payrollStampingParams)
        {
            Trace.WriteLine("Llega al PayrollStampingAsync");
            //Obtiene todos los historic overdrafts del periodo seleccionado
            var historicOverdraftManager = new MiddlewareManager <Overdraft>(new BaseRecordManager <Overdraft>(),
                                                                             new OverdraftValidator());
            var incidentsManager = new MiddlewareManager <Incident>(new BaseRecordManager <Incident>(),
                                                                    new IncidentValidator());
            var inhabilitiesManager = new MiddlewareManager <Inhability>(
                new BaseRecordManager <Inhability>(),
                new InhabilityValidator());
            List <Overdraft>  historicOverdraftsToStamp = null;
            List <Incident>   incidents    = null;
            List <Inhability> inhabilities = null;
            List <EmployerFiscalInformation>   employerFiscalInformations = null;
            List <PayrollCompanyConfiguration> payrollConfigurations      = null;

            if (payrollStampingParams.Detail.Any())
            {
                var overdraftsIds = payrollStampingParams.Detail.Select(p => p.OverdraftID);
                historicOverdraftsToStamp = await historicOverdraftManager.FindByExpressionAsync(p =>
                                                                                                 p.company == payrollStampingParams.IdentityWorkID &&
                                                                                                 p.InstanceID == payrollStampingParams.InstanceID &&
                                                                                                 p.PeriodDetailID == payrollStampingParams.PeriodDetailID &&
                                                                                                 overdraftsIds.Contains(p.ID) &&
                                                                                                 p.OverdraftStatus == OverdraftStatus.Authorized &&
                                                                                                 p.Active,
                                                                                                 payrollStampingParams.IdentityWorkID, new string[] {
                    "OverdraftPreviousCancelRelationship",
                    "OverdraftDetails",
                    "OverdraftDetails.ConceptPayment",
                    "PeriodDetail",
                    "PeriodDetail.Period",
                    "HistoricEmployee",
                    "HistoricEmployee.Employee",
                    "HistoricEmployee.Employee.Workshift",
                    "HistoricEmployee.Employee.EmployerRegistration"
                });

                incidents = await incidentsManager.FindByExpressionAsync(p => p.PeriodDetailID == payrollStampingParams.PeriodDetailID &&
                                                                         p.InstanceID == payrollStampingParams.InstanceID,
                                                                         payrollStampingParams.IdentityWorkID,
                                                                         new string[] { "IncidentType" });

                var initialDate = historicOverdraftsToStamp.FirstOrDefault().PeriodDetail.InitialDate;
                var finalDate   = historicOverdraftsToStamp.FirstOrDefault().PeriodDetail.FinalDate;

                //Incapacidades dentro del periodo
                inhabilities = await inhabilitiesManager.FindByExpressionAsync(p =>
                                                                               p.InstanceID == payrollStampingParams.InstanceID &&
                                                                               (
                                                                                   (p.InitialDate >= initialDate && p.InitialDate.AddDays(p.AuthorizedDays - 1) <= finalDate) ||
                                                                                   (p.InitialDate >= initialDate && p.InitialDate.AddDays(p.AuthorizedDays - 1) > finalDate) ||
                                                                                   (p.InitialDate < initialDate && p.InitialDate.AddDays(p.AuthorizedDays - 1) <= finalDate) ||
                                                                                   (p.InitialDate <initialDate && p.InitialDate.AddDays(p.AuthorizedDays - 1)> finalDate)
                                                                               ),
                                                                               payrollStampingParams.IdentityWorkID);

                //Obtiene la información fiscal del patrón, certificados
                var employerFiscalInformationManager = new MiddlewareManager <EmployerFiscalInformation>(new BaseRecordManager <EmployerFiscalInformation>(),
                                                                                                         new EmployerFiscalInformationValidator());
                employerFiscalInformations = await employerFiscalInformationManager.FindByExpressionAsync(p =>
                                                                                                          p.company == payrollStampingParams.IdentityWorkID &&
                                                                                                          p.InstanceID == payrollStampingParams.InstanceID,
                                                                                                          payrollStampingParams.IdentityWorkID);

                if (!employerFiscalInformations.Any())
                {
                    throw new CotorraException(105, "105", "No se han configurado los certificados (CSD) de la empresa para poder timbrar. Ve al menú Catálogos -> Certificados -> Agregar nuevo", null);
                }

                //Obtiene la configuración general de la empresa
                var payrollCompanyConfigurationManager = new MiddlewareManager <PayrollCompanyConfiguration>(new BaseRecordManager <PayrollCompanyConfiguration>(),
                                                                                                             new PayrollCompanyConfigurationValidator());
                payrollConfigurations = await payrollCompanyConfigurationManager.FindByExpressionAsync(p => p.company == payrollStampingParams.IdentityWorkID &&
                                                                                                       p.InstanceID == payrollStampingParams.InstanceID, payrollStampingParams.IdentityWorkID,
                                                                                                       new string[] { "Address" });
            }
            else
            {
                throw new CotorraException(101, "101", "No se proporcionó los detalles correspondientes para timbrar.", null);
            }

            if (!historicOverdraftsToStamp.Any())
            {
                throw new CotorraException(101, "101", "No hay ningún sobrerecibo a timbrar en estatus autorizado, con los parámetros proporcionados.", null);
            }

            return(await payrollStampingCoreAsync(payrollStampingParams,
                                                  historicOverdraftsToStamp, incidents, inhabilities, employerFiscalInformations,
                                                  payrollConfigurations));
        }
        private async Task <PayrollStampingResult> payrollStampingCoreAsync(PayrollStampingParams payrollStampingParams,
                                                                            List <Overdraft> historicOverdraftsToStamp,
                                                                            List <Incident> incidents,
                                                                            List <Inhability> inhabilities,
                                                                            List <EmployerFiscalInformation> employerFiscalInformations,
                                                                            List <PayrollCompanyConfiguration> payrollConfigurations)
        {
            var payrollStampingResult = new PayrollStampingResult();

            List <string> zipCodesToFind =
                historicOverdraftsToStamp.Select(p => p.HistoricEmployee.EmployerRegistrationZipCode).ToList();

            zipCodesToFind.AddRange(payrollConfigurations.Select(p => p.Address?.ZipCode));

            //Obtener los zipCodes
            var zipCodeMiddlewareManager = new MiddlewareManager <catCFDI_CodigoPostal>(
                new BaseRecordManager <catCFDI_CodigoPostal>(),
                new catCFDI_CodigoPostalValidator());
            var zipCodes = await zipCodeMiddlewareManager.FindByExpressionAsync(p =>
                                                                                zipCodesToFind.Contains(p.c_CodigoPostal)
                                                                                , payrollStampingParams.IdentityWorkID);

            //Round for currency
            var roundUtil = new RoundUtil(payrollStampingParams.Currency.ToString());

            //Zip Code manager
            var zipCodeManager = new ZipCodeManager(zipCodes);

            //Blob Storage Util
            var blobStorageUtil = new BlobStorageUtil(payrollStampingParams.InstanceID);
            await blobStorageUtil.InitializeAsync();

            ISendMailProvider sendMailProvider = FactoryMailProvider.CreateInstance(SendMailProvider.SendGrid);

            var tasks = new List <Task <List <PayrollStampingResultDetail> > >();

            foreach (var overdraftToStamp in historicOverdraftsToStamp)
            {
                tasks.Add(doWorkAsync(overdraftToStamp, roundUtil, zipCodeManager,
                                      payrollStampingParams, blobStorageUtil, sendMailProvider, incidents,
                                      inhabilities, employerFiscalInformations, payrollConfigurations));
            }

            ConcurrentBag <PayrollStampingResultDetail> payrollStampingDetails = new ConcurrentBag <PayrollStampingResultDetail>();

            foreach (var task in await Task.WhenAll(tasks))
            {
                foreach (var insideTask in task)
                {
                    payrollStampingDetails.Add(insideTask);
                }
            }
            payrollStampingResult.PayrollStampingResultDetails = payrollStampingDetails.ToList();

            //Update DB indicate that Overdraft was stamped correctly / PeriodDetail
            await saveOverdraftStampedAsync(payrollStampingParams, payrollStampingResult);

            //Errors preparation
            if (payrollStampingResult.PayrollStampingResultDetails.Any(p => p.PayrollStampingResultStatus == PayrollStampingResultStatus.Fail))
            {
                var errorMessages = payrollStampingResult.PayrollStampingResultDetails.Select(p => p.Message);
                throw new CotorraException(109, "109", string.Join("\n", errorMessages), null);
            }

            return(payrollStampingResult);
        }
        private async Task <List <PayrollStampingResultDetail> > doWorkAsync(Overdraft overdraftToStamp, RoundUtil roundUtil,
                                                                             ZipCodeManager zipCodeManager, PayrollStampingParams payrollStampingParams,
                                                                             BlobStorageUtil blobStorageUtil,
                                                                             ISendMailProvider sendMailProvider,
                                                                             List <Incident> incidents,
                                                                             List <Inhability> inhabilities,
                                                                             List <EmployerFiscalInformation> employerFiscalInformations,
                                                                             List <PayrollCompanyConfiguration> payrollConfigurations)
        {
            var payrollStampingResultDetail  = new PayrollStampingResultDetail();
            var payrollStampingResultDetails = new List <PayrollStampingResultDetail>();

            //Obtiene los xmls de los comprobantes segun la version de CFDI especificada
            IFiscalStamping fiscalStamping = FiscalStampingFactory.CreateInstance(payrollStampingParams.FiscalStampingVersion);

            //1. Get totals
            var overdraftResults = new OverdraftManager().GetTotals(overdraftToStamp, roundUtil);

            //1.1 Datetime for zipCode
            (var zipcode, var datetimeFromZipCode) = await zipCodeManager.GetZipCode(overdraftToStamp, payrollConfigurations.FirstOrDefault());

            //2. Get XML - Creates comprobante
            var payrolllStampingDetail = payrollStampingParams.Detail
                                         .FirstOrDefault(detail => detail.OverdraftID == overdraftToStamp.ID);
            ICFDINomProvider cfdi = null;

            try
            {
                cfdi = fiscalStamping.CreateComprobante(new CreateComprobanteParams()
                {
                    PayrollStampingDetail       = payrolllStampingDetail,
                    PayrollStampingParams       = payrollStampingParams,
                    Overdraft                   = overdraftToStamp,
                    OverdraftResults            = overdraftResults,
                    PayrollCompanyConfiguration = payrollConfigurations.FirstOrDefault(),
                    CFDIDateTimeStamp           = datetimeFromZipCode,
                    ZipCode      = zipcode,
                    RoundUtil    = roundUtil,
                    Incidents    = incidents,
                    Inhabilities = inhabilities
                });
            }
            catch (Exception ex)
            {
                //Errores en validaciónes de armado / fiscales
                payrollStampingResultDetail.Message = ex.Message;
                payrollStampingResultDetail.PayrollStampingResultStatus = PayrollStampingResultStatus.Fail;
                payrollStampingResultDetail.HistoricEmployeeID          = overdraftToStamp.HistoricEmployeeID.Value;
                payrollStampingResultDetail.EmployeeID     = overdraftToStamp.HistoricEmployee.EmployeeID;
                payrollStampingResultDetail.OverdraftID    = overdraftToStamp.ID;
                payrollStampingResultDetail.Overdraft      = overdraftToStamp;
                payrollStampingResultDetail.PeriodDetailID = overdraftToStamp.PeriodDetailID;
                payrollStampingResultDetail.PeriodDetail   = overdraftToStamp.PeriodDetail;

                payrollStampingResultDetails.Add(payrollStampingResultDetail);
                return(payrollStampingResultDetails);
            }

            //3. Sign XML
            var certificateCER = employerFiscalInformations.FirstOrDefault().CertificateCER;
            var certificateKey = employerFiscalInformations.FirstOrDefault().CertificateKEY;
            var certPassword   = employerFiscalInformations.FirstOrDefault().CertificatePwd;

            //Decrypt
            (var certificatebytesCER, var certificatebytesKEY, var certPasswordResult) = Crypto(payrollStampingParams, certificateCER, certificateKey, certPassword);

            var stampingResult = fiscalStamping.SignDocument(cfdi, certificatebytesCER, certificatebytesKEY, certPasswordResult);

            //Set the employer
            stampingResult.EmployerRFC = payrollConfigurations.FirstOrDefault().RFC;

            //4. Stamp XML
            stampingResult = await fiscalStamping.StampDocumetAsync(stampingResult);

            if (stampingResult.WithErrors)
            {
                //error en el timbrado
                var errrorMessage = $"\nPara el empleado <strong>'{overdraftToStamp.HistoricEmployee.FullName}'</strong> encontramos los siguientes errores de timbrado: '{stampingResult.Details}'";
                payrollStampingResultDetail.Message = errrorMessage;
                payrollStampingResultDetail.PayrollStampingResultStatus = PayrollStampingResultStatus.Fail;
            }
            else
            {
                //5. Return the complete XML
                stampingResult.XML = fiscalStamping.CreateXml <ICFDINomProvider>(stampingResult.CFDI, true);

                //5.5 Fill the result data
                payrollStampingResultDetail.Message = String.Empty;
                payrollStampingResultDetail.UUID    = stampingResult.UUID;
                payrollStampingResultDetail.XML     = stampingResult.XML;
                payrollStampingResultDetail.PayrollStampingResultStatus = PayrollStampingResultStatus.Success;

                //6. Fill the result data
                overdraftToStamp.UUID            = stampingResult.UUID;
                overdraftToStamp.OverdraftStatus = OverdraftStatus.Stamped;

                //Fire and forget convertion and sending email
                fireAndForgetAsync(payrollStampingParams, overdraftToStamp, payrollConfigurations,
                                   blobStorageUtil, sendMailProvider, payrollStampingResultDetail.UUID, payrollStampingResultDetail.XML);

                //Fill the result object
                payrollStampingResultDetail.HistoricEmployeeID = overdraftToStamp.HistoricEmployeeID.Value;
                payrollStampingResultDetail.EmployeeID         = overdraftToStamp.HistoricEmployee.EmployeeID;
                payrollStampingResultDetail.OverdraftID        = overdraftToStamp.ID;
                payrollStampingResultDetail.Overdraft          = overdraftToStamp;
                payrollStampingResultDetail.PeriodDetailID     = overdraftToStamp.PeriodDetailID;
                payrollStampingResultDetail.PeriodDetail       = overdraftToStamp.PeriodDetail;
            }


            payrollStampingResultDetails.Add(payrollStampingResultDetail);

            return(payrollStampingResultDetails);
        }