#include #include #include #include #include #include #include #include "../ve/clifor.h" #include "../ve/condv.h" #include "../ve/rcondv.h" #include "../ve/velib.h" #include "ps1002.h" #include "ps1002100a.h" class TDoc_cache : public TCache { TString4 _codnum, _tipodoc; int _anno; long _codcf; TDate _data; protected: virtual void discarding(const THash_object* obj); virtual TObject* key2obj(const char* key); public: TDocumento& doc(const TToken_string& kdoc); TDoc_cache(const char* codnum, const char* tipodoc, const TDate& datadoc, const long codcf); }; //DISCARDING: salva un documento sul disco prima di eliminarlo dalla cache void TDoc_cache::discarding(const THash_object* obj) { TDocumento& doc = (TDocumento&)obj->obj(); int err = doc.rewrite(); } //KEY2OBJ:sceglie il documento giusto da disco in modo da poterlo continuare, o lo crea se non c'è TObject* TDoc_cache::key2obj(const char* key) { TDocumento* doc = NULL; TToken_string chiave(key); const char provv = chiave.get(0)[0]; const int anno = chiave.get_int(1); const TString& codnum = chiave.get(2); const long ndoc = chiave.get_long(3); doc = new TDocumento(provv, anno, codnum, ndoc); if (ndoc <= 0) { doc->put(DOC_PROVV, 'D'); doc->put(DOC_ANNO, _anno); doc->put(DOC_CODNUM, _codnum); doc->put(DOC_NDOC, 0); doc->put(DOC_TIPODOC, _tipodoc); doc->put(DOC_STATO, 1); doc->put(DOC_DATADOC, _data); doc->put(DOC_TIPOCF, 'C'); doc->put(DOC_CODCF, _codcf); doc->cli2doc(); //questo metodo riempie in automatico tutti i campi di testata collegati al cliente! doc->put(DOC_CAUSMAG, doc->tipo().caus_mov()); //causale magazzino collegata al tipo } return doc; } //DOC: restituisce un puntatore ad un documento identificato dalla chiave documento completa TDocumento& TDoc_cache::doc(const TToken_string& kdoc) { return *(TDocumento*)objptr(kdoc); } //metodo costruttore di una cache di 13 elementi TDoc_cache::TDoc_cache(const char* codnum, const char* tipodoc, const TDate& datadoc, const long codcf) : TCache(13) { _codnum = codnum; _tipodoc = tipodoc; _anno = datadoc.year(); _data = datadoc; _codcf = codcf; } /////////////////////////////////////////////////////////// // TAutomask /////////////////////////////////////////////////////////// class TEdit_rdocs_mask : public TAutomask { int _pos_art, _pos_desc, _pos_um, _pos_qta, _pos_qtaev, _pos_prz, _pos_iva, _pos_lav, _pos_col, _pos_dtprd_lav, _pos_qtaprd_lav, _pos_dtprd_col_1, _pos_qtaprd_col_1, _pos_dtprd_col_2, _pos_qtaprd_col_2, _pos_num, _pos_anno, _pos_provv, _pos_ndoc, _pos_nrig, _pos_desiva, _pos_deslav, _pos_descol; protected: virtual bool on_field_event(TOperable_field& o, TField_event e, long jolly); void fill_sheet(); void save_sheet(); const TString4 find_um(const TString& codart) const; const TString4 find_codiva(const TString& codart); real find_prezzo_articolo(const TString& codart) const; public: TEdit_rdocs_mask(); ~TEdit_rdocs_mask() {}; }; TEdit_rdocs_mask::TEdit_rdocs_mask() : TAutomask ("ps1002100a") { //assegna le posizioni delle colonne dello sheet TSheet_field& sf_righe = sfield(F_RIGHE); _pos_art = sf_righe.cid2index(S_CODART); _pos_desc = sf_righe.cid2index(S_DESCR); _pos_um = sf_righe.cid2index(S_UM); _pos_qta = sf_righe.cid2index(S_QTA); _pos_qtaev = sf_righe.cid2index(S_QTAEVASA); _pos_prz = sf_righe.cid2index(S_PREZZO); _pos_iva = sf_righe.cid2index(S_CODIVA); _pos_lav = sf_righe.cid2index(S_LAV); _pos_dtprd_lav = sf_righe.cid2index(S_DATAPROD_LAV); _pos_qtaprd_lav = sf_righe.cid2index(S_QTAPROD_LAV); _pos_col = sf_righe.cid2index(S_COLORE); _pos_dtprd_col_1 = sf_righe.cid2index(S_DATAPROD_COL_1); _pos_qtaprd_col_1 = sf_righe.cid2index(S_QTAPROD_COL_1); _pos_dtprd_col_2 = sf_righe.cid2index(S_DATAPROD_COL_2); _pos_qtaprd_col_2 = sf_righe.cid2index(S_QTAPROD_COL_2); _pos_num = sf_righe.cid2index(S_CODNUM); _pos_anno = sf_righe.cid2index(S_ANNO); _pos_provv = sf_righe.cid2index(S_PROVV); _pos_ndoc = sf_righe.cid2index(S_NDOC); _pos_nrig = sf_righe.cid2index(S_NRIGA); _pos_desiva = sf_righe.cid2index(S_DESIVA); _pos_deslav = sf_righe.cid2index(S_DESLAV); _pos_descol = sf_righe.cid2index(S_DESCOL); } bool TEdit_rdocs_mask::on_field_event(TOperable_field& o, TField_event e, long jolly) { switch (o.dlg()) { //maschera principale case F_RIGHE: if (e == se_notify_add) //righe aggiunte { TToken_string& riga_sheet = sfield(o.dlg()).row(jolly); //riga nuova dello sheet const TString& codnum = get(F_CODNUM); riga_sheet.add(codnum, _pos_num); const int anno = get_date(F_DATADOC).year(); riga_sheet.add(anno, _pos_anno); riga_sheet.add('D', _pos_provv); } if (e == se_query_del) //righe da eliminare { //solo le righe senza NDOC ed NRIGA possono essere eliminate! TToken_string& riga_sheet = sfield(o.dlg()).row(jolly); const long ndoc = riga_sheet.get_long(_pos_ndoc); const int nriga = riga_sheet.get_int(_pos_nrig); return ndoc == 0L || nriga == 0; } break; //maschera di sheet case S_CODART: if (e == fe_modify) { //al cambio articolo deve proporre il codiva, la um, il prezzo const TString& codart = o.get(); const TString& um = find_um(codart); o.mask().set(S_UM, um); const TString& codiva = find_codiva(codart); o.mask().set(S_CODIVA, codiva); const real prezzo = find_prezzo_articolo(codart); o.mask().set(S_PREZZO, prezzo); } break; case S_DATAPROD_LAV: if (e == fe_modify) { //all'uscita dal campo deve proporre la qta prodotta in lavorazione pari alla qta sulla riga documento const real qta = o.mask().get(S_QTA); o.mask().set(S_QTAPROD_LAV, qta); } break; case S_DATAPROD_COL_1: if (e == fe_modify) { const real qta = o.mask().get(S_QTA); o.mask().set(S_QTAPROD_COL_1, qta); } break; //bottoni case DLG_SELECT: //carica i record nello sheet in base al filtro di testata if (e == fe_button) { if (check_fields()) { disable(-1); enable(-2); fill_sheet(); } } break; case DLG_CANCEL: if (e == fe_button && jolly == 0) { disable(-2); enable(-1); sfield(F_RIGHE).destroy(); return false; } break; case DLG_SAVEREC: if (e == fe_button) { save_sheet(); fill_sheet(); } break; case DLG_USER: if (e == fe_button) { TSheet_field& sf_righe = sfield(F_RIGHE); TMask& mask_riga = sf_righe.sheet_row_mask(jolly); TRectype doc(LF_DOC); doc.put(DOC_PROVV, 'D'); doc.put(DOC_ANNO, mask_riga.get_int(S_ANNO)); doc.put(DOC_CODNUM, mask_riga.get(S_CODNUM)); doc.put(DOC_NDOC, mask_riga.get_long(S_NDOC)); doc.edit(); } break; default: break; } return true; } //cerca il codiva const TString4 TEdit_rdocs_mask::find_codiva(const TString& codart) { const long codcf = get_long(F_CODCF); TToken_string key_cfven; key_cfven.add("C"); key_cfven.add(codcf); TString4 codiva = cache().get(LF_CFVEN, key_cfven, CFV_ASSFIS); if (codiva.empty()) codiva = cache().get(LF_ANAMAG, codart, ANAMAG_CODIVA); return codiva; } //cerca la um standard del codart const TString4 TEdit_rdocs_mask::find_um(const TString& codart) const { TToken_string key_umart; key_umart.add(codart); key_umart.add(1); const TRectype& rec_umart = cache().get(LF_UMART, key_umart); const TString4 um = rec_umart.get(UMART_UM); return um; } //cerca prezzo in: contratto->listino->anamag real TEdit_rdocs_mask::find_prezzo_articolo(const TString& codart) const { const long codcf = get_long(F_CODCF); const TDate data_new_doc = get_date(F_DATADOC); real prezzo = ZERO; //0) anagrafica articolo (umart): mal che vada proporrà questa; va vergognosamente messa all'inizio e non alla fine.. //..perchè serve unità di misura un pò dappertutto TToken_string key_umart; key_umart.add(codart); key_umart.add(1); const TRectype& rec_umart = cache().get(LF_UMART, key_umart); const TString4 um = rec_umart.get(UMART_UM); const real umart_prezzo = rec_umart.get_real(UMART_PREZZO); //1) contratto //CONTRATTI: tipo=C|catven=|tipocf=C|codcf=codcf|cod=codcontr|tiporiga=A|codriga=codart|um=um TString query_contr; query_contr << "USE CONDV"; query_contr << "\nFROM TIPO=C TIPOCF=C CODCF=#CODCF"; query_contr << "\nTO TIPO=C TIPOCF=C CODCF=#CODCF"; TISAM_recordset recset_contr(query_contr); recset_contr.set_var("#CODCF", codcf); const long recset_contr_items = recset_contr.items(); //deve cercare un contratto in essere per la data del documento (in teoria ce ne dovrebbe essere 1 solo, oppure nessuno) for (bool ok = recset_contr.move_first(); ok; ok = recset_contr.move_next()) { const TDate dataini_c = recset_contr.get(CONDV_VALIN).as_date(); TDate datafin_c = recset_contr.get(CONDV_VALFIN).as_date(); if (!datafin_c.ok()) datafin_c = data_new_doc; if (dataini_c <= data_new_doc && datafin_c >= data_new_doc) { TString4 codcontr = recset_contr.get(CONDV_COD).as_string(); //per um è necessario se il contratto scelto ha la gestione delle um accesa (tanto per complicarsi la vita) const bool gestum_contr = recset_contr.get(CONDV_GESTUM).as_string() == "X"; TToken_string key_contr; key_contr.add("C"); key_contr.add(""); key_contr.add("C"); key_contr.add(codcf); key_contr.add("A"); key_contr.add(codart); if (gestum_contr) key_contr.add(um); const TRectype& rec_contratto = cache().get(LF_RCONDV, key_contr); const real contratto_prezzo = rec_contratto.get_real(RCONDV_PREZZO); if (!contratto_prezzo.is_zero()) { prezzo = contratto_prezzo; break; } } //if (dataini_c <= data_new_doc... } //for (bool ok = recset_contr.move_first()... //se non ha trovato il prezzo sul contratto -> passa ai listini //2) listino //LISTINI: tipo=L|catven=catven|tipocf=|codcf=|cod=codlis|tiporiga=A|codriga=codart|um=um if (prezzo.is_zero()) { //usa una funzione automaggica dei clifor che raccatta il listino valido per il cliente in data del documento TCli_for clifor('C', codcf); const TString& codlist = clifor.find_listino_al(data_new_doc); //se trova un listino valido raccatta il prezzo dalla riga if (codlist.full()) { TToken_string key_list; key_list.add("L"); //la catven se c'è è del cliente TToken_string key_cfven; key_cfven.add("C"); key_cfven.add(codcf); const TString& catven = cache().get(LF_CFVEN, key_cfven, CFV_CATVEN); key_list.add(catven); key_list.add(""); key_list.add(""); key_list.add(codlist); const bool gestum_list = cache().get(LF_CONDV, key_list, CONDV_GESTUM) == "X"; key_list.add("A"); key_list.add(codart); if (gestum_list) key_list.add(um); const TRectype& rec_listino = cache().get(LF_RCONDV, key_list); const real listino_prezzo = rec_listino.get_real(RCONDV_PREZZO); if (!listino_prezzo.is_zero()) prezzo = listino_prezzo; } } //if (prezzo.is_zero())... //3) umart if (prezzo.is_zero()) prezzo = umart_prezzo; //mal che vada sarà il prezzo di umart return prezzo; } //funzione di ordinamento dello sheet in base al codart static int sort_by_codart(TSheet_field& s, int r1, int r2) { const int pos = s.cid2index(S_CODART); const char* a1 = s.cell(r1, pos); const char* a2 = s.cell(r2, pos); return strcmp(a1, a2); } //riempie lo sheet in base ai parametri di testata void TEdit_rdocs_mask::fill_sheet() { const bool includi_evasi = get_bool(F_INCL_EVASI); //recordset con tutti i documenti non evasi nell'anno per il cliente selezionato TString query; query << "USE DOC KEY 2"; query << "\nSELECT (CODNUM=#CODNUM)"; //se vengono incluse le BEM evase -> ci vuole un anno da cui partire per non passare.. //..il tempo a scandire documenti dello scorso millennio! if (includi_evasi) query << "&&(ANNO>=#DAANNO)"; else query << "&&(DOCEVASO!=\"X\")"; query << "\nFROM TIPOCF=C CODCF=#CODCF PROVV=D"; query << "\nTO TIPOCF=C CODCF=#CODCF PROVV=D"; TISAM_recordset recset(query); recset.set_var("#CODCF", get_long(F_CODCF)); recset.set_var("#CODNUM", get(F_CODNUM)); if (includi_evasi) recset.set_var("#DAANNO", get_long(F_DA_ANNO)); const TString& lav = get(F_LAV); const TString& col = get(F_COLORE); const TString& codart = get(F_CODART); const long items = recset.items(); const TRectype& rec = recset.cursor()->curr(); TSheet_field& sf_righe = sfield(F_RIGHE); sf_righe.destroy(); TProgind pi(items, TR("Caricamento documenti in corso..."), true, true); int k = 0; for (bool ok = recset.move_first(); ok; ok = recset.move_next()) { if (!pi.addstatus(1)) break; //per ogni documento prende le sole righe non evase e le carica sullo sheet TDocumento doc(rec); FOR_EACH_PHYSICAL_RDOC(doc, r, rdoc) { //di default pensa di scartare la riga bool rdoc_da_considerare = false; //solo le righe BEM con una qta iniziale > 0 contano qualcosa! const real qta = rdoc->get_real(RDOC_QTA); if (qta > ZERO) { //guy mi perdoni! const bool riga_bem_evasa = rdoc->is_evasa(); const bool riga_bem_evadibile = rdoc->is_evadibile(); if (includi_evasi) rdoc_da_considerare = riga_bem_evadibile; else rdoc_da_considerare = !riga_bem_evasa && riga_bem_evadibile; //se la riga ha passato i primi controlli... if (rdoc_da_considerare) { if (lav.full() && rdoc->get(RDOC_CODCMS) != lav) continue; if (col.full() && rdoc->get(RDOC_FASCMS) != col) continue; if (codart.full() && rdoc->get(RDOC_CODART) != codart) continue; //se sono richieste anche le righe evase, vuole solo quelle evase le cui bolle di consegna appartengono.. //..all'intervallo di date selezionato sulla maschera (contorto ma vero...) if (includi_evasi && riga_bem_evasa) { //date limite per documento di consegna const TDate da_data = get_date(F_DADATA_EV); const TDate a_data = get_date(F_ADATA_EV); //campi riga BEM corrente in esame const long daanno = rdoc->get_long(RDOC_ANNO); const TString& dacodnum = rdoc->get(RDOC_CODNUM); const long dandoc = rdoc->get_long(RDOC_NDOC); const long daidriga = rdoc->get_long(RDOC_IDRIGA); TString rquery; rquery << "USE RDOC KEY 4"; rquery << "\nFROM DAPROVV=D DAANNO=#DAANNO DACODNUM=#DACODNUM DANDOC=#DANDOC DAIDRIGA=#DAIDRIGA"; rquery << "\nTO DAPROVV=D DAANNO=#DAANNO DACODNUM=#DACODNUM DANDOC=#DANDOC DAIDRIGA=#DAIDRIGA"; TISAM_recordset righe_recset(rquery); righe_recset.set_var("#DAANNO", daanno); righe_recset.set_var("#DACODNUM", dacodnum); righe_recset.set_var("#DANDOC", dandoc); righe_recset.set_var("#DAIDRIGA", daidriga); //ricava il recordset delle righe di bolla di consegna che hanno evaso la riga BEM in esame const int ritems = righe_recset.items(); for (bool ok = righe_recset.move_first(); ok; ok = righe_recset.move_next()) { TToken_string doc_babbo_key; doc_babbo_key.add(righe_recset.get(RDOC_PROVV).as_string()); doc_babbo_key.add(righe_recset.get(RDOC_ANNO).as_int()); doc_babbo_key.add(righe_recset.get(RDOC_CODNUM).as_string()); doc_babbo_key.add(righe_recset.get(RDOC_NDOC).as_int()); const TRectype& doc_babbo = cache().get(LF_DOC, doc_babbo_key); const TDate datadoc_babbo = doc_babbo.get_date(DOC_DATADOC); if (datadoc_babbo < da_data || datadoc_babbo > a_data) rdoc_da_considerare = false; } } //if (includi_evasi && riga_bem_evasa).. if (rdoc_da_considerare) sf_righe.autoload_line(++k, *rdoc); //aggiunge una riga nuova riempiendola con tutti i campi che hanno FIELD nella maschera } //if (rdoc_da_considerare)... } //if (qta > ZERO)... } //FOR_EACH_PHYSICAL_RDOC(doc, r, rdoc)... } //for (bool ok... //richiesta del cazzo della euroforesi: ordinare le righe per codart; si sono poi resi conto loro stessi che era.. //..una richiesta del cazzo e l'hanno abbandonata //sf_righe.sort(sort_by_codart); sf_righe.force_update(); } //salva losheet con eventuali modifiche e nuove righe void TEdit_rdocs_mask::save_sheet() { const TString& codnum = get(F_CODNUM); const TString& tipodoc = get(F_TIPODOC); const TDate datadoc = get_date(F_DATADOC); const long codcf = get_long(F_CODCF); TDoc_cache doc_cache(codnum, tipodoc, datadoc, codcf); TSheet_field& sf_righe = sfield(F_RIGHE); FOR_EACH_SHEET_ROW(sf_righe, r, row) { TToken_string key; key.add(row->get(_pos_provv)); key.add(row->get(_pos_anno)); key.add(row->get(_pos_num)); key.add(row->get(_pos_ndoc)); int nriga = row->get_int(_pos_nrig); TDocumento& curr_doc = doc_cache.doc(key); if (nriga <= 0) { const TRiga_documento& rdoc = curr_doc.new_row("01"); //solo righe merce sono aggiungibili nriga = rdoc.get_int(RDOC_NRIGA); row->add(curr_doc.get_long(DOC_NDOC), _pos_ndoc); row->add(nriga, _pos_nrig); } sf_righe.autosave_line(r + 1, curr_doc[nriga]); //salva maggicamente la riga nuova } doc_cache.destroy(); } /////////////////////////////////////// // TSkeleton_application /////////////////////////////////////// class TEdit_rdocs : public TSkeleton_application { protected: virtual bool check_autorization() const { return false; } virtual const char* extra_modules() const { return "ve"; } virtual void main_loop(); virtual bool create(); }; void TEdit_rdocs::main_loop() { TEdit_rdocs_mask mask; mask.run(); } bool TEdit_rdocs::create() { open_files(LF_DOC, LF_RIGHEDOC, 0); return TSkeleton_application::create(); } int ps1002100 (int argc, char* argv[]) { TEdit_rdocs main_app; main_app.run(argc, argv, TR("Gestione righe per cliente")); return true; }