2018-06-28 18:20:08 +00:00
|
|
|
# -*- mode: python; coding: utf-8 -*-
|
|
|
|
|
|
|
|
"""printer.models
|
|
|
|
Models of the printer application
|
|
|
|
Author : Maxime Bombar <bombar@crans.org>.
|
|
|
|
"""
|
|
|
|
|
|
|
|
from __future__ import unicode_literals
|
|
|
|
|
2018-10-25 12:19:54 +00:00
|
|
|
from numpy.random import randint
|
|
|
|
import unidecode
|
|
|
|
|
2018-10-12 10:49:41 +00:00
|
|
|
from django.core.files.storage import FileSystemStorage
|
2018-10-25 12:20:52 +00:00
|
|
|
from django.core.exceptions import ObjectDoesNotExist
|
2018-10-12 10:49:41 +00:00
|
|
|
|
2018-06-28 18:20:08 +00:00
|
|
|
from django.db import models
|
|
|
|
from django.forms import ValidationError
|
|
|
|
from django.utils.translation import ugettext_lazy as _
|
|
|
|
from django.template.defaultfilters import filesizeformat
|
|
|
|
|
|
|
|
from re2o.mixins import RevMixin
|
|
|
|
|
|
|
|
import users.models
|
|
|
|
|
|
|
|
from .validators import (
|
|
|
|
FileValidator,
|
|
|
|
)
|
|
|
|
|
|
|
|
from .settings import (
|
2018-10-20 13:52:38 +00:00
|
|
|
MAX_PRINTFILE_SIZE,
|
|
|
|
ALLOWED_TYPES,
|
|
|
|
PRICES,
|
|
|
|
FORMAT_AVAILABLE,
|
|
|
|
COLOR_CHOICES,
|
|
|
|
DISPOSITIONS_AVAILABLE,
|
|
|
|
STAPLING_OPTIONS,
|
|
|
|
PERFORATION_OPTIONS,
|
2018-06-28 18:20:08 +00:00
|
|
|
)
|
|
|
|
|
2018-09-25 11:39:12 +00:00
|
|
|
|
2018-09-08 12:04:44 +00:00
|
|
|
import math
|
2018-06-28 18:20:08 +00:00
|
|
|
|
|
|
|
"""
|
|
|
|
- ```user_printing_path``` is a function that returns the path of the uploaded file, used with the FileField.
|
|
|
|
- ```Job``` is the main model of a printer job. His parent is the ```user``` model.
|
|
|
|
"""
|
|
|
|
|
2018-06-28 18:20:08 +00:00
|
|
|
def user_printing_path(instance, filename):
|
2018-10-25 12:19:54 +00:00
|
|
|
"""
|
|
|
|
Defines the path where will be uploaded the files
|
|
|
|
"""
|
2018-06-28 18:20:08 +00:00
|
|
|
# File will be uploaded to MEDIA_ROOT/printings/user_<id>/<filename>
|
2018-10-25 12:19:54 +00:00
|
|
|
return 'printings/user_{0}/{1}'.format(instance.user.id, unidecode.unidecode(filename))
|
|
|
|
|
2018-06-28 18:20:08 +00:00
|
|
|
|
2018-10-25 12:20:52 +00:00
|
|
|
class Digicode(RevMixin, models.Model):
|
|
|
|
"""
|
|
|
|
This is a model to represent a digicode, maybe should be an external app.
|
|
|
|
"""
|
|
|
|
code = models.BigIntegerField(default=0, unique=True)
|
|
|
|
user = models.ForeignKey('users.User', on_delete=models.PROTECT)
|
|
|
|
created = models.DateTimeField(auto_now_add=True)
|
|
|
|
used_time = models.DateTimeField(null=True)
|
|
|
|
|
|
|
|
def _gen_code(user):
|
|
|
|
try_again = True
|
|
|
|
while try_again:
|
|
|
|
try:
|
|
|
|
code = randint(695895, 6958942)*1437+38
|
|
|
|
Digicode.objects.get(code=code)
|
|
|
|
except ObjectDoesNotExist:
|
|
|
|
try_again = False
|
|
|
|
digicode = Digicode.objects.create(code=code, user=user)
|
|
|
|
digicode.save()
|
|
|
|
return (str(code) + '#')
|
|
|
|
|
|
|
|
|
2018-06-28 18:20:08 +00:00
|
|
|
class JobWithOptions(RevMixin, models.Model):
|
|
|
|
"""
|
|
|
|
This is the main model of printer application :
|
|
|
|
|
|
|
|
- ```user``` is a ForeignKey to the User Application
|
|
|
|
- ```file``` is the file to print
|
2018-09-08 10:46:52 +00:00
|
|
|
- ```filename``` is the name of the file to print
|
2018-06-28 18:20:08 +00:00
|
|
|
- ```starttime``` is the time when the job was launched
|
|
|
|
- ```endtime``` is the time when the job was stopped.
|
|
|
|
A job is stopped when it is either finished or cancelled.
|
|
|
|
- ```status``` can be running, finished or cancelled.
|
|
|
|
- ```club``` is blank in general. If the job was launched as a club then
|
|
|
|
it is the id of the club.
|
|
|
|
- ```price``` is the total price of this printing.
|
|
|
|
|
|
|
|
Printing Options :
|
|
|
|
|
|
|
|
- ```format``` is the paper format. Example: A4.
|
|
|
|
- ```color``` is the colorization option. Either Color or Greyscale.
|
|
|
|
- ```disposition``` is the paper disposition.
|
|
|
|
- ```count``` is the number of copies to be printed.
|
|
|
|
- ```stapling``` is the stapling options.
|
|
|
|
- ```perforations``` is the perforation options.
|
|
|
|
|
|
|
|
|
|
|
|
Parent class : User
|
2018-09-08 12:04:44 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Methods:
|
|
|
|
```_compute_price``` compute the printing price
|
|
|
|
```_update_price``` update printing price
|
2018-06-28 18:20:08 +00:00
|
|
|
"""
|
|
|
|
STATUS_AVAILABLE = (
|
2018-09-25 11:53:30 +00:00
|
|
|
('Pending', 'Pending'),
|
|
|
|
('Printable', 'Printable'),
|
|
|
|
('Running', 'Running'),
|
|
|
|
('Cancelled', 'Cancelled'),
|
|
|
|
('Finished', 'Finished')
|
2018-06-28 18:20:08 +00:00
|
|
|
)
|
|
|
|
user = models.ForeignKey('users.User', on_delete=models.PROTECT)
|
2018-10-21 17:48:10 +00:00
|
|
|
paid = models.BooleanField(default='False')
|
2018-10-12 10:49:41 +00:00
|
|
|
file = models.FileField(storage=FileSystemStorage(location='/var/impressions'),
|
|
|
|
upload_to=user_printing_path,
|
|
|
|
validators=[FileValidator(
|
|
|
|
allowed_types=ALLOWED_TYPES,
|
|
|
|
max_size=MAX_PRINTFILE_SIZE)
|
|
|
|
])
|
2018-09-08 10:46:52 +00:00
|
|
|
filename = models.CharField(max_length=255,null=True)
|
2018-06-28 18:20:08 +00:00
|
|
|
starttime = models.DateTimeField(auto_now_add=True)
|
|
|
|
endtime = models.DateTimeField(null=True)
|
|
|
|
status = models.CharField(max_length=255, choices=STATUS_AVAILABLE)
|
2018-09-08 10:46:52 +00:00
|
|
|
printAs = models.ForeignKey('users.User', on_delete=models.PROTECT, related_name='print_as_user', blank=True, null=True)
|
2018-09-08 10:59:45 +00:00
|
|
|
price = models.DecimalField(
|
|
|
|
max_digits=5,
|
|
|
|
decimal_places=2,
|
|
|
|
verbose_name=_("price"),
|
|
|
|
default=0.0)
|
2018-09-08 10:46:52 +00:00
|
|
|
pages = models.IntegerField(default=0)
|
2018-06-28 18:20:08 +00:00
|
|
|
|
|
|
|
format = models.CharField(max_length=255, choices=FORMAT_AVAILABLE, default='A4')
|
|
|
|
color = models.CharField(max_length=255, choices=COLOR_CHOICES, default='Greyscale')
|
|
|
|
disposition = models.CharField(max_length=255, choices=DISPOSITIONS_AVAILABLE, default='TwoSided')
|
|
|
|
count = models.PositiveIntegerField(default=1)
|
|
|
|
stapling = models.CharField(max_length=255, choices=STAPLING_OPTIONS, default='None')
|
|
|
|
perforation = models.CharField(max_length=255, choices=PERFORATION_OPTIONS, default='None')
|
2018-09-08 10:46:52 +00:00
|
|
|
|
|
|
|
|
|
|
|
def _update_price(self):
|
2018-09-08 12:04:44 +00:00
|
|
|
self.price = self._compute_price()
|
|
|
|
|
|
|
|
def _compute_price(self):
|
|
|
|
pages = int(self.pages)
|
|
|
|
price_paper = PRICES[self.format]
|
|
|
|
price_stapling = 0.0
|
|
|
|
nb_staples = 0
|
|
|
|
|
|
|
|
if self.disposition == 'Booklet':
|
|
|
|
sheets = int((pages+3)/4)
|
|
|
|
pages = 2 * sheets
|
|
|
|
elif self.disposition == 'TwoSided':
|
|
|
|
sheets = int(pages/2.+0.5)
|
|
|
|
else:
|
|
|
|
sheets = pages
|
|
|
|
|
|
|
|
if self.format == 'A3':
|
|
|
|
pages*=2
|
|
|
|
|
|
|
|
price_ink = price_paper*sheets + PRICES[self.color]*pages
|
|
|
|
|
|
|
|
if self.stapling:
|
|
|
|
nb_staples = 2 - int('Top' in self.stapling)
|
|
|
|
|
|
|
|
price_stapling = nb_staples * PRICES['Staples']
|
|
|
|
|
|
|
|
total_price = math.floor(self.count * (price_ink + price_stapling))
|
|
|
|
|
|
|
|
return float(total_price)/100
|
2018-10-06 20:13:35 +00:00
|
|
|
|
|
|
|
@staticmethod
|
|
|
|
def can_view_all(user_request, *_args, **_kwargs):
|
|
|
|
"""
|
|
|
|
"""
|
|
|
|
return (
|
|
|
|
True, None
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
@staticmethod
|
|
|
|
def can_create(user_request, *_args, **_kwargs):
|
|
|
|
"""
|
|
|
|
"""
|
|
|
|
return(
|
|
|
|
True, None
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
@staticmethod
|
|
|
|
def can_view(user_request, *_args, **_kwargs):
|
|
|
|
"""
|
|
|
|
"""
|
|
|
|
return(
|
|
|
|
True, None
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
@staticmethod
|
|
|
|
def can_edit(user_request, *_args, **_kwargs):
|
|
|
|
"""
|
|
|
|
"""
|
|
|
|
return(
|
|
|
|
True, None
|
|
|
|
)
|
|
|
|
|
|
|
|
@staticmethod
|
|
|
|
def can_delete(user_request, *_args, **_kwargs):
|
|
|
|
"""
|
|
|
|
|
|
|
|
"""
|
|
|
|
return(
|
|
|
|
True, None
|
|
|
|
)
|