#!/usr/bin/env python3
# -*- coding: utf-8 -*-

# This file is part of Pymetrick.  The COPYRIGHT file at the top level of
# this repository contains the full copyright notices and license terms.

"""Modulo para emitir documentos iso-8859-1"""
from __future__ import division, with_statement

try:
    from pymetrick.version import __author__, __version__, __license__, __copyright__
except ImportError:
    raise ImportError(
        'Failed to find (autogenerated) version.py '
    )

__date__ = '2019-09-08'
__modify__ = '2019-09-08'
__credits__ = ''
__text__ = 'Issue documents'
__file__ = 'issue.py'

#--- CHANGES ------------------------------------------------------------------
# 2019-09-08 v0.50.0 PL: - First version



import sys
# sin bytecode
sys.dont_write_bytecode = True
import os, zlib, struct, re, tempfile, struct
import copy
from functools import wraps
import math
import errno

from datetime import date

# ESC/POS RAW PRINT

try:
    import win32api
    import win32print
    import win32ui
except ImportError:
    pass
    
from PIL import Image, ImageWin, ImageOps
from pymetrick.esc_pos_costants import *
import six

import logging
import logging.handlers

from pymetrick.helpers import *
from pymetrick.fpdf import FPDF

from pymetrick.ttfonts import TTFontFile
from pymetrick.fonts import fpdf_charwidths
from pymetrick.php import substr, sprintf, print_r, UTF8ToUTF16BE, UTF8StringToArray
from pymetrick.py3k import PY3K, pickle, urlopen, Image, basestring, unicode, exception, b, hashpath

import openpyxl
from openpyxl import Workbook,load_workbook       # order2xlsx
from openpyxl.utils.cell import coordinate_from_string
from openpyxl.utils.dataframe import dataframe_to_rows
from openpyxl.styles import Alignment, NamedStyle, Font, Color, colors
from openpyxl.styles.borders import Border, Side, BORDER_THIN
from openpyxl.worksheet.table import Table, TableStyleInfo
from openpyxl.utils import get_column_letter


'''
DEBUG - debug message
INFO - info message
WARNING - warn message
ERROR - error message
CRITICAL - critical message
'''
LOG_LEVEL_VALUE = {'DEBUG':10,'INFO':20,'WARNING':30,'ERROR':40,'CRITICAL':50}
if str(os.environ.get('PYMETRICK_LOG_LEVEL',None)).upper() in LOG_LEVEL_VALUE:
    LOG_LEVEL = LOG_LEVEL_VALUE[str(os.environ.get('PYMETRICK_LOG_LEVEL')).upper()]
else:
    LOG_LEVEL = 30
LOG_FILENAME = '-'.join([os.path.abspath(__file__).split(os.sep)[len(os.path.abspath(__file__).split(os.sep))-1],])[:-3]
LOG = logging.getLogger(LOG_FILENAME)

if 'LD_LIBRARY_PATH' in list(os.environ.keys()):
    # CGI environment
    sys.stdout = sys.stderr
    logging.basicConfig(stream = sys.stderr, level=LOG_LEVEL, format='%(filename)s[line:%(lineno)d] - %(levelname)s - %(message)s')
else:
    # not CGI environment
    logging.basicConfig(stream=sys.stderr)
    hdlr = logging.handlers.RotatingFileHandler(filename=LOG_FILENAME+'.log',mode='a', encoding='utf-8', maxBytes=1048576, backupCount=3)
    formatter = logging.Formatter('%(asctime)s - %(filename)s[line:%(lineno)d] - %(levelname)s - %(message)s')
    hdlr.setFormatter(formatter)
    LOG.addHandler(hdlr)
    LOG.setLevel(LOG_LEVEL)

LOCAL_DECIMAL_SEPARATOR = ','    

class Order(FPDF):
    '''Print trade orders like invoices on A4 (default)''' 

    def config(self,*args,**kwargs):
        ''' * logo          text  imagen logotipo
            * letterhead    list  membrete
            * client        list  datos de cliente
            * title         text  tipo de documento
            * title_head    list  titulo columnas
            * title_line    list  datos de documento
            * body_head     list  titulo columnas
              body_line     dict  lineas detalle
            * footer_head   list  titulos pie
              footer_line   dict  lineas pie
            * terms_of_sale text  Condiciones
            * authorization text  autorizacion legal
            * debug         boolean  solo para desarrollo
        '''
        try:
            # Add font : Courier New.ttf
            self.add_xfont()            
            self.allowed_data = {'logo':'','letterhead':list(),'client':list(),'title':'','title_head':list(),'title_line':list(),'body_head':list(),'footer_head':list(),'terms_of_sale':'','authorization':'','debug':False}
            for n in list(kwargs.keys()):
                if n in self.allowed_data:
                    self.allowed_data[n] = kwargs[n]

            # Add page
            self.add_page()
            
        except Exception as e:
            tb = sys.exc_info()[2]
            LOG.error('<%s> in line %s !!!' % (str(e),tb.tb_lineno))

    def add_xfont(self):
        try:
            if os.path.exists('cour.ttf'):
                self.add_font('Courier New', '', 'cour.ttf', uni=True)
            if os.path.exists('Courier New Bold.ttf'):
                self.add_font('Courier New Bold', '', 'Courier New Bold.ttf', uni=True)
            if os.path.exists('Courier New Bold Italic font.ttf'):
                self.add_font('Courier New Bold Italic', '', 'Courier New Bold Italic font.ttf', uni=True)
        except Exception as e:
            tb = sys.exc_info()[2]
            LOG.error('<%s> in line %s !!!' % (str(e),tb.tb_lineno))

    def header(self):
        try:
            # lineas
            self.set_line_width(width=0.03)
            self.rounded_rect(100,12,105,35.5,0.9)     # datos cliente
            self.rounded_rect(10,49,195,9.5,0.5)       # datos documento
            self.set_line_width(width=0.1)
            self.rounded_rect(10,60,195,193.5,0.5)     # detalle pedido
            self.set_line_width(width=0.07)
            self.line(11,65,204,65)
            self.set_line_width(width=0.1)
            self.rounded_rect(10,255,195,25,0.5)       # total pedido
            self.set_line_width(width=0.07)
            self.line(11,260,204,260)
            self.set_line_width(width=0.1)
            # sombras
            self.line(205.3,13,205.3,47)
            self.line(205.3,50,205.3,57)
            self.line(205.3,61,205.3,251)
            self.line(205.3,256,205.3,279)

            # Logo
            if self.allowed_data['debug']:
                pass
            else:
                if self.allowed_data['logo'] is not None:
                    self.image(self.allowed_data['logo'], 10, 8, 20)
            # Arial bold 15
            self.set_font('Arial', '', 6)
            
            if self.allowed_data['debug']:
                self.allowed_data['letterhead'] = ['RAZON SOCIAL','DIRECCION','COD.POSTAL-LOCALIDAD','PROVINCIA','CIF','TELEFONO','PAGINA WEB','CORREO_ELECTRONICO']

            nY = 15
            for n in self.allowed_data['letterhead']:
                if nY == 15:
                    self.set_font('Arial','B',8)
                else:
                    self.set_font('Arial','',6)
                self.text(33, nY, n)
                nY += 3
            if self.allowed_data['debug']:
                self.allowed_data['client'] = ['RAZON SOCIAL','DIRECCION','COD.POSTAL-LOCALIDAD','PROVINCIA','CIF','TELEFONO','PAGINA WEB','CORREO_ELECTRONICO']

            # Arial bold 15
            self.set_font('Arial', '', 9)
            nY = 15
            for n in self.allowed_data['client']:
                self.text(103, nY, n)
                nY += 3
            # title
            self.set_font('Arial','B',10);
            self.text(11,46,self.allowed_data['title'])
            try:
                self.set_font('Courier New','',8)
            except Exception as e:
                self.set_font('Courier','',8)            
            # registro
            if len(self.allowed_data['authorization'])>0:
                self.rotateText(8,250,self.allowed_data['authorization'],90)

            # background color
            #self.set_fill_color(211,211,211)   # grey
            #pdf.cell(190, 6, 'Testing...', 0, 1, 'L', fill=True)
            #pdf.cell(193, 6, 'Testing...', 0, 1, 'L', fill=False)
            # textos
            try:
                self.set_font('Courier New','',9)
            except Exception as e:
                self.set_font('Courier','',9)

            if self.allowed_data['debug']:
                self.allowed_data['title_head'] = 'NUM.ALBARAN    FECHA'

            if len(self.allowed_data['title_head'])>0:
                self.text(11,52,self.allowed_data['title_head'])

            if self.allowed_data['debug']:
                self.allowed_data['title_line'] = '2017000100    07/11/2017'

            if len(self.allowed_data['title_line'])>0:
                self.text(11,55,self.allowed_data['title_line'])

            try:
                self.set_font('Courier New','',8)
            except Exception as e:
                self.set_font('Courier','',8)
                
            if self.allowed_data['debug']:
                self.allowed_data['body_head'] = """{0:^5s} {1:^13s} {2:^40s}               {3:^8s} {4:^10s} {5:^5s} {6:^3s} {7:^8s}""".format('REF.','EAN13','PRODUCTO','UNIDADES','PRECIO €','DTO.%','IVA','IMPORTE')
   
            self.set_fill_color(211,211,211)   # background cell color grey
            self.set_xy(11, 61)   # 11,64 with .text
            if len(self.allowed_data['body_head'])>0:
                self.cell(193,3,self.allowed_data['body_head'],0,1,'L', fill=True)

            if self.allowed_data['debug']:
                self.allowed_data['footer_head'] = """{0:^1s}  {1:^11s} {2:^27s} {3:^8s}  {4:^9s}  {5:^5s}%  {6:^7s}  {7:^5s}%  {8:^9s}  {9:^9s}""".format(' ','Imp.Neto €','Dto.%','Imp.Dto.','Base Imp.','IVA','Imp.IVA','R.EQ.','Imp.R.EQ.','Total')

            self.set_xy(11, 256)   # 11,258 with .text
            if len(self.allowed_data['footer_head'])>0:
                self.cell(193,3,self.allowed_data['footer_head'],0,1,'L', fill=True)

            if self.allowed_data['debug']:
                try:
                    self.set_font('Courier New Bold Italic','',9)
                except Exception as e:
                    self.set_font('Courier','BI',9)
                self.text(153,278,('{0} {1:>10.2f}'.format('IMPORTE TOTAL €',1000000,00)).replace('.',LOCAL_DECIMAL_SEPARATOR))                

            # configurar documento
            if len(self.allowed_data['title'])>0:
                self.set_title(self.allowed_data['title'])
            if len(self.allowed_data['letterhead'])>0:
                self.set_author(self.allowed_data['letterhead'][0])
                self.set_creator('pymetrick')

            # Line break
            self.ln(20)
        except Exception as e:
            tb = sys.exc_info()[2]
            LOG.error('<%s> in line %s !!!' % (str(e),tb.tb_lineno))

    # Page footer
    def footer(self):
        try:
            # Position at 1.5 cm from bottom
            self.set_y(-15)
            # Arial italic 7
            self.set_font('Arial', 'I', 7)
            # Page number
            self.cell(0, 5, 'Pagina ' + str(self.page_no()) + '/{nb}', 0, 0, 'C')
            # Terms
            self.set_y(-12)
            self.set_font('Arial','', 5)
            self.multi_cell( w=200, h=3, txt=self.allowed_data['terms_of_sale'], border = 0, align = 'J', fill = False, split_only=False)
        except Exception as e:
            tb = sys.exc_info()[2]
            LOG.error('<%s> in line %s !!!' % (str(e),tb.tb_lineno))

    def rotateText(self,x,y,txt,angle):
        #Text rotated around its origin
        try:
            self.rotate(angle,x,y)
            self.text(x,y,txt)
            self.rotate(0)
        except Exception as e:
            tb = sys.exc_info()[2]
            LOG.error('<%s> in line %s !!!' % (str(e),tb.tb_lineno))

    def rotateImage(self,file,x,y,w,h,angle):
        #Image rotated around its upper-left corner
        try:
            self.rotate(angle,x,y)
            self.image(file,x,y,w,h)
            self.rotate(0)
        except Exception as e:
            tb = sys.exc_info()[2]
            LOG.error('<%s> in line %s !!!' % (str(e),tb.tb_lineno))


    def rounded_rect(self,x, y, w, h, r,corners='1234',style=''):
        "Draw a rounded rectangle"
        try:
            if(style=='F'):
                op='f'
            elif(style=='FD' or style=='DF'):
                op='B'
            else:
                op='S'

            myArc = 4/3 * (math.sqrt(2) - 1);
            self._out(sprintf('%.2f %.2f m',(x+r)*self.k,(self.h-y)*self.k ))

            xc = x+w-r;
            yc = y+r;
            self._out(sprintf('%.2f %.2f l', xc*self.k,(self.h-y)*self.k ))
            if (corners.find('2') < 0):
                self._out(sprintf('%.2f %.2f l', (x+w)*self.k,(self.h-y)*self.k ))
            else:
                self._arc(xc + r*myArc, yc - r, xc + r, yc - r*myArc, xc + r, yc)

            xc = x+w-r;
            yc = y+h-r;
            self._out(sprintf('%.2f %.2f l',(x+w)*self.k,(self.h-yc)*self.k));
            if (corners.find('3') < 0):
                self._out(sprintf('%.2f %.2f l',(x+w)*self.k,(self.h-(y+h))*self.k));
            else:
                self._arc(xc + r, yc + r*myArc, xc + r*myArc, yc + r, xc, yc + r)

            xc = x+r;
            yc = y+h-r;
            self._out(sprintf('%.2f %.2f l',xc*self.k,(self.h-(y+h))*self.k));
            if (corners.find('4') < 0):
                self._out(sprintf('%.2f %.2f l',(x)*self.k,(self.h-(y+h))*self.k))
            else:
                self._arc(xc - r*myArc, yc + r, xc - r, yc + r*myArc, xc - r, yc)

            xc = x+r ;
            yc = y+r;
            self._out(sprintf('%.2f %.2f l',(x)*self.k,(self.h-yc)*self.k ))
            if (corners.find('1') < 0):
                self._out(sprintf('%.2f %.2f l',(x)*self.k,(self.hp-y)*self.k ))
                self._out(sprintf('%.2f %.2f l',(x+r)*self.k,(self.h-y)*self.k ))
            else:
                self._arc(xc - r, yc - r*myArc, xc - r*myArc, yc - r, xc, yc - r)
            self._out(op);
        except Exception as e:
            tb = sys.exc_info()[2]
            LOG.error('<%s> in line %s !!!' % (str(e),tb.tb_lineno))


    def _arc(self, x1, y1, x2, y2, x3, y3):
        try:
            h = self.h
            self._out(sprintf('%.2f %.2f %.2f %.2f %.2f %.2f c', x1*self.k, (h-y1)*self.k,
                x2*self.k, (h-y2)*self.k, x3*self.k, (h-y3)*self.k))
        except Exception as e:
            tb = sys.exc_info()[2]
            LOG.error('<%s> in line %s !!!' % (str(e),tb.tb_lineno))


    # EAN14 and UPC-A
    def EAN13(self, x, y, barcode_, h=16, w=.40):
        try:
            self.__barcode__(x,y, barcode_,h,w,13)
        except Exception as e:
            tb = sys.exc_info()[2]
            LOG.error('<%s> in line %s !!!' % (str(e),tb.tb_lineno))


    def UPC_A(self, x, y, barcode_, h=16, wget_y=.35):
        try:
            self.__barcode__(x,y,barcode_,h,w,12)
        except Exception as e:
            tb = sys.exc_info()[2]
            LOG.error('<%s> in line %s !!!' % (str(e),tb.tb_lineno))


    def getCheckDigit(self, barcode_):
        # Compute the check digit
        try:
            sum=0
            for i in range(1,12,2):
                sum += 3*int(barcode_[i])
            for i in range(0,11,2):
                sum+=int(barcode_[i])
            r=sum%10
            if(r>0):
                r=10-r
            return str(r)
        except Exception as e:
            tb = sys.exc_info()[2]
            LOG.error('<%s> in line %s !!!' % (str(e),tb.tb_lineno))


    def testCheckDigit(self, barcode_):
        #Test validity of check digit
        try:
            sum=0
            for i in range(1,12,2):
                sum += 3*int(barcode_[i])
            for i in range(0,11,2):
                sum += int(barcode_[i])
            return (sum+int(barcode_[-1:]))%10==0
        except Exception as e:
            tb = sys.exc_info()[2]
            LOG.error('<%s> in line %s !!!' % (str(e),tb.tb_lineno))


    def __barcode__(self, x, y, barcode_, h, w, lng):
        try:
            # Padding
            barcode_=barcode_.rjust(lng-1,'0')
            if lng==12:
                barcode_ = '0' + barcode_
            # Add or control the check digit
            if len(barcode_) == 12:
                barcode_ += self.getCheckDigit(barcode_)
            elif not self.testCheckDigit(barcode_):
                self.error('Incorrect check digit')
            #Convert digits to bars
            codes={
                'A':{
                    '0':'0001101','1':'0011001','2':'0010011','3':'0111101','4':'0100011',
                    '5':'0110001','6':'0101111','7':'0111011','8':'0110111','9':'0001011'},
                'B':{
                    '0':'0100111','1':'0110011','2':'0011011','3':'0100001','4':'0011101',
                    '5':'0111001','6':'0000101','7':'0010001','8':'0001001','9':'0010111'},
                'C':{
                    '0':'1110010','1':'1100110','2':'1101100','3':'1000010','4':'1011100',
                    '5':'1001110','6':'1010000','7':'1000100','8':'1001000','9':'1110100'}
                }
            parities={
                '0':['A','A','A','A','A','A'],
                '1':['A','A','B','A','B','B'],
                '2':['A','A','B','B','A','B'],
                '3':['A','A','B','B','B','A'],
                '4':['A','B','A','A','B','B'],
                '5':['A','B','B','A','A','B'],
                '6':['A','B','B','B','A','A'],
                '7':['A','B','A','B','A','B'],
                '8':['A','B','A','B','B','A'],
                '9':['A','B','B','A','B','A']
                }
            code_='101';
            p=parities[barcode_[0]]
            for i in range(1,7):
                code_ +=codes[p[i-1]][barcode_[i]]
            code_ +='01010'
            for i in range(7,13):
                code_ +=codes['C'][barcode_[i]]
            code_ +='101'
            #Draw bars
            for i in range(0,len(code_)):
                if code_[i]=='1':
                    self.rect(x+i*w,y,w,h,'F')
            #Print text under barcode
            self.set_font('Arial','',12);
            self.text(x,y+h+11/self.k,barcode_[-lng:])
        except Exception as e:
            tb = sys.exc_info()[2]
            LOG.error('<%s> in line %s !!!' % (str(e),tb.tb_lineno))


class Drafted(FPDF):
    '''Print trade orders like invoices on A4 (other format)''' 

    def config(self,*args,**kwargs):
        ''' * logo          text  imagen logotipo
            * letterhead    list  membrete
            * client        list  datos de cliente
            * invoice_title text  texto en titulo de datos de factura
            * entity_title  text  texto en titulo de entidad receptora
            * title         text  tipo de documento
            * title_head    list  titulo columnas
            * title_line    list  datos de documento
            * body_head     list  titulo columnas
              body_line     dict  lineas detalle
            * footer_head   list  titulos pie
              footer_line   dict  lineas pie
            * terms_of_sale text  Condiciones
            * authorization text  autorizacion legal
            * debug         boolean  solo para desarrollo
        '''
        try:
            self.add_xfont()
            self.allowed_data = {'logo':'','letterhead':list(),'client':list(),'invoice_title':'','entity_title':'', 'title':'','title_head':list(),'title_line':list(),'body_head':list(),'footer_head':list(),'terms_of_sale':'','authorization':'','debug':False}
            for n in list(kwargs.keys()):
                if n in self.allowed_data:
                    self.allowed_data[n] = kwargs[n]

            # Add page
            self.add_page()
        except Exception as e:
            tb = sys.exc_info()[2]
            LOG.error('<%s> in line %s !!!' % (str(e),tb.tb_lineno))

    def add_xfont(self):
        try:
            if os.path.exists('cour.ttf'):
                self.add_font('Courier New', '', 'cour.ttf', uni=True)
            if os.path.exists('Courier New Bold.ttf'):
                self.add_font('Courier New Bold', '', 'Courier New Bold.ttf', uni=True)
            if os.path.exists('Courier New Bold Italic font.ttf'):
                self.add_font('Courier New Bold Italic', '', 'Courier New Bold Italic font.ttf', uni=True)
        except Exception as e:
            tb = sys.exc_info()[2]
            LOG.error('<%s> in line %s !!!' % (str(e),tb.tb_lineno))
            
    def header(self):
        try:
            # lineas
            self.set_line_width(width=0.03)
            # title
            self.set_font('Times','B',8)
            if self.allowed_data['debug']:
                self.allowed_data['invoice_title'] = 'Información de Facturación'
            self.text(120,17,self.allowed_data['invoice_title']) # invoice title
            self.line(120,18,205,18)                     # información de facturación
            if self.allowed_data['debug']:
                self.allowed_data['entity_title'] = 'Receptor de Factura'
            self.text(11,34,self.allowed_data['entity_title'])        
            self.line(11,35,110,35)                    # receptor de factura

            self.set_line_width(width=0.07)            # detalle de pedido
            self.line(11,62,205,62)

            self.set_line_width(width=0.07)            # total pedido
            self.line(11,257,205,257)

            # Logo
            if self.allowed_data['debug']:
                pass
            else:
                if self.allowed_data['logo'] is not None and len(self.allowed_data['logo'])>0:
                    self.image(self.allowed_data['logo'], 10, 8, 20)
            
            self.set_font('Arial', '', 5)
            
            if self.allowed_data['debug']:
                self.allowed_data['letterhead'] = ['RAZON SOCIAL','DIRECCION','COD.POSTAL-LOCALIDAD','PROVINCIA','CIF','TELEFONO','PAGINA WEB','CORREO_ELECTRONICO']
            nY = 7
            for n in self.allowed_data['letterhead']:
                if nY == 7:
                    self.set_font('Times','B',8)
                else:
                    self.set_font('Times','',5)
                self.text(33, nY, n)
                nY += 3
            if self.allowed_data['debug']:
                self.allowed_data['client'] = ['RAZON SOCIAL','DIRECCION','COD.POSTAL-LOCALIDAD','PROVINCIA','CIF','TELEFONO','PAGINA WEB','CORREO_ELECTRONICO']
            #
            self.set_font('Times', '', 7)
            nY = 37
            for n in self.allowed_data['client']:
                self.text(40, nY, n)
                nY += 3
            # title
            self.set_font('Times','B',10);
            self.text(11,61,self.allowed_data['title'].strip())
            try:
                self.set_font('Courier New','',8)
            except Exception as e:
                self.set_font('Courier','',8)
            # registro
            if len(self.allowed_data['authorization'])>0:
                self.rotateText(8,250,self.allowed_data['authorization'],90)

            # background color
            #self.set_fill_color(211,211,211)   # grey
            #pdf.cell(190, 6, 'Testing...', 0, 1, 'L', fill=True)
            #pdf.cell(193, 6, 'Testing...', 0, 1, 'L', fill=False)
            # textos
            try:
                self.set_font('Courier New','',9)
            except Exception as e:
                self.set_font('Courier','',9)
                
            if self.allowed_data['debug']:
                self.allowed_data['title_head'] = 'NUM.ALBARAN    FECHA'
            #
            if len(self.allowed_data['title_head'])>0:
                self.text(120,21,self.allowed_data['title_head'])
            if self.allowed_data['debug']:
                self.allowed_data['title_line'] = '2017000100    07/11/2017'
            #
            if len(self.allowed_data['title_line'])>0:
                self.text(120,24,self.allowed_data['title_line'])

            if self.allowed_data['debug']:
                self.allowed_data['body_head'] = """{0:^5s} {1:^13s} {2:^40s}               {3:^8s} {4:^11s} {5:^5s} {6:^3s} {7:^8s}""".format('REF.','EAN13','PRODUCTO','UNIDADES','PRECIO €','DTO.%','IVA','IMPORTE')
            #
                
            self.set_fill_color(211,211,211)   # background cell color grey
            self.set_xy(11, 63)   # 11,63 with .text
            
            try:
                self.set_font('Courier New','',8)
            except Exception as e:
                self.set_font('Courier','',8)
                
            if len(self.allowed_data['body_head'])>0:
                self.cell(193,3,self.allowed_data['body_head'],0,1,'L')
                
            if self.allowed_data['debug']:
                self.allowed_data['footer_head'] = """{0:^1s}  {1:^11s} {2:^27s} {3:^8s}  {4:^9s}  {5:^5s}%  {6:^7s}  {7:^5s}%  {8:^9s}  {9:^9s}""".format(' ','Imp.Neto €','Dto.%','Imp.Dto.','Base Imp.','IVA','Imp.IVA','R.EQ.','Imp.R.EQ.','Total')
            #
            self.set_xy(11, 253)   # 11,258 with .text
            if len(self.allowed_data['footer_head'])>0:
                self.cell(193,3,self.allowed_data['footer_head'],0,1,'L')
                
            if self.allowed_data['debug']:
                try:
                    self.set_font('Courier New Bold Italic','',9)
                except Exception as e:
                    self.set_font('Courier','BI',9)
                self.text(153,278,('{0} {1:>10.2f}'.format('IMPORTE TOTAL €',1000000,00)).replace('.',LOCAL_DECIMAL_SEPARATOR))                

            # configurar documento
            if len(self.allowed_data['title'])>0:
                self.set_title(self.allowed_data['title'])
            if len(self.allowed_data['letterhead'])>0:
                self.set_author(self.allowed_data['letterhead'][0])
                self.set_creator('pymetrick')

            # Line break
            self.ln(20)
        except Exception as e:
            tb = sys.exc_info()[2]
            LOG.error('<%s> in line %s !!!' % (str(e),tb.tb_lineno))

    # Page footer
    def footer(self):
        try:
            # Position at 1.5 cm from bottom
            self.set_y(-15)
            # Arial italic 7
            self.set_font('Arial', 'I', 7)
            # Page number
            self.cell(0, 5, 'Pág. ' + str(self.page_no()) + '/{nb}', 0, 0, 'C')
            if self.allowed_data['debug']:
                pass
            # Terms
            self.set_y(-12)
            self.set_font('Arial','', 5)
            self.multi_cell( w=200, h=3, txt=self.allowed_data['terms_of_sale'], border = 0, align = 'J', fill = False, split_only=False)
        except Exception as e:
            tb = sys.exc_info()[2]
            LOG.error('<%s> in line %s !!!' % (str(e),tb.tb_lineno))

    def rotateText(self,x,y,txt,angle):
        #Text rotated around its origin
        try:
            self.rotate(angle,x,y)
            self.text(x,y,txt)
            self.rotate(0)
        except Exception as e:
            tb = sys.exc_info()[2]
            LOG.error('<%s> in line %s !!!' % (str(e),tb.tb_lineno))

    def rotateImage(self,file,x,y,w,h,angle):
        #Image rotated around its upper-left corner
        try:
            self.rotate(angle,x,y)
            self.image(file,x,y,w,h)
            self.rotate(0)
        except Exception as e:
            tb = sys.exc_info()[2]
            LOG.error('<%s> in line %s !!!' % (str(e),tb.tb_lineno))


    def rounded_rect(self,x, y, w, h, r,corners='1234',style=''):
        "Draw a rounded rectangle"
        try:
            if(style=='F'):
                op='f'
            elif(style=='FD' or style=='DF'):
                op='B'
            else:
                op='S'

            myArc = 4/3 * (math.sqrt(2) - 1);
            self._out(sprintf('%.2f %.2f m',(x+r)*self.k,(self.h-y)*self.k ))

            xc = x+w-r;
            yc = y+r;
            self._out(sprintf('%.2f %.2f l', xc*self.k,(self.h-y)*self.k ))
            if (corners.find('2') < 0):
                self._out(sprintf('%.2f %.2f l', (x+w)*self.k,(self.h-y)*self.k ))
            else:
                self._arc(xc + r*myArc, yc - r, xc + r, yc - r*myArc, xc + r, yc)

            xc = x+w-r;
            yc = y+h-r;
            self._out(sprintf('%.2f %.2f l',(x+w)*self.k,(self.h-yc)*self.k));
            if (corners.find('3') < 0):
                self._out(sprintf('%.2f %.2f l',(x+w)*self.k,(self.h-(y+h))*self.k));
            else:
                self._arc(xc + r, yc + r*myArc, xc + r*myArc, yc + r, xc, yc + r)

            xc = x+r;
            yc = y+h-r;
            self._out(sprintf('%.2f %.2f l',xc*self.k,(self.h-(y+h))*self.k));
            if (corners.find('4') < 0):
                self._out(sprintf('%.2f %.2f l',(x)*self.k,(self.h-(y+h))*self.k))
            else:
                self._arc(xc - r*myArc, yc + r, xc - r, yc + r*myArc, xc - r, yc)

            xc = x+r ;
            yc = y+r;
            self._out(sprintf('%.2f %.2f l',(x)*self.k,(self.h-yc)*self.k ))
            if (corners.find('1') < 0):
                self._out(sprintf('%.2f %.2f l',(x)*self.k,(self.hp-y)*self.k ))
                self._out(sprintf('%.2f %.2f l',(x+r)*self.k,(self.h-y)*self.k ))
            else:
                self._arc(xc - r, yc - r*myArc, xc - r*myArc, yc - r, xc, yc - r)
            self._out(op);
        except Exception as e:
            tb = sys.exc_info()[2]
            LOG.error('<%s> in line %s !!!' % (str(e),tb.tb_lineno))


    def _arc(self, x1, y1, x2, y2, x3, y3):
        try:
            h = self.h
            self._out(sprintf('%.2f %.2f %.2f %.2f %.2f %.2f c', x1*self.k, (h-y1)*self.k,
                x2*self.k, (h-y2)*self.k, x3*self.k, (h-y3)*self.k))
        except Exception as e:
            tb = sys.exc_info()[2]
            LOG.error('<%s> in line %s !!!' % (str(e),tb.tb_lineno))


    # EAN14 and UPC-A
    def EAN13(self, x, y, barcode_, h=16, w=.40):
        try:
            self.__barcode__(x,y, barcode_,h,w,13)
        except Exception as e:
            tb = sys.exc_info()[2]
            LOG.error('<%s> in line %s !!!' % (str(e),tb.tb_lineno))


    def UPC_A(self, x, y, barcode_, h=16, wget_y=.35):
        try:
            self.__barcode__(x,y,barcode_,h,w,12)
        except Exception as e:
            tb = sys.exc_info()[2]
            LOG.error('<%s> in line %s !!!' % (str(e),tb.tb_lineno))


    def getCheckDigit(self, barcode_):
        # Compute the check digit
        try:
            sum=0
            for i in range(1,12,2):
                sum += 3*int(barcode_[i])
            for i in range(0,11,2):
                sum+=int(barcode_[i])
            r=sum%10
            if(r>0):
                r=10-r
            return str(r)
        except Exception as e:
            tb = sys.exc_info()[2]
            LOG.error('<%s> in line %s !!!' % (str(e),tb.tb_lineno))


    def testCheckDigit(self, barcode_):
        #Test validity of check digit
        try:
            sum=0
            for i in range(1,12,2):
                sum += 3*int(barcode_[i])
            for i in range(0,11,2):
                sum += int(barcode_[i])
            return (sum+int(barcode_[-1:]))%10==0
        except Exception as e:
            tb = sys.exc_info()[2]
            LOG.error('<%s> in line %s !!!' % (str(e),tb.tb_lineno))


    def __barcode__(self, x, y, barcode_, h, w, lng):
        try:
            # Padding
            barcode_=barcode_.rjust(lng-1,'0')
            if lng==12:
                barcode_ = '0' + barcode_
            # Add or control the check digit
            if len(barcode_) == 12:
                barcode_ += self.getCheckDigit(barcode_)
            elif not self.testCheckDigit(barcode_):
                self.error('Incorrect check digit')
            #Convert digits to bars
            codes={
                'A':{
                    '0':'0001101','1':'0011001','2':'0010011','3':'0111101','4':'0100011',
                    '5':'0110001','6':'0101111','7':'0111011','8':'0110111','9':'0001011'},
                'B':{
                    '0':'0100111','1':'0110011','2':'0011011','3':'0100001','4':'0011101',
                    '5':'0111001','6':'0000101','7':'0010001','8':'0001001','9':'0010111'},
                'C':{
                    '0':'1110010','1':'1100110','2':'1101100','3':'1000010','4':'1011100',
                    '5':'1001110','6':'1010000','7':'1000100','8':'1001000','9':'1110100'}
                }
            parities={
                '0':['A','A','A','A','A','A'],
                '1':['A','A','B','A','B','B'],
                '2':['A','A','B','B','A','B'],
                '3':['A','A','B','B','B','A'],
                '4':['A','B','A','A','B','B'],
                '5':['A','B','B','A','A','B'],
                '6':['A','B','B','B','A','A'],
                '7':['A','B','A','B','A','B'],
                '8':['A','B','A','B','B','A'],
                '9':['A','B','B','A','B','A']
                }
            code_='101';
            p=parities[barcode_[0]]
            for i in range(1,7):
                code_ +=codes[p[i-1]][barcode_[i]]
            code_ +='01010'
            for i in range(7,13):
                code_ +=codes['C'][barcode_[i]]
            code_ +='101'
            #Draw bars
            for i in range(0,len(code_)):
                if code_[i]=='1':
                    self.rect(x+i*w,y,w,h,'F')
            #Print text under barcode
            self.set_font('Arial','',12);
            self.text(x,y+h+11/self.k,barcode_[-lng:])
        except Exception as e:
            tb = sys.exc_info()[2]
            LOG.error('<%s> in line %s !!!' % (str(e),tb.tb_lineno))

            

class Simple_Order_PDF(FPDF):
    '''Print receipt on 80 cols. paper (default)'''
    def config(self,*args,**kwargs):
        ''' * logo          text  imagen logotipo
            * letterhead    list  membrete
            * client        list  datos de cliente
            * title         text  tipo de documento
            * title_head    list  titulo columnas
            * title_line    list  datos de documento
            * body_head     list  titulo columnas
              body_line     dict  lineas detalle
            * footer_head   text  titulos pie
              footer_line   dict  lineas pie
            * payment_line  list  lineas de pagos
            * order_code    text  order_code
            * terms_of_sale text  Condiciones
        '''
        try:
            # Add font : Courier New.ttf
            self.add_xfont()            
            self.allowed_data = {'logo':'','letterhead':list(),'client':list(),'title':'','title_head':list(),'title_line':list(),'body_head':list(),'body_line':list(),'footer_head':'','footer_line':list(),'total':list(),'terms_of_sale':'','authorization':'','order_code':'','payment_line':list()}
            for n in list(kwargs.keys()):
                if n in self.allowed_data:
                    self.allowed_data[n] = kwargs[n]

            # Add page
            self.add_page()
            #self.set_auto_page_break(True)

        except Exception as e:
            tb = sys.exc_info()[2]
            LOG.error('<%s> in line %s !!!' % (str(e),tb.tb_lineno))

    def add_xfont(self):
        try:
            if os.path.exists('cour.ttf'):
                self.add_font('Courier New', '', 'cour.ttf', uni=True)
            if os.path.exists('Courier New Bold.ttf'):
                self.add_font('Courier New Bold', '', 'Courier New Bold.ttf', uni=True)
            if os.path.exists('Courier New Bold Italic font.ttf'):
                self.add_font('Courier New Bold Italic', '', 'Courier New Bold Italic font.ttf', uni=True)
        except Exception as e:
            tb = sys.exc_info()[2]
            LOG.error('<%s> in line %s !!!' % (str(e),tb.tb_lineno))
            
    def header(self):
        try:
            pass
        except Exception as e:
            tb = sys.exc_info()[2]
            LOG.error('<%s> in line %s !!!' % (str(e),tb.tb_lineno))

    def body_lines(self):
        try:
            '''print head only one'''
            # Logo
            if self.allowed_data['logo'] is not None:
                self.image(self.allowed_data['logo'], 3, 3, 15)
                self.ln(12)
    
            # configurar documento
            self.set_creator('pymetrick')
            # letterhead
            if len(self.allowed_data['letterhead'])>0:
                self.set_author(self.allowed_data['letterhead'][0])
                self.set_font("Helvetica","B",size=15)
                self.cell(60,4,self.allowed_data['letterhead'][0], ln=1, align="C")
                self.set_font("Helvetica", size=9)
                for n in range(1,len(self.allowed_data['letterhead'])-1):
                    self.cell(60,3,self.allowed_data['letterhead'][n], ln=1, align="C")
            # client
            if len(self.allowed_data['client'])>0:
                self.ln(5)
                for n in range(0,len(self.allowed_data['client'])):

                    # special characters can cause errors in ticket printers, replacing or removing is the only solution
                    removeChars = "!#$%^"    # special chars 
                    # maketrans(chars to replace,chars replaced, chars to remove)
                    transTable = self.allowed_data['client'][n].maketrans("ÁÉÍÓÚ", "AEIOU", removeChars)
                    self.allowed_data['client'][n] = self.allowed_data['client'][n].translate(transTable)
                    # end replacing or removing especial chars
                    
                    self.cell(60,3,self.allowed_data['client'][n], ln=1, align="C")
            
            # title order lines
            if len(self.allowed_data['title_line'])>0:
                self.ln(3)
                for n in range(0,len(self.allowed_data['title_line'])):
                    self.cell(60,3,self.allowed_data['title_line'][n], ln=1, align="")
        
            '''print items line'''

            # body head
            if len(self.allowed_data['body_line'])>0 and len(self.allowed_data['order_code'])>0 and len(self.allowed_data['body_head'])>0:
                self.set_font("Helvetica", size=8)
                self.set_text_color(0, 0, 0)
                self.cell(35, 4, self.allowed_data['body_head'][0], border=1, ln=0, align="C", fill=False)
                self.cell(10, 4, self.allowed_data['body_head'][1], border=1, ln=0, align="R", fill=False)
                self.cell(13, 4, self.allowed_data['body_head'][2], border=1, ln=0, align="R", fill=False)
                self.cell(13, 4, self.allowed_data['body_head'][3], border=1, ln=0, align="R", fill=False)
                self.ln(6)

            # body lines    
            if len(self.allowed_data['body_line'])>0 and len(self.allowed_data['order_code'])>0:
                for n in range(0,len(self.allowed_data['body_line'])):
                    
                    # special characters can cause errors in ticket printers, replacing or removing is the only solution
                    removeChars = "!#$%^&()\\n"    # special chars 
                    # maketrans(chars to replace,chars replaced, chars to remove)
                    transTable = self.allowed_data['body_line'][n][0].maketrans("ÁÉÍÓÚ", "AEIOU", removeChars)
                    self.allowed_data['body_line'][n][0] = self.allowed_data['body_line'][n][0].translate(transTable)
                    # end replacing or removing especial chars
                    
                    self.set_font("Helvetica", size=7)                    
                    self.multi_cell(40,2,self.allowed_data['body_line'][n][0], align="L")
                    self.set_font("Helvetica", size=8.5)
                    self.cell(45, -2, self.allowed_data['body_line'][n][1], align="R")
                    self.cell(13, -2, self.allowed_data['body_line'][n][2], align="R")
                    self.cell(14, -2, self.allowed_data['body_line'][n][3], align="R")
                    # check if exist codebar line
                    if len(self.allowed_data['body_line'][n])>4:
                        self.ln(2)
                        self.set_font("Helvetica", size=6.5)
                        self.cell(13, -2, self.allowed_data['body_line'][n][4],ln=0, align="L")
                    #
                    self.ln(2)
                    if self.get_y()>self.h-self.b_margin-10:
                        self.add_page()
            else:
                self.ln(2)
                for n in range(0,len(self.allowed_data['body_line'])):
                    self.set_font("Courier", size=8)                    
                    self.cell(65,2,self.allowed_data['body_line'][n], ln=1, align="L")
                    self.ln(1)
                    
            if len(self.allowed_data['footer_head'])>0:
                self.set_font("Helvetica", size=8)                    
                self.cell(65,3,self.allowed_data['footer_head'], ln=1, align="L")
                if self.get_y()>self.h-self.b_margin-10:
                    self.add_page()
                self.ln(2)
                
            if len(self.allowed_data['footer_line'])>0:
                for n in range(0,len(self.allowed_data['footer_line'])):
                    self.set_font("Helvetica", size=8)                    
                    self.cell(65,3,self.allowed_data['footer_line'][n], ln=1, align="L")
                    if self.get_y()>self.h-self.b_margin-10:
                        self.add_page()
                self.ln(2)
            # total
            if len(self.allowed_data['total'])>0:
                #self.set_font("Helvetica","B", size=8.5)
                try:
                    self.set_font('Courier New Bold Italic','',8.5)
                except Exception as e:
                    self.set_font('Courier','BI',8.5)
                self.cell(58,4,self.allowed_data['total'][0][0], border=1, ln=0, align="R")
                self.cell(14,4,self.allowed_data['total'][0][1], border=1, ln=0, align="R")
                self.ln(10)

            self.set_font("Helvetica", size=8) 
            for n in range(0,len(self.allowed_data['payment_line'])):
                self.cell(65,3,self.allowed_data['payment_line'][n], ln=1, align="L")
                if self.get_y()>self.h-self.b_margin-10:
                    self.add_page()
            self.ln(4)
            
            # Code39
            if len(self.allowed_data['order_code'])>0:
                if self.get_y()>self.h-self.b_margin-15:
                    self.add_page()
                self.code39(self.allowed_data['order_code'],15,self.get_y(),w=0.7,h=8)
                self.ln(15)
            # Terms
            if len(self.allowed_data['terms_of_sale'])>0:
                if self.get_y()>self.h-self.b_margin-10:
                    self.add_page()
                self.set_font('Arial','', 5)
                self.set_y(self.get_y())
                self.multi_cell( w=73, h=2, txt=self.allowed_data['terms_of_sale'], border = 0, align = 'J', fill = False, split_only=False)

        except Exception as e:
            tb = sys.exc_info()[2]
            LOG.error('<%s> in line %s !!!' % (str(e),tb.tb_lineno))
            
    
    # Page footer
    def footer(self):
        try:
            pass
        except Exception as e:
            tb = sys.exc_info()[2]
            LOG.error('<%s> in line %s !!!' % (str(e),tb.tb_lineno))
    
    def rotateText(self,x,y,txt,angle):
        #Text rotated around its origin
        try:
            self.rotate(angle,x,y)
            self.text(x,y,txt)
            self.rotate(0)
        except Exception as e:
            tb = sys.exc_info()[2]
            LOG.error('<%s> in line %s !!!' % (str(e),tb.tb_lineno))

    def rotateImage(self,file,x,y,w,h,angle):
        #Image rotated around its upper-left corner
        try:
            self.rotate(angle,x,y)
            self.image(file,x,y,w,h)
            self.rotate(0)
        except Exception as e:
            tb = sys.exc_info()[2]
            LOG.error('<%s> in line %s !!!' % (str(e),tb.tb_lineno))


    def rounded_rect(self,x, y, w, h, r,corners='1234',style=''):
        "Draw a rounded rectangle"
        try:
            if(style=='F'):
                op='f'
            elif(style=='FD' or style=='DF'):
                op='B'
            else:
                op='S'

            myArc = 4/3 * (math.sqrt(2) - 1);
            self._out(sprintf('%.2f %.2f m',(x+r)*self.k,(self.h-y)*self.k ))

            xc = x+w-r;
            yc = y+r;
            self._out(sprintf('%.2f %.2f l', xc*self.k,(self.h-y)*self.k ))
            if (corners.find('2') < 0):
                self._out(sprintf('%.2f %.2f l', (x+w)*self.k,(self.h-y)*self.k ))
            else:
                self._arc(xc + r*myArc, yc - r, xc + r, yc - r*myArc, xc + r, yc)

            xc = x+w-r;
            yc = y+h-r;
            self._out(sprintf('%.2f %.2f l',(x+w)*self.k,(self.h-yc)*self.k));
            if (corners.find('3') < 0):
                self._out(sprintf('%.2f %.2f l',(x+w)*self.k,(self.h-(y+h))*self.k));
            else:
                self._arc(xc + r, yc + r*myArc, xc + r*myArc, yc + r, xc, yc + r)

            xc = x+r;
            yc = y+h-r;
            self._out(sprintf('%.2f %.2f l',xc*self.k,(self.h-(y+h))*self.k));
            if (corners.find('4') < 0):
                self._out(sprintf('%.2f %.2f l',(x)*self.k,(self.h-(y+h))*self.k))
            else:
                self._arc(xc - r*myArc, yc + r, xc - r, yc + r*myArc, xc - r, yc)

            xc = x+r ;
            yc = y+r;
            self._out(sprintf('%.2f %.2f l',(x)*self.k,(self.h-yc)*self.k ))
            if (corners.find('1') < 0):
                self._out(sprintf('%.2f %.2f l',(x)*self.k,(self.hp-y)*self.k ))
                self._out(sprintf('%.2f %.2f l',(x+r)*self.k,(self.h-y)*self.k ))
            else:
                self._arc(xc - r, yc - r*myArc, xc - r*myArc, yc - r, xc, yc - r)
            self._out(op);
        except Exception as e:
            tb = sys.exc_info()[2]
            LOG.error('<%s> in line %s !!!' % (str(e),tb.tb_lineno))


    def _arc(self, x1, y1, x2, y2, x3, y3):
        try:
            h = self.h
            self._out(sprintf('%.2f %.2f %.2f %.2f %.2f %.2f c', x1*self.k, (h-y1)*self.k,
                x2*self.k, (h-y2)*self.k, x3*self.k, (h-y3)*self.k))
        except Exception as e:
            tb = sys.exc_info()[2]
            LOG.error('<%s> in line %s !!!' % (str(e),tb.tb_lineno))


    # EAN14 and UPC-A
    def EAN13(self, x, y, barcode_, h=16, w=.35):
        try:
            self.__barcode__(x,y,barcode_,h,w,13)
        except Exception as e:
            tb = sys.exc_info()[2]
            LOG.error('<%s> in line %s !!!' % (str(e),tb.tb_lineno))


    def UPC_A(self, x, y, barcode_, h=16, w=.35):
        try:
            self.__barcode__(x,y,barcode_,h,w,12)
        except Exception as e:
            tb = sys.exc_info()[2]
            LOG.error('<%s> in line %s !!!' % (str(e),tb.tb_lineno))


    def getCheckDigit(self, barcode_):
        # Compute the check digit
        try:
            sum=0
            for i in range(1,12,2):
                sum += 3*int(barcode_[i])
            for i in range(0,11,2):
                sum+=int(barcode_[i])
            r=sum%10
            if(r>0):
                r=10-r
            return str(r)
        except Exception as e:
            tb = sys.exc_info()[2]
            LOG.error('<%s> in line %s !!!' % (str(e),tb.tb_lineno))


    def testCheckDigit(self, barcode_):
        #Test validity of check digit
        try:
            sum=0
            for i in range(1,12,2):
                sum += 3*int(barcode_[i])
            for i in range(0,11,2):
                sum += int(barcode_[i])
            return (sum+int(barcode_[-1:]))%10==0
        except Exception as e:
            tb = sys.exc_info()[2]
            LOG.error('<%s> in line %s !!!' % (str(e),tb.tb_lineno))


    def __barcode__(self, x, y, barcode_, h, w, lng):
        try:
            # Padding
            barcode_=barcode_.rjust(lng-1,'0')
            if lng==12:
                barcode_ = '0' + barcode_
            # Add or control the check digit
            if len(barcode_) == 12:
                barcode_ += self.getCheckDigit(barcode_)
            elif not self.testCheckDigit(barcode_):
                self.error('Incorrect check digit')
            #Convert digits to bars
            codes={
                'A':{
                    '0':'0001101','1':'0011001','2':'0010011','3':'0111101','4':'0100011',
                    '5':'0110001','6':'0101111','7':'0111011','8':'0110111','9':'0001011'},
                'B':{
                    '0':'0100111','1':'0110011','2':'0011011','3':'0100001','4':'0011101',
                    '5':'0111001','6':'0000101','7':'0010001','8':'0001001','9':'0010111'},
                'C':{
                    '0':'1110010','1':'1100110','2':'1101100','3':'1000010','4':'1011100',
                    '5':'1001110','6':'1010000','7':'1000100','8':'1001000','9':'1110100'}
                }
            parities={
                '0':['A','A','A','A','A','A'],
                '1':['A','A','B','A','B','B'],
                '2':['A','A','B','B','A','B'],
                '3':['A','A','B','B','B','A'],
                '4':['A','B','A','A','B','B'],
                '5':['A','B','B','A','A','B'],
                '6':['A','B','B','B','A','A'],
                '7':['A','B','A','B','A','B'],
                '8':['A','B','A','B','B','A'],
                '9':['A','B','B','A','B','A']
                }
            code_='101';
            p=parities[barcode_[0]]
            for i in range(1,7):
                code_ +=codes[p[i-1]][barcode_[i]]
            code_ +='01010'
            for i in range(7,13):
                code_ +=codes['C'][barcode_[i]]
            code_ +='101'
            #Draw bars
            for i in range(0,len(code_)):
                if code_[i]=='1':
                    self.rect(x+i*w,y,w,h,'F')
            #Print text uder barcode
            self.set_font('Arial','',12);
            self.text(x,y+h+11/self.k,barcode_[-lng:])
        except Exception as e:
            tb = sys.exc_info()[2]
            LOG.error('<%s> in line %s !!!' % (str(e),tb.tb_lineno))





            

CHARACTER_CODE_TABLE = 'CP858'

class Simple_Order_ESC():
    '''Print trade orders like tickets on 56 (FONT B) cols. paper (default)'''

    def __init__(self,*args,**kwargs):
        pass

    def config(self,*args,**kwargs):
        ''' * logo          text  imagen logotipo
            * letterhead    list  membrete
            * client        list  datos de cliente
            * title         text  tipo de documento
            * title_head    list  titulo columnas
            * title_line    list  datos de documento
            * body_head     list  titulo columnas
              body_line     dict  lineas detalle
            * footer_head   list  titulos pie
              footer_line   dict  lineas pie
            * payment_line  list  lineas de pagos
            * order_code    text  order_code
            * terms_of_sale text  Condiciones
        '''
        try:
            if sys.platform[:-2] == 'win':
                ALL_PRINTERS = [printer[2] for printer in win32print.EnumPrinters(2)]
            else:
                ALL_PRINTERS = []
            self.printer_name = win32print.GetDefaultPrinter()
            if 'printer_name' in list(kwargs.keys()) and kwargs['printer_name'].upper() in ALL_PRINTERS:
                self.printer_name = kwargs['printer_name'].upper()

            if sys.platform[:-2] == 'win':
                win32print.SetDefaultPrinter(self.printer_name)
            
            self.allowed_data = {'logo':'','letterhead':list(),'client':list(),'title':'','title_head':list(),'title_line':list(),'body_head':'','body_line':list(),'footer_head':'','footer_line':list(),'total':list(),'terms_of_sale':'','authorization':'','order_code':'','payment_line':(),'cut':None,'cash_drawer':None}
            for n in list(kwargs.keys()):
                if n in self.allowed_data:
                    self.allowed_data[n] = kwargs[n]

            # Logo
            if self.allowed_data['logo'] is not None:
                #self.esc_pos_image(img_name=self.allowed_data['logo'])
                pass

            self.width = 56    # Font type B (56 CHARS)  A (43 CHARS)

            if sys.platform[:-2] == 'win':    
                self.hPrinter = win32print.OpenPrinter(self.printer_name)
                
                try:
                    LOG.debug(self.allowed_data['title_line'][0])
                    hJob = win32print.StartDocPrinter(self.hPrinter, 1, (self.allowed_data['title_line'][0], None, "RAW"))    # title on spooler
                    try:
                        win32print.StartPagePrinter(self.hPrinter)
                        win32print.WritePrinter (self.hPrinter,HW_RESET)
                        win32print.WritePrinter (self.hPrinter,HW_INIT)     # Clear data in buffer and reset modes

                        # print memory printer logo
                        win32print.WritePrinter (self.hPrinter,b'\x1c\x70\x01\x00')

                        win32print.WritePrinter (self.hPrinter,CODEPAGE_CHANGE + b'\x13')   # CODEPAGE CHARACTER_CODE_TABLE  Page 13 Latin-9 [ISO8859-15]
                        win32print.WritePrinter (self.hPrinter,LINESPACING_RESET)
                        win32print.WritePrinter (self.hPrinter, SHEET_ROLL_MODE)
                        self.form = ""
                        self.header()
                        
                        if len(self.allowed_data['order_code'])>0:
                            self.esc_pos_code39()
                            
                        win32print.WritePrinter (self.hPrinter, TXT_NORMAL+b'\x0a'*5)
                        win32print.EndPagePrinter(self.hPrinter)
                        
                        if 'cut' in self.allowed_data and self.allowed_data['cut'] is not None:
                            self.esc_pos_cut(cut=self.allowed_data['cut'])
                        else:
                            self.esc_pos_cut(cut=self.allowed_data['cut'])
                            
                        if 'cash_drawer' in self.allowed_data and self.allowed_data['cash_drawer'] is not None:
                            self.esc_pos_cash_drawer()
                        else:
                            self.esc_pos_cash_drawer()
                            
                    finally:
                        win32print.EndDocPrinter(self.hPrinter)
                finally:
                    win32print.ClosePrinter(self.hPrinter)
            
        except Exception as e:
            tb = sys.exc_info()[2]
            LOG.error('<%s> in line %s !!!' % (str(e),tb.tb_lineno))


    def header(self):
        try:
            # configurar documento
            
            # letterhead
            if len(self.allowed_data['letterhead'])>0:
                _txt = bytes(self.allowed_data['letterhead'][0],CHARACTER_CODE_TABLE)
                win32print.WritePrinter(self.hPrinter,TXT_STYLE['bold'][True]+TXT_STYLE['size']['2h'])
                win32print.WritePrinter(self.hPrinter,TXT_STYLE['align']['center'] + _txt + CTL_LF + CTL_CR )
                win32print.WritePrinter(self.hPrinter,TXT_STYLE['bold'][False]+TXT_STYLE['size']['normal'])
                for n in range(1,len(self.allowed_data['letterhead'])-1):
                    _txt = bytes(self.allowed_data['letterhead'][n],CHARACTER_CODE_TABLE)
                    win32print.WritePrinter (self.hPrinter,TXT_STYLE['align']['center'][:56].strip() + _txt + CTL_LF + CTL_CR)
            win32print.WritePrinter (self.hPrinter,TXT_STYLE['align']['left'])
            win32print.WritePrinter (self.hPrinter,TXT_FONT_B)                           # Font type B (56 CHARS)  A (43 CHARS)
            
            win32print.WritePrinter (self.hPrinter, b'\xc4'*56 + CTL_LF + CTL_CR)
            # client
            if len(self.allowed_data['client'])>0:
                for n in range(0,len(self.allowed_data['client'])):
                    
                    # special characters can cause errors in ticket printers, replacing or removing is the only solution
                    removeChars = "!#$%^"    # special chars 
                    # maketrans(chars to replace,chars replaced, chars to remove)
                    transTable = self.allowed_data['client'][n].maketrans("ÁÉÍÓÚ", "AEIOU", removeChars)
                    self.allowed_data['client'][n] = self.allowed_data['client'][n].translate(transTable)
                    # end replacing or removing especial chars
                    
                    _txt = bytes(self.allowed_data['client'][n],CHARACTER_CODE_TABLE)
                    win32print.WritePrinter (self.hPrinter,TXT_STYLE['align']['center'] + _txt + CTL_LF + CTL_CR)
                win32print.WritePrinter (self.hPrinter, b'\xc4'*56 + CTL_LF + CTL_CR)    
            # title order lines
            if len(self.allowed_data['title_line'])>0:
                for n in range(0,len(self.allowed_data['title_line'])):
                    _txt = bytes(self.allowed_data['title_line'][n].ljust(self.width),CHARACTER_CODE_TABLE)
                    win32print.WritePrinter (self.hPrinter,TXT_STYLE['align']['center'] + _txt + CTL_LF + CTL_CR)
                win32print.WritePrinter (self.hPrinter, b'\xc4'*56 + CTL_LF + CTL_CR)
            win32print.WritePrinter (self.hPrinter,LINESPACING_RESET)

            self.body_lines()
            self.footer()
          
        except Exception as e:
            tb = sys.exc_info()[2]
            LOG.error('<%s> in line %s !!!' % (str(e),tb.tb_lineno))

    def body_lines(self):
        '''print items line'''
        try:
            # body head
            win32print.WritePrinter (self.hPrinter,LINESPACING_FUNCS[180]+b' ')          # line_spacing/180
            if len(self.allowed_data['body_line'])>0 and len(self.allowed_data['order_code'])>0 and len(self.allowed_data['body_head'])>0:
                #HEADER TEXT
                _txt = bytes(f"""{self.allowed_data['body_head']}""",CHARACTER_CODE_TABLE)
                win32print.WritePrinter (self.hPrinter,TXT_STYLE['align']['left'])       # Left
                win32print.WritePrinter (self.hPrinter,b'\xdA'+b'\xc4'*54+b'\xbF' + CTL_LF + CTL_CR)
                win32print.WritePrinter (self.hPrinter,b'\xb3'+_txt+b'\xb3' + CTL_LF + CTL_CR )
                win32print.WritePrinter (self.hPrinter,b'\xc0'+b'\xc4'*54+b'\xd9' + CTL_LF + CTL_CR)
            win32print.WritePrinter (self.hPrinter,LINESPACING_RESET)
            
            # body lines
            if len(self.allowed_data['body_line'])>0 and len(self.allowed_data['order_code'])>0:
                win32print.WritePrinter (self.hPrinter,LINESPACING_FUNCS[60])            # line_spacing/60
                win32print.WritePrinter (self.hPrinter,TXT_STYLE['align']['left'])       # Left
                for n in range(0,len(self.allowed_data['body_line'])):
                    
                    # special characters can cause errors in ticket printers, replacing or removing is the only solution
                    removeChars = "!#$%^&()\\n"    # special chars 
                    # maketrans(chars to replace,chars replaced, chars to remove)
                    transTable = self.allowed_data['body_line'][n][0].maketrans("ÁÉÍÓÚ", "AEIOU", removeChars)
                    self.allowed_data['body_line'][n][0] = self.allowed_data['body_line'][n][0].translate(transTable)
                    # end replacing or removing especial chars
                    
                    _txt = bytes(f"""{self.allowed_data['body_line'][n][0][0:33]:<34}{self.allowed_data['body_line'][n][1]:>5}{self.allowed_data['body_line'][n][2]:>7}{self.allowed_data['body_line'][n][3]:>9}""",CHARACTER_CODE_TABLE)
                    win32print.WritePrinter (self.hPrinter, _txt + CTL_LF + CTL_CR )
                    # check if exist codebar line
                    if len(self.allowed_data['body_line'][n])>4:
                        _txt = bytes(f"""{self.allowed_data['body_line'][n][4][0:13]:<13}""",CHARACTER_CODE_TABLE)
                        win32print.WritePrinter (self.hPrinter, _txt + CTL_LF + CTL_CR )
                    #
                win32print.WritePrinter (self.hPrinter, b'\xc4'*56 + CTL_LF + CTL_CR)
            else:
                win32print.WritePrinter (self.hPrinter,LINESPACING_FUNCS[60])            # line_spacing/60
                win32print.WritePrinter (self.hPrinter,TXT_STYLE['align']['left'])       # Left
                for n in range(0,len(self.allowed_data['body_line'])):
                    _txt = bytes(f"""{self.allowed_data['body_line'][n][:56]}""",CHARACTER_CODE_TABLE)
                    win32print.WritePrinter (self.hPrinter, _txt + CTL_LF + CTL_CR )
            win32print.WritePrinter (self.hPrinter,LINESPACING_RESET)
                 
        except Exception as e:
            tb = sys.exc_info()[2]
            LOG.error('<%s> in line %s !!!' % (str(e),tb.tb_lineno))
            
    
    # Page footer
    def footer(self):
        try:
            if len(self.allowed_data['footer_head'])>0:
                win32print.WritePrinter (self.hPrinter,LINESPACING_FUNCS[180]+b' ')      # line_spacing/180
                win32print.WritePrinter (self.hPrinter,TXT_STYLE['align']['left'])       # Left
                #TAX LIST
                _txt = bytes(f'''{self.allowed_data['footer_head']}''',CHARACTER_CODE_TABLE)
                #_txt = bytes('{0:>8s} {1:>5s}% {2:>9s} {3:>5s}%{4:>8s}    {5:>9s}'.format('BASE.IMP.','IVA','TOT.IVA','RE','TOT.RE','TOTAL'),CHARACTER_CODE_TABLE)

                win32print.WritePrinter (self.hPrinter,b'\xdA'+b'\xc4'*54 + b'\xbf' + CTL_LF + CTL_CR)
                win32print.WritePrinter (self.hPrinter,b'\xb3'+_txt + b'\xb3' + CTL_LF + CTL_CR)
                win32print.WritePrinter (self.hPrinter,b'\xc0' + b'\xc4'*54 + b'\xd9' + CTL_LF + CTL_CR)
                win32print.WritePrinter (self.hPrinter,LINESPACING_RESET)

            if len(self.allowed_data['footer_line'])>0:
                # footer lines
                win32print.WritePrinter (self.hPrinter,LINESPACING_FUNCS[60])        # line_spacing/60
                
                for n in range(0,len(self.allowed_data['footer_line'])):
                    _txt = []
                    for m in range(0,len(self.allowed_data['footer_line'][n])):
                        _txt.append(f''' {self.allowed_data['footer_line'][n][m]}''')
                    win32print.WritePrinter (self.hPrinter, bytes(''.join(_txt),CHARACTER_CODE_TABLE) + CTL_LF + CTL_CR)
                #text_linea_footer = bytes('{0:>9.2f} {1:>5.2f}% {2:>9.2f} {3:>5.2f}%{4:>8.2f}    {5:>10.2f}\n\r'.format(127,21.0,round(127*21/100,2),3.0,round(127*3/100,2),127+round(127*21/100,2)+round(127*3/100,2)),CHARACTER_CODE_TABLE)

            # total
            win32print.WritePrinter (self.hPrinter,TXT_FONT_B)                       # Font type B (56 CHARS)  A (43 CHARS)
            win32print.WritePrinter (self.hPrinter,LINESPACING_FUNCS[60])            # line_spacing/60
            if len(self.allowed_data['total'])>0:
                win32print.WritePrinter (self.hPrinter,TXT_FONT_A)                   # Font type A (43 CHARS) B (56 CHARS)
                for n in range(0,len(self.allowed_data['total'])):
                    _txt = bytes(f"""{self.allowed_data['total'][n][0]:>28}{self.allowed_data['total'][n][1]:>10}""",CHARACTER_CODE_TABLE)
                    win32print.WritePrinter (self.hPrinter,TXT_STYLE['bold'][True] + _txt + CODEPAGE_CHANGE + b'\x10'+ CURRENCY['euro'] + CODEPAGE_CHANGE + b'\x00' + TXT_STYLE['bold'][False] + CTL_LF + CTL_CR)

            win32print.WritePrinter (self.hPrinter,TXT_FONT_B)                       # Font type B (56 CHARS)  A (43 CHARS)
            win32print.WritePrinter (self.hPrinter,LINESPACING_FUNCS[60])            # line_spacing/60 
            for n in range(0,len(self.allowed_data['payment_line'])):
                _txt = bytes(self.allowed_data['payment_line'][n],CHARACTER_CODE_TABLE)
                win32print.WritePrinter (self.hPrinter, _txt + CTL_LF + CTL_CR )
            win32print.WritePrinter (self.hPrinter, CTL_LF + CTL_CR )

            # Terms
            #LOG.debug(f'''self.allowed_data {self.allowed_data['terms_of_sale']}''')
            #LOG.debug(f'''self.allowed_data {self.chunk_string(self.allowed_data['terms_of_sale'],self.width)}''')
            terms_list = self.chunk_string(self.allowed_data['terms_of_sale'],self.width)
            for n in terms_list:
                _txt = bytes(n,CHARACTER_CODE_TABLE)
                win32print.WritePrinter (self.hPrinter, _txt + CTL_LF + CTL_CR)
            win32print.WritePrinter (self.hPrinter,LINESPACING_RESET)
        except Exception as e:
            tb = sys.exc_info()[2]
            LOG.error('<%s> in line %s !!!' % (str(e),tb.tb_lineno))            

    def esc_pos_image(self, img_name=None,magnify=200): 
        try:
            if self.printer_name is None:
                self.printer_name = win32print.GetDefaultPrinter()
            else:
                win32print.SetDefaultPrinter(self.printer_name)
            hDC = win32ui.CreateDC()
            hDC.CreatePrinterDC(self.printer_name)

            bmp = Image.open(img_name)
            width_pixels, height_pixels = bmp.size
            factor = float(magnify / width_pixels)
            size = int(factor * width_pixels), int(factor * height_pixels)
            bmp = bmp.resize(size, Image.ANTIALIAS)

            bmp = ImageOps.grayscale(bmp)
            # Pure black and white
            bmp = bmp.convert("1")
            #bmp = bmp.transpose(Image.FLIP_TOP_BOTTOM)
            #bmp.show()
            try:
                hDC.StartDoc(img_name)    # title on spooler
                try:
                    hDC.StartPage()
                    dibuja = ImageWin.Dib(bmp)
                    dibuja.draw(hDC.GetHandleOutput(),(0,0,int(factor*width_pixels),int(factor*height_pixels)))
                finally:
                    hDC.EndPage()
            finally:
                hDC.EndDoc()
        except Exception as e:
            tb = sys.exc_info()[2]
            LOG.error('<%s> in line %s !!!' % (str(e),tb.tb_lineno))

    def esc_pos_code39(self): 
        try:
            # CODE39
            _txt = bytes('*'+self.allowed_data['order_code']+'*',CHARACTER_CODE_TABLE)
            win32print.WritePrinter (self.hPrinter,BARCODE_TXT_ABV+BARCODE_HEIGHT+b'0'+BARCODE_WIDTH+b'1'+BARCODE_TYPE_A['CODE39']+_txt)
        except Exception as e:
            tb = sys.exc_info()[2]
            LOG.error('<%s> in line %s !!!' % (str(e),tb.tb_lineno))

    def esc_pos_cut(self, cut='FULL'): 
        try:
            if cut == 'FULL':
                win32print.WritePrinter (self.hPrinter,PAPER_FULL_CUT)
            else:
                win32print.WritePrinter (self.hPrinter,PAPER_PART_CUT)
        except Exception as e:
            tb = sys.exc_info()[2]
            LOG.error('<%s> in line %s !!!' % (str(e),tb.tb_lineno))

    def esc_pos_cash_drawer(self): 
        try:
            win32print.WritePrinter (self.hPrinter,CD_KICK_2)
            win32print.WritePrinter (self.hPrinter,CD_KICK_5)
        except Exception as e:
            tb = sys.exc_info()[2]
            LOG.error('<%s> in line %s !!!' % (str(e),tb.tb_lineno))

    def chunk_string(self, text, length):
        try:
            words = iter(text.split())
            lines, current = [], next(words)
            for word in words:
                if len(current) + 1 + len(word) > length:
                    lines.append(current)
                    current = word
                else:
                    current += " " + word
            lines.append(current)
            return lines
        except Exception as e:
            tb = sys.exc_info()[2]
            LOG.error('<%s> in line %s !!!' % (str(e),tb.tb_lineno))
            
class Tag(FPDF):
    """ Print tag for store with image and more data
       @parameters on dict with keys:
       logo          text  image logo
       dealer        text  dealer name
       provider      list  provider data [provider code, item number]
       sku           text  sku of product
       name          text  name of product
       EAN13         text  codebar of product
       rate          list  rate of product

       @return file.pdf

       @example: label_list (list) with sku codes of products or codebars.
        if len(label_list)>0:
            pdf = Tag(orientation='P',unit='mm',format='A4')
            pdf.alias_nb_pages()
            pdf.set_line_width(width=0.1)
            pdf.set_compression(compress=2)
            pdf.set_margins(9,1,-5)
            p = list()
            bd = mainSQLite()
            for n in range(0,len(label_list)):
                if len(label_list[n])>0:
                    g = dict()
                    g['logo'] = image_path+'logo.png'
                    g['img'] = image_path+regs[0]+'.jpg'
                    g['dealer'] = dealer_name
                    g['sku'] = regs[0]
                    g['provider'] = [regs[2].lstrip('0'),regs[3].replace('None','')]
                    g['name'] = regs[1]
                    if len(regs[5])>0:
                        g['EAN13'] = regs[5][1:-1]
                    else:
                        g['EAN13'] = '9990000'+regs[0]
                    g['rate'] = [(('%.4f' % regs[4]).rstrip('0').rstrip('.')).replace('.',','),'EUR.']
                    p.append(g)

            pdf.config(p)
            pdf.output("labelpdf.pdf","F")
    """

    def config(self,*args,**kwargs):
        try:
            self.allowed_data = {'logo':'','img':'','dealer':'','sku':'','provider':list(),'EAN13':'','name':'','rate':list()}
            self.tags = list()
            for n in args[0]:      # list of data label
                _tag = copy.deepcopy(self.allowed_data)
                for m in self.allowed_data.keys():
                    _tag[m] = n[m]
                self.tags.append(_tag)
            self.add_page()       # parent function
            self.body_page()
        except Exception as e:
            if hasattr(e, 'message'):
                LOG.error('<%s> in line %s !!!' % (e.message,format(sys.exc_info()[-1].tb_lineno)))
            else:
                LOG.error('<%s> in line %s !!!' % (e,format(sys.exc_info()[-1].tb_lineno)))

    def body_page(self):

        try:

            self.tag = dict()
            self.tag_list = list()
            for m in range(len(self.tags)):
                self.tag = dict()
                for n in list(self.tags[m].keys()):
                    if n in self.allowed_data:
                        self.tag[n] = self.tags[m][n]

                self.tag_list.append(self.tag)

            nY = 16
            np = 0
            for m in range(len(self.tag_list)):
                # comprobar salto de pagina
                if nY+10 > 300:
                    self.add_page()       # parent function
                    nY = 16
                    np = 0                
                # Arial bold 15
                self.set_font('Arial', '', 6)
                # Logo
                if os.path.isfile(self.tag_list[m]['logo']):
                    self.image(self.tag_list[m]['logo'], 10, nY-7, 10)
                # legalname
                self.set_font('Arial','B',8)
                self.text(33, nY-7, ' '.join([self.tag_list[m]['dealer'],date.today().strftime("%d/%m/%Y")]))

                # SKU
                self.set_font('Arial','B',24)
                self.text(150, nY-2, self.tag_list[m]['sku'])
                
                if os.path.isfile(self.tag_list[m]['img']):
                    self.image(self.tag_list[m]['img'], x=20, y=nY+2, h=40, type='jpg')

                # Codebar
                if len(self.tag_list[m]['EAN13'])>0:
                    self.EAN13(33,nY-4,self.tag_list[m]['EAN13'],h=4)

                # Product name
                if len(self.tag_list[m]['name'])>24:
                    self.set_font('Arial','',24)
                    self.text(70, nY+14, self.tag_list[m]['name'][0:24])
                    self.text(70, nY+24, self.tag_list[m]['name'][25:48])
                else:
                    self.set_font('Arial','',24)
                    self.text(70, nY+14, self.tag_list[m]['name'])

                # Rate
                self.set_font('Arial','B',28)
                self.text(120, nY+43, ' '.join(self.tag_list[m]['rate']))

                # Provider and Item number
                self.set_font('Arial','B',20)
                self.text(70, nY+43, ' '.join(self.tag_list[m]['provider']))

                nY += 56
                np += 1
                '''
                if np == 5:
                    self.add_page()
                    nY = 16
                    np = 0
                '''    
        except Exception as e:
            if hasattr(e, 'message'):
                LOG.error('<%s> in line %s !!!' % (e.message,format(sys.exc_info()[-1].tb_lineno)))
            else:
                LOG.error('<%s> in line %s !!!' % (e,format(sys.exc_info()[-1].tb_lineno)))

    def header(self):

        try:

            # lineas
            self.set_line_width(width=0.1)
            self.line(11,6,204,6)
            self.line(11,62,204,62)
            self.line(11,118,204,118)
            self.line(11,174,204,174)
            self.line(11,230,204,230)
            self.line(11,286,204,286)
             # textos
            self.set_font('Courier','',8);
            # configurar documento
            self.set_creator('pymetrick')

            # Line break
            self.ln(20)
        except Exception as e:
            if hasattr(e, 'message'):
                LOG.error('<%s> in line %s !!!' % (e.message,format(sys.exc_info()[-1].tb_lineno)))
            else:
                LOG.error('<%s> in line %s !!!' % (e,format(sys.exc_info()[-1].tb_lineno)))

    # Page footer
    def footer(self):
        # Position at 1.5 cm from bottom
        pass

    def rotateText(self,x,y,txt,angle):
        #Text rotated around its origin
        self.rotate(angle,x,y)
        self.text(x,y,txt)
        self.rotate(0)

    def rotateImage(self,file,x,y,w,h,angle):
        #Image rotated around its upper-left corner
        self.rotate(angle,x,y)
        self.image(file,x,y,w,h)
        self.rotate(0)

    def rounded_rect(self,x, y, w, h, r,corners='1234',style=''):
        "Draw a rounded rectangle"

        try:
            if(style=='F'):
                op='f'
            elif(style=='FD' or style=='DF'):
                op='B'
            else:
                op='S'

            myArc = 4/3 * (math.sqrt(2) - 1);
            self._out(sprintf('%.2f %.2f m',(x+r)*self.k,(self.h-y)*self.k ))

            xc = x+w-r;
            yc = y+r;
            self._out(sprintf('%.2f %.2f l', xc*self.k,(self.h-y)*self.k ))
            if (corners.find('2') < 0):
                self._out(sprintf('%.2f %.2f l', (x+w)*self.k,(self.h-y)*self.k ))
            else:
                self._arc(xc + r*myArc, yc - r, xc + r, yc - r*myArc, xc + r, yc)

            xc = x+w-r;
            yc = y+h-r;
            self._out(sprintf('%.2f %.2f l',(x+w)*self.k,(self.h-yc)*self.k));
            if (corners.find('3') < 0):
                self._out(sprintf('%.2f %.2f l',(x+w)*self.k,(self.h-(y+h))*self.k));
            else:
                self._arc(xc + r, yc + r*myArc, xc + r*myArc, yc + r, xc, yc + r)

            xc = x+r;
            yc = y+h-r;
            self._out(sprintf('%.2f %.2f l',xc*self.k,(self.h-(y+h))*self.k));
            if (corners.find('4') < 0):
                self._out(sprintf('%.2f %.2f l',(x)*self.k,(self.h-(y+h))*self.k))
            else:
                self._arc(xc - r*myArc, yc + r, xc - r, yc + r*myArc, xc - r, yc)

            xc = x+r ;
            yc = y+r;
            self._out(sprintf('%.2f %.2f l',(x)*self.k,(self.h-yc)*self.k ))
            if (corners.find('1') < 0):
                self._out(sprintf('%.2f %.2f l',(x)*self.k,(self.hp-y)*self.k ))
                self._out(sprintf('%.2f %.2f l',(x+r)*self.k,(self.h-y)*self.k ))
            else:
                self._arc(xc - r, yc - r*myArc, xc - r*myArc, yc - r, xc, yc - r)
            self._out(op);

        except Exception as e:
            if hasattr(e, 'message'):
                LOG.error('<%s> in line %s !!!' % (e.message,format(sys.exc_info()[-1].tb_lineno)))
            else:
                LOG.error('<%s> in line %s !!!' % (e,format(sys.exc_info()[-1].tb_lineno)))

    def _arc(self, x1, y1, x2, y2, x3, y3):
        h = self.h
        self._out(sprintf('%.2f %.2f %.2f %.2f %.2f %.2f c', x1*self.k, (h-y1)*self.k,
            x2*self.k, (h-y2)*self.k, x3*self.k, (h-y3)*self.k))

    # EAN14 and UPC-A
    def EAN13(self, x, y, barcode_, h=16, w=.35):
        self.__barcode__(x,y,barcode_,h,w,13)

    def UPC_A(self, x, y, barcode_, h=16, w=.35):
        self.__barcode__(x,y,barcode_,h,w,12)

    def getCheckDigit(self, barcode_):
        # Compute the check digit
        try:

            sum=0
            for i in range(1,12,2):
                sum += 3*int(barcode_[i])
            for i in range(0,11,2):
                sum+=int(barcode_[i])
            r=sum%10
            if(r>0):
                r=10-r
            return str(r)
        except Exception as e:
            if hasattr(e, 'message'):
                LOG.error('<%s> in line %s !!!' % (e.message,format(sys.exc_info()[-1].tb_lineno)))
            else:
                LOG.error('<%s> in line %s !!!' % (e,format(sys.exc_info()[-1].tb_lineno)))

    def testCheckDigit(self, barcode_):
        #Test validity of check digit
        try:
            sum=0
            for i in range(1,12,2):
                sum += 3*int(barcode_[i])
            for i in range(0,11,2):
                sum += int(barcode_[i])
            return (sum+int(barcode_[-1:]))%10==0
        except Exception as e:
            if hasattr(e, 'message'):
                LOG.error('<%s> in line %s !!!' % (e.message,format(sys.exc_info()[-1].tb_lineno)))
            else:
                LOG.error('<%s> in line %s !!!' % (e,format(sys.exc_info()[-1].tb_lineno)))

    def __barcode__(self, x, y, barcode_, h, w, lng):

        try:
            # Padding
            barcode_=barcode_.rjust(lng-1,'0')
            if lng==12:
                barcode_ = '0' + barcode_
            # Add or control the check digit
            if len(barcode_) == 12:
                barcode_ += self.getCheckDigit(barcode_)
            elif not self.testCheckDigit(barcode_):
                self.error('Incorrect check digit')
            #Convert digits to bars
            codes={
                'A':{
                    '0':'0001101','1':'0011001','2':'0010011','3':'0111101','4':'0100011',
                    '5':'0110001','6':'0101111','7':'0111011','8':'0110111','9':'0001011'},
                'B':{
                    '0':'0100111','1':'0110011','2':'0011011','3':'0100001','4':'0011101',
                    '5':'0111001','6':'0000101','7':'0010001','8':'0001001','9':'0010111'},
                'C':{
                    '0':'1110010','1':'1100110','2':'1101100','3':'1000010','4':'1011100',
                    '5':'1001110','6':'1010000','7':'1000100','8':'1001000','9':'1110100'}
                }
            parities={
                '0':['A','A','A','A','A','A'],
                '1':['A','A','B','A','B','B'],
                '2':['A','A','B','B','A','B'],
                '3':['A','A','B','B','B','A'],
                '4':['A','B','A','A','B','B'],
                '5':['A','B','B','A','A','B'],
                '6':['A','B','B','B','A','A'],
                '7':['A','B','A','B','A','B'],
                '8':['A','B','A','B','B','A'],
                '9':['A','B','B','A','B','A']
                }
            code_='101';
            p=parities[barcode_[0]]
            for i in range(1,7):
                code_ +=codes[p[i-1]][barcode_[i]]
            code_ +='01010'
            for i in range(7,13):
                code_ +=codes['C'][barcode_[i]]
            code_ +='101'
            #Draw bars
            for i in range(0,len(code_)):
                if code_[i]=='1':
                    self.rect(x+i*w,y,w,h,'F')
            #Print text uder barcode
            self.set_font('Arial','',12);
            self.text(x,y+h+11/self.k,barcode_[-lng:])
        except Exception as e:
            if hasattr(e, 'message'):
                LOG.error('<%s> in line %s !!!' % (e.message,format(sys.exc_info()[-1].tb_lineno)))
            else:
                LOG.error('<%s> in line %s !!!' % (e,format(sys.exc_info()[-1].tb_lineno)))

class PolyTag(FPDF):
    """ Print tag for store with more than one label on tag
       @parameters on list of dicts with keys:
       logo          text  image logo
       dealer        text  dealer name
       provider      list  provider data [provider code, item number]
       sku           text  sku of product
       name          text  name of product
       EAN13         text  codebar of product
       rate          list  rate of product

       @return file.pdf

       @example: label_list (list) with sku codes of products or codebars.
        if len(label_list)>0:
            pdf = Tag(orientation='P',unit='mm',format='A4')
            pdf.alias_nb_pages()
            pdf.set_line_width(width=0.1)
            pdf.set_compression(compress=2)
            pdf.set_margins(9,1,-5)
            p = list()
            bd = mainSQLite()
            for n in range(0,len(label_list)):
                if len(label_list[n])>0:
                    g = dict()
                    g['logo'] = image_path+'logo.png'
                    g['img'] = image_path+regs[0]+'.jpg'
                    g['dealer'] = dealer_name
                    g['sku'] = regs[0]
                    g['provider'] = [regs[2].lstrip('0'),regs[3].replace('None','')]
                    g['name'] = regs[1]
                    if len(regs[5])>0:
                        g['EAN13'] = regs[5][1:-1]
                    else:
                        g['EAN13'] = '9990000'+regs[0]
                    g['rate'] = [(('%.4f' % regs[4]).rstrip('0').rstrip('.')).replace('.',','),'EUR.']
                    p.append(g)

            pdf.config(p)
            pdf.output("labelpdf.pdf","F")
    """

    def config(self,*args,**kwargs):
        try:
            self.allowed_data = {'logo':'','dealer':'','sku':'','provider':list(),'EAN13':'','name':'','rate':list(), 'img':''}
            self.tags = list()
            for o in args[0]:      # list of tag of label(dict)
                _poly_tags = []
                for n in o:        # list of dict
                    _tag = copy.deepcopy(self.allowed_data)
                    
                    for m in self.allowed_data.keys():  # load dict label
                        _tag[m] = n[m]
                    _poly_tags.append(_tag)  # polytag
                self.tags.append(_poly_tags)  # list of polytags
            self.add_page()       # parent function
            self.body_page()
        except Exception as e:
            if hasattr(e, 'message'):
                LOG.error('<%s> in line %s !!!' % (e.message,format(sys.exc_info()[-1].tb_lineno)))
            else:
                LOG.error('<%s> in line %s !!!' % (e,format(sys.exc_info()[-1].tb_lineno)))

    def body_page(self):

        try:
            nY = 16
            np = 0
            self.tag = dict()
            self.tag_list = list()
            for l in self.tags:  # list of list of polytags
                # comprobar salto de pagina
                if nY+(15*len(l))+10 > 300:
                    self.add_page()       # parent function
                    nY = 16
                    np = 0
                # Arial bold 15
                self.set_font('Arial', '', 6)
                # Logo
                if os.path.isfile(l[0]['logo']):
                    self.image(l[0]['logo'], 10, nY-10, 5)
                # legalname
                self.set_font('Arial','B',5)
                self.text(15, nY-7, l[0]['dealer'])

                if len(l)>0:
                    if 'img' in l[0]:
                        if os.path.isfile(l[0]['img']):
                            self.image(l[0]['img'], x=90, y=nY-10, h=24, type='jpg')
                    
                for m in range(len(l)):  # list of polytags


                    self.tag = dict()            
                    for n in list(l[m].keys()):  # tag
                        if n in self.allowed_data:
                            self.tag[n] = l[m][n]
                    # print
                    # Provider and Item number
                    self.set_font('Arial','',8)
                    self.text(60, nY-3, ' '.join(self.tag['provider']))
                    
                    # SKU
                    self.set_font('Arial','B',8)
                    self.text(10, nY, self.tag['sku'])
                    # Codebar
                    if len(self.tag['EAN13'])>0:
                        self.EAN13(20,nY-4,self.tag['EAN13'],h=4)

                    # Rate
                    self.set_font('Arial','B',16)
                    self.text(57, nY+2, ' '.join(self.tag['rate']))
                    self.set_font('Arial','',6)
                    self.text(60, nY+4, 'IVA INCLUIDO')
                    # Product name
                    self.set_font('Arial','B',10)
                    line = []
                    y_line = 7
                    for s in self.tag['name'].strip():
                        if len(s.strip()) == 0 and len(line)>30:
                            self.text(10, nY+y_line, ''.join(line))
                            line = []
                            y_line += 3
                        else:
                            line.append(s)
                    if len(line)>0:
                        self.text(10, nY+y_line, ''.join(line))
                    #self.text(10, nY+8, self.tag['name'].strip()[:60])                    
                    nY += 15
                self.line(11,nY-2,204,nY-2)
                nY += 10
                np += 1
                '''
                if np == 5:
                    self.add_page()
                    nY = 16
                    np = 0
                # print
                self.tag_list.append(self.tag)
                '''

        except Exception as e:
            if hasattr(e, 'message'):
                LOG.error('<%s> in line %s !!!' % (e.message,format(sys.exc_info()[-1].tb_lineno)))
            else:
                LOG.error('<%s> in line %s !!!' % (e,format(sys.exc_info()[-1].tb_lineno)))

    def header(self):

        try:

            # lineas
            self.set_line_width(width=0.1)
            '''
            self.line(11,6,204,6)
            self.line(11,62,204,62)
            self.line(11,118,204,118)
            self.line(11,174,204,174)
            self.line(11,230,204,230)
            self.line(11,286,204,286)
            '''
             # textos
            self.set_font('Courier','',8);
            # configurar documento
            self.set_creator('pymetrick')

            # Line break
            self.ln(20)
        except Exception as e:
            if hasattr(e, 'message'):
                LOG.error('<%s> in line %s !!!' % (e.message,format(sys.exc_info()[-1].tb_lineno)))
            else:
                LOG.error('<%s> in line %s !!!' % (e,format(sys.exc_info()[-1].tb_lineno)))

    # Page footer
    def footer(self):
        # Position at 1.5 cm from bottom
        pass

    def rotateText(self,x,y,txt,angle):
        #Text rotated around its origin
        self.rotate(angle,x,y)
        self.text(x,y,txt)
        self.rotate(0)

    def rotateImage(self,file,x,y,w,h,angle):
        #Image rotated around its upper-left corner
        self.rotate(angle,x,y)
        self.image(file,x,y,w,h)
        self.rotate(0)

    def rounded_rect(self,x, y, w, h, r,corners='1234',style=''):
        "Draw a rounded rectangle"

        try:
            if(style=='F'):
                op='f'
            elif(style=='FD' or style=='DF'):
                op='B'
            else:
                op='S'

            myArc = 4/3 * (math.sqrt(2) - 1);
            self._out(sprintf('%.2f %.2f m',(x+r)*self.k,(self.h-y)*self.k ))

            xc = x+w-r;
            yc = y+r;
            self._out(sprintf('%.2f %.2f l', xc*self.k,(self.h-y)*self.k ))
            if (corners.find('2') < 0):
                self._out(sprintf('%.2f %.2f l', (x+w)*self.k,(self.h-y)*self.k ))
            else:
                self._arc(xc + r*myArc, yc - r, xc + r, yc - r*myArc, xc + r, yc)

            xc = x+w-r;
            yc = y+h-r;
            self._out(sprintf('%.2f %.2f l',(x+w)*self.k,(self.h-yc)*self.k));
            if (corners.find('3') < 0):
                self._out(sprintf('%.2f %.2f l',(x+w)*self.k,(self.h-(y+h))*self.k));
            else:
                self._arc(xc + r, yc + r*myArc, xc + r*myArc, yc + r, xc, yc + r)

            xc = x+r;
            yc = y+h-r;
            self._out(sprintf('%.2f %.2f l',xc*self.k,(self.h-(y+h))*self.k));
            if (corners.find('4') < 0):
                self._out(sprintf('%.2f %.2f l',(x)*self.k,(self.h-(y+h))*self.k))
            else:
                self._arc(xc - r*myArc, yc + r, xc - r, yc + r*myArc, xc - r, yc)

            xc = x+r ;
            yc = y+r;
            self._out(sprintf('%.2f %.2f l',(x)*self.k,(self.h-yc)*self.k ))
            if (corners.find('1') < 0):
                self._out(sprintf('%.2f %.2f l',(x)*self.k,(self.hp-y)*self.k ))
                self._out(sprintf('%.2f %.2f l',(x+r)*self.k,(self.h-y)*self.k ))
            else:
                self._arc(xc - r, yc - r*myArc, xc - r*myArc, yc - r, xc, yc - r)
            self._out(op);

        except Exception as e:
            if hasattr(e, 'message'):
                LOG.error('<%s> in line %s !!!' % (e.message,format(sys.exc_info()[-1].tb_lineno)))
            else:
                LOG.error('<%s> in line %s !!!' % (e,format(sys.exc_info()[-1].tb_lineno)))

    def _arc(self, x1, y1, x2, y2, x3, y3):
        h = self.h
        self._out(sprintf('%.2f %.2f %.2f %.2f %.2f %.2f c', x1*self.k, (h-y1)*self.k,
            x2*self.k, (h-y2)*self.k, x3*self.k, (h-y3)*self.k))

    # EAN14 and UPC-A
    def EAN13(self, x, y, barcode_, h=16, w=.35):
        self.__barcode__(x,y,barcode_,h,w,13)

    def UPC_A(self, x, y, barcode_, h=16, w=.35):
        self.__barcode__(x,y,barcode_,h,w,12)

    def getCheckDigit(self, barcode_):
        # Compute the check digit
        try:

            sum=0
            for i in range(1,12,2):
                sum += 3*int(barcode_[i])
            for i in range(0,11,2):
                sum+=int(barcode_[i])
            r=sum%10
            if(r>0):
                r=10-r
            return str(r)
        except Exception as e:
            if hasattr(e, 'message'):
                LOG.error('<%s> in line %s !!!' % (e.message,format(sys.exc_info()[-1].tb_lineno)))
            else:
                LOG.error('<%s> in line %s !!!' % (e,format(sys.exc_info()[-1].tb_lineno)))

    def testCheckDigit(self, barcode_):
        #Test validity of check digit
        try:
            sum=0
            for i in range(1,12,2):
                sum += 3*int(barcode_[i])
            for i in range(0,11,2):
                sum += int(barcode_[i])
            return (sum+int(barcode_[-1:]))%10==0
        except Exception as e:
            if hasattr(e, 'message'):
                LOG.error('<%s> in line %s !!!' % (e.message,format(sys.exc_info()[-1].tb_lineno)))
            else:
                LOG.error('<%s> in line %s !!!' % (e,format(sys.exc_info()[-1].tb_lineno)))

    def __barcode__(self, x, y, barcode_, h, w, lng):

        try:
            # Padding
            barcode_=barcode_.rjust(lng-1,'0')
            if lng==12:
                barcode_ = '0' + barcode_
            # Add or control the check digit
            if len(barcode_) == 12:
                barcode_ += self.getCheckDigit(barcode_)
            elif not self.testCheckDigit(barcode_):
                self.error('Incorrect check digit')
            #Convert digits to bars
            codes={
                'A':{
                    '0':'0001101','1':'0011001','2':'0010011','3':'0111101','4':'0100011',
                    '5':'0110001','6':'0101111','7':'0111011','8':'0110111','9':'0001011'},
                'B':{
                    '0':'0100111','1':'0110011','2':'0011011','3':'0100001','4':'0011101',
                    '5':'0111001','6':'0000101','7':'0010001','8':'0001001','9':'0010111'},
                'C':{
                    '0':'1110010','1':'1100110','2':'1101100','3':'1000010','4':'1011100',
                    '5':'1001110','6':'1010000','7':'1000100','8':'1001000','9':'1110100'}
                }
            parities={
                '0':['A','A','A','A','A','A'],
                '1':['A','A','B','A','B','B'],
                '2':['A','A','B','B','A','B'],
                '3':['A','A','B','B','B','A'],
                '4':['A','B','A','A','B','B'],
                '5':['A','B','B','A','A','B'],
                '6':['A','B','B','B','A','A'],
                '7':['A','B','A','B','A','B'],
                '8':['A','B','A','B','B','A'],
                '9':['A','B','B','A','B','A']
                }
            code_='101';
            p=parities[barcode_[0]]
            for i in range(1,7):
                code_ +=codes[p[i-1]][barcode_[i]]
            code_ +='01010'
            for i in range(7,13):
                code_ +=codes['C'][barcode_[i]]
            code_ +='101'
            #Draw bars
            for i in range(0,len(code_)):
                if code_[i]=='1':
                    self.rect(x+i*w,y,w,h,'F')
            #Print text uder barcode
            self.set_font('Arial','',12);
            self.text(x,y+h+11/self.k,barcode_[-lng:])
        except Exception as e:
            if hasattr(e, 'message'):
                LOG.error('<%s> in line %s !!!' % (e.message,format(sys.exc_info()[-1].tb_lineno)))
            else:
                LOG.error('<%s> in line %s !!!' % (e,format(sys.exc_info()[-1].tb_lineno)))

def XLSX_Report(report_path='', item_list=list(), head_list=list(), title=None, orientation='portrait', total=list(), head_trademark=[], footer=[], column_not_is_number = []):
    """ Report of list into xlsx file
        @parameters
        report_path -> path + file name + .xlsx
        head_trademark -> head titles of trademak
        item_list -> list with rows
        head_list -> list with head title
        title -> sheet title
        orientation -> portrait|landscape
        total -> list of columns to add
        footer -> foot totals list
        column_not_is_number -> list   only for number columns like string
        
    """
    try:
        if len(item_list)>0:
            big_red_text = Font(color=colors.COLOR_INDEX[2], size=18)
            bold_font = Font(bold=True)
            # crear xlsx
            wb = Workbook()
            ws = wb.active
            ws.page_setup.orientation = ws.ORIENTATION_PORTRAIT
            ws.page_setup.paperSize = ws.PAPERSIZE_A4

            ws.print_options.horizontalCentered = True
            #ws.print_options.verticalCentered = True

            ws.oddHeader.left.text = "Pag. &[Page] of &N"
            ws.oddHeader.left.size = 10
            ws.oddHeader.left.font = "Tahoma,Bold"

            ws.page_margins.left = 0.2
            ws.page_margins.right = 0.2

            row = 2 + len(head_trademark)
            for reg in item_list:
                # recuperar datos como list
                reg = list(reg)

            # calculate last col
            _first = 64   # number ascii -1 for col name if two chars    
            _head = 64    # number ascii -1 for col name
            _last_col = 'A'
            for n in range(0,len(head_list)):
                if head_list[n] is not None:
                    _head += 1
                    if _head > 90:   # Z
                        _head = 65
                        _first += 1
                    _last_col = chr(_head) if _first == 64 else chr(_first)+chr(_head)

            #insert trade mark on header
            if len(head_trademark)>0:
                #ws.insert_rows(idx=0,amount=len(head_trademark))
                for n in range(0,len(head_trademark)):
                    ws.merge_cells(range_string=chr(65)+str(n+1)+':'+chr(65+6)+str(n+1))
                    ws[chr(65)+str(n+1)] = head_trademark[n]
                    if n == 0:
                        ws[chr(65)+str(n+1)].font = big_red_text
                    else:
                        ws[chr(65)+str(n+1)].font = bold_font
   
            #tab = Table(displayName="Table1", ref="A1:Z{0}".format(len(_account_list)+1))
            tab = Table(displayName="Table1", ref=f'''{chr(65)}{len(head_trademark)+1}:{_last_col}{len(item_list)+2+len(head_trademark)+len(footer)}''')

            # print area
            ws.print_area = "A1:{0}{1}".format(_last_col,len(item_list)+2+len(head_trademark)+len(footer))

            # Add a default style with striped rows and banded columns
            style = TableStyleInfo(name="TableStyleLight1", showFirstColumn=False, showLastColumn=False, showRowStripes=True, showColumnStripes=False)
            tab.tableStyleInfo = style
            ws.add_table(tab)
            
            #print options
            ws.print_options.horizontalCentered = True
            ws.print_options.verticalCentered = False
            # print fit to page width
            ws.sheet_properties.pageSetUpPr.fitToPage = True
            # print all pages fit to page width
            ws.page_setup.fitToHeight = False

            """
            PAPERSIZE_LETTER = '1'
            PAPERSIZE_LETTER_SMALL = '2'
            PAPERSIZE_TABLOID = '3'
            PAPERSIZE_LEDGER = '4'
            PAPERSIZE_LEGAL = '5'
            PAPERSIZE_STATEMENT = '6'
            PAPERSIZE_EXECUTIVE = '7'
            PAPERSIZE_A3 = '8'
            PAPERSIZE_A4 = '9'
            PAPERSIZE_A4_SMALL = '10'
            PAPERSIZE_A5 = '11'
            """
            # portrait or landscape
            ws.set_printer_settings(paper_size = 9, orientation=orientation)
            
            #ws = wb.create_sheet("order_xlsx") # insert at the end (default)
            # crear cabecera

            if title is not None:
                ws.title = title
            else:
                ws.title = 'INFORME'
            _first = 64   # number ascii -1 for col name if two chars    
            _head = 64    # number ascii -1 for col name
            _head_length = 0    # check if head is empty

            for n in range(0,len(head_list)):
                if head_list[n] is not None and len(head_list[n].strip())>0:
                    _head_length += len(head_list[n].strip())
                    _head += 1
                    if _head > 90:   # Z
                        _head = 65
                        _first += 1
                    if _first == 64:
                        if len(head_list[n].split(' '))>1:
                            ws[chr(_head)+str(len(head_trademark)+1)].alignment = openpyxl.styles.Alignment(wrapText=True)               # WRAP TEXT
                        ws[chr(_head)+str(len(head_trademark)+1)] = head_list[n]
                    else:
                        if len(head_list[n].split(' '))>1:
                            ws[chr(_first)+chr(_head)+str(len(head_trademark)+1)].alignment = openpyxl.styles.Alignment(wrapText=True)    # WRAP TEXT
                        ws[chr(_first)+chr(_head)+str(len(head_trademark)+1)] = head_list[n]
                        
                    

            for reg in item_list:
                if len(reg)>0:    # no crear filas sin datos
                    # completar fila y reemplazar caracteres erroneos
                    _col = 0    # numero de columna
                    for col in range(0,len(reg)):
                        if len(head_list)>col and head_list[col] is not None:
                            #ws.row_dimensions[row].height = int(100 / 1.333)   # In pixels
                            try:
                                _col += 1
                                if reg[col] is None:
                                    reg[col] = ''
                                # codebar and yyyy+mm+dd+hh+MM+ss not is a number
                                if isNumber(str(reg[col]).strip()) and len(str(reg[col])) < 12 and col not in column_not_is_number :
                                    # numeros alineacion derecha
                                    ws.cell(row=row,column=_col,value=reg[col]).alignment = Alignment(horizontal='right',vertical='center')
                                else:
                                    # caracteres alineacion izquierda
                                    reg[col] = str(reg[col])
                                    ws.cell(row=row,column=_col,value=reg[col]).alignment = Alignment(horizontal='left',vertical='center')
                            except Exception as e:
                                LOG.error('<%s> in line %s !!!' % (e,format(sys.exc_info()[-1].tb_lineno)))
                    row += 1
                    
            for column_cells in ws.columns:
                length = max(len(as_text(cell.value)) for cell in column_cells)
                ws.column_dimensions[get_column_letter(column_cells[0].column)].width = (length + 2) * 1.2

            #totalized
            mas_n = len(head_trademark)
            if len(total)>0 and total[0]>1:
                ws[chr(total[0]-1+64)+str(len(item_list)+2+len(head_trademark))] = f"""TOTAL"""
                for n in total:
                    ws[chr(n+64)+str(len(item_list)+2+len(head_trademark))] = f"""=SUM({chr(n+64)}{1+mas_n}:{chr(n+64)}{len(item_list)+1+mas_n})"""

            # footer
            if len(footer)>0:
                row = len(item_list)+2+len(head_trademark) + 1
                _col = 0
                for n in range(0,len(footer)):
                    for m in range(0,len(footer[n])):
                        _col += 1
                        if isNumber(str(footer[n][m]).strip()):
                            # numeros alineacion derecha
                            ws.cell(row=row,column=_col,value=footer[n][m]).alignment = Alignment(horizontal='right',vertical='center')
                        else:
                            # caracteres alineacion izquierda
                            footer[n][m] = str(footer[n][m])
                            #ws.merge_cells(range_string=chr(64+_col)+str(n+row)+':'+chr(64+_col+3)+str(n+row))
                            #ws[chr(64+_col)+str(n+row)] = footer[n][m]
                            #_col += 3
                            
                            ws.cell(row=row,column=_col,value=footer[n][m]).alignment = Alignment(horizontal='left',vertical='center')
                    row += 1
                    _col = 0
            if _head_length == 0:
                ws.delete_rows(0)
            else:
                # add print title on all pages
                ws.print_title_rows = f'''1:{len(head_trademark)+1}''' # the first row

            adjust_width(ws)
            """
            #insert trade mark on header
            if len(head_trademark)>0:
                ws.insert_rows(idx=0,amount=len(head_trademark))
                for n in range(0,len(head_trademark)):
                    ws.merge_cells(range_string=chr(65)+str(n+1)+':'+chr(65+4)+str(n+1))
                    ws[chr(65)+str(n+1)] = head_trademark[n]
                    if n == 0:
                        ws[chr(65)+str(n+1)].font = big_red_text
                    else:
                        ws[chr(65)+str(n+1)].font = bold_font
            """
        try:
            wb.save(report_path)
          
            return True
        except Exception as e:
            return False
    except Exception as e:
        if hasattr(e, 'message'):
            LOG.error('<%s> in line %s !!!' % (e.message,format(sys.exc_info()[-1].tb_lineno)))
        else:
            LOG.error('<%s> in line %s !!!' % (e,format(sys.exc_info()[-1].tb_lineno)))

def adjust_width(ws):
    """
    Adjust width of the columns
    @param ws: worksheet
    @return: None
    """

    def is_merged_horizontally(cell):
        """
        Checks if cell is merged horizontally with an another cell
        @param cell: cell to check
        @return: True if cell is merged horizontally with an another cell, else False
        """
        cell_coor = cell.coordinate
        if cell_coor not in ws.merged_cells:
            return False
        for rng in ws.merged_cells.ranges:
            if cell_coor in rng and len(list(rng.cols)) > 1:
                return True
        return False

    for col_number, col in enumerate(ws.columns, start=1):
        col_letter = get_column_letter(col_number)

        max_length = max(
            len(str(cell.value or "")) for cell in col if not is_merged_horizontally(cell)
        )
        adjusted_width = (max_length + 2) * 0.95
        ws.column_dimensions[col_letter].width = adjusted_width
        
            
def esc_pos_code39(order_code): 
    try:
        if sys.platform[:-2] == 'win':
            ALL_PRINTERS = [printer[2] for printer in win32print.EnumPrinters(2)]
        else:
            ALL_PRINTERS = []
        printer_name = win32print.GetDefaultPrinter()
        #if 'printer_name' in list(kwargs.keys()) and kwargs['printer_name'].upper() in ALL_PRINTERS:
        #    printer_name = kwargs['printer_name'].upper()

        if sys.platform[:-2] == 'win':
            win32print.SetDefaultPrinter(printer_name)
            hPrinter = win32print.OpenPrinter(printer_name)
            try:
                hJob = win32print.StartDocPrinter(hPrinter, 1, ('prueba', None, "RAW"))    # title on spooler
                try:
                    win32print.StartPagePrinter(hPrinter)
                    
                    win32print.WritePrinter (hPrinter,HW_RESET)
                    win32print.WritePrinter (hPrinter,HW_INIT)     # Clear data in buffer and reset modes
                    win32print.WritePrinter (hPrinter,CODEPAGE_CHANGE + b'\x00')   # CODEPAGE CHARACTER_CODE_TABLE  PAGE 0
                    win32print.WritePrinter (hPrinter,LINESPACING_RESET)
                    win32print.WritePrinter (hPrinter, SHEET_ROLL_MODE)
                    form = ""
                    # CODE39
                    #win32print.WritePrinter(hPrinter,b'\x1b\x1c\x70\x01\x00')                    
                    _txt = bytes(order_code,CHARACTER_CODE_TABLE)
                    #win32print.WritePrinter(hPrinter,b'\x1d\x68'+six.int2byte(162))    # Set bar code height (1D-Barcode)
                    #win32print.WritePrinter(hPrinter,b'\x1d\x77'+six.int2byte(3))      # Set the horizontal size of the bar code
                    #win32print.WritePrinter(hPrinter,b'\x1d\x48'+six.int2byte(2))      # Select HRI character print position
                    
                    #win32print.WritePrinter(hPrinter,b'\x1d\x68' + six.int2byte(162)+ b'\x1d\x77' + six.int2byte(3) + b'\x1d\x48' + six.int2byte(2) + b'\x1d' + b'k' + b'\x04' +_txt+b'\xff'+CTL_CR+CTL_LF)    # Printing of bar code (1D-Barcode)
                    #win32print.WritePrinter(hPrinter,b'\x1b\x62'+six.int2byte(52)+_txt+b'\xff'+CTL_CR+CTL_LF)    # Printing of bar code (1D-Barcode)

                    win32print.WritePrinter(hPrinter,b'\x1d\x1b\x2a\x72\61\x1b\x1e\x41\x00\x1b\x1e\x41\x00\x1b\x1d\x63\x00\x00\x1b\x2a\x72\x74\x31\x31\x00\x1b\x1e\x74\x00\x1b\x2a\x72\x4b\x30\x00\x62\x2a'+CTL_CR+CTL_LF)

                    #win32print.WritePrinter(hPrinter,b'\x1d\x6b'+b'\x04'+_txt+b'\xff'+CTL_CR+CTL_LF)
                    #win32print.WritePrinter(hPrinter,BARCODE_FONT_A+BARCODE_TXT_BLW+BARCODE_HEIGHT+six.int2byte(160)+BARCODE_WIDTH+six.int2byte(4)+BARCODE_TYPE_A['CODE39']+_txt+b'\x00')
                    win32print.EndPagePrinter(hPrinter)
                except Exception as e:
                    tb = sys.exc_info()[2]
                    LOG.error('<%s> in line %s !!!' % (str(e),tb.tb_lineno))     
                       
                finally:
                    win32print.EndDocPrinter(hPrinter)
            except Exception as e:
                tb = sys.exc_info()[2]
                LOG.error('<%s> in line %s !!!' % (str(e),tb.tb_lineno))
            finally:
                win32print.ClosePrinter(hPrinter)



        

    except Exception as e:
        tb = sys.exc_info()[2]
        LOG.error('<%s> in line %s !!!' % (str(e),tb.tb_lineno))

if __name__ == "__main__":

    print ('''copyright {0}'''.format( __copyright__))
    print ('''license {0}'''.format( __license__))
    print ('''version {0}'''.format( __version__))
    if len(sys.argv) < 2:
        sys.stderr.write("For help use -h o --help")
    elif sys.argv[1]=='-h' or sys.argv[1]=='--help':
        print (''' Issue documents ''')



