From 1ecd47a966f0c19f37949b1d784a5bb41a0defcc Mon Sep 17 00:00:00 2001 From: Na Lee Ha Date: Tue, 5 Dec 2023 12:01:09 +0000 Subject: [PATCH] #980 making basket trade add constituent take in single ric as parsing arrays on rcp message is not supported --- .../BasketTradingConstituentJoinService.scala | 36 ++++++------- .../basket/BasketMutateOffMarketTest.scala | 50 ++++++++++++++++++- 2 files changed, 68 insertions(+), 18 deletions(-) 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 aa1811d6a..66a33d5b3 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 @@ -19,9 +19,9 @@ trait BasketTradingConstituentJoinServiceIF extends EditRpcHandler { def setSell(selection: ViewPortSelection, session: ClientSessionId): ViewPortAction def setBuy(selection: ViewPortSelection, session: ClientSessionId): ViewPortAction -} -object BasketTradingConstituentJoinService {} + def addConstituent(ric: String)(ctx: RequestContext): ViewPortAction +} class BasketTradingConstituentJoinService(val table: DataTable, val tableContainer: TableContainer)(implicit clock: Clock) extends BasketTradingConstituentJoinServiceIF with RpcHandler with StrictLogging { @@ -29,6 +29,7 @@ class BasketTradingConstituentJoinService(val table: DataTable, val tableContain new SelectionViewPortMenuItem("Set Sell", "", this.setSell, "SET_SELECTION_SELL"), new SelectionViewPortMenuItem("Set Buy", "", this.setBuy, "SET_SELECTION_Buy"), ) + override def deleteRowAction(): ViewPortDeleteRowAction = ViewPortDeleteRowAction("", this.onDeleteRow) override def deleteCellAction(): ViewPortDeleteCellAction = ViewPortDeleteCellAction("", this.onDeleteCell) @@ -52,30 +53,30 @@ class BasketTradingConstituentJoinService(val table: DataTable, val tableContain } //this is RCP call and method name is part of contract with UI - def addConstituents(rics: Array[String])(ctx: RequestContext): ViewPortAction = { - if(table.size() == 0) + def addConstituent(ric: String)(ctx: RequestContext): ViewPortAction = { + if (table.size() == 0) ViewPortEditFailure(s"Failed to add constituents to ${table.name} as adding row to empty table is currently not supported") + else { + val existingConstituentRow = table.pullRow(table.primaryKeys.head) + val tradeId = existingConstituentRow.get(ColumnName.InstanceId).asInstanceOf[String] - val existingConstituentRow = table.pullRow(table.primaryKeys.head) - val tradeId = existingConstituentRow.get(ColumnName.InstanceId).asInstanceOf[String] + val tradeRow = tableContainer.getTable(BasketModule.BasketTradingTable).pullRow(tradeId) + val basketId = tradeRow.get(BTColumnName.BasketId).asInstanceOf[String] + val tradeUnit = tradeRow.get(BTColumnName.Units).asInstanceOf[Int] - val tradeRow = tableContainer.getTable(BasketModule.BasketTradingTable).pullRow(tradeId) - val basketId = tradeRow.get(BTColumnName.BasketId).asInstanceOf[String] - val tradeUnit = tradeRow.get(BTColumnName.Units).asInstanceOf[Int] - - val newRows = rics.map(ric => - mkTradingConstituentRow( + val newRow = mkTradingConstituentRow( basketTradeInstanceId = tradeId, sourceBasketId = basketId, tradeUnit = tradeUnit, - ric = ric)) + ric = ric) //todo should we guard against adding row for ric that already exist? - updateJoinTable(newRows) match { + updateJoinTable(Array(newRow)) match { case Right(_) => ViewPortRpcSuccess() case Left(errorReason) => ViewPortRpcFailure(errorReason.reason) } + } } private def onEditCell(key: String, columnName: String, data: Any, vp: ViewPort, session: ClientSessionId): ViewPortEditAction = { @@ -84,7 +85,7 @@ class BasketTradingConstituentJoinService(val table: DataTable, val tableContain case Some(baseTable: DataTable) => columnName match { case ColumnName.Weighting | ColumnName.LimitPrice => - val doubleValue = convertToDouble(data) + val doubleValue = convertToDouble(data) baseTable.processUpdate(key, RowWithData(key, Map(ColumnName.InstanceIdRic -> key, columnName -> doubleValue)), clock.now()) case _ => baseTable.processUpdate(key, RowWithData(key, Map(ColumnName.InstanceIdRic -> key, columnName -> data)), clock.now()) } @@ -93,10 +94,11 @@ class BasketTradingConstituentJoinService(val table: DataTable, val tableContain ViewPortEditFailure("Could not find base table for basket trading constituent join ") } } catch { - case NonFatal(t) => ViewPortEditFailure(s"Could not update $columnName. $t") + case NonFatal(t) => ViewPortEditFailure(s"Could not update $columnName. $t") } } - private def convertToDouble(data:Any): Double = { + + private def convertToDouble(data: Any): Double = { data match { case decimalValue: java.math.BigDecimal => decimalValue.doubleValue 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 8c9489cbd..6ede3b3ef 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 @@ -6,7 +6,7 @@ import org.finos.toolbox.time.{Clock, TestFriendlyClock} import org.finos.vuu.api.ViewPortDef import org.finos.vuu.core.module.TableDefContainer import org.finos.vuu.core.module.basket.BasketModule.{BasketColumnNames => B, BasketConstituentColumnNames => BC} -import org.finos.vuu.core.module.basket.service.{BasketServiceIF, BasketTradeId, BasketTradingServiceIF} +import org.finos.vuu.core.module.basket.service.{BasketServiceIF, BasketTradeId, BasketTradingConstituentJoinServiceIF, BasketTradingServiceIF} import org.finos.vuu.core.module.price.PriceModule import org.finos.vuu.order.oms.OmsApi import org.finos.vuu.test.{TestVuuServer, VuuServerTestCase} @@ -185,6 +185,54 @@ class BasketMutateOffMarketTest extends VuuServerTestCase { } } } + + //TODO oin 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) +// implicit val lifecycle: LifecycleContainer = new LifecycleContainer() +// implicit val tableDefContainer: TableDefContainer = new TableDefContainer(Map()) +// implicit val metricsProvider: MetricsProvider = new MetricsProviderImpl +// +// val omsApi = OmsApi() +// withVuuServer(PriceModule(), BasketModule(omsApi)) { +// vuuServer => +// +// vuuServer.login("testUser", "testToken2") +// +// GivenBasketTradeExist(vuuServer, ".FTSE", "MyCustomBasket") +// val basketTradeInstanceId = BasketTradeId.current +// +// val vpBasketTrading = vuuServer.createViewPort(BasketModule.NAME, BasketTradingTable) +// val vpBasketTradingCons = vuuServer.createViewPort(BasketModule.NAME, BasketTradingConstituentTable) +// val vpBasketTradingConsJoin = vuuServer.createViewPort(BasketModule.NAME, BasketTradingConstituentJoin) +// val basketTradingConstituentJoinService = vuuServer.getViewPortRpcServiceProxy[BasketTradingConstituentJoinServiceIF](vpBasketTradingConsJoin) +// +// vuuServer.runOnce() +// +// When("we edit the side of the parent basket to same side as current value") +// basketTradingConstituentJoinService.addConstituent("0001.HK")(vuuServer.requestContext) +// vuuServer.runOnce() +// +// Then("get all the updates that have occurred for all view ports from the outbound queue") +// val updates = combineQs(vpBasketTradingConsJoin) +// +// +// //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") +// 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") +// ) +// } +// } +// } } def GivenBasketTradeExist(vuuServer: TestVuuServer, basketId: String, basketTradeName: String): Unit = {