/// <summary>
 /// Execs the place order.
 /// </summary>
 /// <param name="sessionId">The session id.</param>
 /// <param name="userId">The user id.</param>
 /// <param name="paymentMethodId">The payment method id.</param>
 /// <param name="testMode">if set to <c>true</c> [test mode].</param>
 /// <param name="uniqueSiteId">The unique site id.</param>
 /// <param name="cartSessionId">The cart session id.</param>
 /// <param name="purchaseOrder">The purchase order.</param>
 /// <param name="orderDate">The order date.</param>
 /// <param name="termId">The term id.</param>
 /// <param name="discount">The discount.</param>
 /// <param name="cn">The connection being used.</param>
 /// <param name="trans">The transaction being used.</param>
 /// <returns>{error:0,desc:""}</returns>
 private static Dictionary<string, object> ExecPlaceOrder(Guid sessionId, int userId, Guid paymentMethodId,
     bool testMode, Guid uniqueSiteId, Guid cartSessionId, string purchaseOrder, DateTime orderDate,
     int termId, decimal discount, SqlConnection cn, SqlTransaction trans)
 {
     Dictionary<string, object> o = new Dictionary<string, object>();
     List<Guid> addressIds = new List<Guid>();
     List<Commerce.Address> addresses = new List<Commerce.Address>();
     Commerce.Address billToAddress;
     Commerce.Address shipToAddress;
     /* place order */
     SqlCommand cmd = new SqlCommand(@"dbo.placeOrder @sessionId,@userId,@paymentMethodId,@testMode,@unique_site_id,
     @cartSessionId,@purchaseOrder,@orderDate,@termId,@discountAmount", cn, trans);
     /* never timeout */
     cmd.CommandTimeout = 0;
     /* start transaction, if the payment method is not valid then rollback the order */
     cmd.Parameters.Add("@sessionId", SqlDbType.UniqueIdentifier).Value = new Guid(sessionId.ToString());
     cmd.Parameters.Add("@userId", SqlDbType.Int).Value = userId;
     cmd.Parameters.Add("@paymentMethodId", SqlDbType.UniqueIdentifier).Value = new Guid(paymentMethodId.ToString());
     cmd.Parameters.Add("@testMode", SqlDbType.Bit).Value = testMode;
     cmd.Parameters.Add("@unique_site_id", SqlDbType.UniqueIdentifier).Value = new Guid(Main.Site.Defaults.SiteId.ToString());
     cmd.Parameters.Add("@cartSessionId", SqlDbType.UniqueIdentifier).Value = new Guid(cartSessionId.ToString());
     cmd.Parameters.Add("@purchaseOrder", SqlDbType.VarChar).Value = purchaseOrder;
     cmd.Parameters.Add("@orderDate", SqlDbType.DateTime).Value = orderDate;
     cmd.Parameters.Add("@termId", SqlDbType.Int).Value = termId;
     cmd.Parameters.Add("@discountAmount", SqlDbType.Money).Value = discount;
     ("Execute SP [dbo].[placeOrder]").Debug(7);
     using(SqlDataReader raw = cmd.ExecuteReader()) {
         raw.Read();
         o.Add("error", raw.GetInt32(13));
         o.Add("description", raw.GetString(14));
         o.Add("userId", raw.GetInt32(19));
         o.Add("sessionId", raw.GetGuid(20));
         /* if an error occurs these values will not be avaliable (Null) (5=test mode)*/
         if(raw.GetInt32(13) == 0 || raw.GetInt32(13) == 5) {
             o.Add("billToAddressId", raw.GetGuid(0).ToString());
             o.Add("paymentMethodId", raw.GetGuid(1).ToString());
             o.Add("orderNumber", raw.GetString(2).ToString());
             o.Add("subTotal", (float)raw.GetDecimal(3));
             o.Add("grandTotal", (float)raw.GetDecimal(4));
             o.Add("taxTotal", (float)raw.GetDecimal(5));
             o.Add("estShipTotal", (float)raw.GetDecimal(6));
             o.Add("discountTotal", (float)raw.GetDecimal(7));
             o.Add("printState", raw.GetString(8));
             o.Add("concatSerialNumbers", raw.GetString(9));
             o.Add("concatShipmentNumbers", raw.GetString(10));
             o.Add("concatSerialIds", raw.GetString(11));
             o.Add("concatShipmentIds", raw.GetString(12));
             o.Add("orderId", raw.GetInt32(15));
             o.Add("discountPct", raw.GetDouble(16).ToString());
             o.Add("discountCode", raw.GetString(17));
             o.Add("termId", raw.GetInt32(18));
             if(cartSessionId != Guid.Empty) {/* only do this during recalculations */
                 o.Add("previous_grandTotal", (float)raw.GetDecimal(21));
                 o.Add("previous_subTotal", (float)raw.GetDecimal(22));
                 o.Add("previous_taxTotal", (float)raw.GetDecimal(23));
                 o.Add("previous_shipTotal", (float)raw.GetDecimal(24));
                 o.Add("previous_discounted", (float)raw.GetDecimal(25));
                 o.Add("previous_sessionId", raw.GetGuid(26).ToString());
                 o.Add("difference", (float)raw.GetDecimal(4) - (float)raw.GetDecimal(21));
                 if(raw.NextResult()) {
                     /* the addtional records are all the addresses (addressId, shipmentId[-1 in the case of the billToAddressId])associated with the order */
                     while(raw.Read()) {
                         /* add all the addresses to the in memory collection so we can process the credit card */
                         addressIds.Add(raw.GetGuid(0));
                     }
                 }
             }
         }
         raw.Close();
     }
     cmd.Dispose();
     if((int)o["error"] == 5 || (int)o["error"] == 0) {
         if(cartSessionId != Guid.Empty) {/* only do this during recalculations */
             if(addressIds.Count == 2) {
                 foreach(Guid id in addressIds) {
                     addresses.Add(new Commerce.Address(id, cn, trans));
                 }
                 billToAddress = addresses.First(delegate(Commerce.Address adr) {
                     return adr.Id == new Guid(o["billToAddressId"].ToString());
                 });
                 /* any one will do, all should be valid but we'll just check one at random - or whatever order it is C# checks in */
                 shipToAddress = addresses.First(delegate(Commerce.Address adr) {
                     return adr.Id != new Guid(o["billToAddressId"].ToString());
                 });
                 o.Add("billToAddress", billToAddress);
                 o.Add("shipToAddress", shipToAddress);
             } else {
                 string msg = @"Calculation caused an internal error.
             Bill to Address or ship to Address is missing.";
                 o["error"] = 104;
                 o["description"] = msg;
                 Exception ex = new Exception(msg);
                 throw ex;
             }
         }
     } else {
         string msg = o["description"].ToString();
         Exception ex = new Exception(msg);
         throw ex;
     }
     return o;
 }