campo-sirio/mr/mr2200.cpp
alex a0a36d6b33 Patch level : XX.282
Files correlati     :
Ricompilazione Demo : [ ]
Commento            : Riportata la versione 01.05 patch 282


git-svn-id: svn://10.65.10.50/trunk@8019 c028cbd2-c16b-5b4b-a496-9718f37d4682
1999-04-06 15:34:39 +00:00

3802 lines
118 KiB
C++
Executable File
Raw Blame History

#include <applicat.h>
#include <colors.h>
#include <defmask.h>
#include <progind.h>
#include <tabutil.h>
#include <xvtility.h>
#include <utility.h>
#include "mrplib.h"
#include "../mg/mglib.h"
#include "../ve/velib.h"
#include "../ve/veconf.h"
#include "mr2100.h"
#include "mr2200a.h"
#include "mr2200b.h"
const real MAXCAPACITY("999999999.99");
///////////////////////////////////////////////////////////
// triga ordine
///////////////////////////////////////////////////////////
#define SORT_BY_CAL -1 // cliente / articolo / impianto-linea
#define SORT_BY_CLA -2 //
#define SORT_BY_ALC -3 //
#define SORT_BY_ACL -4 //
#define SORT_BY_LAC -5 //
#define SORT_BY_LCA -6 //
enum TMSP_mode {_actual_schedule, _stock_break};
enum TMSP_logic {_first_fit_logic, _JIT_logic};
class TMSP_constraint;
class TMSP_constraints;
class TMSP_mask;
class TRiga_articolo : public TToken_string
{
public:
static int order_compare(TSheet_field & s, int i1, int i2, int level);
static int order_compare( const TToken_string& r1 , const TToken_string& r2 , int level);
static int compare_field(TString &str0, TString &str1,short field_no) ;
static int order_compareCAL(TSheet_field & s, int i1, int i2);
static int order_compareCLA(TSheet_field & s, int i1, int i2);
static int order_compareALC(TSheet_field & s, int i1, int i2);
static int order_compareACL(TSheet_field & s, int i1, int i2);
static int order_compareLAC(TSheet_field & s, int i1, int i2);
static int order_compareLCA(TSheet_field & s, int i1, int i2);
static bool find_block(const TSheet_field& sf, const int riga, int &first_row, int &last_row );
int compare(const TToken_string& r, int level) const;
TRiga_articolo& operator=(TToken_string& r);
TRiga_articolo& operator+=(TRiga_articolo& r);
TRiga_articolo() : TToken_string(128) { }
TRiga_articolo(const TMSP_constraint & line);
virtual ~TRiga_articolo() { }
};
///////////////////////////////////////////////////////////
// TMSP_record
///////////////////////////////////////////////////////////
class TMSP_record : public TObject
{
public:
long _numdoc;
int _numrig;
real _qta;
real _price;
TMSP_record() : _numdoc(0L), _numrig(0) { }
};
///////////////////////////////////////////////////////////
// TMSP_record_array;
///////////////////////////////////////////////////////////
class TMSP_record_array : public TObject
{
TArray _buckets;
public:
int items() const { return _buckets.items(); }
int last() const { return _buckets.last(); }
int pred(int i) const { return _buckets.pred(i); }
TMSP_record& operator[](int b);
};
///////////////////////////////////////////////////////////
// TCRP_line ; carichi di linea
///////////////////////////////////////////////////////////
class TCapacita_prod : public TSortable
{
real _capacity; // Capacita' macchina
real _human_capacity; // Capacita' macchina
real _load; // Carico macchina
real _human_load; // Carico uomo
// static TDecoder* _umart1; // Decoder per trovare unita' base articolo
// static TDecoder* _umart2; // Decoder per trovare conversione
// static TDecoder* _umdist; // Decoder per trovare unita' base distinta
protected:
virtual int compare(const TSortable& s) const;
virtual TObject* dup() const { return new TCapacita_prod(*this); }
void copy(const TCapacita_prod& q);
real get_factor(const TCodice_um& um) const;
void convert(real& val, const TCodice_um& from_um, const TCodice_um& to_um) const;
public:
const TCapacita_prod& operator =(const TCapacita_prod& q)
{ copy(q); return q; }
void set(const real& cap, const real& load);
void set_capacity(const real& cap){_capacity=cap;}
void set_human_capacity(const real& cap){_human_capacity=cap;}
void set_load(const real& load) {_load=load;}
void set_human_load(const real& load) {_human_load=load;}
void add_capacity(const real& cap){_capacity+=cap;}
void add_human_capacity(const real& cap){_human_capacity+=cap;}
void add_load(const real& load) {_load+=load;}
void add_human_load(const real& load) {_human_load+=load;}
real & capacity() {return _capacity;}
real & load() {return _load;}
real & human_capacity() {return _human_capacity;}
real & human_load() {return _human_load;}
TCapacita_prod ();
TCapacita_prod (const real& cap, const real& load);
TCapacita_prod (const TCapacita_prod & q) { copy(q); }
virtual ~TCapacita_prod () {}
};
class TCRP_line : public TSortable
{
TString8 _lineap, _imp;
TString _desc;
bool _on_sheet;
TArray _bucket;
protected:
virtual int compare(const TSortable& s) const;
TCapacita_prod& bucket(int n) ;
TCapacita_prod& operator[](int n)
{return bucket(n);}
public:
const TString& codimp() const { return _imp; }
const TString& codlin() const { return _lineap; }
const TString& desc() const { return _desc; }
void set_desc(const char* str) { _desc = str; }
int last() const { return _bucket.last(); }
int pred(int i) const { return _bucket.pred(i); }
real& capacity(int b) { return bucket(b).capacity(); }
real& load(int b) { return bucket(b).load(); }
real& human_capacity(int b) { return bucket(b).human_capacity(); }
real& human_load(int b) { return bucket(b).human_load(); }
void set_capacity(int b,const real & v ) { bucket(b).set_capacity(v); }
void set_human_capacity(int b,const real & v ) { bucket(b).set_human_capacity(v); }
// void set_load(int b, const real & v) { bucket(b).set_load(v); }
// void set_human_capacity(int b,const real & v ) { bucket(b).set_human_capacity(v); }
// void set_human_load(int b, const real & v) { bucket(b).set_human_load(v); }
// void add_capacity(int b,const real & v ) { bucket(b).add_capacity(v); }
void add_load(int b, const real & v) { bucket(b).add_load(v); }
// void add_human_capacity(int b,const real & v ) { bucket(b).add_human_capacity(v); }
void add_human_load(int b, const real & v) { bucket(b).add_human_load(v); }
void fill_capacity_row(TToken_string& row, bool percent=FALSE);
void fill_load_row(TToken_string& row, bool percent=FALSE);
void fill_hcapacity_row(TToken_string& row, bool percent=FALSE);
void fill_hload_row(TToken_string& row, bool percent=FALSE);
bool is_on_sheet() const { return _on_sheet; }
void set_on_sheet(bool on = TRUE) { _on_sheet = on; }
//TCRP_line(const TString& codlin);
TCRP_line(const TString& codimp,const TString& codlin);
virtual ~TCRP_line() { }
};
class TCRP_lines : public TMRP_array
{
protected:
virtual TSortable* new_obj(const TToken_string& key) const;
public:
TCRP_line* find(const TLinea_prod& linea_prod,
const char * codart="", long codcli=0L, bool create=FALSE);
TCRP_line* find(const char * codimp="", const char * codlin="",
const char * codart="", long codcli=0L, bool create=FALSE);
TCRP_line& operator[](long n) const
{ return (TCRP_line&)find_obj(n); }
};
class TMaster_code : public TObject
{
TString _code;
TString _liv;
TString _um;
TString _codimp;
TString _codlin;
TString _codmag;
real _expr;
real _leadtime;
public:
const char *articolo() const {return _code;}
const char *livello() const {return _liv;}
const char *um() const {return _um;}
const real &expr() const {return _expr;}
const real &leadtime() const {return _leadtime;}
const char *codimp() const {return _codimp;}
const char *codlin() const {return _codlin;}
const char *codmag() const {return _codmag;}
TMaster_code(const char *code, const char *liv, const char *ummaster, const real &expr, const real &leadtime, const char *codimp, const char *codlin, const char *codmag);
TMaster_code(const char *code, const char *liv,const char *ummaster, const real &expr, int leadtime, const char *codimp, const char *codlin, const char *codmag);
virtual ~TMaster_code() {}
};
class TMSP_constraints : public TMRP_array
{
protected:
virtual TSortable* new_obj(const TToken_string& key) const;
public:
TMSP_constraint* find(long cliente,const TString& codart,const TString& giac,
const TString& imp, const TString& lin, const TString& mag,
bool create=FALSE) ;
TMSP_constraint& operator[](long n) const
{ return (TMSP_constraint&)find_obj(n); }
};
class TMSP_constraint : public TSortable
{
long _cliente;
TCodice_articolo _codart;
TString16 _giac;
TString8 _imp, _lin;
TString8 _mag;
TString _desc;
bool _on_sheet;
TArray _mastercodes; // codici di livello 2 per articoli NON master
TMSP_constraints _upperlines; // vincoli dei codici di livello 1 per articoli master
TMSP_record_array _bucket_qta;
protected:
virtual int compare(const TSortable& s) const;
public:
long cliente() const { return _cliente; }
const TCodice_articolo& codice() const { return _codart; }
const TString& livgiac() const { return _giac; }
const TString& codimp() const { return _imp; }
const TString& codlin() const { return _lin; }
const TString& codmag() const { return _mag; }
const TString& desc() const { return _desc; }
void set_desc(const char* str) { _desc = str; }
bool riga(int b, long& ndoc, int& nriga);
void set_riga(int b, long ndoc, int nriga);
// master sched. a due livelli:
void add_mastercode(TMaster_code * mc);
TMaster_code * get_mastercode(int i=0);
bool has_mastercodes() const ;
void add_upperline(TMSP_constraint& constr);
TMSP_constraint* get_upperline(TMSP_constraint& constr);
bool has_upperlines() const ;
int last() const { return _bucket_qta.last(); }
int pred(int i) const { return _bucket_qta.pred(i); }
virtual real& qta(int b) { return _bucket_qta[b]._qta; }
virtual real& price(int b) { return _bucket_qta[b]._price; }
virtual void fill_sheet_row(TToken_string& row, const TMSP_mask & m, bool codes_only=FALSE);
bool is_on_sheet() const { return _on_sheet; }
void set_on_sheet(bool on = TRUE) { _on_sheet = on; }
TMSP_constraint & operator=(const TMSP_constraint & line);
TMSP_constraint(long cliente,
const TCodice_articolo& codart,
const TString& giac,
const TString& imp, const TString& lin,
const TString& mag);
TMSP_constraint(TMSP_constraint & cons);
virtual ~TMSP_constraint() { }
};
// linee contenenti pianificazioni
class TMSP_line : public TMSP_constraint
{
public:
virtual void fill_sheet_row(TToken_string& row, const TMSP_mask & m, bool codes_only=FALSE);
TMSP_line(long cliente, const TCodice_articolo& codart,
const TString& giac, const TString& mag,
const TString& imp, const TString& lin);
TMSP_line(TMSP_line & line);
TMSP_line(TMSP_constraint & cons);
virtual ~TMSP_line() { }
};
class TMSP_lines : public TMRP_array
{
protected:
virtual TSortable* new_obj(const TToken_string& key) const;
public:
TMSP_line* find(long cliente, const TString& art, const TString& gia,
const TString& imp, const TString& lin, const TString& mag,
bool create=FALSE);
TMSP_line* find(const TToken_string& row, TCodice_livelli & levels, bool create=FALSE);
TMSP_line& operator[](long i) const
{ return (TMSP_line&)find_obj(i); }
};
class TMSP_mask : public TCalendar_mask
{
TCodgiac_livelli _livelli;
// quantit<69> provenienti dai documenti "ordine":
TMSP_constraints _constraints;
// quantit<69> provenienti dai documenti "planning" (commesse):
TMSP_lines _articles;
// quantit<69> per il processo di nettificazione/sizing in caso di generazione dell'MSP
TMRP_lines _mrp_articles;
// proposte del sistema
TMRP_lines _proposed_articles, _proposed_1stlevel;
// capacit<69> linea per linea
TCRP_lines _capacities;
// albero per le ricerche sulle dist
TDistinta_tree _dist_tree;
protected:
bool on_field_event(TOperable_field& o, TField_event e, long jolly);
bool load_MRP_lines(TMSP_mode mode, int level=0);
bool nettify_MRP_lines(bool already_net, bool lotsizing=FALSE);
void add_MRP_bucket(TMRP_line& new_article, int nbucket, const real &curr_arts);
// proposta automatica del sistema
bool general_review(bool check_machine, bool check_human, bool useextralines, bool useextrahours,bool lotsizing, bool no_outcapacity, int anticipomin,int anticipomax, TMSP_mode mode, TMSP_logic logic );
bool insert_propose(bool verbose=FALSE) ;
bool remove_propose(bool verbose=FALSE) ;
void add_or_sub_propose(char sign);
void propose_1stJIT(TMSP_logic logic, bool check_m, bool check_h);
// void propose_firstfit(bool check_m, bool check_h);
// bool firstfit_review(bool check_machine, bool check_human, bool useextralines, bool useextrahours,bool lotsizing, bool no_outcapacity, int anticipomin,int anticipomax, TMSP_mode mode);
// void propose_JIT(bool check_m, bool check_h);
// bool JIT_review(bool check_machine, bool check_human, bool useextralines, bool useextrahours,bool lotsizing, bool no_outcapacity, int anticipomin,int anticipomax, TMSP_mode mode);
// controlli
bool sort_sheet();
void check_articles();
void check_capacities();
void pack_article_sheet();
// capacity review
bool capacity_review(bool useextralines, bool useextrahours);
TCRP_line *compute_capacity(TLinea_prod &lineaprod, bool useextralines, bool useextrahours);
TMSP_constraint* find_constraint(const TMSP_line& l,bool force_insert=FALSE);
int find_constr_row(const TMSP_constraint& c);
bool do_test_art_row(int r, int c, bool signal);
bool test_art_row(int r, bool signal=TRUE);
bool test_load_row(int r, bool signal=TRUE);
int init_bucket0(TArticolo_giacenza &art, int r);
void copy_sheet_row(TToken_string & newrow, const TToken_string & row);
void clear_sheets();
bool distinta_master(const char *code);
int find_distinta_master(const char * code, TString & master, TString & livmaster,TString & um,real & expr, TString & imp,TString & lin,TString & magdep, int fromindex=0);
public:
const TCodgiac_livelli& livelli_giac() const {return _livelli;}
void msprow2codes(TToken_string &row, long &clifor, TCodice_articolo &art ,
TString & liv, TString & mag, TString & imp, TString & lin, TString & um);
void crprow2codes(TToken_string &row, TString & imp, TString & lin, long &clifor, TCodice_articolo &art ,
TString & liv, TString & um);
TMRP_line* find_propose(long codcli, const char * codart,const char * liv,
const char * codimp,const char * codlin,const char * mag,
bool Force=FALSE);
TMSP_line* find_article(long cli, const char *art, const char *liv,
const char *imp, const char *lin, const char *mag,bool Force=FALSE)
{return _articles.find(cli, art, liv, imp, lin, mag, Force);}
int days_per_bucket() const;
int round_date(TDate& date, bool up = FALSE) const;
void round_field(TMask_field& fld, bool up) const;
int test_codnum(const TCodice_numerazione& num) const;
bool test_tipodoc_num( const TSheet_field &sheet_num , const TSheet_field &sheet_type) ;
bool test_status(const TRectype& doc, int tipo) const;
bool carica_documenti();
void fill_sheet();
void salva_documenti();
TMSP_mask();
virtual ~TMSP_mask() { }
};
class TMSPCheck_mask : public TAutomask
{
protected:
int _col, _row, _constr_row, _last_col, _last_row;
TMSP_mask * _main_mask;
TSheet_field * _sheet;
protected:
int max_rows() {return _sheet->items();}
void go_top();
bool on_field_event(TOperable_field& o, TField_event e, long jolly);
bool move_to(int dlg);
virtual void check_pos_range();
virtual int fill_mask(const bool show=TRUE);
virtual bool is_constraint(int row);
virtual bool is_article(int row);
virtual int find_constraint(int row);
public:
void gopos(int row, int col);
virtual void gopos_mainmask();
void fix_actual_pos();
short last_row(){ return _last_row;}
short last_col(){ return _last_col;}
TMSPCheck_mask(TMSP_mask * main_mask);
TMSPCheck_mask(TMSP_mask * main_mask,const char * m,TSheet_field * s );
};
class TCRPCheck_mask : public TMSPCheck_mask
{
protected:
virtual void check_pos_range();
virtual int fill_mask(const bool show=TRUE);
virtual bool is_constraint(int row);
virtual bool is_article(int row);
virtual int find_constraint(int row);
public:
TCRPCheck_mask(TMSP_mask * main_mask);
};
///////////////////////////////////////////////////////////
TMSP_record& TMSP_record_array::operator[](int b)
{
CHECKD(b >= 0, "Invalid TMSP_record_array ", b);
TMSP_record* rec = (TMSP_record*)_buckets.objptr(b);
if (rec == NULL)
{
rec = new TMSP_record;
_buckets.add(rec, b);
}
return *rec;
}
///////////////////////////////////////////////////////////
TCapacita_prod::TCapacita_prod () :
_capacity(), _load()
{ }
TCapacita_prod::TCapacita_prod (const real& cap, const real& load) :
_capacity(cap), _load(load)
{ }
void TCapacita_prod::set(const real& cap, const real& load)
{ _capacity=(cap);_load=(load);}
void TCapacita_prod::copy (const TCapacita_prod & q)
{
_capacity=q._capacity; // Valore attuale
_load=q._load; // Valore attuale
}
int TCapacita_prod::compare(const TSortable& s) const
{
TCapacita_prod& c=(TCapacita_prod&)s;
real r=_capacity-c._capacity;
return r.sign();
}
TCRP_line::TCRP_line(const TString& codimp,const TString& codlin)
: _lineap(codlin),_on_sheet(FALSE)
{
if (!codlin.blank())
{
TTable tablnp("LNP");
tablnp.put("CODTAB",_lineap);
tablnp.read();
_desc = tablnp.get("S0");
_imp = tablnp.get("S6");
}
else
{
_imp = codimp ;
if (!codimp.blank())
{
TTable tabimp("IMP");
tabimp.put("CODTAB",_imp);
tabimp.read();
_desc = tabimp.get("S0");
}
else
{
_desc = "Totale ditta";
}
}
}
int TCRP_line::compare(const TSortable& s) const
{
const TCRP_line& c = (const TCRP_line&)s;
int cmp = _imp.compare(c._imp);
if (cmp == 0)
{
cmp = _lineap.compare(c._lineap);
}
return cmp;
}
// carica una riga di sheet con i dati dell'oggetto vincolo
void TCRP_line::fill_capacity_row(TToken_string& row, bool percent)
{
row.add(codimp(),F_CODIMPCRP -FIRST_FIELD);
row.add(codlin(),F_CODLINCRP -FIRST_FIELD);
row.add(percent ? "%": "ore",F_LUM -FIRST_FIELD);
real r;
for (int bu = last(); bu > 0; bu = pred(bu))
{
r=capacity(bu);
if (!r.is_zero())
row.add(percent ? "100" : r.string(), bu + F_LBUCKET0 -FIRST_FIELD); // buckets
else
row.add("", bu + F_LBUCKET0 -FIRST_FIELD);
}
}
void TCRP_line::fill_hcapacity_row(TToken_string& row, bool percent)
{
row.add(codimp(),F_CODIMPCRP -FIRST_FIELD);
row.add(codlin(),F_CODLINCRP -FIRST_FIELD);
row.add(percent ? "%": "ore",F_LUM -FIRST_FIELD);
real r;
for (int bu = last(); bu > 0; bu = pred(bu))
{
r=human_capacity(bu);
if (!r.is_zero())
row.add(percent ? "100" : r.string(), bu + F_LBUCKET0 -FIRST_FIELD); // buckets
else
row.add("", bu + F_LBUCKET0 -FIRST_FIELD);
}
}
// carica una riga di sheet con i dati dell'oggetto vincolo
void TCRP_line::fill_load_row(TToken_string& row, bool percent)
{
row.add(codimp(),F_CODIMPCRP -FIRST_FIELD);
row.add(codlin(),F_CODLINCRP -FIRST_FIELD);
row.add(percent ? "%": "ore",F_LUM -FIRST_FIELD);
real r;
for (int bu = last(); bu > 0; bu = pred(bu))
{
r=percent ? (capacity(bu).is_zero() ? ZERO : (100L * load(bu) / capacity(bu))) : load(bu) ;
row.add(r.string(), bu + F_LBUCKET0 -FIRST_FIELD); // buckets
}
}
void TCRP_line::fill_hload_row(TToken_string& row, bool percent)
{
row.add(codimp(),F_CODIMPCRP -FIRST_FIELD);
row.add(codlin(),F_CODLINCRP -FIRST_FIELD);
row.add(percent ? "%": "ore",F_LUM -FIRST_FIELD);
real r;
for (int bu = last(); bu > 0; bu = pred(bu))
{
r=percent ? (human_capacity(bu).is_zero() ? ZERO :(100L * human_load(bu) / human_capacity(bu))) : human_load(bu) ;
row.add(r.string(), bu + F_LBUCKET0 -FIRST_FIELD); // buckets
}
}
TCapacita_prod& TCRP_line::bucket(int n)
{
TCapacita_prod *o;
o=(TCapacita_prod *)_bucket.objptr(n);
if (o==NULL)
{
o=new TCapacita_prod();
_bucket.add(o,n);
}
return *o;
}
///////////////////////////////////////////////////////////
// TCRP_lines ; carichi delle varie linee
///////////////////////////////////////////////////////////
TSortable* TCRP_lines::new_obj(const TToken_string& key) const
{
TString8 codimp, codlin;
key.get(0,codimp);
key.get(1,codlin);
return new TCRP_line(codimp, codlin);
}
TCRP_line* TCRP_lines::find(const TLinea_prod& linea_prod, const char * codart, long codcli, bool create)
{
/* _key=linea_prod.codimp();
_key.add(linea_prod.codice());
TSortable* s = create ? add_obj(_key) : find_obj(_key);
return (TCRP_line*)s;*/
return find(linea_prod.codimp(), linea_prod.codice(),codart, codcli, create);
}
TCRP_line* TCRP_lines::find(const char * codimp, const char * codlin, const char * codart, long codcli, bool create)
{
_key.add(codimp,0);
_key.add(codlin,1);
_key.add(codart,2); // articolo
_key.add(format("%ld",codcli),3); // cliente
TSortable* s = create ? add_obj(_key) : find_obj(_key);
return (TCRP_line*)s;
}
///////////////////////////////////////////////////////////
// TMaster_code
///////////////////////////////////////////////////////////
TMaster_code::TMaster_code(const char *code, const char *liv,const char *ummaster, const real &expr, const real &leadtime, const char *codimp, const char *codlin, const char *codmag)
: _code(code), _liv (liv), _um(ummaster), _expr(expr), _leadtime(leadtime),
_codimp(codimp), _codlin(codlin), _codmag(codmag)
{
}
TMaster_code::TMaster_code(const char *code, const char *liv,const char *ummaster, const real &expr, int leadtime, const char *codimp, const char *codlin, const char *codmag)
: _code(code), _liv (liv), _um(ummaster), _expr(expr), _leadtime(format("%d",leadtime)),
_codimp(codimp), _codlin(codlin), _codmag(codmag)
{
}
///////////////////////////////////////////////////////////
// TMSP_constraint
///////////////////////////////////////////////////////////
int TMSP_constraint::compare(const TSortable& s) const
{
const TMSP_constraint& c = (const TMSP_constraint&)s;
const long diff = _cliente - c._cliente;
int cmp = diff == 0L ? 0 : (diff > 0 ? +1 : -1);
if (cmp == 0)
{
cmp = _codart.compare(c._codart);
if (cmp == 0)
{
cmp = _giac.compare(c._giac);
if (cmp == 0)
{
cmp = _imp.compare(c._imp);
if (cmp == 0)
cmp = _mag.compare(c._mag);
}
}
}
return cmp;
}
// carica una riga di sheet con i dati dell'oggetto vincolo
void TMSP_constraint::fill_sheet_row(TToken_string& row, const TMSP_mask & m, bool codes_only)
{
const TCodgiac_livelli& livelli=m.livelli_giac();
TString tipocf(m.get(F_TIPOCF));
row.add(m.get_bool(F_NOCLI_IN) ? "" : tipocf,F_TIPOCF_SHEET-FIRST_FIELD);
row.add(format("%ld", cliente()),F_CLIENTE-FIRST_FIELD);
row.add(codice(),F_ARTICOLO-FIRST_FIELD);
row.add(" ",F_PRIORITA-FIRST_FIELD);
const TString& liv = livgiac();
for (int l = 1; l <= 4; l++)
{
if (livelli.enabled(l))
row.add(livelli.unpack_grpcode(liv,l),F_LIV1+l-1-FIRST_FIELD);
else
row.add(" ",F_LIV1+l-1-FIRST_FIELD);
}
row.add(desc(),F_DESCART-FIRST_FIELD);
row.add(codimp(),F_CODIMP-FIRST_FIELD);
row.add(codlin(),F_CODLIN-FIRST_FIELD);
TString8 str = _mag.left(3);
row.add(str, F_MAGAZZINO-FIRST_FIELD);
str = _mag.mid(3);
row.add(str,F_DEPOSITO-FIRST_FIELD);
const TCodice_um um;
const TQuantita qta_art(codice(), um, ZERO);
row.add(qta_art.um(),F_UM-FIRST_FIELD);
if (codes_only)
return;
real needs=ZERO;
const int last_buck= last();
for (int bu = 0; bu <= last_buck; bu ++)
{
needs=qta(bu);
row.add(needs.string(), bu*2+F_BUCKET0-FIRST_FIELD);
needs=price(bu);
row.add(needs.string(), bu*2+F_BUCKET0+1-FIRST_FIELD);
}
row.add(has_mastercodes() ? "M" : " ",F_MASTERCODE-FIRST_FIELD);
}
bool TMSP_constraint::riga(int buck, long& ndoc, int& nrig)
{
TMSP_record& b = _bucket_qta[buck];
ndoc = b._numdoc;
nrig = b._numrig;
return ndoc > 0L && nrig > 0;
}
void TMSP_constraint::set_riga(int buck, long ndoc, int nrig)
{
TMSP_record& b = _bucket_qta[buck];
b._numdoc = ndoc;
b._numrig = nrig;
}
bool TMSP_constraint::has_mastercodes() const
{
return _mastercodes.items()>0;
}
void TMSP_constraint::add_mastercode(TMaster_code *mc)
{
_mastercodes.add(mc);
}
TMaster_code *TMSP_constraint::get_mastercode(int i)
{
if (i>=0 && i < _mastercodes.items());
return (TMaster_code *) _mastercodes.objptr(i);
return NULL;
}
bool TMSP_constraint::has_upperlines() const
{
return _upperlines.items()>0;
}
void TMSP_constraint::add_upperline(TMSP_constraint& mc)
{
if (_upperlines.items()==0)
{
// aggiunge se stesso
TMSP_constraint * myself=_upperlines.find(cliente(), codice(), livgiac(),
codimp(),codlin(),codmag(),TRUE);
*myself=*this;
}
_upperlines.find(mc.cliente(), mc.codice(), mc.livgiac(),
mc.codimp(),mc.codlin(),mc.codmag(),TRUE);
}
TMSP_constraint* TMSP_constraint::get_upperline(TMSP_constraint& mc)
{
return _upperlines.find(mc.cliente(), mc.codice(), mc.livgiac(),
mc.codimp(),mc.codlin(),mc.codmag(),FALSE);
}
TMSP_constraint & TMSP_constraint::operator=(const TMSP_constraint & line)
{
_cliente=line.cliente();
_codart=line.codice();
_giac=line.livgiac();
_imp=line.codimp();
_lin=line.codlin();
_mag=line.codmag();
_on_sheet=_on_sheet;
_desc=line.desc();
_bucket_qta=line._bucket_qta;
return *this;
}
TMSP_constraint::TMSP_constraint(long cliente,
const TCodice_articolo& codart,
const TString& giac,
const TString& imp,
const TString& lin,
const TString& mag)
: _cliente(cliente), _codart(codart), _giac(giac),
_imp(imp), _lin(lin), _mag(mag),_on_sheet(FALSE)
{ }
TMSP_constraint::TMSP_constraint(TMSP_constraint & line)
: _cliente(line.cliente()), _codart(line.codice()), _giac(line.livgiac()),
_imp(line.codimp()), _lin(line.codlin()), _mag(line.codmag()), _on_sheet(FALSE),
_desc(line.desc())
{
}
///////////////////////////////////////////////////////////
// TMSP_constraints
///////////////////////////////////////////////////////////
TSortable* TMSP_constraints::new_obj(const TToken_string& key) const
{
long cli; key.get(0, cli);
TCodice_articolo art; key.get(1, art); art.trim();
TString16 gia; key.get(2, gia); gia.trim();
TString8 imp; key.get(3, imp); imp.trim();
TString8 lin; key.get(4, lin); lin.trim();
TString8 mag; key.get(5, mag); mag.trim();
return new TMSP_constraint(cli, art, gia, imp, lin, mag);
}
TMSP_constraint* TMSP_constraints::find(long cliente,
const TString& art,
const TString& gia,
const TString& imp,
const TString& lin,
const TString& mag,
bool create)
{
_key.format("%ld", cliente);
_key.add(art);_key.trim();
_key.add(gia);_key.trim();
_key.add(imp);_key.trim();
_key.add(lin);_key.trim();
_key.add(mag);_key.trim();
TSortable* s = create ? add_obj(_key) : find_obj(_key);
TMSP_constraint *c=(TMSP_constraint*)s;
if (create)
{
if (c->desc().blank())
c->set_desc(cache().get(LF_ANAMAG,art).get("DESCR"));
}
return c;
}
//////////////////////////////////////////////////////////
// TMSP_line
///////////////////////////////////////////////////////////
void TMSP_line::fill_sheet_row(TToken_string& row, const TMSP_mask & m, bool codes_only)
{
TMSP_constraint::fill_sheet_row(row, m, codes_only);
row.add(m.get(F_TIPOCF),F_TIPOCF_SHEET-FIRST_FIELD);
}
TMSP_line::TMSP_line(long cliente, const TCodice_articolo& codart,
const TString& giac, const TString& imp,
const TString& lin, const TString& mag)
: TMSP_constraint(cliente, codart, giac, imp, lin,mag)
{ }
TMSP_line::TMSP_line(TMSP_constraint & cons)
:TMSP_constraint(cons)
{ }
TMSP_line::TMSP_line(TMSP_line & line)
:TMSP_constraint((TMSP_constraint &)line)
{
}
///////////////////////////////////////////////////////////
// TMSP_lines
///////////////////////////////////////////////////////////
TSortable* TMSP_lines::new_obj(const TToken_string& key) const
{
long cliente; key.get(0, cliente);
TCodice_articolo art; key.get(1, art); art.trim();
TString gia; key.get(2, gia); gia.trim();
TString imp; key.get(3, imp); imp.trim();
TString lin; key.get(4, lin); lin.trim();
TString mag; key.get(5, mag); mag.trim();
return new TMSP_line(cliente, art, gia, imp, lin, mag);
}
TMSP_line* TMSP_lines::find(long cliente,
const TString& art,
const TString& gia, const TString& imp,
const TString& lin, const TString& mag,
bool create)
{
_key.format("%ld", cliente);
_key.add(art);
_key.add(gia);
_key.add(imp);
_key.add(lin);
_key.add(mag);
TSortable* s = create ? add_obj(_key) : find_obj(_key);
return (TMSP_line*)s;
}
TMSP_line* TMSP_lines::find(const TToken_string& row, TCodice_livelli & livelli ,bool create)
{
TString80 str,giaclev;
_key.cut(0);
for (int i = 0; i <= 11; i++)
{
row.get(i, str);
str.trim();
switch (i+FIRST_FIELD)
{
case F_LIV1:
case F_LIV2:
case F_LIV3:
livelli.pack_grpcode(giaclev, str, i+FIRST_FIELD-F_LIV1+1); break;
case F_LIV4:
livelli.pack_grpcode(giaclev, str, 4);
giaclev.trim();
_key.add(giaclev);
break; // Concatena i livelli
case F_MAGAZZINO:
_key.add(str);
row.get(i+1, str);
str.trim();
_key << str;
break; // Concatena magazzini e depositi
case F_CLIENTE:
if (str.blank()) str = "0";
case F_ARTICOLO:
case F_CODIMP:
case F_CODLIN:
_key.add(str); break; // Aggiungi normalmente
}
}
TSortable* s = create ? add_obj(_key) : find_obj(_key);
return (TMSP_line*)s;
}
///////////////////////////////////////////////////////////
// TPlan_docs
///////////////////////////////////////////////////////////
class TPlan_docs : public TMRP_array
{
TString16 _num, _doc, _rig;
protected:
virtual TSortable* new_obj(const TToken_string& key) const;
public:
TDocumento& find(int anno, long num);
TRiga_documento& add_to_row(int anno, long num, int riga, const real& qta);
long flush(const TDate& data);
TPlan_docs(const char* num, const char* tip, const char* rig);
virtual ~TPlan_docs() { }
};
TSortable* TPlan_docs::new_obj(const TToken_string& key) const
{
int anno; key.get(0, anno);
long num; key.get(1, num);
TDocumento* doc = new TDocumento('D', anno, _num, num);
doc->head().put(DOC_TIPODOC, _doc);
return doc;
}
TDocumento& TPlan_docs::find(int anno, long num)
{
_key.format("%d|%ld", anno, num);
return *(TDocumento*)add_obj(_key);
}
TRiga_documento& TPlan_docs::add_to_row(int anno, long num, int riga, const real& qta)
{
TDocumento& doc = find(anno, num);
if (riga <= 0 || riga > doc.physical_rows())
{
TRiga_documento& r = doc.new_row(_rig);
riga = r.get_int(RDOC_NRIGA);
}
TRiga_documento& rdoc = doc[riga];
real val = rdoc.get(RDOC_QTA);
val += qta;
if (val <= ZERO)
rdoc.put(RDOC_QTA, ZERO);
else
rdoc.put(RDOC_QTA, val);
return rdoc;
}
long TPlan_docs::flush(const TDate& data)
{
const long tot = items();
if (tot > 0L)
{
TString msg;
msg << "Registrazione dei documenti di planning per il " << data;
TProgind pi(tot, msg, FALSE, TRUE);
TLocalisamfile lfdoc(LF_DOC);
for (long d = 0; d < tot; d++)
{
pi.addstatus(1);
TDocumento& doc = (TDocumento&)find_obj(d);
for (int r = doc.physical_rows(); r > 0; r--)
{
const TRiga_documento& riga = doc[r];
if (riga.is_articolo() && riga.quantita() == ZERO)
doc.destroy_row(r, TRUE);
}
if (doc.physical_rows())
doc.write(lfdoc);
else
doc.remove(lfdoc);
}
destroy();
}
return tot;
}
TPlan_docs::TPlan_docs(const char* num, const char* tip, const char* rig)
: _num(num), _doc(tip), _rig(rig)
{
}
///////////////////////////////////////////////////////////
// ritorna se tutto OK
bool TRiga_articolo::find_block(const TSheet_field& sf, const int riga, int &first_row, int &last_row )
{
const int narticoli=sf.items();
if (narticoli<=riga)
return FALSE;
// Calcola l'indice c della riga coi vincoli
const int b1 = sf.cid2index(F_BUCKET1);
for (first_row = riga; first_row > 0; first_row--)
{
if (sf.cell_disabled(first_row, b1))
break;
}
if (first_row+1 < narticoli && sf.cell_disabled(first_row+1, b1)) first_row++;
// Calcola l'indice r dell'ultima riga articoli
last_row = riga;
if (last_row <= first_row) last_row=first_row+1;
for ( ; last_row < narticoli-1; last_row++)
{
if (sf.cell_disabled(last_row+1, b1))
break;
}
return TRUE;
}
int TRiga_articolo::order_compare( const TToken_string &r1 , const TToken_string &r2 , int level)
{
TString16 str0, str1;
int cmp = 0;
if (level>=0)
{
for (int i = 2; i <= level && cmp == 0; i++)
{
r1.get(i, str0);
r2.get(i, str1);
cmp=TRiga_articolo::compare_field(str0,str1,short(i+FIRST_FIELD));
}
} else {
// ordinamenti non standard
short f;
short fields_ACL[] = {F_PRIORITA, F_ARTICOLO, F_CLIENTE, F_SORTCODIMP, F_SORTCODLIN};
short fields_ALC[] = {F_PRIORITA, F_ARTICOLO, F_SORTCODIMP, F_SORTCODLIN, F_CLIENTE};
short fields_LAC[] = {F_PRIORITA, F_SORTCODIMP, F_SORTCODLIN, F_ARTICOLO, F_CLIENTE};
short fields_LCA[] = {F_PRIORITA, F_SORTCODIMP, F_SORTCODLIN, F_CLIENTE, F_ARTICOLO};
short fields_CLA[] = {F_PRIORITA, F_CLIENTE, F_SORTCODIMP, F_SORTCODLIN, F_ARTICOLO};
short fields_CAL[] = {F_PRIORITA, F_CLIENTE, F_ARTICOLO, F_SORTCODIMP, F_SORTCODLIN};
for (int i = 0; i < 5 && cmp == 0; i++)
{
switch (level)
{
case SORT_BY_CAL:
f=fields_CAL[i]; break;
case SORT_BY_CLA:
f=fields_CLA[i]; break;
case SORT_BY_LCA:
f=fields_LCA[i]; break;
case SORT_BY_LAC:
f=fields_LAC[i]; break;
case SORT_BY_ACL:
f=fields_ACL[i]; break;
case SORT_BY_ALC:
f=fields_ALC[i]; break;
default:
NFCHECK("Ordinamento sconosciuto");
break;
}
r1.get(f-FIRST_FIELD, str0);
r2.get(f-FIRST_FIELD, str1);
cmp=TRiga_articolo::compare_field(str0,str1,f);
}
}
return cmp;
}
// aggiunge li codici di linea/impianto se non presenti usando i default sulle lavorazioni critiche
// cio' permette di ordinare per impianto anche le linee di ordine che non hanno solitamente
// questa indicazione ma solo il codice articolo
void complete_codlinea(TToken_string &r2, bool ignore_imp)
{
static TDistinta_tree *_dist_tree=NULL;
TString8 swp;
r2.get(F_SORTCODLIN-FIRST_FIELD,swp);
if (swp.blank())
{
r2.get(F_CODLIN-FIRST_FIELD,swp);
if (swp.blank())
{
if (_dist_tree==NULL)
_dist_tree= new TDistinta_tree();
if (_dist_tree->set_root(r2.get(F_ARTICOLO-FIRST_FIELD)))
{
TString codimp(r2.get(F_CODIMP-FIRST_FIELD));
TArray labors;
TRiga_esplosione * l=_dist_tree->first_critical_labor(labors);
if (l)
{
TLavorazione *curr_labor=TDistinta_tree::find_labor(l);
CHECK(curr_labor,"Lavorazione non trovata");
for (int nlinea=0; nlinea <curr_labor->linee_standard(); nlinea ++)
{
const TRectype &linea_prod= cache().get("LNP",curr_labor->cod_linea(nlinea));
if ( ignore_imp || codimp.blank() || codimp==linea_prod.get("S6"))
{
r2.add(linea_prod.get("CODTAB"), F_SORTCODLIN-FIRST_FIELD);
r2.add(linea_prod.get("S6"), F_SORTCODIMP-FIRST_FIELD);
return;
}
}
}
}
r2.add('\255', F_SORTCODLIN-FIRST_FIELD);
}
else
{
r2.add(swp, F_SORTCODLIN-FIRST_FIELD);
r2.get(F_CODLIN-FIRST_FIELD,swp);
r2.add(swp, F_SORTCODIMP-FIRST_FIELD);
}
}
}
int TRiga_articolo::order_compare(TSheet_field & s, int i1, int i2, int level)
{
TMask &m=s.mask();
const bool ascending=!m.get_bool(F_MSP_SORT_ORDER);
int first1, first2, last1, last2;
if (find_block(s, i1, first1, last1 )) first1--;
if (find_block(s, i2, first2, last2 )) first2--;
const TToken_string &r1 = s.row(i1);
const TToken_string &r2 = s.row(i2);
if (s.cell_enabled(i1, F_BUCKET1-FIRST_FIELD) && s.cell_enabled(i2, F_BUCKET1-FIRST_FIELD) )
{
// confronto tra righe dello stesso vincolo
if (first1 == first2 )
return order_compare( r1 , r2 , level) * (ascending ? 1 : -1);
} else {
if (first1 != first2 && first1==i1 && first2==i2 )
{
TToken_string &blockr1=(TToken_string &)r1;
TToken_string &blockr2=(TToken_string &)r2;;
complete_codlinea(blockr1, m.get_bool(F_NOIMP_IN));
complete_codlinea(blockr2, m.get_bool(F_NOIMP_IN));
// confronto tra blocchi ed eventuale swap direttamente qui nella compare
int cmp = order_compare(blockr1 , blockr2 , level) * (ascending ? 1 : -1);
if (cmp > 0)
{
for (int bubble=first2; bubble<=last2; bubble++)
{
for (int r=bubble; r>bubble+first1-first2; r--)
{
s.swap_rows(r, r-1);
}
}
}
}
}
return 0;
}
int TRiga_articolo::order_compareCAL(TSheet_field & s, int i1, int i2)
{ return TRiga_articolo::order_compare(s, i1, i2,SORT_BY_CAL);}
int TRiga_articolo::order_compareCLA(TSheet_field & s, int i1, int i2)
{ return TRiga_articolo::order_compare(s, i1, i2,SORT_BY_CLA);}
int TRiga_articolo::order_compareALC(TSheet_field & s, int i1, int i2)
{ return TRiga_articolo::order_compare(s, i1, i2,SORT_BY_ALC);}
int TRiga_articolo::order_compareACL(TSheet_field & s, int i1, int i2)
{ return TRiga_articolo::order_compare(s, i1, i2,SORT_BY_ACL);}
int TRiga_articolo::order_compareLAC(TSheet_field & s, int i1, int i2)
{ return TRiga_articolo::order_compare(s, i1, i2,SORT_BY_LAC);}
int TRiga_articolo::order_compareLCA(TSheet_field & s, int i1, int i2)
{ return TRiga_articolo::order_compare(s, i1, i2,SORT_BY_LCA);}
int TRiga_articolo::compare_field(TString &str0, TString &str1,short field_no)
{
int cmp;
switch (field_no)
{
case F_CLIENTE:
{
const long f0 = atol(str0);
const long f1 = atol(str1);
cmp = f0 == f1 ? 0 : (f0 > f1 ? +1 : -1);
}
break;
case F_PRIORITA:
cmp = -str0.compare(str1);
break;
default:
cmp = str0.compare(str1);
break;
}
return cmp;
}
TRiga_articolo& TRiga_articolo::operator=(TToken_string& r)
{
this->TToken_string::operator=(r);
return *this;
}
TRiga_articolo& TRiga_articolo::operator+=(TRiga_articolo& r)
{
NFCHECK( "Can't add incompatible order line");
return *this;
}
TRiga_articolo::TRiga_articolo(const TMSP_constraint& line)
: TToken_string(128)
{
format("%ld", line.cliente());
add(line.codice(),F_CLIENTE-FIRST_FIELD);
add(" ",F_PRIORITA-FIRST_FIELD);
const TString& liv = line.livgiac();
for (int l = 1; l <= 4; l++)
{
if (livelli_giac().enabled(l))
add(livelli_giac().unpack_grpcode(liv,l),F_LIV1+l-1-FIRST_FIELD);
else
add(" ",F_LIV1+l-1-FIRST_FIELD);
}
add(line.desc(),F_DESCART-FIRST_FIELD);
add(line.codimp(),F_CODIMP-FIRST_FIELD);
add(line.codlin(),F_CODLIN-FIRST_FIELD);
TString8 str = line.codmag().left(3);
add(str, F_MAGAZZINO-FIRST_FIELD);
str = line.codmag().mid(3);
add(str, F_DEPOSITO-FIRST_FIELD);
const TCodice_um um;
const TQuantita qta_art(line.codice(), um, ZERO);
add(qta_art.um(),F_UM-FIRST_FIELD);
TMSP_constraint& lin=(TMSP_constraint& )line;
const int last_buck= line.last();
for (int bu = 0; bu <= last_buck; bu ++)
{
add(lin.qta(bu).string(), bu*2+F_BUCKET0-FIRST_FIELD);
}
}
///////////////////////////////////////////////////////////
// Maschera principale
///////////////////////////////////////////////////////////
// Arrotonda la data al bucket e ne restituisce il numero (data iniziale==bucket 0)
int TMSP_mask::round_date(TDate& date, bool up) const
{
// Dimensione del bucke in giorni
int bucket_size = days_per_bucket();
// Riporta la data al primo lunedi prima dell'inizio
TDate inizio = get(F_DADATA);
const int wday = inizio.wday();
if (wday > 1) inizio -= wday-1;
// Calcola il bucket di appartenenza
const int days = int(date - inizio);
const int bucket = days / bucket_size;
if (up) // Arrotonda alla fine del bucket
date = inizio + long((bucket+1 )* bucket_size - 1);
else // Arrotonda all'inizio del bucket
date = inizio + long(bucket * bucket_size);
return bucket;
}
void TMSP_mask::round_field(TMask_field& fld, bool up) const
{
TDate date = fld.get();
if (date.ok())
{
round_date(date, up);
fld.set(date);
}
}
int TMSP_mask::test_codnum(const TCodice_numerazione& num) const
{
int r=0;
for (int s = 2; s > 0; s--)
{
const short id = s == 2 ? F_NUM_PLA : F_NUM_ORC;
TString_array& nums = sfield(id).rows_array();
for (int i = nums.items()-1; i >= 0; i--)
{
const char* t = nums.row(i).get(0);
if (num.codice() == t)
{
r|=s; break;
}
}
}
return r;
}
bool TMSP_mask::test_tipodoc_num(const TSheet_field &sheet_num ,const TSheet_field &sheet_type)
{
TString16 tipo;
TString_array& nums = sheet_num.rows_array();
TString_array& types = sheet_type.rows_array();
for (int j = types.items()-1; j >= 0; j--)
{
bool ok=FALSE;
tipo = types.row(j).get(0) ;
const char * cazzoinculo=(const char * )tipo;
for (int i = nums.items()-1; i >= 0; i--)
{
TCodice_numerazione num(nums.row(i).get(0));
for (int n = num.ntipi_doc()-1;n >= 0; n--)
{
const char* t = num.tipo_doc(n);
if (tipo == t)
ok = TRUE;
}
}
if (!ok)
return error_box("Il tipo '%s' non appartiene a nessuna delle numerazioni scelte",(const char * )tipo);
}
return TRUE;
}
bool TMSP_mask::test_status(const TRectype& doc, int s) const
{
const short id = (s & 2) ? F_TIPI_PLA : F_TIPI_ORC;
TSheet_field& sf = sfield(id);
const int idfr = sf.cid2index(F_DASTATO);
const int idto = sf.cid2index(F_ASTATO);
const TString16 tipodoc = doc.get(DOC_TIPODOC);
const int statodoc = doc.get_int(DOC_STATO);
bool yes = FALSE;
TString_array& a = sf.rows_array();
for (int i = a.items()-1; i >= 0 && !yes; i--)
{
TToken_string& riga = a.row(i);
const char* t = riga.get(0);
if (tipodoc == t)
{
const int state_fr = riga.get_int(idfr);
const int state_to = riga.get_int(idto);
yes = statodoc >= state_fr && statodoc <= state_to;
}
}
return yes;
}
// Metodo standard per contare gli elementi di una tabella
// in attesa di tempi migliori per le librerie
/*
static long table_items(const char* tab)
{
TRelation tabrel(tab);
TCursor tabcur (&tabrel);
long tot = tabcur.items();
return tot;
}
*/
bool TMSP_mask::carica_documenti()
{
const bool ignore_mag=get_bool(F_NOMAG_IN);
const bool ignore_imp=get_bool(F_NOIMP_IN);
const bool ignore_lin=get_bool(F_NOLIN_IN);
const bool ignore_cli=get_bool(F_NOCLI_IN);
const bool ignore_allcli=get_bool(F_NOCLI_OUT);
const bool is_master_sched = get_bool(F_MSCHEDULEPLAN);
const bool two_level = get_bool(F_2LEVEL_MSP);
TDate date_fr = get(F_DADATA);
const int bucket_fr = round_date(date_fr, FALSE);
TDate date_to = get(F_ADATA);
const int bucket_to = round_date(date_to, TRUE);
const int year_fr = date_fr.year();
const int year_to = date_to.year();
const TString& numplan = get(F_NUM_PLAN);
TTable num("%NUM");
TCodice_numerazione cod;
TRelation rel(LF_DOC);
TCursor cur(&rel);
const TRectype& curr = cur.curr();
TRectype filter_fr(curr), filter_to(curr);
_articles.destroy();
_constraints.destroy();
_proposed_articles.destroy();
// Scandisce tutte le numerazioni considerando solo quelle
// contenenti i tipi documento specificati nella maschera
for (int err = cod.first(num); err == NOERR; err = cod.next(num))
{
const int tn = test_codnum(cod);
if (tn)
{
// Filtra il cursore in modo da limitarlo alla numerazione
// corrente ed agli anni specificati dalle due date limite
filter_fr.put(DOC_PROVV, "D");
filter_fr.put(DOC_CODNUM, cod.get("CODTAB"));
filter_fr.put(DOC_ANNO, year_fr);
filter_to.put(DOC_PROVV, "D");
filter_to.put(DOC_CODNUM, cod.get("CODTAB"));
filter_to.put(DOC_ANNO, year_to);
cur.setregion(filter_fr, filter_to);
TString cfilter;
cfilter << DOC_CODNUM << "==" << '"' << cod.get("CODTAB")<< '"';
cur.setfilter(cfilter);
const long items = cur.items();
cur.freeze(TRUE);
// Scandisce i documenti inevasi e considera solo
// quelli con uno stato nel range corretto
TString msg;
msg.format("Caricamento documenti %s (numerazione '%s')",tn & 1 ? "ordine":"di planning",(const char *)cod.codice());
TProgind pi(items,msg , TRUE, TRUE);
for (cur = 0; cur.pos() < items; ++cur)
{
pi.addstatus(1);
if (pi.iscancelled())
return FALSE;
const bool evaso = curr.get_bool(DOC_DOCEVASO);
if (evaso)
continue;
// Calcola data di consegna per righe che non ce l'hanno
TDate datacons = curr.get(DOC_DATACONS);
if (!datacons.ok())
datacons = curr.get(DOC_DATADOC);
if (!test_status(curr, tn))
continue;
// Scandisce le righe articolo e memorizza
// le quantita' richieste
TDocumento doc(cur.curr());
for (int r = doc.physical_rows(); r > 0; r--)
{
// Seleziona le righe articolo non ancora evase
const TRiga_documento& riga = doc[r];
if (riga.is_articolo())
{
const real qta = riga.qtaresidua();
if (qta > ZERO)
{
const TCodice_articolo art = riga.get(RDOC_CODARTMAG);
const TString16 liv = _livelli.enabled() ? riga.get(RDOC_LIVELLO) : "";
const long cli = (ignore_cli && (tn & 1)) ||ignore_allcli ? 0 : doc.get_long(DOC_CODCF) ;
const TString16 mag = ignore_mag && (tn & 1) ? "" : riga.get(RDOC_CODMAG);
const TString16 imp = ignore_imp && (tn & 1) ? "" : riga.get(RDOC_IMPIANTO);
const TString16 lin = ignore_lin && (tn & 1) ? "" : riga.get(RDOC_LINEA);
const TCodice_um um = riga.get(RDOC_UMQTA);
TQuantita q(art, um, qta);
q.convert2umbase();
TDate consegna = riga.get(RDOC_DATACONS);
if (!consegna.ok())
consegna = datacons;
int buck = round_date(consegna) - bucket_fr + 1;
if (buck < 0) buck = 0; else
if (buck > LAST_BUCKET) buck = LAST_BUCKET;
TMSP_constraint* line;
if (tn & 1)
{
line = _constraints.find(cli, art, liv, imp, lin, mag, TRUE);
if (two_level && !distinta_master(art))
{
TString master, ummaster, livmaster,impmaster(imp), linmaster(lin),magmaster;
real expr;
if (!line->has_mastercodes())
{
int i=0;
while ((i=find_distinta_master(art, master, livmaster, ummaster, expr, impmaster, linmaster, magmaster,i)+1) >0)
{
TMSP_constraint*masterline=_constraints.find(cli, master , livmaster, imp, lin, mag, TRUE);
masterline->add_upperline(*line);
line->add_mastercode(new TMaster_code (master, livmaster, ummaster, expr, cache().get(LF_ANAMAG,master).get_real(ANAMAG_GIORNIRIOR), imp, lin, mag));
}
}
}
} else {
line = _articles. find(cli, art, liv, imp, lin, mag, TRUE);
}
if (line->desc().empty())
line->set_desc(riga.get(RDOC_DESCR));
if (buck > 0 && buck < LAST_BUCKET && cod.codice() == numplan)
{
long numdoc;
int numrig;
if (!line->riga(buck, numdoc, numrig))
{
numdoc = riga.get_long(RDOC_NDOC);
numrig = riga.get_int(RDOC_NRIGA);
line->set_riga(buck, numdoc, numrig);// memorizza la provenienza dal doc
}
}
line->qta(buck) += q.val();
real price;
find_price(get(F_TIPOCV),get(F_CODCONDV),get(F_CATVEN_CV),
get(F_TIPOCF), cli, art,
line->qta(buck), price);
line->price(buck) = price;
}
}
}
}
cur.freeze(FALSE);
}
}
return _constraints.items() > 0L || _articles.items() > 0L;
}
// cerca il vincolo "migliore" secondo la logica :
// - stesso magazzino , impianto e linea
// - stesso magazzino e impianto
// - stesso magazzino
// - stesso impianto e linea
// - stessa linea
TMSP_constraint* TMSP_mask::find_constraint(const TMSP_line& l, bool force_insert)
{
const bool ignore_mag=get_bool(F_NOMAG_IN);
const bool ignore_imp=get_bool(F_NOIMP_IN);
const bool ignore_lin=get_bool(F_NOLIN_IN);
const bool ignore_cli=get_bool(F_NOCLI_IN);
TString16 codmag=ignore_mag ? "" : l.codmag();
TString16 codimp=ignore_imp ? "" : l.codimp();
TString16 codlin=ignore_lin ? "" : l.codlin();
long codcli=ignore_cli ? 0L : l.cliente() ;
// se il magazzino o l'impianto non e' indicato sul vincolo cerca di individuarlo
// in base ai default di linea/impianto
if (codimp.blank())
{
if (!codlin.blank())
{
TLinea_prod &linea_prod=*::get_linea(codlin);
codimp=linea_prod.codimp();
}
}
if (codmag.blank())
{
if (!codlin.blank())
{
TLinea_prod &linea_prod=*::get_linea(codlin);
codmag=linea_prod.codmagdep();
} else
if (!codimp.blank())
{
TImpianto &impianto=*::get_impianto(codimp);
codmag=impianto.codmagdep();
}
}
// cerca il vincolo con - stesso magazzino , impianto e linea
TMSP_constraint* c = _constraints.find(codcli, l.codice(), l.livgiac(), codimp, codlin, codmag);
if (c == NULL )
{
if (!codmag.blank())
{
// cerca il vincolo con - stesso magazzino e impianto
c =_constraints.find(codcli, l.codice(), l.livgiac(), codimp, "", codmag);
if (c == NULL)
// cerca il vincolo con - stesso magazzino
c =_constraints.find(codcli, l.codice(), l.livgiac(), "", "", codmag);
}
if (c == NULL)
// cerca il vincolo con - stesso impianto e linea
c =_constraints.find(codcli, l.codice(), l.livgiac(), codimp, codlin, "");
if (c == NULL)
// cerca il vincolo con - stessa impianto
c =_constraints.find(codcli, l.codice(), l.livgiac(), codimp, "" , "");
}
if (c == NULL && force_insert)
{
// MA STO VINCOLO MANCA PROPRIO! ALLORA LO INSERISCO
c = _constraints.find(codcli, l.codice(), l.livgiac(), codimp, codlin, codmag, TRUE);
if (c->desc().blank())
c->set_desc(l.desc());
}
return c;
}
int TMSP_mask::find_constr_row(const TMSP_constraint& c)
{
TSheet_field& sf = sfield(F_ARTICOLI);
const int maxart=sf.items();
for (int r=0; r <maxart; r++)
{
TToken_string &row=sf.row(r);
TString16 liv;
_livelli.pack_grpcode(liv, row.get(sf.cid2index(F_LIV1)),1);
_livelli.pack_grpcode(liv, row.get(sf.cid2index(F_LIV2)),2);
_livelli.pack_grpcode(liv, row.get(sf.cid2index(F_LIV3)),3);
_livelli.pack_grpcode(liv, row.get(sf.cid2index(F_LIV4)),4);
TString16 imp(row.get(sf.cid2index(F_CODIMP)));imp.trim();
TString16 lin(row.get(sf.cid2index(F_CODLIN)));lin.trim();
TString16 mag;
add_magcode(mag, row.get(sf.cid2index(F_MAGAZZINO)));
add_depcode(mag, row.get(sf.cid2index(F_DEPOSITO )));
if (sf.cell_disabled(r, sf.cid2index(F_BUCKET1)))
{
if (c.cliente()==row.get_long(sf.cid2index(F_CLIENTE)) &&
c.codice() == row.get(sf.cid2index(F_ARTICOLO)) &&
c.livgiac() == liv&&
c.codimp()== imp &&
c.codlin()==lin &&
c.codmag()==mag )
return r;
else
r+=2;
}
}
return -1;
}
void TMSP_mask::fill_sheet()
{
//TSheet_field& su = sfield(F_TESTE);
TSheet_field& sl = sfield(F_LINEE);
TSheet_field& sf = sfield(F_ARTICOLI);
sf.enable_column(F_CLIENTE,!get_bool(F_NOCLI_OUT));
sf.set_column_header(F_CLIENTE-FIRST_FIELD,*get(F_TIPOCF)=='C' ? "Cliente" : "Fornitore");
const TDate date_to = get(F_ADATA);
const int bucket_size = days_per_bucket();
TDate d = get(F_DADATA);
TString16 str;
for (int b = 0; b <= LAST_BUCKET; b++)
{
if (b > 0 && b < LAST_BUCKET)
{
sf.enable_column(F_BUCKET0 + b*2, d < date_to);
sf.enable_column(F_BUCKET0 + b*2+1, d < date_to);
sl.enable_column(F_LBUCKET0 + b, d < date_to);
//su.enable_column(F_LBUCKET0 + b, d < date_to);
}
str = d.string();
switch(b)
{
case 0: str.insert("< "); break;
//case 9: /* Nothing!! */ ; break;
case LAST_BUCKET: str.insert(">= "); break;
default: d += bucket_size; break;
}
sf.set_column_header(F_BUCKET0 + b*2, str);
sf.set_column_header(F_BUCKET0 + b*2 +1, str);
sl.set_column_header(F_LBUCKET0 + b, str);
//su.set_column_header(F_LBUCKET0 + b, str);
}
TMSP_constraint* last_constraint = NULL;
const long totart = _articles.sort();
TWait_cursor hourglass;
for (long i = 0; i < totart; i++)
{
TMSP_line& line = _articles[i];
TMSP_constraint* curr_constraint = find_constraint(line,TRUE);
if (last_constraint != curr_constraint)
{
// aggiunge la linea di vincolo
TToken_string& consrow = sf.row(-1);
curr_constraint->fill_sheet_row(consrow, *this);
consrow.add("** Ordini ",F_DESCART-FIRST_FIELD);
sf.disable_cell(sf.items()-1, -1);
// aggiunge la linea della giacenza prog
TToken_string& rowgiac = sf.row(-1);
copy_sheet_row(rowgiac,consrow);
rowgiac.add("** Giacenza teorica",F_DESCART-FIRST_FIELD);
sf.disable_cell(sf.items()-1, -1);
last_constraint = curr_constraint;
curr_constraint->set_on_sheet();
}
TToken_string& row = sf.row(-1);
line.fill_sheet_row(row, *this);
}
const long totcon = _constraints.sort();
for (long j = 0; j < totcon; j++)
{
TMSP_constraint& cons = _constraints[j];
if (!cons.is_on_sheet())
{
// aggiunge le tre linee
TToken_string& row = sf.row(-1);
cons.fill_sheet_row(row, *this);
cons.set_on_sheet();
sf.disable_cell(sf.items()-1, -1);
//linea della giacenza prog
TToken_string& rowgiac = sf.row(-1);
copy_sheet_row(rowgiac,row);
sf.disable_cell(sf.items()-1, -1);
//linea articolo (vuota)
TMSP_line line(cons);
line.fill_sheet_row(sf.row(-1), *this);
rowgiac.add("** Giacenza teorica",F_DESCART-FIRST_FIELD);
row.add("** Ordini ",F_DESCART-FIRST_FIELD);
}
}
for (int r = sf.items()-1; r >0 ; )
{
// init bucket 0
TCodice_articolo codart(sf.cell(r,sf.cid2index(F_ARTICOLO)));
if (codart.blank())
r = r-2;
TArticolo_giacenza art(codart);
r=init_bucket0(art, r);
}
sf.force_update();
}
bool TMSP_mask::distinta_master(const char *code)
{
const TRectype &rec=cache().get(LF_DIST,code);
if (rec.empty()) return FALSE;
return rec.get_bool("MASTER");
}
int TMSP_mask::find_distinta_master(const char * code, TString & master,TString & livmaster,TString & um, real & expr, TString & imp,TString & lin,TString & magdep, int fromindex)
{
TArray sons;
if (_dist_tree.set_root(code))
{
_dist_tree.explode(sons, FALSE, RAGGR_EXP_NONE, 1);
TRiga_esplosione* riga;
while (riga=(TRiga_esplosione* )sons.objptr(fromindex))
{
if (distinta_master(riga->articolo()))
{
master=riga->articolo();
livmaster=riga->livello();
um =riga->um();
expr =riga->val();
return fromindex;
}
fromindex=sons.succ(fromindex);
}
}
master="";
return -1;
}
bool TMSP_mask::insert_propose(bool verbose)
{
if (_proposed_articles.items()<=0L)
{
if (verbose)
message_box("Nessuna nuova proposta");
return FALSE;
}
else
{
add_or_sub_propose(+1);
const long new_rows=_proposed_articles.items();
TSheet_field& sf = sfield(F_ARTICOLI);
int firstbuck;
TDate firstdate(get_date(F_ADATA));
for (long new_row=0; new_row < new_rows; new_row++)
{
const TDate & d=_proposed_articles[new_row].time(0).date() ;
firstdate=min(firstdate,d);
}
firstbuck=int((firstdate- get_date(F_DADATA))/days_per_bucket())+1;
if (verbose)
message_box("Quantita' proposte a partire dal %s (colonna %0d)", (const char *)firstdate.string(), int(firstbuck));
}
return TRUE;
}
bool TMSP_mask::remove_propose(bool verbose)
{
if (_proposed_articles.items()<=0L)
{
if (verbose)
message_box("Nessuna proposta da annullare");
return FALSE;
}
add_or_sub_propose(-1);
_proposed_articles.destroy();
return TRUE;
}
void TMSP_mask::add_or_sub_propose(char sign)
{
const long new_rows=_proposed_articles.items();
TSheet_field& sf = sfield(F_ARTICOLI);
for (long new_row=0; new_row < new_rows; new_row++)
{
const TMRP_line & a=_proposed_articles[new_row];
TMSP_line line(a.codcli(), a.codice(), a.livgiac(), a.codimp(), a.codlin(), a.codmag());
bool line_found=FALSE;
TMSP_constraint* constraint= find_constraint(line,FALSE);
if (constraint==NULL)
{
CHECK( sign>0, "Impossibile trovare il vincolo da soddisfare...");
// aggiunge le tre linee
constraint=new TMSP_constraint(line);
TToken_string& row = sf.row(-1);
constraint->fill_sheet_row(row, *this);
constraint->set_on_sheet();
sf.disable_cell(sf.items()-1, -1);
//linea della giacenza prog
TToken_string& rowgiac = sf.row(-1);
copy_sheet_row(rowgiac,row);
sf.disable_cell(sf.items()-1, -1);
//linea articolo (vuota)
TToken_string& emptyrowc = sf.row(-1);
rowgiac.add("** Giacenza teorica",F_DESCART-FIRST_FIELD);
row.add("** Ordini ",F_DESCART-FIRST_FIELD);
}
int art_row;
for (art_row=int(sf.items())-1;art_row >=0; art_row--)
{
TToken_string &row=sf.row(art_row);
long codcli;
TCodice_articolo codart ;
TString16 liv, mag, codimp, codlin, codum;
msprow2codes(row,codcli,codart,liv, mag, codimp, codlin, codum);
if (!sf.cell_disabled(art_row, F_BUCKET1-FIRST_FIELD))
{
line_found=(a.codcli()==codcli && a.codice()==codart && a.livgiac()==liv
&& a.codimp()==codimp && a.codlin()==codlin && a.codmag()==mag );
if (line_found)
break;
} else {
TMSP_constraint* currcons=_constraints.find(codcli, codart, liv, codimp, codlin, mag);
if (constraint==currcons)
break;
}
}
if (!line_found)
{
art_row++;
sf.insert(art_row);
TToken_string& artrow = sf.row(art_row);
constraint->fill_sheet_row(artrow, *this,TRUE);
artrow.add(a.codimp(), F_CODIMP-FIRST_FIELD);
artrow.add(a.codlin(), F_CODLIN-FIRST_FIELD);
TString16 str=a.codmag().left(3);
artrow.add(str, F_MAGAZZINO-FIRST_FIELD);
str=a.codmag().mid(3);
artrow.add(str, F_DEPOSITO-FIRST_FIELD);
}
TToken_string& artrow = sf.row(art_row);
const int lastbuck =_proposed_articles[new_row].last_bucket();
//TDate data_buck;
for (int bucket=0; bucket<=lastbuck ; bucket++)
{
int b= int((_proposed_articles[new_row].time(bucket).date() - get_date(F_DADATA))/days_per_bucket());
real art_per_buck(artrow.get(F_BUCKET1 + b*2 - FIRST_FIELD));
if (sign>0)
art_per_buck+=_proposed_articles[new_row].sched_receipts(bucket);
else
{
if (art_per_buck >= _proposed_articles[new_row].sched_receipts(bucket))
art_per_buck-=_proposed_articles[new_row].sched_receipts(bucket);
else
art_per_buck=ZERO;
}
artrow.add(art_per_buck.string(), F_BUCKET1 + b*2 - FIRST_FIELD);
real price;
if (!art_per_buck.is_zero())
find_price(get(F_TIPOCV),get(F_CODCONDV),get(F_CATVEN_CV),
get(F_TIPOCF), a.codcli(), a.codice(),
art_per_buck, price);
artrow.add(price.string(), F_BUCKET1 + b*2 + 1 - FIRST_FIELD);
}
test_art_row(art_row,FALSE);
}
sf.force_update();
}
// compatta le linee togliendo i doppioni
void TMSP_mask::pack_article_sheet()
{
TSheet_field& sf = sfield(F_ARTICOLI);
TToken_string lastrow;
for (int art_row=int(sf.items())-1; art_row >=0; art_row--)
{
if (!sf.cell_disabled(art_row, F_BUCKET1-FIRST_FIELD))
{
TToken_string &row=sf.row(art_row);
long codcli = atol(row.get(F_CLIENTE-FIRST_FIELD));
TCodice_articolo codart = row.get(F_ARTICOLO-FIRST_FIELD);
TString16 codimp= row.get(F_CODIMP-FIRST_FIELD);
TString16 codlin= row.get(F_CODLIN-FIRST_FIELD);
TString16 liv;
_livelli.pack_grpcode(liv, row.get(sf.cid2index(F_LIV1)),1);
_livelli.pack_grpcode(liv, row.get(sf.cid2index(F_LIV2)),2);
_livelli.pack_grpcode(liv, row.get(sf.cid2index(F_LIV3)),3);
_livelli.pack_grpcode(liv, row.get(sf.cid2index(F_LIV4)),4);
TString16 mag;
add_magcode(mag, row.get(F_MAGAZZINO-FIRST_FIELD));
add_depcode(mag, row.get(F_DEPOSITO-FIRST_FIELD));
for (int bucket=0; bucket<=LAST_BUCKET ; bucket++)
{
real art_per_buck(lastrow.get(F_BUCKET1 + bucket*2 - FIRST_FIELD));
row.add(art_per_buck.string(), F_BUCKET1 + bucket*2 - FIRST_FIELD);
}
}
}
sf.force_update();
}
void TMSP_mask::check_articles()
{
TSheet_field& sf = sfield(F_ARTICOLI);
int items=sf.items();
if (items==0)
{
message_box("Nessun articolo da verificare");
return;
}
TMSPCheck_mask cm(this);
cm.run();
cm.gopos_mainmask();
}
void TMSP_mask::check_capacities()
{
TSheet_field& sf = sfield(F_LINEE);
int items=sf.items();
if (items==0)
{
message_box("Nessun carico di linea da verificare");
return;
}
TCRPCheck_mask cm(this);
cm.run();
set_focus_field(sf.dlg());
sf.set_focus_cell(cm.last_row(),cm.last_col()+F_LBUCKET0);
}
bool TMSP_mask::sort_sheet()
{
TWait_cursor hg;
TSheet_field& a = sfield(F_ARTICOLI);
bool ok=TRUE;
switch (-get_int(F_MSP_SORT))
{
case SORT_BY_CAL:
a.sort(TRiga_articolo::order_compareCAL); break;
case SORT_BY_CLA:
a.sort(TRiga_articolo::order_compareCLA); break;
case SORT_BY_ACL:
a.sort(TRiga_articolo::order_compareACL); break;
case SORT_BY_ALC:
a.sort(TRiga_articolo::order_compareALC); break;
case SORT_BY_LCA:
a.sort(TRiga_articolo::order_compareLCA); break;
case SORT_BY_LAC:
a.sort(TRiga_articolo::order_compareLAC); break;
default:
return FALSE;
}
a.force_update();
return ok;
}
void TMSP_mask::add_MRP_bucket(TMRP_line& new_article, int nbucket, const real &curr_arts)
{
TDate data_buck;
data_buck=get_date(F_DADATA);
data_buck+=days_per_bucket()*(nbucket-1);
TMRP_time t(data_buck, 0, "", "");
new_article.add_sched_rec(t, curr_arts );
}
void TMSP_mask::propose_1stJIT(TMSP_logic logic, bool check_machine, bool check_human)
{
const bool useextralines=get_bool(F_USENONSTDLIN_MSP);
const bool useextrahours=get_bool(F_USEEXTRAHRS_MSP) ;
const bool lotsizing=get_bool(F_LOTSIZING) ;
const bool no_outcapacity=get_bool(F_OUTOFCAPACITY) ;
const int anticipomin=get_int(F_ANTICIPOMIN);
const int anticipomax=get_int(F_ANTICIPOMAX);
bool ok=TRUE;
// per sicurezza devo (ri-)calcolare il carico attuale.....
_capacities.destroy();
if (check_machine || check_human)
{
if (ok = load_MRP_lines(_actual_schedule))
{
nettify_MRP_lines(TRUE,FALSE);
ok = general_review(check_machine, check_human, useextralines, useextrahours,FALSE, no_outcapacity,0, 0,_actual_schedule, logic);
}
}
// (two) levels master scheduling
TMRP_lines _1stlevel;
bool some=FALSE;
for (int level=1; ok && level <= 2; level++)
{
if (ok = load_MRP_lines(_stock_break,level))
{
_proposed_articles.destroy();
nettify_MRP_lines(FALSE, lotsizing);
if (ok = general_review(check_machine, check_human, useextralines, useextrahours,lotsizing, no_outcapacity,anticipomin,anticipomax,_stock_break, logic))
some = insert_propose(some || level==2);
if (level==1)
_1stlevel=_proposed_articles;
if (level==2)
_proposed_articles.add(_1stlevel);
}
}
if (!ok)
remove_propose();
_capacities.sort();
}
/*
void TMSP_mask::propose_firstfit(bool check_machine, bool check_human)
{
const bool useextralines=get_bool(F_USENONSTDLIN_MSP);
const bool useextrahours=get_bool(F_USEEXTRAHRS_MSP) ;
const bool lotsizing=get_bool(F_LOTSIZING) ;
const bool no_outcapacity=get_bool(F_OUTOFCAPACITY) ;
const int anticipomin=get_int(F_ANTICIPOMIN);
const int anticipomax=get_int(F_ANTICIPOMAX);
bool ok=TRUE;
// per sicurezza devo (ri-)calcolare il carico attuale.....
_capacities.destroy();
if (check_machine || check_human)
{
if (ok = load_MRP_lines(_actual_schedule))
{
nettify_MRP_lines(TRUE,FALSE);
ok = firstfit_review(check_machine, check_human, useextralines, useextrahours,FALSE, no_outcapacity,0, 0,_actual_schedule);
}
}
// (two) levels master scheduling
TMrp_lines _1stlevel;
for (int level=1; level <= 2; level++)
{
if (ok && (ok = load_MRP_lines(_stock_break,level)))
{
nettify_MRP_lines(FALSE, lotsizing);
if (ok = firstfit_review(check_machine, check_human, useextralines, useextrahours,lotsizing, no_outcapacity,anticipomin,anticipomax,_stock_break))
{
insert_propose();
_1stlevel=_proposed_articles();
}
}
}
if (!ok)
remove_propose();
_capacities.sort();
}
// propone i valori con logica Just-in-time
void TMSP_mask::propose_JIT(bool check_machine, bool check_human)
{
const bool useextralines=get_bool(F_USENONSTDLIN_MSP);
const bool useextrahours=get_bool(F_USEEXTRAHRS_MSP) ;
const bool lotsizing=get_bool(F_LOTSIZING) ;
const bool no_outcapacity=get_bool(F_OUTOFCAPACITY) ;
const int anticipomin=get_int(F_ANTICIPOMIN);
const int anticipomax=get_int(F_ANTICIPOMAX);
bool ok=TRUE;
// per sicurezza devo (ri-)calcolare il carico attuale.....
_capacities.destroy();
if (check_machine || check_human)
{
if (ok = load_MRP_lines(_actual_schedule))
{
nettify_MRP_lines(TRUE, FALSE);
ok = JIT_review(check_machine, check_human, useextralines, useextrahours,FALSE, no_outcapacity,0, 0,_actual_schedule);
}
}
// (two) levels master scheduling
for (int level=1; level < 2; level++)
{
if (ok && (ok = load_MRP_lines(_stock_break, 1)))
{
nettify_MRP_lines(FALSE, lotsizing);
if (ok = JIT_review(check_machine, check_human, useextralines, useextrahours,FALSE, no_outcapacity,anticipomin,anticipomax,_stock_break))
insert_propose();
}
}
if (!ok)
remove_propose();
_capacities.sort();
}
bool TMSP_mask::firstfit_review(bool check_machine, bool check_human, bool useextralines, bool useextrahours,bool lotsizing, bool no_outcapacity, int anticipomin,int anticipomax, TMSP_mode mode)
{
return general_review(check_machine, check_human, useextralines, useextrahours,lotsizing, no_outcapacity, anticipomin,anticipomax, mode, _first_fit_logic);
}
bool TMSP_mask::JIT_review(bool check_machine, bool check_human, bool useextralines, bool useextrahours,bool lotsizing, bool no_outcapacity, int anticipomin,int anticipomax, TMSP_mode mode)
{
return general_review(check_machine, check_human, useextralines, useextrahours,lotsizing, no_outcapacity, anticipomin,anticipomax, mode, _JIT_logic);
}
*/
// propone i valori con logica first-fit
// cerca il primo bucket con capacit<69> produttiva
bool TMSP_mask::general_review(bool check_machine, bool check_human, bool useextralines, bool useextrahours,bool lotsizing, bool no_outcapacity, int anticipomin,int anticipomax, TMSP_mode mode, TMSP_logic logic )
{
const bool ignore_mag=get_bool(F_NOMAG_IN);
const bool ignore_imp=get_bool(F_NOIMP_IN);
const bool ignore_lin=get_bool(F_NOLIN_IN);
TLavorazione *curr_labor;
TLinea_prod linea_prod;
TArray labors;
const long max_mrp_rows=_mrp_articles.items();
const char *msg;
if (mode == _actual_schedule)
msg="Calcolo carico attuale";
else
msg="Calcolo nuove proposte";
TProgind pi(max_mrp_rows,msg, 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=_mrp_articles[mrp_row];
TString16 livello_di_giacenza(mrpline.livgiac());
TString16 codlin(mrpline.codlin());
TString16 codimp(mrpline.codimp());
bool no_labor=!_dist_tree.set_root(mrpline.codice());
if (!no_labor)
{
TDate data_buck;
// la logica del ciclo sulle lav e' da invertire: prima il bucket , poi le lavorazioni
// se si vogliono caricare pi<70> lavorazioni
TRiga_esplosione * l=_dist_tree.first_critical_labor(labors);
no_labor=(l==NULL);
if (!no_labor)
{
curr_labor=TDistinta_tree::find_labor(l);
// cerca le linee sulle quali e' possibile eseguire questa lavorazione
// e la carica con la lavorazione relativa all'articolo corrente
const int lineestd = curr_labor->linee_standard();
const int maxlinee = useextralines ? curr_labor->linee() : lineestd;
TCRP_line *crpline,*crpline_imp,*crpline_firm;
const int lastbuck =mrpline.last_bucket();
for (int bucket=0; bucket<=lastbuck ; bucket++)
{
real curr_arts, art_per_buck(mrpline.net_requirement(bucket)); // quantit<69> da produrre nel bucket
real load, capacity, unit_load, hload, hcapacity, unit_hload ; // carichi di linea
int nbucket, lower_buck, upper_buck;
int attemp=1; // primo tentativo: rimane entro i vincoli di minimo e massimo anticipo utilizando solo le linee STD
// secondo tentativo: rimane entro i vincoli di minimo e massimo anticipo utilizando anche le linee non STD
// terzo tentativo: supera i vincoli di minimo e massimo anticipo utilizando anche le linee non STD
art_per_buck.round(5);
while (art_per_buck > ZERO && attemp <= 3)
{
if (logic == _first_fit_logic)
{
lower_buck = bucket - anticipomax/days_per_bucket();
upper_buck = (attemp <= 2 ? bucket-anticipomin/days_per_bucket(): LAST_BUCKET);
nbucket=lower_buck;
} else {
lower_buck = (attemp <= 2 ? bucket-anticipomax/days_per_bucket(): 0);
upper_buck = bucket - anticipomin/days_per_bucket();
nbucket=upper_buck;
}
if (lower_buck<1)
lower_buck=1;
if (nbucket<1)
nbucket=1;
do {
int nlinea, numlinee;
if (ignore_lin || codlin.blank() )
{
nlinea=(attemp == 2 ? lineestd : 0 ) ;
numlinee=(attemp == 1 ? lineestd : maxlinee ) ;
} else {
nlinea= curr_labor->find_linea(codlin);
if (nlinea<0)
{
error_box("La linea %s non e' in grado di produrre l'articolo %s", (const char * )codlin, (const char *) _mrp_articles[mrp_row].codice());
break;
}
numlinee=nlinea+1;
}
while (art_per_buck > ZERO && nlinea >= 0 && nlinea<numlinee)
{
// scelgo la linea
linea_prod= cache().get("LNP",curr_labor->cod_linea(nlinea));
if ( ignore_imp || codimp.blank() || codimp == linea_prod.codimp())
{
crpline=_capacities.find(linea_prod);
if (crpline==NULL)
crpline=compute_capacity(linea_prod,useextralines, useextrahours);
crpline_imp =_capacities.find(linea_prod.codimp());
crpline_firm=_capacities.find();
int human_level=1;
if ( linea_prod.personale_dedicato())
human_level=3;
else if (linea_prod.get_impianto()->personale_dedicato())
human_level=2;
// individua il massimo caricabile sulla linea
unit_load = l->val()*curr_labor->um_temporale().converti_in_ore()/curr_labor->produttiv_linea(nlinea);
unit_hload=unit_load*curr_labor->numpers_linea(nlinea);
capacity = check_machine ? crpline->capacity(nbucket) : MAXCAPACITY;
load = crpline->load(nbucket);
switch (human_level)
{
case 3:
hcapacity = crpline->human_capacity(nbucket) ;
hload = crpline->human_load(nbucket);
break;
case 2:
hcapacity = crpline_imp->human_capacity(nbucket) ;
hload = crpline_imp->human_load(nbucket);
break;
default:
hcapacity = crpline_firm->human_capacity(nbucket) ;
hload = crpline_firm->human_load(nbucket);
break;
}
// ridimensiona al massimo numero di articoli dovuto alle macchine
curr_arts = art_per_buck ;
if (mode != _actual_schedule /*|| no_outcapacity*/)
{
if (load + curr_arts * unit_load > capacity )
{
curr_arts = (capacity - load ) / unit_load;
curr_arts.floor();
}
// ridimensiona al massimo numero di articoli dovuto alle macchine
if (check_human && hload + curr_arts * unit_hload > hcapacity)
{
curr_arts = (hcapacity - hload) / unit_hload;
curr_arts.floor();
}
/*
// elimina i picchi di capacita' (errato)
if (curr_arts != art_per_buck && mode == _actual_schedule)
{
TMRP_line* new_article = _proposed_articles.find(mrpline.codice(),
mrpline.livgiac(), mrpline.codmag(),
linea_prod.codimp() , linea_prod.codice(), mrpline.codcli(), TRUE);
add_MRP_bucket(*new_article, nbucket, curr_arts-art_per_buck );
}*/
}
if (curr_arts>ZERO)
{
// aggiunge il carico macchina
art_per_buck-=curr_arts;
load= curr_arts * unit_load;
crpline->add_load(nbucket, load );
// aggiunge il carico uomo
load*=curr_labor->numpers_linea(nlinea);
switch (human_level)
{
case 3:
crpline->add_human_load(nbucket, load );
case 2:
crpline_imp->add_human_load(nbucket, load );
default:
crpline_firm->add_human_load(nbucket, load );
}
if (mode == _stock_break)
{
TMRP_line* new_article = find_propose(mrpline.codcli(), mrpline.codice(),
mrpline.livgiac(), linea_prod.codimp() , linea_prod.codice(), mrpline.codmag(), TRUE);
add_MRP_bucket(*new_article, nbucket, curr_arts);
}
}
} else
error_box("Articolo %s: impianto %s incompatibile con la linea %s",(const char *)mrpline.codice(), (const char *)codimp, (const char *)linea_prod.codice());
nlinea++;
} // ciclo sulle linee
if (logic == _first_fit_logic)
nbucket++;
else
nbucket--;
} while(art_per_buck > ZERO && nbucket>=lower_buck && nbucket <= upper_buck );
attemp++; // altro tentativo
}
}
l=_dist_tree.next_critical_labor(labors);
}
}
if (no_labor) // nessuna lavorazione da controllare o capacita' infinita
{
if (mode == _stock_break)
{
const int lastbuck =mrpline.last_bucket();
for (int b=0; b<=lastbuck ; b++)
{
real art_per_buck(mrpline. net_requirement(b));// quantit<69> da produrre nel bucket
if (art_per_buck > ZERO)
{
int nbucket;
if (logic == _first_fit_logic)
nbucket = b - anticipomax/days_per_bucket();
else
nbucket = b - anticipomin/days_per_bucket();
if (nbucket<1)
nbucket=1;
TMRP_line* new_article = find_propose(mrpline.codcli(), mrpline.codice(), mrpline.livgiac(),
mrpline.codimp() , mrpline.codlin(), mrpline.codmag(), TRUE);
add_MRP_bucket(*new_article, nbucket, art_per_buck);
}
}
}
}
}
return TRUE;
}
bool TMSP_mask::capacity_review(bool useextralines, bool useextrahours)
{
bool ok;
if (!load_MRP_lines(_actual_schedule))
return FALSE;
nettify_MRP_lines(TRUE);
_capacities.destroy();
if (get(F_RECALC_TYPE).left(1)=="1")
ok = general_review(TRUE, TRUE, useextralines, useextrahours, FALSE, FALSE, 0, 0, _actual_schedule,_first_fit_logic);
else if (get(F_RECALC_TYPE).left(3)=="JIT")
ok = general_review(TRUE, TRUE, useextralines, useextrahours, FALSE, FALSE, 0, 0, _actual_schedule,_first_fit_logic);
_capacities.sort();
return ok;
}
TCRP_line *TMSP_mask::compute_capacity(TLinea_prod &lineaprod, bool useextralines, bool useextrahours)
{
TMRP_calendar & cal = TMRP_time::get_calendar("", lineaprod.codice());
TMRP_calendar & cal_imp = TMRP_time::get_calendar("", lineaprod.codimp());
TMRP_calendar & cal_firm = TMRP_time::get_calendar("");
CHECK(_capacities.find(lineaprod,FALSE)==NULL,"Errore: impossibile ricalcolare la capacita' di una linea produttiva");
TCRP_line *crpline,*crpline_imp,*crpline_firm;
crpline =_capacities.find(lineaprod, "", 0L,TRUE);
const bool compute_imp = (_capacities.find(lineaprod.codimp(), "", "", 0L)==NULL);
crpline_imp =_capacities.find(lineaprod.codimp(), "", "", 0L, TRUE);
const bool compute_firm = (_capacities.find("", "", "", 0L)==NULL);
crpline_firm=_capacities.find("", "", "", 0L, TRUE);
// calcola la capacita'
TDate data_buck=get_date(F_DADATA);
real capacity,human,human_imp,human_firm;
for (int b=1; b<LAST_BUCKET ; b++)
{
capacity=ZERO;
human=ZERO;
human_imp=ZERO;
human_firm=ZERO;
for (int day=days_per_bucket()-1; day>=0 ; day--)
{
cal.add_oremacchina(capacity, data_buck,useextrahours);
if (lineaprod.personale_dedicato())
cal.add_oreuomo(human, data_buck,useextrahours);
if (compute_imp && lineaprod.get_impianto()->personale_dedicato())
cal_imp.add_oreuomo(human_imp, data_buck,useextrahours);
if (compute_firm)
cal_firm.add_oreuomo(human_firm, data_buck,useextrahours);
++data_buck;
}
crpline->set_capacity(b,capacity);
if (human > ZERO)
{
crpline->set_human_capacity(b,human);
crpline_imp->set_human_capacity(b,human+crpline_imp->human_capacity(b));
crpline_firm->set_human_capacity(b,human+crpline_firm->human_capacity(b));
}
else
crpline->set_human_capacity(b,ZERO);
if (human_imp > ZERO)
{
crpline_imp->set_human_capacity(b,human_imp+crpline_imp->human_capacity(b));
crpline_firm->set_human_capacity(b,human_imp+crpline_firm->human_capacity(b));
}
else
crpline_imp->set_human_capacity(b,ZERO);
if (human_firm > ZERO)
crpline_firm->set_human_capacity(b,human_firm+crpline_firm->human_capacity(b));
}
return crpline;
}
TMRP_line* TMSP_mask::find_propose(
long codcli, const char * codart,const char * liv,
const char * codimp,const char * codlin,
const char * mag, bool Force)
{
return _proposed_articles.find(codart,liv,mag,codimp,codlin,codcli, Force);
}
// carica le MRP line dallo sheet articoli
void TMSP_mask::msprow2codes(TToken_string &row,long &clifor, TCodice_articolo &art ,
TString & liv, TString & mag, TString & imp, TString & lin, TString & um)
{
clifor = row.get_long(F_CLIENTE-FIRST_FIELD);
art = row.get(F_ARTICOLO-FIRST_FIELD);
_livelli.pack_grpcode(liv, row.get(F_LIV1-FIRST_FIELD),1);
_livelli.pack_grpcode(liv, row.get(F_LIV2-FIRST_FIELD),2);
_livelli.pack_grpcode(liv, row.get(F_LIV3-FIRST_FIELD),3);
_livelli.pack_grpcode(liv, row.get(F_LIV4-FIRST_FIELD),4);
add_magcode(mag,row.get(F_MAGAZZINO-FIRST_FIELD));
add_depcode(mag,row.get(F_DEPOSITO-FIRST_FIELD));
imp = row.get(F_CODIMP-FIRST_FIELD); imp.trim();
lin = row.get(F_CODLIN-FIRST_FIELD); lin.trim();
um = row.get(F_UM-FIRST_FIELD); um.trim();
}
void TMSP_mask::crprow2codes(TToken_string &row, TString & imp, TString & lin, long &clifor, TCodice_articolo &art ,
TString & liv, TString & um)
{
clifor=0L;//clifor = row.get_long(F_CLIENTE-FIRST_FIELD);
//art = row.get(F_ARTICOLO-FIRST_FIELD);
//_livelli.pack_grpcode(liv, row.get(F_LIV1-FIRST_FIELD),1);
//_livelli.pack_grpcode(liv, row.get(F_LIV2-FIRST_FIELD),2);
//_livelli.pack_grpcode(liv, row.get(F_LIV3-FIRST_FIELD),3);
//_livelli.pack_grpcode(liv, row.get(F_LIV4-FIRST_FIELD),4);
imp = row.get(F_CODIMPCRP-FIRST_FIELD); imp.trim();
lin = row.get(F_CODLINCRP-FIRST_FIELD); lin.trim();
um = row.get(F_LUM-FIRST_FIELD); um.trim();
}
// carica le MRP line dallo sheet articoli
bool TMSP_mask::load_MRP_lines(TMSP_mode mode, int level)
{
TSheet_field& sa = sfield(F_ARTICOLI);
if (sa.items()==0)
{
message_box("Nessun articolo da valutare");
return FALSE;
}
const int a_buck0 = sa.cid2index(F_BUCKET0);
TDate data_buck;
_mrp_articles.destroy();
// calcola gli impegni di produzione per gli articoli dello sheet
bool skip=FALSE;
TMRP_line* last_constraint = NULL;
FOR_EACH_SHEET_ROW(sa, r, row) if (!sa.cell_disabled(r, a_buck0+2) || sa.cell_disabled(r+1, a_buck0+2))
{
const bool is_constraint=sa.cell_disabled(r, a_buck0+2);
if (is_constraint)
{
const bool has_mastercodes=(*row->get(F_MASTERCODE-FIRST_FIELD)=='M');
skip = (level == 1 && !has_mastercodes || level == 2 && has_mastercodes );
}
if (!skip)
{
long clifor;
TCodice_articolo art ;
TString16 liv,mag, imp, lin;
TCodice_um um ;
msprow2codes(*row,clifor, art , liv, mag, imp, lin, um);
TMRP_line* curr_article = _mrp_articles.find(art, liv, mag, imp, lin, clifor ,TRUE);
if (is_constraint)
last_constraint=curr_article;
bool added_some=FALSE;
for (int nbucket=LAST_BUCKET-1; nbucket>=0 ; nbucket--)
{
data_buck=get_date(F_DADATA);
data_buck+=days_per_bucket()*nbucket;
const TMRP_time t(data_buck, 0, imp, lin);
real qta=row->get(a_buck0+nbucket*2);
if (qta != ZERO)
{
TQuantita q(art, um, qta);
q.convert2umbase();
// mette i vincoli nel gross req
// e le celle normali negli sched receipts
switch (mode)
{
case _actual_schedule:
if (!is_constraint)
{
curr_article->add_gross_req(t, q.val());
curr_article->add_sched_rec(t, q.val());
}
break;
case _stock_break:
if (is_constraint)
{
curr_article->add_gross_req(t, q.val());
last_constraint=curr_article;
} else {
if (last_constraint)
last_constraint->add_sched_rec(t, q.val());
}
break;
}
added_some=TRUE;
} else
if (added_some)
curr_article->set_on_hand(t, ZERO);
if (nbucket == 0)
curr_article->set_on_hand(t, curr_article->giacenza_attuale(qta,data_buck));
}
}
}
return TRUE;
}
// is_net_requirement: dice se le quantit<69> presenti sono da considerare gia' come net req o
// se devo prenderle come scheduled rec e il net req lo devo calcolare di conseguenza
bool TMSP_mask::nettify_MRP_lines(bool already_net, bool lotsizing)
{
// ***********
// gross 2 net
const long max_mrp_rows=_mrp_articles.items();
for (long mrp_row=0; mrp_row < max_mrp_rows; mrp_row++)
{
// calcola il fabbisogno netto e lo riporta sul bucket seguente
TMRP_line & mrp_line = _mrp_articles[mrp_row];
const int last = mrp_line.last_bucket();
for (int bucket = 0; bucket <= last; bucket = mrp_line.next_bucket(bucket))
{
real netreq,giacres;
if (already_net)
{
// generazione del master schedule plan; le quantit<69> sono da considerare nette
netreq= mrp_line.sched_receipts(bucket);
giacres=0;
mrp_line.set_net_req(bucket, netreq );
} else {
// generazione delle pianificazioni (commesse, Master Production Plan (non per famiglie), prove di budget ecc)
giacres = mrp_line.on_hand(bucket);
giacres += mrp_line.sched_receipts(bucket);
giacres -= mrp_line.gross_requirement(bucket);
if (lotsizing)
netreq = mrp_line.sizeup_net_requirement(bucket, giacres);
else
{
netreq = -giacres;
netreq = mrp_line.set_net_req(bucket, netreq);
}
giacres += netreq;
}
if (giacres > ZERO)
{
const int nb = mrp_line.next_bucket(bucket);
if (nb <= mrp_line.last_bucket())
mrp_line.set_on_hand(nb, giacres);
}
}
}
return max_mrp_rows>0;
}
int TMSP_mask::days_per_bucket() const
{
return get_int(F_DAYXBUCK) * (get_int(F_BUCKETS) ? get_int(F_BUCKETS) : get_int(F_BUCKET));
}
void TMSP_mask::clear_sheets()
{
TSheet_field &sa=sfield(F_ARTICOLI);
if (sa.items()>0)
{
sa.destroy();
sa.force_update();
}
TSheet_field &sl=sfield(F_LINEE);
if (sl.items()>0)
{
sl.destroy();
sl.force_update();
}
// sfield(F_TESTE).destroy();
// sfield(F_TESTE).force_update();
xvt_statbar_set("");
}
// **********
// imposta il bucket 0 ; se i flag sulla maschera sono settati,
// - sulla riga delle giacenze progressive : somma la giacenza iniziale
// - sulla riga dell'ordinato progressivo => sottrae la giacenza iniziale
// **********
// valore di ritorno:restituisce l'ultima linea dello sheet processata
int TMSP_mask::init_bucket0(TArticolo_giacenza &art, int r)
{
TSheet_field& sf = sfield(F_ARTICOLI);
const bool add_giac=get_bool(F_MSCHEDULEPLAN);// nettifica la giacenza
// Calcola l'indice c della riga con la giacenza prog
const int b0 = sf.cid2index(F_BUCKET0);
const int b1 = sf.cid2index(F_BUCKET1);
real planned;
for (int c = r; c > 1; c--)
{
if (sf.cell_disabled(c, b1))
break;
planned += real(sf.cell(c, b0));
}
TToken_string &giac_row=sf.row(c);
TToken_string &ord_row=sf.row(c-1);
// calcola codice di magazzino e di livello
TString16 livello;
_livelli.pack_grpcode(livello, giac_row.get(sf.cid2index(F_LIV1)),1);
_livelli.pack_grpcode(livello, giac_row.get(sf.cid2index(F_LIV2)),2);
_livelli.pack_grpcode(livello, giac_row.get(sf.cid2index(F_LIV3)),3);
_livelli.pack_grpcode(livello, giac_row.get(sf.cid2index(F_LIV4)),4);
TString16 codmag;
add_magcode(codmag, giac_row.get(sf.cid2index(F_MAGAZZINO)));
add_depcode(codmag, giac_row.get(sf.cid2index(F_DEPOSITO)));
// calcola i bucket 0
TQuantita prog_giac(art.codice(),giac_row.get(sf.cid2index(F_UM)),planned);
real giac=art.giacenza_anno(codmag, livello, get_date(F_DADATA).year());
if (add_giac)
prog_giac +=giac;
prog_giac += giac_row.get(b0);
giac_row.add(prog_giac.val().string(), b0);
do_test_art_row(r,c,FALSE);
return c-2;
}
bool TMSP_mask::do_test_art_row(int r, int c, bool signal)
{
TSheet_field& sf = sfield(F_ARTICOLI);
TMask & smask= sf.sheet_mask();
TToken_string & curr_row=sf.row(r);
TToken_string & constr_row=sf.row(c-1);
TToken_string & giac_row=sf.row(c);
TCodice_articolo codart(curr_row.get(sf.cid2index(F_ARTICOLO)));
const int b0 = sf.cid2index(F_BUCKET0);
// calcola la giacenza proiettata
TQuantita vincolo(codart,giac_row.get(sf.cid2index(F_UM)),ZERO);
TQuantita totale(vincolo),qta(vincolo);
totale += real(sf.cell(c, b0));// giacenza iniziale
for (int b = 1; b < LAST_BUCKET; b++)
{
vincolo.set_val(real(sf.cell(c-1, b0+b*2)));
for (int i = c+1; i <= r; i++)
{
totale += real(sf.cell(i, b0+b*2)); // somma alla giacenza le produzioni
}
totale -= real(sf.cell(c-1, b0+b*2)); // detrae le uscite
giac_row.add(totale.val().string(), b0+b*2);
if (signal && totale.val() < 0)
{
TString err;
const int bucket_size = days_per_bucket();
const TDate d = get_date(F_DADATA) + long(bucket_size * (b-1));
err << "Riga " << c+1 << ": Vincolo non ripettato al " << d;
beep();
signal =FALSE;
xvt_statbar_set(err);
}
}
sf.force_update(c);
if (signal) xvt_statbar_set("");
if (constr_row.get_char(sf.cid2index(F_MASTERCODE))=='M')
{
// aggancia i master di 2' livello
TString16 liv;
_livelli.pack_grpcode(liv, curr_row.get(sf.cid2index(F_LIV1)),1);
_livelli.pack_grpcode(liv, curr_row.get(sf.cid2index(F_LIV2)),2);
_livelli.pack_grpcode(liv, curr_row.get(sf.cid2index(F_LIV3)),3);
_livelli.pack_grpcode(liv, curr_row.get(sf.cid2index(F_LIV4)),4);
TString16 imp(curr_row.get(sf.cid2index(F_CODIMP)));//imp.trim();
TString16 lin(curr_row.get(sf.cid2index(F_CODLIN)));//lin.trim();
TString16 mag;
add_magcode(mag, curr_row.get(sf.cid2index(F_MAGAZZINO)));
add_depcode(mag, curr_row.get(sf.cid2index(F_DEPOSITO)));
TMSP_line mspline(curr_row.get_long(F_CLIENTE-FIRST_FIELD), codart, liv, imp, lin, mag);
TMSP_constraint*currconstr=find_constraint(mspline);
CHECK (currconstr, "Impossibile trovare il vincolo dell'articolo di 1' livello");
int i=0;
TMaster_code *mc;
while ((mc=currconstr->get_mastercode(i++))!=NULL)
{
TMSP_constraint* line_master=_constraints.find(currconstr->cliente(),mc->articolo()
, mc->livello(), mc->codimp(), mc->codlin(), mc->codmag());
CHECK (line_master, "Impossibile trovare il vincolo dell'articolo di 2' livello");
CHECK (line_master->has_upperlines(), "La linea master non risulta avere dipendenze di alcun tipo");
int mrow= find_constr_row(*line_master);
real q2make(giac_row.get(sf.cid2index(F_BUCKET0)));
for (int b = 1; b <= LAST_BUCKET; b++)
{
const int b2=b-int(long(mc->leadtime()/days_per_bucket()+0.5));
if (b2>=0)
{
q2make=real(giac_row.get(sf.cid2index(F_BUCKET0+b*2)))+
real(constr_row.get(sf.cid2index(F_BUCKET0+b*2)))-
real(giac_row.get(sf.cid2index(F_BUCKET0+b*2-2)));
if (q2make > ZERO)
q2make = (q2make)*mc->expr();
else
q2make = ZERO;
TMSP_constraint* upperline=line_master->get_upperline(*currconstr);
real oldq2make=upperline->qta(b2);
real totale2make=line_master->qta(b2);
line_master->qta(b2) = line_master->qta(b2) - upperline->qta(b2) + q2make;
upperline->qta(b2) = q2make;
TToken_string &master_row=sf.row(mrow);
master_row.add(line_master->qta(b2).string(),sf.cid2index(F_BUCKET0+b2*2));
}
}
sf.force_update(mrow);
int first,last;
TRiga_articolo::find_block(sf, mrow+2, first, last);
do_test_art_row(last, first, signal);
}
}
return c-2;
}
bool TMSP_mask::test_art_row(int r, bool signal)
{
TSheet_field& sf = sfield(F_ARTICOLI);
int c;
if (!TRiga_articolo::find_block(sf, r, c, r))
return TRUE;
else
{
TToken_string & curr_row=sf.row(r);
TToken_string & constr_row=sf.row(c-1);
// setta la priorita' su tutte le righe del blocco
const int prior =curr_row.get_int(sf.cid2index(F_PRIORITA));
const int old_prior=constr_row.get_int(sf.cid2index(F_PRIORITA));
if (old_prior != prior)
{
for (int i = c-1; i<=r; i++)
{
sf.row( i ).add(prior , sf.cid2index(F_PRIORITA));
sf.force_update(i);
}
}
}
return do_test_art_row(r, c, signal);
}
bool TMSP_mask::test_load_row(int r, bool signal)
{
TSheet_field& sf = sfield(F_LINEE);
const int narticoli=sf.items();
if (narticoli<=r)
return TRUE;
// Calcola l'indice c della riga con la capacita'
const int b0 = sf.cid2index(F_LBUCKET0);
const int b1 = sf.cid2index(F_LBUCKET1);
for (int c = r; c > 0; c--)
{
if (sf.cell_disabled(c, b1))
break;
}
// Calcola l'indice r della riga totale di linea
if (r == c) r++;
TToken_string &row=sf.row(c);
real capacita, carico;
for (int b = 1; b < LAST_BUCKET; b++)
{
capacita=real(sf.cell(c, b0+b*2));
carico=real(sf.cell(r, b0+b*2));
if (signal && capacita < carico)
{
TString err;
const int bucket_size = days_per_bucket();
const TDate d = get_date(F_DADATA) + long(bucket_size * (b-1));
err << "Riga " << c+1 << ": capacita' superata al " << d;
beep();
signal =FALSE;
xvt_statbar_set(err);
}
}
if (signal) xvt_statbar_set("");
return signal;
}
void TMSP_mask::salva_documenti()
{
TSheet_field& sf = sfield(F_ARTICOLI);
const int b0 = sf.cid2index(F_BUCKET0);
const int b1 = sf.cid2index(F_BUCKET1);
const int um = sf.cid2index(F_UM);
const TDate date_to = get(F_ADATA);
TPlan_docs doc_rows(get(F_NUM_PLAN), get(F_TIPO_PLAN), get(F_RIGA_PLAN));
const TDate from = get(F_DADATA);
const int bucket_size = days_per_bucket();
const bool number_by_cli = get_bool(F_NUMBERBYCLI);
for (int b = 1; b < LAST_BUCKET; b++)
{
const TDate data = from + long(bucket_size * (b-1));
if (data > date_to)
break;
const int anno = data.year();
FOR_EACH_SHEET_ROW(sf, r, row) if (!sf.cell_disabled(r, b1))
{
TMSP_line& line = *_articles.find(*row, _livelli, TRUE);
const real& old = line.qta(b);
const real val = row->get(b0 + b*2);
if ((get(F_DA_MAGAZZ).empty() || line.codmag() >= get(F_DA_MAGAZZ)) &&
(get(F_A_MAGAZZ).empty() || line.codmag() <= get(F_A_MAGAZZ)) &&
(get(F_DA_IMPIANTO).empty() || line.codimp() >= get(F_DA_IMPIANTO)) &&
(get(F_A_IMPIANTO).empty() || line.codimp() <= get(F_A_IMPIANTO)))
{
if (old != val)
{
long numdoc = 0L;
int numrig = 0;
if (!line.riga(b, numdoc, numrig))
{
if (number_by_cli)
numdoc = line.cliente() * 100L;
numdoc += data.week();
}
const real incr = val-old;
TRiga_documento& riga = doc_rows.add_to_row(anno, numdoc, numrig, incr);
if (riga.get(RDOC_CODART).empty())
{
riga.put(RDOC_CODART, line.codice());
riga.put(RDOC_CODARTMAG, line.codice());
riga.put(RDOC_LIVELLO, line.livgiac());
riga.put(RDOC_CHECKED, "X");
riga.put(RDOC_CODMAG, line.codmag());
riga.put(RDOC_LINEA, line.codlin());
riga.put(RDOC_IMPIANTO, line.codimp());
riga.put(RDOC_UMQTA, row->get(sf.cid2index(F_UM)));
riga.put(RDOC_DATACONS, data);
riga.put(RDOC_DESCR, row->get(sf.cid2index(F_DESCART)));
TRectype& doc = (TRectype&)riga.doc().head();
if (doc.get(DOC_DATACONS).empty())
{
doc.put(DOC_DATACONS, data);
doc.put(DOC_TIPOCF, "C");
doc.put(DOC_CODCF, line.cliente());
}
doc.put(DOC_DATADOC, from);
}
}
}
}
doc_rows.flush(data);
}
}
// copia i dati della riga al di fuori delle informazioni dei bucket
void TMSP_mask::copy_sheet_row(TToken_string & newrow, const TToken_string & row)
{
const TSheet_field& sf = sfield(F_ARTICOLI);
const int b0 = sf.cid2index(F_BUCKET0);
TString str;
for (int i = 0; i < b0; i++)
{
row.get(i, str);
newrow.add(str, i);
}
}
bool TMSP_mask::on_field_event(TOperable_field& o, TField_event e, long jolly)
{
const char * confirm_msg="Le attuali %d linee di articoli verranno perse. Confermi?";
switch (o.dlg())
{
case F_DADATA:
if (e == fe_modify)
round_field(o, FALSE);
break;
case F_ADATA:
if (e == fe_modify)
round_field(o, TRUE);
break;
case F_BUCKET:
if (e == fe_modify)
{
round_field(field(F_DADATA), FALSE);
round_field(field(F_ADATA), TRUE);
}
break;
case F_YEAR:
case F_IMPIANTO:
case F_LINEA:
if (e == fe_modify || (o.dlg() == F_YEAR && e == fe_init ))
update_calendar(F_CALENDAR, F_YEAR, F_IMPIANTO, F_LINEA);
break;
case F_TIPI_ORC:
case F_TIPI_PLA:
if (e == fe_init)
{
TSheet_field& s = (TSheet_field&)o;
if (s.items() == 0)
{
s.row(0);
s.force_update();
}
}
if (e == fe_close)
{
const TSheet_field& s = (const TSheet_field&)o;
FOR_EACH_SHEET_ROW_BACK(s, r, row)
if (!row->empty_items())
{
bool ok;
if (o.dlg()==F_TIPI_PLA)
ok=test_tipodoc_num(sfield(F_NUM_PLA), s );
else
ok=test_tipodoc_num(sfield(F_NUM_ORC), s );
return ok;
}
return error_box("E' necessario inserire almeno una riga");
}
break;
case F_NUM_PLAN:
if (e == fe_close)
{
const TSheet_field& s = sfield(F_NUM_PLA);
FOR_EACH_SHEET_ROW_BACK(s, r, row)
if (o.get() == row->get(s.cid2index(F_NUMERAZ))) return TRUE;
return error_box("Numerazione non inclusa tra quelle di planning");
}
break;
case F_TIPO_PLAN:
if (e == fe_close)
{
const TSheet_field& s = sfield(F_TIPI_PLA);
FOR_EACH_SHEET_ROW_BACK(s, r, row)
if (o.get() == row->get(s.cid2index(F_TIPO))) return TRUE;
return error_box("Tipo documento non incluso tra quelli di planning");
}
break;
case F_ARTICOLI:
{
TSheet_field& s = (TSheet_field&)o;
switch(e)
{
case se_query_add:
return jolly > 1 && s.items() > 0;
case se_notify_add:
if (jolly > 0)
{
const TToken_string& prev = s.row(int(jolly-1));
TToken_string& curr = s.row(int(jolly));
copy_sheet_row(curr,prev);
}
break;
case se_leave:
test_art_row((int)jolly);
break;
default:
break;
}
}
break;
case F_MSP_RESORT:
if (e==fe_button)
sort_sheet();
break;
case F_LINEE:
{
TSheet_field& s = (TSheet_field&)o;
switch(e)
{
case se_query_add:
return FALSE;
case se_leave:
test_load_row((int)jolly);
break;
}
}
break;
case F_CRP_RESORT:
break;
case F_BUCKET1:
case F_BUCKET2:
case F_BUCKET3:
case F_BUCKET4:
case F_BUCKET5:
case F_BUCKET6:
case F_BUCKET7:
case F_BUCKET8:
case F_BUCKET9:
case F_BUCKET10:
case F_BUCKET11:
case F_BUCKET12:
if (e == fe_modify)
{
const TSheet_field& s = sfield(F_ARTICOLI);
TMask & m=s.sheet_mask();
TMask_field &fprice=m.field(o.dlg()+1);
real qta(o.get());
real price(fprice.get());
if (!qta.is_zero() && price.is_zero())
find_price(get(F_TIPOCV),get(F_CODCONDV),get(F_CATVEN_CV),
m.get(F_TIPOCF_SHEET), m.get_long(F_CLIENTE), m.get(F_ARTICOLO),
qta , price);
fprice.set(price.string());
}
case DLG_CANCEL:
if (e == fe_button)
if (jolly == 0L)
{
TSheet_field& s = sfield(F_ARTICOLI);
int lineeart=s.items();
if (lineeart==0 || yesno_box(confirm_msg,lineeart))
{
enable(-1);
clear_sheets();
} else
return FALSE;
}
break;
case DLG_ELABORA:
if (e == fe_button && check_fields())
{
TSheet_field& s = sfield(F_ARTICOLI);
int lineeart=s.items();
if (lineeart==0 || yesno_box(confirm_msg,lineeart))
{
clear_sheets();
if (carica_documenti())
{
fill_sheet();
enable(DLG_SAVEREC, s.items() > 0);
enable(-1, s.items() == 0);
s.set_focus();
on_field_event((TOperable_field&)field(F_SHOWPRICES), fe_modify, jolly );
on_field_event((TOperable_field&)field(F_MSP_SORT), fe_init, jolly );
}
}
}
break;
case F_CANCEL_MSP:
if (e == fe_button)
{
remove_propose(TRUE);
}
break;
case F_RECALC_MSP:
if (e == fe_button && check_fields())
{
remove_propose();
const bool useextralines=get_bool(F_USENONSTDLIN_MSP);
const bool useextrahours=get_bool(F_USEEXTRAHRS_MSP) ;
set(F_USENONSTDLIN_CRP ,useextralines ? "X" : "");
set(F_USEEXTRAHRS_CRP ,useextrahours ? "X" : "");
if (get(F_RECALC_TYPE)=="1")
propose_1stJIT(_first_fit_logic,TRUE,TRUE);
else if (get(F_RECALC_TYPE)=="1_INFH")
propose_1stJIT(_first_fit_logic,TRUE,FALSE);
else if (get(F_RECALC_TYPE)=="1_INF")
propose_1stJIT(_first_fit_logic,FALSE,FALSE);
else if (get(F_RECALC_TYPE)=="JIT")
propose_1stJIT(_JIT_logic,TRUE,TRUE);
else if (get(F_RECALC_TYPE)=="JIT_INFH")
propose_1stJIT(_JIT_logic,TRUE,FALSE);
else if (get(F_RECALC_TYPE)=="JIT_INF")
propose_1stJIT(_JIT_logic,FALSE,FALSE);
// aggiorna lo sheet delle capacita'
on_field_event((TOperable_field&)field(F_LOADTYPE), fe_modify, jolly );
sfield(F_ARTICOLI).set_focus();
}
break;
case F_RECALC_CRP:
if (e == fe_button && check_fields())
{
if (capacity_review(get_bool(F_USENONSTDLIN_CRP) ,get_bool(F_USEEXTRAHRS_CRP) ))
{
on_field_event((TOperable_field&)field(F_LOADTYPE), fe_modify, jolly );
sfield(F_LINEE).set_focus();
}
}
break;
case F_CHECK_MSP:
if (e == fe_button)
{
check_articles();
}
break;
case F_CHECKLINE:
if (e == fe_button)
{
const TSheet_field& s = sfield(F_ARTICOLI);
TMSPCheck_mask cm(this);
cm.disable(-G_MOVIMENTO);
int curr_row=s.selected();
const bool is_disabled=s.cell_disabled(curr_row,F_BUCKET1-FIRST_FIELD) ;
const bool is_constr=(is_disabled && curr_row>0 && s.cell_disabled(curr_row-1,F_BUCKET1-FIRST_FIELD));
if (is_disabled && !is_constr)
curr_row++;
cm.gopos(curr_row, 1);
cm.run();
cm.gopos_mainmask();
}
break;
case F_SHOWPRICES:
if (e == fe_modify)
{
TSheet_field& s = sfield(F_ARTICOLI);
const bool on = get_bool(F_SHOWPRICES);
for (int b=LAST_BUCKET ; b>=0 ; b--)
{
s.set_column_width(F_BUCKET0+1+b*2-FIRST_FIELD, on ? 140 : 0);
s.enable_column(F_BUCKET0+1+b*2-FIRST_FIELD, on && b>0 && b < LAST_BUCKET);
// ^^^^- da sostituire con un piu' elegante (ma non implementato): s.show(F_BUCKET0+1+b*2-FIRST_FIELD,on);
}
s.force_update();
}
case F_CHECK_CRP:
if (e == fe_button)
{
check_capacities();
}
break;
case F_SHOWPERC:
if (e == fe_modify)
on_field_event((TOperable_field&)field(F_LOADTYPE), fe_modify, jolly );
break;
case F_LOADTYPE:
if (e == fe_modify)
{
// *************
// fill sheet of capacities
const bool as_percentage=get_bool(F_SHOWPERC);
const bool show_human=*get(F_LOADTYPE)=='H';
TSheet_field& sl = sfield(F_LINEE);
sl.destroy();
//TSheet_field& su = sfield(F_TESTE);
//su.destroy();
const long max_capacities=_capacities.items();
for (long c=0; c<max_capacities ; c++)
{
TCRP_line &crpline = _capacities[c];
if (show_human)
{
crpline.fill_hcapacity_row(sl.row(-1), as_percentage);
sl.disable_cell(sl.items()-1, -1);
crpline.fill_hload_row(sl.row(-1), as_percentage);
} else {
if (!crpline.codlin().blank())
{
crpline.fill_capacity_row(sl.row(-1), as_percentage);
sl.disable_cell(sl.items()-1, -1);
crpline.fill_load_row(sl.row(-1), as_percentage);
}
}
}
sl.force_update();
}
break;
case DLG_SAVEREC:
if (e == fe_button)
{
salva_documenti();
//clear_sheets();
//disable(DLG_SAVEREC);
//enable_default(-1);
//field(F_BUCKET).on_hit();
}
break;
case DLG_PROFILE:
if (e == fe_modify)
{
clear_sheets();
enable(-1);
}
break;
default:
break;
}
return TRUE;
}
TMSP_mask::TMSP_mask()
: TCalendar_mask("mr2200a")
{
TSheet_field& sf = sfield(F_ARTICOLI);
sf.set_append(FALSE);
for (short l = 0; l < 4; l++)
_livelli.set_sheetcolumn(sf, F_LIV1+l, l+1);
TConfig ini(CONFIG_DITTA, "mg");
if (!ini.get_bool("GESDEPOSITI"))
{
sf.delete_column(F_DEPOSITO);
sf.sheet_mask().hide(F_DEPOSITO);
}
if (!ini.get_bool("GESMULTIMAG"))
{
sf.sheet_mask().disable(F_MAGAZZINO);
}
if (!ini.get_bool("GESTIMPIANTI", "mr"))
{
hide(F_IMPIANTO);
sf.delete_column(F_CODIMP);
sf.sheet_mask().hide(F_CODIMP);
sf.sheet_mask().hide(F_DESCIMP);
}
sfield(F_LINEE).disable();
// sfield(F_TESTE).disable();
load_profile();
}
void TMSPCheck_mask::go_top()
{
gopos(2,1);
if (move_to(FC_UP))
if (move_to(FC_UP))
fill_mask();
fix_actual_pos();
}
void TMSPCheck_mask::gopos_mainmask()
{
TSheet_field &sf=_main_mask->sfield(F_ARTICOLI);
int curr_row=last_row();
while (sf.cell_disabled(curr_row,F_BUCKET1-FIRST_FIELD) )
curr_row++;
sf.select(curr_row,TRUE);
_main_mask->set_focus_field(sf.dlg());
sf.set_focus_cell(curr_row, last_col()*2+F_BUCKET0);
}
TMSPCheck_mask::TMSPCheck_mask(TMSP_mask * main_mask, const char *m,TSheet_field * s):
TAutomask(m), _main_mask(main_mask) , _sheet(s)
{
_last_col=_last_row=_constr_row=-1;
go_top();
}
TMSPCheck_mask::TMSPCheck_mask(TMSP_mask * main_mask):
TAutomask("mr2200b.msk"), _main_mask(main_mask), _sheet(&main_mask->sfield(F_ARTICOLI))
{
_last_col=_last_row=_constr_row=-1;
go_top();
}
//valori di ritorno:
// 0 : nessun errore
// 1 : esistono modifiche
// 2 : esistono nuove proposta
// 4 : giacenza media superiore al voluto
// 8 : sotto stock
int TMSPCheck_mask::fill_mask(const bool show_fields)
{
int error=0;
if (_last_col==_col && _last_row==_row)
return error;
const bool is_constr=is_constraint(_row);
TToken_string &row=_sheet->row(_row);
long codcli ;
TCodice_articolo codart;
TString16 liv, mag, codimp, codlin, um;
_main_mask->msprow2codes(row,codcli,codart,liv,mag,codimp, codlin, um);
if (_last_row!=_row)
{
_constr_row=find_constraint(_row);
set(FC_RIGA,_row+1);
set(FC_CODCLI,codcli,TRUE);
set(FC_CODART,codart,TRUE);
set(FC_CODIMP,codimp,TRUE);
set(FC_CODLIN,codlin,TRUE);
set(FC_CODMAG,mag.left(3),TRUE);
set(FC_CODDEP,mag.mid(3),TRUE);
}
set(FC_BUCKET,_col);
TDate data_buck(_main_mask->get_date(F_DADATA));
data_buck += (_col)*_main_mask->days_per_bucket()-1;
set(FC_DATE2,_col==LAST_BUCKET ? "" : data_buck.string());
data_buck -= _main_mask->days_per_bucket()-1;
set(FC_DATE1,_col==0 ? "" : data_buck.string());
set(FC_IS_VINCOLO,is_constr ? "X" : " ");
field(FC_IS_VINCOLO).on_hit();
if (!is_constr)
{
real art_per_buck(row.get(F_BUCKET0 + _col*2 - FIRST_FIELD));
set(FC_FINAL_VALUE,art_per_buck.string());
TMRP_line* new_article = _main_mask->find_propose(codcli, codart,liv,codimp,codlin,mag);
TMSP_line* old_article = _main_mask->find_article(codcli, codart,liv,codimp,codlin,mag);
real old_value=ZERO;
real new_value=ZERO;
if (old_article)
{
old_value=old_article->qta(_col);
}
if (new_article)
{
TMRP_time t(data_buck,0,"","");
TMRP_record& mrprec = new_article->record(t);
new_value=mrprec.sched_receipts();
if (new_value > ZERO)
error|=2;
}
set(FC_STARTING_VALUE,old_value.string());
set(FC_PROPOSED_VALUE,new_value.string());
show(FC_PROPOSED_VALUE,!new_value.is_zero());
show(FC_STARTING_VALUE,!old_value.is_zero());
if (old_value != art_per_buck)
error|=1;
// mostra i campi
hide(FC_GIAC);
hide(FC_UNDERSTOCK);
}
if (_constr_row>=0)
{
// calcola il sotto stock
real stock(_sheet->cell(_constr_row,F_BUCKET0 + _col*2 - FIRST_FIELD));
bool stockbreak=stock<ZERO;
bool overgiac=FALSE;
set(FC_GIAC,stock.string());
stock=-stock;
set(FC_UNDERSTOCK,stock.string());
show(FC_GIAC, !stockbreak);
show(FC_UNDERSTOCK, stockbreak);
error|=stockbreak ? 8 : 0;
// calcola i giorni di permanenza
stock=-stock;
real giorni=ZERO;
if (!stockbreak)
{
int bucket=0;
int buck_days = _main_mask->days_per_bucket();
real prev_stock(_sheet->cell(_constr_row,F_BUCKET0 + 2*_col - 1 - FIRST_FIELD));
real delivery(_sheet->cell(_constr_row-1,F_BUCKET0 + 2*_col - FIRST_FIELD));
stock=stock-prev_stock+delivery;
if (stock > ZERO)
{
real residuo=stock;
while (residuo > ZERO && (_col + bucket)<LAST_BUCKET)
{
delivery = _sheet->cell(_constr_row-1,F_BUCKET0 + 2*_col + bucket - FIRST_FIELD);
if (delivery < prev_stock)
{
prev_stock-=delivery;
delivery=ZERO;
} else {
delivery-=prev_stock;
prev_stock=ZERO;
}
residuo-= delivery;
if (residuo < ZERO) residuo=ZERO;
giorni+= residuo;
bucket++;
}
giorni = buck_days*giorni / stock;
const int maxdays(_main_mask->get_int(F_MAXGIORNIGIAC));
overgiac=(giorni.integer() > maxdays);
error|=overgiac ? 4 : 0;
}
}
set(FC_GIORNIGIAC,giorni.string());
set(FC_OVERGIORNIGIAC,giorni.string());
show(FC_GIORNIGIAC, !overgiac);
show(FC_OVERGIORNIGIAC,overgiac);
}
return error;
}
void TMSPCheck_mask::fix_actual_pos()
{
_last_col=_col;
_last_row=_row;
}
void TMSPCheck_mask::gopos(int row, int col)
{
_row=row;
_col=col;
fill_mask();
fix_actual_pos();
}
bool TMSPCheck_mask::on_field_event(TOperable_field& o, TField_event e, long jolly)
{
if (e==fe_button)
{
const int dlg=o.dlg();
bool redo=TRUE;
const TString4 old_movefilter(get(FC_MOVEFILTER));
const TString4 new_movefilter(get_int(FC_FINDFILTER) & 1 ? "" : "C");
switch (dlg)
{
case FC_UP_BAD:
set(FC_MOVEFILTER,new_movefilter);
if (redo = move_to(FC_UP))
_col = LAST_BUCKET+1;
case FC_LEFT_BAD:
set(FC_MOVEFILTER,new_movefilter);
while (redo)
{
while (move_to(FC_LEFT))
{
int err=fill_mask() ;
fix_actual_pos();
if (err & get_int(FC_FINDFILTER))
{
set(FC_MOVEFILTER,old_movefilter);
return TRUE;
}
}
if (redo = move_to(FC_UP))
_col = LAST_BUCKET+1;
}
message_box("Ricerca terminata");
break;
case FC_DOWN_BAD:
set(FC_MOVEFILTER,new_movefilter);
if (redo = move_to(FC_DOWN))
_col = -1;
case FC_RIGHT_BAD:
set(FC_MOVEFILTER,new_movefilter);
while (redo)
{
while (redo && move_to(FC_RIGHT))
{
int err=fill_mask() ;
fix_actual_pos();
if (err & get_int(FC_FINDFILTER))
{
set(FC_MOVEFILTER,old_movefilter);
return TRUE;
}
}
if (redo = move_to(FC_DOWN))
_col = -1;
}
message_box("Ricerca terminata");
break;
default:
move_to(dlg);
fill_mask();
fix_actual_pos();
}
set(FC_MOVEFILTER,old_movefilter);
}
return TRUE;
}
int TMSPCheck_mask::find_constraint(int row)
{
while (row >=0 )
{
if (is_constraint(row))
return row;
row--;
}
return -1;
}
bool TMSPCheck_mask::is_constraint(int row)
{
return (row > 0
&& _sheet->cell_disabled(row, F_BUCKET1-FIRST_FIELD)
&& _sheet->cell_disabled(row-1, F_BUCKET1-FIRST_FIELD));
}
bool TMSPCheck_mask::is_article(int row)
{
return !_sheet->cell_disabled(row, F_BUCKET1-FIRST_FIELD);
}
bool TMSPCheck_mask::move_to(int dlg)
{
const bool constraints=*get(FC_MOVEFILTER)!='A';
const bool articles=*get(FC_MOVEFILTER)!='C';
CHECK(constraints||articles, "N'do cazzo muovo?");
const int max_rows=_sheet->items();
bool skip_row=TRUE;
int old_row=_row;
switch (dlg)
{
case FC_DOWNLEFT:
case FC_DOWNRIGHT:
case FC_DOWN:
while (_row < max_rows-1)
{
_row++;
if (constraints && is_constraint(_row) || articles && is_article(_row))
break;
}
if (dlg==FC_DOWNRIGHT) _col++;
if (dlg==FC_DOWNLEFT) _col--;
break; // se non sono sulla linea giusta, torno indietro
case FC_UPRIGHT:
case FC_UPLEFT:
case FC_UP:
while (_row >0 )
{
_row--;
if (constraints && is_constraint(_row) || articles && is_article(_row))
break;
}
if (dlg==FC_UPRIGHT) _col++;
if (dlg==FC_UPLEFT) _col--;
break;
case FC_LEFT:
_col--;
break;
case FC_RIGHT:
_col++;
break;
}
if (!((articles && is_article(_row) ) || (constraints && is_constraint(_row))))
_row=old_row;
check_pos_range();
if (_last_col==_col && _last_row==_row)
return FALSE;
return TRUE;
}
void TMSPCheck_mask::check_pos_range()
{
int max_cols=min(get_int(FC_MAXBUCK2CHECK),LAST_BUCKET);
if (max_cols==0) max_cols=LAST_BUCKET;
const bool constraints=*get(FC_MOVEFILTER)!='A';
const int max_rows=_sheet->items();
if (_row>=max_rows) _row=max_rows-1;
if (_row< (constraints ? 1 : 2) ) _row++;
if (_col>=max_cols) _col=max_cols;
if (_col<1) _col=0;
}
///////////////////////////////////////////////////////////
//
///////////////////////////////////////////////////////////
TCRPCheck_mask::TCRPCheck_mask(TMSP_mask * main_mask):
TMSPCheck_mask(main_mask, "mr2200c.msk", & main_mask->sfield(F_LINEE))
{
}
void TCRPCheck_mask::check_pos_range()
{
const bool constraints=*get(FC_MOVEFILTER)!='A';
const int max_rows=_sheet->items();
if (_row>=max_rows) _row=max_rows-1;
if (_row< (constraints ? 0 : 1) ) _row++;
if (_col>=LAST_BUCKET) _col=LAST_BUCKET-1;
if (_col<1) _col=1;
}
bool TCRPCheck_mask::is_constraint(int row)
{
return (row > 0
&& !_sheet->cell_disabled(row, F_LBUCKET1-FIRST_FIELD)
&& _sheet->cell_disabled(row-1, F_LBUCKET1-FIRST_FIELD));
}
bool TCRPCheck_mask::is_article(int row)
{
return (*_sheet->row(row).get(F_CODARTCRP-FIRST_FIELD)>' ');
}
int TCRPCheck_mask::find_constraint(int row)
{
const int max=max_rows();
while (row < max)
{
if (is_constraint(row))
return row;
row++;
}
return -1;
}
int TCRPCheck_mask::fill_mask(const bool show_fields)
{
int error=0;
if (_last_col==_col && _last_row==_row)
return error;
const bool is_constr=is_constraint(_row);
TSheet_field& sf = _main_mask->sfield(F_LINEE);
TToken_string &row=sf.row(_row);
long codcli ;
TCodice_articolo codart;
TString16 liv, codimp, codlin, um;
_main_mask->crprow2codes(row,codimp, codlin,codcli,codart,liv,um);
if (_last_row!=_row)
{
_constr_row=find_constraint(_row);
set(FC_RIGA,_row+1);
set(FC_CODIMP,codimp);
set(FC_CODLIN,codlin);
set(FC_CODCLI,codcli);
set(FC_CODART,codart);
}
set(FC_BUCKET,_col);
TDate data_buck(_main_mask->get_date(F_DADATA));
data_buck += (_col)*_main_mask->days_per_bucket()-1;
set(FC_DATE2,data_buck.string());
data_buck -= _main_mask->days_per_bucket()-1;
set(FC_DATE1,data_buck.string());
set(FC_IS_VINCOLO,is_constr ? "X" : " ");
field(FC_IS_VINCOLO).on_hit();
if (!is_constr)
{
// articolo
real art_load(_sheet->cell(_row ,F_LBUCKET1 + _col - 1 - FIRST_FIELD));
set(FC_ART_LOAD,art_load.string());
}
if (_constr_row>=0)
{
// vincolo
real load(_sheet->cell(_constr_row ,F_LBUCKET1 + _col - 1 - FIRST_FIELD));
set(FC_LOAD,load.string());
show(FC_LOAD,load>ZERO);
real capacity(_sheet->cell(_constr_row -1 ,F_LBUCKET1 + _col - 1 - FIRST_FIELD));
const bool positive=capacity>ZERO;
set(FC_CAPACITY,capacity.string());
show(FC_CAPACITY,positive);
capacity-=load;
const bool out=capacity<ZERO;
set(FC_CAPACITY_REM,capacity.string());
if (out)
{
capacity=-capacity;
error|=8;
}
set(FC_CAPACITY_OUT,capacity.string());
show(FC_CAPACITY_REM,positive && !out);
show(FC_CAPACITY_OUT,positive && out);
}
return error;
}
///////////////////////////////////////////////////////////
// Applicazione principale
///////////////////////////////////////////////////////////
class TMSP_app : public TSkeleton_application
{
protected:
virtual void main_loop();
virtual bool firm_change_enabled() const { return FALSE; }
public:
TMSP_app() {}
};
void TMSP_app ::main_loop()
{
open_files(LF_TABCOM, LF_TAB, LF_DOC, LF_RIGHEDOC, 0);
open_files(LF_CLIFO, LF_CFVEN, LF_OCCAS, LF_INDSP, LF_CONDV, 0);
open_files(LF_MAG, LF_ANAMAG, LF_DIST, LF_RDIST, 0);
TMSP_mask m;
TConfig prassid(CONFIG_DITTA, "ve"); // apre il file di configurazione della ditta corrente
if (prassid.get_bool("GES", NULL, A_LISTINI))
{
m.enable(F_CATVEN_CV,prassid.get_bool("GESLISCV"));
}
else
{
m.disable(F_TIPOCV);
m.disable(F_CATVEN_CV);
}
while (m.run()!=K_QUIT) ;
}
int mr2200(int argc, char* argv[])
{
TMSP_app a;
a.run(argc, argv, "Master Schedule Planning");
return 0;
}