Como cargar saldos de cuenta corriente en Odoo con xmlrpc

12 de julio de 2023 por
Gustavo Orrillo
| Sin comentarios aún
 

En un post anterior "Comprendiendo (como programador) la cuenta corriente de Odoo
"
, aprendimos que la cuenta corriente se administra en la contabilidad de Odoo. O sea que si necesitamos cargar los saldos de cuenta corriente de los clientes o de los proveedores (por ejemplo durante la migración del sistema), debemos crear los asientos contables para crear los saldos deudores/acreedores de clientes/proveedores.

En este artículo vamos a ver un ejemplo donde vamos a leer un archivo de Excel con los saldos de las facturas impagas de clientes. El archivo tiene las siguientes columnas


En esta planilla de Excel tenemos las columnas: cliente (con el código de referencia del cliente, es la columna que nos va a permitir referenciar al cliente), referencia (con el nro de factura del cliente, nos permite identificar el movimiento contable), fecha de la factura y saldo sin cobrar. Habiendo dicho eso, el primer paso es leer el archivo en formato XLSX

#!/usr/bin/python3
from xmlrpc import client
import openpyxl
from datetime import datetime
url = 'http://localhost:8069'
common = client.ServerProxy('{}/xmlrpc/2/common'.format(url))
res = common.version()
dbname = 'mrputilsv1'
user = 'admin'
pwd = 'admin'
uid = common.authenticate(dbname, user, pwd, {})
# prints Odoo version and UID to make sure we are connected
print(res)
print(uid)
models = client.ServerProxy('{}/xmlrpc/2/object'.format(url))
# Define la variable para leer el workbook
workbook = openpyxl.load_workbook("saldos_cuenta_corriente.xlsx")
# Define variable para la planilla activa
worksheet = workbook.active
# Itera las filas para leer los contenidos de cada celda
rows = worksheet.rows
for x,row in enumerate(rows):
# Saltea la primer fila porque tiene el nombre de las columnas
if x == 0:
continue
# Lee cada una de las celdas en la fila
vals = {}
for i,cell in enumerate(row):
print(i,cell.value)

Esto lee todas las filas y columnas de la planilla de Excel. Paso siguiente, por cada registro leido del archivo Excel creamos un asiento contable. Definimos que el diario en el que se va a crear el asiento contable es "Operaciones miscelaneas" (esta es una decisión arbitraria) que es del tipo varios y permite crear todo tipo de asientos contables. El código para crear los asientos es el siguiente:


#!/usr/bin/python3 

from xmlrpc import client
import openpyxl
from datetime import datetime

url = 'http://localhost:8069'
common = client.ServerProxy('{}/xmlrpc/2/common'.format(url))
res = common.version()
dbname = 'mrputilsv1'
user = 'admin'
pwd = 'admin'
uid = common.authenticate(dbname, user, pwd, {})

# prints Odoo version and UID to make sure we are connected
print(res)
print(uid)
models = client.ServerProxy('{}/xmlrpc/2/object'.format(url))

# Busca el ID del journal MISC
journal_id = models.execute_kw(dbname,uid,pwd,'account.journal','search',[[['code','=','MISC']]])

# Define la variable para leer el workbook
workbook = openpyxl.load_workbook("saldos_cuenta_corriente.xlsx")
# Define variable para la planilla activa
worksheet = workbook.active

# Itera las filas para leer los contenidos de cada celda
rows = worksheet.rows
for x,row in enumerate(rows):
# Saltea la primer fila porque tiene el nombre de las columnas
if x == 0:
continue
# Lee cada una de las celdas en la fila
vals = {}
for i,cell in enumerate(row):
print(i,cell.value)
ref = ''
if i == 1:
col = 'ref'
vals[col] = cell.value
if i == 2:
col = 'date'
vals[col] = cell.value
if type(vals[col]) == datetime:
vals[col] = str(vals[col])
vals['journal_id'] = journal_id[0]
vals['name'] = vals.get('ref')
move_id = models.execute_kw(dbname,uid,pwd,'account.move','search',\
​[[['ref','=',vals.get('ref')]]])
if not move_id:
move_id = models.execute_kw(dbname,uid,pwd,'account.move','create',[vals])
else:
# El asiento ya fue creado, se pasa a la siguiente fila
continue
print(move_id)

y crea los asientos contables de la siguiente manera:


Eso son los asientos, pero no tienen líneas (por eso la columna Total con valor a 0). Ahora vamos a crear las líneas de los asientos contables (conocidas como apuntes contables por el traductor de Odoo). El modelo que debemos actualizar es account.move.line. Cada asiento creado (modelo account.move) va a tener dos líneas, una de débito y otro de crédito donde el monto a debitar/acreditar será el de la deuda. Debido a que en este ejemplo estamos hablando de la deuda de clientes; se debe debitar la cuenta "Deudores por venta" (cuenta del tipo cobrable, se debe debitar la cuenta que va a administrar la cuenta corriente del cliente) por el monto de la deuda, y acreditar la cuenta Ajustes de Capital (elegida arbitrariamente, puede preguntarle al contador que cuenta utilizar). Tambien debemos indicar el cliente de la línea de la deuda (si no hacemos esto, el sistema no va a permitir la conciliación de los saldos y ademas no sabremos como actualizar los saldos). Por último, y no por eso menos importante, debemos indicar el contexto check_move_validity con el valor False. Sino vamos a tener un mensaje de error de Odoo indicando que el asiento no se encuentra balanceado.

El código debajo hace todo esto, el cual crea el asiento y los dos apuntes contables. Por último, se confirma el asiento contable pare registrar la deuda en la cuenta corriente del cliente.

#!/usr/bin/python3
from xmlrpc import client
import openpyxl
from datetime import datetime
url = 'http://localhost:8069'
common = client.ServerProxy('{}/xmlrpc/2/common'.format(url))
res = common.version()
dbname = 'demo_contract_ar'
user = 'admin'
pwd = 'admin'
uid = common.authenticate(dbname, user, pwd, {})
# prints Odoo version and UID to make sure we are connected
print(res)
print(uid)
models = client.ServerProxy('{}/xmlrpc/2/object'.format(url))
# Busca el ID del journal MISC
journal_id = models.execute_kw(dbname,uid,pwd,'account.journal','search',[[['code','=','MISC']]])
# Busca cuenta ajuste de capital (codigo 3.1.1.01.020)
credit_account_id = models.execute_kw(dbname,uid,pwd,'account.account','search',[[['code','=','3.1.1.01.020'],['company_id','=',1]]])
# Busca cuenta deudores por venta (codigo 3.1.1.01.020)
debit_account_id = models.execute_kw(dbname,uid,pwd,'account.account','search',[[['code','=','1.1.3.01.010'],['company_id','=',1]]])
# Define la variable para leer el workbook
workbook = openpyxl.load_workbook("saldos_cuenta_corriente.xlsx")
# Define variable para la planilla activa
worksheet = workbook.active
# Itera las filas para leer los contenidos de cada celda
rows = worksheet.rows
for x,row in enumerate(rows):
# Saltea la primer fila porque tiene el nombre de las columnas
if x == 0:
continue
# Lee cada una de las celdas en la fila
vals = {}
partner_id = None
amount = 0
for i,cell in enumerate(row):
print(i,cell.value)
ref = ''
if i == 0:
# Busca el cliente por el codigo de referencia
partner_id = models.execute_kw(dbname,uid,pwd,'res.partner','search',[[['ref','=',cell.value]]])
if not partner_id:
continue
if i == 1:
col = 'ref'
vals[col] = cell.value
if i == 2:
col = 'date'
vals[col] = cell.value
if type(vals[col]) == datetime:
vals[col] = str(vals[col])
if i == 3:
amount = float(cell.value)
vals['journal_id'] = journal_id[0]
vals['name'] = vals.get('ref')
vals['company_id'] = 1
move_id = models.execute_kw(dbname,uid,pwd,'account.move','search',[[['ref','=',vals.get('ref')]]])
if not move_id:
move_id = models.execute_kw(dbname,uid,pwd,'account.move','create',[vals])
else:
# El asiento ya fue creado, se pasa a la siguiente fila
continue
print(move_id)
vals_debit = {
'company_id': 1,
'move_id': move_id,
'date': vals.get('date'),
'journal_id': vals.get('journal_id'),
'account_id': debit_account_id[0],
'partner_id': partner_id[0],
'name': vals.get('ref'),
'debit': amount,
'credit': 0,
}
debit_id = models.execute_kw(dbname,uid,pwd,'account.move.line','create',[vals_debit],{'context' :{'check_move_validity': False}})
vals_credit = {
'company_id': 1,
'move_id': move_id,
'date': vals.get('date'),
'journal_id': vals.get('journal_id'),
'account_id': credit_account_id[0],
'partner_id': partner_id[0],
'name': vals.get('ref'),
'debit': 0,
'credit': amount,
}
credit_id = models.execute_kw(dbname,uid,pwd,'account.move.line',\
​'create',[vals_credit],{'context' :{'check_move_validity': False}})
post_id = models.execute_kw(dbname,uid,pwd,'account.move',\
​'action_post',[move_id])
print(post_id)

Lo que crea asientos de la siguiente manera


Ahora, si queremos comprobar que la cuenta corriente este actualizada, creemos una nota de crédito para de $1,800 para el cliente Azure Interior. Al validarla, veremos que tenemos como saldo pendiente los asientos que acabamos de crear:


Más o menos a grandes rasgos este es el proceso para cargar saldos de cuenta corriente. En este caso se ejemplificó clientes pero se puede cargar el saldo de proveedores también (solo se debe cambiar las cuentas y los saldos). Lo mismo cualquier otra deuda con un contacto (solo hay que entender la contabilidad de la misma). Y para cargar deuda en otra moneda (por ejemplo USD) solo necesita un par de modificaciones. 

Si no tiene experiencia o no entiende la ccontabilidad, probar el script con un contador, así se asegura de los resultados. Por último, el código se encuentra disponible para su descarga en github.





Gustavo Orrillo 12 de julio de 2023
Compartir
Categorías
Archivar
Identificarse dejar un comentario