#include #include #include #include #include #include #include #include #include #include "ve1100.h" #include "velib.h" #include #include /////////////////////////////////////////////////////////// // TDoc_recordset /////////////////////////////////////////////////////////// class TDoc_recordset : public TISAM_recordset { TDocumentoEsteso* _doc; TRecnotype _mypos; public: virtual TRecnotype items() const; virtual TRecnotype current_row() const { return _mypos; } virtual bool move_to(TRecnotype pos); virtual const TVariant& get(int logic, const char* field) const; 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 { const TRecnotype i = _doc->rows(); return i > 0 ? i : 1; } TRiga_documento& TDoc_recordset::riga_doc(int n) const { if (n <= 0) n = _mypos+1; if (n > _doc->rows()) n = _doc->new_row().get_int(RDOC_NRIGA); 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(int logic, const char* field) const { if (logic == 0 || logic == LF_DOC) { const TFieldref ref(field, LF_DOC); TVariant& tmp = get_tmp_var(); tmp.set(ref.read(*_doc)); return tmp; } else if (logic == LF_RIGHEDOC) { const TFieldref ref(field, LF_RIGHEDOC); TVariant& tmp = get_tmp_var(); tmp.set(ref.read(riga_doc())); return tmp; } return TISAM_recordset::get(logic, field); } TDoc_recordset::TDoc_recordset(const TRecordset& doc, const TString& query) : TISAM_recordset(query), _doc(NULL), _mypos(-1) { TRectype curr(LF_DOC); TString new_query = query; const int acapo = query.find('\n')+1; for (int i = 0; i < 2; i++) { const char* key[] = { DOC_PROVV, DOC_ANNO, DOC_CODNUM, DOC_NDOC }; TString80 filter = (i == 1) ? "FROM " : "TO "; for (int k = 0; k < 4; k++) { const TString& val = doc.get(key[k]).as_string(); filter << key[k] << "='" << val << "' "; if (i == 0) curr.put(key[k], val); } filter << '\n'; new_query.insert(filter, acapo); } set(new_query); _doc = new TDocumentoEsteso(curr); // Posiziona correttamente anche il cursore principale *cursor() = 0L; } TDoc_recordset::~TDoc_recordset() { if (_doc != NULL) delete _doc; } /////////////////////////////////////////////////////////// // TReport_doc /////////////////////////////////////////////////////////// class TReport_doc : public TReport { size_t _first_msg; TRelation _firmrel; 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); 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_ditta(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); int set_printed_status(TDocumento& doc) const; public: bool print(const TRecordset& doc, TReport_book& book, bool def); 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"); 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; } bool TReport_doc::print(const TRecordset& doc, TReport_book& book, bool def) { const TString old_query = recordset()->query_text(); TDoc_recordset* rs = new TDoc_recordset(doc, old_query); set_recordset(rs); const bool ok = book.add(*this, false); if (ok && def) set_printed_status(rs->doc()); set_recordset(old_query); return ok; } 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(); TCli_for& cli_for = doc().clifor(); 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_d_spaces(); cf.set(valore); return true; } return false; } bool TReport_doc::msg_ditta(TVariant_stack& stack) { TReport_field& cf = *curr_field(); TString in = stack.pop().as_string(); TString valore; if (in[0]!='!') { cf.set(_firmrel.curr().get(in)); return true; } in.ltrim(1); const bool is_fisc = _firmrel.curr(LF_ANAG).get("INDRF").not_empty(); if (in=="RAGSOC") { valore = _firmrel.curr().get(NDT_RAGSOC); cf.set(valore); return true; } if (in=="IND") { valore = _firmrel.curr(LF_ANAG).get(is_fisc ? "INDRF" : "INDRES"); cf.set(valore); return true; } if (in=="NUM") { valore = _firmrel.curr(LF_ANAG).get(is_fisc ? "CIVRF" : "CIVRES"); cf.set(valore); return true; } if (in=="CAP") { valore = _firmrel.curr(LF_ANAG).get(is_fisc ? "CAPRF" : "CAPRES"); cf.set(valore); return true; } if (in=="COM") { valore = _firmrel.curr(is_fisc ? -213 : -113).get(COM_DENCOM); cf.set(valore); return true; } if (in=="PROV") { valore = _firmrel.curr(is_fisc ? -213 : -113).get(COM_PROVCOM); cf.set(valore); return true; } if (in=="IVA") { cf.set(_firmrel.curr(LF_ANAG).get("PAIV")); return true; } if (in=="CF") { cf.set(_firmrel.curr(LF_ANAG).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; } 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().items(); 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) { doc().summary_filter(selector); const TString& what = stack.pop().as_string(); // cosa deve stampare ? const TVariant value = doc().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) doc().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; } size_t TReport_doc::get_usr_words(TString_array& words) const { TReport::get_usr_words(words); const char* const name[] = { "DOC_CLIENTE", "DOC_DITTA", "DOC_PARENT_DOC", "DOC_PARENT_ROW", "DOC_RIEPILOGO_IVA", "DOC_SCADENZE", "DOC_TOT_IMPONIBILI", 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) { if (opcode < _first_msg) return TReport::execute_usr_word(opcode, stack); opcode -= _first_msg; switch (opcode) { case 0 : msg_cliente(stack); break; case 1 : msg_ditta(stack); break; case 2 : msg_parent_doc(stack); break; case 3 : msg_parent_row(stack); break; case 4 : msg_riepilogo_iva(stack); break; case 5 : msg_scadenze(stack); break; case 6 : msg_tot_imponibili(stack); break; default: break; } while (!stack.pop().is_null()); // Svuota eventuali parametri variabili inutilizzati return true; } void TReport_doc::include_libraries(bool reload) { TReport::include_libraries(reload); if (reload || !defined("MESSAGE_DESCRIGA")) include("ve1300.alx"); } TReport_doc::TReport_doc(const char* name) : _firmrel(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, "COM=STATORES+COMRES", 1, LF_ANAG, 100+LF_COMUNI); _firmrel.add(LF_COMUNI, "COM=STATORES+COMRF", 1, LF_ANAG, 200+LF_COMUNI); _firmrel.curr().put(NDT_CODDITTA, prefix().get_codditta()); _firmrel.read(); load(name); // Faccio la load altrimenti non include la libreria 1300.alx } TReport_doc::~TReport_doc() { } /////////////////////////////////////////////////////////// // 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) { return true; } TReport_doc_mask::TReport_doc_mask() : TAutomask("ve1100a") { hide(F_PROVV); } /////////////////////////////////////////////////////////// // TReport_doc_app /////////////////////////////////////////////////////////// class TReport_doc_app : public TSkeleton_application { TReport_doc_mask* _msk; protected: 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(const TString& query); public: virtual bool create(); virtual void main_loop(); virtual bool destroy(); }; 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 bool per_data = _msk->get(F_DATA_O_NUM) == "D"; if (per_data) add_data_filter(query, from); else add_ndoc_filter(query, from); } 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(); } bool TReport_doc_app::print_loop(const TString& query) { TISAM_recordset doc(query); const int docs = doc.items(); if (docs <= 0) return false; const bool is_definitive = yesno_box(TR("Stampa in definitiva?")); TReport_doc* report = NULL; TReport_book book; TProgind pi(docs, TR("Elaborazione documenti..."), TRUE, TRUE); for (int i = 0; i < docs; i++) { pi.addstatus(1); if (pi.iscancelled()) break; doc.move_to(i); const TString& tipodoc = doc.get(DOC_TIPODOC).as_string(); const TString& codprof = cache().get("%TIP", tipodoc, "S5"); TFilename profilo = codprof; profilo.ext("rep"); if (!profilo.custom_path()) // Tenta di costruirsi il nome del report { TString msg; msg << codprof << " : " << TR("Report inesistente"); statbar_set_title(TASK_WIN, msg); continue; } // Se ho cambiato report cancello il vecchio if (report == NULL || report->filename() != profilo) { delete report; report = new TReport_doc(profilo); } if (!report->print(doc, book, is_definitive)) break; } if (report != NULL) { book.print_or_preview(); delete report; // Distruggere il report DOPO l'anteprima! } return true; } void TReport_doc_app::main_loop() { while (_msk->run() == K_ENTER) { TString query; query << "USE " << LF_DOC; add_filter(query, true); add_filter(query, false); print_loop(query); } } int ve1300(int argc, char* argv[]) { TReport_doc_app a; a.run(argc, argv, TR("Stampa documenti")); return (0); }