campo-sirio/ve/velib01.cpp
guy c37ca11dcf Praticamente finita la fatturazione bolle.
git-svn-id: svn://10.65.10.50/trunk@3407 c028cbd2-c16b-5b4b-a496-9718f37d4682
1996-08-19 10:32:13 +00:00

767 lines
20 KiB
C++
Executable File

#include <tabutil.h>
#include <clifo.h>
#include "velib01.h"
///////////////////////////////////////////////////////////
// Funzioni per il calcolo dei prezzi netti/lordi
///////////////////////////////////////////////////////////
real lordo2netto(real& lordo, const TString& codiva, bool is_valuta)
{
TTable tabiva("%IVA");
real aliquota = 0.0;
tabiva.put("CODTAB", codiva);
if (tabiva.read() == NOERR) aliquota = tabiva.get_real("R0");
return lordo2netto(lordo,aliquota,is_valuta);
}
real netto2lordo(const real& netto, const TString& codiva, bool is_valuta)
{
TTable tabiva("%IVA");
real aliquota = 0.0;
tabiva.put("CODTAB", codiva);
if (tabiva.read() == NOERR) aliquota = tabiva.get_real("R0");
return netto2lordo(netto,aliquota,is_valuta);
}
real lordo2netto(real& lordo, const real& iva, bool is_valuta)
{
real netto;
real imposta = 0.0;
real imposta_rec = 0.0;
if (!iva.is_zero())
{
imposta = (lordo * iva) / (iva + 100.0); // Calcola l'imposta...
imposta.ceil(is_valuta ? 3 : 0);
}
netto = lordo - imposta; // Questo e' l'importo netto
imposta_rec = (netto * iva) / 100.0; // Ricalcola l'imposta con il nuovo imponibile
imposta_rec.ceil(is_valuta ? 3 : 0);
if (imposta != imposta_rec) // In questo caso corregge l'importo lordo
lordo = netto + imposta_rec;
return netto;
}
real netto2lordo(const real& netto, const real& iva, bool is_valuta)
{
real lordo;
real imposta = 0.0;
if (!iva.is_zero())
{
imposta = (netto * iva) / 100.0; // Calcola l'imposta
imposta.ceil(is_valuta ? 3 : 0);
}
lordo = imposta + netto; // prezzo lordo
return lordo;
}
///////////////////////////////////////////////////////////
// Tipo documento
///////////////////////////////////////////////////////////
TTipo_documento::TTipo_documento(const char* tipodoc)
: TRectype(LF_TABCOM)
{
settab("TIP");
if (tipodoc && *tipodoc)
read(tipodoc);
}
TTipo_documento::TTipo_documento(const TRectype& rec)
: TRectype(rec)
{ }
TTipo_documento::~TTipo_documento()
{
}
int TTipo_documento::read(const char* tipodoc)
{
TTable t("%TIP");
put("CODTAB", tipodoc);
int err = TRectype::read(t);
if (err != NOERR)
yesnofatal_box("Tipo documento errato: %s", tipodoc);
return err;
}
///////////////////////////////////////////////////////////
// Riga documento per vendite
///////////////////////////////////////////////////////////
bool TRiga_documento::solo_descrizione() const
{
return get("QTA").empty() && get("PREZZO").empty();
}
// Ritorna TRUE se le due righe del documento possono essere sommate
bool TRiga_documento::raggruppabile(const TRiga_documento& r, TToken_string& campi) const
{
bool ok = TRUE;
TString campo;
for (const char* c = campi.get(0); c && ok; c = campi.get())
{
campo = get(c); // Separare le due get!
ok &= campo == r.get(c);
}
return ok;
}
TRiga_documento& TRiga_documento::operator +=(const TRiga_documento& r)
{
TToken_string campi("QTA|NCOLLI|QTAEVASA|DAEVADERE");
for (const char* c = campi.get(0); c && ok; c = campi.get())
{
real num(r.get_real(c));
if (!num.is_zero())
{
num += get_real(c);
put(c, num);
}
}
if (!get_bool("RIGAEVASA"))
{
const real qta = get_real("QTA");
const real qtaeva = get_real("QTAEVASA");
if (qtaeva >= qta)
put("RIGAEVASA", "X");
}
return *this;
}
///////////////////////////////////////////////////////////
// Documento per vendite
///////////////////////////////////////////////////////////
TAssoc_array TDocumento::_tipi;
TDocumento::TDocumento()
: TRectype(LF_DOC), _rows(LF_RIGHEDOC, "NRIGA")
{
}
TDocumento::TDocumento(char provv, int anno, const char* codnum, long numdoc)
: TRectype(LF_DOC), _rows(LF_RIGHEDOC, "NRIGA")
{
if (numdoc <= 0)
{
numdoc = get_next_key(provv, anno, codnum);
set_key(*this, provv, anno, codnum, numdoc);
TRiga_documento* key = new TRiga_documento(this);
set_key(*key, provv, anno, codnum, numdoc);
_rows.set_key(key);
#ifdef DBG
TLocalisamfile doc(LF_DOC);
set_key(doc.curr(), provv, anno, codnum, numdoc);
if (doc.read() == NOERR)
yesnofatal_box("Documento gia' esistente: %c %d %s %ld", provv, anno, codnum, numdoc);
#endif
}
else
read(provv, anno, codnum, numdoc);
}
// Funzione statica utile a tutti gli utenti di LF_DOC e LF_RIGHEDOC
void TDocumento::set_key(TRectype& rec, char provv, int anno, const char* codnum, long numdoc)
{
CHECK(provv == 'D' || provv == 'P', "Provvisorio o Definitivo?");
CHECKD(anno > 1900, "Anno non valido: ", anno);
CHECK(*codnum, "Codice numerazione nullo");
CHECK(numdoc > 0, "Numero documento nullo");
rec.put("PROVV", provv);
rec.put("ANNO", anno);
rec.put("CODNUM", codnum);
rec.put("NDOC", numdoc);
}
// Funzione statica utile a tutti gli utenti di LF_DOC e LF_RIGHEDOC
void TDocumento::copy_data(TRectype& dst, const TRectype& src)
{
// Memorizza tutti i campi chiave
const char provv = dst.get_char("PROVV");
const int anno = dst.get_int("ANNO");
const TString16 codnum = dst.get("CODNUM");
const long numdoc = dst.get_long("NDOC");
const int nriga = dst.num() == LF_RIGHEDOC ? dst.get_int("NRIGA") : 0;
// Copia tutto il record
dst = src;
// Ripristina tutti i campi chiave
set_key(dst, provv, anno, codnum, numdoc);
if (nriga > 0)
dst.put("NRIGA", nriga);
}
TDocumento::TDocumento(const TRectype& rec)
: TRectype(LF_DOC), _rows(LF_RIGHEDOC, "NRIGA")
{
read(rec);
}
int TDocumento::read(const TRectype& rec)
{
head() = rec;
TRiga_documento* key = new TRiga_documento(this);
const char pr = tipo_numerazione();
const int an = anno();
const TString16 cn = numerazione();
const long nu = numero();
set_key(*key, pr, an, cn, nu);
TLocalisamfile doc(LF_DOC);
int err = TRectype::read(doc);
if (err == NOERR)
_rows.read(key);
else
{
*this = rec;
destroy_rows();
_rows.set_key(key);
}
return err;
}
int TDocumento::read(char provv, int anno, const char* codnum, long numdoc)
{
TRectype rec(LF_DOC);
set_key(rec, provv, anno, codnum, numdoc);
return read(rec);
}
int TDocumento::write(bool re) const
{
TLocalisamfile doc(LF_DOC);
int err = NOERR;
if (re)
{
err = _rows.write(re);
if (err == NOERR)
{
err = TRectype::rewrite(doc);
if (err != NOERR)
err = TRectype::write(doc);
}
}
else
{
err = TRectype::write(doc);
if (err != NOERR)
err = TRectype::rewrite(doc);
if (err == NOERR)
err = _rows.write(re);
}
return err;
}
int TDocumento::remove() const
{
TLocalisamfile doc(LF_DOC);
int err = _rows.remove();
if (err == NOERR)
err = TRectype::remove(doc);
return err;
}
const bool TDocumento::in_valuta()
{
TString16 val(valuta());
return (val.not_empty() && val != "LIT");
}
long TDocumento::get_next_key(char provv, int anno, const char* codnum) const
{
TLocalisamfile doc(LF_DOC);
TRectype& curr = doc.curr();
set_key(curr, provv, anno, codnum, 9999999L);
const int err = doc.read(_isgreat);
long n = 1;
if (err != _isemptyfile)
{
if (err == NOERR)
doc.prev();
if (curr.get_char("PROVV") == provv &&
curr.get_int("ANNO") == anno &&
curr.get("CODNUM") == codnum)
n = curr.get_long("NDOC") + 1;
}
return n;
}
const TTipo_documento& TDocumento::tipo() const
{
const TString16 tipodoc(get("TIPODOC"));
CHECK(*tipodoc, "Tipo documento nullo");
TTipo_documento * o = (TTipo_documento*)_tipi.objptr(tipodoc);
if (o == NULL)
{
o = new TTipo_documento(tipodoc);
_tipi.add(tipodoc, o);
}
return *o;
}
bool TDocumento::raggruppabile(const TDocumento& doc, TToken_string& campi) const
{
bool ok = raggruppabile() && doc.raggruppabile();
if (ok)
{
TString campo;
for (const char* c = campi.get(0); c && ok; c = campi.get())
{
campo = get(c);
ok &= campo == doc.get(c);
}
}
return ok;
}
///////////////////////////////////////////////////////////
// Lista di documenti
///////////////////////////////////////////////////////////
TDate TLista_documenti::num2date(char provv, int anno, const char* codnum, long num) const
{
TLocalisamfile doc(LF_DOC);
TDocumento::set_key(doc.curr(), provv, anno, codnum, num);
TDate d;
if (doc.read() == NOERR)
d = doc.get("DATADOC");
return d;
}
int TLista_documenti::read(char tipo, long clifo, int anno,
const TDate& dd, const TDate& ad,
const char* codnum, long dn, long an,
char provv)
{
CHECK(tipo == 'C' || tipo == 'F', "Il tipo deve essere Cliente o Fornitore");
CHECK(clifo > 0L, "Codice cliente non valido");
CHECK(provv == 'D' || provv == 'P', "Provvisorio o Definitivo?");
CHECKD(anno > 1900, "Anno non valido: ", anno);
TRelation doc(LF_DOC);
TRectype start(LF_DOC), stop(LF_DOC);
start.put("TIPOCF", tipo);
stop.put("TIPOCF", tipo);
start.put("CODCF", clifo);
stop.put("CODCF", clifo);
start.put("PROVV", provv);
stop.put("PROVV", provv);
start.put("ANNO", anno);
stop.put("ANNO", anno);
if (dn > 0)
{
start.put("DATADOC", num2date(provv, anno, codnum, dn));
start.put("NDOC", dn);
}
else
{
if (dd.ok() && dd > botime)
start.put("DATADOC", dd);
}
if (an > 0)
{
stop.put("DATADOC", num2date(provv, anno, codnum, an));
stop.put("NDOC", an);
}
else
{
if (ad.ok() && ad < eotime)
stop.put("DATADOC", ad);
}
TString filter(16);
if (codnum && *codnum)
{
bool numfilter = FALSE;
if (start.get("DATADOC").empty())
numfilter = TRUE;
else
start.put("CODNUM", codnum);
if (stop.get("DATADOC").empty())
numfilter = TRUE;
else
stop.put("CODNUM", codnum);
if (numfilter)
filter << "CODNUM=" << codnum;
}
TCursor cur(&doc, filter, 2, &start, &stop);
_documenti.destroy();
for (cur = 0; cur.ok(); ++cur)
{
TDocumento* d = new TDocumento(cur.curr());
_documenti.add(d);
}
return _documenti.items();
}
int TLista_documenti::write(bool re) const
{
int err = NOERR;
for (int i = _documenti.items()-1; i >= 0 && err == NOERR; i--)
err = doc(i).write(re);
return err;
}
///////////////////////////////////////////////////////////
// Cliente/Fornitore per vendite
///////////////////////////////////////////////////////////
void TLista_clifo::TClifo::init(const TRectype& rec, const TRectype& ven)
{
_codice = rec.get_long(CLI_CODCF);
CHECK(_codice > 0, "Codice cliente nullo");
if (!ven.empty())
{
_agente = ven.get_long(CLI_CODAG);
_zona = ven.get_long(CLI_CODZONA);
}
else
_agente = _zona = 0;
}
bool TLista_clifo::TClifo::read(char tipo, long cod)
{
TRelation clifo(LF_CLIFO);
clifo.add(LF_CFVEN, "TIPOCF=TIPOCF|CODCF=CODCF");
TRectype& curr = clifo.curr();
curr.put(CLI_TIPOCF, tipo);
curr.put(CLI_CODCF, cod);
if (clifo.read() == NOERR)
init(curr, clifo.curr(LF_CFVEN));
else
zero();
return ok();
}
TLista_clifo::TClifo::TClifo(const TRectype& rec, const TRectype& ven)
{
if (!ven.empty())
init(rec, ven);
else
{
const char tipo = rec.get_char(CLI_TIPOCF);
const long codice = rec.get_long(CLI_CODCF);
read(tipo, codice);
}
}
int TLista_clifo::leggi(long dc, long ac, long da, long aa, long dz, long az)
{
TRelation clifo(LF_CLIFO);
clifo.add(LF_CFVEN, "TIPOCF=TIPOCF|CODCF=CODCF");
TRectype start(LF_CLIFO), stop(LF_CLIFO);
start.put(CLI_TIPOCF, tipo());
if (dc > 0)
start.put(CLI_CODCF, dc);
stop.put(CLI_TIPOCF, tipo());
if (ac > 0)
stop.put(CLI_CODCF, ac);
TString filter(32);
if (da > 0)
filter << '(' << LF_CFVEN << "->" << CLI_CODAG << ">=" << da << ')';
if (aa > 0)
{
if (filter.not_empty()) filter << "&&";
filter << '(' << LF_CFVEN << "->" << CLI_CODAG << "<=" << aa << ')';
}
if (dz > 0)
{
if (filter.not_empty()) filter << "&&";
filter << '(' << LF_CFVEN << "->" << CLI_CODZONA << ">=" << dz << ')';
}
if (az > 0)
{
if (filter.not_empty()) filter << "&&";
filter << '(' << LF_CFVEN << "->" << CLI_CODZONA << "<=" << az << ')';
}
TCursor cur(&clifo, filter, 1, &start, &stop);
for (cur = 0; cur.ok(); ++cur)
{
TClifo* c = new TClifo(cur.curr(), cur.curr(LF_CFVEN));
_clifo.add(c);
}
if (dc > 0 || ac > 0) ordina_per_codice(); else
if (da > 0 || aa > 0) ordina_per_agente(); else
if (dz > 0 || az > 0) ordina_per_zona();
return _clifo.items();
}
int TLista_clifo::sort_by_code(const TObject** o1, const TObject** o2)
{
TLista_clifo::TClifo* c1 = (TLista_clifo::TClifo*)*o1;
TLista_clifo::TClifo* c2 = (TLista_clifo::TClifo*)*o2;
const long d = c1->codice() - c2->codice();
return d == 0L ? 0 : (d > 0 ? +1 : -1);
}
int TLista_clifo::sort_by_agent(const TObject** o1, const TObject** o2)
{
TLista_clifo::TClifo* c1 = (TLista_clifo::TClifo*)*o1;
TLista_clifo::TClifo* c2 = (TLista_clifo::TClifo*)*o2;
const long d = c1->agente() - c2->agente();
return d == 0L ? 0 : (d > 0 ? +1 : -1);
}
int TLista_clifo::sort_by_zone(const TObject** o1, const TObject** o2)
{
TLista_clifo::TClifo* c1 = (TLista_clifo::TClifo*)*o1;
TLista_clifo::TClifo* c2 = (TLista_clifo::TClifo*)*o2;
const long d = c1->zona() - c2->zona();
return d == 0L ? 0 : (d > 0 ? +1 : -1);
}
int TLista_clifo::ordina_per_codice()
{
_clifo.sort(sort_by_code);
return _clifo.items();
}
int TLista_clifo::ordina_per_agente()
{
_clifo.sort(sort_by_agent);
return _clifo.items();
}
int TLista_clifo::ordina_per_zona()
{
_clifo.sort(sort_by_zone);
return _clifo.items();
}
int TLista_clifo::find(long cod) const
{
for (int i = items()-1; i >= 0; i--)
if (clifo(i).codice() == cod) break;
return i;
}
int TLista_clifo::add(long cod)
{
int pos = find(cod);
if (pos < 0)
{
TClifo* c = new TClifo(tipo(), cod);
pos = _clifo.add(c);
}
return pos;
}
///////////////////////////////////////////////////////////
// TElaborazione
///////////////////////////////////////////////////////////
TElaborazione::TElaborazione(const char* cod) : TRectype(LF_TABCOM)
{
settab("ELD");
if (cod && *cod)
read(cod);
}
int TElaborazione::read(const char* cod)
{
CHECK(cod && *cod, "Codice elaborazione nullo");
TTable eld("%ELD");
put("CODTAB", cod);
const int err = TRectype::read(eld);
if (err != NOERR)
yesnofatal_box("Codice elaborazione non valido: %s", cod);
return err;
}
///////////////////////////////////////////////////////////
// TFatturazione bolle
///////////////////////////////////////////////////////////
bool TFatturazione_bolle::raggruppa(TDocumento& doc_in, TDocumento& doc_out)
{
#ifdef DBG
const TString tipi = get("S2");
const TString& tipodoc = doc_in.tipo().codice();
for (int i = 0; i < 5; i++)
{
if (tipodoc == tipi.mid(i*4, 4))
break;
}
if (i >= 5)
{
yesnofatal_box("Tipo documento non valido: ", (const char*)tipodoc);
return FALSE;
}
#endif
const char stato_finale_in = get_char("S4");
doc_in.stato(stato_finale_in);
const TString& tipo_out = get("S8");
doc_out.put("TIPODOC", tipo_out);
const char stato_finale_out = get_char("S9");
doc_out.stato(stato_finale_out);
if (gestione_riferimenti())
{
// Determina ed eventualmente crea la riga di riferimento
const int riga_rif = riferimenti_in_testa() ? 1 : doc_out.rows()+1;
if (riga_rif > doc_out.rows())
doc_out.new_row();
TRiga_documento& rout = doc_out[riga_rif];
// Costruisce la stringa di riferimento
TString riferimento(80);
riferimento = doc_in.tipo().riferimento();
if (riferimento.empty())
riferimento = doc_in.tipo().descrizione();
riferimento << " n. " << doc_in.numero();
riferimento << " del " << doc_in.data().string();
// Setta la descrizione se vuota
if (rout.get("DESCR").empty())
rout.put("DESCR", riferimento);
else
{
// Altrimenti aggiungi il riferimento al memo
TString memo(1024);
memo = rout.get("DESCEST");
if (memo.empty())
rout.put("DESCLUNGA", "X");
else
memo << '\n';
memo << riferimento;
rout.put("DESCEST", memo);
}
}
const bool ignora_desc = ignora_descrizioni();
TToken_string campi_riga(80);
const bool ragg_rig = raggruppa_righe();
if (ragg_rig)
{
campi_riga = "CODART|UMQTA"; // Uguali sempre
// Uguali opzionalmente
if (riga_uguale(0)) campi_riga.add("CODMAG");
if (riga_uguale(1)) campi_riga.add("CODIVA");
if (riga_uguale(2)) campi_riga.add("PREZZO|SCONTO");
}
for (int r = 1; r <= doc_in.rows(); r++)
{
const TRiga_documento& rin = doc_in[r];
const bool rindesc = rin.solo_descrizione(); // La riga di input e' descrittiva
if (ignora_desc && rindesc)
continue;
bool elaborata = FALSE;
// Raggruppo le righe se e' settato il falg di raggruppamento e
// se la riga non contiene solo una descrizione
if (ragg_rig && !rindesc) // Se devo raggruppare le righe ...
{
const int last = doc_out.rows();
for (int o = 1; o <= last; o++) // ... cerca una riga compatibile
{
TRiga_documento& rout = doc_out[o];
if (rout.solo_descrizione()) // Ignora le righe descrittive
continue;
if (rin.raggruppabile(rout, campi_riga)) // Se esiste una riga compatibile ...
{
rout += rin; // ... sommaci la quantita' ecc.
elaborata = TRUE; // Ricorda di averla gia' elaborata
break;
}
}
}
if (!elaborata) // Se la riga non e' stata gia' sommata ...
{
TRiga_documento& rout = doc_out.new_row(); // ... crea una riga nuova e ...
doc_out.copy_data(rout, rin); // ... copiaci tutti i campi della riga sorgente.
}
}
return TRUE;
}
bool TFatturazione_bolle::elabora(TLista_documenti& doc_in, TLista_documenti& doc_out,
const TDate& data_elab)
{
bool ok = TRUE;
TToken_string campi_doc(128); // Lista di campi che devono essere uguali
campi_doc = "TIPOCF|CODCF|CODVAL|CODLIN"; // Uguali sempre
// Uguali opzionalmente
const char* cond[] = { "CAMBIO", "SCONTO", "TIPODOC", "CODNUM",
"CODPAG", "CODABIA|CODCABA", "CODLIST", "CODAG",
"CODSPMEZZO", "CODPORTO", "CAUSTRASP", "CODVETT1|CODVETT2|CODVETT3",
NULL };
for (int u = 0; cond[u]; u++)
if (doc_uguale(u)) campi_doc.add(cond[u]);
for (int id = 0; id < doc_in.items() && ok; id++)
{
TDocumento& campione = doc_in[id];
const int tot = doc_out.items();
int od = tot;
if (campione.raggruppabile()) // Se il documento ha il flag di raggruppabilita' ...
{
for (od = 0; od < tot; od++) // ... cerca un documento compatibile.
{
if (campione.raggruppabile(doc_out[od], campi_doc))
break;
}
}
if (od >= tot) // Se non ho trovato un documento compatibile ...
{ // ... creane uno nuovo (certamente compatibile)
const char provv = tipo_numerazione();
const int anno = campione.anno();
const TString codnum = codice_numerazione_finale();
TDocumento* new_doc = new TDocumento(provv, anno, codnum, -1);
// Copia i dati della testata
TDocumento::copy_data(new_doc->head(), campione.head());
new_doc->put("DATADOC", data_elab);
// Aggiungilo alla lista dei documenti in uscita
od = doc_out.add(new_doc);
}
ok = raggruppa(campione, doc_out[od]);
}
return ok;
}