oc-trytond-configuracion_in.../configurar_tryton.md

43 KiB

Table of Contents

  1. Configuración Etrivial de Tryton
    1. Contexto
      1. imports necesarios
      2. datos de la empresa
      3. Parametros de la configuración del Tryton
    2. Funciones
    3. Main
    4. Manejo de argumentos
    5. Script completo

Configuración Etrivial de Tryton

Si se desea se puede agregar la información de la empresa en un archivo empresa.py junto a este script el cual debe contener una variable EMPRESA con los datos de la empresa.

Contexto

imports necesarios

#!/usr/bin/env python
import os
import sys

from decimal import Decimal
from argparse import ArgumentParser
from datetime import date, timedelta
from dateutil.relativedelta import relativedelta

try:
    from proteus import Model, config, Wizard
    from proteus.config import get_config
    from trytond.transaction import Transaction
except ImportError:
    prog = os.path.basename(sys.argv[0])
    sys.exit("proteus must be installed to use %s" % prog)

datos de la empresa

Importar informacion de la empresa de un archivo py

try:
    from configuracion import EMPRESA
except  ImportError:
    EMPRESA = {
    'nombre': "Nombre Empresa",
    'telefonos': ['0000000'],
    'celulares': ['0000000000'],
    'identificador': '',
    'calle': '',
    'zona horaria': "America/Bogota",
    'listas de precios': ['lista1', 'lista2'],
    'tercero mostrador': 'Mostrador',
    'moneda': 'COP'
    }

Parametros de la configuración del Tryton

  1. Módulos a activar

    MODULOS_NECESARIOS = set([
        'currency',
        'country',
        'party',
        'company',
        'account',
        'trytonpsk_account_co_pyme',
        'product',
        'sale',
        'purchase',
        'sale_shop',
        'sale_payment',
        'sale_pos',
        'account_stock_continental',
        'one_click_for_sale',
        'one_click_for_purchase',
        'account_invoice_expenses',
        'sale_payment_form',
        'sale_w_tax',
        'sale_pos_extras'
    ])
    
  2. Cuentas requeridas en la configuracion

    CUENTA_CAJA = "110505"
    CUENTA_BANCO = "11100501"
    CUENTA_A_COBRAR = "130505"
    CUENTA_A_PAGAR = "220505"
    CUENTA_COMPRAS_PADRE = "6135"
    CUENTA_COMPRAS = "613520"
    CUENTA_COMPRAS_NOMBRE = "Venta de productos en almacenes no especializados".upper()
    TIPO_CUENTA_COMPRAS = 'COSTO DE VENTAS Y OPERACIÓN'
    CUENTA_INGRESOS = "413520"
    CUENTA_PADRE_EXISTENCIAS = "1435"
    TIPO_PADRE_EXISTENCIAS = "UTILIDAD ANTES DE IMPUESTOS"
    CUENTA_EXISTENCIA = "143501"
    CUENTA_EXISTENCIA_COMPRAS = "143502"
    CUENTA_EXISTENCIA_COMPRAS_NOMBRE = "EXISTENCIAS COMPRAS"
    TIPO_CUENTA_EXISTENCIA_COMPRAS = "EXISTENCIAS COMPRAS"
    CUENTA_EXISTENCIA_VENTAS = "143503"
    CUENTA_EXISTENCIA_VENTAS_NOMBRE = "EXISTENCIAS VENTAS"
    TIPO_CUENTA_EXISTENCIA_VENTAS = "EXISTENCIAS VENTAS"
    CUENTA_EXISTENCIA_PERDIDO_NOMBRE = "EXISTENCIAS PERDIDO ENCONTRADO"
    CUENTA_EXISTENCIA_PERDIDO = "143504"
    TIPO_CUENTA_EXISTENCIA_PERDIDO = "EXISTENCIAS PERDIDO ENCONTRADO"
    CUENTA_PATRIMONIO_FACTURA_INICIAL = "311505"
    
  3. Categorías contables

    CATEGORIA_CONTABLE_PRODUCTOS = "CACHARRO"
    CATEGORIA_CONTABLE_GASTOS = "GASTOS"
    
  4. Preferencias de Empresa

    TIME_ZONE = EMPRESA.get('zona horaria', "America/Bogota")
    CURRENCY = EMPRESA.get('moneda', "COP")
    
  5. Lista de precios

    LISTAS_PRECIOS = EMPRESA.get('listas de precios', [])
    
  6. Tercero Genérico

    NOMBRE_TERCERO_MOSTRADOR = EMPRESA.get('tercero mostrador', 'Mostrador')
    
  7. Ajuste de unidades de productos

    CIFRAS_KILOGRAMO = 4
    

Funciones

Se deben de pasar a un archivo(modulo python) aparte y ser importadas en este script. También sería útil documentarlas.

def get_cuenta_gastos(codigo, tipo):
    Cuenta = Model.get('account.account')
    CuentaTipo = Model.get('account.account.type')
    tipo_gasto, = CuentaTipo.find([('name', '=', tipo)])
    cuenta, = Cuenta.find([('code', '=', codigo)])
    cuenta.template_override = True
    cuenta.type = tipo_gasto
    cuenta.save()
    return cuenta

def crear_tipo_cuenta(nombre, statement, nombre_padre, empresa=None, existencia=False, ingreso=False, gasto=False, asiento=False):
    CuentaTipo = Model.get('account.account.type')
    padre, = CuentaTipo.find([('name', '=', nombre_padre)])
    cuentatipo = CuentaTipo(name=nombre,
		statement=statement,
		parent=padre,
		stock=existencia,
		revenue=ingreso,
		expense=gasto,
		assets=asiento)
    cuentatipo.save()
    return cuentatipo

def crear_cuenta(nombre, codigo, tipo, padre, company, activa=True,
	 cerrada=False, en_balance=True,
	 reconcile=False):
    Cuenta = Model.get('account.account')
    parent, = Cuenta.find([('code', '=', padre)])
    cuenta = Cuenta(name=nombre, code=codigo,
	    type=tipo, active=activa,
	    closed=cerrada, reconcile=reconcile,
	    parent=parent,
	    general_ledger_balance=en_balance)
    cuenta.save()
    return cuenta

def activate_modules(modules):
    if isinstance(modules, str):
	modules = [modules]
    Module = Model.get('ir.module')
    records = Module.find([
    ('name', 'in', modules),
    ])
    assert len(records) == len(modules), f"faltan los modulos {set(modules).difference(set(r.name for r in records))}"
    Module.click(records, 'activate')
    Wizard('ir.module.activate_upgrade').execute('upgrade')

def get_company(config=None):
    "Return the only company"
    Company = Model.get('company.company', config=config)
    company, = Company.find()
    return company

def create_party(nombre, telefonos=None, celulares=None, identificador=None, calle=""):
    Party = Model.get('party.party')
    party = Party(name=nombre)
    if identificador:
	_ = party.identifiers.new(code=identificador)
    if telefonos:
	for tel in telefonos:
	    _ = party.contact_mechanisms.new(type='phone', value=tel)
    if celulares:
	for celular in celulares:
	    _ = party.contact_mechanisms.new(type='mobile', value=celular)
    party.save()
    if calle:
	adress, = party.addresses
	adress.street = calle
	adress.save()
    return party

def create_company(party, currency, timezone=None, config=None):
    "Create the company using the proteus config"
    Party = Model.get('party.party', config=config)
    User = Model.get('res.user', config=config)

    company_config = Wizard('company.company.config')
    company_config.execute('company')
    company = company_config.form
    if not party:
	party = Party(name='Dunder Mifflin')
	party.save()
    company.party = party
    company.currency = currency
    company_config.execute('add')

    if not config:
	config = get_config()
    config._context = User.get_preferences(True, {})
    return company_config

def create_fiscalyear(company=None, today=None, config=None):
    "Create a fiscal year for the company on today"
    FiscalYear = Model.get('account.fiscalyear', config=config)
    Sequence = Model.get('ir.sequence', config=config)

    if not company:
	company = get_company()

    if not today:
	today = date.today()

    fiscalyear = FiscalYear(name=str(today.year))
    fiscalyear.start_date = today + relativedelta(month=1, day=1)
    fiscalyear.end_date = today + relativedelta(month=12, day=31)
    fiscalyear.company = company

    post_move_sequence = Sequence(
	name=f"Asiento contabilizado {str(today.year)}",
	code='account.move',
	company=company)
    post_move_sequence.save()
    fiscalyear.post_move_sequence = post_move_sequence
    fiscalyear.account_stock_method = 'continental'
    return fiscalyear

def create_chart(
	company=None, chart='account.account_template_root_en', config=None):
    "Create chart of accounts"
    AccountTemplate = Model.get('account.account.template', config=config)
    CuentaTipo = Model.get('account.account.type')
    ModelData = Model.get('ir.model.data')

    if not company:
	company = get_company()

    module, xml_id = chart.split('.')
    data, = ModelData.find([
	('module', '=', module),
	('fs_id', '=', xml_id),
    ], limit=1)

    account_template = AccountTemplate(data.db_id)

    create_chart = Wizard('account.create_chart')
    create_chart.execute('account')
    create_chart.form.account_template = account_template
    create_chart.form.company = company
    create_chart.execute('create_account')


    Account = Model.get('account.account')
    receivable, = Account.find([('company', '=', company.id),
				('code', '=', CUENTA_A_COBRAR)])
    payable, = Account.find([('company', '=', company.id),
			     ('code', '=', CUENTA_A_PAGAR)])
    tipo_cuenta_compra, = CuentaTipo.find([('name', '=', TIPO_CUENTA_COMPRAS)])
    cuenta_compras = crear_cuenta(
	CUENTA_COMPRAS_NOMBRE,
    CUENTA_COMPRAS,
	tipo_cuenta_compra,
	CUENTA_COMPRAS_PADRE,
	company, en_balance=True
    )
    expense = cuenta_compras
    revenue, = Account.find([('company', '=', company.id),
		     ('code', '=', CUENTA_INGRESOS)])
    create_chart.form.account_receivable = receivable
    create_chart.form.account_payable = payable
    create_chart.form.category_account_expense = expense
    create_chart.form.category_account_revenue = revenue
    create_chart.execute('create_properties')
    return create_chart

def set_fiscalyear_invoice_sequences(fiscalyear, config=None):
    "Set invoice sequences to fiscalyear"
    SequenceStrict = Model.get('ir.sequence.strict', config=config)

    in_invoice_seq = SequenceStrict(
	name=f"Factura Proveedor {fiscalyear.name}",
	code='account.invoice',
	company=fiscalyear.company)
    in_invoice_seq.save()
    in_credit_note_seq = SequenceStrict(
	name=f"Abono Proveedor {fiscalyear.name}",
	code='account.invoice',
	company=fiscalyear.company)
    in_credit_note_seq.save()
    out_invoice_seq = SequenceStrict(
	name=f"Factura Cliente {fiscalyear.name}",
	code='account.invoice',
	company=fiscalyear.company)
    out_invoice_seq.save()
    out_credit_note_seq = SequenceStrict(
	name=f"Abono Cliente {fiscalyear.name}",
	code='account.invoice',
	company=fiscalyear.company)
    out_credit_note_seq.save()

    seq, = fiscalyear.invoice_sequences
    seq.out_invoice_sequence = out_invoice_seq
    seq.in_invoice_sequence = in_invoice_seq
    seq.out_credit_note_sequence = out_credit_note_seq
    seq.in_credit_note_sequence = in_credit_note_seq
    return fiscalyear

def crear_categoria_contable_producto(
	nombre, cuenta_gastos, cuenta_ingresos,
	cuenta_existencia, cuenta_existencia_cliente, cuenta_existencia_proveedor,
	cuenta_existencia_perdido_encontrado):
    CategoriaContable = Model.get('product.category')
    Account = Model.get('account.account')

    categoria_contable = CategoriaContable(
	name=nombre)
    categoria_contable.accounting = True
    categoria_contable.account_expense = cuenta_gastos
    categoria_contable.account_revenue = cuenta_ingresos
    categoria_contable.account_stock = cuenta_existencia
    categoria_contable.account_stock_lost_found = cuenta_existencia_perdido_encontrado
    categoria_contable.account_stock_customer = cuenta_existencia_cliente
    categoria_contable.account_stock_supplier = cuenta_existencia_proveedor
    categoria_contable.save()
    return categoria_contable

def verificar_modulos_necesarios():
    pass

def instalar_modulos_necesarios():
    pass

def configurar_modulos():
    pass

Main

def main(database, config_file=None):
    """ para correr desde ipyhton ejecutar:
    database = 'auto'
    config_file = '/home/yoloarreglo/trytond.conf'
    """
    config.set_trytond(database, config_file=config_file)
    #activar modulos
    activate_modules(MODULOS_NECESARIOS)
    Party = Model.get('party.party')
    Account = Model.get('account.account')
    Currency = Model.get('currency.currency')
    CuentaTipo = Model.get('account.account.type')
    ListaPrecio = Model.get('product.price_list')
    Uom = Model.get('product.uom')
    Journal = Model.get('account.journal')
    PaymentMethod = Model.get('account.invoice.payment.method')
    Sequence = Model.get('ir.sequence')
    Tienda = Model.get('sale.shop')
    Almacen = Model.get('stock.location')
    Usuario = Model.get('res.user')

    today = date.today()
    start_date = today + relativedelta(month=1, day=1)
    end_date = today + relativedelta(month=12, day=31)
    # crear tercero de empresa
    party = create_party(EMPRESA['nombre'], EMPRESA['telefonos'],
		 EMPRESA['celulares'], EMPRESA['identificador'],
		 EMPRESA['calle'])
    # Moneda para empresa
    currency, = Currency.find([('code', '=', CURRENCY)])
    # agregar cambio a moneda para reportes de ventas
    currency.rates.new(date=start_date - timedelta(days=1),
	   rate=Decimal(1.00))
    currency.save()

    # Configurar Empresa
    _ = create_company(party, currency)
    company = get_company()
    # Agregar zona horaria a empresa
    company.timezone = TIME_ZONE
    company.save()
    # Crear año Fiscal
    fiscalyear = set_fiscalyear_invoice_sequences(
	create_fiscalyear(company))
    fiscalyear.click('create_period')
    # Crear plan de cuentas
    chart = create_chart(chart='trytonpsk_account_co_pyme.pc')
    # desactivar tercero requerido para cuenta caja general
    cuenta_caja, = Account.find([('code', '=', CUENTA_CAJA)])
    cuenta_caja.template_override = True
    cuenta_caja.party_required = False
    cuenta_caja.save()
    # desactivar tercero requerido para cuenta existencias
    cuenta_existencia, = Account.find([('company', '=', company.id),
		   ('code', '=', CUENTA_EXISTENCIA)])
    cuenta_existencia.template_override = True
    cuenta_existencia.party_required = False
    cuenta_existencia.save()
    cuenta_compras, = Account.find([('code', '=', CUENTA_COMPRAS)])
    # Ajustar kilo
    kilogram, = Uom.find([('name', 'in', ('Kilogram', 'Kilogramo'))])
    kilogram.digits = CIFRAS_KILOGRAMO
    kilogram.rounding = 1.0 / (10 ** CIFRAS_KILOGRAMO)
    kilogram.save()
    # crear cuentas para inventario
    # tipo_existencia, = CuentaTipo.find(
    #     [('name', '=', 'INVENTARIOS')])
    tipo_existencia_perdido = crear_tipo_cuenta(
	nombre=TIPO_CUENTA_EXISTENCIA_PERDIDO,
	statement='income',
	nombre_padre=TIPO_PADRE_EXISTENCIAS,
	empresa=company, existencia=True)
    tipo_existencia_compra = crear_tipo_cuenta(
	nombre=TIPO_CUENTA_EXISTENCIA_COMPRAS,
	statement='income',
	nombre_padre=TIPO_PADRE_EXISTENCIAS,
	empresa=company, existencia=True)
    tipo_existencia_venta = crear_tipo_cuenta(
	nombre=TIPO_CUENTA_EXISTENCIA_VENTAS,
	statement='income',
	nombre_padre=TIPO_PADRE_EXISTENCIAS,
	empresa=company, existencia=True)
    cuenta_existencia_perdido = crear_cuenta(
	CUENTA_EXISTENCIA_PERDIDO_NOMBRE,
	CUENTA_EXISTENCIA_PERDIDO,
	tipo_existencia_perdido,
	CUENTA_PADRE_EXISTENCIAS,
	company, en_balance=True
    )
    cuenta_existencia_venta = crear_cuenta(
	CUENTA_EXISTENCIA_VENTAS_NOMBRE,
	CUENTA_EXISTENCIA_VENTAS,
	tipo_existencia_venta,
	CUENTA_PADRE_EXISTENCIAS,
	company, en_balance=True
    )
    cuenta_existencia_compra = crear_cuenta(
	CUENTA_EXISTENCIA_COMPRAS_NOMBRE,
	CUENTA_EXISTENCIA_COMPRAS,
	tipo_existencia_compra,
	CUENTA_PADRE_EXISTENCIAS,
	company, en_balance=True
    )
    # crear categoria contable para producto
    categoria_contable_producto = crear_categoria_contable_producto(
	CATEGORIA_CONTABLE_PRODUCTOS,
	cuenta_compras,
	chart.form.category_account_revenue,
	cuenta_existencia,
	cuenta_existencia_venta,
	cuenta_existencia_compra,
	cuenta_existencia_perdido)

    # crear listas precios
    for lista in LISTAS_PRECIOS:
	ListaPrecio(name=lista).save()

    # crear Metodos de pago Efectivo
    journal_cash, = Journal.find([('type', '=', 'cash')])
    payment_method = PaymentMethod()
    payment_method.name = 'Efectivo'
    payment_method.journal = journal_cash
    payment_method.credit_account = cuenta_caja
    payment_method.debit_account = cuenta_caja
    payment_method.save()

    # crear Metodos de pago Factura inicial
    cuenta_pago_patrimonio, = Account.find(
	[('code', '=', CUENTA_PATRIMONIO_FACTURA_INICIAL)])
    journal_cash, = Journal.find([('type', '=', 'cash')])
    payment_method = PaymentMethod()
    payment_method.name = 'Factura Inicial'
    payment_method.journal = journal_cash #@todo verificar si es este diario
    payment_method.credit_account = cuenta_pago_patrimonio
    payment_method.debit_account = cuenta_pago_patrimonio
    payment_method.save()

    # configurar almacen
    almacen, = Almacen.find([('name', 'in', ('Warehouse', 'Almacén'))])
    almacen.input_location = almacen.storage_location
    almacen.output_location = almacen.storage_location
    almacen.save()
    # configurar tienda
    mostrador = Party(name=NOMBRE_TERCERO_MOSTRADOR)
    mostrador.save()
    admin, = Usuario.find([('login', '=', 'admin')])
    tienda = Tienda(name="Principal", company=company,
		warehouse=almacen)
    tienda.users.append(admin)
    tienda.party = mostrador
    tienda.self_pick_up = True
    tienda.save()

    # secuencias necesarias
    Sequence = Model.get('ir.sequence')
    secuencia_libro_ingresos, = Sequence.find([('name', '=', 'Libro Ingresos')])
    secuencia_libro_bancos, = Sequence.find([('name', '=', 'Libro Bancos')])
    secuencia_de_compra, = Sequence.find([('name', '=', 'Purchase')])

    # crear diarios tipo registros para diarios de pagos
    journal_pago_efectivo = Journal(
	name='Efectivo PTV', code='EPTV', active=True,
	type='statement', sequence=secuencia_libro_bancos)
    journal_pago_efectivo.save()

    journal_pago_banco = Journal(
	name='Banco PTV', code='BPTV', active=True,
	type='statement', sequence=secuencia_libro_bancos)
    journal_pago_banco.save()

    # cuenta banco
    cuenta_banco, = Account.find([('code', '=', CUENTA_BANCO)])
    cuenta_banco.template_override = True
    cuenta_banco.party_required = False
    cuenta_banco.save()

    #crear diarios de pagos
    StatementJournal = Model.get('account.statement.journal')
    diario_de_pago_efectivo = StatementJournal(
	name="Efectivo", journal=journal_pago_efectivo,
	account=cuenta_caja, validation='balance')
    diario_de_pago_efectivo.save()
    diario_de_pago_banco = StatementJournal(
	name="Banco", journal=journal_pago_banco, account=cuenta_banco,
	validation='balance')
    diario_de_pago_banco.save()

    #configurar ptv
    Device = Model.get('sale.device')
    device = Device(name='Principal')
    device.change_unit_price = True
    # error cuando agrega la tienda por primera vez
    try:
	device.shop = tienda
    except:
	pass
    device.shop = tienda
    device.journals.extend([diario_de_pago_banco, diario_de_pago_efectivo])
    device.journal = diario_de_pago_efectivo
    device.save()
    #configurar ptv a usuario administrador
    admin.shop = tienda
    admin.sale_device = device
    #ajustar idioma español al administrador
    Lang = Model.get('ir.lang')
    es, = Lang.find([('code', '=', 'es')])
    admin.language = es
    admin.save()

    # configurando destino de compras por defecto
    ConfPurchase = Model.get('purchase.configuration')
    conf_compra = ConfPurchase(1)
    conf_compra.purchase_sequence = secuencia_de_compra
    conf_compra.one_click_to_location = almacen.storage_location
    conf_compra.save()

    # configurando metodo de coste por defecto de productos
    ProductConf = Model.get('product.configuration')
    conf_producto = ProductConf(1)
    conf_producto.default_cost_price_method = 'average'
    conf_producto.save()

Manejo de argumentos

def run():
    print("#################################")
    print("Recuerde Iniciar la base de datos")
    print("createdb base_datos")
    print("trytond-admin -c trytond.conf --all -d base_datos -l es")
    print("trytond-admin -c trytond.conf  -d base_datos -u country")
    print("python enlace_a_modules/country/scripts/import_countries.py -c trytond.conf -d base_datos")
    print("trytond-admin -c trytond.conf  -d auto -u currency")
    print("python enlace_a_modules/currency/scripts/import_currencies.py -c trytond.conf -d base_datos")
    print("#################################")


    parser = ArgumentParser()
    parser.add_argument('-d', '--database', dest='database')
    parser.add_argument('-c', '--config', dest='config_file',
		help='the trytond config file')

    args = parser.parse_args()
    if not args.database:
	parser.error('Missing database')
    main(args.database, args.config_file)

if __name__ == '__main__':
    run()

Script completo

#!/usr/bin/env python
import os
import sys

from decimal import Decimal
from argparse import ArgumentParser
from datetime import date, timedelta
from dateutil.relativedelta import relativedelta

try:
    from proteus import Model, config, Wizard
    from proteus.config import get_config
    from trytond.transaction import Transaction
except ImportError:
    prog = os.path.basename(sys.argv[0])
    sys.exit("proteus must be installed to use %s" % prog)
try:
    from configuracion import EMPRESA
except  ImportError:
    EMPRESA = {
    'nombre': "Nombre Empresa",
    'telefonos': ['0000000'],
    'celulares': ['0000000000'],
    'identificador': '',
    'calle': '',
    'zona horaria': "America/Bogota",
    'listas de precios': ['lista1', 'lista2'],
    'tercero mostrador': 'Mostrador',
    'moneda': 'COP'
    }
MODULOS_NECESARIOS = set([
    'currency',
    'country',
    'party',
    'company',
    'account',
    'trytonpsk_account_co_pyme',
    'product',
    'sale',
    'purchase',
    'sale_shop',
    'sale_payment',
    'sale_pos',
    'account_stock_continental',
    'one_click_for_sale',
    'one_click_for_purchase',
    'account_invoice_expenses',
    'sale_payment_form',
    'sale_w_tax',
    'sale_pos_extras'
])
CUENTA_CAJA = "110505"
CUENTA_BANCO = "11100501"
CUENTA_A_COBRAR = "130505"
CUENTA_A_PAGAR = "220505"
CUENTA_COMPRAS_PADRE = "6135"
CUENTA_COMPRAS = "613520"
CUENTA_COMPRAS_NOMBRE = "Venta de productos en almacenes no especializados".upper()
TIPO_CUENTA_COMPRAS = 'COSTO DE VENTAS Y OPERACIÓN'
CUENTA_INGRESOS = "413520"
CUENTA_PADRE_EXISTENCIAS = "1435"
TIPO_PADRE_EXISTENCIAS = "UTILIDAD ANTES DE IMPUESTOS"
CUENTA_EXISTENCIA = "143501"
CUENTA_EXISTENCIA_COMPRAS = "143502"
CUENTA_EXISTENCIA_COMPRAS_NOMBRE = "EXISTENCIAS COMPRAS"
TIPO_CUENTA_EXISTENCIA_COMPRAS = "EXISTENCIAS COMPRAS"
CUENTA_EXISTENCIA_VENTAS = "143503"
CUENTA_EXISTENCIA_VENTAS_NOMBRE = "EXISTENCIAS VENTAS"
TIPO_CUENTA_EXISTENCIA_VENTAS = "EXISTENCIAS VENTAS"
CUENTA_EXISTENCIA_PERDIDO_NOMBRE = "EXISTENCIAS PERDIDO ENCONTRADO"
CUENTA_EXISTENCIA_PERDIDO = "143504"
TIPO_CUENTA_EXISTENCIA_PERDIDO = "EXISTENCIAS PERDIDO ENCONTRADO"
CUENTA_PATRIMONIO_FACTURA_INICIAL = "311505"
CATEGORIA_CONTABLE_PRODUCTOS = "CACHARRO"
CATEGORIA_CONTABLE_GASTOS = "GASTOS"
TIME_ZONE = EMPRESA.get('zona horaria', "America/Bogota")
CURRENCY = EMPRESA.get('moneda', "COP")
LISTAS_PRECIOS = EMPRESA.get('listas de precios', [])
NOMBRE_TERCERO_MOSTRADOR = EMPRESA.get('tercero mostrador', 'Mostrador')
CIFRAS_KILOGRAMO = 4
def get_cuenta_gastos(codigo, tipo):
    Cuenta = Model.get('account.account')
    CuentaTipo = Model.get('account.account.type')
    tipo_gasto, = CuentaTipo.find([('name', '=', tipo)])
    cuenta, = Cuenta.find([('code', '=', codigo)])
    cuenta.template_override = True
    cuenta.type = tipo_gasto
    cuenta.save()
    return cuenta

def crear_tipo_cuenta(nombre, statement, nombre_padre, empresa=None, existencia=False, ingreso=False, gasto=False, asiento=False):
    CuentaTipo = Model.get('account.account.type')
    padre, = CuentaTipo.find([('name', '=', nombre_padre)])
    cuentatipo = CuentaTipo(name=nombre,
		statement=statement,
		parent=padre,
		stock=existencia,
		revenue=ingreso,
		expense=gasto,
		assets=asiento)
    cuentatipo.save()
    return cuentatipo

def crear_cuenta(nombre, codigo, tipo, padre, company, activa=True,
	 cerrada=False, en_balance=True,
	 reconcile=False):
    Cuenta = Model.get('account.account')
    parent, = Cuenta.find([('code', '=', padre)])
    cuenta = Cuenta(name=nombre, code=codigo,
	    type=tipo, active=activa,
	    closed=cerrada, reconcile=reconcile,
	    parent=parent,
	    general_ledger_balance=en_balance)
    cuenta.save()
    return cuenta

def activate_modules(modules):
    if isinstance(modules, str):
	modules = [modules]
    Module = Model.get('ir.module')
    records = Module.find([
    ('name', 'in', modules),
    ])
    assert len(records) == len(modules), f"faltan los modulos {set(modules).difference(set(r.name for r in records))}"
    Module.click(records, 'activate')
    Wizard('ir.module.activate_upgrade').execute('upgrade')

def get_company(config=None):
    "Return the only company"
    Company = Model.get('company.company', config=config)
    company, = Company.find()
    return company

def create_party(nombre, telefonos=None, celulares=None, identificador=None, calle=""):
    Party = Model.get('party.party')
    party = Party(name=nombre)
    if identificador:
	_ = party.identifiers.new(code=identificador)
    if telefonos:
	for tel in telefonos:
	    _ = party.contact_mechanisms.new(type='phone', value=tel)
    if celulares:
	for celular in celulares:
	    _ = party.contact_mechanisms.new(type='mobile', value=celular)
    party.save()
    if calle:
	adress, = party.addresses
	adress.street = calle
	adress.save()
    return party

def create_company(party, currency, timezone=None, config=None):
    "Create the company using the proteus config"
    Party = Model.get('party.party', config=config)
    User = Model.get('res.user', config=config)

    company_config = Wizard('company.company.config')
    company_config.execute('company')
    company = company_config.form
    if not party:
	party = Party(name='Dunder Mifflin')
	party.save()
    company.party = party
    company.currency = currency
    company_config.execute('add')

    if not config:
	config = get_config()
    config._context = User.get_preferences(True, {})
    return company_config

def create_fiscalyear(company=None, today=None, config=None):
    "Create a fiscal year for the company on today"
    FiscalYear = Model.get('account.fiscalyear', config=config)
    Sequence = Model.get('ir.sequence', config=config)

    if not company:
	company = get_company()

    if not today:
	today = date.today()

    fiscalyear = FiscalYear(name=str(today.year))
    fiscalyear.start_date = today + relativedelta(month=1, day=1)
    fiscalyear.end_date = today + relativedelta(month=12, day=31)
    fiscalyear.company = company

    post_move_sequence = Sequence(
	name=f"Asiento contabilizado {str(today.year)}",
	code='account.move',
	company=company)
    post_move_sequence.save()
    fiscalyear.post_move_sequence = post_move_sequence
    fiscalyear.account_stock_method = 'continental'
    return fiscalyear

def create_chart(
	company=None, chart='account.account_template_root_en', config=None):
    "Create chart of accounts"
    AccountTemplate = Model.get('account.account.template', config=config)
    CuentaTipo = Model.get('account.account.type')
    ModelData = Model.get('ir.model.data')

    if not company:
	company = get_company()

    module, xml_id = chart.split('.')
    data, = ModelData.find([
	('module', '=', module),
	('fs_id', '=', xml_id),
    ], limit=1)

    account_template = AccountTemplate(data.db_id)

    create_chart = Wizard('account.create_chart')
    create_chart.execute('account')
    create_chart.form.account_template = account_template
    create_chart.form.company = company
    create_chart.execute('create_account')


    Account = Model.get('account.account')
    receivable, = Account.find([('company', '=', company.id),
				('code', '=', CUENTA_A_COBRAR)])
    payable, = Account.find([('company', '=', company.id),
			     ('code', '=', CUENTA_A_PAGAR)])
    tipo_cuenta_compra, = CuentaTipo.find([('name', '=', TIPO_CUENTA_COMPRAS)])
    cuenta_compras = crear_cuenta(
	CUENTA_COMPRAS_NOMBRE,
    CUENTA_COMPRAS,
	tipo_cuenta_compra,
	CUENTA_COMPRAS_PADRE,
	company, en_balance=True
    )
    expense = cuenta_compras
    revenue, = Account.find([('company', '=', company.id),
		     ('code', '=', CUENTA_INGRESOS)])
    create_chart.form.account_receivable = receivable
    create_chart.form.account_payable = payable
    create_chart.form.category_account_expense = expense
    create_chart.form.category_account_revenue = revenue
    create_chart.execute('create_properties')
    return create_chart

def set_fiscalyear_invoice_sequences(fiscalyear, config=None):
    "Set invoice sequences to fiscalyear"
    SequenceStrict = Model.get('ir.sequence.strict', config=config)

    in_invoice_seq = SequenceStrict(
	name=f"Factura Proveedor {fiscalyear.name}",
	code='account.invoice',
	company=fiscalyear.company)
    in_invoice_seq.save()
    in_credit_note_seq = SequenceStrict(
	name=f"Abono Proveedor {fiscalyear.name}",
	code='account.invoice',
	company=fiscalyear.company)
    in_credit_note_seq.save()
    out_invoice_seq = SequenceStrict(
	name=f"Factura Cliente {fiscalyear.name}",
	code='account.invoice',
	company=fiscalyear.company)
    out_invoice_seq.save()
    out_credit_note_seq = SequenceStrict(
	name=f"Abono Cliente {fiscalyear.name}",
	code='account.invoice',
	company=fiscalyear.company)
    out_credit_note_seq.save()

    seq, = fiscalyear.invoice_sequences
    seq.out_invoice_sequence = out_invoice_seq
    seq.in_invoice_sequence = in_invoice_seq
    seq.out_credit_note_sequence = out_credit_note_seq
    seq.in_credit_note_sequence = in_credit_note_seq
    return fiscalyear

def crear_categoria_contable_producto(
	nombre, cuenta_gastos, cuenta_ingresos,
	cuenta_existencia, cuenta_existencia_cliente, cuenta_existencia_proveedor,
	cuenta_existencia_perdido_encontrado):
    CategoriaContable = Model.get('product.category')
    Account = Model.get('account.account')

    categoria_contable = CategoriaContable(
	name=nombre)
    categoria_contable.accounting = True
    categoria_contable.account_expense = cuenta_gastos
    categoria_contable.account_revenue = cuenta_ingresos
    categoria_contable.account_stock = cuenta_existencia
    categoria_contable.account_stock_lost_found = cuenta_existencia_perdido_encontrado
    categoria_contable.account_stock_customer = cuenta_existencia_cliente
    categoria_contable.account_stock_supplier = cuenta_existencia_proveedor
    categoria_contable.save()
    return categoria_contable

def verificar_modulos_necesarios():
    pass

def instalar_modulos_necesarios():
    pass

def configurar_modulos():
    pass
def main(database, config_file=None):
    """ para correr desde ipyhton ejecutar:
    database = 'auto'
    config_file = '/home/yoloarreglo/trytond.conf'
    """
    config.set_trytond(database, config_file=config_file)
    #activar modulos
    activate_modules(MODULOS_NECESARIOS)
    Party = Model.get('party.party')
    Account = Model.get('account.account')
    Currency = Model.get('currency.currency')
    CuentaTipo = Model.get('account.account.type')
    ListaPrecio = Model.get('product.price_list')
    Uom = Model.get('product.uom')
    Journal = Model.get('account.journal')
    PaymentMethod = Model.get('account.invoice.payment.method')
    Sequence = Model.get('ir.sequence')
    Tienda = Model.get('sale.shop')
    Almacen = Model.get('stock.location')
    Usuario = Model.get('res.user')

    today = date.today()
    start_date = today + relativedelta(month=1, day=1)
    end_date = today + relativedelta(month=12, day=31)
    # crear tercero de empresa
    party = create_party(EMPRESA['nombre'], EMPRESA['telefonos'],
		 EMPRESA['celulares'], EMPRESA['identificador'],
		 EMPRESA['calle'])
    # Moneda para empresa
    currency, = Currency.find([('code', '=', CURRENCY)])
    # agregar cambio a moneda para reportes de ventas
    currency.rates.new(date=start_date - timedelta(days=1),
	   rate=Decimal(1.00))
    currency.save()

    # Configurar Empresa
    _ = create_company(party, currency)
    company = get_company()
    # Agregar zona horaria a empresa
    company.timezone = TIME_ZONE
    company.save()
    # Crear año Fiscal
    fiscalyear = set_fiscalyear_invoice_sequences(
	create_fiscalyear(company))
    fiscalyear.click('create_period')
    # Crear plan de cuentas
    chart = create_chart(chart='trytonpsk_account_co_pyme.pc')
    # desactivar tercero requerido para cuenta caja general
    cuenta_caja, = Account.find([('code', '=', CUENTA_CAJA)])
    cuenta_caja.template_override = True
    cuenta_caja.party_required = False
    cuenta_caja.save()
    # desactivar tercero requerido para cuenta existencias
    cuenta_existencia, = Account.find([('company', '=', company.id),
		   ('code', '=', CUENTA_EXISTENCIA)])
    cuenta_existencia.template_override = True
    cuenta_existencia.party_required = False
    cuenta_existencia.save()
    cuenta_compras, = Account.find([('code', '=', CUENTA_COMPRAS)])
    # Ajustar kilo
    kilogram, = Uom.find([('name', 'in', ('Kilogram', 'Kilogramo'))])
    kilogram.digits = CIFRAS_KILOGRAMO
    kilogram.rounding = 1.0 / (10 ** CIFRAS_KILOGRAMO)
    kilogram.save()
    # crear cuentas para inventario
    # tipo_existencia, = CuentaTipo.find(
    #     [('name', '=', 'INVENTARIOS')])
    tipo_existencia_perdido = crear_tipo_cuenta(
	nombre=TIPO_CUENTA_EXISTENCIA_PERDIDO,
	statement='income',
	nombre_padre=TIPO_PADRE_EXISTENCIAS,
	empresa=company, existencia=True)
    tipo_existencia_compra = crear_tipo_cuenta(
	nombre=TIPO_CUENTA_EXISTENCIA_COMPRAS,
	statement='income',
	nombre_padre=TIPO_PADRE_EXISTENCIAS,
	empresa=company, existencia=True)
    tipo_existencia_venta = crear_tipo_cuenta(
	nombre=TIPO_CUENTA_EXISTENCIA_VENTAS,
	statement='income',
	nombre_padre=TIPO_PADRE_EXISTENCIAS,
	empresa=company, existencia=True)
    cuenta_existencia_perdido = crear_cuenta(
	CUENTA_EXISTENCIA_PERDIDO_NOMBRE,
	CUENTA_EXISTENCIA_PERDIDO,
	tipo_existencia_perdido,
	CUENTA_PADRE_EXISTENCIAS,
	company, en_balance=True
    )
    cuenta_existencia_venta = crear_cuenta(
	CUENTA_EXISTENCIA_VENTAS_NOMBRE,
	CUENTA_EXISTENCIA_VENTAS,
	tipo_existencia_venta,
	CUENTA_PADRE_EXISTENCIAS,
	company, en_balance=True
    )
    cuenta_existencia_compra = crear_cuenta(
	CUENTA_EXISTENCIA_COMPRAS_NOMBRE,
	CUENTA_EXISTENCIA_COMPRAS,
	tipo_existencia_compra,
	CUENTA_PADRE_EXISTENCIAS,
	company, en_balance=True
    )
    # crear categoria contable para producto
    categoria_contable_producto = crear_categoria_contable_producto(
	CATEGORIA_CONTABLE_PRODUCTOS,
	cuenta_compras,
	chart.form.category_account_revenue,
	cuenta_existencia,
	cuenta_existencia_venta,
	cuenta_existencia_compra,
	cuenta_existencia_perdido)

    # crear listas precios
    for lista in LISTAS_PRECIOS:
	ListaPrecio(name=lista).save()

    # crear Metodos de pago Efectivo
    journal_cash, = Journal.find([('type', '=', 'cash')])
    payment_method = PaymentMethod()
    payment_method.name = 'Efectivo'
    payment_method.journal = journal_cash
    payment_method.credit_account = cuenta_caja
    payment_method.debit_account = cuenta_caja
    payment_method.save()

    # crear Metodos de pago Factura inicial
    cuenta_pago_patrimonio, = Account.find(
	[('code', '=', CUENTA_PATRIMONIO_FACTURA_INICIAL)])
    journal_cash, = Journal.find([('type', '=', 'cash')])
    payment_method = PaymentMethod()
    payment_method.name = 'Factura Inicial'
    payment_method.journal = journal_cash #@todo verificar si es este diario
    payment_method.credit_account = cuenta_pago_patrimonio
    payment_method.debit_account = cuenta_pago_patrimonio
    payment_method.save()

    # configurar almacen
    almacen, = Almacen.find([('name', 'in', ('Warehouse', 'Almacén'))])
    almacen.input_location = almacen.storage_location
    almacen.output_location = almacen.storage_location
    almacen.save()
    # configurar tienda
    mostrador = Party(name=NOMBRE_TERCERO_MOSTRADOR)
    mostrador.save()
    admin, = Usuario.find([('login', '=', 'admin')])
    tienda = Tienda(name="Principal", company=company,
		warehouse=almacen)
    tienda.users.append(admin)
    tienda.party = mostrador
    tienda.self_pick_up = True
    tienda.save()

    # secuencias necesarias
    Sequence = Model.get('ir.sequence')
    secuencia_libro_ingresos, = Sequence.find([('name', '=', 'Libro Ingresos')])
    secuencia_libro_bancos, = Sequence.find([('name', '=', 'Libro Bancos')])
    secuencia_de_compra, = Sequence.find([('name', '=', 'Purchase')])

    # crear diarios tipo registros para diarios de pagos
    journal_pago_efectivo = Journal(
	name='Efectivo PTV', code='EPTV', active=True,
	type='statement', sequence=secuencia_libro_bancos)
    journal_pago_efectivo.save()

    journal_pago_banco = Journal(
	name='Banco PTV', code='BPTV', active=True,
	type='statement', sequence=secuencia_libro_bancos)
    journal_pago_banco.save()

    # cuenta banco
    cuenta_banco, = Account.find([('code', '=', CUENTA_BANCO)])
    cuenta_banco.template_override = True
    cuenta_banco.party_required = False
    cuenta_banco.save()

    #crear diarios de pagos
    StatementJournal = Model.get('account.statement.journal')
    diario_de_pago_efectivo = StatementJournal(
	name="Efectivo", journal=journal_pago_efectivo,
	account=cuenta_caja, validation='balance')
    diario_de_pago_efectivo.save()
    diario_de_pago_banco = StatementJournal(
	name="Banco", journal=journal_pago_banco, account=cuenta_banco,
	validation='balance')
    diario_de_pago_banco.save()

    #configurar ptv
    Device = Model.get('sale.device')
    device = Device(name='Principal')
    device.change_unit_price = True
    # error cuando agrega la tienda por primera vez
    try:
	device.shop = tienda
    except:
	pass
    device.shop = tienda
    device.journals.extend([diario_de_pago_banco, diario_de_pago_efectivo])
    device.journal = diario_de_pago_efectivo
    device.save()
    #configurar ptv a usuario administrador
    admin.shop = tienda
    admin.sale_device = device
    #ajustar idioma español al administrador
    Lang = Model.get('ir.lang')
    es, = Lang.find([('code', '=', 'es')])
    admin.language = es
    admin.save()

    # configurando destino de compras por defecto
    ConfPurchase = Model.get('purchase.configuration')
    conf_compra = ConfPurchase(1)
    conf_compra.purchase_sequence = secuencia_de_compra
    conf_compra.one_click_to_location = almacen.storage_location
    conf_compra.save()

    # configurando metodo de coste por defecto de productos
    ProductConf = Model.get('product.configuration')
    conf_producto = ProductConf(1)
    conf_producto.default_cost_price_method = 'average'
    conf_producto.save()
def run():
    print("#################################")
    print("Recuerde Iniciar la base de datos")
    print("createdb base_datos")
    print("trytond-admin -c trytond.conf --all -d base_datos -l es")
    print("trytond-admin -c trytond.conf  -d base_datos -u country")
    print("python enlace_a_modules/country/scripts/import_countries.py -c trytond.conf -d base_datos")
    print("trytond-admin -c trytond.conf  -d auto -u currency")
    print("python enlace_a_modules/currency/scripts/import_currencies.py -c trytond.conf -d base_datos")
    print("#################################")


    parser = ArgumentParser()
    parser.add_argument('-d', '--database', dest='database')
    parser.add_argument('-c', '--config', dest='config_file',
		help='the trytond config file')

    args = parser.parse_args()
    if not args.database:
	parser.error('Missing database')
    main(args.database, args.config_file)

if __name__ == '__main__':
    run()