/// <summary>
        /// creates the cancelacion xml
        /// </summary>
        /// <param name="cancelDocumentParams"></param>
        /// <param name="cancelacion"></param>
        /// <returns></returns>
        private string createCancelationXML(CancelDocumentParams cancelDocumentParams, Cancelacion cancelacion)
        {
            //get FiscalInformation
            X509Certificate2 x509Certificate2 = new X509Certificate2(cancelDocumentParams.CertificateCER);

            //get cancelacion xml
            string xml = SerializerXml.SerializeObject(cancelacion);

            System.Security.Cryptography.Xml.Signature signature = new Cotorra.DigitalSign.DigitalSign().ApplySignature(cancelDocumentParams.CertificateKey,
                                                                                                                        cancelDocumentParams.Password, xml);
            cancelacion.Signature            = new SignatureType();
            cancelacion.Signature.SignedInfo = new SignedInfoType();
            cancelacion.Signature.SignedInfo.CanonicalizationMethod           = new CanonicalizationMethodType();
            cancelacion.Signature.SignedInfo.CanonicalizationMethod.Algorithm = signature.SignedInfo.CanonicalizationMethodObject.Algorithm;
            cancelacion.Signature.SignedInfo.SignatureMethod           = new SignatureMethodType();
            cancelacion.Signature.SignedInfo.SignatureMethod.Algorithm = signature.SignedInfo.SignatureMethod;
            cancelacion.Signature.SignedInfo.Reference = new ReferenceType();
            Reference reference = (Reference)signature.SignedInfo.References[0];

            cancelacion.Signature.SignedInfo.Reference.URI        = reference.Uri;
            cancelacion.Signature.SignedInfo.Reference.Transforms = new List <TransformType>()
            {
                new TransformType()
                {
                    Algorithm = ALGORITHM_TRANSFORMATION
                }
            }.ToArray();
            cancelacion.Signature.SignedInfo.Reference.DigestMethod           = new DigestMethodType();
            cancelacion.Signature.SignedInfo.Reference.DigestMethod.Algorithm = reference.DigestMethod;
            cancelacion.Signature.SignedInfo.Reference.DigestValue            = reference.DigestValue;
            cancelacion.Signature.SignatureValue   = signature.SignatureValue;
            cancelacion.Signature.KeyInfo          = new KeyInfoType();
            cancelacion.Signature.KeyInfo.X509Data = new X509DataType();
            cancelacion.Signature.SignedInfo.Reference.DigestValue = reference.DigestValue;
            cancelacion.Signature.SignatureValue   = signature.SignatureValue;
            cancelacion.Signature.KeyInfo          = new KeyInfoType();
            cancelacion.Signature.KeyInfo.X509Data = new X509DataType();
            cancelacion.Signature.KeyInfo.X509Data.X509IssuerSerial = new X509IssuerSerialType();
            cancelacion.Signature.KeyInfo.X509Data.X509IssuerSerial.X509IssuerName   = x509Certificate2.Issuer;
            cancelacion.Signature.KeyInfo.X509Data.X509IssuerSerial.X509SerialNumber = x509Certificate2.GetSerialNumberString();
            cancelacion.Signature.KeyInfo.X509Data.X509Certificate = x509Certificate2.GetRawCertData();

            //get xml cancelacion
            string xmlCancelacion = SerializerXml.SerializeObject(cancelacion);

            return(xmlCancelacion);
        }
Exemple #2
0
        public async Task <CancelPayrollStampingResult> CancelPayrollStampingAsync(CancelPayrollStampingParams cancelPayrollStampingParams)
        {
            //Create cancelation instance
            ICancelStamping cancelStamping = CancelStampingFactory.CreateInstance(cancelPayrollStampingParams.FiscalStampingVersion);

            //Get overdrafts and validate
            var overdraftMiddlewareManager = new MiddlewareManager <Overdraft>(new BaseRecordManager <Overdraft>(),
                                                                               new OverdraftValidator());
            var overdraftsIds      = cancelPayrollStampingParams.OverdraftIDs;
            var overdraftsToCancel = await overdraftMiddlewareManager.FindByExpressionAsync(p =>
                                                                                            p.company == cancelPayrollStampingParams.IdentityWorkID &&
                                                                                            p.InstanceID == cancelPayrollStampingParams.InstanceID &&
                                                                                            overdraftsIds.Contains(p.ID) &&
                                                                                            p.OverdraftStatus == OverdraftStatus.Stamped &&
                                                                                            p.Active,
                                                                                            cancelPayrollStampingParams.IdentityWorkID);

            if (!overdraftsToCancel.Any())
            {
                throw new CotorraException(106, "106", "No existen recibos a cancelar con los datos proporcionados.", null);
            }

            //Get configuration company
            var payrollMiddlewareManager = new MiddlewareManager <PayrollCompanyConfiguration>(new BaseRecordManager <PayrollCompanyConfiguration>(),
                                                                                               new PayrollCompanyConfigurationValidator());
            var payrollCompanyConfiguration = await payrollMiddlewareManager.FindByExpressionAsync(p => p.InstanceID == cancelPayrollStampingParams.InstanceID,
                                                                                                   cancelPayrollStampingParams.IdentityWorkID, new string[] { "Address" });

            if (!payrollCompanyConfiguration.Any())
            {
                throw new CotorraException(106, "106", "No existe configuración de la compañia.", null);
            }

            //Get configuration company
            var fiscalInformationManager = new MiddlewareManager <EmployerFiscalInformation>(new BaseRecordManager <EmployerFiscalInformation>(),
                                                                                             new EmployerFiscalInformationValidator());
            var employerFiscalInformations = await fiscalInformationManager.FindByExpressionAsync(p =>
                                                                                                  p.InstanceID == cancelPayrollStampingParams.InstanceID,
                                                                                                  cancelPayrollStampingParams.IdentityWorkID);

            if (!employerFiscalInformations.Any())
            {
                throw new CotorraException(106, "106", "No hay certificados válidos registrados para la compañia.", null);
            }

            //Zipcode Manager
            IEnumerable <string> zipCodesToFind = payrollCompanyConfiguration.Select(p => p.Address?.ZipCode);
            var zipCodeMiddlewareManager        = new MiddlewareManager <catCFDI_CodigoPostal>(
                new BaseRecordManager <catCFDI_CodigoPostal>(),
                new catCFDI_CodigoPostalValidator());
            var zipCodes = await zipCodeMiddlewareManager.FindByExpressionAsync(p =>
                                                                                zipCodesToFind.Contains(p.c_CodigoPostal)
                                                                                , cancelPayrollStampingParams.IdentityWorkID);

            if (!zipCodes.Any())
            {
                throw new CotorraException(106, "106", "No hay codigo postal registrado para la compañia.", null);
            }

            //UUIDs to Cancel
            var uuids = overdraftsToCancel.Select(p => p.UUID).ToList();

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

            //Decrypt and get certificate
            (var certificatebytesCER, var certificatebytesKEY, var certPasswordResult) = Crypto(cancelPayrollStampingParams,
                                                                                                certificateCER, certificateKey, certPassword);

            //Cancel Document Details
            var cancelDocumentParamsDetails = new List <CancelDocumentParamsDetail>();

            uuids.ForEach(p =>
            {
                var cancelDetail         = new CancelDocumentParamsDetail();
                cancelDetail.OverdraftID = overdraftsToCancel.FirstOrDefault(q => q.UUID == p).ID;
                cancelDetail.UUID        = p;
                cancelDocumentParamsDetails.Add(cancelDetail);
            });

            CancelDocumentParams cancelDocumentParams = new CancelDocumentParams()
            {
                ZipCodes       = zipCodes,
                IssuerZipCode  = payrollCompanyConfiguration.FirstOrDefault().Address?.ZipCode,
                IssuerRFC      = payrollCompanyConfiguration.FirstOrDefault().RFC,
                CertificateCER = certificatebytesCER,
                CertificateKey = certificatebytesKEY,
                Password       = certPasswordResult,
                IdentityWorkID = cancelPayrollStampingParams.IdentityWorkID,
                InstanceID     = cancelPayrollStampingParams.InstanceID,
                user           = cancelPayrollStampingParams.user,
                CancelDocumentParamsDetails = cancelDocumentParamsDetails
            };

            //cancel cfdi document
            var result = await cancelStamping.CancelDocumetAsync(cancelDocumentParams);

            if (result.WithErrors)
            {
                throw new CotorraException(107, "107", $"Error al cancelar el recibo: {result.Message}", null);
            }

            //Fill Save Cancelation Object
            var cancelationRequestXMLID  = Guid.NewGuid();
            var cancelationResponseXMLID = Guid.NewGuid();

            var cancelSPFiscalParams = new List <CancelationStoreProcedureParams>();

            result.CancelPayrollStampingResultDetails.ForEach(p => {
                var cancelationStoreProcedure         = new CancelationStoreProcedureParams();
                cancelationStoreProcedure.OverdraftID = overdraftsToCancel.FirstOrDefault(q => q.UUID == p.UUID).ID;
                cancelationStoreProcedure.CancelationFiscalDocumentStatus =
                    p.PayrollStampingResultStatus == PayrollStampingResultStatus.Success ?
                    CancelationFiscalDocumentStatus.Done : CancelationFiscalDocumentStatus.ErrorInRequest;
                cancelSPFiscalParams.Add(cancelationStoreProcedure);
            });

            //Database
            await saveCancelFiscalStamping(cancelPayrollStampingParams, cancelationRequestXMLID, cancelationResponseXMLID, cancelSPFiscalParams);

            //Save XML of cancelation  in blob (request)
            var blobStorageUtil = new BlobStorageUtil(cancelDocumentParams.InstanceID);
            await blobStorageUtil.InitializeAsync();

            await blobStorageUtil.UploadDocumentAsync($"{cancelationRequestXMLID}.xml", result.CancelacionXMLRequest);

            //Save XML of cancelation acknowledgement in blob (response)
            await blobStorageUtil.InitializeAsync();

            await blobStorageUtil.UploadDocumentAsync($"{cancelationResponseXMLID}.xml", result.CancelacionXMLAcknowledgeResponse);

            return(result);
        }
        /// <summary>
        /// CancelDocumetAsync
        /// </summary>
        /// <returns></returns>
        public async Task <CancelPayrollStampingResult> CancelDocumetAsync(CancelDocumentParams cancelDocumentParams)
        {
            var cancelPayrollStampingResult = new CancelPayrollStampingResult();

            try
            {
                //Get datetime from ZipCode of Employer
                var zipCodeManager = new ZipCodeManager(cancelDocumentParams.ZipCodes);
                (var zipcode, var datetimeFromZipCode) = await zipCodeManager.GetZipCode(cancelDocumentParams.IssuerZipCode);

                //Fill the cancelation object
                Cancelacion cancelacion = new Cancelacion();
                cancelacion.RfcEmisor = cancelDocumentParams.IssuerRFC;
                cancelacion.Fecha     = DateTime.Parse(string.Format("{0:s}", datetimeFromZipCode), CultureInfo.InvariantCulture);
                var cancelacionFolios = new List <CancelacionFolios>();
                var uuids             = cancelDocumentParams.CancelDocumentParamsDetails.Select(p => p.UUID).ToList();
                uuids.ForEach(p => cancelacionFolios.Add(new CancelacionFolios()
                {
                    UUID = p.ToString().ToLower()
                }));
                cancelacion.Folios = cancelacionFolios.ToArray();

                //Creates the cancelationXML
                var xmlCancelation = createCancelationXML(cancelDocumentParams, cancelacion);

                //Call PAC for cancelation
                var stampResult = new CancelDocumentResult <ICFDINomProvider>();
                stampResult.CancelationXML = xmlCancelation;
                stampResult.InstanceID     = cancelDocumentParams.InstanceID;
                IPACProvider pACProvider          = FactoryPACProvider.CreateInstanceFromConfig();
                var          cancelationPACResult = await pACProvider.CancelStampingDocumentAsync(stampResult);

                if (cancelationPACResult.WithErrors)
                {
                    cancelPayrollStampingResult.WithErrors = true;
                    cancelPayrollStampingResult.Message    = cancelationPACResult.Details;
                }
                else
                {
                    cancelPayrollStampingResult.WithErrors                        = false;
                    cancelPayrollStampingResult.CancelacionXMLRequest             = cancelationPACResult.CancelationXML;
                    cancelPayrollStampingResult.CancelacionXMLAcknowledgeResponse = cancelationPACResult.CancelationAcknowledgmentReceipt;

                    //Fill each UUID with the proper status
                    var acuse = SerializerXml.DeserializeObject <Acuse>(cancelationPACResult.CancelationAcknowledgmentReceipt);
                    acuse.Folios.ForEach(p =>
                    {
                        var detail = new CancelPayrollStampingResultDetail();

                        /*
                         * 201 - El folio se ha cancelado con éxito.
                         * 202 - El CFDI ya había sido cancelado previamente.
                         * 203 - UUID no corresponde al emisor.
                         * 204 - El CFDI no aplica para cancelación.
                         * 205 - El UUID no existe o no ha sido procesado por el SAT.
                         * 402 - El Contribuyente no se encuentra el la LCO o la validez de obligaciones se reporta como negativa.
                         */
                        if (p.EstatusUUID == "201" || p.EstatusUUID == "202") //estatus good
                        {
                            statusCancelationCodes.TryGetValue(p.EstatusUUID, out string message);
                            detail.Message = $"{p.EstatusUUID} : {message}";
                            detail.UUID    = Guid.Parse(p.UUID);
                            detail.PayrollStampingResultStatus = PayrollStampingResultStatus.Success;
                        }
                        else
                        {
                            statusCancelationCodes.TryGetValue(p.EstatusUUID, out string message);
                            detail.Message = $"Error al cancelar {p.EstatusUUID} : {message}";
                            detail.UUID    = Guid.Parse(p.UUID);
                            detail.PayrollStampingResultStatus = PayrollStampingResultStatus.Fail;
                        }
                        cancelPayrollStampingResult.CancelPayrollStampingResultDetails.Add(detail);
                    });
                }
            }
            catch (Exception ex)
            {
                cancelPayrollStampingResult.WithErrors = true;
                cancelPayrollStampingResult.Message    = $"Ocurrió un error no controlado en la cancelación: {ex.Message}";
            }

            return(cancelPayrollStampingResult);
        }