diff --git a/deep_sequencing_unit/build/build.xml b/deep_sequencing_unit/build/build.xml
index c2ce36d0e357aea998fcf505b0d37a529e69204f..5471f070c10573ec319714cdf824ef1100a33fb7 100644
--- a/deep_sequencing_unit/build/build.xml
+++ b/deep_sequencing_unit/build/build.xml
@@ -19,6 +19,10 @@
 	<property name="dist.createsamplesheet-nov" value="${dist}/createsamplesheet" />
 	<property name="dist.createsamplesheet-nov.lib" value="${dist.createsamplesheet}/lib" />
 	<property name="createsamplesheet-nov.original.dist" value="createsamplesheet/dist" />
+
+	<property name="dist.createInvoices" value="${dist}/createInvoices" />
+	<property name="dist.createInvoices.lib" value="${dist.createInvoices}/lib" />
+	<property name="createInvoices.original.dist" value="createInvoices/dist" />
 	
 	<target name="compile" depends="build-common.compile, clean" />
 
@@ -114,9 +118,35 @@
 					<zipfileset file="${createsamplesheet-nov.original.dist}/createSampleSheet_nov.sh" filemode="755" />
 				</zip>
 			  <delete dir="${dist.createsamplesheet}" />
-		
 	</target>
 
+	<target name="createInvoices-dist">
+		<copy file="source/Jython/create_QGF_Invoices_simplified.py" todir="${dist.createInvoices}" />
+	
+		<copy file="${lib}/commons-codec/commons-codec.jar" todir="${dist.createInvoices.lib}" />
+		<copy file="${lib}/commons-httpclient/commons-httpclient.jar" todir="${dist.createInvoices.lib}" />
+		<copy file="${lib}/commons-logging/commons-logging.jar" todir="${dist.createInvoices.lib}" />
+		<copy file="${lib}/openbis-apis/dss/dss_client.jar" todir="${dist.createInvoices.lib}" />
+		<copy file="${lib}/jython/jython.jar" todir="${dist.createInvoices.lib}" />
+		<copy file="${lib}/spring/spring.jar" todir="${dist.createInvoices.lib}" />
+		<copy file="${lib}/spring/third-party/stream-supporting-httpinvoker.jar" todir="${dist.createInvoices.lib}" />
+		<copy file="${lib}/poi/poi.jar" todir="${dist.createInvoices.lib}" />
+		<copy file="${lib}/poi/poi-ooxml.jar" todir="${dist.createInvoices.lib}" />
+		<copy file="${lib}/poi/poi-ooxml-schemas.jar" todir="${dist.createInvoices.lib}" />
+		<copy file="${lib}/poi/ooxml-lib/xmlbeans-2.3.0.jar" todir="${dist.createInvoices.lib}" />
+		<copy file="${lib}/poi/ooxml-lib/dom4j-1.6.1.jar" todir="${dist.createInvoices.lib}" />
+		<copy file="${lib}/poi/ooxml-lib/geronimo-stax-api_1.0_spec-1.0.jar" todir="${dist.createInvoices.lib}" />
+		<copy file="${lib}/openbis-apis/query/openbis-query-api.jar" todir="${dist.createInvoices.lib}" />
+		
+		<property name="createInvoices.dist.file" value="openbis-createInvoices-${version.number}-r${revision.number}.zip" />
+				<zip basedir="${dist.createInvoices}" destfile="${dist}/${createInvoices.dist.file}" excludes="*.zip *.jar">
+					<zipfileset dir="${createInvoices.original.dist}" excludes="**/*.sh" />
+					<zipfileset file="${createInvoices.original.dist}/createInvoices.sh" filemode="755" />
+
+				</zip>
+			  <delete dir="${dist.createInvoices}" />
+	</target>
+	
 	
 	<target name="jar" depends="compile">
 		<mkdir dir="${dist}" />
@@ -146,7 +176,7 @@
 	<!--
         // Task for creating distributions
         -->
-	<target name="dist" depends="jar, datastore_server.make-plugin-dist, tracking-dist, createsamplesheet-dist, createsamplesheet-nov-dist" />
+	<target name="dist" depends="jar, datastore_server.make-plugin-dist, tracking-dist, createsamplesheet-dist, createsamplesheet-nov-dist,createInvoices-dist" />
 
 	<!--
         // Task for continuous integration server.
diff --git a/deep_sequencing_unit/createInvoices/dist/createInvoices.sh b/deep_sequencing_unit/createInvoices/dist/createInvoices.sh
new file mode 100644
index 0000000000000000000000000000000000000000..74d823767269873bb222bc6859a40087a4cb49b5
--- /dev/null
+++ b/deep_sequencing_unit/createInvoices/dist/createInvoices.sh
@@ -0,0 +1,4 @@
+LIB=/home/sbsuser/openbis/createInvoices/lib/
+CLASSPATH=/home/sbsuser/openbis/createInvoices/lib/
+cd $LIB/..
+java -cp $LIB/dom4j-1.6.1.jar:$LIB/geronimo-stax-api_1.0_spec-1.0.jar:$LIB/openbis-query-api.jar:$LIB/dss_client.jar:jython.jar:$LIB/stream-supporting-httpinvoker.jar:$LIB/spring.jar:commons-logging.jar:$LIB/commons-httpclient.jar:$LIB/commons-codec.jar:$LIB/commons-lang.jar:$LIB/log5j.jar:$LIB/poi.jar:$LIB/poi-ooxml.jar:$LIB/poi-ooxml-schemas.jar org.python.util.jython create_QGF_Invoices_simplified.py "$@"
\ No newline at end of file
diff --git a/deep_sequencing_unit/createInvoices/dist/etc/service.properties b/deep_sequencing_unit/createInvoices/dist/etc/service.properties
new file mode 100644
index 0000000000000000000000000000000000000000..4df364bd8558524a51027b3ac864f45b273383be
--- /dev/null
+++ b/deep_sequencing_unit/createInvoices/dist/etc/service.properties
@@ -0,0 +1,20 @@
+# Config file for QGF Invoicing
+[GENERAL]
+facilityName = Quantitative Genomics Facility
+facilityNameShort = QGF
+facilityInstitution = ETHZ_D-BSSE
+mailList = mail@myinstitute.ch
+mailFrom = invoicing@myinstitute.ch
+smptHost =  <smtpHost>
+separator = ,
+indexSeparator = -
+
+[OPENBIS]
+openbisServer = http://<openbisserver>:8080
+openbisUserName = <username>
+openbisPassword = <password> 
+connectionTimeout = 5000
+principalInvestigator = PRINCIPAL_INVESTIGATOR
+
+[EXCEL]
+defaultFonts = Calibri
diff --git a/deep_sequencing_unit/createInvoices/dist/log/.gitignore b/deep_sequencing_unit/createInvoices/dist/log/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/deep_sequencing_unit/source/Jython/create_QGF_Invoices_simplified.py b/deep_sequencing_unit/source/Jython/create_QGF_Invoices_simplified.py
new file mode 100644
index 0000000000000000000000000000000000000000..49e7933cea2130254d0d11c28ad0a7cde207cc31
--- /dev/null
+++ b/deep_sequencing_unit/source/Jython/create_QGF_Invoices_simplified.py
@@ -0,0 +1,392 @@
+'''
+Copyright 2012 ETH Zuerich, CISD
+  
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+ 
+     http://www.apache.org/licenses/LICENSE-2.0
+ 
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+@author Manuel Kohler
+
+@description:
+Creates Excel-based invoices for the Quantitative Genomics Facility, D-BSSE, ETH Zurich
+
+@attention:
+Runs under Jython
+
+@note:
+
+'''
+
+import os
+import re
+import sys
+import logging
+from datetime import *
+from ConfigParser import SafeConfigParser
+from optparse import OptionParser
+from java.io import FileOutputStream
+from org.apache.poi.hssf.usermodel import HSSFWorkbook
+from org.apache.poi.poifs.filesystem import POIFSFileSystem
+from org.apache.poi.xssf.usermodel import XSSFWorkbook
+from ch.systemsx.cisd.openbis.dss.client.api.v1 import OpenbisServiceFacadeFactory
+from ch.systemsx.cisd.openbis.generic.shared.api.v1.dto import SearchCriteria
+from ch.systemsx.cisd.openbis.generic.shared.api.v1.dto import SearchSubCriteria
+from java.util import EnumSet
+from java.util import TreeMap
+from ch.systemsx.cisd.openbis.generic.shared.api.v1.dto import SampleFetchOption
+
+excelFormats = {"xls": "HSSFWorkbook()" , "xlsx": "XSSFWorkbook()"}
+
+columnHeadersMap = {"EXTERNAL_SAMPLE_NAME": "Sample Name",
+                    "BARCODE": "Index",
+                    "INDEX2": "Index2",
+                    "PREPARED_BY" : "Prepared by",
+                    "KIT" : "Kit",
+                    "CONTACT_PERSON_NAME" : "Contact Person",
+                    "NOTES" : "Notes",
+                    "PRICE" : "Price"}
+
+class uniqueRow():
+  '''
+  Little helper class which ensures the unique use of a row 
+  '''
+  def __init__(self):
+    self.row = -1
+
+  def getNextRow (self):
+    self.row += 1
+    return self.row
+
+  def setRow(self, rowNumber):
+    self.row = rowNumber
+    return self.row
+
+class uniqueColumn():
+  '''
+  Little helper class which ensures the unique use of a column 
+  '''
+  def __init__(self):
+    self.column = -1
+
+  def getCurrentColumn(self):
+    return self.column
+
+  def getNextColumn (self):
+    self.column += 1
+    return self.column
+
+  def setColumn(self, columnNumber):
+    self.column = columnNumber
+    return self.column
+
+def getDate():
+  d = datetime.now()
+  return d.strftime("%A, %d-%B-%Y")
+
+def setFont(wb, configMap, fontSize=10):
+  font = wb.createFont()
+  font.setFontHeightInPoints(fontSize)
+  font.setFontName(configMap["defaultFonts"])
+  font.setItalic(False)
+  font.setStrikeout(False)
+  # Fonts are set into a style so create a new one to use.
+  style = wb.createCellStyle()
+  style.setFont(font)
+  return style
+
+def getVocabulary(service, vocabularyCode):
+  ''' Returns the vocabulary term and vocabulary label of a vocabulary specified by the parameter
+  vocabularyCode in a map'''
+
+  vocabularies = service.listVocabularies()
+  vocabularyMap = {}
+  for vocabulary in vocabularies:
+    if (vocabulary.getCode() == vocabularyCode):
+      terms = vocabulary.getTerms()
+  for term in terms:
+    vocabularyMap[term.getCode()] = term.getLabel()
+  return vocabularyMap
+
+def writeExcel(myoptions, configMap, service, piName, laneDict, sampleDict, piDict,
+                flowCellProperties, flowcellName, format="xls"):
+  '''
+  Writes out all data to an Excel file
+  '''
+
+  myRows = uniqueRow()
+  sequencerVocabulary = getVocabulary(service, "SEQUENCER")
+  setOfFlowcells = set ()
+  runDate, seqId, runningNumber, flowcell = flowcellName.split("_")
+  flowcell = flowcell[1:]
+
+  def writeHeader():
+    # Write header
+    row = sheet.createRow(myRows.getNextRow())
+    row.createCell(0).setCellValue(configMap["facilityName"] + ", " + configMap["facilityInstitution"])
+    row.getCell(0).setCellStyle(setFont(wb, configMap, 14))
+    row1 = sheet.createRow(myRows.getNextRow())
+    row1.createCell(0).setCellValue(getDate())
+    row1.getCell(0).setCellStyle(setFont(wb, configMap, 10))
+
+  def createRow(key="", value="", rowNumber=0, fontSize=10):
+    '''
+    '''
+    if rowNumber == 0:
+      row = sheet.createRow(myRows.getNextRow())
+    else:
+      row = rowNumber
+    row.createCell(0).setCellValue(key)
+    row.createCell(1).setCellValue(value)
+    row.getCell(0).setCellStyle(setFont(wb, configMap, fontSize))
+    row.getCell(1).setCellStyle(setFont(wb, configMap, fontSize))
+    return row
+
+  def writeFooter(service, sheet):
+    footer = sheet.getFooter()
+    footer.setRight("generated on " + datetime.now().strftime("%H:%M - %d.%m.%Y"))
+
+  wb = (eval(excelFormats[format]))
+  createHelper = wb.getCreationHelper()
+  sheet = wb.createSheet(configMap["facilityNameShort"])
+  # 3/2 = 150 percent magnification when opening the workbook
+  sheet.setZoom(3, 2)
+
+  writeHeader()
+  createRow("Principal Investigator", piName)
+
+  createRow("Run Folder Name", flowcellName)
+  createRow()
+
+  myColumns = uniqueColumn()
+
+  sampleHeader = sheet.createRow(myRows.getNextRow())
+  sampleHeader.createCell(myColumns.getNextColumn()).setCellValue("Flow Cell:Lane")
+  sampleHeader.getCell(myColumns.getCurrentColumn()).setCellStyle(setFont(wb, configMap, 10))
+  sampleHeader.createCell(myColumns.getNextColumn()).setCellValue("Sample Code")
+  sampleHeader.getCell(myColumns.getCurrentColumn()).setCellStyle(setFont(wb, configMap, 10))
+  for c in columnHeadersMap:
+    sampleHeader.createCell(myColumns.getNextColumn()).setCellValue(columnHeadersMap[c])
+    sampleHeader.getCell(myColumns.getCurrentColumn()).setCellStyle(setFont(wb, configMap, 10))
+
+  listofLanes = piDict[piName]
+  for lane in listofLanes:
+    singleSampleColumns = uniqueColumn()
+    for sample in sampleDict[lane].keys():
+      rowN = sheet.createRow(myRows.getNextRow())
+      rowN.createCell(singleSampleColumns.getNextColumn()).setCellValue(flowcellName + ":" + str(lane))
+      rowN.getCell(singleSampleColumns.getCurrentColumn()).setCellStyle(setFont(wb, configMap, 10))
+      rowN.createCell(singleSampleColumns.getNextColumn()).setCellValue(sample)
+      rowN.getCell(singleSampleColumns.getCurrentColumn()).setCellStyle(setFont(wb, configMap, 10))
+
+      sampleValues = sampleDict[lane][sample]
+
+      for column in columnHeadersMap.keys():
+        rowN.createCell(singleSampleColumns.getNextColumn()).setCellValue(sampleValues[column])
+        rowN.getCell(singleSampleColumns.getCurrentColumn()).setCellStyle(setFont(wb, configMap, 10))
+
+      singleSampleColumns = uniqueColumn()
+
+  createRow()
+  createRow("Flow Cell Details", "", 0, 14)
+
+  createRow("Flow Cell", flowcell)
+  for property in flowCellProperties:
+    if (property == "SEQUENCER"):
+      val = sequencerVocabulary[flowCellProperties[property]]
+    else:
+      val = flowCellProperties[property]
+
+    createRow(property, val)
+  createRow()
+
+  # adjust width
+  for i in range(0, 20):
+    sheet.autoSizeColumn(i)
+
+  # set layout to landscape
+  sheet.getPrintSetup().setLandscape(True)
+
+  writeFooter(service, sheet)
+
+  #  Write the output to a file
+  fileName = myoptions.outdir + configMap["facilityNameShort"] + "_" + flowcell + "_" + \
+            sanitizeString(piName) + datetime.now().strftime("_%d_%m_%Y.") + format
+  fileOut = FileOutputStream(fileName)
+  print fileName
+
+  wb.write(fileOut);
+  fileOut.close();
+
+def sanitizeString(myString):
+  return re.sub('[^A-Za-z0-9]+', '_', myString)
+
+def setUpLogger(logPath, logLevel=logging.INFO):
+  logFileName = 'createInvoices'
+  d = datetime.now()
+  logFileName = logFileName + '_' + d.strftime('%Y-%m-%d_%H_%M_%S') + '.log'
+  logging.basicConfig(filename=logPath + logFileName,
+                      format='%(asctime)s [%(levelname)s] %(message)s', level=logLevel)
+  logger = logging.getLogger(logFileName)
+  return logger
+
+
+def parseConfigurationFile(propertyFile='etc/service.properties'):
+  '''
+  Parses the given config files and returns the values
+  '''
+  config = SafeConfigParser()
+  config.read(propertyFile)
+  config.sections()
+  return config
+
+def readConfig(logger):
+  GENERAL = 'GENERAL'
+  OPENBIS = 'OPENBIS'
+  EXCEL = 'EXCEL'
+
+  logger.info('Reading config file')
+  configMap = {}
+
+  configParameters = parseConfigurationFile()
+  configMap['facilityName'] = configParameters.get(GENERAL, 'facilityName')
+  configMap['facilityNameShort'] = configParameters.get(GENERAL, 'facilityNameShort')
+  configMap['facilityInstitution'] = configParameters.get(GENERAL, 'facilityInstitution')
+  configMap['mailList'] = configParameters.get(GENERAL, 'mailList')
+  configMap['mailFrom'] = configParameters.get(GENERAL, 'mailFrom')
+  configMap['smptHost'] = configParameters.get(GENERAL, 'smptHost')
+  configMap['separator'] = configParameters.get(GENERAL, 'separator')
+  configMap['indexSeparator'] = configParameters.get(GENERAL, 'indexSeparator')
+
+  configMap['openbisUserName'] = configParameters.get(OPENBIS, 'openbisUserName')
+  configMap['openbisPassword'] = configParameters.get(OPENBIS, 'openbisPassword', raw=True)
+  configMap['openbisServer'] = configParameters.get(OPENBIS, 'openbisServer')
+  configMap['connectionTimeout'] = configParameters.getint(OPENBIS, 'connectionTimeout')
+  configMap['pIPropertyName'] = configParameters.get(OPENBIS, 'pIPropertyName')
+
+  configMap['defaultFonts'] = configParameters.get(EXCEL, 'defaultFonts')
+
+  return configMap
+
+def login(logger, configMap):
+  logger.info('Logging into ' + configMap['openbisServer'])
+  service = OpenbisServiceFacadeFactory.tryCreate(configMap['openbisUserName'],
+                                                  configMap['openbisPassword'],
+                                                  configMap['openbisServer'],
+                                                  configMap['connectionTimeout'])
+  return service
+
+def parseOptions(logger):
+  logger.info('Parsing command line parameters')
+  parser = OptionParser(version='%prog 1.0')
+  parser.add_option('-f', '--flowcell',
+                  dest='flowcell',
+                  help='The flowcell which is used to create the SampleSheet.csv',
+                  metavar='<flowcell>')
+  parser.add_option('-o', '--outdir',
+                  dest='outdir',
+                  default='./',
+                  help='Specify the ouput directory. Default: ./' ,
+                  metavar='<outdir>')
+  parser.add_option('-d', '--debug',
+                  dest='debug',
+                  default=False,
+                  action='store_true',
+                  help='Verbose debug logging. Default: False')
+
+  (options, args) = parser.parse_args()
+
+  if options.outdir[-1] <> '/':
+    options.outdir = options.outdir + '/'
+
+  if options.flowcell is None:
+    parser.print_help()
+    exit(-1)
+  return options
+
+
+def getFLowcellData(service, configMap, flowcell, logger):
+
+  fetchOptions = EnumSet.of(SampleFetchOption.ANCESTORS, SampleFetchOption.PROPERTIES)
+  laneFetchOptions = EnumSet.of(SampleFetchOption.ANCESTORS, SampleFetchOption.PROPERTIES)
+
+  sc = SearchCriteria();
+  sc.addMatchClause(SearchCriteria.MatchClause.createAttributeMatch(SearchCriteria.MatchClauseAttribute.CODE, flowcell));
+  fcList = service.searchForSamples(sc, fetchOptions)
+
+  for p in fcList:
+    flowCellProperties = p.getProperties()
+
+  numberOfLanes = int(flowCellProperties['LANECOUNT'])
+
+  laneDict = {}
+  sampleDict = {}
+  piDict = {}
+
+  for lane in range(1, numberOfLanes + 1):
+    myLane = flowcell + ":" + str(lane)
+    laneSc = SearchCriteria();
+    laneSc.addMatchClause(SearchCriteria.MatchClause.createAttributeMatch(SearchCriteria.MatchClauseAttribute.CODE, myLane));
+    laneList = service.searchForSamples(laneSc, fetchOptions)
+
+    for l in laneList:
+      laneProperties = l.getProperties()
+      laneDict[lane] = laneProperties
+      laneParents = l.getParents()
+
+      s = {}
+      for samples in laneParents:
+        sampleCode = samples.getCode()
+        sampleProperties = samples.getProperties()
+        s[sampleCode] = sampleProperties
+        sampleDict[lane] = s
+        pi = sampleProperties[configMap["pIPropertyName"]]
+
+      if piDict.has_key(pi):
+        piDict[pi].append(lane)
+      else:
+        piDict[pi] = [lane]
+
+  logger.info("Found the following PIs on the lanes: ")
+  logger.info(piDict)
+
+  # simply sort the hashmap
+  treeMap = TreeMap (flowCellProperties)
+  return laneDict, sampleDict, piDict, treeMap
+
+
+'''
+Main script
+'''
+
+def main():
+
+  # for now setting the format by hand
+  format = "xlsx"
+
+  logger = setUpLogger('log/')
+  logger.info('Started Creation Invoices...')
+
+  myoptions = parseOptions(logger)
+  configMap = readConfig(logger)
+
+  service = login(logger, configMap)
+  flowcellName = myoptions.flowcell
+  laneDict, sampleDict, piDict, flowCellProperties = getFLowcellData(service, configMap, flowcellName, logger)
+
+  for piName in piDict:
+    # create an Excel file for each PI
+    writeExcel(myoptions, configMap, service, piName, laneDict, sampleDict, piDict,
+               flowCellProperties, flowcellName, format)
+
+  service.logout()
+
+if __name__ == "__main__":
+    main()