campo-sirio/ve/ve6200.cpp
guy 08991b9696 Corretta tabella elaborazioni differite
git-svn-id: svn://10.65.10.50/trunk@2994 c028cbd2-c16b-5b4b-a496-9718f37d4682
1996-06-14 15:48:34 +00:00

1052 lines
43 KiB
C++
Executable File

// ve6200.cpp: modulo per la generazione dei documenti in modo BATCH.
#include <checks.h>
#include <config.h>
#include <mask.h>
#include <urldefid.h>
#include <utility.h>
#include <relation.h>
#include <tabutil.h>
#include "ve6000.h"
#include "ve6retv.h" // valori di ritorno dalle varie funzioni
#include "ve6gen.h" // dichiarazione della classe base
#define TOKEN_QTA 5
#define TOKEN_QTAEVASA 7
#define TOKEN_QTA_DA_EVADERE 9
#define CAMPO_DAEVADERE 101
// è stata derivata la classe TSheet, perchè in alcuni documenti (es. Ordini)
// l'utente (tramite Ve6 -3, applicazione derivata dalla presente)
// può specificare di evadere una sola parte della quantità di merci indicate
// nella riga, così è stato necessario chiedere all'utente la quantità da evadere
// e riportarla nell'ultima colonna dello sheet: prima non era possibile, in quanto
// tale quantità non era un campo del record del file righedoc
/***********************************/
/**** Classe TInterattivo_sheet ****/
/***********************************/
// funzione quasi uguale a quella del TSheet
void TInterattivo_sheet::get_row(long first, TToken_string& l)
{
*cursor() = (TRecnotype)first;
const int last = fields_array().last();
for (int i = 0; i <= last; i++)
{
const TRecfield* rf = (TRecfield*)fields_array().objptr(i);
const char* s = rf ? (const char*)*rf : "";
l.add(s);
}
// stabilisce per default che la quantità da evadere è quella non ancora evasa
const long qta = l.get_long(TOKEN_QTA);
const long qtaevasa = l.get_long(TOKEN_QTAEVASA);
const real qtadaevadere = qta - qtaevasa;
l.add(qtadaevadere.string(11,3), TOKEN_QTA_DA_EVADERE);
}
// quando l'utente fa doppio click o preme selezione, la on_key riceve un K_ENTER
// e qui apro una mascherina in cui chiedo la qta da evadere, CONFERMA o ANNULLA
bool TInterattivo_sheet::on_key (KEY k)
{
/*
// K_ENTER e' E_MOUSE_DBL, mentre K_SPACE e' E_MOUSE_DOWN
if (k==K_ENTER)
{
// maschera per l'inserimento del valore
TMask m("Modifica", 1, 33, 7);
m.add_number (CAMPO_DAEVADERE, 0, "Quantità da evadere", 1, 3, 11);
m.add_button (DLG_OK, 0, "", 1, 4);
m.add_button (DLG_CANCEL, 0, "", 1, 5);
if (m.run()==K_ENTER)
{
// aggiorna il campo "quantita' evasa della riga selezionata
// TOKEN_QTAEVASA = posizione del campo QTAEVASA nel file ve0300b.dat,
// file gestito da Matteo e coincidente con i campi di righedoc,
// da lui utilizzato per lo spreadsheet delle righe nel suo Motore
long n = selected();
TToken_string temp = row(n); // riga selezionata
real qtaev (temp.get(TOKEN_QTAEVASA)); // valore di qtaevasa
real qtaspec (m.get(CAMPO_DAEVADERE)); // quantita' da evadere specificata
qtaev += real (qtaspec); // aggiorna il campo
real qtatot (temp.get(TOKEN_QTA)); // quantità totale della merce della riga
// controlla che qta_evasa + qta_da_evadere < qta_totale
if (qtaev>qtatot) error_box("Qtà da evadere superiore alla Qta non ancora evasa");
else {
// se corretto, setta la riga dello sheet
temp.add (qtaspec.string(), TOKEN_QTA_DA_EVADERE); // aggiunge il campo aggiornato nella stessa posizione
set_row (temp, (byte)n); // aggiorna lo sheet
}
check(n, TRUE);
}
return FALSE;
}
*/
return TCursor_sheet::on_key(k);
}
/******************************/
/*** Classe TBatch_crea_doc ***/
/******************************/
// L'applicazione TBatch_crea_doc crea n documenti finali partendo da m doc. iniziali,
// individuati tramite una maschera attivata prima dell'elaborazione, ve6000a.uml, che chiede:
// Data elaborazione (del documento da creare)
// Da Codice cli/for a Codice cli/for (doc. originale)
// Da Data documento a Data documento (doc. originale)
// Da Codice agente a Codice agente (doc. originale)
// Da Codice zona a Codice zona (doc. originale)
// Ordinamento della sequenza dei documenti creati per ognuna delle voci precedenti
// Raggruppa più documenti sorgente in un solo doc. destinazione quando possibile
// Raggruppa articoli : quando possibile raggruppa più righe dello stesso articolo,
// accumulandone le quantità
// Stampa immediata (non gestito)
inline TBatch_crea_doc& app() { return (TBatch_crea_doc&) main_app(); } // per accedere ai data members della TElaborazioni dalla filterfunct()
bool TBatch_crea_doc::create()
{
// BATCH --> non interattivo; questo serve perché le routines di TBatch_crea_doc
// sono usate anche da TInterattivo_crea_doc, classe figlia di "
_interattivo = FALSE;
_crea_doc = TRUE;
dispatch_e_menu(BAR_ITEM(1)); // chiama il metodo menu
return TRUE;
}
bool TBatch_crea_doc::destroy()
{
return TRUE;
}
bool TBatch_crea_doc::menu(MENU_TAG)
{
int err;
// contengono i limiti Da - a per l'individuazione dei documenti originali
TRectype first(LF_DOC), last(LF_DOC);
if (errore_fatale (run_mask(first, last))) // richiede e setta i parametri, tramite maschera
return FALSE;
switch (_ordinamento) // in base all'ordinamento, lancia la procedura con diversi parametri
{
case CLIFO :
// crea documenti ordinando per cli./for.
err = per_cliente(first, last, "TIPOCF|CODCF");
break;
case AGENTE:
// crea documenti ordinando per agente
err = per_cliente(first, last, "TIPOCF|CODAG");
break;
case ZONA:
// crea documenti ordinando per zona
err = per_cliente(first, last, "TIPOCF|ZONA");
break;
case DATA:
// crea documenti ordinando per data
err = per_cliente(first, last, "TIPOCF|DATADOC");
break;
default:
break;
}
if (errore_fatale(err))
fatal_box ("A fatal error has occured!");
return FALSE;
}
// run_mask():
// imposta i records first e last con gli estremi Da - a
// per individuare i documenti originali da elaborare
int TBatch_crea_doc::run_mask(TRectype& first, TRectype& last)
{
// int err;
first.zero();
last.zero();
TMask *_msk = new TMask ("ve6000");
// --- parte di Marcello, già disabilitata: a cosa serviva ?
// Imposta il flag di autorizzazione agente
/* TTable t("%TIP");
t.zero();
t.put ("CODTAB", _tipo_doc_org); // tipo del documento originale
if (err = t.read (_isgteq)) // si posiziona sul record relativo al documento del tipo specificato
{
error_box ("TElaborazioni::run_mask() : errore di lettura %d da tab(TIP)", err);
return READ_ERROR;
}
if (t.get ("CODTAB") != _tipo_doc_org) // verifica che il tipo di documento trovato sia quello richiesto
{
error_box ("TElaborazioni::run_mask() : non esiste il tipo documento %s in tab(TIP)", (const char *)_tipo_doc_org);
return DOC_TYPE_NOT_FOUND;
}
TFilename profilo(t.get ("S4")); // nome del profilo documento (nome del .ini associato al tipo documento originale)
profilo.ext("ini");
TConfig profilo_doc(profilo); // file di configurazione (ini) del documento
*/
TConfig p(CONFIG_DITTA);
// gestione agente abilitata <==> abilitata in profilo documento e nel .ini della ditta
// int agente = (profilo_doc.get_int ("CODAG", "PROFILO") && p.get_int("AGENTE", "VE"));
int agente = (p.get_int("AGENTE", "VE"));
/* se il flag per la gestione agenti è != 0, allora visualizza i campi agente ed
adotta la stessa convenzione usata per CODICE CLIENTE e ZONA per gestire l'eventualita' che
l'utente non specifichi nulla.
Se è disabilitata, allora lascia vuoti i campi CODICE AGENTE DA e CODICE AGENTE A, in modo
da eliminare una condizione durante il filtraggio dei records.
*/
// nasconde i campi se la gestione agenti è disabilitata
if (!agente)
{
_msk->show (F_CODICE_AGENTE_DA, FALSE);
_msk->show (F_CODICE_AGENTE_A, FALSE);
}
if (_msk->run() == K_ESC) // runna la maschera: se premuto esc, esci
{
delete _msk;
return ESC_PRESSED;
}
_ordinamento = _msk->get_int (F_ORDINAMENTO_EMISSIONE); // ordinamento (RadioButton)
_raggruppa = _msk->get_bool (F_RAGGRUPPA); // raggruppa più doc. originali ?
_per_articolo = _msk->get_bool (F_RAGGR_ARTICOLI); // raggruppa linee con lo stesso articolo
_datadoc = _msk->get(F_DATA_ELAB); // Data documenti finali
_anno = _datadoc.year(); // anno è una componente della chiave
TString temps; // temporanea per rilevare i valori dei campi della maschera
TLocalisamfile f(LF_DOC);
// i due seguenti campi non sono discriminanti, in quanto due documenti diversi
// (es.: BollaC e Fattura Acc.) sono raggruppabili nella stessa fattura
// e lo stato in cui devono essere dipende solo dal .ini di quel tipo di documento originale
// first.put ("TIPODOC", _tipo_doc_org); // tipo documento (da tab. ELD)
// last.put ("TIPODOC", _tipo_doc_org);
// first.put ("STATO", _stato_i_doc_i); // stato documento originale
// last.put ("STATO", _stato_i_doc_i);
temps = _msk->get(F_CODICE_CLIFO_DA);
if (temps.not_empty())
first.put ("CODCF", temps); // codice cliente (v. filterfunct)
temps = _msk->get(F_CODICE_CLIFO_A);
if (temps.not_empty())
last.put ("CODCF", temps); // codice cliente (v. filterfunct)
// data
first.put ("DATADOC", _msk->get(F_DATA_DOCUMENTO_DA)); // nessun controllo perché data doc. da e data doc. a sono checktype required
last.put ("DATADOC", _msk->get(F_DATA_DOCUMENTO_A));
// codice zona
temps = _msk->get (F_CODICE_ZONA_DA); // mette in temps il valore del campo codice zona da
if (temps.not_empty()) // se è stato inserito un valore...
first.put("ZONA", temps); // mettilo nel campo zona
temps = _msk->get (F_CODICE_ZONA_A);
if (temps.not_empty())
last.put ("ZONA", temps);
// codice agente: imposta i campi solo se ne è abilitata la gestione
// se agente è disabilitato, i campi agente rimangono vuoti
if (agente)
{
temps = _msk->get (F_CODICE_AGENTE_DA);
if (temps.not_empty())
first.put("CODAG", temps);
temps = _msk->get (F_CODICE_AGENTE_A);
if (temps.not_empty())
last.put ("CODAG", temps);
}
delete _msk;
return 0;
}
// crea fatture ordinate tramite la elab_princ()
// first e last sono 2 rectype che contengono i dati da a per filtrare i documenti originali
// campo_ordinamento è una stringa contenente la chiave di ordinamento (per cliente o per altro)
// da specificare nel TCursor usato per individuare i documenti originali
int TBatch_crea_doc::per_cliente(TRectype& first, TRectype& last, const char* campo_ordinamento)
{
TRelation rel (LF_DOC); // relazione sul file dei documenti
// filtro per il TCursor:
// DATADOC è obbligatoria, ma TIPOCF non dovrebbe essere per forza "C"
TString filter("(ANSI(DATADOC)>=\""); // include nel filtro i tests sui campo obbligatori
filter << first.get_date("DATADOC").string(ANSI) << "\")&&(ANSI(DATADOC)<=\"";
filter << last.get_date("DATADOC").string(ANSI) << "\")&&(TIPOCF==\"C\")";
// se per i campi opzionali sono stati specificati dei valori, include i tests nel filtro:
// CODICE AGENTE
if (!first.get("CODAG").empty())
filter << "&&(CODAG>=\"" << first.get("CODAG") << "\")";
if (!last.get("CODAG").empty())
filter << "&&(CODAG<=\"" << last.get("CODAG") << "\")";
// CODICE ZONA
if (!first.get("ZONA").empty())
filter << "&&(ZONA>=\"" << first.get("ZONA") << "\")";
if (!last.get("ZONA").empty())
filter << "&&(ZONA<=\"" << last.get("ZONA") << "\")";
// setta i limiti dei codici CLIENTI/FORNITORI per la funzione filterfunct del TCursor
_first_codcf = first.get_long ("CODCF");
_last_codcf = last.get_long ("CODCF");
#ifdef _TDD_IN_FILTER
// filtro costruito in base a tutti i tipi di doc. che hanno un record ELABORAZIONE DIFFERITA (ELD)
// che li trasforma in _tipo_doc_des
TString tdfilter(1024);
tdfilter = td_ELD_to_filter(_tipo_doc_des);
// se non è vuoto, lo aggiunge al filtro già creato
if (!tdfilter.empty())
filter << "&&(" << tdfilter << ")";
#endif
// crea, tramite un TCursor, un elenco dei documenti sorgente che rispondono alle caratteristiche
TSorted_cursor curs(&rel, campo_ordinamento, filter, _chiave, &first, &last);
// la filterfunct limita i documenti a quelli con un codice CLI/FO fra _first_codcf e _last_codcf
// (cioé quelli indicati nella maschera richiesta in precedenza)
curs.set_filterfunction(filterfunct);
return elab_princ(curs);
}
// esegue tutta l'elaborazione in modo BATCH, sui documenti individuati nel TCursor curs
int TBatch_crea_doc::elab_princ(TSorted_cursor &curs)
{
int err; // errori ritornati dalle funzioni
long n; // numero della fattura nella numerazione corrente
bool no_select = TRUE; // TRUE se non sono stati selezionati documenti dallo sheet
bool no_elab = TRUE; // TRUE se non ha ancora elaborato nessun documento
TLocalisamfile f(LF_DOC); // per gestire la testata dei documenti
TLocalisamfile rdoc(LF_RIGHEDOC); // per gestire le righe dei documenti
int current = 0; // chiave corrente
TRectype pilota (LF_DOC); // record per il documento pilota
TTable t("NUM"); // tabella numerazioni documenti
TRectype tempr(LF_DOC); // record del documento originale che si sta elaborando
TRectype temprdoc (LF_RIGHEDOC); // record per le righe dei documenti originali
int nrdoc; // numero di righe scritte nel doc finale
bool altri; // TRUE se ci sono altri documenti da includere nello stesso doc. finale
if (curs.items() == 0) // se non ha individuato doc. originali, indica errore
{
error_box ("Nessun documento da elaborare.");
return NO_ORG_DOCS;
}
curs.freeze(); // non perdere tempo a riaggiornarti
// curs=0; // comincia dal primo documento della lista
// _processed è un array di flag che indica se il documento relativo a ciascun flag
// sia da processare (FALSE) o da ignorare/già processato (TRUE).
// le prossime sono righe fossili, rimaste da quanto BATCH e INTERATTIVO erano ancora assieme
//*********************
// Inizio righe fossili
//*********************
TString80 Titolo("documenti elaborabili che possono diventare");
Titolo << _tipo_doc_des;
TCursor_sheet docs_sheet(&curs,
" |NDOC|TIPODOC|DATADOC|TIPOCF|CODCF|OCFPI",
Titolo,
"@1|Numero@7|Tipo@4|Data@10|C/F|Cod. cliente|CF o P.IVA@16");
docs_sheet.enable_check();
if (_interattivo)
{
if (docs_sheet.run()==K_ESC) return ESC_PRESSED;
for (int i=0; i<docs_sheet.items(); i++)
if (!docs_sheet.checked(i))_processed.set(i);
else no_select = FALSE;
if (no_select)
{
error_box ("Nessun documento selezionato.");
return NO_ORG_DOCS;
}
}
//*********************
// Fine righe fossili
//*********************
// Scandaglia tutto curs e setta _processed in tutti i doc. originali che non hanno il
// relativo record di ELABORAZIONE DIFFERITA (ELD) per essere trasformati in doc. destinazione
for (int i=0; i<curs.items();i++) if (!_processed[i]) esiste_ELD(curs,i,SET_PROCESSED);
// ciclo di generazione fattura: finchè vi è ancora un documento da elaborare,...
while (next_pilota(curs,pilota)) // locka automaticamente il documento (pilota) che sta elaborando
{
get_info(pilota); // setta un mare di variabili che dipendono dal documento originale
//*****************************************************
//* questa sezione serve a CREARE il documento finale *
//*****************************************************
// le prossime sono righe fossili, rimaste da quanto BATCH e INTERATTIVO erano ancora assieme
//*********************
// Inizio righe fossili
//*********************
if (_interattivo)
{
TDate d(TODAY);
_datadoc = d;
_anno = d.year();
// inserisce il record di testata della fattura che va a creare
f.put ("CODNUM", _codnum); // la fattura va numerata in base alla codnum specificata in ELD
f.put ("ANNO", _anno); // imposta l'anno del documento
f.put ("PROVV", _provv); // imposta provv./def. del documento
f.put ("NDOC", _ndoc); // imposta il numero del documento
if (!_crea_doc)
{
err = f.read(_isgteq); // cerca il documento
if (err) // guarda se si è verificato un errore
{
error_box ("Errore di lettura %d in doc, cercando il documento", err);
return READ_ERROR;
}
} else f.curr() = pilota; // tutti i campi della fattura sono uguali al documento pilota, tranne alcuni (impostati più sotto)
_tipo_doc_des = f.get ("TIPODOC"); // imposta il tipo di documento
_stato_f_doc_f = f.get ("STATO"); // stato della fattura appena creata
}
else
//*********************
// Fine righe fossili
//*********************
{
// dovendo creare un nuovo documento TIPODOCDES, prende il primo numero disponibile nella numerazione
// relativa, aggiornando il record della numerazione
// (chiedi a Matteo se vuoi delle spiegazioni, oppure a me, se credi di non riuscire a capire Matteo)
t.zero(); // azzera il record della tabella NUMerazioni
t.put ("CODTAB", _codnum); // cerca NUMerazione del documento destinazione
// (codice preso dalla get_info)
if (err = t.read (_isgteq, _lock)) // legge lockando il record per evitare conflitti
{
error_box ("TBatch_crea_doc::per_cliente : errore %d di lettura su tab(NUM)", err);
return READ_ERROR;
}
if (t.get("CODTAB") == _codnum) // controlla che il codice numerazione sia effettivamente quello cercato (?)
{
n = t.get_long("I1"); // legge l'ultimo numero di documento utilizzato
n++; // ora n è il numero della mia fattura (da mettere in NDOC);
}
else
n = 1; // se non esiste alcun documento con il codice numerazione specificato, allora la fattura corrente è la n° 1
// inserisce il record di testata del doc_destinazione che va a creare
f.curr() = pilota; // tutti i campi del doc_destinazione sono uguali al documento pilota,
// tranne quelli impostati qui sotto:
f.put ("NDOC", n); // imposta il numero del documento
f.put ("TIPODOC", _tipo_doc_des); // imposta il tipo di documento
f.put ("STATO", _stato_f_doc_f); // stato del documento appena creato
f.put ("DATADOC", _datadoc); // data di creazione del documento (indicata nella maschera)
f.put ("CODNUM", _codnum); // la fattura va numerata in base alla codnum specificata
if ((err = f.write()) == NOERR) // scrive il record in doc. Se non ci sono errori...
{
t.put ("I1", n); // imposta nuovo numero del documento
t.rewrite(); // aggiorna il numero del documento nella tabella NUMerazioni
t.read (_isequal, _unlock); // unlocka il record
}
else // se vi e' stato un errore nello scrivere il doc_destinazione,...
{
t.read (_isequal, _unlock); // unlocka il record in anche in caso di errore
switch (err)
{
case _isreinsert:
fatal_box ("ve6100: Errore fatale: il record con la chiave specificata esiste già: impossibile sovrascrivere");
break;
default:
fatal_box ("ve6100: Errore fatale: %d scrivendo sulla tabella NDOC", err);
break;
}
return RECORD_WRITE_ERROR; // indica al chiamante un errore nella scrittura di un record
}
}
tempr = pilota; // il primo documento originale da elaborare è quello pilota
// qui inizia il ciclo per la creazione della fattura
// N.B.: appende ogni documento originale nella fattura
nrdoc = 0; // numero riga documento
bool endsearch = FALSE; // true quando non ci sono piu' doc_originali per questo doc_destinazione
TRecord_array doc_destinazione (LF_RIGHEDOC, "NRIGA"); // array contenente le righe della fattura
// costruisce ed imposta il record filtro per trovare le righe di doc_destinazione
TRectype r (LF_RIGHEDOC);
r.zero();
_ndoc = "";
_ndoc << n;
// imposta i dati della chiave
r.put ("CODNUM", _codnum);
r.put ("ANNO", _anno);
r.put ("PROVV", _provv);
r.put ("NDOC", _ndoc);
// _crea_doc = FALSE <==> interattivo = TRUE: nel BATCH, _crea_doc = TRUE, sempre
if (!_crea_doc) doc_destinazione.read(r); // se non deve crearlo, legge le righe gia' presenti
// doc_destinazione.set_key(&r);
// legge tutti i doc_originali che vanno nel doc_destinazione
do
{
/* TRecord_array doc_originale (LF_RIGHEDOC, "NRIGA"); // array per leggere le righe del doc. org. da elaborare
// carica il documento corrente da rdoc:
// imposta i campi della chiave
temprdoc.zero();
temprdoc.put ("CODNUM", tempr.get("CODNUM")); // tempr = record del documento originale da inserire
temprdoc.put ("ANNO", tempr.get ("ANNO"));
temprdoc.put ("PROVV", tempr.get("PROVV"));
temprdoc.put ("NDOC", tempr.get("NDOC"));
// lascia il campo "NRDOC" come campo per il conteggio
// legge le righe del documento originale, distruggendo quelle precedentemente memorizzate
// legge solo i records che corrispondono alla chiave (temprdoc)
int err = doc_originale.read(temprdoc);
CHECK (err==NOERR, "read da rdoc fallita");
*/
// appende il documento originale al documento di destinazione
// per ogni doc_originale legge i dati (per il primo non e' necessario)
get_info(tempr);
// legge dal .ini del doc_originale tempr. il flag che dice se le righe di tempr
// possono essere evase parzialmente o devono essere evase per intero: controllo fossile,
// dal momento che in modo BATCH i documenti vengono evasi completamente
bool raggr_parz = get_raggr_parz(tempr,err);
// legge il metodo (es. B01F01) di elaborazione (trasformazione) delle righe
TString met = metodo(tempr);
// elabora le righe, scrivendole nel doc_destinazione tramite l'omonimo TRecord_array
elab_righe(met,raggr_parz,tempr,doc_destinazione,temprdoc);
_processed.set(curs.pos()); // indica che il documento e' stato processato
// aggiorna lo stato del documento originale e lo scrive
curs.file(LF_DOC).put ("STATO", _stato_f_doc_i);
curs.file(LF_DOC).setkey(1);
if (err = curs.file(LF_DOC).rewrite())
{
error_box ("ve6200: Errore fatale: %d scrivendo sul file DOC", err);
return RECORD_WRITE_ERROR;
}
curs.file(LF_DOC).setkey(2);
curs.unlock(); // unlocka il record del documento processato
// cerca il prossimo doc_originale da inserire. Se non ce ne sono piu', termina la generazione del doc_destinazione
// se ce ne sono ancora, mette nel TRectype tempr il record del prossimo doc_originale da aggiungere
if (_raggruppa) // se deve raggruppare piu' doc_originali in uno solo, ne cerca altri
altri = search(pilota, tempr, curs);
else // altrimenti passa al prossimo doc_destinazione
altri = FALSE;
}
while (altri); // fine del ciclo che raggruppa i doc_originali in un solo doc_destinazione
// controlla se deve raggruppare le righe per codice articolo:
// se vi sono piu' righe con lo stesso codice articolo e altre caratteristiche in comune,
// le riunisce in una sola riga
if (_per_articolo && (doc_destinazione.rows() > 1)) // se deve raggr. e ci sono almeno 2 righe
raggruppa_righe (doc_destinazione);
// salva le righe del doc_destinazione creato
if (err = doc_destinazione.write())
{
error_box ("Errore nella scrittura del doc. destinazione. err = %d", err);
return RECORD_WRITE_ERROR;
}
no_elab = FALSE; // ha elaborato almeno un documento
// cerca il prossimo documeto pilota per il prossimo doc_destinazione
}; // finche' i doc_originali non finiscono
if (no_elab) // se non ha elaborato (trovato)doc_originali da elaborare, indica errore
{
error_box ("Nessun documento elaborato.");
return NO_ORG_DOCS;
}
return 0;
}//*** fino a qua ***//
int TBatch_crea_doc::get_info(TRectype &doc)
{
int err;
// informazioni dalla tabella elaborazioni differite
TRectype reld(LF_TAB); // reld e' un record di tipo tabella
leggi_da_ELD(reld,doc.get("TIPODOC"));
// Imposta i dati relativi all'elaborazione differita corrente
_tipo_doc_org = reld.get ("S6"); // tipo documento originale
_tipo_doc_des = reld.get ("S8"); // tipo documento destinazione
TConfig doc_config (getini(doc,err), "RAGGRUPPA"); // prende il .ini di doc
_stati_validi_doc_i = doc_config.get ("STATIVALIDI"); // stato iniziale del documento originale
_stato_f_doc_i = doc_config.get ("STATOFINALE"); // stato finale (dopo l'elaborazione) del documento originale
// ha qualche senso che _stato_f_doc_f e _codnum siano indicati nel record ELD di ciascun documento iniziale ?
if (!_interattivo)
{
_stato_f_doc_f = reld.get ("S9"); // stato finale (dopo l'elaborazione) del documento finale
_codnum = reld.get ("S5"); // codice numerazione per il documento finale
}
// il flag di sospensione imposta da controllare va preso dal registro a cui
// la numerazione del documento e' collegata
_sosp_imposta = getflag(doc, SOSPENSIONE_IMPOSTA); // T/F sospensione imposta
_cod_sconto = getflag(doc, CODICE_SCONTO); // T/F codice sconto
_stesso_anno = stesso_anno_fiscale(doc); // T/F per STESSOANNOFISCALE in [RAGGR.] del .ini di reld
return 0;
}
bool TBatch_crea_doc::stesso_anno_fiscale(TRectype& rec)
{
bool stesso = FALSE;
// bool stesso = _stesso_anno_fiscale;
int err;
// if (!stesso)
// {
TString name(getini(rec, err));
if (!err){
TConfig config (name, "RAGGRUPPA"); // prende il .ini di rec
stesso = (config.get("STESSOANNOFISCALE")[0] == '1'); // trova se si possono evadere parzialmente le righe
}
// }
return stesso;
}
// ritorna la stringa metodo di trasf. dal record ELD per rec->_tipo_destinazione
TString TBatch_crea_doc::metodo(TRectype &rec)
{
TString metodo;
TString _tipo_pilota = rec.get("TIPODOC");
TRectype reld(LF_TAB); // = rec solo per inizializzarlo
leggi_da_ELD(reld,_tipo_pilota);
metodo = reld.get("S1");
return metodo;
}
// trova il .ini di rec e lo restituisce
TString TBatch_crea_doc::getini(TRectype& rec, int &err)
{
// aggiustare con una new ad un TConfig
TTable teld("%TIP"); // nella tabella %TIP
teld.zero();
teld.put ("CODTAB", rec.get("TIPODOC")); // tipo del documento pilota
err = teld.read (_isgteq); // legge il record
if (err)
{
error_box("Non riesco a leggere nella tabella %s il tipo documento %s",teld.name(),(const char *)rec.get("TIPODOC"));
return err;
}
TRectype& rtip = teld.curr(); // e lo mette in dest
TFilename inifile (rtip.get("S4")); // il nome del .ini e' nel campo S4
inifile.ext("ini");
return (TString)inifile;
}
// prende i dati della sezione [RAGGRUPPA]
bool TBatch_crea_doc::get_raggr_parz(TRectype& rec, int &err)
{
bool raggr_parz = FALSE;
err = FALSE;
TString name(getini(rec, err));
// if (err) return err;
// _stati_validi = config.get("STATIVALIDI"); // trova gli stati validi
if (!err) {
TConfig config (name,"RAGGRUPPA"); // prende il .ini di rec
raggr_parz = (config.get("RAGGRPARZ")[0] == '1'); // trova se si possono evadere parzialmente le righe
}
return raggr_parz;
}
// controlla che il documento rec sia in uno degli stati validi indicati nella sezione [RAGGRUPPA] del suo .ini
int TBatch_crea_doc::statovalido(TRectype& rec)
{
int err;
// TConfig config (getini(rec, err), "RAGGRUPPA"); // prende il .ini di rec
// if (err) return err;
// TString80 _stati_validi;
// _stati_validi = config.get("STATIVALIDI"); // trova gli stati validi
err = _stati_validi_doc_i.find((rec.get("STATO"))[0]); // cerca lo stato (-1 e' non trovato)
if (err == -1) err = STATO_NON_VALIDO;
else err = STATO_VALIDO;
return err;
}
// ritorna TRUE se esiste una ELD che passa dal tipo documento di pilota a _tipo_doc_des
int TBatch_crea_doc::esiste_ELD(TSorted_cursor &curs,int i,bool set_proc)
{
//*************
// bisognerebbe affidarsi ad un decoder
//*************
curs = i;
TRectype &pilota = curs.curr(); // imposta il primo documento da verificare : pilota
TString _tipo_pilota = pilota.get("TIPODOC");
TRectype dummy(LF_TAB); // = pilota solo per inizializzarlo
int err = leggi_da_ELD(dummy,_tipo_pilota);
if (err == ELAB_NOT_FOUND)
if (set_proc==SET_PROCESSED) _processed.set(curs.pos());
else error_box ("TElaborazioni::per_cliente() : non esiste il tipo di elaborazione %s -> %s in tab(ELD)", (const char *)_tipo_pilota, (const char *)_tipo_doc_des);
return err;
}
// ritorna ELAB_FOUND se esiste una ELD che passa dal tipo documento di pilota a _tipo_dest
// (o _tipo_doc_dest, se _tipo_dest non viene specificato) e riempie eventualmente dest con la prima ELD
int TBatch_crea_doc::leggi_da_ELD(TRectype &dest,TString _tipo_pilota,TString _tipo_dest)
{
TRelation rel("ELD");
TString80 filter;
filter << "((S6==\"" << _tipo_pilota << "\")";
if (!_tipo_dest.empty()) filter << "&&(S8==\"" << _tipo_doc_des << "\")";
else if (!_tipo_doc_des.empty()) filter << "&&(S8==\"" << _tipo_doc_des << "\")";
filter << ")";
TCursor curs(&rel, filter);
if (curs.items() == 0) return ELAB_NOT_FOUND;
curs = 0;
dest = curs.curr();
return ELAB_FOUND;
/*
int err;
TTable teld("ELD");
teld.zero();
teld.put ("S6", _tipo_pilota); // tipo del documento pilota
teld.put ("S8", _tipo_doc_des); // tipo del documento finale
err = teld.read (_isgteq); // legge il record
dest = teld.curr(); // e lo mette in dest
if (err) // guarda se si è verificato un errore
{
error_box ("TElaborazioni::per_cliente() : errore di lettura %d da tab(ELD)", err);
return READ_ERROR;
}
if ((teld.get ("S6") != _tipo_pilota)||(teld.get ("S8") != _tipo_doc_des)) // verifica che il tipo di documento trovato sia quello richiesto
{
// error_box ("TElaborazioni::per_cliente() : non esiste il tipo di elaborazione %s -> %s in tab(ELD)", (const char *)_tipo_pilota, (const char *)_tipo_doc_des);
// se non esiste una ELD, setta processed (set_proc permettendo),
// in modo da ignorare questo documento nei controlli successivi
return ELAB_NOT_FOUND;
}
teld.read (_isequal, _unlock); // unlocka il record in ogni caso
return ELAB_FOUND;
*/
}
const char *TBatch_crea_doc::td_ELD_to_filter(TString &_tipo_doc_des)
{
bool first = TRUE;
TString td_filter(1024);
TRelation rel("ELD");
TString80 filter;
if (_tipo_doc_des.empty()) return "";
filter << "(S8==\"" << _tipo_doc_des << "\")";
TCursor curs(&rel, filter);
if (curs.items() == 0) return "";
for (int i=0; i<curs.items();i++)
{
if (first) first=FALSE;
else td_filter << "||";
td_filter << "(TIPODOC==\"" << curs.curr().get("S6") << "\")";
}
return (const char *)td_filter;
}
// cerca il prossimo documeto pilota in cursor
bool TBatch_crea_doc::next_pilota(TSorted_cursor &curs,TRectype &pilota)
{
bool cont = TRUE;
TRecnotype temp = curs.items();
int err = FALSE;
for (int i=0; i < temp && cont && (_processed[i] || ((err = esiste_ELD(curs,i)) != READ_ERROR)); i++) // prossimo documento non processato
switch (err)
{
case ELAB_FOUND: // se ne ha trovato uno
curs=i;
if (statovalido(curs.curr()))
{
pilota = curs.curr(); // nuovo documento pilota
curs.lock();
cont = FALSE;
}
break;
default:;
};
if (i>=temp) return FALSE; // se sono stati tutti processati --> termina
return TRUE; // altrimenti continua a processare
}
// elabora le righe di doc_originale in doc_destinazione, sul TRectype temprdoc, col metodo metodo
bool TBatch_crea_doc::elab_righe(TString metodo,bool raggr_parz,TRectype &tempr,TRecord_array &doc_destinazione,TRectype &temprdoc)
{
bool tutte_le_righe_elab = TRUE;
// switch (metodo)
// {
// case "B01F01":
TRecord_array righe_tmp (LF_RIGHEDOC, "NRIGA"); // array contenente le righe della fattura
TRelation rel(LF_RIGHEDOC);
// rel.lfile().zero();
TString80 ndoc_filter = "(";
ndoc_filter << "(CODNUM==\"" << tempr.get("CODNUM") << "\")&&";
ndoc_filter << "(ANNO==\"" << tempr.get("ANNO") << "\")&&";
ndoc_filter << "(PROVV==\"" << tempr.get("PROVV") << "\")&&";
ndoc_filter << "(NDOC==\"" << tempr.get("NDOC") << "\")";
ndoc_filter << ")";
TSorted_cursor curs_righe(&rel, "NRIGA", ndoc_filter);
curs_righe.read(); // legge le righe del documento originale corrente
// qui sostituisci le costanti stringa per testata e fields col tuo frammento di
// codice che interpreta l'apposita sezione del profilo documento.
TTable t("%TIP");
t.zero();
t.put ("CODTAB", tempr.get("TIPODOC"));
t.read (_isgteq);
TString _descr_tipodocorg (t.get("S4"));
TInterattivo_sheet righe_sheet(&curs_righe,"|NRIGA|CODART|DESCR|PREZZO|QTA|UMQTA|QTAEVASA|UMQTA|QTA",
_descr_tipodocorg << " - righe",
"@1|N.riga|Codice articolo@20|Descrizione@50|Prezzo@18|Quantità@11|um|Q.tà evasa@11|um|Q.tà da evadere");
righe_sheet.add_button(DLG_OK, "Conferma", K_YES);
/* if (_raggruppa_intero)
{
righe_sheet.enable(); // seleziona tutte le righe
righe_sheet.disable_check(); // impedisce di toglierne alcune
}
*/
KEY key=0;
int _rdoc = 1;
bool batch = !((raggr_parz)&&(_interattivo));
if (!batch)
key = righe_sheet.run();
if (batch||(key==K_YES))
for (int i=0; i<righe_sheet.items(); i++) // copia le righe selezionate nel documento finale
if (batch||righe_sheet.checked(i))
{
curs_righe = i;
righe_tmp.row (_rdoc++, TRUE) = curs_righe.file(LF_RIGHEDOC).curr();
}
else tutte_le_righe_elab = FALSE;
if (metodo == "B01F01")
{
for (int i=1; i<=righe_tmp.rows(); i++) // per tutte le righe del documento originale
{
temprdoc = righe_tmp.row (i); // prende la riga del documento originale
temprdoc.put ("CODNUM", _codnum); // chiave per la fattura (indicata nella tabella ELD)
temprdoc.put ("ANNO", _anno); //
temprdoc.put ("PROVV", _provv); //
temprdoc.put ("NDOC", _ndoc); //
int nrdoc = doc_destinazione.last_row()+1;
TRectype& r = doc_destinazione.row(nrdoc, TRUE); // il parametro TRUE indica di creare la riga se non esiste già
temprdoc.put ("NRIGA", r.get("NRIGA")); // imposta il numero di riga
temprdoc.put("DESCEST",""); // azzera i campi memo
temprdoc.put("G1",""); //
r = temprdoc; // imposta la i-esima riga (perché r è una reference)
}
}
// }
return tutte_le_righe_elab;
}
// Ritorna due flag a seconda del parametro.
bool TBatch_crea_doc::getflag (TRectype& rec, int n)
{
/*
TTable t("%TIP");
t.zero();
t.put ("CODTAB", rec.get("TIPODOC"));
t.read (_isgteq);
TFilename filename(t.get("S4"));
filename.ext ("ini");
TConfig conf(filename);
*/
int err;
TConfig conf(getini(rec,err));
if (err) return READ_ERROR;
switch (n) // determina quale flag leggere
{
case SOSPENSIONE_IMPOSTA: return TRUE;
/*
return conf.get_bool (" ", " "); // sezione, nome flag
// il flag da controllare va preso dal registro a cui la numerazione del documento
// e' collegata
*/
case CODICE_SCONTO:
return conf.get_bool ("CAMBIO" , "PROFILO"); // sezione, nome flag
}
error_box ("getflag: Errore: parametro 2 = %d, non valido .", n);
return READ_ERROR;
}
/* Cerca tra i documenti selezionati da curs il prossimo, a partire da curs.curr() che puo' essere
raggruppato con il documento pilota. Il record eventualmente trovato e' ritornato in tempr.
La ricerca e' effettuata tra i documenti di curs.
Ritorna FALSE se non trova documenti da raggruppare, TRUE altrimenti. */
bool TBatch_crea_doc::search (TRectype& pilota, TRectype& tempr, TSorted_cursor& curs)
{
// static bool csi = controlla_sosp_imp(); // determina se controllare il flag di sospensione d'imposta
TRectype campi_pilota (LF_DOC); // usato per settare solo i campi importanti.
campi_pilota.zero();
// campi_pilota.put ("CODNUM", pilota.get ("CODNUM"));
// campi_pilota.put ("STATO", pilota.get ("STATO"));
campi_pilota.put ("CODCF", pilota.get ("CODCF"));
campi_pilota.put ("TIPOCF", pilota.get ("TIPOCF"));
// se pilota ha settato STESSOANNOFISCALE, cerca solo i doc. dello stesso anno
// bool stesso_anno = stesso_anno_fiscale(pilota);
if (_stesso_anno)
campi_pilota.put ("ANNO", _anno);
// campi_pilota.put ("ANNO", pilota.get ("ANNO"));
// campi_pilota.put ("TIPODOC", _tipo_doc_org);
//?? campi_pilota.put ("PROVV", pilota.get ("PROVV"));
campi_pilota.put ("RAGGR", pilota.get ("RAGGR"));
campi_pilota.put ("CODVAL", pilota.get ("CODVAL"));
campi_pilota.put ("CAMBIO", pilota.get ("CAMBIO"));
campi_pilota.put ("CODLIN", pilota.get ("CODLIN"));
campi_pilota.put ("SCONTOPERC", pilota.get ("SCONTOPERC"));
//?? campi_pilota.put ("NUMDOCRIF", pilota.get ("NUMDOCRIF"));
// controllo sul codice sconto
bool found = FALSE;
TRecnotype items = curs.items();
for (int i = 0; i<items && !found; i++)
if (!_processed[i])
{
curs = i;
TRectype& temp = curs.curr();
if ((esiste_ELD(curs,i)==ELAB_FOUND) // se esiste la ELD
&&(statovalido(temp)==STATO_VALIDO) // e lo stato del documento e' valido (vedi il .ini)
&&(temp == campi_pilota)) // campi_pilota a destra per ignorare il confronto dei campi vuoti
found = doc_i_compatibili(campi_pilota,temp);
// il codice sconto non e' da leggere nell'ini ma in nel record di ogni documento
}
curs.lock();
tempr = curs.curr();
return found;
}
// guarda se i documenti pil e pil2 sono compatibili per essere uniti nello stesso documento finale
bool TBatch_crea_doc::doc_i_compatibili(TRectype &pil,TRectype &pil2)
{
bool _sosp_imposta; // T/F sospensione imposta
bool _cod_sconto; // T/F codice sconto
if (!(getflag(pil2, SOSPENSIONE_IMPOSTA) == _sosp_imposta)) return FALSE;
if (!(getflag(pil2, CODICE_SCONTO) == _cod_sconto)) return FALSE;
/* if (!_stesso_anno) // if (_stesso_anno) -> search() ha gia' settato la ricerca sull'anno
if (!(pil.get("ANNO") == pil2.get("ANNO")))
if (stesso_anno_fiscale(pil2)) return FALSE;
*/
// _stesso_anno si riferisce solo a pil2, dato che lo STESSOANNOFISCALE che conta e' quello
// dei doc originali e l'_anno e' quello di oggi (TODAY)
if ((_stesso_anno) && (pil2.get("ANNO")!=_anno)) return FALSE;
TRectype dest(LF_TAB); // reld e' un record di tipo tabella
leggi_da_ELD(dest,pil2.get("TIPODOC"));
// if (!(_stato_f_doc_f == dest.get("S9"))) return FALSE;
if (!(_codnum == dest.get("S5"))) return FALSE;
return TRUE;
}
// filterfunction per il campo numerico CODCF (la TExpression::eval() sbaglia perche' considera tutti i dati come stringhe)
bool TBatch_crea_doc::filterfunct(const TRelation* r)
{
TRectype& temp = r->curr(); // per accedere al record corrente senza dover sempre chiamare la funzione curr() della relazione
bool result = TRUE;
long l;
long firstcodcf, lastcodcf; // per non chiamare sempre app()
#ifndef _TDD_IN_FILTER
if (!_tipo_doc_dest.empty())
{
TRectype dummy(LF_TAB); // = pilota solo per inizializzarlo
result = result && ((leggi_da_ELD(dummy,_temp.get("TIPODOC"),_tipo_doc_des) == ELAB_FOUND);
}
#endif
l = temp.get_long("CODCF");
if ((firstcodcf = app()._first_codcf) > 0)
result = result && (l >= firstcodcf);
if ((lastcodcf = app()._last_codcf) > 0)
result = result && (l <= lastcodcf);
return result;
}
/* Raggruppa tutte le righe del documento doc che hanno uguali i seguenti campi:
- codice articolo (deve essere non blank)
- unita' di misura
- prezzo
- IVA
*/
void TBatch_crea_doc::raggruppa_righe (TRecord_array& doc)
{
TRectype pilota (LF_RIGHEDOC); // record corrente di raggruppamento
TRectype tempr (LF_RIGHEDOC); // prossimo record da raggruppare
TBit_array processed; // array per indicare quali righe sono gia' state processate
TBit_array tocopy(doc.rows()); // array che indica quali righe debbono essere copiate in doc2
tocopy.set(); // indica che tutte le righe sono da copiare
// si posiziona sul primo record che ha il codice articolo non vuoto
int i;
// salta le righe senza codice articolo (con CODART vuoto)
for (i=1; i<=doc.rows() && doc.row(i).get("CODART").empty() ; i++);
if (i>doc.rows())
{
message_box ("Tutti gli articoli sono privi di codice. Nessuna riga raggruppata.");
return;
}
TRectype confronto(LF_RIGHEDOC); // record per il confronto dei campi significativi
int current; // posizione dell'ultimo record valido trovato (per non ripetere sempre la ricerca dall'inizio)
do
{
current = i;
pilota = doc.row(i);
confronto.zero(); // imposta i campi significativi per il raggruppamento delle righe
confronto.put ("CODART", pilota.get ("CODART"));
confronto.put ("CODIVA", pilota.get ("CODIVA"));
confronto.put ("PREZZO", pilota.get ("PREZZO"));
confronto.put ("UMQTA", pilota.get ("UMQTA"));
processed.set(i); // la riga trovata e' processata (e' la riga pilota)
int prox; // numero della prossima riga da raggruppare
while (prox_riga (prox, doc, processed, confronto))
{
const real qta = pilota.get_real("QTA") + doc.row(prox).get_real("QTA");
pilota.put("QTA", qta); // aggiorna il contenuto della riga pilota
doc.row(current, FALSE) = pilota;
processed.set(prox); // indica che la riga e' stata processata
tocopy.reset(prox); // indica che la riga non e' da copiare, perche' inglobata nella riga pilota
}
// cerca la prossima riga pilota
bool skip = TRUE;
for (i=current+1; i<=doc.rows() && skip; i++)
skip = doc.row(i).get("CODART").empty() || processed[i];
i--;
}
while (i<=doc.rows()); // finche' ci sono righe da elaborare
// necessario usare questa var. nel ciclo for seguente perche'doc.rows viene valutata ad ogni ciclo,
// e diminuisce di una unita' ogni volta che viene cancellata una riga. Cio' provocherebbe la mancata cancellazione
// delle ultime righe della fattura.
int drows = doc.rows();
for (i=1; i<=drows; i++) // cancella le righe raggruppate
if (!tocopy[i])
doc.destroy_row (i, FALSE);
}
bool TBatch_crea_doc::prox_riga (int& prox, TRecord_array& doc, TBit_array& processed, TRectype& confronto)
{
bool found = FALSE;
for (int i=1; !found && i<=doc.rows(); i++)
if (!processed[i] && !doc.row(i).get("CODART").empty())
found = (doc.row(i) == confronto);
prox = i-1;
return found;
}
int ve6200 (int argc, char **argv)
{
TBatch_crea_doc a;
a.run (argc, argv, "Fatturazione");
return TRUE;
}