[ADD] Invoice no longer uses electronic_invoice_dian

This commit is contained in:
Jorge Enrique Gómez Gómez 2022-04-05 22:53:47 -05:00
parent f800728f89
commit afe03ae962
8 changed files with 1460 additions and 146 deletions

View File

@ -0,0 +1,109 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""Modifica el formato QWeb de facturas y devoluciones."""
import os
import sys
import base64
import odooly
def use_local_resources():
"""Facilita usar recursos en el mismo directorio del script."""
global __location__
__location__ = os.path.realpath(
os.path.join(os.getcwd(), os.path.dirname(__file__)))
def main():
odooly.Client._config_file = os.path.expanduser('~/.config/odooly.ini')
odoo = odooly.Client.from_config('Odoo14_Production')
#odoo = odooly.Client.from_config('odootest27')
"""Desactivar manualmente la vista:
* sale_stock.report_invoice_document_inherit_sale_stock
"""
views = odoo.env['ir.ui.view']
baseid = 'account.report_invoice_document'
viewname = 'report.invoice.factura_o_devolucion_agofer'
viewextid = 'agofer_view.factura_o_devolucion'
reports = odoo.env['ir.actions.report']
repextid = 'account.account_invoices'
papers = odoo.env['report.paperformat']
papextid = 'agofer_paper.factura_carta'
papextid_base = 'base.paperformat_us'
attachments = odoo.env['ir.attachment']
attextid_ff = 'agofer_adjunto.firma_factura'
attextid_iw = 'agofer_adjunto.icono_whatsapp'
vista_base = views.get(baseid)
assert vista_base.name == 'report_invoice_document'
reporte = open(os.path.join(__location__,
'factura_o_devolucion_v14.xml')).read()
formato_carta = papers.get(papextid_base)
destino_arch = """<?xml version="1.0"?>
<data name="{}" inherit_id="{}">
<xpath expr="//t[@t-name='account.report_invoice_document']" position="replace">
{}
</xpath>
</data>
""".format(viewname,baseid,reporte)
viewvalues = {
'active': True,
'inherit_id': vista_base.id,
'mode': 'extension',
'name': viewname,
'priority': 15,
'type': 'qweb',
}
repvalues = {
'name': 'Factura/Devolución',
'attachment': False,
'attachment_use': False,
'report_type': 'qweb-pdf',
}
papvalues = {
'name': 'Tamaño carta para factura',
'dpi': 90,
'format': 'Letter',
'header_line': False,
'header_spacing': 33,
'margin_bottom': 27,
'margin_left': 7,
'margin_right': 7,
'margin_top': 43,
'orientation': 'Portrait',
'page_height': 0,
'page_width': 0,
}
viewvalues['arch'] = destino_arch
destino_vista = views.get(viewextid)
if destino_vista:
destino_vista.write(viewvalues)
else:
destino_vista = views.create(viewvalues)
destino_vista._set_external_id(viewextid)
paper = papers.get(papextid)
if paper:
paper.write(papvalues)
else:
paper = papers.create(papvalues)
paper._set_external_id(papextid)
repvalues['paperformat_id'] = paper.id
# Asegurarse que el nombre de la Cedula de Ciudadania este abreviado:
# cc_extid = 'partner_extended_co.partner_co_document_type_CC'
# odoo.env['res.document.type'].get(cc_extid).name = 'CC'
reports.get(repextid).write(repvalues)
if __name__ == "__main__":
use_local_resources()
main()

291
agofer_payslip.xml Normal file
View File

@ -0,0 +1,291 @@
<t t-foreach="docs" t-as="o">
<t t-call="web.basic_layout">
<style type="text/css">
html * { font-size: 11px; }
.header * { font-size: 12px !important; }
</style>
<div class="page">
<div class="header">
<div class="row clearfix">
<div class="col-3 text-center">
<!-- img t-if="o.company_id.logo" t-att-src="'data:image/png;base64,%s' % o.company_id.logo" width="153" height="80"/ -->
<img src="/web/binary/company_logo" width="153" height="80"/>
<div>
<small><span t-field="o.company_id.name"/></small><br />
<small>NIT <span t-field="o.company_id.partner_id.ref_num"/></small>
</div>
</div>
<div class="col-7 float-right">
<h1 class="h4 mb-4">
<span t-if="o.state == 'draft'">Borrador de </span>
<span t-if="o.state != 'draft'">Comprobante de </span>
<span t-field="o.payslip_type_id.name"/>
<small t-if="o.name"> <span t-field="o.name"/></small>
</h1>
<div class="card mb-6">
<div class="card-body" style="padding:6px 15px;">
<h2 t-if="o.payslip_type_id.name != 'Liquidación'" class="h5 float-left">Período: <small><span t-field="o.period_id.name"/></small></h2>
<h2 t-if="o.payslip_type_id.name == 'Liquidación'" class="h5 float-left">Fecha de liquidación: <small><span t-field="o.liquidation_date"/></small></h2>
</div>
</div>
</div>
</div>
</div>
<div class="row mb-3">
<div class="col-12">
<div class="card">
<div class="card-header">
<h3 class="card-title">
<strong t-field="o.employee_id.name"/>
<small class="text-primary">
<span t-field="o.employee_id.partner_id.ref_type_id.name"/> <span t-field="o.employee_id.partner_id.ref_num"/>
</small>
</h3>
</div>
<div class="row">
<div class="col-5">
<div class="list-group">
<p class="list-group-item border-0 pb-0" t-field="o.employee_id.job_id"/>
<p t-if="o.employee_id.work_email" class="list-group-item border-0 pt-0 pb-0">
<span t-field="o.employee_id.work_email"/>
</p>
<t t-if="o.employee_id.bank_account_id">
<p class="list-group-item border-0 pt-0">
<strong t-field="o.employee_id.bank_account_id.bank_name"/>
<t t-if="o.employee_id.bank_account_id.acc_type == 'saving'">Ah.</t>
<t t-if="o.employee_id.bank_account_id.acc_type == 'current'">Cte.</t>
<span t-field="o.employee_id.bank_account_id.acc_number"/>
</p>
</t>
</div>
</div>
<div class="col-5">
<div class="list-group">
<h4 class="h5 list-group-item border-0 pb-0">
<strong>Contrato</strong> <span t-field="o.contract_id.name"/>
</h4>
<p class="list-group-item border-0 pt-0 pb-0">
<span t-field="o.contract_id.structure_type_id.name"/>
</p>
<p class="list-group-item border-0 pt-0">
<strong>Salario: </strong>
<span t-field="o.contract_id.wage" t-field-options="{&quot;widget&quot;: &quot;monetary&quot;, &quot;display_currency&quot;: &quot;o.company_id.currency_id&quot;}"/>
</p>
</div>
</div>
<div class="col-2 float-right text-right">
<img t-if="o.employee_id.image_128" t-att-src="'data:image/png;base64,%s' % o.employee_id.image_128.decode('utf-8')" class="thumbnail m-1" height="100" style="margin-bottom:0;"/>
</div>
</div>
</div>
</div>
</div>
<div class="row">
<div class="col-6">
<t t-if="o.earnings_ids">
<div class="card mb-3" id="devengos">
<div class="card-header font-weight-bold">
Devengos
</div>
<ul class="list-group list-group-flush">
<t t-set="total_devs" t-value="0" />
<t t-foreach="o.earnings_ids" t-as="earnings">
<t t-set="total_devs" t-value="total_devs + earnings.total"/>
<li class="list-group-item m-0 pt-1 pb-1">
<div class="row">
<div class="col-8">
<span t-field="earnings.name"/>
<small>
<t t-if="earnings.overtime_id">
[<span t-field="earnings.overtime_id.qty"/> horas]
</t>
<t t-elif="earnings.qty != 1.0 or earnings.leave_id">
[<span t-field="earnings.qty"/> días]
</t>
</small>
</div>
<div class="col-4 float-right text-right" t-field="earnings.total" t-options="{'widget': 'float', 'precision': 0}"/>
</div>
</li>
</t>
<li class="list-group-item border-top border-dark m-0 pt-1 pb-1">
<div class="row">
<div class="col-8"><strong>Total</strong></div>
<div class="col-4 float-right text-right">
<strong t-esc="total_devs" t-options="{'widget': 'float', 'precision': 0}"/>
</div>
</div>
</li>
</ul>
</div>
</t>
<div class="card" id="entidades">
<div class="card-header font-weight-bold">
Seguridad Social y Parafiscales
</div>
<ul class="list-group">
<li class="list-group-item border-0 pb-1" t-if="o.contract_id.afp_pension_id.id == o.contract_id.afp_severance_id.id">
<strong>Fondo de pensiones y cesantías:</strong>
<span t-field="o.contract_id.afp_pension_id.name"/>
</li>
<li class="list-group-item border-0 pt-1 pb-1" t-if="o.contract_id.afp_pension_id.id != o.contract_id.afp_severance_id.id">
<strong>Fondo de pensiones:</strong>
<span t-field="o.contract_id.afp_pension_id.name"/>
</li>
<li class="list-group-item border-0 pt-1 pb-1" t-if="o.contract_id.afp_pension_id.id != o.contract_id.afp_severance_id.id">
<strong>Fondo de cesantías:</strong>
<span t-field="o.contract_id.afp_severance_id.name"/>
</li>
<li class="list-group-item border-0 pt-1 pb-1">
<strong>Entidad promotora de salud:</strong>
<span t-field="o.contract_id.eps_id.name"/>
</li>
<li class="list-group-item border-0 pt-1 pb-1">
<strong>Caja de compensación:</strong>
<span t-field="o.contract_id.ccf_id.name"/>
</li>
<li class="list-group-item border-0 pt-1">
<strong>Administradora de riesgos laborales:</strong>
<span t-field="o.contract_id.arl_id.name"/>
</li>
</ul>
</div>
</div>
<div class="col-6">
<t t-if="o.deductions_ids">
<div class="card mb-3" id="deducciones">
<div class="card-header font-weight-bold">
Deducciones
</div>
<ul class="list-group list-group-flush">
<t t-set="total_ded" t-value="0" />
<t t-foreach="o.deductions_ids" t-as="deduction">
<t t-set="total_ded" t-value="total_ded + deduction.total"/>
<li class="list-group-item m-0 pt-1 pb-1">
<div class="row">
<div class="col-8" t-field="deduction.name"/>
<div class="col-4 float-right text-right" t-field="deduction.total" t-options="{'widget': 'float', 'precision': 0}"/>
</div>
</li>
</t>
<li class="list-group-item border-top border-dark m-0 pt-1 pb-1">
<div class="row">
<div class="col-8"><strong>Total</strong></div>
<div class="col-4 float-right text-right">
<strong t-esc="total_ded" t-options="{'widget': 'float', 'precision': 0}"/>
</div>
</div>
</li>
</ul>
</div>
</t>
<div class="card border-dark" id="neto">
<div class="card-header font-weight-bold border-top-0 border-left-0 border-right-0">
<div class="row">
<div class="col-8">
<strong>Neto a pagar</strong>
</div>
<div class="col-4 float-right text-right">
<span t-field="o.amount_total" t-options="{'widget': 'monetary', 'display_currency': o.company_id.currency_id}"/>
</div>
</div>
</div>
<div class="card-body border-top-0 border-left-0 border-right-0">
<p>
<t t-set="amount_words" t-value="o.company_id.currency_id.amount_to_text(o.amount_total) + 's'"/>
<!-- span t-field="o.amount_total_words"/> PESOS -->
<span t-esc="amount_words" />
</p>
</div>
</div>
</div>
</div>
<div class="row" t-if="o.payslip_type_id.name == 'Liquidación'">
<div class="col-4">
<div class="card">
<div class="card-body" style="min-height:2.3cm; max-height:2.3cm; padding-top:0.8cm;">
<small t-field="o.write_uid"/><br/>
<small t-field="o.write_date"/>
</div>
<div class="card-footer" style="padding:1pt 8pt;">
<small style="font-size:8pt; font-weight:normal; line-height:8pt;">
Elaborado por<br/>
</small>
</div>
</div>
</div>
<div class="col-4">
<div class="card">
<div class="card-body" style="min-height:2.3cm; max-height:2.3cm; padding-top:0.6cm; overflow:hidden;">
</div>
<div class="card-footer" style="padding:1pt 8pt;">
<small style="font-size:8pt; font-weight:normal; line-height:8pt;">
Firma autorizada Agofer
</small>
</div>
</div>
</div>
<div class="col-4">
<div class="card">
<div class="card-body" style="min-height:2.3cm; max-height:2.3cm; padding-top:1.6cm; overflow:hidden;">
<small style="font-size:8pt; font-weight:normal; line-height:9pt;">
<span t-field="o.employee_id.name"/>,
<span t-field="o.employee_id.partner_id.ref_type_id.name"/>
<span t-field="o.employee_id.partner_id.ref_num"/>
</small>
</div>
<div class="card-footer" style="padding:1pt 8pt;">
<small style="font-size:8pt; font-weight:normal; line-height:8pt;">
Recibí conforme
</small>
</div>
</div>
</div>
</div>
<div class="row" t-if="o.payslip_type_id.name == 'Vacaciones'">
<div class="col-4">
<div class="card">
<div class="card-body" style="min-height:2.3cm; max-height:2.3cm; padding-top:0.8cm;">
<small t-field="o.write_uid"/><br/>
<small t-field="o.write_date"/>
</div>
<div class="card-footer" style="padding:1pt 8pt;">
<small style="font-size:8pt; font-weight:normal; line-height:8pt;">
Elaborado por<br/>
</small>
</div>
</div>
</div>
<div class="col-4">
<div class="card">
<div class="card-body" style="min-height:2.3cm; max-height:2.3cm; padding-top:0.6cm; overflow:hidden;">
</div>
<div class="card-footer" style="padding:1pt 8pt;">
<small style="font-size:8pt; font-weight:normal; line-height:8pt;">
Firma autorizada Agofer
</small>
</div>
</div>
</div>
<div class="col-4">
<div class="card">
<div class="card-body" style="min-height:2.3cm; max-height:2.3cm; padding-top:1.6cm; overflow:hidden;">
<small style="font-size:8pt; font-weight:normal; line-height:9pt;">
<span t-field="o.employee_id.name"/>,
<span t-field="o.employee_id.partner_id.ref_type_id.name"/>
<span t-field="o.employee_id.partner_id.ref_num"/>
</small>
</div>
<div class="card-footer" style="padding:1pt 8pt;">
<small style="font-size:8pt; font-weight:normal; line-height:8pt;">
Recibí conforme
</small>
</div>
</div>
</div>
</div>
</div>
</t>
</t>

View File

@ -7,9 +7,9 @@
<span t-if="o.move_type == 'out_invoice' and o.state == 'draft'">Factura borrador</span>
<span t-if="o.move_type == 'out_invoice' and o.state == 'cancel'">Factura anulada</span>
<span t-if="o.move_type == 'out_refund' and o.state == 'posted'">Devolución</span>
<span t-if="o.move_type == 'out_refund' and o.state == 'draft'">Devolución borrador</span>
<span t-if="o.move_type == 'out_refund' and o.state == 'cancel'">Devolución anulada</span>
<span t-if="o.move_type == 'out_refund' and o.state == 'posted'">Nota crédito de una factura electrónica de venta</span>
<span t-if="o.move_type == 'out_refund' and o.state == 'draft'">Nota crédito borrador</span>
<span t-if="o.move_type == 'out_refund' and o.state == 'cancel'">Nota crédito anulada de una factura electrónica de venta</span>
<span t-if="o.move_type == 'in_refund'">Devolución de proveedor</span>
<span t-if="o.move_type == 'in_invoice'">
@ -18,42 +18,54 @@
</span>
<span t-if="o.name != '/'" t-field="o.name"/>
</t>
<t t-set="address">
<address t-field="o.partner_id" />
</t>
<!-- div t-call="stock_extended.style_table" / -->
<div>
<style type="text/css">
html * { font-size: 10px; }
.header * { font-size: 12px !important; }
</style>
</div>
<div class="header">
<div class="row">
<div t-attf-class="{{ is_einvoice and 'col-8 col-sm-auto' or 'col-9 col-sm-auto' }}">
<div class="card card-info">
<div class="card-body">
<h4 class="card-title text-dark">
<div class="card mb-1">
<div class="card-body pb-0">
<h1 class="h5 card-title text-dark" style="font-size:12px;">
<strong t-raw="document_title"/>
<!-- Descomentar cuando cierren
https://github.com/OCA/reporting-engine/pull/476 -->
https://github.com/OCA/reporting-engine/pull/476
(merged en 2021-07-29) -->
<!-- small class="not-first-page"> (…continúa)</small -->
</h4>
<div class="row">
<div class="col-5 col-sm-12">
<p>
</h1>
<div class="row no-gutters">
<div class="col-5 col-sm-6">
<p class="mb-1" style="font-size:11px;">
<strong>Fecha:</strong>
<span t-field="o.invoice_date" />
<small t-esc="o.create_date.strftime('%H:%M:%S')" />
<small t-esc="context_timestamp(o.create_date).strftime('%H:%M:%S')"/>
</p>
<p t-if="o.move_type == 'out_invoice' and o.state != 'cancel'">
<strong>Fecha de vencimiento:</strong>
<p t-if="o.move_type == 'out_invoice' and o.state != 'cancel'" class="mb-1" style="font-size:11px;">
<strong>Vencimiento:</strong>
<span t-field="o.invoice_date_due" />
</p>
</div>
<div class="col-7 col-sm-12">
<p t-if="o.move_type in ['out_invoice','in_invoice'] and o.invoice_payment_term_id.note">
<strong>Condición de pago:</strong>
<span t-field="o.invoice_payment_term_id.note" style="font-weight:normal;" />
<div class="col-7 col-sm-6">
<p t-if="o.invoice_payment_term_id" name="payment_term" class="mb-1" style="font-size:11px;">
<span t-if="o.move_type in ['out_invoice','in_invoice']">
<strong>Condición de pago:</strong>
<span t-field="o.invoice_payment_term_id.note"/>
</span>
</p>
<p>
<t t-if="o.invoice_incoterm_id">
<p class="mb-1" style="font-size:11px;">
<t t-if="o.invoice_incoterm_id" name="incoterm">
<strong>Términos de negociación: </strong>
<code t-esc="o.invoice_incoterm_id.name" />
<code t-esc="o.invoice_incoterm_id.code" />
:
<t t-esc="o.invoice_incoterm_id.description" />
<t t-esc="o.invoice_incoterm_id.name" />
</t>
</p>
</div>
</div>
@ -61,10 +73,13 @@
</div>
</div>
<div t-if="is_einvoice" class="col-2 col-sm-auto">
<!-- img t-att-src="'/report/barcode/?move_type=QR&amp;value=%s&amp;width=%s&amp;height=%s' % (is_old_einvoice and o.ei_qr_text or o.ei_qr.replace('&amp;', '%26'), 153, 153)" / -->
<img t-att-src="'/report/barcode/?type=QR&amp;value=%s&amp;width=%s&amp;height=%s' % (o.company_id.website, 153, 153)" t-if="o.ei_qr" />
<t t-foreach="o.dian_document_ids" t-as="dd">
<t t-if="dd.qr_image and dd.state != 'cancel'">
<img t-att-src="image_data_uri(dd.qr_image)" style="width:120px;height:120px"/>
</t>
</t>
</div>
<div class="col-2 col-sm-4">
<div class="col-2 col-sm-3 ml-sm-auto">
<img t-if="o.company_id.logo" t-att-src="'data:image/png;base64,%s' % to_text(o.company_id.logo)" width="153" height="80" class="img-fluid w-100" />
</div>
</div>
@ -78,51 +93,52 @@
<!-- / Data for PDF Outline only -->
<div class="row">
<div class="col-9">
<div class="card card-info">
<div class="card-header">
<h3 class="card-title text-dark">
<strong t-field="o.partner_id.name" />
<div class="card border-info">
<div class="card-header alert-info py-0 px-3">
<h2 class="h3 card-title mb-0 text-dark">
<strong t-field="o.partner_id.name" style="font-size:14px;"/>
&#160;
<span class="text-nowrap">
<span class="text-nowrap" style="font-size:12px;">
<!-- Reemplazar por abbr cuando se cree el campo -->
<span t-field="o.partner_id.ref_type_id.code" />
<span t-field="o.partner_id.ref_type_id.name" />
<span t-field="o.partner_id.ref_num" />
<span t-if="o.partner_id.ref_type_id.code == 'NI'">
<span t-field="o.partner_id.verification_code" />
</span>
</span>
</h3>
</h2>
</div>
<div class="card-body">
<div class="row">
<div t-attf-class="{{ o.partner_shipping_id and (o.partner_shipping_id != o.partner_id) and 'col-xs-6' or 'col-xs-12' }}">
<div class="mb0">
<div class="h5 mb-1" t-if="not o.partner_shipping_id or o.partner_shipping_id == o.partner_id">Dirección:</div>
<div class="h5 mb-1" t-if="o.partner_shipping_id and o.partner_shipping_id != o.partner_id">Dirección de facturación:</div>
<address/>
<div class="list-group">
<p class="list-group-item" t-field="o.partner_id.street" itemprop="name" />
<div class="card-body py-1 px-3">
<div class="row m-0">
<div t-attf-class="{{ o.partner_shipping_id and (o.partner_shipping_id != o.partner_id) and 'col-6' or 'col-12' }}">
<div class="mb-0">
<div class="h5 mb-1" style="font-size:11px;" t-if="not o.partner_shipping_id or o.partner_shipping_id == o.partner_id">Dirección:</div>
<div class="h5 mb-1" style="font-size:11px;" t-if="o.partner_shipping_id and o.partner_shipping_id != o.partner_id">Dirección de facturación:</div>
<address class="mb-1">
<span t-field="o.partner_id.street" itemprop="name" />
<t t-if="o.partner_id.street2">
<p class="list-group-item" t-field="o.partner_id.street2" />
<br/>
<span t-field="o.partner_id.street2" />
</t>
<p class="list-group-item">
<span t-field="o.partner_id.city_id.name" />,
<span t-field="o.partner_id.state_id.name" />
</p>
<p class="list-group-item" t-if="o.partner_id.phone" itemprop="telephone">
<br/>
<span t-field="o.partner_id.city_id.name" />,
<span t-field="o.partner_id.state_id.name" />
<span t-if="o.partner_id.phone" itemprop="telephone">
<br/>
<i class="fa fa-phone" />
<span t-field="o.partner_id.phone" />
</p>
<p class="list-group-item" t-if="o.partner_id.email" itemprop="email">
</span>
<span t-if="o.partner_id.email" itemprop="email">
<br/>
<i class="fa fa-envelope-o" />
<small t-esc="o.partner_id.email.split(';')[0]" />
</p>
</div>
</span>
</address>
</div>
</div>
<div t-if="o.partner_shipping_id and o.partner_shipping_id != o.partner_id" class="col-xs-6">
<div class="list-group mb0">
<div t-if="o.partner_shipping_id and o.partner_shipping_id != o.partner_id" class="col-6">
<div class="list-group mb-0">
<h5 t-if="o.move_type not in ['out_refund','in_invoice']">
Dirección de envío:
</h5>
@ -151,89 +167,150 @@
</div>
</div>
</div>
<div class="col-3 card border-0">
<p style="font-size:9t; line-height:10pt;">
Agofer S.A.S. NIT 800.216.4991 :
</p>
<ul class="fa-ul" style="font-size:8pt; line-height:9pt; margin-left:1.2em;">
<li>
<i class="fa-li fa fa-caret-right" />
Autorretenedor Res. №0010 1994-02-11
</li>
<li>
<i class="fa-li fa fa-caret-right" />
Gran contribuyente Res.DIAN №9061 2020-12-10
</li>
<li>
<i class="fa-li fa fa-caret-right" />
Régimen Común y Agente Retenedor de IVA
</li>
<li>
<i class="fa-li fa fa-caret-right" />
Actividad Económica CIIU 4752
</li>
<t t-if="o.journal_id.resolution_id.number">
<t t-foreach="o.journal_id.resolution_id.description.split('|')" t-as="res">
<div class="col-3">
<div class="card border-0">
<p class="mb-0" style="font-size:8pt; line-height:10pt;">
Agofer S.A.S. NIT 800.216.4991:
</p>
<ul class="fa-ul mb-0" style="font-size:8pt; line-height:9pt; margin-left:1.2em;">
<li>
<i class="fa-li fa fa-caret-right" />
Autorretenedor Res. №0010 1994-02-11
</li>
<li>
<i class="fa-li fa fa-caret-right" />
Gran contribuyente Res.DIAN №9061 2020-12-10
</li>
<li>
<i class="fa-li fa fa-caret-right" />
Régimen Común y Agente Retenedor de IVA
</li>
<li>
<i class="fa-li fa fa-caret-right" />
Actividad Económica CIIU 4752
</li>
<t t-set="res" />
<t t-foreach="o.journal_id.sequence_id.date_range_ids" t-as="dr">
<t t-if="dr.active_resolution">
<t t-set="res" t-value="dr" />
</t>
</t>
<t t-if="res">
<li>
<i class="fa-li fa fa-caret-right" />
<t t-esc="res" />
<t t-esc="'Autorización DIAN {} {} a {} {}{} a {}{}'.format(res.resolution_number,res.date_from,res.date_to_resolution,res.prefix,res.number_from,res.prefix,res.number_to)" />
</li>
<t t-if="res.sequence_id.description">
<t t-foreach="res.sequence_id.description.split('|')" t-as="additional">
<li>
<i class="fa-li fa fa-caret-right" />
<t t-esc="additional" />
</li>
</t>
</t>
</t>
</t>
</ul>
<i class="fa fa-whatsapp" /><small><strong>WhatsApp 310 674 4444</strong></small>
</ul>
<span><i class="fa fa-whatsapp ml-n1 mr-1"/><small class="font-weight-bold">WhatsApp 310 674 4444</small></span>
</div>
</div>
</div>
<div id="informations" class="row mt32 mb32">
<div class="col-auto col-3 mw-100 mb-2">
<!-- ######################################################### -->
<div class="clearfix row mt4 mb8" t-if="o.move_type in ['out_invoice','out_refund']">
<div class="col-3">
<strong>Source:</strong>
<p t-if="o.move_type == 'out_invoice'">
<!-- t t-if="o.picking_id.origin">
<span t-field="o.picking_id.origin"/>,
</t>
<br / -->
<t t-if="o.invoice_origin">
<span t-field="o.invoice_origin" />
<t t-if="o.picking_id and o.picking_id.sale_id and o.picking_id.sale_id.date_order">
<small t-field="o.picking_id.sale_id.date_order" t-field-options="{&quot;format&quot;:&quot;YYYY-MM-dd&quot;}" />
</t>
</t>
</p>
<t t-if="o.move_type == 'out_refund'">
<p t-field="o.invoice_origin" />
<p t-if="o.out_refund_id">
<span t-esc="o.out_refund_id.name"/>
</p>
<p t-if="o.name">
<strong>Description:</strong>
<br/>
<span t-field="o.name" />
</p>
</t>
</div>
<div t-if="o.move_type == 'out_invoice'" class="col-3">
<strong>Orden de compra:</strong>
<p t-if="o.picking_id.sale_id and o.picking_id.sale_id.client_order_ref">
<div t-field="o.picking_id.sale_id.client_order_ref" />
<div t-if="o.ref" name="reference">
<strong>Ref.:</strong>
<span t-field="o.ref"/>
</div>
</p>
</div>
<div class="col-3">
<t t-set="asesor" t-value="o.user_id and o.user_id or o.partner_id.user_id" />
<strong>Asesor comercial:</strong>
<p>
<span t-field="asesor.first_name" />
<t t-if="asesor.second_name">
<span t-esc="asesor.second_name[:1]" />.
</t>
<span t-field="asesor.first_surname" />
<br />
<small t-field="asesor.email" />
<br />
</p>
</div>
<div class="col-3">
<strong>Peso teórico total:</strong>
<p>
<t t-raw="weight" />
kg
</p>
</div>
<div class="col-auto col-3 mw-100 mb-2" t-if="o.invoice_origin" name="origin">
<strong>Source:</strong>
<p class="m-0" t-field="o.invoice_origin"/>
</div>
<div class="col-auto col-3 mw-100 mb-2" t-if="o.partner_id.ref" name="customer_code">
<strong>Customer Code:</strong>
<p class="m-0" t-field="o.partner_id.ref"/>
</div>
<div class="col-auto col-3 mw-100 mb-2" t-if="o.ref" name="reference">
<strong>Reference:</strong>
<p class="m-0" t-field="o.ref"/>
</div>
</div>
<!-- ######################################################### -->
<t t-set="display_discount" t-value="any(l.discount for l in o.invoice_line_ids)"/>
<table class="table table-sm o_main_table" name="invoice_line_table">
<thead>
<tr>
<th></th>
<th name="th_description" class="text-left"><span>Description</span></th>
<th name="th_quantity" class="text-center" colspan="2"><span>Quantity</span></th>
<th name="th_priceunit" t-attf-class="text-right {{ 'd-none d-md-table-cell' if report_type == 'html' else '' }}"><span>Unit Price</span></th>
<th name="th_price_unit" t-if="display_discount" t-attf-class="text-right {{ 'd-none d-md-table-cell' if report_type == 'html' else '' }}">
<th style="border-top: none; border-bottom: 1px solid black !important;" scope="col"></th>
<th style="border-top: none; border-bottom: 1px solid black !important;" scope="col" name="th_description" class="text-left"><span>Description</span></th>
<th style="border-top: none; border-bottom: 1px solid black !important;" scope="col" name="th_quantity" class="text-center" colspan="2"><span>Quantity</span></th>
<th style="border-top: none; border-bottom: 1px solid black !important;" scope="col" name="th_priceunit" t-attf-class="text-right {{ 'd-none d-md-table-cell' if report_type == 'html' else '' }}"><span>Unit Price</span></th>
<th style="border-top: none; border-bottom: 1px solid black !important;" scope="col" name="th_price_unit" t-if="display_discount" t-attf-class="text-right {{ 'd-none d-md-table-cell' if report_type == 'html' else '' }}">
<span>Disc.%</span>
</th>
<th name="th_taxes" t-attf-class="text-left {{ 'd-none d-md-table-cell' if report_type == 'html' else '' }}"><span>Taxes</span></th>
<th name="th_subtotal" class="text-right">
<th style="border-top: none; border-bottom: 1px solid black !important;" scope="col" name="th_subtotal" class="text-right">
<span groups="account.group_show_line_subtotals_tax_excluded">Amount</span>
<span groups="account.group_show_line_subtotals_tax_included">Total Price</span>
</th>
<th style="border-top: none; border-bottom: 1px solid black !important;" scope="col" name="th_taxes" t-attf-class="text-left {{ 'd-none d-md-table-cell' if report_type == 'html' else '' }}"><span>IVA</span></th>
</tr>
</thead>
<tbody class="invoice_tbody">
<t t-set="barras" />
<t t-set="current_subtotal" t-value="0"/>
<t t-set="lines" t-value="o.invoice_line_ids.sorted(key=lambda l: (-l.sequence, l.date, l.move_name, -l.id), reverse=True)"/>
<t t-foreach="lines" t-as="line">
<t t-set="current_subtotal" t-value="current_subtotal + line.price_subtotal" groups="account.group_show_line_subtotals_tax_excluded"/>
<t t-set="current_subtotal" t-value="current_subtotal + line.price_total" groups="account.group_show_line_subtotals_tax_included"/>
<t t-set="iva" />
<t t-foreach="line.tax_ids" t-as="tax">
<t t-if="tax.description[:3] == 'IVA'">
<t t-set="iva" t-value="tax.name.split(' ')[-1]" />
</t>
</t>
<tr t-att-class="'bg-200 font-weight-bold o_line_section' if line.display_type == 'line_section' else 'font-italic o_line_note' if line.display_type == 'line_note' else ''">
<t t-if="not line.display_type" name="account_invoice_line_accountable">
@ -242,7 +319,13 @@
<small t-esc="line_index + 1" />
</tt>
</td>
<td name="account_invoice_line_name"><span t-field="line.name" t-options="{'widget': 'text'}"/></td>
<td name="account_invoice_line_name">
<span t-field="line.name" t-options="{'widget': 'text'}"/>
<t t-if="line.product_id and line.product_id.categ_id and line.product_id.categ_id.id == 9">
<i class="fa fa-tag"></i>
<t t-set="barras" t-value="True" />
</t>
</td>
<td class="text-right">
<span t-field="line.quantity"/>
</td>
@ -250,17 +333,20 @@
<span t-field="line.product_uom_id" />
</td>
<td t-attf-class="text-right {{ 'd-none d-md-table-cell' if report_type == 'html' else '' }}">
<span class="text-nowrap" t-field="line.price_unit"/>
<span class="text-nowrap" t-esc="'{0:,.0f}'.format(line.price_unit)"/>
</td>
<td t-if="display_discount" t-attf-class="text-right {{ 'd-none d-md-table-cell' if report_type == 'html' else '' }}">
<span class="text-nowrap" t-field="line.discount"/>
</td>
<td t-attf-class="text-left {{ 'd-none d-md-table-cell' if report_type == 'html' else '' }}">
<span t-esc="', '.join(map(lambda x: (x.description or x.name), line.tax_ids))" id="line_tax_ids"/>
</td>
<td class="text-right o_price_total">
<span class="text-nowrap" t-field="line.price_subtotal" groups="account.group_show_line_subtotals_tax_excluded"/>
<span class="text-nowrap" t-field="line.price_total" groups="account.group_show_line_subtotals_tax_included"/>
<span class="text-nowrap" t-esc="'{0:,.0f}'.format(line.price_subtotal)" groups="account.group_show_line_subtotals_tax_excluded"/>
<span class="text-nowrap" t-esc="'{0:,.0f}'.format(line.price_total)" groups="account.group_show_line_subtotals_tax_included"/>
</td>
<td t-attf-class="text-left {{ 'd-none d-md-table-cell' if report_type == 'html' else '' }}">
<!-- span t-esc="', '.join(map(lambda x: (x.description or x.name), line.tax_ids))" id="line_tax_ids"/ -->
<small>
<t t-esc="iva" />
</small>
</td>
</t>
<t t-if="line.display_type == 'line_section'">
@ -298,18 +384,48 @@
</tr>
</tfoot>
</table>
<div class="clearfix">
<!-- ######################################################### -->
<div class="clearfix" style="page-break-inside:avoid;">
<div id="total" class="row">
<div t-attf-class="#{'col-6' if report_type != 'html' else 'col-sm-7 col-md-6'} ml-auto">
<table class="table table-sm" style="page-break-inside: avoid;">
<div t-attf-class="#{'col-8' if report_type != 'html' else 'col-sm-5 col-md-6'}">
<div>
<p t-if="o.narration and o.narration != 'false'" name="comment">
<strong>Observaciones:</strong>
<br />
<span t-field="o.narration"/>
<!-- span t-esc="'\n'.join([line for line in o.narration.split('\n') if line.strip() != ''])" / -->
</p>
<p t-if="o.fiscal_position_id.note" name="note">
<!-- strong>Fiscal Position Remark:</strong -->
<span t-field="o.fiscal_position_id.note" />
</p>
</div>
<div t-if="o.move_type == 'out_invoice' and barras" class="card">
<div class="card-header p-1">
<h4 class="card-title">
Barras corrugadas para refuerzo de concreto
</h4>
</div>
<div class="card-body p-1">
<ul class="fa-ul mb-0">
<li>
<i class="fa-li fa fa-tag"></i>
Revise y conserve las etiquetas;
lo exige la Res.1856 de 2017
</li>
</ul>
</div>
</div>
</div>
<div t-attf-class="#{'col-4' if report_type != 'html' else 'col-sm-7 col-md-6'}">
<table class="table table-sm">
<tr class="border-black o_subtotal" style="">
<td><strong>Subtotal</strong></td>
<td class="text-right">
<span t-field="o.amount_untaxed"/>
<span t-esc="'{0:,.2f}'.format(o.amount_untaxed)"/>
</td>
</tr>
<t t-foreach="o.amount_by_group" t-as="amount_by_group">
<!-- t t-foreach="o.amount_by_group" t-as="amount_by_group">
<tr style="">
<t t-if="len(o.line_ids.filtered(lambda line: line.tax_line_id)) in [0, 1] and o.amount_untaxed == amount_by_group[2]">
<td><span class="text-nowrap" t-esc="amount_by_group[0]"/></td>
@ -329,11 +445,17 @@
</td>
</t>
</tr>
</t>
</t -->
<tr>
<td>IVA</td>
<td class="text-right">
<span t-esc="'{0:,.2f}'.format(o.amount_tax)" />
</td>
</tr>
<tr class="border-black o_total">
<td><strong>Total</strong></td>
<td class="text-right">
<span class="text-nowrap" t-field="o.amount_total"/>
<span t-esc="'{0:,.2f}'.format(o.amount_total)" />
</td>
</tr>
<t t-if="print_with_payments">
@ -345,7 +467,7 @@
<i class="oe_form_field text-right oe_payment_label">Paid on <t t-esc="payment_vals['date']" t-options="{&quot;widget&quot;: &quot;date&quot;}"/></i>
</td>
<td class="text-right">
<span t-esc="payment_vals['amount']" t-options="{&quot;widget&quot;: &quot;monetary&quot;, &quot;display_currency&quot;: o.currency_id}"/>
<span t-esc="'{0:,.2f}'.format(payment_vals['amount'])"/>
</td>
</tr>
</t>
@ -353,7 +475,7 @@
<tr class="border-black">
<td><strong>Amount Due</strong></td>
<td class="text-right">
<span t-field="o.amount_residual"/>
<span t-esc="'{0:,.2f}'.format(o.amount_residual)"/>
</td>
</tr>
</t>
@ -363,18 +485,52 @@
</div>
</div>
</div>
<!-- ######################################################### -->
<div class="row mb-1">
<div t-if="is_einvoice" class="col-5">
<!-- TODO Remove duplicate CUDE in invoices -->
<div class="card border border-secondary bg-light p-1">
<pre class="text-uppercase mb-0" style="font-size:8px; line-height:8px; overflow:hidden;"><strong><t t-esc="o.move_type == 'out_invoice' and 'CUFE' or 'CUDE'" />:</strong><t t-foreach="o.dian_document_ids" t-as="dd"><t t-if="dd.cufe_cude and dd.state != 'cancel'"><t t-esc="dd.cufe_cude"/></t></t></pre>
</div>
<div t-if="o.move_type == 'out_refund' and o.out_refund_id" class="card border border-secondary bg-light p-1">
<pre class="text-uppercase mb-0" style="font-size:8px; line-height:8px; overflow:hidden;"><strong><t t-esc="o.out_refund_id.move_type == 'out_invoice' and 'CUFE' or 'CUDE'"/>:</strong><t t-foreach="o.out_refund_id.dian_document_ids" t-as="dd"><t t-if="dd.cufe_cude and dd.state != 'cancel'"><t t-esc="dd.cufe_cude"/></t></t></pre>
</div>
</div>
<div class="col-3">
<div t-if="o.move_type == 'out_invoice'" class="text-center">
<div style="line-height:9pt; font-size:8pt;">
<span>
Favor realizar sus pagos a la
<br />
Cuenta Corriente 210-05341-9
<br />
Banco de Occidente
</span>
</div>
</div>
</div>
<div class="col-4 float-right">
<t t-set="amount_words" t-value="o.currency_id.amount_to_text(o.amount_total) + 's'"/>
<div t-if="o.move_type == 'out_invoice'" class="text-right text-dark alert-info" style="padding:4pt;">
<div style="line-height:8pt; font-size:8pt;">
<span t-esc="amount_words" />
</div>
</div>
</div>
</div>
<!-- ######################################################### -->
<div class="row" t-if="o.move_type == 'out_invoice'">
<div class="col-xs-12">
<div class="col-12">
<div class="alert alert-info mb8" style="padding:8px;">
<p class="text-justify text-default" style="font-size:9pt;line-height:9pt;color:black;">
<span t-if="is_einvoice">
<p class="text-justify mb-0" style="font-size:9px;line-height:9px;color:black;">
<span t-if="is_einvoice" style="font-size:9px;line-height:9px;color:black;">
Ésta es una <strong><em>representación gráfica</em></strong>
de la factura electrónica, que para todos sus
efectos cumple con lo dispuesto en el
Art.&#160;774 del Código de Comercio, y en el
Decreto 2242 de 2015.
</span>
<span t-if="not is_einvoice">
<span t-if="not is_einvoice" style="font-size:9px;line-height:9px;color:black;">
Esta factura cumple, para todos sus
efectos, con lo dispuesto en el
Art.&#160;774 del Código de Comercio.
@ -408,33 +564,133 @@
través de terceros no vinculados a la Compañía.
Este documento es prueba de la negociación
realizada entre el cliente y Agofer S.A.S. en la
jurisdicción de <t t-esc="o.journal_id.name.rsplit(' ',1)[-1]" />.
jurisdicción de <t t-esc="o.journal_id.name.rsplit('-',1)[-1].lstrip()" />.
El cierre de esta venta es realizado únicamente por el
personal autorizado en nuestra sucursal en dicha ciudad.
</p>
</div>
</div>
</div>
<p t-if="o.move_type in ('out_invoice', 'in_refund') and o.payment_reference" name="payment_communication">
Please use the following communication for your payment : <b><span t-field="o.payment_reference"/></b>
</p>
<p t-if="o.invoice_payment_term_id" name="payment_term">
<span t-field="o.invoice_payment_term_id.note"/>
</p>
<p t-if="o.narration and o.narration!='false'" name="comment">
<span t-field="o.narration"/>
</p>
<p t-if="o.fiscal_position_id.note" name="note">
<span t-field="o.fiscal_position_id.note"/>
</p>
<p t-if="o.invoice_incoterm_id" name="incoterm">
<strong>Incoterm: </strong><span t-field="o.invoice_incoterm_id.code"/> - <span t-field="o.invoice_incoterm_id.name"/>
</p>
<div id="qrcode" t-if="o.display_qr_code">
<p t-if="qr_code_urls.get(o.id)">
<strong class="text-center">Scan me with your banking app.</strong><br/><br/>
<img class="border border-dark rounded" t-att-src="qr_code_urls[o.id]"/>
</p>
<!-- ######################################################### -->
<div class="row" style="position:relative; page-break-inside:avoid;" t-if="o.move_type == 'out_invoice'">
<div class="col-8">
<div class="card" style="border:0; box-shadow:none;">
<p style="font-size:9px; line-height:9px;">
Al pagar esta factura exija recibo de caja o recibo
provisional de caja; sin éste no se aceptan reclamos.
Si paga con cheque, coloque sello restrictivo a nombre
de <strong style="font-size:9px;line-height:9px;color:black;">Agofer&#160;S.A.S.</strong>
Verifique la mercancía al momento de ser entregada; Agofer
no se hace responsable por faltantes o deterioro detectados
después de entregado el material o que no cuenten con su
correspondiente anotación o señalamiento en la factura o
remisión, ni por vicios sobre el mismo que sean suceptibles
de ser verificados a simple vista o con ayuda de
instrumentos de medición básicos.
<span t-if="is_einvoice" style="font-size:9px;line-height:9px;color:black;">
<br />
Para aceptar o rechazar esta factura, consulte el mensaje enviado vía e-mail
junto con los documentos adjuntos.
</span>
</p>
</div>
<div class="row">
<div class="col-8">
<div class="card mb-1">
<div class="card-body" style="min-height:2cm; padding-top: 0px;">
<p class="small">
<t>
<strong>Transportador: </strong>
<br />
</t>
<t>
<strong>Empresa de transporte: </strong>
<br />
</t>
<t>
<strong>Placa: </strong>
</t>
</p>
</div>
<div class="card-footer" style="padding:2px;">
<small style="font-size:8pt; font-weight:normal; line-height:8pt;">
Datos transporte
</small>
</div>
</div>
</div>
<div class="col-4">
<div class="panel mb-1">
<div class="panel-body" style="min-height:2cm; padding-top:5px; overflow:hidden;">
<img t-att-src="'/web/image/2297122'" width="109" height="58"/>
</div>
<div class="panel-footer" style="padding:2px;">
<small style="font-size:8pt; font-weight:normal; line-height:8pt;">
Firma autorizada Agofer
</small>
</div>
</div>
</div>
</div>
</div>
<div class="col-4" style="position:absolute;bottom:0;right:0;">
<div class="card mb-1">
<div class="card-body" style="min-height:3.2cm; padding-top: 0px;">
<small style="font-size:8pt; font-weight:normal; line-height:8pt;">
Acepto esta factura y recibo conforme
</small>
</div>
<div class="card-footer" style="padding:2px;">
<small style="font-size:8pt; font-weight:normal; line-height:8pt;">
Nombre | CC | Firma | Sello | Fecha
</small>
</div>
</div>
</div>
</div>
<!-- ######################################################### -->
</div>
<div class="footer" style="font-size:11px;">
<t t-foreach="o.dian_document_ids" t-as="dd">
<t t-if="dd.cufe_cude and dd.state != 'cancel'">
<t t-set="urlvalidacion" t-value="'https://catalogo-vpfe.dian.gov.co/document/searchqr?documentkey=%s' % (dd.cufe_cude)"/>
<div class="clearfix">
<div class="float-left" style="font-size:8px;">
<strong>Fecha de validación:</strong>
<span t-field="dd.validation_datetime" t-field-options='{"format": "%Y-%m-%d %H:%M:%S"}'/>
</div>
<div class="float-right" style="font-size:8px;">
<strong>Consulte:</strong>
<t t-esc="urlvalidacion" />
</div>
</div>
</t>
</t>
<div class="text-center clearfix" style="border-top: 1px solid black;">
<small style="font-size:12px;">
Armenia • Barranquilla • Bogotá • Bucaramanga • Buga • Cali
• Cartagena • Ibagué • Itagüí<br/>Malambo • Montería •
Neiva • Pasto • Pereira • Soacha • Valledupar • Villavicencio • Yumbo<br/>
<span style="font-size:11px;">
Domicilio principal: CL 12A 38-45, Bogotá • Tel: 743 4444
</span>
</small>
</div>
<div class="row text-center" style="font-size:9px;">
<div class="col-4">
<strong>
<i class="fa fa-id-badge"></i>
Complete su esquema de vacunación
</strong>
</div>
<div class="col-4">
<strong>www.agofer.com.co</strong>
</div>
<div class="col-4">
AvancysERP • Por Avancys S.A.S. • NIT 900297700
</div>
</div>
</div>
</t>

79
hr_payslip_override.py Executable file
View File

@ -0,0 +1,79 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""Modifies all of the HR payslip format."""
import os
import sys
import odooly
def use_local_resources():
"""Facilita usar recursos en el mismo directorio del script."""
global __location__
__location__ = os.path.realpath(
os.path.join(os.getcwd(), os.path.dirname(__file__)))
def main():
odooly.Client._config_file = os.path.expanduser('~/.config/odooly.ini')
odoo = odooly.Client.from_config('Odoo14_Production')
views = odoo.env['ir.ui.view']
reports = odoo.env['ir.actions.report']
papers = odoo.env['report.paperformat']
baseid = 'hr_avancys.print_report_payslip'
qweb = open(os.path.join(__location__, 'agofer_payslip.xml')).read()
viewextid = 'agofer_view.override_payslip'
viewname = 'override_payslip'
viewarch = """<?xml version="1.0"?>
<data name="{0}" inherit_id="{1}">
<xpath expr="//t[@t-name='{1}']" position="replace">
<t t-name="{1}">
{2}
</t>
</xpath>
</data>""".format(viewname, baseid, qweb)
repextid = 'hr_avancys.action_print_report_payslip'
papextid = 'agofer_paper.factura_carta'
base_view = views.get(baseid)
assert base_view.name == 'print_report_payslip'
viewvalues = {
'arch': viewarch,
'active': True,
'mode': 'extension',
'inherit_id': base_view.id,
'name': viewname,
'priority': 16,
'type': 'qweb',
'model': False,
}
repvalues = {
'name': 'Comprobante de nómina',
'report_type': 'qweb-pdf',
'multi': False,
'attachment_use': False,
'attachment': False,
'paperformat_id': papers.get(papextid).id,
}
try:
reports.get(repextid).write(repvalues)
newview = views.get(viewextid)
if newview:
newview.write(viewvalues)
else:
newview = views.create(viewvalues)
newview._set_external_id(viewextid)
except:
xt, xc, tb = sys.exc_info()
xm = ''.join(odooly.format_exception(xt, xc, tb, chain=False))
print('### Error\n' + xm.strip())
if __name__ == "__main__":
use_local_resources()
main()

View File

@ -0,0 +1,51 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""Removes Worked Days from employee termination slip."""
import os
import sys
import odooly
def main():
odooly.Client._config_file = os.path.expanduser('~/.config/odooly.ini')
odoo = odooly.Client.from_config('Odoo14_Production')
views = odoo.env['ir.ui.view']
baseid = 'hr_avancys.print_report_payslip'
viewextid = 'agofer_view.hide_worked_days'
viewname = 'hide_worked_days'
viewarch = """<?xml version="1.0"?>
<data name="{0}" inherit_id="{1}">
<xpath expr="//p[@t-if=&quot;o.payslip_type_id.name == 'Liquidación'&quot;]" position="replace"/>
</data>""".format(viewname, baseid)
vista_base = views.get(baseid)
assert vista_base.name == 'print_report_payslip'
viewvalues = {
'arch': viewarch,
'active': True,
'mode': 'extension',
'inherit_id': vista_base.id,
'name': viewname,
'priority': 16,
'type': 'qweb',
'model': False,
}
try:
newview = views.get(viewextid)
if newview:
newview.write(viewvalues)
else:
newview = views.create(viewvalues)
newview._set_external_id(viewextid)
except:
xt, xc, tb = sys.exc_info()
xm = ''.join(odooly.format_exception(xt, xc, tb, chain=False))
print('### Error\n' + xm.strip())
if __name__ == "__main__":
main()

53
hr_payslip_show_period.py Executable file
View File

@ -0,0 +1,53 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""Shows period in employee payslip."""
import os
import sys
import odooly
def main():
odooly.Client._config_file = os.path.expanduser('~/.config/odooly.ini')
odoo = odooly.Client.from_config('Odoo14_Production')
views = odoo.env['ir.ui.view']
baseid = 'hr_avancys.print_report_payslip'
viewextid = 'agofer_view.show_hr_period'
viewname = 'show_hr_period'
viewarch = """<?xml version="1.0"?>
<data name="{0}" inherit_id="{1}">
<xpath expr="//p[contains(., 'Email:')]" position="before">
<br/><strong>Período: </strong><span t-field="o.period_id.name"/>
</xpath>
</data>""".format(viewname, baseid)
vista_base = views.get(baseid)
assert vista_base.name == 'print_report_payslip'
viewvalues = {
'arch': viewarch,
'active': True,
'mode': 'extension',
'inherit_id': vista_base.id,
'name': viewname,
'priority': 16,
'type': 'qweb',
'model': False,
}
try:
newview = views.get(viewextid)
if newview:
newview.write(viewvalues)
else:
newview = views.create(viewvalues)
newview._set_external_id(viewextid)
except:
xt, xc, tb = sys.exc_info()
xm = ''.join(odooly.format_exception(xt, xc, tb, chain=False))
print('### Error\n' + xm.strip())
if __name__ == "__main__":
main()

View File

@ -0,0 +1,389 @@
<t t-call="web.basic_layout">
<t t-set="doc" t-value="doc.with_context(lang=doc.partner_id.lang)"/>
<div class="header">
<div class="row">
<div class="col-sm-9">
<div class="card card-info">
<div class="card-heading">
<h1 class="card-title" style="color:black;">
<t t-set="es_cotizacion" t-value="doc.state not in ['progress','manual','done']"/>
<strong t-if="es_cotizacion">Cotización </strong>
<strong t-if="not es_cotizacion">Pedido de Venta </strong>
<strong t-if="es_cotizacion and doc.state == 'cancel'"> anulada </strong>
<strong t-if="not es_cotizacion and doc.state == 'cancel'"> anulado </strong>
<span t-field="doc.name"/>
<small t-if="doc.state == 'shipping_except'"> [⚠ Excepción en envío]</small>
<small t-if="doc.state == 'invoice_except'"> [⚠ Excepción en facturación]</small>
<small class="not-first-page"> (…continúa)</small>
</h1>
</div>
<div class="card-body">
<div class="col-sm-4">
<p>
<strong>Fecha:</strong>
<span t-field="doc.date_order" t-field-options="{&quot;format&quot;:&quot;YYYY-MM-dd&quot;}"/>
</p>
<div t-if="doc.validity_date and doc.state in ['draft', 'sent']" class="col-auto col-3 mw-100 mb-2" name="expiration_date">
<strong>Expiration:</strong>
<p class="m-0" t-field="doc.validity_date"/>
</div>
<!-- p t-if="doc.date_confirm">
<strong>Fecha de confirmación:</strong><br/>
<span t-field="doc.date_confirm" />
</p>
<p t-if="doc.date_aprobado_credito">
<strong>Fecha de aprobación crédito:</strong><br/>
<span t-field="doc.date_aprobado_credito" />
</p -->
</div>
<div class="col-sm-8">
<p t-if="doc.payment_term_id.note">
<strong>Condición de pago:</strong>
<span t-field="doc.payment_term_id.note" style="font-weight:normal;"/>
</p>
<p>
<t t-if="doc.incoterm">
<strong>Términos de negociación: </strong>
<code t-esc="doc.incoterm.code"/>:
<t t-esc="doc.incoterm.name"/>
</t>
</p>
</div>
</div>
</div>
</div>
<div class="col-sm-3 text-center">
<img t-if="doc.company_id.logo" t-att-src="'data:image/png;base64,%s' % doc.company_id.logo" width="153" height="80"/>
<!-- h4><small>NIT 800.216.4991</small></h4 -->
</div>
</div>
</div>
<div class="page">
<t t-set="weight" t-value="'{:,.2f}'.format(sum((l.product_id.weight &gt; 0 and l.product_id.weight * l.product_uom_qty or 0) for l in doc.order_line))"/>
<div class="row">
<div class="col-sm-9">
<div class="card card-info">
<div class="card-heading">
<h3 class="card-title" style="color:black;">
<strong t-field="doc.partner_id.name"/>
&#160;
<span class="text-nowrap">
<span t-field="doc.partner_id.ref_type_id.name"/> <span t-field="doc.partner_id.ref"/><span t-if="doc.partner_id.ref_type_id.code == 'NI'"><span t-raw="doc.partner_id.dev_ref"/></span>
</span>
</h3>
</div>
<div class="card-body">
<div t-attf-class="{{ doc.partner_shipping_id != doc.partner_id and 'col-sm-6' or 'col-sm-12' }}">
<div class="list-group mb0">
<h4 class="h5 list-group-item-heading" t-if="doc.partner_shipping_id == doc.partner_id">Dirección:</h4>
<h4 class="h5 list-group-item-heading" t-if="doc.partner_shipping_id != doc.partner_id">Dirección de facturación:</h4>
<p class="list-group-item-text" t-field="doc.partner_id.street"/>
<t t-if="doc.partner_id.street2">
<p class="list-group-item-text" t-field="doc.partner_id.street2"/>
</t>
<p class="list-group-item-text"><span t-field="doc.partner_id.city_id.name"/>, <span class="list-group-item-text" t-field="doc.partner_id.state_id.name"/></p>
<p class="list-group-item-text" t-if="doc.partner_id.phone" itemprop="telephone"><i class="fa fa-phone"/><span t-field="doc.partner_id.phone"/></p>
<p class="list-group-item-text" t-if="doc.partner_id.email" itemprop="email"><small t-field="doc.partner_id.email"/></p>
</div>
</div>
<div t-if="doc.partner_shipping_id != doc.partner_id" class="col-sm-6">
<div class="list-group mb0">
<h4 class="h5 list-group-item-heading">
Dirección de envío:
</h4>
<p class="list-group-item-text" t-field="doc.partner_shipping_id.street"/>
<t t-if="doc.partner_id.street2">
<p class="list-group-item-text" t-field="doc.partner_shipping_id.street2"/>
</t>
<p class="list-group-item-text"><span t-field="doc.partner_shipping_id.city_id.name"/>, <span class="list-group-item-text" t-field="doc.partner_shipping_id.state_id.name"/></p>
<p class="list-group-item-text" t-if="doc.partner_shipping_id.phone" itemprop="telephone"><i class="fa fa-phone"/><span t-field="doc.partner_shipping_id.phone"/></p>
<p class="list-group-item-text" t-if="doc.partner_shipping_id.email" itemprop="email"><span t-field="doc.partner_shipping_id.email"/></p>
</div>
</div>
</div>
</div>
</div>
<div class="col-sm-3 input-group">
<p style="font-size:9t; line-height:10pt;">
Agofer S.A.S. NIT 800.216.4991 :
</p>
<ul class="fa-ul" style="font-size:8pt; line-height:9pt; margin-left:1.2em;">
<li><i class="fa-li fa fa-caret-right"/>
Autorretenedor Res. №0010 1994-02-11
</li>
<li><i class="fa-li fa fa-caret-right"/>
Gran contribuyente Res. №000076 2016-12-01
</li>
<li><i class="fa-li fa fa-caret-right"/>
Régimen Común y Agente Retenedor de IVA
</li>
<li><i class="fa-li fa fa-caret-right"/>
Actividad Económica CIIU 4752
</li>
</ul>
</div>
</div>
<div class="row mt4 mb8">
<div class="col-sm-3">
<strong>
<t t-esc="doc.partner_id.user_id.employee_id.gender == 'female' and 'Asesora' or 'Asesor'"/> comercial:
</strong>
<p>
<span t-field="doc.partner_id.user_id.first_name"/>
<t t-if="doc.partner_id.user_id.second_name">
<span t-esc="doc.partner_id.user_id.second_name[:1]"/>.
</t>
<span t-field="doc.partner_id.user_id.first_surname"/>
<br/>
<small t-field="doc.partner_id.user_id.email"/>
<br/>
<em t-if="doc.partner_id.user_id != doc.user_id">
<small>
(<i class="fa fa-print"></i> <t t-esc="doc.user_id.first_name[:1]"/><t t-if="doc.user_id.second_name"><t t-esc="doc.user_id.second_name[:1]"/></t><t t-esc="doc.user_id.first_surname[:1]"/>)
</small>
</em>
</p>
</div>
<div class="col-sm-3">
<strong>Peso teórico total:</strong>
<p><t t-raw="weight"/> kg</p>
</div>
<div t-if="doc.client_order_ref" class="col-sm-3">
<strong>Orden de compra:</strong>
<p t-field="doc.client_order_ref"/>
</div>
<div t-if="not es_cotizacion and doc.warehouse_id" class="col-sm-3">
<strong>Origen:</strong>
<p>
<span t-field="doc.warehouse_id.name"/>
<i t-if="doc.warehouse_id.code[-2:] == '04'" class="fa fa-exclamation-triangle"></i>
</p>
</div>
</div>
<table class="table table-condensed">
<thead>
<tr>
<th>Description</th>
<th class="text-center" colspan="2">Quantity</th>
<th class="text-right">Unit Price</th>
<th class="text-right" groups="sale.group_discount_per_so_line">Discount (%)</th>
<th class="text-right">Valor</th>
<th class="text-right">IVA</th>
</tr>
</thead>
<tbody class="invoice_tbody">
<tr t-foreach="doc.order_line" t-as="l">
<t t-set="iva"/>
<t t-foreach="l.tax_id" t-as="tax">
<t t-if="tax.description[:3] == 'IVA'">
<t t-set="iva" t-value="tax.name[-4:]"/>
</t>
</t>
<td>
<tt>
<small t-field="l.product_id.code"/>
</tt>
<span t-field="l.product_id.name"/>
</td>
<td class="text-right">
<span t-esc="'{:,.2f}'.format(l.product_uom_qty)"/>
</td>
<td>
<span t-field="l.product_uom" groups="product.group_uom"/>
</td>
<td class="text-right">
<span t-esc="'{:,.0f}'.format(l.price_unit)"/>
</td>
<td class="text-right" groups="sale.group_discount_per_so_line"><span t-field="l.discount"/></td>
<td class="text-right">
<span t-field="l.price_subtotal" t-field-options="{&quot;widget&quot;: &quot;monetary&quot;, &quot;display_currency&quot;: &quot;doc.currency_id&quot;}"/>
</td>
<td class="text-right">
<small><t t-esc="iva"/></small>
</td>
</tr>
</tbody>
</table>
<div style="page-break-inside:avoid;">
<div class="row mb4">
<div class="col-sm-7">
<div>
<p t-if="doc.note">
<strong>Observaciones</strong><br/>
<span t-esc="'\n'.join([line for line in doc.note.split('\n') if line.strip() != ''])"/>
</p>
<p t-if="doc.fiscal_position_id.note">
<strong>Fiscal Position Remark:</strong>
<span t-field="doc.fiscal_position_id.note"/>
</p>
<div t-if="not es_cotizacion" class="alert alert-info mb8" style="padding:8px;">
<p class="text-justify text-default" style="font-size:9pt;line-height:9pt;color:black;">
Este <strong>pedido de venta</strong> recoge las
condiciones comerciales pactadas entre Agofer y el
cliente; Agofer emitirá factura de venta al momento
de entregar la mercancía.
No se aceptan reclamos después de 10 días de emitida la
factura.
Consulte nuestra <em>Promesa Comercial</em> en
<u>agofer.co/politicas/</u>
</p>
</div>
</div>
</div>
<div class="col-sm-4 pull-right mb4">
<table class="table table-condensed mb2">
<tr class="border-black">
<td><strong>Total Without Taxes</strong></td>
<td class="text-right">
<span t-field="doc.amount_untaxed" t-field-options="{&quot;widget&quot;: &quot;monetary&quot;, &quot;display_currency&quot;: &quot;doc.currency_id&quot;}"/>
</td>
</tr>
<tr>
<td>Taxes</td>
<td class="text-right">
<span t-field="doc.amount_tax" t-field-options="{&quot;widget&quot;: &quot;monetary&quot;, &quot;display_currency&quot;: &quot;doc.currency_id&quot;}"/>
</td>
</tr>
<tr class="border-black">
<td>
<strong>
Total
</strong>
</td>
<td class="text-right">
<span t-field="doc.amount_total" t-field-options="{&quot;widget&quot;: &quot;monetary&quot;, &quot;display_currency&quot;: &quot;doc.currency_id&quot;}"/>
</td>
</tr>
</table>
<div t-if="not es_cotizacion" class="text-right bg-info" style="padding:4pt;">
<p style="line-height:8pt;font-size:8pt;">
<span class="text-capitalize" t-esc="doc.amount_total" t-esc-options="{&quot;widget&quot;: &quot;num2words&quot;}"/>&amp;nbsp;Pesos.
</p>
</div>
</div>
</div>
<div class="row">
<div class="col-sm-6">
<div class="card card-default">
<div class="card-body" style="min-height:3.2cm; padding-top: 0px;">
<div t-if="doc.empresa_transporte" class="list-group mb0">
<p class="list-group-item-text">
<span t-field="doc.empresa_transporte.name"/>
<span class="text-nowrap">
<span t-field="doc.empresa_transporte.ref_type_id.name"/> <span t-field="doc.empresa_transporte.ref"/><span t-if="doc.empresa_transporte.ref_type_id.code == 'NI'"><span t-raw="doc.empresa_transporte.dev_ref"/></span>
</span>
</p>
<p t-if="doc.empresa_transporte.mobile" class="list-group-item-text" itemprop="telephone">
<i class="fa fa-mobile"/><span t-field="doc.empresa_transporte.mobile"/>
</p>
<p t-if="not doc.empresa_transporte.mobile" class="list-group-item-text" itemprop="telephone">
<i class="fa fa-mobile"/><span t-field="doc.empresa_transporte.phone"/>
</p>
</div>
<div t-if="not doc.empresa_transporte" class="list-group mb0">
<p class="list-group-item-text">
<span t-field="doc.nombre_transportador"/>
</p>
<p class="list-group-item-text">
<span t-field="doc.cedula_transportador"/>
</p>
<p t-if="doc.celular_transportador" class="list-group-item-text">
<i class="fa fa-mobile"/><span t-field="doc.celular_transportador"/>
</p>
</div>
<div t-if="doc.placa_transportador">
<strong>Placa: </strong>
<kbd t-field="doc.placa_transportador"/>
</div>
<div t-if="doc.direccion_despacho">
<strong>Dirección autorizada de envío: </strong>
<span t-field="doc.direccion_despacho"/>
</div>
</div>
<div class="card-footer" style="padding:2px;">
<small t-if="doc.incoterm and doc.incoterm.code in ['EXW','EXD']" style="font-size:8pt; font-weight:normal; line-height:8pt;">
Datos personal autorizado para retiro
</small>
<small t-if="not doc.incoterm or doc.incoterm.code not in ['EXW','EXD']" style="font-size:8pt; font-weight:normal; line-height:8pt;">
Datos transportista autorizado para entrega
</small>
</div>
</div>
</div>
<div class="col-sm-6">
<div class="card card-default">
<div class="card-body" style="min-height:3.2cm; padding-top: 0px;">
<small style="font-size:8pt; font-weight:normal; line-height:8pt;">
<t t-if="es_cotizacion">
Acepto esta cotización y autorizo se elabore
Pedido de Venta
</t>
<!-- Idea: este mensaje puede incluir "estoy
autorizado para firmar en nombre de la
empresa", si es una persona jurídica. También
puede detectar si hay personas autorizadas
para transporte, y solo incluir la firma de
autorización en ese caso -->
<t t-if="not es_cotizacion">
Acepto las condiciones contenidas en este
pedido de venta, y autorizo a las pesonas aquí
detalladas a recoger la mercancía en mi nombre.
</t>
</small>
</div>
<div class="card-footer" style="padding:2px;">
<small style="font-size:8pt; font-weight:normal; line-height:8pt;">
Nombre | CC | Firma | Sello | Fecha
</small>
</div>
</div>
</div>
</div>
<div t-if="doc.signature" class="mt32 ml64 mr4" name="signature">
<div class="offset-8">
<strong>Signature</strong>
</div>
<div class="offset-8">
<img t-att-src="image_data_uri(doc.signature)" style="max-height: 4cm; max-width: 8cm;"/>
</div>
<div class="offset-8 text-center">
<p t-field="doc.signed_by"/>
</div>
</div>
</div>
</div>
<div class="footer">
<div class="text-center" style="border-top: 1px solid black;">
<small>
<span t-field="doc.company_id.rml_footer"/><br/>
</small>
</div>
<div class="row">
<div class="col-sm-2">
<t t-set="abc"/>
<t t-foreach="doc.partner_id.category_id" t-as="cat">
<t t-if="cat.parent_id and cat.parent_id.name == 'ABC'">
<strong t-raw="cat.name" style="display:inline-block; border-radius:50%; width:18px; height:18px; padding:2px; border:1px solid #444; color:#444; text-align:center; font: 10px sans-serif;"/>
<t t-set="abc" t-value="True"/>
</t>
</t>
<i t-if="not abc" class="fa fa-user"></i>
</div>
<div class="col-sm-8 text-center">
<small>
<strong>
#QuedateEnCasa
<t t-if="es_cotizacion"> <i class="fa fa-smile-o"></i> </t>
<t t-if="not es_cotizacion"> <i class="fa fa-home"></i> </t>
<span t-field="doc.company_id.website"/>
</strong>
</small>
</div>
<div t-if="es_cotizacion" class="col-sm-2">
<small><code>P-V-01-R02 / v.2</code></small>
</div>
</div>
</div>
</t>

86
sale.order-formato_agofer.py Executable file
View File

@ -0,0 +1,86 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""Modificar todo el formato QWeb de un pedido de venta / cotización."""
import os
import sys
import odooly
def use_local_resources():
"""Facilita usar recursos en el mismo directorio del script."""
global __location__
__location__ = os.path.realpath(
os.path.join(os.getcwd(), os.path.dirname(__file__)))
def main():
odooly.Client._config_file = os.path.expanduser('~/.config/odooly.ini')
odoo = odooly.Client.from_config('odootest26')
baseid = 'sale.report_saleorder_document'
viewname = 'report.saleorder.cotizacion_o_pedido_agofer'
viewextid = 'agofer_view.cotizacion_o_pedido'
viewmodel = 'ir.ui.view'
repmodel = 'ir.actions.report'
repextid = 'sale.action_report_saleorder'
papmodel = 'report.paperformat'
papextid = 'agofer_paper.factura_carta'
vista_base = odoo.env[viewmodel].get(baseid)
assert vista_base.name == 'report_saleorder_document'
reporte = open(os.path.join(__location__,
'pedido_o_cotizacion_agofer.xml')).read()
formato_carta = odoo.env['report.paperformat'].get('report.paperformat_us')
destino_arch = """<?xml version="1.0"?>
<data>
<xpath expr="//t[@t-name='{0}']" position="replace">
<t t-name="{0}">
{1}
</t>
</xpath>
</data>""".format(baseid,reporte)
viewvalues = {
'active': True,
'arch': destino_arch,
'inherit_id': vista_base.id,
'mode': 'extension',
'name': viewname,
'priority': 15,
'type': 'qweb',
}
repvalues = {
'name': 'Cotización / Pedido de Venta',
'attachment': False,
'attachment_use': False,
'report_type': 'qweb-html',
}
try:
destino_vista = odoo.env[viewmodel].get(viewextid)
if destino_vista:
destino_vista.write(viewvalues)
else:
destino_vista = odoo.env[viewmodel].create(viewvalues)
destino_vista._set_external_id(viewextid)
paper = odoo.env[papmodel].get(papextid)
repvalues['paperformat_id'] = paper.id
# Asegurarse que el nombre de la Cedula de Ciudadania este abreviado:
# cc_extid = 'partner_extended_co.partner_co_document_type_CC'
# odoo.env['res.document.type'].get(cc_extid).name = 'CC'
odoo.env[repmodel].get(repextid).write(repvalues)
except:
xt, xc, tb = sys.exc_info()
xm = ''.join(odooly.format_exception(xt, xc, tb, chain=False))
print('### Error\n' + (xm.strip()))
if __name__ == "__main__":
use_local_resources()
main()