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