@Test public void testBuy() throws Exception { final CurrencyPair btc = new CurrencyPair("BTC"); PortfolioEntry portfolioEntry = new PortfolioEntry(); portfolioEntry.setPrimaryKey(new PortfolioId().toString()); when(userServiceFacade.obtainPortfolioForUser()).thenReturn(portfolioEntry); when(userServiceFacade.isWithdrawPasswordSet()).thenReturn(true); when(userServiceFacade.isWithdrawPasswordMatched(eq("2123423aafsdf"))).thenReturn(true); portfolioEntry.setPrimaryKey(new PortfolioId().toString()); when(userServiceFacade.obtainPortfolioForUser()).thenReturn(portfolioEntry); when(userServiceFacade.isWithdrawPasswordSet()).thenReturn(true); OrderBookEntry orderBookEntry = new OrderBookEntry(); SellOrder sellOrder = new SellOrder(); CoinEntry coinEntry = new CoinEntry(); when(tradeServiceFacade.loadCoin(eq(btc.getBaseCurrency()))).thenReturn(coinEntry); when(tradeServiceFacade.loadOrderBookByCurrencyPair(eq(btc))).thenReturn(orderBookEntry); when(tradeServiceFacade.prepareSellOrder(eq(btc.getBaseCurrency()), eq(btc), eq(orderBookEntry), eq(portfolioEntry))).thenReturn(sellOrder); when(tradeServiceFacade.calculateBuyOrderEffectiveAmount(any(BuyOrder.class))) .thenReturn(BigMoney.of(CurrencyUnit.of(btc.getCounterCurrency()), BigDecimal.valueOf(32.988).multiply(BigDecimal.valueOf(1.3)))); mockMvc.perform(post("/buy/" + btc.getBaseCurrency()) .param("itemPrice", "32.988") .param("tradeAmount", "1.2") .param("tradingPassword", "2123423aafsdf") ).andExpect(status().isOk()) .andExpect(model().attributeExists( "orderBook", "sellOrder", "buyOrder", "coin", "activeOrders", "buyOrders", "sellOrders", "executedTrades" )) .andExpect(model().attributeHasFieldErrors("buyOrder", "tradeAmount")); verify(userServiceFacade).isWithdrawPasswordSet(); verify(userServiceFacade).isWithdrawPasswordMatched(eq("2123423aafsdf")); verify(tradeServiceFacade).calculateBuyOrderEffectiveAmount(any(BuyOrder.class)); verify(tradeServiceFacade).loadCoin(eq(btc.getBaseCurrency())); verify(tradeServiceFacade).loadOrderBookByCurrencyPair(eq(btc)); verify(tradeServiceFacade).prepareSellOrder(eq(btc.getBaseCurrency()), eq(btc), eq(orderBookEntry), eq(portfolioEntry)); verify(tradeServiceFacade).findOrderAggregatedPrice(anyString(), eq(OrderType.BUY), any(Date.class)); verify(tradeServiceFacade).findOrderAggregatedPrice(anyString(), eq(OrderType.SELL), any(Date.class)); verify(tradeServiceFacade).findExecutedTrades(anyString()); verify(tradeServiceFacade).findUserActiveOrders(anyString(), anyString()); }
@RequestMapping(value = "/buy/{coinId}", method = RequestMethod.POST) public String buy(@PathVariable String coinId, @ModelAttribute("buyOrder") @Valid BuyOrder order, BindingResult bindingResult, Model model) { CurrencyPair currencyPair = new CurrencyPair(coinId); CurrencyUnit priceCcy = currencyPair.getCounterCurrencyUnit(); CurrencyUnit coinCcy = currencyPair.getBaseCurrencyUnit(); OrderBookEntry orderBookEntry = tradeServiceFacade.loadOrderBookByCurrencyPair(currencyPair); PortfolioEntry portfolioEntry = userServiceFacade.obtainPortfolioForUser(); if (hasErrors(order, bindingResult, portfolioEntry)) { fillFailedToBuyModels(coinId, currencyPair, model, orderBookEntry, portfolioEntry); return "/index"; } final BigDecimal tradeAmount = order.getTradeAmount(); final BigDecimal itemPrice = order.getItemPrice(); final Money price = Money.of(priceCcy, itemPrice, RoundingMode.HALF_EVEN); final Money btcAmount = Money.of(coinCcy, tradeAmount, RoundingMode.HALF_EVEN); final BigMoney totalMoney = tradeServiceFacade.calculateBuyOrderEffectiveAmount(order); BigMoney availableMoney = portfolioEntry.obtainMoneyToSpend(); if (availableMoney == null || availableMoney.isLessThan(totalMoney)) { bindingResult.rejectValue("tradeAmount", "error.order.buy.notenoughmoney", "Not enough cash to spend to buy the items for the price you want"); logger.info("rejected a buy order with price {}, amount {}, total money {}: {}.", price, btcAmount, totalMoney, order); fillFailedToBuyModels(coinId, currencyPair, model, orderBookEntry, portfolioEntry); return "/index"; } final TransactionId transactionId = new TransactionId(); logger.info("placing a buy transaction {} with price {}, amount {}, total money {}: {}.", transactionId, price, btcAmount, totalMoney, order); tradeServiceFacade.buyOrder(transactionId, coinId, currencyPair, orderBookEntry.getPrimaryKey(), portfolioEntry.getPrimaryKey(), btcAmount.toBigMoney(), price.toBigMoney()); logger.info("Buy order {} dispatched... ", order); return "redirect:/"; }
TradeController { @RequestMapping(value = "/buy/{coinId}", method = RequestMethod.POST) public String buy(@PathVariable String coinId, @ModelAttribute("buyOrder") @Valid BuyOrder order, BindingResult bindingResult, Model model) { CurrencyPair currencyPair = new CurrencyPair(coinId); CurrencyUnit priceCcy = currencyPair.getCounterCurrencyUnit(); CurrencyUnit coinCcy = currencyPair.getBaseCurrencyUnit(); OrderBookEntry orderBookEntry = tradeServiceFacade.loadOrderBookByCurrencyPair(currencyPair); PortfolioEntry portfolioEntry = userServiceFacade.obtainPortfolioForUser(); if (hasErrors(order, bindingResult, portfolioEntry)) { fillFailedToBuyModels(coinId, currencyPair, model, orderBookEntry, portfolioEntry); return "/index"; } final BigDecimal tradeAmount = order.getTradeAmount(); final BigDecimal itemPrice = order.getItemPrice(); final Money price = Money.of(priceCcy, itemPrice, RoundingMode.HALF_EVEN); final Money btcAmount = Money.of(coinCcy, tradeAmount, RoundingMode.HALF_EVEN); final BigMoney totalMoney = tradeServiceFacade.calculateBuyOrderEffectiveAmount(order); BigMoney availableMoney = portfolioEntry.obtainMoneyToSpend(); if (availableMoney == null || availableMoney.isLessThan(totalMoney)) { bindingResult.rejectValue("tradeAmount", "error.order.buy.notenoughmoney", "Not enough cash to spend to buy the items for the price you want"); logger.info("rejected a buy order with price {}, amount {}, total money {}: {}.", price, btcAmount, totalMoney, order); fillFailedToBuyModels(coinId, currencyPair, model, orderBookEntry, portfolioEntry); return "/index"; } final TransactionId transactionId = new TransactionId(); logger.info("placing a buy transaction {} with price {}, amount {}, total money {}: {}.", transactionId, price, btcAmount, totalMoney, order); tradeServiceFacade.buyOrder(transactionId, coinId, currencyPair, orderBookEntry.getPrimaryKey(), portfolioEntry.getPrimaryKey(), btcAmount.toBigMoney(), price.toBigMoney()); logger.info("Buy order {} dispatched... ", order); return "redirect:/"; } }
TradeController { @RequestMapping(value = "/buy/{coinId}", method = RequestMethod.POST) public String buy(@PathVariable String coinId, @ModelAttribute("buyOrder") @Valid BuyOrder order, BindingResult bindingResult, Model model) { CurrencyPair currencyPair = new CurrencyPair(coinId); CurrencyUnit priceCcy = currencyPair.getCounterCurrencyUnit(); CurrencyUnit coinCcy = currencyPair.getBaseCurrencyUnit(); OrderBookEntry orderBookEntry = tradeServiceFacade.loadOrderBookByCurrencyPair(currencyPair); PortfolioEntry portfolioEntry = userServiceFacade.obtainPortfolioForUser(); if (hasErrors(order, bindingResult, portfolioEntry)) { fillFailedToBuyModels(coinId, currencyPair, model, orderBookEntry, portfolioEntry); return "/index"; } final BigDecimal tradeAmount = order.getTradeAmount(); final BigDecimal itemPrice = order.getItemPrice(); final Money price = Money.of(priceCcy, itemPrice, RoundingMode.HALF_EVEN); final Money btcAmount = Money.of(coinCcy, tradeAmount, RoundingMode.HALF_EVEN); final BigMoney totalMoney = tradeServiceFacade.calculateBuyOrderEffectiveAmount(order); BigMoney availableMoney = portfolioEntry.obtainMoneyToSpend(); if (availableMoney == null || availableMoney.isLessThan(totalMoney)) { bindingResult.rejectValue("tradeAmount", "error.order.buy.notenoughmoney", "Not enough cash to spend to buy the items for the price you want"); logger.info("rejected a buy order with price {}, amount {}, total money {}: {}.", price, btcAmount, totalMoney, order); fillFailedToBuyModels(coinId, currencyPair, model, orderBookEntry, portfolioEntry); return "/index"; } final TransactionId transactionId = new TransactionId(); logger.info("placing a buy transaction {} with price {}, amount {}, total money {}: {}.", transactionId, price, btcAmount, totalMoney, order); tradeServiceFacade.buyOrder(transactionId, coinId, currencyPair, orderBookEntry.getPrimaryKey(), portfolioEntry.getPrimaryKey(), btcAmount.toBigMoney(), price.toBigMoney()); logger.info("Buy order {} dispatched... ", order); return "redirect:/"; }  }
TradeController { @RequestMapping(value = "/buy/{coinId}", method = RequestMethod.POST) public String buy(@PathVariable String coinId, @ModelAttribute("buyOrder") @Valid BuyOrder order, BindingResult bindingResult, Model model) { CurrencyPair currencyPair = new CurrencyPair(coinId); CurrencyUnit priceCcy = currencyPair.getCounterCurrencyUnit(); CurrencyUnit coinCcy = currencyPair.getBaseCurrencyUnit(); OrderBookEntry orderBookEntry = tradeServiceFacade.loadOrderBookByCurrencyPair(currencyPair); PortfolioEntry portfolioEntry = userServiceFacade.obtainPortfolioForUser(); if (hasErrors(order, bindingResult, portfolioEntry)) { fillFailedToBuyModels(coinId, currencyPair, model, orderBookEntry, portfolioEntry); return "/index"; } final BigDecimal tradeAmount = order.getTradeAmount(); final BigDecimal itemPrice = order.getItemPrice(); final Money price = Money.of(priceCcy, itemPrice, RoundingMode.HALF_EVEN); final Money btcAmount = Money.of(coinCcy, tradeAmount, RoundingMode.HALF_EVEN); final BigMoney totalMoney = tradeServiceFacade.calculateBuyOrderEffectiveAmount(order); BigMoney availableMoney = portfolioEntry.obtainMoneyToSpend(); if (availableMoney == null || availableMoney.isLessThan(totalMoney)) { bindingResult.rejectValue("tradeAmount", "error.order.buy.notenoughmoney", "Not enough cash to spend to buy the items for the price you want"); logger.info("rejected a buy order with price {}, amount {}, total money {}: {}.", price, btcAmount, totalMoney, order); fillFailedToBuyModels(coinId, currencyPair, model, orderBookEntry, portfolioEntry); return "/index"; } final TransactionId transactionId = new TransactionId(); logger.info("placing a buy transaction {} with price {}, amount {}, total money {}: {}.", transactionId, price, btcAmount, totalMoney, order); tradeServiceFacade.buyOrder(transactionId, coinId, currencyPair, orderBookEntry.getPrimaryKey(), portfolioEntry.getPrimaryKey(), btcAmount.toBigMoney(), price.toBigMoney()); logger.info("Buy order {} dispatched... ", order); return "redirect:/"; }  @Autowired void setTradeServiceFacade(TradeServiceFacade tradeServiceFacade); @Autowired void setUserServiceFacade(UserServiceFacade userServiceFacade); @SuppressWarnings("unchecked") @RequestMapping(value = "index", method = RequestMethod.GET) String get(Model model); @SuppressWarnings("unchecked") @RequestMapping(value = "refresh", method = RequestMethod.GET) String refresh(); @RequestMapping(value = "/coin/{coinId}", method = RequestMethod.GET) String details(@PathVariable String coinId, Model model); @RequestMapping(value = "/sell/{coinId}", method = RequestMethod.POST) String sell(@PathVariable String coinId,
                       @ModelAttribute("sellOrder") @Valid SellOrder order,
                       BindingResult bindingResult, Model model); @RequestMapping(value = "/buy/{coinId}", method = RequestMethod.POST) String buy(@PathVariable String coinId,
                      @ModelAttribute("buyOrder") @Valid BuyOrder order,
                      BindingResult bindingResult, Model model); }
TradeController { @RequestMapping(value = "/buy/{coinId}", method = RequestMethod.POST) public String buy(@PathVariable String coinId, @ModelAttribute("buyOrder") @Valid BuyOrder order, BindingResult bindingResult, Model model) { CurrencyPair currencyPair = new CurrencyPair(coinId); CurrencyUnit priceCcy = currencyPair.getCounterCurrencyUnit(); CurrencyUnit coinCcy = currencyPair.getBaseCurrencyUnit(); OrderBookEntry orderBookEntry = tradeServiceFacade.loadOrderBookByCurrencyPair(currencyPair); PortfolioEntry portfolioEntry = userServiceFacade.obtainPortfolioForUser(); if (hasErrors(order, bindingResult, portfolioEntry)) { fillFailedToBuyModels(coinId, currencyPair, model, orderBookEntry, portfolioEntry); return "/index"; } final BigDecimal tradeAmount = order.getTradeAmount(); final BigDecimal itemPrice = order.getItemPrice(); final Money price = Money.of(priceCcy, itemPrice, RoundingMode.HALF_EVEN); final Money btcAmount = Money.of(coinCcy, tradeAmount, RoundingMode.HALF_EVEN); final BigMoney totalMoney = tradeServiceFacade.calculateBuyOrderEffectiveAmount(order); BigMoney availableMoney = portfolioEntry.obtainMoneyToSpend(); if (availableMoney == null || availableMoney.isLessThan(totalMoney)) { bindingResult.rejectValue("tradeAmount", "error.order.buy.notenoughmoney", "Not enough cash to spend to buy the items for the price you want"); logger.info("rejected a buy order with price {}, amount {}, total money {}: {}.", price, btcAmount, totalMoney, order); fillFailedToBuyModels(coinId, currencyPair, model, orderBookEntry, portfolioEntry); return "/index"; } final TransactionId transactionId = new TransactionId(); logger.info("placing a buy transaction {} with price {}, amount {}, total money {}: {}.", transactionId, price, btcAmount, totalMoney, order); tradeServiceFacade.buyOrder(transactionId, coinId, currencyPair, orderBookEntry.getPrimaryKey(), portfolioEntry.getPrimaryKey(), btcAmount.toBigMoney(), price.toBigMoney()); logger.info("Buy order {} dispatched... ", order); return "redirect:/"; }  @Autowired void setTradeServiceFacade(TradeServiceFacade tradeServiceFacade); @Autowired void setUserServiceFacade(UserServiceFacade userServiceFacade); @SuppressWarnings("unchecked") @RequestMapping(value = "index", method = RequestMethod.GET) String get(Model model); @SuppressWarnings("unchecked") @RequestMapping(value = "refresh", method = RequestMethod.GET) String refresh(); @RequestMapping(value = "/coin/{coinId}", method = RequestMethod.GET) String details(@PathVariable String coinId, Model model); @RequestMapping(value = "/sell/{coinId}", method = RequestMethod.POST) String sell(@PathVariable String coinId,
                       @ModelAttribute("sellOrder") @Valid SellOrder order,
                       BindingResult bindingResult, Model model); @RequestMapping(value = "/buy/{coinId}", method = RequestMethod.POST) String buy(@PathVariable String coinId,
                      @ModelAttribute("buyOrder") @Valid BuyOrder order,
                      BindingResult bindingResult, Model model);  }