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();
                    }
                }
            }
        }
        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);
        }