#include "velib05.h" #include "ve1300a.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "../lv/lvlib.h" /////////////////////////////////////////////////////////// // TDoc_recordset /////////////////////////////////////////////////////////// class TDoc_recordset : public TISAM_recordset { TDocumentoEsteso* _doc; TRecnotype _mypos; protected: virtual const TVariant& get_field(int logic, const char* field) const; public: virtual TRecnotype items() const; virtual TRecnotype current_row() const { return _mypos; } virtual bool move_to(TRecnotype pos); TDocumentoEsteso& doc() { return *_doc; } TRiga_documento& riga_doc(int r = 0) const; TDoc_recordset(const TRecordset& doc, const TString& old_query); virtual ~TDoc_recordset(); }; TRecnotype TDoc_recordset::items() const { return _doc->rows(); } TRiga_documento& TDoc_recordset::riga_doc(int n) const { if (n <= 0) n = _mypos+1; if (n > _doc->rows()) // Non dovrebbe succedere mai n = _doc->new_row("05").get_int(RDOC_NRIGA); // Crea ua riga descrizione fittizia if (n <= 0) n = 1; return (*_doc)[n]; } bool TDoc_recordset::move_to(TRecnotype pos) { const bool ok = pos >= 0 && pos < items(); if (ok) { if (pos != _mypos) { _mypos = pos; TRelation& rel = *relation(); rel.curr(LF_RIGHEDOC) = riga_doc(); // Copia riga corrente nella relazione rel.update(1); // Aggiorna solo i file della relazione dipendenti da LF_RIGHEDOC if (_mypos == 0) { doc().scadenze_reset(); doc().summary_reset(true); } } } else { if (pos == items()) _mypos = pos; } return ok; } const TVariant& TDoc_recordset::get_field(int logic, const char* field) const { if (logic == 0 || logic == LF_DOC) { const TFieldref ref(field, LF_DOC); return get_tmp_var() = ref.read(*_doc); } else if (logic == LF_RIGHEDOC) { const TFieldref ref(field, LF_RIGHEDOC); return get_tmp_var() = ref.read(riga_doc()); } return TISAM_recordset::get_field(logic, field); } static TToken_string _sortexpr; static int compare_rdocs(const TObject** p1, const TObject** p2) { const TRectype& r1 = *(const TRectype*)(*p1); const TRectype& r2 = *(const TRectype*)(*p2); int cmp = 0; FOR_EACH_TOKEN(_sortexpr, fld) { const TString& c1 = r1.get(fld); const TString& c2 = r2.get(fld); if (real::is_real(c1) && real::is_real(c2)) { const real r1(c1); const real r2(c2); cmp = r1 == r2 ? 0 : (r1 < r2 ? -1 : +1); } else cmp = c1.compare(c2); if (cmp != 0) break; } return cmp; } TDoc_recordset::TDoc_recordset(const TRecordset& doc, const TString& old_query) : TISAM_recordset(old_query), _doc(NULL), _mypos(-1) { TRectype curr(LF_DOC); TToken_string query(old_query, '\n'); TToken_string new_query("", '\n'); TString line; _sortexpr.cut(0); FOR_EACH_TOKEN(query, tok) { line = tok; line.trim(); if (line.starts_with("SORT ")) { const int pos = line.find("BY "); if (pos > 0) { TToken_string by(line.mid(pos + 3), ' '); by.strip_double_spaces(); by.trim(); FOR_EACH_TOKEN(by, tok) { TString16 fld = tok; if (fld.starts_with("34.")) fld.ltrim(3); if (fld.starts_with("RDOC.")) fld.ltrim(5); _sortexpr.add(fld); } } line = query.get(); line.trim(); if (line.starts_with("JOIN TO")) line.insert("34 ", 5); new_query.add(line); continue; } if (line.starts_with("USE ")) { new_query.add(line); for (int i = 0; i < 2; i++) { const char* key[4] = { DOC_PROVV, DOC_ANNO, DOC_CODNUM, DOC_NDOC }; line = (i == 0) ? "FROM " : "TO "; for (int k = 0; k < 4; k++) { const TString& val = doc.get(key[k]).as_string(); line << key[k] << '=' << val << ' '; if (i == 0) curr.put(key[k], val); } new_query.add(line); } continue; } new_query.add(line); } set(new_query); _doc = new TDocumentoEsteso(curr); if (_sortexpr.full()) { TRecord_array& rows = _doc->body(); rows.sort(compare_rdocs); } _doc->set_riga_conai(); // Posiziona correttamente anche il cursore principale *cursor() = 0L; } TDoc_recordset::~TDoc_recordset() { if (_doc != NULL) delete _doc; } /////////////////////////////////////////////////////////// // TTrans_recordset /////////////////////////////////////////////////////////// class TTrans_recordset : public TAS400_recordset { protected: virtual bool parse_query(const TString& query, TFilename& n); virtual bool load_file(const TFilename& n); public: TTrans_recordset(const char* ininame); }; bool TTrans_recordset::parse_query(const TString& query, TFilename& n) { n = query; return n.exist() ? _qt_select : _qt_none; } bool TTrans_recordset::load_file(const TFilename& n) { TConfig ini(n, "33"); TToken_string dokey; for (int idx = 0; ; idx++) { dokey = ini.get("Doc", NULL, idx); if (dokey.blank()) break; const TRectype& doc = cache().get(LF_DOC, dokey); if (!doc.empty()) { new_rec(); for (unsigned int c = 0; c < columns(); c++) { const TRecordset_column_info& ci = column_info(c); const char* fldname = ci._name; set(fldname, doc.get(fldname)); } } } return items() > 0; } TTrans_recordset::TTrans_recordset(const char* ininame) : TAS400_recordset(ininame) { _info._width = 32; create_field(DOC_PROVV, -1, 1, _alfafld, true); create_field(DOC_ANNO, -1, 4, _intfld, true); create_field(DOC_CODNUM, -1, 4, _alfafld, true); create_field(DOC_NDOC, -1, 7, _longfld, true); create_field(DOC_TIPODOC, -1, 4, _alfafld); create_field(DOC_TIPOCF, -1, 1, _alfafld); create_field(DOC_CODCF, -1, 6, _longfld); } /////////////////////////////////////////////////////////// // TReport_doc /////////////////////////////////////////////////////////// class TReport_doc : public TReport { size_t _first_msg; int _extra_copies; protected: virtual void include_libraries(bool reload); virtual size_t get_usr_words(TString_array& words) const; virtual bool execute_usr_word(unsigned int opcode, TVariant_stack& stack); virtual bool get_usr_val(const TString& name, TVariant& var) const; virtual bool set_usr_val(const TString& name, const TVariant& var); TDocumentoEsteso& doc(); TRiga_documento& riga_doc(int n = 0); void output_values(const TRectype& rec, const TString& output); void reset_values(const TString& output); bool msg_cliente(TVariant_stack& stack); bool msg_parent_doc(TVariant_stack& stack); bool msg_parent_row(TVariant_stack& stack); bool msg_riepilogo_iva(TVariant_stack& stack); bool msg_scadenze(TVariant_stack& stack); bool msg_tot_imponibili(TVariant_stack& stack); bool msg_lv_dot(TVariant_stack& stack); int set_printed_status(TDocumento& doc) const; public: bool print(const TRecordset& doc, TReport_book& book, bool def, word copies, bool alleg, bool arc, bool signature, word printed_copies = 0); int extra_copies() const { return _extra_copies; } TReport_doc(const char* name); virtual ~TReport_doc(); }; int TReport_doc::set_printed_status(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"); TString4 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; } bool TReport_doc::print(const TRecordset& doc, TReport_book& book, bool definitive, word copie, bool can_allegate, bool arc, bool signature, word printed_copies) { bool printed = true; const TString old_query = recordset()->query_text(); TDoc_recordset* rs = new TDoc_recordset(doc, old_query); set_recordset(rs); TDocumento& d = rs->doc(); if (!definitive || d.stampabile()) { for (int c = 1; c <= copie; c++) { set_copy(c + printed_copies, copie + printed_copies); // Tenta di stampare gli allegati solo sull'ultima copia definitiva if (c == copie && can_allegate) { const TTipo_documento& tipodoc = d.tipo(); if (tipodoc.allega_documenti()) { const long codcf = d.get_long(CLI_CODCF); TString_array allegati; for (bool ok = rs->move_first(); ok; ok = rs->move_next()) { const TString& codart = rs->get("RDOC.CODARTMAG").as_string(); const TRectype& anamag = cache().get(LF_ANAMAG, codart); TToken_string golem(anamag.get(ANAMAG_GOLEM), '\n'); if (!golem.empty_items()) { TToken_string key; key.add(d.get(DOC_PROVV)); key.add(d.get(DOC_ANNO)); key.add(d.get(DOC_CODNUM)); key.add(d.get(DOC_NDOC)); TLocalisamfile alleg(LF_MULTIREL); alleg.put(MULTI_COD, "ALLEG"); alleg.put(MULTI_FIRST, codcf); alleg.put(MULTI_SECOND, codart); alleg.put(MULTI_DATA, key); bool print_alleg = alleg.write() == NOERR; // Se riesco a scrivere vuol dire che non esisteva if (!print_alleg) { alleg.put(MULTI_COD, "ALLEG"); alleg.put(MULTI_FIRST, codcf); alleg.put(MULTI_SECOND, codart); if (alleg.read() == NOERR) print_alleg = alleg.get(MULTI_DATA) == key; } if (print_alleg) { FOR_EACH_TOKEN(golem, allegato) { TToken_string a(allegato); TFilename name = a.get(); const bool link = a.get_char(2) > ' '; if (!link) { TFilename golem_path = firm2dir(prefix().get_codditta()); golem_path.add("golem"); golem_path.add(name.name()); name = golem_path; } if (name.exist()) allegati.add(name); } } } } set_allegates(allegati); } } printed = book.add(*this, false); if (!printed) break; } if (printed) { if (definitive) set_printed_status(d); if (arc) archive(signature); } } set_recordset(old_query); return printed; } TDocumentoEsteso& TReport_doc::doc() { TDoc_recordset* rs = (TDoc_recordset*)recordset(); return rs->doc(); } TRiga_documento& TReport_doc::riga_doc(int n) { TDoc_recordset* rs = (TDoc_recordset*)recordset(); return rs->riga_doc(n); } bool TReport_doc::msg_cliente(TVariant_stack& stack) { TReport_field& cf = *curr_field(); const TCli_for& cli_for = doc().clifor(); const TOccasionale& cli_occ = doc().occas(); const bool occasionale = cli_for.occasionale(); TString in = stack.pop().as_string(); // prende la macro o il fieldref TString valore; 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); TString8 key; if (nascita) { key = occasionale ? cli_occ.get(OCC_STATONASC) : cli_for.get(CLI_STATONASC); key << '|' << (occasionale ? cli_occ.get(OCC_COMNASC) : cli_for.get(CLI_COMNASC)); } else { key = occasionale ? cli_occ.get(OCC_STATO): cli_for.get(CLI_STATOCF); key << '|' << (occasionale ? cli_occ.get(OCC_COM): cli_for.get(CLI_COMCF)); } valore = cache().get(LF_COMUNI, key, in); cf.set(valore); 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; } return false; } void TReport_doc::output_values(const TRectype& rec, const TString& output) { 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) { curr_field()->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 TReport_field* campo = field(fld); if (campo != NULL) campo->set(dat); } } } void TReport_doc::reset_values(const TString& output) { 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) { curr_field()->set(""); } else { TString16 fld(curr.left(poseq)); // preleva il nome del campo del form alla sinistra dell'uguale TReport_field* campo = field(fld); if (campo != NULL) campo->set(""); } } } bool TReport_doc::msg_parent_doc(TVariant_stack& stack) { TReport_field& cf = *curr_field(); const TRectype* rdoc = &riga_doc(); // Se il campo corrente non appartiene al body allora cerco la prima riga documento buona! if (cf.section().type() != 'B') { 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 = riga_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 = stack.pop().as_int(); for (; rdoc != NULL && level > 0; level--) rdoc = ((const TRiga_documento*)rdoc)->find_original_rdoc(); const TString& values = stack.pop().as_string(); const bool is_full = stack.peek().as_bool(); 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 (is_full) { TDocumento doc(provv, anno, codnum, ndoc); output_values(doc, values); } 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, values); } } else reset_values(values); return true; } bool TReport_doc::msg_parent_row(TVariant_stack& stack) { const TRectype* rdoc = &riga_doc(); int level = stack.pop().as_int(); for (; rdoc != NULL && level > 0; level--) rdoc = ((const TRiga_documento *) rdoc)->find_original_rdoc(); const TString& values = stack.pop().as_string(); const bool is_full = stack.peek().as_bool(); if (rdoc != NULL && rdoc->get(RDOC_PROVV).not_empty()) { if (is_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)], values); } else output_values(*rdoc, values); } return true; } bool TReport_doc::msg_riepilogo_iva(TVariant_stack& stack) { // 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 const int selector = stack.pop().as_int(); if (selector != 0) { TDocumentoEsteso& d = doc(); d.summary_filter(selector); const TString& what = stack.pop().as_string(); // cosa deve stampare ? const TVariant value = d.summary_get(what); // Piglia il valore dalla riga selezionata sulla tabellina curr_field()->set(value); const bool next = stack.pop().as_bool(); // deve cambiare elemento ? if (next) d.summary_set_next(); } return true; } bool TReport_doc::msg_scadenze(TVariant_stack& stack) { const TString& what = stack.pop().as_string(); const TVariant value = doc().scadenze_get(what); curr_field()->set(value); const bool next = stack.pop().as_bool(); if (next) doc().scadenze_set_next(); return true; } bool TReport_doc::msg_tot_imponibili(TVariant_stack& stack) { TReport_field& cf = *curr_field(); // 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 const int sel = stack.pop().as_int(); const TVariant x = (sel == 0) ? doc().imponibile(true) : doc().tot_imponibili(sel); cf.set(x); return true; } bool TReport_doc::msg_lv_dot(TVariant_stack& stack) { TReport_field& cf = *curr_field(); const TString& field = stack.pop().as_string(); if(field == "DOTOD" || field == "DOTMP" || field == "DOTIN") { const TRectype& rdoc = riga_doc(); const TDocumento& h = doc(); //instanzio un TArticolo_lavanderie per poter recuperare i dati di interesse TArticolo_lavanderie& artrec = cached_article_laundry(rdoc.get(RDOC_CODARTMAG), h.get(DOC_TIPOCF)[0], h.get_long(DOC_CODCF), h.get_int(DOC_CODINDSP)); //setto datasc a oggi e fisso l'anno esercizio TEsercizi_contabili& esc = esercizi(); const int last_esc = esc.last(); //estraggo il record corrispondente su LF_CLIFOGIAC const TRecmag_lavanderie& reclav = artrec.find_rec(last_esc); TVariant x = reclav.get(field); if(reclav.empty()) { TArticolo_lavanderie& artrec1 = cached_article_laundry(rdoc.get(RDOC_CODARTMAG), h.get(DOC_TIPOCF)[0], h.get_long(DOC_CODCF), 0); const TRecmag_lavanderie& reclav1 = artrec1.find_rec(last_esc); x = reclav1.get(field); } cf.set(x); } else cf.set(""); return true; } size_t TReport_doc::get_usr_words(TString_array& words) const { TReport::get_usr_words(words); const char* const name[] = { "DOC_CLIENTE", "DOC_PARENT_DOC", "DOC_PARENT_ROW", "DOC_RIEPILOGO_IVA", "DOC_SCADENZE", "DOC_TOT_IMPONIBILI", "DOC_LV_DOT", NULL }; ((TReport_doc*)this)->_first_msg = words.items(); // Calcola il primo numero disponibile size_t i; for (i = 0; name[i] != NULL; i++) words.add(name[i]); return words.items(); } bool TReport_doc::execute_usr_word(unsigned int opcode, TVariant_stack& stack) { bool ok = true; if (opcode >= _first_msg) { switch (opcode - _first_msg) { case 0: msg_cliente(stack); break; case 1: msg_parent_doc(stack); break; case 2: msg_parent_row(stack); break; case 3: msg_riepilogo_iva(stack); break; case 4: msg_scadenze(stack); break; case 5: msg_tot_imponibili(stack); break; case 6: msg_lv_dot(stack); break; default: ok = false; break; } stack.reset(); // Svuota eventuali parametri variabili inutilizzati } else ok = TReport::execute_usr_word(opcode, stack); return ok; } void TReport_doc::include_libraries(bool reload) { TReport::include_libraries(reload); if (reload || !defined("MESSAGE_DESCRIGA")) include("ve1300.alx"); } bool TReport_doc::get_usr_val(const TString& name, TVariant& var) const { if (name == "#PRINT_EXTRA_COPIES") { var = long(_extra_copies); return true; } return TReport::get_usr_val(name, var); } bool TReport_doc::set_usr_val(const TString& name, const TVariant& var) { if (name == "#PRINT_EXTRA_COPIES") { _extra_copies = var.as_int(); return true; } return TReport::set_usr_val(name, var); } TReport_doc::TReport_doc(const char* name) : _extra_copies(0) { // istanziamento e impostazione della relazione di gestione della ditta corrente load(name); // Faccio la load altrimenti non include la libreria 1300.alx } TReport_doc::~TReport_doc() { } /////////////////////////////////////////////////////////// // TDoc_book /////////////////////////////////////////////////////////// class TDoc_book : public TReport_book { protected: virtual void draw_link(const TReport_rct& rect, const char* text, const char* link); }; void TDoc_book::draw_link(const TReport_rct& rect, const char* text, const char* link) { if (main_app().argc() < 6) // Vieta i link quando sono in batch TReport_book::draw_link(rect, text, link); } /////////////////////////////////////////////////////////// // TReport_doc_mask /////////////////////////////////////////////////////////// class TReport_doc_mask : public TAutomask { protected: virtual bool on_field_event(TOperable_field& o, TField_event e, long jolly); public: TReport_doc_mask(); }; bool TReport_doc_mask::on_field_event(TOperable_field& o, TField_event e, long jolly) { switch (o.dlg()) { case F_DA_NDOC: if (e == fe_modify) { const long dal = get_long(F_DA_NDOC); const long al = get_long(F_A_NDOC); if (al < dal) set(F_A_NDOC, dal); } break; default: break; } return true; } TReport_doc_mask::TReport_doc_mask() : TAutomask("ve1300a") { hide(F_PROVV); //abilita i bottoni della toolbar in base ai moduli presenti sulla chiave TApplication& a = main_app(); const bool can_pdf = a.has_module(RSAUT); const bool can_sign = can_pdf && a.has_module(FDAUT); enable(DLG_EMAIL, can_pdf); enable(DLG_SIGNMAIL, can_sign); enable(DLG_PDF, can_pdf); enable(DLG_SIGNPDF, can_sign); } /////////////////////////////////////////////////////////// // TReports_cache /////////////////////////////////////////////////////////// class TReports_cache : TCache { protected: virtual TObject* key2obj(const char* key) { return new TReport_doc(key); } public: TReport_doc& get(const TString& key) { return *(TReport_doc*)objptr(key); } TReports_cache() : TCache(13) { } }; /////////////////////////////////////////////////////////// // TReport_doc_app /////////////////////////////////////////////////////////// class TReport_doc_app : public TSkeleton_application { enum TOutput_mode { out_preview, out_print, out_mail, out_signed_mail, out_pdf, out_signed_pdf }; TReport_doc_mask* _msk; int _anno; TString16 _codnum; // codice numerazione / profilo long _ndoc, _codcf; char _tipocf; bool _no_print_dlg; protected: void add_cli_filter(TString& query, bool from) const; void add_data_filter(TString& query, bool from) const; void add_ndoc_filter(TString& query, bool from) const; void add_filter(TString& str, bool from) const; bool print_loop(TRecordset& doc, TOutput_mode mode, bool is_definitive); void print_selection(TOutput_mode mode); void print_trans(const char* ininame); TOutput_mode key2mode(KEY k) const; void set_next_pdf(int an, const char* cn, long nd, char tcf, long cf); virtual bool get_next_pdf(int anno, long ditta, const char* codnum, long numdoc, long codcf, TFilename& pdf) const; const TString& get_mail_address() const; virtual bool get_next_mail(TToken_string& to, TToken_string& cc, TToken_string& ccn, TString& subj, TString& text, TToken_string& attach, short& ui) const ; void print_extra_copies(TReport_doc& report, const TRecordset& doc, TReport_book& book, word printed_copies) const; bool nome_report(const TRecordset& doc, int quale, TFilename& profilo) const; public: virtual bool create(); virtual void main_loop(); virtual bool destroy(); }; void TReport_doc_app::set_next_pdf(int an, const char* cn, long nd, char tcf, long cf) { _anno = an; _codnum = cn; _ndoc = nd; _tipocf = tcf; _codcf = cf; } bool TReport_doc_app::get_next_pdf(int anno, long ditta, const char* codnum, long ndoc, long codcf, TFilename& pdf) const { bool ok = false; if (_anno > 0 && _codnum.full() && _ndoc > 0 && _codcf > 0) ok = TSkeleton_application::get_next_pdf(_anno, ditta, _codnum, _ndoc, _codcf, pdf); return ok; } const TString& TReport_doc_app::get_mail_address() const { TString8 key; key << _tipocf << '|' << _codcf; const TString& maddr = cache().get(LF_CLIFO, key, CLI_DOCMAIL); return maddr; } bool TReport_doc_app::get_next_mail(TToken_string& to, TToken_string& cc, TToken_string& ccn, TString& subj, TString& text, TToken_string& attach, short& ui) const { bool ok = TApplication::get_next_mail(to, cc, ccn, subj, text, attach, ui); if (_ndoc > 0L) { to = get_mail_address(); ok = to.full(); if (ok) { TDocumento doc('D', _anno, _codnum, _ndoc); doc.riferimento(subj); if (subj.blank()) { subj = doc.tipo().descrizione(); subj << ' ' << _ndoc << TR(" del ") << doc.get(DOC_DATADOC) << ' ' << prefix().firm().ragione_sociale(); } text << TR("Invio documento ") << subj; if (to.full()) ui &= ~0x1; // No user interface ui |= 0x2; // Query receipt } } return ok; } void TReport_doc_app::add_cli_filter(TString& query, bool from) const { if (from) { query << " KEY 4 SELECT " << "(PROVV='" << _msk->get(F_PROVV) << "')&&(ANNO=" << _msk->get(F_ANNO) << ")&&(CODNUM='" << _msk->get(F_CODNUM) << "')"; } query << '\n'; const TString4 tipocf = _msk->get(F_TIPOCFD); const long cod = _msk->get_long(from ? F_DA_CLIFO : F_A_CLIFO); if (cod > 0L) query << (from ? "FROM" : "TO") << " TIPOCF=" << tipocf << " CODCF=" << cod; } void TReport_doc_app::add_data_filter(TString& query, bool from) const { if (from) { query << " KEY 3 SELECT " << "(PROVV='D')&&(ANNO=" << _msk->get(F_ANNO) << ")&&(CODNUM='" << _msk->get(F_CODNUM) << "')"; } query << '\n'; const TDate d = _msk->get(from ? F_DA_DATADOC : F_A_DATADOC); if (d.ok()) query << (from ? "FROM" : "TO") << " DATADOC=" << d.date2ansi(); } void TReport_doc_app::add_ndoc_filter(TString& query, bool from) const { query << '\n' << (from ? "FROM" : "TO") << " PROVV='D' ANNO=" << _msk->get(F_ANNO) << " CODNUM='" << _msk->get(F_CODNUM) << '\''; const long ndoc = _msk->get_long(from ? F_DA_NDOC : F_A_NDOC); if (ndoc > 0) query << " NDOC=" << ndoc; } void TReport_doc_app::add_filter(TString& query, bool from) const { const char tipost = _msk->get(F_ORDERING)[0]; switch (tipost) { case 'D' : add_data_filter(query, from); break; case 'C' : add_cli_filter(query, from); break; default : add_ndoc_filter(query, from); break; } } bool TReport_doc_app::create() { if (!has_module(RSAUT)) return error_box(TR("Modulo non autorizzato")); _msk = new TReport_doc_mask; return TSkeleton_application::create(); } bool TReport_doc_app::destroy() { delete _msk; return TSkeleton_application::destroy(); } void TReport_doc_app::print_extra_copies(TReport_doc& report, const TRecordset& doc, TReport_book& book, word printed_copies) const { const int extra_copies = report.extra_copies(); if (extra_copies > 0) report.print(doc, book, false, extra_copies, false, false, false, printed_copies); } // Quale 0=standard,1=aggiuntivo,2=mail bool TReport_doc_app::nome_report(const TRecordset& doc, int quale, TFilename& profilo) const { const TString4 tipodoc = doc.get(DOC_TIPODOC).as_string(); const TTipo_documento& tipo = cached_tipodoc(tipodoc); bool ok = false; switch (quale) { case 1: ok = tipo.additional_print_profile(profilo, 2); break; case 2: ok = tipo.mail_print_profile(profilo); break; default: ok = tipo.main_print_profile(profilo, 2); break; } if (ok) // Cerca eventuale personalizzazione per il singolo cliente { TString8 codcf = doc.get(DOC_CODCF).as_string(); codcf.right_just(6, '0'); TFilename path = profilo.name_only(); path << '_' << doc.get(DOC_TIPOCF) << codcf << ".rep"; if (path.custom_path()) profilo = path; } return ok; } bool TReport_doc_app::print_loop(TRecordset& doc, TOutput_mode mode, bool is_definitive) { const int docs = doc.items(); if (docs <= 0) return false; if (mode == out_signed_mail && !xvt_sign_start()) { if (yesno_box(TR("Si desidera generare comunque documenti non firmati?"))) mode = out_mail; else return false; } const bool signature = mode==out_signed_mail || mode==out_signed_pdf; TReports_cache reports; // Cache degli ultimi reports usati TDoc_book book; // Destinazione dell'intera stampa TDoc_book* mail_book = NULL; // Destinazione della singola mail TLog_report mail_log(TR("Invio documenti per email")); TProgind pi(docs, TR("Elaborazione documenti..."), true, true); bool attach_mail = mode==out_mail || mode==out_signed_mail; if (attach_mail && is_power_station()) attach_mail = yesno_box(TR("Si desidera spedire veramente i documenti via mail?\n" "Rispondendo NO verranno solo salvati gli allegati.")); for (int i = 0; i < docs; i++) { if (!pi.addstatus(1)) break; doc.move_to(i); const TString4 tipodoc = doc.get(DOC_TIPODOC).as_string(); const TTipo_documento& tipo = cached_tipodoc(tipodoc); bool arc = false; if (is_definitive) { if (doc.get(DOC_STATO).as_string()[0] == tipo.stato_finale_stampa()) continue; // Evita lavoro inutile! const TString4 codnum = doc.get(DOC_CODNUM).as_string(); const TCodice_numerazione& cn = cached_numerazione(codnum); arc = cn.auto_archive(); } set_next_pdf(doc.get(DOC_ANNO).as_int(), doc.get(DOC_CODNUM).as_string(), doc.get(DOC_NDOC).as_int(), doc.get(DOC_TIPOCF).as_string()[0], doc.get(DOC_CODCF).as_int()); const bool send_mail = ( mode == out_mail || mode == out_signed_mail) && get_mail_address().full(); const bool paperless = send_mail || mode == out_pdf || mode == out_signed_pdf; // Tenta di costruirsi il nome del report: se non stampo su carta cerco di usare un profilo con sfondo TFilename profilo; const bool ok = nome_report(doc, paperless ? 2 : 0, profilo); if (ok) { int copies = 1; if (!paperless) { copies = _msk->get_int(F_NCOPIE); if (copies <= 0 && is_definitive) copies = tipo.ncopie(); if (copies <= 0) copies = 1; } TReport_doc& report = reports.get(profilo); if (send_mail) { mail_book = new TDoc_book; if (!report.print(doc, *mail_book, is_definitive, 1, true, false, false)) // Non archiviare per ora... break; if (arc) // ... eventualemte archivia direttamente il book senza passare per uno temporaneo mail_book->archive(NULL, signature); TString mesg; mesg << tipo.descrizione() << TR(" n. ") << doc.get(DOC_NDOC) << TR(" del ") << doc.get(DOC_DATADOC) << TR(" a ") << get_mail_address(); mail_log.log(0, mesg); } else { if (!report.print(doc, book, is_definitive, copies, true, arc, signature)) break; if (!paperless) print_extra_copies(report, doc, book, copies); } } //if(profilo.custom_path()... else { TString msg; msg << TR("Report inesistente: ") << profilo; xvtil_popup_error(msg); continue; } // Stampa eventuali allegati if (nome_report(doc, 1, profilo)) { int copies = tipo.additional_ncopie(); if (copies <= 0) copies = 1; TReport_doc& allegato = reports.get(profilo); // Cambio _codnum per non sovrascrivere il pdf precedente if (arc) { _codnum = profilo.name(); _codnum = _codnum.before("."); } // Il flag di definitivo deve essere false altrimenti riaggiorna lo stato e ristampa i documenti allegati if (send_mail) allegato.print(doc, *mail_book, false, 1, false, false, false); // Non archivio gli allegati alla mail else { allegato.print(doc, book, false, copies, false, arc, signature); if (!paperless) print_extra_copies(allegato, doc, book, copies); } } if (mail_book != NULL) { if (mail_book->pages() > 0) { TFilename attachment; bool is_tmp = false; // Se ho archiviato (arc==true) allora il file di attachment e' gia' pronto! bool ok = arc && get_next_pdf(_anno, -1, _codnum, _ndoc, _codcf, attachment); if (!ok || !attachment.exist()) // Altrimenti ne creo uno temporaneo { attachment.tempdir(); attachment << SLASH << _anno <<'_' << _codnum << '_' << _ndoc; attachment.ext("pdf"); ok = mail_book->export_pdf(attachment, mode == out_signed_mail); is_tmp = ok; } if (ok && attach_mail) // Ho chiesto la spedizione vera e propria { ok = spotlite_send_mail(attachment); if (is_tmp) attachment.fremove(); } } delete mail_book; mail_book = NULL; } } if (book.pages() > 0) { if (docs > 1) set_next_pdf(0, "", 0L, ' ', 0L); //spegne l'archiviazione nell'esportazione;non si possono archiviare più docs in uno!!! if (mail_log.recordset()->items() > 0) book.add(mail_log); switch (mode) { case out_preview: book.preview(); break; case out_pdf: case out_signed_pdf: { TFilename pdf; pdf.tempdir(); pdf << SLASH << _anno <<'_' << _codnum << '_' << _ndoc; pdf.ext("pdf"); if (book.export_pdf(pdf, mode == out_signed_pdf)) xvt_sys_goto_url(pdf, "open"); } break; default: if (_no_print_dlg) book.print(1, book.pages()); // Evita di chiedere da pag. a pag. else book.print(); break; } } else { if (mail_log.recordset()->items() > 0) mail_log.preview(); } if (mode == out_signed_mail || mode == out_signed_pdf) xvt_sign_stop(); return true; } void TReport_doc_app::print_selection(TOutput_mode mode) { TString query; query << "USE " << LF_DOC; add_filter(query, true); add_filter(query, false); TISAM_recordset doc(query); const TRecnotype docs = doc.items(); if (docs > 0) { bool is_definitive = false; if (argc() > 7) // Batch is_definitive = *argv(7) == 'D'; else { if (argc() < 6) // Vieta i link quando sono in batch is_definitive = _msk->get(F_TIPOST) == "D"; else { const KEY k = yesnocancel_box(FR("Stampare in definitiva %ld documenti?"), docs); if (k == K_ESC) return; is_definitive = k == K_YES; } } print_loop(doc, mode, is_definitive); } } // Elabora una transazione del tipo // [Transaction] // Action = Stampa // Mode = D // NoPrintDlg = X // [33] // Doc(0)=D|2009|F01|1 // Doc(1)=D|2009|A02|2 void TReport_doc_app::print_trans(const char* ininame) { TTrans_recordset doc(ininame); if (doc.items() > 0) { char a='S', m='P'; if (ininame && *ininame) // Dummy test { TConfig ini(ininame, "Transaction"); a = ini.get("Action")[0]; // Stampa, Anteprima, Pdf, ... m = ini.get("Mode")[0]; // Definitivo o Provvisori _no_print_dlg = ini.get_bool("NoPrintDlg"); } const TOutput_mode mode = key2mode(a); const bool is_definitive = m == 'D'; print_loop(doc, mode, is_definitive); } else cantread_box(ininame); } // Traduce un carattere ASCII nella corrispondente modalita' di stampa TReport_doc_app::TOutput_mode TReport_doc_app::key2mode(KEY k) const { TOutput_mode mode = out_print; if (k >= 'a' && !has_module(FDAUT)) k -= ' '; // toupper dei poveri if (!has_module(RSAUT)) k = 'A'; switch (k) { case 'A': mode = out_preview; break; case 'E': mode = out_mail; break; case 'e': mode = out_signed_mail; break; case 'P': mode = out_pdf; break; case 'p': mode = out_signed_pdf; break; case 'S': default : mode = out_print; break; } return mode; } void TReport_doc_app::main_loop() { _no_print_dlg = false; const int a = argc(); if (a > 2) { const TFixed_string arg = argv(2); // Gestione transazioni di stampa if (arg.starts_with("-i")) { const TFilename ini = arg.mid(2); if (ini.exist()) print_trans(ini); return; } TString4 codnum = arg.left(4); if (arg.len() > 4 || cache().get("%NUM", arg).empty()) { const TToken_string tok(arg, ','); TString16 paragraph, field; tok.get(0, paragraph); tok.get(1, field); if (field.blank()) field = DOC_CODNUM; codnum = ini_get_string(CONFIG_DITTA, paragraph, field); } _msk->set(F_CODNUM, codnum); // Stampa da menu con numerazione imposta } if (a > 6) // Stampa da riga di comando { _msk->set(F_ORDERING, "N"); // Stampa per numero documento _msk->set(F_ANNO, argv(3)); _msk->set(F_PROVV, argv(4)); // "883" = Stampa solo 883; "882-884" = stampa dal 882 al 884 const TToken_string strndoc(argv(5), '-'); long dandoc = 0, andoc = 0; if (strndoc.get(0, dandoc)) { if (!strndoc.get(1, andoc)) andoc = dandoc; _msk->set(F_DA_NDOC, dandoc); _msk->set(F_A_NDOC, andoc); } const TOutput_mode mode = key2mode(*argv(6)); // modo di 'S'tampa, 'A'nteprima, 'P'DF // argv(7); // Provvisiorio o Definitivo testato altrove! if (a > 8) _msk->set(F_NCOPIE, argv(8)); // Numero copie print_selection(mode); return; } while (true) { const KEY k = _msk->run(); if (k == K_QUIT) break; print_selection(key2mode(k)); } } int ve1300(int argc, char* argv[]) { TReport_doc_app a; a.run(argc, argv, TR("Stampa documenti")); return (0); }