Files correlati : f151.dir f151.trr ca1.exe ca2.exe ca3.exe ca3100.uml
ca3100a.rep ca3100b.rep ca3200.uml ca3200a.rep
ca3200b.rep ca3300.uml ca3300a.rep ca3300b.rep
ca3300c.rep ca3300d.rep ca3600.uml ca3600a.rep
ca3700.uml ca3700a.rep ca3700b.rep ca3800.uml
ca3800a.rep ca3800as.rep ca3800b.rep ca3800bs.rep
ca3800c.rep ca3800cs.rep ca3883.cpp ca3900.uml
ca3900a.rep
Commento :
Aggiunta contabilità separata alle stampe di analitica.
Aggiunto meccanismo per lanciare le stampe in batch.
Sintassi: ca3 -7 -b <nome del file che contiene i valori dell maschera> <tipo di output <P>rint|<E>xport|E<X>cel|PD<F>|<T>esto|<D>Base|<V>isualizza> <nome del file di output
Esempio: ca3 -7 -b select.sav X c:\out\rend
esporta il rendiconto di commessa usando i parametri salvati in select.sav nel file c:\out\rend.xls
3416 lines
92 KiB
C++
Executable File
3416 lines
92 KiB
C++
Executable File
#include <applicat.h>
|
|
#include <config.h>
|
|
#include <dongle.h>
|
|
#include <modaut.h>
|
|
#include <tree.h>
|
|
#include <treectrl.h>
|
|
#include <utility.h>
|
|
#include <urldefid.h>
|
|
|
|
#include <mov.h>
|
|
#include <pconti.h>
|
|
#include <doc.h>
|
|
#include <rdoc.h>
|
|
|
|
#include "calib01.h"
|
|
#include "calib02.h"
|
|
#include "calibmsk.h"
|
|
#include "../cg/cglib.h"
|
|
|
|
#include "cdc.h"
|
|
#include "commesse.h"
|
|
#include "fasi.h"
|
|
#include "movana.h"
|
|
#include "rmovana.h"
|
|
#include "rip.h"
|
|
#include "rrip.h"
|
|
#include "saldana.h"
|
|
|
|
|
|
///////////////////////////////////////////////////////////
|
|
// TConfig_anal
|
|
///////////////////////////////////////////////////////////
|
|
|
|
class TConfig_anal : public TConfig
|
|
{
|
|
int _level;
|
|
|
|
public:
|
|
virtual const TString& get(const char* var, const char* section = nullptr, int index = -1, const char* def = "");
|
|
TConfig_anal();
|
|
};
|
|
|
|
TConfig_anal::TConfig_anal() : TConfig(CONFIG_DITTA, "ca"), _level(0)
|
|
{
|
|
const TDongle& a = dongle();
|
|
_level = a.active(CAAUT) ? 4 : (a.active(CMAUT) ? 1 : 0);
|
|
if (a.active(CIAUT)) _level |= 2;
|
|
|
|
// Controllo se è veramente configurato il primo livello a CMS o CDC
|
|
if (_level > 1 && TConfig::get("Level", nullptr, 1).blank())
|
|
_level = 0;
|
|
}
|
|
|
|
const TString& TConfig_anal::get(const char* varname, const char* section, int index, const char* def)
|
|
{
|
|
const TFixed_string var(varname);
|
|
if (var == "Authorizations")
|
|
return get_tmp_string() << _level;
|
|
|
|
if (_level & 0x6) // CA o CI
|
|
return TConfig::get(varname, section, index, def);
|
|
|
|
if (_level & 0x1) // CM
|
|
{
|
|
TString& tmp = get_tmp_string();
|
|
//se il valore della variabile sul .ini e' vuoto controlla se e' possibile assegnarlo di default
|
|
if (var == "AttFasi")
|
|
tmp = "X"; else
|
|
if (var == "Level" && index == 1)
|
|
tmp = "CMS"; else
|
|
if (var == "Cms" && index == 1)
|
|
tmp = TConfig::get(var, section, 1, "LLLLLLLLLLLLLLLLLLLL"); else
|
|
if (var == "CmsDes" && index == 1)
|
|
tmp = TR("Commessa"); else
|
|
if (var == "Fsc" && index == 1)
|
|
tmp = TConfig::get(var, section, 1, "LLLLLLLLLL"); else
|
|
if (var == "FscDes" && index == 1)
|
|
tmp = TR("Fase"); else
|
|
if (var == "EdMask")
|
|
tmp = "ca0300a"; else
|
|
if (var == "UsePdcc")
|
|
tmp = "X";
|
|
|
|
return tmp;
|
|
}
|
|
|
|
return EMPTY_STRING;
|
|
}
|
|
|
|
TConfig& ca_config(bool force_reload)
|
|
{
|
|
static TConfig_anal* cfg = nullptr;
|
|
if (cfg == nullptr || force_reload)
|
|
{
|
|
SAFE_DELETE(cfg);
|
|
cfg = new TConfig_anal;
|
|
}
|
|
return *cfg;
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////
|
|
// TMultilevel_code_info
|
|
///////////////////////////////////////////////////////////
|
|
|
|
int TMultilevel_code_info::levels() const
|
|
{
|
|
return _picture.items();
|
|
}
|
|
|
|
int TMultilevel_code_info::parent_levels() const
|
|
{
|
|
int n = 0;
|
|
if (_logicnum == LF_FASI && _parentnum > 0)
|
|
{
|
|
const TMultilevel_code_info cdc_cms(_parentnum);
|
|
n = cdc_cms.levels();
|
|
}
|
|
return n;
|
|
}
|
|
|
|
|
|
const TString& TMultilevel_code_info::picture(int level) const
|
|
{
|
|
if (level < 0 || level >= levels())
|
|
return EMPTY_STRING;
|
|
return _picture.row(level);
|
|
}
|
|
|
|
bool TMultilevel_code_info::is_required(int level) const
|
|
{ return level <= 0; }
|
|
|
|
bool TMultilevel_code_info::is_numeric_picture(int level) const
|
|
{
|
|
const TString& pic = picture(level);
|
|
if (pic.full())
|
|
{
|
|
int i;
|
|
// Tutti 0 e 9
|
|
for (i = 0; pic[i] == '0' || pic[i] == '9'; i++);
|
|
if (pic[i] == '\0')
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
int TMultilevel_code_info::len(int level) const
|
|
{
|
|
return picture(level).len();
|
|
}
|
|
|
|
int TMultilevel_code_info::total_len(int level) const
|
|
{
|
|
const int max_lev = levels();
|
|
if (level < 0) // -1 = fino al penultimo
|
|
level = max_lev+level-1;
|
|
int l = 0;
|
|
for (int i = 0; i <= level && i < max_lev; i++)
|
|
l += picture(i).len();
|
|
return l;
|
|
}
|
|
|
|
const TString& TMultilevel_code_info::prompt(int level) const
|
|
{
|
|
if (level < 0 || level >= _prompt.items())
|
|
return EMPTY_STRING;
|
|
return _prompt.row(level);
|
|
}
|
|
|
|
const TFieldref& TMultilevel_code_info::fieldref(int level, int key) const
|
|
{
|
|
const TArray& a = key <= 1 ? _key1_fields : _key2_fields;
|
|
const TFieldref& fr = (const TFieldref&)a[level];
|
|
return fr;
|
|
}
|
|
|
|
const char* TMultilevel_code_info::get_key_fieldname(int k) const
|
|
{
|
|
const RecDes& rd = prefix().get_recdes(_logicnum);
|
|
CHECKD(k > 0 && k <= rd.NKeys, "Invalid key ", k);
|
|
const KeyDes& ky = rd.Ky[k-1];
|
|
int idx = 0;
|
|
if (k == 1 && (_logicnum == LF_TAB || _logicnum == LF_TABCOM || _logicnum == LF_FASI))
|
|
idx = 1;
|
|
const int pos = ky.FieldSeq[idx] % MaxFields;
|
|
return rd.Fd[pos].Name;
|
|
}
|
|
|
|
bool TMultilevel_code_info::get_cfg_vars(TString& key, TString& des) const
|
|
{
|
|
switch (_logicnum)
|
|
{
|
|
case LF_PCONANA : key = "Pdci"; des = "PdciDes"; break;
|
|
case LF_CDC : key = "CdC"; des = "CdCDes"; break;
|
|
case LF_COMMESSE: key = "Cms"; des = "CmsDes"; break;
|
|
case LF_FASI : key = "Fsc"; des = "FscDes"; break;
|
|
default: break;
|
|
}
|
|
return key.not_empty();
|
|
}
|
|
|
|
void TMultilevel_code_info::add_fieldref(int k, int from, int to)
|
|
{
|
|
TArray& a = k == 1 ? _key1_fields : _key2_fields;
|
|
TString80 str = get_key_fieldname(k);
|
|
if (from > 0)
|
|
str << '[' << from << ',' << to << ']';
|
|
|
|
TFieldref* fr = new TFieldref(str, _logicnum);
|
|
a.add(fr);
|
|
}
|
|
|
|
int TMultilevel_code_info::pack(TString& code) const
|
|
{
|
|
code.strip("|");
|
|
return levels();
|
|
}
|
|
|
|
int TMultilevel_code_info::unpack(TString& code) const
|
|
{
|
|
const int lev = levels();
|
|
if (lev > 1)
|
|
{
|
|
for (int i = lev-2; i >= 0; i--)
|
|
code.insert("|", total_len(i));
|
|
}
|
|
return lev;
|
|
}
|
|
|
|
TMultilevel_code_info::TMultilevel_code_info(int logicnum) : _logicnum(logicnum), _parentnum(0)
|
|
{
|
|
if (_logicnum == LF_PCON)
|
|
{
|
|
_key1_fields.add(new TFieldref(PCN_GRUPPO, LF_PCON));
|
|
_picture.add("999");
|
|
_prompt.add(TR("Gruppo"));
|
|
|
|
_key1_fields.add(new TFieldref(PCN_CONTO, LF_PCON));
|
|
_picture.add("999");
|
|
_prompt.add(TR("Conto"));
|
|
|
|
_key1_fields.add(new TFieldref(PCN_SOTTOCONTO, LF_PCON));
|
|
_picture.add("999999");
|
|
_prompt.add(TR("Sottoconto"));
|
|
|
|
_key2_fields.add(new TFieldref(PCN_DESCR, LF_PCON));
|
|
}
|
|
else
|
|
{
|
|
TConfig& cfg = ca_config();
|
|
|
|
if (logicnum == LF_FASI)
|
|
{
|
|
const TString& father = cfg.get("FathFasi");
|
|
if (father == "CMS")
|
|
_parentnum = LF_COMMESSE; else
|
|
if (father == "CDC")
|
|
_parentnum = LF_CDC;
|
|
if (_parentnum != 0)
|
|
{
|
|
const TMultilevel_code_info& info = ca_multilevel_code_info(_parentnum);
|
|
for (int i = 0; i < info.levels(); i++)
|
|
{
|
|
_prompt.add(info.prompt(i));
|
|
_picture.add(info.picture(i));
|
|
TFieldref fr = info.fieldref(i);
|
|
fr.set_name("CODCMSFAS");
|
|
_key1_fields.add(fr);
|
|
}
|
|
}
|
|
}
|
|
|
|
TString16 keyvar, desvar;
|
|
get_cfg_vars(keyvar, desvar);
|
|
|
|
int from = 1, to = 1;
|
|
for (int level = 1; ; level++)
|
|
{
|
|
const TString& prompt = cfg.get(desvar, nullptr, level);
|
|
if (prompt.blank())
|
|
break;
|
|
_prompt.add(prompt);
|
|
|
|
const TString& picture = cfg.get(keyvar, nullptr, level);
|
|
_picture.add(picture);
|
|
|
|
const int keylen = picture.len();
|
|
to = from+keylen-1;
|
|
add_fieldref(1, from, to);
|
|
from = to+1;
|
|
}
|
|
add_fieldref(2, 0, 0);
|
|
}
|
|
|
|
const TRectype rec(logicnum);
|
|
rec.get_relapp(_editor);
|
|
}
|
|
|
|
const TMultilevel_code_info& ca_multilevel_code_info(int logicnum)
|
|
{
|
|
static TArray* cache = nullptr;
|
|
|
|
if (cache == nullptr)
|
|
cache = new TArray;
|
|
|
|
TMultilevel_code_info* info = (TMultilevel_code_info*)cache->objptr(logicnum);
|
|
|
|
if (info == nullptr)
|
|
{
|
|
info = new TMultilevel_code_info(logicnum);
|
|
cache->add(info, logicnum);
|
|
}
|
|
return *info;
|
|
}
|
|
|
|
const TMultilevel_code_info* ca_multilevel_code_info_by_index(int level)
|
|
{
|
|
static int _logicnum[3] = { -1, -1, -1 };
|
|
|
|
int logic = 0;
|
|
if (level >= 0 && level < 3)
|
|
{
|
|
// Riempie lista dei livelli, ad esempio:
|
|
// LF_COMMESSE, LF_FASI, LF_CDC oppure LF_COMMESSE, LF_CDC, ecc...
|
|
if (_logicnum[0] < 0)
|
|
{
|
|
TConfig& cfg = ca_config();
|
|
const TString& lev1 = cfg.get("Level", nullptr, 1);
|
|
|
|
if (lev1.full())
|
|
{
|
|
const TMultilevel_code_info& fasi = ca_multilevel_code_info(LF_FASI);
|
|
int k = 0;
|
|
_logicnum[k] = lev1 == "CDC" ? LF_CDC : LF_COMMESSE;
|
|
if (fasi.parent() == _logicnum[k])
|
|
_logicnum[++k] = LF_FASI;
|
|
|
|
const TString& lev2 = cfg.get("Level", nullptr, 2);
|
|
if (lev2.full())
|
|
{
|
|
_logicnum[++k] = _logicnum[0] == LF_COMMESSE ? LF_CDC : LF_COMMESSE;
|
|
if (fasi.parent() == _logicnum[k])
|
|
_logicnum[++k] = LF_FASI;
|
|
}
|
|
}
|
|
else
|
|
memset(_logicnum, 0, sizeof(_logicnum));
|
|
}
|
|
logic = _logicnum[level];
|
|
}
|
|
|
|
return logic > 0 ? &ca_multilevel_code_info(logic) : nullptr;
|
|
}
|
|
|
|
bool ca_test_multilevel_field(TEdit_field& fld, int level)
|
|
{
|
|
const int logic = fld.browse()->cursor()->curr().num();
|
|
const TMultilevel_code_info& info = ca_multilevel_code_info(logic);
|
|
const TString& pic = info.picture(level);
|
|
const TString& val = fld.get();
|
|
|
|
bool ok = val.len() <= pic.len();
|
|
for (int i = 0; val[i] && ok; i++)
|
|
{
|
|
const char v = val[i];
|
|
const char p = pic[i];
|
|
switch (p)
|
|
{
|
|
case 'A': ok = (v >= '0' && v <= '9') || (v >= 'A' && v <= 'Z'); break;
|
|
case '0': ok = (v >= '0' && v <= '9'); break;
|
|
case '9': ok = (v == ' ') || (v >= '0' && v <= '9'); break;
|
|
default : break;
|
|
}
|
|
}
|
|
if (!ok)
|
|
{
|
|
TString msg;
|
|
msg << TR("Il codice non rispetta il formato impostato nella configurazione")
|
|
<< '\n' << val << " <> " << pic;
|
|
return fld.error_box(msg);
|
|
}
|
|
|
|
return ok;
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////
|
|
// Utilities
|
|
///////////////////////////////////////////////////////////
|
|
|
|
const char* ca_dollar2fieldname(int logic, const char* dollar)
|
|
{
|
|
CHECKS(dollar && *dollar == '$', "False dollar", dollar);
|
|
//cerca il nome del campo della variabile dollarata nel file logic in questione
|
|
if (xvt_str_compare_ignoring_case(dollar, "$(CDC)") == 0)
|
|
{
|
|
switch (logic)
|
|
{
|
|
case LF_DOC: return DOC_CODCOSTO;
|
|
case LF_RIGHEDOC: return RDOC_CODCOSTO;
|
|
case LF_RMOVANA: return RMOVANA_CODCCOSTO;
|
|
case LF_SALDANA: return SALDANA_COSTO;
|
|
default : return CDC_CODCOSTO;
|
|
}
|
|
}
|
|
if (xvt_str_compare_ignoring_case(dollar, "$(CMS)") == 0)
|
|
{
|
|
switch (logic)
|
|
{
|
|
case LF_DOC: return DOC_CODCMS;
|
|
case LF_RIGHEDOC: return RDOC_CODCMS;
|
|
case LF_FASI: return FASI_CODCMSFAS;
|
|
case LF_RMOVANA: return RMOVANA_CODCMS;
|
|
case LF_SALDANA: return SALDANA_COMMESSA;
|
|
default : return COMMESSE_CODCOSTO;
|
|
}
|
|
}
|
|
if (xvt_str_compare_ignoring_case(dollar, "$(FAS)") == 0)
|
|
{
|
|
switch (logic)
|
|
{
|
|
case LF_DOC: return DOC_FASCMS;
|
|
case LF_RIGHEDOC: return RDOC_FASCMS;
|
|
case LF_RMOVANA: return RMOVANA_CODFASE;
|
|
case LF_SALDANA: return SALDANA_FASE;
|
|
default : return FASI_CODFASE;
|
|
}
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
void ca_append_and(TString& query, const TString& clause)
|
|
{
|
|
if (clause.full())
|
|
{
|
|
if (query.full())
|
|
{
|
|
query.insert("(");
|
|
query << ")&&(" << clause << ")";
|
|
}
|
|
else
|
|
query = clause;
|
|
}
|
|
}
|
|
|
|
static const TString& ca_get_user_permissions(const TString& utente, const int logic)
|
|
{
|
|
TString select;
|
|
|
|
const TString gruppo(cache().get(LF_USER, utente, "GROUPNAME"));
|
|
if (gruppo.full())
|
|
select = ca_get_user_permissions(gruppo, logic);
|
|
|
|
TFilename fileconf = firm2dir(-1); // Directory dati
|
|
fileconf.add("config"); // + Directory config
|
|
fileconf.add("ca0900conf.ini");
|
|
TConfig ini_permessi(fileconf);
|
|
|
|
if (ini_permessi.set_paragraph(utente))
|
|
{
|
|
const char* fieldname = nullptr;
|
|
|
|
switch (logic)
|
|
{
|
|
case LF_COMMESSE: fieldname = "Cms"; break;
|
|
case LF_CDC: fieldname = "Cdc"; break;
|
|
case LF_FASI: fieldname = "Fas"; break;
|
|
default: break;
|
|
}
|
|
if (fieldname != nullptr)
|
|
{
|
|
const TString& expr = ini_permessi.get(fieldname);
|
|
ca_append_and(select, expr);
|
|
|
|
//che programma sono che chiamo questa funzione?
|
|
const TFilename prog_name = main_app().argv(0);
|
|
TString16 key = prog_name.name_only();
|
|
key << " " << main_app().argv(1);
|
|
|
|
TToken_string row(80, SAFE_PIPE_CHR);
|
|
for (int r = 0;; r++)
|
|
{
|
|
row = ini_permessi.get("Prog", nullptr, r);
|
|
if (row.blank())
|
|
break;
|
|
if (key == row.get(0))
|
|
{
|
|
int column = 0;
|
|
switch (logic)
|
|
{
|
|
case LF_COMMESSE: column = 1; break;
|
|
case LF_CDC: column = 2; break;
|
|
case LF_FASI: column = 3; break;
|
|
default: break;
|
|
}
|
|
const TString& prog_expr = row.get(column);
|
|
ca_append_and(select, prog_expr);
|
|
} //if (key == row.get(0))...
|
|
} //for (int r = 0;; r++)...
|
|
|
|
} //if (fieldname...
|
|
|
|
} //if (ini_permessi.set...
|
|
|
|
return select.full() ? (get_tmp_string() = select) : EMPTY_STRING;
|
|
}
|
|
|
|
|
|
static const TString& ca_get_user_permissions_or_empty(const TString& utente, const int logic)
|
|
{
|
|
const TString& perm = ca_get_user_permissions(utente, logic);
|
|
if (perm.full())
|
|
{
|
|
TString& subclause = get_tmp_string();
|
|
subclause << "(" << perm << ")||($(";
|
|
switch (logic)
|
|
{
|
|
case LF_CDC: subclause << "CDC"; break;
|
|
case LF_COMMESSE: subclause << "CMS"; break;
|
|
case LF_FASI: subclause << "FAS"; break;
|
|
default: break;
|
|
}
|
|
subclause << ")==\"\")";
|
|
return subclause;
|
|
}
|
|
|
|
return EMPTY_STRING;
|
|
}
|
|
|
|
const TString& ca_create_user_select_clause(int logic)
|
|
{
|
|
static TArray clauses;
|
|
TString* clause = (TString*)clauses.objptr(logic);
|
|
|
|
if (clause == nullptr)
|
|
{
|
|
clause = new TString;
|
|
switch (logic)
|
|
{
|
|
case LF_CDC:
|
|
case LF_COMMESSE:
|
|
case LF_FASI:
|
|
*clause = ca_get_user_permissions(user(), logic);
|
|
break;
|
|
case LF_DOC:
|
|
case LF_RIGHEDOC:
|
|
case LF_RMOVANA:
|
|
case LF_SALDANA:
|
|
ca_append_and(*clause, ca_get_user_permissions_or_empty(user(), LF_CDC));
|
|
ca_append_and(*clause, ca_get_user_permissions_or_empty(user(), LF_COMMESSE));
|
|
ca_append_and(*clause, ca_get_user_permissions_or_empty(user(), LF_FASI));
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
for (int dollar = clause->find("$("); dollar >= 0; dollar = clause->find("$(", dollar))
|
|
{
|
|
const int closed = clause->find(')', dollar + 4);
|
|
const TString& before = clause->left(dollar);
|
|
const TString& field = clause->sub(dollar, closed + 1);
|
|
const TString& after = clause->mid(closed + 1);
|
|
clause->cut(0) << before << ca_dollar2fieldname(logic, field) << after;
|
|
}
|
|
clauses.add(clause, logic);
|
|
}
|
|
return *clause;
|
|
}
|
|
|
|
|
|
bool ca_filter_record(const TRectype& rec)
|
|
{
|
|
bool good = true;
|
|
const TString& filter = ca_create_user_select_clause(rec.num());
|
|
if (filter.full())
|
|
{
|
|
TExpression expr(filter, _strexpr);
|
|
for (int v = expr.numvar() - 1; v >= 0; v--)
|
|
{
|
|
const char* field = expr.varname(v);
|
|
expr.setvar(v, rec.get(field));
|
|
}
|
|
good = expr.as_bool();
|
|
}
|
|
return good;
|
|
}
|
|
|
|
|
|
bool ca_filter_function(const TRelation* rel)
|
|
{
|
|
return rel != nullptr && ca_filter_record(rel->curr());
|
|
}
|
|
|
|
|
|
static void ca_append_select_clause(ostream& out, int level, int logic, bool upper_limit)
|
|
{
|
|
TString str;
|
|
if (logic == LF_PCON)
|
|
{
|
|
switch (level)
|
|
{
|
|
case 0: str = "CONTO==\"\""; break;
|
|
case 1: str = "SOTTOCONTO==\"\""; break;
|
|
default: break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
const TMultilevel_code_info& mci = ca_multilevel_code_info(logic);
|
|
const int last_level = mci.levels()-1;
|
|
if (last_level > 0)
|
|
{
|
|
CHECKD(level>=0 && level <= last_level, "Bad analitic level ", level);
|
|
const TFieldref& key = mci.fieldref(level);
|
|
|
|
if (level > 0 && !upper_limit)
|
|
{
|
|
str << "STR(";
|
|
str << "(NUM(LEN(" << key.name() << "))>" << key.from() << ')'; // SE LEN(CODCONTO)>=4
|
|
}
|
|
if (level < last_level)
|
|
{
|
|
if (str.empty())
|
|
str = "STR(";
|
|
else
|
|
str << "&&";
|
|
str << "(NUM(LEN(" << key.name() << "))<=" << key.to() << ')'; // SE LEN(CODCONTO)<=7
|
|
}
|
|
if (str.not_empty())
|
|
str << ')';
|
|
}
|
|
}
|
|
|
|
const TString & condition = ca_create_user_select_clause(logic);
|
|
if (condition.full())
|
|
{
|
|
if (str.full())
|
|
{
|
|
str.insert("(");
|
|
str << ")&&";
|
|
}
|
|
str << '(' << condition << ')';
|
|
}
|
|
|
|
if (str.full())
|
|
out << " SE " << str << '\n';
|
|
}
|
|
|
|
static void ca_append_run_clause(ostream& out, int logicnum)
|
|
{
|
|
const TString& app = ca_multilevel_code_info(logicnum).editor();
|
|
if (app.not_empty())
|
|
out << "AD RU " << app << '\n';
|
|
}
|
|
|
|
static void init_tmp_filename(TFilename& name)
|
|
{
|
|
name.tempdir();
|
|
name.add("tmp.msk");
|
|
}
|
|
|
|
void ca_create_browse1(TEdit_field& kfld, int level, int logic, short key_id, short des_id)
|
|
{
|
|
const TMultilevel_code_info& main_info = ca_multilevel_code_info(logic);
|
|
bool add_select = false;
|
|
if (logic == LF_FASI)
|
|
{
|
|
const int par = main_info.parent();
|
|
if (par > 0)
|
|
{
|
|
const TMultilevel_code_info& parinfo = ca_multilevel_code_info(par);
|
|
if (level < parinfo.levels())
|
|
logic = par;
|
|
else
|
|
add_select = true;
|
|
}
|
|
}
|
|
|
|
const TMultilevel_code_info& mci = ca_multilevel_code_info(logic);
|
|
|
|
TFilename tmp; init_tmp_filename(tmp);
|
|
ofstream out(tmp);
|
|
|
|
out << "US " << logic << '\n';
|
|
ca_append_select_clause(out, level, logic, add_select);
|
|
ca_append_run_clause(out, logic);
|
|
|
|
bool req = false;
|
|
if ((logic == LF_COMMESSE || logic == LF_CDC) && kfld.mask().get_sheet()) // Sono in una maschera di riga?
|
|
{
|
|
if (main_app().name().starts_with("ci"))
|
|
{
|
|
if (logic == LF_COMMESSE)
|
|
req = ini_get_bool(CONFIG_DITTA, "ci", "CmsRequired");
|
|
else
|
|
req = ini_get_bool(CONFIG_DITTA, "ci", "CdcRequired");
|
|
}
|
|
else
|
|
{
|
|
TConfig& ini = ca_config();
|
|
|
|
if (logic == LF_COMMESSE)
|
|
req = ini.get_bool("CmsRequired");
|
|
else
|
|
req = ini.get_bool("CdcRequired");
|
|
}
|
|
}
|
|
|
|
for (int i = 0; i <= level; i++)
|
|
{
|
|
const TString& picture = mci.picture(i);
|
|
const TString& prompt = mci.prompt(i);
|
|
const TFieldref& field = mci.fieldref(i);
|
|
const int length = field.to() - field.from();
|
|
out << "IN " << field << ' ' << (key_id+i);
|
|
if ((add_select && field.name() == FASI_CODCMSFAS) || i < level)
|
|
out << " SE";
|
|
out << '\n';
|
|
out << "DI \"" << prompt;
|
|
if (length > prompt.len())
|
|
out << '@' << length;
|
|
out << "\" " << field << '\n';
|
|
out << "OU " << (key_id+i) << ' ' << field << '\n';
|
|
}
|
|
const TFieldref& field = mci.fieldref(0, 2);
|
|
out << "DI \"" << TR("Descrizione") << "@50\" " << field << '\n';
|
|
if (logic == LF_COMMESSE)
|
|
{
|
|
out << "DI \"" << TR("Proroga") << "\" PROROGA" << '\n';
|
|
out << "DI \"" << TR("Data") << "@10" << "\" DATAPROR" << '\n';
|
|
out << "DI \"" << TR("Chiusa") << "\" CHIUSA" << '\n';
|
|
}
|
|
out << "OU " << (des_id+level) << ' ' << field << '\n';
|
|
out << "CH " << (req ? "RE" : "NO") << '\n';
|
|
out << "FI " << main_info.fieldref(level) << '\n';
|
|
out << "EN" << '\n';
|
|
out.close();
|
|
|
|
TScanner scan(tmp);
|
|
while (scan.pop() != "EN")
|
|
kfld.parse_item(scan);
|
|
|
|
xvt_fsys_remove_file(tmp);
|
|
}
|
|
|
|
void ca_create_browse2(TEdit_field& kfld, int level, int logic, short key_id)
|
|
{
|
|
const TMultilevel_code_info& main_info = ca_multilevel_code_info(logic);
|
|
bool add_select = false;
|
|
if (logic == LF_FASI)
|
|
{
|
|
const int par = main_info.parent();
|
|
if (par > 0)
|
|
{
|
|
const TMultilevel_code_info& parinfo = ca_multilevel_code_info(par);
|
|
if (level < parinfo.levels())
|
|
logic = par;
|
|
else
|
|
add_select = true;
|
|
}
|
|
}
|
|
|
|
const TMultilevel_code_info& mci = ca_multilevel_code_info(logic);
|
|
|
|
const TFieldref& field = mci.fieldref(0, 2);
|
|
TString str2; str2 << field;
|
|
|
|
TFilename tmp; init_tmp_filename(tmp);
|
|
ofstream out(tmp);
|
|
|
|
out << "US " << logic << " KE 2" << '\n';
|
|
ca_append_select_clause(out, level, logic, add_select);
|
|
ca_append_run_clause(out, logic);
|
|
|
|
out << "IN " << str2 << ' ' << kfld.dlg() << '\n';
|
|
out << "DI \"" << TR("Descrizione") << "@50\" " << str2 << '\n';
|
|
|
|
out << "OU " << kfld.dlg() << ' ' << str2 << '\n';
|
|
|
|
for (int i = 0; i <= level; i++)
|
|
{
|
|
const TString& picture = mci.picture(i);
|
|
const TString& prompt = mci.prompt(i);
|
|
const TFieldref& field = mci.fieldref(i);
|
|
const int length = field.to() - field.from();
|
|
out << "DI \"" << prompt;
|
|
if (length > prompt.len())
|
|
{
|
|
out << '@' << length;
|
|
if (mci.is_numeric_picture(i))
|
|
out << 'R';
|
|
}
|
|
out << "\" " << field << '\n';
|
|
out << "OU " << (key_id+i) << ' ' << field << '\n';
|
|
}
|
|
if (logic == LF_COMMESSE)
|
|
{
|
|
out << "DI \"" << HR("Proroga") << "\" PROROGA" << '\n';
|
|
out << "DI \"" << HR("Data") << "@10" << "\" DATAPROR" << '\n';
|
|
out << "DI \"" << HR("Chiusa") << "\" CHIUSA" << '\n';
|
|
}
|
|
|
|
out << "CH NO" << '\n';
|
|
if (level == main_info.levels()-1)
|
|
out << "FI " << main_info.fieldref(0, 2) << '\n';
|
|
out << "EN" << '\n';
|
|
out.close();
|
|
|
|
TScanner scan(tmp);
|
|
while (scan.pop() != "EN")
|
|
kfld.parse_item(scan);
|
|
|
|
xvt_fsys_remove_file(tmp);
|
|
}
|
|
|
|
int ca_create_fields(TMask& msk, int page, int logicnum, int x, int y,
|
|
short key_id, short des_id, unsigned int mode, const char* fieldname, int from, bool desc_in_sh )
|
|
{
|
|
TWait_cursor hourglass;
|
|
const TMultilevel_code_info& mci = ca_multilevel_code_info(logicnum);
|
|
|
|
int maxkeylen = 0, maxdeslen = 0;
|
|
for (int level = 0; level < mci.levels(); level++)
|
|
{
|
|
const TString& prompt = mci.prompt(level);
|
|
const TString& picture = mci.picture(level);
|
|
const int keylen = picture.len();
|
|
const int deslen = prompt.len();
|
|
if (keylen > maxkeylen) maxkeylen = keylen;
|
|
if (deslen > maxdeslen) maxdeslen = deslen;
|
|
}
|
|
|
|
maxdeslen++;
|
|
const int tab0 = x;
|
|
const int tab1 = tab0 + maxdeslen + maxkeylen + 4;
|
|
|
|
if (key_id > 0 && (mode == 0 || (mode & 0x1) != 0))
|
|
{
|
|
const int parent_levels = mci.parent_levels();
|
|
for (int i = 0; i < mci.levels(); i++)
|
|
{
|
|
const short kid = key_id+i;
|
|
|
|
const TString& picture = mci.picture(i);
|
|
TString80 prompt = mci.prompt(i);
|
|
prompt.left_just(maxdeslen);
|
|
|
|
const char* flags = picture[0] == '0' || picture[0] == '9' ? "BUZ" : "BU";
|
|
TEdit_field* kfld = nullptr;
|
|
|
|
if (mci.is_numeric_picture(i)) // Numeric
|
|
kfld = &msk.add_number(kid, page, prompt, tab0, y+i, picture.len(), flags);
|
|
else
|
|
kfld = &msk.add_string(kid, page, prompt, tab0, y+i, picture.len(), flags);
|
|
ca_create_browse1(*kfld, i, logicnum, key_id, desc_in_sh && (i == mci.levels() - 1) ? key_id + mci.levels() - i : des_id);
|
|
if ((mode & 0x1) != 0 && fieldname == nullptr)
|
|
kfld->set_key(1);
|
|
|
|
// Ho specificato un nome di campo speciale
|
|
if (fieldname && *fieldname)
|
|
{
|
|
const TFieldref& fr = *kfld->field();
|
|
const char* campo = fieldname;
|
|
if (i < parent_levels)
|
|
{
|
|
// Aggiunsta nome campo principale
|
|
if (strcmp(campo, RMOVANA_CODFASE) == 0)
|
|
campo = mci.parent() == LF_COMMESSE ? RMOVANA_CODCMS : RMOVANA_CODCCOSTO;
|
|
}
|
|
|
|
TString80 str;
|
|
str.format("%s[%d,%d]", campo, fr.from()+from+1, fr.to()+from);
|
|
kfld->set_field(str);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (des_id > 0 && (mode == 0 || (mode & 0x2) != 0))
|
|
{
|
|
for (int i = 0; i < mci.levels(); i++)
|
|
{
|
|
const short did = desc_in_sh && (i == mci.levels() - 1) ? key_id+mci.levels() : des_id+i;
|
|
TEdit_field& dfld = msk.add_string(did, page, "", tab1, y+i, 50, "B", 72+tab0-tab1);
|
|
ca_create_browse2(dfld, i, logicnum, key_id);
|
|
if ((mode & 0x2) != 0 && fieldname == nullptr)
|
|
dfld.set_key(2);
|
|
else
|
|
dfld.set_field("");
|
|
}
|
|
}
|
|
|
|
return mci.levels();
|
|
}
|
|
|
|
int ca_create_fields_compact(TMask& msk, int page, int logicnum, int x, int y,
|
|
short key_id, short des_id, unsigned int mode, const char* fieldname, int from )
|
|
{
|
|
TWait_cursor hourglass;
|
|
const TMultilevel_code_info& mci = ca_multilevel_code_info(logicnum);
|
|
int par_items = 0;
|
|
|
|
if (logicnum == LF_FASI)
|
|
{
|
|
if (mci.parent() == LF_CDC)
|
|
par_items = ca_multilevel_code_info(LF_CDC).levels();
|
|
else
|
|
if (mci.parent() == LF_COMMESSE)
|
|
par_items = ca_multilevel_code_info(LF_COMMESSE).levels();
|
|
}
|
|
|
|
const int items = par_items > 0 ? par_items : mci.levels();
|
|
int maxkeylen = 0, maxdeslen = 0;
|
|
|
|
for (int level = 0; level < mci.levels(); level++)
|
|
{
|
|
const TString& picture = mci.picture(level);
|
|
const int keylen = picture.len();
|
|
int deslen = 0;
|
|
|
|
if ((level == 0 && items == 1) || (level == par_items && mci.levels() - par_items == 1))
|
|
deslen = mci.prompt(level).len();
|
|
else
|
|
deslen = logicnum != LF_FASI || mci.parent() > 0 ? 8 : 4 ;
|
|
if (deslen > maxdeslen) maxdeslen = deslen;
|
|
if (keylen > maxkeylen) maxkeylen = keylen;
|
|
}
|
|
|
|
maxdeslen++;
|
|
const int tab0 = x;
|
|
int offset = 0;
|
|
int desc_offset = 0;
|
|
int row_offset = 0;
|
|
|
|
if (key_id > 0 && (mode == 0 || (mode & 0x1) != 0))
|
|
{
|
|
for (int i = 0; i < mci.levels(); i++)
|
|
{
|
|
const short kid = key_id+i;
|
|
|
|
const TString& picture = mci.picture(i);
|
|
TString80 prompt;
|
|
|
|
if (i == 0)
|
|
{
|
|
int ln = logicnum;
|
|
if (ln == LF_FASI && mci.parent() > 0)
|
|
ln = mci.parent();
|
|
switch (ln)
|
|
{
|
|
case LF_PCONANA :
|
|
prompt = items == 1 ? mci.prompt(i) : "Conto";
|
|
break;
|
|
case LF_COMMESSE :
|
|
prompt = items == 1 ? mci.prompt(i) : "Commessa";
|
|
break;
|
|
case LF_CDC :
|
|
prompt = items == 1 ? mci.prompt(i) : "C. Costo";
|
|
break;
|
|
case LF_FASI :
|
|
prompt = items == 1 ? mci.prompt(i) : "Fase";
|
|
break;
|
|
default:
|
|
prompt = "Conto";
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
if (i == par_items)
|
|
prompt = mci.levels() - par_items == 1 ? mci.prompt(i) : "Fase" ;
|
|
|
|
|
|
if (prompt.full())
|
|
prompt.left_just(maxdeslen);
|
|
|
|
const char* flags = picture[0] == '0' || picture[0] == '9' ? "BUZG" : "BUG";
|
|
|
|
TEdit_field* kfld = nullptr;
|
|
|
|
if (mci.is_numeric_picture(i)) // Numeric
|
|
kfld = &msk.add_number(kid, page, prompt, tab0 + offset, y + row_offset, picture.len(), flags);
|
|
else
|
|
kfld = &msk.add_string(kid, page, prompt, tab0 + offset, y + row_offset, picture.len(), flags);
|
|
ca_create_browse1(*kfld, i, logicnum, key_id, des_id);
|
|
if ((mode & 0x1) != 0 && fieldname == nullptr)
|
|
kfld->set_key(1);
|
|
|
|
// Ho specificato un nome di campo speciale
|
|
if (fieldname && *fieldname)
|
|
{
|
|
const TFieldref& fr = *kfld->field();
|
|
|
|
TString80 str;
|
|
str.format("%s[%d,%d]", fieldname, fr.from()+from+1, fr.to()+from);
|
|
kfld->set_field(str);
|
|
}
|
|
TString war; war << mci.prompt(i) << ' ' << TR("assente");
|
|
kfld->set_warning(war);
|
|
offset += prompt.len() + picture.len() + 4;
|
|
if (desc_offset < offset)
|
|
desc_offset = offset;
|
|
if (i == par_items - 1)
|
|
{
|
|
row_offset++;
|
|
offset = 0;
|
|
}
|
|
|
|
// Copio il checktype nel campo fantasma per colorare correttamente la colonna
|
|
if (msk.get_sheet() != nullptr && kfld->required())
|
|
msk.efield(kid-100).check_type(kfld->check_type());
|
|
|
|
}
|
|
}
|
|
row_offset = 0;
|
|
const int tab1 = tab0 + desc_offset + 4;
|
|
if (des_id > 0 && (mode == 0 || (mode & 0x2) != 0))
|
|
{
|
|
for (int i = 0; i < mci.levels(); i++)
|
|
{
|
|
const short did = des_id+i;
|
|
TEdit_field& dfld = (i < mci.levels() - 1) && (i != par_items -1) ? msk.add_string(did, page, "", 50, 50, 50, "B")
|
|
: msk.add_string(did, page, "", tab1, y + row_offset, 50, "B", 72+tab0-tab1);
|
|
ca_create_browse2(dfld, i, logicnum, key_id);
|
|
if ((mode & 0x2) != 0 && fieldname == nullptr)
|
|
dfld.set_key(2);
|
|
else
|
|
dfld.set_field("");
|
|
if (i == par_items - 1)
|
|
row_offset++;
|
|
}
|
|
}
|
|
|
|
return mci.levels();
|
|
}
|
|
|
|
int ca_create_fields_ext(TMask& m, int page, int x, int y, short first_id,
|
|
short& first_cdc, short& first_cms, short& first_fase, short& first_conto,
|
|
const char* cdc_fld, const char* cms_fld, const char* fase_fld, const char* conto_fld)
|
|
{
|
|
int numero_campi = 0;
|
|
const TMultilevel_code_info& fasinfo = ca_multilevel_code_info(LF_FASI);
|
|
TConfig& ini = ca_config();
|
|
short dlg = first_id;
|
|
first_cdc = first_cms = first_fase = first_conto = 0;
|
|
|
|
for (int i = 0; i < 2; i++)
|
|
{
|
|
const TString& level = ini.get("Level", nullptr, i+1); // Legge il livello 1 o 2
|
|
|
|
if (level == "CDC" && cdc_fld && *cdc_fld) // Crea centro di costo
|
|
{
|
|
if (fasinfo.parent() == LF_CDC)
|
|
{
|
|
int h = ca_multilevel_code_info(LF_CDC).levels();
|
|
const int sh = ca_create_fields_compact(m, 0, LF_FASI, x, y, dlg, dlg + 50);
|
|
y += 2;
|
|
first_cdc = dlg;
|
|
first_fase = first_cdc + h;
|
|
dlg += sh;
|
|
numero_campi += sh;
|
|
}
|
|
else
|
|
{
|
|
const int sh = ca_create_fields_compact(m, 0, LF_CDC, x, y++, dlg, dlg + 50);
|
|
first_cdc = dlg;
|
|
dlg += sh;
|
|
numero_campi += sh;
|
|
}
|
|
} else
|
|
if (level == "CMS" && cms_fld && *cms_fld) // Crea commessa
|
|
{
|
|
const int h = ca_multilevel_code_info(LF_COMMESSE).levels();
|
|
int sh = 0;
|
|
if (fasinfo.parent() == LF_COMMESSE && fase_fld)
|
|
{
|
|
sh = ca_create_fields_compact(m, 0, LF_FASI, x, y, dlg, dlg + 50);
|
|
y += 2;
|
|
first_cms = dlg;
|
|
first_fase = first_cms + h;
|
|
dlg += sh;
|
|
numero_campi += sh;
|
|
}
|
|
else
|
|
{
|
|
sh = ca_create_fields_compact(m, 0, LF_COMMESSE, x, y++, dlg, dlg + 50);
|
|
first_cms = dlg;
|
|
dlg += sh;
|
|
numero_campi += sh;
|
|
}
|
|
|
|
for (int i = 0; i < sh; i++)
|
|
{
|
|
TEdit_field& ef = m.efield(first_cms+i);
|
|
const TFieldref& fr = *ef.field();
|
|
TString80 str;
|
|
if (i < h)
|
|
str.format("%s[%d,%d]", cms_fld, fr.from()+1, fr.to());
|
|
else
|
|
{
|
|
if (fase_fld)
|
|
{
|
|
if (sh == h+1)
|
|
str = fase_fld; // Fase monolivello: inutile range
|
|
else
|
|
str.format("%s[%d,%d]", fase_fld, fr.from()+1, fr.to());
|
|
}
|
|
}
|
|
ef.set_field(str);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (fasinfo.levels() > 0 && fasinfo.parent() <= 0 && fase_fld && *fase_fld) //Crea fase
|
|
{
|
|
const int sh = ca_create_fields_compact(m, 0, LF_FASI, x, y++, dlg, dlg + 50);
|
|
first_fase = dlg;
|
|
dlg += sh;
|
|
numero_campi += sh;
|
|
}
|
|
|
|
if (conto_fld && *conto_fld) //Crea conto
|
|
{
|
|
const bool use_pdcc = ini.get_bool("UsePdcc");
|
|
const int logicnum = use_pdcc ? LF_PCON : LF_PCONANA;
|
|
const int nfields = ca_create_fields_compact(m, 0, logicnum, x, y++, dlg, dlg + 50);
|
|
first_conto = nfields;
|
|
dlg += nfields;
|
|
numero_campi += nfields;
|
|
}
|
|
|
|
if (m.get_sheet() != nullptr) //Se è una maschera di riga, sistemo le colonne delle sheet
|
|
{
|
|
TSheet_field& s = *m.get_sheet();
|
|
for (short id = first_id + 116; id >= first_id + 100; id--)
|
|
{
|
|
const int pos = m.id2pos(id);
|
|
if (pos >= 0)
|
|
{
|
|
TMask_field& f = m.fld(pos);
|
|
const int size = f.size();
|
|
|
|
TString80 prompt = f.prompt(); prompt.trim();
|
|
if (prompt.blank())
|
|
{
|
|
TToken_string ts(((TEditable_field &)f).get_warning(), ' ');
|
|
prompt = ts.get(0);
|
|
}
|
|
s.set_column_header(id, prompt);
|
|
s.set_column_justify(id, f.is_kind_of(CLASS_REAL_FIELD));
|
|
s.set_column_width(id, (max(3+size, prompt.len()+1)) * CHARX);
|
|
s.enable_column(id);
|
|
m.efield(id-100).check_type(f.check_type()); // Copio il checktype nel campo fantasma per colorare correttamente la colonna
|
|
}
|
|
else
|
|
s.delete_column(id);
|
|
}
|
|
}
|
|
return numero_campi;
|
|
}
|
|
|
|
void ca_get_fields(TMask& m,
|
|
TString& cdc, TString& cms, TString& fase, TString& conto,
|
|
const short first_cdc, const short first_cms, const short first_fase, const short first_conto,
|
|
const char* cdc_fld, const char* cms_fld, const char* fase_fld, const char* conto_fld)
|
|
{
|
|
TString val;
|
|
cdc.cut(0);
|
|
cms.cut(0);
|
|
fase.cut(0);
|
|
conto.cut(0);
|
|
|
|
if (cdc_fld && *cdc_fld)
|
|
for (short id = first_cdc; id < first_cdc + 4; id++)
|
|
{
|
|
TMask_field& fld = m.field(id);
|
|
if(fld.prompt() != cdc_fld)
|
|
break;
|
|
val = fld.get();
|
|
val.rpad(fld.size());
|
|
cdc << val;
|
|
}
|
|
cdc.trim();
|
|
|
|
if (cms_fld && *cms_fld)
|
|
for (short id = first_cms; id < first_cms + 4; id++)
|
|
{
|
|
TMask_field& fld = m.field(id);
|
|
if(fld.prompt() != cms_fld)
|
|
break;
|
|
val = fld.get();
|
|
val.rpad(fld.size());
|
|
cms << val;
|
|
}
|
|
cms.trim();
|
|
|
|
if (fase_fld && *fase_fld)
|
|
for (short id = first_fase; id < first_fase + 4; id++)
|
|
{
|
|
TMask_field& fld = m.field(id);
|
|
if(fld.prompt() != fase_fld)
|
|
break;
|
|
val = fld.get();
|
|
val.rpad(fld.size());
|
|
fase << val;
|
|
}
|
|
fase.trim();
|
|
|
|
if (conto_fld && *conto_fld)
|
|
for (short id = first_conto; id <= first_conto + 4; id++)
|
|
{
|
|
TMask_field& fld = m.field(id);
|
|
if(fld.prompt() != conto_fld)
|
|
break;
|
|
val = fld.get();
|
|
val.rpad(fld.size());
|
|
conto << val;
|
|
}
|
|
conto.trim();
|
|
}
|
|
|
|
void ca_get_row_fields(TSheet_field& sheet, const int selected_row,
|
|
TString& cdc, TString& cms, TString& fase, TString& conto,
|
|
const short first_cdc, const short first_cms, const short first_fase, const short first_conto,
|
|
const char* cdc_fld, const char* cms_fld, const char* fase_fld, const char* conto_fld)
|
|
{
|
|
TString val;
|
|
cdc.cut(0);
|
|
cms.cut(0);
|
|
fase.cut(0);
|
|
conto.cut(0);
|
|
|
|
TToken_string& row = sheet.row(selected_row);
|
|
TMask& m = sheet.sheet_mask();
|
|
|
|
if (cdc_fld && *cdc_fld)
|
|
for (short id = first_cdc; id < first_cdc + 4; id++)
|
|
{
|
|
const TMask_field& fld = m.field(id);
|
|
if (fld.prompt() != cdc_fld)
|
|
break;
|
|
val = row.get(sheet.cid2index(id));
|
|
val.rpad(fld.size());
|
|
cdc << val;
|
|
}
|
|
cdc.trim();
|
|
|
|
if (cms_fld && *cms_fld)
|
|
for (short id = first_cms; id < first_cms + 4; id++)
|
|
{
|
|
const TMask_field& fld = m.field(id);
|
|
if (fld.prompt() != cms_fld)
|
|
break;
|
|
val = row.get(sheet.cid2index(id));
|
|
val.rpad(fld.size());
|
|
cms << val;
|
|
}
|
|
cms.trim();
|
|
|
|
if (fase_fld && *fase_fld)
|
|
for (short id = first_fase; id < first_fase + 4; id++)
|
|
{
|
|
const TMask_field& fld = m.field(id);
|
|
if (fld.prompt() != fase_fld)
|
|
break;
|
|
val = row.get(sheet.cid2index(id));
|
|
val.rpad(fld.size());
|
|
fase << val;
|
|
}
|
|
fase.trim();
|
|
|
|
if (conto_fld && *conto_fld)
|
|
for (short id = first_conto; id <= first_conto + 4; id++)
|
|
{
|
|
const TMask_field& fld = m.field(id);
|
|
if (fld.prompt() != conto_fld)
|
|
break;
|
|
val = row.get(sheet.cid2index(id));
|
|
val.rpad(fld.size());
|
|
conto << val;
|
|
}
|
|
conto.trim();
|
|
}
|
|
|
|
void ca_put_row_fields(TSheet_field& sheet, const int selected_row,
|
|
TString& cdc, TString& cms, TString& fase, TString& conto,
|
|
const short first_cdc, const short first_cms, const short first_fase, const short first_conto,
|
|
const char* cdc_fld, const char* cms_fld, const char* fase_fld, const char* conto_fld)
|
|
{
|
|
TMask& m = sheet.sheet_mask();
|
|
TToken_string& row = sheet.row(selected_row);
|
|
|
|
int pos = 0;
|
|
if (cdc_fld && *cdc_fld)
|
|
for (short id = first_cdc; id < first_cdc + 4; id++)
|
|
{
|
|
const TMask_field& fld = m.field(id);
|
|
if (fld.prompt() != cdc_fld)
|
|
break;
|
|
const int len = fld.size();
|
|
row.add(cdc.mid(pos, len), sheet.cid2index(id));
|
|
pos += len;
|
|
}
|
|
|
|
pos = 0;
|
|
if (cms_fld && *cms_fld)
|
|
for (short id = first_cms; id < first_cms + 4; id++)
|
|
{
|
|
const TMask_field& fld = m.field(id);
|
|
if (fld.prompt() != cms_fld)
|
|
break;
|
|
const int len = fld.size();
|
|
row.add(cdc.mid(pos, len), sheet.cid2index(id));
|
|
pos += len;
|
|
}
|
|
|
|
pos = 0;
|
|
if (fase_fld && *fase_fld)
|
|
for (short id = first_fase; id < first_fase + 4; id++)
|
|
{
|
|
const TMask_field& fld = m.field(id);
|
|
if(fld.prompt() != fase_fld)
|
|
break;
|
|
const int len = fld.size();
|
|
row.add(cdc.mid(pos, len), sheet.cid2index(id));
|
|
pos += len;
|
|
}
|
|
|
|
pos = 0;
|
|
if (conto_fld && *conto_fld)
|
|
for (short id = first_conto; id < first_conto + 4; id++)
|
|
{
|
|
const TMask_field& fld = m.field(id);
|
|
if (fld.prompt() != conto_fld)
|
|
break;
|
|
const int len = fld.size();
|
|
row.add(cdc.mid(pos, len), sheet.cid2index(id));
|
|
}
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////
|
|
// TAnal_tree_pos
|
|
///////////////////////////////////////////////////////////
|
|
|
|
struct TAnal_tree_pos : public TObject
|
|
{
|
|
TRecnotype _pos;
|
|
TToken_string _key;
|
|
bool _is_father;
|
|
|
|
void as_string(TString& id) const;
|
|
TRecnotype pos() const { return _pos; }
|
|
bool is_father() const { return _is_father; }
|
|
int level() const { return _key.items(); }
|
|
void reset();
|
|
void set(const char * key, TRecnotype pos, bool is_father);
|
|
|
|
TAnal_tree_pos() : _pos(0), _is_father(false) {}
|
|
TAnal_tree_pos(const TAnal_tree_pos& p) : _pos(p._pos), _is_father(p._is_father), _key(p._key) {}
|
|
TAnal_tree_pos(const char* id);
|
|
};
|
|
|
|
void TAnal_tree_pos::as_string(TString& id) const
|
|
{
|
|
id.format("%ld|%c|%s", _pos, _is_father ? 'F' : 'S', (const char*)_key);
|
|
}
|
|
|
|
void TAnal_tree_pos::set(const char * key, TRecnotype pos, bool is_father)
|
|
{
|
|
_key = key;
|
|
_pos = _key.full() ? pos : 0;
|
|
_is_father = is_father;
|
|
}
|
|
|
|
|
|
void TAnal_tree_pos::reset()
|
|
{
|
|
_key.cut(0);
|
|
_pos = 0;
|
|
_is_father = false;
|
|
}
|
|
|
|
TAnal_tree_pos::TAnal_tree_pos(const char* id)
|
|
{
|
|
TToken_string ts(id);
|
|
_pos = ts.get_long(0);
|
|
_is_father = ts.get_char(1) == 'F';
|
|
int pipe = ts.find(ts.separator());
|
|
pipe = ts.find(ts.separator(), pipe+1);
|
|
_key = ts.mid(pipe+1);
|
|
}
|
|
|
|
class TAnal_tree : public TBidirectional_tree
|
|
{
|
|
TCursor* _curs;
|
|
TCursor* _father_curs;
|
|
int _fathfasi;
|
|
bool _is_father;
|
|
TAnal_tree_pos _curr;
|
|
|
|
protected:
|
|
virtual void node2id(const TObject* node, TString& id) const;
|
|
|
|
virtual bool could_have_son() const;
|
|
virtual bool has_son() const;
|
|
virtual bool has_father() const;
|
|
virtual bool goto_firstson();
|
|
virtual bool goto_rbrother();
|
|
virtual bool goto_node(const TString &id);
|
|
virtual TObject* curr_node() const;
|
|
virtual bool goto_father();
|
|
virtual bool goto_lbrother();
|
|
virtual bool get_description(TString& desc) const;
|
|
virtual TImage* image(bool selected) const;
|
|
|
|
protected:
|
|
void update_curr();
|
|
int level_of(const TToken_string& key) const;
|
|
int level_of_file() const;
|
|
const TToken_string& curr_of_file() const;
|
|
int curr_level() const;
|
|
int max_level() const;
|
|
const TToken_string& father_of(const TToken_string& key) const;
|
|
const TToken_string& father_of_file() const;
|
|
bool repos() const;
|
|
|
|
public:
|
|
virtual bool goto_root();
|
|
|
|
TAnal_tree(int logicnum);
|
|
virtual ~TAnal_tree();
|
|
};
|
|
|
|
///////////////////////////////////////////////////////////
|
|
// TAnal_msk
|
|
///////////////////////////////////////////////////////////
|
|
|
|
#define F_TREE 99
|
|
|
|
short TSimple_anal_msk::get_field_id(int n, int k) const
|
|
{
|
|
short id = 0;
|
|
if (n >= 0 && n < fieldrefs(1))
|
|
{
|
|
if (k == 1)
|
|
id = F_KEY1+n;
|
|
else
|
|
id = F_DES1+n;
|
|
}
|
|
return id;
|
|
}
|
|
|
|
bool TSimple_anal_msk::test_key_field(short id)
|
|
{
|
|
TEdit_field& fld = efield(id);
|
|
const int level = id - F_KEY1;
|
|
return ca_test_multilevel_field(fld, level);
|
|
}
|
|
|
|
const char * TSimple_anal_msk::get_curr_key() const
|
|
{
|
|
const TTree_field& fld = tfield(F_TREE);
|
|
const TTree& tree = *fld.tree();
|
|
TToken_string & curr = get_tmp_string(100);
|
|
|
|
tree.curr_id(curr);
|
|
curr.destroy(1);
|
|
curr.destroy(0);
|
|
|
|
return curr;
|
|
}
|
|
|
|
bool TSimple_anal_msk::on_field_event(TOperable_field& o, TField_event e, long jolly)
|
|
{
|
|
switch (o.dlg())
|
|
{
|
|
case F_TREE:
|
|
if (e == fe_modify)
|
|
{
|
|
if (edit_mode() && !dirty())
|
|
set_mode(MODE_QUERY);
|
|
if (query_mode())
|
|
{
|
|
const TTree_field& fld = (const TTree_field&)o;
|
|
const TTree& tree = *fld.tree();
|
|
TToken_string curr; tree.curr_id(curr);
|
|
TEdit_field* last = nullptr;
|
|
|
|
for (int i = 0; ; i++)
|
|
{
|
|
const short id = get_field_id(i);
|
|
if (id <= 0)
|
|
break;
|
|
const char* tok = curr.get(i+2);
|
|
TEdit_field& e = efield(id);
|
|
e.set(tok);
|
|
e.show();
|
|
//attenzione!!! modifica necessaria per poter ripulire in automatico i campi inutili al cambio struttura..
|
|
//..del piano dei conti (selezionandone una diversa sull'albero della maschera) e per non avere un warning..
|
|
//..dalla last->check() che andrebbe a fare la check su un campo vuoto
|
|
if (tok && *tok)
|
|
last = &e;
|
|
}
|
|
if (last != nullptr)
|
|
{
|
|
if (last->check())
|
|
stop_run(K_AUTO_ENTER);
|
|
else
|
|
cantaccess_box(TR("questo record"));
|
|
}
|
|
}
|
|
else
|
|
beep(0);
|
|
}
|
|
break;
|
|
case F_KEY1:
|
|
case F_KEY2:
|
|
case F_KEY3:
|
|
case F_KEY4:
|
|
if ((jolly == 0) &&(e == fe_modify || e == fe_close))
|
|
return test_key_field(o.dlg());
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
int TSimple_anal_msk::compute_offset() const
|
|
{
|
|
int delta = 0;
|
|
if (create_tree())
|
|
{
|
|
RCT rct; xvt_vobj_get_client_rect(TASK_WIN, &rct);
|
|
if (rct.right > 720)
|
|
delta = (rct.right - 720) / 2 / CHARX;
|
|
|
|
if (delta > 0)
|
|
{
|
|
int ln = get_logicnum();
|
|
if (ln == LF_FASI)
|
|
{
|
|
const TString& ff = ca_config().get("FathFasi");
|
|
if (ff.full())
|
|
ln = (ff == "CMS") ? LF_COMMESSE : LF_CDC;
|
|
}
|
|
TLocalisamfile lif(ln);
|
|
const TRecnotype recs = lif.items();
|
|
}
|
|
}
|
|
return delta;
|
|
}
|
|
|
|
void TSimple_anal_msk::read(const char* name)
|
|
{
|
|
const int delta = compute_offset();
|
|
|
|
if (delta > 0)
|
|
{
|
|
TFilename outname; init_tmp_filename(outname);
|
|
TFilename inpname = name; inpname.ext("msk");
|
|
inpname.custom_path();
|
|
|
|
ofstream out(outname);
|
|
|
|
TString line;
|
|
int status = 0;
|
|
TScanner inp(inpname);
|
|
while (!inp.eof())
|
|
{
|
|
line = inp.line();
|
|
switch (status)
|
|
{
|
|
case 0:
|
|
if (line.starts_with("PA"))
|
|
status = 1; // Ho trovato la prima pagina
|
|
break;
|
|
case 1:
|
|
if (line.starts_with("PR")) // Ho trovato un prompt sulla prima pagina
|
|
{
|
|
TToken_string l(line, ' ');
|
|
int x = l.get_int(1);
|
|
if (x >= 0)
|
|
{
|
|
x += delta;
|
|
l.add(x, 1);
|
|
line = l;
|
|
}
|
|
} else
|
|
if (line.starts_with("PA")) // Ho finito la prima pagina
|
|
{
|
|
status = 2;
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
out << line << endl;
|
|
}
|
|
out.close();
|
|
|
|
read_mask(outname, 0, 0);
|
|
xvt_fsys_remove_file(outname);
|
|
set_source_file(inpname);
|
|
}
|
|
else
|
|
read_mask(name, 0, 0);
|
|
|
|
create_key_fields();
|
|
create_tree_field();
|
|
}
|
|
|
|
short TSimple_anal_msk::create_tree_field()
|
|
{
|
|
short id = 0;
|
|
const int delta = compute_offset();
|
|
if (delta > 0)
|
|
{
|
|
id = F_TREE;
|
|
add_tree(id, 0, 0, 1, (delta-1)*2, -1);
|
|
|
|
TAnal_tree* t = new TAnal_tree(get_logicnum());
|
|
tfield(id).set_tree(t);
|
|
t->goto_root();
|
|
t->expand();
|
|
}
|
|
set_handlers();
|
|
return id;
|
|
}
|
|
|
|
void TSimple_anal_msk::update_tree_field()
|
|
{
|
|
const int pos = id2pos(F_TREE);
|
|
if (pos >= 0)
|
|
{
|
|
TTree_field& t = tfield(F_TREE);
|
|
t.win().force_update();
|
|
}
|
|
}
|
|
|
|
int TSimple_anal_msk::fieldrefs(int k) const
|
|
{
|
|
int n = 1;
|
|
if (k == 1)
|
|
{
|
|
const TMultilevel_code_info& mci = ca_multilevel_code_info(get_logicnum());
|
|
n = mci.levels();
|
|
}
|
|
return n;
|
|
}
|
|
|
|
const TFieldref& TSimple_anal_msk::fieldref(int n, int k) const
|
|
{
|
|
const TMultilevel_code_info& mci = ca_multilevel_code_info(get_logicnum());
|
|
return mci.fieldref(n, k);
|
|
|
|
}
|
|
|
|
const TToken_string& TSimple_anal_msk::get_key_value(const TRectype& rec, int c) const
|
|
{
|
|
TToken_string& val = get_tmp_string();
|
|
const int tot = fieldrefs(c);
|
|
for (int i = 0; i < tot; i++)
|
|
{
|
|
const TFieldref& field = fieldref(i, c);
|
|
val.add(field.read(rec));
|
|
}
|
|
return val;
|
|
}
|
|
|
|
const TToken_string& TSimple_anal_msk::get_key_value(int c) const
|
|
{
|
|
TToken_string& val = get_tmp_string();
|
|
|
|
for (TEditable_field* f = get_key_field(c, true); f != nullptr; f = get_key_field(c, false))
|
|
{
|
|
val.add(f->get());
|
|
}
|
|
return val;
|
|
}
|
|
|
|
int TSimple_anal_msk::create_key_fields()
|
|
{
|
|
const int logic = get_logicnum();
|
|
const short kid = get_field_id(0, 1);
|
|
const short did = get_field_id(0, 2);
|
|
const int x = compute_offset()+3;
|
|
const int y = 1;
|
|
const int n = ca_create_fields(*this, 0, logic, x, y, kid, did, 0x1);
|
|
const int m = ca_create_fields(*this, 0, logic, x, y, kid, did, 0x2);
|
|
first_focus(kid);
|
|
return n;
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////
|
|
// TAnal_tree
|
|
///////////////////////////////////////////////////////////
|
|
|
|
const TToken_string& TAnal_tree::curr_of_file() const
|
|
{
|
|
const TRectype& rec = _is_father ? _father_curs->curr() : _curs->curr();
|
|
|
|
const TMultilevel_code_info& mci = ca_multilevel_code_info(rec.num());
|
|
TToken_string& k = get_tmp_string();
|
|
|
|
for (int i = 0; i < mci.levels(); i++)
|
|
{
|
|
const TFieldref& fld = mci.fieldref(i);
|
|
k.add(fld.read(rec));
|
|
}
|
|
|
|
for (int j = k.len()-1; j >= 0; j--)
|
|
{
|
|
if (k[j] == ' ' || k[j] == k.separator())
|
|
k.cut(j);
|
|
else
|
|
break;
|
|
}
|
|
|
|
return k;
|
|
}
|
|
|
|
int TAnal_tree::level_of(const TToken_string& k) const
|
|
{
|
|
return k.items();
|
|
}
|
|
|
|
int TAnal_tree::level_of_file() const
|
|
{
|
|
const TToken_string& str = curr_of_file();
|
|
return level_of(str);
|
|
}
|
|
|
|
int TAnal_tree::curr_level() const
|
|
{
|
|
return level_of(_curr._key);
|
|
}
|
|
|
|
int TAnal_tree::max_level() const
|
|
{
|
|
const int logic = _curs->relation()->lfile().num();
|
|
const TMultilevel_code_info& mci = ca_multilevel_code_info(logic);
|
|
return mci.levels();
|
|
}
|
|
|
|
const TToken_string& TAnal_tree::father_of(const TToken_string& key) const
|
|
{
|
|
const int pos = key.rfind(key.separator());
|
|
if (pos <= 0)
|
|
return EMPTY_STRING;
|
|
|
|
TToken_string& k = get_tmp_string();
|
|
k = key.left(pos);
|
|
return k;
|
|
}
|
|
|
|
const TToken_string& TAnal_tree::father_of_file() const
|
|
{
|
|
const TToken_string& k = curr_of_file();
|
|
return father_of(k);
|
|
}
|
|
|
|
void TAnal_tree::update_curr()
|
|
{
|
|
_curr.set(curr_of_file(), _is_father ? _father_curs->pos() : _curs->pos(), _is_father);
|
|
}
|
|
|
|
bool TAnal_tree::repos() const
|
|
{
|
|
bool ok = false;
|
|
if (_curr.level() > 0)
|
|
{
|
|
if (_is_father)
|
|
{
|
|
if (_father_curs->pos() != _curr.pos())
|
|
((TCursor&)*_father_curs) = _curr.pos();
|
|
}
|
|
else
|
|
{
|
|
if (_curs->pos() != _curr.pos())
|
|
((TCursor&) *_curs) = _curr.pos();
|
|
}
|
|
ok = true;
|
|
}
|
|
return ok;
|
|
}
|
|
|
|
void TAnal_tree::node2id(const TObject* node, TString& id) const
|
|
{
|
|
const TAnal_tree_pos* pos = (const TAnal_tree_pos*)node;
|
|
pos->as_string(id);
|
|
}
|
|
|
|
bool TAnal_tree::goto_root()
|
|
{
|
|
bool ok = false;
|
|
|
|
//gestione speciale per le fasi con babbo
|
|
if (_father_curs != nullptr)
|
|
{
|
|
if (_father_curs->items() > 0)
|
|
{
|
|
*_father_curs = 0L;
|
|
_is_father = true;
|
|
update_curr();
|
|
ok = true;
|
|
}
|
|
else
|
|
_curr.reset();
|
|
}
|
|
else //caso standard (cms, cdc, fasi senza babbo)
|
|
{
|
|
if (_curs->items() > 0)
|
|
{
|
|
*_curs = 0L;
|
|
update_curr();
|
|
ok = true;
|
|
}
|
|
else
|
|
_curr.reset();
|
|
}
|
|
return ok;
|
|
}
|
|
|
|
bool TAnal_tree::has_father() const
|
|
{ return _curr.level() > 1; }
|
|
|
|
bool TAnal_tree::could_have_son() const
|
|
{ return _curr.level() < max_level(); }
|
|
|
|
bool TAnal_tree::has_son() const
|
|
{
|
|
if (!could_have_son())
|
|
return false;
|
|
|
|
if (_is_father && _father_curs)
|
|
{
|
|
const int father_logic = _father_curs->file().num(); // LF_COMMESSE o LF_CDC
|
|
const TMultilevel_code_info& fci = ca_multilevel_code_info(father_logic);
|
|
const int son_lev = _curr.level() + 1;
|
|
if (son_lev > fci.levels())
|
|
{
|
|
TLocalisamfile& fasi = _curs->file();
|
|
fasi.zero();
|
|
fasi.put(FASI_CODCMSFAS, _curr._key);
|
|
return fasi.read(_isgteq) == NOERR && fasi.get(FASI_CODCMSFAS) == _curr._key;
|
|
}
|
|
}
|
|
|
|
return TBidirectional_tree::has_son();
|
|
}
|
|
|
|
|
|
bool TAnal_tree::goto_firstson()
|
|
{
|
|
bool ok = _curr.level() < max_level() && repos();
|
|
if (ok)
|
|
{
|
|
if (_is_father && _father_curs)
|
|
{
|
|
const TMultilevel_code_info& fci = ca_multilevel_code_info(_father_curs->file().num());
|
|
const int son_lev = _curr.level() + 1;
|
|
if (son_lev > fci.levels())
|
|
{
|
|
TRectype& rec = _curs->curr();
|
|
rec.zero();
|
|
rec.put(FASI_CODCMSFAS, _curr._key);
|
|
ok = _curs->read() >= 0 && rec.get(FASI_CODCMSFAS) == _curr._key;
|
|
if (ok)
|
|
{
|
|
_is_father = false; // Forzo cursore fasi prima della update_curr
|
|
update_curr();
|
|
}
|
|
else
|
|
repos();
|
|
return ok;
|
|
}
|
|
}
|
|
|
|
TCursor& c = _is_father ? *_father_curs : *_curs;
|
|
ok = c.pos() < c.items();
|
|
if (ok)
|
|
{
|
|
++c;
|
|
ok = father_of_file() == _curr._key;
|
|
if (ok)
|
|
update_curr();
|
|
}
|
|
}
|
|
return ok;
|
|
}
|
|
|
|
bool TAnal_tree::goto_rbrother()
|
|
{
|
|
bool ok = false;
|
|
if (repos())
|
|
{
|
|
TCursor& c = _is_father ? *_father_curs : *_curs;
|
|
const TToken_string curr_father = father_of(_curr._key);
|
|
++c;
|
|
while (ok = c.pos() < c.items())
|
|
{
|
|
const int lev = level_of_file();
|
|
if (lev <= _curr.level())
|
|
{
|
|
const TToken_string& next_father = father_of_file();
|
|
ok = next_father == curr_father;
|
|
break;
|
|
}
|
|
++c;
|
|
}
|
|
if (ok)
|
|
update_curr();
|
|
}
|
|
return ok;
|
|
}
|
|
|
|
bool TAnal_tree::goto_node(const TString &id)
|
|
{
|
|
const TAnal_tree_pos ap(id);
|
|
|
|
const TRecnotype rec = ap.pos();
|
|
_is_father = ap.is_father();
|
|
TCursor& c = _is_father ? *_father_curs : *_curs;
|
|
if (rec >= 0L && rec < c.items())
|
|
{
|
|
c = rec;
|
|
update_curr();
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool TAnal_tree::goto_father()
|
|
{
|
|
const int lev = _curr.level();
|
|
bool ok = lev > 1;
|
|
if (ok)
|
|
{
|
|
const int logicnum = _curs->relation()->lfile().num();
|
|
if (logicnum == LF_FASI && !_is_father)
|
|
{
|
|
const TMultilevel_code_info& mci = ca_multilevel_code_info(logicnum);
|
|
if (mci.parent() != 0)
|
|
{
|
|
const TMultilevel_code_info& fci = ca_multilevel_code_info(mci.parent());
|
|
_is_father = fci.levels() <= lev-1;
|
|
}
|
|
}
|
|
|
|
TCursor& c = *(_is_father ? _father_curs : _curs);
|
|
TRectype& rec = c.curr();
|
|
rec.zero();
|
|
|
|
const TMultilevel_code_info& mci = ca_multilevel_code_info(rec.num());
|
|
for (int i = 0; i < lev-1; i++)
|
|
{
|
|
const char* val = _curr._key.get(i);
|
|
const TFieldref& fld = mci.fieldref(i);
|
|
fld.write(val, rec);
|
|
}
|
|
ok = c.read() == NOERR;
|
|
if (ok)
|
|
{
|
|
update_curr();
|
|
CHECKD(_curr.level() < lev, "Invalid analitic node level: father=son=", lev);
|
|
}
|
|
}
|
|
return ok;
|
|
}
|
|
|
|
bool TAnal_tree::goto_lbrother()
|
|
{
|
|
bool ok = false;
|
|
if (repos())
|
|
{
|
|
const TString curr_father = father_of(_curr._key);
|
|
TCursor& c = _is_father ? *_father_curs : *_curs;
|
|
--c;
|
|
while (ok = c.pos() > 0L)
|
|
{
|
|
const int lev = level_of_file();
|
|
if (lev <= _curr.level())
|
|
{
|
|
const TString& next_father = father_of_file();
|
|
ok = next_father == curr_father;
|
|
break;
|
|
}
|
|
--c;
|
|
}
|
|
if (ok)
|
|
update_curr();
|
|
}
|
|
return ok;
|
|
}
|
|
|
|
TObject* TAnal_tree::curr_node() const
|
|
{
|
|
return (TObject*)&_curr;
|
|
}
|
|
|
|
bool TAnal_tree::get_description(TString& desc) const
|
|
{
|
|
const bool ok = repos();
|
|
if (ok)
|
|
{
|
|
const int lev = _curr.level();
|
|
if (lev > 0)
|
|
{
|
|
TCursor& c = _is_father ? *_father_curs : *_curs;
|
|
const TRectype& rec = c.curr();
|
|
const TMultilevel_code_info& mci = ca_multilevel_code_info(rec.num());
|
|
const TFieldref& fld1 = mci.fieldref(lev-1, 1);
|
|
const TFieldref& fld2 = mci.fieldref(0, 2);
|
|
desc = fld1.read(rec);
|
|
desc << ' ' << fld2.read(rec);
|
|
}
|
|
}
|
|
return ok;
|
|
}
|
|
|
|
TImage* TAnal_tree::image(bool selected) const
|
|
{
|
|
short bmp_id = BMP_FILE;
|
|
if (has_son())
|
|
bmp_id = selected ? BMP_DIRDN : BMP_DIR;
|
|
return get_res_image(bmp_id);
|
|
}
|
|
|
|
TAnal_tree::TAnal_tree(int logicnum) : _curs(nullptr), _father_curs(nullptr), _is_father(false)
|
|
{
|
|
TString select;
|
|
_curs = new TCursor(new TRelation(logicnum), ca_create_user_select_clause(logicnum));
|
|
_fathfasi = 0;
|
|
if (logicnum == LF_FASI)
|
|
{
|
|
const TString& ff = ca_config().get("FathFasi");
|
|
if (ff.full())
|
|
{
|
|
_fathfasi = (ff == "CMS") ? LF_COMMESSE : LF_CDC;
|
|
_father_curs = new TCursor(new TRelation(_fathfasi), ca_create_user_select_clause(_fathfasi));
|
|
}
|
|
}
|
|
}
|
|
|
|
TAnal_tree::~TAnal_tree()
|
|
{
|
|
delete _curs;
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////////////////
|
|
// TAnal_app
|
|
///////////////////////////////////////////////////////////
|
|
|
|
void TAnal_app::init_key_fields(TSimple_anal_msk & m) const
|
|
{
|
|
int maxlev = 0;
|
|
for (maxlev = 0; maxlev < 4; maxlev++)
|
|
{
|
|
const short id = m.get_field_id(maxlev, 1);
|
|
if (id <= 0 || m.id2pos(id) < 0)
|
|
break;
|
|
m.disable(id);
|
|
|
|
const short did = m.get_field_id(maxlev, 2);
|
|
m.disable(did);
|
|
}
|
|
|
|
bool found = false;
|
|
for (int i = maxlev-1; i >= 0; i--)
|
|
{
|
|
const short id = m.get_field_id(i, 1);
|
|
TEdit_field& e = m.efield(id);
|
|
const short did = m.get_field_id(i, 2);
|
|
TEdit_field& d = m.efield(did);
|
|
|
|
if (e.empty())
|
|
{
|
|
e.hide();
|
|
d.hide();
|
|
}
|
|
else
|
|
{
|
|
e.show();
|
|
e.check(STARTING_CHECK);
|
|
|
|
//trattamento speciale per il FIELD delle descrizioni; senza questo if(, si avrebbe la descrizione dell'ultimo..
|
|
//..campo in tutte le descrizioni precedenti! 15/05/2009
|
|
TString80 key2;
|
|
if (!found)
|
|
{
|
|
key2 << m.fieldref(0, 2);
|
|
found = true;
|
|
}
|
|
|
|
d.set_field(key2);
|
|
d.show();
|
|
d.enable();
|
|
m.first_focus(d.dlg());
|
|
d.enable_check(false);
|
|
}
|
|
}
|
|
}
|
|
|
|
TRelation* TAnal_app::create_relation() const
|
|
{
|
|
return new TRelation(_msk->get_logicnum());
|
|
}
|
|
|
|
bool TAnal_app::user_create()
|
|
{
|
|
_msk = create_mask();
|
|
_rel = create_relation();
|
|
return true;
|
|
}
|
|
|
|
void TAnal_app::init_query_mode(TMask& mask)
|
|
{
|
|
TSimple_anal_msk& m = (TSimple_anal_msk&)mask;
|
|
int i;
|
|
|
|
for (i = 0; ; i++)
|
|
{
|
|
const short id = m.get_field_id(i, 1);
|
|
if (id <= 0 || m.id2pos(id) < 0)
|
|
break;
|
|
|
|
TEdit_field& e = m.efield(id);
|
|
e.show(); e.enable();
|
|
|
|
const short did = m.get_field_id(i, 2);
|
|
TEdit_field& d = m.efield(did);
|
|
d.show(); d.enable();
|
|
d.enable_check();
|
|
d.set_field("");
|
|
}
|
|
|
|
if (m.id2pos(F_TREE) > 0)
|
|
{
|
|
TToken_string keys(m.get_curr_key());
|
|
|
|
for (int j = 0 ; j < i - 1; j++)
|
|
{
|
|
const short id = m.get_field_id(j, 1);
|
|
TEdit_field& e = m.efield(id);
|
|
|
|
e.set(keys.get(j));
|
|
}
|
|
}
|
|
m.first_focus(m.get_field_id(0, 1));
|
|
}
|
|
|
|
void TAnal_app::init_modify_mode(TMask& mask)
|
|
{
|
|
init_key_fields((TSimple_anal_msk &)mask);
|
|
}
|
|
|
|
void TAnal_app::init_insert_mode(TMask& mask)
|
|
{
|
|
init_key_fields((TSimple_anal_msk &)mask);
|
|
}
|
|
|
|
int TAnal_app::write(const TMask& m)
|
|
{
|
|
const int err = TRelation_application::write(m);
|
|
_msk->update_tree_field();
|
|
return err;
|
|
}
|
|
|
|
int TAnal_app::rewrite(const TMask& m)
|
|
{
|
|
const int err = TRelation_application::rewrite(m);
|
|
_msk->update_tree_field();
|
|
return err;
|
|
}
|
|
|
|
bool TAnal_app::remove()
|
|
{
|
|
bool ok = TRelation_application::remove();
|
|
_msk->update_tree_field();
|
|
return ok;
|
|
}
|
|
|
|
bool TAnal_app::user_destroy()
|
|
{
|
|
SAFE_DELETE(_msk);
|
|
SAFE_DELETE(_rel);
|
|
return true;
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////
|
|
// TAnal_mov
|
|
///////////////////////////////////////////////////////////
|
|
|
|
const char * TAnal_mov::row_anal_code(int logicnum, int row) const
|
|
{
|
|
const TMultilevel_code_info & c = ca_multilevel_code_info(logicnum);
|
|
const int levels = c.levels();
|
|
TString & code = get_tmp_string();
|
|
|
|
for (int i = 0; i < levels; i++)
|
|
{
|
|
TFieldref fr = c.fieldref(i);
|
|
|
|
if (fr.name() == "CODCOSTO")
|
|
fr.set_name(RMOVANA_CODCCOSTO);
|
|
if (logicnum == LF_FASI && fr.name() == "CODCMSFAS")
|
|
continue;
|
|
|
|
const TString & s = fr.read(body()[row]);
|
|
|
|
if (s.full())
|
|
{
|
|
if (code.full())
|
|
code << " ";
|
|
code << s;
|
|
}
|
|
}
|
|
return code;
|
|
}
|
|
|
|
const char * TAnal_mov::row_code(int row) const
|
|
{
|
|
const TMultilevel_code_info & fasi = ca_multilevel_code_info(LF_FASI);
|
|
TConfig& cfg = ca_config();
|
|
bool fase_added = false;
|
|
const TString16 codfase(row_anal_code(LF_FASI, row));
|
|
bool fase_to_add = codfase.full();
|
|
TString code;
|
|
|
|
for (int i = 0; i < 2; i++)
|
|
{
|
|
const TString& level = cfg.get("Level", nullptr, i+1); // Legge il livello 1 o 2
|
|
|
|
if (level == "CDC") // Crea centro di costo
|
|
{
|
|
const TString & codcdc = row_anal_code(LF_CDC, row);
|
|
|
|
if (codcdc.full())
|
|
{
|
|
if (code.full())
|
|
code << " ";
|
|
code << codcdc;
|
|
}
|
|
if (fase_to_add && fasi.parent() == LF_CDC)
|
|
{
|
|
if (code.full())
|
|
code << " ";
|
|
code << codfase;
|
|
fase_to_add = false;
|
|
}
|
|
}
|
|
else
|
|
if (level == "CMS") // Crea centro di costo
|
|
{
|
|
const TString & codcms = row_anal_code(LF_COMMESSE, row);
|
|
|
|
if (codcms.full())
|
|
{
|
|
if (code.full())
|
|
code << " ";
|
|
code << codcms;
|
|
}
|
|
|
|
if (fase_to_add && fasi.parent() == LF_COMMESSE)
|
|
{
|
|
if (code.full())
|
|
code << " ";
|
|
code << codfase;
|
|
fase_to_add = false;
|
|
}
|
|
}
|
|
}
|
|
if (fase_to_add)
|
|
{
|
|
if (code.full())
|
|
code << " ";
|
|
code << codfase;
|
|
}
|
|
return get_tmp_string() = code;
|
|
}
|
|
void TAnal_mov::saldo_set_reset(const TRectype& row, const char * contsep, bool reset)
|
|
{
|
|
const int dec = TCurrency::get_firm_dec();
|
|
const TImporto imp_row(row.get_char(RMOVANA_SEZIONE), row.get_real(RMOVANA_IMPORTO));
|
|
const int esc_iniziale = get_int(MOVANA_ANNOES);
|
|
int esc_finale = esc_iniziale;
|
|
|
|
//che movimento e'?
|
|
TToken_string annies;
|
|
annies.add(esc_iniziale);
|
|
|
|
const char tipomov = get_char(MOVANA_TIPOMOV);
|
|
if (*contsep != '\0' && tipomov != '\0')
|
|
int i = 1;
|
|
// i movimenti analitici possono avere una data di scadenza come la mozzarella
|
|
const TDate datacomp = get_date(MOVANA_DATACOMP);
|
|
TDate datafcomp = get_date(MOVANA_DATAFCOMP);
|
|
//caso cazzuto della scadenza con la fine della commessa (come nella stampa bilancio commessa)
|
|
if (get_bool(MOVANA_AUTOFCOMP))
|
|
{
|
|
const TString& codcms = row.get(RMOVANA_CODCMS);
|
|
const TRectype& rec_commesse = cache().get(LF_COMMESSE, codcms);
|
|
//data del cazzo che serve per non rovinare datacomp, che è la data sulla riga, non quella iniziale di cms
|
|
TDate datainicms;
|
|
ca_durata_commessa(rec_commesse, datainicms, datafcomp);
|
|
}
|
|
|
|
if (datafcomp.ok() && datafcomp > datacomp)
|
|
{
|
|
TEsercizi_contabili esc;
|
|
esc_finale = esc.date2esc(datafcomp);
|
|
if (esc_finale < esc_iniziale) //se l'esercizio di scadenza non esiste ancora perche' troppo futuro...
|
|
esc_finale = esc_iniziale + datafcomp.year() - datacomp.year(); //...se lo genera
|
|
if (esc_finale > esc_iniziale)
|
|
{
|
|
for (int a = esc_iniziale + 1; a <= esc_finale; a++)
|
|
annies.add(a);
|
|
}
|
|
}
|
|
|
|
TToken_string key;
|
|
|
|
key.add(tipomov);
|
|
key.add(esc_iniziale);
|
|
key.add(row.get(RMOVANA_CODCCOSTO));
|
|
key.add(row.get(RMOVANA_CODCMS));
|
|
key.add(row.get(RMOVANA_CODFASE));
|
|
key.add(row.get(RMOVANA_CODCONTO));
|
|
key.add(contsep);
|
|
|
|
if (annies.items() > 1) //saldi spammati su piu' anni
|
|
{
|
|
TToken_string giorni_annies; //lista dei giorni di saldo per annoes
|
|
TEsercizi_contabili esc;
|
|
|
|
TDate inizio_esc_iniziale, fine_esc_iniziale;
|
|
esc.code2range(esc_iniziale, inizio_esc_iniziale, fine_esc_iniziale);
|
|
giorni_annies.add(fine_esc_iniziale - datacomp + 1); //primo esercizio
|
|
|
|
TDate inizio_esc_finale, fine_esc_finale;
|
|
for (int a = 1; a < annies.items() - 1; a++)
|
|
{
|
|
const int curr_esc = annies.get_int(a);
|
|
esc.code2range(curr_esc, inizio_esc_finale, fine_esc_finale);
|
|
giorni_annies.add(fine_esc_finale - inizio_esc_finale + 1); //esercizi intermedi
|
|
}
|
|
|
|
esc.code2range(esc_finale, inizio_esc_finale, fine_esc_finale);
|
|
giorni_annies.add(datafcomp - inizio_esc_finale + 1); //ultimo esercizio
|
|
|
|
//Adesso che ha l'elenco dei giorni impegnati per esercizio, scatta il casino del distributore..
|
|
TGeneric_distrib texaco(imp_row.valore(), dec);
|
|
FOR_EACH_TOKEN(giorni_annies, gg)
|
|
texaco.add(real(gg));
|
|
|
|
FOR_EACH_TOKEN(annies, es)
|
|
{
|
|
TImporto curr_imp(imp_row.sezione(), texaco.get());
|
|
key.add(es, 1); //sistema l'anno di esercizio nella chiave
|
|
TImporto* imp = (TImporto*)_saldi.objptr(key);
|
|
if (imp == nullptr)
|
|
{
|
|
imp = new TImporto;
|
|
_saldi.add(key, imp);
|
|
}
|
|
if (reset)
|
|
*imp -= curr_imp;
|
|
else
|
|
*imp += curr_imp;
|
|
if (ca_ori_present(row))
|
|
{
|
|
TImporto* impind = (TImporto*)_saldind.objptr(key);
|
|
|
|
if (impind == nullptr)
|
|
{
|
|
impind = new TImporto;
|
|
_saldind.add(key, impind);
|
|
}
|
|
if (reset)
|
|
*impind -= curr_imp;
|
|
else
|
|
*impind += curr_imp;
|
|
}
|
|
}
|
|
}
|
|
else //saldo in un solo anno (caso standard)
|
|
{
|
|
TImporto* imp = (TImporto*)_saldi.objptr(key);
|
|
|
|
if (imp == nullptr)
|
|
{
|
|
imp = new TImporto;
|
|
_saldi.add(key, imp);
|
|
}
|
|
if (reset)
|
|
*imp -= imp_row;
|
|
else
|
|
*imp += imp_row;
|
|
if (ca_ori_present(row))
|
|
{
|
|
TImporto* impind = (TImporto*)_saldind.objptr(key);
|
|
|
|
if (impind == nullptr)
|
|
{
|
|
impind = new TImporto;
|
|
_saldind.add(key, impind);
|
|
}
|
|
if (reset)
|
|
*impind -= imp_row;
|
|
else
|
|
*impind += imp_row;
|
|
}
|
|
|
|
imp->valore().round(dec);
|
|
}
|
|
}
|
|
|
|
void TAnal_mov::load_saldi(bool reset)
|
|
{
|
|
if (reset)
|
|
{
|
|
_saldi.destroy();
|
|
_saldind.destroy();
|
|
}
|
|
|
|
const TRecord_array& a = body(LF_RMOVANA);
|
|
TString contsep = get(MOVANA_CONTSEP);
|
|
|
|
for (int i = a.last_row(); i > 0; i--)
|
|
{
|
|
const TRectype& row = a[i];
|
|
saldo_set_reset(row, "", reset); //aggiunge o toglie la riga corrente ai saldi in memoria
|
|
if (contsep.full())
|
|
saldo_set_reset(row, contsep, reset); //aggiunge o toglie la riga corrente ai saldi in memoria con contabilità separata
|
|
}
|
|
}
|
|
|
|
void TAnal_mov::update_saldi(bool kill)
|
|
{
|
|
if (!kill)
|
|
load_saldi(false);
|
|
|
|
save_saldi();
|
|
|
|
if (kill)
|
|
_saldi.destroy();
|
|
else
|
|
load_saldi(true);
|
|
}
|
|
|
|
bool TAnal_mov::save_saldi(const int annoes)
|
|
{
|
|
TLocalisamfile saldi(LF_SALDANA);
|
|
FOR_EACH_ASSOC_OBJECT(_saldi, h, k, o)
|
|
{
|
|
const TImporto& imp = *(const TImporto*)o;
|
|
if (!imp.is_zero())
|
|
{
|
|
TToken_string key = k;
|
|
const char tipo = key.get_char(0);
|
|
const int anno = key.get_int(1);
|
|
|
|
//Controlla se deve veramente salvre i saldi che ha calcolato
|
|
bool save_for_true = true;
|
|
//se annoes = 0 -> registrazione movimento analitico -> save_for_true = true -> salva!
|
|
//se invece trova un anno e' in fase ricostruzione saldi! Deve fare delle considerazioni..
|
|
if (annoes != 0)
|
|
{
|
|
if (annoes > 0) //se annoes e' positivo -> sono saldi normali -> salva!
|
|
save_for_true = anno == annoes;
|
|
else //se annoes e' negativo -> sono preventivi futuri -> salva solo se abs(anno)>annoes (senno' non sei nel futuro!)
|
|
save_for_true = anno > -annoes;
|
|
}
|
|
if (!save_for_true) //se non deve salvare davvero il saldo -> continua
|
|
continue;
|
|
|
|
saldi.put(SALDANA_ANNO, anno);
|
|
saldi.put(SALDANA_COSTO, key.get(2));
|
|
saldi.put(SALDANA_COMMESSA, key.get(3));
|
|
saldi.put(SALDANA_FASE, key.get(4));
|
|
saldi.put(SALDANA_CONTO, key.get(5));
|
|
saldi.put(SALDANA_CONTSEP, key.get(6));
|
|
|
|
int err = saldi.read(_isequal, _lock);
|
|
if (err != NOERR)
|
|
{
|
|
//Richiesta specifica del nostro Fuhrer! I saldi appartenenti ad esercizi futuri NON ancora aperti vanno..
|
|
//..comunque registrati!!!
|
|
// TEsercizi_contabili esc;
|
|
// if (esc.exist(anno))
|
|
{
|
|
saldi.zero();
|
|
saldi.put(SALDANA_ANNO, anno);
|
|
saldi.put(SALDANA_COSTO, key.get(2));
|
|
saldi.put(SALDANA_COMMESSA, key.get(3));
|
|
saldi.put(SALDANA_FASE, key.get(4));
|
|
saldi.put(SALDANA_CONTO, key.get(5));
|
|
saldi.put(SALDANA_CONTSEP, key.get(6));
|
|
err = saldi.write();
|
|
if (err != NOERR)
|
|
cantwrite_box(saldi.name());
|
|
}
|
|
// else
|
|
// continue; // NON devo dare errori fuorvianti causa saldi nel futuro che ci saranno ma non vanno scritti
|
|
}
|
|
|
|
if (err == NOERR)
|
|
{
|
|
const char* fld_sez = nullptr;
|
|
const char* fld_val = nullptr;
|
|
|
|
switch (tipo)
|
|
{
|
|
case 'P': fld_sez = SALDANA_SEZIONEP; fld_val = SALDANA_SALDOP; break;
|
|
case 'V': fld_sez = SALDANA_SEZIONEV; fld_val = SALDANA_SALDOV; break;
|
|
default : fld_sez = SALDANA_SEZIONE; fld_val = SALDANA_SALDO; break;
|
|
}
|
|
TImporto saldo(saldi.get_char(fld_sez), saldi.get_real(fld_val));
|
|
saldo += imp;
|
|
saldo.normalize();
|
|
|
|
saldi.put(fld_sez, saldo.sezione());
|
|
saldi.put(fld_val, saldo.valore());
|
|
|
|
const TImporto * ind = (const TImporto*) _saldind.objptr(key);
|
|
|
|
if (ind != nullptr)
|
|
{
|
|
const TImporto& impind = *(const TImporto*)ind;
|
|
switch (tipo)
|
|
{
|
|
case 'P': fld_sez = SALDANA_SEZIONEIP; fld_val = SALDANA_SALDOIP; break;
|
|
case 'V': fld_sez = SALDANA_SEZIONEIV; fld_val = SALDANA_SALDOIV; break;
|
|
default : fld_sez = SALDANA_SEZIONEI; fld_val = SALDANA_SALDOI; break;
|
|
}
|
|
TImporto saldoind(saldi.get_char(fld_sez), saldi.get_real(fld_val));
|
|
|
|
saldoind += impind;
|
|
saldoind.normalize();
|
|
|
|
saldi.put(fld_sez, saldoind.sezione());
|
|
saldi.put(fld_val, saldoind.valore());
|
|
}
|
|
err = saldi.rewrite();
|
|
}
|
|
|
|
if (err != NOERR)
|
|
return error_box(FR("Impossibile aggiornare i saldi: errore %d"), err);
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
int TAnal_mov::readat(TBaseisamfile& f, TRecnotype nrec, word lockop)
|
|
{
|
|
const int err = TMultiple_rectype::readat(f, nrec, lockop);
|
|
|
|
load_saldi(true);
|
|
return err;
|
|
}
|
|
|
|
int TAnal_mov::read(TBaseisamfile& f, word op, word lockop)
|
|
{
|
|
const int err = TMultiple_rectype::read(f, op, lockop);
|
|
|
|
load_saldi(true);
|
|
return err;
|
|
}
|
|
|
|
// Riporta su tutte le righe la data di competenza e l'esercizio dellla testata
|
|
//Aggiorna datafcomp e dataexpire sulla testata (dataexpire può dipendere dalle righe se si utilizza il calcolo..
|
|
//..automatico di dataexpire in base alle commesse sulle righe! Adolf ne sa una più del Teufel...)
|
|
void TAnal_mov::update_datacomp() const
|
|
{
|
|
body().renum_key(RMOVANA_ANNOES, get(MOVANA_ANNOES));
|
|
body().renum_key(RMOVANA_DATACOMP, get(MOVANA_DATACOMP));
|
|
|
|
//aggiorna datafcomp (se non specificata deve coincidere con datacomp)
|
|
TDate datafcomp = get(MOVANA_DATAFCOMP);
|
|
if (!datafcomp.ok())
|
|
{
|
|
datafcomp = get(MOVANA_DATACOMP);
|
|
((TAnal_mov*)this)->put(MOVANA_DATAFCOMP, datafcomp);
|
|
}
|
|
}
|
|
|
|
static bool __loaded = false;
|
|
static bool __rmovc = false;
|
|
|
|
int TAnal_mov::remove_rmov_comp() const
|
|
{
|
|
if (!__loaded)
|
|
{
|
|
__rmovc = ini_get_bool(CONFIG_DITTA, "ca", "AttRmovc", false);
|
|
__loaded = true;
|
|
}
|
|
if (!__rmovc)
|
|
return EBADMSG;
|
|
|
|
TISAM_recordset rmac("USE RMOVANAC\nFROM NUMREG=#NR\nTO NUMREG=#NR");
|
|
|
|
rmac.set_var("#NR", get_long(MOVANA_NUMREG));
|
|
TLocalisamfile & lf = rmac.cursor()->relation()->lfile();
|
|
for (bool ok = rmac.move_first(); ok; ok = rmac.move_next())
|
|
{
|
|
const TRectype& curr = rmac.cursor()->curr();
|
|
|
|
curr.remove(lf);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int TAnal_mov::save_rmov_comp() const
|
|
{
|
|
if (!__loaded)
|
|
{
|
|
__rmovc = ini_get_bool(CONFIG_DITTA, "ca", "AttRmovc", false);
|
|
__loaded = true;
|
|
}
|
|
if (!__rmovc)
|
|
return EBADMSG;
|
|
|
|
TAssoc_array old_rows;
|
|
{
|
|
TISAM_recordset rmac("USE RMOVANAC\nFROM NUMREG=#NR\nTO NUMREG=#NR");
|
|
rmac.set_var("#NR", get_long(MOVANA_NUMREG));
|
|
for (bool ok = rmac.move_first(); ok; ok = rmac.move_next())
|
|
{
|
|
const TRectype& curr = rmac.cursor()->curr();
|
|
old_rows.add(curr.build_key(), curr);
|
|
}
|
|
}
|
|
|
|
const TDate start = get(MOVANA_DATACOMP);
|
|
const TDate stop = get(MOVANA_DATAFCOMP);
|
|
TAssoc_array new_rows;
|
|
const TRecord_array& b = body();
|
|
for (int r = b.last_row(); r > 0; r = b.pred_row(r))
|
|
{
|
|
const TRectype& rmov = b.row(r);
|
|
TGeneric_distrib dist(rmov.get_real(RMOVANA_IMPORTO), 2);
|
|
for (TDate d = start; d <= stop; ++d)
|
|
{
|
|
TDate em(d);
|
|
if (d.year() == stop.year() && d.month() == stop.month())
|
|
em = stop;
|
|
else
|
|
em.set_end_month();
|
|
dist.add(em - d + 1L);
|
|
d = em;
|
|
}
|
|
for (TDate d = start; d <= stop; ++d)
|
|
{
|
|
TDate em(d);
|
|
if (d.year() == stop.year() && d.month() == stop.month())
|
|
em = stop;
|
|
else
|
|
em.set_end_month();
|
|
|
|
TRectype* rmovc = new TRectype(LF_RMOVANAC);
|
|
rmovc->put(RMOVANA_NUMREG, rmov.get(RMOVANA_NUMREG));
|
|
rmovc->put(RMOVANA_NUMRIG, rmov.get(RMOVANA_NUMRIG));
|
|
rmovc->put("ANNOCOMP", d.year());
|
|
rmovc->put("MESECOMP", d.month());
|
|
rmovc->put("DATACOMP", d);
|
|
rmovc->put("DATAFCOMP", em);
|
|
rmovc->put(RMOVANA_SEZIONE, rmov.get(RMOVANA_SEZIONE));
|
|
rmovc->put(RMOVANA_IMPORTO, dist.get());
|
|
rmovc->put(RMOVANA_ROWTYPE, rmov.get(RMOVANA_ROWTYPE));
|
|
new_rows.add(rmovc->build_key(), rmovc);
|
|
|
|
d = em;
|
|
}
|
|
}
|
|
|
|
TFast_isamfile file(LF_RMOVANAC);
|
|
if (!new_rows.empty())
|
|
{
|
|
FOR_EACH_ASSOC_OBJECT(new_rows, obj, key, itm)
|
|
{
|
|
const TRectype* rmov_new = (TRectype*)itm;
|
|
const TRectype* rmov_old = (TRectype*)old_rows.objptr(key);
|
|
if (rmov_old)
|
|
{
|
|
if (rmov_new->compare(*rmov_old) != 0)
|
|
rmov_new->rewrite_write(file);
|
|
}
|
|
else
|
|
rmov_new->write_rewrite(file);
|
|
}
|
|
}
|
|
if (!old_rows.empty())
|
|
{
|
|
FOR_EACH_ASSOC_OBJECT(old_rows, obj, key, itm)
|
|
{
|
|
const TRectype* rmov_old = (TRectype*)itm;
|
|
const TRectype* rmov_new = (TRectype*)new_rows.objptr(key);
|
|
|
|
if (rmov_new == nullptr)
|
|
rmov_old->remove(file);
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int TAnal_mov::write(TBaseisamfile& f) const
|
|
{
|
|
update_datacomp();
|
|
const int err = TMultiple_rectype::write(f);
|
|
if (err == NOERR)
|
|
{
|
|
((TAnal_mov*)this)->update_saldi(false);
|
|
save_rmov_comp();
|
|
}
|
|
return err;
|
|
}
|
|
|
|
int TAnal_mov::rewrite(TBaseisamfile& f) const
|
|
{
|
|
update_datacomp();
|
|
const int err = TMultiple_rectype::rewrite(f);
|
|
if (err == NOERR)
|
|
{
|
|
((TAnal_mov*)this)->update_saldi(false);
|
|
save_rmov_comp();
|
|
}
|
|
return err;
|
|
}
|
|
|
|
int TAnal_mov::remove(TBaseisamfile& f) const
|
|
{
|
|
const int err = TMultiple_rectype::remove(f);
|
|
if (err == NOERR)
|
|
{
|
|
((TAnal_mov*)this)->update_saldi(true);
|
|
remove_rmov_comp();
|
|
}
|
|
return err;
|
|
}
|
|
|
|
int TAnal_mov::read(long numreg, word lock)
|
|
{
|
|
put(MOVANA_NUMREG, numreg);
|
|
const int err = TMultiple_rectype::read(_isequal, lock);
|
|
|
|
load_saldi(true);
|
|
return err;
|
|
}
|
|
|
|
int TAnal_mov::read_cgnum(long numreg, word lock)
|
|
{
|
|
TLocalisamfile f(num());
|
|
|
|
f.setkey(3);
|
|
f.put(MOVANA_NUMREGCG, numreg);
|
|
|
|
int err = f.read(_isequal);
|
|
|
|
f.setkey(1);
|
|
if (err == NOERR)
|
|
{
|
|
put(MOVANA_NUMREG, f.get(MOVANA_NUMREG));
|
|
if ((err = TMultiple_rectype::read(_isequal, lock)) == NOERR)
|
|
load_saldi(true);
|
|
}
|
|
return err;
|
|
}
|
|
|
|
void TAnal_mov::zero(char c)
|
|
{
|
|
TMultiple_rectype::zero(c);
|
|
kill_saldi();
|
|
}
|
|
|
|
void TAnal_mov::update_totdoc()
|
|
{
|
|
TImporto totdoc;
|
|
for (int i = rows(); i > 0; i--)
|
|
{
|
|
const TRectype& riga = body().row(i);
|
|
TImporto imp_riga(riga.get_char(RMOVANA_SEZIONE), riga.get_real(RMOVANA_IMPORTO));
|
|
totdoc += imp_riga;
|
|
}
|
|
totdoc.normalize();
|
|
|
|
put(MOVANA_TOTDOC, totdoc.valore());
|
|
put(MOVANA_SEZIONE, totdoc.sezione());
|
|
}
|
|
|
|
TAnal_mov::TAnal_mov(long numreg) : TMultiple_rectype(LF_MOVANA)
|
|
{
|
|
add_file(LF_RMOVANA, RMOVANA_NUMRIG);
|
|
if (numreg > 0)
|
|
read(numreg);
|
|
}
|
|
|
|
|
|
TAnal_mov::TAnal_mov(const TRectype& rec) : TMultiple_rectype(LF_MOVANA)
|
|
{
|
|
add_file(LF_RMOVANA, RMOVANA_NUMRIG);
|
|
|
|
long numreg = 0;
|
|
switch(rec.num())
|
|
{
|
|
case LF_MOV:
|
|
case LF_RMOV:
|
|
case LF_RMOVIVA:
|
|
{
|
|
TLocalisamfile movana(LF_MOVANA);
|
|
movana.setkey(3);
|
|
movana.put(MOVANA_NUMREGCG, rec.get(MOV_NUMREG));
|
|
if (movana.read() == NOERR)
|
|
numreg = movana.get_long(MOVANA_NUMREG);
|
|
}
|
|
break;
|
|
default:
|
|
numreg = rec.get_long(MOVANA_NUMREG);
|
|
break;
|
|
}
|
|
|
|
if (numreg > 0)
|
|
read(numreg);
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////
|
|
// TAnal_ripartizioni_batch
|
|
//////////////////////////////////////////////////////////
|
|
int TAnal_ripartizioni_batch::indbil() const
|
|
{
|
|
return head().get_int(RIP_INDBIL);
|
|
}
|
|
|
|
char TAnal_ripartizioni_batch::tiporip() const
|
|
{
|
|
return head().get_char(RIP_TIPO);
|
|
}
|
|
|
|
int TAnal_ripartizioni_batch::modorip() const
|
|
{
|
|
return head().get_int(RIP_TIPORIP);
|
|
}
|
|
|
|
int TAnal_ripartizioni_batch::read (const char tiporip, const char* codice)
|
|
{
|
|
TLocalisamfile rip(LF_RIP);
|
|
_rip.put(RIP_TIPO, tiporip); //solo tipi batch!
|
|
_rip.put(RIP_CODICE, codice);
|
|
int err = _rip.read(rip); //leggi il record dal file
|
|
if (err == NOERR)
|
|
{
|
|
TRectype rrip(LF_RRIP);
|
|
rrip.put(RRIP_TIPO, tiporip);
|
|
rrip.put(RRIP_CODICE, codice);
|
|
TRecord_array::read(rrip);
|
|
}
|
|
return err;
|
|
}
|
|
|
|
int TAnal_ripartizioni_batch::read_rip_4(TLocalisamfile& rip, const char* codcosto, const char* commessa,
|
|
const char* fase, const int annoes, const int indbil, const int classe_mov) const
|
|
{
|
|
rip.put(RIP_TIPO, "B"); //solo tipi batch, unici per chiave cdc/cms/fase
|
|
rip.put(RIP_CODCOSTO, codcosto);
|
|
rip.put(RIP_CODCMS, commessa);
|
|
rip.put(RIP_CODFASE, fase);
|
|
rip.put(RIP_ANNOES, annoes);
|
|
rip.put(RIP_INDBIL, indbil);
|
|
rip.put(RIP_CLASSEMOV, classe_mov);
|
|
return rip.read();
|
|
}
|
|
|
|
int TAnal_ripartizioni_batch::read (const char* codcosto, const char* commessa, const char* fase,
|
|
const int annoes, const int indbil, const int classe_mov)
|
|
{
|
|
CHECKD(classe_mov > 0, "Classe movimento non valida ", classe_mov);
|
|
TLocalisamfile rip(LF_RIP);
|
|
rip.setkey(4);
|
|
|
|
int err = read_rip_4(rip, codcosto, commessa, fase, annoes, indbil, classe_mov);
|
|
if (err != NOERR)
|
|
err = read_rip_4(rip, codcosto, commessa, fase, annoes, indbil, 0);
|
|
//la put va rifatta perche' potrebbe essersi spostato al record successivo!!!
|
|
//se fallisce il primo tentativo prova con lo stesso anno e indbil=0
|
|
if (err != NOERR && indbil != 0)
|
|
{
|
|
err = read_rip_4(rip, codcosto, commessa, fase, annoes, 0, classe_mov);
|
|
if (err != NOERR)
|
|
err = read_rip_4(rip, codcosto, commessa, fase, annoes, 0, 0);
|
|
}
|
|
//se fallisce ancora riprova con anno=0 e lo stesso indbil
|
|
if (err != NOERR && annoes != 0)
|
|
{
|
|
err = read_rip_4(rip, codcosto, commessa, fase, 0, indbil, classe_mov);
|
|
if (err != NOERR)
|
|
err = read_rip_4(rip, codcosto, commessa, fase, 0, indbil, 0);
|
|
|
|
//estremo tentativo con annoes e indbil = 0
|
|
if (err != NOERR && indbil != 0)
|
|
{
|
|
err = read_rip_4(rip, codcosto, commessa, fase, 0, 0, classe_mov);
|
|
if (err != NOERR)
|
|
err = read_rip_4(rip, codcosto, commessa, fase, 0, 0, 0);
|
|
}
|
|
}
|
|
|
|
if (err == NOERR)
|
|
err = read('B', rip.get(RIP_CODICE)); //per chiave 4 solo tipo B (batch)
|
|
return err;
|
|
}
|
|
|
|
int TAnal_ripartizioni_batch::read_rip_3(TLocalisamfile& rip, const char tiporip, const int gr, const int co, const long sot,
|
|
const int annoes, const int indbil, const int classe_mov) const
|
|
{
|
|
rip.put(RIP_TIPO, tiporip); //tipo 'P' oppure tipo 'I', che sono quelli che vanno per conto
|
|
rip.put(RIP_GRUPPO, gr);
|
|
rip.put(RIP_CONTO, co);
|
|
rip.put(RIP_SOTTOCONTO, sot);
|
|
rip.put(RIP_ANNOES, annoes);
|
|
rip.put(RIP_INDBIL, indbil);
|
|
rip.put(RIP_CLASSEMOV, classe_mov);
|
|
return rip.read();
|
|
}
|
|
|
|
int TAnal_ripartizioni_batch::read (const char tiporip, const int gr, const int co, const long sot,
|
|
const int annoes, const int indbil, const int classe_mov)
|
|
{
|
|
CHECKD(classe_mov > 0, "Classe movimento non valida ", classe_mov);
|
|
TLocalisamfile rip(LF_RIP);
|
|
rip.setkey(3);
|
|
|
|
int err = read_rip_3(rip, tiporip, gr, co, sot, annoes, indbil, classe_mov);
|
|
if (err != NOERR)
|
|
err = read_rip_3(rip, tiporip, gr, co, sot, annoes, indbil, 0);
|
|
|
|
//la put va rifatta perche' potrebbe essersi spostato al record successivo!!!
|
|
//se fallisce il primo tentativo prova con lo stesso anno e indbil=0
|
|
if (err != NOERR && indbil != 0)
|
|
{
|
|
err = read_rip_3(rip, tiporip, gr, co, sot, annoes, 0, classe_mov);
|
|
if (err != NOERR)
|
|
err = read_rip_3(rip, tiporip, gr, co, sot, annoes, 0, 0);
|
|
}
|
|
//se fallisce ancora riprova con anno=0 e lo stesso indbil
|
|
if (err != NOERR && annoes != 0)
|
|
{
|
|
err = read_rip_3(rip, tiporip, gr, co, sot, 0, indbil, classe_mov);
|
|
if (err != NOERR)
|
|
err = read_rip_3(rip, tiporip, gr, co, sot, 0, indbil, 0);
|
|
|
|
//estremo tentativo con annoes e indbil = 0
|
|
if (err != NOERR && indbil != 0)
|
|
{
|
|
err = read_rip_3(rip, tiporip, gr, co, sot, 0, 0, classe_mov);
|
|
if (err != NOERR)
|
|
err = read_rip_3(rip, tiporip, gr, co, sot, 0, 0, 0);
|
|
}
|
|
}
|
|
|
|
_multirip = false;
|
|
if (err == NOERR)
|
|
{
|
|
err = read(tiporip, rip.get(RIP_CODICE)); //per chiave 3 sia tiporip=P che tiporip=I
|
|
const TString curr_key = rip.curr().build_key(3);
|
|
//cerca eventuali altre ripartizioni sorelle (con codice diverso ma stessi parametri)
|
|
if (rip.next() == NOERR)
|
|
{
|
|
const TString next_key = rip.curr().build_key(3);
|
|
_multirip = curr_key == next_key;
|
|
}
|
|
}
|
|
return err;
|
|
}
|
|
|
|
|
|
int TAnal_ripartizioni_batch::find_sister_rips(TString_array& lista_rips) const
|
|
{
|
|
lista_rips.destroy();
|
|
TToken_string key;
|
|
//ci sono più ripartizioni possibili...
|
|
if (has_multirip())
|
|
{
|
|
//relazione e cursore su chiave 3 (TIPO+GRUPPO+CONTO+SOTTOCONTO+ANNOES+INDBIL+CLASSEMOV) sul file LF_RIP alla..
|
|
//..ricerca di eventuali ripartizioni sorelle
|
|
TRelation rel_rip(LF_RIP);
|
|
TCursor cur_rip(&rel_rip, "", 3, &head(), &head());
|
|
for (cur_rip = 0; cur_rip.pos() < cur_rip.items(); ++cur_rip)
|
|
{
|
|
key.cut(0);
|
|
key.add(cur_rip.curr().get(RIP_CODICE));
|
|
key.add(cur_rip.curr().get(RIP_DESCRIZ));
|
|
lista_rips.add(key);
|
|
}
|
|
}
|
|
else //c'è solo una ripartizione
|
|
{
|
|
key.add(head().get_long(RIP_CODICE));
|
|
key.add(head().get(RIP_DESCRIZ));
|
|
lista_rips.add(key);
|
|
}
|
|
|
|
//restituisce il numero di ripartizioni trovate (nel TString_array c'è l'elenco)
|
|
return lista_rips.items();
|
|
}
|
|
|
|
|
|
TAnal_ripartizioni_batch::TAnal_ripartizioni_batch()
|
|
: TRecord_array (LF_RRIP, RRIP_NRIGA), _rip(LF_RIP), _multirip(false)
|
|
{
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////
|
|
// TCache_ripartizioni
|
|
///////////////////////////////////////////////////////////
|
|
TObject* TCache_ripartizioni::key2obj(const char* key)
|
|
{
|
|
TToken_string parametro(key);
|
|
const int nkey = parametro.get_int(0);
|
|
|
|
TAnal_ripartizioni_batch* rip = new TAnal_ripartizioni_batch;
|
|
|
|
switch (nkey)
|
|
{
|
|
case 3:
|
|
{
|
|
const int gruppo = parametro.get_int(1);
|
|
const int conto = parametro.get_int(2);
|
|
const long sottoconto = parametro.get_long(3);
|
|
const int anno = parametro.get_int(4);
|
|
const int indbil = parametro.get_int(5);
|
|
const int classe_mov = parametro.get_int(6);
|
|
|
|
//solo i movimenti a pareggio hanno chiave 3
|
|
rip->read('P', gruppo, conto, sottoconto, anno, indbil, classe_mov);
|
|
}
|
|
break;
|
|
case 5:
|
|
{
|
|
const int gruppo = parametro.get_int(1);
|
|
const int conto = parametro.get_int(2);
|
|
const long sottoconto = parametro.get_long(3);
|
|
const int anno = parametro.get_int(4);
|
|
const int indbil = parametro.get_int(5);
|
|
const int classe_mov = parametro.get_int(6);
|
|
|
|
//solo i movimenti interattivi e di conversione hanno chiave 5
|
|
rip->read('I', gruppo, conto, sottoconto, anno, indbil, 1);
|
|
}
|
|
break;
|
|
default: //chiave 4: normali ripartizioni batch
|
|
{
|
|
const TCodice_cdc codcosto = parametro.get(1);
|
|
const TCodice_cms commessa = parametro.get(2);
|
|
const TCodice_fas fase = parametro.get(3);
|
|
const int anno = parametro.get_int(4);
|
|
const int indbil = parametro.get_int(5);
|
|
const int classe_mov = parametro.get_int(6);
|
|
|
|
rip->read(codcosto, commessa, fase, anno, indbil, classe_mov);
|
|
}
|
|
break;
|
|
}
|
|
//ripartizioni costo/ricavo (quelle bonazziche sui saldi)
|
|
//stabilisce i coefficienti di ripartizione al volo in base al peso economico della commessa/cdc/fase/conto che trova..
|
|
//..sulla riga di ripartizione; ovviamente tali valori sono soggetti a cambiamento tutte le volte che ci sono righe..
|
|
//..analitiche che interessano tali paramtri (cms/cdc ecc.); sono ripartizioni dinamiche per il controllo dei costi/ricavi..
|
|
//..ad una data
|
|
if (rip->modorip() == 1) //modorip=1 -> costo/ricavo
|
|
{
|
|
bool some_value = false;
|
|
const int items = rip->rows();
|
|
|
|
//deve sapere se usare i saldi in Dare o Avere in base al fatto che l'utente voglia un analisi proporzionata..
|
|
//..sui Costi o sui Ricavi; lo legge dalla configurazione della CA; se non lo trova settato lo mette in automatico..
|
|
//..a Costi
|
|
const char sezione_di_riferimento = ca_config().get_char("SezRif");
|
|
|
|
for (int i = 1; i <= items; i++)
|
|
{
|
|
TRectype & rec = (*rip)[i];
|
|
const TAnal_bill bill(rec);
|
|
//calcola il saldo usando come parametri (cms/cdc/fsc/conto) quelli che trova sulla riga di ripartizione
|
|
const TSaldanal& s = ca_saldo(bill, "", _dal, _al, _saldanal_consuntivo); // qui
|
|
//in base a C/R stabilisce quali saldi considerare e in quale sezione normalizzare
|
|
real val;
|
|
if (sezione_di_riferimento == 'R') //in Ricavi normalizza in Avere
|
|
val = s._avere.valore();
|
|
else //in Costi normalizza in Dare
|
|
val = s._dare.valore();
|
|
|
|
//saldi nulli non contano
|
|
if (val < ZERO)
|
|
val = ZERO;
|
|
|
|
//usa il valore del saldo non nullo per stabilire il "peso" della riga di ripartizione
|
|
some_value |= !val.is_zero();
|
|
rec.put(RRIP_RIPARTO, val);
|
|
}
|
|
if (!some_value)
|
|
{
|
|
for (int i = 1; i <= items; i++)
|
|
{
|
|
TRectype& rec = (*rip)[i];
|
|
rec.put(RRIP_RIPARTO, 1);
|
|
}
|
|
}
|
|
}
|
|
|
|
return (TObject*)rip;
|
|
}
|
|
|
|
void TCache_ripartizioni::set_esercizio(const int codes)
|
|
{
|
|
if (codes != _codes)
|
|
{
|
|
TEsercizi_contabili e;
|
|
const TEsercizio& esc = e.esercizio(codes);
|
|
_codes = codes;
|
|
_dal = esc.inizio();
|
|
_al = esc.fine();
|
|
destroy();
|
|
}
|
|
}
|
|
|
|
|
|
const TAnal_ripartizioni_batch& TCache_ripartizioni::righe(const char* costo, const char* commessa, const char* fase,
|
|
const int annoes, const int indbil, const char tipomov)
|
|
{
|
|
//classi di movimento: se preventivi 2, se normali 1
|
|
int classe_movimento;
|
|
if (tipomov == 'P' || tipomov == 'V')
|
|
classe_movimento = 2;
|
|
else
|
|
classe_movimento = 1;
|
|
|
|
TToken_string parametro;
|
|
parametro << "4|" << costo << '|' << commessa << '|' << fase << '|' << annoes << '|' << indbil << '|' << classe_movimento; //per chiave 4
|
|
return *(const TAnal_ripartizioni_batch*)objptr(parametro);
|
|
}
|
|
|
|
const TAnal_ripartizioni_batch& TCache_ripartizioni::righe(const TBill& bill, const int annoes, const char tipomov)
|
|
{
|
|
//classi di movimento: se preventivi 2, se normali 1
|
|
int classe_movimento;
|
|
if (tipomov == 'P' || tipomov == 'V')
|
|
classe_movimento = 2;
|
|
else
|
|
classe_movimento = 1;
|
|
|
|
TToken_string parametro;
|
|
parametro << "3|" << bill.gruppo() << '|' << bill.conto() << '|' << bill.sottoconto() << '|'
|
|
<< annoes << '|' << bill.indicatore_bilancio() << '|' << classe_movimento; //per chiave 3
|
|
return *(const TAnal_ripartizioni_batch*)objptr(parametro);
|
|
}
|
|
|
|
const TAnal_ripartizioni_batch& TCache_ripartizioni::righe(const TAnal_bill& bill, const int annoes, const int indbil,
|
|
const char tipomov)
|
|
{
|
|
TConfig& config = ca_config();
|
|
const bool use_pdcc = config.get_bool("UsePdcc"); //usa il piano dei conti contabile
|
|
if (use_pdcc)
|
|
{
|
|
const TString& contone = bill.conto();
|
|
const int gr = atoi(contone.mid(0,3));
|
|
const int co = atoi(contone.mid(3,3));
|
|
const long so = atol(contone.mid(6,6));
|
|
const TBill zio(gr, co, so);
|
|
const TAnal_ripartizioni_batch& rb = righe(zio, annoes, tipomov);
|
|
//ha trovato una ripartizione?
|
|
if (rb.rows() > 0)
|
|
return rb;
|
|
|
|
}
|
|
//se non riesce a trovare una ripartizione per conto (chiave 3, tipo 'P') prova con la chiave 4 (cdc/cms/fase, tipo 'B')
|
|
return righe(bill.costo(), bill.commessa(), bill.fase(), annoes, indbil, tipomov);
|
|
}
|
|
|
|
const TAnal_ripartizioni_batch& TCache_ripartizioni::righe_interattive(const TBill& bill, const int annoes, const char tipomov)
|
|
{
|
|
//classi di movimento: se preventivi 2, se normali 1
|
|
int classe_movimento;
|
|
if (tipomov == 'P' || tipomov == 'V')
|
|
classe_movimento = 2;
|
|
else
|
|
classe_movimento = 1; //sempre questo per cacnv
|
|
|
|
TToken_string parametro;
|
|
parametro << "5|" << bill.gruppo() << '|' << bill.conto() << '|' << bill.sottoconto() << '|'
|
|
<< annoes << '|' << bill.indicatore_bilancio() << '|' << classe_movimento; //per chiave 5
|
|
return *(const TAnal_ripartizioni_batch*)objptr(parametro);
|
|
}
|
|
|
|
|
|
TCache_ripartizioni::TCache_ripartizioni()
|
|
{
|
|
_codes = 0;
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////////////////
|
|
// Metodi per la ricompattazione delle righe ripartite
|
|
///////////////////////////////////////////////////////////
|
|
bool ca_can_merge_rows(const TRectype& compact_rec, const TRectype& rec)
|
|
{
|
|
return compact_rec.get(RMOVANA_CODCCORI) == rec.get(RMOVANA_CODCCORI) &&
|
|
compact_rec.get(RMOVANA_CODCMSORI) == rec.get(RMOVANA_CODCMSORI) &&
|
|
compact_rec.get(RMOVANA_CODFASEORI) == rec.get(RMOVANA_CODFASEORI) &&
|
|
compact_rec.get(RMOVANA_CODCONTORI) == rec.get(RMOVANA_CODCONTORI);
|
|
}
|
|
|
|
bool ca_can_pack_rows(const TRectype& compact_rec, const TRectype& rec)
|
|
{
|
|
return compact_rec.get(RMOVANA_CODCCOSTO) == rec.get(RMOVANA_CODCCOSTO) &&
|
|
compact_rec.get(RMOVANA_CODCMS) == rec.get(RMOVANA_CODCMS) &&
|
|
compact_rec.get(RMOVANA_CODFASE) == rec.get(RMOVANA_CODFASE) &&
|
|
compact_rec.get(RMOVANA_CODCONTO) == rec.get(RMOVANA_CODCONTO)&&
|
|
compact_rec.get(RMOVANA_CODCCORI) == rec.get(RMOVANA_CODCCORI) &&
|
|
compact_rec.get(RMOVANA_CODCMSORI) == rec.get(RMOVANA_CODCMSORI) &&
|
|
compact_rec.get(RMOVANA_CODFASEORI) == rec.get(RMOVANA_CODFASEORI) &&
|
|
compact_rec.get(RMOVANA_CODCONTORI) == rec.get(RMOVANA_CODCONTORI);
|
|
}
|
|
|
|
bool ca_ori_present(const TRectype& rec)
|
|
{
|
|
return (rec.get(RMOVANA_CODCCORI).not_empty() || rec.get(RMOVANA_CODCMSORI).not_empty() ||
|
|
rec.get(RMOVANA_CODFASEORI).not_empty() || rec.get(RMOVANA_CODCONTORI).not_empty());
|
|
}
|
|
|
|
bool ca_ori_present(const TRecordset & rec)
|
|
{
|
|
return (rec.get(RMOVANA_CODCCORI).as_string().not_empty() || rec.get(RMOVANA_CODCMSORI).as_string().not_empty() ||
|
|
rec.get(RMOVANA_CODFASEORI).as_string().not_empty() || rec.get(RMOVANA_CODCONTORI).as_string().not_empty());
|
|
}
|
|
void ca_taglia_campo(TRectype& src, const char* campo_src, TRectype& dst, const char* campo_dst)
|
|
{
|
|
ca_copia_campo(src, campo_src, dst, campo_dst);
|
|
src.zero(campo_src);
|
|
}
|
|
|
|
void ca_copia_campo(const TRectype& src, const char* campo_src, TRectype& dst, const char* campo_dst)
|
|
{
|
|
const TString& valore = src.get(campo_src);
|
|
if (valore.full())
|
|
dst.put(campo_dst, valore);
|
|
}
|
|
|
|
bool ca_implode_rows(const TRecord_array& input_rows, TRecord_array& compact_rows)
|
|
{
|
|
bool implosion_done = false;
|
|
const int last_row = input_rows.last_row();
|
|
for (int r = input_rows.first_row(); r > 0 && r <= last_row; r = input_rows.succ_row(r))
|
|
{
|
|
const TRectype& rec = input_rows.row(r); //record originale
|
|
//se esiste almeno un campo origine compilato puo' implodere, senno' lascia perdere
|
|
if (ca_ori_present(rec))
|
|
{
|
|
//controlla se e' un pareggio e non una ripartizione
|
|
if (rec.get(RMOVANA_CODCONTORI).blank())
|
|
continue;
|
|
|
|
int i = 0;
|
|
for (i = compact_rows.rows(); i > 0; i--) //giro sulle righe gia' compattate per scoprire se
|
|
{ //il nostro record esiste gia' o e' da aggiungere
|
|
const TRectype& nuovo_rec = compact_rows.row(i); //
|
|
if (ca_can_merge_rows(nuovo_rec, rec)) //se esiste gia'...
|
|
break;
|
|
}
|
|
if (i > 0) //...aggiunge solo importo e sezione...
|
|
{
|
|
const TImporto imp_rec(rec.get_char(RMOVANA_SEZIONE), rec.get_real(RMOVANA_IMPORTO));
|
|
TRectype& compact_rec = compact_rows.row(i, false); //record originale
|
|
|
|
TImporto imp_orig(compact_rec.get_char(RMOVANA_SEZIONE), compact_rec.get_real(RMOVANA_IMPORTO));
|
|
imp_orig += imp_rec;
|
|
imp_orig.normalize();
|
|
compact_rec.put(RMOVANA_SEZIONE, imp_orig.sezione());
|
|
compact_rec.put(RMOVANA_IMPORTO, imp_orig.valore());
|
|
}
|
|
else //...senno' aggiunge direttamente tutta la riga
|
|
{
|
|
TRectype* newrec = new TRectype(rec); //record destinazione
|
|
newrec->put(RMOVANA_NUMRIG, compact_rows.rows() + 1);
|
|
compact_rows.add_row(newrec);
|
|
}
|
|
implosion_done = true; //ha imploso almeno 1 riga!!!
|
|
}
|
|
else
|
|
{
|
|
TRectype* newrec = new TRectype(rec);
|
|
newrec->put(RMOVANA_NUMRIG, compact_rows.rows() + 1);
|
|
compact_rows.add_row(newrec);
|
|
}
|
|
}
|
|
|
|
//ripristina i campi originali sul record di destinazione
|
|
for (int k = 1; k <= compact_rows.rows(); k++)
|
|
{
|
|
TRectype& compact_rec = compact_rows.row(k, false);
|
|
if (ca_ori_present(compact_rec))
|
|
{
|
|
ca_taglia_campo(compact_rec, RMOVANA_CODCCORI, compact_rec, RMOVANA_CODCCOSTO);
|
|
ca_taglia_campo(compact_rec, RMOVANA_CODCMSORI, compact_rec, RMOVANA_CODCMS);
|
|
ca_taglia_campo(compact_rec, RMOVANA_CODFASEORI, compact_rec, RMOVANA_CODFASE);
|
|
ca_taglia_campo(compact_rec, RMOVANA_CODCONTORI, compact_rec, RMOVANA_CODCONTO);
|
|
}
|
|
}
|
|
|
|
return implosion_done;
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////
|
|
//metodi per ricavare informazioni sulla configurazione (usati per ora nel rendiconto)
|
|
///////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
//metodo per ricavare la stringa dei codici dai campi dello sheet
|
|
bool ca_extract_sheet_field(const TSheet_field& sheet, const int row, const int logicnum, TString& codice)
|
|
{
|
|
TMask& mask_sheet = sheet.sheet_mask(); //maschera di riga
|
|
codice.cut(0);
|
|
FOR_EACH_MASK_FIELD(mask_sheet, i, f) //giro sui campi della maschera di riga
|
|
{
|
|
const TFieldref* fr = f->field(); //campo corrente della maschera
|
|
|
|
if (fr != nullptr && f->is_edit()) //deve essere un campo di tipo edit
|
|
{
|
|
TEdit_field& e = *(TEdit_field*)f; //visto che è di tipo edit può creare l'edit_field per farne la browse
|
|
|
|
if (e.browse() != nullptr)
|
|
{
|
|
const TCursor& cur = *e.browse()->cursor();
|
|
const int ln = cur.file().num(); //Allah! dal campo ricava il cursore sul file di numero ln
|
|
if (ln == logicnum && cur.key() == 1 && !e.empty())
|
|
{
|
|
const TString& parte_codice = e.get();
|
|
codice << parte_codice;
|
|
}
|
|
else
|
|
{
|
|
if (codice.full())
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return codice.full();
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////
|
|
//calcola la durata di una commessa e le sue date di inizio e fine
|
|
///////////////////////////////////////////////////////////////////////////////////////
|
|
long ca_durata_commessa(const TRectype& rec_commesse, TDate& dataini, TDate& datafine)
|
|
{
|
|
//date iniziale e finale commessa
|
|
dataini = rec_commesse.get_date(COMMESSE_DATAINIZIO);
|
|
datafine = rec_commesse.get_date(COMMESSE_DATAFINE);
|
|
|
|
//per la data fine deve tener conto di eventuali proroghe..
|
|
if (rec_commesse.get_bool(COMMESSE_PROROGA))
|
|
{
|
|
const TDate datapror = rec_commesse.get_date(COMMESSE_DATAPROR);
|
|
if (datapror.ok())
|
|
datafine = datapror;
|
|
}
|
|
|
|
//se almeno una delle due date risultasse incompleta..
|
|
if (!dataini.ok() || !datafine.ok())
|
|
{
|
|
//prende l'anno
|
|
TEsercizi_contabili esc;
|
|
int anno = rec_commesse.get_int(COMMESSE_ANNO);
|
|
//se non trova un anno valido (non sono ammesse commesse prima del XX secolo!)
|
|
if (anno <= 1900)
|
|
{
|
|
//prova con dataini, se è buona...
|
|
if (dataini.ok())
|
|
anno = esc.date2esc(dataini);
|
|
else
|
|
{
|
|
//allora prova con datafine, se è buona...
|
|
if (datafine.ok())
|
|
anno = esc.date2esc(datafine);
|
|
else
|
|
anno = esc.first(); //se nessuna data è buona mette l'anno = al primo esercizio
|
|
}
|
|
}
|
|
|
|
//se entrambe le date fossero vuote, visto che comunque adesso l'anno ce l'ha, le può ricavare...
|
|
// Probabilmente le prossime 3 righe andrebbero cancellate: si assume una commessa per un anno
|
|
if (!dataini.ok() && !datafine.ok())
|
|
esc.code2range(anno, dataini, datafine);
|
|
else //solo una data o nessuna data non buona
|
|
{
|
|
TDate dummy;
|
|
//dataini viene messa = ad inizio anno commessa
|
|
if (!dataini.ok())
|
|
esc.code2range(anno, dataini, dummy);
|
|
//datafine viene messa = alla data di scadenza dell'ultimo esercizio valido + 1 anno (mantiene corrette le sezioni di stampa)
|
|
if (!datafine.ok())
|
|
esc.code2range(esc.last() + 1, dummy, datafine);
|
|
}
|
|
|
|
} //if (!dataini.ok() || !datafine.ok())
|
|
return datafine - dataini + 1;
|
|
}
|
|
|
|
bool ca_commessa_attiva(const TRectype& rec_commesse, const TDate & from, const TDate & to)
|
|
{
|
|
bool attiva = true;
|
|
TDate inizio;
|
|
TDate fine;
|
|
|
|
ca_durata_commessa(rec_commesse, inizio, fine);
|
|
attiva = (!from.ok() || (fine.year() >= from.year()) && (!to.ok() || (inizio.year() <= to.year())));
|
|
|
|
return attiva;
|
|
}
|