Solved

How does this login script produce the view that you see after everything is validated (Part II)?

Posted on 2016-08-18
1
79 Views
Last Modified: 2016-08-18
Here's the login page:

login screen
...and here's the code behind it:

<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');

class PatientPortal extends MY_Controller {

	private $debug = false; 		 	//Setting this to true will trigger a krumo of the session in a small console window at the bottom of your screen.
	private $payment_threshold = 30; 	// The minimum payment we will take through the portal

	public function index(){
		//$this->pay();
		//$this->login();
	}








	/** Login Function ----------------------------------------------------------------------------------------------------------
		*
		*
		*	This endpoint serves the login form of the patient portal.
		*

			|	In the case that there is no session variable 'guarantor_session' set (and we're not accessing via an admin subdomain),
			|	this becomes the root endpoint

		*
		*	Posting in all of these variables will treat this as a login attempt and will try to validate the data:
		*		pin - The Statement Pin / Accountid associated with an account.
		*		lastfour - The last four digits of the guarantor OR patient associated with the account or with a charge
		*		year - The birth year of the guarantor OR patient associated with the account or with a charge
		*
		*	Sending in a pin variable in your access assumes that you've clicked this link from an email and will autopopulate and lock the statement pin field.
		*
		*
	-----------------------------------------------------------------------------------------------------------------------------*/

	public function login($pin = ''){
		//Start with client colors
		$h = explode('.',$_SERVER['HTTP_HOST']);
		$clientcode = $h[0];
		$client = Clients::getByCode($clientcode);
		$clientid = '-1';
        session_start();
		if($client) $clientid = $client['ClientID'];

		$_SESSION['colors'] = ClientPreferences::getClientColors($clientid);

		//$this->setSessionData($accountid);
		//if(isset($_SESSION['guarantor_session'])) redirect('/patientportal/pay'); //On the offchance this is accessed directly with a session, reroute to pay.
		$lockpin = (isset($_REQUEST['lockpin']) && $_REQUEST['lockpin'] === "0")?false:($pin?true:false);
		$pin = $pin?$pin:(isset($_REQUEST['pin'])? $_REQUEST['pin'] : false);
		$lastfour = isset($_REQUEST['lastfour'])? $_REQUEST['lastfour'] : false;
		$year = isset($_REQUEST['year'])? $_REQUEST['year'] : false;
		$redirect = isset($_REQUEST['uri'])?$_REQUEST['uri']:'/';

		$data = array(
			'lockpin' => $lockpin,
			'pin' => $pin,
			'lastfour' => $lastfour,
			'year' => $year,
			'redirect' => $redirect,
			'debug' => $this->debug,
            'new_statement' => ClientPreferences::getClientPreference($clientid, 'NewStatements')
			);

		if($pin && $lastfour && $year){
			//If these variables are all set, assume validation attempt.

			//1 -> get accountid from pin
			if(strpos($pin,'T') !==false || strpos($pin,'t') !==false){
				$statementid = ltrim($pin,"Tt");
				$_SESSION['statementid'] = $statementid;
				$accountid = Accounts::getAccountidFromStatementid($statementid);
			}else{
				$accountid = $pin;
			}

			//2 -> use accountid to get accountdetails
			$accounts = Accounts::getAccountInfoFromPin($accountid);
			//krumo($accounts); exit();
			$ssns = array();
			$dobs = array();

			if($accounts)foreach($accounts as $account){
				//NOTE the getAccountInfoFromPin function returns 3 records, trying to coalesce
				//the information from Patient, Claim, and txn tables.
				//I'm organizing the data here so I can run an in_array on the fields.
				if($account['SSN'] && !in_array($account['SSN'], $ssns)) array_push($ssns, $account['SSN']);
				if($account['PatientDOB'] && !in_array($account['PatientDOB'], $dobs)) array_push($dobs, substr($account['PatientDOB'], 0,4));
			}
	  		//$details = Accounts::getDetails($accountid); <-- Might not need this
	  		//3 -> Check to see if account CAN be verified
	  		if($accounts && count($ssns) && count($dobs)){

	  			//4 -> Check to make sure our data = the provided data
	  			if(in_array($lastfour, $ssns)  && in_array($year, $dobs)){

	  				//Validated!!!
	  				
	  				//Guarantor Session
	  				$this->setSessionData($accountid);
	  				$data['clientcode'] = $_SESSION['guarantor_session']['clientcode'];

	  				//Are we on the right domain?
	  				$host = explode('.',$_SERVER['SERVER_NAME']);
	  				$sub = $host[0];

	  				if(strtolower($sub) == strtolower($data['clientcode']) || base_url() == 'https://dig.local/' || base_url() == 'https://localhost:8080/' || base_url() == 'https://digdev.patientfocus.com/' || base_url() == 'https://dig2.patientfocus.com/' || base_url() == 'https://staging.patientfocus.com/'){
	  					//This is the correct domain.
		              	redirect($redirect);

	  				} else {
	  					//Destroy existing session.
	  					unset($_SESSION['guarantor_session']);
						unset($_SESSION['userdata']);
						unset($_SESSION['roles']);
						unset($_SESSION['rights']);
						unset($_SESSION['colors']);
						unset($_SESSION['statementid']);
	  					session_destroy();

	  					//Post into the correct subdomain.
	  					$this->load->view('patientportal/subdomaingate',$data);
	  				}

	  				
	  				//exit();
	  			}

	  		} else if($accounts) {
	  			//Account cannot be verified, Give a specific call to action.
	  			$data['errorheader'] = 'Account Incomplete';
	  			$data['errormessage'] = 'There is not enough information in your account to verify your identity through the online portal. If you would like to access your account online, please <a class="cantlogin">let us know</a>, and one of our Patient Account Representatives will help you complete your account.';
	  		}

		}
		if($client){
			$data['clientcode'] = $clientcode;
			$data['clientname'] = $client['ClientName'];
		}
        session_write_close();
		$this->load->view('patientportal/login', $data);
	}







	/** Pay Function ----------------------------------------------------------------------------------------------------------
		*
		*
		*	This endpoint serves the ad hoc payment form of the patient portal.
		*

			|	In the case that there IS a session variable 'guarantor_session' set (and we're not accessing via an admin subdomain),
			|	this becomes the root endpoint

		*
		*	Posting in all of these variables will treat this as a payment attempt and will try to process the data:
		*
			REQUIRED (for any form processing)
		*
		*		paymentamount - This is either a dollar amount or a 'specialamount' flag, which then looks to the 'specialamount' manually entered field for the payment amount.
		*		specialamount - Should paymentamount = the string 'specialamount', this process pulls the value from the specialamount variable.
		*		email - the email address of the user, required for sending a receipt.
		*		cardorbank - Set to the string 'card' if this is a credit card process. Set to 'bank' if it's an echeck
		*
			REQUIRED FOR CREDIT CARD (if cardorbank = 'card')
		*		
		*		cardnum - The number on the front of your card. IF THIS BEGINS WITH A * then we process the payment off the stored BRIC if it is available
		*		cvcode - The 3-4 digit security code on the back of the card.
		*		cardname - The name on the front of the card
		*		cardmonth - the two digit card expiration month
		*
			REQUIRED FOR E CHECK (if cardorbank = 'bank')
		*		
		*		accountnum - the bank account number (in the case that this starts with *, use the associated bank BRIC.
		*		routingnumb - the routing number of the bank. If we're using a brick, Use the bric's associated routing number.
		*		accname - The name on the account.
		*
		*

			ON FAILED FORM PROCESSING,
		*		Reload the form view, populated where you left off, and provide an error that states the problem clearly.
		*
			ON SUCCESS,
		*		Load the payment success view.
		*
		*
	---------------------------------------------------------------------------------------------------------------------------*/


	public function pay($refreshdata = true){

		$data = $this->getData($refreshdata);

		if(isset($_REQUEST['paymentamount'])){

			//Process the payment
			$success = false;
			$amount = $_REQUEST['paymentamount'] == 'specialamount' ? str_replace('$', '', $_REQUEST['specialamount']) : $_REQUEST['paymentamount'];
			$amount = number_format($amount,2,'.','');
			$email = isset($_REQUEST['email'])? $_REQUEST['email'] : false;

			$createdby = $_SESSION['userdata']['id'];

			if($amount >= $data['minpayment']){
				if($amount <= $data['lefttopay']){	
					if($_REQUEST['cardorbank'] == "card"){
						$cardinfo = $data['cardinfo'];

						//Process as Credit Card
						$cardnum = isset($_REQUEST['cardnum'])? $_REQUEST['cardnum'] : false; //ACCOUNT FOR ************XXXX STYLE ENTRIES - IMPLYING TO USE THE CARD ON FILE.
						$bric = substr($cardnum,0,1) == '*' && $cardinfo?$cardinfo['bric']:false;
						$cv = isset($_REQUEST['cvcode'])? $_REQUEST['cvcode'] : false;
						$cardname = $bric?$cardinfo['cardname']:(isset($_REQUEST['name'])? $_REQUEST['name'] : false);
						$cardmonth = isset($_REQUEST['cardmonth'])? $_REQUEST['cardmonth'] : false;
						$cardyear = isset($_REQUEST['cardyear'])? $_REQUEST['cardyear'] : false;
						$cardexp = $this->getEPXExpirationString($cardmonth, $cardyear);					

							//Ensure that the pieces are all available.
							if( ($bric || $cardnum) && $cv && $amount && $cardname && $cardexp && $data['accountid'] && $email){
								if(!$bric || ($cardexp == $cardinfo['cardexp'] && $cv == $cardinfo['cardcv'])){

									if(filter_var($email,FILTER_VALIDATE_EMAIL)){
										if(strtolower($email) != strtolower($data['email'])) Accounts::update($data['accountid'], array(array('field'=>'email','newvalue'=>$email)));

										//PROCESS THE EPX TRANSACTION AND TURN THE RESULTING XML INTO AN ARRAY
										$xmlstr = '';

										if($bric){
											//PROCESS FROM BRIC
											$xmlstr = $this->epx->processCreditCardBRIC($bric, $cv, $amount, $cardname, $cardexp,array('AccountID'=>$data['accountid']),$data['dbanbr']);
										} else {
											//PROCESS FROM CARD NUMBER
											$xmlstr = $this->epx->processCreditCard($cardnum, $cv, $amount, $cardname, $cardexp,array('AccountID'=>$data['accountid']),$data['dbanbr'],$data['address']);
										}
										$xmlobj = simplexml_load_string($xmlstr);
										$xmlarr = array();
										if($xmlobj) foreach($xmlobj->FIELDS->FIELD as $field){
							              $xmlarr[(string)$field->attributes()->KEY] = (string)$field;
							            }
							           	
							           	if(isset($xmlarr['AUTH_RESP']) && $xmlarr['AUTH_RESP'] == '00'){
							           		/**
							           			Successfully paid on card
							           		**/
							           		//This is for the paymentmethodcode.
							           		$this->load->library('CreditCard');
							           		$card = $bric?array('abbr'=>$cardinfo['cardabbr'],'name' => 'card'):$this->creditcard->cardNameFromNumber($cardnum);
							           		$cardfour = substr($cardnum, strlen($cardnum)-4);

							           		$description = 'Credit card ending in ' . $cardfour;

							           		//Create the paymentpending entry.
							           		$paymentpending = PaymentPendings::addPaymentPending(date('Y-m-d H:i:s'), $xmlarr['AMOUNT'],$card['abbr'], $data['accountid'], $data['patientid'], 'PR', 'PT', $createdby, $xmlarr['AUTH_GUID'], $xmlarr['AUTH_CODE'],$xmlarr['AUTH_RESP'],$description);
								            if($paymentpending){
								            	$success = true;
								            	$data['successcardtype'] = $card['name'];
								            	$data['successemail'] = $email;
								            	$data['successcardlastfour'] = $cardfour;
								            	$data['confirmation'] = $paymentpending['PaymentPendingID'];
								            }

							           	} else {
							           		//Error -> epx response
							           		$data['errorcode'] = isset($xmlarr['AUTH_RESP'])? $xmlarr['AUTH_RESP'] : 'PF4';
						           			$data['errormsg'] = isset($xmlarr['AUTH_RESP_TEXT'])?ucfirst($xmlarr['AUTH_RESP_TEXT']):'No response from EPX.';

							           	}
							        } else {
							        	$data['errorcode'] = 'PF8';
										$data['errormsg'] = 'Email invalid.';
							        }
							    } else {
					           		//Error -> CARDEXP DOESN'T MATCH ONE ON FILE OR CCV DOESN'T MATCH
					           		$data['errorcode'] = 'PF5';
				           			$data['errormsg'] = 'Card validation mismatch.';

					           	}
							} else {
								//Error Incomplete Form.
								$data['errorcode'] = 'PF3';
								$data['errormsg'] = 'Payment form incomplete.';
							}

						//$this->epx->processCreditcard();

					} else if ($_REQUEST['cardorbank'] == "bank"){
						$bankinfo = $data['bankinfo'];

						//Process as E Check
						$accnum = isset($_REQUEST['accountnum'])? $_REQUEST['accountnum'] : false; //ACCOUNT FOR ************XXXX STYLE ENTRIES - IMPLYING TO USE THE CARD ON FILE.
						$bric = substr($accnum,0,1) == '*' && $bankinfo?$bankinfo['bric']:false;
						$name = $bric?$bankinfo['accname']:(isset($_REQUEST['account_name'])? $_REQUEST['account_name'] : false);
						$routing = $bric?$bankinfo['accrouting']:(isset($_REQUEST['routingnumb'])? $_REQUEST['routingnumb'] : false);
						//$bankname = $bric?$bankinfo['accbankname']:(isset($_REQUEST['cardmonth'])? $_REQUEST['cardmonth'] : false);

						//Ensure that the pieces are all available.
						if(($bric || $accnum) && $routing && $amount && $name && $data['accountid'] && $email){
							if(filter_var($email,FILTER_VALIDATE_EMAIL)){
								if(strtolower($email) != strtolower($data['email'])) Accounts::update($data['accountid'], array(array('field'=>'email','newvalue'=>$email)));
								//PROCESS THE EPX TRANSACTION AND TURN THE RESULTING XML INTO AN ARRAY
								$xmlstr = '';
								if($bric){
									//PROCESS FROM BRIC
									$xmlstr = $this->epx->processCheckBRIC($bric, $routing, $amount, $name, array('AccountID'=>$data['accountid']),$data['dbanbr']);
								} else {
									//PROCESS FROM ACC NUMBER
									$xmlstr = $this->epx->processCheck($accnum, $routing, $amount, $name, array('AccountID'=>$data['accountid']),$data['dbanbr'],$data['address']);
								}
								$xmlobj = simplexml_load_string($xmlstr);
								$xmlarr = array();
								if($xmlobj) foreach($xmlobj->FIELDS->FIELD as $field){
					              $xmlarr[(string)$field->attributes()->KEY] = (string)$field;
					            }
					           	
					           	if(isset($xmlarr['AUTH_RESP']) && $xmlarr['AUTH_RESP'] == '00'){
					           		/**
					           			Successfully paid from bank
					           		**/
					           		$description = 'Bank account ending in ' . substr($accnum,-4);
					           		//Create the paymentpending entry.
					           		$paymentpending = PaymentPendings::addPaymentPending(date('Y-m-d H:i:s'), $xmlarr['AMOUNT'],'EF', $data['accountid'], $data['patientid'], 'PR', 'PT', $createdby, $xmlarr['AUTH_GUID'], $xmlarr['AUTH_CODE'],$xmlarr['AUTH_RESP'], $description);
						            if($paymentpending){
						            	$success = true;
						            	$data['successcardtype'] = 'bank account';
						            	$data['successemail'] = $email;
						            	$data['successcardlastfour'] = substr($accnum,-4);
						            	$data['confirmation'] = $paymentpending['PaymentPendingID'];
						            }

					           	} else {
					           		//Error -> epx response
					           		$data['errorcode'] = isset($xmlarr['AUTH_RESP'])? $xmlarr['AUTH_RESP'] : 'PF4';
					           		$data['errormsg'] = isset($xmlarr['AUTH_RESP_TEXT'])?ucfirst($xmlarr['AUTH_RESP_TEXT']):'No response from EPX.';

					           	}
					        } else {
						        	$data['errorcode'] = 'PF8';
									$data['errormsg'] = 'Email invalid.';
						    }
						} else {
							//Error Incomplete Form.
							$data['errorcode'] = 'PF3';
							$data['errormsg'] = 'Payment form incomplete.';
						}

					} else {
						//Error as unrecognized type
						$data['errorcode'] = 'PF1';
						$data['errormsg'] = 'Could not process transaction type';
					}
				} else {

					//Error as Amount above Maximum
					$data['errorcode'] = 'PF2';
					$data['errormsg'] = 'Can\'t pay more than you owe.';
				}
			} else {

				//Error as Amount Below Minimum
				$data['errorcode'] = 'PF2';
				$data['errormsg'] = 'Amount below the minimum ' . $data['minpaymentformatted'] . ' payment.';
			}

			if($success){
				//On Success load the next view.
				$data['successamount'] = $amount;
				$data = array_merge($data, $this->getData());
				$this->load->library('Mandrill');

				$message['html'] = $this->load->view('email/receipt',$data,true);
				$message['text'] = "Thank you! Your payment of \$$amount was successfully charged to your $data[successcardtype] ending in $data[successcardlastfour]. Your confirmation number is $data[confirmation].";
				$message['subject'] = "Your payment has been received!";
				$message['from_email'] = 'noreply@patientfocus.com';
				$message['from_name'] = $data['clientname'];
				$message['to'][0] = array('email' => $email);

				$mandrill_response = $this->mandrill->sendemail($message);
				if($mandrill_response){

					$e['templateid'] = 0;
					$e['content'] = pfsql::scrub($message['html']);
					$e['email'] = pfsql::scrub($email);
					$e['systememail'] = $message['from_email'];
					$e['response'] = pfsql::scrub(json_encode($mandrill_response));
					$e['direction'] = 'outbound';
					$e['accountid'] = $data['accountid'];
					$data['receiptemailed'] = true;

					$f = Emails::create($e);

				} else $data['receiptemailed'] = false;

				//echo json_encode($mandrill_response); exit();


				$data['view'] = 'paymentsuccess';
			} else {
				//On Fail load same view.
				$data['view'] = 'makeapayment';
			}			

		} else if($data['lefttopay'] <= 0){
			$data['view'] = 'creditbalance';
		}else{
			$data['view'] = 'makeapayment';
		}

		$this->loadView($data);

	}

    protected function getEPXExpirationString($month, $year) {
        
        $exp = false;
        //Month should be 2 digits.
        if($month && $year) {

            $month = str_pad($month, 2, '00', STR_PAD_LEFT);
            $year = substr($year, -2);
        
            if (strlen($year) === 2 && strlen($month) === 2) {
                $exp = $year . $month;
            }

        }
        
        return $exp;
    
    }





	/** PaymentPlan ---------------------------------------------------------------------------------------------------------------------------

		*
		*
		*	This function handles Payment Plans
		*
		*
		*

	--------------------------------------------------------------------------------------------------------------------------- */

	public function paymentplan(){

		$data = $this->getData();

		if(!$data['paymentplan'] && $data['lefttopay'] < 90){
			
			//This is only accessible if you have an active payment plan OR if you have a balance >= 90 dollars.
			//redirect home
			header ("location: /");

		}else{

			//are we processing a form?
			if(isset($_REQUEST['cardorbank'])){ //we are processing a form.

				//Declare Needed Vars
				$payment_amount; 				//NUMBER - The amount of the monthly payment. Must be greater or equal to the minimum payment.
				$is_new_plan;					//BOOL   - If there is an existing paymentplan, this is false. Otherwise this is true.
				$is_autodraft; 					//BOOL 	 - If this is true we are autodrafting.
				$autodraft_type; 				//STRING - either "card" or "bank"
				$bank = array();			//ARRAY
					$bank['name']		= null; //STRING - The name on the account
					$bank['accountnum'] = null;	//NUMBER - The account number
					$bank['acclastfour']= null; //NUMBER - The last four of the account number
					$bank['routingnum'] = null;	//NUMBER - The routing number
				$card = array();			//ARRAY
					$card['name']		= null; //STRING - The name on the card
					$card['number']		= null; //NUMBER - The number on the front of the card
					$card['lastfour']	= null; //NUMBER - The last four of the card number
					$card['exp']		= null; //NUMBER - The expiration date in YYMM format
					$card['cv']			= null; //NUMBER - The three or four digit security code on the back of the card
				$bric;							//STRING - The AUTH GUID provided by EPX
				$plan_date; 					//NUMBER - Between 1 and 28 (inclusive), the date the payment is owed or autodrafted
				$email;							//STRING - User submitted email
				$plan_starting_balance;			//NUMBER - The balance at the start of this particular payment plan. In the case that there is an
				$number_of_payments;			//NUMBER - The number of payments there should be.
				$payment_method_code;			//STRING - EF for check, PP for promise to pay, Card specific versions for card autodrafts.
				$pmtdetails = array();			//ARRAY  - Formatted for payment plan creation function.

				//Collect Data and validate form.
				try	{
					$is_new_plan = $data['paymentplan'] === false ?
						true
					  : false;

					$payment_amount = $is_new_plan ?
						$_REQUEST['paymentplanamount']
					  : $data['paymentplan']['paymentamount'];
					if($payment_amount < $data['minpayment'])
						throw new Exception('Payment Plan amount below minimum '. $data['minpaymentformatted'] . ' payment amount.',1);

					$plan_starting_balance = $is_new_plan ?
						$data['lefttopay']
					  : $data['paymentplan']['startingbalance'];

					$number_of_payments = ceil( $data['lefttopay'] / floatval($payment_amount) );
					$pmtdetails['NbrOfPayments'] = $number_of_payments;

					$is_autodraft = isset($_REQUEST['autodraft']) ?
						true
					  : false;

					$plan_date = $is_autodraft ?
						$_REQUEST['autodraftdate']
					  : (
					  	$is_new_plan ? // If it IS NOT AN AUTODRAFT and it IS A NEW PLAN, set it to today, otherwise if it IS NOT A NEW PLAN, set it to the stored value.
					  		(
					  			intval(Date('d')) > 28? 1 : Date('d')
					  		)
					  	  : $data['paymentplan']['duedate']
					  	);
					if(intval($plan_date) > 28 or intval($plan_date) < 1)
						throw new Exception('Plan date out of range', 2);

					if($is_autodraft){
						if(isset($_REQUEST['email'])){
							$email = $_REQUEST['email'];
						} else throw new Exception('Incomplete Form', 4);
						if(filter_var($email,FILTER_VALIDATE_EMAIL)) Accounts::update($data['accountid'], array(array('field'=>'email','newvalue'=>$email)));
						else throw new Exception('Email Invalid', 8);
					}

					if($is_autodraft){
						switch($_REQUEST['cardorbank']){
							case 'card':
								$autodraft_type = 'card';
								//collect card values
								if(substr($_REQUEST['cardnum'],0,1) == '*' && $data['cardinfo']){
									//assume stored number
									$cardinfo = $data['cardinfo'];

									$card['name'] 		 = $cardinfo['cardname'];
									$card['lastfour'] 	 = $cardinfo['cardlastfour'];
									$card['exp'] 		 = $cardinfo['exp'];
									$card['cv'] 		 = $cardinfo['cardcv'];
									$bric				 = $cardinfo['bric'];
									$payment_method_code = $cardinfo['cardabbr'];

								} else {
									//Check credit card entries
									if(
										isset($_REQUEST['name']) 	 && $_REQUEST['name']
									 && isset($_REQUEST['cardnum'])  && $_REQUEST['cardnum']
									 && isset($_REQUEST['cardmonth'])&& $_REQUEST['cardmonth']
									 && isset($_REQUEST['cardyear']) && $_REQUEST['cardyear']
									 && isset($_REQUEST['cvcode']) 	 && $_REQUEST['cvcode']
									) {
										//use provided number, preauth required.
										$card['name'] 		= $_REQUEST['name'];
										$card['number'] 	= $_REQUEST['cardnum'];
										$card['lastfour']	= substr($card['number'],strlen($card['number'])-4);
										$card['exp'] 		= substr($_REQUEST['cardyear'],2,2) . $_REQUEST['cardmonth'];
										$card['cv'] 		= $_REQUEST['cvcode'];

										$this->load->library('CreditCard');
										$exp = $this->parseEPXResponse($this->epx->preAuthCreditCard($card['number'],$card['cv'],'.01',$card['name'],$card['exp'],$data['accountid'],$data['dbanbr'],$data['address']));
										if(isset($exp['AUTH_RESP']) && $exp['AUTH_RESP'] == '00'){

											//SUCCESSFULLY PREAUTHED!
											$extra = $this->creditcard->cardNameFromNumber($card['number']);
											$payment_method_code = $extra['abbr'];
											$bric = $exp['AUTH_GUID'];

										} else {
											throw new Exception (
												isset($exp['AUTH_RESP_TEXT'])?ucfirst($exp['AUTH_RESP_TEXT']).'.':'Communication error, unable to preauthorize your card.',
												isset($exp['AUTH_RESP'])?intval('90'.$exp['AUTH_RESP']):5
												);
										}

									} else throw new Exception('Incomplete Form', 4);
								}

								//pmtdetails object.

								$pmtdetails['ccname'] = pfsql::scrub($card['name']);
								$pmtdetails['cclast4']= pfsql::scrub($card['lastfour']);
								$pmtdetails['ccv2']	  = pfsql::scrub($card['cv']);
								$pmtdetails['ccyear'] = pfsql::scrub(substr($card['exp'],0,2));
								$pmtdetails['ccmonth']= pfsql::scrub(substr($card['exp'],2));

								break;
							case 'bank':
								$autodraft_type = 'bank';
								$payment_method_code = 'EF';
								//collect bank values
								if(substr($_REQUEST['accountnum'],0,1) == '*'){
									//assume stored number
										$bankinfo = $data['bankinfo'];

									$bank['name']		= $bankinfo['accname'];
									$bank['acclastfour']= $bankinfo['acclastfour'];
									$bank['routingnum'] = $bankinfo['accroutingnum'];
									$bank['bank']		= $bankinfo['accbankname'];
									$bric				= $bankinfo['bric'];

								} else {
									//assume provided number, preauth required.
									if(
										isset($_REQUEST['account_name']) && $_REQUEST['account_name']
									 && isset($_REQUEST['routingnumb'])  && $_REQUEST['routingnumb']
									 && isset($_REQUEST['accountnum'])	 && $_REQUEST['accountnum']
									) {
										//use provided number, preauth required.
										$bank['name'] 		= $_REQUEST['account_name'];
										$bank['accountnum'] = $_REQUEST['accountnum'];
										$bank['acclastfour']= substr($bank['accountnum'],strlen($bank['accountnum'])-4);
										$bank['routingnum'] = $_REQUEST['routingnumb'];
										$bank['bank'] 		= '';

										$exp = $this->parseEPXResponse($this->epx->preAuthCheck($bank['accountnum'],$bank['routingnum'],'.01',$bank['name'],$data['accountid'],$data['dbanbr'],$data['address']));
										if(isset($exp['AUTH_RESP']) && $exp['AUTH_RESP'] == '00'){

											//SUCCESSFULLY PREAUTHED!
											$bric = $exp['AUTH_GUID'];

										} else {
											throw new Exception (
												isset($exp['AUTH_RESP_TEXT'])?ucfirst($exp['AUTH_RESP_TEXT']).'.':'Communication error, unable to preauthorize your card.',
												isset($exp['AUTH_RESP'])?intval('90'.$exp['AUTH_RESP']):5
												);
										}

									} else throw new Exception('Incomplete Form', 4);
								}

								//pmtdetails object.

								$pmtdetails['BankName'] 	= pfsql::scrub($bank['bank']);
								$pmtdetails['accountname']  = pfsql::scrub($bank['name']);
								$pmtdetails['accountlast4'] = pfsql::scrub($bank['acclastfour']);
								$pmtdetails['routingnum'] 	= pfsql::scrub($bank['routingnum']);

								break;
							default:
								throw new Exception('Autodraft source unrecognized.', 3);
								break;
						}
					} else {
						$payment_method_code = 'PP';
						$bric = false;
					}

					//Create paymentplan.
					if(PaymentPlans::endAllPlansForPatient($data['patientid'])){
					} else throw new Exception('Failed closing old payment plan.',6);

					$createdby = $_SESSION['userdata']['id'];
					if(PaymentPlans::create($data['patientid'], $payment_method_code, $pmtdetails, $bric, $plan_starting_balance, $createdby, $plan_date, $payment_amount)){
					} else throw new Exception('Failed starting new payment plan.',7);

					//refresh data.
					$data = $this->getData();

				} catch (Exception $e) {
					$code = $e->getCode();
					$data['errorcode'] = $code >= 90 ? substr($code, 2):'PF'.$code;
					$data['errormsg']	= $e->getMessage();
				}

			}

			//IS THERE AN EXISTING PAYMENTPLAN?
			if($data['paymentplan']){
				//YES
				$data['view'] = 'editpaymentplan';
			} else {
				//NO
				$data['view'] = 'setuppaymentplan';
			}
			//Load the view	

			$this->loadView($data);
		} 
		
		
	}





	/** Details---------------------------------------------------------------------------------------------------------------------------

		*
		*
		*	This is a read only view, that lets you see your existing account activity. That's all.
		*
		*

	--------------------------------------------------------------------------------------------------------------------------- */

	public function details(){

		$data = $this->getData();
		$data['details'] = Accounts::patientPortalBalanceDetails($data['accountid']);
		//krumo($data['details']); exit();
		$data['view'] = 'balancedetails';
		$this->loadView($data);

	}




	/** Statements ---------------------------------------------------------------------------------------------------------------------------

		*
		*
		*	This is a read only view, that lets you access your existing statements.
		*
		*
		*

	--------------------------------------------------------------------------------------------------------------------------- */


	public function statements(){

		$data = $this->getData();
		$data['statements'] = Statements::getStatements($data['accountid'],'S', false, true);
		$data['view'] = 'viewstatements';

		$this->loadView($data);

	}



	/** Statement ---------------------------------------------------------------------------------------------------------------------------

		*
		*
		*	NOTE:: THIS IS ROUTED TO THE /statements/XXXXXXX URI,
		*	This endpoint, when accessed with a statementid, compares the accountid on the statement entry
		*	with the accountid in the current session, and should they match and the file exists, serves the pdf to the browser.
		*
		*
		*

	--------------------------------------------------------------------------------------------------------------------------- */


	public function statement($statementid){
		$statement = Statements::getStatementByID($statementid);
		//krumo($_SESSION);exit();
		if($statement && $_SESSION['guarantor_session']['accountid'] == $statement['AccountID']){
			$data['path'] = '/p/' . (ENVIRONMENT === "production" ? "prod" : "dev") . '/statements/'.$statement['ExportID'].'/'.$statement['AccountID'].'-'.$statement['StatementID'].'.pdf';
     		if(file_exists($data['path'])){
     			$this->load->view('olddig/viewstatement', $data);
     		} else if ($_SESSION['guarantor_session']['clientcode'] == 'demo') {
     			//Generate statement on-the-fly for demo accounts
     			$data2['accountid'] = $_SESSION['guarantor_session']['accountid'];
			    $data2['templateid'] = 4;
			    $_REQUEST = $data2;

     			$template = Templates::getTemplate($data2['templateid']);
			   
     			$this->load->view($template['content'], $data); 
     		} else {
     			show_404();
     		}
		} else {
			show_404();
		}
	}



	/** Contact ---------------------------------------------------------------------------------------------------------------------------

		*
		*
		*	This is a read only view, it uses the practice the current session is associated with to 
		*	deliver the TwilioPhone entry to the view.
		*
		*

	--------------------------------------------------------------------------------------------------------------------------- */


	public function contact(){

		$data = $this->getData();

		$data['view'] = 'contactus';

		$this->loadView($data);

	}
/**
---------------------------------------------------------------------------------------------------------------------------
	



		THESE ARE PRIVATE (and therefore URL inaccessable) FUNCTIONS VVVVV
		(...beyond here monsters be)




---------------------------------------------------------------------------------------------------------------------------
*/

	/** Settings ---------------------------------------------------------------------------------------------------------------------------

		*
		*
		*	THIS ENDPOINT IS CURRENTLY INACTIVE
		*
		*	The intention of this endpoint is to provide an interface for an account to manage their account preferences
		*	and contact information. Currently there is a data model change required to ensure there will be no loss
		*	of data by using this endpoint.
		*
		*

	--------------------------------------------------------------------------------------------------------------------------- */


	public function settings(){
		//This will be public when:
		//1 - The statement backend respects prefs while the account is active (Default behavior if a preference HAS NOT BEEN SET is to respect the CCE choice).
		//2 - When we have a data structure in place that will ensure that Phone Numbers and Mailing Addresses cannot be deleted by the patient ( an email table and an address table ).

        $data = $this->getData();
        if(pf::post('action') === 'save') {
            
            $results = array();

            if(pf::post('email')) array_push($results,$this->saveEmail());

            $data['results'] = $results;
        }
		$data['settings'] = Accounts::getGuarantorControllableValues($data['accountid']);
		$data['view'] = 'settings';

		$this->loadView($data);

	}

    protected function saveEmail(){

        $email = pf::post('email');
        $gogreen = pf::post('gogreen') ? 1 : 0;

        $data = $this->getData();


        if (filter_var($email,FILTER_VALIDATE_EMAIL)) {
            if(strtolower($email) != strtolower($data['email'])) {
                $result = Accounts::update($data['accountid'], array(array('field'=>'email','newvalue'=>$email)));
                if($result) $email = $result[0]['email'];
                else $email = false;
            }
        } else {
            $email = false;
        }

        $success = false;
        if( $email ) {
            $success = true;
            $data['settings'] = Accounts::getGuarantorControllableValues($data['accountid']);
            if ($gogreen !== $data['settings']['gogreen']) {
                $success = false;
                //Make sure this person is pref E
                $this->load->model('Communications');
                if ($gogreen) {
                    if ($this->Communications->prefin($data['accountid'], 'E')) {
                        $success = true;
                    }
                } else {
                    if ($this->Communications->prefout($data['accountid'], 'E')) {
                        $success = true;
                    }
                }
            }

        }

        return array('success'=>$success, 'reason' => $email ? ($success ? 'Everything updated successfully!' : 'There was an error saving your go green preference. Please try again later or <a href="/contact">call us</a> if you continue to experience problems.') : 'There was a problem processing your email... Please make sure you\'re providing a valid email address, and <a href="/contact">call us</a> if you continue to experience problems.');


    }


	/** loadView ---------------------------------------------------------------------------------------------------------------------------

		*
		*
		*	This processes the $data object that we build before loading our views.
		*	(Any nested views use the $_ci_vars object, which represents the same information, for consistant variables)
		*	It's basically a controller-specific template function.
		*
		*

	--------------------------------------------------------------------------------------------------------------------------- */
	private function loadView($data){
		//utility patientportal view loader, takes care of templating.
		$this->load->view('patientportal/include/header', $data);
		$this->load->view('patientportal/'.$data['view'], $data);
		$this->load->view('patientportal/include/footer');
	}


	/** getData ---------------------------------------------------------------------------------------------------------------------------

		*
		*
		*	This snags and returns the data from the session (and from any controller constants).
		*		If $refresh is set to true (default behavior)
		*		Then it uses the accountid in the session to refresh the data from the database.
		*
		*

	--------------------------------------------------------------------------------------------------------------------------- */

	private function getData($refresh = true){
		//Retrieves the appropriate data from the session, formated nicely and ready to go.
		$data;
		if(isset($_SESSION['guarantor_session']) && $_SESSION['guarantor_session']){

			//Refreshes the data
			if($refresh) $this->setSessionData($_SESSION['guarantor_session']['accountid']);
			$data = $_SESSION['guarantor_session'];
			
		}
		$data['view'] = '';
		$data['debug'] = $this->debug;

		return $data;
	}

	/** setSessionData ---------------------------------------------------------------------------------------------------------------------------

		*
		*
		*	This unsets any existing session, then reaches out to the database and creates a nicely formatted session object
		*	with all sorts of account information. This is usually called once per request.
		*
		*

	--------------------------------------------------------------------------------------------------------------------------- */
	private function setSessionData($accountid){

		//Refreshes session data from the database.
		//In the case that there is no session data, it creates the object.

		//Call to the database
		$sess = Accounts::getGuarantorSession($accountid);

		if($sess){

			//Check to see if this patient can use the patient portal first and foremost.
			$can_login = ($sess['status1'] != 'RT' && ClientPreferences::getClientPreference($sess['clientid'], 'PatientsCanLoginToPatientPortal'));

			if($can_login === true){

				//Get Parameters for this client
				$this->load->model('ClientParameters');
				$params = $this->ClientParameters->read(array('name','value'), array('clientid'=>$sess['clientid'], 'voideddate'=>null));
				$sess['parameters'] = array();
				if($params) foreach($params as $p){
					$sess['parameters'][$p['name']][] = $p['value'];
				}

                $sess['preferences'] = array();
                $sess['preferences']['DisplayCreditBalancesInPatientPortal'] = $this->ClientPreferences->getClientPreference($sess['clientid'], 'DisplayCreditBalancesInPatientPortal');

				//Additional fields not needed from the database
                if($sess['preferences']['DisplayCreditBalancesInPatientPortal'] || $sess['lefttopay'] >= 0){
                    $sess['lefttopayformatted'] = pfmoney::toFromCents($sess['lefttopay']);
                } else {
                    $sess['lefttopayformatted'] = pfmoney::toFromCents(0);
                }
				//Sets what the "Default" make-a-payment amount is. If there is no payment plan active, it defaults to the full amount
				$sess['defaultpayment'] = min((($sess['paymentplan']&&$sess['paymentplan']['paymentamount'])?$sess['paymentplan']['paymentamount']:$sess['lefttopay']),$sess['lefttopay']);
				//payment_threshold is the minimum payment we will accept through the portal (assuming the patient owes more than the threshold)
				$sess['paythresh'] = $this->payment_threshold;
				$sess['paythreshformatted'] = pfmoney::toFromCents($this->payment_threshold);

                //Is left to pay representative of the full amount owed?
                if($sess['lefttopay'] != $sess['totalbalance']){
                    $sess['balancesmatch'] = false;
                } else {
                    $sess['balancesmatch'] = true;
                }

				//Minimum payment
				$sess['minpayment'] = ($sess['lefttopay'] < $this->payment_threshold ? $sess['lefttopay'] : $this->payment_threshold);
					//If the default payment is less than this ^^ set it to the default payment instead.
					if($sess['defaultpayment'] < $sess['minpayment']) $sess['defaultpayment'] = $sess['minpayment'];

				//Minimum payment formatted
				$sess['minpaymentformatted'] = pfmoney::toFromCents($sess['minpayment']);

				//Color Scheme
				$sess['colors'] = ClientPreferences::getClientColors($sess['clientid']);

				//Unset any potentially remaining patient session.
				//Might be a bit heavy handed... May want to account for spoofs.
				if(isset($_SESSION['guarantor_session'])){
					unset($_SESSION['guarantor_session']);
					unset($_SESSION['userdata']);
					unset($_SESSION['rights']);
					unset($_SESSION['roles']);
					//unset($_SESSION['colors']);
					//unset($_SESSION['statementid']);
				}
				$_SESSION['guarantor_session'] = $sess;
				//Userdata object
				$ud = Users::getUserByEmail('patient@patientfocus.com');
				$_SESSION['userdata'] = $ud;
				$_SESSION['userdata']['accountid'] = $sess['accountid'];
				//Roles n rights
	          	$_SESSION['roles'][]= array('id'=>'14', 'name' => 'Patient');       
	          	$_SESSION['rights'] = Rights::getRightsForRolesArray($_SESSION['roles']);

	        } else {

	        	//Destroy session
				unset($_SESSION['guarantor_session']);
				unset($_SESSION['userdata']);
				unset($_SESSION['roles']);
				unset($_SESSION['rights']);
				unset($_SESSION['colors']);
				unset($_SESSION['statementid']);
				session_destroy();

				//Get forwarding Message
				$data = array();
				$data['forwarding_message'] = $this->Clients->getForwardingMessageForPortal($sess['clientid']);

				//Show forwarding Message and break the current flow.
				echo $this->load->view('patientportal/forwardingmessage',$data, true);
				//NOTE:: Echoing this here ensures that this doesn't enter the CI output buffer
				// and writes straight to the output, so we can exit on the next line.
				exit();

	        }

		}

	}

	/** parseEPXResponse ---------------------------------------------------------------------------------------------------------------------------

		*
		*
		*	Converts an xml response string from EPX to an associated array.
		*
		*

	--------------------------------------------------------------------------------------------------------------------------- */
	private function parseEPXResponse($xmlstr){

		$xmlobj = simplexml_load_string($xmlstr);
		$xmlarr = array();
		if($xmlobj) foreach($xmlobj->FIELDS->FIELD as $field){
              $xmlarr[(string)$field->attributes()->KEY] = (string)$field;
        }
        return $xmlarr;

	}

}

?>

Open in new window


The login script begins on line 40. The "getbyCode" SQL looks like this:

select 
client.ClientID,
client.ClientName,
client.ClientTetrisId,
client.ClientPrimaryContact,
client.ClientBankAcctNumber,
client.ClientBankRoutingNumber,
client.ClientStatusCode,
client.Specialty,
client.Address,
client.PhoneNumber,
client.Email,
client.PaymentProcessingDBANbr,
client.CreatedDate,
client.LastModifiedDate,
client.ModifiedBy,
client.Address1,
client.Address2,
client.City,
client.State,
client.Zip,
client.clientcode,
cast(dbo.ufn_ClientPreference(clientid,'WithholdFeesOnInvoice') as bit) withhold,
client.phrase,
client.type,
client.ClientNotes,
client.SitePaymentFee
         from client where clienttetrisid = '$clientcode'"

Open in new window


So, it seems you're getting all of the data you need to validate the user from that SQL.

It's all routed to a specific domain based on lines 111 and 112, yet on line 126 you've got the $this->load->view('patientportal/subdomaingate) thing and that code looks like this:

<!DOCTYPE html>
<html>
	<head>
		<title>Redirecting...</title>
	</head>
	<body>
		<form action="https://<?=$clientcode?>.patientfocus.com/patientportal/login" method="post">
		<!--<form action="patientportal/login" method="post">-->
			<input type="hidden" name="pin" value="<?=$pin?>"/>
			<input type="hidden" name="lastfour" value="<?=$lastfour?>"/>
			<input type="hidden" name="year" value="<?=$year?>"/>
		</form>
		<script type="text/javascript">
			document.forms[0].submit();
		</script>
	</body>
</html>

Open in new window


So, the page is posting all of its data back to itself, but where does it go and how am I getting this page:

home page
How am I getting there?

Thanks!
0
Comment
Question by:brucegust
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
1 Comment
 
LVL 110

Accepted Solution

by:
Ray Paseur earned 500 total points
ID: 41760917
Probably line 462 in the top PHP script.
0

Featured Post

Instantly Create Instructional Tutorials

Contextual Guidance at the moment of need helps your employees adopt to new software or processes instantly. Boost knowledge retention and employee engagement step-by-step with one easy solution.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

I imagine that there are some, like me, who require a way of getting currency exchange rates for implementation in web project from time to time, so I thought I would share a solution that I have developed for this purpose. It turns out that Yaho…
These days socially coordinated efforts have turned into a critical requirement for enterprises.
The viewer will learn how to count occurrences of each item in an array.
The viewer will learn how to look for a specific file type in a local or remote server directory using PHP.

729 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question