Upgrading Your Custom Ecommerce Application to Work with New Payment Processors

Upgrading Your Custom Ecommerce Application to Work with New Payment Processors
Slide Note
Embed
Share

In this presentation, David Schlum and Shannon Merritt discuss the process of upgrading a legacy custom eCommerce application to align with new payment processors. The focus is on enhancing security by eliminating stored encrypted card data and meeting PCI compliance. The conversion process involves a multi-step approach with testing and production phases. Learn about the importance of upgrading custom tables and processes to mimic Abila's baseline process.

  • Upgrade
  • Ecommerce
  • Payment Processors
  • Security
  • PCI Compliance

Uploaded on Feb 18, 2025 | 2 Views


Download Presentation

Please find below an Image/Link to download the presentation.

The content on the website is provided AS IS for your information and personal use only. It may not be sold, licensed, or shared on other websites without obtaining consent from the author.If you encounter any issues during the download, it is possible that the publisher has removed the file from their server.

You are allowed to download the files provided on this website for personal or commercial use, subject to the condition that they are used lawfully. All files are the property of their respective owners.

The content on the website is provided AS IS for your information and personal use only. It may not be sold, licensed, or shared on other websites without obtaining consent from the author.

E N D

Presentation Transcript


  1. "SHOW ME THE MONEY" - UPGRADING YOUR CUSTOM ECOMMERCE APPLICATION TO WORK WITH THE NEW PAYMENT PROCESSORS David Schlum, Director of IT and Software Architect, Old Town IT Shannon Merritt, Manager, Application Support, AAFP SPECIAL THANKS TO OUR AUG DEVELOPER DEEP DIVE SPONSORS:

  2. Shannon Merrit Manager, Software Development American Academy of Family Physicians .NET Developer SQL Developer Troubleshooter oversee development, UX and QA teams netFORUM developer since 2009 Work closely with Abila on solutions

  3. David Schlum IT Director & Software Architect Old Town IT .NET Developer SQL Developer Troubleshooter netFORUM developer since 2010 Work closely with Abila on solutions

  4. Not just because Why upgrade baseline? Lowers PCI compliance concerns doesn t eliminate them (yet) No longer storing encrypted card data in netFORUM And custom stuff? You are responsible for upgrading custom tables/processes Mimicking Abila s baseline process This is what we re here for! Future? More in the works

  5. Legacy eCommerce What s a legacy custom eCommerce application? Custom process Business need Still uses the baseline payment processors Stores payment information in encrypted format**

  6. AAFPs eCommerce App Membership Application Process Potential members complete membership application No requirement to login Pre-authorization only - no actual credit card charge Association and chapter approval required AAFP staff review and approve application; create or match application to netForum individual record Once approved, membership record created and stored payment info used for membership payment

  7. Conversion Process Multi-step approach Test/Prod Note: Assuming Payment Processors have already been set up. Test Prod Schema Changes Metadata (Form) Changes Create fake encrypted card data Test conversion with customized Abila Scheduled Task Clear encrypted card data Deploy schema and metadata Run conversion Clear encrypted card data

  8. The Data Custom table ac_customer_payment_info table v30_cst_key v30_apm_key v30_check_amount v30_name_on_check v30_check_number v30_eft_account_number v30_cc_auth v30_other_ref_number v30_cc_security_code v30_cc_number v30_cc_number_display v30_cc_expire v30_cc_cardholder_name v30_street v30_city v30_state v30_zip v30_enc_version v30_vault_account* v30_cpi_key* cpi_cst_key cpi_apm_key *added during migration cpi_name_on_check cpi_check_number cpi_eft_account_number, cpi_other_preauth_ref_number cpi_cc_security_code cpi_cc_number cpi_cc_number_display cpi_cc_expire cpi_cc_cardholder_name cpi_street cpi_city cpi_state cpi_zip cpi_enc_version cpi_vault_account

  9. Fake Encrypted Card Data UPDATE ac_customer_payment_info SET cpi_cc_number = CASE END , cpi_eft_account_number = CASE END , cpi_eft_routing_number = CASE END , cpi_cc_number_display = CASE END , cpi_eft_account_number_display = CASE END , cpi_enc_version=2 FROM ac_customer_payment_info JOIN ac_payment_method ON cpi_apm_key = apm_key WHEN apm_type = 'credit card' THEN master.dbo.Encrypt('4111111111111111', LOWER(cpi_key), dbo.av_get_version_number()) ELSE NULL WHEN apm_type = 'ACH' THEN master.dbo.Encrypt('1111111111', LOWER(cpi_key), dbo.av_get_version_number()) ELSE NULL WHEN apm_type = 'ACH' THEN '111111118' ELSE NULL WHEN apm_type = 'credit card' THEN '41**********1111' ELSE NULL WHEN apm_type = 'ACH' THEN '******1111' ELSE NULL

  10. Migration Process Migration Process Get records to convert (SPROC) Create map of old payment method to new payment method Decrypt credit card data For records with customer, map and create new cpi record, add cpi_key to v30 table Vault card data and store vault token to v30_vault_account Remove encypted card data from v30 table

  11. The outcome PCI Heaven (well, better) When customer data is added, cpi record can be created with already vaulted data Payments using cpi upon application approval

  12. Lessons Learned Simulated conversion saved the day! ERC YESEVLER MAH. HT. YZB.LEVENT ET NKAYA SOK.AKG L APT. NO:8/9 KOCAS NAN UT8.GetByteCount() != String.Length A little extra time on architecture can come in handy too

  13. The solution public static string StringLengthFix(string p, int length) { if (!string.IsNullOrWhiteSpace(p) && UTF8Encoding.UTF8.GetByteCount(p) > length) { p = StringLengthFix(p.Substring(0, p.Length - 1), length); } return p; } * Solution Provided to Abila R&D for baseline inclusion

  14. The workaround public class AAFP_ac_payment : Payment { //Implemented for the Litle Payment Processor only to address encoding issues with special characters. If moving to a //different processor, please remove public AAFP_ac_payment() { base.ElectronicPaymentConfig.PreAuth.RequestMapper.AfterMapLevel1Data += RequestMapper_AfterMapLevel1Data; base.ElectronicPaymentConfig.PostAuth.RequestMapper.AfterMapLevel1Data += RequestMapper_AfterMapLevel1Data; base.ElectronicPaymentConfig.Sale.RequestMapper.AfterMapLevel1Data += RequestMapper_AfterMapLevel1Data; base.ElectronicPaymentConfig.Void.RequestMapper.AfterMapLevel1Data += RequestMapper_AfterMapLevel1Data; } private void RequestMapper_AfterMapLevel1Data(object sender, CreditCardInfoMappingEventArgs e) { ValidateAddressInformation(e.CreditCardInfo); } private void ValidateAddressInformation(CreditCardInfo creditCardInfo) { //values obtained from Litle Processor but we are taking UTF-8 encoding now into account as some unicode characters //are actually being represented by 2 characters when encoded and the Litle service is throwing errors if the address //is too long due to the encoding creditCardInfo.Name = AAFP_Utility.StringLengthFix(creditCardInfo.Name, 100); creditCardInfo.Address = AAFP_Utility.StringLengthFix(creditCardInfo.Address, 35); creditCardInfo.Address2 = AAFP_Utility.StringLengthFix(creditCardInfo.Address2, 35); creditCardInfo.City = AAFP_Utility.StringLengthFix(creditCardInfo.City, 35); creditCardInfo.State = AAFP_Utility.StringLengthFix(creditCardInfo.State, 2); creditCardInfo.Zip = AAFP_Utility.StringLengthFix(creditCardInfo.Zip, 20); creditCardInfo.companyName = AAFP_Utility.StringLengthFix(creditCardInfo.companyName, 40); creditCardInfo.Email = AAFP_Utility.StringLengthFix(creditCardInfo.Email, 100); creditCardInfo.phoneNumber = AAFP_Utility.StringLengthFix(creditCardInfo.phoneNumber, 20); } }

  15. New Interface Warning! New stuff! namespace Avectra.netForum.Data { /// <summary> /// An interface used to define the functionality that is required when a class supports electronic payment processing /// through an instance of an ICreditCardProcessor. /// </summary> public interface IProcessesElectronicPayments { /// <summary> /// An object that stores configuration information for use when processing different types of /// electronic payments in netFORUM. /// </summary> ElectronicPaymentConfig ElectronicPaymentConfig { get; set; } /// <summary> /// A method in which ElectronicPaymentTypeConfig and associated CreditCardInfoMapper objects should be /// initialized on the ElectronicPaymentConfig object also provided by the IProcessesElectronicPayments interface. /// </summary> /// <remarks> /// When implementing this interface, this method should be called from a facade's InitializeObjects /// method. Also, it is recommended that you make this method protected virtual, allowing custom /// ElectronicPaymentTypeConfig and CreditCardInfoMapper objects to be provided when needed in order /// to satisfy more complex payment gateway requirements. /// </remarks> void InitializePaymentMappers(); } }

  16. Initialization public virtual void InitializePaymentMappers() { this.ElectronicPaymentConfig = new ElectronicPaymentConfig( new ElectronicPaymentTypeConfig(new PaymentPreAuthMapper(new CreditCardInfo())), // Pre-Auth new ElectronicPaymentTypeConfig(new PaymentPostAuthMapper(new CreditCardInfo())), // Post-Auth (aka Capture) new ElectronicPaymentTypeConfig(new PaymentSaleMapper(new CreditCardInfo())), // Sale (Check) null, // Credit new ElectronicPaymentTypeConfig(new PaymentVoidMapper(new CreditCardInfo())), // Void null); // Paypal Express }

  17. Mappers How data gets from Fa adeClass to Payment Processor

  18. Others public CreditCardInfo MapData(ICreditCardProcessor processor, FacadeClass dataSource, params KeyValuePair<string, string>[] additionalData) { // Save our processor reference for use throughout mapping. this.Processor = processor; // Map additional data for use in events and specific mapping routines! AddAdditionalDataForMapping(additionalData); // Spin up our event args object to pass along the CreditCardInfo and data source (FacadeClass) to our events as needed. CreditCardInfoMappingEventArgs args = new CreditCardInfoMappingEventArgs() { CreditCardInfo = this.CreditCardInfo, Processor = this.Processor, DataSource = dataSource, AdditionalData = this.AdditionalData }; // Handle level 1 events and data mapping. OnBeforeMapLevel1Data(args); MapLevel1Data(dataSource); OnAfterMapLevel1Data(args); // Handle level 2 events and data mapping. if (this.Processor.IsLevel2TransactionDataSupportedByProcessor() && this.Processor.IsLevel2TransactionDataSupportedByMerchantAccount) { OnBeforeMapLevel2Data(args); MapLevel2Data(dataSource); OnAfterMapLevel2Data(args); } // Handle level 3 events and data mapping. if (this.Processor.IsLevel3TransactionDataSupportedByProcessor() && this.Processor.IsLevel2TransactionDataSupportedByMerchantAccount && this.Processor.IsLevel3TransactionDataSupportedByMerchantAccount) // Must support level 2 to support level 3... { OnBeforeMapLevel3Data(args); MapLevel3Data(dataSource); OnAfterMapLevel3Data(args); } // Return the CreditCardInfo object that has been populated with netFORUM data based on the mapper configuration/context. return this.CreditCardInfo; }

  19. Payment (and more) events

  20. Payment (and more) events public class AAFP_ac_payment : Avectra.netForum.Components.AC.Payment { public AAFP_ac_payment() { this.BeforeProcessPostAuthTransaction += AAFP_ac_payment_BeforeProcessPostAuthTransaction; } void AAFP_ac_payment_BeforeProcessPostAuthTransaction(object sender , Avectra.netForum.Data.ProcessElectronicPaymentTransactionEventArgs e) { LogData(e.ElectronicPaymentTransactionData.OrderId, e.ElectronicPaymentTransactionData.Amount); } private void LogData(string p, decimal? nullable) { //TODO:move some electrons } }

  21. Riddle me this, Batman Any Questions?

  22. Thank you! David Schlum Old Town IT david@oldtownit.com Shannon Merritt AAFP smerritt@aafp.org

Related


More Related Content