#include "mr2200.h" #include "mr2200a.h" #include "mr2200b.h" #include #include #include #include #include #include "../ve/veconf.h" class TMSPCheck_mask : public TAutomask { protected: int _col, _row, _constr_row, _last_col, _last_row; TPlanning_mask * _main_mask; TSheet_field * _sheet; int max_rows() const { 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() const { return _last_row;} short last_col() const { 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); }; // sotto-maschera di riepilogo di alcune opzione della maschera principale class TPlann_sub_mask : public TAutomask { protected: TPlanning_mask *_m; void copy_fields_from(); void copy_fields_to(); bool on_field_event(TOperable_field& o, TField_event e, long jolly); public: TPlann_sub_mask(TPlanning_mask &m, const char * name); virtual ~TPlann_sub_mask() {} }; class TSave_mask : public TPlann_sub_mask { TExceptions_array _exceptions; protected: bool on_field_event(TOperable_field& o, TField_event e, long jolly); public: TSave_mask(TPlanning_mask &m); virtual ~TSave_mask() {} }; class TPrint_mask : public TPlann_sub_mask { protected: bool on_field_event(TOperable_field& o, TField_event e, long jolly); public: TPrint_mask(TPlanning_mask &m); virtual ~TPrint_mask() {} }; /////////////////////////////////////////////////////////// // Maschera di reassunto /////////////////////////////////////////////////////////// void TPlann_sub_mask::copy_fields_from() { for (int i = fields()-1; i >=0; i--) { const TMask_field & destfld = fld(i); const int dlg = destfld.dlg(); if (dlg > DLG_USER && _m->id2pos(dlg)>=0) { if (destfld.is_sheet()) { TSheet_field & sfld = (TSheet_field & )fld(i); CHECK(_m->field(dlg).is_sheet(),"Impossibile copiare un campo non sheet su uno sheet"); TSheet_field & srcfld = _m->sfield(dlg); for (int it = 0; it get(dlg)); } } } void TPlann_sub_mask::copy_fields_to() { for (int i = fields()-1; i >=0; i--) { const int dlg = fld(i).dlg(); if (dlg > DLG_USER && _m->id2pos(dlg)>=0) _m->set(dlg, get(dlg)); } } TPlann_sub_mask::TPlann_sub_mask(TPlanning_mask &m, const char * name) : TAutomask(name) { _m = &m; copy_fields_from(); } bool TPlann_sub_mask::on_field_event(TOperable_field& o, TField_event e, long jolly) { switch (o.dlg()) { case DLG_QUIT: copy_fields_to(); save_profile(); break; default: break; } return true; } /////////////////////////////////////////////////////////// // Maschera stampa /////////////////////////////////////////////////////////// TPrint_mask::TPrint_mask(TPlanning_mask &m) : TPlann_sub_mask(m, "mr2200f.msk") { } bool TPrint_mask::on_field_event(TOperable_field& o, TField_event e, long jolly) { switch (o.dlg()) { case F_MSP_RESORT: if (e==fe_button) { copy_fields_to(); _m->sortMSPsheet(); } break; case F_SHOWPERC: case F_SHOWDETAILS: case F_LOADTYPE: if (e == fe_modify) { copy_fields_to(); _m->on_field_event((TOperable_field&)_m->field(F_LOADTYPE), fe_modify, jolly ); } break; case DLG_QUIT: if (e == fe_button) { switch (get(S_PRINTTYPE)[0]) { case 'C': _m->print_capacities(); break; case 'O': { TString row_filter=get(F_PRINT_ROW_FILTER); _m->print_articles(get_int(F_PRINT_FROM_COL),get_int(F_PRINT_NUM_COL), row_filter); break; } case 'E': { TExceptions_array e; if (_m->find_exceptions(e, get_bool(S_HURRYUP_EXCEPT),get_bool(S_DELAY_EXCEPT),get_bool(S_EXTRA_EXCEPT), get_bool(S_STOCKBRK_EXCEPT), get_bool(S_CODEMISS_EXCEPT), true)) _m->print_exceptions(e); } break; } } default: TPlann_sub_mask::on_field_event(o,e,jolly); } return true; } /////////////////////////////////////////////////////////// // Maschera salvataggio /////////////////////////////////////////////////////////// TSave_mask::TSave_mask(TPlanning_mask &m) : TPlann_sub_mask(m, "mr2200e.msk") { _m = &m; copy_fields_from(); } bool TSave_mask::on_field_event(TOperable_field& o, TField_event e, long jolly) { switch (o.dlg()) { case F_SAVE_OPT: if (e == se_query_add) return false; break; case DLG_QUIT: _m->find_exceptions(_exceptions, true,true,true,false,true); if (_m->salva_documenti(_exceptions, sfield(F_SAVE_OPT))<0) _m->elabora(); // necessario per ricaricare i rif alle righe if (_exceptions.items()) { if (yesno_box(FR("%d eccezioni rilevate. Stampo il tabulato ?"),_exceptions.items())) _m->print_exceptions(_exceptions); else message_box(TR("Controllare il tabulato eccezioni.")); } break; default: TPlann_sub_mask::on_field_event(o,e,jolly); } return true; } /////////////////////////////////////////////////////////// // Maschera principale /////////////////////////////////////////////////////////// bool TPlanning_mask::_week_complete; void TPlanning_mask::get_week_year(const TDate &d, int &week, int &year) { week = d.week(); year = d.year(); const int wday = TDate(1,1,year).wday(); if (_week_complete) { if (wday != 1) week --; if (week == 0 ) { week = 52; year --; } } else { if (week > 52) { week = 1; year ++; } } } // Arrotonda la data al bucket e ne restituisce il numero (data iniziale==bucket 0) int TPlanning_mask::round_date(TDate& date, bool up, bool towrkday) const { int bucket; TDate inizio(starting_date()); if (bucket_mese()) { if (up) { date.set_end_month(); if (towrkday) { int wday = date.wday(); wday = (7-wday) % 7; wday -= get_int(F_LASTWRKDAY); if (wday<0) date += wday; } } else date.set_day(1); bucket = (date.year()-inizio.year())*12 + date.month() - inizio.month(); if (bucket<0) bucket = -1; } else { // Dimensione del bucket in giorni const int bucket_size = days_per_bucket(); // Riporta la data al primo lunedi prima dell'inizio 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); if (days<0) bucket = -1; else bucket = days / bucket_size; if (bucket_size > 1) // multipli settimanali { if (up || days<0) // Arrotonda alla fine del bucket date = inizio + long((bucket+1 )* bucket_size - 1 - (towrkday ? get_int(F_LASTWRKDAY) : 0)); else // Arrotonda all'inizio del bucket date = inizio + long(bucket * bucket_size); } } return bucket; } // restituisce il numero del bucket (data iniziale==bucket 0) int TPlanning_mask::bucket(const TDate& date) const { int bucket; TDate inizio(starting_date()); if (bucket_mese()) { // bucket = inizio.month() - date.month(); bucket = date.month() - inizio.month() + (date.year() - inizio.year())*12; if (bucket<0) bucket = -1; } else { // Dimensione del bucket in giorni const int bucket_size = days_per_bucket(); // Riporta la data al primo lunedi prima dell'inizio 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); if (days<0) bucket = -1; else bucket = days / bucket_size; } return bucket; } void TPlanning_mask::round_field(TMask_field& fld, bool up, bool towrkday) const { TDate date = fld.get(); if (date.ok()) { round_date(date, up, towrkday); 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; const TString_array& nums = sfield(id).rows_array(); for (int i = nums.last(); i >= 0; i--) { TToken_string& str = (TToken_string&)nums.row(i); const char* t = str.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) { TString_array& nums = sheet_num.rows_array(); TString_array& types = sheet_type.rows_array(); for (int j = types.last(); j >= 0; j--) { bool ok = false; const TString4 tipo = types.row(j).get(0) ; for (int i = nums.last(); 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(FR("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::test_special(const TString & num) const { const TRectype & rec = cache().get("%NUM", num); return rec.get_bool("B9"); } 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); } bool TPlanning_mask::has_confirmed_status(const char * codnum, const char *tipodoc, char stato) const { TRectype doc(LF_DOC); doc.put(DOC_CODNUM, codnum); doc.put(DOC_TIPODOC, tipodoc); doc.put(DOC_STATO, stato); return has_confirmed_status(doc); } // 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() { bool some_lines = false; clear_sheets(); if (carica_documenti()) { fill_sheet(); TSheet_field& s = sfield(F_ARTICOLI); 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; } 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 order_break=get_bool(F_SINGLE_DOC); const bool is_master_sched = get_bool(F_MSCHEDULEPLAN); const bool two_level = get_bool(F_2LEVEL_MSP); const int depth = get_int(F_RIFERIMENTO_MSP); _mrp_articles.ignore(false, false, false, false, !order_break); _proposed_articles.ignore(false, false, false, false, !order_break); _proposed_1stlevel.ignore(false, false, false, false, !order_break); TDate date_fr(starting_date()); 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 TCodice_articolo f_art(get(F_FRART)); const bool f_art_fill = f_art.full(); const TCodice_articolo t_art(get(F_TOART)); const bool t_art_fill = t_art.full(); TString8 f_grm(get(F_FRGRM)); f_grm.rpad(3); f_grm << get(F_FRSGM); f_grm.trim(); const bool f_grm_fill = f_grm.full(); TString8 t_grm(get(F_TOGRM)); t_grm.rpad(3); t_grm << get(F_FRSGM); t_grm.trim(); const bool t_grm_fill = t_grm.full(); TString8 imp; if (!ignore_imp) imp = get(F_IMP); const bool filtered = f_art_fill || t_art_fill || f_grm_fill || t_grm_fill || imp.full(); const int year_fr = date_fr.year() - (get_bool(F_DOC_YEAR_PREC) ? 1 : 0); const int year_to = date_to.year(); TDate datalim(date_fr); const int days = days_per_bucket(); datalim -= get_int(F_LIM); 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(); // Scandisce i documenti inevasi e considera solo // quelli con uno stato nel range corretto TString msg; msg.format(FR("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; const bool ignore_prec = get_bool(F_IGNORE_PREC); // if (ignore_prec && (tn & _Doc_planning) && (datacons < date_fr)) // continue; const bool skip = ignore_prec && (tn & _Doc_planning) && (datacons < date_fr); if (skip) if (datacons < datalim) continue; // Scandisce le righe articolo e memorizza // le quantita' richieste const 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 TCodice_articolo art = riga.get(RDOC_CODARTMAG); const real qta = riga.qtaresidua(); bool ok = qta > ZERO; if (ok && filtered) { if (ok && f_art_fill) ok = art >= f_art; if (ok && t_art_fill) ok = art <= t_art; if (ok && f_grm_fill) ok = cache().get(LF_ANAMAG, art, ANAMAG_GRMERC) >= f_grm; if (ok && t_grm_fill) ok = cache().get(LF_ANAMAG, art, ANAMAG_GRMERC) <= t_grm; if (ok && imp.not_empty()) { const TString & r_imp = riga.get(RDOC_IMPIANTO); ok = (imp == r_imp); } } if (ok) { const TString16 liv = livelli_giacenza().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); TString80 da_rdoc_key; if (order_break) { if ((tn & _Doc_vincoli) && (depth == 0)) { da_rdoc_key.format("%-4s%4dD%7ld%4d", (const char *) riga.get(RDOC_CODNUM), riga.get_int(RDOC_ANNO), riga.get_long(RDOC_NDOC), riga.get_int(RDOC_IDRIGA)); } else da_rdoc_key.format("%-4s%4dD%7ld%4d", (const char *) riga.get(RDOC_DACODNUM), riga.get_int(RDOC_DAANNO), riga.get_long(RDOC_DANDOC), riga.get_int(RDOC_DAIDRIGA)); } 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 && !bucket_mese()) buck--; if (buck < 0) buck = 0; else if (buck > LAST_BUCKET) buck = LAST_BUCKET; TMSP_constraint* line = NULL; if (tn & _Doc_vincoli) { line = _constraints.find(cli, art, liv, imp, lin, mag, magc, da_rdoc_key, true); line->set_mastercode_check(two_level && !distinta_master(art)); } else { if (skip) { const long p = riga.get_long(RDOC_PRIORITY); TMSP_constraint* linec = _constraints.find(cli, art, liv, imp, ignore_lin ? "" : lin, mag, magc, da_rdoc_key, false); if (linec != NULL) { if (p > linec->priority()) { linec->priority(p); line = _articles.find(cli, art, liv, imp, lin, mag, magc, da_rdoc_key, true); if (line->description().blank()) line->set_description(riga.get(RDOC_DESCR)); } } continue; } line = _articles.find(cli, art, liv, imp, lin, mag, magc, da_rdoc_key, true); } if (line->description().blank()) line->set_description(riga.get(RDOC_DESCR)); if (buck >= 0 && buck <= LAST_BUCKET) { const int annodoc=riga.get_int(RDOC_ANNO); TString4 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 * q.val() / qta; TMRP_docref* dr = line->add_rigaref(buck, codnum, annodoc, numdoc, numrig, q.um(), q.val(), prz);// memorizza la provenienza dal doc long p = riga.get_long(RDOC_PRIORITY); const bool user_defined_priority = p > 0; if (!user_defined_priority) { const TString& priority_formula = get(F_PRIORITY); if (!priority_formula.blank()) { TExpression expr(priority_formula); if (expr.numvar() > 0) { for (int i = expr.numvar()-1; i >= 0; i--) { const TString vn(expr.varname(i)); if (vn == "DATE_PRIORITY") { real buck_priority; if (tn & _Doc_vincoli) { buck_priority = date_to - consegna; if (buck_priority < ZERO) buck_priority = ZERO; } expr.setvar(i, buck_priority); } else { const TFieldref fr(vn, 0); switch (fr.file()) { case LF_DOC: expr.setvar(i, fr.read(doc)); break; case LF_RIGHEDOC: expr.setvar(i, fr.read(riga)); break; default: { const TRectype& recart = cache().get(LF_ANAMAG, art); expr.setvar(i, fr.read(recart)); } break; } } } p = expr.as_real().integer(); } } } if (p > line->priority()) line->priority(p); } if (!skip) { 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.codmagdep(); TString8 codimp=ignore_imp ? "" : l.codimp(); TString8 codlin=ignore_lin ? "" : l.codlin(); long codcli=ignore_cli ? 0L : l.codclifor() ; // 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.full()) { TLinea_prod &linea_prod=*::get_linea(codlin); codimp=linea_prod.codimp(); } } if (codmag.blank()) { if (codlin.full()) { TLinea_prod &linea_prod=*::get_linea(codlin); codmag=linea_prod.codmagdep(); } else { if (codimp.full()) { TImpianto &impianto=*::get_impianto(codimp); codmag=impianto.codmagdep(); } } } TString da_rdoc_key(l.da_rdoc_key()); // cerca il vincolo con - stesso magazzino , impianto e linea TMSP_constraint* c = _constraints.find(codcli, l.articolo(), l.livgiac(), codimp, codlin, codmag, EMPTY_STRING, da_rdoc_key); if (c == NULL ) { long try_cli = codcli; do { if (codmag.full()) { // cerca il vincolo con - stesso magazzino e impianto c =_constraints.find(try_cli, l.articolo(), l.livgiac(), codimp, "", codmag, EMPTY_STRING, da_rdoc_key); if (c == NULL) // cerca il vincolo con - stesso magazzino c =_constraints.find(try_cli, l.articolo(), l.livgiac(), "", "", codmag, EMPTY_STRING, da_rdoc_key); } if (c == NULL) // cerca il vincolo con - stesso impianto e linea c =_constraints.find(try_cli, l.articolo(), l.livgiac(), codimp, codlin, "", EMPTY_STRING, da_rdoc_key); if (c == NULL) // cerca il vincolo con - stessa impianto c =_constraints.find(try_cli, l.articolo(), l.livgiac(), codimp, "" , "", EMPTY_STRING, da_rdoc_key); if (try_cli == 0 ) try_cli = -1; if (try_cli > 0 ) try_cli = 0; // cerca il vincolo con altro fornitore } while (c == NULL && try_cli >= 0); } if (c == NULL && force_insert) { // MA STO VINCOLO MANCA PROPRIO! ALLORA LO INSERISCO c = _constraints.find(codcli, l.articolo(), l.livgiac(), codimp, codlin, codmag, EMPTY_STRING, l.da_rdoc_key(), true); if (c->description().blank()) c->set_description(l.description()); c->set_mastercode_check(get_bool(F_2LEVEL_MSP) && !distinta_master(l.articolo())); } return c; } // cerca la riga del vincolo e se non la trova int TPlanning_mask::find_constr_row(TMSP_constraint& cons) { TSheet_field& sf = sfield(F_ARTICOLI); const int maxart=sf.items(); int r; for (r = 0; r =7; const bool show_price = get_bool(F_SHOWPRICES); TDate d(starting_date()); int year, week; TString str; for (int b = 0; b <= LAST_BUCKET; b++) { round_date(d); 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) { get_week_year(d, week, year); str = "S."; str << week << '-' << year; } else str = d.string(); switch(b) { case 0: str.insert("< "); break; case LAST_BUCKET: str.insert(">= "); break; default: d += bucket_size; break; } sl.set_column_header(F_LBUCKET0 + b, str); str.insert(TR("Qta ")); sf.set_column_header(F_BUCKET0 + b*2, str); str.overwrite(TR("Prz")); sf.set_column_header(F_BUCKET0 + b*2 +1, 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; TWait_cursor hourglass; bool special = false; // ************* // parte 1: introduce gli articoli ed i loro vincoli associati const long totart = _articles.sort(); for (long i = 0; i < totart; i++) { TMSP_line& line = _articles[i]; TMSP_constraint* curr_constraint = find_constraint(line,true); TString8 codnum = curr_constraint->da_rdoc_key().left(4); codnum.trim(); const bool special = test_special(codnum); int new_row = -1; for (int nrow = sf.items() - 1; nrow >=0; nrow--) { if (sf.cell_disabled(nrow, F_BUCKET1-FIRST_FIELD)) { last_constraint = _constraints.find(sf.row(nrow)); if (last_constraint == curr_constraint) { new_row = nrow + 1; break; } } } if (last_constraint != curr_constraint) { // aggiunge la linea di vincolo TToken_string& consrow = sf.row(-1); curr_constraint->fill_sheet_row(consrow, *this, TR("** Ordini ")); highlight_row(sf.items()-1, special); sf.disable_cell(sf.items()-1, -1); // aggiunge la linea della giacenza prog TToken_string& rowgiac = sf.row(-1); copy_sheet_row(rowgiac,consrow, TR("** Giacenza teorica")); highlight_row(sf.items()-1, special); sf.disable_cell(sf.items()-1, -1); // last_constraint = curr_constraint; curr_constraint->set_on_sheet(); // int new_row=sf.items(); } sf.insert(new_row); TToken_string& row = sf.row(new_row); line.fill_sheet_row(row, *this, ""); highlight_row(new_row, special); disable_codes(new_row); if (curr_constraint->codclifor()) sf.disable_cell(new_row,sf.cid2index(F_CLIENTE)); } // ************* // parte 2: introduce i rimanenti vincoli non relativi ad articoli caricati 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 TString8 codnum = cons.da_rdoc_key().left(4); codnum.trim(); const bool special = test_special(codnum); TToken_string& consrow = sf.row(-1); cons.fill_sheet_row(consrow, *this, TR("** Ordini ")); cons.set_on_sheet(); highlight_row(sf.items()-1, special); sf.disable_cell(sf.items()-1, -1); //linea della giacenza prog TToken_string& rowgiac = sf.row(-1); copy_sheet_row(rowgiac,consrow, TR("** Giacenza teorica")); highlight_row(sf.items()-1, special); sf.disable_cell(sf.items()-1, -1); //linea articolo (vuota) TMSP_line line(cons); line.fill_sheet_row(sf.row(-1), *this, ""); if (consrow.get_long(sf.cid2index(F_CLIENTE))) sf.disable_cell(sf.items()-1,sf.cid2index(F_CLIENTE)); highlight_row(sf.items()-1, special); } } 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); } sortMSPsheet(); 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(); 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(bucket(firstdate) - bucket(starting_date()))+1; } return firstbuck; } bool TPlanning_mask::remove_propose(bool verbose) { bool remove = false; bool remove_all = false; bool some = _proposed_articles.items() > 0L; // proposte attuali if (some) remove = (!verbose || yesno_box(TR("Vuoi annullare le nuove proposte?"))); if (!some && verbose) { if (load_MRP_lines(_actual_plan)) { some = _mrp_articles.items() > 0L; if (some) { remove = (noyes_box(TR("Vuoi annullare tutte le pianificazioni non confermate?"))); if (remove && get_bool(F_RESCHEDULING) && noyes_box(TR("Vuoi annullare anche le pianificazioni confermate?"))) remove_all = true; } if (!remove) message_box(TR("Nessuna pianificazione da annullare")); else _proposed_articles = _mrp_articles; } } if (remove) { add_or_sub_propose(-1, remove_all); _proposed_articles.destroy(); } return true; } void TPlanning_mask::highlight_row(int row, bool on) { COLOR back = on ? _sel_color.get_back_color(_con_pos) : NORMAL_BACK_COLOR; COLOR fore = on ? _sel_color.get_fore_color(_con_pos) : NORMAL_COLOR; sfield(F_ARTICOLI).set_back_and_fore_color(back, fore, row); } void TPlanning_mask::highlight(int row, int col, bool on, bool special) { COLOR back; COLOR fore; if (special) { back = on ? _sel_color.get_back_color(_npr_pos) : _sel_color.get_back_color(_con_pos); fore = on ? _sel_color.get_fore_color(_npr_pos) : _sel_color.get_fore_color(_con_pos); } else { back = on ? _sel_color.get_back_color(_npr_pos) : NORMAL_BACK_COLOR; fore = on ? _sel_color.get_fore_color(_npr_pos) : NORMAL_COLOR; } sfield(F_ARTICOLI).set_back_and_fore_color(back, fore, row, col); } void TPlanning_mask::add_or_sub_propose(char sign, bool scheduled) { CHECK(sign <0 || !scheduled, "Le qta schedulate possono solo venire sottratte"); 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.codclifor(), a.articolo(), a.livgiac(), a.codimp(), a.codlin(), a.codmagdep(), a.codmagdep_coll(), a.da_rdoc_key()); bool line_found = false; TMSP_constraint* constraint = find_constraint(line, false); if (constraint == NULL) { if (sign < 0) continue; // aggiunge le tre linee constraint = find_constraint(line, true); TToken_string& row = sf.row(-1); constraint->fill_sheet_row(row, *this, TR("** Ordini ")); 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, TR("** Giacenza teorica")); sf.disable_cell(sf.items()-1, -1); //linea articolo (vuota) TToken_string& emptyrowc = sf.row(-1); } 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; TString80 da_rdoc_key; msprow2codes(row,codcli,codart,liv, mag, magc, codimp, codlin, codum, da_rdoc_key); if (!sf.cell_disabled(art_row, F_BUCKET1-FIRST_FIELD)) { line_found=(a.codclifor()==codcli && a.articolo()==codart && a.livgiac()==liv && a.codimp()==codimp && a.codlin()==codlin && a.codmagdep()==mag && a.da_rdoc_key() == da_rdoc_key); if (line_found) break; } else { TMSP_constraint* currcons=_constraints.find(codcli, codart, liv, codimp, codlin, mag, magc, da_rdoc_key); 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(get(F_TIPOCF),F_TIPOCF_SHEET-FIRST_FIELD); artrow.add(a.codclifor(), F_CLIENTE-FIRST_FIELD); artrow.add(a.codimp(), F_CODIMP-FIRST_FIELD); artrow.add(a.codlin(), F_CODLIN-FIRST_FIELD); TString8 str=a.codmagdep().left(3); artrow.add(str, F_MAGAZZINO-FIRST_FIELD); str=a.codmagdep().mid(3); artrow.add(str, F_DEPOSITO-FIRST_FIELD); str=a.codmagdep_coll().left(3); artrow.add(str, F_MAG_COLL-FIRST_FIELD); str=a.codmagdep_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(); TString8 codnum = constraint->da_rdoc_key().left(4); codnum.trim(); const bool special = test_special(codnum); highlight_row(art_row, special); for (int nbucket=0; nbucket<=lastbuck ; nbucket++) { int b = bucket( _proposed_articles[new_row].time(nbucket).date() ); real art_per_buck(artrow.get(F_BUCKET1 + b*2 - FIRST_FIELD)); real prop = _proposed_articles[new_row].planned_orders(nbucket); if (sign>0) art_per_buck += prop; else { if (b>=0) { if (scheduled) prop += _proposed_articles[new_row].sched_receipts(nbucket); if (art_per_buck > prop) art_per_buck -= prop; else art_per_buck = ZERO; } } highlight(art_row, F_BUCKET1 + b*2, prop != ZERO && art_per_buck != ZERO, special); 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.codclifor(), a.articolo(), art_per_buck, price); artrow.add(price.string(), F_BUCKET1 + b*2 + 1 - FIRST_FIELD); } test_art_row(art_row,false); } sf.force_update(); } void TPlanning_mask::check_articles() { TSheet_field& sf = sfield(F_ARTICOLI); int items=sf.items(); if (items==0) { message_box(TR("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(TR("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); } bool TPlanning_mask::sortMSPsheet() { TWait_cursor hg; TSheet_field& a = sfield(F_ARTICOLI); const int ss = get_int(F_MSP_SORT); switch (-ss) { 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_LPAC: a.sort(TRiga_articolo::order_compareLPAC); 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(); // Accende i bottoni di spostamento righe solo se si ordina per periorita' enable(F_PRIORITY_HI, ss < SORT_BY_PRIORITY); enable(F_PRIORITY_LO, ss < SORT_BY_PRIORITY); 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=starting_date(); data_buck+=days_per_bucket()*(nbucket-1); round_date(data_buck); TMRP_time t(data_buck, 0, "", ""); new_article.add_planned_ord(t, curr_arts ); } void TPlanning_mask::propose(int row) { 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" : ""); const TString& rt = get(F_RECALC_TYPE); if (rt=="1") propose_1stJIT(_first_fit_logic,true,true, row); else if (rt=="1_INFH") propose_1stJIT(_first_fit_logic,true,false, row); else if (rt=="1_INF") propose_1stJIT(_first_fit_logic,false,false, row); else if (rt=="JIT") propose_1stJIT(_JIT_logic,true,true, row); else if (rt=="JIT_INFH") propose_1stJIT(_JIT_logic,true,false, row); else if (rt=="JIT_INF") propose_1stJIT(_JIT_logic,false,false, row); else if (rt=="UNIL") propose_1stJIT(_uniform_logic,true,false, row); else if (rt=="UNI") propose_1stJIT(_uniform_logic,false,false, row); // aggiorna lo sheet delle capacita' } // propone secondo la logica FirstFit o JIT void TPlanning_mask::propose_1stJIT(TMSP_logic logic, bool check_machine, bool check_human, int numriga) { 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(_actual_plan)) { gross2net(_actual_plan,false); ok = general_review(check_machine, check_human, useextralines, useextrahours,false, no_outcapacity,0, 0,_actual_plan, logic, TR("Calcolo carico minimo...")); } } // (two) levels master scheduling TMRP_lines last_propose(_proposed_articles); last_propose.destroy(); int buck=NO_PROPOSE; for (int level=1; ok && level <= 2; level++) { ok = load_MRP_lines(_stock_break, level, numriga); if (ok) { _proposed_articles.destroy(); gross2net(_stock_break, lotsizing); const char* msg = (level == 1) ? TR("Calcolo nuove proposte (articoli non Master)") : TR("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); ok = general_review(check_machine, check_human, useextralines, useextrahours,lotsizing, no_outcapacity,anticipomin,anticipomax,_stock_break, logic, msg); if (ok) { const 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(starting_date()); dbuck +=buck*days_per_bucket(); round_date(dbuck); message_box(FR("Quantita' proposte a partire dal %s (colonna %d)"), (const char *)dbuck.string(),buck); } else message_box(TR("Nessuna nuova proposta")); } } else _proposed_articles = last_propose; } } if (!ok) remove_propose(); _capacities.sort(); } void TPlanning_mask::review_cell(long mrp_row, int bucket, 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, bool firstfitxbucket) { 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); TMRP_line &mrpline = _mrp_articles[mrp_row]; TToken_string * row = mrpline.sheet_row(); TDate data_buck(starting_date()); data_buck += days_per_bucket()*(bucket-1); round_date(data_buck); const TMRP_time mrp_time(data_buck, 0, "",""); TMRP_record & mrp_rec= mrpline.record(mrp_time); real art_per_buck = mrp_rec.net_requirement(); // quantitą da produrre nel bucket if (art_per_buck > ZERO) { real pieces, curr_arts; int lastbuck = mrpline.last_bucket(); TString16 livello_di_giacenza(mrpline.livgiac()); TString8 codlin(mrpline.codlin()); TString8 codimp(mrpline.codimp()); if (row != NULL) { codlin = row->get(F_CODLIN-FIRST_FIELD); codimp = row->get(F_CODIMP-FIRST_FIELD); } dist_tree().set_global("_LIVELLO",livello_di_giacenza); dist_tree().set_global("_IMPIANTO",codimp); dist_tree().set_global("_LINEA",codlin); dist_tree().set_global("_MAGDEP",mrpline.codmagdep()); bool no_limits=(logic == _uniform_logic && !check_machine) || !dist_tree().set_root(mrpline.articolo()); if (!no_limits) { TArray labors; TRiga_esplosione * l=dist_tree().first_critical_labor(labors); no_limits = (l == NULL); bool first_buck = true; if (!no_limits) { TLavorazione *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; const real perc_min_lav = curr_labor->percentuale_minima(); 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); //if (nbucket>bucket) if (art_per_buck > mrpline.net_requirement(lastbuck) && mode != _actual_plan) { // il sotto stock si propagherebbe fino alla fine ? art_per_buck = mrpline.net_requirement(lastbuck) ; mrpline.set_net_req(bucket,art_per_buck); } int max_attempts = 3; // non anticipare articoli che potrebbero avere figli non anticipati automaticamente if (!no_limits && get_bool(F_NOANTICIPI_MSP)) max_attempts = 2; while (art_per_buck > ZERO && attemp <= max_attempts) { 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(); if (firstfitxbucket) upper_buck = LAST_BUCKET; else upper_buck = (attemp <= 2 ? bucket-anticipomin/days_per_bucket(): LAST_BUCKET); } if (lower_buck<1) lower_buck=1; if (!firstfitxbucket && upper_buck>bucket) upper_buck=bucket; nbucket= (logic == _JIT_logic) ? upper_buck : lower_buck; int nlinea = -1, numlinee; if (ignore_lin || codlin.blank() ) { if (codlin.blank()) { nlinea=(attemp == 2 ? lineestd : 0 ) ; numlinee=(attemp == 1 ? lineestd : maxlinee ) ; } else // l'utente ha fissato la linea { if (attemp == 1) { nlinea = curr_labor->find_linea(codlin); numlinee = nlinea + 1; } if (nlinea < 0) { nlinea = 0; numlinee = (attemp < 3 ? lineestd : maxlinee ) ; } } } else { nlinea= curr_labor->find_linea(codlin); if (nlinea<0) { error_box(FR("La linea %s non e' in grado di produrre l'articolo %s"), (const char * )codlin, (const char *) _mrp_articles[mrp_row].articolo()); break; } numlinee=nlinea+1; } while (art_per_buck > ZERO // ho un sotto-stock da risolvere && nlinea >= 0 && nlinea=lower_buck && nbucket <= upper_buck) // sono entro il range definito { while (art_per_buck > ZERO && nlinea >= 0 && nlineacod_linea(nlinea))); real perc_min = linea_prod.tempo_minimo(); if (perc_min == ZERO) perc_min = perc_min_lav; 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.articolo(), mrpline.codclifor(),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() && 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 ? (upper_buck-nbucket+1) : 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.codmagdep(), linea_prod.codimp() , linea_prod.codice(), mrpline.codcli(), true); add_MRP_bucket(*new_article, nbucket, curr_arts-art_per_buck ); }*/ } if (curr_arts > ZERO && first_buck && perc_min > ZERO) { real arts_min = art_per_buck * perc_min / CENTO; arts_min.round(5); if (arts_min > curr_arts) curr_arts = ZERO; } if (curr_arts > ZERO) { first_buck = false; // 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.articolo()).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 const real pieces = curr_arts * cache().get(LF_ANAMAG,mrpline.articolo()).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); crpline_lin->load(nbucket).add_human(hload); crpline_imp->load(nbucket).add_human(hload); crpline_firm->load(nbucket).add_human(hload); crpline_art->load(nbucket).add_human(hload) ; if (mode == _stock_break) { TString8 codmag(mrpline.codmagdep()); TString8 codmagc(mrpline.codmagdep_coll()); if (codmag.blank()) codmag = linea_prod.codmagdep(); if (codmagc.blank()) codmagc = linea_prod.codmagdep_coll(); TMRP_line* new_article = find_propose(mrpline.codclifor(), mrpline.articolo(), mrpline.livgiac(), codimplin , linea_prod.codice(), codmag, codmagc, mrpline.da_rdoc_key(), true); add_MRP_bucket(*new_article, nbucket, curr_arts); } } } else error_box("Articolo %s: impianto %s incompatibile con la linea %s",(const char *)mrpline.articolo(), (const char *)codimp, (const char *)linea_prod.codice()); if ((logic == _uniform_logic) || (logic == _first_fit_logic && firstfitxbucket)) nbucket++; else nlinea++; } // ciclo sulle linee if (logic == _first_fit_logic && firstfitxbucket) nlinea++; else { if (logic == _first_fit_logic) nbucket++; else if (logic != _uniform_logic) 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 = 0, lower_buck = 0, upper_buck = 0; switch (logic) { case _uniform_logic: lower_buck = bucket - anticipomax/days_per_bucket(); upper_buck = bucket-anticipomin/days_per_bucket(); break; case _first_fit_logic: lower_buck = bucket - anticipomax/days_per_bucket(); upper_buck = lower_buck; break; default: upper_buck = bucket - anticipomin/days_per_bucket(); lower_buck = upper_buck; break; } if (lower_buck < 1) lower_buck = 1; if (upper_buck < lower_buck) // Oppure bucket?????????????? upper_buck = lower_buck; if (upper_buck > bucket) upper_buck=bucket; nbucket = lower_buck; //if (nbucket>bucket) // sono oltre il bucket attuale ?... if (art_per_buck > mrpline.net_requirement(lastbuck)) // il sotto stock si propagherebbe fino alla fine del periodo? { art_per_buck = mrpline.net_requirement(lastbuck) ; mrpline.set_net_req(bucket,art_per_buck); } while (nbucket <= upper_buck) { long codclifor = mrpline.codclifor() ; TString16 codmagdep = mrpline.codmagdep(); if (is_acq_planning() && codclifor == 0L) { TArticolo art(mrpline.articolo()); codclifor = art.get_long(ANAMAG_CODFORN); if (codclifor == 0L) codclifor = _standard_for; if (codclifor != 0L && codmagdep.empty()) { TString16 key; key.format("F|%ld", codclifor); const TRectype & venrec = cache().get(LF_CFVEN, key); codmagdep = venrec.get(CFV_CODMAG); if (codmagdep.not_empty()) { codmagdep.left_just(3); codmagdep << venrec.get(CFV_CODDEP); } } } if (codmagdep.empty()) { codmagdep = _magazzini.standardmag(); codmagdep.left_just(3); codmagdep << _magazzini.standarddep(); } TMRP_line* new_article = find_propose(codclifor, mrpline.articolo(), mrpline.livgiac(), mrpline.codimp() , mrpline.codlin(), codmagdep, mrpline.codmagdep_coll(), mrpline.da_rdoc_key(), 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++; } } // gestione del pending 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=starting_date(); data_buck+=days_per_bucket()*(b-1); round_date(data_buck); const TMRP_time t(data_buck, 0, "",""); if (b <= lastbuck) mrpline.add_net_req(b, pending); else mrpline.add_net_req(t, art_per_buck); // ?!?!?! perche? b++; } while (lastdate > data_buck); } } } } // 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 long max_mrp_rows=_mrp_articles.items(); if (max_mrp_rows == 0) return true; for (long mrp_row=0; mrp_row < max_mrp_rows; mrp_row++) { TMRP_line &mrpline = _mrp_articles[mrp_row]; TToken_string * row = mrpline.sheet_row(); TString8 codlin(mrpline.codlin()); TString8 codimp(mrpline.codimp()); if (row != NULL) { codlin = row->get(F_CODLIN-FIRST_FIELD); codimp = row->get(F_CODIMP-FIRST_FIELD); } TLinea_prod linea_prod(cache().get("LNP", codlin)); if (_capacities.find(linea_prod) == NULL) compute_capacity(linea_prod,useextralines, useextrahours); } const bool firstfitxbucket = get_bool(F_FFBUCKET_MSP) ; if (firstfitxbucket) return inverse_general_review(check_machine, check_human, useextralines, useextrahours, lotsizing, no_outcapacity, anticipomin, anticipomax, mode, logic, msg); TProgind pi((max_mrp_rows+1)*LAST_BUCKET ,msg, true, true); for (int bucket = 0; bucket < LAST_BUCKET ; bucket++) { pi.addstatus(1); for (long mrp_row=0; mrp_row < max_mrp_rows; mrp_row++) { pi.addstatus(1); if (pi.iscancelled()) return false; review_cell(mrp_row, bucket, check_machine, check_human, useextralines, useextrahours, lotsizing, no_outcapacity, anticipomin, anticipomax, mode, logic, msg, false); } } return true; } bool TPlanning_mask::inverse_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 long max_mrp_rows=_mrp_articles.items(); if (max_mrp_rows == 0) return true; TProgind pi((max_mrp_rows+1)*LAST_BUCKET ,msg, true, true); for (long mrp_row=0; mrp_row < max_mrp_rows; mrp_row++) { pi.addstatus(1); for (int bucket = 0; bucket < LAST_BUCKET ; bucket++) { pi.addstatus(1); if (pi.iscancelled()) return false; review_cell(mrp_row, bucket, check_machine, check_human, useextralines, useextrahours, lotsizing, no_outcapacity, anticipomin, anticipomax, mode, logic, msg, true); } } 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=TR("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) { const TString8 codlin = lineaprod.codice(); const TString8 codimp = lineaprod.codimp(); CHECK(_capacities.find(lineaprod,false)==NULL,"Errore: impossibile ricalcolare la capacitą 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=starting_date(); TDate next_data_buck = data_buck; real capacity,human,human_imp,human_firm; for (int b=1; bpersonale_dedicato()) { const TMRP_calendar& cal_imp = TMRP_time::get_calendar(codimp); int nturni = useextrahours ? cal.turni_max(data_buck) :cal.turni_min(data_buck); cal_imp.add_oreuomo(human_imp, data_buck,useextrahours, nturni); } if (compute_firm) { const TMRP_calendar& cal_firm = TMRP_time::get_calendar(); 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) { const real hmin = crpline_imp->capacity(b).human(); if (hmin < human_imp) crpline_imp->capacity(b).set_human(human_imp); // 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, const char * da_rdoc_key, bool force) { return _proposed_articles.find(codart, liv, mag, magcoll, codimp, codlin, codcli, da_rdoc_key, 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, TString & da_rdoc_key) { clifor = row.get_long(F_CLIENTE-FIRST_FIELD); art = row.get(F_ARTICOLO-FIRST_FIELD); if (livelli_giacenza().enabled()) { livelli_giacenza().pack_grpcode(liv, row.get(F_LIV1-FIRST_FIELD),1); livelli_giacenza().pack_grpcode(liv, row.get(F_LIV2-FIRST_FIELD),2); livelli_giacenza().pack_grpcode(liv, row.get(F_LIV3-FIRST_FIELD),3); livelli_giacenza().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(); const TString val = row.get(F_DESCART-FIRST_FIELD); const int pos = val.find('¦'); if (pos >= 0) da_rdoc_key = val.mid(pos+1); else da_rdoc_key = EMPTY_STRING; } 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_giacenza().pack_grpcode(liv, row.get(F_LIV1-FIRST_FIELD),1); //livelli_giacenza().pack_grpcode(liv, row.get(F_LIV2-FIRST_FIELD),2); //livelli_giacenza().pack_grpcode(liv, row.get(F_LIV3-FIRST_FIELD),3); //livelli_giacenza().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, int numriga) { TSheet_field& sa = sfield(F_ARTICOLI); if (sa.empty()) return message_box(TR("Nessun articolo da valutare")); TWait_cursor hourglass; int first_row=-1, last_row=-1; if (numriga >= 0) { TRiga_articolo::find_block(sa, numriga, first_row, last_row); first_row--; } const int a_buck0 = sa.cid2index(F_BUCKET0); TDate data_buck; _mrp_articles.destroy(); // calcola gli impegni di produzione per gli articoli dello sheet TMRP_line* curr_article=NULL; int added_on = -1; bool skip=false; FOR_EACH_SHEET_ROW(sa, r, row) if (!sa.cell_disabled(r, a_buck0+2) || sa.cell_disabled(r+1, a_buck0+2)) { if (first_row < 0 || r >=first_row && r <=last_row) { 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 = 0L; TCodice_articolo art ; TString16 liv; TString8 mag, magc, imp, lin; TCodice_um um ; TString80 da_rdoc_key; msprow2codes(*row, clifor, art, liv, mag, magc, imp, lin, um, da_rdoc_key); if ((is_constraint && mode == _stock_break ) || (!is_constraint && mode == _actual_plan) || (is_constraint && mode == _rescheduling) ) { curr_article = _mrp_articles.find(art, liv, mag, magc, imp, lin, clifor, da_rdoc_key ,true); added_on = -1; } if (!is_constraint && curr_article->sheet_row() == NULL) curr_article->set_row(row); TMSP_line* mspline = _articles.find(*row, false); if ((mode == _stock_break ) || (!is_constraint && mode == _actual_plan) || (!is_constraint && mode == _rescheduling) ) for (int nbucket=LAST_BUCKET-1; nbucket>=0 ; nbucket--) { data_buck=starting_date(); data_buck+=days_per_bucket()*(nbucket-1); round_date(data_buck); const TMRP_time t(data_buck, 0, imp, lin); real qta=row->get(a_buck0+nbucket*2); 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 _rescheduling: if ((!qta.is_zero() || !rq.is_zero() || added_on>nbucket)&& (nbucket>0)) { curr_article->add_planned_ord(t, q.val()); if (mspline) { // transfer docs' refs TMRP_docref * ref = mspline->first_rigaref(nbucket); while (ref) { if (has_confirmed_status(ref->codnumdoc(),ref->tipodoc(),ref->statodoc())) curr_article->add_sched_rec(t, ref->qta_residua(), ref); ref = mspline->next_rigaref(nbucket); } } added_on = nbucket; } break; case _actual_plan: if (!qta.is_zero()) { if (curr_article) { curr_article->add_sched_rec(t, rq); curr_article->add_planned_ord(t, q.val() - rq); added_on = nbucket; } } else if (added_on > nbucket) curr_article->set_on_hand(t, ZERO); // per settare tutti i bucket precedenti break; case _stock_break: if (!qta.is_zero()) { if (is_constraint) { curr_article->add_gross_req(t, q.val()); } else { curr_article->add_sched_rec(t, rq); curr_article->add_planned_ord(t, q.val() - rq); } TMRP_record dbg = curr_article->record(t); added_on = nbucket; } else if (added_on > nbucket || added_on == 0 && nbucket == 0 ) curr_article->set_on_hand(t, get_bool(F_MSCHEDULEPLAN) && nbucket == 0 ? curr_article->giacenza_attuale(qta,data_buck) : ZERO); break; } } } } } 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 & mrpline = _mrp_articles[mrp_row]; const int last = mrpline.last_bucket(); real netreq, giacres, resched, need; for (int bucket = 0; bucket <= last; bucket = mrpline.next_bucket(bucket)) { switch (mode) { case _actual_plan: netreq = mrpline.planned_orders(bucket); netreq += mrpline.sched_receipts(bucket); mrpline.set_net_req(bucket, netreq); break; case _stock_break: { giacres = mrpline.on_hand(bucket); giacres -= mrpline.gross_requirement(bucket); //if (bucket == 0) giacres += mrpline.planned_orders(bucket); giacres += mrpline.sched_receipts(bucket); if (lotsizing) netreq = mrpline.sizeup_net_requirement(bucket, giacres, netreq); else { netreq = -giacres; netreq = mrpline.set_net_req(bucket, netreq); } const int nb = mrpline.next_bucket(bucket); if (nb <= mrpline.last_bucket()) mrpline.set_on_hand(nb, giacres); } break; default: break; } } } return max_mrp_rows>0; } const TDate & TPlanning_mask::starting_date() const { if (!_start_date.ok()) { TDate &nakedate = ((TPlanning_mask *)(this))->_start_date; if (get_date(F_DADATA).ok()) nakedate = get_date(F_DADATA); else { nakedate = TODAY; round_date(nakedate, true, false); nakedate+=1; } } return _start_date; } int TPlanning_mask::days_per_bucket() const { const int cestini = get_int(F_BUCKETS); return get_int(F_DAYXBUCK) * (cestini > 0 ? cestini : get_int(F_BUCKET)); } bool TPlanning_mask::bucket_mese() const { return get(F_BUCKETS)[0] == 'M'; } void TPlanning_mask::clear_sheets() { _start_date = NULLDATE; _proposed_articles.destroy(); _mrp_articles.destroy(); TSheet_field &sa=sfield(F_ARTICOLI); sa.set_line_number_width(4); if (sa.items()>0) { sa.destroy(); sa.force_update(); } TSheet_field &sl=sfield(F_LINEE); sl.set_line_number_width(4); if (sl.items()>0) { sl.destroy(); sl.force_update(); } xvtil_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; int c; for (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_giacenza().enabled()) { livelli_giacenza().pack_grpcode(livello, giac_row.get(sf.cid2index(F_LIV1)),1); livelli_giacenza().pack_grpcode(livello, giac_row.get(sf.cid2index(F_LIV2)),2); livelli_giacenza().pack_grpcode(livello, giac_row.get(sf.cid2index(F_LIV3)),3); livelli_giacenza().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, starting_date().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,r,false); return c-2; } bool TPlanning_mask::do_test_art_row(int r, int first, int last, 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(first-1); TToken_string & giac_row=sf.row(first); // ********** // setta la priorita' e la linea su tutte le righe del blocco TString16 prior = curr_row.get(sf.cid2index(F_PRIORITA)); prior.trim(); TString16 old_prior=constr_row.get(sf.cid2index(F_PRIORITA)); old_prior.trim(); if (prior != old_prior) { if (prior.full()) { for (int i = first-1; i<=last; i++) { sf.row( i ).add(prior , sf.cid2index(F_PRIORITA)); sf.force_update(i); } } else sf.row(r).add(old_prior, sf.cid2index(F_PRIORITA)); } TString8 codlin = curr_row.get(sf.cid2index(F_CODLIN)); prior.trim(); constr_row.add(codlin , sf.cid2index(F_CODLIN)); sf.force_update(first - 1); // ********** // calcola la giacenza proiettata TCodice_articolo codart(curr_row.get(sf.cid2index(F_ARTICOLO))); if (codart.blank()) // Controllo di DEBUG { if (signal) { error_box(FR("Articolo nullo nella riga %d"), r+1); signal = false; } return signal; } const TArticolo_giacenza art(codart); const long codcli=constr_row.get_long(F_CLIENTE-FIRST_FIELD); const TString8 imp = constr_row.get(sf.cid2index(F_CODIMP)); const TString8 lin = constr_row.get(sf.cid2index(F_CODLIN)); TString16 liv; TString8 mag; TString80 da_rdoc_key; if (livelli_giacenza().enabled()) { livelli_giacenza().pack_grpcode(liv, constr_row.get(sf.cid2index(F_LIV1)),1); livelli_giacenza().pack_grpcode(liv, constr_row.get(sf.cid2index(F_LIV2)),2); livelli_giacenza().pack_grpcode(liv, constr_row.get(sf.cid2index(F_LIV3)),3); livelli_giacenza().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))); const TString val = constr_row.get(sf.cid2index(F_BUCKET)); const int pos = val.find('¦'); if (pos >= 0) da_rdoc_key = val.mid(pos+1); 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(first, b0));// giacenza iniziale for (int b = 1; b < LAST_BUCKET; b++) { vincolo.set_val(real(sf.cell(first-1, b0+b*2))); for (int i = first+1; i <= last; i++) { totale += real(sf.cell(i, b0+b*2)); // somma alla giacenza le produzioni } totale -= real(sf.cell(first-1, b0+b*2)); // detrae le uscite giac_row.add(totale.val().string(), b0+b*2); if (signal && totale.val() < soglia) { TString err; TDate d = starting_date() + long(days_per_bucket() * (b-1)); round_date(d); err << TR("Riga ") << first+1 << ": Vincolo non ripettato al " << d; beep(); signal = false; xvtil_statbar_set(err); } } sf.force_update(first); if (signal) xvtil_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, EMPTY_STRING, da_rdoc_key); CHECK (currconstr, "Impossibile trovare il vincolo dell'articolo di 1' livello"); TMSP_line2 *art2ndlev; currconstr->reset_unused_line2(); r = last; while (r>first) { TToken_string & curr_row=sf.row(r); // aggancia i master di 2' livello if (art2ndlev=currconstr->use_mspline2(curr_row)) do_test_art_2ndlevel(art2ndlev); else if (signal) message_box(FR("Impossibile determinare l'articolo Master per %s"),(const char*)currconstr->articolo()); r--; } while (art2ndlev=currconstr->get_unused_line2()) { do_test_art_2ndlevel(art2ndlev,true); currconstr->discard_line2(art2ndlev); } } return signal; } // // controlla la dipendenza tra articoli Master e dipendenti 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().codclifor(),mc->articolo() , mc->livello(), mc->codimp(), mc->codlin(), mc->codmagdep(), EMPTY_STRING, art2ndlev->constraint().da_rdoc_key()); if (master_constr==NULL) master_constr=_constraints.find(art2ndlev->constraint().codclifor(),mc->articolo(), mc->livello(), mc->codimp(), mc->codlin(), mc->codmagdep(), EMPTY_STRING, art2ndlev->constraint().da_rdoc_key()) ; 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(mrow+2, first, last, false); } } } // compatta le linee togliendo i doppioni bool TPlanning_mask::pack_article_sheet(int r, int first, int last) { TSheet_field& sf = sfield(F_ARTICOLI); TToken_string &art_row = sf.row(r); bool packed = false; for (int curr=last; curr >=first; curr--) if (curr != r) { TToken_string &curr_row=sf.row(curr); if (art_row.get_long(F_CLIENTE-FIRST_FIELD) == curr_row.get_long(F_CLIENTE-FIRST_FIELD)) if (TRiga_articolo::order_compare(art_row, curr_row,LAST_BUCKET)==0) { packed = true; TToken_string work_row = curr_row; for (int bucket=0; packed && bucket<=LAST_BUCKET ; bucket++) { real qta1(art_row.get(F_BUCKET1 + bucket*2 - FIRST_FIELD)); real qta2(work_row.get(F_BUCKET1 + bucket*2 - FIRST_FIELD)); real prz1(art_row.get(F_BUCKET1 +1 + bucket*2 - FIRST_FIELD)); real prz2(work_row.get(F_BUCKET1 +1 + bucket*2 - FIRST_FIELD)); if (!prz1.is_zero() && !qta2.is_zero() && prz1 != prz2) packed = false; if (qta2.is_zero()) work_row.add(prz1.string(), F_BUCKET1 + 1 + bucket*2 - FIRST_FIELD); qta2 += qta1; work_row.add(qta2.string(), F_BUCKET1 + bucket*2 - FIRST_FIELD); } if (packed) { curr_row = work_row; sf.destroy(r); } } } if (packed) { sf.select(first); sf.force_update(); } return packed; } // controllo linee in modo interattivo bool TPlanning_mask::test_art_row(int r, bool signal) { bool ok = true; TSheet_field& sf = sfield(F_ARTICOLI); int first,last; if (TRiga_articolo::find_block(sf, r, first, last)) { if (signal && pack_article_sheet(r, first+1, last)) TRiga_articolo::find_block(sf, first+1, first, last); TToken_string & curr_row=sf.row(r); const bool err = do_test_art_row(r, first, last, signal); if (signal) { // interactive mode: TMSP_line* line = _articles.find(curr_row, false); if (line) { real value,goodvalue; for (int b = 0 ; b < LAST_BUCKET; b++) { value = (curr_row.get(sf.cid2index(F_BUCKET0 + b*2))); goodvalue = line->qta_locked(b); if (!goodvalue.is_zero()) { if (value != goodvalue) { error_box(FR("Impossibile modificare la quantita' per l'articolo %s, colonna %d"),(const char *)line->articolo(),b); do_events(); ok = false; } } else { goodvalue = line->qta_min(b); if (value < goodvalue) { if (!get_bool(F_RESCHEDULING) || get_int(F_RESCHED_ALERT)) { TString msg (format(FR("%s %s confermati per l'articolo %s, colonna %d"),(const char *)line->qta_min(b).string(),(const char *)line->um(),(const char *)line->articolo(),b)); if (get_bool(F_RESCHEDULING)) { if (err) xvtil_statbar_set(msg); } else { error_box(msg); ok = false; } do_events(); } } } if (!ok) { curr_row.add(goodvalue.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); int c; for (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; TDate d = starting_date() + long(days_per_bucket() * (b-1)); round_date(d); err << TR("Riga ") << c+1 << TR(": capacitą superata al ") << d; beep(); signal = false; xvtil_statbar_set(err); } } if (signal) xvtil_statbar_set(""); return signal; } // 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 char * desc) { 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); } if (desc && *desc) { newrow.get(F_DESCART - FIRST_FIELD, str); const int pos = str.find('¦'); TString val(desc); if (pos >= 0) val << '¦' << str.mid(pos + 1); newrow.add(val, F_DESCART - FIRST_FIELD); } } int TPlanning_mask::salva_cella(int r, int b, TPlan_docs &doc_rows, TToken_string& save_opt ) { static long last_clifor = -1; static long act_clifor = -1; static TString *default_codmagdep=NULL; TSheet_field& sf = sfield(F_ARTICOLI); const int b0 = sf.cid2index(F_BUCKET0); const int um = sf.cid2index(F_UM); const TDate date_to = get(F_ADATA); const TDate from(starting_date()); 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); TDate datacons = from + long(bucket_size * (b-1)); //if (datacons > date_to) // return false; round_date(datacons, !bucket_mese()); TToken_string & row = sf.row(r); const TString80 art(row.get(F_ARTICOLO - FIRST_FIELD)); if (art.blank()) return false; TMSP_line &line = *_articles.find(row, true); TMRP_line *mrpline = NULL; TMSP_constraint *constraint = find_constraint(line); if (constraint != NULL) // Added by Guy { mrpline = _mrp_articles.find(constraint->articolo(), constraint->livgiac(), constraint->codmagdep(), "", constraint->codimp(), constraint->codlin(), constraint->codclifor(), constraint->da_rdoc_key()); } if ((*save_opt.get(F_DA_MAGAZZ-FIRST_FIELD)<=' ' || line.codmagdep() >= save_opt.get(F_DA_MAGAZZ-FIRST_FIELD)) && (*save_opt.get(F_A_MAGAZZ-FIRST_FIELD)<=' ' || line.codmagdep() <= save_opt.get(F_A_MAGAZZ-FIRST_FIELD)) && (*save_opt.get(F_DA_IMPIANTO-FIRST_FIELD)<=' ' || line.codimp() >= save_opt.get(F_DA_IMPIANTO-FIRST_FIELD)) && (*save_opt.get(F_A_IMPIANTO-FIRST_FIELD)<=' ' || line.codimp() <= save_opt.get(F_A_IMPIANTO-FIRST_FIELD))) { const TString4 new_tipodoc(save_opt.get(F_TIPO_PLAN-FIRST_FIELD)); const TString4 new_codnum(save_opt.get(F_NUM_PLAN-FIRST_FIELD)); TDate datadoc = datacons; switch (get(F_LEADTIME)[0]) { case 'I': // leadtime gia' calcolato sugli input datacons += cache().get(LF_ANAMAG,line.articolo()).get_real(ANAMAG_GIORNIRIOR).integer(); break; case 'O': // leadtime da calcolare sugli output datadoc -= cache().get(LF_ANAMAG,line.articolo()).get_real(ANAMAG_GIORNIRIOR).integer(); break; default: break; } round_date(datadoc); int new_anno = datadoc.year(); int new_week = datadoc.week(); if (number_by_week) get_week_year(datadoc, new_week, new_anno); const long new_numdoc = (number_by_cli ? line.codclifor() * 100L : 0L)+ (number_by_week ? new_week : 0L); const int new_numrig = 0; TString4 codnum; int anno = 0; long numdoc = 0L; int numrig = 0; real val,new_val(row.get(b0 + b*2)); if (mrpline && mrpline->last_bucket() >= b-1) { // ************* // rescheduling checks const real & pl = mrpline->planned_orders(b-1); const real & sr = mrpline->sched_receipts(b-1); const real & uo = mrpline->unsched_orders(b-1); const real & ro = mrpline->resched_orders(b-1); if (new_val.sign() > 0) // devo pianificare qualcosa... { const real movable = ro - uo; if (!movable.is_zero()) // ... ma posso spostare la qta da altrove { const real moved = fnc_min(new_val, movable); new_val -= moved; mrpline->record(b-1).add_unsched_ord(moved); } } } TMRP_docref *rdr = line.first_rigaref(b); bool found = false; while (rdr || !found && new_val.sign() > 0) { if (rdr==NULL && !found) { found = true; rdr = new TMRP_docref(new_anno,new_codnum,new_numdoc,new_numrig,row.get(sf.cid2index(F_UM)),ZERO,ZERO); line.add_rigaref(b, rdr); } const real old_val = rdr->qta_residua(); codnum = rdr->codnumdoc(); anno = rdr->annodoc(); numdoc = rdr->numdoc(); numrig = rdr->numrig(); if (rdr->codnumdoc() == 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)) { const long old_priority = line.priority(); const long priority = row.get_long(sf.cid2index(F_PRIORITA)); const TString8 old_codlin(line.codlin()); TString8 codlin(row.get(sf.cid2index(F_CODLIN))); codlin.trim(); val = new_val; new_val = ZERO; if (val != old_val || codlin != old_codlin || priority != old_priority) // c'e' una modifica da salvare { // determina il codice cliente/fornitore act_clifor = row.get_long(sf.cid2index(F_CLIENTE)); if (last_clifor >= 0 && last_clifor != act_clifor) doc_rows.flush(datacons, NULL); last_clifor = act_clifor; // inserisce la riga di documento const real incr = val - old_val; TRiga_documento& riga = doc_rows.add_to_row(rdr, incr); if (priority > 0) riga.put(RDOC_PRIORITY, priority); riga.put(RDOC_LINEA, codlin); if (riga.get(RDOC_CODART).empty()) { riga.put(RDOC_CODART, line.articolo()); riga.put(RDOC_CODARTMAG, line.articolo()); riga.put(RDOC_LIVELLO, line.livgiac()); riga.put(RDOC_CHECKED, "X"); if (!line.codmagdep().blank()) riga.put(RDOC_CODMAG, line.codmagdep()); else { if (default_codmagdep==NULL) { default_codmagdep = new TString8(); add_magcode(*default_codmagdep,_magazzini.standardmag()); add_depcode(*default_codmagdep,_magazzini.standarddep()); } riga.put(RDOC_CODMAG, *default_codmagdep); } riga.put(RDOC_CODMAGC, line.codmagdep_coll()); riga.put(RDOC_IMPIANTO, line.codimp()); riga.put(RDOC_UMQTA, row.get(sf.cid2index(F_UM))); riga.put(RDOC_DATACONS, datacons); TString descr(line.description()); if (descr.blank()) descr = cache().get(LF_ANAMAG, line.articolo(), ANAMAG_DESCR); riga.put(RDOC_DESCR, descr); TMSP_constraint *c = find_constraint(line); if (c != NULL) { const TRectype* dardoc = NULL; for (int buck = b; (dardoc == NULL) && (buck < LAST_BUCKET); buck++) { const int refs = c->rigarefs(buck); if (refs > 0) { const TMRP_docref* dr = c->rigaref(buck, 0); dardoc = &dr->get_rdoc(); } } if (dardoc == NULL && b > 0) { for (int buck = b - 1; (dardoc == NULL) && (buck >= 0); buck--) { const int refs = c->rigarefs(buck); if (refs > 0) { const TMRP_docref* dr = c->rigaref(buck, 0); dardoc = &dr->get_rdoc(); } } } if (dardoc != NULL) { const int depth = get_int(F_RIFERIMENTO_MSP); riga.set_original_rdoc_key(*dardoc, depth); riga.put(RDOC_QTAGG5, dardoc->get_int(RDOC_QTAGG5)); // Per ora memorizziamo in QTAGG5, scelto a caso } else { TString msg; msg.format(FR("Riferimento non trovato : riga %d"), r); xvtil_statbar_set(msg); beep(); } } else { TString msg; msg.format(FR("Vincolo non trovato : riga %"), r); xvtil_statbar_set(msg); beep(); } TRectype& doc = (TRectype&)riga.doc().head(); if (doc.get(DOC_DATACONS).empty()) { doc.put(DOC_DATACONS, datacons); doc.put(DOC_TIPOCF, get(F_TIPOCF)); doc.put(DOC_CODCF, line.codclifor()); } doc.put(DOC_DATADOC, from); // Calcola codice iva per la riga in base al fornitore o all'articolo TString16 cod; cod.format("%c|%ld", get(F_TIPOCF)[0], line.codclifor()); cod = cache().get(LF_CFVEN, cod, CFV_ASSFIS); if (cod.empty()) cod = cache().get(LF_ANAMAG, line.articolo(), ANAMAG_CODIVA); riga.put(RDOC_CODIVA, cod); } if (val == ZERO) { line.remove_rigaref(b); enable_codes(r); } else { line.qta(b) -= old_val; line.qta(b) += rdr->qta_residua(); disable_codes(r); } sf.force_update(r); } } else { //if (new_anno==anno && new_codnum==codnum && new_numdoc==numdoc) new_val -= old_val; } } else found = true; rdr=line.next_rigaref(b); } // ciclo di aggiornamento dei riferimenti ai docs return 1; } // filtro sulle righe return 0; } int TPlanning_mask::salva_documenti(TExceptions_array &excepts, TSheet_field & save_opt) { TAssoc_array error_on_row; int some=0,somefilter=0; for (int saveit=save_opt.items()-1; saveit>=0; saveit--) { TToken_string& save_opt_row = save_opt.row(saveit); if (*save_opt_row.get(save_opt.cid2index(F_SEL4SAVE)) > ' ') { somefilter++; const TString4 save_numplan (save_opt_row.get(F_NUM_PLAN-FIRST_FIELD)); const TString4 save_tipoplan (save_opt_row.get(F_TIPO_PLAN-FIRST_FIELD)); const TString4 save_rigaplan (save_opt_row.get(F_RIGA_PLAN-FIRST_FIELD)); const bool clifo_is_optional = cache().get("%TIP",save_opt_row.get(F_TIPO_PLAN-FIRST_FIELD)).get_bool("B5"); TPlan_docs doc_rows(save_numplan, save_tipoplan, save_rigaplan); const TSheet_field& sf = sfield(F_ARTICOLI); const int b1 = sf.cid2index(F_BUCKET1); const TDate from(starting_date()); const bool ordiniXarticolo = get_bool(F_DIVIDEBYART); const bool ordiniXscadenza = get_bool(F_DIVIDEBYDATE); if (ordiniXscadenza && ordiniXarticolo) if (!noyes_box(TR("E' stato scelto di generare un ordine diverso per ogni articolo e scadenza: confermare?"))) return 0; if (!(ordiniXscadenza || ordiniXarticolo)) if (!noyes_box(TR("E' stato scelto di generare un unico ordine per ogni articolo e scadenza: confermare?"))) return 0; TProgind pi(LAST_BUCKET*sf.items(), TR("Emissione documenti") , false, true); if (ordiniXscadenza) { // ************************* // Generazione per scadenza: long act_clifor =-1 ; long last_clifor =-1 ; for (int b = 1; b < LAST_BUCKET; b++) { long recs=0L; TDate datacons = from + long(days_per_bucket() * (b-1)); round_date(datacons); FOR_EACH_SHEET_ROW(sf, r, row) { pi.addstatus(1); if (!sf.cell_disabled(r, b1)) if (clifo_is_optional || row->get_long(F_CLIENTE-FIRST_FIELD)) salva_cella(r, b, doc_rows, save_opt_row); else { TString8 key; key.format("%d",r); if (row->get_long(F_BUCKET0+b-FIRST_FIELD)!=0L && !error_on_row.is_key(key)) { error_box(FR("Riga %d: manca l'indicazione del codice %s"),r+1,get(F_TIPOCF)[0] == 'F' ? "fornitore" : "cliente"); error_on_row.add(key,NULL); } } if (ordiniXarticolo) recs = doc_rows.flush(datacons, row->get(sf.cid2index(F_ARTICOLO))); } pi.addstatus(1); if (!ordiniXarticolo) recs += doc_rows.flush(datacons, NULL); if (recs > 0L) some += 1; else if (recs < 0L) some = -1; } } else { // ************************* // Generazione per articolo: FOR_EACH_SHEET_ROW(sf, r, row) if (!sf.cell_disabled(r, b1)) { for (int b = 1; b < LAST_BUCKET; b++) { pi.addstatus(1); if (row->get_long(F_CLIENTE-FIRST_FIELD) || cache().get("%TIP",save_opt_row.get(F_TIPO_PLAN-FIRST_FIELD)).get_bool("B5")) salva_cella(r, b, doc_rows, save_opt_row); else { TString8 key; key.format("%d",r); if (row->get_long(F_BUCKET0+b-FIRST_FIELD)!=0L && !error_on_row.is_key(key)) { error_box(FR("Riga %d: manca l'indicazione del codice %s"),r+1,get(F_TIPOCF)[0] == 'F' ? "fornitore" : "cliente"); error_on_row.add(key,NULL); } } } long recs = 0L; if (ordiniXarticolo) recs = doc_rows.flush(NULLDATE,row->get(sf.cid2index(F_ARTICOLO))); if (recs > 0L) some += 1; else if (recs < 0L) some = -1; } if (!ordiniXarticolo) some = int(doc_rows.flush(NULLDATE,"")); } switch (some) { case 0: message_box(FR("Nessun documento generato o modificato \n(numerazione %s, tipo %s)"), (const char *)save_numplan,(const char *)save_tipoplan); break; case -1: if (!yesno_box(FR("Problemi nella registrazione dei documenti.\n(numerazione %s, tipo %s)\nRipeto l'elaborazione ?"), (const char *)save_numplan,(const char *)save_tipoplan)) some = 0; break; } } } if (somefilter == 0) message_box(TR("Nessuna opzione di registrazione selezionata")); return some; } bool TPlanning_mask::on_savefields_event(long jolly) { TSheet_field & sf = sfield(F_SAVE_OPT); int nriga = jolly>=0 ? (int)jolly : sf.items()-1; TString4 tmp; do { { tmp = sf.row(nriga).get(sf.cid2index(F_NUM_PLAN)); if (tmp.blank()) return true; const TSheet_field& num_s = sfield(F_NUM_PLA); FOR_EACH_SHEET_ROW_BACK(num_s, r, row) if (tmp == row->get(num_s.cid2index(F_NUMERAZ))) break; if (r < 0) return sf.error_box(FR("Numerazione '%s' non inclusa tra quelle di planning"), (const char *)tmp); } { tmp = sf.row(nriga).get(sf.cid2index(F_TIPO_PLAN)); const TSheet_field& tipo_s = sfield(F_TIPI_PLA); FOR_EACH_SHEET_ROW_BACK(tipo_s, r, row) if (tmp == row->get(tipo_s.cid2index(F_TIPO))) break; if (r < 0) return sf.error_box(FR("Tipo documento '%s' non incluso tra quelli di planning"), (const char *)tmp); } } while (--nriga >= 0 && jolly < 0); return true; } bool TPlanning_mask::on_field_event(TOperable_field& o, TField_event e, long jolly) { const char * confirm_msg=FR("Le modifiche non registrate sulle attuali %d linee di articoli verranno perse: confermare?"); switch (o.dlg()) { case F_DADATA: if (e == fe_modify) { _start_date = NULLDATE; round_field(o, false); } break; case F_ADATA: if (e == fe_modify) round_field(o, true, false); break; case F_BUCKET: if (e == fe_modify) { on_field_event((TOperable_field& )field(F_DADATA), fe_modify, jolly); on_field_event((TOperable_field& )field(F_ADATA), fe_modify, jolly); } 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(TR("E' necessario inserire almeno una riga")); } break; case F_SAVE_OPT: if (e == se_leave) on_savefields_event(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, ""); int rconstr = TRiga_articolo::find_block_constr(s, nriga); TToken_string& constr = s.row(rconstr); if (constr.get_long(s.cid2index(F_CLIENTE))) s.disable_cell(nriga,s.cid2index(F_CLIENTE)); } break; case se_leave: if (nriga >= 0 && nriga < righe) { const TToken_string &art_row = s.row(nriga); if (_curr_art_row != art_row) { const bool ok = test_art_row(nriga); if (!ok) _curr_art_row.cut(0); else _curr_art_row = s.row(nriga); 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: { 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 H_CODIMP: if (e == fe_modify) { const TSheet_field& s = sfield(F_ARTICOLI); TMask & m=s.sheet_mask(); if (!m.get(F_CODLIN).blank()) m.set(F_CODIMP,o.get()); } break; case F_CODIMP: if (jolly == 6 && e == fe_modify) { const TString & val = o.get(); if (!val.empty()) { const TSheet_field& s = sfield(F_ARTICOLI); TMask & m = s.sheet_mask(); TImpianto &unita_prod=*::get_impianto(val); if (m.get(F_MAGAZZINO).blank()) { TString8 codmagdep(unita_prod.codmagdep()); if (!codmagdep.blank()) { m.set(F_MAGAZZINO,::get_magcode(codmagdep)); m.set(F_DEPOSITO,::get_depcode(codmagdep)); } } if (*unita_prod.codmagdep_coll()>' '&& m.get(F_MAG_COLL).blank()) { TString8 codmagdep_coll(unita_prod.codmagdep_coll()); if (!codmagdep_coll.blank()) { m.set(F_MAG_COLL,::get_magcode(codmagdep_coll)); m.set(F_DEP_COLL,::get_depcode(codmagdep_coll)); } } } } break; case F_CODLIN: if (jolly == 6 && e == fe_modify) { const TString & val = o.get(); if (!val.empty()) { const TSheet_field& s = sfield(F_ARTICOLI); TMask & m = s.sheet_mask(); TLinea_prod &unita_prod=*::get_linea(val); if (m.get(F_MAGAZZINO).blank()) { TString8 codmagdep(unita_prod.codmagdep()); if (!codmagdep.blank()) { m.set(F_MAGAZZINO,::get_magcode(codmagdep)); m.set(F_DEPOSITO,::get_depcode(codmagdep)); } } if (*unita_prod.codmagdep_coll()>' '&& m.get(F_MAG_COLL).blank()) { TString8 codmagdep_coll(unita_prod.codmagdep_coll()); if (!codmagdep_coll.blank()) { m.set(F_MAG_COLL,::get_magcode(codmagdep_coll)); m.set(F_DEP_COLL,::get_depcode(codmagdep_coll)); } } } } break; case F_MAGAZZINO: if (jolly == 6 && e == fe_modify) { const TSheet_field& s = sfield(F_ARTICOLI); TMask & m = s.sheet_mask(); if (m.get(F_MAGAZZINO).blank()) { TString8 codmagdep(_magazzini.standardmag()); m.set(F_MAGAZZINO,::get_magcode(codmagdep)); m.set(F_DEPOSITO,::get_depcode(codmagdep)); } if (m.get(F_MAGAZZINO).blank()) m.set(F_DEPOSITO,""); } break; case F_DEPOSITO: if (jolly == 6 && e == fe_modify) { const TSheet_field& s = sfield(F_ARTICOLI); TMask & m = s.sheet_mask(); if (m.get(F_DEPOSITO).blank()) { // controla se il magazzino richiede dep if (_magazzini.get(m.get(F_MAGAZZINO)).get_bool("B0")) return false; } } 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: case F_BUCKET13: case F_BUCKET14: case F_BUCKET15: case F_BUCKET16: case F_BUCKET17: case F_BUCKET18: case F_BUCKET19: case F_BUCKET20: case F_BUCKET21: case F_BUCKET22: case F_BUCKET23: case F_BUCKET24: case F_BUCKET25: case F_BUCKET26: case F_BUCKET27: case F_BUCKET28: case F_BUCKET29: case F_BUCKET30: 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()); if (qta != ZERO) highlight(s.selected(), o.dlg(), true, false); } break; case DLG_CANCEL: if (e == fe_button) if (jolly == 0L) { TSheet_field& s = sfield(F_ARTICOLI); int lineeart=s.items(); if (lineeart==0 || !s.dirty() || yesno_box(confirm_msg,lineeart)) { clear_sheets(); } else return false; } break; case DLG_ELABORA: if (e == fe_button ) { 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 if (check_fields()) { TSheet_field& s = sfield(F_ARTICOLI); const int lineeart = s.items(); if (lineeart==0 || !s.dirty() || yesno_box(confirm_msg,lineeart)) { if (get_int(F_YEAR)==0) { set(F_YEAR,get_date(F_DADATA).ok() ? get_date(F_DADATA).year() :TDate(TODAY).year()); on_field_event((TOperable_field&)field(F_YEAR), fe_modify, jolly ); } elabora(); } // Controlla se e' stato richiesto il salvataggio automatico e se posso salvare if (main_app().argc() >= 2 && field(DLG_SAVEREC).active()) { TString param = main_app().argv(2); param.upper(); if (param.find("AUTOR") > 0) // Lancia salvataggio batch send_key(K_CTRL+'R', 0); } } } 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(); propose(); on_field_event((TOperable_field&)field(F_LOADTYPE), fe_modify, 0L); 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) { TPrint_mask pm(*this); while (pm.run() != K_ESC) ; } break; case F_RECALCLINE: if (e == fe_button) { TSheet_field& s = sfield(F_ARTICOLI); int curr_row=s.selected(); s.update_row(curr_row); propose(curr_row); s.update_mask(curr_row); } break; case F_CHECKLINE: if (e == fe_button) { TSheet_field& s = sfield(F_ARTICOLI); TMSPCheck_mask cm(this); cm.disable(-G_MOVIMENTO); int curr_row=s.selected(); s.update_row(curr_row); 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_DOCUMENTI_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_docref m(l,TR("Documenti pianificati"), starting_date(), days_per_bucket()); if (m.reset_bucket_field()) { if (m.run() != K_ESC) m.edit_checked(); } return true; } message_box(TR("Nessun ordine pianificato per la riga corrente")); } break; case F_DOCUMENTI_IN: case F_VINCOLI_IN: case F_VINCOLI_OUT: 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) { switch (o.dlg()) { case F_DOCUMENTI_IN: { TLista_docref m(c,TR("Documenti vincolo"),starting_date(), days_per_bucket()); if (m.reset_bucket_field()) { if (m.run()!= K_ESC) m.edit_checked(); return true; } } break; case F_VINCOLI_IN: { TLista_upperlines m(c,starting_date(), days_per_bucket()); if (m.reset_bucket_field()) m.run(); else message_box(TR("Nessun vincolo interno sulla riga corrente")); return true; } break; case F_VINCOLI_OUT: { TLista_mastercodes m(c, s.row(s.selected()), starting_date(), days_per_bucket()); if (m.reset_bucket_field()) m.run(); else message_box(TR("Nessun articolo Master dipendente dalla riga corrente")); return true; } break; } } message_box(TR("Nessun vincolo per la riga corrente")); } 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 && s.dirty() && !yesno_box(confirm_msg,lineeart)) return false; } break; case F_SHRINK_ALL: case F_ZOOM_ALL: if (e == fe_button) { TSheet_field& s = sfield(F_ARTICOLI); const int size = o.dlg() == F_SHRINK_ALL ? 1 : -1; int first_master = -1; FOR_EACH_SHEET_ROW(s, i, row) { const bool is_child = s.cell_disabled(i, 18); if (is_child) s.set_row_height(i, size); else { if (first_master < 0) first_master = i; } } if (size == 1 && first_master > 0) s.select(first_master, true); else s.select(0, true); } break; case F_SHRINK_ROW: case F_ZOOM_ROW: if (e == fe_button) { TSheet_field& s = sfield(F_ARTICOLI); const int r = s.selected(); if (r > 0 && r < s.items()) { const int size = o.dlg() == F_SHRINK_ROW ? 1 : -1; int i = r-1; for (; i >= 0; i--) { const bool is_child = s.cell_disabled(i, 18); if (is_child) s.set_row_height(i, size); else break; } s.select(size < 0 ? i+1 : r, true); } } break; case F_PRIORITY_ST: if (e == fe_button && yesno_box(TR("Si desidera rinumerare automaticamente le priorita'?"))) { TSheet_field& s = sfield(F_ARTICOLI); const int pri_pos = s.cid2index(F_PRIORITA); int priority = 0; for(int i = s.items()-1; i >= 0; i--) { priority += 2; int nf = -1, nl = -1; const bool nextok = TRiga_articolo::find_block(s, i, nf, nl); nf--; if (nextok && nf >= 0 && nl >= 0) { for (int j = nf ; j <= i; j++) s.row(j).add(priority, pri_pos); } i = nf; } s.force_update(); } break; case F_PRIORITY_HI: case F_PRIORITY_LO: if (e == fe_button) { TSheet_field& s = sfield(F_ARTICOLI); const int curr = s.selected(); int cf = -1, cl = -1; const bool currok = TRiga_articolo::find_block(s, curr, cf, cl); cf--; if (currok) { const int next = o.dlg() == F_PRIORITY_LO ? cl+1 : cf-1; int nf = -1, nl = -1; const bool nextok = TRiga_articolo::find_block(s, next, nf, nl); nf--; if (nextok && cf != nf) // Scambio possibile solo su due gruppi distinti { if (get_int(F_MSP_SORT) == 7) // Sort by line/priority/ecc.. { const int lin_pos = s.cid2index(F_SORTCODLIN); TString8 old_lin; s.row(cf).get(lin_pos, old_lin); TString8 new_lin; s.row(nf).get(lin_pos, new_lin); if (old_lin != new_lin) return warning_box(TR("Non e' possibile scambiare prodotti su linee diverse")); } const int pri_pos = s.cid2index(F_PRIORITA); const long old_pri = s.row(cl).get_long(pri_pos); const long new_pri = s.row(nl).get_long(pri_pos); TArray& a = s.rows_array(); TPointer_array old_rows, new_rows; int i; for (i = cf; i <= cl; i++) { s.row(i).add(new_pri, pri_pos); old_rows.add(a.remove(i)); } for (i = nf; i <= nl; i++) { s.row(i).add(old_pri, pri_pos); new_rows.add(a.remove(i)); } for (i = cf; i <= cl; i++) { const int j = i-cf; a.add(old_rows.remove(j), nf+j); s.force_update(nf+j); } for (i = nf; i <= nl; i++) { const int j = i-nf; a.add(new_rows.remove(j), cf+j); s.force_update(cf+j); } set_focus_field(F_ARTICOLI); // SOLO cosi' la riga riprende il focus ... s.select(nl, 0); // ... "forzato" da questa chiamata } } } break; default: break; } return true; } TPlanning_mask::TPlanning_mask(const char * name) : TCalendar_mask(name), _sel_color(sfield(F_ARTICOLI)) { init(); } TPlanning_mask::TPlanning_mask() : TCalendar_mask("mr2200a"), _sel_color(sfield(F_ARTICOLI)) { init(); } static bool handle_subcodice(TMask_field &fld, KEY k) { TMask &mask=fld.mask(); if (k == K_TAB && (fld.focusdirty()||!mask.is_running())) //c'e' qualcosa nel campo { //quale e' l'ultimo campo valido per codart in multilevel? short id_last = fld.dlg(); while (id_last <= F_LIVART9 && mask.id2pos(id_last+1) > 0) id_last++; if (fld.empty()) { //gira su tutti i campi di livart esistenti e successivi al livello corrente for(short id = fld.dlg()+1; id <= id_last; id++) { mask.set(id, ""); mask.disable(id); } } else { const int pos = mask.id2pos(fld.dlg()+1); if (pos > 0) { TMask_field& next_fld = mask.fld(pos); next_fld.enable(); } } //riempie in automatico il campo codice complessivo TString80 stringone; bool completo = true; for(short id = F_LIVART1; id <= id_last; id++) { const TString& val = mask.get(id); if (val.blank()) { completo = false; break; } stringone << val; } mask.set(F_CODART, stringone, fld.dlg()==id_last ? 0x3 : 0x0); } return true; } static bool handle_codice(TMask_field &fld, KEY k) { if (k == K_TAB && fld.focusdirty() && !fld.empty()) { TSheet_field& sheet = fld.mask().sfield(F_ARTICOLI); bool found = false; FOR_EACH_SHEET_ROW(sheet, i, row) { if (fld.get() == row->get(2)) { sheet.select(i); found = true; break; } } if (!found) fld.error_box(TR("Articolo non pianificato")); } return true; } static bool handle_interval(TMask_field &fld, KEY k) { if (fld.to_check(k, true)) { TPlanning_mask & m = ((TPlanning_mask &)fld.mask()); const TDate & from = m.get_date(F_DADATA); TDate to(m.get_date(F_DADATA)); int days = m.days_per_bucket(); if (days < 7) days = 7; to += days; m.calendar().set_highlight_interval(from, to); } return true; } void TPlanning_mask::create_browse1(TEdit_field& kfld, int level, short key_id, short des_id, const TCodart_livelli &cal) { TFilename tmp; tmp.temp(); ofstream out(tmp); out << "USE GCA" << endl; //usa la tabella dei livelli articolo const short id = key_id + level - 1; const TString& prompt = cal.name(level); const TString& picture = cal.picture(level); out << "IN CODTAB[1,1] \"" << level << "\"" << endl; out << "IN CODTAB[2,0] " << id << endl; out << "DI \"" << prompt; const int length = cal.code_length(level); if (length > prompt.len()) out << '@' << length; out << "\" CODTAB[2,0]" << endl; out << "DI \"" << TR("Descrizione") << "@50\" S0" << endl; out << "OU " << id << " CODTAB[2,0]" << endl; out << "OU " << (des_id + level -1) << " S0" << endl; out << "EN" << endl; out.close(); TScanner scan(tmp); while (scan.pop() != "EN") kfld.parse_item(scan); xvt_fsys_removefile(tmp); } void TPlanning_mask::create_browse2(TEdit_field& kfld, int level, short key_id, short des_id, const TCodart_livelli &cal) { TFilename tmp; tmp.temp(); ofstream out(tmp); out << "USE GCA KE 2 SELECT CODTAB[1,1]=='" << level << "'" << endl; //cerca per descrizione const short id = des_id + level - 1; out << "IN S0 " << id << endl; out << "DI \"" << TR("Descrizione") << "@50\" S0" << endl; const TString& prompt = cal.name(level); out << "DI \"" << prompt; const int length = cal.code_length(level); if (length > prompt.len()) out << '@' << length; out << "\" CODTAB[2,0]" << endl; out << "CO OU " << (key_id + level -1) << endl; out << "EN" << endl; out.close(); TScanner scan(tmp); while (scan.pop() != "EN") kfld.parse_item(scan); xvt_fsys_removefile(tmp); } int TPlanning_mask::create_codart_fields(int x, int y, short key_id, short des_id) { const TCodart_livelli cal; const int last_level = cal.last_level(); int tab0 = x; int i; for (i = 1; i <= last_level; i++) //cicla su tutti i livelli del codart abilitati { // codice livello articolo const short kid = key_id+i-1; const TString& picture = cal.picture(i); TString4 flags = "BU"; if (picture[0] == '0') flags << 'Z'; TEdit_field& kfld = add_string(kid, 3, "", tab0, y, picture.len(), flags); kfld.set_key(1); create_browse1(kfld, i, key_id, des_id, cal); kfld.set_handler(handle_subcodice); tab0 += picture.len()+3; } for (i = 1; i <= last_level; i++) { // descrizione livello articolo const short did = des_id+i-1; TEdit_field& dfld = add_string(did, 3, "", 200, y, 50, "", 50); dfld.set_key(1); create_browse2(dfld, i, key_id, des_id, cal); } return cal.last_level(); } void TPlanning_mask::init() { TSheet_field& sf = sfield(F_ARTICOLI); sf.set_append(false); for (short l = 0; l < 4; l++) livelli_giacenza().set_sheetcolumn(sf, F_LIV1+l, l+1); create_codart_fields(10, 4, F_LIVART1, F_DESART1); set_handler(F_CODART, handle_codice); set_handler(F_DADATA, handle_interval); set_handler(F_BUCKETS, handle_interval); 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); } _week_complete = ini.get_bool("WEEKCOMPLETE", "mr"); _standard_for = ini.get_long("CODFOR", "mr"); sfield(F_LINEE).disable(); // sfield(F_TESTE).disable(); load_profile(); _npr_pos =_sel_color.add_color_def("PROP", TR("Nuove proposte"), COLOR_YELLOW, COLOR_BLACK); _con_pos =_sel_color.add_color_def("CONST", TR("Vincoli speciali"), blend_colors(COLOR_WHITE, COLOR_YELLOW, 0.60), COLOR_BLACK); TCalendar_field & cf = (TCalendar_field &) field(F_CALENDAR); cf.set_immediate_write(); } 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)) { livelli_giacenza().set_mask_fields(*this, FC_LIV1); _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; TString80 da_rdoc_key; _main_mask->msprow2codes(row, codcli, codart, liv, mag, magc, codimp, codlin, um, da_rdoc_key); TArticolo_giacenza art(codart); if (_last_row!=_row) { _constr_row=find_constr_row(_row); set(FC_RIGA,_row+1); field(FC_CODCLI).set_prompt(_main_mask->get(F_TIPOCF)[0]=='C' ? "Cliente":"Fornitore"); set(FC_CODCLI,codcli, true); set(FC_CODART,codart, true); for (int l= livelli_giacenza().last_level(); l >= 1 ; l--) set(FC_LIV1+l-1, livelli_giacenza().unpack_grpcode(liv,l), 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->starting_date()); data_buck += (_main_mask->days_per_bucket())*(_col); _main_mask->round_date(data_buck); data_buck -= 1; set(FC_DATE2,_col==LAST_BUCKET ? "" : data_buck.string()); _main_mask->round_date(data_buck); 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, da_rdoc_key); TMSP_line* old_article = _main_mask->find_article(codcli, codart, liv, codimp, codlin, mag, magc, da_rdoc_key); 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; } soglia = soglia -0.01; 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; residuo.round(2); 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 >= 0 ? row : 0; _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; default: 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(TR("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(TR("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; default: 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->starting_date()); data_buck += (_main_mask->days_per_bucket())*(_col-1); _main_mask->round_date(data_buck); set(FC_DATE1,data_buck.string()); _main_mask->round_date(data_buck,true); set(FC_DATE2,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=capacitysel(); s.run(); } else ok = TSkeleton_application::menu(mt); return ok; } void TPlanning_app ::openfiles() { open_files(LF_TABCOM, LF_TAB, LF_DOC, LF_RIGHEDOC, LF_CLIFO, LF_CFVEN, LF_OCCAS, LF_INDSP, LF_CONDV, LF_MAG, LF_MOVMAG, LF_RMOVMAG, LF_ANAMAG, LF_DIST, LF_RDIST, LF_MRPREPORT, 0); } bool TPlanning_app ::create() { openfiles(); _m = new TPlanning_mask(); _m->field(F_MSCHEDULEPLAN).set(" "); return TSkeleton_application::create(); } 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); } if (argc() > 1) // Controllo automatismi { TString param = argv(2); param.upper(); if (param.find("AUTO") > 0) mask().send_key(K_CTRL+'L', 0); // Lancia elaborazione batch } while (mask().run()!=K_QUIT) ; } int mr2200(int argc, char* argv[]) { TPlanning_app a; a.run(argc, argv, TR("Pianificazione ordini")); return 0; }