|
|
(3 intermediate revisions by the same user not shown) |
Line 3: |
Line 3: |
| * '''History''': | | * '''History''': |
| ** '''2011-12-18''' Saving current code just before making some API changes | | ** '''2011-12-18''' Saving current code just before making some API changes |
| + | ** '''2013-02-20''' About to rework part of the checkout -- combining shipping and payment pages; mostly works as-is, but iffy. |
| * '''Alternatives''': | | * '''Alternatives''': |
| ** [[/2011-12-18]] - got too ugly and complicated and unreliable | | ** [[/2011-12-18]] - got too ugly and complicated and unreliable |
Line 9: |
Line 10: |
| <?php | | <?php |
| /* | | /* |
− | PURPOSE: vbz class library for handling dynamic data related to shopping (cart, mainly) | + | PURPOSE: vbz library for handling dynamic data related to shopping (cart, mainly) |
| HISTORY: | | HISTORY: |
| 2010-10-28 kluged the blank-order-email problem | | 2010-10-28 kluged the blank-order-email problem |
Line 21: |
Line 22: |
| define('KWP_ICON_ALERT' ,'/tools/img/icons/button-red-X.20px.png'); | | define('KWP_ICON_ALERT' ,'/tools/img/icons/button-red-X.20px.png'); |
| | | |
− | // TABLE NAMES:
| |
− | define('KST_CART_DATA' ,'shop_cart_data');
| |
| | | |
| // TABLE ACTION KEYS | | // TABLE ACTION KEYS |
Line 29: |
Line 28: |
| define('KS_URL_PAGE_ORDERS', 'orders'); | | define('KS_URL_PAGE_ORDERS', 'orders'); |
| | | |
− | // FORM FIELD NAMES:
| + | if (!defined('LIBMGR')) { |
− | // -- cart/shipping
| + | require(KFP_LIB.'/libmgr.php'); |
− | define('KSF_SHIP_ZONE' ,'ship-zone');
| + | } |
− | // -- shipping
| |
− | define('KSF_SHIP_TO_SELF' ,'ship-to-self'); // TRUE = use shipping info for recipient too
| |
− | define('KSF_SHIP_IS_CARD' ,'ship-is-billing'); // TRUE = shipping address same as billing/card
| |
− | define('KSF_SHIP_MESSAGE' ,'ship-message');
| |
− | // address fields: prefix with "ship" or "card" as appropriate
| |
− | define('_KSF_ADDR_NAME' ,'addr-name');
| |
− | define('_KSF_ADDR_STREET' ,'addr-street');
| |
− | define('_KSF_ADDR_CITY' ,'addr-city');
| |
− | define('_KSF_ADDR_STATE' ,'addr-state');
| |
− | define('_KSF_ADDR_ZIP' ,'addr-zip');
| |
− | define('_KSF_ADDR_COUNTRY' ,'addr-country');
| |
− | define('_KSF_ADDR_EMAIL' ,'addr-email');
| |
− | define('_KSF_ADDR_PHONE' ,'addr-phone');
| |
− | | |
− | // for retrieving field data:
| |
− | define('KSF_PFX_SHIP', 'ship-');
| |
− | define('KSF_ADDR_SHIP_NAME' ,KSF_PFX_SHIP._KSF_ADDR_NAME);
| |
− | define('KSF_ADDR_SHIP_STREET' ,KSF_PFX_SHIP._KSF_ADDR_STREET);
| |
− | define('KSF_ADDR_SHIP_CITY' ,KSF_PFX_SHIP._KSF_ADDR_CITY);
| |
− | define('KSF_ADDR_SHIP_STATE' ,KSF_PFX_SHIP._KSF_ADDR_STATE);
| |
− | define('KSF_ADDR_SHIP_ZIP' ,KSF_PFX_SHIP._KSF_ADDR_ZIP);
| |
− | define('KSF_ADDR_SHIP_COUNTRY' ,KSF_PFX_SHIP._KSF_ADDR_COUNTRY);
| |
− | define('KSF_CUST_SHIP_EMAIL' ,KSF_PFX_SHIP._KSF_ADDR_EMAIL);
| |
− | define('KSF_CUST_SHIP_PHONE' ,KSF_PFX_SHIP._KSF_ADDR_PHONE);
| |
− | | |
− | // -- payment
| |
− | define('KSF_CUST_CARD_NUM' ,'cust-card-num');
| |
− | define('KSF_CUST_CARD_EXP' ,'cust-card-exp');
| |
− | define('KSF_CUST_CARD_NAME' ,'cust-card-name');
| |
− | define('KSF_CUST_CARD_STREET' ,'cust-card-street');
| |
− | define('KSF_CUST_CARD_CITY' ,'cust-card-city');
| |
− | define('KSF_CUST_CARD_STATE' ,'cust-card-state');
| |
− | define('KSF_CUST_CARD_ZIP' ,'cust-card-zip');
| |
− | define('KSF_CUST_CARD_COUNTRY' ,'cust-card-country');
| |
− | define('KSF_CUST_CHECK_NUM' ,'cust-check-num');
| |
− | define('KSF_CUST_PAY_EMAIL' ,'cust-pay-email');
| |
− | define('KSF_CUST_PAY_PHONE' ,'cust-pay-phone');
| |
− | // DATA STORAGE KEYS:
| |
− | // -- shipping
| |
− | define('KSI_SHIP_ZONE' ,100);
| |
− | | |
− | define('KSI_ADDR_SHIP_NAME' ,101);
| |
− | define('KSI_ADDR_SHIP_STREET' ,102);
| |
− | define('KSI_ADDR_SHIP_CITY' ,103);
| |
− | define('KSI_ADDR_SHIP_STATE' ,104);
| |
− | define('KSI_ADDR_SHIP_ZIP' ,105);
| |
− | define('KSI_ADDR_SHIP_COUNTRY' ,106);
| |
− | define('KSI_SHIP_MESSAGE' ,107);
| |
− | define('KSI_SHIP_TO_SELF' ,110);
| |
− | define('KSI_SHIP_IS_CARD' ,113);
| |
− | | |
− | define('KSI_CUST_SHIP_EMAIL' ,111);
| |
− | define('KSI_CUST_SHIP_PHONE' ,112);
| |
− | //define('KSI_SHIP_MISSING' ,120);
| |
− | // -- payment
| |
− | define('KSI_CUST_CARD_NUM' ,202);
| |
− | define('KSI_CUST_CARD_EXP' ,203);
| |
− | | |
− | define('KSI_ADDR_CARD_NAME' ,204);
| |
− | define('KSI_CUST_CARD_NAME' ,KSI_ADDR_CARD_NAME); // alias
| |
− | define('KSI_ADDR_CARD_STREET' ,205);
| |
− | define('KSI_CUST_CARD_STREET' ,KSI_ADDR_CARD_STREET); // alias
| |
− | define('KSI_ADDR_CARD_CITY' ,206);
| |
− | define('KSI_CUST_CARD_CITY' ,KSI_ADDR_CARD_CITY);
| |
− | define('KSI_ADDR_CARD_STATE' ,207);
| |
− | define('KSI_CUST_CARD_STATE' ,KSI_ADDR_CARD_STATE);
| |
− | define('KSI_ADDR_CARD_ZIP' ,208);
| |
− | define('KSI_CUST_CARD_ZIP' ,KSI_ADDR_CARD_ZIP);
| |
− | define('KSI_ADDR_CARD_COUNTRY' ,209);
| |
− | define('KSI_CUST_CARD_COUNTRY' ,KSI_ADDR_CARD_COUNTRY);
| |
− | | |
− | define('KSI_CUST_PAY_EMAIL' ,211);
| |
− | define('KSI_CUST_PAY_PHONE' ,212);
| |
− | //define('KSI_CUST_MISSING' ,220);
| |
− | define('KSI_CUST_CHECK_NUM' ,230);
| |
| | | |
− | // calculated data
| + | clsLibMgr::Add('strings', KFP_LIB.'/strings.php',__FILE__,__LINE__); |
− | define('KSI_ITEM_TOTAL' ,301);
| + | clsLibMgr::Add('string.tplt', KFP_LIB.'/StringTemplate.php',__FILE__,__LINE__); |
− | define('KSI_PER_ITEM_TOTAL' ,302);
| + | clsLibMgr::Add('tree', KFP_LIB.'/tree.php',__FILE__,__LINE__); |
− | define('KSI_PER_PKG_TOTAL' ,303);
| + | clsLibMgr::Add('vbz.store', KFP_LIB_VBZ.'/store.php',__FILE__,__LINE__); |
− | | + | clsLibMgr::AddClass('clsVbzPage', 'vbz.store'); |
− | // ORDER MESSAGE TYPES
| + | clsLibMgr::Add('vbz.cart', KFP_LIB_VBZ.'/cart.php',__FILE__,__LINE__); |
− | // these reflect the values in the ord_msg_media table
| + | clsLibMgr::AddClass('clsPageCart', 'vbz.cart'); |
− | define('KSI_ORD_MSG_INSTRUC', 1); // Instructions in submitted order
| + | clsLibMgr::AddClass('clsShopCarts','vbz.cart'); |
− | define('KSI_ORD_MSG_PKSLIP', 2); // Packing slip
| + | clsLibMgr::Add('vbz.order', KFP_LIB_VBZ.'/orders.php',__FILE__,__LINE__); |
− | define('KSI_ORD_MSG_EMAIL', 3); // Email
| + | clsLibMgr::AddClass('clsOrders', 'vbz.order'); |
− | define('KSI_ORD_MSG_PHONE', 4); // Phone call
| + | clsLibMgr::Load('strings',__FILE__,__LINE__); |
− | define('KSI_ORD_MSG_MAIL', 5); // Snail mail
| + | clsLibMgr::Load('string.tplt',__FILE__,__LINE__); |
− | define('KSI_ORD_MSG_FAX', 6); // Faxed message
| + | clsLibMgr::Load('tree',__FILE__,__LINE__); |
− | define('KSI_ORD_MSG_LABEL', 7); // Shipping label (for delivery instructions)
| + | clsLibMgr::Load('vbz.store',__FILE__,__LINE__); |
− | define('KSI_ORD_MSG_INT', 8); // internal use - stored, not sent
| + | // clsLibMgr::Load('vbz.cart',__FILE__,__LINE__); |
− | | |
− | global $vgaCartDataType; // documentation says this shouldn't be necessary
| |
− | $vgaCartDataType = array (
| |
− | KSI_SHIP_ZONE => 'ship zone',
| |
− | KSI_ADDR_SHIP_NAME => 'ship-to name',
| |
− | KSI_ADDR_SHIP_STREET => 'ship-to street',
| |
− | KSI_ADDR_SHIP_CITY => 'ship-to city',
| |
− | KSI_ADDR_SHIP_STATE => 'ship-to state',
| |
− | KSI_ADDR_SHIP_ZIP => 'ship-to zipcode',
| |
− | KSI_ADDR_SHIP_COUNTRY => 'ship-to country',
| |
− | KSI_SHIP_MESSAGE => 'ship-to message',
| |
− | KSI_SHIP_TO_SELF => 'ship to self?',
| |
− | KSI_SHIP_IS_CARD => 'ship to = card?',
| |
− | KSI_CUST_SHIP_EMAIL => 'ship-to email',
| |
− | KSI_CUST_SHIP_PHONE => 'ship-to phone',
| |
− | // KSI_SHIP_MISSING => 'ship-to missing info', | |
− | // -- payment
| |
− | KSI_CUST_CARD_NUM => 'card number',
| |
− | KSI_CUST_CARD_EXP => 'card expiry',
| |
− | KSI_ADDR_CARD_NAME => 'card owner',
| |
− | KSI_ADDR_CARD_STREET => 'card street address',
| |
− | KSI_ADDR_CARD_CITY => 'card address city',
| |
− | KSI_ADDR_CARD_STATE => 'card address state',
| |
− | KSI_ADDR_CARD_ZIP => 'card zipcode',
| |
− | KSI_ADDR_CARD_COUNTRY => 'card country',
| |
− | KSI_CUST_CHECK_NUM => 'check number',
| |
− | KSI_CUST_PAY_EMAIL => 'customer email',
| |
− | KSI_CUST_PAY_PHONE => 'customer phone',
| |
− | | |
− | KSI_ITEM_TOTAL => 'item total',
| |
− | KSI_PER_ITEM_TOTAL => 's/h per-item total',
| |
− | KSI_PER_PKG_TOTAL => 's/h package total',
| |
− | );
| |
− | | |
− | if (defined('LIBMGR')) {
| |
− | clsLibMgr::Add('strings', KFP_LIB.'/strings.php',__FILE__,__LINE__);
| |
− | clsLibMgr::Add('string.tplt', KFP_LIB.'/StringTemplate.php',__FILE__,__LINE__);
| |
− | clsLibMgr::Add('tree', KFP_LIB.'/tree.php',__FILE__,__LINE__);
| |
− | clsLibMgr::Add('vbz.store', KFP_LIB_VBZ.'/store.php',__FILE__,__LINE__);
| |
− | clsLibMgr::Load('strings',__FILE__,__LINE__);
| |
− | clsLibMgr::Load('string.tplt',__FILE__,__LINE__);
| |
− | clsLibMgr::Load('tree',__FILE__,__LINE__);
| |
− | clsLibMgr::Load('vbz.store',__FILE__,__LINE__);
| |
− | } else {
| |
− | // assume all libraries are on path | |
− | require_once(KFP_LIB.'/strings.php');
| |
− | require_once(KFP_LIB.'/StringTemplate.php');
| |
− | require_once('store.php');
| |
− | require_once(KFP_LIB.'/tree.php');
| |
− | }
| |
| | | |
| define('KS_VBZCART_SESSION_KEY','vbzcart_key'); | | define('KS_VBZCART_SESSION_KEY','vbzcart_key'); |
Line 184: |
Line 58: |
| define('KSQ_PAGE_SHIP','ship'); // shipping page | | define('KSQ_PAGE_SHIP','ship'); // shipping page |
| define('KSQ_PAGE_PAY','pay'); // payment page | | define('KSQ_PAGE_PAY','pay'); // payment page |
| + | define('KSQ_PAGE_CONT','cont'); // contact page -- shipping and payment |
| define('KSQ_PAGE_CONF','conf'); // customer confirmation of order | | define('KSQ_PAGE_CONF','conf'); // customer confirmation of order |
| define('KSQ_PAGE_RCPT','rcpt'); // order receipt | | define('KSQ_PAGE_RCPT','rcpt'); // order receipt |
Line 192: |
Line 67: |
| database class with creators for shop classes | | database class with creators for shop classes |
| */ | | */ |
− | abstract class clsPageShop extends clsPage {
| + | class clsVbzData_Shop extends clsVbzData { |
− | public function Sessions() { | + | public function Sessions($id=NULL) { |
− | return $this->Make('clsShopSessions'); | + | return $this->Make('clsSessions_StoreUI',$id); |
| } | | } |
− | public function Clients() { | + | public function Clients($id=NULL) { |
− | return $this->Make('clsShopClients'); | + | return $this->Make('clsShopClients',$id); |
| } | | } |
− | public function Carts() { | + | public function Carts($id=NULL) { |
− | return $this->Make('clsShopCarts'); | + | return $this->Make('clsShopCarts',$id); |
| } | | } |
− | public function CartLines() { | + | public function CartLines($id=NULL) { |
− | return $this->Make('clsShopCartLines'); | + | return $this->Make('clsShopCartLines',$id); |
| } | | } |
| public function CartLog() { | | public function CartLog() { |
| return $this->Make('clsShopCartLog'); | | return $this->Make('clsShopCartLog'); |
| } | | } |
− | public function Orders() { | + | public function Orders($id=NULL) { |
− | return $this->Make('clsOrders'); | + | return $this->Make('clsOrders',$id); |
| } | | } |
− | public function OrdLines() { | + | public function OrdLines($id=NULL) { |
− | return $this->Make('clsOrderLines'); | + | return $this->Make('clsOrderLines',$id); |
| } | | } |
| /* | | /* |
Line 219: |
Line 94: |
| } | | } |
| */ | | */ |
− | public function OrdMsgs() { | + | public function OrdMsgs($id=NULL) { |
− | return $this->Make('clsOrderMsgs'); | + | return $this->Make('clsOrderMsgs',$id); |
| } | | } |
| /* | | /* |
Line 244: |
Line 119: |
| } | | } |
| | | |
− | class clsPageCart extends clsPageShop {
| + | /*================== |
− | protected $objSess;
| + | CLASS: clsShipZone |
− | protected $objCart;
| + | PURPOSE: shipping zone functions |
− | | + | USAGE: Customize the isDomestic() function if you're shipping from somewhere other than the US |
− | // process functions
| |
− | public function DoPreContent() {
| |
− | $this->inCkout = FALSE; // (2011-04-01) not sure why this is sometimes not getting set
| |
− | parent::DoPreContent();
| |
− | }
| |
− | /*----
| |
− | INPUT: $iCaller is for debugging and is discarded; caller should pass __METHOD__ as the argument.
| |
− | */
| |
− | public function GetObjects($iCaller) {
| |
− | $objSessions = $this->Sessions();
| |
− | $this->objSess = $objSessions->GetCurrent(); // get whatever session is currently applicable (existing or new)
| |
− | $this->objCart = $this->objSess->CartObj();
| |
− | $this->objCart->objSess = $this->objSess; // used for logging
| |
− | }
| |
− | public function Cart($iObj=NULL) {
| |
− | if (!is_null($iObj)) {
| |
− | $this->objCart = $iObj;
| |
− | }
| |
− | return $this->objCart;
| |
− | }
| |
− | protected function HandleInput() {
| |
− | $this->GetObjects(__METHOD__);
| |
− | $this->objCart->CheckData(); // check for any form data (added items, recalculations, etc.)
| |
− | | |
− | $this->strSheet = 'cart'; // cart stylesheet has a few different things in it
| |
− | | |
− | $this->strWikiPg = '';
| |
− | $this->strTitle = 'Shopping Cart'; // Displayed title (page header)
| |
− | $this->strName = 'shopping cart'; // HTML title
| |
− | $this->strTitleContext = 'this is your'; // 'Tomb of the...';
| |
− | $this->strHdrXtra = '';
| |
− | $this->strSideXtra = ''; //'<dt><b>Cat #</b>: '.$this->strReq;
| |
− | $this->strSheet = KSQ_PAGE_CART; // default
| |
− | }
| |
− | protected function DoContent() {
| |
− | echo $this->objCart->Render();
| |
− | }
| |
− | }
| |
− | | |
− | /* ==================== *\
| |
− | || -- HELPER CLASSES -- ||
| |
− | \* ==================== */
| |
− | | |
− | /*====
| |
− | PURPOSE: parent class for all cart contact nodes | |
− | HISTORY:
| |
− | 2011-11-26 started experimentally
| |
− | */
| |
− | abstract class clsContactNode extends clsTreeNode {
| |
− | | |
− | protected $actSave; // script created to record this data; NULL = not created yet
| |
− | | |
− | public function __construct($iNodes=NULL) {
| |
− | parent::__construct($iNodes);
| |
− | $this->actSave = NULL;
| |
− | }
| |
− | public function ScriptMe() {
| |
− | return $this->actSave;
| |
− | }
| |
− | /*
| |
− | protected function ScriptUp() {
| |
− | if ($this->HasParent()) {
| |
− | return $this->Parent()->ScriptMe();
| |
− | } else {
| |
− | return NULL;
| |
− | }
| |
− | }
| |
− | */
| |
− | public function ScriptRoot() {
| |
− | if (is_null($this->Parent())) {
| |
− | throw new exception('Internal Error: Expecting parent, but it is NULL. CLASS: '.get_class($this).' CTRL: '.$this->CtrlName());
| |
− | }
| |
− | return $this->Parent()->ScriptRoot();
| |
− | }
| |
− | /*----
| |
− | RETURNS: a "starter" script object to use for generating this object's scripts
| |
− | There's probably a better way to do this.
| |
− | */
| |
− | public function ScriptStart() {
| |
− | return new Script_Script();
| |
− | }
| |
− | public function Engine() {
| |
− | if (is_null($this->Parent())) {
| |
− | throw new exception('Object (class '.get_class($this).') has no parent.');
| |
− | }
| |
− | return $this->Parent()->Engine();
| |
− | }
| |
− | public function Save() {
| |
− | $acts = NULL;
| |
− | if ($this->AccessCount() == 0) {
| |
− | $acts = $this->ScriptStart();
| |
− | | |
− | $acts->Add($this->SaveThis(),'this');
| |
− | $acts->Add($this->SaveSubs(),'subs');
| |
− | $acts->Add($this->SavePost($acts),'post');
| |
− | | |
− | if ($acts->IsEmpty()) {
| |
− | $acts = NULL;
| |
− | }
| |
− | }
| |
− | $this->IncCount();
| |
− | $this->actSave = $acts;
| |
− | return $acts;
| |
− | }
| |
− | abstract protected function SaveThis();
| |
− | protected function SavePost(Script_Script $iScript) {}
| |
− | | |
− | /*----
| |
− | ACTION: Save sub-nodes
| |
− | */
| |
− | protected function SaveSubs() {
| |
− | if ($this->HasNodes()) {
| |
− | $acts = new Script_Script();
| |
− | $ar = $this->Nodes();
| |
− | foreach ($ar as $name => $obj) {
| |
− | $acts->Add($obj->Save(),$name);
| |
− | }
| |
− | } else {
| |
− | $acts = NULL;
| |
− | }
| |
− | return $acts;
| |
− | }
| |
− | }
| |
− | /*====
| |
− | PURPOSE: a contact node that holds other nodes but has no data of its own | |
− | HISTORY: | |
− | 2011-11-29 created
| |
− | */
| |
− | class clsContactFolder extends clsContactNode {
| |
− | protected function SaveThis() {} // nothing to save here; only saves sub-nodes
| |
− | }
| |
− | class clsContactFolder_reference extends clsContactFolder {
| |
− | protected function SaveSubs() {} // do not save sub-nodes; they are for reference only
| |
− | | |
− | /*----
| |
− | OVERRIDE: does not set the nodes' parents, because they may be parented elsewhere
| |
− | Otherwise we might get recursion.
| |
− | */
| |
− | /* not sure if this is actually necessary; the problem seems to be something else
| |
− | protected function NodeAdd($iName,clsTreeNode $iNode) {
| |
− | $this->arSubs[$iName] = $iNode;
| |
− | }
| |
− | */
| |
− | }
| |
− | class clsContactRoot extends clsContactFolder {
| |
− | protected $objDB;
| |
− | protected $actSave;
| |
− | | |
− | public function __construct(clsPageShop $iDB) {
| |
− | $this->objDB = $iDB;
| |
− | $this->actSave = NULL;
| |
− | }
| |
− | public function Engine() {
| |
− | return $this->objDB;
| |
− | }
| |
− | public function ScriptRoot() {
| |
− | if (is_null($this->actSave)) {
| |
− | $this->actSave = $this->ScriptStart();
| |
− | }
| |
− | return $this->actSave;
| |
− | }
| |
− | public function Save() {
| |
− | $this->ResetCount();
| |
− | return parent::Save();
| |
− | }
| |
− | }
| |
− | /*====
| |
− | PURPOSE: Generic cart data field, no special handling
| |
− | HISTORY:
| |
− | 2011-11-29 changed ancestry from clsTreeNode to clsContactNode
| |
− | */
| |
− | class clsCartField extends clsContactNode {
| |
− | protected $objCart;
| |
− | protected $intIndex; // index of field type
| |
− | protected $strCtrlName; // name of control (on form)
| |
− | | |
− | public function __construct($iCart, $iIndex, $iCtrlName) {
| |
− | if (is_object($iIndex)) {
| |
− | echo '<b>Internal error</b>: argument $iIndex is an object of class '.get_class($iIndex).', not a scalar.<br>';
| |
− | throw new exception('Unexpected argument type.');
| |
− | }
| |
− | $this->objCart = $iCart;
| |
− | $this->intIndex = $iIndex;
| |
− | $this->strCtrlName = $iCtrlName;
| |
− | }
| |
− | protected function SaveThis() { } // define later
| |
− | public function DataType() {
| |
− | return $this->intIndex;
| |
− | }
| |
− | public function Value($iVal=NULL) {
| |
− | // overrides default action by loading data from database if needed
| |
− | if (!is_null($iVal)) {
| |
− | die('writing to read-only clsTreeNode object');
| |
− | // this should never happen, because we're not using this class to write these values
| |
− | }
| |
− | if (!$this->Loaded()) {
| |
− | if (is_null($this->intIndex)) {
| |
− | $this->vVal = NULL;
| |
− | } else {
| |
− | $this->vVal = $this->objCart->DataItem($this->intIndex);
| |
− | }
| |
− | } else {
| |
− | }
| |
− | return $this->vVal;
| |
− | }
| |
− | public function CtrlName() {
| |
− | return $this->strCtrlName;
| |
− | }
| |
− | }
| |
− | | |
− | class clsCartAddr extends clsContactFolder {
| |
− | //class clsCartAddr extends clsTreeNode {
| |
− | public $doFixed;
| |
− | public $doFixedCountry; // Country is sometimes determined by Zone
| |
− | public $strStateLabel; // label for "State" field
| |
− | public $strStatePost; // text for after "State" field
| |
− | public $lenStateField; // approximate width of "State" field
| |
− | public $strZipLabel; // label for "Zipcode"/"Postal code" field
| |
− | | |
− | // protected function SaveThis() { } // stubbed off for customer-side pages
| |
− | /*----
| |
− | OVERRIDE: Name is saved normally, but other data is saved in aggregate by SaveThis()
| |
− | */
| |
− | protected function SaveSubs() {
| |
− | return $this->Name()->Save();
| |
− | }
| |
− | | |
− | public function Name() {
| |
− | return $this->Node('name');
| |
− | }
| |
− | public function Street() {
| |
− | return $this->Node('street');
| |
− | }
| |
− | public function City() {
| |
− | return $this->Node('city');
| |
− | }
| |
− | public function State() {
| |
− | return $this->Node('state');
| |
− | }
| |
− | public function Zip() {
| |
− | return $this->Node('zip');
| |
− | }
| |
− | public function Country() {
| |
− | return $this->Node('country');
| |
− | }
| |
− | public function HasCountry() {
| |
− | return $this->Exists('country');
| |
− | }
| |
− | public function Instruc() {
| |
− | return $this->Node('instruc');
| |
− | }
| |
− | public function Render($iCart) {
| |
− | | |
− | // copy calculated stuff over to variables to make it easier to insert in formatted output:
| |
− | $ksName = $this->Name()->CtrlName();
| |
− | $ksStreet = $this->Street()->CtrlName();
| |
− | $ksCity = $this->City()->CtrlName();
| |
− | $ksState = $this->State()->CtrlName();
| |
− | $ksZip = $this->Zip()->CtrlName();
| |
− | $ksCountry = $this->Country()->CtrlName();
| |
− | | |
− | $strName = $this->Name()->Value();
| |
− | $strStreet = $this->Street()->Value();
| |
− | $strCity = $this->City()->Value();
| |
− | $strState = $this->State()->Value();
| |
− | $strZip = $this->Zip()->Value();
| |
− | $strCountry = $this->Country()->Value();
| |
− | | |
− | $strStateLabel = $this->strStateLabel;
| |
− | $strZipLabel = $this->strZipLabel;
| |
− | $lenState = $this->lenStateField;
| |
− | $strStateAfter = $this->strStatePost;
| |
− | | |
− | if ($this->doFixedCountry) {
| |
− | $htCountry = '<b>'.$strCountry.'</b>';
| |
− | $htZone = '';
| |
− | } else {
| |
− | $htCountry = '<input name="'.$ksCountry.'" value="'.$strCountry.'" size=20>';
| |
− | $htShipCombo = $this->htShipCombo;
| |
− | $htBtnRefresh = '<input type=submit name="update" value="Update Form">';
| |
− | $htZone = " - change shippping zone: $htShipCombo $htBtnRefresh";
| |
− | }
| |
− | | |
− | if ($this->doFixedName) {
| |
− | $out = <<<__END__
| |
− | <tr><td align=right valign=middle>Name:</td>
| |
− | <td><b>$strName</b></td>
| |
− | </tr>
| |
− | __END__;
| |
− | } else {
| |
− | $out = <<<__END__
| |
− | <tr><td align=right valign=middle>Name: </td>
| |
− | <td><input name="$ksName" value="$strName" size=50></td>
| |
− | </tr>
| |
− | __END__;
| |
− | }
| |
− | $out .= $this->htmlBeforeAddress;
| |
− | if ($this->doFixed) {
| |
− | $out .= <<<__END__
| |
− | <tr><td align=right valign=middle>Street Address<br>or P.O. Box:</td>
| |
− | <td><b>$strStreet</b></td>
| |
− | </tr>
| |
− | <tr><td align=right valign=middle>City:</td><td><b>$strCity</b></td></tr>
| |
− | <tr><td align=right valign=middle>$strStateLabel:</td><td><b>$strState</b></td></tr>
| |
− | <tr><td align=right valign=middle>$strZipLabel:</td><td><b>$strZip</b></td></tr>
| |
− | <tr><td align=right valign=middle>Country:</td><td><b>$htCountry<b>$htZone</td></tr>
| |
− | __END__;
| |
− | } else {
| |
− | $out .= <<<__END__
| |
− | <tr><td align=right valign=middle>Street Address<br>or P.O. Box:</td>
| |
− | <td><textarea name="$ksStreet" cols=50 rows=3>$strStreet</textarea></td>
| |
− | </tr>
| |
− | <tr><td align=right valign=middle>City: </td><td><input name="$ksCity" value="$strCity" size=20></td></tr>
| |
− | <tr><td align=right valign=middle>$strStateLabel: </td><td><input name="$ksState" value="$strState" size=$lenState>$strStateAfter</td></tr>
| |
− | <tr><td align=right valign=middle>$strZipLabel: </td><td><input name="$ksZip" value="$strZip" size=11></td></tr>
| |
− | <tr><td align=right valign=middle>Country: </td><td>$htCountry - change shippping zone: $htShipCombo $htBtnRefresh</td></tr>
| |
− | __END__;
| |
− | }
| |
− | return $out;
| |
− | }
| |
− | /*----
| |
− | RETURNS: Complete address as single string, in multiple lines
| |
− | HISTORY:
| |
− | 2010-09-13 Added a line for Instruc()
| |
− | */
| |
− | public function AsText($iLineSep="\n") {
| |
− | $xts = new xtString($this->Street()->Value(),TRUE);
| |
− | $xts-> ReplaceSequence(chr(8).' ',' ',0); // replace any blank sequences with single space
| |
− | $xts->ReplaceSequence(chr(10).chr(13),$iLineSep,0); // replace any sequences of newlines with line sep string
| |
− | | |
− | $xts->Value .= $iLineSep.$this->City()->Value();
| |
− | if ($this->State()->Filled()) {
| |
− | $xts->Value .= ', '.$this->State()->Value();
| |
− | }
| |
− | if ($this->Zip()->Filled()) {
| |
− | $xts->Value .= ' '.$this->Zip()->Value();
| |
− | }
| |
− | if ($this->Country()->Filled()) {
| |
− | $xts->Value .= ' '.$this->Country()->Value();
| |
− | }
| |
− | if ($this->Instruc()->Filled()) {
| |
− | $xts->Value .= $iLineSep.$this->Instruc()->Value();
| |
− | }
| |
− | return $xts->Value;
| |
− | }
| |
− | public function AsSingleLine() {
| |
− | return $this->AsText(' / ');
| |
− | }
| |
− | public function AsSearchable() {
| |
− | $out = $this->Street()->Value();
| |
− | $out .= $this->City()->Value();
| |
− | $out .= $this->State()->Value();
| |
− | $out .= $this->Zip()->Value();
| |
− | /* including the country when creating the search string causes issues:
| |
− | if the country is domestic, then we don't want to include it (because many people won't)...
| |
− | so we need to have some way of determining whether this is so -- but that's currently locked inside
| |
− | the ShipZone data, which isn't always available. Need to have a mapping of countries to zones, and
| |
− | more rigorous handling of country inputs.
| |
− | | |
− | For now, just leave it out (how likely is it that an address in another country will match, including postal code?)
| |
− | */
| |
− | // $out .= $this->Country()->Value();
| |
− | $out = clsCustAddrs::Searchable($out);
| |
− | return $out;
| |
− | }
| |
− | }
| |
− | // contact fields
| |
− | class clsCartContact extends clsContactFolder {
| |
− | // public $Addr;
| |
− | public $doFixed;
| |
− | | |
− | /*----
| |
− | HISTORY:
| |
− | 2011-10-05 Apparently, when addr is the same for payment and shipping,
| |
− | the default is to put it under payment rather than with the
| |
− | other contact info (phone, email).
| |
− | | |
− | If I can't figure out why this is, I'll probably switch it around later.
| |
− | | |
− | In any case, this looks first locally, and then under (parent)->payment
| |
− | */
| |
− | public function Addr() {
| |
− | if ($this->Exists('addr')) {
| |
− | return $this->Node('addr');
| |
− | } elseif ($this->Parent()->Exists('payment')) {
| |
− | $objPay = $this->Parent()->Node('payment');
| |
− | if ($objPay->Exists('addr')) {
| |
− | return $objPay->Node('addr');
| |
− | }
| |
− | }
| |
− | return NULL;
| |
− | }
| |
− | public function HasEmail() {
| |
− | return $this->Exists('email');
| |
− | }
| |
− | public function Email() {
| |
− | return $this->Node('email');
| |
− | }
| |
− | public function HasPhone() {
| |
− | return $this->Exists('phone');
| |
− | }
| |
− | public function Phone() {
| |
− | return $this->Node('phone');
| |
− | }
| |
− | protected function Person() {
| |
− | return $this->Parent();
| |
− | }
| |
− | public function Render() {
| |
− | $hrefForSpam = '<a href="'.KWP_WIKI.'Anti-Spam_Policy">';
| |
− | | |
− | // copy any needed constants over to variables for parsing:
| |
− | $ksEmail = $this->Email()->CtrlName();
| |
− | $ksPhone = $this->Phone()->CtrlName();
| |
− | | |
− | $strEmail = $this->Email()->Value();
| |
− | $strPhone = $this->Phone()->Value();
| |
− | | |
− | if ($this->doFixed) {
| |
− | $out = <<<__END__
| |
− | <tr><td align=right valign=middle>Email:</td><td><b>$strEmail</b></td></tr>
| |
− | <tr><td align=right valign=middle>Phone:</td><td><b>$strPhone</b></td></tr>
| |
− | __END__;
| |
− | } else {
| |
− | $out = <<<__END__
| |
− | <tr><td align=right valign=middle>Email:</td>
| |
− | <td><input name="$ksEmail" value="$strEmail" size=30> {$hrefForSpam}anti-spam policy</a>
| |
− | </td>
| |
− | </tr>
| |
− | <tr><td align=right valign=middle>Phone:</td>
| |
− | <td><input name="$ksPhone" value="$strPhone" size=20> (optional)</td>
| |
− | </tr>
| |
− | __END__;
| |
− | }
| |
− | return $out;
| |
− | }
| |
− | | |
− | }
| |
− | // a Payment has an Address, a Number (/CVV/Exp) and a Name
| |
− | class clsPayment extends clsContactFolder {
| |
− | //public $Name; // is this needed? Can be found at Addr->Name()
| |
− | // public $Addr;
| |
− | | |
− | // protected function SaveThis() { } // stubbed for customer-side
| |
− | | |
− | public function CustName() {
| |
− | return $this->Addr()->Node('name');
| |
− | }
| |
− | public function Addr() {
| |
− | return $this->Node('addr');
| |
− | }
| |
− | /*-----
| |
− | USED BY: admin functions
| |
− | */
| |
− | public function MakeAddr($iVal) {
| |
− | $objNode = new clsTreeNode();
| |
− | $objNode->Value($iVal);
| |
− | $this->Node('addr',$objNode);
| |
− | }
| |
− | public function Num() {
| |
− | return $this->Node('num');
| |
− | }
| |
− | /*-----
| |
− | USED BY: admin functions
| |
− | */
| |
− | public function MakeNum($iVal) {
| |
− | $objNode = new clsTreeNode();
| |
− | $objNode->Value($iVal);
| |
− | $this->Node('num',$objNode);
| |
− | }
| |
− | public function Exp() {
| |
− | return $this->Node('exp');
| |
− | }
| |
− | /*-----
| |
− | USED BY: admin functions
| |
− | */
| |
− | public function MakeExp($iVal) {
| |
− | $objNode = new clsTreeNode();
| |
− | $objNode->Value($iVal);
| |
− | $this->Node('exp',$objNode);
| |
− | }
| |
− | /*-----
| |
− | INPUT:
| |
− | iMaxFuture: if year is given as 2 digits, then this is the furthest in the future the year
| |
− | is allowed to be (# of years from now). NOTE: Should be tested with current dates after 2050
| |
− | (or between 1950 and 1999) to make sure it doesn't allow a year too far in the past.
| |
− | OUTPUT: EXP as a DateTime object
| |
− | */
| |
− | public function ExpDate($iMaxFuture=50) {
| |
− | $strExp = $this->Exp()->Value();
| |
− | return clsCustCards::ExpDate($strExp,$iMaxFuture);
| |
− | }
| |
− | public function ExpDateSQL() {
| |
− | return clsCustCards::ExpDateSQL($this->Exp()->Value());
| |
− | }
| |
− | public function CVV() {
| |
− | if ($this->Exists('cvv')) {
| |
− | return $this->Node('cvv')->Value();
| |
− | } else {
| |
− | return NULL;
| |
− | }
| |
− | }
| |
− | /*----
| |
− | ACTION: Return a description of the payment in a safe format
| |
− | (incomplete credit card number)
| |
− | TO DO: Allow for payment types other than credit card
| |
− | */
| |
− | public function SafeDisplay() {
| |
− | $out = clsCustCards::SafeDescr_Long($this->Num()->Value(),$this->Exp()->Value());
| |
− | $out .= '<br>'.$this->Addr()->AsText("\n<br>");
| |
− | return $out;
| |
− | }
| |
− | }
| |
− | /*----
| |
| RULES: | | RULES: |
− | * a Person must have two mailing addresses: one for shipping, one for payment | + | * If a country's code isn't found in arDesc, it defaults to International |
− | * these addresses may be the same
| + | ...there's got to be a better way to do this... |
− | * a Person must have an email address
| |
− | * a Person may have a phone number
| |
− | * email and phone are not tied to mailing address, just to Person
| |
− | * a Person may (for now, must) have a card
| |
− | * a card has one mailing address
| |
| */ | | */ |
− | class clsPerson extends clsContactFolder { | + | class clsShipZone { |
− | /*
| + | static private $arDesc = array( |
− | public $Contact;
| + | 'CA' => 'Canada', |
− | public $Payment;
| + | 'US' => 'United States', |
− | */
| + | 'INT' => 'International', |
− | protected $strName; // for forms
| + | ); |
− | private $strDescr; // for text messages | + | // per-item adjustment factors |
− | | + | static private $arItmFactors = array( |
− | public function __construct($iName,$iDescr) {
| + | 'US' => 1.0, |
− | $this->strName = $iName;
| + | 'CA' => 2.0, |
− | $this->strDescr = $iDescr;
| + | 'INT' => 4.0, |
− | }
| + | ); |
− | public function Descr($iDescr=NULL) {
| + | // per-package adjustment factors |
− | if (!is_null($iDescr)) {
| + | static private $arPkgFactors = array( // there's got to be a better way to do this... |
− | $this->strDescr = $iDescr;
| + | 'US' => 1.0, |
− | }
| + | 'CA' => 2.0, |
− | return $this->strDescr;
| + | 'INT' => 4.0, |
− | }
| + | ); |
− | public function CtrlName() {
| + | static private $arCountryCodes = array( |
− | return $this->strName;
| + | 'united states' => 'US', |
− | } | + | 'canada' => 'CA', |
− | public function HasContact() { | + | 'australia' => 'AU', |
− | return $this->Exists('contact'); | + | ); |
− | }
| |
− | public function Contact() {
| |
− | return $this->Node('contact'); | |
− | }
| |
− | public function Payment() {
| |
− | return $this->Node('payment'); | |
− | }
| |
− | //=== EMAIL functions | |
− | /*---- | |
− | HISTORY:
| |
− | 2011-09-23 This totally wasn't working. Is now.
| |
− | clsTreeNode could probably use some tidying.
| |
− | */
| |
− | public function HasEmail() {
| |
− | $out = FALSE; | |
− | if ($this->Exists('contact')) {
| |
− | $objCont = $this->Contact();
| |
− | if ($objCont->Exists('email')) {
| |
− | $objEmail = $objCont->Node('email');
| |
− | $out = $objEmail->Filled();
| |
− | }
| |
− | }
| |
− | return $out;
| |
− | }
| |
− | /*----
| |
− | HISTORY: | |
− | 2011-09-23 written to simplify things
| |
− | */
| |
− | public function GetEmail() {
| |
− | if ($this->HasEmail()) {
| |
− | $out = $this->Contact()->Email()->Value();
| |
− | } else {
| |
− | $out = NULL;
| |
− | }
| |
− | return $out;
| |
− | }
| |
− | | |
− | //=== PHONE functions
| |
− | public function HasPhone() {
| |
− | $out = FALSE; | |
− | if ($this->Exists('contact')) { | |
− | $objCont = $this->Contact();
| |
− | if ($objCont->Exists('phone')) {
| |
− | $objPhone = $objCont->Node('phone');
| |
− | $out = $objPhone->Filled();
| |
− | }
| |
− | }
| |
− | return $out;
| |
− | }
| |
− | /*----
| |
− | HISTORY: | |
− | 2011-09-23 written to simplify things
| |
− | */
| |
− | public function GetPhone() {
| |
− | if ($this->HasPhone()) {
| |
− | $out = $this->Contact()->Phone()->Value();
| |
− | } else {
| |
− | $out = NULL;
| |
− | }
| |
− | return $out;
| |
− | }
| |
| | | |
− | //=== CCARD functions | + | private $strAbbr; |
− | public function HasCCard() {
| |
− | $out = $this->Exists('payment');
| |
− | return $out;
| |
− | }
| |
− | /*----
| |
− | HISTORY:
| |
− | 2011-09-23 written to simplify things
| |
− | NOTE: slightly different from email/phone;
| |
− | returns object, not string
| |
− | */
| |
− | public function GetCCard() {
| |
− | if ($this->HasCCard()) {
| |
− | return $this->Payment();
| |
− | } else {
| |
− | return NULL;
| |
− | }
| |
− | }
| |
| | | |
− | //===
| |
− | /*----
| |
− | HISTORY:
| |
− | 2011-11-21 fixed a bug where $objAddr was being called as a function,
| |
− | so presumably this method was not working before now.
| |
− | */
| |
− | public function Addrs() {
| |
− | $arOut = NULL;
| |
− | if ($this->HasCCard()) {
| |
− | $arOut['card'] = $this->Payment()->Addr();
| |
− | }
| |
− | $objAddr = $this->Contact()->Addr();
| |
− | if (!is_null($objAddr)) {
| |
− | $arOut['ship'] = $objAddr;
| |
− | }
| |
− | return $arOut;
| |
− | }
| |
− | /*----
| |
− | PURPOSE: The scripted version of DoResolve. EXPERIMENTAL/DEBUGGING
| |
− | HISTORY:
| |
− | 2011-09-21 started
| |
− | 2011-10-08 mostly working
| |
− | 2011-11-21 Script_DataRow was being called as a function instead of new object; fixed.
| |
− | Completed other identifier name changes.
| |
− | INPUT:
| |
− | <form> data:
| |
− | depends on which contact data is being resolved; there can be 1 or 2 different sets
| |
− | $iOrder - changes to be made to the order record
| |
− | This function does not actually execute this, but only modifies it.
| |
− | It is up to the caller to execute it *after* calling this.
| |
− | $iContact - ID of existing contact record to update, or NULL if a new one should be created
| |
− | */
| |
− | /* 2011-11-29 currently trying to obsolete this
| |
− | public function DoResolve_Script(Script_SQL_DataRow_Command $iOrder, $iShipSelf=FALSE) {
| |
− | global $wgRequest;
| |
− |
| |
− | $objPerson = $this;
| |
− | $strStat = NULL;
| |
− |
| |
− | $strFormName = $objPerson->FormName();
| |
− | $strChoice = $wgRequest->GetText($strFormName);
| |
− |
| |
− | $doNew = FALSE;
| |
− | $doUpd = FALSE;
| |
− |
| |
− | if ($strChoice == 'new') {
| |
− | // creating completely new contact record
| |
− | $doNew = TRUE;
| |
− | $strStat = '<b>Creating</b> new contact record(s)';
| |
− | $idContact = NULL;
| |
− | } elseif (is_numeric($strChoice)) {
| |
− | // updating existing contact record (possibly creating new detail records)
| |
− | $doUpd = TRUE;
| |
− | $idContact = (int)$strChoice;
| |
− | $strStat = '<b>Using</b> contact ID='.$idContact;
| |
− | } elseif (empty($strChoice)) {
| |
− | $strStat = 'Please choose which contact to use.';
| |
− | } else {
| |
− | throw new exception('Unexpected value for contact ID: ['.$strChoice.']');
| |
− | }
| |
− |
| |
− | $acts = new Script_Script();
| |
− | $acts->Add(new Script_Status($strStat)); // display the status message
| |
− |
| |
− | if ($doNew || $doUpd) {
| |
− | // get some data for later use
| |
− | $strEmail = $objPerson->GetEmail();
| |
− | $strPhone = $objPerson->GetPhone();
| |
− | $objCCard = $objPerson->GetCCard();
| |
− |
| |
− | // get some objects for later use
| |
− | $objDB = $iOrder->Engine();
| |
− | $tblEmails = $objDB->CustEmails();
| |
− | $tblPhones = $objDB->CustPhones();
| |
− | $tblCCards = $objDB->CustCards();
| |
− |
| |
− |
| |
− | if ($doNew) {
| |
− | $objContact = $objPerson->Contact();
| |
− | if (is_object($objContact)) {
| |
− | // data integrity check successful
| |
− |
| |
− | $objAddr = $objContact->Addr();
| |
− | if (is_null($objAddr)) {
| |
− | $acts->Add(new Script_Status('No address info'));
| |
− | } else {
| |
− | // we have some address data to record, so record it
| |
− |
| |
− | $actCust = $objDB->Custs()->Make_fromCartAddr_SQL($objAddr);
| |
− | $acts->Add(new Script_Status('ADDING CONTACT ADDRESS (check this!)'));
| |
− | $acts->Add($actCust,'cust');
| |
− |
| |
− | // there needs to be a less script-structure-dependent way to do this:
| |
− | //$actCustIns = $actCust->Trial(); // get the insert action
| |
− | $actCustIns = $actCust->Get_byName('cust.ins',TRUE);
| |
− | $actCustXfer = $actCust->Get_byName('cust.id.xfer',TRUE);
| |
− |
| |
− | // make sure email information is saved
| |
− | if (!is_null($strEmail)) {
| |
− |
| |
− | // CHANGE TO Make_Script()
| |
− |
| |
− | $actCustXfer->Add($tblEmails->Script_forAdd($strEmail, $actCustIns),'cust.email');
| |
− | }
| |
− | // make sure phone information is saved
| |
− | if (!is_null($strPhone)) {
| |
− |
| |
− | // CHANGE TO Make_Script()
| |
− |
| |
− | $actCustXfer->Add($tblPhones->Script_forAdd($strPhone, $actCustIns),'cust.phone');
| |
− | }
| |
− | // make sure credit card information is saved
| |
− | if (!is_null($objCCard)) {
| |
− | $actAddr = $actCust->Get_byName('cust.addr',TRUE);
| |
− | $actCCard = $tblCCards->Make_Script($idCust, $objCCard);
| |
− | $actCustXfer->Add($actCCard,'cust.card');
| |
− | //$actCustXfer->Add($tblCCards->Script_forAdd($objCCard, $actCustIns, $actAddr),'cust.card');
| |
− | //$actFill_ID_toCard = new Script_SQL_Use_ID($actAddr,$arCardCreate,'ID_Cust');
| |
− | }
| |
− | }
| |
− |
| |
− | } else {
| |
− | throw new exception('Person object has no Contact object.');
| |
− | }
| |
− | }
| |
− |
| |
− | if ($doUpd) {
| |
− | $idCust = (int)$strChoice;
| |
− | $strStat .= 'resolved as contact ID='.$idCust;
| |
− |
| |
− | $objAddrs = $objPerson->Addrs(); // list of addresses from cart data
| |
− |
| |
− | echo $objPerson->DumpHTML(); die();
| |
− |
| |
− | // create records for all names (will be either 1 or 2) associated with the order
| |
− | $tblNames = $objDB->CustNames(); // customer names table
| |
− | $tblAddrs = $objDB->CustAddrs(); // customer addresses table
| |
− | $out = NULL;
| |
− | if (!is_null($objAddrs)) {
| |
− |
| |
− | foreach ($objAddrs as $type => $obj) {
| |
− |
| |
− | if (!is_object($obj)) {
| |
− | throw new exception('value for '.$type.' is not an object.');
| |
− | }
| |
− |
| |
− | $this->ImportContact($acts,$type,$obj);
| |
− | /*
| |
− | $acts->Add(new Script_Status('CHECKING '.$type));
| |
− |
| |
− | $strName = $obj->Name()->Value();
| |
− | $strKey = strtolower($strName);
| |
− |
| |
− | $acts->Add(new Script_Status('ADDING NAME: '.$strName));
| |
− |
| |
− | $actOrdScratch = new Script_RowObj_scratch('scratch order');
| |
− | // ^ this will be copied to order update action ($iOrder) after name & address are set
| |
− |
| |
− | // only add names that are different
| |
− | //if (array_key_exists($strKey,$arNames)) {
| |
− | $objName = $tblNames->Find($strKey,$idCust);
| |
− | if ($objName->HasRows()) {
| |
− | $objName->FirstRow();
| |
− | $id = $objName->KeyValue();
| |
− | $acts->Add(new Script_Status('SAME as existing name ID='.$id));
| |
− | $actOrdScratch->Value('name.'.$strFormName,$id);
| |
− | } else {
| |
− | $arAct = $tblNames->Create_SQL($idCust,$strName);
| |
− | $act = new Script_Tbl_Insert($tblNames,$arAct);
| |
− | $acts->Add(new Script_SQL_Use_ID($act,$actOrdScratch,'name'));
| |
− | }
| |
− |
| |
− | $strKey = $obj->AsSearchable();
| |
− | $acts->Add(new Script_Status('ADDING ADDRESS: '.$strKey));
| |
− |
| |
− | $acts->Add($tblAddrs->Make_Script($obj,$idCust,$actOrdScratch));
| |
− |
| |
− | switch ($type) {
| |
− | case 'card':
| |
− | $sqlOrdContField = 'ID_Buyer';
| |
− | $sqlOrdNameField = 'ID_NameBuyer';
| |
− | $sqlOrdAddrField = NULL;
| |
− | break;
| |
− | case 'ship':
| |
− | $sqlOrdContField = 'ID_Recip';
| |
− | $sqlOrdNameField = 'ID_NameRecip';
| |
− | $sqlOrdAddrField = 'ID_ContactAddrRecip';
| |
− | break;
| |
− | }
| |
− | $arXl = array(
| |
− | $sqlOrdAddrField => 'addr',
| |
− | $sqlOrdNameField => 'name'
| |
− | );
| |
− | $iOrder->Value($sqlOrdContField,$idCust);
| |
− | echo 'xfer:<pre>'.print_r($arXl,TRUE).'</pre>';
| |
− | echo 'ord scratch:<pre>'.print_r($actOrdScratch->Values(),TRUE).'</pre>';
| |
− | $acts->Add(new Script_Copy_Named($actOrdScratch,$iOrder,$arXl),'order.update.'.$strFormName);
| |
− | //echo '#1:<pre>'.print_r($iOrder->Values(),TRUE).'</pre>';
| |
− |
| |
− | // the name is just for readability/debugging; it is not used by code
| |
− | */
| |
− | /*
| |
− | }
| |
− | }
| |
− |
| |
− | // handle email address
| |
− | if (is_null($strEmail)) {
| |
− | $acts->Add(new Script_Status('No email address given.'));
| |
− | } else {
| |
− | // make new email record, unless an identical one exists:
| |
− | $acts->Add(new Script_Status('Adding email '.$strEmail));
| |
− | $act = $tblEmails->Make_Script($idCust, $strEmail);
| |
− | $acts->Add($act);
| |
− | }
| |
− |
| |
− | // handle phone number
| |
− | if (is_null($strPhone)) {
| |
− | $acts->Add(new Script_Status('No phone number given.'));
| |
− | } else {
| |
− | // make new phone record, unless an identical one exists:
| |
− | $acts->Add(new Script_Status('Adding phone '.$strPhone));
| |
− | // THIS FUNCTION HAS NOT BEEN WRITTEN YET -- reuse code from email class
| |
− | $act = $tblPhones->Make_Script($idCust, $strPhone);
| |
− | $acts->Add($act);
| |
− | }
| |
− |
| |
− | // handle credit card information
| |
− | if (is_null($objCCard)) {
| |
− | $acts->Add(new Script_Status('No credit card information given.'));
| |
− | // currently, we're not expecting this, as ccard is required
| |
− | } else {
| |
− | $acts->Add(new Script_Status('Adding ccard '.$objCCard->SafeDisplay()));
| |
− | $act = $tblCCards->Make_Script($idCust, $objCCard);
| |
− | $acts->Add($act);
| |
− |
| |
− | $actIns = $act->Get_byName('ccard.make',TRUE);
| |
− | $actCopy = new Script_SQL_Use_ID($actIns,$iOrder,'ID_ChargeCard');
| |
− | $acts->Add($actCopy);
| |
− | }
| |
− | }
| |
− | /*
| |
− | By this time, $iOrder should have data for updating these fields:
| |
− | * ID_Buyer
| |
− | * ID_Recip
| |
− | * ID_NameBuyer
| |
− | * ID_NameRecip
| |
− | * ID_ContactAddrRecip
| |
− | * ID_ChargeCard
| |
− |
| |
− | Add one more thing:
| |
− | */
| |
− | /*
| |
− | $iOrder->Value('WhenPrepped','NOW()'); // mark the order as "prepped"
| |
− | //echo '#2:<pre>'.print_r($iOrder->Values(),TRUE).'</pre>';
| |
− | $acts->Add($iOrder,'ord.upd');
| |
− | }
| |
− |
| |
− | return $acts;
| |
− | }
| |
− | */
| |
− | /* 2011-11-29 this can't possibly work -- $strFormName is used but never defined
| |
− | protected function ImportContact(Script_Script $acts, $type, $obj) {
| |
− | $acts->Add(new Script_Status('CHECKING '.$type));
| |
− |
| |
− | $strName = $obj->Name()->Value();
| |
− | $strKey = strtolower($strName);
| |
− |
| |
− | $acts->Add(new Script_Status('ADDING NAME: '.$strName));
| |
− |
| |
− | $actOrdScratch = new Script_RowObj_scratch('scratch order');
| |
− | // ^ this will be copied to order update action ($iOrder) after name & address are set
| |
− |
| |
− | // only add names that are different
| |
− | //if (array_key_exists($strKey,$arNames)) {
| |
− | $objName = $tblNames->Find($strKey,$idCust);
| |
− | if ($objName->HasRows()) {
| |
− | $objName->FirstRow();
| |
− | $id = $objName->KeyValue();
| |
− | $acts->Add(new Script_Status('SAME as existing name ID='.$id));
| |
− | $actOrdScratch->Value('name.'.$strFormName,$id);
| |
− | } else {
| |
− | $arAct = $tblNames->Create_SQL($idCust,$strName);
| |
− | $act = new Script_Tbl_Insert($tblNames,$arAct);
| |
− | $acts->Add(new Script_SQL_Use_ID($act,$actOrdScratch,'name'));
| |
− | }
| |
− |
| |
− | $strKey = $obj->AsSearchable();
| |
− | $acts->Add(new Script_Status('ADDING ADDRESS: '.$strKey));
| |
− |
| |
− | $acts->Add($tblAddrs->Make_Script($obj,$idCust,$actOrdScratch));
| |
− |
| |
− | switch ($type) {
| |
− | case 'card':
| |
− | $sqlOrdContField = 'ID_Buyer';
| |
− | $sqlOrdNameField = 'ID_NameBuyer';
| |
− | $sqlOrdAddrField = NULL;
| |
− | break;
| |
− | case 'ship':
| |
− | $sqlOrdContField = 'ID_Recip';
| |
− | $sqlOrdNameField = 'ID_NameRecip';
| |
− | $sqlOrdAddrField = 'ID_ContactAddrRecip';
| |
− | break;
| |
− | }
| |
− | $arXl = array(
| |
− | $sqlOrdAddrField => 'addr',
| |
− | $sqlOrdNameField => 'name'
| |
− | );
| |
− | $iOrder->Value($sqlOrdContField,$idCust);
| |
− | echo 'xfer:<pre>'.print_r($arXl,TRUE).'</pre>';
| |
− | echo 'ord scratch:<pre>'.print_r($actOrdScratch->Values(),TRUE).'</pre>';
| |
− | $acts->Add(new Script_Copy_Named($actOrdScratch,$iOrder,$arXl),'order.update.'.$strFormName);
| |
− | //echo '#1:<pre>'.print_r($iOrder->Values(),TRUE).'</pre>';
| |
− |
| |
− | // the name is just for readability/debugging; it is not used by code
| |
− | }
| |
− | */
| |
− | // this is the OLD, non-scripted version (it didn't work very well either)
| |
− | public function DoResolve($iDB,$iContactID) {
| |
− | $objDB = $iDB;
| |
− | $objPerson = $this;
| |
− |
| |
− | $strChoice = $iContactID;
| |
− |
| |
− | if (!is_null($strChoice)) {
| |
− | $strStat = $objPerson->Descr().': ';
| |
− |
| |
− | if ($strChoice == 'new') {
| |
− | $doNew = TRUE;
| |
− | $doAdd = FALSE;
| |
− | } else {
| |
− | $doNew = FALSE;
| |
− | if (is_numeric($strChoice)) {
| |
− | $doAdd = TRUE;
| |
− | } else {
| |
− | $doAdd = FALSE;
| |
− | }
| |
− | }
| |
− |
| |
− | if ($doNew || $doAdd) {
| |
− | if ($doNew) {
| |
− | $objContact = $objPerson->Contact();
| |
− | if (is_object($objContact)) {
| |
− | // make new customer record, (shipping) address record, name record:
| |
− | $objCust = $objDB->Custs()->Make_fromCartAddr($objContact->Addr);
| |
− | $idCust = $objCust->ID;
| |
− | $strStat .= 'created new contact ID='.$idCust;
| |
− | } else {
| |
− | throw new exception('Person object has no Contact object.');
| |
− | }
| |
− | }
| |
− | if ($doAdd) {
| |
− | $idCust = (int)$strChoice;
| |
− | $strStat .= 'resolved as contact ID='.$idCust;
| |
− |
| |
− | $objAddrs = $objPerson->Addrs();
| |
− | foreach ($objAddrs as $type => $obj) {
| |
− | $strStat .= ' / '.$type.':';
| |
− | $strName = $obj->Name()->Value();
| |
− | $arAction[] = 'making name record';
| |
− | $idName = $objDB->CustNames()->Create($idCust,$strName);
| |
− | $strStat .= ' ID_Name='.$idName;
| |
− | $arAction[] = 'making address record';
| |
− | $idAddr = $objDB->CustAddrs()->Create($idCust,$obj);
| |
− | $strStat .= ' ID_Addr='.$idAddr;
| |
− | $arAction[] = 'type=<b>'.$type.'</b> idName=<b>'.$idName.'</b> idAddr=<b>'.$idAddr.'</b>';
| |
− | switch ($type) {
| |
− | case 'card':
| |
− | $idNameBuyer = $idName;
| |
− | $arOrdUpd['ID_NameBuyer'] = $idName;
| |
− | break;
| |
− | case 'ship':
| |
− | $idNameRecip = $idName;
| |
− | $idAddrRecip = $idAddr;
| |
− | $arOrdUpd['ID_NameRecip'] = $idName;
| |
− | $arOrdUpd['ID_ContactAddrRecip'] = $idAddr;
| |
− | break;
| |
− | }
| |
− | }
| |
− | $strStat .= ' / ';
| |
− | }
| |
− | $this->SubValue('id',$idCust); // 2011-09-22 what does this do? Where is it defined?
| |
− | //$arOrdUpd['ID_Cust'] = $idCust;
| |
− |
| |
− | $arAction = NULL;
| |
− | $arUpdEv = NULL;
| |
− |
| |
− | // make new email record, unless an identical one exists:
| |
− | if ($objPerson->HasEmail()) {
| |
− | $strEmail = $objPerson->Contact()->Email()->Value();
| |
− | $arAction[] = 'making email record for ['.$strEmail.']';
| |
− | $idEmail = $objDB->CustEmails()->Create($idCust, $strEmail);
| |
− | /*
| |
− | $objDB->LogEvent(
| |
− | __METHOD__,
| |
− | '|idCust='.$idCust.'|strEmail='.SQLValue($strEmail),
| |
− | 'Made email record; SQL='.SQLValue($sql),
| |
− | '+EM',FALSE,FALSE);
| |
− | */
| |
− |
| |
− | $arEv = array(
| |
− | 'where' => __METHOD__,
| |
− | 'params' => '|idCust='.$idCust.'|strEmail='.SQLValue($strEmail),
| |
− | 'descr' => 'Made email record; SQL='.SQLValue($sql),
| |
− | 'code' => '+EM'
| |
− | );
| |
− | $arUpdEv[] = $arEv;
| |
− |
| |
− | /*
| |
− | // 2009-11-28 at present, we don't attach specific email or phone IDs to orders or contacts
| |
− | $arOrdUpd['ID_Email'] = $idEmail;
| |
− | $strStat .= ' ID_Email='.$idEmail;
| |
− | */
| |
− | }
| |
− | // make new phone record, unless an identical one exists:
| |
− | if ($objPerson->HasPhone()) {
| |
− | $strPhone = $objPerson->Contact->Phone()->Value();
| |
− | $arAction[] = 'making phone record for ['.$strPhone.']';
| |
− | $idPhone = $objDB->CustPhones()->Create($idCust, $strPhone);
| |
− | /*
| |
− | $objDB->LogEvent(
| |
− | __METHOD__,
| |
− | '|idCust='.$idCust.'|strPhone='.SQLValue($strPhone),
| |
− | 'Made phone record; SQL='.SQLValue($sql),
| |
− | '+PH',FALSE,FALSE);
| |
− | // ($iWhere,$iParams,$iDescr,$iCode,$iIsError,$iIsSevere
| |
− | */
| |
− | $arEv = array(
| |
− | 'where' => __METHOD__,
| |
− | 'params' => '|idCust='.$idCust.'|strPhone='.SQLValue($strPhone),
| |
− | 'descr' => 'Made phone record; SQL='.SQLValue($sql),
| |
− | 'code' => '+PH'
| |
− | );
| |
− | $arUpdEv[] = $arEv;
| |
− | /*
| |
− | // 2009-11-28 at present, we don't attach specific email or phone IDs to orders or contacts
| |
− | $arOrdUpd['ID_Phone'] = $idPhone;
| |
− | $strStat .= ' ID_Phone='.$idPhone;
| |
− | */
| |
− | }
| |
− | // make new ccard record, unless an identical one exists:
| |
− | if ($objPerson->HasCCard()) {
| |
− | $arAction[] = 'making ccard record';
| |
− | $idCard = $objDB->CustCards()->Create($idCust, $objPerson->Payment());
| |
− | $objDB->LogEvent(
| |
− | __METHOD__,
| |
− | '|idCust='.$idCust,
| |
− | 'Made ccard record; SQL='.SQLValue($sql),
| |
− | '+CC',FALSE,FALSE);
| |
− | assert('!empty($idCard) /* type='.get_class($objDB->CustCards()).' */');
| |
− | $arOrdUpd['ID_ChargeCard'] = $idCard;
| |
− | $strStat .= ' ID_ChargeCard='.$idCard;
| |
− | }
| |
− | // if customer is shipper, write ID_Name and ID_Addr back to customer record:
| |
− | if (isset($idNameRecip)) {
| |
− | $arAction[] = 'updating contact with name/addr';
| |
− | $arUpd['ID_Name'] = $idNameRecip;
| |
− | $arUpd['ID_Addr'] = $idAddrRecip;
| |
− | $objDB->Custs()->Update($arUpd,'ID='.$idCust);
| |
− | } else {
| |
− | $arAction[] = 'recipient details not in this object';
| |
− | }
| |
− | } else {
| |
− | // log invalid input
| |
− | $strStat = 'Could not resolve - invalid choice "'.$strChoice.'".';
| |
− | }
| |
− | } else {
| |
− | $strStat = 'No contact specified for resolution (how did we even get here?).';
| |
− | }
| |
− |
| |
− | $arUpdOrd['upd-ord'] = $arOrdUpd;
| |
− | $arUpdOrd['stat'] = $strStat;
| |
− |
| |
− | $arOut['status'] = $strStat;
| |
− | $arOut['action'] = $arAction;
| |
− | $arOut['upd.ord'] = $arUpdOrd;
| |
− |
| |
− | return $arOut;
| |
− | }
| |
− | }
| |
− | /*==================
| |
− | CLASS: clsShipZone
| |
− | PURPOSE: shipping zone functions
| |
− | */
| |
− | class clsShipZone {
| |
| public function Abbr($iAbbr=NULL) { | | public function Abbr($iAbbr=NULL) { |
− |
| |
| if (!is_null($iAbbr)) { | | if (!is_null($iAbbr)) { |
| $this->strAbbr = $iAbbr; | | $this->strAbbr = $iAbbr; |
Line 1,369: |
Line 163: |
| return $this->strAbbr; | | return $this->strAbbr; |
| } | | } |
− | public function Text() { | + | public function Set_fromName($iName) { |
− | global $listShipListDesc; | + | $strLC = strtolower($iName); |
− | | + | if (array_key_exists($strLC,self::$arCountryCodes)) { |
− | return $listShipListDesc[$this->Abbr()]; | + | $this->strAbbr = self::$arCountryCodes[$strLC]; |
| + | } else { |
| + | echo 'Country ['.$iName.'] not found in list.'; |
| + | throw new exception('Internal error: unknown country requested.'); |
| + | } |
| + | } |
| + | public function Text() { // should be Name() |
| + | return self::$arDesc[$this->Abbr()]; |
| } | | } |
| | | |
| public function hasState() { | | public function hasState() { |
| switch ($this->Abbr()) { | | switch ($this->Abbr()) { |
| + | case 'AU': return TRUE; break; |
| + | case 'CA': return TRUE; break; |
| case 'US': return TRUE; break; | | case 'US': return TRUE; break; |
− | case 'CA': return TRUE; break;
| |
| default: return FALSE; break; | | default: return FALSE; break; |
| } | | } |
Line 1,384: |
Line 186: |
| public function StateLabel() { | | public function StateLabel() { |
| switch ($this->Abbr()) { | | switch ($this->Abbr()) { |
| + | case 'AU': return 'State/Territory'; break; |
| + | case 'CA': return 'Province'; break; |
| case 'US': return 'State'; break; | | case 'US': return 'State'; break; |
− | case 'CA': return 'Province'; break;
| |
| default: return 'County/Province'; break; | | default: return 'County/Province'; break; |
| } | | } |
Line 1,406: |
Line 209: |
| } | | } |
| public function ComboBox() { | | public function ComboBox() { |
− | global $listShipListDesc;
| |
− |
| |
| $strZoneCode = $this->Abbr(); | | $strZoneCode = $this->Abbr(); |
| $out = '<select name="ship-zone">'; | | $out = '<select name="ship-zone">'; |
− | foreach ($listShipListDesc as $key => $descr) { | + | foreach (self::$arDesc as $key => $descr) { |
| //$dest (keys(%listShipListDesc)) { | | //$dest (keys(%listShipListDesc)) { |
| $strZoneDesc = $descr; | | $strZoneDesc = $descr; |
Line 1,422: |
Line 223: |
| } | | } |
| $out .= '</select>'; | | $out .= '</select>'; |
− | return $out;
| |
− | }
| |
− | }
| |
− |
| |
− |
| |
− | // ShopCart
| |
− | class clsShopCarts extends clsTable {
| |
− | const TableName='shop_cart';
| |
− |
| |
− | public function __construct($iDB) {
| |
− | parent::__construct($iDB);
| |
− | $this->Name(self::TableName);
| |
− | $this->KeyName('ID');
| |
− | $this->ClassSng('clsShopCart');
| |
− | $this->ActionKey('cart');
| |
− | }
| |
− | }
| |
− | class clsShopCart extends clsDataSet {
| |
− | public $objShipZone;
| |
− | private $arDataItem;
| |
− | protected $objOrder;
| |
− |
| |
− | protected $hasDetails; // customer details have been loaded?
| |
− | protected $objDataTree;
| |
− | protected $objAddrShip;
| |
− | protected $objAddrCard;
| |
− | protected $objContDest;
| |
− | protected $objContCust;
| |
− | protected $objShip;
| |
− | protected $objCust;
| |
− |
| |
− | public function __construct(clsDatabase $iDB=NULL, $iRes=NULL, array $iRow=NULL) {
| |
− | parent::__construct($iDB,$iRes,$iRow);
| |
− | $this->objShipZone = new clsShipZone();
| |
− | $this->hasDetails = FALSE;
| |
− | }
| |
− | public function InitNew($iSess) {
| |
− | $this->ID = 0;
| |
− | $this->WhenCreated = NULL; // not created until saved
| |
− | $this->WhenViewed = NULL;
| |
− | $this->WhenUpdated = NULL;
| |
− | $this->WhenOrdered = NULL;
| |
− | $this->ID_Sess = $iSess;
| |
− | $this->ID_Order = NULL;
| |
− | $this->ID_Cust = NULL;
| |
− | }
| |
− | /*====
| |
− | BLOCK: EVENT HANDLING
| |
− | HISTORY:
| |
− | 2011-03-27 copied from VbzAdminCustCard to VbzAdminCart
| |
− | Then moved from VbzAdminCart to clsShopCart
| |
− | */
| |
− | 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();
| |
− | }
| |
− | // specialized event logging (deprecated)
| |
− | public function LogEvent($iCode,$iDescr,$iUser=NULL) {
| |
− | global $vgUserName;
| |
− |
| |
− | $strUser = is_null($iUser)?$vgUserName:$iUser;
| |
− | $this->objDB->CartLog()->Add($this,$iCode,$iDescr,$strUser);
| |
− | }
| |
− | //====
| |
− | /*----
| |
− | HISTORY:
| |
− | 2010-12-31 Created so placed orders do not get "stuck" in user's browser
| |
− | 2011-02-07 Doesn't work; same cart still comes up (though at least it generates a new order...
| |
− | but it pulls up all the same contact info)
| |
− | 2011-03-27 Changed flag from ID_Order to WhenOrdered OR WhenVoided, because we don't want to have to clear
| |
− | ID_Order anymore. Carts should retain their order ID.
| |
− | */
| |
− | public function IsLocked() {
| |
− | return $this->IsOrdered() || $this->IsVoided();
| |
− | }
| |
− | /*----
| |
− | RETURNS: TRUE if the cart has been converted to an order
| |
− | USED BY: $this->IsLocked() and (something)->IsUsable()
| |
− | HISTORY:
| |
− | 2011-03-27 written for improved handling of cart status at checkout
| |
− | */
| |
− | public function IsOrdered() {
| |
− | return !(is_null($this->WhenOrdered));
| |
− | }
| |
− | /*----
| |
− | RETURNS: TRUE if the cart has been discarded (voided)
| |
− | USED BY: $this->IsLocked() and (something)->IsUsable()
| |
− | HISTORY:
| |
− | 2011-03-27 written for improved handling of cart status at checkout
| |
− | */
| |
− | public function IsVoided() {
| |
− | return !(is_null($this->WhenVoided));
| |
− | }
| |
− | // == GENERAL DATA UTILITY FUNCTIONS
| |
− | public function GetDataItem($iType) {
| |
− | global $sql; // for debugging
| |
− |
| |
− | if (isset($this->arDataItem[$iType])) {
| |
− | return $this->arDataItem[$iType];
| |
− | } else {
| |
− | $sqlType = $this->objDB->SafeParam($iType);
| |
− | $sql = 'SELECT Val FROM '.KST_CART_DATA.' WHERE (ID_Cart='.$this->ID.') AND (Type="'.$sqlType.'");';
| |
− |
| |
− | $objItem = $this->objDB->DataSet($sql);
| |
− | if ($objItem->HasRows()) {
| |
− | $objItem->FirstRow();
| |
− | return $objItem->Val;
| |
− | } else {
| |
− | return NULL;
| |
− | }
| |
− | }
| |
− | }
| |
− | public function PutDataItem($iType,$iVal,$iForce=FALSE) {
| |
− | global $sql; // for debugging
| |
− |
| |
− | $sqlType = $this->objDB->SafeParam($iType);
| |
− | $sqlFilt = '(ID_Cart='.$this->ID.') AND (Type="'.$iType.'")';
| |
− | if ($iVal == '') {
| |
− | if ($iForce) {
| |
− | // delete the entry
| |
− | $sql = 'DELETE FROM '.KST_CART_DATA.' WHERE '.$sqlFilt;
| |
− | $ok = $this->objDB->Exec($sql);
| |
− | return $ok;
| |
− | } else {
| |
− | return FALSE;
| |
− | }
| |
− | } else {
| |
− | $sqlVal = $this->objDB->SafeParam($iVal);
| |
− | // check to see if item exists (UPDATE) or not (INSERT):
| |
− | $objRows = $this->objDB->DataSet('SELECT Val FROM '.KST_CART_DATA.' WHERE '.$sqlFilt);
| |
− | $qrows = $objRows->RowCount();
| |
− | if ($qrows == 0) {
| |
− | $sql = 'INSERT INTO '.KST_CART_DATA.' (ID_Cart,Type,Val) VALUES('.$this->ID.','.$iType.',"'.$sqlVal.'");';
| |
− | $ok = $this->objDB->Exec($sql);
| |
− | } elseif ($qrows == 1) {
| |
− | $sql = 'UPDATE '.KST_CART_DATA.' SET Val="'.$sqlVal.'" WHERE '.$sqlFilt.';';
| |
− | $ok = $this->objDB->Exec($sql);
| |
− | } else {
| |
− | // the db should never let this happen since ID_Cart+Type is the primary key, but leaving in as a sanity check for now.
| |
− | $this->objDB->LogEvent('cart.data.write','type='.$iType.' val='.$sqlVal,$qrows.' rows match: too many','DUP',TRUE,TRUE);
| |
− | $ok = FALSE;
| |
− | }
| |
− | return $ok;
| |
− | }
| |
− | }
| |
− | public function DataItem($iType,$iVal=NULL,$iForce=FALSE) {
| |
− | if ($this->HasCart()) {
| |
− | if (is_null($iVal)) {
| |
− | return $this->GetDataItem($iType);
| |
− | } else {
| |
− | return $this->PutDataItem($iType,$iVal,$iForce);
| |
− | }
| |
− | } else {
| |
− | return NULL;
| |
− | }
| |
− | }
| |
− | // == STATUS
| |
− | public function HasCart() {
| |
− | return $this->IsCreated(); // may use different criteria later on
| |
− | }
| |
− | public function HasSession() {
| |
− | $ok = FALSE;
| |
− | if ($this->HasField('ID_Sess')) {
| |
− | if ($this->ID_Sess>0) {
| |
− | $ok = TRUE;
| |
− | }
| |
− | }
| |
− | return $ok;
| |
− | }
| |
− | public function Session() {
| |
− | if ($this->HasSession()) {
| |
− | $objSessions = $this->objDB->Sessions();
| |
− | $objSess = $objSessions->GetItem($this->ID_Sess);
| |
− | return $objSess;
| |
− | } else {
| |
− | return NULL;
| |
− | }
| |
− | }
| |
− | // DEPRECATED - use OrderObj()
| |
− | public function Order() {
| |
− | return $this->OrderObj();
| |
− | }
| |
− | /*----
| |
− | RETURNS: Order object
| |
− | */
| |
− | public function OrderObj() {
| |
− | $doGet = TRUE;
| |
− | if (isset($this->objOrder)) {
| |
− | if ($this->objOrder->ID == $this->ID_Order) {
| |
− | $doGet = FALSE;
| |
− | }
| |
− | }
| |
− | if ($doGet) {
| |
− | $this->objOrder = $this->objDB->Orders()->GetItem($this->ID_Order);
| |
− | }
| |
− | return $this->objOrder;
| |
− | }
| |
− | public function HasLines() {
| |
− | $objLines = $this->GetLines();
| |
− | if (is_null($objLines)) {
| |
− | return FALSE;
| |
− | } else {
| |
− | return $objLines->hasRows();
| |
− | }
| |
− | }
| |
− | public function LineCount() {
| |
− | if ($this->HasLines()) {
| |
− | return $this->objLines->RowCount();
| |
− | } else {
| |
− | return 0;
| |
− | }
| |
− | }
| |
− | public function GetLines($iRefresh=TRUE) {
| |
− | if ($iRefresh || (!isset($this->objLines))) {
| |
− | if ($this->IsCreated()) {
| |
− | //$this->objLines = $this->objDB->CartLines()->GetData('(ID_Cart='.$this->ID.') AND (Qty>0)','clsShopCartLine');
| |
− | $this->objLines = $this->objDB->CartLines()->GetData('(ID_Cart='.$this->ID.') AND (Qty>0)');
| |
− | } else {
| |
− | $this->objLines = NULL;
| |
− | }
| |
− | }
| |
− | return $this->objLines;
| |
− | }
| |
− | public function IsCreated() {
| |
− | return ($this->ID > 0);
| |
− | //return !is_null($this->ID);
| |
− | //return $this->hasField('ID') || isset($this->ID)
| |
− | }
| |
− | /*----
| |
− | RETURNS: TRUE iff customer has any known email addresses
| |
− | public function HasEmail() {
| |
− | $isShipCard = $this->DataItem(KSI_SHIP_IS_CARD);
| |
− | $isShipSelf = $this->DataItem(KSI_SHIP_TO_SELF);
| |
− | // $objCart->ContCustObj()->Email()->Value()
| |
− | if ($isShipSelf) {
| |
− | return $this->ContCustObj()->HasEmail();
| |
− | }
| |
− | public function EmailObj() {
| |
− | }
| |
− | */
| |
− | // == FORM HANDLING STUFF
| |
− | public function CheckData() {
| |
− | // check for buttons
| |
− | $doCheckout = isset($_POST['finish']);
| |
− | $isCart = (isset($_POST['recalc']) || $doCheckout);
| |
− | $isZoneSet = FALSE;
| |
− | // check for specific actions
| |
− | if (isset($_GET['action'])) {
| |
− | $strDo = $_GET['action'];
| |
− | switch ($strDo) {
| |
− | case 'del':
| |
− | $intItem = 0+$_GET['item'];
| |
− | $this->GetLines();
| |
− | $this->objLines->Update(array('Qty'=>0),'ID_Item='.$intItem);
| |
− | $this->LogEvent('del','deleting from cart: ID '.$intItem);
| |
− | break;
| |
− | case 'delcart';
| |
− | $this->LogEvent('clr','voiding cart');
| |
− | $this->ID = -1;
| |
− | $this->objSess->DropCart();
| |
− | break;
| |
− | }
| |
− | } else {
| |
− | foreach ($_POST as $key => $val) {
| |
− | // check for added items:
| |
− | if (substr($key,0,4) == 'qty-') {
| |
− | if (($val != '') && ($val != 0)) {
| |
− | $sqlCatNum = $this->objDB->SafeParam(substr($key,4));
| |
− | if ($isCart) {
| |
− | // zero out all items, so only items in visible cart will be retained:
| |
− | $this->ZeroAll();
| |
− | }
| |
− | $this->AddItem($sqlCatNum,$val);
| |
− | }
| |
− | } elseif ($key == KSF_SHIP_ZONE) {
| |
− | // $custShipZone = $this->GetFormItem(KSF_SHIP_ZONE);
| |
− | $custShipZone = $val;
| |
− | $this->DataItem(KSI_SHIP_ZONE,$custShipZone);
| |
− | $this->objShipZone->Abbr($custShipZone);
| |
− | $isZoneSet = TRUE;
| |
− | }
| |
− | }
| |
− | }
| |
− | if (!$isZoneSet) {
| |
− | $this->objShipZone->Abbr($this->DataItem(KSI_SHIP_ZONE));
| |
− | }
| |
− | if ($doCheckout) {
| |
− | $this->LogEvent('ck1','going to checkout');
| |
− | $objSess = $this->Session();
| |
− | //http_redirect(KWP_CHKOUT,array(KS_VBZCART_SESSION_KEY => $objSess->SessKey()));
| |
− | //http_redirect(KWP_CHKOUT.'?'.KS_VBZCART_SESSION_KEY.'='.$objSess->SessKey());
| |
− | http_redirect(KWP_CHKOUT);
| |
− | // http_redirect('https://ssl.vbz.net/phpinfo.php');
| |
− | $this->LogEvent('ck2','sent redirect to checkout');
| |
− | }
| |
− | }
| |
− | public function ZeroAll() {
| |
− | $this->Update(array('Qty'=>0),'ID_Cart='.$this->ID);
| |
− | }
| |
− | public function AddItem($iCatNum,$iQty) {
| |
− | $this->Build(); // make sure there's a record for the cart, get ID
| |
− | $objCartLines = $this->objDB->CartLines();
| |
− | $objCartLines->Add($this->ID,$iCatNum,$iQty);
| |
− | $this->LogEvent('add','adding to cart: cat# '.$iCatNum.' qty '.$iQty);
| |
− | }
| |
− | /*-----
| |
− | ACTION:
| |
− | * make sure there is a cart record
| |
− | * update the quantity, if there is one
| |
− | */
| |
− | public function Build() {
| |
− | $id = $this->ID;
| |
− | if (empty($id)) {
| |
− | $this->Create();
| |
− | }
| |
− | }
| |
− | public function Create() {
| |
− | $sql =
| |
− | 'INSERT INTO `'.clsShopCarts::TableName.'` (WhenCreated,ID_Sess)'.
| |
− | 'VALUES(NOW(),'.$this->ID_Sess.');';
| |
− | $this->objDB->Exec($sql);
| |
− | $this->ID = $this->objDB->NewID('carts.create');
| |
− | $objSess = $this->objDB->Sessions()->GetCurrent();
| |
− | if (!is_object($objSess->Table)) {
| |
− | throw new exception('Session object has no table for Cart ID='.$this->Value('ID'));
| |
− | }
| |
− | $objSess->SetCart($this->ID);
| |
− | }
| |
− | public function RenderHdr() {
| |
− | $out = "\n".'<!-- Cart ID='.$this->KeyValue().' | Session ID='.$this->ID_Sess.' -->';
| |
− | $out .= "\n<center><table class=border><tr><td><table class=cart><tr><td align=center valign=middle>";
| |
− | $out .= "\n<form method=post action='./'>";
| |
− | $out .= "\n<table class=cart-data>\n";
| |
− | return $out;
| |
− | }
| |
− | public function RenderFtr() {
| |
− | return KHT_CART_FTR;
| |
− | }
| |
− | /*----
| |
− | ACTION: Render the receipt in HTML
| |
− | Shows the order as generated from *cart* data, not what's in the order record.
| |
− | ...except for the order number.
| |
− | HISTORY:
| |
− | 2011-03-27 adapting this from clsOrder::RenderReceipt()
| |
− | */
| |
− | public function RenderReceipt() {
| |
− | $out = NULL;
| |
− |
| |
− | $objCart = $this;
| |
− | $objOrd = $this->OrderObj();
| |
− |
| |
− | // load contact data
| |
− | assert('is_object($objOrd);');
| |
− | if (($objOrd->ID == 0) || ($objCart->ID == 0)) {
| |
− | throw new exception('Receipt has missing object: Order ID='.$this->Value('ID_Order').', Cart ID='.$objCart->KeyValue());
| |
− | }
| |
− | $objCart->GetDetailObjs();
| |
− | $objPay = $objCart->PersonCustObj()->Payment();
| |
− | $objAddrCard = $objCart->AddrCardObj();
| |
− | // the next line is a kluge which only works as long as payment is always ccard
| |
− | // it's also not clear why GetDetailObjs() isn't loading it properly
| |
− | $objPay->Node('addr', $objAddrCard);
| |
− |
| |
− | $arVars = array(
| |
− | 'ord.num' => $objOrd->Number,
| |
− | 'timestamp' => date(KF_RCPT_TIMESTAMP),
| |
− | 'cart.id' => $objCart->ID,
| |
− | 'cart.detail' => $objCart->RenderConfirm(),
| |
− | 'ship.name' => $objCart->AddrShipObj()->Name()->Value(),
| |
− | 'ship.addr' => $objCart->AddrShipObj()->AsText("\n<br>"),
| |
− | 'pay.name' => $objPay->Addr()->Name()->Value(),
| |
− | 'pay.spec' => $objPay->SafeDisplay(),
| |
− | 'email.short' => 'orders-'.date('Y').'@vbz.net'
| |
− | );
| |
− | $objStrTplt = new clsStringTemplate_array(NULL,NULL,$arVars);
| |
− | $objStrTplt->MarkedValue(KHT_RCPT_TPLT);
| |
− | $out = '<!-- ORDER ID: '.$objOrd->ID.' / CART ID from order: '.$objCart->ID.' -->';
| |
− | $out .= $objStrTplt->Replace();
| |
− | return $out;
| |
− | }
| |
− | /*-----
| |
− | ACTION: Renders the order contents as plaintext, suitable for emailing
| |
− | */
| |
− | public function RenderOrder_Text() {
| |
− | /* NOT USED HERE
| |
− | $isShipCard = $this->DataItem(KSI_SHIP_IS_CARD);
| |
− | $isShipSelf = $this->DataItem(KSI_SHIP_TO_SELF);
| |
− | */
| |
− | // copy any needed constants over to variables for parsing:
| |
− | $ksShipMsg = KSF_SHIP_MESSAGE;
| |
− | $ksfCustCardNum = KSF_CUST_CARD_NUM;
| |
− | $ksfCustCardExp = KSF_CUST_CARD_EXP;
| |
− |
| |
− | // get non-address field data:
| |
− | $strCardNum = $this->DataItem(KSI_CUST_CARD_NUM);
| |
− | $strCardExp = $this->DataItem(KSI_CUST_CARD_EXP);
| |
− | $strCustShipMsg = $this->DataItem(KSI_SHIP_MESSAGE);
| |
− | $ftCustShipMsg = wordwrap($strCustShipMsg);
| |
− |
| |
− | $out = '';
| |
− | $out .= "ITEMS ORDERED:\n";
| |
− |
| |
− | $out .= $this->RenderCore_Text();
| |
− |
| |
− | $this->doFixedCard = TRUE;
| |
− | $this->doFixedSelf = TRUE;
| |
− | $this->doFixedName = TRUE;
| |
− | $this->htmlBeforeAddress = '';
| |
− | $this->htmlBeforeContact = '';
| |
− |
| |
− | $out .= "\n\nSHIP TO:\n";
| |
− | $out .= ' '.$this->AddrShipObj()->Name()->Value()."\n";
| |
− | $out .= ' '.$this->AddrShipObj()->AsText("\n ");
| |
− | $out .= "\n";
| |
− | $out .= "\n Email: ".$this->ContDestObj()->Email()->Value();
| |
− | $out .= "\n Phone: ".$this->ContDestObj()->Phone()->Value();
| |
− |
| |
− | $out .= "\n\n ";
| |
− | if (empty($strCustShipMsg)) {
| |
− | $out .= "(No special instructions)";
| |
− | } else {
| |
− | $out .= "Special Instructions:\n$ftCustShipMsg";
| |
− | }
| |
− | $out .= "\n\nPAYMENT:\n ".clsCustCards::SafeDescr_Long($strCardNum,$strCardExp)."\n";
| |
− | $out .= ' '.$this->AddrCardObj()->Name()->Value()."\n";
| |
− | $out .= ' '.$this->AddrCardObj()->AsText("\n ");
| |
− | $out .= "\n";
| |
− | $out .= "\n Email: ".$this->ContCustObj()->Email()->Value();
| |
− | $out .= "\n Phone: ".$this->ContCustObj()->Phone()->Value();
| |
− | return $out;
| |
− | }
| |
− | public function RenderCore($iAsForm) {
| |
− | $strZone = $this->objShipZone->Abbr();
| |
− | $shipMinCost = 0;
| |
− |
| |
− | $out = '<tr>'
| |
− | .'<th><big>cat #</big></th>'
| |
− | .'<th><big>description</big></th>'
| |
− | .'<th>price<br>each</th>'
| |
− | .'<th><small>per-item<br>s/h ea.</small></th>'
| |
− | .'<th>qty.</th>'
| |
− | .'<th><small>purchase<br>line total</small></th>'
| |
− | .'<th><small>per-item<br>s/h line total</small></th>'
| |
− | .'<th>totals</th>'
| |
− | .'<th><small>pkg s/h<br>min.</small></th>'
| |
− | .'</tr>';
| |
− |
| |
− | $rsLine = $this->objLines;
| |
− | while ($rsLine->NextRow()) {
| |
− | if ($iAsForm) {
| |
− | $out .= $rsLine->RenderForm($this);
| |
− | } else {
| |
− | $out .= $rsLine->RenderHtml($this);
| |
− | }
| |
− | if ($shipMinCost < $rsLine->ShipPkgDest) {
| |
− | $shipMinCost = $rsLine->ShipPkgDest;
| |
− | }
| |
− | $intQty = $rsLine->Qty;
| |
− | $this->CostTotalItem += $rsLine->CostItemQty;
| |
− | $this->CostTotalShip += $rsLine->CostShipQty;
| |
− | }
| |
− | // save official totals for order creation:
| |
− | // TO DO: are CostTotalItem and CostTotalShip referenced anywhere else? Make them local if not.
| |
− | // But if they are, then why isn't shipMinCost also a field?
| |
− | $this->DataItem(KSI_ITEM_TOTAL,$this->CostTotalItem);
| |
− | $this->DataItem(KSI_PER_ITEM_TOTAL,$this->CostTotalShip);
| |
− | $this->DataItem(KSI_PER_PKG_TOTAL,$shipMinCost);
| |
− |
| |
− | $strTotalMerch = FormatMoney($this->CostTotalItem);
| |
− | $strItemsShip = FormatMoney($this->CostTotalShip);
| |
− | $strTotalItems = FormatMoney($this->CostTotalItem + $this->CostTotalShip);
| |
− | $strShipZone = $this->objShipZone->Text();
| |
− | $strShipDesc = $strShipZone.' s/h package cost:';
| |
− | $strShipPkg = FormatMoney($shipMinCost);
| |
− | $strTotalDesc = 'order total if shipping to '.$strShipZone.':';
| |
− | $strOrdTotal = FormatMoney($this->CostTotalItem + $this->CostTotalShip + $shipMinCost);
| |
− |
| |
− | $objSess = $this->Session();
| |
− |
| |
− | if ($iAsForm) {
| |
− | $htDelAll = '<span class=text-btn>[<a href="?action=delcart" title="remove all items from cart">remove all</a>]</span>';
| |
− | $htFirstTot = "<td align=left>$htDelAll</td><td align=right class=total-desc colspan=4>totals:</td>";
| |
− | $htZoneCombo = 'Shipping destination: '.$this->objShipZone->ComboBox();
| |
− | } else {
| |
− | $htFirstTot = '<td align=right class=total-desc colspan=5>totals:</td>';
| |
− | $htZoneCombo = 'Shipping costs shown assume shipment to <b>'.$this->objShipZone->Text().'</b> address.';
| |
− | }
| |
− | $out .= <<<__END__
| |
− | <tr>$htFirstTot
| |
− | <td align=right class=total-amount>$strTotalMerch</td>
| |
− | <td align=right class=total-amount>$strItemsShip</td>
| |
− | <td align=right class=total-amount>$strTotalItems</td>
| |
− | <td align=right>⇓</td>
| |
− | </tr>
| |
− | <tr>
| |
− | <td align=right class=total-desc colspan=7>$strShipDesc</td>
| |
− | <td align=right class=total-amount>$strShipPkg</td>
| |
− | <td align=right>↵</td>
| |
− | </tr>
| |
− | <tr>
| |
− | <td align=right class=total-desc colspan=7>$strTotalDesc</td>
| |
− | <td align=right class=total-final>$strOrdTotal</td>
| |
− | </tr>
| |
− | <tr><td colspan=6>$htZoneCombo</td></tr>
| |
− | __END__;
| |
− | $this->LogEvent('disp','displaying cart, zone '.$this->objShipZone->Abbr().' total $'.$strOrdTotal);
| |
− | return $out;
| |
− | }
| |
− | /*-----
| |
− | RETURNS: The contents of the cart as text. Includes column headers and totals.
| |
− | USED BY: does anything actually use this, or was it intended for the email confirmation?
| |
− | */
| |
− | public function RenderCore_Text() {
| |
− | $abbrShipZone = $this->DataItem(KSI_SHIP_ZONE);
| |
− | $this->objShipZone->Abbr($abbrShipZone);
| |
− |
| |
− | $shipMinCost = 0;
| |
− |
| |
− | $strLineFmt = '%-16s |%6.2f |%6.2f |%4d |%7.2f |%10.2f |%13.2f';
| |
− |
| |
− | if ($this->HasRows()) {
| |
− | $hdr = "\n".sprintf('%-17s|%6s|%5s|%5s|%7s|%10s|%13s'
| |
− | ,'cat #'
| |
− | ,' $ ea. '
| |
− | ,' $ s/h '
| |
− | ,' qty '
| |
− | ,' $ sale '
| |
− | ,' $ s/h tot '
| |
− | ,' $ LINE TOTAL');
| |
− | $out = $hdr;
| |
− | $out .= "\n".str_repeat('-',strlen($hdr));
| |
− | $objLines = $this->GetLines();
| |
− | $dlrSaleTot = 0; // total sale before shipping
| |
− | $dlrPItmTot = 0; // per-item shipping total
| |
− | $dlrPPkgMax = 0; // per-pkg shipping total
| |
− | while ($objLines->NextRow()) {
| |
− | $objItem = $objLines->Item();
| |
− | $dlrShipItm = $objItem->ShipPriceItem($abbrShipZone);
| |
− | $dlrShipPkg = $objItem->ShipPricePkg($abbrShipZone);
| |
− |
| |
− | $out .= $objLines->RenderText($this,$strLineFmt);
| |
− | if ($dlrPPkgMax < $dlrShipPkg) {
| |
− | $dlrPPkgMax = $dlrShipPkg;
| |
− | }
| |
− | $intQty = $objLines->Qty;
| |
− | $dlrSaleTot += $objLines->PriceItem;
| |
− | $dlrPItmTot += $dlrShipItm*$intQty;
| |
− | }
| |
− | $out .= "\n".str_repeat('=',strlen($hdr));
| |
− |
| |
− | $ftTotalMerch = sprintf('%6.2f',FormatMoney($dlrSaleTot));
| |
− | $ftItemsShip = sprintf('%6.2f',FormatMoney($dlrPItmTot));
| |
− | $ftTotalItems = sprintf('%6.2f',FormatMoney($dlrSaleTot + $dlrPItmTot));
| |
− | $ftShipPkg = sprintf('%6.2f',FormatMoney($dlrPPkgMax));
| |
− | //$ftTotalDesc = 'order total for shipping to '.$ftShipZone.':';
| |
− | $ftOrdTotal = sprintf('%6.2f',FormatMoney($dlrSaleTot + $dlrPItmTot + $dlrPPkgMax));
| |
− |
| |
− | // these items don't depend on cart contents, but there's no point in calculating them if the cart is empty:
| |
− | $ftShipZone = $this->objShipZone->Text();
| |
− | $ftShipDesc = $ftShipZone.' s/h package cost:';
| |
− |
| |
− | //$objSess = $this->Session();
| |
− |
| |
− | $ftZone = $this->objShipZone->Text();
| |
− | //$ftZone = $this->objShipZone->Abbr();
| |
− | //$ftZone = $abbrShipZone;
| |
− |
| |
− | $out .= "\n"
| |
− | ."\n * Sale: $ftTotalMerch"
| |
− | ."\n * S/H -"
| |
− | ."\n * per item sum: $ftItemsShip"
| |
− | ."\n * per package: $ftShipPkg"
| |
− | ."\n========================"
| |
− | ."\n==== FINAL TOTAL: $ftOrdTotal"
| |
− | ."\n\nShipping Zone: $ftZone";
| |
− | } else {
| |
− | $out = "\nSorry, we seem to have goofed: this cart appears to have no items in it.";
| |
− | $out .= "\nThe webmaster is being alerted to the problem.";
| |
− | }
| |
− | return $out;
| |
− | }
| |
− | public function Render() {
| |
− | // return rendering of current contents of cart
| |
− | $ok = FALSE;
| |
− | if ($this->ID) {
| |
− | if ($this->HasLines()) {
| |
− | $ok = TRUE;
| |
− | }
| |
− | }
| |
− |
| |
− | if ($ok) {
| |
− | # get information for that destination type:
| |
− | $out = $this->RenderHdr();
| |
− | $out .= $this->RenderCore(TRUE);
| |
− | $out .= $this->RenderFtr();
| |
− | } else {
| |
− | if ($this->IsCreated()) {
| |
− | if (is_null($this->objLines)) {
| |
− | $out = "<font size=4>Internal error - cart data not available!</font>";
| |
− | $this->LogEvent('disp',"can't display cart - no data!");
| |
− | $this->objDB->Events()->LogEvent('cart.render','','cart data unavailable','cdna',TRUE,TRUE);
| |
− | } else {
| |
− | $out = "<font size=4>Your cart is empty.</font>";
| |
− | $this->LogEvent('disp','displaying cart - empty; zone '.$this->objShipZone->Abbr());
| |
− | }
| |
− | } else {
| |
− | $out = "<font size=4>You have not put anything in your cart yet.</font>";
| |
− | $this->LogEvent('disp','displaying cart - nothing yet; zone '.$this->objShipZone->Abbr());
| |
− | }
| |
− | }
| |
| return $out; | | return $out; |
| } | | } |
| /*---- | | /*---- |
− | PURPOSE: Render cart for order confirmation page (read-only, no form controls)
| + | RETURNS: per-item price factor for the current shipping zone |
| */ | | */ |
− | public function RenderConfirm() { | + | protected function PerItemFactor() { |
− | if ($this->HasLines()) {
| + | echo 'CODE=['.$this->Abbr().'] ITEM FACTOR=['.self::$arItmFactors[$this->Abbr()].']<br>'; |
− | $out = $this->RenderCore(FALSE);
| + | return self::$arItmFactors[$this->Abbr()]; |
− | } else {
| |
− | // log error - you shouldn't be able to get to this point with an empty cart
| |
− | $txtParams = 'Cart ID='.$this->ID.' Order ID='.$this->ID_Order;
| |
− | $this->objDB->LogEvent('cart.renderconf',$txtParams,'cart empty at confirmation','cec',TRUE,TRUE); // also sends email alert
| |
− | $out = '<font color=red>INTERNAL ERROR</font>: cart data has become separated from browser. The webmaster has been notified.';
| |
− | }
| |
− | return $out; | |
− | }
| |
− | /*==========
| |
− | CUSTOMER DATA AMALGAMATION
| |
− | */
| |
− | public function AddrShipObj() {
| |
− | if (empty($this->objAddrShip)) {
| |
− | $arFields = array(
| |
− | 'name' => $this->SpawnName(KSI_ADDR_SHIP_NAME ,KSF_ADDR_SHIP_NAME),
| |
− | 'street' => new clsCartField($this, KSI_ADDR_SHIP_STREET, KSF_ADDR_SHIP_STREET),
| |
− | 'city' => new clsCartField($this, KSI_ADDR_SHIP_CITY ,KSF_ADDR_SHIP_CITY),
| |
− | 'state' => new clsCartField($this, KSI_ADDR_SHIP_STATE ,KSF_ADDR_SHIP_STATE),
| |
− | 'zip' => new clsCartField($this, KSI_ADDR_SHIP_ZIP ,KSF_ADDR_SHIP_ZIP),
| |
− | 'country' => new clsCartField($this, KSI_ADDR_SHIP_COUNTRY,KSF_ADDR_SHIP_COUNTRY),
| |
− | 'instruc' => new clsCartField($this, KSI_SHIP_MESSAGE ,KSF_SHIP_MESSAGE)
| |
− | );
| |
− | $this->objAddrShip = $this->SpawnAddress($arFields);
| |
− | }
| |
− | return $this->objAddrShip;
| |
− | }
| |
− | public function AddrCardObj() {
| |
− | if (empty($this->objAddrCard)) {
| |
− | $arFields = array(
| |
− | 'name' => $this->SpawnName(KSI_ADDR_CARD_NAME ,KSF_CUST_CARD_NAME),
| |
− | 'street' => new clsCartField($this, KSI_ADDR_CARD_STREET ,KSF_CUST_CARD_STREET),
| |
− | 'city' => new clsCartField($this, KSI_ADDR_CARD_CITY ,KSF_CUST_CARD_CITY),
| |
− | 'state' => new clsCartField($this, KSI_ADDR_CARD_STATE ,KSF_CUST_CARD_STATE),
| |
− | 'zip' => new clsCartField($this, KSI_ADDR_CARD_ZIP ,KSF_CUST_CARD_ZIP),
| |
− | 'country' => new clsCartField($this, KSI_ADDR_CARD_COUNTRY,KSF_CUST_CARD_COUNTRY),
| |
− | 'instruc' => new clsCartField($this, NULL ,NULL)
| |
− | );
| |
− | $this->objAddrCard = $this->SpawnAddress($arFields);
| |
− | }
| |
− | return $this->objAddrCard;
| |
− | }
| |
− | public function ContDestObj() {
| |
− | if (empty($this->objContDest)) {
| |
− | $arFields = array(
| |
− | 'email' => $this->SpawnEmail(KSI_CUST_SHIP_EMAIL ,KSF_CUST_SHIP_EMAIL),
| |
− | 'phone' => $this->SpawnPhone(KSI_CUST_SHIP_PHONE ,KSF_CUST_SHIP_PHONE)
| |
− | );
| |
− | $this->objContDest = $this->SpawnContact($arFields); // blank object for rendering
| |
− | }
| |
− | return $this->objContDest;
| |
− | }
| |
− | public function ContCustObj_raw() {
| |
− | if (empty($this->objContCust)) {
| |
− | $arFields = array(
| |
− | 'email' => $this->SpawnEmail(KSI_CUST_PAY_EMAIL ,KSF_CUST_PAY_EMAIL),
| |
− | 'phone' => $this->SpawnPhone(KSI_CUST_PAY_PHONE ,KSF_CUST_PAY_PHONE)
| |
− | );
| |
− | $this->objContCust = $this->SpawnContact($arFields);
| |
− | }
| |
− | return $this->objContCust;
| |
− | }
| |
− | /*----
| |
− | RETURNS: Contact information for the customer. If the "shipping to myself" box was checked,
| |
− | then it returns the shipping contact information instead, since this is presumed to be the
| |
− | customer's contact information as well.
| |
− | */
| |
− | public function ContCustObj() {
| |
− | //$isShipCard = $this->DataItem(KSI_SHIP_IS_CARD);
| |
− | $isShipSelf = $this->DataItem(KSI_SHIP_TO_SELF);
| |
− | if ($isShipSelf) {
| |
− | return $this->ContDestObj();
| |
− | } else {
| |
− | return $this->ContCustObj_raw();
| |
− | }
| |
− | }
| |
− | /*----
| |
− | METHOD: SpawnPerson()
| |
− | ACTION: creates clsPerson object or descendant
| |
− | This lets us stub off admin functionality here and extend it later.
| |
− | HISTORY:
| |
− | 2011-11-29 created
| |
− | */
| |
− | public function SpawnPerson($iName,$iDescr) {
| |
− | return new clsPerson($iName,$iDescr);
| |
− | }
| |
− | /*----
| |
− | METHOD: SpawnPayment()
| |
− | ACTION: creates clsPayment object or descendant
| |
− | This lets us stub off admin functionality here and extend it later.
| |
− | HISTORY:
| |
− | 2011-11-29 created
| |
− | */
| |
− | public function SpawnPayment($iNodes=NULL) {
| |
− | return new clsPayment($iNodes);
| |
− | }
| |
− | /*----
| |
− | METHOD: SpawnAddress()
| |
− | ACTION: creates clsCartAddr object or descendant
| |
− | This lets us stub off admin functionality here and extend it later.
| |
− | HISTORY:
| |
− | 2011-11-29 created
| |
− | */
| |
− | public function SpawnAddress($iNodes=NULL) {
| |
− | return new clsCartAddr($iNodes);
| |
− | }
| |
− | /*----
| |
− | METHOD: SpawnContact()
| |
− | ACTION: creates clsCartContact object or descendant
| |
− | This lets us stub off admin functionality here and extend it later.
| |
− | The extra functionality may not actually be needed for this, but I went and created it anyway.
| |
− | (2011-12-15: yes, it was needed.)
| |
− | HISTORY:
| |
− | 2011-11-29 created
| |
− | */
| |
− | public function SpawnContact($iNodes=NULL) {
| |
− | return new clsCartContact($iNodes);
| |
− | }
| |
− | /*----
| |
− | METHOD: SpawnEmail()
| |
− | ACTION: creates object for handling cart email address data
| |
− | This lets us stub off admin functionality here and extend it later.
| |
− | HISTORY:
| |
− | 2011-11-29 created
| |
− | */
| |
− | public function SpawnEmail($iIndex, $iCtrlName) {
| |
− | return new clsCartField($this, $iIndex, $iCtrlName);
| |
− | }
| |
− | /*----
| |
− | METHOD: SpawnPhone()
| |
− | ACTION: creates object for handling cart phone number data
| |
− | This lets us stub off admin functionality here and extend it later.
| |
− | HISTORY:
| |
− | 2011-11-29 created
| |
− | */
| |
− | public function SpawnPhone($iIndex, $iCtrlName) {
| |
− | return new clsCartField($this, $iIndex, $iCtrlName);
| |
− | }
| |
− | /*----
| |
− | METHOD: SpawnName()
| |
− | ACTION: creates object for handling person-name data
| |
− | This lets us stub off admin functionality here and extend it later.
| |
− | HISTORY:
| |
− | 2011-11-30 created
| |
− | */
| |
− | public function SpawnName($iIndex, $iCtrlName) {
| |
− | return new clsCartField($this, $iIndex, $iCtrlName);
| |
| } | | } |
| /*---- | | /*---- |
− | METHOD: clsShopCart->PersonCustObj() | + | RETURNS: per-package price factor for the current shipping zone |
− | USED BY: clsShopCart->GetDetailObjs(), clsOrder->RenderReceipt()
| |
− | HISTORY:
| |
− | 2010-09-12 Extracted from clsShopCart->GetDetailObjs() so it can be used by clsOrder->RenderReceipt()
| |
− | 2011-11-29 Now using SpawnPayment() and SpawnPerson() instead of creating directly with "new"
| |
| */ | | */ |
− | public function PersonCustObj() { | + | protected function PerPkgFactor() { |
− | if (empty($this->objCust)) {
| + | return self::$arPkgFactors[$this->Abbr()]; |
− | $arFields = array(
| |
− | 'num' => new clsCartField($this, KSI_CUST_CARD_NUM, KSF_CUST_CARD_NUM),
| |
− | 'exp' => new clsCartField($this, KSI_CUST_CARD_EXP, KSF_CUST_CARD_EXP)
| |
− | );
| |
− | $objPayment = $this->SpawnPayment($arFields);
| |
− | $this->objCust = $this->SpawnPerson('cust','buyer');
| |
− | $this->objCust->Node('payment', $objPayment); // the buyer always has the credit card
| |
− | }
| |
− | return $this->objCust; | |
− | }
| |
− | /*-----
| |
− | METHOD: clsShopCart->GetDetailObjs()
| |
− | FUTURE: rename to GetDataTree()
| |
− | HISTORY:
| |
− | 2010-09-12 borrowed (to be moved?) from clsPageCkout
| |
− | 2011-11-27 the version in clsPageCkout has now been commented out
| |
− | 2011-11-29 using SpawnPerson() instead of new clsPerson()
| |
− | */
| |
− | public function GetDetailObjs() {
| |
− | if (!$this->hasDetails) {
| |
− | $objAddrShip = $this->AddrShipObj();
| |
− | $objAddrCard = $this->AddrCardObj();
| |
− | $objContDest = $this->ContDestObj();
| |
− | $objContCust = $this->ContCustObj();
| |
− | | |
− | $objDataTree = new clsContactRoot($this->Engine());
| |
− | /*
| |
− | $objDataRef = new clsContactFolder_reference();
| |
− | $objDataTree->Node('reference data',$objDataRef);
| |
− | $objDataRef->Node('addr.ship',$objAddrShip);
| |
− | $objDataRef->Node('addr.card',$objAddrCard);
| |
− | $objDataRef->Node('cont.dest',$objContDest);
| |
− | $objDataRef->Node('cont.cust',$objContCust);
| |
− | */
| |
− | $this->objShip = $this->SpawnPerson('ship','recipient');
| |
− | $this->objCust = $this->PersonCustObj();
| |
− | | |
− | $objDataTree->Node('person.ship',$this->objShip);
| |
− | $objDataTree->Node('person.cust',$this->objCust);
| |
− | | |
− | $this->objDataTree = $objDataTree;
| |
− | | |
− | $objPayment = $this->objCust->Payment();
| |
− | | |
− | $this->objShip->Node('contact', $objContDest); // shipping information is always specified
| |
− | | |
− | $objContDest->Addr = $objAddrShip; // shipping address
| |
− | | |
− | $this->custShipIsCard = $this->DataItem(KSI_SHIP_IS_CARD);
| |
− | $this->custShipToSelf = $this->DataItem(KSI_SHIP_TO_SELF);
| |
− | | |
− | if ($this->custShipIsCard) {
| |
− | $objPayment->Node('addr', $objAddrShip); // use shipping address for card
| |
− | } else {
| |
− | $objPayment->Node('addr', $objAddrCard); // use separate address for card
| |
− | }
| |
− | | |
− | $this->objShip->Node('name', $objAddrShip->Name());
| |
− | | |
− | if ($this->custShipToSelf) {
| |
− | // don't use separate person data; re-use buyer contact info plus shipping address
| |
− | $this->objShip->Node('payment', $objPayment); // the only buyer field the recipient doesn't have
| |
− | $this->objCust = $this->objShip;
| |
− | //$objContDest->Node('addr', $objAddrShip); // shipping address
| |
− | $this->objShip->Node('contact', $objContDest);
| |
− | $objContDest->Node('addr', $objAddrShip);
| |
− | } else {
| |
− | $this->objShip->Node('contact', $objContDest);
| |
− | $this->objCust->Node('contact', $objContCust);
| |
− | $this->objCust->Node('name', $objAddrCard->Name());
| |
− | }
| |
− | $this->hasDetails = TRUE;
| |
− | }
| |
− | return $this->objDataTree;
| |
| } | | } |
− |
| |
| /*---- | | /*---- |
− | ASSUMES: GetDetailObjs() has been called | + | INPUT: base per-item shipping price |
| + | RETURNS: calculated price for the current shipping zone |
| */ | | */ |
− | public function WhoCust() { | + | public function CalcPerItem($iBase) { |
− | return $this->objCust; | + | return $iBase * $this->PerItemFactor(); |
| } | | } |
| /*---- | | /*---- |
− | ASSUMES: GetDetailObjs() has been called | + | INPUT: base per-package shipping price |
| + | RETURNS: calculated price for the current shipping zone |
| */ | | */ |
− | public function WhoShip() { | + | public function CalcPerPkg($iBase) { |
− | return $this->objShip; | + | return $iBase * $this->PerPkgFactor(); |
− | }
| |
− | }
| |
− | class clsShopCartLines extends clsTable {
| |
− | const TableName='shop_cart_line';
| |
− | | |
− | public function __construct($iDB) {
| |
− | parent::__construct($iDB);
| |
− | $this->Name(self::TableName);
| |
− | $this->KeyName('ID');
| |
− | $this->ClassSng('clsShopCartLine');
| |
− | $this->seqCart = 0;
| |
− | }
| |
− | public function Add($iCart, $iCatNum, $iQty) {
| |
− | $objItems = $this->objDB->Items();
| |
− | $objItem = $objItems->Get_byCatNum($iCatNum);
| |
− | if (is_null($objItem)) {
| |
− | // TO DO: log error
| |
− | echo 'ERROR: Could not find item for catalog #'.$iCatNum.'<br>';
| |
− | } else {
| |
− | $sqlCart = $this->objDB->SafeParam($iCart);
| |
− | $sqlWhere = '(ID_Cart='.$sqlCart.') AND (ID_Item='.$objItem->ID.')';
| |
− | $objLine = $this->GetData($sqlWhere,'clsShopCartLine');
| |
− | $objLine->NextRow(); // load the only data row
| |
− | | |
− | if (!$objLine->hasRows()) {
| |
− | $objLine->ID_Cart=$iCart;
| |
− | }
| |
− | $objLine->ID_Item = $objItem->ID;
| |
− | $objLine->Qty($iQty);
| |
− | $objLine->Build();
| |
− | }
| |
| } | | } |
| } | | } |
− | class clsShopCartLine extends clsDataSet {
| |
− | public function __construct(clsDatabase $iDB=NULL, $iRes=NULL, array $iRow=NULL) {
| |
− | parent::__construct($iDB,$iRes,$iRow);
| |
− | // this is necessary so $this->Update() will work
| |
− | // ...but it should be done by whatever code creates the object
| |
− | //$this->Table = $this->objDB->CartLines();
| |
− | $this->ID = -1;
| |
− | }
| |
− | public function IsLoaded() {
| |
− | return ($this->hasRows());
| |
− | }
| |
− | public function Cart() {
| |
− | return $this->objDB->Carts()->GetItem($this->ID_Cart);
| |
− | }
| |
− | public function Item() {
| |
− | $doLoad = FALSE;
| |
− | if (empty($this->objItem)) {
| |
− | $doLoad = TRUE;
| |
− | } elseif ($this->objItem->ID != $this->ID_Item) {
| |
− | $doLoad = TRUE;
| |
− | }
| |
− | if ($doLoad) {
| |
− | $this->objItem = $this->objDB->Items()->GetItem($this->ID_Item);
| |
− | }
| |
− | return $this->objItem;
| |
− | }
| |
− | public function Build() {
| |
− | if ($this->IsLoaded()) {
| |
− | // if ($this->HasRows()) {
| |
− | $sql = 'UPDATE `'.clsShopCartLines::TableName.'` SET'
| |
− | .' Qty='.$this->Qty
| |
− | .' WhenEdited=NOW()'
| |
− | .' WHERE ID='.$this->ID;
| |
− | $this->objDB->Exec($sql);
| |
− | } else {
| |
− | $this->Seq = $this->Cart()->LineCount()+1;
| |
− | $sql = 'INSERT INTO `'.clsShopCartLines::TableName
| |
− | .'` (Seq,ID_Cart,ID_Item,Qty,WhenAdded)'
| |
− | .' VALUES('
| |
− | .$this->Seq.', '
| |
− | .$this->ID_Cart.', '
| |
− | .$this->ID_Item.', '
| |
− | .$this->Qty.', NOW());';
| |
− | $this->objDB->Exec($sql);
| |
− | $this->ID = $this->objDB->NewID('cartLine.make');
| |
− | }
| |
− | }
| |
− | public function Qty($iQty=NULL) {
| |
− | if (!is_null($iQty)) {
| |
− | if ($this->Qty != $iQty) {
| |
− | $qtyNew = 0+$iQty; // make sure it's an integer -- prevent injection attack
| |
− | $arrSet['Qty'] = SQLValue($qtyNew);
| |
− | $arrSet['WhenEdited'] = 'NOW()';
| |
− | $this->Update($arrSet);
| |
− | $this->Qty = $qtyNew;
| |
− | }
| |
− | }
| |
− | return $this->Qty;
| |
− | }
| |
− | /*
| |
− | protected function ItemSpecs(array $iSpecs=NULL) {
| |
− | if (is_null($iSpecs)) {
| |
− | $this->Item(); // make sure $this->objItem is loaded
| |
− | $this->objTitle = $this->objItem->Title();
| |
− | $this->objItTyp = $this->objItem->ItTyp();
| |
− | $this->objItOpt = $this->objItem->ItOpt();
| |
| | | |
− | $out['tname'] = $this->objTitle->Name;
| |
− | $out['ittyp'] = $this->objItTyp->Name($this->Qty);
| |
− | $out['itopt'] = $this->objItOpt->Descr;
| |
− | return $out;
| |
− | } else {
| |
− | return $iSpecs;
| |
− | }
| |
− | }
| |
− | public function ItemDesc(array $iSpecs=NULL) { // plaintext
| |
− | $sp = $this->ItemSpecs($iSpecs);
| |
− |
| |
− | $strItOpt = $sp['itopt'];
| |
− |
| |
− | $out = '"'.$sp['tname'].'" ('.$sp['ittyp'];
| |
− | if (!is_null($strItOpt)) {
| |
− | $out .= ' - '.$strItOpt;
| |
− | }
| |
− | $out .= ')';
| |
− |
| |
− | return $out;
| |
− | }
| |
− | public function ItemDesc_ht(array $iSpecs=NULL) { // as HTML
| |
− | $sp = $this->ItemSpecs($iSpecs);
| |
− |
| |
− | $htTitleName = '<i>'.$this->objTitle->LinkName().'</i>';
| |
− | $strItOpt = $sp['itopt'];
| |
− |
| |
− | $out = $htTitleName.' ('.$sp['ittyp'];
| |
− | if (!is_null($strItOpt)) {
| |
− | $out .= ' - '.$strItOpt;
| |
− | }
| |
− | $out .= ')';
| |
− |
| |
− | return $out;
| |
− | }
| |
− | public function ItemDesc_wt(array $iSpecs=NULL) { // as wikitext
| |
− | $sp = $this->ItemSpecs($iSpecs);
| |
− |
| |
− | $wtTitleName = "''".$this->objTitle->LinkName_wt()."''";
| |
− | $strItOpt = $sp['itopt'];
| |
− |
| |
− | $out = $wtTitleName.' ('.$sp['ittyp'];
| |
− | if (!is_null($strItOpt)) {
| |
− | $out .= ' - '.$strItOpt;
| |
− | }
| |
− | $out .= ')';
| |
− |
| |
− | return $out;
| |
− | }
| |
− | */
| |
− | /*-----
| |
− | PURPOSE: Do calculations necessary for rendering the cart line
| |
− | USED BY:
| |
− | * the shopping cart form
| |
− | * the final order display
| |
− | * the conversion from cart to order
| |
− | */
| |
− | public function RenderCalc(clsShipZone $iZone) {
| |
− | $arItem = $this->Item()->DescSpecs();
| |
− | $txtItemDesc = $this->Item()->DescLong($arItem);
| |
− | $htmItemDesc = $this->Item()->DescLong_ht($arItem);
| |
− |
| |
− | $objItem = $this->Item();
| |
− | $this->PriceItem = $objItem->PriceSell;
| |
− | $this->Value('CatNum',$objItem->CatNum);
| |
− |
| |
− | // save for copying to order line object:
| |
− | $this->DescText = $txtItemDesc;
| |
− | $this->DescHtml = $htmItemDesc;
| |
− |
| |
− | // save so cart can figure totals;
| |
− | $idsZone = $iZone->Abbr();
| |
− | $this->ShipPkgDest = $objItem->ShipPricePkg($idsZone);
| |
− | $this->ShipItmDest = $objItem->ShipPriceItem($idsZone);
| |
− |
| |
− | // calculate costs:
| |
− | $this->CostItemQty = $this->Qty * $this->PriceItem;
| |
− | $this->CostShipQty = $this->Qty * $this->ShipItmDest;
| |
− | }
| |
− | /*
| |
− | ACTION: Render the current cart line using static HTML (no form elements; read-only)
| |
− | HISTORY:
| |
− | 2011-04-01 adapting this to use clsOrdLine->RenderStatic()
| |
− | */
| |
− | public function RenderHtml(clsShopCart $iCart) {
| |
− |
| |
− | $objOLine = $this->Engine()->OrdLines()->SpawnItem();
| |
− | $this->RenderCalc($iCart->objShipZone); // calculate some needed fields
| |
− | $objOLine->Init_fromCartLine($this);
| |
− | return $objOLine->RenderStatic($iCart->objShipZone);
| |
− | /*/
| |
− | // calculate display fields:
| |
− | if ($this->Qty) {
| |
− | $this->RenderCalc($iCart->objShipZone);
| |
− |
| |
− | $strQty = $this->Qty;
| |
− | $htLineCtrl = $strQty;
| |
− |
| |
− | $mnyPrice = $this->PriceItem; // item price
| |
− | $mnyPerItm = $this->ShipItmDest; // per-item shipping
| |
− | $mnyPerPkg = $this->ShipPkgDest; // per-pkg minimum shipping
| |
− | $mnyPriceQty = $this->CostItemQty; // line total sale
| |
− | $mnyPerItmQty = $this->CostShipQty; // line total per-item shipping
| |
− | $mnyLineTotal = $mnyPriceQty + $mnyPerItmQty; // line total overall (does not include per-pkg minimum)
| |
− |
| |
− | $strCatNum = $this->CatNum;
| |
− | $strPrice = FormatMoney($mnyPrice);
| |
− | $strPerItm = FormatMoney($mnyPerItm);
| |
− | $strPriceQty = FormatMoney($mnyPriceQty);
| |
− | $strPerItmQty = FormatMoney($mnyPerItmQty);
| |
− | $strLineTotal = FormatMoney($mnyLineTotal);
| |
− |
| |
− | $strShipPkg = FormatMoney($mnyPerPkg);
| |
− |
| |
− | $htDesc = $this->DescHtml;
| |
− |
| |
− | $htDelBtn = '';
| |
− |
| |
− | $out = <<<__END__
| |
− | <tr>
| |
− | <td>$htDelBtn$strCatNum</td>
| |
− | <td>$htDesc</td>
| |
− | <td class=cart-price align=right>$strPrice</td>
| |
− | <td class=shipping align=right>$strPerItm</td>
| |
− | <td class=qty align=right>$htLineCtrl</td>
| |
− | <td class=cart-price align=right>$strPriceQty</td>
| |
− | <td class=shipping align=right>$strPerItmQty</td>
| |
− | <td class=total align=right>$strLineTotal</td>
| |
− | <td class=shipping align=right>$strShipPkg</td>
| |
− | </tr>
| |
− | __END__;
| |
− | return $out;
| |
− | }
| |
− | /**/
| |
− | }
| |
− | /*----
| |
− | ACTION: Render the current cart line as part of an interactive HTML form
| |
− | */
| |
− | public function RenderForm(clsShopCart $iCart) {
| |
− | // calculate display fields:
| |
− | if ($this->Qty) {
| |
− | $this->RenderCalc($iCart->objShipZone);
| |
− |
| |
− | //$htLineName = 'cart-line-'.$this->Seq;
| |
− | $htLineName = 'qty-'.$this->CatNum;
| |
− | $strQty = $this->Qty;
| |
− | $htLineCtrl = '<input size=2 align=right name="'.$htLineName.'" value='.$strQty.'>';
| |
− |
| |
− | $mnyPrice = $this->PriceItem; // item price
| |
− | $mnyPerItm = $this->ShipItmDest; // per-item shipping
| |
− | $mnyPerPkg = $this->ShipPkgDest; // per-pkg minimum shipping
| |
− | $mnyPriceQty = $this->CostItemQty; // line total sale
| |
− | $mnyPerItmQty = $this->CostShipQty; // line total per-item shipping
| |
− | $mnyLineTotal = $mnyPriceQty + $mnyPerItmQty; // line total overall (does not include per-pkg minimum)
| |
− |
| |
− | $strCatNum = $this->CatNum;
| |
− | $strPrice = FormatMoney($mnyPrice);
| |
− | $strPerItm = FormatMoney($mnyPerItm);
| |
− | $strPriceQty = FormatMoney($mnyPriceQty);
| |
− | $strPerItmQty = FormatMoney($mnyPerItmQty);
| |
− | $strLineTotal = FormatMoney($mnyLineTotal);
| |
− |
| |
− | $strShipPkg = FormatMoney($mnyPerPkg);
| |
− |
| |
− | $htDesc = $this->DescHtml;
| |
− |
| |
− | $htDelBtn = '<span class=text-btn>[<a href="?item='.$this->ID_Item.'&action=del" title="remove '.$strCatNum.' from cart">remove</a>]</span> ';
| |
− |
| |
− | $out = <<<__END__
| |
− | <tr>
| |
− | <td>$htDelBtn$strCatNum</td>
| |
− | <td>$htDesc</td>
| |
− | <td class=cart-price align=right>$strPrice</td>
| |
− | <td class=shipping align=right>$strPerItm</td>
| |
− | <td class=qty align=right>$htLineCtrl</td>
| |
− | <td class=cart-price align=right>$strPriceQty</td>
| |
− | <td class=shipping align=right>$strPerItmQty</td>
| |
− | <td class=total align=right>$strLineTotal</td>
| |
− | <td class=shipping align=right>$strShipPkg</td>
| |
− | </tr>
| |
− | __END__;
| |
− | return $out;
| |
− | /**/
| |
− | }
| |
− | }
| |
− | public function RenderText(clsShopCart $iCart,$iFmt) {
| |
− | if ($this->Qty) {
| |
− | $this->RenderCalc($iCart->objShipZone);
| |
− |
| |
− | $dlrPrice = $this->PriceItem; // item price
| |
− | $dlrPerItm = $this->ShipItmDest; // per-item shipping
| |
− | $dlrPerPkg = $this->ShipPkgDest; // per-pkg minimum shipping
| |
− | $dlrPriceQty = $this->CostItemQty; // line total sale
| |
− | $dlrPerItmQty = $this->CostShipQty; // line total per-item shipping
| |
− | $dlrLineTotal = $dlrPriceQty + $dlrPerItmQty; // line total overall (does not include per-pkg minimum)
| |
− |
| |
− | $ftCatNum = $this->CatNum;
| |
− | $ftPrice = FormatMoney($dlrPrice);
| |
− | $ftPerItm = FormatMoney($dlrPerItm);
| |
− | $ftQty = $this->Qty;
| |
− | $ftPriceQty = FormatMoney($dlrPriceQty); // price x qty
| |
− | $ftPerItmQty = FormatMoney($dlrPerItmQty); // per-item shipping x qty
| |
− | $ftLineTotal = FormatMoney($dlrLineTotal);
| |
− |
| |
− | $ftShipPkg = FormatMoney($dlrPerPkg);
| |
− |
| |
− | $ftDesc = $this->DescText;
| |
− |
| |
− | $out = "\n".sprintf($iFmt,$ftCatNum,$ftPrice,$ftPerItm,$ftQty,$ftPriceQty,$ftPerItmQty,$ftLineTotal);
| |
− | $out .= "\n - $ftDesc";
| |
− | return $out;
| |
− | }
| |
− | /* (2010-02-18) actually, this is probably superceded by RenderText()
| |
− | public function RenderEmail($iCart) {
| |
− | /* TO DO: to be written; the following is from Perl:
| |
− | $out .= "$intLine. $lineDescText\n";
| |
− | $out .= "Catalog #: $lineCatNum\n";
| |
− | $out .= "Price each : ".AlignDollars($linePrice)."\n";
| |
− | $out .= "Shipping each : ".AlignDollars($lineShipItemDest)."\n";
| |
− | $out .= "Min. base shipping: ".AlignDollars($lineShipPkgDest)."\n";
| |
− | if ($lineQty != 1) {
| |
− | $textOrder .= "##### QTY $strQty #####\n";
| |
− | }
| |
− | $out .= "\n";
| |
− | */
| |
− | }
| |
− | }
| |
| // ShopCart Log | | // ShopCart Log |
| class clsShopCartLog extends clsTable { | | class clsShopCartLog extends clsTable { |
Line 2,743: |
Line 376: |
| */ | | */ |
| public function IsValidNow($iKey) { | | public function IsValidNow($iKey) { |
− | $ok = ($this->Token == $iKey);
| + | $ok = ($this->Token == $iKey); |
− | if ($ok) {
| + | if ($ok) { |
− | $idClientWas = $this->ID_Client;
| + | $idClientWas = $this->ID_Client; |
− | $objClient = $this->Client();
| + | $objClient = $this->Client(); |
− | if ($idClientWas != $this->ID_Client) {
| + | if ($idClientWas != $this->ID_Client) { |
− | // not an error, but could indicate a hacking attempt -- so log it, flagged as severe:
| + | // not an error, but could indicate a hacking attempt -- so log it, flagged as severe: |
− | $this->objDB->LogEvent(
| + | $this->objDB->LogEvent( |
− | 'session.valid',
| + | 'session.valid', |
− | 'KEY='.$iKey,' OLD-CLIENT='.$idClientWas.' NEW-CLIENT='.$this->ID_Client,
| + | 'KEY='.$iKey,' OLD-CLIENT='.$idClientWas.' NEW-CLIENT='.$this->ID_Client, |
− | 'stored session client mismatch','XCRED',FALSE,TRUE);
| + | 'stored session client mismatch','XCRED',FALSE,TRUE); |
− | $ok = FALSE;
| + | $ok = FALSE; |
− | }
| + | } |
− | }
| + | } |
− | return $ok;
| + | return $ok; |
| } | | } |
| public function SetCart($iID) { | | public function SetCart($iID) { |
Line 2,774: |
Line 407: |
| public function SessKey() { | | public function SessKey() { |
| return $this->ID.'-'.$this->Token; | | return $this->ID.'-'.$this->Token; |
− | }
| |
− | /*----
| |
− | RETURNS: TRUE if the cart is usable within the current context
| |
− | If we're displaying checkout stuff, it's okay to use a cart
| |
− | which has already been turned into an order.
| |
− | If we're still in the cart-editing phase, then we need to
| |
− | fetch a new cart if the old one has been ordered (or, later,
| |
− | give the user options -- add to existing order, edit existing order,
| |
− | create completely new order...).
| |
− | */
| |
− | private function IsCartUsable($iCart) {
| |
− | if ($this->Engine()->inCkout) {
| |
− | // for voided, still need a new cart; ordered is ok
| |
− | return !$iCart->IsVoided();
| |
− | } else {
| |
− | // ordered or voided means we need a new cart
| |
− | return !$iCart->IsLocked();
| |
− | }
| |
| } | | } |
| /*---- | | /*---- |
Line 2,803: |
Line 418: |
| public function Cart() { // DEPRECATED FORM | | public function Cart() { // DEPRECATED FORM |
| return $this->CartObj(); | | return $this->CartObj(); |
− | }
| |
− | public function CartObj() {
| |
− | // if there's a cart for this session, load it; otherwise create a new one but don't save it:
| |
− | if (!isset($this->objCart)) {
| |
− | $objCarts = $this->objDB->Carts();
| |
− | if (!is_null($this->ID_Cart)) {
| |
− | $objCart = $objCarts->GetItem($this->ID_Cart);
| |
− | /*
| |
− | // KLUGE for testing - should not normally be necessary:
| |
− | if ($this->objCart->ID_Sess==0) {
| |
− | $this->objCart->ID_Sess = $this->ID;
| |
− | $this->objCart->Update(array('ID_Sess'=>$this->ID));
| |
− | }
| |
− | */
| |
− | if (!$this->IsCartUsable($objCart)) {
| |
− | $this->ID_Cart = NULL; // get a new cart if the order is locked
| |
− | }
| |
− | }
| |
− | if (is_null($this->ID_Cart)) {
| |
− | $objCart = $this->objDB->Carts()->SpawnItem();
| |
− | $objCart->InitNew($this->ID);
| |
− | }
| |
− | }
| |
− | assert('is_object($objCart);'); // we should always have a cart at this point
| |
− | $this->objCart = $objCart;
| |
− | return $objCart;
| |
| } | | } |
| public function Client() { | | public function Client() { |
Line 2,900: |
Line 489: |
| } | | } |
| | | |
− | /* ======================
| |
− | ORDER MANAGEMENT CLASSES
| |
− | Should probably be in a separate file
| |
− | LATER: Split into 3 parts:
| |
− | (1) core pieces, like table name
| |
− | (2) pieces only used by cart
| |
− | (3) (already done - class VbzAdminOrders) pieces only used by admin system
| |
− | */
| |
− | class clsOrders extends clsTable {
| |
− | const TableName='core_orders';
| |
| | | |
− | public function __construct($iDB) {
| |
− | parent::__construct($iDB);
| |
− | $this->Name(self::TableName);
| |
− | $this->KeyName('ID');
| |
− | $this->ClassSng('clsOrder');
| |
− | $this->ActionKey(KS_URL_PAGE_ORDER);
| |
− | }
| |
− | /*-----
| |
− | | FUNCTION: Create()
| |
− | | ACTION: create the order record (fill in minimal fields)
| |
− | */
| |
− | public function Create() {
| |
− | $intSeq = $this->NextOrdSeq();
| |
− | $strSeq = sprintf(KS_ORD_NUM_FMT,$intSeq);
| |
− | $strNum = KC_ORD_NUM_PFX.$strSeq;
| |
− | $arIns = array(
| |
− | 'Number' => SQLValue($strNum),
| |
− | 'SortPfx' => SQLValue(KC_ORD_NUM_SORT),
| |
− | 'WhenStarted' => 'NOW()'
| |
− | );
| |
− | $this->Insert($arIns);
| |
− | $id = $this->objDB->NewID();
| |
− | assert('$id > 0');
| |
− | return $id;
| |
− | }
| |
− | /*-----
| |
− | | FUNCTION: NextOrdSeq()
| |
− | | ACTION: get the next order sequence number
| |
− | */
| |
− | private function NextOrdSeq() {
| |
− | $objVars = $this->objDB->VarsGlobal();
| |
− | $intOrdLast = $objVars->Val('ord_seq_prev');
| |
− | $intOrdThis = $intOrdLast+1;
| |
− | $objVars->Val('ord_seq_prev',$intOrdThis);
| |
− | return $intOrdThis;
| |
− | }
| |
− | /*-----
| |
− | | FUNCTION: Populate()
| |
− | | ACTION: fill in the order record with data from the cart
| |
− | */
| |
− | public function CopyCart($iOrdID, clsShopCart $iCartObj) {
| |
− | assert('$iOrdID > 0');
| |
− |
| |
− | // ** ITEMS IN CART (convert from cart lines to order items)
| |
− | //$objTbl = new clsShopCartLines($this->objDB);
| |
− | //$objRows = $objTbl->GetData('ID_Cart='.$this->ID);
| |
− |
| |
− | $objOrd = $this->GetItem($iOrdID);
| |
− | $objOrd->CopyCart($iCartObj);
| |
− |
| |
− | // should this code be in $objOrd->CopyCart?
| |
− | // in session object, set Order ID and clear Cart ID
| |
− | // 2011-03-27 wrong. just set Order ID.
| |
− | $arUpd = array(
| |
− | 'ID_Order' => $iOrdID,
| |
− | //'ID_Cart' => 'NULL'
| |
− | );
| |
− | $iCartObj->Session()->Update($arUpd);
| |
− | // log the event
| |
− | $this->Engine()->LogEvent(
| |
− | __METHOD__,
| |
− | '|ord ID='.$iOrdID.'|cart ID='.$iCartObj->KeyValue(),
| |
− | 'Converted cart to order; SQL='.SQLValue($iCartObj->Session()->sqlExec),
| |
− | 'C>O',FALSE,FALSE);
| |
− |
| |
− | return $objOrd; // this is used by the checkout process
| |
− | }
| |
− | }
| |
− | class clsOrder extends clsVbzRecs {
| |
− | /*----
| |
− | NOTE: "Code" is now an integer. It used to be a string.
| |
− | HISTORY:
| |
− | 2010-10-08 Moved here from VbzAdminOrder
| |
− | */
| |
− | /*
| |
− | public function StartEvent($iWhere,$iCode,$iDescr,$iNotes=NULL) {
| |
− | $arEvent = array(
| |
− | //'type' => clsEvents::kTypeOrd,
| |
− | 'type' => $this->Table->ActionKey(),
| |
− | 'id' => $this->ID,
| |
− | 'where' => $iWhere,
| |
− | 'code' => $iCode,
| |
− | 'descr' => $iDescr
| |
− | );
| |
− | if (!is_null($iNotes)) {
| |
− | $arEvent['notes'] = $iNotes;
| |
− | }
| |
− | $this->idEvent = $this->objDB->Events()->StartEvent($arEvent);
| |
− | }
| |
− | */
| |
− | protected function StartEvent_Simple($iCode,$iDescr,$iWhere) {
| |
− | //$this->objDB->OrderLog()->Add($this->ID,$iCode,$iDescr);
| |
− | $arEv = array(
| |
− | 'descr' => $iDescr,
| |
− | 'type' => $this->Table->ActionKey(),
| |
− | 'id' => $this->KeyValue(),
| |
− | 'where' => $iWhere,
| |
− | 'code' => $iCode);
| |
− | // $this->objDB->Events()->StartEvent($arEv);
| |
− | $this->StartEvent($arEv);
| |
− | }
| |
− | /*====
| |
− | HISTORY:
| |
− | 2010-12-05 boilerplate event logging added to VbzAdminSupplier
| |
− | 2011-03-23 copied from VbzAdminSupplier to VbzAdminOrder
| |
− | 2011-03-27 moved from VbzAdminOrder to clsOrder
| |
− | */
| |
− | public 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();
| |
− | }
| |
− | //====
| |
− | /*
| |
− | protected function FinishEvent(array $iArgs=NULL) {
| |
− | $this->objDB->Events()->FinishEvent($iArgs);
| |
− | }
| |
− | */
| |
− | /*----
| |
− | HISTORY:
| |
− | 2010-10-08 Moved here from VbzAdminOrder; supercedes existing protected function
| |
− | which might not have been working properly anyway (no idEvent)
| |
− | */
| |
− | /* 2011-03-27 this is now redundant
| |
− | public function FinishEvent(array $iArgs=NULL) {
| |
− | $this->objDB->Events()->FinishEvent($this->idEvent,$iArgs);
| |
− | }
| |
− | */
| |
− | /*-----
| |
− | TO DO: Explain why this object sometimes doesn't know what the cart is yet
| |
− | (presumably happens during the cart->order transfer process)
| |
− | USED BY:
| |
− | Created for VbzAdmin, where it is sometimes necessary to pass the cart ID (why?)
| |
− | Now used by this class for displaying order receipt.
| |
− | */
| |
− | protected function Cart($iID=NULL) {
| |
− | if (is_null($iID)) {
| |
− | $idCart = $this->ID_Cart;
| |
− | } else {
| |
− | $idCart = $iID;
| |
− | }
| |
− |
| |
− | $doLoad = TRUE;
| |
− | if (isset($this->objCart)) {
| |
− | if ($this->objCart->ID == $idCart) {
| |
− | $doLoad = FALSE;
| |
− | }
| |
− | }
| |
− | if ($doLoad) {
| |
− | $objCart = $this->objDB->Carts()->GetItem($idCart);
| |
− | $this->objDB->Cart($objCart);
| |
− | $this->objCart = $objCart;
| |
− | }
| |
− | return $objCart;
| |
− | }
| |
− |
| |
− | public function Lines() {
| |
− | $objTbl = $this->objDB->OrdLines();
| |
− | $objRows = $objTbl->GetData('ID_Order='.$this->ID);
| |
− | return $objRows;
| |
− | }
| |
− | public function CopyCart(clsShopCart $iCartObj) {
| |
− | $this->CopyCartData($iCartObj);
| |
− | $this->CopyCartLines($iCartObj);
| |
− | }
| |
− | /* =====
| |
− | ACTION: Copy over basic cart information (totals, etc.)
| |
− | HISTORY:
| |
− | 2010-10-06 added cart ID to update -- otherwise final order confirmation page can't find cart data
| |
− | */
| |
− | private function CopyCartData(clsShopCart $iCartObj) {
| |
− | $curItemTotal = $iCartObj->DataItem(KSI_ITEM_TOTAL);
| |
− | $curShipItem = $iCartObj->DataItem(KSI_PER_ITEM_TOTAL);
| |
− | $curShipPkg = $iCartObj->DataItem(KSI_PER_PKG_TOTAL);
| |
− | $idCart = $iCartObj->ID;
| |
− | $this->ID_Cart;
| |
− |
| |
− | $arUpd = array(
| |
− | 'ID_Cart' => $idCart,
| |
− | 'WebTotal_Merch' => SQLValue($curItemTotal),
| |
− | 'WebTotal_Ship' => SQLValue($curShipItem+$curShipPkg),
| |
− | 'WebTotal_Final' => SQLValue($curItemTotal+$curShipItem+$curShipPkg)
| |
− | );
| |
− | $this->StartEvent_Simple('CDC','Copying data from cart ID='.$idCart,__METHOD__);
| |
− | $this->Update($arUpd); // we're assuming the order record exists at this point
| |
− | $this->FinishEvent();
| |
− | }
| |
− | /*-----
| |
− | ACTION: Create order lines from cart lines
| |
− | */
| |
− | private function CopyCartLines(clsShopCart $iCartObj) {
| |
− | $objRows = $iCartObj->GetLines(); // shopping cart lines to convert
| |
− | $objTbl = new clsOrderLines($this->objDB);
| |
− | $objTbl->Update(array('QtyOrd'=>0),'ID_Order='.$this->ID); // zero out any existing order lines in case customer edits cart
| |
− | if ($objRows->HasRows()) {
| |
− | $this->StartEvent_Simple('CLC','copying cart lines',__METHOD__);
| |
− | $intNew = 0;
| |
− | $intUpd = 0;
| |
− | while ($objRows->NextRow()) {
| |
− | $intSeq = $objRows->Seq;
| |
− | $idItem = $objRows->ID_Item;
| |
− | $intQty = $objRows->Qty;
| |
− | $dtWhenAdded = $objRows->WhenAdded;
| |
− | $dtWhenEdited = $objRows->WhenEdited;
| |
− |
| |
− | $objRows->RenderCalc($iCartObj->objShipZone);
| |
− |
| |
− | $arUpd = array(
| |
− | 'CatNum' => SQLValue($objRows->CatNum),
| |
− | 'Descr' => SQLValue($objRows->Item()->DescLong()),
| |
− | 'QtyOrd' => $intQty,
| |
− | 'Price' => SQLValue($objRows->PriceItem),
| |
− | 'ShipPkg' => SQLValue($objRows->ShipPkgDest),
| |
− | 'ShipItm' => SQLValue($objRows->ShipItmDest),
| |
− | 'isShipEst' => 'FALSE'
| |
− | );
| |
− |
| |
− | // has this item already been transcribed?
| |
− | $sqlFilt = '(ID_Order='.$this->ID.') AND (ID_Item='.$idItem.')';
| |
− | $objOrdItems = $objTbl->GetData($sqlFilt);
| |
− | if ($objOrdItems->RowCount() > 0) {
| |
− | // already transcribed -- update existing record
| |
− | $objTbl->Update($arUpd,$sqlFilt);
| |
− | $intUpd++;
| |
− | } else {
| |
− | // not already transcribed -- insert new record
| |
− | $arIns = $arUpd + array(
| |
− | 'ID_Order' => $this->ID,
| |
− | 'Seq' => $intSeq,
| |
− | 'ID_Item' => $idItem
| |
− | );
| |
− | $objTbl->Insert($arIns);
| |
− | $intNew++;
| |
− | }
| |
− | }
| |
− | $strLines = $intNew.' order line'.Pluralize($intNew).' created';
| |
− | if ($intUpd > 0) {
| |
− | $strLines .= ' and '.$intUpd.' order line'.Pluralize($intUpd).' updated';
| |
− | }
| |
− | $strLines .= ' from cart lines';
| |
− | $this->FinishEvent(array('descr'=>$strLines));
| |
− | } else {
| |
− | $this->StartEvent_Simple('CL0','No cart lines found at order creation time',__METHOD__);
| |
− | $out = '<b>There has been an error</b>: your cart contents seem to be missing.';
| |
− | // TO DO: send email alerting webmaster; print more helpful message.
| |
− | }
| |
− | }
| |
− | /*----
| |
− | PURPOSE: nomenclatural purity. I could have just added the display code to RenderReceipt(),
| |
− | but it seemed like a good idea to have a function that just generates the output without
| |
− | displaying it. It also seemed like a good idea not to add the code to the calling function,
| |
− | because that's untidy, So here we are, with a function shorter than its comments.
| |
− | NOTE: admin functions will generally want to handle the display themselves, so it is good practice
| |
− | to be able to retrieve the output to be displayed without displaying it.
| |
− | It may be redundant to have ShowReceipt() at all, however.
| |
− | */
| |
− | public function ShowReceipt() {
| |
− | $out = $this->RenderReceipt();
| |
− | echo $out;
| |
− | }
| |
− | /*----
| |
− | ACTION: Render the receipt in HTML
| |
− | Shows the order as generated from *cart* data, not what's in the order record.
| |
− | ...except for the order number.
| |
− | */
| |
− | public function RenderReceipt() {
| |
− | $out = NULL;
| |
− |
| |
− | // 2010-10-17 This should have been loaded earlier, but I don't have time to track it down now.
| |
− | // The problem is that it forgets the cart ID otherwise.
| |
− | $this->Reload();
| |
− |
| |
− | // get core objects, for code clarity/portability
| |
− | $objOrd = $this;
| |
− | $objCart = $this->Cart();
| |
− | $idOrder = $this->KeyValue();
| |
− | $idCart = $this->Value('ID_Cart');
| |
− |
| |
− | if (!is_object($objCart)) {
| |
− | throw new exception("Receipt could not get cart object: Cart ID=[$idCart]");
| |
− | }
| |
− | if (($objOrd->IsNew()) || ($objCart->IsNew())) {
| |
− | throw new exception("Receipt has missing object: Order ID=[$idOrder] Cart ID=[$idCart]");
| |
− | }
| |
− |
| |
− | $objCart->GetDetailObjs();
| |
− | $objPay = $objCart->PersonCustObj()->Payment();
| |
− | $objAddrCard = $objCart->AddrCardObj();
| |
− | // the next line is a kluge which only works as long as payment is always ccard
| |
− | // it's also not clear why GetDetailObjs() isn't loading it properly
| |
− | $objPay->Node('addr', $objAddrCard);
| |
− |
| |
− | $arVars = array(
| |
− | 'ord.num' => $objOrd->Number,
| |
− | 'timestamp' => date(KF_RCPT_TIMESTAMP),
| |
− | 'cart.id' => $objCart->ID,
| |
− | 'cart.detail' => $objCart->RenderConfirm(),
| |
− | 'ship.name' => $objCart->AddrShipObj()->Name()->Value(),
| |
− | 'ship.addr' => $objCart->AddrShipObj()->AsText("\n<br>"),
| |
− | 'pay.name' => $objPay->Addr()->Name()->Value(),
| |
− | 'pay.spec' => $objPay->SafeDisplay(),
| |
− | 'email.short' => 'orders-'.date('Y').'@vbz.net'
| |
− | );
| |
− | $objStrTplt = new clsStringTemplate_array(NULL,NULL,$arVars);
| |
− | $objStrTplt->MarkedValue(KHT_RCPT_TPLT);
| |
− | $out = "<!-- ORDER ID: [$idOrder] / CART ID from order: [$idCart] -->";
| |
− | $out .= $objStrTplt->Replace();
| |
− | return $out;
| |
− |
| |
− | // return $objCart->RenderReceipt();
| |
− | }
| |
− | /*----
| |
− | RETURNS: Email address to use for this order (includes order number in address, as a way of tracking
| |
− | spam and possibly later as a way of automatically filing order-related correspondence)
| |
− | */
| |
− | public function EmailAddr() {
| |
− | return 'order-'.$this->Number.'@vbz.net';
| |
− | }
| |
− | /*----
| |
− | RETURNS: Order receipt (from cart data) in text-only format, suitable for emailing
| |
− | HISTORY:
| |
− | 2010-09-13 writing started
| |
− | */
| |
− | public function RenderReceipt_Text() {
| |
− | $out = $this->Cart()->RenderOrder_Text();
| |
− | return $out;
| |
− | }
| |
− | /*----
| |
− | RETURNS: array of values needed to plug into email templates
| |
− | USED BY:
| |
− | cart class, to generate confirmation email
| |
− | order admin class, to display/generate confirmation email
| |
− | */
| |
− | public function TemplateVars() {
| |
− | // global $ksTextEmail;
| |
− | $this->Reload(); // 2010-10-28 kluge attempt - see also RenderReceipt()
| |
− |
| |
− | $objCart = $this->Cart();
| |
− | $objCust = $objCart->PersonCustObj();
| |
− | $objPay = $objCust->Payment();
| |
− |
| |
− | assert('is_object($objCart)');
| |
− | assert('is_object($objCart)');
| |
− | assert('is_object($objPay)');
| |
− |
| |
− | $objCardAddr = $objCart->AddrCardObj();
| |
− | $objCustCont = $objCart->ContCustObj();
| |
− |
| |
− | assert('is_object($objCardAddr)');
| |
− | assert('is_object($objCustCont)');
| |
− |
| |
− | $arVars = array(
| |
− | // THIS IS A KLUGE -- should be something like objCart->CustObj->Name
| |
− | 'cust-name' => $objCardAddr->Name()->Value(),
| |
− | 'cust-email' => $objCustCont->Email()->Value(),
| |
− | 'orders-email' => $this->EmailAddr(),
| |
− | 'ord-num' => $this->Number
| |
− | );
| |
− | return $arVars;
| |
− | }
| |
− | /*----
| |
− | RETURNS: array of values needed for sending confirmation email
| |
− | USED BY:
| |
− | cart class, to generate confirmation email
| |
− | order admin class, to display/generate confirmation email
| |
− | */
| |
− | public function EmailParams(array $iarVars, $iSubj=NULL, $iMsgPre=NULL) {
| |
− | $arVars = $iarVars;
| |
− | $objStrTplt = new clsStringTemplate_array(KS_TPLT_OPEN,KS_TPLT_SHUT,$arVars);
| |
− |
| |
− | $txtSubj = $iSubj;
| |
− | if (empty($txtSubj)) {
| |
− | //$objStrTplt->MarkedValue(KS_TEXT_EMAIL_SUBJECT);
| |
− | $txtSubj = $objStrTplt->Replace(KS_TPLT_EMAIL_SUBJECT);
| |
− | }
| |
− | $arOut['subj'] = $txtSubj;
| |
− |
| |
− | $txtMsgPre = $iMsgPre;
| |
− | if (empty($txtMsgPre)) {
| |
− | $txtMsgPre = $objStrTplt->Replace(KS_TPLT_EMAIL_MSG_TOP);
| |
− | }
| |
− | $arOut['msg.pre'] = $txtMsgPre;
| |
− |
| |
− | $arVars['subject'] = $txtSubj;
| |
− | $objStrTplt->List = $arVars;
| |
− |
| |
− | //$objStrTplt->MarkedValue(KS_TEXT_EMAIL_ADDR_SELF);
| |
− | $txtAddr_Self = $objStrTplt->Replace(KS_TPLT_EMAIL_ADDR_SELF);
| |
− | $arOut['addr.self'] = $txtAddr_Self;
| |
− |
| |
− | //$objStrTplt->MarkedValue(KS_TEXT_EMAIL_ADDR_CUST);
| |
− | $txtAddr_Cust = $objStrTplt->Replace(KS_TPLT_EMAIL_ADDR_CUST);
| |
− | $arOut['addr.cust'] = $txtAddr_Cust;
| |
− |
| |
− | // Calculate text of email to send:
| |
− | $txtEmailBody = $txtMsgPre."\n".$this->RenderReceipt_Text();
| |
− | $arOut['msg.body'] = $txtEmailBody;
| |
− |
| |
− | return $arOut;
| |
− | }
| |
− | /*----
| |
− | ACTION: Email an order confirmation (or show what would be sent)
| |
− | RETURNS: contents of the email
| |
− | HISTORY:
| |
− | 2010-10-08 moved from VbzAdminOrder to clsOrder
| |
− | INPUT:
| |
− | iReally: if FALSE, does not actually send the email, but only renders (and returns) it
| |
− | iParams: array of specifications for how to send the email
| |
− | iParams['to-self']: if TRUE, send a copy to the store admin's address
| |
− | iParams['to-cust']: if TRUE, send a copy to the customer's address
| |
− | iParams['addr-self']: email address for store admin
| |
− | iParams['addr-cust']: email address for customer
| |
− | iParams['subject']: subject of the email
| |
− | iParams['message']: body of the email
| |
− | */
| |
− | //public function EmailConfirm($iReally, $iSendToSelf, $iSendToCust, $iAddrSelf, $iAddrCust, $iSubject, $iMessage) {
| |
− | public function EmailConfirm($iReally, array $iParams, clsLogger $iLog) {
| |
− | $iSendToSelf = $iParams['to-self'];
| |
− | $iSendToCust = $iParams['to-cust'];
| |
− | $iAddrSelf = $iParams['addr-self'];
| |
− | $iAddrCust = $iParams['addr-cust'];
| |
− | $iSubject = $iParams['subject'];
| |
− | $iMessage = $iParams['message'];
| |
− | $htEmailAddr_Self = htmlspecialchars($iAddrSelf);
| |
− | $htEmailAddr_Cust = htmlspecialchars($iAddrCust);
| |
− |
| |
− | $htEmailBody = htmlspecialchars($iMessage);
| |
− | $txtSubj = $iSubject;
| |
− | $htSubj = htmlspecialchars($txtSubj);
| |
− | $intCustCopy = $iSendToCust?'1':'0';
| |
− | $txtCustCopy = $iSendToCust?'YES':'no';
| |
− | $txtSelfCopy = $iSendToSelf?'YES':'no';
| |
− | $doSend = $iReally;
| |
− |
| |
− | $out = NULL;
| |
− | $out .= '<table>';
| |
− | $out .= "<tr><td align=right><b>Store's email address</b>:</td><td>$htEmailAddr_Self</td></tr>";
| |
− | $out .= "<tr><td align=right><b>Customer's email address</b>:</td><td>$htEmailAddr_Cust</td></tr>";
| |
− | $out .= "<tr><td align=right><b>Subject</b>:</td><td>$htSubj</td></tr>";
| |
− | $out .= "<tr><td align=right><b>Copying to customer?</td><td>$txtCustCopy</td></tr>";
| |
− | $out .= '</table>';
| |
− |
| |
− | $out .= '<pre>'.$htEmailBody.'</pre>';
| |
− | if (!$doSend) {
| |
− | $out .= '<form method=post>';
| |
− | $out .= '<input type=hidden name=email-body value="'.$htEmailBody.'">';
| |
− | $out .= '<input type=hidden name=send-to-cust value="'.$intCustCopy.'">';
| |
− | $out .= '<input type=hidden name=addr-self value="'.$htEmailAddr_Self.'">';
| |
− | $out .= '<input type=hidden name=addr-cust value="'.$htEmailAddr_Cust.'">';
| |
− | $out .= '<input type=hidden name=subject value="'.$htSubj.'">';
| |
− | $out .= '<input type=submit name=btnSend value="Send email">';
| |
− | $out .= '</form>';
| |
− | }
| |
− |
| |
− | if ($iReally) {
| |
− | // if we're actually sending, then actually send the email and log it:
| |
− |
| |
− | // log attempt to send email (EM: email/manual)
| |
− | $arEv = array(
| |
− | 'descr' => 'manual order email (self:'.$txtSelfCopy.' cust:'.$txtCustCopy.') Subject: '.$txtSubj,
| |
− | 'code' => 'OEM',
| |
− | 'where' => __METHOD__
| |
− | );
| |
− | $iLog->StartEvent($arEv);
| |
− |
| |
− | if ($iSendToCust) {
| |
− | // if being sent to customer. record the email in the messages table
| |
− | }
| |
− | $okSelf = TRUE;
| |
− | if ($iSendToSelf) {
| |
− | // send our copy of the email
| |
− | $okSelf = mail($iAddrSelf,$txtSubj.' (store copy)',$iMessage,"From: $iAddrCust");
| |
− | }
| |
− | $okCust = TRUE;
| |
− | if ($iSendToCust) {
| |
− | // log the message we're trying to send
| |
− | global $vgUserName;
| |
− | $this->LogEmail(NULL,$vgUserName,'customer',$txtSubj,$iMessage);
| |
− |
| |
− | // send the message to the customer
| |
− | $okCust = mail($iAddrCust,$txtSubj,$iMessage,"From: $iAddrSelf");
| |
− | }
| |
− |
| |
− | // log event completion
| |
− | if ($okSelf && $okCust) {
| |
− | $arEv = NULL;
| |
− | } else {
| |
− | $arEv = array(
| |
− | 'descrfin' => "self ok:$okSelf | cust ok:$okCust",
| |
− | 'error' => TRUE,
| |
− | 'severe' => TRUE);
| |
− | }
| |
− | $this->FinishEvent($arEv);
| |
− | }
| |
− | return $out;
| |
− | }
| |
− | public function LogEmail($iPackage,$iTxtFrom,$iTxtTo,$iSubject,$iMessage) {
| |
− | $this->LogMessage(
| |
− | $iPackage,
| |
− | KSI_ORD_MSG_EMAIL,
| |
− | $iTxtFrom,
| |
− | $iTxtTo,
| |
− | $iSubject,
| |
− | $iMessage);
| |
− | }
| |
− | public function LogMessage($iPackage,$iMethod,$iTxtFrom,$iTxtTo,$iSubject,$iMessage) {
| |
− | $this->objDB->OrdMsgs()->Add(
| |
− | $this->ID,
| |
− | $iPackage,
| |
− | $iMethod,
| |
− | $iTxtFrom,
| |
− | $iTxtTo,
| |
− | $iSubject,
| |
− | $iMessage);
| |
− | }
| |
− | }
| |
− | class clsOrderLines extends clsTable {
| |
− | const TableName='ord_lines';
| |
− |
| |
− | public function __construct($iDB) {
| |
− | parent::__construct($iDB);
| |
− | $this->Name(self::TableName);
| |
− | $this->KeyName('ID');
| |
− | $this->ClassSng('clsOrderLine');
| |
− | }
| |
− | }
| |
− | class clsOrderLine extends clsDataSet {
| |
− | public function Init_fromCartLine(clsShopCartLine $iLine) {
| |
− | // some fields get copied over directly
| |
− | $arNames = array(
| |
− | 'Seq' => 'Seq',
| |
− | 'ID_Item' => 'ID_Item',
| |
− | 'Qty' => 'QtyOrd',
| |
− | 'CatNum' => 'CatNum',
| |
− | 'PriceItem' => 'Price',
| |
− | 'ShipPkgDest' => 'ShipPkg',
| |
− | 'ShipItmDest' => 'ShipItm',
| |
− | 'DescText' => 'Descr',
| |
− | //'DescHtml' => 'DescrHTML' // we may eventually add this field
| |
− | );
| |
− | foreach($arNames as $srce => $dest) {
| |
− | $val = $iLine->Value($srce);
| |
− | $this->Value($dest,$val);
| |
− | }
| |
− | }
| |
− | /*----
| |
− | HISTORY:
| |
− | 2011-03-23 created for AdminPage()
| |
− | */
| |
− | protected $objItem, $idItem;
| |
− | public function ItemObj() {
| |
− | $doLoad = TRUE;
| |
− | $id = $this->Value('ID_Item');
| |
− | if (isset($this->idItem)) {
| |
− | if ($this->idItem == $id) {
| |
− | $doLoad = FALSE;
| |
− | }
| |
− | }
| |
− | if ($doLoad) {
| |
− | $this->objItem = $this->Engine()->Items($id);
| |
− | $this->idItem = $id;
| |
− | }
| |
− | return $this->objItem;
| |
− | }
| |
− | /*----
| |
− | RETURNS: selling price
| |
− | if order line has no price, falls back to catalog item
| |
− | HISTORY:
| |
− | 2011-03-23 created for "charge for package" process
| |
− | */
| |
− | public function PriceSell() {
| |
− | $prc = $this->Value('Price');
| |
− | if (is_null($prc)) {
| |
− | $prc = $this->ItemObj()->PriceSell();
| |
− | }
| |
− | return $prc;
| |
− | }
| |
− | /*----
| |
− | RETURNS: shipping per-package price
| |
− | if order line has no per-package price, falls back to catalog item
| |
− | HISTORY:
| |
− | 2011-03-23 created for "charge for package" process
| |
− | */
| |
− | public function ShPerPkg() {
| |
− | $prc = $this->Value('ShipPkg');
| |
− | if (is_null($prc)) {
| |
− | $prc = $this->ItemObj()->ShPerPkg();
| |
− | }
| |
− | return $prc;
| |
− | }
| |
− | /*----
| |
− | RETURNS: shipping per-item price -- defaults to catalog item's data
| |
− | unless specified in package line
| |
− | HISTORY:
| |
− | 2011-03-23 created for "charge for package" process
| |
− | */
| |
− | public function ShPerItm() {
| |
− | $prc = $this->Value('ShipItm');
| |
− | if (is_null($prc)) {
| |
− | $prc = $this->ItemObj()->ShPerItm();
| |
− | }
| |
− | return $prc;
| |
− | }
| |
− | /*----
| |
− | RETURNS: array of calculated values for this order line
| |
− | array[sh-pkg]: shipping charge per package
| |
− | array[sh-itm.qty]: shipping charge per item, adjusted for quantity ordered
| |
− | array[cost-sell.qty]: selling cost, adjusted for quantity ordered
| |
− | USED BY: so far, only admin functions (shopping functions use Cart objects, not Order)
| |
− | */
| |
− | public function FigureStats() {
| |
− | $qty = $this->Value('QtyOrd');
| |
− | if ($qty != 0) {
| |
− | $prcShPkg = $this->ShPerPkg();
| |
− | } else {
| |
− | // none of this item in package, so don't require this minimum
| |
− | $prcShPkg = 0;
| |
− | }
| |
− | $arOut['sh-pkg'] = $prcShPkg;
| |
− | $arOut['sh-itm.qty'] = $this->ShPerItm() * $qty;
| |
− | $arOut['cost-sell.qty'] = $this->PriceSell() * $qty;
| |
− | return $arOut;
| |
− | }
| |
− | /*----
| |
− | ACTION: Figures totals for the current rowset
| |
− | USED BY: so far, only admin functions (shopping functions use Cart objects, not Order)
| |
− | RETURNS: array in same format as FigureStats(), except with ".qty" removed from index names
| |
− | */
| |
− | public function FigureTotals() {
| |
− | $arSum = NULL;
| |
− | while ($this->NextRow()) {
| |
− | $ar = $this->FigureStats();
| |
− |
| |
− | $prcShItmSum = nzArray($arSum,'sh-itm',0);
| |
− | $prcShPkgMax = nzArray($arSum,'sh-pkg',0);
| |
− | $prcSaleSum = nzArray($arSum,'cost-sell',0);
| |
− |
| |
− | $prcShItmThis = $ar['sh-itm.qty'];
| |
− | $prcShPkgThis = $ar['sh-pkg'];
| |
− | $prcSaleThis = $ar['cost-sell.qty'];
| |
− |
| |
− | $arSum['sh-itm'] = $prcShItmSum + $prcShItmThis;
| |
− | $arSum['cost-sell'] = $prcSaleSum + $prcSaleThis;
| |
− | if ($prcShPkgMax < $prcShPkgThis) {
| |
− | $prcShPkgMax = $prcShPkgThis;
| |
− | }
| |
− | $arSum['sh-pkg'] = $prcShPkgMax;
| |
− | }
| |
− | return $arSum;
| |
− | }
| |
− | /*----
| |
− | ACTION: Render the current order line using static HTML (no form elements; read-only)
| |
− | HISTORY:
| |
− | 2011-04-01 adapted from clsShopCartLine::RenderHtml() to clsOrderLine::RenderStatic()
| |
− | */
| |
− | public function RenderStatic(clsShipZone $iZone) {
| |
− | // calculate display fields:
| |
− | $qty = $this->Value('QtyOrd');
| |
− | if ($qty) {
| |
− | //$this->RenderCalc($iZone);
| |
− |
| |
− | $htLineCtrl = $qty;
| |
− |
| |
− | $mnyPrice = $this->Value('Price'); // item price
| |
− | $mnyPerItm = $this->Value('ShipItm'); // per-item shipping
| |
− | $mnyPerPkg = $this->Value('ShipPkg'); // per-pkg minimum shipping
| |
− | $intQty = $this->Value('QtyOrd');
| |
− | $mnyPriceQty = $mnyPrice * $intQty; // line total sale
| |
− | $mnyPerItmQty = $mnyPerItm * $intQty; // line total per-item shipping
| |
− | $mnyLineTotal = $mnyPriceQty + $mnyPerItmQty; // line total overall (does not include per-pkg minimum)
| |
− |
| |
− | $strCatNum = $this->Value('CatNum');
| |
− | $strPrice = FormatMoney($mnyPrice);
| |
− | $strPerItm = FormatMoney($mnyPerItm);
| |
− | $strPriceQty = FormatMoney($mnyPriceQty);
| |
− | $strPerItmQty = FormatMoney($mnyPerItmQty);
| |
− | $strLineTotal = FormatMoney($mnyLineTotal);
| |
− |
| |
− | $strShipPkg = FormatMoney($mnyPerPkg);
| |
− |
| |
− | $htDesc = $this->Value('Descr'); // was 'DescHtml', but that field doesn't exist here
| |
− |
| |
− | $htDelBtn = '';
| |
− |
| |
− | $out = <<<__END__
| |
− | <tr>
| |
− | <td>$htDelBtn$strCatNum</td>
| |
− | <td>$htDesc</td>
| |
− | <td class=cart-price align=right>$strPrice</td>
| |
− | <td class=shipping align=right>$strPerItm</td>
| |
− | <td class=qty align=right>$htLineCtrl</td>
| |
− | <td class=cart-price align=right>$strPriceQty</td>
| |
− | <td class=shipping align=right>$strPerItmQty</td>
| |
− | <td class=total align=right>$strLineTotal</td>
| |
− | <td class=shipping align=right>$strShipPkg</td>
| |
− | </tr>
| |
− | __END__;
| |
− | return $out;
| |
− | }
| |
− | }
| |
− | }
| |
− |
| |
− | /*----------
| |
− | CLASS PAIR: order messages (table ord_msg)
| |
− | */
| |
− | class clsOrderMsgs extends clsTable {
| |
− | public function __construct($iDB) {
| |
− | parent::__construct($iDB);
| |
− | $this->Name('ord_msg');
| |
− | $this->KeyName('ID');
| |
− | $this->ClassSng('clsOrderMsg');
| |
− | }
| |
− | /*----
| |
− | ACTION: Adds a message to the order
| |
− | */
| |
− | public function Add($iOrder,$iPackage,$iMethod,$iTxtFrom,$iTxtTo,$iSubject,$iMessage) {
| |
− | global $vgUserName;
| |
− |
| |
− | $arIns = array(
| |
− | 'ID_Ord' => $iOrder,
| |
− | 'ID_Pkg' => SQLValue($iPackage), // might be NULL
| |
− | 'ID_Media' => SQLValue($iMethod),
| |
− | 'TxtFrom' => SQLValue($iTxtFrom),
| |
− | 'TxtTo' => SQLValue($iTxtTo),
| |
− | 'TxtRe' => SQLValue($iSubject),
| |
− | 'doRelay' => 'FALSE', // 2010-09-23 this field needs to be re-thought
| |
− | 'WhenCreated' => 'NOW()', // later: add this as an optional argument, if needed
| |
− | 'WhenEntered' => 'NOW()',
| |
− | 'WhenRelayed' => 'NULL',
| |
− | 'Message' => SQLValue($iMessage)
| |
− | );
| |
− | $this->Insert($arIns);
| |
− | }
| |
− | }
| |
− | class clsOrderMsg extends clsDataSet {
| |
− | }
| |
− |
| |
− | /* =======
| |
− | CREDIT CARD UTILITY CLASS
| |
− | */
| |
− | class clsCustCards extends clsTable {
| |
− | public function __construct($iDB) {
| |
− | parent::__construct($iDB);
| |
− | $this->Name('cust_cards');
| |
− | $this->KeyName('ID');
| |
− | }
| |
− |
| |
− | // STATIC section //
| |
− |
| |
− | public static function CardTypeChar($iNum) {
| |
− | $chDigit = substr($iNum,0,1);
| |
− | $arDigits = array(
| |
− | '3' => 'A',
| |
− | '4' => 'V',
| |
− | '5' => 'M',
| |
− | '6' => 'D'
| |
− | );
| |
− | if (isset($arDigits[$chDigit])) {
| |
− | $chOut = $arDigits[$chDigit];
| |
− | } else {
| |
− | $chOut = '?'.$chDigit;
| |
− | }
| |
− | return $chOut;
| |
− | }
| |
− | public static function CardTypeName($iNum) {
| |
− | $chDigit = substr($iNum,0,1);
| |
− | $arDigits = array(
| |
− | '3' => 'Amex',
| |
− | '4' => 'Visa',
| |
− | '5' => 'MasterCard',
| |
− | '6' => 'Discover'
| |
− | );
| |
− | if (isset($arDigits[$chDigit])) {
| |
− | $out = $arDigits[$chDigit];
| |
− | } else {
| |
− | $out = '?'.$chDigit;
| |
− | }
| |
− | return $out;
| |
− | }
| |
− | public static function SafeDescr_Short($iNum,$iExp) {
| |
− | //$dtExp = strtotime($this->CardExp);
| |
− | $dtExp = self::ExpDate($iExp);
| |
− | if (is_null($dtExp)) {
| |
− | $strDate = '?/?';
| |
− | } else {
| |
− | $strDate = $dtExp->format('n/y');
| |
− | }
| |
− | $out = self::CardTypeChar($iNum).'-'.substr($iNum,-4).'x'.$strDate;
| |
− | return $out;
| |
− | }
| |
− | public static function SafeDescr_Long($iNum,$iExp) {
| |
− | $dtExp = self::ExpDate($iExp);
| |
− | if (is_null($dtExp)) {
| |
− | $strDate = '?/?';
| |
− | } else {
| |
− | $strDate = $dtExp->format('F').' of '.$dtExp->format('Y').' ('.$dtExp->format('n/y').')';
| |
− | }
| |
− | $out = self::CardTypeName($iNum).' # ends with -'.substr($iNum,-4).' expires in '.$strDate;
| |
− | return $out;
| |
− | }
| |
− | public static function Searchable($iRaw) {
| |
− | $xts = new xtString(strtolower($iRaw),TRUE);
| |
− | $xts->KeepOnly('0-9'); // keep only numerics
| |
− | return $xts->Value;
| |
− | }
| |
− | /*-----
| |
− | INPUT:
| |
− | iMaxFuture: if year is given as 2 digits, then this is the furthest in the future the year
| |
− | is allowed to be (# of years from now). NOTE: Should be tested with current dates after 2050
| |
− | (or between 1950 and 1999) to make sure it doesn't allow a year too far in the past.
| |
− | OUTPUT: EXP as a DateTime object
| |
− | */
| |
− | public static function ExpDate($iRaw,$iMaxFuture=50) {
| |
− | $strExp = $iRaw;
| |
− | // -- split into month/year or month/day/year
| |
− | $arExp = preg_split('/[\/.\- ]/',$strExp);
| |
− | $intParts = count($arExp);
| |
− | switch ($intParts) {
| |
− | case 1: // for now, we're going to assume MMYY[YY]
| |
− | // TO DO: if people start typing in M with no leading zero, will have to check for even/odd # of chars
| |
− | $intMo = substr($strExp,0,2);
| |
− | $intYr = substr($strExp,2);
| |
− | break;
| |
− | case 2: // month/year
| |
− | $intMo = $arExp[0];
| |
− | $intYr = $arExp[1];
| |
− | break;
| |
− | case 3: // month/day/year or year/month/day
| |
− | if (strlen($arExp[0]) > 3) {
| |
− | $intYr = $arExp[0];
| |
− | $intMo = $arExp[1];
| |
− | $intDy = $arExp[2];
| |
− | } else {
| |
− | $intMo = $arExp[0];
| |
− | $intDy = $arExp[1];
| |
− | $intYr = $arExp[2];
| |
− | }
| |
− | break;
| |
− | default:
| |
− | // unknown format, can't do anything
| |
− | }
| |
− | // check for validity:
| |
− | $ok = FALSE;
| |
− | if (isset($intYr)) {
| |
− | if ($intYr > 0) {
| |
− | if (($intMo > 0) && ($intMo < 13)) {
| |
− | $ok = TRUE;
| |
− | }
| |
− | }
| |
− | }
| |
− | if ($ok) {
| |
− | if ($intYr < 100) { // if year has no century, give it one
| |
− | $intYrNowPart = strftime('%y');
| |
− | $intCent = (int)substr(strftime('%Y'),0,2);
| |
− | if ($intYr < $intYrNowPart) {
| |
− | $intCent++;
| |
− | }
| |
− | $intYr += ($intCent*100);
| |
− | $intYrNowFull = (int)strftime('%Y');
| |
− | if ($intYr - $intYrNowFull > $iMaxFuture) {
| |
− | $intYr -= 100;
| |
− | }
| |
− | }
| |
− | if (!isset($intDy)) {
| |
− | $intDy = cal_days_in_month(CAL_GREGORIAN, $intMo, $intYr); // set to last day of month
| |
− | }
| |
− | $dtOut = $datetime = new DateTime();
| |
− | $dtOut->setDate($intYr, $intMo, $intDy);
| |
− | return $dtOut;
| |
− | } else {
| |
− | return NULL; // if no year, then could not parse format
| |
− | }
| |
− | }
| |
− | public static function ExpDateSQL($iRaw) {
| |
− | $dt = self::ExpDate($iRaw);
| |
− | if (is_object($dt)) {
| |
− | return '"'.$dt->format('Y-m-d').'"';
| |
− | } else {
| |
− | return 'NULL';
| |
− | }
| |
− | }
| |
− | }
| |
| | | |
| /* =============== | | /* =============== |