//~ Empresa Libre
//~ Copyright (C) 2016-2018  Mauricio Baeza Servin (web@correolibre.net)
//~
//~ This program is free software: you can redistribute it and/or modify
//~ it under the terms of the GNU General Public License as published by
//~ the Free Software Foundation, either version 3 of the License, or
//~ (at your option) any later version.
//~
//~ This program is distributed in the hope that it will be useful,
//~ but WITHOUT ANY WARRANTY; without even the implied warranty of
//~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//~ GNU General Public License for more details.
//~
//~ You should have received a copy of the GNU General Public License
//~ along with this program.  If not, see <http://www.gnu.org/licenses/>.

var query = []
var grid = null
var msg = ''
var result = false
var tipo_relacion = ''
var anticipo = false
var donativo = false
var cfg_invoice = new Object()
//~ var values_comercioe = null
var values_global = ''


function init_config_invoices(){
    var multi_currency = get_config('multi_currency')
    var g = $$('grid_invoices')

    if(multi_currency){
        g.showColumn('total')
        g.showColumn('currency')
    }
    show('cmd_show_global_information', false)
}


var invoices_controllers = {
    init: function(){
        //~ Invoices
        $$('cmd_new_invoice').attachEvent("onItemClick", cmd_new_invoice_click)
        $$('cmd_refacturar').attachEvent("onItemClick", cmd_refacturar_click)
        $$('cmd_invoice_report_pdf').attachEvent('onItemClick', cmd_invoice_report_pdf_click)
        $$('cmd_invoice_report_xls').attachEvent('onItemClick', cmd_invoice_report_xls_click)
        $$('cmd_delete_invoice').attachEvent("onItemClick", cmd_delete_invoice_click)
        $$('cmd_timbrar').attachEvent('onItemClick', cmd_timbrar_click)
        $$('cmd_close_invoice').attachEvent('onItemClick', cmd_close_invoice_click)
        $$('search_client_id').attachEvent('onKeyPress', search_client_id_key_press)
        $$('grid_clients_found').attachEvent('onValueSuggest', grid_clients_found_click)
        $$('search_product_id').attachEvent('onKeyPress', search_product_id_key_press)
        $$('grid_products_found').attachEvent('onValueSuggest', grid_products_found_click)
        $$('grid_students_found').attachEvent('onValueSuggest', grid_students_found_click)
        $$('grid_details').attachEvent('onItemClick', grid_details_click)
        $$('grid_details').attachEvent('onHeaderClick', grid_details_header_click)
        $$('grid_details').attachEvent('onBeforeEditStart', grid_details_before_edit_start)
        $$('grid_details').attachEvent('onBeforeEditStop', grid_details_before_edit_stop)
        $$('grid_details').attachEvent('onAfterEditStop', grid_details_after_edit_stop)
        $$('cmd_invoice_timbrar').attachEvent('onItemClick', cmd_invoice_timbrar_click)
        $$('cmd_invoice_sat').attachEvent('onItemClick', cmd_invoice_sat_click)
        $$('cmd_invoice_verify_sat').attachEvent('onItemClick', cmd_invoice_verify_sat_click)
        $$('cmd_invoice_ask_cancel').attachEvent('onItemClick', cmd_invoice_ask_cancel_click)
        $$('grid_invoices').attachEvent('onItemClick', grid_invoices_click)
        $$('grid_invoices').attachEvent('onSelectChange', grid_invoices_on_select_change)
        $$('grid_invoices').attachEvent('onHeaderClick', grid_invoices_on_header_click)
        $$('grid_invoices').attachEvent('onSubViewCreate', grid_invoices_on_subview_create)

        $$('filter_year').attachEvent('onChange', filter_year_change)
        $$('filter_month').attachEvent('onChange', filter_month_change)
        var show_filter_by_day = get_config('show_filter_by_day')
        show('filter_day', show_filter_by_day)
        if(show_filter_by_day){
            $$('filter_day').attachEvent('onChange', filter_day_change)
        }
        $$('filter_dates').attachEvent('onChange', filter_dates_change)
        $$('cmd_prefactura').attachEvent('onItemClick', cmd_prefactura_click)
        $$('cmd_preinvoice_generate_delete').attachEvent('onItemClick', cmd_preinvoice_generate_delete_click)
        $$('cmd_cfdi_relacionados').attachEvent('onItemClick', cmd_cfdi_relacionados_click)
        $$('lst_metodo_pago').attachEvent('onChange', lst_metodo_pago_change)
        $$('lst_moneda').attachEvent('onChange', lst_moneda_change)
        $$('lst_tipo_comprobante').attachEvent('onChange', lst_tipo_comprobante_change)
        $$('lst_serie').attachEvent('onChange', lst_serie_change)
        $$('txt_tipo_cambio').attachEvent('onBlur', txt_tipo_cambio_lost_focus)

        $$('cmd_cfdi_notes').attachEvent('onItemClick', cmd_cfdi_notes_click)
        $$('cmd_admin_invoice_notes').attachEvent('onItemClick', cmd_admin_invoice_notes_click)
        $$('cmd_import_invoice').attachEvent('onItemClick', cmd_import_invoice_click)

        $$('txt_folio_custom').attachEvent('onKeyPress', txt_folio_custom_key_press);
        $$('txt_folio_custom').attachEvent('onBlur', txt_folio_custom_lost_focus);

        $$('search_by').attachEvent('onKeyPress', search_by_key_press)
        $$('search_by').attachEvent('onItemClick', search_by_click)

        tv_invoice = $$('tv_invoice').getTabbar()
        tv_invoice.attachEvent('onChange', tv_invoice_change)

        //~ CartaPorte
        $$('grid_ccp_ubicaciones').attachEvent('onBeforeEditStop', grid_ccp_ubicaciones_before_edit_stop)
        $$('grid_ccp_ubicaciones').attachEvent('onItemClick', grid_ccp_ubicaciones_click)
        $$('grid_ccp_mercancias').attachEvent('onItemClick', grid_ccp_mercancias_click)
        $$('grid_ccp_remolques').attachEvent('onItemClick', grid_ccp_remolques_click)
        $$('cmd_ccp_agregar_ubicacion').attachEvent('onItemClick', cmd_ccp_agregar_ubicacion_click)
        $$('cmd_ccp_add_product').attachEvent('onItemClick', cmd_ccp_add_product_click)
        $$('cmd_ccp_agregar_remolque').attachEvent('onItemClick', cmd_ccp_agregar_remolque_click)
        //~ $$('cmd_carta_copy_from_invoice').attachEvent('onItemClick', cmd_carta_copy_from_invoice_click)
        $$('cmd_carta_import_json').attachEvent('onItemClick', cmd_carta_import_json_click)

        //~ ComercioExterior
        $$('cmd_import_json_comercioe').attachEvent('onItemClick', cmd_import_json_comercioe_click)
        $$('cmd_ce_import_ods').attachEvent('onItemClick', cmd_ce_import_ods_click)
        $$('cmd_ce_tipo_cambio').attachEvent('onItemClick', cmd_ce_tipo_cambio_click)
        $$('cmd_ce_add_propietario').attachEvent('onItemClick', cmd_ce_add_propietario_click)
        $$('cmd_ce_add_mercancia').attachEvent('onItemClick', cmd_ce_add_mercancia_click)
        $$('grid_ce_propietarios').attachEvent('onItemClick', grid_ce_propietarios_click)
        $$('grid_ce_mercancias').attachEvent('onItemClick', grid_ce_mercancias_click)

        $$('cmd_show_global_information').attachEvent('onItemClick', cmd_show_global_information_click)

        webix.extend($$('grid_invoices'), webix.ProgressBar)

        init_config_invoices()

        focus('search_client_name')
    }
}


function get_condicion_pago(){
    webix.ajax().get('/values/condicionespago', {
        error: function(text, data, xhr) {
        },
        success: function(text, data, xhr) {
            var values = data.json();
            $$('txt_condicion_pago').define('suggest', values)
            $$('txt_condicion_pago').refresh()
        }
    })
}


function get_series(){
    webix.ajax().sync().get('/values/series', function(text, data){
        var values = data.json()
        table_series.clear()
        table_series.insert(values)
        pre = values[0]
        $$('lst_serie').getList().parse(values)
        $$('lst_serie').setValue(pre.id)
        if(pre.usarcon){
            $$('lst_tipo_comprobante').setValue(pre.usarcon)
            $$('lst_tipo_comprobante').config.readonly = true
            $$('lst_tipo_comprobante').refresh()
        }
        if(values.length == 1){
            $$('lst_serie').config.readonly = true
            $$('lst_serie').refresh()
        }
    })
}


function get_monedas(){
    webix.ajax().get('/values/monedas', function(text, data){
        var values = data.json()
        pre = values[0]
        $$('lst_moneda').getList().parse(values)
        $$('lst_moneda').setValue(pre.id)
        if(values.length == 1){
            $$('fs_moneda').hide()
        }
    })
}


function get_uso_cfdi(){
    get_uso_cfdi_to_table({key: true})
    query = table_usocfdi.chain().data()
    $$('lst_uso_cfdi').getList().parse(query)
}


function get_regimen_fiscal(){
    webix.ajax().get('/values/regimenes', function(text, data){
        var values = data.json()
        pre = values[0]
        $$('lst_regimen_fiscal').getList().parse(values)
        $$('lst_regimen_fiscal').setValue(pre.id)
        if(values.length == 1){
            $$('fs_regimen_fiscal').hide()
        }
    })
}


function validar_timbrar(){
    webix.ajax().sync().get('/values/validartimbrar', function(text, data){
        var values = data.json()
        if(!values.ok){
            msg_error(values.msg)
            $$('cmd_timbrar').disable()
        }else{
            if(values.msg){
                msg_error(values.msg)
            }
            $$('cmd_timbrar').enable()
        }
    })
}


function default_config(){
    webix.ajax().sync().get('/values/taxes', function(text, data){
        var values = data.json()
        table_taxes.clear()
        table_taxes.insert(values)
    })
    get_series()
    get_forma_pago('lst_forma_pago')
    get_monedas()
    get_uso_cfdi()
    get_regimen_fiscal()
    table_pt.clear()
    table_totals.clear()

    validar_timbrar()

    webix.ajax().sync().get('/values/configtimbrar', function(text, data){
        var values = data.json()
        show('chk_cfdi_anticipo', values.cfdi_anticipo)
        show('chk_cfdi_donativo', values.cfdi_donativo)
        show('lst_metodo_pago', !values.cfdi_metodo_pago)
        show('txt_condicion_pago', !values.cfdi_condicion_pago)
        if(!values.cfdi_ine){
            $$('tv_invoice').getTabbar().hideOption('INE')
        }else{
            $$('tv_invoice').getTabbar().showOption('INE')
        }
        if(!values.cfdi_leyendasfiscales){
            $$('tv_invoice').getTabbar().hideOption('Leyendas Fiscales')
        }else{
            get_leyendas_fiscales()
            $$('tv_invoice').getTabbar().showOption('Leyendas Fiscales')
        }
        if(!values.cfdi_carta_porte){
            $$('tv_invoice').getTabbar().hideOption('Carta Porte')
        }else{
            $$('tv_invoice').getTabbar().showOption('Carta Porte')
        }
        if(!values.cfdi_comercioe){
            $$('tv_invoice').getTabbar().hideOption('Comercio Exterior')
        }else{
            $$('tv_invoice').getTabbar().showOption('Comercio Exterior')
            _set_default_comercio_exterior()
        }
        cfg_invoice['leyendasfiscales'] = values.cfdi_leyendasfiscales
        cfg_invoice['edu'] = values.cfdi_edu
        cfg_invoice['carta_porte'] = values.cfdi_carta_porte
        cfg_invoice['comercioe'] = values.cfdi_comercioe
        cfg_invoice['open_pdf'] = values.cfdi_open_pdf
        cfg_invoice['tax_locales'] = values.cfdi_tax_locales
        cfg_invoice['tax_decimals'] = values.cfdi_tax_decimals
        cfg_invoice['with_taxes'] = values.cfdi_with_taxes
        cfg_invoice['add_same_product'] = values.cfdi_add_same_product
        cfg_invoice['tax_locales_truncate'] = values.cfdi_tax_locales_truncate
        cfg_invoice['decimales_precios'] = get_config('decimales_precios')
        if(values.cfdi_show_pedimento){
            $$('grid_details').showColumn('pedimento')
        }
        if(values.cfdi_edu){
            $$('grid_details').showColumn('student')
        }
        show('fs_students', values.cfdi_edu)
        show('fs_divisas', values.cfdi_divisas)
        show('txt_folio_custom', values.cfdi_folio_custom)
        show('txt_total_cant', values.cfdi_show_total_cant)
        show('date_invoice', values.cfdi_change_date_invoice)
    })

    values_global = ''
}


function price_without_taxes(price, id){
    var final_price = price

    query = table_pt.chain().find({'product': id}).data()
    for(var tax of query){
        impuesto = table_taxes.findOne({'id': tax.tax})
        if(impuesto.tipo == 'E'){
            continue
        }

        var tasa = 1.00 + impuesto.tasa.to_float()
        if(impuesto.tipo == 'T' && impuesto.name == 'IVA'){
            final_price = (price / tasa).round(cfg_invoice['decimales_precios'])
        }
    }
    return final_price
}


function cmd_new_invoice_click(){
    var form = $$('form_invoice')
    var grid_totals = $$('grid_totals')
    grid = $$('grid_details')

    default_config()
    form.adjust()
    form.setValues({id: 0, id_partner: 0, lbl_client: 'Ninguno', notas: ''})
    get_condicion_pago()
    grid.clearAll()
    grid_totals.clearAll()
    grid_totals.add({id: 1, concepto: 'SubTotal', importe: 0})
    $$('cmd_cfdi_relacionados').disable()
    $$('multi_invoices').setValue('invoices_new')

    var lst = $$('lst_invoice_client_regimen')
    lst.setValue('')
    lst.getList().clearAll()

    $$('date_invoice').setValue(new Date())
    show('cmd_show_global_information', false)

    form.focus('search_client_name')
}


function cmd_edit_invoice_click(id, e, node){

    $$("multi_invoices").setValue("invoices_new")

}


function delete_invoice(id){
    webix.ajax().del('/invoices', {id: id}, function(text, xml, xhr){
        if(xhr.status == 200){
            gi.remove(id)
            msg_ok('Factura eliminada correctamente')
        }else{
            msg_error('No se pudo eliminar')
        }
    })
}


function cmd_delete_invoice_click(id, e, node){
    if(gi.count() == 0){
        return
    }

    var row = gi.getSelectedItem()

    if (row == undefined){
        msg_error('Selecciona una factura')
        return
    }
    if (row instanceof Array){
        msg_error('Selecciona solo una factura')
        return
    }

    if(row.uuid){
        msg_error('Solo se pueden eliminar facturas sin timbrar')
        return
    }

    msg = '¿Estás seguro de eliminar la siguiente Factura?<BR><BR>'
    msg += '(' + row['folio'] + ') ' + row['cliente']
    msg += '<BR><BR>ESTA ACCIÓN NO SE PUEDE DESHACER'
    webix.confirm({
        title:'Eliminar Factura',
        ok:'Si',
        cancel:'No',
        type:'confirm-error',
        text:msg,
        callback:function(result){
            if (result){
                delete_invoice(row['id'])
            }
        }
    })
}


function validate_invoice(values){

    var date_invoice = $$('date_invoice').getValue()
    if(date_invoice == null){
        msg = 'La fecha es requerida'
        msg_error(msg)
        $$('date_invoice').setFocus()
        return false
    }

    var now = new Date()
    var difference = (now.getTime() - date_invoice.getTime()) / (1000 * 3600 * 24)
    if(difference > 3){
        msg_error('Fecha inválida')
        return false
    }

    var tipo_comprobante = $$('lst_tipo_comprobante').getValue()
    if(tipo_comprobante != 'T'){
        if(values.id_partner == 0){
            focus('search_client_name')
            msg = 'Selecciona un cliente'
            msg_error(msg)
            return false
        }
    }

    var regimen_fiscal = $$('lst_invoice_client_regimen').getValue()
    if(!regimen_fiscal){
        msg = 'El Regimen Fiscal del Cliente es obligatorio.'
        msg_error(msg)
        return false
    }

    if(!grid.count()){
        webix.UIManager.setFocus('search_product_id')
        msg = 'Agrega al menos un producto o servicio'
        msg_error(msg)
        return false
    }

    var uso_cfdi = $$('lst_uso_cfdi').getValue()
    if(uso_cfdi.trim() == ""){
        webix.UIManager.setFocus('lst_uso_cfdi')
        msg = 'El Uso del CFDI es requerido'
        msg_error(msg)
        return false
    }

    var forma_pago = $$('lst_forma_pago').getValue()
    if(forma_pago.trim() == ""){
        webix.UIManager.setFocus('lst_forma_pago')
        msg = 'La Forma de pago es requerida'
        msg_error(msg)
        return false
    }

    var metodo_pago = $$('lst_metodo_pago').getValue()
    if(metodo_pago=='PPD' && forma_pago!='99'){
        webix.UIManager.setFocus('lst_forma_pago')
        msg = 'La Forma de pago debe ser: [99] Por definir'
        msg_error(msg)
        return false
    }

    var tipo_cambio = $$('txt_tipo_cambio').getValue()
    if(tipo_cambio.trim() == ""){
        webix.UIManager.setFocus('txt_tipo_cambio')
        msg = 'El Tipo de Cambio es requerido'
        msg_error(msg)
        return false
    }

    if(isNaN(tipo_cambio * 1)){
        webix.UIManager.setFocus('txt_tipo_cambio')
        msg = 'El Tipo de Cambio debe ser un valor númerico'
        msg_error(msg)
        return false
    }

    var moneda = $$('lst_moneda').getValue()
    if(moneda == 'MXN' && tipo_cambio != 1){
        webix.UIManager.setFocus('txt_tipo_cambio')
        msg = 'Si la moneda es MXN, el Tipo de Cambio debe ser 1.00'
        msg_error(msg)
        return false
    }

    if(moneda != 'MXN' && tipo_cambio == 1){
        webix.UIManager.setFocus('txt_tipo_cambio')
        msg = 'Si la moneda no es MXN, el Tipo de Cambio debe ser diferente de 1.00'
        msg_error(msg)
        return false
    }

    anticipo = $$('chk_cfdi_anticipo').getValue()
    if(anticipo){
        //~ var mp = $$('lst_metodo_pago').getValue()
        if(metodo_pago != 'PUE'){
            msg = 'En anticipos, el método de pago debe ser: Pago en una sola exhibición'
            msg_error(msg)
            return false
        }

        if(grid.count() != 1){
            msg = 'Los anticipos solo llevan un concepto'
            msg_error(msg)
            return false
        }

        var r = grid.data.getRange()
        if(r[0].clave_sat != CLAVE_ANTICIPOS){
            msg = 'La clave del SAT para anticipos debe ser: ' + CLAVE_ANTICIPOS
            msg_error(msg)
            return false
        }

        query = table_relaciones.chain().data()
        if(query.length > 0){
            msg = 'Los anticipos no deben llevar CFDI relacionados'
            msg_error(msg)
            return false
        }
    }

    donativo = $$('chk_cfdi_donativo').getValue()
    if(donativo){
        query = table_totals.chain().data()
        for(var t of query){
            tax = table_taxes.findOne({'id': t.tax})
            if(tax.tipo != 'E'){
                msg = 'Los donativos deben de ser exentos'
                msg_error(msg)
                return false
            }
        }
    }

    usar_ine = $$('chk_cfdi_usar_ine').getValue()
    if(usar_ine){
        var id_contabilidad = $$('txt_ine_idcontabilidad').getValue().trim()
        if(!id_contabilidad){
            $$('tv_invoice').getTabbar().setValue('INE')
            msg = 'El ID de contabilidad es requerido si se usa el complemento INE'
            msg_error(msg)
            return false
        }

        if(!id_contabilidad.is_number()){
            $$('tv_invoice').getTabbar().setValue('INE')
            msg = 'El ID de contabilidad deben ser solo digitos'
            msg_error(msg)
            return false
        }

        if(id_contabilidad.length > 6){
            $$('tv_invoice').getTabbar().setValue('INE')
            msg = 'El ID de contabilidad deben tener máximo seis digitos'
            msg_error(msg)
            return false
        }

    }

    var is_global = $$('cmd_show_global_information').isVisible()
    if(is_global){
        if(values_global=='' && tipo_comprobante=='I'){
            msg = 'Captura los datos de la Factura Global'
            msg_error(msg)
            return false
        }
    }

    var rows = grid.data.getRange()
    for (i = 0; i < rows.length; i++) {

        if(is_global){
            var key_sat = rows[i]['clave_sat']
            if(key_sat!=KEY_SAT_01){
                var msg = 'Clave SAT inválida para Factura Global en la línea: ' + (i + 1)
                msg_error(msg)
                return false
            }
        }

        var importe = rows[i]['importe']
        if(!importe){
            var msg = 'No es posible facturar importes en cero, revisa la línea: ' + (i + 1)
            msg_error(msg)
            return false
        }
    }

    //~ validate comercio exterior
    var usar_comercioe = $$('chk_cfdi_usar_comercioe').getValue()
    if(usar_comercioe){
        var values = _get_values_comercio_exterior()
    }

    //~ validate carta porte
    var usar_cartaporte = $$('chk_cfdi_usar_cartaporte').getValue()
    if(usar_cartaporte){
        var result = _get_values_carta_porte()
        if(!result.ok){
            return false
        }
    }

    return true
}


function _get_values_carta_porte(){
    var ok = false
    var values = new Object()

    unidad_peso = $$('lst_carta_UnidadPeso').getValue()
    if(!unidad_peso){
        msg = 'Es necesario seleccionar una Unidad de Peso'
        msg_error(msg)
        return {ok: ok, values: values}
    }

    var ubicaciones = $$('grid_ccp_ubicaciones').data.getRange()
    if (ubicaciones.length < 2){
        msg = 'Se requieren al menos dos ubicaciones'
        msg_error(msg)
        return {ok: ok, values: values}
    }
    ubicaciones.forEach(function(row, index){
        delete row['id']
        delete row['delete']
        //~ delete row['IDUbicacion']
    })

    var mercancias = $$('grid_ccp_mercancias').data.getRange()
    if (mercancias.length < 1){
        msg = 'Se requieren al menos una mercancía'
        msg_error(msg)
        return {ok: ok, values: values}
    }
    mercancias.forEach(function(row, index){
        delete row['id']
        delete row['delete']
    })

    var autotransporte = $$('grid_ccp_autotransporte').data.getRange()[0]
    delete autotransporte['id']
    if(autotransporte['PermSCT'] === undefined){
        msg = 'El campo PermSCT es requerido'
        msg_error(msg)
        return {ok: ok, values: values}
    }

    var remolques = $$('grid_ccp_remolques').data.getRange()
    remolques.forEach(function(row, index){
        delete row['id']
    })

    var seguros = $$('grid_ccp_seguros').data.getRange()[0]
    delete seguros['id']
    if(seguros['AseguraRespCivil'] === undefined){
        msg = 'El campo AseguraRespCivil es requerido'
        msg_error(msg)
        return {ok: ok, values: values}
    }
    if(seguros['PolizaRespCivil'] === undefined){
        msg = 'El campo PolizaRespCivil es requerido'
        msg_error(msg)
        return {ok: ok, values: values}
    }

    var tipos_figuras = $$('grid_ccp_tipos_figuras').data.getRange()
    tipos_figuras.forEach(function(row, index){
        delete row['id']
    })

    values['TranspInternac'] = $$('lst_cp_TranspInternac').getValue()
    values['unidad_peso'] = unidad_peso
    values['ubicaciones'] = ubicaciones
    values['mercancias'] = mercancias
    values['autotransporte'] = autotransporte
    values['remolques'] = remolques
    values['seguros'] = seguros
    values['tiposfigura'] = tipos_figuras

    ok = true

    return {ok: ok, values: values}
}


function update_grid_invoices(values){
    if(values.new){
        gi.add(values.row)
    }else{
        gi.updateItem(values.row['id'], values.row)
    }
}


function send_anticipo_egreso(id){
    webix.ajax().get('/values/anticipoegreso', {id: id}, function(text, data){
        var values = data.json()
        if(values.ok){
            msg_ok(values.msg)
            gi.add(values.row)
        }else{
            webix.alert({
                title: 'Error al Timbrar',
                text: values.msg,
                type: 'alert-error'
            })
        }
    })

}


function generar_anticipo_egreso(id){
    msg = 'La factura tiene un CFDI de anticipo relacionado<BR><BR>'
    msg += '¿Deseas generar la factura de egreso correspondiente?'

    webix.confirm({
        title: 'Generar Egreso',
        ok: 'Si',
        cancel: 'No',
        type: 'confirm-error',
        text: msg,
        callback:function(result){
            if(result){
                send_anticipo_egreso(id)
            }
        }
    })
}


function send_timbrar(id){
    webix.ajax().post('invoices', {opt: 'timbrar', id: id}, function(text, data){
        var values = data.json()
        if(values.ok){
            cmd_update_timbres_click()
            msg_ok(values.msg)
            gi.updateItem(id, values.row)
            if(values.anticipo){
                //~ generar_anticipo_egreso(id)
                //~ show('Generar egreso de anticipo')
            }
            if(cfg_invoice.open_pdf){
                get_pdf(id)
            }
        }else{
            webix.alert({
                title: 'Error al Timbrar',
                text: values.msg,
                type: 'alert-error'
            })
            gi.updateItem(id, values.row)
        }
    })

}


function save_invoice(data){
    var result = false
    var values = NaN

    webix.ajax().sync().post('invoices', data, {
        error:function(text, data, XmlHttpRequest){
            msg = 'Ocurrio un error, consulta a soporte técnico'
            msg_error(msg)
        },
        success:function(text, data, XmlHttpRequest){
            values = data.json();
            if(values.ok){
                msg_ok('Factura guardada correctamente<BR>Enviando a timbrar...')
                update_grid_invoices(values)
                gi.select(values.row['id'], false)
                send_timbrar(values.row['id'])
                result = true
            }else{
                msg_error(values.msg)
            }
        }
    })

    if(result){
        table_pt.clear()
        table_totals.clear()
        grid.clearAll()
        $$('grid_totals').clearAll()
    }

    return result
}


function save_preinvoice(data){
    var result = false
    var values = NaN

    webix.ajax().sync().post('preinvoices', data, {
        error:function(text, data, XmlHttpRequest){
            msg = 'Ocurrio un error, consulta a soporte técnico'
            msg_error(msg)
        },
        success:function(text, data, XmlHttpRequest){
            values = data.json();
            if(values.ok){
                msg_ok('Pre Factura generada correctamente')
                result = true
            }else{
                msg_error(values.msg)
            }
        }
    })

    if(result){
        table_pt.clear()
        table_totals.clear()
        grid.clearAll()
        $$('grid_totals').clearAll()

    }

    return result
}


function guardar_y_timbrar(values){
    query = table_relaciones.chain().data()
    var ids = []
    if(query.length > 0){
        for (i = 0; i < query.length; i++) {
            ids.push(query[i]['id'])
        }
    }

    var rows = grid.data.getRange()
    for (i = 0; i < rows.length; i++) {
        delete rows[i]['id']
        delete rows[i]['delete']
        delete rows[i]['clave']
        delete rows[i]['clave_sat']
        delete rows[i]['importe']
        delete rows[i]['student']
        rows[i]['valor_unitario'] = parseFloat(rows[i]['valor_unitario'])
        rows[i]['descuento'] = parseFloat(rows[i]['descuento'])
    }

    var data = new Object()
    data['id'] = values.id
    data['cliente'] = values.id_partner
    data['productos'] = rows
    data['date'] = $$('date_invoice').getValue()
    data['serie'] = $$('lst_serie').getText()
    data['forma_pago'] = $$('lst_forma_pago').getValue()
    data['condiciones_pago'] = $$('txt_condicion_pago').getValue().trim()
    data['moneda'] = $$('lst_moneda').getValue()
    data['tipo_cambio'] = $$('txt_tipo_cambio').getValue()
    data['tipo_comprobante'] = $$('lst_tipo_comprobante').getValue()
    data['metodo_pago'] = $$('lst_metodo_pago').getValue()
    data['uso_cfdi'] = $$('lst_uso_cfdi').getValue()
    data['regimen_fiscal'] = $$('lst_regimen_fiscal').getValue()
    data['receptor_regimen'] = $$('lst_invoice_client_regimen').getValue()
    data['relacionados'] = ids
    data['tipo_relacion'] = tipo_relacion
    data['anticipo'] = anticipo
    data['donativo'] = donativo
    data['notas'] = values.notas
    data['folio_custom'] = $$('txt_folio_custom').getValue()
    data['divisas'] = $$('opt_divisas').getValue()
    data['leyendas_fiscales'] = $$('grid_leyendas_fiscales').getSelectedId(true, true)
    data['periodicidad'] = values_global

    $$('grid_leyendas_fiscales').unselectAll()

    var usar_ine = $$('chk_cfdi_usar_ine').getValue()
    if(usar_ine){
        ine_type_comite = $$('lst_ine_tipo_comite').getValue()
        var valores = {
            TipoProceso: $$('lst_ine_tipo_proceso').getValue(),
            IdContabilidad: $$('txt_ine_idcontabilidad').getValue(),
            ClaveEntidad: $$('lst_ine_key_entidad').getValue(),
            Ambito: $$('lst_ine_ambito').getValue(),
        }
        if(ine_type_comite){
            valores['TipoComite'] = ine_type_comite
        }
        data['ine'] = valores
    }

    var usar_cartaporte = $$('chk_cfdi_usar_cartaporte').getValue()
    if(usar_cartaporte){
        //~ var total_distance = 0.00
        //~ var total_weight = 0.00
        //~ var cartaporte = {
            //~ TranspInternac: $$('lst_carta_TranspInternac').getValue(),
            //~ TotalDistRec: total_distance,
        //~ }
        //~ var ubicaciones = $$('grid_carta_ubicaciones').data.getRange()
        //~ ubicaciones.forEach(function(row, index){
            //~ delete row['id']
            //~ delete row['delete']
            //~ if(row['DistanciaRecorrida']){
                //~ total_distance += parseFloat(row['DistanciaRecorrida'])
            //~ }
        //~ })
        //~ cartaporte['TotalDistRec'] = total_distance
        //~ cartaporte['ubicaciones'] = ubicaciones

        //~ var row = $$('grid_carta_autotransporte').data.getRange()[0]
        //~ var autotransporte = {
            //~ PermSCT: row['PermSCT'],
            //~ NumPermisoSCT: row['NumPermisoSCT'],
            //~ identificacion: {
                //~ ConfigVehicular: row['ConfigVehicular'],
                //~ PlacaVM: row['PlacaVM'],
                //~ AnioModeloVM: row['AnioModeloVM'],
            //~ },
            //~ seguros: {
                //~ AseguraRespCivil: row['AseguraRespCivil'],
                //~ PolizaRespCivil: row['PolizaRespCivil'],
            //~ },
            //~ remolque: {
                //~ SubTipoRem: row['SubTipoRem'],
                //~ Placa: row['Placa'],
            //~ }
        //~ }

        //~ var mercancias = $$('grid_carta_mercancias').data.getRange()
        //~ mercancias.forEach(function(row, index){
            //~ delete row['id']
            //~ delete row['delete']
            //~ row['Cantidad'] = String(row['Cantidad'])
            //~ row['ValorMercancia'] = String(row['ValorMercancia'])
            //~ if(row['PesoEnKg']){
                //~ total_weight += parseFloat(row['PesoEnKg'])
            //~ }
        //~ })
        //~ var mercancias = {
            //~ 'PesoBrutoTotal': 0.00,
            //~ 'UnidadPeso': $$('lst_carta_UnidadPeso').getValue(),
            //~ 'NumTotalMercancias': String(mercancias.length),
            //~ mercancias: mercancias,
            //~ autotransporte: autotransporte,
        //~ }
        //~ cartaporte['mercancias'] = mercancias

        //~ var tiposfigura = $$('grid_carta_tipos_figuras').data.getRange()
        //~ tiposfigura.forEach(function(row, index){
            //~ delete row['id']
        //~ })
        //~ cartaporte['tiposfigura'] = tiposfigura
        var result = _get_values_carta_porte()
        data['cartaporte'] = result.values
    }

    var usar_comercioe = $$('chk_cfdi_usar_comercioe').getValue()
    if(usar_comercioe){
        data['comercioe'] = _get_values_comercio_exterior()
    }

    if(!save_invoice(data)){
        return
    }

    //~ values_comercioe = null
    values_global = ''
    $$('chk_cfdi_usar_comercioe').setValue(false)

    table_relaciones.clear()
    tipo_relacion = ''
    anticipo = false
    $$('chk_cfdi_anticipo').setValue(0)
    $$('chk_cfdi_donativo').setValue(0)
    $$('chk_cfdi_usar_ine').setValue(0)
    show('cmd_show_global_information', false)

    $$('form_invoice').setValues({id_partner: 0, lbl_partner: 'Ninguno', notas:''})
    $$('multi_invoices').setValue('invoices_home')

}


function cmd_timbrar_click(id, e, node){
    var form = this.getFormView();

    if(!form.validate()) {
        msg_error('Valores inválidos')
        return
    }

    var values = form.getValues()

    if(!validate_invoice(values)){
        return
    }

    var tipo_comprobante = $$('lst_tipo_comprobante').getValue()

    query = table_relaciones.chain().data()
    msg = '¿Todos los datos son correctos?<BR><BR>'
    if(query.length > 0){
        msg += 'La factura tiene CFDI relacionados<BR><BR>'
    }
    if(anticipo){
        msg += 'La factura es un Anticipo<BR><BR>'
    }
    if(donativo){
        msg += 'La factura es un Donativo'
        if($$('lst_forma_pago').getValue()=='12'){
            msg += ' en Especie'
        }
        msg += '<BR><BR>'
    }

    usar_ine = $$('chk_cfdi_usar_ine').getValue()
    if(usar_ine){
        msg += 'Estas usando el complemento: INE<BR><BR>'
    }

    if($$('chk_cfdi_usar_comercioe').getValue()){
        msg += 'Estas usando el complemento:<BR>Comercio Exterior<BR><BR>'
    }

    usar_carta_porte = $$('chk_cfdi_usar_cartaporte').getValue()
    if(usar_carta_porte){
        msg += 'Estas usando el complemento:<BR>Carta Porte<BR><BR>'
    }

    if(tipo_comprobante == 'T'){
        msg += 'El Tipo de Comprobante es Traslado, el total será puesto a 0 (Cero), asegurate de que sea el tipo de comprobante correcto<BR><BR>'
    }

    if(cfg_invoice['leyendasfiscales']){
        var rows = $$('grid_leyendas_fiscales').getSelectedId(true, true)
        if(rows.length == 0){
            msg += 'No se agregará ninguna leyenda fiscal<BR><BR>'
        }else if(rows.length == 1){
            msg += 'Se agregará una leyenda fiscal<BR><BR>'
        }else{
            msg += 'Se agregarán ' +  rows.length + ' leyendas fiscales<BR><BR>'
        }
    }

    if($$('cmd_show_global_information').isVisible()){
        msg += 'Es una Factura Global<BR><BR>'
    }

    msg += '¿Estás seguro de timbrar esta factura?<BR><BR>'

    webix.confirm({
        title: 'Timbrar Factura',
        ok: 'Si',
        cancel: 'No',
        type: 'confirm-error',
        text: msg,
        callback:function(result){
            if(result){
                guardar_y_timbrar(values)
            }
        }
    })
}


function cmd_close_invoice_click(id, e, node){
    $$('multi_invoices').setValue('invoices_home')
}


function search_client_by_id(id){
    var msg = ''
    webix.ajax().get('/values/client', {'id': id}, {
        error: function(text, data, xhr) {
            msg_error('Error al consultar')
        },
        success: function(text, data, xhr){
            var values = data.json()
            if (values.ok){
                set_client(values.row)
            }else{
                msg = 'No se encontró un cliente con la clave: ' + id
                msg_error(msg)
            }
        }
    })

}


function set_client(row){
    if(!row.codigo_postal){
        msg = 'El cliente no tiene capturado su Código Postal, es obligatorio.'
        msg_error(msg)
        return
    }

    var form = $$('form_invoice')
    var html = '<span class="webix_icon fa-user"></span><span class="lbl_partner">'
    form.setValues({
        id_partner:row.id, search_client_id:'', search_client_name:'',
        forma_pago: row.forma_pago, uso_cfdi: row.uso_cfdi,
        notas: row.notas}, true)
    html += row.nombre + ' (' + row.rfc + ')</span>'
    $$('lbl_client').setValue(html)
    $$('cmd_cfdi_relacionados').enable()

    var lst = $$('lst_invoice_client_regimen')
    lst.getList().clearAll()
    if(row.regimenes==undefined){
        var options = {opt: 'by_id', id: row.id}
        webix.ajax().sync().get('/sociosregimenes', options, function(text, data){
            var values = data.json()
            lst.getList().parse(values)
        })
    }else{
        lst.getList().parse(row.regimenes)
    }
    lst.setValue(lst.getPopup().getList().getFirstId())

    if(row.nombre.toUpperCase() == PUBLICO && row.rfc == RFC_PUBLICO){
        show('cmd_show_global_information', true)
    }else{
        show('cmd_show_global_information', false)
    }

    form.focus('search_product_id')
}


function grid_clients_found_click(obj){
    set_client(obj)
}


function search_client_id_key_press(code, e){
    var value = this.getValue()
    if(code == 13 && value.length > 0){
        var id = parseInt(value, 10)
        if (isNaN(id)){
            msg_error('Captura una clave válida')
        }else{
            search_client_by_id(id)
        }
    }
}


function calcular_impuestos(){
    var tmp = null
    var subtotal = 0
    var id = 2
    var grid_totals = $$('grid_totals')
    var impuesto_producto = 0
    var impuesto = null
    var total_cant = 0

    table_totals.clear()
    grid_totals.clearAll()
    grid_totals.add({id: 1, concepto: 'SubTotal', importe: 0})

    var tc = $$('lst_tipo_comprobante').getValue()
    if(tc=='T'){
        return
    }

    grid.eachRow(function(row){
        var product = grid.getItem(row)
        var valor_unitario = parseFloat(product.valor_unitario)
        var cantidad = parseFloat(product.cantidad)
        var import2 = (valor_unitario * cantidad).round(DECIMALES)
        var importe = parseFloat(product.importe)

        subtotal += importe
        total_cant += cantidad

        query = table_pt.chain().find({'product': product.id_product}).data()
        for(var tax of query){
            impuesto = table_taxes.findOne({'id': tax.tax})
            if(impuesto.tipo == 'E'){
                continue
            }

            var base = importe
            if(cfg_invoice['tax_locales'] && impuesto.key == '000'){
                base = import2
            }

            if(cfg_invoice.tax_decimals){
                impuesto_producto = (impuesto.tasa * base).round(DECIMALES_TAX)
            }else{
                impuesto_producto = (impuesto.tasa * base).round(DECIMALES)
            }

            if(cfg_invoice['tax_locales_truncate'] && impuesto.key == '000'){
                impuesto_producto = Math.trunc(impuesto.tasa * base * 100) / 100
            }

            if(impuesto.tipo == 'R'){
                impuesto_producto = (impuesto_producto * -1).round(DECIMALES)
            }

            tmp = table_totals.findOne({'tax': tax.tax})
            if(tmp === null){
                table_totals.insert({'tax': tax.tax, 'importe': impuesto_producto})
            }else{
                tmp.importe += impuesto_producto
                table_totals.update(tmp)
            }

        }
    })

    var tipo = ''
    var concepto = ''

    query = table_totals.chain().data()
    for(var t of query){
        tax = table_taxes.findOne({'id': t.tax})
        if(tax.tipo == 'E'){
            continue
        }
        tipo = 'Traslado '
        if(tax.tipo == 'R'){
            tipo = 'Retención '
        }
        concepto = tipo + tax.name + ' (' + tax.tasa + ')'
        grid_totals.add({id: id, concepto: concepto, importe: t.importe})
        id += 1
    }

    var row = {importe: subtotal}
    grid_totals.updateItem(1, row)
    $$('txt_total_cant').setValue(format_decimal_2(total_cant))
}


function set_product(data){
    var taxes = data.taxes
    var values = data.row
    var form = $$('form_invoice')
    var row = undefined

    if(!cfg_invoice['add_same_product']){
        for(var id in grid.data.pull){
            if(grid.getItem(id).id_product == values.id_product){
                row = grid.getItem(id)
                break
            }
        }
    }

    values['delete'] = '-'
    if (row == undefined){
        values['cantidad'] = 1
        values['importe'] = values['valor_unitario']
        //~ grid.add(values)
    } else {
        values['cantidad'] = parseFloat(row.cantidad) + 1
        values['descuento'] = parseFloat(row.descuento)
        values['valor_unitario'] = parseFloat(row.valor_unitario)
        var precio_final = values['valor_unitario'] - values['descuento']
        values['importe'] = (precio_final * values['cantidad']).round(DECIMALES)
        //~ grid.updateItem(row.id, values)
    }
    form.setValues({search_product_id: '', search_product_name: ''}, true)

    //~ Validate stock
    if(values.inventario){
        if(values.cantidad > values.existencia){
            msg_error('No hay suficiente existencia de este producto')
            return
        }
    }

    if(row == undefined){
        grid.add(values)
    }else{
        grid.updateItem(row.id, values)
    }

    for(var v of taxes){
        var pt = table_pt.findOne(v)
        if(pt === null){
            table_pt.insert(v)
        }
    }
    calcular_impuestos()
}


function grid_products_found_click(obj){
    search_product_by_key(obj.clave)
}


function grid_students_found_click(obj){
    var form = $$('form_invoice')
    var row = grid.getSelectedItem()

    if (row == undefined){
        msg = 'Selecciona un registro primero'
        msg_error(msg)
        return
    }

    var values = {
        id_student: obj.id,
        student: obj.nombre + ' ' + obj.paterno + ' ' + obj.materno,
    }
    grid.updateItem(row.id, values)
    form.setValues({search_student: ''}, true)
}


function search_product_by_key(key){

    var filters = {
        opt: 'by_key',
        key: key,
    }

    webix.ajax().get('/products', filters, {
        error: function(text, data, xhr) {
            msg_error('Error al consultar')
        },
        success: function(text, data, xhr){
            var values = data.json()
            if (values.ok){
                set_product(values)
            } else {
                msg = 'No se encontró un producto con la clave<BR><BR>' + key
                msg_error(msg)
            }
        }
    })
}


function search_product_id_key_press(code, e){
    var value = this.getValue().trim()
    if(code == 13 && value.length > 0){
        search_product_by_key(value)
    }
}


function grid_details_before_edit_start(id){
    var columns = ['', 'unidad', 'descripcion', 'pedimento','cantidad', 'valor_unitario', 'descuento']
    if(!columns.indexOf(id.column)){
        return !this.getItem(id.row)[id.column]
    }
    var tc = $$('lst_tipo_comprobante').getValue()
    if(tc=='T' && id.column=='descuento'){
        return false
    }
}


function grid_ccp_ubicaciones_before_edit_stop(state, editor){
    var g = $$('grid_ccp_ubicaciones')
    var row = g.getItem(editor.row)

    if(editor.column != 'CodigoPostal'){
        if(editor.column == 'DistanciaRecorrida' && row['TipoUbicacion'] == 'Origen'){
            msg = 'En el Origen, la distancia recorrida debe estar vacía'
            msg_error(msg)
            g.blockEvent()
            state.value = ''
            g.editCancel()
            g.unblockEvent()
        }
        return true
    }

    var cp = state.value.trim()

    if(!cp){
        msg = 'El Código Postal no puede estar vacío'
        msg_error(msg)
        g.blockEvent()
        state.value = state.old
        g.editCancel()
        g.unblockEvent()
        return true
    }

    if(cp.length != 5){
        msg = 'El Código Postal debe ser de 5 digitos'
        msg_error(msg)
        g.blockEvent()
        state.value = state.old
        g.editCancel()
        g.unblockEvent()
        return true
    }

    if(cp.match(/\d/) == null){
        msg = 'El Código Postal deben ser solo digitos'
        msg_error(msg)
        g.blockEvent()
        state.value = state.old
        g.editCancel()
        g.unblockEvent()
        return true
    }

    webix.ajax().get('/values/cp', {cp: cp}, {
        error: function(text, data, xhr) {
            msg_error('Error al consultar el C.P.')
        },
        success: function(text, data, xhr) {
            var values = data.json();
            if (values.estado == undefined){
                msg = 'No se encontró el C.P., asegurate de que sea correcto'
                msg_error(msg)
            } else {
                //~ row['Estado'] = opt_carta_estados.find(x => x.value === values.estado).id
                row['Estado'] = values.key_estado
                row['Municipio'] = values.key_municipio
                g.refresh()
                msg_ok('Municipio:\n' + values.municipio)
            }
        }
    })
}


function grid_details_before_edit_stop(state, editor){
    var row = grid.getItem(editor.row)

    if(editor.column == 'unidad'){
        return true
    }

    if(editor.column == 'descripcion'){
        if(!state.value.trim()){
            msg = 'La descripción no puede estar vacía'
            msg_error(msg)
            grid.blockEvent()
            state.value = state.old
            grid.editCancel()
            grid.unblockEvent()
            return true
        }
        state.value = state.value.trim()
        if(state.value.length > 1000){
            msg = 'La descripción tiene más de 1000 caracteres, esta  '
            msg += 'descripción será rechazada por el SAT. Edita esta '
            msg += 'descripción hasta que ya no veas este mensaje. <BR>'
            msg += '<BR>Caracteres: ' + state.value.length
            msg_error(msg)
        }
        return true
    }

    if(editor.column == 'pedimento'){
        state.value = state.value.trim()
        if(state.value.length != 21){
            msg = 'El Pedimento debe ser de 21 caracteres, será  '
            msg += 'rechazado por el SAT. Editalo hasta que ya '
            msg += 'no veas este mensaje de error. <BR>'
            msg += '<BR>Caracteres: ' + state.value.length
            msg_error(msg)
        }
        if(state.value){
            if(!validate_pedimento(state.value)){
                msg = 'El formato del Pedimento es erroneo, será rechazado por el SAT'
                msg_error(msg)
            }
        }
        return true
    }

    if(editor.column == 'cantidad'){
        var cantidad = parseFloat(state.value)
        if(isNaN(cantidad)){
            msg = 'La cantidad debe ser un número'
            msg_error(msg)
            grid.blockEvent()
            state.value = state.old
            grid.editCancel()
            grid.unblockEvent()
            return true
        }

        cantidad = cantidad.round(DECIMALES)

        //~ Validate stock
        if(row['inventario']){
            if(cantidad > row['existencia']){
                msg = 'No hay suficiente existencia de este producto'
                msg_error(msg)
                grid.blockEvent()
                state.value = state.old
                grid.editCancel()
                grid.unblockEvent()
                return true
            }
        }

        grid.blockEvent()
        state.value = cantidad
        grid.unblockEvent()

        var valor_unitario = parseFloat(row['valor_unitario'])
        var descuento = parseFloat(row['descuento'])
    }

    if(editor.column == 'valor_unitario'){
        if(isNaN(state.value)){
            msg = 'El valor unitario debe ser un número'
            msg_error(msg)
            grid.blockEvent()
            state.value = state.old
            grid.editCancel()
            grid.unblockEvent()
            return true
        }

        if(cfg_invoice['with_taxes']){
            var valor_unitario = price_without_taxes(parseFloat(state.value), row.id_product)
        }else{
            //~ var valor_unitario = parseFloat(state.value).round(DECIMALES)
            var valor_unitario = parseFloat(state.value).round(cfg_invoice['decimales_precios'])
        }
        grid.blockEvent()
        state.value = valor_unitario
        grid.unblockEvent()

        var cantidad = parseFloat(row['cantidad'])
        var descuento = parseFloat(row['descuento'])
    }

    if(editor.column == 'descuento'){
        var descuento = parseFloat(state.value)
        if(isNaN(descuento)){
            msg = 'El descuento debe ser un número'
            msg_error(msg)
            grid.blockEvent()
            state.value = state.old
            grid.editCancel()
            grid.unblockEvent()
            return true
        }

        //~ descuento = descuento.round(DECIMALES)
        descuento = descuento.round(cfg_invoice['decimales_precios'])
        var cantidad = parseFloat(row['cantidad'])
        var valor_unitario = parseFloat(row['valor_unitario'])

        if(descuento>=valor_unitario){
            msg = 'El descuento debe ser menor al Valor Unitario'
            msg_error(msg)
            grid.blockEvent()
            state.value = state.old
            grid.editCancel()
            grid.unblockEvent()
            return true
        }

        grid.blockEvent()
        state.value = descuento
        grid.unblockEvent()

    }

    var precio_final = valor_unitario - descuento
    row['importe'] = (cantidad * precio_final).round(DECIMALES)

    grid.refresh()
}


function grid_details_after_edit_stop(state, editor, ignoreUpdate){
    var columns = ['', 'cantidad', 'valor_unitario', 'descuento']
    if(columns.indexOf(editor.column) > 0){
        calcular_impuestos()
    }
}


function grid_details_click(id, e, node){
    if(id.column != 'delete'){
        return
    }
    grid.remove(id.row)
    calcular_impuestos()
}


function grid_details_header_click(id){
    if(id.column != 'delete'){
        return
    }

    var msg = '¿Estás seguro de quitar todos los productos?'
    webix.confirm({
        title: 'Quitar todos',
        ok: 'Si',
        cancel: 'No',
        type: 'confirm-error',
        text: msg,
        callback:function(result){
            if (result){
                grid.clearAll()
                calcular_impuestos()
            }
        }
    })
}


function set_invoice(row){
    $$('lst_serie').setValue(row.serie)
    $$('lst_tipo_comprobante').setValue(row.tipo_comprobante)
    $$('lst_uso_cfdi').setValue(row.uso_cfdi)
    $$('lst_metodo_pago').setValue(row.metodo_pago)
    $$('lst_forma_pago').setValue(row.forma_pago)
    $$('txt_condicion_pago').setValue(row.condicion_pago)
}


function set_products_reinvoice(values){
    var rows = []
    for(var product of values){
        var row = product.row
        rows.push(row)

        var taxes = product.taxes
        for(var v of taxes){
            var pt = table_pt.findOne(v)
            if(pt === null){
                table_pt.insert(v)
            }
        }
    }
    grid.parse(rows, 'json')
}


function refacturar_invoice(id){
    filters = {id: id, opt: 'reinvoice'}

    webix.ajax().get('/invoices', filters, {
        error: function(text, data, xhr) {
            msg_error('Error al consultar')
        },
        success: function(text, data, xhr) {
            var values = data.json();
            cmd_new_invoice_click()
            pause(500)
            set_client(values.receptor)
            set_invoice(values.invoice)
            set_products_reinvoice(values.products)
            calcular_impuestos()
        }
    })
}


function cmd_refacturar_click(){
    if(gi.count() == 0){
        return
    }

    var row = gi.getSelectedItem()
    if (row == undefined){
        msg_error('Selecciona una factura')
        return
    }
    if (row instanceof Array){
        msg_error('Selecciona solo una factura')
        return
    }

    var msg = '¿Estás seguro de refacturar la siguiente factura?<BR><BR>'
    msg += '(' + row['serie'] + '-' + row['folio'] + ') ' + row['cliente']
    webix.confirm({
        title: 'Refacturar',
        ok: 'Si',
        cancel: 'No',
        type: 'confirm-error',
        text: msg,
        callback:function(result){
            if (result){
                refacturar_invoice(row['id'])
            }
        }
    })
}


function cmd_invoice_timbrar_click(){
    if(gi.count() == 0){
        return
    }

    var row = gi.getSelectedItem()
    if (row == undefined){
        msg_error('Selecciona una factura')
        return
    }
    if (row instanceof Array){
        msg_error('Selecciona solo una factura')
        return
    }

    if(row.uuid){
        msg_error('La factura ya esta timbrada')
        return
    }

    msg = '¿Estás seguro de enviar a timbrar esta factura?'
    webix.confirm({
        title: 'Timbrar Factura',
        ok: 'Si',
        cancel: 'No',
        type: 'confirm-error',
        text: msg,
        callback:function(result){
            if(result){
                send_timbrar(row.id)
            }
        }
    })
}


function enviar_correo(row){
    if(!row.uuid){
        msg_error('La factura no esta timbrada')
        return
    }

    msg = '¿Estás seguro de enviar por correo esta factura?'
    webix.confirm({
        title: 'Enviar Factura',
        ok: 'Si',
        cancel: 'No',
        type: 'confirm-error',
        text: msg,
        callback:function(result){
            if(result){
                webix.ajax().post('/values/sendmail', {'id': row.id}, {
                    error:function(text, data, XmlHttpRequest){
                        msg = 'Ocurrio un error, consulta a soporte técnico'
                        msg_error(msg)
                    },
                    success:function(text, data, XmlHttpRequest){
                        values = data.json();
                        if(values.ok){
                            msg_ok(values.msg)
                        }else{
                            msg_error(values.msg)
                        }
                    }
                })
            }
        }
    })
}


function get_pdf(id){
    window.open('/doc/pdf/' + id, '_blank')
}


function get_html(id){
    window.open('/doc/html/' + id, '_blank')
}


function grid_invoices_click(id, e, node){
    var row = this.getItem(id)

    if(id.column == 'xml'){
        location = '/doc/xml/' + row.id
    }else if(id.column == 'pdf'){
        get_pdf(row.id)
    }else if(id.column == 'html'){
        get_html(row.id)
    }else if(id.column == 'ods'){
        location = '/doc/ods/' + row.id
    }else if(id.column == 'zip'){
        location = '/doc/zip/' + row.id
    }else if(id.column == 'email'){
        enviar_correo(row)
    }

}


function get_filters_invoices(){
    var filters = $$('filter_dates').getValue()

    if(filters['start'] && !filters['end']){
        msg = 'No seleccionaste la fecha final'
        msg_error(msg)
    }

    filters['year'] = $$('filter_year').getValue()
    filters['month'] = $$('filter_month').getValue()
    filters['day'] = '-1'
    if(get_config('show_filter_by_day')){
        filters['day'] = $$('filter_day').getValue()
    }
    filters['client'] = $$('grid_invoices').getFilter('cliente').value
    return filters
}


function get_invoices(){
    var filters = get_filters_invoices()
    filters['by'] = 'dates'

    var grid = $$('grid_invoices')
    grid.showProgress({type: 'icon'})

    webix.ajax().get('/invoices', filters, {
        error: function(text, data, xhr) {
            msg_error('Error al consultar')
        },
        success: function(text, data, xhr) {
            var values = data.json();
            grid.clearAll();
            if (values.ok){
                grid.parse(values.rows, 'json');
            };
        }
    });
}


function filter_year_change(nv, ov){
    get_invoices()
}


function filter_month_change(nv, ov){
    get_invoices()
}


function filter_day_change(nv, ov){
    get_invoices()
}


function filter_dates_change(range){
    if(range.start != null && range.end != null){
        get_invoices()
    }
}


function invoice_uncancel(id){
    var options = {opt: 'uncancel', id: id}
    webix.ajax().put('/invoices', options, function(text, data){
        var result = data.json()
        if(result['result']){
            gi.updateItem(id, result['values'])
            msg_ok(result['msg'])
        }else{
            msg_error(result['msg'])
        }
    })
}


function ask_invoice_uncancel(id){
    var msg = 'La factura seleccionada esta Vigente en el SAT, pero Cancelada en el sistema <BR>¿Deseas cambiar su estatus?'
    webix.confirm({
        title: 'Cambiar estatus de factura',
        ok: 'Si',
        cancel: 'No',
        type: 'confirm-error',
        text: msg,
        callback:function(result){
            if (result){
                invoice_uncancel(id)
            }
        }
    })
}


function cmd_invoice_sat_click(){
    if(gi.count() == 0){
        return
    }

    var row = gi.getSelectedItem()
    if (row == undefined){
        msg_error('Selecciona una factura')
        return
    }
    if (row instanceof Array){
        msg_error('Selecciona solo una factura')
        return
    }

    if(!row.uuid){
        msg_error('La factura no esta timbrada, solo es posible consultar \
            el estatus en el SAT de facturas timbradas')
        return
    }

    var options = {opt: 'statussat', id: row.id}
    webix.ajax().get('/invoices', options, function(text, data){
        var value = data.json()
        if(value == 'Vigente'){
            msg_ok(value)
        }else if(value == 'uncancel'){
            ask_invoice_uncancel(row.id)
        }else{
            msg_error(value)
        }
    })

}


function reset_invoice(){
    var form = $$('form_invoice')
    var grid_totals = $$('grid_totals')

    form.adjust()
    form.setValues({id: 0, id_partner: 0, lbl_client: 'Ninguno'})
    grid.clearAll()
    grid_totals.clearAll()
    grid_totals.add({id: 1, concepto: 'SubTotal', importe: 0})

    table_pt.clear()
    table_totals.clear()
    $$('cmd_cfdi_relacionados').disable()
    form.focus('search_client_name')

}


function cmd_prefactura_click(){
    var form = this.getFormView()

    if(!form.validate()) {
        msg_error('Valores inválidos')
        return
    }

    var values = form.getValues()
    if(!validate_invoice(values)){
        return
    }

    var rows = grid.data.getRange()
    for (i = 0; i < rows.length; i++) {
        delete rows[i]['id']
        delete rows[i]['delete']
        delete rows[i]['clave']
        delete rows[i]['importe']
        rows[i]['valor_unitario'] = parseFloat(rows[i]['valor_unitario'])
        rows[i]['descuento'] = parseFloat(rows[i]['descuento'])
    }

    var data = new Object()
    data['id'] = values.id
    data['cliente'] = values.id_partner
    data['productos'] = rows
    data['serie'] = $$('lst_serie').getText()
    data['forma_pago'] = $$('lst_forma_pago').getValue()
    data['condiciones_pago'] = $$('txt_condicion_pago').getValue().trim()
    data['moneda'] = $$('lst_moneda').getValue()
    data['tipo_cambio'] = $$('txt_tipo_cambio').getValue()
    data['tipo_comprobante'] = $$('lst_tipo_comprobante').getValue()
    data['metodo_pago'] = $$('lst_metodo_pago').getValue()
    data['uso_cfdi'] = $$('lst_uso_cfdi').getValue()
    data['regimen_fiscal'] = $$('lst_regimen_fiscal').getValue()
    data['notas'] = values.notas

    if(!save_preinvoice(data)){
        return
    }

    reset_invoice()
    $$('tv_invoice').getTabbar().setValue('PreFacturas')
}


function lst_metodo_pago_change(nv, ov){
    if(nv == 'PPD'){
        $$('lst_forma_pago').setValue('99')
    }
}


function lst_moneda_change(nv, ov){
    if(nv == 'MXN'){
        $$('txt_tipo_cambio').setValue('1.00')
        $$('txt_tipo_cambio').config.readonly = true
    }else{
        $$('txt_tipo_cambio').config.readonly = false
    }
    $$('txt_tipo_cambio').refresh()
    select_all('txt_tipo_cambio')
}


function txt_tipo_cambio_lost_focus(prev){
    var tipo_cambio = $$('txt_tipo_cambio').getValue()

    if(isNaN(tipo_cambio * 1)){
        webix.UIManager.setFocus('txt_tipo_cambio')
        msg = 'El Tipo de Cambio debe ser un valor númerico'
        msg_error(msg)
        $$('txt_tipo_cambio').setValue('1.00')
    }else{
        $$('txt_tipo_cambio').setValue(parseFloat(tipo_cambio).round(4))
    }
}


function get_prefacturas(){
    var fy = $$('prefilter_year')
    var fm = $$('prefilter_month')

    var y = fy.getValue()
    var m = fm.getValue()
    rango = {'year': y, 'month': m}

    var grid = $$('grid_preinvoices')
    webix.ajax().get('/preinvoices', rango, {
        error: function(text, data, xhr) {
            msg_error('Error al consultar')
        },
        success: function(text, data, xhr) {
            var values = data.json();
            grid.clearAll();
            if (values.ok){
                grid.parse(values.rows, 'json')
            }
        }
    })
}


function tb_invoice_change(nv, ov){
    if(nv == 'PreFacturas'){
        get_prefacturas()
    }
}


function prefilter_year_change(nv, ov){
    get_prefacturas()
}


function prefilter_month_change(nv, ov){
    get_prefacturas()
}


function delete_preinvoice(id){
    webix.ajax().del('/preinvoices', {id: id}, function(text, xml, xhr){
        if(xhr.status == 200){
            $$('grid_preinvoices').remove(id)
            msg_ok('PreFactura eliminada correctamente')
        }else{
            msg_error('No se pudo eliminar')
        }
    })
}


function cmd_delete_preinvoice_click(id, e, node){
    var grid = $$('grid_preinvoices')

    if(grid.count() == 0){
        return
    }

    var row = grid.getSelectedItem()
    if (row == undefined){
        msg_error('Selecciona una prefactura')
        return
    }

    var msg = '¿Estás seguro de eliminar la siguiente PREFactura?<BR><BR>'
    msg += '(' + row['folio'] + ') ' + row['cliente']
    msg += '<BR><BR>ESTA ACCIÓN NO SE PUEDE DESHACER'
    webix.confirm({
        title:'Eliminar Pre Factura',
        ok:'Si',
        cancel:'No',
        type:'confirm-error',
        text:msg,
        callback:function(result){
            if (result){
                delete_preinvoice(row['id'])
            }
        }
    })
}


function agregar_preproducto(values){
    var taxes = values.taxes
    var values = values.row
    var form = $$('form_invoice')
    var row = grid.getItem(values.id)

    values['delete'] = '-'
    if (row == undefined){
        grid.add(values)
    } else {
        values['cantidad'] = parseFloat(row.cantidad) + parseFloat(values['cantidad'])
        values['valor_unitario'] = parseFloat(row.valor_unitario)
        values['descuento'] = parseFloat(row.descuento)
        var precio_final = values['valor_unitario'] - values['descuento']
        values['importe'] = (precio_final * values['cantidad']).round(DECIMALES)
        grid.updateItem(row.id, values)
    }

    for(var v of taxes){
        var pt = table_pt.findOne(v)
        if(pt === null){
            table_pt.insert(v)
        }
    }
}


function refacturar_preinvoice(id){

    webix.ajax().get('/values/preproductos', {'id': id}, {
        error: function(text, data, xhr) {
            msg_error('Error al consultar')
        },
        success: function(text, data, xhr){
            var values = data.json()
            set_client(values.receptor)
            for(var p of values.rows){
                agregar_preproducto(p)
            }
            calcular_impuestos()
            $$('tv_invoice').getTabbar().setValue('Generar')
        }
    })
}


function cmd_facturar_preinvoice_click(){
    var grid = $$('grid_preinvoices')

    if(grid.count() == 0){
        return
    }

    var row = grid.getSelectedItem()
    if (row == undefined){
        msg_error('Selecciona una prefactura')
        return
    }

    var msg = '¿Estás seguro de facturar la siguiente PREFactura?<BR><BR>'
    msg += '(' + row['folio'] + ') ' + row['cliente']
    webix.confirm({
        title: 'Generar Factura',
        ok: 'Si',
        cancel: 'No',
        type: 'confirm-error',
        text: msg,
        callback:function(result){
            if (result){
                refacturar_preinvoice(row['id'])
            }
        }
    })
}


function enviar_prefactura(id){
    msg = '¿Estás seguro de enviar por correo esta prefactura?'
    webix.confirm({
        title: 'Enviar Factura',
        ok: 'Si',
        cancel: 'No',
        type: 'confirm-error',
        text: msg,
        callback:function(result){
            if(result){
                webix.ajax().post('/values/enviarprefac', {'id': id.row}, {
                    error:function(text, data, XmlHttpRequest){
                        msg = 'Ocurrio un error, consulta a soporte técnico'
                        msg_error(msg)
                    },
                    success:function(text, data, XmlHttpRequest){
                        values = data.json();
                        if(values.ok){
                            msg_ok(values.msg)
                        }else{
                            msg_error(values.msg)
                        }
                    }
                })
            }
        }
    })
}


function generate_pdf(id){
    webix.ajax().get('/values/canopenpre', {id: id}, {
        error: function(text, data, xhr) {
        },
        success: function(text, data, xhr) {
            var value = data.json();
            //~ if(value){
            window.open('/doc/pre/' + id, '_blank')
            //~ }else{
                //~ msg_ok('Generando prefactura...')
            //~ }
        }
    })

}


function grid_preinvoices_click(id, e, node){
    if(id.column == 'pdf'){
        //~ generate_pdf(id.row)
        window.open('/doc/pre/' + id, '_blank')
    }else if(id.column == 'email'){
        enviar_prefactura(id)
    }

}


function get_facturas_por_cliente(){
    var values = $$('form_invoice').getValues()
    var id = values.id_partner

    var y = $$('filter_cfdi_year').getValue()
    var m = $$('filter_cfdi_month').getValue()

    var ids = []
    var rows = $$('grid_relacionados').data.getRange()
    for (i = 0; i < rows.length; i++) {
        ids.push(rows[i]['id'])
    }

    filters = {
        'year': y,
        'month': m,
        'id_cliente': id,
        'cfdis': ids,
        'anticipo': $$('chk_relacionados_anticipo').getValue(),
        'folio': $$('filter_cfdi_folio').getValue(),
        'uuid': $$('filter_cfdi_uuid').getValue(),
        'opt': 'relacionados'
    }

    var grid = $$('grid_cfdi_cliente')

    webix.ajax().get('/invoices', filters, {
        error: function(text, data, xhr) {
            msg_error('Error al consultar')
        },
        success: function(text, data, xhr) {
            var values = data.json();
            grid.clearAll();
            if (values.ok){
                grid.parse(values.rows, 'json');
            };
        }
    })
}


function get_info_cfdi_relacionados(){

    webix.ajax().get('/values/tiporelacion', {key: true}, function(text, data){
        var values = data.json()
        $$('lst_tipo_relacion').getList().parse(values)
        $$('lst_tipo_relacion').setValue(tipo_relacion)
    })

    query = table_relaciones.chain().data()
    $$('grid_relacionados').parse(query)
    get_facturas_por_cliente()
}


function cmd_cfdi_relacionados_click(){
    var d = new Date()
    ui_invoice.init()
    var fy = $$('filter_cfdi_year')
    var fm = $$('filter_cfdi_month')

    fy.blockEvent()
    fm.blockEvent()

    $$('lbl_cfdi_cliente').setValue($$('lbl_client').getValue())
    data = $$('filter_year').getList().data
    fy.getList().data.sync(data)
    fy.setValue(d.getFullYear())
    fm.setValue(d.getMonth() + 1)

    fy.unblockEvent()
    fm.unblockEvent()

    get_info_cfdi_relacionados()

    $$('win_cfdi_relacionados').show()
}


function cmd_limpiar_relacionados_click(){
    msg = '¿Estás seguro de quitar todas las relaciones<BR><BR>'
    msg += 'ESTA ACCION NO SE PUEDE DESHACER'

    webix.confirm({
        title: 'Limpiar relaciones',
        ok: 'Si',
        cancel: 'No',
        type: 'confirm-error',
        text: msg,
        callback:function(result){
            if(result){
                $$('lst_tipo_relacion').setValue('')
                $$('grid_relacionados').clearAll()
                table_relaciones.clear()
                tipo_relacion = ''
                msg_ok('Las relaciones han sido eliminadas')
            }
        }
    })
}


function cmd_guardar_relacionados_click(){
    var grid = $$('grid_relacionados')
    var value = $$('lst_tipo_relacion').getValue()

    if(value == '' || value == '-'){
        msg_error('Selecciona el tipo de relación')
        return
    }

    if(grid.count() == 0){
        msg_error('Agrega al menos un CFDI a relacionar')
        return
    }

    var data = grid.data.getRange()
    table_relaciones.clear()
    table_relaciones.insert(data)
    tipo_relacion = value
    msg_ok('Relaciones guardadas correctamente')
}


function cmd_filter_relacionados_click(){
    get_facturas_por_cliente()
}


function filter_cfdi_year_change(nv, ov){
    cmd_filter_relacionados_click()
}


function filter_cfdi_month_change(nv, ov){
    cmd_filter_relacionados_click()
}


function lst_tipo_relacion_change(nv, ov){
    $$('chk_relacionados_anticipo').setValue(0)
    $$('chk_relacionados_anticipo').disable()
    if(nv=='07'){
        $$('chk_relacionados_anticipo').enable()
        $$('chk_relacionados_anticipo').setValue(1)
        cmd_filter_relacionados_click()
    }

}


function lst_tipo_comprobante_change(nv, ov){
    if(nv=='T'){
        grid.eachRow(function(row){
            var p = grid.getItem(row)
            p.descuento = 0.0
            p.importe = (p.cantidad * p.valor_unitario).round(DECIMALES)
            grid.updateItem(row, p)
        })
    }
    if(nv=='T' || ov=='T'){
        calcular_impuestos()
    }
}


function lst_serie_change(nv, ov){
    query = table_series.chain().find({id: nv}).data()[0]
    if(query.usarcon){
        $$('lst_tipo_comprobante').setValue(query.usarcon)
        $$('lst_tipo_comprobante').config.readonly = true
    }else{
        $$('lst_tipo_comprobante').config.readonly = false
    }
    $$('lst_tipo_comprobante').refresh()
}


function cmd_cfdi_notes_click(){
    win_invoice_notes.init()
    var values = $$('form_invoice').getValues()
    $$('invoice_notes').setValue(values.notas)
    $$('win_invoice_notes').show()
    to_end('invoice_notes')
    cfg_invoice['notes'] = false
}


function save_invoice_notes(notes){
    var row = $$('grid_invoices').getSelectedId()

    webix.ajax().post('/values/invoicenotes', {id: row.id, notes: notes}, {
        error:function(text, data, XmlHttpRequest){
        },
        success:function(text, data, XmlHttpRequest){
            values = data.json();
            if(values.ok){
                msg_ok(values.msg)
            }else{
                msg_error(values.msg)
            }
        }
    })

}


function cmd_invoice_save_note_click(){
    var value = $$('invoice_notes').getValue()
    if(cfg_invoice['notes']){
        save_invoice_notes(value)
    }else{
        $$('form_invoice').setValues({notas: value}, true)
    }
    $$('win_invoice_notes').close()

}


function cmd_invoice_report_pdf_click(){
    var d = new Date()
    var ds = d.toISOString().slice(0,10).replace(/-/g, "_")

    webix.toPDF($$('grid_invoices'), {
        ignore: {'xml': true, 'pdf': true, 'zip': true, 'mail': true},
        filename: 'Reporte_de_Facturas_' + ds,
        width: 612,
        height: 792,
        //~ autowidth: true,
        filterHTML: true,
        fontSize: 8,
        padding: 5,
        header:{
            textAlign: 'center',
            fontSize: 9,
        },
        table:{
            fontSize: 8,
        },
        row:{
            padding: 0,
        },
        columns:{
            index: true,
            serie: {width: 40},
            folio: {width: 30},
            fecha: {width: 95},
            tipo_comprobante: {width: 20},
            estatus: {width: 50},
            total_mn: {width: 70},
            cliente: {width: 200},
        }
    })
}


function cmd_invoice_report_xls_click(){
    webix.toExcel($$('grid_invoices'), {
        filename: 'Reporte_de_Facturas',
        name: 'Facturas',
        ignore: {'xml': true, 'pdf': true, 'zip': true, 'mail': true},
        rawValues: true,
    })
}


function grid_invoices_on_select_change(){
    var g = $$('grid_invoices')
    var rows = g.getSelectedItem(true)
    var total = 0

    for (i = 0; i < rows.length; i++) {
        if(typeof(rows[i].total_mn) == 'string'){
            total += rows[i].total_mn.to_float()
        }else{
            total += rows[i].total_mn
        }
    }
    g.getColumnConfig('cliente').footer[0].text = webix.i18n.priceFormat(total)
    g.refreshColumns()
    $$('cmd_admin_invoice_notes').disable()
    if(rows.length==1){
        $$('cmd_admin_invoice_notes').enable()
    }
}


function grid_invoices_on_header_click(id){
    if(id.column != 'index'){
        return
    }
    var g = $$('grid_invoices')
    var rows = g.getSelectedItem(true)
    if(rows.length){
        g.unselectAll()
    }else{
        g.selectAll()
    }
}


function get_invoice_notes(row){
    webix.ajax().sync().get('/values/invoicenotes', {id: row.id}, function(text, data){
        var values = data.json()
        return values.notes
    })
}


function cmd_admin_invoice_notes_click(){
    var row = $$('grid_invoices').getSelectedId()
    win_invoice_notes.init()
    webix.ajax().sync().get('/values/invoicenotes', {id: row.id}, function(text, data){
        var values = data.json()
        $$('invoice_notes').setValue(values.notes)
        $$('win_invoice_notes').show()
        to_end('invoice_notes')
    })
    cfg_invoice['notes'] = true
}


function cmd_import_invoice_click(){
    win_import_invoice.init()
    $$('win_import_invoice').show()
}


function cmd_upload_invoice_click(){
    var form = $$('form_upload_invoice')

    var values = form.getValues()

    if(!$$('lst_upload_invoice').count()){
        $$('win_import_invoice').close()
        return
    }

    if($$('lst_upload_invoice').count() > 1){
        msg = 'Selecciona solo un archivo'
        msg_error(msg)
        return
    }

    var template = $$('up_invoice').files.getItem($$('up_invoice').files.getFirstId())

    if(template.type.toLowerCase() != 'ods'){
        msg = 'Archivo inválido.\n\nSe requiere un archivo ODS'
        msg_error(msg)
        return
    }

    msg = '¿Estás seguro de importar este archivo?'
    webix.confirm({
        title: 'Importar Factura',
        ok: 'Si',
        cancel: 'No',
        type: 'confirm-error',
        text: msg,
        callback:function(result){
            if(result){
                $$('up_invoice').send()
            }
        }
    })
}


function add_import_product_taxes(taxes){
    for(var v of taxes){
        var pt = table_pt.findOne(v)
        if(pt === null){
            table_pt.insert(v)
        }
    }
}


function up_invoice_upload_complete(response){
    if(response.status != 'server'){
        msg = 'Ocurrio un error al subir el archivo'
        msg_error(msg)
        return
    }
    msg = 'Archivo subido correctamente.\n\nComenzando importación.'
    msg_ok(msg)
    $$('win_import_invoice').close()

    webix.ajax().get('/values/importinvoice', {
        error: function(text, data, xhr) {
            msg_error('Error al consultar')
        },
        success: function(text, data, xhr){
            var values = data.json()
            if (values.ok){
                for(var p of values.rows){
                    add_import_product_taxes(p.taxes)
                }
                grid.clearAll()
                grid.parse(values.rows, 'json')
                grid.refresh()
                calcular_impuestos()
            }else{
                webix.alert({
                    title: 'Error al importar',
                    text: values.msg,
                    type: 'alert-error',
                })
            }
        }
    })
}


function cmd_invoice_verify_sat_click(){
    var rows = gi.getSelectedItem(true)

    if (rows.length == 0){
        msg_error('Selecciona una factura')
        return
    }

    if (rows.length > 1){
        msg_error('Selecciona solo una factura')
        return
    }

    if(!rows[0].uuid){
        msg_error('La factura no esta timbrada, solo es posible verificar \
            en el SAT, facturas timbradas')
        return
    }

    webix.ajax().get('/values/verifysat', {id: rows[0].id}, function(text, data){
        var values = data.json()
        window.open(values.url, '_blank')
    })
}


function grid_invoices_on_subview_create(view, item){
    var values = {'opt': 'detalle', 'id': item.id}
    webix.ajax().get('/invoices', values, {
        error: function(text, data, xhr) {
            msg_error('Error al consultar')
        },
        success: function(text, data, xhr) {
            view.parse(data.json(), 'json')
        }
    });
}


function cmd_preinvoice_generate_delete_click(){
}


function txt_folio_custom_key_press(code, e){
    var data = [8, 9, 37, 39, 46]
    if ( data.indexOf(code) >= 0 ){
        return true;
    }

    if ( code < 48 || code > 57){
        return false;
    }
}


function validate_folio_exists(folio){
    var serie = $$('lst_serie').getText()
    var values = {'opt': 'foliocustom', 'folio': folio, 'serie': serie}
    webix.ajax().get('/invoices', values, {
        error: function(text, data, xhr) {
            msg_error('Error al consultar')
        },
        success: function(text, data, xhr) {
            var result = data.json()
            if(result.ok){
                msg_error(result.msg)
                focus('txt_folio_custom')
            }else{
                msg_ok(result.msg)
            }
            return result.ok
        }
    })
}


function txt_folio_custom_lost_focus(prev){
    if(prev.getValue()){
        validate_folio_exists(prev.getValue())
    }
}


function search_by(value){
    var filters = get_filters_invoices()
    filters['by'] = 'notes'
    filters['notes'] = value


    var grid = $$('grid_invoices')
    grid.showProgress({type: 'icon'})

    webix.ajax().get('/invoices', filters, {
        error: function(text, data, xhr) {
            msg_error('Error al consultar')
        },
        success: function(text, data, xhr) {
            var values = data.json();
            grid.clearAll();
            if (values.ok){
                grid.parse(values.rows, 'json');
            };
        }
    });
}


function search_by_key_press(code, e){
    var value = this.getValue().trim()
    if(code == 13 && value.length > 3){
        search_by(value)
    }
}


function search_by_click(){
    var value = this.getValue().trim()
    if(value.length > 3){
        search_by(value)
    }
}


function get_leyendas_fiscales(){
    webix.ajax().get('/leyendasfiscales', {'opt': 'active'}, {
        error:function(text, data, XmlHttpRequest){
            msg = 'Ocurrio un error, consulta a soporte técnico'
            msg_error(msg)
        },
        success:function(text, data, XmlHttpRequest){
            var values = data.json()
            var grid = $$('grid_leyendas_fiscales')
            grid.clearAll()
            grid.parse(values)
            grid.refresh()
        }
    })
}

//~ Delete
function _tab_carta_porte(){

}


function tv_invoice_change(nv, ov){
    if(nv=='Carta Porte'){
        //~ _tab_carta_porte()
    }
}


function send_invoice_cancel(id, reason='', uuid=''){
    var args = {
        opt: 'cancel',
        values: {
            id: id,
            reason: reason,
            uuid: uuid,
        }
    }
    webix.ajax().post('invoices', args, function(text, data){
        var values = data.json()
        if(values.ok){
            msg_ok(values.msg)
            gi.updateItem(id, values.row)
        }else{
            msg_error('No fue posible cancelar')
            webix.alert({
                title: 'Error al Cancelar',
                text: values.msg,
                type: 'alert-error'
            })
        }
    })
}


function cmd_invoice_cancel_click(){
    var row = $$('grid_invoices').getSelectedItem()
    var reason = $$('lst_reasons_cancel').getValue()
    var uuid = $$('txt_cancel_uuid').getValue()

    if(!reason){
        msg = 'Selecciona un motivo para esta cancelación'
        msg_error(msg)
        return
    }
    if(reason=='01' & !uuid){
        msg = 'Debes de capturar el UUID que reemplaza a este CFDI'
        msg_error(msg)
        return
    }

    send_invoice_cancel(row.id, reason, uuid)
    $$('win_invoice_cancel').close()
}


function cmd_win_cancel_close_click(){
    $$('win_invoice_cancel').close()
}


function cmd_invoice_ask_cancel_click(){
    var g = $$('grid_invoices')

    if(g.count() == 0){
        return
    }

    var row = g.getSelectedItem()

    if (row == undefined){
        msg_error('Selecciona una factura')
        return
    }

    if (row instanceof Array){
        msg_error('Selecciona solo una factura')
        return
    }

    if(row.estatus == 'Cancelada'){
        msg_error('La factura ya esta cancelada')
        return
    }

    msg = ''
    if(row.uuid){
        win_invoice_cancel.init()
        $$('win_invoice_cancel').show()
    }else{
        msg = 'La factura NO esta timbrada, asegurate de que efectivamente NO este timbrada.<BR><BR>'
        msg += '¿Estás seguro de enviar a cancelar esta factura?<BR><BR> \
            ESTA ACCIÓN NO SE PUEDE DESHACER'
        webix.confirm({
            title: 'Cancelar Factura',
            ok: 'Si',
            cancel: 'No',
            type: 'confirm-error',
            text: msg,
            callback:function(result){
                if(result){
                    send_invoice_cancel(row.id)
                }
            }
        })
    }
}


function cmd_ccp_agregar_ubicacion_click(){
    var g = $$('grid_ccp_ubicaciones')
    g.add({delete: '-', Pais: 'MEX'})
}


function cmd_ccp_add_product_click(){
    var g = $$('grid_ccp_mercancias')
    g.add({delete: '-'})
}


function cmd_ccp_agregar_remolque_click(){
    var g = $$('grid_ccp_remolques')
    if(g.count() < 2){
        g.add({delete: '-'})
    }
}


function _copy_from_invoice(){
    var g1 = $$('grid_details')
    var g2 = $$('grid_carta_mercancias')

    if(!g1.count()){
        msg = 'Agrega primero "todos" los productos a trasladar'
        msg_error(msg)
        return
    }

    g2.clearAll()

    g1.eachRow(function(row){
        const r = g1.getItem(row)
        var data = new Object()
        data['delete'] = '-'
        data['BienesTransp'] = r.clave_sat
        data['Descripcion'] = r.descripcion
        data['Cantidad'] = r.cantidad
        data['ClaveUnidad'] = r.unidad
        //~ data['ValorMercancia'] = r.importe
        g2.add(data)
    })
}

function cmd_carta_copy_from_invoice_click(){
    msg = '¿Estás seguro de copiar los productos?<BR><BR> \
        Esto reemplazara todos los datos actuales de las mercancías.'
    webix.confirm({
        title: 'Copiar productos',
        ok: 'Si',
        cancel: 'No',
        type: 'confirm-error',
        text: msg,
        callback:function(result){
            if(result){
                _copy_from_invoice()
            }
        }
    })
}


function grid_ccp_ubicaciones_click(id, e, node){
    if(id.column != 'delete'){
        return
    }
    this.remove(id.row)
}


function grid_ccp_mercancias_click(id, e, node){
    if(id.column != 'delete'){
        return
    }
    this.remove(id.row)
}


function grid_ccp_remolques_click(id, e, node){
    if(id.column != 'delete'){
        return
    }
    this.remove(id.row)
}


function _set_carta_porte_from_json(data){
    try{
        var values = JSON.parse(data)
    }catch(e){
        msg_error('Revisa el archivo JSON')
        webix.alert({
            title: 'Error al cargar JSON',
            text: e.message,
            type: 'alert-error'
        })
        return
    }

    $$('lst_cp_TranspInternac').setValue(values['TranspInternac'])
    $$('lst_carta_UnidadPeso').setValue(values['UnidadPeso'])

    var ubicaciones = values['ubicaciones']
    var mercancias = values['mercancias']
    var autotransporte = values['autotransporte']
    var remolques = values['remolques']
    var seguros = values['seguros']
    var figura = values['figura']

    var grid = $$('grid_ccp_ubicaciones')
    grid.clearAll()
    ubicaciones.forEach(function(row, index){
        var data = new Object()
        data['delete'] = '-'
        data['TipoUbicacion'] = row.tipo
        data['RFCRemitenteDestinatario'] = row.rfc
        data['NombreRemitenteDestinatario'] = row.nombre
        data['FechaHoraSalidaLlegada'] = new Date(row.fecha)
        if('distancia' in row){
            data['DistanciaRecorrida'] = row.distancia
        }
        data['Municipio'] = row.municipio
        data['Estado'] = row.estado
        data['Pais'] = 'MEX'
        data['CodigoPostal'] = row.codigo_postal
        grid.add(data)
    })

    var grid = $$('grid_ccp_mercancias')
    grid.clearAll()
    mercancias.forEach(function(row, index){
        var data = new Object()
        data['delete'] = '-'
        data['BienesTransp'] = row.clave_sat
        data['Descripcion'] = row.descripcion
        data['Cantidad'] = row.cantidad
        data['ClaveUnidad'] = row.clave_unidad
        data['PesoEnKg'] = row.peso_en_kg
        grid.add(data)
    })

    var grid = $$('grid_ccp_autotransporte')
    grid.clearAll()
    var data = new Object()
    data['PermSCT'] = autotransporte.PermSCT
    data['NumPermisoSCT'] = autotransporte.NumPermisoSCT
    data['ConfigVehicular'] = autotransporte.ConfigVehicular
    data['PesoBrutoVehicular'] = autotransporte.PesoBrutoVehicular
    data['PlacaVM'] = autotransporte.PlacaVM
    data['AnioModeloVM'] = autotransporte.AnioModeloVM
    grid.add(data)

    var grid = $$('grid_ccp_remolques')
    //~ if(remolques.length > 0){
    grid.clearAll()
    remolques.forEach(function(row, index){
        var data = new Object()
        data['SubTipoRem'] = row.SubTipoRem
        data['Placa'] = row.Placa
        grid.add(data)
    })
    //~ }

    var grid = $$('grid_ccp_seguros')
    grid.clearAll()
    var data = new Object()
    data['AseguraRespCivil'] = seguros.AseguraRespCivil
    data['PolizaRespCivil'] = seguros.PolizaRespCivil
    grid.add(data)

    var grid = $$('grid_ccp_tipos_figuras')
    grid.clearAll()
    var data = new Object()
    data['TipoFigura'] = figura.TipoFigura
    data['RFCFigura'] = figura.RFCFigura
    data['NumLicencia'] = figura.NumLicencia
    data['NombreFigura'] = figura.NombreFigura
    grid.add(data)

    $$('chk_cfdi_usar_cartaporte').setValue(1)
}


function cmd_carta_import_json_click(){
    win_carta_import_json.init()
    $$('win_carta_import_json').show()
}


function up_invoice_json_on_after_file_add(obj){
    let reader = new FileReader()
    reader.readAsText(obj.file)
    reader.onload = function(){
        _set_carta_porte_from_json(reader.result)
    }
    $$('win_carta_import_json').close()
}


function _set_default_comercio_exterior(){
    const controls = {
        lst_ce_exportacion: '02',
        lst_ce_motivo_traslado: '',
        lst_ce_clave_pedimento: 'A1',
        lst_ce_certificado_origen: '0',
        txt_ce_numero_certificado: '',
        txt_ce_numero_exportador: '',
        lst_ce_incoterm: 'CFR',
        txt_ce_observaciones: '',
        txt_ce_tipo_cambio_usd: '',
        txt_ce_total_usd: '',
    };

    Object.keys(controls).forEach(key => {
        $$(key).setValue(controls[key])
    });

    var grid = $$('grid_ce_emisor')
    grid.clearAll()
    grid.add({id: 0})

    var grid = $$('grid_ce_receptor')
    grid.clearAll()
    grid.add({id: 0})

    var grid = $$('grid_ce_destinatario')
    grid.clearAll()
    grid.add({id: 0})

    var grid = $$('grid_ce_propietarios')
    grid.clearAll()

    var grid = $$('grid_ce_mercancias')
    grid.clearAll()
}


function _set_from_json_comercioe(data, json){

    _set_default_comercio_exterior()

    try{
        if(json){
            values = JSON.parse(data)
        }else{
            values = data
        }
    }catch(e){
        msg_error('Revisa el archivo JSON')
        webix.alert({
            title: 'Error al cargar JSON',
            text: e.message,
            type: 'alert-error'
        })
        return
    }

    const controls = {
        Exportacion: 'lst_ce_exportacion',
        MotivoTraslado: 'lst_ce_motivo_traslado',
        ClaveDePedimento: 'lst_ce_clave_pedimento',
        CertificadoOrigen: 'lst_ce_certificado_origen',
        NumCertificadoOrigen: 'txt_ce_numero_certificado',
        NumeroExportadorConfiable: 'txt_ce_numero_exportador',
        Incoterm: 'lst_ce_incoterm',
        Observaciones: 'txt_ce_observaciones',
        TipoCambioUSD: 'txt_ce_tipo_cambio_usd',
        TotalUSD: 'txt_ce_total_usd',
    };

    Object.keys(controls).forEach(key => {
        if(key in values){
            $$(controls[key]).setValue(values[key])
        }
    });

    var grid = $$('grid_ce_emisor')
    grid.clearAll()
    if ('emisor' in values) {
        grid.add(values['emisor'])
    } else {
        grid.add({id: 0})
    }

    var grid = $$('grid_ce_receptor')
    grid.clearAll()
    if ('receptor' in values) {
        grid.add(values['receptor'])
    } else {
        grid.add({id: 0})
    }

    var grid = $$('grid_ce_destinatario')
    grid.clearAll()
    if ('destinatario' in values) {
        grid.add(values['destinatario'])
    } else {
        grid.add({id: 0})
    }

    var grid = $$('grid_ce_propietarios')
    grid.clearAll()
    if ('propietarios' in values) {
        values['propietarios'].forEach(function(row, index){
            row['delete'] = '-'
            grid.add(row)
        })
    }

    var grid = $$('grid_ce_mercancias')
    grid.clearAll()
    values['mercancias'].forEach(function(row, index){
        row['delete'] = '-'
        grid.add(row)
    })

    msg = 'Valores cargados correctamente'
    msg_ok(msg)
}


function cmd_import_json_comercioe_click(){
    win_import_json_comercioe.init()
    $$('win_import_json_comercioe').show()
}


function up_invoice_json_comercioe_on_after_file_add(obj){
    let reader = new FileReader()
    reader.readAsText(obj.file)
    reader.onload = function(){
        _set_from_json_comercioe(reader.result, true)
    }
    $$('win_import_json_comercioe').close()
}


function cmd_show_global_information_click(){
    win_global_information.init()
    $$('win_global_information').show()
}

function cmd_save_global_information_click(){
    values_global = $$('lst_global_periodicidad').getValue() + "|"
    values_global += $$('lst_global_months').getValue() + "|"
    values_global += $$('lst_global_year').getValue()
    $$('win_global_information').close()
}

function cmd_win_global_close_click(){
    $$('win_global_information').close()
}


function cmd_ce_tipo_cambio_click(){
    window.open('https://www.banxico.org.mx/tipcamb/tipCamMIAction.do?idioma=sp', '_blank')
}


function cmd_ce_add_propietario_click(){
    var g = $$('grid_ce_propietarios')
    g.add({delete: '-'})
}


function grid_ce_propietarios_click(id, e, node){
    if(id.column != 'delete'){
        return
    }
    this.remove(id.row)
}


function cmd_ce_add_mercancia_click(){
    var g = $$('grid_ce_mercancias')
    g.add({delete: '-'})
}


function grid_ce_mercancias_click(id, e, node){
    if(id.column != 'delete'){
        return
    }
    this.remove(id.row)
}



function _get_values_comercio_exterior(){
    var form = $$('form_comercio_exterior')

    if(!form.validate()) {
        msg_error('Valores inválidos en Comercio Exterior')
        return
    }

    const controls = {
        Exportacion: 'lst_ce_exportacion',
        MotivoTraslado: 'lst_ce_motivo_traslado',
        ClaveDePedimento: 'lst_ce_clave_pedimento',
        CertificadoOrigen: 'lst_ce_certificado_origen',
        NumCertificadoOrigen: 'txt_ce_numero_certificado',
        NumeroExportadorConfiable: 'txt_ce_numero_exportador',
        Incoterm: 'lst_ce_incoterm',
        Observaciones: 'txt_ce_observaciones',
        TipoCambioUSD: 'txt_ce_tipo_cambio_usd',
        TotalUSD: 'txt_ce_total_usd',
    };

    var values = new Object()

    Object.keys(controls).forEach(key => {
        var value = $$(controls[key]).getValue().trim()
        if(value){
            values[key] = value
        }
    });

    var propietarios = $$('grid_ce_propietarios').data.getRange()
    propietarios.forEach(function(row, index){
        delete row['id']
        delete row['delete']
    })

    var mercancias = $$('grid_ce_mercancias').data.getRange()
    mercancias.forEach(function(row, index){
        delete row['id']
        delete row['delete']
    })

    var emisor = $$('grid_ce_emisor').data.getRange()[0]
    delete emisor['id']

    var receptor = $$('grid_ce_receptor').data.getRange()[0]
    delete receptor['id']

    var destinatario = $$('grid_ce_destinatario').data.getRange()[0]
    delete destinatario['id']

    values['emisor'] = emisor
    values['propietarios'] = propietarios
    values['receptor'] = receptor
    values['destinatario'] = destinatario
    values['mercancias'] = mercancias

    return values
}


function cmd_ce_import_ods_click(){
    win_ce_import_ods.init()
    $$('win_ce_import_ods').show()
}


function cmd_ce_upload_ods_click(){
    var form = $$('form_ce_import_ods')

    var values = form.getValues()

    if(!$$('lst_ce_up_template').count()){
        $$('win_ce_import_ods').close()
        return
    }

    if($$('lst_ce_up_template').count() > 1){
        msg = 'Selecciona solo un archivo'
        msg_error(msg)
        return
    }

    var template = $$('ce_up_template').files.getItem($$('ce_up_template').files.getFirstId())

    if(template.type.toLowerCase() != 'ods'){
        msg = 'Archivo inválido.\n\nSe requiere un archivo ODS'
        msg_error(msg)
        return
    }

    msg = '¿Estás seguro de importar este archivo?'
    webix.confirm({
        title: 'Importar datos de plantilla',
        ok: 'Si',
        cancel: 'No',
        type: 'confirm-error',
        text: msg,
        callback:function(result){
            if(result){
                $$('ce_up_template').send()
            }
        }
    })
}


function ce_up_template_complete(response){
    if(response.status != 'server'){
        msg = 'Ocurrio un error al subir el archivo'
        msg_error(msg)
        return
    }
    msg = 'Archivo subido correctamente.\n\nComenzando importación.'
    msg_ok(msg)
    $$('win_ce_import_ods').close()

    webix.ajax().get('/values/importceods', {
        error: function(text, data, xhr) {
            msg_error('Error al consultar')
        },
        success: function(text, data, xhr){
            var values = data.json()
            if (values.ok){
                _set_from_json_comercioe(values.data, false)
                //~ msg_ok('Plantilla importada correctamente...')
            }else{
                webix.alert({
                    title: 'Error al importar',
                    text: values.msg,
                    type: 'alert-error',
                })
            }
        }
    })
}