diff --git a/CHANGELOG.md b/CHANGELOG.md index ab9cb43..734813c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,8 @@ This project follows [Semantic Versioning](https://semver.org/). ### Added +- **Vehicle company counts** (Tango API 5.8.0). `Vehicle` gains `holder_count` (distinct companies holding one of the vehicle's IDVs) and `order_winner_count` (distinct companies that have won a task order under it), and both join the `VEHICLES_MINIMAL` and `VEHICLES_COMPREHENSIVE` defaults next to `awardee_count`, so `listVehicles()` and `getVehicle()` return them without a custom `shape`. Neither is orderable or filterable. + - **Boards-of-contract-appeals decisions** (Tango API 4.26.0). `listContractAppeals(options)` and `getContractAppeal(uuid, options)` over `/api/contract_appeals/`, with every filter the API accepts declared as a typed option on `ListContractAppealsOptions` (`search`, `board`, `docket`, `appellant`, `judge`, `decision_type`, the `decision_date_after` / `_before` pair, `listed`, `document_id`, `ordering`), the new `ContractAppealRecord` return type, and a registered `ContractAppeal` shape schema so the typed shape API resolves the resource's fields. These are Contract Disputes Act decisions from the CBCA (civilian) and the ASBCA (defense) — a dispute under an existing contract, not a challenge to an award. Bid protests remain the separate `listProtests()` resource, and the two do not overlap. @@ -28,10 +30,15 @@ This project follows [Semantic Versioning](https://semver.org/). ### Changed +- Re-vendored the contract for Tango API 5.8.0 and regenerated the overlay, which picks up the fields the API added since 5.1.0. Federal Register documents are in the contract without an SDK method yet, so the resource is baselined as a tracked gap in both conformance gates. - Re-vendored `contracts/filter_shape_contract.json` (schema_version 2, 48 resources) and regenerated `src/shapes/generatedOverlay.ts` from it — 359 fields across 25 containers, 73 nested schemas. - Re-vendored the contract for Tango API 5.1.0 and regenerated the overlay, which now merges a model's expand when two resources embed it instead of letting the narrower copy win. eBuy requests are in the contract without an SDK method yet, so it is baselined as a tracked gap. - Baselined 14 reverse-shape-coverage gaps in `contracts/shape_coverage_baseline.json`, matching tango-python. All 14 are the nested sub-resource routes above, which reuse the parent resource's model rather than carrying one of their own; none is SLED, and none is a regression — they became visible only with the re-vendored contract. +### Deprecated + +- `Vehicle.awardee_count` is deprecated in favor of `order_winner_count`, which carries the same value. The API keeps serving it as an alias until its next major version. + ### Fixed - **`attachments(name,doc_role,doc_role_alt)` no longer throws `ShapeValidationError`** on `getOpportunity`, `listOpportunities`, `getNotice` and `listNotices`; the API serves both fields on the Pro plan and above when they are named. New `OpportunityAttachment` and `AttachmentDocRole` types cover the six roles and are used on `Opportunity` and `Notice`. diff --git a/contracts/conformance_baseline.json b/contracts/conformance_baseline.json index a63dbeb..6a0c05b 100644 --- a/contracts/conformance_baseline.json +++ b/contracts/conformance_baseline.json @@ -4,6 +4,7 @@ "unimplemented_resources": [ "ebuy/requests", "events", + "federal_register", "news" ] } diff --git a/contracts/filter_shape_contract.json b/contracts/filter_shape_contract.json index 0e47b14..28e7e52 100644 --- a/contracts/filter_shape_contract.json +++ b/contracts/filter_shape_contract.json @@ -1,6 +1,6 @@ { "meta": { - "api_version": "5.1.0", + "api_version": "5.8.0", "description": "Canonical API filter/shape contract. Downstream consumers (SDK, MCP) should validate their conformance against this manifest.", "generated_from": "scripts/filter_shape_conformance.py", "schema_version": 2 @@ -1628,6 +1628,8 @@ "resource_key": "budget/accounts", "runtime": { "filter_params": [ + "account_category", + "account_category__in", "account_title__icontains", "actual_vs_requested_contract", "actual_vs_requested_contract__gte", @@ -1635,6 +1637,7 @@ "actual_vs_requested_contract_capped", "actual_vs_requested_contract_capped__gte", "actual_vs_requested_contract_capped__lte", + "agency", "agency_code", "agency_code__in", "apportioned", @@ -1669,6 +1672,10 @@ "contract_share_of_obligated_capped", "contract_share_of_obligated_capped__gte", "contract_share_of_obligated_capped__lte", + "data_through_period", + "data_through_period__gte", + "data_through_period__isnull", + "data_through_period__lte", "enacted_ba", "enacted_ba_5yr_cagr", "enacted_ba_5yr_cagr__gte", @@ -1726,6 +1733,15 @@ "unobligated_pct__lte" ], "filter_params_detail": { + "account_category": { + "filter_class": "CharFilter", + "type": "string" + }, + "account_category__in": { + "filter_class": "CharInFilter", + "lookup": "in", + "type": "string" + }, "account_title__icontains": { "filter_class": "CharFilter", "lookup": "icontains", @@ -1759,6 +1775,10 @@ "lookup": "lte", "type": "number" }, + "agency": { + "filter_class": "OrganizationScopeAgencyFilter", + "type": "string" + }, "agency_code": { "filter_class": "CharFilter", "type": "string" @@ -1917,6 +1937,25 @@ "lookup": "lte", "type": "number" }, + "data_through_period": { + "filter_class": "NumberFilter", + "type": "number" + }, + "data_through_period__gte": { + "filter_class": "NumberFilter", + "lookup": "gte", + "type": "number" + }, + "data_through_period__isnull": { + "filter_class": "BooleanFilter", + "lookup": "isnull", + "type": "boolean" + }, + "data_through_period__lte": { + "filter_class": "NumberFilter", + "lookup": "lte", + "type": "number" + }, "enacted_ba": { "filter_class": "NumberFilter", "type": "number" @@ -2240,9 +2279,22 @@ "subaccount_code", "subfunction_code" ] + }, + "organization": { + "expands": {}, + "fields": [ + "agency_code", + "agency_name", + "department_code", + "department_name", + "office_code", + "office_name", + "organization_id" + ] } }, "fields": [ + "account_category", "account_narrative_excerpt", "account_title", "actual_vs_requested_contract", @@ -2275,6 +2327,7 @@ "contract_share_of_obligated", "contract_share_of_obligated_capped", "created", + "data_through_period", "enacted_ba", "enacted_ba_5yr_cagr", "enacted_ba_yoy_pct", @@ -2299,6 +2352,7 @@ "obligated_total", "obligated_yoy_pct", "on_off_budget", + "organization_id", "outlayed_to_obligated_pct", "outlayed_to_obligated_pct_capped", "outlayed_to_obligated_pct_capped_flag", @@ -2306,6 +2360,7 @@ "requested_ba", "requested_contractual_services", "requested_personnel_share", + "source_anomalies", "subfunction_code", "top_contract_recipients", "top_grant_recipients", @@ -2315,6 +2370,7 @@ ] }, "shape_flat_paths": [ + "account_category", "account_narrative_excerpt", "account_title", "actual_vs_requested_contract", @@ -2360,6 +2416,7 @@ "contract_share_of_obligated", "contract_share_of_obligated_capped", "created", + "data_through_period", "enacted_ba", "enacted_ba_5yr_cagr", "enacted_ba_yoy_pct", @@ -2407,6 +2464,15 @@ "obligated_total", "obligated_yoy_pct", "on_off_budget", + "organization", + "organization.agency_code", + "organization.agency_name", + "organization.department_code", + "organization.department_name", + "organization.office_code", + "organization.office_name", + "organization.organization_id", + "organization_id", "outlayed_to_obligated_pct", "outlayed_to_obligated_pct_capped", "outlayed_to_obligated_pct_capped_flag", @@ -2414,6 +2480,7 @@ "requested_ba", "requested_contractual_services", "requested_personnel_share", + "source_anomalies", "subfunction_code", "top_contract_recipients", "top_grant_recipients", @@ -4174,6 +4241,7 @@ "resource_key": "ebuy/requests", "runtime": { "filter_params": [ + "agency", "buyer_agency", "close_date_after", "close_date_before", @@ -4189,6 +4257,10 @@ "status" ], "filter_params_detail": { + "agency": { + "filter_class": "OrganizationScopeAgencyFilter", + "type": "string" + }, "buyer_agency": { "filter_class": "BaseSmartFilter", "type": "string" @@ -4234,7 +4306,7 @@ "type": "string" }, "search": { - "filter_class": "BaseSmartFilter", + "filter_class": "EbuyRequestSearchFilter", "type": "string" }, "sin": { @@ -7363,6 +7435,7 @@ "activate_date_after", "activate_date_before", "active", + "agency", "cage_code", "classification_type", "delisted", @@ -7394,6 +7467,10 @@ "filter_class": "BooleanFilter", "type": "boolean" }, + "agency": { + "filter_class": "OrganizationScopeAgencyFilter", + "type": "string" + }, "cage_code": { "filter_class": "BaseSmartFilter", "type": "string" @@ -7474,7 +7551,20 @@ "max_page_size": 100 }, "shape": { - "expands": {}, + "expands": { + "organization": { + "expands": {}, + "fields": [ + "agency_code", + "agency_name", + "department_code", + "department_name", + "office_code", + "office_name", + "organization_id" + ] + } + }, "fields": [ "activate_date", "additional_comments", @@ -7500,6 +7590,7 @@ "middle_name", "more_locations", "npi", + "organization_id", "prefix", "primary_address", "references", @@ -7542,6 +7633,15 @@ "middle_name", "more_locations", "npi", + "organization", + "organization.agency_code", + "organization.agency_name", + "organization.department_code", + "organization.department_name", + "organization.office_code", + "organization.office_name", + "organization.organization_id", + "organization_id", "prefix", "primary_address", "references", @@ -7575,6 +7675,230 @@ "show_shapes" ] }, + "federal_register": { + "basename": "federalregisterdocument", + "docs_file": null, + "docs_params": [], + "prefix": "federal_register", + "resource_key": "federal_register", + "runtime": { + "filter_params": [ + "agency", + "cfr_part", + "cfr_title", + "comments_close_on_after", + "comments_close_on_before", + "comments_open", + "document_number", + "effective_on_after", + "effective_on_before", + "executive_order_number", + "fr_agency", + "publication_date_after", + "publication_date_before", + "rin", + "search", + "significant", + "type" + ], + "filter_params_detail": { + "agency": { + "filter_class": "FederalRegisterAgencyFilter", + "type": "string" + }, + "cfr_part": { + "filter_class": "CharFilter", + "type": "string" + }, + "cfr_title": { + "filter_class": "CharFilter", + "type": "string" + }, + "comments_close_on_after": { + "filter_class": "DateFilter", + "lookup": "gte", + "type": "date" + }, + "comments_close_on_before": { + "filter_class": "DateFilter", + "lookup": "lte", + "type": "date" + }, + "comments_open": { + "filter_class": "BooleanFilter", + "type": "boolean" + }, + "document_number": { + "filter_class": "IdListFilter", + "type": "string" + }, + "effective_on_after": { + "filter_class": "DateFilter", + "lookup": "gte", + "type": "date" + }, + "effective_on_before": { + "filter_class": "DateFilter", + "lookup": "lte", + "type": "date" + }, + "executive_order_number": { + "filter_class": "CharFilter", + "type": "string" + }, + "fr_agency": { + "filter_class": "JsonbContainsFilter", + "type": "string" + }, + "publication_date_after": { + "filter_class": "DateFilter", + "lookup": "gte", + "type": "date" + }, + "publication_date_before": { + "filter_class": "DateFilter", + "lookup": "lte", + "type": "date" + }, + "rin": { + "filter_class": "JsonbContainsFilter", + "type": "string" + }, + "search": { + "filter_class": "FederalRegisterSearchFilter", + "type": "string" + }, + "significant": { + "filter_class": "BooleanFilter", + "type": "boolean" + }, + "type": { + "filter_class": "DocumentTypeFilter", + "type": "string" + } + }, + "ordering_aliases": [], + "ordering_fields": [ + "comments_close_on", + "document_number", + "effective_on", + "publication_date", + "rank" + ], + "pagination": { + "class": "CachedPageNumberPagination", + "max_page_size": 100 + }, + "shape": { + "expands": {}, + "fields": [ + "abstract", + "action", + "agencies", + "body_html_url", + "cfr_references", + "citation", + "comment_url", + "comments_close_on", + "correction_of", + "corrections", + "dates", + "disposition_notes", + "docket_ids", + "dockets", + "document_number", + "effective_on", + "end_page", + "executive_order_notes", + "executive_order_number", + "html_url", + "not_received_for_publication", + "page_length", + "pdf_url", + "presidential_document_number", + "proclamation_number", + "public_inspection_pdf_url", + "publication_date", + "raw_text_url", + "regulation_id_number_info", + "regulation_id_numbers", + "regulations_dot_gov_info", + "regulations_dot_gov_url", + "significant", + "signing_date", + "start_page", + "subtype", + "title", + "toc_doc", + "toc_subject", + "topics", + "type", + "uuid", + "volume" + ] + }, + "shape_flat_paths": [ + "abstract", + "action", + "agencies", + "body_html_url", + "cfr_references", + "citation", + "comment_url", + "comments_close_on", + "correction_of", + "corrections", + "dates", + "disposition_notes", + "docket_ids", + "dockets", + "document_number", + "effective_on", + "end_page", + "executive_order_notes", + "executive_order_number", + "html_url", + "not_received_for_publication", + "page_length", + "pdf_url", + "presidential_document_number", + "proclamation_number", + "public_inspection_pdf_url", + "publication_date", + "raw_text_url", + "regulation_id_number_info", + "regulation_id_numbers", + "regulations_dot_gov_info", + "regulations_dot_gov_url", + "significant", + "signing_date", + "start_page", + "subtype", + "title", + "toc_doc", + "toc_subject", + "topics", + "type", + "uuid", + "volume" + ], + "shape_gated_by_level": {}, + "shape_supported": true, + "shape_tier_required": null, + "viewset": "federal_register.views.FederalRegisterDocumentViewSet" + }, + "swagger_has_key": true, + "swagger_params": [ + "flat", + "flat_lists", + "joiner", + "limit", + "ordering", + "page", + "shape", + "show_shapes" + ] + }, "forecasts": { "basename": "forecast", "docs_file": null, @@ -10472,6 +10796,7 @@ "resource_key": "itdashboard", "runtime": { "filter_params": [ + "agency", "agency_code", "agency_name", "cio_rating", @@ -10484,6 +10809,10 @@ "updated_time_before" ], "filter_params_detail": { + "agency": { + "filter_class": "OrganizationScopeAgencyFilter", + "type": "string" + }, "agency_code": { "filter_class": "NumberFilter", "type": "number" @@ -11169,7 +11498,11 @@ "archive", "attachment_count", "attachments", + "award_amount", + "award_date", "award_number", + "awardee", + "awardee_uei", "description", "last_updated", "meta", @@ -11211,7 +11544,11 @@ "attachments.resource_id", "attachments.type", "attachments.url", + "award_amount", + "award_date", "award_number", + "awardee", + "awardee_uei", "description", "last_updated", "meta", @@ -11401,6 +11738,8 @@ "filter_params": [ "active", "agency", + "awarded", + "awardee_uei", "first_notice_date_after", "first_notice_date_before", "last_notice_date_after", @@ -11425,6 +11764,14 @@ "filter_class": "PerformantAgencyFilter", "type": "string" }, + "awarded": { + "filter_class": "BooleanFilter", + "type": "boolean" + }, + "awardee_uei": { + "filter_class": "AwardeeUeiFilter", + "type": "string" + }, "first_notice_date_after": { "filter_class": "DateFromToRangeFilter", "lookup": "gte", @@ -11526,6 +11873,18 @@ "url" ] }, + "awards": { + "expands": {}, + "fields": [ + "award_amount", + "award_date", + "award_number", + "awardee", + "awardee_uei", + "notice_id", + "opportunity_id" + ] + }, "department": { "expands": {}, "fields": [ @@ -11632,7 +11991,13 @@ "agency_id", "archive_date", "attachments", + "award_amount", + "award_count", + "award_date", "award_number", + "awarded", + "awardee", + "awardee_uei", "department", "department_id", "description", @@ -11654,6 +12019,7 @@ "set_aside", "snippet", "solicitation_number", + "solicitation_opportunity_id", "title" ] }, @@ -11677,7 +12043,21 @@ "attachments.resource_id", "attachments.type", "attachments.url", + "award_amount", + "award_count", + "award_date", "award_number", + "awarded", + "awardee", + "awardee_uei", + "awards", + "awards.award_amount", + "awards.award_date", + "awards.award_number", + "awards.awardee", + "awards.awardee_uei", + "awards.notice_id", + "awards.opportunity_id", "department", "department.abbreviation", "department.cgac", @@ -11748,6 +12128,7 @@ "set_aside.description", "snippet", "solicitation_number", + "solicitation_opportunity_id", "title" ], "shape_gated_by_level": { @@ -11765,6 +12146,8 @@ "swagger_params": [ "active", "agency", + "awarded", + "awardee_uei", "first_notice_date_after", "first_notice_date_before", "flat", @@ -13598,6 +13981,18 @@ "s3_key" ] }, + "organization": { + "expands": {}, + "fields": [ + "agency_code", + "agency_name", + "department_code", + "department_name", + "office_code", + "office_name", + "organization_id" + ] + }, "topics": { "expands": {}, "fields": [ @@ -13642,6 +14037,14 @@ "documents.n_pages", "documents.s3_key", "end_date", + "organization", + "organization.agency_code", + "organization.agency_name", + "organization.department_code", + "organization.department_name", + "organization.office_code", + "organization.office_name", + "organization.organization_id", "out_of_cycle", "program", "sol_download_url", @@ -13681,6 +14084,7 @@ "agency", "close_date_after", "close_date_before", + "cycle_name", "doc_source", "open_date_after", "open_date_before", @@ -13703,8 +14107,7 @@ "type": "choice" }, "agency": { - "filter_class": "CharFilter", - "lookup": "icontains", + "filter_class": "OrganizationScopeAgencyFilter", "type": "string" }, "close_date_after": { @@ -13717,6 +14120,10 @@ "lookup": "lte", "type": "date" }, + "cycle_name": { + "filter_class": "CharFilter", + "type": "string" + }, "doc_source": { "filter_class": "CharFilter", "lookup": "iexact", @@ -13794,6 +14201,18 @@ "title" ] }, + "organization": { + "expands": {}, + "fields": [ + "agency_code", + "agency_name", + "department_code", + "department_name", + "office_code", + "office_name", + "organization_id" + ] + }, "solicitation": { "expands": {}, "fields": [ @@ -13814,6 +14233,7 @@ "activity", "agency", "close_date", + "cycle_name", "description", "doc_source", "due_dates_text", @@ -13836,6 +14256,7 @@ "activity", "agency", "close_date", + "cycle_name", "description", "doc_source", "due_dates_text", @@ -13852,6 +14273,14 @@ "opportunity.response_deadline", "opportunity.solicitation_number", "opportunity.title", + "organization", + "organization.agency_code", + "organization.agency_name", + "organization.department_code", + "organization.department_name", + "organization.office_code", + "organization.office_name", + "organization.organization_id", "release_date", "solicitation", "solicitation.cycle_name", @@ -15485,6 +15914,18 @@ "url" ] }, + "awards": { + "expands": {}, + "fields": [ + "award_amount", + "award_date", + "award_number", + "awardee", + "awardee_uei", + "notice_id", + "opportunity_id" + ] + }, "department": { "expands": {}, "fields": [ @@ -15591,7 +16032,13 @@ "agency_id", "archive_date", "attachments", + "award_amount", + "award_count", + "award_date", "award_number", + "awarded", + "awardee", + "awardee_uei", "department", "department_id", "description", @@ -15613,6 +16060,7 @@ "set_aside", "snippet", "solicitation_number", + "solicitation_opportunity_id", "title" ] }, @@ -15638,6 +16086,7 @@ "description", "descriptions", "fiscal_year", + "holder_count", "idv_count", "is_synthetic_solicitation", "last_date_to_order", @@ -15646,6 +16095,7 @@ "name", "opportunity_id", "order_count", + "order_winner_count", "organization", "organization_id", "program_acronym", @@ -16051,6 +16501,7 @@ "description", "descriptions", "fiscal_year", + "holder_count", "idv_count", "is_synthetic_solicitation", "last_date_to_order", @@ -16088,7 +16539,21 @@ "opportunity.attachments.resource_id", "opportunity.attachments.type", "opportunity.attachments.url", + "opportunity.award_amount", + "opportunity.award_count", + "opportunity.award_date", "opportunity.award_number", + "opportunity.awarded", + "opportunity.awardee", + "opportunity.awardee_uei", + "opportunity.awards", + "opportunity.awards.award_amount", + "opportunity.awards.award_date", + "opportunity.awards.award_number", + "opportunity.awards.awardee", + "opportunity.awards.awardee_uei", + "opportunity.awards.notice_id", + "opportunity.awards.opportunity_id", "opportunity.department", "opportunity.department.abbreviation", "opportunity.department.cgac", @@ -16159,9 +16624,11 @@ "opportunity.set_aside.description", "opportunity.snippet", "opportunity.solicitation_number", + "opportunity.solicitation_opportunity_id", "opportunity.title", "opportunity_id", "order_count", + "order_winner_count", "organization", "organization.agency_code", "organization.agency_name", @@ -16993,6 +17460,7 @@ "entities_subawards", "events", "exclusions", + "federal_register", "forecasts", "grants", "gsa_elibrary_contracts", diff --git a/contracts/shape_coverage_baseline.json b/contracts/shape_coverage_baseline.json index 0d20bc4..3f45d57 100644 --- a/contracts/shape_coverage_baseline.json +++ b/contracts/shape_coverage_baseline.json @@ -1,6 +1,6 @@ { "description": "Known reverse shape-coverage gaps (Tango exposes, SDK schema lacks), accepted as a tracked backlog. check-shape-coverage.ts fails only on gaps NOT listed here. Burn down and regenerate with --update-baseline.", - "count": 15, + "count": 16, "known_gaps": [ "unmapped_resource|agencies_contracts_awarding|(root)|(no model mapped)", "unmapped_resource|agencies_contracts_funding|(root)|(no model mapped)", @@ -12,6 +12,7 @@ "unmapped_resource|entities_otas|(root)|(no model mapped)", "unmapped_resource|entities_otidvs|(root)|(no model mapped)", "unmapped_resource|entities_subawards|(root)|(no model mapped)", + "unmapped_resource|federal_register|(root)|(no model mapped)", "unmapped_resource|idvs_awards|(root)|(no model mapped)", "unmapped_resource|idvs_idvs|(root)|(no model mapped)", "unmapped_resource|idvs_lcats|(root)|(no model mapped)", diff --git a/docs/API_REFERENCE.md b/docs/API_REFERENCE.md index ddbb4e7..150262e 100644 --- a/docs/API_REFERENCE.md +++ b/docs/API_REFERENCE.md @@ -130,6 +130,12 @@ Supported parameters: - `page`, `limit` (max 100) - `shape`, `flat`, `flatLists` +Company counts (on both the list and detail defaults; neither is orderable or filterable): + +- `holder_count`: distinct companies holding one of the vehicle's IDVs. +- `order_winner_count`: distinct companies that have won a task order under the vehicle. +- `awardee_count`: deprecated alias of `order_winner_count` (same value), removed at the API's next major version. + ### `getVehicle(uuid, options?)` ```ts diff --git a/scripts/check-filter-shape-conformance.ts b/scripts/check-filter-shape-conformance.ts index b5bf2a5..45740ea 100644 --- a/scripts/check-filter-shape-conformance.ts +++ b/scripts/check-filter-shape-conformance.ts @@ -71,6 +71,8 @@ export const RESOURCE_TO_METHOD: Record = { contract_appeals: "listContractAppeals", // eBuy requests are published by the API but not yet ported — baselined as a tracked gap. "ebuy/requests": null, + // Federal Register documents are published by the API but not yet ported — baselined as a tracked gap. + federal_register: null, psc: "listPsc", mas_sins: "listMasSins", departments: "listDepartments", diff --git a/src/config.ts b/src/config.ts index 04936e6..21bae70 100644 --- a/src/config.ts +++ b/src/config.ts @@ -45,7 +45,7 @@ export const ShapeConfig = { VEHICLES_MINIMAL: "uuid,solicitation_identifier,is_synthetic_solicitation,program_acronym," + "organization_id,organization,vehicle_type,description," + - "idv_count,awardee_count,order_count,total_obligated," + + "idv_count,awardee_count,holder_count,order_winner_count,order_count,total_obligated," + "vehicle_obligations,vehicle_contracts_value,latest_award_date," + "solicitation_title,solicitation_date", @@ -56,7 +56,7 @@ export const ShapeConfig = { "solicitation_title,solicitation_description,solicitation_date,opportunity_id," + "naics_code,psc_code,set_aside," + "fiscal_year,award_date,latest_award_date,last_date_to_order," + - "description,idv_count,awardee_count,order_count,total_obligated," + + "description,idv_count,awardee_count,holder_count,order_winner_count,order_count,total_obligated," + "vehicle_obligations,vehicle_contracts_value," + "type_of_idc,contract_type,metrics(*)", diff --git a/src/models/Vehicle.ts b/src/models/Vehicle.ts index b5f217a..e456fc1 100644 --- a/src/models/Vehicle.ts +++ b/src/models/Vehicle.ts @@ -24,7 +24,12 @@ export interface Vehicle { award_date?: string | null; last_date_to_order?: string | null; + /** @deprecated Same value as `order_winner_count`; the API removes this alias at its next major version. */ awardee_count?: number | null; + /** Number of distinct companies holding one of the vehicle's IDVs. */ + holder_count?: number | null; + /** Number of distinct companies that have won a task order under the vehicle. */ + order_winner_count?: number | null; order_count?: number | null; vehicle_obligations?: string | null; vehicle_contracts_value?: string | null; diff --git a/src/shapes/explicitSchemas.ts b/src/shapes/explicitSchemas.ts index bb7b71d..dd5b65d 100644 --- a/src/shapes/explicitSchemas.ts +++ b/src/shapes/explicitSchemas.ts @@ -2520,6 +2520,20 @@ export const VEHICLE_SCHEMA: FieldSchemaMap = { isList: false, nestedModel: null, }, + holder_count: { + name: "holder_count", + type: "int", + isOptional: true, + isList: false, + nestedModel: null, + }, + order_winner_count: { + name: "order_winner_count", + type: "int", + isOptional: true, + isList: false, + nestedModel: null, + }, order_count: { name: "order_count", type: "int", diff --git a/src/shapes/generatedOverlay.ts b/src/shapes/generatedOverlay.ts index 0f90a9c..4343ace 100644 --- a/src/shapes/generatedOverlay.ts +++ b/src/shapes/generatedOverlay.ts @@ -144,6 +144,15 @@ export const GENERATED_NESTED: Record = { total_contract_value: f("total_contract_value", "Decimal"), transactions: f("transactions", "str"), }, + Awards2: { + award_amount: f("award_amount", "Decimal"), + award_date: f("award_date", "date"), + award_number: f("award_number", "str"), + awardee: f("awardee", "str"), + awardee_uei: f("awardee_uei", "str"), + notice_id: f("notice_id", "str"), + opportunity_id: f("opportunity_id", "str"), + }, BudgetAppropriation: { cgac: f("cgac", "int"), fiscal_year: f("fiscal_year", "int"), @@ -657,6 +666,7 @@ export const GENERATED_OVERLAY: Record = { organization_id: f("organization_id", "str"), }, BudgetAccount: { + account_category: f("account_category", "str"), account_narrative_excerpt: f("account_narrative_excerpt", "str"), account_title: f("account_title", "str"), actual_vs_requested_contract: f("actual_vs_requested_contract", "str"), @@ -690,6 +700,7 @@ export const GENERATED_OVERLAY: Record = { contract_share_of_obligated: f("contract_share_of_obligated", "str"), contract_share_of_obligated_capped: f("contract_share_of_obligated_capped", "str"), created: f("created", "datetime"), + data_through_period: f("data_through_period", "str"), enacted_ba: f("enacted_ba", "str"), enacted_ba_5yr_cagr: f("enacted_ba_5yr_cagr", "str"), enacted_ba_yoy_pct: f("enacted_ba_yoy_pct", "str"), @@ -715,6 +726,8 @@ export const GENERATED_OVERLAY: Record = { obligated_total: f("obligated_total", "str"), obligated_yoy_pct: f("obligated_yoy_pct", "str"), on_off_budget: f("on_off_budget", "str"), + organization: f("organization", "dict", false, "AwardingOffice"), + organization_id: f("organization_id", "str"), outlayed_to_obligated_pct: f("outlayed_to_obligated_pct", "str"), outlayed_to_obligated_pct_capped: f("outlayed_to_obligated_pct_capped", "str"), outlayed_to_obligated_pct_capped_flag: f("outlayed_to_obligated_pct_capped_flag", "str"), @@ -722,6 +735,7 @@ export const GENERATED_OVERLAY: Record = { requested_ba: f("requested_ba", "str"), requested_contractual_services: f("requested_contractual_services", "str"), requested_personnel_share: f("requested_personnel_share", "str"), + source_anomalies: f("source_anomalies", "str"), subfunction_code: f("subfunction_code", "str"), top_contract_recipients: f("top_contract_recipients", "str"), top_grant_recipients: f("top_grant_recipients", "str"), @@ -801,6 +815,10 @@ export const GENERATED_OVERLAY: Record = { uuid: f("uuid", "str"), workforce: f("workforce", "dict", false, "Workforce"), }, + Exclusion: { + organization: f("organization", "dict", false, "AwardingOffice"), + organization_id: f("organization_id", "str"), + }, Forecast: { created: f("created", "datetime"), display: f("display", "dict", false, "Display"), @@ -903,6 +921,10 @@ export const GENERATED_OVERLAY: Record = { address: f("address", "dict", false, "Address"), archive: f("archive", "dict", false, "Archive"), attachments: f("attachments", "dict", true, "Attachments2"), + award_amount: f("award_amount", "Decimal"), + award_date: f("award_date", "date"), + awardee: f("awardee", "str"), + awardee_uei: f("awardee_uei", "str"), meta: f("meta", "dict", false, "Meta"), office: f("office", "dict", false, "AwardingOffice"), opportunity: f("opportunity", "dict", false, "Opportunity2"), @@ -967,6 +989,13 @@ export const GENERATED_OVERLAY: Record = { agency_id: f("agency_id", "str"), archive_date: f("archive_date", "date"), attachments: f("attachments", "dict", true, "Attachments5"), + award_amount: f("award_amount", "Decimal"), + award_count: f("award_count", "int"), + award_date: f("award_date", "date"), + awarded: f("awarded", "str"), + awardee: f("awardee", "str"), + awardee_uei: f("awardee_uei", "str"), + awards: f("awards", "dict", false, "Awards2"), department: f("department", "dict", false, "Department3"), department_id: f("department_id", "str"), latest_notice: f("latest_notice", "dict", false, "LatestNotice"), @@ -978,6 +1007,7 @@ export const GENERATED_OVERLAY: Record = { secondary_contact: f("secondary_contact", "dict", false, "PrimaryContact"), set_aside: f("set_aside", "dict", false, "CodeDescription"), snippet: f("snippet", "str"), + solicitation_opportunity_id: f("solicitation_opportunity_id", "str"), }, Organization: { aac_code: f("aac_code", "str"), @@ -1046,6 +1076,13 @@ export const GENERATED_OVERLAY: Record = { outcome_reason: f("outcome_reason", "str"), size_standard: f("size_standard", "str"), }, + SbirSolicitation: { + organization: f("organization", "dict", false, "AwardingOffice"), + }, + SbirTopic: { + cycle_name: f("cycle_name", "str"), + organization: f("organization", "dict", false, "AwardingOffice"), + }, Vehicle: { name: f("name", "str"), }, diff --git a/tests/unit/client.test.ts b/tests/unit/client.test.ts index 64c1df9..8273559 100644 --- a/tests/unit/client.test.ts +++ b/tests/unit/client.test.ts @@ -335,6 +335,9 @@ describe("TangoClient", () => { solicitation_identifier: "47QSWA20D0001", solicitation_date: "2024-01-15", vehicle_obligations: 123.45, + awardee_count: 7, + holder_count: 12, + order_winner_count: 7, }, ], }); @@ -368,6 +371,7 @@ describe("TangoClient", () => { }); expect((vehicles.results[0] as any).solicitation_date).toBeInstanceOf(Date); expect((vehicles.results[0] as any).vehicle_obligations).toBe("123.45"); + expect(vehicles.results[0]).toMatchObject({ holder_count: 12, order_winner_count: 7, awardee_count: 7 }); const vehicle = await client.getVehicle("00000000-0000-0000-0000-000000000001", { shape: "uuid,opportunity(title)", diff --git a/tests/unit/config.shapes.parity.test.ts b/tests/unit/config.shapes.parity.test.ts index bc230c7..88079b0 100644 --- a/tests/unit/config.shapes.parity.test.ts +++ b/tests/unit/config.shapes.parity.test.ts @@ -177,7 +177,7 @@ describe("ShapeConfig parity with Python SDK", () => { const expected = "uuid,solicitation_identifier,is_synthetic_solicitation,program_acronym," + "organization_id,organization,vehicle_type,description," + - "idv_count,awardee_count,order_count,total_obligated," + + "idv_count,awardee_count,holder_count,order_winner_count,order_count,total_obligated," + "vehicle_obligations,vehicle_contracts_value,latest_award_date," + "solicitation_title,solicitation_date"; expect(ShapeConfig.VEHICLES_MINIMAL).toBe(expected); @@ -193,7 +193,7 @@ describe("ShapeConfig parity with Python SDK", () => { "solicitation_title,solicitation_description,solicitation_date,opportunity_id," + "naics_code,psc_code,set_aside," + "fiscal_year,award_date,latest_award_date,last_date_to_order," + - "description,idv_count,awardee_count,order_count,total_obligated," + + "description,idv_count,awardee_count,holder_count,order_winner_count,order_count,total_obligated," + "vehicle_obligations,vehicle_contracts_value," + "type_of_idc,contract_type,metrics(*)"; expect(ShapeConfig.VEHICLES_COMPREHENSIVE).toBe(expected);