00001 #include "page_control.hpp"
00002 #include "ocTypes.h"
00003 #include "cgiCookie.h"
00004 #include "ocXML.h"
00005 #include "Customer_ui.h"
00006 #include "pay_form.hpp"
00007 #include "Order.hpp"
00008 #include "shoppingCart.hpp"
00009 #include "lookup.hpp"
00010 #include "oc_Mail.h"
00011 #include "proofs.hpp"
00012 #include "../admin/ItemDetail.hpp"
00013 #include "../admin/Manufacturer.hpp"
00014 #include "../admin/Promotion.hpp"
00015 #include "Session.hpp"
00016
00017 #include <sstream>
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027 static char * mailPath = "127.0.0.1";
00028
00029 typedef map <long long, int> pnodecounts;
00030 class virtualCheckout : public read_base
00031 {
00032 protected:
00033 ocString productSQL, keySQL;
00034 string sql;
00035 string m_result;
00036
00037 Ordered_Obj odr;
00038 Product_Obj product;
00039
00040 public:
00041
00042 ocString prodHead;
00043 ocString prodList;
00044 ocString prodFoot;
00045 ocString prodBuy;
00046 ocString cfrmHead;
00047 ocString cfrmList;
00048 ocString cfrmFoot;
00049
00050 ocString cfrmHeading;
00051 ocString cfrmListItem;
00052 ocString cfrmSubmit;
00053
00054
00055 ocString finiThanks;
00056
00057
00058 ocString finiError;
00059
00060
00061 ocString mailCustomer;
00062
00063
00064 ocString mailManufacturer;
00065
00066
00067 string mailMfrAddr;
00068
00069
00070 string mailFrom;
00071
00072
00073 ocString mailStoreClerk;
00074
00075 cgiScript & script;
00076 uiShoppingCart cart;
00077
00078 double discount;
00079 bool freeShipping;
00080 llong Promotion;
00081
00082
00083
00084 virtualCheckout(cgiScript & script):read_base(),odr(),script(script),cart(script),
00085 discount(0.0),freeShipping(false),Promotion(0)
00086 {
00087 }
00088 ~virtualCheckout()
00089 {
00090 ;
00091 }
00092
00093
00094
00095
00096 void show( page & pg,
00097 string & acctTmpltName,
00098 string contentTag )
00099 {
00100
00101 bool gotProducts=false;
00102
00103 if( cart.XML.length() )
00104 {
00105 cgiInput & args = script.ClientArguments();
00106
00107
00108 if( args.count("step") == 0)
00109 {
00110 showProducts( script, prodHead, prodList, prodFoot );
00111 gotProducts=true;
00112 }
00113 else
00114 {
00115 if( args["step"] == "buy" )
00116 {
00117
00118 script << prodBuy.replace("$result$", m_result );
00119 gotProducts=true;
00120 }
00121 else if ( args["step"] == "sign-in" )
00122 {
00123
00124 if( !accountForm(script,acctTmpltName,"ChangeUser") )
00125 {
00126 script << prodBuy.replace("$result$",m_result);
00127 }
00128 gotProducts=true;
00129 }
00130 else if ( args["step"] == "new-user" )
00131 {
00132
00133 if( !accountForm(script,acctTmpltName,"AddUser") )
00134 {
00135 script << prodBuy.replace("$result$",m_result);
00136 }
00137 gotProducts=true;
00138 }
00139 else if( args["step"] == "payinfo" )
00140 {
00141
00142 paymentForm(script,acctTmpltName);
00143 gotProducts=true;
00144 }
00145 else if( args["step"] == "verify" )
00146 {
00147
00148 confirmOrderPanel(script,acctTmpltName);
00149 gotProducts=true;
00150 }
00151 else if( args["step"] == "confirmed" )
00152 {
00153
00154 createOrderPanel(script,acctTmpltName);
00155 gotProducts=true;
00156 }
00157 }
00158 }
00159 if( !gotProducts )
00160 {
00161 pg.emitContent( contentTag, "$content" );
00162 }
00163 }
00164
00165 bool accountForm( cgiScript & script, string & formTemplate, string Action )
00166 {
00167 bool bRet = false;
00168 Customer_form customer(script);
00169 customer.loadControlTemplates(formTemplate);
00170
00171 if( Action == "ChangeUser" )
00172 {
00173 if( !setKey(script,customer) )
00174 {
00175 m_result = "We could not find your login in our system!";
00176 return bRet;
00177 }
00178 }
00179
00180
00181 customer.form_action();
00182
00183 if( Action == "AddUser" && !customer.ivalidate() )
00184 {
00185 m_result = customer.last_result();
00186 return bRet;
00187 }
00188
00189
00190 bRet = true;
00191
00192 if( Action == "AddUser" )
00193 {
00194 script << customer.makeTop( "?step=payinfo", "Customer Information" ) ;
00195 }
00196 else
00197 {
00198 script << customer.makeTop( "?step=payinfo", "Account Verification" ) ;
00199 }
00200 customer.form_display();
00201
00202 script << customer.makeButtonedBottom( Action ) ;
00203
00204 return bRet;
00205 }
00206
00207 bool setKey(cgiScript & script, read_write_base & obj )
00208 {
00209 bool bret=false;
00210 cgiInput & args = script.ClientArguments();
00211 sql = keySQL.replace("$Email",args["EMail"].c_str()).replace("$Password",args["Password"].c_str());
00212 if( rs.open(sql) )
00213 {
00214 obj.key(atoll(rs.getField(0).format().c_str()));
00215 rs.close();
00216 bret = true;
00217 }
00218 return bret;
00219 }
00220
00221 void paymentForm( cgiScript & script, string & formTemplate )
00222 {
00223 Payment_Form pay(script);
00224 pay.loadControlTemplates(formTemplate);
00225
00226
00227
00228
00229 Customer_form customer(script);
00230
00231 bool isInserting = customer.getMode()=="i";
00232 string Action = isInserting?"Insert":"Update";
00233
00234 cgiInput & args = script.ClientArguments();
00235 ocString customer_Id = args["customer_Id"].c_str();
00236 string Login = args["EMail"].c_str();
00237
00238 bool isCustomerOK = customer.form_action();
00239
00240 if( isCustomerOK == false )
00241 {
00242
00243
00244
00245 if( customer.getMode() == "i" && customer_Id == "0" )
00246 customer.getMode() = "s";
00247 string sql = "select Id from Customer where EMail = '";
00248 sql += Login;
00249 sql += "'";
00250
00251 if( rs.open(sql) )
00252 {
00253 customer.key(atoll(rs.getField(0).format().c_str()));
00254 rs.close();
00255 isCustomerOK = customer.form_action();
00256 }
00257 else
00258 {
00259 script << "<h4 style=\"color:red;\">Error! Couldn't get a user key value!</h4>";
00260 }
00261 }
00262 if( isCustomerOK )
00263 {
00264 script << pay.makeTop( "?step=verify", "Payment Setup" ) ;
00265
00266
00267 if( ( customer_Id.length() == 0 || customer_Id == "0" )
00268 && customer.Id )
00269 {
00270
00271 customer_Id.append(customer.Id);
00272 args["customer_Id"] = customer_Id.c_str();
00273 }
00274 pay.getMode() = "s";
00275 llong Payment_Service_Id;
00276 if( args.count("Payment_Service_Id") > 0 )
00277 {
00278 Payment_Service_Id = atoll(args["Payment_Service_Id"].c_str());
00279 }
00280 else
00281 {
00282 ocString qry = "select Id from Customer_Payment_Service where Customer_Id = ";
00283 qry.append(customer.Id);
00284 string psid = tableLookup ( qry );
00285 if( psid.length() ) Payment_Service_Id = atoll(psid.c_str());
00286 }
00287 pay.key(Payment_Service_Id);
00288 pay.Customer_Id = customer.Id;
00289 pay.form_action();
00290 pay.form_display();
00291 script << pay.makeButtonedBottom( Action );
00292 }
00293 else
00294 {
00295 script << "Error! unable to create customer account!<br> Result: <p><pre>"
00296 << customer.last_result() << "</pre><p>" << endl;
00297 }
00298 }
00299
00300
00301
00302
00303 void confirmOrderPanel( cgiScript & script, string & formTemplate )
00304 {
00305
00306 Payment_Form_Complete payment_setup(script);
00307
00308 cgiInput & args = script.ClientArguments();
00309
00310 string qry = "select Id from Customer_Payment_Service where Customer_Id = ";
00311 qry += args["Customer_Id"].c_str();
00312 qry += " and Payment_Service_Id = ";
00313 qry += args["Payment_Service_Id"].c_str();
00314
00315 if( rs.open(qry) )
00316 {
00317 string key = rs.getField(0).format();
00318
00319 payment_setup.Id = atoll(key.c_str());
00320 payment_setup.key(payment_setup.Id);
00321 rs.close();
00322 }
00323
00324 bool isPaymentOK = payment_setup.form_action();
00325
00326 if( !isPaymentOK )
00327 { script << "<h1 color='red'>!</h1><p>An Error occured setting your payment options - "
00328 << endl
00329 << "<br> Result: </p><pre>"
00330 << payment_setup.last_result()
00331 << "</pre>"
00332 << endl;
00333 return;
00334 }
00335
00336
00337
00338 string customer_Id = args["Customer_Id"].c_str();
00339 Customer_Obj customer;
00340
00341 customer.key( atoll(customer_Id.c_str()) );
00342 if( customer.get_data() )
00343 {
00344
00345 globalTax.State(customer.State);
00346
00347
00348 if( cart.XML.length() )
00349 {
00350 showProducts( script, cfrmHead, cfrmList, cfrmFoot);
00351 }
00352
00353
00354 script << cfrmHeading.replace("$label"," ") << endl;
00355 script << cfrmHeading.replace("$label","Customer Information:") << endl;
00356
00357 script << cfrmListItem.replace("$label","First Name")
00358 .replace("$value",customer.First_Name.c_str()) << endl;
00359 script << cfrmListItem.replace("$label","Last Name")
00360 .replace("$value",customer.Last_Name.c_str()) << endl;
00361
00362 ocString pSrvSQL = "select Name from Payment_Service where Id = ";
00363 pSrvSQL.append(customer.Payment_Service_Id);
00364 script << cfrmListItem.replace("$label","Payment Type")
00365 .replace("$value",tableLookup (pSrvSQL).c_str() ) << endl;
00366
00367
00368 if( isPaymentOK )
00369 {
00370
00371 script << cfrmHeading.replace("$label","Customer Payment Setup:") << endl;
00372 Customer_Payment_Parameters & uparms = payment_setup.uparms;
00373 for(size_t i=0;i<uparms.size();i++)
00374 {
00375 if( uparms[i].Machine_Name != "cc" )
00376 {
00377 script << cfrmListItem.replace("$label",uparms[i].Name.c_str())
00378 .replace("$value",uparms[i].Value.c_str()) << endl;
00379 }
00380 }
00381 }
00382 script << cfrmSubmit.replace("$ID",customer_Id.c_str()) << endl;
00383 }
00384 }
00385
00386 void createOrderPanel( cgiScript & script, string & formTemplate )
00387 {
00388
00389
00390 cgiInput & args = script.ClientArguments();
00391 string customer_Id = args["customer_Id"].c_str();
00392 Customer_Obj customer;
00393
00394
00395 customer.key( atoll(customer_Id.c_str()) );
00396
00397 if( customer_Id.length() > 0 && customer.get_data() )
00398 {
00399 globalTax.State(customer.State);
00400
00401
00402
00403 ocString ORDER_ID, ORDER_AMOUNT, BACK_URL;
00404
00405
00406 Ordered_Obj order;
00407 order.Customer_Id = customer.Id;
00408 order.discount = discount;
00409 order.freeShipping = freeShipping;
00410 order.Promotion = Promotion;
00411
00412 order.setOrderedItems(cart.XML);
00413
00414
00415 if( cart.Checked_Out )
00416 {
00417 script << finiError.replace("$Error","You have already checked out").replace("$url",baseUrl.c_str()) << endl;
00418 return;
00419 }
00420
00421
00422
00423 if( order.pay(customer.Payment_Service_Id) )
00424 {
00425 cart.CheckOut();
00426
00427 ORDER_ID.append(order.Id);
00428 ORDER_AMOUNT = order.Order_Total.format("%n");
00429
00430
00431 script << finiThanks.replace("$Order_Total",ORDER_AMOUNT.c_str()).replace("$Order_Id",ORDER_ID.c_str());
00432
00433
00434 emailManufacturer( order, customer );
00435 emailClerk(order);
00436 emailcustomer(order,customer);
00437 }
00438 else
00439 {
00440
00441 script << finiError.replace("$Error",order.last_result().c_str())
00442 .replace("$url",baseUrl.c_str()) << endl;
00443 }
00444 }
00445 else
00446 {
00447
00448 script << finiError.replace("$Error","I couldn't find you in our database!")
00449 .replace("$url",baseUrl.c_str()) << endl;
00450 }
00451 }
00452
00453 bool emailManufacturer( Ordered_Obj & order, Customer_Obj & customer )
00454 {
00455 bool isMailed = false;
00456
00457 for ( manufacturer_ids::iterator mit = order.manufacturers.begin();
00458 mit != order.manufacturers.end(); ++mit )
00459 {
00460 Manufacturer_Obj mfc;
00461 mfc.key(*mit);
00462 if( mfc.get_data() )
00463 {
00464 mailMfrAddr = mfc.Email_Contact;
00465 stringstream items;
00466 proofs proof;
00467 proof.m="1";
00468 proof.o="";
00469 proof.o.append(order.Id);
00470 proof.showOrderedItems( items, *mit );
00471
00472 string custName = customer.First_Name + " " + customer.Last_Name;
00473
00474 ocSendMail sendMail(mailPath);
00475 string sendTo = mailMfrAddr;
00476 ocString strOrder;
00477 strOrder.append(order.Id);
00478 ocString body=mailManufacturer
00479 .replace("$items", items.str().c_str() )
00480 .replace("$name$",custName.c_str() )
00481 .replace("$address$",customer.Address.c_str())
00482 .replace("$city$",customer.City.c_str())
00483 .replace("$state$",customer.State.c_str())
00484 .replace("$zip$",customer.Zip.c_str());
00485 sendMail.openRoute( mailFrom.c_str(), sendTo.c_str(), "You have an Order!" );
00486 sendMail.setMimeType("text/html");
00487 sendMail.write( body.c_str() );
00488 sendMail.send();
00489 isMailed = true;
00490 }
00491 }
00492 return isMailed;
00493 }
00494
00495 void emailcustomer( Ordered_Obj & order, Customer_Obj & customer )
00496 {
00497 ocSendMail sendMail(mailPath);
00498 string sendTo = customer.EMail;
00499 ocString strOrder;
00500 strOrder.append(order.Id);
00501 ocString body=mailCustomer.replace("$orderid", strOrder.c_str() )
00502 .replace("$amount", order.Order_Total.format("%n").c_str() );
00503 sendMail.openRoute( mailFrom.c_str(), sendTo.c_str(), "Thank You for your order" );
00504 sendMail.setMimeType("text/html");
00505 sendMail.write( body.c_str() );
00506 sendMail.send();
00507
00508
00509 }
00510
00511 void emailClerk( Ordered_Obj & order )
00512 {
00513 string current = mailStoreClerk.parse(",");
00514 while( !mailStoreClerk.endOfParse() )
00515 {
00516 ocSendMail sendMail(mailPath);
00517
00518 ocString body="<html><body><h1>An order has been placed and needs your attention!</h1>\n"
00519 "The details of your order are given below.</p>\n"
00520 "Order ID: ";
00521 body.append(order.Id);
00522 body+="<br>\nTotal Amount: ";
00523 body+=order.Order_Total.format("%n");
00524 body+="<br>\n"
00525 "<p>You will find this order on the 'Orders' control panel in 'paid' status.<br>\n"
00526 "You should enter this order into quickbooks as soon as possible then set the status to 'entered'.<br>\n"
00527 "Thanks!</p>";
00528
00529 sendMail.openRoute( mailFrom.c_str(), current.c_str(), "You have an Order!" );
00530 sendMail.setMimeType("text/html");
00531 sendMail.write( body.c_str() );
00532 sendMail.send();
00533 current = mailStoreClerk.parse(",");
00534 }
00535 }
00536
00537
00538 pnodecounts pncs;
00539 void trackProductNodes(long long productId)
00540 {
00541 pnodecounts::iterator it = pncs.find(productId);
00542 if( it == pncs.end() )
00543 {
00544 pncs.insert(make_pair(productId,0));
00545 }
00546 else
00547 {
00548 it->second++;
00549 }
00550 }
00551
00552
00553 void showProducts( cgiScript & script, ocString & prodHead, ocString & listTemplate, ocString & prodFoot)
00554 {
00555 script << prodHead;
00556 xmlParser parser( cart.XML );
00557 parser.parse();
00558 node_vector & xnodes = parser.nodeList();
00559 int i;
00560 money tot = 0.0;
00561
00562
00563 if( xnodes.size() == 0 )
00564 {
00565
00566 script << finiError.replace("$Error","Nothing was found in the cart!")
00567 .replace("$url",baseUrl.c_str()) << endl;
00568 }
00569
00570
00571 for(i=0;i<xnodes.size();i++)
00572 {
00573 ItemDetail dtl;
00574 dtl = xnodes[i];
00575
00576 if( dtl.Product() )
00577 {
00578 trackProductNodes( dtl.Product() );
00579 ocString productId;
00580 productId.append(dtl.Product());
00581 ocString seq;
00582 seq.append(pncs[dtl.Product()]);
00583
00585 string Price;
00586 string Shipping;
00587 if( discount > 0.0 && discount < 100.0 )
00588 {
00589 money reducedPrice;
00590 reducedPrice.amount() = dtl.Price().amount();
00591 reducedPrice.amount() *= (100-discount);
00592 reducedPrice.amount() /=100.0;
00593 Price = "<del>";
00594 Price += dtl.Price().format("%n");
00595 Price += "</del><br><ins>";
00596 Price += reducedPrice.format("%n");
00597 Price += "</ins>";
00598 dtl.Price().amount() = reducedPrice.amount();
00599 }
00600 else
00601 {
00602 Price = dtl.Price().format("%n");
00603 }
00604 if( freeShipping )
00605 {
00606 dtl.Shipping().amount() = 0.0;
00607 }
00608
00610 money mon = dtl.Price();
00611 double cnt = dtl.Count();
00612 double ship = dtl.Shipping().amount();
00613 ship *= cnt;
00614 ocString count;
00615 count.append(cnt);
00616 odr.shipInc(ship);
00617 tot.amount() += cnt*mon.amount();
00618
00619 script << listTemplate.replace( "$detail", dtl.ProductDescription() )
00620 .replaceAll("$title", dtl.ProductName() )
00621 .replace( "$price", Price )
00622 .replace( "$image", dtl.StyleImage() )
00623 .replace( "$text", dtl.CustomText() )
00624 .replace( "$count", count.c_str() )
00625 .replaceAll( "$id", productId )
00626 .replaceAll( "$pnode", seq);
00627 }
00628 }
00629 ocString tmp = prodFoot.replace("$shipping", odr.netShipping() );
00630 globalTax.ProductTotal(tot);
00631 tot.amount() += odr.Shipping_Total.amount() + globalTax.TaxTotal().amount();
00632 script << tmp.replace("$price", tot.format("%n")).replace("$tax", globalTax.TaxTotal().format("%n"));
00633 }
00634 };
00635
00636 class chkout_functor: public base_functor
00637 {
00638 protected:
00639 cgiScript & script;
00640 virtualCheckout checkout;
00641 Promotion_Obj pro;
00642
00643 public:
00644 chkout_functor(page & ipg,cgiScript & scriptIn):base_functor(ipg),script(scriptIn),checkout(scriptIn)
00645 {
00646
00647 Session_Obj sess(false);
00648 string proId = sess.GetData( "Promotion");
00649 if( proId.length() )
00650 {
00651 pro.key( atoll(proId.c_str() ) );
00652 if( pro.get_data() )
00653 {
00654 checkout.discount = pro.Percent_Discount;
00655 checkout.freeShipping = pro.Free_Shipping;
00656 checkout.Promotion = pro.Id;
00657 }
00658 }
00659 }
00660 virtual ~chkout_functor(){;}
00661
00662 virtual bool operator()( xmlNode & node )
00663 {
00664 bool bRet = false;
00665 string headPName = getXmlAttribute(node,"uiListHead");
00666 string listPName = getXmlAttribute(node,"uiListitem");
00667 string footPName = getXmlAttribute(node,"uiListFoot");
00668 string buyPName = getXmlAttribute(node,"uiBuyForm");
00669 string defPName = getXmlAttribute(node,"uiDefault");
00670 string uiCfrmHead = getXmlAttribute(node,"uiCfrmHead");
00671 string uiCfrmFoot = getXmlAttribute(node,"uiCfrmFoot");
00672 string uiCfrmList = getXmlAttribute(node,"uiCfrmList");
00673
00674 string acctTmpltName = getXmlAttribute(node,"uiAccountTemplate");
00675
00676 if( listPName.length() )
00677 {
00678 checkout.prodHead = pg.paragraph_string(headPName);
00679 checkout.prodList = pg.paragraph_string(listPName);
00680 checkout.prodFoot = pg.paragraph_string(footPName);
00681 checkout.prodBuy = pg.paragraph_string(buyPName);
00682 checkout.cfrmHead = pg.paragraph_string(uiCfrmHead);
00683 checkout.cfrmList = pg.paragraph_string(uiCfrmList);
00684 checkout.cfrmFoot = pg.paragraph_string(uiCfrmFoot);
00685 checkout.cfrmHeading = pg.paragraph_string(getXmlAttribute(node,"uiCfrmGenHead"));
00686 checkout.cfrmListItem = pg.paragraph_string(getXmlAttribute(node,"uiCfrmGenList"));
00687 checkout.cfrmSubmit = pg.paragraph_string(getXmlAttribute(node,"uiCfrmSubmit"));
00688 checkout.finiThanks = pg.paragraph_string(getXmlAttribute(node,"uiThanks"));
00689 checkout.finiError = pg.paragraph_string(getXmlAttribute(node,"uiError"));
00690 checkout.mailFrom = getXmlAttribute(node,"mailFrom");
00691 checkout.mailStoreClerk = getXmlAttribute(node,"mailStoreClerk");
00692 checkout.mailMfrAddr = getXmlAttribute(node,"mfrEmail");
00693
00694 checkout.mailCustomer = pg.paragraph_string(getXmlAttribute(node,"uiMailCustomer"));
00695 checkout.mailManufacturer = pg.paragraph_string(getXmlAttribute(node,"uiMailManufacturer"));
00696 checkout.show( pg, acctTmpltName, defPName );
00697 bRet = true;
00698 }
00699 else
00700 {
00701 script << "<h1>No XML control items!</h1>" << endl;
00702 }
00703 return bRet;
00704 }
00705
00706 };
00707
00708
00709
00710