diff --git a/example/basket/src/main/scala/org/finos/vuu/core/module/basket/BasketConstants.scala b/example/basket/src/main/scala/org/finos/vuu/core/module/basket/BasketConstants.scala index 6de498283..8e8baf046 100644 --- a/example/basket/src/main/scala/org/finos/vuu/core/module/basket/BasketConstants.scala +++ b/example/basket/src/main/scala/org/finos/vuu/core/module/basket/BasketConstants.scala @@ -2,7 +2,7 @@ package org.finos.vuu.core.module.basket object BasketConstants { - object Side{ + object Side { final val Buy = "BUY" final val Sell = "SELL" } diff --git a/example/basket/src/main/scala/org/finos/vuu/core/module/basket/BasketModule.scala b/example/basket/src/main/scala/org/finos/vuu/core/module/basket/BasketModule.scala index 70a5683f9..8630bcb8e 100644 --- a/example/basket/src/main/scala/org/finos/vuu/core/module/basket/BasketModule.scala +++ b/example/basket/src/main/scala/org/finos/vuu/core/module/basket/BasketModule.scala @@ -202,9 +202,4 @@ object BasketModule extends DefaultModule { final val OrderStatus = "orderStatus" final val FilledQty = "filledQty" } - - object Sides{ - final val Buy = "Buy" - final val Sell = "Sell" - } } diff --git a/example/basket/src/main/scala/org/finos/vuu/core/module/basket/provider/BasketConstituentProvider.scala b/example/basket/src/main/scala/org/finos/vuu/core/module/basket/provider/BasketConstituentProvider.scala index 4b1ec3d06..a87c400ed 100644 --- a/example/basket/src/main/scala/org/finos/vuu/core/module/basket/provider/BasketConstituentProvider.scala +++ b/example/basket/src/main/scala/org/finos/vuu/core/module/basket/provider/BasketConstituentProvider.scala @@ -34,7 +34,7 @@ class BasketConstituentProvider(val table: DataTable)(implicit lifecycle: Lifecy val weighting = row("Weighting") val side = BasketConstants.Side.Buy val ricBasketId = symbol + "." + basketId - table.processUpdate(ricBasketId, RowWithData(symbol, Map( + table.processUpdate(ricBasketId, RowWithData(ricBasketId, Map( Ric -> symbol, BasketId -> basketId, RicBasketId -> ricBasketId, diff --git a/example/basket/src/main/scala/org/finos/vuu/core/module/basket/provider/BasketTradingConstituentProvider.scala b/example/basket/src/main/scala/org/finos/vuu/core/module/basket/provider/BasketTradingConstituentProvider.scala index 2cc9d691d..74fb2dd71 100644 --- a/example/basket/src/main/scala/org/finos/vuu/core/module/basket/provider/BasketTradingConstituentProvider.scala +++ b/example/basket/src/main/scala/org/finos/vuu/core/module/basket/provider/BasketTradingConstituentProvider.scala @@ -19,14 +19,16 @@ class BasketTradingConstituentProvider(val table: DataTable, val omsApi: OmsApi) table.processUpdate(ack.clientOrderId, RowWithData(ack.clientOrderId, Map[String, Any](BTC.InstanceIdRic -> ack.clientOrderId, BTC.OrderStatus -> OrderStates.ACKED)),clock.now()) } - override def onCancelAck(ack: CancelAck): Unit = ??? + override def onCancelAck(ack: CancelAck): Unit = { + table.processUpdate(ack.clientOrderId, RowWithData(ack.clientOrderId, Map[String, Any](BTC.InstanceIdRic -> ack.clientOrderId, + BTC.OrderStatus -> OrderStates.CANCELLED)), clock.now()) + } override def onReplaceAck(ack: ReplaceAck): Unit = ??? override def onFill(fill: Fill): Unit = { val state = if(fill.orderQty == fill.totalFilledQty) OrderStates.FILLED else OrderStates.ACKED table.processUpdate(fill.clientOrderId, RowWithData(fill.clientOrderId, Map[String, Any](BTC.InstanceIdRic -> fill.clientOrderId, - BTC.FilledQty -> fill.totalFilledQty, BTC.OrderStatus -> state)) - ,clock.now()) + BTC.FilledQty -> fill.totalFilledQty, BTC.OrderStatus -> state)),clock.now()) } }) diff --git a/example/basket/src/main/scala/org/finos/vuu/core/module/basket/service/BasketService.scala b/example/basket/src/main/scala/org/finos/vuu/core/module/basket/service/BasketService.scala index b720d80ad..991aa248d 100644 --- a/example/basket/src/main/scala/org/finos/vuu/core/module/basket/service/BasketService.scala +++ b/example/basket/src/main/scala/org/finos/vuu/core/module/basket/service/BasketService.scala @@ -2,8 +2,9 @@ package org.finos.vuu.core.module.basket.service import com.typesafe.scalalogging.StrictLogging import org.finos.toolbox.time.Clock +import org.finos.vuu.core.module.basket.BasketConstants.Side import org.finos.vuu.core.module.basket.BasketModule -import org.finos.vuu.core.module.basket.BasketModule.{BasketConstituentTable, Sides} +import org.finos.vuu.core.module.basket.BasketModule.{BasketConstituentTable} import org.finos.vuu.core.table.{DataTable, RowData, RowWithData, TableContainer} import org.finos.vuu.net.rpc.RpcHandler import org.finos.vuu.net.{ClientSessionId, RequestContext} @@ -57,7 +58,7 @@ class BasketService(val table: DataTable, val tableContainer: TableContainer, va } private def mkTradingBasketRow(sourceBasketId: String, basketTradeName: String, basketTradeInstanceId: String) = { - RowWithData(basketTradeInstanceId, Map(BT.InstanceId -> basketTradeInstanceId, BT.Status -> "OFF-MARKET", BT.BasketId -> sourceBasketId, BT.BasketName -> basketTradeName, BT.Side -> Sides.Buy, BT.Units -> 1)) + RowWithData(basketTradeInstanceId, Map(BT.InstanceId -> basketTradeInstanceId, BT.Status -> "OFF-MARKET", BT.BasketId -> sourceBasketId, BT.BasketName -> basketTradeName, BT.Side -> Side.Buy, BT.Units -> 1)) } def createBasketFromRpc(basketId: String, name: String)(ctx: RequestContext): ViewPortAction = { diff --git a/example/basket/src/main/scala/org/finos/vuu/core/module/basket/service/BasketTradingConstituentJoinService.scala b/example/basket/src/main/scala/org/finos/vuu/core/module/basket/service/BasketTradingConstituentJoinService.scala index 66a33d5b3..41d113792 100644 --- a/example/basket/src/main/scala/org/finos/vuu/core/module/basket/service/BasketTradingConstituentJoinService.scala +++ b/example/basket/src/main/scala/org/finos/vuu/core/module/basket/service/BasketTradingConstituentJoinService.scala @@ -5,9 +5,9 @@ import org.finos.toolbox.time.Clock import org.finos.vuu.api.JoinTableDef import org.finos.vuu.core.module.basket.BasketConstants.Side import org.finos.vuu.core.module.basket.BasketModule -import org.finos.vuu.core.module.basket.BasketModule.{BasketTradingColumnNames => BTColumnName, BasketTradingConstituentColumnNames => ColumnName} +import org.finos.vuu.core.module.basket.BasketModule.{BasketConstituentColumnNames => BCColumnName, BasketTradingColumnNames => BTColumnName, BasketTradingConstituentColumnNames => ColumnName} import org.finos.vuu.core.module.basket.result.ErrorReason -import org.finos.vuu.core.table.{DataTable, JoinTable, RowWithData, TableContainer} +import org.finos.vuu.core.table.{DataTable, JoinTable, RowData, RowWithData, TableContainer} import org.finos.vuu.net.rpc.{EditRpcHandler, RpcHandler} import org.finos.vuu.net.{ClientSessionId, RequestContext} import org.finos.vuu.viewport._ @@ -64,11 +64,18 @@ class BasketTradingConstituentJoinService(val table: DataTable, val tableContain val basketId = tradeRow.get(BTColumnName.BasketId).asInstanceOf[String] val tradeUnit = tradeRow.get(BTColumnName.Units).asInstanceOf[Int] + val basketConstituentRows = getConstituentsWith(ric) //todo what to do when multiple result? + val description = + if(basketConstituentRows.nonEmpty) + basketConstituentRows.head.get(BCColumnName.Description).asInstanceOf[String] + else "" + val newRow = mkTradingConstituentRow( basketTradeInstanceId = tradeId, sourceBasketId = basketId, tradeUnit = tradeUnit, - ric = ric) + ric = ric, + description = description) //todo should we guard against adding row for ric that already exist? updateJoinTable(Array(newRow)) match { @@ -79,6 +86,12 @@ class BasketTradingConstituentJoinService(val table: DataTable, val tableContain } } + private def getConstituentsWith(ric: String): List[RowData] = { + val table = tableContainer.getTable(BasketModule.BasketConstituentTable) + val keys = table.primaryKeys.toList + keys.map(key => table.pullRow(key)).filter(_.get(BCColumnName.Ric).toString == ric) + } + private def onEditCell(key: String, columnName: String, data: Any, vp: ViewPort, session: ClientSessionId): ViewPortEditAction = { try { getBaseTable() match { @@ -180,7 +193,7 @@ class BasketTradingConstituentJoinService(val table: DataTable, val tableContain } } - private def mkTradingConstituentRow(basketTradeInstanceId: String, sourceBasketId: String, tradeUnit: Int, ric: String): RowWithData = { + private def mkTradingConstituentRow(basketTradeInstanceId: String, sourceBasketId: String, tradeUnit: Int, ric: String, description: String): RowWithData = { val constituentKey = s"$basketTradeInstanceId.$ric" val weighting: Double = 0.1 RowWithData( @@ -191,7 +204,7 @@ class BasketTradingConstituentJoinService(val table: DataTable, val tableContain ColumnName.InstanceId -> basketTradeInstanceId, ColumnName.InstanceIdRic -> constituentKey, ColumnName.Quantity -> (weighting * 100).asInstanceOf[Long], - ColumnName.Description -> "", //todo look up description from instrument table + ColumnName.Description -> description, ColumnName.Side -> Side.Buy, ColumnName.Weighting -> weighting, ColumnName.PriceStrategyId -> 2, diff --git a/example/basket/src/main/scala/org/finos/vuu/core/module/basket/service/BasketTradingService.scala b/example/basket/src/main/scala/org/finos/vuu/core/module/basket/service/BasketTradingService.scala index a738b2887..8a805e9bc 100644 --- a/example/basket/src/main/scala/org/finos/vuu/core/module/basket/service/BasketTradingService.scala +++ b/example/basket/src/main/scala/org/finos/vuu/core/module/basket/service/BasketTradingService.scala @@ -3,14 +3,18 @@ package org.finos.vuu.core.module.basket.service import com.typesafe.scalalogging.StrictLogging import org.finos.toolbox.time.Clock import org.finos.vuu.core.module.basket.BasketModule -import org.finos.vuu.core.module.basket.BasketModule.{BasketTradingConstituentTable, Sides} -import org.finos.vuu.core.table.{DataTable, RowWithData, TableContainer, ViewPortColumnCreator} +import org.finos.vuu.core.module.basket.BasketConstants.Side +import org.finos.vuu.core.module.basket.BasketModule.{BasketTradingConstituentTable} +import org.finos.vuu.core.table.{DataTable, RowData, RowWithData, TableContainer, ViewPortColumnCreator} import org.finos.vuu.net.rpc.{EditRpcHandler, RpcHandler} import org.finos.vuu.net.{ClientSessionId, RequestContext} -import org.finos.vuu.order.oms.{NewOrder, OmsApi} +import org.finos.vuu.order.oms.{CancelOrder, NewOrder, OmsApi} import org.finos.vuu.viewport._ -trait BasketTradingServiceIF extends EditRpcHandler{ + +trait BasketTradingServiceIF extends EditRpcHandler { def sendToMarket(basketInstanceId: String)(ctx: RequestContext): ViewPortAction + + def takeOffMarket(basketInstanceId: String)(ctx: RequestContext): ViewPortAction } @@ -20,18 +24,14 @@ class BasketTradingService(val table: DataTable, val tableContainer: TableContai /** - * Send basket to market + * Send basket to market rpc call */ - override def sendToMarket(name: String)(ctx: RequestContext): ViewPortAction = { - val tableRow = table.asTable.pullRow(name) - - logger.info("Sending basket to market:" + name + " (row:" + tableRow + ")") + override def sendToMarket(basketInstanceId: String)(ctx: RequestContext): ViewPortAction = { + val tableRow = table.asTable.pullRow(basketInstanceId) - val tradingConsTable = tableContainer.getTable(BasketModule.BasketTradingConstituentTable) + logger.info("Sending basket to market:" + basketInstanceId + " (row:" + tableRow + ")") - val constituents = tradingConsTable.primaryKeys.toList - .map(tradingConsTable.pullRow) - .filter(_.get(BTC.InstanceId) == name) + val constituents = getConstituents(basketInstanceId) constituents.foreach(constituentRow => { @@ -48,12 +48,43 @@ class BasketTradingService(val table: DataTable, val tableContainer: TableContai omsApi.createOrder(nos) }) - table.processUpdate(name, RowWithData(name, - Map(BT.InstanceId -> name, BT.Status -> BasketStates.ON_MARKET)), clock.now()) + updateBasketTradeStatus(basketInstanceId, state = BasketStates.ON_MARKET) ViewPortEditSuccess() } + /** + * Take basket off market rpc call + */ + override def takeOffMarket(basketInstanceId: String)(ctx: RequestContext): ViewPortAction = { + val tableRow = table.asTable.pullRow(basketInstanceId) + + logger.info("Tasking basket off market:" + basketInstanceId + " (row:" + tableRow + ")") + + updateBasketTradeStatus(basketInstanceId, BasketStates.OFF_MARKET) + + getConstituents(basketInstanceId) + .flatMap(c => omsApi.getOrderId(clientOrderId = c.get(BTC.InstanceIdRic).toString)) + .foreach(orderId => omsApi.cancelOrder(CancelOrder(orderId))) + + ViewPortEditSuccess() + } + + private def getConstituents(basketInstanceId: String): List[RowData] = { + val tradingConsTable = tableContainer.getTable(BasketModule.BasketTradingConstituentTable) + + tradingConsTable.primaryKeys.toList + .map(tradingConsTable.pullRow) + .filter(_.get(BTC.InstanceId) == basketInstanceId) + } + + private def updateBasketTradeStatus(basketInstanceId: String, state: String): Unit = { + table.processUpdate( + basketInstanceId, + RowWithData(basketInstanceId, Map(BT.InstanceId -> basketInstanceId, BT.Status -> state)), + clock.now()) + } + private def onEditCell(key: String, columnName: String, data: Any, vp: ViewPort, session: ClientSessionId): ViewPortEditAction = { logger.info("Change requested for cell value for key:" + key + "(" + columnName + ":" + data + ")") @@ -80,8 +111,8 @@ class BasketTradingService(val table: DataTable, val tableContainer: TableContai val constituents = constituentTable.primaryKeys.map(key => constituentTable.pullRow(key)).filter(_.get(BTC.InstanceId) == key) constituents.foreach(row => { val newSide = row.get(BTC.Side) match { - case Sides.Buy => Sides.Sell - case _ => Sides.Buy + case Side.Buy => Side.Sell + case _ => Side.Buy } constituentTable.processUpdate(row.key(), RowWithData(row.key(), Map(BTC.InstanceIdRic -> row.key(), BTC.Side -> newSide)), clock.now()) }) diff --git a/example/basket/src/test/scala/org/finos/vuu/core/module/basket/BasketConstituentMutateTest.scala b/example/basket/src/test/scala/org/finos/vuu/core/module/basket/BasketConstituentMutateTest.scala index 6fe045421..e3493813b 100644 --- a/example/basket/src/test/scala/org/finos/vuu/core/module/basket/BasketConstituentMutateTest.scala +++ b/example/basket/src/test/scala/org/finos/vuu/core/module/basket/BasketConstituentMutateTest.scala @@ -33,9 +33,9 @@ class BasketConstituentMutateTest extends VuuServerTestCase { vuuServer.login("testUser", "testToken") val basketName = "test_basket1" - val tradeId = GivenBasketTrade(vuuServer.tableContainer, basketName, "Buy") + val tradeId = GivenBasketTrade(vuuServer.tableContainer, basketName, "BUY") GivenPrices(vuuServer.tableContainer, List(("VOD.L", 1.1, 1.4), ("BP.L", 2.1, 2.4))) - GivenBasketTradeConstituentsJoin(vuuServer.tableContainer, tradeId, Map(("VOD.L" -> "Buy"), ("BP.L" -> "Sell"))) + GivenBasketTradeConstituentsJoin(vuuServer.tableContainer, tradeId, Map(("VOD.L" -> "BUY"), ("BP.L" -> "SELL"))) val vpBasketTrading = vuuServer.createViewPort(BasketModule.NAME, BasketTradingTable) val vpBasketTradingConsJoin = vuuServer.createViewPort(BasketModule.NAME, BasketTradingConstituentJoin) @@ -60,9 +60,9 @@ class BasketConstituentMutateTest extends VuuServerTestCase { assertVpEq(filterByVp(vpBasketTradingConsJoin, updates)) { Table( ("quantity", "side", "instanceId", "instanceIdRic", "basketId", "ric", "description", "notionalUsd", "notionalLocal", "venue", "algo", "algoParams", "pctFilled", "weighting", "priceSpread", "limitPrice", "priceStrategyId", "bid", "ask", "filledQty", "orderStatus"), - (10L, "Buy", "testUser-00001", "testUser-00001.BP.L", ".FTSE", "BP.L", "Beyond Petroleum", null, null, null, -1, null, null, 0.1, null, null, 2, 2.1, 2.4, 0, "PENDING"), - (10L, "Sell", "testUser-00001", "testUser-00001.BT.L", ".FTSE", "BT.L", "British Telecom", null, null, null, -1, null, null, 0.1, null, null, 2, null, null, 0, "PENDING"), - (10L, "Sell", "testUser-00001", "testUser-00001.VOD.L", ".FTSE", "VOD.L", "Vodafone", null, null, null, -1, null, null, 0.1, null, null, 2, 1.1, 1.4, 0, "PENDING") + (10L, "BUY", "testUser-00001", "testUser-00001.BP.L", ".FTSE", "BP.L", "Beyond Petroleum", null, null, null, -1, null, null, 0.1, null, null, 2, 2.1, 2.4, 0, "PENDING"), + (10L, "SELL", "testUser-00001", "testUser-00001.BT.L", ".FTSE", "BT.L", "British Telecom", null, null, null, -1, null, null, 0.1, null, null, 2, null, null, 0, "PENDING"), + (10L, "SELL", "testUser-00001", "testUser-00001.VOD.L", ".FTSE", "VOD.L", "Vodafone", null, null, null, -1, null, null, 0.1, null, null, 2, 1.1, 1.4, 0, "PENDING") ) } } diff --git a/example/basket/src/test/scala/org/finos/vuu/core/module/basket/BasketCreateTest.scala b/example/basket/src/test/scala/org/finos/vuu/core/module/basket/BasketCreateTest.scala index f847d55e6..9451fa78f 100644 --- a/example/basket/src/test/scala/org/finos/vuu/core/module/basket/BasketCreateTest.scala +++ b/example/basket/src/test/scala/org/finos/vuu/core/module/basket/BasketCreateTest.scala @@ -68,7 +68,7 @@ class BasketCreateTest extends VuuServerTestCase { assertVpEq(combineQsForVp(viewportBasketTrading)) { Table( ("basketId", "instanceId", "basketName", "units", "status", "filledPct", "totalNotionalUsd", "totalNotional", "fxRateToUsd", "side"), - (".FTSE", BasketTradeId.current, "TestBasket", 100, "OFF-MARKET", null, null, null, null, "Buy") + (".FTSE", BasketTradeId.current, "TestBasket", 100, "OFF-MARKET", null, null, null, null, "BUY") ) } } diff --git a/example/basket/src/test/scala/org/finos/vuu/core/module/basket/BasketMutateOffMarketTest.scala b/example/basket/src/test/scala/org/finos/vuu/core/module/basket/BasketMutateOffMarketTest.scala index 6ede3b3ef..c60cb88d1 100644 --- a/example/basket/src/test/scala/org/finos/vuu/core/module/basket/BasketMutateOffMarketTest.scala +++ b/example/basket/src/test/scala/org/finos/vuu/core/module/basket/BasketMutateOffMarketTest.scala @@ -60,9 +60,9 @@ class BasketMutateOffMarketTest extends VuuServerTestCase { assertVpEq(combineQsForVp(vpConstituent)) { Table( ("ricBasketId", "ric", "basketId", "weighting", "lastTrade", "change", "volume", "description", "side"), - ("BP.L.FTSE", "BP.L", ".FTSE", 0.1, null, null, null, "Beyond Petroleum", "Buy"), - ("BT.L.FTSE", "BT.L", ".FTSE", 0.1, null, null, null, "British Telecom", "Sell"), - ("VOD.L.FTSE", "VOD.L", ".FTSE", 0.1, null, null, null, "Vodafone", "Buy") + ("BP.L.FTSE", "BP.L", ".FTSE", 0.1, null, null, null, "Beyond Petroleum", "BUY"), + ("BT.L.FTSE", "BT.L", ".FTSE", 0.1, null, null, null, "British Telecom", "SELL"), + ("VOD.L.FTSE", "VOD.L", ".FTSE", 0.1, null, null, null, "Vodafone", "BUY") ) } @@ -80,7 +80,7 @@ class BasketMutateOffMarketTest extends VuuServerTestCase { assertVpEq(combineQsForVp(vpBasketTrading)) { Table( ("instanceId", "basketId", "basketName", "status", "units", "filledPct", "fxRateToUsd", "totalNotional", "totalNotionalUsd", "side"), - (basketTradeInstanceId, ".FTSE", "MyCustomBasket", "OFF-MARKET", 1, null, null, null, null, "Buy") + (basketTradeInstanceId, ".FTSE", "MyCustomBasket", "OFF-MARKET", 1, null, null, null, null, "BUY") ) } @@ -91,16 +91,16 @@ class BasketMutateOffMarketTest extends VuuServerTestCase { assertVpEq(combineQsForVp(vpBasketTradingCons)) { Table( ("quantity", "side", "instanceId", "instanceIdRic", "basketId", "ric", "description", "notionalUsd", "notionalLocal", "venue", "algo", "algoParams", "pctFilled", "weighting", "priceSpread", "limitPrice", "priceStrategyId", "filledQty", "orderStatus"), - (10L, "Buy", basketTradeInstanceId, s"$basketTradeInstanceId.BP.L", ".FTSE", "BP.L", "Beyond Petroleum", null, null, null, -1, null, null, 0.1, null, null, 2, 0, "PENDING"), - (10L, "Sell", basketTradeInstanceId, s"$basketTradeInstanceId.BT.L", ".FTSE", "BT.L", "British Telecom", null, null, null, -1, null, null, 0.1, null, null, 2, 0, "PENDING"), - (10L, "Buy", basketTradeInstanceId, s"$basketTradeInstanceId.VOD.L", ".FTSE", "VOD.L", "Vodafone", null, null, null, -1, null, null, 0.1, null, null, 2, 0, "PENDING") + (10L, "BUY", basketTradeInstanceId, s"$basketTradeInstanceId.BP.L", ".FTSE", "BP.L", "Beyond Petroleum", null, null, null, -1, null, null, 0.1, null, null, 2, 0, "PENDING"), + (10L, "SELL", basketTradeInstanceId, s"$basketTradeInstanceId.BT.L", ".FTSE", "BT.L", "British Telecom", null, null, null, -1, null, null, 0.1, null, null, 2, 0, "PENDING"), + (10L, "BUY", basketTradeInstanceId, s"$basketTradeInstanceId.VOD.L", ".FTSE", "VOD.L", "Vodafone", null, null, null, -1, null, null, 0.1, null, null, 2, 0, "PENDING") ) } val basketTradingService = vuuServer.getViewPortRpcServiceProxy[BasketTradingServiceIF](vpBasketTrading) When("we edit the side of the parent basket") - basketTradingService.editCellAction().func(basketTradeInstanceId, "side", "Sell", vpBasketTrading, vuuServer.session) + basketTradingService.editCellAction().func(basketTradeInstanceId, "side", "SELL", vpBasketTrading, vuuServer.session) Then("get all the updates that have occurred for all view ports from the outbound queue") val updates = combineQs(vpBasketTrading) @@ -109,7 +109,7 @@ class BasketMutateOffMarketTest extends VuuServerTestCase { assertVpEq(filterByVp(vpBasketTrading, updates)) { Table( ("instanceId", "basketId", "basketName", "status", "units", "filledPct", "fxRateToUsd", "totalNotional", "totalNotionalUsd", "side"), - (basketTradeInstanceId, ".FTSE", "MyCustomBasket", "OFF-MARKET", 1, null, null, null, null, "Sell") + (basketTradeInstanceId, ".FTSE", "MyCustomBasket", "OFF-MARKET", 1, null, null, null, null, "SELL") ) } @@ -118,9 +118,9 @@ class BasketMutateOffMarketTest extends VuuServerTestCase { assertVpEq(filterByVp(vpBasketTradingCons, updates)) { Table( ("quantity", "side", "instanceId", "instanceIdRic", "basketId", "ric", "description", "notionalUsd", "notionalLocal", "venue", "algo", "algoParams", "pctFilled", "weighting", "priceSpread", "limitPrice", "priceStrategyId", "filledQty", "orderStatus"), - (10L, "Sell", basketTradeInstanceId, s"$basketTradeInstanceId.BP.L", ".FTSE", "BP.L", "Beyond Petroleum", null, null, null, -1, null, null, 0.1, null, null, 2, 0, "PENDING"), - (10L, "Buy", basketTradeInstanceId, s"$basketTradeInstanceId.BT.L", ".FTSE", "BT.L", "British Telecom", null, null, null, -1, null, null, 0.1, null, null, 2, 0, "PENDING"), - (10L, "Sell", basketTradeInstanceId, s"$basketTradeInstanceId.VOD.L", ".FTSE", "VOD.L", "Vodafone", null, null, null, -1, null, null, 0.1, null, null, 2, 0, "PENDING") + (10L, "SELL", basketTradeInstanceId, s"$basketTradeInstanceId.BP.L", ".FTSE", "BP.L", "Beyond Petroleum", null, null, null, -1, null, null, 0.1, null, null, 2, 0, "PENDING"), + (10L, "BUY", basketTradeInstanceId, s"$basketTradeInstanceId.BT.L", ".FTSE", "BT.L", "British Telecom", null, null, null, -1, null, null, 0.1, null, null, 2, 0, "PENDING"), + (10L, "SELL", basketTradeInstanceId, s"$basketTradeInstanceId.VOD.L", ".FTSE", "VOD.L", "Vodafone", null, null, null, -1, null, null, 0.1, null, null, 2, 0, "PENDING") ) } @@ -131,9 +131,9 @@ class BasketMutateOffMarketTest extends VuuServerTestCase { assertVpEq(filterByVp(vpBasketTradingCons, combineQs(vpBasketTrading))) { Table( ("quantity", "side", "instanceId", "instanceIdRic", "basketId", "ric", "description", "notionalUsd", "notionalLocal", "venue", "algo", "algoParams", "pctFilled", "weighting", "priceSpread", "limitPrice", "priceStrategyId", "filledQty", "orderStatus"), - (100L, "Sell", basketTradeInstanceId, s"$basketTradeInstanceId.BP.L", ".FTSE", "BP.L", "Beyond Petroleum", null, null, null, -1, null, null, 0.1, null, null, 2, 0, "PENDING"), - (100L, "Buy", basketTradeInstanceId, s"$basketTradeInstanceId.BT.L", ".FTSE", "BT.L", "British Telecom", null, null, null, -1, null, null, 0.1, null, null, 2, 0, "PENDING"), - (100L, "Sell", basketTradeInstanceId, s"$basketTradeInstanceId.VOD.L", ".FTSE", "VOD.L", "Vodafone", null, null, null, -1, null, null, 0.1, null, null, 2, 0, "PENDING") + (100L, "SELL", basketTradeInstanceId, s"$basketTradeInstanceId.BP.L", ".FTSE", "BP.L", "Beyond Petroleum", null, null, null, -1, null, null, 0.1, null, null, 2, 0, "PENDING"), + (100L, "BUY", basketTradeInstanceId, s"$basketTradeInstanceId.BT.L", ".FTSE", "BT.L", "British Telecom", null, null, null, -1, null, null, 0.1, null, null, 2, 0, "PENDING"), + (100L, "SELL", basketTradeInstanceId, s"$basketTradeInstanceId.VOD.L", ".FTSE", "VOD.L", "Vodafone", null, null, null, -1, null, null, 0.1, null, null, 2, 0, "PENDING") ) } } @@ -160,7 +160,7 @@ class BasketMutateOffMarketTest extends VuuServerTestCase { val basketTradingService = vuuServer.getViewPortRpcServiceProxy[BasketTradingServiceIF](vpBasketTrading) When("we edit the side of the parent basket to same side as current value") - basketTradingService.editCellAction().func(basketTradeInstanceId, "side", "Buy", vpBasketTrading, vuuServer.session) + basketTradingService.editCellAction().func(basketTradeInstanceId, "side", "BUY", vpBasketTrading, vuuServer.session) vuuServer.runOnce() Then("get all the updates that have occurred for all view ports from the outbound queue") @@ -170,7 +170,7 @@ class BasketMutateOffMarketTest extends VuuServerTestCase { assertVpEq(filterByVp(vpBasketTrading, updates2)) { Table( ("instanceId", "basketId", "basketName", "status", "units", "filledPct", "fxRateToUsd", "totalNotional", "totalNotionalUsd", "side"), - (basketTradeInstanceId, ".FTSE", "MyCustomBasket", "OFF-MARKET", 1, null, null, null, null, "Buy") + (basketTradeInstanceId, ".FTSE", "MyCustomBasket", "OFF-MARKET", 1, null, null, null, null, "BUY") ) } @@ -178,15 +178,15 @@ class BasketMutateOffMarketTest extends VuuServerTestCase { assertVpEq(filterByVp(vpBasketTradingCons, updates2)) { Table( ("quantity", "side", "instanceId", "instanceIdRic", "basketId", "ric", "description", "notionalUsd", "notionalLocal", "venue", "algo", "algoParams", "pctFilled", "weighting", "priceSpread", "limitPrice", "priceStrategyId", "filledQty", "orderStatus"), - (10L, "Buy", basketTradeInstanceId, s"$basketTradeInstanceId.BP.L", ".FTSE", "BP.L", "Beyond Petroleum", null, null, null, -1, null, null, 0.1, null, null, 2, 0, "PENDING"), - (10L, "Sell", basketTradeInstanceId, s"$basketTradeInstanceId.BT.L", ".FTSE", "BT.L", "British Telecom", null, null, null, -1, null, null, 0.1, null, null, 2, 0, "PENDING"), - (10L, "Buy", basketTradeInstanceId, s"$basketTradeInstanceId.VOD.L", ".FTSE", "VOD.L", "Vodafone", null, null, null, -1, null, null, 0.1, null, null, 2, 0, "PENDING") + (10L, "BUY", basketTradeInstanceId, s"$basketTradeInstanceId.BP.L", ".FTSE", "BP.L", "Beyond Petroleum", null, null, null, -1, null, null, 0.1, null, null, 2, 0, "PENDING"), + (10L, "SELL", basketTradeInstanceId, s"$basketTradeInstanceId.BT.L", ".FTSE", "BT.L", "British Telecom", null, null, null, -1, null, null, 0.1, null, null, 2, 0, "PENDING"), + (10L, "BUY", basketTradeInstanceId, s"$basketTradeInstanceId.VOD.L", ".FTSE", "VOD.L", "Vodafone", null, null, null, -1, null, null, 0.1, null, null, 2, 0, "PENDING") ) } } } - //TODO oin table cannot be tested currently as it doesnt get updated when underlying table gets updated + //TODO join table cannot be tested currently as it doesnt get updated when underlying table gets updated // Scenario("Adding new constituents by ric should add it to basket trading") { // import BasketModule._ // implicit val clock: Clock = new TestFriendlyClock(10001L) @@ -217,18 +217,16 @@ class BasketMutateOffMarketTest extends VuuServerTestCase { // Then("get all the updates that have occurred for all view ports from the outbound queue") // val updates = combineQs(vpBasketTradingConsJoin) // +// //todo should basketid be where the stock was sourced from? in this case .HSI? // -// //todo map description -// //todo should basketid be where the stock was sourced from? in this case .HSI? -// -// And("assert the basket trading constituent table has not changed sides") +// And("assert the basket trading constituent table has added row") // assertVpEq(filterByVp(vpBasketTradingCons, updates)) { // Table( // ("quantity", "side", "instanceId", "instanceIdRic", "basketId", "ric", "description", "notionalUsd", "notionalLocal", "venue", "algo", "algoParams", "pctFilled", "weighting", "priceSpread", "limitPrice", "priceStrategyId", "filledQty", "orderStatus"), -// (10L, "Buy", basketTradeInstanceId, s"$basketTradeInstanceId.BP.L", ".FTSE", "BP.L", "Beyond Petroleum", null, null, null, -1, null, null, 0.1, null, null, 2, 0, "PENDING"), -// (10L, "Sell", basketTradeInstanceId, s"$basketTradeInstanceId.BT.L", ".FTSE", "BT.L", "British Telecom", null, null, null, -1, null, null, 0.1, null, null, 2, 0, "PENDING"), -// (10L, "Buy", basketTradeInstanceId, s"$basketTradeInstanceId.VOD.L", ".FTSE", "VOD.L", "Vodafone", null, null, null, -1, null, null, 0.1, null, null, 2, 0, "PENDING"), -// (10L, "Buy", basketTradeInstanceId, s"$basketTradeInstanceId.0001.HK", ".FTSE", "0001.HK", "", null, null, null, -1, null, null, 0.1, null, null, 2, 0, "PENDING") +// (10L, "BUY", basketTradeInstanceId, s"$basketTradeInstanceId.BP.L", ".FTSE", "BP.L", "Beyond Petroleum", null, null, null, -1, null, null, 0.1, null, null, 2, 0, "PENDING"), +// (10L, "SELL", basketTradeInstanceId, s"$basketTradeInstanceId.BT.L", ".FTSE", "BT.L", "British Telecom", null, null, null, -1, null, null, 0.1, null, null, 2, 0, "PENDING"), +// (10L, "BUY", basketTradeInstanceId, s"$basketTradeInstanceId.VOD.L", ".FTSE", "VOD.L", "Vodafone", null, null, null, -1, null, null, 0.1, null, null, 2, 0, "PENDING"), +// (10L, "BUY", basketTradeInstanceId, s"$basketTradeInstanceId.0001.HK", ".FTSE", "0001.HK", "", null, null, null, -1, null, null, 0.1, null, null, 2, 0, "PENDING") // ) // } // } @@ -240,9 +238,9 @@ class BasketMutateOffMarketTest extends VuuServerTestCase { basketProvider.tick(".FTSE", Map(B.Id -> ".FTSE", B.Name -> ".FTSE 100", B.NotionalValue -> 1000001, B.NotionalValueUsd -> 1500001)) val constituentProvider = vuuServer.getProvider(BasketModule.NAME, BasketModule.BasketConstituentTable) - constituentProvider.tick("VOD.L.FTSE", Map(BC.RicBasketId -> "VOD.L.FTSE", BC.Ric -> "VOD.L", BC.BasketId -> basketId, BC.Weighting -> 0.1, BC.Side -> "Buy", BC.Description -> "Vodafone")) - constituentProvider.tick("BT.L.FTSE", Map(BC.RicBasketId -> "BT.L.FTSE", BC.Ric -> "BT.L", BC.BasketId -> basketId, BC.Weighting -> 0.1, BC.Side -> "Sell", BC.Description -> "British Telecom")) - constituentProvider.tick("BP.L.FTSE", Map(BC.RicBasketId -> "BP.L.FTSE", BC.Ric -> "BP.L", BC.BasketId -> basketId, BC.Weighting -> 0.1, BC.Side -> "Buy", BC.Description -> "Beyond Petroleum")) + constituentProvider.tick("VOD.L.FTSE", Map(BC.RicBasketId -> "VOD.L.FTSE", BC.Ric -> "VOD.L", BC.BasketId -> basketId, BC.Weighting -> 0.1, BC.Side -> "BUY", BC.Description -> "Vodafone")) + constituentProvider.tick("BT.L.FTSE", Map(BC.RicBasketId -> "BT.L.FTSE", BC.Ric -> "BT.L", BC.BasketId -> basketId, BC.Weighting -> 0.1, BC.Side -> "SELL", BC.Description -> "British Telecom")) + constituentProvider.tick("BP.L.FTSE", Map(BC.RicBasketId -> "BP.L.FTSE", BC.Ric -> "BP.L", BC.BasketId -> basketId, BC.Weighting -> 0.1, BC.Side -> "BUY", BC.Description -> "Beyond Petroleum")) val vpBasket = vuuServer.createViewPort(BasketModule.NAME, BasketModule.BasketTable) val basketService = vuuServer.getViewPortRpcServiceProxy[BasketServiceIF](vpBasket) diff --git a/example/basket/src/test/scala/org/finos/vuu/core/module/basket/BasketSendToMarketTest.scala b/example/basket/src/test/scala/org/finos/vuu/core/module/basket/BasketSendToMarketTest.scala index 36fc23848..7bc7511ea 100644 --- a/example/basket/src/test/scala/org/finos/vuu/core/module/basket/BasketSendToMarketTest.scala +++ b/example/basket/src/test/scala/org/finos/vuu/core/module/basket/BasketSendToMarketTest.scala @@ -54,9 +54,20 @@ class BasketSendToMarketTest extends VuuServerTestCase { val basketTradeInstanceId = BasketTradeId.current val vpBasketTrading = vuuServer.createViewPort(BasketModule.NAME, BasketTradingTable) + val vpBasketTradingCons = vuuServer.createViewPort(BasketModule.NAME, BasketTradingConstituentTable) vuuServer.runOnce() + And("Check the trading constituents are created") + assertVpEq(combineQsForVp(vpBasketTradingCons)) { + Table( + ("quantity", "side", "instanceId", "instanceIdRic", "basketId", "ric", "description", "notionalUsd", "notionalLocal", "venue", "algo", "algoParams", "pctFilled", "weighting", "priceSpread", "limitPrice", "priceStrategyId", "filledQty", "orderStatus"), + (10L, "BUY", basketTradeInstanceId, s"$basketTradeInstanceId.BP.L", ".FTSE", "BP.L", "Beyond Petroleum", null, null, null, -1, null, null, 0.1, null, null, 2, 0, "PENDING"), + (10L, "SELL", basketTradeInstanceId, s"$basketTradeInstanceId.BT.L", ".FTSE", "BT.L", "British Telecom", null, null, null, -1, null, null, 0.1, null, null, 2, 0, "PENDING"), + (10L, "BUY", basketTradeInstanceId, s"$basketTradeInstanceId.VOD.L", ".FTSE", "VOD.L", "Vodafone", null, null, null, -1, null, null, 0.1, null, null, 2, 0, "PENDING") + ) + } + val tradingService = vuuServer.getViewPortRpcServiceProxy[BasketTradingServiceIF](vpBasketTrading) And("send the basket to market") @@ -68,7 +79,20 @@ class BasketSendToMarketTest extends VuuServerTestCase { assertVpEq(combineQsForVp(vpBasketTrading)) { Table( ("instanceId", "basketId", "basketName", "status", "units", "filledPct", "fxRateToUsd", "totalNotional", "totalNotionalUsd", "side"), - (basketTradeInstanceId, ".FTSE", "TestBasket", "ON_MARKET", 1, null, null, null, null, "Buy") + (basketTradeInstanceId, ".FTSE", "TestBasket", "ON_MARKET", 1, null, null, null, null, "BUY") + ) + } + + Then("Take the basket off the market") + tradingService.takeOffMarket(basketTradeInstanceId)(vuuServer.requestContext) + + vuuServer.runOnce() + + And("verify basket is on market") + assertVpEq(combineQsForVp(vpBasketTrading)) { + Table( + ("instanceId", "basketId", "basketName", "status", "units", "filledPct", "fxRateToUsd", "totalNotional", "totalNotionalUsd", "side"), + (basketTradeInstanceId, ".FTSE", "TestBasket", "OFF_MARKET", 1, null, null, null, null, "BUY") ) } } diff --git a/example/basket/src/test/scala/org/finos/vuu/core/module/basket/BasketTestCaseHelper.scala b/example/basket/src/test/scala/org/finos/vuu/core/module/basket/BasketTestCaseHelper.scala index 540cb1d2d..657af5767 100644 --- a/example/basket/src/test/scala/org/finos/vuu/core/module/basket/BasketTestCaseHelper.scala +++ b/example/basket/src/test/scala/org/finos/vuu/core/module/basket/BasketTestCaseHelper.scala @@ -20,8 +20,8 @@ object BasketTestCaseHelper { //symbol + "." + basketId //Columns.fromNames(BC.RicBasketId.string(), BC.Ric.string(), BC.BasketId.string(), BC.Weighting.double(), BC.LastTrade.string(), BC.Change.string(), // BC.Volume.string(), BC.Side.string()) - provider.tick("VOD.L.FTSE", Map(BC.RicBasketId -> "VOD.L.FTSE", BC.Ric -> "VOD.L", BC.BasketId -> ".FTSE", BC.Weighting -> 0.1, BC.Side -> "Buy", BC.Description -> "Vodafone")) - provider.tick("BT.L.FTSE", Map(BC.RicBasketId -> "BT.L.FTSE", BC.Ric -> "BT.L", BC.BasketId -> ".FTSE", BC.Weighting -> 0.1, BC.Side -> "Sell", BC.Description -> "British Telecom")) - provider.tick("BP.L.FTSE", Map(BC.RicBasketId -> "BP.L.FTSE", BC.Ric -> "BP.L", BC.BasketId -> ".FTSE", BC.Weighting -> 0.1, BC.Side -> "Buy", BC.Description -> "Beyond Petroleum")) + provider.tick("VOD.L.FTSE", Map(BC.RicBasketId -> "VOD.L.FTSE", BC.Ric -> "VOD.L", BC.BasketId -> ".FTSE", BC.Weighting -> 0.1, BC.Side -> "BUY", BC.Description -> "Vodafone")) + provider.tick("BT.L.FTSE", Map(BC.RicBasketId -> "BT.L.FTSE", BC.Ric -> "BT.L", BC.BasketId -> ".FTSE", BC.Weighting -> 0.1, BC.Side -> "SELL", BC.Description -> "British Telecom")) + provider.tick("BP.L.FTSE", Map(BC.RicBasketId -> "BP.L.FTSE", BC.Ric -> "BP.L", BC.BasketId -> ".FTSE", BC.Weighting -> 0.1, BC.Side -> "BUY", BC.Description -> "Beyond Petroleum")) } } diff --git a/example/basket/src/test/scala/org/finos/vuu/core/module/basket/TestHelper/TestDataFactory.scala b/example/basket/src/test/scala/org/finos/vuu/core/module/basket/TestHelper/TestDataFactory.scala index a7ce889b1..526a13f93 100644 --- a/example/basket/src/test/scala/org/finos/vuu/core/module/basket/TestHelper/TestDataFactory.scala +++ b/example/basket/src/test/scala/org/finos/vuu/core/module/basket/TestHelper/TestDataFactory.scala @@ -1,7 +1,7 @@ package org.finos.vuu.core.module.basket.TestHelper +import org.finos.vuu.core.module.basket.BasketModule.{BasketTradingColumnNames => BT, BasketTradingConstituentColumnNames => BTC} import org.finos.vuu.core.table.RowWithData -import org.finos.vuu.core.module.basket.BasketModule.{Sides, BasketColumnNames => B, BasketConstituentColumnNames => BC, BasketTradingColumnNames => BT, BasketTradingConstituentColumnNames => BTC} object TestDataFactory { def uuid = java.util.UUID.randomUUID.toString diff --git a/example/main-java/pom.xml b/example/main-java/pom.xml index 6f9014449..7e1e2f1b3 100644 --- a/example/main-java/pom.xml +++ b/example/main-java/pom.xml @@ -19,6 +19,15 @@ 0.9.36-SNAPSHOT + + org.finos.vuu + vuu + 0.9.36-SNAPSHOT + tests + test-jar + test + + org.finos.vuu basket diff --git a/example/main-java/src/main/java/org/finos/vuu/module/MyExampleModule.java b/example/main-java/src/main/java/org/finos/vuu/module/MyExampleModule.java index 188ac9ffa..2d3d441ff 100644 --- a/example/main-java/src/main/java/org/finos/vuu/module/MyExampleModule.java +++ b/example/main-java/src/main/java/org/finos/vuu/module/MyExampleModule.java @@ -14,7 +14,7 @@ public class MyExampleModule extends DefaultModule { - private final String NAME = "MY_MOD"; + public static final String NAME = "MY_MOD"; public ViewServerModule create(final TableDefContainer tableDefContainer){ return ModuleFactory.withNamespace(NAME, tableDefContainer) diff --git a/example/main-java/src/test/java/org/finos/vuu/JavaTestExample.java b/example/main-java/src/test/java/org/finos/vuu/JavaTestExample.java new file mode 100644 index 000000000..617a5e29d --- /dev/null +++ b/example/main-java/src/test/java/org/finos/vuu/JavaTestExample.java @@ -0,0 +1,60 @@ +package org.finos.vuu; + +import org.finos.toolbox.jmx.MetricsProvider; +import org.finos.toolbox.jmx.MetricsProviderImpl; +import org.finos.toolbox.lifecycle.LifecycleContainer; +import org.finos.toolbox.time.Clock; +import org.finos.toolbox.time.TestFriendlyClock; +import org.finos.vuu.core.module.TableDefContainer; +import org.finos.vuu.core.module.ViewServerModule; +import org.finos.vuu.module.MyExampleModule; +import org.finos.vuu.provider.MockProvider; +import org.finos.vuu.test.VuuServerTestCase; +import org.finos.vuu.viewport.ViewPort; +import org.scalatest.Ignore; +import scala.collection.immutable.Seq; + +import java.util.Arrays; +import java.util.stream.Collectors; + +import static scala.jdk.javaapi.CollectionConverters.asScala; + +public class JavaTestExample extends VuuServerTestCase { + + public static Seq toScalaSeq(ViewServerModule... modules){ + return new scala.collection.mutable.ListBuffer().addAll(asScala(Arrays.stream(modules).collect(Collectors.toList()))).toSeq(); + } + + + @Ignore + public void testVuuServerFunctionality() throws Exception{ + + final MetricsProvider metrics = new MetricsProviderImpl(); + final Clock clock = new TestFriendlyClock(1000000000000L); + final LifecycleContainer lifecycle = new LifecycleContainer(clock); + final TableDefContainer tableDefContainer = new TableDefContainer(); + + final ViewServerModule module = new MyExampleModule().create(tableDefContainer); + + withVuuServer(toScalaSeq(module), (vuuServer) -> { + + vuuServer.login("test", "test"); + + ViewPort viewport = vuuServer.createViewPort(MyExampleModule.NAME, "myTable"); + + MockProvider provider = vuuServer.getProvider(MyExampleModule.NAME, "myTable"); + +// provider.tick("123", Map.of("id", "123", "foo", "bar", "myInt", 123)); +// +// Seq updates = combineQs(viewport); +// +// assertVpEq(updates, () -> asList( +// asList("id", "foo", "myInt"), +// asList("123", "bar", 123) +// )); + + return null; + }, clock, lifecycle, metrics); + } + +} diff --git a/example/order/src/main/scala/org/finos/vuu/core/module/simul/provider/ParentChildOrdersModel.scala b/example/order/src/main/scala/org/finos/vuu/core/module/simul/provider/ParentChildOrdersModel.scala index 5d08aee37..9b0be7bbf 100644 --- a/example/order/src/main/scala/org/finos/vuu/core/module/simul/provider/ParentChildOrdersModel.scala +++ b/example/order/src/main/scala/org/finos/vuu/core/module/simul/provider/ParentChildOrdersModel.scala @@ -291,7 +291,7 @@ class ParentChildOrdersModel(implicit clock: Clock, lifecycleContainer: Lifecycl val instIdx = randomNumbers.seededRand(0, instruments.length - 1) val instrument = instruments(instIdx) val quantity = randomNumbers.seededRand(0, 30) * 100 + randomNumbers.seededRand(0, 100) - val side = if (randomNumbers.seededRand(0, 10) > 8) "Buy" else "Sell" + val side = if (randomNumbers.seededRand(0, 10) > 8) "BUY" else "SELL" val account = accounts(randomNumbers.seededRand(0, accounts.length - 1)) val algo = algos(randomNumbers.seededRand(0, algos.length - 1)) val volLimit = randomNumbers.seededRand(0, 10) * 10 diff --git a/example/order/src/main/scala/org/finos/vuu/order/oms/OmsApi.scala b/example/order/src/main/scala/org/finos/vuu/order/oms/OmsApi.scala index 12a15fdac..a780c854a 100644 --- a/example/order/src/main/scala/org/finos/vuu/order/oms/OmsApi.scala +++ b/example/order/src/main/scala/org/finos/vuu/order/oms/OmsApi.scala @@ -23,6 +23,7 @@ trait OmsApi { def addListener(omsListener: OmsListener): Unit def runOnce(): Unit def containsOrder(clientOrderId: String): Boolean + def getOrderId(clientOrderId: String): Option[Int] } trait OmsListener{ diff --git a/example/order/src/main/scala/org/finos/vuu/order/oms/impl/InMemOmsApi.scala b/example/order/src/main/scala/org/finos/vuu/order/oms/impl/InMemOmsApi.scala index 1805f5a9b..09b4ac4c2 100644 --- a/example/order/src/main/scala/org/finos/vuu/order/oms/impl/InMemOmsApi.scala +++ b/example/order/src/main/scala/org/finos/vuu/order/oms/impl/InMemOmsApi.scala @@ -42,7 +42,13 @@ class InMemOmsApi(implicit val clock: Clock) extends OmsApi { override def replaceOrder(replaceOrder: ReplaceOrder): Unit = ??? - override def cancelOrder(cancelOrder: CancelOrder): Unit = ??? + override def cancelOrder(cancelOrder: CancelOrder): Unit = { + orders = orders.map(orderState => + if (orderState.orderId == cancelOrder.orderId) + orderState.copy(state = States.CANCELLED, nextEventTime = clock.now()) + else orderState + ) + } override def addListener(omsListener: OmsListener): Unit = listeners = listeners ++ List(omsListener) @@ -58,9 +64,14 @@ class InMemOmsApi(implicit val clock: Clock) extends OmsApi { orderstate.copy(state = States.ACKED, nextEventTime = clock.now() + random.between(1000, MaxTimes.MAX_FILL_TIME_MS), orderId = orderId) case 'A' => val remainingQty = orderstate.qty - orderstate.filledQty - val fillQty = if(remainingQty > 1) random.between(1, orderstate.qty - orderstate.filledQty) else 1 - listeners.foreach(_.onFill(Fill(orderstate.orderId, fillQty, orderstate.price, orderstate.clientOrderId, orderstate.filledQty + fillQty, orderstate.qty))) - orderstate.copy(filledQty = orderstate.filledQty + fillQty, nextEventTime = clock.now() + random.between(1000, 5000)) + val fillQty = if(remainingQty > 1) random.between(1, remainingQty) else 1 + val totalFilledQty = orderstate.filledQty + fillQty + val nextState = if( orderstate.qty == totalFilledQty) States.FILLED else States.ACKED + listeners.foreach(_.onFill(Fill(orderstate.orderId, fillQty, orderstate.price, orderstate.clientOrderId, totalFilledQty, orderstate.qty))) + orderstate.copy(state = nextState, filledQty = totalFilledQty, nextEventTime = clock.now() + random.between(1000, MaxTimes.MAX_FILL_TIME_MS)) + case 'X' => + listeners.foreach(_.onCancelAck(CancelAck(orderstate.orderId, orderstate.clientOrderId))) + orderstate case _ => orderstate } @@ -70,8 +81,14 @@ class InMemOmsApi(implicit val clock: Clock) extends OmsApi { } }) - orders = orders.filter(os => os.filledQty != os.qty) + orders = orders.filter(os => os.state != States.FILLED && os.state != States.CANCELLED) } + override def getOrderId(clientOrderId: String): Option[Int] = { + orders.find(os => os.clientOrderId == clientOrderId) match { + case Some(os) => Some(os.orderId) + case None => None + } + } } diff --git a/example/order/src/test/scala/org/finos/vuu/order/oms/OmsApiTest.scala b/example/order/src/test/scala/org/finos/vuu/order/oms/OmsApiTest.scala index e3e2b54f5..eb2ed2454 100644 --- a/example/order/src/test/scala/org/finos/vuu/order/oms/OmsApiTest.scala +++ b/example/order/src/test/scala/org/finos/vuu/order/oms/OmsApiTest.scala @@ -62,7 +62,7 @@ class OmsApiTest extends AnyFeatureSpec with GivenWhenThen with Matchers { omsApi.addListener(listener) - omsApi.createOrder(NewOrder("Buy","VOD.L", 1000L, 100.01, "clOrdId1")) + omsApi.createOrder(NewOrder("BUY","VOD.L", 1000L, 100.01, "clOrdId1")) clock.sleep(MAX_ACK_TIME_MS) omsApi.runOnce() @@ -74,7 +74,7 @@ class OmsApiTest extends AnyFeatureSpec with GivenWhenThen with Matchers { omsApi.containsOrder("clOrdId1") should equal(true) - listener.getOrderState("clOrdId1").get.filledQty should be > (0L) + listener.getOrderState("clOrdId1").get.filledQty should be > 0L for (n <- 1 to 1000) { clock.sleep(MAX_FILL_TIME_MS) @@ -84,5 +84,34 @@ class OmsApiTest extends AnyFeatureSpec with GivenWhenThen with Matchers { omsApi.containsOrder("clOrdId1") should equal(false) } + + Scenario("Check we can submit order and cancel") { + + implicit val clock: Clock = new TestFriendlyClock(1000L) + + val omsApi = OmsApi() + + val listener = new TestListener() + + omsApi.addListener(listener) + + omsApi.createOrder(NewOrder("BUY", "VOD.L", 1000L, 100.01, "clOrdId1")) + omsApi.createOrder(NewOrder("BUY", "BP.L", 1000L, 150.01, "clOrdId2")) + + clock.sleep(MAX_ACK_TIME_MS) + omsApi.runOnce() + + listener.getOrderState("clOrdId1").get.state should equal("ACKED") + + val orderId = omsApi.getOrderId("clOrdId1").get + omsApi.cancelOrder(CancelOrder(orderId)) + omsApi.runOnce() + + omsApi.containsOrder("clOrdId1") should equal(false) + listener.getOrderState("clOrdId1").get.state should equal("CANCELLED") + + omsApi.containsOrder("clOrdId2") should equal(true) + + } } } diff --git a/vuu/src/main/scala/org/finos/vuu/viewport/ViewPortAction.scala b/vuu/src/main/scala/org/finos/vuu/viewport/ViewPortAction.scala index a91273908..3575beab6 100644 --- a/vuu/src/main/scala/org/finos/vuu/viewport/ViewPortAction.scala +++ b/vuu/src/main/scala/org/finos/vuu/viewport/ViewPortAction.scala @@ -25,7 +25,7 @@ case class CloseDialogViewPortAction(vpId: String) extends ViewPortAction new Type(value = classOf[NoAction], name = "NO_ACTION"), new Type(value = classOf[ViewPortEditSuccess], name = "VP_EDIT_SUCCESS"), new Type(value = classOf[ViewPortEditFailure], name = "VP_EDIT_FAILURE"), - new Type(value = classOf[ViewPortRpcSuccess], name = "VP_RCP_SUCCESS"), - new Type(value = classOf[ViewPortRpcFailure], name = "VP_RCP_FAILURE"), + new Type(value = classOf[ViewPortRpcSuccess], name = "VP_RPC_SUCCESS"), + new Type(value = classOf[ViewPortRpcFailure], name = "VP_RPC_FAILURE"), )) trait ViewPortActionMixin {} diff --git a/vuu/src/main/scala/org/finos/vuu/viewport/ViewPortColumns.scala b/vuu/src/main/scala/org/finos/vuu/viewport/ViewPortColumns.scala index 02775ed7c..eca0bd55b 100644 --- a/vuu/src/main/scala/org/finos/vuu/viewport/ViewPortColumns.scala +++ b/vuu/src/main/scala/org/finos/vuu/viewport/ViewPortColumns.scala @@ -2,40 +2,55 @@ package org.finos.vuu.viewport import org.finos.vuu.core.table.{CalculatedColumn, Column, RowData, RowWithData} -class ViewPortColumns(sourceColumns: List[Column]){ +class ViewPortColumns(sourceColumns: List[Column]) { - @volatile private var columns: List[Column] = sourceColumns + @volatile private var columns: List[Column] = sourceColumns - def addColumn(column: Column): Unit = { - columns = columns ++ List(column) - } + def canEqual(a: Any): Boolean = a.isInstanceOf[ViewPortColumns] - def columnExists(name: String): Boolean = { - columns.exists(_.name == name) + override def equals(that: Any): Boolean = + that match { + case that: ViewPortColumns => + that.canEqual(this) && + this.columns.size == that.columns.size && + 0 == this.columns.sortBy(c => c.name) + .zip(that.columns.sortBy(c => c.name)) + .count(columnPair => columnPair._1.name != columnPair._2.name || columnPair._1.dataType != columnPair._2.dataType) + case _ => false } - def getColumns(): List[Column] = columns + override def hashCode(): Int = columns.sortBy(c => c.name).map(_.hashCode()).hashCode() - def getColumnForName(name: String): Option[Column] = { - columns.find(_.name == name) - } + def addColumn(column: Column): Unit = { + columns = columns ++ List(column) + } - def count(): Int = columns.size + def columnExists(name: String): Boolean = { + columns.exists(_.name == name) + } - private lazy val hasCalculatedColumn = columns.exists(c => c.isInstanceOf[CalculatedColumn]) + def getColumns(): List[Column] = columns - def pullRow(key: String, row: RowData): RowData = { + def getColumnForName(name: String): Option[Column] = { + columns.find(_.name == name) + } - if(!hasCalculatedColumn){ - row - }else{ - val rowData = this.getColumns().map(c => c.name -> row.get(c)).toMap - RowWithData(key, rowData) - } - } + def count(): Int = columns.size - def pullRowAlwaysFilter(key: String, row: RowData): RowData = { + private lazy val hasCalculatedColumn = columns.exists(c => c.isInstanceOf[CalculatedColumn]) + + def pullRow(key: String, row: RowData): RowData = { + + if (!hasCalculatedColumn) { + row + } else { val rowData = this.getColumns().map(c => c.name -> row.get(c)).toMap RowWithData(key, rowData) + } + } + + def pullRowAlwaysFilter(key: String, row: RowData): RowData = { + val rowData = this.getColumns().map(c => c.name -> row.get(c)).toMap + RowWithData(key, rowData) } } diff --git a/vuu/src/test/scala/org/finos/vuu/viewport/ViewPortColumnsTests.scala b/vuu/src/test/scala/org/finos/vuu/viewport/ViewPortColumnsTests.scala new file mode 100644 index 000000000..ff678c1bf --- /dev/null +++ b/vuu/src/test/scala/org/finos/vuu/viewport/ViewPortColumnsTests.scala @@ -0,0 +1,55 @@ +package org.finos.vuu.viewport + +import org.finos.vuu.core.table.Columns +import org.scalatest.featurespec.AnyFeatureSpec + +class ViewPortColumnsTests extends AnyFeatureSpec { + + Feature("compare two view port columns") { + + Scenario("when all the columns names are same equality check should return true") { + val sourceColumn = Columns.fromNames("firstColumn:String", "secondColumn:String") + val oldVPColumns = new ViewPortColumns(sourceColumn.toList) + val sourceColumn2 = Columns.fromNames("firstColumn:String", "secondColumn:String") + val newVPColumns = new ViewPortColumns(sourceColumn2.toList) + + assert(oldVPColumns == newVPColumns) + } + + Scenario("when all the columns names are same in different order equality check should return true") { + val sourceColumn = Columns.fromNames("firstColumn:String", "secondColumn:String") + val oldVPColumns = new ViewPortColumns(sourceColumn.toList) + val sourceColumn2 = Columns.fromNames("secondColumn:String", "firstColumn:String") + val newVPColumns = new ViewPortColumns(sourceColumn2.toList) + + assert(oldVPColumns == newVPColumns) + } + + Scenario("when one if the column has different type equality check should return false") { + val sourceColumn = Columns.fromNames("firstColumn:String", "secondColumn:String") + val oldVPColumns = new ViewPortColumns(sourceColumn.toList) + val sourceColumn2 = Columns.fromNames("firstColumn:String", "secondColumn:Int") + val newVPColumns = new ViewPortColumns(sourceColumn2.toList) + + assert(oldVPColumns != newVPColumns) + } + + Scenario("when one if the column has different name equality check should return false") { + val sourceColumn = Columns.fromNames("firstColumn:String", "secondColumn:String") + val oldVPColumns = new ViewPortColumns(sourceColumn.toList) + val sourceColumn2 = Columns.fromNames("firstColumn:String", "someOtherColumn:String") + val newVPColumns = new ViewPortColumns(sourceColumn2.toList) + + assert(oldVPColumns != newVPColumns) + } + + Scenario("when all the columns not same equality check should return false") { + val sourceColumn = Columns.fromNames("firstColumn:String", "secondColumn:String") + val oldVPColumns = new ViewPortColumns(sourceColumn.toList) + val sourceColumn2 = Columns.fromNames("firstColumn:String") + val newVPColumns = new ViewPortColumns(sourceColumn2.toList) + + assert(oldVPColumns != newVPColumns) + } + } +}