예제 #1
0
            /// <summary>
            /// Pays with check.
            /// </summary>
            /// <param name="routingNumber">The routing number.</param>
            /// <param name="checkNumber">The check number.</param>
            /// <param name="bankAccountNumber">The bank account number.</param>
            /// <param name="notes">The notes.</param>
            /// <param name="amount">The amount.</param>
            /// <param name="userId">The userId.</param>
            /// <param name="postingDate">The posting date.</param>
            /// <param name="orderIds">The order ids.</param>
            /// <param name="cn">The sql connection (or null).</param>
            /// <param name="trans">The sql transaction (or null).</param>
            /// <returns>{error:0,desc:"error description"}.</returns>
            public static Dictionary<string, object> PayWithCheck( string routingNumber, string checkNumber, string bankAccountNumber,
			string notes, decimal amount, int userId, DateTime postingDate, List<object> orderIds, SqlConnection cn, SqlTransaction trans )
            {
                List<int> intIds = orderIds.ConvertAll( delegate( object i ) {
                    return Convert.ToInt32( i );
                } );
                Dictionary<string, object> j = new Dictionary<string, object>();
                Guid paymentMethodId = Guid.NewGuid();
                Commerce.Check check = new Commerce.Check( checkNumber, routingNumber, bankAccountNumber, notes );
                check.Insert( paymentMethodId, userId, Guid.Empty, -1, "", amount, postingDate, intIds, "", cn, trans );
                /* update the orders with the payment data */
                UpdateOrders( orderIds, amount, paymentMethodId, cn, trans );
                j.Add( "paymentMethodId", paymentMethodId.ToString() );
                j.Add( "error", 0 );
                j.Add( "description", "" );
                return j;
            }
예제 #2
0
            /// <summary>
            /// Recalculates the order.
            /// </summary>
            /// <param name="args">The order arguments.</param>
            /// <param name="fcn">The FCN.</param>
            /// <param name="ftrans">The ftrans.</param>
            /// <returns>{error:0,desc:""}</returns>
            public static Dictionary<string, object> RecalculateOrder(Dictionary<string, object> args, SqlConnection fcn, SqlTransaction ftrans)
            {
                Dictionary<string, object> vt;
                Dictionary<string, object> j;
                Commerce.CreditCard card = null;
                Commerce.Cash cash = null;
                Commerce.Wire wire = null;
                // never used -> Commerce.PayPal PayPal=null;
                Commerce.Check check = null;
                Commerce.PromiseToPay promiseToPay = null;
                decimal discountAmount = 0;
                Guid paymentMethodId = Guid.NewGuid();
                bool backorder = false;
                bool preview = false;
                int errorId = -1;
                ("FUNCTION /w SP,CN,TRANS recalculateOrder").Debug(10);
                string[] keys = { "userId", "orderSessionId", "cartSessionId", "preview", "purchaseOrder" };
                bool transactionSucsessStatus = false;
                int termId = 0;
                int orderId = 0;
                decimal difference = 0;
                foreach(string keyName in keys) {
                    if(!args.ContainsKey(keyName)) {
                        Dictionary<string, object> o = new Dictionary<string, object>();
                        string _msg = "The key \"" + keyName + "\" is missing from the argument dictionary.  All keys must be present even if they are blank.";
                        o.Add("error", -4010);
                        o.Add("description", _msg);
                        String.Format("recalculateOrder failed. {0}", _msg).Debug(1);
                        return o;
                    }
                }
                /* get the old order */
                SqlConnection cn;
                SqlTransaction trans;
                Guid orderSessionId = new Guid((string)args["orderSessionId"]);
                if(fcn == null) {
                    cn = Site.CreateConnection(true, true);
                    cn.Open();
                    trans = cn.BeginTransaction("Recalculate transaction");
                } else {
                    cn = fcn;
                    trans = ftrans;
                }
                Commerce.Order originalOrder = Commerce.Order.GetOrderBySessionId(orderSessionId, cn, trans);
                termId = originalOrder.TermId;
                preview = Convert.ToBoolean(args["preview"].ToString());
                if(!preview) {
                    /* preview the recalculation in preview to asertain the grand total for charging the card */
                    trans.Save("preChargePreview");
                    j = ExecPlaceOrder(
                        orderSessionId,
                        Convert.ToInt32(args["userId"].ToString()),
                        orderSessionId,
                        true,/*preview*/
                        new Guid(Main.Site.Defaults.SiteId),
                        new Guid((string)args["cartSessionId"]),
                        args["purchaseOrder"].ToString(),
                        DateTime.Now/* this value is ignored in the SP for recalculations */,
                        termId,
                        discountAmount,
                        cn,
                        trans
                    );
                    termId = (int)j["termId"];
                    orderId = (int)j["orderId"];
                    if(j["error"].ToString() != "0" && j["error"].ToString() != "5") {
                        Exception ex = new Exception(j["description"].ToString());
                        throw ex;
                    }
                    if(!decimal.TryParse(j["difference"].ToString(), out difference)) {
                        difference = 0;
                    }
                    difference = Math.Round(difference, 2, MidpointRounding.AwayFromZero);
                    if(difference != 0) {
                        if(backorder) {
                            /* no need to do anything */
                        } else if(termId == 0 && difference > 0) {/*this is a prepaid credit card transaction - termId 0 */
                            /* don't try and charge credit cards negitive amounts */
                            card = new Commerce.CreditCard(
                                args["cardType"].ToString().MaxLength(50, true),
                                args["cardNumber"].ToString().MaxLength(100, true),
                                args["nameOnCard"].ToString().MaxLength(100, true),
                                args["secNumber"].ToString().MaxLength(7, true),
                                args["expMonth"].ToString().MaxLength(4, true),
                                args["expYear"].ToString().MaxLength(4, true)
                            );
                            List<int> orderIds = new List<int>();
                            orderIds.Add(orderId);
                            card.Insert(paymentMethodId, orderSessionId, originalOrder.UserId, originalOrder.SessionId,
                            termId, "", difference, DateTime.Now, orderIds, "", cn, trans);
                        } else if(termId == 9 /* this is a COD Check transaction - termId 9 */ ) {
                            check = new Commerce.Check(
                                args["checkNumber"].ToString().MaxLength(50, true),
                                args["routingNumber"].ToString().MaxLength(50, true),
                                args["bankAccountNumber"].ToString().MaxLength(50, true),
                                args["checkNotes"].ToString().MaxLength(50, true)
                            );
                            List<int> orderIds = new List<int>();
                            orderIds.Add(orderId);
                            check.Insert(paymentMethodId, originalOrder.UserId, originalOrder.SessionId, termId, "", difference, DateTime.Now, orderIds, "", cn, trans);
                        } else if(termId == 20 /* this is a wire transfer - termId 20 */ ) {
                            wire = new Commerce.Wire(
                                args["swift"].ToString().MaxLength(50, true),
                                args["bankName"].ToString().MaxLength(50, true),
                                args["routingTransitNumber"].ToString().MaxLength(50, true)
                            );
                            List<int> orderIds = new List<int>();
                            orderIds.Add(orderId);
                            wire.Insert(paymentMethodId, originalOrder.UserId, originalOrder.SessionId, termId, "", difference, DateTime.Now, orderIds, "", cn, trans);
                        } else if(termId == 13 /* this order is prepaid in cash */) {
                            cash = new Commerce.Cash(); /*don't you wish it was really that easy?*/
                            List<int> orderIds = new List<int>();
                            orderIds.Add(orderId);
                            cash.Insert(paymentMethodId, originalOrder.UserId, originalOrder.SessionId, termId, "", difference, DateTime.Now, orderIds, "", cn, trans);
                        } else if(difference > 0) {
                            /* this order is an accrued order */
                            promiseToPay = new Commerce.PromiseToPay();
                            List<int> orderIds = new List<int>();
                            orderIds.Add(orderId);
                            promiseToPay.Insert(paymentMethodId, originalOrder.UserId, originalOrder.SessionId, termId, "", difference, DateTime.Now, orderIds, "", cn, trans);
                        }
                    }
                    trans.Rollback("preChargePreview");
                }
                /* do the recalculation */
                j = ExecPlaceOrder(
                    new Guid((string)args["orderSessionId"]),
                    Convert.ToInt32(args["userId"].ToString()),
                    new Guid((string)args["orderSessionId"]),
                    preview,
                    new Guid(Main.Site.Defaults.SiteId),
                    new Guid((string)args["cartSessionId"]),
                    args["purchaseOrder"].ToString(),
                    DateTime.Now/* this value is ignored in the SP for recalculations */,
                    termId,
                    discountAmount,
                    cn,
                    trans
                );
                errorId = Convert.ToInt32(j["error"].ToString());
                if(errorId != 0 && errorId != 5) {/* if there was an return the error without continuing */
                    if(fcn == null) {
                        trans.Rollback();
                        cn.Close();
                    }
                    return j;
                };

                if(termId != 0 || backorder == true) {
                    /* this order uses acrued payment method or has lost value, don't charge now */
                    ("order with payment terms, backorder.  No payment gateway now.").Debug(7);
                    transactionSucsessStatus = true;
                } else if(difference > 0) {
                    ("starting payment gateway...").Debug(5);
                    vt = Commerce.VirtualTerminal.ChargeCreditCard(
                        (Commerce.Address)j["billToAddress"], (Commerce.Address)j["shipToAddress"], card,
                        difference, new Guid((string)args["orderSessionId"]), originalOrder.OrderNumber,
                        originalOrder.PurchaseOrder, fcn, ftrans
                    );
                    if(vt == null) {
                        Dictionary<string, object> o = new Dictionary<string, object>();
                        trans.Rollback();
                        o.Add("error", -1754);
                        o.Add("description", "Internal virtual terminal error.  Unable to create virtual terminal object.");
                        ("Invalid credit card passed to local system").Debug(7);
                        ("placeOrder Failed with error code -1754").Debug(7);
                        if(fcn == null) {
                            cn.Dispose();
                        }
                        return o;
                    }
                    transactionSucsessStatus = vt["error"].ToString() == "0";
                    if(!transactionSucsessStatus) {
                        j.Add("error", -3);
                        j.Add("description", vt["description"]);
                        j.Add("virtualTerminal", vt);
                        if(fcn == null) {
                            cn.Dispose();
                        }
                        return j;
                    }
                }
                if(errorId != 0 || transactionSucsessStatus == false || preview) {
                    if(fcn == null) {
                        trans.Rollback();
                    }
                    if(!preview) {
                        Exception ex = new Exception("The trasnaction failed.");
                        throw ex;
                    }
                } else {
                    Commerce.Order order;
                    RecalculateOrderEventArgs e;
                    if(fcn == null) {
                        order = Commerce.Order.GetOrderByOrderId(orderId, cn, trans);
                        e = new RecalculateOrderEventArgs(order, cn, trans, args, Main.GetCurrentSession(), HttpContext.Current);
                    } else {
                        order = Commerce.Order.GetOrderByOrderId(orderId, fcn, ftrans);
                        e = new RecalculateOrderEventArgs(order, fcn, ftrans, args, Main.GetCurrentSession(), HttpContext.Current);
                    }
                    Main.Site.raiseOnrecalculateorder(e);
                    if(Site.AbortDefaultEvent == true) {
                        Site.AbortDefaultEvent = false;
                    }
                    if(fcn == null) {
                        trans.Commit();
                    }
                }
                if(fcn == null) {
                    cn.Dispose();
                }
                return j;
            }
            /// <summary>
            /// Places an order once a cart has been filled with items using the specified sessionId within a transaction.
            /// </summary>
            /// <param name="args">JSON Object that can contain the following keys (even if blank)
            /// sessionId
            /// userId
            /// nameOnCard
            /// cardType
            /// cardNumber
            /// expMonth
            /// expYear
            /// secNumber
            /// soldBy
            /// requisitionedBy
            /// parentOrderId
            /// deliverBy
            /// purchaseOrder
            /// manifestNumber
            /// vendorAccountNumber
            /// Fob
            /// scannedImage
            /// comments
            /// billToContactId
            /// billToFirstName
            /// billToLastName
            /// billToAddress1
            /// billToAddress2
            /// billToCity
            /// billToState
            /// billToZip
            /// billToCountry
            /// billToCompany
            /// billToEmail
            /// billToSendShipmentUpdates
            /// billToHomePhone
            /// billToWorkPhone
            /// billToSpecialInstructions
            /// billToEmailAds
            /// billToComments
            /// billToRateId
            /// shipToContactId
            /// shipToFirstName
            /// shipToLastName
            /// shipToAddress1
            /// shipToAddress2
            /// shipToCity
            /// shipToState
            /// shipToZip
            /// shipToCountry
            /// shipToCompany
            /// shipToEmail
            /// shipToSendShipmentUpdates
            /// shipToHomePhone
            /// shipToWorkPhone
            /// shipToSpecialInstructions
            /// shipToComments
            /// shipToEmailAds
            /// shipToRateId</param>
            /// <param name="fcn">The FCN.</param>
            /// <param name="trans">The transaction being used.</param>
            /// <returns>
            /// {billToAddressId:Guid,paymentMethodId:Guid,orderNumber:string,subTotal:float,grandTotal:float,taxTotal:float,shipTotal:float,
            /// discounted:Guid,printState:string,concatSerialNumbers:string,concatShipmentNumbers:float,concatSerialIds:float,
            /// concatShipmentIds:Guid,error:Guid,errorDescription:string,orderId:float,discountPct:float,
            /// discountCode:Guid,termId:int,userId:int,approvedBy:int,scannedImage:string}.
            /// </returns>
            public static Dictionary<string, object> PlaceOrderWithTransaction(Dictionary<string, object> args, SqlConnection fcn, SqlTransaction trans)
            {
                /* do not put debug statements before the transaction start */
                int requisitionedBy = -1;
                int approvedBy = -1;
                int soldBy = -1;
                int parentOrderId = -1;
                bool backorderMode = false;
                DateTime SQLMin = DateTime.Parse("1/1/1900 00:00:00.000");
                DateTime deliverBy = SQLMin;
                DateTime orderDate = SQLMin;
                string customOrderNumber = "";
                string vtDesc = "";
                Commerce.CreditCard card = null;
                Commerce.Cash cash = null;
                Commerce.Wire wire = null;
                // never used -> Commerce.PayPal PayPal = null;
                Commerce.Check check = null;
                Commerce.PromiseToPay promiseToPay = null;
                Dictionary<string, object> vt = null;
                Dictionary<string, object> o = new Dictionary<string, object>();
                /* last chance to reject before transaction starts */
                SqlConnection cn;
                if(fcn == null) {
                    /* create a seperate connection so we can control the transaction process (MARS will confict) */
                    cn = Site.CreateConnection(false, true);
                    cn.Open();
                } else {
                    cn = fcn;
                }
                string transSessionId = Guid.NewGuid().ToFileName();
                SqlCommand cmd;
                SqlTransaction orderTransaction;
                if(fcn == null) {
                    orderTransaction = cn.BeginTransaction(transSessionId);
                } else {
                    orderTransaction = trans;
                }
                /* debug statements OK after this */
                ("FUNCTION /w SP,CN,TRANS placeOrder").Debug(10);
                bool rollback = false;
                int termId = 0;
                /* check all keys to make sure the keys are present */
                string[] keys = {
                "userId","nameOnCard","cardType","cardNumber","expMonth","expYear","secNumber","soldBy",
                "requisitionedBy","parentOrderId","deliverBy","purchaseOrder","manifestNumber",
                "vendorAccountNumber","FOB","comments","billToContactId",
                "billToFirstName","billToLastName","billToAddress1","billToAddress2",
                "billToCity","billToState","billToZip","billToCountry","billToCompany",
                "billToEmail","billToSendShipmentUpdates","billToHomePhone","billToWorkPhone",
                "billToSpecialInstructions","billToEmailAds","billToComments","billToRateId",
                "shipToContactId","shipToFirstName","shipToLastName","shipToAddress1",
                "shipToAddress2","shipToCity","shipToState","shipToZip","shipToCountry",
                "shipToCompany","shipToEmail","shipToSendShipmentUpdates","shipToHomePhone",
                "shipToWorkPhone","shipToSpecialInstructions","shipToComments","shipToEmailAds",
                "shipToRateId","termId","approvedBy","scannedImage","orderDate",
                "eraseVisitorHistory","backorder"};
                string[] requiredKeys = { };
                Session session = null;
                if(args.ContainsKey("sessionId")) {
                    if(fcn == null) {
                        session = new Session(Main.Site, new Guid((string)args["sessionId"]));
                    } else {
                        session = new Session(Main.Site, new Guid((string)args["sessionId"]), cn, orderTransaction);
                    }
                } else {
                    session = Main.GetCurrentSession();
                }
                foreach(string keyName in requiredKeys) {
                    if(!args.ContainsKey(keyName)) {
                        string errMsg = "The key \"" + keyName + "\" is missing from the argument dictionary.  All required keys must be present.";
                        o.Add("error", -4010);
                        o.Add("description", errMsg);
                        Exception e = new Exception(errMsg);
                        e.Message.Debug(1);
                        throw e;
                    }
                }
                foreach(string keyName in keys) {
                    if(!args.ContainsKey(keyName)) {
                        args.Add(keyName, "");
                    }
                }
                /* gather bill to and ship to data, if any, from the request */
                Dictionary<string, object> btAddr = new Dictionary<string, object>();
                Dictionary<string, object> stAddr = new Dictionary<string, object>();
                foreach(KeyValuePair<string, object> field in args as Dictionary<string, object>) {
                    if(field.Key.StartsWith("shipTo")) {
                        stAddr.Add(field.Key.Replace("shipTo", ""), field.Value);
                    } else if(field.Key.StartsWith("billTo")) {
                        btAddr.Add(field.Key.Replace("billTo", ""), field.Value);
                    }
                }
                if(!(session.User.AccountType == 0 || session.User.AccountType == 1)) {
                    Exception e = new Exception(string.Format("Only users with account type 0 or 1 can place orders.  " +
                    "The account type of userId {0} is {1}.", session.UserId, session.User.AccountType));
                    e.Message.Debug(1);
                    throw e;
                }
                /* if the cart isn't populated, do that now */
                if(session.Cart.Items.Count == 0) {
                    session.Cart.Refresh(cn, orderTransaction);
                }
                if(session.Cart.Items.Count == 0) {
                    string _msg = String.Format("No items found in cart. UserId:{0}, SessionId:{1}", session.UserId, session.Id);
                    o.Add("error", -2016);
                    o.Add("description", "No items found in cart.");
                    rollback = true;
                    Exception e = new Exception(_msg);
                    e.Message.Debug(1);
                    throw e;
                }
                /* update the bill to and ship to addresses in the database
                 * if the Address does not exist, validate it and insert it.
                 */
                if(stAddr.Count > 0) {
                    stAddr.Remove("ContactId");
                    stAddr.Add("contactId", session.Cart.Items[0].AddressId.ToString());
                    stAddr.Add("sessionId", session.Id.ToString());
                    stAddr.Add("userId", session.UserId.ToString());
                    Address.UpdateContactWithTransaction(stAddr, cn, orderTransaction);
                }
                if(btAddr.Count > 0) {
                    btAddr.Remove("ContactId");
                    btAddr.Add("contactId", session.Id.ToString());
                    btAddr.Add("sessionId", session.Id.ToString());
                    btAddr.Add("userId", session.UserId.ToString());
                    Address.UpdateContactWithTransaction(btAddr, cn, orderTransaction);
                }
                /* refresh again to reflect changes in the addresses */
                session.Cart.Refresh(cn, orderTransaction);
                Commerce.Address billToAddress = session.Cart.Addresses.Find(delegate(Commerce.Address adr) {
                    return adr.Id == session.Id;
                });
                Commerce.Address shipToAddress = session.Cart.Addresses.Find(delegate(Commerce.Address adr) {
                    return adr.Id != session.Id;
                });
                /* if there is no shipToAddress, or billToAddress then reject now */
                if(billToAddress == null) {
                    o.Add("error", -2001);
                    o.Add("description", "No bill to Address found for session.");
                    rollback = true;
                    string _msg = String.Format("No bill to Address found for session. UserId:{0}, SessionId:{1}",
                    session.UserId, session.Id);
                    Exception e = new Exception(_msg);
                    e.Message.Debug(1);
                    throw e;
                }
                if(shipToAddress == null) {
                    o.Add("error", -2002);
                    o.Add("description", "No ship to Address found for session.");
                    rollback = true;
                    string _msg = String.Format("No ship to Address found. UserId:{0}, SessionId:{1}",
                    session.UserId, session.Id);
                    Exception e = new Exception(_msg);
                    e.Message.Debug(1);
                    throw e;
                }
                ("Begin place order transaction >").Debug(7);
                PlaceOrderEventArgs ev = new PlaceOrderEventArgs(session.Cart, cn, orderTransaction, session, HttpContext.Current);
                Main.Site.raiseOnbeforeplaceorder(ev);
                try {
                    bool transactionSucsessStatus = false;
                    int errorId = -1;
                    string errorDescription = "";
                    int orderId = -1;
                    string orderNumber = "";
                    Guid newSessionId = Guid.Empty;
                    if(!DateTime.TryParse(args["orderDate"].ToString(), out orderDate)) {
                        orderDate = DateTime.Now;
                    }
                    /* if the date is today at 12:00, change the date to now.  Some functions
                     * want to pretend there is no such thing as time of day, this is bad behaviour.
                     */
                    if(orderDate == DateTime.Today) {
                        orderDate = DateTime.Now;
                    }
                    /* validate order */
                    if(HttpContext.Current != null) {
                        /* if this is a web user, check that they have permission for these keys */
                        int _term;
                        if(!int.TryParse(args["termId"].ToString(), out _term)) {
                            termId = session.User.TermId;
                        }
                        /* is the person who owns the order an administrator? If not they gota use their account terms. */
                        if(!session.User.Administrator) {
                            termId = session.User.TermId;
                        }
                        /* is the person who is submitting the order an administrator? */
                        Session submitter = Main.GetCurrentSession();
                        if(submitter != null) {
                            if(submitter.User.Administrator) {
                                termId = _term;
                            }
                        }
                    } else {
                        /* if this isn't a web user (EDI) then see if they passed a valid termId, or use the user's default */
                        termId = session.User.TermId;
                        if(!int.TryParse(args["termId"].ToString(), out termId)) {
                            termId = session.User.TermId;
                        }
                    }
                    String.Format("Place Order > Set termId {0} for userId  {1}", termId, session.UserId).Debug(7);
                    /* try to create a paymentMethodId */
                    Guid paymentMethodId = Guid.NewGuid();
                    if(!bool.TryParse(args["backorder"].ToString(), out backorderMode)) {
                        backorderMode = false;
                    }
                    if(termId == 0 && backorderMode == false) {/*this is a prepaid credit card transaction - termId 0 */
                        String.Format("Place Order > Begin CC Transaction for userId {0}", session.UserId).Debug(7);
                        card = new Commerce.CreditCard(
                            args["cardType"].ToString().MaxLength(50, true),
                            args["cardNumber"].ToString().MaxLength(100, true),
                            args["nameOnCard"].ToString().MaxLength(100, true),
                            args["secNumber"].ToString().MaxLength(7, true),
                            args["expMonth"].ToString().MaxLength(4, true),
                            args["expYear"].ToString().MaxLength(4, true)
                        );
                        List<int> orderIds = new List<int>();
                        orderIds.Add(orderId);
                        card.Insert(paymentMethodId, session.Id, session.UserId, session.Id, termId, "",
                        session.Cart.GrandTotal, orderDate, orderIds, "", cn, orderTransaction);
                    } else if(termId == 9 && backorderMode == false /* this is a COD Check transaction - termId 9 */ ) {
                        check = new Commerce.Check(
                            args["checkNumber"].ToString().MaxLength(50, true),
                            args["routingNumber"].ToString().MaxLength(50, true),
                            args["bankAccountNumber"].ToString().MaxLength(50, true),
                            args["checkNotes"].ToString().MaxLength(50, true)
                        );
                        List<int> orderIds = new List<int>();
                        orderIds.Add(orderId);
                        check.Insert(paymentMethodId, session.UserId, session.Id, termId, "", session.Cart.GrandTotal, orderDate, orderIds, "", cn, orderTransaction);
                    } else if(termId == 20 && backorderMode == false /* this is a wire transfer - termId 20 */ ) {
                        wire = new Commerce.Wire(
                            args["swift"].ToString().MaxLength(50, true),
                            args["bankName"].ToString().MaxLength(50, true),
                            args["routingTransitNumber"].ToString().MaxLength(50, true)
                        );
                        List<int> orderIds = new List<int>();
                        orderIds.Add(orderId);
                        wire.Insert(paymentMethodId, session.UserId, session.Id, termId, "", session.Cart.GrandTotal, orderDate, orderIds, "", cn, orderTransaction);
                    } else if(termId == 13 && backorderMode == false /* this order is prepaid in cash */) {
                        List<int> orderIds = new List<int>();
                        orderIds.Add(orderId);
                        cash = new Commerce.Cash(); /*don't you wish it was really that easy?*/
                        cash.Insert(paymentMethodId, session.UserId, session.Id, termId, "", session.Cart.GrandTotal, orderDate, orderIds, "", cn, orderTransaction);
                    } else {
                        /* this order is an accrued order, post a 0 payment as a placeholder */
                        List<int> orderIds = new List<int>();
                        orderIds.Add(orderId);
                        promiseToPay = new Commerce.PromiseToPay();
                        promiseToPay.Insert(paymentMethodId, session.UserId, session.Id, termId, "", session.Cart.GrandTotal, orderDate, orderIds, "", cn, orderTransaction);
                    }
                    /* save forms */
                    for(var x = 0; session.Cart.Items.Count > x; x++) {
                        if(session.Cart.Items[x].Item.Form != null) {
                            cmd = new SqlCommand("dbo.insertOrderLineForm @cartId,@sourceCode,@formName", cn, orderTransaction);
                            cmd.Parameters.Add("@cartId", SqlDbType.UniqueIdentifier).Value = new Guid(session.Cart.Items[x].CartId.ToString());
                            cmd.Parameters.Add("@sourceCode", SqlDbType.VarChar).Value = session.Cart.Items[x].Item.Form.SourceCode;
                            cmd.Parameters.Add("@formName", SqlDbType.VarChar).Value = session.Cart.Items[x].Item.Form.Name.MaxLength(50, true);
                            cmd.ExecuteNonQuery();
                            cmd.Dispose();
                        }
                    }
                    /* place order */
                    o = ExecPlaceOrder(
                        new Guid(session.Id.ToString()),
                        session.UserId,
                        paymentMethodId,
                        Main.Site.test_mode,
                        new Guid(Main.Site.Defaults.SiteId.ToString()),
                        Guid.Empty,
                        args["purchaseOrder"].ToString(),
                        orderDate,
                        termId,
                        session.Cart.DiscountTotal,
                        cn,
                        orderTransaction
                    );
                    errorId = (int)o["error"];
                    errorDescription = (string)o["description"];
                    if(errorId == 0) {/* these keys will be absent in the event of an error */
                        orderId = (int)o["orderId"];
                        orderNumber = (string)o["orderNumber"];
                    }
                    if(errorId == 0) {
                        /* if termId == 0 then this is a credit card and we can actaully automate the payment. */
                        if(termId == 0 && session.User.AccountType == 0/*AR accounts only*/) {
                            if(card.Error == 0) {
                                ("starting payment gateway...").Debug(5);
                                vt = Commerce.VirtualTerminal.ChargeCreditCard(
                                    billToAddress, shipToAddress, card, session.Cart.GrandTotal, session.Id, orderNumber, args["purchaseOrder"].ToString(), cn, orderTransaction
                                );
                                if(vt == null) {
                                    o.Add("error", -1754);
                                    o.Add("description", "Internal virtual terminal error.  Unable to create virtual terminal object.");
                                    rollback = true;
                                    Exception e = new Exception("Invalid credit card passed to local system");
                                    e.Message.Debug(5);
                                    throw e;
                                }
                                transactionSucsessStatus = vt["error"].ToString() == "0";
                                vtDesc = vt["description"].ToString();
                            } else {
                                o.Add("error", -1744);
                                o.Add("description", "Invalid credit card passed to local system");
                                rollback = true;
                                Exception e = new Exception("Invalid credit card passed to local system");
                                e.Message.Debug(5);
                                throw e;
                            }
                        } else { /* if this was anything else we can't really tell if the payment is good or bad so we just assume it's good */
                            ("Non credit card order - assume payment is OK").Debug(7);
                            transactionSucsessStatus = true;
                        }
                        if(transactionSucsessStatus || Main.Site.test_mode == true) {
                            /* add info to the order now that it has been placed */
                            if(args.ContainsKey("orderNumber")) {
                                if(args["orderNumber"].ToString() != "") {
                                    customOrderNumber = args["orderNumber"].ToString();
                                }
                            }
                            if(!Int32.TryParse(args["soldBy"].ToString(), out soldBy)) {
                                soldBy = -1;
                            }
                            if(!Int32.TryParse(args["requisitionedBy"].ToString(), out requisitionedBy)) {
                                requisitionedBy = -1;
                            }
                            if(!Int32.TryParse(args["approvedBy"].ToString(), out soldBy)) {
                                approvedBy = -1;
                            }
                            if(!Int32.TryParse(args["parentOrderId"].ToString(), out parentOrderId)) {
                                parentOrderId = -1;
                            }
                            if(!DateTime.TryParse(args["deliverBy"].ToString(), out deliverBy)) {
                                deliverBy = SQLMin;
                            }
                            string discountCode = "";
                            object s_code = session.GetProperty("discountCode");
                            object s_desc = session.GetProperty("discountDescription");
                            if(s_desc != null) {
                                discountCode = s_desc.ToString().MaxLength(50, true);
                            } else if(s_code != null) {
                                string t_code = s_code.ToString().ToLower().Trim();
                                /* if ther was a discount code enter the description into the order now */
                                Discount orderDiscount = Main.Site.Discounts.List.Find(delegate(Discount d) {
                                    return d.Code == t_code;
                                });
                                if(orderDiscount != null) {
                                    discountCode = orderDiscount.Comments.MaxLength(50, true);
                                }
                            }
                            ("Execute SP [dbo].[updateExtOrderInfo]").Debug(7);
                            using(cmd = new SqlCommand(@"dbo.updateExtOrderInfo @orderId,@purchaseOrder,@soldBy,@manifestNumber,@requisitionedBy,
                        @deliverBy,@vendorAccountNumber,@fob,@parentOrderId,@scannedImage,@comments,@approvedBy,@oldSessionId,
                        @uniqueSiteId,@customOrderNumber,@discountCode", cn, orderTransaction)) {
                                cmd.Parameters.Add("@orderId", SqlDbType.Int).Value = orderId;
                                cmd.Parameters.Add("@purchaseOrder", SqlDbType.VarChar).Value = Convert.ToString(args["purchaseOrder"]).MaxLength(100, true);
                                cmd.Parameters.Add("@soldBy", SqlDbType.Int).Value = soldBy;
                                cmd.Parameters.Add("@manifestNumber", SqlDbType.VarChar).Value = Convert.ToString(args["manifestNumber"]).MaxLength(100, true);
                                cmd.Parameters.Add("@requisitionedBy", SqlDbType.Int).Value = soldBy;
                                cmd.Parameters.Add("@deliverBy", SqlDbType.DateTime).Value = deliverBy;
                                cmd.Parameters.Add("@vendorAccountNumber", SqlDbType.VarChar).Value = Convert.ToString(args["vendorAccountNumber"]).MaxLength(50, true);
                                cmd.Parameters.Add("@fob", SqlDbType.VarChar).Value = Convert.ToString(args["FOB"]).MaxLength(50, true);
                                cmd.Parameters.Add("@parentOrderId", SqlDbType.Int).Value = parentOrderId;
                                cmd.Parameters.Add("@scannedImage", SqlDbType.VarChar).Value = Convert.ToString(args["scannedImage"]).MaxLength(50, true);
                                cmd.Parameters.Add("@approvedBy", SqlDbType.Int).Value = approvedBy;
                                cmd.Parameters.Add("@comments", SqlDbType.VarChar).Value = Convert.ToString(args["comments"]).MaxLength(10000, true);
                                cmd.Parameters.Add("@oldSessionId", SqlDbType.UniqueIdentifier).Value = new Guid(session.Id.ToString());
                                cmd.Parameters.Add("@uniqueSiteId", SqlDbType.UniqueIdentifier).Value = new Guid(Site.Id.ToString());
                                cmd.Parameters.Add("@customOrderNumber", SqlDbType.VarChar).Value = customOrderNumber;
                                cmd.Parameters.Add("@discountCode", SqlDbType.VarChar).Value = discountCode;
                                cmd.ExecuteNonQuery();
                            }
                            bool eraseVisitorHistory = false;
                            if(!bool.TryParse(args["eraseVisitorHistory"].ToString(), out eraseVisitorHistory)) {
                                eraseVisitorHistory = false;
                            }
                            if(eraseVisitorHistory) {
                                /* TODO: erase Visitor History.  This was causing a deadlock. maybe do it later? */
                            }
                            /* if there was a scaned image attached move it now */
                            if(((string)args["scannedImage"]).Length > 0) {
                                Admin.StoreScannedImage((string)args["scannedImage"], orderNumber);
                            }
                            if(Main.Site.test_mode) {
                                rollback = true;
                                Exception e = new Exception("placeOrder > __TEST MODE__ - ORDER SUCCESS - __TEST MODE__ >> ROLLBACK!" +
                                " Order Number:" + orderNumber + ",SessionId:" + session.Id.ToString());
                                e.Message.Debug(7);
                                throw e;
                            } else {
                                /* if they had a discount code, remove that now */
                                session.RemoveProperty("discountCode", cn, orderTransaction);
                                session.RemoveProperty("discountDescription", cn, orderTransaction);

                                if(fcn == null) {/* commit transaction if there was no caller transaction */
                                    orderTransaction.Commit();
                                }
                                Commerce.Order order = Commerce.Order.GetOrderByOrderId(orderId, cn, orderTransaction);
                                ("placeOrder > $$$$$$$$$$ <CHA CHING> - ORDER SUCCESS - <CHA CHING> $$$$$$$$$$ Order Number:" + orderNumber).Debug(7);
                                AfterPlaceOrderEventArgs f = new AfterPlaceOrderEventArgs(order, cn, orderTransaction, session, HttpContext.Current);
                                Main.Site.raiseOnplaceorder(f);
                                if(args.ContainsKey("sendOrderConfirmEmail")) {
                                    if(((bool)args["sendOrderConfirmEmail"]) == true) {
                                        try {
                                            Dictionary<string, object> emailArgs = new Dictionary<string, object>();
                                            emailArgs.Add("orderId", orderId);
                                            PlacedOrderEmail(order, cn, orderTransaction);
                                        } catch(Exception e) {
                                            String.Format("Could not send email for orderId {0}. {1}"
                                            , orderId, e.Message).Debug(1);
                                        }
                                    }
                                }
                            }
                            if(fcn == null) {
                                cn.Dispose();
                            }
                            return o;
                        } else {
                            if(fcn == null) {
                                rollback = true;
                            }
                            /* the order failed becuase the user could not provide a convincing enough payment method */
                            o.Remove("error");
                            o.Remove("description");
                            o.Add("error", -2000);
                            o.Add("description", vtDesc);
                            rollback = true;
                            Exception e = new Exception(vtDesc);
                            e.Message.Debug(3);
                            throw e;
                        }
                    } else {
                        /* error occured, error in in the object o */
                        o.Remove("error");
                        o.Remove("description");
                        o.Add("error", errorId);
                        o.Add("description", errorDescription);
                        rollback = true;
                        Exception e = new Exception(errorId.ToString() + ":" + errorDescription);
                        e.Message.Debug(1);
                        throw e;
                    }
                } catch(Exception ex) {
                    o.Remove("error");
                    o.Remove("description");
                    o.Add("error", -500);
                    o.Add("description", ex.Message);
                    ("Exception:" + ex.Message + " SessionId:" + session.Id.ToString()).Debug(1);
                    rollback = true;
                    return o;
                } finally {
                    if(rollback) {
                        if(fcn == null) {
                            orderTransaction.Rollback(transSessionId);
                        }
                    }
                }
            }