#include "velib.h" #include #ifndef __EXECP_H #include #endif #ifndef __TABUTIL_H #include #endif /////////////////////////////////////////////////////////// // Lista di documenti /////////////////////////////////////////////////////////// TDate TLista_documenti::num2date(char provv, int anno, const char* codnum, long num) const { TLocalisamfile doc(LF_DOC); CHECK(num > 0, "Numero documento nullo."); TDocumento::set_key(doc.curr(), provv, anno, codnum, num); if (doc.read(_isgteq) != NOERR) // In caso d'errore ... doc.last(); // prendi l'ultimo return doc.get("DATADOC"); } int TLista_documenti::read(char provv, char tipocf, long clifo, int anno, TToken_string& tipidoc, TToken_string& statidoc, const TDate& dd, const TDate& ad, const char* codnum, long dn, long an) { CHECK(provv == 'D' || provv == 'P', "Provvisorio o Definitivo?"); CHECK(tipocf == 'C' || tipocf == 'F', "Il tipo deve essere Cliente o Fornitore"); CHECKD(clifo > 0L, "Codice cliente non valido", clifo); CHECKD(anno > 1900, "Anno non valido: ", anno); CHECK(!tipidoc.empty_items(), "Lista dei tipi documento vuota"); CHECK(!statidoc.empty_items(), "Lista degli stati documento vuota"); TRelation doc(LF_DOC); TRectype start(LF_DOC), stop(LF_DOC); start.put("TIPOCF", tipocf); stop.put("TIPOCF", tipocf); start.put("CODCF", clifo); stop.put("CODCF", clifo); start.put("PROVV", provv); stop.put("PROVV", provv); start.put("ANNO", anno); stop.put("ANNO", anno); if (dn > 0) { start.put("DATADOC", num2date(provv, anno, codnum, dn)); start.put("NDOC", dn); } else { if (dd.ok() && dd > botime) start.put("DATADOC", dd); } if (an > 0) { stop.put("DATADOC", num2date(provv, anno, codnum, an)); stop.put("NDOC", an); } else { if (ad.ok() && ad < eotime) stop.put("DATADOC", ad); } TString filter(16); if (codnum && *codnum) { bool numfilter = FALSE; if (start.get("DATADOC").empty()) numfilter = TRUE; else start.put("CODNUM", codnum); if (stop.get("DATADOC").empty()) numfilter = TRUE; else stop.put("CODNUM", codnum); if (numfilter) filter << "CODNUM=\"" << codnum << '"'; } TCursor cur(&doc, filter, 2, &start, &stop); const TRectype& head = cur.curr(); _documenti.destroy(); for (cur = 0; cur.ok(); ++cur) { const TString16 tipodoc = head.get("TIPODOC"); const TString16 statodoc = head.get("STATO"); if (tipidoc.get_pos(tipodoc) >= 0 && statidoc.get_pos(statodoc) >= 0) { TDocumento* d = new TDocumento(head); _documenti.add(d); } } return _documenti.items(); } int TLista_documenti::write(bool re) const { int err = NOERR; for (int i = 0; i < _documenti.items() && err == NOERR; i++) err = doc(i).write(re); return err; } /////////////////////////////////////////////////////////// // Cliente/Fornitore per vendite /////////////////////////////////////////////////////////// void TLista_clifo::TClifo::init(const TRectype& rec, const TRectype& ven) { _codice = rec.get_long(CLI_CODCF); CHECK(_codice > 0, "Codice cliente nullo"); if (!ven.empty()) { _agente = ven.get_long(CLI_CODAG); _zona = ven.get_long(CLI_CODZONA); } else _agente = _zona = 0; } bool TLista_clifo::TClifo::read(char tipo, long cod) { TRelation clifo(LF_CLIFO); clifo.add(LF_CFVEN, "TIPOCF=TIPOCF|CODCF=CODCF"); TRectype& curr = clifo.curr(); curr.put(CLI_TIPOCF, tipo); curr.put(CLI_CODCF, cod); if (clifo.read() == NOERR) init(curr, clifo.curr(LF_CFVEN)); else zero(); return ok(); } TLista_clifo::TClifo::TClifo(const TRectype& rec) { CHECK(rec.num() == LF_CLIFO, "Record non clienti"); const char tipo = rec.get_char(CLI_TIPOCF); const long codice = rec.get_long(CLI_CODCF); read(tipo, codice); } int TLista_clifo::leggi(long dc, long ac, long da, long aa, long dz, long az) { TRelation clifo(LF_CLIFO); clifo.add(LF_CFVEN, "TIPOCF=TIPOCF|CODCF=CODCF"); TRectype start(LF_CLIFO), stop(LF_CLIFO); start.put(CLI_TIPOCF, tipo()); if (dc > 0) start.put(CLI_CODCF, dc); stop.put(CLI_TIPOCF, tipo()); if (ac > 0) stop.put(CLI_CODCF, ac); TString filter(32); if (da > 0) filter << '(' << LF_CFVEN << "->" << CLI_CODAG << ">=" << da << ')'; if (aa > 0) { if (filter.not_empty()) filter << "&&"; filter << '(' << LF_CFVEN << "->" << CLI_CODAG << "<=" << aa << ')'; } if (dz > 0) { if (filter.not_empty()) filter << "&&"; filter << '(' << LF_CFVEN << "->" << CLI_CODZONA << ">=" << dz << ')'; } if (az > 0) { if (filter.not_empty()) filter << "&&"; filter << '(' << LF_CFVEN << "->" << CLI_CODZONA << "<=" << az << ')'; } TCursor cur(&clifo, filter, 1, &start, &stop); const TRectype& cli = cur.curr(); const TRectype& ven = cur.curr(LF_CFVEN); for (cur = 0; cur.ok(); ++cur) { TClifo* c = new TClifo(cli, ven); _clifo.add(c); } if (dc > 0 || ac > 0) ordina_per_codice(); else if (da > 0 || aa > 0) ordina_per_agente(); else if (dz > 0 || az > 0) ordina_per_zona(); return _clifo.items(); } int TLista_clifo::sort_by_code(const TObject** o1, const TObject** o2) { TLista_clifo::TClifo* c1 = (TLista_clifo::TClifo*)*o1; TLista_clifo::TClifo* c2 = (TLista_clifo::TClifo*)*o2; const long d = c1->codice() - c2->codice(); return d == 0L ? 0 : (d > 0 ? +1 : -1); } int TLista_clifo::sort_by_agent(const TObject** o1, const TObject** o2) { TLista_clifo::TClifo* c1 = (TLista_clifo::TClifo*)*o1; TLista_clifo::TClifo* c2 = (TLista_clifo::TClifo*)*o2; const long d = c1->agente() - c2->agente(); return d == 0L ? 0 : (d > 0 ? +1 : -1); } int TLista_clifo::sort_by_zone(const TObject** o1, const TObject** o2) { TLista_clifo::TClifo* c1 = (TLista_clifo::TClifo*)*o1; TLista_clifo::TClifo* c2 = (TLista_clifo::TClifo*)*o2; const long d = c1->zona() - c2->zona(); return d == 0L ? 0 : (d > 0 ? +1 : -1); } int TLista_clifo::ordina_per_codice() { _clifo.sort(sort_by_code); return _clifo.items(); } int TLista_clifo::ordina_per_agente() { _clifo.sort(sort_by_agent); return _clifo.items(); } int TLista_clifo::ordina_per_zona() { _clifo.sort(sort_by_zone); return _clifo.items(); } int TLista_clifo::find(long cod) const { for (int i = items()-1; i >= 0; i--) if (clifo(i).codice() == cod) break; return i; } int TLista_clifo::add(long cod) { int pos = find(cod); if (pos < 0) { TClifo* c = new TClifo(tipo(), cod); pos = _clifo.add(c); } return pos; } /////////////////////////////////////////////////////////// // TElaborazione /////////////////////////////////////////////////////////// TElaborazione::TElaborazione(const char* cod) : TRectype(LF_TABCOM) { settab("ELD"); if (cod && *cod) read(cod); } int TElaborazione::read(const char* cod) { CHECK(cod && *cod, "Codice elaborazione nullo"); TTable eld("%ELD"); put("CODTAB", cod); const int err = TRectype::read(eld); if (err != NOERR) yesnofatal_box("Codice elaborazione non valido: %s", cod); return err; } /////////////////////////////////////////////////////////// // TEsterna /////////////////////////////////////////////////////////// TEsterna::TEsterna(const char* cod) : TElaborazione(cod) { } bool TEsterna::elabora(TLista_documenti& doc_in, TLista_documenti& doc_out, const TDate& data_elab) { CHECK(doc_in.items() == 1, "Si deve specificare uno e un solo documento in entrata"); CHECK(doc_out.items() == 1, "Si deve specificare uno e un solo documento in uscita"); TFilename name; name.temp("ext"); { TConfig c(name); TDocumento & d = doc_in[0]; int nfields = d.items(); TString par; par.format("%d,0", LF_DOC); for (int i = 0; i < nfields; i++) { const TString16 fname(d.fieldname(i)); TFieldref f(fname, LF_DOC); f.write(c, par, d.get(fname)); } for (TVariable_field * v = d.first_variable_field(); v ; v = d.succ_variable_field()) c.set(v->name(), v->get(), par); const int rows = d.physical_rows(); if (rows > 0) { nfields = d[0].items(); for (int r = 0; r < rows; r++) { TRiga_documento row = d[r]; par.format("%d,%d", LF_RIGHEDOC, r + 1); for (int i = 0; i < nfields; i++) { const TString16 fname(row.fieldname(i)); TFieldref f(fname, LF_RIGHEDOC); f.write(c, par, row.get(fname)); } } } } TString command_line(applicazione_esterna()); command_line << " -i " << name; TExternal_app app(command_line); if (app.run() == 0) { TConfig c(name); TDocumento & d = doc_out[0]; int nfields = d.items(); TString par; par.format("%d,0", LF_DOC); for (int i = 0; i < nfields; i++) { const TString16 fname(d.fieldname(i)); TFieldref f(fname, LF_DOC); d.put(fname, f.read(c, par)); } for (TVariable_field * v = d.first_variable_field(); v ; v = d.succ_variable_field()) v->put(c.get(v->name(), par)); TString_array p; c.list_paragraphs(p); nfields = d[0].items(); d.destroy_rows(); int r = 1 ; par.format("%d,%d", LF_RIGHEDOC, r); while (p.find(par) >= 0) { TRiga_documento row = d.new_row(); for (int i = 0; i < nfields; i++) { const TString16 fname(row.fieldname(i)); TFieldref f(fname, LF_RIGHEDOC); row.put(fname, f.read(c, par)); } r++; par.format("%d,%d", LF_RIGHEDOC, r); } } return TRUE; } /////////////////////////////////////////////////////////// // TConsegna ordini /////////////////////////////////////////////////////////// TConsegna_ordini::TConsegna_ordini(const char* cod) : TElaborazione(cod) { } bool TConsegna_ordini::elabora(TLista_documenti& doc_in, TLista_documenti& doc_out, const TDate& data_elab) { return TRUE; } /////////////////////////////////////////////////////////// // TFatturazione bolle /////////////////////////////////////////////////////////// TFatturazione_bolle::TFatturazione_bolle(const char* cod) : TElaborazione(cod) { } void TFatturazione_bolle::tipi_validi(TToken_string& tipi) const { const TString& s2 = get("S2"); tipi.cut(0); TString16 t; for (int i = 0; i < 5; i++) { t = s2.mid(i*4, 4); t.trim(); if (t.not_empty()) tipi.add(t); } CHECK(!tipi.empty_items(), "Nessun tipo documento valido"); } void TFatturazione_bolle::stati_validi(TToken_string& stati) const { const TString& s7 = get("S7"); stati.cut(0); TString16 s; for (int i = 0; i < 5; i++) { s = s7.mid(i*4, 1); s.trim(); if (s.not_empty()) stati.add(s); } CHECK(!stati.empty_items(), "Nessuno stato documento valido"); } bool TFatturazione_bolle::raggruppa(TDocumento& doc_in, TDocumento& doc_out) { #ifdef DBG const TString tipi = get("S2"); const TString& tipodoc = doc_in.tipo().codice(); for (int i = 0; i < 5; i++) { if (tipodoc == tipi.mid(i*4, 4)) break; } if (i >= 5) { NFCHECK("Tipo documento non valido: '%s'", (const char*)tipodoc); return FALSE; } #endif const char stato_finale_in = get_char("S4"); doc_in.stato(stato_finale_in); const TString& tipo_out = get("S8"); doc_out.put("TIPODOC", tipo_out); const char stato_finale_out = get_char("S9"); doc_out.stato(stato_finale_out); if (gestione_riferimenti()) { // Determina ed eventualmente crea la riga di riferimento const int riga_rif = riferimenti_in_testa() ? 1 : doc_out.rows()+1; if (riga_rif > doc_out.rows()) { TRiga_documento& rout = doc_out.new_row(); rout.forza_sola_descrizione(); } TRiga_documento& rout = doc_out[riga_rif]; // Costruisce la stringa di riferimento TString riferimento(80); riferimento = doc_in.tipo().riferimento(); if (riferimento.empty()) riferimento = doc_in.tipo().descrizione(); riferimento << " n. " << doc_in.numero(); riferimento << " del " << doc_in.data().string(); // Setta la descrizione se vuota if (rout.get("DESCR").empty()) rout.put("DESCR", riferimento); else { // Altrimenti aggiungi il riferimento al memo TString memo(1024); memo = rout.get("DESCEST"); if (memo.empty()) rout.put("DESCLUNGA", "X"); else memo << '\n'; memo << riferimento; rout.put("DESCEST", memo); } } const bool ignora_desc = ignora_descrizioni(); TToken_string campi_riga(80); const bool ragg_rig = raggruppa_righe(); if (ragg_rig) { campi_riga = "CODART|UMQTA"; // Uguali sempre // Uguali opzionalmente if (riga_uguale(0)) campi_riga.add("CODMAG"); if (riga_uguale(1)) campi_riga.add("CODIVA"); if (riga_uguale(2)) campi_riga.add("PREZZO|SCONTO"); } for (int r = 1; r <= doc_in.rows(); r++) { const TRiga_documento& rin = doc_in[r]; const bool rindesc = rin.sola_descrizione(); // La riga di input e' descrittiva if (ignora_desc && rindesc) continue; bool elaborata = FALSE; // Raggruppo le righe se e' settato il falg di raggruppamento e // se la riga non contiene solo una descrizione if (ragg_rig && !rindesc) // Se devo raggruppare le righe ... { const int last = doc_out.rows(); for (int o = 1; o <= last; o++) // ... cerca una riga compatibile { TRiga_documento& rout = doc_out[o]; if (rout.sola_descrizione()) // Ignora le righe descrittive continue; if (rin.raggruppabile(rout, campi_riga)) // Se esiste una riga compatibile ... { rout += rin; // ... sommaci la quantita' ecc. elaborata = TRUE; // Ricorda di averla gia' elaborata break; } } } if (!elaborata) // Se la riga non e' stata gia' sommata ... { TRiga_documento& rout = doc_out.new_row(); // ... crea una riga nuova e ... doc_out.copy_data(rout, rin); // ... copiaci tutti i campi della riga sorgente. } } return TRUE; } bool TFatturazione_bolle::elabora(TLista_documenti& doc_in, TLista_documenti& doc_out, const TDate& data_elab) { bool ok = TRUE; TToken_string campi_doc(128); // Lista di campi che devono essere uguali campi_doc = "TIPOCF|CODCF|CODVAL|CODLIN"; // Uguali sempre // Uguali opzionalmente const char* cond[] = { "CAMBIO", "SCONTO", "TIPODOC", "CODNUM", "CODPAG", "CODABIA|CODCABA", "CODLIST", "CODAG", "CODSPMEZZO", "CODPORTO", "CAUSTRASP", "CODVETT1|CODVETT2|CODVETT3", NULL }; for (int u = 0; cond[u]; u++) if (doc_uguale(u)) campi_doc.add(cond[u]); for (int id = 0; id < doc_in.items() && ok; id++) { TDocumento& campione = doc_in[id]; const int tot = doc_out.items(); int od = tot; if (campione.raggruppabile()) // Se il documento ha il flag di raggruppabilita' ... { for (od = 0; od < tot; od++) // ... cerca un documento compatibile. { if (campione.raggruppabile(doc_out[od], campi_doc)) break; } } if (od >= tot) // Se non ho trovato un documento compatibile ... { // ... creane uno nuovo (certamente compatibile) const char provv = tipo_numerazione(); const int anno = campione.anno(); const TString codnum = codice_numerazione_finale(); TDocumento* new_doc = new TDocumento(provv, anno, codnum, -1); // Copia i dati della testata TDocumento::copy_data(new_doc->head(), campione.head()); new_doc->put("DATADOC", data_elab); // Aggiungilo alla lista dei documenti in uscita od = doc_out.add(new_doc); } ok = raggruppa(campione, doc_out[od]); } return ok; } /////////////////////////////////////////////////////////// // TContabilizzazione /////////////////////////////////////////////////////////// TContabilizzazione::TContabilizzazione(const char* cod) : TElaborazione(cod) { } bool TContabilizzazione::elabora(TLista_documenti& doc_in, TLista_documenti& doc_out, const TDate& data_elab) { CHECK(doc_in.items() == 1, "Si deve specificare uno e un solo documento in entrata"); CHECK(doc_out.items() == 1, "Si deve specificare uno e un solo documento in uscita"); return TRUE; } /////////////////////////////////////////////////////////// // TCopia_documento /////////////////////////////////////////////////////////// TCopia_documento::TCopia_documento(const char* cod) : TElaborazione(cod) { } bool TCopia_documento::elabora(TLista_documenti& doc_in, TLista_documenti& doc_out, const TDate& data_elab) { CHECK(doc_in.items() == 1, "Si deve specificare uno e un solo documento in entrata"); CHECK(doc_out.items() == 1, "Si deve specificare uno e un solo documento in uscita"); TDocumento & doc_src = doc_in[0]; TDocumento & doc_dest = doc_out[0]; doc_dest.copy_contents(doc_src); return TRUE; } /////////////////////////////////////////////////////////// // TGenerazione_effetti /////////////////////////////////////////////////////////// TGenerazione_effetti::TGenerazione_effetti(const char* cod) : TElaborazione(cod) { } bool TGenerazione_effetti::elabora(TLista_documenti& doc_in, TLista_documenti& doc_out, const TDate& data_elab) { CHECK(doc_in.items() == 1, "Si deve specificare uno e un solo documento in entrata"); CHECK(doc_out.items() == 1, "Si deve specificare uno e un solo documento in uscita"); return TRUE; } /////////////////////////////////////////////////////////// // TLista_elaborazioni /////////////////////////////////////////////////////////// void TLista_elaborazioni::read() { if (_elab == NULL) { _elab = new TAssoc_array(); TTable eld("%ELD"); for (int err = eld.first(); err == NOERR; err = eld.next()) { TElaborazione * el = NULL; switch (eld.curr().get_int("I0")) { case _esterna : el = new TEsterna(eld.curr()); break; case _consegna_ordini: el = new TConsegna_ordini(eld.curr()); break; case _fatturazione_bolle : el = new TFatturazione_bolle(eld.curr()); break; case _contabilizzazione : el = new TContabilizzazione(eld.curr()); break; case _copia_documento : el = new TCopia_documento(eld.curr()); break; case _generazione_effetti : el = new TGenerazione_effetti(eld.curr()); break; default : break; } _elab->add(el->codice(), el); } } } int TLista_elaborazioni::select(TString_array & result, bool interattivo, bool insert_mode, const char * tipo_iniziale, const char * stato_iniziale, const char * tipo_finale, const char * stato_finale) { read(); _elab->restart(); result.destroy(); for (TElaborazione * el = (TElaborazione *)_elab->get(); el ; el = (TElaborazione *) _elab->get()) { bool ok = TRUE; if (tipo_iniziale && stato_iniziale) { bool found = FALSE; for (int i = 0; !found && i < 5; i++) found = el->tipo_iniziale(i) == tipo_iniziale && el->stato_iniziale(i) == *stato_iniziale; ok = found; } ok &= (tipo_finale && stato_finale && el->tipo_finale() == tipo_finale && el->stato_finale() == *stato_finale); if (ok && (!interattivo || interattivo == el->interattivo()) && (!insert_mode || insert_mode == el->insert_mode())) result.add(el->codice()); } return result.items(); } TElaborazione & TLista_elaborazioni::operator [](const char * key) const { ((TLista_elaborazioni *)this)->read(); return (TElaborazione &) (*_elab)[key]; } void TLista_elaborazioni::update() { delete _elab; _elab = NULL; read(); } TLista_elaborazioni::~TLista_elaborazioni() { if (_elab) delete _elab; }