#include "calib01.h" #include "calib02.h" #include "ca3883.h" #include "panapdc.h" #include "pconana.h" //////////////////////////////////////////////////////////////////////////////////////// // Classe per ricavare l'indicatore di bilancio dei conti analitici riclassificati e non //////////////////////////////////////////////////////////////////////////////////////// TObject* TIndbil_cache::key2obj(const char* key) { TString80 conto = key; if (_usepdcc && conto.len() == 12 && real::is_natural(conto)) { TLocalisamfile panapdc(LF_PANAPDC); panapdc.setkey(2); const int gr = atoi(conto.left(3)); const int co = atoi(conto.mid(3,3)); const long so = atol(conto.mid(6,6)); TRectype& panapdrec = panapdc.curr(); int i; for (i = 2; i >= 0; i--) { panapdrec.zero(); panapdrec.put(PANAPDC_GRUPPO, gr); if (i > 0) panapdrec.put(PANAPDC_CONTO, co); if (i == 2) panapdrec.put(PANAPDC_SOTTOCONTO, so); //occhio al prefisso! panapdrec.put(PANAPDC_CODCONTO, _prefix); if (panapdc.read(_isgteq) == NOERR) { bool found = panapdrec.get_int(PANAPDC_GRUPPO) == gr; if (found) found = panapdrec.get_int(PANAPDC_CONTO) == (i > 0 ? co : 0); if (found) found = panapdrec.get_long(PANAPDC_SOTTOCONTO) == (i > 1 ? so : 0L); if (found && _prefix.full()) found = panapdrec.get(PANAPDC_CODCONTO).starts_with(_prefix); if (found) { conto = panapdrec.get(PANAPDC_CODCONTO); break; } } } //se non trova il corrispondente conto analitico azzera il conto per il prossimo giro if (i < 0) conto.cut(0); } //conto analitico TAnal_bill bill(conto); int indbil = bill.indicatore_bilancio(); TToken_string* ib = new TToken_string; *ib << indbil; ib->add(conto); return ib; } int TIndbil_cache::get_indbil(const TString& conto, TString& conto_anale) { TToken_string* ib = (TToken_string*)objptr(conto); if (ib != NULL) ib->get(1, conto_anale); return ib ? ib->get_int(0) : 0; } void TIndbil_cache::set_prefix(const char* prefix) { if (_prefix != prefix) { _prefix = prefix; destroy(); } } TIndbil_cache::TIndbil_cache() { TConfig& cfg = ca_config(); _usepdcc = cfg.get_bool("UsePdcc"); } ///////////////////////////////////////////////////////////////////////////////// //Classe di report speciale con numero colonne adattabile in base ad un parametro ///////////////////////////////////////////////////////////////////////////////// void TCRPA_report::merge_array(TString_array& c, TString_array& t, TString_array& codici, TString_array& testate) const { while (c.items() > 0) { TObject* cod = c.remove(0,true); TObject* tes = t.remove(0,true); codici.TArray::add(cod); testate.TArray::add(tes); } } void TCRPA_report::analize_pconana_structure (const TString& prefix, const int depth, TString_array& codici, TString_array& testate) const { //cerca quale e' la lunghezza della stringa conto da considerare in base alla depth scelta TConfig& cfg = ca_config(); const TMultilevel_code_info& pconana_info = ca_multilevel_code_info(LF_PCONANA); const long total_length = pconana_info.total_len(depth); //scandisce il piano dei conti analitico alla ricerca dei conti di lunghezza pari a.. //..quella appena ricavata TISAM_recordset recset("USE PCONANA\nSELECT LEN(CODCONTO)=#LUN\nFROM CODCONTO=#PREFIX\nTO CODCONTO=#PREFIX"); recset.set_var("#LUN", TVariant(total_length)); recset.set_var("#PREFIX", TVariant(prefix)); const int prefix_length = prefix.len(); TString_array codici_c, testate_c, codici_r, testate_r; //riempie gli array con i codici conto di lunghezza opportuna e relative testate for (bool ok = recset.move_first(); ok; ok = recset.move_next()) { const TString& codconto = recset.get(PCONANA_CODCONTO).as_string(); const TAnal_bill zio(codconto); const int indbil = zio.indicatore_bilancio(); //solo Costi e Ricavi! if (indbil == 3 || indbil == 4) { const TString& codice = codconto.mid(prefix_length); const TString& testata = zio.testata(); if (indbil == 3) { codici_c.add(codice); testate_c.add(testata); } else { codici_r.add(codice); testate_r.add(testata); } } } if (codici_r.items() == 1) //se il campo da stampare e' uno solo->e' il totale del livello { codici_r.destroy(); testate_r.destroy(); } codici_r.add("#RICAVI"); testate_r.add(TR("RICAVI")); //..analogo per i Costi if (codici_c.items() == 1) { codici_c.destroy(); testate_c.destroy();; } codici_c.add("#COSTI"); testate_c.add(TR("COSTI")); //condensa gli array di Costo e Ricavo in un unico array che servira' di base per la stampa merge_array(codici_r, testate_r, codici, testate); merge_array(codici_c, testate_c, codici, testate); } void TCRPA_report::offset_and_fill_columns(TReport_section& rep_sect, const TString_array& str_arr, const int model_id) { TReport_field& rep_field = *rep_sect.find_field(model_id); //deve spostare i campi a destra della colonna modello //prende il rettangolo del campo.. const TRectangle& rep_field_rect = rep_field.get_rect(); //si memorizza i campi a destra del campo modello per poterli mettere a destra di tutti.. //..i campi che saranno generati TPointer_array campi_a_destra; for (int j = 0; j < rep_sect.items(); j++) { const TReport_field& campo = rep_sect.field(j); const TRectangle& rct = campo.get_rect(); //se il campo e' a destra del modello lo aggiunge all'array dei campi_a_destra if (rct.left() >= rep_field_rect.right()) campi_a_destra.add(campo); } //duplica il campo modello e riempie i duplicati con i valori degli array //serve il tipo di sezione poiche' gli header vanno trattati diversamente dai body const char sect_type = rep_sect.type(); //ciclo su tutti gli elementi dell'array con i valori da settare nei nuovi campi for (int i = 0; i < str_arr.items(); i++) { TReport_field* new_field = i == 0 ? &rep_field : (TReport_field*)rep_field.dup(); if (i > 0) { rep_sect.add(new_field); new_field->set_pos(rep_field_rect.left() + rep_field_rect.width() * i, rep_field_rect.top()); new_field->set_id(rep_field.id() + i); } switch (sect_type) { case 'H': //gli header devono stampare l'intestazione { new_field->set_picture(str_arr.row(i)); } break; case 'B': //i body devono stampare i valori e sommarli ai totali nei footer { new_field->set_field(str_arr.row(i)); TString ps = "MESSAGE ADD,F3."; ps << new_field->id(); new_field->set_postscript(ps); } break; case 'F': //i footer devono calcolarsi i totali! if (rep_sect.level() > 1) { new_field->set_field(""); TString ps = "MESSAGE ADD,F"; ps << (rep_sect.level() - 1) << '.' << new_field->id(); new_field->set_postscript(ps); } break; default: break; } } //sposta a destra gli ultimi campi non generati const TReport_field& ultimo_campo = rep_sect.field(rep_sect.last()); const TPoint offset(ultimo_campo.get_rect().right() - rep_field.get_rect().right(), 0); for (int k = 0; k < campi_a_destra.items(); k++) { TReport_field& campo = (TReport_field&)campi_a_destra[k]; campo.offset(offset); } } bool TCRPA_report::generate_columns (TString_array& codici, TString_array& testate, const int model_id) { //sezioni del report da modificare TReport_section& b1 = section('B', 1); //controllo dell'esistenza dei campi modello da replicare e loro duplicazione e riempimento! TReport_field* b1_model = b1.find_field(model_id); if (b1_model == NULL) return false; offset_and_fill_columns(b1, codici, model_id); //testate //la testata di pagina deve invece riempire le intestazioni delle colonne generate TReport_section& h0 = section('H', 0); TReport_field* h0_model = h0.find_field(model_id); if (h0_model == NULL) warning_box(TR("Manca l'intestazione della colonna modello (H0.%d)"),model_id); else offset_and_fill_columns(h0, testate, model_id); //le testate di sezione devono resettare i campi totale dei corrispondenti footers for (int j = 3; j > 0; j--) { TReport_section& head = section('H', j); if (head.items() > 0) { TString ps; //i campi dei totali da resettare sono tanti quante le colonne generate //k=0 per includere la colonna 69!!! usata nel caso i ricavi siano solo di livello 1 (depth=1) for (int k = 0; k <= codici.items(); k++) { if (ps.full()) ps << "\n"; ps << "MESSAGE RESET,F"; ps << head.level() << '.' << (k+model_id); } head.set_prescript(ps); } } //footers for (int i = 3; i > 0; i--) { TReport_section& foot = section('F', i); TReport_field* foot_model = foot.find_field(model_id); if (foot_model == NULL) warning_box(TR("Manca la colonna modello (F%d.%d)"), i, model_id); else offset_and_fill_columns(foot, codici, model_id); } return true; } TCRPA_report::TCRPA_report (const char* rep_name, const TString& prefix, const int depth) { //che report usare? load (rep_name); //array contenenti i conti analitici e le loro descrizioni di testata che diventeranno.. //.colonne del report dopo lungo e periglioso travaglio TString_array codici, testate; //per prima cosa si deve analizzare la struttura del piano conti.. //..da stampare fino al livello richiesto! analize_pconana_structure (prefix, depth, codici, testate); //poi vanno generate le colonne del report corrispondenti alla struttura analizzata generate_columns (codici, testate, 69); }