#include #include #include #include #include #include #include #include #include "..\mg\anamag.h" #include "..\mg\codcorr.h" #include "..\ve\veconf.h" #include #include #include "mr2100.h" #include "mr2100a.h" #include "mr2100c.h" #define NODIST "NODIST" /////////////////////////////////////////////////////////// // Utility /////////////////////////////////////////////////////////// static bool is_production_article(const TCodice_articolo& codart) { const TRectype& rec=cache().get(LF_DIST, codart); bool art_prod = false; if (rec.empty()) art_prod = cache().get(LF_ANAMAG, codart).get_bool(ANAMAG_ARTPROD); else art_prod = rec.get_bool(ANAMAG_ARTPROD); return art_prod; } /////////////////////////////////////////////////////////// // TMRP_record /////////////////////////////////////////////////////////// void TMRP_record::add_ref(TMRP_docref* ref, TMRP_docrefs* &refs) { if (ref != NULL) { if (refs == NULL) refs = new TMRP_docrefs; refs->add(ref); } } const real& TMRP_record::add_gross_req(const real& val, TMRP_internalref * ref) { if (_internal_req == NULL) _internal_req = new TMRP_internalrefs; _internal_req->add(ref); return add_gross_req(val); } const real& TMRP_record::add_gross_req(const real& val, TMRP_docref * ref) { add_ref(ref, _requirements); _gross_requirement += val; return _gross_requirement; } const real& TMRP_record::add_sched_rec(const real& val, TMRP_docref * ref) { add_ref(ref, _scheduls); _sched_receipts += val; return _sched_receipts; } const real& TMRP_record::add_planned_ord(const real& val, TMRP_docref * ref) { add_ref(ref, _plans); _planned_orders += val; return _planned_orders; } const real& TMRP_record::add_resched_ord(const real& val) { _resched_orders += val; return _resched_orders; } const real& TMRP_record::add_unsched_ord(const real& val) { _unsched_orders += val; return _unsched_orders; } const real& TMRP_record::add_net_req(const real& val) { _net_requirement += val; return _net_requirement; } TObject * TMRP_record::dup() const { TMRP_record *o= new TMRP_record(_time); o->TMRP_record::operator=(*this); return o; } TMRP_record & TMRP_record::operator=(const TMRP_record& a) { _gross_requirement=a._gross_requirement; _on_hand=a._on_hand; _sched_receipts=a._sched_receipts; _net_requirement=a._net_requirement; _planned_orders=a._planned_orders; _resched_orders=a._resched_orders; if (a._plans) _plans = (TMRP_docrefs *)a._plans->dup(); if (a._scheduls) _scheduls = (TMRP_docrefs *)a._scheduls->dup(); if (a._requirements) _requirements = (TMRP_docrefs *)a._requirements->dup(); if (a._internal_req) _internal_req = (TMRP_internalrefs *)a._internal_req->dup(); return *this; } TMRP_record::TMRP_record(const TMRP_time& t) : _time(t) { _plans = NULL; _scheduls = NULL; _requirements = NULL; _internal_req = NULL; } /////////////////////////////////////////////////////////// // TMRP_line /////////////////////////////////////////////////////////// TArticolo_giacenza *TMRP_line::_articolo_giac = NULL; // Stringa temporanea di lavoro static TString16 _sub; const TString& TMRP_line::codmag() const { return _sub = _codmag.left(3); } const TString& TMRP_line::codmagaz_coll() const { return _sub = _codmag_coll.left(3); } const TString& TMRP_line::coddep() const { return _sub = _codmag.mid(3); } const TString& TMRP_line::coddep_coll() const { return _sub = _codmag_coll.mid(3); } const TString& TMRP_line::livgiac(int l) const { const TCodgiac_livelli& lg = livelli_giacenza(); return _sub = _livgiac.mid(lg.code_start(l)-1, lg.code_length(l)); } void TMRP_line::lotti_riordino(real& minimo, real& increm) const { _articolo_giac->read(_codart); const int i=_articolo_giac->find_mag("", _codmag); if (i>=0) { const TRectype & rec=_articolo_giac->mag("").row(i); minimo = rec.get_real(MAG_LOTTORIOR); increm = rec.get_real(MAG_LOTTOIRIOR); } else minimo=increm=0; if (minimo.is_zero()) minimo = _articolo_giac->get_real(MAG_LOTTORIOR); if (increm.is_zero()) increm = _articolo_giac->get_real(MAG_LOTTOIRIOR); } int TMRP_line::add_son(const real& qta, TMRP_line* son) { CHECK(son, "Can't add NULL TMRP_line son"); if (son == this) fatal_box(FR("Riga di MRP %sz %s padre di se stessa"), (const char *)articolo(), (const char *)livgiac()); CHECK(son != this, "Hermafrodite TMRP_line"); _qta_sons.add(qta); return _sons.add(son); } bool TMRP_line::is_son(const TCodice_articolo& art) const { int i; for (i = sons()-1; i >= 0; i--) { const TMRP_line& r = son(i); if (r.articolo() == art) break; } return i >= 0; } int TMRP_line::compare(const TSortable& s) const { const TMRP_line& line = (const TMRP_line&)s; const bool imfather = sons() > 0; const bool hesfather = line.sons() > 0; /* if (imfather && (!hesfather || is_son(line.articolo()))) return +1; if (hesfather && (!imfather || line.is_son(articolo()))) return -1; return 0; */ if (imfather && !hesfather) return +1; if (hesfather && !imfather) return -1; int c = 0; // Non farti ingannare dalle distinte cicliche! if (is_son(line.articolo())) c++; if (line.is_son(articolo())) c--; return c; } TObject* TMRP_line::dup() const { TMRP_line* o = new TMRP_line(*this); return o; } TMRP_line& TMRP_line::operator=(const TMRP_line & a) { //key _codart=a._codart; _livgiac=a._livgiac; _codmag=a._codmag; _codimp=a._codimp; _codlin=a._codlin; _codclifor=a._codclifor; _da_rdoc_key=a._da_rdoc_key; // contents _descr=a._descr; _sons=a._sons; _qta_sons=a._qta_sons; _req_per_bucket=a._req_per_bucket; _final_product = a._final_product; _sheet_row = a._sheet_row; _articolo_giac= new TArticolo_giacenza(a._articolo_giac->codice()); return *this; } TMRP_record& TMRP_line::record(int i) const { TMRP_record* rec = (TMRP_record*)_req_per_bucket.objptr(i); CHECKD(rec, "Invalid MRP record ", i); return *rec; } TMRP_record& TMRP_line::record(const TMRP_time& t) const { const int last = last_bucket(); int i; for (i = 0; i <= last; i++) { TMRP_record& rec = record(i); const int cmp = rec.time().compare(t); if (cmp == 0) return rec; if (cmp > 0) { ((TArray&)_req_per_bucket).insert(NULL, i); break; } } TMRP_record* rec = new TMRP_record(t); ((TArray&)_req_per_bucket).add(rec, i); return *rec; } // approssima in base al lotto minimo; prevede valori negativi real TMRP_line::sizeup_net_requirement(int i, const real &val, const real & oldnet) { real req(oldnet); // Azzera net requirement if (val + oldnet < ZERO) { req = -(val + oldnet); // Rende positiva la richiesta effettiva real lm,li; lotti_riordino(lm,li); if (req > lm) // Se la richiesta supera il lotto minimo { if (li > ZERO) { // Calcola il numero di lotti incrementali real lotti = (req - lm) / li; lotti.ceil(); // La quantita' richiesta = minimo + lotti * dim.lotti req = lm + lotti * li; } } else req = lm; // Forza la richiesta almeno al lotto minimo req += oldnet; } set_net_req(i, req); return req; } const real& TMRP_line::add_gross_req(const TMRP_time& t, const real& val, TMRP_internalref* ref) { return record(t).add_gross_req(val, ref); } const real& TMRP_line::add_gross_req(const TMRP_time& t, const real& val, TMRP_docref* ref) { return record(t).add_gross_req(val, ref); } const real& TMRP_line::add_sched_rec(const TMRP_time& t, const real &val, TMRP_docref* ref) {return record(t).add_sched_rec(val, ref);} const real& TMRP_line::add_planned_ord(const TMRP_time& t, const real &val, TMRP_docref* ref) { return record(t).add_planned_ord(val, ref);} const real& TMRP_line::add_resched_ord(int i, const real &val) { return record(i).add_resched_ord(val); } const real& TMRP_line::add_unsched_ord(int i, const real &val) { return record(i).add_unsched_ord(val); } const real & TMRP_line::set_net_req(int i, const real &val) { if (val>ZERO) return record(i).set_net_req(val); else return record(i).set_net_req(ZERO); } const real & TMRP_line::add_net_req(const TMRP_time &t, const real &val) {return record(t).add_net_req(val); } const real & TMRP_line::add_net_req(int i, const real &val) { return record(i).add_net_req(val); } const real & TMRP_line::set_on_hand(int i, const real &val) { return record(i).set_on_hand(val);} const real & TMRP_line::set_on_hand(const TMRP_time &t, const real &val) { return record(t).set_on_hand(val);} const TMRP_time& TMRP_line::lead_time(int i, TMRP_time& t, bool anticipate) const { t = record(i).time(); if (anticipate) { const TRectype& dist = cache().get(LF_DIST, articolo()); if (!dist.empty()) { const int days = dist.get_int("LEADTIME"); const long hours = dist.get_long("LEADHOURS"); t.sub_time(days, hours); } else { _articolo_giac->read(articolo()); TDate d = t.date(); d -= _articolo_giac->lead_time(codmagdep(), livgiac()); t.set(d, t.hour(), t.impianto(), t.linea()); } } return t; } real& TMRP_line::giacenza_attuale(real &g) const { TDate d(TODAY); return giacenza_attuale(g, d); } real& TMRP_line::giacenza_attuale(real &g, const TDate &d) const { _articolo_giac->read(articolo()); g = _articolo_giac->giacenza_anno(codmagdep(),livgiac(),d.year()); return g; } real& TMRP_line::scorta_minima(real &g) const { TDate d(TODAY); return scorta_minima(g,d); } real& TMRP_line::scorta_minima(real &g, const TDate &d) const { _articolo_giac->read(articolo()); g = _articolo_giac->scorta_minima(codmagdep(),livgiac(),d.year()); return g; } void TMRP_line::set_imp_lin(const char* imp, const char* lin) { _codimp = imp; _codlin = lin; if (_codlin.full() && _codimp.full()) { const TLinea_prod l(_codlin); imp = l.codimp(); if (_codimp != imp) { #ifdef DBG warning_box("Impianto '%s' incompatibile con la linea '%s':\nforzato a '%s'.", (const char*)_codimp, lin, imp); #endif _codimp = imp; } } } TMRP_line::TMRP_line(const char* art, const char* giac, const char* mag, const char* magc, const char* imp, const char* lin, long codcli, const char* da_rdoc_key) : _codart(art), _livgiac(giac), _explosion_depth(0), _codmag(mag), _codmag_coll(magc), _codclifor(codcli), _da_rdoc_key(da_rdoc_key), _final_product(FALSE), _sheet_row(NULL) { set_imp_lin(imp, lin); if (_articolo_giac == NULL) _articolo_giac= new TArticolo_giacenza(); } TMRP_line::TMRP_line(const TMRP_line&a) { TMRP_line::operator=(a); } /////////////////////////////////////////////////////////// // TMRP_lines /////////////////////////////////////////////////////////// TMRP_lines::TMRP_lines(const TMRP_lines & a) { TMRP_lines::operator=(a); } TObject* TMRP_lines::dup() const { return new TMRP_lines(*this); } TMRP_lines & TMRP_lines::operator= (const TMRP_lines &a) { TMRP_array::operator= (a); _ignore_mag=a._ignore_mag; _ignore_dep=a._ignore_dep; _ignore_imp=a._ignore_imp; _ignore_lin=a._ignore_lin; _ignore_key=a._ignore_key; return *this; } TSortable* TMRP_lines::new_obj(const TToken_string& key) const { TCodice_articolo art; key.get(0, art); art.trim(); TString16 gia; key.get(1, gia); gia.trim(); TString8 mag; key.get(2, mag); mag.trim(); TString8 magc; key.get(3, magc); magc.trim(); TString8 imp; key.get(4, imp); imp.trim(); TString8 lin; key.get(5, lin); lin.trim(); long clifor; key.get(6, clifor); TString da_rdoc_key; key.get(7, da_rdoc_key); return new TMRP_line(art, gia, mag, magc, imp, lin, clifor, da_rdoc_key); } TMRP_line* TMRP_lines::find(const TCodice_articolo& codart, const TString& gia, const TString& mag, const TString& magc, const TString& imp, const TString& lin, long codcli, const char* rdoc_key, bool create) { _key = codart; _key.add(gia); _key.trim(); // trim to trim giaclevel... if (_ignore_mag) { _key.add(" ",2); _key.add(" ",3); } else { if (_ignore_dep) { _key.add(mag.left(3) ,2); _key.add(magc.left(3),3); } else { _key.add(mag,2); _key.add(magc,3); } } if (_ignore_imp || imp.blank()) _key.add(" ",4); else _key.add(imp,4); if (_ignore_lin || lin.blank()) _key.add(" ",5); else _key.add(lin,5); _key.add(codcli,6); if (_ignore_key) _key.add(" ",7); else _key.add(rdoc_key,7); TSortable* s = create ? add_obj(_key) : find_obj(_key); return (TMRP_line*)s; } TMRP_lines::TMRP_lines() : _ignore_mag(false), _ignore_dep(false), _ignore_imp(false), _ignore_lin(false), _ignore_key(true) { } TMRP_lines::~TMRP_lines() { destroy(); } /////////////////////////////////////////////////////////// // TRiga_ordine /////////////////////////////////////////////////////////// #define COMPARE_ALL_CODES 13 // #define COMPARE_COMPLETE 99 // #define COMPARE_TDFA -1 // #define COMPARE_TDAF -2 // #define COMPARE_TFAD -3 // #define COMPARE_TFDA -4 // #define COMPARE_TAFD -5 // #define COMPARE_TADF -6 // #define COMPARE_DTFA -7 // data documento + data di consegna + fornitore + articolo #define COMPARE_DATF -8 // data documento + data di consegna + articolo + fornitore #define COMPARE_ATFD -9 // #define COMPARE_ADTF -10 // #define COMPARE_TCFA -11 // #define COMPARE_TCAF -12 // #define COMPARE_TFAC -13 // #define COMPARE_TFCA -14 // #define COMPARE_TAFC -15 // #define COMPARE_TACF -16 // #define COMPARE_CTFA -17 // data di consegna + data documento + fornitore + articolo #define COMPARE_CATF -18 // data di consegna + data documento + articolo + fornitore #define COMPARE_ATFC -19 // #define COMPARE_ACTF -20 // class TRiga_ordine : public TToken_string { TRiga_ordine() { CHECK(false, "Miiii"); } public: int compare(const TToken_string& r, bool compare_orig_doc, int level = COMPARE_ALL_CODES, bool ascending = true) const; int compare_field(TString &str0, TString &str1,short field_no) const; TRiga_ordine& operator=(TToken_string& r); TRiga_ordine& operator+=(TRiga_ordine& r); TRiga_ordine(const TDate& datadoc, const TDate& datacons, long forn, const TMRP_line& line, int bucket, const real & price); virtual ~TRiga_ordine() { } }; int TRiga_ordine::compare(const TToken_string& riga, bool compare_orig_doc, int level, bool ascending) const { TString str0, str1; int cmp = 0; if (level>=0) { int i; for (i = 2; i <= level && i <= COMPARE_ALL_CODES && cmp == 0; i++) { get(i, str0); riga.get(i, str1); cmp = compare_field(str0,str1,short(i+FIRST_FIELD)); } if (level > COMPARE_ALL_CODES) { i = F_DOCANNODOC; while (cmp == 0 && i <= F_DOCNRIGA) { get(i-FIRST_FIELD, str0); riga.get(i-FIRST_FIELD, str1); if (str1.blank()) // se la linea trovata non è riferita a un doc, va sempre bene break; cmp = compare_field(str0,str1,short(i++)); } } } else { // ordinamenti non standard short f; short fields_TFAD[] = {F_ORD_TYPE, F_FORNITORE, F_ARTICOLO, F_LIV1, F_LIV2, F_LIV3, F_LIV4, F_DATADOC, F_DATACONS}; short fields_TFDA[] = {F_ORD_TYPE, F_FORNITORE, F_DATADOC, F_DATACONS, F_ARTICOLO, F_LIV1, F_LIV2, F_LIV3, F_LIV4}; short fields_TDFA[] = {F_ORD_TYPE, F_DATADOC, F_DATACONS, F_FORNITORE, F_ARTICOLO, F_LIV1, F_LIV2, F_LIV3, F_LIV4}; short fields_TDAF[] = {F_ORD_TYPE, F_DATADOC, F_DATACONS, F_ARTICOLO, F_LIV1, F_LIV2, F_LIV3, F_LIV4, F_FORNITORE}; short fields_TAFD[] = {F_ORD_TYPE, F_ARTICOLO, F_LIV1, F_LIV2, F_LIV3, F_LIV4, F_FORNITORE, F_DATADOC, F_DATACONS}; short fields_TADF[] = {F_ORD_TYPE, F_ARTICOLO, F_LIV1, F_LIV2, F_LIV3, F_LIV4, F_DATADOC, F_DATACONS, F_FORNITORE}; short fields_DTFA[] = {F_DATADOC, F_DATACONS, F_ORD_TYPE, F_FORNITORE, F_ARTICOLO, F_LIV1, F_LIV2, F_LIV3, F_LIV4}; short fields_DATF[] = {F_DATADOC, F_DATACONS, F_ARTICOLO, F_LIV1, F_LIV2, F_LIV3, F_LIV4, F_ORD_TYPE, F_FORNITORE}; short fields_ATFD[] = {F_ARTICOLO, F_LIV1, F_LIV2, F_LIV3, F_LIV4, F_ORD_TYPE, F_FORNITORE, F_DATADOC, F_DATACONS}; short fields_ADTF[] = {F_ARTICOLO, F_LIV1, F_LIV2, F_LIV3, F_LIV4, F_ORD_TYPE, F_DATADOC, F_DATACONS, F_FORNITORE}; short fields_TFAC[] = {F_ORD_TYPE, F_FORNITORE, F_ARTICOLO, F_LIV1, F_LIV2, F_LIV3, F_LIV4, F_DATACONS, F_DATADOC}; short fields_TFCA[] = {F_ORD_TYPE, F_FORNITORE, F_DATACONS, F_DATADOC, F_ARTICOLO, F_LIV1, F_LIV2, F_LIV3, F_LIV4}; short fields_TCFA[] = {F_ORD_TYPE, F_DATACONS, F_DATADOC, F_FORNITORE, F_ARTICOLO, F_LIV1, F_LIV2, F_LIV3, F_LIV4}; short fields_TCAF[] = {F_ORD_TYPE, F_DATACONS, F_DATADOC, F_ARTICOLO, F_LIV1, F_LIV2, F_LIV3, F_LIV4, F_FORNITORE}; short fields_TAFC[] = {F_ORD_TYPE, F_ARTICOLO, F_LIV1, F_LIV2, F_LIV3, F_LIV4, F_FORNITORE, F_DATACONS, F_DATADOC}; short fields_TACF[] = {F_ORD_TYPE, F_ARTICOLO, F_LIV1, F_LIV2, F_LIV3, F_LIV4, F_DATACONS, F_DATADOC, F_FORNITORE}; short fields_CTFA[] = {F_DATACONS, F_DATADOC, F_ORD_TYPE, F_FORNITORE, F_ARTICOLO, F_LIV1, F_LIV2, F_LIV3, F_LIV4}; short fields_CATF[] = {F_DATACONS, F_DATADOC, F_ARTICOLO, F_LIV1, F_LIV2, F_LIV3, F_LIV4, F_ORD_TYPE, F_FORNITORE}; short fields_ATFC[] = {F_ARTICOLO, F_LIV1, F_LIV2, F_LIV3, F_LIV4, F_ORD_TYPE, F_FORNITORE, F_DATACONS, F_DATADOC}; short fields_ACTF[] = {F_ARTICOLO, F_LIV1, F_LIV2, F_LIV3, F_LIV4, F_ORD_TYPE, F_DATACONS, F_DATADOC, F_FORNITORE}; for (int i = 0; i < 9 && cmp == 0; i++) { switch (level) { case COMPARE_TFAD: f=fields_TFAD[i]; break; case COMPARE_TFDA: f=fields_TFDA[i]; break; case COMPARE_TDFA: f=fields_TDFA[i]; break; case COMPARE_TDAF: f=fields_TDAF[i]; break; case COMPARE_TADF: f=fields_TADF[i]; break; case COMPARE_TAFD: f=fields_TAFD[i]; break; case COMPARE_DTFA: f=fields_DTFA[i]; break; case COMPARE_DATF: f=fields_DATF[i]; break; case COMPARE_ADTF: f=fields_ADTF[i]; break; case COMPARE_ATFD: f=fields_ATFD[i]; break; case COMPARE_TFAC: f=fields_TFAC[i]; break; case COMPARE_TFCA: f=fields_TFCA[i]; break; case COMPARE_TCFA: f=fields_TCFA[i]; break; case COMPARE_TCAF: f=fields_TCAF[i]; break; case COMPARE_TACF: f=fields_TACF[i]; break; case COMPARE_TAFC: f=fields_TAFC[i]; break; case COMPARE_CTFA: f=fields_CTFA[i]; break; case COMPARE_CATF: f=fields_CATF[i]; break; case COMPARE_ACTF: f=fields_ACTF[i]; break; case COMPARE_ATFC: f=fields_ATFC[i]; break; default: NFCHECK("Ordinamento sconosciuto"); break; } get(f - FIRST_FIELD, str0); riga.get(f - FIRST_FIELD, str1); cmp=compare_field(str0,str1,f); } } if (compare_orig_doc) { int i = F_DAANNO; while (cmp == 0 && i <= F_DANRIGA) { get(i-FIRST_FIELD, str0); riga.get(i-FIRST_FIELD, str1); cmp = compare_field(str0,str1,short(i++)); } } return ascending ? cmp : -cmp; } int TRiga_ordine::compare_field(TString &str0, TString &str1,short field_no) const { int cmp; switch (field_no) { case F_DATADOC: case F_DATACONS: { if (str0 != str1) { const TDate mine(str0); const TDate his(str1); cmp = mine > his ? +1 : -1; } else cmp = 0; } break; case F_FORNITORE: // data doc { const long f0 = atol(str0); const long f1 = atol(str1); cmp = f0 == f1 ? 0 : (f0 > f1 ? +1 : -1); } break; default: cmp = str0.compare(str1); break; } return cmp; } TRiga_ordine& TRiga_ordine::operator=(TToken_string& r) { this->TToken_string::operator=(r); return *this; } TRiga_ordine& TRiga_ordine::operator+=(TRiga_ordine& r) { // CHECK(compare(r) == 0, "Can't add incompatible order line"); const real q = r.get(F_QUANTITA - FIRST_FIELD); if (!q.is_zero()) { real qta = get(F_QUANTITA - FIRST_FIELD); qta += q; qta.round(5); add(qta.is_zero() ? " " : qta.string(), F_QUANTITA - FIRST_FIELD); } return *this; } TRiga_ordine::TRiga_ordine(const TDate& datadoc, const TDate& datacons, long forn, const TMRP_line& line, int bucket, const real& price) : TToken_string(128) { // Determino il tipo di ordine (PROD/ACQ) const TCodice_articolo& codart = line.articolo(); const bool art_prod = is_production_article(codart); add(" ",F_SELECTED - FIRST_FIELD); add(art_prod ? "P" : "F", F_ORD_TYPE - FIRST_FIELD); add(datadoc.string(),F_DATADOC - FIRST_FIELD); add(datacons.string(),F_DATACONS - FIRST_FIELD); add(line.codclifor() ? line.codclifor() : forn, F_FORNITORE - FIRST_FIELD); add(codart, F_ARTICOLO - FIRST_FIELD); for (int l = livelli_giacenza().last_level(); l >= 1; l--) add(line.livgiac(l), F_LIV1+l-1 - FIRST_FIELD); add(line.codmag(), F_MAGAZZINO - FIRST_FIELD); add(line.coddep(),F_DEPOSITO - FIRST_FIELD); add(line.codimp(),F_CODIMP - FIRST_FIELD); add(line.codlin(),F_CODLIN - FIRST_FIELD); real q = line.net_requirement(bucket); //q -= line.planned_orders(bucket); const TCodice_um um_nulla; const TQuantita qta(line.articolo(), um_nulla, q); if (!q.is_zero()) // cosi' non ci sono inestetici 0.0000 sulla maschera add(qta.val().string(),F_QUANTITA - FIRST_FIELD); add(qta.um(),F_UM - FIRST_FIELD); add(price.string(),F_PREZZO - FIRST_FIELD); add(line.description(),F_DESCART - FIRST_FIELD); } /////////////////////////////////////////////////////////// // TMRP_docref / TMRP_docrefs /////////////////////////////////////////////////////////// const TRectype& TMRP_docref::get_doc() const { TToken_string key; key.add("D"); key.add(_annodoc); key.add(_codnum); key.add(_numdoc); return cache().get(LF_DOC,key); } const TRectype& TMRP_docref::get_rdoc() const { TToken_string key; key.add(_codnum); key.add(_annodoc); key.add("D"); key.add(_numdoc); key.add(_numrig); return cache().get(LF_RIGHEDOC, key); } TDate TMRP_docref::datadoc() const { return get_doc().get_date(DOC_DATADOC); } TDate TMRP_docref::datacons() const { TDate d; d = get_rdoc().get_date(RDOC_DATACONS); if (!d.ok()) d=get_doc().get_date(DOC_DATACONS); return d; } const TString & TMRP_docref::tipodoc() { static TString4 s; return s = get_doc().get(DOC_TIPODOC); } char TMRP_docref::statodoc() { return get_doc().get_char(DOC_STATO); } TMRP_docref::TMRP_docref(int anno, const char * codnum,long numdoc,int nriga, const char *um, const real & qta, const real &prz) { _annodoc = anno; _codnum = codnum; _numdoc = numdoc; _numrig = nriga; _um = um; _qta = qta; _prz = prz; } TObject* TMRP_docref::dup() const { TMRP_docref * o = new TMRP_docref(_annodoc, _codnum, _numdoc, _numrig, _um, _qta, _prz); return o; } TObject* TMRP_internalref::dup() const { TMRP_internalref * o = new TMRP_internalref(*this); return o; } TMRP_internalref::TMRP_internalref(TMRP_line *line, int bucket, const real & qta): _line(line), _qta(qta), _bucket(bucket) { _um = cache().get(LF_DIST,line->articolo()).get("UM"); _date = _line->record(bucket).time().date(); } TMRP_internalref::TMRP_internalref(const TMRP_internalref &r): _line(r._line), _qta(r._qta) ,_date (r._date), _um(r._um), _bucket(r._bucket) { } TObject* TMRP_docrefs::dup() const { TMRP_docrefs * o = new TMRP_docrefs(); *o = *this; return o; } /////////////////////////////////////////////////////////// // TLav_finder Trova la prima lavorazione di un articolo /////////////////////////////////////////////////////////// class TLav_finder : public TAssoc_array { TDecoder _lnp; bool _keep_imp; public: void init(bool ki = TRUE); const TString& lin2imp(const TString& lin); TLavorazione& art2lav(const TCodice_articolo& art); void art2magimpline(const TCodice_articolo& art, TString& mag, TString& imp, TString& lin); TLav_finder(); virtual ~TLav_finder() { } }; void TLav_finder::init(bool ki) { _keep_imp = ki; TAssoc_array::destroy(); _lnp.destroy(); } TLavorazione& TLav_finder::art2lav(const TCodice_articolo& art) { TLavorazione* lav = (TLavorazione*)objptr(art); if (lav == NULL) { TDistinta_tree tree; TArray boom; tree.set_root(art); tree.explode(boom, FALSE, RAGGR_EXP_UMBASE, 1, "L"); TString80 codlav; if (boom.items() > 0) codlav = ((TRiga_esplosione&)boom[0]).articolo(); lav = new TLavorazione(codlav); add(art, lav); } return *lav; } void TLav_finder::art2magimpline(const TCodice_articolo& art, TString& mag, TString& imp, TString& lin) { TLavorazione& lav = art2lav(art); if (imp.blank() && lin.full()) imp = _lnp.decode(lin); lin.cut(0); const int ll = _keep_imp ? lav.linee() : lav.linee_standard(); for (int l = 0; l < ll; l++) { const TString& linea = lav.cod_linea(l); const bool goodimp = imp.empty() || _lnp.decode(linea) == imp; if (l == 0 || goodimp) { lin = linea; lin.trim(); } if (goodimp) break; } if (lin.full()) { const TLinea_prod lnp(lin) ; imp = lnp.codimp(); mag = lnp.codmagdep(); } else { if (!_keep_imp) imp = mag = ""; } } TLav_finder::TLav_finder() : _lnp("LNP", "S6"), _keep_imp(TRUE) { } /////////////////////////////////////////////////////////// // TMatResPlanning /////////////////////////////////////////////////////////// class TMatResMask : public TCalendar_mask { TCondizione_vendita *_condv; TSelect_color_mask _sel_color; void clear_sheets(); int num_orders(); void round_field(TMask_field& fld, bool up) const; virtual bool on_field_event(TOperable_field& o, TField_event e, long jolly); int find_pos(const TRiga_ordine& r, int& cmp, int level=COMPARE_ALL_CODES) const; void sort_orders(); bool orders_selected(char type, const char * dacatmer,const char * acatmer); void select_orders(char type, const char * dacatmer, const char * acatmer); public: int round_date(TDate& date, bool up = FALSE) const; int add_order_line(long forn, const TMRP_line& l, int bucket); TSelect_color_mask & sel() { return _sel_color; } TMatResMask(); virtual ~TMatResMask() { } }; class TMatResPlanning : public TSkeleton_application { TMRP_lines _articles; TLav_finder _artinfo; TMatResMask* _mask; private: bool gross2net_logic(TMRP_line &curr_article, int bucket, bool & sc_used); bool load_gross_requirements(); bool load_planned_orders(); bool ciclica(TDistinta_tree& distinta); bool explode_articles(); bool test_codnum(const TCodice_numerazione& num, const TString_array& a) const; bool test_codnum(const TString & codnum, const TString_array& a) const; int test_status(const TRectype& doc, const TString_array& a) const; bool has_confirmed_status(const TRectype& doc, const TToken_string& riga) const; protected: bool preprocess_cycle(); // req iniziale dai docs bool net_requirement_cycle(); bool build_orders(); static void print_except_header(TPrinter& pr); static void print_orders_header(TPrinter& pr); static void print_orders_body(TPrinter& pr, TToken_string *sheetrow); static void set_body_order_line(TPrintrow &row, TToken_string *sheetrow); TMRP_line* find_risalita_line(TToken_string &row); const TRectype* irefs2rdoc(const TMRP_internalrefs& iref) const; bool print_risalita(TToken_string &row, int backlevel, bool dett_ord); bool print_risalita(const TMRP_line & line, const TDate & d, int backlevel, bool dett_ord); int print_internal_ref(const TMRP_internalref &iref, int backlevel, bool dett_ord); int print_gross_ref(const TMRP_line& line, int bucket); void print_exceptions(TExceptions_array &excepts); bool print_exceptions(TMask &m); bool print_planning(TMask &m); bool ask_save(); void save_orders(TAssoc_array& docs); long compute_production_time(const TMRP_line& line, const real& qta) const; const TRectype* trova_da_rdoc(const TMRP_line& line, const TDate& datacon) const; public: virtual bool menu(MENU_TAG mt); virtual void main_loop(); virtual bool firm_change_enabled() const { return FALSE; } void compute(); bool print_orders(); bool emit_orders(); void risalita(const TMask & m); int round_date(TDate &d, bool up=FALSE) const {return _mask->round_date(d, up);} }; TMatResPlanning& app() { return (TMatResPlanning&)main_app(); } /////////////////////////////////////////////////////////// // TRisalita_mask /////////////////////////////////////////////////////////// class TRisalita_mask : public TAutomask { TMRP_line* _line; bool add_total_row(int pos, const char * um , const real & lordo, const char * umpadre ,const real & lordopadre) ; protected: virtual bool on_field_event(TOperable_field& o, TField_event e, long jolly); bool add_total_rows(); static int compare_rows(TSheet_field &sf, int r1, int r2); public: int add_gross_ref(const TMRP_line& line, int bucket); int add_internal_ref(const TMRP_internalref & iref); TRisalita_mask(TMRP_line* line, const TDate & from, const TDate & to, bool is_buck0,int extraleadtime); virtual ~TRisalita_mask() { } }; int TMatResMask::round_date(TDate& date, bool up) const { // Dimensione del bucket in giorni const int bucket_size = get_int(F_BUCKET)*get_int(F_DAYXBUCK); // Riporta la data al primo lunedi prima dell'inizio TDate inizio = get_date(F_DADATA); int bucket; if (bucket_size == 31) // mese solare { if (up) { date.set_end_month(); 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 { 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 = 0; else bucket = days / bucket_size; if (up) // Arrotonda alla fine del bucket date = inizio + long((bucket+1 )* bucket_size - 1 /*- get_int(F_LASTWRKDAY)*/); else // Arrotonda all'inizio del bucket date = inizio + long(bucket * bucket_size); } return bucket; } void TMatResMask::round_field(TMask_field& fld, bool up) const { TDate date = fld.get(); if (date.ok()) { round_date(date, up); fld.set(date); } } int TMatResMask::num_orders() { int n = 0; TSheet_field& s = sfield(F_ORDINI); FOR_EACH_SHEET_ROW_BACK(s, r, row) if (!real(row->get(F_QUANTITA-FIRST_FIELD)).is_zero()) n++; return n; } class TForn_ext_sheet : public TBrowse_sheet { protected: virtual bool get_ini_paragraph(const TEdit_field& field, TString& parag) const; public: TForn_ext_sheet(TCursor& cur, TEdit_field& f); }; bool TForn_ext_sheet::get_ini_paragraph(const TEdit_field& field, TString& parag) const { const bool ok = TSheet::get_ini_paragraph(field, parag); if (ok) parag << "_F81"; return ok; } TForn_ext_sheet::TForn_ext_sheet(TCursor& cur, TEdit_field& f) : TBrowse_sheet(&cur, HR("CODCF|20->RAGSOC"), TR("Ricerca Fornitori alternativi"), HR("Codice|Ragioen Sociale @50"), 0, f, TToken_string()) { } bool TMatResMask::on_field_event(TOperable_field& o, TField_event e, long jolly) { const char * confirm_msg=FR("Le attuali %d righe di ordine verranno perse. Confermare?"); switch (o.dlg()) { case F_DADATA: if (e == fe_modify) round_field(o, FALSE); break; case F_ADATA: if (e == fe_modify) round_field(o, TRUE); break; case F_BUCKET: case F_DAYXBUCK: if (e == fe_modify) { round_field(field(F_DADATA), FALSE); round_field(field(F_ADATA), TRUE); } break; case F_NUM_ORC: case F_TIPI_ORC: case F_NUM_ORF: case F_TIPI_ORF: 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()) return TRUE; return error_box(TR("E' necessario inserire almeno una riga")); } break; case F_ORDINI: { TSheet_field& s = (TSheet_field&)o; switch(e) { case se_query_add: return FALSE; default: break; } } break; case F_FORNITORE: if (jolly == 5) // codice fornitore sullo sheet ordini { TSheet_field& so = sfield(F_ORDINI); TToken_string &row = so.row(so.selected()); switch(e) { case fe_modify: case fe_init: { real qta, price; TString codart; long codfor; char tipocf; row.get(F_FORNITORE - FIRST_FIELD, codfor); row.get(F_ORD_TYPE - FIRST_FIELD, tipocf); if (tipocf == 'F') if (codfor == 0L) { } else { row.get(F_QUANTITA - FIRST_FIELD, qta); row.get(F_ARTICOLO - FIRST_FIELD, codart); find_price(get(F_TIPOCV),get(F_CODCONDV),get(F_CATVEN_CV), "F", codfor, codart, qta, price); row.add(price.string(), F_PREZZO - FIRST_FIELD); } break; } case fe_magic: { TRelation rel(LF_CODCORR); TRectype from(rel.curr()); TRectype to(rel.curr()); TString codart; row.get(so.cid2index(F_ARTICOLO), codart); rel.add(LF_CLIFO, "TIPOCF==TIPOCF|CODCF==CODCF"); from.put(CODCORR_CODART, codart); to.put(CODCORR_CODART, codart); TCursor cur(&rel, "TIPOCF==\"F\"", 1, &from, &to); cur.items(); cur.freeze(); TForn_ext_sheet sheet(cur, (TEdit_field &)o); if (sheet.run() == K_ENTER) { TToken_string& row = sheet.row(sheet.selected()); const long codcf = row.get_long(0); o.set(codcf); } } break; } } else 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 DLG_QUIT: if (e == fe_button && jolly == 0L) { const int it=num_orders(); if (it > 0 && !yesno_box(confirm_msg, it)) return FALSE; } break; case DLG_CANCEL: if (e == fe_button) if (jolly == 0L) { TSheet_field& s = sfield(F_ORDINI); const int it=s.items(); if (it==0 || yesno_box(confirm_msg, it)) { enable(-1); s.destroy(); s.force_update(); } else return FALSE; } break; case DLG_ELABORA: if (e == fe_button && check_fields()) { TSheet_field& s = sfield(F_ORDINI); const int it=s.items(); if (it==0 || yesno_box(confirm_msg, it)) { s.destroy(); app().compute(); enable(DLG_SAVEREC, s.items() > 0 && !get_bool(F_DISABLESAVE)); enable(-G_PREPROCESS, s.items() == 0); sort_orders(); s.set_focus(); // Controlla se e' stato richiesto il salvataggio automatico e se posso salvare if (app().argc() >= 2 && field(DLG_SAVEREC).active()) { TString param = app().argv(2); param.upper(); if (param.find("AUTOR") > 0) // Lancia salvataggio batch { app().emit_orders(); stop_run(K_FORCE_CLOSE); } } } } break; case F_RISALITA: if (e == fe_button) { /*TSheet_field & sf= m.sfield(F_ORDINI); TToken_string & row=sf.row(sf.selected()); TDate datacons(row.get(sf.cid2index(F_DATACONS)));*/ app().risalita(*this); } break; case F_RESORT_ORDINI: if (e == fe_button) sort_orders(); break; case F_SELECT_ORD: if (e == fe_button) if (*get(F_SEL_ORD_TYPE)=='F') select_orders('F', get(F_OF_DAGRMERC), get(F_OF_AGRMERC)); else select_orders('P', get(F_OP_DAGRMERC), get(F_OP_AGRMERC)); break; case DLG_SAVEREC: if (e == fe_button && check_fields()) { if (!app().emit_orders()) message_box(TR("Nessun ordine generato")); } break; case DLG_PRINT: if (e == fe_button) { app().print_orders(); return FALSE; } break; case DLG_PROFILE: if (e == fe_modify) { clear_sheets(); enable(-1); } break; default: break; }; return TRUE; } void TMatResMask::clear_sheets() { TSheet_field &sa=sfield(F_ORDINI); if (sa.items()>0) { sa.destroy(); sa.force_update(); } } int TMatResMask::find_pos(const TRiga_ordine& r, int& cmp, int level) const { TSheet_field& s = sfield(F_ORDINI); TString_array& a = s.rows_array(); const bool cmp_orig = get_bool(F_SINGLE_DOC); int i; cmp = +1; // vacca for (i = 0; i < a.items(); i++) { const TRiga_ordine& riga = (const TRiga_ordine&)a[i]; cmp = r.compare(riga, cmp_orig, level); if (cmp == 0) break; } return i; } // Aggiunge le righe d'ordine allo sheet int TMatResMask::add_order_line(long forn, const TMRP_line& line, int bucket) { const TString& num_forn = get(F_NUM_FORN); const TString& num_prod = get(F_NUM_PROD); int pos = -1; TMRP_time deliv_time = line.time(bucket); TMRP_time plan_time; if (get_bool(F_IGN_LDTIME)) plan_time = line.time(bucket); else line.lead_time(bucket, plan_time, TRUE); plan_time.sub_time(get_int(F_XTRA_PLTIME)); TDate datadoc = plan_time.date(); round_date(datadoc); TDate datacons = deliv_time.date(); round_date(datacons); TSheet_field& s = sfield(F_ORDINI); TString_array& a = s.rows_array(); real q = line.net_requirement(bucket); // Fabbisogno netto TMRP_docrefs * pl_orders=NULL,*sc_orders=NULL; if (get_bool(F_RESCHEDULING)) sc_orders = line.record(bucket).scheduls_refs(); pl_orders = line.record(bucket).plans_refs(); // le proposte di rescheduling sono da mettere su uno sheet a parte... int nref = pl_orders != NULL ? pl_orders->items() : 0; real qtaplan; // Quantità da pianificare do { TRiga_ordine* r = new TRiga_ordine(datadoc, datacons, forn, line, bucket, ZERO); // Setta un codice numerazione (provvisorio) in base al tipo di ordine const char ot = r->get_char(F_ORD_TYPE - FIRST_FIELD); r->add(ot == 'F' ? num_forn : num_prod, F_DOCCODNUM - FIRST_FIELD); nref--; if (nref >= 0) { const TMRP_docref& dr = pl_orders->get_ref(nref); const TString& codnum = dr.codnumdoc(); if (codnum == num_prod || codnum == num_forn) { qtaplan = dr.qta_residua(); qtaplan.round(5); q.round(5); qtaplan = q - qtaplan; // tengo solo in parte questo ordine ... r->add(dr.annodoc() , F_DOCANNODOC - FIRST_FIELD); r->add(dr.codnumdoc() , F_DOCCODNUM - FIRST_FIELD); r->add(dr.numdoc() , F_DOCNUM - FIRST_FIELD); r->add(dr.numrig() , F_DOCNRIGA - FIRST_FIELD); r->add(qtaplan.is_zero() ? " " : qtaplan.string(), F_QUANTITA - FIRST_FIELD); r->add(dr.datacons().string() , F_DATACONS - FIRST_FIELD); r->add(dr.datadoc().string(), F_DATADOC - FIRST_FIELD); q = ZERO; } else r->add(" " , F_QUANTITA - FIRST_FIELD); } else { r->add(q.is_zero() ? " " : q.string() , F_QUANTITA - FIRST_FIELD); qtaplan = ZERO; } const TString dadockey(line.da_rdoc_key()); r->add(dadockey.mid(4, 4), s.cid2index(F_DAANNO)); r->add(dadockey.left(4), s.cid2index(F_DACODNUM)); r->add(dadockey.mid(9, 7), s.cid2index(F_DANUMDOC)); r->add(dadockey.mid(16), s.cid2index(F_DANRIGA)); if ((nref >= 0 && (!qtaplan.is_zero() || get_bool(F_ALL_ORDERSCHANGES))) || // correggo un vecchio ordine ... (nref < 0 && !q.is_zero()) || // ... o ne genero uno nuovo get_bool(F_ALL_MRPLINES)) // ...o voglio tutte le righe { int cmp = -1; if (nref >= 0 && qtaplan < ZERO) pos = find_pos(*r, cmp, COMPARE_COMPLETE); else pos = find_pos(*r, cmp, COMPARE_ALL_CODES); if (cmp == 0) // RIGA GIA' PRESENTE { TRiga_ordine& riga = (TRiga_ordine&)a[pos]; const TString4 codnum = riga.get(F_DOCCODNUM - FIRST_FIELD); // if (!(codnum != get(F_NUM_PROD) && codnum != get(F_NUM_FORN))) if (codnum == num_prod || codnum == num_forn) // Guy was here! riga += *r; delete r; const TString& qta2or = riga.get(F_QUANTITA - FIRST_FIELD); if (qta2or[0]==' ' && ! ((nref >= 0 && get_bool(F_ALL_ORDERSCHANGES)) // correzione .. || get_bool(F_ALL_MRPLINES))) // ... o voglio tutte le righe { // riabilita i campi del doc s.enable_cell(pos, F_ORD_TYPE - FIRST_FIELD); s.enable_cell(pos, F_DATADOC - FIRST_FIELD); s.enable_cell(pos, F_DATACONS - FIRST_FIELD); s.enable_cell(pos, F_FORNITORE - FIRST_FIELD); s.enable_cell(pos, F_MAGAZZINO - FIRST_FIELD); s.enable_cell(pos, F_DEPOSITO - FIRST_FIELD); s.enable_cell(pos, F_CODIMP - FIRST_FIELD); s.enable_cell(pos, F_CODLIN - FIRST_FIELD); a.destroy(pos, nref < 0); // no null rows if not desired } } else { // RIGA DA AGGIUNGERE a.add(r); pos = a.items()-1; } if (nref >= 0) { const TMRP_docref& dr = pl_orders->get_ref(nref); const TString& codnum = dr.codnumdoc(); TRiga_ordine& riga = (TRiga_ordine&)a[pos]; riga.add(codnum, F_DOCCODNUM - FIRST_FIELD); riga.add(dr.annodoc(), F_DOCANNODOC - FIRST_FIELD); riga.add(dr.numdoc(), F_DOCNUM - FIRST_FIELD); riga.add(dr.numrig(), F_DOCNRIGA - FIRST_FIELD); if (codnum != get(F_NUM_PROD) && codnum != get(F_NUM_FORN)) riga.add(" ", F_QUANTITA - FIRST_FIELD); // disabilita i campi del doc s.disable_cell(pos, F_ORD_TYPE - FIRST_FIELD); s.disable_cell(pos, F_DATADOC - FIRST_FIELD); s.disable_cell(pos, F_DATACONS - FIRST_FIELD); s.disable_cell(pos, F_FORNITORE - FIRST_FIELD); s.disable_cell(pos, F_MAGAZZINO - FIRST_FIELD); s.disable_cell(pos, F_DEPOSITO - FIRST_FIELD); s.disable_cell(pos, F_CODIMP - FIRST_FIELD); s.disable_cell(pos, F_CODLIN - FIRST_FIELD); } } else delete r; } while (nref >= 0 /*&& q > ZERO*/); if (line.final_product()) { COLOR back = NORMAL_BACK_COLOR; COLOR fore = NORMAL_COLOR; _sel_color.get_color(NODIST, back, fore); s.set_back_and_fore_color(back, fore, pos); } return pos; } static int order_compare(TSheet_field& s, int i1, int i2, int sorttype) { TMask &m=s.mask(); const bool ascending=!m.get_bool(F_SORT_ORDER); const bool cmp_orig = m.get_bool(F_SINGLE_DOC); const TRiga_ordine& r1 = (TRiga_ordine&)s.row(i1); const TRiga_ordine& r2 = (TRiga_ordine&)s.row(i2); return r1.compare(r2, cmp_orig, sorttype, ascending); } static int order_compareDTFA(TSheet_field &s,int i1,int i2) { return order_compare(s,i1,i2,COMPARE_DTFA);} static int order_compareDATF(TSheet_field &s,int i1,int i2) { return order_compare(s,i1,i2,COMPARE_DATF);} static int order_compareATFD(TSheet_field &s,int i1,int i2) { return order_compare(s,i1,i2,COMPARE_ATFD);} static int order_compareADTF(TSheet_field &s,int i1,int i2) { return order_compare(s,i1,i2,COMPARE_ADTF);} static int order_compareTFAD(TSheet_field &s,int i1,int i2) { return order_compare(s,i1,i2,COMPARE_TFAD);} static int order_compareTFDA(TSheet_field &s,int i1,int i2) { return order_compare(s,i1,i2,COMPARE_TFDA);} static int order_compareTDFA(TSheet_field &s,int i1,int i2) { return order_compare(s,i1,i2,COMPARE_TDFA);} static int order_compareTDAF(TSheet_field &s,int i1,int i2) { return order_compare(s,i1,i2,COMPARE_TDAF);} static int order_compareTAFD(TSheet_field &s,int i1,int i2) { return order_compare(s,i1,i2,COMPARE_TAFD);} static int order_compareTADF(TSheet_field &s,int i1,int i2) { return order_compare(s,i1,i2,COMPARE_TADF);} static int order_compareCTFA(TSheet_field &s,int i1,int i2) { return order_compare(s,i1,i2,COMPARE_CTFA);} static int order_compareCATF(TSheet_field &s,int i1,int i2) { return order_compare(s,i1,i2,COMPARE_CATF);} static int order_compareATFC(TSheet_field &s,int i1,int i2) { return order_compare(s,i1,i2,COMPARE_ATFC);} static int order_compareACTF(TSheet_field &s,int i1,int i2) { return order_compare(s,i1,i2,COMPARE_ACTF);} static int order_compareTFAC(TSheet_field &s,int i1,int i2) { return order_compare(s,i1,i2,COMPARE_TFAC);} static int order_compareTFCA(TSheet_field &s,int i1,int i2) { return order_compare(s,i1,i2,COMPARE_TFCA);} static int order_compareTCFA(TSheet_field &s,int i1,int i2) { return order_compare(s,i1,i2,COMPARE_TCFA);} static int order_compareTCAF(TSheet_field &s,int i1,int i2) { return order_compare(s,i1,i2,COMPARE_TCAF);} static int order_compareTAFC(TSheet_field &s,int i1,int i2) { return order_compare(s,i1,i2,COMPARE_TAFC);} static int order_compareTACF(TSheet_field &s,int i1,int i2) { return order_compare(s,i1,i2,COMPARE_TACF);} void TMatResMask::sort_orders() { TWait_cursor clessidra; TSheet_field& a = sfield(F_ORDINI); int choose = -(get_int(F_SORT)+ (get_bool(F_DATE_SORT_ORDER) ? 10 : 1)); switch (choose) { case COMPARE_ATFD: a.sort(order_compareATFD); break; case COMPARE_ADTF: a.sort(order_compareADTF); break; case COMPARE_DTFA: a.sort(order_compareDTFA); break; case COMPARE_DATF: a.sort(order_compareDATF); break; case COMPARE_TFAD: a.sort(order_compareTFAD); break; case COMPARE_TFDA: a.sort(order_compareTFDA); break; case COMPARE_TAFD: a.sort(order_compareTAFD); break; case COMPARE_TADF: a.sort(order_compareTADF); break; case COMPARE_TDAF: a.sort(order_compareTDAF); break; case COMPARE_TDFA: a.sort(order_compareTDFA); break; case COMPARE_ATFC: a.sort(order_compareATFC); break; case COMPARE_ACTF: a.sort(order_compareACTF); break; case COMPARE_CTFA: a.sort(order_compareCTFA); break; case COMPARE_CATF: a.sort(order_compareCATF); break; case COMPARE_TFAC: a.sort(order_compareTFAC); break; case COMPARE_TFCA: a.sort(order_compareTFCA); break; case COMPARE_TAFC: a.sort(order_compareTAFC); break; case COMPARE_TACF: a.sort(order_compareTACF); break; case COMPARE_TCAF: a.sort(order_compareTCAF); break; case COMPARE_TCFA: a.sort(order_compareTCFA); break; default: return; } a.force_update(); } bool TMatResMask::orders_selected(char type, const char * dacatmer,const char * acatmer) { TSheet_field& s = sfield(F_ORDINI); const int it=s.items(); for (int r=0; r< it; r++) { if ( *s.cell(r, s.cid2index(F_ORD_TYPE))==type && *s.cell(r, s.cid2index(F_SELECTED))=='X') if (*dacatmer <= ' ' || cache().get(LF_ANAMAG,s.cell(r, s.cid2index(F_ARTICOLO))).get(ANAMAG_GRMERC).left(3) >= dacatmer) if (*acatmer <= ' ' || cache().get(LF_ANAMAG,s.cell(r, s.cid2index(F_ARTICOLO))).get(ANAMAG_GRMERC).left(3) <= acatmer) return TRUE; } return FALSE; } void TMatResMask::select_orders(char type, const char * dacatmer,const char * acatmer) { TSheet_field& s = sfield(F_ORDINI); bool on=!orders_selected(type, dacatmer, acatmer); const int it=s.items(); for (int r=0; r< it; r++) { if ( *s.cell(r, s.cid2index(F_ORD_TYPE))==type ) if (*dacatmer <= ' ' || cache().get(LF_ANAMAG,s.cell(r, s.cid2index(F_ARTICOLO))).get(ANAMAG_GRMERC).left(3) >= dacatmer) if (*acatmer <= ' ' || cache().get(LF_ANAMAG,s.cell(r, s.cid2index(F_ARTICOLO))).get(ANAMAG_GRMERC).left(3) <= acatmer) { s.row(r).add(on ? "X" : " ", s.cid2index(F_SELECTED)); s.force_update(r); } } TString msg=format(FR("Ordini %s %s"),type=='F' ? TR("fornitore") : TR("di produzione") ,on ? TR("selezionati") :TR("de-selezionati")); xvtil_statbar_set(msg); } static bool handle_interval(TMask_field &fld, KEY k) { if (fld.to_check(k, true)) { TMatResMask & m = ((TMatResMask &)fld.mask()); const TDate & from = m.get_date(F_DADATA); const TDate & to = m.get_date(F_ADATA); m.calendar().set_highlight_interval(from, to); } return true; } TMatResMask::TMatResMask() : TCalendar_mask("mr2100a"), _sel_color("mr2100a") { _condv = NULL; TSheet_field& sf = sfield(F_ORDINI); livelli_giacenza().set_sheet_columns(sf, F_LIV1); TConfig ini(CONFIG_DITTA, "mg"); if (!ini.get_bool("GESDEPOSITI", "mg")) { sf.delete_column(F_DEPOSITO); sf.sheet_mask().hide(F_DEPOSITO); } if (!ini.get_bool("GESTIMPIANTI", "mr")) { sf.delete_column(F_CODIMP); // Elimina colonna impianto sf.sheet_mask().hide(F_CODIMP); sf.sheet_mask().hide(F_DESCIMP); disable(F_NOIMP); // Forza l'ignoramento degli impianti set(F_NOIMP, "X"); } _sel_color.add_color_def(NODIST, TR("Art.pianificati senza distinta"), COLOR_YELLOW, COLOR_BLACK); set_handler(F_DADATA, handle_interval); set_handler(F_ADATA, handle_interval); TCalendar_field & cf = (TCalendar_field &) field(F_CALENDAR); cf.set_immediate_write(); } /////////////////////////////////////////////////////////// // TRisalita_mask : /////////////////////////////////////////////////////////// TRisalita_mask::TRisalita_mask(TMRP_line* line, const TDate& fromdate, const TDate& todate, bool isbuck0, int extraleadtime) : TAutomask("mr2100b.msk"), _line (line) { TSheet_field& sf = sfield(F_ORDINI); sf.disable(); livelli_giacenza().set_sheet_columns(sf, F_LIV1); livelli_giacenza().set_mask_fields(*this, F_LIV1); TConfig ini(CONFIG_DITTA, "mg"); if (!ini.get_bool("GESDEPOSITI", "mg")) { sf.delete_column(F_DEPOSITO); sf.sheet_mask().hide(F_DEPOSITO); } if (!ini.get_bool("GESTIMPIANTI", "mr")) { sf.delete_column(F_CODIMP); // Elimina colonna impianto sf.sheet_mask().hide(F_CODIMP); sf.sheet_mask().hide(F_DESCIMP); } TToken_string cod = line->articolo(); set(F_ARTICOLO,cod); set(F_DESCART,line->description()); cod.add("1"); set(F_UM,cache().get(LF_UMART,cod).get("UM")); for (int l = livelli_giacenza().last_level(); l>=1 ; l--) set(F_LIV1+l-1, line->livgiac(l)); bool has_internal_refs=FALSE; real lordo,netto,plan,sched; for (int b = line->last_bucket(); b >= 0 ; b--) { // TMRP_time dtime = line->record(b).time(); // if (extraleadtime && line->sons() == 0) // dtime.sub_time(extraleadtime); // const TDate &d = dtime.date(); const TDate &d = line->record(b).time().date(); if (isbuck0 || d >= fromdate) { set(F_FABB_DADATA, isbuck0 ? "" : fromdate); set(F_FABB_ADATA, todate); set(F_FABB_GIAC, line->record(b).on_hand().string()); if (d <= todate) { lordo += line->gross_requirement(b); netto += line->net_requirement(b); plan += line->planned_orders(b); sched += line->sched_receipts(b); TMRP_internalrefs *irefs = line->record(b).internal_refs(); if (irefs) { int ir = 0; while (ir < irefs->items()) { TMRP_internalref &iref = irefs->get_ref(ir); add_internal_ref(iref); ir ++; } has_internal_refs = TRUE; } else { add_gross_ref(*line,b); } } } } if (!has_internal_refs) for (int c = F_ARTICOLO; c < F_DOCANNODOC; c++) sf.delete_column(c); add_total_rows(); set(F_FABB_LORDO,lordo.string()); set(F_FABB_PIAN, plan.string()); set(F_FABB_SCHED, sched.string()); netto -= plan; set(F_TOPLAN, netto.string()); netto += plan + sched; set(F_FABB_NETTO,netto.string()); } bool TRisalita_mask::add_total_rows() { TSheet_field& sf = sfield(F_ORDINI); if (sf.items() == 0) return FALSE; sf.sort(compare_rows); TString codice(get(F_ARTICOLO)), codpadre, um; const TCodice_um um_nulla; TQuantita totale(codice, um_nulla, ZERO); TQuantita parziale(totale), qta, lordopadre; real val; int padri(0), riga(0); TToken_string * row; TString_array& ra = sf.rows_array(); while (row = (TToken_string *)ra.objptr(riga++)) { if (codpadre != row->get(sf.cid2index(F_ARTICOLO))) { if (!codpadre.blank()) { add_total_row(riga++, parziale.um(), parziale.val(), lordopadre.um(), lordopadre.val()); parziale.set_val(ZERO); lordopadre.set_articolo(codpadre, um_nulla); lordopadre.set_val(ZERO); padri++; } codpadre = row->get(sf.cid2index(F_ARTICOLO)); } // fabbisogno articolo row->get(sf.cid2index(F_FABBISOGNO), val); row->get(sf.cid2index(F_UMFABB), um); qta.set(codice, um, val); parziale += qta; totale += qta; // qta padre row->get(sf.cid2index(F_QUANTITA), val); row->get(sf.cid2index(F_UM), um); qta.set(codpadre.blank() ? codice : codpadre, um, val); lordopadre += qta; } add_total_row(riga++, parziale.um(), parziale.val(), lordopadre.um(), lordopadre.val()); if (padri > 0) add_total_row(riga, totale.um(), totale.val(), "", ZERO); sf.force_update(); return padri != 0; } int TRisalita_mask::compare_rows(TSheet_field &sf, int r1, int r2) { const TToken_string& s1 = sf.row(r1); const TToken_string& s2 = sf.row(r2); TString80 ss1, ss2; s1.get(sf.cid2index(F_ARTICOLO), ss1); s2.get(sf.cid2index(F_ARTICOLO), ss2); int d = ss1.compare(ss2); if (d == 0) { TDate d1, d2; s1.get(sf.cid2index(F_DATACONS), ss1); s2.get(sf.cid2index(F_DATACONS), ss2); d1 = ss1; d2 = ss2; d = int (d1 - d2); if (d == 0) { s1.get(sf.cid2index(F_FABBISOGNO), ss1); s2.get(sf.cid2index(F_FABBISOGNO), ss2); real r1(ss1),r2(ss2); r1 -= r2; d = r1.sign(); } } return d; } bool TRisalita_mask::add_total_row(int pos, const char* um , const real& lordo, const char* umpadre ,const real& lordopadre) { TSheet_field& sf = sfield(F_ORDINI); sf.insert(--pos); TToken_string & row = sf.row(pos); row.add(um, sf.cid2index(F_UMFABB)); row.add(lordo.string(), sf.cid2index(F_FABBISOGNO)); row.add(umpadre, sf.cid2index(F_UM)); row.add(lordopadre.string(), sf.cid2index(F_QUANTITA)); sf.disable_row(pos); return true; } bool TRisalita_mask::on_field_event(TOperable_field& o, TField_event e, long jolly) { switch (o.dlg()) { case F_RISALITA: if (e == fe_button) app().risalita(*this); break; default: break; } return true; } int TRisalita_mask::add_internal_ref(const TMRP_internalref &iref) { const TMRP_line& line=*iref.line(); int bucket=iref.bucket(); const TMRP_time &deliv_time = line.time(bucket); TMRP_time doc_time; line.lead_time(bucket,doc_time, TRUE); TSheet_field& s = sfield(F_ORDINI); TString_array& a = s.rows_array(); TToken_string dockey; TMRP_docrefs * gr_refs= line.record(bucket).requirements_refs(); int grref = gr_refs ? gr_refs->items() : 0; TMRP_docrefs * pl_refs= line.record(bucket).plans_refs(); int plref = pl_refs ? pl_refs->items() : 0; TMRP_docrefs * sr_refs = line.record(bucket).scheduls_refs(); int srref = sr_refs ? sr_refs->items() : 0; real totreq = line.net_requirement(bucket); totreq += line.sched_receipts(bucket); real qtaplan(totreq); real qtareq(totreq); do { TCodice_um um; TToken_string r; real q = iref.qta(); TMRP_docref * docref = NULL; if (grref > 0) docref = gr_refs->get_ref_ptr(--grref); else if (srref > 0) docref = sr_refs->get_ref_ptr(--srref); else if (plref > 0) docref = pl_refs->get_ref_ptr(--plref); if (docref) { dockey.add("D",0); dockey.add(docref->annodoc(),1); dockey.add(docref->codnumdoc(),2); dockey.add(docref->numdoc(),3); //const TString & codnum = docref->codnumdoc(); qtaplan = docref->qta_residua(); qtaplan.round(5); TQuantita qta(line.articolo(), docref->um(), docref->qta_residua()); qta.convert2umbase(); qtareq = qtareq - qta.val(); qtareq.round(5); // qtareq = qtareq - qtaplan; r.add(cache().get(LF_DOC,dockey).get(DOC_DATADOC),F_DATADOC - FIRST_FIELD); // data del documento di rif. r.add(docref->annodoc() , F_DOCANNODOC - FIRST_FIELD); r.add(docref->codnumdoc() , F_DOCCODNUM - FIRST_FIELD); r.add(docref->numdoc() , F_DOCNUM - FIRST_FIELD); r.add(docref->numrig() , F_DOCNRIGA - FIRST_FIELD); r.add(qtaplan.string() , F_QUANTITA - FIRST_FIELD); um = docref->um(); const TRectype& rdoc = docref->get_rdoc(); r.add(rdoc.get(RDOC_DAANNO), F_DAANNO - FIRST_FIELD); r.add(rdoc.get(RDOC_DACODNUM), F_DACODNUM - FIRST_FIELD); r.add(rdoc.get(RDOC_DANDOC), F_DANUMDOC - FIRST_FIELD); } else { qtaplan = qtareq; r.add(doc_time.date().string(), F_DATADOC - FIRST_FIELD); } TQuantita qta(line.articolo(), um, qtaplan); r.add(get(F_UM), F_UMFABB - FIRST_FIELD); r.add(deliv_time.date().string(), F_DATACONS - FIRST_FIELD); r.add(" ",F_FORNITORE - FIRST_FIELD); r.add(line.articolo(),F_ARTICOLO - FIRST_FIELD); const TString& liv = line.livgiac(); for (int l = livelli_giacenza().last_level(); l >= 1; l--) r.add(line.livgiac(l), F_LIV1+l-1 - FIRST_FIELD); r.add(line.codmag(), F_MAGAZZINO - FIRST_FIELD); r.add(line.coddep(), F_DEPOSITO - FIRST_FIELD); r.add(line.codimp(),F_CODIMP - FIRST_FIELD); r.add(line.codlin(),F_CODLIN - FIRST_FIELD); r.add("",F_PREZZO - FIRST_FIELD); r.add(line.description(),F_DESCART - FIRST_FIELD); r.add(qta.val().string(),F_QUANTITA - FIRST_FIELD); r.add(qta.um(),F_UM - FIRST_FIELD); // aggiunge il fabbisogno qta.convert2umbase(); q = iref.qta() * qta.val() / totreq; r.add(q.string(), F_FABBISOGNO - FIRST_FIELD); a.add(r); } while ((grref > 0 || srref > 0 || plref > 0) && qtareq > ZERO); return 0; } int TRisalita_mask::add_gross_ref(const TMRP_line& line, int bucket) { TSheet_field& s = sfield(F_ORDINI); TString_array& a = s.rows_array(); TToken_string dockey; real totreq, qtaplan, qtareq; TMRP_time deliv_time = line.time(bucket); TMRP_time doc_time; line.lead_time(bucket,doc_time, TRUE); TToken_string r; //const TString & codnum = docref->codnumdoc(); TMRP_docref * docref = NULL; TMRP_docrefs * gr_refs= line.record(bucket).requirements_refs(); int grref = gr_refs ? gr_refs->items() : 0; while (grref) { docref = gr_refs->get_ref_ptr(--grref); qtaplan = docref->qta_residua(); qtaplan.round(5); dockey.add("D",0); dockey.add(docref->annodoc(),1); dockey.add(docref->codnumdoc(),2); dockey.add(docref->numdoc(),3); r.add(cache().get(LF_DOC,dockey).get(DOC_DATADOC),F_DATADOC - FIRST_FIELD); // data del documento di rif. r.add(docref->annodoc(), F_DOCANNODOC - FIRST_FIELD); r.add(docref->codnumdoc(), F_DOCCODNUM - FIRST_FIELD); r.add(docref->numdoc(), F_DOCNUM - FIRST_FIELD); r.add(docref->numrig(), F_DOCNRIGA - FIRST_FIELD); r.add(deliv_time.date().string(), F_DATACONS - FIRST_FIELD); r.add(" ",F_FORNITORE - FIRST_FIELD); const TCodice_um um_nulla; const TQuantita qta(line.articolo(), docref->um(), qtaplan); r.add(qta.val().string(),F_QUANTITA - FIRST_FIELD); r.add(qta.um(),F_UM - FIRST_FIELD); r.add(qtaplan.string(), F_FABBISOGNO - FIRST_FIELD); r.add(qta.um(),F_UMFABB - FIRST_FIELD); a.add(r); } return 0; } /////////////////////////////////////////////////////////// // TMatResPlanning /////////////////////////////////////////////////////////// bool TMatResPlanning::test_codnum(const TString& codnum, const TString_array& a) const { TString4 tmp; FOR_EACH_ARRAY_ROW(a, i, row) { row->get(0, tmp); if (tmp == codnum) return true; } return false; } bool TMatResPlanning::test_codnum(const TCodice_numerazione& num, const TString_array& a) const { const TString& codnum = num.codice(); return test_codnum(codnum, a); } bool TMatResPlanning::has_confirmed_status(const TRectype& doc, const TToken_string& riga) const { char statodoc = doc.get_char(DOC_STATO); char state_def; riga.get(F_STATODEF - FIRST_FIELD, state_def); return statodoc >= state_def; } int TMatResPlanning::test_status(const TRectype& doc, const TString_array& a) const { const TString4 tipodoc = doc.get(DOC_TIPODOC); const char statodoc = doc.get_char(DOC_STATO); for (int i = a.items()-1; i >= 0; i--) { TToken_string& riga = (TToken_string&)a.row(i); const char* t = riga.get(0); if (tipodoc == t) { const char state_fr = riga.get_char(F_DASTATO - FIRST_FIELD); const char state_to = riga.get_char(F_ASTATO - FIRST_FIELD); if (statodoc >= state_fr && statodoc <= state_to) return i; } } return -1; } /////////// finished: 100% /////////// tested : 100% bool TMatResPlanning::load_gross_requirements() { const TMatResMask& m = *_mask; TDate date_fr = m.get(F_DADATA); const int bucket_fr = m.round_date(date_fr, FALSE); TDate date_to = m.get(F_ADATA); const int bucket_to = m.round_date(date_to, TRUE); const int year_fr = date_fr.year() - (m.get_bool(F_DOC_YEAR_PREC) ? 1 : 0); const int year_to = date_to.year(); const bool master = m.get(F_ORC_MASTER)[0] == 'M'; // Master Plan o Ordine Cliente // azzera l'array _requirements const bool nomag = m.get_bool(F_NOMAG); const bool nodep = m.get_bool(F_NODEP); const bool noimp = m.get_bool(F_NOIMP); const bool nolin = m.get_bool(F_NOLIN); const bool nokey = !m.get_bool(F_SINGLE_DOC); _articles.ignore(nomag, nodep, noimp, nolin, nokey); _articles.destroy(); TTable num("%NUM"); TCodice_numerazione cod; TRelation rel(LF_DOC); TCursor cur(&rel); const TRectype& curr_doc = cur.curr(); TRectype filter_fr(curr_doc), filter_to(curr_doc); TString_array& n = m.sfield(F_NUM_ORC).rows_array(); TString_array& a = m.sfield(F_TIPI_ORC).rows_array(); // Scandisce tutte le numerazioni considerando solo quelle // contenenti i tipi documento specificati nella maschera // Inizializza la cache delle lavorazioni _artinfo.init(m.get_bool(F_KEEP_IMP)); for (int err = cod.first(num); err == NOERR; err = cod.next(num)) if (test_codnum(cod, n)) { // Filtra il cursore in modo da limitarlo alla numerazione // corrente ed agli anni specificati dalle due date limite cur.freeze(false); filter_fr.put(DOC_PROVV, "D"); filter_fr.put(DOC_ANNO, year_fr); filter_fr.put(DOC_CODNUM, cod.codice()); filter_to.put(DOC_PROVV, "D"); filter_to.put(DOC_ANNO, year_to); filter_to.put(DOC_CODNUM, cod.codice()); cur.setregion(filter_fr, filter_to); TString16 cfilter; cfilter << DOC_CODNUM << "==\"" << cod.codice() << '"'; cur.setfilter(cfilter); const long items = cur.items(); cur.freeze(true); // Scandisce i documenti inevasi e considera solo // quelli con uno stato nel range corretto TString msg; msg << TR("Caricamento fabbisogni lordi") << "... (" << cod.codice() << ')'; TProgind pi(items, msg, true, true); for (cur = 0; cur.pos() < items; ++cur) { if (!pi.addstatus(1)) break; const bool evaso = curr_doc.get_bool(DOC_DOCEVASO); if (evaso) continue; TDate doc_cons = curr_doc.get(DOC_DATACONS); if (!doc_cons.ok()) doc_cons = curr_doc.get(DOC_DATADOC); if (test_status(curr_doc, a)>=0) { // Scandisce le righe articolo e memorizza le quantita' richieste const TDocumento doc(curr_doc); 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()) continue; TDate datacons = riga.get(RDOC_DATACONS); if (!datacons.ok()) datacons = doc_cons; // Data consegna troppo avanti if (datacons > date_to) continue; const real qta = riga.qtaresidua(); if (qta > ZERO) { const TCodice_articolo art = riga.get(RDOC_CODARTMAG); const TString16 liv = riga.get(RDOC_LIVELLO); TString8 mag = nomag ? EMPTY_STRING : riga.get(RDOC_CODMAG).left(nodep ? 3 : 5); TString8 imp = noimp ? EMPTY_STRING : riga.get(RDOC_IMPIANTO); TString8 lin = nolin ? EMPTY_STRING : riga.get(RDOC_LINEA); const TCodice_um um = riga.get(RDOC_UMQTA); // GUY was Here, but it's Koki fault! const long codcli = is_production_article(art) ? doc.get_long(DOC_CODCF) : 0; TString80 rdoc_key = riga.build_key(); 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)); TPrice prz(riga.prezzo(TRUE,TRUE)); TQuantita q(art, um, qta); q.convert2umbase(); q.currency2umbase(prz); if (lin.empty()) _artinfo.art2magimpline(art, mag, imp, lin); TMRP_line* line = _articles.find(art, liv, mag, EMPTY_STRING, imp, lin, codcli, rdoc_key); if (line == NULL) { // nuova linea line = _articles.find(art, liv, mag, EMPTY_STRING, imp, lin, codcli, rdoc_key, true); line->set_description(riga.get(RDOC_DESCR)); line->set_final_product(); } const int anno = doc.get_int(DOC_ANNO); const TString4 codnum = doc.get(DOC_CODNUM); const long ndoc = doc.get_long(DOC_NDOC); const int numriga = riga.get_int(RDOC_NRIGA); TMRP_docref* docref = new TMRP_docref(anno, codnum, ndoc, numriga, um, qta, prz.get_num()); TMRP_time t(datacons, 0, imp, lin); if (m.get_int(F_LDTIME_MODE) != 0) { t.add_time(0, -1); // Toglie un'ora: sposta datacons a fine turno t.add_time(0, +1); // Riaggiunge un'ora nel giorno stesso } line->add_gross_req(t, q.val(), docref); if (master) line->add_net_req(t, q.val()); } } } } } return _articles.items() > 0L; } /////////// finished: 100% /////////// tested : 100% static bool cyclic(TTree& tree, void* jolly, word flags) { TDistinta_tree & distinta = (TDistinta_tree &) tree; return distinta.is_cyclic(); } bool TMatResPlanning::explode_articles() { const TMatResMask& m = *_mask; TDistinta_tree distinta; // albero distinta TArray boom; // array per i figli int level = 0; int maxlevel = m.get_int(F_MAXLEVEL); bool finiti = TRUE; TProgind* pi = NULL; // Inizializza la cache delle lavorazioni // _artinfo.init(m.get_bool(F_KEEP_IMP)); ?? // Scandisce gli articoli inseriti dal gross requirements ed // accoda tutti gli articoli risultanti dalla loro esplosione for (long a = 0; a < _articles.items(); a++) { if (pi && pi->isfinished()) { delete pi; pi = NULL; finiti = FALSE; } if (pi == NULL) { if (maxlevel > 0 && level >= maxlevel) return _articles.items() > 0; TString80 msg; msg.format(FR("Esplosione articoli (livello %d)"), ++level); pi = new TProgind(_articles.items()-a, msg, TRUE, TRUE); } if (!pi->addstatus(1)) { delete pi; pi = NULL; return FALSE; } TMRP_line& line = _articles[a]; // Se la linea dell'articolo principale e' vuota (non c'era sull'ordine) me la invento. if (line.codlin().empty()) { TString8 mag = line.codmagdep(), imp = line.codimp(), lin = line.codlin(); _artinfo.art2magimpline(line.articolo(), mag, imp, lin); if (lin.full()) line.set_imp_lin(imp, lin); } distinta.set_global("_DISTINTA", line.articolo()); distinta.set_global("_MAGDEP" , line.codmagdep()); distinta.set_global("_IMPIANTO", line.codimp()); distinta.set_global("_LINEA" , line.codlin()); if (distinta.set_root(line.articolo(), "", 1.0 , line.livgiac())) { line.set_final_product(FALSE); distinta.goto_root(); if (distinta.scan_depth_first(cyclic, NULL)) { TToken_string & rdoc = (TToken_string &)line.da_rdoc_key(); error_box ("Ordine %s %d/%ld riga n. %d - Distinta %s ciclica", (const char *) rdoc.left(4), atoi(rdoc.mid(4, 4)), atoi(rdoc.mid(9, 7)), atoi(rdoc.mid(16)), (const char *) line.articolo()); continue; } distinta.explode(boom, FALSE, RAGGR_EXP_UMBASE, 1, "AV"); for (int i = 0; i < boom.items(); i++) { const TRiga_esplosione& riga = (const TRiga_esplosione&)boom[i]; const TCodice_articolo& art = riga.articolo(); const TRectype& articolo=cache().get(LF_ANAMAG,art); bool add=true; if (articolo.get(ANAMAG_CODART).full()) { const char reorder_type=articolo.get_char(ANAMAG_RIORDINO); if (reorder_type!='F' && reorder_type!=' ' && reorder_type!='\0') // e' a riordino add=false; } if (add) { // articolo gestito dall'MRP TString8 mag = line.codmagdep(); TString8 imp = line.codimp(); TString8 lin = line.codlin(); _artinfo.art2magimpline(art, mag, imp, lin); // GUY was here with Koki const long codcli = is_production_article(art) ? line.codclifor() : 0L; const TString& rdoc_key = line.da_rdoc_key(); TMRP_line* son = _articles.find(art, riga.giacenza(), mag, EMPTY_STRING, imp, lin, codcli, rdoc_key); if (son == NULL) { son = _articles.find(art, riga.giacenza(), mag, EMPTY_STRING, imp, lin, codcli, rdoc_key, true); son->set_description(distinta.describe(art)); } const int son_depth = line.explosion_depth()+1; if (son_depth > son->explosion_depth()) son->set_explosion_depth(son_depth); line.add_son(riga.val(), son); distinta.describe(art); } } } } if (pi != NULL) delete pi; return _articles.items() > 0; } /////////// finished: 100% /////////// tested: bool TMatResPlanning::load_planned_orders() { const TMatResMask& m = *_mask; TDate date_fr = m.get(F_DADATA); const int bucket_fr = m.round_date(date_fr, FALSE); TDate date_to = m.get(F_ADATA); const int bucket_to = m.round_date(date_to, TRUE); const int year_fr = date_fr.year() - (m.get_bool(F_DOC_YEAR_PREC) ? 1 : 0); const int year_to = date_to.year(); const bool load_evasi = m.get_bool(F_LOAD_EVASI); 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); const TString_array& n = m.sfield(F_NUM_ORF).rows_array(); const TString_array& a = m.sfield(F_TIPI_ORF).rows_array(); // 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)) if (test_codnum(cod, n)) { // Filtra il cursore in modo da limitarlo alla numerazione // corrente ed agli anni specificati dalle due date limite cur.freeze(false); filter_fr.put(DOC_PROVV, "D"); filter_fr.put(DOC_CODNUM, cod.codice()); filter_fr.put(DOC_ANNO, year_fr); filter_to.put(DOC_PROVV, "D"); filter_to.put(DOC_CODNUM, cod.codice()); filter_to.put(DOC_ANNO, year_to); cur.setregion(filter_fr, filter_to); TString16 cfilter; cfilter << DOC_CODNUM << "==" << '"' << cod.codice() << '"' ; cur.setfilter(cfilter); const long items = cur.items(); cur.freeze(true); TString msg; msg << TR("Caricamento arrivi futuri") << "... (" << cod.codice() << ')'; TProgind pj(items, msg, true, true); // Scandisce i documenti inevasi e considera solo // quelli con uno stato nel range corretto for (cur = 0; cur.pos() < items; ++cur) { if (!pj.addstatus(1)) break; const bool doc_evaso = curr.get_bool(DOC_DOCEVASO); const bool evaso = !load_evasi && doc_evaso; if (evaso) continue; const int sheetrow = test_status(curr, a); if (sheetrow<0) continue; // Data di consegna standard TDate doc_cons = curr.get(DOC_DATACONS); if (!doc_cons.ok()) doc_cons = curr.get_date(DOC_DATADOC); // 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()) continue; TDate consegna = riga.get(RDOC_DATACONS); if (!consegna.ok()) consegna = doc_cons; // Data consegna troppo avanti if (consegna > date_to) continue; bool padre_evaso = false; if (load_evasi) { const TRectype* dariga = riga.find_original_rdoc(); if (dariga != NULL && dariga->get_bool(RDOC_RIGAEVASA)) { const TRectype* dadoc = riga.find_original_doc(); if (dadoc != NULL) padre_evaso = dadoc->get_bool(DOC_DOCEVASO); } } const real qta = load_evasi && !padre_evaso ? riga.quantita() : riga.qtaresidua(); if (qta > ZERO) { const TCodice_articolo art = riga.get(RDOC_CODARTMAG); const TString16 liv = riga.get(RDOC_LIVELLO); const TString8 mag = riga.get(RDOC_CODMAG); const TString8 imp = riga.get(RDOC_IMPIANTO); const TString8 lin = riga.get(RDOC_LINEA); // GUY was Here, but it's Koki fault! const long codcli = is_production_article(art) ? doc.get_long(DOC_CODCF) : 0; TString80 rdoc_key ; 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)); TMRP_line* line = _articles.find(art, liv, mag, EMPTY_STRING, imp, lin, codcli, rdoc_key); if (line == NULL) { line = _articles.find(art, liv, mag, EMPTY_STRING, imp, lin, codcli, rdoc_key, true); line->set_description(riga.get(RDOC_DESCR)); } TPrice prz(riga.prezzo(TRUE,TRUE)); const TCodice_um um = riga.get(RDOC_UMQTA); TQuantita q(art, um, qta); q.convert2umbase(); q.currency2umbase(prz); const TString4 codnum = doc.get(DOC_CODNUM); const long docnum = doc.get_long(DOC_NDOC); const int numriga = riga.get_int(RDOC_NRIGA); TMRP_docref* docref = new TMRP_docref(doc.get_int(DOC_ANNO), codnum, docnum, numriga, um, q.val(), prz.get_num()); const TMRP_time t(consegna, 0, imp, lin); if (has_confirmed_status(doc, a.row(sheetrow)) || (codnum != m.get(F_NUM_PROD) && codnum != m.get(F_NUM_FORN))) line->add_sched_rec(t, q.val(), docref); else line->add_planned_ord(t, q.val(), docref); } } } } return _articles.items() > 0L; } /////////// finished: 99% /////////// tested: 99% bool TMatResPlanning::preprocess_cycle() { // costruisce il gross requirement dai DOC di planning bool ok=load_gross_requirements(); // costruisce gli sched rec degli elementi dai DOCS ordini fornitore emessi ok |= load_planned_orders(); if (ok) // esplode l'array mediante la Distinta Base return explode_articles(); /* // costruisce il gross requirement dai DOC di planning if (load_gross_requirements(m)) // esplode l'array mediante la DIBA if (explode_articles(m)) // costruisce gli sched rec degli elementi dai DOCS ordini fornitore emessi return load_planned_orders(m); */ return false; } long TMatResPlanning::compute_production_time(const TMRP_line& line, const real& qta) const { real tot; if (line.codlin().not_empty()) { TDistinta_tree tree; tree.set_global("_MAGDEP", line.codmagdep()); tree.set_global("_LINEA", line.codlin()); tree.set_global("_IMPIANTO", line.codimp()); tree.set_root(line.articolo(), "", qta, line.livgiac()); TArray lav_array; for (TRiga_esplosione* llav = tree.first_labor(lav_array, RAGGR_EXP_UMBASE); llav; llav = tree.next_labor(lav_array)) { TLavorazione* lavorazione = tree.find_labor(llav); const int linea = lavorazione->find_linea(line.codlin()); if (linea >= 0) { const real prod_linea = lavorazione->produttiv_linea(linea); real ore = (llav->val() * lavorazione->um_temporale().converti_in_ore()) / prod_linea; // if (carico_uomo) ore *= lavorazione->numpers_linea(linea); tot += ore; } } tot.ceil(); } return tot.integer(); } /////////// finished: 99% /////////// tested: // implementa la logica che porta dal fabbisogno lordo a quello netto // per quel bucket e riporta il balance on hand sul bucket successivo // ipotesi essenziale per il rescheduling: la chiamata della funzione // deve essere fatta ciclicamente su tutti i bucket di un articolo // prima di passare ad un altro articolo bool TMatResPlanning::gross2net_logic(TMRP_line &curr_article, int bucket, bool & sc_used) { const TMatResMask& m = *_mask; const TDate start_date =m.get_date(F_DADATA); const bool lotsizing_p =m.get_bool(F_LOTSIZING_P); const bool lotsizing_f =m.get_bool(F_LOTSIZING_F); const bool use_leadtime =!m.get_bool(F_IGN_LDTIME); // Verifico se esiste gia' un fabbisogno netto real sm,tmpreal = -curr_article.net_requirement(bucket); if (tmpreal >= ZERO) // Devo calcolare il fabbisogno netto { tmpreal = curr_article.on_hand(bucket); tmpreal -= curr_article.gross_requirement(bucket); if (!sc_used) { curr_article.scorta_minima(sm, curr_article.time(bucket).date()); sc_used = true; tmpreal -= sm; } } // tmpreal += curr_article.planned_orders(bucket); //planned orders are not added here, but in build orders phase if (!m.get_bool(F_RESCHEDULING)) tmpreal += curr_article.sched_receipts(bucket);//scheduled orders are not added if we reschedule them // adegua il quantitativo del fabbisogno netto in base al lot-sizing, se il valore risulta negativo const int n_figli = curr_article.sons(); real net_req; if ((lotsizing_p && n_figli!=0 )||(lotsizing_f && n_figli==0) ) net_req = curr_article.sizeup_net_requirement(bucket, tmpreal); else net_req = curr_article.set_net_req(bucket, -tmpreal); // calcola la giacenza del bucket successivo tmpreal += net_req; if (tmpreal > ZERO) { const int nb = curr_article.next_bucket(bucket); if (nb <= curr_article.last_bucket()) curr_article.set_on_hand(nb, tmpreal); } // trasforma i fabbisogni totali nel fabbisogno lordo dei figli net_req += curr_article.sched_receipts(bucket); // net_req += curr_article.planned_orders(bucket);//planned orders are not added here, but in build orders phase if (net_req > ZERO && n_figli > 0) { TMRP_time lead_time; curr_article.lead_time(bucket, lead_time, use_leadtime); const int ldtime_mode = m.get_int(F_LDTIME_MODE); if (ldtime_mode == 1 || ldtime_mode == 2) { const long xtrahours = compute_production_time(curr_article, net_req); if (xtrahours > 0) { if (ldtime_mode == 1) lead_time.sub_time(0, xtrahours); else { TMRP_time prod_time = curr_article.time(bucket); prod_time.sub_time(0, xtrahours); if (prod_time < lead_time) lead_time = prod_time; } } } const int xtradays = m.get_int(F_XTRA_LDTIME); if (xtradays) lead_time.sub_time(xtradays); for (int o = 0; o < n_figli; o++) { TMRP_line& article_son = curr_article.son(o); tmpreal = net_req * curr_article.qta_son(o); tmpreal.round(5); if (tmpreal > ZERO) { TMRP_internalref * iref = new TMRP_internalref( &curr_article, bucket, tmpreal); article_son.add_gross_req(lead_time, tmpreal, iref); } } } return true; } /////////// finished: 99% /////////// tested: bool TMatResPlanning::net_requirement_cycle() { const TMatResMask& m = *_mask; const bool use_mag = !m.get_bool(F_DONT_USE_MAG); bool ok = true; // ordina gli articoli const long total = _articles.sort(); TProgind pi(total, TR("Calcolo dei fabbisogni netti"), false, true); // cicla iterativamente sugli elementi di _articles for (long a = 0; a < total; a++) { pi.addstatus(1); TMRP_line& curr_article = _articles[a]; const int last = curr_article.last_bucket(); if (last >= 0) { real curgiac; if (use_mag) curr_article.giacenza_attuale(curgiac, m.get_date(F_DADATA)); curr_article.set_on_hand(0, curgiac); bool sc_used = false; for (int bucket = 0; ok && bucket <= last; bucket = curr_article.next_bucket(bucket)) { // !?!?! la logica gross2net dovrebbe funzionare in termini di intervalli di date // (bucket-utente) piuttosto che di bucket di MRPline (che possono essere più di uno // in un intervallo, altrimenti i ragionamenti di scorte minime e lotti // funzionano in modo sbagliato, perchè approssimano più volte ok = gross2net_logic(curr_article, bucket, sc_used); if (!ok) break; } } } return ok; } /////////// finished: 100% /////////// tested : 100% // genera le righe degli ordini di produzione o a fornitore bool TMatResPlanning::build_orders() { TMatResMask& m = *_mask; TSheet_field& sf = m.sfield(F_ORDINI); sf.destroy(); const long tot = _articles.items(); if (tot > 0L) { TProgind pi(tot, TR("Generazione righe ordini..."), false, true); for (long a = 0; a < tot; a++) { pi.addstatus(1); const TMRP_line& line = _articles[a]; const bool prod = is_production_article(line.articolo()); long forn = 0; if (!prod) // Se l'articolo NON e' di produzione ... { TString80 key = line.codimp(); key.rpad(5); key << line.articolo(); // Cerco il fornitore specifico per l'impianto forn = atol(cache().get("FIA", key, "I0")); if (forn == 0L) // Cerco il fornitore di default in anagrafica { const TRectype& anarec = cache().get(LF_ANAMAG,line.articolo()); forn = anarec.get_long("CODFORN"); } } else forn = line.codclifor(); // Prendo il codice "eventualmente" proveniente dall'ordine for (int b = line.last_bucket(); b >= 0; b--) { /* const TMRP_record & rrr = line.record(b); const real r0 = line.gross_requirement(b); const real r1 = line.planned_orders(b); const real r2 = line.sched_receipts(b); real qta = line.net_requirement(b); qta -= line.planned_orders(b); qta.round(5); if (!qta.is_zero() || line.planned_orders(b)>0 || line.sched_receipts(b)>line.gross_requirement(b)) m.add_order_line(forn, line, b); else */ m.add_order_line(forn, line, b); } } } const int orders=sf.items(); if (orders==0) message_box(TR("Nessun ordine da emettere")); real price, qta; TCodice_articolo codart; FOR_EACH_SHEET_ROW(sf,n,row) { row->get(F_QUANTITA - FIRST_FIELD,qta); row->get(F_ARTICOLO - FIRST_FIELD,codart); const long codcli=row->get_long(F_FORNITORE - FIRST_FIELD); const TRectype& rec=cache().get(LF_DIST, codart); bool art_prod, art_acq; if (rec.empty()) { art_acq=TRUE; art_prod = is_production_article(codart); } else { art_prod = rec.get_bool("ARTPROD"); art_acq = rec.get_bool("ARTACQ") || codcli!=0L; } TString4 tipoord = art_prod ? "P" : "F" ; row->add(tipoord, F_ORD_TYPE - FIRST_FIELD); sf.check_row(n); if (tipoord=="P") tipoord=" "; else tipoord=m.get(F_TIPOCF_CONDV); find_price(m.get(F_TIPOCV),m.get(F_CODCONDV),m.get(F_CATVEN_CV), tipoord, codcli, codart, qta, price); row->add(price.string(), F_PREZZO - FIRST_FIELD); if (!art_prod || !art_acq) sf.disable_cell(n,F_ORD_TYPE - FIRST_FIELD); } sf.enable(!m.get_bool(F_DISABLESAVE)); return TRUE; } /////////// finished: 0% void TMatResPlanning::print_orders_header(TPrinter& pr) { TPrintrow row; print_header(pr); row.put(FR("@48G@BSTAMPA PROPOSTE D'ORDINE DA M.R.P.")); pr.setheaderline(1,row); row.reset(); set_body_order_line(row, NULL); pr.setheaderline(3,row); row.reset(); row.put((const char *)TString(131,'-')); pr.setheaderline(4,row); } void TMatResPlanning::print_orders_body(TPrinter& pr, TToken_string *sheetrow) { TPrintrow row; // riga 1 set_body_order_line(row, sheetrow); // riga 2 pr.print(row); row.reset(); int pos = 31; row.put(format("@%dG%s", pos, (const char *)sheetrow->get(F_DESCART-FIRST_FIELD))); if (*sheetrow->get(F_DOCCODNUM-FIRST_FIELD) > ' ') { row.put(format(FR("@%dGDocumento %s"), pos+= 54+1, (const char *)sheetrow->get(F_DOCCODNUM-FIRST_FIELD))); row.put(format("@%dG%d", pos+= 4+10+1, sheetrow->get_int(F_DOCANNODOC-FIRST_FIELD))); row.put(format("@%dGn.%6ld", pos+= 4+1, sheetrow->get_long(F_DOCNUM-FIRST_FIELD))); row.put(format(FR("@%dGriga %3d"), pos+= 2+6+1, sheetrow->get_int(F_DOCNRIGA-FIRST_FIELD))); } pr.print(row); } void TMatResPlanning::set_body_order_line(TPrintrow &row, TToken_string *sheetrow) { int pos = 0; row.put(format("@b@%dG%1s", pos, sheetrow ? (const char *)sheetrow->get(F_ORD_TYPE-FIRST_FIELD): "")); row.put(format("@%dG%6s", pos+= 1+1, sheetrow ? (const char *)sheetrow->get(F_FORNITORE-FIRST_FIELD): "CliFor")); row.put(format("@%dG%s", pos+= 6+1, sheetrow ? (const char *)sheetrow->get(F_DATADOC-FIRST_FIELD): "Data doc.")); row.put(format("@%dG%s", pos+= 10+1, sheetrow ? (const char *)sheetrow->get(F_DATACONS-FIRST_FIELD): "Consegna")); row.put(format("@%dG%s", pos+= 10+1, sheetrow ? (const char *)sheetrow->get(F_ARTICOLO-FIRST_FIELD): "Codice articolo")); pos += 20+1; for (int l = 1; l <= livelli_giacenza().last_level(); l++) { const int len = livelli_giacenza().code_length(l); if (sheetrow == NULL) { if (l == 1) row.put(format("@%dG%s", pos, "Livello")); } else row.put(format("@%dG%s", pos, (const char *)sheetrow->get(F_LIV1+l-1-FIRST_FIELD))); pos += len+1; } real r; if (sheetrow) { sheetrow->get(F_QUANTITA-FIRST_FIELD, r); row.put(format("@%dG%18s", pos, (const char *)r.string(18,5))); } else { row.put(format(FR("@%dGQuantita'"), pos+8)); } row.put(format("@%dG%s", pos+= 18+1, sheetrow ? (const char *)sheetrow->get(F_UM-FIRST_FIELD): "UM")); if (sheetrow) sheetrow->get(F_PREZZO-FIRST_FIELD, r); const TPrice c(r); row.put(format("@%dG%18s", pos+=2+1, sheetrow ? (const char *)c.string(): "Prezzo")); row.put(format("@%dG%3s", pos+=18+1, sheetrow ? (const char *)sheetrow->get(F_MAGAZZINO-FIRST_FIELD): "Mag.")); row.put(format("@%dG%2s", pos+= 3+1, sheetrow ? (const char *)sheetrow->get(F_DEPOSITO-FIRST_FIELD): "")); row.put(format("@%dG%5s", pos+= 2+1, sheetrow ? (const char *)sheetrow->get(F_CODIMP-FIRST_FIELD): "Imp.")); row.put(format("@%dG%5s", pos+= 5+1, sheetrow ? (const char *)sheetrow->get(F_CODLIN-FIRST_FIELD): "Linea")); pos += 5+1; } /////////// tested : 0% // stampa le proposte d'ordine bool TMatResPlanning::print_orders() { TMatResMask& m = *_mask; TSheet_field& sf = m.sfield(F_ORDINI); if (sf.items() <= 0) { message_box(TR("Nessun ordine da stampare")); return FALSE; } TMask pmask("mr2100c.msk"); pmask.set(S_LIV_RISALITA,1); while (pmask.run() != K_ESC) { if (pmask.get(S_PRINTTYPE)[0] == 'O') { print_planning(pmask); } else { print_exceptions(pmask); } } return TRUE; } bool TMatResPlanning::print_planning(TMask &pmask) { TMatResMask& m = *_mask; TSheet_field& sf = m.sfield(F_ORDINI); TPrinter& pr = printer(); pr.open(); if (pmask.get_bool(S_RISALITA)) { TIndwin(60,TR("Ordinamento proposte per articolo/data..."),FALSE); sf.sort(order_compareADTF); sf.force_update(); } pr.setheaderhandler(print_orders_header); pr.headerlen(6); pr.setfooterhandler(print_footer); pr.footerlen(2); TString last_key; TString key; FOR_EACH_SHEET_ROW(sf, r, row) { if (!pmask.get_bool(S_SELECTEDONLY) || *row->get(sf.cid2index(F_SELECTED)) == 'X') { key = row->get(sf.cid2index(F_ARTICOLO)); key << row->get(sf.cid2index(F_DATACONS)); if (last_key.blank()) last_key = key; print_orders_body(pr,row); if (pmask.get_bool(S_RISALITA) /*&& (key != last_key || sf.items() == r)*/) { print_risalita(*row, pmask.get_int(S_LIV_RISALITA), pmask.get_bool(S_DETT_ORDINI)); last_key=key; } if (pmask.get_bool(S_INTERLINEA)) { TPrintrow prow; pr.print(prow); } } } pr.close(); return true; } TMRP_line* TMatResPlanning::find_risalita_line(TToken_string &row) { TSheet_field& sf = _mask->sfield(F_ORDINI); TCodice_articolo art; row.get(sf.cid2index(F_ARTICOLO), art); if (art.blank()) return NULL; TString16 liv; for (int l= livelli_giacenza().last_level(); l>=1; l--) livelli_giacenza().pack_grpcode(liv, row.get(sf.cid2index(F_LIV1+l-1)), l); TString8 mag, magc, imp, lin; add_magcode(mag, row.get(sf.cid2index(F_MAGAZZINO))); add_depcode(mag, row.get(sf.cid2index(F_DEPOSITO ))); row.get(sf.cid2index(F_CODIMP), imp); row.get(sf.cid2index(F_CODLIN), lin); const long codcf = row.get_long(sf.cid2index(F_FORNITORE)); TString80 rdoc_key; rdoc_key.format("%-4s%4dD%7ld%4d", row.get(sf.cid2index(F_DACODNUM)), row.get_int(sf.cid2index(F_DAANNO)), row.get_long(sf.cid2index(F_DANUMDOC)), row.get_int(sf.cid2index(F_DANRIGA))); TMRP_line* line = NULL; if (_mask->get_bool(F_SINGLE_DOC)) line = _articles.find(art, liv, mag, magc, imp, lin, codcf, rdoc_key); if (line == NULL) { line = _articles.find(art, liv, mag, magc, imp, lin, codcf, EMPTY_STRING); if (line == NULL) { line = _articles.find(art, liv, mag, magc, imp, lin, 0L, EMPTY_STRING); // Riprovo senza clifo if (line == NULL) { line = _articles.find(art, liv, mag, magc, imp, EMPTY_STRING, codcf, EMPTY_STRING); // Riprovo senza linea if (line == NULL) { line = _articles.find(art, liv, mag, magc, EMPTY_STRING, lin, codcf, EMPTY_STRING); // Riprovo senza impianto if (line == NULL) { line = _articles.find(art, liv, mag, magc, imp, EMPTY_STRING, 0L, EMPTY_STRING); // Riprovo senza nulla } } } } } return line; } bool TMatResPlanning::print_risalita(TToken_string &row, int ris_level, bool dett_ord) { TMRP_line* line = find_risalita_line(row); if (line != NULL) { const TSheet_field& sf = _mask->sfield(F_ORDINI); print_risalita(*line, row.get(sf.cid2index(F_DATACONS)), ris_level, dett_ord); return true; } else { TPrintrow prow; prow.put(format(FR("@32gRisalita: impossibile rintracciare la proposta originale"))); printer().print(prow); return false; } } bool TMatResPlanning::print_risalita(const TMRP_line & line, const TDate &date, int backlevel, bool dett_ord) { TPrinter& pr = printer(); TDate todate(date); TDate fromdate = todate; const bool isbuck0 = round_date(fromdate) == 0; round_date(todate,TRUE); int rows=0; //int extraleadtime = _mask->get_int(F_XTRA_LDTIME); real on_hand, lordo, netto, plan, sched; for (int b = line.last_bucket(); b >= 0 ; b--) { //TMRP_time dtime = line.record(b).time(); //if (extraleadtime && line.sons() == 0) // dtime.sub_time(extraleadtime); //const TDate &d = dtime.date(); const TDate &d = line.record(b).time().date(); if ((isbuck0 || d >= fromdate)) { if (d <= todate) { on_hand = line.record(b).on_hand(); lordo += line.gross_requirement(b); netto += line.net_requirement(b); plan += line.planned_orders(b); sched += line.sched_receipts(b); TMRP_internalrefs *irefs = line.record(b).internal_refs(); if (irefs != NULL) { int ir = 0; while (ir < irefs->items()) { TMRP_internalref &iref = irefs->get_ref(ir); rows += print_internal_ref(iref, backlevel, dett_ord); ir ++; } } else { rows += print_gross_ref(line, b); } } } } if (rows==0) return FALSE; TPrintrow prow; int pos = 30; prow.put(format(FR("@%dg Totale fabbisogno lordo %s"), pos, lordo.string(18,5))); pr.print(prow); prow.put(format(FR("@%dg Giacenza iniziale %s"), pos, on_hand.string(18,5))); pr.print(prow); if (dett_ord) { prow.put(format(FR("@%dg Ordini pianificati %s"), pos, plan.string(18,5))); pr.print(prow); prow.put(format(FR("@%dg Ordini confermati %s"), pos, sched.string(18,5))); pr.print(prow); } sched += plan; prow.put(format(FR("@%dg Totale ordinato %s"), pos, sched.string(18,5))); pr.print(prow); netto -= plan; prow.put(format(FR("@%dg Totale da pianificare %s"), pos, netto.string(18,5))); pr.print(prow); if (backlevel>1 || backlevel<0) { prow.reset(); pr.print(prow); } return TRUE; } int TMatResPlanning::print_internal_ref(const TMRP_internalref &iref, int backlevel, bool dett_ord) { TPrinter& pr = printer(); int rows=0; const TMRP_line& line=*iref.line(); int bucket=iref.bucket(); const TMRP_time &deliv_time = line.time(bucket); { TMRP_time doc_time; line.lead_time(bucket,doc_time, TRUE); TDate docdate = doc_time.date(); TToken_string dockey; TMRP_docrefs * gr_refs= line.record(bucket).requirements_refs(); int grref = gr_refs ? gr_refs->items() : 0; TMRP_docrefs * pl_refs= line.record(bucket).plans_refs(); int plref = pl_refs ? pl_refs->items() : 0; TMRP_docrefs * sr_refs = line.record(bucket).scheduls_refs(); int srref = sr_refs ? sr_refs->items() : 0; real totreq = line.net_requirement(bucket); totreq += line.sched_receipts(bucket); real qtaplan(totreq); real qtareq(totreq); do { TCodice_um um; TPrintrow r1, r2; real q = iref.qta(); TMRP_docref * docref = NULL; if (grref > 0) docref = gr_refs->get_ref_ptr(--grref); else if (srref > 0) docref = sr_refs->get_ref_ptr(--srref); else if (plref > 0) docref = pl_refs->get_ref_ptr(--plref); if (docref) { dockey.add("D",0); dockey.add(docref->annodoc(),1); dockey.add(docref->codnumdoc(),2); dockey.add(docref->numdoc(),3); qtaplan = docref->qta_residua(); qtaplan.round(5); TQuantita qta(line.articolo(), docref->um(), docref->qta_residua()); qta.convert2umbase(); qtareq = qtareq - qta.val(); qtareq.round(5); // documento di rif. docdate = cache().get(LF_DOC,dockey).get(DOC_DATADOC); r2.put(format(FR("@86gDocumento %s"),(const char *)docref->codnumdoc() )); r2.put(format("@101g%d",docref->annodoc() )); r2.put(format("@106gn.%6ld",docref->numdoc())); r2.put(format(FR("@115griga %3d"),docref->numrig())); um = docref->um(); } else { qtaplan = qtareq; } TQuantita qta(line.articolo(), um, qtaplan); r1.put(format("@9g%s", (const char *) docdate.string())); r1.put(format("@20g%s", (const char *)deliv_time.date().string())); r1.put(format("@31g%s", (const char *)line.articolo())); int pos= 52; for (int l = 1; l <= livelli_giacenza().last_level(); l++) { r1.put(format("@%dg%s",pos, (const char *)line.livgiac(l))); pos += livelli_giacenza().code_length(l)+1; } // aggiunge il fabbisogno r1.put(format("@%dg%s", pos+18+1+2+1, (const char *)qta.val().string(15,2))); r1.put(format("@%dg%s", pos+18+1+2+1+15+1, (const char *)qta.um())); qta.convert2umbase(); q = iref.qta() / totreq * qta.val(); r1.put(format("@%dg%s", pos, (const char *)q.string(18,5))); r1.put(format("@%dg%s", pos+=18+1, (const char *)"\"\"")); pos +=2+1+15+1; r1.put(format("@%dg%s", pos+=2+1, (const char *)line.codmag())); r1.put(format("@%dg%s", pos+=3+1, (const char *)line.coddep())); r1.put(format("@%dg%s", pos+=2+1, (const char *)line.codimp())); r1.put(format("@%dg%s", pos+=5+1, (const char *)line.codlin())); r2.put(format("@31g%s", (const char *)line.description())); pr.print(r1); pr.print(r2); rows++; } while ((grref > 0 || srref > 0 || plref > 0) && qtareq > ZERO); } if (--backlevel != 0) print_risalita(line, deliv_time.date(), backlevel, dett_ord); return rows; } int TMatResPlanning::print_gross_ref(const TMRP_line& line, int bucket) { return 0; // Guy: a cosa serve ???????????????????????????????????????????????? TPrinter& pr = printer(); TToken_string dockey; real totreq, qtaplan, qtareq; TMRP_time deliv_time = line.time(bucket); TMRP_time doc_time; line.lead_time(bucket,doc_time, TRUE); TPrintrow r; TMRP_docref * docref = NULL; TMRP_docrefs * gr_refs= line.record(bucket).requirements_refs(); int grref = gr_refs ? gr_refs->items() : 0; while (grref) { docref = gr_refs->get_ref_ptr(--grref); qtaplan = docref->qta_residua(); qtaplan.round(5); dockey.add("D",0); dockey.add(docref->annodoc(),1); dockey.add(docref->codnumdoc(),2); dockey.add(docref->numdoc(),3); // data del documento di rif. //r.put(format("", add(cache().get(LF_DOC,dockey).get(DOC_DATADOC))); r.put(format("@82g%d",docref->annodoc())); r.put(format("@86g%s",(const char *) docref->codnumdoc())); r.put(format("@90g%ld", docref->numdoc())); r.put(format("@100g%riga n.d", docref->numrig())); //r.put(format("", deliv_time.date().string()); const TCodice_um um_nulla; const TQuantita qta(line.articolo(), docref->um(), qtaplan); r.put(format("@10g%s", (const char *)qta.val().string())); r.put(format("@30g%s", (const char *)qta.um())); r.put(format("@50g%s", (const char *)qtaplan.string())); r.put(format("@70g%s", (const char *)qta.um())); } return 0; } void TMatResPlanning::save_orders(TAssoc_array& docs) { TMatResMask& m = *_mask; FOR_EACH_ASSOC_OBJECT(docs, hash, str, obj) { TDocumento& doc = (TDocumento&)*obj; int err; if (doc.get_long(DOC_NDOC)) { // riscrittura; elimina righe con qta zero // if (!m.get_bool(F_ALL_ORDERSCHANGES)) int nrows = doc.physical_rows(); for (int numriga = nrows; numriga >0 ; numriga--) { if (doc[numriga].get_real(RDOC_QTA).is_zero()) doc.destroy_row(numriga, TRUE); } nrows = doc.physical_rows(); if (nrows > 0) err = doc.rewrite(); else { TDocumento d; if (d.read(doc, _isequal, _testandlock) == NOERR) d.remove(); } } else // generazione err = doc.write(); if (err != NOERR) doc.read(); // unlock } docs.destroy(); } bool TMatResPlanning::ask_save() { TMatResMask& m = *_mask; TSheet_field& sf = m.sfield(F_ORDINI); int tot = 0; FOR_EACH_SHEET_ROW(sf, r, row) { TToken_string& riga = *row; if (*riga.get(0) == 'X') tot++; } bool yes = TRUE; if (tot > 0) yes = yesno_box(FR("Si desidera elaborare %d righe?"), tot); return yes; } const TRectype* TMatResPlanning::irefs2rdoc(const TMRP_internalrefs& irefs) const { const TRectype* rdoc = NULL; for (int i = irefs.items()-1; i >= 0 && rdoc == NULL; i--) { const TMRP_internalref& iref = irefs.get_ref(i); const TMRP_line& line = *iref.line(); const int bucket = iref.bucket(); const TMRP_record& rec = line.record(bucket); for (int i = 0; i < 3 && rdoc == NULL; i++) { TMRP_docrefs* refs = NULL; switch (i) { case 0: refs = rec.requirements_refs(); break; case 1: refs = rec.plans_refs(); break; case 2: refs = rec.scheduls_refs(); break; default: break; } if (refs != NULL && refs->items() > 0) { for (int j = refs->last(); j >= 0; j--) { const TMRP_docref& docref = *refs->get_ref_ptr(j); if (docref.numrig() > 0) { rdoc = &docref.get_rdoc(); break; } } } } // Qui comincia la magia, perche' differente dalla risalita standard if (rdoc == NULL) { const TMRP_internalrefs* inter = rec.internal_refs(); if (inter != NULL && inter->items() > 0) rdoc = irefs2rdoc(*inter); } } return rdoc; } const TRectype* TMatResPlanning::trova_da_rdoc(const TMRP_line& line, const TDate& datacon) const { const TRectype* dardoc = NULL; // Cerco la riga di risalita const int last_bucket = line.last_bucket(); for (int bucket = last_bucket; bucket >= 0; bucket--) { const TMRP_record& buck = line.record(bucket); if (datacon >= buck.time().date()) { TMRP_internalrefs *irefs = buck.internal_refs(); if (irefs != NULL && irefs->items() > 0) { dardoc = irefs2rdoc(*irefs); } if (dardoc == NULL) { TMRP_docrefs* gr_refs = buck.requirements_refs(); if (gr_refs != NULL && gr_refs->items() > 0) // Esiste almeno una riga di risalita { const TMRP_docref& docref = *gr_refs->get_ref_ptr(0); dardoc = &docref.get_rdoc(); break; } } else break; } } return dardoc; } /////////// finished: 90% /////////// tested : 10% // genera gli ordini di produzione o a fornitore bool TMatResPlanning::emit_orders() { TMatResMask& m = *_mask; TSheet_field& sf = m.sfield(F_ORDINI); const bool divide_by_date = m.get_bool(F_DIVIDEBYDATE); const bool divide_by_art = m.get_bool(F_DIVIDEBYART); TTipo_documento tipo_doc_forn(m.get(F_TIPO_FORN )); TTipo_documento tipo_doc_prod(m.get(F_TIPO_PROD )); TDate today(TODAY); int docf = 0, docp = 0; TAssoc_array docs; TToken_string key; int ignore_docdate_too_soon = 0; int ignore_duedate_lt_docdate = 0; if (!ask_save()) return FALSE; TProgind pi(sf.items(), TR("Generazione ordini"), FALSE, TRUE); FOR_EACH_SHEET_ROW(sf, r, row) { pi.addstatus(1); TToken_string& riga = *row; if (riga[0] == 'X') { bool ok = true; const bool newdoc = riga.get_long(F_DOCNUM - FIRST_FIELD) == 0L; const TDate datadoc = riga.get(sf.cid2index(F_DATADOC)); const TDate datacon = riga.get(sf.cid2index(F_DATACONS)); const char type = riga.get_char(sf.cid2index(F_ORD_TYPE)); const bool prod = type == 'P'; const long forn = riga.get_long(sf.cid2index(F_FORNITORE)); const long numdoc = riga.get_long(sf.cid2index(F_DOCNUM)); real qta(riga.get(sf.cid2index(F_QUANTITA))); const TString4 realcodnum = riga.get(sf.cid2index(F_DOCCODNUM)); riga.add(" ",sf.cid2index(F_OK)); if (qta.is_zero()) continue; if (datadoc < today && newdoc) if (ignore_docdate_too_soon != K_ENTER && ignore_docdate_too_soon != K_ESC) { TYesnoallnone_box b(format(FR("Riga %d: data di emissione del documento (%s) inferiore a quella odierna. Confermare?"),r+1,(const char *)datadoc.string()), K_NO); ignore_docdate_too_soon = b.run(); } if (ignore_docdate_too_soon == K_NO || ignore_docdate_too_soon == K_ESC) continue; if (datacon < datadoc && newdoc) if (ignore_duedate_lt_docdate != K_ENTER && ignore_duedate_lt_docdate != K_ESC) { TYesnoallnone_box b(format(FR("Riga %d: data di consegna (%s) inferiore a quella di emissione del documento (%s). Confermare?"),r+1,(const char *)datacon.string(), (const char *)datadoc.string()), K_NO); ignore_duedate_lt_docdate = b.run(); } if (ignore_duedate_lt_docdate == K_NO || ignore_duedate_lt_docdate == K_ESC) continue; if (forn == 0L && newdoc) { if ((prod && !tipo_doc_prod.clifo_optional()) || (!prod && !tipo_doc_forn.clifo_optional())) { error_box(FR("Codice fornitore mancante alla riga %d"), r+1); continue; } } key.cut(0); if (newdoc) { key.add(type); key.add(forn); key.add(datadoc.string()); key.add(divide_by_date ? datacon.string() : " "); key.add(divide_by_art ? riga.get(sf.cid2index(F_ARTICOLO)) : " "); } else { key.format("%c%ld",prod ? 'P':'F',numdoc); } TDocumento* doc = (TDocumento*)docs.objptr(key); if (doc == NULL) { if (docs.items() >= 200) save_orders(docs); TString4 codnum = m.get(prod ? F_NUM_PROD : F_NUM_FORN ); const TString& tipdoc = m.get(prod ? F_TIPO_PROD: F_TIPO_FORN ); if (numdoc) { if (codnum != realcodnum) codnum = realcodnum; } doc = new TDocumento('D', datadoc.year(), codnum, 0); doc->set_tipo(tipdoc); TRectype& testata = doc->head(); if (numdoc) { doc->put(DOC_NDOC, numdoc); ok = doc->read()==NOERR; } else { testata.put(DOC_DATADOC, datadoc); testata.put(DOC_DATACONS, divide_by_date ? datacon : datadoc); } if (ok) { if (prod) { testata.put(DOC_TIPOCF, doc->tipo().tipocf()); // Puo' essere C o F testata.put(DOC_CODCF, forn); docp++; } else { testata.put(DOC_TIPOCF, "F"); testata.put(DOC_CODCF, forn); docf++; } testata.put(DOC_CAUSMAG, doc->tipo().caus_mov()); docs.add(key, doc); } } if (ok) { const int numriga = riga.get_int(sf.cid2index(F_DOCNRIGA)); TRiga_documento& rdoc = numdoc ? (*doc)[numriga] : doc->new_row(m.get(prod ? F_RIGA_PROD : F_RIGA_FORN)); if (numdoc) qta += rdoc.get_real(RDOC_QTA); rdoc.put(RDOC_CODART, riga.get(sf.cid2index(F_ARTICOLO))); TString80 str; for (int l= livelli_giacenza().last_level(); l>0; l--) livelli_giacenza().pack_grpcode(str, riga.get(sf.cid2index(F_LIV1+l-1)), l); rdoc.put(RDOC_LIVELLO,str); add_magcode(str,riga.get(sf.cid2index(F_MAGAZZINO))); add_depcode(str,riga.get(sf.cid2index(F_DEPOSITO))); rdoc.put(RDOC_CODMAG, str); rdoc.put(RDOC_IMPIANTO, riga.get(sf.cid2index(F_CODIMP))); rdoc.put(RDOC_LINEA, riga.get(sf.cid2index(F_CODLIN))); rdoc.put(RDOC_QTA, qta); rdoc.put(RDOC_UMQTA, riga.get(sf.cid2index(F_UM))); rdoc.put(RDOC_PREZZO, riga.get(sf.cid2index(F_PREZZO))); rdoc.put(RDOC_DESCR, riga.get(sf.cid2index(F_DESCART))); if (!divide_by_date) rdoc.put(RDOC_DATACONS,datacon.string()); // Cerca il codice di assoggettamento fiscale sul fornitore TString16 cod; if (forn > 0) { cod.format("F|%ld", forn); cod = cache().get(LF_CFVEN, cod, CFV_ASSFIS); } // Se non lo trova lo cerca sull'articolo if (cod.empty()) cod = cache().get(LF_ANAMAG, riga.get(sf.cid2index(F_ARTICOLO)), ANAMAG_CODIVA); rdoc.put(RDOC_CODIVA, cod); riga.add("X",sf.cid2index(F_OK)); // Cerca di impostare la riga di provenienza dell'ordine if (rdoc.get(RDOC_DAPROVV).blank()) // Se e' una riga nuova ... { TMRP_line* line = find_risalita_line(riga); // ... cerco la riga di risalita if (line != NULL) { const int depth = line->explosion_depth()+1; // Profondita' esplosione (+1 per non avere zeri) rdoc.put(RDOC_QTAGG5, depth); // Per ora memorizziamo in QTAGG5, scelto a caso const TRectype* dardoc = trova_da_rdoc(*line, datacon); if (dardoc != NULL) { int rifdepth = m.get_int(F_RIFERIMENTO_MRP); if (rifdepth == 0 && dardoc->get(RDOC_DACODNUM).full()) { // rifdepth = 1; const TString_array& n = m.sfield(F_NUM_ORC).rows_array(); while (dardoc != NULL) { const TString& codnum = dardoc->get(RDOC_CODNUM); if (test_codnum(codnum, n)) break; dardoc = ((const TRiga_documento*)dardoc)->find_original_rdoc(); } } if (dardoc != NULL) rdoc.set_original_rdoc_key(*dardoc, rifdepth); // Imposto DAPROVV, DAANNO, DACODNUM, DANDOC, DAIDRIGA else { TString80 msg; msg.format(FR("Riferimento non trovato: riga %d"), r+1); xvtil_statbar_set(msg); beep(); } } else { TString80 msg; msg.format(FR("Riferimento non trovato: riga %d"), r+1); xvtil_statbar_set(msg); beep(); } } else { TString80 msg; msg.format(FR("Linea risalita non trovata: riga %d"), r+1); xvtil_statbar_set(msg); beep(); } } } } } save_orders(docs); if (sf.items()) { FOR_EACH_SHEET_ROW_BACK(sf, r, row) { if ((*row->get(sf.cid2index(F_SELECTED)) == 'X' && *row->get(sf.cid2index(F_OK))=='X') || real(row->get(sf.cid2index(F_QUANTITA))).is_zero()) { if (m.get_bool(F_ALL_ORDERSCHANGES)) row->add("", sf.cid2index(F_QUANTITA)); else sf.destroy(r, FALSE); } } sf.force_update(); } m.enable(DLG_SAVEREC, sf.items() > 0); return TRUE; } void TMatResPlanning::compute() { if (preprocess_cycle()) // req iniziale dai docs if (net_requirement_cycle()) build_orders(); } void TMatResPlanning::risalita(const TMask & m) { TSheet_field & sf= m.sfield(F_ORDINI); TToken_string& row=sf.row(sf.selected()); TCodice_articolo art; row.get(sf.cid2index(F_ARTICOLO), art); if (art.blank()) return; TMRP_line* line = find_risalita_line(row); if (line != NULL) { TDate todate(row.get(sf.cid2index(F_DATACONS))); TDate fromdate = todate; round_date(fromdate); round_date(todate,TRUE); TRisalita_mask *rismask; rismask = new TRisalita_mask(line, fromdate, todate, fromdate <= _mask->get_date(F_DADATA),_mask->get_int(F_XTRA_LDTIME)); rismask->run(); delete rismask; } else message_box(TR("Impossibile rintracciare la riga d'ordine indicata tra quelle generate in MRP")); } bool TMatResPlanning::print_exceptions(TMask &m) { TExceptions_array e; bool anticipi = m.get_bool(S_HURRYUP_EXCEPT); bool posticipi = m.get_bool(S_DELAY_EXCEPT); bool extra = m.get_bool(S_EXTRA_EXCEPT); if (_articles.items()>0) { // PER OGNI ARTICOLO ... const long max_mrp_rows=_articles.items(); TProgind pi=((max_mrp_rows+1) ,TR("Ricerca eccezioni..."), TRUE, TRUE); for (long mrp_row=0; mrp_row < max_mrp_rows; mrp_row++) { pi.addstatus(1); if (pi.iscancelled()) return FALSE; TMRP_line &mrpline=_articles[mrp_row]; mrpline.reset_excepts(); mrpline.find_ad_excepts(anticipi, posticipi, e); if (extra) mrpline.find_extra_excepts(_mask->get_bool(F_DIVIDEBYART)||_mask->get_bool(F_DIVIDEBYDATE), e); } // ... for each article } if (e.items()<=0) message_box(TR("Nessuna eccezione rilevata")); else print_exceptions(e); return e.items()>0; } void TMatResPlanning::print_except_header(TPrinter& pr) { TString format; TPrintrow row; print_header(pr); row.put(FR("@48G@BSTAMPA TABULATO ECCEZIONI DA M.R.P.")); pr.setheaderline(1,row); row.reset(); row.put((const char *)TString(131,'-')); pr.setheaderline(4,row); } void TMatResPlanning::print_exceptions(TExceptions_array &excepts) { if (excepts.items()) { TPrinter& pr = printer(); pr.open(); pr.setheaderhandler(print_except_header); pr.headerlen(6); pr.setfooterhandler(print_footer); pr.footerlen(2); TString_array keys; TToken_string key, lastkey; TString tmp; excepts.get_keys(keys); keys.sort(); int header=0; for (int k=0; k< keys.items(); k++) { key = keys.row(k); key.get(0,tmp); if (tmp != lastkey.get(0)) header = 0; else if (key.get(1,tmp)&& tmp != lastkey.get(1)) header = 0; else if (key.get(2,tmp) && tmp != lastkey.get(2)) header = 1; else header = 2; const TException & e = (const TException &)excepts[key]; const TMRP_line &line = e.mrpline(); line.print_exception(e.from(), e.to(), e.qta(), header); lastkey = key; } pr.close(); } } bool TMatResPlanning::menu(MENU_TAG mt) { bool ok = TRUE; if (mt == MENU_ITEM_ID(1)) _mask->sel().run(); else ok = TSkeleton_application::menu(mt); return ok; } void TMatResPlanning::main_loop() { open_files(LF_TABCOM, LF_TAB, LF_DOC, LF_RIGHEDOC, LF_CLIFO, LF_CFVEN, LF_OCCAS, LF_INDSP,LF_CONDV, LF_ANAMAG, LF_DIST, LF_RDIST, LF_MAG, LF_STOMAG, LF_DESLIN, LF_CODCORR, 0); TSheet_field::set_line_number_width(4); // Allarga numeri di riga (default = 3) _mask = new TMatResMask; // Graffe necessarie per chiudere TConfig prassid { 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 (!prassid.get_bool("GES", NULL, A_CONTRATTI) || !prassid.get_bool("GESCONCC")) _mask->disable(F_TIPOCF_CONDV); } if (argc() >= 2) { TString param = argv(2); param.upper(); if (param.find("AUTO") > 0) // Lancia elaborazione batch (AUTOC o AUTOR) _mask->send_key(K_CTRL+'L', 0); // Preme tasto ricalcola } while (_mask->run()!=K_QUIT); delete _mask; _mask = NULL; } void print_header(TPrinter& pr) { TPrintrow row; const TRectype& firm = cache().get(LF_NDITTE, main_app().get_firm()); TString16 key; key.format("%s|%s", (const char*)firm.get(NDT_TIPOA), (const char*)firm.get(NDT_CODANAGR)); const TString& anag= cache().get(LF_ANAG, key, ANA_RAGSOC); TString format; format << "@2g" << anag << "@80g@>@110gPagina @#"; row.put(format); pr.setheaderline(0,row); } void print_footer(TPrinter& pr) { TPrintrow row; pr.setfooterline(1,row); } int mr2100(int argc, char* argv[]) { TMatResPlanning a; a.run(argc, argv, TR("Material Requirements Planning")); return 0; }