// mg1400.cpp : Chiusura/Apertura esercizi di magazzino #include #include #include #include #include #include #include "mglib.h" #include "..\cg\cglib01.h" #include "mg1400.h" #include "movmag.h" #define MAX_ROWS 500 enum action { provvisoria, definitiva }; enum method { costomedio, ultimocosto, mediacosti, prezzolistino, prezzostd, lifoannuale, fifoannuale, liforagionieristico, fiforagionieristico }; class TMask_openclose: public TMask { TEsercizi_contabili esercizi; static bool handle_close(TMask_field &, KEY); static bool handle_open(TMask_field &, KEY); public: TEsercizi_contabili& exercise() { return (TEsercizi_contabili&) esercizi; } TMask_openclose(); virtual ~TMask_openclose() {} }; TMask_openclose::TMask_openclose() : TMask("mg1400") { set_handler(F_DATECLOSE, handle_close); set_handler(F_DATEOPEN, handle_open); } 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.esercizi; TDate d(fld.get()); const int es_close = ex.date2esc(d); if (es_close == 0) return fld.error_box("La data indicata non appartiene a nessun esercizio."); if (k == K_ENTER && ex.esercizio(es_close).chiusura_mag() != TDate(NULLDATE)) return fld.error_box("L'esercizio risulta gia' chiuso. Selezionare" " un altro esercizio o togliere il flag di chiusura."); else { int pred = ex.pred(es_close); if (k == K_ENTER && pred != 0 && ex.esercizio(pred).chiusura_mag() == TDate(NULLDATE)) return fld.error_box("L'esercizio precedente a quello indicato non e' ancora stato chiuso."); } mask.set(F_ESTOCLOSE, es_close); } 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 ("La data di inizio del nuovo esercizio deve essere superiore alla data di fine esercizio precedente"); const int es_open = mask.esercizi.date2esc(in); if (es_open == 0) return fld.error_box("La data indicata non appartiene a nessun esercizio"); mask.set(F_ESTOOPEN, es_open); const int es_close = mask.esercizi.pred(es_open); if (es_close == 0) return fld.error_box("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.esercizi.esercizio(es_close).fine()); } return TRUE; } class TApp_openclose : public TSkeleton_application { TLocalisamfile *_anamag, *_mag, *_movmag, *_rmovmag, *_stomag; 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; TDate _date_to_close; TDate _date_to_open; action _what; method _calctype; protected: virtual bool create(); virtual bool destroy(); virtual void main_loop(); void scrivi_movimenti(); void chiudi_esercizio(); public: TApp_openclose(action w) { _what = w; }; virtual ~TApp_openclose() {}; }; bool TApp_openclose::create() { _msk = new TMask_openclose; _msk->set_caption(_what == definitiva ? "Chiusura definitiva esercizio" : "Chiusura provvisoria esercizio"); if (has_module(ORAUT)) _msk->disable(-1); // Se il modulo ordini e' abilitato disabilita l'inserimento delle rispettive causali d'apertura _anamag = new TLocalisamfile(LF_ANAMAG); _mag = new TLocalisamfile(LF_MAG); _movmag = new TLocalisamfile(LF_MOVMAG); _rmovmag = new TLocalisamfile(LF_RMOVMAG); _stomag = new TLocalisamfile(LF_RMOVMAG); return TSkeleton_application::create(); } bool TApp_openclose::destroy() { delete _msk; delete _anamag; delete _mag; delete _movmag; delete _rmovmag; delete _stomag; return TSkeleton_application::destroy(); } void TApp_openclose::scrivi_movimenti() { // Scorre i saldi del vecchio esercizio, compilando un array di almeno 7 TMov_mag // Almeno 7 perche' fissiamo il limite di righe per movimento a 500 TRelation saldi_rel(_mag); TRectype rec_from(LF_MAG), rec_to(LF_MAG); rec_from.put(MAG_ANNOES, _es_to_close); rec_to = rec_from; TCursor saldi_cur(&saldi_rel,"",2,&rec_from,&rec_to); // Repersice l'ultimo movimento di magazzino per il numero di registrazione _movmag->last(); long numreg = _movmag->get_long(MOVMAG_NUMREG) +1; // La chiave 1 dei saldi di magazzino e' anno esercizio+codice articolo+numero riga // Mi chiedo : che ci faccio col numero riga? Raggruppo o creo un'altra riga per quel // movimento? // Corrispondenza elementi: /* elemento 0 : movimento con causale di rimanenze iniziali elemento 1 : " " " In conto lav. elemento 2 : " " " A conto lav. elemento 3 : " " " In prod. fin. elemento 4 : " " " In prod. comp. elemento 5 : " " " Ordinato fornitori elemento 6 : " " " Ordinato clienti */ real val,qta,prezzo; TString descrizione, codmag, codart, livello, catven, codlis; // Richiede in input catven, codlist... per valorizzazione prezzo di listino descrizione.format("Apertura esercizio %s", (const char*)_es_to_open); // Indici per i movimenti. Crea i movimenti di base (uno per ogni causale) int indici[7]; int last = 6; for (int j=0; j < 7; j++) { _movimenti.add(new TMov_mag); indici[j] = j; } TLocalisamfile& saldi = saldi_cur.file(); const long saldi_items = saldi_cur.items(); TProgind *prog; prog = new TProgind(saldi_items, descrizione,FALSE,TRUE,10); for (saldi_cur = 0L; saldi_cur.ok(); saldi_cur +=1) { prog->addstatus(1L); codmag = saldi.get(MAG_CODMAG); codart = saldi.get(MAG_CODART); livello= saldi.get(MAG_LIVELLO); // Ciclo per i tipi di movimento for (int i=0; i<7; 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; } TMov_mag& currmov = (TMov_mag&) _movimenti[indici[i]]; // Se il movimento non ha righe, compila la testata if (currmov.rows() == 0) { TRectype& head = currmov.head(); head.put(MOVMAG_NUMREG, numreg); 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(i)); head.put(MOVMAG_DESCR, descrizione); } // Aggiunge una nuova riga al movimento corrente TRectype& riga = currmov.new_row(); riga.put(RMOVMAG_NUMREG, numreg); riga.put(RMOVMAG_CODMAG, codmag); riga.put(RMOVMAG_CODART, codart); riga.put(RMOVMAG_LIVGIAC, livello); riga.put(RMOVMAG_CODCAUS, _causali.row(i)); qta = 0.0; prezzo = 0.0; // switch sul tipo per settare quantita' e prezzo: switch (i) { case 0: // Rimanenze iniziali { qta = saldi.get_real(MAG_GIAC)+ saldi.get_real(MAG_PRODFIN)-saldi.get_real(MAG_PRODCOMP) + saldi.get_real(MAG_ACL) - saldi.get_real(MAG_INCL); // ??corretta da AcL, IncL e InProdF ?? TArticolo_giacenza artgiac(codart); switch (_calctype) { case costomedio: val = artgiac.costo_medio(_es_to_close, codmag, livello); break; case ultimocosto: val = artgiac.ultimo_costo(_es_to_close); break; case mediacosti: val = artgiac.media_costi(_es_to_close); break; case prezzolistino: val = artgiac.prezzo_listino(_es_to_close, catven, codlis); break; case prezzostd: val = artgiac.costo_standard(_es_to_close); break; case lifoannuale: val = artgiac.LIFO_annuale(_es_to_close, codmag, livello); break; case fifoannuale: val = artgiac.FIFO_annuale(_es_to_close, codmag, livello); break; case liforagionieristico: val = artgiac.LIFO_ragionieristico(_es_to_close, codmag, livello); break; case fiforagionieristico: val = artgiac.FIFO_ragionieristico(_es_to_close, codmag, livello); break; default: break; } prezzo = val/qta; } break; case 1: // In conto lav. qta = saldi.get_real(MAG_INCL); break; case 2: // A conto lav. qta = saldi.get_real(MAG_ACL); break; case 3: // In prod. fin. qta = saldi.get_real(MAG_PRODFIN); break; case 4: // In prod. com. qta = saldi.get_real(MAG_PRODCOMP); break; case 5: // Ord. forn. qta = saldi.get_real(MAG_ORDF); val = saldi.get_real(MAG_VALORDF); prezzo = val/qta; break; case 6: // Ord. cli. qta = saldi.get_real(MAG_ORDC); val = saldi.get_real(MAG_VALORDC); prezzo = val/qta; break; default: break; } riga.put(RMOVMAG_QUANT, qta); riga.put(RMOVMAG_PREZZO, prezzo); } } delete prog; // Scorre i movimenti generati ed effettua la scrittura const int items = _movimenti.items(); int err = NOERR; prog = new TProgind(items, "Scrittura movimenti in corso...",FALSE,TRUE,10); 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; if (err != NOERR) error_box("Errore %d durante la scrittura dei movimenti.",err); _movimenti.destroy(); } // 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() { TEsercizi_contabili& esercizi = _msk->exercise(); TTable esc("ESC"); int err = NOERR; // La ricostruzione dei saldi e' comune in entrambi i casi (definitiva o provvisoria) // 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). // Pertanto il flag NON dovra' piu' essere passato // Valorizza e scrive sullo storico di magazzino in base al metodo scelto if (definitiva) { // Vi sarebbe l'azzeramento saldi dell'esercizio nuovo, ma e' gia' fatta alla fine // perche' dopo la ricostruzione movimenti l'esercizio vecchio e' marcato come chiuso. // Scrive movimenti d'apertura scrivi_movimenti(); // Marca l'esercizio come chiuso esc.put("CODTAB", _es_to_close); if (esc.read() == NOERR) { esc.put("D4", _date_to_close); esc.rewrite(); } } rebuild_balances(_es_to_open); } 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); _msk->set(F_DATEOPEN,ex.esercizio(es_open).inizio()); _msk->set(F_ESTOOPEN,es_open); const int es_close = ex.pred(es_open); _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_close = _msk->get_date(F_DATEOPEN); _es_to_close = _msk->get(F_ESTOCLOSE); _es_to_open = _msk->get(F_ESTOOPEN); _calctype = (method) _msk->get_int(F_VALORIZZAZIONE); if (_calctype == fifoannuale || _calctype == lifoannuale) if (_msk->get_int(F_METODO) == 2) _calctype = _calctype == fifoannuale ? fiforagionieristico : liforagionieristico; for (short xx = F_CAURIM; xx <= F_CAUORC; xx++) // legge le causali impostate _causali.add(_msk->get(xx)); chiudi_esercizio(); // Chiusura esercizio } } int mg1400(int argc, char* argv[]) { const bool is_c = argc > 3 && *argv[2] == 'D'; const char* msg = is_c ? "Chiusura definitiva esercizio" : "Chiusura provvisoria esercizio"; TApp_openclose a(is_c ? definitiva : provvisoria); a.run(argc, argv, msg); return 0; }