From 3a99fafe2da0a2cc85915673c7b70ed2f15b0956 Mon Sep 17 00:00:00 2001
From: guy <guy@c028cbd2-c16b-5b4b-a496-9718f37d4682>
Date: Wed, 30 Jul 2014 12:59:04 +0000
Subject: [PATCH] Generazione Fatture PA con CUP, CIG e rate

git-svn-id: svn://10.65.10.50/branches/R_10_00@22982 c028cbd2-c16b-5b4b-a496-9718f37d4682
---
 pa/pa0.cpp     |    6 +-
 pa/pa0.h       |    1 +
 pa/pa0100.cpp  | 2386 ++++++++++++++++++++++++++++++------------------
 pa/pa0100a.h   |    1 +
 pa/pa0100a.uml |   31 +-
 pa/pa0200.cpp  |   20 +
 pa/paf.ini     |  593 +++++++++---
 pa/pamenu.men  |    3 +-
 pa/patbcon.h   |   13 +
 pa/patbcon.uml |  107 +++
 10 files changed, 2150 insertions(+), 1011 deletions(-)
 create mode 100644 pa/pa0200.cpp
 create mode 100644 pa/patbcon.h
 create mode 100644 pa/patbcon.uml

diff --git a/pa/pa0.cpp b/pa/pa0.cpp
index 6eee59d16..a5b805318 100644
--- a/pa/pa0.cpp
+++ b/pa/pa0.cpp
@@ -8,10 +8,8 @@ int main(int argc, char** argv)
 
   switch (r)
   {
-  case 0:
-  default:
-    rt = pa0100(argc, argv);
-    break;
+  case 1 : rt = pa0200(argc, argv); break;
+  default: rt = pa0100(argc, argv); break;
   }
   return rt;
 }
diff --git a/pa/pa0.h b/pa/pa0.h
index 616d1a825..79f49944a 100644
--- a/pa/pa0.h
+++ b/pa/pa0.h
@@ -2,5 +2,6 @@
 #define __PA0_H
 
 int pa0100(int argc, char* argv[]);
+int pa0200(int argc, char* argv[]);
 
 #endif
diff --git a/pa/pa0100.cpp b/pa/pa0100.cpp
index 18e4e43e0..0746c0495 100644
--- a/pa/pa0100.cpp
+++ b/pa/pa0100.cpp
@@ -1,879 +1,1507 @@
-#include <applicat.h>
-#include <automask.h>
-#include <dongle.h>
-#include <progind.h>
-#include <utility.h>
-
-#include "../ve/velib05.h"
-
-#include "pa0.h"
-#include "pa0100a.h"
-
-#include "../fe/felib.h"
-
-#include <nditte.h>
-
-/////////////////////////////////////////////////////////////////////////////////////
-// Globals
-/////////////////////////////////////////////////////////////////////////////////////
-
-XVT_SQLDB _db = NULL;  // PAF sqlite db
-
-/////////////////////////////////////////////////////////////////////////////////////
-// TPaf_record
-/////////////////////////////////////////////////////////////////////////////////////
-
-class TPaf_record : public TObject
-{
-  TString8 _table;
-  TToken_string _key;
-  TAssoc_array _fields;
-
-protected:
-  void copy(const TPaf_record& rec) { _table = rec._table; _key = rec._key; _fields = rec._fields; }
-  const TString& var2str(const TVariant& var) const;
-
-public:
-  void reset() { _fields.destroy(); }
-  void set(const char* fld, const TVariant& var);
-  void set(const char* fld, long var);
-  void set(const char* fld, const char* var);
-  void set(const char* fld, const real& var);
-  void set(const char* fld, const TString& var);
-  void set(const char* fld, const TDate& var);
-  void set(const char* fld, bool var);
-  const TVariant& get(const char* fld) const;
-
-  bool insert();
-  bool remove();
-  bool search();
-  bool search(const char* k1, const char* k2, const char* k3 = NULL);
-
-  virtual TObject* dup() const { return new TPaf_record(*this); }
-  virtual bool ok() const { return _table.not_empty(); }
-  
-  TPaf_record& operator=(const TPaf_record& rec) { copy(rec); return *this; }
-  TPaf_record(const TPaf_record& rec) { copy(rec); }
-  TPaf_record(const char* table);
-};
-
-void TPaf_record::set(const char* fld, const TVariant& var)
-{
-  CHECK(fld && *fld, "Null field name");
-
-  if (var.is_null())
-  {
-    _fields.remove(fld);
-  }
-  else
-  {
-    TVariant* obj = (TVariant*)_fields.objptr(fld);
-    if (obj != NULL)
-      *obj = var;
-    else
-      _fields.add(fld, new TVariant(var));
-  }
-}
-
-void TPaf_record::set(const char* fld, long val)
-{
-  const TVariant var(val);
-  set(fld, var);
-}
-
-void TPaf_record::set(const char* fld, const char* val)
-{
-  if (val == NULL)
-    set(fld, NULL_VARIANT);
-  else
-  {
-    const TVariant var(val);
-    set(fld, var);
-  }
-}
-
-void TPaf_record::set(const char* fld, const TString& val)
-{
-  const TVariant var(val);
-  set(fld, var);
-}
-
-
-void TPaf_record::set(const char* fld, const real& val)
-{
-  const char* str = val.string(0, 2);
-  set(fld, str);
-}
-
-void TPaf_record::set(const char* fld, const TDate& var)
-{
-  const char* str = var.string(full, '-', full, full, amg_date);
-  set(fld, str);
-}
-
-void TPaf_record::set(const char* fld, bool var)
-{
-  set(fld, var ? "SI" : "NO");
-}
-
-
-const TVariant& TPaf_record::get(const char* fld) const
-{
-  const TVariant* var = (const TVariant*)_fields.objptr(fld);
-  return var ? *var : NULL_VARIANT;
-}
-
-const TString& TPaf_record::var2str(const TVariant& var) const
-{
-  const TString& str = var.as_string();
-
-  bool apici = var.type() == _alfafld;
-  if (apici && str[0] != '0' && real::is_natural(str))
-    apici = false;
-  
-  if (!apici)
-    return str;
-  
-  TString& tmp = get_tmp_string();
-  tmp = str;
-  for (int a = str.rfind('\''); a >= 0; a--)
-  {
-    if (tmp[a] == '\'')
-      tmp.insert("'", a);
-  }
-  tmp.insert("'", 0);
-  tmp << '\'';
-  return tmp;
-}
-
-bool TPaf_record::remove()
-{
-  TString256 query;
-  query << "DELETE FROM " << _table << " WHERE ";
-  int nkf = 0;
-  FOR_EACH_TOKEN(_key, fld)
-  {
-    const TVariant& var = get(fld);
-    if (!var.is_null())
-    {
-      if (nkf++ > 0)
-        query << " AND ";
-      query << fld << '=' << var2str(var) ;
-    }
-  }
-  CHECKS(nkf >= 2, "Can't remove partial key on table ", (const char*)_table);
-  query << ';';
-  return xvt_sql_execute(_db, query, NULL, 0L) > 0;
-}
-
-
-static int paf_search_record(void* jolly, int cols, char** names, char** values)
-{
-  TPaf_record& rec = *(TPaf_record*)jolly;
-  for (int i = 0; i < cols; i++)
-    rec.set(names[i], values[i]);
-  return 0;
-}
-
-bool TPaf_record::search()
-{
-  CHECKS(_fields.items() >= _key.items(), "Can't search partial key on table ", _table);
-  TString256 query;
-  query << "SELECT * FROM " << _table << " WHERE ";
-  FOR_EACH_TOKEN(_key, fld)
-  {
-    const TVariant& var = get(fld);
-    if (!var.is_null())
-      query << fld << '=' << var2str(var) << " AND ";
-  }
-  query.rtrim(5);
-  query << ';';
-  return xvt_sql_execute(_db, query, paf_search_record, this) == 1;
-}
-
-bool TPaf_record::search(const char* k1, const char* k2, const char* k3)
-{
-  _fields.destroy();
-
-  set(_key.get(0), k1);
-  set(_key.get(1), k2);
-  if (k3 && *k3)
-    set(_key.get(2), k3);
-
-  return search();
-}
-
-bool TPaf_record::insert()
-{
-  CHECKS(_fields.items() > _key.items(), "Can't insert empty record on table ", _table);
-
-  TString query, values;
-  query << "INSERT INTO " << _table << "\n(";
-  FOR_EACH_ASSOC_OBJECT(_fields, obj, fld, itm)
-  {
-    const TVariant& var = get(fld);
-    if (!var.is_null())
-    {
-      query << fld << ',';
-      values << var2str(var) << ',';
-    }
-  }
-  query.rtrim(1); values.rtrim(1);
-  query << ")\nVALUES (" << values << ");";
-  return xvt_sql_execute(_db, query, NULL, 0L) == 1;
-}
-
-TPaf_record::TPaf_record(const char* table) : _table(table), _key(15, ',')
-{
-  _key = ini_get_string("./paf.ini", table, "INDEX_1");
-  if (_key.empty())
-  {
-    TConfig cfg("paf.ini", table);
-    TAssoc_array& fields = cfg.list_variables();
-    FOR_EACH_ASSOC_STRING(fields, obj, key, str)
-    {
-      if (key[2] == 'K')
-        _key.add(key);
-    }
-  }
-  CHECKS(_key.full(), "Invalid primary key for table ", table);
-}
-
-/////////////////////////////////////////////////////////////////////////////////////
-// TPa_mask
-/////////////////////////////////////////////////////////////////////////////////////
-
-class TPA_mask : public TAutomask
-{
-protected:
-  virtual bool on_field_event(TOperable_field& o, TField_event e, long jolly);
-  void fill();
-
-public:
-  TPA_mask() : TAutomask("pa0100a") {}
-};
-
-void TPA_mask::fill()
-{
-  TSheet_field& docs = sfield(F_DOCS);
-  TString_array& sht = docs.rows_array();
-  docs.hide();
-  
-  sht.destroy();
-
-  TString query;
-  query << "USE 17 SELECT (PADESTIN!='')&&(PARIFAMM!='')"
-        << "\nJOIN 20 INTO TIPOCF=TIPOCF CODCF==CODCF"
-        << "\nFROM TIPOCF=C\nTO TIPOCF=C";
-
-  TISAM_recordset clifo_pa(query);
-  const TRecnotype n = clifo_pa.items();
-  if (n > 0)
-  {
-    const TDate dal = get(F_DATAINI);
-    TProgress_monitor pi(n, NULL);
-    for (bool okc = clifo_pa.move_first(); okc; okc = clifo_pa.move_next())
-    {
-      if (!pi.addstatus(1))
-        break;
-
-      query.cut(0);
-      query << "USE 33 KEY 2\nSELECT (BETWEEN(STATO,2,8))";
-      if (!get_bool(F_SHOWALL))
-        query << "&&(PAF!='X')";
-      query << "\nFROM TIPOCF=C CODCF=#CLIENTE PROVV=D ANNO=2014 DATADOC=" << dal.date2ansi()
-            << "\nTO TIPOCF=C CODCF=#CLIENTE PROVV=D";
-      TISAM_recordset doc_pa(query);
-      doc_pa.set_var("#CLIENTE", clifo_pa.get(CLI_CODCF));
-      for (bool okd = doc_pa.move_first(); okd; okd = doc_pa.move_next())
-      {
-        const TTipo_documento& td = cached_tipodoc(doc_pa.get(DOC_TIPODOC).as_string());
-        if (!td.is_fattura())
-          continue;
-        TToken_string* row = new TToken_string;
-        *row = doc_pa.get(DOC_PAF).as_bool() ? " " : "X";
-        row->add(doc_pa.get(DOC_ANNO).as_int(), 1);
-        row->add(doc_pa.get(DOC_CODNUM).as_string());
-        row->add(doc_pa.get(DOC_NDOC).as_int());
-        row->add(doc_pa.get(DOC_DATADOC).as_date());
-        row->add(clifo_pa.get(CFV_CODCF).as_int());
-        row->add(clifo_pa.get("20."CLI_RAGSOC).as_string());
-        row->add(clifo_pa.get(CFV_PADESTIN).as_string());
-        row->add(clifo_pa.get(CFV_PARIFAMM).as_string());
-        
-        sht.add(row);
-      }
-    }
-  }
-  docs.force_update();
-  docs.show();
-}
-
-bool TPA_mask::on_field_event(TOperable_field& o, TField_event e, long jolly)
-{
-  switch (o.dlg())
-  {
-  case F_DATAINI:
-    if (e == fe_init)
-      o.set("01-06-2014");
-    if (e == fe_modify)
-      fill();
-    break;
-  case F_SHOWALL:
-    if (e == fe_modify)
-      fill();
-    break;
-  case F_DOCS:
-    if (e == fe_init)
-      fill();
-    if (e == se_query_add || e == se_query_del)
-      return false;
-    break;
-  default: break;
-  }
-  return true;
-}
-
-/////////////////////////////////////////////////////////////////////////////////////
-// TDoc2Paf
-/////////////////////////////////////////////////////////////////////////////////////
-
-class TDoc2Paf : public TSkeleton_application
-{
-  TAnagrafica _ditta;
-
-private:
-  int parse_line(const TString& line, TString& var, TString& val) const;
-  void create_table(TScanner& paf, const TString& table);
-
-protected:
-  const TString& cessionario(const TDocumento& doc);
-  const TString& fattura(const TDocumento& doc);
-  
-  void elabora(TDocumentoEsteso& doc);
-  void elabora(const TRectype& rec);
-  void elabora(const TDoc_key& key);
-  void elabora(const TFilename& ini);
-
-public:
-  virtual bool create();
-  virtual bool destroy();
-  virtual void main_loop();
-};
-
-const TString& TDoc2Paf::cessionario(const TDocumento& doc)
-{
-  const TString& cess = doc.clifor().vendite().get(CFV_PADESTIN);
-  CHECK(cess.full(), "Destinatario fattura elettronica non valido");
-  return cess;
-}
-
-const TString& TDoc2Paf::fattura(const TDocumento& doc)
-{
-  TString& key = get_tmp_string();
-  key << doc.get_date(DOC_DATADOC).date2ansi() << '/' 
-      << doc.numerazione() << '/' << doc.numero();
-  return key;
-}
-
-void TDoc2Paf::elabora(TDocumentoEsteso& doc)
-{
-  const TFirm& firm = prefix().firm();
-  TString8 prginv; prginv.format("%08d", ini_get_int("./paf.ini", "Main", "PRGINV") + 1);
-
-  const TString8  hfatt = cessionario(doc);  // Codice univoco di 6 caratteri dell'ufficio P.A.
-  const TString80 bfatt = fattura(doc);      // Codice univoco di 20 caratteri del documento
-
-  // <DatiTrassmissione>
-  TPaf_record paf0100f("PAF0100F");
-  paf0100f.set("P1KHFATT", hfatt);
-  paf0100f.set("P1KBFATT", bfatt);
-  paf0100f.remove();
-
-  paf0100f.set("P1PAESE",  "IT");
-  paf0100f.set("P1CODICE", _ditta.partita_IVA());
-  paf0100f.set("P1PRGINV", prginv);
-  paf0100f.set("P1FTRASM", "SDI10");
-
-  paf0100f.set("P1CDEST", hfatt);
-  TString80 tel; tel << firm.get(NDT_PTEL) << firm.get(NDT_TEL);
-  paf0100f.set("P1TELEF", tel);
-  paf0100f.set("P1MAIL", firm.get(NDT_MAIL));
-  paf0100f.insert();
-  // </DatiTrassmissione>
-  
-  // <CedentePrestatore>
-  TPaf_record paf0200f("PAF0200F");
-  paf0200f.set("P2KHFATT", hfatt);
-  paf0200f.set("P2KBFATT", bfatt);
-  paf0200f.remove();
-  paf0200f.set("P2PAESE",  paf0100f.get("P1PAESE")); // Sempre IT
-  paf0200f.set("P2CODICE", _ditta.partita_IVA());
-  paf0200f.set("P2FISCA",  _ditta.codice_fiscale());
-  if (_ditta.fisica())
-  {
-    paf0200f.set("P2NOME", _ditta.nome());
-    paf0200f.set("P2COGN", _ditta.cognome());
-  }
-  else
-  {
-    paf0200f.set("P2DENOM", _ditta.ragione_sociale());
-  }
-  paf0200f.set("P2RFISC", "RF01");
-  
-  // DatiSede
-  paf0200f.set("P2SINDI", _ditta.indirizzo_residenza());
-  paf0200f.set("P2SCOMU", _ditta.comune_residenza());
-  paf0200f.set("P2SPROV", _ditta.provincia_residenza());
-  paf0200f.set("P2SNAZI", paf0100f.get("P1PAESE"));
-  
-  /*
-  // DatiStabile
-  paf0200f.set("P2OINDI", _ditta.indirizzo_residenza());
-  paf0200f.set("P2OCOMU", _ditta.comune_residenza());
-  paf0200f.set("P2OPROV", _ditta.provincia_residenza());
-  paf0200f.set("P2ONAZI", paf0100f.get("P1PAESE"));
-
-  paf0200f.insert();
-  */
-
-  // </CedentePrestatore>
-
-  // <CessionarioCommittente>
-  TAnagrafica cliente(doc.clifor());
-
-  TPaf_record paf0400f("PAF0400F");
-  paf0400f.set("P4KHFATT", hfatt);
-  paf0400f.set("P4KBFATT", bfatt);
-  paf0400f.remove();
-  paf0400f.set("P4PAESE",  "IT");
-  paf0400f.set("P4CODICE", cliente.partita_IVA());
-  paf0400f.set("P4FISCA",  cliente.codice_fiscale());
-  if (cliente.fisica())
-  {
-    paf0400f.set("P4NOME", cliente.nome());
-    paf0400f.set("P4COGN", cliente.cognome());
-  }
-  else
-  {
-    paf0400f.set("P4DENOM", cliente.ragione_sociale());
-  }
-  paf0400f.set("P4RFISC", "RF01");
-  
-  // DatiSede
-  paf0400f.set("P4SINDI", cliente.indirizzo_residenza());
-  paf0400f.set("P4SCOMU", cliente.comune_residenza());
-  paf0400f.set("P4SPROV", cliente.provincia_residenza());
-  paf0400f.set("P4SNAZI", "IT");
-  paf0400f.insert();
-  // </CessionarioCommittente>
-
-  // <DatiGenerali>
-  TPaf_record paf0700f("PAF0700F");
-  paf0700f.set("P7KHFATT", hfatt);
-  paf0700f.set("P7KBFATT", bfatt);
-  paf0700f.remove();
-  paf0700f.set("P7TDOC",   doc.is_nota_credito() ? "TD04" : "TD01");
-  paf0700f.set("P7DIVISA", "EUR"); // Aggiungere codice ISO 4217 a tabella divise (%VAL)
-  paf0700f.set("P7DATA", doc.data());
-  paf0700f.set("P7NUME", doc.numero());
-  paf0700f.insert();
-
-  // <ScontoMaggiorazione>
-  TPaf_record paf0900f("PAF0900F");
-  paf0900f.set("P9KHFATT", hfatt);
-  paf0900f.set("P9KBFATT", bfatt);
-  paf0900f.remove();
-  TToken_string sconto(doc.get(DOC_SCONTOPERC), '+');
-  sconto.strip_spaces();
-  long nlin_sconto = 1;
-  FOR_EACH_TOKEN(sconto, str)
-  {
-    const real sconto = str;
-    if (!sconto.is_zero())
-    {
-      paf0900f.set("P9NLIN", nlin_sconto++);
-      paf0900f.set("P9TSCO", sconto > ZERO ? "SC" : "MG");
-      paf0900f.set("P9PSCO", sconto);
-    }
-    paf0900f.insert();
-  }
-  // </ScontoMaggiorazione>
-
-  TPaf_record paf2700f("PAF2700F");
-  paf2700f.set("PQKHFATT", hfatt);
-  paf2700f.set("PQKBFATT", bfatt);
-  paf2700f.remove();
-  paf2700f.set("PQITDOC",  doc.totale_doc());
-  paf2700f.set("PQCAUS",   doc.tipo().descrizione());
-  paf2700f.set("PQART73",  true);
-  paf2700f.insert();
-  // </DatiGenerali>
-
-  // <DatiBeniServizi>
-  TPaf_record paf1800f("PAF1800F");
-  paf1800f.set("PIKHFATT", hfatt);
-  paf1800f.set("PIKBFATT", bfatt);
-  paf1800f.remove(); // Cancella tutte le righe documento
-  
-  long pinlin = 0;
-  const int nrows = doc.rows();
-  FOR_EACH_PHYSICAL_RDOC(doc, r, rdoc) 
-  {
-    paf1800f.reset();
-    paf1800f.set("PIKHFATT", hfatt);
-    paf1800f.set("PIKBFATT", bfatt);
-    paf1800f.set("PINLIN",   ++pinlin);
-    paf1800f.set("PIDESC",  rdoc->get(RDOC_DESCR));
-    if (rdoc->is_merce())
-    {
-      paf1800f.set("PIQTA",   rdoc->quantita());
-      paf1800f.set("PIUNMIS", rdoc->get(RDOC_UMQTA));
-      paf1800f.set("PIPREZ",  rdoc->prezzo(true, false));
-      paf1800f.set("PIPRZT",  rdoc->importo(true, false));
-      const real aliquota = cache().get("%IVA", rdoc->get(RDOC_CODIVA), "R0");
-      paf1800f.set("PIAIVA", aliquota);
-
-      // <ScontoMaggiorazione>
-      TPaf_record paf2000f("PAF2000F");
-      paf2000f.set("PJKHFATT", hfatt);
-      paf2000f.set("PJKBFATT", bfatt);
-      paf2000f.remove();
-      TToken_string sconto(rdoc->get(RDOC_SCONTO), '+');
-      sconto.strip_spaces();
-      if (sconto.items())
-      {
-        /*
-        long nlin_sconto = 1;
-        FOR_EACH_TOKEN(sconto, str)
-        {
-          const real perc = str;
-          if (!perc.is_zero())
-          {
-            paf2000f.set("PJNLIN", nlin_sconto++);
-            paf2000f.set("PJTSCO", perc > ZERO ? "SC" : "MG");
-            paf2000f.set("PJPSCO", perc);
-            paf2000f.insert();
-          }
-        }
-        */
-        const real perc = sconto;
-        if (!perc.is_zero())
-        {
-          paf2000f.set("PJKNLIN", pinlin);
-          paf2000f.set("PJTSCO", perc > ZERO ? "SC" : "MG");
-          paf2000f.set("PJPSCO", perc);
-          paf2000f.insert();
-        }
-      }
-
-      // </ScontoMaggiorazione>
-    }
-    paf1800f.insert();
-  }
-  // </DatiBeniServizi>
-
-  // <DatiRiepilogo>
-  TPaf_record paf2200f("PAF2200F");
-  paf2200f.set("PLKHFATT", hfatt);
-  paf2200f.set("PLKBFATT", bfatt);
-  paf2200f.remove(); // Cancella tutte le righe di riepilogo IVA
-
-  TAssoc_array& tiva = doc.tabella_iva(false);
-  FOR_EACH_ASSOC_OBJECT(tiva, obj, key, itm)
-  {
-    const TRiepilogo_iva& riva = *(const TRiepilogo_iva*)itm;
-    const real aliquota = riva.cod_iva().percentuale();
-    paf2200f.set("PLALIVA", aliquota);
-    const TString& tipo = riva.cod_iva().tipo();
-    if (tipo.full())
-    {
-      if (tipo == "NS") paf2200f.set("PLNATU", "N2"); else
-      if (tipo == "NI") paf2200f.set("PLNATU", "N3"); else
-      if (tipo == "ES") paf2200f.set("PLNATU", "N4");
-    }
-    paf2200f.set("PLIMPO", riva.imponibile());
-    paf2200f.set("PLIMPS", riva.imposta());
-    // Esigibilit� IVA: immediata o no?
-    const char* eiva = doc.get_bool(DOC_LIQDIFF) || doc.get_bool(DOC_IVAXCASSA) ? "D" : "I";
-    paf2200f.set("PLEIVA", eiva);
-    
-    paf2200f.insert();
-  }
-  // </DatiRiepilogo>
-
-  // <DatiPagamento>
-  TPaf_record paf2400f("PAF2400F");
-  paf2400f.set("PNKHFATT", hfatt);
-  paf2400f.set("PNKBFATT", bfatt);
-  paf2400f.remove(); // Cancella i dati pagamento
-  const TPagamento& pag = doc.pagamento();
-
-  doc.scadenze_recalc();                 // Ricalcola array delle rate
-  TString_array& scad = doc.scadenze();
-  const int nrate = scad.items();        // Conta rate generate 
-  paf2400f.set("PNCPAG", nrate > 1 ? "TP01" : "TP02"); // A rate (TP01) o una soluzione(TP02)?
-  paf2400f.insert();
-  
-  TPaf_record paf2500f("PAF2500F");
-  paf2500f.set("POKHFATT", hfatt);
-  paf2500f.set("POKBFATT", bfatt);
-  paf2500f.remove(); // Cancella tutte le rate
-  for (int nr = 0; nr < nrate; nr++)
-  {
-    paf2500f.set("POKNLIN", long(nr+1));       // Numero riga
-    const char* mod_pag = "MP01";              // Modalit� di pagamento
-    const int n = nr < pag.n_rate() ? nr : 0;  // Si assicura che il numero riga sia accettabile
-    switch (pag.tipo_rata(n))
-    {
-    case _bonfico: mod_pag = "MP05"; break;    // bonifico
-    case _rid    : mod_pag = "MP09"; break;    // RID
-    case _ric_ban: mod_pag = "MP12"; break;    // RIBA
-    default      : mod_pag = "MP01"; break;    // contanti
-    }
-    paf2500f.set("POMPAGAM", mod_pag);
-    
-    TToken_string& riga = scad.row(nr);          // Data|Importo   
-    paf2500f.set("POUSCAD", TDate(riga.get(0))); // Data scadenza
-    paf2500f.set("POIMPO",  real(riga.get()));   // Importo rata 
-    paf2500f.set("POCPAG",  pag.code());         // Codice pagamento di CAMPO   
-    paf2500f.insert();
-  }
-
-  // </DatiPagamento>
-
-  ini_set_string("./paf.ini", "Main", "PRGINV", prginv);
-}
-
-void TDoc2Paf::elabora(const TRectype& rec)
-{
-  TDocumentoEsteso doc;
-  if (doc.read(rec) == NOERR)
-    elabora(doc);
-}
-
-void TDoc2Paf::elabora(const TDoc_key& key)
-{
-  TRectype rec(LF_DOC);
-  rec.put(DOC_PROVV,  key.provv());
-  rec.put(DOC_ANNO,   key.anno());
-  rec.put(DOC_CODNUM, key.codnum());
-  rec.put(DOC_NDOC,   key.ndoc());
-  elabora(rec);
-}
-
-void TDoc2Paf::elabora(const TFilename& ini)
-{
-  TConfig cfg(ini, "33");
-  const int anno  = cfg.get_int(DOC_ANNO);
-  const long ndoc = cfg.get_long(DOC_NDOC);
-  const TFixed_string codnum(cfg.get(DOC_CODNUM)); // lascio sapientemente per ultima la get di una stringa
-  const TDoc_key key(anno, codnum, ndoc);
-  elabora(key);
-}
-
-void TDoc2Paf::main_loop()
-{
-  bool is_batch = false;
-  for (int a = 1; a < argc(); a++)
-  {
-    TFilename ini = argv(a);
-    if (ini.starts_with("-i", true) || ini.starts_with("/i", true))
-      ini.ltrim(2);
-    if (ini.exist())
-    {
-      is_batch = true;
-      elabora(ini);
-    }
-    else
-    {
-      if (ini.find('*') >= 0 || ini.find('?') >= 0)
-      {
-        TString_array f; list_files(ini, f);
-        FOR_EACH_ARRAY_ROW(f, r, row)
-        {
-          ini = *row;
-          if (ini.exist())
-          {
-            is_batch = true;
-            elabora(ini);
-          }
-        }
-      }
-    }
-  }
-
-  if (!is_batch)
-  {
-    TPA_mask mask;
-
-    for (;;)
-    {
-      if (mask.run() == K_ENTER)
-      {
-        TString_array& sht = mask.sfield(F_DOCS).rows_array();
-        TProgress_monitor pi(sht.items(), NULL);
-        int ndocs = 0;
-        FOR_EACH_ARRAY_ROW(sht, r, riga) 
-        {
-          if (!pi.add_status(1))
-            break;
-          if (riga->starts_with("X"))
-          {
-            const int   anno = riga->get_int(1);
-            const long  ndoc = riga->get_long(3);
-            const TFixed_string codnum(riga->get(2)); // lascio sapientemente per ultima la get di una stringa
-            const TDoc_key key(anno, codnum, ndoc);
-            elabora(key);
-            ndocs++;
-          }
-        }
-        message_box(FR("Sono stati elborati %d documenti"), ndocs);
-      }
-      else
-        break;
-    }
-  }
-}
-
-int TDoc2Paf::parse_line(const TString& line, TString& var, TString& val) const
-{
-  if (line.blank())
-    return 0;
-
-  if (line[0] == '[')
-  {
-    var = line.mid(1);
-    var.rtrim(1);
-    val.cut(0);
-    return 1;
-  }
-
-  const int equal = line.find('=');
-  if (equal < 6)
-    return 0;
-  var = line.left(equal); var.trim();
-  val = line.mid(equal+1);  val.trim();
-  return 2;
-}
-
-static SLIST_ELT xvt_slist_find_str(SLIST list, const char* str)
-{
-  SLIST_ELT e = NULL;
-  for (e = xvt_slist_get_first(list); e; e = xvt_slist_get_next(list, e))
-  {
-    const char* val = xvt_slist_get(list, e, NULL);
-    if (xvt_str_compare_ignoring_case(str, val) == 0)
-      break;
-  }
-  return e;
-}
-
-void TDoc2Paf::create_table(TScanner& paf, const TString& table)
-{
-  TString query, var, val;
-  if (xvt_sql_table_exists(_db, table))
-  {
-    SLIST fields = xvt_sql_list_fields(_db, table);
-    while (!paf.eof())
-    {
-      const TString& line = paf.line();
-      const int n = parse_line(line, var, val);
-      if (n <= 0)
-        break;
-      if (n == 1) // paragraph!
-      {
-        paf.push(line);
-        break;
-      }
-      if (var.starts_with("INDEX_"))
-        continue;
-      if (xvt_slist_find_str(fields, var) == NULL)
-      {
-        query.cut(0) << "ALTER TABLE " << table << " ADD COLUMN " << var << ' ' << val << ';'; 
-        xvt_sql_execute(_db, query, NULL, NULL); // Create table
-      }
-    }
-    xvt_slist_destroy(fields);
-  }
-  else
-  {
-    query << "CREATE TABLE " << table << " (";
-    while (!paf.eof())
-    {
-      const TString& line = paf.line();
-      const int n = parse_line(line, var, val);
-      if (n <= 0)
-        break;
-      if (n == 1)
-      {
-        paf.push(line);
-        break;
-      }
-      if (var.starts_with("INDEX_"))
-      {
-        query.rtrim(1); // toglie ultima ,
-        query << ");";
-        xvt_sql_execute(_db, query, NULL, NULL); // Create table
-        query.cut(0);
-        query << "CREATE UNIQUE INDEX "
-              << table << "_1 ON " << table 
-              << " (" << val << ");";
-        xvt_sql_execute(_db, query, NULL, NULL); // Create index
-        break;
-      }
-      else
-      {
-        query << "\n " << var << ' ' << val << ',';
-      }
-    }
-  }
-}
-
-bool TDoc2Paf::create()
-{
-  TFilename n = prefix().get_studio();  // base direcotry
-  n.add("sql"); make_dir(n);
-  n.add("paf.db");
-  _db = xvt_sql_open(n, user(), "", n.path());
-  if (_db == NULL)
-    return false;
-
-  n = "paf.ini";
-  if (n.exist())
-  {
-    TScanner paf(n);
-    while (!paf.eof())
-    {
-      const TString& p = paf.line();
-      if (p.starts_with("[PAF"))
-      {
-        const TString8 table = p.mid(1, 8);
-        create_table(paf, table);
-      }
-    }
-  }
-  else
-    return cantread_box(n);
-
-  TRectype cfven(LF_CFVEN);
-  if (cfven.type(CFV_PARIFAMM) != _alfafld)
-    return error_box(TR("Database non convertito per fatturazione elettronica"));
-
-  _ditta.init(LF_NDITTE, prefix().get_codditta());
-
-  return TSkeleton_application::create();
-}
-
-bool TDoc2Paf::destroy()
-{
-  xvt_sql_close(_db); _db = NULL;
-  return TSkeleton_application::destroy();
-}
-
-int pa0100(int argc, char* argv[])
-{
-  TDoc2Paf d2p;
-  d2p.run(argc, argv, TR("Fatturazione P.A."));
-  return 0;
-}
+#include <applicat.h>
+#include <automask.h>
+#include <execp.h>
+#include <progind.h>
+#include <utility.h>
+
+#include "../ve/velib05.h"
+
+#include "pa0.h"
+#include "pa0100a.h"
+
+#include "../fe/felib.h"
+
+#include <anagiu.h>
+#include <comuni.h>
+#include <cfven.h>
+#include <nditte.h>
+#include <unloc.h>
+#include "../cg/cfban.h"
+
+/////////////////////////////////////////////////////////////////////////////////////
+// Globals
+/////////////////////////////////////////////////////////////////////////////////////
+
+static XVT_SQLDB _db = NULL;  // PAF sqlite db
+
+/////////////////////////////////////////////////////////////////////////////////////
+// Utilities
+/////////////////////////////////////////////////////////////////////////////////////
+
+// Crea la coppia di chiavi per il db PAF a partire da un documento vero e proprio
+static bool chiave_paf(const TDocumento& doc, TString& cess, TString& numdoc)
+{
+  cess = doc.clifor().vendite().get(CFV_PADESTIN);
+  CHECK(cess.full(), "Destinatario fattura P.A. non valido");
+
+  numdoc.cut(0) << doc.get_date(DOC_DATADOC).date2ansi() << '/' 
+                << doc.numerazione() << '/' << doc.numero();
+  return cess.full();
+}
+
+// Crea la coppia di chiavi per il db PAF a partire da un semplice record di testata documento
+static bool chiave_paf(const TRectype& doc, TString& cess, TString& numdoc)
+{
+  TString16 key; key.format("C|%ld", doc.get_long(DOC_CODCF));
+  cess = cache().get(LF_CFVEN, key, CFV_PADESTIN);
+  CHECK(cess.full(), "Destinatario fattura P.A. non valido");
+
+  numdoc.cut(0) << doc.get_date(DOC_DATADOC).date2ansi() << '/' 
+                << doc.get(DOC_CODNUM) << '/' << doc.get(DOC_NDOC);
+  return cess.full();
+}
+
+// Cerca una stringa all'interno di una SLIST (Potrebbe diventare una funzione di XVT.h)
+static SLIST_ELT xvt_slist_find_str(SLIST list, const char* str)
+{
+  SLIST_ELT e = NULL;
+  for (e = xvt_slist_get_first(list); e; e = xvt_slist_get_next(list, e))
+  {
+    const char* val = xvt_slist_get(list, e, NULL);
+    if (xvt_str_compare_ignoring_case(str, val) == 0)
+      break;
+  }
+  return e;
+}
+
+// Aggiorna il file dst se pi� vecchio di src (Potrebbe diventare una funzione di XVT.h)
+bool xvt_fsys_fupdate(const char* src, const char* dst)
+{
+  bool ok = false;
+  if (xvt_fsys_file_exists(src))
+  {
+    const long tsrc = xvt_fsys_file_attr(src, XVT_FILE_ATTR_MTIME);
+    if (tsrc > 0)
+    {
+      long tdst = 0;
+      if (xvt_fsys_file_exists(dst))
+        tdst = xvt_fsys_file_attr(dst, XVT_FILE_ATTR_MTIME);
+      if (tsrc > tdst)
+        ok = xvt_fsys_fcopy(src, dst) != 0;
+    }
+  }
+
+  return ok;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////
+// TJava_profile
+/////////////////////////////////////////////////////////////////////////////////////
+
+class TJava_profile : public TObject
+{
+  TFilename _path;
+  TString_array _row;
+  bool _dirty;
+
+protected:
+  const TString& path2prop(const char* path) const;
+
+public:
+  void set(const char* key, const char* value);
+  void save();
+  TJava_profile(const char* path);
+  ~TJava_profile() { if (_dirty) save(); }
+};
+
+// Converte una stringa in un percorso per un file profile di Java
+const TString& TJava_profile::path2prop(const char* path) const
+{
+  TString percorso;
+  for (const char* c = path; *c; c++)
+  {
+    if (*c == ':' || is_slash(*c))
+      percorso << '\\';
+    percorso << *c;
+  }
+  return get_tmp_string() = percorso;
+}
+
+
+void TJava_profile::set(const char* key, const char* value)
+{
+  _dirty = true;
+  FOR_EACH_ARRAY_ROW(_row, r, line)
+  {
+    if (line->starts_with(key, true))
+    {
+      const int equal = line->find('=');
+      if (equal > 0)
+      {
+        line->cut(equal + 1);
+        *line << path2prop(value);
+        return;
+      }
+    }
+  }
+
+  TToken_string*  prop = new TToken_string(50, '=');
+  prop->add(key); prop->add(path2prop(value));
+  _row.add(prop);
+}
+
+void TJava_profile::save()
+{
+  ofstream out(_path);
+  if (out.good())
+  {
+    FOR_EACH_ARRAY_ROW(_row, r, line) if (line->full())
+      out << *line << endl;
+    _dirty = false;
+  }
+  else
+    cantwrite_box(_path);
+}
+
+TJava_profile::TJava_profile(const char* path) : _path(path), _dirty(false)
+{
+  TScanner s(_path);
+  while (!s.eof())
+  {
+    const TString& line = s.line();
+    if (line.full())
+      _row.add(new TToken_string(line, '='));
+    else
+      break;
+  }
+}
+
+/////////////////////////////////////////////////////////////////////////////////////
+// TPaf_record
+/////////////////////////////////////////////////////////////////////////////////////
+
+// Contenitore di campi di un record di database SQLite
+class TPaf_record : public TObject
+{
+  TString8 _table;
+  TToken_string _key;
+  TAssoc_array _fields;
+
+protected:
+  void copy(const TPaf_record& rec) { _table = rec._table; _key = rec._key; _fields = rec._fields; }
+  const TString& var2str(const TVariant& var) const;
+
+public:
+  void reset() { _fields.destroy(); }
+  void set(const char* fld, const TVariant& var);
+  void set(const char* fld, long var);
+  void set(const char* fld, const char* var);
+  void set(const char* fld, const real& var);
+  void set(const char* fld, const TString& var);
+  void set(const char* fld, const TDate& var);
+  void set(const char* fld, bool var);
+  const TVariant& get(const char* fld) const;
+
+  bool insert();
+  bool remove();
+  bool search();
+  bool search(const char* k1, const char* k2, const char* k3 = NULL);
+
+  virtual TObject* dup() const { return new TPaf_record(*this); }
+  virtual bool ok() const { return _table.not_empty(); }
+  
+  TPaf_record& operator=(const TPaf_record& rec) { copy(rec); return *this; }
+  TPaf_record(const TPaf_record& rec) { copy(rec); }
+  TPaf_record(const char* table);
+};
+
+// Imposta il valore di un campo variant
+void TPaf_record::set(const char* fld, const TVariant& var)
+{
+  CHECK(fld && *fld, "Null field name");
+
+  if (var.is_null())
+  {
+    _fields.remove(fld);
+  }
+  else
+  {
+    TVariant* obj = (TVariant*)_fields.objptr(fld);
+    if (obj != NULL)
+      *obj = var;
+    else
+      _fields.add(fld, new TVariant(var));
+  }
+}
+
+// Imposta il valore di un campo intero
+void TPaf_record::set(const char* fld, long val)
+{
+  const TVariant var(val);
+  set(fld, var);
+}
+
+// Imposta il valore di un campo stringa
+void TPaf_record::set(const char* fld, const char* val)
+{
+  if (val == NULL)
+    set(fld, NULL_VARIANT);
+  else
+  {
+    const TVariant var(val);
+    set(fld, var);
+  }
+}
+
+// Imposta il valore di un campo stringa
+void TPaf_record::set(const char* fld, const TString& val)
+{
+  const TVariant var(val);
+  set(fld, var);
+}
+
+// Imposta il valore di un campo numerico
+void TPaf_record::set(const char* fld, const real& val)
+{
+  const TVariant var(val);
+  set(fld, var);
+}
+
+// Imposta il valore di un campo data in formato ISO
+void TPaf_record::set(const char* fld, const TDate& val)
+{
+  if (val.ok())
+  {
+    const TVariant var(val);
+    set(fld, var);
+  }
+  else
+    set(fld, "");
+}
+
+// Imposta il valore di un campo booleano
+void TPaf_record::set(const char* fld, bool var)
+{
+  set(fld, var ? "SI" : "NO");
+}
+
+// Legge il valore di un campo variant
+const TVariant& TPaf_record::get(const char* fld) const
+{
+  const TVariant* var = (const TVariant*)_fields.objptr(fld);
+  return var ? *var : NULL_VARIANT;
+}
+
+// Converte un varian in una stringa valida per SQLite
+const TString& TPaf_record::var2str(const TVariant& var) const
+{
+  const TFieldtypes vt = var.type();
+  if (vt == _realfld)
+  {
+    TString& tmp = get_tmp_string();
+    tmp << '\'' << var.as_real().string(0, 2) << '\'';
+    return tmp;
+  }
+  if (vt == _datefld)
+  {
+    TString& tmp = get_tmp_string();
+    tmp << '\'' <<  var.as_date().string(full, '-', full, full, amg_date) << '\'';
+    return tmp;
+  }
+
+  const TString& str = var.as_string();
+
+  bool apici = vt == _alfafld;
+  if (apici && str[0] != '0' && real::is_natural(str))
+    apici = false;
+  
+  if (!apici)
+    return str;
+  
+  TString& tmp = get_tmp_string();
+  tmp = str;
+  for (int a = str.rfind('\''); a >= 0; a--)
+  {
+    if (tmp[a] == '\'')
+      tmp.insert("'", a);
+  }
+  tmp.insert("'", 0);
+  tmp << '\'';
+  return tmp;
+}
+
+// Elimina il record in base ai cmapi chiave
+bool TPaf_record::remove()
+{
+  TString256 query;
+  query << "DELETE FROM " << _table << " WHERE ";
+  int nkf = 0;
+  FOR_EACH_TOKEN(_key, fld)
+  {
+    const TVariant& var = get(fld);
+    if (!var.is_null())
+    {
+      if (nkf++ > 0)
+        query << " AND ";
+      query << fld << '=' << var2str(var) ;
+    }
+  }
+  CHECKS(nkf >= 2, "Can't remove partial key on table ", (const char*)_table);
+  query << ';';
+  return xvt_sql_execute(_db, query, NULL, 0L) > 0;
+}
+
+// Callback per la sottostante funzione search()
+static int paf_search_record(void* jolly, int cols, char** values, char** names)
+{
+  TPaf_record& rec = *(TPaf_record*)jolly;
+  for (int i = 0; i < cols; i++)
+    rec.set(names[i], values[i]);
+  return 0;
+}
+
+// Carica un record in base ai campi chiave
+bool TPaf_record::search()
+{
+  CHECKS(_fields.items() >= _key.items(), "Can't search partial key on table ", _table);
+  TString256 query;
+  query << "SELECT * FROM " << _table << " WHERE ";
+  FOR_EACH_TOKEN(_key, fld)
+  {
+    const TVariant& var = get(fld);
+    if (!var.is_null())
+      query << fld << '=' << var2str(var) << " AND ";
+  }
+  query.rtrim(5);
+  query << ';';
+  return xvt_sql_execute(_db, query, paf_search_record, this) == 1;
+}
+
+// Carica un record in base ad un massimo di 3 campi chiave
+bool TPaf_record::search(const char* k1, const char* k2, const char* k3)
+{
+  _fields.destroy();
+
+  set(_key.get(0), k1);
+  set(_key.get(1), k2);
+  if (k3 && *k3)
+    set(_key.get(2), k3);
+
+  return search();
+}
+
+// Aggiunge un record al db
+bool TPaf_record::insert()
+{
+  CHECKS(_fields.items() > _key.items(), "Can't insert empty record on table ", _table);
+
+  TString query, values;
+  query << "INSERT INTO " << _table << "\n(";
+  FOR_EACH_ASSOC_OBJECT(_fields, obj, fld, itm)
+  {
+    const TVariant& var = get(fld);
+    if (!var.is_null())
+    {
+      query << fld << ',';
+      values << var2str(var) << ',';
+    }
+  }
+  query.rtrim(1); values.rtrim(1);
+  query << ")\nVALUES (" << values << ");";
+  return xvt_sql_execute(_db, query, NULL, 0L) == 1;
+}
+
+// Crea un record della tabella data ed imposta i nomi dei campi chiave
+TPaf_record::TPaf_record(const char* table) : _table(table), _key(15, ',')
+{
+  _key = ini_get_string("./paf.ini", table, "INDEX_1");
+  if (_key.empty()) 
+  {
+    // Cerco di costruire i nomi della chiave cercando la K, come in P1_KEYHEADERFATT
+    TConfig cfg("paf.ini", table);
+    TAssoc_array& fields = cfg.list_variables();
+    FOR_EACH_ASSOC_STRING(fields, obj, key, str)
+    {
+      if (key[3] == 'K')
+        _key.add(key);
+    }
+  }
+  CHECKS(!_key.empty_items(), "Invalid primary key for table ", table);
+}
+
+/////////////////////////////////////////////////////////////////////////////////////
+// TPa_mask
+/////////////////////////////////////////////////////////////////////////////////////
+
+class TPA_mask : public TAutomask
+{
+protected:
+  virtual bool on_field_event(TOperable_field& o, TField_event e, long jolly);
+  void fill();
+
+public:
+  TPA_mask() : TAutomask("pa0100a") {}
+};
+
+void TPA_mask::fill()
+{
+  TSheet_field& docs = sfield(F_DOCS);
+  TString_array& sht = docs.rows_array();
+  docs.hide();
+  
+  sht.destroy();
+
+  // Seleziona tutti i clienti che sono pubbliche amministrazioni (PADESTIN!='')
+  TString query;
+  query << "USE 17 SELECT PADESTIN!=''"
+        << "\nJOIN 20 INTO TIPOCF=TIPOCF CODCF==CODCF"
+        << "\nFROM TIPOCF=C\nTO TIPOCF=C";
+
+  TISAM_recordset clifo_pa(query);
+  const TRecnotype n = clifo_pa.items();
+  if (n > 0)
+  {
+    const TDate dal = get(F_DATAINI);
+    const bool hide_processed = !get_bool(F_SHOWALL);
+
+    // Record di controllo per eventuali elaborazioni precedenti
+    TString hfatt(8), bfatt(20); 
+    TPaf_record paf0100f("PAF0100F");
+
+    TProgress_monitor pi(n, NULL);
+    for (bool okc = clifo_pa.move_first(); okc; okc = clifo_pa.move_next())
+    {
+      if (!pi.addstatus(1))
+        break;
+
+      query.cut(0);
+      query << "USE 33 KEY 2\nSELECT (BETWEEN(STATO,2,8))";
+      query << "\nFROM TIPOCF=C CODCF=#CLIENTE PROVV=D ANNO=2014 DATADOC=" << dal.date2ansi()
+            << "\nTO TIPOCF=C CODCF=#CLIENTE PROVV=D";
+      TISAM_recordset doc_pa(query);
+      doc_pa.set_var("#CLIENTE", clifo_pa.get(CLI_CODCF));
+      const TRectype& doc = doc_pa.cursor()->curr();
+      for (bool okd = doc_pa.move_first(); okd; okd = doc_pa.move_next())
+      {
+        const TTipo_documento& td = cached_tipodoc(doc.get(DOC_TIPODOC));
+        if (!td.is_fattura()) // Tengo per buone solo le fatture e le note di credito
+          continue;
+
+        bool sent = false;
+        if (chiave_paf(doc, hfatt, bfatt))
+        {
+          if (paf0100f.search(hfatt, bfatt))
+          {
+            sent = paf0100f.get("P1_GESTIONE").as_string() == "X";
+            if (sent && hide_processed)
+              continue;
+          }
+        }
+        TToken_string* row = new TToken_string;
+        *row = sent ? " " : "X";
+        row->add(doc_pa.get(DOC_ANNO).as_int(), 1);
+        row->add(doc_pa.get(DOC_CODNUM).as_string());
+        row->add(doc_pa.get(DOC_NDOC).as_int());
+        row->add(doc_pa.get(DOC_DATADOC).as_date());
+        row->add(clifo_pa.get(CFV_CODCF).as_int());
+        row->add(clifo_pa.get("20."CLI_RAGSOC).as_string());
+        row->add(clifo_pa.get(CFV_PADESTIN).as_string());
+        row->add(clifo_pa.get(CFV_PARIFAMM).as_string());
+        row->add(clifo_pa.get("20."CLI_COFI).as_string());
+        
+        sht.add(row);
+      }
+    }
+  }
+  docs.force_update();
+  docs.show();
+}
+
+bool TPA_mask::on_field_event(TOperable_field& o, TField_event e, long jolly)
+{
+  switch (o.dlg())
+  {
+  case F_DATAINI:
+    if (e == fe_init)
+      o.set("01-06-2014");
+    if (e == fe_modify)
+      fill();
+    break;
+  case F_SHOWALL:
+    if (e == fe_modify)
+      fill();
+    break;
+  case F_DOCS:
+    if (e == fe_init)
+      fill();
+    if (e == se_query_add || e == se_query_del)
+      return false;
+    break;
+  case DLG_USER:
+    if (e == fe_button && jolly > 0)
+    {
+      TSheet_field& docs = sfield(F_DOCS); 
+      TToken_string& row = docs.row(docs.selected());
+      TRectype doc(LF_DOC);
+      doc.put(DOC_PROVV,  'D');
+      doc.put(DOC_ANNO,   row.get(1));
+      doc.put(DOC_CODNUM, row.get());
+      doc.put(DOC_NDOC,   row.get());
+      if (doc.edit())
+        fill();
+    }
+    break;
+  default: break;
+  }
+  return true;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////
+// TDoc2Paf
+/////////////////////////////////////////////////////////////////////////////////////
+
+class TDoc2Paf : public TSkeleton_application
+{
+  TAnagrafica _ditta;
+  TFilename _dbname;
+
+private:
+  int parse_line(const TString& line, TString& var, TString& val) const;
+  bool create_table(TScanner& paf, const TString& table);
+
+  const TRectype* find_parent_row(const TRectype& rdoc) const;
+  int find_ancestors(const TRiga_documento& rdoc, TArray& ancestors) const;
+
+protected:
+  bool parse_sconto(const TString& formula, TToken_string& sconti) const;
+  bool get_bank(const TDocumento& doc, TString& iban, TString& abi, TString& cab, TString& istituto) const;
+  const char* descrizione(const TRiga_documento& rdoc) const;
+
+  bool elabora(TDocumentoEsteso& doc);
+  bool elabora(const TRectype& rec);
+  bool elabora(const TDoc_key& key);
+  bool elabora(const TFilename& ini);
+  bool genera_xml();
+
+public:
+  virtual bool create();
+  virtual bool destroy();
+  virtual void main_loop();
+};
+
+bool TDoc2Paf::parse_sconto(const TString& formula, TToken_string& sconti) const
+{
+  sconti.cut(0);
+  int start = 0;
+  for (int i = 0; ; i++)
+  {
+    const char c = formula[i];
+    if (c == '+' || c == '-' || c < ' ')
+    {
+      if (i > 0)
+      {
+        TString8 tok = formula.sub(start, i);
+        tok.replace(',', '.');
+        const real perc = tok;
+        if (!perc.is_zero())
+          sconti.add(tok);
+      }
+      if (c < ' ')
+        break;
+      start = i;
+    }
+  }
+  return sconti.full();
+}
+
+bool TDoc2Paf::get_bank(const TDocumento& doc, TString& iban, TString& abi, TString& cab, TString& istituto) const
+{
+  bool found = false;
+  TToken_string key;
+  key.add("C"); key.add(doc.codcf()); key.add("N"); key.add(1);
+  const TRectype& cfban = cache().get(LF_CFBAN, key);
+  if (!cfban.empty())
+  {
+    abi = cfban.get(CFBAN_ABI);
+    cab = cfban.get(CFBAN_CAB);
+    found = abi.full() && cab.full();
+    iban = cfban.get(CFBAN_IBAN);
+    if (iban.blank() && found)
+    {
+      key.cut(0) << abi << cab << cfban.get(CFBAN_PROGPR);
+      iban = cache().get("BNP", key, "S3");
+    }
+  }
+
+  if (!found)
+  {
+    const TRectype& cfven = doc.clifor().vendite();
+    abi = cfven.get(CFV_CODABIPR);
+    cab = cfven.get(CFV_CODCABPR);
+    found = abi.full() && cab.full();
+    if (!found)
+    {
+      abi = doc.get(DOC_CODABIP);
+      cab = doc.get(DOC_CODCABP);
+      found = abi.full() && cab.full();
+    }
+  }
+
+  if (found)
+  {
+    istituto = cache().get("%BAN", abi, "S0");
+  }
+
+  return found;
+}
+
+const char* TDoc2Paf::descrizione(const TRiga_documento& rdoc) const
+{
+  if (rdoc.get_bool(RDOC_DESCLUNGA))
+  {
+    TString tmp;
+    tmp << rdoc.get(RDOC_DESCR) << rdoc.get(RDOC_DESCEST);
+    tmp.replace('\n', ' '); tmp.strip_double_spaces();
+    TParagraph_string para(tmp, 100);
+    return para.get(0);
+  }
+  return rdoc.get(RDOC_DESCR);
+}
+
+struct TAncestor : public TObject
+{
+  TString16 _numdoc;
+  TDate _datadoc;
+
+  TAncestor(const TRectype& rdoc);
+};
+
+TAncestor::TAncestor(const TRectype& rdoc)
+{
+  TToken_string kdoc;
+  kdoc = rdoc.get(RDOC_PROVV);
+  kdoc.add(rdoc.get(RDOC_ANNO));
+  kdoc.add(rdoc.get(RDOC_CODNUM));
+  kdoc.add(rdoc.get(RDOC_NDOC));
+  const TRectype& doc = cache().get(LF_DOC, kdoc);
+  _numdoc.format("%d/%s/%ld", doc.get_int(DOC_ANNO), (const char*)doc.get(DOC_CODNUM), doc.get_long(DOC_NDOC));
+  _datadoc = doc.get_date(DOC_DATADOC);
+}
+
+const TRectype* TDoc2Paf::find_parent_row(const TRectype& rdoc) const
+{
+  const long id = rdoc.get_long(RDOC_DAIDRIGA);
+  if (id > 0L)
+  {
+    TToken_string key;
+    key.add(rdoc.get(RDOC_DACODNUM));
+    if (key.full())
+    {
+      key.add(rdoc.get(RDOC_DAANNO));
+      key.add(rdoc.get(RDOC_DAPROVV));
+      key.add(rdoc.get(RDOC_DANDOC));
+      for (int r = 0; ; r++)
+      {
+        if (r == 0)
+          key.add(id, 4);
+        else
+          key.add(r, 4);
+        const TRectype& rec = cache().get(LF_RIGHEDOC, key);
+        if (r > 0 && rec.empty()) 
+          break;
+        if (rec.get_long(RDOC_IDRIGA) == id)
+          return &rec;
+      }
+    }
+  }
+  return NULL;
+}
+
+int TDoc2Paf::find_ancestors(const TRiga_documento& rdoc, TArray& ancestors) const
+{
+  if (rdoc.is_articolo())
+  {
+    for (const TRectype* prdoc = find_parent_row(rdoc); prdoc != NULL; prdoc = find_parent_row(*prdoc))
+    {
+      const TCodice_numerazione& cn = cached_numerazione(prdoc->get(RDOC_CODNUM));
+      const int td = cn.tipo();
+      if (td > 0 && ancestors.objptr(td) == NULL)
+        ancestors.add(new TAncestor(*prdoc), td);
+    }
+  }
+  return ancestors.items();
+}
+
+bool TDoc2Paf::elabora(TDocumentoEsteso& doc)
+{
+  TString8 hfatt;  // Codice univoco di 6 caratteri dell'ufficio P.A.
+  TString80 bfatt; // Codice univoco di 20 caratteri del documento
+  if (!chiave_paf(doc, hfatt, bfatt))
+    return false;
+
+  const TFirm& firm = prefix().firm();
+  const char* const paese = "IT";
+
+  // <DatiTrassmissione>
+  TPaf_record paf0100f("PAF0100F");
+  paf0100f.set("P1_KEYHEADERFATT", hfatt);
+  paf0100f.set("P1_KEYBODYFATT",   bfatt);
+  paf0100f.remove();
+
+  paf0100f.set("P1_TRASMITTPAESE",  paese);
+  paf0100f.set("P1_TRASMITTCOD",    _ditta.partita_IVA());
+  paf0100f.set("P1_PRGINVIO",       ""); // Ci pensa SiAggPA
+  paf0100f.set("P1_FMTTRASMISS",    "SDI10");
+
+  paf0100f.set("P1_CODDEST", hfatt);
+  TString80 tel; tel << firm.get(NDT_PTEL) << firm.get(NDT_TEL);
+  paf0100f.set("P1_TELEFONO", tel);
+  paf0100f.set("P1_MAIL", firm.get(NDT_MAIL));
+  paf0100f.set("P1_GESTIONE", "D");
+  paf0100f.insert();
+  // </DatiTrassmissione>
+  
+  // <CedentePrestatore>
+  TPaf_record paf0200f("PAF0200F");
+  paf0200f.set("P2_KEYHEADERFATT", hfatt);
+  paf0200f.set("P2_KEYBODYFATT", bfatt);
+  paf0200f.remove();
+  
+  if (_ditta.partita_IVA().full())
+  {
+    paf0200f.set("P2_FISCIVAPAESE", paese); // Sempre IT
+    paf0200f.set("P2_FISCIVACOD",   _ditta.partita_IVA());
+  }
+  paf0200f.set("P2_CODFISCALE",   _ditta.codice_fiscale());
+  if (_ditta.fisica())
+  {
+    paf0200f.set("P2_ANANOME",    _ditta.nome());
+    paf0200f.set("P2_ANACOGNOME", _ditta.cognome());
+  }
+  else
+  {
+    paf0200f.set("P2_ANADENOMIN", _ditta.ragione_sociale());
+  }
+
+  const char* regime_fiscale = "RF01";
+  if (doc.get_bool(DOC_IVAXCASSA))
+  {
+    // Supponiamo volume d'affari > 200000, altrimenti sarebbe RF17
+    regime_fiscale = "RF16";
+  }
+  paf0200f.set("P2_REGFISCALE", regime_fiscale);
+  
+  // DatiSede
+  paf0200f.set("P2_SEDEIND",      _ditta.via_residenza());
+  paf0200f.set("P2_SEDENRCIVICO", _ditta.civico_residenza());
+  paf0200f.set("P2_SEDECAP",      _ditta.CAP_residenza());
+  paf0200f.set("P2_SEDECOMUNE",   _ditta.comune_residenza());
+  paf0200f.set("P2_SEDEPROV",     _ditta.provincia_residenza());
+  paf0200f.set("P2_SEDENAZ",      paese);
+  paf0200f.set("P2_GESTIONE",     "D");
+  paf0200f.insert();
+
+  TISAM_recordset unloc("USE UNLOC\nJOIN COMUNI INTO COM==COMCCIAA\nFROM CODDITTA=#DITTA\nTO CODDITTA=#DITTA");
+  unloc.set_var("#DITTA", firm.get(NDT_CODDITTA));
+  if (unloc.move_first())
+  {
+    const TString& numrea = unloc.get(ULC_NUMCCIAA).as_string();
+    if (numrea.full())
+    {
+      paf0200f.set("P2_ISCRREANUM", numrea);
+      paf0200f.set("P2_ISCRREAUFF", unloc.get("13->"COM_PROVCOM));
+    }
+  }
+  
+  TISAM_recordset anagiu("USE ANAGIU\nFROM CODANAGR=#CODICE\nTO CODANAGR=#CODICE");
+  anagiu.set_var("#CODICE", firm.get(NDT_CODANAGR));
+  if (anagiu.move_first())
+  {
+    paf0200f.set("P2_ISCRREACAP", anagiu.get(ANG_CAPSOC));
+  }
+
+  // </CedentePrestatore>
+
+  // <CessionarioCommittente>
+  TAnagrafica cliente(doc.clifor());
+
+  TPaf_record paf0400f("PAF0400F");
+  paf0400f.set("P4_KEYHEADERFATT", hfatt);
+  paf0400f.set("P4_KEYBODYFATT", bfatt);
+  paf0400f.remove();
+
+  if (cliente.partita_IVA().full())
+  {
+    paf0400f.set("P4_FISCIVAPAESE", paese);
+    paf0400f.set("P4_FISCIVACOD",   cliente.partita_IVA());
+  }
+  paf0400f.set("P4_CODFISC", cliente.codice_fiscale());
+  
+  if (cliente.fisica())
+  {
+    paf0400f.set("P4_ANANOME",    cliente.nome());
+    paf0400f.set("P4_ANACOGNOME", cliente.cognome());
+  }
+  else
+  {
+    paf0400f.set("P4_ANADENOM",   cliente.ragione_sociale());
+  } 
+  
+  // DatiSede
+  paf0400f.set("P4_SEDEIND",      cliente.via_residenza());
+  paf0400f.set("P4_SEDENRCIVICO", cliente.civico_residenza());
+  paf0400f.set("P4_SEDECAP",      cliente.CAP_residenza());
+  paf0400f.set("P4_SEDECOMUNE",   cliente.comune_residenza());
+  paf0400f.set("P4_SEDEPROV",     cliente.provincia_residenza());
+  paf0400f.set("P4_SEDENAZ",      "IT");
+  paf0400f.set("P4_GESTIONE",     "D");
+  paf0400f.insert();
+  // </CessionarioCommittente>
+
+  // <DatiGenerali>
+  TPaf_record paf0700f("PAF0700F");
+  paf0700f.set("P7_KEYHEADERFATT", hfatt);
+  paf0700f.set("P7_KEYBODYFATT",   bfatt);
+  paf0700f.remove();
+  paf0700f.set("P7_TIPODOC", doc.is_nota_credito() ? "TD04" : "TD01");
+  paf0700f.set("P7_DIVISA",  "EUR"); // Aggiungere codice ISO 4217 a tabella divise (%VAL)
+  paf0700f.set("P7_DATA",    doc.data());
+  paf0700f.set("P7_NUMERO",  doc.numero());
+  paf0700f.set("P7_GESTIONE", "D");
+  paf0700f.insert();
+
+  // <ScontoMaggiorazione>
+  TPaf_record paf0900f("PAF0900F");
+  paf0900f.set("P9_KEYHEADERFATT", hfatt);
+  paf0900f.set("P9_KEYBODYFATT",   bfatt);
+  paf0900f.remove();
+  
+  TString80 sconto_expr = doc.get(DOC_SCONTOPERC);
+  TToken_string sconti;
+  if (parse_sconto(sconto_expr, sconti))
+  {
+    long nlin_sconto = 0;
+    FOR_EACH_TOKEN(sconti, str)
+    {
+      const real sconto = str;
+      if (!sconto.is_zero()) // Precauzione inutile
+      {
+        paf0900f.set("P9_RIFNUMLINEA", ++nlin_sconto);
+        if (sconto > ZERO)
+        {
+          paf0900f.set("P9_TIPOSCONTO", "SC");
+          paf0900f.set("P9_PERCSCONTO", sconto);
+        }
+        else
+        {
+          paf0900f.set("P9_TIPOSCONTO", "MG");
+          paf0900f.set("P9_PERCSCONTO", -sconto);
+        }
+        paf0900f.set("P9_GESTIONE", "D");
+        paf0900f.insert();
+      }
+    }
+  }
+  // </ScontoMaggiorazione>
+
+  // <DatiGenerali>
+  TPaf_record paf2700f("PAF2700F");
+  paf2700f.set("PQ_KEYHEADERFATT", hfatt);
+  paf2700f.set("PQ_KEYBODYFATT", bfatt);
+  paf2700f.remove();
+  paf2700f.set("PQ_IMPTOTDOC", doc.totale_doc());
+  paf2700f.set("PQ_CAUSALE",   doc.tipo().descrizione());
+  // paf2700f.set("PQ_ART73",     true);
+  paf2700f.set("PQ_GESTIONE", "D");
+  paf2700f.insert();
+  // </DatiGenerali>
+
+  // Azzera contratti
+  TPaf_record paf1000f("PAF1000F");
+  paf1000f.set("P0_KEYHEADERFATT", hfatt);
+  paf1000f.set("P0_KEYBODYFATT",   bfatt);
+  paf1000f.remove();
+
+  // Azzera convenzioni
+  TPaf_record paf1100f("PAF1100F");
+  paf1100f.set("PA_KEYHEADERFATT", hfatt);
+  paf1100f.set("PA_KEYBODYFATT",   bfatt);
+  paf1100f.remove();
+
+  // Azzera ordini
+  TPaf_record paf1200f("PAF1200F");
+  paf1200f.set("PB_KEYHEADERFATT", hfatt);
+  paf1200f.set("PB_KEYBODYFATT",   bfatt);
+  paf1200f.remove();
+
+  // Azzera DDT
+  TPaf_record paf1600f("PAF1600F");
+  paf1600f.set("PF_KEYHEADERFATT", hfatt);
+  paf1600f.set("PF_KEYBODYFATT",   bfatt);
+  paf1600f.remove();
+
+  const TString16 cup = doc.get(DOC_CUP);
+  const TString16 cig = doc.get(DOC_CIG);
+  const TString80 com = doc.get(DOC_CODCMS);
+  TString80 con = doc.get(DOC_CONTRATTO);
+  if (con.full() || cup.full() || cig.full())
+  {
+    char tcon = doc.get_char(DOC_MODPAG);
+    if (tcon < 'C') tcon = 'C';
+    TDate datadoc;   // Data contratto non obbligatoria
+    if (con.full())
+    {
+      TString80 conkey;
+      conkey.format("%c%06ld%s", tcon, doc.codcf(), (const char*)con);
+      const TRectype& con = cache().get("&CON", conkey);
+      datadoc = con.get_date("D0");
+    }
+    else
+    {
+      // IdDocumento obbligatorio
+      con = cig;
+      if (con.blank())
+        con = cup;
+    }
+
+    if (tcon == 'O')
+    {
+      paf1000f.set("P0_RIFNUMLINEA", 0L);
+      paf1000f.set("P0_IDDOC",       con);
+      paf1000f.set("P0_DATADOC",     datadoc);
+      paf1000f.set("P0_COMMCONVENZ", com);
+      paf1000f.set("P0_CODCUP",      cup);
+      paf1000f.set("P0_CODCIG",      cig);
+      paf1000f.set("P0_GESTIONE",    "D");
+      paf1000f.insert();
+    } else
+    if (tcon == 'C')
+    {
+      paf1100f.set("PA_RIFNUMLINEA", 0L);
+      paf1100f.set("PA_IDDOC",       con);
+      paf1100f.set("PA_DATADOCU",    datadoc);
+      paf1100f.set("PA_COMMCONVENZ", com);
+      paf1100f.set("PA_CODCUP",      cup);
+      paf1100f.set("PA_CODCIG",      cig);
+      paf1000f.set("PA_GESTIONE",    "D");
+      paf1100f.insert();
+    } 
+    else
+    {
+      paf1200f.set("PB_RIFNUMLINEA", 0L);
+      paf1200f.set("PB_IDDOC",       con);
+      paf1200f.set("PB_DATADOCO",    datadoc);
+      paf1200f.set("PB_COMMCONVENZ", com);
+      paf1200f.set("PB_CODCUP",      cup);
+      paf1200f.set("PB_CODCIG",      cig);
+      paf1200f.set("PB_GESTIONE",    "D");
+      paf1200f.insert();
+    }
+  }
+
+  // <DatiBeniServizi>
+
+  TPaf_record paf1800f("PAF1800F");
+  paf1800f.set("PI_KEYHEADERFATT", hfatt);
+  paf1800f.set("PI_KEYBODYFATT", bfatt);
+  paf1800f.remove(); // Cancella tutte le righe documento
+  
+  TPaf_record paf2000f("PAF2000F");
+  paf2000f.set("PJ_KEYHEADERFATT", hfatt);
+  paf2000f.set("PJ_KEYBODYFATT", bfatt);
+  paf2000f.remove(); // Cancella tutti gli sconti di riga
+
+  FOR_EACH_PHYSICAL_RDOC(doc, r, rdoc) 
+  {
+    paf1800f.reset();
+    paf1800f.set("PI_KEYHEADERFATT", hfatt);
+    paf1800f.set("PI_KEYBODYFATT",   bfatt);
+    paf1800f.set("PI_NUMEROLINEA",   (long)r);
+    paf1800f.set("PI_DESCRIZIONE",   descrizione(*rdoc));
+    paf1800f.set("PI_ALIQUOTAIVA", "22.00"); // Altrimenti scarta le righe di descrizione
+    if (rdoc->is_merce())
+    {
+      paf1800f.set("PI_UNITAMISURA", rdoc->get(RDOC_UMQTA));
+      const real qta = rdoc->quantita();
+      if (qta >= ZERO)
+      {
+        paf1800f.set("PI_QUANTITA",    qta);
+        paf1800f.set("PI_PREZZOUNIT",  rdoc->prezzo(false, false));
+      }
+      else
+      {
+        paf1800f.set("PI_QUANTITA",    -qta);
+        paf1800f.set("PI_PREZZOUNIT",  -rdoc->prezzo(false, false));
+      }
+      paf1800f.set("PI_PRZTOTALE",   rdoc->importo(false, false));
+
+      const TRectype& ai = cache().get("%IVA", rdoc->get(RDOC_CODIVA));
+      const real aliquota = ai.get("R0");
+      paf1800f.set("PI_ALIQUOTAIVA", aliquota);
+      if (aliquota.is_zero())
+      {
+        const TString& tipo = ai.get("S1");
+        const char* natura = "N2";             // Non soggetto
+        if (tipo == "NI") natura = "N3"; else  // Non imponibile
+        if (tipo == "ES") natura = "N4";       // Esente
+        paf1800f.set("PI_NATURA", natura);
+      }
+
+      /*
+      const TDate data = doc.get(DOC_DATADOC);
+      paf1800f.set("PI_DTINIZIOPER", data);
+      paf1800f.set("PI_DTFINEPER", data);
+      */
+
+      // <ScontoMaggiorazione>
+      
+      sconto_expr = rdoc->get(RDOC_SCONTO);
+      if (parse_sconto(sconto_expr, sconti))
+      {
+        long nlin_sconto = 0;
+        FOR_EACH_TOKEN(sconti, str)
+        {
+          const real perc = str;
+          if (!perc.is_zero())
+          {
+            paf2000f.set("PJ_KEYNLINEA", (long)r);
+            paf2000f.set("PJ_KEYNPROGR", ++nlin_sconto);
+            if (perc > ZERO)
+            {
+              paf2000f.set("PJ_TIPOSCONTO", "SC");
+              paf2000f.set("PJ_PERCSCONTO", perc);
+            }
+            else
+            {
+              paf2000f.set("PJ_TIPOSCONTO", "MG");
+              paf2000f.set("PJ_PERCSCONTO", -perc);
+            }
+            paf2000f.set("PJ_GESTIONE", "D");
+            paf2000f.insert();
+          }
+        }
+      }
+      // </ScontoMaggiorazione>
+
+      TArray ancestors; find_ancestors(*rdoc, ancestors);
+      for (int i = ancestors.last(); i > 0; i = ancestors.pred(i))
+      {
+        const TAncestor& a = (const TAncestor&)ancestors[i];
+        if (i == 1)
+        {
+          TPaf_record paf1600f("PAF1600F");
+          paf1600f.reset();
+          paf1600f.set("PF_KEYHEADERFATT", hfatt);
+          paf1600f.set("PF_KEYBODYFATT",   bfatt);
+          paf1600f.set("PF_RIFNUMLINEA",   (long)r);
+          paf1600f.set("PF_NUMDDDT",       a._numdoc);
+          paf1600f.set("PF_DATADDT",       a._datadoc);
+          paf1600f.set("PF_GESTIONE",      "D");
+          paf1600f.insert();
+        } else
+        if (i == 3)
+        {
+          TPaf_record paf1000f("PAF1000F");
+          paf1000f.set("P0_KEYHEADERFATT", hfatt);
+          paf1000f.set("P0_KEYBODYFATT",   bfatt);
+          paf1000f.set("P0_RIFNUMLINEA",   (long)r);
+          paf1000f.set("P0_IDDOC",         a._numdoc);
+          paf1000f.set("P0_DATADOC",       a._datadoc);
+          paf1000f.set("P0_COMMCONVENZ",  com);
+          paf1000f.set("P0_CODCUP",        cup);
+          paf1000f.set("P0_CODCIG",        cig);
+          paf1000f.set("P0_GESTIONE",      "D");
+          paf1000f.insert();
+        }
+      }
+    }
+    paf1800f.set("PI_GESTIONE", "D");
+    paf1800f.insert();
+  }
+
+
+  // </DatiBeniServizi>
+
+  // <DatiRiepilogo>
+  TPaf_record paf2200f("PAF2200F");
+  paf2200f.set("PL_KEYHEADERFATT", hfatt);
+  paf2200f.set("PL_KEYBODYFATT",   bfatt);
+  paf2200f.remove(); // Cancella tutte le righe di riepilogo IVA
+
+  long num_riep = 0;
+  TAssoc_array& tiva = doc.tabella_iva(false);
+  FOR_EACH_ASSOC_OBJECT(tiva, obj, key, itm)
+  {
+    const TRiepilogo_iva& riva = *(const TRiepilogo_iva*)itm;
+    const real aliquota = riva.cod_iva().percentuale();
+    paf2200f.set("PL_KEYNPROGR",   ++num_riep);
+    paf2200f.set("PL_ALIQUOTAIVA", aliquota);
+    if (aliquota.is_zero())
+    {
+      const TString& tipo = riva.cod_iva().tipo();
+      const char* natura = "N2";            // Non soggetto
+      if (tipo == "NI") natura = "N3"; else // Non imponibile
+      if (tipo == "ES") natura = "N4";      // Esente
+      paf2200f.set("PL_NATURA", natura);
+    }
+    paf2200f.set("PL_IMPONIBILE", riva.imponibile());
+    paf2200f.set("PL_IMPOSTA",    riva.imposta());
+    // Esigibilit� IVA: immediata o no?
+    const char* eiva = (doc.get_bool(DOC_LIQDIFF) || doc.get_bool(DOC_IVAXCASSA)) ? "D" : "I";
+    paf2200f.set("PL_ESIGIVA",      eiva);
+    paf2200f.set("PL_RIFNORMATIVO", riva.cod_iva().descrizione());
+    paf2200f.set("PL_GESTIONE", "D");
+    paf2200f.insert();
+  }
+  // </DatiRiepilogo>
+
+  // <DatiPagamento>
+  TPaf_record paf2400f("PAF2400F");
+  paf2400f.set("PN_KEYHEADERFATT", hfatt);
+  paf2400f.set("PN_KEYBODYFATT", bfatt);
+  paf2400f.remove(); // Cancella i dati pagamento
+  
+  const TPagamento& pag = doc.pagamento();
+  doc.scadenze_recalc();                 // Ricalcola array delle rate
+  TString_array& scad = doc.scadenze();
+  const int nrate = scad.items();        // Conta rate generate 
+  const char* rateazione = nrate > 1 ? "TP01" : "TP02"; // A rate (TP01) o una soluzione(TP02)?
+  paf2400f.set("PN_CONDPAGAMENTO", rateazione); 
+  paf2400f.set("PN_GESTIONE", "D");
+  paf2400f.insert();
+  
+  TPaf_record paf2500f("PAF2500F");
+  paf2500f.set("PO_KEYHEADERFATT", hfatt);
+  paf2500f.set("PO_KEYBODYFATT", bfatt);
+  paf2500f.remove(); // Cancella tutte le rate
+  
+  // Imposto i campi uguali per tutte le rate
+  paf2500f.set("PO_CONDPAGAMENTO", rateazione); // Condizione di pagamento PA
+  paf2500f.set("PO_CODICEPAGAM",   pag.code()); // Condizione di pagamento CAMPO   
+
+  TString80 iban, istituto; 
+  TString8 abi, cab;
+  if (get_bank(doc, iban, abi, cab, istituto))
+  {
+    paf2500f.set("PO_ISTFINANZ", istituto);
+    paf2500f.set("PO_IBAN",      iban);
+    paf2500f.set("PO_ABI",       abi);
+    paf2500f.set("PO_CAB",       cab);
+  }
+
+  for (int nr = 0; nr < nrate; nr++)
+  {
+    paf2500f.set("PO_KEYNPROGR", long(nr+1));  // Numero rata
+
+    const char* mod_pag = "MP01";              // Modalit� di pagamento
+    const int n = nr < pag.n_rate() ? nr : 0;  // Si assicura che il numero riga sia accettabile
+    switch (pag.tipo_rata(n))
+    {
+    case _bonfico: mod_pag = "MP05"; break;    // bonifico
+    case _rid    : mod_pag = "MP09"; break;    // RID
+    case _ric_ban: mod_pag = "MP12"; break;    // RIBA
+    default      : mod_pag = "MP01"; break;    // contanti
+    }
+    paf2500f.set("PO_MODALITAPAGAM", mod_pag);
+    
+    TToken_string& riga = scad.row(nr);                  // Data|Importo   
+    paf2500f.set("PO_DATASCADENZA", TDate(riga.get(0))); // Data scadenza
+    paf2500f.set("PO_IMPORTO",      real(riga.get()));   // Importo rata 
+    
+    paf2500f.set("PO_GESTIONE", "D");
+    paf2500f.insert();
+  }
+
+  // </DatiPagamento>
+
+  return true;
+}
+
+bool TDoc2Paf::elabora(const TRectype& rec)
+{
+  bool done = false;
+  TDocumentoEsteso doc;
+  if (doc.read(rec) == NOERR)
+  {
+    xvt_sql_begin(_db);
+    done = elabora(doc);
+    if (done)
+      xvt_sql_commit(_db);
+    else
+      xvt_sql_rollback(_db);
+  }
+  return done;
+}
+
+bool TDoc2Paf::elabora(const TDoc_key& key)
+{
+  TRectype rec(LF_DOC);
+  rec.put(DOC_PROVV,  key.provv());
+  rec.put(DOC_ANNO,   key.anno());
+  rec.put(DOC_CODNUM, key.codnum());
+  rec.put(DOC_NDOC,   key.ndoc());
+  return elabora(rec);
+}
+
+bool TDoc2Paf::elabora(const TFilename& ini)
+{
+  TConfig cfg(ini, "33");
+  const int anno  = cfg.get_int(DOC_ANNO);
+  const long ndoc = cfg.get_long(DOC_NDOC);
+  const TFixed_string codnum(cfg.get(DOC_CODNUM)); // lascio sapientemente per ultima la get di una stringa
+  const TDoc_key key(anno, codnum, ndoc);
+  return elabora(key);
+}
+
+
+bool TDoc2Paf::genera_xml()
+{
+  #define PABASE "SiaggPA"
+
+  TFilename tmp; 
+
+  // Copia eventuali protezioni software
+  TString_array files;
+  if (list_files(PABASE"/*.ssa", files) == 0)
+  {
+    list_files("*.ssa", files);
+    FOR_EACH_ARRAY_ROW(files, i, row)
+    {
+      tmp = PABASE; tmp.add(*row);
+      xvt_fsys_fupdate(*row, tmp);
+    }
+  }
+
+  TFilename home; 
+  xvt_sys_get_env("USERPROFILE", home.get_buffer(), home.size());
+  home.add("SoftwareSirio"); home.add(PABASE);
+  if (!dexist(home))
+    make_dir(home);
+
+  tmp = home; tmp.add("config.properties");
+  xvt_fsys_fupdate(PABASE"/config.properties", tmp);
+
+  tmp = home; tmp.add("configGUI.properties");
+  xvt_fsys_fupdate(PABASE"/configGUI.properties", tmp);
+
+  if (tmp.exist())
+  {
+    TJava_profile prop(tmp);
+    prop.set("percorso", _dbname.path());
+    prop.set("nomePAF", _dbname);
+  }
+  else
+    cantread_box(tmp);
+
+  tmp = PABASE"/SiaggPACAMPO.jar";
+  const bool good = xvt_sys_goto_url(tmp, "run") != 0;
+  if (!good)
+    cantread_box(tmp);
+
+  return good;
+}
+
+void TDoc2Paf::main_loop()
+{
+  int ndocs = 0;
+  for (int a = 1; a < argc(); a++)
+  {
+    TFilename ini = argv(a);
+    if (ini.starts_with("-i", true) || ini.starts_with("/i", true))
+      ini.ltrim(2);
+    if (ini.exist() && elabora(ini))
+      ndocs++;
+    else
+    {
+      if (ini.find('*') >= 0 || ini.find('?') >= 0)
+      {
+        TString_array f; list_files(ini, f);
+        FOR_EACH_ARRAY_ROW(f, r, row)
+        {
+          ini = *row;
+          if (ini.exist() && elabora(ini))
+            ndocs++;
+        }
+      }
+    }
+  }
+  if (ndocs > 0)
+  {
+    genera_xml();
+    return;
+  }
+
+  TPA_mask mask;
+  while (mask.run() == K_ENTER)
+  {
+    TString_array& sht = mask.sfield(F_DOCS).rows_array();
+    TProgress_monitor pi(sht.items(), NULL);
+    ndocs = 0;
+    FOR_EACH_ARRAY_ROW(sht, r, riga) 
+    {
+      if (!pi.add_status(1))
+        break;
+      if (riga->starts_with("X"))
+      {
+        const int   anno = riga->get_int(1);
+        const long  ndoc = riga->get_long(3);
+        const TFixed_string codnum(riga->get(2)); // lascio sapientemente per ultima la get di una stringa
+        const TDoc_key key(anno, codnum, ndoc);
+        if (elabora(key))
+          ndocs++;
+      }
+    }
+    message_box(FR("Sono stati elaborati %d documenti"), ndocs);
+    if (ndocs > 0)
+      genera_xml();
+  }
+}
+
+int TDoc2Paf::parse_line(const TString& line, TString& var, TString& val) const
+{
+  if (line.blank())
+    return 0;
+
+  if (line[0] == '[')
+  {
+    var = line.mid(1);
+    var.rtrim(1);
+    val.cut(0);
+    return 1;
+  }
+
+  const int equal = line.find('=');
+  if (equal < 6)
+    return 0;
+  var = line.left(equal); var.trim();
+  val = line.mid(equal+1);  val.trim();
+  return 2;
+}
+
+bool TDoc2Paf::create_table(TScanner& paf, const TString& table)
+{
+  TString query, var, val;
+  if (xvt_sql_table_exists(_db, table))
+  {
+    SLIST fields = xvt_sql_list_fields(_db, table);
+    while (!paf.eof())
+    {
+      const TString& line = paf.line();
+      const int n = parse_line(line, var, val);
+      if (n <= 0)
+        break;
+      if (var.starts_with("INDEX_"))
+        break;
+      if (xvt_slist_find_str(fields, var) == NULL)
+      {
+        query.cut(0) << "ALTER TABLE " << table << " ADD COLUMN " << var << ' ' << val << " NOT NULL"; 
+        if (val.find("INT") >= 0 || val.find("NUM") >= 0)
+          query << " DEFAULT 0"; 
+        else
+          query << " DEFAULT ''";
+        query << ";";
+        xvt_sql_execute(_db, query, NULL, NULL); // Create table
+      }
+    }
+    xvt_slist_destroy(fields);
+  }
+  else
+  {
+    query << "CREATE TABLE " << table << " (";
+    while (!paf.eof())
+    {
+      const TString& line = paf.line();
+      const int n = parse_line(line, var, val);
+      if (n <= 0)
+        break;
+      if (n == 1)
+      {
+        paf.push(line);
+        break;
+      }
+      if (var.starts_with("INDEX_"))
+      {
+        query.rtrim(1); // toglie ultima ,
+        query << ");";
+        xvt_sql_execute(_db, query, NULL, NULL); // Create table
+        query.cut(0);
+        query << "CREATE UNIQUE INDEX "
+              << table << "_1 ON " << table 
+              << " (" << val << ");";
+        xvt_sql_execute(_db, query, NULL, NULL); // Create index
+        break;
+      }
+      else
+      {
+        query << "\n " << var << ' ' << val << " NOT NULL";
+        if (val.find("INT") >= 0 || val.find("NUM") >= 0)
+          query << " DEFAULT 0";
+        else
+          query << " DEFAULT ''";
+        query << ",";
+      }
+    }
+  }
+
+  return true;
+}
+
+bool TDoc2Paf::create()
+{
+  open_files(LF_TAB,   LF_TABCOM, LF_TABMOD, LF_ANAG, 
+             LF_CLIFO, LF_CFVEN,  LF_NDITTE, 
+             LF_DOC, LF_RIGHEDOC, 0);
+
+  TRectype cfven(LF_CFVEN);
+  if (cfven.type(CFV_PARIFAMM) != _alfafld)
+    return error_box(TR("Database non convertito per fatturazione P.A."));
+
+  _ditta.init(LF_NDITTE, prefix().get_codditta());
+
+  _dbname = prefix().get_studio();  // base direcotry
+  _dbname.add("sql"); make_dir(_dbname);
+  TString16 d; d.format("PAF%05ld.db", prefix().get_codditta());
+  _dbname.add(d);
+  _db = xvt_sql_open(_dbname, user(), "", _dbname.path());
+  if (_db == NULL)
+    return false;
+
+  const TFilename ini = "paf.ini";
+  bool ok = ini.exist();
+  if (ok)
+  {
+    xvt_sql_begin(_db);
+    TScanner paf(ini);
+    while (ok && !paf.eof())
+    {
+      const TString& p = paf.line();
+      if (p.starts_with("[PA") && p.ends_with("F]"))
+      {
+        TString16 table = p; table.strip("[]");
+        ok = create_table(paf, table);
+      }
+    }
+
+    if (ok)
+    {
+      TPaf_record panum("PANUM00F");
+      panum.set("PJNKEY", "00001");
+      if (!panum.search())
+      {
+        panum.set("PJNINV", "0000000000");
+        panum.insert();
+      }
+
+      xvt_sql_commit(_db);
+    }
+    else
+      xvt_sql_rollback(_db);
+  }
+  else
+    return cantread_box(ini);
+
+  return ok && TSkeleton_application::create();
+}
+
+bool TDoc2Paf::destroy()
+{
+  xvt_sql_close(_db); _db = NULL;
+  return TSkeleton_application::destroy();
+}
+
+int pa0100(int argc, char* argv[])
+{
+  TDoc2Paf d2p;
+  d2p.run(argc, argv, TR("Fatturazione P.A."));
+  return 0;
+}
diff --git a/pa/pa0100a.h b/pa/pa0100a.h
index 6ce9dcc48..6643e4a55 100644
--- a/pa/pa0100a.h
+++ b/pa/pa0100a.h
@@ -11,4 +11,5 @@
 #define S_RAGSOC   107
 #define S_UFFICIO  108
 #define S_RIFAMM   109
+#define S_COFI     110
 
diff --git a/pa/pa0100a.uml b/pa/pa0100a.uml
index 9ab6cf280..cbd9f77b0 100644
--- a/pa/pa0100a.uml
+++ b/pa/pa0100a.uml
@@ -26,9 +26,10 @@ BEGIN
   ITEM "Num.\nDoc.@7"
   ITEM "Data\nDoc.@10"
   ITEM "Cliente"
-  ITEM "Ragione Sociale@50"
+  ITEM "Ragione Sociale\nPubblica Amministrazione@50"
   ITEM "Ufficio"
   ITEM "Riferimento\nAmministrazione@20"
+  ITEM "Codice Fiscale@16"
 END
 
 ENDPAGE
@@ -90,6 +91,34 @@ BEGIN
   FLAGS "D"
 END
 
+STRING S_COFI 20
+BEGIN
+  PROMPT 1 5 ""
+  FLAGS "D"
+END
+
+ENDPAGE
+
+TOOLBAR "Documento" 0 0 0 2
+
+BUTTON DLG_OK 2 2 
+BEGIN
+  PROMPT 1 1 ""
+END
+
+BUTTON DLG_USER 2 2 
+BEGIN
+  PROMPT 1 1 "Collega"
+  PICTURE TOOL_LINK
+END
+
+
+BUTTON DLG_CANCEL 2 2 
+BEGIN
+  PROMPT 1 1 ""
+END
+
+
 ENDPAGE
 
 ENDMASK
diff --git a/pa/pa0200.cpp b/pa/pa0200.cpp
new file mode 100644
index 000000000..f3fd7d3e3
--- /dev/null
+++ b/pa/pa0200.cpp
@@ -0,0 +1,20 @@
+// gestione tabelle di modulo PA
+
+#include <modtbapp.h>
+
+///////////////////////////////////////////////////////////
+// Applicazione generica di gestione tabelle di modulo
+///////////////////////////////////////////////////////////
+
+// applicazione per la gestione delle tabelle di lavanderia
+class TPA_table_app : public TTable_module_application
+{
+public:
+};
+
+int pa0200(int argc, char* argv[])
+{
+  TPA_table_app a;
+  a.run(argc, argv, TR("Tabella Fatture PA"));
+  return 0;
+}
diff --git a/pa/paf.ini b/pa/paf.ini
index a138f89b5..d879bb247 100644
--- a/pa/paf.ini
+++ b/pa/paf.ini
@@ -1,172 +1,513 @@
 [PAF0100F]
-P1KHFATT = VARCHAR(20)
-P1KBFATT = VARCHAR(20)
-P1PAESE  = VARCHAR(2)
-P1CODICE = VARCHAR(28) 
-P1PRGINV = VARCHAR(10)
-P1FTRASM = VARCHAR(5)
-P1CDEST  = VARCHAR(6)
-P1TELEF  = VARCHAR(12)
-P1MAIL   = VARCHAR(256)
-P1GESTIONE = VARCHAR(1)
-P1ERRORE   = VARCHAR(5)
+P1_KEYHEADERFATT = CHAR(20)
+P1_KEYBODYFATT   = CHAR(20)
+P1_TRASMITTPAESE = CHAR(2)
+P1_TRASMITTCOD   = CHAR(28) 
+P1_PRGINVIO      = CHAR(10)
+P1_FMTTRASMISS   = CHAR(5)
+P1_CODDEST       = CHAR(6)
+P1_TELEFONO      = CHAR(12)
+P1_MAIL          = CHAR(256)
 
-INDEX_1  = P1KHFATT,P1KBFATT
+P1_GESTIONE      = CHAR(1)
+P1_ERRINT        = CHAR(1)
+P1_ERREST        = CHAR(1)
+
+INDEX_1 = P1_KEYHEADERFATT,P1_KEYBODYFATT
 
 [PAF0200F]
-P2KHFATT = VARCHAR(20)
-P2KBFATT = VARCHAR(20)
-P2PAESE  = VARCHAR(2)
-P2CODICE = VARCHAR(28)
-P2FISCA  = VARCHAR(16)
-P2DENOM  = VARCHAR(80)
-P2NOME   = VARCHAR(60)
-P2COGN   = VARCHAR(60)
-P2RFISC  = VARCHAR(4)
+P2_KEYHEADERFATT = CHAR(20)
+P2_KEYBODYFATT   = CHAR(20)
 
-P2SINDI  = VARCHAR(60)
-P2SNCIV  = VARCHAR(8)
-P2SCAP   = VARCHAR(5)
-P2SCOMU  = VARCHAR(60)
-P2SPROV  = VARCHAR(2)
-P2SNAZI  = VARCHAR(2)
+P2_FISCIVAPAESE    = CHAR(2)
+P2_FISCIVACOD      = CHAR(28)
+P2_CODFISCALE      = CHAR(16)
+P2_ANADENOMIN      = CHAR(80)
+P2_ANANOME         = CHAR(60)
+P2_ANACOGNOME      = CHAR(60)
+P2_ANATITOLO       = CHAR(10)
+P2_ANACODEORI      = CHAR(17)
+P2_ALBOPROFESS     = CHAR(60)
+P2_PROVALBO        = CHAR(2)
+P2_NRISCRIZALBO    = CHAR(60)
+P2_DTISCRIZEALBO   = DATE
+P2_REGFISCALE      = CHAR(4)
+P2_SEDEIND         = CHAR(60)
+P2_SEDENRCIVICO    = CHAR(8)
+P2_SEDECAP         = NUMERIC(5, 0)
+P2_SEDECOMUNE      = CHAR(60)
+P2_SEDEPROV        = CHAR(2)
+P2_SEDENAZ         = CHAR(2)
+P2_STABORGIND      = CHAR(60)
+P2_STABORGNRCIVICO = CHAR(8)
+P2_STABORGCAP      = NUMERIC(5, 0)
+P2_STABORGCOMUNE   = CHAR(60)
+P2_STABORGPROV     = CHAR(2)
+P2_STABORGNAZ      = CHAR(2)
+P2_ISCRREAUFF      = CHAR(2)
+P2_ISCRREANUM      = CHAR(20)
+P2_ISCRREACAP      = VARNUMERIC(15, 2)
+P2_ISCRREASOCIOU   = CHAR(2)
+P2_ISCRREASLIQUID  = CHAR(2)
+P2_CONTATTITELEF   = CHAR(12)
+P2_CONTATTIFAX     = CHAR(12)
+P2_CONTATTIMAIL    = CHAR(256)
+P2_RIFAMMINISTR    = CHAR(20)
 
-P2OINDI  = VARCHAR(60)
-P2ONCIV  = VARCHAR(8)
-P2OCAP   = VARCHAR(5)
-P2OCOMU  = VARCHAR(60)
-P2OPROV  = VARCHAR(2)
-P2ONAZI  = VARCHAR(2)
+P2_GESTIONE = CHAR(1)
+P2_ERRINT   = CHAR(1)
+P2_ERREST   = CHAR(1)
 
-P2GESTIONE = VARCHAR(1)
-P2ERRORE   = VARCHAR(5)
+INDEX_1 = P2_KEYHEADERFATT,P2_KEYBODYFATT
 
-INDEX_1  = P2KHFATT,P2KBFATT
+[PAF0300F]
+P3_KEYHEADERFATT = CHAR(20)
+P3_KEYBODYFATT   = CHAR(20)
+
+P3_FISCIVAPAESE  = CHAR(2) 
+P3_FISCIVACODICE = CHAR(28)
+P3_CODFISC       = CHAR(16)
+P3_ANADENOMI     = CHAR(80)
+P3_ANANOME       = CHAR(60)
+P3_ANACOGNOME    = CHAR(60)
+P3_ANATITOLO     = CHAR(10)
+P3_ANACODEORI    = CHAR(17)
+	
+P3_GESTIONE = CHAR(1)
+P3_ERRINT   = CHAR(1)
+P3_ERREST   = CHAR(1)
+
+INDEX_1 = P3_KEYHEADERFATT,P3_KEYBODYFATT
 
 [PAF0400F]
-P4KHFATT = VARCHAR(20)
-P4KBFATT = VARCHAR(20)
-P4PAESE  = VARCHAR(2)
-P4CODICE = VARCHAR(28)
-P4FISCA  = VARCHAR(16)
-P4DENOM  = VARCHAR(80)
-P4NOME   = VARCHAR(60)
-P4COGN   = VARCHAR(60)
-P4RFISC  = VARCHAR(4)
+P4_KEYHEADERFATT = CHAR(20)
+P4_KEYBODYFATT   = CHAR(20)
+P4_FISCIVAPAESE  = CHAR(2)
+P4_FISCIVACOD    = CHAR(28)
+P4_CODFISC       = CHAR(16)
+P4_ANADENOM      = CHAR(80)
+P4_ANANOME       = CHAR(60)
+P4_ANACOGNOME    = CHAR(60)
+P4_ANATITOLO     = CHAR(10)
+P4_ANACODEORI    = CHAR(17) 
 
-P4SINDI  = VARCHAR(60)
-P4SNCIV  = VARCHAR(8)
-P4SCAP   = VARCHAR(5)
-P4SCOMU  = VARCHAR(60)
-P4SPROV  = VARCHAR(2)
-P4SNAZI  = VARCHAR(2)
+P4_SEDEIND      = CHAR(60)
+P4_SEDENRCIVICO = CHAR(8)
+P4_SEDECAP      = CHAR(5)
+P4_SEDECOMUNE   = CHAR(60)
+P4_SEDEPROV     = CHAR(2)
+P4_SEDENAZ      = CHAR(2)
 
-P4GESTIONE = VARCHAR(1)
-P4ERRORE   = VARCHAR(5)
+P4_GESTIONE = CHAR(1)
+P4_ERRINT   = CHAR(1)
+P4_ERREST   = CHAR(1)
 
-INDEX_1  = P4KHFATT,P4KBFATT
+INDEX_1 = P4_KEYHEADERFATT,P4_KEYBODYFATT
+
+[PAF0500F]
+P5_KEYHEADERFATT = CHAR(20)
+P5_KEYBODYFATT   = CHAR(20)
+P5_FISCIVAPAESE  = CHAR(2)
+P5_FISCIVACOD    = CHAR(28)
+P5_CODICEFISC    = CHAR(16)
+P5_ANADENOMIN    = CHAR(80)
+P5_ANANOME       = CHAR(60)
+P5_ANACOGNOME    = CHAR(60)
+P5_ANATITOLO     = CHAR(10)
+P5_ANACODEORI    = CHAR(17) 
+
+P5_GESTIONE = CHAR(1)
+
+INDEX_1 = P5_KEYHEADERFATT,P5_KEYBODYFATT
+
+[PAF0600F]
+P6_KEYHEADERFATT = CHAR(20)
+P6_KEYBODYFATT   = CHAR(20)
+P6_SOGGEMITT     = CHAR(2)
+
+P6_GESTIONE = CHAR(1)
+
+INDEX_1 = P6_KEYHEADERFATT,P6_KEYBODYFATT
 
 [PAF0700F]
-P7KHFATT = VARCHAR(20)
-P7KBFATT = VARCHAR(20)
-P7TDOC   = VARCHAR(4)
-P7DIVISA = VARCHAR(3)
-P7DATA   = VARCHAR(10)
-P7NUME   = VARCHAR(20)
+P7_KEYHEADERFATT = CHAR(20)
+P7_KEYBODYFATT   = CHAR(20)
+P7_TIPODOC       = CHAR(4)
+P7_DIVISA        = CHAR(3)
+P7_DATA          = DATE
+P7_NUMERO        = CHAR(20)
 
-P7GESTIONE = VARCHAR(1)
-P7ERRORE   = VARCHAR(5)
+P7_TIPORITENUTA  = CHAR(4)
+P7_IMPORTORIT    = NUMERIC(15, 2)
+P7_ALIQUOTARIT   = NUMERIC(6, 2)
+P7_CAUSPAGAM     = CHAR(1)
+P7_NUMEROBOLLO   = CHAR(14)
+P7_IMPORTOBOLLO  = NUMERIC(15, 2)
 
-INDEX_1  = P7KHFATT,P7KBFATT
+P7_GESTIONE = CHAR(1)
+P7_ERRINT   = CHAR(1)
+P7_ERREST   = CHAR(1)
+
+INDEX_1  = P7_KEYHEADERFATT,P7_KEYBODYFATT
+
+[PAF0800F]
+P8_KEYHEADERFATT = CHAR(20)
+P8_KEYBODYFATT   = CHAR(20)
+P8_RIFNUMLINEA   = INTEGER
+
+P8_TIPOCASSA     = CHAR(4)
+P8_ALIQCASSA     = NUMERIC(6, 2)
+P8_IMCONTRCASSA  = NUMERIC(15, 2)
+P8_IMPONCASSA    = NUMERIC(15, 2)
+P8_ALIQIVA       = NUMERIC(6, 2)
+P8_RITENUTA      = CHAR(2) 
+P8_NATURA        = CHAR(2) 
+P8_RIFAMMINIS    = CHAR(20)
+
+P8_GESTIONE = CHAR(1)
+P8_ERRINT   = CHAR(1)
+P8_ERREST   = CHAR(1)
+
+INDEX_1  = P8_KEYHEADERFATT,P8_KEYBODYFATT,P8_RIFNUMLINEA
 
 [PAF0900F]
-P9KHFATT = VARCHAR(20)
-P9KBFATT = VARCHAR(20)
-P9NLIN   = INTEGER
-P9TSCO   = VARCHAR(2)
-P9PSCO   = NUMERIC
-P9ISCO   = NUMERIC
+P9_KEYHEADERFATT = CHAR(20)
+P9_KEYBODYFATT   = CHAR(20)
+P9_RIFNUMLINEA   = INTEGER
 
-P9GESTIONE = VARCHAR(1)
+P9_NPROGR        = INTEGER
+P9_TIPOSCONTO    = CHAR(2)
+P9_PERCSCONTO    = NUMERIC(6,2)
+P9_IMPSCONTO     = NUMERIC(15,2)
 
-INDEX_1  = P9KHFATT,P9KBFATT,P9NLIN
+P9_GESTIONE = CHAR(1)
 
+INDEX_1  = P9_KEYHEADERFATT,P9_KEYBODYFATT,P9_RIFNUMLINEA
+
+[PAF1000F]
+P0_KEYHEADERFATT = CHAR(20)
+P0_KEYBODYFATT   = CHAR(20)
+P0_RIFNUMLINEA   = INTEGER
+P0_IDDOC         = CHAR(20)
+P0_DATADOC       = DATE
+P0_NUMITEM       = INTEGER
+P0_COMMCONVENZ   = CHAR(100)
+P0_CODCUP        = CHAR(15)
+P0_CODCIG        = CHAR(15)
+
+P0_GESTIONE = CHAR(1)
+
+INDEX_1  = P0_KEYHEADERFATT,P0_KEYBODYFATT,P0_RIFNUMLINEA
+
+[PAF1100F]
+PA_KEYHEADERFATT = CHAR(20)
+PA_KEYBODYFATT   = CHAR(20)
+PA_RIFNUMLINEA   = INTEGER
+PA_IDDOC         = CHAR(20)
+PA_DATADOCU      = DATE
+PA_NUMITEM       = INTEGER
+PA_COMMCONVENZ   = CHAR(100)
+PA_CODCUP        = CHAR(15)
+PA_CODCIG        = CHAR(15)
+
+PA_GESTIONE = CHAR(1)
+
+INDEX_1  = PA_KEYHEADERFATT,PA_KEYBODYFATT,PA_RIFNUMLINEA
+
+[PAF1200F]
+PB_KEYHEADERFATT = CHAR(20)
+PB_KEYBODYFATT   = CHAR(20)
+PB_RIFNUMLINEA   = INTEGER
+PB_IDDOC         = CHAR(20)
+PB_DATADOCO      = DATE
+PB_NUMITEM       = INTEGER
+PB_COMMCONVENZ  = CHAR(100)
+PB_CODCUP        = CHAR(15)
+PB_CODCIG        = CHAR(15)
+
+PB_GESTIONE = CHAR(1)
+
+INDEX_1  = PB_KEYHEADERFATT,PB_KEYBODYFATT,PB_RIFNUMLINEA
+
+[PAF1300F]
+PC_KEYHEADERFATT = CHAR(20)
+PC_KEYBODYFATT   = CHAR(20)
+PC_RIFNUMLINEA   = INTEGER
+PC_IDDOC         = CHAR(20)
+PC_DATADOC       = DATE
+PC_NUMITEM       = INTEGER
+PC_COMMCONVENZ   = CHAR(100)
+PC_CODCUP        = CHAR(15)
+PC_CODCIG        = CHAR(15)
+
+PC_GESTIONE = CHAR(1)
+
+INDEX_1  = PC_KEYHEADERFATT,PC_KEYBODYFATT
+
+[PAF1400F]
+PD_KEYHEADERFATT = CHAR(20)
+PD_KEYBODYFATT   = CHAR(20)
+PD_RIFNUMLINEA   = INTEGER
+PD_IDDOC         = CHAR(20)
+PD_DATADOC       = DATE
+PD_NUMITEM       = INTEGER
+PD_COMMCONVENZ   = CHAR(100)
+PD_CODCUP        = CHAR(15)
+PD_CODCIG        = CHAR(15)
+
+PD_GESTIONE = CHAR(1)
+
+INDEX_1  = PD_KEYHEADERFATT,PD_KEYBODYFATT
+
+[PAF1500F]
+PE_KEYHEADERFATT = CHAR(20)
+PE_KEYBODYFATT   = CHAR(20)
+PE_RIFFASE       = NUMERIC(3, 0)
+
+PE_GESTIONE = CHAR(1)
+
+INDEX_1  = PE_KEYHEADERFATT,PE_KEYBODYFATT
+
+[PAF1600F]
+PF_KEYHEADERFATT = CHAR(20)
+PF_KEYBODYFATT   = CHAR(20)
+
+PF_NUMDDDT       = CHAR(20)
+PF_DATADDT       = DATE
+PF_RIFNUMLINEA   = NUMERIC(4, 0)
+
+PF_GESTIONE = CHAR(1)
+PF_ERRINT   = CHAR(1)
+PF_ERREST   = CHAR(1)
+
+INDEX_1  = PF_KEYHEADERFATT,PF_KEYBODYFATT,PF_NUMDDDT,PF_RIFNUMLINEA
+
+[PAF1700F]
+PG_KEYHEADERFATT = CHAR(20)
+PG_KEYBODYFATT   = CHAR(20)
+PG_FISCIVAPAESE  = CHAR(2) 
+PG_FISCIVACODICE = CHAR(28)
+PG_CODICEFISCALE = CHAR(16)
+PG_ANADENOMINAZ  = CHAR(80)
+PG_ANANOME       = CHAR(60)
+PG_ANACOGNOME    = CHAR(60)
+PG_ANATITOLO     = CHAR(10)
+PG_ANACODEORI    = CHAR(17)
+PG_NUMLICGUIDA   = CHAR(20)
+
+PG_GESTIONE = CHAR(1)
+
+INDEX_1  = PG_KEYHEADERFATT,PG_KEYBODYFATT
 
 [PAF1800F]
-PIKHFATT = VARCHAR(20)
-PIKBFATT = VARCHAR(20)
-PINLIN   = INTEGER
-PITCPRES = VARCHAR(2)
-PIDESC   = VARCHAR(100)
-PIQTA    = NUMERIC
-PIUNMIS  = VARCHAR(10)
-PIPREZ   = NUMERIC
-PIPRZT   = NUMERIC
-PIAIVA   = NUMERIC 
+PI_KEYHEADERFATT = CHAR(20)
+PI_KEYBODYFATT   = CHAR(20)
+PI_NUMEROLINEA   = INTEGER
+PI_TIPOCESSPREST = CHAR(2)
+PI_DESCRIZIONE   = CHAR(100)
+PI_QUANTITA      = NUMERIC
+PI_UNITAMISURA   = CHAR(10)
+PI_DTINIZIOPER   = DATE
+PI_DTFINEPER     = DATE
+PI_PREZZOUNIT    = NUMERIC
+PI_PRZTOTALE     = NUMERIC
+PI_ALIQUOTAIVA   = NUMERIC 
+PI_RITENUTA      = CHAR(2)
+PI_NATURA        = CHAR(2)
+PI_RIFAMMINISTR  = CHAR(20)
 
-PIGESTIONE = VARCHAR(1)
-PIERRORE   = VARCHAR(5)
+PI_GESTIONE = CHAR(1)
+PI_ERRINT   = CHAR(1)
+PI_ERREST   = CHAR(1)
 
-INDEX_1  = PIKHFATT,PIKBFATT,PINLIN
+INDEX_1  = PI_KEYHEADERFATT,PI_KEYBODYFATT,PI_NUMEROLINEA
+
+[PAF1900F]
+PY_KEYHEADERFATT  = CHAR(20)
+PY_KEYBODYFATT    = CHAR(20)
+PY_KEYNLINEA      = INTEGER
+
+PY_TIPOARTICOLO   = CHAR(35)
+PY_VALOREARTICOLO = CHAR(35)
+
+PY_GESTIONE = CHAR(1)
+
+INDEX_1 = PY_KEYHEADERFATT,PY_KEYBODYFATT,PY_KEYNLINEA
 
 [PAF2000F]
-PJKHFATT = VARCHAR(20)
-PJKBFATT = VARCHAR(20)
-PJKNLIN  = INTEGER
-PJTSCO   = VARCHAR(2)
-PJPSCO   = NUMERIC
-PJISCO   = NUMERIC
+PJ_KEYHEADERFATT = CHAR(20)
+PJ_KEYBODYFATT   = CHAR(20)
+PJ_KEYNLINEA     = INTEGER
+PJ_KEYNPROGR     = INTEGER
 
-PJGESTIONE = VARCHAR(1)
+PJ_TIPOSCONTO    = CHAR(2)
+PJ_PERCSCONTO    = NUMERIC(6,2)
+PJ_IMPORTOSCONTO = NUMERIC(15,2)
 
-INDEX_1  = PJKHFATT,PJKBFATT,PJKNLIN
+PJ_GESTIONE = CHAR(1)
+
+INDEX_1 = PJ_KEYHEADERFATT,PJ_KEYBODYFATT,PJ_KEYNLINEA,PJ_KEYNPROGR
+
+[PAF2100F]
+PK_KEYHEADERFATT = CHAR(20)
+PK_KEYBODYFATT   = CHAR(20)
+PK_KEYNLINEA     = INTEGER
+
+PK_TIPODATO  = CHAR(10)
+PK_RIFDATO   = CHAR(60)
+PK_RIFNUMERO = NUMERIC(21, 5)
+PK_RIFDATA   = DATE
+PK_GESTIONE  = CHAR(1)
+
+INDEX_1 = PK_KEYHEADERFATT,PK_KEYBODYFATT,PK_KEYNLINEA
 
 [PAF2200F]
-PLKHFATT = VARCHAR(20)
-PLKBFATT = VARCHAR(20)
-PLALIVA  = NUMERIC
-PLNATU   = VARCHAR(2)
-PLIMPO   = NUMERIC
-PLIMPS   = NUMERIC
-PLEIVA   = VARCHAR(1)
+PL_KEYHEADERFATT = CHAR(20)
+PL_KEYBODYFATT   = CHAR(20)
+PL_KEYNPROGR     = INTEGER
 
-PLGESTIONE = VARCHAR(1)
-PLERRORE   = VARCHAR(5)
+PL_ALIQUOTAIVA   = NUMERIC(6,2)
+PL_NATURA        = CHAR(2)
+PL_SPESEACCESS   = NUMERIC(15,2)
+PL_ARROTONDAM    = NUMERIC(15,2)
+PL_IMPONIBILE    = NUMERIC(15,2)
+PL_IMPOSTA       = NUMERIC(15,2)
+PL_ESIGIVA       = CHAR(1)
+PL_RIFNORMATIVO  = CHAR(100)
 
-INDEX_1  = PLKHFATT,PLKBFATT,PLALIVA,PLNATU
+PL_GESTIONE = CHAR(1)
+PL_ERRINT   = CHAR(1)
+PL_ERREST   = CHAR(1)
+
+INDEX_1  = PL_KEYHEADERFATT,PL_KEYBODYFATT,PL_KEYNPROGR
+
+[PAF2300F]
+PM_KEYHEADERFATT = CHAR(20)
+PM_KEYBODYFATT   = CHAR(20)
+
+PM_DATA           = DATE
+PM_TOTALEPERCORSO = CHAR(15)
+
+PM_GESTIONE = CHAR(1)
+PM_ERRINT   = CHAR(1)
+PM_ERREST   = CHAR(1)
+
+INDEX_1  = PM_KEYHEADERFATT,PM_KEYBODYFATT
 
 [PAF2400F]
-PNKHFATT = VARCHAR(20)
-PNKBFATT = VARCHAR(20)
-PNCPAG   = VARCHAR(4)
+PN_KEYHEADERFATT = CHAR(20)
+PN_KEYBODYFATT   = CHAR(20)
 
-PNGESTIONE = VARCHAR(1)
-PNERRORE   = VARCHAR(5)
+PN_CONDPAGAMENTO = CHAR(4)
 
-INDEX_1  = PNKHFATT,PNKBFATT
+PN_GESTIONE = CHAR(1)
+PN_ERRINT   = CHAR(1)
+PN_ERREST   = CHAR(1)
+
+INDEX_1  = PN_KEYHEADERFATT,PN_KEYBODYFATT
 
 [PAF2500F]
-POKHFATT = VARCHAR(20)
-POKBFATT = VARCHAR(20)
-POKNLIN  = INTEGER
-POMPAGAM = VARCHAR(4)
-POUSCAD  = VARCHAR(10)
-POIMPO   = NUMERIC
-POCPAG   = VARCHAR(15)
+PO_KEYHEADERFATT = CHAR(20)
+PO_KEYBODYFATT   = CHAR(20)
+PO_KEYNPROGR     = INTEGER
 
-POGESTIONE = VARCHAR(1)
-POERRORE   = VARCHAR(5)
+PO_CONDPAGAMENTO = CHAR(4)
+PO_BENEFICIARIO  = CHAR(200)
+PO_MODALITAPAGAM = CHAR(4)
+PO_DATARIFTERM   = DATE
+PO_GGTERMINIPAG  = INTEGER
+PO_DATASCADENZA  = DATE
+PO_IMPORTO       = NUMERIC(15, 2)
+PO_CODUFFPOST    = CHAR(20)
+PO_COGNOMEQUIET  = CHAR(60)
+PO_NOMEQUIET     = CHAR(60)
+PO_CFQUIETANZA   = CHAR(16)
+PO_TITOLOQUIET   = CHAR(10)
+PO_ISTFINANZ     = CHAR(80)
+PO_IBAN          = CHAR(34)
+PO_ABI           = NUMERIC(5, 0)
+PO_CAB           = NUMERIC(5, 0)
+PO_BIC           = CHAR(11)
+PO_SCPAGANTIC    = NUMERIC(15, 2)
+PO_DTLIMANTIC    = DATE
+PO_PENALITAPAGAM = NUMERIC(15, 2)
+PO_DATADECORRP   = DATE
+PO_CODICEPAGAM   = CHAR(15)
 
-INDEX_1  = POKHFATT,POKBFATT,POKNLIN
+PO_GESTIONE = CHAR(1)
+PO_ERRINT   = CHAR(1)
+PO_ERREST   = CHAR(1)
+
+INDEX_1  = PO_KEYHEADERFATT,PO_KEYBODYFATT,PO_KEYNPROGR
+
+[PAF2600F]
+
+PP_KEYHEADERFATT = CHAR(20)
+PP_KEYBODYFATT   = CHAR(20)
+
+PP_NOMEATTACHMENT = CHAR(60)
+PP_COMPRESSIONE   = CHAR(10)
+PP_FMTATTACHMENT  = CHAR(10)
+PP_DESCATTACHMENT = CHAR(10)
+PP_ATTACHMENT     = CHAR(256)
+
+PP_GESTIONE = CHAR(1)
+
+INDEX_1  = PP_KEYHEADERFATT,PP_KEYBODYFATT
 
 [PAF2700F]
-PQKHFATT = VARCHAR(20)
-PQKBFATT = VARCHAR(20)
-PQITDOC  = NUMERIC
-PQARRO   = NUMERIC
-PQCAUS   = VARCHAR(200)
-PQART73  = VARCHAR(2)
+PQ_KEYHEADERFATT = CHAR(20)
+PQ_KEYBODYFATT   = CHAR(20)
+PQ_IMPTOTDOC     = NUMERIC(15,2)
+PQ_ARROTOND      = NUMERIC(15,2)
+PQ_CAUSALE       = CHAR(200)
+PQ_ART73         = CHAR(2)
 
-PQGESTIONE = VARCHAR(1)
+PQ_GESTIONE = CHAR(1)
 
-INDEX_1  = PQKHFATT,PQKBFATT
\ No newline at end of file
+INDEX_1  = PQ_KEYHEADERFATT,PQ_KEYBODYFATT
+
+[PAF2800F]
+PR_KEYHEADERFATT = CHAR(20)
+PR_KEYBODYFATT   = CHAR(20)
+
+PR_MEZZOTRASP    = CHAR(80)
+PR_CAUSALETRASP  = CHAR(100)
+PR_NUMCOLLI      = INTEGER
+PR_DESCRIZIONE   = CHAR(100)
+PR_UMPESO        = CHAR(10)
+PR_PESOLORDO     = NUMERIC(7, 2)
+PR_PESONETTO     = NUMERIC(7, 2)
+PR_DATAORARIT    = TIMESTAMP
+PR_DATAUNIZIO    = DATE
+PR_TIPORESA      = CHAR(3)
+PR_INDIRIZZORESA = CHAR(60)
+PR_NRCIVICORESA  = CHAR(8)
+PR_CAPRESA       = NUMERIC(5, 0)
+PR_COMUNERESA    = CHAR(60)
+PR_PROVINCIARESA = CHAR(2)
+PR_NAZIONERESA   = CHAR(2) 
+PR_DATAORACON    = TIMESTAMP
+PR_GESTIONE      = CHAR(1)
+
+INDEX_1 = PR_KEYHEADERFATT,PR_KEYBODYFATT
+
+[PAF2900F]
+PS_KEYHEADERFATT = CHAR(20)
+PS_KEYBODYFATT   = CHAR(20)
+
+PS_NORMARIFER    = CHAR(100)
+PS_NUMFATTPRINC  = CHAR(20)
+PS_DATAFATTPRINC = DATE
+
+PS_GESTIONE = CHAR(1)
+
+INDEX_1  = PS_KEYHEADERFATT,PS_KEYBODYFATT
+
+[PANUM00F]
+PJNKEY = CHAR(5)
+PJNINV = CHAR(10)
+PJCPER = CHAR(256)
+PJFILL = CHAR(256)
+
+INDEX_1 = PJNKEY
diff --git a/pa/pamenu.men b/pa/pamenu.men
index 6fdf3c10e..bd127cee2 100644
--- a/pa/pamenu.men
+++ b/pa/pamenu.men
@@ -4,4 +4,5 @@ Picture = <ve01>
 Module  = pa
 Flags   = "F"
 Item_01 = "Fatture P.A.", "pa0 -0", "F"
-Item_02 = "Firma Digitale", fd0 -0, "F"
+Item_02 = "Firma Digitale", "fd0 -0", "F"
+Item_03 = "Contratti/Convenzioni P.A.", "pa0 -1 &CON", "F"
diff --git a/pa/patbcon.h b/pa/patbcon.h
new file mode 100644
index 000000000..d13e71e11
--- /dev/null
+++ b/pa/patbcon.h
@@ -0,0 +1,13 @@
+#ifndef __PATBCON_H
+#define __PATBCON_H
+
+#define F_CON_TIPO         101
+#define F_CON_CODCF        102
+#define F_CON_RAGSOC       112
+#define F_CON_CODICE       103
+#define F_CON_DESCRIZIONE  113
+#define F_CON_DATA         121
+
+#endif
+
+
diff --git a/pa/patbcon.uml b/pa/patbcon.uml
new file mode 100644
index 000000000..7c7289b68
--- /dev/null
+++ b/pa/patbcon.uml
@@ -0,0 +1,107 @@
+#include "patbcon.h"
+
+TOOLBAR "topbar" 0 0 0 2
+#include <relapbar.h>
+ENDPAGE
+
+PAGE "Contratti per PA" 0 2 0 0
+
+GROUPBOX DLG_NULL 78 7
+BEGIN
+  PROMPT 1 0 "@bEstremi contratto/convenzione/ordine P.A."
+END
+
+LIST F_CON_TIPO 1 11
+BEGIN
+  PROMPT 2 1 "Tipo    "
+  ITEM "C|Contratto"
+  ITEM "V|Convenzione"
+  ITEM "O|Ordine"
+  FIELD CODTAB[1,1]
+  KEY 1
+END
+
+NUMBER F_CON_CODCF 6
+BEGIN
+  PROMPT 2 2 "Cliente "
+  USE LF_CFVEN SELECT PADESTIN!=""
+  JOIN LF_CLIFO INTO TIPOCF==TIPOCF CODCF==CODCF
+  INPUT TIPOCF "C"
+  INPUT CODCF F_CON_CODCF
+  DISPLAY "Codice" CODCF
+  DISPLAY "Ragione Sociale@50" LF_CLIFO->RAGSOC
+  DISPLAY "Destinatario" PADESTIN
+  DISPLAY "Riferimento amm.@20" PARIFAMM
+  OUTPUT F_CON_CODCF CODCF
+  OUTPUT F_CON_RAGSOC LF_CLIFO->RAGSOC
+  CHECKTYPE REQUIRED
+  FIELD CODTAB[2,7]
+  KEY 1
+  MESSAGE EMPTY ENABLE,F_CON_RAGSOC
+  MESSAGE DISABLE,F_CON_RAGSOC
+END
+
+STRING F_CON_RAGSOC 50
+BEGIN
+  PROMPT 24 2 ""
+  USE LF_CLIFO KEY 2 SELECT LF_CFVEN->PADESTIN!=""
+  JOINT LF_CFVEN INTO TIPOCF==TIPOCF CODCF==CODCF
+  INPUT TIPOCF "C"
+  INPUT RAGSOC F_CON_RAGSOC
+  DISPLAY "Ragione Sociale@50" RAGSOC
+  DISPLAY "Codice" CODCF
+  DISPLAY "Destinatario" LF_CFVEN->PADESTIN
+  DISPLAY "Riferimento amm.@20" LF_CFVEN->PARIFAMM
+  COPY OUTPUT F_CON_CODCF
+  CHECKTYPE NORMAL
+END
+
+STRING F_CON_CODICE 20
+BEGIN
+  PROMPT 2 3 "Numero  "
+  FLAGS "U"
+  FIELD CODTAB[8,27]
+  USE &CON
+  JOIN LF_CLIFO INTO TIPOCF="C" CODCF=CODTAB[2,7]
+  INPUT CODTAB[1,1] F_CON_TIPO SELECT
+  INPUT CODTAB[2,7] F_CON_CODCF SELECT
+  INPUT CODTAB[8,27] F_CON_CODICE
+  DISPLAY "Tipo" CODTAB[1,1]
+  DISPLAY "Numero@20" CODTAB[8,]
+  DISPLAY "Descrizione@50" S0
+  DISPLAY "Cliente" CODTAB[2,7]
+  DISPLAY "Ragione Sociale@50" LF_CLIFO->RAGSOC
+  OUTPUT F_CON_CODCF CODTAB[2,7]
+  OUTPUT F_CON_CODICE CODTAB[8,]
+  OUTPUT F_CON_DESCRIZIONE S0
+  CHECKTYPE REQUIRED
+  KEY 1
+END
+
+STRING F_CON_DESCRIZIONE 70 50
+BEGIN
+  PROMPT 2 4 "Descrizione           "
+  FIELD S0
+  USE &CON KEY 2 SELECT (CODTAB[1,1]==#F_CON_TIPO)&&(STR(CODTAB[2,7]=#F_CON_CODCF))
+  JOIN LF_CLIFO INTO TIPOCF=CODTAB[1,1] CODCF=CODTAB[2,7]
+  INPUT S0 F_CON_DESCRIZIONE
+  DISPLAY "Tipo" CODTAB[1,1]
+  DISPLAY "Descrizione@50" S0
+  DISPLAY "Numero@20" CODTAB[8,]
+  DISPLAY "Cliente" CODTAB[2,7]
+  DISPLAY "Ragione Sociale@50" LF_CLIFO->RAGSOC
+  CHECKTYPE REQUIRED
+  COPY OUTPUT F_CON_CODICE
+  KEY 2
+END
+
+DATA F_CON_DATA
+BEGIN
+  PROMPT 2 5 "Data           "
+  FIELD D0
+END
+
+ENDPAGE
+ENDMASK
+
+