Files correlati : sc2.exe pec.frm sc2200a.msk sc2300a.msk MODIFICA CRPA Possibilità di stampare il pagamento del cliente nella testata dell'estratti conto. Aggiunto filtro per ulteriore classificazione nello scadenziario. Possibilità di stampare le note delle scadenze nella stampa scaduto. Possibiltà di stampare il flag di rata bloccata e il dati di analitica e di filtrare per dati analitica nei solleciti. git-svn-id: svn://10.65.10.50/branches/R_10_00@23573 c028cbd2-c16b-5b4b-a496-9718f37d4682
592 lines
17 KiB
C++
Executable File
592 lines
17 KiB
C++
Executable File
#include "sc2.h"
|
|
#include "sc2402.h"
|
|
#include "sc2102.h"
|
|
#include "sc2400a.h"
|
|
|
|
#include "../ca/movana.h"
|
|
#include "../ca/rmovana.h"
|
|
#include "../ca/calib01.h"
|
|
#include <applicat.h>
|
|
#include <dongle.h>
|
|
#include <progind.h>
|
|
#include <printer.h>
|
|
#include <reputils.h>
|
|
|
|
#include <clifo.h>
|
|
|
|
///////////////////////////////////////////////////////////
|
|
// 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());
|
|
form().anal_filter(mask().get_anal_filter());
|
|
|
|
// 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();
|
|
TToken_string anal_filter = form().get_anal_filter();
|
|
const bool select_analitica = (dongle().active(CAAUT) || dongle().active(CMAUT)) && anal_filter.full() ;
|
|
TDecoder anal(LF_MOVANA, MOVANA_NUMREG, 3);
|
|
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 (select_analitica)
|
|
{
|
|
bool print = false;
|
|
for (int r = game.first(); !print && r <= game.last(); r = game.succ(r))
|
|
{
|
|
const TRiga_partite& row = game.riga(r);
|
|
const TString& numregcg = row.get(PART_NREG);
|
|
const long numreg = atol(anal.decode(numregcg));
|
|
|
|
if (numreg > 0)
|
|
{
|
|
TAnal_mov anal_mov(numreg);
|
|
TRecord_array & rows = anal_mov.body();
|
|
const int nrows = rows.rows();
|
|
TString s;
|
|
|
|
for (int i = 1; !print && i <= nrows; i++)
|
|
{
|
|
const TRectype & row = anal_mov.body().row(i);
|
|
TString f = anal_filter.get(0);
|
|
f.trim();
|
|
|
|
if (f.full())
|
|
{
|
|
s = row.get(RMOVANA_CODCMS);
|
|
print |= s.match(f);
|
|
}
|
|
f = anal_filter.get();
|
|
if (f.full())
|
|
{
|
|
s = row.get(RMOVANA_CODCCOSTO);
|
|
print |= s.match(f);
|
|
}
|
|
f = anal_filter.get();
|
|
if (f.full())
|
|
{
|
|
s = row.get(RMOVANA_CODFASE);
|
|
print |= s.match(f);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (!print)
|
|
return 0;
|
|
}
|
|
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());
|
|
form().anal_filter(mask().get_anal_filter());
|
|
|
|
// 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()
|
|
{
|
|
mask().reset();
|
|
mask().set(F_STAMPSALDO, "X");
|
|
|
|
TApplication::on_firm_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;
|
|
}
|