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