diff --git a/ve/batbeld.h b/ve/batbeld.h new file mode 100755 index 000000000..0616f90b1 --- /dev/null +++ b/ve/batbeld.h @@ -0,0 +1,11 @@ +// campi della tabella di gestione delle elaborazioni differite +#define F_CODICE 101 +#define F_DESCR 102 +#define F_TIPODOC 103 +#define F_STATO_I_DOC_I 104 +#define F_STATO_F_DOC_I 106 +#define F_TIPODOCDES 105 +#define F_STATO_F_DOC_F 107 +#define F_PROGRAMMA 108 +#define F_CODNUM 109 +#define F_AVVIA 110 // button per lanciare l'elaborazione selezionata diff --git a/ve/batbeld.uml b/ve/batbeld.uml new file mode 100755 index 000000000..b855fa8cf --- /dev/null +++ b/ve/batbeld.uml @@ -0,0 +1,122 @@ +#include "batbeld.h" + +TOOLBAR "" 0 20 0 2 +#include +ENDPAGE + +PAGE "Tabella elaborazioni differite" 0 0 0 0 + +STRING F_CODICE 8 // campo della maschera: stringa, id = F_CODICE, 8 caratteri +BEGIN + PROMPT 1 2 "Codice " // scrivi nella maschera alle coord. (x,y) = (1,2) il prompt "Codice" + FLAG "U" + FIELD CODTAB // campo del database tabelle (tab) in cui salvare il valore immesso dall'utente + CHECKTYPE REQUIRED // indica che il campo deve essere compilato per poter salvare + WARNING "E' necessario specificare un valore" + USE ELD // indica quale tabella utilizzare per le ricerche + INPUT CODTAB F_CODICE // cerca nel dbase la prima occorrenza di F_CODICE cercando nel campo CODTAB + DISPLAY "Codice@10" CODTAB // visualizza i codici trovati (CODTAB) + DISPLAY "Descrizione@50" S0 // visualizza la descrizione (campo S0 in uno spazio di 50 caratteri) + OUTPUT F_CODICE CODTAB // metti F_CODICE nel campo codtab + OUTPUT F_DESCR S0 // metti F_DESCR nel campo S0 + KEY 1 + HELP "Codice dell'elaborazione differita da eseguire" + MESSAGE ENABLE, F_PROGRAMMA +END + +STRING F_DESCR 50 +BEGIN + PROMPT 1 3 "Descrizione " + FIELD S0 + CHECKTYPE REQUIRED + WARNING "E' necessario specificare un valore" + USE ELD KEY 2 + INPUT S0 F_DESCR + DISPLAY "Descrizione@50" S0 + DISPLAY "Codice" CODTAB + COPY OUTPUT F_CODICE // usa il segmento di codice per OUTPUT F_CODICE + KEY 2 +END + +STRING F_TIPODOC 4 +BEGIN + PROMPT 1 4 "Tipo documento originale " + FIELD S6 // usa il campo S6 del database tab + CHECKTYPE REQUIRED + WARNING "E' necessario specificare un valore" + USE %TIP + INPUT CODTAB F_TIPODOC + DISPLAY "Codice" CODTAB + DISPLAY "Tipo documento@50" S0 + OUTPUT F_TIPODOC CODTAB +END + + +// STRING F_STATO_I_DOC_I 1 +// BEGIN +// PROMPT 1 5 "Stato del documento originale " +// FIELD S7 +// CHECKTYPE REQUIRED +// WARNING "E' necessario specificare un valore" +// END + +// STRING F_STATO_F_DOC_I 1 +// BEGIN +// PROMPT 1 6 "Stato finale del documento originale " +// FIELD S4 +// CHECKTYPE REQUIRED +// WARNING "E' necessario specificare un valore" +// END + +STRING F_TIPODOCDES 4 +BEGIN + PROMPT 1 7 "Tipo documento di destinazione " + FIELD S8 + CHECKTYPE REQUIRED + WARNING "E' necessario specificare un valore" + USE %TIP + INPUT CODTAB F_TIPODOCDES + COPY DISPLAY F_TIPODOC + OUTPUT F_TIPODOCDES CODTAB +END + +// STRING F_STATO_F_DOC_F 1 +// BEGIN +// PROMPT 1 8 "Stato finale del documento finale " +// FIELD S9 +// CHECKTYPE REQUIRED +// WARNING "E' necessario specificare un valore" +// END + +STRING F_CODNUM 4 +BEGIN + PROMPT 1 9 "Codice numerazione per il documento di destinazione: " + FIELD S5 + USE NUM + INPUT CODTAB F_CODNUM + DISPLAY "Codice" CODTAB + DISPLAY "Descrizione@50" S0 + OUTPUT F_CODNUM CODTAB + CHECKTYPE REQUIRED + WARNING "E' necessario specificare un valore" +END + +STRING F_PROGRAMMA 50 +BEGIN +// PROMPT 1 10 "Programma (nome + parametri): " + PROMPT 1 10 "Metodo di elaborazione " + FLAGS "G" + FIELD S1 + CHECKTYPE REQUIRED +END + +BUTTON F_AVVIA 21 2 +BEGIN + PROMPT 1 11 "Lancia elaborazione" + MESSAGE RUN,#F_PROGRAMMA + FL "D" +END + +ENDPAGE + +ENDMASK diff --git a/ve/ve6.cpp b/ve/ve6.cpp index f906a0203..efc182812 100755 --- a/ve/ve6.cpp +++ b/ve/ve6.cpp @@ -1,11 +1,10 @@ -#include -#include #include -#include +#include +#include #include "ve6.h" // dichiarazioni delle procedure -#define usage "Errore - Utilizzo: %s -1" +#define usage "Errore - Utilizzo: %s -1 -2 -3" int main( int argc, char** argv ) { @@ -15,7 +14,13 @@ int main( int argc, char** argv ) switch (r) { case 1: - rt = ve6100( argc, argv); + rt = ve6100( argc, argv ); // gestione tabella ELD + break; + case 2: + rt = ve6200 (argc, argv); // creazione fatture partendo da bolle + break; + case 3: + rt = ve6300 (argc, argv); break; default: error_box( usage, argv[0] ); diff --git a/ve/ve6.h b/ve/ve6.h index d08da09b9..c71413b66 100755 --- a/ve/ve6.h +++ b/ve/ve6.h @@ -1,15 +1,10 @@ -// Dichiarazione della classe per l'applicazione ve6.cpp +// Dichiarazione delle funzioni per ve6.cpp + +#if !defined (_VE6_H) +#define _VE6_H + +int ve6100 (int, char**); +int ve6200 (int, char**); +int ve6300 (int, char**); -#if !defined(_VE6_ELAB_STRUCT) -#define _VE6_ELAB_STRUCT -/* struttura in cui sono memorizzati i campi dell'elaborazione differita che - servono sia alla ve6gen che alle procedure particolari di generazione */ -typedef struct TElab_structTag -{ - TString tipo_doc_org; // tipo documento originale - TString tipo_doc_des; // tipo documento finale - TString stato_doc_ini; // stato documento originale prima dell'elaborazione - TString stato_doc_fin; // dopo l'elaborazione - TString codnum; // codice per la numerazione del documento di destinazione -} TElab_struct; #endif diff --git a/ve/ve6.url b/ve/ve6.url index 62f6a6974..5b94a3292 100755 --- a/ve/ve6.url +++ b/ve/ve6.url @@ -1,36 +1,23 @@ #include -/* ba1 -0 */ +/* ve6 */ MENU TASK_MENUBAR - SUBMENU MENU_FILE "~File" + SUBMENU MENU_FILE "~File" - -/* ba1 -1 */ +/* ve6 -1 */ MENUBAR MENU_BAR(1) MENU MENU_BAR(1) - SUBMENU MENU_FILE "~File" - ITEM BAR_ITEM(1) "~Test" + SUBMENU MENU_FILE "~File" - -/* ba1 -2 */ +/* ve6 -2 */ MENUBAR MENU_BAR(2) MENU MENU_BAR(2) - SUBMENU MENU_FILE "~File" - ITEM BAR_ITEM(1) "~Test" - ITEM BAR_ITEM(2) "~Debug" + SUBMENU MENU_FILE "~File" -/* ba1 -3 */ +/* ve6 -3 */ MENUBAR MENU_BAR(3) MENU MENU_BAR(3) - SUBMENU MENU_FILE "~File" - -/* ba1 -4 */ -MENUBAR MENU_BAR(4) - -MENU MENU_BAR(4) - SUBMENU MENU_FILE "~File" - - + SUBMENU MENU_FILE "~File" diff --git a/ve/ve6100.cpp b/ve/ve6100.cpp index 63e142373..94550575e 100755 --- a/ve/ve6100.cpp +++ b/ve/ve6100.cpp @@ -1,185 +1,58 @@ -// ve6100.cpp: modulo per la generazione delle fatture. +// ve6100.cpp: modulo per la gestione della tabella elaborazioni differite. -#include "ve6retv.h" // valori di ritorno dalle varie funzioni +#include +#include "batbeld.h" -class TCrea_fatture : public TElaborazioni +class TGestione_ELD : public Tab_application { -protected: - virtual bool menu (MENU_TAG); - virtual bool create () ; - virtual bool destroy(); +protected: // TRelation_application + virtual bool user_create() ; + virtual bool protected_record(TRectype& rec) ; + virtual void init_insert_mode(TMask& m) ; + virtual void init_modify_mode(TMask& m); + virtual int rewrite(const TMask& m); + virtual void init_query_mode (TMask& m); public: - TCrea_fatture (void) {} // costruttore + TGestione_ELD() {} + virtual ~TGestione_ELD() {} }; -bool TCrea_fatture::create() +inline bool TGestione_ELD::user_create() +{ return Tab_application::user_create(); } + +inline bool TGestione_ELD::protected_record(TRectype& rec) +{ return Tab_application::protected_record(rec); } + +inline void TGestione_ELD::init_insert_mode(TMask& m) { - cod_elab = "01"; // imposta il codice elaborazione (per il riferimento alla tabella ELD) - dispatch_e_menu(BAR_ITEM(1)); // chiama il metodo menu - return TRUE; + Tab_application::init_insert_mode(m); + m.disable (F_AVVIA); // disabilita il button quando il record non e' ancora stato registrato + return; } -bool TCrea_fatture::destroy() +inline int TGestione_ELD::rewrite(const TMask& m) +{ return Tab_application::rewrite (m); } + +void TGestione_ELD::init_modify_mode(TMask& m) { - delete _msk; - return TRUE; + Tab_application::init_modify_mode(m); + m.enable (F_AVVIA); // abilita la pressione del tasto solo quando il record e' stato registrato + TString temp = m.get(F_CODICE); + if (temp == "01") + m.enable(F_PROGRAMMA, FALSE); } -bool TCrea_fatture::menu(MENU_TAG) +void TGestione_ELD::init_query_mode (TMask& m) { - int err; // errore ritornato dalle funzioni - if (err = scan_doc()) // se durante la scansione c'è un errore, esci - return !errore_fatale(err); - - switch (ordinamento) // in base all'ordinamento, lancia diverse procedure di creazione - { - case CLIENTE: - // crea fatture raggruppando per cliente - err = per_cliente(); - break; - case AGENTE: - // crea fatture per agente - break; - case ZONA: - // crea fatture per zona - break; - case DATA_NUMDOC: - if (raggruppa) - // crea fatture per data/numero documento - else - // crea una fattura per ogni cliente - break; - default: - break; - } - if (err) while (!getchar()); // se c'è un errore, attende la pressione di invio - return !errore_fatale(err) // ritorna FALSE se c'è stato un errore fatale - } - -int per_cliente(void) -{ - TLocalisamfile f(LF_DOC); - TLocalisamfile rdoc(LF_RDOC); - int current = 0; // chiave corrente - TToken_string tempt; // ttoken string temporanea - TString cliente; - TRectype tempr (LF_DOC); - TRectype temprdoc (LF_RDOC); - TTable t("NUM"); // tabella numerazioni - int nrdoc=0; // numero di riga della fattura - - do - { - // memorizza il record del documento pilota - f.zero(); - tempt = _chiavi->row(current); // rileva la chiave corrente - codnum = tempt.get(0) - f.put ("CODNUM", codnum); // memorizza i valori della chiave corrente nel record - f.put ("ANNO", tempt.get()); - f.put ("PROVV", tempt.get()); - f.put ("NDOC", tempt.get()); - if (!f.read (_isequal)) // cerca il record corrispondente alla chiave corrente - { - error_box ("TCrea_fatture::per_cliente() : errore %d durante la lettura su doc", err); - return READ_ERROR; - } - tempr = f.curr(); // copia ilrecord del doc. pilota in tempr - - // imposta il numero documento per la fattura da creare - t.zero(); - t.put ("CODTAB", _elab.codnum); // codice numerazione per le fatture - t.read (_isgteq); // legge il primo record con lo stesso codice di numerazione - if (t.get("CODTAB") == _elab.codnum) // controlla che il codice numerazione sia effettivamente lo stesso - { - n = t.get("I1"); // legge l'ultimo numero di documento utilizzato (o il primo disponibile) - // supponiamo che sia l'ultimo 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 del documento pilota in doc - f.curr() = tempr // tutti i campi della fattura sono uguali al documento pilota, tranne alcuni (impostati più sotto) - f.put ("NDOC", n); // imposta il numero del documento - f.put ("TIPODOC", _elab.tipo_doc_des); // imposta il tipo di documento - f.put ("STATO", ???); // stato della fattura appena creata - - if ((err = f.write()) == NOERR) // se nonci sono problemi - { - t--; // si posiziona sul record precedente nella tabella numerazione - t.put ("I1", n); // imposta nuovo numero del documento - t.write(); // registra - } - else - { - switch (err) - { - case REINSERT: - message_box ("ve6100: Errore fatale: il record con la chiave specificata esiste già: impossibile sovrascrivere"); - break; - default: - message_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 - } - - // cerca la prima riga del documento pilota in rdoc - nrdoc = 1; // comincia dalla prima riga - temprdoc.zero(); - temprdoc.put ("CODNUM", tempr.get("CODNUM")); - temprdoc.put ("ANNO", tempr.get ("ANNO")); - temprdoc.put ("PROVV", tempr.get("PROVV")); - temprdoc.put ("NDOC", tempr.get("NDOC")); - - TRecord_array doc_originale; - doc_originale.read (temprdoc); // legge tutte le righe del documento originale - - // con la funzione doc_originale.row(i) ho l'i-esima riga del doc. originale - TRecord_array doc_destinazione; - temprdoc.put ("CODNUM", _elab.codnum); // imposta il codice numerazione per la fattura - - - /* - prendi la prima chiave - - ripeti - cerca su doc il record corrispondente alla chiave corrente - - prendi il codcf (codice cliente) // costruzion file pilota per il cliente corrente - prendi tutti i campi obbligatori // meglio: copia il record trovato in un oggetto record - - scrivi su doc il record relativo alla nuova fattura creata - cerca su rdoc la prima riga del doc. pilota // inserimento del doc. pilota nella fattura - copia le righe del doc. pilota nella fattura - segna a[0] come processato - - per ogni chiave dell'array (dopo la prima) - se non è processata - cerca su doc il record corrispondente - se codcf è uguale a codcf del doc. pilota // meglio: crea un record campione con codcf e campi obbligatori = a guelli del record pilota e cerca il - allora se i campi obbligatori sono uguali a quelli del doc. pilota - allora copia tutte le righe del doc. attuale nella fattura - indica il record come processato - - prendi dall'array la prima chiave non processata - finché la chiave corrente è oltre l'ultimo record. (chiave corrente == a.items() - */ - - - Per numerazione fatture: - TTable t ("NUM"); - metto in codtab il codice numerazione - leggo il record con quel codice - nel campi I1 c'è il numero del primo campo disponibile (o dell'ultimo utilizzato) - - } - + Tab_application::init_query_mode(m); + m.enable (F_AVVIA, FALSE); // disabilita il button anche in modalita' ricerca + return; +} int ve6100 (int argc, char **argv) { - TCrea_fatture a; - a.run (argc, argv, "Fatturazione"); - return 0; + TGestione_ELD a; + a.run (argc, argv, "Gestione elaborazioni differite"); + return TRUE; } diff --git a/ve/ve6200.cpp b/ve/ve6200.cpp new file mode 100755 index 000000000..391003fc8 --- /dev/null +++ b/ve/ve6200.cpp @@ -0,0 +1,1071 @@ +// 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_CLIENTE_DA); + if (temps.not_empty()) + first.put ("CODCF", temps); // codice cliente (v. filterfunct) + temps = _msk->get(F_CODICE_CLIENTE_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; +} diff --git a/ve/ve6300.cpp b/ve/ve6300.cpp new file mode 100755 index 000000000..94e2ea97b --- /dev/null +++ b/ve/ve6300.cpp @@ -0,0 +1,432 @@ +// ve6300.cpp. Composizione interattiva dei documenti. + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "ve6retv.h" +#include "ve6300.h" +#include "ve6gen.h" + +class TInterattivo_crea_doc : public TBatch_crea_doc +{ +private: + virtual bool menu (MENU_TAG); + virtual bool create (); + virtual bool destroy(); + +// int set_vars(); // setta le variabili della classe + int componi_doc_finale(); // corpo del programma + static bool tipo_doc_handler (TMask_field&, KEY); // handler per il campo tipo doc. destinaz. della maschera +// static bool filterfunct(const TRelation*); // funzione per filtrare i documenti originali + + int _rdoc; // numero di righe nel documento finale +public: + TInterattivo_crea_doc(void) {} + ~TInterattivo_crea_doc() {} +}; + +inline TInterattivo_crea_doc& app() { return (TInterattivo_crea_doc&) main_app(); } + +bool TInterattivo_crea_doc::create() +{ + _interattivo = TRUE; +// _stesso_anno_fiscale = FALSE; + + int cargc = argc(); + const char **vargv = argv(); + + if (cargc>=2) + { + if (cargc<5) fatal_box ("Numero di parametri insufficiente: chiave incompleta!"); + if (cargc>=5) + { + _codnum = vargv[2]; + _anno = vargv[3]; + _provv = vargv[4]; + _ndoc = vargv[5]; + } + if (cargc==7) _crea_doc = TRUE; + else _crea_doc = FALSE; + if (cargc>7) message_box ("Sono presenti piu' di 6 argomenti sulla linea di comando: possibile errore"); + } + + dispatch_e_menu(BAR_ITEM(1)); + return TRUE; +} + +bool TInterattivo_crea_doc::destroy() +{ + return TRUE; +} + +bool TInterattivo_crea_doc::menu(MENU_TAG) +{ +// if (errore_fatale (set_vars())) return FALSE; + if (errore_fatale (componi_doc_finale())) return FALSE; + return TRUE; +} + +/* +TInterattivo_crea_doc::set_vars() +{ + TMask m("ve6300.uml"); + + m.set_handler (F_TIPODOCDES, tipo_doc_handler); + if (m.run()==K_ESC) return ESC_PRESSED; + _datadoc = m.get(F_DATADOC); // data da assegnare al documento da creare + _first_codcf = _last_codcf = m.get_long(F_CODCF); // codice cliente + _tipo_doc_des = m.get(F_TIPODOCDES); // tipo del documento da creare + _codnum = m.get(F_CODNUM); // codice numerazione per il documento da creare + _anno << _datadoc.year(); // anno fiscale del documento da creare + _provv = m.get(F_PROVV); // indica se il la numerazione _codnum e' provvisoria o definitiva + + // cerca il record di ELD che corrisponde a _tipo_doc_des +// TRelation rel("ELD"); +// TString16 filter ("S8==\""); +// filter << _tipo_doc_des << '"'; +// TCursor curs(&rel, filter); +// if (curs.items()==0) +// { +// fatal_box (TString("Nessuna elaborazione genera documenti del tipo ") << _tipo_doc_des); +// return NO_ELABS; +// } +// else if (curs.items()>1) +// warning_box ("Trovate %d elaborazioni per la generazione dei documenti di tipo %s", curs.items(), (const char*)_tipo_doc_des); +// +// return 0; +} +*/ + +// handler per il tipo documento di destinazione +bool TInterattivo_crea_doc::tipo_doc_handler (TMask_field& field, KEY key) +{ + if (key == K_TAB) + { + if (field.to_check(key)) + { + TFixed_string tdd(field.get(),4); // tipo del documento destinazione selezionato + tdd.trim(); + TTable t("%TIP"); + t.zero(); + t.put ("CODTAB", tdd); // cerca tipo del documento destinazione + t.read (_isgteq); +/* 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") != tdd) // 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 *)tdd); + 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 + TString tipocf = (profilo_doc.get("TIPOCF", "MAIN")); + tipocf.cut(1); + field.mask().set(F_TIPOCF, tipocf); + } + } + + TMask& mask = field.mask(); + TFixed_string s(mask.get(F_TIPIDOC), 40); + if (key==K_ENTER || key==K_TAB) + return (s.find(field.get()) % 4) == 0; // per evitare che trovi "0010" in "00010002" + return TRUE; +} + +int TInterattivo_crea_doc::componi_doc_finale() +{ + 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 + TRectype tempr(LF_DOC); // record del documento originale che si sta elaborando + TRectype temprdoc (LF_RIGHEDOC); // record per trovare le righe dei documenti originale +// int nrdoc; // numero di righe scritte nella fattura + // bool end = FALSE; // true non ci sono piu' documenti originali da elaborare + bool altri; // TRUE se ci sono altri documenti da includere nella fattura +// se _crea_doc, il documento destinazione (testata) deve essere inizializzato +// con i valori del primo documento originale selezionato + bool primo_pilota = _crea_doc; + + 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 + + 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 if (_crea_doc) f.curr() = pilota; // tutti i campi della fattura sono uguali al documento pilota, tranne alcuni (impostati più sotto) + else { +// confronta f.curr() e pilota (se pilota ha dei campi diversi, segnalalo e chiedi conferma + } +*/ +// } + _first_codcf = _last_codcf = f.get_long("CODCF"); // valori del campo CODCF dei records first e last, per potervi accedere dalla filterfunct() + _tipo_doc_des = f.get ("TIPODOC"); // imposta il tipo di documento + _stato_f_doc_f = f.get ("STATO"); // stato della fattura appena creata + + TRelation rel (LF_DOC); + TString tdfilter(1024); + tdfilter =""; // non so se e' necessaria +#ifdef _TDD_IN_FILTER + // filtro costruito in base a tutti i tipi di doc. che hanno un ELD che li trasforma in _tipo_doc_des + tdfilter = td_ELD_to_filter(_tipo_doc_des); +#endif + + TSorted_cursor curs (&rel, "NDOC", tdfilter); // lista i documenti ordinati per numero + curs.set_filterfunction (filterfunct); + +// non dovrebbe servire : _raggruppa = TRUE; + _per_articolo = TRUE; + + // Cursore per selezionare le testate dei documenti + if (curs.items() == 0) // se non ci sono bolle allo stato richiesto, 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 + +// scandaglia tutto curs e setta _processed tutti i doc. originali che non sono selezionati + 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 (docs_sheet.run()==K_ESC) return ESC_PRESSED; + for (int i=0; i 1)) // se deve raggr. e ci sono almeno 2 righe + raggruppa_righe (doc_destinazione); + + // salva la fattura creata + 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 + }; // finche' i documenti non finiscono + if (no_elab) // se non ci sono bolle allo stato richiesto, indica errore + { + error_box ("Nessun documento elaborato."); + return NO_ORG_DOCS; + } + return 0; +} + +int ve6300 (int argc, char** argv) +{ + TInterattivo_crea_doc a; + a.run (argc, argv, "Composizione documenti"); + return 0; +} + +/* +TPerson p ("MATTEO LIGABUE"); +p.send_message( + "DISCLAIMER: se leggerai questo pseudocodice e lo troverai childish, sappi che dopo la prima + stesura non l'ho piu' modificato, quindi questa e' l'idea che inizialmente avevo del programma + di composizione interattiva."); +p.bye(); + +- il prg per ora fa: + +a) runna una maschera in cui chiede: + a1) il codice di numerazione del doc da comporre (+PROVV) + a2) il tipo di documento da comporre + a3) la data (AUTOMAGIC) + a4) TIPOCF/CODCF del doc da comporre (e degli originali da selezionare) + a5) tipo di documento originale (da TOGLIERE !!!) + +b) runna un TCursor_Sheet con i documenti individuati da scegliere ed elaborare + +c) runna un TInterattivo_sheet (TCursor_Sheet) con le singole righe da elaborare (selezionabili) + +d) se la relativa tabella ELD permette l'evasione di parti di riga, + a1) mostrare il TCursor_sheet o TSpreadsheet (TSheet_field con maschera ve6301.uml) + a2) che possa trattare l'evasione parziale (TCursor_sheet -> con un campo number staccato dallo sheet) + a3) oppure il TSpreadsheet (TSheet_field) con tutte le colonne disabilitate, tranne la QTA_DA_EVADERE + +il programma deve ancora: + +a) passare la trasformazione al ve6200, che nella sua parte centrale (elaborazione del singolo doc.) + deve avere la eventuale selezione (da richiedersi in base ad un flag che ve6200 e ve6300 devono + settare rispettivamente a FALSE e TRUE, alla propria entrata) delle singole righe.... + aggiornare la qtaevase dei singoli sorgenti... + lo stato del documento varia solo con la completa evasione delle righe !!! + +... da continuare ... + +- controllare lo stato dei documenti originali + +-*chiama una funzione che runna la maschera e copia i nomi dei campi in variabili private +-*chiama una funzione che trova il record di ELD relativo al documento destinazione specificato + e setta le rimanenti variabili private +-*chiama una funzione che trova i documenti (testate) validi. Usare un TSorted_cursor od un + TRecord_array + + componi la testata del documento originale con le variabili private (non metterci NDOC) + while l'utente non preme il button "Salva" per salvare il documento composto + se l'utente vuole inserire un documento dalla lista allora + mostra la lista + per ogni documento selezionato + se il flag "raggruppa unito" e' true, allora // caso doc. orig = BOLLE + fagli vedere le righe + attendi che prema un button + se preme ok aggiungi le righe al documento finale + end se ru=TRUE + altrimenti // caso doc. orig = ORDINI + fagli vedere le righe + attendi che selezioni le righe (possibilita' di selezionarle tutte) +// + usare un TBit_array per indicare se una riga va evasa tutta oppure se ne e' stata specificata una parte + settare a TRUE tutto il TBit_array; ?????????? + se doubleclicka una riga + chiedigli la quantita' da evadere (puo' essere inferiore alla quantita' ordinata su quella riga) + scrivi nel documento originale la quantita' evasa + setta il TBit_array per indicare che nella bolla deve essere scritta la quantita' evasa + end se dblclk riga +// + ...preferisco usare un TArray delle quantita' evase + + end altrimenti (ru=FALSE) + end per ogni documento selezionato + end se seleziona dei documenti + altrimenti // vuole aggiungere delle righe + leggi i campi della riga (settando automaticamente codnum, ecc.) + metti la riga letta nel documento finale + end altrimenti (inserimento righe) + end + + scrivi NDOC nella testata del documento + scrivi la testata del documento + salva il documento destinazione +end +*/ diff --git a/ve/ve6300.h b/ve/ve6300.h new file mode 100755 index 000000000..0ef6635e8 --- /dev/null +++ b/ve/ve6300.h @@ -0,0 +1,14 @@ +// Include file per ve6300.uml + +#define F_CODNUM 101 +#define F_TIPIDOC 102 +#define F_PROVV 103 +#define F_TIPODOCDES 104 +#define F_DESCR_TIPODOCDES 105 +#define F_DATADOC 106 +#define F_TIPOCF 107 +#define F_CODCF 108 +#define F_RAGSOC 109 +#define F_TIPODOCORG 110 +#define F_DESCR_TIPODOCORG 111 +#define F_INIDOCORG 112 \ No newline at end of file diff --git a/ve/ve6300.uml b/ve/ve6300.uml new file mode 100755 index 000000000..0e041e854 --- /dev/null +++ b/ve/ve6300.uml @@ -0,0 +1,118 @@ +PAGE "Selezione parametri" 0 0 0 0 + +#include + +BUTTON DLG_OK 9 2 +BEGIN + PROMPT 20 19 "" +END + +BUTTON DLG_CANCEL 9 2 +BEGIN + PROMPT 40 19 "" +END + +STRING F_CODNUM 4 +BEGIN +PROMPT 1 1 "Codice numerazione: " +FLAG "U" +CHECKTYPE REQUIRED +USE NUM KEY 1 +INPUT CODTAB F_CODNUM +DISPLAY "Codice" CODTAB +DISPLAY "Descrizione@50" S0 +OUTPUT F_CODNUM CODTAB +OUTPUT F_TIPIDOC S2 +OUTPUT F_PROVV S8 +HELP "Codice numerazione per il documento da creare" +END + +STRING F_TIPIDOC 40 +BEGIN +PROMPT 28 1 "Tipi documenti" +FLAG "" +END + +STRING F_PROVV 1 +BEGIN +PROMPT 84 1 "Provv" +FLAG "" +HELP "Indica se la numerazione e' provvisoria (P) o definitiva (D)" +WARNING "I tipi di numerazione ammessi sono provvisoria (P) e definitiva (D)" +CHECKTYPE REQUIRED +END + +STRING F_TIPODOCDES 4 +BEGIN +PROMPT 1 2 "Tipo documento: " +FLAG "U" +USE %TIP KEY 1 +INPUT CODTAB F_TIPODOCDES +DISPLAY "Codice" CODTAB +DISPLAY "Descrizione@50" S0 +OUTPUT F_TIPODOCDES CODTAB +OUTPUT F_DESCR_TIPODOCDES S0 +CHECKTYPE REQUIRED +HELP "Tipo del documento da creare" +END + +STRING F_DESCR_TIPODOCDES 50 +BEGIN +PROMPT 28 2 "Descrizione: " +USE %TIP KEY 1 +INPUT F_DESCR_TIPODOCDES S0 +DISPLAY "Descrizione@50" S0 +DISPLAY "Codice" CODTAB +COPY OUTPUT F_TIPODOCDES +END + +DATE F_DATADOC +BEGIN +PROMPT 1 3 "Data: " +FLAG "A" +CHECKTYPE REQUIRED +HELP "Data da assegnare al documento" +END + +STRING F_TIPOCF 1 +BEGIN +PROMPT 1 5 "Tipo Cliente/Fornitore " +FLAG "D" +// FLAG "U" +// HELP "Indica C se cliente, F se fornitore" +// WARNING "Ho detto: C se cliente, F se fornitore (obbligatorio)" +CHECKTYPE REQUIRED +END + +NUMBER F_CODCF 6 +BEGIN +PROMPT 1 6 "Codice cliente: " +FLAG "UR" +USE LF_CLIFO KEY 1 +INPUT TIPOCF F_TIPOCF +INPUT CODCF F_CODCF +DISPLAY "Codice" CODCF +DISPLAY "Descrizione@50" RAGSOC +OUTPUT F_CODCF CODCF +OUTPUT F_RAGSOC RAGSOC +HELP "Inserisci il codice del cliente/fornitore" +WARNING "Codice cliente/fornitore non trovato" +CHECKTYPE REQUIRED +END + +STRING F_RAGSOC 50 +BEGIN +PROMPT 27 6 "Ragione sociale " +FLAG "U" +USE LF_CLIFO KEY 2 +INPUT TIPOCF F_TIPOCF +INPUT RAGSOC F_RAGSOC +DISPLAY "Descrizione@50" RAGSOC +DISPLAY "Codice" CODCF +COPY OUTPUT F_CODCF +HELP "Inserisci la ragione sociale del cliente" +WARNING "Ragione sociale non trovata nell'elenco clienti/fornitori" +END + +END +ENDMASK diff --git a/ve/ve6301.uml b/ve/ve6301.uml new file mode 100755 index 000000000..efcd1b4a0 --- /dev/null +++ b/ve/ve6301.uml @@ -0,0 +1,22 @@ +PAGE "Selezione parametri" 0 0 0 0 + +#include + +BUTTON DLG_OK 9 2 +BEGIN + PROMPT 20 19 "" +END + +BUTTON DLG_CANCEL 9 2 +BEGIN + PROMPT 40 19 "" +END + +SPREADSHEET F_SHEET 70 15 +BEGIN +PROMPT 5 4 "" + +END + +END +ENDMASK diff --git a/ve/ve6gen.cpp b/ve/ve6gen.cpp index 8174f2a0a..307a25174 100755 --- a/ve/ve6gen.cpp +++ b/ve/ve6gen.cpp @@ -1,7 +1,6 @@ // Classe che contiene i data members comuni a tutti gli oggetti di creazione // e la funzione di scansione. -#include #include #include #include @@ -9,27 +8,11 @@ #include #include #include - +#include #include "ve6retv.h" // definizione dei valori di ritorno #include "ve6.h" #include "ve6000.h" // identificativi dei campi della maschera - -class TElaborazioni : public TApplication -{ -protected: - // i data members sono protected in modo che gli oggetti generatori - // possano accedervi senza la necessità di funzioni specifiche - TString_array *_chiavi; // array contenente i valori delle chiavi per ogni record selezionato da scan_doc - TString _codelab; // codice elaborazione differita - TElab_struct _elab; // struttura per memorizzare i campi significativi dei records di doc - int _ordinamento; // indica il tipo di ordinamento - bool _raggruppa; // indica se si deve raggruppare o no - - int scan_doc (void); // lancia le altre due procedure - int run_mask (void); // lancia la maschera e scandisce i records - int get_info (void); // imposta la struttura elab leggendo il record per l'elaborazione corrente - bool errore_fatale(int); // ritorna true se l'errore passato come argomento è nella lista degli errori fatali -}; +#include "ve6gen.h" // dichiarazione della classe bool TElaborazioni::errore_fatale (int err) { @@ -40,179 +23,10 @@ bool TElaborazioni::errore_fatale (int err) case ELAB_NOT_FOUND: case DOC_TYPE_NOT_FOUND: case READ_ERROR: + case ESC_PRESSED: + case NO_ELABS: return TRUE; default: return 0; } } - -int TElaborazioni::get_info(void) -{ - int err; - - // informazioni dalla tabella elaborazioni differite - TTable t("ELD"); // tabella elaborazioni differite - t.zero(); - t.put ("CODTAB", _codelab); // imposta il codice elaborazione da cercare - if (!(err = t.read (_isgteq))) // si posiziona sul record dell'elab. differita con codice cod_elab - { - error_box ("TElaborazioni::get_info() : errore di lettura %d da tab(ELD)", err); - return READ_ERROR; - } - if (t.get("CODTAB") != _codelab) // controlla se il codice trovato è proprio cod_tab - { - error_box ("TElaborazioni::get_info() : non esiste l'elaborazione con codice %s in tab(ELD)", (const char *)_codelab); - return ELAB_NOT_FOUND; - } - - // Imposta i dati relativi all'elaborazione differita corrente - _elab.tipo_doc_org = t.get("S6"); // tipo documento originale - _elab.tipo_doc_des = t.get ("S8"); // tipo documento destinazione - _elab.stato_doc_ini = t.get ("S7"); // stato iniziale del documento originale - _elab.stato_doc_fin = t.get ("S9"); // stato finale (dopo l'elaborazione) del documento originale - _elab.codnum = t.get ("S5"); // codice numerazione per il documento finale - - return 0; -} - -int TElaborazioni::run_mask(void) -{ - int err; - TMask *_msk = new TMask ("ve6000"); // carica la maschera - - // Imposta il flag di autorizzazione agente - TTable t("TIP"); // tabella tipi documento - t.zero(); // azzera i campi - t.put ("CODTAB", _elab.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") != _elab.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 *)_elab.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"); // necessario per aggiungere l'estensione - TConfig profilo_doc(profilo); // oggetto configurazione (file ini del documento) - TConfig p(CONFIG_DITTA); // crea l'oggetto per rilevare l'autorizzazione dall'ini della ditta - // gestione agente abilitata <==> abilitata in profilo documento e nell'ini della ditta - int agente = (profilo_doc.get_int ("CODAG", "PROFILO") && 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 test per 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) // se premuto esc, esci - return ESC_PRESSED; - - _ordinamento = _msk->get_int (F_ORDINAMENTO_EMISSIONE); - _raggruppa = _msk->get_int (F_RAGGRUPPA); - - TString temps; // stringa temporanea - - // Imposta i campi dei records campione per il filtraggio - TLocalisamfile f(LF_DOC); // file doc - f.zero(); // azzera i campi - TRectype first(f.curr()), last(f.curr()); // dichiara due records con la stessa struttura dei records di $doc - - first.put("TIPOCF", 'C'); // trattare solo clienti - last.put ("TIPOCF", 'C'); - first.put ("TIPODOC", _elab.tipo_doc_org); // tipo documento (da tab. ELD) - last.put ("TIPODOC", _elab.tipo_doc_org); - first.put ("STATO", _elab.stato_doc_ini); // stato documento originale - last.put ("STATO", _elab.stato_doc_ini); - - // codice cliente - temps = _msk->get(F_CODICE_CLIENTE_DA); - if (temps.not_empty()) - first.put ("CODCF", temps); - temps = _msk->get(F_CODICE_CLIENTE_A); - if (temps.not_empty()) - last.put ("CODCF", temps); - - // 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... - // ******************** N.B.: il campo ZONA va aggiunto a $doc. verificare se il campo è proprio ZONA ***************** - 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("CODCF", temps); - temps = _msk->get (F_CODICE_AGENTE_A); - if (temps.not_empty()) - last.put ("CODCF", temps); - } - - f.put ("STATO", _elab.stato_doc_ini); - if (! (err = f.read (_isgteq))) - error_box ("TElaborazioni::run_mask() : errore di lettura &d da doc", err); - if (f.get ("STATO") != _elab.stato_doc_ini) - { - error_box ("TElaborazioni::run_mask() : non esistrono documenti allo stato %s", (const char *)_elab.stato_doc_ini); - return NO_ORG_DOCS; - } - - do // scandisce tutti i records a partire dal primo che ha lo stato richiesto - { - TToken_string tempt; // ttoken string per aggiungere chiavi all'array - if (f.curr() >= first && f.curr() <= last) - { - tempt = f.get("CODNUM"); // utilizza la chiave 1 di $doc - tempt.add( (const char *)f.get("ANNO") ); - tempt.add( (const char *)f.get("PROVV") ); - tempt.add( (const char *)f.get ("NDOC") ); - _chiavi->add(tempt); // aggiunge la chiave del record alla lista - } - } - while (err = f.read(_isnext)); - if (err !=NOERR) - { - error_box ("TElaborazioni::run_mask() : errore di lettura %d da doc", err); - return READ_ERROR; - } - - if (!_chiavi->items()) // se l'array è vuoto, indica al chiamante che non ci sono documenti da raggruppare - { - error_box ("TElaborazioni::run_mask() : nessun documento originale soddisfa le condizioni richieste"); - return NO_ORG_DOCS; - } - - for (int i = 0; i<_chiavi->items()-1; i++) - message_box ("Record %d: %s", i, (const char *)_chiavi->row(i)); - - return 0; -} - -int TElaborazioni::scan_doc(void) -{ - int err; // codice ritornato dalle procedure - - if (err = get_info()) - return err; // ritorna al chiamante l'errore di get_info, senza eseguire run_mask - return run_mask(); // ritorna il codice di errore di run_mask -} diff --git a/ve/ve6gen.h b/ve/ve6gen.h new file mode 100755 index 000000000..21a3b62b7 --- /dev/null +++ b/ve/ve6gen.h @@ -0,0 +1,128 @@ +// Dichiarazione della classe generale. + +#ifndef _TELABORAZIONI_DECL +#define _TELABORAZIONI_DECL + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "ve6retv.h" +#include "ve6300.h" +#include "ve6gen.h" + +#include +//#include +#include "ve6.h" +#include + +#define _TDD_IN_FILTER + +#define STATO_PPT '*' +#define SET_PROCESSED TRUE +#define DONT_SET_PROCESSED FALSE + +class TElaborazioni : public TApplication +{ +protected: + // i data members sono protected in modo che gli oggetti generatori + // possano accedervi senza la necessità di funzioni specifiche + TString16 _codnum; // (stringa di 4) + TString16 _anno; // int _anno; + TString16 _provv; // char _provv; + TString16 _ndoc; // int _ndoc; + bool _crea_doc; // deve creare il documento di destinazione ? + int _ordinamento; // indica il tipo di ordinamento + bool _raggruppa; // indica se si deve raggruppare o no + bool _per_articolo; // indica se raggruppare le righe per codice articolo o no + int _chiave; // chiave di doc usata per selezionare i doc. originali + TBit_array _processed; // array in cui è indicato se un documento di _chiavi è stato processato o no + TString _tipo_doc_org; // tipo documento originale + TString _tipo_doc_des; // tipo documento finale + TString80 _stati_validi_doc_i;// lista stati documenti originali prima dell'elaborazione + TString _stato_f_doc_i; // dopo l'elaborazione + TString _stato_f_doc_f; // stato documento finale al termine dell'operazione +// TString _codnum; // codice per la numerazione del documento di destinazione + bool _sosp_imposta; // T/F sospensione imposta + bool _cod_sconto; // T/F codice sconto + bool _stesso_anno; // T/F STESSOANNOFISCALE in [RAGGR.] del .ini del doc pilota + TDate _datadoc; // data dei documenti che si vanno a creare + + bool errore_fatale(int); // ritorna true se l'errore passato come argomento è nella lista degli errori fatali +public: + TElaborazioni() : _provv(1) { _chiave = 2; } + ~TElaborazioni () {} +}; + +// TCursor_sheet con la on_key() customizzata per l'inserimento del campo QTAEVASA nelle righe +class TInterattivo_sheet : public TCursor_sheet +{ +protected: + virtual bool on_key(KEY); +public: + virtual void page_build(long first, byte rows); // modificata per fare apparire anche le qta' da evadere + TInterattivo_sheet(TCursor* cursor, const char* fields, const char* title, const char* head, byte buttons = 0) + : TCursor_sheet(cursor, fields, title, head, buttons) + {}; + virtual ~TInterattivo_sheet() {}; +}; + +class TBatch_crea_doc : public TElaborazioni +{ +protected: + bool _interattivo; // TRUE se e' stata attivata l'elaborazione interattiva; +// bool _stesso_anno_fiscale; // TRUE se i documenti originali debbono avere lo stesso anno fiscale del documento da creare + TString _descr_tipodocorg; // descrizione del tipo documento originale (solo come titolo del TSheet_array) + virtual bool menu (MENU_TAG); + virtual bool create (); + virtual bool destroy(); + + int run_mask (TRectype&, TRectype&); // lancia la maschera e scandisce i records + int per_cliente(TRectype&, TRectype&, const char*); // crea fatture ordinate tramite la elab_princ + int elab_princ(TSorted_cursor&); // elabora tutti i documenti del cursore che hanno un record ELD + bool search (TRectype&, TRectype&, TSorted_cursor&); // cerca il prossimo record da includere nel doc. destinazione + bool getflag (TRectype&, int); // ritorna i valori di due flag + static bool filterfunct(const TRelation*); // funzione di filtro per i campi non alfanumerici + void raggruppa_righe (TRecord_array&); // raggruppa le righe per codice articolo + bool prox_riga (int&, TRecord_array&, TBit_array&, TRectype&); // cerca la prossima riga da raggruppare + long _first_codcf, _last_codcf; // valori del campo CODCF dei records first e last, per potervi accedere dalla filterfunct() + bool elab_righe(TString metodo,bool raggr_parz,TRectype &tempr,TRecord_array &doc_destinazione,TRectype &temprdoc); + // elabora le righe (di doc_originale), mettendole in doc_destinazione + // usando il metodo metodo, tramite il record temprdoc gia' inizializzato + bool next_pilota(TSorted_cursor &curs,TRectype &pilota); + // cerca il prossimo documeto pilota in cursor tenendo conto di processed + int esiste_ELD(TSorted_cursor &curs,int i,bool set_proc = DONT_SET_PROCESSED); + // 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 leggi_da_ELD(TRectype &dest,TString _tipo_pilota,TString _tipo_dest = ""); + // legge dalla tabella ELD il record _tipo_pilota->_tipo_destinazione, lo mette in dest e ritorna l'errore + TString metodo(TRectype &rec); + // restituisce la stringa metodo di trasf. dal record ELD per rec->_tipo_destinazione + int statovalido(TRectype& rec); + // controlla che il documento rec sia in uno degli stati validi indicati nella sezione [RAGGRUPPA] del suo .ini + const char *td_ELD_to_filter(TString &_tipo_doc_des); + // trova il .ini di rec e lo restituisce + TString getini(TRectype& rec, int &err); + // prende RAGGRPARZ della sezione [RAGGRUPPA] + bool get_raggr_parz(TRectype& rec, int& err); + // ritorna TRUE se _stesso_anno_fiscale o STESSOANNOFISCALE del .ini di rec + bool stesso_anno_fiscale(TRectype& rec); + // setta le informazioni sugli stati del doc e le mette nelle relative variabili globali + int get_info(TRectype &doc); + // guarda se i documenti pil e pil2 sono compatibili per essere uniti nello stesso documento finale + bool doc_i_compatibili(TRectype &pil,TRectype &pil2); + +public: + TBatch_crea_doc () {} // costruttore + ~TBatch_crea_doc () {} +}; + +#endif // _TELABORAZIONI_DECL // diff --git a/ve/ve6retv.h b/ve/ve6retv.h index 82a64ead2..fcf635902 100755 --- a/ve/ve6retv.h +++ b/ve/ve6retv.h @@ -6,11 +6,18 @@ #define NO_ORG_DOCS 100 // indica che non ci sono documenti originali con le caratteristiche richieste #define ESC_PRESSED 101 // indica che è stato premuto il pulsante "Annulla" sulla maschera di selezione dei ranges #define RECORD_WRITE_ERROR 102 // errore nella scrittura di un record -#define CLIENTE 1 // codici ordinamento (codici ritornati dal radiobutton della maschera) +#define CLIFO 1 // codici ordinamento (codici ritornati dal radiobutton della maschera) #define AGENTE 2 #define ZONA 3 #define DATA 4 -#define ELAB_NOT_FOUND 107 // indica che non è stata trovato un record per il codice di elaborazione specificato -#define DOC_TYPE_NOT_FOUND 108 // indica che non è stato trovato un record per il tipo di documento specificato -#define READ_ERROR 109 // indica che c'è stato un errore in lettura +#define ELAB_NOT_FOUND 107 // indica che non è stato trovato un record per il codice di elaborazione specificato +#define ELAB_FOUND 108 // indica che è stato trovato un record per il codice di elaborazione specificato +#define DOC_TYPE_NOT_FOUND 109 // indica che non è stato trovato un record per il tipo di documento specificato +#define READ_ERROR 110 // indica che c'è stato un errore in lettura +#define SOSPENSIONE_IMPOSTA 111 // valori per un parametro di getflag() +#define CODICE_SCONTO 112 +#define ERR_STATO_NON_VALIDO 113 // errore: lo stato del documento non e' uno di quelli previsti nella sezione raggruppa +#define NO_ELABS 114 // non ci sono elaborazioni che producano il documento specificato +#define STATO_NON_VALIDO FALSE // lo stato del documento non e' uno di quelli previsti nella sezione raggruppa +#define STATO_VALIDO TRUE // lo stato del documento non e' uno di quelli previsti nella sezione raggruppa #endif