accepting payments on website - php

I have 2 pages for collecting payments for an online services business.
1st form collects basic information (name, address, dob, etc) from buyers and inserts into a mysql table
when 1st page is submitted it forwards user to a page where they can select service packages which is linked to paypal payment gateway.
The scenario that i am facing is, after submitting the first page (data gets inserted to mysql) but lets say user decides not to pay for packages on 2nd page, i have redundant data in mysql table
Is there a way to manage this? should i combine payment collection + information collection in one page?
please advise,

If you don't want a customer to enter twice his personnal/shipping information, implement an account system, where a user creates an account with email/password, and his personnal/shipping information is linked to that account.
If you don't want an account system, you can make the folowing: when a user comes back, and if he already entered shipping information and didn't complete she payment, suggest him to reuse the previous information (by his cookie for example).
But anyway, there is not much you can do against a user that chooses to re-enter information (or create multiple accounts)

You have no redundant data in your database, you have potential customers that are interested in your product - but somehow didn't complete the payment step.
You could contact them later - having their email - and do some aftersales.

What you can do is set a timestamp on the data entered in the first page. Periodically, have a script run through the database and remove entries that are older than the last sweep. For example, if you run it daily, remove everything older than 2 days. Hourly, everything more than 2 hours, etc.

Related

Get the user status in WooCommerce plugin

I have a custom plugin that calls an API and adds some additional things to my orders at Woocommerce platform.
I had three scenarios before:
first time purchase, uses data submitted from the checkout form fields is used, e.g., $_POST['account_phone'], and everything went fine
subsequent purchases used the same principle
renewals used the order data from the initial orders, and acted like a single purchase is made
Now, the API has changed a bit and several new methods are available, which changes the scenario options above:
first time purchases go into two categories, new users at the API site, and existing users at the API site but new to this platform
remaining is the same
I have issue with the purchases for existing users of this site. First time purchase sends a request to the API, using the POST parameters. However, if a user is already registered, those parameters, like his cell phone number, should be read from the billing data he/she already entered. Thus, I need a way to tell the WooCommerce is this new user trying to buy something and registering, or that this is an already existing user that has his or her data entered. I can get this data from the initial order, or user's billing info, but can't figure out how to check what type of order is it and where WooCommerce should get those values from.
Thanks!
Managed to solve this via another way. The $fields['account']['account_phone'] was shown only during the registration, and simple change of that to $fields['billing']['account_phone'] makes that field "belong" to billing info, which is always shown, which is very convenient and makes no difference later when I check for input there.

Session being cleared during paypal Express checkout

I am currently developing an E-Comm site that uses Paypals express check out system. The express checkout system works fine, I send the payments amount, the user logs in to confirm the shipping details, and returns back to my page where I confirm it and the payment is completed. The main issue I am having is that I have the username (email) saved in the session. Once the user clicks checkout with paypal and confirms his/her paypal account, my session is cleared. So I cannot keep a record of who purchased what item (unless I use the users paypals email address which could be different from the one the user used on my site).
So my question is, is there any way that I can preserve the session state throughout this confirmation action? Or is there another way to keep the users information? is this a documented problem (I have not seen it anywhere)?
If any more detail is required let me know.
Thanks for your time.
No, once the user leaves your domain the session will terminate.
Instead you can store the email address in a table before user leaves your site and pass the ID of the inserted record to paypal. As this ID is a custom field it will be returned in the call back url once the user completes the payment. You can get the ID from URL and retrieve the corresponding email from database.
Even if your PHP session didn't terminate (there is likely a different reason for it closing), it still isn't a good idea to depend on the session being unmodified between the time the user leaves for PayPal and returns. Consider a user with multiple tabs that starts poking around your website in another tab before finishing Express Checkout.
Instead, store everything that is important to your checkout completion in a database, and pass a unique identifier through the Express Checkout process via the CUSTOM or INVNUM parameters. Those will be juggled through the checkout process. Once the callback returns to your site, you can very easily identify which "incomplete" order in your database it is referring to and mark it "paid."

What ways are there to store information about an anonymous/guest user in a database?

Our application has an online shop among other features, and users are normally requested to register before completing a sale, creating a unique customer_ID in the process. When they return, they can log in and their contact details and transaction history are retrieved from the database.
We are now exploring what to do in the case of an 'anonymous' or 'guest' customer, opening up the online shop to customers who don't want to register, and also for sales logged in the backend application, where taking the customer's email, postal address, etc is just too time consuming. The solution has applications outside the online shop too.
Multiple companies use the same database, and the database is built on a party model structure, so we have explored a few options:
Store all anonymous customers under one pre-defined customer_ID in the transaction table:
customer_ID = 0 for every anonymous user, and customer_ID > 0 for every real user
This is straight-forward to hard-code into the application
But more involved to determine which customers belong to which company
Should details for customer_ID = 0 exist in the customer table in the database or as an object in the application?
If in the database, what database-level constraints can be made to ensure that it always exists?
If not in the database, then foreign key constraints from transaction.customer_ID to customer.customer_ID no longer work
customer_ID is the same as the company party_ID
Easier to determine aggregate sales for each company, etc
This would confuse matters as it would appear that the company is its own customer, rather than other unique customers
Generate a unique customer_ID for every new anonymous customer (per session)
What if the same physical user returns? There will be many records repeating the same sort of data; email, shipping address, etc.
Use another unique key, such as email address, to refer to a customer
Not always reliable as people sometimes use more than one email address, or leave old addresses behind.
What if there is no email address to be taken, as is the case on the shop floor, pro forma invoices, etc?
Some other Stack Overflow inspired solution!
Addition
A combination of #2 and #3 has been suggested elsewhere - attempt to store a single record for each customer, using the email address if possible, or a new record on every visit if not.
I should point out that we don't need to store a record for every anonymous customer, but it just seems that the relational database was built to deal with relationships, so having a NULL or a customer_ID in the transaction table that doesn't reference an actual customer record just seems wrong...
I must also stress that the purpose of this question is to determine what real-world solutions there are to recording 'casual' transactions where no postal address or email address are given (imagine a supermarket chekout) alongside online shop transactions where an email address and postal address are given whether they are stored or not.
What solutions have the SO community used in the past?
Assuming you require an e-mail address for all online orders, you could create a temporary account for every customer at the completion of each order when they are not logged in.
This can be done by using the shipping address and other information provided during checkout to fill in the account, and e-mailing a random temporary password to them (optionally flagging it to require changing on the first log-in, if that functionality is built into the website). This requires minimal effort on their part to setup the account, and allows them to sign in to check their order status.
Since the primary key in your database is the customer_id, it should not cause conflicts if they continue making new accounts with the same e-mail/address/etc, unless you have code in place to prevent duplicates already. It's rare for someone to create more than one temporary account though, since it's easier to log in with the password e-mailed to them than entering their data again.
For the backend orders, we generally create an account in the same way as above for every customer. However, if they don't have an e-mail address (or they only want to purchase by phone), we generate an account with their shipping information and a blank e-mail address (have to code an exception to not send temporary passwords/order confirmations when it's blank). The customer_id is given to them, and their shipping information and company name are stored in the account to look up and expedite future orders.
I doubt there are any perfect solutions to this problem. You simply have to make a choice: How important is it to guarantee recognizable customer history in contrast to the improvement in conversions you get from not forcing a customer to go through a full registration process.
If you go without forcing registration, you will not be able to recognize returning customers 100% of the time. One might argue that even with registration that will not be possible, as users sometimes choose to create new accounts for various reasons. But you might be able to do something that's "good enough" by understanding the data you already have.
For example, in some countries, postcodes are quite specific. Are they specific enough? Depends in which countries you operate and also how your customer base is built. If you tend to only have one user per household, maybe.
Or depending on which payment methods you support, you might consider building a one-way hash of the credit card number ("pseudo-unique ID"). Some payment solutions actually do return a unique "payer ID", which could be perfect -- assuming that you get something from all the payment services you support.
I would assign a unique Customer ID to save the data, and then on future purchases that the same anonymous purchaser makes you could look to see if the same email address and/or first line of the address and post code already exists. If you ask for a phone number, compare that. Basically you need something fairly unique whilst getting rid of possible errors (eg. only looking at first line of the address - it's very likely that there is more than one 123 Main Street! But there will be only one 123 Main Street with post code ABC123).
Once you know this, you could automatically create them an account - sending the customer an email saying that you've noticed that they purchased previously, and to save them time use this email address and this automatically generated password. When they login for the first time, do a quick security check (maybe value of last invoice), then let them check their details. You could even do this during the checkout process. I think by showing that you can save them time by doing it automatically could be a bonus.
If you don't want to do this, then it's possible to set a cookie, though you'd have to warn the user if you are trading from within the EU (cookie laws).
The problem with someone having different email address and postal address, could be that they order for business, then they could order for personal use (hard to say as we don't know what you're selling).
Ofcourse you can track the sale session by using cookies. but Also register anonymous users to your site but don't let them realize that they are filling any registration form .Let them follow the sale process and at the end of the sale process generate a unique customer id and email them and also display that notification on the site after they complete their sale and make them login into the site by just entering their customer id.
I usually use the user IP, I create an account with just an ID and his IP address. When he registers, I just update his record. Other things than IP could (and should) be used too, like creating a random token to put in a cookie to bypass any session system in use so you can make it last longer for example.
Now, in the application, you have to make your user class able to "identify" your users with either this IP/token, a real session or any other login system you may have in place.
Mmmm ... we generate a uniq ID for guest users -- a hash-value or uuid for the username and store this one in the basket table. You cold store this also in the customer table, if you don't mind cluttering your database with such data. The uuid is stored in a cookie in the customers browser, until he checks out the basket. The cookie thing is also nice for assigning the anonymous account (and the content of it's basket) to a valid account, if the user decided to register later on / before checking out the basket.
I would create a unique customer ID, and store it on the user's machine as a cookie. This should decrease the number of users with multiple customer IDs.
But in all seriousness, as long as your number of ids isn't getting into the hundreds of thousands (and congrats if it is!), it's not going to hurt your database as long as you have proper indexes on the customer id column.
If you had id=0 for each customer wouldn't you have just as many rows though? I think that's inescapable if you want to keep all the data, right? A zero id might cause your index extra problems too.
The way I do it is : Not at all.
Simply put, let people pay through paypal or whatever you put as payment solution and get the data from there, automatically create the user and the order after the payment is processed using the provided API.
At that point you have all the information you need and can definitely store just enough for your statistics / e-spam marketing.
Keep it simple, require NOTHING, not even people to enter a customer id or an e-mail, and they'll all love it.
Doing that I still have every bit of information I could be interested in and the user experience is as fast/easy as can be.

What is common practice for handling backend data on eCommerce Confirm Order Page?

I'm seeking some guidance from people with experience in building ecommerce sites. This is actually my first time integrating with a payment gateway.
My implementation is actually a very basic booking system, where user places selects a date and number of tickets to book, clicks checkout and comes to a order confirmation screen, and then upon clicking submit again, user is brought to 3rd party payment gateway.
The 3rd party payment gateway url expects a post submission, containing a few mandatory fields for their api, one of which is a orderID to identify the order.
This is what I'm doing:
Unique order is generated when the ticket booking page is loaded.
User chooses what date he want, # of tickets, and clicks submit.
Data is validated, and then saved to a bookings table in db, while the user is brought to the confirmation page, presenting him/her with the details they have chosen and the price.
User clicks checkout, and the form is submitted to the 3rd party payment gateway url, user is brought to their page as well to complete payment.
Payment is completed, user is brought to our success page, payment gateway also posts details of transaction to a url of our choice which captures the transaction details, and saves it into a orders database.
So is that feasible ? My questions are:
Should unique order ID be generated as soon as ticket booking page is loaded ?
Should I have a booking database that saves bookings on the confirmation page ? What is user never clicks submit, then i'd eventually have a long list of records.. of course we could create some functionality to clean up the table, but is this common practice ?
Should I have a temporary booking database as mentioned above, as well as a completed transaction database that only captures transaction details from the payment gateway ? (Regardless of successful/failed)
Q1. Should unique order ID be generated as soon as ticket booking page is loaded ?
Ans: No, you should not do it at the time of load. Rather, should do it when the final submit is made for the 3rd Party payment gateway.
Q2. Should I have a booking database that saves bookings on the confirmation page ? What is user never clicks submit, then i'd eventually have a long list of records.. of course we could create some functionality to clean up the table, but is this common practice ?
Ans: Submit the form to your php script and make entry in the database only after submit is clicked. Then you can submit the form to the 3rd party from your php script once the enty has been made into your database.
Q3. Should I have a temporary booking database as mentioned above, as well as a completed transaction database that only captures transaction details from the payment gateway ? (Regardless of successful/failed)
Ans: Not required if followed what mentioned in answer for q2 above.
Hope this helps.

Data integrity when data is stored on our site and the user is taken to PayPal and back?

One of the web applications I recently developed works like this:
User picks a subscription level
User enters various custom/personal data on the site as well as picking out certain options
User confirms their data
The system stores this data in an array with a flag set specifying that the data is incomplete
The user is directed to PayPal to pay
PayPal makes an IPN request and we grab the row ID containing their information and complete the rest of the fields, effectively completing the process.
Now, obviously there are a few problems with this approach.
1. These rows are created whenever a user visits the form and can quickly add up
I solved this issue by adding a last_touched column which is a timestamp, and I routinely delete records older than 48 hours (more than enough time to complete a PayPal transaction).
2. Because of the above, it's possible that a user could checkout successfully with PayPal and there is no row in the database
I transmit the essential information such as the ID of the subscription package with the PayPal custom field, and if the row doesn't exist when I'm doing my IPN request, I fill in the blanks using the data supplied to PayPal and from the custom field.
3. The username the user entered could theoretically be taken by the time they checkout
I've solved this by checking to see if the username is taken and if it is, I add a number to it and keep incrementing the number until I get an available username.
I'm not sure if this is the best way to handle the given situations or if there is a better alternative (Not involving PayPal Payments Pro). At which point would the potential issues with a system like this outweigh the cost of PayPal Payments Pro?
Your best bet is to store all account information on your database as if the user created the account before sending them to PayPal.
So store everything including the username before allowing them to proceed to the checkout. This enables you to validate their information and username before they go to PayPal. Then you cache it all for 48 hours just to make sure they don't lose the username while checking out. You could also take advantage of PHP's session support to track the user if they happen to come back the next day to make the purchase. As long as they didn't clear their cookies/cache and your session lifetime hasn't expired the session server-side, they should be able to resume the session right where they left off and go straight to PayPal.
I would still send all vital data to PayPal just in case the user somehow manages to sit on PayPal's payment page for a week and then decides to put in CC info.
You could also use this system to "check" if the user has already started paying. Perhaps ask them to enter an email address first. Associate all data to that email and the user's IP address ($_SERVER['REMOTE_ADDR']). If you don't have session concurrency for a user, but they enter an email address already in the database. Check their IP (and maybe even browser too if you want to be really anal about it) and if it's a match, tell the user "looks like you started checking out before and never finished. want to continue?" and let them pick up where they left off. Obviously don't store any sensitive information this way, and only cache it in the temp table for paypal stuff so it only lasts for 2 days at best.
This way the user can click "Yes" and they don't have to choose their subscription again and go through all that picking/deciding a second time. If the user says "No, I'd like to start over" then just delete the row in the temp table and make a new one for them.

Categories