diff options
Diffstat (limited to 'servo/management')
30 files changed, 1663 insertions, 0 deletions
diff --git a/servo/management/__init__.py b/servo/management/__init__.py new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/servo/management/__init__.py diff --git a/servo/management/commands/__init__.py b/servo/management/commands/__init__.py new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/servo/management/commands/__init__.py diff --git a/servo/management/commands/backup.py b/servo/management/commands/backup.py new file mode 100644 index 0000000..90c2bd0 --- /dev/null +++ b/servo/management/commands/backup.py @@ -0,0 +1,155 @@ +# -*- coding: utf-8 -*- +# Copyright (c) 2013, First Party Software +# All rights reserved. + +# Redistribution and use in source and binary forms, with or without modification, +# are permitted provided that the following conditions are met: + +# 1. Redistributions of source code must retain the above copyright notice, +# this list of conditions and the following disclaimer. + +# 2. Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. + +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT +# OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +# SUCH DAMAGE. + +import os +import csv +import shutil +import subprocess +from datetime import date +from django.db import connection + +from django.core.management.base import BaseCommand + + +def write(path, header, cursor): + with open(path, 'w') as fout: + writer = csv.writer(fout) + writer.writerow(header) + + for row in cursor.fetchall(): + row = [unicode(s).encode('utf-8') for s in row] + writer.writerow(row) + + +class Command(BaseCommand): + + help = 'Export this servo database in a portable format' + + def handle(self, *args, **options): + backupdir = 'backups/%s' % date.today().isoformat() + os.mkdir(backupdir) + + cursor = connection.cursor() + + path = os.path.join(backupdir, 'notes.csv') + cursor.execute("""SELECT id, order_id, created_by_id, created_at, body + FROM servo_note""") + header = ['ID', 'ORDER_ID', 'USER_ID', 'CREATED_AT', 'NOTE'] + write(path, header, cursor) + + path = os.path.join(backupdir, 'users.csv') + header = ['ID', 'USERNAME', 'FIRST_NAME', 'LAST_NAME', 'EMAIL'] + cursor.execute("""SELECT id, username, first_name, last_name, email + FROM servo_user WHERE is_visible = TRUE""") + write(path, header, cursor) + + path = os.path.join(backupdir, 'orders.csv') + header = ['ID', 'CODE', 'CREATED_AT', + 'CLOSED_AT', 'CUSTOMER_ID', 'USER_ID', 'QUEUE_ID'] + cursor.execute("""SELECT id, code, created_at, closed_at, + customer_id, user_id, queue_id + FROM servo_order""") + write(path, header, cursor) + + path = os.path.join(backupdir, 'queues.csv') + header = ['ID', 'NAME', 'DESCRIPTION', + 'CLOSED_AT', 'CUSTOMER_ID', 'USER_ID', 'QUEUE_ID'] + cursor.execute("""SELECT id, title, description FROM servo_queue""") + write(path, header, cursor) + + path = os.path.join(backupdir, 'devices.csv') + header = ['ID', 'SERIAL_NUMBER', 'IMEI', + 'CONFIGURATION', 'WARRANTY_STATUS', 'PURCHASE_DATE', 'NOTES'] + cursor.execute("""SELECT id, sn, imei, configuration, warranty_status, + purchased_on, notes FROM servo_device""") + write(path, header, cursor) + + path = os.path.join(backupdir, 'repairs.csv') + header = ['ID', 'ORDER_ID', 'DEVICE_ID', 'USER_ID', + 'SUBMITTED_AT', 'COMPLETED_AT', 'REQUEST_REVIEW', + 'TECH_ID', 'UNIT_RECEIVED', 'CONFIRMATION', + 'REFERENCE', 'SYMPTOM', 'DIAGNOSIS', 'NOTES'] + cursor.execute("""SELECT id, order_id, device_id, + created_by_id, submitted_at, completed_at, + request_review, tech_id, unit_received_at, confirmation, reference, + symptom, diagnosis, notes + FROM servo_repair + WHERE submitted_at IS NOT NULL""") + write(path, header, cursor) + + header = ['ID', 'CODE', 'TITLE', 'DESCRIPTION', + 'PRICE_PURCHASE_EXCHANGE', 'PRICE_PURCHASE_STOCK', + 'PRICE_SALES_EXCHANGE', 'PRICE_SALES_STOCK', 'COMPONENT_CODE', + 'PART_TYPE', 'EEE_CODE'] + cursor.execute("""SELECT id, code, title, description, + price_purchase_exchange, price_purchase_stock, + price_sales_exchange, price_sales_stock, + component_code, part_type, eee_code + FROM servo_product""") + path = os.path.join(backupdir, 'products.csv') + write(path, header, cursor) + + header = ['ID', 'PARENT_ID', 'NAME', 'PHONE', 'EMAIL', + 'STREET_ADDRESS', 'POSTAL_CODE', 'CITY' + 'COUNTRY', 'NOTES'] + cursor.execute("""SELECT id, parent_id, name, phone, + email, street_address, zip_code, city, country, notes + FROM servo_customer""") + path = os.path.join(backupdir, 'customers.csv') + write(path, header, cursor) + + path = os.path.join(backupdir, 'order_products.csv') + header = ['ID', 'PRODUCT_ID', 'ORDER_ID', 'CODE', 'TITLE', + 'DESCRIPTION', 'AMOUNT', 'SERIAL_NUMBER', 'KBB_SN', + 'IMEI', 'REPORTED', 'PRICE_CATEGORY', 'PRICE' + 'COMPTIA_CODE', 'COMPTIA_MODIFIER'] + cursor.execute("""SELECT id, product_id, order_id, code, + title, description, amount, sn, price, kbb_sn, + imei, should_report, price_category, price, + comptia_code, comptia_modifier + FROM servo_serviceorderitem""") + write(path, header, cursor) + + path = os.path.join(backupdir, 'parts.csv') + header = ['ID', 'REPAIR_ID', 'ORDER_ITEM_ID', + 'NUMBER', 'TITLE', 'COMPTIA_CODE', 'COMPTIA_MODIFIER', + 'RETURN_ORDER', 'RETURN_STATUS', 'RETURN_CODE', + 'ORDER_STATUS', 'COVERAGE', 'SHIP_TO', 'RETURNED_AT'] + cursor.execute("""SELECT id, repair_id, order_item_id, + part_number, part_title, comptia_code, comptia_modifier, + return_order, return_status, return_code, + order_status, coverage_description, ship_to, returned_at + FROM servo_servicepart""") + write(path, header, cursor) + + path = os.path.join(backupdir, 'order_devices.csv') + header = ['ID', 'ORDER_ID', 'DEVICE_ID', 'REPORTED'] + cursor.execute("""SELECT id, order_id, device_id, should_report + FROM servo_orderdevice""") + write(path, header, cursor) + + subprocess.call(['tar', '-C', backupdir, '-zcf', '%s.tar.gz' % backupdir, '.']) + shutil.rmtree(backupdir, ignore_errors=True) diff --git a/servo/management/commands/checkescalations.py b/servo/management/commands/checkescalations.py new file mode 100644 index 0000000..7a49244 --- /dev/null +++ b/servo/management/commands/checkescalations.py @@ -0,0 +1,71 @@ +# -*- coding: utf-8 -*- +# Copyright (c) 2013, First Party Software +# All rights reserved. + +# Redistribution and use in source and binary forms, with or without modification, +# are permitted provided that the following conditions are met: + +# 1. Redistributions of source code must retain the above copyright notice, +# this list of conditions and the following disclaimer. + +# 2. Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. + +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT +# OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +# SUCH DAMAGE. + +from django.db.models import Q +from django.utils import timezone +from django.core.management.base import BaseCommand, CommandError + +from servo.models import Configuration, Note, User, Escalation + + +class Command(BaseCommand): + help = "Check updates for open escalations" + + def handle(self, *args, **options): + uid = Configuration.conf('imap_act') + + if uid in [None, '']: + return + + user = User.objects.get(pk=uid) + tz = timezone.get_current_timezone() + + for i in Escalation.objects.exclude(Q(escalation_id='') | Q(status='C')): + i.gsx_account.connect(i.created_by) + r = i.get_escalation().lookup() + aware = timezone.make_aware(r.lastModifiedTimestamp, tz) + + if aware < i.updated_at: # hasn't been updated + continue + + try: + parent = i.note_set.latest() + except Note.DoesNotExist: + continue + + bodies = [n.body for n in i.note_set.all()] + + for x in r.escalationNotes.iterchildren(): + if x.text in bodies: # skip notes we already have + continue + + note = Note(created_by=user, escalation=i, body=x.text) + parent.add_reply(note) + note.save() + + i.updated_at = timezone.now() + i.status = r.escalationStatus + i.save() diff --git a/servo/management/commands/checkmail.py b/servo/management/commands/checkmail.py new file mode 100644 index 0000000..891d6aa --- /dev/null +++ b/servo/management/commands/checkmail.py @@ -0,0 +1,58 @@ +# -*- coding: utf-8 -*- +# Copyright (c) 2013, First Party Software +# All rights reserved. + +# Redistribution and use in source and binary forms, with or without modification, +# are permitted provided that the following conditions are met: + +# 1. Redistributions of source code must retain the above copyright notice, +# this list of conditions and the following disclaimer. + +# 2. Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. + +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT +# OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +# SUCH DAMAGE. + +import logging +from email.parser import Parser + +from django.core.management.base import BaseCommand + +from servo.models import Configuration, Note, User + + +class Command(BaseCommand): + help = "Checks IMAP box for new mail" + + def handle(self, *args, **options): + uid = Configuration.conf('imap_act') + + if uid == '': + raise ValueError('Incoming message user not configured') + + user = User.objects.get(pk=uid) + server = Configuration.get_imap_server() + typ, data = server.search(None, "UnSeen") + + for num in data[0].split(): + #logging.debug("** Processing message %s" % num) + typ, data = server.fetch(num, "(RFC822)") + # parsestr() seems to return an email.message? + msg = Parser().parsestr(data[0][1]) + Note.from_email(msg, user) + #server.copy(num, 'servo') + server.store(num, '+FLAGS', '\\Seen') + + server.close() + server.logout() diff --git a/servo/management/commands/cleandups.py b/servo/management/commands/cleandups.py new file mode 100644 index 0000000..fa333bf --- /dev/null +++ b/servo/management/commands/cleandups.py @@ -0,0 +1,42 @@ +# -*- coding: utf-8 -*- +# Copyright (c) 2013, First Party Software +# All rights reserved. + +# Redistribution and use in source and binary forms, with or without modification, +# are permitted provided that the following conditions are met: + +# 1. Redistributions of source code must retain the above copyright notice, +# this list of conditions and the following disclaimer. + +# 2. Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. + +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT +# OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +# SUCH DAMAGE. + +import logging +from django.core.management.base import BaseCommand +from django.template.defaultfilters import slugify + +from servo.models import TaggedItem + + +class Command(BaseCommand): + + help = "Cleans various duplicate data" + + def handle(self, *args, **options): + logging.info("Cleaning up duplicate tags") + for d in TaggedItem.objects.filter(slug=None): + d.slug = slugify(d.description) + d.save() diff --git a/servo/management/commands/cleanphones.py b/servo/management/commands/cleanphones.py new file mode 100644 index 0000000..4bc2371 --- /dev/null +++ b/servo/management/commands/cleanphones.py @@ -0,0 +1,43 @@ +# -*- coding: utf-8 -*- +# Copyright (c) 2013, First Party Software +# All rights reserved. + +# Redistribution and use in source and binary forms, with or without modification, +# are permitted provided that the following conditions are met: + +# 1. Redistributions of source code must retain the above copyright notice, +# this list of conditions and the following disclaimer. + +# 2. Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. + +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT +# OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +# SUCH DAMAGE. + +from django.core.management.base import BaseCommand + +from servo.models import Customer + + +class Command(BaseCommand): + help = "Cleans illegal characters from phone numbers" + + def handle(self, *args, **options): + ALLOWED_CHARS = r'^[\d\s\+\-]+$' + for i in Customer.objects.exclude(phone__regex=ALLOWED_CHARS): + if i.phone == '': + continue + + i.notes = i.notes + i.phone + i.phone = '' + i.save() diff --git a/servo/management/commands/cleanup.py b/servo/management/commands/cleanup.py new file mode 100644 index 0000000..8f6f39e --- /dev/null +++ b/servo/management/commands/cleanup.py @@ -0,0 +1,56 @@ +# -*- coding: utf-8 -*- +# Copyright (c) 2013, First Party Software +# All rights reserved. + +# Redistribution and use in source and binary forms, with or without modification, +# are permitted provided that the following conditions are met: + +# 1. Redistributions of source code must retain the above copyright notice, +# this list of conditions and the following disclaimer. + +# 2. Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. + +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT +# OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +# SUCH DAMAGE. + +import os +import Image +import logging +from glob import glob +from django.core.management.base import BaseCommand + +from servo.models import Attachment + + +class Command(BaseCommand): + + help = "Does various cleanup" + + def handle(self, *args, **options): + size = 128, 128 + logging.info("Building avatar thumbnails") + for infile in glob("servo/uploads/avatars/*.jpg"): + logging.info(infile) + im = Image.open(infile) + im.thumbnail(size, Image.ANTIALIAS) + im.save(infile, "JPEG") + + logging.info("Cleaning up unused attachments") + for infile in glob("servo/uploads/attachments/*"): + fn = infile.decode('utf-8') + fp = os.path.join("attachments", os.path.basename(fn)) + try: + Attachment.objects.get(content=fp) + except Attachment.DoesNotExist: + os.remove(infile) diff --git a/servo/management/commands/clearcache.py b/servo/management/commands/clearcache.py new file mode 100644 index 0000000..826ddef --- /dev/null +++ b/servo/management/commands/clearcache.py @@ -0,0 +1,36 @@ +# -*- coding: utf-8 -*- +# Copyright (c) 2013, First Party Software +# All rights reserved. + +# Redistribution and use in source and binary forms, with or without modification, +# are permitted provided that the following conditions are met: + +# 1. Redistributions of source code must retain the above copyright notice, +# this list of conditions and the following disclaimer. + +# 2. Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. + +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT +# OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +# SUCH DAMAGE. + +from django.core.cache import cache +from django.core.management.base import BaseCommand + + +class Command(BaseCommand): + + help = "Clears this install's cache" + + def handle(self, *args, **options): + cache.clear() diff --git a/servo/management/commands/cron.py b/servo/management/commands/cron.py new file mode 100755 index 0000000..e2831e9 --- /dev/null +++ b/servo/management/commands/cron.py @@ -0,0 +1,164 @@ +# -*- coding: utf-8 -*- +# Copyright (c) 2013, First Party Software +# All rights reserved. + +# Redistribution and use in source and binary forms, with or without modification, +# are permitted provided that the following conditions are met: + +# 1. Redistributions of source code must retain the above copyright notice, +# this list of conditions and the following disclaimer. + +# 2. Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. + +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT +# OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +# SUCH DAMAGE. + +import gsxws +from datetime import date, timedelta + +from django.conf import settings +from django.core.files import File +from django.utils.translation import ugettext as _ + +from django.core.management.base import BaseCommand + +from django.db.models import F +from django.utils import timezone +from django.core.cache import cache + +from servo.models.common import Configuration, Location, CsvTable, GsxAccount +from servo.models import Inventory, Order, PurchaseOrder, User + + +def send_table(sender, recipient, subject, table, send_empty=False): + from django.core.mail import send_mail + if not send_empty and not table.has_body(): + return + + config = Configuration.conf() + settings.EMAIL_HOST = config.get('smtp_host') + settings.EMAIL_USE_TLS = config.get('smtp_ssl') + settings.EMAIL_HOST_USER = config.get('smtp_user') + settings.EMAIL_HOST_PASSWORD = config.get('smtp_password') + + send_mail(subject, unicode(table), sender, [recipient], fail_silently=False) + + +class Command(BaseCommand): + help = "Runs Servo's periodic commands" + + def update_invoices(self): + uid = Configuration.conf('imap_act') + user = User.objects.get(pk=uid) + + for a in GsxAccount.objects.all(): + try: + a.default(user) + lookup = gsxws.Lookup(shipTo=a.ship_to, invoiceDate=date.today()) + invoices = lookup.invoices() + for i in invoices: + details = gsxws.Lookup(invoiceID=i).invoice_details() + # @TODO: What about stock orders? + po = PurchaseOrder.objects.get(pk=details.purchaseOrderNumber) + po.invoice_id = i + po.invoice.save("%s.pdf" % i, File(open(details.invoiceData))) + except Exception, e: + raise e + + def update_warranty(self): + pass + + def notify_aging_repairs(self): + """ + Reports on cases that have been red for a day + """ + conf = Configuration.conf() + + try: + sender = conf['default_sender'] + except KeyError: + raise ValueError('Default sender address not defined') + + now = timezone.now() + limit = now - timedelta(days=1) + locations = Location.objects.filter(site_id=settings.SITE_ID) + + for l in locations: + table = CsvTable() + table.addheader(['Order', 'Assigned To', 'Status', 'Days red']) + + # "Aging" repairs are ones that have been red for at least a day + orders = Order.objects.filter( + location=l, + state__lt=Order.STATE_CLOSED, + status_limit_yellow__lt=limit + ) + + for o in orders: + username = o.get_user_name() or _("Unassigned") + status_title = o.get_status_name() or _("No Status") + days = (now - o.status_limit_yellow).days + table.addrow([o.code, username, status_title, days]) + + subject = _(u"Repairs aging beyond limits at %s") % l.title + + if Configuration.notify_location(): + send_table(sender, l.email, subject, table) + if Configuration.notify_email_address(): + send_table(sender, conf['notify_address'], subject, table) + + def notify_stock_limits(self): + conf = Configuration.conf() + + try: + sender = conf['default_sender'] + except KeyError: + raise ValueError('Default sender address not defined') + + locations = Location.objects.filter(site_id=settings.SITE_ID) + + for l in locations: + out_of_stock = Inventory.objects.filter( + location=l, + amount_stocked__lt=F('amount_minimum') + ) + + table = CsvTable() + table.addheader(['Product', 'Minimum', 'Stocked']) + + for i in out_of_stock: + table.addrow([i.product.code, i.amount_minimum, i.amount_stocked]) + + subject = _(u"Products stocked below limit") + + if Configuration.notify_location(): + send_table(sender, l.email, subject, table) + if Configuration.notify_email_address(): + send_table(sender, conf['notify_address'], subject, table) + + def update_counts(self): + now = timezone.now() + orders = Order.objects.filter(state__lt=Order.STATE_CLOSED) + green = orders.filter(status_limit_green__gte=now) + cache.set('green_order_count', green.count()) + yellow = orders.filter(status_limit_yellow__gte=now) + cache.set('yellow_order_count', yellow.count()) + red = orders.filter(status_limit_yellow__lte=now) + cache.set('red_order_count', red.count()) + + def handle(self, *args, **options): + #self.update_invoices() + self.update_counts() + self.notify_aging_repairs() + self.notify_stock_limits() diff --git a/servo/management/commands/dbbackup.py b/servo/management/commands/dbbackup.py new file mode 100644 index 0000000..91d3875 --- /dev/null +++ b/servo/management/commands/dbbackup.py @@ -0,0 +1,43 @@ +# -*- coding: utf-8 -*- +# Copyright (c) 2013, First Party Software +# All rights reserved. + +# Redistribution and use in source and binary forms, with or without modification, +# are permitted provided that the following conditions are met: + +# 1. Redistributions of source code must retain the above copyright notice, +# this list of conditions and the following disclaimer. + +# 2. Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. + +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT +# OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +# SUCH DAMAGE. + +import sys +import logging +import subprocess +from django.conf import settings +from django.core.management.base import BaseCommand + + +class Command(BaseCommand): + help = 'Backup this Servo database' + def handle(self, *args, **options): + if len(args) < 1: + print 'Usage: dbbackup file' + sys.exit(1) + db = settings.DATABASES['default'] + pg_dump = subprocess.check_output(['which', 'pg_dump']).strip() + subprocess.call([pg_dump, '-Fc', db['NAME'], '-U', db['USER'], + '-f' , args[0]], env={'PGPASSWORD': db['PASSWORD']}) diff --git a/servo/management/commands/dbdump.py b/servo/management/commands/dbdump.py new file mode 100644 index 0000000..12023c4 --- /dev/null +++ b/servo/management/commands/dbdump.py @@ -0,0 +1,37 @@ +# -*- coding: utf-8 -*- +# Copyright (c) 2013, First Party Software +# All rights reserved. + +# Redistribution and use in source and binary forms, with or without modification, +# are permitted provided that the following conditions are met: + +# 1. Redistributions of source code must retain the above copyright notice, +# this list of conditions and the following disclaimer. + +# 2. Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. + +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT +# OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +# SUCH DAMAGE. + +import subprocess +from django.conf import settings +from django.core.management.base import BaseCommand + + +class Command(BaseCommand): + help = "Dumps DB of this instance to specified file" + + def handle(self, *args, **options): + dbname = settings.DATABASES['default']['NAME'] + #subprocess.call('pg_dump', '-Fc', dbname, '-U', 'pgsql' > "${BACKUPDIR}/${db}_$(date "+%Y%m%d_%H%M").pgdump" diff --git a/servo/management/commands/dbrestore.py b/servo/management/commands/dbrestore.py new file mode 100644 index 0000000..640d3d6 --- /dev/null +++ b/servo/management/commands/dbrestore.py @@ -0,0 +1,42 @@ +# -*- coding: utf-8 -*- +# Copyright (c) 2013, First Party Software +# All rights reserved. + +# Redistribution and use in source and binary forms, with or without modification, +# are permitted provided that the following conditions are met: + +# 1. Redistributions of source code must retain the above copyright notice, +# this list of conditions and the following disclaimer. + +# 2. Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. + +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT +# OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +# SUCH DAMAGE. + +import subprocess +from django.conf import settings +from django.core.management.base import BaseCommand + + +class Command(BaseCommand): + help = 'Restore this Servo database from backup' + def handle(self, *args, **options): + if len(args) < 1: + print 'Usage: dbrestore file' + sys.exit(1) + + db = settings.DATABASES['default'] + pg_restore = subprocess.check_output(['which', 'pg_restore']).strip() + subprocess.call([pg_restore, '-d', db['NAME'], '-O', '-x', '-U', db['USER'], + args[0]], env={'PGPASSWORD': db['PASSWORD']}) diff --git a/servo/management/commands/deleteorders.py b/servo/management/commands/deleteorders.py new file mode 100644 index 0000000..e531029 --- /dev/null +++ b/servo/management/commands/deleteorders.py @@ -0,0 +1,54 @@ +# -*- coding: utf-8 -*- +# Copyright (c) 2013, First Party Software +# All rights reserved. + +# Redistribution and use in source and binary forms, with or without modification, +# are permitted provided that the following conditions are met: + +# 1. Redistributions of source code must retain the above copyright notice, +# this list of conditions and the following disclaimer. + +# 2. Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. + +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT +# OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +# SUCH DAMAGE. + +import logging +from django.core.management.base import BaseCommand + +from servo.models import (Order, Repair,) + +class Command(BaseCommand): + help = "Deletes orders listed in text file" + + def handle(self, *args, **options): + if len(args) < 1: + print 'Usage: deleteorders data.txt' + sys.exit(1) + + counter = 0 + dataf = open(args[0], 'r') + + for l in dataf.readlines(): + cols = l.strip().split("\t") + try: + print 'Deleting order %s' % cols[0] + order = Order.objects.get(code=cols[0]) + Repair.objects.filter(order=order).delete() + order.delete() + counter += 1 + except Order.DoesNotExist: + pass + + print '%d orders deleted' % counter diff --git a/servo/management/commands/fixfollowers.py b/servo/management/commands/fixfollowers.py new file mode 100644 index 0000000..bd8e1cb --- /dev/null +++ b/servo/management/commands/fixfollowers.py @@ -0,0 +1,43 @@ +# -*- coding: utf-8 -*- +# Copyright (c) 2013, First Party Software +# All rights reserved. + +# Redistribution and use in source and binary forms, with or without modification, +# are permitted provided that the following conditions are met: + +# 1. Redistributions of source code must retain the above copyright notice, +# this list of conditions and the following disclaimer. + +# 2. Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. + +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT +# OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +# SUCH DAMAGE. + +from django.core.management.base import BaseCommand + +from servo.models import Event + + +class Command(BaseCommand): + help = "Fixes missing follower data from event logs" + + def handle(self, *args, **options): + for i in Event.objects.filter(action='set_user'): + user = i.triggered_by + order = i.content_object + if order.user is None and 'unassigned' not in i.description: + print('Assigning %s to %s' % (order, user)) + order.add_follower(user) + order.user = i.triggered_by + order.save() diff --git a/servo/management/commands/fixproducts.py b/servo/management/commands/fixproducts.py new file mode 100644 index 0000000..9767ab4 --- /dev/null +++ b/servo/management/commands/fixproducts.py @@ -0,0 +1,43 @@ +# -*- coding: utf-8 -*- +# Copyright (c) 2013, First Party Software +# All rights reserved. + +# Redistribution and use in source and binary forms, with or without modification, +# are permitted provided that the following conditions are met: + +# 1. Redistributions of source code must retain the above copyright notice, +# this list of conditions and the following disclaimer. + +# 2. Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. + +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT +# OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +# SUCH DAMAGE. + +from django.core.management.base import BaseCommand +from django.template.defaultfilters import slugify + +from servo.models import ServiceOrderItem, Product + + +class Command(BaseCommand): + help = "Fixes SOI and Product codes that include spaces" + + def handle(self, *args, **options): + for i in Product.objects.filter(code__contains=' '): + i.code = slugify(i.code) + i.save() + + for i in ServiceOrderItem.objects.filter(code__contains=' '): + i.code = slugify(i.code) + i.save() diff --git a/servo/management/commands/fixtimestamps.py b/servo/management/commands/fixtimestamps.py new file mode 100644 index 0000000..81e1cdb --- /dev/null +++ b/servo/management/commands/fixtimestamps.py @@ -0,0 +1,46 @@ +# -*- coding: utf-8 -*- +# Copyright (c) 2013, First Party Software +# All rights reserved. + +# Redistribution and use in source and binary forms, with or without modification, +# are permitted provided that the following conditions are met: + +# 1. Redistributions of source code must retain the above copyright notice, +# this list of conditions and the following disclaimer. + +# 2. Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. + +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT +# OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +# SUCH DAMAGE. + +from django.core.management.base import BaseCommand +from django.template.defaultfilters import slugify +from django.contrib.contenttypes.models import ContentType + +from servo.models import OrderStatus + + +class Command(BaseCommand): + help = "Fixes finished_at timestamps of OrderStatuses" + + def handle(self, *args, **options): + for s in OrderStatus.objects.all(): + next_status = s.get_next() + + if next_status is None: + continue # current status + + s.finished_at = next_status.started_at + s.duration = (s.finished_at - s.started_at).total_seconds() + s.save() diff --git a/servo/management/commands/importparts.py b/servo/management/commands/importparts.py new file mode 100644 index 0000000..8df1ecb --- /dev/null +++ b/servo/management/commands/importparts.py @@ -0,0 +1,127 @@ +# -*- coding: utf-8 -*- +# Copyright (c) 2013, First Party Software +# All rights reserved. + +# Redistribution and use in source and binary forms, with or without modification, +# are permitted provided that the following conditions are met: + +# 1. Redistributions of source code must retain the above copyright notice, +# this list of conditions and the following disclaimer. + +# 2. Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. + +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT +# OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +# SUCH DAMAGE. + +import re +import os +import logging + +from decimal import Decimal, InvalidOperation, ROUND_CEILING + +from django.db import DatabaseError +from django.core.management.base import BaseCommand +from django.contrib.contenttypes.models import ContentType + +from servo.models import Product, TaggedItem + + +class Command(BaseCommand): + + help = "Imports complete GSX parts database" + + def handle(self, *args, **options): + + update_prices = True + import_vintage = True + dbpath = "servo/uploads/products/partsdb.csv" + + try: + partsdb = open(dbpath, "r") + except Exception: + pass + + content_type = ContentType.objects.get(model="product") + + for l in partsdb.readlines(): + + line = l.decode("iso-8859-1") + row = line.strip().split("\t") + + if row[5] == "" or row[5] == "Currency": + continue # Skip header row and rows without currency + + logging.debug(row) + + category = row[0] + + if re.match(r'~VIN', category) and not import_vintage: + continue # Skip vintage devices if so desired + + p_number = row[1] + + if re.match(r'675-', p_number): + continue # Skip DEPOT REPAIR INVOICE + + p_title = row[2] + p_type = row[3] + lab_tier = row[4] + + try: + stock_price = Decimal(row[6]) + except InvalidOperation: + continue # Skip parts with no stock price + + exchange_price = Decimal(row[7]) + + eee_code = row[8] + + # skip substitute + component_group = row[10] or None + is_serialized = row[11] + req_diag = (row[12] == "Y") + + product, created = Product.objects.get_or_create(code=p_number) + + product.title = p_title + product.eee_code = eee_code + product.labour_tier = lab_tier + product.part_type = p_type or "OTHER" + + product.component_code = component_group + product.is_serialized = (is_serialized == "Y") + + if update_prices: + if stock_price: + purchase_sp = Decimal(stock_price) + product.price_purchase_stock = purchase_sp.to_integral_exact(rounding=ROUND_CEILING) + product.set_stock_sales_price() + + if exchange_price: + purchase_ep = Decimal(exchange_price) + product.price_purchase_exchange = purchase_ep.to_integral_exact(rounding=ROUND_CEILING) + product.set_exchange_sales_price() + + product.save() + + try: + tag, created = TaggedItem.objects.get_or_create( + content_type=content_type, + object_id=product.pk, + tag=category) + tag.save() + except DatabaseError: + pass + + os.unlink(dbpath) diff --git a/servo/management/commands/migratepayments.py b/servo/management/commands/migratepayments.py new file mode 100644 index 0000000..84c5c40 --- /dev/null +++ b/servo/management/commands/migratepayments.py @@ -0,0 +1,44 @@ +# -*- coding: utf-8 -*- +# Copyright (c) 2013, First Party Software +# All rights reserved. + +# Redistribution and use in source and binary forms, with or without modification, +# are permitted provided that the following conditions are met: + +# 1. Redistributions of source code must retain the above copyright notice, +# this list of conditions and the following disclaimer. + +# 2. Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. + +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT +# OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +# SUCH DAMAGE. + +import logging + +from django.core.management.base import BaseCommand, CommandError + +from servo.models import Invoice, Payment + + +class Command(BaseCommand): + help = "Migrate invoice payment info to Payments" + + def handle(self, *args, **options): + Payment.objects.all().delete() + for i in Invoice.objects.all(): + p = Payment(invoice=i, method=i.payment_method) + p.created_at = i.paid_at + p.created_by = i.created_by + p.amount = i.total_gross + p.save() diff --git a/servo/management/commands/migratestatuses.py b/servo/management/commands/migratestatuses.py new file mode 100644 index 0000000..e6ca601 --- /dev/null +++ b/servo/management/commands/migratestatuses.py @@ -0,0 +1,54 @@ +# -*- coding: utf-8 -*- +# Copyright (c) 2013, First Party Software +# All rights reserved. + +# Redistribution and use in source and binary forms, with or without modification, +# are permitted provided that the following conditions are met: + +# 1. Redistributions of source code must retain the above copyright notice, +# this list of conditions and the following disclaimer. + +# 2. Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. + +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT +# OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +# SUCH DAMAGE. + +import logging + +from django.core.management.base import BaseCommand, CommandError + +from servo.models import Event, OrderStatus, Status + + +class Command(BaseCommand): + help = "Migrate Events to Order Statuses" + + def handle(self, *args, **options): + OrderStatus.objects.all().delete() + + for i in Event.objects.filter(action='set_status'): + if i.content_object is None: + continue + + os = OrderStatus(order=i.content_object) + os.started_by = i.triggered_by + os.started_at = i.triggered_at + os.finished_at = i.handled_at + + try: + os.status = Status.objects.get(title=i.description) + except Status.DoesNotExist: + continue + + os.save() diff --git a/servo/management/commands/migratetimezones.py b/servo/management/commands/migratetimezones.py new file mode 100644 index 0000000..7eb63d1 --- /dev/null +++ b/servo/management/commands/migratetimezones.py @@ -0,0 +1,41 @@ +# -*- coding: utf-8 -*- +# Copyright (c) 2013, First Party Software +# All rights reserved. + +# Redistribution and use in source and binary forms, with or without modification, +# are permitted provided that the following conditions are met: + +# 1. Redistributions of source code must retain the above copyright notice, +# this list of conditions and the following disclaimer. + +# 2. Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. + +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT +# OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +# SUCH DAMAGE. + +import logging + +from django.core.management.base import BaseCommand, CommandError + +from servo.models import User + + +class Command(BaseCommand): + help = "Migrate location timezones to user timezones" + + def handle(self, *args, **options): + for i in User.objects.all(): + if i.location: + i.timezone = i.location.timezone + i.save() diff --git a/servo/management/commands/obfuscate.py b/servo/management/commands/obfuscate.py new file mode 100644 index 0000000..8673846 --- /dev/null +++ b/servo/management/commands/obfuscate.py @@ -0,0 +1,107 @@ +# -*- coding: utf-8 -*- +# Copyright (c) 2013, First Party Software +# All rights reserved. + +# Redistribution and use in source and binary forms, with or without modification, +# are permitted provided that the following conditions are met: + +# 1. Redistributions of source code must retain the above copyright notice, +# this list of conditions and the following disclaimer. + +# 2. Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. + +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT +# OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +# SUCH DAMAGE. + +from random import choice +from django.db.utils import IntegrityError +from django.template.defaultfilters import slugify +from django.core.management.base import BaseCommand, CommandError + +from servo.models import Customer, Order, User, Location, GsxAccount + + +class Command(BaseCommand): + def handle(self, *args, **options): + help = "Obfuscates the information in this Servo install" + names = ('Daniel Scott', 'Amy Collins', 'Linda Moore', + 'Dennis Parker', 'Mark Cox', 'Jesse Clark', + 'Brian Patterson', 'Andrew Bennett', 'Frank Lopez', + 'Benjamin Wood', 'Michelle Jenkins', 'Alice Lee', + 'Lois Gonzales', 'Diane Perez', 'Cheryl Torres', + 'Ernest Smith', 'Steve Mitchell', 'Barbara Jones', + 'Wanda Roberts', 'Julie Watson', 'Carlos Harris', + 'Anthony Phillips', 'Ralph Gray', 'Donna Hill', + 'Alan Coleman', 'Lawrence Ross', 'Stephen Flores', + 'Robert Simmons', 'Gloria White', 'Doris Wilson', + 'Shirley Sanders', 'Matthew Bell', 'Janice Hughes', + 'Walter Nelson', 'Gerald Taylor', 'Tammy Martin', + 'Gregory Barnes', 'Jonathan Baker', 'Lillian Green', + 'Brenda Hernandez', 'Denise Davis', 'Bobby Rogers', + 'Joe Lewis', 'Teresa Bailey', 'Craig Russell', + 'Angela Rivera', 'Rebecca Jackson', 'Nicole Henderson', + 'Kenneth James', 'Nicholas Bryant', 'Anne Washington', + 'Irene Miller', 'Theresa Martinez', 'Evelyn Sanchez', + 'Richard Anderson', 'Jeffrey Robinson', 'Heather Diaz', + 'Joshua Butler', 'Joan Peterson', 'Todd Campbell', + 'Timothy Kelly', 'Steven King', 'Norma Reed', + 'Carolyn Turner', 'Ruth Evans', 'Carol Thomas', + 'Arthur Howard', 'Peter Carter', 'Debra Ramirez', + 'Marie Walker', 'Donald Garcia', 'Janet Gonzalez', + 'Harold Adams', 'Bonnie Cook', 'Paula Long', + 'Bruce Griffin', 'Adam Hall' ,'Annie Young', + 'Jacqueline Alexander', 'Kimberly Edwards', 'Sarah Wright', + 'Terry Williams', 'Johnny Morris', 'Andrea Ward', + 'Margaret Allen', 'Sandra Price', 'Scott Foster', + 'Elizabeth Brown', 'Wayne Cooper', 'Mildred Brooks', + 'Dorothy Perry', 'Lori Powell', 'Kathryn Murphy', + 'Judy Johnson', 'Albert Morgan', 'William Richardson', + 'Randy Stewart', 'Roger Thompson', 'Anna Rodriguez', + ) + """ + print 'Munging customer names of open orders...' + for i in Order.objects.filter(state=Order.STATE_QUEUED): + if i.customer: + i.customer.name = choice(names) + i.customer.save() + """ + print 'Munging technician names' + users = User.objects.exclude(username='filipp') + newnames = [x.split()[0].lower() for x in names] + oldnames = users.values_list("username", flat=True) + idx = 0 + + for i in users: + i.first_name, i.last_name = choice(names).split() + i.email = i.username + '@example.com' + i.save() + + print 'Munging location names' + a = 65 + for i in Location.objects.all(): + #i.title = 'Location %s' % chr(a) + i.email = slugify(i.title) + '@example.com' + i.city = 'Cupertino' + i.phone = '0451 202 7' + str(a) + i.address = '1 Infinite Loop' + a += 1 + i.save() + + print 'Munging GSX account names' + a = 65 + for i in GsxAccount.objects.all(): + i.title = 'GSX Account %s' % chr(a) + a += 1 + i.save() + diff --git a/servo/management/commands/slugifycategories.py b/servo/management/commands/slugifycategories.py new file mode 100644 index 0000000..07ea3a1 --- /dev/null +++ b/servo/management/commands/slugifycategories.py @@ -0,0 +1,38 @@ +# -*- coding: utf-8 -*- +# Copyright (c) 2013, First Party Software +# All rights reserved. + +# Redistribution and use in source and binary forms, with or without modification, +# are permitted provided that the following conditions are met: + +# 1. Redistributions of source code must retain the above copyright notice, +# this list of conditions and the following disclaimer. + +# 2. Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. + +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT +# OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +# SUCH DAMAGE. + +from django.utils.text import slugify +from django.core.management.base import BaseCommand + +from servo.models import ProductCategory + + +class Command(BaseCommand): + help = "Fixes ProductCategory slug fields" + + def handle(self, *args, **options): + for i in ProductCategory.objects.all(): + i.save() diff --git a/servo/management/commands/sutostaff.py b/servo/management/commands/sutostaff.py new file mode 100644 index 0000000..6450603 --- /dev/null +++ b/servo/management/commands/sutostaff.py @@ -0,0 +1,43 @@ +# -*- coding: utf-8 -*- +# Copyright (c) 2013, First Party Software +# All rights reserved. + +# Redistribution and use in source and binary forms, with or without modification, +# are permitted provided that the following conditions are met: + +# 1. Redistributions of source code must retain the above copyright notice, +# this list of conditions and the following disclaimer. + +# 2. Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. + +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT +# OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +# SUCH DAMAGE. + +import logging +from email.parser import Parser + +from django.core.management.base import BaseCommand, CommandError + +from servo.models import User + + +class Command(BaseCommand): + help = "Converts SuperUsers to Staff" + + def handle(self, *args, **options): + for u in User.objects.filter(is_superuser=True): + u.is_superuser = False + u.is_staff = True + u.save() +
\ No newline at end of file diff --git a/servo/management/commands/tokenize.py b/servo/management/commands/tokenize.py new file mode 100644 index 0000000..fd5daa9 --- /dev/null +++ b/servo/management/commands/tokenize.py @@ -0,0 +1,39 @@ +# -*- coding: utf-8 -*- +# Copyright (c) 2013, First Party Software +# All rights reserved. + +# Redistribution and use in source and binary forms, with or without modification, +# are permitted provided that the following conditions are met: + +# 1. Redistributions of source code must retain the above copyright notice, +# this list of conditions and the following disclaimer. + +# 2. Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. + +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT +# OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +# SUCH DAMAGE. + +from django.db.models import Q +from django.utils import timezone +from django.core.management.base import BaseCommand, CommandError + +from servo.models import User + + +class Command(BaseCommand): + help = "Creates API token for user" + + def handle(self, *args, **options): + user = User.objects.get(username=args[0]) + print(user.create_token()) diff --git a/servo/management/commands/updatecomponents.py b/servo/management/commands/updatecomponents.py new file mode 100644 index 0000000..75b6de5 --- /dev/null +++ b/servo/management/commands/updatecomponents.py @@ -0,0 +1,44 @@ +# -*- coding: utf-8 -*- +# Copyright (c) 2013, First Party Software +# All rights reserved. + +# Redistribution and use in source and binary forms, with or without modification, +# are permitted provided that the following conditions are met: + +# 1. Redistributions of source code must retain the above copyright notice, +# this list of conditions and the following disclaimer. + +# 2. Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. + +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT +# OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +# SUCH DAMAGE. + +from django.core.management.base import BaseCommand + +from servo.models import User, GsxAccount, Product, ServicePart + + +class Command(BaseCommand): + help = "Update missing component codes" + + def handle(self, *args, **options): + u = User.objects.get(username='filipp') + GsxAccount.default(u) + for p in Product.objects.filter(component_code='').exclude(labour_tier=''): + try: + info = ServicePart(part_number=p.code).lookup() + p.component_code = info.componentCode.strip() + p.save() + except Exception, e: + print e diff --git a/servo/management/commands/updateorders.py b/servo/management/commands/updateorders.py new file mode 100644 index 0000000..caad815 --- /dev/null +++ b/servo/management/commands/updateorders.py @@ -0,0 +1,47 @@ +# -*- coding: utf-8 -*- +# Copyright (c) 2013, First Party Software +# All rights reserved. + +# Redistribution and use in source and binary forms, with or without modification, +# are permitted provided that the following conditions are met: + +# 1. Redistributions of source code must retain the above copyright notice, +# this list of conditions and the following disclaimer. + +# 2. Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. + +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT +# OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +# SUCH DAMAGE. + +from django.core.management.base import BaseCommand + +from servo.models import Order + + +class Command(BaseCommand): + + help = "Updates order descriptions" + + def handle(self, *args, **options): + for o in Order.objects.filter(description=""): + o.description = o.device_name() or "" + o.save() + + for o in Order.objects.filter(status_name=""): + o.status_name = o.get_status_name() or "" + o.save() + + for o in Order.objects.filter(customer_name=""): + o.customer_name = o.get_customer_name() or "" + o.save() diff --git a/servo/management/commands/updatepototals.py b/servo/management/commands/updatepototals.py new file mode 100644 index 0000000..ae8f7cd --- /dev/null +++ b/servo/management/commands/updatepototals.py @@ -0,0 +1,38 @@ +# -*- coding: utf-8 -*- +# Copyright (c) 2013, First Party Software +# All rights reserved. + +# Redistribution and use in source and binary forms, with or without modification, +# are permitted provided that the following conditions are met: + +# 1. Redistributions of source code must retain the above copyright notice, +# this list of conditions and the following disclaimer. + +# 2. Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. + +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT +# OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +# SUCH DAMAGE. + +from django.core.management.base import BaseCommand +from servo.models import PurchaseOrder + + +class Command(BaseCommand): + + help = "Update Purchase Order totals" + + def handle(self, *args, **options): + for po in PurchaseOrder.objects.all(): + po.total = po.sum() + po.save() diff --git a/servo/management/commands/updateprices.py b/servo/management/commands/updateprices.py new file mode 100644 index 0000000..a916870 --- /dev/null +++ b/servo/management/commands/updateprices.py @@ -0,0 +1,63 @@ +# -*- coding: utf-8 -*- +# Copyright (c) 2013, First Party Software +# All rights reserved. + +# Redistribution and use in source and binary forms, with or without modification, +# are permitted provided that the following conditions are met: + +# 1. Redistributions of source code must retain the above copyright notice, +# this list of conditions and the following disclaimer. + +# 2. Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. + +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT +# OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +# SUCH DAMAGE. + +import sys +import logging + +from django.core.management.base import BaseCommand +from servo.models import (Product, GsxAccount, User,) + + +class Command(BaseCommand): + help = "Updates all part prices from GSX" + + def handle(self, *args, **options): + if len(args) < 1: + print "Usage: updateprices username [start:finish]" + sys.exit(1) + + start, counter = 0, 0 + finish = 999999999999 + + if len(args) == 2: + start, finish = args[1].split(':') + + GsxAccount.default(User.objects.get(username=args[0])) + + products = Product.objects.filter(pk__gt=start, pk__lt=finish) + products = products.exclude(part_type='SERVICE') + products = products.exclude(fixed_price=True) + + for i in products.order_by('id'): + logging.debug('Updating product %d' % i.pk) + try: + i.update_price() + i.save() + counter += 1 + except Exception, e: + logging.debug(e) + + print '%d product prices updated' % counter diff --git a/servo/management/commands/updaterepairs.py b/servo/management/commands/updaterepairs.py new file mode 100644 index 0000000..4eb1b58 --- /dev/null +++ b/servo/management/commands/updaterepairs.py @@ -0,0 +1,45 @@ +# -*- coding: utf-8 -*- +# Copyright (c) 2013, First Party Software +# All rights reserved. + +# Redistribution and use in source and binary forms, with or without modification, +# are permitted provided that the following conditions are met: + +# 1. Redistributions of source code must retain the above copyright notice, +# this list of conditions and the following disclaimer. + +# 2. Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. + +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT +# OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +# SUCH DAMAGE. + +from django.core.management.base import BaseCommand + +from servo.models import Repair + + +class Command(BaseCommand): + + help = "Updates statuses and details of open GSX repairs" + + def handle(self, *args, **options): + repairs = Repair.objects.filter(completed_at=None) + + for r in repairs.exclude(confirmation=""): + r.connect_gsx() + try: + details = r.get_details() + r.update_details(details) + except Exception: + pass |