Example #1
0
function process_state( $ps_state )
////////////////////////////////////////////
//
// A basic state machine.
//
// Given the $ps_state value passed, perform
// the action dictated by that state.
//
////////////////////////////////////////////
{
GLOBAL $argv;
GLOBAL $msg_log;
GLOBAL $db_host, $db_user, $db_pwd, $db_name;
GLOBAL $DEBUG;

	$done = FALSE;

// $cont_key is an integer 1 .. N of the contract number 
// we'll display.  It indexes the arrays $headers and $details

	$cont_key  = isset( $_SESSION[ 'cont_key'  ] ) ? $_SESSION[ 'cont_key'  ] : NULL;
	$campaigns = isset( $_SESSION[ 'campaigns' ] ) ? $_SESSION[ 'campaigns' ] : NULL;
	$headers   = isset( $_SESSION[ 'headers'   ] ) ? $_SESSION[ 'headers'   ] : NULL;
	$details   = isset( $_SESSION[ 'details'   ] ) ? $_SESSION[ 'details'   ] : NULL;

// loop until we reach a state where the user (web client)
// must perform an action to determine what the next state
// will be.

	output_style_header();
	do {

		message_log_reset( $msg_log );
		if ($DEBUG)
		{
			message_log_append( $msg_log, "database name is $db_name\n" );
		}
		if ($DEBUG)
		{
			message_log_append( $msg_log, "state is $ps_state\n" );
		}
		switch (TRUE) 
		{
/////////////////////////////////
//
//  Initial state is BEGIN
//
/////////////////////////////////
			case ($ps_state == 'BEGIN'):
//  Clear all keys in array $_SESSION
				foreach (array_keys( $_SESSION ) as $sess_key) 
				{
					unset( $_SESSION[ $sess_key ] );
				} // foreach
//  Proceed to a prompting state
				next_state( 'PROMPT_FOR_XML_INPUT' );
				break;
/////////////////////////////////
//
//  Prompt the user to provide an
//  XML file.
//
/////////////////////////////////
			case ($ps_state == 'PROMPT_FOR_XML_INPUT'):
// We are ready to prompt for an input file
				if (CLI) 
				{
					;
// In CLI mode, the input file name will be on the command line.
				} 
				else 
				{
					prompt_for_xml_input();
				}
//  The next step is to check the XML file for basic sanity checks
				next_state( 'CHECK_XML_FILENAME' );
//  But first we have to wait for the web client to upload the file
				$done = TRUE;
				if (CLI) 
				{
					$done = FALSE;
				}
				break;
/////////////////////////////////
//
//  Do some basic checking on the
//  XML file the user provided.
//
/////////////////////////////////
			case ($ps_state == 'CHECK_XML_FILENAME'):
				$input_nam = 'xmlfile'; // per the POST form
				$filnam = isset( $_FILES[ $input_nam ] ) ? 
						 $_FILES[ $input_nam ][ 'name' ] : NULL;
// The full path to where the file was uploaded on the server
				$filtmp = isset( $_FILES[ $input_nam ] ) ? 
						 $_FILES[ $input_nam ][ 'tmp_name' ] : NULL;
				if (is_null( $filnam ) || is_null( $filtmp ) ||
						(strlen( $filnam ) == 0) ||
						(strlen( $filtmp ) == 0)) 
				{
					next_state( 'BEGIN' );
				} 
				else 
				{
					next_state( 'CHECK_XML_UPLOAD' );
				}
				break;
			case ($ps_state == 'CHECK_XML_UPLOAD'):
				if (CLI) 
				{
					$filtmp = $argv[1];
					echo "input file is $filtmp\n";
				}
// The size of the file in bytes
				$filsiz = $_FILES[ $input_nam ][ 'size' ];
// The error code of the upload process
				$filerr = $_FILES[ $input_nam ][ 'error' ];
				if (CLI || $filerr == UPLOAD_ERR_OK) 
				{
					next_state( 'PARSE_XML_UPLOAD' );
				} 
				else 
				{
					message_log_append( $msg_log, "Upload error $filerr", MSG_LOG_ERROR );
					$done = TRUE;
					next_state( 'BEGIN' );	// start over
				}
				break;
/////////////////////////////////
//
//  Do a full parsing of the
//  XML file the user provided.
//
/////////////////////////////////

			case ($ps_state == 'PARSE_XML_UPLOAD'):
				open_mysql();
//  What is the path portion of the $filtmp filename?
				$_SESSION[ 'xmlfile' ] = $filtmp;
				if ($DEBUG) 
				{
					echo "calling parse_xml<br>\n";
					echo "parsing file: $filtmp<br>\n";
				}
//  Set state to start over, in case we fail before parse_xml
// returns.
				next_state( 'BEGIN' );
// parse the XML file, returning an array of contract headers,
// and an array of arrays of detail lines.  First-order indices of 
// headers and details arrays will be integers starting from 1.
				if (parse_xml( $filtmp, $campaigns, $headers, $details )) 
				{
					next_state( 'VERIFY_CAMPAIGN' );
				} 
				else 
				{
					message_log_append( $msg_log, "XML order parsing failed", MSG_LOG_ERROR );
					unset( $_SESSION[ 'campaigns' ] );
					unset( $_SESSION[ 'headers'   ] );
					unset( $_SESSION[ 'details'   ] );
					next_state( 'TRY_AGAIN' );
				}
				break;
/////////////////////////////////
//
//  Verify some basic integrity
//  checks on the data, and create
//  human-readable log messages for
//  problems that are identified.
//
/////////////////////////////////
			case ($ps_state == 'RE-VERIFY_CAMPAIGN'):
// unset all header row MSG_LOG values
				foreach (array_keys( $headers ) as $key)
				{
				    unset( $headers[ $key ][ 'MSG_LOG' ] );
				}
// unset all detail line MSG_LOG values
				foreach (array_keys( $details ) as $dkey)
				{
				    foreach (array_keys( $details[ $dkey ] ) as $ln)
					{
						unset( $details[ $dkey ][ $ln ][ 'MSG_LOG' ] );
					}
				}
// and fall through to VERIFY_CAMPAIGN:
			case ($ps_state == 'VERIFY_CAMPAIGN'):
				verify_campaign( $campaigns, $headers, $details );
				next_state( 'BEGIN' );	// as precaution
//echo "calling verify_all_contracts<br>";
				if (verify_all_contracts( $campaigns, $headers, $details )) 
				{
//echo "vac succeeded<br>";
				} 
				else 
				{
//echo "vac failed<br>";
				}
				next_state( ($ps_state == 'VERIFY_CAMPAIGN')
					? 'DISPLAY_CAMPAIGN'
					: 'DISPLAY_CONTRACT' );
				break;
			case ($ps_state == 'DISPLAY_CAMPAIGN'):
				unset( $cont_key );	// contract array key
				next_state( 'DISPLAY_CONTRACT' );
				break;
			case ($ps_state == 'DISPLAY_CONTRACT'):
//echo "$ps_state<br>";
				if (is_null( $campaigns ) ||
				    is_null( $headers   ) || is_null( $details   )) 
				{
				    next_state( 'BEGIN' );
				} 
				else 
				{
				    if (!isset( $cont_key ) || is_null( $cont_key )) 
					{
						$keys = array_keys( $headers );
						$cont_key = $keys[0];
				    } // if
				    if (is_null( $cont_key )) 
					{
						next_state( 'BEGIN' );
				    } 
					else 
					{
						echo html_campaign( $campaigns );
						echo nav_buttons( array_keys( $headers ), 
							  TRUE,
							  $headers,
							  $cont_key );
						echo html_order( $headers[$cont_key], $cont_key );
						echo html_detail( $details[$cont_key], $cont_key );
// set a safe next state.  form_handler ought to override, unless error.
						next_state( 'BEGIN' );
						$done = TRUE;
				    } //if
				} // if
				break;
			case ($ps_state == 'DISPLAY_NEXT'):
				$keys = array_keys( $headers );
				$cont_key = next_cont_key( $cont_key, $keys );
// we might someday use a better state than BEGIN here.  A NULL
// return from next_cont_key would mean that no contracts remain.
				next_state( is_null( $cont_key ) ? 'BEGIN' : 'DISPLAY_CONTRACT' );
				break;
			case ($ps_state == 'DISPLAY_PREV'):
				$keys = array_keys( $headers );
				$cont_key = prev_cont_key( $cont_key, $keys );
				next_state( is_null( $cont_key ) ? 'BEGIN' : 'DISPLAY_CONTRACT' );
				break;
/////////////////////////////////
//
//  Push SQL file out to
//  the web client for download.
//
/////////////////////////////////
			case ($ps_state == 'PUSH_SQL_FILE'):
				next_state( 'BEGIN' );
				if (CLI) 
				{
					echo "SQL output is in file $sql_file\n";
				} 
				else 
				{
					header( 'Content-type: application/force-download' );
    				header( 'Content-Transfer-Encoding: Binary' );
    				header( 'Content-length: ' . filesize( $sql_file ) );
    				header( 'Content-disposition: attachment; filename="' . basename( $sql_file ) . '"' );
    				readfile( $sql_file );
					unlink( $sql_file );   // delete
				}
				$done = TRUE;
				break;
/////////////////////////////////
//
//  Connect to the SQL server and
//  move the data into the database.
//
/////////////////////////////////
			case ($ps_state == 'IMPORT'):
				next_state( 'BEGIN' );
				open_mysql();
				insert_sql( $campaigns, $headers, $details );
				echo message_log_format( $msg_log );
				message_log_reset( $msg_log );
				break;
/////////////////////////////////
//
//  Delete a LineID from a contract
//
/////////////////////////////////
			case ($ps_state == 'DELETE_LINE'):
				$lineID	   = $_SESSION[ 'LineID'    ];  // XML LineID number
//message_log_append( $msg_log, 'You requested to delete LineID ' . $lineID . ' from contract key ' . $cont_key );

// Deleting detail lines will change the header spot and value totals.
// delete_detail_lineid is responsible for telling us how many spots
// were deleted, and what their total value was.
				$spots = 0;
				$value = 0;
				$details[ $cont_key ] = delete_detail_lineid( 
					$details[ $cont_key ], $lineID, $spots, $value );

// subtract deleted spots and value from header 'detail_*' totals
				$headers[ $cont_key ][ 'detail_spots' ] -= $spots;
				$v = $headers[ $cont_key ][ 'detail_cost' ];
				$v = bcsub( $v, $value, 2 );
				$headers[ $cont_key ][ 'detail_cost' ] = $v;

// subtract deleted spots and value from header 'total_*' totals
				$headers[ $cont_key ][ 'total_spots' ] -= $spots;
				$v = $headers[ $cont_key ][ 'total_cost' ];
				$v = bcsub( $v, $value, 2 );
				$headers[ $cont_key ][ 'total_cost' ] = $v;

// subtract deleted spots and value from campaign 'detail_*' totals
				$campaigns[0][ 'detail_spots' ] -= $spots;
				$v = $campaigns[0][ 'detail_cost' ];
				$v = bcsub( $v, $value, 2 );
				$campaigns[0][ 'detail_cost' ] = $v;

// subtract deleted spots and value from campaign 'total_*' totals
				$campaigns[0][ 'total_spots' ] -= $spots;
				$v = $campaigns[0][ 'total_cost' ];
				$v = bcsub( $v, $value, 2 );
				$campaigns[0][ 'total_cost' ] = $v;

// Now re-validate everything, and re-display this
// specific contract.
				next_state( 'RE-VERIFY_CAMPAIGN' );
				break;
/////////////////////////////////
//
//  Delete a Network from a contract
//
/////////////////////////////////
			case ($ps_state == 'DELETE_NETWORK'):
next_state( 'BEGIN' );
				$lineID	   = $_SESSION[ 'LineID'    ];  // XML LineID number
				$network   = NULL;
				foreach ($details[ $cont_key ] as $det) 
				{
					if ($det[ 'LineID' ] === $lineID) 
					{
						$network = $det[ 'Network' ];
//echo "<pre>"; var_dump( $det ); echo "</pre>";
						break;
					}
				}

				next_state( 'RE-VERIFY_CAMPAIGN' );
				if (is_null( $network)) 
				{
message_log_append( $msg_log, 'Invalid LineID: ' . $lineID . ' not found in contract key ' . $cont_key );
					break;
				}

// Deleting detail lines will change the header spot and value totals.
// delete_detail_network is responsible for telling us how many spots
// were deleted, and what their total value was.
				$spots = 0;
				$value = 0;
				$details[ $cont_key ] = delete_detail_network( 
					$details[ $cont_key ], $network, $spots, $value );

// subtract deleted spots and value from header 'detail_*' totals
				$headers[ $cont_key ][ 'detail_spots' ] -= $spots;
				$v = $headers[ $cont_key ][ 'detail_cost' ];
				$v = bcsub( $v, $value, 2 );
				$headers[ $cont_key ][ 'detail_cost' ] = $v;

// subtract deleted spots and value from header 'total_*' totals
				$headers[ $cont_key ][ 'total_spots' ] -= $spots;
				$v = $headers[ $cont_key ][ 'total_cost' ];
				$v = bcsub( $v, $value, 2 );
				$headers[ $cont_key ][ 'total_cost' ] = $v;

// subtract deleted spots and value from campaign 'detail_*' totals
				$campaigns[0][ 'detail_spots' ] -= $spots;
				$v = $campaigns[0][ 'detail_cost' ];
				$v = bcsub( $v, $value, 2 );
				$campaigns[0][ 'detail_cost' ] = $v;

// subtract deleted spots and value from campaign 'total_*' totals
				$campaigns[0][ 'total_spots' ] -= $spots;
				$v = $campaigns[0][ 'total_cost' ];
				$v = bcsub( $v, $value, 2 );
				$campaigns[0][ 'total_cost' ] = $v;

				message_log_append( $msg_log, 
					'Network ' . $network . 
					' deleted from contract ' . $cont_key );

// Now re-validate everything, and re-display this
// specific contract.
				next_state( 'RE-VERIFY_CAMPAIGN' );
				break;
/////////////////////////////////
//
//  Delete an entire contract
//
/////////////////////////////////
			case ($ps_state == 'DELETE_CONTRACT'):
//message_log_append( $msg_log, 'You requested to delete contract ' . $cont_key );

// Unset the individual detail lines for this contract.
				$dkeys = array_keys( $details[ $cont_key ] );
				foreach ($dkeys as $key) 
				{
					unset( $details[ $cont_key ][ $key ] );
				}
// subtract contract spots and value from campaign 'detail_*' totals
				$spots = $headers[ $cont_key ][ 'detail_spots' ];
				$value = $headers[ $cont_key ][ 'detail_cost'  ];
				$campaigns[0][ 'detail_spots' ] -= $spots;
				$v = $campaigns[0][ 'detail_cost' ];
				$v = bcsub( $v, $value, 2 );
				$campaigns[0][ 'detail_cost' ] = $v;

// subtract contract spots and value from campaign 'total_*' totals
				$spots = $headers[ $cont_key ][ 'total_spots' ];
				$value = $headers[ $cont_key ][ 'total_cost'  ];
				$campaigns[0][ 'total_spots' ] -= $spots;
				$v = $campaigns[0][ 'total_cost' ];
				$v = bcsub( $v, $value, 2 );
				$campaigns[0][ 'total_cost' ] = $v;

// Set the contract header to show 0 spots, 0 value.
				$spots = 0;
				$value = 0;
				$headers[ $cont_key ][ 'detail_spots' ] = $spots;
				$headers[ $cont_key ][ 'detail_cost'  ] = $value;
				$headers[ $cont_key ][ 'total_spots'  ] = $spots;
				$headers[ $cont_key ][ 'total_cost'   ] = $value;

// Unset the 'versionN' fields of deleted contracts so that version
// problems don't prevent the remaining contracts from being imported.
				$j = 0;
				$done = FALSE;
				while (!$done) 
				{
					$fld = 'version' . (++$j);
					$done = !isset( $headers[ $cont_key ][ $fld ] );
					unset( $headers[ $cont_key ][ $fld ] );
				} // while
// auto-advance to next contract
				$done = FALSE;
				$keys = array_keys( $headers );
				$cont_key = next_cont_key( $cont_key, $keys );
// we might someday use a better state than BEGIN here.  A NULL
// return from next_cont_key would mean that no contracts remain.
				next_state( is_null( $cont_key ) ? 'BEGIN' : 'RE-VERIFY_CAMPAIGN' );
				break;
/////////////////////////////////
//
//  Dummy stub.
//
/////////////////////////////////
			case ($ps_state == 'DEAD_END'):
			case ($ps_state == 'STOP'):
				echo $ps_state;
				next_state( 'BEGIN' );
				$done = TRUE;
				break;
/////////////////////////////////
//
//  Screen has error messages.
//  Force user to go back and retry.
//
/////////////////////////////////
			case ($ps_state == 'TRY_AGAIN'):
				next_state( 'BEGIN' );
				echo nav_buttons( NULL, FALSE );	// Cancel only
				$done = TRUE;
				break;
/////////////////////////////////
//
//  State is unknown or invalid.
//  Go back to BEGIN state.
//
/////////////////////////////////
			default:
				message_log_append( $msg_log, 'Invalid state label: ' . $ps_state, MSG_LOG_ERROR );
				next_state( 'BEGIN' );
				$done = TRUE;

		} // switch
		$ps_state = current_state();
//		echo message_log_format( $msg_log );
		echo message_log_table( $msg_log );
	} while (!$done);
	$_SESSION[ 'campaigns' ] = $campaigns;
	$_SESSION[ 'headers'   ] = $headers;
	$_SESSION[ 'details'   ] = $details;
	$_SESSION[ 'cont_key'  ] = $cont_key;
} // process_state
Example #2
0
function verify_one_contract( $campaign, &$header, &$detail )
// check one contract's $campaign, $header and $detail arrays
// the header array is passed by reference because
// we will add detail_spots and detail_cost fields to the
// header.
// the detail array is passed by reference because 
// detail_time_validation will add the Priority element to
// each row, and MSG_LOG entries could be added.
// return TRUE if no errors, else FALSE
{
//GLOBAL $DEBUG;

	$success     = TRUE;
	$done        = FALSE;
	$test_number = 0;

// total_spots is the XML reference field in the contract header:
	$total_spots = $header['total_spots'];
// total_cost is the XML reference field in the contract header:
	$total_cost  = $header['total_cost'];

	message_log_reset( $h_msg_log ); // local $h_msg_log specific to this header

//  sum spots and cost across all the detail lines passed to us
	$det_spots = 0;
	$det_cost  = 0;

	foreach ($detail as $det) 
	{
		$det_spots += $det[ 'nOrdered' ];
// calculate values with binary precision arithmetic routines
		$v = bcmul( bcmul( $det[ 'nOrdered' ], $det[ 'UnitPrice' ], 2 ), '0.01', 2 );
		$det_cost = bcadd( $det_cost, $v, 2 );
	} // foreach

// Add 'detail_spots' and 'detail_cost' fields to header array.
// These fields will hold the total spots and costs as summed from
// individual detail lines.  These should agree with 'total_spots'
// and 'total_cost' (which are parsed directly from the XML) but we 
// will check that (elsewhere).

    $header[ 'detail_spots' ] = $det_spots;
    $header[ 'detail_cost'  ] = $det_cost;

//echo "test number " . ($test_number + 1) . "\n";

	while (!$done) 
	{

		switch (++$test_number) 
		{
		case 1:
			break;
// per 11-06-2012 email from Carolyn Boyer to Dustin Carlson,
// we no longer care about header version numbers.
		case 2:
			break;
// all contract headers must be version 1
//if ($DEBUG)
//echo "<pre>VOC: calling header_version_check\n</pre>\n";
			if (header_version_check( $header, $h_msg_log )) ;
			else {
				$success = FALSE;
			}
//			$done = (!$success);	// don't continue if this fails
			break;
		case 3:
// $header totals must match sum of detail
			if ($header[ 'detail_spots' ] != $header[ 'total_spots' ]) 
			{
				$msg = "Total number of spots doesn't match";
				message_log_append( $h_msg_log, $msg, MSG_LOG_ERROR );
//if ($DEBUG)
//echo "<pre>$msg\n</pre>\n";
			}
			if ($header[ 'detail_cost' ] != $header[ 'total_cost' ]) 
			{
				$msg = "Total value of spots doesn't match";
				message_log_append( $h_msg_log, $msg, MSG_LOG_ERROR );
//if ($DEBUG)
//echo "<pre>$msg\n</pre>\n";
			}
			break;
		case 4:
			break;
		case 5:
// validate all detail lines' StartDate/TimeOn against EndDate/TimeOff
// To figure the priority, we must know the customer name 
// for this contract.  The customer record is stored in 
// the header array.  Pass the Name field as a parameter.
			$cust_name = $campaign[ 'Customer Name' ];
			if (!detail_time_validation( $detail, $cust_name )) 
			{
//echo "Received FALSE from DTV<br>";
				$success = FALSE;
// make the contract flag as red
               	message_log_append( $h_msg_log, '', MSG_LOG_ERROR );
			} // if
			break;
// Let's look at the networks on these orders.
// All networks on the order have to map to
// networks available at the sitename/syscode.
		case 6:
			if (!detail_network_validation( $h_msg_log, $detail, $header[ 'SiteName' ], $campaign[ 'TELAMERICA' ] )) 
			{
				$success = FALSE;
			} // if
			break;
// total number of spots and weeks on each order must be in range
		case 7:
			$weeks = $header[ 'week_count'  ];
			$spots = $header[ 'total_spots' ];
//if ($DEBUG)
//echo "week_count check, header ($weeks)\n";
			if ($weeks > 0 && $weeks <= MAX_WEEKS) ;
			else {
				$success = FALSE;
				$msg     = "Number of weeks ($weeks) is out of range";
                        	message_log_append( $h_msg_log, $msg, MSG_LOG_ERROR );
			} // if
//if ($DEBUG)
//echo "spot count check, header ($spots)\n";
			if ($spots > 0 && $spots <= MAX_SPOTS) ;
			else if ($spots == 0) {
				$msg     = "ZERO spots on this contract";
                        	message_log_append( $h_msg_log, $msg, MSG_LOG_WARNING );
			} else {
				$success = FALSE;
				$msg     = "Number of spots ($spots) is out of range";
                        	message_log_append( $h_msg_log, $msg, MSG_LOG_ERROR );
			} // if
			break;	
		case 8:
			break;
		case 9:
			break;
		case 10:
			break;
		default:
			$done = TRUE;
		} // switch
	} // while

	if (isset( $header[ 'MSG_LOG' ] ))
	{
		die( 'verify_one_contract: header already has a message log' );
	}
	else 
	{
//if ($DEBUG)
//echo "<pre>Setting header[MSG_LOG]\n</pre>\n";
		$header[ 'MSG_LOG' ] = $h_msg_log;
	}

//if ($DEBUG) {
//echo "Returning " . ( $success ? 'TRUE' : 'FALSE' ) . " from VOC<br>";
//echo message_log_format( $header[ 'MSG_LOG' ] ); }
	return( $success );
} // verify_one_contract