El manejo que logra Odoo con la librería XlsxWriter es muy potente y poder generar planillas con la info de Odoo nos da una enorme gama de posibilidades para que nuestro sistema ofrezca importantes ventajas sobre los listados que vienen en el core de Odoo.
Como ya nombramos en el blog para armar un Excel con el stock o para personalizar una IVA Ventas-Compras que cada contador tiene su forma es un elemento distintivo de lo que pueda ofrecer otro partner
Este es un ejemplo de un Excel hecho con Odoo con formatos, fórmulas, autofiltros, inmovilizador de paneles, etc. Y se podrían agregar gráficos, botones, formularios, etc.
Entonces, vamos a ver el código para ver como hacer un Excel.
Hay que tener instalada la aplicación report_xlsx y luego tenemos que tener en un archivo XML el código para agregar un reporte estilo XLSX con el modelo que vamos a usar. Esto va a agregar en el formulario del modelo un opción de imprimir el Excel
<odoo>
<report
id="account_vat_ledger_xlsx"
model="account.vat.ledger"
string="Print to XLSX"
report_type="xlsx"
name="l10n_ar_account_vat_ledger.account_vat_ledger_xlsx"
file="account_vat_ledger"
attachment_use="False"
/>
</odoo>
En el name tenemos el nombre de la función que va a armar el archivo en el modelo que pusimos en model
La función sería algo como esto, en donde les pongo unas cuantas funciones de lo poderosa de la herramienta
class AccountVatLedgerXlsxColumn(models.AbstractModel):
_name = 'report.l10n_ar_account_vat_ledger.vat_column_xlsx'
_inherit = 'report.report_xlsx.abstract'
def generate_xlsx_report(self, workbook, data, vat_ledger):
if vat_ledger.invoice_ids:
report_name = 'IVA Compras'
sheet = workbook.add_worksheet(report_name[:31])
money_format = workbook.add_format({'num_format': '$#,##0.00'})
total_format = workbook.add_format({'num_format': '$#,##0.00', 'bold': True,'bg_color':'#E3E2E4','border': True})
titulo = workbook.add_format({'font_size': 20, 'bold': True,'bg_color':'#E3E2E4','align': 'center','border': True})
bold = workbook.add_format({'bold': True,'bg_color':'#E3E2E4','align': 'center','border': True})
#sheet.write(1, 0, vat_ledger.display_name, bold)
sheet.merge_range(1,0,1,3, vat_ledger.display_name, titulo)
titles = ['Fecha','Tipo Comprobante','Nro Comprobante','Razón Social','CUIT','Responsabilidad AFIP',
'Neto gravado 21%','Neto gravado 10.5%','Neto gravado 27%',
'IVA 21%','IVA 10.5%','IVA 27%',
'PERC.IVA','No Gravado','Fac.C',
'Perc.IIBB','Total','PIB CABA','PIB BS AS']
for i,title in enumerate(titles):
sheet.write(3, i, title, bold)
row = 4
index = 0
sheet.set_column('A:A', 10) #fecha
sheet.set_column('B:B', 16) #tipo
sheet.set_column('C:C', 19) #número
sheet.set_column('D:D', 30) #razon social
sheet.set_column('E:E', 11) #cuit
sheet.set_column('F:F', 25) #cuit
sheet.set_column('G:L', 18) #Números grandes
sheet.set_column('G:L', 18) #Números grandes
sheet.set_column('M:P', 14) #Números chicos
sheet.set_column('Q:Q', 18) #Números grandes
sheet.set_column('R:S', 14) #Números chicos
for i,obj in enumerate(vat_ledger.invoice_ids):
# One sheet by partner
#if obj.qty_available < 1:
# continue
sheet.write(row + index, 0, obj.invoice_date.strftime("%Y-%m-%d"))
sheet.write(row + index, 1, obj.l10n_latam_document_type_id.display_name)
sheet.write(row + index, 2, obj.display_name)
sheet.write(row + index, 3, obj.partner_id.display_name)
sheet.write(row + index, 4, obj.partner_id.vat)
sheet.write(row + index, 5, obj.partner_id.l10n_ar_afip_responsibility_type_id.name)
sheet.write(row + index,6, 0.00,money_format)
sheet.write(row + index,7, 0.00,money_format)
sheet.write(row + index,8, 0.00,money_format)
sheet.write(row + index,9, 0.00,money_format)
sheet.write(row + index,10, 0.00,money_format)
sheet.write(row + index,11, 0.00,money_format)
sheet.write(row + index,12, 0.00,money_format)
sheet.write(row + index,13, 0.00,money_format)
sheet.write(row + index,14, 0.00,money_format)
sheet.write(row + index,15, 0.00,money_format)
sheet.write(row + index,16, 0.00,money_format)
sheet.write(row + index,17, 0.00,money_format)
sheet.write(row + index,18, 0.00,money_format)
vat_taxable_amount = 0.00
vat_exempt_base_amount = 0.00
per_iva = 0.00
per_iibb = 0.00
per_ibcaba = 0.00
per_ibarba = 0.00
for move_tax in obj.move_tax_ids:
if move_tax.tax_id.tax_group_id.tax_type == 'vat':
if move_tax.tax_id.amount != 0:
vat_taxable_amount += move_tax.base_amount
else:
vat_exempt_base_amount += move_tax.base_amount
if move_tax.tax_id.tax_group_id.tax_type == 'withholdings':
if move_tax.tax_id.tax_group_id.l10n_ar_tribute_afip_code in ['01','06']:
per_iva += move_tax.tax_amount
if move_tax.tax_id.tax_group_id.l10n_ar_tribute_afip_code in ['07']:
per_iibb += move_tax.tax_amount
busqueda_CABA = move_tax.tax_id.tax_group_id.name.find('CABA')
if busqueda_CABA !=-1:
per_ibcaba += move_tax.tax_amount
busqueda_ARBA = move_tax.tax_id.tax_group_id.name.find('ARBA')
if busqueda_ARBA !=-1:
per_ibarba += move_tax.tax_amount
sheet.write(row + index,12, per_iva,money_format)
sheet.write(row + index,13, vat_exempt_base_amount,money_format)
sheet.write(row + index,15, per_iibb,money_format)
sheet.write(row + index,17, per_ibcaba,money_format)
sheet.write(row + index,18, per_ibarba,money_format)
#sheet.write(row + index, 6, vat_taxable_amount,money_format)
for tax_line in obj.move_tax_ids:
if tax_line.tax_id.amount == 21:
sheet.write(row + index, 6, tax_line.base_amount,money_format)
sheet.write(row + index, 9, tax_line.tax_amount,money_format)
if tax_line.tax_id.amount == 10.5:
sheet.write(row + index, 7, tax_line.base_amount,money_format)
sheet.write(row + index, 10, tax_line.tax_amount,money_format)
if tax_line.tax_id.amount == 27:
sheet.write(row + index, 8, tax_line.base_amount,money_format)
sheet.write(row + index, 11, tax_line.tax_amount,money_format)
sheet.write(row + index, 16, obj.amount_total,money_format)
if obj.partner_id.l10n_ar_afip_responsibility_type_id.name.find('Monotributo') !=-1:
sheet.write(row + index, 14, obj.amount_total,money_format)
index += 1
sheet.write(row + index, 5, 'Totales',bold)
sheet.autofilter(row-1, 0, row, 18)
sheet.freeze_panes(4, 0) # Freeze the first row.
col_G = '=sum(G'+str(row+1)+':G'+str(row+index)+')'
col_H = '=sum(H'+str(row+1)+':H'+str(row+index)+')'
col_I = '=sum(I'+str(row+1)+':I'+str(row+index)+')'
col_J = '=sum(J'+str(row+1)+':J'+str(row+index)+')'
col_K = '=sum(K'+str(row+1)+':K'+str(row+index)+')'
col_L = '=sum(L'+str(row+1)+':L'+str(row+index)+')'
col_M = '=sum(M'+str(row+1)+':M'+str(row+index)+')'
col_N = '=sum(N'+str(row+1)+':N'+str(row+index)+')'
col_O = '=sum(O'+str(row+1)+':O'+str(row+index)+')'
col_P = '=sum(P'+str(row+1)+':P'+str(row+index)+')'
col_Q = '=sum(Q'+str(row+1)+':Q'+str(row+index)+')'
col_R = '=sum(R'+str(row+1)+':R'+str(row+index)+')'
col_S = '=sum(S'+str(row+1)+':S'+str(row+index)+')'
sheet.write(row + index, 6, col_G, total_format)
sheet.write(row + index, 7, col_H, total_format)
sheet.write(row + index, 8, col_I, total_format)
sheet.write(row + index, 9, col_J, total_format)
sheet.write(row + index, 10, col_K, total_format)
sheet.write(row + index, 11, col_L, total_format)
sheet.write(row + index, 12, col_M, total_format)
sheet.write(row + index, 13, col_N, total_format)
sheet.write(row + index, 14, col_O, total_format)
sheet.write(row + index, 15, col_P, total_format)
sheet.write(row + index, 16, col_Q, total_format)
sheet.write(row + index, 17, col_R, total_format)
sheet.write(row + index, 18, col_S, total_format)
En el ejemplo generamos distintos formatos, texto, con negrita, con formato numérico, tamaños y luego cuando insertamos un dato en una celda lo hacemos con uno de los formatos deseados, seteamos anchos de columnas, combinación de celdas, insertamos fórmulas, autofiltro, etc. Y al terminar el código se descarga el Excel a nuestro equipo.