diff options
Diffstat (limited to 'servo/models')
-rw-r--r-- | servo/models/common.py | 4 | ||||
-rw-r--r-- | servo/models/device.py | 15 | ||||
-rw-r--r-- | servo/models/note.py | 119 | ||||
-rw-r--r-- | servo/models/order.py | 10 | ||||
-rw-r--r-- | servo/models/parts.py | 35 | ||||
-rw-r--r-- | servo/models/repair.py | 5 |
6 files changed, 166 insertions, 22 deletions
diff --git a/servo/models/common.py b/servo/models/common.py index 4d91296..7a1c79c 100644 --- a/servo/models/common.py +++ b/servo/models/common.py @@ -223,9 +223,11 @@ class GsxAccount(models.Model): def get_shipto_choices(cls): return cls.objects.values_list('ship_to', 'ship_to') - @classmethod def get_default_account(cls): + """ + Returns the default GSX account without connecting to it + """ from servo.lib.utils import empty act_pk = Configuration.conf('gsx_account') diff --git a/servo/models/device.py b/servo/models/device.py index d422f92..0e244fc 100644 --- a/servo/models/device.py +++ b/servo/models/device.py @@ -289,7 +289,7 @@ class Device(models.Model): return gsxws.Product(self.sn) @classmethod - def from_gsx(cls, sn, device=None, cached=True): + def from_gsx(cls, sn, device=None, cached=True, user=None): """ Initialize new Device with warranty info from GSX Or update existing one @@ -308,7 +308,14 @@ class Device(models.Model): raise ValueError(_(u"Invalid input for warranty check: %s") % sn) product = gsxws.Product(sn) - wty = product.warranty() + + if user and user.location: + ship_to = user.location.gsx_shipto + else: + gsx_act = GsxAccount.get_default_account() + ship_to = gsx_act.ship_to + + wty = product.warranty(ship_to=gsx_act.ship_to) model = product.model() if device is None: @@ -440,6 +447,10 @@ class Device(models.Model): return diags.fetch() def get_warranty(self): + """ + Returns latest warranty info from GSX without + updating the Device record + """ return gsxws.Product(self.sn).warranty() def get_repairs(self): diff --git a/servo/models/note.py b/servo/models/note.py index ed8b944..a598a95 100644 --- a/servo/models/note.py +++ b/servo/models/note.py @@ -24,6 +24,7 @@ from django.contrib.contenttypes.fields import GenericRelation from django.template.defaultfilters import truncatechars from django.db.models.signals import pre_delete, post_save +from django.contrib.postgres.fields import ArrayField from mptt.managers import TreeManager from mptt.models import MPTTModel, TreeForeignKey @@ -144,6 +145,18 @@ class Note(MPTTModel): tpl = template.Template(tpl) return tpl.render(template.Context(ctx)) + def get_sender(self): + return self.sender + + def get_creation_date(self): + return self.created_at + + def get_body(self): + return self.body + + def get_title(self): + return self.subject + def render_subject(self, ctx): """ Renders this Markdown body @@ -162,7 +175,7 @@ class Note(MPTTModel): note.parent = self note.order = self.order note.escalation = self.escalation - + def zip_attachments(self): pass @@ -325,7 +338,7 @@ class Note(MPTTModel): def mailto(self): """ Returns the email recipients of this note - Don't use validate_email because addresses may also be in + Don't use validate_email because addresses may also be in Name <email> format (replies to emails) """ to = [] @@ -395,7 +408,7 @@ class Note(MPTTModel): for f in self.attachments.all(): msg.attach_file(f.content.path) - + msg.send() for r in recipients: @@ -458,9 +471,9 @@ class Note(MPTTModel): if not sms_gw: raise ValueError(_("SMS gateway not configured")) - + msg = Message(note=self, recipient=number, created_by=user, body=self.body) - + if sms_gw == 'hqsms': from servo.messaging.sms import HQSMSProvider HQSMSProvider(number, self, msg).send() @@ -523,7 +536,7 @@ class Note(MPTTModel): self.save() - if len(messages) < 1: + if len(messages) < 1: messages = [_('Note saved')] return ', '.join([force_text(m) for m in messages]) @@ -575,7 +588,7 @@ class Message(models.Model): default=METHODS[0][0] ) error = models.TextField() - + def send(self): result = None self.recipient = self.recipient.strip() @@ -600,6 +613,97 @@ class Message(models.Model): unique_together = ('note', 'recipient') +class Article(models.Model): + """ + GSX Communications article or a bit of local news + """ + created_by = models.ForeignKey(User, null=True) + gsx_id = models.CharField(max_length=20, default='', editable=False) + date_created = models.DateField(editable=False) + date_published = models.DateField(null=True) + title = models.TextField(default=_('New Article')) + summary = models.TextField(default='') + content = models.TextField(default='') + PRIORITY_CHOICES = ( + ('HIGH', _('High')), + ('MEDIUM', _('Medium')), + ('LOW', _('Low')), + ) + priority = models.CharField(max_length=128, + choices=PRIORITY_CHOICES, + default=PRIORITY_CHOICES[0][0] + ) + url = models.URLField(default='') + product_model = ArrayField(models.CharField(max_length=128), + null=True, + editable=False) + read_by = ArrayField(models.IntegerField(), default=[]) + flagged_by = ArrayField(models.IntegerField(), default=[]) + + def get_creation_date(self): + return self.date_created + + def get_sender(self): + return self.created_by or 'GSX' + + def get_body(self): + return self.title + + def get_title(self): + return self.title + + def get_read_title(self, user): + if user.pk in self.read_by: + return _('Mark as unread') + + return _('Mark as read') + + def get_flagged_title(self, user): + if user.pk in self.flagged_by: + return _('Mark as unflagged') + + return _('Mark as flagged') + + def toggle_read(self, user): + if user.pk in self.read_by: + self.read_by.remove(user.pk) + else: + self.read_by = self.read_by + [user.pk] + + return self.save() + + def toggle_flagged(self, user): + if user.pk in self.flagged_by: + self.flagged_by.remove(user.pk) + else: + self.flagged_by = self.flagged_by + [user.pk] + + return self.save() + + @classmethod + def from_gsx(cls, article): + """ + Create a local Article from a GSX comms article + """ + from datetime import date + from servo.lib.utils import unescape + aid = article.articleID + + if cls.objects.filter(gsx_id=aid): + raise ValueError('Article %s already exists' % aid) + + a = Article(gsx_id=aid, priority=article.priority) + a.date_created = article.createdDate + a.date_published = date.today() + a.title = unescape(article.articleTitle) + a.summary = unescape(article.articleSummary) + + return a + + class Meta: + app_label = "servo" + + @receiver(pre_delete, sender=Note) def clean_files(sender, instance, **kwargs): instance.attachments.all().delete() @@ -614,4 +718,3 @@ def note_saved(sender, instance, created, **kwargs): if user is not order.user: msg = truncatechars(instance.body, 75) order.notify("note_added", msg, user) - diff --git a/servo/models/order.py b/servo/models/order.py index 8d8eddd..b155f14 100644 --- a/servo/models/order.py +++ b/servo/models/order.py @@ -7,6 +7,7 @@ from django.conf import settings from django.utils import timezone from django.utils.translation import ugettext_lazy as _ +from django.contrib.postgres.fields import ArrayField from django.contrib.contenttypes.fields import GenericRelation from django.dispatch import receiver @@ -1111,9 +1112,16 @@ class OrderDevice(models.Model): order = models.ForeignKey(Order) device = models.ForeignKey(Device) should_report = models.BooleanField(default=True) + repeat_service = models.BooleanField(default=False) + repair_strategies = ArrayField(models.CharField(max_length=100), + help_text='Available repair strategies from GSX', + null=True) def is_repeat_service(self): - from django.utils import timezone + """ + Returns true if this is a repeat (< 30 days from last) service + for this device + """ created_at = self.order.created_at tlimit = timezone.now() - timedelta(days=30) orders = Order.objects.filter(orderdevice__device=self.device, diff --git a/servo/models/parts.py b/servo/models/parts.py index ab54e79..ecea0ad 100644 --- a/servo/models/parts.py +++ b/servo/models/parts.py @@ -6,6 +6,7 @@ import gsxws from django.db import models from django.utils import timezone from django.core.files import File +from django.core.cache import caches from django.utils.translation import ugettext_lazy as _ from servo.models import GsxAccount @@ -18,21 +19,39 @@ def symptom_modifiers(): return gsxws.MODIFIERS +def get_remote_symptom_codes(group): + """ + Remote lookup for symptom codes + """ + symptoms = {} + cache = caches['comptia'] + # First, try to load from global cache (updated every 24h) + data = cache.get('codes') or {} + + if not data: + # ... then try to fetch from GSX + GsxAccount.fallback() + data = gsxws.comptia.fetch() + cache.set('codes', data) + + for k, v in data.get(group): + symptoms[k] = v + + return symptoms + + def symptom_codes(group): """ - Return CompTIA symptom codes for component group + Returns CompTIA symptom codes for component group """ if group == '': return - symptoms = {} - try: - act = GsxAccount.fallback() - codes = gsxws.comptia.fetch()[group] - for k, v in codes: - symptoms[k] = v - except gsxws.GsxError as e: + symptoms = get_remote_symptom_codes(group) + except Exception as e: + # ... finally fall back to local static data + # @FIXME: How do we keep this up to date? data = yaml.load(open("servo/fixtures/comptia.yaml", "r")) symptoms = data[group]['symptoms'] diff --git a/servo/models/repair.py b/servo/models/repair.py index 2836759..93b348d 100644 --- a/servo/models/repair.py +++ b/servo/models/repair.py @@ -285,7 +285,8 @@ class Repair(models.Model): self.connect_gsx(self.created_by) product = gsxws.Product(self.device.sn) parts = [(p.code, p.comptia_code,) for p in self.order.get_parts()] - return product.warranty(parts, self.get_received_date()) + return product.warranty(parts, self.get_received_date(), + ship_to=self.gsx_account.ship_to) def is_open(self): return self.completed_at is None @@ -518,7 +519,7 @@ class Repair(models.Model): User can also be different from the one who initially created the repair. """ account = user or self.created_by - self.gsx_account.connect(account) + return self.gsx_account.connect(account) def set_status(self, new_status, user): """ |