";
$out .= "\n<form method=post action='./'>";
$out .= "\n\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 "),
'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 = ;
$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 = ''
.''
.''
.''
.''
.''
.''
.''
.''
.''
.'';
$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 = '[<a href="?action=delcart" title="remove all items from cart">remove all</a>]';
$htFirstTot = "";
$htZoneCombo = 'Shipping destination: '.$this->objShipZone->ComboBox();
} else {
$htFirstTot = '';
$htZoneCombo = 'Shipping costs shown assume shipment to '.$this->objShipZone->Text().' address.';
}
$out .= <<<__END__
$htFirstTot
__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 = "Internal error - cart data not available!";
$this->LogEvent('disp',"can't display cart - no data!");
$this->objDB->Events()->LogEvent('cart.render',,'cart data unavailable','cdna',TRUE,TRUE);
} else {
$out = "Your cart is empty.";
$this->LogEvent('disp','displaying cart - empty; zone '.$this->objShipZone->Abbr());
}
} else {
$out = "You have not put anything in your cart yet.";
$this->LogEvent('disp','displaying cart - nothing yet; zone '.$this->objShipZone->Abbr());
}
}
return $out;
}
/*----
PURPOSE: Render cart for order confirmation page (read-only, no form controls)
*/
public function RenderConfirm() {
if ($this->HasLines()) {
$out = $this->RenderCore(FALSE);
} 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 = 'INTERNAL ERROR: 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);
}
/*
$objDataTree->Node('person.ship',$this->objShip);
$objDataTree->Node('person.cust',$this->objCust);
/*----
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()
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() {
if (empty($this->objCust)) {
$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('person.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());
$this->objShip = $this->SpawnPerson('person.ship','recipient');
$this->objCust = $this->PersonCustObj();
$objDataTree->NodeAdd($this->objShip);
$objDataTree->NodeAdd($this->objCust);
//echo $objDataTree->DumpHTML(); die();
$this->objDataTree = $objDataTree;
$objPayment = $this->objCust->Payment();
if (is_null($objPayment)) {
echo 'objCust is class '.get_class($this->objCust).' ';
echo $this->objCust->DumpHTML();
throw new exception('coding error');
}
$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->NameNode());
// (2011-12-25) this section is tricky... it puts some of the key branches into the tree:
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
//$objContDest->Node('addr', $objAddrShip); // shipping address
$this->objShip->Node('contact', $objContDest);
$objContDest->Node('addr', $objAddrShip);
$this->objCust = $this->objShip;
} else {
// buyer and recipient are different
$this->objShip->Node('contact', $objContDest);
$objContDest->Node('addr', $objAddrShip);
$this->objCust->Node('contact', $objContCust);
$this->objCust->Node('name', $objAddrCard->NameNode());
}
$this->hasDetails = TRUE;
}
return $this->objDataTree;
}
/*----
ASSUMES: GetDetailObjs() has been called
*/
/*
public function WhoCust() {
return $this->objCust;
}
/*----
ASSUMES: GetDetailObjs() has been called
*/
/*
public function WhoShip() {
return $this->objShip;
}
}</php>
cat # | description | price each | per-item s/h ea. | qty. | purchase line total | per-item s/h line total | totals | pkg s/h min. |
---|
$htDelAll | totals: | totals: |
$strTotalMerch |
$strItemsShip |
$strTotalItems |
⇓ |
$strShipDesc |
$strShipPkg |
↵ |
$strTotalDesc |
$strOrdTotal |
$htZoneCombo |
|