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