#include #include #include "lvlib.h" #include "lv2500a.h" #include "cfven.h" #include "lvcondv.h" #include "lvrcondv.h" #include "rdoc.h" #include "../ve/ve6200.h" #include "../ve/ve6200a.h" //////////////////////////////////////// //// TFatturazione_lavanderie //// //////////////////////////////////////// //Classe TFatturazione_lavanderie class TFatturazione_lavanderie:public TFatturazione_bolle { TDate _data_elab; TToken_string _campi_raggruppamento; 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_out) {} virtual void post_process_output(TLista_documenti& doc_out); 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); public: virtual bool elabora(TLista_documenti& doc_in, TLista_documenti& doc_out, const TDate& data_elab, bool interattivo = false); TFatturazione_lavanderie(const char* cod); ~TFatturazione_lavanderie() {} }; TFatturazione_lavanderie::TFatturazione_lavanderie(const char* cod) : TFatturazione_bolle(cod) { } //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; } //POST_PROCESS_OUTPUT: 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_output(TLista_documenti& doc_out) { //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); 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", "RigTest"); 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); } if (riftest) { TRiga_documento& rout = doc[1]; TString80 descr = rout.get_date(RDOC_DESCR); doc.put(DOC_NOTE,descr); } 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 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_int(CONFIG_DITTA, "lv", "Codartcafix"); // 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_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_CANFIX); const TString80 codartcfg = ini_get_int(CONFIG_DITTA, "lv", "Codartfix"); // 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_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 { //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 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; } } } } } //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 = "CODART|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"); 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); } 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(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); } } //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); } //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); } } } //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); return TFatturazione_bolle::elabora(doc_in, doc_out, data_elab, interattivo); } ///////////////////////////////// //// TFatturazione_msk //// ///////////////////////////////// //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_msk::TFatturazione_msk():TAutomask("lv2500a") { } ///////////////////////////////////// //// TFatturazione_lav_app //// ///////////////////////////////////// //classe TFatturazione_lav_app class TFatturazione_lav_app: public TSkeleton_application { protected: virtual void main_loop(); }; void TFatturazione_lav_app::main_loop() { //instanzio la maschera TFatturazione_msk msk; //instanzio i localisamfile che mi servono TLocalisamfile doc(LF_DOC); TLocalisamfile rdoc(LF_RIGHEDOC); while (msk.run()!=K_QUIT) { //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)); //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\")\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); //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(); //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.elabora(docsin, docsout, datafat); docsout.write(); 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) { elab.elabora(docsin, docsout, datafat); docsout.write(); docsout.destroy(-1); docsin.rewrite(); docsin.destroy(-1); } } } int lv2500(int argc, char *argv[]) { TFatturazione_lav_app a; a.run (argc, argv, "Fatturazione lavanderie"); return TRUE; }