// mg1400.cpp : Chiusura/Apertura esercizi di magazzino #include #include #include #include #include #include #include "mglib.h" #include "../cg/cglib01.h" #include "../ve/veconf.h" #include "mg1400.h" #include "movmag.h" #define MAX_ROWS 500 enum action { provvisoria, definitiva }; class TApp_openclose; class TMask_openclose: public TMask { bool _ordaut; TEsercizi_contabili _esercizi; bool _gestione_listini; bool _gestione_condv; protected: static bool handle_close(TMask_field &, KEY); static bool handle_open(TMask_field &, KEY); static void common_handler(TMask_field &); static bool handle_what(TMask_field &, KEY); static bool handle_val(TMask_field &, KEY); public: TEsercizi_contabili& exercise() { return (TEsercizi_contabili&)_esercizi; } TMask_openclose(const bool ord) ; virtual ~TMask_openclose() {} }; TMask_openclose::TMask_openclose(const bool ord) : TMask("mg1400") { _ordaut = ord; if (_ordaut) disable(-1); set_handler(F_DATECLOSE, handle_close); set_handler(F_DATEOPEN, handle_open); set_handler(F_WHAT, handle_what); set_handler(F_VALORIZZAZIONE, handle_val); TConfig cfg(CONFIG_DITTA, "ve"); _gestione_listini = cfg.get_bool("GES", NULL, A_LISTINI); _gestione_condv = _gestione_listini && cfg.get_bool("GESLISCV"); } bool TMask_openclose::handle_close(TMask_field &fld, KEY k) { TMask_openclose& mask = (TMask_openclose&)fld.mask(); if (k == K_ENTER || fld.to_check(k)) { TEsercizi_contabili& ex = mask.exercise(); TDate d(fld.get()); const int es_close = ex.date2esc(d); mask.set(F_ESTOCLOSE, es_close); if (es_close == 0) return fld.error_box(TR("La data indicata non appartiene a nessun esercizio.")); if (k == K_ENTER && ex.esercizio(es_close).chiusura_mag() != TDate(NULLDATE)) return fld.error_box(FR("L'esercizio %d risulta gia' chiuso. Selezionare" " un altro esercizio o togliere la data di chiusura."), es_close); else { int pred = ex.pred(es_close); if (k == K_ENTER && pred != 0 && ex.esercizio(pred).chiusura_mag() == TDate(NULLDATE)) return fld.error_box(TR("L'esercizio precedente a quello indicato non e' ancora stato chiuso.")); } } return TRUE; } bool TMask_openclose::handle_open(TMask_field &fld, KEY k) { TMask_openclose& mask = (TMask_openclose&)fld.mask(); if (k == K_ENTER || fld.to_check(k)) { TDate in(mask.get(F_DATEOPEN)); TDate fi(mask.get(F_DATECLOSE)); if (k == K_ENTER && in <= fi ) return fld.warning_box (TR("La data di apertura del nuovo esercizio deve essere superiore alla data di chiusura dell'esercizio precedente")); const int es_open = mask.exercise().date2esc(in); mask.set(F_ESTOOPEN, es_open); if (es_open == 0) return fld.error_box(TR("La data indicata non appartiene a nessun esercizio")); const int es_close = mask.exercise().pred(es_open); if (es_close == 0) return fld.error_box(TR("Non esiste l'esercizio precedente per la data indicata.")); // Setta data ed esercizio di chiusura mask.set(F_ESTOCLOSE,es_close); mask.set(F_DATECLOSE, mask.exercise().esercizio(es_close).fine()); } return TRUE; } void TMask_openclose::common_handler(TMask_field &fld) { TMask_openclose& mask = (TMask_openclose&)fld.mask(); const action w = (action) mask.get_int(F_WHAT); const TTipo_valorizz t = (TTipo_valorizz) mask.get_int(F_VALORIZZAZIONE); const bool eb = w == definitiva && t >= valorizz_FIFOa; if (w == provvisoria) // Se oper. provv. disabilita tutte le causali { mask.disable(-6); mask.reset(-6); } else { mask.enable(-6); mask.enable(-5, eb); mask.enable(-4, !eb); // Le causali degli ordini sono abilitate solo se NON c'e' il modulo ordini if (mask._ordaut) mask.disable(-1); if (eb) mask.reset(-4); else mask.reset(-5); } if (mask.field(F_LIST).shown()) { mask.enable(F_LIST, mask._gestione_listini); mask.enable(F_CATVEN, mask._gestione_condv); } } bool TMask_openclose::handle_what(TMask_field &fld, KEY k) { if (k == K_SPACE) common_handler(fld); return TRUE; } bool TMask_openclose::handle_val(TMask_field &fld, KEY k) { if (fld.to_check(k)) common_handler(fld); return TRUE; } // Corrispondenza elementi di _movimenti: #define CAUS_A_RIMIN 0 // movimento con causale di rimanenze iniziali #define CAUS_A_INCL 1 // " " " In conto lav. #define CAUS_A_ACL 2 // " " " A conto lav. #define CAUS_A_INPRF 3 // " " " In prod. fin. #define CAUS_A_INPRC 4 // " " " In prod. comp. #define CAUS_A_ORDF 5 // " " " Ordinato fornitori #define CAUS_A_ORDC 6 // " " " Ordinato clienti #define CAUS_A_QTA 7 // " " " Movimentazione solo quantità #define CAUS_A_VAL 8 // " " " Movimentazione solo valore // Elemento 9 e successivi: tutte le righe in eccesso a MAX_ROWS // CAUS_A_QTA e CAUS_A_VAL vengono utilizzate solo se la chiusura è definitiva e la // valorizzazione impostata è FIFO/LIFO class TApp_openclose : public TSkeleton_application { TMask_openclose *_msk; TArray _movimenti; // Array di movimenti di TMov_mag TString_array _causali; // Array delle causali per i movimenti d'apertura (7) TString _es_to_close; TString _es_to_open; TString _catven; TString _codlis; TDate _date_to_close; TDate _date_to_open; action _what; bool _valorizza_comp; TTipo_valorizz _calctype; protected: virtual bool create(); virtual bool destroy(); virtual void main_loop(); //void scrivi_movimenti(TCursor&); //void aggiorna_saldi(); void compila_movimento(TMov_mag& currmov, TArticolo_giacenza& art, TRectype& rec, const int caus); void chiudi_esercizio(); public: TApp_openclose() {}; virtual ~TApp_openclose() {}; }; bool TApp_openclose::create() { TConfig c(CONFIG_DITTA); open_files(LF_ANAMAG, LF_UMART, LF_MAG, LF_MOVMAG, LF_RMOVMAG, LF_STOMAG, 0); _msk = new TMask_openclose(!c.get_bool("RIPORD")); return TSkeleton_application::create(); } bool TApp_openclose::destroy() { delete _msk; return TSkeleton_application::destroy(); } void TApp_openclose::compila_movimento(TMov_mag& currmov, TArticolo_giacenza& art, TRectype& rec, const int caus) { // Aggiorna la testata se il movimento e' nuovo (non ha righe) if (currmov.rows() == 0) { TRectype& head = currmov.head(); head.put(MOVMAG_ANNOES, _es_to_open); head.put(MOVMAG_DATAREG, _date_to_open); head.put(MOVMAG_DATACOMP, _date_to_open); head.put(MOVMAG_CODCAUS, _causali.row(caus)); } // Currency delle mie brame... TCurrency currency; // Aggiunge una nuova riga al movimento corrente TString codmagdep(rec.get(MAG_CODMAG)); TString codmag(codmagdep);codmag.cut(3); TString codart(rec.get(MAG_CODART)); TString livello(rec.get(MAG_LIVELLO)); real qta, prezzo, val; // switch sul tipo di causale per settare quantita' e prezzo: switch (caus) { case CAUS_A_RIMIN: // Rimanenze iniziali case CAUS_A_QTA: // Movimentazione solo quantità case CAUS_A_VAL: // Movimentazione solo valore { qta = rec.get_real(MAG_GIAC) + rec.get_real(MAG_ACL) - rec.get_real(MAG_INCL); // ??corretta da AcL, IncL e InProdF ?? if (!_valorizza_comp) qta += rec.get_real(MAG_PRODFIN)-rec.get_real(MAG_PRODCOMP); if (caus != CAUS_A_QTA) { switch (_calctype) { case valorizz_costmediopond: val = art.costo_mediopond(_es_to_close, codmag, livello); break; case valorizz_costmedio: val = art.costo_medio(_es_to_close, codmag, livello); break; case valorizz_ultcos: val = art.ultimo_costo(_es_to_close); break; case valorizz_mediacos: val = art.media_costi(_es_to_close); break; case valorizz_przlist: val = art.prezzo_listino(_es_to_close, _catven, _codlis); break; case valorizz_coststd: val = art.costo_standard(_es_to_close); break; case valorizz_LIFOa: val = art.LIFO_annuale(_es_to_close, codmag, livello); break; case valorizz_FIFOa: val = art.FIFO_annuale(_es_to_close, codmag, livello); break; case valorizz_LIFO: val = art.LIFO(_es_to_close, codmag, livello); break; case valorizz_FIFO: val = art.FIFO(_es_to_close, codmag, livello); break; case valorizz_LIFOr: val = art.LIFO_ragionieristico(_es_to_close, codmag, livello); break; case valorizz_FIFOr: val = art.FIFO_ragionieristico(_es_to_close, codmag, livello); break; default: break; } } if (caus == CAUS_A_RIMIN) prezzo = val; else if (caus == CAUS_A_VAL) { prezzo = val * qta; qta = ZERO; }// Per CAUS_A_QTA prezzo rimane a ZERO } break; case CAUS_A_INCL: // In conto lav. qta = rec.get_real(MAG_INCL); break; case CAUS_A_ACL: // A conto lav. qta = rec.get_real(MAG_ACL); break; case CAUS_A_INPRF: // In prod. fin. qta = rec.get_real(MAG_PRODFIN); break; case CAUS_A_INPRC: // In prod. com. qta = rec.get_real(MAG_PRODCOMP); break; case CAUS_A_ORDF: // Ord. forn. qta = rec.get_real(MAG_ORDF); val = rec.get_real(MAG_VALORDF); prezzo = val/qta; break; case CAUS_A_ORDC: // Ord. cli. qta = rec.get_real(MAG_ORDC); val = rec.get_real(MAG_VALORDC); prezzo = val/qta; break; default: break; } if (qta != 0.0 || (caus == CAUS_A_VAL && prezzo != ZERO)) { TRectype& riga = currmov.new_row(); TRecord_array& ums = art.um(); const int r = ums.first_row(); if (r > 0) riga.put(RMOVMAG_UM, (ums[r]).get(UMART_UM)); riga.put(RMOVMAG_CODMAG, codmagdep); riga.put(RMOVMAG_CODART, codart); riga.put(RMOVMAG_LIVGIAC, livello); // La causale di riga va messa solo se e' diversa da quella di testata! riga.put(RMOVMAG_QUANT, qta); // Setta il prezzo al nr di decimali impostati per la valuta corrente currency.set_price(caus == CAUS_A_VAL ? FALSE : TRUE); // Se mov. solo valore (FIFO/LIFO) i decimali devono essere per gl'importi currency.set_num(prezzo); riga.put(RMOVMAG_PREZZO, currency); } } // Chiude l'esercizio selezionato (in base al flag lo fa provvisoriamente o definitivamente) // L'unica differenza sta nella creazione dei movimenti d'apertura nel caso di chiusura definitiva void TApp_openclose::chiudi_esercizio() { TRelation rel(LF_ANAMAG); TCursor cur(&rel); rel.lfile().set_curr(new TArticolo_giacenza()); // setta il Multirec come current della relazione TString descr1, descr2, codmag; int err = NOERR; TTable esc("ESC"); TTable magazzini("MAG"); // rebuild_balances(_es_to_close); // Cosi' ci assicuriamo che i saldi dell'esercizio vecchio siano a posto descr1.format(_what == definitiva ? FR("Apertura esercizio %s") : FR("Aggiornamento saldi esercizio %s"), (const char*) _es_to_open); descr2 << descr1 << TR(" in corso..."); // cose specifiche per chiusura definitiva... // Reperisce l'ultimo movimento di magazzino per il numero di registrazione TLocalisamfile movmag(LF_MOVMAG); movmag.last(); long numreg = movmag.get_long(MOVMAG_NUMREG) +1; // Indici per i movimenti. Crea i movimenti di base (uno per ogni causale) int indici[9], last = 8; if (_what == definitiva) { for (int j = 0; j < 9; j++) { _movimenti.add(new TMov_mag); TRectype& h = ((TMov_mag&) _movimenti[j]).head(); h.put(MOVMAG_NUMREG, numreg++); h.put(MOVMAG_DESCR, descr1); indici[j] = j; } const long max_art = cur.items(); cur.freeze(); TProgind *prog = new TProgind(max_art, descr2, FALSE, TRUE); // Ciclo per i fottuti articoli for (cur = 0L; cur.pos() < max_art; ++cur) { // Scorre i saldi del vecchio esercizio per questo TArticolo_giacenza // compilando un array di almeno 9 TMov_mag // Almeno 9 perche' 9 sono le causali; fissiamo il limite di righe per movimento a 500 (MAXROWS) // quindi i movimenti possono essere di piu'. // Caso particolare da notare: nel caso di valorizzazione LIFO/FIFO in realtà i movimenti // Sono sempre e solo 2, uno movimenta solo la qta ed uno solo il valore, in modo da far // tornare i cosiddetti conti // I saldi per questo articolo TArticolo_giacenza& art = (TArticolo_giacenza&)cur.curr(); TRecord_array& rec_arr = art.mag(_es_to_close); // Scorriamo le righe... const int lastrow = rec_arr.last_row(); for (int r = lastrow; r > 0; r = rec_arr.pred_row(r)) { TRectype& rec = rec_arr[r]; for (int i = 0; i < 9; i++) { if (_causali.row(i).empty()) continue; // Salta eventuali causali vuote // se il numero di righe di questo movimento eccede le 500 ne crea uno nuovo e // setta il nuovo indice const int rows = ((TMov_mag&) _movimenti[indici[i]]).rows() ; if (rows > MAX_ROWS) { _movimenti.add(new TMov_mag); last++; indici[i] = last; TRectype& h = ((TMov_mag&) _movimenti[last]).head(); h.put(MOVMAG_NUMREG, numreg++); // Aggiorna il nr. reg per il prossimo movimento h.put(MOVMAG_DESCR, descr1); } TMov_mag& currmov = (TMov_mag&) _movimenti[indici[i]]; compila_movimento(currmov, art, rec, i); } } // Aggiornamento storico // Zappa eventuali record già presenti. art.storico(_es_to_open).destroy_rows(); // Ricostruisce lo storico per ogni magazzino possibile for (magazzini.first(); !magazzini.eof(); magazzini.next()) { codmag = magazzini.get("CODTAB"); if (codmag.len() > 3) continue; // Salta i depositi switch (_calctype) { case valorizz_LIFO: art.agg_storicoLIFO(_es_to_close, codmag, TRUE, _valorizza_comp); break; case valorizz_FIFO: art.agg_storicoFIFO(_es_to_close, codmag, TRUE, _valorizza_comp); break; default: { real val; switch (_calctype) { case valorizz_costmediopond: val = art.costo_mediopond(_es_to_close, codmag, ""); break; case valorizz_costmedio: val = art.costo_medio(_es_to_close, codmag, ""); break; case valorizz_ultcos: val = art.ultimo_costo(_es_to_close); break; case valorizz_mediacos: val = art.media_costi(_es_to_close); break; case valorizz_przlist: val = art.prezzo_listino(_es_to_close, _catven, _codlis); break; case valorizz_coststd: val = art.costo_standard(_es_to_close); break; case valorizz_LIFOa: val = art.LIFO_annuale(_es_to_close, codmag, ""); break; case valorizz_FIFOa: val = art.FIFO_annuale(_es_to_close, codmag, ""); break; default: break; } if (val != ZERO) art.agg_storico(_es_to_close, codmag, TRUE, _valorizza_comp, val); break; } } } prog->addstatus(1L); } delete prog; // ************** // Effettua la scrittura dei movimenti di apertura generati const int max_mov = _movimenti.items(); prog = new TProgind(max_mov, TR("Scrittura movimenti di apertura in corso..."),FALSE,TRUE); for (int i=0; err == NOERR && iaddstatus(1L); TMov_mag& mov = (TMov_mag&) _movimenti[i]; if (mov.rows() == 0) continue; // Salta eventuali movimenti senza righe (OrdC e OrdF) // Effettua la rinumerazione del movimento se esso esiste gia'? err = mov.write(movmag); } delete prog; // ************** // chiude l'esercizio if (err == NOERR) { // Marca l'esercizio come chiuso esc.put("CODTAB", _es_to_close); err = esc.read(); if (err == NOERR) { esc.put("D4", _date_to_close); err = esc.rewrite(); if (err != NOERR) error_box(FR("Errore %d in fase di chiusura esercizio %s."), err, (const char*) _es_to_close); } else error_box(FR("Errore %d in fase di lettura esercizio %s."), err, (const char*) _es_to_close); } else error_box(FR("Errore %d durante la scrittura dei movimenti."),err); _movimenti.destroy(); } // A questo punto l'esercizio vecchio e' marcato come chiuso in base al tipo di chiusura // (definitiva o provvisoria); La ricostruzione dei saldi e' comune in entrambi i casi: // la rebuild_balances() deve sapere da sola se azzerare o meno le giacenze // a seconda che l'esercizio precedente sia chiuso (AZZERA) o no (NON AZZERARE). rebuild_balances(_es_to_open, _calctype, _catven, _codlis); } void TApp_openclose::main_loop() { //Preimposta valori di apertura e chiusura esercizio TDate d(TODAY); TEsercizi_contabili& ex = _msk->exercise(); const int es_open = ex.date2esc(d); if (es_open != 0) { _msk->set(F_DATEOPEN,ex.esercizio(es_open).inizio()); _msk->set(F_ESTOOPEN,es_open); } const int es_close = ex.pred(es_open); if (es_close != 0) { _msk->set(F_DATECLOSE,ex.esercizio(es_close).fine()); _msk->set(F_ESTOCLOSE,es_close); } while (_msk->run() == K_ENTER) { // Here is _causali.destroy(); _date_to_close = _msk->get_date(F_DATECLOSE); _date_to_open = _msk->get_date(F_DATEOPEN); _es_to_close = _msk->get(F_ESTOCLOSE); _es_to_open = _msk->get(F_ESTOOPEN); _calctype = (TTipo_valorizz) _msk->get_int(F_VALORIZZAZIONE); _what = (action) _msk->get_int(F_WHAT); //Provvisoria o definitiva? _valorizza_comp= _msk->get(F_VALCOMP)=="C"; //Valorizza i componenti o i finiti _codlis = _msk->get(F_LIST); _catven = _msk->get(F_CATVEN); for (short xx = F_CAURIM; xx <= F_CAUVAL; xx++) // legge le causali impostate _causali.add(_msk->get(xx)); chiudi_esercizio(); // Chiusura esercizio } } int mg1400(int argc, char* argv[]) { TApp_openclose a; a.run(argc, argv, TR("Apertura/Chiusura esercizio")); return 0; }