#include #include #include #include "lvlib.h" #include "lv2500a.h" #include "clifo.h" #include "cfven.h" #include "lvcondv.h" #include "lvrcondv.h" #include "rdoc.h" #include "../db/dblib.h" #include "../mg/mglib.h" #include "../ve/ve6200.h" #include "../ve/ve6200a.h" class TFatturazione_lavanderie; //////////////////////////////////////// //// classe TFatturazione_msk //// //////////////////////////////////////// class TFatturazione_msk: public TAutomask { protected: virtual bool on_field_event(TOperable_field& o,TField_event e,long jolly){return true;} public: TFatturazione_msk(); }; //////////////////////////////////////// //// TFatturazione_lavanderie app //// //////////////////////////////////////// //Classe TFatturazione_lavanderie_app class TFatturazione_lav_app: public TSkeleton_application { TFatturazione_msk* _msk; protected: virtual void main_loop(); void genera_bolle_nolo(TAssoc_array& cliela, TFatturazione_lavanderie& elab, int& numdocgen); bool controlli_preliminari(); }; TFatturazione_lav_app & app() { return (TFatturazione_lav_app &) main_app();} //////////////////////////////////////// //// TCalc_02_data //// //////////////////////////////////////// //Classe TCalc_02_data class TCalc_02_data : public TObject { TString _key; TGeneric_distrib _distr; TGeneric_distrib _distr_rit; TAssoc_array _bol_rows; virtual TObject* dup() const; void copy(const TCalc_02_data & d); public: TCalc_02_data & operator = (const TCalc_02_data & d) { copy(d); return *this; } const TString & key() const { return _key; } TGeneric_distrib & distr() { return _distr; } TGeneric_distrib & distr_rit() { return _distr_rit; } TAssoc_array & bol_rows() { return _bol_rows; } TCalc_02_data(const char * key) : _key(key) {} TCalc_02_data(const TCalc_02_data & d) {copy(d);} }; void TCalc_02_data::copy(const TCalc_02_data & d) { _key = d._key; _distr = d._distr; _bol_rows = d._bol_rows; } TObject* TCalc_02_data::dup() const { TCalc_02_data* o = new TCalc_02_data(*this); return o; } //////////////////////////////////////// //// TFatturazione_lavanderie //// //////////////////////////////////////// //Classe TFatturazione_lavanderie class TFatturazione_lavanderie:public TFatturazione_bolle { TDate _data_elab; TToken_string _campi_raggruppamento; TAssoc_array _output_rows_02; bool _prova; protected: virtual void add_rows(TRiga_documento & rout, TRiga_documento & rin); virtual void create_row(TDocumento& doc_out, const TRiga_documento & rin); virtual void pre_process_input(TLista_documenti& doc_in); virtual void post_process_input(TLista_documenti& doc_in) {} virtual void post_process(TLista_documenti& doc_out, TLista_documenti& doc_in); virtual bool da_raggruppare(const TRiga_documento & rin); virtual bool doc_raggruppabili(const TDocumento& doc_in, const TDocumento& doc_out, TToken_string& campi) const ; virtual bool doc_raggruppabile(const TDocumento & doc) const { return true; } virtual void campi_raggruppamento_righe(TToken_string& campi_riga) const; virtual bool gestione_riferimenti() const { return true; } virtual bool riferimenti_in_testa() const { return true; } virtual TRiga_documento& find_or_create_row(TDocumento& doc_out, const TRiga_documento & rin,const char lavtype); void aggiorna_fattura(TDocumento & doc, int codcont); bool fatt_02() const { return !_prova &&lv_is_02_active(); } public: virtual bool elabora(TLista_documenti& doc_in, TLista_documenti& doc_out, const TDate& data_elab, bool interattivo = false); TFatturazione_lavanderie(const char* cod, bool prova = false); ~TFatturazione_lavanderie() {} }; TFatturazione_lavanderie::TFatturazione_lavanderie(const char* cod, bool prova) : TFatturazione_bolle(cod), _prova(prova) { } //DOC_RAGGRUPPABILI: metodo che restituisce true se i documenti sono raggruppabili sulla base dei campi //contenuti nella stringa campi bool TFatturazione_lavanderie::doc_raggruppabili(const TDocumento& doc_in, const TDocumento& doc_out, TToken_string& campi) const { if (doc_in.ha_riga_esenzione() != doc_out.ha_riga_esenzione()) return false; bool ok = true; TString campo; //scorro tutti i campi contenuti nella TToken_string //se sto controllando i campi CODABI e CODCAB, allora il controllo //deve essere numerico e non tra stringhe for (const char* c = campi.get(0); c && ok; c = campi.get()) { if (strncmp(c, "CODABI", 6) == 0 || strncmp(c, "CODCAB", 6) == 0) { long cod = doc_in.get_long(c); ok &= (cod == doc_out.get_long(c)); } else { campo = doc_in.get(c); ok &= campo == doc_out.get(c); } } return ok; } //DA_RAGGRUPPARE: per adesso segnaposto: resituisce sempre false bool TFatturazione_lavanderie::da_raggruppare(const TRiga_documento & rin) { /* const long clifo = rin.doc().get_long(DOC_CODCF); const int indsped = rin.doc().get_int(DOC_CODINDSP); TLaundry_contract contr(clifo, indsped, _data_elab); const TString80 codart = rin.get(RDOC_CODART); const TRectype & rcont = contr.row(codart); const int tipoforf = rcont.get_int(LVRCONDV_TIPOFORF); // return tipoforf > 1; // Test originale if (tipoforf > 1) return true; // Da qui in poi e' sottinteso tipoforf == 1 if (ini_get_int(CONFIG_DITTA, "lv", "TipoPr") == 1) return false; // Test GUY const TString8 causale = rin.get(RDOC_CODAGG1); const TCausale_lavand cau = cache().get("&CAU", causale); if (cau.get_bool("B1")) { const TCausale_magazzino& con = cached_causale_magazzino(cau.get("S2")); if (con.sgn(s_dottm)) // Causale di incremento sotazione temporanea return true; } if (cau.get_bool("B4")) // Causale di rotto return true; */ return false; } void TFatturazione_lavanderie::pre_process_input(TLista_documenti& doc_in) { for (int id = 0; id < doc_in.items(); id++) { TDocumento& doc = doc_in[id]; const int rows = doc.physical_rows(); for (int i = 1; i <= rows; i++) { TRiga_documento & row = doc[i]; TString str_real = row.get(RDOC_QTAREALE); if (str_real.full()) { real qta_real(decode(str_real)); row.put(RDOC_QTA, qta_real); row.zero(RDOC_QTAREALE); } str_real = row.get(RDOC_QTARITREALE); if (str_real.full()) { real qta_real(decode(str_real)); row.put(RDOC_QTAGG1, qta_real); row.zero(RDOC_QTARITREALE); } } } } void TFatturazione_lavanderie::aggiorna_fattura(TDocumento & doc, int codcont) { const int nrows = doc.physical_rows(); const long codcf = doc.get_long(DOC_CODCF); TString str; str << "USE LVRCONDV\n" << "FROM CODCF=" << codcf << " CODCONT=" << codcont << "\n" << "TO CODCF=" << codcf << " CODCONT=" << codcont; TISAM_recordset rcont(str); for(bool ok = rcont.move_first(); ok; ok = rcont.move_next()) { TRectype& riga = rcont.cursor()->curr(); int forfait = riga.get_int(LVRCONDV_TIPOFORF); const TString & codart = riga.get(LVRCONDV_CODART); bool to_add = forfait != 0; for (int i = 1; to_add && i <= nrows ; i++) { TRiga_documento& rout = doc[i]; const TString80 codart_contr = rout.get(RDOC_CODART); if (codart == codart_contr) to_add = false; } if (to_add) { TRiga_documento& rdoc = doc.new_row("21"); rdoc.put(RDOC_CODART, codart); rdoc.put(RDOC_CODARTMAG, riga.get(LVRCONDV_CODART)); rdoc.put(RDOC_DESCR, cached_article(codart).get(ANAMAG_DESCR)); rdoc.put(RDOC_CHECKED, true); rdoc.put(RDOC_QTA, 1); rdoc.put(RDOC_QTAGG1, 1); rdoc.put(RDOC_UMQTA, riga.get(LVRCONDV_UM)); TToken_string key; key.add('C'); key.add(codcf); TString8 codiva = cache().get(LF_CFVEN, key, CFV_ASSFIS); if (codiva.blank()) codiva = cache().get(LF_ANAMAG, riga.get(LVRCONDV_CODART), ANAMAG_CODIVA); rdoc.put(RDOC_CODIVA, codiva); rdoc.put(RDOC_CODAGG1, ini_get_string(CONFIG_DITTA, "lv", "CAUSLAV")); } } } //POST_PROCESS: metodo che elabora i documenti di output dopo che si sono svolte //le operazioni di base sugli stessi, in modo da raggruppare le righe raggruppabili //e/o eliminare quelle inutili e/o aggiungere quelle per il ciclaggio su 2 linee void TFatturazione_lavanderie::post_process(TLista_documenti& doc_out, TLista_documenti& doc_in) { //scorro tutti i documenti di output generati precedentemente for (int id = 0; id < doc_out.items(); id++) { //instanzio il documento e recupero le variabili di interesse per recuperare //il contratto del cliente in questione TDocumento& doc = doc_out[id]; const long clifo = doc.get_long(DOC_CODCF); if (clifo >550l && clifo <580l) int i = 1; const int indsped = doc.get_int(DOC_CODINDSP); TLaundry_contract contr(clifo,indsped,_data_elab); //flag per il calcolo sul valore convenzionale e sul fisso per dotazione iniziale bool valconvcli = false; bool fixdotin = false; bool elcons = contr.get_bool(LVCONDV_ELCONS); bool rifbol = contr.get_bool(LVCONDV_RIFBOL); bool riftest = ini_get_bool(CONFIG_DITTA, "lv", "RifTest"); if (doc.physical_rows() > 0 && doc[1].is_descrizione()) { if (elcons) { TRiga_documento& rout = doc[1]; rout.put(RDOC_DESCR, "COME DA ELENCO CONSEGNE"); rout.put(RDOC_DESCLUNGA, false); rout.put(RDOC_DESCEST, ""); } else if (!rifbol) doc.destroy_row(1, true); } //se devo mettere i riferimenti della bolla in testata, prendo la descrizione della prima riga //e la metto sulla testata del documento, poi cancello la prima riga del documento if (rifbol && riftest) { TRiga_documento& rout = doc[1]; TString descr = rout.get(RDOC_DESCR); descr << ' ' << rout.get(RDOC_DESCEST); descr.ltrim(21); //sostituisco la stringa " - n. " e la sostituisco con la stringa " - " su tutta la stringa descrizione int pos = descr.find(" - n. "); while (pos > 0) { descr.overwrite(" - ", pos, 7); pos = descr.find(" - n. ", pos + 1); } descr.strip_double_spaces(); doc.put(DOC_NOTE, descr); doc.destroy_row(1, true); } const bool ragart = contr.get_bool(LVCONDV_RAGART); // leggo il flag di testata raggruppa su unico articolo const int tipocan = contr.get_int(LVCONDV_TIPOCAN); // leggo il tipo canone const real redditivita = contr.get_real(LVCONDV_REDDI); if (ragart) { real totmerc; const int rows = doc.physical_rows(); for (int i=1; i <= rows; i++) //calcolo totale merce { const TRiga_documento& riga = doc[i]; if (riga.is_merce()) totmerc += riga.importo(true,false); } const int rigamerce = doc[1].is_descrizione() ? 2 : 1; for (int i=rigamerce; i <= rows; i++) doc.destroy_row(i); TRiga_documento& riga = doc.new_row("01"); const TString80 codartcfg = ini_get_string(CONFIG_DITTA, "lv", "Codartcafix"); const TString80 descart = cache().get(LF_ANAMAG, codartcfg, ANAMAG_DESCR); // istanzio una token string e poi una cache per estrarre l'unità di misura dell articolo in configurazione da UMART TToken_string key; key.add(codartcfg); key.add(1); const TRectype& umart = cache().get(LF_UMART,key); const TString4 umcodart = umart.get(UMART_UM); /* estraggo il codice IVA istanziando in primis una cache su CFVEN per analizzare il codice esenzione iva del cliente in questione. Se è >0 imposto il codiva a tale valore, altrimenti se è uguale a 0 istanzio un altra cache su ANAMAG e imposto il codiva uguale al codice iva dell articolo in questione */ key = doc.get(DOC_TIPOCF); key.add(clifo); const TRectype& cfven = cache().get(LF_CFVEN,key); TString8 codiva = cfven.get(CFV_ASSFIS); if (codiva.blank()) { const TRectype& anamag = cache().get(LF_ANAMAG,codartcfg); codiva = anamag.get(ANAMAG_CODIVA); } riga.put(RDOC_QTA,UNO); riga.put(RDOC_UMQTA,umcodart); riga.put(RDOC_PREZZO,totmerc); riga.put(RDOC_CODART,codartcfg); riga.put(RDOC_DESCR,descart); riga.put(RDOC_CODIVA,codiva); break; } else // se non è selezionato raggrupa su unico articolo controllo il tipo canone se è impostato a importo fisso if (tipocan == 1) //se è selezionato tipo canone = importo fisso { // estraggo il canone fisso e l'articolo in configurazione const real canfis=contr.get_real(LVCONDV_IMPFIX); const TString80 codartcfg = ini_get_string(CONFIG_DITTA, "lv", "Codartfix"); const TString80 descart = cache().get(LF_ANAMAG, codartcfg, ANAMAG_DESCR); // istanzio una token string e poi una cache per estrarre l'unità di misura dell articolo in configurazione da UMART TToken_string key; key.add(codartcfg); key.add(1); const TRectype& umart = cache().get(LF_UMART,key); const TString4 umcodart = umart.get(UMART_UM); /* estraggo il codice IVA istanziando in primis una cache su CFVEN per analizzare il codice esenzione iva del cliente in questione. Se è >0 imposto il codiva a tale valore, altrimenti se è uguale a 0 istanzio un altra cache su ANAMAG e imposto il codiva uguale al codice iva dell articolo in questione */ key = doc.get(DOC_TIPOCF); key.add(clifo); const TRectype& cfven = cache().get(LF_CFVEN,key); TString8 codiva = cfven.get(CFV_ASSFIS); if (codiva.blank()) { const TRectype& anamag = cache().get(LF_ANAMAG,codartcfg); codiva = anamag.get(ANAMAG_CODIVA); } const int rigamerce = doc[1].is_descrizione()?2:1; TRiga_documento& fixrow=doc.insert_row(rigamerce, "01"); // creo una nuova riga in cima al documento e imposto i valori appena estratti fixrow.put(RDOC_QTA,UNO); fixrow.put(RDOC_UMQTA,umcodart); fixrow.put(RDOC_PREZZO,canfis); fixrow.put(RDOC_CODART,codartcfg); fixrow.put(RDOC_DESCR,descart); fixrow.put(RDOC_CODIVA,codiva); int tipocanfix = contr.get_int(LVCONDV_CANFIX); const int rows = doc.physical_rows(); switch (tipocanfix) { case 0: for (int k = rigamerce+1; k <= rows; k++) doc.destroy_row(k); break; case 1: for (int k = rigamerce+1; k <= rows; k++) { TRiga_documento& rout = doc[k]; rout.zero(RDOC_PREZZO); } break; case 2: for (int k = rigamerce+1; k <= rows; k++) { TRiga_documento& rout = doc[k]; rout.zero(RDOC_PREZZO); rout.zero(RDOC_QTA); } break; default: break; } break; } else // se il tipo canone è impostato a nessuno o % sul valore convenzionale per cliente vado in ambedue i casi ad eseguire il ciclo che analizza i tipi forfait { if (!contr.get_bool(LVCONDV_FORFNOCONS)) aggiorna_fattura(doc, contr.get_int(LVCONDV_CODCONT)); //per ogni documento, scorro tutte le sue righe for (int i = 1; i <= doc.physical_rows() ; i++) { TRiga_documento& rout = doc[i]; const TString80 codart = rout.get(RDOC_CODART); //leggo dalla riga del contratto di questo articolo il tipo dotazione e //la scelta per la % sul val.conv su articolo o cliente const TRectype& rcont = contr.row(codart); const TString4 tipodot = rcont.get(LVRCONDV_NOLCIC); const TString4 artcli = rcont.get(LVRCONDV_VCARTCLI); real dot; const int annoes = _data_elab.year(); //instanzio il TArticolo_lavanderia TArticolo_lavanderie artlav(codart, 'C', clifo, indsped); //cerco la giacenza per articolo dell'articolo esaminato const int index = artlav.find_clifomag(annoes); //se lo trovo e se il tipo dotazione è iniziale 'I', allora leggo la dotazione iniziale //dalle giacenze articolo per cliente, altrimenti leggo la dotazione odierna if (index >= 0) { if (tipodot == "I") dot = artlav.clifomag(annoes)[index].get_real("DOTIN"); else dot = artlav.clifomag(annoes)[index].get_real("DOTOD"); } //leggo dalla riga contratto il tipo forfait const int tipoforf = rcont.get_int(LVRCONDV_TIPOFORF); switch (tipoforf) { case 0: //forfait = NESSUNO { //gestione fatturazione a kg const bool fatkg = rcont.get_bool(LVRCONDV_FATTKG); //se devo fatturare a kg if(fatkg) { const TString4 umkg = ini_get_string(CONFIG_DITTA, "lv", "UmKg"); const TString4 umri = rout.get(RDOC_UMQTA); //se la riga è già espressa in kg non devo fare niente, altrimenti: if(umri != umkg) { //leggo e controllo l'unità di misura del peso const TString4 ump = artlav.get(ANAMAG_UMP); if(ump.empty()) { warning_box(TR("Manca l'unità di misura del peso")); break; } //leggo e controllo il peso dell'articolo const real peso = artlav.get_real(ANAMAG_PESO); if(peso == ZERO) { warning_box(TR("Manca il peso")); break; } //leggo l'unità di misura dell'articolo e la quantità convertita all'unità di misura dell'articolo const TString4 umart = artlav.um()[1].get(UMART_UM); const real qta = artlav.convert_to_um(rout.get_real(RDOC_QTA), umart, umri, false); //se l'articolo non è espresso in kg, allora: if(umart != umkg) { //preparo una cache sulla tabella delle unità di misura const TRectype& unita = cache().get("%UMS", umart); //leggo e controllo se esiste l'unità di misura di riferimento const TString4 umrif = unita.get("S7"); if(umrif.empty()) { warning_box(TR("Manca l'unità di misura di riferimento")); break; } if(umrif != umkg) { warning_box(TR("L'unità di misura di riferimento non è quella dei Kg")); break; } //leggo e controllo il fattore di conversione const real fatconv = unita.get_real("R10"); if(fatconv == ZERO) { warning_box(TR("Manca il fattore di conversione")); break; } //se tutti i controlli sono andati a buon fine, converto la quantità e la scrivo sulla riga documento const real qtaconv = qta * fatconv * peso; rout.put(RDOC_QTA, qtaconv); } } } } break; case 1: //forfait = A VALORE FISSO { rout.put(RDOC_QTA, UNO); //qta fissa a UNO rout.put(RDOC_PREZZO, rcont.get_real(LVRCONDV_IMPFISART)); //prezzo letto dalla riga contratto // gestione in base codice per valore fisso ??? tolta la scelta dell'articolo o del cliente } break; case 2: //forfait = NOLO { //aggiungo una riga tipo merce, che contiene tutti i dati della riga del documento //di partenza, poi costruisco la descrizione in base alla periodicità di fatturazione, //metto la qta uguale alla dotazione che ho appena letto //e prendo il prezzo nolo dalla riga contratto TRiga_documento& nolorow = doc.insert_row(++i, "01"); doc.copy_data(nolorow, rout); TString80 descr("Nolo"); const int contrper = contr.get_int(LVCONDV_PERFAT); switch (contrper) { case 0: descr << " per il giorno"; break; case 1: descr << " per la settimana"; break; case 2: descr << " per la quindicina"; break; case 3: descr << " per il mese"; break; default: break; } nolorow.put(RDOC_DESCR,descr); nolorow.put(RDOC_QTA, dot); nolorow.put(RDOC_PREZZO, rcont.get_real(LVRCONDV_PREZNOL)); } break; case 3: //forfait = CICLAGGIO { //leggo la quantità consegnata e calcolo consumo e ciclaggio secondo le formule //CONSUMO = QTA * PREZZO(dalla riga documento) //CLICLAGGIO = DOT * PREZZO(dalla riga contratto) * MINIMO CICLAGGIO const real qta = rout.get_real(RDOC_QTA); const real consumo = qta * rout.get_real(RDOC_PREZZO); const real ciclaggio = dot * rcont.get_real(LVRCONDV_PREZZO) * rcont.get_real(LVRCONDV_MINCIC); //se il consumo è minore del ciclaggio, allora if (consumo < ciclaggio) { //leggo il flag del tipo ciclaggio const bool cicl2rig = contr.get_bool(LVCONDV_CICLAGGIO); //calcolo il valore cicl secondo la formula CICL = MINIMO CICLAGGIO * DOT const real cicl = rcont.get_real(LVRCONDV_MINCIC) * dot; //se il ciclaggio è su due linee, allora aggiungo una riga merce, per pareggiare il minimo ciclaggio //che ha come quantità la differenza tra la quantità di minimo cilcaggio //e la quantità effettivamente consegnata e come prezzo il prezzo preso dalla riga contratto; //altimenti correggo quantità e prezzo direttamente sulla riga documento che sto analizzando if (cicl2rig) { TRiga_documento& congrow = doc.insert_row(++i, "01"); doc.copy_data(congrow,rout); congrow.put(RDOC_DESCR,"Pareggio minimo ciclaggio"); congrow.put(RDOC_QTA, cicl - qta); congrow.put(RDOC_PREZZO, rcont.get_real(LVRCONDV_PREZZO)); } else { rout.put(RDOC_QTA, cicl); rout.put(RDOC_PREZZO, rcont.get_real(LVRCONDV_PREZZO)); } } } break; case 4: //forfait = % SUL VALORE CONVENZIONALE { //leggo dalla riga contratto la % sul val.conv su articolo o cliente const char tipovalconv = rcont.get_char(LVRCONDV_VCARTCLI); //se la percentuale sul valore convenzionale è sull'articolo, allora: if (tipovalconv == 'A') { //leggo la quantità consegnata e calcolo consumo e importo convenzionale secondo le formule //CONSUMO = QTA * PREZZO(dalla riga documento) //IMPCONV = DOT * PREZZO(dalla riga contratto) * PERCENTUALE DI FORFAIT CLIENTE const real qta = rout.get_real(RDOC_QTA); const real consumo = qta * rout.get_real(RDOC_PREZZO); const real impconv = dot * rcont.get_real(LVRCONDV_VALCONV) * rcont.get_real(LVRCONDV_FORFPERCL) / 100; //se il consumo è minore del ciclaggio, allora if (consumo < impconv) { const bool cicl2rig = contr.get_bool(LVCONDV_CICLAGGIO); //se il ciclaggio è su due linee, allora aggiungo una riga merce, che contiene //il conguaglio al valore convenzionale, che ha come quantità la costante UNO //e come prezzo la differenza tra l'importo convenzionale e il consumo; //altimenti correggo quantità e prezzo direttamente sulla riga documento che sto analizzando if (cicl2rig) { TRiga_documento& congrow = doc.insert_row(++i, "01"); doc.copy_data(congrow, rout); congrow.put(RDOC_DESCR, "Conguaglio valore convenzionale"); congrow.put(RDOC_QTA, UNO); congrow.put(RDOC_PREZZO, impconv - consumo); } else { rout.put(RDOC_QTA, UNO); rout.put(RDOC_PREZZO, impconv); } } } else { //se la percentuale sul valore convenzionale è sul cliente, allora se il flag valconvcli è false if (!valconvcli) { //pongo valconvcli a true in modo da non tornare più in questo if valconvcli = true; //instanzio i due real che andranno a contenere l'importo covenzionale totale e il consumo totale real impconvtot; real consumotot; //scorro tutte le righe documento dalla riga in esame fino alla fine for (int j = i; j < doc.physical_rows(); j++) { //instanzio la riga documento e sommo ai totali gli importi solo se //la percentuale sul valore convenzionale è sul cliente TRiga_documento& riga = doc[j]; const TString80 codart = riga.get(RDOC_CODART); const TRectype & rcont = contr.row(codart); const char tipvalconvcli = rcont.get_char(LVRCONDV_VCARTCLI); if (tipvalconvcli == 'C') { impconvtot += dot * rcont.get_real(LVRCONDV_VALCONV) * rcont.get_real(LVRCONDV_FORFPERCL); consumotot += riga.get_real(RDOC_QTA) * riga.get_real(RDOC_PREZZO); } } //se il consumo è minore del ciclaggio, allora if (consumotot < impconvtot) { const bool cicl2rig=contr.get_bool(LVCONDV_CICLAGGIO); //se il ciclaggio è su due linee, allora aggiungo una riga merce, che contiene //il conguaglio al valore convenzionale, che ha come quantità la costante UNO //e come prezzo la differenza tra l'importo convenzionale totale e il consumo totale; //altimenti correggo quantità e prezzo direttamente sulla riga documento che sto analizzando //e elimino tutte le righe che vanno a comporre il totale in modo che rimanga una riga sola //per mostrare l'importo del conguaglio al valore convenzionale if (cicl2rig) { TRiga_documento& congrow=doc.insert_row(++i, "01"); doc.copy_data(congrow, rout); congrow.put(RDOC_DESCR, "Conguaglio valore convenzionale"); congrow.put(RDOC_QTA, UNO); congrow.put(RDOC_PREZZO, impconvtot - consumotot); } else { rout.put(RDOC_QTA, UNO); rout.put(RDOC_PREZZO, impconvtot); for (int k = doc.physical_rows(); k > i; k--) { TRiga_documento& delrow = doc[k]; const TString80 codart = delrow.get(RDOC_CODART); const TRectype& rcont = contr.row(codart); const char tipvalconvcli = rcont.get_char(LVRCONDV_VCARTCLI); if (tipvalconvcli == 'C') doc.destroy_row(k, true); } } } } } } break; case 5: //forfait = FISSO SU DOTAZIONE INIZIALE { rout.put(RDOC_PREZZO, rcont.get_real(LVRCONDV_IMPFISART)); rout.put(RDOC_QTA, artlav.clifomag(annoes)[index].get_real("DOTIN")); const TString80 codartorig=rout.get(RDOC_CODART); for (int h = doc.physical_rows(); h > i; h--) { TRiga_documento& delrow = doc[h]; const TString80 codart=delrow.get(RDOC_CODART); if ( codartorig == codart) doc.destroy_row(h, true); } } break; default: break; } } } if (redditivita > ZERO && fatt_02() && !ragart && tipocan != 1) { const real totdoc = doc.totale_doc(); const real provvigione1 = doc.provvigione(); const real provvigione2 = doc.provvigione(false); doc.put(RDOC_TOTREALE, encode(totdoc.string())); doc.put(RDOC_PROVV1REALE, encode(provvigione1.string())); doc.put(RDOC_PROVV2REALE, encode(provvigione2.string())); for(int j = doc.physical_rows(); j > 0; j--) { TRiga_documento& rdoc = doc[j]; const TString80 codart = rdoc.get(RDOC_CODARTMAG); const TRectype& rcont = contr.row(codart); const int tipoforf = rcont.get_int(LVRCONDV_TIPOFORF); long ppconf = cached_article(codart).get_long(ANAMAG_PPCONF); const real real_qta = rdoc.get(RDOC_QTA); if (rcont.get_int(LVRCONDV_CALCCONS) != 1 || ppconf == 0) ppconf = 1; const char lvtype = rdoc.get_char("LVTYPE"); bool row_has_02 = (tipoforf == 0) && (real_qta / ppconf > UNO) && (lvtype == 'C'); // 0 forfait = NESSUN FORFAIT SI // 1 forfait = A VALORE FISSO NO // 2 forfait = NOLO NO // 3 forfait = CICLAGGIO NO // 4 forfait = % SUL VALORE CONVENZIONALE NO // 5 forfait = FISSO SU DOTAZIONE INIZIALE NO if (row_has_02) { const TString key = format("%04d%04d", doc.get_int("FATID"), rdoc.get_int(RDOC_IDRIGA)); real new_qta = real_qta; TCalc_02_data * data = (TCalc_02_data *) _output_rows_02.objptr(key); rdoc.put(RDOC_QTAREALE, encode(real_qta.string())); if (data != NULL) { new_qta /= ppconf; real test = new_qta; test.ceil(); if (test * ppconf != real_qta) { warning_box(FR("L'articolo %s per il cliente %ld ha una quantità %s\nnon coincidente coi pacchi. Controllare le bolle"), (const char *)codart, doc.get_long(DOC_CODCF), real_qta.string()); ppconf = 1; } new_qta *= (CENTO - redditivita) / CENTO; new_qta.round(); data->distr() = new_qta; new_qta *= ppconf; rdoc.put(RDOC_QTA, new_qta); real new_qta_rit = rdoc.get_real("TOTRIT"); new_qta_rit *= (CENTO - redditivita) / CENTO; new_qta_rit.round(); data->distr_rit() = new_qta_rit; TAssoc_array & bol_rows = data->bol_rows(); FOR_EACH_ASSOC_OBJECT(bol_rows, obj, wkey, item) { TToken_string bolkey(wkey); const long ndoc = bolkey.get_long(3); const long id = bolkey.get_long(4); for (int i = 0; i < doc_in.items(); i++) { TDocumento& doc = doc_in[i]; if (doc.get_long(DOC_NDOC) == ndoc) { TRiga_documento * bolrow = (TRiga_documento *) doc.get_row_id(id); if (bolrow != NULL) { const TString8 causale = bolrow->get(RDOC_CODAGG1); const TCausale_lavanderie & cau = cached_causale_lavanderie(causale); if (cau.is_rotto()) break; bool fatturo_ritirato = cau.is_ritiro(); bool fatturo_consegnato = cau.is_consegna(); if (fatturo_ritirato) { const TCausale_magazzino& rit = cau.causale_ritiro(); fatturo_ritirato = rit.sgn(s_consmese) != 0; } if (fatturo_consegnato) { const TCausale_magazzino& con = cau.causale_consegna(); fatturo_consegnato = con.sgn(s_consmese) != 0; } TString str_real = bolrow->get(RDOC_QTA); real qta = real(str_real) / ppconf; qta.round(); if (str_real.full()) bolrow->put(RDOC_QTAREALE, encode(str_real)); str_real = bolrow->get(RDOC_QTAGG1); real qtarit = real(str_real); data->distr_rit().add(qtarit); if (str_real.full()) bolrow->put(RDOC_QTARITREALE, encode(str_real)); if (fatturo_ritirato && !fatturo_consegnato) // ! fatturo il ritirato o fatturo il consegnato { qtarit = real(str_real) / ppconf; qtarit.round(); data->distr().add(qtarit); } else data->distr().add(qta); } else message_box("Riga_bolla smarrita %d - %s - %ld - id = %ld", bolkey.get_int(1), bolkey.get(0), bolkey.get(3), bolkey.get(4)); break; } } } FOR_EACH_ASSOC_OBJECT(bol_rows, obj1, wkey1, item1) { TToken_string bolkey(wkey); const long ndoc = bolkey.get_long(3); const long id = bolkey.get_long(4); for (int i = 0; i < doc_in.items(); i++) { TDocumento& doc = doc_in[i]; if (doc.get_long(DOC_NDOC) == ndoc) { TRiga_documento * bolrow = (TRiga_documento *) doc.get_row_id(id); if (bolrow != NULL) { const TString8 causale = bolrow->get(RDOC_CODAGG1); const TCausale_lavanderie & cau = cached_causale_lavanderie(causale); if (cau.is_rotto()) break; bool fatturo_ritirato = cau.is_ritiro(); bool fatturo_consegnato = cau.is_consegna(); if (fatturo_ritirato) { const TCausale_magazzino& rit = cau.causale_ritiro(); fatturo_ritirato = rit.sgn(s_consmese) != 0; } if (fatturo_consegnato) { const TCausale_magazzino& con = cau.causale_consegna(); fatturo_consegnato = con.sgn(s_consmese) != 0; } const real qta = data->distr().get() * ppconf; const real qtarit = data->distr_rit().get(); bolrow->put(RDOC_QTAGG1, qtarit); if ((!fatturo_ritirato) || (fatturo_consegnato)) // ! fatturo il ritirato o fatturo il consegnato bolrow->put(RDOC_QTA, qta); else int c = 1; // placeholder } else message_box("Riga_bolla smarrita %d - %s - %ld - id = %ld", bolkey.get_int(1), bolkey.get(0), bolkey.get(3), bolkey.get(4)); break; } } } } } } } for(int h = doc.physical_rows(); h > 0; h--) { TRiga_documento& rdoc = doc[h]; if (rdoc.get(RDOC_DESCR).empty()) doc.destroy_row(h, true); } } for (int id = doc_out.items() - 1; id >= 0 ; id--) { TDocumento& doc = doc_out[id]; const int rows = doc.physical_rows(); bool to_delete = true; for (int i = rows; to_delete && i > 0; i--) { const TRiga_documento& riga = doc[i]; if (!riga.is_descrizione()) to_delete = (riga.imponibile() == ZERO && riga.get_real(RDOC_QTA) == ZERO); } if (to_delete) doc_out.destroy(id); } for (int id = doc_out.items() - 1; id >= 0 ; id--) { TDocumento& doc = doc_out[id]; const TString4 tipocf = doc.get(DOC_TIPOCF); const int act_cli = doc.get_long(DOC_CODCF); TToken_string key(tipocf); key.add(act_cli); const TRectype & reccli = cache().get(LF_CLIFO, key); const long new_cli = reccli.get_long(CLI_CODCFFATT); if (new_cli > 0L) { doc.put(DOC_CODCF, new_cli); key = tipocf; key.add(new_cli); const TRectype & new_reccliven = cache().get(LF_CFVEN, key); doc.put(DOC_CODINDSP, new_reccliven.get(CFV_CODINDDOC)); TString descr; TRiga_documento & r = doc.insert_row(1, "05"); r.put(RDOC_DESCR, "Consegne effettuate presso\n"); descr << act_cli << " " << reccli.get(CLI_RAGSOC); r.put(RDOC_DESCLUNGA, "X"); r.put(RDOC_DESCEST, descr); } } } //ADD_ROWS: per adesso un segnaposto void TFatturazione_lavanderie::add_rows(TRiga_documento & rout, TRiga_documento & rin) { /*const TString8 causale = rin.get(RDOC_CODAGG1); const TRectype& cau = cache().get("&CAU", causale); const TCausale_magazzino& rit = cached_causale_magazzino(cau.get("S1")); const TCausale_magazzino& con = cached_causale_magazzino(cau.get("S2")); //movimento o meno la dotazione temporanea/odierna a seconda di cosa prevede la causale const long clifo = rin.doc().get_long(DOC_CODCF); const int indsped = rin.doc().get_int(DOC_CODINDSP); TLaundry_contract contr(clifo, indsped, _data_elab); if (cau.get_bool("B4") && contr.get_int(LVCONDV_ADDCAPROT)) // Guardo se è una causale di rotto e se è abilitato nella testata del contratto la fatturazione dei rotti { const real qta = rit.sgn(s_consmese) * rin.get_real(RDOC_QTA); rout.put(RDOC_PREZZO,contr.get_int(LVCONDV_PREZROT)); rout.add(RDOC_QTA, qta); } else { if (cau.get_bool("B0")) { const real qta = rit.sgn(s_consmese) * rin.get_real(RDOC_QTA); rout.add(RDOC_QTA, qta); } if (cau.get_bool("B1")) { const real qta = con.sgn(s_consmese) * rin.get_real(RDOC_QTA); rout.add(RDOC_QTA, qta); } } */ } //CAMPI_RAGGRUPPAMENTO_RIGHE: ridefinisco il metodo campi_raggruppamento_righe della TFatturazione_bolle void TFatturazione_lavanderie::campi_raggruppamento_righe(TToken_string& campi_riga) const { //richiamo la funzione standard TFatturazione_bolle::campi_raggruppamento_righe(campi_riga); //se lo standard lascia campi_riga vuota, allora la pongo uguale a "CODART|UMQTA" //che sono sicuramente sempre uguali if (campi_riga.empty()) campi_riga = RDOC_CODART"|"RDOC_UMQTA; // Uguali sempre } //FIND_OR_CREATE_ROW: questo metodo cerca tra tutte le righe documento della fattura prodotta //una eventuale riga lavanderia raggruppabile; se la trova restituiace quella riga, altrimenti //ne crea una nuova TRiga_documento& TFatturazione_lavanderie::find_or_create_row(TDocumento& doc_out, const TRiga_documento& rin, const char lavtype) { int r; //scorro le righe documetno for (r = doc_out.physical_rows(); r > 0; r--) //se trovo una riga raggruppabile e di lavanderia, allora interrompo il ciclo if (doc_out[r].raggruppabile(rin, _campi_raggruppamento) && (doc_out[r].get_char("LVTYPE") == lavtype)) break; //se non ho trovato la riga, ne creo una nuova if (r <= 0) { TRiga_documento& row = doc_out.new_row("01"); doc_out.copy_data(row, rin); row.put(RDOC_TIPORIGA, "01"); const TRectype& anamag = cache().get(LF_ANAMAG, rin.get(RDOC_CODART)); row.put(RDOC_CODIVA, anamag.get(ANAMAG_CODIVA)); row.zero(RDOC_CODAGG1); row.zero(RDOC_QTA); row.zero(RDOC_QTAGG1); row.zero(RDOC_CODMAGC); row.put("LVTYPE", lavtype); r = row.get_int(RDOC_NRIGA); } if (fatt_02()) { doc_out.set_row_ids(); const TString key = format("%04d%04d", doc_out.get_int("FATID"), doc_out[r].get_int(RDOC_IDRIGA)); TCalc_02_data * data = (TCalc_02_data *) _output_rows_02.objptr(key); if (data == NULL) { data = new TCalc_02_data(key); _output_rows_02.add(key, data); } TString bolkey = rin.get_rdoc_key(); data->bol_rows().add(bolkey, bolkey); } return doc_out[r]; } //CREATE_ROW: metodo che crea fisicamente la riga sul documento di uscita partendo dal documento di ingresso (bolla) void TFatturazione_lavanderie::create_row(TDocumento& doc_out, const TRiga_documento & rin) { //leggo la causale della riga del documento di ingresso const TString8 causale = rin.get(RDOC_CODAGG1); const TCausale_lavanderie & cau = cached_causale_lavanderie(causale); //recupero i dati cliente dalla testata del documento e instanzio il contratto const long clifo = rin.doc().get_long(DOC_CODCF); const int indsped = rin.doc().get_int(DOC_CODINDSP); TLaundry_contract contr(clifo, indsped, _data_elab); //leggo dal documento i valori che vanno riportati sulla fattura e recupero la riga contratto //di quell'articolo const TString80 codart = rin.get(RDOC_CODARTMAG); // non è gestito il caso di un articolo fuori contratto const real qta = rin.get_real(RDOC_QTA); const real qta1 = rin.get_real(RDOC_QTAGG1); const TRectype& rcont = contr.row(codart); //leggo dalla configurazione da dove va preso il prezzo const int tipoprezzo = ini_get_int(CONFIG_DITTA, "lv", "TipoPr"); real prezzo; //se tipoprezzo == 0 (prezzo da contratto), allora cerco il prezzo sul contratto; se l'articolo //non esiste sul contratto, allora cerco il suo prezzo sull'anagrafica di magazzino. //Se tipoprezzo == 1 (prezzo da bolla), allora leggo il prezzo sulla riga della bolla if (tipoprezzo == 0) { if (!rcont.empty()) prezzo = rcont.get_real(LVRCONDV_PREZZO); } else prezzo = rin.get_real(RDOC_PREZZO); //se è una causale di rotto e se è abilitato nella testata del contratto la fatturazione dei rotti //e se sto ritirando una quantità di merce diversa da zero, allora: if (cau.is_rotto() && contr.get_int(LVCONDV_ADDCAPROT) && !qta1.is_zero()) { //se passo le condizioni iniziali cerco eventualmente una riga che possa essere raggruppata con quella //che sto guardando adesso, altrimenti la creo; in ogni caso aggiungo la quantità da ritirare //al prezzo segnato in contratto TRiga_documento& rd = find_or_create_row(doc_out, rin ,'D'); rd.add(RDOC_QTA, qta1); rd.put(RDOC_PREZZO, rcont.get_real(LVRCONDV_PREZDAN)); } //se è una causale di ritirato e se sto ritirando una quantità di merce diversa da zero, allora: if (cau.is_ritiro() && !qta1.is_zero()) { //leggo la casuale di magazzino associata al ritiro e il suo segno sul consegnato mese const TCausale_magazzino& rit = cau.causale_ritiro(); const real sgnrit = rit.sgn(s_consmese); //se movimenta il consegnato mese, cerco eventualmente una riga che possa essere raggruppata con quella //che sto guardando adesso, altrimenti la creo; in ogni caso aggiungo la quantità che sto ritirando moltiplicata //per il suo segno al prezzo ricavato sopra o da contratto (o da magazzino), o da bolla if (!sgnrit.is_zero()) { TRiga_documento& rr = find_or_create_row(doc_out, rin, 'C'); rr.add(RDOC_QTA, sgnrit * qta1); rr.put(RDOC_PREZZO, prezzo); rr.add("TOTRIT", qta1); } } //se è una causale di consegnato e se sto consegnando una quantità di merce diversa da zero, allora: if (cau.is_consegna() && !qta.is_zero()) { //leggo la casuale di magazzino associata al ritiro e i suoi segni sul consegnato mese, //sulla dotazione temporanea e sulla dotazione iniziale const TCausale_magazzino& con = cau.causale_consegna(); const real sgntmp=con.sgn(s_dottm); const real sgndotin=con.sgn(s_dotin); const real sgncons=con.sgn(s_consmese); //se movimenta la dotazione temporanea e è previsto l'addebito dotazione temporanea con prezzo diverso, //cerco eventualmente una riga che possa essere raggruppata con quella che sto guardando adesso, //altrimenti la creo; in ogni caso aggiungo la quantità che sto consegnando moltiplicata //per il suo segno al prezzo scritto sul contratto per la dotazine temporanea if (!sgntmp.is_zero() && contr.get_bool(LVCONDV_DOTTMPPRZD)) { TRiga_documento& rt = find_or_create_row(doc_out, rin, 'T'); rt.add(RDOC_QTA, sgntmp * qta); rt.put(RDOC_PREZZO, rcont.get_real(LVRCONDV_PRZDTTMP)); } //se movimenta la dotazione iniziale, cerco eventualmente una riga che possa essere raggruppata con quella //che sto guardando adesso, altrimenti la creo; in ogni caso aggiungo la quantità che sto consegnando moltiplicata //per il suo segno al prezzo ricavato sopra o da contratto (o da magazzino), o da bolla if (!sgndotin.is_zero()) { TRiga_documento& rc = find_or_create_row(doc_out, rin, 'I'); rc.add(RDOC_QTA, sgndotin * qta); rc.put(RDOC_PREZZO, prezzo); } else { //se movimenta il consegnato mese, cerco eventualmente una riga che possa essere raggruppata con quella //che sto guardando adesso, altrimenti la creo; in ogni caso aggiungo la quantità che sto consegnando moltiplicata //per il suo segno al prezzo ricavato sopra o da contratto (o da magazzino), o da bolla if (!sgncons.is_zero()) { TRiga_documento& rc = find_or_create_row(doc_out, rin, 'C'); rc.add(RDOC_QTA, sgncons * qta); rc.put(RDOC_PREZZO, prezzo); rc.add("TOTRIT", qta1); } } } } //ELABORA: metodo che esegue alcune operazioni prliminari, quali settare la data elaborazione e trovare i campi //in base ai quali è possibile raggruppare le righe documetno, e poi chiama l'elaborazione standard per la fatturazione bool TFatturazione_lavanderie::elabora(TLista_documenti& doc_in, TLista_documenti& doc_out, const TDate& data_elab, bool interattivo) { _data_elab = data_elab; campi_raggruppamento_righe(_campi_raggruppamento); _output_rows_02.destroy(); return TFatturazione_bolle::elabora(doc_in, doc_out, data_elab, interattivo); } ///////////////////////////////// //// TFatturazione_msk //// ///////////////////////////////// TFatturazione_msk::TFatturazione_msk():TAutomask("lv2500a") { //imposto il periodo di fatturazione dal primo del mese precedente all'ultimo del mese precedente //se la data odierna è inferiore al 10 del mese corrente //altrimenti la imposto dal primo del mese corrente alla data odierna TDate data(TODAY); if (data.day() <= 10) { data.addmonth(-1); data.set_day(1); set(F_DADATA, data); data.set_end_month(); set(F_ADATA, data); } else { set(F_ADATA, data); data.set_day(1); set(F_DADATA, data); } if (main_app().argc() > 2) { TString16 tpela = main_app().argv(2); tpela = tpela.mid(4); TString8 codela = ini_get_string(CONFIG_DITTA, "lv", tpela); set(F_COD_ELAB, codela); field(F_COD_ELAB).check(); disable(F_COD_ELAB); disable(F_DESC_ELAB); } } ///////////////////////////////////// //// TFatturazione_lav_app //// ///////////////////////////////////// //GENERA_BOLLE_NOLO: metodo che genera le fatture di solo nolo per quei clienti a cui non è stato consegnato niente void TFatturazione_lav_app::genera_bolle_nolo(TAssoc_array& cliela, TFatturazione_lavanderie& elab, int& numdocgen) { TString4 codnum = ini_get_string(CONFIG_DITTA, "lv", "NUM_GEN"); TString4 tipodoc = ini_get_string(CONFIG_DITTA, "lv", "TIPODOC_GEN"); char stato = cache().get("%TIP", tipodoc, "S2").mid(1,1)[0]; //preparo la query sui contratti TString str; str << "USE LVCONDV"; if (_msk->get_long(F_DACODCF) > 0) str << "\nFROM CODCF=" << _msk->get_long(F_DACODCF); if (_msk->get_long(F_ACODCF) > 0) str << "\nTO CODCF=" << _msk->get_long(F_ACODCF); TISAM_recordset contr(str); TLista_documenti doc_in; TLista_documenti doc_out; TProgind pi(contr.items(), "Fatturazione", true, true); for(bool ok = contr.move_first(); ok; ok = contr.move_next()) { pi.set_text(TR("Elaborazione Nolo")); if (!pi.addstatus(1)) break; //scarto i contratti scaduti if (contr.get(LVCONDV_DATASC).as_date().ok()) if (_msk->get_date(F_DADATA) <= contr.get(LVCONDV_DATAIN).as_date() || _msk->get_date(F_ADATA) >= contr.get(LVCONDV_DATASC).as_date()) continue; //scarto tutti quelli che non sono in periodo di fatturazione corretto if (contr.get(LVCONDV_PERFAT).as_int() > _msk->get_int(F_PERFAT)) continue; //scarto tutti quelli a cui ho già fatturato if(cliela.is_key(contr.get(LVCONDV_CODCF).as_string())) continue; TDocumento *pdoc= new TDocumento('D', _msk->get_date(F_DATAFAT).year(), codnum, 0); doc_in.add(pdoc); TDocumento& doc = *pdoc; doc.put(DOC_TIPODOC, tipodoc); doc.put(DOC_STATO, stato); doc.put(DOC_TIPOCF, 'C'); doc.put(DOC_CODCF, contr.get(LVCONDV_CODCF).as_int()); TLaundry_contract contratto(contr.cursor()->curr()); const long codcf = contratto.get_long(LVCONDV_CODCF); const int codcont = contratto.get_int(LVCONDV_CODCONT); TString str; str << "USE LVRCONDV\n" << "FROM CODCF=" << codcf << " CODCONT=" << codcont << "\n" << "TO CODCF=" << codcf << " CODCONT=" << codcont; TISAM_recordset rcont(str); for(bool ok = rcont.move_first(); ok; ok = rcont.move_next()) { TRectype& riga = rcont.cursor()->curr(); if (riga.get_int(LVRCONDV_TIPOFORF) == 2) { TRiga_documento& rdoc = doc.new_row("21"); rdoc.put(RDOC_CODART, riga.get(LVRCONDV_CODART)); rdoc.put(RDOC_CODARTMAG, riga.get(LVRCONDV_CODART)); rdoc.put(RDOC_QTA, UNO); rdoc.put(RDOC_QTAGG1, UNO); rdoc.put(RDOC_PREZZO, riga.get_real(LVRCONDV_PREZNOL)); rdoc.put(RDOC_CHECKED, true); rdoc.put(RDOC_UMQTA, riga.get(LVRCONDV_UM)); TToken_string key; key.add('C'); key.add(codcf); TString8 codiva = cache().get(LF_CFVEN, key, CFV_ASSFIS); if (codiva.blank()) codiva = cache().get(LF_ANAMAG, riga.get(LVRCONDV_CODART), ANAMAG_CODIVA); rdoc.put(RDOC_CODIVA, codiva); rdoc.put(RDOC_CODAGG1, ini_get_string(CONFIG_DITTA, "lv", "CAUSLAV")); } } if (ini_get_bool(CONFIG_DITTA, "lv", "RifTest")) elab.put("B15", true); //forzo la descrizione abbreviata if (doc.rows() > 0) { elab.elabora(doc_in, doc_out, _msk->get_date(F_DATAFAT)); doc_out.write(); numdocgen += doc_out.items(); } doc_out.destroy(-1); doc_in.destroy(-1); } } //CONTROLLI PRELIMINARI: metodo che si preoccupa di ferivicare la presenza in configurazione di tutti //i dati necessari alla fatturazione bool TFatturazione_lav_app::controlli_preliminari() { bool corretto = true; //controllo se il tipo documento è configurato if (ini_get_string(CONFIG_DITTA, "lv", "NUM_FAT").empty() || ini_get_string(CONFIG_DITTA, "lv", "TIPODOC_FAT").empty()) { warning_box(TR("Il Tipo documento fattura non è configurato correttamente")); corretto = false; } //controllo se le causali di dafault sono configurate if (ini_get_string(CONFIG_DITTA, "lv", "CAUSLAV").empty()) { warning_box(TR("La causale di default non è configurata correttamente")); corretto = false; } if (ini_get_string(CONFIG_DITTA, "lv", "CAULVRITDT").empty()) { warning_box(TR("La causale di default non è configurata correttamente")); corretto = false; } //controllo se l'articolo per il canone fisso è configurato if (ini_get_string(CONFIG_DITTA, "lv", "Codartfix").empty()) { warning_box(TR("L'articolo per canone fisso non è configurato correttamente")); corretto = false; } //controllo se l'articolo per il raggruppamento è configurato if (ini_get_string(CONFIG_DITTA, "lv", "Codartcafix").empty()) { warning_box(TR("L'articolo per il raggruppamento non è configurato correttamente")); corretto = false; } //controllo se l'unità di misura per la fatturazioni a Kg è settata if(ini_get_string(CONFIG_DITTA, "lv", "UmKg").empty()) { warning_box(TR("L'unità di misura per la fatturazione a Kg non è configurata correttamente")); corretto = false; } return corretto; } void TFatturazione_lav_app::main_loop() { bool prova = false; if (main_app().argc() > 2) { TString16 tpela = main_app().argv(2); tpela = tpela.mid(4); prova = (tpela == "FatPro"); } //instanzio la maschera _msk = new TFatturazione_msk(); //instanzio i localisamfile che mi servono TLocalisamfile doc(LF_DOC); TLocalisamfile rdoc(LF_RIGHEDOC); while (_msk->run()!= K_QUIT) { if (!controlli_preliminari()) { TString str; str << "Prima di poter eseguire la fatturazione è necessario correggre tutti gli errori segnalati. " << "Si prega di controllare i dati di configurazione"; warning_box(str); return; } //leggo i dati di primo interesse const TString4 mskzona = _msk->get(F_CODZONA); const TString4 mskcat = _msk->get(F_CODCATC); //preparo le date estremi (dal - al) della query e l'anno dell'esercizio TDate al = _msk->get_date(F_ADATA); //se la data "al" non è corretta, la pongo uguale alla data fattura if (!al.ok()) al = _msk->get_date(F_DATAFAT); const long year = al.year(); TDate dal = _msk->get_date(F_DADATA); //se la data "dal" non è corretta, la pongo uguale a 1/1/annoes if (!dal.ok()) { dal.set_day(1); dal.set_month(1); dal.set_year(year); } //instanzio una TFatturaziome_lavanderie TFatturazione_lavanderie elab(_msk->get(F_COD_ELAB), prova); //preparo le variabili di interesse TLista_documenti docsin; TLista_documenti docsout; long lastcli = 0; const int period = _msk->get_int(F_PERFAT); const TDate datafat = _msk->get_date(F_DATAFAT); long indsped; //preparo la query TString query; //&&(BETWEEN(DATADOC,#DADATA,#ADATA))&&(STATO==\"2\")&&(TIPODOC==\"B01\") query << "USE DOC KEY 3 SELECT (TIPOCF==\"C\")&&" << "(BETWEEN(CODCF," << _msk->get_long(F_DACODCF) << ',' << _msk->get_long(F_ACODCF) << "))\n" << "BY TIPOCF CODCF DATADOC\n" << "FROM " << "DATADOC=" << dal << " PROVV=D ANNO=" << year << "\n" << "TO " << "DATADOC=" << al << " PROVV=D ANNO=" << year << "\n"; // query << "USE DOC KEY 2 SELECT BETWEEN(DATADOC,#DADATA,#ADATA)&&STATO==\"2\")&&(TIPODOC==\"B01\")\n" // << "FROM " << "TIPOCF=C PROVV=D ANNO=#ANNO DATADOC=#DADATA \n" // << "TO " << "TIPOCF=C PROVV=D ANNO=#ANNO DATADOC=#ADATA \n"; //instanzio il recordset TISAM_recordset recset(query); TProgind pi(recset.items(), "Fatturazione", true, true); long last_clifo = 0; int numdocgen = 0; //TAssoc_array dei clienti per cui ho generato dei documenti TAssoc_array cliela; //scorro tutti documenti che la query mi restiuisce for (bool ok = recset.move_first(); ok; ok = recset.move_next()) { //leggo il codcf const long clifo = recset.get(DOC_CODCF).as_int(); if (clifo != last_clifo) { TString80 str; str << TR("Elaborazione Cliente ") << clifo; pi.set_text(str); last_clifo=clifo; } if (!pi.addstatus(1)) break; //se non è l'ultimo cliente, allora: if (clifo != lastcli) { //se effettivamente devo elaborare delle bolle per questo cliente, allora: if (docsin.items()!= 0) { //elaboro tutti i documenti, li salvo nei file di Campo e svuoto le TList_file elab.put("B15", 'X'); elab.elabora(docsin, docsout, datafat); const int items = docsout.items(); if (items > 0) { docsout.write(); numdocgen += items; TString tmp; tmp << lastcli; cliela.add(tmp, tmp); } docsout.destroy(-1); docsin.rewrite(); docsin.destroy(-1); } lastcli = clifo; } //preparo la chiave e recupero da CFVEN i dati di quel cliente TToken_string key; key.add('C'); key.add(clifo); const TRectype& clienti = cache().get(LF_CFVEN,key); //se il documento che sto analizzando è corretto, allora: bool cliok = elab.is_document_ok(recset.cursor()->curr()); if (cliok) { //se il codice di zona è pieno, allora: if (mskzona.full()) { //leggo il codice di zona standard di quel cliente e lo confronto con quello della mascera (V o F) const TString& codzona = clienti.get(CFV_CODZONA); cliok = (codzona == mskzona); } //se il codice categoria economica è pieno e ho passato il test sul codice di zona, allora: if (cliok && mskcat.full()) { //leggo il codice categoria economica standard di quel cliente e lo confronto con quello della mascera (V o F) const TString& codcat = clienti.get(CFV_CODCATC); cliok = (codcat == mskcat); } } //se ho passato tutti e due i test, allora: if (cliok) { //cerco sul contratto qual'è il periodo di fatturazione di quel cliente indsped = recset.get(DOC_CODINDSP).as_int(); TLaundry_contract contr(clifo, indsped, datafat); const int contrper = contr.get_int(LVCONDV_PERFAT); //se il cliente non è sospeso e se si è nel periodo di fatturazione giusto, aggiungo il documento alla //lista dei documetni da elaborare if (!contr.get_bool(LVCONDV_FATTSOSP) && contrper <= period) docsin.add(new TDocumento(recset.cursor()->curr())); } } //se ho dei documenti in lista li elaboro e poi svuoto le TList_file if (docsin.items() != 0) { if (ini_get_bool(CONFIG_DITTA, "lv", "RifTest")) elab.put("B15", true); //forzo la descrizione abbreviata elab.elabora(docsin, docsout, datafat); const int items = docsout.items(); if (items > 0) { docsout.write(); numdocgen += items; TString tmp; tmp << lastcli; cliela.add(tmp, tmp); } docsout.destroy(-1); docsin.rewrite(); docsin.destroy(-1); } genera_bolle_nolo(cliela, elab, numdocgen); TString str; if (numdocgen > 1 || numdocgen == 0) str << "Sono state generate " << numdocgen << " fatture"; else str << "E' stata generata " << numdocgen << " fattura"; message_box(str); message_box(TR("Elaborazione terminata")); } } int lv2500(int argc, char *argv[]) { TFatturazione_lav_app a; a.run (argc, argv, "Fatturazione lavanderie"); return TRUE; }