import labels import datetime from random import randint from django.db.models import BigIntegerField from django.urls import reverse from reportlab.graphics import shapes from reportlab.graphics.barcode.qr import QrCodeWidget from reportlab.lib.pagesizes import LETTER from config.settings import DEBUG BREWFATHER_APP_ROOT = 'https://web.brewfather.app' def random_with_n_digits(n): range_start = 10**(n-1) range_end = (10**n)-1 return randint(range_start, range_end) class AveryLabel: """ Class to generate page of averty labels. """ AVERY = { 18294: (4, 15, LETTER, (44.45, 16.764), (7.62, 13.97)), 5263: (2, 5, LETTER, (101.6, 50.8), (3.95, 12.7)), } def __init__(self, label, **kwargs): data = self.AVERY[label] self.across = data[0] self.down = data[1] self.pagesize = data[2] self.labelsize = data[3] self.margins = data[4] self.topDown = True self.debug = False self.position = 0 self.previous_used = 0 self.corner_radius = 2 self.__dict__.update(kwargs) self.specs = labels.Specification( self.pagesize[0]*0.352778, self.pagesize[1] * 0.352778, # Convert from PostScript points to mm self.across, self.down, self.labelsize[0], self.labelsize[1], corner_radius=self.corner_radius, left_margin=self.margins[0], right_margin=self.margins[0], top_margin=self.margins[1], left_padding=2, right_padding=1, top_padding=1, bottom_padding=0, row_gap=0) def draw(self, label, width, height, obj): if not obj['blank']: obj['path'] = reverse( "{}:{}".format(obj['ns'], obj['template']), kwargs={"{}_id".format(obj['template']): obj['id']} ) # Barcode if DEBUG: qrw = QrCodeWidget( 'https://brewery.giacofei.org/{path}'.format(**obj)) else: qrw = QrCodeWidget('https://{host}/{path}'.format(**obj)) num_lines = max(len(obj['data']) + 1, 6) font = height/num_lines b = qrw.getBounds() w = b[2]-b[0] h = b[3]-b[1] ps_size = (self.labelsize[1]/0.352778) d = shapes.Drawing( w, h, transform=[(ps_size/w), 0, 0, (ps_size/h), 0, 0]) d.add(qrw) label.add(d) # Line line_pos = (num_lines - 1) * height / num_lines label.add(shapes.Line(height, line_pos, width, line_pos)) # Title label.add(shapes.String( height, # Left Position line_pos * 1.05, # Bottom Position '{title}'.format(**obj), # Text fontName="Helvetica", fontSize=font )) for x, line in enumerate(obj['data']): x = x+1 label.add(shapes.String( height, # Left Position line_pos - font * x, # Bottom Position line, # Text fontName="Helvetica", fontSize=font )) def render(self, objects, render_file, labels_used=0): """ Create the HttpResponse object with the appropriate PDF headers.""" # Create the sheet. # if render_type == 'sample': # sheet = labels.Sheet(self.specs, self.draw_sample, border=self.debug) sheet = labels.Sheet(self.specs, self.draw, border=self.debug) # Add a couple of labels. for i in range(int(labels_used)): sheet.add_label({'blank': True}) for entry in objects: sheet.add_label(entry) # Save the file and we are done. sheet.save(render_file) class DateUUIDField(BigIntegerField): """ A field which stores a Short UUID value with prepended date. This may also have the Boolean attribute 'auto' which will set the value on initial save to a new UUID value (calculated using shortuuid's default (uuid4)). Note that while all UUIDs are expected to be unique we enforce this with a DB constraint. """ def __init__(self, auto=True, *args, **kwargs): self.auto = auto if auto: # Do not let the user edit UUIDs if they are auto-assigned. kwargs['editable'] = False kwargs['blank'] = True kwargs['unique'] = True super(DateUUIDField, self).__init__(*args, **kwargs) def pre_save(self, model_instance, add): """ This is used to ensure that we auto-set values if required. See CharField.pre_save """ value = super(DateUUIDField, self).pre_save(model_instance, add) if self.auto and not value: # Assign a new value for this attribute if required. x = datetime.datetime.now() front = x.strftime("%Y%m%d") value = int('{}{}'.format(front, random_with_n_digits(6))) setattr(model_instance, self.attname, value) return value def formfield(self, **kwargs): if self.auto: return None return super(DateUUIDField, self).formfield(**kwargs)