// Transaction Methods /// <summary> /// On Pinpad screen, alternates between "RETIRE O CARTÃO" and parameter 'message' received, until card removal. /// </summary> /// <param name="message">Message to be shown on pinpad screen. Must not exceed 16 characters. This message remains on Pinpad screen after card removal.</param> /// <param name="padding">Message alignment.</param> /// <returns></returns> public bool RemoveCard(string message, DisplayPaddingType padding) { RmcRequest request = new RmcRequest(); // Assemblies RMC command. request.RMC_MSG.Value = new SimpleMessageProperty(message, padding); // Sends command and receive response GenericResponse response = null; while (response == null) { response = this.pinpadCommunication.SendRequestAndReceiveResponse <GenericResponse>(request); } // Getting legacy response status code: AbecsResponseStatus legacyStatus = AbecsResponseStatus.ST_OK; // Mapping legacy status code into Pinpad.Sdk response status code. this.LastCommandStatus = ResponseStatusMapper.MapLegacyResponseStatus(legacyStatus); // Verifies if the command was executed. if (this.LastCommandStatus == ResponseStatus.Ok) { return(true); } else { return(false); } }
// Methods /// <summary> /// Read security information when card has no chip - magnetic stripe only. /// </summary> /// <param name="pinpadCommunication">Pinpad communication, through which c</param> /// <param name="pan">Primary Account Number printed on the card.</param> /// <param name="amount">Transaction amount.</param> /// <param name="pin">Pin read.</param> /// <returns>Wheter is an online transaction or not.</returns> /// <exception cref="System.InvalidOperationException">Thrown when parameter validation fails.</exception> internal ResponseStatus Read(IPinpadCommunication pinpadCommunication, string pan, decimal amount, out Pin pin) { pin = null; // Validating data try { this.Validate(pinpadCommunication, amount, pan); } catch (Exception ex) { throw new InvalidOperationException("Error while trying to read security info using magnetic stripe. Verify inner exception.", ex); } // Using ABECS GPN command to get pin block & KSN. GpnResponse response = this.SendGpn(pinpadCommunication, pan, amount); // Saving command response status: AbecsResponseStatus legacyStatus = response.RSP_STAT.Value; ResponseStatus status = ResponseStatusMapper.MapLegacyResponseStatus(legacyStatus); if (status == ResponseStatus.Ok) { // Magnetic stripe always validates pin online. pin = new Pin(); pin.PinBlock = response.GPN_PINBLK.Value.DataString; pin.KeySerialNumber = response.GPN_KSN.Value.DataString; pin.IsOnline = true; } pin.ApplicationCryptogram = null; return(status); }
internal static ResponseStatus MapLegacyResponseStatus(AbecsResponseStatus status) { switch (status) { case AbecsResponseStatus.ST_OK: return(ResponseStatus.Ok); case AbecsResponseStatus.ST_NOSEC: return(ResponseStatus.NotSecureCommunication); case AbecsResponseStatus.ST_F1: return(ResponseStatus.F1KeyPressed); case AbecsResponseStatus.ST_F2: return(ResponseStatus.F2KeyPressed); case AbecsResponseStatus.ST_F3: return(ResponseStatus.F3KeyPressed); case AbecsResponseStatus.ST_F4: return(ResponseStatus.F4KeyPressed); case AbecsResponseStatus.ST_BACKSP: return(ResponseStatus.BackspacePressed); case AbecsResponseStatus.ST_ERRPKTSEC: return(ResponseStatus.CancelKeyPressed); case AbecsResponseStatus.ST_INVCALL: return(ResponseStatus.InvalidCommand); case AbecsResponseStatus.ST_INVPARM: return(ResponseStatus.InvalidParameter); case AbecsResponseStatus.ST_TIMEOUT: return(ResponseStatus.TimeOut); case AbecsResponseStatus.ST_CANCEL: return(ResponseStatus.OperationCancelled); case AbecsResponseStatus.ST_NOTOPEN: return(ResponseStatus.PinpadIsClosed); case AbecsResponseStatus.ST_MANDAT: return(ResponseStatus.MandatoryParameterNotReceived); case AbecsResponseStatus.ST_TABVERDIF: return(ResponseStatus.InvalidEmvTable); case AbecsResponseStatus.ST_TABERR: return(ResponseStatus.CouldNotWriteTable); case AbecsResponseStatus.ST_INTERR: return(ResponseStatus.InternalError); case AbecsResponseStatus.ST_MCDATAERR: return(ResponseStatus.MagneticStripeError); case AbecsResponseStatus.ST_ERRKEY: return(ResponseStatus.PinIndexNotFound); case AbecsResponseStatus.ST_NOCARD: return(ResponseStatus.NoneCardDetected); case AbecsResponseStatus.ST_PINBUSY: return(ResponseStatus.PinBusy); case AbecsResponseStatus.ST_RSPOVRFL: return(ResponseStatus.ResponseDataOverflow); case AbecsResponseStatus.ST_NOSAM: return(ResponseStatus.SamError); case AbecsResponseStatus.ST_DUMBCARD: return(ResponseStatus.DumbCard); case AbecsResponseStatus.ST_ERRCARD: return(ResponseStatus.CardCommunicationError); case AbecsResponseStatus.ST_CARDINVALIDAT: return(ResponseStatus.InvalidCard); case AbecsResponseStatus.ST_CARDPROBLEMS: return(ResponseStatus.CardProblems); case AbecsResponseStatus.ST_CARDINVDATA: return(ResponseStatus.InconsistentCard); case AbecsResponseStatus.ST_CARDAPPNAV: return(ResponseStatus.InvalidEmvApplication); case AbecsResponseStatus.ST_CARDAPPNAUT: return(ResponseStatus.UnableToProcessEmvApplication); case AbecsResponseStatus.ST_ERRFALLBACK: return(ResponseStatus.Fallback); case AbecsResponseStatus.ST_INVAMOUNT: return(ResponseStatus.InvalidAmount); case AbecsResponseStatus.ST_CTLSSMULTIPLE: return(ResponseStatus.MultipleContactlessDetected); case AbecsResponseStatus.ST_CTLSSCOMMERR: return(ResponseStatus.CtlsCommunicationError); case AbecsResponseStatus.ST_CTLSSINVALIDAT: return(ResponseStatus.InvalidCtlsCard); case AbecsResponseStatus.ST_CTLSSPROBLEMS: return(ResponseStatus.CtlsCardProblems); case AbecsResponseStatus.ST_CTLSSAPPNAV: return(ResponseStatus.InvalidCtlsApplication); case AbecsResponseStatus.ST_CTLSSAPPNAUT: return(ResponseStatus.UnableToProcessCtlsApplication); case AbecsResponseStatus.ST_MFNFOUND: return(ResponseStatus.FileNotFound); case AbecsResponseStatus.ST_MFERRFMT: return(ResponseStatus.FileFormatError); case AbecsResponseStatus.ST_MFERR: return(ResponseStatus.FileLoadingError); default: return((ResponseStatus)status); } }
/// <summary> /// Read basic card information, that is, brand id, card type, card primary account number (PAN), cardholder name and expiration date. /// If the card is removed in the middle of the process, returns CANCEL status. /// </summary> /// <param name="transactionType">Transaction type, that is, debit/credit.</param> /// <param name="amount">Transaction amount.</param> /// <param name="cardRead">Card to be read.</param> /// <param name="newTransactionType">New transaction type read throgh ABECS protocol.</param> /// <param name="cardBrands">List of brands supported.</param> /// <returns>Operation status.</returns> private AbecsResponseStatus PerformCardReading(TransactionType transactionType, decimal amount, out CardEntry cardRead, out TransactionType newTransactionType, IList <PinpadCardBrand> cardBrands) { cardRead = null; newTransactionType = transactionType; GcrRequest request = this.CreateGcrRequest(transactionType, amount); // There's no table version, therefore tables cannot be reached. if (request == null) { return(AbecsResponseStatus.ST_TABERR); } // Sending and receiving response. Debug.WriteLine("Sending GCR command <{0}>", request.CommandString); GcrResponse response = this.pinpadCommunication.SendRequestAndReceiveResponse <GcrResponse>(request); // If timeout was reached: if (response == null) { return(AbecsResponseStatus.ST_TIMEOUT); } // If an error occurred: else if (response.RSP_STAT.Value != AbecsResponseStatus.ST_OK) { return(response.RSP_STAT.Value); } // If the card has expired: else if (response.GCR_CARDTYPE.Value == ApplicationType.MagneticStripe) { CardEntry tempCard; // Verify if it is really a magnetic stripe card: tempCard = CardMapper.MapCardFromTracks(response, cardBrands); // TODO: Incluir o fallback nessa condição. if (tempCard.Type != response.GCR_CARDTYPE.Value.ToCardType()) { throw new CardHasChipException(); } // Validate expired cards: DateTime expirationDate = tempCard.ExpirationDate; if (expirationDate < DateTime.Now) { throw new ExpiredCardException(expirationDate); } } else if (response.GCR_CARDEXP.HasValue == false) { throw new ExpiredCardException(DateTime.MinValue); } // Saving the transaction type. This is handy if you have initiated the transaction without knowing the transaction type. // In this situation, the user will select transaction type throgh the pinpad. newTransactionType = (TransactionType)response.GCR_APPTYPE.Value; // Saving command response status. // Getting legacy response status code: AbecsResponseStatus legacyStatus = response.RSP_STAT.Value; // Mapping legacy status code into Pinpad.Sdk response status code. this.LastCommandStatus = ResponseStatusMapper.MapLegacyResponseStatus(legacyStatus); // Get card information and return it: cardRead = CardMapper.MapCardFromTracks(response, cardBrands); if (cardRead.Type == CardType.Emv) { if (this.EmvTable.AidTable.Count <= 0) { throw new InvalidTableException("AID table is empty."); } int brandId = cardRead.BrandId; var aidVar = this.EmvTable.AidTable.First(a => a.TAB_RECIDX.Value.Value == brandId); cardRead.ApplicationId = aidVar.T1_AID.Value.DataString; // If it is a EMV transaction, then the application SHOULD send a CNG to change EMV parameters: // TODO: Ver como o comando CNG funciona. Não retirar. //if (response.GCR_CARDTYPE.Value == ApplicationType.IccEmv) //{ // CngRequest cng = new CngRequest(); // cng.CNG_EMVDAT.Value = ((...)) // bool stats = this.pinpadCommunication.SendRequestAndVerifyResponseCode(cng); //} } return(AbecsResponseStatus.ST_OK); }
// Methods /// <summary> /// Reads the card. /// </summary> /// <param name="communication">Pinpad facade, responsible for pinpad communication and plus.</param> /// <param name="amount">Transaction amount.</param> /// <param name="pin">Pin information read.</param> /// <returns>Operation status.</returns> internal ResponseStatus Read(IPinpadCommunication communication, decimal amount, out Pin pin) { pin = null; // Validating data this.Validate(communication, amount); // Using ABECS GOC command to communicate with pinpad. GocResponse commandResponse = this.SendGoc(communication, amount); if (commandResponse == null) { if (communication.Ping() == true) { // Pinpad is connected. Time out. return(ResponseStatus.TimeOut); } else { // Pinpad loss conection. throw new PinpadDisconnectedException("Não foi possível ler a senha.\nVerifique a conexão com o pinpad."); } } // Saving command response status: AbecsResponseStatus legacyStatus = commandResponse.RSP_STAT.Value; ResponseStatus status = ResponseStatusMapper.MapLegacyResponseStatus(legacyStatus); if (status != ResponseStatus.Ok) { return(status); } //if (status == ResponseStatus.OperationCancelled) { return status; } pin = new Pin(); pin.ApplicationCryptogram = this.GetValueFromEmvData( commandResponse.GOC_EMVDAT.Value.DataString, EmvTagCode.ApplicationCryptogram); pin.CardholderNameExtended = this.GetValueFromEmvData( commandResponse.GOC_EMVDAT.Value.DataString, EmvTagCode.CardholderNameExtended); // Whether is a pin online authentication or not. if (commandResponse.GOC_PINONL.Value.HasValue == true) { pin.IsOnline = commandResponse.GOC_PINONL.Value.Value; } // If EMV data war not returned from the command: if (commandResponse.GOC_EMVDAT.HasValue == false) { return(ResponseStatus.PinBusy); } // Savind EMV data: if (commandResponse.GOC_EMVDAT.Value != null) { pin.EmvData = commandResponse.GOC_EMVDAT.Value.DataString; } if (pin.IsOnline == true && commandResponse.GOC_DECISION.Value == OfflineTransactionStatus.RequiresAuthorization) { // If it's an online transaction, that is, needs pin and ksn emv validation: pin.PinBlock = commandResponse.GOC_PINBLK.Value.DataString; pin.KeySerialNumber = commandResponse.GOC_KSN.Value.DataString; } // Returns read pin block. return(status); }