00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027 #define FREPPLE_CORE
00028 #include "frepple/model.h"
00029
00030 namespace frepple
00031 {
00032
00033 template<class Demand> DECLARE_EXPORT Tree utils::HasName<Demand>::st;
00034
00035
00036 DECLARE_EXPORT void Demand::setQuantity(double f)
00037 {
00038
00039 double delta(f - qty);
00040 if (f < 0.0 || fabs(delta)<ROUNDING_ERROR) return;
00041
00042
00043 qty = f;
00044 setChanged();
00045 }
00046
00047
00048 DECLARE_EXPORT void Demand::deleteOperationPlans (bool deleteLockedOpplans)
00049 {
00050
00051 for (OperationPlan_list::iterator i = deli.begin(); i!=deli.end(); )
00052 if (deleteLockedOpplans || !(*i)->getLocked())
00053 {
00054
00055
00056
00057 (*i)->dmd = NULL;
00058 delete *i;
00059
00060
00061 OperationPlan_list::iterator todelete = i;
00062 ++i;
00063 deli.erase(todelete);
00064 }
00065 else ++i;
00066
00067
00068 setChanged();
00069 }
00070
00071
00072 DECLARE_EXPORT void Demand::removeDelivery(OperationPlan * o)
00073 {
00074
00075 if (!o) return;
00076
00077
00078 if (o->dmd != this)
00079 throw LogicException("Delivery operationplan incorrectly registered");
00080
00081
00082 o->dmd = NULL;
00083 o->setDemand(NULL);
00084
00085
00086 OperationPlan_list::iterator j = deli.begin();
00087 while (j!=deli.end() && *j!=o) ++j;
00088
00089
00090
00091
00092 if (j!=deli.end())
00093 {
00094
00095 deli.erase(j);
00096
00097 setChanged();
00098 }
00099 }
00100
00101
00102 DECLARE_EXPORT const Demand::OperationPlan_list& Demand::getDelivery() const
00103 {
00104
00105
00106
00107
00108
00109 for (bool swapped(!deli.empty()); swapped; swapped=false)
00110 {
00111 OperationPlan_list::iterator j = const_cast<Demand*>(this)->deli.begin();
00112 ++j;
00113 for (OperationPlan_list::iterator i =
00114 const_cast<Demand*>(this)->deli.begin();
00115 j!=const_cast<Demand*>(this)->deli.end(); ++j)
00116 {
00117 if ((*i)->getDates().getEnd() < (*j)->getDates().getEnd())
00118 {
00119
00120 iter_swap(i,j);
00121
00122
00123 swapped = true;
00124 break;
00125 }
00126 ++i;
00127 }
00128 }
00129
00130 return deli;
00131 }
00132
00133
00134 DECLARE_EXPORT OperationPlan* Demand::getLatestDelivery() const
00135 {
00136 const Demand::OperationPlan_list& l = getDelivery();
00137 return l.empty() ? NULL : *(l.begin());
00138 }
00139
00140
00141 DECLARE_EXPORT OperationPlan* Demand::getEarliestDelivery() const
00142 {
00143 const Demand::OperationPlan_list& l = getDelivery();
00144 OperationPlan *last = NULL;
00145 for (Demand::OperationPlan_list::const_iterator i = l.begin(); i!=l.end(); ++i)
00146 last = *i;
00147 return last;
00148 }
00149
00150
00151 DECLARE_EXPORT void Demand::addDelivery (OperationPlan * o)
00152 {
00153
00154 if (!o) return;
00155
00156
00157
00158
00159 for (OperationPlan_list::iterator i = deli.begin(); i!=deli.end(); ++i)
00160 if (*i == o) return;
00161
00162
00163
00164
00165
00166
00167
00168 getDelivery();
00169 OperationPlan_list::iterator j = deli.begin();
00170 while (j!=deli.end() && (*j)->getDates().getEnd()>o->getDates().getEnd()) ++j;
00171 deli.insert(j, o);
00172
00173
00174 setChanged();
00175
00176
00177 o->setDemand(this);
00178
00179
00180 Operation* tmpOper = getDeliveryOperation();
00181 if (tmpOper && tmpOper != o->getOperation())
00182 logger << "Warning: Delivery Operation '" << o->getOperation()
00183 << "' different than expected '" << tmpOper
00184 << "' for demand '" << this << "'" << endl;
00185 }
00186
00187
00188 DECLARE_EXPORT Operation* Demand::getDeliveryOperation() const
00189 {
00190
00191 if (oper) return oper;
00192
00193 if (it) return it->getOperation();
00194
00195 return NULL;
00196 }
00197
00198
00199 DECLARE_EXPORT double Demand::getPlannedQuantity() const
00200 {
00201 double delivered(0.0);
00202 for (OperationPlan_list::const_iterator i=deli.begin(); i!=deli.end(); ++i)
00203 delivered += (*i)->getQuantity();
00204 return delivered;
00205 }
00206
00207
00208 DECLARE_EXPORT void Demand::writeElement(XMLOutput *o, const Keyword& tag, mode m) const
00209 {
00210
00211 if (m == REFERENCE)
00212 {
00213 o->writeElement(tag, Tags::tag_name, getName());
00214 return;
00215 }
00216
00217
00218 if (m != NOHEADER) o->BeginObject(tag, Tags::tag_name, getName());
00219
00220
00221 HasDescription::writeElement(o, tag);
00222 HasHierarchy<Demand>::writeElement(o, tag);
00223 o->writeElement(Tags::tag_operation, oper);
00224 o->writeElement(Tags::tag_customer, cust);
00225 Plannable::writeElement(o, tag);
00226
00227 o->writeElement(Tags::tag_quantity, qty);
00228 o->writeElement(Tags::tag_item, it);
00229 o->writeElement(Tags::tag_due, dueDate);
00230 if (getPriority()) o->writeElement(Tags::tag_priority, getPriority());
00231 if (getMaxLateness() != TimePeriod::MAX)
00232 o->writeElement(Tags::tag_maxlateness, getMaxLateness());
00233 if (getMinShipment())
00234 o->writeElement(Tags::tag_minshipment, getMinShipment());
00235
00236
00237 if ((o->getContentType() == XMLOutput::PLAN
00238 || o->getContentType() == XMLOutput::PLANDETAIL) && !deli.empty())
00239 {
00240 o->BeginObject(Tags::tag_operationplans);
00241 for (OperationPlan_list::const_iterator i=deli.begin(); i!=deli.end(); ++i)
00242 o->writeElement(Tags::tag_operationplan, *i, FULL);
00243 o->EndObject(Tags::tag_operationplans);
00244 }
00245 o->EndObject(tag);
00246 }
00247
00248
00249 DECLARE_EXPORT void Demand::beginElement(XMLInput& pIn, const Attribute& pAttr)
00250 {
00251 if (pAttr.isA (Tags::tag_item))
00252 pIn.readto( Item::reader(Item::metadata,pIn.getAttributes()) );
00253 else if (pAttr.isA (Tags::tag_operation))
00254 pIn.readto( Operation::reader(Operation::metadata,pIn.getAttributes()) );
00255 else if (pAttr.isA (Tags::tag_customer))
00256 pIn.readto( Customer::reader(Customer::metadata,pIn.getAttributes()) );
00257 else if (pAttr.isA(Tags::tag_operationplan))
00258 pIn.readto(OperationPlan::createOperationPlan(OperationPlan::metadata,pIn.getAttributes()));
00259 else
00260 HasHierarchy<Demand>::beginElement(pIn, pAttr);
00261 }
00262
00263
00264 DECLARE_EXPORT void Demand::endElement(XMLInput& pIn, const Attribute& pAttr, const DataElement& pElement)
00265 {
00266 if (pAttr.isA (Tags::tag_quantity))
00267 setQuantity (pElement.getDouble());
00268 else if (pAttr.isA (Tags::tag_priority))
00269 setPriority (pElement.getInt());
00270 else if (pAttr.isA (Tags::tag_due))
00271 setDue(pElement.getDate());
00272 else if (pAttr.isA (Tags::tag_operation))
00273 {
00274 Operation *o = dynamic_cast<Operation*>(pIn.getPreviousObject());
00275 if (o) setOperation(o);
00276 else throw LogicException("Incorrect object type during read operation");
00277 }
00278 else if (pAttr.isA (Tags::tag_customer))
00279 {
00280 Customer *c = dynamic_cast<Customer*>(pIn.getPreviousObject());
00281 if (c) setCustomer(c);
00282 else throw LogicException("Incorrect object type during read operation");
00283 }
00284 else if (pAttr.isA (Tags::tag_item))
00285 {
00286 Item *i = dynamic_cast<Item*>(pIn.getPreviousObject());
00287 if (i) setItem(i);
00288 else throw LogicException("Incorrect object type during read operation");
00289 }
00290 else if (pAttr.isA (Tags::tag_maxlateness))
00291 setMaxLateness(pElement.getTimeperiod());
00292 else if (pAttr.isA (Tags::tag_minshipment))
00293 setMinShipment(pElement.getDouble());
00294 else if (pAttr.isA(Tags::tag_operationplan))
00295 {
00296 OperationPlan* opplan
00297 = dynamic_cast<OperationPlan*>(pIn.getPreviousObject());
00298 if (opplan) addDelivery(opplan);
00299 else throw LogicException("Incorrect object type during read operation");
00300 }
00301 else
00302 {
00303 Plannable::endElement(pIn, pAttr, pElement);
00304 HasDescription::endElement(pIn, pAttr, pElement);
00305 HasHierarchy<Demand>::endElement (pIn, pAttr, pElement);
00306 }
00307 }
00308
00309
00310 DECLARE_EXPORT PyObject* PythonDemand::getattro(const Attribute& attr)
00311 {
00312 if (!obj) return Py_BuildValue("");
00313 if (attr.isA(Tags::tag_name))
00314 return PythonObject(obj->getName());
00315 if (attr.isA(Tags::tag_quantity))
00316 return PythonObject(obj->getQuantity());
00317 if (attr.isA(Tags::tag_due))
00318 return PythonObject(obj->getDue());
00319 if (attr.isA(Tags::tag_priority))
00320 return PythonObject(obj->getPriority());
00321 if (attr.isA(Tags::tag_owner))
00322 return PythonObject(obj->getOwner());
00323 if (attr.isA(Tags::tag_item))
00324 return PythonObject(obj->getItem());
00325 if (attr.isA(Tags::tag_customer))
00326 return PythonObject(obj->getCustomer());
00327 if (attr.isA(Tags::tag_operation))
00328 return PythonObject(obj->getOperation());
00329 if (attr.isA(Tags::tag_description))
00330 return PythonObject(obj->getDescription());
00331 if (attr.isA(Tags::tag_category))
00332 return PythonObject(obj->getCategory());
00333 if (attr.isA(Tags::tag_subcategory))
00334 return PythonObject(obj->getSubCategory());
00335 if (attr.isA(Tags::tag_minshipment))
00336 return PythonObject(obj->getMinShipment());
00337 if (attr.isA(Tags::tag_maxlateness))
00338 return PythonObject(obj->getMaxLateness());
00339 if (attr.isA(Tags::tag_hidden))
00340 return PythonObject(obj->getHidden());
00341 if (attr.isA(Tags::tag_operationplans))
00342 return new PythonDemandPlanIterator(obj);
00343 if (attr.isA(Tags::tag_pegging))
00344 return new PythonPeggingIterator(obj);
00345 return NULL;
00346 }
00347
00348
00349 DECLARE_EXPORT int PythonDemand::setattro(const Attribute& attr, const PythonObject& field)
00350 {
00351 if (attr.isA(Tags::tag_name))
00352 obj->setName(field.getString());
00353 else if (attr.isA(Tags::tag_priority))
00354 obj->setPriority(field.getInt());
00355 else if (attr.isA(Tags::tag_quantity))
00356 obj->setQuantity(field.getDouble());
00357 else if (attr.isA(Tags::tag_due))
00358 obj->setDue(field.getDate());
00359 else if (attr.isA(Tags::tag_item))
00360 {
00361 if (!field.check(PythonItem::getType()))
00362 {
00363 PyErr_SetString(PythonDataException, "demand item must be of type item");
00364 return -1;
00365 }
00366 Item* y = static_cast<PythonItem*>(static_cast<PyObject*>(field))->obj;
00367 obj->setItem(y);
00368 }
00369 else if (attr.isA(Tags::tag_customer))
00370 {
00371 if (!field.check(PythonCustomer::getType()))
00372 {
00373 PyErr_SetString(PythonDataException, "demand customer must be of type customer");
00374 return -1;
00375 }
00376 Customer* y = static_cast<PythonCustomer*>(static_cast<PyObject*>(field))->obj;
00377 obj->setCustomer(y);
00378 }
00379 else if (attr.isA(Tags::tag_description))
00380 obj->setDescription(field.getString());
00381 else if (attr.isA(Tags::tag_category))
00382 obj->setCategory(field.getString());
00383 else if (attr.isA(Tags::tag_subcategory))
00384 obj->setSubCategory(field.getString());
00385 else if (attr.isA(Tags::tag_minshipment))
00386 obj->setMinShipment(field.getDouble());
00387 else if (attr.isA(Tags::tag_maxlateness))
00388 obj->setMaxLateness(field.getTimeperiod());
00389 else if (attr.isA(Tags::tag_owner))
00390 {
00391 if (!field.check(PythonDemand::getType()))
00392 {
00393 PyErr_SetString(PythonDataException, "demand owner must be of type demand");
00394 return -1;
00395 }
00396 Demand* y = static_cast<PythonDemand*>(static_cast<PyObject*>(field))->obj;
00397 obj->setOwner(y);
00398 }
00399 else if (attr.isA(Tags::tag_operation))
00400 {
00401 if (!field.check(PythonOperation::getType()))
00402 {
00403 PyErr_SetString(PythonDataException, "demand operation must be of type operation");
00404 return -1;
00405 }
00406 Operation* y = static_cast<PythonOperation*>(static_cast<PyObject*>(field))->obj;
00407 obj->setOperation(y);
00408 }
00409 else if (attr.isA(Tags::tag_hidden))
00410 obj->setHidden(field.getBool());
00411 else
00412 return -1;
00413 return 0;
00414 }
00415
00416
00417 DECLARE_EXPORT PyObject* PythonDemandDefault::getattro(const Attribute& attr)
00418 {
00419 return PythonDemand(obj).getattro(attr);
00420 }
00421
00422
00423 DECLARE_EXPORT int PythonDemandDefault::setattro(const Attribute& attr, const PythonObject& field)
00424 {
00425 return PythonDemand(obj).setattro(attr, field);
00426 }
00427
00428
00429 int PythonDemandPlanIterator::initialize(PyObject* m)
00430 {
00431
00432 PythonType& x = PythonExtension<PythonDemandPlanIterator>::getType();
00433 x.setName("demandplanIterator");
00434 x.setDoc("frePPLe iterator for demand delivery operationplans");
00435 x.supportiter();
00436 return x.typeReady(m);
00437 }
00438
00439
00440 PyObject* PythonDemandPlanIterator::iternext()
00441 {
00442 if (i == dem->getDelivery().end()) return NULL;
00443 return new PythonOperationPlan(const_cast<OperationPlan*>(&**(i++)));
00444 }
00445
00446 }