*** empty log message ***
[Packages/TYPO3.CMS.git] / misc / 3.0.0 / oldscripts / productsLib.inc
1 <?php
2 /***************************************************************
3 *  Copyright notice
4 *  
5 *  (c) 1999-2003 Kasper Skårhøj (kasper@typo3.com)
6 *  All rights reserved
7 *
8 *  This script is part of the Typo3 project. The Typo3 project is 
9 *  free software; you can redistribute it and/or modify
10 *  it under the terms of the GNU General Public License as published by
11 *  the Free Software Foundation; either version 2 of the License, or
12 *  (at your option) any later version.
13
14 *  The GNU General Public License can be found at
15 *  http://www.gnu.org/copyleft/gpl.html.
16 *  A copy is found in the textfile GPL.txt and important notices to the license 
17 *  from the author is found in LICENSE.txt distributed with these scripts.
18 *
19
20 *  This script is distributed in the hope that it will be useful,
21 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
22 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
23 *  GNU General Public License for more details.
24 *
25 *  This copyright notice MUST APPEAR in all copies of the script!
26 ***************************************************************/
27 /**
28  * productsLib.inc
29  * 
30  * Creates a list of products for the shopping basket in Typo3.
31  * Also controls basket, searching and payment.
32  * 
33  * TypoScript config:
34  * - See static_template "plugin.tt_products"
35  * - See TS_ref.pdf
36  *
37  * @author      Kasper Skårhøj <kasper@typo3.com>
38  * @coauthor René Fritz <r.fritz@colorcube.de>
39  */
40
41  
42 /**
43  * changes:
44  *
45  * 12.9.2001 
46  *
47  * added 'page browsing': <- 1 2 3 ->
48  * - see ###LINK_BROWSE### and ###BROWSE_LINKS###
49  * added ###ITEMS_SELECT_COUNT### for displaying the amount of the current available items (in this category or search)
50  *
51  * 13.9.2001 René Fritz
52  *
53  * added range check for $begin_at
54  *
55  * 14.9.2001 René Fritz
56  * bugfix: with adding of page browsing 'orderby' was damaged
57  *
58  * 19.9.2001 René Fritz
59  * changed counting select to 'select count(*)' 
60  *
61  * 20.9.2001 René Fritz
62  * new TS value 'stdSearchFieldExt' extends the search fields. Example: 'stdSearchFieldExt = note2,year'
63  *
64  */
65
66  
67 class user_products {
68         var $cObj;              // The backReference to the mother cObj object set at call time
69
70         var $searchFieldList="title,note,itemnumber";
71
72                 // Internal
73         var $pid_list="";
74         var $uid_list="";                                       // List of existing uid's from the basket, set by initBasket()
75         var $categories=array();                        // Is initialized with the categories of the shopping system
76         var $pageArray=array();                         // Is initialized with an array of the pages in the pid-list
77         var $orderRecord = array();                     // Will hold the order record if fetched.
78
79
80                 // Internal: init():
81         var $cObj="";                                           // Instance of  class cObj, set in init()
82         var $templateCode="";                           // In init(), set to the content of the templateFile. Used by default in getBasket()
83
84                 // Internal: initBasket():
85         var $basket=array();                            // initBasket() sets this array based on the registered items 
86         var $basketExtra;                                       // initBasket() uses this for additional information like the current payment/shipping methods
87         var $recs = Array();                            // in initBasket this is set to the recs-array of fe_user.
88         var $personInfo;                                        // Set by initBasket to the billing address 
89         var $deliveryInfo;                                      // Set by initBasket to the delivery address
90
91                 // Internal: Arrays from getBasket() function
92         var $calculatedBasket;                          // - The basked elements, how many (quantity, count) and the price and total
93         var $calculatedSums_tax;                        // - Sums of goods, shipping, payment and total amount WITH TAX included
94         var $calculatedSums_no_tax;                     // - Sums of goods, shipping, payment and total amount WITHOUT TAX
95
96         var $config=array();
97         var $conf=array();
98         var $tt_product_single="";
99         var $globalMarkerArray=array();
100         var $templateCode="";
101         var $externalCObject="";
102         
103         
104         /**
105          * Main method. Call this from TypoScript by a USER cObject. 
106          */
107         function main_products($content,$conf)  {
108                 $GLOBALS["TSFE"]->set_no_cache();
109
110                 // *************************************
111                 // *** getting configuration values:
112                 // *************************************
113         
114                         // getting configuration values:
115                 $this->conf=$conf;
116                 $this->config["code"] = strtolower(trim($this->cObj->stdWrap($this->conf["code"],$this->conf["code."])));
117                 $this->config["limit"] = t3lib_div::intInRange($this->conf["limit"],0,1000);
118                 $this->config["limit"] = $this->config["limit"] ? $this->config["limit"] : 50;
119                 
120                 $this->config["pid_list"] = trim($this->cObj->stdWrap($this->conf["pid_list"],$this->conf["pid_list."]));
121                 $this->config["pid_list"] = $this->config["pid_list"] ? $this->config["pid_list"] : $GLOBALS["TSFE"]->id;
122         
123                 $this->config["recursive"] = $this->cObj->stdWrap($this->conf["recursive"],$this->conf["recursive."]);
124                 $this->config["storeRootPid"] = $this->conf["PIDstoreRoot"] ? $this->conf["PIDstoreRoot"] : $GLOBALS["TSFE"]->tmpl->rootLine[0][uid];
125         
126                         //extend standard search fields with user setup
127                 $this->searchFieldList = trim($this->conf["stdSearchFieldExt"]) ? implode(",", array_unique(t3lib_div::trimExplode(",",$this->searchFieldList.",".trim($this->conf["stdSearchFieldExt"]),1))) : $this->searchFieldList;
128                 
129                         // If the current record should be displayed.
130                 $this->config["displayCurrentRecord"] = $this->conf["displayCurrentRecord"];
131                 if ($this->config["displayCurrentRecord"])      {
132                         $this->config["code"]="SINGLE";
133                         $this->tt_product_single = true;
134                 } else {
135                         $this->tt_product_single = $GLOBALS["HTTP_GET_VARS"]["tt_products"];
136                 }
137         
138                         // template file is fetched. The whole template file from which the various subpart are extracted.
139                 $this->templateCode = $this->cObj->fileResource($this->conf["templateFile"]);
140         
141                         // globally substituted markers, fonts and colors.      
142                 $splitMark = md5(microtime());
143                 $globalMarkerArray=array();
144                 list($globalMarkerArray["###GW1B###"],$globalMarkerArray["###GW1E###"]) = explode($splitMark,$this->cObj->stdWrap($splitMark,$this->conf["wrap1."]));
145                 list($globalMarkerArray["###GW2B###"],$globalMarkerArray["###GW2E###"]) = explode($splitMark,$this->cObj->stdWrap($splitMark,$this->conf["wrap2."]));
146                 $globalMarkerArray["###GC1###"] = $this->cObj->stdWrap($this->conf["color1"],$this->conf["color1."]);
147                 $globalMarkerArray["###GC2###"] = $this->cObj->stdWrap($this->conf["color2"],$this->conf["color2."]);
148                 $globalMarkerArray["###GC3###"] = $this->cObj->stdWrap($this->conf["color3"],$this->conf["color3."]);
149
150                         // Substitute Global Marker Array
151                 $this->templateCode= $this->cObj->substituteMarkerArrayCached($this->templateCode, $globalMarkerArray);
152
153         
154                         // This cObject may be used to call a function which manipulates the shopping basket based on settings in an external order system. The output is included in the top of the order (HTML) on the basket-page.
155                 $this->externalCObject = $this->getExternalCObject("externalProcessing");
156                 
157                         // Initializes object
158                 $this->setPidlist($this->config["pid_list"]);                           // The list of pid's we're operation on. All tt_products records must be in the pidlist in order to be selected.
159                 $this->TAXpercentage = doubleval($this->conf["TAXpercentage"]);         // Set the TAX percentage.
160                 $this->globalMarkerArray = $globalMarkerArray;
161                 $this->initCategories();        
162                 $this->initBasket($GLOBALS["TSFE"]->fe_user->getKey("ses","recs"));     // Must do this to initialize the basket...
163                 
164                         
165                 // *************************************
166                 // *** Listing items:
167                 // *************************************
168                 
169                 $codes=t3lib_div::trimExplode(",", $this->config["code"]?$this->config["code"]:$this->conf["defaultCode"],1);
170                 if (!count($codes))     $codes=array("");
171                 while(list(,$theCode)=each($codes))     {
172                         $theCode = (string)strtoupper(trim($theCode));
173         
174                         //      debug($theCode);
175                         switch($theCode)        {
176                                 case "TRACKING":
177                                         $content.=$this->products_tracking($theCode);
178                                 break;
179                                 case "BASKET":
180                                 case "PAYMENT":
181                                 case "FINALIZE":
182                                 case "INFO":
183                                         $content.=$this->products_basket($theCode);
184                                 break;
185                                 case "SEARCH":
186                                 case "SINGLE":
187                                 case "LIST":
188                                         $content.=$this->products_display($theCode);
189                                 break;
190                                 default:
191                                         $langKey = strtoupper($GLOBALS["TSFE"]->config["config"]["language"]);
192                                         $helpTemplate = $this->cObj->fileResource("media/scripts/products_help.tmpl");
193         
194                                                 // Get language version
195                                         $helpTemplate_lang="";
196                                         if ($langKey)   {$helpTemplate_lang = $this->cObj->getSubpart($helpTemplate,"###TEMPLATE_".$langKey."###");}
197                                         $helpTemplate = $helpTemplate_lang ? $helpTemplate_lang : $this->cObj->getSubpart($helpTemplate,"###TEMPLATE_DEFAULT###");
198         
199                                                 // Markers and substitution:
200                                         $markerArray["###CODE###"] = $theCode;
201                                         $content.=$this->cObj->substituteMarkerArray($helpTemplate,$markerArray);
202                                 break;
203                         }
204                 }
205                 return $content;
206         }
207
208         /**
209          * Get External CObjects
210          */ 
211         function getExternalCObject($mConfKey)  {
212                 if ($this->conf[$mConfKey] && $this->conf[$mConfKey."."])       {
213                         $this->cObj->regObj = &$this;
214                         return $this->cObj->cObjGetSingle($this->conf[$mConfKey],$this->conf[$mConfKey."."],"/".$mConfKey."/")."";
215                 }
216         }
217
218         /**
219          * Order tracking
220          */ 
221         function products_tracking($theCode)    {
222                 $admin = $this->shopAdmin();
223                 if (t3lib_div::GPvar("tracking") || $admin)     {               // Tracking number must be set
224                         $orderRow = $this->getOrderRecord("",t3lib_div::GPvar("tracking"));
225                         if (is_array($orderRow) || $admin)      {               // If order is associated with tracking id.
226                                 if (!is_array($orderRow))       $orderRow=array("uid"=>0);
227                                 $content = $this->getTrackingInformation($orderRow,$this->templateCode);
228                         } else {        // ... else output error page
229                                 $content=$this->cObj->getSubpart($this->templateCode,$this->spMarker("###TRACKING_WRONG_NUMBER###"));
230                                 if (!$GLOBALS["TSFE"]->beUserLogin)     {$content = $this->cObj->substituteSubpart($content,"###ADMIN_CONTROL###","");}
231                         }
232                 } else {        // No tracking number - show form with tracking number
233                         $content=$this->cObj->getSubpart($this->templateCode,$this->spMarker("###TRACKING_ENTER_NUMBER###"));
234                         if (!$GLOBALS["TSFE"]->beUserLogin)     {$content = $this->cObj->substituteSubpart($content,"###ADMIN_CONTROL###","");}
235                 }
236                 $markerArray=array();
237                 $markerArray["###FORM_URL###"] = $this->getLinkUrl();   // Add FORM_URL to globalMarkerArray, linking to self.
238                 $content= $this->cObj->substituteMarkerArray($content, $markerArray);
239                         
240                 return $content;
241         }
242
243         /**
244          * Takes care of basket, address info, confirmation and gate to payment
245          */
246         function products_basket($theCode)      {
247                 $this->setPidlist($this->config["storeRootPid"]);       // Set list of page id's to the storeRootPid. 
248                 $this->initRecursive(999);              // This add's all subpart ids to the pid_list based on the rootPid set in previous line
249                 $this->generatePageArray();             // Creates an array with page titles from the internal pid_list. Used for the display of category titles.
250
251                 if (count($this->basket))       {       // If there is content in the shopping basket, we are going display some basket code
252                                 // prepare action
253                         $activity="";
254                         if (t3lib_div::GPvar("products_info"))  {
255                                 $activity="products_info";
256                         } elseif (t3lib_div::GPvar("products_payment")) {
257                                 $activity="products_payment";
258                         } elseif (t3lib_div::GPvar("products_finalize"))        {
259                                 $activity="products_finalize";
260                         }
261                         
262                         if ($theCode=="INFO")   {
263                                 $activity="products_info";
264                         } elseif ($theCode=="PAYMENT")  {
265                                 $activity="products_payment";
266                         } elseif ($theCode=="FINALIZE") {
267                                 $activity="products_finalize";
268                         }
269                         
270 //                      debug($activity);
271                                 // perform action
272                         switch($activity)       {
273                                 case "products_info":
274                                         $this->load_noLinkExtCobj();
275                                         $content.=$this->getBasket("###BASKET_INFO_TEMPLATE###");
276                                 break;
277                                 case "products_payment":
278                                         $this->load_noLinkExtCobj();
279                                         if ($this->checkRequired())     {
280                                                 $this->mapPersonIntoToDelivery();
281                                                 $content=$this->getBasket("###BASKET_PAYMENT_TEMPLATE###");
282                                         } else {        // If not all required info-fields are filled in, this is shown instead:
283                                                 $content.=$this->cObj->getSubpart($this->templateCode,$this->spMarker("###BASKET_REQUIRED_INFO_MISSING###"));
284                                                 $content = $this->cObj->substituteMarkerArray($content, $this->addURLMarkers(array()));
285                                         }
286                                 break;
287                                 case "products_finalize":
288                                         if ($this->checkRequired())     {
289                                                 $this->load_noLinkExtCobj();
290                                                 $this->mapPersonIntoToDelivery();
291                                                 $handleScript = $GLOBALS["TSFE"]->tmpl->getFileName($this->basketExtra["payment."]["handleScript"]);
292                                                 if ($handleScript)      {
293                                                         $content = $this->includeHandleScript($handleScript,$this->basketExtra["payment."]["handleScript."]);
294                                                 } else {
295                                                         $orderUid = $this->getBlankOrderUid();
296                                                         $content=$this->getBasket("###BASKET_ORDERCONFIRMATION_TEMPLATE###");
297                                                         $this->finalizeOrder($orderUid);        // Important: finalizeOrder MUST come after the call of prodObj->getBasket, because this function, getBasket, calculates the order! And that information is used in the finalize-function
298                                                 }
299                                         } else {        // If not all required info-fields are filled in, this is shown instead:
300                                                 $content.=$this->cObj->getSubpart($this->templateCode,$this->spMarker("###BASKET_REQUIRED_INFO_MISSING###"));
301                                                 $content = $this->cObj->substituteMarkerArray($content, $this->addURLMarkers(array()));
302                                         }
303                                 break;
304                                 default:
305                                         $content.=$this->getBasket();
306                                 break;
307                         }
308                 } else {
309                         $content.=$this->cObj->getSubpart($this->templateCode,$this->spMarker("###BASKET_TEMPLATE_EMPTY###"));
310                 }
311                 $markerArray=array();
312                 $markerArray["###EXTERNAL_COBJECT###"] = $this->externalCObject;        // adding extra preprocessing CObject
313                 $content= $this->cObj->substituteMarkerArray($content, $markerArray);
314
315                 return $content;
316         }
317         function load_noLinkExtCobj()   {
318                 if ($this->conf["externalProcessing_final"] || is_array($this->conf["externalProcessing_final."]))      {       // If there is given another cObject for the final order confirmation template!
319                         $this->externalCObject = $this->getExternalCObject("externalProcessing_final");
320                 }
321         }
322         
323         /**
324          * Returning template subpart marker
325          */
326         function spMarker($subpartMarker)       {
327                 $sPBody = substr($subpartMarker,3,-3);
328                 $altSPM = "";
329                 if (isset($this->conf["altMainMarkers."]))      {
330                         $altSPM = trim($this->cObj->stdWrap($this->conf["altMainMarkers."][$sPBody],$this->conf["altMainMarkers."][$sPBody."."]));
331                         $GLOBALS["TT"]->setTSlogMessage("Using alternative subpart marker for '".$subpartMarker."': ".$altSPM,1);
332                 }
333                 return $altSPM ? $altSPM : $subpartMarker;
334         }
335
336         /**
337          * Displaying single products/ the products list / searching
338          */
339         function products_display($theCode)     {
340                 $formUrl = $this->getLinkUrl($this->conf["PIDbasket"]);
341                 if ($this->tt_product_single)   {
342         // List single product:                 
343                                 // performing query:
344                         $this->setPidlist($this->config["storeRootPid"]);
345                         $this->initRecursive(999);
346                         $this->generatePageArray();
347                         
348                         $query = "SELECT * FROM tt_products WHERE uid=".intval($this->tt_product_single)." AND pid IN (".$this->pid_list.")".$this->cObj->enableFields("tt_products");
349                         $res = mysql(TYPO3_db,$query);
350                         echo mysql_error();
351
352                         if($this->config["displayCurrentRecord"] || $row=mysql_fetch_assoc($res))               {
353                                         // Get the subpart code
354                                 $item ="";
355                                 if ($this->config["displayCurrentRecord"])      {
356                                         $row=$this->cObj->data;
357                                         $item = trim($this->cObj->getSubpart($this->templateCode,$this->spMarker("###ITEM_SINGLE_DISPLAY_RECORDINSERT###")));
358                                 }
359                                 $catTitle= $this->pageArray[$row["pid"]]["title"].($row["category"]?"/".$this->categories[$row["category"]]:"");
360                                 if (!$item)     {$item = $this->cObj->getSubpart($this->templateCode,$this->spMarker("###ITEM_SINGLE_DISPLAY###"));}
361
362                                         // Fill marker arrays
363                                 $wrappedSubpartArray=array();
364                                 $wrappedSubpartArray["###LINK_ITEM###"]= array('<A href="'.$this->getLinkUrl(t3lib_div::GPvar("backPID")).'">','</A>');
365
366                                 $markerArray = $this->getItemMarkerArray ($row,$catTitle,10);
367                                 $markerArray["###FORM_NAME###"]="item_".$this->tt_product_single;
368                                 $markerArray["###FORM_URL###"]=$formUrl;
369                                 
370                                         // Substitute
371                                 $content= $this->cObj->substituteMarkerArrayCached($item,$markerArray,array(),$wrappedSubpartArray);
372                         }
373                 } elseif ($theCode=="SINGLE") {         
374                         $content.="Wrong parameters, GET/POST var 'tt_products' was missing.";
375                 } else {                
376                         $content="";
377         // List products:
378                         $where="";                      
379                         if ($theCode=="SEARCH") {
380                                         // Get search subpart
381                                 $t["search"] = $this->cObj->getSubpart($this->templateCode,$this->spMarker("###ITEM_SEARCH###"));
382                                         // Substitute a few markers
383                                 $out=$t["search"];                              
384                                 $out=$this->cObj->substituteMarker($out, "###FORM_URL###", $this->getLinkUrl($this->conf["PIDsearch"]));
385                                 $out=$this->cObj->substituteMarker($out, "###SWORDS###", htmlspecialchars(t3lib_div::GPvar("swords")));
386                                         // Add to content
387                                 $content.=$out;
388                                 if (t3lib_div::GPvar("swords")) {
389                                         $where = $this->searchWhere(trim(t3lib_div::GPvar("swords")));
390                                 }
391                         }
392                         $begin_at=t3lib_div::intInRange(t3lib_div::GPvar("begin_at"),0,100000);
393                         if (($theCode!="SEARCH" && !t3lib_div::GPvar("swords")) || $where)      {
394                         
395                                 $this->initRecursive($this->config["recursive"]);
396                                 $this->generatePageArray();
397         
398                                         // Get products
399                                 $selectConf = Array();
400                                 $selectConf["pidInList"] = $this->pid_list;
401                                 $selectConf["where"] = "1=1 ".$where;
402
403                                         // performing query to count all products (we need to know it for browsing):
404                                 $query = eregi_replace("^[\t ]*SELECT.+FROM", "SELECT count(*) FROM", $this->cObj->getQuery("tt_products",$selectConf));
405                                 $res = mysql(TYPO3_db,$query); 
406                                 echo mysql_error();
407                                 $row = mysql_fetch_row($res);
408                                 $productsCount = $row[0];
409
410                                         // range check to current productsCount
411                                 $begin_at = t3lib_div::intInRange(($begin_at >= $productsCount)?($productsCount-$this->config["limit"]):$begin_at,0); 
412
413                                         // performing query for display:
414                                 $selectConf["orderBy"] = "pid,category,title"; 
415
416                                 $query = $this->cObj->getQuery("tt_products",$selectConf);
417                                 $query.=" LIMIT ".$begin_at.",".($this->config["limit"]+1);
418
419                                 $res = mysql(TYPO3_db,$query);
420                                 echo mysql_error();
421                                 $productsArray=array();
422                                 while($row=mysql_fetch_assoc($res))             {
423                                         $productsArray[$row["pid"]][]=$row;
424                                 }
425                                 
426                                         // Getting various subparts we're going to use here:
427                                 $t["listFrameWork"] = $this->cObj->getSubpart($this->templateCode,$this->spMarker("###ITEM_LIST_TEMPLATE###"));
428                                 $t["categoryTitle"] = $this->cObj->getSubpart($t["listFrameWork"],"###ITEM_CATEGORY###");
429                                 $t["itemFrameWork"] = $this->cObj->getSubpart($t["listFrameWork"],"###ITEM_LIST###");
430                                 $t["item"] = $this->cObj->getSubpart($t["itemFrameWork"],"###ITEM_SINGLE###");
431                                 
432                                 $pageArr=explode(",",$this->pid_list);
433                                 $currentP="";
434                                 $out="";
435                                 $iCount=0;
436                                 $more=0;                // If set during this loop, the next-item is drawn
437                                 while(list(,$v)=each($pageArr)) {
438                                         if (is_array($productsArray[$v]))       {
439                                                 reset($productsArray[$v]);
440                                                 $itemsOut="";
441                                                 while(list(,$row)=each($productsArray[$v]))     {
442                                                         $iCount++;
443                                                         if ($iCount>$this->config["limit"])     {
444                                                                 $more=1;
445                                                                 break;
446                                                         }
447
448
449                                                                 // Print Category Title
450                                                         if ($row["pid"]."_".$row["category"]!=$currentP)        {
451                                                                 if ($itemsOut)  {
452                                                                         $out.=$this->cObj->substituteSubpart($t["itemFrameWork"], "###ITEM_SINGLE###", $itemsOut);
453                                                                 }
454                                                                 $itemsOut="";                   // Clear the item-code var
455                         
456                                                                 $currentP = $row["pid"]."_".$row["category"];
457                                                                 if ($where || $this->conf["displayListCatHeader"])      {
458                                                                         $markerArray=array();
459                                                                         $catTitle= $this->pageArray[$row["pid"]]["title"].($row["category"]?"/".$this->categories[$row["category"]]:"");
460                                                                         $this->cObj->setCurrentVal($catTitle);
461                                                                         $markerArray["###CATEGORY_TITLE###"]=$this->cObj->cObjGetSingle($this->conf["categoryHeader"],$this->conf["categoryHeader."], "categoryHeader");
462                                                                         $out.= $this->cObj->substituteMarkerArray($t["categoryTitle"], $markerArray);
463                                                                 }
464                                                         }
465         
466                                                                 // Print Item Title
467                                                         $wrappedSubpartArray=array();
468                                                         $wrappedSubpartArray["###LINK_ITEM###"]= array('<A href="'.$this->getLinkUrl($this->conf["PIDitemDisplay"]).'&tt_products='.$row["uid"].'">','</A>'); 
469                                                         $markerArray = $this->getItemMarkerArray ($row,$catTitle,1,"listImage");
470                                                         $markerArray["###FORM_URL###"]=$formUrl; // Applied later as well.
471                                                         $markerArray["###FORM_NAME###"]="item_".$iCount;
472                                                         $itemsOut.= $this->cObj->substituteMarkerArrayCached($t["item"],$markerArray,array(),$wrappedSubpartArray);
473                                                 }
474                                                 if ($itemsOut)  {
475                                                         $out.=$this->cObj->substituteMarkerArrayCached($t["itemFrameWork"], array(), array("###ITEM_SINGLE###"=>$itemsOut));
476                                                 }
477                                         }
478                                 }
479                         }
480                         if ($out)       {
481                                 // next / prev:
482                                 $url = $this->getLinkUrl("","begin_at");
483                                         // Reset:
484                                 $subpartArray=array();
485                                 $wrappedSubpartArray=array();
486                                 $markerArray=array();
487                                         
488                                 if ($more)      {
489                                         $next = ($begin_at+$this->config["limit"] > $productsCount) ? $productsCount-$this->config["limit"] : $begin_at+$this->config["limit"];
490                                         $wrappedSubpartArray["###LINK_NEXT###"]=array('<A href="'.$url.'&begin_at='.$next.'">','</A>');
491                                 } else {
492                                         $subpartArray["###LINK_NEXT###"]="";
493                                 }
494                                 if ($begin_at)  {
495                                         $prev = ($begin_at-$this->config["limit"] < 0) ? 0 : $begin_at-$this->config["limit"];
496                                         $wrappedSubpartArray["###LINK_PREV###"]=array('<A href="'.$url.'&begin_at='.$prev.'">','</A>');
497                                 } else {
498                                         $subpartArray["###LINK_PREV###"]="";
499                                 }
500                                 if ($productsCount > $this->config["limit"] )   { // there is more than one page, so let's browse
501                                         $wrappedSubpartArray["###LINK_BROWSE###"]=array('',''); // <- this could be done better I think, or not?
502                                         $markerArray["###BROWSE_LINKS###"]="";
503                                         for ($i = 0 ; $i < ($productsCount/$this->config["limit"]); $i++)       {
504                                                 if (($begin_at >= $i*$this->config["limit"]) && ($begin_at < $i*$this->config["limit"]+$this->config["limit"]))         {
505                                                         $markerArray["###BROWSE_LINKS###"].= ' <b>'.(string)($i+1).'</b> ';
506                                                         //      you may use this if you want to link to the current page also
507                                                         //      $markerArray["###BROWSE_LINKS###"].= ' <A href="'.$url.'&begin_at='.(string)($i * $this->config["limit"]).'"><b>'.(string)($i+1).'</b></A> ';
508                                                 } else {
509                                                         $markerArray["###BROWSE_LINKS###"].= ' <A href="'.$url.'&begin_at='.(string)($i * $this->config["limit"]).'">'.(string)($i+1).'</A> ';
510                                                 }
511                                         }
512                                 } else {
513                                         $subpartArray["###LINK_BROWSE###"]="";
514                                 }
515
516                                 $subpartArray["###ITEM_CATEGORY_AND_ITEMS###"]=$out;
517                                 $markerArray["###FORM_URL###"]=$formUrl;      // Applied it here also...
518                                 $markerArray["###ITEMS_SELECT_COUNT###"]=$productsCount;
519
520                                 $content.= $this->cObj->substituteMarkerArrayCached($t["listFrameWork"],$markerArray,$subpartArray,$wrappedSubpartArray);
521                         } elseif ($where)       {
522                                 $content.=$this->cObj->getSubpart($this->templateCode,$this->spMarker("###ITEM_SEARCH_EMPTY###"));
523                         }
524                 }
525                 return $content;
526         }
527
528         /**
529          * Sets the pid_list internal var
530          */
531         function setPidlist($pid_list)  {
532                 $this->pid_list = $pid_list;
533         }
534
535         /**
536          * Extends the internal pid_list by the levels given by $recursive
537          */
538         function initRecursive($recursive)      {
539                 if ($recursive) {               // get pid-list if recursivity is enabled
540                         $pid_list_arr = explode(",",$this->pid_list);
541                         $this->pid_list="";
542                         while(list(,$val)=each($pid_list_arr))  {
543                                 $this->pid_list.=$val.",".$this->cObj->getTreeList($val,intval($recursive));
544                         }
545                         $this->pid_list = ereg_replace(",$","",$this->pid_list);
546                 }
547         }
548
549         /**
550          * Getting all tt_products_cat categories into internal array
551          */
552         function initCategories()       {
553                         // Fetching catagories:
554                 $query = "select * from tt_products_cat where 1=1".$this->cObj->enableFields("tt_products_cat");
555                 $res = mysql(TYPO3_db,$query);
556                 echo mysql_error();
557                 $this->categories=array();
558                 while($row = mysql_fetch_assoc($res))   {
559                         $this->categories[$row["uid"]] = $row["title"];
560                 }       
561         }
562
563         /**
564          * Generates an array, ->pageArray of the pagerecords from ->pid_list
565          */
566         function generatePageArray()    {
567                         // Get pages (for category titles)              
568                 $query="SELECT title,uid FROM pages WHERE uid IN(".$this->pid_list.")";
569                 $res = mysql(TYPO3_db,$query);
570                 echo mysql_error();
571                 $this->pageArray=array();
572                 while($row=mysql_fetch_assoc($res))             {
573                         $this->pageArray[$row["uid"]] = $row;
574                 }
575         }
576
577         /**
578          * Initialized the basket, setting the deliveryInfo if a users is logged in
579          *
580      * $basket is the Typo3 default shopping basket array from ses-data
581          */
582         function initBasket($basket)    {
583                 $this->recs = $basket;  // Sets it internally
584                 $this->basket=array();
585                 $uidArr=array();
586                 if (is_array($basket["tt_products"]))   {
587                         reset($basket["tt_products"]);
588                         while(list($uid,$count)=each($basket["tt_products"]))   {
589                                 if (t3lib_div::testInt($uid))   {
590                                         $count=t3lib_div::intInRange($count,0,100000);
591                                         if ($count)     {
592                                                 $this->basket[$uid]=$count;
593                                                 $uidArr[]=$uid;
594                                         }
595                                 }
596                         }
597                 }
598                 $this->uid_list=implode($uidArr,",");
599                 $this->setBasketExtras($basket);
600
601                 $this->personInfo = $basket["personinfo"];
602                 $this->deliveryInfo = $basket["delivery"];
603                 if ($GLOBALS["TSFE"]->loginUser && (!$this->personInfo || $this->conf["lockLoginUserInfo"]))    {
604                         $address = implode(chr(10),t3lib_div::trimExplode(chr(10),
605                                 $GLOBALS["TSFE"]->fe_user->user["address"].chr(10).
606                                 $GLOBALS["TSFE"]->fe_user->user["zip"]." ".$GLOBALS["TSFE"]->fe_user->user["city"].chr(10).
607                                 $GLOBALS["TSFE"]->fe_user->user["country"]
608                                 ,1)
609                         );
610
611                         $this->personInfo["name"] = $GLOBALS["TSFE"]->fe_user->user["name"];
612                         $this->personInfo["address"] = $address;
613                         $this->personInfo["email"] = $GLOBALS["TSFE"]->fe_user->user["email"];
614                         $this->personInfo["telephone"] = $GLOBALS["TSFE"]->fe_user->user["telephone"];
615                         $this->personInfo["fax"] = $GLOBALS["TSFE"]->fe_user->user["fax"];
616                 }
617         }
618
619         /**
620          * Check if payment/shipping option is available
621          */
622         function checkExtraAvailable($name,$key)        {
623                 if (is_array($this->conf[$name."."][$key."."]) && (!isset($this->conf[$name."."][$key."."]["show"]) || $this->conf[$name."."][$key."."]["show"]))       {
624                         return true;
625                 }
626         }
627         
628         /**
629          * Setting shipping and payment methods
630          */
631         function setBasketExtras($basket)       {
632                         // shipping
633                 ksort($this->conf["shipping."]);
634                 reset($this->conf["shipping."]);
635                 $k=intval($basket["tt_products"]["shipping"]);
636                 if (!$this->checkExtraAvailable("shipping",$k)) {
637                         $k=intval(key($this->cleanConfArr($this->conf["shipping."],1)));
638                 }
639                 $this->basketExtra["shipping"] = $k;
640                 $this->basketExtra["shipping."] = $this->conf["shipping."][$k."."];
641                 $excludePayment = trim($this->basketExtra["shipping."]["excludePayment"]);
642                 
643                         // payment
644                 if ($excludePayment)    {
645                         $exclArr = t3lib_div::intExplode(",",$excludePayment);
646                         while(list(,$theVal)=each($exclArr))    {
647                                 unset($this->conf["payment."][$theVal]);
648                                 unset($this->conf["payment."][$theVal."."]);
649                         }
650                 }
651                 
652                 ksort($this->conf["payment."]);
653                 reset($this->conf["payment."]);
654                 $k=intval($basket["tt_products"]["payment"]);
655                 if (!$this->checkExtraAvailable("payment",$k))  {
656                         $k=intval(key($this->cleanConfArr($this->conf["payment."],1)));
657                 }
658                 $this->basketExtra["payment"] = $k;
659                 $this->basketExtra["payment."] = $this->conf["payment."][$k."."];
660
661 //              debug($this->basketExtra);
662 //              debug($this->conf);
663         }
664
665         /**
666          * Returns a clear 'recs[tt_products]' array - so clears the basket.
667          */
668         function getClearBasketRecord() {
669                         // Returns a basket-record cleared of tt_product items
670                 unset($this->recs["tt_products"]);
671                 return ($this->recs);
672         }
673
674
675
676
677         
678         
679
680         // **************************
681         // ORDER related functions
682         // **************************
683         
684         /**
685          * Create a new order record
686          *
687          * This creates a new order-record on the page with pid, .PID_sys_products_orders. That page must exist!
688          * Should be called only internally by eg. getBlankOrderUid, that first checks if a blank record is already created.
689          */
690         function createOrder()  {
691                 $newId=0;
692                 $pid = intval($this->conf["PID_sys_products_orders"]);
693                 if (!$pid)      $pid = intval($GLOBALS["TSFE"]->id);
694                 if ($GLOBALS["TSFE"]->sys_page->getPage_noCheck ($pid)) {
695                         $query = "INSERT INTO sys_products_orders (pid,tstamp,crdate,deleted) values (".$pid.",".time().",".time().",1)";
696                         $res = mysql(TYPO3_db,$query);
697                         $newId = mysql_insert_id();
698                         echo mysql_error();
699                 }
700                 return $newId;
701         }
702
703         /**
704          * Returns a blank order uid. If there was no order id already, a new one is created.
705          *
706          * Blank orders are marked deleted and with status=0 initialy. Blank orders are not necessarily finalized because users may abort instead of buying. 
707          * A finalized order is marked "not deleted" and with status=1.
708          * Returns this uid which is a blank order record uid.
709          */
710         function getBlankOrderUid()     {
711                 $orderUid = intval($this->recs["tt_products"]["orderUid"]);
712                 $query = "SELECT uid FROM sys_products_orders WHERE uid=".$orderUid." AND deleted AND NOT status";      // Checks if record exists, is marked deleted (all blank orders are deleted by default) and is not finished.
713                 $res = mysql(TYPO3_db,$query);
714                 echo mysql_error();
715                 if (!mysql_num_rows($res))      {
716                         $orderUid = $this->createOrder();
717                         $this->recs["tt_products"]["orderUid"] = $orderUid;
718                         $this->recs["tt_products"]["orderDate"] = time();
719                         $this->recs["tt_products"]["orderTrackingNo"] = $this->getOrderNumber($orderUid)."-".strtolower(substr(md5(uniqid(time())),0,6));
720                         $GLOBALS["TSFE"]->fe_user->setKey("ses","recs",$this->recs);
721                 }
722                 return $orderUid;
723         }
724
725         /**
726          * Returns the orderRecord if $orderUid. 
727          * If $tracking is set, then the order with the tracking number is fetched instead.
728          */
729         function getOrderRecord($orderUid,$tracking="") {
730                 $selectClause= $tracking ? "tracking_code='".$tracking."'" : "uid=".intval($orderUid);
731                 $query = "SELECT * FROM sys_products_orders WHERE ".$selectClause." AND NOT deleted";
732                 $res = mysql(TYPO3_db,$query);
733                 echo mysql_error();
734                 return mysql_fetch_assoc($res);
735         }
736
737         /**
738          * This returns the order-number (opposed to the order_uid) for display in the shop, confirmation notes and so on.
739          * Basically this prefixes the .orderNumberPrefix, if any
740          */
741         function getOrderNumber($orderUid)      {
742                 return substr($this->conf["orderNumberPrefix"],0,10).$orderUid;
743         }
744
745         /**
746          * Finalize an order
747          *
748          * This finalizes an order by saving all the basket info in the current order_record.
749          * A finalized order is then marked "not deleted" and with status=1
750          * The basket is also emptied, but address info is preserved for any new orders.
751          * $orderUid is the order-uid to finalize
752          * $mainMarkerArray is optional and may be pre-prepared fields for substitutiong in the template.
753          */
754         function finalizeOrder($orderUid,$mainMarkerArray=array())      {
755                         // Fix delivery address
756                 $this->mapPersonIntoToDelivery();       // This maps the billing address into the blank fields of the delivery address
757                 $mainMarkerArray["###EXTERNAL_COBJECT###"] = $this->externalCObject."";
758                 $orderConfirmationHTML=trim($this->getBasket("###BASKET_ORDERCONFIRMATION_TEMPLATE###","",$mainMarkerArray));           // Getting the template subpart for the order confirmation!
759
760                         // Saving order data
761                 $fieldsArray=array();
762                 $fieldsArray["note"]=$this->deliveryInfo["note"];
763                 $fieldsArray["name"]=$this->deliveryInfo["name"];
764                 $fieldsArray["telephone"]=$this->deliveryInfo["telephone"];
765                 $fieldsArray["email"]=$this->deliveryInfo["email"];
766                 $fieldsArray["email_notify"]=  $this->conf["email_notify_default"];             // Email notification is set here. Default email address is delivery email contact
767
768                         // can be changed after order is set.
769                 $fieldsArray["payment"]=$this->basketExtra["payment"].": ".$this->basketExtra["payment."]["title"];
770                 $fieldsArray["shipping"]=$this->basketExtra["shipping"].": ".$this->basketExtra["shipping."]["title"];
771                 $fieldsArray["amount"]=$this->calculatedSums_tax["total"];
772                 $fieldsArray["status"]=1;       // This means, "Order confirmed on website, next step: confirm from shop that order is received"
773
774                                 // Default status_log entry
775                 $status_log=array();
776                 $status_log[] = array(
777                         "time" => time(),
778                         "info" => $this->conf["statusCodes."][$fieldsArray["status"]], 
779                         "status" => $fieldsArray["status"],
780                         "comment" => $this->deliveryInfo["note"]
781                 );
782                 $fieldsArray["status_log"]=serialize($status_log);
783
784                         // Order Data serialized 
785                 $fieldsArray["orderData"]=serialize(array(
786                                 "html_output"                   => $orderConfirmationHTML,
787                                 "deliveryInfo"                  => $this->deliveryInfo,
788                                 "personInfo"                    => $this->personInfo,
789                                 "calculatedBasket"              =>      $this->calculatedBasket,
790                                 "calculatedSum_tax"             =>      $this->calculatedSums_tax,
791                                 "calculatedSums_no_tax" =>      $this->calculatedSums_no_tax
792                 ));
793                         
794                         // Setting tstamp, deleted and tracking code
795                 $fieldsArray["tstamp"]=time();
796                 $fieldsArray["deleted"]=0;
797                 $fieldsArray["tracking_code"]=$this->recs["tt_products"]["orderTrackingNo"];
798                 
799                         // Saving the order record
800                 $query="UPDATE sys_products_orders SET ".$this->getUpdateQuery($fieldsArray)." WHERE uid=".$orderUid;
801                 $res = mysql(TYPO3_db,$query);
802                 echo mysql_error();
803
804                         // Fetching the orderRecord by selecing the newly saved one...
805                 $this->orderRecord = $this->getOrderRecord($orderUid);
806
807
808                         // Creates M-M relations for the products with tt_products table. Isn't really used yet, but later will be used to display stock-status by looking up how many items are already ordered.
809                         // First: delete any existing. Shouldn't be any
810                 $query="DELETE FROM sys_products_orders_mm_tt_products WHERE sys_products_orders_uid=".$orderUid;
811                 $res = mysql(TYPO3_db,$query);
812                 echo mysql_error();
813                         // Second: Insert a new relation for each ordered item
814                 reset($this->calculatedBasket);
815                 while(list(,$itemInfo)=each($this->calculatedBasket))   {
816 //                      debug($itemInfo);
817                         $query="INSERT INTO sys_products_orders_mm_tt_products (sys_products_orders_uid,sys_products_orders_qty,tt_products_uid) VALUES ('".$orderUid."','".intval($itemInfo["count"])."','".intval($itemInfo["rec"]["uid"])."')";
818                         $res = mysql(TYPO3_db,$query);
819                         echo mysql_error();
820                 }
821 //              debug($this->calculatedBasket);
822
823
824                         // Sends order emails:
825                 $headers=array();
826                 if ($this->conf["orderEmail_from"])     {$headers[]="FROM: ".$this->conf["orderEmail_fromName"]." <".$this->conf["orderEmail_from"].">";}
827
828                 $recipients = $this->conf["orderEmail_to"];
829                 $recipients.=",".$this->deliveryInfo["email"];
830                 $recipients=t3lib_div::trimExplode(",",$recipients,1);
831                 
832                 if (count($recipients)) {       // If any recipients, then compile and send the mail.
833                         $emailContent=trim($this->getBasket("###EMAIL_PLAINTEXT_TEMPLATE###"));
834                         if ($emailContent)      {               // If there is plain text content - which is required!!
835                                 $parts = split(chr(10),$emailContent,2);                // First line is subject
836                                 $subject=trim($parts[0]);
837                                 $plain_message=trim($parts[1]);
838
839                                 $cls  = t3lib_div::makeInstanceClassName("tt_products_htmlmail");
840                                 if (class_exists($cls) && $this->conf["orderEmail_htmlmail"])   {       // If htmlmail lib is included, then generate a nice HTML-email
841                                         $HTMLmailShell=$this->cObj->getSubpart($this->templateCode,"###EMAIL_HTML_SHELL###");
842                                         $HTMLmailContent=$this->cObj->substituteMarker($HTMLmailShell,"###HTML_BODY###",$orderConfirmationHTML);
843                                         $HTMLmailContent=$this->cObj->substituteMarkerArray($HTMLmailContent, $this->globalMarkerArray);
844                                         $V = array (
845                                                 "from_email" => $this->conf["orderEmail_from"],
846                                                 "from_name" => $this->conf["orderEmail_fromName"]
847                                         );
848                                         $Typo3_htmlmail = t3lib_div::makeInstance("tt_products_htmlmail");
849                                         $Typo3_htmlmail->useBase64();
850                                         $Typo3_htmlmail->start(implode($recipients,","), $subject, $plain_message, $HTMLmailContent, $V);
851 //echo $HTMLmailContent;
852 //                                              debug($Typo3_htmlmail->message);
853 //                                              debug($Typo3_htmlmail->recipient);
854 //                                              debug($Typo3_htmlmail->theParts);
855                                                 $Typo3_htmlmail->sendtheMail();
856
857                                                 //debug($HTMLmailContent);
858                                 } else {                // ... else just plain text...
859                                         mail (implode($recipients,","), $subject, $plain_message, implode($headers,chr(10))); 
860                                 }
861                         }
862                 }
863
864                         // Empties the shopping basket!
865                 $GLOBALS["TSFE"]->fe_user->setKey("ses","recs",$this->getClearBasketRecord());
866
867                         // This cObject may be used to call a function which clears settings in an external order system. 
868                         // The output is NOT included anywhere
869                 $this->getExternalCObject("externalFinalizing");
870         }
871
872
873
874
875
876
877         // **************************
878         // Utility functions
879         // **************************
880
881
882         /**
883          * Returns the $price with either tax or not tax, based on if $tax is true or false. This function reads the TypoScript configuration to see whether prices in the database are entered with or without tax. That's why this function is needed.
884          */
885         function getPrice($price,$tax=1)        {
886                 $taxFactor = 1+$this->TAXpercentage/100;
887                 $taxIncluded = $this->conf["TAXincluded"];
888                 if ($tax)       {
889                         if ($taxIncluded)       {       // If the configuration says that prices in the database is with tax included
890                                 return doubleval($price);
891                         } else {
892                                 return doubleval($price)*$taxFactor;
893                         }
894                 } else {
895                         if ($taxIncluded)       {       // If the configuration says that prices in the database is with tax included
896                                 return doubleval($price)/$taxFactor;
897                         } else {
898                                 return doubleval($price);
899                         }
900                 }
901         }
902
903         /**
904          * Takes an array with key/value pairs and returns it for use in an UPDATE query.
905          */
906         function getUpdateQuery($Darray)        {
907                 reset($Darray);
908                 $query=array();
909                 while(list($field,$data)=each($Darray)) {
910                         $query[]=$field."='".addslashes($data)."'";
911                 }
912                 return implode($query,",");
913         }
914
915         /**
916          * Generates a search where clause.
917          */
918         function searchWhere($sw)       {
919                 $where=$this->cObj->searchWhere($sw,$this->searchFieldList);
920                 return $where;
921         }
922
923         /**
924          * Returns a url for use in forms and links
925          */
926         function getLinkUrl($id="",$excludeList="")     {
927                 $queryString=array();
928                 $queryString["id"] = ($id ? $id : $GLOBALS["TSFE"]->id);
929                 $queryString["type"]= $GLOBALS["TSFE"]->type ? 'type='.$GLOBALS["TSFE"]->type : "";
930                 $queryString["backPID"]= 'backPID='.$GLOBALS["TSFE"]->id;
931                 $queryString["begin_at"]= t3lib_div::GPvar("begin_at") ? 'begin_at='.t3lib_div::GPvar("begin_at") : "";
932                 $queryString["swords"]= t3lib_div::GPvar("swords") ? "swords=".rawurlencode(stripslashes(t3lib_div::GPvar("swords"))) : "";
933
934                 reset($queryString);
935                 while(list($key,$val)=each($queryString))       {
936                         if (!$val || ($excludeList && t3lib_div::inList($excludeList,$key)))    {
937                                 unset($queryString[$key]);
938                         }
939                 }
940                 return $GLOBALS["TSFE"]->absRefPrefix.'index.php?'.implode($queryString,"&");
941         }
942
943         /**
944          * Formatting a price
945          */
946         function priceFormat($double)   {
947                 return number_format($double,intval($this->conf["priceDec"]),$this->conf["priceDecPoint"],$this->conf["priceThousandPoint"]);
948         }
949
950         /**
951          * Fills in all empty fields in the delivery info array
952          */
953         function mapPersonIntoToDelivery()      {
954                 $infoFields = explode(",","name,address,telephone,fax,email,company,city,zip,state,country");
955                 while(list(,$fName)=each($infoFields))  {
956                         if (!trim($this->deliveryInfo[$fName])) {
957                                 $this->deliveryInfo[$fName] = $this->personInfo[$fName];
958                         }
959                 }
960         }
961
962         /**
963          * Checks if required fields are filled in
964          */
965         function checkRequired()        {
966                 $flag=1;
967                 if (trim($this->conf["requiredInfoFields"]))    {
968                         $infoFields = t3lib_div::trimExplode(",",$this->conf["requiredInfoFields"]);
969                         while(list(,$fName)=each($infoFields))  {
970                                 if (!trim($this->personInfo[$fName]))   {
971                                         $flag=0;
972                                         break;
973                                 }
974                         }
975                 }
976                 return $flag;
977         }
978
979         /**
980          * Include calculation script which should be programmed to manipulate internal data.
981          */
982         function includeCalcScript($calcScript,$conf)   {
983                 include($calcScript);
984         }
985
986         /**
987          * Include handle script
988          */
989         function includeHandleScript($handleScript,$conf)       {
990                 include($handleScript);
991                 return $content;
992         }
993
994
995
996
997
998
999
1000         // **************************
1001         // Template marker substitution
1002         // **************************
1003
1004         /**
1005          * Fills in the markerArray with data for a product
1006          */
1007         function getItemMarkerArray ($row,$catTitle, $imageNum=0, $imageRenderObj="image")      {
1008                         // Returns a markerArray ready for substitution with information for the tt_producst record, $row
1009                 $markerArray=array();
1010                         // Get image
1011                 $theImgCode="";
1012                 $imgs = explode(",",$row["image"]);
1013                 $val = $imgs[0];
1014                 while(list($c,$val)=each($imgs))        {
1015                         if ($c==$imageNum)      break;
1016                         if ($val)       {
1017                                 $this->conf[$imageRenderObj."."]["file"] = "uploads/pics/".$val;
1018                         } else {
1019                                 $this->conf[$imageRenderObj."."]["file"] = $this->conf["noImageAvailable"];
1020                         }
1021                         $theImgCode.=$this->cObj->IMAGE($this->conf[$imageRenderObj."."]);
1022                 }
1023                         // Subst. fields
1024                 $markerArray["###PRODUCT_TITLE###"] = $row["title"];
1025                 $markerArray["###PRODUCT_NOTE###"] = nl2br($row["note"]);
1026                 if (is_array($this->conf["parseFunc."]))        {
1027                         $markerArray["###PRODUCT_NOTE###"] = $this->cObj->parseFunc($markerArray["###PRODUCT_NOTE###"],$this->conf["parseFunc."]);
1028                 }
1029                 $markerArray["###PRODUCT_ITEMNUMBER###"] = $row["itemnumber"];
1030                 $markerArray["###PRODUCT_IMAGE###"] = $theImgCode;
1031                 $markerArray["###PRICE_TAX###"] = $this->priceFormat($this->getPrice($row["price"]));
1032                 $markerArray["###PRICE_NO_TAX###"] = $this->priceFormat($this->getPrice($row["price"],0));
1033                 $markerArray["###PRODUCT_INSTOCK###"] = $row["inStock"];
1034
1035                 $markerArray["###CATEGORY_TITLE###"] = $catTitle;
1036                 
1037                 $markerArray["###FIELD_NAME###"]="recs[tt_products][".$row["uid"]."]";
1038                 $markerArray["###FIELD_QTY###"]= $this->basket[$row["uid"]] ? $this->basket[$row["uid"]] : "";
1039                 
1040                 if ($this->conf["itemMarkerArrayFunc"]) {
1041                         $markerArray = $this->userProcess("itemMarkerArrayFunc",$markerArray);
1042                 }
1043
1044                 return $markerArray;
1045         }
1046
1047         /**
1048          * Calls user function
1049          */
1050         function userProcess($mConfKey,$passVar)        {
1051                 if ($this->conf[$mConfKey])     {
1052                         $funcConf = $this->conf[$mConfKey."."];
1053                         $funcConf["parentObj"]=&$this;
1054                         $passVar = $GLOBALS["TSFE"]->cObj->callUserFunction($this->conf[$mConfKey], $funcConf, $passVar);
1055                 }
1056                 return $passVar;
1057         }
1058
1059         /**
1060          * Adds URL markers to a markerArray
1061          */
1062         function addURLMarkers($markerArray)    {
1063                         // Add's URL-markers to the $markerArray and returns it
1064                 $markerArray["###FORM_URL###"] = $this->getLinkUrl($this->conf["PIDbasket"]);
1065                 $markerArray["###FORM_URL_INFO###"] = $this->getLinkUrl($this->conf["PIDinfo"] ? $this->conf["PIDinfo"] : $this->conf["PIDbasket"]);
1066                 $markerArray["###FORM_URL_FINALIZE###"] = $this->getLinkUrl($this->conf["PIDfinalize"] ? $this->conf["PIDfinalize"] : $this->conf["PIDbasket"]);
1067                 $markerArray["###FORM_URL_THANKS###"] = $this->getLinkUrl($this->conf["PIDthanks"] ? $this->conf["PIDthanks"] : $this->conf["PIDbasket"]);
1068                 $markerArray["###FORM_URL_TARGET###"] = "_self";
1069 //              debug($this->basketExtra["payment."]);
1070                 if ($this->basketExtra["payment."]["handleURL"])        {       // This handleURL is called instead of the THANKS-url in order to let handleScript process the information if payment by credit card or so.
1071                         $markerArray["###FORM_URL_THANKS###"] = $this->basketExtra["payment."]["handleURL"];
1072                 }
1073                 if ($this->basketExtra["payment."]["handleTarget"])     {       // Alternative target
1074                         $markerArray["###FORM_URL_TARGET###"] = $this->basketExtra["payment."]["handleTarget"];
1075                 }
1076                 return $markerArray;
1077         }
1078
1079         /**
1080          * Generates a radio or selector box for payment shipping
1081          */
1082         function generateRadioSelect($key)      {
1083                         /*
1084                          The conf-array for the payment/shipping configuration has numeric keys for the elements
1085                          But there are also these properties:
1086
1087                                 .radio          [boolean]       Enables radiobuttons instead of the default, selector-boxes
1088                                 .wrap           [string]        <select>|</select> - wrap for the selectorboxes.  Only if .radio is false. See default value below
1089                                 .template       [string]        Template string for the display of radiobuttons.  Only if .radio is true. See default below
1090                          
1091                          */
1092                 $type=$this->conf[$key."."]["radio"];
1093                 $active = $this->basketExtra[$key];
1094                 $confArr = $this->cleanConfArr($this->conf[$key."."]);
1095                 $out="";
1096
1097                 $template = $this->conf[$key."."]["template"] ? $this->conf[$key."."]["template"] : '<nobr>###IMAGE### <input type="radio" name="recs[tt_products]['.$key.']" onClick="submit()" value="###VALUE###"###CHECKED###> ###TITLE###</nobr><BR>';
1098                 $wrap = $this->conf[$key."."]["wrap"] ? $this->conf[$key."."]["wrap"] :'<select name="recs[tt_products]['.$key.']" onChange="submit()">|</select>';
1099                 
1100                 while(list($key,$val)=each($confArr))   {
1101                         if ($val["show"] || !isset($val["show"]))       {
1102                                 if ($type)      {       // radio
1103                                         $markerArray=array();
1104                                         $markerArray["###VALUE###"]=intval($key);
1105                                         $markerArray["###CHECKED###"]=(intval($key)==$active?" checked":"");
1106                                         $markerArray["###TITLE###"]=$val["title"];
1107                                         $markerArray["###IMAGE###"]=$this->cObj->IMAGE($val["image."]);
1108                                         $out.=$this->cObj->substituteMarkerArrayCached($template, $markerArray);
1109                                 } else {
1110                                         $out.='<option value="'.intval($key).'"'.(intval($key)==$active?" selected":"").'>'.htmlspecialchars($val["title"]).'</option>';
1111                                 }
1112                         }
1113                 }
1114                 if (!$type)     {
1115                         $out=$this->cObj->wrap($out,$wrap);
1116                 }
1117                 return $out;
1118         }
1119         function cleanConfArr($confArr,$checkShow=0)    {
1120                 $outArr=array();
1121                 if (is_array($confArr)) {
1122                         reset($confArr);
1123                         while(list($key,$val)=each($confArr))   {
1124                                 if (!t3lib_div::testInt($key) && intval($key) && is_array($val) && (!$checkShow || $val["show"] || !isset($val["show"])))       {
1125                                         $outArr[intval($key)]=$val;
1126                                 }
1127                         }
1128                 }
1129                 ksort($outArr);
1130                 reset($outArr);
1131                 return $outArr;
1132         }
1133         /**
1134          * This generates the shopping basket layout and also calculates the totals. Very important function.
1135          */
1136         function getBasket($subpartMarker="###BASKET_TEMPLATE###", $templateCode="", $mainMarkerArray=array())  {
1137                         /*
1138                                 Very central function in the library.
1139                                 By default it extracts the subpart, ###BASKET_TEMPLATE###, from the $templateCode (if given, else the default $this->templateCode)
1140                                 and substitutes a lot of fields and subparts. 
1141                                 Any pre-preparred fields can be set in $mainMarkerArray, which is substituted in the subpart before the item-and-categories part is substituted.
1142                                 
1143                                 This function also calculates the internal arrays 
1144                                 
1145                                 $this->calculatedBasket         - The basked elements, how many (quantity, count) and the price and total
1146                                 $this->calculatedSums_tax               - Sums of goods, shipping, payment and total amount WITH TAX included
1147                                 $this->calculatedSums_no_tax    - Sums of goods, shipping, payment and total amount WITHOUT TAX
1148                                 
1149                                 ... which holds the total amount, the final list of products and the price of payment and shipping!!
1150                                 
1151                         */
1152         
1153                 $templateCode = $templateCode ? $templateCode : $this->templateCode;
1154                 $this->calculatedBasket=array();                // array that holds the final list of items, shipping and payment + total amounts
1155                 
1156                         // Get the products from the uid_list (initialized by the initBasket function)
1157                 $query = "SELECT * FROM tt_products WHERE uid IN (".$this->uid_list.") AND pid IN (".$this->pid_list.")".$this->cObj->enableFields("tt_products");
1158                 $res = mysql(TYPO3_db,$query);
1159                 echo mysql_error();
1160                 $productsArray=array();
1161                 while($row=mysql_fetch_assoc($res))             {
1162                         $productsArray[$row["pid"]][]=$row;             // Fills this array with the product records. Reason: Sorting them by category (based on the page, they reside on)
1163                 }
1164                 
1165
1166                         // Getting subparts from the template code.
1167                 $t=array();
1168                         // If there is a specific section for the billing address if user is logged in (used because the address may then be hardcoded from the database
1169                 $t["basketFrameWork"] = $this->cObj->getSubpart($templateCode,$this->spMarker($subpartMarker));
1170                 if (trim($this->cObj->getSubpart($t["basketFrameWork"],"###BILLING_ADDRESS_LOGIN###"))) {
1171                         if ($GLOBALS["TSFE"]->loginUser)        {
1172                                 $t["basketFrameWork"]=$this->cObj->substituteSubpart($t["basketFrameWork"], "###BILLING_ADDRESS###", "");
1173                         } else {
1174                                 $t["basketFrameWork"]=$this->cObj->substituteSubpart($t["basketFrameWork"], "###BILLING_ADDRESS_LOGIN###", "");
1175                         }
1176                 }
1177                 
1178                 $t["categoryTitle"] = $this->cObj->getSubpart($t["basketFrameWork"],"###ITEM_CATEGORY###");
1179                 $t["itemFrameWork"] = $this->cObj->getSubpart($t["basketFrameWork"],"###ITEM_LIST###");
1180                 $t["item"] = $this->cObj->getSubpart($t["itemFrameWork"],"###ITEM_SINGLE###");
1181
1182                 $pageArr=explode(",",$this->pid_list);
1183                 $currentP="";
1184                 $out="";
1185
1186                         // Initialize traversing the items in the basket
1187                 $this->calculatedSums_tax=array();
1188                 $this->calculatedSums_no_tax=array();
1189
1190                 while(list(,$v)=each($pageArr)) {
1191                         if (is_array($productsArray[$v]))       {
1192                                 reset($productsArray[$v]);
1193                                 $itemsOut="";
1194                                 while(list(,$row)=each($productsArray[$v]))     {
1195                                                 // Print Category Title
1196                                         if ($row["pid"]."_".$row["category"]!=$currentP)        {
1197                                                 if ($itemsOut)  {
1198                                                         $out.=$this->cObj->substituteSubpart($t["itemFrameWork"], "###ITEM_SINGLE###", $itemsOut);
1199                                                 }
1200                                                 $itemsOut="";                   // Clear the item-code var
1201                                                 $currentP = $row["pid"]."_".$row["category"];
1202                                                 if ($this->conf["displayBasketCatHeader"])      {
1203                                                         $markerArray=array();
1204                                                         $catTitle= $this->pageArray[$row["pid"]]["title"].($row["category"]?"/".$this->categories[$row["category"]]:"");
1205                                                         $this->cObj->setCurrentVal($catTitle);
1206                                                         $markerArray["###CATEGORY_TITLE###"]=$this->cObj->cObjGetSingle($this->conf["categoryHeader"],$this->conf["categoryHeader."], "categoryHeader");
1207                                                         $out.= $this->cObj->substituteMarkerArray($t["categoryTitle"], $markerArray);
1208                                                 }
1209                                         }
1210
1211                                                 // Fill marker arrays
1212                                         $wrappedSubpartArray=array();
1213                                         $markerArray = $this->getItemMarkerArray ($row,$catTitle,1,"basketImage");
1214
1215                                         $calculatedBasketItem = array(
1216                                                 "priceTax" => $this->getPrice($row["price"]),
1217                                                 "priceNoTax" => $this->getPrice($row["price"],0),
1218                                                 "count" => intval($this->basket[$row["uid"]]),
1219                                                 "rec" => $row
1220                                         );
1221                                         $calculatedBasketItem["totalTax"] = $calculatedBasketItem["priceTax"]*$calculatedBasketItem["count"];
1222                                         $calculatedBasketItem["totalNoTax"] = $calculatedBasketItem["priceNoTax"]*$calculatedBasketItem["count"];
1223                                         $markerArray["###PRICE_TOTAL_TAX###"]=$this->priceFormat($calculatedBasketItem["totalTax"]);
1224                                         $markerArray["###PRICE_TOTAL_NO_TAX###"]=$this->priceFormat($calculatedBasketItem["totalNoTax"]);
1225
1226                                         $wrappedSubpartArray["###LINK_ITEM###"]=array('<A href="'.$this->getLinkUrl($this->conf["PIDitemDisplay"]).'&tt_products='.$row["uid"].'">','</A>');
1227                                                 // Substitute
1228                                         $itemsOut.= $this->cObj->substituteMarkerArrayCached($t["item"],$markerArray,array(),$wrappedSubpartArray);
1229
1230                                         $this->calculatedSums_tax["goodstotal"]+= $calculatedBasketItem["totalTax"];
1231                                         $this->calculatedSums_no_tax["goodstotal"]+= $calculatedBasketItem["totalNoTax"];
1232                                         $this->calculatedBasket[] = $calculatedBasketItem;
1233                                 }
1234                                 if ($itemsOut)  {
1235                                         $out.=$this->cObj->substituteSubpart($t["itemFrameWork"], "###ITEM_SINGLE###", $itemsOut);
1236                                 }
1237                         }
1238                 }
1239                 
1240                         // Initializing the markerArray for the rest of the template
1241                 $markerArray=$mainMarkerArray;
1242
1243                         // This is the total for the goods in the basket.
1244                 $markerArray["###PRICE_GOODSTOTAL_TAX###"] = $this->priceFormat($this->calculatedSums_tax["goodstotal"]);
1245                 $markerArray["###PRICE_GOODSTOTAL_NO_TAX###"] = $this->priceFormat($this->calculatedSums_no_tax["goodstotal"]);
1246
1247
1248                         // Shipping
1249                 $this->calculatedSums_tax["shipping"]=doubleVal($this->basketExtra["shipping."]["priceTax"]);
1250                 $this->calculatedSums_no_tax["shipping"]=doubleVal($this->basketExtra["shipping."]["priceNoTax"]);
1251                 $perc = doubleVal($this->basketExtra["shipping."]["percentOfGoodstotal"]);
1252                 if ($perc)      {
1253                         $this->calculatedSums_tax["shipping"]+= $this->calculatedSums_tax["goodstotal"]/100*$perc;
1254                         $this->calculatedSums_no_tax["shipping"]+= $this->calculatedSums_no_tax["goodstotal"]/100*$perc;
1255                 }
1256                 if ($this->basketExtra["shipping."]["calculationScript"])       {
1257                         $calcScript = $GLOBALS["TSFE"]->tmpl->getFileName($this->basketExtra["shipping."]["calculationScript"]);
1258                         if ($calcScript)        {
1259                                 $this->includeCalcScript($calcScript,$this->basketExtra["shipping."]["calculationScript."]);
1260                         }
1261                 }
1262
1263                 $markerArray["###PRICE_SHIPPING_PERCENT###"] = $perc;
1264                 $markerArray["###PRICE_SHIPPING_TAX###"] = $this->priceFormat($this->calculatedSums_tax["shipping"]);
1265                 $markerArray["###PRICE_SHIPPING_NO_TAX###"] = $this->priceFormat($this->calculatedSums_no_tax["shipping"]);
1266
1267                 $markerArray["###SHIPPING_SELECTOR###"] = $this->generateRadioSelect("shipping");
1268                 $markerArray["###SHIPPING_IMAGE###"] = $this->cObj->IMAGE($this->basketExtra["shipping."]["image."]);
1269                 $markerArray["###SHIPPING_TITLE###"] = $this->basketExtra["shipping."]["title"];
1270                 
1271
1272                         // Payment      
1273                 $this->calculatedSums_tax["payment"]=doubleVal($this->basketExtra["payment."]["priceTax"]);
1274                 $this->calculatedSums_no_tax["payment"]=doubleVal($this->basketExtra["payment."]["priceNoTax"]);
1275                 $perc = doubleVal($this->basketExtra["payment."]["percentOfGoodstotal"]);
1276                 if ($perc)      {
1277                         $this->calculatedSums_tax["payment"]+= $this->calculatedSums_tax["goodstotal"]/100*$perc;
1278                         $this->calculatedSums_no_tax["payment"]+= $this->calculatedSums_no_tax["goodstotal"]/100*$perc;
1279                 }
1280                 if ($this->basketExtra["payment."]["calculationScript"])        {
1281                         $calcScript = $GLOBALS["TSFE"]->tmpl->getFileName($this->basketExtra["payment."]["calculationScript"]);
1282                         if ($calcScript)        {
1283                                 $this->includeCalcScript($calcScript,$this->basketExtra["payment."]["calculationScript."]);
1284                         }
1285                 }
1286
1287                 $markerArray["###PRICE_PAYMENT_PERCENT###"] = $perc;
1288                 $markerArray["###PRICE_PAYMENT_TAX###"] = $this->priceFormat($this->calculatedSums_tax["payment"]);
1289                 $markerArray["###PRICE_PAYMENT_NO_TAX###"] = $this->priceFormat($this->calculatedSums_no_tax["payment"]);
1290
1291                 $markerArray["###PAYMENT_SELECTOR###"] = $this->generateRadioSelect("payment");
1292                 $markerArray["###PAYMENT_IMAGE###"] = $this->cObj->IMAGE($this->basketExtra["payment."]["image."]);
1293                 $markerArray["###PAYMENT_TITLE###"] = $this->basketExtra["payment."]["title"];
1294
1295
1296                         // This is the total for everything
1297                 $this->calculatedSums_tax["total"] = $this->calculatedSums_tax["goodstotal"];
1298                 $this->calculatedSums_tax["total"]+= $this->calculatedSums_tax["payment"];
1299                 $this->calculatedSums_tax["total"]+= $this->calculatedSums_tax["shipping"];
1300                 
1301                 $this->calculatedSums_no_tax["total"] = $this->calculatedSums_no_tax["goodstotal"];
1302                 $this->calculatedSums_no_tax["total"]+= $this->calculatedSums_no_tax["payment"];
1303                 $this->calculatedSums_no_tax["total"]+= $this->calculatedSums_no_tax["shipping"];
1304
1305                 $markerArray["###PRICE_TOTAL_TAX###"] = $this->priceFormat($this->calculatedSums_tax["total"]);
1306                 $markerArray["###PRICE_TOTAL_NO_TAX###"] = $this->priceFormat($this->calculatedSums_no_tax["total"]);
1307                 
1308
1309                         // Personal and delivery info:
1310                 $infoFields = explode(",","name,address,telephone,fax,email,company,city,zip,state,country");           // Fields...
1311                 while(list(,$fName)=each($infoFields))  {
1312                         $markerArray["###PERSON_".strtoupper($fName)."###"] = $this->personInfo[$fName];
1313                         $markerArray["###DELIVERY_".strtoupper($fName)."###"] = $this->deliveryInfo[$fName];
1314                 }
1315                         // Markers for use if you want to output line-broken address information
1316                 $markerArray["###PERSON_ADDRESS_DISPLAY###"] = nl2br($markerArray["###PERSON_ADDRESS###"]);
1317                 $markerArray["###DELIVERY_ADDRESS_DISPLAY###"] = nl2br($markerArray["###DELIVERY_ADDRESS###"]);
1318                         // Delivery note.
1319                 $markerArray["###DELIVERY_NOTE###"] = $this->deliveryInfo["note"];
1320                 $markerArray["###DELIVERY_NOTE_DISPLAY###"] = nl2br($markerArray["###DELIVERY_NOTE###"]);
1321
1322                 
1323                         // Order:       NOTE: Data exist only if the getBlankOrderUid() has been called. Therefore this field in the template should be used only when an order has been established
1324                 $markerArray["###ORDER_UID###"] = $this->getOrderNumber($this->recs["tt_products"]["orderUid"]);
1325                 $markerArray["###ORDER_DATE###"] = $this->cObj->stdWrap($this->recs["tt_products"]["orderDate"],$this->conf["orderDate_stdWrap."]);
1326                 $markerArray["###ORDER_TRACKING_NO###"] = $this->recs["tt_products"]["orderTrackingNo"];
1327
1328                         // Fe users:
1329                 $markerArray["###FE_USER_USERNAME###"] = $GLOBALS["TSFE"]->fe_user->user["username"];
1330                 $markerArray["###FE_USER_UID###"] = $GLOBALS["TSFE"]->fe_user->user["uid"];
1331                 
1332                         // URL
1333                 $markerArray = $this->addURLMarkers($markerArray);
1334                 $subpartArray = array();
1335                 $wrappedSubpartArray = array();
1336
1337                         // Final substitution:
1338                 if (!$GLOBALS["TSFE"]->loginUser)       {               // Remove section for FE_USERs only, if there are no fe_user
1339                         $subpartArray["###FE_USER_SECTION###"]="";
1340                 }
1341                 $bFrameWork = $t["basketFrameWork"];
1342 //              debug(array($bFrameWork));
1343 //              debug($this->basketExtra["payment"]);
1344                 $subpartArray["###MESSAGE_SHIPPING###"] = $this->cObj->substituteMarkerArrayCached($this->cObj->getSubpart($bFrameWork,"###MESSAGE_SHIPPING_".$this->basketExtra["shipping"]."###"),$markerArray);
1345                 $subpartArray["###MESSAGE_PAYMENT###"] = $this->cObj->substituteMarkerArrayCached($this->cObj->getSubpart($bFrameWork,"###MESSAGE_PAYMENT_".$this->basketExtra["payment"]."###"),$markerArray);
1346                 
1347                 $bFrameWork=$this->cObj->substituteMarkerArrayCached($t["basketFrameWork"],$markerArray,$subpartArray,$wrappedSubpartArray);
1348                         
1349                         // substitute the main subpart with the rendered content.
1350                 $out=$this->cObj->substituteSubpart($bFrameWork, "###ITEM_CATEGORY_AND_ITEMS###", $out);
1351                 return $out;
1352         }
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362         // **************************
1363         // tracking information
1364         // **************************
1365
1366         /**
1367          * Returns 1 if user is a shop admin
1368          */
1369         function shopAdmin()    {
1370                 $admin=0;
1371                 if ($GLOBALS["TSFE"]->beUserLogin)      {
1372                         if (t3lib_div::GPvar("update_code")==$this->conf["update_code"])        {
1373                                 $admin= 1;              // Means that the administrator of the website is authenticated.
1374                         }
1375                 }
1376                 return $admin;
1377         }
1378         
1379         /**
1380          * Tracking administration
1381          */
1382         function getTrackingInformation($orderRow, $templateCode)       {
1383                         /*
1384                         
1385                         
1386                         
1387                                         Tracking information display and maintenance.
1388                                         
1389                                         status-values are 
1390                                         0:      Blank order
1391                                         1:      Order confirmed at website
1392                                         ...
1393                                         50-59:  User messages, may be updated by the ordinary users.
1394                                         100-:   Order finalized.
1395                         
1396                         
1397                                         All status values can be altered only if you're logged in as a BE-user and if you know the correct code (setup as .update_code in TypoScript config)
1398                         */
1399         
1400                 $admin = $this->shopAdmin();
1401
1402                 if ($orderRow["uid"])   {
1403                                 // Initialize update of status...
1404                         $fieldsArray = array();
1405                         $orderRecord = t3lib_div::GPvar("orderRecord");
1406                         if (isset($orderRecord["email_notify"]))        {
1407                                 $fieldsArray["email_notify"]=$orderRecord["email_notify"];
1408                                 $orderRow["email_notify"] = $fieldsArray["email_notify"];
1409                         }
1410                         if (isset($orderRecord["email"]))       {
1411                                 $fieldsArray["email"]=$orderRecord["email"];
1412                                 $orderRow["email"] = $fieldsArray["email"];
1413                         }
1414         
1415                         if (is_array($orderRecord["status"]))   {
1416                                 $status_log = unserialize($orderRow["status_log"]);
1417                                 reset($orderRecord["status"]);
1418                                 $update=0;
1419                                 while(list(,$val)=each($orderRecord["status"])) {
1420                                         if ($admin || ($val>=50 && $val<59))    {// Numbers 50-59 are usermessages.
1421                                                 $status_log_element = array(
1422                                                         "time" => time(),
1423                                                         "info" => $this->conf["statusCodes."][$val], 
1424                                                         "status" => $val,
1425                                                         "comment" => stripslashes($orderRecord["status_comment"])
1426                                                 );
1427                                                 if ($orderRow["email"] && $orderRow["email_notify"])    {
1428                                                         $this->sendNotifyEmail($orderRow["email"], $status_log_element, t3lib_div::GPvar("tracking"), $this->getOrderNumber($orderRow["uid"]),$templateCode);
1429                                                 }
1430                                                 $status_log[] = $status_log_element;
1431                                                 $update=1;
1432                                         }
1433                                 }
1434                                 if ($update)    {
1435                                         $fieldsArray["status_log"]=serialize($status_log);
1436                                         $fieldsArray["status"]=$status_log_element["status"];
1437                                         if ($fieldsArray["status"] >= 100)      {
1438                                                         // Deletes any M-M relations between the tt_products table and the order. 
1439                                                         // In the future this should maybe also automatically count down the stock number of the product records. Else it doesn't make sense.
1440                                                 $query="DELETE FROM sys_products_orders_mm_tt_products WHERE sys_products_orders_uid=".$orderRow["uid"];
1441                                                 $res = mysql(TYPO3_db,$query);
1442                                                 echo mysql_error();
1443                                         }
1444                                 }
1445         //                              debug($fieldsArray);
1446                         }
1447                         
1448                         if (count($fieldsArray))        {               // If any items in the field array, save them
1449                                 $fieldsArray["tstamp"]=time();
1450                                 $query="UPDATE sys_products_orders SET ".$this->getUpdateQuery($fieldsArray)." WHERE uid=".$orderRow["uid"];
1451         //                      debug($query);
1452                                 $res = mysql(TYPO3_db,$query);
1453                                 echo mysql_error();
1454                                 $orderRow = $this->getOrderRecord($orderRow["uid"]);
1455                         }
1456                 }
1457         
1458
1459
1460
1461                         // Getting the template stuff and initialize order data.
1462                 $content=$this->cObj->getSubpart($templateCode,"###TRACKING_DISPLAY_INFO###");
1463                 $status_log = unserialize($orderRow["status_log"]);
1464                 $orderData = unserialize($orderRow["orderData"]);
1465
1466                         // Status:
1467                 $STATUS_ITEM=$this->cObj->getSubpart($content,"###STATUS_ITEM###");
1468                 $STATUS_ITEM_c="";
1469                 if (is_array($status_log))      {
1470                         reset($status_log);
1471                         while(list($k,$v)=each($status_log))    {
1472                                 $markerArray=Array();
1473                                 $markerArray["###ORDER_STATUS_TIME###"]=$this->cObj->stdWrap($v["time"],$this->conf["statusDate_stdWrap."]);
1474                                 $markerArray["###ORDER_STATUS###"]=$v["status"];
1475                                 $markerArray["###ORDER_STATUS_INFO###"]=$v["info"];
1476                                 $markerArray["###ORDER_STATUS_COMMENT###"]=nl2br($v["comment"]);
1477                                 
1478                                 $STATUS_ITEM_c.=$this->cObj->substituteMarkerArrayCached($STATUS_ITEM, $markerArray);
1479                         }
1480                 }
1481
1482                 $subpartArray=array();
1483                 $subpartArray["###STATUS_ITEM###"]=$STATUS_ITEM_c;
1484
1485                 
1486                 
1487                 
1488                 $markerArray=Array();
1489
1490                         // Display admin-interface if access.
1491                 if (!$GLOBALS["TSFE"]->beUserLogin)     {
1492                         $subpartArray["###ADMIN_CONTROL###"]="";
1493                 } elseif ($admin) {
1494                         $subpartArray["###ADMIN_CONTROL_DENY###"]="";
1495                 } else {
1496                         $subpartArray["###ADMIN_CONTROL_OK###"]="";
1497                 }
1498                 if ($GLOBALS["TSFE"]->beUserLogin)      {
1499                                 // Status admin:
1500                         if (is_array($this->conf["statusCodes."]))      {
1501                                 reset($this->conf["statusCodes."]);
1502                                 while(list($k,$v)=each($this->conf["statusCodes."]))    {
1503                                         if ($k!=1)      {
1504                                                 $markerArray["###STATUS_OPTIONS###"].='<option value="'.$k.'">'.htmlspecialchars($k.": ".$v).'</option>';
1505                                         }
1506                                 }
1507                         }
1508         
1509                                 // Get unprocessed orders.
1510                         $query="SELECT uid,name,tracking_code,amount from sys_products_orders WHERE NOT deleted AND status!=0 AND status<100 ORDER BY crdate";
1511                         $res = mysql(TYPO3_db,$query);
1512                         echo mysql_error();
1513                         while($row=mysql_fetch_assoc($res))     {
1514                                 $markerArray["###OTHER_ORDERS_OPTIONS###"].='<option value="'.$row["tracking_code"].'">'.htmlspecialchars($this->getOrderNumber($row["uid"]).": ".$row["name"]." (".$this->priceFormat($row["amount"])." ".$this->conf["currencySymbol"].")").'</option>';
1515                         }
1516                 }               
1517
1518                 
1519                         // Final things
1520                 $markerArray["###ORDER_HTML_OUTPUT###"] = $orderData["html_output"];            // The save order-information in HTML-format
1521                 $markerArray["###FIELD_EMAIL_NOTIFY###"] = $orderRow["email_notify"] ? " checked" : "";
1522                 $markerArray["###FIELD_EMAIL###"] = $orderRow["email"];
1523                 $markerArray["###ORDER_UID###"] = $this->getOrderNumber($orderRow["uid"]);
1524                 $markerArray["###ORDER_DATE###"] = $this->cObj->stdWrap($orderRow["crdate"],$this->conf["orderDate_stdWrap."]);
1525                 $markerArray["###TRACKING_NUMBER###"] = t3lib_div::GPvar("tracking");
1526                 $markerArray["###UPDATE_CODE###"] = t3lib_div::GPvar("update_code");
1527                 
1528                 $content= $this->cObj->substituteMarkerArrayCached($content, $markerArray, $subpartArray);
1529                 return $content;
1530         }
1531
1532         /**
1533          * Send notification email for tracking
1534          */
1535         function sendNotifyEmail($recipient, $v, $tracking, $uid, $templateCode)        {
1536                         // Notification email
1537                 $headers=array();
1538                 if ($this->conf["orderEmail_from"])     {$headers[]="FROM: ".$this->conf["orderEmail_fromName"]." <".$this->conf["orderEmail_from"].">";}
1539
1540                 $recipients = $recipient;
1541                 $recipients=t3lib_div::trimExplode(",",$recipients,1);
1542                 
1543                 if (count($recipients)) {       // If any recipients, then compile and send the mail.
1544                         $emailContent=trim($this->cObj->getSubpart($templateCode,"###TRACKING_EMAILNOTIFY_TEMPLATE###"));
1545                         if ($emailContent)      {               // If there is plain text content - which is required!!
1546
1547                                 $markerArray["###ORDER_STATUS_TIME###"]=$this->cObj->stdWrap($v["time"],$this->conf["statusDate_stdWrap."]);
1548                                 $markerArray["###ORDER_STATUS###"]=$v["status"];
1549                                 $markerArray["###ORDER_STATUS_INFO###"]=$v["info"];
1550                                 $markerArray["###ORDER_STATUS_COMMENT###"]=$v["comment"];
1551                                 
1552                                 $markerArray["###ORDER_TRACKING_NO###"]=$tracking;
1553                                 $markerArray["###ORDER_UID###"]=$uid;
1554                                 
1555                                 $emailContent=$this->cObj->substituteMarkerArrayCached($emailContent, $markerArray);
1556
1557                                 $parts = split(chr(10),$emailContent,2);
1558                                 $subject=trim($parts[0]);
1559                                 $plain_message=trim($parts[1]);
1560 //                              debug(array($plain_message));
1561
1562                                 mail (implode($recipients,","), $subject, $plain_message, implode($headers,chr(10)));
1563 //                              debug($recipients);
1564                         }
1565                 }
1566         }
1567 }
1568
1569
1570
1571 if (defined("TYPO3_MODE") && $TYPO3_CONF_VARS[TYPO3_MODE]["XCLASS"]["media/scripts/productsLib.inc"])   {
1572         include_once($TYPO3_CONF_VARS[TYPO3_MODE]["XCLASS"]["media/scripts/productsLib.inc"]);
1573 }
1574
1575
1576 ?>