Added the ability to print freezer labels.
[htsworkflow.git] / samplebc / samples / views.py
1 from django.http import HttpResponse, HttpResponseRedirect
2 from samplebc.samples import models
3 from django.core.exceptions import ObjectDoesNotExist
4 from django.template import Context, Template, RequestContext
5 from django.template.loader import get_template
6 from django.shortcuts import render_to_response
7
8 from django.utils.safestring import mark_safe
9
10 from samplebc.samples.forms import FreezerForm, ContainerForm, SampleForm
11 from samplebc.samples.models import Freezer, Container, Sample
12 from samplebc.samples.util import get_uuid, get_sampleid, assign_to_container
13 from samplebc.samples.errors import NoSpaceAvaliable
14 from samplebc import settings
15
16 # Barcode Magic!
17 from samplebc.bcmagic.forms import BarcodeMagicForm
18
19
20 import random
21 import ftplib
22 import StringIO
23
24
25 ################################################
26 # Util functions
27 ################################################
28
29
30 def print_zpl(zpl_text):
31     """
32     Sends zpl_text to printer
33     """
34     ftp = ftplib.FTP(host='131.215.54.194', user='blank', passwd='')
35     ftp.login()
36     ftp.storlines("STOR printme.txt", StringIO.StringIO(zpl_text))
37
38
39 def __center_line(line, width):
40     spaces_to_add = width - len(line)
41     
42     front_half = spaces_to_add / 2
43     back_half = spaces_to_add - front_half
44     
45     return (' ' * front_half) + line + (' ' * back_half)    
46
47
48   
49   
50 ################################################
51 # Container
52 ################################################
53
54 def container_index(request):
55     """
56     Returns an index of available to containers
57     """
58     container_list = Container.objects.all()
59     c = Context({'title': 'Container Index',
60                  'container_list': container_list})
61     t = get_template('container_index.html')
62     
63     return render_to_response('app.html', {
64         'app_name': "HTSW-SampleTracker",
65         'page_name': 'Container Index',
66         'bcmagic': BarcodeMagicForm(),
67         'select': 'container',
68         'body': t.render(c)
69     })
70     
71
72
73     
74 def container_summary(request, container_id):
75     """
76     Returns details of a container
77     """
78     # Retrieve container by UUID
79     try:
80         container = models.Container.objects.get(uuid=container_id)
81     except ObjectDoesNotExist, e:
82         msg = "Container (%s) does not exist." % (container_id)
83         return render_to_response('app.html', {
84             'app_name': settings.HTSW_ST_APPNAME,
85             'page_name': 'Container Summary',
86             'media': '',
87             'bcmagic': BarcodeMagicForm(),
88             'select': 'container',
89             'body': msg
90         })
91     
92     # Retrieve samples from container
93     sample_list = container.sample_set.all()
94     
95     # Prepare a Sample Index of Contained Samples
96     cs = Context({'title': 'Contained Samples',
97                  'sample_list': sample_list})
98     ts = get_template('sample_index.html')
99     
100     # Render prepared samples into container summary
101     cc = Context({'container': container,
102                  'rendered_samples': ts.render(cs) })
103     tc = get_template('container_summary.html')
104     
105     # Render container summary to app html
106     return render_to_response('app.html', {
107         'app_name': settings.HTSW_ST_APPNAME,
108         'page_name': 'Container Summary',
109         'media': '',
110         'bcmagic': BarcodeMagicForm(),
111         'select': 'container',
112         'body': tc.render(cc)
113     })
114
115
116 def container_add(request):
117     """
118     Form for adding a container.
119     """
120     # If user submitted the Container form.
121     if request.method == 'POST':
122         # Fill in ContainerForm with POSTed data.
123         form = ContainerForm(request.POST)
124         
125         # If the form is valid, process it.
126         if form.is_valid():
127             # Create new Container object from form data
128             c_obj = form.save(commit=False)
129             # Added UUID
130             c_obj.uuid = get_uuid()
131             # Save to DB.
132             c_obj.save()
133             # Save the many to many link data.
134             form.save_m2m()
135             return container_summary(request, c_obj.uuid)
136     else:
137         # If users first visit, create empty form.
138         form = ContainerForm()
139         
140     # Load form template
141     c = Context({'form': form,
142                  'action_url': '/samples/container/add/'})
143     t = get_template('generic_form.html')
144
145     return render_to_response('app.html', {
146         'app_name': settings.HTSW_ST_APPNAME,
147         'page_name': 'Container Add',
148         'media': form.media,
149         'bcmagic': BarcodeMagicForm(),
150         'select': 'container',
151         'body': t.render(c)
152     })
153     
154 def container_edit(request, container_id):
155     """
156     Allow editing of a container
157     """
158     try:
159         container = models.Container.objects.get(uuid=container_id)
160     except ObjectDoesNotExist, e:
161         msg = "Container (%s) cannot be edited as it does not exist." % (container_id)
162         return render_to_response('app.html', {
163             'app_name': settings.HTSW_ST_APPNAME,
164             'page_name': 'Container Edit',
165             'media': '',
166             'bcmagic': BarcodeMagicForm(),
167             'select': 'container',
168             'body': msg
169         })
170     
171     # If user submitted the container form.
172     if request.method == 'POST':
173         # Fill in ContainerForm with POSTed data.
174         form = ContainerForm(request.POST, instance=container)
175         
176         # If the form is valid, process it.
177         if form.is_valid():
178             # Save Container object from form data
179             c_obj = form.save(commit=True)
180             # Save many2many changes as well
181             #form.save_m2m() #Not needed when form.save(commit=True)
182             
183             return container_summary(request, c_obj.uuid)
184     else:
185         # If users first visit, create form from Container instance.
186         form = ContainerForm(instance=container)
187
188     # Load form template
189     c = Context({'form': form,
190                  'action_url': '%sedit/' % (container.get_absolute_url())})
191     t = get_template('generic_form.html')
192
193     return render_to_response('app.html', {
194         'app_name': settings.HTSW_ST_APPNAME,
195         'page_name': 'Container Edit',
196         'media': form.media,
197         'bcmagic': BarcodeMagicForm(),
198         'select': 'container',
199         'body': t.render(c)
200     })
201
202
203
204 ################################################
205 # Freezer
206 ################################################
207
208 def freezer_index(request):
209     """
210     Returns an index of available freezers
211     """
212     freezer_list = Freezer.objects.all()
213     c = Context({'freezer_list': freezer_list})
214     t = get_template('freezer_index.html')
215     
216     return render_to_response('app.html', {
217         'app_name': "HTSW-SampleTracker",
218         'page_name': 'Freezer Index',
219         'media': '',
220         'bcmagic': BarcodeMagicForm(),
221         'select': 'freezer',
222         'body': t.render(c)
223     })
224     
225     
226 def freezer_summary(request, freezer_id):
227     """
228     Returns summary of freezer_id
229     """
230     # Retrieve freezer by UUID
231     try:
232         freezer = models.Freezer.objects.get(uuid=freezer_id)
233     except ObjectDoesNotExist, e:
234         msg = "Freezer (%s) does not exist." % (freezer_id)
235         return render_to_response('app.html', {
236                 'app_name': settings.HTSW_ST_APPNAME,
237                 'page_name': 'Freezer Summary',
238                 'media': '',
239                 'bcmagic': BarcodeMagicForm(),
240                 'select': 'freezer',
241                 'body': msg
242                 })
243     
244     # List of contained containers
245     container_list = freezer.container_set.all()
246     
247     
248     # Render prepared container index into freezer summary
249     cf = Context({'freezer': freezer })
250     tf = get_template('freezer_summary.html')
251     
252     # Render Freezer summary to app html
253     return render_to_response('app.html', {
254         'app_name': settings.HTSW_ST_APPNAME,
255         'page_name': 'Freezer Summary',
256         'media': '',
257         'bcmagic': BarcodeMagicForm(),
258         'select': 'freezer',
259         'body': tf.render(cf)
260     })
261
262
263 def freezer_add(request):
264     """
265     Allows you to add a new freezer.
266     """
267     # If user submitted the freezer form.
268     if request.method == 'POST':
269         # Fill in FreezerForm with POSTed data.
270         form = FreezerForm(request.POST)
271         
272         # If the form is valid, process it.
273         if form.is_valid():
274             # Create new Freezer object from form data
275             f_obj = form.save(commit=False)
276             # Added UUID
277             f_obj.uuid = get_uuid()
278             # Save to DB.
279             f_obj.save()
280             return freezer_summary(request, f_obj.uuid)
281     else:
282         # If users first visit, create empty form.
283         form = FreezerForm()
284
285     # Load form template
286     c = Context({'form': form,
287                  'action_url': '/samples/freezer/add/'})
288     t = get_template('generic_form.html')
289
290     return render_to_response('app.html', {
291         'app_name': settings.HTSW_ST_APPNAME,
292         'page_name': 'Freezer Add',
293         'media': form.media,
294         'bcmagic': BarcodeMagicForm(),
295         'select': 'freezer',
296         'body': t.render(c)
297     })
298
299
300 def freezer_edit(request, freezer_id):
301     """
302     Allow editing of a freezer
303     """
304     try:
305         freezer = models.Freezer.objects.get(uuid=freezer_id)
306     except ObjectDoesNotExist, e:
307         msg = "Freezer (%s) cannot be edited as it does not exist." % (freezer_id)
308         return render_to_response('app.html', {
309                 'app_name': settings.HTSW_ST_APPNAME,
310                 'page_name': 'Freezer Summary',
311                 'media': '',
312                 'bcmagic': BarcodeMagicForm(),
313                 'select': 'freezer',
314                 'body': msg
315                 })
316     
317     # If user submitted the freezer form.
318     if request.method == 'POST':
319         # Fill in FreezerForm with POSTed data.
320         form = FreezerForm(request.POST, instance=freezer)
321         
322         # If the form is valid, process it.
323         if form.is_valid():
324             # Save Freezer object from form data
325             f_obj = form.save(commit=True)
326             
327             return freezer_summary(request, f_obj.uuid)
328     else:
329         # If users first visit, create form from freezer instance.
330         form = FreezerForm(instance=freezer)
331
332     # Load form template
333     c = Context({'form': form,
334                  'action_url': '%sedit/' % (freezer.get_absolute_url())})
335     t = get_template('generic_form.html')
336
337     return render_to_response('app.html', {
338         'app_name': settings.HTSW_ST_APPNAME,
339         'page_name': 'Freezer Edit',
340         'media': form.media,
341         'bcmagic': BarcodeMagicForm(),
342         'select': 'freezer',
343         'body': t.render(c)
344     })
345
346
347 def freezer_print(request, freezer_id):
348     """
349     prints a freezer label
350     """
351     
352     try:
353         freezer = models.Freezer.objects.get(uuid=freezer_id)
354     except ObjectDoesNotExist:
355         return HttpResponse('Freezer (%s) does not exist!' % (freezer_id))
356     
357     params = {}
358     params['line1'] = __center_line('', 10)
359     params['line2'] = __center_line('', 14)
360     params['line3'] = __center_line('Temp: %s C' % (freezer.temperature), 15)
361     params['freezer_name'] = __center_line(freezer.name, 16)
362     params['barcode'] = 'frzr|%s' % (freezer.uuid)
363     params['symbol'] = ''
364     
365     c = Context(params)
366     t = get_template('zpl_freezer_label.txt')
367     print_zpl(t.render(c))
368     
369     return HttpResponse('print command for freezer %s sent.' % (freezer.uuid))
370
371 ################################################
372 # Samples
373 ################################################
374
375 def sample_index(request):
376     """
377     return a list of samples and what we can do with them.
378     """
379     sample_list = models.Sample.objects.all()
380     
381     # Load form template
382     c = Context({'title': 'Sample Index',
383                  'sample_list': sample_list})
384     t = get_template('sample_index.html')
385     #html.append('%s <a href="/samples/sample/%s/print">(print)</a>' \
386     #            % (sample, sample.sampleid))
387         
388     return render_to_response('app.html', {
389         'app_name': settings.HTSW_ST_APPNAME,
390         'page_name': 'Samples Index',
391         'media': '',
392         'bcmagic': BarcodeMagicForm(),
393         'select': 'samples',
394         'body': t.render(c)
395     })
396
397
398 def sample_homeless(request):
399     """
400     Returns an index of homeless samples
401     """
402     sample_list = Sample.objects.filter(container=None)
403     c = Context({'title': 'Homeless Samples',
404                  'sample_list': sample_list})
405     t = get_template('sample_homeless.html')
406     
407     return render_to_response('app.html', {
408         'app_name': "HTSW-SampleTracker",
409         'page_name': 'Homeless Samples',
410         'bcmagic': BarcodeMagicForm(),
411         'select': 'samples',
412         'body': t.render(c)
413     })
414     
415     
416 def sample_add(request):
417     """
418     Allow adding of a new sample
419     """
420     ASSIGNED_CONTAINER = False
421     
422     # If user submitted the sample form.
423     if request.method == 'POST':
424         # Fill in SampleForm with POSTed data.
425         form = SampleForm(request.POST)
426         
427         # If the form is valid, process it.
428         if form.is_valid():
429             # Create new Sample object from form data
430             s_obj = form.save(commit=False)
431             
432             # Add sample ID
433             s_obj.sampleid = get_sampleid()
434             
435             # If the user wants us to assign a container.
436             if form.cleaned_data['assign_container']:
437                 # Choose container
438                 try:
439                     assign_to_container(s_obj)
440                     ASSIGNED_CONTAINER = True
441                 except NoSpaceAvaliable, e:
442                     #return HttpResponse("<b>Error:</b> %s<br /><i>You will need to prepare a new container before continuing.</i>" \
443                     #                    % (e))
444                     ASSIGNED_CONTAINER = False
445                                     
446             # Save to DB.
447             s_obj.save()
448             
449             if not ASSIGNED_CONTAINER:
450                 msg = "NOTE: Sample is homeless"
451                 return sample_summary(request, s_obj.sampleid, msg=msg)
452
453             
454             msg = "Sample created."
455             return sample_summary(request, s_obj.sampleid, msg=msg)
456     else:
457         # If users first visit, create empty form.
458         form = SampleForm()
459
460     # Load form template
461     c = Context({'form': form,
462                  'action_url': '/samples/sample/add/'})
463     t = get_template('generic_form.html')
464
465     return render_to_response('app.html', {
466         'app_name': settings.HTSW_ST_APPNAME,
467         'page_name': 'Sample Add',
468         'media': form.media,
469         'bcmagic': BarcodeMagicForm(),
470         'select': 'samples',
471         'body': t.render(c)
472     })
473     
474
475 def sample_edit(request, sampleid):
476     """
477     Allow editing of a sample
478     """
479     try:
480         sample = models.Sample.objects.get(sampleid=sampleid)
481     except ObjectDoesNotExist, e:
482         msg = "Sample (%s) cannot be edited as it does not exist." % (sampleid)
483         return render_to_response('app.html', {
484                     'app_name': settings.HTSW_ST_APPNAME,
485                     'page_name': 'Sample Edit',
486                     'media': '',
487                     'bcmagic': BarcodeMagicForm(),
488                     'select': 'samples',
489                     'body': msg
490                 })
491     
492     # If user submitted the sample form.
493     if request.method == 'POST':
494         # Fill in SampleForm with POSTed data.
495         form = SampleForm(request.POST, instance=sample)
496         
497         # If the form is valid, process it.
498         if form.is_valid():
499             # Save Sample object from form data
500             s_obj = form.save(commit=True)
501             
502             msg = "Sample Update Saved"
503             return sample_summary(request, s_obj.sampleid, msg)
504     else:
505         # If users first visit, create form from sample instance.
506         form = SampleForm(instance=sample)
507
508     # Load form template
509     c = Context({'form': form,
510                  'action_url': '%sedit/' % (sample.get_absolute_url())})
511     t = get_template('generic_form.html')
512
513     return render_to_response('app.html', {
514         'app_name': settings.HTSW_ST_APPNAME,
515         'page_name': 'Sample Edit',
516         'media': form.media,
517         'bcmagic': BarcodeMagicForm(),
518         'select': 'samples',
519         'body': t.render(c)
520     })
521
522
523 def sample_assign_container(request, sampleid):
524     """
525     Assigns sample to container using the assign to container algorithm
526     """
527     
528     sample = Sample.objects.get(sampleid=sampleid)
529     
530     try:
531         assign_to_container(sample)
532     except NoSpaceAvaliable, e:
533         return render_to_response('app.html', {
534         'app_name': settings.HTSW_ST_APPNAME,
535         'page_name': 'Sample Assign',
536         'media': '',
537         'bcmagic': BarcodeMagicForm(),
538         'select': 'samples',
539         'body': mark_safe("<b>Error:</b> %s<br /><i>You will need to prepare a new container before continuing.</i>" \
540                             % (e))
541         })
542         
543     sample.save()
544     
545     body = 'Sample (<a href="%s">%s</a>) assigned to container (<a href="%s">%s</a>)' \
546            % (sample.get_absolute_url(), str(sample), sample.container.get_absolute_url(), str(sample.container))
547     
548     return render_to_response('app.html', {
549             'app_name': settings.HTSW_ST_APPNAME,
550             'page_name': 'Sample Assign',
551             'media': '',
552             'bcmagic': BarcodeMagicForm(),
553             'select': 'samples',
554             'body': mark_safe(body),
555             })
556
557
558 def sample_summary(request, sampleid, msg=None):
559     """
560     Display a summary of a given sample
561     """
562     try:
563         sample = models.Sample.objects.get(sampleid=sampleid)
564     except ObjectDoesNotExist, e:
565         msg = "Sample (%s) does not exist." % (sampleid)
566         return render_to_response('app.html', {
567                     'app_name': settings.HTSW_ST_APPNAME,
568                     'page_name': 'Sample Summary',
569                     'media': '',
570                     'bcmagic': BarcodeMagicForm(),
571                     'select': 'samples',
572                     'body': msg
573                 })
574     
575     c = Context({'sample': sample,
576                  'msg': msg,})
577     t = get_template('sample_summary.html')
578     
579     return render_to_response('app.html', {
580         'app_name': settings.HTSW_ST_APPNAME,
581         'page_name': 'Sample Summary',
582         'media': '',
583         'bcmagic': BarcodeMagicForm(),
584         'select': 'samples',
585         'body': t.render(c)
586     })
587
588     
589 def sample_print(request, sampleid):
590     """
591     prints a sample!
592     """
593     
594     try:
595         sample = models.Sample.objects.get(sampleid=sampleid)
596     except ObjectDoesNotExist:
597         return HttpResponse('Sample (%s) does not exist!' % (sampleid))
598     
599     params = {}
600     params['fullid'] = str(sample)
601     params['sampleid'] = __center_line("s|%s" % (sample.sampleid), 16)
602     params['line1'] = __center_line(sample.name[0:10], 10)
603     params['line2'] = __center_line(sample.name[10:25], 14)
604     params['line3'] = __center_line('ExpType %s' % (sample.sample_type.name[0:8]), 15)
605     params['slot_num'] = random.randint(1,81)
606     
607     c = Context(params)
608     t = get_template('half_inch_samples.txt')
609     print_zpl(t.render(c))
610     
611     return HttpResponse('print command for sample %s sent.' % (sample.sampleid))
612
613
614 ################################################
615 # Barcode Magic Commands
616 ################################################
617
618 def cmd_move_sample(request):
619     """
620     Moves a sample to a target container
621     """
622     return render_to_response('app.html', {
623         'app_name': settings.HTSW_ST_APPNAME,
624         'page_name': 'CMD: Move Sample',
625         'media': '',
626         'bcmagic': BarcodeMagicForm(),
627         'select': 'samples',
628         'body': ""
629     })