#include "velib04.h" #include /////////////////////////////////////////////////////////// // TFatturazione bolle /////////////////////////////////////////////////////////// void TFatturazione_bolle::init() { // Attenzione: uso il TConfig perchè con varibili del tipo AGGFLD(FATPROV) la ini_get_string() NON funziona bene TConfig ini(CONFIG_DITTA, "ve"); const char* cod = get("CODTAB"); TString80 name; name.format("AGGFLD(%s)", cod); _lista_campi = ini.get(name); name.format("ROWSORT(%s)", cod); _rowsort = ini.get(name); _impminfat = real(ini.get("IMPMINFAT")); } TFatturazione_bolle::TFatturazione_bolle(const char* cod) : TElaborazione(cod) { init(); } TFatturazione_bolle::TFatturazione_bolle(const TRectype& rec) : TElaborazione(rec) { init(); } void TFatturazione_bolle::campi_raggruppamento_righe(TToken_string& campi_riga) const { const bool ragg_rig = raggruppa_righe(); if (ragg_rig) { campi_riga = RDOC_CODART"|"RDOC_UMQTA; // Uguali sempre // Uguali se commesse attive if (ca_config().get_int("Authorizations") != 0) { campi_riga.add(RDOC_CODCMS); campi_riga.add(RDOC_FASCMS); campi_riga.add(RDOC_CODCOSTO); } // Uguali opzionalmente if (riga_uguale(0)) campi_riga.add(RDOC_CODMAG); if (riga_uguale(1)) campi_riga.add(RDOC_CODIVA); if (riga_uguale(2)) campi_riga.add(RDOC_PREZZO"|"RDOC_SCONTO); } else campi_riga.cut(0); } void TFatturazione_bolle::campi_raggruppamento(TToken_string& campi) const { campi = DOC_TIPOCF"|"DOC_CODCF"|"DOC_CODVAL"|"DOC_CODLIN; // Uguali sempre // Uguali opzionalmente const char* cond[] = { DOC_CAMBIO, "SCONTO", DOC_TIPODOC, DOC_CODNUM, DOC_CODPAG, DOC_CODABIA"|"DOC_CODCABA, DOC_CODLIST, DOC_CODAG"|"DOC_CODAGVIS, DOC_CODSPMEZZO, DOC_CODPORTO, DOC_CAUSTRASP, DOC_CODVETT1"|"DOC_CODVETT2"|"DOC_CODVETT3, DOC_CODINDSP, DOC_CODCMS, NULL }; for (int u = 0; cond[u]; u++) if (doc_uguale(u)) campi.add(cond[u]); } bool TFatturazione_bolle::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; return doc_in.raggruppabile(doc_out, campi); } void TFatturazione_bolle::create_row(TDocumento& doc_out, const TRiga_documento& rin) { TRiga_documento& rout = doc_out.new_row(); // ... crea una riga nuova e doc_out.copy_data(rout, rin); // copiaci tutti i campi della riga sorgente. rout.set_original_rdoc_key(rin); // memorizza il codice della riga originale if (usa_data_consegna()) { rout.zero(RDOC_QTAEVASA); rout.zero(RDOC_RIGAEVASA); } if (kill_descrizione_estesa()) // Cancello eventualmente la descrizione estesa { rout.zero(RDOC_DESCLUNGA); rout.zero(RDOC_DESCEST); } if (prezzo_da_ordine()) // Se devo copiare il prezzo originale all'ordine { const TRectype* row_ord = rin.find_original_rdoc(); if (row_ord != NULL) { const real ord_price = row_ord->get_real(RDOC_PREZZO); const TString& ord_scont = row_ord->get(RDOC_SCONTO); rout.put(RDOC_PREZZO, ord_price); rout.put(RDOC_SCONTO, ord_scont); } } } void TFatturazione_bolle::elabora_riga(TRiga_documento& r, TDocumento& doc_out, bool usa_dcons, bool ragg_rig, bool ignora_desc, TToken_string & campi_riga, const TDate & dcons, const TDate & ddoc) { const bool rindesc = r.sola_descrizione(); // La riga di input e' descrittiva if (ignora_desc && rindesc) return; TRiga_documento rin(r); if (rin.is_attrezzatura() || rin.is_risorsa()) rin.cost2revenue(); const bool delete_spese_aut = r.doc().tipo().spese_aut() && doc_out.rows() > 0; if (delete_spese_aut) { if (rin.is_generata() && rin.get("GENTIPO").empty() && rin.is_spese()) { const TSpesa_prest& sp = rin.spesa(); if (sp.tipo() == 'P') return; } } //if(delete_spese_aut).. if (usa_dcons) { TDate data_cons = rin.get(RDOC_DATACONS); if (!data_cons.ok()) data_cons = dcons; if (ddoc < data_cons || rin.get_bool(RDOC_RIGAEVASA)) return; const real q = rin.get(RDOC_QTA); r.put(RDOC_QTAEVASA, q); r.put(RDOC_RIGAEVASA, true); } bool elaborata = false; // Raggruppo le righe se e' settato il flag di raggruppamento e // se la riga non contiene solo una descrizione if (ragg_rig && !rindesc && da_raggruppare(rin)) // Se devo raggruppare le righe ... { FOR_EACH_PHYSICAL_RDOC(doc_out, r, rout) // ... cerca una riga compatibile { if (rout->sola_descrizione()) // Ignora le righe descrittive continue; if (rin.raggruppabile(*rout, campi_riga)) // Se esiste una riga compatibile ... { add_rows(*rout, rin); elaborata = true; // Ricorda di averla gia' elaborata break; } } } if (!elaborata) // Se la riga non e' stata gia' sommata ... create_row(doc_out, rin); } bool TFatturazione_bolle::raggruppa(TDocumento& doc_in, TDocumento& doc_out) { #ifdef DBG const TString4 tipodoc = doc_in.tipo().codice(); int i; for (i = 0; i < TElaborazione::_max_tipi_doc_elab; i++) { if (tipodoc == tipo_iniziale(i)) break; } if (i >= TElaborazione::_max_tipi_doc_elab) { NFCHECK("Tipo documento non valido: '%s'", (const char*)tipodoc); return true; } #endif const TDate dcons = doc_in.get_date(DOC_DATACONS); const TDate ddoc = doc_out.get_date(DOC_DATADOC); const bool usa_dcons = usa_data_consegna(); const int doc_out_rows = doc_out.physical_rows(); if (usa_dcons) { bool da_elaborare = FALSE; FOR_EACH_PHYSICAL_RDOC(doc_in, r, rin) { TDate data_cons = rin->get_date(RDOC_DATACONS); if (!data_cons.ok()) data_cons = dcons; da_elaborare = ddoc >= data_cons && !rin->get_bool(RDOC_RIGAEVASA); } if (!da_elaborare) return FALSE; } if (gestione_riferimenti()) { if (change_clifo()) { const int indsped = doc_in.get_int(DOC_CODINDSP); if (indsped > 0) { const char t = doc_in.get_char(DOC_TIPOCFFATT); const long codcf = doc_in.get_long(DOC_CODCFFATT); TString16 kis; kis << t << '|' << codcf << '|' << indsped; const TString& dest = cache().get(LF_INDSP, kis, IND_RAGSOC); if (dest.full()) // crea una riga descrizione nuova per indirizzo di spedizione valido { TRiga_documento& rout = doc_out.new_row(); rout.forza_sola_descrizione(); rout.put(RDOC_DESCR, dest); } } //if(indsped)... } //if(change_clifo)... // Determina ed eventualmente crea la riga di riferimento const bool rif_testa = riferimenti_in_testa(); const bool rif_packed = pack_rif(); const int riga_rif = rif_testa ? 1 : doc_out.physical_rows()+1; if (riga_rif > doc_out.physical_rows()) { TRiga_documento& rout = doc_out.new_row(); rout.forza_sola_descrizione(); } TRiga_documento& rout = doc_out[riga_rif]; // Costruisce la stringa di riferimento TString riferimento; if (!rif_testa || !rif_packed || doc_out_rows == 0) { doc_in.riferimento(riferimento); if (riferimento.empty()) riferimento = doc_in.tipo().descrizione(); if (riferimento.full()) riferimento << ' '; } if (usa_doc_rif() && doc_in.get(DOC_NUMDOCRIF).not_empty()) { riferimento << "n. " << doc_in.get(DOC_NUMDOCRIF); if (rif_packed) riferimento << ' ' << doc_in.get_date(DOC_DATADOCRIF).string(brief); else riferimento << " del " << doc_in.get(DOC_DATADOCRIF); } else { riferimento << " n. " << doc_in.numero(); if (rif_packed) riferimento << ' ' << doc_in.data().string(brief); else riferimento << " del " << doc_in.data().string(); } // Setta la descrizione se vuota if (rif_packed) { TString memo(1024); memo = rout.get(RDOC_DESCR); if (rout.get_bool(RDOC_DESCLUNGA)) memo << rout.get(RDOC_DESCEST); if (riferimento.full()) { if (memo.full()) memo << " - "; memo << riferimento; } const int maxlen = rout.length(RDOC_DESCR); if (memo.len() < maxlen) rout.put(RDOC_DESCR, memo); else { rout.put(RDOC_DESCR, memo.left(maxlen)); rout.put(RDOC_DESCEST, memo.mid(maxlen)); rout.put(RDOC_DESCLUNGA, true); } } else //else if(rif_packed)... { if (rout.get(RDOC_DESCR).empty()) rout.put(RDOC_DESCR, riferimento); else { // Altrimenti aggiungi il riferimento al memo TString memo(1024); memo = rout.get(RDOC_DESCEST); memo.rtrim(); memo << '\n' << riferimento; rout.put(RDOC_DESCEST, memo); rout.put(RDOC_DESCLUNGA, "X"); } } //if(rif_packed).. } //if(gestione_riferimenti)... const bool ignora_desc = ignora_descrizioni() && !doc_in.clifor().vendite().get_bool(CFV_RIFDOC); TToken_string campi_riga(80); campi_raggruppamento_righe(campi_riga); const bool ragg_rig = campi_riga.full(); FOR_EACH_PHYSICAL_RDOC(doc_in, r, rin) elabora_riga(*rin, doc_out, usa_dcons, ragg_rig, ignora_desc, campi_riga, dcons, ddoc); //cambio stato documento bool cambia_stato_doc_in = true; if (usa_dcons) { FOR_EACH_PHYSICAL_RDOC(doc_in, r, rin) { if (!rin->sola_descrizione() && !rin->get_bool(RDOC_RIGAEVASA)) // Perche' non rin->is_evasa() { cambia_stato_doc_in = false; break; } } } if (cambia_stato_doc_in) { const char stato_finale_in = get_char("S4"); doc_in.stato(stato_finale_in); } const char stato_finale_out = get_char("S9"); doc_out.stato(stato_finale_out); if (usa_dcons) doc_in.rewrite(); return true; } bool TFatturazione_bolle::elabora(TLista_documenti& doc_in, TLista_documenti& doc_out, const TDate& data_elab, bool interattivo) { TWait_cursor hourglass; TBit_array closed; TArray docrefs; TToken_string campi_doc(128); // Lista di campi che devono essere uguali campi_raggruppamento(campi_doc); pre_process_input(doc_in); for (int id = 0; id < doc_in.items(); id++) { TDocumento& campione = doc_in[id]; const char orig_t = campione.get_char(DOC_TIPOCF); const long orig_cod = campione.get_long(DOC_CODCF); if (change_clifo()) { const char t = campione.get_char(DOC_TIPOCFFATT); const long codcf = campione.get_long(DOC_CODCFFATT); if (t > ' ') { campione.put(DOC_TIPOCF, t); if (interattivo) doc_out[0].put(DOC_TIPOCF, t); } if (codcf > 0L) { campione.put(DOC_CODCF, codcf); if (interattivo) doc_out[0].put(DOC_CODCF, codcf); } } if (_lista_campi.full()) { const TCli_for& cf = campione.clifor(true); TToken_string s("", '='); for (s = _lista_campi.get(0); s.full(); s = _lista_campi.get()) { const TString16 oname = s.get(); TString16 iname = s.get(); if (oname == RDOC_CODIVA) { const TString4 codesiva = campione.codesiva(); FOR_EACH_PHYSICAL_RDOC(campione, i, rdoc) { // Elabora solo righe articolo, spese o prestazioni valide if (!rdoc->is_descrizione()) { if (codesiva.full()) { if (rdoc->imponibile().is_zero()) rdoc->zero(RDOC_CODIVA); else rdoc->put(RDOC_CODIVA, codesiva); } else { if (rdoc->is_articolo()) { const TArticolo_giacenza& art = rdoc->articolo(); const TString& codiva = art.get(ANAMAG_CODIVA); if (codiva.full()) rdoc->put(RDOC_CODIVA, codiva); } else if ((rdoc->is_spese() || rdoc->is_prestazione())) { const TSpesa_prest& s = rdoc->spesa(); const TString& codiva = s.cod_iva(); if (codiva.full()) rdoc->put(RDOC_CODIVA, codiva); } } } } } else { if (iname.starts_with("17.") || iname.starts_with("CFVEN.")) { const TString& sfld = iname.after('.'); const TString& sval = cf.vendite().get(sfld); campione.put(oname, sval); } else { if (iname.blank()) iname = oname; campione.put(oname, cf.get(iname)); } } } } campione.set_riga_esenzione(); const int tot = doc_out.items(); int od = tot; if (interattivo) { od = 0; const char tipo = campione.get_char(DOC_TIPOCF); const long codice = campione.get_long(DOC_CODCF); TDocumento & out = doc_out[od]; if (tipo != out.get_char(DOC_TIPOCF) || codice != out.get_long(DOC_CODCF)) return error_box("Documenti incompatibili: cliente/fornitore diverso"); const TString4 codnum(out.get(DOC_CODNUM)); if (cached_numerazione(codnum).num_provv()) out.put(DOC_PROVV, 'P'); } else { if (doc_raggruppabile(campione)) // Se il documento ha il flag di raggruppabilita' ... { for (od = 0; od < tot; od++) // ... cerca un documento compatibile. { if (!closed[od]) { const int in_rows = campione.rows(); const int out_rows = doc_out[od].rows(); if (in_rows + out_rows > 990) closed.set(od); else { if (doc_raggruppabili(campione, doc_out[od], campi_doc)) break; } } } } } if (od >= tot) // Se non ho trovato un documento compatibile ... { // ... creane uno nuovo (certamente compatibile) const int anno = data_elab.year(); const TString4 codnum(campione.get(DOC_CODNUM)); const TString4 tipo_out(get("S8")); // Tipo del documento di output char provv = 'D'; if (cached_numerazione(codice_numerazione_finale()).num_provv()) provv = 'P'; TDocumento* new_doc = new TDocumento(provv, anno, codnum, -1); // Attenzione! Il cambio del tipo documento provocherebbe il reset delle variabili // Per cui lo scrivo temporaneamente nel tipo del documento d'ingresso // TRecfield td(campione, DOC_TIPODOC); // Uso il TRecfield per scavalcare tutti gli automatismi // const TString16 old_tipo_in = td; // Salvo il vecchio tipo // td = tipo_out; // Setto il nuovo TDocumento::copy_data(new_doc->head(), campione.head()); // Copio la testata // td = old_tipo_in; // Ripristino il vecchio new_doc->zero(DOC_SPESEUPD); // Senno' non aggiorna le spese automatiche new_doc->put(DOC_DATADOC, data_elab); // Aggiungilo alla lista dei documenti in uscita od = doc_out.add(new_doc); new_doc->put("FATID", od + 1); } if (change_clifo()) { campione.put(DOC_TIPOCF, orig_t); campione.put(DOC_CODCF, orig_cod); } if ((!raggruppa(campione, doc_out[od]) && doc_out[od].physical_rows() == 0)) doc_out.destroy(od); else doc_out[od].set_riga_esenzione(); TBit_array * row = (TBit_array *) docrefs.objptr(od); if (row == NULL) { row = new TBit_array; docrefs.add(row, od); } row->set(id); } post_process_input(doc_in); const int tot = doc_out.items(); const TString4 codnum(codice_numerazione_finale()); real impminfat; if (!interattivo && tot > 0) { impminfat = doc_out[0].clifor().vendite().get_real(CFV_IMPMINFAT); if (impminfat == ZERO) impminfat = _impminfat; } for (int i = tot - 1; i >=0; i--) // Forza tipo e numerazione documento. { TDocumento& d = doc_out[i]; d.put(DOC_CODNUM, codnum); TToken_string key; key.add(d.get(DOC_TIPOCF)); key.add(d.get(DOC_CODCF)); const TRectype & cfven = cache().get(LF_CFVEN, key); const TString4 tipo_cli(cfven.get(CFV_TIPODOCFAT)); const TString& tipo_out = get_tipo_out(d); // Tipo del documento di output TRecfield td(d, DOC_TIPODOC); // Uso il TRecfield per scavalcare tutti gli automatismi td = tipo_cli.empty() ? tipo_out : tipo_cli; const TString& sconto = d.get(DOC_SCONTOPERC); d.put(DOC_SCONTOPERC, sconto); if (change_clifo()) { const TString4 tipodoc(d.tipo().codice()); TDocumento_mask m(tipodoc); if (reload_prices()) { FOR_EACH_PHYSICAL_RDOC_BACK(d, r, rdoc) rdoc->zero(RDOC_CHECKED); } m.doc() = d; m.doc2mask(true, true); m.mask2doc(); d = m.doc(); } if (_rowsort.full()) d.sort_rows(_rowsort); } post_process(doc_out, doc_in); for (int i = doc_out.items() - 1; i >=0; i--) { TDocumento& d = doc_out[i]; if (!interattivo && impminfat > ZERO && d.totale_doc() <= impminfat) { doc_out.destroy(i); TBit_array & row = (TBit_array &) docrefs[i]; for (int j = row.last_one(); j >= row.first_one(); j--) if (row[j]) doc_in.destroy(j); docrefs.destroy(i); } else d.put("FATID", 0); } for (int i = doc_out.items() - 1; i >= 0; i--) // Aggiorna esenzione { TDocumento& d = doc_out[i]; d.update_esenzione(); } return doc_out.items() > 0; }