--json prints only JSON on stdout (withJsonOutput around every command: logs, tables and prompts to stderr; printJson everywhere; test runs every --json command against the fake stores and parses stdout); prices ppp compares like with like: par = the store's own US-equivalent price (Play convertRegionPrices, Apple equalizations; offline base x fx x (1 + VAT) rounded up) scaled by the PPP price level; defaults only lower, only price levels <= 0.5, World Bank high-income at par, CN at par on Apple and skipped on Play, never above par (--only-decreases, --max-ratio, --min-ratio, --max-level, --include-high-income; --floor / --ceiling kept), top-10 revenue market drops > 20 % warned (sales reports, else a static list), unchanged regions out of the sheet; price changes of existing products only with --allow-price-changes, TTY or not (a terminal yes covered them), then their own question listing each old -> new, held section in dry runs (play products, prices import, play / apple subscriptions); pitfalls 61-63; tests
This commit is contained in:
parent
bab3f63227
commit
357319a775
30 changed files with 865 additions and 209 deletions
|
|
@ -66,6 +66,9 @@ async function readState(c: Asc, appId: string): Promise<AppleSubState> {
|
|||
return state;
|
||||
}
|
||||
|
||||
const heldOf = (id: string, changes: { territory: string; from: number | null; to: number; startDate?: string | null }[]): HeldPrice =>
|
||||
({ id, changes: changes.map(ch => ({ region: ch.territory, from: ch.from === null ? '-' : String(ch.from), to: `${ch.to}${ch.startDate ? ` from ${ch.startDate}` : ''}` })) });
|
||||
|
||||
export async function run(ctx: Ctx): Promise<void> {
|
||||
const { config, root, resolve } = ctx.loaded;
|
||||
const only = ctx.args.list('only');
|
||||
|
|
@ -83,11 +86,10 @@ export async function run(ctx: Ctx): Promise<void> {
|
|||
if (dry) { done(TAG, `subscriptions planned (dry run, nothing written; prices are compared per territory on a real run${csv.length ? `, ${csv.length} CSV rows` : ''})`); return; }
|
||||
|
||||
const yes = ctx.args.has('yes');
|
||||
// price changes of existing subscriptions: known per subscription, decided at the first one (lib/price-gate.ts)
|
||||
let liveOk: boolean | undefined;
|
||||
// price changes of existing subscriptions: only with --allow-price-changes, their own question per subscription
|
||||
// listing each old -> new (lib/price-gate.ts); the terminal question here covers creates and other updates only
|
||||
if (stdinIsTTY() && !yes && process.env.STOREBOUND_SERVE !== '1') {
|
||||
if (!(await confirm(ctx, 'Create / update these subscriptions on App Store Connect? Nothing is public before App Review, but price changes of existing subscriptions apply to new subscribers right away.'))) return;
|
||||
liveOk = true;
|
||||
if (!(await confirm(ctx, 'Create / update these subscriptions on App Store Connect? Nothing is public before App Review. Price changes of existing subscriptions are not part of this answer (--allow-price-changes).'))) return;
|
||||
} else if (!yes) log(TAG, 'not a terminal: creating what is new; price changes of existing subscriptions wait for the owner');
|
||||
const held: HeldPrice[] = [];
|
||||
|
||||
|
|
@ -148,9 +150,9 @@ export async function run(ctx: Ctx): Promise<void> {
|
|||
const current = hasPrices ? appleSubPrices(await pages(c, `/v1/subscriptions/${id}/prices?include=subscriptionPricePoint,territory&limit=200`)) : [];
|
||||
const changes = applePriceChanges(current, appleWantedPrices(s, equalized, csv), csv.filter(r => r.product === s.id));
|
||||
if (!changes.length) log(TAG, ' prices up to date');
|
||||
else if (current.length && !(liveOk ??= await allowPriceChanges(ctx, changes.length, `Change the prices of existing subscriptions on App Store Connect (first: ${s.id}, ${changes.length} territories)? New subscribers pay the new price.`))) {
|
||||
else if (current.length && !(await allowPriceChanges(ctx, [heldOf(s.id, changes)], `Change the prices of the existing subscription ${s.id} on App Store Connect (${changes.length} territories)? New subscribers pay the new price.`))) {
|
||||
log(TAG, ' owner: price change of an existing subscription (--allow-price-changes)');
|
||||
held.push({ id: s.id, changes: changes.map(ch => ({ region: ch.territory, from: ch.from === null ? '-' : String(ch.from), to: `${ch.to}${ch.startDate ? ` from ${ch.startDate}` : ''}` })) });
|
||||
held.push(heldOf(s.id, changes));
|
||||
} else {
|
||||
const resolved: { territory: string; pointId: string; startDate?: string | null }[] = [];
|
||||
for (const ch of changes) {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue