Change idempotency to be cached with invalidating fields.
This commit is contained in:
parent
2a59399f75
commit
fe05b61fa6
4 changed files with 112 additions and 14 deletions
|
|
@ -123,6 +123,8 @@ const storeActions = {
|
|||
|
||||
SAVE_LOGGING_OPTION: "saveLoggingOption",
|
||||
UPDATE_HAS_TRIGGERED_ERROR: "updateHasTriggeredError",
|
||||
GET_VALID_IDEMPOTENCY_KEY: "getValidIdempotencyKey",
|
||||
CORRECT_IDEMPOTENCY_KEY_EXPIRY: "correctIdempotencyKeyExpiry",
|
||||
};
|
||||
|
||||
export { storeActions };
|
||||
|
|
|
|||
|
|
@ -98,6 +98,7 @@ const storeMutations = {
|
|||
UPDATE_LAST_PAGE_VISITED: "updateLastPageVisited",
|
||||
UPDATE_LOGGING_OPTION: "updateLoggingOption",
|
||||
UPDATE_HAS_TRIGGERED_ERROR: "updateHasTriggeredError",
|
||||
UPDATE_IDEMPOTENCY_KEY: "updateIdempotencyKey",
|
||||
|
||||
// EXPERIMENT MUTATIONS
|
||||
UPDATE_EXPERIMENTS: "updateExperiments",
|
||||
|
|
|
|||
|
|
@ -163,7 +163,7 @@ export default {
|
|||
console.log(`Price = ${this.amountDue}`);
|
||||
console.log(`Adyen Price = ${this.adyenPriceTotal}`);
|
||||
|
||||
const requestBody = this.getAdyenInitRequestInfo();
|
||||
const requestBody = await this.getAdyenInitRequestInfo();
|
||||
|
||||
console.log(`Calling with:`);
|
||||
console.log(requestBody);
|
||||
|
|
@ -257,6 +257,7 @@ export default {
|
|||
this.dropinComponent = dropin;
|
||||
|
||||
dropin.mount("#adyen-container");
|
||||
await this.dispatchStoreAction(storeActions.CORRECT_IDEMPOTENCY_KEY_EXPIRY, expiryTime);
|
||||
},
|
||||
|
||||
async handleCompletedPayment(result) {
|
||||
|
|
@ -438,19 +439,13 @@ export default {
|
|||
},
|
||||
|
||||
// Now a Method so it is always freshly called and not cached.
|
||||
getIdempotencyKey() {
|
||||
const currentDateTime = new Date();
|
||||
const currentHour = currentDateTime.getUTCHours();
|
||||
const currentDate = currentDateTime.getUTCDate();
|
||||
const id = this?.$store?.getters?.order?.referralCorrelationId;
|
||||
const system = this.sourceSystem;
|
||||
const total = this.adyenPriceTotal;
|
||||
|
||||
return `${id}-${system}-${currentDate}-${currentHour}-${total}`;
|
||||
async getIdempotencyKey() {
|
||||
return await this.dispatchStoreAction(storeActions.GET_VALID_IDEMPOTENCY_KEY);
|
||||
},
|
||||
|
||||
// Now a Method so it is always freshly called and not cached.
|
||||
getAdyenInitRequestInfo() {
|
||||
async getAdyenInitRequestInfo() {
|
||||
const key = await this.getIdempotencyKey();
|
||||
return {
|
||||
sourceSystem: this.sourceSystem,
|
||||
referralSequenceNumber: this.$store.getters.order.referralSequenceNumber,
|
||||
|
|
@ -464,10 +459,9 @@ export default {
|
|||
stateOrProvince: this.locationInfo.state,
|
||||
returnUrl: applicationConfig.PIA_ADYEN_RETURN_URL,
|
||||
email: this.$store.getters.order.customer.emailAddress,
|
||||
IP: "127.0.0.1", // TODO
|
||||
firstName: this.$store.getters.order.customer.firstName,
|
||||
lastName: this.$store.getters.order.customer.lastName,
|
||||
idempotencyKey: this.getIdempotencyKey(),
|
||||
idempotencyKey: key,
|
||||
};
|
||||
},
|
||||
},
|
||||
|
|
|
|||
|
|
@ -59,7 +59,7 @@ import {
|
|||
} from "@/helpers/recal-helper";
|
||||
import { externalParameterStatus } from "@/constants/external-parameters";
|
||||
import { experimentSettings } from "@/constants/experiments";
|
||||
import { addPricesToLineItems } from "@/helpers/pricing-helper";
|
||||
import { addPricesToLineItems, getAmountDue } from "@/helpers/pricing-helper";
|
||||
|
||||
// Export State
|
||||
const getDefaultState = () => {
|
||||
|
|
@ -207,6 +207,12 @@ const getDefaultState = () => {
|
|||
loggingOption: false,
|
||||
hasAlreadyTriggeredError: false,
|
||||
},
|
||||
idempotencyKeyFields: {
|
||||
referralCorrelationId: null,
|
||||
totalInCents: 0,
|
||||
expiryTime: null,
|
||||
idempotencyKey: null,
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
|
|
@ -862,6 +868,15 @@ export const mutations = {
|
|||
updateHasTriggeredError(state, hasTriggeredError) {
|
||||
state.applicationUser.hasAlreadyTriggeredError = hasTriggeredError;
|
||||
},
|
||||
updateIdempotencyKey(
|
||||
state,
|
||||
{ idempotencyKey, referralCorrelationId, totalInCents, expiryTime }
|
||||
) {
|
||||
state.idempotencyKeyFields.idempotencyKey = idempotencyKey;
|
||||
state.idempotencyKeyFields.referralCorrelationId = referralCorrelationId;
|
||||
state.idempotencyKeyFields.totalInCents = totalInCents;
|
||||
state.idempotencyKeyFields.expiryTime = expiryTime;
|
||||
},
|
||||
};
|
||||
|
||||
// Export Getters
|
||||
|
|
@ -1105,6 +1120,35 @@ export const getters = {
|
|||
state.order.customer.emailAddress
|
||||
);
|
||||
},
|
||||
|
||||
isIdempotencyKeyValid: (state) => {
|
||||
if (!state.idempotencyKeyFields?.idempotencyKey) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const referralCorrelationId = state.order?.referralCorrelationId;
|
||||
if (
|
||||
!referralCorrelationId ||
|
||||
referralCorrelationId !== state.idempotencyKeyFields?.referralCorrelationId
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const total = getAmountDue(state.order?.lineItems);
|
||||
const totalInCents = Math.round(total * 100);
|
||||
if (totalInCents !== state.idempotencyKeyFields?.totalInCents) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const currentTime = new Date();
|
||||
const expiryTime = new Date(state.idempotencyKeyFields.expiryTime);
|
||||
if (!expiryTime || expiryTime.getTime() < currentTime.getTime()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// If all checks pass, then the key is valid.
|
||||
return true;
|
||||
},
|
||||
};
|
||||
|
||||
// Export Actions
|
||||
|
|
@ -3665,6 +3709,63 @@ export const actions = {
|
|||
updateHasTriggeredError(context, hasAlreadyTriggeredError) {
|
||||
context.commit(storeMutations.UPDATE_HAS_TRIGGERED_ERROR, hasAlreadyTriggeredError);
|
||||
},
|
||||
|
||||
getValidIdempotencyKey(context) {
|
||||
if (context.getters.isIdempotencyKeyValid) {
|
||||
return context.state.idempotencyKeyFields.idempotencyKey;
|
||||
}
|
||||
|
||||
// If invalid, need to regenerate.
|
||||
const referralCorrelationId = context.state.order?.referralCorrelationId;
|
||||
if (!referralCorrelationId) {
|
||||
// Can't generate!
|
||||
return null;
|
||||
}
|
||||
|
||||
const total = getAmountDue(context.state.order?.lineItems);
|
||||
const totalInCents = Math.round(total * 100);
|
||||
if (Number.isNaN(totalInCents)) {
|
||||
// Can't generate!
|
||||
return null;
|
||||
}
|
||||
|
||||
const currentTime = new Date();
|
||||
const nextHour = currentTime.getUTCHours() + 1;
|
||||
currentTime.setUTCHours(nextHour);
|
||||
|
||||
const newId = crypto.randomUUID();
|
||||
|
||||
const newKeyInfo = {
|
||||
idempotencyKey: newId,
|
||||
referralCorrelationId: referralCorrelationId,
|
||||
totalInCents: totalInCents,
|
||||
expiryTime: currentTime,
|
||||
};
|
||||
|
||||
context.commit(storeMutations.UPDATE_IDEMPOTENCY_KEY, newKeyInfo);
|
||||
|
||||
return newId;
|
||||
},
|
||||
|
||||
correctIdempotencyKeyExpiry(context, expiryTime) {
|
||||
if (!context.getters.isIdempotencyKeyValid) {
|
||||
return;
|
||||
}
|
||||
|
||||
const currentExpiryTime = new Date(context.state.idempotencyKeyFields.expiryTime);
|
||||
const expiryTimeAsDate = new Date(expiryTime);
|
||||
|
||||
if (expiryTimeAsDate.getTime() < currentExpiryTime.getTime()) {
|
||||
const existingKey = context.state.idempotencyKeyFields;
|
||||
const newKey = {
|
||||
referralCorrelationId: existingKey.referralCorrelationId,
|
||||
totalInCents: existingKey.totalInCents,
|
||||
idempotencyKey: existingKey.idempotencyKey,
|
||||
expiryTime: expiryTimeAsDate,
|
||||
};
|
||||
context.commit(storeMutations.UPDATE_IDEMPOTENCY_KEY, newKey);
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
export default createStore({
|
||||
|
|
|
|||
Loading…
Reference in a new issue