// ve6200.cpp: modulo per la generazione dei documenti in modo BATCH. #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #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::page_build(long first, byte rows) { TToken_string l(256); *cursor() = (TRecnotype)first; for (int r = 0; r < rows; r++, ++(*cursor())) { l.cut(0); const int last = fields().last(); for (int i = 0; i <= last; i++) { const TRecfield* rf = (TRecfield*)fields().objptr(i); const char* s = rf ? (const char*)*rf : ""; l.add(s); } // cambiamenti dalla routine TSheet::page_build : // 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); // char buffer[16]; // _ltoa(qta-qtaevasa,buffer,10); // TString daevadere(buffer); real n(qta-qtaevasa); l.add((const char *)n.string(11,3),TOKEN_QTA_DA_EVADERE); set_row(l, r); } } // 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); } // nasconde il codice elaborazione: ? _msk->show (F_CODICE_ELAB, 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 TDate d((const char*) _msk->get(F_DATA_ELAB)); // Data documenti finali _datadoc = d; _anno = d.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 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=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 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)) { pilota.put("QTA", pilota.get_real("QTA") + doc.row(prox).get_real("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; }