xiconsulting2 Posted July 15, 2010 Share Posted July 15, 2010 (edited) I tried to enter this in tips and tricks, but I guess it would have to be moved if deemed helpful. A while back I had looked for something to do an external check on the promo code database in order to integrate it with an external (API) based form, and did not really have any luck. So, this code I am posting does work - but do keep in mind the comments, code structure, and everything does work, but is not optimized fully - the actual version we converted to an API function and integrated with XAJAX and JQuery on the front end. Anyway, I figured that if I needed to find something like this and it was not available, that I would provide my previous script since I am sure someone else has looked for it before. I would release the XAJAX API version, but I am unable to publicly release it (not because it was very difficult, but because my client agreement does not allow me to release any code that is actually in use). There are more efficient ways of doing the checks which we implemented in the API version, but again I just cannot release that code at this time, and I am sure the WHMCS developers have already created this possibility for future API versions - but for now, it does work. Anyway, here you go - again, unrefined but it is a way to check promo code validity (expiration, product type, and billing cycle only) and return its values in an array. I do not have much time to assist in anything, but if you have a small question I would probably be happy to HELP (not give beginner PHP lessons). I am posting this to help others LEARN or at least take some initiative to learn - I did take about an hour or so to comment the code before this post, so it should be pretty self explanatory. I have also attached a text file, if you want to test this on your server (has to reside on your whmcs server), just rename to *.php and be sure to edit the form drop down product id's, and also the db values and it should be good to go. <?php /** * @author Amir W Husain * @license You are free to use this code, but we are not responsible if it destroys your business, your life, your car, or anything else. This script does not write against your database, it only reads it - so it is unlikely to do any damage. But as always, backup your database before doing any additional development. */ ## START OF THE CHECK PROMO CODE FUNCTION BELOW ## ## FUNCTION INPUT VARS EXPLANATION ## ## $promocode = the promocode entered on your order form ## $selectedplan = this would be the id of the plan that the user has chosen ## $selectedcycle = this is the billing cycle selected - passed as Monthly, Annually, etc. Our services only offer monthly ## and annual billing so if you offer other forms of billing you are on your own. ## Note: You could add additional checks here, these just happen to be the only ones that currently matter for what we do with promocodes. ## RESPONSE EXPLANATION ## ## The below function always returns an array called $pr and will always ## return in the array $pr['valid'] which will equal either 0 for false ## and 1 for true - and $pr['reason'] which will explain the reason why ## the code was not accepted. On acceptance this value is still sent back, ## its just blank. function checkPromo($promocode,$selectedplan,$selectedcycle) { /** WHMCS database connection information. * This is not really where the DB login information comes from in our live script, but its good for a quick and easy test. */ $dbhost = "localhost"; //usually unchanged $dbname = "database_1"; //enter your whmcs database name here $dbuser = "root"; //enter your database username here $dbpass = "rootpass"; //enter your password here /** * ESTABLISH DATABASE CONNECTION - This would usually be done outside of the function but again we are doing it this way for simplicity) */ $con = mysql_connect("$dbhost", "$dbuser", "$dbpass"); if ($con) { mysql_select_db("$dbname", $con); } else { die("Could not connect to database"); } /** * CREATE SHORT VARIABLES - The below is totally not neccessary, just shortening the values from the function to be shorter */ $pc = $promocode; $plannum = $selectedplan; // 4, 6, 8 in our case $bc = $selectedcycle; // Annually or Monthly /** * CHECK DATABASE - for the existence of entered promo code */ $rsd = mysql_query("select * from tblpromotions where code='$pc'"); $pcexist = mysql_num_rows($rsd); // this returns 0 if not exist if ($pcexist=="0") // the promo code does not exist in the table { // build response array with minimum values $pr['promocode'] = $pc; $pr['valid'] = 0; $pr['reason'] = 'Promo code not found.'; // oh well, at least it was quick! return the array return $pr; } elseif ($pcexist!="0") // the code exists, so get the rest of the fields from the database relating to that code { // FYI, we are only retreiving the fields we are actually using so if you have other fields in the whmcs promotions table that you use, // you'll need to code those functions. If you do decide to do this, its a good idea to think logically, the order at which the validation // is done is very important (for example it is not worth checking the rest of the values if the code is expired...so we check that first, // and so on to limit the response time to the user and limit unneccessary server processing ) $query = "SELECT type, value, cycles, appliesto, expirationdate, maxuses, uses FROM tblpromotions WHERE code='$pc'"; $result = mysql_query($query); // build variables from the returned db array while ($row = mysql_fetch_array($result, MYSQL_ASSOC)) { // date functions (these arent returned from the db, but from the server to determine validity) $thedate = date("Y-m-d"); $todaysdate = strtotime($thedate); $type = $row['type']; // We only provide percentage discounts, but you could used fixed values in your script by adding additional logic $value = $row['value']; // The value of the code $cycles = $row['cycles']; // The billing cycles that the code applies to $appliesto = $row['appliesto']; // The product types the code applies to $expirationdate = $row['expirationdate']; // The expiration date of the code, we assume that if the exp date is 0000-00-00 or empty, that there is no exp $expires = strtotime($expirationdate); // the expiration date formatted so we can check against todays date $maxuses = $row['maxuses']; // Maximum uses of the code $uses = $row['uses']; // How many times the code has been used } /** * NOW WE DO THE VALIDATION! */ ## 1. check if expired // ok promocode is not past expiry, so we continue // Add the promo code given to the array response so we know what was entered and can provide it back to the user - this value is given for all responses regardless of outcome. $pr['promocode'] = $pc; if ($expires >= $todaysdate OR $expirationdate == "0000-00-00") { ## 2. now check if valid for the chosen products and term // generate arrays for the billing cycles and for the valid products $cyclesarray = explode(',', $cycles); // outputs the valid cycles which are separated by commas into an array for processing $productsarray = explode(',', $appliesto); // outputs the products which are separated by commas into an array for processing // just add these to the response right now since they will not change from this point on and no point in adding them in the if statements $pr['validproducts'] = $productsarray; // products that this code is valid for $pr['validcycles'] = $cyclesarray; // provide the cycles that this code is valid for so that the user could try changing their plan to one it would work on if (in_array($bc, $cyclesarray) OR $cycles == "") { // ok, promocode is valid for the billing cycle selected ## 3. continue to check if valid for specified product if (in_array($plannum, $productsarray)) { // ok, code is valid for billing cycle and product selected ## 4. Check if code has passed its maximum number of uses // do math to subtract used number from maximum number to see if this code can be used again $usesleft = $maxuses - $uses; if ($usesleft > 0) { ## GREAT! Product code has some free uses left, is not expired, is valid for the selected billing cycle, and is valid for the selected product ## congrats, our code is valid and we can notify the user and apply their discount // this is the only VALID response we give to users, since a passcode can only be accepted or rejected and there is no inbetween $pr['valid'] = 1; // promo is valid $pr['errorcode'] = 0; // there is no error code $pr['discounttype'] = $type; // percent or fixed? $pr['discountvalue'] = $value; // the value of the promo code (use the discounttype response to create logic for % or $ calculation) $pr['expirationdate'] = $expirationdate; $pr['maxuses'] = $maxuses; // maximum number of uses $pr['usesleft'] = $usesleft; // number of uses left before code is no longer valid $pr['uses'] = $uses; // number of times code was used return $pr; } else ## CHECK 4 FAILED because the maximum code uses has passed { $pr['valid'] = 0; $pr['errorcode'] = 4; $pr['reason'] = 'Maximum promo code use has been reached'; $pr['expirationdate'] = $expirationdate; $pr['maxuses'] = $maxuses; $pr['usesleft'] = $usesleft; $pr['uses'] = $uses; return $pr; } } else ## CHECK 3 FAILED because the code is not valid for the selected product that the user has chosen { $pr['valid'] = 0; $pr['errorcode'] = 3; $pr['reason'] = 'Not valid for selected product type'; $pr['expirationdate'] = $expirationdate; return $pr; } } else ## CHECK 2 FAILED because the code is not valid for the billing cycle the user has chosen { $pr['valid'] = 0; $pr['errorcode'] = 2; $pr['reason'] = 'Not valid for selected billing cycle'; $pr['expirationdate'] = $expirationdate; return $pr; } } elseif ($expires <= $todaysdate) ## CHECK 1 FAILED because promo code has expired, or your servers date and time is screwed up { $pr['valid'] = 0; $pr['errorcode'] = 1; $pr['reason'] = 'Expired'; $pr['expirationdate'] = $expirationdate; return $pr; } else ## CHECK 1 FAILED because something went wrong when checking if code was expired, could be that the date is not being calculated correctly { $pr['valid'] = 0; $pr['errorcode'] = 98; $pr['reason'] = 'Unknown Error While Determining Expiration'; $pr['expirationdate'] = $expirationdate; return $pr; } } else ## CHECK 0 FAILED because something went wrong when checking for the promo code, but we don't know what so we just respond with invalid { $pr['valid'] = 0; $pr['errorcode'] = 99; $pr['reason'] = 'Unknown error when checking for promo code validity, please try again.'; return $pr; } } ?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <title>WHMCS Promo Code Test</title> <style> html,body{font-family:Arial, Helvetica, sans-serif;} label{display:block;padding:5px;width:200px;font-size:10px;margin-bottom:10px;} input{width:100%;padding:5px;} select{width:100%;padding:5px;} button{padding:10px;font-family:Arial, Helvetica, sans-serif;} .error{padding:10px;margin:5px;font-size:16px;background-color:#C00;color:#fff;} .success{padding:10px;margin:5px;font-size:16px;background-color:#9C0;color:#fff;} </style> </head> <body> <form id="pctestform" name="pctestform" method="post" action="<?php echo $PHP_SELF; ?>"> <label>Promo Code <input type="text" name="promocode" id="promocode" tabindex="1" /> </label> <label>Product Type <select id="plan" name="plan"> <!-- Be sure to change these to your product codes, optionally you could do make a php script to just populate dynamically --> <option value="4">Advanced Plan</option> <option value="6">Premium Plan</option> <option value="8">Superior Plan</option> </select> </label> <label>Billing Cycle <select id="cycle" name="cycle"> <!-- Only Annually and Monthly billing cycles are checked, if you have others that is OK, as long as the code is also valid for the following as well --> <option value="Annually">Billed Annually</option> <option value="Monthly">Billed Monthly</option> </select> </label> <button name="submit" type="submit">Validate Promo Code</button> </form> <hr /> <?php ## HOW TO USE SAMPLE ## # Don't actually use this in your script, its just for testing to show you how to call the # function we will use just use POST variables, these are not going to be sanitized or # anything so again DO NOT USE POST in production without some kind of validation. if($_POST){ if($_POST["promocode"]!=""){ $enteredpromo = $_POST["promocode"]; $plannumber = $_POST["plan"]; $plancycle = $_POST["cycle"]; // Call the function and get the response. $response = checkPromo($enteredpromo,$plannumber,$plancycle); // Print the resulting array print "<h1>Response Output Array</h1><pre>"; var_dump($response); print "</pre>"; // Print an individual value for the array, for example if the code is valid or not, show something print "<h1>User Friendly Response Example:</h1>"; if($response["valid"]!=1){ // show error if code is not valid echo '<p class="error"><strong>Sorry!</strong> Promocode' . $response["promocode"] . ' is not a valid promo code for the following reason: ' . $response["reason"] . '</p>'; } else { // show if code is valid - these variables don't have to be printed, but could be used in your script or could update your order form using javascript (which is what we did with XAJAX) echo '<p class="success"><strong>Congrats!</strong> Promocode ' . $response["promocode"] . ' was accepted! You are now saving ' . $response["discounttype"] . $response["value"] . ' on your order!</p>'; } }else{ echo '<p class="error"><strong>Sorry!</strong> You have to at least enter a promo code to check!</p>'; } } ####### END EXAMPLE ######## ?> </body> </html> whmcs-promo-code-check.txt Edited July 15, 2010 by xiconsulting2 Link to comment Share on other sites More sharing options...
xiconsulting2 Posted July 15, 2010 Author Share Posted July 15, 2010 Oh, just fyi, I fixed it in the post - but not in the attached version, if you use the attached text file be sure to replace the following: $rsd = mysql_query("select * from tblpromotions where code='$pc'"); $msg = mysql_num_rows($rsd); // this returns 0 if not exist with: $rsd = mysql_query("select * from tblpromotions where code='$pc'"); $pcexist = mysql_num_rows($rsd); // this returns 0 if not exist Link to comment Share on other sites More sharing options...
drosendo Posted January 26, 2018 Share Posted January 26, 2018 Hi, Any update on this code? I have a code of mine to try and fit all possible solutions, must read to understand... but maybe we can exchange things. function runPromos() { global $whmcsis_cart, $whmcs; $promo = $_POST["promo"]; $postfields["code"] = $promo; $promotions = $whmcs->getpromotions($postfields); $active_promo = $promotions->promotions->promotion[0]; $thedate = date("Y-m-d"); $todaysdate = strtotime($thedate); $expirationdate = $active_promo->expirationdate; $expires = strtotime($expirationdate); if ($expires < $todaysdate && $expirationdate != "0000-00-00") { header("Content-type: application/json"); echo json_encode(false); die(); } if ($active_promo == '') { header("Content-type: application/json"); echo json_encode(false); die(); } $cart_data = $whmcsis_cart->getItems(); if ($cart_data['promocode'] != '') { header("Content-type: application/json"); echo json_encode(false); die(); } $whmcsis_cart->addItem('promocode', $promo); $str_ids = explode(',', $active_promo->appliesto); $str_cycle = explode(',', strtolower($active_promo->cycles)); $cart_data = $whmcsis_cart->getItems(); $cart = $cart_data['cart']; $x = 0; $promo_option = array(); foreach ($cart as $group => $option) { foreach ($option as $key => $item) { $duration = $item['duration']; if ($item['duration'] == 'semiannually') $duration = 'semi-annually'; switch ($group) { case 'domains': $tld = explode('.', $item['name'], 2); if ($item['price'] > 0) { if (in_array('D.' . $tld[1], $str_ids) && in_array($item['duration'] . 'years', $str_cycle)) { if (isset($item['original_price']) && $item['original_price'] != '') $price = $item['original_price']; else $price = $item['price']; $new_price = $whmcs->promotionType($active_promo, $price); if ($price < 0) $price = 0; if ($new_price < 0) $new_price = 0; $item['original_price'] = $price; $item['price'] = $new_price; $item['promo'] = true; $promo_option['data'][$x]['group'] = $group; $promo_option['data'][$x]['data'] = $item; $x += 1; } else { if (isset($item['original_price']) && $item['original_price'] != '') $price = $item['original_price']; else $price = $item['price']; $item['promo'] = false; $item['original_price'] = $price; } $whmcsis_cart->updateItemQuantity('cart', $group, $key, $item); $whmcsis_cart->addItem('promocode', $promo); } break; case 'dedicated': case 'cloud': case 'housing': if (in_array($item["id"], $str_ids) && in_array($duration, $str_cycle)) { if (isset($item['original_price']) && $item['original_price'] != '') $price = $item['original_price']; else $price = $item['prod_price']; $new_price = $whmcs->promotionType($active_promo, $price); if ($price < 0) $price = 0; if ($new_price < 0) $new_price = 0; $item['original_price'] = $price; $item['prod_price'] = $new_price; $item['price'] = $new_price; $item['promo'] = true; $promo_option['data'][$x]['group'] = $group; $promo_option['data'][$x]['data'] = $item; $promo_option['data'][$x]['key'] = $key; $x += 1; } else { if (isset($item['original_price']) && $item['original_price'] != '') $price = $item['original_price']; else $price = $item['prod_price']; $item['promo'] = false; $item['price'] = $price; $item['original_price'] = $price; } $whmcsis_cart->updateItemQuantity('cart', $group, $key, $item); $whmcsis_cart->addItem('promocode', $promo); break; case 'ssl': foreach ($item['configoption'] as $kssl => $dssl) { $ssl_period = $dssl['ssl_period'] . 'years'; } if (in_array($item["id"], $str_ids) && in_array($ssl_period, $str_cycle)) { if ($item['original_price']) $price = $item['original_price']; else $price = $item['price']; $new_price = $whmcs->promotionType($active_promo, $price); if ($price < 0) $price = 0; if ($new_price < 0) $new_price = 0; //pre($new_price); //pre($item); $item['original_price'] = $price; $item['prod_price'] = $new_price; $item['promo'] = true; /* ADICIONAR EXTRA AO PRECO */ /* if ($item['configoption']) { foreach ($item['configoption'] as $k => $v) { if ($v['value']) $new_price = $new_price + (($whmcs->calc_extras_cost($v['price'], $item['duration']))); else unset($data['configoption'][$k]); } } */ $item['price'] = $new_price + $item['domain']['price']; $promo_option['data'][$x]['group'] = $group; $promo_option['data'][$x]['data'] = $item; $promo_option['data'][$x]['key'] = $key; $x += 1; } else { $price = $item['prod_price']; if ($price == '') $price = $item['price']; /* ADICIONAR EXTRA AO PRECO */ if ($item['configoption']) { foreach ($item['configoption'] as $k => $v) { if ($v['value']) $price = $price + (($whmcs->calc_extras_cost($v['price'], $item['duration']))); else unset($item['configoption'][$k]); } } $item['promo'] = false; $item['price'] = $price + $item['domain']['price']; $item['original_price'] = $price; $promo_option['data'][$x]['group'] = $group; $promo_option['data'][$x]['data'] = $item; $promo_option['data'][$x]['key'] = $key; $x += 1; } $whmcsis_cart->updateItemQuantity('cart', $group, $key, $item); $whmcsis_cart->addItem('promocode', $promo); break; case 'webstore': $tld = explode('.', $item['domain']['name'], 2); if ($item['domain']['price'] > 0) { if (in_array('D.' . $tld[1], $str_ids) && in_array($item['domain']['period'] . 'years', $str_cycle)) { if (isset($item['domain']['original_price']) && $item['domain']['original_price'] != '') $price = $item['domain']['original_price']; else $price = $item['domain']['price']; $new_price = $whmcs->promotionType($active_promo, $price); if ($price < 0) $price = 0; if ($new_price < 0) $new_price = 0; $item['domain']['original_price'] = $price; $item['domain']['price'] = $new_price; $item['domain']['promo'] = true; } else { if (isset($item['domain']['original_price']) && $item['domain']['original_price'] != '') $price = $item['domain']['original_price']; else $price = $item['domain']['price']; $item['domain']['promo'] = false; $item['domain']['original_price'] = $price; } } if (in_array($item["id"], $str_ids) && in_array($duration, $str_cycle)) { $price = $item['prod_price']; if ($price == '') $price = $item['price']; $new_price = $whmcs->promotionType($active_promo, $price); if ($price < 0) $price = 0; if ($new_price < 0) $new_price = 0; $item['original_price'] = $price; $item['prod_price'] = $new_price; $item['promo'] = true; /* ADICIONAR EXTRA AO PRECO */ if ($item['configoption']) { foreach ($item['configoption'] as $k => $v) { if ($v['value']) $new_price = $new_price + $value['value']; else unset($data['configoption'][$k]); } } if ($item['addons']) { foreach ($item['addons'] as $k => $v) { if ($v['value']) $new_price = $new_price + $v['price']; else unset($item['addons'][$k]); } } $item['price'] = $new_price + $item['domain']['price']; $promo_option['data'][$x]['group'] = $group; $promo_option['data'][$x]['data'] = $item; $promo_option['data'][$x]['key'] = $key; $x += 1; } else { $price = $item['prod_price']; if ($price == '') $price = $item['price']; /* ADICIONAR EXTRA AO PRECO */ if ($item['configoption']) { foreach ($item['configoption'] as $k => $v) { if ($v['value']) $price = $price + $value['value']; else unset($item['configoption'][$k]); } } if ($item['addons']) { foreach ($item['addons'] as $k => $v) { if ($v['value']) $price = $price + $v['price']; else unset($item['addons'][$k]); } } $item['promo'] = false; $item['price'] = $price + $item['domain']['price']; $item['original_price'] = $price; $promo_option['data'][$x]['group'] = $group; $promo_option['data'][$x]['data'] = $item; $promo_option['data'][$x]['key'] = $key; $x += 1; } $whmcsis_cart->updateItemQuantity('cart', $group, $key, $item); $whmcsis_cart->addItem('promocode', $promo); break; default: $tld = explode('.', $item['domain']['name'], 2); if ($item['domain']['price'] > 0) { if (in_array('D.' . $tld[1], $str_ids) && in_array($item['domain']['period'] . 'years', $str_cycle)) { if (isset($item['domain']['original_price']) && $item['domain']['original_price'] != '') $price = $item['domain']['original_price']; else $price = $item['domain']['price']; $new_price = $whmcs->promotionType($active_promo, $price); if ($price < 0) $price = 0; if ($new_price < 0) $new_price = 0; $item['domain']['original_price'] = $price; $item['domain']['price'] = $new_price; $item['domain']['promo'] = true; } else { if (isset($item['domain']['original_price']) && $item['domain']['original_price'] != '') $price = $item['domain']['original_price']; else $price = $item['domain']['price']; $item['domain']['promo'] = false; $item['domain']['original_price'] = $price; } } if (in_array($item["id"], $str_ids) && in_array($duration, $str_cycle)) { $price = $item['prod_price']; if ($price == '') $price = $item['price']; $new_price = $whmcs->promotionType($active_promo, $price); if ($price < 0) $price = 0; if ($new_price < 0) $new_price = 0; $item['original_price'] = $price; $item['prod_price'] = $new_price; $item['promo'] = true; /* ADICIONAR EXTRA AO PRECO */ if ($item['configoption']) { foreach ($item['configoption'] as $k => $v) { if ($v['value']) $new_price = $new_price + (($whmcs->calc_extras_cost($v['price'], $item['duration'])) * $value['value']); else unset($data['configoption'][$k]); } } if ($item['addons']) { foreach ($item['addons'] as $k => $v) { if ($v['value']) $new_price = $new_price + $v['price']; else unset($item['addons'][$k]); } } $item['price'] = $new_price + $item['domain']['price']; $promo_option['data'][$x]['group'] = $group; $promo_option['data'][$x]['data'] = $item; $promo_option['data'][$x]['key'] = $key; $x += 1; } else { $price = $item['prod_price']; if ($price == '') $price = $item['price']; /* ADICIONAR EXTRA AO PRECO */ if ($item['configoption']) { foreach ($item['configoption'] as $k => $v) { if ($v['value']) $price = $price + (($whmcs->calc_extras_cost($v['price'], $item['duration'])) * $v['value']); else unset($item['configoption'][$k]); } } if ($item['addons']) { foreach ($item['addons'] as $k => $v) { if ($v['value']) $price = $price + $v['price']; else unset($item['addons'][$k]); } } $item['promo'] = false; $item['price'] = $price + $item['domain']['price']; $item['original_price'] = $price; $promo_option['data'][$x]['group'] = $group; $promo_option['data'][$x]['data'] = $item; $promo_option['data'][$x]['key'] = $key; $x += 1; } $whmcsis_cart->updateItemQuantity('cart', $group, $key, $item); $whmcsis_cart->addItem('promocode', $promo); break; } } } $promo_option['promocode'] = $promo; $whmcsis_cart->save(); header("Content-type: application/json"); echo json_encode($promo_option); die(); } Link to comment Share on other sites More sharing options...
Recommended Posts