78b73fd387ce926f18b63b8f1500b0eea5befa2a
[htsworkflow.git] / htsworkflow / frontend / inventory / views.py
1 from htsworkflow.frontend.samples.changelist import HTSChangeList
2 from htsworkflow.frontend.inventory.models import Item, LongTermStorage, ItemType
3 from htsworkflow.frontend.inventory.admin import ItemAdmin
4 from htsworkflow.frontend.inventory.bcmagic import item_search
5 from htsworkflow.frontend.bcmagic.plugin import register_search_plugin
6 from htsworkflow.frontend.experiments.models import FlowCell
7 from htsworkflow.frontend.bcmagic.forms import BarcodeMagicForm
8 from htsworkflow.frontend.bcmagic.utils import print_zpl_socket
9
10 from django.conf import settings
11 from django.contrib.auth.decorators import login_required
12 from django.core.exceptions import ObjectDoesNotExist
13 from django.http import HttpResponse, HttpResponseRedirect
14 from django.shortcuts import render_to_response
15 from django.template import RequestContext, Template
16 from django.template.loader import get_template
17
18 register_search_plugin('Inventory Item', item_search)
19
20 try:
21     import json
22 except ImportError, e:
23     import simplejson as json
24
25 INVENTORY_CONTEXT_DEFAULTS = {
26     'app_name': 'Inventory Tracker',
27     'bcmagic': BarcodeMagicForm()
28 }
29
30 def __flowcell_rundate_sort(x, y):
31     """
32     Sort by rundate
33     """
34     if x.run_date > y.run_date:
35         return 1
36     elif x.run_date == y.run_date:
37         return 0
38     else:
39         return -1
40
41 def __expand_longtermstorage_context(context, item):
42     """
43     Expand information for LongTermStorage
44     """
45     flowcell_list = []
46     flowcell_id_list = []
47     library_id_list = []
48
49     for lts in item.longtermstorage_set.all():
50         flowcell_list.append(lts.flowcell)
51         flowcell_id_list.append(lts.flowcell.flowcell_id)
52         library_id_list.extend([ lib.id for lib in lts.libraries.all() ])
53
54     flowcell_list.sort(__flowcell_rundate_sort)
55     context['oldest_rundate'] = flowcell_list[0].run_date
56     context['latest_rundate'] = flowcell_list[-1].run_date
57
58     context['flowcell_id_list'] = flowcell_id_list
59     context['library_id_list_1_to_20'] = library_id_list[0:20]
60     context['library_id_list_21_to_40'] = library_id_list[20:40]
61     context['library_id_list_41_to_60'] = library_id_list[40:60]
62     context['library_id_list_61_to_80'] = library_id_list[60:80]
63
64
65 EXPAND_CONTEXT = {
66     'Hard Drive': __expand_longtermstorage_context
67 }
68
69 #INVENTORY_ITEM_PRINT_DEFAULTS = {
70 #    'Hard Drive': 'inventory/hard_drive_shell.zpl',
71 #    'default': 'inventory/default.zpl',
72 #    'host': settings.BCPRINTER_PRINTER1_HOST
73 #}
74
75 def getPrinterTemplateByType(item_type):
76     """
77     returns template to use given item_type
78     """
79     assert item_type.printertemplate_set.count() < 2
80
81     # Get the template for item_type
82     if item_type.printertemplate_set.count() > 0:
83         printer_template = item_type.printertemplate_set.all()[0]
84         return printer_template
85     # Get default
86     else:
87         try:
88             printer_template = PrinterTemplate.objects.get(default=True)
89         except ObjectDoesNotExist:
90             msg = "No template for item type (%s) and no default template found" % (item_type.name)
91             raise ValueError, msg
92
93         return printer_template
94
95
96 @login_required
97 def data_items(request):
98     """
99     Returns items in json format
100     """
101     item_list = Item.objects.all()
102     d = { 'results': len(item_list) }
103     rows = []
104
105     for item in item_list:
106         item_d = {}
107         item_d['uuid'] = item.uuid
108         item_d['barcode_id'] = item.barcode_id
109         item_d['model_id'] = item.item_info.model_id
110         item_d['part_number'] = item.item_info.part_number
111         item_d['lot_number'] = item.item_info.lot_number
112         item_d['vendor'] = item.item_info.vendor.name
113         item_d['creation_date'] = item.creation_date.strftime('%Y-%m-%d %H:%M:%S')
114         item_d['modified_date'] = item.modified_date.strftime('%Y-%m-%d %H:%M:%S')
115         item_d['location'] = item.location.name
116
117         # Item status if exists
118         if item.status is None:
119             item_d['status'] = ''
120         else:
121             item_d['status'] = item.status.name
122
123         # Stored flowcells on device
124         if item.longtermstorage_set.count() > 0:
125             item_d['flowcells'] = ','.join([ lts.flowcell.flowcell_id for lts in item.longtermstorage_set.all() ])
126         else:
127             item_d['flowcells'] = ''
128
129         item_d['type'] = item.item_type.name
130         rows.append(item_d)
131
132     d['rows'] = rows
133
134     return HttpResponse(json.dumps(d), content_type="application/javascript")
135
136 @login_required
137 def all_index(request):
138     """
139     Inventory Index View
140     """
141     # build changelist
142     item_changelist = HTSChangeList(request, Item,
143         list_filter=[],
144         search_fields=[],
145         list_per_page=200,
146         model_admin=ItemAdmin(Item, None)
147     )
148
149     context_dict = {
150         'item_changelist': item_changelist,
151         'page_name': 'Inventory Index'
152     }
153     context_dict.update(INVENTORY_CONTEXT_DEFAULTS)
154
155     return render_to_response('inventory/inventory_all_index.html',
156                               context_dict,
157                               context_instance=RequestContext(request))
158
159 @login_required
160 def index(request):
161     """
162     Inventory Index View
163     """
164     # build changelist
165     item_changelist = HTSChangeList(request, Item,
166         list_filter=['barcode_id',  ],
167         search_fields=[],
168         list_per_page=50,
169         model_admin=ItemAdmin(Item, None)
170     )
171
172     context_dict = {
173         'item_changelist': item_changelist,
174         'page_name': 'Inventory Index'
175     }
176     context_dict.update(INVENTORY_CONTEXT_DEFAULTS)
177
178     return render_to_response('inventory/inventory_index.html',
179                               context_dict,
180                               context_instance=RequestContext(request))
181
182 @login_required
183 def itemtype_index(request, name):
184     """
185     Inventory Index View
186     """
187
188     name = name.replace('%20', ' ')
189
190     itemtype = ItemType.objects.get(name=name)
191
192     # build changelist
193     item_changelist = HTSChangeList(request, Item,
194         list_filter=[],
195         search_fields=[],
196         list_per_page=200,
197         model_admin=ItemAdmin(Item, None)
198     )
199
200     context_dict = {
201         'item_changelist': item_changelist,
202         'page_name': 'Inventory Index'
203     }
204     context_dict.update(INVENTORY_CONTEXT_DEFAULTS)
205
206     return render_to_response('inventory/inventory_itemtype_index.html',
207                               context_dict,
208                               context_instance=RequestContext(request))
209
210
211 @login_required
212 def item_summary_by_barcode(request, barcode_id, msg=''):
213     """
214     Display a summary for an item by barcode
215     """
216     try:
217         item = Item.objects.get(barcode_id=barcode_id)
218     except ObjectDoesNotExist, e:
219         item = None
220
221     return item_summary_by_uuid(request, None, msg, item)
222
223
224 @login_required
225 def item_summary_by_uuid(request, uuid, msg='', item=None):
226     """
227     Display a summary for an item
228     """
229     # Use item instead of looking it up if it is passed.
230     if item is None:
231         try:
232             item = Item.objects.get(uuid=uuid)
233         except ObjectDoesNotExist, e:
234             item = None
235
236     context_dict = {
237         'page_name': 'Item Summary',
238         'item': item,
239         'uuid': uuid,
240         'msg': msg
241     }
242     context_dict.update(INVENTORY_CONTEXT_DEFAULTS)
243
244     return render_to_response('inventory/inventory_summary.html',
245                               context_dict,
246                               context_instance=RequestContext(request))
247
248
249
250
251
252
253 def __expand_context(context, item):
254     """
255     If EXPAND_CONTEXT dictionary has item.item_type.name function registered, use it to expand context
256     """
257     if item.item_type.name in EXPAND_CONTEXT:
258         expand_func = EXPAND_CONTEXT[item.item_type.name]
259         expand_func(context, item)
260
261 def _item_print(item, request):
262     """
263     Prints an item given a type of item label to print
264     """
265     #FIXME: Hard coding this for now... need to abstract later.
266     context = {'item': item}
267     __expand_context(context, item)
268
269     # Print using barcode_id
270     if not item.force_use_uuid and (item.barcode_id is None or len(item.barcode_id.strip())):
271         context['use_uuid'] = False
272         msg = 'Printing item with barcode id: %s' % (item.barcode_id)
273     # Print using uuid
274     else:
275         context['use_uuid'] = True
276         msg = 'Printing item with UUID: %s' % (item.uuid)
277
278     printer_template = getPrinterTemplateByType(item.item_type)
279
280     c = RequestContext(request, context)
281     t = Template(printer_template.template)
282     print_zpl_socket(t.render(c), host=printer_template.printer.ip_address)
283
284     return msg
285
286 @login_required
287 def item_print(request, uuid):
288     """
289     Print a label for a given item
290     """
291     try:
292         item = Item.objects.get(uuid=uuid)
293     except ObjectDoesNotExist, e:
294         item = None
295         msg = "Item with UUID %s does not exist" % (uuid)
296
297     if item is not None:
298         msg = _item_print(item, request)
299
300     return item_summary_by_uuid(request, uuid, msg)
301
302
303 def link_flowcell_and_device(request, flowcell, serial):
304     """
305     Updates database records of a flowcell being archived on a device with a particular serial #
306     """
307     assert flowcell is not None
308     assert serial is not None
309
310     LTS_UPDATED = False
311     SD_UPDATED = False
312     LIBRARY_UPDATED = False
313
314     ###########################################
315     # Retrieve Storage Device
316     try:
317         sd = Item.objects.get(barcode_id=serial)
318     except ObjectDoesNotExist, e:
319         msg = "Item with barcode_id of %s not found." % (serial)
320         raise ObjectDoesNotExist(msg)
321
322     ###########################################
323     # Retrieve FlowCell
324     try:
325         fc = FlowCell.objects.get(flowcell_id__startswith=flowcell)
326     except ObjectDoesNotExist, e:
327         msg = "FlowCell with flowcell_id of %s not found." % (flowcell)
328         raise ObjectDoesNotExist(msg)
329
330     ###########################################
331     # Retrieve or create LongTermStorage Object
332     count = fc.longtermstorage_set.count()
333     lts = None
334     if count > 1:
335         msg = "There really should only be one longtermstorage object per flowcell"
336         raise ValueError, msg
337     elif count == 1:
338         # lts already attached to flowcell
339         lts = fc.longtermstorage_set.all()[0]
340     else:
341         lts = LongTermStorage()
342         # Attach flowcell
343         lts.flowcell = fc
344         # Need a primary keey before linking to storage devices
345         lts.save()
346         LTS_UPDATED = True
347
348
349     ############################################
350     # Link Storage to Flowcell
351
352     # Add a link to this storage device if it is not already linked.
353     if sd not in lts.storage_devices.all():
354         lts.storage_devices.add(sd)
355         SD_UPDATED = True
356
357     ###########################################
358     # Add Library Links to LTS
359
360     for lane in fc.lane_set.all():
361         if lane.library not in lts.libraries.all():
362             lts.libraries.add(lane.library)
363             LIBRARY_UPDATED = True
364
365     # Save Changes
366     lts.save()
367
368     msg = ['Success:']
369     if LTS_UPDATED or SD_UPDATED or LIBRARY_UPDATED:
370         msg.append('  LongTermStorage (LTS) Created: %s' % (LTS_UPDATED))
371         msg.append('   Storage Device Linked to LTS: %s' % (SD_UPDATED))
372         msg.append('       Libraries updated in LTS: %s' % (LIBRARY_UPDATED))
373     else:
374         msg.append('  No Updates Needed.')
375
376     return HttpResponse('\n'.join(msg))