VbzCart/code/SpecialVbzAdmin

<?php /* NAME: SpecialVbzAdmin PURPOSE: Special page for administering VbzCart AUTHOR: Woozle (Nick) Staddon REQUIRES: Tabber extension for tabs on Supplier admin page TreeAndMenu extension (tentatively) for category management VERSION: 2009-03-10 0.0 (Wzl) Started writing had a few functions implemented by June or so, but not enough to process anything 2009-07-09 (Wzl) rewrote menu functions as classes started on Shipments 2009-10-04 (Wzl) menu classes now in separate file; removed from here added 'orders' and 'order' pages/classes 2009-10-06 (Wzl) clsTitles -> clsVbzTitles, clsTitle -> clsVbzTitle 2010-06-27 (Wzl) new functionality in Bins, Images; moved catalog rebuild out to standalone script 2010-09-22 (Wzl) working on email confirmation of orders (finally) 2011-02-06 (Wzl) extensive work since 9/22... most features usable 2011-12-21 (Wzl) extracted clsVbzAdminData into base.admin.php so it could be used from command line $wgSpecialPages['VbzAdmin'] = 'SpecialVbzAdmin'; # Let MediaWiki know about your new special page. $wgExtensionCredits['other'][] = array(       'name' => 'Special:VbzAdmin',	'url' => 'http://htyp.org/VbzCart',        'description' => 'special page for VbzCart administration',        'author' => 'Woozle (Nick) Staddon',	'version' => '2011-12-21 unreleased' ); global $dbgShowLibs; $dbgShowLibs = TRUE;

if (!defined('LIBMGR')) { require('libmgr.php'); } //clsLibMgr::$doDebug = TRUE; clsLibMgr::Add('vbz.site',	KFP_LIB_VBZ.'/site.php',__FILE__,__LINE__); clsLibMgr::Add('vbz.shop',	KFP_LIB_VBZ.'/shop.php',__FILE__,__LINE__); clsLibMgr::Add('vbz.ckout',	KFP_LIB_VBZ.'/ckout.php',__FILE__,__LINE__); clsLibMgr::Add('vbz.topic',	KFP_LIB_VBZ.'/topic.php',__FILE__,__LINE__); clsLibMgr::Add('admin.events',	KFP_MW_PLUGINS.'/lib/admin.events.php',__FILE__,__LINE__); clsLibMgr::Add('admin.forms',	KFP_MW_PLUGINS.'/lib/admin.forms.php',__FILE__,__LINE__); clsLibMgr::Add('vbz.admin.base',	KFP_LIB_VBZ.'/base.admin.php',__FILE__,__LINE__); clsLibMgr::Add('vbz.admin.cache',	KFP_LIB_VBZ.'/admin.cache.php',__FILE__,__LINE__); clsLibMgr::Add('vbz.admin.cat',	KFP_LIB_VBZ.'/admin.cat.php',__FILE__,__LINE__); clsLibMgr::Add('vbz.admin.sess',KFP_LIB_VBZ.'/admin.sess.php',__FILE__,__LINE__); clsLibMgr::Add('vbz.admin.cart',KFP_LIB_VBZ.'/admin.cart.php',__FILE__,__LINE__); clsLibMgr::Add('vbz.admin.ord',	KFP_LIB_VBZ.'/admin.ord.php',__FILE__,__LINE__); clsLibMgr::Add('vbz.admin.pkg',	KFP_LIB_VBZ.'/admin.pkg.php',__FILE__,__LINE__); clsLibMgr::Add('vbz.admin.cust',KFP_LIB_VBZ.'/admin.cust.php',__FILE__,__LINE__); clsLibMgr::Add('vbz.admin.rstk',KFP_LIB_VBZ.'/admin.rstk.php',__FILE__,__LINE__); clsLibMgr::Add('vbz.admin.stock',KFP_LIB_VBZ.'/admin.stock.php',__FILE__,__LINE__); clsLibMgr::Add('richtext',	KFP_MW_PLUGINS.'/richtext.php',__FILE__,__LINE__); clsLibMgr::Add('menus',	KFP_MW_PLUGINS.'/menu.php',__FILE__,__LINE__); clsLibMgr::Load('vbz.site'	,__FILE__,__LINE__); clsLibMgr::Load('vbz.shop'	,__FILE__,__LINE__); clsLibMgr::Load('vbz.ckout'	,__FILE__,__LINE__); clsLibMgr::Load('vbz.topic'	,__FILE__,__LINE__); clsLibMgr::Load('admin.events'	,__FILE__,__LINE__); clsLibMgr::Load('admin.forms'	,__FILE__,__LINE__); clsLibMgr::Load('vbz.admin.base'	,__FILE__,__LINE__); clsLibMgr::Load('vbz.admin.cache'	,__FILE__,__LINE__); clsLibMgr::Load('vbz.admin.cat'		,__FILE__,__LINE__); clsLibMgr::Load('vbz.admin.sess'	,__FILE__,__LINE__); clsLibMgr::Load('vbz.admin.ord'		,__FILE__,__LINE__); clsLibMgr::Load('vbz.admin.pkg'		,__FILE__,__LINE__); clsLibMgr::Load('vbz.admin.cart'	,__FILE__,__LINE__); clsLibMgr::Load('vbz.admin.cust'	,__FILE__,__LINE__); clsLibMgr::Load('vbz.admin.rstk'	,__FILE__,__LINE__); clsLibMgr::Load('vbz.admin.stock'	,__FILE__,__LINE__); clsLibMgr::Load('richtext'	,__FILE__,__LINE__); clsLibMgr::Load('menus'	,__FILE__,__LINE__);

define('kwp_DocPfx','htyp:VbzCart/'); define('kwp_DocTblPfx',kwp_DocPfx.'tables/'); define('kwp_DocPrcPfx',kwp_DocPfx.'procs/'); define('kwp_DocTermPfx',kwp_DocPfx.'ui/terms/'); //echo 'LIB LOG:'.clsLibMgr::$Log;

if (!defined('KS_CHAR_URL_ASSIGN')) { define('KS_CHAR_URL_ASSIGN',':');	// character used for encoding values in wiki-internal URLs }

// data source names -- these are used only by admin functions; general tables are in store.php define('KSQL_DS_ITEMS_TO_SHIP','qryStock_forOpenOrders');

function Date_DefaultYear($iDate,$iYear,$iSmallerPfx=' ',$iSmallerSfx=' ') { if (empty($iDate)) { return NULL; } else { $dtIn = strtotime($iDate); $yrIn = date('Y',$dtIn); $doYr = ($yrIn != $iYear); $out = ''; if ($doYr) { $out .= $iSmallerPfx; }	$ftIn = date('m/d',$dtIn); $out .= $ftIn; if ($doYr) { $out .= ' '.$yrIn; $out .= $iSmallerSfx; }	return $out; } }

function wfSpecialVbzAdmin { // This registers the page's class. I think. global $wgRequest;

$app = new SpecialVbzAdmin($wgRequest); } function NextSeq($iData) { if ($iData->HasRows) { $intMax = 0; while ($iData->NextRow) { if ($iData->Seq > $intMax) { $intMax = $iData->Seq; }	}	return $intMax+1; } else { return 1; } }

/* DEACTIVATED 2010-11-08 function VbzDb { static $objDb;

if (!isset($objDb)) { $objDb = new clsVbzAdminData(KS_DB_VBZCART); $objDb->Open; }   return $objDb; } class SpecialVbzAdmin extends SpecialPageApp { protected $args; protected $objDB;

public function __construct { global $wgMessageCache,$wgUser; global $vgUserName,$vgPage;

parent::__construct( 'VbzAdmin' ); $this->includable( TRUE ); $this->SetTitle('VbzAdmin'); $vgUserName = 'wiki:'.$wgUser->getName; $vgPage = $this; }   /*      USAGE: Must be called before parent::SetHeaders */   public function SetTitle($iText) { global $wgMessageCache;

$wgMessageCache->addMessage('vbzadmin',$iText); }   protected function DB { if (!isset($this->objDB)) { $this->objDB = new clsVbzAdminData(KS_DB_VBZCART); $this->objDB->Open; }	return $this->objDB; }   function execute( $par ) { global $wgUser;

$doAdmin = $wgUser->isAllowed('editinterface'); $this->GetArgs($par);

if ($doAdmin) { $this->RegObjs($this->ClassList); $this->HandlePageArgs; }

$this->setHeaders;

$this->doMenu($doAdmin);

if ($doAdmin) { $this->doAdmin; } else { $this->doUser; }   }    protected function doMenu($iAdmin) { global $wgOut;

$wtSelf = 'Special:'.$this->name; $objMenu = new clsMenu($wtSelf); if ($iAdmin) { $objMenu->Add($objRow = new clsMenuRow('Stock','menu.stock')); $objRow->Add(new clsMenuItem('stock places','place')); $objRow->Add(new clsMenuItem('stock bins','bin')); $objMenu->Add($objRow = new clsMenuRow('Catalog','menu.cat')); $objRow->Add(new clsMenuItem('suppliers','supp')); $objRow->Add(new clsMenuItem('images','cat.img')); $objRow->Add(new clsMenuItem('topics','topic')); $objRow->Add(new clsMenuItem('search','cat.search')); $objMenu->Add($objRow = new clsMenuRow('Restocks','menu.rstk')); $objRow->Add(new clsMenuItem('needed','rstk.need')); $objRow->Add(new clsMenuItem('expected','rstk.wait')); $objRow->Add(new clsMenuItem('past','rstk.past')); $objMenu->Add($objRow = new clsMenuRow('Orders','menu.orders')); $objRow->Add(new clsMenuItem('carts','cart')); $objRow->Add(new clsMenuItem('orders',KS_URL_PAGE_ORDER)); $objRow->Add(new clsMenuItem('charges','chg')); $objMenu->Add($objRow = new clsMenuRow('Ship','menu.ship')); $objRow->Add(new clsMenuItem('items to ship','toship')); $objRow->Add(new clsMenuItem('shipments','shpmt')); $objMenu->Add($objRow = new clsMenuRow('Utilities','menu.utils')); $objRow->Add(new clsMenuItem('cache tables','cache')); $objRow->Add(new clsMenuItem('ccard encryption','migr.encr')); $objRow->Add(new clsMenuItem('update stats','util.stats')); $objRow->Add(new clsMenuItem('price list','util.plist')); $objRow->Add(new clsMenuItem('inventory','util.inv')); $objMenu->Add($objRow = new clsMenuRow('Logs','menu.logs')); $objRow->Add(new clsMenuItem('general','log.misc')); $objRow->Add(new clsMenuItem('carts','log.cart')); }	$wgOut->addHTML(' ');

// a little diagnostic info $isFnd = FALSE; $out .= ' '; if (is_object($this->tbl)) { $out .= 'table class: '.get_class($this->tbl).''; $isFnd = TRUE; }	if (is_object($this->obj)) { $out .'record class: '.get_class($this->obj).''; $isFnd = TRUE; }	if (!$isFnd) { $out .= 'No classes found for page ['.$this->page.'].'; }	$out .= ' '; $wgOut->addHTML($out);	$out = '';

}   protected function ClassList { $ar = array(	 //'clsAdminCacheFlows',	  //'clsAdminCacheProc',	  //'clsAdminCacheTables',	  //'VbzAdminCartLines',	  //'VbzAdminCartLog',	  'VbzAdminCarts',	  'VbzAdminCatalogs',	  'clsAdminCustAddrs',	  'VbzAdminCustCards',	  'clsAdminCustEmails',	  'clsAdminCustNames',	  'clsAdminCustPhones',	  'VbzAdminCusts',	  'VbzAdminDepts',	  'clsAdminEvents',	  'clsAdminImages',	  'VbzAdminItems',	  //'clsAdminItems_info_Cat',	  'VbzAdminOrderChgs',	  'VbzAdminOrderItems',	  //'VbzAdminOrderPulls',	  'VbzAdminOrders',	  'VbzAdminOrderTrxacts',	  //'VbzAdminOrderTrxTypes',	  'VbzAdminOrderMsgs',	  //'clsAdminRstkReqItems',	  'clsAdminRstkReqs',	  //'VbzAdminSessions',	  'VbzAdminStkItems',	  'VbzAdminSuppliers',	  'VbzAdminTitles',	  //'VbzAdminTitles_info_Cat',	  //'VbzAdminTitles_info_Item',	  //'clsAdminTitleTopic_Titles',	  //'clsAdminTitleTopic_Topics',	  'clsAdminTopics',

//'clsCMITems', 'clsCtgGroups', //'clsCtgTitles', //'clsOrderPullTypes', 'clsPackages', //'clsPkgLines', 'clsShipments', //'clsStkLog', //'clsTitleTopics_base', //'clsRstkRcdLines', 'clsRstkRcds', //'VbzStockBinLog', 'VbzStockBins', 'VbzStockPlaces', );	return $ar;   }    /*-      PURPOSE: do stuff that only admins are allowed to do    */    public function doAdmin {	global $wgOut;	$obj = $this->obj;	$tbl = $this->tbl;

$out =NULL; $didPage = FALSE;

if (is_object($obj)) { $out = $obj->AdminPage; $didPage = TRUE; } elseif (is_object($tbl)) { $out = $tbl->AdminPage; $didPage = TRUE; }

if (!$didPage) { $page = $this->page; $idObj = $this->idObj; $doObj = $this->doObj;

if (!is_null($page)) { $dbVBZ = $this->DB;

$out = NULL; switch ($page) { case 'cache': case 'cache.tbl': case 'cache.proc': $this->DB->CacheMgr->MenuDispatch($page,$idObj); break; case 'cat.search': $tbl = $dbVBZ->Titles_Cat; $out = $tbl->SearchPage; break; case 'log.cart': $objTbl = new VbzAdminCartLog($dbVBZ); $out = $objTbl->AdminPage; break; case 'log.misc': $objLog = new clsAdminEvents($dbVBZ); $objLog->ListPage; break; case 'migr.encr': $objCards = $dbVBZ->CustCards; $objCards->EncryptAdmin; break; case 'rstk.need': $objTbl = $dbVBZ->RstkReqs; $objTbl->AdminItemsNeeded; break; case 'rstk.past': $objTbl = $dbVBZ->RstkReqs; $objRows = $objTbl->RowsInactive; $out = $objRows->AdminList; break; case 'rstk-rcd': $objTbl = $dbVBZ->RstkRcds; $objRow = $objTbl->GetItem($idObj); $out = $objRow->AdminPage; break; case 'rstk-req': $objTbl = $dbVBZ->RstkReqs; $objRow = $objTbl->GetItem($idObj); $out = $objRow->AdminPage; break; case 'rstk.wait': $objTbl = $dbVBZ->RstkReqs; $objRows = $objTbl->RowsActive; $out = $objRows->AdminList; break; case 'toship': $this->doStockToShip; break; case 'util.stats': $this->DoUpdateStats; break; case 'util.plist': $this->DoPriceList; break; case 'util.inv': $this->DoInvCompare; break; default: $out = 'Select from the menu above.'; }	   }	}	if (!is_null($out)) { $wgOut->AddWikiText($out,TRUE); }   }    public function doCharges { global $wgOut; global $vgPage;

$doAll = $vgPage->Arg('all'); $strMnuAll = $this->SelfLink_WT(array('all' => TRUE),'all'); $strMnuUnp = $this->SelfLink_WT(array('all' => FALSE),'to process');

$objTbl = new VbzAdminOrderChgs($this->DB); if ($doAll) { $strMenu = "$strMnuUnp .. $strMnuAll"; $strDescr = ' in database'; $sqlFilt = NULL; } else { $strMenu = "$strMnuUnp .. $strMnuAll"; $strDescr = ' to be processed'; $sqlFilt = '(WhenDecided IS NULL) AND ((WhenXmitted IS NULL) OR isSuccess) AND (WhenVoided IS NULL) AND (WhenHeldUp IS NULL)'; }	$objRows = $objTbl->GetData($sqlFilt,NULL,'ID DESC'); $wgOut->AddWikiText("Show Charges: $strMenu", TRUE); $arArgs['descr'] = $strDescr; $wgOut->AddWikiText($objRows->AdminTable($arArgs),TRUE); }   public function doUser { global $wgOut; /*	PURPOSE: do only stuff that regular users are allowed to do $wgOut->AddWikiText('Hello regular user! I haven\'t written anything for you yet, but soon (Josh permitting).'); }

// individual admin functions public function doStockToShip { global $wgOut;

$dbVBZ = $this->DB; $out = '==Stock to Ship=='."\n"; $wgOut->addWikiText($out,TRUE);	$out = ''; $objRows = $dbVBZ->DataSet('SELECT * FROM '.KSQL_DS_ITEMS_TO_SHIP); if ($objRows->hasRows) { $out = "{| class=sortable \n|-\n! item || order || # needed || # avail || bin"; while ($objRows->NextRow) { $idItem = $objRows->ID_Item; $idOrd = $objRows->ID_Order; $idBin = $objRows->ID_Bin; $strOrd = $objRows->OrdText?$objRows->OrdText:'?ord#?'; $wtItem = ' '.SelfLink_Page('item','id',$idItem,$objRows->ItemText); $wtOrder = ' '.SelfLink_Page(KS_URL_PAGE_ORDER,'id',$idOrd,$strOrd); $wtBin = ' '.SelfLink_Page('bin','id',$idBin,$objRows->BinText); $wtQtyNeed = $objRows->QtyOpen; $intQtyForShip = $objRows->QtyForSale; $intQtyForSale = $objRows->QtyForSale; $wtQtyAvail = $intQtyForShip; if ($intQtyForShip != $intQtyForSale) { $wtQtyAvail .= ' ('.$intQtyForSale.')'; }		$out .= "\n|-\n| $wtItem || $wtOrder || $wtQtyNeed || $wtQtyAvail || $wtBin"; }	   $out .= "\n|}\n(Retrieval complete.)"; } else { $out = 'No stock items available for open orders.'; }	$wgOut->addWikiText($out,TRUE);	$out = ''; } /*   public function doCacheTables { $this->DB->CacheMgr->AdminPage; }   public function doSuppliers { $objSupps = $this->DB->Suppliers; $objSupps->ListPage; }   public function doSupplier($iID) { $objSupps = $this->DB->Suppliers; $objSupp = $objSupps->GetItem($iID); return $objSupp->AdminPage; }   public function doDept($iID) { $objDepts = $this->DB->Depts; $objDept = $objDepts->GetItem($iID); return $objDept->InfoPage; }   public function doTitle($iID) { $objTitles = $this->DB->Titles; $objTitle = $objTitles->GetItem($iID); return $objTitle->InfoPage; }   public function doItem($iID) { $objTbl = $this->DB->Items; $objRow = $objTbl->GetItem($iID); return $objRow->InfoPage; }   public function doImgAdmin { $objTbl = $this->DB->Images; return $objTbl->AdminPage_Unassigned; }   /*      TO DO: This really should be rewritten as a method of clsContactNode USED BY: VbzAdminOrder::DoSetupCart in admin.ord.php HISTORY: 2011-04-17 using AdminLink on customer object instead of hand-building the links */   function CheckPersonMatches(clsPerson $iPerson,VbzAdminCart $iCart) { $objDB = $this->DB; $objPage = $this; $objPerson = $iPerson; $objCart = $iCart; //$arLink = $iLinkArr;

$strName = $objPerson->FormName; $strDescr = $objPerson->Descr;

$objName = $iPerson->Node('name'); if (!is_object($objName)) { echo $iPerson->DumpHTML; throw new exception('Internal error: missing object in tree.'); }	$strCustName = $objName->Value;

$out = "\n Contact information for $strDescr:";

$out .= "\n Customer: ".$strCustName; $out .= "\n"; if ($objCart->DataItem(KSI_SHIP_IS_CARD)) { $strAddrShip = 'Address'; } else { //	   $strCardAddr = $objPerson->Card->Addr->AsSingleLine; $objPay = $objPerson->Payment; if (is_null($objPay)) { /*		 2011-10-04 this isn't a problem as long as _one_ of the calls has payment in iPerson echo 'Person object tree:'; echo $objPerson->DumpHTML; throw new exception('Payment object is NULL'); */		$strCardAddr = NULL;	// so later code knows not to try using it	   } else { $strCardAddr = $objPay->Addr->AsSingleLine; $out .= "\n Card Address: ".$strCardAddr.''; $strAddrShip = 'Shipping Address'; }	}	if ($objPerson->HasContact) { $objAddr = $objPerson->Contact->Addr; if ($objAddr) { $strShipAddr = $objAddr->AsSingleLine; $out .= "\n $strAddrShip: ".$strShipAddr.''; $out .= "\nSearching as: ".clsCustAddrs::Searchable($strShipAddr).''; }	   if ($objPerson->Contact->HasEmail) { $strEmail = $objPerson->Contact->Email->Value; $out .= "\n Email: ".$strEmail.''; }	   if ($objPerson->Contact->HasPhone) { $strPhone = $objPerson->Contact->Phone->Value; $out .= "\n Phone: ".$strPhone.''; }	}	$out .= "\n";

// Look for matches to existing contacts $out .= "\nChecking $strDescr for matches to existing customers..."; // -- name // --- customer $objRows = $objDB->CustNames->Find($strCustName); if ($objRows->HasRows) { while ($objRows->NextRow) { $idCont = $objRows->ID_Cust; $idName = $objRows->ID; $arSame[$idCont]['name'] = $objRows->RowCopy; }	}	// --- destination (if different) if (isset($strDestName)) { $objRows = $objDB->CustNames->Find($strDestName); if ($objRows->HasRows) { while ($objRows->NextRow) { $idCont = $objRows->ID_Cust; $idName = $objRows->ID; $arSame[$idCont]['name'] = $objRows->RowCopy; }	   }	}

// -- address // --- card if ($objCart->DataItem(KSI_SHIP_IS_CARD)) { $strAddrShip = 'addr'; } else { $strAddrShip = 'addr-ship'; if (!is_null($strCardAddr)) { $objRows = $objDB->CustAddrs->Find($strCardAddr); if ($objRows->HasRows) { while ($objRows->NextRow) { $idCont = $objRows->ID_Cust; $idName = $objRows->ID; $arSame[$idCont]['addr-card'] = $objRows->RowCopy; }		}	   }	}	// --- shipping if (isset($strCardAddr)) { $objRows = $objDB->CustAddrs->Find($strCardAddr); if ($objRows->HasRows) { while ($objRows->NextRow) { $idCont = $objRows->ID_Cust; $idName = $objRows->ID; $arSame[$idCont][$strAddrShip] = $objRows->RowCopy; }	   }	}	if (isset($objPerson->Contact)) { // -- phone if (isset($strPhone)) { $objRows = $objDB->CustPhones->Find($strPhone); if ($objRows->HasRows) { while ($objRows->NextRow) { $idCont = $objRows->ID_Cust; $idName = $objRows->ID; $arSame[$idCont]['phone'] = $objRows->RowCopy; }		}	   }

// -- email if (isset($strEmail)) {	// sometimes this isn't set; this may be a bug. figure out why later. $objRows = $objDB->CustEmails->Find($strEmail); if ($objRows->HasRows) { while ($objRows->NextRow) { $idCont = $objRows->ID_Cust; $idName = $objRows->ID; $arSame[$idCont]['email'] = $objRows->RowCopy; }		}	   }	}	// -- credit card $strCard = $objCart->DataItem(KSI_CUST_CARD_NUM); $objRows = $objDB->CustCards->Find($strCard); if ($objRows->HasRows) { while ($objRows->NextRow) { $idCont = $objRows->ID_Cust; $idName = $objRows->ID; $arSame[$idCont]['card'] = $objRows->RowCopy; }	}	// Report any matches found: if (isset($arSame)) { $out .= "\nChoose how to resolve the match:"; $out .= "\n"; foreach ($arSame as $idCont=>$val) { $objCust = $objDB->Custs($idCont); $htLink = $objCust->AdminLink_status;

$out .= "\n<input type=radio name=\"$strName\" value=\"$idCont\">Use contact #$htLink</a>:"; $out .= "\n"; foreach($val as $vkey=>$vval) { $strDescr = $vval->ShortDescr; $out .= "\n $vkey: $strDescr</li>"; }		$out .= "\n</ul></li>"; }	   $out .= "\n<input type=radio name=\"$strName\" value=\"new\">Create new contact record</li>"; $out .= "\n</ul>"; } else { // 2011-07-28 removing "create new records" link; should be created on import if none found //	   $htURL = $objPage->SelfURL(array('allnew'=>TRUE)); //	   $htLink = '<a href="'.$htURL.'">create new records</a>'; $out .= "\n No matches found; new contact records will be created."; $out .= '<input type=hidden name="cust" value=new /><input type=hidden name="ship" value=new />'; }	return $out; }   protected function DoUpdateStats { $objVars = $this->objDB->VarsGlobal;

$sqlStkQty = 'SELECT SUM(QtyForSale) AS Qty FROM qryStkItms_for_sale'; $intStkQty = 0;

$objVars->Val('stat.stock.qty',$intStkQty);	// total stock quantity }   protected function DoPriceList { global $wgOut,$wgRequest; global $vgPage;

$vgPage->UseHTML;

$doCheck = $wgRequest->GetBool('btnCheck');

$out = NULL; $out .= 'Enter catalog numbers or item IDs:';

if ($doCheck) { $txt = $wgRequest->GetText('list'); $xts = new xtString($txt); $xts->ReplaceSequence("\n\t ", ' ',0); $ar = explode (' ',$xts->Value);

$pos = strpos ($txt,':');	// colon means there are quantities $hasQtys = is_numeric($pos);

$htTxt = htmlspecialchars($txt); $htTxtRows = 3; } else { $htTxt = ''; $htTxtRows = 30; }

if ($doCheck) { $out .= ' ';	// item listing table $out .= '  ';	// outer table }

$out .= ' '; $out .= '<textarea name=list rows='.$htTxtRows.'>'.$htTxt.' '; $out .= '<input type=submit name=btnCheck value="Check" />'; $out .= ' ';

$wgOut->AddHTML($out); return NULL;	// caller expects wikitext }   private function DoInvCompare { global $vgPage; global $wgOut,$wgRequest;

$txtStart = $wgRequest->GetText('txtStart'); $txtFinish = $wgRequest->GetText('txtFinish');

$vgPage->UseHTML;

$htStart = htmlspecialchars($txtStart); $htFinish = htmlspecialchars($txtFinish);

$fxParse = function($iText) { $ar = preg_split('/ /',$iText); foreach ($ar as $item) { list($id,$qty) = preg_split('/:/',$item); $arOut[$id] = $qty; }	   return $arOut; };

$arStart = $fxParse($txtStart); $arFinish = $fxParse($txtFinish);

$arDiff = array; foreach ($arStart as $id => $qty) { $qtyFinish = nzArray($arFinish,$id); if ($qty != $qtyFinish) { $arDiff[$id] = 'old:'.$qty.' new:'.$qtyFinish; }	}	foreach ($arFinish as $id => $qty) { $qtyStart = nzArray($arStart,$id); if (!array_key_exists($id,$arStart)) { $arDiff[$id] = 'new:'.$qty; }	}

$out = '<form method=post action="'.$vgPage->SelfURL.'">'; $out .= 'Display difference between two inventory counts:'; $out .= ' '; $out .= ' ';

if (count($arDiff) > 0) { $tbl = $this->DB->Items; $out .= ' '; } else { $cnt = count($arStart); $out .= $cnt.' item'.Pluralize($cnt).' compared - inventories are identical.'; }

$wgOut->AddHTML($out); return NULL;	// caller expects wikitext } }

/* ***** class VbzAdminSuppliers extends clsSuppliers { public function __construct($iDB) { parent::__construct($iDB); $this->ClassSng('VbzAdminSupplier'); }   public function AdminPage { global $wgOut; global $vgPage;
 * CATALOG DATA

$vgPage->UseWiki;

$out = '==Suppliers=='; $wgOut->addWikiText($out,TRUE);	$out = ''; $objRecs = $this->GetData; if ($objRecs->HasRows) { $out = "{| class=sortable\n|-\n! ID || A? || Code || Actions || Name"; $isOdd = TRUE; while ($objRecs->NextRow) { $strCatKey = $objRecs->CatKey; $id = $objRecs->ID; $wtActions = '['.KWP_CAT.strtolower($strCatKey)." shop] " .$objRecs->AdminLink('manage'); $wtCatNum = $strCatKey; $wtStyle = $isOdd?'background:#ffffff;':'background:#cccccc;'; $isActive = $objRecs->isActive; if ($isActive) { $wtName = .$objRecs->Name.; } else { $wtName = $objRecs->Name; $wtStyle .= ' color: #888888;'; }		$out .= "\n|- style=\"$wtStyle\"\n| ".$id .' || '.($isActive?'&radic;':'') .' || '.$wtCatNum .' || '.$wtActions .' || '.$wtName; $isOdd = !$isOdd; }	   $out .= "\n|}"; } else { $out = 'No suppliers have been created yet.'; }	$wgOut->addWikiText($out,TRUE);	$out = ''; } } class VbzAdminSupplier extends clsSupplier { /*====     HISTORY: 2010-12-05 boilerplate event logging added to VbzAdminSupplier */   protected function Log { if (!is_object($this->logger)) { $this->logger = new clsLogger_DataSet($this,$this->objDB->Events); }	return $this->logger; }   public function StartEvent(array $iArgs) { return $this->Log->StartEvent($iArgs); }   public function FinishEvent(array $iArgs=NULL) { return $this->Log->FinishEvent($iArgs); }   public function EventListing { return $this->Log->EventListing; }   //====    /*      HISTORY: 2010-10-11 Replaced existing code with call to static function */   public function AdminLink($iText=NULL,$iPopup=NULL,array $iarArgs=NULL) { return clsAdminData::_AdminLink($this,$iText,$iPopup,$iarArgs); }   public function AdminLink_name { return $this->AdminLink($this->Name); }   /*      HISTORY: 2010-11-04 Created so AdminPage can use HTML 2011-02-16 Disabled until I figure out why it isn't redundant */ /*   public function ShopLink($iText=NULL) { return '<a href="'.KWP_CAT.strtolower($this->CatKey).'">'.$iText.'</a>'; }   public function PageTitle { global $vgPage;

$doShow = $vgPage->Arg('show'); return $this->Value('CatKey').':'.$doShow; }   /*      RETURNS: object for Supplier's Topic HISTORY: 2011-10-01 written -- replacing Departments with Topics */   public function TopicObj { $id = $this->Value('ID_Topic'); if (is_null($id)) { return NULL; } else { $row = $this->Engine->Topics($id); return $row; }   }    /*      RETURNS: nicely-formatted link to Supplier's Topic HISTORY: 2011-10-01 written -- replacing Departments with Topics */   public function TopicLink($iNone=n/a) { $row = $this->TopicObj; if (is_object($row)) { return $row->AdminLink_name; } else { return $iNone; }   }    /*    */    public function AdminPage { global $wgOut,$wgRequest; global $vgPage,$vgOut;

$vgPage->UseHTML; $out = NULL;

$doEdit = $vgPage->Arg('edit'); $doSave = $wgRequest->GetBool('btnSave');

// save edits before showing events $ftSaveStatus = NULL; if ($doEdit || $doSave) { $this->BuildEditForm; if ($doSave) { $ftSaveStatus = $this->AdminSave; }	}

$strCatKey = $this->CatKey; $strName = $this->Name;

$doDeptAdd = $vgPage->Arg('add.dept');

$objPage = new clsWikiFormatter($vgPage); $objSection = new clsWikiSection($objPage,$strName.' ('.$strCatKey.')'); $out = $objSection->Generate; $wgOut->AddHTML($out); $out = '';

$objSection = new clsWikiSection($objPage,'Current Record (ID '.$this->ID.')',NULL,3); $objSection->ToggleAdd('edit'); $out = $objSection->Generate;

if ($doEdit) { $out .= $objSection->FormOpen;

$objForm = $this->objForm; $ftName	= $objForm->Render('Name'); $ftCatKey	= $objForm->Render('CatKey'); $ftTopic	= $objForm->Render('ID_Topic'); $ftActive	= $objForm->Render('isActive'); } else { $ftName	= $vgOut->InternalLink($strName); $ftCatKey	= $this->ShopLink($strCatKey); $ftTopic	= $this->TopicLink; $ftActive	= NoYes($this->isActive); }

$ftID = $this->AdminLink;

$out .= $vgOut->TableOpen;

$out .= $vgOut->TblRowOpen; $out .= $vgOut->TblCell('ID:','align=right'); $out .= $vgOut->TblCell($ftID); $out .= $vgOut->TblRowShut;

$out .= $vgOut->TblRowOpen; $out .= $vgOut->TblCell('Name:','align=right'); $out .= $vgOut->TblCell($ftName); $out .= $vgOut->TblRowShut;

$out .= $vgOut->TblRowOpen; $out .= $vgOut->TblCell('CatKey:','align=right'); $out .= $vgOut->TblCell($ftCatKey); $out .= $vgOut->TblRowShut;

$out .= $vgOut->TblRowOpen; $out .= $vgOut->TblCell('Topic:','align=right'); $out .= $vgOut->TblCell($ftTopic); $out .= $vgOut->TblRowShut;

$out .= $vgOut->TblRowOpen; $out .= $vgOut->TblCell('Active:','align=right'); $out .= $vgOut->TblCell($ftActive); $out .= $vgOut->TblRowShut;

$out .= $vgOut->TableShut;

if ($doEdit) { $out .= 'Edit notes: <input type=text name="EvNotes" size=40> '; $out .= '<input type=submit name="btnSave" value="Save">'; $out .= '<input type=submit name="btnCancel" value="Cancel">'; $out .= '<input type=reset value="Reset">'; $out .= ' '; }

$vgOut->addText($out,TRUE);	$out = '';

// show submenu $arMnu = array(	 'dept'	=> '.departments.'.$strName.' departments',	  'cat'		=> '.catalogs.'.$strName.' wholesale catalogs',	  'rreq'	=> '.restocks.'.$strName.' restock requests',	  'ctg'		=> '.catalog groups.groups for organizing '.$strName.' catalog items'	  ); $out = 'Manage: '.$vgPage->SelfLinkMenu('show',$arMnu); $vgOut->AddText($out); $out = '';

$doShow = $vgPage->Arg('show');

//$vgPage->UseWiki; switch ($doShow) { /* Some remediation needed here. Some of these output in wikitext, others in HTML. All of them seem to output directly, rather than returning rendered text. case 'dept': $objSection = new clsWikiSection($objPage,'Departments',NULL,3); $objSection->ToggleAdd('add','add a department to '.$strName,'add.dept'); $out = $objSection->Generate; $wgOut->addHTML($out,TRUE); $out = ''; $out .= $this->DeptsListing; break; case 'cat': $objSection = new clsWikiSection($objPage,'Catalogs',NULL,3); $arLink = array(	     'page'	=> $this->objDB->CtgSrcs->ActionKey,	      'id'	=> 'new',	      'supp'	=> $this->ID	      ); $objSection->ActionAdd('add','add a catalog to '.$strName,FALSE,$arLink); $out = $objSection->Generate; $wgOut->addHTML($out,TRUE); $out = ''; $out .= $this->CatalogAdmin; break; case 'rreq': $objSection = new clsWikiSection($objPage,'Restock Requests',NULL,3); $out = $objSection->Generate; $wgOut->addHTML($out,TRUE); $out = ''; $out .= $this->RstkReqAdmin; break; case 'ctg': $objSection = new clsWikiSection($objPage,'Catalog Groups','catalog management groups',3); $objSection->ArgsToKeep(array('show','page','id')); $objSection->ToggleAdd('edit','edit the list of groups','edit.ctg'); $out = $objSection->Generate; $wgOut->addHTML($out,TRUE); $out = ''; $doEdit = $vgPage->Arg('edit.ctg'); $out .= $this->CtgGrpAdmin($doEdit); break; default: $out = ''; }	$vgOut->addText($out); }   /*      ACTION: Save user changes to the record HISTORY: 2010-11-06 copied from VbzStockBin to VbzAdminItem 2011-01-26 copied from VbzAdminItem to clsAdminTopic 2011-10-02 copied from clsAdminTopic to VbzAdminSupplier */   public function AdminSave { global $vgOut;

$out = $this->objForm->Save; $vgOut->AddText($out); }   /*      HISTORY: 2010-11-06 adapted from VbzStockBin for VbzAdminTitle 2011-10-01 adapted from VbzAdminTitle for VbzAdminSupplier */   private function BuildEditForm { global $vgOut;

if (is_null($this->objForm)) { // create fields & controls $objForm = new clsForm_DataSet($this,$vgOut); //$objCtrls = new clsCtrls($objForm->Fields); //$objCtrls = $objForm;

$objForm->AddField(new clsField('Name'),		new clsCtrlHTML(array('size'=>25))); $objForm->AddField(new clsFieldNum('ID_Topic'),	new clsCtrlHTML); $objForm->AddField(new clsField('CatKey'),		new clsCtrlHTML(array('size'=>8))); $objForm->AddField(new clsFieldBool('isActive'),	new clsCtrlHTML_CheckBox); $objForm->AddField(new clsField('Notes'),	new clsCtrlHTML_TextArea(array('height'=>3,'width'=>50)));

$this->objForm = $objForm; //$this->objCtrls = $objCtrls; }   }    public function DeptsListing { $out = $this->objDB->Depts->Listing_forSupp($this->ID,$this); return $out; } /*%%%%    SECTION: Data Entry Management PROCESS: * User enters a list of Titles or Items in a textarea box, one per line. * Each line is checked against Supplier catalog #s * if found, shows details for the title/item and provides option to approve it in the final resultset * if not found, gives user the option to give more information identifying the Title/Item, such as	our catalog # (or what our catalog # would be if the Title/Item existed in the database) */   /*      PURPOSE: renders form for reconciliation of a user-entered list of Titles from a Supplier source document INPUT: $iTitles[line #] = array of title information, format to be determined ['id'] = ID of Title record to be approved as matching the input ['scat'] = supplier's catalog number ['ocat'] = our catalog number (may be hypothetical) ['$buy'] = cost to us	 ['$sell'] = our selling price (to customer) ['name'] = descriptive name for the Title RETURNS: HTML code for reconciliation form. Does not include tags or buttons. */ /*   public function AdminTitles_form_entry(array $iTitles) { die('This function is not ready yet!');

if (count($iTitles) > 0) { $isOdd = TRUE; $isReady = TRUE;	// ready to enter - all items have been identified $out .= ' '; } else { $out = 'No titles entered.'; }	return $out; }   /*      ACTION: Receives user data from form rendered by AdminItems_form_entry INPUT: http POST data from Item reconciliation form id[line #] = array of Item IDs, where known name[line #] = array of item descriptions qty[line #] = array of item quantities scat[line #] = array of supplier catalog numbers for each line, entered by user ocat[line #] = array of our catalog numbers for each line, entered by user $buy[line #] = array of price-to-us for each line, entered by user $sell[line #] = array of price-to-customer for each line, entered by user NOTE: sell[] is not currently used in any known scenario. Possibly it should be removed. RETURNS: array of all received data, but indexed by line number first includes the following fields: ['qty'] = item quantity ['ocat'] = catalog number entered by the user to be used either for looking up the item or creating it     FUTURE: This should be generalized somehow */   public function AdminItems_form_receive { global $wgRequest;

$arCols = array('id','name','qty','ocat','scat','$buy','$sell','do-upd-scat','do-upd-desc'); foreach ($arCols as $col) { $arOut[$col] = $wgRequest->GetArray($col); }	$arRtn = ArrayPivot($arOut); //echo ' '.print_r($arRtn,TRUE).' '; return $arRtn; }   /*      ACTION: Check item data against database and return status information INPUT: $iItems[line #]: array in format returned by AdminItems_form_receive RETURNS: ['#add'] = number of rows which need to be added to the catalog ['#use'] = number of rows which are ready to be used (item exists in catalog) ['rows'] = input data with additional fields: ['@state']: status of line as indicated by one of the following strings: 'use' = item has been found, so this line is ready to use 'add' = item not found, but there is enough information to create it	   ['@obj'] is the Item object (only included if @state = 'use') */   public function AdminItems_data_check(array $iItems) { if (count($iItems) > 0) { $cntUse = 0; $cntAdd = 0; $cntUpd = 0;	// count of updatable fields $arRows = array; $strCatPfx = $this->Value('CatKey'); foreach ($iItems as $idx => $data) { $idItem = nz($data['id']);

$strOCatRaw = nz($data['ocat']); $strOCatFull = $strCatPfx.'-'.$strOCatRaw; $gotOCat = !empty($strOCatRaw);

$strSCat = nz($data['scat']);

$data['@state'] = NULL; $data['@obj'] = NULL; if (empty($idItem)) { if ($gotOCat) { // look up item using our catalog # $objItem = $this->objDB->Items->Get_byCatNum($strOCatFull); } else { // look up item using supplier catalog # $objItem = $this->GetItem_bySCatNum($strSCat); }		   if (is_null($objItem)) { if ($gotOCat) { $data['@state'] = 'add'; $cntAdd++; }		   }		} else { $objItem = $this->objDB->Items($idItem); }		if (is_object($objItem)) { $data['@obj'] = $objItem; $data['@state'] = 'use'; $cntUse++;

// compare entered values with recorded values // -- supplier catalog # $strSCatEnt = $strSCat;			// entered $strSCatRec = $objItem->Supp_CatNum;	// recorded if ($strSCatEnt != $strSCatRec) { $cntUpd++; $data['@can-upd-scat'] = TRUE; } else { $data['@can-upd-scat'] = FALSE; }		   // -- title $strDescrEnt = nz($data['name']);		// entered $strDescrRec = $objItem->Descr;		// recorded if ($strDescrEnt != $strDescrRec) { $cntUpd++; $data['@can-upd-desc'] = TRUE; } else { $data['@can-upd-desc'] = FALSE; }		}		$arRows[$idx] = $data; }	// foreach ($iItems...) } else { $arRtn = NULL; }	$arRtn = array(	 'rows' => $arRows,	  '#use' => $cntUse,	  '#upd' => $cntUpd,	  '#add' => $cntAdd); return $arRtn; }   /*      ACTION: Creates listed catalog items INPUT: Array of items as returned by AdminItems_data_check RETURNS: HTML to display (messages) */   public function AdminItems_data_add(array $iItems) { $out = '';

$tblItems = $this->objDB->Items;

$cntItems = count($iItems); $txtOCats = ''; foreach ($iItems as $idx => $row) { $txtOCats .= ' '.$row['ocat']; }	$strEv = 'Adding '.$cntItems.' item'.Pluralize($cntItems).':'.$txtOCats;

$arEv = array(	 'descr'	=> SQLValue($strEv),	  'where'	=> SQLValue(__METHOD__),	  'code'	=> SQLValue('RI+')	// Reconcile Items: add	  ); $this->StartEvent($arEv);

$strCatPfx = $this->Value('CatKey'); foreach ($iItems as $idx => $row) { $strOCat = $strCatPfx.'-'.strtoupper($row['ocat']); $arAdd = array(	     'CatNum'		=> SQLValue($strOCat),	      'isCurrent'	=> 'FALSE',	// we don't actually know anything about availability yet	      'ID_Title'	=> 0,		// needs to be assigned to a title	      'Descr'		=> SQLValue($row['name']),	      'Supp_CatNum'	=> SQLValue($row['scat'])	      ); if (!empty($row['$buy'])) { $arAdd['PriceBuy'] = SQLValue($row['$buy']); }	   if (!empty($row['$sell'])) { $arAdd['PriceSell'] = SQLValue($row['$sell']); }	   //$out .= ' '.print_r($arAdd,TRUE).' '; $tblItems->Insert($arAdd); }	$out = $strEv; $this->FinishEvent; return $out; }   /*      ACTION: Renders drop-down box of all Suppliers, with the current one as default USED BY: Restock edit screen HISTORY: 2011-03-02 What happened? Apparently this method used to exist, but got deleted without a trace. Rewriting from scratch. */   public function DropDown($iName=NULL,$iNone=NULL) { $strName = is_null($iName)?($this->Table->ActionKey):$iName;	// control name defaults to action key

$rs = $this->Table->GetData;

if ($rs->HasRows) { $out = "\n<SELECT NAME=$strName>"; if (!is_null($iNone)) { $out .= DropDown_row(NULL,$iNone,$iDefault); }	   while ($rs->NextRow) { $id = $rs->Value('ID'); $txtAbbr = $rs->Value('CatKey'); $htAbbr = is_null($txtAbbr)?'':($txtAbbr.' '); $htShow = $htAbbr.$rs->Value('Name'); $out .= DropDown_row($id,$htShow,$this->Value('ID')); }	   $out .= "\n "; return $out; } else { return NULL; }   }    /*      ACTION: Renders drop-down box of active departments for this supplier RETURNS: HTML code */   public function Depts_DropDown($iName=NULL,$iDefault=NULL,$iNone=NULL) { $objRecs = $this->objDB->Depts->Data_forSupp($this->ID,'isActive'); $out = $objRecs->DropDown($iName,$iDefault,$iNone); return $out; }   public function CatalogAdmin { $objTbl = $this->objDB->Catalogs; $objRows = $objTbl->GetData('ID_Supplier='.$this->ID,NULL,'ID DESC'); $out = $objRows->AdminList; return $out; }   public function RstkReqAdmin { $objTbl = $this->objDB->RstkReqs; $objRows = $objTbl->GetData('ID_Supplier='.$this->ID,NULL,'IFNULL(WhenOrdered,WhenCreated) DESC'); $out = $objRows->AdminList; return $out; }   public function CtgGrpAdmin($iEdit) { $objTbl = $this->objDB->CtgGrps; $id = $this->KeyValue; $objRows = $objTbl->GetData('ID_Supplier='.$id,NULL,'Sort'); $out = $objRows->AdminList($iEdit,array('ID_Supplier'=>$id)); return $out; }   /*-      ACTION: Finds the last restock request for the given supplier RETURNS: the last request by date and the last request sorted by (our) PO # */   public function LastReq { //$sqlBase = 'SELECT * FROM `rstk_req` WHERE ID_Supplier='.$this->ID; $sqlBase = 'WHERE ID_Supplier='.$this->ID; $sql = $sqlBase.' ORDER BY PurchOrdNum DESC LIMIT 1;'; //$objRow = $this->objDB->DataSet($sql); $objRow = $this->objDB->RstkReqs->DataSet($sql); $objRow->NextRow; $arOut['by purch ord'] = $objRow->RowCopy;

$sql = $sqlBase.' ORDER BY WhenOrdered DESC LIMIT 1;'; //$objRow = $this->objDB->DataSet($sql); $objRow = $this->objDB->RstkReqs->DataSet($sql); $objRow->NextRow; $arOut['by ord date'] = $objRow->RowCopy;

return $arOut; }   /*      ACTION: Checks each item in the list to see if it corresponds to a given item for the current supplier INPUT: Array of supplier catalog numbers OUTPUT: Array in this format: array[cat#] = item object (if found) or NULL (if not found) */ /*   public function FindItems(array $iList) { $objTblItems = $this->objDB->Items; foreach ($iList as $catnum) { $strCat = rtrim($catnum,';#!');	// remove comments $strCat = trim($strCat);		// remove leading & trailing whitespace if (!empty($strCat)) { $sqlFind = 'Supp_CatNum="'.$strCat.'"'; $objItem = $objTblItems->GetData($sqlFind); if (is_null($objItem)) { $arOut[$strCat] = NULL; } else { $arOut[$strCat] = $objItem->RowCopy; }	   }	}	return $arOut; }   // DEPRECATED - use GetItem_bySCatNum public function FindItem($iCatNum) { return $this->GetItem_bySCatNum($iCatNum); } }

class VbzAdminDepts extends clsDepts { public function __construct($iDB) { parent::__construct($iDB); $this->ClassSng('VbzAdminDept'); }   public function Data_forSupp($iSupp,$iFilt=NULL) { $sqlFilt = "ID_Supplier=$iSupp"; if (!is_null($iFilt)) { $sqlFilt = "($sqlFilt) AND ($iFilt)"; }	$objRecs = $this->GetData($sqlFilt,NULL,'isActive, Sort, CatKey, PageKey'); return $objRecs; }   public function Listing_forSupp($iSuppID,clsSupplier $iSuppObj=NULL) { global $wgOut;

if (is_null($iSuppObj)) { $objSupp = $this->objDB->Suppliers->GetItem($iSuppID); } else { $objSupp = $iSuppObj; }	$strSuppKey = strtolower($objSupp->CatKey);

$objRecs = $this->GetData('ID_Supplier='.$iSuppID,'VbzAdminDept','isActive, Sort, CatKey, PageKey'); if ($objRecs->HasRows) { $out = "{| class=sortable\n|-\n! ID || A? || Cat || Page || Sort || Name || Description"; $isOdd = TRUE; while ($objRecs->NextRow) { $strPageCode = $objRecs->PageKey; if (is_null($strPageCode)) { $wtPageCode = $strPageCode; } else { $strPagePath = $strSuppKey.'/'.strtolower($strPageCode); $wtPageCode = '['.KWP_CAT.$strPagePath.' '.$strPageCode.']'; }		$id = $objRecs->ID; $wtID = SelfLink_Page('dept','id',$id,$id); $wtStyle = $isOdd?'background:#ffffff;':'background:#cccccc;'; $isActive = $objRecs->isActive; if (!$isActive) { $wtStyle .= ' color: #888888;'; }		$out .= "\n|- style=\"$wtStyle\"". "\n| ".$wtID. ' || '.($isActive?'&radic;':''). ' || '.$objRecs->CatKey. ' || '.$wtPageCode. ' || '.$objRecs->Sort. ' || '.$objRecs->Name. ' || '.$objRecs->Descr; $isOdd = !$isOdd; }	   $out .= "\n|}"; } else { $out = 'This supplier has no departments.'; }	$wgOut->addWikiText($out,TRUE);	$out = ''; } } class VbzAdminDept extends clsDept { /*     HISTORY: 2010-10-11 Replaced existing code with call to static function */   public function AdminLink($iText=NULL,$iPopup=NULL,array $iarArgs=NULL) { return clsAdminData::_AdminLink($this,$iText,$iPopup,$iarArgs); }   public function AdminLink_name { $strPgKey = strtoupper($this->Value('PageKey')); $out = (is_null($strPgKey))?'':($strPgKey.' '); $out .= $this->Value('Name'); return $this->AdminLink($out); }   public function DropDown($iName=NULL,$iDefault=NULL,$iNone=NULL) { $strName = is_null($iName)?($this->Table->ActionKey):$iName;	// control name defaults to action key

if ($this->HasRows) { $out = "\n<SELECT NAME=$strName>"; if (!is_null($iNone)) { $out .= DropDown_row(NULL,$iNone,$iDefault); }	   while ($this->NextRow) { $id = $this->ID; $htAbbr = (is_null($this->PageKey))?'':($this->PageKey.' '); $htShow = $htAbbr.$this->Name; $out .= DropDown_row($id,$htShow,$iDefault); }	   $out .= "\n "; return $out; } else { return NULL; }   } /* 2010-11-06 commenting out old event handling public function StartEvent($iWhere,$iCode,$iDescr,$iNotes=NULL) { $arEvent = array(	 'type'	=> clsEvents::kTypeDept,	  'id'		=> $this->ID,	  'where'	=> $iWhere,	  'code'	=> $iCode,	  'descr'	=> $iDescr	  ); if (!is_null($iNotes)) { $arEvent['notes'] = $iNotes; }	$this->idEvent = $this->objDB->Events->StartEvent($arEvent); }   public function FinishEvent { $this->objDB->Events->FinishEvent($this->idEvent); }   /*      HISTORY: 2010-10-20 changing event logging to use helper class 2010-11-07 added StartEvent, FinishEvent */   protected function Log { if (!is_object($this->logger)) { $this->logger = new clsLogger_DataSet($this,$this->objDB->Events); }	return $this->logger; }   public function StartEvent(array $iArgs) { return $this->Log->StartEvent($iArgs); }   public function FinishEvent(array $iArgs=NULL) { return $this->Log->FinishEvent($iArgs); }   public function EventListing { return $this->Log->EventListing; /*	$objTbl = $this->objDB->Events; $objRows = $objTbl->GetData('(ModType="'.clsEvents::kTypeDept.'") AND (ModIndex='.$this->ID.')'); if ($objRows->HasRows) { $out = $objRows->AdminRows; } else { $out = 'No events found for this department.'; }	return $out; }   /*      HISTORY: 2011-09-25 renamed from InfoPage to AdminPage */   public function AdminPage { global $wgOut,$wgRequest; global $vgPage;

$strCatKey = $this->CatKey; $strPageKey = $this->PageKey; if (empty($strPageKey)) { $strShopKey = strtolower($strCatKey); } else { $strShopKey = strtolower($strPageKey); }	$strAction = $vgPage->Arg('do'); $doEdit = ($strAction == 'edit'); $doEnter = ($strAction == 'enter');

$doTitleCheck = $wgRequest->GetBool('btnCheck'); $doTitleAdd = $wgRequest->GetBool('btnAdd'); $doEnterBox = $doEnter || $doTitleCheck || $doTitleAdd;

$strTitle = '&ldquo;'.$this->Name.'&rdquo; Department';

$vgPage->UseHTML; $objPage = new clsWikiFormatter($vgPage); //$objSection = new clsWikiAdminSection($strName); $objSection = new clsWikiSection($objPage,$strTitle); //$out = $objSection->HeaderHtml_Edit; $objSection->ActionAdd('edit'); $objSection->ActionAdd('enter','enter titles for this department'); $out = $objSection->Generate;

$wgOut->AddHTML($out); $out = '';

if ($doEnterBox) { $out = ' '; }		$out .= $htNotes.' '; $out .= '<input type=hidden name="titles" value="'.htmlspecialchars($strTitles).'">'; $out .= '<input type=submit name="btnAdd" value="Add Titles">'; } else { // STAGE 3; process entered titles -- add them to the data: $strTitles = $wgRequest->getText('titles'); $arTitles = $this->ParseSubmittedTitles($strTitles); $cntTitles = count($arTitles); $strAddText = 'Add '.$cntTitles.' title'.Pluralize($cntTitles); $this->StartEvent(__METHOD__,'ADD',$strAddText,$txtNotes); $out .= ' '; $this->FinishEvent; }	   if ($doShowForm) { $out .= '<input type=submit name="btnCancel" value="Cancel">'; $out .= '<input type=reset value="Reset">'; $out .= ' '; }	   $out .= '   '; $wgOut->AddHTML($out); $out = ''; }

if ($doEdit) { $out .= $objSection->FormOpen; } else { }

$vgPage->UseWiki; $out .= "\n* ID: ".$this->ID; $out .= "\n* Supplier: ".$this->SuppObj->AdminLink_name; $out .= "\n* CatKey: $strCatKey"; $out .= "\n* PageKey: $strPageKey"; $out .= "\n* Shop: [".$this->URL_Abs.' '.$this->URL_Rel.']'; $out .= "\n===Titles==="; $wgOut->addWikiText($out,TRUE);	$out = ''; $out = $this->TitleListing; $wgOut->addWikiText($out,TRUE);	$out = '';

if ($doEdit) { $out .= '<input type=submit name="btnSave" value="Save">'; $out .= '<input type=submit name="btnCancel" value="Cancel">'; $out .= '<input type=reset value="Reset">'; $out .= ' '; }	$wgOut->AddHTML($out); $out = ''; $wgOut->addWikiText('===Events===',TRUE); $out = $this->EventListing; $wgOut->addWikiText($out,TRUE); }   public function TitleListing { $out = $this->objDB->Titles_Item->Listing_forDept($this); return $out; }   /*      ACTION: Add a list of titles to this department INPUT: iTitles: array iTitles[catkey] = name iEvent: array to be passed to event log */   public function AddTitles(array $iTitles,array $iEvent=NULL) { $cntTitles = count($iTitles); if ($cntTitles > 0) { $strDescr = 'adding '.$cntTitles.' title'.Pluralize($cntTitles); $iEvent['descr'] = StrCat($iEvent['descr'],$strDescr,' '); $iEvent['where'] = nz($iEvent['where'],__METHOD__); $iEvent['code'] = 'ADM';	// add multiple $this->StartEvent($iEvent); $cntAdded = 0; $cntError = 0; $txtAdded = ''; $txtError = ''; $tblTitles = $this->objDB->Titles; foreach ($iTitles as $catnum => $name) { $arIns = array(		 'Name'	=> SQLValue($name),		  'CatKey'	=> SQLValue($catnum),		  'ID_Dept'	=> $this->ID,		  'DateAdded'	=> 'NOW'		  		  ); $ok = $tblTitles->Insert($arIns); if ($ok) { $idNew = $tblTitles->LastID; $cntAdded++; $txtAdded .= '['.$catnum.' ID='.$idNew.']'; } else { $cntError++; $txtError .= '['.$catnum.' Error: '.$this->objDB->getError.']'; }	   }	    if ($cntError > 0) { $txtDescr = $cntError.' error'.Pluralize($cntError).': '.$txtError; $txtDescr .= ' and '; } else { $txtDescr = 'Success:'; }	   $txtDescr .= $cntAdded.' title'.Pluralize($cntAdded).' added '.$txtAdded; $arEv = array(	     'descrfin' => SQLValue($txtDescr),	      'error' => SQLValue($cntError > 0)	      ); $this->FinishEvent($arEv); }   } } class VbzAdminTitles extends clsVbzTitles { public function __construct($iDB) { parent::__construct($iDB); $this->ClassSng('VbzAdminTitle'); $this->ActionKey('title'); }   public function Add($iCatKey,$iName,$iDept,$iNotes) { // log start of event $arEvent = array(	 'type'	=> clsEvents::kTypeTitle,	  'id'		=> NULL,	  'where'	=> __METHOD__,	  'code'	=> 'add',	  'descr'	=> 'new title in dept. '.$iDept.': '.$iCatKey.': '.$iName	  ); if (!is_null($iNotes)) { $arEvent['notes'] = $iNotes; }	$idEvent = $this->objDB->Events->StartEvent($arEvent);

// add the title record $arIns = array(	 'CatKey'	=> SQLValue($iCatKey),	  'Name'	=> SQLValue($iName),	  'ID_Dept'	=> $iDept,	  'DateAdded'	=> 'NOW'	  ); $this->Insert($arIns); $idTitle = $this->objDB->NewID(__METHOD__);

// log the event's completion $arUpd = array('id' => $idTitle); $this->objDB->Events->FinishEvent($idEvent,$arUpd); return $idTitle; }   /*      HISTORY: 2010-11-15 Changed to use qryTitles_Item_info instead of qryCat_Titles_Item_stats */   public function Data_Imageless { //$sql = 'SELECT t.ID_Title AS ID, t.* FROM `qryCat_Titles_Item_stats` AS t LEFT JOIN `cat_images` AS i ON t.ID_Title=i.ID_Title' $sql = 'SELECT t.* FROM `qryTitles_Item_info` AS t LEFT JOIN `cat_images` AS i ON t.ID=i.ID_Title' .' WHERE (i.ID IS NULL) AND (cntForSale > 0)'; $this->ClassSng('VbzAdminTitle_info_Item'); $objRows = $this->DataSQL($sql); return $objRows; } } class VbzAdminTitle extends clsVbzTitle { /*     HISTORY: 2010-10-20 changing event logging to use helper class 2010-11-08 conversion complete: added StartEvent and FinishEvent, deleted commented code */   //    // BOILERPLATE: event logging protected function Log { if (!is_object($this->logger)) { $this->logger = new clsLogger_DataSet($this,$this->objDB->Events); }	return $this->logger; }   public function EventListing { return $this->Log->EventListing; }   public function StartEvent(array $iArgs) { return $this->Log->StartEvent($iArgs); }   public function FinishEvent(array $iArgs=NULL) { return $this->Log->FinishEvent($iArgs); }   // BOILERPLATE: admin HTML /*     HISTORY: 2010-10-11 Replaced existing code with call to static function */   public function AdminLink($iText=NULL,$iPopup=NULL,array $iarArgs=NULL) { return clsAdminData::_AdminLink($this,$iText,$iPopup,$iarArgs); }   public function AdminLink_name { return $this->AdminLink($this->Value('Name')); }   public function AdminURL(array $iArgs=NULL) { return clsAdminData::_AdminURL($this,$iArgs); }   // END BOILERPLATE //   /*      ACTION: Return the current title name If a value is given, update it to the new value first (returns old value) If an event array is given, log the event HISTORY: 2010-11-07 adapted from clsItem::SCatNum */   public function Name($iVal=NULL,array $iEvent=NULL) { $strOld = $this->Name; if (!is_null($iVal)) { if (is_array($iEvent)) { $iEvent['descr'] = StrCat($iEvent['descr'],'renaming title',': '); $iEvent['params'] = nz($iEvent['params']).':old=['.$strOld.']'; $iEvent['code'] = 'NN';	// new name $this->StartEvent($iEvent); }	   $arUpd = array('Name'=>SQLValue($iVal)); $this->Update($arUpd); if (is_array($iEvent)) { $this->FinishEvent; }	}	return $strOld; }   /*      RETURNS: Text suitable for use as a title for this Title (Ok, can *you* think of a better method name?) HISTORY: 2010-11-19 Created for AdminPage */   public function Title { return $this->CatNum.' '.$this->Name; }   public function DeptObj { $objDept = $this->objDB->Depts->GetItem($this->ID_Dept); return $objDept; }   public function ShopLink($iText) { return $this->LinkAbs.$iText.'</a>'; }   public function PageTitle { return $this->CatNum('-'); }   /*      RETURNS: List of titles as formatted text HISTORY: 2011-10-01 created for revised catalog entry -- no departments anymore, need more topic info */   public function TopicList_ft($iNone='-') { $rcs = $this->Topics;	// recordset of Topics for this Title if ($rcs->HasRows) { $out = ''; while ($rcs->NextRow) { $out .= ' '.$rcs->AdminLink; }	} else { $out = $iNone; }	return $out; }   /*      HISTORY: 2011-02-23 Finally renamed from InfoPage to AdminPage */   public function AdminPage { global $wgOut,$wgRequest; global $vgPage,$vgOut;

$doEdit = $vgPage->Arg('edit'); $doSave = $wgRequest->GetBool('btnSave');

$vgPage->UseHTML;

// save edits before showing events $ftSaveStatus = NULL; if ($doEdit || $doSave) { $this->BuildEditForm; if ($doSave) { $ftSaveStatus = $this->AdminSave; }	}

$isMissing = is_null($this->ID); if ($isMissing) { $strTitle = 'Missing Record'; $this->ID = $vgPage->Arg('ID'); } else { // items $ftItems = $this->ItemListing; $htImages = $this->ImageListing;	// this may update the thumbnails, so do it before showing them $htGroups = $this->CMGrpListing; $wtEvents = $this->EventListing;

$objTbl = $this->objDB->Images; $htThumbs = $objTbl->Thumbnails($this->ID); if (!is_null($htThumbs)) { $wgOut->AddHTML(' '); }

//$strCatNum = $this->CatNum; $strCatPage = $this->CatNum('/');

$strTitle = 'Title: '.$this->Title; }

$objPage = new clsWikiFormatter($vgPage); $objSection = new clsWikiSection($objPage,$strTitle); $objSection->ToggleAdd('edit'); $out = $objSection->Generate; $wgOut->AddHTML($out); $out = ''; $vgOut->AddText($ftSaveStatus);

$objSupp = $this->SuppObj; assert(is_object($objSupp));

if ($doEdit) { $out .= $objSection->FormOpen;

$ftCatKey = $this->objForm->Ctrl('CatKey')->Render; $ftSuppCN = $this->objForm->Ctrl('Supplier_CatNum')->Render; $ftSupp = $objSupp->DropDown('ID_Supp'); $ftDept = $objSupp->Depts_DropDown('ID_Dept',$this->ID_Dept); $ftName = $this->objForm->Ctrl('Name')->Render; $ftSearch = $this->objForm->Ctrl('Search')->Render; $ftDescr = $this->objForm->Ctrl('Desc')->Render; $ftNotes = $this->objForm->Ctrl('Notes')->Render; $ftWhAdded = $this->objForm->Ctrl('DateAdded')->Render; $ftWhChckd = $this->objForm->Ctrl('DateChecked')->Render; $ftWhUnavl = $this->objForm->Ctrl('DateUnavail')->Render; } else { $ftCatKey = htmlspecialchars($this->CatKey); $ftSuppCN = htmlspecialchars($this->Supplier_CatNum); $ftSupp = $objSupp->AdminLink_name; $objDept = $this->DeptObj; if (is_object($objDept)) { $ftDept = $objDept->AdminLink($objDept->Name); } else { $ftDept = 'not set'; }	   $ftName = htmlspecialchars($this->Name); $ftSearch = htmlspecialchars($this->Search); $ftDescr = htmlspecialchars($this->Desc); $ftNotes = htmlspecialchars($this->Notes); $ftWhAdded = $this->DateAdded; $ftWhChckd = $this->DateChecked; $ftWhUnavl = $this->DateUnavail; }	$out .= ' '; if ($doEdit) { $out .= 'Edit notes: <input type=text name="EvNotes" size=40> '; $out .= '<input type=submit name="btnSave" value="Save">'; $out .= '<input type=submit name="btnCancel" value="Cancel">'; $out .= '<input type=reset value="Reset">'; $out .= ' '; }	$wgOut->addHTML($out);	$out = '';

if (!$isMissing) { $wgOut->addWikiText('===Items===',TRUE); $vgOut->addText($ftItems); $wgOut->addHTML($htImages);	// Images $wgOut->addWikiText('===Topics===',TRUE); $wgOut->addHTML($this->TopicListing); $wgOut->addHTML($htGroups);	// Catalog Groups $wgOut->addWikiText('===Events===',TRUE); $wgOut->addWikiText($wtEvents,TRUE); }   }    /*      HISTORY: 2010-11-06 adapted from VbzStockBin for VbzAdminTitle */   private function BuildEditForm { global $vgOut;

if (is_null($this->objForm)) { // create fields & controls $objForm = new clsForm_DataSet($this,$vgOut); //$objCtrls = new clsCtrls($objForm->Fields); //$objCtrls = $objForm;

$objForm->AddField(new clsField('CatKey'),		new clsCtrlHTML(array('size'=>8))); $objForm->AddField(new clsField('Supplier_CatNum'),	new clsCtrlHTML(array('size'=>25))); $objForm->AddField(new clsFieldNum('ID_Supp'),	new clsCtrlHTML); $objForm->AddField(new clsFieldNum('ID_Dept'),	new clsCtrlHTML); $objForm->AddField(new clsField('Name'),		new clsCtrlHTML(array('size'=>25))); $objForm->AddField(new clsField('Search'),		new clsCtrlHTML(array('size'=>25))); $objForm->AddField(new clsField('Desc'),		new clsCtrlHTML(array('size'=>25))); $objForm->AddField(new clsField('Notes'),		new clsCtrlHTML); $objForm->AddField(new clsFieldTime('DateAdded'),	new clsCtrlHTML); $objForm->AddField(new clsFieldTime('DateChecked'),	new clsCtrlHTML); $objForm->AddField(new clsFieldTime('DateUnavail'),	new clsCtrlHTML);

$this->objForm = $objForm; //$this->objCtrls = $objCtrls; }   }    public function AdminSave { global $wgRequest; global $vgOut;

// check input for problems $strCatKeyNew = $wgRequest->GetText('CatKey'); $strCatKeyOld = $this->CatKey; $ok = TRUE;	// ok to save unless CatKey conflict $out = ''; if ($strCatKeyNew != $strCatKeyOld) { $ok = FALSE; // don't save unless CatKey passes tests // if catkey is being changed, then check new number for duplicates $objSupp = $this->SuppObj; $objMatch = $objSupp->GetTitle_byCatKey($strCatKeyNew,'VbzAdminTitle'); if (is_null($objMatch)) { $ok = TRUE; } else { /*		 Requested catkey matches an existing title. Look for other titles with the same base catkey (in same supplier), on the theory that this will represent a list of previous renames for this catkey. */		$objMatch->NextRow; $out = 'Your entered CatKey ['.$strCatKeyNew.'] has already been used for '.$objMatch->AdminLink($objMatch->Name); $objMatch = $objSupp->GetTitles_byCatKey($strCatKeyOld,'VbzAdminTitle'); if (!is_null($objMatch)) { // there are some similar entries -- show them: $out .= ' Other similar CatKeys:'; while ($objMatch->NextRow) { $out .= ' '.$objMatch->AdminLink($objMatch->CatKey); }		}	   }	}	if ($ok) { $out .= $this->objForm->Save($wgRequest->GetText('EvNotes')); }	return $out; }   public function ItemListing { $out = $this->objDB->Items->Listing_forTitle($this); return $out; }   public function ImageListing { $objTbl = $this->objDB->Images; $arArgs = array(	 'filt'	=> 'ID_Title='.$this->ID,	  'sort'	=> 'AttrSort,ID',	  'event.obj'	=> $this,	  'title.id'	=> $this->ID,	  'new'		=> TRUE	  ); $out = $objTbl->AdminPage($arArgs);

//	$objRows = $objTbl->GetData('ID_Title='.$this->ID,NULL,'AttrSort'); //	$out = $objRows->AdminList; return $out; }   /*      RETURNS: Editable listing of topics for this Title */   protected function TopicListing { global $wgRequest; global $vgPage;

$tblTitleTopics = $this->Engine->TitleTopics;

$me = $this; $arOpts = $this->Engine->Topics->TopicListing_base_array; $arOpts['fHandleData_Change_Start'] = function($iText) use ($me) { $arEv = array(		'descr'	=> 'Adding '.$iText,		'code'	=> 'topic++',		'where'	=> __METHOD__		); $me->StartEvent($arEv); };

$arOpts['fHandleData_Change_Finish'] = function($iText) use ($me) { $arEv = array(		'descrfin'	=> $iText		); $me->FinishEvent($arEv); };	$arOpts['fHandleData_Change_Item'] = function($iVal) use ($me,$tblTitleTopics) { $sqlTopic = $iVal; $arIns = array(		'ID_Title'	=> SQLValue($me->KeyValue),		'ID_Topic'	=> $sqlTopic		); $db = $tblTitleTopics->Engine; $db->ClearError; $ok = $tblTitleTopics->Insert($arIns); if (!$ok) { $strErr = $db->getError; $out = $sqlTopic.': '.$strErr.' (SQL:'.$tblTitleTopics->sqlExec.')'; } else { $out = SQLValue($sqlTopic); }	     return $out; };

$ctrlList = new clsWidget_ShortList; $ctrlList->Options($arOpts); $htStatus = $ctrlList->HandleInput;

$doRmvTopics = $wgRequest->GetBool('btnRmvTopics');

// begin output phase $out = '';

if ($doRmvTopics) { $arTopics = $wgRequest->GetArray('rmvTitle'); $cnt = $tblTitleTopics->DelTopics($this->Value('ID'),$arTopics); $out .= 'Removed '.$cnt.' topic'.Pluralize($cnt).':'; foreach ($arTopics as $id => $on) { $objTopic = $tblTopics->GetItem($id); $out .= ' '.$objTopic->AdminLink; }	} /*	$htPath = $vgPage->SelfURL; $out = "\n<form method=post action=\"$htPath\">"; $out .= "\n ";

$rs = $this->Topics; if ($rs->HasRows) { while ($rs->NextRow) {

$id = $rs->KeyString; $ftName = $rs->AdminLink_name;

$out .= "\n[<input type=checkbox name=\"rmvTitle[$id]\">$ftName ]"; }	   $out .= ' <input type=submit name="btnRmvTopics" value="Remove Checked">'; } else { $out .= None found.; } /*	$out .= '<input type=submit name="btnAddTopics" value="Add These:">'; $out .= '<input size=40 name=txtNewTitles> (IDs separated by spaces)'; $out .= ' '.$htStatus; $out .= $ctrlList->RenderForm_Entry;

$out .= ' '; return $out; }   /*      RETURNS: Listing of CM (catalog management) groups for this title HISTORY: 2011-02-06 added controls to allow deactivating/activating selected rows */   protected function CMGrpListing { global $wgRequest; global $vgOut;

$out = $vgOut->Header('Catalog Groups',3);

$tblCMT = $this->objDB->CtgTitles;	// catalog management titles $tblCMS = $this->objDB->CtgSrcs;	// catalog management sources $tblCMG = $this->objDB->CtgGrps;	// catalog management groups

$doEnable = $wgRequest->GetBool('btnCtgEnable'); $doDisable = $wgRequest->GetBool('btnCtgDisable'); if ($doEnable || $doDisable) { $arChg = $wgRequest->GetArray('ctg'); $out .= $doEnable?'Activating':'Deactivating'; foreach ($arChg as $id => $on) { $out .= ' '.$id; $arUpd = array(		 'isActive'	=> SQLValue($doEnable)		  ); $tblCMT->Update($arUpd,'ID='.$id); }	}

$rsRows = $tblCMT->GetData('ID_Title='.$this->ID); if ($rsRows->HasRows) { $out .= ' '; $out .= $vgOut->TableOpen; $out .= $vgOut->TblRowOpen(NULL,TRUE); $out .= $vgOut->TblCell('ID'); $out .= $vgOut->TblCell('A?'); $out .= $vgOut->TblCell('Catalog'); $out .= $vgOut->TblCell('Group'); $out .= $vgOut->TblCell('Discontinued'); $out .= $vgOut->TblCell('Grp Code'); $out .= $vgOut->TblCell('Grp Descr'); $out .= $vgOut->TblCell('Grp Sort'); $out .= $vgOut->TblCell('Supp Cat #'); $out .= $vgOut->TblCell('Notes'); $out .= $vgOut->TblRowShut; while ($rsRows->NextRow) { $isActive = $rsRows->isActive; $htActive = $isActive?'&radic;':'-';

$objCMSrce = $tblCMS->GetItem($rsRows->ID_Source); $objCMGrp = $tblCMG->GetItem($rsRows->ID_Group); if ($objCMSrce->HasRows) { $htCMSrce = $objCMSrce->AdminLink_name; } else { $htCMSrce = '?'.$rsRows->ID_Source; }		if ($objCMGrp->HasRows) { $htCMGrp = $objCMGrp->AdminLink_name; } else { $htCMGrp = '?'.$rsRows->ID_Group; }

$out .= $vgOut->TblRowOpen; $htID = '<input type=checkbox name="ctg['.$rsRows->KeyValue.']">'.$rsRows->AdminLink; $out .= $vgOut->TblCell($htID); $out .= $vgOut->TblCell($htActive); $out .= $vgOut->TblCell($htCMSrce); $out .= $vgOut->TblCell($htCMGrp); //		$out .= $vgOut->TblCell($rsRows->ID_Source); //		$out .= $vgOut->TblCell($rsRows->ID_Group);

$out .= $vgOut->TblCell($rsRows->WhenDiscont); $out .= $vgOut->TblCell($rsRows->GroupCode); $out .= $vgOut->TblCell($rsRows->GroupDescr); $out .= $vgOut->TblCell($rsRows->GroupSort); $out .= $vgOut->TblCell($rsRows->Supp_CatNum); $out .= $vgOut->TblCell($rsRows->Notes); $out .= $vgOut->TblRowShut; }	   $out .= $vgOut->TableShut; $out .= '<input type=submit name=btnCtgDisable value="Deactivate Selected">'; $out .= '<input type=submit name=btnCtgEnable value="Activate Selected">'; $out .= ' '; } else { $out .= 'None found.'; }	return $out; } } /*==== PURPOSE: VbzAdminTitles with additional catalog information class VbzAdminTitles_info_Cat extends VbzAdminTitles { public function __construct($iDB) { parent::__construct($iDB); $this->Name('qryCat_Titles'); }   public function Search_forText_SQL($iFind) { $sqlFind = '"%'.$iFind.'%"'; return "(Name LIKE $sqlFind) OR (Descr LIKE $sqlFind) OR (Search LIKE $sqlFind) OR (CatNum LIKE $sqlFind)"; }   public function SearchPage { global $wgOut,$wgRequest; global $vgPage;

$strFind = $wgRequest->GetText('txtSearch');

$vgPage->UseHTML; $out = "\n "; $htFind = htmlspecialchars($strFind); $out .= 'Search for:<input name=txtSearch size=40 value="'.$htFind.'"><input type=submit name=btnSearch value="Go">'; $out .= ' '; $wgOut->AddHTML($out); $out = '';

//$tblTitles = $this->Engine->Titles; $tblTitles = $this; $tblItems = $this->Engine->Items; $tblImgs = $this->Engine->Images;

$arTitles = NULL;

$rs = $tblTitles->Search_forText($strFind); if ($rs->HasRows) { while ($rs->NextRow) { $id = $rs->ID; $arTitles[$id] = $rs->Values; }	}

if (!empty($strFind)) { $out .= ' Searching for "'.$htFind.'": '; $wgOut->AddHTML($out); $out = '';

$rs = $tblItems->Search_byCatNum($strFind); if (is_object($rs)) { while ($rs->NextRow) { $id = $rs->Value('ID_Title'); if (!isset($arTitles[$id])) { $obj = $tblTitles->GetItem($id); $arTitles[$id] = $obj->Values; }		}	   }

if (!is_null($arTitles)) { if (empty($obj)) { $obj = $tblTitles->SpawnItem; }		$out .= ' '.$ftImgs; }

$wgOut->AddHTML($out); $out = ''; }

return $out; } } /*==== PURPOSE: VbzAdminTitles with additional item (and stock) information class VbzAdminTitles_info_Item extends VbzAdminTitles { public function __construct($iDB) { parent::__construct($iDB); $this->Name('qryTitles_Item_info'); $this->ClassSng('VbzAdminTitle_info_Item'); }   public function Listing_forDept($iDeptObj) { global $wgOut; global $vgPage; global $sql;

$vgPage->UseHTML;

$objDept = $iDeptObj; $idDept = $objDept->ID; //	$strSuppKey = strtolower($objSupp->CatKey); //	$objRecs = $this->GetData('ID_Dept='.$idDept,'VbzAdminTitle','CatKey'); //$objRecs = $this->DataSQL('SELECT t.ID_Title AS ID, t.* FROM qryCat_Titles_Item_stats AS t WHERE t.ID_Dept='.$idDept); $objRecs = $this->GetData('ID_Dept='.$idDept,NULL,'CatKey');

$out = $objRecs->AdminList; $wgOut->addHTML($out); } } class VbzAdminTitle_info_Item extends VbzAdminTitle { /*     RETURNS: listing of titles in the current dataset HISTORY: 2010-11-16 "in print" column now showing cntInPrint instead of cntForSale */   public function AdminList(array $iarArgs=NULL) { $objRecs = $this;

if ($objRecs->HasRows) { $out = "\n "; } else { if (isset($iarArgs['none'])) { $out .= $iarArgs['none']; } else { $out .= 'No titles found.'; }	}	return $out; } } /***** GROUP: Item administration class VbzAdminItems extends clsItems { // STATIC section // /*     HISTORY: 2010-10-13 Re-enabled as a boilerplate call */   public static function AdminLink($iID,$iShow=NULL,$iPopup=NULL) { return clsAdminTable::AdminLink($iID,$iShow,$iPopup); } // DYNAMIC section // public function __construct($iDB) { parent::__construct($iDB); $this->ClassSng('VbzAdminItem'); $this->ActionKey('item'); }   public function Listing_forTitle(clsVbzTitle $iTitleObj) { $objTitle = $iTitleObj; $idTitle = $objTitle->ID; //$cntRow = 0;

$objRecs = $this->GetData('(IFNULL(isDumped,0)=0) AND (ID_Title='.$idTitle.')','VbzAdminItem','ItOpt_Sort'); return $objRecs->AdminList; }   /*      ACTION: Updates fields in given catalog items Does not log an event (maybe it should?) INPUT: Array of items as returned by AdminItems_data_check RETURNS: HTML to display (messages) FUTURE: This possibly should be in a helper class HISTORY: 2011-01-04 partially written */   public function AdminItems_data_update(array $iItems) { $out = "\n"; foreach ($iItems as $idx => $row) { $obj = $row['@obj']; $id = $obj->KeyValue; $out .= "\nRow $idx ID=$id:\n"; $arUpd = NULL; if (!empty($row['do-upd-scat'])) { $arUpd['Supp_CatNum'] = SQLValue($row['scat']); $out .= "\nscat# [".$obj->Supp_CatNum.']=>['.$row['scat'].']'; }	   if (!empty($row['do-upd-desc'])) { $arUpd['Descr'] = SQLValue($row['name']); $out .= "\ndescr [".$obj->Descr.']=>['.$row['name'].']'; }	   $out .= "\n</ul>"; $obj->Update($arUpd); }	$out .= "\n</ul>"; return $out; } } class VbzAdminItem extends clsItem { private $idEvent;

/*     HISTORY: 2010-10-11 Added iarArgs parameter */   public function AdminLink($iText=NULL,$iPopup=NULL,array $iarArgs=NULL) { return clsAdminData::_AdminLink($this,$iText,$iPopup,$iarArgs); }   public function AdminLink_name { return $this->AdminLink($this->DescLong);	// can make this more elaborate later }   /*      PURPOSE: Like AdminLink_name. but okay to take up more room to provide more info HISTORY: 2010-11-24 created */   public function AdminLink_friendly { $strItem = $this->AdminLink_CatNum; $strFull = $strItem.' '.$this->DescLong_ht; return $strFull; }   /*      HISTORY: 2010-11-27 created */   public function AdminLink_CatNum { return $this->AdminLink($this->CatNum,$this->DescLong); }   /*      HISTORY: 2010-11-06 replaced old event logging with boilerplate calls to helper class */   protected function Log { if (!is_object($this->logger)) { $this->logger = new clsLogger_DataSet($this,$this->objDB->Events); }	return $this->logger; }   public function EventListing { return $this->Log->EventListing; }   public function StartEvent(array $iArgs) { return $this->Log->StartEvent($iArgs); }   public function FinishEvent(array $iArgs=NULL) { return $this->Log->FinishEvent($iArgs); }   /*      ACTION: Return the current supplier catalog number If a value is given, update it to the new value first (returns old value) If an event array is given, log the event */   public function SCatNum($iVal=NULL,array $iEvent=NULL) { $strOld = $this->Supp_CatNum; if (!is_null($iVal)) { if (is_array($iEvent)) { $iEvent['params'] = nz($iEvent['params']).':old=['.$strOld.']'; $iEvent['code'] = 'SCN'; $this->StartEvent($iEvent); }	   $arUpd = array('Supp_CatNum'=>SQLValue($iVal)); $this->Update($arUpd); if (is_array($iEvent)) { $this->FinishEvent; }	}	return $strOld; }   public function AdminList { global $vgPage,$vgOut; global $sql;

$cntRow = 0;

if ($this->HasRows) { $out = $vgOut->TableOpen('class=sortable'); $out .= $vgOut->TblRowOpen(NULL,TRUE); $out .= $vgOut->TblCell('ID'); $out .= $vgOut->TblCell('Cat #'); $out .= $vgOut->TblCell('Status'); $out .= $vgOut->TblCell('Description'); $out .= $vgOut->TblCell('$ buy'); $out .= $vgOut->TblCell('$ sell'); $out .= $vgOut->TblRowShut; $isOdd = TRUE; while ($this->NextRow) { $id = $this->ID; //$wtID = SelfLink_Page('item','id',$id,$id); $wtID = $this->AdminLink; $wtStyle = $isOdd?'background:#ffffff;':'background:#cccccc;'; $isActive = $this->isForSale; $isCurrent = $this->isCurrent; $isInPrint = $this->isInPrint; $isPulled = $this->isPulled; if ($isActive) { $cntRow++; } else { $wtStyle .= ' color: #888888;'; }		if (!$isInPrint) { $wtStyle .= ' font-style: italic;'; }		if ($isPulled) { $wtStyle .= ' text-decoration: line-through;'; }		$strStatus = ''; if ($isActive)	{ $strStatus .= ' A ';	} if ($isCurrent) { $strStatus .= ' C ';	} if ($isInPrint) { $strStatus .= ' P ';	} if ($isPulled)	{ $strStatus .= ' U ';	} $out .= $vgOut->TblRowOpen('style="'.$wtStyle.'"'); $out .= $vgOut->TblCell($wtID); $out .= $vgOut->TblCell($this->CatNum); $out .= $vgOut->TblCell($strStatus,'align=center'); $out .= $vgOut->TblCell($this->ItOpt_Descr); $out .= $vgOut->TblCell(DataCurr($this->PriceBuy)); $out .= $vgOut->TblCell(DataCurr($this->PriceSell)); $out .= $vgOut->TblRowShut; if (!is_null($this->Descr)) { $out .= $vgOut->TblRowOpen('style="'.$wtStyle.'"'); $out .= $vgOut->TblCell($this->Descr,'colspan=4'); $out .= $vgOut->TblRowShut; }

$isOdd = !$isOdd; //$objLine = $objRecs->CloneFields; $objLine = clone $this; }	   $out .= $vgOut->TableShut; } else { $out = 'No items listed. (SQL='.$sql.')'; }	return $out; }   public function Title { return $this->objDB->Titles->GetItem($this->ID_Title); }   public function ItTyp { return $this->objDB->ItTyps->GetItem($this->ID_ItTyp); }   public function FullDescr($iSep=' ') { $objTitle = $this->Title; return $objTitle->Name.$iSep.$this->ItOpt_Descr; }   public function FullDescr_HTML($iSep=' ') { $objTitle = $this->Title; $objItTyp = $this->ItTyp; if ($objItTyp->IsNew) { $out = '(no item type)'; } else { $out = //	 $objTitle->SelfLink($objTitle->Name).$iSep. $objTitle->AdminLink($objTitle->Name).$iSep. $objItTyp->Row['NameSng'].$iSep. $this->ItOpt_Descr; }	return $out; } /* 2010-11-11 This should be completely obsolete, right? protected function ReceiveForm { global $wgOut,$wgRequest;

if ($wgRequest->getCheck('btnSave')) { $intQtyNew = $wgRequest->GetInt('StkMin'); $arUpd['QtyMin_Stk'] = $intQtyNew; $intQtyOld = $this->QtyMin_Stk; if ($intQtyOld == $intQtyNew) { $out = 'No change requested; min qty is already '.$intQtyOld.'.'; } else { $strDescr = 'Updating per-item stock minimum from '.$intQtyOld.' to '.$intQtyNew; $out = $strDescr; $this->StartEvent(__METHOD__,'UPD',$strDescr); $this->Update($arUpd); $this->Reload; $this->FinishEvent; }	   $wgOut->AddWikiText($out); }   }    /*      HISTORY: 2011-02-24 Finally renamed from InfoPage to AdminPage */   public function AdminPage { global $wgOut,$wgRequest; global $vgPage;

$strCatNum = $this->CatNum;

//$this->ReceiveForm;

$vgPage->UseHTML; $objTitle = $this->Title; $strTitleName = $objTitle->Name; $ftTitleLink = (is_object($objTitle))?($objTitle->AdminLink($strTitleName)):'title N/A'; $strTitle = 'Item: '.$strCatNum.' ('.$this->ID.') - '.$this->FullDescr;

$objPage = new clsWikiFormatter($vgPage); $objSection = new clsWikiSection($objPage,$strTitle); $objSection->ToggleAdd('edit'); //$objSection->ActionAdd('view'); $out = $objSection->Generate;

$strAction = $vgPage->Arg('do'); $doAdd = ($strAction == 'add'); $doEdit = $vgPage->Arg('edit'); $doSave = $wgRequest->GetBool('btnSave');

if ($doEdit || $doSave) { $this->BuildEditForm; if ($doSave) { $this->AdminSave; }	}

$ftPriceSell = $this->PriceSell;	// this can be edited if item is not in print if ($doEdit) { $out .= $objSection->FormOpen; $objForm = $this->objForm;

$ftCatNum = $objForm->Render('CatNum'); $ftCatSfx = $objForm->Render('CatSfx'); $ftDescr = $objForm->Render('Descr'); if (!$this->isInPrint) { $ftPriceSell = $objForm->Render('PriceSell'); }	   $ftPriceList = $objForm->Render('PriceList'); $ftSCatNum = $objForm->Render('Supp_CatNum'); $ftStkMin = $objForm->Render('QtyMin_Stk'); } else { $ftCatNum = $this->CatNum; $ftCatSfx = $this->CatSfx; $ftDescr = $this->Descr; $ftPriceList = $this->PriceList; $ftSCatNum = $this->Supp_CatNum; $ftStkMin = $this->QtyMin_Stk; }	// non-editable fields: $ftTitle = $ftTitleLink; $ftPriceBuy = $this->PriceBuy; $ftItOpt = $this->ID_ItOpt; $ftIODescr = $this->ItOpt_Descr; $ftIOSort = $this->ItOpt_Sort; $ftGrpCode = $this->GrpCode; $ftGrpDescr = $this->GrpDescr; $ftGrpSort = $this->GrpSort;

$out .= ''; $out .= ' ID: '.$this->ID; $out .= ' Cat #: '.$ftCatNum.' suffix: '.$ftCatSfx; $out .= ' Description: '.$ftDescr; $out .= ' Prices: '.$ftItOpt; $out .= ''; $out .= ' Buy: '.$ftPriceBuy; $out .= '<li> Sell: '.$ftPriceSell; $out .= '<li> List': '.$ftPriceList.'; $out .= '</ul>'; $out .= '<li> Item Option: '.$ftItOpt; $out .= '<ul>'; $out .= '<li> Descr: '.$ftIODescr; $out .= '<li> Sort: '.$ftIOSort; $out .= '</ul>'; $out .= '<li> Group - code: '.$ftGrpCode.' descr: '.$ftGrpDescr.' sort: '.$ftGrpSort; $out .= '<li> Title: '.$ftTitle; $out .= '<li> Stk Min: '.$ftStkMin; $out .= '<li> Status:'; if ($this->isMaster) {	$out .= ' MASTER'; } if ($this->isForSale) {	$out .= ' FOR-SALE'; } if ($this->isInPrint) {	$out .= ' IN-PRINT'; } if ($this->isCloseOut) {	$out .= ' CLOSEOUT'; } if ($this->isPulled) {	$out .= ' PULLED'; } if ($this->isDumped) {	$out .= ' DUMPED'; } $out .= '<li> Supplier Cat #:'.$ftSCatNum; $out .= '</ul>';

if ($doEdit) { $out .= '<input type=submit name="btnSave" value="Save">'; $out .= '<input type=reset value="Reset">'; $out .= ' '; }	$wgOut->AddHTML($out); $wgOut->AddHTML(" Stock "); $wgOut->AddWikiText($this->StockListing,TRUE); $wgOut->AddHTML(" Orders "); $wgOut->AddWikiText($this->OrderListing,TRUE); $wgOut->AddHTML(" Restocks "); $wgOut->AddWikiText($this->RestockListing,TRUE); $wgOut->AddHTML(' Events '); $wgOut->AddWikiText($this->EventListing,TRUE); }   /*      HISTORY: 2010-11-06 adapted from VbzStockBin */   private function BuildEditForm { global $vgOut;

if (is_null($this->objForm)) { // create fields & controls $objForm = new clsForm_DataSet($this,$vgOut); //$objCtrls = new clsCtrls($objForm->Fields);

$objForm->AddField(new clsField('Descr'),		new clsCtrlHTML(array('size'=>40))); $objForm->AddField(new clsField('CatNum'),		new clsCtrlHTML); $objForm->AddField(new clsField('CatSfx'),		new clsCtrlHTML(array('size'=>5))); $objForm->AddField(new clsFieldNum('PriceSell'),	new clsCtrlHTML); $objForm->AddField(new clsFieldNum('PriceList'),	new clsCtrlHTML); $objForm->AddField(new clsField('Supp_CatNum'),	new clsCtrlHTML); $objForm->AddField(new clsFieldNum('QtyMin_Stk'),	new clsCtrlHTML(array('size'=>3)));

$this->objForm = $objForm; //$this->objCtrls = $objCtrls; }   }    /*      ACTION: Save user changes to the record HISTORY: 2010-11-06 copied from VbzStockBin to VbzAdminItem */   public function AdminSave { global $vgOut;

$out = $this->objForm->Save; $vgOut->AddText($out); }   public function StockListing { $out = $this->objDB->StkItems->Listing_forItem($this); return $out; }   public function OrderListing { $objTbl = $this->objDB->OrdItems; $objRows = $objTbl->GetData('ID_Item='.$this->ID); $out = $objRows->AdminTable_forItem; return $out; }   public function RestockListing { $objTbl = $this->objDB->RstkReqItems; $objRows = $objTbl->GetData('ID_Item='.$this->ID); $out = $objRows->AdminList('No restocks found for this item'); return $out; }   /*      RETURNS: wikitext which links to the catalog page for the item NOTE: Since the store doesn't yet have pages for each item, this returns a link to the item's Title page FUTURE: create StoreLink function which uses RichText object */   public function StoreLink_WT($iText) { return .$iText.; } // FUNCTION DEPRECATED - remove eventually public function AdminLink_WT($iText) { return .$iText.; } // FUNCTION DEPRECATED - remove eventually public function StoreLink_HT($iText) { return '<a href="'.KWP_CAT.$this->Title->URL_part.'" title="browse in store">'.$iText.'</a>'; } } class clsAdminItems_info_Cat extends clsItems_info_Cat { public function __construct($iDB) { parent::__construct($iDB); $this->ActionKey('item'); } } /******* IMAGES class clsAdminImages extends clsImages { public function __construct($iDB) { parent::__construct($iDB); $this->Name('cat_images'); $this->KeyName('ID'); $this->ClassSng('clsAdminImage'); }   /*-      ACTION: Processes form data, shows section header, loads image dataset, calls clsAdminImage::AdminList to render INPUT: iarArgs: array of options ['filt'] = SQL filter for dataset to show ("WHERE" clause) ['sort'] = sorting order for dataset to show ("ORDER BY" clause) ['event.obj'] = object used for event logging ['title.id'] = ID_Title to use for new records ['new']: if TRUE, allow user to create new records when editing */   public function AdminPage(array $iarArgs) { global $wgRequest; global $vgPage,$vgOut;

$out = '';

// get URL input $doEdit = ($vgPage->Arg('edit.img')); $doAdd = ($vgPage->Arg('add.img')); $arArgs = $iarArgs; $arArgs['edit'] = $doEdit; $sqlFilt = $arArgs['filt']; $sqlSort = $arArgs['sort'];

// display section header //	$strName = 'Images';

$vgPage->UseHTML; $objPage = new clsWikiFormatter($vgPage); $objSection = new clsWikiSection($objPage,'Images',NULL,3); $objSection->ToggleAdd('edit','edit image records','edit.img'); $objSection->ToggleAdd('add','add multiple image records','add.img'); $out .= $objSection->Generate;

// handle possible form requests

// -- bulk-entry form stage 1: check input if ($wgRequest->getBool('btnCheckImgs')) { $doCheck = TRUE; $xts = new xtString($wgRequest->GetText('txtImgs')); $arLines = $xts->ParseTextLines(array('line'=>'arr')); $htForm = "\nImages submitted:\n<ul>"; foreach ($arLines as $idx => $arLine) { $txtURL = $arLine[0]; $txtSize = isset($arLine[1])?$arLine[1]:NULL;

$rsFldr = $this->Engine->Folders->FindBest($txtURL); if (is_null($rsFldr)) { $htForm .= "\n<li>No folder found for $txtUrl</li>"; } else { $fsFldr = $rsFldr->Value('PathPart'); $fsImg = $rsFldr->Remainder($txtURL); $idFldr = $rsFldr->KeyValue;

$ftSize = empty($txtSize)?:.$txtSize.' '; $htForm .= "\n<li>$ftSize$fsFldr<a href=\"$fsFldr$fsImg\">$fsImg</a></li>"; $htForm .= '<input type=hidden name="img-fldr['.$idx.']" value='.$idFldr.'>'; $htForm .= '<input type=hidden name="img-spec['.$idx.']" value="'.$fsImg.'">'; if (!is_null($txtSize)) { $htForm .= '<input type=hidden name="img-size['.$idx.']" value="'.$txtSize.'">'; }		}	   }	    $htForm .= '</ul>'; } else { $doCheck = FALSE; } // -- bulk-entry form stage 2: create records if ($wgRequest->getBool('btnAddImgs')) { $arFldrs = $wgRequest->GetArray('img-fldr'); $arSpecs = $wgRequest->GetArray('img-spec'); $arSizes = $wgRequest->GetArray('img-size'); $idTitle = $vgPage->Arg('id'); assert('!empty($idTitle);');

// log event to the title $objTitle = $this->Engine->Titles($idTitle); $cntImgs = count($arFldrs); $arEv = array(	     'descr'	=> 'Adding '.$cntImgs.' image'.Pluralize($cntImgs),	      'where'	=> __METHOD__,	      'code'	=> 'IMG++'	      ); $objTitle->StartEvent($arEv);

foreach ($arFldrs as $idx => $idFldr) { $fs = $arSpecs[$idx]; $sz = $arSizes[$idx]; $arIns = array(		 'ID_Folder'	=> $idFldr,		  'isActive'	=> 'TRUE',		  'Spec'	=> SQLValue($fs),		  'ID_Title'	=> $idTitle,		  'WhenAdded'	=> 'NOW'		  ); if (!empty($sz)) { $arIns['Ab_Size'] = SQLValue($sz); }		$this->Insert($arIns); $strNew = ' '.$this->LastID; }	   $arEv = array(	      'descrfin'	=> 'New ID'.Pluralize($cntImgs).':'.$strNew	      ); $objTitle->FinishEvent($arEv); }	// -- existing item edit form if ($wgRequest->getBool('btnSaveImgs')) {

$arUpdate = $wgRequest->getArray('update'); $arDelete = $wgRequest->getArray('del'); $arActive = $wgRequest->getArray('isActive'); $arFolder = $wgRequest->getArray('ID_Folder'); $arFileSpec = $wgRequest->getArray('txtFileSpec'); $arAttrSize = $wgRequest->getArray('txtAttrSize'); $arAttrFldr = $wgRequest->getArray('txtAttrFldr'); $arAttrDispl = $wgRequest->getArray('txtAttrDispl'); $arAttrSort = $wgRequest->getArray('txtAttrSort');

if (count($arActive > 0)) { // add any reactivated rows to the update list foreach ($arActive as $id => $null) { $arUpdate[$id] = TRUE; }	   }

$cntRows = count($arUpdate); if ($cntRows > 0) { $out .= 'Updating: '; $txtEvDescr = 'Checking '.$cntRows.' record'.Pluralize($cntRows); $txtRowEdits = ''; $txtRowFlips = '';

$doLog = isset($arArgs['event.obj']); if ($doLog) { $objLog = $arArgs['event.obj']; $arEv = array(		     'descr'	=> $txtEvDescr,		      'where'	=> __METHOD__,		      'code'	=> 'IMG SVM'	// image save multiple		      ); $objLog->StartEvent($arEv); }

$cntUpd = 0; foreach ($arUpdate as $id => $null) { $isActive = isset($arActive[$id]); $isNew = ($id == 'new'); if (empty($arFileSpec[$id])) { $isNew = FALSE;	// nothing to save }		   $objImg = $this->GetItem($id);

if ($isNew) { $isDiff = TRUE; $doSaveActive = TRUE; $doSaveValues = TRUE; } else { $isDiff = ((int)$isActive != (int)$objImg->isActive); $isStateChg = $isDiff; $doSaveActive = $isDiff; $doSaveValues = !$isDiff; }		   if (!$isDiff) { $arUpd = array(			 'ID_Folder'	=> $arFolder[$id],			  'Spec'	=> $arFileSpec[$id],			  'Ab_Size'	=> $arAttrSize[$id],			  'AttrFldr'	=> nz($arAttrFldr[$id]),			  'AttrDispl'	=> nz($arAttrDispl[$id]),			  'AttrSort'	=> nz($arAttrSort[$id])			  ); $isDiff = !$objImg->SameAs($arUpd); }		   $arUpd = NULL; if ($isDiff) { if ($doSaveValues) { $arUpd = array(			     'ID_Folder'	=> SQLValue($arFolder[$id]),			      'Spec'		=> SQLValue($arFileSpec[$id]),			      'Ab_Size'		=> SQLValue($arAttrSize[$id]),			      'AttrFldr'	=> SQLValue(nz($arAttrFldr[$id])),			      'AttrDispl'	=> SQLValue(nz($arAttrDispl[$id])),			      'AttrSort'	=> SQLValue(nz($arAttrSort[$id]))			      ); $txtRowEdits .= ' #'.$id; }			if ($doSaveActive) { $arUpd['isActive'] = SQLValue($isActive); $txtRowFlips .= ' #'.$id.'('.NoYes($isActive,'off','ON').')'; }			if ($isNew) { // create new record $idTitle = (int)$arArgs['title.id']; assert('is_int($idTitle)'); $arUpd['ID_Title'] = $idTitle; $this->Insert($arUpd); } else { // not new: just update $objImg->Update($arUpd); //global $sql; //$out .= ' SQL: '.$objImg->sqlExec; }			$cntUpd++; }		}		if ($doLog) { $txtStat = $cntUpd.' image'.Pluralize($cntUpd).' updated -'; if (!empty($txtRowFlips)) { $txtStat .= ' toggled:'.$txtRowEdits; }		   if (!empty($txtRowEdits)) { $txtStat .= ' edits:'.$txtRowEdits; }		   $arEv = array(		      'descrfin' => SQLValue($txtStat)		      ); $objLog->FinishEvent($arEv); }		$out .= $txtStat; } else { $out .= 'No image records selected for update.'; }	}

// render edit form outer shell: if ($doEdit || $doAdd || $doCheck) { $arLink = $vgPage->Args(array('page','id')); $urlSelf = $vgPage->SelfURL($arLink,TRUE); $arArgs['pfx'] = '<form method=post action="'.$urlSelf.'">';

if ($doEdit) { $sfx = '<input type=submit name=btnSaveImgs value="Save">'; $sfx .= '<input type=reset value="Revert">'; }	   if ($doAdd) { $sfx = 'Enter images, one complete URL per line:'; $sfx .= '<textarea name=txtImgs rows=6> '; $sfx .= '<input type=submit name=btnCheckImgs value="Check">'; }	   if ($doCheck) { $sfx = $htForm;	// calculated earlier $sfx .= '<input type=submit name=btnAddImgs value="Add These">'; }	   $sfx .= ' '; $arArgs['sfx'] = $sfx; }

// load the latest data and show it in a table: $arArgs['none'] = 'No images found.'; $objRows = $this->GetData($sqlFilt,NULL,$sqlSort); $out .= $objRows->AdminList($arArgs);

return $out; }   /*      HISTORY: 2010-10-19 Adapted from AdminPage 2010-11-16 Commented out editing functions, per earlier thought, after partly updating them. Note: they were written for AdminPage. */   public function AdminPage_Unassigned { global $wgRequest,$wgOut; global $vgPage,$vgOut;

$out = '';

// get URL input $doEdit = ($vgPage->Arg('edit.img')); $arArgs['edit'] = $doEdit;

// display section header //	$strName = 'Images';

$vgPage->UseHTML; $objPage = new clsWikiFormatter($vgPage); $objSection = new clsWikiSection($objPage,'Unassigned Images',NULL,3); $objSection->ToggleAdd('edit','edit image records','edit.img'); $out .= $objSection->Generate;

// load the latest data and show it in a table: $arArgs['none'] = 'No unassigned images found.'; $sqlFilt = 'ID_Title IS NULL'; $sqlSort = NULL;	// maybe this could be useful later $objRows = $this->GetData($sqlFilt,NULL,$sqlSort); $out .= $objRows->AdminList($arArgs);

$objSection = new clsWikiSection($objPage,'Imageless Active Titles',NULL,3); $out .= $objSection->Generate; $objRows = $this->objDB->Titles->Data_Imageless; $out .= $objRows->AdminList($arArgs);

$wgOut->AddHTML($out); $out = NULL; return $out; } } class clsAdminImage extends clsImage { /*-     ACTION: Renders dataset as a table INPUT: iarArgs none: text to insert as description if no records pfx: html to include before table rows, if there is data sfx: html to include after table rows, if there is data edit: render editable fields new: allow entering new records -- show edit even if no data */   public function AdminList(array $iarArgs) { $out = ''; $doNew = nz($iarArgs['new']); if ($doNew || $this->HasRows) { $doEdit = nz($iarArgs['edit']); $out .= nz($iarArgs['pfx']); $out .= "\n "; $out .= nz($iarArgs['sfx']); } else { if (isset($iarArgs['none'])) { $out .= $iarArgs['none']; } else { $out .= 'No images found.'; }	}	return $out; }   protected function AdminListRow($iEdit,$iOdd,$iNew=FALSE) { $isOdd = $iOdd; $doEdit = $iEdit;

if ($iNew) { $doEdit = TRUE; $isActive = TRUE; $id = 'new'; $txtFileSpec = ''; $txtFolder = ''; $txtAttrSize = ''; $txtAttrFldr = ''; $txtAttrDispl = ''; $txtAttrSort = ''; } else { $id = $this->ID; $wtID = $id; $isActive = $this->isActive; $txtFileSpec = $this->Spec; $txtFolder = $this->FolderPath; $txtAttrSize = $this->Ab_Size; $txtAttrFldr = $this->AttrFldr; $txtAttrDispl = $this->AttrDispl; $txtAttrSort = $this->AttrSort; }

$wtStyle = $isOdd?'background:#ffffff;':'background:#eeeeee;'; if ($isActive) { $wtStyleCell = ''; $ftActive = '&radic;'; } else { $wtStyle .= ' color: #888888;'; $wtStyleCell = ' style="text-decoration: line-through;"'; $ftActive = ''; }	if ($doEdit) { // replace field values with editable versions if ($isActive) { $wtID = '<input type=hidden name=update['.$id.'] value=1>'.$id; } else { $wtID = '<input type=checkbox name=del['.$id.'] title="check rows to delete">'.$id; }	   $htEnabled = $isActive?'':' disabled'; $ftActive = '<input type=checkbox name=isActive['.$id.'] title="check if this image should be used"'.($isActive?' checked':'').'>'; $htFolder = $this->objDB->Folders->DropDown('ID_Folder['.$id.']',$this->ID_Folder); $htFileSpec = '<input'.$htEnabled.' size=20 name=txtFileSpec['.$id.'] value="'.htmlspecialchars($txtFileSpec).'">'; $htAttrSize = '<input'.$htEnabled.' size=4 name=txtAttrSize['.$id.'] value="'.htmlspecialchars($txtAttrSize).'">'; $htAttrFldr = '<input'.$htEnabled.' size=4 name=txtAttrFldr['.$id.'] value="'.htmlspecialchars($txtAttrFldr).'">'; $htAttrDispl = '<input'.$htEnabled.' size=10 name=txtAttrDispl['.$id.'] value="'.htmlspecialchars($txtAttrDispl).'">'; $htAttrSort = '<input'.$htEnabled.' size=2 name=txtAttrSort['.$id.'] value="'.htmlspecialchars($txtAttrSort).'">'; } else { $htFolder = $txtFolder; $htFileSpec = $txtFileSpec = '<a href="'.$this->WebSpec.'">'.$txtFileSpec.'</a>';

$htAttrSize = $txtAttrSize; $htAttrFldr = $txtAttrFldr; $htAttrDispl = $txtAttrDispl; $htAttrSort = $txtAttrSort; }

$out = "\n<tr style=\"$wtStyle\">". "\n<td align=right$wtStyleCell>$wtID ". "\n<td$wtStyleCell>$ftActive ". "\n<td$wtStyleCell>$htFolder ". "\n<td$wtStyleCell>$htFileSpec ". "\n<td$wtStyleCell>$htAttrSize ". "\n<td$wtStyleCell>$htAttrFldr ". "\n<td$wtStyleCell>$htAttrDispl ". "\n<td$wtStyleCell>$htAttrSort ". "\n ";

return $out; } }

/****** SHIPPING class clsShipments extends clsVbzTable { public function __construct($iDB) { parent::__construct($iDB); $this->Name('ord_shipmt'); $this->KeyName('ID'); $this->ClassSng('clsShipment'); $this->ActionKey('shpmt'); }   protected function _newItem { return new clsCatPage($this); }   public function GetActive($iSort=NULL) { $objRows = $this->GetData('WhenClosed IS NULL',NULL,$iSort); return $objRows; }   public function AdminPage { global $wgOut; global $vgPage;

$out = '==Shipments=='; $wgOut->addWikiText($out,TRUE);	$out = '';

$vgPage->UseWiki;

$objRecs = $this->GetData(NULL,NULL,'ID DESC'); if ($objRecs->HasRows) { $out = "{| class=sortable\n|-\n! ID || Code || Status || Created || Shipped || Closed || Descr/Notes"; $isOdd = TRUE; while ($objRecs->NextRow) { $id = $objRecs->ID; //$wtID = SelfLink_Page('shipmt','id',$id,$id); $wtID = $objRecs->AdminLink; $wtStyle = $isOdd?'background:#ffffff;':'background:#cccccc;'; $wtCode = $objRecs->Abbr; //		$wtStatus = ($objRecs->isDedicated==TRUE?'D':''). ($objRecs->isOnHold==TRUE?'H':''); $wtStatus = (ord($objRecs->isDedicated)=='1'?'D':''). (ord($objRecs->isOnHold)=='1'?'H':''); $wtWhenCre = TimeStamp_HideTime($objRecs->WhenCreated); $wtWhenShp = TimeStamp_HideTime($objRecs->WhenShipped); $wtWhenCls = TimeStamp_HideTime($objRecs->WhenClosed); $wtDescr = $objRecs->Descr; if (!is_null($objRecs->Notes)) { $wtDescr .= " ".$objRecs->Notes.""; }		$isActive = is_null($objRecs->WhenShipped); if ($isActive) { //later: show link to ship/close it		   $wtStyle .= ' color: #006600;'; } else { }		$out .= "\n|- style=\"$wtStyle\"\n| ".$wtID.' || '.$wtCode.' || '.$wtStatus.' || '.$wtWhenCre.' || '.$wtWhenShp.' || '.$wtWhenCls.' || '.$wtDescr; $isOdd = !$isOdd; }	   $out .= "\n|}"; } else { $out = 'No shipments have been created yet.'; }	$wgOut->addWikiText($out,TRUE);	$out = ''; } } class clsShipment extends clsVbzRecs { /*     HISTORY: 2010-10-11 Added iarArgs parameter */   public function AdminLink($iText=NULL,$iPopup=NULL,array $iarArgs=NULL) { return clsAdminData::_AdminLink($this,$iText,$iPopup,$iarArgs); }   public function AdminLink_name { return $this->AdminLink($this->ShortName); }   public function ShortName { return $this->Value('Abbr'); }   /*      ACTION: Redirect to the url of the admin page for this object HISTORY: 2010-11-26 copied from VbzAdminCatalog to clsRstkRcd 2011-01-02 copied from clsRstkRcd to VbzAdminOrderTrxact 2011-09-24 copied from VbzAdminOrderTrxact to clsShipment */   public function AdminRedirect(array $iarArgs=NULL) { return clsAdminData::_AdminRedirect($this,$iarArgs); }   /*-      TO DO: * Convert old-style edit/header to new, wherever that is     HISTORY: 2011-03-29 renamed from InfoPage to AdminPage */   public function AdminPage { global $wgOut,$wgRequest; global $vgPage;

$vgPage->UseHTML;

// check for form data $doNew = ($vgPage->Arg('id') == 'new'); $didAdd = FALSE;

// 2011-09-02 This was the old code for saving a new record. Keeping it in case tweaks are needed to the new code. /*	if ($wgRequest->getBool('btnCreate')) { $wgOut->AddWikiText('==Creating Shipment==',TRUE); // create new record from form data $strAbbr = $wgRequest->getText('abbr'); $strDescr = $wgRequest->getText('descr'); $strNotes = $wgRequest->getText('notes');

$arEv = array(	     'descr'	=> 'new shipment',	      'where'	=> __METHOD__,	      'code'	=> 'new'	      ); $this->StartEvent($arEv); $arIns = array(	     'id'		=> 0,	      'WhenCreated'	=> 'NOW',	      'Abbr'		=> SQLValue($strAbbr),	      'Descr'		=> SQLValue($strDescr),	      'Notes'		=> SQLValue($strNotes)	      ); $this->Table->Insert($arIns); $this->ID = $this->Table->LastID; $wgOut->AddWikiText('New ID='.$this->ID,TRUE); $this->Reload;	// load the newly-created record $didAdd = TRUE;	// a new record has just been created $this->FinishEvent(array('id'=>$this->ID)); }

// check for more actions: $doEdit = ($doNew || $vgPage->Arg('edit')); $doClose = $vgPage->Arg('close'); $doSave = $wgRequest->getBool('btnSave');

if ($doClose) { // add up totals $objRecs = $this->PkgsData; if ($objRecs->HasRows) { $wgOut->AddWikiText('==Closing Shipment==',TRUE); $ok = TRUE; $dlrShip = 0; $dlrPack = 0; $cntPkgErr = 0; $out = ''; while ($objRecs->NextRow) { $out .= ' Pkg ID '.$objRecs->AdminLink; if (is_null($objRecs->ShipCost)) { $out .= ': no shipping cost!'; $ok = FALSE; $cntPkgErr++; } elseif (is_null($objRecs->PkgCost)) { $out .= ': no materials cost!'; $ok = FALSE; $cntPkgErr++; } else { $dlrShip += $objRecs->ShipCost; $dlrPack += $objRecs->PkgCost; }		}		if ($ok) { $strUpd = '$'.$dlrShip.' shipping, $'.$dlrPack.' materials'; $out = ' Cost totals: '.$strUpd; } else { $out .= ' '.$cntPkgErr.Pluralize($cntPkgErr,' package has','packages have').' missing information.'; }	   } else { $ok = FALSE; $out = 'No packages in shipment; nothing to close.'; }	   $wgOut->AddHTML($out); $out=NULL;

if ($ok) { // log the attempt $arEv = array(		 'descr'	=> 'closing shipment: '.$strUpd,		  'where'	=> __METHOD__,		  'code'	=> 'CLO'		  ); $this->StartEvent($arEv);

// fill in stats $arUpd = array(		 'WhenClosed' => 'NOW',		  'OrderCost' => $dlrShip,		  'SupplCost' => $dlrPack		  ); $this->Update($arUpd); global $sql; $out = ' Shipment updated - SQL: '.$sql; $this->Reload;

// log the completion $this->FinishEvent; $wgOut->AddWikiText($out,TRUE);	$out=NULL; }	}

if ($doEdit || $doSave) { $this->BuildEditForm; if ($doSave) { $this->AdminSave; }	}

$htAbbr = htmlspecialchars($this->Abbr); $htDescr = htmlspecialchars($this->Descr); $htNotes = htmlspecialchars($this->Notes); // values which are always static if ($doNew) { $strID = 'NEW'; $strTitle = 'NEW Shipment'; } else { if ($didAdd) { $strID = $this->AdminLink; } else { $strID = $this->ID; }	   $strTitle = 'Shipment '.$htAbbr; }	$out = ''; if ($doEdit) { // open editing form $sqlID = $doNew?'new':$this->ID; $arLink = array(	     'edit' => FALSE,	      'id' => $sqlID	      ); $htPath = $vgPage->SelfURL($arLink); $out .= "\n<form method=post action=\"$htPath\">"; // code for editable values /*	   $strAbbr = '<input name=abbr type=text size=16 value="'.$htAbbr.'">'; $strDescr = '<input name=descr type=text size=50 value="'.$htDescr.'">'; $strNotes = '<textarea name=notes width=50 height=3>'.$htNotes.' '; $objForm = $this->objForm; $ctrlAbbr	= $objForm->Render('Abbr'); $ctrlDescr	= $objForm->Render('Descr'); $ctrlNotes	= $objForm->Render('Notes');

$ctrlWhenCre	= $objForm->Render('WhenCreated'); $ctrlWhenShp	= $objForm->Render('WhenShipped'); $ctrlCostRcpt	= '$'.$objForm->Render('ReceiptCost'); $ctrlCostOuts	= '$'.$objForm->Render('OutsideCost'); $ctrlCostOrdr	= '$'.$objForm->Render('OrderCost'); $ctrlCostSupp	= '$'.$objForm->Render('SupplCost'); $ctrlCarrier	= $objForm->Render('Carrier');

$ctrlIsDedic	= $objForm->Render('isDedicated'); $ctrlIsOnHold	= $objForm->Render('isOnHold'); $ctrlStatus = $ctrlIsDedic.'dedicated '.$ctrlIsOnHold.'on hold';

$htClose = ''; } else { // Only allow closing the shipment if we're not editing. // Clicking a link from edit mode loses any edits. if (is_null($this->WhenClosed)) { $arLink = array(		 'close' => TRUE,		  ); $htClose = ' ['.$vgPage->SelfLink($arLink,'close the shipment','set closing timestamp and add up totals').']'; } else { $htClose = '';	// already closed }

// code for static values $ctrlAbbr = $htAbbr; $ctrlDescr = $htDescr; $ctrlNotes = $htNotes;

$ctrlWhenCre = $this->WhenCreated; $ctrlWhenShp = $this->WhenShipped; $ctrlCostRcpt = $this->ReceiptCost; $ctrlCostOuts = $this->OutsideCost; $ctrlCostOrdr = $this->OrderCost; $ctrlCostSupp = $this->SupplCost; $ctrlCarrier = $this->Carrier;

$isDedicated = (ord($this->isDedicated)); $isOnHold = (ord($this->isOnHold)); if ($isDedicated || $isOnHold) { $ctrlStatus = ($isDedicated?'Dedicated':''). ($isOnHold?' OnHold':''); } else { $ctrlStatus = normal; }	}	// non-editable controls $ctrlWhenClo = $this->WhenClosed.$htClose;

$out .= WikiSectionHdr_Edit($strTitle,$doEdit);	// old style //	$out .= "\n $strTitle ";

$out .= "\n "; if ($doEdit) { // form buttons if ($doNew) { // next line needed only if we have special code for Create vs. Save // $out .= '<input type=submit name="btnCreate" value="Create">'; // 2011-09-02 testing this instead: $out .= '<input type=submit name="btnSave" value="Create">'; } else { $out .= '<input type=submit name="btnSave" value="Save">'; $out .= '<input type=reset value="Revert">'; }	// close editing form $out .= "\n "; }	$wgOut->addHTML($out);	$out = '';

if (!$doNew) { $wgOut->addWikiText('===Packages===',TRUE);	$out = ''; $out .= $this->PkgTable; $wgOut->addWikiText($out,TRUE);	$out = '';

$wgOut->addWikiText('===Events===',TRUE); $out = $this->EventListing; $wgOut->addWikiText($out,TRUE);	$out = ''; }   }    /*      HISTORY: 2011-02-17 Updated to use objForm instead of objFlds/objCtrls */   private function BuildEditForm { global $vgOut;

// create fields & controls

if (is_null($this->objForm)) { $objForm = new clsForm_DataSet($this,$vgOut);

$objForm->AddField(new clsFieldTime('WhenCreated'),	new clsCtrlHTML); $objForm->AddField(new clsFieldTime('WhenShipped'),	new clsCtrlHTML); //$objCtrls->AddField(new clsFieldTime('WhenClosed'),		new clsCtrlHTML); $objForm->AddField(new clsFieldNum('ReceiptCost'),	new clsCtrlHTML(array('size'=>5))); $objForm->AddField(new clsFieldNum('OutsideCost'),	new clsCtrlHTML(array('size'=>5))); $objForm->AddField(new clsFieldNum('OrderCost'),	new clsCtrlHTML(array('size'=>5))); $objForm->AddField(new clsFieldNum('SupplCost'),	new clsCtrlHTML(array('size'=>5))); $objForm->AddField(new clsField('Carrier'),	new clsCtrlHTML); $objForm->AddField(new clsField('Abbr'),	new clsCtrlHTML(array('size'=>16))); $objForm->AddField(new clsField('Descr'),	new clsCtrlHTML(array('size'=>50))); $objForm->AddField(new clsField('Notes'),	new clsCtrlHTML_TextArea(array('height'=>3,'width'=>50))); $objForm->AddField(new clsFieldBool('isDedicated'),	new clsCtrlHTML_CheckBox); $objForm->AddField(new clsFieldBool('isOnHold'),	new clsCtrlHTML_CheckBox);

$this->objForm = $objForm; }   }    /*-      ACTION: Save the user's edits to the shipment HISTORY: 2011-02-17 Retired old custom code; now using objForm helper object */   private function AdminSave { global $vgOut;

$out = $this->objForm->Save; $vgOut->AddText($out); /* 2011-02-17 old code global $wgOut;

// get the form data and note any changes $objFlds = $this->objCtrls->Fields; $objFlds->RecvVals; // get the list of field updates $arUpd = $objFlds->DataUpdates; // log that we are about to update $strDescr = 'Edited: '.$objFlds->DescrUpdates; $wgOut->AddWikiText('==Saving Edit==',TRUE); $wgOut->AddWikiText($strDescr,TRUE);

$arEv = array(	 'descr'	=> $strDescr,	  'where'	=> __METHOD__,	  'code'	=> 'ED'	  ); $this->StartEvent($arEv); // update the recordset $this->Update($arUpd); global $sql; $wgOut->AddWikiText(' SQL='.$sql,TRUE); $this->Reload; // log completion $this->FinishEvent; }   public function PkgsData { $objTbl = $this->objDB->Pkgs; $objRows = $objTbl->GetData('(ID_Shipment='.$this->KeyValue.') AND (WhenVoided IS NULL)'); return $objRows; }   public function PkgTable { /*	//$objTbl = new clsPackages($this->objDB); $objTbl = $this->objDB->Pkgs; $objRows = $objTbl->GetData('ID_Shipment='.$this->ID); $objRows = $this->PkgsData; $arArgs = array(	 'descr'	=> ' for this shipment',	  'omit'	=> '',	  'ord'		=> $this->ID_Order	  ); $out = $objRows->AdminTable($arArgs); return $out; }   /*      HISTORY: 2010-10-23 added event logging using helper class */   protected function Log { if (!is_object($this->logger)) { $this->logger = new clsLogger_DataSet($this,$this->objDB->Events); }	return $this->logger; }   public function EventListing { return $this->Log->EventListing; }   public function DropDown($iName,$iDefault=NULL) { if ($this->HasRows) { $out = '<select name="'.$iName.'">'."\n"; while ($this->NextRow) { $id = $this->Value('ID'); if ($id == $iDefault) { $htSelect = " selected"; } else { $htSelect = ''; }		$htDescr = $this->Descr; $out .= "<option$htSelect value=\"$id\">$htDescr \n"; }	   $out .= ' '; } else { $out = 'No shipments matching filter'; }	return $out; }   public function Descr { $out = $this->Abbr; return $out; } } /****** TOPIC MANAGEMENT class clsAdminTopics extends clsTopics {

public function __construct($iDB) { parent::__construct($iDB); $this->ClassSng('clsAdminTopic'); $this->ActionKey('topic'); }   protected function AdminRedirect { global $vgPage; global $wgOut;

$ar = array('page'=>$this->ActionKey); $url = $vgPage->SelfURL($ar,TRUE); $wgOut->redirect($url); }   public function RootNode { $objRoot = $this->SpawnItem; $objRoot->ID = NULL; return $objRoot; }   /*      PURPOSE: renders tree with colors and links suitable for admin usage LATER: The parent method should be generalized for color and link-function */ /*   public function RenderTree($iTwig=NULL) { if (is_null($iTwig)) { $objRoot = $this->RootNode; } else { $objRoot = $this->GetItem($iTwig); }	$out = $objRoot->DrawTree; return $out; }   public function ListTitles_unassigned { global $vgPage;

$sql = 'SELECT tc.*, t.Name' .' FROM (_titles AS tc LEFT JOIN cat_title_x_topic AS tt ON tc.ID=tt.ID_Title)' .' LEFT JOIN cat_titles AS t ON tc.ID=t.ID' .' WHERE (tt.ID_Title IS NULL) AND (tc.cntForSale > 0)'; $rs = $this->Engine->DataSet($sql,$this->Engine->Titles->ClassSng); if ($rs->HasRows) { $vgPage->UseHTML; $rs->Table = $this->Engine->Titles; $out = "\n<ul>"; while ($rs->NextRow) { $out .= "\n<li>".$rs->AdminLink($rs->Value('CatNum')).' '.$rs->Value('Name').'</li>'; }	   $out .= "\n</ul>"; } else { $out = 'All active titles have topics.'; }	return $out; }   public function Data_forTitle($iTitle) { $sql = 'SELECT bt.* FROM cat_topic AS bt LEFT JOIN cat_title_x_topic AS bx ON bx.ID_Topic=bt.ID WHERE ID_Title='.$iTitle; $objRows = $this->Engine->DataSet($sql,$this->ClassSng); return $objRows; }   public function AdminPage { global $wgOut; global $vgPage,$vgOut;

$out = "\n".' ";

$arLink = array('rebuild'=>TRUE); $htLink = $vgPage->SelfURL($arLink,TRUE);

$doRebuild = $vgPage->Arg('rebuild');

if ($doRebuild) { // apparently there's no way to display a message without preventing the redirect $this->RenderTree(TRUE); $this->AdminRedirect; } else { $out .= "\n".'[<a href="'.$htLink.'">rebuild tree</a>]';

$this->TreeCtrl->FileForCSS('dtree.css'); $out .= $this->RenderTree(FALSE); }	$wgOut->AddHTML($out); $out = ''; return $out; }   /*      RETURNS: options array for entering topics USAGE: 1. fill in fHandleData_Change_Start, fHandleData_Change_Finish, fHandleData_Change_Item 2. Then, where $arOpts is the array returned: $ctrlList = new clsWidget_ShortList; $ctrlList->Options($arOpts); $htOut = $ctrlList->HandleInput; HISTORY: 2011-09-29 adapted from VbzAdminTitle::TopicListing */   public function TopicListing_base_array { $tblTopics = $this; $tblTopics->doBranch(TRUE); $arOpts = array(	 'name'	=> 'title',	  'btnChk_Text'	=> 'Enter topics:',	  'btnChg_Text' => '<= Add',	  'txtCargo_sng' => 'topic ID',	  'txtCargo_plr' => 'topic IDs',	  'txtProd_sng' => 'topic',	  'txtProd_plr' => 'topics',	  'txtConf_list' => 'Adding',	  'fHandleData_Check' => function($iVal) use ($tblTopics) {	      $obj = $tblTopics->GetItem($iVal);	// for now, assume topic is ID

$arOut['html'] = $obj->AdminLink_name; $arOut['text'] = $obj->KeyValue; return $arOut; },	 );	return $arOpts;    } } class clsAdminTopic extends clsTopic {    /*      HISTORY:	2010-12-05 boilerplate event logging added    */    //    // BOILERPLATE: event logging    protected function Log {	if (!is_object($this->logger)) {	    $this->logger = new clsLogger_DataSet($this,$this->objDB->Events);	}	return $this->logger;    }    public function StartEvent(array $iArgs) {	return $this->Log->StartEvent($iArgs);    }    public function FinishEvent(array $iArgs=NULL) {	return $this->Log->FinishEvent($iArgs);    }    public function EventListing {	return $this->Log->EventListing;    }    // BOILERPLATE: admin HTML    public function AdminURL {	return clsAdminData::_AdminURL($this);    }    public function AdminLink($iText=NULL,$iPopup=NULL,array $iarArgs=NULL) {	$strPopup = $this->AdminLink_default_popup($iPopup);	return clsAdminData::_AdminLink($this,$iText,$strPopup,$iarArgs); }   // END BOILERPLATES //   //    // Boilerplate auxiliary functions public function AdminLink_name { if ($this->IsNew) { return 'root'; } else { $txtShow = $this->Value('Name'); if ($this->doBranch) { $txtPopup = $this->RenderBranch_text('<'); } else { $txtPopup = $this->NameFull; }	   return $this->AdminLink($txtShow,$txtPopup); }   }    protected function AdminLink_default_popup($iOverrideText) { if (is_null($iOverrideText)) { $out = $this->Value('Name'); } else { $out = $iOverrideText; }	return $out; }   // END boilerplate auxiliary //   public function RenderBranch($iSep="&larr;") { $ftFullName = htmlspecialchars($this->Value('FullName')); $out = $this->AdminLink($this->Value('TreeName'),$ftFullName); if ($this->HasParent) { $out .= $iSep.$this->ParentObj->RenderBranch($iSep); }	return $out; }   public function Tree_RenderTwig($iCntTitles) { $cntTitles = $iCntTitles; $txtNoun = ' title'.Pluralize($cntTitles).' available';	// for topic #'.$id; $out = ' [<span style="color: #00cc00;" title="'.$cntTitles.$txtNoun.'">'.$cntTitles.' ]'; //	$txt = $this->Value('CatNum').' '.$this->Value('Name'); return $out; }   public function Tree_AddTwig(clsTreeNode $iTwig,$iText) { $id = $this->Value('ID'); //	$objSub = $iTwig->Add($id,$iText,$this->ShopURL); $objSub = $iTwig->Add($id,$iText,$this->AdminURL); return $objSub; }   public function AdminPage { global $wgOut,$wgRequest; global $vgPage,$vgOut;

$doEdit = $vgPage->Arg('edit'); $doSave = $wgRequest->GetBool('btnSave'); $doRmvTitles = $wgRequest->GetBool('btnRmvTitles');

$vgPage->UseHTML;

$strTitle = 'Topic: '.$this->Value('Name');

$objPage = new clsWikiFormatter($vgPage); $objSection = new clsWikiSection($objPage,$strTitle); $objSection->ToggleAdd('edit'); //$objSection->ActionAdd('view'); $out = $objSection->Generate;

// save edits before re-displaying data

// edits to this record $ftSaveStatus = NULL; if ($doEdit || $doSave) { $this->BuildEditForm; if ($doSave) { $ftSaveStatus = $this->AdminSave; }	}

// topic deletion if ($doRmvTitles) { // TO BE WRITTEN }

if ($doEdit) { $out .= $objSection->FormOpen; $objForm = $this->objForm;

$ctParent	= $objForm->Render('ID_Parent'); $ctName	= $objForm->Render('Name'); $ctNameTree	= $objForm->Render('NameTree'); $ctNameFull	= $objForm->Render('NameFull'); $ctNameMeta	= $objForm->Render('NameMeta'); $ctUsage	= $objForm->Render('Usage'); $ctSort	= $objForm->Render('Sort'); $ctVariants	= $objForm->Render('Variants'); $ctMispeled	= $objForm->Render('Mispeled'); } else { $ctParent	= $this->ParentObj->AdminLink_name; $ctName	= $this->Value('Name'); $ctNameTree	= $this->Value('NameTree'); $ctNameFull	= $this->Value('NameFull'); $ctNameMeta	= $this->Value('NameMeta'); $ctUsage	= $this->Value('Usage'); $ctSort	= $this->Value('Sort'); $ctVariants	= $this->Value('Variants'); $ctMispeled	= $this->Value('Mispeled'); }

$out .= '<ul>'; $out .= '<li> ID: '.$this->KeyValue.' ['.$this->ShopLink('shop').']'; $out .= '<li> Parent: '.$ctParent; $out .= '<li> Name: '.$ctName; $out .= '<ul>'; $out .= '<li> in tree: '.$ctNameTree; $out .= '<li> complete: '.$ctNameFull; $out .= '<li> meta: '.$ctNameMeta; $out .= '</ul>'; $out .= '<li> Usage: '.$ctUsage; $out .= '<li> Searching: '; $out .= '<ul>'; $out .= '<li> variants: '.$ctVariants; $out .= '<li> misspellings: '.$ctMispeled; $out .= '<li> sort by: '.$ctSort; $out .= '</ul>'; $out .= '</ul>';

if ($doEdit) { $out .= '<input type=submit name="btnSave" value="Save">'; $out .= '<input type=reset value="Reset">'; $out .= ' '; }	$wgOut->AddHTML($out); $wgOut->AddHTML(" Subtopics "); $wgOut->AddHTML($this->SubtopicListing); $wgOut->AddHTML(" Titles "); $wgOut->AddHTML($this->TitleListing); }   /*      ACTION: Save user changes to the record HISTORY: 2010-11-06 copied from VbzStockBin to VbzAdminItem 2011-01-26 copied from VbzAdminItem to clsAdminTopic */   public function AdminSave { global $vgOut;

$out = $this->objForm->Save; $vgOut->AddText($out); }   /*      HISTORY: 2010-11-06 adapted from VbzStockBin for VbzAdminTitle 2011-01-26 adapted from VbzAdminTitle */   private function BuildEditForm { global $vgOut;

if (is_null($this->objForm)) { // create fields & controls $objForm = new clsForm_DataSet($this,$vgOut); //$objCtrls = new clsCtrls($objForm->Fields); //$objCtrls = $objForm;

$objForm->AddField(new clsFieldNum('ID_Parent'),	new clsCtrlHTML); $objForm->AddField(new clsField('Name'),		new clsCtrlHTML(array('size'=>20))); $objForm->AddField(new clsField('NameTree'),	new clsCtrlHTML(array('size'=>15))); $objForm->AddField(new clsField('NameFull'),	new clsCtrlHTML(array('size'=>25))); $objForm->AddField(new clsField('NameMeta'),	new clsCtrlHTML(array('size'=>25))); $objForm->AddField(new clsField('Usage'),		new clsCtrlHTML(array('size'=>25))); $objForm->AddField(new clsField('Sort'),		new clsCtrlHTML(array('size'=>5))); $objForm->AddField(new clsField('Variants'),	new clsCtrlHTML(array('size'=>40))); $objForm->AddField(new clsField('Mispeled'),	new clsCtrlHTML(array('size'=>40)));

$this->objForm = $objForm; //$this->objCtrls = $objCtrls; }   }    protected function SubtopicListing { global $wgRequest;

$htStatus = NULL;

// set up the entry widget $ctrlList = new clsWidget_ShortList; $me = $this; $arOpts = array(	 'name'	=> 'topic',	  'btnChk_Text'	=> 'Enter subtopics:',	  'btnChg_Text' => '<= Create',	  'txtCargo_sng' => 'topic name',	  'txtCargo_plr' => 'topic names',	  'txtProd_sng' => 'subtopic',	  'txtProd_plr' => 'subtopics',	  'fHandleData_Check' => function($iVal) {	      $arOut['html'] = $iVal;	      $arOut['text'] = $iVal;	      return $arOut;	  },	  'fHandleData_Change_Start' => function($iText) use ($me) {	      $arEv = array( 'descr'	=> 'Adding '.$iText, 'code'	=> 'sub++', 'where'	=> __METHOD__ );	     $me->StartEvent($arEv);	  },	  'fHandleData_Change_Finish' => function($iText) use ($me) {	      $arEv = array( 'descrfin'	=> $iText );	     $me->FinishEvent($arEv);	  },	  'fHandleData_Change_Item' => function($iVal) use ($me) {	      $txt = $iVal;	      $arIns = array( 'ID_Parent'	=> SQLValue($me->KeyValue), 'Name'	=> SQLValue($txt) );	     $me->Table->Insert($arIns);	      $out = $me->Table->LastID;	      return $out;	  },	  ); $ctrlList->Options($arOpts); $htStatus = $ctrlList->HandleInput;

$out = "\n ";

$rs = $this->Subtopics; if ($rs->HasRows) { $out .= "\n "; } else { $out .= None found.; }	$out .= ' '.$htStatus; $out .= $ctrlList->RenderForm_Entry; $out .= ' '; return $out; }   protected function TitleListing { global $wgRequest; global $vgPage;

// check for any form actions $doChk = $wgRequest->GetBool('btnChkTitles'); $doAdd = $wgRequest->GetBool('btnAddTitles'); $doRmv = $wgRequest->GetBool('btnRmvTitles');

$htStatus = NULL;

// pass-along vars for anon functions $tblTitles = $this->Engine->Titles;	// for anon function to use $tblTitleTopics = $this->Engine->TitleTopics; $me = $this;

$ctrlList = new clsWidget_ShortList; $arOpts = array(	 'name'	=> 'title',	  'btnChk_Text'	=> 'Enter titles:',	  'btnChg_Text' => '<= Add',	  'txtCargo_sng' => 'title ID',	  'txtCargo_plr' => 'title IDs',	  'txtProd_sng' => 'title',	  'txtProd_plr' => 'titles',	  'fHandleData_Check' => function($iVal) use ($tblTitles) {	      $obj = $tblTitles->GetItem($iVal);	// for now, assume title is ID

$arOut['html'] = $obj->AdminLink($obj->CatNum,$obj->Value('Name')); //$arOut['text'] = $obj->KeyValue.'('.$obj->CatNum.')'; $arOut['text'] = $obj->KeyValue; return $arOut; },	 'fHandleData_Change_Start' => function($iText) use ($me) { $arEv = array(		'descr'	=> 'Adding '.$iText,		'code'	=> 'sub++',		'where'	=> __METHOD__		); $me->StartEvent($arEv); },	 'fHandleData_Change_Finish' => function($iText) use ($me) { $arEv = array(		'descrfin'	=> $iText		); $me->FinishEvent($arEv); },	 'fHandleData_Change_Item' => function($iVal) use ($me,$tblTitleTopics) { $txt = $iVal; $arIns = array(		'ID_Title'	=> SQLValue($txt),		'ID_Topic'	=> SQLValue($me->KeyValue)		); //$this->Engine->TitleTopics->Insert($arIns); $sql = $tblTitleTopics->Insert($arIns); $out = SQLValue($txt); return $out; },	 );	$ctrlList->Options($arOpts);	$htStatus = $ctrlList->HandleInput;	if ($wgRequest->GetBool('btnRmvTitles')) {	    $arRmv = $wgRequest->GetArray('rmvTitle');	    $cntRmv = count($arRmv);	    $arEv = array( 'descr'	=> 'Removing '.$cntRmv.' title'.Pluralize($cntRmv).' from this topic', 'code'	=> 'TTL--', 'where'	=> __METHOD__ );	   $this->StartEvent($arEv);	    $txtRmv = '';	    foreach ($arRmv as $id => $on) {		$sqlFilt = '(ID_Topic='.$this->ID.') AND (ID_Title='.$id.')';		$this->Engine->TitleTopics->Delete($sqlFilt);		$txtRmv .= ' '.$id;	    }	    $arEv = array( 'descrfin'	=> 'Titles removed:'.$txtRmv );	   $this->FinishEvent($arEv);	    $htStatus .= 'Titles removed:'.$txtRmv;	}

$out = "\n<form name=\"add-titles\" method=post>";

$rs = $this->Titles; if ($rs->HasRows) { $out .= "\n "; $out .= '<input type=submit name="btnRmvTitles" value="Remove Checked">'; } else { $out .= None found.; }	$out .= ' '.$htStatus; $out .= $ctrlList->RenderForm_Entry; /*	$out .= '<input type=submit name="btnChkTitles" value="Add These:">'; $out .= '<input size=40 name=txtNewTitles> (IDs separated by spaces)'; $out .= ' '; return $out; }   /*      What uses this?

*/   public function AdminList { $objRecs = $this;

if ($objRecs->HasRows) { $out = "{| class=sortable\n|-\n! ID || Name || Abbr || When Avail || Superceded || Status"; $isOdd = TRUE; while ($objRecs->NextRow) { $objTopic = $this->objDB->Topics->GetItem($this->ID_Topic); $id = $objTopic->ID; $ftID = $id; $out .= "\n|- style=\"$wtStyle\"". "\n| ".$ftID. ' || '.$objRecs->Name. ' || '.$objRecs->Abbr. ' || '.$strDate. ' || '.$strSuper. ' || '.$strStatus; $isOdd = !$isOdd; }	   $out .= "\n|}"; } else { $out = 'No topics found.'; }	return $out; }   /*      HISTORY: 2010-10-11 Created -- then discovered that it probably doesn't need to be a separate function... but I think it makes things clearer. */   public function Twigs { if (is_null($this->ID)) { $sql = 'ID_Parent IS NULL'; } else { $sql = 'ID_Parent='.$this->ID; }	$objRows = $this->Table->GetData($sql,NULL,'Sort,NameTree,Name'); return $objRows; }   public function DrawTree($iLevel=0,$iRootName="Topics") { global $vgPage;

$out = ''; $intLevel = $iLevel + 1; $strIndent = str_repeat('*',$intLevel);

$objRows = $this->Twigs; if ($objRows->HasRows) { if (empty($iLevel)) { $strName = $this->Name; if (empty($strName)) { $strName = $iRootName; }		$out .= "\n{{#tree:id=root|root=$strName|"; $vgPage->UseWiki; }	   while ($objRows->NextRow) { $strNameTree = $objRows->NameTree; $strTwig = ifEmpty($strNameTree,$objRows->Name); $out .= "\n$strIndent".$objRows->AdminLink($strTwig); $out .= $objRows->DrawTree($intLevel); }	   if ($iLevel == 0) { $out .= "\n}}"; $vgPage->UseWiki; }	   return $out; } else { if (empty($iLevel)) { return 'NO TOPICS FOUND'; } else { return NULL; }	}   } } class clsAdminTitleTopic_Titles extends clsTitleTopic_Titles { public function __construct(clsDatabase $iDB) { parent::__construct($iDB); $this->ClassSng('VbzAdminTitle'); $this->ActionKey($this->Engine->Titles->ActionKey); } } class clsAdminTitleTopic_Topics extends clsTitleTopic_Topics { public function __construct(clsDatabase $iDB) { parent::__construct($iDB); $this->ClassSng('clsAdminTopic'); $this->ActionKey($this->Engine->Topics->ActionKey); } } /*========== /* PURPOSE: This is the newer version of WhoString_wt which uses WhoAdmin, WhoSystem, and WhoNetwork instead of VbzUser, SysUser, and Machine function WhoString2_wt($iRow) { $htUnknown = ' ? ';
 * UTILITY FUNCTIONS
 * These should probably go into a separate file at some point

if (isset($iRow['WhoSystem'])) { $strSysUser	= $iRow['WhoSystem']; $hasSysUser 	= TRUE; } else { $strSysUser	= NULL; $hasSysUser	= FALSE; }   $strMachine	= $iRow['WhoNetwork']; $strVbzUser	= $iRow['WhoAdmin'];

$htSysUser	= is_null($strSysUser)?$htUnknown:$strSysUser; $htMachine	= is_null($strMachine)?$htUnknown:$strMachine; $htVbzUser	= is_null($strVbzUser)?$htUnknown:$strVbzUser;

$htWho = $htVbzUser; if ($hasSysUser) { $htWho .= '/'.$htSysUser; }   $htWho .= '@'.$htMachine;

return $htWho; } /* STATUS: DEPRECATED Where possible, convert table fieldnames to be compatible with WhoString2_wt function WhoString_wt($iRow) { $htUnknown = ' ? ';

if (isset($iRow['SysUser'])) { $strSysUser	= $iRow['SysUser']; $hasSysUser 	= TRUE; } else { $strSysUser	= NULL; $hasSysUser	= FALSE; }   $strMachine	= $iRow['Machine']; $strVbzUser	= $iRow['VbzUser'];

$htSysUser	= is_null($strSysUser)?$htUnknown:$strSysUser; $htMachine	= is_null($strMachine)?$htUnknown:$strMachine; $htVbzUser	= is_null($strVbzUser)?$htUnknown:$strVbzUser;

$htWho = $htVbzUser; if ($hasSysUser) { $htWho .= '/'.$htSysUser; }   $htWho .= '@'.$htMachine;

return $htWho; } function SelfLink_Page($iPage,$iKey,$iVal,$iText=NULL) { $strText = (is_null($iText))?$iVal:$iText; if (is_null($strText)) { return NULL; } else { return .$strText.; } }

function WikiSelfLink($iArgs,$iText) { // this function is deprecated; gradually convert to SelfLink and then rename it return '[ '.$iText.']'; } function WikiSectionHdr($iTitle,$iMenuName,array $iMenu) { global $vgPage;

$out = ' '; foreach ($iMenu as $name=>$arLink) { $htPath = $arLink['path']; $htPopup = $arLink['popup']; $htDispl = $arLink['displ']; $out .= ' [<a href="'.$htPath.'" title="'.$htPopup.'">'.$htDispl.'</a>] '; }   $out .= ' '.$iTitle.' '; return $out; } function WikiSectionHdr_Edit($iTitle,$iEditTitle) { global $vgPage; //   global $vgOut;

$doEdit = $vgPage->Arg('edit'); $arLink = array(     'edit'	=> !$doEdit,      'page'	=> $vgPage->Arg('page'),      'id'	=> $vgPage->Arg('id')      ); $htPath = $vgPage->SelfURL($arLink,TRUE);

$out = ' '; if ($doEdit) { $out .= ' [<a href="'.$htPath.'" title="View '.$iEditTitle.'">view</a>] '; } else { $out .= ' [<a href="'.$htPath.'" title="Edit '.$iEditTitle.'">edit</a>] '; }   $out .= ' '.$iTitle.' '; return $out; }

if (!function_exists('TimeStamp_HideTime')) { //-- function TimeStamp_HideTime($iStamp) {

if (is_string($iStamp)) { $intStamp = strtotime($iStamp); } else if (is_int($iStamp)) { $intStamp = $iStamp; } else { $intStamp = NULL; }   if (!is_null($intStamp)) { return date('Y-m-d',$intStamp); } else { return NULL; } } //-- }

function IsWebSecure { if (isset($_SERVER["HTTPS"])) { return $_SERVER["HTTPS"] == 'on'; } else { return FALSE; } }