diff --git a/bs/bs0.cpp b/bs/bs0.cpp new file mode 100644 index 000000000..520da762f --- /dev/null +++ b/bs/bs0.cpp @@ -0,0 +1,13 @@ +#include +#include "bs0.h" + +int main(int argc, char** argv) +{ + const int p = argc > 1 ? argv[1][1]-'0' : 0; + switch(p) + { + case 1: bs0200(argc, argv); break; + default: bs0100(argc, argv); break; + } + return 0; +} diff --git a/bs/bs0.h b/bs/bs0.h new file mode 100644 index 000000000..1c404d95e --- /dev/null +++ b/bs/bs0.h @@ -0,0 +1,3 @@ +int bs0200(int argc, char* argv[]); +int bs0100(int argc, char* argv[]); + diff --git a/bs/bs0100.cpp b/bs/bs0100.cpp new file mode 100644 index 000000000..bba9b9049 --- /dev/null +++ b/bs/bs0100.cpp @@ -0,0 +1,20 @@ +#include +#include "bs0.h" + +#include + +class TParametri_ditta : public TConfig_application +{ +public: + virtual bool check_autorization() const { return false; } + virtual const char* get_mask_name() const { return "bs0100a"; } + + TParametri_ditta() : TConfig_application(CONFIG_DITTA) {} +}; + +int bs0100(int argc, char* argv[]) +{ + TParametri_ditta appc; + appc.run(argc, argv, TR("Parametri Bee Store")); + return 0; +} \ No newline at end of file diff --git a/bs/bs0100a.uml b/bs/bs0100a.uml new file mode 100644 index 000000000..e6a184ade --- /dev/null +++ b/bs/bs0100a.uml @@ -0,0 +1,22 @@ +TOOLBAR "topbar" 0 0 0 2 +#include +ENDPAGE + +PAGE "Parametri Bee Store" 0 2 0 0 + +GROUPBOX DLG_NULL 78 3 +BEGIN + PROMPT 1 1 "@bODBC" +END + +STRING 101 50 +BEGIN + PROMPT 2 2 "Data Source Name (DSN) " + CHECKTYPE REQUIRED + FIELD DSN +END + + +ENDPAGE + +ENDMASK \ No newline at end of file diff --git a/bs/bs0200.cpp b/bs/bs0200.cpp new file mode 100644 index 000000000..40bf9b6da --- /dev/null +++ b/bs/bs0200.cpp @@ -0,0 +1,509 @@ +#include +#include +#include +#include +#include + +#include <../ve/velib.h> + +#include "bs0.h" + + +/////////////////////////////////////////////////////////// +// TBeeStore_mask +/////////////////////////////////////////////////////////// + +class TBeeStore_mask : public TAutomask +{ +protected: + virtual bool on_field_event(TOperable_field& o, TField_event e, long jolly); + +public: + void autoload(); + void autosave() const; + + bool get_bool(const char* fld) { TMask_field* f = find_by_fieldname(fld); return f ? f->get().full() : false; } + TDate get_date(const char* fld) { TMask_field* f = find_by_fieldname(fld); return TDate(f ? f->get() : EMPTY_STRING); } + + TBeeStore_mask() : TAutomask("bs0200a") { autoload(); } + ~TBeeStore_mask() { autosave(); } +}; + +bool TBeeStore_mask::on_field_event(TOperable_field& o, TField_event e, long jolly) +{ + return true; +} + +void TBeeStore_mask::autoload() +{ + FOR_EACH_MASK_FIELD(*this, i, f) + { + const TFieldref* fr = f->field(); + if (fr != NULL) + f->set(ini_get_string(CONFIG_DITTA, "bs", fr->name())); + } +} + +void TBeeStore_mask::autosave() const +{ + FOR_EACH_MASK_FIELD(*this, i, f) + { + const TFieldref* fr = f->field(); + if (fr != NULL) + ini_set_string(CONFIG_DITTA, "bs", fr->name(), f->get()); + } +} + +/////////////////////////////////////////////////////////// +// TBeeStore_sync +/////////////////////////////////////////////////////////// + +class TBeeStore_sync : public TSkeleton_application +{ + TString16 _dsn; + TLog_report* _log; + +protected: + bool save_doc(TDocumento* doc) const; + + void load_origine_1(TISAM_recordset& out_set, const char* in_table, const TString_array& pairs); + void save_origine_2(TISAM_recordset& in_set, const char* out_table, const TString_array& pairs); + + void sync_table(TISAM_recordset& in_set, const char* out_table, const TString_array& pairs); + void sync_table(const char* in_table, const char* out_table, const TString_array& fields, const TDate& dal); + void sync_table(const int logicnum, const char* out_table, const TString_array& fields, const TDate& dal); + + void sync_iva(const TDate& dal); + void sync_ums(const TDate& dal); + void sync_lines(const TDate& dal); + void sync_catmer(const TDate& dal); + void sync_anamag(const TDate& dal); + void sync_scontrini(const TDate& dal); + +public: + virtual void main_loop(); +}; + +const TString& date2sql(const TDate& d) +{ + TString& tmp = get_tmp_string(); + tmp.format("DATEFROMPARTS(%d,%d,%d)", d.year(), d.month(), d.day()); + return tmp; +} + + +const TString& var2sql(const TVariant& var) +{ + TString& tmp = get_tmp_string(); + switch (var.type()) + { + case _boolfld: + tmp = var.as_bool() ? "1" : "0"; + break; + case _datefld: + tmp = date2sql(var.as_date()); + break; + default: + { + var.as_string(tmp); + const int pos = tmp.find('\''); + if (pos >= 0) + { + for (int i = tmp.len()-1; i >= pos; i--) + if (tmp[i] == '\'') tmp.insert("'", i); + } + tmp.insert("'"); + tmp << "'"; + } + break; + } + return tmp; +} + +// Carica da Bee Store i record con Origine=1, cioè generati da lui ed eventualmente aggiorna i corrispondenti in Campo +void TBeeStore_sync::load_origine_1(TISAM_recordset& out_set, const char* in_table, const TString_array& pairs) +{ + TString str(255); + str << "ODBC(" << _dsn << ")\n" + << "SELECT * FROM " << in_table << " WHERE Origine=1;"; + TODBC_recordset odbc(str); + const TRecnotype n = odbc.items(); + if (n > 0) + { + TLocalisamfile& file = out_set.cursor()->file(); + const RecDes& rd = file.curr().rec_des(); + TToken_string key_fields; + for (int i = 0; i < rd.Ky->NkFields; i++) + { + const int nf = rd.Ky[0].FieldSeq[i] % MaxFields; + key_fields.add(rd.Fd[nf].Name); + } + + str.format(TR("Importazione %ld record dalla tabella %s"), n, in_table); + _log->log(0, ""); + _log->log(0, str); + + TProgress_monitor pi(n, str); + for (bool ok = odbc.move_first(); ok; ok = odbc.move_next()) + { + file.zero(); + TString80 cfld, bfld; // Campo field e BeeStore field + FOR_EACH_ARRAY_ROW(pairs, p, row) + { + bfld = row->get(0); + cfld = row->get(); + const int pos = key_fields.get_pos(cfld); + if (pos >= 0) + { + const TVariant& var = odbc.get(bfld); + if (!var.is_null()) + file.put(cfld, var.as_string()); + if (pos == key_fields.items()-1) + break; + } + } + + int err = file.read(_isequal, _lock); + if (err == NOERR) + { + bool dirty = false; + const TDate dataagg = file.get("DATAAGG"); + TDate dtultagg = odbc.get("DtUltAgg").as_date(); + if (!dtultagg.ok()) dtultagg = TODAY; + + str.format("record"); + FOR_EACH_TOKEN(key_fields, f) + str << ' ' << file.get(f); + + if (dtultagg >= dataagg) + { + FOR_EACH_ARRAY_ROW(pairs, r,row) + { + bfld = row->get(0); + cfld = row->get(); + if (cfld[0] >= 'A' && cfld.find("->") < 0 && key_fields.get_pos(cfld) < 0) // Aggiorno solo i campi NON chiave + { + const TString& vec = file.get(cfld); + const TString& nov = odbc.get(bfld).as_string(); + if (nov != vec) + { + if (!dirty) + str << ' ' << bfld << "='" << nov << '\''; + file.put(cfld, nov); + dirty = true; + } + } + } + if (dirty) + { + file.put("UTENTE", "BEESTORE"); + file.put("DATAAGG", dtultagg); + } + else + str << " Nessuna variazione pertinente"; + } + else + str << " Data di ultimo aggiornamento obsoleta"; + if (dirty) + { + if (file.rewrite() == 0) + _log->log(1, str); + else + { + TString80 err; err << TR("ERRORE ") << err << TR(" aggiornando il "); + str.insert(err); + _log->log(2, str); + } + } + else + { + _log->log(0, str); + file.reread(_unlock); + } + } else + if (err == _iskeynotfound) + { + file.zero(); + FOR_EACH_ARRAY_ROW(pairs, r,row) + { + bfld = row->get(0); + cfld = row->get(); + if (cfld[0] >= 'A' && cfld.find("->")) + { + const TString& nov = odbc.get(bfld).as_string(); + file.put(cfld, nov); + } + } + if (file.write() == 0) + _log->log(1, str); + else + { + TString80 msg; msg << TR("ERRORE ") << err << TR(" inserendo il "); + str.insert(msg); + _log->log(2, str); + } + } + } + + str.cut(0) << "DELETE FROM " << in_table << " WHERE Origine=1;"; + odbc.exec(str); + } +} + +void TBeeStore_sync::save_origine_2(TISAM_recordset& in_set, const char* out_table, const TString_array& fields) +{ + const TRecnotype n = in_set.items(); + TString str(255); + str << "ODBC(" << _dsn << ")\n"; + TODBC_recordset odbc(str); + + str.cut(0) << "DELETE FROM " << out_table << " WHERE Origine=2;"; + odbc.exec(str); + + str.format(TR("Esportazione %ld record nella tabella %s"), n, out_table); + _log->log(0, ""); + _log->log(0, str); + + TProgress_monitor pi(n, str); + for (bool ok = in_set.move_first(); ok; ok = in_set.move_next()) + { + str.cut(0) << "INSERT INTO " << out_table << " ("; + FOR_EACH_ARRAY_ROW(fields, sr, srow) + str << (sr ? ", " : "") << srow->get(0); + str << ", Origine, Errore, DTUltAgg"; + str << ")\nVALUES ("; + + FOR_EACH_ARRAY_ROW(fields, ir, irow) + { + if (ir) + { + str << ", "; + if (str.len() - str.rfind('\n') > 80) + str << '\n'; + } + const TFixed_string cfld = irow->get(1); + if (cfld[0] >= 'A' && cfld[0] <= 'Z') + { + const TVariant& var = in_set.get(cfld); + str << var2sql(var); + } else + if (cfld.find("->") > 0) + { + const TVariant& var = in_set.get(cfld); + str << var2sql(var); + } + else + str << cfld; + } + str << ", 2, 0, GETDATE()"; + str << ");"; + + if (odbc.exec(str) <= 0) + _log->log(1, str); + + if (!pi.add_status()) + break; + } + + odbc.exec("COMMIT;"); +} + +void TBeeStore_sync::sync_table(TISAM_recordset& in_set, const char* out_table, const TString_array& fields) +{ + load_origine_1(in_set, out_table, fields); + save_origine_2(in_set, out_table, fields); +} + +void TBeeStore_sync::sync_table(const char* table, const char* out_table, const TString_array& fields, const TDate& dal) +{ + TString q; + q << "USE " << table << " SELECT BETWEEN(DATAAGG,"<< dal.date2ansi() << ",0)"; + TISAM_recordset set(q); + sync_table(set, out_table, fields); +} + +void TBeeStore_sync::sync_table(const int logicnum, const char* out_table, const TString_array& fields, const TDate& dal) +{ + TString4 q; q << logicnum; + sync_table(q, out_table, fields, dal); +} + +void TBeeStore_sync::sync_ums(const TDate& dal) +{ + TString_array fields; + fields.add("CodUntMis|CODTAB"); + fields.add("DSUntMis|S0"); + sync_table("%UMS", "tieUntMisura", fields, dal); +} + +void TBeeStore_sync::sync_iva(const TDate& dal) +{ + TString_array fields; + fields.add("CodIva|CODTAB"); + fields.add("CodIvaSt|CODTAB"); + fields.add("DSIva|S0"); + fields.add("Aliquota|R0"); + + sync_table("%IVA", "tieIva", fields, dal); +} + +void TBeeStore_sync::sync_lines(const TDate& dal) +{ + TString_array fields; + fields.add("CodLinea|CODTAB"); + fields.add("DSLinea|S0"); + + TString query; + query << "USE GMC SELECT (CODTAB?='???')"; + if (dal.ok()) + query << "&&(BETWEEN(DATAAGG,"<< dal.date2ansi() << ",0))"; + + TISAM_recordset lin(query); + sync_table(lin, "tieLineeArt", fields); +} + +void TBeeStore_sync::sync_catmer(const TDate& dal) +{ + TString_array fields; + fields.add("CodCategoriaMerceologica|CODTAB"); + fields.add("DSCategoriaMerceologica|S0"); + fields.add("CodTipoEtichetta|''"); + + sync_table("GMC", "tieCategorieMerceologiche", fields, dal); +} + +void TBeeStore_sync::sync_anamag(const TDate& dal) +{ + TString_array fields; + fields.add("CodPadre|"ANAMAG_CODART); + fields.add("DSArticolo|"ANAMAG_DESCR); + fields.add("DSArticoloAgg|"ANAMAG_DESCRAGG"[1,70]"); + fields.add("CodUntMagazzino|49->UM"); + fields.add("CodIva|"ANAMAG_CODIVA); + fields.add("CodLinea|"ANAMAG_GRMERC"[1,3]"); + fields.add("CodCategMerceologica|"ANAMAG_GRMERC); + fields.add("Bloccato|"ANAMAG_SOSPESO); + + TString query; + query << "USE 47\nJOIN 49 INTO CODART==CODART"; + if (dal.ok()) + query << "\nSELECT BETWEEN(DATAAGG,"<< dal.date2ansi() << ",0)"; + TISAM_recordset art(query); + sync_table(art, "tieArticoli", fields); +} + +bool TBeeStore_sync::save_doc(TDocumento* doc) const +{ + if (doc != NULL && doc->rows() > 0) + { + const int err = doc->write(); + if (err != NOERR) + { + TString msg; + msg.format(FR("Errore %d in registrazione scontrino %s/%d del %s"), err, + (const char*)doc->get(DOC_CODNUM), doc->get_long(DOC_NDOC), + (const char*)doc->get(DOC_DATADOC)); + _log->log(2, msg); + msg << TR("\nSi desidera proseguire ugualmente?"); + if (!noyes_box(msg)) + return false; + } + } + return true; +} + +void TBeeStore_sync::sync_scontrini(const TDate& dal) +{ + const TString4 codnum = ini_get_string(CONFIG_DITTA, "bs", DOC_CODNUM); + const TString4 tipodoc = ini_get_string(CONFIG_DITTA, "bs", DOC_TIPODOC); + if (codnum.blank() || tipodoc.blank()) + { + _log->log(2, "Configurare numerazione e tipo documento per movimenti Bee Store"); + return; + } + + TString str(255); + str << "ODBC(" << _dsn << ")\n"; + str << "SELECT * FROM tieDMovMag WHERE Origine=1"; + if (dal.ok()) + str << " AND DataMov>=" << date2sql(dal); + str << "\nORDER BY NumMov,NumRiga"; + + TODBC_recordset mov(str); + TProgress_monitor pi(mov.items(), str); + + TString num_mov; + TDocumento* doc = NULL; + + for (bool ok = mov.move_first(); ok; ok = mov.move_next()) + { + const TString80 nm = mov.get("NumMov").as_string(); + if (nm != num_mov) + { + if (!save_doc(doc)) + break; + delete doc; + + num_mov = nm; + const TDate datadoc = mov.get("DataMov").as_date(); + doc = new TDocumento('D', datadoc.year(), codnum, 0L); + doc->put(DOC_TIPODOC, tipodoc); + doc->put(DOC_DATADOC, datadoc); + + const TString& codval = mov.get("CodValuta").as_string(); + if (is_true_value(codval)) + { + doc->put(DOC_CODVAL, codval); + doc->put(DOC_CAMBIO, mov.get("CambioValuta").as_string()); + } + } + TRiga_documento& rdoc = doc->new_row("01"); + rdoc.put(RDOC_CODART, mov.get("CodArticolo").as_string()); + rdoc.put(RDOC_CODARTMAG, mov.get("CodArticolo").as_string()); + rdoc.put(RDOC_CHECKED, true); + rdoc.put(RDOC_UMQTA, mov.get("CodUntMis").as_string()); + rdoc.put(RDOC_PREZZO, mov.get("PrzCassaValuta").as_real()); + } + + save_doc(doc); +} + +void TBeeStore_sync::main_loop() +{ + TBeeStore_mask mask; + + _dsn = ini_get_string(CONFIG_DITTA, "bs", "DSN", "BEESTORE"); + + while (mask.run() == K_ENTER) + { + mask.autosave(); // Rende definitivi tutti i paramentri in [bs] + _log = new TLog_report; + + const TDate dal = mask.get_date("SyncDate"); + + if (mask.get_bool("SyncUMS")) + sync_ums(dal); + if (mask.get_bool("SyncIVA")) + sync_iva(dal); + if (mask.get_bool("SyncLinee")) + sync_lines(dal); + if (mask.get_bool("SyncCatMer")) + sync_catmer(dal); + if (mask.get_bool("SyncAnamag")) + sync_anamag(dal); + if (mask.get_bool("SyncSontr")) + sync_scontrini(dal); + + _log->preview(); + delete _log; + _log = NULL; + } + +} + +int bs0200(int argc, char* argv[]) +{ + TBeeStore_sync bss; + bss.run(argc, argv, TR("Bee Store")); + return 0; +} diff --git a/bs/bs0200a.uml b/bs/bs0200a.uml new file mode 100644 index 000000000..72f7461bd --- /dev/null +++ b/bs/bs0200a.uml @@ -0,0 +1,107 @@ +TOOLBAR "topbar" 0 0 0 2 +#include +ENDPAGE + +PAGE "Sincronizzazione Bee Store" 0 2 0 0 + +GROUPBOX DLG_NULL 78 8 +BEGIN + PROMPT 1 1 "@bArchivi" +END + +BOOLEAN 103 +BEGIN + PROMPT 2 2 "Unità di misura " + FIELD SyncUMS +END + +BOOLEAN 104 +BEGIN + PROMPT 2 3 "Codici IVA " + FIELD SyncIVA +END + +BOOLEAN 105 +BEGIN + PROMPT 2 4 "Linee Articolo " + FIELD SyncLinee +END + +BOOLEAN 106 +BEGIN + PROMPT 2 5 "Categorie Merceol." + FIELD SyncCatMer +END + +BOOLEAN 147 +BEGIN + PROMPT 2 6 "Articoli " + FIELD SyncAnamag +END + +BOOLEAN 148 +BEGIN + PROMPT 2 7 "Scontrini " + FIELD SyncScontr +END + +GROUPBOX DLG_NULL 78 8 +BEGIN + PROMPT 1 10 "@bFiltri" +END + +DATE 100 +BEGIN + PROMPT 2 11 "Dalla data di modifica " + FIELD SyncDate +END + +ENDPAGE + +PAGE "Parametri" 0 2 0 0 + +GROUPBOX DLG_NULL 78 6 +BEGIN + PROMPT 1 1 "@bScontrini" +END + +STRING 201 4 +BEGIN + PROMPT 2 2 "Codice numerazione " + USE %NUM + INPUT CODTAB 201 + DISPLAY "Codice" CODTAB + DISPLAY "Descrizione@50" S0 + OUTPUT 201 CODTAB + OUTPUT 202 S0 + CHECKTYPE REQUIRED + FIELD CODNUM +END + +STRING 202 50 46 +BEGIN + PROMPT 30 2 "" + FLAGS "D" +END + +STRING 203 4 +BEGIN + PROMPT 2 3 "Tipo documento " + USE %TIP + INPUT CODTAB 203 + COPY DISPLAY 201 + OUTPUT 203 CODTAB + OUTPUT 204 S0 + CHECKTYPE REQUIRED + FIELD TIPODOC +END + +STRING 204 50 46 +BEGIN + PROMPT 30 3 "" + FLAGS "D" +END + +ENDPAGE + +ENDMASK \ No newline at end of file diff --git a/bs/bsmenu.men b/bs/bsmenu.men new file mode 100644 index 000000000..083916b46 --- /dev/null +++ b/bs/bsmenu.men @@ -0,0 +1,7 @@ +[BSMENU_001] +Caption = "Bee Store" +Picture = +Module = bs +Flags = "F" +Item_01 = "Configurazione", "bs0 -0", "F", 9015 +Item_02 = "Sincronizzazione", "bs0 -1", "F", 9015