From dc1243ae57c77b52e9b0808888b7403d8873de88 Mon Sep 17 00:00:00 2001
From: guy <guy@c028cbd2-c16b-5b4b-a496-9718f37d4682>
Date: Mon, 11 Dec 1995 11:22:47 +0000
Subject: [PATCH] Stampa EC

git-svn-id: svn://10.65.10.50/trunk@2264 c028cbd2-c16b-5b4b-a496-9718f37d4682
---
 sc/sc2100.cpp  | 244 +++++++++++++-------
 sc/sc2100a.uml |   5 +-
 sc/sc2102.cpp  | 100 +++++----
 sc/sc2102.h    | 111 ++++++----
 sc/sc21pec.h   |   7 +-
 sc/sc2402.cpp  | 589 +++++++++++++++++++++++++------------------------
 6 files changed, 584 insertions(+), 472 deletions(-)

diff --git a/sc/sc2100.cpp b/sc/sc2100.cpp
index 139c9c1a0..6be2cea50 100755
--- a/sc/sc2100.cpp
+++ b/sc/sc2100.cpp
@@ -32,7 +32,9 @@ class TEC_form : public TForm
   TDecoder _causali;
   
   TString _lingua;
-  TDate _dlo, _dls;
+  TDate _dlo, _dls, _dir;
+  int _giorni_rischio;
+  bool _in_valuta;
 
 protected:
   static void ec_header_handler(TPrinter& p);
@@ -44,7 +46,12 @@ public:
 
   const TDate& data_limite_operazione() const { return _dlo; }
   const TDate& data_limite_scaduto() const { return _dls; }
+  int giorni_rischio() const { return _giorni_rischio; }
+  const TDate& data_inizio_rischio() const { return _dir; }
+
   const TString& lingua() const { return _lingua; }
+  bool in_valuta() const { return _in_valuta; }
+  const TString& describe(short id, char sez = 'B') const;
   
   bool print_game(const TPartita& game);
 
@@ -75,6 +82,8 @@ class TEC_row : public TSortable
   TImporto _importo;             // Importo in valuta
   TImporto _importo_lire;        // Importo in lire
   real     _scaduto;             // Importo scaduto
+  real     _esposto;             // Importo esposto
+  bool     _salvo_buon_fine;     // Importo esposto salvo buon fine
   real     _totale;              // Totale documento
   TValuta  _valuta;              // Codice valuta, data cambio e cambio
   
@@ -86,11 +95,16 @@ public:
   int rata() const { return _rata; }
 
   void descrizione(const char* s) { _descrizione = s; }
+  void importo(const TImporto& i) { _importo = i; }
   void scaduto(const real& s) { _scaduto = s; }
+  void esposto(const real& e) { _esposto = e; }
+  void salvo_buon_fine(bool sbf) { _salvo_buon_fine = sbf; }
   
-  const TValuta& valuta() const { return _valuta; } 
-  const TImporto& importo() const { return _importo; }
   const TDate& data() const { return _data; }
+  const TImporto& importo() const { return _importo; }
+  real scaduto() const { return _scaduto; }
+  real esposto() const { return _esposto; }
+  const TValuta& valuta() const { return _valuta; } 
   
   void print_on(TPrint_section& body);
   
@@ -100,7 +114,7 @@ public:
 };
 
 TEC_row::TEC_row(const TRiga_partite& row, const TDate& data, const TImporto& imp, int rata)
-       : _num_prot(0)
+       : _num_prot(0), _salvo_buon_fine(FALSE)
 {        
   _riga     = row.get_int(PART_NRIGA); 
   _rata     = rata;
@@ -116,7 +130,7 @@ TEC_row::TEC_row(const TRiga_partite& row, const TDate& data, const TImporto& im
 }
 
 TEC_row::TEC_row(const char* desc, const TImporto& imp)
-       : _num_prot(0)
+       : _riga(9999), _rata(9999), _num_prot(0), _salvo_buon_fine(FALSE)
 {
   _descrizione = desc;
   _importo = imp; _importo.normalize();                  
@@ -130,12 +144,12 @@ int TEC_row::compare(const TSortable& s) const
   int c = 0;
   if (_data == r._data)
   {
-    c = r._riga - _riga;
+    c = _riga - r._riga;
     if (c == 0)
-      c = r._rata - _rata;
+      c = _rata - r._rata;
   }  
   else
-    c = _data < r._data ? +1 : -1;
+    c = _data > r._data ? +1 : -1;
   return c;    
 }  
 
@@ -185,6 +199,12 @@ void TEC_row::print_on(TPrint_section& body)
   TForm_item& scaduto = body.find_field(PEC_SCADUTO);
   scaduto.set(_scaduto.string());
   
+  TForm_item& esposto = body.find_field(PEC_ESPOSTO);
+  esposto.set(_esposto.string());
+  
+  TForm_item& sbf = body.find_field(PEC_SBF);
+  sbf.set(_salvo_buon_fine ? "*" : " ");
+  
   TForm_item& cambio = body.find_field(PEC_CAMBIO);
   cambio.set(_valuta.cambio().string());
     
@@ -255,13 +275,15 @@ TImporto TEC_array::importo(const TPartita& game, const TRectype& pag, bool valu
   return imp;
 }
 
+// Certified 100%
 TImporto& TEC_array::importo_riga_scaduto(int n)
-{
+{                         
+  CHECKD(n > 0 && n < 9999, "Riga scaduto errata ", n);
   TImporto* imp = importo_riga_scaduto_ptr(n);
   if (imp == NULL)
   {
     imp = new TImporto;
-    _scaduto.add(imp);
+    _scaduto.add(imp, n);
   }
   return *imp;
 }
@@ -278,13 +300,14 @@ real TEC_array::calcola_scaduto(const TRiga_scadenze& rata, bool valuta)
   for (int p = rata.first(); p <= lastp; p = rata.succ(p))    // Qui bisogna andare in avanti!
   {
     const TRectype& pag = rata.row(p);
-    const TRiga_partite& sum = game.riga(pag.get_int(PAGSCA_NRIGP));
+    const int nrigp = pag.get_int(PAGSCA_NRIGP);
+    const TRiga_partite& sum = game.riga(nrigp);
     const tipo_movimento tm = sum.tipo();
     const TImporto imp = importo(game, pag, valuta);
-    if (tm == tm_insoluto && tm == tm_pagamento_insoluto)
+    if (tm == tm_insoluto || tm == tm_pagamento_insoluto)
     {   
       if (tm == tm_insoluto)
-        riga_corrente_scaduto = pag.get_int(PAGSCA_NRIGP);
+        riga_corrente_scaduto = nrigp;
       else
         CHECKD(riga_corrente_scaduto > 0, "Pagamento insoluto senza insoluto ", p);
       importo_riga_scaduto(riga_corrente_scaduto) += imp;
@@ -303,15 +326,16 @@ real TEC_array::calcola_scaduto(const TRiga_scadenze& rata, bool valuta)
 TEC_row& TEC_array::new_row(const TRiga_partite& row, const TDate& data, 
                             const TImporto& imp, int n)
 { 
-  if (n == 0) 
-    n = items();      
+  CHECKD(n > 0, "Numero rata errato: ", n);
   TEC_row* riga = new TEC_row(row, data, imp, n);
-  add(riga, n);
+  add(riga);
   return *riga;
 }
 
 void TEC_array::add_row(const TRiga_partite& row)
 {
+  const bool in_valuta = form().in_valuta();
+  
   if (row.is_fattura())
   {
     for (int r = 1; r <= row.rate(); r++)
@@ -320,11 +344,10 @@ void TEC_array::add_row(const TRiga_partite& row)
       const TDate data(rata.get(SCAD_DATASCAD));
       if (data <= form().data_limite_operazione())
       {
-        TEC_row& rec = new_row(row, data, rata.importo(TRUE), r);
+        TEC_row& rec = new_row(row, data, rata.importo(in_valuta), r);
         if (data <= form().data_limite_scaduto())
         {
-          real s;
-          calcola_scaduto(rata, s);
+          const real s = calcola_scaduto(rata, in_valuta);
           rec.scaduto(s);
         }  
       }  
@@ -335,23 +358,51 @@ void TEC_array::add_row(const TRiga_partite& row)
     const TDate data(row.get(PART_DATAPAG));
     if (data <= form().data_limite_operazione())
     {  
-      const TImporto imp(row.importo(FALSE, 0x1));
-      new_row(row, data, imp);
+      const TImporto imp(row.importo(in_valuta, 0x1));
+      TEC_row& riga = new_row(row, data, imp, 1);
       
-      const TImporto abbuoni(row.importo(FALSE, 0x2));
+      const int tipo_pag = row.get_int(PART_TIPOPAG);
+      if (tipo_pag >= 2 && tipo_pag <= 7)          // Controlla se e' un pagamento con effetti
+      { 
+        const TDate data_pag(row.get(PART_DATAPAG));
+        const TDate& dls = form().data_limite_scaduto();
+        const int gr = form().giorni_rischio(); 
+        
+        bool sbf = FALSE;
+        if (gr > 0)
+        {          
+          const TDate& dir = form().data_inizio_rischio();
+          sbf = data_pag >= dir && data_pag <= dls;
+          riga.salvo_buon_fine(sbf);                        // Esposto salvo buon fine
+        }
+        
+        bool esp = sbf;
+        if (!esp)
+        {
+          esp = gr > 0 ? data_pag >= dls : data_pag > dls;  // Esposto normale
+        }   
+        
+        if (esp)
+        {
+          TImporto esposto(imp);
+          const char sezione = row.get_char(PART_TIPOCF) == 'C' ? 'D' : 'A';
+          esposto.normalize(sezione);
+          riga.esposto(esposto.valore());
+        }
+      }
+      
+      const TImporto abbuoni(row.importo(in_valuta, 0x2));
       if (!abbuoni.is_zero())
       {
-        TEC_row& r = new_row(row, data, abbuoni);
-        const TForm_item& desc_abb = form().find_field('B', odd_page, 302);
-        r.descrizione(desc_abb.prompt());
+        TEC_row& r = new_row(row, data, abbuoni, 2);
+        r.descrizione(form().describe(302));
       }  
-        
-      const TImporto diffcam(row.importo(FALSE, 0x4));
+      
+      const TImporto diffcam(row.importo(in_valuta, 0x4));
       if (!diffcam.is_zero())
       {
-        TEC_row& r = new_row(row, data, diffcam);
-        const TForm_item& desc_dif = form().find_field('B', odd_page, 303);
-        r.descrizione(desc_dif.prompt());
+        TEC_row& r = new_row(row, data, diffcam, 3);
+        r.descrizione(form().describe(303));
       }  
     }  
   }
@@ -367,11 +418,14 @@ TEC_array::TEC_array(const TPartita& game, const TEC_form* f)
   for (r = items()-1; r >= 0; r--)
   {
     TEC_row& s = row(r);
-    TImporto* imp = importo_riga_scaduto_ptr(s.riga());
-    if (imp != NULL)
+    if (s.rata() == 1)
     {
-      imp->normalize(sezione);
-      s.scaduto(imp->valore());
+      TImporto* imp = importo_riga_scaduto_ptr(s.riga());
+      if (imp != NULL)
+      {
+        imp->normalize(sezione);
+        s.scaduto(imp->valore());
+      }  
     }  
   }
   
@@ -394,14 +448,15 @@ void TEC_form::ec_header_handler(TPrinter& pr)
     pr.setheaderline(j, head.row(j));
 }
 
-// Confronta due valute alfabeticamente
-static int val_compare(const void* o1, const void* o2)
-{ 
+// Confronta due totali in valuta alfabeticamente
+static int tot_compare(const void* o1, const void* o2)
+{                       
+  if (o1 == o2) // Sfrutto una piccola debolezza di qsort: 
+    return 0;   // ogni tanto confronta oggetti con se stessi    
+
   const THash_object* h1 = (const THash_object*)o1;
   const THash_object* h2 = (const THash_object*)o2;
-  const TString& s1 = (const TString&)h1->obj();
-  const TString& s2 = (const TString&)h2->obj();
-  return s2.compare(s1, -1, TRUE);    // same as stricmp(s1, s2) in reverse order
+  return stricmp(h1->key(), h2->key());
 }
 
 void TEC_form::ec_footer_handler(TPrinter& pr)
@@ -409,7 +464,7 @@ void TEC_form::ec_footer_handler(TPrinter& pr)
   TPrint_section& foot = _form->section('F');
   pr.resetfooter();
   
-  const word MAXTOT = 32;
+  const word MAXTOT = 16;
   THash_object* tot[MAXTOT];
   
   // I totali sono in un assoc array disordinato per cui li copio in un array e li ordino
@@ -422,20 +477,41 @@ void TEC_form::ec_footer_handler(TPrinter& pr)
        numtot < MAXTOT && obj != NULL; 
        obj = totali.get_hashobj())
     tot[numtot++] = obj;
-  qsort(tot, numtot, sizeof(THash_object*), val_compare);
+  qsort(tot, numtot, sizeof(THash_object*), tot_compare);
   
-  if (numtot > foot.height())
-    numtot = foot.height();
+  const word maxtot = foot.height() / 3;
+  if (numtot > maxtot)
+    numtot = maxtot;
   
+  TString desc(80);
   TPrint_section& body = _form->section('B');
   for (word j = 0; j < numtot; j++)
   {                                
+    const word line = j*3;
     const TString& key = tot[j]->key();
-    TImporto& imp = (TImporto&)tot[j]->obj();
-    TEC_row r(key, imp.normalize());
-    r.print_on(body);
-    const TPrintrow& ri = body.row(0);
-    pr.setfooterline(j, ri);
+    TTotal& t = (TTotal&)(tot[j]->obj());
+    
+    desc = _form->describe(301, 'F');
+    if (key.not_empty())
+      desc << ' ' << key;
+    TEC_row rip(desc, t.importo().normalize());
+    rip.print_on(body);
+    pr.setfooterline(line, body.row(0));
+    
+    desc = _form->describe(302, 'F');
+    desc << ' ' << _form->data_limite_scaduto();
+    rip.descrizione(desc);
+    rip.importo(TImporto('D', ZERO));
+    rip.scaduto(t.scaduto());
+    rip.print_on(body);
+    pr.setfooterline(line+1, body.row(0));
+               
+    desc = _form->describe(303, 'F');
+    rip.descrizione(desc);
+    rip.scaduto(ZERO);
+    rip.esposto(t.esposto());
+    rip.print_on(body);
+    pr.setfooterline(line+2, body.row(0));
   }
 } 
 
@@ -452,6 +528,7 @@ bool TEC_form::print_game(const TPartita& game)
   TPrint_section& body = section('B');
   
   TImporto saldo;
+  real scaduto, esposto;
   
   // Stampa le righe di partita
   for (int r = 0; r < righe.items(); r++)
@@ -464,9 +541,11 @@ bool TEC_form::print_game(const TPartita& game)
     riga.print_on(body);
     pr.print(body.row(0));
     
-    totali().add(riga.importo(), riga.valuta().codice());
+    totali().add(riga.importo(), riga.scaduto(), riga.esposto(), riga.valuta().codice());
     
     saldo += riga.importo();
+    scaduto += riga.scaduto();
+    esposto += riga.esposto();
     ok = TRUE;
   }
   
@@ -474,9 +553,11 @@ bool TEC_form::print_game(const TPartita& game)
   {         
     saldo.normalize();         
     
-    const TForm_item& desc_sld = body.find_field(301);
-    TEC_row sld(desc_sld.prompt(), saldo);
+    TEC_row sld(describe(301), saldo);
+    sld.scaduto(scaduto);
+    sld.esposto(esposto);
     sld.print_on(body);
+    pr.print(body.row(0));
     
     // Salta una riga vuota
     TPrintrow vuota;
@@ -485,8 +566,14 @@ bool TEC_form::print_game(const TPartita& game)
   return ok;
 }
 
+const TString& TEC_form::describe(short id, char sez) const
+{                                 
+  const TForm_item& fi = find_field(sez, odd_page, id);
+  return fi.prompt();
+}
+
 TEC_form::TEC_form(const TEC_mask& m)
-        : TForm(BASE_EC_PROFILE, m.get_prof_code()), 
+        : TForm(BASE_EC_PROFILE, m.get_prof_code()), _in_valuta(FALSE),
           _causali(LF_CAUSALI, CAU_CODCAUS, CAU_DESCR)
 { 
   _form = this;                 
@@ -496,8 +583,10 @@ TEC_form::TEC_form(const TEC_mask& m)
   TCursor_sheet& cs = m.cur_sheet();
   _cursore = cs.cursor();                     
 
- _dlo = m.get(F_DATALIMOP);
- _dls = m.get(F_DATALIMSC);
+  _dlo = m.get(F_DATALIMOP);
+  _dls = m.get(F_DATALIMSC);
+  _giorni_rischio = m.get_int(F_GIORISCH); 
+  _dir = _dls; _dir -= _giorni_rischio;
    
   TPrinter& pr = printer();
   
@@ -545,7 +634,6 @@ public:
   TCursor_sheet& sheet() { return _msk->cur_sheet(); }
   TEC_form& form() { return *_form; }
   
-  bool select_ec();                       // starting point 
   bool print_selected();                  // print selected items
   bool print_ec();                        // print one item
 
@@ -553,21 +641,6 @@ public:
   virtual ~TStampaEC_application() {}
 };
 
-bool TStampaEC_application::select_ec()
-{
-  TEC_mask& m = mask();
-  while (m.run() != K_ESC)
-  {
-    _form = new TEC_form(m); 
-
-    print_selected();
-
-    delete _form;
-    _form = NULL;
-  }
-  return TRUE;
-}                                                     
-
 bool TStampaEC_application::print_selected()
 {            
   TCursor_sheet& s = sheet();         
@@ -621,6 +694,8 @@ bool TStampaEC_application::print_ec()
   
   if (!ok)   // Cliente analfabeta
     return FALSE;
+    
+  f.totali().destroy();       // Azzera totali di fine pagina
   
   // Filtra solo le partite del cliente selezionato
   TLocalisamfile& partite = _file[LF_PARTITE];
@@ -631,8 +706,6 @@ bool TStampaEC_application::print_ec()
   
   const bool stampa_chiuse = mask().get_bool(F_STAMPCHIU);
   const TDate data_chiuse = mask().get(F_DATACHIU);
-  const TDate data_scaduto = mask().get(F_DATALIMSC);
-  const int giorni_rischio = mask().get_int(F_GIORISCH);
   
   bool one_printed = FALSE;
   for (int err = partite.read(_isgteq); 
@@ -642,9 +715,9 @@ bool TStampaEC_application::print_ec()
     TPartita game(partite.curr());
     
     if (game.chiusa())
-    {                    
-      TDate data_rischio = data_scaduto; data_rischio -= giorni_rischio;
-      const TImporto saldo = game.calcola_saldo_al(data_rischio, TRUE);
+    {                         
+      const TDate& dir = form().data_inizio_rischio();
+      const TImporto saldo = game.calcola_saldo_al(dir, TRUE);
       if (saldo.is_zero())
       {  
         int r = 0;              
@@ -656,7 +729,7 @@ bool TStampaEC_application::print_ec()
             if (riga.is_fattura())
             {
               const TDate dd(riga.get(PART_DATADOC));
-              if (dd > data_rischio)
+              if (dd > dir)
                 break;
             }
           } 
@@ -673,9 +746,6 @@ bool TStampaEC_application::print_ec()
     partite.put(PART_NRIGA, 9999);
   }
   
-  if (one_printed)
-    printer().formfeed();
-  
   return TRUE;  
 } 
 
@@ -712,9 +782,19 @@ void TStampaEC_application::on_firm_change()
   _gesval = c.get_bool("GesVal");
 }  
 
-bool TStampaEC_application::menu(MENU_TAG m)
+bool TStampaEC_application::menu(MENU_TAG)
 {
-  select_ec();  
+  TEC_mask& m = mask();
+  while (m.run() != K_QUIT)
+  {
+    _form = new TEC_form(m); 
+
+    print_selected();
+
+    delete _form;
+    _form = NULL;
+  }
+
   return FALSE;
 }                
 
diff --git a/sc/sc2100a.uml b/sc/sc2100a.uml
index 5c3e6af43..2f2b9bbd4 100755
--- a/sc/sc2100a.uml
+++ b/sc/sc2100a.uml
@@ -157,12 +157,13 @@ BEGIN
 END
 
 
-BUTTON DLG_OK 10 2
+BUTTON DLG_PRINT 10 2
 BEGIN
   PROMPT -12 -1 ""
+  MESSAGE EXIT,K_ENTER
 END
 
-BUTTON DLG_CANCEL 10 2
+BUTTON DLG_QUIT 10 2
 BEGIN
   PROMPT -22 -1 ""
 END
diff --git a/sc/sc2102.cpp b/sc/sc2102.cpp
index 8f29cab41..faaec8256 100755
--- a/sc/sc2102.cpp
+++ b/sc/sc2102.cpp
@@ -1,46 +1,54 @@
-
-#include "sc2102.h"
-
-///////////////////////////////////////////////////////////
-// Totalizzatore
-///////////////////////////////////////////////////////////
-
-void TTotalizer::add(const TImporto& imp, const TString& val)
-{              
-  TString16 codice(val);
-  if (codice == "LIT")
-    codice.cut(0);
-   
-  TObject* obj = objptr(codice);
-  if (obj != NULL)
-  {
-    TImporto& tot = (TImporto&)*obj;
-    tot += imp;
-  }
-  else
-  {
-    TAssoc_array::add(codice, new TImporto(imp));
-  }
-}
-
-
-///////////////////////////////////////////////////////////
-// TFilearray
-///////////////////////////////////////////////////////////
-
-void TFile_array::open(int logicnum, ...)  
-{  
-  va_list marker;
-  va_start(marker, logicnum);
-  while (logicnum > 0)
-  {
-    CHECKD(_file.objptr(logicnum) == NULL, "File gia' aperto: ", logicnum);
-    _file.add(new TLocalisamfile(logicnum), logicnum);
-    logicnum = va_arg(marker, int);
-  }
-}
-
-void TFile_array::close()
-{
-	_file.destroy();
-}
+
+#include "sc2102.h"
+
+///////////////////////////////////////////////////////////
+// Totalizzatore
+///////////////////////////////////////////////////////////
+
+TTotal::TTotal(const TImporto& imp, const real& sca, const real& esp)
+      : _importo(imp), _scaduto(sca), _esposto(esp)
+{ }      
+
+void TTotalizer::add(const TImporto& imp, const real& sca,
+                     const real& esp, const TString& val)
+{              
+  TString16 codice(val);
+  if (codice == "LIT")
+    codice.cut(0);
+   
+  TObject* obj = objptr(codice);
+  if (obj != NULL)
+  {
+    TTotal& tot = (TTotal&)*obj;
+    tot.importo() += imp;
+    tot.scaduto() += sca;
+    tot.esposto() += esp;
+  }
+  else
+  {                     
+    obj = new TTotal(imp, sca, esp);
+    TAssoc_array::add(codice, obj);
+  }
+}
+
+
+///////////////////////////////////////////////////////////
+// TFilearray
+///////////////////////////////////////////////////////////
+
+void TFile_array::open(int logicnum, ...)  
+{  
+  va_list marker;
+  va_start(marker, logicnum);
+  while (logicnum > 0)
+  {
+    CHECKD(_file.objptr(logicnum) == NULL, "File gia' aperto: ", logicnum);
+    _file.add(new TLocalisamfile(logicnum), logicnum);
+    logicnum = va_arg(marker, int);
+  }
+}
+
+void TFile_array::close()
+{
+  _file.destroy();
+}
diff --git a/sc/sc2102.h b/sc/sc2102.h
index f0e5cb550..4537afe56 100755
--- a/sc/sc2102.h
+++ b/sc/sc2102.h
@@ -1,46 +1,65 @@
-
-#ifndef __SC2102_H
-#define __SC2102_H
-                    
-#include <stdarg.h>
-                    
-#include <utility.h>
-#include <array.h>
-#include <strings.h>
-#include <real.h>
-#include <isam.h>
-
-
-///////////////////////////////////////////////////////////
-// Totalizzatore
-///////////////////////////////////////////////////////////
-
-class TTotalizer : public TAssoc_array
-{ 
-public:
-  void add(const TImporto& imp, const TString& val);
-
-  TTotalizer() { }
-  virtual ~TTotalizer() { }
-};
-
-
-///////////////////////////////////////////////////////////
-// TFilearray
-///////////////////////////////////////////////////////////
-
-class TFile_array
-{         
-  TArray _file;
-
-public:
-  void open(int num, ...);
-  void close();
-  TLocalisamfile& file(int num) const { return (TLocalisamfile&)_file[num]; }
-  TLocalisamfile& operator[](int num) const { return file(num); }
-
-  TFile_array() {}
-  virtual ~TFile_array() {}
-};
-
-#endif // __SC2102_H
+
+#ifndef __SC2102_H
+#define __SC2102_H
+                    
+#include <stdarg.h>
+                    
+#include <utility.h>
+#include <array.h>
+#include <strings.h>
+#include <real.h>
+#include <isam.h>
+
+
+///////////////////////////////////////////////////////////
+// Totalizzatore
+///////////////////////////////////////////////////////////
+
+class TTotal : public TObject
+{
+  TImporto _importo;
+  real _scaduto;
+  real _esposto;
+  
+public:
+  const TImporto& importo() const { return _importo; }  
+  const real& scaduto() const { return _scaduto; }
+  const real& esposto() const { return _esposto; }
+  TImporto& importo() { return _importo; }  
+  real& scaduto() { return _scaduto; }
+  real& esposto() { return _esposto; }
+  
+  TTotal(const TImporto& imp, const real& scaduto, const real& esposto);
+  virtual ~TTotal() {}
+};
+
+class TTotalizer : public TAssoc_array
+{ 
+public:
+  void add(const TImporto& imp, const real& scaduto, 
+           const real& esposto, const TString& val);
+
+  TTotalizer() { }
+  virtual ~TTotalizer() { }
+};
+
+
+///////////////////////////////////////////////////////////
+// TFilearray
+///////////////////////////////////////////////////////////
+
+class TFile_array
+{         
+  TArray _file;
+
+public:
+  void open(int num, ...);
+  void close();
+  TLocalisamfile& file(int num) const { return (TLocalisamfile&)_file[num]; }
+  TLocalisamfile& operator[](int num) const { return file(num); }
+
+  TFile_array() {}
+  virtual ~TFile_array() {}
+};
+
+#endif // __SC2102_H
diff --git a/sc/sc21pec.h b/sc/sc21pec.h
index 506210721..4d6cc3603 100755
--- a/sc/sc21pec.h
+++ b/sc/sc21pec.h
@@ -14,8 +14,9 @@
 #define PEC_AVERE   211
 #define PEC_SCADUTO 212
 #define PEC_ESPOSTO 213
-#define PEC_IMPLIRE 214
-#define PEC_CAMBIO  215
-#define PEC_DATACAM 216
+#define PEC_SBF     214
+#define PEC_IMPLIRE 215
+#define PEC_CAMBIO  216
+#define PEC_DATACAM 217
 
 #endif
diff --git a/sc/sc2402.cpp b/sc/sc2402.cpp
index 39b80e820..cee4d70ae 100755
--- a/sc/sc2402.cpp
+++ b/sc/sc2402.cpp
@@ -1,293 +1,296 @@
-
-#include "../cg/saldacon.h"
-#include <pagsca.h>
-#include <scadenze.h>
-#include <partite.h>
-
-#include "sc21pec.h"
-#include "sc2102.h"
-#include "sc2402.h"
-
-#include <causali.h>
-
-
-///////////////////////////////////////////////////////////
-// TSol_row
-///////////////////////////////////////////////////////////
-
-TSol_row::TSol_row(const TRiga_partite& row, const TDate& data, const TImporto& imp, int rata): _num_prot(0) {        
-  _riga     = row.get_int(PART_NRIGA); 
-  _rata     = rata;
-
-  _data     = data;              
-  _causale  = row.get(PART_CODCAUS);
-  _data_doc = row.get(PART_DATADOC);
-  _num_prot = row.get_long(PART_PROTIVA);
-  _importo  = imp;   _importo.normalize();                  
-  _totale   = row.get_real(PART_IMPTOTPAG);
-
-  _valuta.get(row);
-}
-
-TSol_row::TSol_row(const char* desc, const TImporto& imp): _num_prot(0) {
-  _descrizione = desc;
-  _importo = imp; _importo.normalize();                  
-}
-
-// le righe dell'estratto conto sono ordinate per data, riga partita, numero rata, 
-// posizione iniziale nell'array (in caso di uguaglianza di tutto il resto)
-int TSol_row::compare(const TSortable& s) const {
-  const TSol_row& r = (const TSol_row&)s;
-  int c = 0;
-  if (_data == r._data) {
-    c = r._riga - _riga;
-    if (c == 0) c = r._rata - _rata;
-  } else c = _data < r._data ? +1 : -1;
-  return c;    
-}  
-
-void TSol_row::print_on(TPrint_section& body) {                     
-  TSol_form& form = (TSol_form&)body.form();
-
-  TForm_item& causale = body.find_field(PEC_CODCAUS);
-  causale.set(_causale);
-  if (_causale.not_empty() && _descrizione.empty()) {
-    TDecoder& causali = form.causali();
-    _descrizione = causali.decode(_causale);
-  }
-  
-  TForm_item& descr = body.find_field(PEC_DESCR1);
-  descr.set(_descrizione);
-  
-  TForm_item& datadoc = body.find_field(PEC_DATADOC);
-  datadoc.set(_data_doc.string());
-  
-  TForm_item& numdoc = body.find_field(PEC_NUMDOC);
-  numdoc.set(_num_doc);
-  
-  TForm_item& numprot = body.find_field(PEC_PROTIVA);
-  TString16 protiva; protiva << _num_prot;
-  numprot.set(protiva);
-  
-  TForm_item& datapag = body.find_field(PEC_DATAPAG);
-  datapag.set(_data.string());
-  
-  const real& imp = _importo.valore();
-  TForm_item& dare  = body.find_field(PEC_DARE);
-  TForm_item& avere = body.find_field(PEC_AVERE);
-    
-  if (_importo.sezione() == 'D') {
-    dare.set(imp.string());
-    avere.set("");
-  } else {
-    avere.set(imp.string());
-    dare.set("");
-  }   
-  
-  TForm_item& scaduto = body.find_field(PEC_SCADUTO);
-  scaduto.set(_scaduto.string());
-  
-  TForm_item& cambio = body.find_field(PEC_CAMBIO);
-  cambio.set(_valuta.cambio().string());
-    
-  TForm_item& datacambio = body.find_field(PEC_DATACAM);
-  datacambio.set(_valuta.data().string());
-
-  body.update();
-}
-
-static int val_compare(const void* o1, const void* o2) { 
-  const THash_object* h1 = (const THash_object*)o1;
-  const THash_object* h2 = (const THash_object*)o2;
-  const TString& s1 = (const TString&)h1->obj();
-  const TString& s2 = (const TString&)h2->obj();
-  return s2.compare(s1, -1, TRUE);    // same as stricmp(s1, s2) in reverse order
-}
-
-
-///////////////////////////////////////////////////////////
-// TSol_array
-///////////////////////////////////////////////////////////
-
-void TSol_array::calcola_scaduto(const TRiga_scadenze& rata, real& scaduto) const {                                   
-  const TPartita& game = rata.partita();
-  TImporto imp_scaduto = rata.importo(TRUE);
-  
-  const char* const field = rata.in_valuta() ? PAGSCA_IMPORTOVAL : PAGSCA_IMPORTO;
-  TImporto imp;
-  
-  for (int p = rata.last(); p > 0; p = rata.pred(p)) {
-    const TRectype& pag = rata.row(p);
-    const TRiga_partite& sum = game.riga(pag.get_int(PAGSCA_NRIGP));
-    const tipo_movimento tm = sum.tipo();
-    if (tm != tm_insoluto && tm != tm_pagamento_insoluto) {                                                     
-      imp.set(sum.sezione(), pag.get_real(field));
-      imp_scaduto += imp;
-    }  
-  }
-  const char sezione = game.conto().tipo() == 'C' ? 'D' : 'A';
-  imp_scaduto.normalize(sezione);
-  scaduto = imp_scaduto.valore();
-}
-
-TSol_row& TSol_array::new_row(const TRiga_partite& row, const TDate& data, const TImporto& imp, int n) { 
-  if (n == 0) n = items();      
-  TSol_row* riga = new TSol_row(row, data, imp, n);
-  add(riga, n);
-  return *riga;
-}
-
-void TSol_array::add_row(const TRiga_partite& row) {
-  if (row.is_fattura()) {
-    for (int r = 1; r <= row.rate(); r++) {                                                    
-      const TRiga_scadenze& rata = row.rata(r);
-      const TDate data(rata.get(SCAD_DATASCAD));
-      if (data <= form().data_limite_operazione()) {
-        TSol_row& rec = new_row(row, data, rata.importo(TRUE), r);
-        if (data <= form().data_limite_scaduto()) {
-          real s;
-          calcola_scaduto(rata, s);
-          rec.scaduto(s);
-        }  
-      }  
-    }
-  } else {      
-    const TDate data(row.get(PART_DATAPAG));
-    if (data <= form().data_limite_operazione()) {  
-      const TImporto imp(row.importo(FALSE, 0x1));
-      new_row(row, data, imp);
-      
-      const TImporto abbuoni(row.importo(FALSE, 0x2));
-      if (!abbuoni.is_zero()) {
-        TSol_row& r = new_row(row, data, abbuoni);
-        const TForm_item& desc_abb = form().find_field('B', odd_page, 302);
-        r.descrizione(desc_abb.prompt());
-      }  
-        
-      const TImporto diffcam(row.importo(FALSE, 0x4));
-      if (!diffcam.is_zero()) {
-        TSol_row& r = new_row(row, data, diffcam);
-        const TForm_item& desc_dif = form().find_field('B', odd_page, 303);
-        r.descrizione(desc_dif.prompt());
-      }  
-    }  
-  }
-}
-
-TSol_array::TSol_array(const TPartita& game, const TSol_form* f): _form(f) { 
-  for (int r = game.last(); r > 0; r = game.pred(r)) add_row(game.riga(r));
-  sort();  
-}
-
-
-///////////////////////////////////////////////////////////
-// TSol_form: form speciale per solleciti
-///////////////////////////////////////////////////////////
-
-TSol_form* TSol_form::_form = NULL;
-
-void TSol_form::sol_header_handler(TPrinter& pr) {
-  TPrint_section& head = _form->section('H');
-  head.reset();
-  pr.resetheader();
-
-  head.update(); 
-  for (word j = 0; j < head.height(); j++) pr.setheaderline(j, head.row(j));
-}
-
-void TSol_form::sol_footer_handler(TPrinter& pr) {
-  TPrint_section& foot = _form->section('F');
-  pr.resetfooter();
-  
-  const word MAXTOT = 32;
-  THash_object* tot[MAXTOT];
-  
-  // i totali sono in un assoc array disordinato per cui li copio in un array e li ordino
-  // alfabeticamente in base al loro codice valuta
-  TTotalizer& totali = _form->totali();
-  totali.restart();
-  
-  word numtot = 0;
-  for (THash_object* obj = totali.get_hashobj(); numtot < MAXTOT && obj != NULL; obj = totali.get_hashobj()) tot[numtot++] = obj;
-  qsort(tot, numtot, sizeof(THash_object*), val_compare);
-  
-  if (numtot > foot.height()) numtot = foot.height();
-  
-  TPrint_section& body = _form->section('B');
-  for (word j = 0; j < numtot; j++) {                                
-    const TString& key = tot[j]->key();
-    TImporto& imp = (TImporto&)tot[j]->obj();
-    TSol_row r(key, imp.normalize());
-    r.print_on(body);
-    const TPrintrow& ri = body.row(0);
-    pr.setfooterline(j, ri);
-  }
-} 
-
-
-bool TSol_form::print_game(const TPartita& game) {
-  bool ok = FALSE;
-  
-  TSol_array righe(game, this);
-  
-  TPrinter& pr = printer();
-  TPrintrow prow;
-  
-  TPrint_section& body = section('B');
-  
-  TImporto saldo;
-  
-  // stampa le righe di partita
-  for (int r = 0; r < righe.items(); r++) {                          
-    TSol_row& riga = righe.row(r);
-    
-    if (pr.rows_left() < body.height()) pr.formfeed();
-
-    riga.print_on(body);
-    pr.print(body.row(0));
-    
-    totali().add(riga.importo(), riga.valuta().codice());
-    
-    saldo += riga.importo();
-    ok = TRUE;
-  }
-  
-  if (ok) {         
-    saldo.normalize();         
-    
-    const TForm_item& desc_sld = body.find_field(301);
-    TSol_row sld(desc_sld.prompt(), saldo);
-    sld.print_on(body);
-    
-    // salta una riga vuota
-    TPrintrow vuota;
-    pr.print(vuota);
-  }
-  return ok;
-}
-
-TSol_form::TSol_form(const TSol_mask& m, short datafld): TForm(BASE_EC_PROFILE, m.get_prof_code()), _causali(LF_CAUSALI, CAU_CODCAUS, CAU_DESCR) { 
-  _form = this;                 
-
-  _lingua = m.get_prof_lang();  
-
-  TCursor_sheet& cs = m.cur_sheet();
-  _cursore = cs.cursor();                     
-
-  _dlo = _dls = m.get(datafld); // prende il campo con la data limite sollecito
-   
-  TPrinter& pr = printer();
-  
-  pr.setheaderhandler(sol_header_handler);
-  pr.headerlen(section('H').height());
-
-  pr.setfooterhandler(sol_footer_handler);
-  pr.footerlen(section('F').height());
-}
-
-TSol_form::~TSol_form() { 
-  TPrinter& pr = printer();
-  pr.setheaderhandler(NULL);
-  pr.setfooterhandler(NULL);
-  _form = NULL;
-}
+
+#include "../cg/saldacon.h"
+#include <pagsca.h>
+#include <scadenze.h>
+#include <partite.h>
+
+#include "sc21pec.h"
+#include "sc2102.h"
+#include "sc2402.h"
+
+#include <causali.h>
+
+
+///////////////////////////////////////////////////////////
+// TSol_row
+///////////////////////////////////////////////////////////
+
+TSol_row::TSol_row(const TRiga_partite& row, const TDate& data, const TImporto& imp, int rata): _num_prot(0) {        
+  _riga     = row.get_int(PART_NRIGA); 
+  _rata     = rata;
+
+  _data     = data;              
+  _causale  = row.get(PART_CODCAUS);
+  _data_doc = row.get(PART_DATADOC);
+  _num_prot = row.get_long(PART_PROTIVA);
+  _importo  = imp;   _importo.normalize();                  
+  _totale   = row.get_real(PART_IMPTOTPAG);
+
+  _valuta.get(row);
+}
+
+TSol_row::TSol_row(const char* desc, const TImporto& imp): _num_prot(0) {
+  _descrizione = desc;
+  _importo = imp; _importo.normalize();                  
+}
+
+// le righe dell'estratto conto sono ordinate per data, riga partita, numero rata, 
+// posizione iniziale nell'array (in caso di uguaglianza di tutto il resto)
+int TSol_row::compare(const TSortable& s) const {
+  const TSol_row& r = (const TSol_row&)s;
+  int c = 0;
+  if (_data == r._data) {
+    c = r._riga - _riga;
+    if (c == 0) c = r._rata - _rata;
+  } else c = _data < r._data ? +1 : -1;
+  return c;    
+}  
+
+void TSol_row::print_on(TPrint_section& body) {                     
+  TSol_form& form = (TSol_form&)body.form();
+
+  TForm_item& causale = body.find_field(PEC_CODCAUS);
+  causale.set(_causale);
+  if (_causale.not_empty() && _descrizione.empty()) {
+    TDecoder& causali = form.causali();
+    _descrizione = causali.decode(_causale);
+  }
+  
+  TForm_item& descr = body.find_field(PEC_DESCR1);
+  descr.set(_descrizione);
+  
+  TForm_item& datadoc = body.find_field(PEC_DATADOC);
+  datadoc.set(_data_doc.string());
+  
+  TForm_item& numdoc = body.find_field(PEC_NUMDOC);
+  numdoc.set(_num_doc);
+  
+  TForm_item& numprot = body.find_field(PEC_PROTIVA);
+  TString16 protiva; protiva << _num_prot;
+  numprot.set(protiva);
+  
+  TForm_item& datapag = body.find_field(PEC_DATAPAG);
+  datapag.set(_data.string());
+  
+  const real& imp = _importo.valore();
+  TForm_item& dare  = body.find_field(PEC_DARE);
+  TForm_item& avere = body.find_field(PEC_AVERE);
+    
+  if (_importo.sezione() == 'D') {
+    dare.set(imp.string());
+    avere.set("");
+  } else {
+    avere.set(imp.string());
+    dare.set("");
+  }   
+  
+  TForm_item& scaduto = body.find_field(PEC_SCADUTO);
+  scaduto.set(_scaduto.string());
+  
+  TForm_item& cambio = body.find_field(PEC_CAMBIO);
+  cambio.set(_valuta.cambio().string());
+    
+  TForm_item& datacambio = body.find_field(PEC_DATACAM);
+  datacambio.set(_valuta.data().string());
+
+  body.update();
+}
+
+static int val_compare(const void* o1, const void* o2) { 
+  const THash_object* h1 = (const THash_object*)o1;
+  const THash_object* h2 = (const THash_object*)o2;
+  const TString& s1 = (const TString&)h1->obj();
+  const TString& s2 = (const TString&)h2->obj();
+  return s2.compare(s1, -1, TRUE);    // same as stricmp(s1, s2) in reverse order
+}
+
+
+///////////////////////////////////////////////////////////
+// TSol_array
+///////////////////////////////////////////////////////////
+
+void TSol_array::calcola_scaduto(const TRiga_scadenze& rata, real& scaduto) const {                                   
+  const TPartita& game = rata.partita();
+  TImporto imp_scaduto = rata.importo(TRUE);
+  
+  const char* const field = rata.in_valuta() ? PAGSCA_IMPORTOVAL : PAGSCA_IMPORTO;
+  TImporto imp;
+  
+  for (int p = rata.last(); p > 0; p = rata.pred(p)) {
+    const TRectype& pag = rata.row(p);
+    const TRiga_partite& sum = game.riga(pag.get_int(PAGSCA_NRIGP));
+    const tipo_movimento tm = sum.tipo();
+    if (tm != tm_insoluto && tm != tm_pagamento_insoluto) {                                                     
+      imp.set(sum.sezione(), pag.get_real(field));
+      imp_scaduto += imp;
+    }  
+  }
+  const char sezione = game.conto().tipo() == 'C' ? 'D' : 'A';
+  imp_scaduto.normalize(sezione);
+  scaduto = imp_scaduto.valore();
+}
+
+TSol_row& TSol_array::new_row(const TRiga_partite& row, const TDate& data, const TImporto& imp, int n) { 
+  if (n == 0) n = items();      
+  TSol_row* riga = new TSol_row(row, data, imp, n);
+  add(riga, n);
+  return *riga;
+}
+
+void TSol_array::add_row(const TRiga_partite& row) {
+  if (row.is_fattura()) {
+    for (int r = 1; r <= row.rate(); r++) {                                                    
+      const TRiga_scadenze& rata = row.rata(r);
+      const TDate data(rata.get(SCAD_DATASCAD));
+      if (data <= form().data_limite_operazione()) {
+        TSol_row& rec = new_row(row, data, rata.importo(TRUE), r);
+        if (data <= form().data_limite_scaduto()) {
+          real s;
+          calcola_scaduto(rata, s);
+          rec.scaduto(s);
+        }  
+      }  
+    }
+  } else {      
+    const TDate data(row.get(PART_DATAPAG));
+    if (data <= form().data_limite_operazione()) {  
+      const TImporto imp(row.importo(FALSE, 0x1));
+      new_row(row, data, imp);
+      
+      const TImporto abbuoni(row.importo(FALSE, 0x2));
+      if (!abbuoni.is_zero()) {
+        TSol_row& r = new_row(row, data, abbuoni);
+        const TForm_item& desc_abb = form().find_field('B', odd_page, 302);
+        r.descrizione(desc_abb.prompt());
+      }  
+        
+      const TImporto diffcam(row.importo(FALSE, 0x4));
+      if (!diffcam.is_zero()) {
+        TSol_row& r = new_row(row, data, diffcam);
+        const TForm_item& desc_dif = form().find_field('B', odd_page, 303);
+        r.descrizione(desc_dif.prompt());
+      }  
+    }  
+  }
+}
+
+TSol_array::TSol_array(const TPartita& game, const TSol_form* f): _form(f) { 
+  for (int r = game.last(); r > 0; r = game.pred(r)) add_row(game.riga(r));
+  sort();  
+}
+
+
+///////////////////////////////////////////////////////////
+// TSol_form: form speciale per solleciti
+///////////////////////////////////////////////////////////
+
+TSol_form* TSol_form::_form = NULL;
+
+void TSol_form::sol_header_handler(TPrinter& pr) {
+  TPrint_section& head = _form->section('H');
+  head.reset();
+  pr.resetheader();
+
+  head.update(); 
+  for (word j = 0; j < head.height(); j++) pr.setheaderline(j, head.row(j));
+}
+
+void TSol_form::sol_footer_handler(TPrinter& pr) {
+  TPrint_section& foot = _form->section('F');
+  pr.resetfooter();
+  
+  const word MAXTOT = 32;
+  THash_object* tot[MAXTOT];
+  
+  // i totali sono in un assoc array disordinato per cui li copio in un array e li ordino
+  // alfabeticamente in base al loro codice valuta
+  TTotalizer& totali = _form->totali();
+  totali.restart();
+  
+  word numtot = 0;
+  for (THash_object* obj = totali.get_hashobj(); numtot < MAXTOT && obj != NULL; obj = totali.get_hashobj()) tot[numtot++] = obj;
+  qsort(tot, numtot, sizeof(THash_object*), val_compare);
+  
+  if (numtot > foot.height()) numtot = foot.height();
+  
+  TPrint_section& body = _form->section('B');
+  for (word j = 0; j < numtot; j++) {                                
+    const TString& key = tot[j]->key();
+    TImporto& imp = (TImporto&)tot[j]->obj();
+    TSol_row r(key, imp.normalize());
+    r.print_on(body);
+    const TPrintrow& ri = body.row(0);
+    pr.setfooterline(j, ri);
+  }
+} 
+
+
+bool TSol_form::print_game(const TPartita& game) 
+{
+  bool ok = FALSE;
+  
+  TSol_array righe(game, this);
+  
+  TPrinter& pr = printer();
+  TPrintrow prow;
+  
+  TPrint_section& body = section('B');
+  
+  TImporto saldo;
+  
+  // stampa le righe di partita
+  for (int r = 0; r < righe.items(); r++) 
+  {                          
+    TSol_row& riga = righe.row(r);
+    
+    if (pr.rows_left() < body.height()) 
+      pr.formfeed();
+
+    riga.print_on(body);
+    pr.print(body.row(0));
+    
+    totali().add(riga.importo(), ZERO, ZERO, riga.valuta().codice());
+    
+    saldo += riga.importo();
+    ok = TRUE;
+  }
+  
+  if (ok) {         
+    saldo.normalize();         
+    
+    const TForm_item& desc_sld = body.find_field(301);
+    TSol_row sld(desc_sld.prompt(), saldo);
+    sld.print_on(body);
+    
+    // salta una riga vuota
+    TPrintrow vuota;
+    pr.print(vuota);
+  }
+  return ok;
+}
+
+TSol_form::TSol_form(const TSol_mask& m, short datafld): TForm(BASE_EC_PROFILE, m.get_prof_code()), _causali(LF_CAUSALI, CAU_CODCAUS, CAU_DESCR) { 
+  _form = this;                 
+
+  _lingua = m.get_prof_lang();  
+
+  TCursor_sheet& cs = m.cur_sheet();
+  _cursore = cs.cursor();                     
+
+  _dlo = _dls = m.get(datafld); // prende il campo con la data limite sollecito
+   
+  TPrinter& pr = printer();
+  
+  pr.setheaderhandler(sol_header_handler);
+  pr.headerlen(section('H').height());
+
+  pr.setfooterhandler(sol_footer_handler);
+  pr.footerlen(section('F').height());
+}
+
+TSol_form::~TSol_form() { 
+  TPrinter& pr = printer();
+  pr.setheaderhandler(NULL);
+  pr.setfooterhandler(NULL);
+  _form = NULL;
+}