#include #include #include #include #include #include #include #include #include #include "../cg/cglib01.h" #include "../ve/velib.h" #include "halib.h" #include "ha0.h" #include "ha0500a.h" /////////////////////////////////////////////////////////// // TAutomask /////////////////////////////////////////////////////////// class THardy_elab_docs_mask : public TAutomask { protected: virtual bool on_field_event(TOperable_field& o, TField_event e, long jolly); public: THardy_elab_docs_mask(); ~THardy_elab_docs_mask(); }; THardy_elab_docs_mask::THardy_elab_docs_mask() : TAutomask ("ha0500a") { } THardy_elab_docs_mask::~THardy_elab_docs_mask() { } bool THardy_elab_docs_mask::on_field_event(TOperable_field& o, TField_event e, long jolly) { switch (o.dlg()) { case F_ADATA: if (e == fe_close || e == fe_modify) { //se la data iniziale è piena -> l'anno deve essere lo stesso nelle 2 date; //se invece è vuota -> la data iniziale viene presa come la data iniziale dell'esercizio della data finale... //..ma questo qui non serve e viene rinviato alla query principale del recordset const TDate adata = get_date(F_ADATA); TEsercizi_contabili esc; const int adata_esc = esc.date2esc(adata); TDate dadata = o.get(); if (dadata.ok()) { const int dadata_esc = esc.date2esc(dadata); if (adata_esc != dadata_esc) return error_box("Le date devono appartenere allo stesso esercizio!"); } } break; /*case F_TIPOCONTR: if (e == fe_modify) { //in base alla tipologia di contratti da elaborare decide numerazione e tipo delle NAC da generare TConfig config(CONFIG_DITTA, "ha"); TString4 codnum, tipodoc; switch (o.get()[0]) { case 'A': codnum = config.get("NaAntNum"); tipodoc = config.get("NaAntTip"); break; case 'R': codnum = config.get("NaRifaNum"); tipodoc = config.get("NaRifaTip"); break; default: codnum = config.get("NaPostNum"); tipodoc = config.get("NaPostTip"); break; } set(F_CODNUM_NAC, codnum); set(F_CODTIPO_NAC, tipodoc); } break;*/ //in caso di elaborazione definitiva è obbligatorio.. //..eliminare tutte le NAC provvisorie generate in precedenza case F_DEFINITIVO: if (e == fe_modify) { if (o.get() == "X") { set(F_KILLPROVV, "X"); disable(F_KILLPROVV); } else { enable(F_KILLPROVV); set(F_KILLPROVV, " "); } } break; default: break; } return true; } /////////////////////////////////////// // TSkeleton_application /////////////////////////////////////// class THardy_elab_docs : public TSkeleton_application { protected: //metodi alto livello void elabora(const TMask& mask); int kill_provv_nac(const TMask& mask); long genera_recordset(const TMask& mask, TISAM_recordset& recset); void elabora_documenti(const TMask& mask, TISAM_recordset& recset, TLog_report& log); //metodi medio livello bool aggiorna_contratti_anticipo(const TString& rdoc_codart, const real& rdoc_qta, TDocumento& contratto); bool aggiorna_contratti_posticipo(const TString& rdoc_codart, const real& rdoc_qta, TDocumento& contratto); bool aggiorna_contratti(TDocumento& curr_doc, TArray& contratti_cliente); bool genera_nac(const TMask& mask, TArray& contratti_cliente, TArray& documenti_cliente, TLog_report& log); //metodi basso livello int find_contratti_cliente(const long codcf, const TMask& mask, TArray& contratti_cliente); void check_date(const TDate& datafine, TDate& dataini); int find_numerazioni(const TString& tipo_to_elab, TString_array& num_doc); public: virtual void main_loop(); virtual bool create(); }; //metodo per ricavare la data iniziale di elaborazione qualora l'utonto non la metta e l'esercizio da usare void THardy_elab_docs::check_date(const TDate& datafine, TDate& dataini) { TEsercizi_contabili esc; TDate datafine_tmp = datafine; const int esercizio = esc.date2esc(datafine); esc.code2range(esercizio, dataini, datafine_tmp); } int THardy_elab_docs::find_numerazioni(const TString& tipo_to_elab, TString_array& num_doc) { TISAM_recordset num_recset("USE %NUM"); for (bool ok = num_recset.move_first(); ok; ok = num_recset.move_next()) //giro sui vari tipi numerazione { const TString4 codtab = num_recset.get("CODTAB").as_string(); const TCodice_numerazione numerazione(codtab); for (int t = numerazione.ntipi_doc() - 1; t >= 0; t--) { const TString& tipo_doc = numerazione.tipo_doc(t); if (tipo_doc == tipo_to_elab) { if (num_doc.find(codtab) < 0) // Evito aggiunta di doppioni num_doc.add(codtab); break; } } //for (int t = codnum.. } //for (bool ok = num_recset... return num_doc.items(); } //metodo per accoppare tutte le NAC provvisorie generate in precedenza int THardy_elab_docs::kill_provv_nac(const TMask& mask) { int nac_killed = 0; const TDate& adata = mask.get_date(F_ADATA); int anno = adata.year(); TConfig config(CONFIG_DITTA, "ha"); TToken_string numerazioni; numerazioni.add(config.get("NaAntNum")); numerazioni.add(config.get("NaRifaNum")); numerazioni.add(config.get("NaPostNum")); FOR_EACH_TOKEN(numerazioni, codnum) { TRelation rel_doc(LF_DOC); TRectype& rec = rel_doc.curr(); rec.put(DOC_PROVV, "P"); rec.put(DOC_ANNO, anno); rec.put(DOC_CODNUM, codnum); TCursor cur_doc (&rel_doc, "", 1, &rec, &rec); const long items = cur_doc.items(); cur_doc.freeze(); TProgind progind(items, "Eliminazione NAC provvisorie in corso...", false, true); for (cur_doc = 0; cur_doc.pos() < items; ++cur_doc) { progind.addstatus(1); TDocumento doc(rec); int err = doc.remove(); if (err == NOERR) nac_killed++; } } return nac_killed; } //metodo che filtra tutti i documenti in base ai parametri della maschera long THardy_elab_docs::genera_recordset(const TMask& mask, TISAM_recordset& recset) { //parametri di elaborazione //per prima cosa controlla se il cliente è stato specificato; questo influisce sulla scelta della chiave di ricerca sul file int key = 3; const long codcf = mask.get_long(F_CODCF); if (codcf > 0) key = 2; //e costruiamola 'sta query! //usa i documenti con chiave variabile (vedi sopra) TString query; query << "USE DOC KEY " << key; //lo stato dipende da quanto sta scritto sulla elaborazione differita (stato iniziale dei docs da considerare) //viene messo CODNUM nella SELECT perchè, essendoci un range di date nelle chiavi, la numerazione verrebbe ignorata! (provato!) query << "\nSELECT (STATO=#STATOINI)"; //in base al tipo documento che si deve elaborare (settato in configurazione), ci possono essere più numerazioni da considerare! TConfig config(CONFIG_DITTA, "ha"); const TString& tipo_to_elab = config.get("TipoFatt"); //e adesso cerca le numerazioni che contengono il tipo preso dalla configurazione TString_array num_doc; const int numerazioni_valide = find_numerazioni(tipo_to_elab, num_doc); if (numerazioni_valide > 0) { query << "&&("; for (int i = 0; i < numerazioni_valide; i++) { if (i > 0) query << "||"; query << "(CODNUM='" << num_doc[i] << "')"; } query << ")"; } //se c'è l'agente specificato... const TString& agente = mask.get(F_CODAGE); const bool has_007 = agente.full(); if (has_007) query << "&&(CODAG=#CODAG)"; //ordinamento agente-codcf-numdoc query << "\nBY "; if (has_007) query << DOC_CODAG << " "; query << DOC_CODCF << " " << DOC_NDOC; //from-to dipendente da chiave switch (key) { case 2: //chiave per tipocf-codcf-provv-anno-datadoc-codnum { query << "\nFROM TIPOCF=C CODCF=#CODCF PROVV=D ANNO=#ANNO DATADOC=#DADATA"; query << "\nTO TIPOCF=C CODCF=#CODCF PROVV=D ANNO=#ANNO DATADOC=#ADATA"; } break; case 3: //chiave per datadoc-provv-anno-codnum { query << "\nFROM DATADOC=#DADATA PROVV=D ANNO=#ANNO"; query << "\nTO DATADOC=#ADATA PROVV=D ANNO=#ANNO"; } break; default: break; } //setta la nuova query al recordset (inizialmente nato dequeryzzato) recset.set(query); //settaggio delle variabili const TDate adata = mask.get_date(F_ADATA); TDate dadata = mask.get_date(F_DADATA); //se la data iniziale è vuota deve coincidere con l'inizio dell'esercizio della data finale (obbligatoria!) int esc = adata.year(); if (!dadata.ok()) check_date(adata, dadata); //lo stato dei documenti da considerare va a raccatarlo nel config const TString& stato_ini = config.get("StatoIniFatt"); recset.set_var("#STATOINI", stato_ini); if (agente.full()) recset.set_var("#CODAG", agente); if (codcf > 0) recset.set_var("#CODCF", codcf); recset.set_var("#ANNO", long(esc)); recset.set_var("#DADATA", dadata); recset.set_var("#ADATA", adata); return recset.items(); } //metodo che riempie un array con tutti i contratti del cliente passatogli (in base alla tipologia di contratti da elaborare) int THardy_elab_docs::find_contratti_cliente(const long codcf, const TMask& mask, TArray& contratti_cliente) { contratti_cliente.destroy(); //deve cercare tutti i contratti del cliente e metterli nell'array TString query; query << "USE DOC KEY 4"; query << "\nSELECT ((CODNUM=#A_CODNUM)||(CODNUM=#R_CODNUM)||(CODNUM=#P_CODNUM))"; query << "\nFROM TIPOCF=C CODCF=#CODCF"; query << "\nTO TIPOCF=C CODCF=#CODCF"; TISAM_recordset recset(query); //settaggio delle variabili //il codice numerazione lo trova nella configurazione Hardy, e lo deve scegliere in base alla tipologia di contratti che sta esaminando! TConfig config(CONFIG_DITTA, "ha"); const TString& num_ant = config.get("CoAntNum"); const TString& num_rifa = config.get("CoRifaNum"); const TString& num_post = config.get("CoPostNum"); recset.set_var("#A_CODNUM", num_ant); recset.set_var("#R_CODNUM", num_rifa); recset.set_var("#P_CODNUM", num_post); recset.set_var("#CODCF", codcf); const long n_contratti = recset.items(); //questo serve solo al sagace programmatore //aggiunge i contratti all'array: solo quelli in auge nel periodo di calcolo selezionato sulla maschera! for (bool ok = recset.move_first(); ok; ok = recset.move_next()) { //controlla il tipo di contratto const char tipo_contr = recset.get(DOC_TIPOCFFATT).as_string()[0]; //contratti anticipo 'A': datainizio esiste sempre, datafine non esiste (va ad esaurimento) //contratti posticipo 'P': datainizio esiste sempre, datafine può non esistere //contratti rifatturazione 'R': come contratti anticipo //controlla validità del contratto con le date scelte per l'elaborazione dei documenti const TDate data_ini_contratto = recset.get(DOC_DATACOMP).as_date(); TDate data_ini_elab = mask.get_date(F_DADATA); const TDate data_fine_elab = mask.get_date(F_ADATA); if (!data_ini_elab.ok()) check_date(data_fine_elab, data_ini_elab); //quindi la datainizio vale per tutti allo stesso modo (è obbligatoria nei contratti) //se l'elaborazione finisce prima che cominci il contratto -> il contratto non serve a nulla if (data_ini_contratto > data_fine_elab) continue; //la data fine vale invece solo per i contratti 'P' e potrebbe non esserci (contratti senza scadenza) TDate data_fine_contratto; if (tipo_contr == 'P') { data_fine_contratto = recset.get(DOC_DATAFCOMP).as_date(); if (data_fine_contratto.ok()) { if (data_fine_contratto < data_ini_elab) continue; } } TDocumento* curr_contratto = new TDocumento(recset.get(DOC_PROVV).as_string()[0], recset.get(DOC_ANNO).as_int(), recset.get(DOC_CODNUM).as_string(), recset.get(DOC_NDOC).as_int()); contratti_cliente.add(curr_contratto); } return contratti_cliente.items(); } bool THardy_elab_docs::aggiorna_contratti_anticipo(const TString& rdoc_codart, const real& rdoc_qta, TDocumento& contratto) { bool elaborato = false; FOR_EACH_PHYSICAL_RDOC(contratto, rm, rigamerce) { const TString& rigamerce_codart = rigamerce->get(RDOC_CODART); //se trova il codart in una delle righe di contratto... if (rdoc_codart == rigamerce_codart) { const real rigamerce_premio = rigamerce->get_real(RC_1_PREMIO); //se il premio non è nullo procede all'aggiornamento del restituito if (rigamerce_premio != ZERO) { //aggiornamento delle righe di tipo spesa (verigH02) per aggiornare le somme restituite FOR_EACH_PHYSICAL_RDOC(contratto, ra, rigacontratto) { //cerca una riga anticipo da evadere sul contratto per aggiornare la somma restituita sull'anticipo if (rigacontratto->is_spese()) { //usa qtagg3 come campo di appoggio per il calcolo della somma restituita dovuta al contratto (parte da zero per ogni elaborazione di NAC) real somma_restituita = rigacontratto->get_real(RCA_2_RESTITUITO); //la somma restituita deve essere incrementata per la qta di merce (caffè) che c'è sulla riga della fattura in esame... //..moltiplicata per il premio che c'è nella riga di tipo merce del contratto in esame somma_restituita += rdoc_qta * rigamerce_premio; rigacontratto->put(RCA_2_RESTITUITO, somma_restituita); elaborato = true; } } //FOR_EACH_PHYSICAL.. fine casino sulla riga di tipo spese if (rigamerce->is_merce()) { real somma_bonus = rigamerce->get_real(RC_1_BONUS); somma_bonus += rdoc_qta * rigamerce_premio; rigamerce->put(RC_1_BONUS, somma_bonus); elaborato = true; } } //aggiornamento delle quantità per le righe di tipo merce (verigH01) if (rigamerce->is_merce()) { real qta_tot = rigamerce->get_real(RDOC_QTA); //prende la qta tot dal contratto (è usato un campo di appoggio RDOC_QTA) qta_tot += rdoc_qta; //aggiunge la qta della riga documento rigamerce->put(RDOC_QTA, qta_tot); //riscrive sul campo di appoggio del contratto } } //if(rdoc_codart... } //FOR_EACH_PHYSICAL.. return elaborato; } bool THardy_elab_docs::aggiorna_contratti_posticipo(const TString& rdoc_codart, const real& rdoc_qta, TDocumento& contratto) { bool elaborato = false; FOR_EACH_PHYSICAL_RDOC(contratto, rm, rigamerce) { const TString& rigamerce_codart = rigamerce->get(RDOC_CODART); //se trova il codart in una delle righe di contratto... if (rdoc_codart == rigamerce_codart) { const real rigamerce_premio = rigamerce->get_real(RC_1_PREMIO); //..aggiorna direttamente il bonus totale per l'articolo presente sulla riga if (rigamerce_premio != ZERO) { //usa QTAGG3 come campo di appoggio per il calcolo della somma restituita dovuta al contratto (parte da zero per ogni elaborazione di NAC) real somma_bonus = rigamerce->get_real(RC_1_BONUS); somma_bonus += rdoc_qta * rigamerce_premio; rigamerce->put(RC_1_BONUS, somma_bonus); elaborato = true; } //if(rigamerce... //aggiornamento delle righe di tipo merce (verigH01) if (rigamerce->is_merce()) { real qta_tot = rigamerce->get_real(RDOC_QTA); qta_tot += rdoc_qta; rigamerce->put(RDOC_QTA, qta_tot); } } //if(rdoc_codart... } //FOR_EACH_PHYSICAL.. return elaborato; } //aggiorna, in base al documento in esame curr_doc, le somme restituite nelle righe di tipo verigh02 nei contratti validi.. //..del cliente bool THardy_elab_docs::aggiorna_contratti(TDocumento& curr_doc, TArray& contratti_cliente) { bool elaborato = false; FOR_EACH_PHYSICAL_RDOC(curr_doc, r, rdoc) if (rdoc->is_merce()) //giro su tutte le righe merce delle fatture { TString80 rdoc_codart = rdoc->get(RDOC_CODART); //non si riesce ad usare un TString& perchè lo perde dopo un pò rdoc_codart.trim(); const real rdoc_qta = rdoc->quantita(); //controlla se il codart della riga esiste in uno dei contratti validi for (int i = 0; i < contratti_cliente.items(); i++) { TDocumento& contratto = (TDocumento&)contratti_cliente[i]; const TString& tipo_contratto = contratto.get(DOC_TIPOCFFATT); //in base al tipo di contratto (Anticipo/Posticipo/Rifatturazione) decide cosa fare if (tipo_contratto == "A" || tipo_contratto == "R") { elaborato |= aggiorna_contratti_anticipo(rdoc_codart, rdoc_qta, contratto); } //if(tipo_contratto... else if (tipo_contratto == "P") { elaborato |= aggiorna_contratti_posticipo(rdoc_codart, rdoc_qta, contratto); } } //for(int i.. } //FOR_EACH... return elaborato; } bool THardy_elab_docs::genera_nac(const TMask& mask, TArray& contratti_cliente, TArray& documenti_cliente, TLog_report& log) { //si informa se l'elaborazione è definitiva o meno const bool definitivo = mask.get_bool(F_DEFINITIVO); //giro su tutti i contratti del cliente che stanno nell'array (ogni contratto genera una NAC) FOR_EACH_ARRAY_ITEM(contratti_cliente, r, riga) { TDocumento& contratto = *(TDocumento*)riga; const long ndoc = contratto.numero(); //il numdoc del contratto serve nelle segnalazioni const long codcf = contratto.codcf(); //il codice cliente ci serve nella generazione della NAC.. const char tipo_contratto = contratto.get(DOC_TIPOCFFATT)[0]; //..e pure il tipo di contratto in esame! //segnaliamo l'elaborazione del contratto sul log TString msg; msg << "Elaborato contratto premi n." << ndoc << " del cliente " << codcf; log.log(0, msg); // generazione del documento NAC dal contratto // ------------------------------------------- // TESTATA //alcuni parametri delle righe vanno presi dalla configurazione TConfig config(CONFIG_DITTA, "ha"); TString4 nac_codnum, nac_tipo; TString8 cod_riga; switch (tipo_contratto) { case 'A': nac_codnum = config.get("NaAntNum"); nac_tipo = config.get("NaAntTip"); cod_riga = config.get("NaAntSpe"); break; case 'R': nac_codnum = config.get("NaRifaNum"); nac_tipo = config.get("NaRifaTip"); cod_riga = config.get("NaRifaSpe"); break; default: nac_codnum = config.get("NaPostNum"); nac_tipo = config.get("NaPostTip"); cod_riga = config.get("NaPostSpe"); break; } const int anno = mask.get_date(F_ADATA).year(); //solo in caso di elaborazione definitiva si scrivono NAC di tipo D; sennò di tipo P, che sono uccidibili.. //..all'inizio di ogni nuova elaborazione char provv = 'P'; if (definitivo) provv = 'D'; TDocumento nac(provv, anno, nac_codnum, 0); //num_doc = 0 perchè viene aggiornato in fase di registrazione nac.set_tipo(nac_tipo); nac.put(DOC_STATO, 1); nac.put(DOC_DATADOC, mask.get(F_DATAELAB)); nac.put(DOC_TIPOCF, 'C'); nac.put(DOC_CODCF, codcf); // RIGHE //ogni riga di tipo merce (verigh01) del contratto origina una riga della NAC //noto il codice di riga spesa (che farà le veci del codart), troviamo il tipo riga dalla tabella SPP e tutte le features che servono const TRectype& rec_spp = cache().get("SPP", cod_riga); const TString4 tipo_riga = rec_spp.get("S8"); const TString80 descr_riga_spp = rec_spp.get("S0"); const TString4 codiva = rec_spp.get("S3"); //giro sulle righe del contratto, che originano le righe NAC for (int i = 1; i <= contratto.rows(); i++) { const TRiga_documento& riga_contratto = contratto[i]; //le righe di un documento partono da 1! (standard del mercoledì) const TString& tiporiga = riga_contratto.get(RDOC_TIPORIGA); const TString& tipo_riga_contratto = cache().get("%TRI", tiporiga, "S7"); //solo le righe di tipo merce (verigh01) dei contratti devono comparire nelle NAC if (tipo_riga_contratto == "M") { TString80 riga_contratto_codart = riga_contratto.get(RDOC_CODART); riga_contratto_codart.trim(); const real riga_contratto_bonus = riga_contratto.get_real(RDOC_QTAGG3); if (riga_contratto_bonus != ZERO) int cazzone = 1; const real riga_contratto_qta = riga_contratto.get_real(RDOC_QTA); const TString4 riga_contratto_um = riga_contratto.get(RDOC_UMQTA); const real riga_contratto_premio = riga_contratto.get_real(RC_1_PREMIO); // riga (dovrebbe essere un'unica riga per NAC, il cui valore sta in QTAGG3 ed è stato calcolato nella aggiorna_contratti()) TRiga_documento& nac_row = nac.new_row(tipo_riga); nac_row.put(RDOC_NRIGA, i); nac_row.put(RDOC_CODART, cod_riga); //panegirico della descrizione nac_row.put(RDOC_DESCR, descr_riga_spp); msg.cut(0); //risparmiamo sulle stringhe, mica sono gratis const TDate adata = mask.get_date(F_ADATA); TDate dadata = mask.get_date(F_DADATA); if (!dadata.ok()) check_date(adata, dadata); msg << " " << dadata << " -- " << adata << " --(Art." << riga_contratto_codart << ")"; nac_row.put(RDOC_DESCEST, msg); nac_row.put(RDOC_DESCLUNGA, "X"); //importi, qta, umqta nac_row.put(RDOC_UMQTA, riga_contratto_um); nac_row.put(RDOC_QTA, riga_contratto_qta); nac_row.put(RDOC_PREZZO, riga_contratto_premio); //iva nac_row.put(RDOC_CODIVA, codiva); } } // salvataggi vari // --------------- //la NAC viene scritta comunque, con provv='D' se elaborazione definitiva int err = nac.write(); msg.cut(0); //la fase di risparmio stringhe continua if (err == NOERR) msg << "Generata NAC "; else msg << "Impossibile generare NAC "; msg << " - provv:" << provv << " - num:" << nac_codnum << " - tipo:" << nac_tipo << " - anno:" << anno << " |" << r; log.log(0, msg); // se non ci sono errori -> in caso di elaborazione definitiva procede alla registrazione.. //.. del contratto (ricordiamo che in memoria il contratto ha già le righe aggiornate if (definitivo && err == NOERR) { //prima di registrare il contratto vanno svuotati i campi appoggio sulle righe che sono stati usati.. //..per qta e premi vari e riempiti nella aggiorna_contratti() for (int i = 1; i <= contratto.rows(); i++) { TRiga_documento& riga_contratto = contratto[i]; riga_contratto.put(RDOC_QTAGG3, ZERO); riga_contratto.put(RDOC_QTA, ZERO); } //alla fine della fiera aggiorna il contratto err = contratto.rewrite(); msg.cut(0); if (err == NOERR) msg << "Aggiornato contratto premi n. "; else msg << "Impossibile aggiornare il contratto premi n. "; msg << ndoc << " del cliente " << codcf; log.log(0, msg); } log.log(0, ""); } //FOR_EACH_ARRAY_ITEM(... giro sui contratti cliente //il metodo ritornerà il successo o meno della registrazione return true; } void THardy_elab_docs::elabora_documenti(const TMask& mask, TISAM_recordset& recset, TLog_report& log) { TProgind pi(recset.items(), TR("Elaborazione documenti in corso..."), true, true); //inizializza variabili da usare nella scansione del recordset long old_codcf = 0L; //array con l'insieme dei contratti e dei documenti elaborati per un singolo cliente! TArray contratti_cliente, documenti_cliente; //giro sulle fatture (è il giro di più alto livello che viene esteso all'interno delle aggiorna_contratti) for (bool ok = recset.move_first(); ok; ok = recset.move_next()) { if (!pi.addstatus(1)) break; const long codcf = recset.get(DOC_CODCF).as_int(); //al cambio cliente deve controllare i contratti di quel cliente nel periodo di elaborazione!! if (codcf != old_codcf) { //aggiorna old_codcf in modo da poter controllare i contratti solo al cambio codcf old_codcf = codcf; const int n_contratti = find_contratti_cliente(codcf, mask, contratti_cliente); if (n_contratti == 0) { TString msg; msg << "Il cliente " << codcf << " non ha un contratto premi valido nel periodo di elaborazione selezionato ma ha fatture."; log.log_error(msg); } } if (contratti_cliente.items() > 0) { //se ha trovato uno o più contratti validi nel periodo passa alla elaborazione dei documenti del cliente TDocumento* curr_doc = new TDocumento(recset.cursor()->curr()); //elabora il documento corrente aggiornando le somme restituite sui contratti validi if (aggiorna_contratti(*curr_doc, contratti_cliente)) documenti_cliente.add(curr_doc); else delete(curr_doc); } } //for (bool ok = recset.move_first()... //generazione NAC (una per contratto cliente) genera_nac(mask, contratti_cliente, documenti_cliente, log); } //metodo di alto livello con i punti principali del programma (come da analisi...) void THardy_elab_docs::elabora(const TMask& mask) { //1) eventuale accoppamento di tutti i documenti provvisori creati con precedenti elaborazioni precedenti int nac_killed = 0; if (mask.get_bool(F_KILLPROVV)) nac_killed = kill_provv_nac(mask); //log report con segnalazioni sui clienti trattati (bene o male) TLog_report log("Sintesi elaborazione"); log.kill_duplicates(); log.log(0, ""); //2) recordset ordinato codag-codcf-numdoc con tutti i docs che soddisfano i parametri dell'utente // --------------------------------------------------------------------------------------------- TISAM_recordset recset(""); const long items = genera_recordset(mask, recset); if (items == 0) { log.log(1, "Non esistono documenti di vendita che soddisfino i parametri selezionati! Ritenta sarai più fortunato!"); } //3) elaborazione documenti e contratti, generazione NAC, salvataggi // --------------------------------------------------------------- elabora_documenti(mask, recset, log); //3) scrittura log // ------------- log.print_or_preview(); } void THardy_elab_docs::main_loop() { THardy_elab_docs_mask mask; while (mask.run() == K_ENTER) { elabora(mask); } } bool THardy_elab_docs::create() { //controlla se la chiave ha l'autorizzazione a questo programma (solo per hardy!) Tdninst dninst; if (!dninst.can_I_run(true)) return error_box(TR("Programma non autorizzato!")); open_files(LF_DOC, LF_RIGHEDOC, 0); return TSkeleton_application::create(); } int ha0500 (int argc, char* argv[]) { THardy_elab_docs main_app; main_app.run(argc, argv, TR("Elaborazione documenti Hardy")); return true; }