def build_tabla_cabecera(canvas, datos_albaran, y1): # Cabecera. canvas.saveState() x1 = 1.0 * cm + 1 limite = x1 + 0.9 * PAGE_WIDTH incremento = (limite - x1) / 3 #y1 = 22.5 * cm y2 = y1 - 18 for texto, clave in (("Código cliente", "codcliente"), ("Nº Albarán", "número"), ("Fecha", "fecha")): x2 = x1 + incremento canvas.setFont("Times-Roman", 12) dato_albaran = escribe(datos_albaran[clave]) rectangulo(canvas, (x1, y1), (x2, y2), texto = dato_albaran, alinTxtX = "centro", alinTxtY = "centro") canvas.setFont("Times-Roman", 10) canvas.drawString(x1+0.2*cm, y1 + 3, texto) x1 += incremento canvas.restoreState() # Página x de y. canvas.saveState() canvas.setFont("Times-Italic", 9) canvas.drawRightString(0.9 * PAGE_WIDTH - 0.5 * cm, 1.0 * cm, escribe("Página %d de " % canvas.getPageNumber())) canvas.doForm("lastPageNumber") canvas.restoreState()
def cuadritos_en_ruta(): """ Devuelve dos flowables: Un texto centrado con el texto de "ENVASES VACÍOS..." y una tabla con el texto y los cuadraditos que se rellenan a mano durante la ruta del transportista. """ estilo_centrado = ParagraphStyle("Alineado centrado", parent=estilos["Normal"]) estilo_centrado.alignment = enums.TA_CENTER cab = Paragraph(escribe("ENVASES VACÍOS SIN LIMPIAR, 3 A.D.R."), estilo_centrado) datos = [["G.R.G. 1.000L", "", "", "BIDONES 100L", ""], ["", "", "", "", ""], ["DEPÓSITO 600L", "", "", "BIDONES 50L", ""], ["", "", "", "", ""], ["BIDONES 200L", "", "", "GARRAFAS 60L", ""], ["", "", "", "", ""], ["BIDONES 25L", "", "", "BIDONES 10L", ""]] datos = [[escribe(c) for c in fila] for fila in datos] tabla = Table(datos, colWidths = (3*cm, 0.75*cm, 5*cm, 3*cm, 0.75*cm)) tabla.setStyle(TableStyle([ ("BOX", (1, 0), (1, 0), 1.0, colors.black), ("BOX", (4, 0), (4, 0), 1.0, colors.black), ("BOX", (1, 2), (1, 2), 1.0, colors.black), ("BOX", (4, 2), (4, 2), 1.0, colors.black), ("BOX", (1, 4), (1, 4), 1.0, colors.black), ("BOX", (4, 4), (4, 4), 1.0, colors.black), ("BOX", (1, 6), (1, 6), 1.0, colors.black), ("BOX", (4, 6), (4, 6), 1.0, colors.black), ])) return KeepTogether([Spacer(1, 0.3*cm), cab, Spacer(1, 0.5*cm), tabla])
def solo_cabecera(canvas, doc, datos_de_la_empresa, datos_albaran): """ Escribe el texto "ALBARÁN" y los datos del cliente. Los datos del cliente vienen en un diccionario con: código (de cliente), cif, razón social, dirección, población, provincia. """ fuente = "Helvetica" tamanno = 24 canvas.saveState() canvas.setFont(fuente, tamanno) canvas.drawString( PAGE_WIDTH - canvas.stringWidth(escribe("ALBARÁN"), fuente, tamanno) - 1.0 * cm, PAGE_HEIGHT - 1.5 * cm, escribe("ALBARÁN"), ) canvas.restoreState() # Datos de la empresa dibujar_datos_empresa(canvas, datos_de_la_empresa) # logo, empresa = build_logo_y_empresa_por_separado(datos_de_la_empresa) ##LineaHorizontal(0.9 * PAGE_WIDTH).drawOn(canvas, 78.0, 12.5*cm) ##LineaHorizontal(0.9 * PAGE_WIDTH).drawOn(canvas, 78.0, 12.4 *cm) # logo.drawOn(canvas, 1*cm, PAGE_HEIGHT - 2.8 * cm) # fuente = "Helvetica" # tamanno = 10 # for i in range(len(empresa)): # linea = PAGE_HEIGHT - 1.5 * cm # el_encogedor_de_fuentes_de_doraemon(canvas, # fuente, # tamanno, # 3.25*cm, # PAGE_WIDTH - 1*cm, # linea - (i*0.5*cm), # escribe(empresa[i])) # Cabecera. build_tabla_cabecera(canvas, datos_albaran, 26.0 * cm)
def build_tabla_contenido(data): """ Construye la tabla del contenido del albaranSalida. Los datos deben venir en listas. Cada línea de la tabla, una tupla o lista con el código, descripción, cantidad, precio unitario (con dto. si lo lleva e IVA) y número de pedido. El precio y cantidad deben ser flotantes para poder calcular el subtotal. """ estilo_cabecera_tabla = ParagraphStyle("Cabecera tabla", parent=estilos["Heading3"]) estilo_cabecera_tabla.fontName = "Times-Bold" estilo_cabecera_tabla.alignment = enums.TA_CENTER estilo_numeros_tabla = ParagraphStyle("Números tabla", parent=estilos["Normal"]) estilo_numeros_tabla.alignment = enums.TA_RIGHT datos = [(Paragraph(escribe("Código"), estilo_cabecera_tabla), Paragraph(escribe("Descripción"), estilo_cabecera_tabla), Paragraph("Cantidad", estilo_cabecera_tabla), Paragraph("Precio/U", estilo_cabecera_tabla), #Paragraph("Total c/IVA", estilo_cabecera_tabla), # CWT: Prefiere la carta de portes sin IVA. Paragraph("Total", estilo_cabecera_tabla), Paragraph(escribe("Nº Pedido"), estilo_cabecera_tabla)) ] for d in data: fila = (escribe(d[0]), Paragraph(escribe(d[1]),estilos["Normal"]), Paragraph(escribe(utils.float2str(d[2])),estilo_numeros_tabla), Paragraph(escribe(utils.float2str(d[3])),estilo_numeros_tabla), Paragraph(escribe(utils.float2str(d[2] * d[3])), estilo_numeros_tabla), escribe(d[4]) ) datos.append(fila) tabla = Table(datos, colWidths = (PAGE_WIDTH * 0.13, PAGE_WIDTH * 0.35, PAGE_WIDTH * 0.09, PAGE_WIDTH * 0.09, PAGE_WIDTH * 0.13, PAGE_WIDTH * 0.11), repeatRows = 1) tabla.setStyle(TableStyle([ ("BACKGROUND", (0, 0), (-1, 0), colors.lightgrey), ("LINEBEFORE", (0, 0), (-1, -1), 0.25, colors.black), ("LINEBELOW", (0, 0), (-1, 0), 1.0, colors.black), ("LINEBELOW", (0, "splitlast"), (-1, "splitlast"), 1.0, colors.black), ("BOX", (0, 0), (-1, -1), 1.0, colors.black), ("INNERGRID", (0, 0), (-1, -1), 0.25, colors.black), ("VALIGN", (0, 0), (-1, 0), "CENTER"), ("VALIGN", (0, 0), (0, -1), "TOP"), ("ALIGN", (0, 0), (-1, 0), "CENTER"), ("ALIGN", (-3, 1), (-1, -1), "RIGHT"), #("ALIGN", (0, 1), (0, -1), "DECIMAL"), <- No puedo cambiar # el pivotChar de "." a ",". No me vale. ("ALIGN", (-1, 1), (-1, -1), "CENTER"), ("ALIGN", (0, 1), (0, -1), "CENTER"), #("RIGHTPADDING", (0, 1), (0, -1), 0.75 * cm), ])) return tabla
def build_tabla_vencimientos(observaciones, vencimientos, forma_de_pago): """ Los tres parámetros pueden ser una única cadena o una lista de cadenas. Si es lo segundo, cada elemento irá en una celda independiente. """ datos = [["Observaciones", "Vencimientos", "Forma de pago"]] for columna, lista in ((0, observaciones), (1, vencimientos), (2, forma_de_pago)): if isinstance(lista, str): lista = [lista] fila = 1 for elemento in lista: try: datos[fila][columna] = elemento except IndexError: datos.append(["", "", ""]) datos[fila][columna] = elemento finally: fila += 1 datos = sanitize(datos) estilo_cont_tabla = ParagraphStyle("Contenido tabla", parent=estilos["Normal"]) estilo_cont_tabla.alignment = enums.TA_JUSTIFY estilo_cont_tabla.fontSize += 2 _datos = [] fila = [] for celda in datos[0]: #fila.append(Paragraph(celda, estilos["Normal"])) fila.append(escribe(celda)) _datos.append(fila) for fila_datos in datos[1:]: fila = [] for celda in fila_datos: fila.append(Paragraph(escribe(celda), estilo_cont_tabla)) _datos.append(fila) datos = _datos tabla = TablaFija(78, 3*cm, datos, colWidths = (PAGE_WIDTH * 0.9 * 0.5, PAGE_WIDTH * 0.9 * 0.25, PAGE_WIDTH * 0.9 * 0.25)) #tabla = Table(datos, # colWidths = (PAGE_WIDTH * (0.9/3),)*3) tabla.setStyle(TableStyle([ ("BACKGROUND", (0, 0), (-1, 0), colors.lightgrey), ("LINEBELOW", (0, 0), (-1, 0), 1.0, colors.black), ("BOX", (0, 0), (-1, -1), 1.0, colors.black), ("LINEBEFORE", (1, 1), (1, -1), 0.5, colors.black), ("LINEBEFORE", (2, 1), (2, -1), 0.5, colors.black), #("INNERGRID", (0, 0), (-1, -1), 1.0, colors.black), ("ALIGN", (0, 0), (-1, 0), "CENTER"), ])) return tabla
def build_datos_cliente(datos_cliente = []): """ Devuelve una lista de Flowables con las líneas recibidas como texto. """ datos_c = [] estilo_datos_c = ParagraphStyle("Cliente", parent = estilos["Heading3"]) estilo_datos_c.alignment = enums.TA_RIGHT estilo_datos_c.spaceAfter = estilo_datos_c.spaceBefore = 2 if datos_cliente: try: datos_cliente[0] = "<strong>%s</strong>" % datos_cliente[0] except TypeError: datos_cliente = ["<strong>%s</strong>" % datos_cliente[0]] \ + list(datos_cliente[1:]) tamanno_predeterminado = estilo_datos_c.fontSize for linea in datos_cliente: # ¡Esto debería hacerlo ReportLab, pero no sé por qué el markup # sólo funciona con el estilo normal! if "<strong>" in linea: estilo_datos_c.fontSize += 4 else: estilo_datos_c.fontSize = tamanno_predeterminado p = Paragraph(escribe(linea), estilo_datos_c) datos_c.append(p) return datos_c
def build_encabezado(datos_albaran): """ Devuelve una tabla de dos líneas con los datos del albarán, que es un diccionario de: fecha -como texto-, número (de albarán), kilos, bultos. """ datos_albaran = sanitize(datos_albaran) datos = [["Fecha", escribe("Nº Albarán"), "Kilos", "Bultos"], [datos_albaran["fecha"], datos_albaran["número"], datos_albaran["kilos"], datos_albaran["bultos"]]] estilo_centrado = ParagraphStyle("Alineado centrado", parent=estilos["Normal"]) estilo_centrado.alignment = enums.TA_CENTER estilo_centrado.fontSize += 2 datos = [[Paragraph(celda, estilos["Normal"]) for celda in datos[0]] , [Paragraph(celda, estilo_centrado) for celda in datos[1]]] tabla = Table(datos, colWidths = (PAGE_WIDTH * 0.9/4,)*4) tabla.setStyle(TableStyle([ ("BOX", (0, 1), (-1, -1), 1.0, colors.black), ("INNERGRID", (0, 1), (-1, -1), 0.25, colors.black), ("ALIGN", (0, 0), (-1, 0), "LEFT"), ("ALIGN", (0, 1), (-1, 1), "CENTER"), ])) return tabla
def build_encabezado(datos_empresa = []): """ Devuelve una lista de "Flowables" de reportlab con los datos de la empresa. Los datos de la empresa se reciben como una lista de textos. """ cabecera = [] estilo_encabezado = ParagraphStyle("Encabezado", parent = estilos["Heading2"]) estilo_encabezado.rightIndent = PAGE_WIDTH * 0.25 estilo_encabezado.alignment = enums.TA_JUSTIFY estilo_encabezado.spaceAfter = 0 estilo_encabezado.spaceBefore = 4 datos_empresa[0] = datos_empresa[0].upper() for linea in datos_empresa: if linea is datos_empresa[0]: estilo_encabezado.fontSize += 3 p = Paragraph(escribe(linea), estilo_encabezado) cabecera.append(p) estilo_encabezado.fontSize -= 1 if estilo_encabezado.spaceAfter > -4: estilo_encabezado.spaceAfter -= 1 estilo_encabezado.spaceBefore = estilo_encabezado.spaceAfter if linea is datos_empresa[0]: estilo_encabezado.fontSize -= 3 return cabecera
def build_texto(titular): """ Construye el texto genérico de la carta de portes. """ estilo_texto = ParagraphStyle("Texto", parent=estilos["Normal"]) estilo_texto.alignment = enums.TA_JUSTIFY estilo_texto.firstLineIndent = 24 estilo_texto.fontSize = 8 estilo_texto.leading = 9 texto = ( """%s hace constar que esta materia se admite al transporte por carretera de acuerdo con las disposiciones del proyecto europeo del transporte de mercancías peligrosas por carretera (ADR) y del reglamento nacional para el transporte de mercancías peligrosas por carretera (TPC). El abajo firmante (conductor y/o transportista) declara: 1.- Que el vehículo cargado cumple las condiciones que establece el reglamento nacional para el transporte de mercancías peligrosas por carretera (ADR/TPC). 2.- Que se ha efectuado correctamente la carga y/o estiba de la mercancía de acuerdo con el citado reglamento. 3.- Que ha recibido la hoja de instrucciones escritas respecto a: - Naturaleza del peligro de la mercancía a transportar. - Medidas de seguridad y otras a tener en cuenta en caso de accidentes, incendio, derrame y otros, todas las cuales ha leído y conoce. 4.- Conocer las disposiciones generales y especiales sobre vehículos, carga, descarga y manipulación de la mercancía, circulación y otras que se establecen para este transporte en el citado reglamento. 5.- El transportista asume la responsabilidad por cualquier accidente ocurrido durante el transporte, sea cual fuere el lugar del siniestro una vez que la mercancía le haya sido entregada. """ % titular ) p = [Paragraph(escribe(t), estilo_texto) for t in texto.split("\n")] estilo_texto2 = ParagraphStyle("Texto2", parent=estilo_texto) estilo_texto2.alignment = enums.TA_CENTER estilo_texto2.firstLineIndent = 0 # estilo_texto2.fontSize = 8 texto2 = """<b><font size=12>UN 1263, PINTURAS O PRODUCTOS PARA LA PINTURA, 3, II, ADR</b></font>""" texto3 = """ GRG DEPÓSITO 600L BIDÓN 200L BIDÓN 100L ENVASES METÁLICOS GARRAFAS 60L GARRAFAS 25L LEY 11/79 (ART.18.1 DEL REGLAMENTO) el responsable de la entrega del envase usado será el poseedor final Fdo. Conductor Matrícula: Fdo. El expedidor Fdo. El cliente Fdo. Central de carga """ p.append(XPreformatted(escribe(texto2), estilo_texto2)) p.append(XPreformatted(escribe(texto3), estilo_texto2)) return KeepTogether(p)
def build_head2(texto, ancho_linea = PAGE_WIDTH - 5.5*cm, offset_linea = 0.0): """ Devuelve el texto con el estilo de encabezado de 2º. nivel y el subrayado. """ estilo_head2 = ParagraphStyle("Header2", parent = estilos["Normal"]) estilo_head2.fontSize = 14 estilo_head2.fontName = "Times-Italic" estilo_head2.textColor = colors.gray texto = Paragraph(escribe(texto), estilo_head2) linea = LineaHorizontal(ancho_linea, offset = offset_linea, color = colors.green) return KeepTogether([texto, Spacer(1, 0.1*cm), linea, Spacer(1, 0.15*cm)])
def build_mas_texto(titular): """ Construye más texto genérico de la carta de portes. """ estilo_texto = ParagraphStyle("Texto", parent=estilos["Normal"]) estilo_texto.alignment = enums.TA_JUSTIFY estilo_texto.firstLineIndent = 24 estilo_texto.fontSize = 8 texto = ( """%s hace constar que esta materia se admite al transporte por carretera, de acuerdo con las disposiciones del proyecto europeo del transporte de mercancías peligrosas por carretera (ADR) y del reglamento nacional para el transporte de mercancías peligrosas por carretera (TPC). El abajo firmante (conductor y/o transportista) declara: 6.- Que el vehículo cargado cumple las condiciones que establece el Reglamento Nacional para el Transporte de Mercancías Peligrosas por carretera (ADR/TPC). 7.- Que se ha efectuado correctamente la carga y/o estiba de la mercancía de acuerdo con el citado Reglamento. 8.- Que ha recibido la hoja de instrucciones escrita respecto a: - Naturaleza del peligro de la mercancía a transportar. - Medidas de seguridad y otras a tener en cuenta en caso de accidentes, incendio, derrame y otros, todas las cuales ha leído y conoce. 9.- Conocer las disposiciones generales y especiales sobre vehículos, carga, descarga y manipulación de la mercancía, circulación y otras que se establecen para este transporte en el citado Reglamento. 10.- El transportista asume la responsabilidad por cualquier accidente ocurrido durante el transporte, sea cual fuere el lugar del siniestro una vez que la mercancía le haya sido entregada. """ % titular ) p = [Paragraph(escribe(t), estilo_texto) for t in texto.split("\n")] estilo_texto2 = ParagraphStyle("Texto2", parent=estilo_texto) estilo_texto2.alignment = enums.TA_CENTER estilo_texto2.firstLineIndent = 0 # estilo_texto2.fontSize = 8 texto2 = """<b><font size=12>UN 1263, PINTURAS O PRODUCTOS PARA LA PINTURA, 3, II, ADR</b></font> GRG DEPÓSITO 600L BIDÓN 200L BIDÓN 100L ENVASES METÁLICOS GARRAFAS 60L GARRAFAS 25L LEY 11/79 (ART.18.1 DEL REGLAMENTO) EL RESPONSABLE DE LA ENTREGA DEL ENVASE USADO SERÁ EL POSEEDOR FINAL FDO. CONDUCTOR MATRÍCULA: FDO. EL EXPEDIDOR FDO. EL CLIENTE """ p.append(XPreformatted(escribe(texto2), estilo_texto2)) p.append(XPreformatted(" FECHA:", estilo_texto)) return p
def build_texto(datos_de_la_empresa): """ Construye el texto genérico de la carta de portes. """ estilo_texto = ParagraphStyle("Texto", parent = estilos["Normal"]) estilo_texto.alignment = enums.TA_JUSTIFY estilo_texto.firstLineIndent = 24 estilo_texto.fontSize = 8 estilo_texto.leading = 9 texto = """Norma UNE EN 13249:2001 y UNE EN 13249:2001/A1:2005, Norma UNE EN 13250:2001 y UNE EN 13250:2001/A1:2005, Norma UNE EN 13251:2001 y UNE EN 13251:2001/A1:2005, Norma UNE EN 13252:2001, UNE EN 13252/Erratum:2002 y UNE EN 13252:2001/A1:2005, Norma UNE EN 13253:2001 y UNE EN 13253:2001/A1:2005, Norma UNE EN 13254:2001, UNE EN 13254/AC:2003 y UNE EN 13254:2001/A1:2005, Norma UNE EN 13255:2001, UNE EN 13255/AC:2003 y UNE EN 13255:2001/A1:2005, Norma UNE EN 13256:2001, UNE EN 13256/AC:2003 y UNE EN 13256:2001/A1:2005,Norma UNE EN 13257:2001, UNE EN 13257/AC:2003 y UNE EN 13257:2001/A1:2005, Norma UNE EN 13265:2001, UNE EN 13265/AC:2003 y UNE EN 13265:2001/A1:2005. Geotextil no tejido formado por fibras vírgenes <b>100% de polipropileno</b>, unidas mecánicamente por un proceso de agujado con posterior termofijado. Campo de aplicación: en carreteras y otras zonas de tráfico, construcciones ferroviarias, movimientos de tierras, cimentaciones y estructuras de contención, sistemas de drenaje, control de la erosión (protección costera y revestimiento de taludes), construcción de embalses y presas, construcción de canales, construcción de túneles y estructuras subterráneas, vertederos de residuos sólidos, proyectos de contenedores de residuos sólidos. """ p = [Paragraph(escribe(t), estilo_texto) for t in texto.split("\n") if t] p.insert(1, Spacer(1, 0.25*cm)) logo_ce = Image(os.path.join("..", "imagenes", "CE.png")) logo_ce.drawHeight = 0.75*cm logo_ce.drawWidth = 1*cm p.insert(0, logo_ce) p.insert(1, Spacer(1, 0.15*cm)) estilo_numero_marcado = ParagraphStyle("NumeroMarcado", parent = estilos["Normal"]) estilo_numero_marcado.alignment = enums.TA_CENTER estilo_numero_marcado.fontSize = 7 estilo_numero_marcado.fontName = "Courier" p.insert(2, Paragraph(escribe("9000122-1035"), estilo_numero_marcado)) estilo_nombre_empresa = ParagraphStyle("NombreEmpresa", parent = estilos["Normal"]) estilo_nombre_empresa.alignment = enums.TA_CENTER estilo_nombre_empresa.fontSize = 7 estilo_nombre_empresa.fontName = "Courier-Bold" nombre_empresa = datos_de_la_empresa.nombre p.insert(3, Paragraph(escribe(nombre_empresa.upper()), estilo_nombre_empresa)) p.insert(4, Spacer(1, 0.15*cm)) return KeepTogether(p)
def pie(canvas, datos_de_la_empresa): canvas.saveState() tamanno = 8 fuente = "Times-Bold" canvas.setFont(fuente, tamanno) canvas.drawString(2*cm, 2.2*cm, escribe(datos_de_la_empresa.nombre.upper())) fuente = "Times-Roman" canvas.setFont(fuente, tamanno) canvas.drawString(2*cm, 1.9*cm, escribe(datos_de_la_empresa.direccion)) canvas.drawString(2*cm, 1.6*cm, escribe("%s - %s (%s), %s" % ( datos_de_la_empresa.cp, datos_de_la_empresa.ciudad, datos_de_la_empresa.provincia, datos_de_la_empresa.pais))) canvas.drawString(2*cm, 1.3*cm, escribe("Tel.: %s Fax: %s" % ( datos_de_la_empresa.telefono, datos_de_la_empresa.fax))) # FIXME: Está un poco chungaleta esto, pero para no meter más datos en # la tabla ahora mismo y por no perder mucho tiempo con chequeos lo dejo # de momento así hasta que llegue a pruebas. canvas.drawString(2*cm, 1*cm, escribe("Web: www.%s Correo-e: %s" % ( datos_de_la_empresa.email.split("@")[1], datos_de_la_empresa.email))) canvas.restoreState()
def build_texto(texto): """ El texto que encabeza la tabla. """ res = None if texto: estilo_texto = ParagraphStyle("Texto", parent = estilos["Normal"]) estilo_texto.alignment = enums.TA_JUSTIFY estilo_texto.firstLineIndent = 24 _res = [Paragraph(escribe(i), estilo_texto) for i in texto.split("\n")] espacio = Spacer(1, 0.25*cm) res = [_res[0]] for i in _res[1:]: res.extend([espacio, i]) return res
def build_todavia_mas_texto(): """ Construye más texto genérico de la carta de portes. """ estilo_texto = ParagraphStyle("Texto", parent=estilos["Normal"]) estilo_texto.alignment = enums.TA_JUSTIFY estilo_texto.firstLineIndent = 24 estilo_texto.fontSize = 12 texto = """ Transporte que no excede de los límites establecidos en el capítulo 1.1.3.6. """ estilo_texto2 = ParagraphStyle("Texto2", parent=estilo_texto) estilo_texto2.alignment = enums.TA_CENTER estilo_texto2.firstLineIndent = 0 # estilo_texto2.fontSize = 8 p = Paragraph(escribe(texto), estilo_texto2) return p
def build_encabezado(datos_empresa = []): """ Devuelve una lista de "Flowables" de reportlab con los datos de la empresa. Los datos de la empresa se reciben como una lista de textos. """ cabecera = [] estilo_encabezado = ParagraphStyle("Encabezado", parent = estilos["Heading2"]) estilo_encabezado.rightIndent = PAGE_WIDTH * 0.4 estilo_encabezado.alignment = enums.TA_CENTER estilo_encabezado.spaceAfter = estilo_encabezado.spaceBefore = 6 for linea in datos_empresa: p = Paragraph(escribe(linea), estilo_encabezado) cabecera.append(p) estilo_encabezado.fontSize -= 1 if estilo_encabezado.spaceAfter > 0: estilo_encabezado.spaceAfter -= 1 estilo_encabezado.spaceBefore = estilo_encabezado.spaceAfter return cabecera
def dibujar_datos_empresa(canvas, datos_de_la_empresa): """ Dibuja los datos de la empresa en la parte superior. """ logo, empresa = build_logo_y_empresa_por_separado(datos_de_la_empresa) logo.drawOn(canvas, 1*cm, PAGE_HEIGHT - 2.8 * cm) fuente = "Helvetica" tamanno = 16 for i in range(len(empresa)): if i == 1: tamanno -= 4 # Primera línea (nombre empresa) un poco más grande. linea = PAGE_HEIGHT - 1.5 * cm el_encogedor_de_fuentes_de_doraemon(canvas, fuente, tamanno, 3.25*cm, PAGE_WIDTH - 5*cm, linea - (i*0.55*cm), escribe(empresa[i]))
def cabecera(canvas, datos_de_la_empresa): """ Escribe el texto «CERTIFICADO DE CALIDAD», el logotipo de la empresa, una imagen de geotextiles y un par de rayajos de adorno. """ fuente = "Helvetica-Bold" tamanno = 12 canvas.saveState() canvas.setFont(fuente, tamanno) canvas.drawCentredString(PAGE_WIDTH / 2.0 + 1*cm, PAGE_HEIGHT - 2 * cm, escribe("CERTIFICADO DE CALIDAD")) canvas.restoreState() rutalogo = datos_de_la_empresa.logo if rutalogo: rutalogo = os.path.join("..", "imagenes", rutalogo) logo = Image(rutalogo) logo.drawHeight = 2*cm * logo.drawHeight / logo.drawWidth logo.drawWidth = 2*cm logo.drawOn(canvas, 2.75*cm, PAGE_HEIGHT - 1*cm - 2*cm) # OJO: Foto de geotextiles HARCODED. rutafoto = os.path.join("..", "imagenes", "foto_geotextiles.jpg") foto = Image(rutafoto) foto.drawHeight = 2*cm * foto.drawHeight / foto.drawWidth foto.drawWidth = 2*cm foto.drawOn(canvas, PAGE_WIDTH - 5*cm, PAGE_HEIGHT - 2.75*cm - 2*cm) canvas.saveState() canvas.setStrokeColor(colors.green) canvas.rect(PAGE_WIDTH - 5*cm, PAGE_HEIGHT - 2.75*cm - 2*cm, 2*cm, 2*cm) ## XXX: Esto de ahora es un poco chapuza, y como cambie algún margen se va ## al carajo este trocito de línea que se supone que debería ser parte de ## la sección Denominación. canvas.line(PAGE_WIDTH - 5*cm + 2*cm, PAGE_HEIGHT - 3.25*cm, PAGE_WIDTH - 5*cm + 2.25*cm, PAGE_HEIGHT - 3.25*cm) ## XXX: EOChapuza canvas.restoreState() canvas.line(5*cm, PAGE_HEIGHT - 1*cm, # (x1, y1) 5*cm, PAGE_HEIGHT - 2.5*cm) # (x2, y2) canvas.line(PAGE_WIDTH - 3*cm, PAGE_HEIGHT - 1*cm, # (x1, y1) PAGE_WIDTH - 3*cm, PAGE_HEIGHT - 2.5*cm) # (x2, y2) # En la primera página también debe ir el pie pie(canvas, datos_de_la_empresa)
def cabecera_y_cliente(canvas, doc, datos_cliente, datos_de_la_empresa, datos_albaran): """ Escribe el texto "ALBARÁN" y los datos del cliente. Los datos del cliente vienen en un diccionario con: código (de cliente), cif, razón social, dirección, población, provincia. """ fuente = "Helvetica" tamanno = 24 canvas.saveState() canvas.setFont(fuente, tamanno) canvas.drawString( PAGE_WIDTH - canvas.stringWidth(escribe("ALBARÁN"), fuente, tamanno) - 1.0 * cm, PAGE_HEIGHT - 1.5 * cm, escribe("ALBARÁN"), ) canvas.restoreState() tamanno = 12 altura_linea = 16 xCliente = (PAGE_WIDTH - 1 * cm) / 2.5 linea = (PAGE_HEIGHT - 1.5 * cm) - 0.10 * cm - 2 * cm rectangulo( canvas, (xCliente - 0.2 * cm, PAGE_HEIGHT - 1.5 * cm + altura_linea - 2 * cm), (PAGE_WIDTH - 1 * cm, (PAGE_HEIGHT - 1.5 * cm + altura_linea) - (altura_linea * 5 + 0.5 * cm) - 2 * cm), ) canvas.drawString( xCliente, linea, escribe("Cód. cliente: %s C.I.F.: %s" % (datos_cliente["código"], datos_cliente["cif"])) ) linea -= altura_linea el_encogedor_de_fuentes_de_doraemon( canvas, fuente, tamanno, xCliente, PAGE_WIDTH - 1 * cm, linea, escribe(datos_cliente["razón social"]) ) linea -= altura_linea el_encogedor_de_fuentes_de_doraemon( canvas, fuente, tamanno, xCliente, PAGE_WIDTH - 1 * cm, linea, escribe(datos_cliente["dirección"]) ) linea -= altura_linea canvas.drawString(xCliente, linea, escribe(datos_cliente["población"])) linea -= altura_linea canvas.drawString(xCliente, linea, escribe(datos_cliente["provincia"])) # Datos de la empresa dibujar_datos_empresa(canvas, datos_de_la_empresa) # Cabecera de factura build_tabla_cabecera(canvas, datos_albaran, 22.5 * cm)
def cabecera_y_cliente(canvas, doc, datos_cliente, datos_de_la_empresa, datos_factura): """ Escribe el texto "FACTURA" y los datos del cliente. Los datos del cliente vienen en un diccionario con: código (de cliente), cif, razón social, dirección, población, provincia. """ fuente = "Helvetica" tamanno = 24 # XXX CWT: Para poder taladrar y archivar sin comerse el cuerpo. canvas.translate(0.6*cm, 0) # XXX canvas.saveState() canvas.setFont(fuente, tamanno) canvas.drawString(PAGE_WIDTH - canvas.stringWidth(escribe("FACTURA"),fuente,tamanno) - 1.0*cm, PAGE_HEIGHT - 1.5*cm, escribe("FACTURA")) canvas.restoreState() tamanno = 12 altura_linea = 16 xCliente = (PAGE_WIDTH - 1*cm) / 2.5 linea = (PAGE_HEIGHT-1.5*cm) - 0.10*cm - 2*cm rectangulo(canvas, (xCliente - 0.2*cm, PAGE_HEIGHT - 1.5*cm + altura_linea - 2*cm), (PAGE_WIDTH - 1*cm, (PAGE_HEIGHT- 1.5*cm + altura_linea) -(altura_linea*5 + 0.5*cm) - 2*cm), doble = True ) canvas.drawString(xCliente, linea, escribe( "Cód. cliente: %s C.I.F.: %s" % ( datos_cliente['código'], datos_cliente['cif']))) linea -= altura_linea el_encogedor_de_fuentes_de_doraemon(canvas, fuente, tamanno, xCliente, PAGE_WIDTH - 1*cm, linea, escribe(datos_cliente['razón social'])) linea -= altura_linea el_encogedor_de_fuentes_de_doraemon(canvas, fuente, tamanno, xCliente, PAGE_WIDTH - 1*cm, linea, escribe(datos_cliente['dirección'])) linea -= altura_linea canvas.drawString(xCliente, linea, escribe(datos_cliente['población'])) linea -= altura_linea canvas.drawString(xCliente, linea, escribe(datos_cliente['provincia'])) # Datos de la empresa dibujar_datos_empresa(canvas, datos_de_la_empresa) # Cabecera de factura build_tabla_cabecera(canvas, datos_factura, 22.5*cm)
def cabecera_y_cliente(canvas, doc, datos_cliente, datos_de_la_empresa, titular, datos_albaran): """ Escribe el texto "ALBARÁN/CARTA DE PORTE" y los datos del cliente. Los datos del cliente vienen en un diccionario con: código (de cliente), cif, razón social, dirección, población, provincia. """ fuente = "Helvetica" tamanno = 12 canvas.drawString(1.0*cm, PAGE_HEIGHT - 1.5*cm, escribe("ALBARÁN/CARTA DE PORTE")) altura_linea = 16 xCliente = (PAGE_WIDTH - 1*cm) / 2.5 linea = (PAGE_HEIGHT-1.5*cm) - 0.10*cm rectangulo(canvas, (xCliente - 0.2*cm, PAGE_HEIGHT - 1.5*cm + altura_linea), (PAGE_WIDTH - 1*cm, (PAGE_HEIGHT- 1.5*cm + altura_linea)-(altura_linea*5 + 0.5*cm)) ) canvas.drawString(xCliente, linea, escribe( "Cód. cliente: %s C.I.F.: %s" % ( datos_cliente['código'], datos_cliente['cif']))) linea -= altura_linea el_encogedor_de_fuentes_de_doraemon(canvas, fuente, tamanno, xCliente, PAGE_WIDTH - 1*cm, linea, escribe("Razón social: %s" % datos_cliente['razón social'])) #canvas.drawString(xCliente, # linea, # escribe("Razón social: %s"%datos_cliente['razón social'])) linea -= altura_linea el_encogedor_de_fuentes_de_doraemon(canvas, fuente, tamanno, xCliente, PAGE_WIDTH - 1*cm, linea, escribe("Dirección: %s" % datos_cliente['dirección'])) #canvas.drawString(xCliente, # linea, # escribe("Dirección: %s" % datos_cliente['dirección'])) linea -= altura_linea canvas.drawString(xCliente, linea, escribe("Población: %s" % datos_cliente['población'])) linea -= altura_linea canvas.drawString(xCliente, linea, escribe("Provincia: %s" % datos_cliente['provincia'])) # Y el pie de página: logo, empresa = build_logo_y_empresa_por_separado(datos_de_la_empresa) LineaHorizontal(0.9 * PAGE_WIDTH).drawOn(canvas, 78.0, 12.5*cm) LineaHorizontal(0.9 * PAGE_WIDTH).drawOn(canvas, 78.0, 12.4 *cm) logo.drawOn(canvas, 3*cm, 10 * cm) fuente = "Helvetica" tamanno = 10 for i in range(len(empresa)): linea = 11.5 * cm el_encogedor_de_fuentes_de_doraemon(canvas, fuente, tamanno, 5.25*cm, PAGE_WIDTH - 1*cm, linea - (i*0.5*cm), escribe(empresa[i])) #logo_y_empresa.drawOn(canvas, 10.5*cm, 78.0) texto = build_texto(titular) lineas = [] for l in [p.text for p in texto._content]: lineas.extend(l.split("\n")) y = 9.5*cm tamanno = 8 centrado = False for linea in lineas: linea = linea.replace(" ", "") if "<b>" in linea: fuente = "Times-Bold" linea = linea.replace("<b>", "").replace("</b>", "") # Aprovechando que el Pisuerga... centrado = True else: fuente = "Times-Roman" if "<font size=12>" in linea: tamanno = 12 linea = linea.replace("<font size=12>", "").replace("</font>", "") else: tamanno = 10 lineas_agregadas = agregarFila(1*cm, y, PAGE_WIDTH - 1*cm, escribe(linea), canvas, fuente, tamanno, centrado = centrado) y -= lineas_agregadas * 10 #canvas.drawString(PAGE_WIDTH - 2*cm, 2*cm, str(canvas.getPageNumber())) #texto.drawOn(canvas, 9*cm, 72.0) # Página x de y. canvas.saveState() canvas.setFont("Times-Italic", 9) canvas.drawRightString(PAGE_WIDTH - 1.5*cm, 12.7*cm, escribe("Página %d de " % canvas.getPageNumber())) canvas.doForm("lastPageNumber") canvas.restoreState() # Cabecera. # Sí, ahora va aquí. No hace falta que ponga el CWT, ¿o sí? canvas.saveState() x1 = 1.0 * cm + 1 limite = x1 + 0.9 * PAGE_WIDTH incremento = (limite - x1) / 4 y1 = 24.5 * cm y2 = y1 - 18 for texto, clave in (("Fecha", "fecha"), ("Nº Albarán", "número"), ("Kilos", "kilos"), ("Bultos", "bultos")): x2 = x1 + incremento canvas.setFont("Times-Roman", 12) rectangulo(canvas, (x1, y1), (x2, y2), texto = escribe(datos_albaran[clave]), alinTxtX = "centro", alinTxtY = "centro") canvas.setFont("Times-Roman", 10) canvas.drawString(x1+0.2*cm, y1 + 3, texto) x1 += incremento canvas.restoreState()
def build_caracteristicas(dic_valores, orden = None): """ Si recibe una lista de valores en "orden" la seguirá para recorrer los valores a mostrar. En caso contrario el orden es aleatorio. """ head2 = build_head2("3.- Características técnicas") if not orden: orden = dic_valores.keys() # Voy construyendo párrafos para los datos de la tabla. datos = [[escribe("Característica"), escribe("Método de ensayo"), escribe("Unidad"), escribe("Valor")]] for caracteristica in orden: try: datos.append([escribe(dic_valores[caracteristica]["descripción"]), escribe(dic_valores[caracteristica]['método']), escribe(dic_valores[caracteristica]['unidad']), escribe(dic_valores[caracteristica]['valor'])]) except KeyError: if (caracteristica in dic_valores and "valor" in dic_valores[caracteristica]): datos.append([escribe(caracteristica), "", "", escribe(dic_valores[caracteristica]['valor'])]) estilo_centrado = ParagraphStyle("Alineado centrado", parent = estilos["Normal"]) estilo_centrado.alignment = enums.TA_CENTER estilo_centrado.textColor = colors.white estilo_centrado.fontSize = 8 estilo_tabla = ParagraphStyle("Estilo tabla", parent = estilo_centrado) estilo_tabla.alignment = enums.TA_JUSTIFY estilo_tabla.textColor = colors.black estilo_centrado_negro = ParagraphStyle("Estilo centrado negro", parent = estilo_centrado) estilo_centrado_negro.textColor = colors.black _datos = [[Paragraph(celda, estilo_centrado) for celda in datos[0]]] for fila in datos[1:]: primera_celda, resto = fila[0], fila[1:] _datos.append([Paragraph(primera_celda, estilo_tabla)] + [Paragraph(celda, estilo_centrado_negro) for celda in resto]) _datos.append([Paragraph(escribe("Durabilidad"), estilo_tabla), [ Paragraph(escribe("- A recubrir en el día de la " "instalación para refuerzos y en dos" " semanas para otras aplicaciones."), estilo_tabla), Paragraph(escribe("- Durabilidad prevista para un " "mínimo de 25 años en suelos " "naturales con 4<pH<9 y una " "temperatura <25 ºC."), estilo_tabla) ], "", ""]) #print len(_datos), len(datos) tabla = Table(_datos, style = [("SPAN", (-3, -1), (-1, -1)), ("BOX", ( 0, 0), (-1, -1), 0.50, colors.black), ("INNERGRID", ( 0, 0), (-1, -1), 0.50, colors.black), ("BACKGROUND", ( 0, 0), (-1, 0), colors.green), ("TEXTCOLOR", ( 0, 0), (-1, 0), colors.white), ("VALIGN", ( 0, 0), (-1, -1), "MIDDLE"), ], colWidths = (PAGE_WIDTH / 3.0, PAGE_WIDTH / 7.0, PAGE_WIDTH / 8.0, PAGE_WIDTH / 8.0)) return head2, tabla
def build_tabla_contenido(data): """ Construye la tabla del contenido del presupuesto. """ estilo_cabecera_tabla = ParagraphStyle("Cabecera tabla", parent=estilos["Heading3"]) estilo_cabecera_tabla.fontName = "Times-Bold" estilo_cabecera_tabla.alignment = enums.TA_CENTER estilo_numeros_tabla = ParagraphStyle("Números tabla", parent=estilos["Normal"]) estilo_numeros_tabla.alignment = enums.TA_RIGHT datos = [(Paragraph("Cantidad", estilo_cabecera_tabla), Paragraph(escribe("Descripción"), estilo_cabecera_tabla), Paragraph("Precio", estilo_cabecera_tabla), Paragraph("Importe", estilo_cabecera_tabla)) ] for d in data: if isinstance(d, (list, tuple)): fila = d[:4] elif isinstance(d, pclases.LineaDePedido): fila = (utils.float2str(d.cantidad, autodec = True), d.producto.descripcion, d.calcular_precio_unitario_coherente(precision = 2), utils.float2str(d.get_subtotal() + (d.precio * d.descuento * d.cantidad))) elif isinstance(d, pclases.Servicio): fila = (utils.float2str(d.cantidad, autodec = True), d.concepto, utils.float2str(d.precio), utils.float2str(d.get_subtotal() + (d.precio * d.descuento * d.cantidad))) _fila = (fila[0], Paragraph(escribe(fila[1]), estilos["Normal"]), Paragraph(escribe(fila[2]), estilo_numeros_tabla), Paragraph(escribe(fila[3]), estilo_numeros_tabla), ) datos.append(_fila) if d.descuento: fila_descuento = ("", "Descuento %s %%" % utils.float2str(d.descuento * 100, autodec = True), utils.float2str(-d.precio * d.descuento), utils.float2str(-d.precio*d.descuento*d.cantidad)) _fila = (fila_descuento[0], Paragraph(escribe(fila_descuento[1]),estilo_numeros_tabla), Paragraph(escribe(fila_descuento[2]),estilo_numeros_tabla), Paragraph(escribe(fila_descuento[3]),estilo_numeros_tabla), ) datos.append(_fila) tabla = Table(datos, colWidths = (PAGE_WIDTH * 0.1, PAGE_WIDTH * 0.45, PAGE_WIDTH * 0.15, PAGE_WIDTH * 0.2), repeatRows = 1) tabla.setStyle(TableStyle([ ("BACKGROUND", (0, 0), (-1, 0), colors.lightgrey), ("LINEBEFORE", (0, 0), (-1, -1), 0.25, colors.black), ("LINEBELOW", (0, 0), (-1, 0), 1.0, colors.black), ("LINEBELOW", (0, "splitlast"), (-1, "splitlast"), 1.0, colors.black), ("BOX", (0, 0), (-1, -1), 1.0, colors.black), ("VALIGN", (0, 0), (-1, 0), "CENTER"), ("VALIGN", (0, 0), (0, -1), "TOP"), ("ALIGN", (0, 0), (-1, 0), "CENTER"), ("ALIGN", (-3, 1), (-1, -1), "RIGHT"), #("ALIGN", (0, 1), (0, -1), "DECIMAL"), <- No puedo cambiar # el pivotChar de "." a ",". No me vale. ("ALIGN", (0, 1), (0, -1), "CENTER"), ("RIGHTPADDING", (0, 1), (0, -1), 0.75 * cm), ])) return tabla
def etiqueta_rollos_portrait(rollos, mostrar_marcado = True): """ Construye una etiqueta """ # Voy a tratar de reescribir esto regla en mano a ver si consigo # cuadrarlo bien en la etiquetadora GEMINI. height = 12.55 * cm width = 8.4 * cm # Escala ancho = 7.2 alto = 11.3 scale = height / alto # Medidas en papel. brand = (0.4 * scale, (alto - 2.0) * scale) logo = (3.8 * scale, (alto - 2.8) * scale) marcado = ((7.2/2) * scale, (alto - 3.0) * scale) column1 = .35 * scale column2 = logo[0] lineas = map(lambda x: (alto - x) * scale, [3.4 + (i*.6) for i in range(13)]) # Datos data = {'brand': "EkoTex", "c100": "UK Distributor", "c108": "Product Name", "c109": "Roll Number", "c110": "Product Dimensions", "c111": "Polymer", "c112": "Product Classification", "c200": "Geosynthetics Limited", "c201": "Fleming Road", "c202": "Harrowbrook Ind Est", "c203": "Hinckley", "c204": "Leicestershire", "c205": "LE10 3 DU", "c206": "Tel 01455 617139", "c207": "Fax 01455 617140", "c211": "Polypropylene", "c212": "GTX-N", "marcado": "0799-CPD", # Hay que incluirle el logotipo CE delante. } data["logo"] = os.path.abspath(os.path.join(os.path.dirname(__file__), "..", "imagenes", "logo_ekotex.png")) # Ruta absoluta # a la imagen del logotipo. logo_marcado = os.path.abspath(os.path.join(os.path.dirname(__file__), "..", "imagenes", "CE.png")) # Creo la hoja nomarchivo = os.path.join(gettempdir(), "etiqEkotex_%s.pdf" % give_me_the_name_baby()) c = canvas.Canvas(nomarchivo, pagesize = (width, height)) for rollo in rollos: try: data["c208"] = rollo['objeto'].productoVenta.nombre data["c209"] = rollo['objeto'].numrollo cer = rollo['objeto'].productoVenta.camposEspecificosRollo except AttributeError: # No se ha creado el objeto todavía. Es None. data["c208"] = rollo['productoVenta'].nombre data["c209"] = rollo['nrollo'] cer = rollo['productoVenta'].camposEspecificosRollo data["c210"] = "%sm x %dm" % (float2str(cer.ancho, autodec = True, separador_decimales = "."), cer.metrosLineales) rectangulo(c, (0.3 * cm, 0.3 * cm), (width - 0.3 * cm, height - 0.3 * cm)) c.setFont("Helvetica-Bold", 16) c.drawString(brand[0], brand[1], escribe(data['brand'])) c.setFont("Helvetica-Bold", 10) c.drawString(column1, lineas[0], escribe(data['c100'])) c.drawString(column1, lineas[8], escribe(data['c108'])) c.drawString(column1, lineas[9], escribe(data['c109'])) c.drawString(column1, lineas[10], escribe(data['c110'])) c.drawString(column1, lineas[11], escribe(data['c111'])) c.drawString(column1, lineas[12], escribe(data['c112'])) c.drawString(column2, lineas[0], escribe(data['c200'])) c.drawString(column2, lineas[1], escribe(data['c201'])) c.drawString(column2, lineas[2], escribe(data['c202'])) c.drawString(column2, lineas[3], escribe(data['c203'])) c.drawString(column2, lineas[4], escribe(data['c204'])) c.drawString(column2, lineas[5], escribe(data['c205'])) c.drawString(column2, lineas[6], escribe(data['c206'])) c.drawString(column2, lineas[7], escribe(data['c207'])) c.drawString(column2, lineas[8], escribe(data['c208'])) c.drawString(column2, lineas[9], escribe(data['c209'])) c.drawString(column2, lineas[10], escribe(data['c210'])) c.drawString(column2, lineas[11], escribe(data['c211'])) c.drawString(column2, lineas[12], escribe(data['c212'])) c.drawImage(data['logo'], logo[0], logo[1], 2.5 * cm, 2.5 * cm) if mostrar_marcado and not rollo['defectuoso']: c.drawImage(logo_marcado, marcado[0] - ((0.30*cm + c.stringWidth(data['marcado']) ) / 2), marcado[1], width = 0.35 * cm, height = 6) c.setFont("Helvetica-Bold", 8) c.drawCentredString(marcado[0] + ((0.35*cm) / 2), marcado[1], escribe(data["marcado"])) #c.setPageRotation(-90) #c.rotate(-90) c.showPage() c.save() return nomarchivo