#include "sc2.h" #include "sc2402.h" #include "sc2102.h" #include "sc2400a.h" #include #include #include #include #include /////////////////////////////////////////////////////////// // Stampa solleciti /////////////////////////////////////////////////////////// class TStampaSol_application: public TSkeleton_application { TString _lingua_ditta; TSol_mask* _msk; bool _gesval; TSol_form* _form; protected: virtual bool create(); virtual bool destroy(); virtual void main_loop(); virtual void on_firm_change(); virtual void on_config_change(); bool get_mail_address(TToken_string& to, TToken_string& cc) const; virtual bool get_next_mail(TToken_string& to, TToken_string& cc, TToken_string& ccn, TString& subj, TString& text, TToken_string& attach, short& ui) const; const TString& game_key(const TRectype& part) const; // Costruisce chiave univoca per TAssoc_array partite bool ci_sono_scadenze_aperte(const TPartita& game, const TDate& dal, const TDate& al, const TDate& data_rischio) const; bool puoi_scartare(const TPartita& game, const TDate& datalim) const; int print_sol(); // stampa l'elemento corrente public: TSol_mask& mask() const { return *_msk; } TSol_form& form() const { return *_form; } TCursor_sheet& sheet() { return _msk->cur_sheet(); } bool print_selected(); // cicla la stampa sugli elementi selezionati bool mail_selected(); // manda email agli elementi selezionati TStampaSol_application(); virtual ~TStampaSol_application() {} }; bool TStampaSol_application::print_selected() { TCursor_sheet &s = sheet(); TCursor &c = *s.cursor(); const char who = mask().get_who(); const int key = mask().get_key(); // Attiva la stampa del saldo partita form().stampa_saldo(mask().stampa_saldo()); // filtra il cursore del form in modo che diventi uguale al cursor_sheet corrente // Qui sarebbe bello copiarsi l'indice dell'altro cursore TCursor &fc = *form().cursor(); fc.setkey(key); TRectype filter(LF_CLIFO); filter.put(CLI_TIPOCF, who); fc.setregion(filter, filter); const long print_all = !s.one_checked(); // se non ho selezionato nulla allora li stampo tutti long analfabeti = 0; // persone non stampate in quanto aventi lingua errata TPrinter& pr = printer(); pr.open(); const long items = c.items(); for (long i=0; i < items; i++) { if (print_all || s.checked(i)) { fc = i; // muove il cursore alla posizione corrente const int ret = print_sol(); if (ret < 0) analfabeti++; } if (pr.frozen()) break; } pr.close(); if (analfabeti > 0) warning_box(FR("%ld clienti non sono stati stampati in quanto " "il codice lingua non corrispondeva al profilo di stampa"), analfabeti); return true; } bool TStampaSol_application::ci_sono_scadenze_aperte(const TPartita& game, const TDate& dal, const TDate& al, const TDate& data_rischio) const { bool found = false; for (int r = game.last(); r > 0; r = game.pred(r)) { const TRiga_partite& row = game.riga(r); if (row.is_fattura() && row.get_date(PART_DATAREG) <= al) { for (int s = row.rate(); s > 0 ;s--) { const TRiga_scadenze& rata = row.rata(s); const TDate data = rata.get(SCAD_DATASCAD); if (data >= dal && data <= al) { found = !rata.chiusa(); if (!found) { TImporto rat = rata.importo(true); TImporto imp = rata.importo_pagato_al(true, data_rischio); imp.normalize(rat.sezione()); const real saldo = rat.valore() + imp.valore(); found = saldo > ZERO; } if (found) break; } } } } return found; } const TString& TStampaSol_application::game_key(const TRectype& part) const { TToken_string& tok = get_tmp_string(); tok = part.get(PART_ANNO); tok.add(part.get(PART_NUMPART)); return tok; } bool TStampaSol_application::puoi_scartare(const TPartita& game, const TDate& datalim) const { bool yes = game.chiusa(); if (yes && datalim.ok()) { TDate last; for (int r = game.last(); r > 0; r = game.pred(r)) { const TRiga_partite& riga = game.riga(r); if (riga.tipo() > tm_fattura) { const TDate d = riga.get(PART_DATAPAG); if (d > last) last = d; } } yes = last < datalim; } return yes; } int TStampaSol_application::print_sol() { TSol_form& f = form(); // preparazione variabili per controllo lingua const TRectype &clf= f.cursor()->file().curr(); const TString4 lincf = clf.get(CLI_CODLIN); bool ok = true; // controllo lingua ditta corrente if ((f.lingua() == _lingua_ditta && !lincf.empty()) || f.lingua() != _lingua_ditta) ok= (lincf == f.lingua()); if (!ok) return -1; // cliente analfabeta f.azzera_totali(); // filtra solo le partite del cliente selezionato TLocalisamfile partite(LF_PARTITE); partite.zero(); partite.put(PART_TIPOCF, clf.get(CLI_TIPOCF)); partite.put(PART_SOTTOCONTO, clf.get(CLI_CODCF)); const TRectype& parkur = partite.curr(); const TRectype filter(parkur); bool one_printed = false; // booleano di controllo di riuscita della stampa const bool sel_tot_saldo = f.get_sel_tot_saldo(); // selezione sul saldo totale cliente const real sel_importo(f.get_sel_importo()); // importo di selezione const TDate data_inizio_soll = _msk->get(F_DATAINISCAD); const TDate data_limite_soll = f.data_limite_operazione(); const TDate data_limite_scaduto = f.data_limite_scaduto(); const TDate data_rischio = f.data_inizio_rischio(); TAssoc_array games_in_range; if ((sel_tot_saldo && sel_importo > ZERO) || data_inizio_soll.ok()) { real saldo; for (int err = partite.read(_isgteq); err == NOERR && parkur == filter; err = partite.read(_isgreat)) { const TPartita game(parkur); if (!puoi_scartare(game, data_rischio)) { if (sel_tot_saldo) { const real sld = game.calcola_scaduto_al(false, data_limite_soll); saldo += sld; } if (data_inizio_soll.ok()) { if (ci_sono_scadenze_aperte(game, data_inizio_soll, data_limite_soll, data_rischio)) games_in_range.add(game_key(parkur)); } } partite.put(PART_NRIGA, 9999); } if (sel_tot_saldo && sel_importo > ZERO && saldo < sel_importo) return 0; if (data_inizio_soll.ok() && games_in_range.empty()) return 0; partite.curr() = filter; } for (int err = partite.read(_isgteq); err == NOERR && parkur == filter; err = partite.read(_isgreat)) { if (data_inizio_soll.ok() && !games_in_range.is_key(game_key(parkur))) continue; // Scarta parite fuori range di date const TPartita game(parkur); if (!puoi_scartare(game, data_rischio)) { const real saldo = game.calcola_scaduto_al(false, data_limite_scaduto); TImporto unreferenced; //Totale non assegnati per questa partita. { // E' giusto calcolare il saldo, comprendente i non assegnati. // se il saldo della partita chiude in avere va sommato ad unreferenced const TRiga_partite& sum = game.riga(game.first()); unreferenced = game.calcola_saldo_al(game.in_valuta() && f.in_valuta(),data_limite_soll, data_limite_scaduto, data_rischio); if (unreferenced.valore() > ZERO && unreferenced.sezione() == 'A') { unreferenced.normalize('A'); //per i non assegnati/anticipi c'e' solo la colonna AVERE const TString4 valuta = sum.get(PART_CODVAL); form().totali().add(unreferenced,valuta); } } if (sel_tot_saldo || (saldo > ZERO && saldo >= sel_importo ) || (saldo.is_zero() && !unreferenced.is_zero() && data_rischio < data_limite_scaduto)) { const bool printed = form().print_game(game); one_printed |= printed; } } partite.put(PART_NRIGA, 9999); if (printer().frozen()) break; } if (one_printed) { f.ultima_pagina(); printer().formfeed(); } return one_printed ? 1 : 0; } bool TStampaSol_application::get_mail_address(TToken_string& to, TToken_string& cc) const { const TRectype& fc = form().cursor()->curr(); const long codcf = fc.get_long(CLI_CODCF); TString8 clifo; clifo.format("C%06ld", codcf); TISAM_recordset contacts("USE MULTIREL\nFROM COD=BACON FIRST=#CLIFO\nTO COD=BACON FIRST=#CLIFO"); contacts.set_var("#CLIFO", clifo); TToken_string data; for (bool ok = contacts.move_first(); ok; ok = contacts.move_next()) { data = contacts.get("DATA").as_string(); FOR_EACH_TOKEN(data, tok) { const TFixed_string doc(tok); if (doc.starts_with("sc2400", true) || doc.starts_with("sollec", true)) { const TRectype& rub = cache().get(LF_CONTACT, contacts.get("SECOND").as_int()); TString80 mail = rub.get("MAIL"); if (mail.blank()) mail = rub.get("MAIL2"); if (mail.full()) { if (to.blank()) to = mail; else cc.add(mail); break; } } } } if (to.blank()) { TString8 key; key << "C|" << codcf; to = cache().get(LF_CLIFO, key, CLI_DOCMAIL); } return to.full(); } bool TStampaSol_application::get_next_mail(TToken_string& to, TToken_string& cc, TToken_string& ccn, TString& subj, TString& text, TToken_string& attach, short& ui) const { bool ok = TApplication::get_next_mail(to, cc, ccn, subj, text, attach, ui) && get_mail_address(to, cc); if (ok) { const TRectype& clifo = form().cursor()->curr(); TDate oggi = mask().get(F_DATALIMSOL); if (!oggi.ok()) oggi = mask().get_date(F_DATASEND); subj << TR("Sollecito ") << prefix().firm().ragione_sociale(); TString ragsoc = clifo.get(CLI_RAGSOC); ragsoc.strip_double_spaces(); text << "Spett. " << ragsoc << '\n' << TR("Si ricorda il rispetto delle scadenze aperte al ") << oggi << '\n' << TR(" riepilogate nel file allegato ") << attach << '\n' << prefix().firm().ragione_sociale(); if (to.full()) ui &= ~0x1; // No user interface ui |= 0x2; // Query receipt const long codcf = clifo.get_long(CLI_CODCF); TFilename pdf; ok = get_next_pdf(oggi.year(), -1, "SOLL", oggi.date2ansi(), codcf, pdf); attach = pdf; } return ok; } struct TMail_message : public TObject { TToken_string _to, _cc, _ccn; TString _subj, _text; TToken_string _attach; short _ui; }; bool TStampaSol_application::mail_selected() { TCursor_sheet &s = sheet(); TCursor &c = *s.cursor(); const char who = mask().get_who(); const int key = mask().get_key(); // Attiva la stampa del saldo partita form().stampa_saldo(mask().stampa_saldo()); // filtra il cursore del form in modo che diventi uguale al cursor_sheet corrente // Qui sarebbe bello copiarsi l'indice dell'altro cursore TCursor &fc = *form().cursor(); fc.setkey(key); TRectype filter(LF_CLIFO); filter.put(CLI_TIPOCF, who); fc.setregion(filter, filter); const long print_all = !s.one_checked(); // se non ho selezionato nulla allora li stampo tutti TLog_report log; TArray mail; const long items = c.items(); if (items > 0) { const TDate oggi(TODAY); TProgind pi(items); TPrinter& pr = printer(); for (long i=0; i < items; i++) { if (!pi.addstatus(1)) break; if (print_all || s.checked(i)) { fc = i; // muove il cursore alla posizione corrente pr.set_export_file("soll.pdf", true); pr.open(); const int ret = print_sol(); pr.close(); if (ret > 0) { TString msg; msg << fc.curr().get(CLI_RAGSOC) << ": "; msg.strip_double_spaces(); TMail_message* m = new TMail_message; bool done = false; if (get_next_mail(m->_to, m->_cc, m->_ccn, m->_subj, m->_text, m->_attach, m->_ui)) { const TFilename fn = m->_attach; xvt_vobj_destroy(883); done = pr.print_pdf(printer().get_txt(), fn); if (done) { msg << TR("invio ") << fn.name() << TR(" a ") << m->_to; log.log(0, msg); mail.add(m); } else { msg << TR("Impossibile genereare ") << fn; log.log(2, msg); } } else { msg << TR("Impossibile trovare un indirizzo e-mail valido"); log.log(2, msg); } if (!done) delete m; } } } pr.read_configuration(); } log.preview(); if (!mail.empty()) { TArray_sheet sheet(-1, -1, 78, 20, TR("Mail"), HR("@1|Destinatario@32|Messaggio@50"), 0, 1); FOR_EACH_ARRAY_ITEM(mail, r, obj) { const TMail_message& m = *(TMail_message*)obj; TToken_string* row = new TToken_string; *row = "X"; row->add(m._to); row->add(m._text.before('\n')); sheet.add(row); } if (sheet.run() == K_ENTER) { const long m = sheet.checked(); if (m > 0 && yesno_box(FR("Confermare l'invio di %ld mail?"), m)) { FOR_EACH_CHECKED_ROW(sheet, r, row) { const TMail_message& m = (const TMail_message&)mail[r]; xvt_mail_send(m._to, m._cc, m._ccn, m._subj, m._text, m._attach, m._ui); } } } } return true; } bool TStampaSol_application::create() { TApplication::create(); open_files(LF_TABCOM, LF_TAB, LF_CAUSALI, LF_MOV, LF_RMOV, 0); open_files(LF_NDITTE, LF_ANAG, LF_COMUNI, LF_RFORM, 0); open_files(LF_CLIFO, LF_PARTITE, LF_SCADENZE, LF_PAGSCA ,0); _msk = new TSol_mask("sc2400a"); return TSkeleton_application::create(); } bool TStampaSol_application::destroy() { delete _msk; return TSkeleton_application::destroy(); } void TStampaSol_application::on_config_change() { TConfig c(CONFIG_DITTA, "cg"); _lingua_ditta= c.get("CodLin"); _gesval= c.get_bool("GesVal"); } void TStampaSol_application::on_firm_change() { mask().reset(); mask().set(F_STAMPSALDO, "X"); } void TStampaSol_application::main_loop() { TSol_mask& m = mask(); for (;;) { const KEY key = m.run(); if (key == K_QUIT) break; _form= new TSol_form(m, _gesval, F_DATALIMOP, F_DATALIMSOL, F_GGRISCHIO); if (key == 'M') mail_selected(); else print_selected(); delete _form; _form= NULL; } } TStampaSol_application::TStampaSol_application(): _lingua_ditta(1), _msk(NULL), _form(NULL) {} int sc2400(int argc, char** argv) { TStampaSol_application app; app.run(argc, argv, TR("Stampa solleciti")); return 0; }