From 259e7587984028168083ba435942583198dced68 Mon Sep 17 00:00:00 2001 From: luca Date: Mon, 18 May 2009 15:39:54 +0000 Subject: [PATCH] Patch level : Files correlati : Ricompilazione Demo : [ ] Commento : analisi bilancio di commessa alla data: aggiunta elaborazione documenti git-svn-id: svn://10.65.10.50/trunk@18883 c028cbd2-c16b-5b4b-a496-9718f37d4682 --- ca/ca3700.cpp | 3 +- ca/ca3883.cpp | 331 +++++++++++++++++++++++++++++++------------------- ca/ca3883.h | 4 +- 3 files changed, 211 insertions(+), 127 deletions(-) diff --git a/ca/ca3700.cpp b/ca/ca3700.cpp index 006ab8e0e..1492ccddc 100755 --- a/ca/ca3700.cpp +++ b/ca/ca3700.cpp @@ -1414,8 +1414,7 @@ void TPrint_rendiconto_ca_recordset::crea_righe_da_rdoc(TLocalisamfile& tmp, con //validi nei filtri impostati dall'utente for (cur_rdoc = 0; cur_rdoc.pos() < rdoc_items; ++cur_rdoc) { - pi.addstatus(1); - if (pi.iscancelled()) + if (!pi.addstatus(1)) break; //La riga esaminata deve avere una testata valida!!!!Se la testata non esiste va saltata.. diff --git a/ca/ca3883.cpp b/ca/ca3883.cpp index bf53fa295..d9ef7f166 100755 --- a/ca/ca3883.cpp +++ b/ca/ca3883.cpp @@ -1,6 +1,7 @@ #include #include "../ve/velib.h" +#include "../ve/velib04.h" #include "calib01.h" #include "calib02.h" @@ -1037,8 +1038,7 @@ void TPrint_saldana_recordset::parse_saldana(TAssoc_array* cms, const TDate& dat for (bool ok = saldana_set.move_first(); ok; ok = saldana_set.move_next()) { //progind tanto per gradire - pi.addstatus(1); - if (pi.iscancelled()) + if (!pi.addstatus(1)) break; const TString& codconto = saldana.get(SALDANA_CONTO); @@ -1140,6 +1140,129 @@ void TPrint_saldana_recordset::parse_saldana(TAssoc_array* cms, const TDate& dat } +//elabora realmente la riga analitica che gli viene passata (serve sia per le rmovana pure (chiamata dalla parse_rmovava()).. +//..che per quelle create contabilizzando un documento (chiamata dalla parse_rdoc()) +void TPrint_saldana_recordset::elabora_rmovana(TAssoc_array* cms, const TDate& datainiesc, const TDate& datafinesc, + const TRectype& movana, const TRectype& rmovana) +{ + const char tipomov = movana.get_char(MOVANA_TIPOMOV); + //la data iniziale è la datacomp sulla testata per tutte le righe + const TDate datacomp = movana.get_date(MOVANA_DATACOMP); + + const TString& codcms = rmovana.get(RMOVANA_CODCMS); + const TRectype& rec_commesse = cache().get(LF_COMMESSE, codcms); + const int indice = ricava_sezione_di_stampa(rec_commesse, datainiesc, datafinesc); + + //solo le righe con commessa buona (indice >= 0) vengono considerate + if (indice >= 0) + { + //ci sono filtri o raggruppamenti per fase o centro di costo? + const TString& fase = rmovana.get(RMOVANA_CODFASE); + const TString& cdc = rmovana.get(RMOVANA_CODCCOSTO); + //se la riga è risultata buona ricava la chiave completa per l'assoc_array comprendendo eventuali.. + //..fasi e/o cdc + TString chiave = ricava_chiave_cdc_fase(codcms, fase, cdc); + + //calcola la "durata complessiva" della riga, ovvero l'intervallo di tempo per cui essa risulta valida + //la data fine ci fa sudare un pò + //di base è pari a datafcomp di testata (che è sempre esistente, mal che vada è uguale a datacomp) + TDate datafcomp = movana.get_date(MOVANA_DATAFCOMP); + //se invece è un movimento cazzuto con il calcolo automatico della data di morte (dataexpire)... + if (movana.get_bool(MOVANA_AUTOFCOMP)) + { + //data del cazzo che serve per non rovinare datacomp, che è la data sulla riga, non quella iniziale di cms + TDate datainicms; + durata_commessa(rec_commesse, datainicms, datafcomp); + } + //se siamo in presenza di un movimento senza datafcomp (inserito precdentemente alla nascita di datafcomp.. + //..per tutti i movimenti, come nel gestore dei movana mette datafcomp = datacomp; + if (!datafcomp.ok()) + datafcomp = datacomp; + //finalmente la tanto agognata vita della riga di movana! + //si aggiunge 1 perchè se un movimento ha datacomp=datafcomp (come in generale accade) in realtà.. + //..il poveretto vive un giorno, non 0 + const long vita_totale_riga = datafcomp - datacomp + 1; + + //riproporzionamento dell'importo di riga in base alla frazione di vita di riga interessata + real importo = rmovana.get_real(RMOVANA_IMPORTO); + + if (vita_totale_riga > 1) + { + //trova la frazione di vita della riga che interessa l'esercizio corrente + const TDate inizio_inter = fnc_max(datainiesc, datacomp); + const TDate fine_inter = fnc_min(_datacalcolo, datafcomp); + //si aggiunge anche qui 1 per gli stessi motivi della vita_totale + const long vita_frazione_riga = fine_inter - inizio_inter + 1; + + //il riproporzionamento vale solo per i movimenti che durano più di 1 giorno e con una vita_frazione.. + //..> vita_totale (il contrario sarebbe un errore!). I movimenti tutti nel futuro risultano con.. + //..vita_frazione negativa e quindi non sono considerati + //Anche le commesse tutte nel futuro rispetto a datacalcolo danno origine a una vita_frazione negativa.. + //..parando il culo al povero programma + if (vita_frazione_riga > 1 && vita_frazione_riga < vita_totale_riga) + { + importo = vita_frazione_riga * importo / vita_totale_riga; + importo.round(2); + } + } + //dopo tutto sto panegirico sul riproporzionamento finalmente si passa ad aggiornare gli array di stampa.. + //..con gli importi aggiustati + if (!importo.is_zero()) + { + //importo della riga già eventualmente riproporzionato + const TImporto importo_riga(rmovana.get_char(RMOVANA_SEZIONE), importo); + //riga array da aggiungere agli arrayoni da mandare in stampa + TAssoc_array& riga_array = get_row(cms[indice], chiave, indice, codcms, fase, cdc, + rec_commesse.get(COMMESSE_DESCRIZ)); + + + const TString& codconto = rmovana.get(RMOVANA_CODCONTO); + //trova l'indicatore di bilancio + TString80 conto_anale; + + const int indbil = _indicatori.get_indbil(codconto, conto_anale); + //solo i Costi(3) ed i Ricavi(4) devono essere considerati per la stampa + if (indbil == 3 || indbil == 4) + { + //gruppo e conto servono solo per il caso _tipo=8 ma vanno dichiarati e ricavati.. + //..qui in modo che siano a disposizione delle commesse del cazzo poco sotto + const char* gruppo = indbil == 3 ? "COSTI" : "RICAVI"; + TString80 conto; + parse_bill(conto_anale, conto); + + TRectype saldana(LF_SALDANA); + saldana.put(SALDANA_ANNO, _anno); + saldana.put(SALDANA_CONTO, conto_anale); + saldana.put(SALDANA_COSTO, cdc); + saldana.put(SALDANA_COMMESSA, codcms); + saldana.put(SALDANA_FASE, fase); + + switch(tipomov) + { + case 'P': + saldana.put(SALDANA_SEZIONEP, importo_riga.sezione()); + saldana.put(SALDANA_SALDOP, importo_riga.valore()); + break; + case 'V': + saldana.put(SALDANA_SEZIONEV, importo_riga.sezione()); + saldana.put(SALDANA_SALDOV, importo_riga.valore()); + break; + default: + saldana.put(SALDANA_SEZIONE, importo_riga.sezione()); + saldana.put(SALDANA_SALDO, importo_riga.valore()); + break; + } + + //aggiunge gli importi e normalizza + aggiorna_importo(riga_array, gruppo, indbil, saldana); + aggiorna_importo(riga_array, conto, indbil, saldana); + } + } + } //if(indice>=0)... + +} + + //aggiorna l'arrayone cms con le rmovana void TPrint_saldana_recordset::parse_rmovana(TAssoc_array* cms, const TDate& datainiesc, const TDate& datafinesc) { @@ -1196,125 +1319,13 @@ void TPrint_saldana_recordset::parse_rmovana(TAssoc_array* cms, const TDate& dat for (bool ok = recset.move_first(); ok; ok = recset.move_next()) //giro sui vari rmovana... { //aggiornamento progind intrattenitiva - pi.addstatus(1); - if (pi.iscancelled()) + if (!pi.addstatus(1)) break; - const char tipomov = movana.get_char(MOVANA_TIPOMOV); - //la data iniziale è la datacomp sulla testata per tutte le righe - const TDate datacomp = movana.get_date(MOVANA_DATACOMP); + //metodo per generare i saldi alla data della riga analitica in base alla vita della riga + elabora_rmovana(cms, datainiesc, datafinesc, movana, rmovana); - const TString& codcms = rmovana.get(RMOVANA_CODCMS); - const TRectype& rec_commesse = cache().get(LF_COMMESSE, codcms); - const int indice = ricava_sezione_di_stampa(rec_commesse, datainiesc, datafinesc); - - //solo le righe con commessa buona (indice >= 0) vengono considerate - if (indice >= 0) - { - //ci sono filtri o raggruppamenti per fase o centro di costo? - const TString& fase = rmovana.get(RMOVANA_CODFASE); - const TString& cdc = rmovana.get(RMOVANA_CODCCOSTO); - //se la riga è risultata buona ricava la chiave completa per l'assoc_array comprendendo eventuali.. - //..fasi e/o cdc - TString chiave = ricava_chiave_cdc_fase(codcms, fase, cdc); - - //calcola la "durata complessiva" della riga, ovvero l'intervallo di tempo per cui essa risulta valida - //la data fine ci fa sudare un pò - //di base è pari a datafcomp di testata (che è sempre esistente, mal che vada è uguale a datacomp) - TDate datafcomp = movana.get_date(MOVANA_DATAFCOMP); - //se invece è un movimento cazzuto con il calcolo automatico della data di morte (dataexpire)... - if (movana.get_bool(MOVANA_AUTOFCOMP)) - { - //data del cazzo che serve per non rovinare datacomp, che è la data sulla riga, non quella iniziale di cms - TDate datainicms; - durata_commessa(rec_commesse, datainicms, datafcomp); - } - //se siamo in presenza di un movimento senza datafcomp (inserito precdentemente alla nascita di datafcomp.. - //..per tutti i movimenti, come nel gestore dei movana mette datafcomp = datacomp; - if (!datafcomp.ok()) - datafcomp = datacomp; - //finalmente la tanto agognata vita della riga di movana! - //si aggiunge 1 perchè se un movimento ha datacomp=datafcomp (come in generale accade) in realtà.. - //..il poveretto vive un giorno, non 0 - const long vita_totale_riga = datafcomp - datacomp + 1; - - //riproporzionamento dell'importo di riga in base alla frazione di vita di riga interessata - real importo = rmovana.get_real(RMOVANA_IMPORTO); - - if (vita_totale_riga > 1) - { - //trova la frazione di vita della riga che interessa l'esercizio corrente - const TDate inizio_inter = fnc_max(datainiesc, datacomp); - const TDate fine_inter = fnc_min(_datacalcolo, datafcomp); - //si aggiunge anche qui 1 per gli stessi motivi della vita_totale - const long vita_frazione_riga = fine_inter - inizio_inter + 1; - - //il riproporzionamento vale solo per i movimenti che durano più di 1 giorno e con una vita_frazione.. - //..> vita_totale (il contrario sarebbe un errore!). I movimenti tutti nel futuro risultano con.. - //..vita_frazione negativa e quindi non sono considerati - //Anche le commesse tutte nel futuro rispetto a datacalcolo danno origine a una vita_frazione negativa.. - //..parando il culo al povero programma - if (vita_frazione_riga > 1 && vita_frazione_riga < vita_totale_riga) - { - importo = vita_frazione_riga * importo / vita_totale_riga; - importo.round(2); - } - } - //dopo tutto sto panegirico sul riproporzionamento finalmente si passa ad aggiornare gli array di stampa.. - //..con gli importi aggiustati - if (!importo.is_zero()) - { - //importo della riga già eventualmente riproporzionato - const TImporto importo_riga(rmovana.get_char(RMOVANA_SEZIONE), importo); - //riga array da aggiungere agli arrayoni da mandare in stampa - TAssoc_array& riga_array = get_row(cms[indice], chiave, indice, codcms, fase, cdc, - rec_commesse.get(COMMESSE_DESCRIZ)); - - - const TString& codconto = rmovana.get(RMOVANA_CODCONTO); - //trova l'indicatore di bilancio - TString80 conto_anale; - - const int indbil = _indicatori.get_indbil(codconto, conto_anale); - //solo i Costi(3) ed i Ricavi(4) devono essere considerati per la stampa - if (indbil == 3 || indbil == 4) - { - //gruppo e conto servono solo per il caso _tipo=8 ma vanno dichiarati e ricavati.. - //..qui in modo che siano a disposizione delle commesse del cazzo poco sotto - const char* gruppo = indbil == 3 ? "COSTI" : "RICAVI"; - TString80 conto; - parse_bill(conto_anale, conto); - - TRectype saldana(LF_SALDANA); - saldana.put(SALDANA_ANNO, _anno); - saldana.put(SALDANA_CONTO, conto_anale); - saldana.put(SALDANA_COSTO, cdc); - saldana.put(SALDANA_COMMESSA, codcms); - saldana.put(SALDANA_FASE, fase); - - switch(tipomov) - { - case 'P': - saldana.put(SALDANA_SEZIONEP, importo_riga.sezione()); - saldana.put(SALDANA_SALDOP, importo_riga.valore()); - break; - case 'V': - saldana.put(SALDANA_SEZIONEV, importo_riga.sezione()); - saldana.put(SALDANA_SALDOV, importo_riga.valore()); - break; - default: - saldana.put(SALDANA_SEZIONE, importo_riga.sezione()); - saldana.put(SALDANA_SALDO, importo_riga.valore()); - break; - } - - //aggiunge gli importi e normalizza - aggiorna_importo(riga_array, gruppo, indbil, saldana); - aggiorna_importo(riga_array, conto, indbil, saldana); - } - } - } //if(indice>=0)... - } //for(bool ok=recset.move_first()... + } //for(bool ok=recset.move_first()... } //if(recset_items>0... } @@ -1357,7 +1368,7 @@ int TPrint_saldana_recordset::numerazioni_ordini(TString_array& num_ordini, TStr //aggiorna l'arrayone cms con le righedoc non ancora contabilizzate -void TPrint_saldana_recordset::parse_rdoc(TAssoc_array* cms, const TDate& datainiesc) +void TPrint_saldana_recordset::parse_rdoc(TAssoc_array* cms, const TDate& datainiesc, const TDate& datafinesc) { //solo le numerazioni con almeno un tipo documento ordine interessano TString_array num_ordini, tip_ordini; @@ -1372,7 +1383,7 @@ void TPrint_saldana_recordset::parse_rdoc(TAssoc_array* cms, const TDate& datain TString query; query << "USE RDOC KEY 3\n"; - query << "SELECT (BETWEEN(DOC.DATADOC, #DATAINIES, #DATACALCOLO))"; + query << "SELECT (BETWEEN(DOC.DATADOC, #DATAINIES, #DATACALCOLO))&&(RIGAEVASA!=\"X\")"; //filtro su cdc/cms/fasi (fatto come per saldi e rmovana; purtroppo non si può metodizzare perchè in tutti i files.. //..i nomi dei campi sono diversi! @@ -1416,13 +1427,85 @@ void TPrint_saldana_recordset::parse_rdoc(TAssoc_array* cms, const TDate& datain //simpatica progind per intrattenere l'utonto TProgind pi(recset_items, "Scansione documenti...", true, true); + //memorizza l'ultimo doc per evitare doppioni in caso di doc con più righe (rielaborerebbe.. + //..lo stesso documento tante volte quante sono le sue righe!) + TString old_key; + //misterioso oggetto necessario per contabilizzare il documento in osservazione + TContabilizzazione_analitica cont_anal; + for (bool ok = recset.move_first(); ok; ok = recset.move_next()) //giro sulle varie rdoc... { //aggiornamento progind intrattenitiva - pi.addstatus(1); - if (pi.iscancelled()) + if (!pi.addstatus(1)) break; - } + + const TRectype& curr_doc = recset.cursor()->curr(LF_DOC); + //controlla se il documento contenente la riga è davvero un ordine ricontrollando il suo tipo nell'array.. + //..con i tipi validi; se non lo fosse...ciao ciao rigadocumento! + const TString& tipodoc = curr_doc.get(DOC_TIPODOC); + if (tip_ordini.find(tipodoc)) + continue; + + //ovviamente non è finita qui... + //la riga documento non deve risultare contabilizzata! infatti, se lo fosse, i suoi valori apparirebbero.. + //..nella sezione delle rmovana + const long numregca = curr_doc.get_long(DOC_NUMREGCA); + //se la rigadoc non è stata contabilizzata.. + if (numregca == 0) + { + //magico trucco per non dover ricontabilizzare lo stesso documento tante volte quante sono le righe consecutive + const TString curr_key = curr_doc.build_key(); + if (curr_key == old_key) + continue; + else + old_key = curr_key; + + //crea il documento virtuale in memoria; se non è ordine oppure lo è ma è già evaso, lo saltiamo!!! ole'! + TDocumento doc(curr_doc); + if (!doc.is_ordine() || doc.is_evaso()) + continue; + + //il documento virtuale è adesso un ordine non evaso + //tarocchiamo il documento prendendo solo le righe non evase (almeno una ci sarà, perchè la query del recordset.. + //..richiedeva che la rigadoc fosse non evasa, quindi quella riga nel doc esiste, magari in compagnia di altre) + for (int r = doc.body().last_row(); r > 0; r = doc.body().pred_row(r)) + { + TRiga_documento& rigadoc = doc[r]; + if (!rigadoc.is_evasa()) + { + //trasforma tutte le righe a valore, assegnando al prezzo il valore del residuo + const real residuo = rigadoc.valore(false); + rigadoc.put(rigadoc.tipo().quant(), UNO); + rigadoc.put(RDOC_PREZZO, residuo); + } + else + doc.body().destroy_row(r, true); //se la riga fosse evasa la salta e compatta il documento + } + + //movana nevessario per la contabilizzazione analitica del documento + TAnal_mov movana; + //finalmente contabilizza il documento in memoria + cont_anal.elabora(doc, 0, NULL, false, movana, false); + + //controlla che la riga in esame abbia realmente la cms/cdc/fas indicata nel filtro; + //procedimento necessario per evitare di prendere righe appartenenti a docs elaborati + //perchè contenenti 1 riga con cms corretta ed altre righe con cms sbagliate + for (int j = 1; j <= movana.rows(); j++) + { + const TRectype& rmovana = movana.body()[j]; + + if (_cdc.not_empty() && rmovana.get(RMOVANA_CODCCOSTO) != _cdc) + continue; + if (_fase.not_empty() && rmovana.get(RMOVANA_CODFASE) != _fase) + continue; + + //metodo per il calcolo importo riga riproporzionato + //metodo per generare i saldi alla data della riga analitica in base alla vita della riga + elabora_rmovana(cms, datainiesc, datafinesc, movana, rmovana); + + } //for int j... + } + } //for (bool ok = recset.... } //for (int n = 0; n < numerazioni... @@ -1454,7 +1537,7 @@ void TPrint_saldana_recordset::create_lines_to_print(const TString& query) parse_rmovana(cms, datainiesc, datafinesc); // 2_b) calcolo dei saldi da documenti non ancora contabilizzati e quindi senza movana e saldana - parse_rdoc(cms, datainiesc); + parse_rdoc(cms, datainiesc, datafinesc); } //if((_datacalcolo