ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

App-Store-Connect-CLI 订阅定价推导:用 `asc subscriptions pricing derive` 一键将月度订阅价格体系复制为年度订阅

App-Store-Connect-CLI 订阅定价推导:用 `asc subscriptions pricing derive` 一键将月度订阅价格体系复制为年度订阅 【免费下载链接】App-Store-Connect-CLIFast, scriptable CLI for the App Store Connect API. Automate TestFlight, builds, submissions, signing, analytics, screenshots, subscriptions, and more项目地址https://gitcode.com/gh_mirrors/ap/App-Store-Connect-CLI点击查看免费下载导读App-Store-Connect-CLI简称 ASC CLI提供了一条窄聚焦、一次性执行的定价工作流asc subscriptions pricing derive以某个订阅源订阅当前生效的各地区UPFRONT价格为基础乘以用户指定的倍率再对照目标订阅的 Apple 价格点阶梯price-point ladder就近解析出目标价格并批量写入。本文基于仓库中的设计文档 docs/design/subscription-pricing-derive.md结合命令实现 internal/cli/subscriptions/pricing_derive.go、输出契约 internal/asc/output_subscription_pricing_derive.go 与端到端测试 internal/cli/cmdtest/subscriptions_pricing_derive_test.go完整讲解该命令的定位、全部参数与校验规则、四种舍入策略、底层 API 编排流程、输出/失败语义以及测试与替代方案。读完本文你将掌握如何用--dry-run先预览再--confirm落地执行exact / nearest / up / down四种价格点解析策略的取舍--start-date、--preserved、--auto-start-date等调度与存量保护参数的正确用法以及命令在哪个环节 fail-closed、何时退出码为 1、如何做 readback 校验。一、设计决策一个窄而完整的源到目标定价任务1.1 命令定位设计文档将derive定义为一种snapshot 操作而非订阅之间持久的价格关系命令在每次执行时独立计算源订阅地区客户价格 × 倍率然后针对目标订阅的 Apple 价格点阶梯解析出目标价格。它只负责一次设置不维护任何后续同步。命令的基本形态沿用文档中的示例# 先 dry-run 预览完整计划不产生任何写入请求 asc subscriptions pricing derive \ --source-subscription-id MONTHLY_ID \ --target-subscription-id YEARLY_ID \ --multiplier 10 \ --round nearest \ --dry-run # 确认无误后落地执行 asc subscriptions pricing derive \ --source-subscription-id MONTHLY_ID \ --target-subscription-id YEARLY_ID \ --multiplier 10 \ --round nearest \ --confirm典型动机场景是月度订阅到年度订阅的价格体系迁移源订阅如月度 0.99 USD在各地区已有完整定价目标订阅年度需要按某个倍数如 10推导出各地区价格。实现层面的核心逻辑位于 internal/cli/subscriptions/pricing_derive.go 的buildSubscriptionPriceDerivePlanL435-L549每个地区独立执行desired sourcePrice × multiplier使用math/big的有理数精确算术再调用resolveSubscriptionPriceDerivePoint对照目标阶梯解析。1.2 与pricing equalize的刻意区分文档强调该命令与pricing equalize是两条刻意分开的路径equalize针对单个订阅使用 Apple 的本地化均衡矩阵localized equalization matrix设置基准价格derive在两个订阅之间尽可能保持用户选定的本地价格倍数其保真度受限于目标订阅价格点阶梯的离散程度。因此derive不改变、不废弃equalize两者都是asc subscriptions pricing家族下的独立子命令。命令族注册见 internal/cli/subscriptions/pricing_family.go 的SubscriptionsPricingCommand()L13-L48其中子命令列表包含SubscriptionsPricingEqualizeCommand()与SubscriptionsPricingDeriveCommand()。1.3 范围与兼容性属于纯增量命令不改变任何既有命令、flag、API 请求或 JSON 输出初始版本仅支持标准UPFRONT价格且要求源与目标都是两个不同的、已有定价的订阅Monthly with 12-Month Commitment月度12 个月承诺计划不在范围内其可用性与价格约束不同由subscriptions pricing monthly-commitment单独管理见命令 LongHelp 与 pricing_family.go 的子命令注册注意UPFRONT是 Apple 的计费计划模式billing-plan mode不是订阅周期普通的ONE_MONTH、ONE_YEAR产品都使用UPFRONT因此本文示例中的月度→年度关系完全落在支持范围内。二、参数清单与校验规则2.1 完整参数表参数说明约束/默认--source-subscription-id源订阅 ID、产品 ID 或精确的当前名称必填--target-subscription-id目标订阅 ID、产品 ID 或精确的当前名称必填且必须解析为与源不同的订阅--appApp ID用于任一选择器为产品 ID 或名称时的归属解析可选可用ASC_APP_ID环境变量替代--multiplier正有限十进制倍率必填必须是正小数禁止二进制浮点使用精确十进制/有理数运算--round价格点解析策略exact、nearest、up、down默认nearest--territory限定单个地区地区 ID、2 字母代码或名称做聚焦预览/落地省略则覆盖源订阅所有有价格的地区--start-date计划生效日期YYYY-MM-DD可选--preserved为存量订阅者保留当前价格布尔默认 false--auto-start-date省略--start-date时为 approved/live 状态的目标订阅自动排期到明天布尔默认 true--workers并发规划 worker 与价格写入数范围 1-32默认 8--dry-run只计算并打印完整计划不产生写入与--confirm互斥--confirm确认执行写入除 dry-run 外必须与--dry-run互斥这些 flag 的定义可以在实现中逐一对照pricing_derive.go。--workers的默认值 8 与equalize共用defaultEqualizeWorkers常量见 pricing_equalize.go 与 pricing_derive.go。2.2 校验规则失败发生在创建客户端之前退出码 2文档明确非法或缺失的 flag 在创建 API 客户端之前即失败使用 usage 退出码 2。实现里对应shared.UsageError/shared.MissingRequiredUsageError的返回路径pricing_derive.go。规则要点两个订阅 ID 均必填且源与目标必须不同字面量与解析后两次校验--multiplier必须为正有限十进制。实现通过parseSubscriptionPriceDeriveMultiplier先做十进制字符白名单检查isSubscriptionPriceDeriveDecimal再用big.Rat.SetString解析并断言Sign() 0L656-L689从而拒绝0、负数、NaN、1/2这类分数写法--round只接受exact/nearest/up/downnormalizeSubscriptionPriceDeriveRoundingL691-L702--territory显式传空串会被拒绝非空值经ascterritory.Normalize归一化非法地区名报invalid --territory--workers必须在 1-32 之间L126-L128--dry-run与--confirm不得同时出现非 dry-run 模式必须带--confirm不接受位置参数Exec 入口首先拒绝len(args) 0。测试用例完整覆盖了上述每一条见 internal/cli/cmdtest/subscriptions_pricing_derive_test.goTestSubscriptionsPricingDeriveValidationErrors以及布尔 flag 非法值的退出码测试L245-L266。当选择器使用产品 ID 或名称时--app或ASC_APP_ID为硬性要求且该检查在认证之前执行L206-L224 的TestSubscriptionsPricingDeriveRequiresAppForLookupSelectorBeforeAuth。三、价格点解析四种舍入策略每个地区独立执行先算出精确有理数desired price再检查目标订阅在该地区的完整价格点阶梯按策略选择策略行为边界失败语义exact要求存在与期望价格相等的价格点无精确命中 → 行错误 no exact target price point for …nearest选择绝对价差最小的价格点平局取较低价避免隐性溢价无可用候选 → 行错误up选择大于等于期望价格的最低价格点阶梯中没有 ≥ 期望价 → 错误 no target price point at or above …down选择小于等于期望价格的最高价格点阶梯中没有 ≤ 期望价 → 错误 no target price point at or below …实现细节pricing_derive.go 的resolveSubscriptionPriceDerivePoint空阶梯、非法价格、同一价格点 ID 出现冲突价格、选中价格存在多个同价价格点重复 ID均作为显式行错误返回nearest的平局规则体现在subscriptionPriceDeriveCandidateIsNearerL804-L814距离相等时返回candidate selected即取较低价全程使用big.Rat有理数比较杜绝浮点误差。fail-closed 语义规划阶段只要有任何地区无法解析命令打印完整计划、退出码 1且不发出任何写入请求见文档 Output 章节与实现 L236-L245。测试TestSubscriptionsPricingDeriveApplyFailsClosedWhenExactPriceIsMissingL855-L931验证了--round exact无精确命中时mutationRequests 0且行状态为unresolved。noop 抑制若某地区当前目标价格点与解析出的价格点一致该行标记为noop在报告中展示但不参与写入实现 L528-L534测试TestSubscriptionsPricingDeriveApplySkipsMatchingTargetPriceL933-L1007 断言Noop 1、Applied 0、无任何 mutation 请求。值得注意的一个细节noop 判断针对的是目标价格在生效日start date时的有效值而非当前值。测试TestSubscriptionsPricingDeriveUsesTargetPriceEffectiveOnStartDateForNoopDetectionL540-L619构造了当前 89、未来 99两条价格记录验证了在--start-date 2099-01-02下按未来价格判断避免把将要变为 99 的 89误判为已匹配noop。四、API 编排流程纯客户端编排不引入新端点命令完全构建在既有公开 API 之上是纯客户端编排。设计文档给出的七步流程与实现一一对应解析两个订阅选择器resolveSubscriptionPriceDeriveLookupID将 ID/产品 ID/名称解析为订阅 IDL308-L327依赖shared.ResolveSubscriptionID读取源与目标当前UPFRONT价格GET /v1/subscriptions/{id}/prices带filter[planType]UPFRONT、地区过滤与effectiveAt参数fetchResolvedSubscriptionPrices。源订阅没有任何当前 UPFRONT 价格时报错终止目标必须有既有定价配置当聚焦--territory读取没有当前目标价格时会再发一次不带地区过滤的全局 preflight用于区分该地区缺价与目标完全未定价——只有前者允许继续规划更新实现 L194-L206测试 L393-L538 同时验证了两种分支包括目标targetPriceReads 2的断言批量读取目标价格点阶梯对GET /v1/subscriptions/{id}/pricePoints使用批量地区过滤filter[territory]A,B,…、includeterritory、fields[subscriptionPricePoints]customerPrice,territory、limit8000配合完整分页asc.PaginateEach在本地按地区分组阶梯——刻意避免为每个地区单独发分页请求fetchSubscriptionPriceDeriveCandidatesByTerritoryL551-L633请求参数被测试在 L293-L306 断言产出完整计划并标记 noop写入阶段POST /v1/subscriptionPrices请求体为SubscriptionPriceCreateRequest可选startDate、preserveCurrentPrice、planType以及指向目标订阅、地区和选定价格点的 relationships。测试TestSubscriptionsPricingDeriveApplyCreatesAndVerifiesTargetPriceL621-L768对请求体的planTypeUPFRONT、startDate、preserveCurrentPricetrue与 relationships 逐一断言写入后 readback 校验对模糊的传输失败先对照回读状态做对账、只重试可重试的 mutation然后重新读取目标生效价格并逐地区比对价格点 ID全部通过才返回成功verifySubscriptionPriceDeriveResultL329-L416不匹配时报 verification mismatch: expected target price point …, got …。并发写入通过applyEqualizedPrices以--workers并发执行与 equalize 共用实现。整个命令从不修改订阅的销售可用性sale availability。五、输出与失败行为结构化契约5.1 输出结构JSON 使用导出且带 camelCase 标签的结果结构体注册到共享输出渲染器internal/asc/output_subscription_pricing_derive.go 定义结构体output_registry_init.go 注册SubscriptionPricingDeriveResult的渲染。核心结构SubscriptionPricingDeriveResult顶层契约含sourceSubscriptionId、targetSubscriptionId、multiplier、rounding、startDate、autoScheduled、preserved、targetSubscriptionState、dryRun、summary、rows、verificationSubscriptionPricingDeriveRow每个地区一行含territory、currency、sourcePrice、sourcePricePointId、desiredPrice、currentTargetPrice、currentTargetPricePointId、targetPrice、targetPricePointId、requestedMultiple、achievedMultiple、multipleDelta、action、status、errorSubscriptionPricingDeriveSummarytotal / planned / noop / applied / verified / unresolved / failedSubscriptionPricingDeriveVerificationstatus、verified、failed。Table 与 Markdown 输出为摘要 逐行业务字段两段式数据走 stdout进度与诊断走 stderr例如 Fetching current source and target subscription prices...、Resolving target price points for N territories...、Verifying derived target prices...。5.2 退出码与失败语义场景行为成功的 dry-run退出码 0dryRun: true零 mutation 请求成功的 apply仅在 readback 校验通过后退出码 0规划期有无法解析的行打印完整计划退出码 1不发任何 mutation 请求部分写入失败或校验不匹配打印全部行结果退出码 1并逐一标识失败地区行状态机依次为unresolved → planned → applied → verified / failednoop独立于该链。测试断言了--dry-run下mutationRequests 0L336-L338、写入失败时结构化输出含 test rejection 且Verification.Status failedTestSubscriptionsPricingDeriveReportsMutationFailuresInStructuredOutputL770-L853。六、测试策略与验证门槛设计文档规划了三层测试仓库均已落地CLI 层 RED 覆盖命令注册、必填 flag、非法小数、相同订阅、非法舍入模式、worker 边界、位置参数、确认语义、混合 flag 位置——见 subscriptions_pricing_derive_test.go 的TestSubscriptionsPricingDeriveValidationErrors与TestSubscriptionsPricingDeriveHelpRegistersNewSurface后者逐一断言 12 个 flag 均已注册精确小数单元覆盖四种舍入策略、精确命中、nearest 平局、乱序阶梯、重复选中价格、畸形条目、缺失上下界resolveSubscriptionPriceDerivePoint的分支逻辑httptest命令级覆盖分页源/目标价格、分页目标阶梯、确定性行排序测试断言 SWE 行在前、USA 行在后、noop 抑制、fail-closed 规划、mutation 请求体、排期与 preserved 变更、限流对账、readback 校验、API 错误并解析 JSON 断言 stdout/stderr/退出行为。文档提到的最终验证路径还包括构建/tmp/asc、检查 help 与代表性用法失败、跑 generated-doc 检查、受影响包测试以及ASC_BYPASS_KEYCHAIN1的完整仓库门禁——仓库的 CI 与 Makefile 中对应此套流程可参考 Makefile 与 docs/TESTING.md。七、设计备选方案与取舍设计文档记录了三个方向的权衡用prices list --resolved 外部脚本 CSV 导入组合今天即可工作但舍入、审计输出、fail-closed 行为与校验都留给每个调用方自行实现——这正是derive要内建的价值实现 issue 928 中更宏大的 spec 驱动的pricing plan/apply工作流仍是值得继续的产品方向但体量远大于这个具体的源到目标定价任务。derive的规划引擎将来可以反哺该通用计划引擎而当前不承诺任何通用定价模板 schemaderive自身的定位窄聚焦、快照式、一次性执行与equalize各司其职。八、实战建议先 dry-run 后 confirm--dry-run是零风险预览输出中的desiredPrice与achievedMultiple让你能逐地区核对倍率保真度确认后再加--confirm执行善用--territory聚焦试点先用单一地区如--territory SWE验证阶梯解析结果再放开到全部地区聚焦模式下命令会自动做全局 preflight 以区分缺价地区与未定价目标注意nearest的平局取低价当期望价恰好在两个价格点正中间时命令选择较低价以避免隐性涨价规划时留意multipleDelta排期与存量保护--start-date排定生效日--auto-start-date默认开为 approved/live 目标自动排到明天--preserved为存量订阅者保留当前价格——三者可组合出平滑过渡的定价变更目标订阅必须先有定价对完全未定价的目标执行会直接报错并建议先用asc subscriptions pricing prices set初始化再运行 derive。相关资源设计文档docs/design/subscription-pricing-derive.md命令实现internal/cli/subscriptions/pricing_derive.go命令族注册internal/cli/subscriptions/pricing_family.go输出契约internal/asc/output_subscription_pricing_derive.go输出渲染注册internal/asc/output_registry_init.go端到端测试internal/cli/cmdtest/subscriptions_pricing_derive_test.go赞分享【免费下载链接】App-Store-Connect-CLIFast, scriptable CLI for the App Store Connect API. Automate TestFlight, builds, submissions, signing, analytics, screenshots, subscriptions, and more项目地址https://gitcode.com/gh_mirrors/ap/App-Store-Connect-CLI点击查看免费下载相关推荐App Store Connect CLI订阅与内购管理subscriptions、iap命令与定价配置完全指南App Store Connect CLI订阅与内购管理subscriptions、iap命令与定价配置完全指南 App Store Connect CLIReadest 年度订阅改造实录Stripe 价格编排、Billing Portal 换期与 Google Play IAP 订阅替换Readest 年度订阅改造实录Stripe 价格编排、Billing Portal 换期与 Google Play IAP 订阅替换 本文基于 Reades桌面应用跨平台前端Hyperapp 订阅系统完全指南subscriptions 架构原理与自定义订阅实战Hyperapp 订阅系统完全指南subscriptions 架构原理与自定义订阅实战 导读 本文以 Hyperapp 架构文档中的 subscriptio前端上一篇AI驱动的文档生成GitHub_Trending/cla/claude-skills文档技能详解下一篇FormsFX架构解析为什么它是JavaFX表单开发的革命性框架创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表