001 002 package market; 003 004 import java.util.Hashtable; 005 import java.util.Iterator; 006 007 import market.stdform.ButtonIDs; 008 import market.stdform.FSCheckable; 009 import market.stdform.FSWorkerDefault; 010 import market.stdform.FSWorkerEdit; 011 import market.stdform.FSWorkerOrder; 012 import market.stdform.MSLogOff; 013 import sale.FormSheet; 014 import sale.Gate; 015 import sale.GateChangeTransition; 016 import sale.SaleProcess; 017 import sale.SalesPoint; 018 import sale.Shop; 019 import sale.Transition; 020 import sale.UIGate; 021 import sale.stdforms.MsgForm; 022 import users.User; 023 import users.UserManager; 024 import data.StockItem; 025 import data.events.VetoException; 026 import data.ooimpl.CountingStockImpl; 027 import data.stdforms.SingleTableFormSheet; 028 029 /** 030 * The worker process. This process handles execution of the orders. 031 */ 032 public class SProcessWorker extends SProcessMarket{ 033 034 public static final int BUYPROCESS = 0; 035 public static final int TILLQUEUE = 1; 036 public static final int WAREHOUSEQUEUE = 2; 037 public static final int OLDOFFER = 3; 038 039 /** 040 * Gate for displaying how much workers are currently logged on and 041 * how much orders aren`t yet executed. 042 */ 043 private UIGate uig_initial = new UIGate(null, null); 044 045 /** 046 * Gate for displaying a checklist for the order of the currently selected customer. 047 */ 048 private UIGate uig_order = new UIGate(null, null); 049 050 /** 051 * Gate for displaying that the execution of the order isn`t completed. 052 */ 053 private UIGate uig_notReady = new UIGate(null, null); 054 055 /** 056 * Gate for editing the count of articles in case of a shortage. 057 */ 058 private UIGate uig_edit = new UIGate(null, null); 059 060 /** 061 * Gate for displaying that no article was selected. 062 */ 063 private UIGate uig_noItemSelected = new UIGate(null, null); 064 065 /** 066 * Gate for affirming that the correction of the article`s count was successful. 067 */ 068 private UIGate uig_editConfirmation = new UIGate(null, null); 069 070 private SingleTableFormSheet stfs_order; 071 private FSCheckable fsc_edit; 072 073 /** 074 * Current {@link CSOrder} to execute. 075 */ 076 private CSOrder cso_order = null; 077 078 /** 079 * A new order that might contains articles which aren`t yet avaible in case of a shortage. 080 */ 081 private CountingStockImpl cs_newOrder; 082 083 /** 084 * Current selected [@link SICustomer}. 085 */ 086 private SICustomer sic_customer = null; 087 088 /** 089 * The global warehouse-queue. 090 */ 091 private static SSListenable ss_orders = SMarket.getWarehouseQueue(); 092 093 /** 094 * A Hashtable storing which articles are already executed and which not. 095 */ 096 private Hashtable h_articlesDone = new Hashtable(); 097 098 /** 099 * The {@link CIArticle} which count has to be edit. 100 */ 101 private CIArticle ci_article = null; 102 103 /** 104 * An Array containing the count of an article in all different datastructures in the market, 105 * temporarily items in shoppingbaskets, orders waiting at the till-queue, 106 * orders waiting at the warehouse-queue and items in the markets-offer. 107 */ 108 private int[] databaseCount = new int[4]; 109 110 111 /** 112 * @param sName the name of the process. 113 */ 114 public SProcessWorker(String sName) { 115 super(sName); 116 } 117 118 119 //################################### Gates ############################################################ 120 121 /** 122 * Attaches {@link FSWorkerDefault}, its actions and the menu to {@link #uig_initial}. 123 * @return the set up {@link #uig_initial}. 124 */ 125 protected Gate getInitialGate() { 126 FormSheet fs = new FSWorkerDefault(getOrderCount(), getWorkerCount()); 127 setTransition(fs, changeToOrderGate(), ButtonIDs.BTN_OK); 128 uig_initial.setFormSheet(fs); 129 uig_initial.setMenuSheet(new MSLogOff(logOff())); 130 return uig_initial; 131 } 132 133 /** 134 * Attaches {@link FSWorkerOrder} and its actions to {@link #uig_order}. 135 * @return the set up {@link #uig_order}. 136 */ 137 private Gate getOrderGate(){ 138 stfs_order = FSWorkerOrder.getOrderTable(sic_customer.getName(), cso_order, h_articlesDone); 139 setTransition(stfs_order, GateChangeTransition.CHANGE_TO_COMMIT_GATE, ButtonIDs.BTN_ACCEPT); 140 setTransition(stfs_order, changeToEditGate(), ButtonIDs.BTN_EDIT); 141 setTransition(stfs_order, GateChangeTransition.CHANGE_TO_ROLLBACK_GATE, ButtonIDs.BTN_BACK); 142 uig_order.setFormSheet(stfs_order); 143 return uig_order; 144 } 145 146 /** 147 * Attaches {@link MsgForm} and its ok-action to {@link #uig_notReady}. 148 * @return the set up {@link #uig_notReady}. 149 */ 150 private Gate notReadyGate(){ 151 FormSheet fs = new MsgForm("Auftrag nicht fertig","Sie haben nicht alle Artikel abgearbeitet.\n"+ 152 "Bitte erledigen Sie dies zunächst damit der Auftrag abgeschlossen werden kann!"); 153 setTransition(fs, new GateChangeTransition(uig_order), FormSheet.BTNID_OK); 154 uig_notReady.setFormSheet(fs); 155 return uig_notReady; 156 } 157 158 /** 159 * Attaches {@link FSWorkerEdit} and its actions to {@link #uig_edit}. 160 * @return the set up {@link #uig_edit}. 161 */ 162 private Gate getEditGate(){ 163 fsc_edit = FSWorkerEdit.create(ci_article, getDatabaseCount()); 164 setAction(fsc_edit, new sale.Action(){ 165 public void doAction(SaleProcess p, SalesPoint sp) throws Throwable { 166 if(fsc_edit.checkTextFields(FSCheckable.ALL_ERRORMESSAGES_AT_ONCE, false)){ 167 uig_edit.setNextTransition(changeToEditConfirmationGate()); 168 } 169 } 170 }, ButtonIDs.BTN_OK); 171 setTransition(fsc_edit, new GateChangeTransition(getOrderGate()), ButtonIDs.BTN_BACK); 172 uig_edit.setFormSheet(fsc_edit); 173 return uig_edit; 174 } 175 176 /** 177 * Attaches {@link MsgForm} and its ok-action to {@link #uig_noItemSelected}. 178 * @return the set up {@link #uig_noItemSelected}. 179 */ 180 private Gate getNoItemSelectedGate(){ 181 FormSheet fs = new MsgForm("Kein Artikel gewählt", "Sie müssen zunächst einen Artikel auswählen!"); 182 setTransition(fs, new GateChangeTransition(getOrderGate()), FormSheet.BTNID_OK); 183 uig_noItemSelected.setFormSheet(fs); 184 return uig_noItemSelected; 185 } 186 187 /** 188 * Attaches {@link MsgForm} and its ok-action to {@link #uig_editConfirmation}. 189 * @return the set up {@link #uig_editConfirmation}. 190 */ 191 private Gate getEditConfirmationGate(){ 192 FormSheet fs = new MsgForm("Bestand aktualisiert", "Der Bestand wurde erfolgreich korrigiert!"); 193 setTransition(fs, new GateChangeTransition(getOrderGate()), FormSheet.BTNID_OK); 194 uig_editConfirmation.setFormSheet(fs); 195 return uig_editConfirmation; 196 } 197 198 /** 199 * @return the Gate to jump to if the current order is complete. 200 */ 201 public Gate getCommitGate() { 202 return new Gate(){ 203 public Transition getNextTransition(SaleProcess pOwner, User usr) 204 throws InterruptedException { 205 return commit(); 206 } 207 }; 208 } 209 210 /** 211 * @return the Gate to jump to if the current order has to be rolled back. 212 */ 213 public Gate getRollbackGate() { 214 return new Gate(){ 215 public Transition getNextTransition(SaleProcess pOwner, User usr) 216 throws InterruptedException { 217 return rollback(); 218 } 219 }; 220 } 221 222 //################################## Transitions ########################################################## 223 224 /** 225 * @return a Transition that changes to the {@link #getOrderGate()} if there are any orders left, 226 * otherwise returns back to {@link #getInitialGate()}, 227 * sets the next customer and order. 228 */ 229 private Transition changeToOrderGate(){ 230 return new Transition(){ 231 public Gate perform(SaleProcess pOwner, User usr) { 232 setNextCustomer(); 233 if(sic_customer==null) return getInitialGate(); 234 try { 235 ss_orders.remove(sic_customer, pOwner.getBasket()); 236 } catch (VetoException e) { 237 System.err.println(e.getMessage()); 238 return getInitialGate(); 239 } 240 cso_order = sic_customer.removeOrderFromQueue(); 241 initiateArticlesDone(); 242 return getOrderGate(); 243 } 244 }; 245 } 246 247 /** 248 * @return a Transition that changes to the {@link #getInitialGate()} if order is completed, 249 * otherwise changes to the {@link #notReadyGate()}, 250 * adds a new CSOrder to the customer if some articles were not avaible. 251 */ 252 private Transition commit(){ 253 return new Transition(){ 254 public Gate perform(SaleProcess pOwner, User usr) { 255 if(h_articlesDone.contains(Boolean.FALSE)) return notReadyGate(); 256 if(cs_newOrder != null) sic_customer.addOrderToQueue(cs_newOrder, false); 257 if(sic_customer.getOrderCount(false)==0) getBasket().commit(); 258 else getBasket().rollback(); 259 Shop.getTheShop().removeStock(cso_order.getName()); 260 sic_customer = null; 261 cso_order = null; 262 cs_newOrder = null; 263 h_articlesDone.clear(); 264 return getInitialGate(); 265 } 266 }; 267 } 268 269 /** 270 * @return a Transition that changes to the {@link #getInitialGate()}, 271 * rolls back the previously selected order. 272 */ 273 private Transition rollback(){ 274 return new Transition(){ 275 public Gate perform(SaleProcess pOwner, User usr) { 276 pOwner.getBasket().rollback(); 277 sic_customer.rollbackOrder(cso_order); 278 sic_customer = null; 279 cso_order = null; 280 h_articlesDone.clear(); 281 ci_article = null; 282 cs_newOrder = null; 283 return getInitialGate(); 284 } 285 }; 286 } 287 288 /** 289 * @return a Transition that changes to the {@link #getEditGate()} if an article was choosed, 290 * otherwise changes to the {@link #getNoItemSelectedGate()}. 291 */ 292 private Transition changeToEditGate(){ 293 return new Transition(){ 294 public Gate perform(SaleProcess pOwner, User usr) { 295 if(stfs_order.getSelectedRecord()==null) return getNoItemSelectedGate(); 296 ci_article = Conversions.recordToCIArticle(stfs_order.getSelectedRecord()); 297 countDatabase(); 298 return getEditGate(); 299 } 300 }; 301 } 302 303 /** 304 * @return a Transition that changes to the {@link #getEditConfirmationGate()}, 305 * corrects the count of the currently selected article in market`s dates. 306 */ 307 private Transition changeToEditConfirmationGate(){ 308 return new Transition(){ 309 public Gate perform(SaleProcess pOwner, User usr) { 310 // Checks whether the new number of articles is smaller than the old one 311 // because if their is no shortage there is no need to update 312 // this can be done during an inventure or something like this 313 if(Integer.parseInt(fsc_edit.getEntry(FSWorkerEdit.JTFC_REAL))<=getDatabaseCount()){ 314 updateOffer(); 315 } 316 return getEditConfirmationGate(); 317 } 318 }; 319 } 320 321 /** 322 * @return a Transition that changes to the {@link #getStopGate()}, 323 * fires Event: updateWorkerScreen to all MarketEventListeners 324 */ 325 private Transition logOff(){ 326 return new Transition(){ 327 public Gate perform(SaleProcess pOwner, User usr) { 328 SMarket.fireUpdateWorkerScreen(); 329 return getStopGate(); 330 } 331 }; 332 } 333 334 //#################################### internal methods ##################################################### 335 336 /** 337 * @return the count of all workers which are currently logged on. 338 */ 339 private static int getWorkerCount(){ 340 int worker = 0; 341 Iterator salespoints = Shop.getTheShop().getSalesPoints().iterator(); 342 while(salespoints.hasNext()){ 343 User user = ((SalesPoint)salespoints.next()).getUser(); 344 if(((UMUserBase)UserManager.getGlobalUM()).getWarehouseWorker().match(user)){ 345 worker++; 346 } 347 } 348 return worker; 349 } 350 351 /** 352 * @return the count of all orders which aren`t completed yet. 353 */ 354 private static int getOrderCount(){ 355 int order = 0; 356 Iterator it = ss_orders.iterator(null, false); 357 while(it.hasNext()){ 358 order = order + ((SICustomer)it.next()).getOrderCount(true); 359 } 360 return order; 361 } 362 363 /** 364 * Selects the next customer and order to be execute. 365 */ 366 private void setNextCustomer(){ 367 Long time = new Long(System.currentTimeMillis()); 368 SICustomer sic_next = null; 369 Iterator it = ss_orders.iterator(null, true); 370 while(it.hasNext()){ 371 SICustomer sic_current = (SICustomer)it.next(); 372 if((time.compareTo(sic_current.getOrderQueueTime())>=0) && (sic_current.getOrderCount(true) > 0)){ 373 time = sic_current.getOrderQueueTime(); 374 sic_next = sic_current; 375 } 376 } 377 sic_customer = sic_next; 378 } 379 380 /** 381 * Initiates the HashTable with false in the value-fields to signal the articles aren`t executed yet. 382 */ 383 private void initiateArticlesDone(){ 384 Iterator it = cso_order.iterator(null, false); 385 while(it.hasNext()){ 386 h_articlesDone.put(((StockItem)it.next()).getAssociatedItem(null), Boolean.FALSE); 387 } 388 } 389 390 /** 391 * @return the count of the selected article currently stored in the market`s database. 392 */ 393 private int getDatabaseCount(){ 394 return databaseCount[BUYPROCESS]+ 395 databaseCount[TILLQUEUE]+ 396 databaseCount[WAREHOUSEQUEUE]+ 397 databaseCount[OLDOFFER]; 398 } 399 400 /** 401 * Adds a given value to the value at the specified position, 402 * used by different implementations of OfferEventListener 403 * to find out the count of an article considering all datastructures of the market. 404 * 405 * @param value the value that will be added. 406 * @param type the index of the array at which the value will be added, 407 * use {@link #BUYPROCESS} to {@link #OLDOFFER}. 408 */ 409 public synchronized void addDatabaseCount(int value, int type){ 410 databaseCount[type] += value; 411 } 412 413 /** 414 * Sets {@link #databaseCount} to the current count of the selected article, 415 * uses Event: countArticles of OfferEventListener. 416 */ 417 private void countDatabase(){ 418 databaseCount = new int[4]; 419 SPCustomer.fireCountArticles(ci_article.getName(), this); 420 SMarket.getTillQueue().fireCountArticles(ci_article.getName(), this); 421 SMarket.getWarehouseQueue().fireCountArticles(ci_article.getName(), this); 422 addDatabaseCount(cso_order.countItems(ci_article.getName(), null), WAREHOUSEQUEUE); 423 addDatabaseCount(SMarket.getOffer().countItems(ci_article.getName(), null), OLDOFFER); 424 } 425 426 /** 427 * Updates the count of the selected article in market`s database, 428 * if necessary fires Event: offerIsEmpty to OfferEventListeners. 429 */ 430 private void updateOffer(){ 431 String aKey = ci_article.getName(); 432 int realCount = Integer.parseInt(fsc_edit.getEntry(FSWorkerEdit.JTFC_REAL)); 433 int newCount = databaseCount[OLDOFFER] + databaseCount[BUYPROCESS] 434 + databaseCount[TILLQUEUE] + databaseCount[WAREHOUSEQUEUE] - realCount; 435 //if real count of the article doesn`t reach for orders at the till and warehouse 436 //and selections of the customers, then first temporarily selected articles will be rolled back 437 //by firing event: offerIsEmpty to {@link SPCustomer} 438 if(realCount < (databaseCount[BUYPROCESS] + databaseCount[TILLQUEUE] + databaseCount[WAREHOUSEQUEUE])){ 439 SPCustomer.fireOfferIsEmpty(aKey); 440 //if real count still doesn`t reach, the article will be removed from orders at the till-queue 441 //by firing event: offerIsEmpty to {@link SICustomer}s at the till-queue 442 if(realCount < (databaseCount[TILLQUEUE] + databaseCount[WAREHOUSEQUEUE])){ 443 SMarket.getTillQueue().fireOfferIsEmpty(aKey); 444 //if real count still doesn`t reach, the article will be removed from orders 445 //at the warehouse-queue, 446 //by firing event: offerIsEmpty to {@link SICustomer}s at the warehouse-queue 447 if(realCount<databaseCount[WAREHOUSEQUEUE]){ 448 SMarket.getWarehouseQueue().fireOfferIsEmpty(aKey); 449 //if real count doesn`t reach for the current order, 450 //the missing one will be added as a new inactive order to the warehouse-queue 451 if(realCount < cso_order.countItems(aKey, null)){ 452 int i = cso_order.countItems(aKey, null) - realCount; 453 cso_order.remove(aKey, i, null); 454 if(cs_newOrder == null){ 455 cs_newOrder = new CountingStockImpl("new Order", SMarket.getArticleCatalog()); 456 } 457 cs_newOrder.add(aKey, i, null); 458 if(!cso_order.contains(aKey, null)) h_articlesDone.remove(ci_article); 459 newCount -= i; 460 } 461 } 462 } 463 464 } 465 if(newCount <= 0) newCount = SMarket.getOffer().countItems(aKey, null); 466 if(newCount > 0){ 467 try { 468 SMarket.getOffer().remove(aKey, newCount, null); 469 } catch (Exception e) { 470 System.out.println(e.getMessage()); 471 } 472 } 473 } 474 }