Skip to content
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

feat(criteria): Add TestOpportunityBookable(Non)FreeCancellable criterias #547

Merged
merged 1 commit into from
Jul 13, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@ export type OfferConstraint = (offer: import("../types/Offer").Offer, opportunit
* Implements https://openactive.io/test-interface#TestOpportunityBookableCancellable
*/
export const TestOpportunityBookableCancellable: import("../types/Criteria").Criteria;
export const mustBeWithinCancellationWindowOrHaveNoWindowOfferConstraint: [string, import("../types/Criteria").OfferConstraint];
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@ export type OfferConstraint = (offer: import("../types/Offer").Offer, opportunit
* Implements https://openactive.io/test-interface#TestOpportunityBookableFree
*/
export const TestOpportunityBookableFree: import("../types/Criteria").Criteria;
export const onlyFreeBookableOffersWithUnavailablePrepaymentOfferConstraint: [string, import("../types/Criteria").OfferConstraint];
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
/**
* Implements https://openactive.io/test-interface#TestOpportunityBookableFreeCancellable
*/
export const TestOpportunityBookableFreeCancellable: import("../types/Criteria").Criteria;
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@ export type OfferConstraint = (offer: import("../types/Offer").Offer, opportunit
* Implements https://openactive.io/test-interface#TestOpportunityBookableNonFree
*/
export const TestOpportunityBookableNonFree: import("../types/Criteria").Criteria;
export const onlyNonFreeBookableOfferConstraint: [string, import("../types/Criteria").OfferConstraint];
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
/**
* Implements https://openactive.io/test-interface#TestOpportunityBookableNonFreeCancellable
*/
export const TestOpportunityBookableNonFreeCancellable: import("../types/Criteria").Criteria;
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,7 @@ export function mustNotAllowFullRefund(offer: import("../types/Offer").Offer, op
* @type {OfferConstraint}
*/
export function mustAllowFullRefund(offer: import("../types/Offer").Offer): boolean;
export const mustAllowFullRefundOfferConstraint: [string, import("../types/Criteria").OfferConstraint];
/**
* @type {OfferConstraint}
*/
Expand All @@ -158,3 +159,9 @@ export function excludePaidBookableOffersWithPrepaymentUnavailable(offer: import
* @return {TestDataShape}
*/
export function extendTestDataShape(baseTestDataShape: TestDataShape, extraTestDataShape: TestDataShape, criteriaName: string): TestDataShape;
/**
* @param {string} name
* @param {OfferConstraint} constraint
* @returns {Criteria['offerConstraints'][number]}
*/
export function createCriteriaOfferConstraint(name: string, constraint: OfferConstraint): Criteria['offerConstraints'][number];
10 changes: 10 additions & 0 deletions packages/test-interface-criteria/built-types/testDataShape.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -114,4 +114,14 @@ export namespace shapeConstraintRecipes {
export function mustAllowFullRefund(): {
'oa:allowCustomerCancellationFullRefund': import("./types/TestDataShape").BooleanNodeConstraint;
};
export function mustBeWithinCancellationWindowOrHaveNoWindow(): {
'oa:latestCancellationBeforeStartDate': import("./types/TestDataShape").NullNodeConstraint;
};
export function onlyNonFreeBookableOffers(): {
'schema:price': import("./types/TestDataShape").NumericNodeConstraint;
};
export function onlyFreeBookableOffersWithUnavailablePrepayment(): {
'schema:price': import("./types/TestDataShape").NumericNodeConstraint;
'oa:openBookingPrepayment': import("./types/TestDataShape").OptionNodeConstraint<import("./types/TestDataShape").RequiredStatusType, "oa:RequiredStatusType">;
};
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
const { TestOpportunityBookable } = require('./TestOpportunityBookable');
const { createCriteria, mustAllowFullRefund, getDateBeforeWhichCancellationsCanBeMade } = require('./criteriaUtils');
const { BLOCKED_FIELD, shapeConstraintRecipes } = require('../testDataShape');
const { createCriteria, getDateBeforeWhichCancellationsCanBeMade, createCriteriaOfferConstraint, mustAllowFullRefundOfferConstraint } = require('./criteriaUtils');
const { shapeConstraintRecipes } = require('../testDataShape');

/**
* @typedef {import('../types/Criteria').OfferConstraint} OfferConstraint
Expand All @@ -17,32 +17,31 @@ function mustBeWithinCancellationWindowOrHaveNoWindow(offer, opportunity, option
return options.harvestStartTimeTwoHoursLater < dateBeforeWhichCancellationsCanBeMade;
}

const mustBeWithinCancellationWindowOrHaveNoWindowOfferConstraint = createCriteriaOfferConstraint(
'Offer must not have cancellation window (`latestCancellationBeforeStartDate`), or be within the cancellation window',
mustBeWithinCancellationWindowOrHaveNoWindow,
);

/**
* Implements https://openactive.io/test-interface#TestOpportunityBookableCancellable
*/
const TestOpportunityBookableCancellable = createCriteria({
name: 'TestOpportunityBookableCancellable',
opportunityConstraints: [],
offerConstraints: [
[
'Offer must not have cancellation window (`latestCancellationBeforeStartDate`), or be within the cancellation window',
mustBeWithinCancellationWindowOrHaveNoWindow,
],
[
'Offer must be fully refundable on customer cancellation, with `"allowCustomerCancellationFullRefund": true`',
mustAllowFullRefund,
],
mustBeWithinCancellationWindowOrHaveNoWindowOfferConstraint,
mustAllowFullRefundOfferConstraint,
],
testDataShape: () => ({
offerConstraints: {
...shapeConstraintRecipes.mustAllowFullRefund(),
// mustBeWithinCancellationWindowOrHaveNoWindow
'oa:latestCancellationBeforeStartDate': BLOCKED_FIELD,
...shapeConstraintRecipes.mustBeWithinCancellationWindowOrHaveNoWindow(),
},
}),
includeConstraintsFromCriteria: TestOpportunityBookable,
});

module.exports = {
TestOpportunityBookableCancellable,
mustBeWithinCancellationWindowOrHaveNoWindowOfferConstraint,
};
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
const { TestOpportunityBookable } = require('./TestOpportunityBookable');
const { createCriteria } = require('./criteriaUtils');
const { prepaymentOptionNodeConstraint, FREE_PRICE_QUANTITATIVE_VALUE } = require('../testDataShape');
const { createCriteria, createCriteriaOfferConstraint } = require('./criteriaUtils');
const { shapeConstraintRecipes } = require('../testDataShape');

/**
* @typedef {import('../types/Criteria').OfferConstraint} OfferConstraint
Expand All @@ -13,31 +13,29 @@ function onlyFreeBookableOffersWithUnavailablePrepayment(offer) {
return offer.price === 0 && (!offer.openBookingPrepayment || offer.openBookingPrepayment === 'https://openactive.io/Unavailable');
}

const onlyFreeBookableOffersWithUnavailablePrepaymentOfferConstraint = createCriteriaOfferConstraint(
'Only free bookable Offers (free offers must always either omit `openBookingPrepayment` or set it to `https://openactive.io/Unavailable`) ',
onlyFreeBookableOffersWithUnavailablePrepayment,
);

/**
* Implements https://openactive.io/test-interface#TestOpportunityBookableFree
*/
const TestOpportunityBookableFree = createCriteria({
name: 'TestOpportunityBookableFree',
opportunityConstraints: [],
offerConstraints: [
[
'Only free bookable Offers (free offers must always either omit `openBookingPrepayment` or set it to `https://openactive.io/Unavailable`) ',
onlyFreeBookableOffersWithUnavailablePrepayment,
],
onlyFreeBookableOffersWithUnavailablePrepaymentOfferConstraint,
],
testDataShape: () => ({
offerConstraints: {
// onlyFreeBookableOffersWithUnavailablePrepayment
'schema:price': FREE_PRICE_QUANTITATIVE_VALUE,
'oa:openBookingPrepayment': prepaymentOptionNodeConstraint({
allowlist: ['https://openactive.io/Unavailable'],
allowNull: true,
}),
...shapeConstraintRecipes.onlyFreeBookableOffersWithUnavailablePrepayment(),
},
}),
includeConstraintsFromCriteria: TestOpportunityBookable,
});

module.exports = {
TestOpportunityBookableFree,
onlyFreeBookableOffersWithUnavailablePrepaymentOfferConstraint,
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
const { shapeConstraintRecipes } = require('../testDataShape');
const { TestOpportunityBookable } = require('./TestOpportunityBookable');
const { mustBeWithinCancellationWindowOrHaveNoWindowOfferConstraint } = require('./TestOpportunityBookableCancellable');
const { onlyFreeBookableOffersWithUnavailablePrepaymentOfferConstraint } = require('./TestOpportunityBookableFree');
const { createCriteria, mustAllowFullRefundOfferConstraint } = require('./criteriaUtils');

/**
* Implements https://openactive.io/test-interface#TestOpportunityBookableFreeCancellable
*/
const TestOpportunityBookableFreeCancellable = createCriteria({
name: 'TestOpportunityBookableFreeCancellable',
opportunityConstraints: [],
offerConstraints: [
onlyFreeBookableOffersWithUnavailablePrepaymentOfferConstraint,
mustBeWithinCancellationWindowOrHaveNoWindowOfferConstraint,
mustAllowFullRefundOfferConstraint,
],
testDataShape: () => ({
offerConstraints: {
...shapeConstraintRecipes.onlyFreeBookableOffersWithUnavailablePrepayment(),
...shapeConstraintRecipes.mustAllowFullRefund(),
...shapeConstraintRecipes.mustBeWithinCancellationWindowOrHaveNoWindow(),
},
}),
includeConstraintsFromCriteria: TestOpportunityBookable,
});

module.exports = {
TestOpportunityBookableFreeCancellable,
};
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
const { TestOpportunityBookable } = require('./TestOpportunityBookable');
const { createCriteria } = require('./criteriaUtils');
const { NON_FREE_PRICE_QUANTITATIVE_VALUE } = require('../testDataShape');
const { createCriteria, createCriteriaOfferConstraint } = require('./criteriaUtils');
const { shapeConstraintRecipes } = require('../testDataShape');

/**
* @typedef {import('../types/Criteria').OfferConstraint} OfferConstraint
Expand All @@ -13,27 +13,29 @@ function onlyNonFreeBookableOffers(offer) {
return offer.price > 0;
}

const onlyNonFreeBookableOfferConstraint = createCriteriaOfferConstraint(
'Only non-free bookable Offers',
onlyNonFreeBookableOffers,
);

/**
* Implements https://openactive.io/test-interface#TestOpportunityBookableNonFree
*/
const TestOpportunityBookableNonFree = createCriteria({
name: 'TestOpportunityBookableNonFree',
opportunityConstraints: [],
offerConstraints: [
[
'Only non-free bookable Offers',
onlyNonFreeBookableOffers,
],
onlyNonFreeBookableOfferConstraint,
],
testDataShape: () => ({
offerConstraints: {
// onlyNonFreeBookableOffers
'schema:price': NON_FREE_PRICE_QUANTITATIVE_VALUE,
...shapeConstraintRecipes.onlyNonFreeBookableOffers(),
},
}),
includeConstraintsFromCriteria: TestOpportunityBookable,
});

module.exports = {
TestOpportunityBookableNonFree,
onlyNonFreeBookableOfferConstraint,
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
const { shapeConstraintRecipes } = require('../testDataShape');
const { TestOpportunityBookable } = require('./TestOpportunityBookable');
const { mustBeWithinCancellationWindowOrHaveNoWindowOfferConstraint } = require('./TestOpportunityBookableCancellable');
const { onlyNonFreeBookableOfferConstraint } = require('./TestOpportunityBookableNonFree');
const { createCriteria, mustAllowFullRefundOfferConstraint } = require('./criteriaUtils');

/**
* Implements https://openactive.io/test-interface#TestOpportunityBookableNonFreeCancellable
*/
const TestOpportunityBookableNonFreeCancellable = createCriteria({
name: 'TestOpportunityBookableNonFreeCancellable',
opportunityConstraints: [],
offerConstraints: [
onlyNonFreeBookableOfferConstraint,
mustBeWithinCancellationWindowOrHaveNoWindowOfferConstraint,
mustAllowFullRefundOfferConstraint,
],
testDataShape: () => ({
offerConstraints: {
...shapeConstraintRecipes.onlyNonFreeBookableOffers(),
...shapeConstraintRecipes.mustAllowFullRefund(),
...shapeConstraintRecipes.mustBeWithinCancellationWindowOrHaveNoWindow(),
},
}),
includeConstraintsFromCriteria: TestOpportunityBookable,
});

module.exports = {
TestOpportunityBookableNonFreeCancellable,
};
19 changes: 19 additions & 0 deletions packages/test-interface-criteria/src/criteria/criteriaUtils.js
Original file line number Diff line number Diff line change
Expand Up @@ -395,6 +395,11 @@ function mustAllowFullRefund(offer) {
return offer.allowCustomerCancellationFullRefund === true;
}

const mustAllowFullRefundOfferConstraint = createCriteriaOfferConstraint(
'Offer must be fully refundable on customer cancellation, with `"allowCustomerCancellationFullRefund": true`',
mustAllowFullRefund,
);

/**
* @type {OfferConstraint}
*/
Expand Down Expand Up @@ -453,6 +458,18 @@ function excludePaidBookableOffersWithPrepaymentUnavailable(offer) {
return !(offer.price > 0 && offer.openBookingPrepayment === 'https://openactive.io/Unavailable');
}

/**
* @param {string} name
* @param {OfferConstraint} constraint
* @returns {Criteria['offerConstraints'][number]}
*/
function createCriteriaOfferConstraint(name, constraint) {
// It's frozen so that it may be easily used in multiple criteria without the possibility of
// erroneous mutation in one criteria affecting all others.
// In a later version of TS, just use `const` rather than `any`
return Object.freeze(/** @type {any} */([name, constraint]));
}

module.exports = {
createCriteria,
getId,
Expand All @@ -474,9 +491,11 @@ module.exports = {
mustBeOutsideCancellationWindow,
mustNotAllowFullRefund,
mustAllowFullRefund,
mustAllowFullRefundOfferConstraint,
mustRequireAdditionalDetails,
mustNotRequireAdditionalDetails,
sellerMustAllowOpenBooking,
excludePaidBookableOffersWithPrepaymentUnavailable,
extendTestDataShape,
createCriteriaOfferConstraint,
};
4 changes: 4 additions & 0 deletions packages/test-interface-criteria/src/criteria/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ const { TestOpportunityBookableSellerTermsOfService } = require('./TestOpportuni
const { TestOpportunityOnlineBookable } = require('./TestOpportunityOnlineBookable');
const { TestOpportunityOfflineBookable } = require('./TestOpportunityOfflineBookable');
const { TestOpportunityBookableWithNegotiation } = require('./TestOpportunityBookableWithNegotiation');
const { TestOpportunityBookableFreeCancellable } = require('./TestOpportunityBookableFreeCancellable');
const { TestOpportunityBookableNonFreeCancellable } = require('./TestOpportunityBookableNonFreeCancellable');

module.exports = {
allCriteria: [
Expand All @@ -39,6 +41,8 @@ module.exports = {
TestOpportunityBookableWithinValidFromBeforeStartDate,
TestOpportunityBookableCancellable,
TestOpportunityBookableNotCancellable,
TestOpportunityBookableFreeCancellable,
TestOpportunityBookableNonFreeCancellable,
TestOpportunityBookableInPast,
TestOpportunityBookableOutsideValidFromBeforeStartDate,
TestOpportunityBookableCancellableNoWindow,
Expand Down
13 changes: 13 additions & 0 deletions packages/test-interface-criteria/src/testDataShape.js
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,19 @@ const shapeConstraintRecipes = {
mustAllowFullRefund: () => ({
'oa:allowCustomerCancellationFullRefund': TRUE_BOOLEAN_CONSTRAINT,
}),
mustBeWithinCancellationWindowOrHaveNoWindow: () => ({
'oa:latestCancellationBeforeStartDate': BLOCKED_FIELD,
}),
onlyNonFreeBookableOffers: () => ({
'schema:price': NON_FREE_PRICE_QUANTITATIVE_VALUE,
}),
onlyFreeBookableOffersWithUnavailablePrepayment: () => ({
'schema:price': FREE_PRICE_QUANTITATIVE_VALUE,
'oa:openBookingPrepayment': prepaymentOptionNodeConstraint({
allowlist: ['https://openactive.io/Unavailable'],
allowNull: true,
}),
}),
};

module.exports = {
Expand Down