direct-cli 0.3.14__tar.gz → 0.3.15__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (235) hide show
  1. {direct_cli-0.3.14 → direct_cli-0.3.15}/CHANGELOG.md +27 -0
  2. {direct_cli-0.3.14 → direct_cli-0.3.15}/PKG-INFO +4 -4
  3. {direct_cli-0.3.14 → direct_cli-0.3.15}/README.md +3 -3
  4. {direct_cli-0.3.14 → direct_cli-0.3.15}/direct_cli/commands/v4finance.py +4 -35
  5. {direct_cli-0.3.14 → direct_cli-0.3.15}/direct_cli/v4_contracts.py +28 -18
  6. {direct_cli-0.3.14 → direct_cli-0.3.15}/direct_cli.egg-info/PKG-INFO +4 -4
  7. {direct_cli-0.3.14 → direct_cli-0.3.15}/direct_cli.egg-info/SOURCES.txt +1 -0
  8. {direct_cli-0.3.14 → direct_cli-0.3.15}/pyproject.toml +1 -1
  9. direct_cli-0.3.15/scripts/preflight_check.sh +62 -0
  10. {direct_cli-0.3.14 → direct_cli-0.3.15}/scripts/test_dangerous_commands.sh +1 -1
  11. {direct_cli-0.3.14 → direct_cli-0.3.15}/tests/API_COVERAGE.md +6 -5
  12. {direct_cli-0.3.14 → direct_cli-0.3.15}/tests/test_v4_contracts.py +4 -4
  13. {direct_cli-0.3.14 → direct_cli-0.3.15}/tests/test_v4finance_money.py +15 -20
  14. {direct_cli-0.3.14 → direct_cli-0.3.15}/.env.example +0 -0
  15. {direct_cli-0.3.14 → direct_cli-0.3.15}/.github/copilot-instructions.md +0 -0
  16. {direct_cli-0.3.14 → direct_cli-0.3.15}/.github/workflows/api-coverage.yml +0 -0
  17. {direct_cli-0.3.14 → direct_cli-0.3.15}/.github/workflows/claude.yml +0 -0
  18. {direct_cli-0.3.14 → direct_cli-0.3.15}/.github/workflows/quality.yml +0 -0
  19. {direct_cli-0.3.14 → direct_cli-0.3.15}/.gitignore +0 -0
  20. {direct_cli-0.3.14 → direct_cli-0.3.15}/AGENTS.md +0 -0
  21. {direct_cli-0.3.14 → direct_cli-0.3.15}/CLAUDE.md +0 -0
  22. {direct_cli-0.3.14 → direct_cli-0.3.15}/MANIFEST.in +0 -0
  23. {direct_cli-0.3.14 → direct_cli-0.3.15}/direct_cli/__init__.py +0 -0
  24. {direct_cli-0.3.14 → direct_cli-0.3.15}/direct_cli/_bidding_strategy.py +0 -0
  25. {direct_cli-0.3.14 → direct_cli-0.3.15}/direct_cli/_deprecated.py +0 -0
  26. {direct_cli-0.3.14 → direct_cli-0.3.15}/direct_cli/_smoke_probes.py +0 -0
  27. {direct_cli-0.3.14 → direct_cli-0.3.15}/direct_cli/_vendor/__init__.py +0 -0
  28. {direct_cli-0.3.14 → direct_cli-0.3.15}/direct_cli/_vendor/tapi_yandex_direct/__init__.py +0 -0
  29. {direct_cli-0.3.14 → direct_cli-0.3.15}/direct_cli/_vendor/tapi_yandex_direct/endpoints.py +0 -0
  30. {direct_cli-0.3.14 → direct_cli-0.3.15}/direct_cli/_vendor/tapi_yandex_direct/exceptions.py +0 -0
  31. {direct_cli-0.3.14 → direct_cli-0.3.15}/direct_cli/_vendor/tapi_yandex_direct/resource_mapping.py +0 -0
  32. {direct_cli-0.3.14 → direct_cli-0.3.15}/direct_cli/_vendor/tapi_yandex_direct/tapi_yandex_direct.py +0 -0
  33. {direct_cli-0.3.14 → direct_cli-0.3.15}/direct_cli/_vendor/tapi_yandex_direct/tapi_yandex_direct.pyi +0 -0
  34. {direct_cli-0.3.14 → direct_cli-0.3.15}/direct_cli/_vendor/tapi_yandex_direct/v4/__init__.py +0 -0
  35. {direct_cli-0.3.14 → direct_cli-0.3.15}/direct_cli/_vendor/tapi_yandex_direct/v4/adapter.py +0 -0
  36. {direct_cli-0.3.14 → direct_cli-0.3.15}/direct_cli/_vendor/tapi_yandex_direct/v4/adapter.pyi +0 -0
  37. {direct_cli-0.3.14 → direct_cli-0.3.15}/direct_cli/_vendor/tapi_yandex_direct/v4/resource_mapping.py +0 -0
  38. {direct_cli-0.3.14 → direct_cli-0.3.15}/direct_cli/api.py +0 -0
  39. {direct_cli-0.3.14 → direct_cli-0.3.15}/direct_cli/auth.py +0 -0
  40. {direct_cli-0.3.14 → direct_cli-0.3.15}/direct_cli/cli.py +0 -0
  41. {direct_cli-0.3.14 → direct_cli-0.3.15}/direct_cli/commands/__init__.py +0 -0
  42. {direct_cli-0.3.14 → direct_cli-0.3.15}/direct_cli/commands/adextensions.py +0 -0
  43. {direct_cli-0.3.14 → direct_cli-0.3.15}/direct_cli/commands/adgroups.py +0 -0
  44. {direct_cli-0.3.14 → direct_cli-0.3.15}/direct_cli/commands/adimages.py +0 -0
  45. {direct_cli-0.3.14 → direct_cli-0.3.15}/direct_cli/commands/ads.py +0 -0
  46. {direct_cli-0.3.14 → direct_cli-0.3.15}/direct_cli/commands/advideos.py +0 -0
  47. {direct_cli-0.3.14 → direct_cli-0.3.15}/direct_cli/commands/agencyclients.py +0 -0
  48. {direct_cli-0.3.14 → direct_cli-0.3.15}/direct_cli/commands/audiencetargets.py +0 -0
  49. {direct_cli-0.3.14 → direct_cli-0.3.15}/direct_cli/commands/auth.py +0 -0
  50. {direct_cli-0.3.14 → direct_cli-0.3.15}/direct_cli/commands/balance.py +0 -0
  51. {direct_cli-0.3.14 → direct_cli-0.3.15}/direct_cli/commands/bidmodifiers.py +0 -0
  52. {direct_cli-0.3.14 → direct_cli-0.3.15}/direct_cli/commands/bids.py +0 -0
  53. {direct_cli-0.3.14 → direct_cli-0.3.15}/direct_cli/commands/businesses.py +0 -0
  54. {direct_cli-0.3.14 → direct_cli-0.3.15}/direct_cli/commands/campaigns.py +0 -0
  55. {direct_cli-0.3.14 → direct_cli-0.3.15}/direct_cli/commands/changes.py +0 -0
  56. {direct_cli-0.3.14 → direct_cli-0.3.15}/direct_cli/commands/clients.py +0 -0
  57. {direct_cli-0.3.14 → direct_cli-0.3.15}/direct_cli/commands/creatives.py +0 -0
  58. {direct_cli-0.3.14 → direct_cli-0.3.15}/direct_cli/commands/dictionaries.py +0 -0
  59. {direct_cli-0.3.14 → direct_cli-0.3.15}/direct_cli/commands/dynamicads.py +0 -0
  60. {direct_cli-0.3.14 → direct_cli-0.3.15}/direct_cli/commands/dynamicfeedadtargets.py +0 -0
  61. {direct_cli-0.3.14 → direct_cli-0.3.15}/direct_cli/commands/feeds.py +0 -0
  62. {direct_cli-0.3.14 → direct_cli-0.3.15}/direct_cli/commands/keywordbids.py +0 -0
  63. {direct_cli-0.3.14 → direct_cli-0.3.15}/direct_cli/commands/keywords.py +0 -0
  64. {direct_cli-0.3.14 → direct_cli-0.3.15}/direct_cli/commands/keywordsresearch.py +0 -0
  65. {direct_cli-0.3.14 → direct_cli-0.3.15}/direct_cli/commands/leads.py +0 -0
  66. {direct_cli-0.3.14 → direct_cli-0.3.15}/direct_cli/commands/negativekeywordsharedsets.py +0 -0
  67. {direct_cli-0.3.14 → direct_cli-0.3.15}/direct_cli/commands/reports.py +0 -0
  68. {direct_cli-0.3.14 → direct_cli-0.3.15}/direct_cli/commands/retargeting.py +0 -0
  69. {direct_cli-0.3.14 → direct_cli-0.3.15}/direct_cli/commands/sitelinks.py +0 -0
  70. {direct_cli-0.3.14 → direct_cli-0.3.15}/direct_cli/commands/smartadtargets.py +0 -0
  71. {direct_cli-0.3.14 → direct_cli-0.3.15}/direct_cli/commands/strategies.py +0 -0
  72. {direct_cli-0.3.14 → direct_cli-0.3.15}/direct_cli/commands/turbopages.py +0 -0
  73. {direct_cli-0.3.14 → direct_cli-0.3.15}/direct_cli/commands/v4account.py +0 -0
  74. {direct_cli-0.3.14 → direct_cli-0.3.15}/direct_cli/commands/v4events.py +0 -0
  75. {direct_cli-0.3.14 → direct_cli-0.3.15}/direct_cli/commands/v4forecast.py +0 -0
  76. {direct_cli-0.3.14 → direct_cli-0.3.15}/direct_cli/commands/v4goals.py +0 -0
  77. {direct_cli-0.3.14 → direct_cli-0.3.15}/direct_cli/commands/v4shells.py +0 -0
  78. {direct_cli-0.3.14 → direct_cli-0.3.15}/direct_cli/commands/v4tags.py +0 -0
  79. {direct_cli-0.3.14 → direct_cli-0.3.15}/direct_cli/commands/v4wordstat.py +0 -0
  80. {direct_cli-0.3.14 → direct_cli-0.3.15}/direct_cli/commands/vcards.py +0 -0
  81. {direct_cli-0.3.14 → direct_cli-0.3.15}/direct_cli/output.py +0 -0
  82. {direct_cli-0.3.14 → direct_cli-0.3.15}/direct_cli/reports_coverage.py +0 -0
  83. {direct_cli-0.3.14 → direct_cli-0.3.15}/direct_cli/smoke_matrix.py +0 -0
  84. {direct_cli-0.3.14 → direct_cli-0.3.15}/direct_cli/utils.py +0 -0
  85. {direct_cli-0.3.14 → direct_cli-0.3.15}/direct_cli/v4/__init__.py +0 -0
  86. {direct_cli-0.3.14 → direct_cli-0.3.15}/direct_cli/v4/money.py +0 -0
  87. {direct_cli-0.3.14 → direct_cli-0.3.15}/direct_cli/wsdl_coverage.py +0 -0
  88. {direct_cli-0.3.14 → direct_cli-0.3.15}/direct_cli.egg-info/dependency_links.txt +0 -0
  89. {direct_cli-0.3.14 → direct_cli-0.3.15}/direct_cli.egg-info/entry_points.txt +0 -0
  90. {direct_cli-0.3.14 → direct_cli-0.3.15}/direct_cli.egg-info/requires.txt +0 -0
  91. {direct_cli-0.3.14 → direct_cli-0.3.15}/direct_cli.egg-info/top_level.txt +0 -0
  92. {direct_cli-0.3.14 → direct_cli-0.3.15}/docs/audits/issue-198-mutating-wsdl-audit.md +0 -0
  93. {direct_cli-0.3.14 → direct_cli-0.3.15}/docs/superpowers/plans/2026-04-12-issue-32-completion.md +0 -0
  94. {direct_cli-0.3.14 → direct_cli-0.3.15}/docs/superpowers/specs/2026-04-23-vendor-tapi-yandex-direct-design.md +0 -0
  95. {direct_cli-0.3.14 → direct_cli-0.3.15}/scripts/anonymize_cassettes.py +0 -0
  96. {direct_cli-0.3.14 → direct_cli-0.3.15}/scripts/build_api_coverage_checklist.py +0 -0
  97. {direct_cli-0.3.14 → direct_cli-0.3.15}/scripts/build_api_coverage_report.py +0 -0
  98. {direct_cli-0.3.14 → direct_cli-0.3.15}/scripts/build_wsdl_optional_field_audit.py +0 -0
  99. {direct_cli-0.3.14 → direct_cli-0.3.15}/scripts/check_all_docs_urls.py +0 -0
  100. {direct_cli-0.3.14 → direct_cli-0.3.15}/scripts/check_reports_drift.py +0 -0
  101. {direct_cli-0.3.14 → direct_cli-0.3.15}/scripts/check_wsdl_drift.py +0 -0
  102. {direct_cli-0.3.14 → direct_cli-0.3.15}/scripts/patch_vendor_imports.py +0 -0
  103. {direct_cli-0.3.14 → direct_cli-0.3.15}/scripts/refresh_reports_cache.py +0 -0
  104. {direct_cli-0.3.14 → direct_cli-0.3.15}/scripts/refresh_wsdl_cache.py +0 -0
  105. {direct_cli-0.3.14 → direct_cli-0.3.15}/scripts/release_pypi.sh +0 -0
  106. {direct_cli-0.3.14 → direct_cli-0.3.15}/scripts/sandbox_write_audit.py +0 -0
  107. {direct_cli-0.3.14 → direct_cli-0.3.15}/scripts/sandbox_write_live.py +0 -0
  108. {direct_cli-0.3.14 → direct_cli-0.3.15}/scripts/test_safe_commands.sh +0 -0
  109. {direct_cli-0.3.14 → direct_cli-0.3.15}/scripts/test_sandbox_write.sh +0 -0
  110. {direct_cli-0.3.14 → direct_cli-0.3.15}/scripts/update_vendor.sh +0 -0
  111. {direct_cli-0.3.14 → direct_cli-0.3.15}/setup.cfg +0 -0
  112. {direct_cli-0.3.14 → direct_cli-0.3.15}/setup.py +0 -0
  113. {direct_cli-0.3.14 → direct_cli-0.3.15}/tests/API_ISSUE_AUDIT.md +0 -0
  114. {direct_cli-0.3.14 → direct_cli-0.3.15}/tests/MANUAL_COVERAGE.md +0 -0
  115. {direct_cli-0.3.14 → direct_cli-0.3.15}/tests/WSDL_OPTIONAL_FIELD_AUDIT.md +0 -0
  116. {direct_cli-0.3.14 → direct_cli-0.3.15}/tests/__init__.py +0 -0
  117. {direct_cli-0.3.14 → direct_cli-0.3.15}/tests/_orphan_store.py +0 -0
  118. {direct_cli-0.3.14 → direct_cli-0.3.15}/tests/api_coverage_payloads.py +0 -0
  119. {direct_cli-0.3.14 → direct_cli-0.3.15}/tests/cassettes/test_integration_write/TestWriteAdExtensions.test_add_delete.yaml +0 -0
  120. {direct_cli-0.3.14 → direct_cli-0.3.15}/tests/cassettes/test_integration_write/TestWriteAdGroups.test_add_update_delete.yaml +0 -0
  121. {direct_cli-0.3.14 → direct_cli-0.3.15}/tests/cassettes/test_integration_write/TestWriteAdImages.test_add_delete.yaml +0 -0
  122. {direct_cli-0.3.14 → direct_cli-0.3.15}/tests/cassettes/test_integration_write/TestWriteAds.test_add_text_ad_update_delete.yaml +0 -0
  123. {direct_cli-0.3.14 → direct_cli-0.3.15}/tests/cassettes/test_integration_write/TestWriteAudienceTargets.test_add_delete.yaml +0 -0
  124. {direct_cli-0.3.14 → direct_cli-0.3.15}/tests/cassettes/test_integration_write/TestWriteBidModifiersAdd.test_add_delete_mobile.yaml +0 -0
  125. {direct_cli-0.3.14 → direct_cli-0.3.15}/tests/cassettes/test_integration_write/TestWriteBidModifiersSet.test_set_without_id_is_rejected.yaml +0 -0
  126. {direct_cli-0.3.14 → direct_cli-0.3.15}/tests/cassettes/test_integration_write/TestWriteBids.test_set_bid.yaml +0 -0
  127. {direct_cli-0.3.14 → direct_cli-0.3.15}/tests/cassettes/test_integration_write/TestWriteBidsRead.test_bids_get.yaml +0 -0
  128. {direct_cli-0.3.14 → direct_cli-0.3.15}/tests/cassettes/test_integration_write/TestWriteBidsRead.test_bids_set_auto.yaml +0 -0
  129. {direct_cli-0.3.14 → direct_cli-0.3.15}/tests/cassettes/test_integration_write/TestWriteCampaignDraftLifecycle.test_draft_create_get_delete.yaml +0 -0
  130. {direct_cli-0.3.14 → direct_cli-0.3.15}/tests/cassettes/test_integration_write/TestWriteCampaigns.test_campaign_lifecycle.yaml +0 -0
  131. {direct_cli-0.3.14 → direct_cli-0.3.15}/tests/cassettes/test_integration_write/TestWriteDynamicAds.test_add_update_delete.yaml +0 -0
  132. {direct_cli-0.3.14 → direct_cli-0.3.15}/tests/cassettes/test_integration_write/TestWriteFeeds.test_add_update_delete.yaml +0 -0
  133. {direct_cli-0.3.14 → direct_cli-0.3.15}/tests/cassettes/test_integration_write/TestWriteKeywordBids.test_set_keyword_bid.yaml +0 -0
  134. {direct_cli-0.3.14 → direct_cli-0.3.15}/tests/cassettes/test_integration_write/TestWriteKeywords.test_add_update_delete.yaml +0 -0
  135. {direct_cli-0.3.14 → direct_cli-0.3.15}/tests/cassettes/test_integration_write/TestWriteNegativeKeywordSharedSets.test_add_update_delete.yaml +0 -0
  136. {direct_cli-0.3.14 → direct_cli-0.3.15}/tests/cassettes/test_integration_write/TestWriteRetargeting.test_add_delete.yaml +0 -0
  137. {direct_cli-0.3.14 → direct_cli-0.3.15}/tests/cassettes/test_integration_write/TestWriteRetargetingUpdate.test_retargeting_update.yaml +0 -0
  138. {direct_cli-0.3.14 → direct_cli-0.3.15}/tests/cassettes/test_integration_write/TestWriteSitelinks.test_add_delete.yaml +0 -0
  139. {direct_cli-0.3.14 → direct_cli-0.3.15}/tests/cassettes/test_integration_write/TestWriteSmartAdTargets.test_add_update_delete.yaml +0 -0
  140. {direct_cli-0.3.14 → direct_cli-0.3.15}/tests/cassettes/test_integration_write/TestWriteStrategies.test_strategies_lifecycle.yaml +0 -0
  141. {direct_cli-0.3.14 → direct_cli-0.3.15}/tests/cassettes/test_integration_write/TestWriteVCards.test_add_delete.yaml +0 -0
  142. {direct_cli-0.3.14 → direct_cli-0.3.15}/tests/cassettes/test_v5_live_write/test_v5_live_draft_adgroups_add_update_delete.yaml +0 -0
  143. {direct_cli-0.3.14 → direct_cli-0.3.15}/tests/cassettes/test_v5_live_write/test_v5_live_draft_adimages_add_get_delete.yaml +0 -0
  144. {direct_cli-0.3.14 → direct_cli-0.3.15}/tests/cassettes/test_v5_live_write/test_v5_live_draft_ads_add_update_delete.yaml +0 -0
  145. {direct_cli-0.3.14 → direct_cli-0.3.15}/tests/cassettes/test_v5_live_write/test_v5_live_draft_ads_suspend_resume_archive_unarchive.yaml +0 -0
  146. {direct_cli-0.3.14 → direct_cli-0.3.15}/tests/cassettes/test_v5_live_write/test_v5_live_draft_advideos_add_get.yaml +0 -0
  147. {direct_cli-0.3.14 → direct_cli-0.3.15}/tests/cassettes/test_v5_live_write/test_v5_live_draft_audiencetargets_add_delete.yaml +0 -0
  148. {direct_cli-0.3.14 → direct_cli-0.3.15}/tests/cassettes/test_v5_live_write/test_v5_live_draft_audiencetargets_suspend_resume.yaml +0 -0
  149. {direct_cli-0.3.14 → direct_cli-0.3.15}/tests/cassettes/test_v5_live_write/test_v5_live_draft_bids_set.yaml +0 -0
  150. {direct_cli-0.3.14 → direct_cli-0.3.15}/tests/cassettes/test_v5_live_write/test_v5_live_draft_campaign_create_get_delete.yaml +0 -0
  151. {direct_cli-0.3.14 → direct_cli-0.3.15}/tests/cassettes/test_v5_live_write/test_v5_live_draft_creatives_chain_advideo_to_creative.yaml +0 -0
  152. {direct_cli-0.3.14 → direct_cli-0.3.15}/tests/cassettes/test_v5_live_write/test_v5_live_draft_dynamicads_add_delete.yaml +0 -0
  153. {direct_cli-0.3.14 → direct_cli-0.3.15}/tests/cassettes/test_v5_live_write/test_v5_live_draft_dynamicads_suspend_resume.yaml +0 -0
  154. {direct_cli-0.3.14 → direct_cli-0.3.15}/tests/cassettes/test_v5_live_write/test_v5_live_draft_keywordbids_set.yaml +0 -0
  155. {direct_cli-0.3.14 → direct_cli-0.3.15}/tests/cassettes/test_v5_live_write/test_v5_live_draft_keywords_add_update_delete.yaml +0 -0
  156. {direct_cli-0.3.14 → direct_cli-0.3.15}/tests/cassettes/test_v5_live_write/test_v5_live_draft_keywords_suspend_resume.yaml +0 -0
  157. {direct_cli-0.3.14 → direct_cli-0.3.15}/tests/cassettes/test_v5_live_write/test_v5_live_draft_sitelinks_add_get_delete.yaml +0 -0
  158. {direct_cli-0.3.14 → direct_cli-0.3.15}/tests/cassettes/test_v5_live_write/test_v5_live_draft_smartadtargets_add_update_delete.yaml +0 -0
  159. {direct_cli-0.3.14 → direct_cli-0.3.15}/tests/cassettes/test_v5_live_write/test_v5_live_draft_smartadtargets_suspend_resume.yaml +0 -0
  160. {direct_cli-0.3.14 → direct_cli-0.3.15}/tests/conftest.py +0 -0
  161. {direct_cli-0.3.14 → direct_cli-0.3.15}/tests/fixtures/test-video.mp4 +0 -0
  162. {direct_cli-0.3.14 → direct_cli-0.3.15}/tests/reports_cache/raw/fields-list.html +0 -0
  163. {direct_cli-0.3.14 → direct_cli-0.3.15}/tests/reports_cache/raw/headers.html +0 -0
  164. {direct_cli-0.3.14 → direct_cli-0.3.15}/tests/reports_cache/raw/period.html +0 -0
  165. {direct_cli-0.3.14 → direct_cli-0.3.15}/tests/reports_cache/raw/spec.html +0 -0
  166. {direct_cli-0.3.14 → direct_cli-0.3.15}/tests/reports_cache/raw/type.html +0 -0
  167. {direct_cli-0.3.14 → direct_cli-0.3.15}/tests/reports_cache/spec.json +0 -0
  168. {direct_cli-0.3.14 → direct_cli-0.3.15}/tests/test_api_coverage.py +0 -0
  169. {direct_cli-0.3.14 → direct_cli-0.3.15}/tests/test_auth_bw.py +0 -0
  170. {direct_cli-0.3.14 → direct_cli-0.3.15}/tests/test_auth_oauth.py +0 -0
  171. {direct_cli-0.3.14 → direct_cli-0.3.15}/tests/test_auth_op.py +0 -0
  172. {direct_cli-0.3.14 → direct_cli-0.3.15}/tests/test_auth_write_json.py +0 -0
  173. {direct_cli-0.3.14 → direct_cli-0.3.15}/tests/test_balance.py +0 -0
  174. {direct_cli-0.3.14 → direct_cli-0.3.15}/tests/test_changes.py +0 -0
  175. {direct_cli-0.3.14 → direct_cli-0.3.15}/tests/test_cli.py +0 -0
  176. {direct_cli-0.3.14 → direct_cli-0.3.15}/tests/test_cli_contract.py +0 -0
  177. {direct_cli-0.3.14 → direct_cli-0.3.15}/tests/test_comprehensive.py +0 -0
  178. {direct_cli-0.3.14 → direct_cli-0.3.15}/tests/test_dry_run.py +0 -0
  179. {direct_cli-0.3.14 → direct_cli-0.3.15}/tests/test_env_loading.py +0 -0
  180. {direct_cli-0.3.14 → direct_cli-0.3.15}/tests/test_integration.py +0 -0
  181. {direct_cli-0.3.14 → direct_cli-0.3.15}/tests/test_integration_write.py +0 -0
  182. {direct_cli-0.3.14 → direct_cli-0.3.15}/tests/test_low_coverage_payloads.py +0 -0
  183. {direct_cli-0.3.14 → direct_cli-0.3.15}/tests/test_reports_drift.py +0 -0
  184. {direct_cli-0.3.14 → direct_cli-0.3.15}/tests/test_reports_parsing.py +0 -0
  185. {direct_cli-0.3.14 → direct_cli-0.3.15}/tests/test_sandbox_write_audit.py +0 -0
  186. {direct_cli-0.3.14 → direct_cli-0.3.15}/tests/test_smoke_matrix.py +0 -0
  187. {direct_cli-0.3.14 → direct_cli-0.3.15}/tests/test_transport_contract.py +0 -0
  188. {direct_cli-0.3.14 → direct_cli-0.3.15}/tests/test_unknown_option_hints.py +0 -0
  189. {direct_cli-0.3.14 → direct_cli-0.3.15}/tests/test_v4_exit_codes.py +0 -0
  190. {direct_cli-0.3.14 → direct_cli-0.3.15}/tests/test_v4_foundation.py +0 -0
  191. {direct_cli-0.3.14 → direct_cli-0.3.15}/tests/test_v4_live_contracts.py +0 -0
  192. {direct_cli-0.3.14 → direct_cli-0.3.15}/tests/test_v4_runtime_shape.py +0 -0
  193. {direct_cli-0.3.14 → direct_cli-0.3.15}/tests/test_v4_safety.py +0 -0
  194. {direct_cli-0.3.14 → direct_cli-0.3.15}/tests/test_v4account.py +0 -0
  195. {direct_cli-0.3.14 → direct_cli-0.3.15}/tests/test_v4events.py +0 -0
  196. {direct_cli-0.3.14 → direct_cli-0.3.15}/tests/test_v4finance_read.py +0 -0
  197. {direct_cli-0.3.14 → direct_cli-0.3.15}/tests/test_v4forecast.py +0 -0
  198. {direct_cli-0.3.14 → direct_cli-0.3.15}/tests/test_v4goals.py +0 -0
  199. {direct_cli-0.3.14 → direct_cli-0.3.15}/tests/test_v4tags.py +0 -0
  200. {direct_cli-0.3.14 → direct_cli-0.3.15}/tests/test_v4wordstat.py +0 -0
  201. {direct_cli-0.3.14 → direct_cli-0.3.15}/tests/test_v5_live_write.py +0 -0
  202. {direct_cli-0.3.14 → direct_cli-0.3.15}/tests/test_vendor_imports.py +0 -0
  203. {direct_cli-0.3.14 → direct_cli-0.3.15}/tests/test_wsdl_parity_gate.py +0 -0
  204. {direct_cli-0.3.14 → direct_cli-0.3.15}/tests/wsdl_cache/adextensions.xml +0 -0
  205. {direct_cli-0.3.14 → direct_cli-0.3.15}/tests/wsdl_cache/adgroups.xml +0 -0
  206. {direct_cli-0.3.14 → direct_cli-0.3.15}/tests/wsdl_cache/adimages.xml +0 -0
  207. {direct_cli-0.3.14 → direct_cli-0.3.15}/tests/wsdl_cache/ads.xml +0 -0
  208. {direct_cli-0.3.14 → direct_cli-0.3.15}/tests/wsdl_cache/advideos.xml +0 -0
  209. {direct_cli-0.3.14 → direct_cli-0.3.15}/tests/wsdl_cache/agencyclients.xml +0 -0
  210. {direct_cli-0.3.14 → direct_cli-0.3.15}/tests/wsdl_cache/audiencetargets.xml +0 -0
  211. {direct_cli-0.3.14 → direct_cli-0.3.15}/tests/wsdl_cache/bidmodifiers.xml +0 -0
  212. {direct_cli-0.3.14 → direct_cli-0.3.15}/tests/wsdl_cache/bids.xml +0 -0
  213. {direct_cli-0.3.14 → direct_cli-0.3.15}/tests/wsdl_cache/businesses.xml +0 -0
  214. {direct_cli-0.3.14 → direct_cli-0.3.15}/tests/wsdl_cache/campaigns.xml +0 -0
  215. {direct_cli-0.3.14 → direct_cli-0.3.15}/tests/wsdl_cache/changes.xml +0 -0
  216. {direct_cli-0.3.14 → direct_cli-0.3.15}/tests/wsdl_cache/clients.xml +0 -0
  217. {direct_cli-0.3.14 → direct_cli-0.3.15}/tests/wsdl_cache/creatives.xml +0 -0
  218. {direct_cli-0.3.14 → direct_cli-0.3.15}/tests/wsdl_cache/dictionaries.xml +0 -0
  219. {direct_cli-0.3.14 → direct_cli-0.3.15}/tests/wsdl_cache/dynamicfeedadtargets.xml +0 -0
  220. {direct_cli-0.3.14 → direct_cli-0.3.15}/tests/wsdl_cache/dynamictextadtargets.xml +0 -0
  221. {direct_cli-0.3.14 → direct_cli-0.3.15}/tests/wsdl_cache/feeds.xml +0 -0
  222. {direct_cli-0.3.14 → direct_cli-0.3.15}/tests/wsdl_cache/imports/adextensiontypes.xsd +0 -0
  223. {direct_cli-0.3.14 → direct_cli-0.3.15}/tests/wsdl_cache/imports/general.xsd +0 -0
  224. {direct_cli-0.3.14 → direct_cli-0.3.15}/tests/wsdl_cache/imports/generalclients.xsd +0 -0
  225. {direct_cli-0.3.14 → direct_cli-0.3.15}/tests/wsdl_cache/keywordbids.xml +0 -0
  226. {direct_cli-0.3.14 → direct_cli-0.3.15}/tests/wsdl_cache/keywords.xml +0 -0
  227. {direct_cli-0.3.14 → direct_cli-0.3.15}/tests/wsdl_cache/keywordsresearch.xml +0 -0
  228. {direct_cli-0.3.14 → direct_cli-0.3.15}/tests/wsdl_cache/leads.xml +0 -0
  229. {direct_cli-0.3.14 → direct_cli-0.3.15}/tests/wsdl_cache/negativekeywordsharedsets.xml +0 -0
  230. {direct_cli-0.3.14 → direct_cli-0.3.15}/tests/wsdl_cache/retargetinglists.xml +0 -0
  231. {direct_cli-0.3.14 → direct_cli-0.3.15}/tests/wsdl_cache/sitelinks.xml +0 -0
  232. {direct_cli-0.3.14 → direct_cli-0.3.15}/tests/wsdl_cache/smartadtargets.xml +0 -0
  233. {direct_cli-0.3.14 → direct_cli-0.3.15}/tests/wsdl_cache/strategies.xml +0 -0
  234. {direct_cli-0.3.14 → direct_cli-0.3.15}/tests/wsdl_cache/turbopages.xml +0 -0
  235. {direct_cli-0.3.14 → direct_cli-0.3.15}/tests/wsdl_cache/vcards.xml +0 -0
@@ -1,5 +1,32 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.3.15
4
+
5
+ **BREAKING CHANGES:**
6
+
7
+ - `direct v4finance transfer-money` no longer accepts `--currency`, and
8
+ the wire-body no longer carries `Currency` on `FromCampaigns`/
9
+ `ToCampaigns` items. The official v4 docs
10
+ (`dg-v4/reference/TransferMoney`) define `PayCampElement` with only
11
+ `CampaignID` and `Sum`; `Sum` is in conventional units. The CLI now
12
+ matches the docs 1:1. Closes #432.
13
+ - `direct v4finance pay-campaigns` no longer accepts `--currency`. The
14
+ v4 documentation (`dg-v4/reference/PayCampaigns`) defines
15
+ `PayCampElement` with only `CampaignID` and `Sum` — `Currency` is not
16
+ part of the wire-body and was never forwarded to the API. The option
17
+ is removed entirely to make the CLI surface 1:1 with the docs.
18
+ - `direct v4finance pay-campaigns` no longer accepts `--pay-method
19
+ Overdraft`. The v4 documentation
20
+ (`dg-v4/reference/PayCampaigns#PayMethod`) lists only `"Bank"` as a
21
+ supported value; `Overdraft` was a historical undocumented value
22
+ retained by the CLI for sandbox flow. Strict 1:1 docs alignment
23
+ drops it.
24
+ - `direct v4finance create-invoice` no longer accepts `--currency`. The
25
+ v4 documentation (`dg-v4/reference/CreateInvoice`) defines
26
+ `PayCampElement` with only `CampaignID` and `Sum` — `Currency` is not
27
+ part of the wire-body and was never forwarded to the API. The option
28
+ is removed entirely to make the CLI surface 1:1 with the docs.
29
+
3
30
  ## 0.3.14
4
31
 
5
32
  **Fixed:**
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: direct-cli
3
- Version: 0.3.14
3
+ Version: 0.3.15
4
4
  Summary: Command-line interface for Yandex Direct API
5
5
  Author: axisrow
6
6
  License: MIT
@@ -232,10 +232,10 @@ is omitted. Dry-run output masks the financial token.
232
232
  ```bash
233
233
  direct v4finance get-clients-units --logins client-login,other-client --format table
234
234
  direct v4finance get-credit-limits --master-token MASTER_TOKEN --operation-num 123 --finance-login agency-login
235
- direct v4finance create-invoice --payment 123=100.50 --payment 456=25 --currency RUB --master-token MASTER_TOKEN --operation-num 124 --finance-login agency-login --dry-run
235
+ direct v4finance create-invoice --payment 123=100.50 --payment 456=25 --master-token MASTER_TOKEN --operation-num 124 --finance-login agency-login --dry-run
236
236
  direct v4finance check-payment --custom-transaction-id A123456789012345678901234567890B
237
- direct v4finance transfer-money --from-campaign-id 123 --to-campaign-id 456 --amount 100.50 --currency RUB --master-token MASTER_TOKEN --operation-num 123 --finance-login agency-login --dry-run
238
- direct v4finance pay-campaigns --campaign-ids 123,456 --amount 100.50 --currency RUB --contract-id CONTRACT_ID --pay-method Bank --master-token MASTER_TOKEN --operation-num 123 --finance-login agency-login --dry-run
237
+ direct v4finance transfer-money --from-campaign-id 123 --to-campaign-id 456 --amount 100.50 --master-token MASTER_TOKEN --operation-num 123 --finance-login agency-login --dry-run
238
+ direct v4finance pay-campaigns --campaign-ids 123,456 --amount 100.50 --contract-id CONTRACT_ID --pay-method Bank --master-token MASTER_TOKEN --operation-num 123 --finance-login agency-login --dry-run
239
239
  ```
240
240
 
241
241
  ### V4 Live Shared Account
@@ -189,10 +189,10 @@ is omitted. Dry-run output masks the financial token.
189
189
  ```bash
190
190
  direct v4finance get-clients-units --logins client-login,other-client --format table
191
191
  direct v4finance get-credit-limits --master-token MASTER_TOKEN --operation-num 123 --finance-login agency-login
192
- direct v4finance create-invoice --payment 123=100.50 --payment 456=25 --currency RUB --master-token MASTER_TOKEN --operation-num 124 --finance-login agency-login --dry-run
192
+ direct v4finance create-invoice --payment 123=100.50 --payment 456=25 --master-token MASTER_TOKEN --operation-num 124 --finance-login agency-login --dry-run
193
193
  direct v4finance check-payment --custom-transaction-id A123456789012345678901234567890B
194
- direct v4finance transfer-money --from-campaign-id 123 --to-campaign-id 456 --amount 100.50 --currency RUB --master-token MASTER_TOKEN --operation-num 123 --finance-login agency-login --dry-run
195
- direct v4finance pay-campaigns --campaign-ids 123,456 --amount 100.50 --currency RUB --contract-id CONTRACT_ID --pay-method Bank --master-token MASTER_TOKEN --operation-num 123 --finance-login agency-login --dry-run
194
+ direct v4finance transfer-money --from-campaign-id 123 --to-campaign-id 456 --amount 100.50 --master-token MASTER_TOKEN --operation-num 123 --finance-login agency-login --dry-run
195
+ direct v4finance pay-campaigns --campaign-ids 123,456 --amount 100.50 --contract-id CONTRACT_ID --pay-method Bank --master-token MASTER_TOKEN --operation-num 123 --finance-login agency-login --dry-run
196
196
  ```
197
197
 
198
198
  ### V4 Live Shared Account
@@ -15,8 +15,7 @@ from .v4shells import V4_EPILOG
15
15
 
16
16
  FINANCE_TOKEN_MASK = "<redacted>"
17
17
  CUSTOM_TRANSACTION_ID_RE = re.compile(r"[A-Za-z0-9]{32}")
18
- V4_FINANCE_CURRENCIES = ["RUB", "USD", "EUR", "BYN", "KZT", "TRY", "UAH", "CHF"]
19
- V4_PAY_METHODS = ["Bank", "Overdraft"]
18
+ V4_PAY_METHODS = ["Bank"]
20
19
  FINANCE_HELP_EPILOG = (
21
20
  "To issue a master token in the Yandex Direct UI, open Tools -> API -> "
22
21
  "Financial operations, enable the 'Allow financial operations' checkbox, "
@@ -34,14 +33,13 @@ def _logins_param(logins: str) -> list[str]:
34
33
  return login_list
35
34
 
36
35
 
37
- def _invoice_payments_param(payments: tuple[str, ...], currency: str) -> dict:
36
+ def _invoice_payments_param(payments: tuple[str, ...]) -> dict:
38
37
  """Build the v4 Live CreateInvoice payment object parameter."""
39
38
  if not payments:
40
39
  raise click.UsageError("--payment is required")
41
40
 
42
41
  parsed_payments = []
43
42
  seen_campaign_ids = set()
44
- normalized_currency = currency.upper()
45
43
  for payment in payments:
46
44
  spec = (payment or "").strip()
47
45
  if "=" not in spec:
@@ -64,7 +62,6 @@ def _invoice_payments_param(payments: tuple[str, ...], currency: str) -> dict:
64
62
  {
65
63
  "CampaignID": campaign_id,
66
64
  "Sum": parse_v4_money_sum(amount_text),
67
- "Currency": normalized_currency,
68
65
  }
69
66
  )
70
67
 
@@ -333,13 +330,6 @@ def check_payment(
333
330
  required=True,
334
331
  help="Invoice payment as CAMPAIGN_ID=AMOUNT; repeat for multiple campaigns",
335
332
  )
336
- @click.option(
337
- "--currency",
338
- default="RUB",
339
- show_default=True,
340
- type=click.Choice(V4_FINANCE_CURRENCIES, case_sensitive=False),
341
- help="Payment currency",
342
- )
343
333
  @click.option(
344
334
  "--finance-token",
345
335
  envvar="YANDEX_DIRECT_FINANCE_TOKEN",
@@ -377,7 +367,6 @@ def check_payment(
377
367
  def create_invoice(
378
368
  ctx,
379
369
  payments,
380
- currency,
381
370
  finance_token,
382
371
  master_token,
383
372
  operation_num,
@@ -395,7 +384,7 @@ def create_invoice(
395
384
  "CreateInvoice",
396
385
  ctx.obj.get("login"),
397
386
  )
398
- param = _invoice_payments_param(payments, currency)
387
+ param = _invoice_payments_param(payments)
399
388
 
400
389
  if dry_run:
401
390
  format_output(
@@ -438,13 +427,6 @@ def create_invoice(
438
427
  help="Destination campaign ID",
439
428
  )
440
429
  @click.option("--amount", required=True, help="Positive amount, for example 100.50")
441
- @click.option(
442
- "--currency",
443
- default="RUB",
444
- show_default=True,
445
- type=click.Choice(V4_FINANCE_CURRENCIES, case_sensitive=False),
446
- help="Payment currency",
447
- )
448
430
  @click.option(
449
431
  "--finance-token",
450
432
  envvar="YANDEX_DIRECT_FINANCE_TOKEN",
@@ -480,7 +462,6 @@ def transfer_money(
480
462
  from_campaign_id,
481
463
  to_campaign_id,
482
464
  amount,
483
- currency,
484
465
  finance_token,
485
466
  master_token,
486
467
  operation_num,
@@ -498,20 +479,17 @@ def transfer_money(
498
479
  ctx.obj.get("login"),
499
480
  )
500
481
  parsed_amount = parse_v4_money_sum(amount)
501
- currency = currency.upper()
502
482
  param = {
503
483
  "FromCampaigns": [
504
484
  {
505
485
  "CampaignID": from_campaign_id,
506
486
  "Sum": parsed_amount,
507
- "Currency": currency,
508
487
  },
509
488
  ],
510
489
  "ToCampaigns": [
511
490
  {
512
491
  "CampaignID": to_campaign_id,
513
492
  "Sum": parsed_amount,
514
- "Currency": currency,
515
493
  },
516
494
  ],
517
495
  }
@@ -531,13 +509,6 @@ def transfer_money(
531
509
  help="Comma-separated campaign IDs to pay",
532
510
  )
533
511
  @click.option("--amount", required=True, help="Positive amount, for example 100.50")
534
- @click.option(
535
- "--currency",
536
- default="RUB",
537
- show_default=True,
538
- type=click.Choice(V4_FINANCE_CURRENCIES, case_sensitive=False),
539
- help="Payment currency",
540
- )
541
512
  @click.option("--contract-id", help="Agency contract ID; required for Bank")
542
513
  @click.option(
543
514
  "--pay-method",
@@ -579,7 +550,6 @@ def pay_campaigns(
579
550
  ctx,
580
551
  campaign_ids,
581
552
  amount,
582
- currency,
583
553
  contract_id,
584
554
  pay_method,
585
555
  finance_token,
@@ -600,14 +570,13 @@ def pay_campaigns(
600
570
  )
601
571
  parsed_amount = parse_v4_money_sum(amount)
602
572
  parsed_campaign_ids = _campaign_ids_param(campaign_ids)
603
- currency = currency.upper()
604
573
  pay_method = _non_empty_option(pay_method, "--pay-method")
605
574
  contract_id = (contract_id or "").strip()
606
575
  if pay_method == "Bank" and not contract_id:
607
576
  raise click.UsageError("--contract-id is required when --pay-method Bank")
608
577
  param = {
609
578
  "Payments": [
610
- {"CampaignID": campaign_id, "Sum": parsed_amount, "Currency": currency}
579
+ {"CampaignID": campaign_id, "Sum": parsed_amount}
611
580
  for campaign_id in parsed_campaign_ids
612
581
  ],
613
582
  "PayMethod": pay_method,
@@ -69,10 +69,10 @@ V4_METHOD_CONTRACTS: dict[str, V4MethodContract] = {
69
69
  live_probe_allowed=False,
70
70
  example_param=None,
71
71
  notes=(
72
- "Official docs (dg-v4/reference/GetCreditLimits) define the "
73
- "request body as method + finance_token + operation_num only; "
74
- "no param. Live probe without finance credentials returns "
75
- "error_code=350."
72
+ "Docs-verified 2026-05-28 against dg-v4/reference/GetCreditLimits: "
73
+ "request body is method + finance_token + operation_num only, "
74
+ "no param; CLI dry-run output matches exactly. Live probe "
75
+ "without finance credentials returns error_code=350."
76
76
  ),
77
77
  ),
78
78
  "TransferMoney": V4MethodContract(
@@ -87,13 +87,15 @@ V4_METHOD_CONTRACTS: dict[str, V4MethodContract] = {
87
87
  source_status=SOURCE_DOCS,
88
88
  live_probe_allowed=False,
89
89
  example_param={
90
- "FromCampaigns": [{"CampaignID": 123, "Sum": 100.5, "Currency": "RUB"}],
91
- "ToCampaigns": [{"CampaignID": 456, "Sum": 100.5, "Currency": "RUB"}],
90
+ "FromCampaigns": [{"CampaignID": 123, "Sum": 100.5}],
91
+ "ToCampaigns": [{"CampaignID": 456, "Sum": 100.5}],
92
92
  },
93
93
  notes=(
94
- "Official v4 docs define campaign-to-campaign transfer with "
95
- "Currency on each transfer item. "
96
- "This CLI exposes dry-run only; the method is not live-probed."
94
+ "Docs-verified 2026-05-28 against dg-v4/reference/TransferMoney: "
95
+ "PayCampElement carries only CampaignID and Sum (conventional "
96
+ "units, условные единицы). Total from-sum must equal total "
97
+ "to-sum or the API returns error_code=353. This CLI exposes "
98
+ "dry-run only; the method is not live-probed."
97
99
  ),
98
100
  ),
99
101
  "PayCampaigns": V4MethodContract(
@@ -108,14 +110,17 @@ V4_METHOD_CONTRACTS: dict[str, V4MethodContract] = {
108
110
  source_status=SOURCE_DOCS,
109
111
  live_probe_allowed=False,
110
112
  example_param={
111
- "Payments": [{"CampaignID": 123, "Sum": 100.5, "Currency": "RUB"}],
113
+ "Payments": [{"CampaignID": 123, "Sum": 100.5}],
112
114
  "ContractID": "contract-id",
113
115
  "PayMethod": "Bank",
114
116
  },
115
117
  notes=(
116
- "Official v4 docs define agency credit-limit payment with "
117
- "Currency on each payment item and PayMethod Bank/Overdraft. "
118
- "This CLI exposes dry-run only; the method is not live-probed."
118
+ "Docs-verified 2026-05-28 against dg-v4/reference/PayCampaigns: "
119
+ "PayCampElement carries only CampaignID and Sum (conventional "
120
+ "units); PayMethod currently accepts 'Bank' only. The CLI "
121
+ "dropped --currency and the undocumented 'Overdraft' PayMethod "
122
+ "value in 0.3.15 (BREAKING) to mirror docs 1:1. This CLI "
123
+ "exposes dry-run only; the method is not live-probed."
119
124
  ),
120
125
  ),
121
126
  "PayCampaignsByCard": V4MethodContract(
@@ -143,7 +148,10 @@ V4_METHOD_CONTRACTS: dict[str, V4MethodContract] = {
143
148
  "Official public docs were not found. Sandbox v4 Live rejects "
144
149
  "PaymentID with error_code=71 and requires CustomTransactionID; "
145
150
  "a valid 32-character unknown CustomTransactionID reaches method "
146
- "validation and returns error_code=370."
151
+ "validation and returns error_code=370. "
152
+ "Docs-verified 2026-05-28: method is absent from the v4 "
153
+ "_AllMethods index (dg-v4/ru/reference/_AllMethods); sandbox "
154
+ "behaviour remains the source of truth for the wire shape."
147
155
  ),
148
156
  ),
149
157
  "CreateInvoice": V4MethodContract(
@@ -158,12 +166,14 @@ V4_METHOD_CONTRACTS: dict[str, V4MethodContract] = {
158
166
  source_status=SOURCE_DOCS,
159
167
  live_probe_allowed=False,
160
168
  example_param={
161
- "Payments": [{"CampaignID": 123, "Sum": 100.5, "Currency": "RUB"}],
169
+ "Payments": [{"CampaignID": 123, "Sum": 100.5}],
162
170
  },
163
171
  notes=(
164
- "Official v4 docs define invoice creation with Payments[]."
165
- "CampaignID/Sum/Currency and a URL response. The method has no "
166
- "v5 equivalent and requires finance_token plus operation_num."
172
+ "Docs-verified 2026-05-28 against dg-v4/reference/CreateInvoice: "
173
+ "PayCampElement carries only CampaignID and Sum (conventional "
174
+ "units). The CLI dropped --currency in 0.3.15 (BREAKING) to "
175
+ "mirror docs 1:1. The method has no v5 equivalent and requires "
176
+ "finance_token plus operation_num."
167
177
  ),
168
178
  ),
169
179
  "AccountManagement": V4MethodContract(
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: direct-cli
3
- Version: 0.3.14
3
+ Version: 0.3.15
4
4
  Summary: Command-line interface for Yandex Direct API
5
5
  Author: axisrow
6
6
  License: MIT
@@ -232,10 +232,10 @@ is omitted. Dry-run output masks the financial token.
232
232
  ```bash
233
233
  direct v4finance get-clients-units --logins client-login,other-client --format table
234
234
  direct v4finance get-credit-limits --master-token MASTER_TOKEN --operation-num 123 --finance-login agency-login
235
- direct v4finance create-invoice --payment 123=100.50 --payment 456=25 --currency RUB --master-token MASTER_TOKEN --operation-num 124 --finance-login agency-login --dry-run
235
+ direct v4finance create-invoice --payment 123=100.50 --payment 456=25 --master-token MASTER_TOKEN --operation-num 124 --finance-login agency-login --dry-run
236
236
  direct v4finance check-payment --custom-transaction-id A123456789012345678901234567890B
237
- direct v4finance transfer-money --from-campaign-id 123 --to-campaign-id 456 --amount 100.50 --currency RUB --master-token MASTER_TOKEN --operation-num 123 --finance-login agency-login --dry-run
238
- direct v4finance pay-campaigns --campaign-ids 123,456 --amount 100.50 --currency RUB --contract-id CONTRACT_ID --pay-method Bank --master-token MASTER_TOKEN --operation-num 123 --finance-login agency-login --dry-run
237
+ direct v4finance transfer-money --from-campaign-id 123 --to-campaign-id 456 --amount 100.50 --master-token MASTER_TOKEN --operation-num 123 --finance-login agency-login --dry-run
238
+ direct v4finance pay-campaigns --campaign-ids 123,456 --amount 100.50 --contract-id CONTRACT_ID --pay-method Bank --master-token MASTER_TOKEN --operation-num 123 --finance-login agency-login --dry-run
239
239
  ```
240
240
 
241
241
  ### V4 Live Shared Account
@@ -96,6 +96,7 @@ scripts/check_all_docs_urls.py
96
96
  scripts/check_reports_drift.py
97
97
  scripts/check_wsdl_drift.py
98
98
  scripts/patch_vendor_imports.py
99
+ scripts/preflight_check.sh
99
100
  scripts/refresh_reports_cache.py
100
101
  scripts/refresh_wsdl_cache.py
101
102
  scripts/release_pypi.sh
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "direct-cli"
7
- version = "0.3.14"
7
+ version = "0.3.15"
8
8
  description = "Command-line interface for Yandex Direct API"
9
9
  readme = "README.md"
10
10
  license = {text = "MIT"}
@@ -0,0 +1,62 @@
1
+ #!/usr/bin/env bash
2
+ #
3
+ # Pre-release preflight check — runs the network-dependent docs / cache
4
+ # health checks that used to be wired into release_pypi.sh.
5
+ #
6
+ # Run this manually before bumping the version. It is *not* wired into
7
+ # release_pypi.sh on purpose: Yandex frequently rate-limits the docs host
8
+ # with a SmartCaptcha gateway, which is an external rate-limit on our IP,
9
+ # not evidence that an URL is gone. Mixing this into the release path made
10
+ # releases non-deterministic.
11
+ #
12
+ # What this script does:
13
+ # 1. scripts/check_all_docs_urls.py
14
+ # Hard-fails on canonical move (3xx → different path) or 404.
15
+ # Soft-warns on 5xx or persistent captcha (likely rate-limit).
16
+ # 2. pytest TestReportsCoverage TestWsdlCacheFreshness
17
+ # Read-only: confirms committed cache files are real content, not
18
+ # captcha gateways.
19
+ # 3. git diff --quiet -- tests/reports_cache tests/wsdl_cache
20
+ # Refuses to proceed with uncommitted cache changes; the maintainer
21
+ # must commit cache refreshes deliberately.
22
+ #
23
+ # Exit status: 0 if everything passes (warnings allowed), non-zero on any
24
+ # hard failure.
25
+
26
+ set -euo pipefail
27
+
28
+ ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
29
+
30
+ require_command() {
31
+ local name="$1"
32
+ if ! command -v "${name}" >/dev/null 2>&1; then
33
+ echo "Required command not found: ${name}" >&2
34
+ exit 1
35
+ fi
36
+ }
37
+
38
+ require_command python3
39
+ require_command git
40
+
41
+ cd "${ROOT_DIR}"
42
+
43
+ echo "[1/3] Checking docs URLs..."
44
+ python3 scripts/check_all_docs_urls.py
45
+
46
+ echo
47
+ echo "[2/3] Verifying committed docs/WSDL cache is real content..."
48
+ python3 -m pytest tests/test_api_coverage.py::TestReportsCoverage \
49
+ tests/test_api_coverage.py::TestWsdlCacheFreshness -v
50
+
51
+ echo
52
+ echo "[3/3] Checking that docs/WSDL cache has no uncommitted changes..."
53
+ if ! git diff --quiet HEAD -- tests/reports_cache tests/wsdl_cache; then
54
+ echo "ERROR: tests/reports_cache or tests/wsdl_cache has uncommitted changes."
55
+ echo " Run scripts/refresh_reports_cache.py separately, review the diff,"
56
+ echo " and commit it before releasing."
57
+ git diff --stat -- tests/reports_cache tests/wsdl_cache
58
+ exit 1
59
+ fi
60
+
61
+ echo
62
+ echo "Preflight passed. Safe to bump version and run scripts/release_pypi.sh."
@@ -21,7 +21,7 @@ Local credential mutations:
21
21
  - direct auth use ...
22
22
 
23
23
  V4 Live finance money mutations (0.3.3 exposes dry-run-only previews):
24
- - direct v4finance transfer-money --from-campaign-id ... --to-campaign-id ... --amount ... --currency ... --dry-run
24
+ - direct v4finance transfer-money --from-campaign-id ... --to-campaign-id ... --amount ... --dry-run
25
25
  - direct v4finance pay-campaigns --campaign-ids ... --amount ... --contract-id ... --pay-method ... --dry-run
26
26
 
27
27
  Production commands that are only allowed in automated smoke tests with --sandbox:
@@ -59,11 +59,12 @@ The public v4/Live4 finance docs found during milestone 0.3.3 list
59
59
  No official `CheckPayment` page or `PaymentID` contract was found.
60
60
  Financial methods use an additional `finance_token`, computed from the
61
61
  master token, operation number, method name, and normalized login. Public
62
- dry-run examples mask the computed token. The docs-backed `PayCampaigns` and
63
- `TransferMoney` contracts require `Currency` on each payment/transfer item.
64
- `CreateInvoice` is exposed as `v4finance create-invoice` with repeated
65
- `--payment CAMPAIGN_ID=AMOUNT` flags and sends docs-backed
66
- `Payments[].CampaignID/Sum/Currency`; its live write test is opt-in via
62
+ dry-run examples mask the computed token. The docs-backed `PayCampaigns`,
63
+ `TransferMoney`, and `CreateInvoice` `PayCampElement` carries only
64
+ `CampaignID` and `Sum` (no `Currency`); `PayCampaigns.PayMethod` is
65
+ `'Bank'` only. `CreateInvoice` is exposed as `v4finance create-invoice`
66
+ with repeated `--payment CAMPAIGN_ID=AMOUNT` flags and sends docs-backed
67
+ `Payments[].CampaignID/Sum`; its live write test is opt-in via
67
68
  `YANDEX_DIRECT_LIVE_FINANCE_WRITE=1`.
68
69
 
69
70
  Sandbox v4 Live probes on 2026-04-30 confirmed the runtime request shape for
@@ -198,8 +198,8 @@ def test_v4finance_money_contracts_are_docs_backed_dangerous_objects():
198
198
  assert build_v4_body("TransferMoney", transfer.example_param) == {
199
199
  "method": "TransferMoney",
200
200
  "param": {
201
- "FromCampaigns": [{"CampaignID": 123, "Sum": 100.5, "Currency": "RUB"}],
202
- "ToCampaigns": [{"CampaignID": 456, "Sum": 100.5, "Currency": "RUB"}],
201
+ "FromCampaigns": [{"CampaignID": 123, "Sum": 100.5}],
202
+ "ToCampaigns": [{"CampaignID": 456, "Sum": 100.5}],
203
203
  },
204
204
  }
205
205
 
@@ -209,7 +209,7 @@ def test_v4finance_money_contracts_are_docs_backed_dangerous_objects():
209
209
  assert build_v4_body("PayCampaigns", pay.example_param) == {
210
210
  "method": "PayCampaigns",
211
211
  "param": {
212
- "Payments": [{"CampaignID": 123, "Sum": 100.5, "Currency": "RUB"}],
212
+ "Payments": [{"CampaignID": 123, "Sum": 100.5}],
213
213
  "ContractID": "contract-id",
214
214
  "PayMethod": "Bank",
215
215
  },
@@ -223,7 +223,7 @@ def test_v4finance_money_contracts_are_docs_backed_dangerous_objects():
223
223
  assert build_v4_body("CreateInvoice", create_invoice.example_param) == {
224
224
  "method": "CreateInvoice",
225
225
  "param": {
226
- "Payments": [{"CampaignID": 123, "Sum": 100.5, "Currency": "RUB"}],
226
+ "Payments": [{"CampaignID": 123, "Sum": 100.5}],
227
227
  },
228
228
  }
229
229
 
@@ -89,8 +89,8 @@ def test_transfer_money_dry_run_uses_campaign_arrays_and_masks_finance_token():
89
89
  assert json.loads(result.output) == {
90
90
  "method": "TransferMoney",
91
91
  "param": {
92
- "FromCampaigns": [{"CampaignID": 123, "Sum": 100.5, "Currency": "RUB"}],
93
- "ToCampaigns": [{"CampaignID": 456, "Sum": 100.5, "Currency": "RUB"}],
92
+ "FromCampaigns": [{"CampaignID": 123, "Sum": 100.5}],
93
+ "ToCampaigns": [{"CampaignID": 456, "Sum": 100.5}],
94
94
  },
95
95
  "finance_token": "<redacted>",
96
96
  "operation_num": 42,
@@ -122,8 +122,8 @@ def test_pay_campaigns_dry_run_uses_payment_object_and_masks_finance_token():
122
122
  "method": "PayCampaigns",
123
123
  "param": {
124
124
  "Payments": [
125
- {"CampaignID": 123, "Sum": 100.5, "Currency": "RUB"},
126
- {"CampaignID": 456, "Sum": 100.5, "Currency": "RUB"},
125
+ {"CampaignID": 123, "Sum": 100.5},
126
+ {"CampaignID": 456, "Sum": 100.5},
127
127
  ],
128
128
  "ContractID": "contract-id",
129
129
  "PayMethod": "Bank",
@@ -152,7 +152,7 @@ def test_create_invoice_dry_run_uses_payment_object_and_masks_finance_token():
152
152
  "method": "CreateInvoice",
153
153
  "param": {
154
154
  "Payments": [
155
- {"CampaignID": 123, "Sum": 100.5, "Currency": "RUB"},
155
+ {"CampaignID": 123, "Sum": 100.5},
156
156
  ],
157
157
  },
158
158
  "finance_token": "<redacted>",
@@ -160,7 +160,7 @@ def test_create_invoice_dry_run_uses_payment_object_and_masks_finance_token():
160
160
  }
161
161
 
162
162
 
163
- def test_create_invoice_dry_run_accepts_multiple_payments_and_currency():
163
+ def test_create_invoice_dry_run_accepts_multiple_payments():
164
164
  result = _invoke(
165
165
  "v4finance",
166
166
  "create-invoice",
@@ -168,8 +168,6 @@ def test_create_invoice_dry_run_accepts_multiple_payments_and_currency():
168
168
  "123=100.50",
169
169
  "--payment",
170
170
  "456=1",
171
- "--currency",
172
- "usd",
173
171
  "--finance-token",
174
172
  "secret-finance-token",
175
173
  "--operation-num",
@@ -180,8 +178,8 @@ def test_create_invoice_dry_run_accepts_multiple_payments_and_currency():
180
178
  assert result.exit_code == 0
181
179
  assert json.loads(result.output)["param"] == {
182
180
  "Payments": [
183
- {"CampaignID": 123, "Sum": 100.5, "Currency": "USD"},
184
- {"CampaignID": 456, "Sum": 1.0, "Currency": "USD"},
181
+ {"CampaignID": 123, "Sum": 100.5},
182
+ {"CampaignID": 456, "Sum": 1.0},
185
183
  ],
186
184
  }
187
185
 
@@ -485,8 +483,10 @@ def test_pay_campaigns_rejects_non_positive_campaign_ids():
485
483
  "0,-1",
486
484
  "--amount",
487
485
  "100.50",
486
+ "--contract-id",
487
+ "contract-id",
488
488
  "--pay-method",
489
- "Overdraft",
489
+ "Bank",
490
490
  "--finance-token",
491
491
  "finance-token",
492
492
  "--operation-num",
@@ -498,7 +498,7 @@ def test_pay_campaigns_rejects_non_positive_campaign_ids():
498
498
  assert "--campaign-ids must contain only positive integers" in result.output
499
499
 
500
500
 
501
- def test_pay_campaigns_allows_overdraft_without_contract():
501
+ def test_pay_campaigns_rejects_undocumented_pay_method():
502
502
  result = _invoke(
503
503
  "v4finance",
504
504
  "pay-campaigns",
@@ -508,8 +508,6 @@ def test_pay_campaigns_allows_overdraft_without_contract():
508
508
  "100.50",
509
509
  "--pay-method",
510
510
  "Overdraft",
511
- "--currency",
512
- "usd",
513
511
  "--finance-token",
514
512
  "finance-token",
515
513
  "--operation-num",
@@ -517,11 +515,8 @@ def test_pay_campaigns_allows_overdraft_without_contract():
517
515
  "--dry-run",
518
516
  )
519
517
 
520
- assert result.exit_code == 0
521
- assert json.loads(result.output)["param"] == {
522
- "Payments": [{"CampaignID": 123, "Sum": 100.5, "Currency": "USD"}],
523
- "PayMethod": "Overdraft",
524
- }
518
+ assert result.exit_code != 0
519
+ assert "Invalid value for '--pay-method'" in result.output
525
520
 
526
521
 
527
522
  def test_check_payment_dry_run_uses_custom_transaction_id_object():
@@ -636,7 +631,7 @@ def test_create_invoice_formats_mocked_response_as_json():
636
631
  "CreateInvoice",
637
632
  {
638
633
  "Payments": [
639
- {"CampaignID": 123, "Sum": 100.5, "Currency": "RUB"},
634
+ {"CampaignID": 123, "Sum": 100.5},
640
635
  ],
641
636
  },
642
637
  )
File without changes
File without changes
File without changes
File without changes
File without changes