Revision ecceede8
b/src/main/scala/gr/grnet/aquarium/logic/accounting/Accounting.scala | ||
---|---|---|
63 | 63 |
val instanceId = currentResourceEvent.instanceId |
64 | 64 |
val currentValue = currentResourceEvent.value |
65 | 65 |
val currentOccurredMillis = currentResourceEvent.occurredMillis |
66 |
val currentResourceEventDebugStr = currentResourceEvent.toDebugString(defaultResourcesMap, false) |
|
67 |
|
|
68 |
|
|
69 |
def validateCostPolicy(toCheck: DSLCostPolicy, whatEvent: String) { |
|
70 |
if(costPolicy != toCheck) { |
|
71 |
throw new Exception("Actual cost policy %s is not the same as provided %s for %s event %s". |
|
72 |
format(costPolicy, toCheck, whatEvent, currentResourceEventDebugStr)) |
|
73 |
} |
|
74 |
} |
|
75 |
def validateCostPolicyM(toCheckM: Maybe[DSLCostPolicy], whatEvent: String): Unit = { |
|
76 |
toCheckM match { |
|
77 |
case Just(toCheck) ⇒ |
|
78 |
validateCostPolicy(toCheck, whatEvent) |
|
79 |
|
|
80 |
case _ ⇒ |
|
81 |
throw new Exception("Could not verify cost policy %s for %s event %s". |
|
82 |
format(costPolicy, whatEvent, currentResourceEventDebugStr)) |
|
83 |
} |
|
84 |
} |
|
66 | 85 |
|
67 | 86 |
///////////////////////////////////////////////////////////////////// |
68 | 87 |
// Validations |
69 | 88 |
///////////////////////////////////////////////////////////////////// |
70 |
// 1. Validate cost policy |
|
71 |
val actualCostPolicyM = currentResourceEvent.findCostPolicyM(defaultResourcesMap) |
|
72 |
val currentResourceEventDebugStr = currentResourceEvent.toDebugString(defaultResourcesMap, false) |
|
73 |
actualCostPolicyM match { |
|
74 |
case Just(actualCostPolicy) ⇒ |
|
75 |
if(costPolicy != actualCostPolicy) { |
|
76 |
throw new Exception("Actual cost policy %s is not the same as provided %s for event %s". |
|
77 |
format(actualCostPolicy, costPolicy, currentResourceEventDebugStr)) |
|
78 |
} |
|
79 |
case _ ⇒ |
|
80 |
throw new Exception("Could not verify cost policy %s for event %s". |
|
81 |
format(costPolicy, currentResourceEventDebugStr)) |
|
82 |
} |
|
89 |
// 1. Validate cost policy for current event |
|
90 |
val currentEventCostPolicyM = currentResourceEvent.findCostPolicyM(defaultResourcesMap) |
|
91 |
validateCostPolicyM(currentEventCostPolicyM, "current") |
|
83 | 92 |
|
84 | 93 |
// 2. Validate previous resource event |
85 | 94 |
previousResourceEventM match { |
95 |
// We have a previous event |
|
86 | 96 |
case Just(previousResourceEvent) ⇒ |
87 | 97 |
if(!costPolicy.needsPreviousEventForCreditAndAmountCalculation) { |
88 | 98 |
throw new Exception("Provided previous event but cost policy %s does not need one".format(costPolicy)) |
89 | 99 |
} |
90 | 100 |
|
91 |
// 3. resource and instanceId
|
|
101 |
// 3. Validate resource and instanceId for previous resource event
|
|
92 | 102 |
val previousResource = previousResourceEvent.resource |
93 | 103 |
val previousInstanceId = previousResourceEvent.instanceId |
94 | 104 |
(resource == previousResource, instanceId == previousInstanceId) match { |
... | ... | |
107 | 117 |
format((resource, instanceId), (previousResource, previousInstanceId))) |
108 | 118 |
} |
109 | 119 |
|
120 |
// 4. Validate cost policy for previous resource event |
|
121 |
val previousEventCostPolicyM = previousResourceEvent.findCostPolicyM(defaultResourcesMap) |
|
122 |
validateCostPolicyM(previousEventCostPolicyM, "previous") |
|
123 |
|
|
124 |
// We do not have a previous event |
|
110 | 125 |
case NoVal ⇒ |
111 | 126 |
if(costPolicy.needsPreviousEventForCreditAndAmountCalculation) { |
112 |
throw new Exception("Did not provid previous event but cost policy %s needa one".format(costPolicy))
|
|
127 |
throw new Exception("Did not provide previous event but cost policy %s needs one".format(costPolicy))
|
|
113 | 128 |
} |
114 | 129 |
|
130 |
// We cannot obtain a previous resource event |
|
115 | 131 |
case failed @ Failed(e, m) ⇒ |
116 | 132 |
throw new Exception("Error obtaining previous event".format(m), e) |
117 | 133 |
} |
118 | 134 |
|
119 |
// 4. Make sure this is billable.
|
|
120 |
// It is the caller's responsibility to provide us with billable events |
|
135 |
// 5. Make the current event is billable.
|
|
136 |
// It is the caller's responsibility to provide us with billable events
|
|
121 | 137 |
costPolicy.isBillableEventBasedOnValue(currentValue) match { |
122 | 138 |
case true ⇒ |
123 | 139 |
case false ⇒ |
124 |
throw new Exception("Event not billable %s".format(currentResourceEventDebugStr))
|
|
140 |
throw new Exception("Not billable event %s".format(currentResourceEventDebugStr))
|
|
125 | 141 |
} |
126 | 142 |
///////////////////////////////////////////////////////////////////// |
127 | 143 |
|
... | ... | |
131 | 147 |
previousAccumulatingAmountM.getOr(0.0), |
132 | 148 |
currentOccurredMillis - previousResourceEventM.map(_.occurredMillis).getOr(currentOccurredMillis), |
133 | 149 |
previousResourceEventM.map(_.value).getOr(0.0), |
134 |
currentValue) |
|
150 |
currentValue, |
|
151 |
1.0 /*UNITPRICE*/) |
|
135 | 152 |
// Now, we need to find the proper agreement(s) and feed the data to them. |
136 | 153 |
|
137 |
|
|
138 | 154 |
Nil |
139 | 155 |
} |
140 | 156 |
|
... | ... | |
218 | 234 |
* Creates a list of wallet entries by applying the agreement provisions on |
219 | 235 |
* the resource state. |
220 | 236 |
* |
221 |
* @param resourceEvent The resource event to create charges for
|
|
237 |
* @param currentResourceEvent The resource event to create charges for
|
|
222 | 238 |
* @param agreement The agreement applicable to the user mentioned in the event |
223 |
* @param currentValue The current state of the resource
|
|
224 |
* @param currentSnapshotDate The last time the resource state was updated
|
|
239 |
* @param previousAmount The current state of the resource
|
|
240 |
* @param previousOccurred The last time the resource state was updated
|
|
225 | 241 |
*/ |
226 |
def chargeEvent(resourceEvent: ResourceEvent,
|
|
227 |
agreement: DSLAgreement,
|
|
228 |
currentValue: Double,
|
|
229 |
currentSnapshotDate: Date,
|
|
242 |
def chargeEvent(currentResourceEvent: ResourceEvent,
|
|
243 |
agreements: List[String],
|
|
244 |
previousAmount: Double,
|
|
245 |
previousOccurred: Date,
|
|
230 | 246 |
related: List[WalletEntry]): Maybe[List[WalletEntry]] = { |
231 | 247 |
|
232 |
assert(currentSnapshotDate.getTime <= resourceEvent.occurredMillis)
|
|
248 |
assert(previousOccurred.getTime <= currentResourceEvent.occurredMillis)
|
|
233 | 249 |
|
234 |
if (!resourceEvent.validate())
|
|
250 |
if (!currentResourceEvent.validate())
|
|
235 | 251 |
return Failed(new AccountingException("Event not valid")) |
236 | 252 |
|
237 | 253 |
val policy = Policy.policy |
238 |
val dslResource = policy.findResource(resourceEvent.resource) match {
|
|
254 |
val dslResource = policy.findResource(currentResourceEvent.resource) match {
|
|
239 | 255 |
case Some(x) => x |
240 |
case None => return Failed(new AccountingException("No resource [%s]".format(resourceEvent.resource)))
|
|
256 |
case None => return Failed(new AccountingException("No resource [%s]".format(currentResourceEvent.resource)))
|
|
241 | 257 |
} |
242 | 258 |
|
243 | 259 |
/* This is a safeguard against the special case where the last |
... | ... | |
246 | 262 |
* this is the first time the resource state has been recorded. |
247 | 263 |
* Charging in this case only makes sense for discrete resources. |
248 | 264 |
*/ |
249 |
if (currentSnapshotDate.getTime == resourceEvent.occurredMillis) {
|
|
265 |
if (previousOccurred.getTime == currentResourceEvent.occurredMillis) {
|
|
250 | 266 |
dslResource.costPolicy match { |
251 | 267 |
case DiscreteCostPolicy => //Ok |
252 | 268 |
case _ => return Some(List()) |
253 | 269 |
} |
254 | 270 |
} |
255 | 271 |
|
256 |
val creditCalculationValueM = dslResource.costPolicy.getValueForCreditCalculation(Just(currentValue), resourceEvent.value)
|
|
272 |
val creditCalculationValueM = dslResource.costPolicy.getValueForCreditCalculation(Just(previousAmount), currentResourceEvent.value)
|
|
257 | 273 |
val amount = creditCalculationValueM match { |
258 | 274 |
case failed @ Failed(_, _) ⇒ |
259 | 275 |
return failed |
... | ... | |
267 | 283 |
// above, since this point won't be reached in case of error. |
268 | 284 |
val isFinal = dslResource.costPolicy match { |
269 | 285 |
case OnOffCostPolicy => |
270 |
OnOffPolicyResourceState(currentValue) match {
|
|
286 |
OnOffPolicyResourceState(previousAmount) match {
|
|
271 | 287 |
case OnResourceState => false |
272 | 288 |
case OffResourceState => true |
273 | 289 |
} |
... | ... | |
275 | 291 |
} |
276 | 292 |
|
277 | 293 |
val timeslot = dslResource.costPolicy match { |
278 |
case DiscreteCostPolicy => Timeslot(new Date(resourceEvent.occurredMillis),
|
|
279 |
new Date(resourceEvent.occurredMillis + 1))
|
|
280 |
case _ => Timeslot(currentSnapshotDate, new Date(resourceEvent.occurredMillis))
|
|
294 |
case DiscreteCostPolicy => Timeslot(new Date(currentResourceEvent.occurredMillis),
|
|
295 |
new Date(currentResourceEvent.occurredMillis + 1))
|
|
296 |
case _ => Timeslot(previousOccurred, new Date(currentResourceEvent.occurredMillis))
|
|
281 | 297 |
} |
282 | 298 |
|
283 | 299 |
val chargeChunks = calcChangeChunks(agreement, amount, dslResource, timeslot) |
284 | 300 |
|
285 | 301 |
val timeReceived = System.currentTimeMillis |
286 | 302 |
|
287 |
val rel = related.map{x => x.sourceEventIDs}.flatten ++ List(resourceEvent.id)
|
|
303 |
val rel = related.map{x => x.sourceEventIDs}.flatten ++ List(currentResourceEvent.id)
|
|
288 | 304 |
|
289 | 305 |
val entries = chargeChunks.map { |
290 | 306 |
c => |
291 | 307 |
WalletEntry( |
292 | 308 |
id = CryptoUtils.sha1(c.id), |
293 |
occurredMillis = resourceEvent.occurredMillis,
|
|
309 |
occurredMillis = currentResourceEvent.occurredMillis,
|
|
294 | 310 |
receivedMillis = timeReceived, |
295 | 311 |
sourceEventIDs = rel, |
296 | 312 |
value = c.cost, |
297 | 313 |
reason = c.reason, |
298 |
userId = resourceEvent.userId,
|
|
299 |
resource = resourceEvent.resource,
|
|
300 |
instanceId = resourceEvent.instanceId,
|
|
314 |
userId = currentResourceEvent.userId,
|
|
315 |
resource = currentResourceEvent.resource,
|
|
316 |
instanceId = currentResourceEvent.instanceId,
|
|
301 | 317 |
finalized = isFinal |
302 | 318 |
) |
303 | 319 |
} |
Also available in: Unified diff