// Programma di gestione provvigioni #include #include #include "../ve/velib.h" #include "prlib.h" #include "provv.h" #include "pr0700a.h" #include "pr0700b.h" #include "pr0.h" class TGestione_provv_app : public TSkeleton_application { TMask *_msk; TDocumento *_documento; TLocalisamfile *_provv, *_rdoc, *_doc, *_tab, *_occas, *_cfven; TProvvigioni_agente *_prag; TAssoc_array _vittime; bool _dirty; protected: virtual bool create(); virtual bool destroy(); virtual void main_loop(); void kill_vittime(); void load_provvigioni(TMask* m); void fill_sheet_doc(); bool check_totals(); static bool doc_sheet_notify(TSheet_field& ds, int r, KEY key); static bool rate_sheet_notify(TSheet_field& rs, int r, KEY key); static bool nrata_handler(TMask_field& f, KEY key); static bool ndoc_handler(TMask_field& f, KEY key); static bool calcola_rate_handler(TMask_field& f, KEY k); static bool datascad_handler(TMask_field& f, KEY key); static bool imprata_handler(TMask_field& f, KEY key); static bool improvv_handler(TMask_field& f, KEY key); static bool enable_handler(TMask_field& f, KEY k); static void fill_rate_doc(TRate_doc& rd, TSheet_field& sf); public: }; static inline TGestione_provv_app& app() { return (TGestione_provv_app&) main_app(); } static TString16 __current_key; //////////////////////////////////////////////////////////////////////////////////////// // Da fare : // - Quando si elimina l'ultima riga dello spreadsheet si posiziona sulla prima senza // mandare un K_TAB per aggiornare le rate // - Browse dei documenti in ricerca, quando si seleziona setta giustamente focusdirty() e manda // un K_TAB. Quando si tenta di uscire dal campo si ha ancora il campo focusdirty() // - Cercare di implementare scarico/saldo righe provvigionali per agente in base ad una // impostata // - Ultimo ma non meno importante (da ritenersi visualmente valido) lo riempimento fisso // degli sheet (documenti e rate) in modo da evitare il fastidiosissimo sfarfallio in // inserimento righe con elementi vuoti //////////////////////////////////////////////////////////////////////////////////////// bool TGestione_provv_app::calcola_rate_handler(TMask_field& f, KEY key) { // - Impostazione importi e provvigioni (documento) in caso di selezione documento // - Calcolo righe di provvigioni in caso di selezione documento (integrato in TDocumento) // - Rata 0 : importo rata = 0; importo provvigione = provvigione all'atto della fattura (percentuale sugli agenti) // la provvigione rimanente va suddivisa in rate a seconda del codice pagamento if (f.focusdirty() && key == K_TAB) { TMask& m = f.mask(); TLocalisamfile& doc = *app()._doc; TSheet_field & rs = (TSheet_field&)app()._msk->field(F_RATE_SHEET);// Resetta lo spreadsheet if (rs.items() > 0) // Resetta lo spreadsheet se vi sono delle righe rs.reset(); doc.put(DOC_PROVV,"D"); doc.put(DOC_ANNO,m.get_int(F_ANNO)); doc.put(DOC_CODNUM,m.get(F_CODNUM)); doc.put(DOC_NDOC,m.get(F_NDOC)); if (doc.read() == NOERR) // Se esiste il documento allora prende i valori relativi al totale documento, totale provvigione e base di calcolo provvigione { TDocumento* documento = app()._documento; int err = documento->read(doc.curr()); if (err == NOERR) { m.set(F_DATADOC, documento->data()); m.set(F_CLIENTE, documento->codcf()); m.set(F_CODVAL,documento->valuta()); m.set(F_CAMBIO,documento->cambio()); m.set(F_DATACAMBIO,documento->get_date(DOC_DATACAMBIO)); m.set(F_IMPDOC,documento->totale_doc()); m.set(F_IMPPRDOC,documento->provvigione()); m.set(F_IMPNETDOC, documento->totale_netto()); // Adesso calcoliamo la provvigione all'atto della fatturazione da inserire // nella rata 0. Il residuo va ripartito nelle rate del documento TProvvigioni_agente& pra = documento->calc_provvigioni(FALSE); // Non settare il flag di generata dal documento! // Adesso genera le righe da mettere nello spreadsheet. Quando si uscira' dalla riga // attuale verra' chiamata la doc_sheet_notify() con K_ENTER, che memorizza il tutto // gestendo automaticamente la eventuale modifica di un documento gia' presente o meno. TRate_doc& rd = pra.rate(documento->anno(), m.get(F_CODNUM), documento->numero()); // Estrae le rate appena calcolate const int numrate = rd.items(); /* Numero rate per questo documento */ for (int i = 0; i < numrate; i++) { TToken_string& ttt = rs.row(i); TRata& rt = rd[i]; ttt.add(rt.rata()); // Numero di rata ttt.add(rt.datascad()); // Data scadenza della rata ttt.add(rt.tipopag()); // Tipo pag per questa rata ttt.add(rt.imprata().string()); // Importo della rata (occhio alla valuta) ttt.add(rt.impprovv().string()); // Importo della provvigione per questa rata ttt.add(""); // Tutti gli altri valori sono a 0 ttt.add(""); ttt.add(""); ttt.add(""); ttt.add(""); ttt.add(""); } rs.force_update(); f.set_focusdirty(FALSE); f.set_dirty(FALSE); } else return f.error_box("Errore %d tentando di leggere il documento specificato",err); } // Altrimenti l'utente e' libero di inserire importi e rate } return TRUE; } bool TGestione_provv_app::ndoc_handler(TMask_field& f, KEY key) { if (key == K_ENTER) // Quando sta cambiando riga... { // Scorre tutte le righe dello spreadsheet esaminando ANNO+CODNUM+NDOC // nel caso trovi un'altra riga con la stessa chiave, visualizza un errore TSheet_field& s = *f.mask().get_sheet(); const int selected = s.selected(); const int items = s.items(); // Numero di righe dello spreadsheet TToken_string& tt = s.row(selected); int anno = tt.get_int(0); TString codnum = tt.get(1); long ndoc = tt.get_long(2); TString key,other_key; key.format("%4d%4s%7ld",anno,(const char*)codnum,ndoc); for (int i = 0; i < items; i++) if (i != selected) { TToken_string& ot = s.row(i); anno = ot.get_int(0); codnum = ot.get(1); ndoc = ot.get_long(2); other_key.format("%4d%4s%7ld",anno,(const char*)codnum,ndoc); if (key == other_key) return f.error_box("Non e' possibile inserire due documenti con lo stessa chiave"); } } return calcola_rate_handler(f, key); } bool TGestione_provv_app::nrata_handler(TMask_field& f, KEY key) { if (key == K_ENTER) { // Scorre tutte le righe dello spreadsheet esaminando il numero di rata // nel caso trovi un'altra riga con lo stesso numero, visualizza un errore const int nrata = atoi(f.get()); TSheet_field& s = *f.mask().get_sheet(); const int selected = s.selected(); const int items = s.items(); // Numero di righe dello spreadsheet for (int i = 0; i < items; i++) if (i != selected) { int other_rata = s.row(i).get_int(0); if (nrata == other_rata) return f.error_box("Non e' possibile inserire due rate con lo stesso numero"); } } return TRUE; } bool TGestione_provv_app::datascad_handler(TMask_field& f, KEY key) { if (key == K_ENTER && __current_key.not_empty()) { TProvvigioni_agente* pa = app()._prag; TRate_doc& rd = pa->rate(__current_key); TDate d(f.get()); if (d < rd.datadoc()) return f.error_box("La data di scadenza deve essere maggiore o uguale della data documento"); } return TRUE; } // Abilita le colonne PAGATO e PROVVPAG per evntuale editing degli importi bool TGestione_provv_app::enable_handler(TMask_field& f, KEY key) { if (key == K_SPACE) f.mask().enable(-5); return TRUE; } bool TGestione_provv_app::imprata_handler(TMask_field& f, KEY key) { if (key == K_ENTER && __current_key.not_empty()) { TProvvigioni_agente* pa = app()._prag; TRate_doc& rd = pa->rate(__current_key); real r(f.get()); if (r > rd.impdoc()) return f.error_box("L'importo della rata non puo' essere maggiore dell'importo del documento"); } return TRUE; } bool TGestione_provv_app::improvv_handler(TMask_field& f, KEY key) { if (key == K_ENTER && __current_key.not_empty()) { TProvvigioni_agente* pa = app()._prag; TRate_doc& rd = pa->rate(__current_key); real r(f.get()); if (r > rd.impprdoc()) return f.error_box("L'importo della provvigione non puo' essere maggiore dell'importo provvigione del documento"); } return TRUE; } void TGestione_provv_app::fill_rate_doc(TRate_doc& rd, TSheet_field& sf) { // Righe delle rate const int items = sf.items(); rd.remove_rata(); // cancella tutte le rate for (int i = 0; i < items; i++) // Aggiunge le rate presenti nello sheet { TToken_string& tt = sf.row(i); TRata* rt = new TRata; rt->set(tt); rd.add_rata(rt); } } bool TGestione_provv_app::rate_sheet_notify(TSheet_field& ds, int r, KEY key) { TProvvigioni_agente* pa = app()._prag; if (__current_key.empty() || pa->items() == 0) return TRUE; TRate_doc& rd = pa->rate(__current_key); switch (key) { case K_INS: // Inserimento di una nuova rata vuota { TRata* rt = new TRata; // Nuova rata: va segnalata come inserita (generata = blank) rd.add_rata(rt); app()._dirty = TRUE; } break; case K_ENTER: // Notifica dell'avvenuta modifica di una rata { TRata& rt = rd[r]; // Sostituisce i valori della riga corrente rt.set(ds.row(r)); app()._dirty = TRUE; } break; case K_DEL: // Notifica della cancellazione di una riga rd.remove_rata(r); rd.pack_rate(); // Effettua anche il pack degli elementi (corrispondenza 1 a 1 tra sheet ed array) app()._dirty = TRUE; break; default: break; } return TRUE; } bool TGestione_provv_app::doc_sheet_notify(TSheet_field& ds, int r, KEY key) { TProvvigioni_agente* pa = app()._prag; switch (key) { case K_INS: // Inserimento di un nuovo documento { TSheet_field& rs = ds.mask().sfield(F_RATE_SHEET); if (rs.items() > 0) // Resetta lo spreadsheet se vi sono delle righe rs.reset(); app()._dirty = TRUE; } break; case K_TAB: // Posizionamento sulla riga r // Visualizza le rate relative sull'apposito sheet { TMask& m = ds.mask(); if (!m.is_running()) break; TToken_string& tt = ds.row(r); int anno = tt.get_int(0); TString codnum = tt.get(1); long ndoc = tt.get_long(2); m.set(F_MANNO,anno); m.set(F_MCODNUM,codnum); m.set(F_MNDOC,ndoc); __current_key.format("%4d%4s%7ld",anno,(const char*)codnum,ndoc); TSheet_field& rs = ds.mask().sfield(F_RATE_SHEET); if (rs.items() > 0) // Resetta lo spreadsheet se vi sono delle righe precedenti rs.reset(); TRate_doc& rd = pa->rate(__current_key,TRUE); const int items = rd.items(); for (int i = 0; i < items; i++) { TRata& rt = rd[i]; TToken_string& ttt = rs.row(i); ttt.add(rt.rata()); ttt.add(rt.datascad()); ttt.add(rt.tipopag()); ttt.add(rt.imprata().string()); ttt.add(rt.impprovv().string()); ttt.add(rt.pagmat().string()); ttt.add(rt.provvmat().string()); ttt.add(rt.pagato().string()); ttt.add(rt.provvpag().string()); ttt.add(rt.saldata() ? "X" : " "); ttt.add(rt.tipopagpr()); } rs.force_update(); } break; case K_ENTER: // Abbandono della riga r (modificata). Analogamente va fatto sullo sheet delle rate // Memorizza rate e documento // Confronta la chiave della riga attuale con quella ricavata quando ci si e' // posizionati sopra. // Se __current_key non e' vuota viene rimosso il vecchio TRate_doc // e aggiunto quello con la chiave nuova { TToken_string& tt = ds.row(r); int anno = tt.get_int(0); TString codnum = tt.get(1); long ndoc = tt.get_long(2); TString k; k.format("%4d%4s%7ld",anno,(const char*)codnum,ndoc); bool flag = FALSE; if (__current_key != k) // Se le chiavi sono diverse { TAssoc_array& vitt = app()._vittime; if (__current_key.not_empty()) { pa->remove_rate(__current_key); // Cancella il vecchio vitt.add(__current_key); } __current_key = k; if (vitt.is_key(k)) vitt.remove(k); flag = TRUE; } TRate_doc& rd = pa->rate(k,flag); // Aggiunge il nuovo o prende lo stesso elemento // Schiaffa dentro rate e dati documento rd.set(tt); fill_rate_doc(rd, ds.mask().sfield(F_RATE_SHEET)); app()._dirty = TRUE; } break; case K_DEL: // Rimozione della riga r // Rimuove il documento e le rate pa->remove_rate(__current_key); app()._vittime.add(__current_key); __current_key.cut(0); if (pa->items() == 0) { TSheet_field& rs = (TSheet_field&) ds.mask().field(F_RATE_SHEET); if (rs.items() > 0) // Resetta lo spreadsheet se vi sono delle righe rs.reset(); } app()._dirty = TRUE; break; default: break; } return TRUE; } bool TGestione_provv_app::create() { open_files(LF_CONDV, LF_RCONDV, LF_ANAMAG, LF_SCONTI, LF_UMART, LF_TABCOM, LF_CLIFO,LF_INDSP, LF_MOVMAG, LF_RMOVMAG,0); _msk = new TMask("pr0700b") ; _provv = new TLocalisamfile(LF_PROVV); _doc = new TLocalisamfile(LF_DOC); _rdoc = new TLocalisamfile(LF_RIGHEDOC); _cfven = new TLocalisamfile(LF_CFVEN); _occas = new TLocalisamfile(LF_OCCAS); _tab = new TLocalisamfile(LF_TAB); _prag = new TProvvigioni_agente; _documento = new TDocumento; TSheet_field & sf = (TSheet_field&)_msk->field(F_DOC_SHEET); sf.set_notify(doc_sheet_notify); sf.sheet_mask().set_handler(F_NDOC,ndoc_handler); TSheet_field & rs = (TSheet_field&)_msk->field(F_RATE_SHEET); rs.set_notify(rate_sheet_notify); TMask& sm = rs.sheet_mask(); sm.set_handler(F_RATA,nrata_handler); sm.set_handler(F_DATASCAD,datascad_handler); sm.set_handler(F_IMPRATA,imprata_handler); sm.set_handler(F_IMPPROVV,improvv_handler); sm.set_handler(DLG_ENABLE,enable_handler); return TSkeleton_application::create(); } bool TGestione_provv_app::destroy() { delete _msk; delete _documento; delete _prag; delete _provv; delete _doc; delete _rdoc; delete _tab; delete _cfven; delete _occas; return TRUE; } void TGestione_provv_app::fill_sheet_doc() { TString_array kl; const int items = _prag->documenti(kl); kl.sort(); // Cosi' i documenti sono in ordine TSheet_field & sf = (TSheet_field&)_msk->field(F_DOC_SHEET); TSheet_field & rs = (TSheet_field&)_msk->field(F_RATE_SHEET); __current_key = ""; rs.reset(); sf.reset(); for (int i = 0; i < items; i++) { TRate_doc& rd = _prag->rate(kl.row(i)); TToken_string& tt = sf.row(i); tt.add(rd.anno()); tt.add(rd.codnum()); tt.add(rd.ndoc()); tt.add(rd.datadoc()); tt.add(rd.impdoc().string()); tt.add(rd.impprdoc().string()); tt.add(rd.impnet().string()); tt.add(rd.codcf()); tt.add(rd.codval()); tt.add(rd.cambio().string()); tt.add(rd.datacam()); } } bool TGestione_provv_app::check_totals() // Controlla che la somma delle provvigioni per ogni rata non sia superiore alla provvigione // totale del documento. Ritorna TRUE se tutti i documenti hanno le provvigioni ok { TString_array kl; const int items = _prag->documenti(kl); bool rt = TRUE; for (int i = 0; rt && i < items ; i++) if (!_prag->rate(kl.row(i)).ok_provvigione()) { rt = FALSE; error_box("La somma delle provvigioni supera l'importo della provvigione totale per il documento %s", (const char*)kl.row(i)); } return rt; } void TGestione_provv_app::kill_vittime() { const TString16 agente = _msk->get(F_CODAGE); TProvvigioni_agente prov; FOR_EACH_ASSOC_OBJECT(_vittime, ass, key, doc) { const TFixed_string codice(key); const int anno = atoi(codice.left(4)); const long ndoc = atol(codice.right(7)); TString16 codnum = codice.mid(4, 4); codnum.trim(); if (prov.read(agente, anno, codnum, ndoc) == NOERR) prov.remove(); } } void TGestione_provv_app::load_provvigioni(TMask* m) { const TString16 agente = m->get(F_CODAGE); const int anno = m->get_int(F_FILTERANNO); _msk->set(F_CODAGE,agente); _msk->set(F_RAGSOC,m->get(F_RAGSOC)); _msk->set(F_MANNO,""); _msk->set(F_MCODNUM,""); _msk->set(F_MNDOC,""); if (_prag->read(agente, anno) == _islocked) { message_box("Dati agente %s in uso da un altro utente.", (const char*) agente); return; } KEY k; bool repeat; const char* msg = _prag->items() == 0 ? "Registrare i dati inseriti" : "Registrare le modifiche" ; fill_sheet_doc(); // Inizializza lo sheet dei documenti _dirty = FALSE; int err = NOERR; do { k = _msk->run(); bool to_write = k == K_ENTER; repeat = FALSE; if (k == K_ESC && _dirty) { k = yesnocancel_box(msg); if (k == K_ESC) repeat = TRUE; else if (k == K_YES) to_write = TRUE; } if (to_write) { if (check_totals()) // Controlla i totali delle provvigioni per tutti i documenti { kill_vittime(); // Cancella eventuali documenti eliminati dallo sheet err = _prag->write(); } else repeat = TRUE; } } while (repeat); if (err != NOERR) message_box("Errore %d tentando di scrivere i dati provvigionali dell'agente.",err, (const char*) agente); _prag->unlock(); } void TGestione_provv_app::main_loop() { bool ok = TRUE; TMask* m = new TMask("pr0700a"); while (ok) { xvt_statbar_set("Ricerca", TRUE); m->reset(); ok = m->run() == K_ENTER; if (ok) load_provvigioni(m); } delete m; } int pr0700(int argc, char** argv) { TGestione_provv_app a; a.run(argc,argv,"Gestione provvigioni"); return 0; }