Services & Adapters

ERP functions (formule)

Placeholder per funzioni formula ERP-native registrabili nel motore Fortune Sheet (=ERP.FATTURATO, =ERP.ORDINI, ...). Da implementare nel consumer.

Cosa fornisce la libreria

import { erpFunctions } from '@pzeta/vue-foglidicalcolo'
// → ErpFormulaFunction[]

Un array di placeholder per 5 funzioni ERP-native pronte per essere registrate nell'engine formule di Fortune Sheet:

FunzioneArgomenti attesi
ERP.FATTURATOtipooperazione?, dataDa?, dataA?, idcliente?
ERP.ORDINIidtipodocumento?, dataDa?, dataA?, idcliente?
ERP.SCADENZEdataDa?, dataA?
ERP.CLIENTIcodtipoanagrafica?
ERP.ARTICOLIidelementitipo?
Sono placeholder: tutti gli handler lanciano Error('Not implemented'). La libreria definisce solo i nomi e le firme; l'implementazione concreta (chiamate a ErpDataService, aggregazione risultati, formattazione output) è responsabilità del consumer.

Tipo ErpFormulaFunction

interface ErpFormulaFunction {
  name: string                                                  // es. 'ERP.FATTURATO'
  handler: (...args: (string | number | null)[]) => Promise<number | string>
}

Uso (registrazione)

import { FortuneSheetAdapter, erpFunctions } from '@pzeta/vue-foglidicalcolo'

const adapter = new FortuneSheetAdapter()
await adapter.initialize(container)
adapter.registerCustomFunctions(erpFunctions) // placeholder — lanciano errore se invocati

Una volta registrate, sono usabili come formule dalle celle:

=ERP.FATTURATO("V"; "2026-01-01"; "2026-12-31"; 42)
=ERP.ORDINI(15; "2026-01-01"; "2026-12-31")
=ERP.SCADENZE("2026-05-01"; "2026-05-31")

Implementazione concreta

Per rendere le funzioni operative, sostituisci erpFunctions con una tua versione implementata:

import { ErpDataService, FortuneSheetAdapter } from '@pzeta/vue-foglidicalcolo'
import type { ErpFormulaFunction } from '@pzeta/vue-foglidicalcolo'

const erp = new ErpDataService('https://api.example.com/rest')

const customErpFunctions: ErpFormulaFunction[] = [
  {
    name: 'ERP.FATTURATO',
    handler: async (tipooperazione, dataDa, dataA, idcliente) => {
      try {
        const rows = await erp.fetchFatture({
          tipooperazione: tipooperazione as string | undefined,
          dataDa: dataDa as string | undefined,
          dataA: dataA as string | undefined,
          idcliente: idcliente as number | undefined,
          limit: 10_000,
        })
        return rows.reduce((sum, r) => sum + Number(r.imponibile ?? 0), 0)
      } catch (err) {
        return `#ERR_${err instanceof Error ? err.message.slice(0, 20) : 'FETCH'}`
      }
    },
  },
  {
    name: 'ERP.ORDINI',
    handler: async (idtipodocumento, dataDa, dataA, idcliente) => {
      const rows = await erp.fetchOrdini({
        idtipodocumento: idtipodocumento as number | undefined,
        dataDa: dataDa as string | undefined,
        dataA: dataA as string | undefined,
        idcliente: idcliente as number | undefined,
        limit: 10_000,
      })
      return rows.length
    },
  },
  {
    name: 'ERP.SCADENZE',
    handler: async (dataDa, dataA) => {
      const rows = await erp.fetchScadenze({
        dataDa: dataDa as string | undefined,
        dataA: dataA as string | undefined,
        limit: 10_000,
      })
      return rows.reduce((sum, r) => sum + Number(r.importo ?? 0), 0)
    },
  },
  {
    name: 'ERP.CLIENTI',
    handler: async (codtipoanagrafica) => {
      const rows = await erp.fetchAnagrafica({
        codtipoanagrafica: codtipoanagrafica as string | undefined,
        limit: 10_000,
      })
      return rows.length
    },
  },
  {
    name: 'ERP.ARTICOLI',
    handler: async (idelementitipo) => {
      const rows = await erp.fetchElementi({
        idelementitipo: idelementitipo as number | undefined,
        limit: 10_000,
      })
      return rows.length
    },
  },
]

const adapter = new FortuneSheetAdapter()
await adapter.initialize(container)
adapter.registerCustomFunctions(customErpFunctions)  // ✓ ora funzionanti

Quando i placeholder sono comunque utili

Anche senza implementarli:

  • Verificare la registrazione: le formule appaiono nell'autocomplete di Fortune Sheet
  • Test di parsing: il workbook accetta =ERP.FATTURATO(...) senza errori di sintassi
  • Documentazione: chi apre il foglio vede le funzioni "ufficiali" anche se non valutate
  • Migrazione progressiva: implementa una funzione alla volta, le altre semplicemente erroreranno

Convenzioni handler

Argomenti

Gli argomenti sono passati come (string | number | null)[]. Il numero e ordine dipendono da come l'utente invoca la formula. Buona pratica:

  • Validare/normalizzare i tipi con cast espliciti
  • Trattare null / undefined come "filtro non applicato"
  • Limitare il numero di righe scaricate (limit) per evitare timeout

Risultato

Il risultato deve essere number | string:

  • number per aggregazioni numeriche (somme, conteggi, percentuali)
  • string per testo o codici di errore (es. '#ERP_ERR', '#NA')

Gestione errori

handler: async (...args) => {
  try {
    // fetch + calcolo
    return result
  } catch (err) {
    return '#ERP_ERR'  // mostra un errore visibile nella cella
  }
}

Non propagare l'eccezione: Fortune Sheet potrebbe non gestirla in modo elegante.

Caching

Per formule chiamate centinaia di volte (es. =ERP.FATTURATO ripetuta in un foglio mensile), considera di aggiungere caching client-side:

const cache = new Map<string, number>()

handler: async (tipoop, dataDa, dataA, idcliente) => {
  const key = `${tipoop}|${dataDa}|${dataA}|${idcliente}`
  if (cache.has(key)) return cache.get(key)!

  const rows = await erp.fetchFatture({ ... })
  const total = rows.reduce(...)
  cache.set(key, total)
  return total
}

Invalidare la cache al refreshAll() del pannello ERP o al cambio dei filtri globali.

Tipi correlati