-
Notifications
You must be signed in to change notification settings - Fork 90
feat: calculate grant spent amounts from new table #3412
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: bc/raf-1031/grant-spent-amounts
Are you sure you want to change the base?
Conversation
let existingOutgoingPaymentGrant: OutgoingPaymentGrant | undefined | ||
|
||
if (grantId) { | ||
const stopTimerGrant = deps.telemetry.startTimer( | ||
'outgoing_payment_service_insertgrant_time_ms', | ||
{ | ||
callName: 'OutgoingPaymentGrantModel:insert', | ||
description: 'Time to insert grant in outgoing payment' | ||
} | ||
) | ||
await OutgoingPaymentGrant.query(trx) | ||
.insert({ | ||
id: grantId | ||
}) | ||
.onConflict('id') | ||
.ignore() | ||
stopTimerGrant() | ||
const existingGrant = | ||
await OutgoingPaymentGrant.query(trx).findById(grantId) | ||
|
||
if (!existingGrant) { | ||
// TODO: insert w/ interval | ||
await OutgoingPaymentGrant.query(trx) | ||
.insert({ id: grantId }) | ||
.onConflict('id') | ||
.ignore() | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We need to insert this grant record before creating the payment (grantId no payment is a fk of this table) but we also need to know if a record already existed (to check if its a legacy grant). Hence the existing grant query.
I thought maybe this meant we could not do the onConflict
/ignore
but its still necessary (race condition observed in one of the unit tests).
🚀 Performance Test ResultsTest Configuration:
Test Metrics:
📜 Logs
|
intervalReceiveAmountValue: paymentLimits.interval | ||
? payment.receiveAmount.value | ||
: null, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We also need to add the newSpentAmounts
to the cumulative interval value (if we are still within the same interval, that is). This will require changing the starting point for newSpentAmounts
expect(spentAmounts).toEqual( | ||
expect.objectContaining({ | ||
grantId: grant.id, | ||
outgoingPaymentId: payment.id, | ||
debitAmountCode: debitAmount.assetCode, | ||
debitAmountScale: debitAmount.assetScale, | ||
paymentDebitAmountValue: debitAmount.value, | ||
grantTotalDebitAmountValue: debitAmount.value * BigInt(i + 1), | ||
receiveAmountCode: debitAmount.assetCode, | ||
receiveAmountScale: debitAmount.assetScale, | ||
paymentReceiveAmountValue: adjustedReceiveAmountValue, | ||
grantTotalReceiveAmountValue: | ||
adjustedReceiveAmountValue * BigInt(i + 1), | ||
intervalDebitAmountValue: null, | ||
intervalReceiveAmountValue: null, | ||
intervalStart: null, | ||
intervalEnd: null, | ||
paymentState: 'FUNDING' | ||
}) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
the grant spent amounts are kind of an implementation detail. at the end of the day its grantSpent[Receive|Debit]Amounts which matter, which is already tested. IDK, left for now but considered not including this.
if (createdTime < start) { | ||
return 'next' | ||
} else if (createdTime >= end) { | ||
return 'previous' |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Double checking this: given an interval [start, end]:
if createdAt < start: would this be in the previous interval? (createdAt equal to start would put us in the current interval)
Conversely, if createdTime > end, we would be in the next interval, right? (maybe if createdAt is equal to end, we count it as being part of the current interval)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I will revisit this. The refactor of this function in general from returning a boolean to the status. I was thinking I'd need more resolution based off the general logic we discussed but Im not sure I ended up using it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was thinking I'd need more resolution based off the general logic we discussed but Im not sure I ended up using it.
I think it will be useful (you will need the three cases) for calculating the spent amounts on outgoing payment failure (RAF-1036), so its good to have. We just need to flip the conditions.
[OutgoingPaymentError.InvalidGrantSpentAmountState]: | ||
'invalid grant spent amounts' |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we should differentiate between errors served up to an Open Payments client vs those that are just on the Admin API (since this error would not be necessarily useful to an OP client)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK I think I've sidestepped this by making it more typesafe here: 934e9f6 Yay, make the invalid state unrepresentable.
Maybe not important anymore, but I'm not exactly following - how would open payments client not care about this but admin api would (given it could happen in either open payments api/admin api)?
It was a bad state (500/internal server error) so it's true that there is nothing the client could really do to recover. But not sure what the difference between the two APIs would be. Again, it's a moot point because it no longer throws the error.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK I think I've sidestepped this by making it more typesafe here: 934e9f6 Yay, make the invalid state unrepresentable.
Getting rid of the error entirely works great :)
My original thinking was to separate errorToMessage
, and have an errorToGraphQLMessage
vs errorToOpenPaymentsMessage
(something like this) such that we dont show "invalid grant spent amounts" to the OP client, and maybe something more generic instead.
As an aside, we would never end up throwing the InvalidGrantSpentAmountState
error in the Admin API since there is no grant associated when its a first-party, Admin API payment.
…ernal server error
Changes proposed in this pull request
create
method on outgoing payment service to use new grant spent amount tables to get the spent amounts. Falls back to existing method of summing all payments for grants that pre-exist this change.Context
fixes: #3373
Checklist
fixes #number
user-docs
label (if necessary)