Generar PDF ok

This commit is contained in:
Mauricio Baeza 2017-10-24 00:03:07 -05:00
parent 5fabcceb70
commit d960158bf8
5 changed files with 406 additions and 33 deletions

View File

@ -12,7 +12,7 @@ from email.mime.text import MIMEText
from email import encoders
from email.utils import formatdate
from reportlab.platypus import BaseDocTemplate, Frame, PageTemplate
from reportlab.platypus import BaseDocTemplate, Frame, PageTemplate, Image
from reportlab.lib import colors
from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
from reportlab.lib.units import cm
@ -105,7 +105,7 @@ class NumLet(object):
#~ texto_final='/100 m.n.)-', fraccion_letras=False, fraccion=''):
def _letters(self, numero, moneda='peso'):
texto_inicial = ''
texto_inicial = '-('
texto_final = '/100 m.n.)-'
fraccion_letras = False
fraccion = ''
@ -309,7 +309,7 @@ class SendMail(object):
class NumberedCanvas(canvas.Canvas):
X = 20.59 * cm
Y = 1 * cm
Y = 1.5 * cm
def __init__(self, *args, **kwargs):
canvas.Canvas.__init__(self, *args, **kwargs)
@ -335,6 +335,8 @@ class NumberedCanvas(canvas.Canvas):
self.setFillColor(colors.darkred)
text = 'Página {} de {}'.format(self._pageNumber, page_count)
self.drawRightString(self.X, self.Y, text)
text = 'Factura elaborada con software libre: www.empresalibre.net'
self.drawString(1.5 * cm, 1.5 * cm, text)
return
@ -366,6 +368,10 @@ class TemplateInvoice(BaseDocTemplate):
return
def _set_text(self, styles, value):
text = styles.pop('valor', '')
if not value:
value = text
rect = styles['rectangulo']
if value:
self.canv.setFillColor(colors.white)
@ -379,17 +385,174 @@ class TemplateInvoice(BaseDocTemplate):
return
def _emisor(self, styles, data):
logo_path = data.pop('logo', '')
logo_style = styles.pop('logo', {})
for k, v in styles.items():
self._set_text(styles[k], data.get(k, ''))
if logo_path and logo_style:
rect = logo_style['rectangulo']
keys = ('x', 'y', 'width', 'height')
for k in keys:
rect[k] = rect[k] * cm
self.canv.drawImage(logo_path, **rect)
return
def _receptor(self, styles, data):
title = styles.pop('titulo', {})
for k, v in styles.items():
self._set_text(styles[k], data.get(k, ''))
if title:
rect = title['rectangulo']
self.canv.saveState()
self.canv.rotate(90)
value = title.pop('valor', '')
title['rectangulo']['x'], title['rectangulo']['y'] = \
title['rectangulo']['y'], title['rectangulo']['x'] * -1
self._set_text(title, value)
self.canv.restoreState()
return
def _comprobante1(self, styles, data):
title = styles.pop('titulo', {})
for k, v in styles.items():
self._set_text(styles[k], data.get(k, ''))
if title:
rect = title['rectangulo']
self.canv.saveState()
self.canv.rotate(90)
value = title.pop('valor', '')
title['rectangulo']['x'], title['rectangulo']['y'] = \
title['rectangulo']['y'], title['rectangulo']['x'] * -1
self._set_text(title, value)
self.canv.restoreState()
return
def afterPage(self):
encabezado = self._custom_styles['encabezado']
self.canv.saveState()
self._emisor(encabezado['emisor'], self._data['emisor'])
self._receptor(encabezado['receptor'], self._data['receptor'])
self._comprobante1(encabezado['comprobante'], self._data['comprobante'])
self.canv.restoreState()
return
def _currency(self, value, simbol='$'):
return '{} {:,.2f}'.format(simbol, float(value))
def _format(self, value, field):
fields = ('valorunitario', 'importe')
if field in fields:
return self._currency(value)
return value
def _conceptos(self, conceptos):
headers = (('Clave', 'Descripción', 'Unidad', 'Cantidad',
'Valor Unitario', 'Importe'),)
fields = ('noidentificacion', 'descripcion', 'unidad', 'cantidad',
'valorunitario', 'importe')
rows = []
for concepto in conceptos:
row = tuple([self._format(concepto[f], f) for f in fields])
rows.append(row)
return headers + tuple(rows)
def _totales(self, values):
#~ print (values)
rows = [('', 'Subtotal', self._currency(values['subtotal']))]
for tax in values['traslados']:
row = ('', tax[0], self._currency(tax[1]))
rows.append(row)
for tax in values['retenciones']:
row = ('', tax[0], self._currency(tax[1]))
rows.append(row)
for tax in values['taxlocales']:
row = ('', tax[0], self._currency(tax[1]))
rows.append(row)
row = ('', 'Total', self._currency(values['total']))
rows.append(row)
widths = [12.5 * cm, 4 * cm, 3 * cm]
table_styles = [
('GRID', (0, 0), (-1, -1), 0.05 * cm, colors.white),
('ALIGN', (1, 0), (-1, -1), 'RIGHT'),
('FONTSIZE', (0, 0), (-1, -1), 8),
('BACKGROUND', (1, 0), (-1, -1), colors.linen),
('TEXTCOLOR', (1, 0), (-1, -1), colors.darkred),
('FACE', (1, 0), (-1, -1), 'Helvetica-Bold'),
]
table = Table(rows, colWidths=widths, spaceBefore=0.25*cm)
table.setStyle(TableStyle(table_styles))
return table
def _comprobante2(self, styles, data):
leyenda = styles.pop('leyenda', {})
ls = []
for k, v in styles.items():
if k in data:
if 'spaceBefore' in v['estilo']:
v['estilo']['spaceBefore'] = v['estilo']['spaceBefore'] * cm
ps = ParagraphStyle(**v['estilo'])
p = Paragraph(data[k], ps)
ls.append(p)
cbb = Image(data['path_cbb'])
cbb.drawHeight = 4 * cm
cbb.drawWidth = 4 * cm
style_bt = getSampleStyleSheet()['BodyText']
style_bt.leading = 8
html_t = '<b><font size=6>{}</font></b>'
html = '<font color="darkred" size=5>{}</font>'
msg = 'Cadena original del complemento de certificación digital del SAT'
rows = [
(cbb, Paragraph(html_t.format('Sello Digital del CFDI'), style_bt)),
('', Paragraph(html.format(data['sellocfd']), style_bt)),
('', Paragraph(html_t.format('Sello Digital del SAT'), style_bt)),
('', Paragraph(html.format(data['sellosat']), style_bt)),
('', Paragraph(html_t.format(msg), style_bt)),
('', Paragraph(html.format(data['cadenaoriginal']), style_bt)),
]
widths = [4 * cm, 15.5 * cm]
table_styles = [
('FONTSIZE', (0, 0), (-1, -1), 6),
('SPAN', (0, 0), (0, -1)),
('FACE', (1, 0), (1, 0), 'Helvetica-Bold'),
('BACKGROUND', (1, 1), (1, 1), colors.linen),
('TEXTCOLOR', (1, 1), (1, 1), colors.darkred),
('FACE', (1, 2), (1, 2), 'Helvetica-Bold'),
('BACKGROUND', (1, 3), (1, 3), colors.linen),
('TEXTCOLOR', (1, 3), (1, 3), colors.darkred),
('FACE', (1, 4), (1, 4), 'Helvetica-Bold'),
('BACKGROUND', (1, 5), (1, 5), colors.linen),
('TEXTCOLOR', (1, 5), (1, 5), colors.darkred),
('ALIGN', (0, 0), (0, 0), 'CENTER'),
('VALIGN', (0, 0), (0, 0), 'MIDDLE'),
]
table = Table(rows, colWidths=widths)
table.setStyle(TableStyle(table_styles))
ls.append(table)
if leyenda:
if 'spaceBefore' in leyenda['estilo']:
leyenda['estilo']['spaceBefore'] = \
leyenda['estilo']['spaceBefore'] * cm
msg = 'Este documento es una representación impresa de un CFDI'
ps = ParagraphStyle(**leyenda['estilo'])
p = Paragraph(msg, ps)
ls.append(p)
return ls
@property
def custom_styles(self):
return self._custom_styles
@ -402,23 +565,34 @@ class TemplateInvoice(BaseDocTemplate):
return self._data
@data.setter
def data(self, values):
#~ print (values)
self._data = values
text = 'Total este reporte = $ {}'.format('1,000.00')
ps = ParagraphStyle(
name='Total',
fontSize=12,
fontName='Helvetica-BoldOblique',
textColor=colors.darkred,
spaceBefore=0.5 * cm,
spaceAfter=0.5 * cm)
p1 = Paragraph(text, ps)
text = 'Nota: esta suma no incluye documentos cancelados'
ps = ParagraphStyle(
name='Note',
fontSize=7,
fontName='Helvetica-BoldOblique')
p2 = Paragraph('', ps)
self._rows = [p2]
rows = self._conceptos(self._data['conceptos'])
widths = [2 * cm, 9 * cm, 1.5 * cm, 2 * cm, 2 * cm, 3 * cm]
table_styles = [
('GRID', (0, 0), (-1, -1), 0.05 * cm, colors.white),
('FONTSIZE', (0, 0), (-1, 0), 7),
('ALIGN', (0, 0), (-1, 0), 'CENTER'),
('TEXTCOLOR', (0, 0), (-1, 0), colors.white),
('FACE', (0, 0), (-1, 0), 'Helvetica-Bold'),
('BACKGROUND', (0, 0), (-1, 0), colors.darkred),
('FONTSIZE', (0, 1), (-1, -1), 7),
('VALIGN', (0, 1), (-1, -1), 'TOP'),
('ALIGN', (0, 1), (0, -1), 'CENTER'),
('ALIGN', (2, 1), (2, -1), 'CENTER'),
('ALIGN', (3, 1), (5, -1), 'RIGHT'),
('LINEBELOW', (0, 1), (-1, -1), 0.05 * cm, colors.darkred),
('LINEBEFORE', (0, 1), (-1, -1), 0.05 * cm, colors.white),
]
table_conceptos = Table(rows, colWidths=widths, repeatRows=1)
table_conceptos.setStyle(TableStyle(table_styles))
totales = self._totales(self.data['totales'])
comprobante = self._comprobante2(
self._custom_styles['comprobante'], self.data['comprobante'])
self._rows = [Spacer(0, 6*cm), table_conceptos, totales] + comprobante
def render(self):
frame = Frame(self.leftMargin, self.bottomMargin,
@ -487,7 +661,7 @@ class ReportTemplate(BaseDocTemplate):
('GRID', (0, 0), (-1, -1), 0.25, colors.darkred),
('FONTSIZE', (0, 0), (-1, 0), 9),
('BOX', (0, 0), (-1, 0), 1, colors.darkred),
('TEXTCOLOR', (0, 0), (-1, 0), colors.darkred),
('TEXTCOLOR', (0, 0), (-1, 0), colors.black),
('FONTSIZE', (0, 1), (-1, -1), 8),
('ALIGN', (0, 0), (-1, 0), 'CENTER'),
('ALIGN', (0, 0), (0, -1), 'RIGHT'),

View File

@ -29,7 +29,7 @@ from dateutil import parser
from .helper import CaseInsensitiveDict, NumLet, SendMail, TemplateInvoice
from settings import DEBUG, log, template_lookup, COMPANIES, DB_SAT, \
PATH_XSLT, PATH_XSLTPROC, PATH_OPENSSL, PATH_TEMPLATES, PRE
PATH_XSLT, PATH_XSLTPROC, PATH_OPENSSL, PATH_TEMPLATES, PATH_MEDIA, PRE
#~ def _get_hash(password):
@ -774,14 +774,15 @@ def _comprobante(values, options):
'T': 'traslado',
}
data['tipodecomprobante'] = tipos.get(data['tipodecomprobante'])
data['lugarexpedicion'] = 'C.P. Expedición: {}'.format(data['lugarexpedicion'])
data['lugarexpedicion'] = 'C.P. de Expedición: {}'.format(data['lugarexpedicion'])
data['metododepago'] = options['metododepago']
data['formadepago'] = options['formadepago']
data['moneda'] = options['moneda']
data['tipocambio'] = 'Tipo de Cambio: $ {:0.2f}'.format(
float(data['tipocambio']))
if 'serie' in data:
data['folio'] = '{}-{}'.format(data['serie'], data['folio'])
return data
@ -792,6 +793,11 @@ def _emisor(doc, version, values):
if not node is None:
data.update(CaseInsensitiveDict(node.attrib.copy()))
data['regimenfiscal'] = values['regimenfiscal']
path = _join(PATH_MEDIA, 'logos', '{}.png'.format(data['rfc'].lower()))
if is_file(path):
data['logo'] = path
return data
@ -813,7 +819,7 @@ def _conceptos(doc, version):
if version == '3.3':
values['noidentificacion'] = '{}\n(SAT {})'.format(
values['noidentificacion'], values['ClaveProdServ'])
values['unidad'] = '({}) {}'.format(
values['unidad'] = '({})\n{}'.format(
values['ClaveUnidad'], values['unidad'])
data.append(values)
return data
@ -926,6 +932,7 @@ def get_data_from_xml(invoice, rfc, values):
'total': data['comprobante']['total'],
}
data['timbre'] = _timbre(doc, version, options)
data['comprobante'].update(data['timbre'])
return custom_styles, data

View File

@ -137,7 +137,7 @@ class SATRegimenes(BaseModel):
)
def __str__(self):
return '({}) {}'.format(self.key, self.name)
return '{} ({})'.format(self.name, self.key)
@classmethod
def get_(cls, ids):
@ -597,7 +597,7 @@ class SATUsoCfdi(BaseModel):
)
def __str__(self):
return 'Uso del CFDI: ({}) {}'.format(self.key, self.name)
return 'Uso del CFDI: {} ({})'.format(self.name, self.key)
@classmethod
def get_activos(cls, values):

View File

@ -17,6 +17,7 @@ EMAIL_SUPPORT = ('soporte@empresalibre.net',)
BASE_DIR = os.path.abspath(os.path.dirname(__file__))
PATH_STATIC = os.path.abspath(os.path.join(BASE_DIR, '..'))
PATH_TEMPLATES = os.path.abspath(os.path.join(BASE_DIR, '..', 'templates'))
PATH_MEDIA = os.path.abspath(os.path.join(BASE_DIR, '..', 'docs'))
PATH_CP = os.path.abspath(os.path.join(BASE_DIR, '..', 'db', 'cp.db'))
COMPANIES = os.path.abspath(os.path.join(BASE_DIR, '..', 'db', 'rfc.db'))

View File

@ -2,25 +2,216 @@
"encabezado": {
"emisor": {
"direccion": {
"rectangulo": {"x": 1.0, "y": 26.9, "width": 19.6, "height": 0.4,
"rectangulo": {"x": 1.0, "y": 26.2, "width": 19.6, "height": 0.4,
"radius": 0.1, "stroke": false, "fill": true, "color": "darkred"}
},
"nombre": {
"rectangulo": {"x": 10.6, "y": 25.9, "width": 10.0, "height": 0.4,
"rectangulo": {"x": 10.6, "y": 25.6, "width": 10.0, "height": 0.4,
"radius": 0.0, "stroke": false, "fill": false},
"estilo": {"name": "nombre", "fontName": "Helvetica-Bold", "fontSize": 12,
"alignment": 2, "textColor": "darkred", "backColor": "white"}
"estilo": {"name": "nombre", "fontName": "Helvetica-Bold",
"fontSize": 14, "alignment": 2, "textColor": "darkred",
"backColor": "white"}
},
"rfc": {
"rectangulo": {"x": 10.6, "y": 25.1, "width": 10.0, "height": 0.4,
"rectangulo": {"x": 10.6, "y": 25.0, "width": 10.0, "height": 0.4,
"radius": 0.0, "stroke": false, "fill": false},
"estilo": {"name": "rfc", "fontName": "Helvetica-Bold", "fontSize": 11,
"alignment": 2, "textColor": "darkred", "backColor": "white"}
"estilo": {"name": "rfc", "fontName": "Helvetica-Bold",
"fontSize": 12, "alignment": 2, "textColor": "darkred",
"backColor": "white"}
},
"regimenfiscal": {
"rectangulo": {"x": 10.6, "y": 24.4, "width": 10.0, "height": 0.4,
"radius": 0.0, "stroke": false, "fill": false},
"estilo": {"name": "regimenfiscal", "fontName": "Helvetica-Bold",
"fontSize": 7, "alignment": 2, "textColor": "darkred",
"backColor": "white"}
},
"logo": {
"rectangulo": {"x": 1.0, "y": 24.2, "width": 2.5, "height": 2.5}
}
},
"receptor": {
"titulo": {
"valor": "Receptor",
"rectangulo": {"x": 1.5, "y": 20.8, "width": 2.8, "height": 0.9,
"radius": 0.0, "stroke": false, "fill": false},
"estilo": {"name": "nombre", "fontName": "Helvetica-Bold",
"fontSize": 9, "alignment": 1, "textColor": "darkred",
"backColor": "linen"}
},
"nombre": {
"rectangulo": {"x": 2.0, "y": 23.2, "width": 15.0, "height": 0.4,
"radius": 0.0, "stroke": false, "fill": false},
"estilo": {"name": "nombre", "fontName": "Helvetica-Bold",
"fontSize": 10, "alignment": 0, "textColor": "black",
"backColor": "white"}
},
"rfc": {
"rectangulo": {"x": 2.0, "y": 22.5, "width": 10.0, "height": 0.4,
"radius": 0.0, "stroke": false, "fill": false},
"estilo": {"name": "rfc", "fontName": "Helvetica-Bold",
"fontSize": 9, "alignment": 0, "textColor": "black",
"backColor": "white"}
},
"usocfdi": {
"rectangulo": {"x": 2.0, "y": 20.7, "width": 15.0, "height": 0.4,
"radius": 0.0, "stroke": false, "fill": false},
"estilo": {"name": "usocfdi", "fontName": "Helvetica",
"fontSize": 8, "alignment": 0, "textColor": "black",
"backColor": "white"}
}
},
"comprobante": {
"titulo": {
"valor": "Datos CFDI",
"rectangulo": {"x": 14.0, "y": 20.8, "width": 2.8, "height": 0.9,
"radius": 0.0, "stroke": false, "fill": false},
"estilo": {"name": "nombre", "fontName": "Helvetica-Bold",
"fontSize": 9, "alignment": 1, "textColor": "darkred",
"backColor": "linen"}
},
"t_folio": {
"valor": "Folio:",
"rectangulo": {"x": 14.2, "y": 23.2, "width": 1.0, "height": 0.8,
"radius": 0.0, "stroke": false, "fill": false},
"estilo": {"name": "nombre", "fontName": "Helvetica-Bold",
"fontSize": 8, "alignment": 0, "textColor": "black",
"backColor": "white"}
},
"folio": {
"rectangulo": {"x": 15.1, "y": 23.2, "width": 3.0, "height": 0.4,
"radius": 0.0, "stroke": false, "fill": false},
"estilo": {"name": "nombre", "fontName": "Helvetica-Bold",
"fontSize": 8, "alignment": 0, "textColor": "red",
"backColor": "white"}
},
"t_tipo": {
"valor": "Tipo:",
"rectangulo": {"x": 18.2, "y": 23.2, "width": 1.0, "height": 0.8,
"radius": 0.0, "stroke": false, "fill": false},
"estilo": {"name": "nombre", "fontName": "Helvetica-Bold",
"fontSize": 8, "alignment": 0, "textColor": "black",
"backColor": "white"}
},
"tipodecomprobante": {
"rectangulo": {"x": 19.0, "y": 23.2, "width": 1.5, "height": 0.8,
"radius": 0.0, "stroke": false, "fill": false},
"estilo": {"name": "nombre", "fontName": "Helvetica-Bold",
"fontSize": 8, "alignment": 0, "textColor": "red",
"backColor": "white"}
},
"t_uuid": {
"valor": "Folio Fiscal:",
"rectangulo": {"x": 14.2, "y": 22.7, "width": 3.0, "height": 0.4,
"radius": 0.0, "stroke": false, "fill": false},
"estilo": {"name": "nombre", "fontName": "Helvetica-Bold",
"fontSize": 6, "alignment": 0, "textColor": "black",
"backColor": "white"}
},
"uuid": {
"rectangulo": {"x": 15.6, "y": 22.7, "width": 6.5, "height": 0.4,
"radius": 0.0, "stroke": false, "fill": false},
"estilo": {"name": "nombre", "fontName": "Helvetica-Bold",
"fontSize": 6, "alignment": 0, "textColor": "red",
"backColor": "white"}
},
"t_fecha": {
"valor": "Fecha Expedición:",
"rectangulo": {"x": 14.2, "y": 22.1, "width": 2.2, "height": 0.3,
"radius": 0.0, "stroke": false, "fill": false},
"estilo": {"name": "nombre", "fontName": "Helvetica-Bold",
"fontSize": 6, "alignment": 2, "textColor": "black",
"backColor": "white"}
},
"fecha": {
"rectangulo": {"x": 16.5, "y": 22.1, "width": 3.0, "height": 0.3,
"radius": 0.0, "stroke": false, "fill": false},
"estilo": {"name": "nombre", "fontName": "Helvetica-Bold",
"fontSize": 6, "alignment": 0, "textColor": "black",
"backColor": "white"}
},
"t_fecha_timbrado": {
"valor": "Fecha Timbrado:",
"rectangulo": {"x": 14.2, "y": 21.8, "width": 2.2, "height": 0.3,
"radius": 0.0, "stroke": false, "fill": false},
"estilo": {"name": "nombre", "fontName": "Helvetica-Bold",
"fontSize": 6, "alignment": 2, "textColor": "black",
"backColor": "white"}
},
"fechatimbrado": {
"rectangulo": {"x": 16.5, "y": 21.8, "width": 3.0, "height": 0.3,
"radius": 0.0, "stroke": false, "fill": false},
"estilo": {"name": "nombre", "fontName": "Helvetica-Bold",
"fontSize": 6, "alignment": 0, "textColor": "black",
"backColor": "white"}
},
"t_serie_emisor": {
"valor": "Serie CSD Emisor:",
"rectangulo": {"x": 14.2, "y": 21.4, "width": 2.2, "height": 0.3,
"radius": 0.0, "stroke": false, "fill": false},
"estilo": {"name": "nombre", "fontName": "Helvetica-Bold",
"fontSize": 6, "alignment": 2, "textColor": "black",
"backColor": "white"}
},
"nocertificado": {
"rectangulo": {"x": 16.5, "y": 21.4, "width": 3.0, "height": 0.3,
"radius": 0.0, "stroke": false, "fill": false},
"estilo": {"name": "nombre", "fontName": "Helvetica-Bold",
"fontSize": 6, "alignment": 0, "textColor": "black",
"backColor": "white"}
},
"t_serie_sat": {
"valor": "Serie CSD SAT:",
"rectangulo": {"x": 14.2, "y": 21.1, "width": 2.2, "height": 0.3,
"radius": 0.0, "stroke": false, "fill": false},
"estilo": {"name": "nombre", "fontName": "Helvetica-Bold",
"fontSize": 6, "alignment": 2, "textColor": "black",
"backColor": "white"}
},
"nocertificadosat": {
"rectangulo": {"x": 16.5, "y": 21.1, "width": 3.0, "height": 0.3,
"radius": 0.0, "stroke": false, "fill": false},
"estilo": {"name": "nombre", "fontName": "Helvetica-Bold",
"fontSize": 6, "alignment": 0, "textColor": "black",
"backColor": "white"}
},
"lugarexpedicion": {
"rectangulo": {"x": 14.2, "y": 20.7, "width": 5.5, "height": 0.4,
"radius": 0.0, "stroke": false, "fill": false},
"estilo": {"name": "nombre", "fontName": "Helvetica-Bold",
"fontSize": 7, "alignment": 1, "textColor": "black",
"backColor": "white"}
}
}
},
"conceptos": {
},
"comprobante": {
"totalenletras": {
"estilo": {"name": "enletras", "fontName": "Helvetica-Bold",
"fontSize": 7, "alignment": 1, "textColor": "black",
"spaceBefore": 0.1}
},
"formadepago": {
"estilo": {"name": "formadepago", "fontName": "Helvetica",
"fontSize": 7, "alignment": 0, "textColor": "black"}
},
"metododepago": {
"estilo": {"name": "metododepago", "fontName": "Helvetica",
"fontSize": 7, "alignment": 0, "textColor": "black"}
},
"moneda": {
"estilo": {"name": "moneda", "fontName": "Helvetica",
"fontSize": 7, "alignment": 0, "textColor": "black"}
},
"tipocambio": {
"estilo": {"name": "tipocambio", "fontName": "Helvetica",
"fontSize": 7, "alignment": 0, "textColor": "black"}
},
"leyenda": {
"estilo": {"name": "leyenda", "fontName": "Helvetica-Bold",
"fontSize": 6, "alignment": 1, "textColor": "black",
"spaceBefore": 0.2}
}
}
}