Files correlati : Ricompilazione Demo : [ ] Commento :errore riporto git-svn-id: svn://10.65.10.50/trunk@14174 c028cbd2-c16b-5b4b-a496-9718f37d4682
3624 lines
111 KiB
C++
Executable File
3624 lines
111 KiB
C++
Executable File
#include <applicat.h>
|
||
#include <colmask.h>
|
||
#include <printer.h>
|
||
#include <progind.h>
|
||
#include <tabutil.h>
|
||
#include <urldefid.h>
|
||
#include <utility.h>
|
||
|
||
#include "..\mg\anamag.h"
|
||
#include "..\ve\veconf.h"
|
||
|
||
#include <anagr.h>
|
||
#include <nditte.h>
|
||
|
||
#include "mr2100.h"
|
||
#include "mr2100a.h"
|
||
#include "mr2100c.h"
|
||
|
||
///////////////////////////////////////////////////////////
|
||
// 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;
|
||
|
||
const TString& TMRP_line::livgiac(int l) const
|
||
{
|
||
const TCodgiac_livelli& lg = livelli_giacenza();
|
||
return _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
|
||
{
|
||
for (int 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;
|
||
}
|
||
|
||
|
||
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;
|
||
|
||
_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();
|
||
for (int 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)
|
||
{
|
||
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)
|
||
{
|
||
for (int 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 <20> 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;
|
||
int _nodist_pos;
|
||
|
||
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 explode_articles();
|
||
|
||
bool test_codnum(const TCodice_numerazione& num, 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;
|
||
}
|
||
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;
|
||
}
|
||
}
|
||
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);
|
||
cmp = +1;
|
||
for (int 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<69> 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 = _sel_color.get_back_color(_nodist_pos);
|
||
COLOR fore = _sel_color.get_fore_color(_nodist_pos);
|
||
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);
|
||
}
|
||
|
||
|
||
|
||
TMatResMask::TMatResMask() : TCalendar_mask("mr2100a"), _sel_color(sfield(F_ORDINI))
|
||
{
|
||
_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");
|
||
}
|
||
_nodist_pos =_sel_color.add_color_def("NODIST", TR("Art.pianificati senza distinta"), COLOR_YELLOW, COLOR_BLACK);
|
||
}
|
||
|
||
///////////////////////////////////////////////////////////
|
||
// 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 TCodice_numerazione& num, const TString_array& a) const
|
||
{
|
||
const TString& codnum = num.codice();
|
||
TString4 tmp;
|
||
for (int it = 0 ;it < a.items(); it++ )
|
||
{
|
||
a.row(it).get(0, tmp);
|
||
if (tmp == codnum)
|
||
return true;
|
||
}
|
||
return false;
|
||
bool yes = a.find(num.codice()) >= 0; // E' questa roba a cosa serve???
|
||
return yes;
|
||
}
|
||
|
||
bool TMatResPlanning::has_confirmed_status(const TRectype& doc, const TToken_string& riga) const
|
||
{
|
||
const char statodoc = doc.get_char(DOC_STATO);
|
||
const char state_def = ((TToken_string&)riga).get_char(F_STATODEF - FIRST_FIELD);
|
||
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%
|
||
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.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<70> di uno
|
||
// in un intervallo, altrimenti i ragionamenti di scorte minime e lotti
|
||
// funzionano in modo sbagliato, perch<63> approssimano pi<70> 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);
|
||
TCurrency c(TRUE);
|
||
c.set_num(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;
|
||
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("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(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;
|
||
}
|