diff --git a/src/fp/fp0500a.uml b/src/fp/fp0500a.uml index cae04a682..c9a016e27 100644 --- a/src/fp/fp0500a.uml +++ b/src/fp/fp0500a.uml @@ -175,7 +175,7 @@ BEGIN DISPLAY "Tipo riga@8" CODTAB DISPLAY "Descrizione@50" S0 OUTPUT S_ADG_TIPORIGA CODTAB - HELP "Condizione che se è vera abilita la riga" + HELP "La personalizzazione viene abilitata solo su queste righe" END STRING S_ADG_COND 200 50 diff --git a/src/fp/fplib.h b/src/fp/fplib.h index 14ed27a6b..798c5cd12 100644 --- a/src/fp/fplib.h +++ b/src/fp/fplib.h @@ -269,8 +269,6 @@ protected: bool export_paf0100f(); bool export_paf3200f(); - - // Record clifo //void set_rec_clifo(char tipocf, long codcf); @@ -287,14 +285,6 @@ public: int force_commit(); void set_cache_insert(const bool v) { _cache_insert = v; } - // Test - static const TString& parse_expression(const TString& expr, TRiga_documento& rdoc); - static TString& parse_read(const TString& str, TRiga_documento& rdoc); - static TString& do_read(const TString& tabella, const TString& campo, TRiga_documento& rdoc); - static TString& parse_search(const TString& str, TRiga_documento& rdoc); - - - TDoc_fp(); ~TDoc_fp(); }; @@ -490,4 +480,29 @@ public: for (int __r = bodyof##__radg.first_row(); bodyof##__radg.exist(__r) && (__radg=&(TRectype&)bodyof##__radg.row(__r))!=NULL; __r=bodyof##__radg.succ_row(__r)) +class TFP_expression : public TObject +{ +private: + enum TFP_operator { error, eq, neq, gt, ls, gteq, lseq }; + + // Etrattori + static void extract_info(const TString& expr, TString& tabella, TString& campo, TToken_string* search); + static bool calc_table(const TString& tabella, int& file); + static void split_condition(const TString& cond, TString& cond_sx, TString& cond_dx, TFP_operator& symb); + static TVariant& get_value(const TRectype& rec, const TString& campo); + static TVariant& parse_var(const TString& str); + + // Calcolatori + static TVariant& parse_read(const TString& str, TRiga_documento& rdoc); + static TVariant& do_read(const TString& tabella, const TString& campo, TRiga_documento& rdoc); + static TVariant& parse_search(const TString& str, TRiga_documento& rdoc); + +public: + static const TVariant parse_expression(const TString& expr, TRiga_documento& rdoc); + static bool check_condition(const TString& cond, TRiga_documento& rdoc); + + TFP_expression() = default; + virtual ~TFP_expression() = default; +}; + #endif // __FPLIB_H diff --git a/src/fp/fplib01.cpp b/src/fp/fplib01.cpp index 25a38633c..30031e301 100644 --- a/src/fp/fplib01.cpp +++ b/src/fp/fplib01.cpp @@ -1408,164 +1408,6 @@ bool TDoc_fp::export_paf3200f() return true; } -/* - * Sintassi: - * READ(TABELLA, CAMPO) -> legge dalle tabelle predefinite - * SEARCH(TABELLA, CAMPO, RICERCA) -> legge da una tabella qualsiasi - * SEARCH e READ sono diverse sotto richiesta di Ilaria per avere una sintassi più chiara - * resto: TExpr_documento() - */ -const TString& TDoc_fp::parse_expression(const TString& expr, TRiga_documento& rdoc) -{ - const TToken_string exprs(expr, '+'); - TString& result = get_tmp_string().cut(0); - TExpr_documento expr_documento(_mixexpr, &rdoc.doc(), &rdoc); - - FOR_EACH_STR_TOKEN(exprs, str) - { - // Come prima cosa trimmo la vita - str.trim(); - if(str.starts_with("READ(", true)) - { - result << parse_read(str, rdoc); - } else if(str.starts_with("SEARCH(", true)) - { - result << parse_search(str, rdoc); - } else - { - // Controllo non sia una ricerca a DB con il punto - if(expr.contains("->")) - { - // Se contiene una freccia non posso fare un TToken_string easy - // Non esistono campi con -> vero? - str.replace("->", "."); - } - - // Questo diventa true se sono passato sopra o effettivamente ha un punto dall'inizio - if(expr.contains('.')) - { - TToken_string simple_field(expr, '.'); - result << do_read(simple_field.get(0), simple_field.get(), rdoc); - } - // Se inizia come una stringa o non contiene parentesi -> no expr - else if (str.starts_with("\"") || !(str.contains("(") && str.contains(")"))) - { - str.replace("\"", ""); - result << str; - } - else - { - expr_documento.set(str, _mixexpr); - result << expr_documento.as_string(); - } - } - } - - return result; -} - -void extract_info(const TString& expr, TString& tabella, TString& campo, TToken_string* search) -{ - // Prendo la stringa pulita della parte sinistra - TString clean_expr = expr.mid(expr.find('(') + 1); - // Tolgo eventuali spazi ai lati - clean_expr.trim(); - // Tolgo la virgola finale - clean_expr.rtrim(1); - TToken_string info(clean_expr, ','); - - // Trimmare sempre come se non sapessi fare altro nella vita - tabella.cut(0) << info.remove(0); tabella.trim(); - campo.cut(0) << info.remove(0); campo.trim(); - if(search != nullptr) - { - // Prendo il resto - search->cut(0) << info; - search->trim(); - search->restart(); - } -} - -bool calc_table(const TString& tabella, int& file) -{ - file = atoi(tabella); - if (file == 0) - file = table2logic(tabella); - return is_multi_table(file); -} - -TString& TDoc_fp::parse_read(const TString& str, TRiga_documento& rdoc) -{ - TString tabella, campo; - - extract_info(str, tabella, campo, nullptr); - - return do_read(tabella, campo, rdoc); -} - -TString& TDoc_fp::do_read(const TString& tabella, const TString& campo, TRiga_documento& rdoc) -{ - TString& result = get_tmp_string().cut(0); - int file; - - bool multi_table = calc_table(tabella, file); - - switch (file) - { - case LF_DOC: - result = rdoc.doc().get(campo); - break; - case LF_RIGHEDOC: - result = rdoc.get(campo); - break; - case LF_CLIFO: - result = rdoc.doc().clifor().get(campo); - break; - case LF_CFVEN: - result = rdoc.doc().clifor().vendite().get(campo); - break; - case LF_LETINT: - result = rdoc.doc().clifor().lettera().get(campo); - break; - case LF_ANAMAG: - result = rdoc.articolo().get(campo); - break; - default: - // Skip - break; - } - - return result; -} - -TString& TDoc_fp::parse_search(const TString& str, TRiga_documento& rdoc) -{ - TString& result = get_tmp_string(); - - TString tabella, campo; - TToken_string input_search, search; - int file; - - extract_info(str, tabella, campo, &input_search); - const bool multi_table = calc_table(tabella, file); - - // Parso ogni singolo token della ricerca - FOR_EACH_TOKEN(input_search, tok) - { - search.add(parse_expression(tok, rdoc)); - } - - if(multi_table) - { - result.cut(0) << cache().get(tabella, search, campo); - } else - { - result.cut(0) << cache().get(file, search, campo); - } - return result; -} - - bool TDoc_fp::doc_to_paf(TDocumentoEsteso& doc) { if (!initialize(doc)) diff --git a/src/fp/fplib05.cpp b/src/fp/fplib05.cpp index 691e6ee63..834e42dba 100644 --- a/src/fp/fplib05.cpp +++ b/src/fp/fplib05.cpp @@ -37,6 +37,7 @@ void TFP_custom::autoload(const TSheet_field& sf, const int file) const { TRectype& rec_row = rcaus.row(-1, true); rec_row.put(FPCCAUS_VALORE, row->get(0)); + rec_row.put(FPCCAUS_COND, row->get()); } } break; @@ -49,6 +50,7 @@ void TFP_custom::autoload(const TSheet_field& sf, const int file) const TRectype& rec_row = rart.row(-1, true); rec_row.put(FPCART_TIPO, row->get(0)); rec_row.put(FPCART_VALORE, row->get()); + rec_row.put(FPCART_COND, row->get()); } } break; @@ -63,6 +65,9 @@ void TFP_custom::autoload(const TSheet_field& sf, const int file) const rec_row.put(FPCADG_RTESTO, row->get()); rec_row.put(FPCADG_RNUMERO, row->get()); rec_row.put(FPCADG_RDATA, row->get()); + rec_row.put(FPCADG_TIPORIGA, row->get()); + rec_row.put(FPCADG_SPLIT, row->get()); + rec_row.put(FPCADG_COND, row->get()); } } break; @@ -89,3 +94,315 @@ TFP_custom::TFP_custom(const char* codcust) : TFP_custom() init(); load(codcust); } + + + +/* + * Sintassi: + * READ(TABELLA, CAMPO) -> legge dalle tabelle predefinite + * SEARCH(TABELLA, CAMPO, RICERCA) -> legge da una tabella qualsiasi + * SEARCH e READ sono diverse sotto richiesta di Ilaria per avere una sintassi più chiara + * resto: TExpr_documento() + */ +const TVariant TFP_expression::parse_expression(const TString& expr, TRiga_documento& rdoc) +{ + const TToken_string exprs(expr, '+'); + TVariant result; + TExpr_documento expr_documento(_mixexpr, &rdoc.doc(), &rdoc); + + FOR_EACH_STR_TOKEN(exprs, str) + { + // Come prima cosa trimmo la vita + str.trim(); + if (str.starts_with("READ(", true)) + { + result.add(parse_read(str, rdoc)); + } + else if (str.starts_with("SEARCH(", true)) + { + result.add(parse_search(str, rdoc)); + } + else + { + // Controllo non sia una ricerca a DB con il punto + if (expr.contains("->")) + { + // Se contiene una freccia non posso fare un TToken_string easy + // Non esistono campi con -> vero? + str.replace("->", "."); + } + + // Questo diventa true se sono passato sopra o effettivamente ha un punto dall'inizio + if (expr.contains('.')) + { + TToken_string simple_field(expr, '.'); + result.add(do_read(simple_field.get(0), simple_field.get(), rdoc)); + } + // Se inizia come una stringa o non contiene parentesi -> no expr + else if (str.starts_with("\"") || !(str.contains("(") && str.contains(")"))) + { + str.replace("\"", ""); + // Cerchiamo di capire che è + result.add(parse_var(str)); + } + else + { + expr_documento.set(str, _mixexpr); + result.add(expr_documento.as_string()); + } + } + } + + return result; +} + +bool TFP_expression::check_condition(const TString& cond, TRiga_documento& rdoc) +{ + TString cond_sx, cond_dx; + TFP_operator symb; + split_condition(cond, cond_sx, cond_dx, symb); + + const TVariant value_sx = parse_expression(cond_sx, rdoc); + const TVariant value_dx = parse_expression(cond_dx, rdoc); + + switch(symb) + { + case eq: + return value_sx == value_dx; + case neq: + return value_sx != value_dx; + case gt: + return value_sx > value_dx; + case ls: + return value_sx < value_dx; + case gteq: + return value_sx >= value_dx; + case lseq: + return value_sx <= value_dx; + default: + return false; + } +} + +void TFP_expression::extract_info(const TString& expr, TString& tabella, TString& campo, TToken_string* search) +{ + // Prendo la stringa pulita della parte sinistra + TString clean_expr = expr.mid(expr.find('(') + 1); + // Tolgo eventuali spazi ai lati + clean_expr.trim(); + // Tolgo la virgola finale + clean_expr.rtrim(1); + TToken_string info(clean_expr, ','); + + // Trimmare sempre come se non sapessi fare altro nella vita + tabella.cut(0) << info.remove(0); tabella.trim(); + campo.cut(0) << info.remove(0); campo.trim(); + if (search != nullptr) + { + // Prendo il resto + search->cut(0) << info; + search->trim(); + search->restart(); + } +} + +bool TFP_expression::calc_table(const TString& tabella, int& file) +{ + file = atoi(tabella); + if (file == 0) + file = table2logic(tabella); + return is_multi_table(file); +} + +void TFP_expression::split_condition(const TString& cond, TString& cond_sx, TString& cond_dx, TFP_operator& symb) +{ + // Cerchiamo di capire che condizione ho + TString4 symbol; + if(cond.contains(" == ")) + { + symb = eq; + symbol = " == "; + } + else if(cond.contains(" != ")) + { + symb = neq; + symbol = " != "; + } + else if (cond.contains(" >= ")) + { + symb = gteq; + symbol = " >= "; + } + else if (cond.contains(" <= ")) + { + symb = lseq; + symbol = " <= "; + } + else if (cond.contains(" > ")) + { + symb = gt; + symbol = " > "; + } + else if (cond.contains(" < ")) + { + symb = ls; + symbol = " < "; + } + + if(symb != error) + { + cond_sx = cond.left(cond.find(symbol)); + cond_dx = cond.right(cond.len() - (cond.find(symbol) + symbol.len())); + } + else + { + // Considero come se è true o no il campo in generale + symb = gt; + cond_sx = cond; + cond_dx.cut(0); + } +} + +// Questa funzione potrebbe diventare standard per TRectype +TVariant& TFP_expression::get_value(const TRectype& rec, const TString& campo) +{ + TVariant& ret = get_tmp_var(); + switch(rec.type(campo)) + { + case _intfld: + ret.set(rec.get_int(campo)); + break; + case _longfld: + ret.set(rec.get_long(campo)); + break; + case _realfld: + ret.set(rec.get_real(campo)); + break; + case _datefld: + ret.set(rec.get_date(campo)); + break; + case _wordfld: + ret.set(rec.get_word(campo)); + break; + case _charfld: + ret.set(rec.get_char(campo)); + break; + case _boolfld: + ret.set(rec.get_bool(campo)); + break; + case _nullfld: + case _alfafld: + case _intzerofld: + case _longzerofld: + case _memofld: + ret.set(rec.get(campo)); + break; + } + return ret; +} + +TVariant& TFP_expression::parse_var(const TString& str) +{ + TVariant& ret = get_tmp_var(); + + // Come prima cosa leggo la stringa e cerco di capire se ci sono numeri o no + bool is_real = false, is_string = false; + for(int i = 0; i < str.len() && !is_string; i++) + { + const char val = str[i]; + if(val < '0' || val > '9') + { + if (val == '.' || val == ',') + is_real = true; + else + is_string = true; + } + } + + // Una volta che ho capito che ho davanti tento il trick! + if (is_string) + { + // Tento la data + const TDate pop(str); + + if (pop.ok()) + ret.add(pop); + else + ret.add(str); + } + else if (is_real) + ret.add(real(str)); + else + { + char* err; + const long long_val = strtol(str, &err, 10); + // Ho avuto un errore? Il controllo ha fallito! + if(err && *err) + { + ret.add(str); + } + else + { + ret.add(long_val); + } + } + + return ret; +} + +TVariant& TFP_expression::parse_read(const TString& str, TRiga_documento& rdoc) +{ + TString tabella, campo; + extract_info(str, tabella, campo, nullptr); + return do_read(tabella, campo, rdoc); +} + +TVariant& TFP_expression::do_read(const TString& tabella, const TString& campo, TRiga_documento& rdoc) +{ + int file; + calc_table(tabella, file); + + switch (file) + { + case LF_DOC: + return get_value(rdoc.doc(), campo); + case LF_RIGHEDOC: + return get_value(rdoc, campo); + case LF_CLIFO: + return get_value(rdoc.doc().clifor(), campo); + case LF_CFVEN: + return get_value(rdoc.doc().clifor().vendite(), campo); + case LF_LETINT: + return get_value(rdoc.doc().clifor().lettera(), campo); + case LF_ANAMAG: + return get_value(rdoc.articolo(), campo); + default: + static TVariant null_var(EMPTY_STRING); + return null_var; + } +} + +TVariant& TFP_expression::parse_search(const TString& str, TRiga_documento& rdoc) +{ + TString tabella, campo; + TToken_string input_search, search; + int file; + + extract_info(str, tabella, campo, &input_search); + const bool multi_table = calc_table(tabella, file); + + // Parso ogni singolo token della ricerca + FOR_EACH_TOKEN(input_search, tok) + { + search.add(parse_expression(tok, rdoc).as_string()); + } + + if (multi_table) + { + return get_value(cache().get(tabella, search), campo); + } + else + { + return get_value(cache().get(file, search), campo); + } +}