MyDinaup

El paquete NuGet que Dinaup genera con una clase por sección, informe y documento dinámico de tu esquema.

MyDinaup es la biblioteca .NET que Dinaup genera leyendo tu esquema: cada sección, informe y documento dinámico de tu licencia se convierte en una clase con los nombres reales de tus campos. El SDK Dinaup se conecta a la API; MyDinaup añade las clases de tu modelo.

Antes de empezar

  • El paquete NuGet Dinaup, para net10.0. Ver SDK .NET.
  • Una clave API de tu licencia. Ver Claves API.
  • Tu paquete {Empresa}.MyDinaup. Los ejemplos de esta página salen de DemoUp.MyDinaup, un modelo de ejemplo que depende de Dinaup y compila para net10.0.
dotnet add package Dinaup
dotnet add package DemoUp.MyDinaup

Claves internas frente a constantes

Sin MyDinaup identificas cada campo por su clave interna:

// Sin MyDinaup: claves de columna a pelo
var data = new Dictionary<string, string>
{
    { "pr_30655031", "SC-4471" },
    { "nombre", "Almacén central" }
};

Esas claves (pr_30655031, pr_506847515) no se autocompletan y un error tipográfico solo aparece cuando la petición falla. MyDinaup las expone como constantes con el nombre del campo:

// Con MyDinaup: nombres de tu esquema
using static DemoUp.MyDinaup.SectionsD;

var data = new Dictionary<string, string>
{
    { AlmacenesD.AlmacenesES.SendcloudID, "SC-4471" },
    { AlmacenesD.AlmacenesES.TextoPrincipal, "Almacén central" }
};

SectionsD, Reports y DynamicDocuments son clases parciales, no espacios de nombres: se importan con using static. Un using sin static sobre ellas no compila.

using Dinaup;
using static DemoUp.MyDinaup.SectionsD;
using static DemoUp.MyDinaup.Reports.FuncionalidadD;

Qué contiene

CarpetaClase generadaHereda de
Secciones/SectionsD.{Seccion}D, con {Seccion}ES y {Seccion}C anidadasDinaupRowBase (la fila C)
Informes/{Categoria}/Reports.{Categoria}D.{Informe}C con su fila {Informe}_RowCDinaupReportBase<RowC>
DocDinamicos/{Categoria}/DynamicDocuments.{Categoria}D.{Documento}CDinaupDynamicDocumentBase
Enumeraciones.vbLos tipos de lista de tu esquema como enum
Constants.vbConstants.{Catalogo}.{Valor} como DinaupBasicInformation, solo para las secciones de catálogo y hasta 50 valores por sección
PGSync/PGSync.{Informe}Model, solo en licencias con PG SyncDinaup.Database.Definitions.BaseModelConverter

El código generado es VB.NET con OptionStrict Off. Lo consumes igual desde C#.

Secciones

Una sección es una tabla de tu licencia: Almacenes, Entidades, Ventas. Por cada una, MyDinaup genera dentro de SectionsD una clase {Seccion}D con dos clases anidadas y dos métodos de lectura:

MiembroQué es
{Seccion}D._SectionIDEl GUID de la sección como string.
{Seccion}D._SectionIDGUIDEl mismo GUID como Guid. Es el que piden RunWriteOperationAsync y RowsGetAsync.
{Seccion}D.GetRowByIdAsync(client, id)Devuelve una fila {Seccion}C, o null si id es Guid.Empty o no existe.
{Seccion}D.GetRowsAsync(client, RowsRequestParameters)Devuelve List<{Seccion}C> con las filas que cumplen el filtro.
{Seccion}ESLas claves de campo como constantes string, con _SectionID (Guid), _Table (nombre de la tabla), _FieldIDs (clave a GUID de campo) y FieldsByRole.
{Seccion}CLa fila tipada. Hereda de DinaupRowBase: LoadData, ToDic, ToWriteOperation(), Base__ID, Base__Label.

Las plantillas base de cada sección (ficheros B. - {Seccion}.vb) generan {Seccion}BaseD con la misma forma.

Partial Public Class SectionsD
  Public Class AlmacenesD
      Public Shared ReadOnly _SectionID As String = "7eec3e34-fbbd-4f1e-a77b-d4a6145686a3"
      Public Shared ReadOnly _SectionIDGUID As New Guid("7eec3e34-fbbd-4f1e-a77b-d4a6145686a3")

      Public Class AlmacenesES
          Public Shared ReadOnly SendcloudID$ = "pr_30655031"
          Public Shared ReadOnly TextoPrincipal$ = "nombre"
          Public Shared ReadOnly FechaAlta_UTC$ = "pr_400105496714"
          Public Shared ReadOnly ReferenciaResponsable$ = "pr_20010549681"
      End Class

      Public Class AlmacenesC
          Inherits DinaupRowBase
          Public Property SendcloudID As String
          Public Property FechaAlta_UTC As DateTime?
          Public Property Color As EnumTextoEstiloE?
          Public Property ReferenciaResponsable As Dinaup.DinaupBasicInformation
      End Class
  End Class
End Class

Un campo que apunta a otra sección se tipa como DinaupBasicInformation: Id, Title, SectionID e ImageId del registro relacionado, sin segunda consulta. Los campos de sistema (ID, FechaAltaDato_UTC, FechaUltimaModificacion_UTC, Eliminado, Empresa) tienen el setter privado: los pone el servidor.

using Dinaup;
using static DemoUp.MyDinaup.SectionsD;

var almacenes = await AlmacenesD.GetRowsAsync(client, new RowsRequestParameters("eliminado", "=", false));
foreach (var almacen in almacenes)
{
    Console.WriteLine($"{almacen.TextoPrincipal}: {almacen.ReferenciaResponsable?.Title}");
}

var uno = await AlmacenesD.GetRowByIdAsync(client, almacenes[0].ID);

RowsRequestParameters tiene constructores por Guid, por lista de Guid y por (campo, operador, valor), y las propiedades Limit, Skip y QuerySearch. Limit vale 100 por defecto. Para leer muchas filas, pagina con Skip.

GetRowsAsync trae la sección entera más los textos de sus relaciones. Para listados o volumen, usa un informe: solo devuelve las columnas que pide y pagina en el servidor.

Para escribir, combina las constantes de {Seccion}ES con una WriteOperation:

var wop = new WriteOperation(Guid.Empty);
wop.DataMainRow.Add(AlmacenesD.AlmacenesES.TextoPrincipal, "Almacén central");
wop.DataMainRow.Add(AlmacenesD.AlmacenesES.SendcloudID, "SC-4471");

await client.RunWriteOperationAsync(AlmacenesD._SectionIDGUID, wop, false);
wop.EnsureSuccess();
Guid nuevoId = wop.WriteOperationResult.RowID;

Informes

Un informe es una consulta tipada. Por cada uno, MyDinaup genera Reports.{Categoria}D.{Informe}C, heredera de DinaupReportBase<RowC>, con la fila anidada {Informe}_RowC: una propiedad por columna, ya con su tipo.

Partial Public Class Reports
  Partial Public Class FuncionalidadD
      Public Class APIAlmacenesC
          Inherits dinaup.DinaupReportBase(Of APIAlmacenes_RowC)
          Public Shared _ReportID As String = "83fd57a3-893c-4651-adf9-d5d980af2c85"
          Public Shared _ReportIDGuid As Guid = New Guid("83fd57a3-893c-4651-adf9-d5d980af2c85")
          Public Shared _SectionIdGuid As Guid = New Guid("7eec3e34-fbbd-4f1e-a77b-d4a6145686a3")

          Public Class APIAlmacenes_RowC
              Implements IReportRow
              Public Property ID As Guid
              Public Property TextoPrincipal As String = ""
              Public Property DisponibleEnTPV As Boolean
              Public Property FechaIA As DateTime
              Public Property Color As EnumTextoEstiloE
          End Class
      End Class
  End Class
End Class

La fila implementa IReportRow, IDinaupRow (Id, Label, SectionID, ImageId) e IDataFechaIA, lleva atributos ProtoBuf para caché y la constante SchemaHash del esquema con el que se generó. Al cargar la respuesta, cada columna se convierte con una extensión del paquete Dinaup según su tipo: .STR() para texto, .ToGUID() para identificadores, .BOOL() para booleanos, .ToDateTime_UTC() para fechas y .INT(0) para enteros y enums.

Miembros heredados de DinaupReportBase<RowC> que usas a diario:

MiembroQué hace
ExecuteQueryAsync(client, page, resultsPerPage = 2000, querysearch = "", adminMode = false, includeFiles = false, includeFieldsDetails = false)Ejecuta una página del informe.
LoadAllRowsAsync(client, pageSize = 10000, maxRows = 50000000, adminMode = false)Recorre todas las páginas y devuelve List<RowC>.
Rows, RowsDicLas filas de la última respuesta, como lista y como diccionario por ID.
CurrentPage, ExistNextPage, ExecuteQuery_NextPageAsync(), TotalResults, TotalPagesPaginación. TotalResults y TotalPages están marcadas [Obsolete]: el recuento del servidor no es fiable y ExistNextPage depende de él. Recorre pidiendo páginas hasta que una vuelva corta, o con LoadAllRowsAsync. Ver Cliente Dinaup.
AddFilter(campo, operador, valor), AddFilterIn, AddFilterBetween, AddOrder(campo, desc), AddVariable(clave, valor)Filtros, orden y variables antes de ejecutar.
TolerateMissingColumnsQué pasa si el servidor no devuelve una columna del modelo.
MaxFechaIA, TokenChangesFecha de actividad más alta y token que cambia con cada carga.
ColIdByColProperty, GetColIDByProperty(prop)GUID de columna a partir del nombre de la propiedad.
using Dinaup;
using static DemoUp.MyDinaup.Reports.FuncionalidadD;

var client = await DinaupClientC.ConnectAsync(
    endPoint: "https://api.dinaup.com/v2/tu-codigo",
    publicKey: "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
    secretKey: "tu-secret-key"
);

var report = new APIAlmacenesC();
report.AddFilter("eliminado", "=", false);
await report.ExecuteQueryAsync(client, page: 1, resultsPerPage: 50);

foreach (var row in report.Rows)
{
    Console.WriteLine($"{row.TextoPrincipal}: {row.DisponibleEnTPV}");
}

El informe generado comprueba que cada columna existe antes de leerla. Si falta alguna, TolerateMissingColumns decide:

  • false (valor por defecto): lanza Exception con el nombre del informe y las columnas ausentes, y lo registra con Dinaup.Logs.Error.
  • true: registra un aviso con Dinaup.Logs.Warning y deja esas propiedades en su valor por defecto.

Dinaup.DinaupReportSettings.TolerateMissingColumns fija el valor inicial para todos los informes del proceso; cada instancia lo puede cambiar.

Documentos dinámicos

Un documento dinámico es un guion que se ejecuta en el servidor y devuelve HTML, JSON o PDF: una factura, un correo, un volcado JSON. MyDinaup genera DynamicDocuments.{Categoria}D.{Documento}C, heredera de DinaupDynamicDocumentBase, que fija RequestParameters, Id y Title en su constructor. Encima de la clase va un comentario con el tipo del documento y su código en forma legible.

Partial Public Class DynamicDocuments
  Partial Class APID
      '  DOCUMENTO DINAMICO: Sesión
      '  Tipo:        API
      '  Codigo (forma legible: campos/secciones/funciones por nombre):
      '      <!--:  F.WriteText(D.SesionActual.TextoPrincipal)  :-->
      Public Class SesionC
          Inherits DinaupDynamicDocumentBase
          Sub New()
              RequestParameters = New DynamicDocumentGetRequestParameters(New Guid("73fd6203-3109-4572-8ad0-8c58702dd1a5"))
              Me.ID = New Guid("73fd6203-3109-4572-8ad0-8c58702dd1a5")
              Me.Title = "Sesión"
          End Sub
      End Class
  End Class
End Class

SetVariableValue(clave, valor) rellena las variables del documento y ExecuteAsync(client) devuelve un DynamicDocumentsGetResponse con Content, URL, FileName y Metadata.

using static DemoUp.MyDinaup.DynamicDocuments;

var doc = new APID.SesionC();
var respuesta = await doc.ExecuteAsync(client);
Console.WriteLine(respuesta.Content);

Enumeraciones y constantes

  • Enumeraciones.vb: los tipos de lista de tu esquema como enum de .NET, cada valor con su atributo Description. EnumTextoEstiloE va de Indefinido = 0 a Estilo20 = 20; EnumTareaEstadoE recoge los estados de tarea. Las filas con campos de ese tipo los usan.

  • Constants.vb: los valores de las secciones de catálogo como constantes. Constants.EstadosDeVentas.Abierta, Pagada y Anulada son DinaupBasicInformation con Id, Title y SectionID; cada catálogo tiene GetDic(), que devuelve Dictionary<Guid, DinaupBasicInformation>.

    No todas las secciones entran. Entra si deriva de una de las 25 secciones base de catálogo del núcleo: estados, tipos, categorías, familias, motivos, métodos, libros registro y jornadas. También entra si su título empieza por Estado, Tipo, Categoría, Clasificación, Familia, Motivo, Método, Fase, Etapa o Prioridad. En inglés cuenta la última palabra: Status, Type, Category y sus equivalentes. Cada sección da como mucho 50 constantes: las de sus 50 primeras filas por fecha de alta. Una fila sin nombre no da constante.

PGSync

En licencias con PG Sync, la carpeta PGSync/ trae una clase PGSync.{Informe}Model por informe sincronizado: hereda de Dinaup.Database.Definitions.BaseModelConverter, implementa IRow y declara Tabla, Campos y LastModifiedFieldDatetimeUTC para leer la réplica de PostgreSQL con Dinaup.Database.

El esquema documentado en el código

Cada constante de campo lleva su comportamiento en el servidor como documentación XML, y cada sección incluye sus scripts como comentarios.

Anotaciones de cada campo

El comentario aparece en el editor al pasar el cursor o autocompletar. Un campo real de la sección Proyectos:

''' <summary>
''' Field ID: 6cde977d-fc04-04f6-27ac-3247ad830765
''' This field is related to the 'bd46bc13-a3be-43c7-bdf6-b063bcc082aa' section (Tipos de proyecto).
''' Auto-filled with Referencia dato: To Do (Siempre).
''' Auto-managed: filled and locked by the server, do not provide it.
''' Text field: up to 36 characters.
''' </summary>
Public Shared ReadOnly ReferenciaTipo$ = "pr_30010431914"
AnotaciónQué significa para tu código
Field ID: <guid>El GUID del campo, el mismo que _FieldIDs.
This field is related to the '<guid>' section (Nombre).Es una relación: escribe el GUID de un registro de esa sección.
Auto-filled with <origen> (Siempre).El servidor lo rellena con un campo de la sesión, una constante o un dato de referencia. Con Siempre, no intentes sobrescribirlo.
Auto-managed: filled and locked by the server, do not provide it.No lo envíes en la escritura: lo pone y bloquea el servidor.
READ-ONLY: auto-calculated by the server from the section: <guid> (Nombre). Do not write it.Contador o suma calculada desde otra sección. Escribirlo no tiene efecto.
Read-only: mirror/embedded field derived by the server from its source section.Campo espejo de otra sección.
Read-only: the main text is generated automatically. / Read-only: the main date is assigned automatically.Texto principal o fecha principal calculados por el servidor.
Read-only: auto-filled from its list document; it cannot be assigned.Lo rellena el documento de su lista.
REST write policy: can be set when creating the record, but read-only on update.Solo acepta valor en el alta.
Read-only via REST: auto-set by the server, never writable.Campos de sistema: nunca se escriben.
Required: you must provide this value when creating the record.Obligatorio al crear.
Unique: the value must not be duplicated within the section.Sin duplicados en la sección.
Text field: up to N characters.Longitud máxima del texto.
Numeric size: up to N integer digits and N decimals.Dígitos enteros y decimales admitidos.
Numeric validation: only values greater than 0 / only zero or positive valuesEl servidor rechaza negativos, y el cero en el primer caso.
Semantic role: URL / phone number / email address / Spanish tax id NIF/CIFFormato que el servidor valida o normaliza (correo a minúsculas, NIF a mayúsculas).

Revisar estas anotaciones antes de construir una WriteOperation evita los dos fallos típicos: enviar campos que gestiona el servidor y omitir los obligatorios.

Los scripts de la sección

Debajo de las constantes, cada sección incluye un bloque COMPORTAMIENTO / SCRIPTS con la lógica que el servidor ejecuta sobre sus registros. Cada script trae Script, Cuando, Campo y Codigo:

'  ---------------------------------------------------------------------
'  Script:  Estado cambiado
'  Cuando:  Campo cambiado
'  Campo:   pr_50010431912
'  Codigo:
'      if C.ReferenciaEstado.Estado = S.Enums.estadotramite.pendiente
'          C.EnProceso = 1
'      else
'          C.EnProceso = 0
'          end
'  ---------------------------------------------------------------------

Tu aplicación no ejecuta ese código: documenta lo que pasa en el servidor cuando escribes en esa sección. Si una escritura devuelve un error de validación o un campo cambia de valor solo, la explicación está en este bloque. La sintaxis es DinaScript, con C. apuntando al registro en edición.

Regenerar la biblioteca

MyDinaup no se escribe: lo genera Dinaup. Cuando cambias el modelo en Flex (un campo, una sección, un informe), regeneras la biblioteca para que el código vuelva a reflejar el esquema.

Abre SDK .NET

En play.dinaup.com, abre la app Desarrollo y, en el menú, Conectar → SDK .NET. La tarjeta 5. Tu biblioteca MyDinaup la ve cualquiera con acceso a Desarrollo.

Regenera

Pulsa Regenerar MyDinaup y confirma con Regenerar. Dinaup vuelve a escribir la biblioteca entera. Tarda varios minutos y la pantalla espera hasta que termina: no la cierres. Al acabar, el aviso MyDinaup regenerado confirma que la biblioteca está lista.

Actualiza la referencia

Sube la versión de {Empresa}.MyDinaup en tu proyecto. El paquete depende del SDK Dinaup, así que actualiza los dos a la vez.

Si el esquema cambia y no regeneras, el modelo y el servidor se desincronizan: un informe pide una columna que ya no existe y lanza excepción. TolerateMissingColumns te deja cargar el resto; regenerar es la solución de fondo.

Qué modelo elegir

PaqueteCuándo
{Empresa}.MyDinaupAplicación vinculada a tu licencia. Es el único que refleja tu esquema.
DemoUp.MyDinaupPruebas y ejemplos. Su esquema no es el tuyo.

Límites

  • Nombres del esquema. Las clases salen con los nombres de tus secciones y campos (APIVentasC, ProductosES). No es configurable.
  • VB.NET generado. El idioma del paquete no condiciona el de tu aplicación.
  • Regeneración a mano. Un cambio de esquema exige volver a pulsar Regenerar MyDinaup.
  • Datos maestros con GetRowsAsync. Lee la sección entera; para listados usa informes.

La conexión, la lectura y la escritura están en Cliente Dinaup; la pantalla de Play, en SDK .NET de Play.

En esta página