001 import sale.*;
002 import sale.stdforms.*;
003 import data.*;
004 import data.ooimpl.*;
005 import data.stdforms.*;
006 import users.*;
007 import log.*;
008
009 import java.util.*;
010 import java.text.*;
011 import java.lang.*;
012 import java.io.*;
013
014 import javax.swing.JTextField;
015 import javax.swing.JPanel;
016 import javax.swing.JOptionPane;
017 import javax.swing.BoxLayout;
018 import javax.swing.JLabel;
019
020
021
022 /**
023 * Verkaufs- bzw. Verleihprozess, der von einem registrierten Kunden
024 * am Automaten durchgeführt werden kann.
025 */
026 public class RentProcess extends SaleProcess
027 {
028
029 //// attributes ////////////////////////////////////////////////////////////
030
031 // Gates
032 protected UIGate capabilityGate;
033 protected UIGate selectionGate;
034 protected UIGate rentGate;
035 protected Gate decisionGate;
036 protected UIGate getChangeGate;
037
038 // Transitions
039 protected Transition toSelectionTransition;
040 protected Transition toPayingTransition;
041 protected Transition toDecisionTransition;
042 protected Transition toGetChangeTransition;
043
044 // verwendete Waehrung
045 private Currency myCurrency;
046
047 // zu zahlender Betrag
048 private IntegerValue toPayValue;
049
050 // gezahlter Betrag
051 private IntegerValue paidValue;
052
053 // Bewertung der Relation zwischen zu zahlendem und gezahltem Betrag
054 private int payAssessment;
055
056 // Kunde, der ausleihen moechte
057 private Customer customer;
058
059 // der Iterator ueber die geliehenen Videos
060 private transient Iterator videoIterator;
061
062
063 //// constructor ///////////////////////////////////////////////////////////
064
065 /**
066 * Erzeugt ein neues Objekt der Klasse RentProcess.
067 */
068 public RentProcess()
069 {
070 super ("RentProcess");
071 }
072
073 //// protected methods /////////////////////////////////////////////////////
074
075 /**
076 * Baut die Oberfläche für den Verleihvorgang auf.
077 */
078 protected void setupMachine()
079 {
080 // verwendete Waehrung ermitteln
081 myCurrency = (Currency)Shop.getTheShop().getCatalog("DM");
082
083 // zu verwendenden Datenkorb ermitteln
084 final DataBasket db = getBasket();
085
086 // zu verwendenden Bestand ermitteln
087 final CountingStockImpl cs =
088 (CountingStockImpl)Shop.getTheShop().getStock("Video-Countingstock");
089
090
091 //////////////////////////////////////////////////
092 /// Capability-Gate //////////////////////////////
093 //////////////////////////////////////////////////
094
095
096 // Formsheet fuer Eingabe der Kundennummer
097 // tif ist final, damit in der anonymen Klasse des FSCC auf Attribute des tif zugegriffen werden kann
098 final TextInputForm tif = new TextInputForm("Customer-ID",
099 "Customer-ID",
100 "");
101
102 // FormSheetContentCreator fuer Capability-Gate implementieren
103 tif.addContentCreator(
104 new FormSheetContentCreator()
105 {
106 protected void createFormSheetContent(FormSheet fs)
107 {
108 // "OK"-Button neu definieren
109 fs.getButton(FormSheet.BTNID_OK).
110 setAction(
111 new sale.Action()
112 {
113 public void doAction (SaleProcess p, SalesPoint sp)
114 {
115 // Eingabe ueberpruefen
116 String customerID = tif.getText();
117 boolean isNotAnInteger = true;
118
119 try {
120 new Integer(customerID);
121 isNotAnInteger = false;
122 }
123 catch(NumberFormatException nfe) {
124 isNotAnInteger = true;
125 }
126
127 // Eingabe korrekt -> selectionGate
128 if (!isNotAnInteger && (new Integer(customerID)).intValue() > 0)
129 {
130 // existiert der Kunde?
131 try {
132 customer = new Customer(customerID);
133 // nein, dann neu anlegen und der Liste reg. Kunden hinzufuegen
134 VideoMachine.addCustomer(customer);
135 }
136 // ja, dann diesen holen
137 catch (DuplicateKeyException dke) {
138 customer = VideoMachine.getCustomerByID(customerID);
139 }
140 capabilityGate.setNextTransition(toSelectionTransition);
141 }
142 // Eingabe falsch -> Kunden informieren und
143 // Eingabe wiederholen
144 else {
145 JOptionPane.showMessageDialog(null,
146 "CustomerID must be a positive Number!");
147 capabilityGate.setNextTransition(
148 new GateChangeTransition(capabilityGate));
149 }
150 }
151 }
152 );
153 // "Cancel"-Button neu definieren
154 fs.getButton(FormSheet.BTNID_CANCEL).
155 setAction(
156 new sale.Action()
157 {
158 public void doAction (SaleProcess p, SalesPoint sp)
159 {
160 // Transition zum Rollback-Gate als naechste Transition setzen
161 capabilityGate.setNextTransition(
162 GateChangeTransition.CHANGE_TO_ROLLBACK_GATE);
163 }
164 }
165 );
166 }
167 }
168 );
169
170 // Gate zur Kundennummer-Abfrage mit erstellter TextInputForm anlegen
171 capabilityGate = new UIGate((FormSheet) tif,
172 (MenuSheet) null);
173
174
175 //////////////////////////////////////////////////
176 /// Selection-Gate ///////////////////////////////
177 //////////////////////////////////////////////////
178
179
180 // Auswahl-Gate anlegen
181 // Das FormSheet wird durch die Transition waehrend der Laufzeit erzeugt
182 selectionGate = new UIGate((FormSheet) null, (MenuSheet) null);
183
184 // Transition zum Selection Gate
185 toSelectionTransition =
186 new Transition()
187 {
188 public Gate perform(SaleProcess pOwner, User usr)
189 {
190 // am Gate darzustellendes FormSheet
191 TwoTableFormSheet ttfs =
192 TwoTableFormSheet.create("Make your selection", // Titel des FormSheets
193 cs, // Quell-CountingStock
194 db, // Ziel-DataBasket
195 selectionGate, // Gate, an dem das FormSheet darzustellen ist
196 null, // Comparator fuer Quelltabelle
197 null, // Comparator furr Ziel-Tabelle
198 false, // Zeilen mit Anzahl == 0 in der Quelltabelle anzeigen?
199 new OfferTED(true), // TableEntryDescriptor furr Quelltabelle
200 null, // TableEntryDescriptor furr Zieltabelle
201 null // Transferstrategie
202 );
203
204 // FormSheetContentCreator am Auswahl-Gate anmelden
205 ttfs.addContentCreator(
206 new FormSheetContentCreator()
207 {
208 protected void createFormSheetContent(FormSheet fs)
209 {
210 // "OK"-Button neu definieren
211 fs.getButton(FormSheet.BTNID_OK).
212 setAction(
213 new sale.Action()
214 {
215 public void doAction (SaleProcess p, SalesPoint sp)
216 {
217 // Transition zum Bezahlen als naechste Transition setzen
218 selectionGate.setNextTransition(toPayingTransition);
219 }
220 }
221 );
222
223 // "Cancel"-Button neu definieren
224 fs.getButton(FormSheet.BTNID_CANCEL).
225 setAction(
226 new sale.Action()
227 {
228 public void doAction (SaleProcess p, SalesPoint sp)
229 {
230 // Transition zum Rollback-Gate als naechste Transition setzen
231 selectionGate.setNextTransition(
232 GateChangeTransition.CHANGE_TO_ROLLBACK_GATE);
233 }
234 }
235 );
236 }
237 }
238 );
239
240 // erstelltes FormSheet am zu betretenden Gate setzen
241 selectionGate.setFormSheet(ttfs);
242
243 // als naechstes zu betretendes Gate zurueckgeben
244 return selectionGate;
245 }
246 };
247
248
249 //////////////////////////////////////////////////
250 /// Rent-Gate ////////////////////////////////////
251 //////////////////////////////////////////////////
252
253
254 // Gate zum Ausleihen/Bezahlen anlegen
255 // Das FormSheet wird durch die Transition waehrend der Laufzeit erzeugt
256 rentGate = new UIGate(null, null);
257
258 // Transition zum Gate, an dem zu bezahlen ist
259 toPayingTransition =
260 new Transition()
261 {
262 public Gate perform(SaleProcess pOwner, User usr)
263 {
264 // Parameter zum Aufsummieren des Datenkorbes festlegen
265 final DataBasketCondition dbc =
266 DataBasketConditionImpl.allStockItemsWithSource(cs);
267 BasketEntryValue bev = BasketEntryValues.ONLY_STOCK_ITEMS;
268 QuoteValue qvSum = new QuoteValue(new IntegerValue(0), new IntegerValue(0));
269
270 // ...und Datenkorb damit aufsummieren
271 pOwner.getBasket().sumBasket (dbc, bev, qvSum);
272
273 // zu zahlenden Betrag ermitteln
274 toPayValue = (IntegerValue)qvSum.getBid();
275
276 // FormSheet für das naechste Gate erstellen
277 FormSheet tif = new TextInputForm("Paying",
278 "You have to pay " +
279 myCurrency.toString (toPayValue) + ".",
280 myCurrency.toString (toPayValue)
281 );
282
283 // FormSheetContentCreator zum Einbauen der Buttons anmelden
284 tif.addContentCreator(
285 new FormSheetContentCreator()
286 {
287 protected void createFormSheetContent(FormSheet fs)
288 {
289 // als 'final' markierte Version des FormSheets anlegen
290 final TextInputForm tifFinal = (TextInputForm)fs;
291
292 // der Cancel-Button steht im Weg und wird zunaechst entfernt
293 fs.removeButton(FormSheet.BTNID_CANCEL);
294
295 // "OK"-Button neu definieren
296 fs.getButton(FormSheet.BTNID_OK).
297 setAction(
298 new sale.Action()
299 {
300 public void doAction (SaleProcess p, SalesPoint sp)
301 {
302 try {
303 // eingegebenen Text verarbeiten
304 paidValue = (IntegerValue)myCurrency.parse(tifFinal.getText());
305
306 // Der Iterator ueber die zu leihenden Videos wird initialisiert
307 videoIterator = db.iterator(dbc);
308
309 // ...und naechste Transition setzen
310 rentGate.setNextTransition(toDecisionTransition);
311 }
312 catch(ParseException pexc) {
313 // eingegebener Text konnte nicht verarbeitet werden
314 // Meldung erzeugen und ausgeben
315 MsgForm mf = new MsgForm ("Error",
316 "The specified amount does " +
317 "not have an appropriate format.");
318
319 try {
320 p.getContext().popUpFormSheet (p, mf);
321 }
322 catch(InterruptedException iexc) {
323 }
324 }
325 }
326 }
327 );
328
329 // "Back"-Button einbauen
330 fs.addButton ("Back", 101,
331 new sale.Action()
332 {
333 public void doAction (SaleProcess p, SalesPoint sp)
334 {
335 // naechste Transition setzen, fuehrt ohne weitere Aktionen
336 // zum Auswahl-Gate
337 rentGate.setNextTransition(
338 new GateChangeTransition(selectionGate));
339 }
340 }
341 );
342
343 // "Cancel"-Button wieder einbauen
344 fs.addButton ("Cancel", 102,
345 new sale.Action()
346 {
347 public void doAction (SaleProcess p, SalesPoint sp)
348 {
349 // naechste Transition setzen, fuehrt zum Rollback-Gate
350 rentGate.setNextTransition(
351 GateChangeTransition.CHANGE_TO_ROLLBACK_GATE);
352 }
353 }
354 );
355
356 }
357 }
358 );
359
360 // FormSheet am entsprechenden Gate setzen
361 rentGate.setFormSheet(tif);
362
363 // ...und naechstes zu betretendes Gate zurueckgeben
364 return rentGate;
365 }
366 };
367
368
369 //////////////////////////////////////////////////
370 /// Decision-Gate ////////////////////////////////
371 //////////////////////////////////////////////////
372
373
374 // Transition zum Entscheidungsgate
375 toDecisionTransition =
376 new Transition()
377 {
378 public Gate perform (SaleProcess pOwner, User usr)
379 {
380 // ausreichend Geld gegeben?
381 if (paidValue.compareTo (toPayValue) >= 0)
382 {
383 // zu zahlenden Betrag im Safe der Videomaschine ablegen, wenn
384 // ueberhaupt etwas zu bezahlen ist
385 if (toPayValue.getValue().intValue() > 0)
386 ((CountingStock)Shop.getTheShop().
387 getStock("coin slot")).add(CurrencyImpl.PFENNIG_STCK_1,
388 toPayValue.getValue().intValue(), pOwner.getBasket());
389
390 // Genau richtig gezahlt? - payAssessment entsprechend belegen
391 if (paidValue.compareTo(toPayValue) == 0)
392 payAssessment = 0;
393 else
394 payAssessment = 1;
395 }
396 // nein, zuwenig bezahlt - payAssessment entsprechend belegen
397 else
398 payAssessment = -1;
399
400 // Entscheidungsgate als naechstes zu betretendes Gate zurueckgeben
401 return decisionGate;
402 }
403 };
404
405
406 // Gate anlegen, das entscheidet, ob Wechselgeld gegeben, zum Bezahlen
407 // oder zum Commit-Gate gegangen wird
408 decisionGate =
409 new Gate()
410 {
411 public Transition getNextTransition(SaleProcess pOwner, User usr)
412 throws InterruptedException
413 {
414 switch(payAssessment)
415 {
416 // zuwenig bezahlt - Message anzeigen und zurueck zum Bezahlen
417 case -1:
418 // FehlerFormSheet erzeugen
419 FormSheet mf = new MsgForm("Error",
420 "You have to pay more!",
421 false);
422 // mit Hilfe des ProcessContext das FormSheet anzeigen
423 pOwner.getContext().popUpFormSheet(pOwner, mf);
424
425 return new GateChangeTransition(rentGate);
426
427 // genau richtig bezahlt - Transaktion ausfuehren - zum Commit-Gate
428 case 0:
429 // Ausleihvorgang ausfuehren
430 commitTransfer();
431
432 return GateChangeTransition.CHANGE_TO_COMMIT_GATE;
433
434 // zuviel bezahlt - zur Wechselgeldausgabe
435 case 1:
436 // Ausleihvorgang ausfuehren
437 commitTransfer();
438
439 return toGetChangeTransition;
440
441 // falscher Wert in payAssessment - Fehlermeldung und Abbruch
442 default:
443 FormSheet mf2 = new MsgForm("Error",
444 "Internal error at Decision Gate. " +
445 "Will quit process.",
446 false);
447 pOwner.getContext().popUpFormSheet (pOwner, mf2);
448 return GateChangeTransition.CHANGE_TO_QUIT_GATE;
449 }
450 }
451
452 public void commitTransfer()
453 {
454 // aktuelles Datum holen
455 Object date = Shop.getTheShop().getTimer().getTime();
456 while (videoIterator.hasNext())
457 {
458 CountingStockItemDBEntry cassetteItem =
459 (CountingStockItemDBEntry)videoIterator.next();
460 int number = cassetteItem.count();
461 for (; number > 0; number --)
462 {
463 // Videos in den Bestand des Kunden uebernehmen
464 customer.addVideoCassette(new
465 CassetteStoringStockItem(cassetteItem.getSecondaryKey(), date));
466
467 // Vorgang in Logdatei eintragen
468 try {
469 Log.getGlobalLog().log(new MyLoggable(cassetteItem.getSecondaryKey(),
470 customer.getCustomerID(),
471 date));
472 }
473 catch (LogNoOutputStreamException lnose) {
474 }
475 catch (IOException ioe) {
476 }
477 }
478 }
479 }
480 };
481
482
483 //////////////////////////////////////////////////
484 /// GetChange-Gate ///////////////////////////////
485 //////////////////////////////////////////////////
486
487
488 // Gate zum Ausgeben des Wechselgeldes anlegen
489 // Das FormSheet wird durch die Transition waehrend der Laufzeit erzeugt
490 getChangeGate = new UIGate(null, null);
491
492 // Transition zum Wechselgeld-Gate
493 toGetChangeTransition =
494 new Transition()
495 {
496 public Gate perform(SaleProcess pOwner, User usr)
497 {
498 // am Gate darzustellendes FormSheet
499 MsgForm mf = new MsgForm("Get Change",
500 "You get " +
501 myCurrency.toString((IntegerValue)paidValue.subtract(toPayValue)) +
502 " Change.");
503
504 // ContentCreator zur Neubelegung des "OK"-Buttons hinzufuegen
505 mf.addContentCreator(
506 new FormSheetContentCreator()
507 {
508 public void createFormSheetContent(FormSheet fs)
509 {
510 // neue Aktion setzen
511 fs.getButton(FormSheet.BTNID_OK).setAction(
512 new Action()
513 {
514 public void doAction(SaleProcess p, SalesPoint sp)
515 {
516 // zum Commit-Gate fuehrende Transition als
517 // naechste Transition setzen
518 getChangeGate.setNextTransition(
519 GateChangeTransition.CHANGE_TO_COMMIT_GATE);
520 }
521 }
522 );
523 }
524 }
525 );
526
527 // erstelltes FormSheet am zu betretenden Gate setzen
528 getChangeGate.setFormSheet(mf);
529
530 // als naechstes zu betretendes Gate zurueckgeben
531 return getChangeGate;
532 }
533 };
534 }
535
536 //// public methods ////////////////////////////////////////////////////////
537
538 /**
539 * Gibt das Startgate des Prozesses zurück.
540 */
541 public Gate getInitialGate()
542 {
543 // Automat aufbauen
544 setupMachine();
545
546 // ...und Capability-Gate als Startgate zurueckgeben
547 return capabilityGate;
548 }
549
550 /**
551 * Übergibt das Log-Gate. Hier das Stop-Gate, da beim Beenden des
552 * Prozesses kein Log-Eintrag geschrieben werden soll.
553 */
554 public Gate getLogGate()
555 {
556 return getStopGate();
557 }
558 }