// ve6300.cpp: programma di generazione effetti // Muliebrica parodia... // Il cavo delirante che irrompe nel silenzio dell'apogeo // * * * * * * * // * // _ _______ _____________ ___================ // _I_I___oo_____ii__| |_|| | | \ | |O| |_| |_| // | | - - | I | | | L M S | | | | // _|___|________|____ I____|_|=|_____________|=II=|__|_|_____________ // I=| o (_)--(_)--(_)--(_) O--O O-O +++++ O-O \--/ ()==() ++++ //======================================================================= // // // ____||____============____||___ ___=============================== // /__| OOOOOOOOOOOOO [_] | | |[]| [_] [_] [_] [_] // / S N C F | | | | // \________________________________|_ii_|__|__|___________________________ // ()==() === ++++ === ()==() ()==() +++ +++ ++++++++ //========================================================================= // // Have you ever heard MK ? #include #include #include #include #include #include #include #include "velib04.h" #include "ve6300a.h" #include // TGenerazioneEffetti_app // Applicazione di generazione effetti class TGenerazioneEffetti_app : public TSkeleton_application { TString16 _cod_el; // codice elaborazione immesso bool _raggruppa; // se TRUE raggruppa gli effetti secondo i criteri TMask *_msk; // maschera di selezione dati TBit_array _valid_array; // array dei tipi di pagamento validi per la generazione di effetti TArray_sheet *_num_sheet; // Array sheet selezionabile dei codici numerazione TAssoc_array _group_array; // Assoc_array dei documenti da raggruppare. La chiave di ogni elemento TString_array _tipi_doc; // Array di stringhe contenente i tipi documenti da elaborare char _final_doc_status; // Valore per lo stato finale del documento // Flags di raggruppamento opzionali (%ELD->S1): bool _group_by_date, // raggruppa per data di scadenza _group_by_sosp, // raggruppa per flag sosp. d'imposta _group_by_change, // raggruppa per cambio _group_by_pag, // raggruppa per cond. di pagamento _group_by_bank, // raggruppa per banca (ABI-CAB) _group_by_type, // raggruppa per tipo di documento _group_by_num, // raggruppa per cod. numerazione _group_by_agent; // raggruppa per agente TArray _file; protected: // TApplication // Le 4 seguenti non hanno bisogno di commenti virtual void main_loop(); virtual bool create(); virtual bool destroy(); // Cambia lo stato del documento int change_doc_status(TDocumento*); // Coontrolla se lo stato ed il tipo del documento sono validi e rispettano la selezione bool doc_tipo_stato_ok(TDocumento*); // Handler del codice elaborazione differita static bool handle_cod_eld(TMask_field& f, KEY k); // Handler dell'intervallo di date static bool handle_data_range(TMask_field& f, KEY k); // Handler del pulsante di selezione codici numerazione static bool handle_select(TMask_field& f, KEY k); // Handler del campo numerazione static bool handle_codnum(TMask_field& f, KEY k); // Ritorna il TArray_sheet contenente le selezioni sui codici numerazione TArray_sheet* get_num_sheet() const { return _num_sheet; } // Costruisce lo sheet dei codici numerazione void build_num_sheet(); // Aggiunge il documento corrente alla lista dei documenti raggruppabili void add_to_group_list(TDocumento* doc); // Costruisce la stringa chiave per raggruppamento void build_group_key(TString& key, TDocumento* doc); // Costruisce la stringa chiave per documento void build_doc_key(TToken_string& key, TDocumento* doc); // Setta i flags di raggruppamento opzionali in base alla tabella void set_options(); void generate(); public: TGenerazioneEffetti_app() {_msk = NULL; _num_sheet = NULL;} virtual ~TGenerazioneEffetti_app() { } }; inline TGenerazioneEffetti_app& app() { return (TGenerazioneEffetti_app&) main_app(); } bool TGenerazioneEffetti_app::handle_data_range(TMask_field& f, KEY k) { if (k==K_ENTER && f.dirty()) { TMask& m = f.mask(); TDate da(m.get_date(F_DATA_INI)); TDate a(m.get_date(F_DATA_FIN)); //m.field(F_DATA_REG).set_dirty(); //if (a == botime || da == botime) return TRUE; if (a < da) { f.error_box("La data di inizio deve essere minore della data di fine."); return FALSE; } //if ((a - da) > 15) //{ // f.error_box("L'intervallo tra le date non puo' eccedere i 15 giorni."); // return FALSE; //} } return TRUE; } bool TGenerazioneEffetti_app::handle_cod_eld(TMask_field& f, KEY k) { TMask& m = f.mask(); if (k == K_TAB && !m.is_running()) { TEdit_field& e = (TEdit_field&)f; TCursor& cur = *e.browse()->cursor(); if (cur.items() > 0) { cur = 0L; const TRectype& eld = cur.curr(); app()._cod_el = eld.get("CODTAB"); f.set(app()._cod_el); m.set(F_DESC_ELAB, eld.get("S0")); app().build_num_sheet(); } } if (f.to_check(k) && k == K_TAB) // se e' cambiato ricostruisce anche lo sheet dei codici numerazione { app()._cod_el = f.get(); // aggiorna il codice elaborazione per la build_num_sheet() app().build_num_sheet(); m.disable(DLG_OK); } return TRUE; } bool TGenerazioneEffetti_app::handle_select(TMask_field& f, KEY k) { if (k == K_SPACE) { TArray_sheet& s = *app().get_num_sheet(); if (s.run()) { TMask& m = f.mask(); if (s.checked() > 0) // Hai selezionato qualcosa ? { // Cerca di proporre la prima numerazione possibile for (long i = 0; i < s.items(); i++) if (s.checked(i)) { TToken_string& row = s.row(i); m.set(F_CODNUM, row.get(1)); m.set(F_DESCNUM, row.get()); break; } m.enable(DLG_OK); // allora abilita il pulsante di conferma } else m.disable(DLG_OK); } } return TRUE; } bool TGenerazioneEffetti_app::handle_codnum(TMask_field& f, KEY k) { TMask& m = f.mask(); if (k == K_F9) return handle_select(m.field(DLG_USER), K_SPACE); if (k == K_TAB && f.focusdirty() && !f.empty()) { m.set(F_DESCNUM, cache().get("%NUM", f.get(), "S0")); k = K_ENTER; } if (k == K_ENTER) { TArray_sheet& s = *app().get_num_sheet(); for (long i = 0; i < s.items(); i++) if (s.row_enabled(i)) { TToken_string& row = s.row(i); if (f.get() == row.get(1)) return TRUE; } return error_box("Numerazione non valida"); } return TRUE; } void TGenerazioneEffetti_app::build_num_sheet() { _num_sheet->destroy(); _tipi_doc.destroy(); if (_cod_el.not_empty()) { TContabilizzazione* cont = new TContabilizzazione(_cod_el); if (!cont->empty()) { TToken_string t; TString16 tipo; _final_doc_status = cont->stato_finale()[0]; for (int i=0;itipo_iniziale(i); if (tipo.not_empty()) { t = tipo; t.add(cont->stato_iniziale(i)); // Stato iniziale _tipi_doc.add(t); // Aggiunge questo tipo documento alla lista } } long pos = 0l; TTable num("%NUM"); for (num.first();num.good();num.next(),pos++) // scorre tutte le numerazioni possibili { TToken_string t,z; t.add(" "); t.add(num.get("CODTAB")); t.add(num.get("S0")); _num_sheet->add(t); const TString& s2 = num.get("S2"); // reperisce i tipi documento validi per questa numerazione for (int x = 0; x <= s2.len(); x += 4) z.add(s2.mid(x,4)); bool found = FALSE; for (int i = _tipi_doc.last(); !found && i >= 0; i--) found |= (z.find(((TToken_string &)_tipi_doc[i]).get(0)) >= 0); if (found) _num_sheet->enable_row(pos); else _num_sheet->disable_row(pos); } // Applica un filtro ai documenti da elaborare TString filter; for (int td = _tipi_doc.last(); td >= 0; td--) { TToken_string& row = _tipi_doc.row(td); if (filter.not_empty()) filter << "||"; filter << "((" << DOC_TIPODOC << "==\"" << row.get(0) << "\")&&("; filter << DOC_STATO << "==\"" << row.get(1) << "\"))" ; } _msk->efield(F_NDOC_INI).browse()->set_filter(filter); _msk->efield(F_NDOC_FIN).browse()->set_filter(filter); } delete cont; } } bool TGenerazioneEffetti_app::create() { if (!has_module(EFAUT)) { error_box("Impossibile eseguire il programma se il modulo Effetti non e' abilitato"); return FALSE; } open_files(LF_TABCOM, LF_TAB, LF_CLIFO, LF_OCCAS, LF_INDSP, LF_CFVEN, LF_DOC, LF_RIGHEDOC, LF_ANAMAG, LF_MOVMAG, LF_RMOVMAG, LF_CONDV, LF_SVRIEP, LF_AGENTI, LF_PERCPROV, LF_CESS, LF_CAUSALI, 0); _msk = new TMask("ve6300a"); _msk->set_handler(F_CODICE_ELAB, handle_cod_eld); _msk->set_handler(F_DATA_INI, handle_data_range); _msk->set_handler(F_DATA_FIN, handle_data_range); _msk->set_handler(F_CODNUM, handle_codnum); _msk->set_handler(DLG_USER, handle_select); _num_sheet = new TArray_sheet(-1,-1,-4,-4,"Codici numerazione", "@1|Cod. numerazione|Descrizione@50"); return TSkeleton_application::create(); } bool TGenerazioneEffetti_app::destroy() { if (_msk) delete _msk; if (_num_sheet) delete _num_sheet; return TSkeleton_application::destroy(); } void TGenerazioneEffetti_app::main_loop() { while (_msk->run() == K_ENTER) { _cod_el = _msk->get(F_CODICE_ELAB); _raggruppa = _msk->get_bool(F_RAGGRUPPA); generate(); } } bool TGenerazioneEffetti_app::doc_tipo_stato_ok(TDocumento* doc) // Verifica che il tipo documento corrente esista tra i tipi previsti dalla elaborazione // differita selezionata { const int items = _tipi_doc.items(); bool found = FALSE; const TString16 tipo(doc->tipo().codice()); const char stato = doc->stato(); for (int i=0;istato(_final_doc_status); return doc->rewrite(); } // Criteri di raggruppamento effetti. // Un documento puo' essere raggruppato con i seguenti criteri: // - flag di raggruppamento effetti a TRUE (obbligatorio) // - cliente (obbligatorio) // - valuta (obbligatorio) // - data scadenza (opzionale) // - flag di sosp. d'imposta (opzionale) // - cambio valuta (opzionale) // - cond di pagamento (opzionale) // - banca (opzionale) // - tipo doc. (opzionale) // - cod. numerazione (opzionale) // - agente (opzionale) // I parametri opzionali sono decisi nella tabella elaborazioni // Spiegazione del raggruppamento: // Il raggruppamento di documenti diversi in uno stesso effetto consiste nella creazione // di piu' righe dello stesso effetto. // Ad esempio supponiamo di avere il cliente 10 con 4 fatture ognuna con condizioni di pagamento diverse // la fattura 1 e' suddivisa in 2 rate (10.000 + 30.000) // la fattura 2 e' suddivisa in 4 rate (15.000 + 20.000 + 25.000 + 30.000) // la fattura 3 e' suddivisa in 5 rate (20.000 + 40.000 + 80.000 + 160.000 + 320.000) // la fattura 4 e' suddivisa in 3 rate (50.000 + 100.000 + 150.000) // Il numero di effetti generati equivale al massimo numero di rate (5 in questo caso) // quindi avremo 5 effetti: // il primo avra' 4 righe (prima rata di tutte le fatture) // il secondo avra' 4 righe (seconda rata di tutte le fatture) // il terzo avra' 3 righe (terza rata delle fatture 2,3,4) // il quarto avra' 2 righe (quarta rata delle fatture 2 e 3) // il quinto avra' 1 riga (quinta rata della fattura 3) // La testata di ogni effetto conterra' il totale (somma) dei singoli importi delle righe // ovvero: // tot. primo effetto: 95.000 // tot. secondo effetto: 190.000 // tot. terzo effetto: 255.000 // tot. quarto effetto: 190.000 // tot. quinto effetto: 320.000 // I dati della testata (soprattutto la data di scadenza) di ogni effetto vengono presi dal // primo documento valido per la generazione dell'effetto corrente: // per i primi due effetti vale la fattura 1 // per gli effetti 3 e 4 vale la fattura 2 // per l'effetto 5 vale la fattura 3. // Questo e' quanto ho appreso (Hope I'm right...) ;-) void TGenerazioneEffetti_app::add_to_group_list(TDocumento* doc) { TString key; TToken_string t("",'$'); build_group_key(key,doc); build_doc_key(t,doc); const bool is_key = _group_array.is_key(key); TToken_string tt(is_key ? (TToken_string&) _group_array[key]: ""); tt.add(t); _group_array.add(key,tt, is_key ? TRUE : FALSE); } void TGenerazioneEffetti_app::build_group_key(TString& key, TDocumento* doc) { const long cli = doc->get_long(DOC_CODCF); TString16 val; if (doc->in_valuta()) val = doc->get(DOC_CODVAL); // campi obbligatori key.format("%7ld%3s",cli,(const char*)val); // campi opzionali if (_group_by_date) { TString16 d(doc->get(DOC_DATAINSC)); if (d.empty()) d = doc->get(DOC_DATADOC); key << d; } // Qual'e' il flag di sospensione d'imposta del documento ?? // if (_group_by_sosp) // key << _doc->get(DOC_????); if (_group_by_change) key << doc->get(DOC_CAMBIO); if (_group_by_pag) key << doc->get(DOC_CODPAG); if (_group_by_bank) { key << doc->get(DOC_CODABIA); // banca cliente key << doc->get(DOC_CODCABA); } if (_group_by_type) key << doc->get(DOC_TIPODOC); if (_group_by_num) key << doc->get(DOC_CODNUM); if (_group_by_agent) key << doc->get(DOC_CODAG); } void TGenerazioneEffetti_app::build_doc_key(TToken_string& key, TDocumento* doc) { key.add(doc->get(DOC_PROVV)); key.add(doc->get(DOC_ANNO)); key.add(doc->get(DOC_CODNUM)); key.add(doc->get(DOC_NDOC)); } void TGenerazioneEffetti_app::set_options() { const TRectype& eld = cache().get("%ELD", _cod_el); if (!eld.empty()) { TString s1; s1.format("%-20s",(const char*)eld.get("S1")); // Forzo la sua lunghezza a 20 per evitare subscript errors _group_by_date = s1[12] == 'X'; _group_by_sosp = s1[13] == 'X'; _group_by_change = s1[0] == 'X'; _group_by_pag = s1[4] == 'X'; _group_by_bank = s1[5] == 'X'; _group_by_type = s1[2] == 'X'; _group_by_num = s1[3] == 'X'; _group_by_agent = s1[7] == 'X'; } } void TGenerazioneEffetti_app::generate() { TRelation doc_rel(LF_DOC); const long items = _num_sheet->items(); long tot = 0L; TGenerazione_effetti gen_eff(_cod_el); TDate data; _group_array.destroy(); set_options(); const bool sort_by_date = _msk->get_int(F_ORDERBY) == 0; for (long i=0L; irow(i).get(1); // Controlla se la numerazione corrente e' stata selezionata bool is_selected = _num_sheet->row_enabled(i); if (is_selected) { if (sort_by_date) is_selected = _num_sheet->checked(i); else is_selected = _msk->get(F_CODNUM) == codnum; } if (!is_selected) continue; TString filt_expr; int cursor_key = 0; TRectype da(LF_DOC), a(LF_DOC); da.put(DOC_PROVV,"D"); a.put(DOC_PROVV,"D"); if (sort_by_date) { cursor_key = 3; const TDate dataini = _msk->get_date(F_DATA_INI); da.put(DOC_ANNO,dataini.year()); da.put(DOC_DATADOC,dataini); const TDate datafin = _msk->get_date(F_DATA_FIN); a.put(DOC_ANNO,datafin.year()); a.put(DOC_DATADOC,datafin); filt_expr << DOC_CODNUM << "=\"" << codnum << "\""; } else { cursor_key = 1; da.put(DOC_ANNO, _msk->get(F_ANNO)); da.put(DOC_CODNUM, codnum); da.put(DOC_NDOC, _msk->get(F_NDOC_INI)); a.put(DOC_ANNO, _msk->get(F_ANNO)); a.put(DOC_CODNUM, codnum); a.put(DOC_NDOC, _msk->get(F_NDOC_FIN)); } TCursor doc_cur(&doc_rel, filt_expr, cursor_key, &da, &a); const long cur_items = doc_cur.items(); // Scorre tutti i documenti che rientrano nell'intervallo selezionato if (cur_items == 0) { warning_box("Non vi sono effetti da generare per il codice numerazione %s",(const char*)codnum); continue; } TString msg; msg << "Selezione documenti " << codnum; if (sort_by_date) { msg << " dal " << _msk->get(F_DATA_INI); msg << " al " << _msk->get(F_DATA_FIN); } else { msg << " dal " << _msk->get(F_NDOC_INI); msg << " al " << _msk->get(F_NDOC_FIN); } TProgind p(cur_items,msg,FALSE,TRUE); long j = 0; // Comportamento: // - scorre i documenti della numerazione corrente. // - se e' possibile generare subito l'effetto (tipo di pagamento valido, // stato documento valido e non e' abilitato il raggruppamento) lo fa, // altrimenti compone una lista dei documenti da raggruppare // - alla fine del ciclo per numerazioni scorre la lista residua e genera gli // effetti rimasti for (;jread(doc_cur.curr()) == NOERR && // legge il documento codnum == doc->get(DOC_CODNUM) && // patch del cazzo doc_tipo_stato_ok(doc)) // controlla che il tipo documento e lo stato siano coerenti con la ELD selezionata { TPagamento & pag = doc->pagamento(); if (pag.code().not_empty()) { const bool raggruppabile = doc->get_bool(DOC_RAGGREFF); if (!_raggruppa || (_raggruppa && !raggruppabile)) { // Aggiunge alla lista degli effetti da generare singolarmente TLista_documenti lista_in,lista_out; lista_in.add(doc); if (!gen_eff.elabora(lista_in,lista_out,data)) // La data non serve, cosi' come la lista documenti in uscita gen_eff.set_writeable(FALSE); tot += gen_eff.bills(); } else { add_to_group_list(doc); // Aggiorna la lista degli effetti da raggruppare delete doc; } } else { int err = change_doc_status(doc); // Cambia lo stato al documento if (err != NOERR) warning_box("Errore %d tentando di cambiare lo stato del documento %s/%d",err,(const char*)doc->numerazione(),doc->numero()); delete doc; } } else delete doc; } } // Ogni elemento di _group_array è una TToken_string. Ogni elemento della TToken_string contiene // la chiave per identificare il documento che fa parte di quel raggruppamento tot += gen_eff.group_bills(_group_array);// Setta l'elenco dei documenti per generare effetti raggruppati if (tot > 0L) message_box("Totale effetti generati: %ld", tot); xvtil_statbar_set(""); } int ve6300 (int argc, char **argv) { TGenerazioneEffetti_app a; a.run(argc,argv,"Generazione effetti"); return TRUE; }