1788 lines
50 KiB
C++
1788 lines
50 KiB
C++
#include <applicat.h>
|
||
#include <automask.h>
|
||
#include <execp.h>
|
||
#include <golem.h>
|
||
#include <progind.h>
|
||
#include <reputils.h>
|
||
#include <tabutil.h>
|
||
#include <utility.h>
|
||
#include <agasys.h>
|
||
|
||
#include "../ve/velib05.h"
|
||
|
||
#include "pa0.h"
|
||
#include "pa0100a.h"
|
||
|
||
#include "../fe/felib.h"
|
||
|
||
#include <anagiu.h>
|
||
#include <comuni.h>
|
||
#include <cfven.h>
|
||
#include <nditte.h>
|
||
#include <unloc.h>
|
||
#include "../cg/cfban.h"
|
||
|
||
/////////////////////////////////////////////////////////////////////////////////////
|
||
// Globals
|
||
/////////////////////////////////////////////////////////////////////////////////////
|
||
|
||
static XVT_SQLDB _db = NULL; // PAF sqlite db
|
||
|
||
/////////////////////////////////////////////////////////////////////////////////////
|
||
// Utilities
|
||
/////////////////////////////////////////////////////////////////////////////////////
|
||
|
||
// Crea la coppia di chiavi per il db PAF a partire da un documento vero e proprio
|
||
static bool chiave_paf(const TDocumento& doc, TString& cess, TString& numdoc)
|
||
{
|
||
cess = doc.clifor().vendite().get(CFV_PADESTIN);
|
||
CHECK(cess.full(), "Destinatario fattura P.A. non valido");
|
||
|
||
const TCodice_numerazione& codnum = doc.codice_numerazione();
|
||
const long ndoc = doc.numero();
|
||
TString16 fullnumdoc; codnum.complete_num(ndoc, fullnumdoc);
|
||
|
||
numdoc.cut(0) << doc.get(DOC_ANNO) << '/' << codnum.codice() << '/' << fullnumdoc;
|
||
return cess.full();
|
||
}
|
||
|
||
// Crea la coppia di chiavi per il db PAF a partire da un semplice record di testata documento
|
||
static bool chiave_paf(const TRectype& doc, TString& cess, TString& numdoc)
|
||
{
|
||
const long codcf = doc.get_long(DOC_CODCF);
|
||
TString8 key; key.format("C|%ld", codcf);
|
||
cess = cache().get(LF_CFVEN, key, CFV_PADESTIN);
|
||
CHECK(cess.full(), "Destinatario fattura P.A. non valido");
|
||
|
||
const TCodice_numerazione& codnum = cached_numerazione(doc.get(DOC_CODNUM));
|
||
const long ndoc = doc.get_long(DOC_NDOC);
|
||
TString16 fullnumdoc; codnum.complete_num(ndoc, fullnumdoc);
|
||
numdoc.cut(0) << doc.get(DOC_ANNO) << '/' << codnum.codice() << '/' << fullnumdoc;
|
||
|
||
return cess.full();
|
||
}
|
||
|
||
// Cerca una stringa all'interno di una SLIST (Potrebbe diventare una funzione di XVT.h)
|
||
static SLIST_ELT xvt_slist_find_str(SLIST list, const char* str)
|
||
{
|
||
SLIST_ELT e = NULL;
|
||
for (e = xvt_slist_get_first(list); e; e = xvt_slist_get_next(list, e))
|
||
{
|
||
const char* val = xvt_slist_get(list, e, NULL);
|
||
if (xvt_str_compare_ignoring_case(str, val) == 0)
|
||
break;
|
||
}
|
||
return e;
|
||
}
|
||
|
||
// Aggiorna il file dst se pi<70> vecchio di src (Potrebbe diventare una funzione di XVT.h)
|
||
bool xvt_fsys_fupdate(const char* src, const char* dst)
|
||
{
|
||
bool ok = false;
|
||
if (xvt_fsys_file_exists(src))
|
||
{
|
||
const long tsrc = xvt_fsys_file_attr(src, XVT_FILE_ATTR_MTIME);
|
||
if (tsrc > 0)
|
||
{
|
||
long tdst = 0;
|
||
if (xvt_fsys_file_exists(dst))
|
||
tdst = xvt_fsys_file_attr(dst, XVT_FILE_ATTR_MTIME);
|
||
if (tsrc > tdst)
|
||
ok = xvt_fsys_fcopy(src, dst) != 0;
|
||
}
|
||
}
|
||
|
||
return ok;
|
||
}
|
||
|
||
/////////////////////////////////////////////////////////////////////////////////////
|
||
// TJava_profile
|
||
/////////////////////////////////////////////////////////////////////////////////////
|
||
|
||
class TJava_profile : public TObject
|
||
{
|
||
TFilename _path;
|
||
TString_array _row;
|
||
bool _dirty;
|
||
|
||
protected:
|
||
const TString& path2prop(const char* path) const;
|
||
|
||
public:
|
||
void set(const char* key, const char* value);
|
||
void save();
|
||
TJava_profile(const char* path);
|
||
~TJava_profile() { if (_dirty) save(); }
|
||
};
|
||
|
||
// Converte una stringa in un percorso per un file profile di Java
|
||
const TString& TJava_profile::path2prop(const char* path) const
|
||
{
|
||
TString percorso;
|
||
for (const char* c = path; *c; c++)
|
||
{
|
||
if (*c == ':' || is_slash(*c))
|
||
percorso << '\\';
|
||
percorso << *c;
|
||
}
|
||
return get_tmp_string() = percorso;
|
||
}
|
||
|
||
|
||
void TJava_profile::set(const char* key, const char* value)
|
||
{
|
||
_dirty = true;
|
||
FOR_EACH_ARRAY_ROW(_row, r, line)
|
||
{
|
||
if (line->starts_with(key, true))
|
||
{
|
||
const int equal = line->find('=');
|
||
if (equal > 0)
|
||
{
|
||
line->cut(equal + 1);
|
||
*line << path2prop(value);
|
||
return;
|
||
}
|
||
}
|
||
}
|
||
|
||
TToken_string* prop = new TToken_string(50, '=');
|
||
prop->add(key); prop->add(path2prop(value));
|
||
_row.add(prop);
|
||
}
|
||
|
||
void TJava_profile::save()
|
||
{
|
||
ofstream out(_path);
|
||
if (out.good())
|
||
{
|
||
FOR_EACH_ARRAY_ROW(_row, r, line) if (line->full())
|
||
out << *line << endl;
|
||
_dirty = false;
|
||
}
|
||
else
|
||
cantwrite_box(_path);
|
||
}
|
||
|
||
TJava_profile::TJava_profile(const char* path) : _path(path), _dirty(false)
|
||
{
|
||
TScanner s(_path);
|
||
while (!s.eof())
|
||
{
|
||
const TString& line = s.line();
|
||
if (line.full())
|
||
_row.add(new TToken_string(line, '='));
|
||
else
|
||
break;
|
||
}
|
||
}
|
||
|
||
/////////////////////////////////////////////////////////////////////////////////////
|
||
// TAncestor
|
||
/////////////////////////////////////////////////////////////////////////////////////
|
||
|
||
struct TAncestor : public TObject
|
||
{
|
||
TString20 _numdoc;
|
||
TDate _datadoc;
|
||
|
||
TAncestor(const TRectype& rdoc);
|
||
};
|
||
|
||
TAncestor::TAncestor(const TRectype& rdoc)
|
||
{
|
||
const int anno = rdoc.get_int(RDOC_ANNO);
|
||
const TString4 codnum = rdoc.get(RDOC_CODNUM);
|
||
const long ndoc = rdoc.get_long(RDOC_NDOC);
|
||
const TCodice_numerazione& num = cached_numerazione(codnum);
|
||
|
||
TToken_string kdoc;
|
||
kdoc = rdoc.get(RDOC_PROVV);
|
||
kdoc.add(anno);
|
||
kdoc.add(codnum);
|
||
kdoc.add(ndoc);
|
||
const TRectype& doc = cache().get(LF_DOC, kdoc);
|
||
|
||
TString16 numdoc; num.complete_num(ndoc, numdoc);
|
||
_numdoc.format("%d/%s/%s", anno, (const char*)codnum, (const char*)numdoc);
|
||
_datadoc = doc.get_date(DOC_DATADOC);
|
||
}
|
||
|
||
|
||
/////////////////////////////////////////////////////////////////////////////////////
|
||
// TPaf_record
|
||
/////////////////////////////////////////////////////////////////////////////////////
|
||
|
||
// Contenitore di campi di un record di database SQLite
|
||
class TPaf_record : public TObject
|
||
{
|
||
TString8 _table;
|
||
TToken_string _key;
|
||
TAssoc_array _fields;
|
||
|
||
protected:
|
||
void copy(const TPaf_record& rec) { _table = rec._table; _key = rec._key; _fields = rec._fields; }
|
||
const TString& var2str(const TString& fld, const TVariant& var) const;
|
||
|
||
public:
|
||
void reset() { _fields.destroy(); }
|
||
void set(const char* fld, const TVariant& var);
|
||
void set(const char* fld, long var);
|
||
void set(const char* fld, const char* var);
|
||
void set(const char* fld, const real& var);
|
||
void set(const char* fld, const TString& var);
|
||
void set(const char* fld, const TDate& var);
|
||
void set(const char* fld, bool var);
|
||
const TVariant& get(const char* fld) const;
|
||
|
||
bool insert();
|
||
bool remove();
|
||
bool search();
|
||
bool search(const char* k1, const char* k2, const char* k3 = NULL);
|
||
|
||
virtual TObject* dup() const { return new TPaf_record(*this); }
|
||
virtual bool ok() const { return _table.not_empty(); }
|
||
|
||
TPaf_record& operator=(const TPaf_record& rec) { copy(rec); return *this; }
|
||
TPaf_record(const TPaf_record& rec) { copy(rec); }
|
||
TPaf_record(const char* table);
|
||
};
|
||
|
||
// Imposta il valore di un campo variant
|
||
void TPaf_record::set(const char* fld, const TVariant& var)
|
||
{
|
||
CHECK(fld && *fld, "Null field name");
|
||
|
||
if (var.is_null())
|
||
{
|
||
_fields.remove(fld);
|
||
}
|
||
else
|
||
{
|
||
TVariant* obj = (TVariant*)_fields.objptr(fld);
|
||
if (obj != NULL)
|
||
*obj = var;
|
||
else
|
||
_fields.add(fld, new TVariant(var));
|
||
}
|
||
}
|
||
|
||
// Imposta il valore di un campo intero
|
||
void TPaf_record::set(const char* fld, long val)
|
||
{
|
||
const TVariant var(val);
|
||
set(fld, var);
|
||
}
|
||
|
||
// Imposta il valore di un campo stringa
|
||
void TPaf_record::set(const char* fld, const char* val)
|
||
{
|
||
if (val == NULL)
|
||
set(fld, NULL_VARIANT);
|
||
else
|
||
{
|
||
const TVariant var(val);
|
||
set(fld, var);
|
||
}
|
||
}
|
||
|
||
// Imposta il valore di un campo stringa
|
||
void TPaf_record::set(const char* fld, const TString& val)
|
||
{
|
||
const TVariant var(val);
|
||
set(fld, var);
|
||
}
|
||
|
||
// Imposta il valore di un campo numerico
|
||
void TPaf_record::set(const char* fld, const real& val)
|
||
{
|
||
const TVariant var(val);
|
||
set(fld, var);
|
||
}
|
||
|
||
// Imposta il valore di un campo data in formato ISO
|
||
void TPaf_record::set(const char* fld, const TDate& val)
|
||
{
|
||
if (val.ok())
|
||
{
|
||
const TVariant var(val);
|
||
set(fld, var);
|
||
}
|
||
else
|
||
set(fld, "");
|
||
}
|
||
|
||
// Imposta il valore di un campo booleano
|
||
void TPaf_record::set(const char* fld, bool var)
|
||
{
|
||
set(fld, var ? "SI" : "NO");
|
||
}
|
||
|
||
// Legge il valore di un campo variant
|
||
const TVariant& TPaf_record::get(const char* fld) const
|
||
{
|
||
const TVariant* var = (const TVariant*)_fields.objptr(fld);
|
||
return var ? *var : NULL_VARIANT;
|
||
}
|
||
|
||
// Converte un variant in una stringa valida per SQLite
|
||
const TString& TPaf_record::var2str(const TString& fldname, const TVariant& var) const
|
||
{
|
||
const TFieldtypes vt = var.type();
|
||
if (vt == _realfld)
|
||
{
|
||
const TCurrency v(var.as_real(), "", ZERO, fldname.find("PRZ")>0 || fldname.find("PREZZO")>0);
|
||
TString& tmp = get_tmp_string();
|
||
tmp << '\'' << v.string() << '\''; tmp.replace(',','.');
|
||
return tmp;
|
||
}
|
||
if (vt == _datefld)
|
||
{
|
||
TString& tmp = get_tmp_string();
|
||
tmp << '\'' << var.as_date().string(full, '-', full, full, amg_date) << '\'';
|
||
return tmp;
|
||
}
|
||
|
||
const TString& str = var.as_string();
|
||
|
||
bool apici = vt == _alfafld;
|
||
if (apici && str[0] != '0' && real::is_natural(str))
|
||
apici = false;
|
||
|
||
if (!apici)
|
||
return str;
|
||
|
||
TString& tmp = get_tmp_string();
|
||
tmp = str;
|
||
for (int a = str.rfind('\''); a >= 0; a--)
|
||
{
|
||
if (tmp[a] == '\'')
|
||
tmp.insert("'", a);
|
||
}
|
||
tmp.insert("'", 0);
|
||
tmp << '\'';
|
||
return tmp;
|
||
}
|
||
|
||
// Elimina il record in base ai campi chiave
|
||
bool TPaf_record::remove()
|
||
{
|
||
TString256 query;
|
||
query << "DELETE FROM " << _table << " WHERE ";
|
||
int nkf = 0;
|
||
FOR_EACH_TOKEN(_key, fld)
|
||
{
|
||
const TVariant& var = get(fld);
|
||
if (!var.is_null())
|
||
{
|
||
if (nkf++ > 0)
|
||
query << " AND ";
|
||
query << fld << '=' << var2str(fld, var) ;
|
||
}
|
||
}
|
||
CHECKS(nkf >= 2, "Can't remove partial key on table ", (const char*)_table);
|
||
query << ';';
|
||
return xvt_sql_execute(_db, query, NULL, 0L) > 0;
|
||
}
|
||
|
||
// Callback per la sottostante funzione search()
|
||
static int paf_search_record(void* jolly, int cols, char** values, char** names)
|
||
{
|
||
TPaf_record& rec = *(TPaf_record*)jolly;
|
||
for (int i = 0; i < cols; i++)
|
||
rec.set(names[i], values[i]);
|
||
return 0;
|
||
}
|
||
|
||
// Carica un record in base ai campi chiave
|
||
bool TPaf_record::search()
|
||
{
|
||
CHECKS(_fields.items() >= _key.items(), "Can't search partial key on table ", _table);
|
||
TString256 query;
|
||
query << "SELECT * FROM " << _table << " WHERE ";
|
||
FOR_EACH_TOKEN(_key, fld)
|
||
{
|
||
const TVariant& var = get(fld);
|
||
if (!var.is_null())
|
||
query << fld << '=' << var2str(fld, var) << " AND ";
|
||
}
|
||
query.rtrim(5);
|
||
query << ';';
|
||
return xvt_sql_execute(_db, query, paf_search_record, this) == 1;
|
||
}
|
||
|
||
// Carica un record in base ad un massimo di 3 campi chiave
|
||
bool TPaf_record::search(const char* k1, const char* k2, const char* k3)
|
||
{
|
||
_fields.destroy();
|
||
|
||
set(_key.get(0), k1);
|
||
set(_key.get(1), k2);
|
||
if (k3 && *k3)
|
||
set(_key.get(2), k3);
|
||
|
||
return search();
|
||
}
|
||
|
||
// Aggiunge un record al db
|
||
bool TPaf_record::insert()
|
||
{
|
||
CHECKS(_fields.items() > _key.items(), "Can't insert empty record on table ", _table);
|
||
|
||
TString query, values;
|
||
query << "INSERT INTO " << _table << "\n(";
|
||
FOR_EACH_ASSOC_OBJECT(_fields, obj, fld, itm)
|
||
{
|
||
const TVariant& var = get(fld);
|
||
if (!var.is_null())
|
||
{
|
||
query << fld << ',';
|
||
values << var2str(fld, var) << ',';
|
||
}
|
||
}
|
||
query.rtrim(1); values.rtrim(1);
|
||
query << ")\nVALUES (" << values << ");";
|
||
return xvt_sql_execute(_db, query, NULL, 0L) == 1;
|
||
}
|
||
|
||
// Crea un record della tabella data ed imposta i nomi dei campi chiave
|
||
TPaf_record::TPaf_record(const char* table) : _table(table), _key(15, ',')
|
||
{
|
||
_key = ini_get_string("./paf.ini", table, "INDEX_1");
|
||
if (_key.empty())
|
||
{
|
||
// Cerco di costruire i nomi della chiave cercando la K, come in P1_KEYHEADERFATT
|
||
TConfig cfg("paf.ini", table);
|
||
TAssoc_array& fields = cfg.list_variables();
|
||
FOR_EACH_ASSOC_STRING(fields, obj, key, str)
|
||
{
|
||
if (key[3] == 'K')
|
||
_key.add(key);
|
||
}
|
||
}
|
||
CHECKS(!_key.empty_items(), "Invalid primary key for table ", table);
|
||
}
|
||
|
||
/////////////////////////////////////////////////////////////////////////////////////
|
||
// TPa_mask
|
||
/////////////////////////////////////////////////////////////////////////////////////
|
||
|
||
class TPA_mask : public TAutomask
|
||
{
|
||
protected:
|
||
virtual bool on_field_event(TOperable_field& o, TField_event e, long jolly);
|
||
|
||
void fill();
|
||
void init();
|
||
bool is_fattura(const TRectype& doc) const;
|
||
|
||
public:
|
||
TPA_mask() : TAutomask("pa0100a") { }
|
||
};
|
||
|
||
bool TPA_mask::is_fattura(const TRectype& doc) const
|
||
{
|
||
const TTipo_documento& td = cached_tipodoc(doc.get(DOC_TIPODOC));
|
||
if (!td.is_fattura()) // Tengo per buone solo le fatture e le note di credito
|
||
return false;
|
||
|
||
const TCodice_numerazione& cn = cached_numerazione(doc.get(DOC_CODNUM));
|
||
return cn.tipo() == 2 && !cn.get_bool("B10"); // Controlla se fattura provvisioria esclusa da P.A.
|
||
}
|
||
|
||
|
||
void TPA_mask::fill()
|
||
{
|
||
TSheet_field& docs = sfield(F_DOCS);
|
||
TString_array& sht = docs.rows_array();
|
||
docs.hide();
|
||
|
||
sht.destroy();
|
||
|
||
// Seleziona tutti i clienti che sono pubbliche amministrazioni (PADESTIN!='')
|
||
TString query;
|
||
query << "USE 17 SELECT PADESTIN!=''"
|
||
<< "\nJOIN 20 INTO TIPOCF=TIPOCF CODCF==CODCF"
|
||
<< "\nFROM TIPOCF=C\nTO TIPOCF=C";
|
||
|
||
TISAM_recordset clifo_pa(query);
|
||
const TRecnotype n = clifo_pa.items();
|
||
if (n > 0)
|
||
{
|
||
const TDate dal = get(F_DATAINI);
|
||
const bool hide_processed = !get_bool(F_SHOWALL);
|
||
|
||
// Record di controllo per eventuali elaborazioni precedenti
|
||
TString hfatt(8), bfatt(20);
|
||
TPaf_record paf0100f("PAF0100F");
|
||
|
||
TProgress_monitor pi(n, NULL);
|
||
for (bool okc = clifo_pa.move_first(); okc; okc = clifo_pa.move_next())
|
||
{
|
||
if (!pi.add_status())
|
||
break;
|
||
|
||
query.cut(0);
|
||
query << "USE 33 KEY 2\nSELECT (BETWEEN(STATO,2,8))";
|
||
query << "\nFROM TIPOCF=C CODCF=#CLIENTE PROVV=D ANNO=" << dal.year() << " DATADOC=" << dal.date2ansi()
|
||
<< "\nTO TIPOCF=C CODCF=#CLIENTE PROVV=D";
|
||
TISAM_recordset doc_pa(query);
|
||
doc_pa.set_var("#CLIENTE", clifo_pa.get(CLI_CODCF));
|
||
const TRectype& doc = doc_pa.cursor()->curr();
|
||
for (bool okd = doc_pa.move_first(); okd; okd = doc_pa.move_next())
|
||
{
|
||
const TTipo_documento& td = cached_tipodoc(doc.get(DOC_TIPODOC));
|
||
if (!td.is_fattura()) // Tengo per buone solo le fatture e le note di credito
|
||
continue;
|
||
|
||
bool sent = false;
|
||
if (chiave_paf(doc, hfatt, bfatt))
|
||
{
|
||
if (paf0100f.search(hfatt, bfatt))
|
||
{
|
||
sent = paf0100f.get("P1_GESTIONE").as_string() == "X";
|
||
if (sent && hide_processed)
|
||
continue;
|
||
}
|
||
}
|
||
TToken_string* row = new TToken_string;
|
||
*row = sent ? " " : "X";
|
||
row->add(doc_pa.get(DOC_ANNO).as_int(), 1);
|
||
row->add(doc_pa.get(DOC_CODNUM).as_string());
|
||
row->add(doc_pa.get(DOC_NDOC).as_int());
|
||
row->add(doc_pa.get(DOC_DATADOC).as_date());
|
||
row->add(clifo_pa.get(CFV_CODCF).as_int());
|
||
row->add(clifo_pa.get("20."CLI_RAGSOC).as_string());
|
||
row->add(clifo_pa.get(CFV_PADESTIN).as_string());
|
||
row->add(clifo_pa.get(CFV_PARIFAMM).as_string());
|
||
row->add(clifo_pa.get("20."CLI_COFI).as_string());
|
||
row->add(clifo_pa.get("20."CLI_SPLITPAY).as_bool() ? "X" : "");
|
||
|
||
sht.add(row);
|
||
}
|
||
}
|
||
}
|
||
docs.force_update();
|
||
docs.show();
|
||
}
|
||
|
||
bool TPA_mask::on_field_event(TOperable_field& o, TField_event e, long jolly)
|
||
{
|
||
switch (o.dlg())
|
||
{
|
||
case F_DATAINI:
|
||
if (e == fe_init)
|
||
o.set(ini_get_string(CONFIG_DITTA, "pa", "LastXML", "31-03-2015")); else
|
||
if (e == fe_modify)
|
||
fill(); else
|
||
if (e == fe_close)
|
||
ini_set_string(CONFIG_DITTA, "pa", "LastXML", o.get());
|
||
break;
|
||
case F_SHOWALL:
|
||
if (e == fe_modify)
|
||
fill();
|
||
break;
|
||
case F_DOCS:
|
||
if (e == fe_init)
|
||
fill();
|
||
if (e == se_query_add || e == se_query_del)
|
||
return false;
|
||
break;
|
||
case DLG_USER:
|
||
if (e == fe_button && jolly > 0)
|
||
{
|
||
TSheet_field& docs = sfield(F_DOCS);
|
||
TToken_string& row = docs.row(docs.selected());
|
||
TRectype doc(LF_DOC);
|
||
doc.put(DOC_PROVV, 'D');
|
||
doc.put(DOC_ANNO, row.get(1));
|
||
doc.put(DOC_CODNUM, row.get());
|
||
doc.put(DOC_NDOC, row.get());
|
||
if (doc.edit())
|
||
fill();
|
||
}
|
||
break;
|
||
default: break;
|
||
}
|
||
return true;
|
||
}
|
||
|
||
/////////////////////////////////////////////////////////////////////////////////////
|
||
// TDoc2Paf
|
||
/////////////////////////////////////////////////////////////////////////////////////
|
||
|
||
class TDoc2Paf : public TSkeleton_application
|
||
{
|
||
TAnagrafica _ditta;
|
||
TString16 _cofi;
|
||
TFilename _dbname;
|
||
TLog_report* _log;
|
||
TString _logpaf;
|
||
|
||
private:
|
||
int parse_line(const TString& line, TString& var, TString& val) const;
|
||
bool create_table(TScanner& paf, const TString& table);
|
||
|
||
const TRectype* find_parent_row(const TRectype& rdoc) const;
|
||
int find_ancestors(const TRiga_documento& rdoc, TArray& ancestors) const;
|
||
|
||
protected:
|
||
bool parse_sconto(const TString& formula, TToken_string& sconti) const;
|
||
bool get_bnp_iban(const TString& abi, const TString& cab, int prg, TString& iban) const;
|
||
bool get_bank(const TDocumento& doc, TString& iban, TString& abi, TString& cab, TString& istituto) const;
|
||
const char* descrizione(const TRiga_documento& rdoc) const;
|
||
const TRectype& cco(const TRectype& doc) const; // Contratto/Convenzione/Offerta
|
||
|
||
void log(int severity, const char* msg);
|
||
bool show_log();
|
||
void set_IVA(const TRiga_documento& rdoc, TPaf_record& paf) const;
|
||
|
||
bool elabora(TDocumentoEsteso& doc);
|
||
bool elabora(const TRectype& rec);
|
||
bool elabora(const TDoc_key& key);
|
||
bool elabora(const TFilename& ini);
|
||
bool genera_xml();
|
||
|
||
public:
|
||
virtual bool create();
|
||
virtual bool destroy();
|
||
virtual void main_loop();
|
||
|
||
TDoc2Paf() : _log(NULL) {}
|
||
};
|
||
|
||
bool TDoc2Paf::parse_sconto(const TString& formula, TToken_string& sconti) const
|
||
{
|
||
sconti.cut(0);
|
||
int start = 0;
|
||
for (int i = 0; ; i++)
|
||
{
|
||
const char c = formula[i];
|
||
if (c == '+' || c == '-' || c < ' ')
|
||
{
|
||
if (i > 0)
|
||
{
|
||
TString8 tok = formula.sub(start, i);
|
||
tok.replace(',', '.');
|
||
const real perc = tok;
|
||
if (!perc.is_zero())
|
||
sconti.add(tok);
|
||
}
|
||
if (c < ' ')
|
||
break;
|
||
start = i;
|
||
}
|
||
}
|
||
return sconti.full();
|
||
}
|
||
|
||
bool TDoc2Paf::get_bnp_iban(const TString& abi, const TString& cab, int nprog, TString& iban) const
|
||
{
|
||
TTable bnp("BNP");
|
||
TString16 key;
|
||
key << abi << cab;
|
||
if (nprog > 0)
|
||
{
|
||
TString4 sprog; sprog.format("%02d", nprog);
|
||
key << sprog;
|
||
}
|
||
bnp.put("CODTAB", key);
|
||
int err = bnp.read(_isgteq);
|
||
if (err == NOERR && !bnp.get("CODTAB").starts_with(abi))
|
||
err = _iskeynotfound;
|
||
if (err == NOERR)
|
||
iban = bnp.get("S3");
|
||
|
||
return err == NOERR;
|
||
}
|
||
|
||
bool TDoc2Paf::get_bank(const TDocumento& doc, TString& iban, TString& abi, TString& cab, TString& istituto) const
|
||
{
|
||
bool found = false;
|
||
abi = doc.get(DOC_CODABIP);
|
||
cab = doc.get(DOC_CODCABP);
|
||
int prg = doc.get_int(DOC_PROGBNP);
|
||
|
||
found = abi.full() && cab.full();
|
||
if (found)
|
||
get_bnp_iban(abi, cab, prg, iban);
|
||
|
||
if (!found) // Se non trovo banca sul DOC la cerco su CFBAN
|
||
{
|
||
TToken_string key;
|
||
key.add("C"); key.add(doc.codcf()); key.add("N"); key.add(1);
|
||
const TRectype& cfban = cache().get(LF_CFBAN, key);
|
||
if (!cfban.empty())
|
||
{
|
||
abi = cfban.get(CFBAN_ABI);
|
||
cab = cfban.get(CFBAN_CAB);
|
||
prg = cfban.get_int(CFBAN_PROGPR);
|
||
found = abi.full() && cab.full();
|
||
iban = cfban.get(CFBAN_IBAN);
|
||
if (found && iban.blank())
|
||
get_bnp_iban(abi, cab, prg, iban);
|
||
}
|
||
}
|
||
|
||
if (!found) // Se non trovo banca su CFBAN la cerco su CFVEN
|
||
{
|
||
const TRectype& cfven = doc.clifor().vendite();
|
||
abi = cfven.get(CFV_CODABIPR);
|
||
cab = cfven.get(CFV_CODCABPR);
|
||
found = abi.full() && cab.full();
|
||
if (found)
|
||
get_bnp_iban(abi, cab, 0, iban);
|
||
}
|
||
|
||
if (found)
|
||
istituto = cache().get("%BAN", abi, "S0");
|
||
|
||
return found;
|
||
}
|
||
|
||
const char* TDoc2Paf::descrizione(const TRiga_documento& rdoc) const
|
||
{
|
||
if (rdoc.get_bool(RDOC_DESCLUNGA))
|
||
{
|
||
TString tmp;
|
||
tmp << rdoc.get(RDOC_DESCR) << rdoc.get(RDOC_DESCEST);
|
||
tmp.replace('\n', ' '); tmp.strip_double_spaces(); tmp.trim();
|
||
TParagraph_string para(tmp, 100);
|
||
return para.get(0);
|
||
}
|
||
return rdoc.get(RDOC_DESCR);
|
||
}
|
||
|
||
const TRectype* TDoc2Paf::find_parent_row(const TRectype& rdoc) const
|
||
{
|
||
const long id = rdoc.get_long(RDOC_DAIDRIGA);
|
||
if (id > 0L)
|
||
{
|
||
TToken_string key;
|
||
key.add(rdoc.get(RDOC_DACODNUM));
|
||
if (key.full())
|
||
{
|
||
key.add(rdoc.get(RDOC_DAANNO));
|
||
key.add(rdoc.get(RDOC_DAPROVV));
|
||
key.add(rdoc.get(RDOC_DANDOC));
|
||
for (int r = 0; ; r++)
|
||
{
|
||
if (r == 0)
|
||
key.add(id, 4);
|
||
else
|
||
key.add(r, 4);
|
||
const TRectype& rec = cache().get(LF_RIGHEDOC, key);
|
||
if (r > 0 && rec.empty())
|
||
break;
|
||
if (rec.get_long(RDOC_IDRIGA) == id)
|
||
return &rec;
|
||
}
|
||
}
|
||
}
|
||
return NULL;
|
||
}
|
||
|
||
int TDoc2Paf::find_ancestors(const TRiga_documento& rdoc, TArray& ancestors) const
|
||
{
|
||
if (rdoc.is_articolo())
|
||
{
|
||
for (const TRectype* prdoc = find_parent_row(rdoc); prdoc != NULL; prdoc = find_parent_row(*prdoc))
|
||
{
|
||
const TCodice_numerazione& cn = cached_numerazione(prdoc->get(RDOC_CODNUM));
|
||
const int td = cn.tipo();
|
||
if (td > 0 && ancestors.objptr(td) == NULL)
|
||
ancestors.add(new TAncestor(*prdoc), td);
|
||
}
|
||
}
|
||
return ancestors.items();
|
||
}
|
||
|
||
const TRectype& TDoc2Paf::cco(const TRectype& doc) const
|
||
{
|
||
TString80 conkey;
|
||
const TString& con = doc.get(DOC_CONTRATTO);
|
||
if (con.full())
|
||
{
|
||
char tcon = doc.get_char(DOC_MODPAG);
|
||
if (tcon < 'C') tcon = 'C';
|
||
conkey.format("%c%6ld%s", tcon, doc.get_long(DOC_CODCF), (const char*)con);
|
||
}
|
||
return cache().get("&CON", conkey);
|
||
}
|
||
|
||
void TDoc2Paf::log(int severity, const char* msg)
|
||
{
|
||
if (severity < 0)
|
||
{
|
||
_logpaf = msg;
|
||
} else
|
||
if (_log == NULL)
|
||
{
|
||
_log = new TLog_report;
|
||
if (_logpaf.full())
|
||
{
|
||
TString txt;
|
||
txt << _logpaf << ": " << msg;
|
||
_log->log(severity, txt);
|
||
}
|
||
else
|
||
_log->log(severity, msg);
|
||
}
|
||
}
|
||
|
||
bool TDoc2Paf::show_log()
|
||
{
|
||
bool ok = true;
|
||
if (_log)
|
||
{
|
||
_log->preview();
|
||
delete _log;
|
||
_log = NULL;
|
||
ok = noyes_box(TR("Si desidera procedere con la generazione file xml?"));
|
||
}
|
||
return ok;
|
||
}
|
||
|
||
void TDoc2Paf::set_IVA(const TRiga_documento& rdoc, TPaf_record& paf) const
|
||
{
|
||
const TRectype& ai = cache().get("%IVA", rdoc.get(RDOC_CODIVA));
|
||
const real aliquota = ai.get("R0");
|
||
paf.set("PI_ALIQUOTAIVA", aliquota);
|
||
if (aliquota.is_zero())
|
||
{
|
||
const TString& tipo = ai.get("S1");
|
||
const char* natura = "N2"; // Non soggetto
|
||
if (tipo == "NI") natura = "N3"; else // Non imponibile
|
||
if (tipo == "ES") natura = "N4"; // Esente
|
||
paf.set("PI_NATURA", natura);
|
||
}
|
||
}
|
||
|
||
|
||
bool TDoc2Paf::elabora(TDocumentoEsteso& doc)
|
||
{
|
||
TString8 hfatt; // Codice univoco di 6 caratteri dell'ufficio P.A.
|
||
TString20 bfatt; // Codice univoco di 20 caratteri del documento
|
||
if (!chiave_paf(doc, hfatt, bfatt))
|
||
return false;
|
||
log(-1, bfatt);
|
||
|
||
const TFirm& firm = prefix().firm();
|
||
const char* const paese = "IT";
|
||
|
||
// <DatiTrassmissione>
|
||
TPaf_record paf0100f("PAF0100F");
|
||
paf0100f.set("P1_KEYHEADERFATT", hfatt);
|
||
paf0100f.set("P1_KEYBODYFATT", bfatt);
|
||
paf0100f.remove();
|
||
|
||
paf0100f.set("P1_TRASMITTPAESE", paese);
|
||
paf0100f.set("P1_TRASMITTCOD", _cofi);
|
||
paf0100f.set("P1_PRGINVIO", ""); // Ci pensa SiAggPA
|
||
paf0100f.set("P1_FMTTRASMISS", "SDI11"); // SDI11 si usa dal 2015 per lo split payment (prima era SDI10)
|
||
|
||
paf0100f.set("P1_CODDEST", hfatt);
|
||
TString80 tel; tel << firm.get(NDT_PTEL) << firm.get(NDT_TEL);
|
||
paf0100f.set("P1_TELEFONO", tel);
|
||
paf0100f.set("P1_MAIL", firm.get(NDT_MAIL));
|
||
paf0100f.set("P1_GESTIONE", "D");
|
||
paf0100f.insert();
|
||
// </DatiTrassmissione>
|
||
|
||
// <CedentePrestatore>
|
||
TPaf_record paf0200f("PAF0200F");
|
||
paf0200f.set("P2_KEYHEADERFATT", hfatt);
|
||
paf0200f.set("P2_KEYBODYFATT", bfatt);
|
||
paf0200f.remove();
|
||
|
||
if (_ditta.partita_IVA().full())
|
||
{
|
||
paf0200f.set("P2_FISCIVAPAESE", paese); // Sempre IT
|
||
paf0200f.set("P2_FISCIVACOD", _ditta.partita_IVA());
|
||
}
|
||
paf0200f.set("P2_CODFISCALE", _ditta.codice_fiscale());
|
||
if (_ditta.fisica())
|
||
{
|
||
paf0200f.set("P2_ANANOME", _ditta.nome());
|
||
paf0200f.set("P2_ANACOGNOME", _ditta.cognome());
|
||
}
|
||
else
|
||
{
|
||
paf0200f.set("P2_ANADENOMIN", _ditta.ragione_sociale());
|
||
}
|
||
|
||
const char* regime_fiscale = "RF01";
|
||
if (doc.get_bool(DOC_IVAXCASSA))
|
||
{
|
||
// Supponiamo volume d'affari > 200000, altrimenti sarebbe RF17
|
||
regime_fiscale = "RF16";
|
||
}
|
||
paf0200f.set("P2_REGFISCALE", regime_fiscale);
|
||
|
||
// DatiSede
|
||
paf0200f.set("P2_SEDEIND", _ditta.via_residenza());
|
||
paf0200f.set("P2_SEDENRCIVICO", _ditta.civico_residenza());
|
||
paf0200f.set("P2_SEDECAP", _ditta.CAP_residenza());
|
||
paf0200f.set("P2_SEDECOMUNE", _ditta.comune_residenza());
|
||
paf0200f.set("P2_SEDEPROV", _ditta.provincia_residenza());
|
||
paf0200f.set("P2_SEDENAZ", paese);
|
||
paf0200f.set("P2_GESTIONE", "D");
|
||
|
||
TAnagrafica cliente(doc.clifor());
|
||
|
||
TString rifamm = cco(doc).get("S4");
|
||
if (rifamm.blank())
|
||
rifamm = doc.clifor().vendite().get(CFV_PARIFAMM);
|
||
paf0200f.set("P2_RIFAMMINISTR", rifamm);
|
||
|
||
TISAM_recordset unloc("USE UNLOC\nJOIN COMUNI INTO COM==COMCCIAA\nFROM CODDITTA=#DITTA\nTO CODDITTA=#DITTA");
|
||
unloc.set_var("#DITTA", firm.get(NDT_CODDITTA));
|
||
if (unloc.move_first())
|
||
{
|
||
const TString& numrea = unloc.get(ULC_NUMCCIAA).as_string();
|
||
if (numrea.full())
|
||
{
|
||
paf0200f.set("P2_ISCRREANUM", numrea);
|
||
paf0200f.set("P2_ISCRREAUFF", unloc.get("13->"COM_PROVCOM));
|
||
}
|
||
}
|
||
|
||
if (_ditta.giuridica())
|
||
{
|
||
TISAM_recordset anagiu("USE ANAGIU\nFROM CODANAGR=#CODICE\nTO CODANAGR=#CODICE");
|
||
anagiu.set_var("#CODICE", firm.get(NDT_CODANAGR));
|
||
if (anagiu.move_first())
|
||
{
|
||
paf0200f.set("P2_ISCRREACAP", anagiu.get(ANG_CAPSOC));
|
||
const int ss = anagiu.get(ANG_STATOSOC).as_int();
|
||
paf0200f.set("P2_ISCRREASLIQUID", (ss==2 || ss==3) ? "LS" : "LN");
|
||
}
|
||
}
|
||
else
|
||
paf0200f.set("P2_ISCRREASLIQUID", "LN");
|
||
|
||
paf0200f.insert();
|
||
|
||
// </CedentePrestatore>
|
||
|
||
// <CessionarioCommittente>
|
||
|
||
TPaf_record paf0400f("PAF0400F");
|
||
paf0400f.set("P4_KEYHEADERFATT", hfatt);
|
||
paf0400f.set("P4_KEYBODYFATT", bfatt);
|
||
paf0400f.remove();
|
||
|
||
if (cliente.partita_IVA().full())
|
||
{
|
||
paf0400f.set("P4_FISCIVAPAESE", paese);
|
||
paf0400f.set("P4_FISCIVACOD", cliente.partita_IVA());
|
||
}
|
||
paf0400f.set("P4_CODFISC", cliente.codice_fiscale());
|
||
|
||
if (cliente.fisica())
|
||
{
|
||
paf0400f.set("P4_ANANOME", cliente.nome());
|
||
paf0400f.set("P4_ANACOGNOME", cliente.cognome());
|
||
}
|
||
else
|
||
{
|
||
paf0400f.set("P4_ANADENOM", cliente.ragione_sociale());
|
||
}
|
||
|
||
// DatiSede
|
||
paf0400f.set("P4_SEDEIND", cliente.via_residenza());
|
||
paf0400f.set("P4_SEDENRCIVICO", cliente.civico_residenza());
|
||
paf0400f.set("P4_SEDECAP", cliente.CAP_residenza());
|
||
paf0400f.set("P4_SEDECOMUNE", cliente.comune_residenza());
|
||
paf0400f.set("P4_SEDEPROV", cliente.provincia_residenza());
|
||
paf0400f.set("P4_SEDENAZ", "IT");
|
||
paf0400f.set("P4_GESTIONE", "D");
|
||
paf0400f.insert();
|
||
// </CessionarioCommittente>
|
||
|
||
// <DatiGenerali>
|
||
TPaf_record paf0700f("PAF0700F");
|
||
paf0700f.set("P7_KEYHEADERFATT", hfatt);
|
||
paf0700f.set("P7_KEYBODYFATT", bfatt);
|
||
paf0700f.remove();
|
||
paf0700f.set("P7_TIPODOC", doc.is_nota_credito() ? "TD04" : "TD01");
|
||
paf0700f.set("P7_DIVISA", "EUR"); // Aggiungere codice ISO 4217 a tabella divise (%VAL)
|
||
paf0700f.set("P7_DATA", doc.data());
|
||
|
||
const TCodice_numerazione& codnum = doc.codice_numerazione();
|
||
TString20 numdoc; codnum.complete_num(doc.numero(), numdoc);
|
||
paf0700f.set("P7_NUMERO", numdoc);
|
||
paf0700f.set("P7_GESTIONE", "D");
|
||
paf0700f.insert();
|
||
|
||
// <ScontoMaggiorazione>
|
||
TPaf_record paf0900f("PAF0900F");
|
||
paf0900f.set("P9_KEYHEADERFATT", hfatt);
|
||
paf0900f.set("P9_KEYBODYFATT", bfatt);
|
||
paf0900f.remove();
|
||
|
||
TString80 sconto_expr = doc.get(DOC_SCONTOPERC);
|
||
TToken_string sconti;
|
||
if (parse_sconto(sconto_expr, sconti))
|
||
{
|
||
long nlin_sconto = 0;
|
||
FOR_EACH_TOKEN(sconti, str)
|
||
{
|
||
const real sconto = str;
|
||
if (!sconto.is_zero()) // Precauzione inutile
|
||
{
|
||
paf0900f.set("P9_RIFNUMLINEA", ++nlin_sconto);
|
||
if (sconto > ZERO)
|
||
{
|
||
paf0900f.set("P9_TIPOSCONTO", "SC");
|
||
paf0900f.set("P9_PERCSCONTO", sconto);
|
||
}
|
||
else
|
||
{
|
||
paf0900f.set("P9_TIPOSCONTO", "MG");
|
||
paf0900f.set("P9_PERCSCONTO", -sconto);
|
||
}
|
||
paf0900f.set("P9_GESTIONE", "D");
|
||
paf0900f.insert();
|
||
}
|
||
}
|
||
}
|
||
// </ScontoMaggiorazione>
|
||
|
||
// <DatiGenerali>
|
||
TPaf_record paf2700f("PAF2700F");
|
||
paf2700f.set("PQ_KEYHEADERFATT", hfatt);
|
||
paf2700f.set("PQ_KEYBODYFATT", bfatt);
|
||
paf2700f.remove();
|
||
paf2700f.set("PQ_IMPTOTDOC", doc.totale_doc());
|
||
|
||
const TRectype& cont_conv_off = cco(doc);
|
||
TString causale = cont_conv_off.get("S1");
|
||
if (causale.full())
|
||
{
|
||
causale << ' ' << cont_conv_off.get("S2");
|
||
causale << ' ' << cont_conv_off.get("S3");
|
||
causale.strip_double_spaces();
|
||
causale.cut(200);
|
||
}
|
||
else
|
||
causale = doc.tipo().descrizione();
|
||
paf2700f.set("PQ_CAUSALE", causale);
|
||
// paf2700f.set("PQ_ART73", true);
|
||
paf2700f.set("PQ_GESTIONE", "D");
|
||
paf2700f.insert();
|
||
// </DatiGenerali>
|
||
|
||
// Azzera contratti
|
||
TPaf_record paf1000f("PAF1000F");
|
||
paf1000f.set("P0_KEYHEADERFATT", hfatt);
|
||
paf1000f.set("P0_KEYBODYFATT", bfatt);
|
||
paf1000f.remove();
|
||
|
||
// Azzera convenzioni
|
||
TPaf_record paf1100f("PAF1100F");
|
||
paf1100f.set("PA_KEYHEADERFATT", hfatt);
|
||
paf1100f.set("PA_KEYBODYFATT", bfatt);
|
||
paf1100f.remove();
|
||
|
||
// Azzera ordini
|
||
TPaf_record paf1200f("PAF1200F");
|
||
paf1200f.set("PB_KEYHEADERFATT", hfatt);
|
||
paf1200f.set("PB_KEYBODYFATT", bfatt);
|
||
paf1200f.remove();
|
||
|
||
// Azzera DDT
|
||
TPaf_record paf1600f("PAF1600F");
|
||
paf1600f.set("PF_KEYHEADERFATT", hfatt);
|
||
paf1600f.set("PF_KEYBODYFATT", bfatt);
|
||
paf1600f.remove();
|
||
|
||
const TString16 cup = doc.get(DOC_CUP);
|
||
const TString16 cig = doc.get(DOC_CIG);
|
||
const TString80 com = doc.get(DOC_CODCMS);
|
||
|
||
TString80 con = doc.get(DOC_CONTRATTO);
|
||
if (con.full() || cup.full() || cig.full())
|
||
{
|
||
char tcon = doc.get_char(DOC_MODPAG);
|
||
if (tcon < 'C') tcon = 'C';
|
||
|
||
TDate datadoc; // Data contratto non obbligatoria
|
||
if (con.full())
|
||
{
|
||
datadoc = cco(doc).get_date("D0");
|
||
}
|
||
else
|
||
{
|
||
// IdDocumento obbligatorio
|
||
con = cig;
|
||
if (con.blank())
|
||
con = cup;
|
||
}
|
||
|
||
if (tcon == 'O')
|
||
{
|
||
paf1000f.set("P0_RIFNUMLINEA", 0L);
|
||
paf1000f.set("P0_IDDOC", con);
|
||
paf1000f.set("P0_DATADOC", datadoc);
|
||
paf1000f.set("P0_COMMCONVENZ", com);
|
||
paf1000f.set("P0_CODCUP", cup);
|
||
paf1000f.set("P0_CODCIG", cig);
|
||
paf1000f.set("P0_GESTIONE", "D");
|
||
paf1000f.insert();
|
||
} else
|
||
if (tcon == 'C')
|
||
{
|
||
paf1100f.set("PA_RIFNUMLINEA", 0L);
|
||
paf1100f.set("PA_IDDOC", con);
|
||
paf1100f.set("PA_DATADOCU", datadoc);
|
||
paf1100f.set("PA_COMMCONVENZ", com);
|
||
paf1100f.set("PA_CODCUP", cup);
|
||
paf1100f.set("PA_CODCIG", cig);
|
||
paf1000f.set("PA_GESTIONE", "D");
|
||
paf1100f.insert();
|
||
}
|
||
else
|
||
{
|
||
paf1200f.set("PB_RIFNUMLINEA", 0L);
|
||
paf1200f.set("PB_IDDOC", con);
|
||
paf1200f.set("PB_DATADOCO", datadoc);
|
||
paf1200f.set("PB_COMMCONVENZ", com);
|
||
paf1200f.set("PB_CODCUP", cup);
|
||
paf1200f.set("PB_CODCIG", cig);
|
||
paf1200f.set("PB_GESTIONE", "D");
|
||
paf1200f.insert();
|
||
}
|
||
}
|
||
|
||
if (cup.blank() && cig.blank())
|
||
log(1, "CIG e CUP assenti");
|
||
|
||
// <DatiBeniServizi>
|
||
|
||
TPaf_record paf1800f("PAF1800F");
|
||
paf1800f.set("PI_KEYHEADERFATT", hfatt);
|
||
paf1800f.set("PI_KEYBODYFATT", bfatt);
|
||
paf1800f.remove(); // Cancella tutte le righe documento
|
||
|
||
TPaf_record paf2000f("PAF2000F");
|
||
paf2000f.set("PJ_KEYHEADERFATT", hfatt);
|
||
paf2000f.set("PJ_KEYBODYFATT", bfatt);
|
||
paf2000f.remove(); // Cancella tutti gli sconti di riga
|
||
|
||
long riga = 0;
|
||
FOR_EACH_PHYSICAL_RDOC(doc, r, rdoc)
|
||
{
|
||
paf1800f.reset();
|
||
paf1800f.set("PI_KEYHEADERFATT", hfatt);
|
||
paf1800f.set("PI_KEYBODYFATT", bfatt);
|
||
paf1800f.set("PI_NUMEROLINEA", ++riga);
|
||
paf1800f.set("PI_DESCRIZIONE", descrizione(*rdoc));
|
||
paf1800f.set("PI_ALIQUOTAIVA", "22.00"); // Altrimenti scarta le righe di descrizione
|
||
if (rdoc->is_merce())
|
||
{
|
||
paf1800f.set("PI_UNITAMISURA", rdoc->get(RDOC_UMQTA));
|
||
const real qta = rdoc->get(RDOC_QTA);
|
||
if (qta.is_zero())
|
||
{
|
||
TString msg; msg.format("La riga merce %d ha quantit<69> nulla", riga);
|
||
log(1, msg);
|
||
}
|
||
if (qta >= ZERO)
|
||
{
|
||
paf1800f.set("PI_QUANTITA", qta);
|
||
paf1800f.set("PI_PREZZOUNIT", rdoc->prezzo(false, false));
|
||
}
|
||
else
|
||
{
|
||
paf1800f.set("PI_QUANTITA", -qta);
|
||
paf1800f.set("PI_PREZZOUNIT", -rdoc->prezzo(false, false));
|
||
}
|
||
paf1800f.set("PI_PRZTOTALE", rdoc->importo(false, false));
|
||
set_IVA(*rdoc, paf1800f);
|
||
|
||
/*
|
||
const TDate data = doc.get(DOC_DATADOC);
|
||
paf1800f.set("PI_DTINIZIOPER", data);
|
||
paf1800f.set("PI_DTFINEPER", data);
|
||
*/
|
||
|
||
// <ScontoMaggiorazione>
|
||
|
||
sconto_expr = rdoc->get(RDOC_SCONTO);
|
||
if (parse_sconto(sconto_expr, sconti))
|
||
{
|
||
long nlin_sconto = 0;
|
||
FOR_EACH_TOKEN(sconti, str)
|
||
{
|
||
const real perc = str;
|
||
if (!perc.is_zero())
|
||
{
|
||
paf2000f.set("PJ_KEYNLINEA", (long)r);
|
||
paf2000f.set("PJ_KEYNPROGR", ++nlin_sconto);
|
||
if (perc > ZERO)
|
||
{
|
||
paf2000f.set("PJ_TIPOSCONTO", "SC");
|
||
paf2000f.set("PJ_PERCSCONTO", perc);
|
||
}
|
||
else
|
||
{
|
||
paf2000f.set("PJ_TIPOSCONTO", "MG");
|
||
paf2000f.set("PJ_PERCSCONTO", -perc);
|
||
}
|
||
paf2000f.set("PJ_GESTIONE", "D");
|
||
paf2000f.insert();
|
||
}
|
||
}
|
||
}
|
||
// </ScontoMaggiorazione>
|
||
|
||
TArray ancestors; find_ancestors(*rdoc, ancestors);
|
||
for (int i = ancestors.last(); i > 0; i = ancestors.pred(i))
|
||
{
|
||
const TAncestor& a = (const TAncestor&)ancestors[i];
|
||
if (i == 1)
|
||
{
|
||
TPaf_record paf1600f("PAF1600F");
|
||
paf1600f.reset();
|
||
paf1600f.set("PF_KEYHEADERFATT", hfatt);
|
||
paf1600f.set("PF_KEYBODYFATT", bfatt);
|
||
paf1600f.set("PF_RIFNUMLINEA", (long)r);
|
||
paf1600f.set("PF_NUMDDDT", a._numdoc);
|
||
paf1600f.set("PF_DATADDT", a._datadoc);
|
||
paf1600f.set("PF_GESTIONE", "D");
|
||
paf1600f.insert();
|
||
} else
|
||
if (i == 3)
|
||
{
|
||
TPaf_record paf1000f("PAF1000F");
|
||
paf1000f.set("P0_KEYHEADERFATT", hfatt);
|
||
paf1000f.set("P0_KEYBODYFATT", bfatt);
|
||
paf1000f.set("P0_RIFNUMLINEA", (long)r);
|
||
paf1000f.set("P0_IDDOC", a._numdoc);
|
||
paf1000f.set("P0_DATADOC", a._datadoc);
|
||
paf1000f.set("P0_COMMCONVENZ", com);
|
||
paf1000f.set("P0_CODCUP", cup);
|
||
paf1000f.set("P0_CODCIG", cig);
|
||
paf1000f.set("P0_GESTIONE", "D");
|
||
paf1000f.insert();
|
||
}
|
||
}
|
||
} else
|
||
if (rdoc->is_spese())
|
||
{
|
||
const TSpesa_prest& sp = rdoc->spesa();
|
||
const real imp = rdoc->importo(true, false);
|
||
real qta = UNO;
|
||
if (sp.is_tipo())
|
||
{
|
||
paf1800f.set("PI_UNITAMISURA", rdoc->get(RDOC_UMQTA));
|
||
qta = rdoc->get_real(RDOC_QTA);
|
||
if (qta.is_zero())
|
||
{
|
||
TString msg; msg.format("La riga spese a quantit<69> %d ha quantit<69> nulla (campo %s)", riga, (const char*)rdoc->field_qta());
|
||
log(1, msg);
|
||
qta = UNO;
|
||
}
|
||
paf1800f.set("PI_QUANTITA", qta);
|
||
}
|
||
real prz = imp;
|
||
if (qta != UNO)
|
||
{
|
||
prz = rdoc->prezzo(true, false);
|
||
if (prz.is_zero() && !imp.is_zero())
|
||
{
|
||
const TPrice price(imp / qta);
|
||
prz = price.get_value();
|
||
}
|
||
}
|
||
paf1800f.set("PI_PREZZOUNIT", prz);
|
||
paf1800f.set("PI_PRZTOTALE", imp);
|
||
set_IVA(*rdoc, paf1800f);
|
||
} else
|
||
if (rdoc->is_prestazione())
|
||
{
|
||
paf1800f.set("PI_UNITAMISURA", rdoc->get(RDOC_UMQTA));
|
||
real qta = rdoc->get(RDOC_QTA); if (qta.is_zero()) qta = UNO;
|
||
paf1800f.set("PI_QUANTITA", qta);
|
||
paf1800f.set("PI_PREZZOUNIT", rdoc->prezzo(false, false));
|
||
paf1800f.set("PI_PRZTOTALE", rdoc->importo(true, false));
|
||
set_IVA(*rdoc, paf1800f);
|
||
}
|
||
|
||
paf1800f.set("PI_GESTIONE", "D");
|
||
paf1800f.insert();
|
||
}
|
||
// </DatiBeniServizi>
|
||
|
||
// <DatiRiepilogo>
|
||
TPaf_record paf2200f("PAF2200F");
|
||
paf2200f.set("PL_KEYHEADERFATT", hfatt);
|
||
paf2200f.set("PL_KEYBODYFATT", bfatt);
|
||
paf2200f.remove(); // Cancella tutte le righe di riepilogo IVA
|
||
|
||
const char* eiva = "I"; // Esigibilit<69> IVA: Immediata, Differita, Split payment
|
||
if (doc.is_split_payment())
|
||
eiva = "S"; else
|
||
if (doc.get_bool(DOC_LIQDIFF) || doc.get_bool(DOC_IVAXCASSA))
|
||
eiva = "D";
|
||
|
||
long num_riep = 0;
|
||
TAssoc_array& tiva = doc.tabella_iva(false);
|
||
FOR_EACH_ASSOC_OBJECT(tiva, obj, key, itm)
|
||
{
|
||
const TRiepilogo_iva& riva = *(const TRiepilogo_iva*)itm;
|
||
const real aliquota = riva.cod_iva().percentuale();
|
||
paf2200f.set("PL_KEYNPROGR", ++num_riep);
|
||
paf2200f.set("PL_ALIQUOTAIVA", aliquota);
|
||
if (aliquota.is_zero())
|
||
{
|
||
const TString& tipo = riva.cod_iva().tipo();
|
||
const char* natura = "N2"; // Non soggetto
|
||
if (tipo == "NI") natura = "N3"; else // Non imponibile
|
||
if (tipo == "ES") natura = "N4"; // Esente
|
||
paf2200f.set("PL_NATURA", natura);
|
||
}
|
||
paf2200f.set("PL_IMPONIBILE", riva.imponibile());
|
||
paf2200f.set("PL_IMPOSTA", riva.imposta());
|
||
paf2200f.set("PL_ESIGIVA", eiva);
|
||
paf2200f.set("PL_RIFNORMATIVO", riva.cod_iva().descrizione());
|
||
paf2200f.set("PL_GESTIONE", "D");
|
||
paf2200f.insert();
|
||
}
|
||
// </DatiRiepilogo>
|
||
|
||
// <DatiPagamento>
|
||
TPaf_record paf2400f("PAF2400F");
|
||
paf2400f.set("PN_KEYHEADERFATT", hfatt);
|
||
paf2400f.set("PN_KEYBODYFATT", bfatt);
|
||
paf2400f.remove(); // Cancella i dati pagamento
|
||
|
||
TPagamento& pag = doc.pagamento();
|
||
doc.scadenze_recalc(); // Ricalcola array delle rate
|
||
TString_array& scad = doc.scadenze();
|
||
const int nrate = scad.items(); // Conta rate generate
|
||
const char* rateazione = nrate > 1 ? "TP01" : "TP02"; // A rate (TP01) o una soluzione(TP02)?
|
||
paf2400f.set("PN_CONDPAGAMENTO", rateazione);
|
||
paf2400f.set("PN_GESTIONE", "D");
|
||
paf2400f.insert();
|
||
|
||
TPaf_record paf2500f("PAF2500F");
|
||
paf2500f.set("PO_KEYHEADERFATT", hfatt);
|
||
paf2500f.set("PO_KEYBODYFATT", bfatt);
|
||
paf2500f.remove(); // Cancella tutte le rate
|
||
|
||
// Imposto i campi uguali per tutte le rate
|
||
paf2500f.set("PO_CONDPAGAMENTO", rateazione); // Condizione di pagamento PA
|
||
paf2500f.set("PO_CODICEPAGAM", pag.code()); // Condizione di pagamento CAMPO
|
||
|
||
TString80 iban, istituto;
|
||
TString8 abi, cab;
|
||
if (get_bank(doc, iban, abi, cab, istituto))
|
||
{
|
||
paf2500f.set("PO_ISTFINANZ", istituto);
|
||
paf2500f.set("PO_IBAN", iban);
|
||
paf2500f.set("PO_ABI", abi);
|
||
paf2500f.set("PO_CAB", cab);
|
||
}
|
||
|
||
if (cab.blank())
|
||
log(2, TR("Non sono presenti ABI, CAB, IBAN per il pagamento")); else
|
||
if (iban.blank())
|
||
log(1, TR("Non <20> presente il codice IBAN per il pagamento"));
|
||
|
||
for (int nr = 0; nr < nrate; nr++)
|
||
{
|
||
paf2500f.set("PO_KEYNPROGR", long(nr+1)); // Numero rata
|
||
|
||
const char* mod_pag = "MP01"; // Modalit<69> di pagamento
|
||
const int n = nr < pag.n_rate() ? nr : 0; // Si assicura che il numero riga sia accettabile
|
||
switch (pag.tipo_rata(n))
|
||
{
|
||
case _bonfico: mod_pag = "MP05"; break; // bonifico
|
||
case _rid : mod_pag = "MP09"; break; // RID
|
||
case _ric_ban: mod_pag = "MP12"; break; // RIBA
|
||
default : mod_pag = "MP01"; break; // contanti
|
||
}
|
||
paf2500f.set("PO_MODALITAPAGAM", mod_pag);
|
||
|
||
TToken_string& riga = scad.row(nr); // Data|Importo
|
||
paf2500f.set("PO_DATASCADENZA", TDate(riga.get(0))); // Data scadenza
|
||
paf2500f.set("PO_IMPORTO", real(riga.get())); // Importo rata
|
||
|
||
paf2500f.set("PO_GESTIONE", "D");
|
||
paf2500f.insert();
|
||
}
|
||
|
||
TToken_string allegati = doc.get("COLL_GOLEM");
|
||
if (allegati.full())
|
||
{
|
||
TFilename fzip;
|
||
fzip = prefix().get_studio();
|
||
fzip.add("sql"); fzip.add("attach");
|
||
make_dir(fzip);
|
||
|
||
TString20 code = bfatt; code.replace('/', '_');
|
||
fzip.add(code); fzip << ".zip";
|
||
|
||
TFilename fname;
|
||
if (allegati.items() <= 2) // Una sola coppia (path|nome)
|
||
{
|
||
fname = allegati.get(0);
|
||
aga_zip(fname, fzip);
|
||
}
|
||
else
|
||
{
|
||
TFilename flist; flist.tempdir(); flist.add("ziplist.txt");
|
||
ofstream list(flist);
|
||
FOR_EACH_TOKEN(allegati, str)
|
||
{
|
||
fname = str;
|
||
if (fname.exist())
|
||
list << fname << endl;
|
||
}
|
||
list.close();
|
||
aga_zip_filelist(flist, fzip);
|
||
xvt_fsys_remove_file(flist);
|
||
}
|
||
|
||
TPaf_record paf2600f("PAF2600F");
|
||
paf2600f.set("PP_KEYHEADERFATT", hfatt);
|
||
paf2600f.set("PP_KEYBODYFATT", bfatt);
|
||
paf2600f.remove(); // Cancella allegati
|
||
if (fzip.exist())
|
||
{
|
||
paf2600f.set("PP_NOMEATTACHMENT", fname.name());
|
||
paf2600f.set("PP_FMTATTACHMENT", fname.ext());
|
||
paf2600f.set("PP_ATTACHMENT", fzip);
|
||
paf2600f.set("PP_COMPRESSIONE", "ZIP");
|
||
paf2600f.insert();
|
||
}
|
||
}
|
||
|
||
// </DatiPagamento>
|
||
|
||
return true;
|
||
}
|
||
|
||
bool TDoc2Paf::elabora(const TRectype& rec)
|
||
{
|
||
bool done = false;
|
||
TDocumentoEsteso doc;
|
||
if (doc.read(rec) == NOERR)
|
||
{
|
||
xvt_sql_begin(_db);
|
||
done = elabora(doc);
|
||
if (done)
|
||
xvt_sql_commit(_db);
|
||
else
|
||
xvt_sql_rollback(_db);
|
||
}
|
||
return done;
|
||
}
|
||
|
||
bool TDoc2Paf::elabora(const TDoc_key& key)
|
||
{
|
||
TRectype rec(LF_DOC);
|
||
rec.put(DOC_PROVV, key.provv());
|
||
rec.put(DOC_ANNO, key.anno());
|
||
rec.put(DOC_CODNUM, key.codnum());
|
||
rec.put(DOC_NDOC, key.ndoc());
|
||
return elabora(rec);
|
||
}
|
||
|
||
bool TDoc2Paf::elabora(const TFilename& ini)
|
||
{
|
||
TConfig cfg(ini, "33");
|
||
const int anno = cfg.get_int(DOC_ANNO);
|
||
const long ndoc = cfg.get_long(DOC_NDOC);
|
||
const TFixed_string codnum(cfg.get(DOC_CODNUM)); // lascio sapientemente per ultima la get di una stringa
|
||
const TDoc_key key(anno, codnum, ndoc);
|
||
return elabora(key);
|
||
}
|
||
|
||
|
||
bool TDoc2Paf::genera_xml()
|
||
{
|
||
#define PABASE "SiaggPA"
|
||
|
||
TFilename tmp;
|
||
|
||
// Copia eventuali protezioni software
|
||
TString_array files;
|
||
if (list_files(PABASE"/*.ssa", files) == 0)
|
||
{
|
||
list_files("*.ssa", files);
|
||
FOR_EACH_ARRAY_ROW(files, i, row)
|
||
{
|
||
tmp = PABASE; tmp.add(*row);
|
||
xvt_fsys_fupdate(*row, tmp);
|
||
}
|
||
}
|
||
files.destroy();
|
||
if (list_files(PABASE"/*.ssa", files) != 1)
|
||
warning_box(FR("Nella cartella %s deve essere presente esattamente un file .ssa"), PABASE);
|
||
|
||
TFilename home;
|
||
xvt_sys_get_env("USERPROFILE", home.get_buffer(), home.size());
|
||
home.add("SoftwareSirio"); home.add(PABASE);
|
||
if (!dexist(home))
|
||
make_dir(home);
|
||
|
||
tmp = home; tmp.add("config.properties");
|
||
xvt_fsys_fupdate(PABASE"/config.properties", tmp);
|
||
|
||
tmp = home; tmp.add("configGUI.properties");
|
||
xvt_fsys_fupdate(PABASE"/configGUI.properties", tmp);
|
||
|
||
if (tmp.exist())
|
||
{
|
||
TJava_profile prop(tmp);
|
||
prop.set("percorso", _dbname.path());
|
||
prop.set("nomePAF", _dbname);
|
||
}
|
||
else
|
||
cantread_box(tmp);
|
||
|
||
tmp = PABASE"\\SiaggPACAMPO.jar";
|
||
tmp.make_absolute_path();
|
||
|
||
DIRECTORY old_dir; xvt_fsys_get_dir(&old_dir);
|
||
DIRECTORY new_dir; xvt_fsys_convert_str_to_dir(tmp.path(), &new_dir);
|
||
xvt_fsys_set_dir(&new_dir);
|
||
const bool good = goto_url(tmp);
|
||
if (good)
|
||
xvt_sys_sleep(3000);
|
||
else
|
||
error_box(FR("Impossibile eseguire Java -jar %s"), (const char*)tmp);
|
||
xvt_fsys_set_dir(&old_dir);
|
||
|
||
return good;
|
||
}
|
||
|
||
void TDoc2Paf::main_loop()
|
||
{
|
||
int ndocs = 0;
|
||
for (int a = 1; a < argc(); a++)
|
||
{
|
||
TFilename ini = argv(a);
|
||
if (ini.starts_with("-i", true) || ini.starts_with("/i", true))
|
||
ini.ltrim(2);
|
||
if (ini.exist() && elabora(ini))
|
||
ndocs++;
|
||
else
|
||
{
|
||
if (ini.find('*') >= 0 || ini.find('?') >= 0)
|
||
{
|
||
TString_array f; list_files(ini, f);
|
||
FOR_EACH_ARRAY_ROW(f, r, row)
|
||
{
|
||
ini = *row;
|
||
if (ini.exist() && elabora(ini))
|
||
ndocs++;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
if (ndocs > 0)
|
||
{
|
||
if (show_log())
|
||
genera_xml();
|
||
return;
|
||
}
|
||
|
||
TPA_mask mask;
|
||
mask.set(F_COFI, _cofi);
|
||
while (mask.run() == K_ENTER)
|
||
{
|
||
_cofi = mask.get(F_COFI);
|
||
|
||
TString_array& sht = mask.sfield(F_DOCS).rows_array();
|
||
TProgress_monitor pi(sht.items(), NULL);
|
||
ndocs = 0;
|
||
FOR_EACH_ARRAY_ROW(sht, r, riga)
|
||
{
|
||
if (riga->starts_with("X"))
|
||
{
|
||
const int anno = riga->get_int(1);
|
||
const long ndoc = riga->get_long(3);
|
||
const TFixed_string codnum(riga->get(2)); // lascio sapientemente per ultima la get di una stringa
|
||
const TDoc_key key(anno, codnum, ndoc);
|
||
if (elabora(key))
|
||
ndocs++;
|
||
}
|
||
if (!pi.add_status(1))
|
||
break;
|
||
}
|
||
message_box(FR("Sono stati elaborati %d documenti"), ndocs);
|
||
if (ndocs > 0 && show_log())
|
||
genera_xml();
|
||
}
|
||
}
|
||
|
||
int TDoc2Paf::parse_line(const TString& line, TString& var, TString& val) const
|
||
{
|
||
if (line.blank())
|
||
return 0;
|
||
|
||
if (line[0] == '[')
|
||
{
|
||
var = line.mid(1);
|
||
var.rtrim(1);
|
||
val.cut(0);
|
||
return 1;
|
||
}
|
||
|
||
const int equal = line.find('=');
|
||
if (equal < 6)
|
||
return 0;
|
||
var = line.left(equal); var.trim();
|
||
val = line.mid(equal+1); val.trim();
|
||
return 2;
|
||
}
|
||
|
||
bool TDoc2Paf::create_table(TScanner& paf, const TString& table)
|
||
{
|
||
TString query, var, val;
|
||
if (xvt_sql_table_exists(_db, table))
|
||
{
|
||
SLIST fields = xvt_sql_list_fields(_db, table);
|
||
while (!paf.eof())
|
||
{
|
||
const TString& line = paf.line();
|
||
const int n = parse_line(line, var, val);
|
||
if (n <= 0)
|
||
break;
|
||
if (var.starts_with("INDEX_"))
|
||
break;
|
||
if (xvt_slist_find_str(fields, var) == NULL)
|
||
{
|
||
query.cut(0) << "ALTER TABLE " << table << " ADD COLUMN " << var << ' ' << val << " NOT NULL";
|
||
if (val.find("INT") >= 0 || val.find("NUM") >= 0)
|
||
query << " DEFAULT 0";
|
||
else
|
||
query << " DEFAULT ''";
|
||
query << ";";
|
||
xvt_sql_execute(_db, query, NULL, NULL); // Create table
|
||
}
|
||
}
|
||
xvt_slist_destroy(fields);
|
||
}
|
||
else
|
||
{
|
||
query << "CREATE TABLE " << table << " (";
|
||
while (!paf.eof())
|
||
{
|
||
const TString& line = paf.line();
|
||
const int n = parse_line(line, var, val);
|
||
if (n <= 0)
|
||
break;
|
||
if (n == 1)
|
||
{
|
||
paf.push(line);
|
||
break;
|
||
}
|
||
if (var.starts_with("INDEX_"))
|
||
{
|
||
query.rtrim(1); // toglie ultima ,
|
||
query << ");";
|
||
xvt_sql_execute(_db, query, NULL, NULL); // Create table
|
||
query.cut(0);
|
||
query << "CREATE UNIQUE INDEX "
|
||
<< table << "_1 ON " << table
|
||
<< " (" << val << ");";
|
||
xvt_sql_execute(_db, query, NULL, NULL); // Create index
|
||
break;
|
||
}
|
||
else
|
||
{
|
||
query << "\n " << var << ' ' << val << " NOT NULL";
|
||
if (val.find("INT") >= 0 || val.find("NUM") >= 0)
|
||
query << " DEFAULT 0";
|
||
else
|
||
query << " DEFAULT ''";
|
||
query << ",";
|
||
}
|
||
}
|
||
}
|
||
|
||
return true;
|
||
}
|
||
|
||
bool TDoc2Paf::create()
|
||
{
|
||
open_files(LF_TAB, LF_TABCOM, LF_TABMOD, LF_ANAG,
|
||
LF_CLIFO, LF_CFVEN, LF_CFBAN, LF_NDITTE,
|
||
LF_DOC, LF_RIGHEDOC, 0);
|
||
|
||
TRectype cfven(LF_CFVEN);
|
||
if (cfven.type(CFV_PARIFAMM) != _alfafld)
|
||
return error_box(TR("Database non convertito per fatturazione P.A."));
|
||
|
||
_ditta.init(LF_NDITTE, prefix().get_codditta());
|
||
|
||
_dbname = prefix().get_studio(); // base direcotry
|
||
_dbname.add("sql"); make_dir(_dbname);
|
||
TString16 d; d.format("PAF%05ld.db", prefix().get_codditta());
|
||
_dbname.add(d);
|
||
_db = xvt_sql_open(_dbname, user(), "", _dbname.path());
|
||
if (_db == NULL)
|
||
return false;
|
||
|
||
const TFilename ini = "paf.ini";
|
||
bool ok = ini.exist();
|
||
if (ok)
|
||
{
|
||
xvt_sql_begin(_db);
|
||
TScanner paf(ini);
|
||
while (ok && !paf.eof())
|
||
{
|
||
const TString& p = paf.line();
|
||
if (p.starts_with("[PA") && p.ends_with("F]"))
|
||
{
|
||
TString16 table = p; table.strip("[]");
|
||
ok = create_table(paf, table);
|
||
}
|
||
}
|
||
|
||
if (ok)
|
||
{
|
||
TPaf_record panum("PANUM00F");
|
||
panum.set("PJNKEY", "00001");
|
||
if (!panum.search())
|
||
{
|
||
panum.set("PJNINV", "0000000000");
|
||
panum.insert();
|
||
}
|
||
|
||
xvt_sql_commit(_db);
|
||
}
|
||
else
|
||
xvt_sql_rollback(_db);
|
||
}
|
||
else
|
||
return cantread_box(ini);
|
||
|
||
_cofi = ini_get_string(CONFIG_DITTA, "pa", "TRASMITTCOD");
|
||
if (_cofi.blank())
|
||
_cofi = _ditta.codice_fiscale();
|
||
|
||
return ok && TSkeleton_application::create();
|
||
}
|
||
|
||
bool TDoc2Paf::destroy()
|
||
{
|
||
if (_cofi.full())
|
||
ini_set_string(CONFIG_DITTA, "pa", "TRASMITTCOD", _cofi);
|
||
|
||
xvt_sql_close(_db); _db = NULL;
|
||
return TSkeleton_application::destroy();
|
||
}
|
||
|
||
int pa0100(int argc, char* argv[])
|
||
{
|
||
TDoc2Paf d2p;
|
||
d2p.run(argc, argv, TR("Fatturazione P.A."));
|
||
return 0;
|
||
}
|