Files correlati : lv4.exe Ricompilazione Demo : [ ] Commento : Aggiunta creazione file ini per le fatture in sospensione aperte git-svn-id: svn://10.65.10.50/trunk@20081 c028cbd2-c16b-5b4b-a496-9718f37d4682
		
			
				
	
	
		
			856 lines
		
	
	
		
			26 KiB
		
	
	
	
		
			C++
		
	
	
		
			Executable File
		
	
	
	
	
			
		
		
	
	
			856 lines
		
	
	
		
			26 KiB
		
	
	
	
		
			C++
		
	
	
		
			Executable File
		
	
	
	
	
#include <applicat.h>
 | 
						|
#include <automask.h>
 | 
						|
#include <execp.h>
 | 
						|
#include <progind.h>
 | 
						|
#include <relation.h>
 | 
						|
#include <reputils.h>
 | 
						|
#include <utility.h>
 | 
						|
 | 
						|
#include "../cg/cglib01.h"
 | 
						|
#include "../cg/cg2103.h"
 | 
						|
#include "../cg/cgsaldac.h"
 | 
						|
 | 
						|
#include "lv4.h"
 | 
						|
#include "lv4100.h"
 | 
						|
#include "lv4200a.h"
 | 
						|
 | 
						|
#include <causali.h>
 | 
						|
#include <rcausali.h>
 | 
						|
#include <clifo.h>
 | 
						|
#include <pconti.h>
 | 
						|
#include <mov.h>
 | 
						|
#include <rmov.h>
 | 
						|
#include <rmoviva.h>
 | 
						|
 | 
						|
enum CGC_SALDAC { CGC_NULL,      CGC_TIPOCF,  CGC_ANNO,       CGC_NUMPART, CGC_CODCF,
 | 
						|
                  CGC_NUMEROREC, CGC_CAMBIO,  CGC_VALUTA,     CGC_TIPODOC, CGC_DATADOC,
 | 
						|
                  CGC_SCADENZA,  CGC_IMPORTO,	CGC_IMPORTO_VAL,CGC_NUMDOC };
 | 
						|
 | 
						|
class TCausali_cache : public TCache
 | 
						|
{
 | 
						|
  TString4 _cln, _frn;
 | 
						|
 | 
						|
protected:
 | 
						|
  virtual TObject* key2obj(const char* key);
 | 
						|
 | 
						|
public:
 | 
						|
  const TCausale& causale(char tipocf, tipo_movimento tm);
 | 
						|
  void init(const char* cln, const char* frn) { _cln = cln; _frn = frn; }
 | 
						|
};
 | 
						|
 | 
						|
TObject* TCausali_cache::key2obj(const char* key)
 | 
						|
{
 | 
						|
  const char tipocf = key[0];
 | 
						|
  const tipo_movimento tm = tipo_movimento(key[1]-'0');
 | 
						|
 | 
						|
  TString4 codcaus;
 | 
						|
  if (tm == tm_fattura)
 | 
						|
    codcaus = tipocf == 'F' ? _frn : _cln;
 | 
						|
  if (codcaus.blank())
 | 
						|
  {
 | 
						|
    TString query;
 | 
						|
    query << "USE CAUS\nSELECT (TIPOMOV='" << tm << "')&&(RCAUS->TIPOCF='" << tipocf << "')"
 | 
						|
          << "\nJOIN RCAUS INTO CODCAUS=CODCAUS NRIGA=1";
 | 
						|
    TISAM_recordset caus(query);
 | 
						|
    if (caus.move_first())
 | 
						|
      codcaus = caus.get(CAU_CODCAUS).as_string();
 | 
						|
  }
 | 
						|
  TCausale* pcaus = new TCausale(codcaus);
 | 
						|
  return pcaus;
 | 
						|
}
 | 
						|
 | 
						|
const TCausale& TCausali_cache::causale(const char tipocf, tipo_movimento tm)
 | 
						|
{
 | 
						|
  // Metodo bastardo per evitare TToken_string temporanee "a randa"
 | 
						|
  // creo chiave a lunghezza fissa TIPOCF+TIPOMOV+ANNO = C12010
 | 
						|
  const char key[4] = { tipocf, '0'+tm, '\0' };
 | 
						|
  return *(const TCausale*)objptr(key);
 | 
						|
}
 | 
						|
 | 
						|
///////////////////////////////////////////////////////////
 | 
						|
// TAutomask
 | 
						|
///////////////////////////////////////////////////////////
 | 
						|
 | 
						|
class TImporta_sc_mask : public TAutomask
 | 
						|
{
 | 
						|
protected:
 | 
						|
  virtual bool on_field_event(TOperable_field& o, TField_event e, long jolly);
 | 
						|
 | 
						|
public:
 | 
						|
  TImporta_sc_mask();
 | 
						|
};
 | 
						|
  
 | 
						|
TImporta_sc_mask::TImporta_sc_mask() :TAutomask ("lv4200a")
 | 
						|
{
 | 
						|
}  
 | 
						|
 | 
						|
bool TImporta_sc_mask::on_field_event(TOperable_field& f, TField_event e, long jolly)
 | 
						|
{ 
 | 
						|
	switch (f.dlg())
 | 
						|
	{
 | 
						|
	//giochetto per avere la lista dei files validi nella directory di trasferimento!
 | 
						|
	case F_NAME:
 | 
						|
		if (e == fe_button)
 | 
						|
		{
 | 
						|
			TArray_sheet as(-1, -1, 72, 20, TR("Selezione file"), "File@32");
 | 
						|
			TFilename path = get(F_PATH);
 | 
						|
			path.add("*.txt");	//file da importare
 | 
						|
			list_files(path, as.rows_array());
 | 
						|
			TFilename name;
 | 
						|
			FOR_EACH_ARRAY_ROW(as.rows_array(), i, row)
 | 
						|
			{
 | 
						|
				name = *row;
 | 
						|
				*row = name.name();
 | 
						|
			}
 | 
						|
			if (as.run() == K_ENTER)
 | 
						|
				f.set(as.row(as.selected()));
 | 
						|
		}
 | 
						|
		break;
 | 
						|
	default:
 | 
						|
		break;
 | 
						|
	}
 | 
						|
  return true;
 | 
						|
}
 | 
						|
 | 
						|
///////////////////////////////////////
 | 
						|
// TSkeleton_application
 | 
						|
///////////////////////////////////////
 | 
						|
class TImporta_sc : public TSkeleton_application
 | 
						|
{
 | 
						|
	TImporta_sc_mask*	_msk;
 | 
						|
	
 | 
						|
  TCausali_cache _cache_causali;
 | 
						|
  TBill _clienti, _fornitori;
 | 
						|
	int _fattsosp;
 | 
						|
 | 
						|
private:
 | 
						|
  void nuovo_pagamento_o_nota(const TImporta_cogeco_recset& recset, TPartita& game, tipo_movimento tm, bool is_riba);
 | 
						|
  bool paga_rata(TPartita& game, int nrata, int nrigp, real& importo) const;
 | 
						|
  void set_descr(TRectype& rec) const;
 | 
						|
 | 
						|
protected:
 | 
						|
  bool log_error(TLog_report& log, const char* msg, const TRecordset& recset);
 | 
						|
  const TCausale& causale(char tipocf, tipo_movimento tm);
 | 
						|
  char get_tmcf(int gruppo, int conto) const;
 | 
						|
  bool find_clifo_bill(char tipocf, int& gruppo, int& conto, long sottoconto);
 | 
						|
 | 
						|
  TRiga_partite& nuova_fattura(const TImporta_cogeco_recset& recset, TPartita& game);
 | 
						|
	long fattura_in_sospensione(const TImporta_cogeco_recset& recset, const TRiga_partite& rigafat, long nmov);
 | 
						|
  void nuova_scadenza(const TImporta_cogeco_recset& recset, TPartita& game, bool is_riba);
 | 
						|
  void nuova_riba(const TImporta_cogeco_recset& recset, TPartita& game);
 | 
						|
  void nuovo_pagamento(const TImporta_cogeco_recset& recset, TPartita& game);
 | 
						|
  void nuova_nota_credito(const TImporta_cogeco_recset& recset, TPartita& game);
 | 
						|
  bool nuovo_insoluto(const TImporta_cogeco_recset& recset, TPartita& game, TLog_report& log);
 | 
						|
  void salva_partita(TPartita*& game, long nmov);
 | 
						|
 | 
						|
public:           
 | 
						|
  virtual bool create();
 | 
						|
  virtual bool destroy();
 | 
						|
  virtual void main_loop();
 | 
						|
	void transfer(const TFilename& file);
 | 
						|
};
 | 
						|
 | 
						|
// Cerca una causale appropriata in base a TIPOCF (C o F) e TIPOMOV (1, 2, 3, ...)
 | 
						|
const TCausale& TImporta_sc::causale(char tipocf, tipo_movimento tm)
 | 
						|
{ return _cache_causali.causale(tipocf, tm); }
 | 
						|
 | 
						|
// Ricava il campo TMCF (Cliente o Fornitore) di un dato conto
 | 
						|
char TImporta_sc::get_tmcf(int gruppo, int conto) const
 | 
						|
{
 | 
						|
  char tmcf = ' ';
 | 
						|
  if (gruppo > 0 && conto > 0)
 | 
						|
  {
 | 
						|
    TString8 key; key.format("%d|%d", gruppo, conto);
 | 
						|
    const TRectype& pcon = cache().get(LF_PCON, key);
 | 
						|
    tmcf = pcon.get_char(PCN_TMCF);
 | 
						|
  }
 | 
						|
  return tmcf;
 | 
						|
}
 | 
						|
 | 
						|
// Trova il conto cliente di una certa anagrafica
 | 
						|
bool TImporta_sc::find_clifo_bill(char tipocf, int& gruppo, int& conto, long sottoconto)
 | 
						|
{
 | 
						|
  bool found = false;
 | 
						|
  
 | 
						|
  TString8 key;
 | 
						|
  gruppo = conto = 0;
 | 
						|
  
 | 
						|
  // Prima lo cerca sull'anagrafica stessa
 | 
						|
  key.format("%c|%ld", tipocf, sottoconto);
 | 
						|
  const TRectype& clifo = cache().get(LF_CLIFO, key);
 | 
						|
  gruppo = clifo.get_int(CLI_GRUPPO);
 | 
						|
  conto = clifo.get_int(CLI_CONTO);
 | 
						|
 | 
						|
  // Controlla che il conto esista
 | 
						|
  found = get_tmcf(gruppo, conto) == tipocf;
 | 
						|
 | 
						|
  if (!found)
 | 
						|
  {
 | 
						|
    // Cerca sulla prima riga dellla causale
 | 
						|
    const TCausale& caus = causale(tipocf, tm_fattura);
 | 
						|
    TBill bill; caus.bill(1, bill);
 | 
						|
		gruppo = bill.gruppo();
 | 
						|
		conto = bill.conto();
 | 
						|
    found = get_tmcf(gruppo, conto) == tipocf;
 | 
						|
  }
 | 
						|
 | 
						|
  if (!found)
 | 
						|
  {
 | 
						|
    // Usa un conto C/F trovato preventivamente in fase di inizializzazione
 | 
						|
    if (tipocf == 'C')
 | 
						|
    {
 | 
						|
      gruppo = _clienti.gruppo();
 | 
						|
      conto = _clienti.conto();
 | 
						|
    }
 | 
						|
    else
 | 
						|
    {
 | 
						|
      gruppo = _fornitori.gruppo();
 | 
						|
      conto = _fornitori.conto();
 | 
						|
    }
 | 
						|
    found = gruppo > 0 && conto > 0;
 | 
						|
  }
 | 
						|
 | 
						|
  return found;
 | 
						|
}
 | 
						|
 | 
						|
void TImporta_sc::set_descr(TRectype& rec) const
 | 
						|
{
 | 
						|
  TString descr;
 | 
						|
  descr << "*** ";
 | 
						|
  switch (rec.num())
 | 
						|
  {
 | 
						|
  case LF_SCADENZE:
 | 
						|
    descr << TR("Rata") << ' ' << rec.get(SCAD_NRATA);
 | 
						|
    rec.put(SCAD_DESCR, descr);
 | 
						|
    break;
 | 
						|
  case LF_PARTITE:
 | 
						|
    switch (tipo_movimento(rec.get_int(PART_TIPOMOV)))
 | 
						|
    {
 | 
						|
    case tm_fattura     : descr << TR("Fattura") << ' ' 
 | 
						|
                                << rec.get(PART_ANNO) << '/' <<  rec.get(PART_NUMDOC); break;
 | 
						|
    case tm_nota_credito: descr << TR("Nota di credito")
 | 
						|
                                << rec.get(PART_ANNO) << '/' <<  rec.get(PART_NUMDOC); break;
 | 
						|
    case tm_insoluto    : descr << TR("Insoluto"); break;
 | 
						|
    default             : descr << TR("Pagamento"); break;
 | 
						|
    }
 | 
						|
    rec.put(PART_DESCR, descr);
 | 
						|
    break;
 | 
						|
  default:
 | 
						|
    break;
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
// Aggiunge una nuova riga fattura a 'game' in base ai dati in 'recset'
 | 
						|
TRiga_partite& TImporta_sc::nuova_fattura(const TImporta_cogeco_recset& recset, TPartita& game)
 | 
						|
{
 | 
						|
  int nriga = game.prima_fattura();
 | 
						|
  if (game.prima_fattura() <= 0)
 | 
						|
  {
 | 
						|
		TRiga_partite& fattura = game.new_row();
 | 
						|
 | 
						|
    const TDate datadoc = recset.get_date(CGC_DATADOC);
 | 
						|
		fattura.put(PART_DATAREG, datadoc); 
 | 
						|
		fattura.put(PART_DATADOC, datadoc);
 | 
						|
    const long numdoc = recset.get(CGC_NUMDOC).as_int();
 | 
						|
    if (numdoc > 0)
 | 
						|
     fattura.put(PART_NUMDOC, numdoc);
 | 
						|
 | 
						|
    const char tipocf = game.conto().tipo();
 | 
						|
    const TCausale& caus = causale(tipocf, tm_fattura);
 | 
						|
    if (caus.ok())
 | 
						|
    {
 | 
						|
  		fattura.put(PART_CODCAUS, caus.codice());
 | 
						|
	  	fattura.put(PART_REG, caus.reg().name());
 | 
						|
      fattura.put(PART_TIPOMOV, caus.tipomov());
 | 
						|
  		fattura.put(PART_SEZ, caus.sezione(1));
 | 
						|
    }
 | 
						|
    else
 | 
						|
    {
 | 
						|
      fattura.put(PART_TIPOMOV, tm_fattura);
 | 
						|
      fattura.put(PART_SEZ, tipocf == 'C' ? 'D' : 'A');
 | 
						|
    }
 | 
						|
    set_descr(fattura);
 | 
						|
 | 
						|
    nriga = fattura.get_int(PART_NRIGA);
 | 
						|
  }
 | 
						|
 | 
						|
  TRiga_partite& fattura = game.riga(nriga);
 | 
						|
  const real importo = recset.get_real(CGC_IMPORTO);
 | 
						|
 | 
						|
  fattura.add(PART_IMPTOTDOC, importo);
 | 
						|
  fattura.add(PART_IMPORTO, importo);
 | 
						|
 | 
						|
  return fattura;
 | 
						|
}
 | 
						|
 | 
						|
long TImporta_sc::fattura_in_sospensione(const TImporta_cogeco_recset& recset, const TRiga_partite& rigafat, long nmov)
 | 
						|
{
 | 
						|
	TFilename temp(_msk->get(F_PATHOUT));
 | 
						|
 | 
						|
	temp << '/' << format("%05ld", nmov++);
 | 
						|
	temp.ext("ini");
 | 
						|
	if (fexist(temp))
 | 
						|
		remove_file(temp);
 | 
						|
	TConfig	conf(temp);
 | 
						|
	
 | 
						|
	conf.set_paragraph("Transaction"); //setto il paragrafo [Transaction] del file ini
 | 
						|
	conf.set("Action","INSERT");
 | 
						|
	conf.set("Mode","AUTO");
 | 
						|
 | 
						|
	conf.set_paragraph("23"); //setto il paragrafo [23] del file ini (testata)
 | 
						|
	conf.set(MOV_CODCAUS, rigafat.get(PART_CODCAUS));
 | 
						|
	TDate datareg = rigafat.get_date(PART_DATAREG);
 | 
						|
 | 
						|
	if (esercizi().date2esc(datareg) == 0)
 | 
						|
		datareg = esercizi().esercizio(esercizi().first()).inizio();
 | 
						|
	conf.set(MOV_DATAREG, datareg);
 | 
						|
	TDate datadoc = rigafat.get_date(PART_DATADOC);
 | 
						|
 | 
						|
	if (!datadoc.ok())
 | 
						|
		datadoc = esercizi().esercizio(esercizi().first()).inizio();
 | 
						|
	conf.set(MOV_DATADOC, datadoc);
 | 
						|
	TString16 numdoc = rigafat.get(PART_NUMDOC);
 | 
						|
 | 
						|
	if (numdoc.blank())
 | 
						|
		numdoc = "1";
 | 
						|
	conf.set(MOV_NUMDOC, numdoc);
 | 
						|
	conf.set("SOLAIVA", "X");
 | 
						|
	conf.set(MOV_STAMPATO, "X");
 | 
						|
	conf.set(MOV_REGST, "X");
 | 
						|
	conf.set(MOV_LIQDIFF, "X");
 | 
						|
	conf.set(MOV_DESCR, rigafat.get(PART_DESCR));
 | 
						|
	conf.set(MOV_TIPO, rigafat.get(PART_TIPOCF));  
 | 
						|
	conf.set(MOV_CODCF, rigafat.get(PART_SOTTOCONTO));
 | 
						|
	conf.set(MOV_TOTDOC, rigafat.get(PART_IMPTOTDOC));
 | 
						|
	conf.set("CODIVA", _msk->get(F_CODIVA));
 | 
						|
	_fattsosp++;
 | 
						|
 | 
						|
	return nmov;
 | 
						|
}
 | 
						|
 | 
						|
// Aggiunge una nuova rata alla UNICA fattura di 'game'.
 | 
						|
// Attenzione: in assenza di fattura ne viene creata una "al volo" di pari importo.
 | 
						|
void TImporta_sc::nuova_scadenza(const TImporta_cogeco_recset& recset, TPartita& game, bool is_riba)
 | 
						|
{
 | 
						|
  int nriga = game.prima_fattura(); // PART_NRIGA della fattura (solitamente = 1)
 | 
						|
  if (nriga <= 0) // Se non ci sono fattura in questa partita ...
 | 
						|
  {
 | 
						|
    nuova_fattura(recset, game);  // Creo una nuova fattura
 | 
						|
    nriga = game.prima_fattura(); // Aggiorno PART_NRIGA che valeva -1
 | 
						|
  }
 | 
						|
  TRiga_partite& fattura = game.riga(nriga);    // Accedo alla riga di fattura, che ora DEVE esistere!
 | 
						|
 | 
						|
  // Se la scadenza coincide o precede l'ultima, non creo una rata nuova
 | 
						|
  const TDate datascad = recset.get_date(CGC_SCADENZA);
 | 
						|
  int nrata = fattura.rate();
 | 
						|
  if (nrata > 0)
 | 
						|
  {
 | 
						|
    const TRiga_scadenze& rata = fattura.rata(nrata);
 | 
						|
    if (datascad > rata.get_date(SCAD_DATASCAD))
 | 
						|
      nrata = 0; // Devo creare una rata nuova
 | 
						|
  }
 | 
						|
  if (nrata <= 0)
 | 
						|
  {
 | 
						|
  	TRiga_scadenze& scadenza = fattura.new_row(); // Creo nuova rata, alla faccia di SCAD_CODPAG
 | 
						|
    nrata = scadenza.get_int(SCAD_NRATA);         // valeva 0 
 | 
						|
    scadenza.put(SCAD_DATASCAD, recset.get_date(CGC_SCADENZA));
 | 
						|
    scadenza.put(SCAD_TIPOPAG, is_riba ? 3 : 1);
 | 
						|
    set_descr(scadenza);
 | 
						|
  }
 | 
						|
 | 
						|
  TRiga_scadenze& scadenza = fattura.rata(nrata);
 | 
						|
  const real importo = recset.get_real(CGC_IMPORTO);
 | 
						|
  scadenza.add(SCAD_IMPORTO, importo);
 | 
						|
}
 | 
						|
 | 
						|
bool TImporta_sc::paga_rata(TPartita& game, int nrata, int nrigp, real& importo) const
 | 
						|
{
 | 
						|
  const int nriga = game.prima_fattura();
 | 
						|
  if (nriga > 0)
 | 
						|
  {
 | 
						|
    const TRiga_partite& fattura = game.riga(nriga);
 | 
						|
    TRiga_scadenze& scadenza = fattura.rata(nrata);
 | 
						|
    const real residuo = scadenza.residuo(false).valore();
 | 
						|
    if (!residuo.is_zero()) // Considera solo rate aperte
 | 
						|
    {
 | 
						|
      // Elenco dei campi chiave da riportare dalla rata al pagamento
 | 
						|
      const char* const field[] = { PAGSCA_TIPOC, PAGSCA_SOTTOCONTO, PAGSCA_ANNO, PAGSCA_NUMPART, 
 | 
						|
                                    PAGSCA_NRIGA, PAGSCA_NRATA, NULL };
 | 
						|
      const real pagare = residuo > importo ? importo : residuo; // Importo da pagare sulla rata
 | 
						|
      TRectype rpag(LF_PAGSCA);
 | 
						|
      for (int k = 0; field[k]; k++)
 | 
						|
        rpag.put(field[k], scadenza.get(field[k]));
 | 
						|
      rpag.put(PAGSCA_NRIGP, nrigp); // Completa la chiave di PAGSCA col numero riga di partita
 | 
						|
      rpag.put(PAGSCA_IMPORTO, pagare);
 | 
						|
      rpag.put(PAGSCA_ACCSAL, pagare >= residuo ? 'S' : 'A');
 | 
						|
      const TValuta euro;
 | 
						|
      game.modifica_pagamento(rpag, euro, true); // Speriamo che faccia tutto lei :-)
 | 
						|
      importo -= pagare;
 | 
						|
      return true;
 | 
						|
    }
 | 
						|
  }
 | 
						|
  return false;
 | 
						|
}
 | 
						|
 | 
						|
// Aggiunge una nuova riga tipo 2 (n.c.) o 3 (pag.) alla partita
 | 
						|
void TImporta_sc::nuovo_pagamento_o_nota(const TImporta_cogeco_recset& recset, TPartita& game, tipo_movimento tm, bool is_riba)
 | 
						|
{
 | 
						|
  // Crea una nuova riga di partita
 | 
						|
  TRiga_partite& pagamento = game.new_row();
 | 
						|
  const int nrigp = pagamento.get_int(PART_NRIGA); // Ricorda numero da mettere in PAGSCA_NRIGP
 | 
						|
 | 
						|
  const TDate datadoc = recset.get_date(CGC_DATADOC);
 | 
						|
	pagamento.put(PART_DATAREG, datadoc); 
 | 
						|
	pagamento.put(PART_DATADOC, datadoc);
 | 
						|
  if (tm == tm_nota_credito)
 | 
						|
  {
 | 
						|
    const long numdoc = recset.get(CGC_NUMDOC).as_int();
 | 
						|
    if (numdoc > 0)
 | 
						|
      pagamento.put(PART_NUMDOC, numdoc);
 | 
						|
  }
 | 
						|
  else
 | 
						|
    pagamento.put(PART_DATAPAG, datadoc);
 | 
						|
 | 
						|
  // Cerca di inizlizzare la riga con una causale appropriata
 | 
						|
  const char tipocf = game.conto().tipo();
 | 
						|
  const TCausale& caus = causale(tipocf, tm);
 | 
						|
  if (caus.ok())
 | 
						|
  {
 | 
						|
		pagamento.put(PART_CODCAUS, caus.codice());
 | 
						|
  	pagamento.put(PART_REG, caus.reg().name());
 | 
						|
    pagamento.put(PART_TIPOMOV, caus.tipomov());
 | 
						|
		pagamento.put(PART_SEZ, caus.sezione(1));
 | 
						|
  }
 | 
						|
  else
 | 
						|
  {
 | 
						|
    pagamento.put(PART_TIPOMOV, tm);
 | 
						|
    pagamento.put(PART_SEZ, tipocf == 'F' ? 'D' : 'A');
 | 
						|
  }
 | 
						|
  set_descr(pagamento); // Ora sono certo del TIPOMOV e posso generare la descrizione
 | 
						|
 | 
						|
  // Somma da distribuire sulle rate aperte
 | 
						|
  real importo = recset.get_real(CGC_IMPORTO);
 | 
						|
  pagamento.put(PART_IMPTOTDOC, importo);
 | 
						|
 | 
						|
  // Se esiste una fattura cerca di saldare il residuo delle rate aperte
 | 
						|
  const int nriga = game.prima_fattura();
 | 
						|
  if (nriga > 0)
 | 
						|
  {
 | 
						|
    const TRiga_partite& fattura = game.riga(nriga);
 | 
						|
    
 | 
						|
    // Si assicura che la sezione sia inversa rispetto alla fattura
 | 
						|
    pagamento.put(PART_SEZ, fattura.sezione() == 'D' ? 'A' : 'D'); 
 | 
						|
 | 
						|
    while (true)
 | 
						|
    {
 | 
						|
      int best_rata = 0, best_score = 0;
 | 
						|
      for (int nrata = 1; nrata <= fattura.rate() && !importo.is_zero(); nrata++)
 | 
						|
      {
 | 
						|
        const TRiga_scadenze& rata = fattura.rata(nrata);
 | 
						|
        const real residuo = rata.residuo(false).valore();
 | 
						|
				if (!residuo.is_zero())
 | 
						|
				{
 | 
						|
					const TDate data_scad = rata.get(SCAD_DATASCAD);
 | 
						|
					int score = data_scad == datadoc ? 2 : 0;
 | 
						|
					if (score == 0 && datadoc == data_scad+1L)
 | 
						|
						score++;
 | 
						|
					if (residuo >= importo)
 | 
						|
					{
 | 
						|
						score++;
 | 
						|
						if (residuo == importo)
 | 
						|
							score++;
 | 
						|
					}
 | 
						|
					if (score > best_score)
 | 
						|
					{
 | 
						|
						best_rata = nrata;
 | 
						|
						best_score = score;
 | 
						|
					}
 | 
						|
				}
 | 
						|
      }
 | 
						|
      if (best_rata > 0)
 | 
						|
      {
 | 
						|
        if (is_riba)
 | 
						|
        {
 | 
						|
          const TRiga_scadenze& rata = fattura.rata(best_rata);
 | 
						|
          if (rata.get_int(SCAD_TIPOPAG) == 3) // Per le RIBA precisa la data pagamento
 | 
						|
            pagamento.put(PART_DATAPAG, rata.get(SCAD_DATASCAD));
 | 
						|
        }
 | 
						|
        paga_rata(game, best_rata, nrigp, importo);
 | 
						|
      }
 | 
						|
      else
 | 
						|
        break;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  // Se ci rimane qualcosa o non e' stata trovata una rata aperta allora crea un pagamento non assegnato
 | 
						|
  if (!importo.is_zero())
 | 
						|
  {
 | 
						|
    TRectype rpag(LF_PAGSCA);
 | 
						|
    const char* const field[] = { PAGSCA_TIPOC, PAGSCA_SOTTOCONTO, PAGSCA_ANNO, PAGSCA_NUMPART, NULL };
 | 
						|
    for (int k = 0; field[k]; k++)
 | 
						|
      rpag.put(field[k], pagamento.get(field[k]));
 | 
						|
    rpag.put(PAGSCA_NRIGA, 9999);  // Questo 9999 significa "fattura ignota"
 | 
						|
    rpag.put(PAGSCA_NRATA, 9999);  // Questo 9999 significa "rata ignota"
 | 
						|
    rpag.put(PAGSCA_NRIGP, nrigp); // Completa la chiave di PAGSCA col numero riga di partita
 | 
						|
    rpag.put(PAGSCA_IMPORTO, importo);
 | 
						|
    rpag.put(PAGSCA_ACCSAL, 'A');  // Gli ancticipi sono sempre in acconto :-)
 | 
						|
    const TValuta euro;
 | 
						|
    game.modifica_pagamento(rpag, euro, true);
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
void TImporta_sc::nuova_riba(const TImporta_cogeco_recset& recset, TPartita& game)
 | 
						|
{
 | 
						|
  nuova_scadenza(recset, game, true);
 | 
						|
  if (game.conto().tipo() == 'C') // Le riba cliente vengono considerate pagate subito!
 | 
						|
    nuovo_pagamento_o_nota(recset, game, tm_pagamento, true);
 | 
						|
}
 | 
						|
 | 
						|
// Creo una nuova riga partita corrispondente ad una riga pagamento in PAGSCA
 | 
						|
void TImporta_sc::nuovo_pagamento(const TImporta_cogeco_recset& recset, TPartita& game)
 | 
						|
{ nuovo_pagamento_o_nota(recset, game, tm_pagamento, false); }
 | 
						|
 | 
						|
// Creo una nuova riga partita corrispondente ad una riga nota di credito in PAGSCA
 | 
						|
void TImporta_sc::nuova_nota_credito(const TImporta_cogeco_recset& recset, TPartita& game)
 | 
						|
{ nuovo_pagamento_o_nota(recset, game, tm_nota_credito, false); }
 | 
						|
 | 
						|
// Creo una nuova riga partita corrispondente ad una riga di insoluto PAGSCA
 | 
						|
bool TImporta_sc::nuovo_insoluto(const TImporta_cogeco_recset& recset, TPartita& game, TLog_report& log)
 | 
						|
{
 | 
						|
  const int nriga = game.prima_fattura();  // Cerco la fattura insoluta
 | 
						|
  if (nriga <= 0)     // Non e' carino creare un insoluto non assegnato
 | 
						|
    return log_error(log, TR("Impossibile associare insoluto"), recset);
 | 
						|
 | 
						|
  const TDate datadoc = recset.get_date(CGC_DATADOC);
 | 
						|
  real importo = recset.get_real(CGC_IMPORTO);
 | 
						|
 | 
						|
  // Cerca la miglior rata possibile da mandare insoluta
 | 
						|
  // Per fare cio', si assegna un punteggio ad ogni rata, basato sulla data e sull'importo
 | 
						|
  int best_rata = 0, best_score = 0;
 | 
						|
  const TRiga_partite& fattura = game.riga(nriga);
 | 
						|
  for (int nrata = fattura.rate(); nrata > 0; nrata--)
 | 
						|
  {
 | 
						|
    const TRiga_scadenze& scadenza = fattura.rata(nrata);
 | 
						|
		const real imp = scadenza.importo_pagato(false).valore();
 | 
						|
		if (!imp.is_zero())
 | 
						|
		{
 | 
						|
			const TDate data = scadenza.get(SCAD_DATASCAD);
 | 
						|
			int score = datadoc == data ? 2 : 0;
 | 
						|
			if (score == 0 && datadoc == data+1L)
 | 
						|
				 score++;
 | 
						|
			if (imp >= importo)
 | 
						|
			{
 | 
						|
				score++;
 | 
						|
				if (imp == importo)
 | 
						|
					score++;
 | 
						|
			}
 | 
						|
			if (score > best_score)
 | 
						|
			{
 | 
						|
				best_rata = nrata;
 | 
						|
				best_score = score;
 | 
						|
			}
 | 
						|
		}
 | 
						|
  }
 | 
						|
 | 
						|
  if (best_rata > 0) // Se ho trovato almeno una rata compatibile con l'insoluto...
 | 
						|
  {
 | 
						|
    const TRiga_scadenze& scadenza = fattura.rata(best_rata);
 | 
						|
    TRiga_partite& insoluto = game.new_row();
 | 
						|
    const int nrigp = insoluto.get_int(PART_NRIGA);
 | 
						|
 | 
						|
  	insoluto.put(PART_DATAREG, datadoc); 
 | 
						|
  	insoluto.put(PART_DATADOC, datadoc);
 | 
						|
    insoluto.put(PART_IMPTOTDOC, importo); 
 | 
						|
 | 
						|
    const char tipocf = game.conto().tipo();
 | 
						|
    const TCausale& caus = causale(tipocf, tm_insoluto);
 | 
						|
    if (caus.ok())
 | 
						|
    {
 | 
						|
      insoluto.put(PART_CODCAUS, caus.codice());
 | 
						|
    	insoluto.put(PART_REG, caus.reg().name());
 | 
						|
      insoluto.put(PART_TIPOMOV, caus.tipomov());
 | 
						|
  		insoluto.put(PART_SEZ, caus.sezione(1));
 | 
						|
    }
 | 
						|
    else
 | 
						|
    {
 | 
						|
      insoluto.put(PART_TIPOMOV, tm_insoluto);
 | 
						|
      insoluto.put(PART_SEZ, fattura.sezione());
 | 
						|
    }
 | 
						|
    set_descr(insoluto);
 | 
						|
    paga_rata(game, best_rata, nrigp, importo);
 | 
						|
  }
 | 
						|
  else
 | 
						|
    log_error(log, TR("Impossibile associare insoluto"), recset);
 | 
						|
  
 | 
						|
  return best_rata > 0;
 | 
						|
}
 | 
						|
 | 
						|
bool TImporta_sc::log_error(TLog_report& log, const char* msg, const TRecordset& recset)
 | 
						|
{
 | 
						|
  TString message;
 | 
						|
  message << recset.get(CGC_TIPOCF) << recset.get(CGC_CODCF) << '-' 
 | 
						|
          << recset.get(CGC_ANNO) << '/' << recset.get(CGC_NUMPART) 
 | 
						|
          << '.' << recset.get(CGC_NUMEROREC) << " : " << msg;
 | 
						|
  log.log(2, message);
 | 
						|
  return false;
 | 
						|
}
 | 
						|
 | 
						|
// Ordina le righe di partita per TIPOCF+CODCF+ANNO+NUMPART+SCADENZA+TIPODOC
 | 
						|
static int game_sorter(const TObject** o1, const TObject** o2)
 | 
						|
{
 | 
						|
  TToken_string& r1 = *(TToken_string*)*o1;
 | 
						|
  TToken_string& r2 = *(TToken_string*)*o2;
 | 
						|
 | 
						|
  if (r1.get_int(0) != 1)
 | 
						|
    return -1; // Riga testata!
 | 
						|
  if (r2.get_int(0) != 1)
 | 
						|
    return +1; // Riga testata!
 | 
						|
 | 
						|
  const char tipocf1 = r1.get_char(CGC_TIPOCF);
 | 
						|
  const char tipocf2 = r2.get_char(CGC_TIPOCF);
 | 
						|
  int cmp = tipocf1 - tipocf2;
 | 
						|
  if (cmp != 0)
 | 
						|
    return cmp;
 | 
						|
 | 
						|
  const long codice1 = r1.get_long(CGC_CODCF);
 | 
						|
  const long codice2 = r2.get_long(CGC_CODCF);
 | 
						|
  cmp = codice1 - codice2;
 | 
						|
  if (cmp != 0)
 | 
						|
    return cmp;
 | 
						|
  
 | 
						|
  const int anno1 = r1.get_int(CGC_ANNO);
 | 
						|
  const int anno2 = r2.get_int(CGC_ANNO);
 | 
						|
  cmp = anno1 - anno2;
 | 
						|
  if (cmp != 0)
 | 
						|
    return cmp;
 | 
						|
 | 
						|
  const int part1 = r1.get_int(CGC_NUMPART);
 | 
						|
  const int part2 = r2.get_int(CGC_NUMPART);
 | 
						|
  cmp = part1 - part2;
 | 
						|
  if (cmp != 0)
 | 
						|
    return cmp;
 | 
						|
 | 
						|
  const TString datadoc1 = r1.get(CGC_DATADOC);
 | 
						|
  if (datadoc1.blank() || datadoc1 == "00/00/0000")
 | 
						|
    return -1;
 | 
						|
  const TString datadoc2 = r2.get(CGC_DATADOC);
 | 
						|
  if (datadoc2.blank() || datadoc2 == "00/00/0000")
 | 
						|
    return +1;
 | 
						|
  cmp = TDate(datadoc1)-TDate(datadoc2);
 | 
						|
  if (cmp != 0)
 | 
						|
    return cmp;
 | 
						|
 | 
						|
  const TString data1 = r1.get(CGC_SCADENZA);
 | 
						|
  if (data1.blank() || data1 == "00/00/0000")
 | 
						|
    return -1;
 | 
						|
  const TString data2 = r2.get(CGC_SCADENZA);
 | 
						|
  if (data2.blank() || data2 == "00/00/0000")
 | 
						|
    return +1;
 | 
						|
 | 
						|
  cmp = TDate(data1)-TDate(data2);
 | 
						|
  if (cmp != 0)
 | 
						|
    return cmp;
 | 
						|
 | 
						|
  // I tipi documento vanno ordinati in base alla sequenza sequente, non in base al valore numerico!
 | 
						|
  TToken_string priority = "1|3|15|2|4|5|6|7|8|9|10|11";
 | 
						|
  const int tipodoc1 = r1.get_int(CGC_TIPODOC);
 | 
						|
  const int tipodoc2 = r2.get_int(CGC_TIPODOC);
 | 
						|
  int pri1 = priority.get_pos(tipodoc1); 
 | 
						|
  if (pri1 < 0) pri1 = 100+tipodoc1;
 | 
						|
  int pri2 = priority.get_pos(tipodoc2); 
 | 
						|
  if (pri2 < 0) pri2 = 100+tipodoc2;
 | 
						|
  cmp = pri1 - pri2;
 | 
						|
  
 | 
						|
  return cmp;
 | 
						|
}
 | 
						|
 | 
						|
void TImporta_sc::salva_partita(TPartita*& game, long nmov)
 | 
						|
{
 | 
						|
  if (game != NULL)
 | 
						|
  {
 | 
						|
		game->write();
 | 
						|
		if (_fattsosp > 0 && game->chiusa(true))
 | 
						|
		{
 | 
						|
			while (_fattsosp-- > 0)
 | 
						|
			{
 | 
						|
				TFilename temp(_msk->get(F_PATHOUT));
 | 
						|
 | 
						|
				temp << '/' << format("%05ld", --nmov);
 | 
						|
				temp.ext("ini");
 | 
						|
				if (fexist(temp))
 | 
						|
					remove_file(temp);
 | 
						|
			}
 | 
						|
		}
 | 
						|
		_fattsosp = 0;
 | 
						|
    delete game;
 | 
						|
    game = NULL;
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
void TImporta_sc::transfer(const TFilename& file)
 | 
						|
{
 | 
						|
  TImporta_cogeco_recset recset(file);
 | 
						|
  recset.sort(game_sorter);
 | 
						|
  
 | 
						|
  const TString& caption = main_app().title();
 | 
						|
  TProgind pi(recset.items(), caption, true, true);
 | 
						|
 | 
						|
  TConfig* conf = NULL;
 | 
						|
	int anno = 0;
 | 
						|
	long part = 0;
 | 
						|
	char tipocf = ' ';
 | 
						|
	long sottoconto = 0L;
 | 
						|
	TPartita* game = NULL;
 | 
						|
	TToken_string key;
 | 
						|
	const TString& codcausc = _msk->get(F_CODCAUSC);
 | 
						|
	const TString& codcausf = _msk->get(F_CODCAUSF);
 | 
						|
	long nmov = 1L;
 | 
						|
	_fattsosp = 0;
 | 
						|
 | 
						|
  TLog_report log(caption);
 | 
						|
 | 
						|
  for (bool ok = recset.move_to(0); ok; ok = recset.move_next())
 | 
						|
  {
 | 
						|
    if (!pi.addstatus(1)) 
 | 
						|
      break;
 | 
						|
    const int chk = recset.get(CGC_NULL).as_int(); 
 | 
						|
    if (chk != 1) // Prende solo righe buone!
 | 
						|
      continue;
 | 
						|
 | 
						|
    const char t = recset.get(CGC_TIPOCF).as_string()[0]; 
 | 
						|
		const long s = recset.get(CGC_CODCF).as_int();
 | 
						|
		const int  a = recset.get(CGC_ANNO).as_int();
 | 
						|
	  const long p = recset.get(CGC_NUMPART).as_int();
 | 
						|
	
 | 
						|
		if (tipocf != t || sottoconto != s || anno != a || p != part)
 | 
						|
		{
 | 
						|
      salva_partita(game, nmov); // Salva parita corrente se non nulla
 | 
						|
 | 
						|
      TToken_string key; key.format("%c|%ld", t, s);
 | 
						|
  		const TRectype& clifo = cache().get(LF_CLIFO, key);
 | 
						|
      if (clifo.empty())
 | 
						|
      {
 | 
						|
        log_error(log, TR("Codice Cliente/Fornitore non valido"), recset);
 | 
						|
        continue;
 | 
						|
      }
 | 
						|
      if (a < 2000)
 | 
						|
      {
 | 
						|
        log_error(log, TR("Anno partita non valido"), recset);
 | 
						|
        continue;
 | 
						|
      }
 | 
						|
      if (p <= 0)
 | 
						|
      {
 | 
						|
        log_error(log, TR("Numero partita non valido"), recset);
 | 
						|
        continue;
 | 
						|
      }
 | 
						|
 | 
						|
 			tipocf = t;
 | 
						|
			sottoconto = s;
 | 
						|
			anno = a;
 | 
						|
			part = p;
 | 
						|
 | 
						|
      if (game == NULL)
 | 
						|
      {
 | 
						|
        int gruppo = 0, conto = 0;
 | 
						|
        if (find_clifo_bill(tipocf, gruppo, conto, sottoconto))
 | 
						|
        {
 | 
						|
          const TBill codclifo(gruppo, conto, sottoconto, tipocf);
 | 
						|
        	game = new TPartita(codclifo, anno, format("%ld", part));
 | 
						|
        }
 | 
						|
        else
 | 
						|
        {
 | 
						|
          log_error(log, TR("Impossibile determinare il conto cliente/fornitore"), recset);
 | 
						|
          break; // Esce subito, probabilmente il piano dei conti non e' stato ancora importato
 | 
						|
        }
 | 
						|
      }
 | 
						|
		}
 | 
						|
 | 
						|
    if (game != NULL)
 | 
						|
    {
 | 
						|
  		const int tipodoc = recset.get(CGC_TIPODOC).as_int();
 | 
						|
      switch (tipodoc)
 | 
						|
      {
 | 
						|
      case  1: nuova_fattura(recset, *game); break;       // Fattura 
 | 
						|
      case  2: nuova_nota_credito(recset, *game); break;  // Nota di credito
 | 
						|
			case  3:
 | 
						|
				{
 | 
						|
					const TRiga_partite & rigafat = nuova_fattura(recset, *game);
 | 
						|
 | 
						|
					nmov = fattura_in_sospensione( recset, rigafat, nmov);
 | 
						|
 | 
						|
					break;
 | 
						|
				} // Fattura in sospensione
 | 
						|
      case  4: nuova_nota_credito(recset, *game); break;  // Reso su fattura in sospensione
 | 
						|
      case  5: nuovo_pagamento(recset, *game); break;     // Pagamento fattura in sospeso
 | 
						|
      case  6: nuovo_insoluto(recset, *game, log); break; // Insoluto
 | 
						|
      case  8:                                            // Tratta 
 | 
						|
      case  9:                                            // Ri.Ba.
 | 
						|
      case 10: nuova_riba(recset, *game); break;          // Cambiale 
 | 
						|
      case 11: nuovo_pagamento(recset, *game); break;     // Pagamento
 | 
						|
      case 13: nuova_nota_credito(recset, *game); break;  // Nota di credito su RB clienti
 | 
						|
      case 14: nuova_nota_credito(recset, *game); break;  // Abbuono
 | 
						|
      case 15: nuova_scadenza(recset, *game, false); break;
 | 
						|
      case 18: nuova_riba(recset, *game); break;          // Paghero' 
 | 
						|
      case 19: nuova_riba(recset, *game); break;          // Avviso di scadenza
 | 
						|
      case 20: nuova_riba(recset, *game); break;          // R.I.D.
 | 
						|
      default: log_error(log, TR("Tipo documento non riconosciuto"), recset); break;
 | 
						|
      }
 | 
						|
    }
 | 
						|
  }
 | 
						|
  salva_partita(game, nmov); // Salva ultima partita se non nulla
 | 
						|
 | 
						|
	if (nmov > 1 && yesno_box(FR("Si desidera confermare l'importazione di %ld fatture in sospensione"), nmov - 1))
 | 
						|
	{
 | 
						|
		TString app;
 | 
						|
 | 
						|
		app << "cg2 -0 -i" << _msk->get(F_PATHOUT) << "/*.ini"; 
 | 
						|
		TExternal_app primanota(app);
 | 
						|
		primanota.run(true);
 | 
						|
	}
 | 
						|
  if (log.recordset()->items() > 0)
 | 
						|
    log.preview();
 | 
						|
}
 | 
						|
 | 
						|
bool TImporta_sc::create()
 | 
						|
{
 | 
						|
  // Determina i conti per clienti e fornitori nel caso non siano in anagrafica
 | 
						|
  TString query; query << "USE PCON SELECT TMCF!=\'\'";
 | 
						|
  TISAM_recordset pcon(query);
 | 
						|
  for (bool ok = pcon.move_first(); ok; ok = pcon.move_next())
 | 
						|
  {
 | 
						|
    const TRectype& rec = pcon.cursor()->curr();
 | 
						|
    const char tmcf = rec.get_char(PCN_TMCF);
 | 
						|
    if (tmcf == 'C' && _clienti.gruppo() == 0)
 | 
						|
      _clienti.get(rec);
 | 
						|
    if (tmcf == 'F' && _fornitori.gruppo() == 0)
 | 
						|
      _fornitori.get(rec);
 | 
						|
  }
 | 
						|
  _msk = new TImporta_sc_mask();     
 | 
						|
  return TSkeleton_application::create();
 | 
						|
}
 | 
						|
 | 
						|
bool TImporta_sc::destroy()
 | 
						|
{
 | 
						|
	delete _msk;
 | 
						|
  return TApplication::destroy();
 | 
						|
}
 | 
						|
 | 
						|
void TImporta_sc::main_loop()
 | 
						|
{
 | 
						|
  if (_msk->run() == K_ENTER)
 | 
						|
  {
 | 
						|
    _cache_causali.init(_msk->get(F_CODCAUSC), _msk->get(F_CODCAUSF));
 | 
						|
 | 
						|
    //genero il nome del file da caricare
 | 
						|
    TFilename name = _msk->get(F_PATH);
 | 
						|
    name.add(_msk->get(F_NAME));
 | 
						|
		transfer(name);
 | 
						|
  }   
 | 
						|
}
 | 
						|
 | 
						|
int lv4200 (int argc, char* argv[])
 | 
						|
{
 | 
						|
  TImporta_sc main_app;
 | 
						|
  main_app.run(argc, argv, TR("Importazione saldaconto COGECO"));
 | 
						|
  return true;
 | 
						|
} |