0
Fork 0
mirror of https://github.com/TryGhost/Ghost.git synced 2025-04-01 02:41:39 -05:00

Added last redeemed property to Offers (#19066)

refs https://github.com/TryGhost/Product/issues/4153

- wired up a new last_redeemed prop to the Offers API endpoint.
This commit is contained in:
Ronald Langeveld 2023-11-21 15:02:15 +07:00 committed by GitHub
parent bc6f69d823
commit 83a1060983
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 58 additions and 19 deletions

View file

@ -100,6 +100,12 @@ class OfferBookshelfRepository {
const count = await this.OfferRedemptionModel.where({offer_id: json.id}).count('id', {
transacting: options.transacting
});
const lastRedeemed = await this.OfferRedemptionModel.where({offer_id: json.id}).orderBy('created_at', 'DESC').fetchAll({
transacting: options.transacting,
limit: 1
});
try {
return await Offer.create({
id: json.id,
@ -119,7 +125,8 @@ class OfferBookshelfRepository {
id: json.product.id,
name: json.product.name
},
created_at: json.created_at
created_at: json.created_at,
last_redeemed: lastRedeemed.toJSON().length > 0 ? lastRedeemed.toJSON()[0].created_at : null
}, null);
} catch (err) {
logger.error(err);

View file

@ -14,6 +14,7 @@ Object {
"duration": "once",
"duration_in_months": null,
"id": StringMatching /\\[a-f0-9\\]\\{24\\}/,
"last_redeemed": null,
"name": "Fourth of July Sales",
"redemption_count": 0,
"status": "active",
@ -30,7 +31,7 @@ exports[`Offers API Can add a fixed offer 2: [headers] 1`] = `
Object {
"access-control-allow-origin": "http://127.0.0.1:2369",
"cache-control": "no-cache, private, no-store, must-revalidate, max-stale=0, post-check=0, pre-check=0",
"content-length": "347",
"content-length": "368",
"content-type": "application/json; charset=utf-8",
"content-version": StringMatching /v\\\\d\\+\\\\\\.\\\\d\\+/,
"etag": StringMatching /\\(\\?:W\\\\/\\)\\?"\\(\\?:\\[ !#-\\\\x7E\\\\x80-\\\\xFF\\]\\*\\|\\\\r\\\\n\\[\\\\t \\]\\|\\\\\\\\\\.\\)\\*"/,
@ -55,6 +56,7 @@ Object {
"duration": "once",
"duration_in_months": null,
"id": StringMatching /\\[a-f0-9\\]\\{24\\}/,
"last_redeemed": null,
"name": "Black Friday",
"redemption_count": 0,
"status": "active",
@ -71,7 +73,7 @@ exports[`Offers API Can add a new offer 2: [headers] 1`] = `
Object {
"access-control-allow-origin": "http://127.0.0.1:2369",
"cache-control": "no-cache, private, no-store, must-revalidate, max-stale=0, post-check=0, pre-check=0",
"content-length": "389",
"content-length": "410",
"content-type": "application/json; charset=utf-8",
"content-version": StringMatching /v\\\\d\\+\\\\\\.\\\\d\\+/,
"etag": StringMatching /\\(\\?:W\\\\/\\)\\?"\\(\\?:\\[ !#-\\\\x7E\\\\x80-\\\\xFF\\]\\*\\|\\\\r\\\\n\\[\\\\t \\]\\|\\\\\\\\\\.\\)\\*"/,
@ -96,6 +98,7 @@ Object {
"duration": "once",
"duration_in_months": null,
"id": StringMatching /\\[a-f0-9\\]\\{24\\}/,
"last_redeemed": null,
"name": "Easter Sales",
"redemption_count": 0,
"status": "active",
@ -112,7 +115,7 @@ exports[`Offers API Can add a new offer with minimal fields 2: [headers] 1`] = `
Object {
"access-control-allow-origin": "http://127.0.0.1:2369",
"cache-control": "no-cache, private, no-store, must-revalidate, max-stale=0, post-check=0, pre-check=0",
"content-length": "344",
"content-length": "365",
"content-type": "application/json; charset=utf-8",
"content-version": StringMatching /v\\\\d\\+\\\\\\.\\\\d\\+/,
"etag": StringMatching /\\(\\?:W\\\\/\\)\\?"\\(\\?:\\[ !#-\\\\x7E\\\\x80-\\\\xFF\\]\\*\\|\\\\r\\\\n\\[\\\\t \\]\\|\\\\\\\\\\.\\)\\*"/,
@ -137,6 +140,7 @@ Object {
"duration": "trial",
"duration_in_months": null,
"id": StringMatching /\\[a-f0-9\\]\\{24\\}/,
"last_redeemed": null,
"name": "Fourth of July Sales trial",
"redemption_count": 0,
"status": "active",
@ -153,7 +157,7 @@ exports[`Offers API Can add a trial offer 2: [headers] 1`] = `
Object {
"access-control-allow-origin": "http://127.0.0.1:2369",
"cache-control": "no-cache, private, no-store, must-revalidate, max-stale=0, post-check=0, pre-check=0",
"content-length": "359",
"content-length": "380",
"content-type": "application/json; charset=utf-8",
"content-version": StringMatching /v\\\\d\\+\\\\\\.\\\\d\\+/,
"etag": StringMatching /\\(\\?:W\\\\/\\)\\?"\\(\\?:\\[ !#-\\\\x7E\\\\x80-\\\\xFF\\]\\*\\|\\\\r\\\\n\\[\\\\t \\]\\|\\\\\\\\\\.\\)\\*"/,
@ -179,6 +183,7 @@ Object {
"duration": "once",
"duration_in_months": null,
"id": StringMatching /\\[a-f0-9\\]\\{24\\}/,
"last_redeemed": null,
"name": "Cyber Monday",
"redemption_count": 0,
"status": "archived",
@ -196,7 +201,7 @@ exports[`Offers API Can archive an offer 2: [headers] 1`] = `
Object {
"access-control-allow-origin": "http://127.0.0.1:2369",
"cache-control": "no-cache, private, no-store, must-revalidate, max-stale=0, post-check=0, pre-check=0",
"content-length": "468",
"content-length": "489",
"content-type": "application/json; charset=utf-8",
"content-version": StringMatching /v\\\\d\\+\\\\\\.\\\\d\\+/,
"etag": StringMatching /\\(\\?:W\\\\/\\)\\?"\\(\\?:\\[ !#-\\\\x7E\\\\x80-\\\\xFF\\]\\*\\|\\\\r\\\\n\\[\\\\t \\]\\|\\\\\\\\\\.\\)\\*"/,
@ -221,6 +226,7 @@ Object {
"duration": "once",
"duration_in_months": null,
"id": StringMatching /\\[a-f0-9\\]\\{24\\}/,
"last_redeemed": null,
"name": "Black Friday",
"redemption_count": 0,
"status": "active",
@ -242,6 +248,7 @@ Object {
"duration": "once",
"duration_in_months": null,
"id": StringMatching /\\[a-f0-9\\]\\{24\\}/,
"last_redeemed": null,
"name": "Easter Sales",
"redemption_count": 0,
"status": "active",
@ -263,6 +270,7 @@ Object {
"duration": "once",
"duration_in_months": null,
"id": StringMatching /\\[a-f0-9\\]\\{24\\}/,
"last_redeemed": null,
"name": "Summer Sale",
"redemption_count": 0,
"status": "active",
@ -284,6 +292,7 @@ Object {
"duration": "once",
"duration_in_months": null,
"id": StringMatching /\\[a-f0-9\\]\\{24\\}/,
"last_redeemed": null,
"name": "Fourth of July Sales",
"redemption_count": 0,
"status": "active",
@ -305,6 +314,7 @@ Object {
"duration": "trial",
"duration_in_months": null,
"id": StringMatching /\\[a-f0-9\\]\\{24\\}/,
"last_redeemed": null,
"name": "Fourth of July Sales trial",
"redemption_count": 0,
"status": "active",
@ -322,7 +332,7 @@ exports[`Offers API Can browse 2: [headers] 1`] = `
Object {
"access-control-allow-origin": "http://127.0.0.1:2369",
"cache-control": "no-cache, private, no-store, must-revalidate, max-stale=0, post-check=0, pre-check=0",
"content-length": "2063",
"content-length": "2168",
"content-type": "application/json; charset=utf-8",
"content-version": StringMatching /v\\\\d\\+\\\\\\.\\\\d\\+/,
"etag": StringMatching /\\(\\?:W\\\\/\\)\\?"\\(\\?:\\[ !#-\\\\x7E\\\\x80-\\\\xFF\\]\\*\\|\\\\r\\\\n\\[\\\\t \\]\\|\\\\\\\\\\.\\)\\*"/,
@ -346,6 +356,7 @@ Object {
"duration": "once",
"duration_in_months": null,
"id": StringMatching /\\[a-f0-9\\]\\{24\\}/,
"last_redeemed": null,
"name": "Easter Sales",
"redemption_count": 0,
"status": "active",
@ -367,6 +378,7 @@ Object {
"duration": "once",
"duration_in_months": null,
"id": StringMatching /\\[a-f0-9\\]\\{24\\}/,
"last_redeemed": null,
"name": "Summer Sale",
"redemption_count": 0,
"status": "active",
@ -388,6 +400,7 @@ Object {
"duration": "once",
"duration_in_months": null,
"id": StringMatching /\\[a-f0-9\\]\\{24\\}/,
"last_redeemed": null,
"name": "Fourth of July Sales",
"redemption_count": 0,
"status": "active",
@ -409,6 +422,7 @@ Object {
"duration": "trial",
"duration_in_months": null,
"id": StringMatching /\\[a-f0-9\\]\\{24\\}/,
"last_redeemed": null,
"name": "Fourth of July Sales trial",
"redemption_count": 0,
"status": "active",
@ -426,7 +440,7 @@ exports[`Offers API Can browse active 2: [headers] 1`] = `
Object {
"access-control-allow-origin": "http://127.0.0.1:2369",
"cache-control": "no-cache, private, no-store, must-revalidate, max-stale=0, post-check=0, pre-check=0",
"content-length": "1621",
"content-length": "1705",
"content-type": "application/json; charset=utf-8",
"content-version": StringMatching /v\\\\d\\+\\\\\\.\\\\d\\+/,
"etag": StringMatching /\\(\\?:W\\\\/\\)\\?"\\(\\?:\\[ !#-\\\\x7E\\\\x80-\\\\xFF\\]\\*\\|\\\\r\\\\n\\[\\\\t \\]\\|\\\\\\\\\\.\\)\\*"/,
@ -450,6 +464,7 @@ Object {
"duration": "once",
"duration_in_months": null,
"id": StringMatching /\\[a-f0-9\\]\\{24\\}/,
"last_redeemed": null,
"name": "Cyber Monday",
"redemption_count": 0,
"status": "archived",
@ -467,7 +482,7 @@ exports[`Offers API Can browse archived 2: [headers] 1`] = `
Object {
"access-control-allow-origin": "http://127.0.0.1:2369",
"cache-control": "no-cache, private, no-store, must-revalidate, max-stale=0, post-check=0, pre-check=0",
"content-length": "468",
"content-length": "489",
"content-type": "application/json; charset=utf-8",
"content-version": StringMatching /v\\\\d\\+\\\\\\.\\\\d\\+/,
"etag": StringMatching /\\(\\?:W\\\\/\\)\\?"\\(\\?:\\[ !#-\\\\x7E\\\\x80-\\\\xFF\\]\\*\\|\\\\r\\\\n\\[\\\\t \\]\\|\\\\\\\\\\.\\)\\*"/,
@ -491,6 +506,7 @@ Object {
"duration": "once",
"duration_in_months": null,
"id": StringMatching /\\[a-f0-9\\]\\{24\\}/,
"last_redeemed": null,
"name": "Cyber Monday",
"redemption_count": 0,
"status": "active",
@ -508,7 +524,7 @@ exports[`Offers API Can edit an offer 2: [headers] 1`] = `
Object {
"access-control-allow-origin": "http://127.0.0.1:2369",
"cache-control": "no-cache, private, no-store, must-revalidate, max-stale=0, post-check=0, pre-check=0",
"content-length": "466",
"content-length": "487",
"content-type": "application/json; charset=utf-8",
"content-version": StringMatching /v\\\\d\\+\\\\\\.\\\\d\\+/,
"etag": StringMatching /\\(\\?:W\\\\/\\)\\?"\\(\\?:\\[ !#-\\\\x7E\\\\x80-\\\\xFF\\]\\*\\|\\\\r\\\\n\\[\\\\t \\]\\|\\\\\\\\\\.\\)\\*"/,
@ -533,6 +549,7 @@ Object {
"duration": "once",
"duration_in_months": null,
"id": StringMatching /\\[a-f0-9\\]\\{24\\}/,
"last_redeemed": null,
"name": "Black Friday",
"redemption_count": 0,
"status": "active",
@ -550,7 +567,7 @@ exports[`Offers API Can get a single offer 2: [headers] 1`] = `
Object {
"access-control-allow-origin": "http://127.0.0.1:2369",
"cache-control": "no-cache, private, no-store, must-revalidate, max-stale=0, post-check=0, pre-check=0",
"content-length": "454",
"content-length": "475",
"content-type": "application/json; charset=utf-8",
"content-version": StringMatching /v\\\\d\\+\\\\\\.\\\\d\\+/,
"etag": StringMatching /\\(\\?:W\\\\/\\)\\?"\\(\\?:\\[ !#-\\\\x7E\\\\x80-\\\\xFF\\]\\*\\|\\\\r\\\\n\\[\\\\t \\]\\|\\\\\\\\\\.\\)\\*"/,
@ -574,6 +591,7 @@ Object {
"duration": "trial",
"duration_in_months": null,
"id": StringMatching /\\[a-f0-9\\]\\{24\\}/,
"last_redeemed": null,
"name": "Fourth of July Sales trial",
"redemption_count": 0,
"status": "active",
@ -591,7 +609,7 @@ exports[`Offers API Can get a trial offer 2: [headers] 1`] = `
Object {
"access-control-allow-origin": "http://127.0.0.1:2369",
"cache-control": "no-cache, private, no-store, must-revalidate, max-stale=0, post-check=0, pre-check=0",
"content-length": "424",
"content-length": "445",
"content-type": "application/json; charset=utf-8",
"content-version": StringMatching /v\\\\d\\+\\\\\\.\\\\d\\+/,
"etag": StringMatching /\\(\\?:W\\\\/\\)\\?"\\(\\?:\\[ !#-\\\\x7E\\\\x80-\\\\xFF\\]\\*\\|\\\\r\\\\n\\[\\\\t \\]\\|\\\\\\\\\\.\\)\\*"/,
@ -708,6 +726,7 @@ Object {
"duration": "once",
"duration_in_months": null,
"id": StringMatching /\\[a-f0-9\\]\\{24\\}/,
"last_redeemed": null,
"name": "Cyber Monday",
"redemption_count": 0,
"status": "archived",
@ -725,7 +744,7 @@ exports[`Offers API Cannot update offer amount 2: [headers] 1`] = `
Object {
"access-control-allow-origin": "http://127.0.0.1:2369",
"cache-control": "no-cache, private, no-store, must-revalidate, max-stale=0, post-check=0, pre-check=0",
"content-length": "468",
"content-length": "489",
"content-type": "application/json; charset=utf-8",
"content-version": StringMatching /v\\\\d\\+\\\\\\.\\\\d\\+/,
"etag": StringMatching /\\(\\?:W\\\\/\\)\\?"\\(\\?:\\[ !#-\\\\x7E\\\\x80-\\\\xFF\\]\\*\\|\\\\r\\\\n\\[\\\\t \\]\\|\\\\\\\\\\.\\)\\*"/,
@ -750,6 +769,7 @@ Object {
"duration": "once",
"duration_in_months": null,
"id": StringMatching /\\[a-f0-9\\]\\{24\\}/,
"last_redeemed": null,
"name": "Cyber Monday",
"redemption_count": 0,
"status": "archived",
@ -767,7 +787,7 @@ exports[`Offers API Cannot update offer cadence 2: [headers] 1`] = `
Object {
"access-control-allow-origin": "http://127.0.0.1:2369",
"cache-control": "no-cache, private, no-store, must-revalidate, max-stale=0, post-check=0, pre-check=0",
"content-length": "468",
"content-length": "489",
"content-type": "application/json; charset=utf-8",
"content-version": StringMatching /v\\\\d\\+\\\\\\.\\\\d\\+/,
"etag": StringMatching /\\(\\?:W\\\\/\\)\\?"\\(\\?:\\[ !#-\\\\x7E\\\\x80-\\\\xFF\\]\\*\\|\\\\r\\\\n\\[\\\\t \\]\\|\\\\\\\\\\.\\)\\*"/,
@ -885,6 +905,7 @@ Object {
"duration": "once",
"duration_in_months": null,
"id": StringMatching /\\[a-f0-9\\]\\{24\\}/,
"last_redeemed": null,
"name": "Cyber Monday",
"redemption_count": 0,
"status": "archived",
@ -902,7 +923,7 @@ exports[`Offers API Cannot update offer tier 2: [headers] 1`] = `
Object {
"access-control-allow-origin": "http://127.0.0.1:2369",
"cache-control": "no-cache, private, no-store, must-revalidate, max-stale=0, post-check=0, pre-check=0",
"content-length": "468",
"content-length": "489",
"content-type": "application/json; charset=utf-8",
"content-version": StringMatching /v\\\\d\\+\\\\\\.\\\\d\\+/,
"etag": StringMatching /\\(\\?:W\\\\/\\)\\?"\\(\\?:\\[ !#-\\\\x7E\\\\x80-\\\\xFF\\]\\*\\|\\\\r\\\\n\\[\\\\t \\]\\|\\\\\\\\\\.\\)\\*"/,
@ -945,6 +966,7 @@ Object {
"duration": "once",
"duration_in_months": null,
"id": StringMatching /\\[a-f0-9\\]\\{24\\}/,
"last_redeemed": null,
"name": "Summer Sale",
"redemption_count": 0,
"status": "active",
@ -961,7 +983,7 @@ exports[`Offers API Slugifies offer codes 2: [headers] 1`] = `
Object {
"access-control-allow-origin": "http://127.0.0.1:2369",
"cache-control": "no-cache, private, no-store, must-revalidate, max-stale=0, post-check=0, pre-check=0",
"content-length": "347",
"content-length": "368",
"content-type": "application/json; charset=utf-8",
"content-version": StringMatching /v\\\\d\\+\\\\\\.\\\\d\\+/,
"etag": StringMatching /\\(\\?:W\\\\/\\)\\?"\\(\\?:\\[ !#-\\\\x7E\\\\x80-\\\\xFF\\]\\*\\|\\\\r\\\\n\\[\\\\t \\]\\|\\\\\\\\\\.\\)\\*"/,

View file

@ -28,7 +28,8 @@
* @prop {object} tier
* @prop {string} tier.id
* @prop {string} tier.name
* @prop {Date} created_at
* @prop {string} created_at
* @prop {string|null} last_redeemed
*/
class OfferMapper {
@ -56,7 +57,8 @@ class OfferMapper {
id: offer.tier.id,
name: offer.tier.name
},
created_at: offer.createdAt
created_at: offer.createdAt,
last_redeemed: offer.lastRedeemed
};
}
}

View file

@ -31,6 +31,7 @@ const OfferCreatedAt = require('./OfferCreatedAt');
* @prop {OfferTier} tier
* @prop {number} redemptionCount
* @prop {string} createdAt
* @prop {string|null} lastRedeemed
*/
/**
@ -50,6 +51,7 @@ const OfferCreatedAt = require('./OfferCreatedAt');
* @prop {number} redemptionCount
* @prop {TierProps|OfferTier} tier
* @prop {Date} created_at
* @prop {Date|null} last_redeemed
*/
/**
@ -186,6 +188,10 @@ class Offer {
return this.props.createdAt;
}
get lastRedeemed() {
return this.props.lastRedeemed;
}
/**
* @param {OfferCode} code
* @param {UniqueChecker} uniqueChecker
@ -283,6 +289,7 @@ class Offer {
const duration = OfferDuration.create(data.duration, data.duration_in_months);
const status = OfferStatus.create(data.status || 'active');
const createdAt = isNew ? new Date().toISOString : OfferCreatedAt.create(data.created_at);
const lastRedeemed = data.last_redeemed ? new Date(data.last_redeemed).toISOString() : null;
if (isNew && data.redemptionCount !== undefined) {
// TODO correct error
@ -349,7 +356,8 @@ class Offer {
tier,
redemptionCount,
status,
createdAt
createdAt,
lastRedeemed
}, {isNew});
}
}