Flatten project hierarchy, moving djano applications out of htsworkflow.frontend...
[htsworkflow.git] / inventory / models.py
1 from __future__ import absolute_import, print_function
2
3 import logging
4
5 from django.db import models
6 from django.db.models.signals import pre_save
7
8 from samples.models import Library
9 from experiments.models import FlowCell
10 from bcmagic.models import Printer
11
12 LOGGER = logging.getLogger(__name__)
13
14 try:
15     import uuid
16 except ImportError, e:
17     # Some systems are using python 2.4, which doesn't have uuid
18     # this is a stub
19     LOGGER.warning('Real uuid is not available, initializing fake uuid module')
20     class uuid:
21         def uuid1(self):
22             self.hex = None
23             return self
24
25 def _assign_uuid(sender, instance, **kwargs):
26     """
27     Assigns a UUID to model on save
28     """
29     #print 'Entered _assign_uuid'
30     if instance.uuid is None or len(instance.uuid) != 32:
31         instance.uuid = uuid.uuid1().hex
32
33 def _switch_default(sender, instance, **kwargs):
34     """
35     When new instance has default == True, uncheck all other defaults
36     """
37     if instance.default:
38         other_defaults = PrinterTemplate.objects.filter(default=True)
39
40         for other in other_defaults:
41             other.default = False
42             other.save()
43
44
45 class Vendor(models.Model):
46     name = models.CharField(max_length=256)
47     url = models.URLField(blank=True, null=True)
48
49     def __unicode__(self):
50         return u"%s" % (self.name)
51
52
53 class Location(models.Model):
54
55     name = models.CharField(max_length=256, unique=True)
56     location_description = models.TextField()
57
58     uuid = models.CharField(max_length=32, blank=True, help_text="Leave blank for automatic UUID generation", editable=False)
59
60     notes = models.TextField(blank=True, null=True)
61
62     def __unicode__(self):
63         if len(self.location_description) > 16:
64             return u"%s: %s" % (self.name, self.location_description[0:16]+u"...")
65         else:
66             return u"%s: %s" % (self.name, self.location_description)
67
68 pre_save.connect(_assign_uuid, sender=Location)
69
70
71 class ItemInfo(models.Model):
72     model_id = models.CharField(max_length=256, blank=True, null=True)
73     part_number = models.CharField(max_length=256, blank=True, null=True)
74     lot_number = models.CharField(max_length=256, blank=True, null=True)
75
76     url = models.URLField(blank=True, null=True)
77
78     qty_purchased = models.IntegerField(default=1)
79
80     vendor = models.ForeignKey(Vendor)
81     purchase_date = models.DateField(blank=True, null=True)
82     warranty_months = models.IntegerField(blank=True, null=True)
83
84     notes = models.TextField(blank=True, null=True)
85
86     def __unicode__(self):
87         name = u''
88         if self.model_id:
89             name += u"model:%s " % (self.model_id)
90         if self.part_number:
91             name += u"part:%s " % (self.part_number)
92         if self.lot_number:
93             name += u"lot:%s " % (self.lot_number)
94
95         return u"%s: %s" % (name, self.purchase_date)
96
97     class Meta:
98         verbose_name_plural = "Item Info"
99
100
101 class ItemType(models.Model):
102
103     name = models.CharField(max_length=64, unique=True)
104     description = models.TextField(blank=True, null=True)
105
106     def __unicode__(self):
107         return u"%s" % (self.name)
108
109 class ItemStatus(models.Model):
110     name = models.CharField(max_length=64, unique=True)
111     notes = models.TextField(blank=True, null=True)
112
113     def __unicode__(self):
114         return self.name
115
116     class Meta:
117         verbose_name_plural = "Item Status"
118
119
120 class Item(models.Model):
121
122     item_type = models.ForeignKey(ItemType)
123
124     #Automatically assigned uuid; used for barcode if one is not provided in
125     # barcode_id
126     uuid = models.CharField(max_length=32, blank=True, help_text="Leave blank for automatic UUID generation", unique=True, editable=False)
127
128     # field for existing barcodes; used instead of uuid if provided
129     barcode_id = models.CharField(max_length=256, blank=True, null=True)
130     force_use_uuid = models.BooleanField(default=False)
131
132     item_info = models.ForeignKey(ItemInfo)
133
134     location = models.ForeignKey(Location)
135
136     status = models.ForeignKey(ItemStatus, blank=True, null=True)
137
138     creation_date = models.DateTimeField(auto_now_add=True)
139     modified_date = models.DateTimeField(auto_now=True)
140
141     notes = models.TextField(blank=True, null=True)
142
143     def __unicode__(self):
144         if self.barcode_id is None or len(self.barcode_id) == 0:
145             return u"invu|%s" % (self.uuid)
146         else:
147             return u"invb|%s" % (self.barcode_id)
148
149     def get_absolute_url(self):
150         return '/inventory/%s/' % (self.uuid)
151
152 pre_save.connect(_assign_uuid, sender=Item)
153
154
155 class PrinterTemplate(models.Model):
156     """
157     Maps templates to printer to use
158     """
159     item_type = models.ForeignKey(ItemType)
160     printer = models.ForeignKey(Printer)
161
162     default = models.BooleanField(default=False)
163
164     template = models.TextField()
165
166     def __unicode__(self):
167         if self.default:
168             return u'%s %s' % (self.item_type.name, self.printer.name)
169         else:
170             return u'%s %s (default)' % (self.item_type.name, self.printer.name)
171
172 pre_save.connect(_switch_default, sender=PrinterTemplate)
173
174
175 class LongTermStorage(models.Model):
176
177     flowcell = models.ForeignKey(FlowCell)
178     libraries = models.ManyToManyField(Library)
179
180     storage_devices = models.ManyToManyField(Item)
181
182     creation_date = models.DateTimeField(auto_now_add=True)
183     modified_date = models.DateTimeField(auto_now=True)
184
185     def __unicode__(self):
186         return u"%s: %s" % (str(self.flowcell), ', '.join([ str(s) for s in self.storage_devices.iterator() ]))
187
188     class Meta:
189         verbose_name_plural = "Long Term Storage"
190
191
192
193 class ReagentBase(models.Model):
194
195     reagent = models.ManyToManyField(Item)
196
197     creation_date = models.DateTimeField(auto_now_add=True)
198     modified_date = models.DateTimeField(auto_now=True)
199
200     class Meta:
201         abstract = True
202
203
204 class ReagentFlowcell(ReagentBase):
205     """
206     Links reagents and flowcells
207     """
208     flowcell = models.ForeignKey(FlowCell)
209
210     def __unicode__(self):
211         return u"%s: %s" % (str(self.flowcell), ', '.join([ str(s) for s in self.reagent.iterator() ]))
212
213
214 class ReagentLibrary(ReagentBase):
215     """
216     Links libraries and flowcells
217     """
218     library = models.ForeignKey(Library)
219
220     def __unicode__(self):
221         return u"%s: %s" % (str(self.library), ', '.join([ str(s) for s in self.reagent.iterator() ]))