#include "cgsalda3.h" #include #include #include #include #include /////////////////////////////////////////////////////////// // TPartite_cache /////////////////////////////////////////////////////////// // Callback per scansione cursore static bool fill_games(const TRelation& rel, void* pJolly) { TPartite_cache& a = *(TPartite_cache*)pJolly; a.add_game(rel.curr()); return true; } // Carica la lista delle partite. void TPartite_cache::set_bill(TPartite_array& games, const TBill& conto, long numreg, const TString& codval, TSolder_tree_flags flags) { _games = &games; _bill = conto; _numreg = numreg; _codval = codval; destroy(); TRelation partite(LF_PARTITE); TRectype& rec = partite.curr(); const char tipocf = conto.tipo(); if (tipocf > ' ') { rec.put(PART_TIPOCF, tipocf); rec.put(PART_SOTTOCONTO, conto.codclifo()); } else { rec.put(PART_GRUPPO, conto.gruppo()); rec.put(PART_CONTO, conto.conto()); rec.put(PART_SOTTOCONTO, conto.sottoconto()); } _flags = TSolder_tree_flags(flags & sct_all_games); // Ignora eventuale flag di valuta TString filter; if (_flags != sct_all_games && numreg > 0 && numreg < 999999) filter << '(' << PART_NREG << "==\"" << numreg << "\")"; if (_flags == sct_open_games || _flags == sct_closed_games) { if (filter.full()) filter << "||"; filter << "(" << PART_CHIUSA << ((_flags & sct_open_games)!=0 ? "!=" : "==") << "\"X\")"; } TCursor cur(&partite, filter, 1, &rec, &rec); cur.scan(fill_games, this); for (TPartita* p = games.first(); p != NULL; p = games.next()) if (!p->is_on_file()) add_game(*p); } TPartita* TPartite_cache::find(int idx) const { TPartita* g = NULL; if (has_game(idx)) { const TToken_string& str = row(idx); int anno; str.get(0, anno); TString8 numero; str.get(1, numero); g = &_games->partita(_bill, anno, numero); } return g; } const TString& TPartite_cache::build_key(int anno, const char* partita) const { TString8 numpart = partita; numpart.trim(); TString& tmp = get_tmp_string(16); tmp.format("%04d|%s", anno, (const char*)numpart); return tmp; } int TPartite_cache::game_id(int anno, const char* numpart) const { const TString& key = build_key(anno, numpart); return TString_array::find(key); } bool TPartite_cache::add_game(int anno, const char* partita) { const TString16 key = build_key(anno, partita); bool can_add = TString_array::find(key) < 0; if (can_add) { if (_flags == sct_open_games || _flags == sct_closed_games) { const TPartita game(_bill, anno, partita); const bool chiusa = game.chiusa(true); can_add = (_flags == sct_closed_games) == chiusa; if (!can_add) // Faccio un'eccezione per le mie partite { for (int i = game.last(); i > 0 && !can_add; i = game.pred(i)) can_add = game.riga(i).get_long(PART_NREG) == _numreg; } } if (can_add) add(key); } return can_add; } bool TPartite_cache::add_game(const TRectype& partita) { if (!same_values(partita.get(PART_CODVAL), _codval)) return false; return add_game(partita.get_int(PART_ANNO), partita.get(PART_NUMPART)); } bool TPartite_cache::add_game(const TPartita& partita) { if (!same_values(partita.codice_valuta(), _codval)) return false; return add_game(partita.anno(), partita.numero()); } /////////////////////////////////////////////////////////// // TSolder_tree /////////////////////////////////////////////////////////// TPartita* TSolder_tree::partita() const { int index = -1; _curr.get(0, index); return _cache.find(index); } TRiga_partite* TSolder_tree::riga_partita() const { TRiga_partite* fatt = NULL; if (_curr.items() >= 2) { TPartita* g = partita(); if (g != NULL) { int nriga = 1; _curr.get(1, nriga); if (nriga > 0 && nriga < g->UNASSIGNED) return &g->riga(nriga); } } return fatt; } TRiga_scadenze* TSolder_tree::scadenza() const { TRiga_scadenze* scad = NULL; if (_curr.items() >= 3) { TPartita* g = partita(); if (g != NULL) { int nriga = 1; _curr.get(1, nriga); int nrata = 1; _curr.get(2, nrata); if (nrata > 0 && nrata < g->UNASSIGNED && g->esiste(nriga, nrata)) scad = &g->rata(nriga, nrata); } } return scad; } TRectype* TSolder_tree::pagamento() const { TRectype* rpag = NULL; if (_curr.items() >= 4) { TPartita* g = partita(); if (g != NULL) { int nriga = 1; _curr.get(1, nriga); int nrata = 1; _curr.get(2, nrata); int nrigp = 2; _curr.get(3, nrigp); if (g->esiste(nriga, nrata, nrigp)) rpag = &g->pagamento(nriga, nrata, nrigp); } } return rpag; } bool TSolder_tree::goto_root() { const bool can_be_done = has_root(); if (can_be_done) _curr = "0"; // Prima partita della lista else _curr.cut(0); return can_be_done; } bool TSolder_tree::goto_firstson() { const int level = _curr.items(); if (level <= 0 || level >= 4) return false; TPartita* g = partita(); if (g == NULL) // Dovrebbe funzionare sempre per level > 0 return false; if (level == 1) { int riga = g->prima_fattura(); bool ok = riga > 0 && riga < TPartita::UNASSIGNED; if (!ok && g->unassigned().rows() > 0) { riga = TPartita::UNASSIGNED; ok = true; } if (ok) _curr.add(riga); return ok; } const int riga = _curr.get_int(1); if (level == 2) { if (riga == TPartita::UNASSIGNED) { _curr.add(TPartita::UNASSIGNED); return true; } const bool ok = g->esiste(riga, 1); if (ok) _curr.add(1); return ok; } const int rata = _curr.get_int(2); if (level == 3) { int nrigp = 0; if (rata != TPartita::UNASSIGNED) { const TRiga_scadenze& scad = g->rata(riga, rata); nrigp = scad.first(); } else { nrigp = g->unassigned().first_row(); } const bool ok = g->esiste(riga, rata, nrigp); if (ok) _curr.add(nrigp); return ok; } return false; } bool TSolder_tree::goto_rbrother() { const int level = _curr.items(); if (level == 0) // Il prossimo clifo non esiste mai per progetto return false; const int index = _curr.get_int(0); if (level == 1) // Esite la prossima partita? { const bool ok = _cache.find(index+1) != NULL; if (ok) _curr.add(index+1, 0); return ok; } TPartita& g = _cache.game(index); const int riga = _curr.get_int(1); if (level == 2) // Esite la prossima riga? { bool ok = false; if (riga > 0 && riga < g.UNASSIGNED) { int nriga = riga+1; // good guess :-) for (nriga = g.succ(riga); g.esiste(nriga); nriga = g.succ(nriga)) { const TRiga_partite& rp = g.riga(nriga); if (rp.is_fattura()) break; } ok = g.esiste(nriga); if (!ok && g.unassigned().rows() > 0) { nriga = g.UNASSIGNED; ok = true; } if (ok) _curr.add(nriga, 1); } return ok; } const int rata = _curr.get_int(2); if (level == 3) // Esiste la prossima rata? { bool ok = false; if (rata > 0 && rata < g.UNASSIGNED) { const int nrata = rata+1; ok = g.esiste(riga, nrata); if (ok) _curr.add(nrata, 2); } return ok; } const int pag = _curr.get_int(3); if (level == 4) // Esiste il prossimo pagamento { int npag = 0; if (rata > 0 && rata < g.UNASSIGNED) { const TRiga_scadenze& scad = g.rata(riga, rata); npag = scad.succ(pag); } else npag = g.unassigned().succ_row(pag); const bool ok = g.esiste(riga, rata, npag); if (ok) _curr.add(npag, 3); return ok; } return false; } bool TSolder_tree::could_have_son() const { const int level = _curr.items(); if (level <= 0 || level >= 4) return false; // Sono su di un pagamento const TPartita* g = partita(); if (g == NULL) return false; int riga = 0; _curr.get(1, riga); if (level == 2) // Sono su di una riga fattura o non assegnata return riga == g->UNASSIGNED || g->esiste(riga, 1); if (level == 3) // Sono su di una rata o non assegnata { int rata = 0; _curr.get(2, rata); return rata == g->UNASSIGNED || g->esiste(riga, rata); } return true; } bool TSolder_tree::has_son() const { bool ok = could_have_son(); if (ok) { TSolder_tree& me = (TSolder_tree&)*this; const TString16 old = me._curr; ok = me.goto_firstson(); me._curr = old; } return ok; } bool TSolder_tree::has_root() const { return _cache.items() > 0; } bool TSolder_tree::has_father() const { return _curr.find(_curr.separator()) > 0; } bool TSolder_tree::has_rbrother() const { TSolder_tree& me = (TSolder_tree&)*this; const TString16 old = me._curr; const bool ok = me.goto_rbrother(); me._curr = old; return ok; } bool TSolder_tree::has_lbrother() const { TSolder_tree& me = (TSolder_tree&)*this; const TString16 old = me._curr; const bool ok = me.goto_lbrother(); me._curr = old; return ok; } bool TSolder_tree::goto_father() { const bool ok = has_father(); if (ok) { const int pipe = _curr.rfind(_curr.separator()); if (pipe > 0) _curr.cut(pipe); else _curr.cut(0); } return ok; } bool TSolder_tree::goto_lbrother() { const int level = _curr.items(); if (level <= 0) // Il precedente clifo non esiste mai per progetto return false; const int index = _curr.get_int(0); if (level == 1) // Esite la precedente partita? { const bool ok = index > 0; if (ok) _curr.add(index-1, 0); return ok; } TPartita& g = _cache.game(index); const int riga = _curr.get_int(1); if (level == 2) // Esite la precedente riga? { int nriga = 0; if (riga == g.UNASSIGNED) nriga = g.last(); else nriga = g.pred(riga); while (nriga > 0 && !g.riga(nriga).is_fattura()) nriga = g.pred(nriga); const bool ok = nriga > 0; if (ok) _curr.add(nriga, 1); return ok; } const int rata = _curr.get_int(2); if (level == 3) // Esiste la precedente rata? { bool ok = false; if (riga != g.UNASSIGNED && rata != g.UNASSIGNED) { const int nrata = rata-1; ok = nrata > 0; if (ok) _curr.add(nrata, 2); } return ok; } const int pag = _curr.get_int(3); if (level == 4) // Esiste il precedente pagamento { int npag = 0; if (riga == g.UNASSIGNED || rata == g.UNASSIGNED) { npag = g.unassigned().pred_row(pag); } else { const TRiga_scadenze& scad = g.rata(riga, rata); npag = scad.pred(pag); } const bool ok = npag > 0; if (ok) _curr.add(npag, 3); return ok; } return false; } void TSolder_tree::set_var_imp(TVariant& var, const TImporto& imp, bool in_value) const { if (!imp.is_zero()) { const TCurrency cur(imp.valore(), in_value ? _codval : EMPTY_STRING); var = cur.string(true); } else var.set_null(); } void TSolder_tree::set_var_real(TVariant& var, const real& imp, bool in_value) const { if (!imp.is_zero()) { TCurrency cur(imp, in_value ? (const char*)_codval : ""); if (in_value != show_val()) { if (in_value) cur.change_to_firm_val(); else cur.change_value(_codval, _cambio); } var = cur.string(true); } } TFieldtypes TSolder_tree::get_var(const TString& name, TVariant& var) const { const int level = _curr.items(); if (level == 0) // Should never happen :-) { if (name == PART_DESCR) var = _cache.bill().descrizione(); return var.type(); } TPartita& g = *partita(); if (name == PART_CODVAL) { var = _codval; return _alfafld; } if (level == 1) { if (name == PART_DESCR) { TString8 numpart = g.numero(); numpart.trim(); TString16 desc; desc << g.anno() << '/' << numpart; var = desc; } else if (name == PART_NUMDOC || name == PART_DATADOC) { int r = g.prima_fattura(); if (r <= 0) r = g.first(); var = g.riga(r).get(name); } else if (name == "DARE" || name == "AVERE") { if (!g.chiusa()) // Ignora saldi sicuramente nulli { const bool sv = show_val(); const TImporto saldo = g.calcola_saldo(sv); if (saldo.sezione() == name[0]) set_var_imp(var, saldo, sv); } } return var.type(); } int nriga = 1; _curr.get(1, nriga); if (level == 2) { if (nriga > 0 && nriga < g.UNASSIGNED && g.esiste(nriga)) { const TRiga_partite& riga = g.riga(nriga); if (name == PART_DESCR) { TString desc = riga.get(PART_DESCR); if (desc.blank()) { const long nreg = riga.get_long(PART_NREG); if (nreg > 0) desc = cache().get(LF_MOV, nreg, MOV_DESCR); if (desc.blank()) desc = cache().get(LF_CAUSALI, riga.get(PART_CODCAUS), CAU_DESCR); } var = desc; } else if (name == "DARE" || name == "AVERE") { const bool sv = show_val(); const TImporto imp = riga.importo(sv); if (imp.sezione() == name[0]) set_var_imp(var, imp, sv); } else { // NUMDOC, DATADOC, NREG if (riga.TRectype::exist(name)) var = riga.get(name); } } else { if (name == PART_DESCR) var = TR("Pagamenti non assegnati"); else { if (g.unassigned().rows() == 1) { const int nriga = g.unassigned().first_row(); const TRiga_partite& riga = g.riga(nriga); const TFieldtypes ft = riga.type(name); switch (ft) { case _nullfld: break; case _intfld: case _intzerofld: case _longfld: case _longzerofld: { const TString& n = riga.get(name); if (!real::is_null(n)) var = n; } break; case _realfld: set_var_real(var, riga.get_real(name), false); break; default : var = riga.get(name); break; } } } } return var.type(); } int nrata = 1; _curr.get(2, nrata); if (level == 3) { if (nrata > 0 && nrata < g.UNASSIGNED && g.esiste(nriga, nrata)) { const TRiga_partite& fatt = g.riga(nriga); const TRiga_scadenze& rata = fatt.rata(nrata); if (name == PART_DESCR) { TString16 desc; desc << nrata << '/' << fatt.rate(); var = desc; } else if (name == PART_NUMDOC) var = fatt.get(name); else if (name == PART_DATADOC) var = rata.get(SCAD_DATASCAD); else if (name == "DARE" || name == "AVERE") { const bool sv = show_val(); const TImporto imp = rata.importo(sv); if (imp.sezione() == name[0]) set_var_imp(var, imp, sv); } } else { if (name == PART_DESCR) var = TR("Rata non assegnata"); } return var.type(); } int npag = 2; _curr.get(3, npag); if (g.esiste(nriga, nrata, npag)) { const TRectype& pag = g.pagamento(nriga, nrata, npag); const TRiga_partite& rpag = g.riga(npag); const tipo_movimento tipo = rpag.tipo(); if (name == PART_DESCR) { switch(tipo) { case tm_nota_credito : var = TR("Nota di credito"); break; case tm_insoluto : var = TR("Insoluto"); break; case tm_pagamento_insoluto: var = TR("Pagamento insoluto"); break; default : var = TR("Pagamento"); break; } } else if (name == "DARE" || name == "AVERE") { if (rpag.sezione() == name[0]) { const bool sv = show_val(); const real imp = pag.get_real(sv ? PAGSCA_IMPORTOVAL : PAGSCA_IMPORTO); set_var_imp(var, TImporto(rpag.sezione(), imp), sv); } } else if (name == PAGSCA_ABBUONI) { const real a = pag.get_real(name); set_var_real(var, a, show_val()); } else if (name == PAGSCA_DIFFCAM) { if (_codval.full() && !show_val()) { const real d = pag.get_real(name); set_var_real(var, d, false); } } else if (name == PAGSCA_RITENUTE) { if (_codval.empty()) set_var_real(var, pag.get_real(name), false); } else if (name == PAGSCA_RITSOC) { if (_codval.empty()) set_var_real(var, rpag.get_real(name), false); } else if (name == PART_DATADOC) { TDate d = rpag.get(PART_DATAPAG); if (!d.ok()) d = rpag.get(PART_DATADOC); if (!d.ok()) d = rpag.get(PART_DATAREG); var = d; } else if (rpag.TRectype::exist(name)) var = rpag.get(name); } return var.type(); } bool TSolder_tree::get_description(TString& desc) const { TVariant var; get_var(PART_DESCR, var); desc = var.as_string(); return !var.is_null(); } // Flags: 3 = tutte le partite; 8 = mostra in valuta void TSolder_tree::set_root(TPartite_array& games, const TBill& conto, long numreg, int numrig, const TString& codval, const real& cambio, TSolder_tree_flags flags) { _num_rig = numrig; _flags = flags; if (is_true_value(codval)) { _codval = codval; _cambio = cambio; if (_cambio <= ZERO) _cambio = UNO; } else { _codval.cut(0); _cambio = ZERO; // Ignora visualizzazione importi in valuta in assenza di vera valuta _flags = TSolder_tree_flags(_flags & ~sct_show_val); } _cache.set_bill(games, conto, numreg, _codval, _flags); goto_root(); } bool TSolder_tree::marked() const { bool yes = false; const int level = _curr.items(); if (level >= 1) { const TPartita& g = *partita(); if (level == 1) yes = !g.chiusa(); else { int nriga = 1; _curr.get(1, nriga); if (nriga > 0 && nriga < g.UNASSIGNED) { const TRiga_partite& riga = g.riga(nriga); yes = riga.get_long(PART_NREG) == _cache.num_reg(); if (!yes && level == 3) { int nrata = 1; _curr.get(2, nrata); const TRiga_scadenze& scad = g.rata(nriga, nrata); yes = !scad.chiusa(); } } } } return yes; } TImage* TSolder_tree::image(bool selected) const { const int level = _curr.items(); short id = 0; switch (level) { case 1: { TPartita* p = partita(); id = p && p->chiusa() ? BMP_DIRDNSEL : BMP_DIRDN; } break; case 2: { const TRiga_partite* s = riga_partita(); id = s && s->get_bool(PART_CHIUSA) ? BMP_FILECHK : BMP_FILE; } break; case 3: { const TRiga_scadenze* s = scadenza(); id = s && s->chiusa() ? BMP_DIRDNSEL : BMP_DIRDN; } break; case 4: { int nrigp = 0; _curr.get(3, nrigp); if (nrigp > 0) { const TRiga_partite& rp = partita()->riga(nrigp); switch (rp.tipo()) { case tm_pagamento_insoluto: // Alias tm_pagamento case tm_pagamento: id = BMP_PAGAMENTO; break; default: id = BMP_INSOLUTO; break; } } else id = BMP_FILE; } break; default: break; } return id > 0 ? get_res_image(id) : TTree::image(selected); } bool TSolder_tree::goto_game(int anno, const char* numpart, int nriga, int nrata, int nrigp) { // Controllo cge la partita sia tra quelle possibili in cache const int idx = _cache.game_id(anno, numpart); if (idx < 0) return false; // Costruisco la chiave del nodo desiderato: idx|nriga|nrata|nrigp TToken_string key; key.add(idx); if (nriga > 0) { key.add(nriga); if (nrata > 0) { key.add(nrata); if (nrigp > 0) key.add(nrigp); } } return goto_node(key); } bool TSolder_tree::goto_single_game(int anno, const char* numpart, int nriga, int nrata, int nrigp) { // Controllo se per caso la partita non sia gia' in cache if (_cache.game_id(anno, numpart) < 0) { TPartite_array& giochi = _cache.partite(); if (!giochi.exist(_cache.bill(), anno, numpart)) return false; } // Svuoto la cache e ci metto la sola partita desiderata _cache.destroy(); _cache.add_game(anno, numpart); expand_all(); // Espando tutto l'alberello // Posiziono l'albero normalmente return goto_game(anno, numpart, nriga, nrata, nrigp); }