campo-sirio/db/db1100.cpp
alex d0ab8cc457 Patch level :
Files correlati     :
Ricompilazione Demo : [ ]
Commento            : riportata la versione 98.01.05 patch 34


git-svn-id: svn://10.65.10.50/trunk@7409 c028cbd2-c16b-5b4b-a496-9718f37d4682
1998-11-04 18:04:26 +00:00

1240 lines
39 KiB
C++
Executable File

// Stampa esplosione distinte
// Ma ke freddo fa!?
// ...
// & God took away Ish 2 create Isha
// Warning: TAssoc_array heavily used in this App
// ...
// Señor... donde esta El Jefe!?
// Ola! Estrella querida... Yo soy El Jefe!
#include <applicat.h>
#include <form.h>
#include <mask.h>
#include <printer.h>
#include <progind.h>
#include <sheet.h>
#include <tabutil.h>
#include "../cg/cglib01.h"
#include "../mg/mglib.h"
#include "../ve/velib.h"
#include "dblib.h"
#include <doc.h>
#include <rdoc.h>
#include "../mg/anamag.h"
#include "db1100a.h"
#define DIST_HEAD 0
/////////////////////////////////////////////////////////
// Inizio ammenicoli di supporto
/////////////////////////////////////////////////////////
enum seltype { by_num, by_date };
enum expltype { mat_base, scalare};
enum valtype { no_val, last_cost, average_cost, pond_cost, last2cost, std_cost, LIFO_annuale, LIFO_storico, FIFO_annuale, FIFO_storico };
enum grptype { no_grp, first_um, ref_um, normal_um };
struct _ParmStruct
{
seltype _selections;
expltype _explosion;
valtype _valorization;
grptype _group_by;
TString16 _anno_es, _from_num, _to_num, _sl_mag, _mb_mag; // Ma perche'...
TDate _from_date, _to_date, _obs_date;
long _from_doc, _to_doc;
int _year, _periods, _det_lev, _ordering;
bool _last_qta, _vis_art, _vis_lav, _vis_vir, _fabbisogno,
_val_magmb, _val_depmb, _cfr_scmin, _separate_dists;
};
struct _CallBackStruct
{
_ParmStruct* _p;
TAssoc_array* _a;
} ;
static TString __key;
static TDate __current_period;
///////////////////////////////////////////////////////////
// TArticolo_giacenza_static
///////////////////////////////////////////////////////////
//
// Particolarita' della classe: il metodo "vero" per calcolare
// la disponibilita' viene chiamato solo la prima volta, poi viene sempre
// tenuto in memoria per eventuali aggiornamenti sulle qta, in modo
// da non fare cazzilli pocciosi sul file delle giacenza
class TArticolo_giacenza_static : public TArticolo_giacenza
{
bool _calc;
real _disp; // Disponibilita': sempre espressa in UM base!!
// Prima di effettuare addizioni/sottrazioni ricordarsi di convertire
public:
const real get_scmin(const char * annoes, const char * codmag, const char * livello);
real& static_disp(const char * annoes, const char * codmag, const char * livello, bool solo_giac=FALSE);
TArticolo_giacenza_static(const char* codice = NULL);
TArticolo_giacenza_static(const TRectype& rec);
virtual ~TArticolo_giacenza_static() {}
};
TArticolo_giacenza_static::TArticolo_giacenza_static(const char* codice)
: TArticolo_giacenza(codice), _calc(FALSE)
{
}
TArticolo_giacenza_static::TArticolo_giacenza_static(const TRectype& rec)
: TArticolo_giacenza(rec), _calc(FALSE)
{
}
const real TArticolo_giacenza_static::get_scmin(const char * annoes, const char * codmag, const char * livello)
{
real r;
const int i = find_mag(annoes, codmag, livello);
if (i > 0)
{
TRecord_array& ra = mag(annoes);
r = ra[i].get_real("SCORTAMIN");
}
return r;
}
real& TArticolo_giacenza_static::static_disp(const char * annoes, const char * codmag, const char * livello, bool solo_giac)
{
if (!_calc)
{
_calc =TRUE;
_disp = disponibilita(annoes, codmag, livello, solo_giac);
}
return _disp;
}
///////////////////////////////////////////////////////////
// TArticolo_cache
///////////////////////////////////////////////////////////
class TArticolo_cache : public TRecord_cache
{
protected:
virtual TObject* rec2obj(const TRectype& rec) const;
public:
TArticolo_giacenza_static& art(const char* key);
TArticolo_cache();
virtual ~TArticolo_cache() { }
};
TArticolo_cache::TArticolo_cache()
: TRecord_cache(LF_ANAMAG, 1)
{ }
TObject* TArticolo_cache::rec2obj(const TRectype& curr) const
{
return new TArticolo_giacenza_static(curr);
}
TArticolo_giacenza_static& TArticolo_cache::art(const char* key)
{
TArticolo_giacenza_static& art = (TArticolo_giacenza_static&)query(key);
return art;
}
///////////////////////////////////////////////////////////
// TRiga_esplosione2print
///////////////////////////////////////////////////////////
class TRiga_esplosione2print : public TRiga_esplosione
{
real _fabbisogno;
real _disponibilita;
real _qta2order;
real _value;
real _residuo;
public:
const real& fabbisogno() { return _fabbisogno; }
const real& disponibilita() { return _disponibilita; }
const real& qta2order() { return _qta2order; }
const real& value() { return _value; }
const real& residuo() { return _residuo; }
void set_fabbisogno(const real& r) { _fabbisogno = r; }
void set_disponibilita(const real& r) { _disponibilita = r; }
void set_qta2order(const real& r) { _qta2order = r; }
void set_value(const real& r) { _value = r; }
void set_residuo(const real& r) { _residuo = r; }
TRiga_esplosione2print() {};
TRiga_esplosione2print(const TDistinta_tree& tree,
const TExplosion_params& ep);
TRiga_esplosione2print(const TRiga_esplosione& re);
~TRiga_esplosione2print() {};
};
TRiga_esplosione2print::TRiga_esplosione2print(const TDistinta_tree& tree, const TExplosion_params& ep)
: TRiga_esplosione(tree, ep)
{
}
TRiga_esplosione2print::TRiga_esplosione2print(const TRiga_esplosione& re)
: TRiga_esplosione(re)
{
}
///////////////////////////////////////////////////////////
// _Dist2Explode
///////////////////////////////////////////////////////////
class _Dist2Explode : public TObject
{
TCodice_articolo _cod;
TString16 _livgiac;
TCodice_um _um;
TString16 _mag;
real _qta;
TDate _datacons;
TDate _data_per; // Data limite del periodo del quale fa parte questa distinta da esplodere
bool _acq_ven;
public:
TRiga_esplosione* head_obj();
void set(const TRiga_documento& r);
void set(TToken_string& t);
void set_cod(const char* c) { _cod = c; }
void set_liv(const char* l) { _livgiac = l;}
void set_mag(const char* m) { _mag = m;}
void set_um (const char* u) { _um = u;}
void set_qta(const real& q) { _qta = q;}
void set_datacons(const TDate& d) { _datacons = d; }
void set_acq(const bool b) { _acq_ven = b; }
real& qta() { return _qta;}
const TDate& datacons() { return _datacons;}
const TDate& data_per() { return _data_per;}
const bool& acqven() { return _acq_ven; }
const TString& mag() { return _mag; }
const TCodice_um& um() { return _um; }
const TString& liv() { return _livgiac; }
const TCodice_articolo& cod() { return _cod; }
const char * key();
_Dist2Explode () {};
virtual ~_Dist2Explode() {};
};
///////////////////////////////////////////////////////////
// TExplode_distinta_form
///////////////////////////////////////////////////////////
class TExplode_distinta_form : public TForm
{
static TExplode_distinta_form *_f; // Yes, I am THIS.
TDistinta_tree _distinta; // Albero della distinta
TArticolo_cache _art_cache; // Cache di articoli con disponibilita
TArray _exploded_tree; // Righe di eplosione
TAssoc_array _valori; // Righe dei valori dei nodi e delle foglie
TAssoc_array _residui; // Righe dei residui (solo semilavorati/nodi)
_Dist2Explode *_d; // Distinta corrente da esplodere
_ParmStruct *_p; // Struttura dei parametri
int _curr_row; // Riga corrente della distinta esplosa da stampare
protected:
void print_header(TPrinter& p);
void print_footer(TPrinter& p);
static void dist_header_handler(TPrinter& p);
static void dist_footer_handler(TPrinter& p);
virtual bool validate(TForm_item &, TToken_string &);
void set_explosion_rows(TArray& exp_array);
real res2produce_by_father(TRiga_esplosione& re);
public:
void set_distinta(_Dist2Explode* dd) { _d = dd; }
void set_parameters(_ParmStruct* ps);
void print();
void reset_cache() { _art_cache.destroy(); }
TExplode_distinta_form(const char *);
virtual ~TExplode_distinta_form();
};
TExplode_distinta_form* TExplode_distinta_form::_f = NULL;
///////////////////////////////////////////////////////////////////
// Callback & funzione per valorizzazione nodi
///////////////////////////////////////////////////////////////////
static real valorizza(const TRiga_esplosione& re, const _CallBackStruct* c)
{
CHECK(c, "Invalid parameter struct passed");
real total;
TString80 dis(re.articolo());
TString16 liv(re.giacenza());
if (dis.not_empty())
{
TAssoc_array* valori = c->_a;
_ParmStruct * pp = c->_p;
TString80 cod(dis);
if (liv.not_empty())
cod << ',' << liv;
real* val = (real*)valori->objptr(cod);
if (val == NULL)
{
const char tipo = re.tipo();
switch (tipo)
{
case 'A':
{
TArticolo_giacenza art(dis);
TString& annoes = pp->_anno_es;
TString16 codmag;
if (pp->_val_magmb) // Se non c'e' _val_magmb non c'e' nemmeno _val_depmb
{ // Quindi codmag rimane a zero e la valorizzazione viene fatta su tutti i mag.
codmag = pp->_mb_mag;
if (!pp->_val_depmb && codmag.len() > 3)
codmag.cut(3); // se non deve valorizzare sul deposito lo accorciamo
}
switch (pp->_valorization)
{
case last_cost: total = art.ultimo_costo(annoes); break;
case last2cost: total = art.media_costi(annoes); break;
case std_cost: total = art.costo_standard(annoes); break;
case average_cost: total = art.costo_medio(annoes, codmag, liv); break;
case pond_cost: total = art.costo_mediopond(annoes, codmag, liv); break;
case LIFO_annuale: total = art.LIFO_annuale(annoes, codmag, liv); break;
case FIFO_annuale: total = art.FIFO_annuale(annoes, codmag, liv); break;
case LIFO_storico: total = art.LIFO(annoes, codmag, liv); break;
case FIFO_storico: total = art.FIFO(annoes, codmag, liv); break;
default: NFCHECK("Tipo valorizzazione errato: %d", pp->_valorization);
}
}
break;
case 'L':
{
TDecoder val("LAV", "R0");
total = real(val.decode(dis));
}
break;
case 'V':
{
TDecoder dist(LF_DIST, "PREZZO");
total = real(dist.decode(dis));
}
break;
default :
NFCHECK("L'articolo %s non esiste", (const char*)dis);
}
valori->add(cod, total);
}
else
total = *val;
}
return total;
}
static bool valorizza_nodo(TTree& node, void* jolly, word when)
{
if (when == SCAN_PRE_ORDER)
{
TArray exploded;
TToken_string __path;
_CallBackStruct* c = (_CallBackStruct*) jolly;
TAssoc_array* valori = c->_a;
TDistinta_tree& dist_node = (TDistinta_tree&) node;
dist_node.curr_id(__path);
if (dist_node.goto_firstson())
{
dist_node.explode(exploded, TRUE, 2);
dist_node.goto_node(__path);
const int items = exploded.items(); // Se 0 siamo su di una foglia...
real totale; // Somma dei valori di tutti i materiali di base sottostanti
for (int i = 0; i < items; i++)
{
TRiga_esplosione& re = (TRiga_esplosione&) exploded[i];
// Valore per questa riga (NB si sta calcolando il valore unitario dei componenti di UNA distinta)
// ed intanto memorizza i valori dei singoli materiali di base in cache
// Per i materiali di base si memorizza soltanto il cod.articolo+liv.giac
totale += re.val() * valorizza(re, c);
}
// Memorizza nell'array il valore di questo nodo memorizzato in total
// La chiave per questo nodo e' tutto il path dalla radice...(comprensivo di livello di gaicenza)
real* val = (real*)valori->objptr(__path);
if (val == NULL)
valori->add(__path, totale);
}
}
return FALSE;
}
/////////////////////////////////////////////////////////////
// Implementazione metodi di TExplode_distinta_form
/////////////////////////////////////////////////////////////
TExplode_distinta_form::TExplode_distinta_form(const char * n) : TForm(n)
{
_d = NULL;
_p = NULL;
_f = this;
TPrinter& pr = printer();
pr.setheaderhandler(dist_header_handler);
TPrint_section& head = section('H');
pr.headerlen(head.height());
pr.setfooterhandler(dist_footer_handler);
const TPrint_section& foot = section('F');
pr.footerlen(foot.height());
}
TExplode_distinta_form::~TExplode_distinta_form()
{
}
void TExplode_distinta_form::set_parameters(_ParmStruct* ps)
{
_p = ps;
// Accende o spegne le colonne a seconda di stampa disponibilita/valorizzazione
for (short i = 7; i<=9; i++)
find_field('B',odd_page,i).enable(_p->_fabbisogno); // Colonne disponibilita...
find_field('B',odd_page,10).enable(_p->_valorization != no_val);
}
void TExplode_distinta_form::print_header(TPrinter& pr)
{
TPrint_section& head = section('H');
head.update();
const word r = head.height()-1;
for (word j = 0; j <= r; j++)
pr.setheaderline(j, head.row(j));
}
void TExplode_distinta_form::print_footer(TPrinter& pr)
{
const bool p = page(pr)>0;
TPrint_section& foot = section('F',p ? odd_page : last_page);
foot.update();
word r = foot.height();
for (word j = 0; j < r; j++)
pr.setfooterline(j, foot.row(j));
}
void TExplode_distinta_form::dist_header_handler(TPrinter& pr)
{
pr.resetheader();
_f->print_header(pr);
}
void TExplode_distinta_form::dist_footer_handler(TPrinter& pr)
{
pr.resetfooter();
_f->print_footer(pr);
}
bool TExplode_distinta_form::validate(TForm_item &f, TToken_string &t)
{
const TString subcommand(t.get(0)); // Sub-comandante Marcos
const TString code(t.get(1)); // codice del messaggio
TString valore;
TRiga_esplosione2print& re = (TRiga_esplosione2print&) _exploded_tree[_curr_row];
const char tipo = re.tipo();
if (subcommand != "_DISTINTA")
return TForm::validate(f, t);
if (code == "_COD")
{
if (_curr_row == DIST_HEAD)
valore = "@B";
valore << re.articolo();
}
else
if (code == "_DES")
{
const TRelation* rel = relation();
switch (tipo)
{
case 'A':
{
TLocalisamfile& anamag = rel->lfile(LF_ANAMAG);
anamag.put(ANAMAG_CODART, re.articolo());
if (anamag.read() == NOERR)
valore = anamag.get(ANAMAG_DESCR);
break;
}
case 'L':
{
TTable& lav = (TTable&) rel->lfile("LAV");
lav.put("CODTAB", re.articolo());
if (lav.read() == NOERR)
valore = lav.get("S0");
break;
}
case 'V':
{
TLocalisamfile& dist = rel->lfile();
dist.put("CODDIST", re.articolo());
if (dist.read() == NOERR)
valore = dist.get("DESCR");
break;
}
default:
break;
}
}
else
if (code == "_LIV")
{
if (re.livello() > 0)
valore << re.livello();
}
else
if (code == "_DCO")
{
if (_curr_row == DIST_HEAD)
valore = _d->datacons();
}
else
if (code == "_UM")
{
valore = re.um();
}
else
if (code == "_FAB")
{
valore = re.fabbisogno().string();
}
else
if (code == "_DIS")
{
valore = re.disponibilita().string();
}
else
if (code == "_ORDPROD")
{
valore = re.qta2order().string();
}
else
if (code == "_RESIDUO")
{
valore = re.residuo().string();
}
else
if (code == "_VALORE")
{
valore = re.value().string();
}
f.set(valore);
return TRUE;
}
real TExplode_distinta_form::res2produce_by_father(TRiga_esplosione& re)
{
real r;
TString k;
if (!_p->_fabbisogno) // Se non e' abilitata il calcolo del fabbisogno/disponibilita
r = _d->qta(); // ritorna la qta della distinta come residuo da produrre
else
{
// Se sta esaminando la riga della "radice"
// ritorna la qta richiesta, altrimenti se si tratta di esplosione ai mat.base
// ritorna il residuo da produrre per la distinta "radice".
// Se l'esplosione e' scalare ritorna il residuo del padre di questo nodo.
if (re.livello() == 0)
r = _d->qta();
else
{
TToken_string& tt = (TToken_string&) re.path();
real * rs = (real*) _residui.objptr(_p->_explosion == mat_base ? tt.get(0) : re.father());
r = rs != NULL ? *rs : ZERO; // Se er padre non ha residui... smette de fatica'
}
}
return r;
}
void TExplode_distinta_form::set_explosion_rows(TArray& exp_array)
{
const int rows = exp_array.items();
real r;
TString k;
for (int i = 0; i < rows; i++)
{
TRiga_esplosione& re = (TRiga_esplosione&) exp_array[i];
const char tipo = re.tipo();
const bool is_head = i == DIST_HEAD;
// Il fabbisogno e': nr. componenti di questo articolo per residuo da produrre del padre
//r = re.val() * _d->qta(); // In UM locale...
r = re.val() * res2produce_by_father(re); // In UM locale...
if (r == ZERO)
continue; // Don't store in _exploded_tree if there's no need
TRiga_esplosione2print* r2p = new TRiga_esplosione2print(re);
r2p->set_fabbisogno(r);
if (tipo != 'A') // Distinte Virtuali e Lavorazioni non hanno disponibilita', quindi sono sempre da produrre
{
r2p->set_qta2order(r);
if (tipo == 'V')
_residui.add(re.path(), r); // Memorizza nei residui...
}
// Se si tratta dell'articolo distinta da esplodere, calcola la disponibilita'
// prendendo il magazzino indicato sulla riga stessa
// Se invece e' un componente, prende cio' che e' stato indicato dall'utente per quanto
// riguarda se e' materiale di base o semilavorato
// Il livello di giacenza lo si prende dall'articolo distinta da esplodere
// oppure dalla riga esplosione se non stiamo stampando la testata della distinta
// il cod. esercizio e' calc. come sempre
const TString& codmag = is_head ? _d->mag() : re.mat_base() ? (const TString&)_p->_mb_mag : (const TString&)_p->_sl_mag;
const TString& liv = is_head ? _d->liv() : re.giacenza();
// Compone la chiave da cercare nella cache: CODART|CODMAG|LIVELLO
// ovvio che tutti i campi debbono essre paddati alla loro massima lunghezza
// Al TArticolo_cache importa solo del CODART in ricerca... i campi seguenti vengono ignorati
// anche se nel TAssoc_array interno vengono cmq memorizzati come chiave
__key.format("%-20s|%-15s|%-5s", (const char*)re.articolo(), (const char*) liv, (const char*) codmag);
TArticolo_giacenza_static& aaa = _art_cache.art(__key);
if (tipo == 'A') // Disponibilita, qta da ordinare e residuo vengono calcolati solo per le righe Articolo
{
// Si ricorda che la disponibilita' e' calcolata in UM base!!
// Quindi e' opportuno effettuare la conversione nell'unita' di misura
// del presente articolo....
const real zero_ref = _p->_cfr_scmin ? aaa.get_scmin(_p->_anno_es, codmag, liv) : ZERO;
real& disp = aaa.static_disp(_p->_anno_es, codmag, liv);
// Converte in UM della riga corrente
r = aaa.convert_to_um(disp, re.um());
r2p->set_disponibilita(r);
// Riconverto la qta di fabbisogno in UM base per aggiornare
// la disponibilita.
// cfr. _d->_acq_ven
//r = re.convert_in_base() * _d->qta(); // Fabbisogno unitario in UM base
r = r2p->fabbisogno() * re.conv(); // Sempre in UM base...
// Mmmmmmmhhhhhhh...
if (_d->acqven())
disp += r;
else
disp -= r;
if (disp < zero_ref)
{
r = zero_ref - disp;
r2p->set_qta2order(aaa.convert_to_um(r, re.um())); // In UM locale...
if (!re.mat_base())
_residui.add(re.path(), r);
}
if (disp > zero_ref)
{
r = disp - zero_ref;
r2p->set_residuo(aaa.convert_to_um(r, re.um())); // In UM locale...
}
if (disp < zero_ref) // Se la disponibilita' va sotto il riferimento... azzera
disp = zero_ref;
}
// Il valore lo calcola per qualsiasi tipo riga
if (_p->_valorization > no_val)
{
if (re.mat_base())
{
k = re.articolo();
if (re.giacenza().not_empty())
k << "," << re.giacenza();
}
else
k = re.path(); // I nodi sono cachati con tutto il path in modo da essere univoci
// Se l'utente non vuole la valorizzazione sul calcolo
// disponibilita', stampa quella sul fabbisogno richiesto
const real& qta = !(tipo == 'A' && _p->_fabbisogno) ? re.val() * _d->qta() : r2p->qta2order();
CHECK(_valori.objptr(k),"Perke' mi ritrovo senza un elemento nella cache dei valori?!?!?");
r = *(real*)_valori.objptr(k);
r *= qta;
r2p->set_value(r);
}
_exploded_tree.add(r2p);
}
}
void TExplode_distinta_form::print()
{
// Explode & deflagrate...
if (!_distinta.set_root(_d->cod()))
return;
// Inizializza lo sfondo delle pagine normali se no col piffero che stampa la fincatura...
set_background(3, TRUE);
_distinta.restart();
if (_distinta.goto_root())
{
TArray explosion_array;
TPrintrow p;
TString16 fi;
// Reset...
_exploded_tree.destroy();
_valori.destroy();
_residui.destroy();
if (_p->_vis_art) fi << 'A';
if (_p->_vis_lav) fi << 'L';
if (_p->_vis_vir) fi << 'V';
if (fi.len() == 3) fi.cut(0);
_distinta.curr_code((TCodice_articolo& )_d->cod());
_distinta.explode(explosion_array, _p->_explosion == mat_base, _p->_group_by,
_p->_det_lev, fi, _p->_ordering, _p->_last_qta);
// Dopo l'esplosione mette in testa all'array la riga di definizione della Distinta stessa:
// codice + UM + Fabbisogno (sostanzialmente si tratta di un TRiga_esplosione)
explosion_array.insert(_d->head_obj(), 0);
// Effettua la valorizzazione scorrendo i nodi...
if (_p->_valorization > no_val)
{
_CallBackStruct setter; // many, many dog races exists...
// I know this is kinda dog-programming
setter._p = _p; // but it seems quite reasonable setting a couple
setter._a = &_valori; // of pointers and passing'em in a struct
_distinta.set_root(_d->cod());
_distinta.scan_depth_first(valorizza_nodo, &setter);
}
// Ora scorre l'array locale delle righe esplosione, settando quello
// vero (_exploded_tree) con le TRiga_esplosione2print necessarie
// ed i valori corretti (fabbisogno, disponibilita, residuo, da ordinare e valore)
set_explosion_rows(explosion_array);
const int righe = _exploded_tree.items();
TPrint_section& body = section('B');
TPrinter& pr = printer();
// Setta pure la data sul form item di testa...
// Se e' cambiato il periodo effettua un form feed di separazione
TPrint_section& head = section('H');
head.find_field(4).set(_d->data_per());
// Ad ogni cambio periodo effettua un formfeed...
// Be careful: evitare di stampare doppio form feed di separazione in caso
// di Separa distinte e cambio periodo contemporaneamente
if (!_p->_separate_dists && __current_period.ok() && _d->data_per() > __current_period)
pr.formfeed();
__current_period = _d->data_per();
set_last_page(FALSE);
// This is GoodStuff... browse all rows & print'em
for (_curr_row=0; _curr_row<righe; _curr_row++)
{
if (pr.rows_left() <= (body.height()+1))
pr.formfeed();
body.update();
const word h = body.height();
for (word j = 0; j < h; j++)
pr.print(body.row(j));
}
set_last_page(TRUE);
// form feed su opzione parametro...
if (_p->_separate_dists)
pr.formfeed();
else // Altrimenti aggiunge una riga mezza ciucciata...
pr.print(p);
}
else
error_box("Impossibile leggere l'albero relativo alla distinta %s. Controllarne la definizione.", (const char*) _d->cod());
return ;
}
///////////////////////////////////////////////////////////
// TEsplosione_distinta_app
///////////////////////////////////////////////////////////
class TEsplosione_distinta_app : public TSkeleton_application
{
TMask *_mask;
TDocumento *_doc;
TExplode_distinta_form
*_form;
TAssoc_array _dist_list;
TArray _date_array;
TArray _file;
TCodgiac_livelli
*_liv_giac;
// Dati "i/n/m/putati" ma non ancora condannati...
_ParmStruct _parameters;
protected:
static bool sheet_notify(TSheet_field& s, int r, KEY key);
void open_files(int logicnum, ...);
virtual bool create();
virtual bool destroy();
virtual void main_loop();
static bool check_articoli(TMask_field& f, KEY k);
void compile_list();
void compile_periods();
virtual void print();
public:
const int date2period(const TDate&);
const TDate& date_period(const TDate&);
TEsplosione_distinta_app() {};
virtual ~TEsplosione_distinta_app() {};
};
inline TEsplosione_distinta_app& app() { return (TEsplosione_distinta_app&) main_app(); }
///////////////////////////////////////////////////////////
// _Dist2Explode
// Generic Minkiatell used...
///////////////////////////////////////////////////////////
//
// Implementation of base object used in skantacazz 2 be stored in a TAssoc_array so we can order it
//
TRiga_esplosione * _Dist2Explode::head_obj()
{
TRiga_esplosione * re = new TRiga_esplosione;
re->set(_cod, _um, real(1.00));
re->set_tipo('A'); // La testata e' cmq un articolo... disse Zorba Il Greco a Sinuhe L'Egiziano
re->set_path(_cod);
return re;
}
void _Dist2Explode::set(const TRiga_documento& r)
{
_cod = r.get(RDOC_CODART);
_livgiac = r.get(RDOC_LIVELLO);
_um = r.get(RDOC_UMQTA);
_mag = r.get(RDOC_CODMAG);
_qta = r.get_real("QTARES"); // Virtual field... must exist!!
_datacons = r.get_date(RDOC_DATACONS);
_acq_ven = r.doc().get(DOC_TIPOCF) == "F" ? TRUE : FALSE;
_data_per = app().date_period(_datacons);
}
void _Dist2Explode::set(TToken_string& t)
{
_cod = t.get(0);
_livgiac = t.get(1);
_livgiac << t.get(2);
_livgiac << t.get(3);
_livgiac << t.get(4);
_livgiac.trim();
_mag.format("%3s", (const char*)t.get(5));
_mag << t.get(6);
_um = t.get(7);
_qta = t.get(8);
_datacons = t.get(10);
_acq_ven = t.get(11)[0] == 'X' ? TRUE : FALSE;
_data_per = app().date_period(_datacons);
}
const char* _Dist2Explode::key()
{
__key.format("%d%-20s%-15s%-2s%-5s",
app().date2period(_datacons), (const char*)_cod, (const char*) _livgiac,
(const char*)_um, (const char*) _mag);
return (const char*) __key;
}
///////////////////////////////////////////////////////////////////
// Implementazione metodi di TEsplosione_distinta_app
///////////////////////////////////////////////////////////////////
bool TEsplosione_distinta_app::sheet_notify(TSheet_field& s, int r, KEY key)
{
if (key==(K_CTRL+K_INS))
{
TDate d(TODAY);
TToken_string& t = s.row(r);
t.add(d.string(),10);
}
return TRUE;
}
void TEsplosione_distinta_app::open_files(int logicnum, ...)
{
va_list marker;
va_start(marker, logicnum);
while (logicnum > 0)
{
CHECKD(_file.objptr(logicnum) == NULL, "File gia' aperto: ", logicnum);
_file.add(new TLocalisamfile(logicnum), logicnum);
logicnum = va_arg(marker, int);
}
}
const int TEsplosione_distinta_app::date2period(const TDate& d)
{
const int items = _date_array.items();
for (int i = 0; i<items; i++)
{
if (d <= (TDate&)_date_array[i])
break;
}
if (i == items) // Didn't find my way...
return 0;
return i+1;
}
const TDate& TEsplosione_distinta_app::date_period(const TDate& d)
{
const int period = date2period(d);
return (TDate&)_date_array[period ? period -1 : 0];
}
bool TEsplosione_distinta_app::check_articoli(TMask_field& f, KEY k)
{
if (k == K_ENTER && f.dlg() == F_QTA)
{
TMask& m = f.mask();
TSheet_field& s = *m.get_sheet();
const int selected = s.selected();
TToken_string& row = s.row(selected);
bool ok;
if (!row.empty_items())
{
const TCodice_articolo articolo(m.get(F_CODDIS));
const TCodice_um um(m.get(F_UMEXPR));
const int items = s.items();
const short F = F_QTA - 101;
for (int i = 0; i < items; i++)
if (i != selected && !s.row(i).empty_items()) // Articolo/unita' di misura gia' usata... chiede se gabolarli assieme...
{
TCodice_articolo art;
TCodice_um u;
art = s.row(i).get(0);
u = s.row(i).get(7);
if (articolo == art && um == u)
{
ok = f.yesno_box("L'articolo %s (UM %s) e' gia' stato utilizzato al rigo %d.\n"
"Si desidera sommare le quantita' nello stesso rigo?",
(const char*) articolo, (const char*) um, i+1);
if (ok)
{
int src = selected, dst = i;
if (src < dst)
{ int tmp = src; src = dst; dst = tmp; }
TToken_string& srcrow = s.row(src);
TToken_string& dstrow = s.row(dst);
real tot = dstrow.get(F);
tot += real(srcrow.get(F));
dstrow.add(tot.string(), F);
s.force_update(dst);
srcrow.cut(0);
s.force_update(src);
}
break;
}
}
}
}
return TRUE;
}
bool TEsplosione_distinta_app::create()
{
open_files(LF_UMART, LF_OCCAS, LF_CLIFO, LF_DOC, LF_RIGHEDOC, LF_INDSP, LF_CFVEN, LF_TABCOM, LF_MAG, LF_DIST, 0);
_mask = new TMask("db1100a");
TSheet_field& sa = (TSheet_field&) _mask->field(F_SHEETART);
sa.sheet_mask().set_handler(F_QTA, check_articoli);
sa.set_notify(sheet_notify);
_mask->set(F_ARTICOLI, "X");
_mask->set(F_LAVORAZIONI, "X");
_mask->set(F_VIRTUALI, "X");
_form = new TExplode_distinta_form("db1100a");
_liv_giac = new TCodgiac_livelli;
_liv_giac->set_sheetcolumn(sa, F_LIV1, 1);
_liv_giac->set_sheetcolumn(sa, F_LIV2, 2);
_liv_giac->set_sheetcolumn(sa, F_LIV3, 3);
_liv_giac->set_sheetcolumn(sa, F_LIV4, 4);
TConfig conf(CONFIG_DITTA, "mg");
const bool depositi = conf.get_bool("GESDEPOSITI");
sa.enable_column(F_DEP-F_CODDIS,depositi);
_mask->show(-5, depositi);
_doc = new TDocumento;
return TSkeleton_application::create();
}
bool TEsplosione_distinta_app::destroy()
{
delete _liv_giac;
delete _form;
delete _mask;
delete _doc;
return TSkeleton_application::destroy();
}
void TEsplosione_distinta_app::compile_periods()
{
TDate oggi(TODAY),dday;
_date_array.destroy();
const long ndays = _parameters._obs_date - oggi;
const long daysperiod = ndays / _parameters._periods;
dday = oggi;
for (int i = 0; i < _parameters._periods; i++)
{
dday += daysperiod;
if (i == _parameters._periods -1)
dday = _parameters._obs_date;
_date_array.add(dday);
}
}
void TEsplosione_distinta_app::compile_list()
{
_dist_list.destroy();
TDocumento& doc = *_doc;
TString key;
TRectype from(LF_DOC);
from.put(DOC_ANNO, _parameters._year);
from.put(DOC_PROVV, "D");
from.put(DOC_CODNUM, _parameters._from_num);
from.put(DOC_DATADOC, _parameters._from_date);
from.put(DOC_NDOC, _parameters._from_doc);
TRectype to(from);
to.put(DOC_CODNUM, _parameters._to_num);
to.put(DOC_DATADOC, _parameters._to_date);
to.put(DOC_NDOC, _parameters._to_doc);
TString filter_expr;
if (_parameters._selections == by_date && _parameters._from_num.not_empty() && _parameters._to_num.not_empty())
filter_expr.format("(%s>=\"%s\")&&(%s<=\"%s\")",
DOC_CODNUM, (const char*) _parameters._from_num,
DOC_CODNUM, (const char*) _parameters._to_num);
// Filtra i documenti
TLocalisamfile& dist = (TLocalisamfile&)_file[LF_DIST];
TRelation *r = new TRelation(LF_DOC);
TCursor c(r, filter_expr, _parameters._selections == by_num ? 1 : 3);
c.setregion(from,to);
const bool null_sel = _parameters._from_num.empty() || _parameters._to_num.empty();
const long items = null_sel ? 0L : c.items();
TSheet_field& sa = (TSheet_field&) _mask->field(F_SHEETART);
const int righe = sa.items();
TProgind p(items+righe,"Estrazione distinte da esplodere...", FALSE, TRUE);
for (c = 0L; c.pos() < items; c += 1L)
{
p.addstatus(1L);
if (doc.read(c.curr()) == NOERR)
{
const int rows = doc.rows();
for (int i = 1; i <= rows; i++)
{
dist.put("CODDIST", doc[i].get(RDOC_CODART));
if (doc[i].is_articolo() && dist.read() == NOERR) // Aggiunge le righe che sono solo effettivamente articoli di magazzino e distinte
{
_Dist2Explode * de = new _Dist2Explode;
de->set(doc[i]);
key = de->key();
const bool is_key = _dist_list.is_key(key);
if (is_key)
{
_Dist2Explode * dd = (_Dist2Explode*)_dist_list.objptr(key);
// Check 2 see whether we've 2 convert in base UM...
if (de->acqven()) // Se acquisto sottrae...
de->qta() = dd->qta() - de->qta();
else
de->qta() += dd->qta(); // altrimenti aggiunge
}
_dist_list.add(key, de, TRUE);
if (de->qta() == ZERO)
_dist_list.remove(key);
}
}
}
}
// Aggiunge le righe dallo spreadsheet
for (int i = 0; i < righe; i++)
{
p.addstatus(1L);
if (!sa.row(i).empty_items())
{
_Dist2Explode * de = new _Dist2Explode;
de->set(sa.row(i));
key = de->key();
const bool is_key = _dist_list.is_key(key);
if (is_key)
{
_Dist2Explode * dd = (_Dist2Explode*)_dist_list.objptr(key);
// Check 2 see whether we've 2 convert in base UM...
if (de->acqven()) // Se acquisto sottrae...
de->qta() = dd->qta() - de->qta();
else
de->qta() += dd->qta(); // altrimenti aggiunge
}
_dist_list.add(key, de, TRUE);
}
}
delete r;
}
void TEsplosione_distinta_app::print()
{
TString chiave;
TString_array chiavi;
_dist_list.get_keys(chiavi);
chiavi.sort();
const int items = chiavi.items();
if (items == 0)
return;
// Settaggio parametri del form (fincature)
TPrinter& pr = printer();
pr.open();
const int hh = 7;
const int fl = pr.formlen();
int rows[4]; // Righe orizzontali
rows[0] = hh-3;
rows[1] = hh;
rows[2] = fl-1;
rows[3] = 0;
// Setta l'intestazione corretta per la colonna del valore distinta
TForm_item& fi = _form->find_field('B', odd_page, 10);
fi.set_col_head(_parameters._fabbisogno ? "@cValore da ord./prod." : "@cValore");
_form->set_parameters(&_parameters);
_form->genera_intestazioni(odd_page, hh-2);
_form->genera_fincatura(odd_page, hh-3, fl-1, rows);
_form->reset_cache(); // Resetta ad ogni stampa
// Ciclo per distinta: tutte quelle dei documenti indicati
// E tutte quelle indicate singolarmente nello spreadsheet dell'articolo
// Stampa esplosione distinta, nell'ordine specificato: periodo+codice+livello+um+mag
__current_period = 0L;
for (int i = 0 ; i<items; i++)
{
chiave = (TString&) chiavi[i];
_form->set_distinta((_Dist2Explode*)_dist_list.objptr(chiave)); // Setta la distinta corrente
_form->print(); // Esplode & Stampa sta distinta
}
// Formfeed finale solo in caso non sia stata indicata la
// separazione delle esplosioni (altrimenti ne fa 2...)
if (!_parameters._separate_dists)
pr.formfeed();
pr.close();
}
void TEsplosione_distinta_app::main_loop()
{
while (_mask->run()!=K_QUIT)
{
TDate df(1,1,1998);
TDate dt(31,12,1998);
// Raccolta dati dalla maschera
_parameters._selections = (seltype) _mask->get_int(F_TIPOSEL);
_parameters._explosion = (expltype) _mask->get_int(F_STAMPA);
_parameters._valorization = (valtype) _mask->get_int(F_VALORIZZAZIONE);
_parameters._group_by = (grptype) _mask->get_int(F_GROUPMODE);
_parameters._year = _mask->get_int(F_ANNO);
_parameters._from_num = _mask->get(F_NUMFROM);
_parameters._to_num = _mask->get(F_NUMTO);
// Setta le date di default (dal primo all'ultimo dell'anno)
df.set_year(_parameters._year);
dt.set_year(_parameters._year);
_parameters._from_date = _mask->get_date(F_EMISFROM);
if (_parameters._from_date.empty())
_parameters._from_date = df;
_parameters._to_date = _mask->get_date(F_EMISTO);
if (_parameters._to_date.empty())
_parameters._to_date = dt;
_parameters._from_doc = _mask->get_long(F_NDOCFROM);
_parameters._to_doc = _mask->get_long(F_NDOCTO);
_parameters._obs_date = _mask->get_date(F_DATAOBS);
_parameters._periods = _mask->get_int(F_PERIODS);
_parameters._det_lev = _mask->get_int(F_DETTAGLIO);
_parameters._ordering = _mask->get_int(F_SORT);
_parameters._vis_art = _mask->get_bool(F_ARTICOLI);
_parameters._vis_vir = _mask->get_bool(F_VIRTUALI);
_parameters._vis_lav = _mask->get_bool(F_LAVORAZIONI);
_parameters._fabbisogno= _mask->get_bool(F_FABBISOGNO);
_parameters._last_qta = _mask->get_bool(F_LASTQTA);
_parameters._sl_mag = _mask->get(F_SLMAG); _parameters._sl_mag << _mask->get(F_SLDEP);
_parameters._mb_mag = _mask->get(F_MBMAG); _parameters._mb_mag << _mask->get(F_MBDEP);
_parameters._val_magmb = _mask->get_bool(F_VALMAGMB);
_parameters._val_depmb = _mask->get_bool(F_VALDEPMB);
_parameters._cfr_scmin = _mask->get_bool(F_SCMIN);
_parameters._separate_dists = _mask->get_bool(F_SEPARATE);
// Credo che il seguente anno esercizio sia calcolato
// in modo abbastanza schifoso, visto che si e' in possesso del solo anno solare
// Da controllare in futuro ...
TDate d(TODAY);
d.set_year(_parameters._year);
TEsercizi_contabili esc;
_parameters._anno_es.format("%04d",esc.date2esc(d));
// Compila la lista di testate termo-nucleare-globale
// delle distinte da esplodere nell'universo conosciuto
compile_periods();
compile_list();
// Stampa...
print();
}
}
///////////////////////////////////////////////////////////
// db1100 stampa esplosione distinte
///////////////////////////////////////////////////////////
int db1100(int argc, char* argv[])
{
TEsplosione_distinta_app *a = new TEsplosione_distinta_app;
a->run(argc, argv, "Stampa esplosione");
delete a;
return 0;
}