class SFTPStorageFile(File): def __init__(self, name, storage, mode): self._name = name self._storage = storage self._mode = mode self._is_dirty = False self.file = BytesIO() self._is_read = False @property def size(self): if not hasattr(self, '_size'): self._size = self._storage.size(self._name) return self._size def read(self, num_bytes=None): if not self._is_read: self.file = self._storage._read(self._name) self._is_read = True return self.file.read(num_bytes) def write(self, content): if 'w' not in self._mode: raise AttributeError("File was opened for read-only access.") self.file = BytesIO(content) self._is_dirty = True self._is_read = True def close(self): if self._is_dirty: self._storage._save(self._name, self) self.file.close()
def render(data, width, height, force=True, padding=None, overlays=(), overlay_sources=(), overlay_tints=(), overlay_sizes=None, overlay_positions=None, mask=None, mask_source=None, center=".5,.5", format=IMAGE_DEFAULT_FORMAT, quality=IMAGE_DEFAULT_QUALITY, fill=None, background=None, tint=None, pre_rotation=None, post_rotation=None, crop=True, grayscale=False): """ Rescale the given image, optionally cropping it to make sure the result image has the specified width and height. """ if not isinstance(data, six.string_types): input_file = BytesIO(data) else: input_file = StringIO(data) img = pil.open(input_file) if img.mode != "RGBA": img = img.convert("RGBA") if width is None: width = img.size[0] if height is None: height = img.size[1] img = do_rotate(img, pre_rotation) if crop: img = resizeCrop(img, width, height, center, force) else: img = resizeScale(img, width, height, force) if grayscale: img = do_grayscale(img) do_tint(img, tint) img = do_fill(img, fill, width, height) img = do_background(img, background) do_mask(img, mask, mask_source) img = do_overlays(img, overlays, overlay_tints, overlay_sources, overlay_sizes, overlay_positions) img = do_padding(img, padding) img = do_rotate(img, post_rotation) tmp = BytesIO() if not format.upper() in ALPHA_FORMATS: img = img.convert("RGB") img.save(tmp, format, quality=quality) tmp.seek(0) output_data = tmp.getvalue() input_file.close() tmp.close() return output_data
def add_user(name, bio): u = User.objects.get_or_create(username=name)[0] u.save() p = UserProfile.objects.get_or_create(user=u)[0] p.bio = bio # https://stackoverflow.com/questions/54891829/typeerror-memoryview-a-bytes-like-object-is-required-not-jpegimagefile image = 'populate_images/' + name + '.jpg' img_in = Image.open(image) buf = BytesIO() img_in.save(buf, 'jpeg') buf.seek(0) p.profile_image.save(name + '.jpeg', buf, True) buf.close() img_in.close() return p
def downloadSheetPage(request, pk): """ View for dowloading a sheet """ student = getStudent(request.user) sheet = getSheetInstance(pk) # Get the file # Check if the user can have access to it (if he is part of the lesson) if sheet.lesson not in student.classroom.lessons.all(): raise PermissionDenied() files = sheet.fileSet if len(files) == 1: uploadedFile = files[0] contentType = uploadedFile.contentType fileName = sheet.name + uploadedFile.extension data = uploadedFile.file response = HttpResponse(data.read(), content_type=contentType) response['Content-Disposition'] = 'attachment; filename="{}"'.format(fileName) data.close() else: contentType = 'application/zip' fileName = sheet.name + '.zip' zipStream = BytesIO() zipFile = ZipFile(zipStream, 'w') for uploadedFile in files: filePath = join(settings.MEDIA_ROOT, uploadedFile.file.name) archiveName = uploadedFile.file.name.replace('sheets/', '').replace('-point-', '.') zipFile.write(filePath, archiveName) zipFile.close() zipStream.seek(0) response = HttpResponse(zipStream, content_type=contentType) response['Content-Disposition'] = 'attachment; filename="{}"'.format(fileName) zipStream.close() return response
class FTPStorageFile(File): def __init__(self, name, storage, mode): self.name = name self._storage = storage self._mode = mode self._is_dirty = False self.file = BytesIO() self._is_read = False @property def size(self): if not hasattr(self, "_size"): self._size = self._storage.size(self.name) return self._size def readlines(self): if not self._is_read: self._storage._start_connection() self.file = self._storage._read(self.name) self._is_read = True return self.file.readlines() def read(self, num_bytes=None): if not self._is_read: self._storage._start_connection() self.file = self._storage._read(self.name) self._is_read = True return self.file.read(num_bytes) def write(self, content): if "w" not in self._mode: raise AttributeError("File was opened for read-only access.") self.file = BytesIO(content) self._is_dirty = True self._is_read = True def close(self): if self._is_dirty: self._storage._start_connection() self._storage._put_file(self.name, self) self._storage.disconnect() self.file.close()
class CouchDBFile(File): """ CouchDBFile - a Django File-like class for CouchDB documents. """ def __init__(self, name, storage, mode): self._name = name self._storage = storage self._mode = mode self._is_dirty = False try: self._doc = self._storage.get_document(name) tmp, ext = os.path.split(name) if ext: filename = "content." + ext else: filename = "content" attachment = self._storage.db.get_attachment(self._doc, filename=filename) self.file = BytesIO(attachment) except couchdb.client.ResourceNotFound: if 'r' in self._mode: raise ValueError("The file cannot be reopened.") else: self.file = BytesIO() self._is_dirty = True @property def size(self): return self._doc['size'] def write(self, content): if 'w' not in self._mode: raise AttributeError("File was opened for read-only access.") self.file = BytesIO(content) self._is_dirty = True def close(self): if self._is_dirty: self._storage._put_file(self._name, self.file.getvalue()) self.file.close()
class LibCloudFile(File): """File inherited class for libcloud storage objects read and write""" def __init__(self, name, storage, mode): self.name = name self._storage = storage self._mode = mode self._is_dirty = False self._file = None def _get_file(self): if self._file is None: data = self._storage._read(self.name) self._file = BytesIO(data) return self._file def _set_file(self, value): self._file = value file = property(_get_file, _set_file) @property def size(self): if not hasattr(self, '_size'): self._size = self._storage.size(self.name) return self._size def read(self, num_bytes=None): return self.file.read(num_bytes) def write(self, content): if 'w' not in self._mode: raise AttributeError("File was opened for read-only access.") self.file = BytesIO(content) self._is_dirty = True def close(self): if self._is_dirty: self._storage._save(self.name, self.file) self.file.close()
def add_event(request, me): """ 创建活动 """ if request.method == 'POST': # 获取表单提交数据 name = request.POST['name'] time = request.POST['time'] address = request.POST['address'] introduce = request.POST['introduce'] event_img = request.FILES['event_img'] # 生成二维码 # 保存表单数据 event = Event.objects.create(name=name, time=time, address=address, introduce=introduce, event_img=event_img) qr = qrcode.make( 'https://pinkslash.metatype.cn/wechat_login/?status=provider_{0}'. format(event.id)) buf = BytesIO() qr.save(buf) qr_data = buf.getvalue() buf.write(qr_data) qr_img = InMemoryUploadedFile(file=buf, field_name=None, name='event.png', content_type='image/png', size=len(qr_data), charset=None) # 保存表单数据 event.qrcode = qr_img event.save() buf.close() return redirect('/events/')
def add_food(request, me): if request.method == 'POST': # 获取表单提交数据 name = request.POST['name'] credit = request.POST['credit'] # event_id = request.POST['event_id'] food_img = request.FILES['food_img'] event = me.event # 保存表单数据 food = Food.objects.create(name=name, provider=me, credit=credit, event=event, food_img=food_img) # 生成二维码 qr = qrcode.make( 'https://pinkslash.metatype.cn/wechat_login/?status=purchase_{0}_{1}' .format(event.id, food.id)) buf = BytesIO() qr.save(buf) qr_data = buf.getvalue() buf.write(qr_data) qr_img = InMemoryUploadedFile(file=buf, field_name=None, name='food.png', content_type='image/png', size=len(qr_data), charset=None) food.qrcode = qr_img food.save() buf.close() return redirect('/foods?eid={0}'.format(event.id))
def list(self, request, project): """ GET method implementation for log slicer Receives a line range and job_id and returns those lines """ job_id = request.query_params.get("job_id") log_name = request.query_params.get("name") if log_name: log_names = [log_name] else: log_names = ["buildbot_text", "builds-4h"] format = 'json' if log_name == 'mozlog_json' else 'text' file = None start_line = request.query_params.get("start_line") end_line = request.query_params.get("end_line") if not start_line or not end_line: return Response( "``start_line`` and ``end_line`` parameters are both required", 400) try: start_line = abs(int(start_line)) end_line = abs(int(end_line)) except ValueError: return Response("parameters could not be converted to integers", 400) if start_line >= end_line: return Response("``end_line`` must be larger than ``start_line``", 400) try: job = Job.objects.get(repository__name=project, project_specific_id=job_id) except Job.DoesNotExist: return Response("Job does not exist", 404) try: url = JobLog.objects.filter( job=job, name__in=log_names)[0:1].values_list('url', flat=True)[0] except JobLog.DoesNotExist: return Response("Job log does not exist", 404) try: file = filesystem.get(url) if not file: r = make_request(url) try: file = gzip.GzipFile(fileobj=BytesIO(r.content)) # read 16 bytes, just to make sure the file is gzipped file.read(16) file.seek(0) filesystem.set(url, file.fileobj) except IOError: # file is not gzipped, but we should still store / read # it as such, to save space file = BytesIO(r.content) gz_file_content = BytesIO() with gzip.GzipFile('none', 'w', fileobj=gz_file_content) as gz: gz.write(r.content) filesystem.set(url, gz_file_content) else: file = gzip.GzipFile(fileobj=file) lines = [] for i, line in enumerate(file): if i < start_line: continue elif i >= end_line: break if format == 'json': lines.append({"data": json.loads(line), "index": i}) else: lines.append({"text": line, "index": i}) return Response(lines) finally: if file: file.close()
def list(self, request, project): """ GET method implementation for log slicer Receives a line range and job_id and returns those lines """ job_id = request.query_params.get("job_id") log_name = request.query_params.get("name") if log_name: log_names = [log_name] else: log_names = ["buildbot_text", "builds-4h"] format = 'json' if log_name == 'mozlog_json' else 'text' file = None start_line = request.query_params.get("start_line") end_line = request.query_params.get("end_line") if not start_line or not end_line: return Response("``start_line`` and ``end_line`` parameters are both required", 400) try: start_line = abs(int(start_line)) end_line = abs(int(end_line)) except ValueError: return Response("parameters could not be converted to integers", 400) if start_line >= end_line: return Response("``end_line`` must be larger than ``start_line``", 400) try: job = Job.objects.get(repository__name=project, project_specific_id=job_id) except Job.DoesNotExist: return Response("Job does not exist", 404) try: url = JobLog.objects.filter( job=job, name__in=log_names)[0:1].values_list('url', flat=True)[0] except JobLog.DoesNotExist: return Response("Job log does not exist", 404) try: file = filesystem.get(url) if not file: r = make_request(url) try: file = gzip.GzipFile(fileobj=BytesIO(r.content)) # read 16 bytes, just to make sure the file is gzipped file.read(16) file.seek(0) filesystem.set(url, file.fileobj) except IOError: # file is not gzipped, but we should still store / read # it as such, to save space file = BytesIO(r.content) gz_file_content = BytesIO() with gzip.GzipFile('none', 'w', fileobj=gz_file_content) as gz: gz.write(r.content) filesystem.set(url, gz_file_content) else: file = gzip.GzipFile(fileobj=file) lines = [] for i, line in enumerate(file): if i < start_line: continue elif i >= end_line: break if format == 'json': lines.append({"data": json.loads(line), "index": i}) else: lines.append({"text": line, "index": i}) return Response(lines) finally: if file: file.close()
def generate_pdf(request, obj, bid_item_dict, invoice, employee, save_to_disk=False, return_file_object=False): buff = BytesIO() # The page width totals 18.6cm doc = SimpleDocTemplate(buff, rightMargin=2 * cm, leftMargin=2 * cm, topMargin=1.5 * cm, bottomMargin=3.75 * cm) def _header_footer(canvas, doc): # Save the state of our canvas so we can draw on it canvas.saveState() styles = getSampleStyleSheet() # Header header = Paragraph( 'This is a multi-line header. It goes on every page. ' * 5, styles['Normal']) w, h = header.wrap(doc.width, doc.topMargin) header.drawOn(canvas, doc.leftMargin, doc.height + doc.topMargin - h) # Footer footer = Paragraph('Thank You For Your Business', styles['Normal']) w, h = footer.wrap(doc.width, doc.bottomMargin) footer.drawOn(canvas, doc.leftMargin, h) # Release the canvas canvas.restoreState() story = [] # Styles styles = getSampleStyleSheet() styles.add(ParagraphStyle(name='Center', alignment=TA_CENTER)) styles.add(ParagraphStyle(name='Right', alignment=TA_RIGHT)) styles.add(ParagraphStyle(name='Left', alignment=TA_LEFT)) styles.add( ParagraphStyle(name='Line_Data', alignment=TA_LEFT, fontSize=8, leading=7)) styles.add( ParagraphStyle(name='Line_Data_Small', alignment=TA_LEFT, fontSize=7, leading=8)) styles.add( ParagraphStyle(name='Line_Data_Medium', alignment=TA_LEFT, fontSize=10, leading=8)) styles.add( ParagraphStyle(name='Line_Data_Large', alignment=TA_LEFT, fontSize=12, leading=12)) styles.add( ParagraphStyle(name='Line_Data_Large_Right', alignment=TA_RIGHT, fontSize=12, leading=12)) styles.add( ParagraphStyle(name='Line_Data_Large_Center', alignment=TA_CENTER, fontSize=12, leading=12)) styles.add( ParagraphStyle(name='Invoice_Date', alignment=TA_LEFT, fontSize=12, leading=12)) styles.add( ParagraphStyle(name='Line_Data_Largest', fontName='Times-BoldItalic', alignment=TA_CENTER, fontSize=22, leading=15)) styles.add( ParagraphStyle(name='Line_Label', fontSize=10, leading=12, alignment=TA_LEFT)) styles.add( ParagraphStyle(name='Line_Label_Center', fontSize=7, alignment=TA_CENTER)) # Add Company Address, Logo and Invoice Info company_paragraph = """ 179 Marvy ST<br /> Lino Lakes, MN 55014<br /> (612) 508-2484 <br /> [email protected] <br /> MN License: BC690748 """ logo = os.path.join(settings.STATIC_ROOT, 'img/logo.jpg') denominator = 5 image = Image(logo, width=800 / denominator, height=269 / denominator) if invoice: proposal_invoice_paragraph = """ Date: {}<br /> Invoice #: {:04d} <br /> """.format(datetime.date.today().strftime('%x'), obj.id) else: proposal_invoice_paragraph = """ Submitted By: <br /> Tom Madsen <br /> Date: {}<br /> Proposal #: {:04d} <br /> """.format(datetime.date.today().strftime('%x'), obj.id) data1 = [[ Paragraph(company_paragraph, styles['Line_Data_Large']), image, Paragraph(proposal_invoice_paragraph, styles['Line_Data_Large']) ]] t1 = Table(data1, colWidths=(6.7 * cm, 8 * cm, 4.6 * cm)) t1.setStyle(TableStyle([ ('VALIGN', (0, 0), (-1, -1), 'TOP'), ])) story.append(t1) # Add Proposal or Invoice Title to PDF if invoice: pdf_type = 'Invoice' elif employee: pdf_type = 'Employee Copy' else: pdf_type = 'Proposal' data1 = [[Paragraph(pdf_type, styles["Line_Data_Largest"])]] t1 = Table(data1, colWidths=(18.6 * cm)) t1.setStyle(TableStyle([('VALIGN', (0, 0), (-1, -1), 'TOP')])) story.append(t1) story.append(Spacer(2, 32)) # Add Customer Info and Job Description telephone = obj.customer.telephone telephone = "({}) {}-{}".format(telephone[:3], telephone[3:6], telephone[6:]) if obj.customer.company_name: company = "{}<br />".format(obj.customer.company_name) else: company = "" location_paragraph = """ {first} {last}<br /> {company} {street}<br /> {city}, {state} {zip}<br /> {telephone}<br /> {email}""".format(first=obj.customer.first_name, last=obj.customer.last_name, company=company, street=obj.address.street, city=obj.address.city, state=obj.address.state, zip=obj.address.zip, telephone=telephone, email=obj.customer.email) if obj.billto_city_st_zip: # check if this is an alternate billto field populated if len(obj.billto_telephone) == 10: billto_telephone = obj.billto_telephone billto_telephone = "({}) {}-{}".format(billto_telephone[:3], billto_telephone[3:6], billto_telephone[6:]) else: billto_telephone = obj.billto_telephone billto_paragraph = """ {name}<br /> {street}<br /> {city_st_zip}<br /> {telephone}""".format(name=obj.billto_name, street=obj.billto_street, city_st_zip=obj.billto_city_st_zip, telephone=billto_telephone) else: billto_paragraph = location_paragraph description_paragraph = obj.description if invoice: data1 = [[ Paragraph('Bill To', styles["Line_Data_Large"]), Paragraph('Job Address', styles["Line_Data_Large"]) ], [ Paragraph(billto_paragraph, styles["Line_Data_Large"]), Paragraph(location_paragraph, styles["Line_Data_Large"]) ]] t1 = Table(data1, colWidths=(9.3 * cm, 9.3 * cm)) t1.setStyle( TableStyle([('VALIGN', (0, 0), (-1, -1), 'TOP'), ('BACKGROUND', (0, 0), (1, 0), colors.lightgrey)])) story.append(t1) story.append(Spacer(4, 20)) data1 = [[Paragraph('Job Description', styles["Line_Data_Large"])], [Paragraph(description_paragraph, styles["Line_Data_Large"])]] t1 = Table(data1, colWidths=(18.6 * cm)) t1.setStyle( TableStyle([('VALIGN', (0, 0), (-1, -1), 'TOP'), ('BACKGROUND', (0, 0), (1, 0), colors.lightgrey)])) story.append(t1) else: # Proposal data1 = [[ Paragraph('Job Address', styles["Line_Data_Large"]), Paragraph('Job Description', styles["Line_Data_Large"]) ], [ Paragraph(billto_paragraph, styles["Line_Data_Large"]), Paragraph(description_paragraph, styles["Line_Data_Large"]) ]] t1 = Table(data1, colWidths=(7 * cm, 11.6 * cm)) t1.setStyle( TableStyle([('VALIGN', (0, 0), (-1, -1), 'TOP'), ('BACKGROUND', (0, 0), (1, 0), colors.lightgrey)])) story.append(t1) if obj.notes: story.append(Spacer(2, 10)) data1 = [[Paragraph('Notes', styles["Line_Data_Large"])], [Paragraph(obj.notes, styles["Line_Data_Large"])]] t1 = Table(data1, colWidths=(18.6 * cm)) t1.setStyle( TableStyle([('VALIGN', (0, 0), (-1, -1), 'TOP'), ('BACKGROUND', (0, 0), (1, 0), colors.lightgrey)])) story.append(t1) # Add Bid Items to PDF story.append(Spacer(4, 32)) for job_name, items in bid_item_dict.items(): title = [[ Paragraph(job_name, styles["Line_Data_Large"]), Paragraph('', styles["Line_Data_Large"]) ]] t1 = Table(title, colWidths=(15 * cm, 3.6 * cm)) t1.setStyle( TableStyle([('INNERGRID', (0, 0), (-1, -1), 0.25, colors.black), ('BOX', (0, 0), (-1, -1), .25, colors.black), ('VALIGN', (0, 0), (-1, -1), 'MIDDLE'), ('BACKGROUND', (0, 0), (-1, -1), colors.lightgrey)])) story.append(t1) if employee: # Add quantities but remove pricing data1 = [[ Paragraph(str(item.description), styles["Line_Data_Large"]), Paragraph(str(item.quantity), styles["Line_Data_Large_Right"]) ] for item in items] t1 = Table(data1, colWidths=(15 * cm, 3.6 * cm)) t1.setStyle( TableStyle([ ('INNERGRID', (0, 0), (-1, -1), 0.25, colors.black), ('BOX', (0, 0), (-1, -1), 0.25, colors.black), ('VALIGN', (0, 0), (-1, -1), 'MIDDLE'), ])) story.append(t1) story.append(Spacer(4, 32)) else: # Add pricing but not quantity for end customer data1 = [[ Paragraph(str(item.description), styles["Line_Data_Large"]), Paragraph(str("{0:.2f}".format(round(item.total, 2))), styles["Line_Data_Large_Right"]) ] for item in items] t1 = Table(data1, colWidths=(15 * cm, 3.6 * cm)) t1.setStyle( TableStyle([ ('INNERGRID', (0, 0), (-1, -1), 0.25, colors.black), ('BOX', (0, 0), (-1, -1), 0.25, colors.black), ('VALIGN', (0, 0), (-1, -1), 'MIDDLE'), ])) story.append(t1) # Calculate total per job and add to PDF total = items.aggregate(Sum('total'))['total__sum'] total_text = "{} Total".format(job_name) data1 = [[ Paragraph(total_text, styles["Line_Data_Large"]), Paragraph(str("${0:.2f}".format(total)), styles['Line_Data_Large_Right']) ]] t1 = Table(data1, colWidths=(15 * cm, 3.6 * cm)) t1.setStyle( TableStyle([ ('INNERGRID', (0, 0), (-1, -1), 0.25, colors.black), ('BOX', (0, 0), (-1, -1), .25, colors.black), ('VALIGN', (0, 0), (-1, -1), 'MIDDLE'), ('BACKGROUND', (0, 0), (-1, -1), colors.lightgrey) ])) story.append(t1) story.append(Spacer(4, 32)) # Calculate Bid Total items = BidItem.objects.all().filter(bid=obj.id) bid_total = items.aggregate(Sum('total'))['total__sum'] if not bid_total: bid_total = 0 if invoice: # Calculate Balance Due and Payment History for Invoice payments = Payment.objects.all().filter(bid=obj.id) payment_total = payments.aggregate(Sum('amount'))['amount__sum'] cents = Decimal('0.01') if payment_total: remaining_balance = Decimal(bid_total - payment_total).quantize( cents, ROUND_HALF_UP) else: remaining_balance = bid_total data1 = [ [Paragraph('Invoice Summary', styles["Line_Data_Large"]), None], [ Paragraph('Initial Balance', styles["Line_Data_Large"]), Paragraph(str("{0:.2f}".format(round(bid_total, 2))), styles["Line_Data_Large_Right"]) ], ] data2 = [[ Paragraph( str("Received Payment on {}".format( payment.date.strftime('%x'))), styles["Line_Data_Large"]), Paragraph(str("-{0:.2f}".format(round(payment.amount, 2))), styles["Line_Data_Large_Right"]) ] for payment in payments] last_row = len(data2) + 2 data3 = [[ Paragraph('Remaining Balance Due', styles["Line_Data_Large"]), Paragraph(str("${0:.2f}".format(round(remaining_balance, 2))), styles["Line_Data_Large_Right"]) ]] all_data = data1 + data2 + data3 t1 = Table(all_data, colWidths=(14 * cm, 4.6 * cm)) t1.setStyle( TableStyle([ ('BOX', (0, 0), (-1, -1), .25, colors.black), ('VALIGN', (0, 0), (-1, -1), 'MIDDLE'), ('BACKGROUND', (0, 0), (-1, 0), colors.lightgrey), # we propose ('BACKGROUND', (0, last_row), (-1, last_row), colors.lightgrey), # payment outline ])) story.append(KeepTogether(t1)) elif employee: # If employee skip rest of bid info pass else: # Proposal if obj.custom_down_payment and obj.custom_down_payment != -1: down_payment = obj.custom_down_payment elif obj.custom_down_payment == -1: down_payment = 0 else: if bid_total: down_payment = bid_total / 2 else: down_payment = 0 if bid_total: cents = Decimal('0.01') final_payment = Decimal(bid_total - down_payment).quantize( cents, ROUND_HALF_UP) else: final_payment = 0 if not bid_total: bid_total = 0 we_propose = 'Hereby to furnish material and labor complete in accordance with above specifications,' \ ' for the sum of' acceptance = """The above prices, specifications and conditions are satisfactory and are hereby accepted. You are authorized to do the work as specified. Payment will be made as outlined above. I have received a copy of the Pre-Lien notice.""" data1 = [ [Paragraph('We Propose', styles["Line_Data_Large"]), None], [ Paragraph(we_propose, styles["Line_Data_Large"]), Paragraph(str("${0:.2f}".format(round(bid_total, 2))), styles["Line_Data_Large_Right"]) ], [Paragraph('Payment Outline', styles["Line_Data_Large"]), None], [ Paragraph('Deposit', styles["Line_Data_Large"]), Paragraph(str("${0:.2f}".format(round(down_payment, 2))), styles["Line_Data_Large_Right"]) ], [ Paragraph( 'Remaining Balance Due Upon Completion of the Contract', styles["Line_Data_Large"]), Paragraph(str("${0:.2f}".format(round(final_payment, 2))), styles["Line_Data_Large_Right"]) ], [ Paragraph('Acceptance of Proposal', styles["Line_Data_Large"]), None ], [Paragraph(acceptance, styles["Line_Data_Large"]), None], [ Paragraph('Signature:', styles["Line_Label"]), Paragraph('Date:', styles["Line_Label"]) ], [ Paragraph( 'X__________________________________________________________________', styles["Line_Label"]), Paragraph('_____________________', styles["Line_Label"]) ], ] t1 = Table(data1, colWidths=(14 * cm, 4.6 * cm)) t1.setStyle( TableStyle([ ('BOX', (0, 0), (-1, -1), .25, colors.black), ('VALIGN', (0, 0), (-1, -1), 'MIDDLE'), ('BACKGROUND', (0, 0), (-1, 0), colors.lightgrey), # we propose ('BACKGROUND', (0, 2), (-1, 2), colors.lightgrey), # payment outline ('BACKGROUND', (0, 5), (-1, 5), colors.lightgrey), # acceptance of proposal ('SPAN', (0, 6), (-1, 6)), # span acceptance text across both columns ('BOTTOMPADDING', (0, 7), (-1, 7), 40) ])) story.append(KeepTogether(t1)) # Add Pre-Lien Notice to PDF story.append(PageBreak()) pre_lien_notice = """ <br /> ANY PERSON OR COMPANY SUPPLYING LABOR OR MATERIALS FOR THIS IMPROVEMENT TO YOUR PROPERTY MAY FILE A LIEN AGAINST YOUR PROPERTY IF THAT PERSON OR COMPANY IS NOT PAID FOR THE CONTRIBUTIONS.<br /><br /> UNDER MINNESOTA LAW, YOU HAVE THE RIGHT TO PAY PERSONS WHO SUPPLIED LABOR OR MATERIALS FOR THIS IMPROVEMENT DIRECTLY AND DEDUCT THIS AMOUNT FROM OUR CONTRACT PRICE, OR WITHHOLD THE AMOUNTS DUE THEM FROM US UNTIL 120 DAYS AFTER COMPLETION OF THE IMPROVEMENT UNLESS WE GIVE YOU A LIEN WAIVER SIGNED BY PERSONS WHO SUPPLIED ANY LABOR OR MATERIAL FOR THE IMPROVEMENT AND WHO GAVE YOU TIMELY NOTICE. """ data1 = [[ Paragraph('PRE-LIEN NOTICE', styles["Line_Data_Large_Center"]) ], [Paragraph(pre_lien_notice, styles["Line_Data_Large"])]] t1 = Table(data1) story.append(t1) # doc.build(story, onFirstPage=_header_footer, onLaterPages=_header_footer, canvasmaker=NumberedCanvas) doc.build(story, canvasmaker=NumberedCanvas) pdf = buff.getvalue() buff.close() if return_file_object: # For send pdf to employee which isnt stored to database, return the file object return pdf if save_to_disk: myfile = ContentFile(pdf) db_model = PDFImage() db_model.bid = obj if invoice: filename_temp = 'invoice' else: filename_temp = 'proposal' db_model.filename.save(filename_temp, myfile) messages.success(request, "PDF was saved successfully!") return redirect('bid_app:bid_detail', pk=obj.id) if invoice: filename = "{}_invoice_{}".format( obj.customer.__str__().replace(' ', '_').replace(',', '').lower(), datetime.date.today()) else: filename = "{}_proposal_{}".format( obj.customer.__str__().replace(' ', '_').replace(',', '').lower(), datetime.date.today()) response = HttpResponse(content_type='application/pdf') response['Content-Disposition'] = 'filename={}.pdf'.format(filename) response.write(pdf) return response