diff --git a/CHANGELOG.md b/CHANGELOG.md index ca85b75..e34a823 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,16 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html). +## [Unreleased] + +### Fixed + +- Allow omitting search text for Carta Porte, Comercio Exterior, and payroll catalogs, matching the API contract. Empty queries return no matches. + +### Added + +- Search Mexican postal codes, countries, tax regimes, and CFDI uses through `catalogs`, and retrieve postal-code details including neighborhoods. Postal-code searches accept numeric prefixes or neighborhood, locality/city, municipality, and state names, ignore case and diacritics, and support page and cursor pagination. Every postal-code result includes all its neighborhoods. + ## [6.0.0] Unreleased ### Breaking diff --git a/README.md b/README.md index 8d215f7..6253e0c 100644 --- a/README.md +++ b/README.md @@ -157,6 +157,31 @@ await facturapi.customers.createGeneric({ Los tres métodos usan la misma operación de la API. `create()` sigue disponible si decides el caso dinámicamente, o si quieres guardar datos incompletos con `{ createEditLink: true }`. Las validaciones siguen siendo responsabilidad de la API. +### Catálogos de domicilio y datos fiscales + +```ts +const zips = await facturapi.catalogs.searchZipCodes({ + q: 'Nápoles', + state: 'CMX', + pagination: 'cursor', + limit: 10, +}); +if (zips.next_cursor) { + await facturapi.catalogs.searchZipCodes({ + q: 'Nápoles', + state: 'CMX', + after: zips.next_cursor, + limit: 10, + }); +} +const zip = await facturapi.catalogs.getZipCode('01000'); +const countries = await facturapi.catalogs.searchCountries({ q: 'México' }); +const taxSystems = await facturapi.catalogs.searchTaxSystems({ q: '601' }); +const uses = await facturapi.catalogs.searchInvoiceUses({ q: 'gastos' }); +``` + +La búsqueda postal acepta el código completo o un prefijo numérico, o el nombre de una colonia, localidad/ciudad, municipio o estado, y un filtro opcional `state` con la clave de tres letras. Las búsquedas por nombre ignoran mayúsculas y diacríticos, priorizan coincidencias exactas y devuelven cada código postal una sola vez. Cada resultado incluye todas sus colonias en `neighborhoods`, con clave y nombre; el detalle devuelve el mismo objeto. Los códigos postales admiten páginas o cursores (`pagination`, `after`, `before`); conserva los filtros al avanzar. Países, regímenes y usos usan `page` y `limit` (1–100); las claves de catálogo permanecen como strings para conservar ceros iniciales. El régimen y el uso CFDI deben ser declarados por el receptor; consultar el catálogo no los determina. + ## Qué puedes integrar | Necesitas… | Recurso o guía | diff --git a/openapi/source.json b/openapi/source.json index 02568e4..d4b04bf 100644 --- a/openapi/source.json +++ b/openapi/source.json @@ -1,5 +1,5 @@ { "repository": "FacturAPI/facturapi-docs", - "revision": "fbcd72e8cf2b1d1b38d3fd5889ecde6545434c61", + "revision": "9e0fdd689647a1d60f8d9181038225dd04c12732", "path": "website/openapi_v2.yaml" } diff --git a/scripts/sdk/resources.json b/scripts/sdk/resources.json index d5a7c8d..2618a68 100644 --- a/scripts/sdk/resources.json +++ b/scripts/sdk/resources.json @@ -538,7 +538,17 @@ "optional": { "params": false } - } + }, + "searchZipCodes": "searchZipCodes", + "getZipCode": { + "operation": "getZipCode", + "argumentNames": { + "code": "code" + } + }, + "searchCountries": "searchCountries", + "searchTaxSystems": "searchTaxSystems", + "searchInvoiceUses": "searchInvoiceUses" } }, "comercioExteriorCatalogs": { diff --git a/src/generated/dates.ts b/src/generated/dates.ts index da980e6..6a9063b 100644 --- a/src/generated/dates.ts +++ b/src/generated/dates.ts @@ -418,6 +418,11 @@ export const componentDatePlans = { CustomerEditLinkCompletedEvent: 33, ApiEvent: 36, SignedDownloadUrl: 37, + CatalogEntry: 0, + CatalogEntrySearchResult: 0, + ZipCode: 0, + ZipCodeDetail: 0, + ZipCodeSearchResult: 0, SearchKeyDescriptionResult: 0, RelatedResourceMessage: 5, EventBase: 38, @@ -797,6 +802,11 @@ export const operationDatePlans = { validateWebhookSignature: 0, checkApiHealth: 0, validateTaxId: 0, + searchCountries: 0, + searchTaxSystems: 0, + searchInvoiceUses: 0, + searchZipCodes: 0, + getZipCode: 0, searchProducts: 0, searchUnits: 0, onInvoiceGlobalInvoiceCreated: 0, diff --git a/src/generated/input.ts b/src/generated/input.ts index 2d110c9..2a995a3 100644 --- a/src/generated/input.ts +++ b/src/generated/input.ts @@ -2060,6 +2060,106 @@ export interface paths { patch?: never; trace?: never; }; + '/catalogs/countries': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * Buscar países + * Busca países por código ISO de tres letras o nombre. La búsqueda ignora acentos y mayúsculas. + */ + get: operations['searchCountries']; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/catalogs/tax-systems': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * Buscar regímenes fiscales + * Consulta los regímenes fiscales admitidos por la API. El receptor debe declarar su régimen; esta búsqueda no lo determina. + */ + get: operations['searchTaxSystems']; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/catalogs/invoice-uses': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * Buscar usos CFDI + * Consulta claves de uso CFDI por código o descripción. El uso debe ser declarado por el receptor. + */ + get: operations['searchInvoiceUses']; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/catalogs/zip-codes': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * Buscar códigos postales + * Busca códigos postales mexicanos. Una consulta de 1 a 5 dígitos busca por código o prefijo; el texto busca nombres de colonia, localidad/ciudad, municipio o estado, sin distinguir mayúsculas ni diacríticos. Las coincidencias exactas de nombre preceden a las parciales. Cada código postal aparece una sola vez e incluye todas sus colonias en neighborhoods. El filtro de estado se aplica en ambos casos. Sin consulta, lista códigos postales. Admite páginas y cursores; los totales de búsquedas textuales pueden estar limitados, indicado por totals_are_capped. + */ + get: operations['searchZipCodes']; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/catalogs/zip-codes/{code}': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * Consultar código postal + * Devuelve los datos de domicilio y las colonias de un código postal mexicano. + */ + get: operations['getZipCode']; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; '/catalogs/products': { parameters: { query?: never; @@ -2412,6 +2512,26 @@ export interface components { /** Nombre sugerido del archivo. */ filename: string; }; + CatalogEntry: { + key: string; + description: string; + }; + CatalogEntrySearchResult: components['schemas']['SearchResult'] & { + data: components['schemas']['CatalogEntry'][]; + }; + ZipCode: { + key: string; + country: components['schemas']['CatalogEntry']; + state: components['schemas']['CatalogEntry'] | null; + municipality: components['schemas']['CatalogEntry'] | null; + locality: components['schemas']['CatalogEntry'] | null; + /** Todas las colonias del código postal, aunque la búsqueda coincida por otro campo. */ + neighborhoods: components['schemas']['CatalogEntry'][]; + }; + ZipCodeDetail: components['schemas']['ZipCode']; + ZipCodeSearchResult: components['schemas']['SearchResult'] & { + data: components['schemas']['ZipCode'][]; + }; SearchKeyDescriptionResult: components['schemas']['SearchResult'] & { data?: { /** Clave del catálogo */ @@ -7494,9 +7614,9 @@ export type $defs = Record; export interface operations { searchNominaDeductions: { parameters: { - query: { + query?: { /** Prefijo para buscar en `key` o `description`. */ - q: string; + q?: string; page?: number; limit?: number; }; @@ -7522,9 +7642,9 @@ export interface operations { }; searchNominaPerceptions: { parameters: { - query: { + query?: { /** Prefijo para buscar en `key` o `description`. */ - q: string; + q?: string; page?: number; limit?: number; }; @@ -7550,7 +7670,7 @@ export interface operations { }; searchCartaPorteAirTransportCodes: { parameters: { - query: { + query?: { /** Modo de paginación de la búsqueda. `page` (por defecto) o `cursor` (recomendado para listas grandes). */ pagination?: components['parameters']['SearchPagination']; /** Devuelve los resultados posteriores al cursor indicado. Solo con `pagination=cursor`; mutuamente excluyente con `before`. */ @@ -7558,7 +7678,7 @@ export interface operations { /** Devuelve los resultados anteriores al cursor indicado. Solo con `pagination=cursor`; mutuamente excluyente con `after`. */ before?: components['parameters']['SearchBefore']; /** Prefijo para buscar en `key`, `airline_name` o `icao_designator`. */ - q: string; + q?: string; /** Página de resultados a regresar, empezando desde la página 1. El máximo no es fijo; junto con `limit` debe caber dentro del tope de 3,000 resultados. */ page?: number; /** Número del 1 al 100 que representa la cantidad máxima de resultados a regresar con motivos de paginación. */ @@ -7588,7 +7708,7 @@ export interface operations { }; searchComercioExteriorTariffFractions: { parameters: { - query: { + query?: { /** Modo de paginación de la búsqueda. `page` (por defecto) o `cursor` (recomendado para listas grandes). */ pagination?: components['parameters']['SearchPagination']; /** Devuelve los resultados posteriores al cursor indicado. Solo con `pagination=cursor`; mutuamente excluyente con `before`. */ @@ -7596,7 +7716,7 @@ export interface operations { /** Devuelve los resultados anteriores al cursor indicado. Solo con `pagination=cursor`; mutuamente excluyente con `after`. */ before?: components['parameters']['SearchBefore']; /** Prefijo para buscar en `key` o `description`. */ - q: string; + q?: string; /** Página de resultados a regresar, empezando desde la página 1. El máximo no es fijo; junto con `limit` debe caber dentro del tope de 3,000 resultados. */ page?: number; /** Número del 1 al 100 que representa la cantidad máxima de resultados a regresar con motivos de paginación. */ @@ -7626,7 +7746,7 @@ export interface operations { }; searchCartaPorteTransportConfigs: { parameters: { - query: { + query?: { /** Modo de paginación de la búsqueda. `page` (por defecto) o `cursor` (recomendado para listas grandes). */ pagination?: components['parameters']['SearchPagination']; /** Devuelve los resultados posteriores al cursor indicado. Solo con `pagination=cursor`; mutuamente excluyente con `before`. */ @@ -7634,7 +7754,7 @@ export interface operations { /** Devuelve los resultados anteriores al cursor indicado. Solo con `pagination=cursor`; mutuamente excluyente con `after`. */ before?: components['parameters']['SearchBefore']; /** Prefijo para buscar en `key` o `description`. */ - q: string; + q?: string; /** Página de resultados a regresar, empezando desde la página 1. El máximo no es fijo; junto con `limit` debe caber dentro del tope de 3,000 resultados. */ page?: number; /** Número del 1 al 100 que representa la cantidad máxima de resultados a regresar con motivos de paginación. */ @@ -7664,7 +7784,7 @@ export interface operations { }; searchCartaPorteRightsOfPassage: { parameters: { - query: { + query?: { /** Modo de paginación de la búsqueda. `page` (por defecto) o `cursor` (recomendado para listas grandes). */ pagination?: components['parameters']['SearchPagination']; /** Devuelve los resultados posteriores al cursor indicado. Solo con `pagination=cursor`; mutuamente excluyente con `before`. */ @@ -7672,7 +7792,7 @@ export interface operations { /** Devuelve los resultados anteriores al cursor indicado. Solo con `pagination=cursor`; mutuamente excluyente con `after`. */ before?: components['parameters']['SearchBefore']; /** Prefijo para buscar en `key`, `right_of_passage` o `concessionaire`. */ - q: string; + q?: string; /** Página de resultados a regresar, empezando desde la página 1. El máximo no es fijo; junto con `limit` debe caber dentro del tope de 3,000 resultados. */ page?: number; /** Número del 1 al 100 que representa la cantidad máxima de resultados a regresar con motivos de paginación. */ @@ -7702,7 +7822,7 @@ export interface operations { }; searchCartaPorteCustomsDocuments: { parameters: { - query: { + query?: { /** Modo de paginación de la búsqueda. `page` (por defecto) o `cursor` (recomendado para listas grandes). */ pagination?: components['parameters']['SearchPagination']; /** Devuelve los resultados posteriores al cursor indicado. Solo con `pagination=cursor`; mutuamente excluyente con `before`. */ @@ -7710,7 +7830,7 @@ export interface operations { /** Devuelve los resultados anteriores al cursor indicado. Solo con `pagination=cursor`; mutuamente excluyente con `after`. */ before?: components['parameters']['SearchBefore']; /** Prefijo para buscar en `key` o `description`. */ - q: string; + q?: string; /** Página de resultados a regresar, empezando desde la página 1. El máximo no es fijo; junto con `limit` debe caber dentro del tope de 3,000 resultados. */ page?: number; /** Número del 1 al 100 que representa la cantidad máxima de resultados a regresar con motivos de paginación. */ @@ -7740,7 +7860,7 @@ export interface operations { }; searchCartaPortePackagingTypes: { parameters: { - query: { + query?: { /** Modo de paginación de la búsqueda. `page` (por defecto) o `cursor` (recomendado para listas grandes). */ pagination?: components['parameters']['SearchPagination']; /** Devuelve los resultados posteriores al cursor indicado. Solo con `pagination=cursor`; mutuamente excluyente con `before`. */ @@ -7748,7 +7868,7 @@ export interface operations { /** Devuelve los resultados anteriores al cursor indicado. Solo con `pagination=cursor`; mutuamente excluyente con `after`. */ before?: components['parameters']['SearchBefore']; /** Prefijo para buscar en `key` o `description`. */ - q: string; + q?: string; /** Página de resultados a regresar, empezando desde la página 1. El máximo no es fijo; junto con `limit` debe caber dentro del tope de 3,000 resultados. */ page?: number; /** Número del 1 al 100 que representa la cantidad máxima de resultados a regresar con motivos de paginación. */ @@ -7778,7 +7898,7 @@ export interface operations { }; searchCartaPorteTrailerTypes: { parameters: { - query: { + query?: { /** Modo de paginación de la búsqueda. `page` (por defecto) o `cursor` (recomendado para listas grandes). */ pagination?: components['parameters']['SearchPagination']; /** Devuelve los resultados posteriores al cursor indicado. Solo con `pagination=cursor`; mutuamente excluyente con `before`. */ @@ -7786,7 +7906,7 @@ export interface operations { /** Devuelve los resultados anteriores al cursor indicado. Solo con `pagination=cursor`; mutuamente excluyente con `after`. */ before?: components['parameters']['SearchBefore']; /** Prefijo para buscar en `key` o `description`. */ - q: string; + q?: string; /** Página de resultados a regresar, empezando desde la página 1. El máximo no es fijo; junto con `limit` debe caber dentro del tope de 3,000 resultados. */ page?: number; /** Número del 1 al 100 que representa la cantidad máxima de resultados a regresar con motivos de paginación. */ @@ -7816,7 +7936,7 @@ export interface operations { }; searchCartaPorteHazardousMaterials: { parameters: { - query: { + query?: { /** Modo de paginación de la búsqueda. `page` (por defecto) o `cursor` (recomendado para listas grandes). */ pagination?: components['parameters']['SearchPagination']; /** Devuelve los resultados posteriores al cursor indicado. Solo con `pagination=cursor`; mutuamente excluyente con `before`. */ @@ -7824,7 +7944,7 @@ export interface operations { /** Devuelve los resultados anteriores al cursor indicado. Solo con `pagination=cursor`; mutuamente excluyente con `after`. */ before?: components['parameters']['SearchBefore']; /** Prefijo para buscar en `key`, `description` o `class_division`. */ - q: string; + q?: string; /** Página de resultados a regresar, empezando desde la página 1. El máximo no es fijo; junto con `limit` debe caber dentro del tope de 3,000 resultados. */ page?: number; /** Número del 1 al 100 que representa la cantidad máxima de resultados a regresar con motivos de paginación. */ @@ -7854,7 +7974,7 @@ export interface operations { }; searchCartaPorteNavalAuthorizations: { parameters: { - query: { + query?: { /** Modo de paginación de la búsqueda. `page` (por defecto) o `cursor` (recomendado para listas grandes). */ pagination?: components['parameters']['SearchPagination']; /** Devuelve los resultados posteriores al cursor indicado. Solo con `pagination=cursor`; mutuamente excluyente con `before`. */ @@ -7862,7 +7982,7 @@ export interface operations { /** Devuelve los resultados anteriores al cursor indicado. Solo con `pagination=cursor`; mutuamente excluyente con `after`. */ before?: components['parameters']['SearchBefore']; /** Prefijo para buscar en `key`. */ - q: string; + q?: string; /** Página de resultados a regresar, empezando desde la página 1. El máximo no es fijo; junto con `limit` debe caber dentro del tope de 3,000 resultados. */ page?: number; /** Número del 1 al 100 que representa la cantidad máxima de resultados a regresar con motivos de paginación. */ @@ -7896,7 +8016,7 @@ export interface operations { }; searchCartaPortePortStations: { parameters: { - query: { + query?: { /** Modo de paginación de la búsqueda. `page` (por defecto) o `cursor` (recomendado para listas grandes). */ pagination?: components['parameters']['SearchPagination']; /** Devuelve los resultados posteriores al cursor indicado. Solo con `pagination=cursor`; mutuamente excluyente con `before`. */ @@ -7904,7 +8024,7 @@ export interface operations { /** Devuelve los resultados anteriores al cursor indicado. Solo con `pagination=cursor`; mutuamente excluyente con `after`. */ before?: components['parameters']['SearchBefore']; /** Prefijo para buscar en `key`, `description` o `iata_designator`. */ - q: string; + q?: string; /** Página de resultados a regresar, empezando desde la página 1. El máximo no es fijo; junto con `limit` debe caber dentro del tope de 3,000 resultados. */ page?: number; /** Número del 1 al 100 que representa la cantidad máxima de resultados a regresar con motivos de paginación. */ @@ -7934,7 +8054,7 @@ export interface operations { }; searchCartaPorteMarineContainers: { parameters: { - query: { + query?: { /** Modo de paginación de la búsqueda. `page` (por defecto) o `cursor` (recomendado para listas grandes). */ pagination?: components['parameters']['SearchPagination']; /** Devuelve los resultados posteriores al cursor indicado. Solo con `pagination=cursor`; mutuamente excluyente con `before`. */ @@ -7942,7 +8062,7 @@ export interface operations { /** Devuelve los resultados anteriores al cursor indicado. Solo con `pagination=cursor`; mutuamente excluyente con `after`. */ before?: components['parameters']['SearchBefore']; /** Prefijo para buscar en `key` o `description`. */ - q: string; + q?: string; /** Página de resultados a regresar, empezando desde la página 1. El máximo no es fijo; junto con `limit` debe caber dentro del tope de 3,000 resultados. */ page?: number; /** Número del 1 al 100 que representa la cantidad máxima de resultados a regresar con motivos de paginación. */ @@ -11248,6 +11368,157 @@ export interface operations { 500: components['responses']['UnexpectedError']; }; }; + searchCountries: { + parameters: { + query?: { + /** Código o texto a buscar. */ + q?: string; + page?: number; + limit?: number; + }; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** Resultados de búsqueda */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': components['schemas']['CatalogEntrySearchResult']; + }; + }; + 400: components['responses']['BadRequest']; + 401: components['responses']['Unauthenticated']; + 429: components['responses']['RateLimited']; + 500: components['responses']['UnexpectedError']; + }; + }; + searchTaxSystems: { + parameters: { + query?: { + /** Código o texto a buscar. */ + q?: string; + page?: number; + limit?: number; + }; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** Resultados de búsqueda */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': components['schemas']['CatalogEntrySearchResult']; + }; + }; + 400: components['responses']['BadRequest']; + 401: components['responses']['Unauthenticated']; + 429: components['responses']['RateLimited']; + 500: components['responses']['UnexpectedError']; + }; + }; + searchInvoiceUses: { + parameters: { + query?: { + /** Código o texto a buscar. */ + q?: string; + page?: number; + limit?: number; + }; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** Resultados de búsqueda */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': components['schemas']['CatalogEntrySearchResult']; + }; + }; + 400: components['responses']['BadRequest']; + 401: components['responses']['Unauthenticated']; + 429: components['responses']['RateLimited']; + 500: components['responses']['UnexpectedError']; + }; + }; + searchZipCodes: { + parameters: { + query?: { + /** Modo de paginación de la búsqueda. `page` (por defecto) o `cursor` (recomendado para listas grandes). */ + pagination?: components['parameters']['SearchPagination']; + /** Devuelve los resultados posteriores al cursor indicado. Solo con `pagination=cursor`; mutuamente excluyente con `before`. */ + after?: components['parameters']['SearchAfter']; + /** Devuelve los resultados anteriores al cursor indicado. Solo con `pagination=cursor`; mutuamente excluyente con `after`. */ + before?: components['parameters']['SearchBefore']; + /** Código o prefijo de 1 a 5 dígitos, o nombre de colonia, localidad/ciudad, municipio o estado. */ + q?: string; + page?: number; + limit?: number; + /** Clave de estado de tres letras (por ejemplo ZAC). */ + state?: string; + }; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** Resultados de búsqueda */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': components['schemas']['ZipCodeSearchResult']; + }; + }; + 400: components['responses']['BadRequest']; + 401: components['responses']['Unauthenticated']; + 429: components['responses']['RateLimited']; + 500: components['responses']['UnexpectedError']; + }; + }; + getZipCode: { + parameters: { + query?: never; + header?: never; + path: { + code: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** Código postal */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': components['schemas']['ZipCodeDetail']; + }; + }; + 400: components['responses']['BadRequest']; + 401: components['responses']['Unauthenticated']; + 404: components['responses']['NotFound']; + 429: components['responses']['RateLimited']; + 500: components['responses']['UnexpectedError']; + }; + }; searchProducts: { parameters: { query?: { diff --git a/src/generated/models.ts b/src/generated/models.ts index 17f02ba..223d4f9 100644 --- a/src/generated/models.ts +++ b/src/generated/models.ts @@ -17,6 +17,12 @@ export type ReceiptStatusUpdatedEvent = export type CustomerEditLinkCompletedEvent = Output['schemas']['CustomerEditLinkCompletedEvent']; export type SignedDownloadUrl = Output['schemas']['SignedDownloadUrl']; +export type CatalogEntry = Output['schemas']['CatalogEntry']; +export type CatalogEntrySearchResult = + Output['schemas']['CatalogEntrySearchResult']; +export type ZipCode = Output['schemas']['ZipCode']; +export type ZipCodeDetail = Output['schemas']['ZipCodeDetail']; +export type ZipCodeSearchResult = Output['schemas']['ZipCodeSearchResult']; export type SearchKeyDescriptionResult = Output['schemas']['SearchKeyDescriptionResult']; export type RelatedResourceMessage = diff --git a/src/generated/output.ts b/src/generated/output.ts index 8f4a4ef..748a014 100644 --- a/src/generated/output.ts +++ b/src/generated/output.ts @@ -2072,6 +2072,106 @@ export interface paths { patch?: never; trace?: never; }; + '/catalogs/countries': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * Buscar países + * Busca países por código ISO de tres letras o nombre. La búsqueda ignora acentos y mayúsculas. + */ + get: operations['searchCountries']; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/catalogs/tax-systems': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * Buscar regímenes fiscales + * Consulta los regímenes fiscales admitidos por la API. El receptor debe declarar su régimen; esta búsqueda no lo determina. + */ + get: operations['searchTaxSystems']; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/catalogs/invoice-uses': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * Buscar usos CFDI + * Consulta claves de uso CFDI por código o descripción. El uso debe ser declarado por el receptor. + */ + get: operations['searchInvoiceUses']; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/catalogs/zip-codes': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * Buscar códigos postales + * Busca códigos postales mexicanos. Una consulta de 1 a 5 dígitos busca por código o prefijo; el texto busca nombres de colonia, localidad/ciudad, municipio o estado, sin distinguir mayúsculas ni diacríticos. Las coincidencias exactas de nombre preceden a las parciales. Cada código postal aparece una sola vez e incluye todas sus colonias en neighborhoods. El filtro de estado se aplica en ambos casos. Sin consulta, lista códigos postales. Admite páginas y cursores; los totales de búsquedas textuales pueden estar limitados, indicado por totals_are_capped. + */ + get: operations['searchZipCodes']; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + '/catalogs/zip-codes/{code}': { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * Consultar código postal + * Devuelve los datos de domicilio y las colonias de un código postal mexicano. + */ + get: operations['getZipCode']; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; '/catalogs/products': { parameters: { query?: never; @@ -2424,6 +2524,26 @@ export interface components { /** Nombre sugerido del archivo. */ filename: string; }; + CatalogEntry: { + key: string; + description: string; + }; + CatalogEntrySearchResult: components['schemas']['SearchResult'] & { + data: components['schemas']['CatalogEntry'][]; + }; + ZipCode: { + key: string; + country: components['schemas']['CatalogEntry']; + state: components['schemas']['CatalogEntry'] | null; + municipality: components['schemas']['CatalogEntry'] | null; + locality: components['schemas']['CatalogEntry'] | null; + /** Todas las colonias del código postal, aunque la búsqueda coincida por otro campo. */ + neighborhoods: components['schemas']['CatalogEntry'][]; + }; + ZipCodeDetail: components['schemas']['ZipCode']; + ZipCodeSearchResult: components['schemas']['SearchResult'] & { + data: components['schemas']['ZipCode'][]; + }; SearchKeyDescriptionResult: components['schemas']['SearchResult'] & { data?: { /** Clave del catálogo */ @@ -7510,9 +7630,9 @@ export type $defs = Record; export interface operations { searchNominaDeductions: { parameters: { - query: { + query?: { /** Prefijo para buscar en `key` o `description`. */ - q: string; + q?: string; page?: number; limit?: number; }; @@ -7538,9 +7658,9 @@ export interface operations { }; searchNominaPerceptions: { parameters: { - query: { + query?: { /** Prefijo para buscar en `key` o `description`. */ - q: string; + q?: string; page?: number; limit?: number; }; @@ -7566,7 +7686,7 @@ export interface operations { }; searchCartaPorteAirTransportCodes: { parameters: { - query: { + query?: { /** Modo de paginación de la búsqueda. `page` (por defecto) o `cursor` (recomendado para listas grandes). */ pagination?: components['parameters']['SearchPagination']; /** Devuelve los resultados posteriores al cursor indicado. Solo con `pagination=cursor`; mutuamente excluyente con `before`. */ @@ -7574,7 +7694,7 @@ export interface operations { /** Devuelve los resultados anteriores al cursor indicado. Solo con `pagination=cursor`; mutuamente excluyente con `after`. */ before?: components['parameters']['SearchBefore']; /** Prefijo para buscar en `key`, `airline_name` o `icao_designator`. */ - q: string; + q?: string; /** Página de resultados a regresar, empezando desde la página 1. El máximo no es fijo; junto con `limit` debe caber dentro del tope de 3,000 resultados. */ page?: number; /** Número del 1 al 100 que representa la cantidad máxima de resultados a regresar con motivos de paginación. */ @@ -7604,7 +7724,7 @@ export interface operations { }; searchComercioExteriorTariffFractions: { parameters: { - query: { + query?: { /** Modo de paginación de la búsqueda. `page` (por defecto) o `cursor` (recomendado para listas grandes). */ pagination?: components['parameters']['SearchPagination']; /** Devuelve los resultados posteriores al cursor indicado. Solo con `pagination=cursor`; mutuamente excluyente con `before`. */ @@ -7612,7 +7732,7 @@ export interface operations { /** Devuelve los resultados anteriores al cursor indicado. Solo con `pagination=cursor`; mutuamente excluyente con `after`. */ before?: components['parameters']['SearchBefore']; /** Prefijo para buscar en `key` o `description`. */ - q: string; + q?: string; /** Página de resultados a regresar, empezando desde la página 1. El máximo no es fijo; junto con `limit` debe caber dentro del tope de 3,000 resultados. */ page?: number; /** Número del 1 al 100 que representa la cantidad máxima de resultados a regresar con motivos de paginación. */ @@ -7642,7 +7762,7 @@ export interface operations { }; searchCartaPorteTransportConfigs: { parameters: { - query: { + query?: { /** Modo de paginación de la búsqueda. `page` (por defecto) o `cursor` (recomendado para listas grandes). */ pagination?: components['parameters']['SearchPagination']; /** Devuelve los resultados posteriores al cursor indicado. Solo con `pagination=cursor`; mutuamente excluyente con `before`. */ @@ -7650,7 +7770,7 @@ export interface operations { /** Devuelve los resultados anteriores al cursor indicado. Solo con `pagination=cursor`; mutuamente excluyente con `after`. */ before?: components['parameters']['SearchBefore']; /** Prefijo para buscar en `key` o `description`. */ - q: string; + q?: string; /** Página de resultados a regresar, empezando desde la página 1. El máximo no es fijo; junto con `limit` debe caber dentro del tope de 3,000 resultados. */ page?: number; /** Número del 1 al 100 que representa la cantidad máxima de resultados a regresar con motivos de paginación. */ @@ -7680,7 +7800,7 @@ export interface operations { }; searchCartaPorteRightsOfPassage: { parameters: { - query: { + query?: { /** Modo de paginación de la búsqueda. `page` (por defecto) o `cursor` (recomendado para listas grandes). */ pagination?: components['parameters']['SearchPagination']; /** Devuelve los resultados posteriores al cursor indicado. Solo con `pagination=cursor`; mutuamente excluyente con `before`. */ @@ -7688,7 +7808,7 @@ export interface operations { /** Devuelve los resultados anteriores al cursor indicado. Solo con `pagination=cursor`; mutuamente excluyente con `after`. */ before?: components['parameters']['SearchBefore']; /** Prefijo para buscar en `key`, `right_of_passage` o `concessionaire`. */ - q: string; + q?: string; /** Página de resultados a regresar, empezando desde la página 1. El máximo no es fijo; junto con `limit` debe caber dentro del tope de 3,000 resultados. */ page?: number; /** Número del 1 al 100 que representa la cantidad máxima de resultados a regresar con motivos de paginación. */ @@ -7718,7 +7838,7 @@ export interface operations { }; searchCartaPorteCustomsDocuments: { parameters: { - query: { + query?: { /** Modo de paginación de la búsqueda. `page` (por defecto) o `cursor` (recomendado para listas grandes). */ pagination?: components['parameters']['SearchPagination']; /** Devuelve los resultados posteriores al cursor indicado. Solo con `pagination=cursor`; mutuamente excluyente con `before`. */ @@ -7726,7 +7846,7 @@ export interface operations { /** Devuelve los resultados anteriores al cursor indicado. Solo con `pagination=cursor`; mutuamente excluyente con `after`. */ before?: components['parameters']['SearchBefore']; /** Prefijo para buscar en `key` o `description`. */ - q: string; + q?: string; /** Página de resultados a regresar, empezando desde la página 1. El máximo no es fijo; junto con `limit` debe caber dentro del tope de 3,000 resultados. */ page?: number; /** Número del 1 al 100 que representa la cantidad máxima de resultados a regresar con motivos de paginación. */ @@ -7756,7 +7876,7 @@ export interface operations { }; searchCartaPortePackagingTypes: { parameters: { - query: { + query?: { /** Modo de paginación de la búsqueda. `page` (por defecto) o `cursor` (recomendado para listas grandes). */ pagination?: components['parameters']['SearchPagination']; /** Devuelve los resultados posteriores al cursor indicado. Solo con `pagination=cursor`; mutuamente excluyente con `before`. */ @@ -7764,7 +7884,7 @@ export interface operations { /** Devuelve los resultados anteriores al cursor indicado. Solo con `pagination=cursor`; mutuamente excluyente con `after`. */ before?: components['parameters']['SearchBefore']; /** Prefijo para buscar en `key` o `description`. */ - q: string; + q?: string; /** Página de resultados a regresar, empezando desde la página 1. El máximo no es fijo; junto con `limit` debe caber dentro del tope de 3,000 resultados. */ page?: number; /** Número del 1 al 100 que representa la cantidad máxima de resultados a regresar con motivos de paginación. */ @@ -7794,7 +7914,7 @@ export interface operations { }; searchCartaPorteTrailerTypes: { parameters: { - query: { + query?: { /** Modo de paginación de la búsqueda. `page` (por defecto) o `cursor` (recomendado para listas grandes). */ pagination?: components['parameters']['SearchPagination']; /** Devuelve los resultados posteriores al cursor indicado. Solo con `pagination=cursor`; mutuamente excluyente con `before`. */ @@ -7802,7 +7922,7 @@ export interface operations { /** Devuelve los resultados anteriores al cursor indicado. Solo con `pagination=cursor`; mutuamente excluyente con `after`. */ before?: components['parameters']['SearchBefore']; /** Prefijo para buscar en `key` o `description`. */ - q: string; + q?: string; /** Página de resultados a regresar, empezando desde la página 1. El máximo no es fijo; junto con `limit` debe caber dentro del tope de 3,000 resultados. */ page?: number; /** Número del 1 al 100 que representa la cantidad máxima de resultados a regresar con motivos de paginación. */ @@ -7832,7 +7952,7 @@ export interface operations { }; searchCartaPorteHazardousMaterials: { parameters: { - query: { + query?: { /** Modo de paginación de la búsqueda. `page` (por defecto) o `cursor` (recomendado para listas grandes). */ pagination?: components['parameters']['SearchPagination']; /** Devuelve los resultados posteriores al cursor indicado. Solo con `pagination=cursor`; mutuamente excluyente con `before`. */ @@ -7840,7 +7960,7 @@ export interface operations { /** Devuelve los resultados anteriores al cursor indicado. Solo con `pagination=cursor`; mutuamente excluyente con `after`. */ before?: components['parameters']['SearchBefore']; /** Prefijo para buscar en `key`, `description` o `class_division`. */ - q: string; + q?: string; /** Página de resultados a regresar, empezando desde la página 1. El máximo no es fijo; junto con `limit` debe caber dentro del tope de 3,000 resultados. */ page?: number; /** Número del 1 al 100 que representa la cantidad máxima de resultados a regresar con motivos de paginación. */ @@ -7870,7 +7990,7 @@ export interface operations { }; searchCartaPorteNavalAuthorizations: { parameters: { - query: { + query?: { /** Modo de paginación de la búsqueda. `page` (por defecto) o `cursor` (recomendado para listas grandes). */ pagination?: components['parameters']['SearchPagination']; /** Devuelve los resultados posteriores al cursor indicado. Solo con `pagination=cursor`; mutuamente excluyente con `before`. */ @@ -7878,7 +7998,7 @@ export interface operations { /** Devuelve los resultados anteriores al cursor indicado. Solo con `pagination=cursor`; mutuamente excluyente con `after`. */ before?: components['parameters']['SearchBefore']; /** Prefijo para buscar en `key`. */ - q: string; + q?: string; /** Página de resultados a regresar, empezando desde la página 1. El máximo no es fijo; junto con `limit` debe caber dentro del tope de 3,000 resultados. */ page?: number; /** Número del 1 al 100 que representa la cantidad máxima de resultados a regresar con motivos de paginación. */ @@ -7912,7 +8032,7 @@ export interface operations { }; searchCartaPortePortStations: { parameters: { - query: { + query?: { /** Modo de paginación de la búsqueda. `page` (por defecto) o `cursor` (recomendado para listas grandes). */ pagination?: components['parameters']['SearchPagination']; /** Devuelve los resultados posteriores al cursor indicado. Solo con `pagination=cursor`; mutuamente excluyente con `before`. */ @@ -7920,7 +8040,7 @@ export interface operations { /** Devuelve los resultados anteriores al cursor indicado. Solo con `pagination=cursor`; mutuamente excluyente con `after`. */ before?: components['parameters']['SearchBefore']; /** Prefijo para buscar en `key`, `description` o `iata_designator`. */ - q: string; + q?: string; /** Página de resultados a regresar, empezando desde la página 1. El máximo no es fijo; junto con `limit` debe caber dentro del tope de 3,000 resultados. */ page?: number; /** Número del 1 al 100 que representa la cantidad máxima de resultados a regresar con motivos de paginación. */ @@ -7950,7 +8070,7 @@ export interface operations { }; searchCartaPorteMarineContainers: { parameters: { - query: { + query?: { /** Modo de paginación de la búsqueda. `page` (por defecto) o `cursor` (recomendado para listas grandes). */ pagination?: components['parameters']['SearchPagination']; /** Devuelve los resultados posteriores al cursor indicado. Solo con `pagination=cursor`; mutuamente excluyente con `before`. */ @@ -7958,7 +8078,7 @@ export interface operations { /** Devuelve los resultados anteriores al cursor indicado. Solo con `pagination=cursor`; mutuamente excluyente con `after`. */ before?: components['parameters']['SearchBefore']; /** Prefijo para buscar en `key` o `description`. */ - q: string; + q?: string; /** Página de resultados a regresar, empezando desde la página 1. El máximo no es fijo; junto con `limit` debe caber dentro del tope de 3,000 resultados. */ page?: number; /** Número del 1 al 100 que representa la cantidad máxima de resultados a regresar con motivos de paginación. */ @@ -11264,6 +11384,157 @@ export interface operations { 500: components['responses']['UnexpectedError']; }; }; + searchCountries: { + parameters: { + query?: { + /** Código o texto a buscar. */ + q?: string; + page?: number; + limit?: number; + }; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** Resultados de búsqueda */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': components['schemas']['CatalogEntrySearchResult']; + }; + }; + 400: components['responses']['BadRequest']; + 401: components['responses']['Unauthenticated']; + 429: components['responses']['RateLimited']; + 500: components['responses']['UnexpectedError']; + }; + }; + searchTaxSystems: { + parameters: { + query?: { + /** Código o texto a buscar. */ + q?: string; + page?: number; + limit?: number; + }; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** Resultados de búsqueda */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': components['schemas']['CatalogEntrySearchResult']; + }; + }; + 400: components['responses']['BadRequest']; + 401: components['responses']['Unauthenticated']; + 429: components['responses']['RateLimited']; + 500: components['responses']['UnexpectedError']; + }; + }; + searchInvoiceUses: { + parameters: { + query?: { + /** Código o texto a buscar. */ + q?: string; + page?: number; + limit?: number; + }; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** Resultados de búsqueda */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': components['schemas']['CatalogEntrySearchResult']; + }; + }; + 400: components['responses']['BadRequest']; + 401: components['responses']['Unauthenticated']; + 429: components['responses']['RateLimited']; + 500: components['responses']['UnexpectedError']; + }; + }; + searchZipCodes: { + parameters: { + query?: { + /** Modo de paginación de la búsqueda. `page` (por defecto) o `cursor` (recomendado para listas grandes). */ + pagination?: components['parameters']['SearchPagination']; + /** Devuelve los resultados posteriores al cursor indicado. Solo con `pagination=cursor`; mutuamente excluyente con `before`. */ + after?: components['parameters']['SearchAfter']; + /** Devuelve los resultados anteriores al cursor indicado. Solo con `pagination=cursor`; mutuamente excluyente con `after`. */ + before?: components['parameters']['SearchBefore']; + /** Código o prefijo de 1 a 5 dígitos, o nombre de colonia, localidad/ciudad, municipio o estado. */ + q?: string; + page?: number; + limit?: number; + /** Clave de estado de tres letras (por ejemplo ZAC). */ + state?: string; + }; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** Resultados de búsqueda */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': components['schemas']['ZipCodeSearchResult']; + }; + }; + 400: components['responses']['BadRequest']; + 401: components['responses']['Unauthenticated']; + 429: components['responses']['RateLimited']; + 500: components['responses']['UnexpectedError']; + }; + }; + getZipCode: { + parameters: { + query?: never; + header?: never; + path: { + code: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** Código postal */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + 'application/json': components['schemas']['ZipCodeDetail']; + }; + }; + 400: components['responses']['BadRequest']; + 401: components['responses']['Unauthenticated']; + 404: components['responses']['NotFound']; + 429: components['responses']['RateLimited']; + 500: components['responses']['UnexpectedError']; + }; + }; searchProducts: { parameters: { query?: { diff --git a/src/tools/cartaPorteCatalogs.ts b/src/tools/cartaPorteCatalogs.ts index 68d19f1..8ea4074 100644 --- a/src/tools/cartaPorteCatalogs.ts +++ b/src/tools/cartaPorteCatalogs.ts @@ -14,11 +14,10 @@ export default class CartaPorteCatalogs { * Devuelve entradas del catálogo de aerolíneas que coinciden con la consulta. Usado para el complemento Carta Porte. * * @param params - Parámetros de consulta. - * @param params.q - Prefijo para buscar en `key`, `airline_name` o `icao_designator`. * @returns Búsqueda exitosa */ searchAirTransportCodes( - params: OperationQuery<'searchCartaPorteAirTransportCodes'> | null, + params?: OperationQuery<'searchCartaPorteAirTransportCodes'> | null, ): Promise> { return this.client.request< OperationResponse<'searchCartaPorteAirTransportCodes'> @@ -35,11 +34,10 @@ export default class CartaPorteCatalogs { * Devuelve configuraciones de transporte (p. ej., camión/semirremolque). * * @param params - Parámetros de consulta. - * @param params.q - Prefijo para buscar en `key` o `description`. * @returns Búsqueda exitosa */ searchTransportConfigs( - params: OperationQuery<'searchCartaPorteTransportConfigs'> | null, + params?: OperationQuery<'searchCartaPorteTransportConfigs'> | null, ): Promise> { return this.client.request< OperationResponse<'searchCartaPorteTransportConfigs'> @@ -56,11 +54,10 @@ export default class CartaPorteCatalogs { * Devuelve derechos de paso ferroviarios que coinciden con la consulta. * * @param params - Parámetros de consulta. - * @param params.q - Prefijo para buscar en `key`, `right_of_passage` o `concessionaire`. * @returns Búsqueda exitosa */ searchRightsOfPassage( - params: OperationQuery<'searchCartaPorteRightsOfPassage'> | null, + params?: OperationQuery<'searchCartaPorteRightsOfPassage'> | null, ): Promise> { return this.client.request< OperationResponse<'searchCartaPorteRightsOfPassage'> @@ -77,11 +74,10 @@ export default class CartaPorteCatalogs { * Devuelve tipos de documentos aduaneros. * * @param params - Parámetros de consulta. - * @param params.q - Prefijo para buscar en `key` o `description`. * @returns Búsqueda exitosa */ searchCustomsDocuments( - params: OperationQuery<'searchCartaPorteCustomsDocuments'> | null, + params?: OperationQuery<'searchCartaPorteCustomsDocuments'> | null, ): Promise> { return this.client.request< OperationResponse<'searchCartaPorteCustomsDocuments'> @@ -98,11 +94,10 @@ export default class CartaPorteCatalogs { * Devuelve tipos de empaque para mercancías. * * @param params - Parámetros de consulta. - * @param params.q - Prefijo para buscar en `key` o `description`. * @returns Búsqueda exitosa */ searchPackagingTypes( - params: OperationQuery<'searchCartaPortePackagingTypes'> | null, + params?: OperationQuery<'searchCartaPortePackagingTypes'> | null, ): Promise> { return this.client.request< OperationResponse<'searchCartaPortePackagingTypes'> @@ -119,11 +114,10 @@ export default class CartaPorteCatalogs { * Devuelve tipos de remolque/semirremolque. * * @param params - Parámetros de consulta. - * @param params.q - Prefijo para buscar en `key` o `description`. * @returns Búsqueda exitosa */ searchTrailerTypes( - params: OperationQuery<'searchCartaPorteTrailerTypes'> | null, + params?: OperationQuery<'searchCartaPorteTrailerTypes'> | null, ): Promise> { return this.client.request< OperationResponse<'searchCartaPorteTrailerTypes'> @@ -140,11 +134,10 @@ export default class CartaPorteCatalogs { * Devuelve entradas del catálogo de materiales peligrosos. * * @param params - Parámetros de consulta. - * @param params.q - Prefijo para buscar en `key`, `description` o `class_division`. * @returns Búsqueda exitosa */ searchHazardousMaterials( - params: OperationQuery<'searchCartaPorteHazardousMaterials'> | null, + params?: OperationQuery<'searchCartaPorteHazardousMaterials'> | null, ): Promise> { return this.client.request< OperationResponse<'searchCartaPorteHazardousMaterials'> @@ -161,11 +154,10 @@ export default class CartaPorteCatalogs { * Devuelve códigos de autorización naval (solo `key`). * * @param params - Parámetros de consulta. - * @param params.q - Prefijo para buscar en `key`. * @returns Búsqueda exitosa */ searchNavalAuthorizations( - params: OperationQuery<'searchCartaPorteNavalAuthorizations'> | null, + params?: OperationQuery<'searchCartaPorteNavalAuthorizations'> | null, ): Promise> { return this.client.request< OperationResponse<'searchCartaPorteNavalAuthorizations'> @@ -182,11 +174,10 @@ export default class CartaPorteCatalogs { * Devuelve entradas de estaciones aéreas/marítimas/terrestres. * * @param params - Parámetros de consulta. - * @param params.q - Prefijo para buscar en `key`, `description` o `iata_designator`. * @returns Búsqueda exitosa */ searchPortStations( - params: OperationQuery<'searchCartaPortePortStations'> | null, + params?: OperationQuery<'searchCartaPortePortStations'> | null, ): Promise> { return this.client.request< OperationResponse<'searchCartaPortePortStations'> @@ -203,11 +194,10 @@ export default class CartaPorteCatalogs { * Devuelve tipos de contenedores marítimos. * * @param params - Parámetros de consulta. - * @param params.q - Prefijo para buscar en `key` o `description`. * @returns Búsqueda exitosa */ searchMarineContainers( - params: OperationQuery<'searchCartaPorteMarineContainers'> | null, + params?: OperationQuery<'searchCartaPorteMarineContainers'> | null, ): Promise> { return this.client.request< OperationResponse<'searchCartaPorteMarineContainers'> diff --git a/src/tools/catalogs.ts b/src/tools/catalogs.ts index 6c865b3..f5d5e7d 100644 --- a/src/tools/catalogs.ts +++ b/src/tools/catalogs.ts @@ -49,4 +49,105 @@ export default class Catalogs { }, ); } + + /** + * Buscar códigos postales + * + * Busca códigos postales mexicanos. Una consulta de 1 a 5 dígitos busca por código o prefijo; el texto busca nombres de colonia, localidad/ciudad, municipio o estado, sin distinguir mayúsculas ni diacríticos. Las coincidencias exactas de nombre preceden a las parciales. Cada código postal aparece una sola vez e incluye todas sus colonias en neighborhoods. El filtro de estado se aplica en ambos casos. Sin consulta, lista códigos postales. Admite páginas y cursores; los totales de búsquedas textuales pueden estar limitados, indicado por totals_are_capped. + * + * @param params - Parámetros de consulta. + * @returns Resultados de búsqueda + */ + searchZipCodes( + params?: OperationQuery<'searchZipCodes'> | null, + ): Promise> { + return this.client.request>( + `/catalogs/zip-codes`, + { + method: 'GET', + datePlan: operationDatePlans.searchZipCodes, + params: params, + }, + ); + } + + /** + * Consultar código postal + * + * Devuelve los datos de domicilio y las colonias de un código postal mexicano. + * + * @param code - code + * @returns Código postal + */ + getZipCode(code: string): Promise> { + if (!code) return Promise.reject(new Error('code is required')); + + return this.client.request>( + `/catalogs/zip-codes/${encodeURIComponent(code)}`, + { method: 'GET', datePlan: operationDatePlans.getZipCode }, + ); + } + + /** + * Buscar países + * + * Busca países por código ISO de tres letras o nombre. La búsqueda ignora acentos y mayúsculas. + * + * @param params - Parámetros de consulta. + * @returns Resultados de búsqueda + */ + searchCountries( + params?: OperationQuery<'searchCountries'> | null, + ): Promise> { + return this.client.request>( + `/catalogs/countries`, + { + method: 'GET', + datePlan: operationDatePlans.searchCountries, + params: params, + }, + ); + } + + /** + * Buscar regímenes fiscales + * + * Consulta los regímenes fiscales admitidos por la API. El receptor debe declarar su régimen; esta búsqueda no lo determina. + * + * @param params - Parámetros de consulta. + * @returns Resultados de búsqueda + */ + searchTaxSystems( + params?: OperationQuery<'searchTaxSystems'> | null, + ): Promise> { + return this.client.request>( + `/catalogs/tax-systems`, + { + method: 'GET', + datePlan: operationDatePlans.searchTaxSystems, + params: params, + }, + ); + } + + /** + * Buscar usos CFDI + * + * Consulta claves de uso CFDI por código o descripción. El uso debe ser declarado por el receptor. + * + * @param params - Parámetros de consulta. + * @returns Resultados de búsqueda + */ + searchInvoiceUses( + params?: OperationQuery<'searchInvoiceUses'> | null, + ): Promise> { + return this.client.request>( + `/catalogs/invoice-uses`, + { + method: 'GET', + datePlan: operationDatePlans.searchInvoiceUses, + params: params, + }, + ); + } } diff --git a/src/tools/comercioExteriorCatalogs.ts b/src/tools/comercioExteriorCatalogs.ts index aef29aa..106bc48 100644 --- a/src/tools/comercioExteriorCatalogs.ts +++ b/src/tools/comercioExteriorCatalogs.ts @@ -14,11 +14,10 @@ export default class ComercioExteriorCatalogs { * Devuelve fracciones arancelarias que coinciden con la consulta. * * @param params - Parámetros de consulta. - * @param params.q - Prefijo para buscar en `key` o `description`. * @returns Búsqueda exitosa */ searchTariffFractions( - params: OperationQuery<'searchComercioExteriorTariffFractions'>, + params?: OperationQuery<'searchComercioExteriorTariffFractions'> | null, ): Promise> { return this.client.request< OperationResponse<'searchComercioExteriorTariffFractions'> diff --git a/src/tools/nominaCatalogs.ts b/src/tools/nominaCatalogs.ts index e8a37c9..4e73e36 100644 --- a/src/tools/nominaCatalogs.ts +++ b/src/tools/nominaCatalogs.ts @@ -14,11 +14,10 @@ export default class NominaCatalogs { * Devuelve tipos de deducción que coinciden con la consulta. * * @param params - Parámetros de consulta. - * @param params.q - Prefijo para buscar en `key` o `description`. * @returns Búsqueda exitosa */ searchDeductions( - params: OperationQuery<'searchNominaDeductions'>, + params?: OperationQuery<'searchNominaDeductions'> | null, ): Promise> { return this.client.request>( `/catalogs/deductions`, @@ -36,11 +35,10 @@ export default class NominaCatalogs { * Devuelve tipos de percepción que coinciden con la consulta. * * @param params - Parámetros de consulta. - * @param params.q - Prefijo para buscar en `key` o `description`. * @returns Búsqueda exitosa */ searchPerceptions( - params: OperationQuery<'searchNominaPerceptions'>, + params?: OperationQuery<'searchNominaPerceptions'> | null, ): Promise> { return this.client.request>( `/catalogs/perceptions`, diff --git a/test-d/runtime-types.test-d.ts b/test-d/runtime-types.test-d.ts index b248abb..aac47bc 100644 --- a/test-d/runtime-types.test-d.ts +++ b/test-d/runtime-types.test-d.ts @@ -5,6 +5,9 @@ import { expectError, } from 'tsd'; import Facturapi, { + CatalogEntrySearchResult, + ZipCodeSearchResult, + ZipCodeDetail, BinaryDownload, ApiKeys, ApiEvent, @@ -774,3 +777,33 @@ expectType(restoredOrganization.legal?.curp); expectType( restoredOrganization.customization?.default_series?.I, ); + +expectType>( + client.catalogs.searchZipCodes({ q: '01', state: 'CMX', limit: 10 }), +); +expectType>(client.catalogs.getZipCode('01000')); +expectType>( + client.catalogs.searchCountries({ q: 'México' }), +); +expectType>( + client.catalogs.searchTaxSystems(), +); +expectType>( + client.catalogs.searchInvoiceUses({ page: 2 }), +); +expectError(client.catalogs.getZipCode(1000)); +expectError(client.catalogs.searchZipCodes({ state: 9 })); + +client.cartaPorteCatalogs.searchAirTransportCodes({ page: 1 }); +client.comercioExteriorCatalogs.searchTariffFractions({ limit: 10 }); +client.nominaCatalogs.searchDeductions(); +client.nominaCatalogs.searchPerceptions({ page: 2 }); + +client.catalogs.searchZipCodes({ + q: '01', + pagination: 'cursor', + after: 'cursor', + limit: 10, +}); +client.catalogs.searchZipCodes({ q: '01', before: 'cursor', limit: 10 }); +expectError(client.catalogs.searchZipCodes({ pagination: 'other' })); diff --git a/test/catalogs.shared.ts b/test/catalogs.shared.ts new file mode 100644 index 0000000..037b9f3 --- /dev/null +++ b/test/catalogs.shared.ts @@ -0,0 +1,169 @@ +import { afterEach, describe, expect, it, vi } from 'vitest'; +import Facturapi from '../src'; + +afterEach(() => vi.unstubAllGlobals()); + +describe('address and fiscal catalogs', () => { + it('sends search parameters through HTTP and preserves catalog keys', async () => { + const client = new Facturapi('sk_test_example'); + client.BASE_URL = 'https://api.example.com/v2'; + const page = { + page: 2, + total_pages: 3, + total_results: 25, + data: [{ key: '01000', description: 'Catalog entry' }], + }; + const fetch = vi.fn(async () => Response.json(page)); + vi.stubGlobal('fetch', fetch); + for (const [method, path] of [ + ['searchZipCodes', 'zip-codes'], + ['searchCountries', 'countries'], + ['searchTaxSystems', 'tax-systems'], + ['searchInvoiceUses', 'invoice-uses'], + ] as const) { + fetch.mockClear(); + expect( + await client.catalogs[method]({ q: '01', page: 2, limit: 10 }), + ).toEqual(page); + expect(fetch).toHaveBeenCalledExactlyOnceWith( + `https://api.example.com/v2/catalogs/${path}?q=01&page=2&limit=10`, + expect.objectContaining({ method: 'GET' }), + ); + } + }); + + it('browses specialized catalogs without a query string', async () => { + const client = new Facturapi('sk_test_example'); + client.BASE_URL = 'https://api.example.com/v2'; + const page = { page: 0, total_pages: 0, total_results: 0, data: [] }; + const fetch = vi.fn(async () => Response.json(page)); + vi.stubGlobal('fetch', fetch); + expect(await client.nominaCatalogs.searchDeductions()).toEqual(page); + expect( + await client.cartaPorteCatalogs.searchAirTransportCodes({ page: 1 }), + ).toEqual(page); + expect( + await client.comercioExteriorCatalogs.searchTariffFractions({ + limit: 10, + }), + ).toEqual(page); + expect(fetch).toHaveBeenNthCalledWith( + 1, + 'https://api.example.com/v2/catalogs/deductions', + expect.objectContaining({ method: 'GET' }), + ); + expect(fetch).toHaveBeenNthCalledWith( + 2, + 'https://api.example.com/v2/catalogs/cartaporte/3.1/air-transport-codes?page=1', + expect.objectContaining({ method: 'GET' }), + ); + expect(fetch).toHaveBeenNthCalledWith( + 3, + 'https://api.example.com/v2/catalogs/comercioexterior/2.0/tariff-fractions?limit=10', + expect.objectContaining({ method: 'GET' }), + ); + }); + + it('forwards postal cursor boundaries and preserves cursor metadata', async () => { + const client = new Facturapi('sk_test_example'); + client.BASE_URL = 'https://api.example.com/v2'; + const result = { + data: [{ key: '01000' }], + next_cursor: 'next', + previous_cursor: null, + }; + const fetch = vi.fn(async () => Response.json(result)); + vi.stubGlobal('fetch', fetch); + expect( + await client.catalogs.searchZipCodes({ + q: '01', + pagination: 'cursor', + after: 'boundary', + limit: 10, + }), + ).toEqual(result); + expect(fetch).toHaveBeenLastCalledWith( + 'https://api.example.com/v2/catalogs/zip-codes?q=01&pagination=cursor&after=boundary&limit=10', + expect.objectContaining({ method: 'GET' }), + ); + await client.catalogs.searchZipCodes({ q: '01', before: 'boundary' }); + expect(fetch).toHaveBeenLastCalledWith( + 'https://api.example.com/v2/catalogs/zip-codes?q=01&before=boundary', + expect.objectContaining({ method: 'GET' }), + ); + }); + + it('forwards neighborhood names with case and diacritics intact', async () => { + const client = new Facturapi('sk_test_example'); + client.BASE_URL = 'https://api.example.com/v2'; + const result = { + page: 1, + total_pages: 1, + total_results: 1, + data: [ + { + key: '03810', + country: { key: 'MEX', description: 'México' }, + state: { key: 'CMX', description: 'Ciudad de México' }, + municipality: null, + locality: null, + neighborhoods: [ + { key: '0001', description: 'Nápoles' }, + { key: '0002', description: 'Norte' }, + ], + }, + ], + }; + const fetch = vi.fn(async () => Response.json(result)); + vi.stubGlobal('fetch', fetch); + for (const q of ['Nápoles', 'NAPOLES', 'na\u0301poles']) { + expect(await client.catalogs.searchZipCodes({ q, state: 'CMX' })).toEqual( + result, + ); + expect(fetch).toHaveBeenLastCalledWith( + `https://api.example.com/v2/catalogs/zip-codes?q=${encodeURIComponent(q)}&state=CMX`, + expect.objectContaining({ method: 'GET' }), + ); + } + }); + + it('forwards state names in postal search text', async () => { + const client = new Facturapi('sk_test_example'); + client.BASE_URL = 'https://api.example.com/v2'; + const response = { page: 0, total_pages: 0, total_results: 0, data: [] }; + const fetch = vi.fn(async () => Response.json(response)); + vi.stubGlobal('fetch', fetch); + expect( + await client.catalogs.searchZipCodes({ q: 'Nuevo León', state: 'NLE' }), + ).toEqual(response); + expect(fetch).toHaveBeenCalledExactlyOnceWith( + 'https://api.example.com/v2/catalogs/zip-codes?q=Nuevo+Le%C3%B3n&state=NLE', + expect.objectContaining({ method: 'GET' }), + ); + }); + + it('retrieves postal-code details and URL-encodes the code argument', async () => { + const client = new Facturapi('sk_test_example'); + client.BASE_URL = 'https://api.example.com/v2'; + const detail = { + key: '01000', + country: { key: 'MEX', description: 'México' }, + state: null, + municipality: null, + locality: null, + neighborhoods: [{ key: '0001', description: 'Centro' }], + }; + const fetch = vi.fn(async () => Response.json(detail)); + vi.stubGlobal('fetch', fetch); + expect(await client.catalogs.getZipCode('01000')).toEqual(detail); + expect(fetch).toHaveBeenLastCalledWith( + 'https://api.example.com/v2/catalogs/zip-codes/01000', + expect.objectContaining({ method: 'GET' }), + ); + await client.catalogs.getZipCode('01/000'); + expect(fetch).toHaveBeenLastCalledWith( + 'https://api.example.com/v2/catalogs/zip-codes/01%2F000', + expect.objectContaining({ method: 'GET' }), + ); + }); +}); diff --git a/test/node/catalogs.node.test.ts b/test/node/catalogs.node.test.ts new file mode 100644 index 0000000..6fc9dbd --- /dev/null +++ b/test/node/catalogs.node.test.ts @@ -0,0 +1 @@ +import '../catalogs.shared'; diff --git a/test/web/catalogs.web.test.ts b/test/web/catalogs.web.test.ts new file mode 100644 index 0000000..6fc9dbd --- /dev/null +++ b/test/web/catalogs.web.test.ts @@ -0,0 +1 @@ +import '../catalogs.shared';