diff --git a/airline-data/src/main/scala/com/patson/model/Link.scala b/airline-data/src/main/scala/com/patson/model/Link.scala index 8f46db2fc..27eeb78e8 100644 --- a/airline-data/src/main/scala/com/patson/model/Link.scala +++ b/airline-data/src/main/scala/com/patson/model/Link.scala @@ -142,6 +142,27 @@ case class Link(from : Airport, to : Airport, airline: Airline, price : LinkClas futureCapacity } + /** + * Future LinkValues based on configuration that can accommodate the max pax (ie single class configuration with lowest space multiplier). + * + * This is usually only used for negotiation calculations + * @return + */ + def futureMaxCapacity(): LinkClassValues = { + //need to do all these calculations so we an support class with a non 1 lowest space multiplier... + val lowestClass = LinkClass.values.sortBy(_.spaceMultiplier).head + var maxCapacity = LinkClassValues.getInstance() + assignedAirplanes.foreach { + case (airplane, assignment) => { + val maxCapacityPerFlight = LinkClassValues.getInstanceByMap(Map(lowestClass -> (airplane.model.capacity / lowestClass.spaceMultiplier).toInt)) + //not doing maxCapacityPerFlight * futureFrequency ...in case we allow mixed model in the future... + maxCapacity = maxCapacity + (maxCapacityPerFlight * assignment.frequency) + } + } + + maxCapacity + } + def futureFrequency() = { assignedAirplanes.values.map(_.frequency).sum } diff --git a/airline-web/app/controllers/NegotiationUtil.scala b/airline-web/app/controllers/NegotiationUtil.scala index 65ab99810..4f507770c 100644 --- a/airline-web/app/controllers/NegotiationUtil.scala +++ b/airline-web/app/controllers/NegotiationUtil.scala @@ -97,7 +97,12 @@ object NegotiationUtil { val officeStaffCount : Int = baseOption.map(_.getOfficeStaffCapacity).getOrElse(0) val airlineLinksFromThisAirport = airlineLinks.filter(link => link.from.id == airport.id && (isNewLink || link.id != existingLinkOption.get.id)) val currentOfficeStaffUsed = airlineLinksFromThisAirport.map(_.getFutureOfficeStaffRequired).sum - val newOfficeStaffRequired = newLink.getFutureOfficeStaffRequired + /** + * Use futureMaxCapacity for calculating negotiation difficulty to avoid loophole of negotiating with first class and switch config + */ + val newOfficeStaffRequired : Int = { + newLink.getOfficeStaffRequired(newLink.from, newLink.to, newLink.futureFrequency(), newLink.futureMaxCapacity()) + } val newTotal = currentOfficeStaffUsed + newOfficeStaffRequired if (newTotal < officeStaffCount) { @@ -154,10 +159,11 @@ object NegotiationUtil { case class FrequencyRestrictionByModel(threshold : Int, frequencyRestriction : Int) def getToAirportRequirements(airline : Airline, newLink : Link, existingLinkOption : Option[Link], airlineLinks : List[Link]) = { - val newCapacity : LinkClassValues = newLink.futureCapacity() + //use futureMaxCapacity as calculation, to avoid cheat of changing config after negotiation + val newCapacity = newLink.futureMaxCapacity() val newFrequency = newLink.futureFrequency() - val existingCapacity = existingLinkOption.map(_.futureCapacity()).getOrElse(LinkClassValues.getInstance()) + val existingCapacity = existingLinkOption.map(_.futureMaxCapacity()).getOrElse(LinkClassValues.getInstance()) val existingFrequency = existingLinkOption.map(_.futureFrequency()).getOrElse(0) val capacityDelta = normalizedCapacity(newCapacity - existingCapacity)