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