Index: /branches/OaaS/HeuristicLab 3.3 Services.sln
===================================================================
--- /branches/OaaS/HeuristicLab 3.3 Services.sln	(revision 10012)
+++ /branches/OaaS/HeuristicLab 3.3 Services.sln	(revision 10013)
@@ -197,5 +197,4 @@
 		{F685556B-F6EB-4143-8E7E-662D00FDD299}.Release|x86.Build.0 = Release|x86
 		{034C2EE4-E303-4E45-98AB-F0074EC83B81}.Debug|Any CPU.ActiveCfg = Debug
-		{034C2EE4-E303-4E45-98AB-F0074EC83B81}.Debug|Any CPU.Build.0 = Debug
 		{034C2EE4-E303-4E45-98AB-F0074EC83B81}.Debug|Mixed Platforms.ActiveCfg = Debug
 		{034C2EE4-E303-4E45-98AB-F0074EC83B81}.Debug|Mixed Platforms.Build.0 = Debug
Index: /branches/OaaS/HeuristicLab.Services.Hive.DataAccess/3.3/Settings.Designer.cs
===================================================================
--- /branches/OaaS/HeuristicLab.Services.Hive.DataAccess/3.3/Settings.Designer.cs	(revision 10012)
+++ /branches/OaaS/HeuristicLab.Services.Hive.DataAccess/3.3/Settings.Designer.cs	(revision 10013)
@@ -2,5 +2,5 @@
 // <auto-generated>
 //     This code was generated by a tool.
-//     Runtime Version:4.0.30319.269
+//     Runtime Version:4.0.30319.18047
 //
 //     Changes to this file may cause incorrect behavior and will be lost if
@@ -27,5 +27,5 @@
         [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
         [global::System.Configuration.SpecialSettingAttribute(global::System.Configuration.SpecialSetting.ConnectionString)]
-        [global::System.Configuration.DefaultSettingValueAttribute("Data Source=pok6rtjc5c.database.windows.net;Initial Catalog=HeuristicLab.Hive-3.3" +
+        [global::System.Configuration.DefaultSettingValueAttribute("Data Source=y1hi1qbs9d.database.windows.net;Initial Catalog=HeuristicLab.Hive-3.3" +
             ";User ID=cloudia;Password=d1fFntitafvX;Enlist=False")]
         public string HeuristicLab_Hive_LinqConnectionString {
Index: /branches/OaaS/HeuristicLab.Services.Hive.Scaler/HeuristicLab.Services.Optimization.Scaler.csproj
===================================================================
--- /branches/OaaS/HeuristicLab.Services.Hive.Scaler/HeuristicLab.Services.Optimization.Scaler.csproj	(revision 10012)
+++ /branches/OaaS/HeuristicLab.Services.Hive.Scaler/HeuristicLab.Services.Optimization.Scaler.csproj	(revision 10013)
@@ -89,5 +89,7 @@
       <SubType>Designer</SubType>
     </None>
-    <None Include="packages.config" />
+    <None Include="packages.config">
+      <SubType>Designer</SubType>
+    </None>
   </ItemGroup>
   <ItemGroup>
Index: /branches/OaaS/HeuristicLab.Services.Optimization.Billing.Test/App.config
===================================================================
--- /branches/OaaS/HeuristicLab.Services.Optimization.Billing.Test/App.config	(revision 10012)
+++ /branches/OaaS/HeuristicLab.Services.Optimization.Billing.Test/App.config	(revision 10013)
@@ -1,16 +1,18 @@
-﻿<?xml version="1.0" encoding="utf-8"?>
+<?xml version="1.0"?>
 <configuration>
   <configSections>
     <!-- For more information on Entity Framework configuration, visit http://go.microsoft.com/fwlink/?LinkID=237468 -->
-    <section name="entityFramework" type="System.Data.Entity.Internal.ConfigFile.EntityFrameworkSection, EntityFramework, Version=4.4.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" />
+    <section name="entityFramework" type="System.Data.Entity.Internal.ConfigFile.EntityFrameworkSection, EntityFramework, Version=4.4.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false"/>
   </configSections>
   <appSettings>
-    <add key="BillingEngineInterval" value ="00:01:00"/>
+    <add key="BillingEngineInterval" value="00:01:00"/>
+    <add key="LongRunningDbCommandTimeout" value="00:05:00"/>
+    <add key="StorageConnectionString" value="ADJUST_ME"/>
   </appSettings>
   <connectionStrings>
-    <add name="BillingContext" connectionString="ADJUST_ME" providerName="System.Data.SqlClient" />
+    <add name="BillingContext" connectionString="ADJUST_ME" providerName="System.Data.SqlClient"/>
   </connectionStrings>
   <entityFramework>
-    <defaultConnectionFactory type="System.Data.Entity.Infrastructure.SqlConnectionFactory, EntityFramework" />
+    <defaultConnectionFactory type="System.Data.Entity.Infrastructure.SqlConnectionFactory, EntityFramework"/>
   </entityFramework>
-</configuration>
+<startup><supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0"/></startup></configuration>
Index: /branches/OaaS/HeuristicLab.Services.Optimization.Billing.Test/DDLScript.sql
===================================================================
--- /branches/OaaS/HeuristicLab.Services.Optimization.Billing.Test/DDLScript.sql	(revision 10012)
+++ /branches/OaaS/HeuristicLab.Services.Optimization.Billing.Test/DDLScript.sql	(revision 10013)
@@ -18,4 +18,5 @@
     [Due] [datetime] not null,
     [StatusValue] [int] not null,
+    [SubTotal] [float] not null,
     [Total] [float] not null,
     [Tax] [float] not null,
Index: /branches/OaaS/HeuristicLab.Services.Optimization.Billing.Test/HeuristicLab.Services.Optimization.Billing.Test.csproj
===================================================================
--- /branches/OaaS/HeuristicLab.Services.Optimization.Billing.Test/HeuristicLab.Services.Optimization.Billing.Test.csproj	(revision 10012)
+++ /branches/OaaS/HeuristicLab.Services.Optimization.Billing.Test/HeuristicLab.Services.Optimization.Billing.Test.csproj	(revision 10013)
@@ -12,5 +12,6 @@
     <AssemblyName>HeuristicLab.Services.Optimization.Billing.Test</AssemblyName>
     <TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
-    <TargetFrameworkProfile>Client</TargetFrameworkProfile>
+    <TargetFrameworkProfile>
+    </TargetFrameworkProfile>
     <FileAlignment>512</FileAlignment>
   </PropertyGroup>
Index: /branches/OaaS/HeuristicLab.Services.Optimization.Billing.Test/Program.cs
===================================================================
--- /branches/OaaS/HeuristicLab.Services.Optimization.Billing.Test/Program.cs	(revision 10012)
+++ /branches/OaaS/HeuristicLab.Services.Optimization.Billing.Test/Program.cs	(revision 10013)
@@ -9,5 +9,5 @@
 namespace HeuristicLab.Services.Optimization.Billing.Test {
   class Program {
-    private static BillingEngine.BillingEngine billingEngine;
+    private static HeuristicLab.Services.Optimization.Billing.BillingEngine.BillingEngine billingEngine;
     private static Thread billingEngineThread;
 
@@ -15,5 +15,4 @@
       string ddlScript;
       using (var context = new BillingContext()) {
-        System.Data.Entity.Database.SetInitializer(new HeuristicLab.Services.Optimization.Billing.DataAccess.BillingContext.BillingContextInitiliazer());
         ddlScript = (((IObjectContextAdapter)context).ObjectContext.CreateDatabaseScript());
       }
Index: /branches/OaaS/HeuristicLab.Services.Optimization.Billing/BillingEngine/AzureInvoiceDao.cs
===================================================================
--- /branches/OaaS/HeuristicLab.Services.Optimization.Billing/BillingEngine/AzureInvoiceDao.cs	(revision 10013)
+++ /branches/OaaS/HeuristicLab.Services.Optimization.Billing/BillingEngine/AzureInvoiceDao.cs	(revision 10013)
@@ -0,0 +1,61 @@
+﻿using System.Configuration;
+using System.IO;
+using HeuristicLab.Services.Optimization.Billing.Interfaces;
+using Microsoft.WindowsAzure;
+using Microsoft.WindowsAzure.StorageClient;
+
+namespace HeuristicLab.Services.Optimization.Billing.BillingEngine {
+  public class AzureInvoiceDao : IInvoiceDao {
+    private CloudStorageAccount storageAccount;
+    private CloudStorageAccount StorageAccount {
+      get {
+        if (storageAccount == null) {
+          storageAccount = CloudStorageAccount.Parse(ConfigurationManager.AppSettings[AzureConstants.CLOUD_STORAGE_SETTINGS_STRING]);
+        }
+        return storageAccount;
+      }
+    }
+
+    private CloudBlobClient blobClient;
+    private CloudBlobClient BlobClient {
+      get {
+        if (blobClient == null) {
+          blobClient = StorageAccount.CreateCloudBlobClient();
+        }
+        return blobClient;
+      }
+    }
+
+    public AzureInvoiceDao() {
+
+    }
+
+    public bool SaveDocument(string documentName, string contents) {
+      CloudBlobContainer container = BlobClient.GetContainerReference(AzureConstants.INVOICE_BLOB_CONTAINER);
+      container.CreateIfNotExist();
+      var blob = container.GetBlobReference(documentName);
+      blob.UploadText(contents);
+      return true;
+    }
+
+    public string LoadDocument(string documentName) {
+      CloudBlobContainer container = BlobClient.GetContainerReference(AzureConstants.INVOICE_BLOB_CONTAINER);
+      container.CreateIfNotExist();
+      var blob = container.GetBlobReference(documentName);
+      return blob.DownloadText();
+    }
+
+    public void LoadDocument(string documentName, Stream target) {
+      CloudBlobContainer container = BlobClient.GetContainerReference(AzureConstants.INVOICE_BLOB_CONTAINER);
+      container.CreateIfNotExist();
+      var blob = container.GetBlobReference(documentName);
+      blob.DownloadToStream(target);
+    }
+
+
+    private static class AzureConstants {
+      public static readonly string INVOICE_BLOB_CONTAINER = "invoices";
+      public static readonly string CLOUD_STORAGE_SETTINGS_STRING = "StorageConnectionString";
+    }
+  }
+}
Index: /branches/OaaS/HeuristicLab.Services.Optimization.Billing/BillingEngine/BillingEngine.cs
===================================================================
--- /branches/OaaS/HeuristicLab.Services.Optimization.Billing/BillingEngine/BillingEngine.cs	(revision 10012)
+++ /branches/OaaS/HeuristicLab.Services.Optimization.Billing/BillingEngine/BillingEngine.cs	(revision 10013)
@@ -6,4 +6,5 @@
 using System.Linq;
 using System.Threading;
+using System.Transactions;
 using HeuristicLab.Services.Optimization.Billing.Business;
 using HeuristicLab.Services.Optimization.Billing.Interfaces;
@@ -51,4 +52,7 @@
     public void Run() {
       while (!stop) {
+        TransactionOptions options = new TransactionOptions();
+        options.IsolationLevel = IsolationLevel.ReadUncommitted;
+        TransactionScope transaction = new TransactionScope(TransactionScopeOption.Required, options);
         try {
           Trace.WriteLine("[BillingEngine] Start billing cycle");
@@ -58,4 +62,6 @@
           Trace.WriteLine(string.Format("[BillingEngine] Processing {0} active orders.", activeOrders.Count));
           foreach (Order order in activeOrders) {
+            Trace.WriteLine(string.Format("[BillingEngine] Processing order with id: {0}", order.OrderId));
+
             if (!order.NextBillableDay.HasValue) {
               // An invoice has never been generated from this order 
@@ -64,11 +70,11 @@
             }
 
-            if (order.NextBillableDay >= currentDate) {
-              // TODO: Embed everything in a transaction
-
+            if (order.NextBillableDay <= currentDate) {
               // Collect Usage Data
+              Trace.WriteLine("[BillingEngine] Collecting usage data");
               //IList<UsageRecord> usageRecrods = BillingService.GetUsageRecords(order.User.Name, order.LastBillableDay.Value, currentDate);
 
               // Collect Invoice Data
+              Trace.WriteLine("[BillingEngine] Collecting invoice data");
               Invoice invoice = new Invoice();
               invoice.Order = order;
@@ -96,7 +102,16 @@
               // Bill Post Processing: Apply Discounts or Promotions
               // add discounts, sum up items to sub-total, calc. tax -> total current charges
-              // maybe use windows workflow foundation for this task 
+              // maybe use rule execution feature from the windows workflow foundation for this task 
+              Trace.WriteLine("[BillingEngine] Bill post preccessing");
+              double subTotal = 0.0;
+              foreach (InvoiceLine invoiceLine in invoice.InvoiceLines) {
+                subTotal += invoiceLine.ProductPrice;
+              }
+              invoice.SubTotal = subTotal;
+              invoice.Tax = invoice.SubTotal * 0.2;
+              invoice.Total = invoice.SubTotal + invoice.Tax;
 
-              // Invoice Formatting Engine: Generate Invoice 
+              // Invoice Formatting Engine: Generate Invoice
+              Trace.WriteLine("[BillingEngine] Generating invoice document");
               invoice.InvoiceDocument = InvoiceFormattingEngine.Generate(invoice);
 
@@ -104,4 +119,6 @@
               billingService.UpdateOrder(order);
               billingService.SaveInvoice(invoice);
+
+              transaction.Complete();
             }
           }
@@ -112,4 +129,8 @@
           Trace.WriteLine(string.Format("[BillingEngine] The following exception occured: {0}", e.ToString()));
         }
+        finally {
+          transaction.Dispose();
+        }
+
         waitHandle.WaitOne(interval);
       }
Index: /branches/OaaS/HeuristicLab.Services.Optimization.Billing/BillingEngine/FileSystemInvoiceDao.cs
===================================================================
--- /branches/OaaS/HeuristicLab.Services.Optimization.Billing/BillingEngine/FileSystemInvoiceDao.cs	(revision 10013)
+++ /branches/OaaS/HeuristicLab.Services.Optimization.Billing/BillingEngine/FileSystemInvoiceDao.cs	(revision 10013)
@@ -0,0 +1,31 @@
+﻿using System.IO;
+using HeuristicLab.Services.Optimization.Billing.Interfaces;
+
+namespace HeuristicLab.Services.Optimization.Billing.BillingEngine {
+  class FileSystemInvoiceDao : IInvoiceDao {
+    private string rootPath;
+
+    public FileSystemInvoiceDao()
+      : this("") {
+
+    }
+
+    public FileSystemInvoiceDao(string rootPath) {
+      this.rootPath = rootPath;
+    }
+
+    public bool SaveDocument(string documentName, string contents) {
+      File.WriteAllText(rootPath + documentName, contents);
+      return true;
+    }
+
+    public string LoadDocument(string documentName) {
+      return File.ReadAllText(rootPath + documentName);
+    }
+
+    public void LoadDocument(string documentName, System.IO.Stream target) {
+      byte[] contents = File.ReadAllBytes(rootPath + documentName);
+      target = new MemoryStream(contents);
+    }
+  }
+}
Index: /branches/OaaS/HeuristicLab.Services.Optimization.Billing/BillingEngine/PlainTextInvoiceFormattingEngine.cs
===================================================================
--- /branches/OaaS/HeuristicLab.Services.Optimization.Billing/BillingEngine/PlainTextInvoiceFormattingEngine.cs	(revision 10012)
+++ /branches/OaaS/HeuristicLab.Services.Optimization.Billing/BillingEngine/PlainTextInvoiceFormattingEngine.cs	(revision 10013)
@@ -3,4 +3,5 @@
 using System.IO;
 using System.Linq;
+using System.Text.RegularExpressions;
 using System.Windows.Forms;
 using HeuristicLab.Services.Optimization.Billing.Interfaces;
@@ -20,4 +21,14 @@
     private PlainTextInvoiceFormat invoiceFormat;
     private string invoiceOutputPath;
+    private IInvoiceDao invoiceDao;
+
+    private IInvoiceDao InvoiceDao {
+      get {
+        if (invoiceDao == null) {
+          invoiceDao = new FileSystemInvoiceDao();
+        }
+        return invoiceDao;
+      }
+    }
 
     public PlainTextInvoiceFormattingEngine()
@@ -82,6 +93,10 @@
       invoiceText = invoiceText.Replace("{INVOICE_TOTAL}", invoice.Total.ToString("C2").PadLeft(14));
 
+      // remove all escape sequences and replace directory separator with a hyphen 
+      string customerName = Regex.Replace(invoice.User.ContactInformation.OrganizationName, "\\r\\n|\\[bnrt]", "");
+      customerName = customerName.Replace("/", "-");
+
       if (invoiceFormat == PlainTextInvoiceFormat.RTF) {
-        invoiceOutputPath = string.Format("{0}_{1}_{2}.rtf", invoice.InvoiceId, invoice.InvoiceDate.ToString("yyyMMdd"), "{CUSTOMER}");
+        invoiceOutputPath = string.Format("{0}_{1}_{2}.rtf", invoice.InvoiceId, invoice.InvoiceDate.ToString("yyyMMdd"), customerName);
 
         RichTextBox richTextBox = new RichTextBox();
@@ -90,9 +105,11 @@
         richTextBox.SelectionFont = new Font("Consolas", 10, FontStyle.Regular);
 
-        File.WriteAllText(invoiceOutputPath, richTextBox.Rtf);
+        //File.WriteAllText(invoiceOutputPath, richTextBox.Rtf);
+        InvoiceDao.SaveDocument(invoiceOutputPath, richTextBox.Rtf);
       } else if (invoiceFormat == PlainTextInvoiceFormat.TXT) {
-        invoiceOutputPath = string.Format("{0}_{1}_{2}.txt", invoice.InvoiceId, invoice.InvoiceDate.ToString("yyyMMdd"), "{CUSTOMER}");
+        invoiceOutputPath = string.Format("{0}_{1}_{2}.txt", invoice.InvoiceId, invoice.InvoiceDate.ToString("yyyMMdd"), customerName);
 
-        File.WriteAllText(invoiceOutputPath, invoiceText);
+        //File.WriteAllText(invoiceOutputPath, invoiceText);
+        InvoiceDao.SaveDocument(invoiceOutputPath, invoiceText);
       } else if (invoiceFormat == PlainTextInvoiceFormat.PDF) {
         throw new Exception("PDF invoice format is currently not supported");
Index: /branches/OaaS/HeuristicLab.Services.Optimization.Billing/Business/BillingService.cs
===================================================================
--- /branches/OaaS/HeuristicLab.Services.Optimization.Billing/Business/BillingService.cs	(revision 10012)
+++ /branches/OaaS/HeuristicLab.Services.Optimization.Billing/Business/BillingService.cs	(revision 10013)
@@ -19,4 +19,12 @@
     }
 
+    private ITransactionManager transaction;
+    private ITransactionManager Transaction {
+      get {
+        if (transaction == null) transaction = new TransactionManager();
+        return transaction;
+      }
+    }
+
     #endregion
 
@@ -25,12 +33,14 @@
     public IList<Product> GetProducts() {
       //TODO: Authentication
-      //TODO: Enable Transaction
-      return BillingDao.FindAllProducts().ToList();
+      return Transaction.UseTransaction(() => {
+        return BillingDao.FindAllProducts().ToList();
+      });
     }
 
     public IList<Product> GetProductByName(string productName) {
       //TODO: Authentication
-      //TODO: Enable Transaction
-      return BillingDao.FindProdcutBy(prod => prod.Name == productName).ToList();
+      return Transaction.UseTransaction(() => {
+        return BillingDao.FindProdcutBy(prod => prod.Name == productName).ToList();
+      });
     }
 
@@ -41,25 +51,29 @@
     public void SaveOrder(Order order) {
       //TODO: Authentication
-      //TODO: Enable Transaction
-      BillingDao.InsertOrUpdateOrder(order);
+      Transaction.UseTransaction(() => {
+        BillingDao.InsertOrUpdateOrder(order);
+      });
     }
 
     public IList<Order> GetOrdersByState(OrderState state) {
       //TODO: Authentication
-      //TODO: Enable Transaction
-      return BillingDao.FindOrderBy(order => order.StateValue == (int)state).ToList();
+      return Transaction.UseTransaction(() => {
+        return BillingDao.FindOrderBy(order => order.StateValue == (int)state).ToList();
+      });
     }
 
     public IList<Order> GetOrders(string userName) {
       //TODO: Authentication
-      //TODO: Enable Transaction
-      User user = GetUser(userName);
-      return BillingDao.FindOrderBy(order => order.User == user).ToList();
+      return Transaction.UseTransaction(() => {
+        User user = GetUser(userName);
+        return BillingDao.FindOrderBy(order => order.User == user).ToList();
+      });
     }
 
     public void UpdateOrder(Order order) {
       //TODO: Authentication
-      //TODO: Enable Transaction
-      BillingDao.InsertOrUpdateOrder(order);
+      Transaction.UseTransaction(() => {
+        BillingDao.InsertOrUpdateOrder(order);
+      });
     }
 
@@ -70,12 +84,14 @@
     public User GetUser(string userName) {
       //TODO: Authentication
-      //TODO: Enable Transaction
-      return BillingDao.FindUserBy(u => u.Name == userName).First();
+      return Transaction.UseTransaction(() => {
+        return BillingDao.FindUserBy(u => u.Name == userName).First();
+      });
     }
 
     public void SaveUser(User user) {
       //TODO: Authentication
-      //TODO: Enable Transaction
-      BillingDao.InsertOrUpdateUser(user);
+      Transaction.UseTransaction(() => {
+        BillingDao.InsertOrUpdateUser(user);
+      });
     }
 
@@ -86,7 +102,8 @@
     public IList<UsageRecord> GetUsageRecords(string userName) {
       //TODO: Authentication
-      //TODO: Enable Transaction
-      User user = GetUser(userName);
-      return BillingDao.FindUsageRecordsBy(ur => ur.User == user).ToList();
+      return Transaction.UseTransaction(() => {
+        User user = GetUser(userName);
+        return BillingDao.FindUsageRecordsBy(ur => ur.User == user).ToList();
+      });
     }
 
@@ -101,13 +118,15 @@
     public IList<Invoice> GetInvoices(string userName) {
       //TODO: Authentication
-      //TODO: Enable Transaction
-      User user = GetUser(userName);
-      return BillingDao.FindInvoiceBy(inv => inv.User == user).ToList();
+      return Transaction.UseTransaction(() => {
+        User user = GetUser(userName);
+        return BillingDao.FindInvoiceBy(inv => inv.User == user).ToList();
+      });
     }
 
     public void SaveInvoice(Invoice invoice) {
       //TODO: Authentication
-      //TODO: Enable Transaction
-      BillingDao.InsertOrUpdateInvoice(invoice);
+      Transaction.UseTransaction(() => {
+        BillingDao.InsertOrUpdateInvoice(invoice);
+      });
     }
 
Index: /branches/OaaS/HeuristicLab.Services.Optimization.Billing/Business/TransactionManager.cs
===================================================================
--- /branches/OaaS/HeuristicLab.Services.Optimization.Billing/Business/TransactionManager.cs	(revision 10013)
+++ /branches/OaaS/HeuristicLab.Services.Optimization.Billing/Business/TransactionManager.cs	(revision 10013)
@@ -0,0 +1,76 @@
+﻿using System;
+using System.Configuration;
+using System.Data.SqlClient;
+using System.Diagnostics;
+using System.Transactions;
+using HeuristicLab.Services.Optimization.Billing.Interfaces;
+
+namespace HeuristicLab.Services.Optimization.Billing.Business {
+  public class TransactionManager : ITransactionManager {
+    private const int retries = 10;
+    private readonly TimeSpan timeoutInterval;
+
+    public TransactionManager() {
+      timeoutInterval = TimeSpan.Parse(ConfigurationManager.AppSettings["LongRunningDbCommandTimeout"]);
+    }
+
+    public void UseTransaction(System.Action call, bool repeatableRead = false, bool longRunning = false) {
+      int n = retries;
+      while (n > 0) {
+        TransactionScope transaction = CreateTransaction(repeatableRead, longRunning);
+        try {
+          call();
+          transaction.Complete();
+          n = 0;
+        }
+        catch (SqlException ex) {
+          n--;
+          // TODO: log exception
+          Trace.WriteLine(string.Format("Exception occured, repeating transaction {0} more times: {1}", n, ex.ToString()));
+          if (n <= 0) throw;
+        }
+        finally {
+          transaction.Dispose();
+        }
+      }
+    }
+
+    public T UseTransaction<T>(System.Func<T> call, bool repeatableRead = false, bool longRunning = false) {
+      int n = retries;
+      while (n > 0) {
+        TransactionScope transaction = CreateTransaction(repeatableRead, longRunning);
+        try {
+          T result = call();
+          transaction.Complete();
+          n = 0;
+          return result;
+        }
+        catch (SqlException ex) {
+          n--;
+          // TODO: log exception
+          Trace.WriteLine(string.Format("Exception occured, repeating transaction {0} more times: {1}", n, ex.ToString()));
+          if (n <= 0) throw;
+        }
+        finally {
+          transaction.Dispose();
+        }
+      }
+      throw new Exception("This code should not be reached");
+    }
+
+    private TransactionScope CreateTransaction(bool repeatableRead, bool longRunning) {
+      var options = new TransactionOptions();
+      if (repeatableRead) {
+        options.IsolationLevel = IsolationLevel.RepeatableRead;
+      } else {
+        options.IsolationLevel = IsolationLevel.ReadUncommitted;
+      }
+
+      if (longRunning) {
+        options.Timeout = timeoutInterval;
+      }
+
+      return new TransactionScope(TransactionScopeOption.Required, options);
+    }
+  }
+}
Index: /branches/OaaS/HeuristicLab.Services.Optimization.Billing/HeuristicLab.Services.Optimization.Billing.csproj
===================================================================
--- /branches/OaaS/HeuristicLab.Services.Optimization.Billing/HeuristicLab.Services.Optimization.Billing.csproj	(revision 10012)
+++ /branches/OaaS/HeuristicLab.Services.Optimization.Billing/HeuristicLab.Services.Optimization.Billing.csproj	(revision 10013)
@@ -35,4 +35,5 @@
       <HintPath>..\packages\EntityFramework.5.0.0\lib\net40\EntityFramework.dll</HintPath>
     </Reference>
+    <Reference Include="Microsoft.WindowsAzure.StorageClient, Version=1.7.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL" />
     <Reference Include="System" />
     <Reference Include="System.ComponentModel.DataAnnotations" />
@@ -42,4 +43,5 @@
     <Reference Include="System.Drawing" />
     <Reference Include="System.ServiceModel" />
+    <Reference Include="System.Transactions" />
     <Reference Include="System.Windows.Forms" />
     <Reference Include="System.Xml.Linq" />
@@ -50,16 +52,21 @@
   </ItemGroup>
   <ItemGroup>
+    <Compile Include="BillingEngine\AzureInvoiceDao.cs" />
     <Compile Include="BillingEngine\BillingEngine.cs" />
+    <Compile Include="BillingEngine\FileSystemInvoiceDao.cs" />
     <Compile Include="BillingEngine\PlainTextInvoiceFormattingEngine.cs" />
     <Compile Include="Business\BillingService.cs" />
     <Compile Include="Business\BillingServiceProvider.cs" />
+    <Compile Include="Business\TransactionManager.cs" />
     <Compile Include="DataAccess\BillingContext.cs" />
     <Compile Include="DataAccess\BillingDao.cs" />
     <Compile Include="Interfaces\IEntity.cs" />
     <Compile Include="Interfaces\IGenericDao.cs" />
+    <Compile Include="Interfaces\IInvoiceDao.cs" />
     <Compile Include="Interfaces\IInvoiceFormattingEngine.cs" />
     <Compile Include="Interfaces\IObjectWithState.cs" />
     <Compile Include="Interfaces\IOptimizationBilling.cs" />
     <Compile Include="Business\MockupBillingService.cs" />
+    <Compile Include="Interfaces\ITransactionManager.cs" />
     <Compile Include="Model\Model.cs" />
     <Compile Include="Properties\AssemblyInfo.cs" />
Index: /branches/OaaS/HeuristicLab.Services.Optimization.Billing/Interfaces/IInvoiceDao.cs
===================================================================
--- /branches/OaaS/HeuristicLab.Services.Optimization.Billing/Interfaces/IInvoiceDao.cs	(revision 10013)
+++ /branches/OaaS/HeuristicLab.Services.Optimization.Billing/Interfaces/IInvoiceDao.cs	(revision 10013)
@@ -0,0 +1,9 @@
+﻿
+using System.IO;
+namespace HeuristicLab.Services.Optimization.Billing.Interfaces {
+  public interface IInvoiceDao {
+    bool SaveDocument(string documentName, string content);
+    string LoadDocument(string documentName);
+    void LoadDocument(string documentName, Stream target);
+  }
+}
Index: /branches/OaaS/HeuristicLab.Services.Optimization.Billing/Interfaces/ITransactionManager.cs
===================================================================
--- /branches/OaaS/HeuristicLab.Services.Optimization.Billing/Interfaces/ITransactionManager.cs	(revision 10013)
+++ /branches/OaaS/HeuristicLab.Services.Optimization.Billing/Interfaces/ITransactionManager.cs	(revision 10013)
@@ -0,0 +1,8 @@
+﻿using System;
+
+namespace HeuristicLab.Services.Optimization.Billing.Interfaces {
+  public interface ITransactionManager {
+    void UseTransaction(Action call, bool repeatableRead = false, bool longRunning = false);
+    T UseTransaction<T>(Func<T> call, bool repeatableRead = false, bool longRunning = false);
+  }
+}
Index: /branches/OaaS/HeuristicLab.Services.Optimization.Billing/Model/Model.cs
===================================================================
--- /branches/OaaS/HeuristicLab.Services.Optimization.Billing/Model/Model.cs	(revision 10012)
+++ /branches/OaaS/HeuristicLab.Services.Optimization.Billing/Model/Model.cs	(revision 10013)
@@ -151,4 +151,5 @@
     public DateTime Due { get; set; }
     public int StatusValue { get; set; }
+    public double SubTotal { get; set; }
     public double Total { get; set; }
     public double Tax { get; set; }
