001    package org.cocome.tradingsystem.systests.scenarios;
002    
003    import java.util.concurrent.TimeoutException;
004    
005    import org.cocome.tradingsystem.systests.interfaces.ICashBox;
006    import org.cocome.tradingsystem.systests.interfaces.ICashDesk;
007    import org.cocome.tradingsystem.systests.interfaces.IProduct;
008    import org.cocome.tradingsystem.systests.interfaces.IStorePC;
009    import org.cocome.tradingsystem.systests.util.GeneratedStockItem;
010    
011    /**
012     * This abstract class holds basic operations needed for a purchase and its
013     * variants as described in use case 1.
014     * 
015     * @author Benjamin Hummel
016     * @author Christian Pfaller
017     * @author $Author: hummel $
018     * @version $Rev: 64 $
019     * @levd.rating GREEN Rev: 64
020     */
021    public class ProcessSaleBase extends TestScenarioBase {
022    
023            /** The number of items sold for this test case. */
024            private static final int NUM_SOLD_ITEMS = 15;
025    
026            /** The number of items currently sold. */
027            protected int currentlySold = 0;
028    
029            /** The store used for this sale */
030            protected IStorePC store;
031    
032            /** The cash desk used for this sale */
033            protected ICashDesk cashDesk;
034    
035            /** The cash box used for this sale */
036            protected ICashBox cashBox;
037    
038            /** Array which holds the expected remaining amount of a product in the store */
039            protected int[] expectedAmounts;
040    
041            /** The list of products which where bought */
042            protected IProduct[] products;
043    
044            /** Holds the sum to pay */
045            protected int priceSum;
046    
047            /** Setup only a single store with two cash desks. */
048            @Override
049            protected void setUp() throws Exception {
050                    super.setUp();
051                    productGenerator.generate(100);
052                    createStore(3);
053            }
054    
055            /**
056             * Executes a standard purchase process at a cash desk with no exceptions.
057             * Payment will be by cash.
058             */
059            public void purchase() throws Exception {
060                    initializeCashDesk(0, 0);
061                    startNewSale();
062                    enterAllRemainingProducts();
063    
064                    finishSale();
065    
066                    handleCashPayment();
067    
068                    updateInventory();
069            }
070    
071            /**
072             * Executes actions for initializing cash desk when a customer arrives
073             * there. Corresponds to step 1 of use case 1.
074             * 
075             * @param storeIndex
076             *            the index of the store used.
077             * @param cashDeskIndex
078             *            the index of the cash desk in the store.
079             */
080            protected void initializeCashDesk(int storeIndex, int cashDeskIndex)
081                            throws Exception {
082                    // 1. The customer arrives at cash desk with goods and/or services to
083                    // purchase.
084                    store = stores.get(storeIndex).getStorePC();
085                    cashDesk = stores.get(storeIndex).getCashDesk(cashDeskIndex);
086                    cashBox = cashDesk.getCashBox();
087            }
088    
089            /**
090             * Executes actions for starting a new sale with a default number of items.
091             * Corresponds to step 2 of use case 1.
092             */
093            protected void startNewSale() throws Exception {
094                    startNewSale(NUM_SOLD_ITEMS);
095            }
096    
097            /**
098             * Executes actions for starting a new sale. Corresponds to step 2 of use
099             * case 1.
100             * 
101             * @param how_many_items
102             *            the number of items the sale should contain in total
103             */
104            protected void startNewSale(int how_many_items) throws Exception {
105                    // 2. The cashier starts new sale by pressing a button at the cash box.
106                    cashBox.startNewSale();
107    
108                    priceSum = 0;
109                    currentlySold = 0;
110                    expectedAmounts = new int[how_many_items];
111                    products = new IProduct[how_many_items];
112            }
113    
114            /**
115             * Executes actions for entering products in the cashbox. This is done by
116             * using the bar code scanner. Correspondes to steps 3 and 4 of use case 1.
117             * This method enters all remaining products at once.
118             */
119            protected void enterAllRemainingProducts() throws Exception,
120                            TimeoutException {
121                    enterProducts(products.length - currentlySold);
122            }
123    
124            /**
125             * Executes actions for entering products in the cashbox. This is done by
126             * using the bar code scanner. Correspondes to steps 3 and 4 of use case 1.
127             * 
128             * @param howMany
129             *            the number of products to be sold next.
130             */
131            protected void enterProducts(int howMany) throws Exception,
132                            TimeoutException {
133                    for (int i = 0; i < howMany && currentlySold < products.length; ++i, ++currentlySold) {
134                            // 3. The cashier enters item identifier.
135                            GeneratedStockItem stockItem = stores.get(0).getStockGenerator()
136                                            .getGeneratedStockItem(2 * currentlySold + 3);
137                            products[currentlySold] = stockItem.getProduct().getProduct();
138                            expectedAmounts[currentlySold] = stockItem.getAmount() - 1;
139                            priceSum += stockItem.getSalesPrice();
140    
141                            int barcode = stockItem.getProduct().getBarcode();
142                            // This can be done ... by using the barcode scanner.
143                            cashDesk.getBarcodeScanner().sendBarcode(barcode);
144    
145                            // 4. The system records sale item and presents product description,
146                            // price, and running total.
147                            cashDesk.getUserDisplay().waitForUpdate(1000);
148                            assertTrue(cashDesk.getUserDisplay().isPriceShown(
149                                            stockItem.getSalesPrice()));
150                            assertTrue(cashDesk.getUserDisplay().isProductNameShown(
151                                            stockItem.getProduct().getName()));
152                    }
153            }
154    
155            /**
156             * Executes actions for finishing sale (after entering all products in
157             * cashbox, before payment). Corresponds to step 5 of use case 1.
158             */
159            protected void finishSale() throws Exception {
160                    // 5. The cashier indicates the end of entering items by pressing the
161                    // SaleFinished-button at the cash box.
162                    cashBox.finishSale();
163            }
164    
165            /**
166             * Executs actions of handling cash payment. Corresponds to step 5 a. of use
167             * case 1.
168             */
169            protected void handleCashPayment() throws Exception {
170                    // Holds the received payment cash
171                    int payment;
172    
173                    // a. The cashier presses the button for bar payment.
174                    cashBox.startCashPayment();
175    
176                    payment = priceSum + 42;
177                    // iii. The cashier enters the cash received and confirms by pressing
178                    // Enter.
179                    cashBox.enterReceivedCash(payment);
180    
181                    // i. The cash box opens. (NOTE: in the use case the cash box opens
182                    // BEFORE the amount is entered. However the reference implementation
183                    // expects the amount to be entered before opening the cash box, so we
184                    // use this order here)
185                    cashBox.waitForUpdate(1000);
186                    assertTrue("The system should open the cashbox", cashBox
187                                    .wasOpenSignalSent());
188                    cashBox.setCashboxStatus(false);
189    
190                    // iv. The received money and the change amount are displayed, and the
191                    // cashier hands over the change.
192                    cashDesk.getUserDisplay().waitForUpdate(1000);
193    
194                    // v. The cashier closes the cash box.
195                    cashBox.setCashboxStatus(true);
196            }
197    
198            /**
199             * Executes actions after reciept of payment. Corresponds to steps 6, 7 and
200             * 8 of use case 1.
201             */
202            protected void updateInventory() throws Exception {
203                    // 6. The system logs completed sale and sends sale information to the
204                    // inventory system to update the stock.
205                    Thread.sleep(500);
206                    for (int i = 0; i < currentlySold; ++i) {
207                            assertEquals("The amount should now be as calculated", store
208                                            .getAmount(products[i]), expectedAmounts[i]);
209                    }
210    
211                    // 7. The system prints the receipt and the cashier hands out the
212                    // receipt.
213                    cashDesk.getPrinter().waitForUpdate(500);
214    
215                    // 8. The customer leaves with receipt and goods.
216            }
217    
218    }