Exportación importación cliente universal

Nav123: Navision, Showare, OrderApp

Print Friendly, PDF & Email

Navision y Business Central ya ofrecen varias formas de exportar clientes y, en principio, importarlos a otra base de datos. Lamentablemente, a menudo no funcionan como se desea, se espera o se espera. Aquí le ofrezco una opción sencilla (!) y universal. Sin embargo, ni siquiera esto puede hacer milagros. Para milagros en Navision, Dynamics, Financials y Business Central tiene que contactarme directamente.

Casos prácticos (ejemplos)

Guardar o restaurar el cliente Cronus

Ese era el requisito original de esta función. La casa de sistemas había borrado el cliente Cronus en una base de datos de clientes. ¿Por qué? No tengo ni idea. Definitivamente fue una idea estúpida. También he tenido clientes que han borrado Cronus AG por error. Y entonces te das cuenta (yo incluido) de que no es tan fácil restaurar un solo cliente. Así que tienes que vivir con el hecho de que Cronus AG permanece borrado. Pero no tiene por qué ser así.

Crear entorno de pruebas

Yo no usaría esta función para eso, hay aquí y aquí una forma mejor de hacerlo. Pero si te hace feliz...

Transferencia de una base de datos personalizada a una base de datos estándar

Se trata de un uso muy práctico. Suponga que tiene una base de datos doblada muy desafortunada de Navision o Business Central, y ahora quiere cambiar a una versión estándar de Navision en la misma versión de lanzamiento. Mi exportación universal saca todos los campos de datos de todas las tablas que se encuentran. En cambio, la importación universal correspondiente sólo lee los campos de las tablas que se encuentran en la base de datos de destino. Creo que esta función por sí sola cumplirá muchos deseos. Por supuesto, aquí también hay límites enormes. Por ejemplo, nunca conseguirá que una versión de Food-Vision, sea cual sea, funcione en un estándar. Las personalizaciones (si es que todavía se pueden llamar así) realizadas aquí por Modus también afectan al estándar de Navision y Business Central tan profundamente que aquí se requiere un cuidado intensivo. Por supuesto, esto no sólo se aplica a Foodvision, sino a muchas soluciones del sector. ¿Sufre usted también de una solución sectorial mal ajustada?

Actualización de Navision más allá de los límites de versión

A menudo, las diferencias entre cambios de versión importantes (por ejemplo, entre Navision Dynamics 2015 y Navision Dynamics 2016) no son tan grandes, por lo que puede probar hasta dónde puede llegar con este mazo. Sin embargo, también hay cambios de versión que tienen un impacto tan masivo en la estructura de datos que todavía tienes que hacer un montón de retrabajo en los datos transferidos. Por ejemplo, en las versiones anteriores de Navision, todavía era posible simplemente borrar la tabla 339 Artículos de ajuste sin ningún problemaEn versiones posteriores, la tabla 339 Artículos de balance es vital para el - siempre hilarante - control de existencias. El cambio a los artículos de valor y los detalles de los artículos de cliente/proveedor también imposibilitaría una transferencia ejecutable de las bases de datos de artículos de valor ANTES a las bases de datos de artículos de valor DESPUÉS. Pero ¿quizás sea suficiente con poder ver al menos un cliente antiguo en un Navision / Business Central ultramoderno? Si utiliza esta función aquí, ya sabrá lo que hace... de lo contrario, ¡mejor póngase en contacto conmigo!¿Quizás sólo quieres echar un vistazo a tu base de datos 2009R2 en el RTC sin mucho esfuerzo? Usted tiene Cronus en una nueva instalación de demostración de todos modos. Con esta pequeña herramienta aquí también puede simplemente transferir un cliente real, varias estadísticas, entrada de pedidos, tarjeta de cliente y mucho más funcionará al menos un poco.

Manipulación de datos

Sí... una opción de uso muy interesante. Salida de cliente, modificación de datos, lectura de vuelta de cliente... ¡Te lo desaconsejo totalmente!

Salida de todos los datos para análisis

Esto también puede ser muy práctico. Usted emite todos los datos que conoce de Navision a los archivos de datos de una sola vez y luego integra los datos deseados en Access o Excel utilizando un controlador CSV, por ejemplo. Pero aquí también elegiría otros métodos .

Salida de todos los datos para el cambio de sistema

¿Desea sustituir Navision / Business Central? ¿Por qué? No lo haga. Dicen que no hay que dejar de viajar, pero yo no estoy tan contento si aplica con Navision y Business Central. ¿Habrá tenido malas experiencias con Navision o Business Central? ¿Lo intentamos juntos??

Opciones anteriores para la salida e importación de clientes desde Navision / Business Central

Exportar a un fichero de datos / Importar desde un fichero de datos

¿Ha utilizado alguna vez las funciones Exportar a un fichero de datos o Importar de un fichero de datos en el RTC? Si hace tiempo que lo utiliza: ¿Le resulta familiar? Pues sí. Se trata de la antigua copia de seguridad de datos a la que podía acceder en el antiguo Navision a través de Extras/Crear copia de seguridad de datos.

Ansicht der Funktion "In eine Datendatei exportieren" im RTC: Das ist die alte Datensicherung!
«Exportar a un archivo de datos» en el RTC: ¡Esta es la copia de seguridad de datos anterior!
Ansicht der Funktion "Datensicherung erstellen" im alten 2009er Client: Das ist die Basis für "In eine Datendatei exportieren"!
Captura de pantalla de la función «Crear copia de seguridad de los datos» en el antiguo cliente de 2009: ¡Esta es la base de «Exportar a un archivo de datos»!

Y esto significa que usted también tiene las mismas restricciones. Si aquí sólo sale un único cliente (la menor cantidad de datos) y luego quiere importarlo a otra base de datos, las bases de datos de origen y de destino deben ser idénticas al 100% (más bien al 110%). Incluso las extensiones deben ser absolutamente idénticas, aunque no modifiquen las estructuras de datos o no estén activas. Además, los datos se codifican durante la exportación, por lo que no es posible editarlos en texto plano.

Por lo tanto, para todos los casos de uso descritos anteriormente, transferir clientes de una base de datos a otra mediante esta función es prácticamente imposible.

Esto también se aplica al comando Powershell correspondiente, que llama a la misma función de Navision.

Export-NAVData -ServerInstance <service name> -Tenant <tenant ID> -CompanyName "<Company name>" -FilePath <location>

Técnicamente, tanto el comando Powershell como la función Exportar a un fichero de datos no es más que una llamada al comando (relativamente nuevo) [Database.]ExportData:

La llamada al comando ExportData de Navision / Business Central directamente a través del código del programa crea los mismos archivos que Exportar a archivo de datos, en efecto, una antigua copia de seguridad de los datos de Navision.

Si ha buscado y encontrado esta página aquí, probablemente ya sepa que no es adecuada para las aplicaciones descritas.

Paquetes de configuración / Rapidstart / Exportación de datos (antes exportación de archivos de cumplimiento fiscal y contabilidad electrónica)

Voy a omitir aquí las exportaciones de datos, son demasiado específicas, ¡pero también pueden ser una herramienta adecuada! Antes se llamaban exportación de archivos de cumplimiento fiscal y contabilidad electrónica, lo que ya da una idea de la finalidad real.

Los paquetes de configuración (antiguo nombre: Rapidstart) son una herramienta increíblemente genial, que se ha convertido en un auténtico todoterreno a lo largo de las distintas versiones.
Puede utilizarlo para enviar TODOS los datos de Navision a Excel (bueno... «todos» hasta 2 millones de registros de datos...), y también para leer de vuelta muchos datos. «Muchos» se limita a las tablas que no están protegidas contra escritura. Así que nada de documentos contabilizados como facturas de venta, albaranes, recordatorios registrados... y partidas contabilizadas (partidas de artículo, partidas de valor, partidas de deudor...). Aparte de esto, sin embargo, es muy recomendable que se familiarice con los paquetes de configuración si aún no lo ha hecho. Esta herramienta no es adecuada para restaurar rápidamente un Cronus o copiar un cliente de una versión antigua de Navision a una nueva versión. A) a menudo no está disponible en la versión anterior, B) a veces la estructura interna de los archivos de salida difiere entre los distintos paquetes de configuración / versiones Rapidstart de Navision, y C) simplemente lleva demasiado tiempo introducir allí todas las tablas que necesita. Bueno, y D) de nuevo, por supuesto, que esta herramienta no puede exportar/importar en áreas protegidas como facturas contabilizadas o directamente en partidas de clientes.

Copy & paste

En efecto. En el Navision antiguo se pueden copiar muchos datos de tablas (¡los datos detodos de Navision están en cualquier tabla!) directamente a través de las tablas (Diseñador, Tabla, Ejecutar) de una tabla/base de datos con CTRL+A (Seleccionar todo), CTRL+C (Copiar, en Navision RTC y Business Central CTRL+Shift+C), y luego pegarlos en la otra base de datos Navision con CTRL+V (Insertar, la V recuerda a un embudo, en Navision RTC y Business Central CTRL+Shift+V).
Sin embargo, las tablas en cuestión deben volver a ser idénticas al 100% (no tanto con RTC) y, en función del número de registros de datos, copiar (¡no pegar!) lleva mucho tiempo. Hay que mencionar por separado una desventaja: todos los activadores y comprobaciones de las tablas se ejecutan a través de ellas, por lo que el orden de las columnas en la pantalla y el orden de inserción de las tablas desempeñan un papel importante. Y, por ejemplo, la fecha «Corregido el» es siempre una fecha actual. Aquí y allá, sin embargo, copiar y pegar es realmente algo práctico que puede ahorrar mucho tiempo.

Cómo funciona mi exportación e importación universal de clientes

En principio, he escrito simplemente un serializador y de-serializador, que simplemente recorre todas las tablas una tras otra, crea un archivo para cada tabla y luego escribe una línea por registro de datos en este archivo. Los campos vacíos, los campos de flujo y los filtros de flujo se omiten automáticamente, lo que hace que los archivos sean algo más sencillos. Por supuesto, las tablas también pueden restringirse realizando ajustes en la función.
El deserializador, a su vez, puede entender este formato de datos, entonces crea un registro de datos por línea en el archivo en la tabla correcta.

Por cierto, este es también un buen ejemplo del uso de Recordref (recRef) y Fieldref, que mantiene el código del programa sorprendentemente corto.

Jede einzelne benutzte Tabelle von Navision / Business Central wird in eine einzelne Datendatei ausgegeben
La exportación se escribe en un único archivo de datos para cada tabla Navision / Business Central utilizada. De este modo, también se puede borrar simplemente un archivo antes de una importación (por ejemplo, la tabla de artículos). De este modo, simplemente ya no se leerá/importará en el cliente de destino.

No se emiten campos BLOB, por lo que, por ejemplo, no se ven imágenes de artículos, etc. en el cliente importado. Si lo necesita, póngase en contacto conmigo. Sin embargo, usted mismo puede añadir la exportación/importación binaria a la función. Técnicamente, se genera un archivo separado con el contenido binario para cada campo BLOB y se vuelve a leer más tarde.

Esta función es «de uso libre» con esta versión, por supuesto sin garantías ni seguridades funcionales.
El uso NO ne permite , ni siquiera en extractos, de la empresa Landefeld Druckluft & Pneumatik de Kassel ni del Dr. Ulrich Obermüller (posiblemente con sede en Kiel) . Hay una historia previa sobre ambos, que publicaré cuando tenga ocasión. He tenido experiencias increíblemente malas con ambos.

Versiones compatibles de Navision o Business Central

No funciona sin RecordRef. Recordref o RecRef se introdujo con la versión Navision 3.60, estable a partir de la 3.70. La buena noticia: Las bases de datos Navision más antiguas, p. ej. de la versión 2.01(b), etc. se pueden convertir muy fácilmente a una versión 2009 o 2009 R2 o 4/5.
Además, se utilizó la longitud de cadena ilimitada introducida con el RTC (Navision 2013, 2015, etc.). En este caso, sin embargo, los campos de datos podían emitirse simplemente línea por línea en lugar de en una sola línea como en las versiones anteriores. No hay más restricciones, por ejemplo, todas las tablas y campos que son idénticos en Navision 2009R2 y Navision 2018 (Business Central BC 14) también podrían transferirse de 2.01b o 2009R2 a BC14. Durante la importación, todos los campos que no se pueden asignar se ignoran automáticamente. Los cambios menores, por ejemplo el cambio de un campo entero a un campo de código, se realizan automáticamente.
Spoiler alert: con esta base de datos no podrá hacer más que "echar un vistazo". Pero eso ya es más de lo que puedes hacer con las herramientas oficiales.

En principio, un Navision 3.56 también podría leerse en un Navision 2.01, que a su vez podría convertirse a 2009R2, y así sucesivamente. Pero... Eso no es necesario. Simplemente puede importar una copia de seguridad de datos Navision 3.53, 3.56, 3.5x directamente con un Navision 2.01(b). Todas las tablas y todos los campos que faltan son creados automáticamente por Navision en la base de datos previamente vacía. Sin embargo, no se importa ninguna lógica de proceso, sólo los datos. A continuación, puede convertirlos a 2009R2 con un simple movimiento del dedo (bueno... casi...) y visualizar rápidamente sus datos maestros en RTC o en el cliente web.

El código se publica aquí tal y como funciona. No se mantendrá ni ampliará aquí. Si usted está interesado en esta función, pero espera obtener más de ella que simplemente restaurar rápidamente un Cronus AG, por favor póngase en contacto conmigo.

OBJECT Codeunit 50003 RTH_ExportImportCompany
{
  OBJECT-PROPERTIES
  {
  }
  PROPERTIES
  {
    Permissions=TableData 17=id,
                TableData 21=id,
                TableData 25=id,
                TableData 32=id,
                TableData 45=id,
                TableData 46=id,
                TableData 110=id,
                TableData 111=id,
                TableData 112=id,
                TableData 113=id,
                TableData 114=id,
                TableData 115=id,
                TableData 120=id,
                TableData 121=id,
                TableData 122=id,
                TableData 123=id,
                TableData 124=id,
                TableData 297=id,
                TableData 298=id,
                TableData 339=id,
                TableData 379=id,
                TableData 380=id,
                TableData 405=id,
                TableData 480=id,
                TableData 5802=id,
                TableData 5811=id,
                TableData 9004=id,
                TableData 9006=id,
                TableData 9008=id,
                TableData 9999=id;
    OnRun=VAR
            TXTImportExport@1000000000 : TextConst 'DEU=Firma %1 in Datei exportieren,Datei in Mandant %1 migrieren,Mandant %1 mit Datei initialisieren;ENU=Export company %1 to File,Migrate File into Company %1,Init Company %1 with File';
            ConfirmString@1000000001 : Text;
          BEGIN
            ConfirmString := STRSUBSTNO(TXTImportExport,COMPANYNAME);
            CASE STRMENU(ConfirmString) OF
              1 : ExportCompany;
              2 : ImportCompany(FALSE);
              3 : ImportCompany(TRUE);
            END;
          END;

  }
  CODE
  {
    VAR
      Tables@1000000002 : Record 2000000028;
      SystemObject@1000000008 : Record 2000000029;
      RecRef@1000000000 : RecordRef;
      TXTbasicPath@1000000003 : TextConst 'DEU=c:\temp\';
      Window@1000000004 : Dialog;
      DataFile@1000000001 : File;
      RecCounter@1000000005 : Integer;
      TXTextension@1000000007 : TextConst 'DEU=NavCompany';
      TXTdivider@1000000006 : TextConst 'DEU=Ý';

    LOCAL PROCEDURE ExportCompany@1000000000();
    VAR
      FileName@1000000000 : Text;
    BEGIN
      Tables.SETRANGE("Table No.",1,1999999999);
      Tables.SETFILTER("No. of Records",'>0');
      Tables.SETRANGE("Company Name",COMPANYNAME);
      Window.OPEN('Export #1########################################\@2@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@');
      IF Tables.FINDSET THEN REPEAT
        FileName := TXTbasicPath + FORMAT(Tables."Table No.") + '_'+ DELCHR(Tables."Table Name",'=','/\?*+') +'.'+ TXTextension;
        Window.UPDATE(1,FileName);
        CLEAR(RecRef);
        RecRef.OPEN(Tables."Table No.");
        IF RecRef.READPERMISSION THEN
          IF RecRef.FINDSET THEN BEGIN
            CLEAR(DataFile);
            DataFile.TEXTMODE(TRUE);
            DataFile.CREATE(FileName,TEXTENCODING::UTF8);
            CLEAR(RecCounter);
            REPEAT
              RecCounter += 1;
              IF RecCounter MOD 1000 = 0 THEN BEGIN
                Window.UPDATE(2,ROUND(RecCounter / Tables."No. of Records" * 10000,1,'<'));
                CLEAR(RecCounter);
              END;
              DataFile.WRITE(ExportRecord(RecRef));
            UNTIL RecRef.NEXT = 0;
            DataFile.CLOSE;
          END;
      UNTIL Tables.NEXT = 0;
      Window.CLOSE;
    END;

    LOCAL PROCEDURE ExportRecord@1000000002(pRecRef@1000000000 : RecordRef) RecordString : Text;
    VAR
      FieldRef@1000000001 : FieldRef;
      FieldCounter@1000000002 : Integer;
      FieldAsText@1000000003 : Text;
    BEGIN
      FOR FieldCounter := 1 TO pRecRef.FIELDCOUNT DO BEGIN
        FieldRef := pRecRef.FIELDINDEX(FieldCounter);
        IF FORMAT(FieldRef.CLASS) = 'Normal' THEN BEGIN
          CLEAR(FieldAsText);
          CASE FORMAT(FieldRef.TYPE) OF
            'BLOB','Binary','Media','MediaSet':;
          ELSE
            FieldAsText := FORMAT(FieldRef,0,9);
          END;
          FieldAsText := CONVERTSTR(FieldAsText,TXTdivider,'_');
          IF FieldAsText <> '' THEN
            RecordString += TXTdivider + FORMAT(FieldRef.NUMBER) +';'+FieldAsText;
        END;
      END;
    END;

    LOCAL PROCEDURE ImportCompany@1000000001(pInitTables@1000000000 : Boolean);
    VAR
      FileList@1000000001 : Record 2000000022;
      TableNo@1000000002 : Integer;
      TXTallTables@1000000003 : TextConst 'DEU="Sollen ALLE Tabellen gel”scht werden? Nein=nur die eingelesenen.";ENU="Clear ALL Tables? No=Only imported."';
      DataFileLen@1000000004 : Integer;
      DataFileLine@1000000005 : Text;
    BEGIN
      IF pInitTables THEN
        IF CONFIRM(TXTallTables) THEN BEGIN
          Window.OPEN('Delete Table #1###########');
          Tables.SETFILTER("No. of Records",'>0');
          Tables.SETRANGE("Table No.",1,1999999999);
          IF Tables.FINDSET THEN REPEAT
            Window.UPDATE(1,Tables."Table No.");
            CLEAR(RecRef);
            RecRef.OPEN(Tables."Table No.");
            RecRef.DELETEALL;
          UNTIL Tables.NEXT = 0;
          Window.CLOSE;
          COMMIT;
        END;

      Window.OPEN(
        'Import #1########################################\'+
        '@2@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@\'+
        '#3########################################');
      FileList.SETRANGE(Path,TXTbasicPath);
      FileList.SETFILTER(Name,'@*'+TXTextension);
      FileList.SETFILTER(Size,'>0');
      IF FileList.FINDSET THEN REPEAT
        Window.UPDATE(1,FileList.Name);
        EVALUATE(TableNo,COPYSTR(FileList.Name,1,STRPOS(FileList.Name,'_')-1));
        CLEAR(RecRef);
        RecRef.OPEN(TableNo);
        IF RecRef.WRITEPERMISSION THEN BEGIN
          DataFile.TEXTMODE(TRUE);
          DataFile.OPEN(FileList.Path + FileList.Name,TEXTENCODING::UTF8);
          DataFileLen := DataFile.LEN;
          WHILE DataFile.POS < DataFileLen DO BEGIN
            IF DataFile.POS MOD 1000 = 0 THEN
              Window.UPDATE(2,ROUND(DataFile.POS / DataFileLen * 10000,1,'<'));
            DataFile.READ(DataFileLine);
            ImportRecord(RecRef,DataFileLine);
          END;
          DataFile.CLOSE;
        END;
        COMMIT;
      UNTIL FileList.NEXT = 0;
      Window.CLOSE;
    END;

    LOCAL PROCEDURE ImportRecord@1000000003(pRecRef@1000000000 : RecordRef;pDataLine@1000000001 : Text);
    VAR
      FieldRef@1000000002 : FieldRef;
      FieldNo@1000000003 : Integer;
      FieldContent@1000000004 : Text;
      FieldContentPosition@1000000005 : Integer;
      FieldContentLen@1000000006 : Integer;
      RecCounter@1000000007 : Integer;
    BEGIN
      WHILE STRLEN(pDataLine) > 0  DO BEGIN
        IF COPYSTR(pDataLine,1,1) = TXTdivider THEN
          pDataLine := COPYSTR(pDataLine,2);
        EVALUATE(FieldNo,COPYSTR(pDataLine,1,STRPOS(pDataLine,';')-1));
        IF pRecRef.FIELDEXIST(FieldNo) THEN BEGIN
          FieldRef := RecRef.FIELD(FieldNo);
          FieldContentPosition := STRPOS(pDataLine,';')+1;
          IF STRPOS(pDataLine,TXTdivider) > 0 THEN BEGIN
            FieldContentLen := STRPOS(pDataLine,TXTdivider) - FieldContentPosition;
            FieldContent := COPYSTR(pDataLine,FieldContentPosition,FieldContentLen);
            pDataLine := COPYSTR(pDataLine,STRPOS(pDataLine,TXTdivider)+1);
          END ELSE BEGIN
            FieldContent := COPYSTR(pDataLine,STRPOS(pDataLine,';')+1);
            CLEAR(pDataLine);
          END;
          IF EVALUATE(FieldRef,FieldContent) THEN;
        END;

      END;
      IF pRecRef.INSERT THEN BEGIN
        RecCounter += 1;
        IF RecCounter = 100 THEN BEGIN
          Window.UPDATE(3,pRecRef.GETPOSITION);
          CLEAR(RecCounter);
        END;
      END;
    END;

    BEGIN
    END.
  }
}