#include "sc0300a.h" #include "../cg/cgsalda3.h" #include #include #include #include #include #include #include #include #include /////////////////////////////////////////////////////////// // TPareggio_tree /////////////////////////////////////////////////////////// class TPareggio_tree : public TObject_tree { TPartite_array _games; protected: virtual TFieldtypes get_var(const TString& name, TVariant& var) const; virtual TImage* image(bool selected) const; public: bool init(const TBill& bill, const TString& valuta, bool nc, int stato); // Stato: 1=aperte; 2=chiuse; 0 o 3 = tutte TPartita& partita(const TRectype& rec) const; bool is_lonely_pag(const TRectype& rec) const; const TRectype* node2rec(const TString& id); }; TPartita& TPareggio_tree::partita(const TRectype& rec) const { return ((TPartite_array&)_games).partita(rec); } // Controlla se rec è una riga di tipo nota credito non associata a nessuna scadenza in una partita a sè stante bool TPareggio_tree::is_lonely_pag(const TRectype& rec) const { const tipo_movimento tm = (tipo_movimento)rec.get_int(PART_TIPOMOV); if (tm == tm_fattura) return false; const TPartita& part = partita(rec); for (int r = part.last(); r > 0; r = part.pred(r)) { const tipo_movimento tm = part.riga(r).tipo(); if (tm <= tm_fattura || tm >= tm_insoluto) return false; } return true; } const TRectype* TPareggio_tree::node2rec(const TString& id) { const TRectype* rec = NULL; if (id.blank() || goto_node(id)) { const TObject* obj = curr_node(); if (obj != NULL && obj->is_kind_of(CLASS_RECTYPE)) rec = (const TRectype*)obj; } return rec; } TFieldtypes TPareggio_tree::get_var(const TString& name, TVariant& var) const { TFieldtypes ft = _nullfld; const TObject* obj = curr_node(); if (obj != NULL) { if (obj->is_kind_of(CLASS_RECTYPE)) { const TRectype& rec = *(const TRectype*)obj; ft = rec.type(name); if (ft != _nullfld) { if (ft == _realfld) { if (name == PART_IMPORTO) { char sez = 'D'; if (rec.num() == LF_SCADENZE) { const int nriga = rec.get_int(SCAD_NRIGA); const TPartita& game = partita(rec); sez = game.riga(nriga).get_char(PART_SEZ); } else if (rec.exist(PART_SEZ)) sez = rec.get_char(PART_SEZ); TImporto imp(sez, rec.get_real(name)); if (!imp.is_zero()) { imp.normalize(); TString80 str; str << imp.valore().stringa(0, 2) << ' ' << imp.sezione(); var = str; } } else var = rec.get_real(name).stringa(0, 2); ft = _alfafld; } else var = rec.get(name); } else { if (name.starts_with("PART.", true)) { const TString& fld = name.after("."); if (rec.num() == LF_SCADENZE) { const int nriga = rec.get_int(SCAD_NRIGA); const TPartita& game = partita(rec); var = game.riga(nriga).get(fld); ft = _alfafld; } else { var = rec.get(fld); ft = _alfafld; if (var.is_empty() && name.ends_with(PART_DESCR)) { switch (rec.get_int(PART_TIPOMOV)) { case tm_fattura : var = TR("Fattura"); break; case tm_nota_credito : var = TR("Nota di credito"); break; case tm_pagamento : var = TR("Pagamento"); break; case tm_insoluto : var = TR("Insoluto"); break; case tm_pagamento_insoluto: var = TR("Pagamento di insoluto"); break; default: break; }; } } } else if (name == "RESIDUO") { TImporto saldo; switch (rec.num()) { case LF_SCADENZE: if (!rec.get_bool(SCAD_PAGATA)) { const TPartita& game = partita(rec); const TRiga_scadenze& s = game.rata(rec.get_int(SCAD_NRIGA), rec.get_int(SCAD_NRATA)); saldo = s.residuo(true); } break; case LF_PARTITE: if (!rec.get_bool(PART_CHIUSA)) { const TPartita& game = partita(rec); saldo = game.calcola_saldo(true); } break; default: break; } if (!saldo.is_zero()) { TString80 str; str << saldo.valore().stringa(0, 2) << ' ' << saldo.sezione(); var = str; } ft = _alfafld; } } } else { if (name == PART_NUMPART) { const real& year = *(real*)obj; var = year.integer(); ft = _intfld; } } } return ft; } TImage* TPareggio_tree::image(bool selected) const { const TObject* obj = curr_node(); short id = 0; if (obj != NULL) { if (obj->is_kind_of(CLASS_RECTYPE)) { const TRectype& rec = *(const TRectype*)obj; switch (rec.num()) { case LF_PARTITE: switch (rec.get_int(PART_TIPOMOV)) { case tm_fattura: id = rec.get_bool(PART_CHIUSA) ? BMP_DIRDNSEL : BMP_DIRDN; break; case tm_pagamento_insoluto: // Alias tm_pagamento case tm_pagamento: id = BMP_PAGAMENTO; break; default: id = BMP_INSOLUTO; break; } break; case LF_SCADENZE: id = rec.get_bool(SCAD_PAGATA) ? BMP_DIRDNSEL : BMP_DIRDN; break; default: break; } } } return id > 0 ? get_res_image(id) : TTree::image(selected); } bool TPareggio_tree::init(const TBill& bill, const TString& valuta, bool nc, int stato) { _games.destroy(); goto_root(); kill_node(); TString filter; if (bill.tipo() > ' ') filter << PART_TIPOCF << '=' << bill.tipo(); else { filter << PART_GRUPPO << '=' << bill.gruppo() << ' '; filter << PART_CONTO << '=' << bill.conto(); } filter << ' ' << PART_SOTTOCONTO << '=' << bill.sottoconto(); TString query; query << "USE PART SELECT (NRIGA<9999)&&(" << (nc ? "BETWEEN(TIPOMOV,1,3)" : "TIPOMOV=1") << ')' << "\nFROM " << filter << "\nTO " << filter; TISAM_recordset games(query); const TRectype& rec = games.cursor()->curr(); int last_year = 0; TString80 id_year, id_rec; TProgind pi(games.items(), nc ? TR("Caricamento note di credito") : TR("Caricamento fatture")); for (bool ok = games.move_first(); ok; ok = games.move_next()) { if (!pi.addstatus(1)) break; const TString& codval = rec.get(PART_CODVAL); if (!same_values(codval, valuta)) continue; bool add_riga = true; if (stato == 1 || stato == 2) { bool chiusa = rec.get_bool(PART_CHIUSA); if (!chiusa && partita(rec).chiusa(true)) chiusa = true; // Flag CHIUSA non affidabilissimo if (chiusa) add_riga = stato == 2; else add_riga = stato == 1; if (!add_riga) continue; } if (nc) { const tipo_movimento tm = (tipo_movimento)rec.get_int(PART_TIPOMOV); // Se filtro le note di credito cerco di riconoscere le fatture negative if (tm == tm_fattura) { const char sezione_positiva = bill.tipo() == 'C' ? 'D' : 'A'; TImporto importo(rec.get_char(PART_SEZ), rec.get_real(PART_IMPORTO)); importo.normalize(); add_riga = sezione_positiva != importo.sezione(); // Ignora fattura positiva } else { const int nriga = rec.get_int(PART_NRIGA); const TPartita& game = partita(rec); add_riga = ((TPartita&)game).unassigned().exist(nriga) && is_lonely_pag(rec); } } else { const char sezione_positiva = bill.tipo() == 'C' ? 'D' : 'A'; TImporto importo(rec.get_char(PART_SEZ), rec.get_real(PART_IMPORTO)); importo.normalize(); add_riga = sezione_positiva == importo.sezione(); // Ignora fattura negativa } if (!add_riga) continue; const int year = rec.get_int(PART_ANNO); if (year != last_year) { goto_root(); while(goto_rbrother()); add_rbrother(real(year)); last_year = year; curr_id(id_year); id_rec.cut(0); } if (nc) { if (id_rec.full()) { goto_node(id_rec); add_rbrother(rec); } else add_son(rec); curr_id(id_rec); } else { TPartita& game = partita(rec); const TRiga_partite& riga = game.riga(rec.get_int(PART_NRIGA)); for (int rata = 1; rata <= riga.rate(); rata++) { const TRiga_scadenze& s = riga.rata(rata); bool add_rata = true; if (stato == 1 || stato == 2) { const bool chiusa = s.get_bool(SCAD_PAGATA); if (chiusa) add_rata = stato == 2; else add_rata = stato == 1; } if (add_rata) { if (id_rec.full()) add_rbrother(s); else add_son(s); curr_id(id_rec); } } } } if (goto_node(id_year)) expand(); return goto_root(); } /////////////////////////////////////////////////////////// // TScad_mask /////////////////////////////////////////////////////////// class TScad_mask : public TAutomask { protected: virtual bool on_field_event(TOperable_field& o, TField_event e, long jolly); public: TScad_mask() : TAutomask("sc0300b") {} }; bool TScad_mask::on_field_event(TOperable_field& o, TField_event e, long jolly) { switch (o.dlg()) { case F_TUTTE: if (e == se_query_add || e == se_query_del) return false; if (e = fe_close) { TSheet_field& s = (TSheet_field&)o; real tot, imp = get_real(F_IMPORTO); FOR_EACH_SHEET_ROW(s, r, row) tot += real(row->get(0)); if (tot > imp) return error_box(FR("Il totale degli importi (%s) supera la cifra disponibile (%s)"), tot.stringa(), imp.stringa()); } break; default: break; } return true; } /////////////////////////////////////////////////////////// // TPareggio_mask /////////////////////////////////////////////////////////// class TPareggio_mask : public TAutomask { TPareggio_tree _nc, _ft; long _numreg; protected: virtual bool on_field_event(TOperable_field& o, TField_event e, long jolly); const TString& reg2caus(const TString& reg) const; bool ft2nc(const TRectype& rec); bool abbuona_rata(const real& imp, const TRectype& nota, TRiga_scadenze& scad); bool elabora(const TRectype& nota, TPointer_array& scadenze); void refill(); public: TPareggio_mask(); }; // Cerca una causale di nota di credito compatibile col registro reg const TString& TPareggio_mask::reg2caus(const TString& reg) const { if (reg.full()) { const char tipocf = get(F_TIPO)[0]; const TString& codcaus = get(tipocf == 'F' ? F_CODCAUS_F : F_CODCAUS_C); const TString& cod = cache().get(LF_CAUSALI, codcaus, CAU_REG); if (cod == reg) return codcaus; // Siamo fortunati: va bene la causale standard TISAM_recordset recset("USE CAUS SELECT (REG=#CODREG)&&(TIPOMOV=2)"); recset.set_var("#CODREG", reg); if (recset.move_first()) return recset.get(CAU_CODCAUS).as_string(); } return EMPTY_STRING; } // Trasforma una fattura negativa in nota di credito bool TPareggio_mask::ft2nc(const TRectype& rec) { CHECK(rec.num() == LF_PARTITE, "Solo partite, grazie!"); const long numreg = rec.get_long(PART_NREG); const TString4 codreg = rec.get(PART_REG); const TString4 codcau = reg2caus(codreg); if (codcau.blank()) return error_box(FR("E' necessario creare una causale di nota di credito sul registro %s"), (const char*)codreg); TString msg; msg << TR("Si desidera trasformare la fattura in nota di credito con causale ") << codcau << '\n' << cache().get(LF_CAUSALI, codcau, CAU_DESCR); if (!yesno_box(msg)) return false; int err = NOERR; if (numreg > 0) { TLocalisamfile mov(LF_MOV); mov.curr().put(MOV_NUMREG, numreg); err = mov.read(_isequal, _lock); if (err == NOERR) { mov.put(MOV_CODCAUS, codcau); mov.put(MOV_TIPOMOV, tm_nota_credito); err = mov.rewrite(); } if (err != NOERR) return error_box(FR("Impossibile modificare il movimento %ld: errore %d"), numreg, err); } if (err == NOERR) { TPartita& game = _nc.partita(rec); const int nriga = game.prima_fattura(numreg); if (nriga > 0) { TRiga_partite& fatt = game.riga(nriga); fatt.put(PART_CODCAUS, codcau); fatt.put(PART_TIPOMOV, tm_nota_credito); TRectype& pag = game.unassigned().row(nriga, true); pag.put(PAGSCA_IMPORTO, fatt.get(PART_IMPORTO)); err = game.rewrite() ? NOERR : _islocked; } else err = _iskeynotfound; } if (err != NOERR) return error_box(FR("Impossibile modificare la partita associata la movimento %ld: errore %d"), numreg, err); return true; } bool TPareggio_mask::abbuona_rata(const real& imp, const TRectype& nota, TRiga_scadenze& scad) { const TValuta valuta(scad.riga()); const bool in_valuta = valuta.in_valuta() ; const char* imp_field = in_valuta ? PAGSCA_IMPORTOVAL : PAGSCA_IMPORTO; TPartita& nc = _nc.partita(nota); TPartita& ft = scad.partita(); TRiga_partite& new_nc = ft.new_row(); new_nc.put(PART_SEZ, scad.riga().get_char(PART_SEZ) == 'D' ? 'A' : 'D'); new_nc.put(PART_TIPOMOV, nota.get(PART_TIPOMOV)); new_nc.put(PART_NREG, nota.get(PART_NREG)); new_nc.put(PART_NUMRIG, max(nota.get_int(PART_NUMRIG),1)); // corretto 24-09-2012 ! new_nc.put(PART_CODCAUS, nota.get(PART_CODCAUS)); new_nc.put(PART_REG, nota.get(PART_REG)); new_nc.put(PART_NUMDOC, nota.get(PART_NUMDOC)); new_nc.put(PART_DATADOC, nota.get(PART_DATADOC)); TRectype new_pag = scad.new_row(new_nc.get_int(PART_NRIGA)); new_pag.put(imp_field, imp); ft.modifica_pagamento(new_pag, valuta, true); ft.write(true); TRecord_array& unarray = nc.unassigned(); TRectype unass = unarray.row(nota.get_int(PART_NRIGA)); if (new_nc.get(PART_SEZ) == nota.get(PART_SEZ)) unass.add(imp_field, -imp); else unass.add(imp_field, imp); nc.modifica_pagamento(unass, valuta, true); nc.write(true); return true; } bool TPareggio_mask::elabora(const TRectype& nota, TPointer_array& scadenze) { CHECK(nota.num() == LF_PARTITE, "Solo partite, grazie!"); const tipo_movimento tm = (tipo_movimento)nota.get_int(PART_TIPOMOV); if (tm == tm_fattura && !ft2nc(nota)) // Trasforma eventuale fattura negativa return false; TScad_mask ass; const TString& codval = get(F_CODVAL); ass.set(F_CODVAL, codval); const bool in_valuta = is_true_value(codval); real residuo_nc = abs(nota.get_real(in_valuta ? PART_IMPORTOVAL : PART_IMPORTO)); ass.set(F_IMPORTO, residuo_nc); TSheet_field& sheet = ass.sfield(F_TUTTE); TString_array rate; FOR_EACH_ARRAY_ITEM(scadenze, i, s) { const TRiga_scadenze& scad = *(TRiga_scadenze*)s; TToken_string& row = sheet.row(-1); const real residuo_scad = scad.residuo(true).valore(); real imp = residuo_nc; if (imp > residuo_scad) imp = residuo_scad; row.add(imp.string()); residuo_nc -= imp; row.add(scad.get(SCAD_DATASCAD)); row.add(residuo_scad.string()); row.add(scad.importo(true).valore().string()); } if (ass.run() == K_ENTER) { FOR_EACH_SHEET_ROW(sheet, r, row) { const real imp = row->get(0); if (imp > ZERO) { TRiga_scadenze& scad = (TRiga_scadenze&)scadenze[r]; abbuona_rata(imp, nota, scad); } } } return true; } void TPareggio_mask::refill() { TWait_cursor hourglass; const short id = efield(F_FORNITORE).active() ? F_FORNITORE : (efield(F_SOTTOCONTO).active() ? F_SOTTOCONTO : F_CLIENTE); TBill bill; bill.get(*this, F_GRUPPO, F_CONTO, id, F_TIPO); if (bill.sottoconto() <= 0) return; const int tipo = get_int(F_TUTTE); const TString& codval = get(F_CODVAL); _nc.init(bill, codval, true, tipo); _ft.init(bill, codval, false, tipo); tfield(F_NC_TREE).set_tree(&_nc); tfield(F_FT_TREE).set_tree(&_ft); _numreg = 0; disable(DLG_LINK); disable(DLG_RECALC); } bool TPareggio_mask::on_field_event(TOperable_field& o, TField_event e, long jolly) { switch (o.dlg()) { //case F_SOTTOCONTO: case F_CLIENTE: case F_FORNITORE: if (e == fe_modify && !o.empty()) refill(); break; case F_CODVAL: case F_TUTTE: if (e == fe_modify) refill(); break; case F_CODCAUS_C: case F_CODCAUS_F: if (e == fe_init) { TEdit_field& e = (TEdit_field&)o; TCursor& cur = *e.browse()->cursor(); cur = 0L; e.set(cur.curr().get(CAU_CODCAUS)); } break; case F_NC_TREE: case F_FT_TREE: if (e == fe_button || e == fe_modify || e == fe_init) { _numreg = 0L; TTree_field& tf = (TTree_field&)o; if (tf.tree() != NULL) { TVariant var; if (tf.tree()->get_var("PART.NREG", var)) _numreg = var.as_int(); } enable(DLG_LINK, _numreg > 0); bool can_conv = false; if (_numreg > 0 && o.dlg() == F_NC_TREE) { TLocalisamfile mov(LF_MOV); mov.put(MOV_NUMREG, _numreg); can_conv = mov.read() == NOERR && mov.get_int(MOV_TIPOMOV) == tm_fattura; } enable(DLG_RECALC, can_conv); const bool can_work = _nc.has_root() && _ft.has_root(); enable(DLG_ELABORA, can_work); } break; case DLG_LINK: if (_numreg > 0) { TRectype mov(LF_MOV); mov.put(MOV_NUMREG, _numreg); if (mov.edit()) refill(); } break; case DLG_RECALC: if (e == fe_button) { const TRectype* nota = _nc.node2rec(EMPTY_STRING); if (nota != NULL && ft2nc(*nota)) refill(); } break; case DLG_ELABORA: if (e == fe_button) { const TRectype* nota = _nc.node2rec(EMPTY_STRING); if (nota == NULL) return error_box(TR("Selezionare una nota di credito nel pannello di sinistra")); const TTree_field& ft = tfield(F_FT_TREE); TPointer_array rate; TString_array a; if (ft.selection(a) > 0) { FOR_EACH_ARRAY_ROW(a, r, riga) { const TRectype* rec = _ft.node2rec(*riga); if (rec) rate.add((TRectype*)rec); } } if (rate.items() > 0) { if (elabora(*nota, rate)) refill(); } else return error_box(TR("Selezionare almeno una rata nel pannello di destra")); } break; default: break; } return true; } TPareggio_mask::TPareggio_mask() : TAutomask("sc0300a"), _numreg(0L) { TTree_field& nc = tfield(F_NC_TREE); TTree_field& ft = tfield(F_FT_TREE); RCT rct_nc; nc.get_rect(rct_nc); RCT rct_ft; ft.get_rect(rct_ft); RCT rct_ms; xvt_vobj_get_client_rect(nc.parent(), &rct_ms); const int b = rct_nc.left; rct_nc.right = rct_ft.left-b; rct_ft.right = rct_ms.right - b; nc.set_rect(rct_nc); ft.set_rect(rct_ft); } /////////////////////////////////////////////////////////// // TPareggio_partite /////////////////////////////////////////////////////////// class TPareggio_partite : public TSkeleton_application { protected: virtual void main_loop(); }; void TPareggio_partite::main_loop() { const int anno = xvt_vobj_get_attr(NULL_WIN, ATTR_APPL_VERSION_YEAR); if (anno >= 2121) { TPareggio_mask pm; pm.run(); } else error_box(TR("Versione non supportata: %d"), anno); } /////////////////////////////////////////////////////////// // Main /////////////////////////////////////////////////////////// int sc0300(int argc, char* argv[]) { TPareggio_partite pp; pp.run(argc, argv, TR("Pareggio Partite")); return 0; }