diff --git a/bs/bs0100.cpp b/bs/bs0100.cpp index bba9b9049..1a14c9d49 100644 --- a/bs/bs0100.cpp +++ b/bs/bs0100.cpp @@ -1,10 +1,47 @@ -#include +#include +#include +#include + #include "bs0.h" -#include +class TParametri_mask : public TAutomask +{ +protected: + virtual bool on_field_event(TOperable_field& o, TField_event e, long jolly); + +public: + TParametri_mask(const char* n) : TAutomask(n) {} +}; + + +bool TParametri_mask::on_field_event(TOperable_field& o, TField_event e, long jolly) +{ + if (e == fe_button && o.is_edit()) + { + TConfig odbc("c:/windows/odbc.ini", "ODBC 32 bit Data Sources"); + TAssoc_array& var = odbc.list_variables(); + if (!var.empty()) + { + TArray_sheet dsn(-1, -1, 78, 20, TR("Sorgenti dati ODBC"), HR("Nome@25|Driver@50")); + TToken_string row; + FOR_EACH_ASSOC_OBJECT(var, obj, key, itm) + { + row = key; + row.add(*(TString*)itm); + dsn.add(row); + } + if (dsn.run() == K_ENTER) + o.set(dsn.row(-1).get(0)); + } + } + return true; +} class TParametri_ditta : public TConfig_application { +protected: + virtual TMask* create_mask(const TFilename& fname); + public: virtual bool check_autorization() const { return false; } virtual const char* get_mask_name() const { return "bs0100a"; } @@ -12,6 +49,11 @@ public: TParametri_ditta() : TConfig_application(CONFIG_DITTA) {} }; +TMask* TParametri_ditta::create_mask(const TFilename& fname) +{ + return new TParametri_mask(fname); +} + int bs0100(int argc, char* argv[]) { TParametri_ditta appc; diff --git a/bs/bs0100a.uml b/bs/bs0100a.uml index e6a184ade..c6ed42681 100644 --- a/bs/bs0100a.uml +++ b/bs/bs0100a.uml @@ -1,10 +1,10 @@ TOOLBAR "topbar" 0 0 0 2 -#include +#include ENDPAGE PAGE "Parametri Bee Store" 0 2 0 0 -GROUPBOX DLG_NULL 78 3 +GROUPBOX DLG_NULL 78 5 BEGIN PROMPT 1 1 "@bODBC" END @@ -12,10 +12,16 @@ END STRING 101 50 BEGIN PROMPT 2 2 "Data Source Name (DSN) " + FLAGS "B" CHECKTYPE REQUIRED FIELD DSN END +STRING 102 260 50 +BEGIN + PROMPT 2 3 "File di log errori SQL " + FIELD Log +END ENDPAGE diff --git a/bs/bs0200.cpp b/bs/bs0200.cpp index 40bf9b6da..60a9413da 100644 --- a/bs/bs0200.cpp +++ b/bs/bs0200.cpp @@ -1,13 +1,16 @@ #include #include +#include #include #include #include -#include <../ve/velib.h> +#include "../mg/mglib.h" #include "bs0.h" +#include "../ve/condv.h" +#include "../ve/rcondv.h" /////////////////////////////////////////////////////////// // TBeeStore_mask @@ -22,20 +25,22 @@ 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); } + 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; -} +{ return true; } void TBeeStore_mask::autoload() { + // Carica i valori default dei parametri dal [bs] in ditta,ini FOR_EACH_MASK_FIELD(*this, i, f) { const TFieldref* fr = f->field(); @@ -46,12 +51,13 @@ void TBeeStore_mask::autoload() 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()); - } + // Salva i valori dei parametri in [bs] in ditta,ini + 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()); + } } /////////////////////////////////////////////////////////// @@ -61,48 +67,76 @@ void TBeeStore_mask::autosave() const class TBeeStore_sync : public TSkeleton_application { TString16 _dsn; + TFilename _sqlog; TLog_report* _log; protected: - bool save_doc(TDocumento* doc) const; + bool save_and_delete_doc(TMov_mag*& 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); + 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, const TDate& al); + void sync_table(const int logicnum, const char* out_table, + const TString_array& fields, const TDate& dal, const TDate& al); + void sync_iva (const TDate& dal, const TDate& al); + void sync_ums (const TDate& dal, const TDate& al); + void sync_lines (const TDate& dal, const TDate& al); + void sync_catmer (const TDate& dal, const TDate& al); + void sync_val (const TDate& dal, const TDate& al); + void sync_anamag (const TDate& dal, const TDate& al); + void sync_scontrini(const TDate& dal, const TDate& al); + void sync_listino (const TString& listino); + public: + virtual bool create(); virtual void main_loop(); }; +// Converte una TDate in una data SQL const TString& date2sql(const TDate& d) { TString& tmp = get_tmp_string(); - tmp.format("DATEFROMPARTS(%d,%d,%d)", d.year(), d.month(), d.day()); + if (d.ok()) + tmp.format("'%02d-%02d-%04d'", d.day(), d.month(), d.year()); + else + tmp = "NULL"; return tmp; } - +// Coverte un qualsiasi TVariant in stringa SQL const TString& var2sql(const TVariant& var) { TString& tmp = get_tmp_string(); switch (var.type()) { + case _nullfld: + tmp = "NULL"; + break; case _boolfld: tmp = var.as_bool() ? "1" : "0"; break; case _datefld: tmp = date2sql(var.as_date()); break; + case _intfld: + case _longfld: + var.as_string(tmp); + break; + case _realfld: + if (var.is_empty()) + tmp = "0"; + else + { + tmp = var.as_real().string(0, 2); + if (tmp.ends_with(".00")) + tmp.rtrim(3); + } + break; default: { var.as_string(tmp); @@ -124,8 +158,11 @@ const TString& var2sql(const TVariant& var) 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;"; + str << "ODBC(" << _dsn << ")\nSELECT "; + FOR_EACH_ARRAY_ROW(pairs, f, row) + str << row->get(0) << ','; + str.rtrim(1); // toglie ultima virgola + str << "\nFROM " << in_table << " WHERE Origine=1;"; TODBC_recordset odbc(str); const TRecnotype n = odbc.items(); if (n > 0) @@ -282,6 +319,26 @@ void TBeeStore_sync::save_origine_2(TISAM_recordset& in_set, const char* out_tab str << '\n'; } const TFixed_string cfld = irow->get(1); + if (cfld.find("SCONTO")>=0) + { + real sconto; + const TString& exp = in_set.get(cfld).as_string(); + if (exp.full()) + { + if (real::is_natural(exp)) + sconto = real(exp); + else + { + TString80 goodexp; real val_perc; + if (scontoexpr2perc(exp, false, goodexp, val_perc) && val_perc != UNO) + { + sconto = CENTO - CENTO*val_perc; + sconto.round(5); + } + } + } + str << var2sql(sconto); + } else if (cfld[0] >= 'A' && cfld[0] <= 'Z') { const TVariant& var = in_set.get(cfld); @@ -314,29 +371,44 @@ void TBeeStore_sync::sync_table(TISAM_recordset& in_set, const char* out_table, 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& append_select_range(TString& q, const TDate& dal, const TDate& al) +{ + q << "\nSELECT (UTENTE!=\"BEESTORE\")"; + if (dal.ok() || al.ok()) + { + q << "&&(BETWEEN(DATAAGG," + << dal.date2ansi() << ',' << al.date2ansi() << "))"; + } + return q; +} + +void TBeeStore_sync::sync_table(const char* table, const char* out_table, + const TString_array& fields, const TDate& dal, const TDate& al) { TString q; - q << "USE " << table << " SELECT BETWEEN(DATAAGG,"<< dal.date2ansi() << ",0)"; + q << "USE " << table; + append_select_range(q, dal, al); + 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) +void TBeeStore_sync::sync_table(const int logicnum, const char* out_table, + const TString_array& fields, const TDate& dal, const TDate& al) { TString4 q; q << logicnum; - sync_table(q, out_table, fields, dal); + sync_table(q, out_table, fields, dal, al); } -void TBeeStore_sync::sync_ums(const TDate& dal) +void TBeeStore_sync::sync_ums(const TDate& dal, const TDate& al) { TString_array fields; fields.add("CodUntMis|CODTAB"); fields.add("DSUntMis|S0"); - sync_table("%UMS", "tieUntMisura", fields, dal); + sync_table("%UMS", "tieUntMisura", fields, dal, al); } -void TBeeStore_sync::sync_iva(const TDate& dal) +void TBeeStore_sync::sync_iva(const TDate& dal, const TDate& al) { TString_array fields; fields.add("CodIva|CODTAB"); @@ -344,35 +416,35 @@ void TBeeStore_sync::sync_iva(const TDate& dal) fields.add("DSIva|S0"); fields.add("Aliquota|R0"); - sync_table("%IVA", "tieIva", fields, dal); + sync_table("%IVA", "tieIva", fields, dal, al); } -void TBeeStore_sync::sync_lines(const TDate& dal) +void TBeeStore_sync::sync_lines(const TDate& dal, const TDate& al) { 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))"; - + query << "USE GMC"; + append_select_range(query, dal, al); + query << "&&(CODTAB?='???')"; + TISAM_recordset lin(query); sync_table(lin, "tieLineeArt", fields); } -void TBeeStore_sync::sync_catmer(const TDate& dal) +void TBeeStore_sync::sync_catmer(const TDate& dal, const TDate& al) { TString_array fields; fields.add("CodCategoriaMerceologica|CODTAB"); fields.add("DSCategoriaMerceologica|S0"); fields.add("CodTipoEtichetta|''"); - sync_table("GMC", "tieCategorieMerceologiche", fields, dal); + sync_table("GMC", "tieCategorieMerceologiche", fields, dal, al); } -void TBeeStore_sync::sync_anamag(const TDate& dal) +void TBeeStore_sync::sync_anamag(const TDate& dal, const TDate& al) { TString_array fields; fields.add("CodPadre|"ANAMAG_CODART); @@ -385,114 +457,209 @@ void TBeeStore_sync::sync_anamag(const TDate& dal) 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)"; + query << "USE " << LF_ANAMAG; + append_select_range(query, dal, al); + query << "\nJOIN " << LF_UMART << " INTO CODART==CODART"; + TISAM_recordset art(query); sync_table(art, "tieArticoli", fields); + + fields.destroy(); + fields.add("CodArticolo|"ANAMAG_CODART); + fields.add("CodPadre|"ANAMAG_CODART); + save_origine_2(art, "tieArtVarianti", fields); } -bool TBeeStore_sync::save_doc(TDocumento* doc) const +bool TBeeStore_sync::save_and_delete_doc(TMov_mag*& doc) const { - if (doc != NULL && doc->rows() > 0) + int err = 0; + if (doc != NULL) { - 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; + if (doc->rows() > 0) + { + TLocalisamfile mm(LF_MOVMAG); + err = doc->write(mm); + if (err != NOERR) + { + TString msg; + msg.format(FR("Errore %d in registrazione scontrino %ld del %s"), err, + doc->get_long(MOVMAG_NUMREG), (const char*)doc->get(MOVMAG_DATAREG)); + _log->log(2, msg); + msg << TR("\nSi desidera proseguire ugualmente?"); + if (noyes_box(msg)) + err = 0; + } } + delete doc; + doc = NULL; } - return true; + return err == 0; } -void TBeeStore_sync::sync_scontrini(const TDate& dal) +void TBeeStore_sync::sync_val(const TDate& dal, const TDate& al) { - 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()) + TString_array fields; + fields.add("CodValuta|CODTAB"); + fields.add("DSValuta|S0"); + fields.add("Simbolo|CODTAB"); + sync_table("%VAL", "tieValute", fields, dal, al); +} + +void TBeeStore_sync::sync_listino(const TString& listino) +{ + TString str(255); + str << "ODBC(" << _dsn << ")\n"; + TODBC_recordset prz(str); + + str = "DELETE FROM tiePrzVendita WHERE Origine=1"; + prz.exec(str); + + str.cut(0) << "USE " << LF_RCONDV + << "\nFROM TIPO=L TIPORIGA=A COD=" << listino + << "\nTO TIPO=L TIPORIGA=A COD=" << listino; + TISAM_recordset lis(str); + if (lis.move_first()) { - _log->log(2, "Configurare numerazione e tipo documento per movimenti Bee Store"); + TString16 eur; eur << "CodValuta|'" << TCurrency::get_euro_val() << "'"; + + TString16 key; key << "L||||" << listino; + const TRectype& condv = cache().get(LF_CONDV, key); + + TDate dt_inizio = condv.get(CONDV_VALIN); + if (!dt_inizio.ok()) dt_inizio = TDate(1,1,2000); + TDate dt_fine = condv.get(CONDV_VALFIN); + if (dt_fine < dt_inizio) dt_fine = TDate(31,12,2100); + + TString descr; descr << "DSListino|'" << condv.get(CONDV_DESCR) << '\''; + TString dtini; dtini << "DTInizio|'" << dt_inizio.string() << '\''; + TString dtfin; dtfin << "DTFine|'" << dt_fine.string() << '\''; + + TString_array fields; + fields.add("Cod_PK|"RCONDV_CODRIGA); + fields.add("CodPadre|"RCONDV_CODRIGA); + //fields.add("CodArticolo|"RCONDV_CODRIGA); // NON metterlo! + fields.add("TipoPrezzo|'1'"); // 1=Listino + fields.add(eur); + fields.add("Prezzo|"RCONDV_PREZZO); + fields.add("Prezzo2|0"); + fields.add("Sconto|"RCONDV_SCONTO); + if (real::is_natural(listino)) + fields.add("NumListino|"RCONDV_COD); + fields.add(descr); + fields.add(dtini); + fields.add(dtfin); + + save_origine_2(lis, "tiePrzVendita", fields); + } +} + +void TBeeStore_sync::sync_scontrini(const TDate& dal, const TDate& al) +{ + const TString8 codcaus = ini_get_string(CONFIG_DITTA, "bs", MOVMAG_CODCAUS); + if (codcaus.blank()) + { + _log->log(2, "Configurare parametri 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); + if (dal.ok() || al.ok()) + { + str << " AND DataMov"; + if (dal.ok() && al.ok()) + str << " BETWEEN " << date2sql(dal) << " AND " << date2sql(al); + else + { + if (dal.ok()) + str << ">=" << date2sql(dal); + else + str << "<=" << date2sql(al); + } + } str << "\nORDER BY NumMov,NumRiga"; TODBC_recordset mov(str); TProgress_monitor pi(mov.items(), str); TString num_mov; - TDocumento* doc = NULL; + TMov_mag* 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)) + if (!save_and_delete_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()); - } + doc = new TMov_mag; + doc->put(MOVMAG_CODCAUS, codcaus); + doc->put(MOVMAG_DATAREG, datadoc); } - 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()); + TRectype& rdoc = doc->new_row(); + rdoc.put(RMOVMAG_CODART, mov.get("CodArticolo").as_string()); + rdoc.put(RMOVMAG_UM, mov.get("CodUntMis").as_string()); + rdoc.put(RMOVMAG_PREZZO, mov.get("PrzCassaValuta").as_real()); } + save_and_delete_doc(doc); // Salva ultimo documento in sospeso +} - save_doc(doc); +bool TBeeStore_sync::create() +{ + _dsn = ini_get_string(CONFIG_DITTA, "bs", "DSN", "BEESTORE"); + _sqlog = ini_get_string(CONFIG_DITTA, "bs", "Log", ""); + + if (_dsn.full()) + { + TTimerind ti(10, TR("Connessione a SQL Server"), false, false); + ti.force_update(); + TString query; query << "ODBC(" << _dsn << ")\nSELECT * FROM tieValute;"; + TODBC_recordset recset(query); + recset.move_first(); + if (_sqlog.full() && _sqlog.is_relative_path()) + { + TFilename n; n.tempdir(); + n.add(_sqlog.name()); + _sqlog = n; + } + recset.set_log_file(_sqlog); + return TSkeleton_application::create(); + } + return error_box(FR("Impossibile connettersi al DSN '%s'"), (const char*)_dsn); + } 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"); + const TDate dal = mask.get_date("SyncDateFrom"); + const TDate al = mask.get_date("SyncDateTo"); if (mask.get_bool("SyncUMS")) - sync_ums(dal); + sync_ums(dal, al); if (mask.get_bool("SyncIVA")) - sync_iva(dal); + sync_iva(dal, al); if (mask.get_bool("SyncLinee")) - sync_lines(dal); + sync_lines(dal, al); if (mask.get_bool("SyncCatMer")) - sync_catmer(dal); + sync_catmer(dal, al); if (mask.get_bool("SyncAnamag")) - sync_anamag(dal); + sync_anamag(dal, al); + if (mask.get_bool("SyncVAL")) + sync_val(dal, al); + if (mask.get("SyncListino").full()) + sync_listino(mask.get("SyncListino")); if (mask.get_bool("SyncSontr")) - sync_scontrini(dal); + sync_scontrini(dal, al); _log->preview(); delete _log; diff --git a/bs/bs0200a.uml b/bs/bs0200a.uml index 72f7461bd..62ed116ea 100644 --- a/bs/bs0200a.uml +++ b/bs/bs0200a.uml @@ -29,7 +29,7 @@ END BOOLEAN 106 BEGIN - PROMPT 2 5 "Categorie Merceol." + PROMPT 2 5 "Categorie Merceologiche" FIELD SyncCatMer END @@ -39,12 +39,36 @@ BEGIN FIELD SyncAnamag END -BOOLEAN 148 +STRING 148 3 +BEGIN + PROMPT 40 6 "Listino " + USE LF_CONDV + INPUT TIPO "L" + INPUT CATVEN "" + INPUT TIPOCF "" + INPUT CODCF "" + INPUT COD 148 + DISPLAY "Codice" COD + DISPLAY "Descrizione@50" DESCR + DISPLAY "Valuta@5" CODVAL + DISPLAY "Inizio@10" VALIN + DISPLAY "Fine@10" VALFIN + OUTPUT 148 COD + FIELD SyncListino +END + +BOOLEAN 149 BEGIN PROMPT 2 7 "Scontrini " FIELD SyncScontr END +BOOLEAN 151 +BEGIN + PROMPT 40 2 "Valute" + FIELD SyncVAL +END + GROUPBOX DLG_NULL 78 8 BEGIN PROMPT 1 10 "@bFiltri" @@ -53,7 +77,13 @@ END DATE 100 BEGIN PROMPT 2 11 "Dalla data di modifica " - FIELD SyncDate + FIELD SyncDateFrom +END + +DATE 101 +BEGIN + PROMPT 42 11 " al " + FIELD SyncDateTo END ENDPAGE @@ -67,15 +97,15 @@ END STRING 201 4 BEGIN - PROMPT 2 2 "Codice numerazione " - USE %NUM + PROMPT 2 2 "Causale magazzino " + USE %CAU SELECT (S2[8,8]=1)&&(S6="P") INPUT CODTAB 201 DISPLAY "Codice" CODTAB DISPLAY "Descrizione@50" S0 OUTPUT 201 CODTAB OUTPUT 202 S0 CHECKTYPE REQUIRED - FIELD CODNUM + FIELD CODCAUS END STRING 202 50 46 @@ -84,24 +114,6 @@ BEGIN 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