josecar1osBuen tutorial Pablo, si pudieras enviarlo a mi correo te lo agradeceria mucho. josecarlitos@outlook.com Gracias3 weeks ago
Are you sure you want to
Natxo Pistatxo Algarrobo at CIC Consulting InformáticoMuy buenas, Pablo. El manual me parece muy completo y no paro de echarle vistazos todos los días para hacerme con la forma de programar con C/AL. ¿Me podrías enviar a ifermort87@gmail.com la presentación? Gracias.3 weeks ago
Are you sure you want to
PedroErcegHola Pablo , excelente manual pero me podrías hacer favor de enviarmelo. este es el correo pedro_erceg@hotmail.com3 months ago
Are you sure you want to
josegpemunozcQue tal Pablo, me parece excelente tu manual, estoy empezando a trabajar con navision y realmente casi no hay material en la web, me podrias enviar este manual, te lo agradecería bastante, en caso de que lo puedas hacer te dejo mi direccion de correo josegpemunozc@hotmail.com. Saludos. José., gracias por tu apoyo...5 months ago
Are you sure you want to
Maria PerezHola Pablo, me parece muy bueno tu manual, stoy empezando a trabajar con navision y se consigue poco material por ahi, por favor podrias enviarme este manual a mi email, me seria de mucha utilidad de verdad, y si tienes mas informacion sobre como programar C/AL te estaria inmensamente agradecida en que me la facilitaras. Aqui te dejo mi correo: mamelin026@hotmail.com. Saludos. Maria.1 year ago
Are you sure you want to
migelo123ola mi podrias mandar el manual ami correo law522@hotmail.com esque recien estoy aprendiendo navision y tu manual me vendria super grAcias de antemano..1 year ago
Are you sure you want to
migelo123OLA PABLO pliss me podrias enviar ese manual de nav a mi correo: law522@hotmail.com estoy empezando con nav gracias de antemano1 year ago
Are you sure you want to
Pablo Guevarahola tocayo, me agrado mucho el manual, estoy empezando con el NAV y me gustaria conocerlo mas a fondo, me lo podrias enviar a pablo31531@hotmail.com de antemano gracias y espero poder seguirte en otros manuales que saques1 year ago
Programación con C/AL para Microsoft Business Solutions NavisionPresentation Transcript
Programación en Lenguaje C/AL para Microsoft Business Solutions Navision Pablo Espada Bueno www.esbupa.com www.programadorautonomo.net Nota: Microsoft, Navision, C/AL, etc… son marcas registradas de Microsoft
Habitualmente me dedico a impartir formación y a labores de desarrollo y consultoría en .NET
También imparto formaciones sobre Desarrollo en Navision
Si desea que colabore con usted impartiéndoles una formación o desarrollando algún proyecto, puede contactarme:
Web
www.programadorautonomo.net
www.esbupa.com
Email
[email_address]
[email_address]
Espero que les guste la presentación
Contacto
Lenguaje C/AL - Indice
Tipos de datos
Variables
Funciones
Operadores
Sentencias
Asignación
Decisión (IF, CASE)
Iteración (FOR, REPEAT, WHILE)
Otras
Comentarios
Tablas
Acceso a objetos
Formularios
Informes
Unidades de código
DataPorts
Funciones comunes
SumIndexFields
Flowfields
Diálogos
Acceso a ficheros
Depurador
Seguimiento de Código
Asistente para código
OCX
BLOB
Formateo estándar
Introducción
Lenguaje 4GL para trabajar en entorno Navision
Especializado en trabajo sobre la BBDD relacional
Integrado en entorno Windows
OCX para acceso a datos de otras aplicaciones
Acceso a ficheros
Tipos de datos
Variables fundamentales: Numéricas
Integer
Números entre -2.147.483.647 y +2.147.483.647.
BigInteger
Número de 64 bits.
Se usa L para indicar que es un entero largo: bi := 3983200032984209L.
Decimal
Números entre -10E63 y +10E63.
18 dígitos significativos.
Char
Un carácter entre 0 y 255, convertible libremente de entero a carácter.
Operable como un integer o como un carácter:
C := 'A';
C := S[2];
C := C + 1;
Option
Número de opción entre -2.147.483.647 y +2.147.483.647 , convertible libremente de entero a opción. Las opciones se declaran simbólicamente con la propiedad OptionString de la variable: OptionString = Oferta,Pedido,Factura,Abono
Tipos de datos (II)
Variables fundamentales: De Cadena
Text
Cadenas de hasta 250 caracteres.
Sus caracteres son indizables:
Nombre[3]
Code
Cadenas de texto de hasta 250 caracteres.
En mayúsculas.
El sistema hace automáticamente la conversión, y quita espacios iniciales y finales. Sus caracteres son indizables:
CodFormasPago[3]
Tipos de datos (III)
Variables fundamentales: Fecha y Hora
Date
Almacena una fecha.
Se inicializa con 0D.
hoy := 220704D;
Time
Almacena una hora
Se inicializa con 0T
hora := 123000T;
DateTime
Almacena una hora UTC. Siempre se mostrará adaptada al horario local
Se inicializa con 0T
fechahora := December 31, 2004, 14:20:59.999.;
Tipos de Datos (y IV)
Variables fundamentales: Booleanas
Boolean
Valores lógicos: TRUE o FALSE
Tipos Complejos
C/AL incluye un conjunto de tipos complejos utilizados en ciertos casos
BLOB
Se utiliza para almacenar valores binarios (imágenes, ficheros, videos, etc..) y se almacena de forma externa al registro de la base de datos. Tamaño máx 2GB
Record
Un record se asocia con un registro de cada tabla.
El acceso a los campos se realiza escribiendo el nombre del registro, un punto y el nombre del campo:
EJ: Customer.”No.”
Tipos Complejos (II)
Form
Representa un Formulario. Cada formulario estará compuesto por un conjunto de controles
Report
Representa un Informe
Codeunit
Contenedores de código, organizado en funciones
File
Tipo Fichero. Permite acceder a un fichero del sistema de ficheros
Tipos Complejos (III)
Dialog
Representa un cuadro de diálogo.
DateFormula
Representa una fórmula para la función CALCDATE
GUID
Identificador Único del sistema. 16 bytes:
12345678-1234-1234-1234-1234567890AB
TableFilter
Permite aplicar un filtro a una tabla. Sólo utilizado para Permisos
Tipos Complejos (IV)
RecordRef
Puntero a un Registro. Se diferencia con el tipo Record en que, a priori, desconocemos la tabla a la que va a apuntar.
El equivalente para campos es el FieldRef
El equivalente para claves es el KeyRef
RecordID
Almacena el ID de la Tabla junto con la Clave Primaria.
Similar al BLOB pero sólo para contenidos de texto. MAX 2GB
Variables
Inicialización
C/AL inicializa las variables por defecto a los siguientes valores:
Boolean: FALSE
Numeric: 0
Strings: ''
Date: 0D
Time: 0T
Variables (II)
Definición
Las variables en C/AL pueden ser :
Locales : Su ámbito es la función donde se definen
Globales : Su ámbito es el objeto donde se definen
Variables (III)
Ejemplo:
Crearemos una nueva CodeUnit
Definiremos un conjunto de variables (locales y globales)
Podemos crear una variable Option y mostrar sus valores así:
MESSAGE('The value of %1 is %2','LoopNo',LoopNo);
Variables (IV)
Arrays y matrices
Se definen con la propiedad Dimensions de la variable
Dimensions=4;3
Se las referencia con corchetes
SaldoCtaBanco[2,2]
los índices tienen rango 1…n
Funciones:
CLEAR (Borra todo el Array)
ARRAYLEN (Devuelve la Longitud del Array)
Variables del Sistema
Variables del sistema (system-defined variables)
C/SIDE las crea y deja disponibles para el programador en ciertos contextos
Rec
Cuando se modifica un registro, Rec contiene el registro en su estado modificado.
xRec
Cuando se modifica un registro, xRec contiene el registro antes de la modificación.
CurrForm
Variable que representa el objeto Form actual.
CurrReport
Variable que representa el objeto Report actual.
RequestOptionsForm
Variable que representa el formulario de diálogo de entrada al objeto Report actual.
CurrFieldNo
El número de campo del campo actual desde el que se llamó al disparador.
Funciones
Definición
La función se define con un nombre, una serie de parámetros opcionales y un valor de retorno opcional. Pueden tener variables locales.
Los parámetros pueden ser por referencia (se modifica su valor, ej: “valor”) o por valor (no se altera el valor, ej: “flag”)
Se pueden llamar desde otros objetos
Operadores
Operador de C/AL Significado
. campo de registro, control de formulario o informe
( ) paréntesis
[ ] indización
:: ámbito
+ suma
- resta
* multiplicación
/ división
DIV división entera
MOD resto
> mayor que
>= mayor o igual que
< menor que
<= menor o igual que
= igual a
<> diferente de
IN pertenencia a un rango (conjunto)
AND Y lógico
OR O lógico
NOT negación lógica
XOR O excluyente lógico
.. Rango
Operadores (II)
1. . campo de un registro
[] indización
() paréntesis
:: ámbito
2. NOT negación lógica
- inversión de signo o signo negativo
+ signo positivo
3. * multiplicación
/ división decimal
DIV división entera
MOD resto
AND Y lógico
XOR O excluyente lógico
4. + suma - resta OR O lógico 5. > mayor que < menor que >= mayor o igual que <= menor o igual que = igual que <> distinto de IN pertenencia a conjunto 6. .. rango Precedencia
Operadores (III)
Ejemplos
Creamos un nuevo formulario tipo Ficha
Añadimos 3 TextBox y un Botón (Ejecutar)
Asociamos los 3 TextBox con 3 variables:
Value1: Integer
Value2: Integer
Result: Boolean
Al pulsar Ejecutar, realizamos las siguientes comparaciónes:
Result := Value1 > Value2;
Result := (Value1 >= Value2) AND (Value1 <= Value2 * 2)
Sentencias - Normas
Notación y reglas
Una sentencia comienza en ; como separador de la anterior.
La parte ELSE de las sentencias IF es parte de la misma sentencia.
[ ] indica opcionalidad en esa parte de la sentencia.
Un bloque de sentencias contiene un conjunto de sentencias entre BEGIN y END;
Begin
<sentencia>
<sentencia>
..
End;
Una <expresion> devuelve un valor.
Una <expr-asignación> asigna el valor resultado de la expresión a una variable.
El nombre de los campos, si contiene espacios o caracteres especiales, se escribe entre “comillas”
Sentencias (I)
Asignación
Operador de asignación
hoy := 220704D;
valor := 4;
Como consecuencia de llamada a función
Valor de retorno de una función
Function Cuadrado (valor : Integer) cuad : Integer
Begin
cuad := valor * valor
End;
valor := Cuadrado(3); // Valor será igual a 9
Paso de parámetro por referencia a una función
Function Cubo (VAR valor : Integer)
Begin
valor := valor * valor * valor
End;
valor := 2;
Cubo(valor); // Valor será igual a 8
Operador de Cadenas
El símbolo ‘+’ se utiliza para concatenar cadenas
¿Qué ocurre si realizamos una asignación de una cadena con el resultado de concatenar otras dos, y dicho resultado es de mayor tamaño que la cadena?
Se produce un error de ejecución
Lo podemos solucionar comprobando primero dicho desbordamiento:
MAXSTRLEN nos devuelve el tamaño máximo de cadena
COPYSTR nos permite copiar n caracteres de una cadena a otra.
Usar F5 (Symbol Menu) para ayudarse
Sentencias (II)
Decisión
IF
Evalúa la condición, si es cierta se ejecuta el bloque de sentencias del IF , en otro caso el de la parte ELSE.
IF <condición> THEN
<bloque de sentencias>
[ ELSE
<bloque de sentencias> ]
Ejemplo
IF (Cantidad = 0) AND ("Cantidad facturada" <> 0) THEN
TESTFIELD("Nº orden mov. producto asoc.")
ELSE BEGIN
IF Cantidad <> "Cantidad facturada" THEN
TESTFIELD("Cantidad facturada",0);
TESTFIELD("Nº orden mov. producto asoc.",0);
END;
Ejemplos
Modificaremos el formulario anterior de la siguiente forma:
Definición Variables Execute OnPush Execute Clear
Ejemplos
Añadir lo necesario para calcular la media de unidades vendidas/compradas
Contadores de veces que se compra/vende
Totales de Ventas/Compras
Ejemplos
Sobre el ejemplo anterior, añadimos la opción una lista de 10 TextBox y un Array de 10 decimales
Debemos hacer que cada vez que pulsemos el botón Ejecutar, el resultado se muestre en una posición distinta del Array
Sentencias (III)
Decisión
CASE
Evalúa la expresión y ejecuta el bloque de sentencias del valor correspondiente. Si no hay un valor igual, ejecuta el bloque de sentencias del ELSE .
Las sentencias dentro del WITH se refieren al registro, formulario, etc.
WITH Clie DO BEGIN
"No." := '1';
Name := 'Pepe';
Address := 'Rue del Percebe, nº 13';
City := 'Niu llor';
END;
EXIT
Salir de un segmento de código o función (se puede retornar el valor)
FUNCTION Absoluto (valor : Integer) ret : Integer
BEGIN
IF (valor < 0) THEN BEGIN
ret := -valor;
EXIT;
END;
EXIT(valor);
END;
Comentarios
// - Una sola línea
// Find next register no.
IF ItemReg.FIND(‘+’) THEN
ItemRegNo := ItemReg.”Nº” + 1
ELSE
ItemRegNo := 1;
{} – Varias líneas
{ Find next
register no. }
IF ItemReg.FIND(‘+’) THEN
ItemRegNo := ItemReg.”Nº” + 1
ELSE
ItemRegNo := 1;
Ejemplos
Modificar el formulario para que se muestren siempre los 10 últimos resultados, mostrando siempre en la primera posición (la superior) el último resultado obtenido
Ejemplos
Añadimos al formulario un botón “Ordenar” y realizaremos una ordenación de los elementos a través del método de la burbuja
Ejemplos Repetimos la ordenación hasta que el array está ordenado
Ejemplos Mejoramos el Algoritmo sabiendo que en cada iteración el último elemento siempre queda “ordenado”
Tablas
Dónde introducir código
Disparadores de tabla:
OnInsert . Se ejecuta al insertar un registro en la tabla.
OnModify . Se ejecuta al modiicar un campo de un registro de la tabla.
OnDelete . Se ejecuta al borrar un registro de la tabla.
OnRename . Se ejecuta al modificar un campo que forma parte de la clave primaria de un registro de la tabla.
Disparadores de campos en la tabla:
OnValidate . Se ejecuta al modificar el valor de un campo.
OnLookup . Se ejecuta al pulsar F6 sobre el campo para buscar un valor.
Funciones definidas en una tabla
Se pueden definir funciones en la tabla y llamarlas desde el propio objeto o desde otros objetos.
Tablas (II)
Para acceder a tablas se definen variables tipo Record
Modificación de campos de la tabla:
Mediante asignación de valores.
Clie : Record (Cliente); // Variable Clie de tipo registro de // tabla cliente
Clie.”Nº” := ‘10’;
Clie.”Nombre” := ‘Pepe’;
Con la sentencia Validate, asigna el valor y ejecuta el disparador OnValidate de cada campo asignado de la tabla Cliente.
Clie : Record (Cliente);
Clie.VALIDATE(“Nº”, ’10’);
Clie.VALIDATE(Nombre, ‘Pepe’);
Tablas (III)
Trabajo con registros de la tabla:
Inicialización. Se establece cada campo del registro a su valor por defecto dependiendo de su tipo.
Clie : Record (Cliente);
Clie.INIT;
Inserción de registros en la tabla. Con la sentencia INSERT y un párámetro que indica si se ejecuta el disparador OnInsert de la tabla o no.
Clie.VALIDATE(“Nº”, ‘10’);
Clie.VALIDATE(Nombre, ‘Pepe’);
…
Clie.INSERT(TRUE);
Modificación de registros de la tabla. Sentencia MODIFY con un parámetro que indica si se ejecuta el disparador OnModify de la tabla.
Clie.VALIDATE(Nombre, ‘Luis’);
Clie.MODIFY(TRUE);
Tablas (IV)
Trabajo con registros de la tabla:
Borrado de registros en la tabla. Con la sentencia DELETE y un párámetro que indica si se ejecuta el disparador OnDelete de la tabla o no.
Clie.DELETE(TRUE);
Modificación de campos de registros de la tabla que forman parte de la clave primaria. Sentencia RENAME con un parámetro que indica si se ejecuta el disparador OnRename de la tabla.
Clie.VALIDATE(“Nº”, ‘21’);
Clie.RENAME(TRUE);
Tablas (V)
Buscar registros en una tabla:
Obtener un registro de una tabla por su clave primaria.
Job.GET(“Job Nº.”);
Job.TESTFIELD(Blocked,FALSE);
Con las sentencias anteriores obtenemos un registro de la tabla Job (sentencia GET) y comprobamos que uno de los campos del registro tenga el valor indicado (TESTFIELD)
Obtener uno o varios registro de una tabla por claves secundarias.
Clie.RESET;
Clie.SETCURRENTKEY(Name,Address,City);
Clie.SETRANGE(Name,’Luis’);
Clie.SETFILTER(City, ‘%1 | %2’, ‘Paris’, ‘Roma’);
Primero actuamos sobre la variable Clie eliminando todos los filtros y rangos anteriores ( RESET ). Activamos una clave por la que vamos a buscar ( SETCURRENTKEY ) para que el establecimiento de rangos y la búsqueda de registro se base en índices para esta clave y sea mucho más efectiva. Se establecen filtros con dos funciones: SETRANGE y SETFILTER , básicamente iguales aunque SETFILTER permite establecer condiciones más complejas. Es recomendable establecer los filtros sobre los campos en el orden en que aparecen en la clave primaria. En este momento Clie contiene todos los registros que cumplen las condiciones indicadas en los filtros.
Tablas (VI)
Buscar registros en una tabla:
Recorrer registros de la tabla
IF Clie.FIND(‘-’) THEN
REPEAT
<tratar registro>
UNTIL Clie.NEXT = 0;
FIND permite obtener un registro dentro del filtro establecido. El parámetro indica:
‘ -’ toma el primer registro del filtro
‘ +’ toma el último registro del filtro
‘ =‘ toma el registro que es igual a los valores de las claves (por defecto)
FIND devuelve un valor Boolean y si no encuentra un registro que cumpla con las condiciones del filtro provoca un error de ejecución. Para evitar este error se puede encerrar en una sentencia IF .
NEXT toma el siguiente registro del filtro y toma un parámetro:
> 0 busca el siguiente registro saltando el número indicado
< 0 busca el registro anterior saltando el número indicado
Por defecto busca el siguiente registro.
Tablas (y VII)
OnLookup :
Buscar valores de campos en otra tabla.
Clie.SETCURRENTKEY("Nº");
Clie.SETFILTER("Nº",'<40000');
ListaClientes.SETTABLEVIEW(Clie);
IF Clie.FIND('-') THEN;
ListaClientes.SETRECORD(Clie);
ListaClientes.LOOKUPMODE(TRUE);
IF ListaClientes.RUNMODAL = ACTION::LookupOK THEN BEGIN
ListaClientes.GETRECORD(Clie);
cliente.validate(Clie."Nº “);
CLEAR(ListaClientes);
END;
Se establecen los filtros adecuados en la variable Clie de tipo Record de Clientes .
ListaClientes es de tipo Form .
SETTABLEVIEW establece la vista del formulario ListaClientes y establecemos el cliente activo mediante SETRECORD .
LOOKUPMODE hace que el formulario sirva para obtener datos.
OnAfterGetRecord . Se ejecuta al recurperar un registro de la tabla, pero antes de mostrar el registro en el formulario.
Disparadores de controles del formulario.
Botones del formulario:
Command Button
Menu Button: En cada uno de los Menu Items
Funciones definidas en un formulario:
Se pueden definir funciones en el formulario y llamarlas desde el propio objeto o desde otros objetos.
¡¡ En cualquier caso el código debe escribirse en la tabla si es posible !!
Formularios (II)
Después de recuperar un registro de la tabla, pero antes de mostrarlo en el formulario se ejecuta el trigger OnAfterGetRecord.
Ej: Antes de mostrar el registro, aplica un filtro y calcula el valor de un SumIndexField que mostrará en el formulario.
Formularios (y III)
Al pulsar sobre un botón o sobre una opción de menú en un botón desplegable se ejecuta el trigger OnPush .
Ej: Podemos invocar una función en un Codeunit con un parámetro.
Informes
Dónde introducir código
Disparadores del informe:
OnPreReport . Se procesa antes de ejecutar el informe.
Disparadores de cada DataItem:
OnPreDataItem. Se ejecuta antes de que el DataItem se procese.
OnAfterGetRecord. Se ejecuta cada vez que se obtiene un registro.
OnPostDataItem. Se ejecuta después del procesamiento del DataItem.
Request Form del informe.
Funciones definidas en un informe.
Secciones del formulario:
OnPreSection. Se ejecuta antes de que una sección sea procesada.
OnPostSection. Se ejecuta después de que una sección sea procesada.
Informes (II)
Antes de la ejecución de un Report se ejecuta el trigger OnPreReport.
Ej: Podemos utilizarlo para obtener los filtros con los que el Report se ha llamado, y después imprimirlos en una sección Header (FiltClient y FiltMovProducto) .
Informes (III)
Antes de la ejecución de un DataItem se dispara OnPreDataItem.
Ej: Podemos utilizarlo para mantener totales de un campo para una sección FOOTER con la función CREATETOTALS . También se puede establecer un registro por página con la función NEWPAGEPERRECORD , si hemos elegido la opción en el Request Form.
Después de obtener un registro del DataItem se ejecuta OnAfterGetRecord .
Ej: Podemos hacer cálculos para algún valor que se va a imprimir ( Bfº bruto ). También se puede llamar a NEWPAGE desde este disparador para cambiar de página.
Con CurrReport.SKIP podemos saltar la iteración del DataItem.
Informes (y IV)
Antes de mostrar una sección se ejecuta OnPreSection.
Ej: Podemos querer mostrar la sección o no (con la función SHOWOUTPUT ), o realizar los cáculos para un valor a imprimir.
Unidades de Código
Donde introducir código
Función OnRun :
Se crea por defecto con una nueva codeunit.
Es el punto de entrada para su ejecución por defecto .
Puede tener como parámetro una registro.
Funciones de la Codeunit:
Si se crea una función en una Codeunit se puede invocar desde otros objetos:
DiaGenTestLin : Codeunit “Dia. Gen-Test línea”;
DiaGenTestLin. Testear (LinDiaGen);
DataPorts
Dónde introducir código
Disparadores de DataPort
OnPreDataport . Antes de la ejecución del Dataport.
OnPostDataport. Después de la ejecución del Dataport.
Disparadores de DataItem
OnPreDataItem(). Antes de procesar el DataItem.
OnBeforeExportRecord(). Antes de exportar un registro.
OnAfterExportRecord(). Después de exportar un registro.
OnBeforeImportRecord(). Antes de importar un registro.
OnAfterImportRecord(). Después de importar un registro.
OnPostDataItem(). Después de procesar un DataItem.
Request form del Dataport
Funciones del Dataport
DataPorts (II)
Un Dataport puede importar datos y añadirlos a una tabla.
Ej: Añade registros a un diario. Necesita antes de comenzar saber que “Nº línea” tendrá el primer registro de los importados
DataPorts (III)
Antes de procesar un DataItem.
Ej: Una función del Dataport es llamada antes de invocar el Dataport, después se ejecuta el Dataport y se establece un filtro sobre un campo del DataItem. La variable FiltroNoCampaña no pierde su valor entre las dos llamadas si no se ejecuta CLEAR .
DataPorts (y IV)
Después de importar el registro, y antes de insertarlo en la tabla.
Ej: Se busca un nuevo número de línea y se rellenan los campo de descripción.
Funciones Comunes
Otras funciones comunmente usadas:
RESET
Elimina filtros y selección de claves en una variable Record
Copia una variable Record en otra de la misma tabla, incluyendo filtros y claves activas.
NuevoClie := COPY(Clie);
TRANSFERFIELDS
Copia el contenido de los campos de una variable Record a otra que no tiene que ser de la misma tabla. Tiene en cuenta para ello el número de campo.Los campos que no tengan correspondencia de número se establecen a sus valores por defecto.
RegHasta := TRANSFERFIELDS (RegDesde);
Funciones Comunes (III)
EVALUATE
Convertir un valor de un tipo a otro.
Valor := '010196'; // Tipo cadena
Ok := EVALUATE(VarInteger, Valor); // Entero = 10196
Ok := EVALUATE(VarDate, Valor); // Fecha = 010196D
Copia los filtros de una variable a otra de tipo Record de la misma tabla (COPYFILTER sólo copia los filtros de un campo)
Clie1.SETFILTER("No.", '<1000');
Clie1.SETRANGE(Group, 1);
Clie2.COPYFILTERS(Clie1);
TESTFIELD
Comprueba que un campo contenga un valor dado. Si se omite el segundo parámetro se comprueba que contenga un valor distinto de 0 o blanco. Si esto no se cumple muestra un mensaje de ERROR.
Clie.TESTFIELD(Bloqueado, FALSE);
Clie.TESTFIELD(“Nº”);
Funciones Comunes (VI)
LOCKTABLE
Bloquea una tabla para procesos transaccionales
FIELDNAME
Obtiene el nombre de un campo
SumIndexFields
[Ok :=] Record. CALCSUMS (Campo1 [, Campo2] ,...)
Devuelve la suma para uno (o varios) SumIndexField.
Debe estar activa una clave para la que se haya definido el campo.
No debe haber filtros en campos fuera de la clave.
Si no se cumplen las condiciones anteriores, se devuelve FALSE (o se lanza un mensaje de error).
estoy empezando con nav gracias de antemano 1 year ago
de antemano gracias y espero poder seguirte en otros manuales que saques 1 year ago