jueves, 25 de abril de 2024

ODOO (XVI) Consultar la base de datos Postgres

 Vemos algunas sentencias para descubrir la información de la provincia de Valencia.


Para ello entramos en Odoo y seleccionameos en Configuracion el modo desarrollador y comprobamos que aparece el escarabajo.

Entramos en el menu Contactos - Configuracion - (Localizacion Provincias)

Ahora le damos al Escarabajo - Ver campos 

y sale que la el modelo es Country State que es res.country.state

por tanto hay que buscar una tabla que se llame parecido (seguramene sera res_country_state


# 1. Conectarse como postgres
myuser@SRV-ODOO-ERP:~$ sudo -i -u postgres

# 2. pide la contraseña (en principio de su)

# 3.ejecutar psql
postgres@SRV-ODOO-ERP:~$ psql 

# 4. Listr las pases de datos
postgres=# \l

# 5. Devuelve
#   Name    |  Owner   | Encoding |   Collate   |    Ctype    | ICU Locale | Locale Provider |   Access privileges   
#-----------+----------+----------+-------------+-------------+------------+-----------------+-----------------------
# odoo      | odoo     | UTF8     | C           | es_ES.UTF-8 |            | libc            | 
# postgres  | postgres | UTF8     | es_ES.UTF-8 | es_ES.UTF-8 |            | libc            | 
# template0 | postgres | UTF8     | es_ES.UTF-8 | es_ES.UTF-8 |            | libc            | =c/postgres          +
#           |          |          |             |             |            |                 | postgres=CTc/postgres
# template1 | postgres | UTF8     | es_ES.UTF-8 | es_ES.UTF-8 |            | libc            | =c/postgres          +
#           |          |          |             |             |            |                 | postgres=CTc/postgres
#(4 rows)

# 5. Nos salimos
q

# 6. Nos conectamos a la bbdd "odoo"
postgres=# \c odoo
# You are now connected to database "odoo" as user "postgres # 7. Comados para listar # 7.1 \d lista todo todo # 7.2 \dn lista esquems # 7.3 \dt lista tablas # 8. mostrar las tablas y vemos que aprece una llamada res_country_state odoo=# \dt # 9. Ver los campos de una tabla (No olvidar el ";" del final !!! odoo=# select column_name from information_schema.columns where table_name='res_country_state'; # column_name #------------- # id # country_id # create_uid # write_uid # create_date # write_date # name # code #(8 rows) # 10. Ver la información de la provincia de Valencia odoo=# select id, name, code, country_id from res_country_state where code='V'; # id | name | code | country_id #-----+---------------------+------+------------ # 464 | València (Valencia) | V | 68 # 575 | Tierra del Fuego | V | 10 #(2 rows)


En este caso consultamos el valor del id y del country_id


ODOO (XV) Añadir campos al modelo

0. Introducción

Créditos: RGB Consulting 

1. Añadir un campo

Entrar en el boton de la parte superior izquierda(1) -Ajustes (2) -Técnico(3)  -Estructura de la base de datos (4) - Modelo (5)



Ahora buscamos el modelo que es hr.employee en el filtro 




Una vez dentro del modelo, nos vamos a la ventana de campos (1) y paginamos hasta el final (2) (en mi caso hay que correr 4 pantallas, y al seleccionamos agregar línea (3). 

OJO: Al paginar hay que paginar sobre la ventana de campos del modelo que está un poco mas abajo, y no en la ventana de modelos que está arriba!!

Ahora añadimos el campo x_micampo y le indicamos el tipo de campo, y varias características mas.




2. Crear un formulario donde aparezca dicho campo

Entrar en el boton de la parte superior izquierda(1) -Ajustes (2) -Técnico(3)  -Interfaz de Usuario (4) - Vistas (5) tal como hemos visto en el apartado anterior hasta el punto 3











martes, 23 de abril de 2024

Python (III). Crear ejecutables linux y Windows

0. Introducción

Si estamos en Linux solo podremos hacer ejecutables windows si utilizamos Wine, pero suele fallar.

Para ello es conveniente utilizar Windows para realizar ejecutables Windows y Linux para hacer ejecutables Linux.

Lo primero que hay que hacer es instalar pyinstaller

# En windows
pip install pyinstaller
# En windows si falla
python -m pip install pyinstaller
# En Linux ./bin/python -m pip install pyinstaller

1. Caso especial de windows 11

Cuando se instala en windows 11 se instala pyinstaller dentro de la carpeta del usuario. Por tanto debemos incluir en el path del usuario 

En windows tenemos que añadir a las variables de entorno de usuario estas carpetas tal como se muestra:

C:\Users\eduard\AppData\Local\Programs\Python\Python312\Scripts

C:\Users\eduard\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.12_qbz5n2kfra8p0\LocalCache\local-packages\Python312\Scripts






2. Generación del ejecutable

Ahora ejecutamos la opción para que genere un único fichero (en este caso hemos utilizado el módulo python mdph.py


# En windows
Pyinstaller --onefile -w mdph.py
# En windows, si falla
python -m Pyinstaller --onefile -w mdph.py

# En Linux
pyinstaller --onefile mdph.py

Ahora ejecutamos la opción para que genere un único fichero

Para el caso de linux, crea una carpeta llamada dist y dentro está el ejecutable mdph


3. Ejemplo de conversión

Anteriormente hemos utilizado el comando de creación del ejecutable del módulo mdph.py. Ahora vamos a mostrar el detalle de este fichero y el módulo adicional que utiliza.

El problema en cuestión consiste en transformar un fichero excel que por cada persona tiene 4 filas, donde hay un campo "Denominació" que puede tomar los valores "Observacions, pares, emails y telefons", y otro campo "Valor" que toma los valores específicos". El fichero transformado tendrá un único registro por persona y le añadirá los 4 campos Observacions, pares, emails y telefons"

Para este ejemplo tenemos que instalar las dependencias pandas, numpy y tkinter


# En windows
pip install pandas
pip install numpy
pip install tkinter
# En Linux ./bin/python -m pip install pandas
./bin/python -m pip install numpy
./bin/python -m pip install tkinter



Y utilizamos 2 módulos mdexcel.py y mdph.py

El primero (mdexcel.py) tiene utilidades para manejar ficheros excel
El segundo (mdph.py)

3.1 mdexcel.py



import
pandas import numpy def getExcel(object)->object: excel=pandas.read_excel(object) return excel def getCSVText(object)->str: myStr="" excel=pandas.ExcelFile(object) for sheetName in excel.sheet_names: sheet=pandas.read_excel(excel, sheetName) myStr+=str(sheet) print (myStr) return myStr #getCSVText("/home/eduard/Baixades/edu.xlsx") def getColumnNamesAndRows(obj:object, sheetName:str='')->list[list[object]]: excel=pandas.ExcelFile(obj) print (excel) colNames=[] if len(sheetName)==0: sheet=pandas.read_excel(excel, excel.sheet_names[0]) else: sheet=pandas.read_excel(excel, excel.sheet_names[excel.sheet_names.index(sheetName)]) for column in sheet.columns: print (column) colNames.append(column) return colNames,sheet.values def getColumnValues(columnNames:list[str], values:list[list[object]], wantedCols:list[str])->list[object]: allCols=[] for colName in wantedCols: print('colName='+colName) myCol=[] colNum=columnNames.index(colName) for row in values: myValue=row[colNum] myCol.append(myValue) allCols.append(myCol) return allCols def list2ExcelFile(inList:list[list[object]], filePath:str, transpose:bool=False): df=None if transpose: print('Transposing the matrix and getting dataframe........') df=pandas.DataFrame(numpy.array(inList).T) else: print('Getting dataframe........') df=pandas.DataFrame(inList) with pandas.ExcelWriter(filePath) as writer: print ('Writing excel File.....') df.to_excel(writer, sheet_name='Full1')



3.2 mdph.py


import mdexcel
import tkinter
import tkinter.filedialog

#-------------------------------------------------------------------
#  Arreglem el xls que torna el programa del padró que conté fins 
#  4 registres per persona amb cada línia té: 
#  pares, observacions, teléfons i emails
#  I afegeix eixos 4 camps i deixa només una línia per persona
#-------------------------------------------------------------------
def arreglarXLS(input:object, outFilePath:str)->object:
    
    print('1. Reading Excel File...')
    columnNames,myData= mdexcel.getColumnNamesAndRows(input)
    
    myWantedCols=['Nº documento','Nom'           ,'Partícula 1'  ,'Cognom 1'             ,'Partícula 2',
                  'Cognom 2'    ,'Data naixement','Cognoms i Nom','Tipus Via normalitzat','Nom Via',
                  'Nombres'     ,'Escala'        ,'Codi Planta'  ,'Porta'                ,'Nom nucli/disseminat (50)',
                  'Adreça'      ,"Data d'alta"   ,'Denominació'  ,'Valor'                ,'Estat']
    myColNames=     myWantedCols[0:17] + ['Emails','Observacions','Telefons', 'PARES'] + myWantedCols[19:20]
    
    print('2. getting column Values...')
    myDataCols=mdexcel.getColumnValues(columnNames, myData, myWantedCols)
    
    print('3. Selecting data...')
    myDocu='xxxx',
    myCognomNom='xxxxx'
    #Create a list of columns
    myNewDataCols=[]
    #add column headers
    for name in myColNames:
        aList=[]
        aList.append(name)
        myNewDataCols.append(aList)
    ii=0
    for i in range(len(myDataCols[0])):
        if myDataCols[0][i]!=myDocu or myDataCols[7][i]!=myCognomNom:
            myDocu=     myDataCols[0][i]
            myCognomNom=myDataCols[7][i]
            ii+=1
            for j in range(len(myColNames)):
                myNewDataCols[ j].append('')
                if j<17 :                     myNewDataCols[ j][ii]=myDataCols[j][i]
                if j>=17 and j<21:            myNewDataCols[ j][ii]=''
                if j==21:                     myNewDataCols[ j][ii]=myDataCols[19][i]

        if myDataCols[17][i]==myColNames[17]: myNewDataCols[17][ii]=myDataCols[18][i]    
        if myDataCols[17][i]==myColNames[18]: myNewDataCols[18][ii]=myDataCols[18][i]    
        if myDataCols[17][i]==myColNames[19]: myNewDataCols[19][ii]=myDataCols[18][i]    
        if myDataCols[17][i]==myColNames[20]: myNewDataCols[20][ii]=myDataCols[18][i]    

    print('4. Writing excel file...')
    mdexcel.list2ExcelFile(myNewDataCols,outFilePath, transpose=True)       

    print('5. The end ...')
    return True


def getOutputFileName(inputFileName:str)->str:
    if inputFileName.endswith('.xlsx'):
        return inputFileName.replace('.xlsx','.arreglat.xlsx')
    else: import mdexcel
import tkinter

#-------------------------------------------------------------------
#  Arreglem el xls que torna el programa del padró que conté fins 
#  4 registres per persona amb cada línia té: 
#  pares, observacions, teléfons i emails
#  I afegeix eixos 4 camps i deixa només una línia per persona
#-------------------------------------------------------------------
def arreglarXLS(input:object, outFilePath:str)->object:
    
    print('1. Reading Excel File...')
    columnNames,myData= mdexcel.getColumnNamesAndRows(input)
    
    myWantedCols=['Nº documento','Nom'           ,'Partícula 1'  ,'Cognom 1'             ,'Partícula 2',
                  'Cognom 2'    ,'Data naixement','Cognoms i Nom','Tipus Via normalitzat','Nom Via',
                  'Nombres'     ,'Escala'        ,'Codi Planta'  ,'Porta'                ,'Nom nucli/disseminat (50)',
                  'Adreça'      ,"Data d'alta"   ,'Denominació'  ,'Valor'                ,'Estat']
    myColNames=     myWantedCols[0:17] + ['Emails','Observacions','Telefons', 'PARES'] + myWantedCols[19:20]
    
    print('2. getting column Values...')
    myDataCols=mdexcel.getColumnValues(columnNames, myData, myWantedCols)
    
    print('3. Selecting data...')
    myDocu='xxxx',
    myCognomNom='xxxxx'
    #Create a list of columns
    myNewDataCols=[]
    #add column headers
    for name in myColNames:
        aList=[]
        aList.append(name)
        myNewDataCols.append(aList)
    ii=0
    for i in range(len(myDataCols[0])):
        if myDataCols[0][i]!=myDocu or myDataCols[7][i]!=myCognomNom:
            myDocu=     myDataCols[0][i]
            myCognomNom=myDataCols[7][i]
            ii+=1
            for j in range(len(myColNames)):
                myNewDataCols[ j].append('')
                if j<17 :                     myNewDataCols[ j][ii]=myDataCols[j][i]
                if j>=17 and j<21:            myNewDataCols[ j][ii]=''
                if j==21:                     myNewDataCols[ j][ii]=myDataCols[19][i]

        if myDataCols[17][i]==myColNames[17]: myNewDataCols[17][ii]=myDataCols[18][i]    
        if myDataCols[17][i]==myColNames[18]: myNewDataCols[18][ii]=myDataCols[18][i]    
        if myDataCols[17][i]==myColNames[19]: myNewDataCols[19][ii]=myDataCols[18][i]    
        if myDataCols[17][i]==myColNames[20]: myNewDataCols[20][ii]=myDataCols[18][i]    

    print('4. Writing excel file...')
    mdexcel.list2ExcelFile(myNewDataCols,outFilePath, transpose=True)       

    print('5. The end ...')
    return True


def getOutputFileName(inputFileName:str)->str:
    if inputFileName.endswith('.xlsx'):
        return inputFileName.replace('.xlsx','.arreglat.xlsx')
    else: 
        return inputFileName.replace('.xls','.arreglat.xls')

def capturaExcel(inputFileNameEntry):
    fitxerExcel=tkinter.filedialog.askopenfilename( filetypes=[("Excel files", ".xlsx .xls")])
    inputFileNameEntry.delete(0,tkinter.END)
    inputFileNameEntry.insert(0,fitxerExcel)

def arreglarExcel(inputFileNameEntry):
    # Get the user input from the form
    inputFileName = inputFileNameEntry.get()
    outputFileName=getOutputFileName(inputFileName)
    arreglarXLS(inputFileName, outputFileName)
    tkinter.messagebox.showinfo("Success", "Proces acabat!")

def formArreglarXLS():
    # Create the main tkinter window
    root = tkinter.Tk()
    root.title("Arreglar fitxer Excel per a importar a ODOO")
    root.geometry('800x300')


    # Create labels and entry fields for each input
    #inputFileNameLabel= tkinter.Label(root, text="A capturar....:").grid(row=0, sticky=tkinter.W)
    inputFileNameLabel= tkinter.Label(root, text="Fitxer:")
    inputFileNameLabel.grid(row=0, column=0)
    #inputFileNameLabel.pack()
    inputFileNameEntry= tkinter.Entry(root, text='', width=70)
    inputFileNameEntry.grid(row=0, column=1)
    #inputFileNameEntry.pack()
    #botoCaptura = tkinter.Button(root, text ="Capturar Fitxer excel del padró", command = capturaExcel(inputFileNameEntry))
    botoCaptura = tkinter.Button(root, text ="Capturar", command = lambda:capturaExcel(inputFileNameEntry))
    botoCaptura.grid(row=0, column=2)
    #botoCaptura.pack()
    
    #executeButton = tkinter.Button(root, text="Arreglar Excel del Padró", command=arreglarExcel(inputFileNameEntry))
    executeButton = tkinter.Button(root, text="Arreglar Excel del Padró", command=lambda:arreglarExcel(inputFileNameEntry))
    executeButton.grid(row=5, column=1)
    #executeButton.pack()
    executeButton.grid()

    root.mainloop()

''''
------------------------------------------------------------
Tests
------------------------------------------------------------
'''
def mytest():
    #if __name__ == '__main__':
    #props=mdconfig.read_app_props("sqlite")
    
    '''
    inDir='/home/eduard/MyOdoo/Control-Presencia/DADES/'
    inFName='Padro_habitants_migracio_sedipualba240416.xlsx'
    outFName=inFName.replace('.xls','.out.xls')

    arreglarXLS(inDir+inFName, inDir+outFName)
    '''

    formArreglarXLS()
    
#------ main
mytest()    






jueves, 4 de abril de 2024

Escaneo de documentos en urbanismo.



  1. Para cada expediente se creará una carpeta dentro del NAS
  2. Se escanearan los documentos de ese expediente dentro de la carpeta creada. 
  3. Hay impresoras que permiten pasar el OCR. 
  4. Es importante que los documentos se pueda saber el orden que se ha escaneado pues marcará el orden del documento dentro del expediente.
  5. Si no se puede pasar el OCR, se podrá pasar posteriormente el OCR a través de adobe profesional u otros medios (easyOCR ..)
  6. Cuando se haya pasado el OCR se puede renombrar el documento en base al expediente y el tipo de documento que se obtenga analizando el texto del documento.
  7. Con estos datos se puede pasar a odoo.
  8. Mas tarde se rellenaran en odoo los datos del expediente y los departamentos que pertenezca el expediente.