////////////////////////////////////////////////////////////// // Stampa documenti ////////////////////////////////////////////////////////////// #include #include #include #include #include #include #include "velib.h" #include "sconti.h" #include "ve1100.h" #include #define LISTADOC "listadoc" #define FAKETOTFLD 9999 // Queste classi (TDocisamfile e TRDocisamfile) servono nel costruttore di TDocumento_form // in modo da sostituire i file della relazione, ovvero LF_DOC e LF_RIGHEDOC. // Facendo in questo modo ogni get() del record, viene reindirizzata alla get() dei // TVariable_recfield, in modo da utilizzare nel form le istruzioni FIELD anche per i campi // virtuali. class TDocisamfile : public TLocalisamfile { TDocumentoEsteso *_doc; public: virtual TRectype& curr() const { return (TRectype&) *_doc; } virtual int readat(TRecnotype nrec, word lockop = _nolock); TDocisamfile(TDocumentoEsteso* doc) : TLocalisamfile(LF_DOC) { _doc = doc;} virtual ~TDocisamfile() {}; }; int TDocisamfile::readat(TRecnotype nrec, word lockop) { int err = TBaseisamfile::readat(nrec, _nolock); if (err == NOERR) { err = _doc->read(curr()); if (err == NOERR) { _doc->summary_reset(TRUE); // forza il ricalcolo perche' trattasi di documento diverso _doc->summary_filter(1); } } return err; } class TRDocisamfile : public TLocalisamfile { TDocumento *_doc; bool _normal_next; int _row; protected: TDocumento& doc() const { return *_doc;} public: void set_normal_next(const bool b = TRUE) { _normal_next = TRUE; } virtual int next(word lockop = _nolock) { return _normal_next ? TLocalisamfile::next(lockop) : NOERR; } virtual TRectype& curr() const ; void set_row(int r) { _row = r;} TRDocisamfile(TDocumento* doc) : TLocalisamfile(LF_RIGHEDOC) { _doc = doc; _row = 1; _normal_next = FALSE;} virtual ~TRDocisamfile() {}; }; TRectype& TRDocisamfile::curr() const { TRectype& rr = ((_row > 0 && _row <= _doc->rows()) ? (TRectype&) doc()[_row] : TLocalisamfile::curr()); return rr; } //////////////////////////////////////////////////////////////////////////// // classe TDocumento_form customizzata dalla Form per i documenti //////////////////////////////////////////////////////////////////////////// class TDocumento_form : public TForm { static TDocumento_form* _form; TRelation &_firmrel; // relazione di gestione dei dati della ditta corrente TString _module; // codice del modulo di carta associato a questo al form TString_array _exclude_array; // array di tipi riga e articoli da escludere dalla stampa TAssoc_array _doc_totals; // Assocarray per codice numerazione contenente i totali nel caso di stampa lista documenti TString_array _group_decimals; // Array di TToken_string per ogni gruppo definito in GENERAL. // Il primo elelemento della token_string conterra' il numero del gruppo // il secondo il n.ro di decimali per importi in lire ed il terzo il n.ro // di decimali per gli importi in valuta TSorted_cursor * _sorted_cur; // Valido solo per i form di lista documenti TDocisamfile* _docfile; TRDocisamfile* _rdocfile; TDocumentoEsteso * _doc; // Documento da stampare bool _valid, _cli_loaded; // flag che indica se il form e' valido | se l'oggetto cliente è già stato caricato // I gruppi sono cosi' predefiniti: // PRI_DECIMALS corrisponde al gruppo 29 // QTA_DECIMALS corrisponde al gruppo 30 // IMP_DECIMALS corrisponde al gruppo 31 // Altri gruppi definiti dall'utente saranno cosi' sintatticamente impostati: // NEW_GROUP // Dove e' il numero del gruppo // e' il numero di decimali per i documenti in lire // e' il numero di decimali per i documenti in valuta // ATTENZIONE: e' importante che i nomi dei gruppi utilizzati per modificare le pictures non siano usati per // per altri messaggi. Inoltre un TForm_item che appartiene ad un gruppo di modifica picture // non puo' appartenere ad un altro gruppo dello stesso tipo, ad esempio i gruppi 29 e 30 contemporaneamente. // Puo' pero' appartenere anche ad altri gruppi che non siano utilizzati per lo scopo qui definito protected: virtual void extended_parse_general(TScanner &); // gestione dei parametri estesi nella sezione general virtual bool validate(TForm_item &, TToken_string &); // gestione dei messaggi estesi nei campi bool print_on_body(int r); // Trascrive la riga 'r' del documento sul body. Ritorna TRUE se va stampata, FALSE se va saltata void print_header(TPrinter& p); // Stampa la testata void print_footer(TPrinter& p); // Stampa la pedata static void doc_header_handler(TPrinter& p); static void doc_footer_handler(TPrinter& p); void output_values(const TRectype & rec, const char * output, TForm_item & cf); public: void edit_picture(TForm_item & f, const int dec); void modify_pictures(); virtual TCursor* cursor() const { return _sorted_cur ? _sorted_cur : TForm::cursor(); } void hide_sections(); bool is_faketotfld(); void print_documento(); bool valid() const { return _valid; } bool doc_arrange(); int ncopie() const { return _doc->tipo().ncopie(); } const TString &get_module_code() const { return _module; } // ritorna il codice del modulo di carta TString_array& exclude_list() { return _exclude_array; } TDocumentoEsteso& doc() { return *_doc; } void set_doc_ext(TRectype* doc); TDocumento_form(TRectype& doc, TRelation& rel, bool definitiva, bool interattivo, bool aggiuntivo); TDocumento_form(const char* form, TRelation& rel); virtual ~TDocumento_form(); }; TDocumento_form* TDocumento_form::_form = NULL; void TDocumento_form::set_doc_ext(TRectype* doc) { CHECK(_doc == NULL, "Doppio documeto esteso"); if (doc != NULL) _doc = new TDocumentoEsteso(*doc); else _doc = new TDocumentoEsteso; _docfile = new TDocisamfile(_doc); _rdocfile = new TRDocisamfile(_doc); _rdocfile->set_normal_next(); relation()->replace(_docfile,0); relation()->replace(_rdocfile,1); if (_doc->physical_rows() > 0) relation()->update(); } static TTipi_documento_cache __tipi; TDocumento_form::TDocumento_form(TRectype& doc, TRelation& rel, bool definitiva, bool interattivo, bool aggiuntivo) : _firmrel(rel), _sorted_cur(NULL), _docfile(NULL), _rdocfile(NULL), _doc(NULL), _valid(FALSE) { _form = this; const TString4 tipodoc(doc.get(DOC_TIPODOC)); TFilename nomeform; const TTipo_documento & tipo = __tipi.tipo(tipodoc); if (tipo.empty()) { error_box(FR("Tipo di documento non valido: '%s'"), (const char*)tipodoc); return; } if (tipo.printable()) { // se non ci sono errori procede con la stampa nomeform = aggiuntivo ? tipo.additional_print_profile() : tipo.main_print_profile(); // legge il nome del form di stampa nomeform.trim(); TFilename test(nomeform); test.ext("frm"); if (!test.custom_path()) { error_box(FR("Nome form di stampa '%s' non valido per il tipo documento %s"), (const char*)nomeform, (const char*)tipodoc); return; } } else return; _valid = TRUE; read(nomeform); _cli_loaded= FALSE; set_doc_ext(&doc); // istanzia TDocumentoEsteso modify_pictures(); dec_parm p; const int items = _group_decimals.items(); for (int i = 0; i< items; i++) { TToken_string& t = _group_decimals.row(i); int gruppo = t.get_int(0); switch (gruppo) { case GROUP_QTA : p.qta_lit = t.get_int(1);p.qta_val = t.get_int(2); break; // add other groups here default: break; } } _doc->set_decimals(p); // Inizializza lo sfondo delle pagine normali set_background(3, TRUE); TPrinter& pr = printer(); pr.setheaderhandler(doc_header_handler); TPrint_section& head = section('H'); pr.headerlen(head.height()); pr.setfooterhandler(doc_footer_handler); const TPrint_section& foot = section('F'); pr.footerlen(foot.height()); } // costruttore per stampa lista documenti (uso convenzionale dei forms) TDocumento_form::TDocumento_form(const char* form, TRelation& rel) : TForm(form), _firmrel(rel), _docfile(NULL), _rdocfile(NULL), _doc(NULL), _valid(FALSE) { _cli_loaded= FALSE; _sorted_cur = new TSorted_cursor(relation(), "PROVV|ANNO|CODNUM|STATO|DATADOC|NDOC"); } TDocumento_form::~TDocumento_form() { // Membri di cui NON va fatta la delete: // _docfile : perche' viene fatta dal distruttore di TRelation // _rdocfile : perche' viene fatta dal distruttore di TRelation if (_doc) delete _doc; if (_sorted_cur) delete _sorted_cur; } void TDocumento_form::hide_sections() { // Scorre tutte le sezioni e nasconde gli items const char s[3] = { 'B', 'G', 'H' }; for (int sn = 0; sn < 3 ; sn++) { const char sc = s[sn]; for (pagetype pt = odd_page; pt <= last_page; pt = pagetype(pt+1)) { TPrint_section* sec = exist(sc, pt); if (sec == NULL) continue; TForm_item* f; for(word i = 0; i < sec->fields(); i++) { f = &(sec->field(i)); f->hide(); } } } } bool TDocumento_form::is_faketotfld() { TPrint_section* fl = exist('F',last_page); if (fl != NULL) { TForm_item* f; for(word i = 0; i < fl->fields(); i++) { f = &(fl->field(i)); if (f->id() == FAKETOTFLD) return TRUE; } } return FALSE; } bool TDocumento_form::doc_arrange() { TPrinter& pr = printer(); if (char_to_pos() != '\0' || (ipx()+ipy()+fpx()) != 0) { if (offset_x() != 0 || offset_y() != 0) { error_box(FR("Non e' possibile settare contemporaneamente gli offset" " e i parametri di posizionamento del modulo %s."), (const char*)name()); return FALSE; } else if (pr.printtype() == winprinter) _form->arrange_form(); } else pr.set_offset(_form->offset_y(), _form->offset_x()); return TRUE; } void TDocumento_form::print_documento() { TPrinter& pr = printer(); // stampa tutte le righe TPrint_section& body = section('B'); // TPrint_section& foot = section('F'); // qui verificare TPrint_section* sect = exist('B', last_page); TString last_section; const int righe = _doc->rows(); bool one_row_printed = FALSE; const bool update_relation = relation()->has_children(1); set_last_page(FALSE); // E' importante settare questo flag, per evitare "Falli di Piede" eheh :-) for (int r=1; r<=righe; r++) { _rdocfile->set_row(r); if (update_relation) relation()->update(1); if (!print_on_body(r)) continue; if (sect) { sect->update(); const TString& curr_section = sect->field(0).get(); if (r == 1 || curr_section != last_section) { last_section = curr_section; const word h = sect->height(); for (word j = 0; j < h; j++) pr.print(sect->row(j)); } } const word h = body.height(); for (word j = 0; j < h; j++) pr.print(body.row(j)); if (!one_row_printed) one_row_printed = TRUE; if ((*_doc)[r].tipo().formfeed()) pr.formfeed(); } if (!one_row_printed) { // Riga fasulla... per stampare l'intestazione obbligatoriamente, // anche in caso che non vi siano righe nel documento o che siano tutte escluse TPrintrow r; pr.print(r); } if (_doc->tipo().add_conai() && _doc->clifor().vendite().get_bool("CONAIASS")) { TRiga_documento last_row(_doc); TConfig c(CONFIG_DITTA); last_row = _rdocfile->curr(); _rdocfile->zero(); TString80 desc(c.get("DESCCONAIASS")); if (desc.empty()) desc = "Contributo CONAI assolto"; _rdocfile->put(RDOC_DESCR, desc); body.update(); const word h = body.height(); if (pr.rows_left() <= h+1) // salto pagina pr.formfeed(); for (word j = 0; j < h; j++) pr.print(body.row(j)); _rdocfile->curr() = last_row; } TPrint_section* last_foot = exist('F', last_page, FALSE); if (last_foot != NULL) { const word lfh = last_foot->height(); const word left = pr.rows_left() + pr.footersize(); if (lfh > left) // Se l'ultimo footer e' troppo grande ... pr.formfeed(); // Stampa il footer normale pr.footerlen(lfh); // Fondamentale! } set_last_page(TRUE); pr.formfeed(); // Stampa l'ultimo footer // Rimette ad 1 il numero della pagina pr.setcurrentpage(1); } void TDocumento_form::print_header(TPrinter& pr) { TPrint_section& head = section('H'); head.update(); const word r = head.height()-1; for (word j = 0; j <= r; j++) pr.setheaderline(j, head.row(j)); } void TDocumento_form::print_footer(TPrinter& pr) { const bool p = _form->page(pr)>0; TPrint_section& foot = section('F',p ? odd_page : last_page); foot.update(); word r = foot.height(); for (word j = 0; j < r; j++) pr.setfooterline(j, foot.row(j)); } void TDocumento_form::doc_header_handler(TPrinter& pr) { pr.resetheader(); _form->print_header(pr); } void TDocumento_form::doc_footer_handler(TPrinter& pr) { pr.resetfooter(); _form->print_footer(pr); } void TDocumento_form::edit_picture(TForm_item & fi, const int dec) { const TString old_picture = fi.picture(); TString new_picture(20); const int comma_pos = old_picture.find(','); const int stop_pos = old_picture.find('.'); char migliaia_char = '.'; if (comma_pos > 0 && stop_pos > 0) { if (stop_pos > comma_pos) migliaia_char = ','; } if (old_picture.empty()) // picture di default { new_picture = "."; // in lire if (dec > 0) new_picture << dec; // in valuta } else { if (dec == 0) return; // 0 non cambia la picture new_picture = old_picture; // Resetta la picture: toglie eventuali decimali gia' presenti... const int pos = new_picture.rfind(migliaia_char == '.' ? ',' : '.'); if (pos >= 0) new_picture.cut(pos); // Se si decide di metterne... altrimenti ndec -1 lascia la picture senza decimali if (dec > 0) { TString16 dec_to_add; for (int i = 0; i < dec; i++) dec_to_add << "@"; // aggiunge tanti "@" quanti sono i decimali voluti if (migliaia_char == ',') new_picture << "."; // se ha trovato la virgola come separatore di migliaia significa che deve aggiungere il punto decimale else new_picture << ","; // altrimenti aggiunge la solita virgola new_picture << dec_to_add; // infine aggiunge i decimali richiesti } } const int w = old_picture.len(); // se la picture eccede la dimensione della picture, toglie i caratteri piu' a sx int exceed = w - new_picture.len(); if (exceed<0 && w>0) { exceed=::abs(exceed); new_picture = new_picture.mid(exceed,new_picture.len()-exceed); if (new_picture[0] == migliaia_char) new_picture.ltrim(1); } fi.set_picture(new_picture); // setta la nuova picture } void TDocumento_form::modify_pictures() { const bool valuta = _doc->in_valuta(); const char sechar[4] = { 'B', 'F', 'G', 'H' }; for (int sn = 0; sn < 4 ; sn++) { const char sc = sechar[sn]; for (pagetype pt = odd_page; pt <= last_page; pt = pagetype(pt+1)) { TPrint_section* sec = exist(sc, pt); if (sec != NULL) for (word i = 0; i < sec->fields() ; i++) { TForm_item& fi = sec->field(i); if (fi.in_group(GROUP_PRICES)) edit_picture(fi, _doc->decimals(TRUE)); else if (fi.in_group(GROUP_IMPORTI)) edit_picture(fi, _doc->decimals()); else { const int items = _group_decimals.items(); // numero di gruppi definiti for (int j = 0; j < items; j++) { TToken_string& r = _group_decimals.row(j); const int group = r.get_int(0); if (fi.in_group(group)) // trova se appartiene al gruppo, modifica la picture { edit_picture(fi,valuta ? r.get_int(2) : r.get_int(1)); break; // considera solo il primo gruppo trovato } } } } } } } bool TDocumento_form::print_on_body(int r) { TPrint_section& body = section('B'); TRiga_documento& riga = doc()[r]; const TString & tiporiga = riga.get(RDOC_TIPORIGA); bool ok = TRUE; FOR_EACH_ARRAY_ROW(_exclude_array, i, row) { if (row->starts_with(tiporiga)) { const int pos = row->find(','); if (pos <= 0) ok = FALSE; else { const TString & codart = riga.get(RDOC_CODART); const TString art_to_exclude(row->mid(pos+1)); ok = art_to_exclude.not_empty() && (art_to_exclude.find(codart) < 0); } if (!ok) break; } } if (ok) body.update(); // Crea la vera riga di stampa, eventuali allineamenti avverranno nella validate(), come al solito. return ok; } void TDocumento_form::extended_parse_general(TScanner &scanner) { // se viene riconosciuto il token per l'impostazione del modulo legge il codice... if (scanner.key() == "MO") _module= scanner.string(); // Legge i decimali necessari per gli arrotondamenti (il primo per gli importi in lire, l'altro per quelli in valuta) // if (scanner.key() == "PR") // { // TToken_string t; // t.add(GROUP_PRICES);t.add(scanner.integer());t.add(scanner.integer()); // _group_decimals.add(t); // } // Stessa cosa per le quantita' if (scanner.key() == "QT") { TToken_string t; t.add(GROUP_QTA);t.add(scanner.integer());t.add(scanner.integer()); _group_decimals.add(t); } // Stessa cosa per gli importi in genere // if (scanner.key() == "IM") // { // TToken_string t; // t.add(GROUP_IMPORTI);t.add(scanner.integer());t.add(scanner.integer()); // _group_decimals.add(t); // } if (scanner.key() == "NE") { TToken_string t; t.add(scanner.integer());t.add(scanner.integer());t.add(scanner.integer()); _group_decimals.add(t); } // Esclude certi tipi riga e codici articolo if (scanner.key() == "EX") { TToken_string s(scanner.string(),','); _exclude_array.add(s); } } void TDocumento_form::output_values(const TRectype & rec, const char * output, TForm_item & cf) { TToken_string out(output, '!'); TString curr; for (const char * str = out.get(0); str; str = out.get()) { // scansione sugli elementi dell'output curr = str; int poseq = curr.find('='); // divide la stringa corrente in lvalue e rvalue if (poseq < 0) cf.set(rec.get(curr)); else { int posrv = poseq+1; if (poseq >= 0 && curr[posrv] == '=') posrv++; TString16 fld(curr.left(poseq)); // preleva il nome del campo del form alla sinistra dell'uguale const TString dat(rec.get(curr.mid(posrv))); // preleva il nome del campo del file alla destra dell'uguale e lo legge dal record if (fld[0] == '#') fld.ltrim(1); if (fld.right(1) == "@") { // se c'è la a-commerciale è un gruppo char sec = cf.section().section_type(); pagetype pt = cf.section().page_type(); int group = atoi(fld); if (fld.find("->") >= 0) { // se nel gruppo c'è la freccia si riferisce ad un'altra sezione sec = fld[0]; pt= (fld[1] != '-') ? char2page(fld[1]) : even_page; } TPrint_section &fs = section(sec, pt); word itms = fs.fields(); for (word j=0; j|} // dove: è un riferimento alla relazione di gestione dei dati della ditta (es. 113@->DENCOM è la denominazione del comune di residenza della ditta) // è uno delle macro seguenti: // !RAGSOC ragione sociale // !IND indirizzo (fiscale se c'è, oppure di residenza) // !NUM numero civico (fiscale se c'è, oppure di residenza) // !CAP CAP (fiscale se c'è, oppure di residenza) // !COM comune (fiscale se c'è, oppure di residenza) // !PROV provincia (fiscale se c'è, oppure di residenza) // !IVA partita iva // !CF codice fiscale // !TEL numero di telefono (con prefisso) // !FAX numero di fax (con prefisso) // !REGSOC numero di registrazione presso il Tribunale // !CCIAA numero di registrazione presso la camera di commercio // nota: la relazione della ditta è così strutturata: // %NDITTE (9) Dati ditte // + %ANAGR (6) Anagrafica generale (indirizzo, ecc.) // + %COMUNI (113@) Comune di residenza // + %COMUNI (213@) Comune di residenza fiscale TString in(s.get()); if (in[0]!='!') { cf.set(_firmrel.curr().get(in)); return TRUE; } else { in.ltrim(1); const bool _fisc= _firmrel.lfile(6).get("INDRF").not_empty(); if (in=="RAGSOC") { cf.set(_firmrel.lfile().get("RAGSOC")); return TRUE; } if (in=="IND") { if (_fisc) cf.set(_firmrel.lfile(6).get("INDRF")); else cf.set(_firmrel.lfile(6).get("INDRES")); return TRUE; } if (in=="NUM") { if (_fisc) cf.set(_firmrel.lfile(6).get("CIVRF")); else cf.set(_firmrel.lfile(6).get("CIVRES")); return TRUE; } if (in=="CAP") { if (_fisc) cf.set(_firmrel.lfile(6).get("CAPRF")); else cf.set(_firmrel.lfile(6).get("CAPRES")); return TRUE; } if (in=="COM") { if (_fisc) cf.set(_firmrel.lfile(-213).get("DENCOM")); else cf.set(_firmrel.lfile(-113).get("DENCOM")); return TRUE; } if (in=="PROV") { if (_fisc) cf.set(_firmrel.lfile(-213).get("PROVCOM")); else cf.set(_firmrel.lfile(-113).get("PROVCOM")); return TRUE; } if (in=="IVA") { cf.set(_firmrel.lfile(6).get("PAIV")); return TRUE; } if (in=="CF") { cf.set(_firmrel.lfile(6).get("COFI")); return TRUE; } if (in=="TEL") { valore = _firmrel.lfile().get("PTEL"); valore << "/" << _firmrel.lfile().get("TEL"); cf.set(valore); return TRUE; } if (in=="FAX") { valore = _firmrel.lfile().get("PFAX"); valore << "/" << _firmrel.lfile().get("FAX"); cf.set(valore); return TRUE; } if (in=="REGSOC") { valore = _firmrel[LF_UNLOC].get("REGIMP"); valore.insert(" ", 2); valore.insert(" ", 6); valore.insert(" ", 11); valore.insert(" ", 21); valore.insert("Reg.Imp. ", 0); cf.set(valore); return TRUE; } if (in=="CCIAA") { valore = _firmrel[LF_UNLOC].get("NUMCCIAA"); const TString & data = _firmrel[LF_UNLOC].get("DATAICCIAA"); if (data.not_empty()) valore << " del " << data; cf.set(valore); return TRUE; } } } // fine _DITTA if (code== "_CLIENTE") { // lettura dei dati del cliente // sintassi: _CLIENTE,{|} // dove: è un riferimento alla relazione di gestione dei dati del cliente // è uno delle macro seguenti: // !RAGSOC ragione sociale // !CAP Codice Avviamento Postale (viene implementato un messaggio perche' sugli occasionali ha un nome campo diverso!!) // !IND indirizzo // !NUM numero civico // !INDNUM indirizzo + numero civico // !COM comune // !PROV provincia // !TEL primo numero di telefono (con prefisso) // !TEL2 secondo numero di telefono (con prefisso) // !TEL3 terzo numero di telefono (con prefisso) // !FAX numero di fax (con prefisso) // !COM-> accede ai campi del comune di residenza cliente // !COMN-> accede ai campi del comune di nascita del cliente TCli_for & cli_for = _doc->clifor(); TOccasionale & cli_occ = _doc->occas(); const bool occasionale = cli_for.occasionale(); TString in(s.get()); // prende la macro o il fieldref if (in[0] != '!') { // Controlla l'esistenza dei campi... if (occasionale && cli_occ.exist(in)) valore = cli_occ.get(in); if (!occasionale && cli_for.exist(in)) valore = cli_for.get(in); cf.set(valore); return TRUE; } in.ltrim(1); if (in=="INDNUM") { valore = occasionale ? cli_occ.get(OCC_INDIR) : cli_for.get(CLI_INDCF); valore << " " ; valore << (occasionale ? cli_occ.get(OCC_CIV) : cli_for.get(CLI_CIVCF)); cf.set(valore); return TRUE; } if (in.find("COM") == 0) { const bool nascita = in[3] == 'N'; const int p = in.find("->"); if (p > 0) in.ltrim(p + 2); TLocalisamfile com(LF_COMUNI); if (nascita) { com.put(COM_STATO, occasionale ? cli_occ.get(OCC_STATONASC) : cli_for.get(CLI_STATONASC)); com.put(COM_COM, occasionale ? cli_occ.get(OCC_COMNASC) : cli_for.get(CLI_COMNASC)); } else { com.put(COM_STATO, occasionale ? cli_occ.get(OCC_STATO): cli_for.get(CLI_STATOCF)); com.put(COM_COM, occasionale ? cli_occ.get(OCC_COM): cli_for.get(CLI_COMCF)); } if (com.read() == NOERR) cf.set(com.get(in)); return TRUE; } if (in.find("CAP") == 0) { valore = occasionale ? cli_occ.get(OCC_CAP) : cli_for.get(CLI_CAPCF); cf.set(valore); return TRUE; } if (in.find("TEL") == 0) { if (!occasionale) { if (in.len() == 3) in << "1"; const TString num(cli_for.get(in)); in.insert("P"); valore = cli_for.get(in); valore << "/" << num; } cf.set(valore); return TRUE; } if (in=="FAX") { if (!occasionale) { valore = cli_for.get("PFAX"); valore << "/" << cli_for.get("FAX"); } cf.set(valore); return TRUE; } if (in=="RAGSOC") { valore = occasionale ? cli_occ.get(in) : cli_for.get(in); valore.strip_double_spaces(); cf.set(valore); return TRUE; } } // fine _CLIENTE if (code == "_DESCRIGA") { // Messaggio per reperire la descrizione estesa sulle righe del documento const TRectype &rdoc= cursor()->curr(LF_RIGHEDOC); TString descrizione = rdoc.get(RDOC_DESCR); const bool desclunga = rdoc.get_bool(RDOC_DESCLUNGA); if (desclunga) { const TString& dest = rdoc.get(RDOC_DESCEST); if (!dest.blank()) descrizione << dest; } int nfields = s.items(); for (int j = 1; j < nfields; j++) { const TString & fld = s.get(j); TForm_item & f = cf.find_field(fld); const TString & val = f.get(); if (!val.blank()) descrizione << ' ' << val; } cf.set(descrizione); TParagraph_string p(descrizione, cf.width()); const int h = cf.height(); int i; for (i = 0; p.get() != NULL && i < h; i++); // cf.put_paragraph(descrizione); // Setta l'altezza effettiva del body, per evitare sprechi di righe cf.section().set_height(p.empty() ? 1 : i); return TRUE; } if (code== "_RIEPILOGOIVA") { // tabella riepilogo aliquote iva e relative imposte // sintassi: _RIEPILOGOIVA,,, // dove: è uno dei seguenti: // 1 = codici IVA a regime normale // 2 = codici IVA da ventilare // 4 = codici IVA esenti // 8 = codici IVA non imponibili // 16 = codici IVA non soggetti // oppure la combinazione di uno o piu' di essi: // 12 = 4+8, 19 = 1+2+16, 29 = 1+4+8+16 ecc... // dove: è uno dei seguenti: // COD colonna dei codici // IMP colonna degli imponibili // IVA colonna delle imposte // ALI colonna delle aliquote // DES colonna delle descrizioni (stampata solo se il regime IVA non e' normale) // dove: è uno dei seguenti: // 0 indica di non leggere il successivo codice IVA nella tabella riepilogativa // 1 indica di leggere il successivo codice IVA nella tabella riepilogativa if (s.items() == 4) { byte selector = byte(atoi(s.get())); // il primo parametro e' il selettore del tipo di codice if (selector != 0) { _doc->summary_filter(selector); TString16 what = s.get(); // cosa deve stampare ? TString value(_doc->summary_get(what)); // Piglia il valore dalla riga selezionata sulla tabellina what = s.get(); const bool next = what == "1"; // deve cambiare elemento ? if (next) _doc->summary_set_next(); cf.set(value); } } else error_box("Numero di parametri non corretto in _RIEPILOGOIVA"); return TRUE; } // fine _RIEPILOGOIVA if (code == "_TOTIMPONIBILI") { // sintassi: _TOTIMPONIBILI, // dove: funge da filtro per la somma degli imponibili // se selettore vale 0 restituisce il tot. imponibili con le spese // vedi _RIEPILOGOIVA per la spiegazione dei filtri selettivi byte sel = atoi(s.get()); real x = sel == 0 ? _doc->imponibile(TRUE) : _doc->tot_imponibili(sel); cf.set(x.string()); return (TRUE); } // fine _TOTIMPONIBILI if (code== "_SCADENZE") { // messaggio per stampare le scadenze // sintassi: _SCADENZE,, // dove e' uno dei seguenti: // DATA : stampa la data di scadenza // IMPORTO : stampa l'importo in scadenza // dove vale 0 o 1 se indica di rendere corrente la prossima scadenza if (s.items() == 3) { TString what(s.get()); TString value(_doc->scadenze_get(what)); what = s.get(); const bool next = what == "1"; if (next) _doc->scadenze_set_next(); cf.set(value); } return TRUE; } if (code == "_EDITPICTURE") { const int flds2set = s.items() -1; // TString16 val(cursor()->file(LF_DOC).get(DOC_CODVAL)); // const bool valuta = val.not_empty() && val != "LIT"; const int ndec = _doc->decimals(); for (int i = 1; i<=flds2set; i++) { const short fld = s.get_int(i); edit_picture(cf.section().find_field(fld), ndec); } return TRUE; } if (code == "_SEPARATOR") // Riempitore { TString sep; sep.fill('-',s.get_int(1)); cf.set(sep); return TRUE; } if (code == "_WEEK" || code == "_YEAR") { const TString16 which(s.get()); TString16 data; if (which == RDOC_DATACONS) { const TRectype& rdoc= cursor()->curr(LF_RIGHEDOC); data = rdoc.get(which); } if (data.empty()) data = _doc->get(which); TDate d(data); const char * c = s.get(); bool complete = c != NULL && *c != '\0'; int week; int year; d.get_week_year(week, year, complete); if (code == "_WEEK") cf.set(data.format("%d", week)); else cf.set(data.format("%d", year)); return TRUE; } if (code== "_PARENTDOC") { const TRectype* rdoc = &cursor()->curr(LF_RIGHEDOC); // Se il campo corrente non appartiene al body allora cerco la prima riga documento buona! if (cf.section().section_type() != 'B') { const TDocumento& doc = (const TDocumento&)cursor()->curr(); const TRiga_documento* first_merc = NULL; const TRiga_documento* first_desc = NULL; for (int r = 1; r <= doc.physical_rows(); r++) { const TRiga_documento& row = doc[r]; if (row.get(RDOC_DANDOC).not_empty()) { if (row.is_descrizione()) { if (first_desc == NULL) first_desc = &row; // Non e' una riga buona, ma nemmeno da buttare! } else { first_merc = &row; break; // Ho trovato la riga buona! } } } if (first_merc != NULL) rdoc = first_merc; else { if (first_desc != NULL) rdoc = first_desc; } } int level = s.get_int(1); for (; rdoc != NULL && level > 0; level--) rdoc = ((const TRiga_documento*)rdoc)->find_original_rdoc(); if (rdoc != NULL && rdoc->get(RDOC_PROVV).not_empty()) { const char provv = rdoc->get_char(RDOC_PROVV); const int anno = rdoc->get_int(RDOC_ANNO); const TString4 codnum = rdoc->get(RDOC_CODNUM); const long ndoc = rdoc->get_long(RDOC_NDOC); if (s.get(3) != NULL) // "FULL" { TDocumento doc(provv, anno, codnum, ndoc); output_values(doc, s.get(2), cf); } else { TToken_string key; key.add(provv); key.add(anno); key.add(codnum); key.add(ndoc); const TRectype& doc = cache().get(LF_DOC, key); output_values(doc, s.get(2), cf); } } return TRUE; } if (code== "_PARENTROW") { const TRectype * rdoc = & cursor()->file(LF_RIGHEDOC).curr(); int level = s.get_int(1); for (; rdoc != NULL && level > 0; level--) rdoc = ((const TRiga_documento *) rdoc)->find_original_rdoc(); if (rdoc != NULL && rdoc->get(RDOC_PROVV).not_empty()) { if (s.get(3) != NULL) // "FULL" { const char provv = rdoc->get_char(RDOC_PROVV); const int anno = rdoc->get_int(RDOC_ANNO); const TString4 codnum = rdoc->get(RDOC_CODNUM); const long ndoc = rdoc->get_long(RDOC_NDOC); TDocumento doc(provv, anno, codnum, ndoc); output_values(doc[rdoc->get_int(RDOC_NRIGA)], s.get(2), cf); } else output_values(*rdoc, s.get(2), cf); } return TRUE; } if (code == "_LISTADOC") // Messaggio per riepilogo lista documenti { const TString16 what(s.get(1)); TString16 which(s.get(2)); if (what == "STORE") { if (which[0] == '#') which.ltrim(1); // Toglie il # const TString16 codnum(cf.section().find_field(atoi(which)).get()); const real r(cf.get()); real* v = (real*)_doc_totals.objptr(codnum); if (v == NULL) { v = new real(ZERO); _doc_totals.add(codnum, v); } if (_doc->is_nota_credito()) *v -= r; else *v += r; } else if (what == "ADDTOT") { const real r = cf.get(); if (!r.is_zero()) { TForm_item& tot = cf.find_field(which); real v = tot.get(); if (_doc->is_nota_credito()) v -= r; else v += r; tot.set(v.string()); } } else { TString_array k; _doc_totals.get_keys(k); const int index = atoi(which)-1; if (index < k.items()) { TString16 codnum(k.row(index)); if (what == "CODICE") cf.set(codnum); else if (what == "TOTALE") { real& r = (real&) _doc_totals[codnum]; cf.set(r.string()); } } } return TRUE; } return TForm::validate(cf, s); // se il codice del messaggio non è identificato viene passato alla funzione standard } ////////////////////////////////////////////////////////////////////////////////////////////// // classe TStampaDoc_application customizzata dalla TApplication per l'applicazione principale ////////////////////////////////////////////////////////////////////////////////////////////// enum behaviour { skip, go, cancel }; // Chiavi di ordinamento LF_DOC: // Chiave 1: ordinamento per Provvisorio + Anno + Codice numerazione + Numero documento // Chiave 3: ordinamento per Data documento + Provvisorio + Anno + Codice numerazione + Numero documento #define BY_NUM_KEY 1 #define BY_DATE_KEY 3 class TStampaDoc_application: public TSkeleton_application { TString _codnum; // codice di numerazione char _provv; // stampa documenti provvisiori o definitivi (D o P) int _anno; // anno della documentazione int _key; // chiave per scorrere i documenti (1 o 3, vedi sopra) int _ncopie; // numero di copie per ogni documento long _dalnum, _alnum; // estremi di numerazione dei documenti TDate _dadata, _adata; // estremi di data dei documenti bool _interattivo; // flag che indica se il prog. funziona in interattivo o in batch bool _is_lista; // flga che indica se e' stata selezionata la lista documenti bool _definitiva; // flag che indica se la stampa è definitiva o no TRelation *_firmrel; // puntatore alla relazione che gestisce i dati della ditta corrente TMask * _selection_mask; TRelation* _clifo_rel; TCursor* _clifo_cur; TCursor_sheet* _clifo_sheet; // Array sheet per la selezione cli/fo TAssoc_array _clifo_sel; // Assoc array con solo i cli/fo selezionati. Facilita il filtro... protected: virtual bool create(); virtual bool destroy(); virtual void main_loop(); bool select(void); virtual void on_firm_change(void); virtual behaviour on_module_change(const TString &, TString &); // funzione chiamata ad ogni cambio modulo durante la stampa virtual bool query_final_print(void); // funzione chiamata all'inizializzazione per sapere se la stampa è definitiva void set_filter(TDocumento_form& frm); static bool date2num_handler(TMask_field& f, KEY key); static bool range_handler(TMask_field& f, KEY key); static bool tipocf_handler (TMask_field& f, KEY k); static bool fr_cod_handler (TMask_field& f, KEY k); static bool to_cod_handler (TMask_field& f, KEY k); static bool select_button (TMask_field& f, KEY k); static bool reset_button (TMask_field& f, KEY k); static bool tipodoc_handler (TMask_field& f, KEY k); static bool filter_clifo(const TRelation* r); long select_cod_range(long from, long to); void reset_choices(TMask& m); void set_choice_limits(TMask& m); void build_clifo_list(const char c='C'); int numerazione_definitiva(TDocumento& doc) const; public: void print_documento(TDocumento_form& frm); void print_selected(); TStampaDoc_application() : _key(BY_NUM_KEY) {}; virtual ~TStampaDoc_application() {}; }; inline TStampaDoc_application& app() { return (TStampaDoc_application&) main_app(); } int TStampaDoc_application::numerazione_definitiva(TDocumento& doc) const { int err = NOERR; if (doc.get_char(DOC_PROVV) == 'D') // Se e' una numerazione definitiva { if (doc.stampabile()) // Controlla se non e' gia' nello stato si stampato in definitiva { doc.stato(doc.tipo().stato_finale_stampa()); // Se e' gia' in definitiva aggiorna solo lo stato err = doc.rewrite(); // Invia la transazione di cambio stato se necessario if (::can_dispatch_transaction(doc)) { TFilename tmpname; tmpname.temp(); { // Parentesi strategiche TConfig ini(tmpname, "Transaction"); ini.set("Action", "MODIFY"); ini.set("Firm", prefix().get_codditta()); ini.set("Mode", "A"); TString8 paradoc; paradoc.format("%d", LF_DOC); ini.set_paragraph(paradoc); ini.set(DOC_PROVV, doc.get(DOC_PROVV)); ini.set(DOC_ANNO, doc.get(DOC_ANNO)); ini.set(DOC_CODNUM, doc.get(DOC_CODNUM)); ini.set(DOC_NDOC, doc.get(DOC_NDOC)); ini.set(DOC_STATO, doc.stato()); } ::dispatch_transaction(doc, tmpname); ::remove(tmpname); } } } else // Se e' una numerazione provvisoria { // Scrive il nuovo documento con lo stato, numero e flag di definitiva TDocumento bak_doc; bak_doc = doc; // Setta il flag di nuovo documento bak_doc.put(DOC_STATO,doc.tipo().stato_finale_stampa()); bak_doc.put(DOC_PROVV,"D"); bak_doc.put(DOC_NDOC,-1L); const int pr = bak_doc.physical_rows(); for (int i=1;i<=pr;i++) bak_doc[i].put(DOC_PROVV,"D"); err = bak_doc.write(); // Esegue automagicamente rinumerazione di testata e righe nel caso di reinsert if (err == NOERR) // Cancella il vecchio documento doc.remove(); } return err; } void TStampaDoc_application::print_selected() { TRelation rel(LF_DOC); rel.add(LF_RIGHEDOC,"CODNUM==CODNUM|ANNO==ANNO|PROVV==PROVV|NDOC==NDOC"); TCursor cur(&rel); cur.setkey(_key); TLocalisamfile& doc = cur.file(); TRectype darec(LF_DOC),arec(LF_DOC); // Estremi filtro TString modulo_prec; const bool order_by_num = _key == BY_NUM_KEY; if (!_is_lista) { doc.put(DOC_CODNUM, _codnum); // compone la chiave per il record di inizio cursore doc.put(DOC_ANNO, _anno); doc.put(DOC_PROVV, _provv); arec = doc.curr(); if (order_by_num) doc.put(DOC_NDOC, _dalnum); else doc.put(DOC_DATADOC, _dadata); //doc.setkey(_key); doc.read(); // trova il record iniziale darec = doc.curr(); doc.curr() = arec; if (order_by_num) { doc.put(DOC_NDOC, _alnum); if (doc.read() == _iskeynotfound) // trova il record finale doc.prev(); } else { doc.put(DOC_DATADOC, _adata); // trova il record finale doc.put(DOC_NDOC, 999999L); int err = doc.read(_isgteq); if (err == NOERR) err = doc.prev(); } arec = doc.curr(); if (arec < darec) { error_box("Non vi sono documenti da stampare nell'intervallo indicato"); return; } _definitiva= query_final_print(); // legge il flag di stampa definitiva } TPrinter& pr = printer(); pr.open(); TProgind* pi = pr.printtype() != screenvis ? new TProgind(cur.items(), TR("Stampa documenti in corso..."),FALSE,TRUE) : NULL; if (!_is_lista) { cur.setregion(darec, arec); if (!order_by_num) { TString80 filter; filter.format("(CODNUM==\"%s\")&&(PROVV==\"%c\")", (const char*)_codnum, _provv); cur.setfilter(filter); } const long items = cur.items(); behaviour whattodo = go; bool first_inst = TRUE; real totdocumenti = ZERO; //TDocumentoEsteso *documento = new TDocumentoEsteso; //cur.file().set_curr(documento); for (long i = 0; i < items; i++) { cur = i; // Posiziona il documento if (_definitiva && !((TDocumento &) cur.curr()).stampabile()) continue; // Istanzia il form principale TDocumento_form* mainform = new TDocumento_form(cur.curr(), *_firmrel, _definitiva, _interattivo, FALSE); if (!mainform->valid()) break; // interrompe la stampa se il doc corrente non e' tra i tipi validi const TString &modulo = mainform->get_module_code(); // legge dal form il codice del modulo di carta per la stampa if (modulo_prec.empty()) modulo_prec = modulo; // se siamo al primo passaggio la variabile di modulo precedente viene riempita else first_inst = FALSE; const bool module_changed = modulo != modulo_prec; if (first_inst || module_changed) if (!mainform->doc_arrange()) // Setta l'offset o posiziona manualmente break; // Se vi sono errori interrompe la stampa if (module_changed) whattodo = on_module_change(modulo, modulo_prec); // se il modulo è cambiato dalla stampa precedente interroga la funzione per sapere che comportamento tenere if (whattodo==cancel) break; // se non si può procedere la stampa viene interrotta if (whattodo==skip) continue; // Salta il documento corrente // altrimenti prosegue // Carica il numero di copie da stampare per questo form int ncopie = _ncopie <= 0 ? mainform->ncopie() : _ncopie; // Numero di copie da stampare per questo documento if (ncopie <= 0) ncopie = 1; for (int n=0; n < ncopie; n++) { TDocumentoEsteso& extdoc = mainform->doc(); print_documento(*mainform); extdoc.summary_reset(); extdoc.scadenze_reset(); // Stampa eventuali documenti allegati const TFilename formagg = extdoc.tipo().additional_print_profile(); const int ncopie2 = extdoc.tipo().get_int("I2"); if (!formagg.blank() && ncopie2 > 0) // Se esiste un tipo documento da accodare { TDocumento_form* secform = new TDocumento_form(cur.curr(), *_firmrel, _definitiva, _interattivo, TRUE); if (secform->valid()) { for (int i = 0; i < ncopie2; i++) { print_documento(*secform); extdoc.summary_reset(); extdoc.scadenze_reset(); } } delete secform; } } // se la stampa è definitiva viene lanciata la procedura di rinumerazione if (_definitiva && _interattivo) { if (numerazione_definitiva(mainform->doc()) != NOERR) { error_box(FR("Non è possibile completare la procedura di numerazione definitiva dei documenti. Errore %d"), doc.status()); break; } } // Totalizza gli importi per eventuale stampa su FAKETOTFLD totdocumenti += mainform->doc().totale_doc(); if (i == items - 1 && mainform->is_faketotfld()) { mainform->hide_sections(); TForm_item& fk = mainform->find_field('F', last_page, FAKETOTFLD); fk.show(); fk.set(totdocumenti.string()); print_documento(*mainform); } delete mainform; } } else // Lista documenti { TDocumento_form* mainform = new TDocumento_form(LISTADOC,*_firmrel); TCursor& cur = *mainform->cursor(); cur.setkey(_key); darec.put(DOC_DATADOC, _dadata); darec.put(DOC_PROVV, _provv); darec.put(DOC_ANNO, _anno); arec = darec; arec.put(DOC_DATADOC, _adata); cur.setregion(darec,arec); const bool dettaglio = _selection_mask->get_bool(F_DETTAGLIO); mainform->find_field('B', odd_page, "H_RIGHE").enable(dettaglio); // Visualizza i dettagli righe se richiesto mainform->find_field('B', odd_page, "RIGHE").enable(dettaglio); set_filter(*mainform); const TRecnotype items = cur.items(); if (items > 0) { cur.freeze(); mainform->set_doc_ext(NULL); // Setta il documento esteso DOPO aver fatto il filtro mainform->print(); } delete mainform; } if (pi != NULL) delete pi; printer().close(); } void TStampaDoc_application::print_documento(TDocumento_form& f) { const TRectype& doc = f.cursor()->curr(); const bool is_vis = printer().printtype() == screenvis; if (!is_vis) { TString80 status(TR("Documento: ")); status << doc.get(DOC_CODNUM); status << '\\' << doc.get(DOC_NDOC); xvtil_statbar_set(status); } f.print_documento(); if (!is_vis) xvtil_statbar_set(NULL); } behaviour TStampaDoc_application::on_module_change(const TString &modulo, TString &modulo_prec) { if (!_interattivo) return skip; // se siamo in interattivo il documento viene saltato... else { // ...altrimenti viene chiesto all'utente il da farsi int risp= yesnocancel_box(FR("Il modulo di carta è cambiato: inserire il modulo '%s' e premere 'Si' per continuare," "'No' per saltare il documento o 'Annulla' per interrompere la stampa"), (const char*) modulo); behaviour ret; switch (risp) { case K_YES: modulo_prec= modulo; // aggiorna l'inseguitore dei moduli ret= go; // la stampa può continuare break; case K_NO: ret= skip; // il documento viene saltato break; case K_ESC: default: ret= cancel; // la stampa viene interrotta break; } return ret; } } bool TStampaDoc_application::query_final_print() { if (_interattivo) { // se siamo in interattivo viene richiesto all'utente se la stampa è definitiva o meno if (yesno_box(TR("E' una stampa definitiva?"))) return TRUE; else return FALSE; } else return _definitiva; // altrimenti ritorna il valore letto dalla linea di comando } void TStampaDoc_application::set_filter(TDocumento_form& frm) { TCursor* cur = frm.cursor(); TString filtro,e1,e2,sw; // Compone la lista dei clienti/forntitori selezionati _clifo_sel.destroy(); TString16 key; const long items = _clifo_sheet->items(); for (long i = 0L; ichecked(i)) { key.format("%06ld", _clifo_sheet->row(i).get_long(1)); // Formatta il codice _clifo_sel.add(key, NULL); } // NB: se _clifo_sel non contiene nulla, non viene effettuato alcun filtro su CLI/FO (non setta la funzione!!) filtro.format("TIPOCF==\"%c\"", _selection_mask->get(F_TIPOCF)[0]); const int selval = _selection_mask->get_int(F_SELVAL); const TString16 val = _selection_mask->get(F_VALUTA); const int ndec = TCurrency::get_firm_dec(); frm.edit_picture(frm.find_field('F',last_page, 6), ndec); // pictures per totali finali frm.edit_picture(frm.find_field('F',last_page, 8), ndec); frm.edit_picture(frm.find_field('F',last_page, 10), ndec); frm.edit_picture(frm.find_field('F',last_page, 12), ndec); frm.edit_picture(frm.find_field('F',last_page, 16), ndec); frm.edit_picture(frm.find_field('F',last_page, 17), ndec); if (selval == 1) //In Lire { const TString16 firm_val(TCurrency::get_firm_val()); const bool not_empty = firm_val.not_empty(); filtro << "&&"; if (not_empty) filtro << "((CODVAL==\"" << firm_val << "\")||"; filtro << "(CODVAL==\"\")"; if (not_empty) filtro << ")"; } else if (selval == 2) // nella valuta specificata filtro << "&&(CODVAL==\"" << val << "\")"; else frm.find_field('B',odd_page,35).set("1"); // Cosi' effettua i totali generali in lire ????? // Compone l'espressione filtro... // prende tutte le righe dello spreasheet che non sono totalmente vuote: // (CODNUM=="xxx"&&(STATO=="x"||STATO=="y"||STATO=="z"...)) ---> questo per una singola riga... // se vi sono piu' righe, lo si ripete aggiungendo prima un bellissimo "||" bool put_parentheses = FALSE; TSheet_field& sf = (TSheet_field&)_selection_mask->field(F_SHEETNUMS); const int rows = sf.items(); for (int j=0; jsetfilter(filtro); cur->set_filterfunction(_clifo_sheet->checked() > 0 ? filter_clifo : NULL); } //////////////////////////////////////////////////////////////// // Handlers della maschera //////////////////////////////////////////////////////////////// long TStampaDoc_application::select_cod_range(long from, long to) { TWait_cursor hourglass; if (to <= 0l) to = 999999L; for (int i = 0; i < _clifo_sheet->items(); i++) { TToken_string& c = _clifo_sheet->row(i); const long cod = c.get_long(1); if (cod >= from && cod <= to) _clifo_sheet->check(i); else _clifo_sheet->uncheck(i); } return _clifo_sheet->checked(); } void TStampaDoc_application::build_clifo_list(const char c) { // Semplice ed efficace TRectype rec(LF_CLIFO); rec.put(CLI_TIPOCF, c); _clifo_cur->setregion(rec, rec); } bool TStampaDoc_application::tipocf_handler(TMask_field& f, KEY key) { if (f.to_check(key) && key == K_TAB) { TWait_cursor hourglass; app().reset_choices(f.mask()); app().build_clifo_list(f.get()[0]); } return TRUE; } bool TStampaDoc_application::fr_cod_handler(TMask_field& f, KEY key) { TMask& m = f.mask(); if (key == K_F9) { TMask& m = f.mask(); TCursor_sheet* sh = app()._clifo_sheet; sh->disable_check(); sh->disable(DLG_USER); if (sh->run() == K_ENTER) { app().select_cod_range(sh->row(sh->selected()).get_long(1), m.get_long(F_CODTO)); app().set_choice_limits(m); } sh->enable(DLG_USER); } else if (key == K_TAB && f.focusdirty()) { const long l = app().select_cod_range(m.get_long(F_CODFR), m.get_long(F_CODTO)); app().set_choice_limits(m); m.set(F_SELECTED, l); } return TRUE; } bool TStampaDoc_application::to_cod_handler(TMask_field& f, KEY key) { TMask& m = f.mask(); if (key == K_F9) { TCursor_sheet* sh = app()._clifo_sheet; TMask& m = f.mask(); sh->disable_check(); sh->disable(DLG_USER); if (sh->run() == K_ENTER) { app().select_cod_range(m.get_long(F_CODFR),sh->row(sh->selected()).get_long(1)); app().set_choice_limits(m); } sh->enable(DLG_USER); } if (key == K_TAB && f.focusdirty()) { const long l = app().select_cod_range(m.get_long(F_CODFR), m.get_long(F_CODTO)); app().set_choice_limits(m); m.set(F_SELECTED, l); } return TRUE; } bool TStampaDoc_application::select_button(TMask_field& f, KEY key) { if (key == K_SPACE) { app()._clifo_sheet->enable_check(); if (app()._clifo_sheet->run() == K_ENTER) app().set_choice_limits(f.mask()); } return TRUE; } void TStampaDoc_application::reset_choices(TMask& m) { m.reset(F_SELECTED); m.reset(F_CODFR); m.reset(F_CODTO); _clifo_sheet->check(-1, FALSE); } bool TStampaDoc_application::reset_button(TMask_field& f, KEY key) { if (key == K_SPACE) app().reset_choices(f.mask()); return TRUE; } void TStampaDoc_application::set_choice_limits(TMask& m) { TWait_cursor hourglass; long first = -1l, last = -1l; for (int i = 0; i < _clifo_sheet->items(); i++) { if (_clifo_sheet->checked(i)) { const long cf = _clifo_sheet->row(i).get_long(1); if (first == -1l) first = cf; if (last < cf) last = cf; } } if (first != -1) m.set(F_CODFR, first); if (last != -1) m.set(F_CODTO, last); m.set(F_SELECTED, _clifo_sheet->checked()); } bool TStampaDoc_application::date2num_handler(TMask_field& f, KEY key) { TMask& m = f.mask(); if (key == K_TAB && f.focusdirty()) { short dlg = f.dlg(); TLocalisamfile doc(LF_DOC); doc.setkey(3); TString codnum1(m.get(F_CODNUM)),codnum2; TString anno1(m.get(F_ANNO)),anno2; TString provv1(m.get(F_PROVV)),provv2; TDate data1(m.get_date(dlg)),data2; long numdoc; doc.zero(); doc.put("CODNUM", codnum1); doc.put("ANNO", anno1); doc.put("PROVV", provv1); doc.put("DATADOC", data1); if (doc.read(_isgteq) == NOERR) { codnum2 = doc.get("CODNUM"); anno2 = doc.get("ANNO"); provv2 = doc.get("PROVV"); data2 = doc.get_date("DATADOC"); if (codnum1 == codnum2 && anno1 == anno2 && provv1 == provv2 && data1 == data2) { numdoc = doc.get_long("NDOC"); m.set(dlg == F_DA_DATADOC ? F_DA_NDOC : F_A_NDOC, numdoc); } } } return TRUE; } bool TStampaDoc_application::range_handler(TMask_field& f, KEY key) { bool rt = TRUE; if (key == K_TAB && f.focusdirty()) { const long lim_sup = atol(f.get()); const long lim_inf = f.mask().get_long(F_DA_NDOC); if (lim_sup < lim_inf) rt = f.error_box(TR("Il limite superiore deve essere maggiore del limite inferiore")); } return rt; } bool TStampaDoc_application::tipodoc_handler(TMask_field& f, KEY key) { TMask& m = f.mask(); switch (key) { case K_F9: //caso del bottone di selezione { TArray_sheet as(-1,-1,70,20,TR("Tipi documento"),"Codice|Descrizione@50"); //costruisce uno sheet di selezione dei tipi doc const TRectype& recnum = cache().get("%NUM",m.get(101)); //cache sulla tabella numerazione documento con il numero doc immesso nella maschera const TString80 s2 = recnum.get("S2"); //prende tutto il contenuto del campo S2 della tabella %NUM (numerazione docs) for (int i = 0; i < s2.len(); i+=4) { const TString4 tipodoc = s2.mid(i,4); //si va di 4 in 4, x' cosi' sono ordinati i tipidoc nel campo S2 if (!tipodoc.blank()) //ovviamente si procede solo se il tipodoc esiste { TToken_string row; //classica token_string con codice e descrizione del tipodoc: questa viene scelta nella tabella row.add(tipodoc); //dei tipi docs %TIP row.add(cache().get("%TIP", tipodoc, "S0")); as.add(row); //..e viene aggiunta allo sheet di selezione } } if (as.run() != K_ESC) { TToken_string& riga = as.row(-1); //setta sul campo a maschera il codice della riga selezionata di as f.set(riga.get(0)); } } break; case K_ENTER: //caso del bottone invio; + o - come sopra; deve xo' verificare che l'eventuale codice di tipodoc digitato if (!f.empty()) //sia valido (esista nel campo S2 della tabella NUM) { const TRectype& recnum = cache().get("%NUM",m.get(101)); const TString80 s2 = recnum.get("S2"); for (int i = 0; i < s2.len(); i+=4) { TString4 tipodoc = s2.mid(i,4); tipodoc.trim(); if (tipodoc == f.get()) return TRUE; } return f.error_box(FR("Tipo documento non valido per la numerazione %s"), (const char*)m.get(101)); } break; default: break; } return TRUE; } //////////////////////////////////////////////////////////////// // Filtro per cli/fo sul cursore della lista documenti //////////////////////////////////////////////////////////////// bool TStampaDoc_application::filter_clifo(const TRelation* r) { const long codcf = r->lfile().get_long(CLI_CODCF); TString16 key; key.format("%06ld", codcf); return app()._clifo_sel.is_key(key); } //////////////////////////////////////////////////////////////// // Funzioni rimanenti //////////////////////////////////////////////////////////////// bool TStampaDoc_application::create() { _firmrel= new TRelation(LF_NDITTE); // istanziamento e impostazione della relazione di gestione della ditta corrente _firmrel->add(LF_ANAG, "TIPOA=TIPOA|CODANAGR=CODANAGR"); _firmrel->add(LF_UNLOC,"CODDITTA=CODDITTA"); // si posiziona sulla prima unita' locale della ditta _firmrel->add(LF_COMUNI, "STATO=STATORES|COM=COMRES", 1, LF_ANAG, 100+LF_COMUNI); _firmrel->add(LF_COMUNI, "STATO=STATORES|COM=COMRF", 1, LF_ANAG, 200+LF_COMUNI); open_files(LF_TABCOM, LF_TAB, LF_OCCAS, LF_CLIFO, LF_INDSP, LF_CFVEN, LF_MOVMAG, LF_RMOVMAG, LF_CONDV, LF_ANAMAG , LF_SVRIEP, LF_AGENTI, LF_PERCPROV, LF_CAUSALI, 0); const int argc = TApplication::argc(); _is_lista = argc == 3 && argv(2)[0] == 'L'; on_firm_change(); _selection_mask = new TMask(_is_lista ? "ve1100b" : "ve1100a"); if (!_is_lista) { _clifo_sheet = NULL; _selection_mask->set_handler(F_DA_DATADOC, date2num_handler); _selection_mask->set_handler(F_A_DATADOC, date2num_handler); _selection_mask->set_handler(F_A_NDOC, range_handler); } else { _clifo_rel = new TRelation(LF_CLIFO); _clifo_cur = new TCursor(_clifo_rel); _clifo_sheet = new TCursor_sheet(_clifo_cur, " |CODCF|RAGSOC", TR("Selezione Clienti/Fornitori"), "@1|Codice@6R|Descrizione@50", 0, 1); build_clifo_list(); // Costruisce l'array sheet dei clienti (si parte!!) _selection_mask->set_handler(F_TIPOCF, tipocf_handler); _selection_mask->set_handler(F_CODFR, fr_cod_handler); _selection_mask->set_handler(F_CODTO, to_cod_handler); _selection_mask->set_handler(BUT_SEL, select_button); _selection_mask->set_handler(BUT_ANN, reset_button); _selection_mask->sfield(F_SHEETNUMS).sheet_mask().set_handler(102, tipodoc_handler); } if (argc>3) { // lettura dei parametri iniziali dalla linea di comando _codnum= argv(2); // il primo parametro è il codice di numerazione _anno= atoi(argv(3)); // il secondo è l'anno _provv= argv(4)[0]; // il terzo è il flag di numerazione provvisoria _dalnum= atol(argv(5)); // il quarto è il numero di documento di partenza _alnum = _dalnum; _definitiva = FALSE; _ncopie = 1; _interattivo= FALSE; if (argc > 6) { _alnum= atol(argv(6)); // il quinto è il numero di documento di fine if (argc > 7) { _definitiva= (strcmp(argv(7), "D")==0); // il sesto è se la stampa è definitiva (rinumerazione dei documenti) if (argc > 8) _ncopie = atoi(argv(8)); } else _interattivo = TRUE; } print_selected(); return FALSE; } else { if (argc == 2 || _is_lista) { // oppure lancio della maschera _interattivo= TRUE; TSkeleton_application::create(); } else return error_box("Usage: ve1 -0 {[codnum anno {D|P} dalnum alnum {D|P} [ncopie]] | [L]}"); } return TRUE; } bool TStampaDoc_application::destroy() { delete _firmrel; // distruzione della relazione di gestione della ditta corrente delete _selection_mask; if (_clifo_sheet != NULL) { delete _clifo_sheet; delete _clifo_cur; delete _clifo_rel; } return TApplication::destroy(); } void TStampaDoc_application::on_firm_change() { TLocalisamfile &firmfile= _firmrel->lfile(); firmfile.put("CODDITTA", get_firm()); _firmrel->read(); } bool TStampaDoc_application::select() { TMask & m = * _selection_mask; m.reset(); if (_is_lista) reset_choices(m); const bool ok = m.run() == K_ENTER; if (ok) { if (!_is_lista) { _codnum= m.get(F_CODNUM); // lettura dei dati dalla maschera _dalnum= m.get_long(F_DA_NDOC); _alnum= m.get_long(F_A_NDOC); _ncopie = m.get_int(F_NCOPIE); if (_alnum == 0) _alnum = 9999999L; /* Per ora disabilitamo questa feature, che forse deve essere studiata meglio TString16 config; config << "NUM" << _codnum; printer().read_configuration(config); */ } _anno= m.get_int(F_ANNO); _provv= m.get(F_PROVV)[0]; _dadata = m.get_date(F_DA_DATADOC); if (!_dadata.ok()) _dadata = TDate(1,1,_anno); _adata = m.get_date(F_A_DATADOC); if (!_adata.ok()) _adata = TDate(31,12,_anno); if (_is_lista || m.get(F_DATA_O_NUM) == "D") _key = BY_DATE_KEY; else _key = BY_NUM_KEY; } return ok; } void TStampaDoc_application::main_loop() { while (select()) print_selected(); } // Do all the work! int ve1100(int argc, char* argv[]) { TStampaDoc_application a; const bool riep = argc == 4 && argv[2][0] == 'L'; // Lista documenti a.run(argc, argv, riep ? TR("Lista documenti") : TR("Stampa documenti")); return 0; }