aboutsummaryrefslogtreecommitdiffstats
path: root/servo/models
diff options
context:
space:
mode:
Diffstat (limited to 'servo/models')
-rw-r--r--servo/models/common.py4
-rw-r--r--servo/models/device.py15
-rw-r--r--servo/models/note.py119
-rw-r--r--servo/models/order.py10
-rw-r--r--servo/models/parts.py35
-rw-r--r--servo/models/repair.py5
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):
"""