#include "mr2200.h" #include "mr2200a.h" #include "mr2200b.h" class TMSPCheck_mask : public TAutomask { protected: int _col, _row, _constr_row, _last_col, _last_row; TPlanning_mask * _main_mask; TSheet_field * _sheet; protected: int max_rows() {return _sheet->items();} void go_top(); bool on_field_event(TOperable_field& o, TField_event e, long jolly); bool move_to(int dlg); virtual void check_pos_range(); virtual int fill_mask(const bool show=TRUE); virtual bool is_constraint(int row); virtual bool is_article(int row); virtual int find_constr_row(int row); public: virtual void gopos_mainmask(); void gopos(int row, int col); void fix_actual_pos(); short last_row(){ return _last_row;} short last_col(){ return _last_col;} TMSPCheck_mask(TPlanning_mask * main_mask); TMSPCheck_mask(TPlanning_mask * main_mask,const char * m,TSheet_field * s ); }; class TCRPCheck_mask : public TMSPCheck_mask { protected: virtual void check_pos_range(); virtual int fill_mask(const bool show=TRUE); virtual bool is_constraint(int row); virtual bool is_article(int row); virtual int find_constr_row(int row); public: TCRPCheck_mask(TPlanning_mask * main_mask); }; class TSave_mask : public TAutomask { TPlanning_mask *_m; protected: bool on_field_event(TOperable_field& o, TField_event e, long jolly); void copy_fields_from(); void copy_fields_to(); public: TSave_mask(TPlanning_mask &m); virtual ~TSave_mask() {} }; /////////////////////////////////////////////////////////// // Maschera salvataggio /////////////////////////////////////////////////////////// TSave_mask::TSave_mask(TPlanning_mask &m) : TAutomask("mr2200e.msk") { _m = &m; copy_fields_from(); } void TSave_mask::copy_fields_from() { for (int i = fields()-1; i >=0; i--) { const int dlg = fld(i).dlg(); if (dlg > DLG_USER) set(dlg, _m->get(dlg)); } } void TSave_mask::copy_fields_to() { for (int i = fields()-1; i >=0; i--) { const int dlg = fld(i).dlg(); if (dlg > DLG_USER) _m->set(dlg, get(dlg)); } } bool TSave_mask::on_field_event(TOperable_field& o, TField_event e, long jolly) { switch (o.dlg()) { case DLG_QUIT: copy_fields_to(); break; case F_NUM_PLAN: case F_TIPO_PLAN: return _m->on_savefields_event(o, fe_close, jolly); } return TRUE; } /////////////////////////////////////////////////////////// // Maschera principale /////////////////////////////////////////////////////////// // Arrotonda la data al bucket e ne restituisce il numero (data iniziale==bucket 0) int TPlanning_mask::round_date(TDate& date, bool up) const { // Dimensione del bucke in giorni const int bucket_size = days_per_bucket(); // Riporta la data al primo lunedi prima dell'inizio TDate inizio = get_date(F_DADATA); if (bucket_size>1) // non vado a giorni { const int wday = inizio.wday(); if (wday > 1) inizio -= wday-1; } // Calcola il bucket di appartenenza const int days = int(date - inizio); int bucket; if (days<0) bucket = -1; else bucket = days / bucket_size; if (up || days<0) // Arrotonda alla fine del bucket date = inizio + long((bucket+1 )* bucket_size - 1 - get_int(F_LASTWRKDAY)); else // Arrotonda all'inizio del bucket date = inizio + long(bucket * bucket_size); return bucket; } void TPlanning_mask::round_field(TMask_field& fld, bool up) const { TDate date = fld.get(); if (date.ok()) { round_date(date, up); fld.set(date); } } int TPlanning_mask::test_codnum(const TCodice_numerazione& num) const { int r=0; for (int s = 2; s > 0; s--) { const short id = s == _Doc_planning ? F_NUM_PLA : F_NUM_ORC; TString_array& nums = sfield(id).rows_array(); for (int i = nums.items()-1; i >= 0; i--) { const char* t = nums.row(i).get(0); if (num.codice() == t) { r|=s; break; } } } return r; } bool TPlanning_mask::test_tipodoc_num(const TSheet_field &sheet_num ,const TSheet_field &sheet_type) { TString16 tipo; TString_array& nums = sheet_num.rows_array(); TString_array& types = sheet_type.rows_array(); for (int j = types.items()-1; j >= 0; j--) { bool ok=FALSE; tipo = types.row(j).get(0) ; for (int i = nums.items()-1; i >= 0; i--) { TCodice_numerazione num(nums.row(i).get(0)); for (int n = num.ntipi_doc()-1;n >= 0; n--) { const char* t = num.tipo_doc(n); if (tipo == t) ok = TRUE; } } if (!ok) return error_box("Il tipo '%s' non appartiene a nessuna delle numerazioni scelte",(const char * )tipo); } return TRUE; } int TPlanning_mask::test_status(const TRectype& doc, int s) const { const short id = (s & _Doc_planning) ? F_TIPI_PLA : F_TIPI_ORC; TSheet_field& sf = sfield(id); const int idfr = sf.cid2index(F_DASTATO); const int idto = sf.cid2index(F_ASTATO); const TString16 tipodoc = doc.get(DOC_TIPODOC); const int statodoc = doc.get_int(DOC_STATO); TString_array& a = sf.rows_array(); for (int i = a.items()-1; i >= 0 ; i--) { TToken_string& riga = a.row(i); const char* t = riga.get(0); if (tipodoc == t) { const int state_fr = riga.get_int(idfr); const int state_to = riga.get_int(idto); if (statodoc >= state_fr && statodoc <= state_to) return i; } } return -1; } bool TPlanning_mask::has_confirmed_status(const TRectype &doc, TToken_string &riga) const { const char statodoc = doc.get_char(DOC_STATO); char def_status = riga.get_char(F_STATODEF-FIRST_FIELD); return def_status > ' ' ? statodoc >= def_status : FALSE; } bool TPlanning_mask::has_confirmed_status(const TRectype &doc) const { int sheetrow = test_status(doc, _Doc_planning); TToken_string & riga = sfield(F_TIPI_PLA).row(sheetrow); return has_confirmed_status(doc, riga); } // Metodo standard per contare gli elementi di una tabella // in attesa di tempi migliori per le librerie /* static long table_items(const char* tab) { TRelation tabrel(tab); TCursor tabcur (&tabrel); long tot = tabcur.items(); return tot; } */ bool TPlanning_mask::elabora() { TSheet_field& s = sfield(F_ARTICOLI); clear_sheets(); if (carica_documenti()) { fill_sheet(); const bool some_lines=s.items() > 0; enable(-G_PREPROCESS, !some_lines); enable(-G_POSTPROCESS, some_lines); if (some_lines) { s.select(2); s.set_focus(); on_field_event((TOperable_field&)field(F_SHOWPRICES), fe_modify, 0L); on_field_event((TOperable_field&)field(F_MSP_SORT), fe_init, 0L ); } return some_lines>0; } return FALSE; } bool TPlanning_mask::carica_documenti() { const bool ignore_mag=get_bool(F_NOMAG_IN); const bool ignore_imp=get_bool(F_NOIMP_IN); const bool ignore_lin=get_bool(F_NOLIN_IN); const bool ignore_cli=get_bool(F_NOCLI_IN); const bool ignore_allcli=get_bool(F_NOCLI_OUT); const bool is_master_sched = get_bool(F_MSCHEDULEPLAN); const bool two_level = get_bool(F_2LEVEL_MSP); TDate date_fr = get(F_DADATA); const int bucket_fr = round_date(date_fr, FALSE); TDate date_to = get(F_ADATA); const int bucket_to = round_date(date_to, TRUE); const int year_fr = date_fr.year(); const int year_to = date_to.year(); const TString& numplan = get(F_NUM_PLAN); const TString& tipoplan = get(F_TIPO_PLAN); TTable num("%NUM"); TCodice_numerazione cod; TRelation rel(LF_DOC); TCursor cur(&rel); const TRectype& curr = cur.curr(); TRectype filter_fr(curr), filter_to(curr); _articles.destroy(); _constraints.destroy(); _proposed_articles.destroy(); // Scandisce tutte le numerazioni considerando solo quelle // contenenti i tipi documento specificati nella maschera for (int err = cod.first(num); err == NOERR; err = cod.next(num)) { const int tn = test_codnum(cod); if (tn) { // Filtra il cursore in modo da limitarlo alla numerazione // corrente ed agli anni specificati dalle due date limite filter_fr.put(DOC_PROVV, "D"); filter_fr.put(DOC_CODNUM, cod.get("CODTAB")); filter_fr.put(DOC_ANNO, year_fr); filter_to.put(DOC_PROVV, "D"); filter_to.put(DOC_CODNUM, cod.get("CODTAB")); filter_to.put(DOC_ANNO, year_to); cur.setregion(filter_fr, filter_to); TString cfilter; cfilter << DOC_CODNUM << "==" << '"' << cod.get("CODTAB")<< '"'; cur.setfilter(cfilter); const long items = cur.items(); cur.freeze(TRUE); // Scandisce i documenti inevasi e considera solo // quelli con uno stato nel range corretto TString msg; msg.format("Caricamento documenti %s (numerazione '%s')",tn & _Doc_vincoli ? "ordine":"di planning",(const char *)cod.codice()); TProgind pi(items,msg , TRUE, TRUE); for (cur = 0; cur.pos() < items; ++cur) { pi.addstatus(1); if (pi.iscancelled()) return FALSE; const bool evaso = curr.get_bool(DOC_DOCEVASO); if (evaso) continue; // Calcola data di consegna per righe che non ce l'hanno TDate datacons = curr.get(DOC_DATACONS); if (!datacons.ok()) datacons = curr.get(DOC_DATADOC); const int sheetrow=test_status(curr, tn); if (sheetrow < 0) continue; // Scandisce le righe articolo e memorizza // le quantita' richieste TDocumento doc(cur.curr()); for (int r = doc.physical_rows(); r > 0; r--) { // Seleziona le righe articolo non ancora evase const TRiga_documento& riga = doc[r]; if (riga.is_articolo()) { const real qta = riga.qtaresidua(); if (qta > ZERO) { const TCodice_articolo art = riga.get(RDOC_CODARTMAG); const TString16 liv = livelli_giac().enabled() ? riga.get(RDOC_LIVELLO) : ""; const long cli = (ignore_cli && (tn & _Doc_vincoli)) ||ignore_allcli ? 0 : doc.get_long(DOC_CODCF) ; const TString8 mag = ignore_mag && (tn & _Doc_vincoli) ? "" : riga.get(RDOC_CODMAG); const TString8 magc = ignore_mag && (tn & _Doc_vincoli) ? "" : riga.get(RDOC_CODMAGC); const TString8 imp = ignore_imp && (tn & _Doc_vincoli) ? "" : riga.get(RDOC_IMPIANTO); const TString8 lin = ignore_lin && (tn & _Doc_vincoli) ? "" : riga.get(RDOC_LINEA); const TCodice_um um = riga.get(RDOC_UMQTA); TQuantita q(art, um, qta); q.convert2umbase(); TDate consegna = riga.get(RDOC_DATACONS); if (!consegna.ok()) consegna = datacons; TDate consegna_upper(consegna); int buck = round_date(consegna_upper,tn & _Doc_vincoli) - bucket_fr + 1; if ((tn & _Doc_vincoli) && consegna_upper>consegna) buck--; if (buck < 0) buck = 0; else if (buck > LAST_BUCKET) buck = LAST_BUCKET; TMSP_constraint* line; if (tn & _Doc_vincoli) { line = _constraints.find(cli, art, liv, imp, lin, mag, TRUE); line->set_mastercode_check(two_level && !distinta_master(art)); } else { line = _articles. find(cli, art, liv, imp, lin, mag, magc, TRUE); } if (line->desc().empty()) line->set_desc(riga.get(RDOC_DESCR)); if (buck >= 0 && buck <= LAST_BUCKET) { int annodoc=riga.get_int(RDOC_ANNO); TString8 codnum(cod.codice()); TString4 tiporiga(riga.get(RDOC_TIPORIGA)); char provv= riga.get_char(RDOC_PROVV); long numdoc = riga.get_long(RDOC_NDOC); int numrig = riga.get_int(RDOC_NRIGA); real prz = riga.get_int(RDOC_PREZZO); prz = prz / qta * q.val(); line->add_rigaref(buck, codnum, annodoc, numdoc, numrig,q.val(),prz);// memorizza la provenienza dal doc } if (tn & _Doc_planning) { // controlla lo stato definitivo dei documenti // appartenenti alla numerazione da generare const bool confirmed = has_confirmed_status(rel.lfile().curr(), sfield(F_TIPI_PLA).row(sheetrow)); if (confirmed) { //line->qta_locked(buck) = TRUE; line->qta_min(buck) += q.val(); } else { //add_MRP_bucket(*find_propose(cli, art, liv, imp, lin, mag, magc, TRUE), buck, q.val()); } } line->qta(buck) += q.val(); real price; find_price(get(F_TIPOCV),get(F_CODCONDV),get(F_CATVEN_CV), get(F_TIPOCF), cli, art, line->qta(buck), price); line->price(buck) = price; } } } } cur.freeze(FALSE); } } return _constraints.items() > 0L || _articles.items() > 0L; } // cerca il vincolo "migliore" secondo la logica : // - stesso magazzino , impianto e linea // - stesso magazzino e impianto // - stesso magazzino // - stesso impianto e linea // - stessa linea TMSP_constraint* TPlanning_mask::find_constraint(const TMSP_line& l, bool force_insert) { const bool ignore_mag=get_bool(F_NOMAG_IN); const bool ignore_imp=get_bool(F_NOIMP_IN); const bool ignore_lin=get_bool(F_NOLIN_IN); const bool ignore_cli=get_bool(F_NOCLI_IN); TString8 codmag=ignore_mag ? "" : l.codmag(); TString8 codimp=ignore_imp ? "" : l.codimp(); TString8 codlin=ignore_lin ? "" : l.codlin(); long codcli=ignore_cli ? 0L : l.cliente() ; // se il magazzino o l'impianto non e' indicato sul vincolo cerca di individuarlo // in base ai default di linea/impianto if (codimp.blank()) { if (!codlin.blank()) { TLinea_prod &linea_prod=*::get_linea(codlin); codimp=linea_prod.codimp(); } } if (codmag.blank()) { if (!codlin.blank()) { TLinea_prod &linea_prod=*::get_linea(codlin); codmag=linea_prod.codmagdep(); } else if (!codimp.blank()) { TImpianto &impianto=*::get_impianto(codimp); codmag=impianto.codmagdep(); } } // cerca il vincolo con - stesso magazzino , impianto e linea TMSP_constraint* c = _constraints.find(codcli, l.codice(), l.livgiac(), codimp, codlin, codmag); if (c == NULL ) { if (!codmag.blank()) { // cerca il vincolo con - stesso magazzino e impianto c =_constraints.find(codcli, l.codice(), l.livgiac(), codimp, "", codmag); if (c == NULL) // cerca il vincolo con - stesso magazzino c =_constraints.find(codcli, l.codice(), l.livgiac(), "", "", codmag); } if (c == NULL) // cerca il vincolo con - stesso impianto e linea c =_constraints.find(codcli, l.codice(), l.livgiac(), codimp, codlin, ""); if (c == NULL) // cerca il vincolo con - stessa impianto c =_constraints.find(codcli, l.codice(), l.livgiac(), codimp, "" , ""); } if (c == NULL && force_insert) { // MA STO VINCOLO MANCA PROPRIO! ALLORA LO INSERISCO c = _constraints.find(codcli, l.codice(), l.livgiac(), codimp, codlin, codmag, TRUE); if (c->desc().blank()) c->set_desc(l.desc()); c->set_mastercode_check(get_bool(F_2LEVEL_MSP) && !distinta_master(l.codice())); } return c; } int TPlanning_mask::find_constr_row(TMSP_constraint& cons) { TSheet_field& sf = sfield(F_ARTICOLI); const int maxart=sf.items(); for (int r=0; r =7; const bool show_price = get_bool(F_SHOWPRICES); TDate d = get(F_DADATA); TString str; for (int b = 0; b <= LAST_BUCKET; b++) { const bool on=(b > 0 && b < LAST_BUCKET && d < date_to); sf.enable_column(F_BUCKET0 + b*2, on); sf.enable_column(F_BUCKET0 + b*2+1, on && show_price ); sf.set_column_width(F_BUCKET0+1+b*2-FIRST_FIELD, show_price ? 140 : 0); sl.enable_column(F_LBUCKET0 + b, on); if (show_week) { str = "S."; str << d.week() << '-' << d.year(); } else str = d.string(); switch(b) { case 0: str.insert("< "); break; case LAST_BUCKET: str.insert(">= "); break; default: d += bucket_size; break; } str.insert("Qta "); sf.set_column_header(F_BUCKET0 + b*2, str); str.overwrite("Prz"); sf.set_column_header(F_BUCKET0 + b*2 +1, str); sl.set_column_header(F_LBUCKET0 + b, str); } sf.force_update(); sl.force_update(); } void TPlanning_mask::enable_codes(int row, bool on) { TSheet_field& sf = sfield(F_ARTICOLI); const bool ignore_cli=get_bool(F_NOCLI_IN); const bool ignore_imp=get_bool(F_NOIMP_IN); const bool ignore_lin=get_bool(F_NOLIN_IN); const bool ignore_mag=get_bool(F_NOMAG_IN); sf.enable_cell(row,F_CLIENTE-FIRST_FIELD, on&& ignore_cli); sf.enable_cell(row,F_CODIMP-FIRST_FIELD, on && ignore_imp); sf.enable_cell(row,F_CODLIN-FIRST_FIELD, on && ignore_lin); sf.enable_cell(row,F_MAGAZZINO-FIRST_FIELD, on && ignore_mag); sf.enable_cell(row,F_DEPOSITO-FIRST_FIELD, on && ignore_mag); sf.enable_cell(row,F_MAG_COLL-FIRST_FIELD, on && ignore_mag); sf.enable_cell(row,F_DEP_COLL-FIRST_FIELD, on && ignore_mag); } void TPlanning_mask::fill_sheet() { set_sheet_header(); TSheet_field& sl = sfield(F_LINEE); TSheet_field& sf = sfield(F_ARTICOLI); TMSP_constraint* last_constraint = NULL; const long totart = _articles.sort(); TWait_cursor hourglass; for (long i = 0; i < totart; i++) { TMSP_line& line = _articles[i]; TMSP_constraint* curr_constraint = find_constraint(line,TRUE); if (last_constraint != curr_constraint) { // aggiunge la linea di vincolo TToken_string& consrow = sf.row(-1); curr_constraint->fill_sheet_row(consrow, *this); consrow.add("** Ordini ",F_DESCART-FIRST_FIELD); sf.disable_cell(sf.items()-1, -1); // aggiunge la linea della giacenza prog TToken_string& rowgiac = sf.row(-1); copy_sheet_row(rowgiac,consrow); rowgiac.add("** Giacenza teorica",F_DESCART-FIRST_FIELD); sf.disable_cell(sf.items()-1, -1); last_constraint = curr_constraint; curr_constraint->set_on_sheet(); } const int new_row=sf.items(); TToken_string& row = sf.row(new_row); line.fill_sheet_row(row, *this); disable_codes(new_row); } const long totcon = _constraints.sort(); for (long j = 0; j < totcon; j++) { TMSP_constraint& cons = _constraints[j]; if (!cons.is_on_sheet()) { // aggiunge le tre linee TToken_string& consrow = sf.row(-1); cons.fill_sheet_row(consrow, *this); cons.set_on_sheet(); sf.disable_cell(sf.items()-1, -1); //linea della giacenza prog TToken_string& rowgiac = sf.row(-1); copy_sheet_row(rowgiac,consrow); sf.disable_cell(sf.items()-1, -1); //linea articolo (vuota) TMSP_line line(cons); line.fill_sheet_row(sf.row(-1), *this); rowgiac.add("** Giacenza teorica",F_DESCART-FIRST_FIELD); consrow.add("** Ordini ",F_DESCART-FIRST_FIELD); } } TArticolo_giacenza art; for (int r = sf.items()-1; r >0 ; ) { // init bucket 0 TCodice_articolo codart(sf.cell(r,sf.cid2index(F_ARTICOLO))); if (codart.blank()) r = r-2; art.read(codart); r=init_bucket0(art, r); } sf.force_update(); } // ritorna il numero del bucket dell'eventuali proposte +1 // (NO_PROPOSE se nessuna proposta) int TPlanning_mask::insert_propose(bool verbose) { int firstbuck=NO_PROPOSE; if (_proposed_articles.items()>0L) { add_or_sub_propose(+1); const long new_rows=_proposed_articles.items(); TSheet_field& sf = sfield(F_ARTICOLI); TDate firstdate(get_date(F_ADATA)); for (long new_row=0; new_row < new_rows; new_row++) { const TDate & d=_proposed_articles[new_row].time(0).date() ; firstdate=min(firstdate,d); } firstbuck=int((firstdate- get_date(F_DADATA))/days_per_bucket())+1; } return firstbuck; } bool TPlanning_mask::remove_propose(bool verbose) { bool removed = FALSE; if (_proposed_articles.items()>0L) { if (!verbose || yesno_box("Vuoi annullare le nuove proposte?")) { add_or_sub_propose(-1); _proposed_articles.destroy(); removed = TRUE; } } bool some = _proposed_articles.items() > 0L; if (!some && verbose) { if (load_MRP_lines(_released_schedule)) { some = _mrp_articles.items() > 0L; if (some && noyes_box("Vuoi annullare tutte le pianificazioni non confermate?")) { _proposed_articles = _mrp_articles; add_or_sub_propose(-1); _proposed_articles.destroy(); removed = TRUE; } if (!removed) message_box("Nessuna pianificazione da annullare"); } } return TRUE; } void TPlanning_mask::add_or_sub_propose(char sign) { TWait_cursor hourglass; const long new_rows=_proposed_articles.items(); TSheet_field& sf = sfield(F_ARTICOLI); for (long new_row=0; new_row < new_rows; new_row++) { const TMRP_line & a=_proposed_articles[new_row]; TMSP_line line(a.codcli(), a.codice(), a.livgiac(), a.codimp(), a.codlin(), a.codmag(), a.codmag_coll()); bool line_found=FALSE; TMSP_constraint* constraint= find_constraint(line,FALSE); if (constraint==NULL) { CHECK( sign>0, "Impossibile trovare il vincolo da soddisfare..."); // aggiunge le tre linee constraint=new TMSP_constraint(line); TToken_string& row = sf.row(-1); constraint->fill_sheet_row(row, *this); constraint->set_on_sheet(); sf.disable_cell(sf.items()-1, -1); //linea della giacenza prog TToken_string& rowgiac = sf.row(-1); copy_sheet_row(rowgiac,row); sf.disable_cell(sf.items()-1, -1); //linea articolo (vuota) TToken_string& emptyrowc = sf.row(-1); rowgiac.add("** Giacenza teorica",F_DESCART-FIRST_FIELD); row.add("** Ordini ",F_DESCART-FIRST_FIELD); } int art_row; for (art_row=int(sf.items())-1;art_row >=0; art_row--) { TToken_string &row=sf.row(art_row); long codcli; TCodice_articolo codart ; TString16 liv; TString8 mag, magc, codimp, codlin, codum; msprow2codes(row,codcli,codart,liv, mag, magc, codimp, codlin, codum); if (!sf.cell_disabled(art_row, F_BUCKET1-FIRST_FIELD)) { line_found=(a.codcli()==codcli && a.codice()==codart && a.livgiac()==liv && a.codimp()==codimp && a.codlin()==codlin && a.codmag()==mag ); if (line_found) break; } else { TMSP_constraint* currcons=_constraints.find(codcli, codart, liv, codimp, codlin, mag); if (constraint==currcons) break; } } if (!line_found) { art_row++; sf.insert(art_row); TToken_string& predrow = sf.row(art_row-1); TToken_string& artrow = sf.row(art_row); constraint->fill_sheet_row(artrow, *this,TRUE); artrow.add(predrow.get_long(F_PRIORITA-FIRST_FIELD), F_PRIORITA-FIRST_FIELD); artrow.add(predrow.get_char(F_TIPOCF_SHEET-FIRST_FIELD), F_TIPOCF_SHEET-FIRST_FIELD); artrow.add(a.codimp(), F_CODIMP-FIRST_FIELD); artrow.add(a.codlin(), F_CODLIN-FIRST_FIELD); TString8 str=a.codmag().left(3); artrow.add(str, F_MAGAZZINO-FIRST_FIELD); str=a.codmag().mid(3); artrow.add(str, F_DEPOSITO-FIRST_FIELD); str=a.codmag_coll().left(3); artrow.add(str, F_MAG_COLL-FIRST_FIELD); str=a.codmag_coll().mid(3); artrow.add(str, F_DEP_COLL-FIRST_FIELD); } TToken_string& artrow = sf.row(art_row); const int lastbuck = _proposed_articles[new_row].last_bucket(); //TDate data_buck; for (int bucket=0; bucket<=lastbuck ; bucket++) { int b= int((_proposed_articles[new_row].time(bucket).date() - get_date(F_DADATA))/days_per_bucket()); real art_per_buck(artrow.get(F_BUCKET1 + b*2 - FIRST_FIELD)); if (sign>0) art_per_buck += _proposed_articles[new_row].planned_orders(bucket); else { if (art_per_buck >= _proposed_articles[new_row].planned_orders(bucket)) art_per_buck -= _proposed_articles[new_row].planned_orders(bucket); else art_per_buck = ZERO; } artrow.add(art_per_buck.string(), F_BUCKET1 + b*2 - FIRST_FIELD); real price; if (!art_per_buck.is_zero()) find_price(get(F_TIPOCV),get(F_CODCONDV),get(F_CATVEN_CV), get(F_TIPOCF), a.codcli(), a.codice(), art_per_buck, price); artrow.add(price.string(), F_BUCKET1 + b*2 + 1 - FIRST_FIELD); } test_art_row(art_row,FALSE); } sf.force_update(); } // compatta le linee togliendo i doppioni void TPlanning_mask::pack_article_sheet() { TSheet_field& sf = sfield(F_ARTICOLI); TToken_string lastrow; for (int art_row=int(sf.items())-1; art_row >=0; art_row--) { if (!sf.cell_disabled(art_row, F_BUCKET1-FIRST_FIELD)) { TToken_string &row=sf.row(art_row); long codcli = atol(row.get(F_CLIENTE-FIRST_FIELD)); TCodice_articolo codart = row.get(F_ARTICOLO-FIRST_FIELD); TString16 codimp= row.get(F_CODIMP-FIRST_FIELD); TString16 codlin= row.get(F_CODLIN-FIRST_FIELD); TString16 liv; if (livelli_giac().enabled()) { livelli_giac().pack_grpcode(liv, row.get(sf.cid2index(F_LIV1)),1); livelli_giac().pack_grpcode(liv, row.get(sf.cid2index(F_LIV2)),2); livelli_giac().pack_grpcode(liv, row.get(sf.cid2index(F_LIV3)),3); livelli_giac().pack_grpcode(liv, row.get(sf.cid2index(F_LIV4)),4); liv.trim(); } TString16 mag; add_magcode(mag, row.get(F_MAGAZZINO-FIRST_FIELD)); add_depcode(mag, row.get(F_DEPOSITO-FIRST_FIELD)); for (int bucket=0; bucket<=LAST_BUCKET ; bucket++) { real art_per_buck(lastrow.get(F_BUCKET1 + bucket*2 - FIRST_FIELD)); row.add(art_per_buck.string(), F_BUCKET1 + bucket*2 - FIRST_FIELD); } } } sf.force_update(); } void TPlanning_mask::check_articles() { TSheet_field& sf = sfield(F_ARTICOLI); int items=sf.items(); if (items==0) { message_box("Nessun articolo da verificare"); return; } TMSPCheck_mask cm(this); int curr_row=sf.selected(); const bool is_disabled=sf.cell_disabled(curr_row,F_BUCKET1-FIRST_FIELD) ; const bool is_constr=(is_disabled && curr_row>0 && sf.cell_disabled(curr_row-1,F_BUCKET1-FIRST_FIELD)); if (is_disabled && !is_constr) curr_row++; cm.gopos(curr_row, 1); cm.run(); cm.gopos_mainmask(); } void TPlanning_mask::check_capacities() { TSheet_field& sf = sfield(F_LINEE); int items=sf.items(); if (items==0) { message_box("Nessun carico di linea da verificare"); return; } TCRPCheck_mask cm(this); cm.run(); set_focus_field(sf.dlg()); sf.set_focus_cell(cm.last_row(),cm.last_col()+F_LBUCKET0); } void TPlanning_mask::print_articles() { TString repname("mr2200"); TSheet_field& sf = sfield(F_ARTICOLI); const int nrows=sf.items(); TIsamtempfile * report = new TIsamtempfile(LF_MRPREPORT,repname, TRUE, TRUE ); TString8 codimp,codlin; TProgind pi(nrows, format("Stampa %s...",(const char *)(get_bool(F_MSCHEDULEPLAN)? "Master Schedule Plan":"pianificazione ordini"))); char block='\0'; const int a_buck0 = sf.cid2index(F_BUCKET0); for (int r=0; rcurr(); if (sf.cell_disabled(r, a_buck0 +2)) { if (r= 0; b--) { switch(b) { case 0: campo = "QTAFIRST"; break; case LAST_BUCKET: campo = "QTALAST"; break; default: campo.format("QTA%d", b); break; } record.put(campo, row.get(sf.cid2index(F_BUCKET0+b*2))); } report->write(); pi.addstatus(1); } TMSP_form form(report); // stampa if (form.cursor()->items() > 0) { TDate fd = get_date(F_DADATA); TDate td = get_date(F_ADATA); TDate wd; const short first_id = 3; const short last_id = 12; --fd; TString descr; descr.format("\nAl %s", (const char*)fd); form.find_field('B', odd_page, first_id).set_col_head(descr); for (;fd <= td;) { ++fd; descr.format("Da %s\nAl ",(const char*)fd); fd += days_per_bucket()-1; wd = fd; descr << (const char*) fd; const short id = first_id+round_date(wd,FALSE)+1; if (id > last_id) continue; form.find_field('B', odd_page, id).set_col_head(descr); } ++td; descr.format("Dal %s", (const char*)td); form.find_field('B', odd_page, last_id).set_col_head(descr); const int hh = 7; const int fl = printer().formlen(); int rows[4]; // Righe orizzontali rows[0] = hh-3; rows[1] = hh; rows[2] = fl; rows[3] = 0; form.genera_intestazioni(odd_page, hh-2); //FOrm.genera_fincatura(odd_page, hh-3, fl, rows); form.print(); } // report non va cancellato, poiche' ne viene fatta la sostituzione nella relazione del form // quindi la delete viene gia' fatta alla distruzione di _form } void TPlanning_mask::print_capacities() { TString repname("mr2200"); TSheet_field& sf = sfield(F_LINEE); const int nrows=sf.items(); TIsamtempfile * report = new TIsamtempfile(LF_MRPREPORT,repname, TRUE, FALSE ); TString8 codimp,codlin; TString codart; TProgind pi(nrows, format("Stampa %s...",(const char *)(*get(F_LOADTYPE)=='M'? "carico macchina":"carico uomo"))); const int a_buck0 = sf.cid2index(F_LBUCKET0); char block='\0'; for (int r=0; r curr(); record.zero(' '); codimp=row.get(sf.cid2index(F_CODIMPCRP)); codlin=row.get(sf.cid2index(F_CODLINCRP)); codart=row.get(sf.cid2index(F_CODARTCRP)); record.put("RIGA", r); record.put("IMPIANTO", codimp); record.put("LINEA", codlin); record.put("CODART", codart); char type('D'); if (!codart.blank()) type = 'A'; else if (!codlin.blank()) type = 'L'; else if (!codimp.blank()) type = 'I'; const bool is_capacity = sf.cell_disabled(r, a_buck0 +2); if (!is_capacity) type = tolower(type); record.put("TIPO",type); // record.put("TIPOCF", row.get(sf.cid2index(F_TIPOCF_SHEET))); // record.put("CODCLI", row.get(sf.cid2index(F_CLIENTE))); record.put("UM", row.get(sf.cid2index(F_LUM))); TString16 campo; for (int b = LAST_BUCKET; b >= 0; b--) { switch(b) { case 0: campo = "QTAFIRST"; break; case LAST_BUCKET: campo = "QTALAST"; break; default: campo.format("QTA%d", b); } record.put(campo, row.get(sf.cid2index(F_LBUCKET0+b*2))); } report->write(); pi.addstatus(1); } // delete report; // TIsamtempfile * report = new TIsamtempfile(LF_MRPREPORT,repname, FALSE, FALSE ); TCRP_form form(report); // stampa if (form.cursor()->items() > 0) form.print(); // report non va cancellato, poiche' ne viene fatta la sostituzione nella relazione del form // quindi la delete viene gia' fatta alla distruzione di _form } bool TPlanning_mask::sortMSPsheet() { TWait_cursor hg; TSheet_field& a = sfield(F_ARTICOLI); switch (-get_int(F_MSP_SORT)) { case SORT_BY_CAL: a.sort(TRiga_articolo::order_compareCAL); break; case SORT_BY_CLA: a.sort(TRiga_articolo::order_compareCLA); break; case SORT_BY_ACL: a.sort(TRiga_articolo::order_compareACL); break; case SORT_BY_ALC: a.sort(TRiga_articolo::order_compareALC); break; case SORT_BY_LCA: a.sort(TRiga_articolo::order_compareLCA); break; case SORT_BY_LAC: a.sort(TRiga_articolo::order_compareLAC); break; case SORT_BY_PCAL: a.sort(TRiga_articolo::order_comparePCAL); break; case SORT_BY_PCLA: a.sort(TRiga_articolo::order_comparePCLA); break; case SORT_BY_PACL: a.sort(TRiga_articolo::order_comparePACL); break; case SORT_BY_PALC: a.sort(TRiga_articolo::order_comparePALC); break; case SORT_BY_PLCA: a.sort(TRiga_articolo::order_comparePLCA); break; case SORT_BY_PLAC: a.sort(TRiga_articolo::order_comparePLAC); break; case SORT_BY_AC: a.sort(TRiga_articolo::order_compareAC); break; case SORT_BY_CA: a.sort(TRiga_articolo::order_compareCA); break; case SORT_BY_PAC: a.sort(TRiga_articolo::order_comparePAC); break; case SORT_BY_PCA: a.sort(TRiga_articolo::order_comparePCA); break; default: return FALSE; } a.force_update(); return TRUE; } bool TPlanning_mask::sortCRPsheet() { TWait_cursor hg; TSheet_field& a = sfield(F_LINEE); a.sort(); a.force_update(); return TRUE; } void TPlanning_mask::add_MRP_bucket(TMRP_line& new_article, int nbucket, const real &curr_arts) { TDate data_buck; data_buck=get_date(F_DADATA); data_buck+=days_per_bucket()*(nbucket-1); TMRP_time t(data_buck, 0, "", ""); new_article.add_planned_ord(t, curr_arts ); } // propone secondo la logica FirstFit o JIT void TPlanning_mask::propose_1stJIT(TMSP_logic logic, bool check_machine, bool check_human) { const bool useextralines=get_bool(F_USENONSTDLIN_MSP); const bool useextrahours=get_bool(F_USEEXTRAHRS_MSP) ; const bool lotsizing=get_bool(F_LOTSIZING) ; const bool no_outcapacity=get_bool(F_OUTOFCAPACITY) ; bool ok=TRUE; TWait_cursor clessidra; // per sicurezza devo (ri-)calcolare il carico attuale..... _capacities.destroy(); if (check_machine || check_human) { if (ok = load_MRP_lines(_released_schedule)) { /* gross2net(_released_schedule,FALSE); ok = general_review(check_machine, check_human, useextralines, useextrahours,FALSE, no_outcapacity,0, 0,_released_schedule, logic, "Calcolo carico minimo..."); _proposed_articles = _mrp_articles; add_or_sub_propose(-1); */ //add_or_sub_propose(-1); gross2net(_actual_plan,FALSE); ok = general_review(check_machine, check_human, useextralines, useextrahours,FALSE, no_outcapacity,0, 0,_actual_plan, logic, "Calcolo carico minimo..."); } } // (two) levels master scheduling TMRP_lines last_propose; int buck=NO_PROPOSE; for (int level=1; ok && level <= 2; level++) { if (ok = load_MRP_lines(_stock_break,level)) { _proposed_articles.destroy(); gross2net(_stock_break, lotsizing); const char * msg; msg = (level == 1) ? "Calcolo nuove proposte (articoli non Master)" :"Calcolo nuove proposte"; const int anticipomin=get_int((level == 2) ? F_ANTICIPOMIN : F_ANTICIPOMIN2); const int anticipomax=get_int((level == 2) ? F_ANTICIPOMAX : F_ANTICIPOMAX2); if (ok = general_review(check_machine, check_human, useextralines, useextrahours,lotsizing, no_outcapacity,anticipomin,anticipomax,_stock_break, logic, msg)) { int buck2 = insert_propose(FALSE); buck = min (buck,buck2); if (level!=2) last_propose.add(_proposed_articles); else { _proposed_articles.add(last_propose); if (buck!=NO_PROPOSE) { TDate dbuck(get_date(F_DADATA)); dbuck +=buck*days_per_bucket(); message_box("Quantita' proposte a partire dal %s (colonna %d)", (const char *)dbuck.string(),buck); } else message_box("Nessuna nuova proposta"); } } else _proposed_articles = last_propose; } } if (!ok) remove_propose(); _capacities.sort(); } // propone i valori con logica first-fit // cerca il primo bucket con capacitą produttiva bool TPlanning_mask::general_review(bool check_machine, bool check_human, bool useextralines, bool useextrahours,bool lotsizing, bool no_outcapacity, int anticipomin,int anticipomax, TMSP_mode mode, TMSP_logic logic, const char * msg ) { const bool ignore_mag=get_bool(F_NOMAG_IN); const bool ignore_imp=get_bool(F_NOIMP_IN); const bool ignore_lin=get_bool(F_NOLIN_IN); TLavorazione *curr_labor; TLinea_prod linea_prod; TArray labors; const long max_mrp_rows=_mrp_articles.items(); TProgind pi(max_mrp_rows*LAST_BUCKET ,msg, TRUE, TRUE); for (int bucket = 0; bucket < LAST_BUCKET ; bucket++) { for (long mrp_row=0; mrp_row < max_mrp_rows; mrp_row++) { pi.addstatus(1); if (pi.iscancelled()) return FALSE; TMRP_line &mrpline=_mrp_articles[mrp_row]; TDate data_buck(get_date(F_DADATA)); data_buck+=days_per_bucket()*(bucket-1); const TMRP_time mrp_time(data_buck, 0, "",""); TMRP_record & mrp_rec= mrpline.record(mrp_time); real pieces, curr_arts, art_per_buck(mrp_rec.net_requirement()); // quantitą da produrre nel bucket if (art_per_buck>ZERO) { int lastbuck =mrpline.last_bucket(); TString16 livello_di_giacenza(mrpline.livgiac()); TString8 codlin(mrpline.codlin()); TString8 codimp(mrpline.codimp()); dist_tree().set_global("_LIVELLO",livello_di_giacenza); dist_tree().set_global("_IMPIANTO",codimp); dist_tree().set_global("_LINEA",codlin); dist_tree().set_global("_MAGAZZINO",mrpline.codmag()); bool no_limits=(logic == _uniform_logic && !check_machine) || !dist_tree().set_root(mrpline.codice()); if (!no_limits) { TRiga_esplosione * l=dist_tree().first_critical_labor(labors); no_limits=(l==NULL); if (!no_limits) { curr_labor=TDistinta_tree::find_labor(l); // cerca le linee sulle quali e' possibile eseguire questa lavorazione // e la carica con la lavorazione relativa all'articolo corrente const int lineestd = curr_labor->linee_standard(); const int maxlinee = useextralines ? curr_labor->linee() : lineestd; TCRP_line *crpline_art,*crpline_lin,*crpline_imp,*crpline_firm; real load, capacity, unit_load, hload, hcapacity, unit_hload ; // carichi di linea int nbucket, lower_buck, upper_buck; int attemp=1; // primo tentativo: rimane entro i vincoli di minimo e massimo anticipo utilizando solo le linee STD // secondo tentativo: rimane entro i vincoli di minimo e massimo anticipo utilizando anche le linee non STD // terzo tentativo: supera i vincoli di minimo e massimo anticipo utilizando anche le linee non STD art_per_buck.round(5); while (art_per_buck > ZERO && attemp <= 3) { if (logic == _JIT_logic) { lower_buck = (attemp <= 2 ? bucket-anticipomax/days_per_bucket() : 1); upper_buck = bucket - anticipomin/days_per_bucket(); } else { lower_buck = bucket - anticipomax/days_per_bucket(); upper_buck = (attemp <= 2 ? bucket-anticipomin/days_per_bucket(): LAST_BUCKET); } if (lower_buck<1) lower_buck=1; if (upper_buck>bucket) upper_buck=bucket; nbucket= (logic == _JIT_logic) ? upper_buck : lower_buck; if (nbucket>bucket) { // sono oltre il bucket attuale: il sotto stock si propagherebbe fino alla fine ? art_per_buck = mrpline.net_requirement(lastbuck) ; mrpline.set_net_req(bucket,art_per_buck); } while (art_per_buck > ZERO // ho un sotto-stock da risolvere && nbucket>=lower_buck && nbucket <= upper_buck) // sono entro il range definito { int nlinea, numlinee; if (ignore_lin || codlin.blank() ) { nlinea=(attemp == 2 ? lineestd : 0 ) ; numlinee=(attemp == 1 ? lineestd : maxlinee ) ; } else { nlinea= curr_labor->find_linea(codlin); if (nlinea<0) { error_box("La linea %s non e' in grado di produrre l'articolo %s", (const char * )codlin, (const char *) _mrp_articles[mrp_row].codice()); break; } numlinee=nlinea+1; } while (art_per_buck > ZERO && nlinea >= 0 && nlineacod_linea(nlinea)); TString8 codimplin=linea_prod.codimp(); if ( ignore_imp || codimp.blank() || codimp == codimplin) { crpline_lin = _capacities.find(linea_prod); if (crpline_lin == NULL) crpline_lin = compute_capacity(linea_prod,useextralines, useextrahours); crpline_art = _capacities.find(codimplin, linea_prod.codice(), mrpline.codice(), mrpline.codcli(),TRUE); crpline_imp = _capacities.find(codimplin); crpline_firm = _capacities.find(); int human_level = 1; if ( linea_prod.personale_dedicato()) human_level = 3; else if (linea_prod.get_impianto()->personale_dedicato()) human_level = 2; // individua il massimo caricabile sulla linea unit_load = l->val()*curr_labor->um_temporale().converti_in_ore()/curr_labor->produttiv_linea(nlinea); unit_hload = unit_load*curr_labor->numpers_linea(nlinea); capacity = check_machine ? crpline_lin->capacity(nbucket).machine() : MAXCAPACITY; load = crpline_lin->load(nbucket).machine(); switch (human_level) { case 3: hcapacity = crpline_lin->capacity(nbucket).human() ; hload = crpline_lin->load(nbucket).human(); break; case 2: hcapacity = crpline_imp->capacity(nbucket).human() ; hload = crpline_imp->load(nbucket).human(); break; default: hcapacity = crpline_firm->capacity(nbucket).human() ; hload = crpline_firm->load(nbucket).human(); break; } curr_arts = art_per_buck; if (logic == _uniform_logic) curr_arts /= (upper_buck-nbucket+1); if (mode == _stock_break /*|| no_outcapacity*/) { // ridimensiona al massimo numero di articoli dovuto alle macchine capacity *= (100.0+get_int(F_EXTRACAPACITY))/100.0; if (load + curr_arts * unit_load > capacity ) { curr_arts = (capacity - load ) / unit_load; curr_arts.floor(); } hcapacity *= (100.0+get_int(F_EXTRAHCAPACITY))/100.0; // ridimensiona al massimo numero di articoli dovuto alle macchine if (check_human && hload + curr_arts * unit_hload > hcapacity) { curr_arts = (hcapacity - hload) / unit_hload; curr_arts.floor(); } /* // elimina i picchi di capacita' (errato) if (curr_arts != art_per_buck && mode == _actual_plan) { TMRP_line* new_article = _proposed_articles.find(mrpline.codice(), mrpline.livgiac(), mrpline.codmag(), linea_prod.codimp() , linea_prod.codice(), mrpline.codcli(), TRUE); add_MRP_bucket(*new_article, nbucket, curr_arts-art_per_buck ); }*/ } if (curr_arts>ZERO) { // aggiunge il carico macchina art_per_buck -= curr_arts; load= curr_arts * unit_load; crpline_art->load(nbucket).add_machine(load); crpline_lin->load(nbucket).add_machine(load); // aggiunge il numero pezzi pieces = curr_arts * cache().get(LF_ANAMAG,mrpline.codice()).get_real(ANAMAG_PPCONF); crpline_art->load(nbucket).add_pieces(pieces); crpline_lin->load(nbucket).add_pieces(pieces); crpline_imp->load(nbucket).add_pieces(pieces); // aggiunge l'impegno finanziario pieces = curr_arts * cache().get(LF_ANAMAG,mrpline.codice()).get_real(ANAMAG_COSTSTD); crpline_art->load(nbucket).add_money(pieces); crpline_lin->load(nbucket).add_money(pieces); crpline_imp->load(nbucket).add_money(pieces); hload = load*curr_labor->numpers_linea(nlinea); switch (human_level) { case 3: crpline_lin->load(nbucket).add_human(hload); case 2: crpline_imp->load(nbucket).add_human(hload); case 1: crpline_firm->load(nbucket).add_human(hload); } crpline_art->load(nbucket).add_human(hload) ; if (mode == _stock_break) { TString8 codmag(mrpline.codmag()); TString8 codmagc(mrpline.codmag_coll()); if (codmag.blank()) codmag = linea_prod.codmagdep(); if (codmagc.blank()) codmagc = linea_prod.codmagdep_coll(); TMRP_line* new_article = find_propose(mrpline.codcli(), mrpline.codice(), mrpline.livgiac(), codimplin , linea_prod.codice(), codmag, codmagc, TRUE); add_MRP_bucket(*new_article, nbucket, curr_arts); } } } else error_box("Articolo %s: impianto %s incompatibile con la linea %s",(const char *)mrpline.codice(), (const char *)codimp, (const char *)linea_prod.codice()); if (logic == _uniform_logic) nbucket++; else nlinea++; } // ciclo sulle linee if (logic == _first_fit_logic) nbucket++; else nbucket--; } attemp++; // altro tentativo } // ciclo di risoluzione dei sotto-stock } // qui andrebbe aggiunta la gestione di pił lavorazioni critiche, ora disabled // l=dist_tree().next_critical_labor(labors); } if (mode == _stock_break) { if (no_limits) // nessuna lavorazione da controllare o capacita' infinita { int nbucket, lower_buck, upper_buck; if (logic == _uniform_logic) { lower_buck = bucket - anticipomax/days_per_bucket(); upper_buck = bucket-anticipomin/days_per_bucket(); } else if (logic == _first_fit_logic) { lower_buck = bucket - anticipomax/days_per_bucket(); upper_buck = lower_buck; } else { upper_buck = bucket - anticipomin/days_per_bucket(); lower_buck = upper_buck; } if (lower_buck<1) lower_buck=1; if (upper_buck>bucket) upper_buck=bucket; nbucket = lower_buck; while (nbucket <= upper_buck) { TMRP_line* new_article = find_propose(mrpline.codcli(), mrpline.codice(), mrpline.livgiac(), mrpline.codimp() , mrpline.codlin(), mrpline.codmag(), mrpline.codmag_coll(), TRUE); curr_arts = art_per_buck; if (logic == _uniform_logic) curr_arts /= (upper_buck-nbucket+1); add_MRP_bucket(*new_article, nbucket, curr_arts); art_per_buck -= curr_arts; nbucket++; } } real pending(art_per_buck); pending -= mrpline.net_requirement(bucket); if (pending != ZERO || art_per_buck != ZERO) { const TDate lastdate = mrpline.record(lastbuck).time().date(); int b=bucket+1; do { data_buck=get_date(F_DADATA); data_buck+=days_per_bucket()*(b-1); const TMRP_time t(data_buck, 0, "",""); if (mrpline.record(t).net_requirement() > ZERO) mrpline.add_net_req(b, pending); else mrpline.add_net_req(t, art_per_buck); b++; } while (lastdate > data_buck); } } } } } return TRUE; } bool TPlanning_mask::capacity_review(bool useextralines, bool useextrahours) { bool ok; TWait_cursor clessidra; if (!load_MRP_lines(_actual_plan)) return FALSE; gross2net(_actual_plan); _capacities.destroy(); const char *msg="Calcolo carico attuale..."; if (get(F_RECALC_TYPE).left(1)=="1") ok = general_review(TRUE, TRUE, useextralines, useextrahours, FALSE, FALSE, 0, 0, _actual_plan,_first_fit_logic, msg); else if (get(F_RECALC_TYPE).left(3)=="JIT") ok = general_review(TRUE, TRUE, useextralines, useextrahours, FALSE, FALSE, 0, 0, _actual_plan,_first_fit_logic, msg); _capacities.sort(); return ok; } TCRP_line *TPlanning_mask::compute_capacity(TLinea_prod &lineaprod, bool useextralines, bool useextrahours) { TString8 codlin(lineaprod.codice()); TString8 codimp(lineaprod.codimp()); TMRP_calendar & cal = TMRP_time::get_calendar("", codlin); TMRP_calendar & cal_imp = TMRP_time::get_calendar(codimp); TMRP_calendar & cal_firm = TMRP_time::get_calendar(); CHECK(_capacities.find(lineaprod,FALSE)==NULL,"Errore: impossibile ricalcolare la capacita' di una linea produttiva"); TCRP_line *crpline_lin,*crpline_imp,*crpline_firm; crpline_lin =_capacities.find(lineaprod, "", 0L,TRUE); const bool compute_imp = (_capacities.find(codimp, "", "", 0L)==NULL); crpline_imp =_capacities.find(codimp, "", "", 0L, TRUE); const bool compute_firm = (_capacities.find("", "", "", 0L)==NULL); crpline_firm=_capacities.find("", "", "", 0L, TRUE); // calcola la capacita' TDate data_buck=get_date(F_DADATA); real capacity,human,human_imp,human_firm; for (int b=1; b=0 ; day--) { cal.add_oremacchina(capacity, data_buck,useextrahours); if (lineaprod.personale_dedicato()) cal.add_oreuomo(human, data_buck,useextrahours); if (compute_imp && lineaprod.get_impianto()->personale_dedicato()) cal_imp.add_oreuomo(human_imp, data_buck,useextrahours); if (compute_firm) cal_firm.add_oreuomo(human_firm, data_buck,useextrahours); ++data_buck; } crpline_lin->capacity(b).set_machine(capacity); if (human > ZERO) { crpline_lin->capacity(b).set_human(human); crpline_imp->capacity(b).set_human(human+crpline_imp->capacity(b).human()); crpline_firm->capacity(b).set_human(human+crpline_firm->capacity(b).human()); } if (human_imp > ZERO) { crpline_imp->capacity(b).set_human(human_imp+crpline_imp->capacity(b).human()); crpline_firm->capacity(b).set_human(human_imp+crpline_firm->capacity(b).human()); } if (human_firm > ZERO) crpline_firm->capacity(b).set_human(human_firm+crpline_firm->capacity(b).human()); } return crpline_lin; } TMRP_line* TPlanning_mask::find_propose( long codcli, const char * codart,const char * liv, const char * codimp,const char * codlin, const char * mag, const char * magcoll, bool Force) { return _proposed_articles.find(codart, liv, mag, magcoll, codimp, codlin, codcli, Force); } // carica le MRP line dallo sheet articoli void TPlanning_mask::msprow2codes(TToken_string &row,long &clifor, TCodice_articolo &art , TString & liv, TString & mag, TString & magc, TString & imp, TString & lin, TString & um) { clifor = row.get_long(F_CLIENTE-FIRST_FIELD); art = row.get(F_ARTICOLO-FIRST_FIELD); if (livelli_giac().enabled()) { livelli_giac().pack_grpcode(liv, row.get(F_LIV1-FIRST_FIELD),1); livelli_giac().pack_grpcode(liv, row.get(F_LIV2-FIRST_FIELD),2); livelli_giac().pack_grpcode(liv, row.get(F_LIV3-FIRST_FIELD),3); livelli_giac().pack_grpcode(liv, row.get(F_LIV4-FIRST_FIELD),4); liv.trim(); } add_magcode(mag,row.get(F_MAGAZZINO-FIRST_FIELD)); add_depcode(mag,row.get(F_DEPOSITO-FIRST_FIELD)); add_magcode(magc,row.get(F_MAG_COLL-FIRST_FIELD)); add_depcode(magc,row.get(F_DEP_COLL-FIRST_FIELD)); imp = row.get(F_CODIMP-FIRST_FIELD); imp.trim(); lin = row.get(F_CODLIN-FIRST_FIELD); lin.trim(); um = row.get(F_UM-FIRST_FIELD); um.trim(); } void TPlanning_mask::crprow2codes(TToken_string &row, TString & imp, TString & lin, long &clifor, TCodice_articolo &art , TString & liv, TString & um) { clifor=0L; //clifor = row.get_long(F_CLIENTE-FIRST_FIELD); //art = row.get(F_ARTICOLO-FIRST_FIELD); //livelli_giac().pack_grpcode(liv, row.get(F_LIV1-FIRST_FIELD),1); //livelli_giac().pack_grpcode(liv, row.get(F_LIV2-FIRST_FIELD),2); //livelli_giac().pack_grpcode(liv, row.get(F_LIV3-FIRST_FIELD),3); //livelli_giac().pack_grpcode(liv, row.get(F_LIV4-FIRST_FIELD),4); imp = row.get(F_CODIMPCRP-FIRST_FIELD); imp.trim(); lin = row.get(F_CODLINCRP-FIRST_FIELD); lin.trim(); um = row.get(F_LUM-FIRST_FIELD); um.trim(); } // carica le MRP line dallo sheet articoli bool TPlanning_mask::load_MRP_lines(TMSP_mode mode, int level) { TSheet_field& sa = sfield(F_ARTICOLI); if (sa.items()==0) { message_box("Nessun articolo da valutare"); return FALSE; } TWait_cursor hourglass; const int a_buck0 = sa.cid2index(F_BUCKET0); TDate data_buck; _mrp_articles.destroy(); // calcola gli impegni di produzione per gli articoli dello sheet bool skip=FALSE; TMRP_line* last_constraint = NULL; FOR_EACH_SHEET_ROW(sa, r, row) if (!sa.cell_disabled(r, a_buck0+2) || sa.cell_disabled(r+1, a_buck0+2)) { const bool is_constraint=sa.cell_disabled(r, a_buck0+2); if (is_constraint) { bool is_second_level; const int prior=get_int(F_2LEVEL_PRIORITY); if (prior>0) is_second_level=(atoi(row->get(F_PRIORITA-FIRST_FIELD))>=prior); else is_second_level=(row->get_char(F_MASTERCODE-FIRST_FIELD)==MASTERCODE_CHAR); skip = (level == 1 && !is_second_level || level == 2 && is_second_level ); } if (!skip) { long clifor; TCodice_articolo art ; TString16 liv; TString8 mag, magc, imp, lin; TCodice_um um ; msprow2codes(*row, clifor, art, liv, mag, magc, imp, lin, um); TMRP_line* curr_article=last_constraint; if (!is_constraint || mode == _stock_break) curr_article = _mrp_articles.find(art, liv, mag, magc, imp, lin, clifor ,TRUE); if (is_constraint) last_constraint = curr_article; TMSP_line* mspline = _articles.find(*row, FALSE); bool added_some=FALSE; for (int nbucket=LAST_BUCKET-1; nbucket>=0 ; nbucket--) { data_buck=get_date(F_DADATA); data_buck+=days_per_bucket()*(nbucket-1); const TMRP_time t(data_buck, 0, imp, lin); real qta=row->get(a_buck0+nbucket*2); if (qta != ZERO) { TQuantita q(art, um, qta); q.convert2umbase(); real rq(mspline ? mspline->qta_min(nbucket) : ZERO); // mette i vincoli nel gross req // e le celle normali negli sched receipts switch (mode) { case _actual_plan: case _released_schedule: if (curr_article) { curr_article->add_sched_rec(t, rq); curr_article->add_planned_ord(t, q.val() - rq); added_some=TRUE; } break; case _stock_break: if (is_constraint) { curr_article->add_gross_req(t, q.val()); added_some=TRUE; } else { if (last_constraint) { last_constraint->add_sched_rec(t, rq); last_constraint->add_planned_ord(t, q.val() - rq); } } break; } } else if (added_some) curr_article->set_on_hand(t, ZERO); // per settare tutti i bucket precedenti if (nbucket == 0 && is_constraint) { //curr_article->set_on_hand(t, curr_article->giacenza_attuale(qta,data_buck)); if (last_constraint) last_constraint->set_on_hand(t, curr_article->giacenza_attuale(qta,data_buck)); } } } } return TRUE; } // already_net: dice se le quantitą presenti sono da considerare gia' come net req o // se devo prenderle come scheduled rec e il net req lo devo calcolare di conseguenza bool TPlanning_mask::gross2net(TMSP_mode mode, bool lotsizing) { // *********** // gross 2 net const long max_mrp_rows=_mrp_articles.items(); for (long mrp_row=0; mrp_row < max_mrp_rows; mrp_row++) { // calcola il fabbisogno netto e lo riporta sul bucket seguente TMRP_line & mrp_line = _mrp_articles[mrp_row]; const int last = mrp_line.last_bucket(); for (int bucket = 0; bucket <= last; bucket = mrp_line.next_bucket(bucket)) { real netreq,giacres; switch (mode) { case _actual_plan: netreq += mrp_line.planned_orders(bucket); case _released_schedule: netreq += mrp_line.sched_receipts(bucket); mrp_line.set_net_req(bucket, netreq); break; case _stock_break: giacres = mrp_line.on_hand(bucket); giacres += mrp_line.sched_receipts(bucket); giacres -= mrp_line.gross_requirement(bucket); if (lotsizing) netreq = mrp_line.sizeup_net_requirement(bucket, giacres); else { netreq = -giacres; netreq = mrp_line.set_net_req(bucket, netreq); } const int nb = mrp_line.next_bucket(bucket); if (nb <= mrp_line.last_bucket()) mrp_line.set_on_hand(nb, giacres); break; } } } return max_mrp_rows>0; } int TPlanning_mask::days_per_bucket() const { return get_int(F_DAYXBUCK) * (get_int(F_BUCKETS) ? get_int(F_BUCKETS) : get_int(F_BUCKET)); } void TPlanning_mask::clear_sheets() { _proposed_articles.destroy(); _mrp_articles.destroy(); TSheet_field &sa=sfield(F_ARTICOLI); if (sa.items()>0) { sa.destroy(); sa.force_update(); } TSheet_field &sl=sfield(F_LINEE); if (sl.items()>0) { sl.destroy(); sl.force_update(); } xvt_statbar_set(""); enable(-G_PREPROCESS); disable(-G_POSTPROCESS); field(F_DADATA).set_focus(); } // ********** // imposta il bucket 0 ; se i flag sulla maschera sono settati, // - sulla riga delle giacenze progressive : somma la giacenza iniziale // - sulla riga dell'ordinato progressivo => sottrae la giacenza iniziale // ********** // valore di ritorno:restituisce l'ultima linea dello sheet processata int TPlanning_mask::init_bucket0(TArticolo_giacenza &art, int r) { TSheet_field& sf = sfield(F_ARTICOLI); const bool add_giac=get_bool(F_MSCHEDULEPLAN);// nettifica la giacenza // Calcola l'indice c della riga con la giacenza prog const int b0 = sf.cid2index(F_BUCKET0); const int b1 = sf.cid2index(F_BUCKET1); real planned; for (int c = r; c > 1; c--) { if (sf.cell_disabled(c, b1)) break; planned += real(sf.cell(c, b0)); } TToken_string &giac_row=sf.row(c); TToken_string &ord_row=sf.row(c-1); TToken_string &art_row=sf.row(r); // calcola codice di magazzino e di livello TString16 livello; if (livelli_giac().enabled()) { livelli_giac().pack_grpcode(livello, giac_row.get(sf.cid2index(F_LIV1)),1); livelli_giac().pack_grpcode(livello, giac_row.get(sf.cid2index(F_LIV2)),2); livelli_giac().pack_grpcode(livello, giac_row.get(sf.cid2index(F_LIV3)),3); livelli_giac().pack_grpcode(livello, giac_row.get(sf.cid2index(F_LIV4)),4); livello.trim(); } TString16 codmag; add_magcode(codmag, giac_row.get(sf.cid2index(F_MAGAZZINO))); add_depcode(codmag, giac_row.get(sf.cid2index(F_DEPOSITO))); // calcola i bucket 0 TQuantita prog_giac(art.codice(),giac_row.get(sf.cid2index(F_UM)),planned); if (add_giac) { real giac=art.giacenza_anno(codmag, livello, get_date(F_DADATA).year()); prog_giac +=giac; } // ??? prog_giac += giac_row.get(b0); prog_giac -= ord_row.get(b0); giac_row.add(prog_giac.val().string(), b0); if (ord_row.get_char(F_MASTERCODE-FIRST_FIELD) == MASTERCODE_CHAR) art_row.add(get_int(F_2LEVEL_PRIORITY),F_PRIORITA-FIRST_FIELD); do_test_art_row(r,c,FALSE); return c-2; } bool TPlanning_mask::do_test_art_row(int r, int c, bool signal) { TSheet_field& sf = sfield(F_ARTICOLI); TMask & smask= sf.sheet_mask(); TToken_string & curr_row=sf.row(r); TToken_string & constr_row=sf.row(c-1); TToken_string & giac_row=sf.row(c); // ********** // setta la priorita' su tutte le righe del blocco const int prior =curr_row.get_int(sf.cid2index(F_PRIORITA)); const int old_prior=constr_row.get_int(sf.cid2index(F_PRIORITA)); if (old_prior != prior) { for (int i = c-1; i<=r; i++) { sf.row( i ).add(prior , sf.cid2index(F_PRIORITA)); sf.force_update(i); } } // ********** // calcola la giacenza proiettata TCodice_articolo codart(curr_row.get(sf.cid2index(F_ARTICOLO))); TArticolo_giacenza art(codart); TString16 liv; TString8 mag,imp,lin; long codcli=constr_row.get_long(F_CLIENTE-FIRST_FIELD); imp=constr_row.get(sf.cid2index(F_CODIMP)); lin=constr_row.get(sf.cid2index(F_CODLIN)); if (livelli_giac().enabled()) { livelli_giac().pack_grpcode(liv, constr_row.get(sf.cid2index(F_LIV1)),1); livelli_giac().pack_grpcode(liv, constr_row.get(sf.cid2index(F_LIV2)),2); livelli_giac().pack_grpcode(liv, constr_row.get(sf.cid2index(F_LIV3)),3); livelli_giac().pack_grpcode(liv, constr_row.get(sf.cid2index(F_LIV4)),4); liv.trim(); } add_magcode(mag, constr_row.get(sf.cid2index(F_MAGAZZINO))); add_depcode(mag, constr_row.get(sf.cid2index(F_DEPOSITO))); real soglia; switch (*get(F_SOGLIAATT)) { case 'S': soglia = art.scorta_minima(mag, liv, 0, FALSE); break; case 'R': soglia = art.scorta_minima(mag, liv, 0, TRUE); break; default: soglia = ZERO; } const int b0 = sf.cid2index(F_BUCKET0); TQuantita vincolo(codart,giac_row.get(sf.cid2index(F_UM)),ZERO); TQuantita totale(vincolo),qta(vincolo); totale += real(sf.cell(c, b0));// giacenza iniziale for (int b = 1; b < LAST_BUCKET; b++) { vincolo.set_val(real(sf.cell(c-1, b0+b*2))); for (int i = c+1; i <= r; i++) { totale += real(sf.cell(i, b0+b*2)); // somma alla giacenza le produzioni } totale -= real(sf.cell(c-1, b0+b*2)); // detrae le uscite giac_row.add(totale.val().string(), b0+b*2); if (signal && totale.val() < soglia) { TString err; const int bucket_size = days_per_bucket(); const TDate d = get_date(F_DADATA) + long(bucket_size * (b-1)); err << "Riga " << c+1 << ": Vincolo non ripettato al " << d; beep(); signal =FALSE; xvt_statbar_set(err); } } sf.force_update(c); if (signal) xvt_statbar_set(""); // ********** // aggancia i master di 2' livello if (constr_row.get_char(sf.cid2index(F_MASTERCODE))==MASTERCODE_CHAR) { TMSP_constraint*currconstr=_constraints.find(codcli, codart, liv, imp, lin, mag); CHECK (currconstr, "Impossibile trovare il vincolo dell'articolo di 1' livello"); TMSP_line2 *art2ndlev; currconstr->reset_unused_line2(); while (r>c) { TToken_string & curr_row=sf.row(r); // aggancia i master di 2' livello if (art2ndlev=currconstr->use_mspline2(curr_row, sf)) do_test_art_2ndlevel(art2ndlev); else if (signal) message_box("Impossibile determinare l'articolo Master per %s",(const char*)currconstr->codice()); r--; } while (art2ndlev=currconstr->get_unused_line2()) { do_test_art_2ndlevel(art2ndlev,TRUE); currconstr->discard_line2(art2ndlev); } } return signal; } void TPlanning_mask::do_test_art_2ndlevel(TMSP_line2 *art2ndlev, bool erase) { TSheet_field& sf = sfield(F_ARTICOLI); TMask & smask= sf.sheet_mask(); int i=0; TMaster_code *mc; while ((mc=art2ndlev->get_mastercode(i++))!=NULL) { TMSP_constraint* master_constr=_constraints.find(art2ndlev->constraint().cliente(),mc->articolo() , mc->livello(), mc->codimp(), mc->codlin(), mc->codmag()); if (master_constr==NULL) { master_constr=_constraints.find(art2ndlev->constraint().cliente(),mc->articolo(), mc->livello(), mc->codimp(), mc->codlin(), mc->codmag(), TRUE); } int mrow= find_constr_row(*master_constr); TMSP_constraint* upperline=master_constr->get_upperline(art2ndlev->constraint()); real difference; bool changed=FALSE; for (int b = 0; b <= LAST_BUCKET; b++) { const int b2=b-int(((real)(mc->leadtime()/days_per_bucket()+0.5)).integer()); if (b2>=0) { if (!erase) difference= art2ndlev->constraint().qta(b2)*mc->expr(); if (upperline) difference -= upperline->qta(b2); else upperline = master_constr->add_upperline(art2ndlev->constraint()); if (difference != ZERO) { upperline->qta(b2) = upperline->qta(b2) + difference; master_constr->qta(b2) = master_constr->qta(b2) + difference; // ricostruisce il vincolo della linea master sullo sheet TToken_string &master_row=sf.row(mrow); master_row.add(master_constr->qta(b2).string(),sf.cid2index(F_BUCKET0+b2*2)); changed=TRUE; } } } if (changed) { sf.force_update(mrow); int first,last; TRiga_articolo::find_block(sf, mrow+2, first, last); do_test_art_row(last, first, FALSE); } } } // controllo linee in modo interattivo bool TPlanning_mask::test_art_row(int r, bool signal) { int ok = TRUE; TSheet_field& sf = sfield(F_ARTICOLI); int first,last; if (TRiga_articolo::find_block(sf, r, first, last)) { TToken_string & curr_row=sf.row(r); do_test_art_row(last, first, signal); if (signal) { TMSP_line* line = _articles.find(curr_row, FALSE); if (line) { real value; for (int b = 0 ; b < LAST_BUCKET; b++) { value = (curr_row.get(sf.cid2index(F_BUCKET0 + b*2))); if (value != line->qta_min(b)) { if (line->qta_locked(b)) { error_box("Impossibile modificare la quantita' per l'articolo %s, colonna %d",(const char *)line->codice(),b); do_events(); ok = FALSE; } else if (value < line->qta_min(b)) { error_box("Impossibile inserire una quantita' inferiore a %s per l'articolo %s, colonna %d",(const char *)line->qta_min(b).string(),(const char *)line->codice(),b); do_events(); ok = FALSE; } } if (!ok) { curr_row.add(line->qta_min(b).string(), sf.cid2index(F_BUCKET0 + b*2)); sf.force_update(r); } } } } } return ok; } bool TPlanning_mask::test_load_row(int r, bool signal) { TSheet_field& sf = sfield(F_LINEE); const int narticoli=sf.items(); if (narticoli<=r) return TRUE; // Calcola l'indice c della riga con la capacita' const int b0 = sf.cid2index(F_LBUCKET0); const int b1 = sf.cid2index(F_LBUCKET1); for (int c = r; c > 0; c--) { if (sf.cell_disabled(c, b1)) break; } // Calcola l'indice r della riga totale di linea if (r == c) r++; TToken_string &row=sf.row(c); real capacita, carico; for (int b = 1; b < LAST_BUCKET; b++) { capacita=real(sf.cell(c, b0+b*2)); carico=real(sf.cell(r, b0+b*2)); if (signal && capacita < carico) { TString err; const int bucket_size = days_per_bucket(); const TDate d = get_date(F_DADATA) + long(bucket_size * (b-1)); err << "Riga " << c+1 << ": capacita' superata al " << d; beep(); signal =FALSE; xvt_statbar_set(err); } } if (signal) xvt_statbar_set(""); return signal; } int TPlanning_mask::salva_documenti() { int some=0; TSheet_field& sf = sfield(F_ARTICOLI); const int b0 = sf.cid2index(F_BUCKET0); const int b1 = sf.cid2index(F_BUCKET1); const int um = sf.cid2index(F_UM); const TDate date_to = get(F_ADATA); TPlan_docs doc_rows(get(F_NUM_PLAN), get(F_TIPO_PLAN), get(F_RIGA_PLAN)); const TDate from = get(F_DADATA); const int bucket_size = days_per_bucket(); const bool number_by_cli = get_bool(F_NUMBERBYCLI); const bool number_by_week = get_bool(F_NUMBERBYWEEK); TProgind pi(LAST_BUCKET, "Emissione documenti" , FALSE, TRUE); for (int b = 1; b < LAST_BUCKET; b++) { pi.addstatus(1); TDate datacons = from + long(bucket_size * (b-1)); if (datacons > date_to) continue; round_date(datacons,TRUE); FOR_EACH_SHEET_ROW(sf, r, row) if (!sf.cell_disabled(r, b1)) { TMSP_line& line = *_articles.find(*row, TRUE); if ((get(F_DA_MAGAZZ).empty() || line.codmag() >= get(F_DA_MAGAZZ)) && (get(F_A_MAGAZZ).empty() || line.codmag() <= get(F_A_MAGAZZ)) && (get(F_DA_IMPIANTO).empty() || line.codimp() >= get(F_DA_IMPIANTO)) && (get(F_A_IMPIANTO).empty() || line.codimp() <= get(F_A_IMPIANTO))) { TDate datadoc = datacons; datadoc -= cache().get(LF_ANAMAG,line.codice()).get_real(ANAMAG_GIORNIRIOR).integer(); round_date(datadoc); const TString8 new_tipodoc(get(F_TIPO_PLAN)); const TString8 new_codnum(get(F_NUM_PLAN)); const int new_anno = datadoc.year(); const long new_numdoc = (number_by_cli ? line.cliente() * 100L : 0L)+ (number_by_week ? datadoc.week() : 0L); const int new_numrig = 0; TString8 codnum; int anno; long numdoc; int numrig; real old, val,new_val(row->get(b0 + b*2)); if (new_val < line.qta_min(b)) { if (yesno_box("Impossibile inserire un ordine inferiore a %s per %s. Interrompo ?",(const char *)line.qta_min(b).string(), (const char *)line.codice())) return FALSE; } new_val -= line.qta_min(b); TRigadoc_ref *rdr=line.first_rigaref(b); bool found=FALSE; while (rdr || found==FALSE && new_val!=ZERO) { if (rdr==NULL && !found) { found=TRUE; rdr=new TRigadoc_ref(new_codnum,new_anno,new_numdoc,new_numrig,ZERO,ZERO); line.add_rigaref(b, rdr); } old = rdr->qta_residua(); codnum = rdr->codnum(); anno = rdr->annodoc(); numdoc = rdr->numdoc(); numrig = rdr->numrig(); //if (rdr->codnum()==new_codnum && rdr->annodoc() == new_anno && rdr->numdoc() == new_numdoc) if (rdr->codnum()==new_codnum) { TToken_string keydoc("D"); keydoc.add(anno); keydoc.add(codnum); keydoc.add(numdoc); const TRectype & docrec = cache().get(LF_DOC,keydoc); if (docrec.empty() || new_tipodoc == docrec.get(DOC_TIPODOC) && !has_confirmed_status(docrec)) { val = new_val; new_val = ZERO; if (val != old) { const real incr = val-old; TRiga_documento& riga = doc_rows.add_to_row(rdr, incr); if (riga.get(RDOC_CODART).empty()) { riga.put(RDOC_CODART, line.codice()); riga.put(RDOC_CODARTMAG, line.codice()); riga.put(RDOC_LIVELLO, line.livgiac()); riga.put(RDOC_CHECKED, "X"); riga.put(RDOC_CODMAG, line.codmag()); riga.put(RDOC_CODMAGC, line.codmag_coll()); riga.put(RDOC_LINEA, line.codlin()); riga.put(RDOC_IMPIANTO, line.codimp()); riga.put(RDOC_UMQTA, row->get(sf.cid2index(F_UM))); riga.put(RDOC_DATACONS, datacons); riga.put(RDOC_DESCR, row->get(sf.cid2index(F_DESCART))); TRectype& doc = (TRectype&)riga.doc().head(); if (doc.get(DOC_DATACONS).empty()) { doc.put(DOC_DATACONS, datacons); doc.put(DOC_TIPOCF, "C"); doc.put(DOC_CODCF, line.cliente()); } doc.put(DOC_DATADOC, from); } if (val == ZERO) { line.remove_rigaref(b); enable_codes(r); } else { line.qta(b) -= old; line.qta(b) += rdr->qta_residua(); disable_codes(r); } sf.force_update(r); } } } else found = TRUE; rdr=line.next_rigaref(b); } // ciclo di aggiornamento dei riferimenti ai docs } } const long recs= doc_rows.flush(datacons); if (recs > 0L) some += 1; else if (recs < 0L) some = -1; } switch (some) { case 0: message_box("Nessun documento generato o modificato \n(numerazione %s, tipo %s)", (const char *)get(F_NUM_PLAN),(const char *)get(F_TIPO_PLAN)); break; case -1: if (yesno_box("Problemi nella registrazione dei documenti.\n(numerazione %s, tipo %s)\nRipeto l'elaborazione ?")) elabora(); // necessario per ricaricare i rif alle righe break; } return some; } /* int TPlanning_mask::salva_cell() { TMSP_line& line = *_articles.find(*row, TRUE); if ((get(F_DA_MAGAZZ).empty() || line.codmag() >= get(F_DA_MAGAZZ)) && (get(F_A_MAGAZZ).empty() || line.codmag() <= get(F_A_MAGAZZ)) && (get(F_DA_IMPIANTO).empty() || line.codimp() >= get(F_DA_IMPIANTO)) && (get(F_A_IMPIANTO).empty() || line.codimp() <= get(F_A_IMPIANTO))) { TDate datadoc = datacons; datadoc -= cache().get(LF_ANAMAG,line.codice()).get_real(ANAMAG_GIORNIRIOR).integer(); round_date(datadoc); const TString8 new_tipodoc(get(F_TIPO_PLAN)); const TString8 new_codnum(get(F_NUM_PLAN)); const int new_anno = datadoc.year(); const long new_numdoc = (number_by_cli ? line.cliente() * 100L : 0L)+ (number_by_week ? datadoc.week() : 0L); const int new_numrig = 0; TString8 codnum; int anno; long numdoc; int numrig; real old, val,new_val(row->get(b0 + b*2)); if (new_val < line.qta_min(b)) { if (yesno_box("Impossibile inserire un ordine inferiore a %s per %s. Interrompo ?",(const char *)line.qta_min(b).string(), (const char *)line.codice())) return FALSE; } new_val -= line.qta_min(b); TRigadoc_ref *rdr=line.first_rigaref(b); bool found=FALSE; while (rdr || found==FALSE && new_val!=ZERO) { if (rdr==NULL && !found) { found=TRUE; rdr=new TRigadoc_ref(new_codnum,new_anno,new_numdoc,new_numrig,ZERO,ZERO); line.add_rigaref(b, rdr); } old = rdr->qta_residua(); codnum = rdr->codnum(); anno = rdr->annodoc(); numdoc = rdr->numdoc(); numrig = rdr->numrig(); //if (rdr->codnum()==new_codnum && rdr->annodoc() == new_anno && rdr->numdoc() == new_numdoc) if (rdr->codnum()==new_codnum) { TToken_string keydoc("D"); keydoc.add(anno); keydoc.add(codnum); keydoc.add(numdoc); const TRectype & docrec = cache().get(LF_DOC,keydoc); if (docrec.empty() || new_tipodoc == docrec.get(DOC_TIPODOC) && !has_confirmed_status(docrec)) { val = new_val; new_val = ZERO; if (val != old) { const real incr = val-old; TRiga_documento& riga = doc_rows.add_to_row(rdr, incr); if (riga.get(RDOC_CODART).empty()) { riga.put(RDOC_CODART, line.codice()); riga.put(RDOC_CODARTMAG, line.codice()); riga.put(RDOC_LIVELLO, line.livgiac()); riga.put(RDOC_CHECKED, "X"); riga.put(RDOC_CODMAG, line.codmag()); riga.put(RDOC_CODMAGC, line.codmag_coll()); riga.put(RDOC_LINEA, line.codlin()); riga.put(RDOC_IMPIANTO, line.codimp()); riga.put(RDOC_UMQTA, row->get(sf.cid2index(F_UM))); riga.put(RDOC_DATACONS, datacons); riga.put(RDOC_DESCR, row->get(sf.cid2index(F_DESCART))); TRectype& doc = (TRectype&)riga.doc().head(); if (doc.get(DOC_DATACONS).empty()) { doc.put(DOC_DATACONS, datacons); doc.put(DOC_TIPOCF, "C"); doc.put(DOC_CODCF, line.cliente()); } doc.put(DOC_DATADOC, from); } if (val == ZERO) { line.remove_rigaref(b); enable_codes(r); } else { line.qta(b) -= old; line.qta(b) += rdr->qta_residua(); disable_codes(r); } sf.force_update(r); } } } else found = TRUE; rdr=line.next_rigaref(b); } // ciclo di aggiornamento dei riferimenti ai docs } } */ // copia i dati della riga al di fuori delle informazioni dei bucket void TPlanning_mask::copy_sheet_row(TToken_string & newrow, const TToken_string & row) { const TSheet_field& sf = sfield(F_ARTICOLI); const int b0 = sf.cid2index(F_BUCKET0); TString str; for (int i = 0; i < b0; i++) { row.get(i, str); newrow.add(str, i); } } bool TPlanning_mask::on_savefields_event(TOperable_field& o, TField_event e, long jolly) { switch (o.dlg()) { case F_NUM_PLAN: if (e == fe_close) { const TSheet_field& s = sfield(F_NUM_PLA); FOR_EACH_SHEET_ROW_BACK(s, r, row) if (o.get() == row->get(s.cid2index(F_NUMERAZ))) return TRUE; return o.error_box("Numerazione non inclusa tra quelle di planning"); } break; case F_TIPO_PLAN: if (e == fe_close) { const TSheet_field& s = sfield(F_TIPI_PLA); FOR_EACH_SHEET_ROW_BACK(s, r, row) if (o.get() == row->get(s.cid2index(F_TIPO))) return TRUE; return o.error_box("Tipo documento non incluso tra quelli di planning"); } break; } return TRUE; } bool TPlanning_mask::on_field_event(TOperable_field& o, TField_event e, long jolly) { const char * confirm_msg="Le attuali %d linee di articoli verranno perse. Confermi?"; switch (o.dlg()) { case F_DADATA: if (e == fe_modify) round_field(o, FALSE); break; case F_ADATA: if (e == fe_modify) round_field(o, TRUE); break; case F_BUCKET: if (e == fe_modify) { round_field(field(F_DADATA), FALSE); round_field(field(F_ADATA), TRUE); } break; case F_YEAR: case F_IMPIANTO: case F_LINEA: if (e == fe_modify || (o.dlg() == F_YEAR && e == fe_init )) update_calendar(F_CALENDAR, F_YEAR, F_IMPIANTO, F_LINEA); break; case F_TIPI_ORC: case F_TIPI_PLA: if (e == fe_init) { TSheet_field& s = (TSheet_field&)o; if (s.items() == 0) { s.row(0); s.force_update(); } } if (e == fe_close) { const TSheet_field& s = (const TSheet_field&)o; FOR_EACH_SHEET_ROW_BACK(s, r, row) if (!row->empty_items()) { bool ok; if (o.dlg()==F_TIPI_PLA) ok=test_tipodoc_num(sfield(F_NUM_PLA), s ); else ok=test_tipodoc_num(sfield(F_NUM_ORC), s ); return ok; } return error_box("E' necessario inserire almeno una riga"); } break; case F_NUM_PLAN: case F_TIPO_PLAN: on_savefields_event(o, e, jolly); break; case F_ARTICOLI: { static TToken_string _curr_art_row; TSheet_field& s = (TSheet_field&)o; const int righe = s.items(); const int nriga = int(jolly); switch(e) { case se_query_add: return jolly > 1 && righe > 0; case se_notify_add: if (jolly > 0) { const TToken_string& prev = s.row(nriga-1); TToken_string& curr = s.row(nriga); copy_sheet_row(curr,prev); } break; case se_leave: if (nriga < righe && _curr_art_row != s.row(nriga)) { const bool ok=test_art_row(nriga); if (!ok) _curr_art_row.cut(0); return ok; } break; case se_enter: if (nriga < righe) _curr_art_row= s.row(nriga); break; default: break; } } break; case F_MSP_RESORT: if (e==fe_button) sortMSPsheet(); break; case F_LINEE: { TSheet_field& s = (TSheet_field&)o; switch(e) { case se_query_add: return FALSE; case se_leave: test_load_row((int)jolly); break; } } break; case F_CRP_RESORT: if (e==fe_button) sortCRPsheet(); break; case F_BUCKET1: case F_BUCKET2: case F_BUCKET3: case F_BUCKET4: case F_BUCKET5: case F_BUCKET6: case F_BUCKET7: case F_BUCKET8: case F_BUCKET9: case F_BUCKET10: case F_BUCKET11: case F_BUCKET12: if (e == fe_modify) { const TSheet_field& s = sfield(F_ARTICOLI); TMask & m=s.sheet_mask(); TMask_field &fprice=m.field(o.dlg()+1); real qta(o.get()); real price(fprice.get()); if (!qta.is_zero() && price.is_zero()) find_price(get(F_TIPOCV),get(F_CODCONDV),get(F_CATVEN_CV), m.get(F_TIPOCF_SHEET), m.get_long(F_CLIENTE), m.get(F_ARTICOLO), qta , price); fprice.set(price.string()); } case DLG_CANCEL: if (e == fe_button) if (jolly == 0L) { TSheet_field& s = sfield(F_ARTICOLI); int lineeart=s.items(); if (lineeart==0 || yesno_box(confirm_msg,lineeart)) { clear_sheets(); } else return FALSE; } break; case DLG_ELABORA: if (e == fe_button && check_fields()) { if (is_page_crp()) { if (capacity_review(get_bool(F_USENONSTDLIN_CRP) ,get_bool(F_USEEXTRAHRS_CRP) )) { on_field_event((TOperable_field&)field(F_LOADTYPE), fe_modify, jolly ); sfield(F_LINEE).set_focus(); } } else { TSheet_field& s = sfield(F_ARTICOLI); int lineeart=s.items(); if (lineeart==0 || yesno_box(confirm_msg,lineeart)) { elabora(); } } } break; case F_CANCEL_MSP: if (e == fe_button) { remove_propose(TRUE); } break; case F_RECALC_MSP: if (e == fe_button && check_fields()) { remove_propose(); const bool useextralines=get_bool(F_USENONSTDLIN_MSP); const bool useextrahours=get_bool(F_USEEXTRAHRS_MSP) ; set(F_USENONSTDLIN_CRP ,useextralines ? "X" : ""); set(F_USEEXTRAHRS_CRP ,useextrahours ? "X" : ""); if (get(F_RECALC_TYPE)=="1") propose_1stJIT(_first_fit_logic,TRUE,TRUE); else if (get(F_RECALC_TYPE)=="1_INFH") propose_1stJIT(_first_fit_logic,TRUE,FALSE); else if (get(F_RECALC_TYPE)=="1_INF") propose_1stJIT(_first_fit_logic,FALSE,FALSE); else if (get(F_RECALC_TYPE)=="JIT") propose_1stJIT(_JIT_logic,TRUE,TRUE); else if (get(F_RECALC_TYPE)=="JIT_INFH") propose_1stJIT(_JIT_logic,TRUE,FALSE); else if (get(F_RECALC_TYPE)=="JIT_INF") propose_1stJIT(_JIT_logic,FALSE,FALSE); else if (get(F_RECALC_TYPE)=="UNIL") propose_1stJIT(_uniform_logic,TRUE,FALSE); else if (get(F_RECALC_TYPE)=="UNI") propose_1stJIT(_uniform_logic,FALSE,FALSE); // aggiorna lo sheet delle capacita' on_field_event((TOperable_field&)field(F_LOADTYPE), fe_modify, jolly ); sfield(F_ARTICOLI).set_focus(); } break; case F_CHECK: if (e == fe_button) { if (is_page_crp()) check_capacities(); else check_articles(); } break; case F_PRINT: if (e == fe_button) { if (is_page_crp()) print_capacities(); else print_articles(); } break; case F_CHECKLINE: if (e == fe_button) { const TSheet_field& s = sfield(F_ARTICOLI); TMSPCheck_mask cm(this); cm.disable(-G_MOVIMENTO); int curr_row=s.selected(); const bool is_disabled=s.cell_disabled(curr_row,F_BUCKET1-FIRST_FIELD) ; const bool is_constr=(is_disabled && curr_row>0 && s.cell_disabled(curr_row-1,F_BUCKET1-FIRST_FIELD)); if (is_disabled && !is_constr) curr_row++; cm.gopos(curr_row, 1); cm.run(); //cm.gopos_mainmask(); } break; case F_DETTAGLIO_OUT: if (e == fe_button) { TSheet_field& s = sfield(F_ARTICOLI); int curr_row=s.selected(); TMSP_line *l = _articles.find(s.row(curr_row)); if (l) { TLista_ordini m(l,"Pianificazione", get_date(F_DADATA), days_per_bucket()); if (m.run()!= K_ESC) m.edit_checked(); } else { message_box("Nessun ordine pianificato per questa riga"); } } break; case F_DETTAGLIO_IN: if (e == fe_button) { TSheet_field& s = sfield(F_ARTICOLI); int curr_row=s.selected(); while (curr_row && !s.cell_disabled(curr_row,F_BUCKET1-FIRST_FIELD)) curr_row--; TMSP_constraint *c = _constraints.find(s.row(curr_row)); if (c) { TLista_ordini m(c,"Vincoli",get_date(F_DADATA), days_per_bucket()); if (m.run()!= K_ESC) m.edit_checked(); } else { message_box("Nessun vincolo per questa riga"); } } break; case F_SHOW_WEEK: case F_SHOWPRICES: if (e == fe_modify) set_sheet_header(); break; case F_SHOWDETAILS: case F_SHOWPERC: if (e == fe_modify) on_field_event((TOperable_field&)field(F_LOADTYPE), fe_modify, jolly ); break; case F_LOADTYPE: if (e == fe_modify) { // ************* // fill sheet of capacities const bool as_percentage=get_bool(F_SHOWPERC); const char load_type=*get(F_LOADTYPE); TSheet_field& sl = sfield(F_LINEE); sl.destroy(); const long max_capacities=_capacities.items(); for (long c=0; c0 && !yesno_box(confirm_msg,lineeart)) return FALSE; } break; default: break; } return TRUE; } TPlanning_mask::TPlanning_mask(const char * name) : TCalendar_mask(name) { init(); } TPlanning_mask::TPlanning_mask() : TCalendar_mask("mr2200a") { init(); } void TPlanning_mask::init() { TSheet_field& sf = sfield(F_ARTICOLI); sf.set_append(FALSE); for (short l = 0; l < 4; l++) livelli_giac().set_sheetcolumn(sf, F_LIV1+l, l+1); TConfig ini(CONFIG_DITTA, "mg"); if (!ini.get_bool("GESDEPOSITI")) { sf.delete_column(F_DEPOSITO); sf.sheet_mask().hide(F_DEPOSITO); } if (!ini.get_bool("GESMULTIMAG")) { sf.sheet_mask().disable(F_MAGAZZINO); } if (!ini.get_bool("GESTIMPIANTI", "mr")) { hide(F_IMPIANTO); sf.delete_column(F_CODIMP); sf.sheet_mask().hide(F_CODIMP); sf.sheet_mask().hide(F_DESCIMP); } sfield(F_LINEE).disable(); // sfield(F_TESTE).disable(); load_profile(); } void TMSPCheck_mask::go_top() { gopos(2,1); if (move_to(FC_UP)) if (move_to(FC_UP)) fill_mask(); fix_actual_pos(); } void TMSPCheck_mask::gopos_mainmask() { TSheet_field &sf=_main_mask->sfield(F_ARTICOLI); int curr_row=last_row(); while (sf.cell_disabled(curr_row,F_BUCKET1-FIRST_FIELD) ) curr_row++; sf.select(curr_row/*,TRUE*/); _main_mask->set_focus_field(sf.dlg()); sf.set_focus_cell(curr_row, last_col()*2+F_BUCKET0); } TMSPCheck_mask::TMSPCheck_mask(TPlanning_mask * main_mask, const char *m,TSheet_field * s): TAutomask(m), _main_mask(main_mask) , _sheet(s) { _last_col=_last_row=_constr_row=-1; } TMSPCheck_mask::TMSPCheck_mask(TPlanning_mask * main_mask): TAutomask("mr2200b.msk"), _main_mask(main_mask), _sheet(&main_mask->sfield(F_ARTICOLI)) { _last_col=_last_row=_constr_row=-1; go_top(); set(FC_MINBUCK2CHECK,0L); set(FC_MAXBUCK2CHECK,LAST_BUCKET); } //valori di ritorno: // 0 : nessun errore // 1 : esistono modifiche // 2 : esistono nuove proposta // 4 : giacenza media superiore al voluto // 8 : sotto stock int TMSPCheck_mask::fill_mask(const bool show_fields) { int error=0; if (_last_col==_col && _last_row==_row) return error; const bool is_constr=is_constraint(_row); TToken_string &row=_sheet->row(_row); long codcli ; TCodice_articolo codart; TString16 liv; TString8 mag, magc, codimp, codlin; TString4 um; _main_mask->msprow2codes(row, codcli, codart, liv, mag, magc, codimp, codlin, um); TArticolo_giacenza art(codart); if (_last_row!=_row) { _constr_row=find_constr_row(_row); set(FC_RIGA,_row+1); set(FC_CODCLI,codcli,TRUE); set(FC_CODART,codart,TRUE); set(FC_CODIMP,codimp,TRUE); set(FC_CODLIN,codlin,TRUE); set(FC_CODMAG,mag.left(3),TRUE); set(FC_CODDEP,mag.mid(3),TRUE); //set(FC_CODMAG_C,magc.left(3),TRUE); //set(FC_CODDEP_C,magc.mid(3),TRUE); } set(FC_BUCKET,_col); TDate data_buck(_main_mask->get_date(F_DADATA)); data_buck += (_col)*_main_mask->days_per_bucket()-1; set(FC_DATE2,_col==LAST_BUCKET ? "" : data_buck.string()); data_buck -= _main_mask->days_per_bucket()-1; set(FC_DATE1,_col==0 ? "" : data_buck.string()); set(FC_IS_VINCOLO,is_constr ? "X" : " "); field(FC_IS_VINCOLO).on_hit(); if (!is_constr) { real art_per_buck(row.get(F_BUCKET0 + _col*2 - FIRST_FIELD)); set(FC_FINAL_VALUE,art_per_buck.string()); TMRP_line* new_article = _main_mask->find_propose(codcli, codart, liv, codimp, codlin, mag, magc); TMSP_line* old_article = _main_mask->find_article(codcli, codart, liv, codimp, codlin, mag, magc); real old_value=ZERO; real new_value=ZERO; if (old_article) { old_value=old_article->qta(_col); } if (new_article) { TMRP_time t(data_buck,0,"",""); TMRP_record& mrprec = new_article->record(t); new_value=mrprec.sched_receipts(); if (new_value > ZERO) error|=2; } set(FC_STARTING_VALUE,old_value.string()); set(FC_PROPOSED_VALUE,new_value.string()); show(FC_PROPOSED_VALUE,!new_value.is_zero()); show(FC_STARTING_VALUE,!old_value.is_zero()); if (old_value != art_per_buck) error|=1; // mostra i campi hide(FC_GIAC); hide(FC_UNDERSTOCK); } if (_constr_row>=0) { // calcola il sotto stock real stock(_sheet->cell(_constr_row,F_BUCKET0 + _col*2 - FIRST_FIELD)); real soglia; switch (*_main_mask->get(F_SOGLIAATT)) { case 'R': soglia = art.scorta_minima(mag, liv, 0, TRUE); if (!soglia.is_zero()) break; case 'S': soglia = art.scorta_minima(mag, liv, 0, FALSE); break; default: soglia = ZERO; } bool stockbreak = stock < soglia; bool overgiac = FALSE; set(FC_GIAC,stock.string()); show(FC_GIAC, stock > ZERO); stock = soglia - stock; set(FC_UNDERSTOCK,stock.string()); show(FC_UNDERSTOCK, stockbreak); error|=stockbreak ? 8 : 0; // calcola i giorni di permanenza stock = - stock; real giorni=ZERO; if (!stockbreak) { int bucket=0; int buck_days = _main_mask->days_per_bucket(); real prev_stock(_sheet->cell(_constr_row,F_BUCKET0 + 2*_col - 1 - FIRST_FIELD)); real delivery(_sheet->cell(_constr_row-1,F_BUCKET0 + 2*_col - FIRST_FIELD)); stock=stock-prev_stock+delivery; if (stock > ZERO) { real residuo=stock; while (residuo > ZERO && (_col + bucket)cell(_constr_row-1,F_BUCKET0 + 2*_col + bucket - FIRST_FIELD); if (delivery < prev_stock) { prev_stock-=delivery; delivery=ZERO; } else { delivery-=prev_stock; prev_stock=ZERO; } residuo-= delivery; if (residuo < ZERO) residuo=ZERO; giorni+= residuo; bucket++; } giorni = buck_days*giorni / stock; const int maxdays(_main_mask->get_int(F_MAXGIORNIGIAC)); overgiac=(giorni.integer() > maxdays); error|=overgiac ? 4 : 0; } } set(FC_GIORNIGIAC,giorni.string()); set(FC_OVERGIORNIGIAC,giorni.string()); show(FC_GIORNIGIAC, !overgiac); show(FC_OVERGIORNIGIAC,overgiac); } if (get_int(FC_FINDFILTER)==-1) { return codart==get(FC_ARTICLE2FIND); } else if (get_int(FC_FINDFILTER)==-2) { if (is_constr) { return _sheet->row(_row-1).get_char(F_MASTERCODE-FIRST_FIELD)==MASTERCODE_CHAR; } return FALSE; } else return error; } void TMSPCheck_mask::fix_actual_pos() { _last_col=_col; _last_row=_row; } void TMSPCheck_mask::gopos(int row, int col) { _row=row; _col=col; fill_mask(); fix_actual_pos(); } bool TMSPCheck_mask::on_field_event(TOperable_field& o, TField_event e, long jolly) { if (e==fe_button) { const int dlg=o.dlg(); bool redo=TRUE; const int findfilter=get_int(FC_FINDFILTER); const TString4 old_movefilter(get(FC_MOVEFILTER)); const TString4 new_movefilter(findfilter & 1 ? "" : "C"); switch (dlg) { case FC_UP_BAD: case FC_LEFT_BAD: case FC_DOWN_BAD: case FC_RIGHT_BAD: set(FC_MOVEFILTER,new_movefilter); break; } switch (dlg) { case FC_UP_BAD: if (redo = move_to(FC_UP)) _col = LAST_BUCKET+1; case FC_LEFT_BAD: while (redo) { while ((findfilter>0 || _col>LAST_BUCKET) && move_to(FC_LEFT)) { int err=fill_mask() ; fix_actual_pos(); if (findfilter<0 && err || err & findfilter) { set(FC_MOVEFILTER,old_movefilter); return TRUE; } } if (redo = move_to(FC_UP)) _col = LAST_BUCKET+1; } message_box("Ricerca terminata"); break; case FC_DOWN_BAD: if (redo = move_to(FC_DOWN)) _col = -1; case FC_RIGHT_BAD: while (redo) { while ((findfilter>0 || _col<0)&& move_to(FC_RIGHT)) { int err=fill_mask() ; fix_actual_pos(); if (findfilter<0 && err || err & findfilter) { set(FC_MOVEFILTER,old_movefilter); return TRUE; } } if (redo = move_to(FC_DOWN)) _col = -1; } message_box("Ricerca terminata"); break; default: move_to(dlg); fill_mask(); fix_actual_pos(); } set(FC_MOVEFILTER,old_movefilter); } return TRUE; } int TMSPCheck_mask::find_constr_row(int row) { while (row >=0 ) { if (is_constraint(row)) return row; row--; } return -1; } bool TMSPCheck_mask::is_constraint(int row) { return (row > 0 && _sheet->cell_disabled(row, F_BUCKET1-FIRST_FIELD) && _sheet->cell_disabled(row-1, F_BUCKET1-FIRST_FIELD)); } bool TMSPCheck_mask::is_article(int row) { return !_sheet->cell_disabled(row, F_BUCKET1-FIRST_FIELD); } bool TMSPCheck_mask::move_to(int dlg) { const bool constraints=*get(FC_MOVEFILTER)!='A'; const bool articles=*get(FC_MOVEFILTER)!='C'; CHECK(constraints||articles, "N'do cazzo muovo?"); const int max_rows=_sheet->items(); bool skip_row=TRUE; int old_row=_row; switch (dlg) { case FC_DOWNLEFT: case FC_DOWNRIGHT: case FC_DOWN: while (_row < max_rows-1) { _row++; if (constraints && is_constraint(_row) || articles && is_article(_row)) break; } if (dlg==FC_DOWNRIGHT) _col++; if (dlg==FC_DOWNLEFT) _col--; break; // se non sono sulla linea giusta, torno indietro case FC_UPRIGHT: case FC_UPLEFT: case FC_UP: while (_row >0 ) { _row--; if (constraints && is_constraint(_row) || articles && is_article(_row)) break; } if (dlg==FC_UPRIGHT) _col++; if (dlg==FC_UPLEFT) _col--; break; case FC_LEFT: _col--; break; case FC_RIGHT: _col++; break; } if (!((articles && is_article(_row) ) || (constraints && is_constraint(_row)))) _row=old_row; check_pos_range(); if (_last_col==_col && _last_row==_row) return FALSE; return TRUE; } void TMSPCheck_mask::check_pos_range() { int max_cols=max(get_int(FC_MINBUCK2CHECK),min(get_int(FC_MAXBUCK2CHECK),LAST_BUCKET)); if (max_cols==0) max_cols=LAST_BUCKET; int min_cols=max(get_int(FC_MINBUCK2CHECK),0); if (min_cols>max_cols) min_cols=max_cols; const bool constraints=*get(FC_MOVEFILTER)!='A'; const int max_rows=_sheet->items(); if (_row>=max_rows) _row=max_rows-1; if (_row< (constraints ? 1 : 2) ) _row++; if (_col>=max_cols) _col=max_cols; if (_colsfield(F_LINEE)) { go_top(); set(FC_MINBUCK2CHECK,0L); set(FC_MAXBUCK2CHECK,LAST_BUCKET); } void TCRPCheck_mask::check_pos_range() { const bool constraints=*get(FC_MOVEFILTER)!='A'; const int max_rows=_sheet->items(); if (_row>=max_rows) _row=max_rows-1; if (_row< (constraints ? 0 : 1) ) _row++; if (_col>=LAST_BUCKET) _col=LAST_BUCKET-1; if (_col<1) _col=1; } bool TCRPCheck_mask::is_constraint(int row) { return (row > 0 && !_sheet->cell_disabled(row, F_LBUCKET1-FIRST_FIELD) && _sheet->cell_disabled(row-1, F_LBUCKET1-FIRST_FIELD)); } bool TCRPCheck_mask::is_article(int row) { return (*_sheet->row(row).get(F_CODARTCRP-FIRST_FIELD)>' '); } int TCRPCheck_mask::find_constr_row(int row) { const int max=max_rows(); while (row < max) { if (is_constraint(row)) return row; row++; } return -1; } int TCRPCheck_mask::fill_mask(const bool show_fields) { int error=0; if (_last_col==_col && _last_row==_row) return error; const bool is_constr=is_constraint(_row); TSheet_field& sf = _main_mask->sfield(F_LINEE); TToken_string &row=sf.row(_row); long codcli ; TCodice_articolo codart; TString16 liv, codimp, codlin, um; _main_mask->crprow2codes(row,codimp, codlin,codcli,codart,liv,um); if (_last_row!=_row) { _constr_row=find_constr_row(_row); set(FC_RIGA,_row+1); set(FC_CODIMP,codimp); set(FC_CODLIN,codlin); set(FC_CODCLI,codcli); set(FC_CODART,codart); } set(FC_BUCKET,_col); TDate data_buck(_main_mask->get_date(F_DADATA)); data_buck += (_col)*_main_mask->days_per_bucket()-1; set(FC_DATE2,data_buck.string()); data_buck -= _main_mask->days_per_bucket()-1; set(FC_DATE1,data_buck.string()); set(FC_IS_VINCOLO,is_constr ? "X" : " "); field(FC_IS_VINCOLO).on_hit(); if (!is_constr) { // articolo real art_load(_sheet->cell(_row ,F_LBUCKET1 + _col - 1 - FIRST_FIELD)); set(FC_ART_LOAD,art_load.string()); } if (_constr_row>=0) { // vincolo real load(_sheet->cell(_constr_row ,F_LBUCKET1 + _col - 1 - FIRST_FIELD)); set(FC_LOAD,load.string()); show(FC_LOAD,load>ZERO); real capacity(_sheet->cell(_constr_row -1 ,F_LBUCKET1 + _col - 1 - FIRST_FIELD)); const bool positive=capacity>ZERO; set(FC_CAPACITY,capacity.string()); show(FC_CAPACITY,positive); capacity-=load; const bool out=capacityfield(F_MSCHEDULEPLAN).set(" "); return TRUE; } return FALSE; } void TPlanning_app::main_loop() { TConfig prassid(CONFIG_DITTA, "ve"); // apre il file di configurazione della ditta corrente if (prassid.get_bool("GES", NULL, A_LISTINI)) { mask().enable(F_CATVEN_CV,prassid.get_bool("GESLISCV")); } else { mask().disable(F_TIPOCV); mask().disable(F_CATVEN_CV); } while (mask().run()!=K_QUIT) ; } int mr2200(int argc, char* argv[]) { TPlanning_app a; a.run(argc, argv, "Pianificazione ordini"); return 0; }